对称加密和伪随机性
加密算法设计的两种基本策略
流密码:(序列密码)
- 将密钥扩展到与密文等长
- 加密算法一般为异或操作
- 其安全性主要在于密钥扩展后的随机性
分组密码:
- 将明文分成等长的分组(比如64bit, 128bit)
- 对每个分组采用相同的加密算法进行加密
- 算法一般是交替使用混合和扩散技术
注意:替换使用混乱和扩散技术的本质是为了实现伪随机函数(PRF)。
随机函数:给定集合X和Y,设函数\(f:X \to Y\)。则该类函数\(f\)一共有\(|X|^{|Y|}\)个,令集合\(D=\{f_i|f_i : X\to Y\}\)。随机从集合D中选择一个元素\(f_i\),则称\(f_i\)为随机函数
伪随机函数:设K为密文空间,X是输入数据,Y是输出数据。若\(k \in K, x \in X, y \in Y, \ y=F(k, x)\in Y\),其安全性要求:给定一个随机产生的密钥k,函数\(F(k,)\)为集合X到集合Y的随机函数。
常见的流密码加密算法
-
RC4加密算法
该算法包括2个过程:
- 密钥调度算法:置乱S盒的初式序列
- 伪随机生成算法:输出随机序列并修改S的当前排列顺序
package io.kzw.advance.csdn_blog;
public class RC4 {
public static String decry_RC4(byte[] data, String key) {
if (data == null || key == null) {
return null;
}
return asString(RC4Base(data, key));
}
public static String decry_RC4(String data, String key) {
if (data == null || key == null) {
return null;
}
return new String(RC4Base(HexString2Bytes(data), key));
}
public static byte[] encry_RC4_byte(String data, String key) {
if (data == null || key == null) {
return null;
}
byte b_data[] = data.getBytes();
return RC4Base(b_data, key);
}
public static String encry_RC4_string(String data, String key) {
if (data == null || key == null) {
return null;
}
return toHexString(asString(encry_RC4_byte(data, key)));
}
private static String asString(byte[] buf) {
StringBuffer strbuf = new StringBuffer(buf.length);
for (int i = 0; i < buf.length; i++) {
strbuf.append((char) buf[i]);
}
return strbuf.toString();
}
private static byte[] initKey(String aKey) {
byte[] b_key = aKey.getBytes();
byte state[] = new byte[256];
for (int i = 0; i < 256; i++) {
state[i] = (byte) i;
}
int index1 = 0;
int index2 = 0;
if (b_key == null || b_key.length == 0) {
return null;
}
for (int i = 0; i < 256; i++) {
index2 = ((b_key[index1] & 0xff) + (state[i] & 0xff) + index2) & 0xff;
byte tmp = state[i];
state[i] = state[index2];
state[index2] = tmp;
index1 = (index1 + 1) % b_key.length;
}
return state;
}
private static String toHexString(String s) {
String str = "";
for (int i = 0; i < s.length(); i++) {
int ch = (int) s.charAt(i);
String s4 = Integer.toHexString(ch & 0xFF);
if (s4.length() == 1) {
s4 = '0' + s4;
}
str = str + s4;
}
// 0x表示十六进制
return str;
}
private static byte[] HexString2Bytes(String src) {
int size = src.length();
byte[] ret = new byte[size / 2];
byte[] tmp = src.getBytes();
for (int i = 0; i < size / 2; i++) {
ret[i] = uniteBytes(tmp[i * 2], tmp[i * 2 + 1]);
}
return ret;
}
private static byte uniteBytes(byte src0, byte src1) {
char _b0 = (char) Byte.decode("0x" + new String(new byte[]{src0}))
.byteValue();
_b0 = (char) (_b0 << 4);
char _b1 = (char) Byte.decode("0x" + new String(new byte[]{src1}))
.byteValue();
byte ret = (byte) (_b0 ^ _b1);
return ret;
}
private static byte[] RC4Base(byte[] input, String mKkey) {
int x = 0;
int y = 0;
// 这边将密钥确保为 256 个字节
byte key[] = initKey(mKkey);
int xorIndex;
byte[] result = new byte[input.length];
for (int i = 0; i < input.length; i++) {
x = (x + 1) & 0xff;
y = ((key[x] & 0xff) + y) & 0xff;
byte tmp = key[x];
key[x] = key[y];
key[y] = tmp;
xorIndex = ((key[x] & 0xff) + (key[y] & 0xff)) & 0xff;
result[i] = (byte) (input[i] ^ key[xorIndex]);
}
return result;
}
}
常见的分组加密算法
- DES加密算法
DES算法的入口参数有三个:key, data, mode(DES的工作方式:加密,解密)
DES是一种分组加密算法,该算法每次处理固定长度(64bit)的数据段。DES算法具体通过对明文进行一系列的排列和替换将其加密。过程的关键就是从给定的初始密钥中得到16个密钥的函数。将要加密一组明文,每个子密钥按照顺序进行位运算。每一个子密钥一次,重复16次。要对密文解密逆向其过程即可。
子密钥的生成过程:
加密/解密过程:
private static final String ALGO = "DES";
private static byte[] encrypt(byte[] src, String password) {
try {
// DES 算法要求有一个可信任的随机数源
SecureRandom random = new SecureRandom();
DESKeySpec desKey = new DESKeySpec(password.getBytes());
// 创建一个密匙工厂,然后用它把 DESKeySpec 转换成 SecretKey
SecretKeyFactory keyFactory = SecretKeyFactory.getInstance(ALGO);
SecretKey securekey = keyFactory.generateSecret(desKey);
// Cipher对象实际完成加密操作
Cipher cipher = Cipher.getInstance(ALGO);
// 用密匙初始化 Cipher 对象,ENCRYPT_MODE 用于将 Cipher 初始化为加密模式的常量
cipher.init(Cipher.ENCRYPT_MODE, securekey, random);
// 加密数据
return cipher.doFinal(src);
} catch (Throwable e) {
e.printStackTrace();
}
return null;
}
private static byte[] decrypt(byte[] src, String password) {
try {
// DES 算法要求有一个可信任的随机数源
SecureRandom random = new SecureRandom();
// 创建一个 DESKeySpec 对象
DESKeySpec desKey = new DESKeySpec(password.getBytes());
// 创建一个密匙工厂
SecretKeyFactory keyFactory = SecretKeyFactory.getInstance(ALGO);
// 将 DESKeySpec 对象转换成 SecretKey 对象
SecretKey securekey = keyFactory.generateSecret(desKey);
// Cipher 对象实际完成解密操作
Cipher cipher = Cipher.getInstance(ALGO);
// 用密匙初始化 Cipher 对象
cipher.init(Cipher.DECRYPT_MODE, securekey, random);
// 解密数据
return cipher.doFinal(src);
} catch (Throwable e) {
e.printStackTrace();
}
return null;
}
public static void main(String[] args) {
String psw = "12345678";
String data = "hello Test symmetric encry";
byte[] encryData = encrypt(data.getBytes(), psw);
System.out.println("encryData = " + new String(encryData));
byte[] decryData = decrypt(encryData, psw);
System.out.println("decryData = " + new String(decryData));
}
-
3DES加密算法
3DES加密算法本质是有3个不同的DES密钥,然后按照下列流程进行加密:
注意:当3个DES密钥相同,其中前2次加密被抵消,退化为DES加密,过程如下:
private static final String Algorithm = "DESede";
private static byte[] encrypt(byte[] keybyte, byte[] src) {
try {
// 生成密钥
SecretKey deskey = new SecretKeySpec(keybyte, Algorithm);
Cipher c1 = Cipher.getInstance(Algorithm);
c1.init(Cipher.ENCRYPT_MODE, deskey);
// 加密数据
return c1.doFinal(src);
} catch (java.security.NoSuchAlgorithmException e1) {
e1.printStackTrace();
} catch (javax.crypto.NoSuchPaddingException e2) {
e2.printStackTrace();
} catch (java.lang.Exception e3) {
e3.printStackTrace();
}
return null;
}
private static byte[] decrypt(byte[] keybyte, byte[] src) {
try {
// 生成密钥
SecretKey deskey = new SecretKeySpec(keybyte, Algorithm);
Cipher c1 = Cipher.getInstance(Algorithm);
c1.init(Cipher.DECRYPT_MODE, deskey);
// 解密
return c1.doFinal(src);
} catch (java.security.NoSuchAlgorithmException e1) {
e1.printStackTrace();
} catch (javax.crypto.NoSuchPaddingException e2) {
e2.printStackTrace();
} catch (java.lang.Exception e3) {
e3.printStackTrace();
}
return null;
}
public static void main(String[] args) {
// 添加新安全算法,如果用JCE就要把它添加进去
Security.addProvider(new com.sun.crypto.provider.SunJCE());
// 24字节的密钥
final byte[] keyBytes = {
0x11, 0x22, 0x4F, 0x58,
(byte) 0x88, 0x10, 0x40, 0x38,
0x28, 0x25, 0x79, 0x51,
(byte) 0xCB, (byte) 0xDD, 0x55, 0x66,
0x77, 0x29, 0x74, (byte) 0x98,
0x30, 0x40, 0x36, (byte) 0xE2
};
String szSrc = "hello Test symmetric encry";
byte[] encryData = encrypt(keyBytes, szSrc.getBytes());
System.out.println("encryData: " + new String(encryData));
byte[] decryptData = decrypt(keyBytes, encryData);
System.out.println("decryptData: " + (new String(decryptData)));
}
- AES加密算法
private static final String ALGO = "AES/ECB/PKCS5Padding";
public static byte[] encrypt(String data, Key key) {
try {
Cipher cipher = Cipher.getInstance(ALGO);
cipher.init(cipher.ENCRYPT_MODE, key);
return cipher.doFinal(data.getBytes());
} catch (Throwable throwable) {
throwable.printStackTrace();
}
return null;
}
private static byte[] decrypt(byte[] result, Key key) {
try {
Cipher cipher = Cipher.getInstance(ALGO);
cipher.init(Cipher.DECRYPT_MODE, key);
return cipher.doFinal(result);
} catch (Throwable throwable) {
throwable.printStackTrace();
}
return null;
}
private static Key createKey() {
try {
// 生成key
KeyGenerator keyGenerator;
// 构造密钥生成器,指定为AES算法,不区分大小写
keyGenerator = KeyGenerator.getInstance("AES");
// 生成一个128位的随机源,根据传入的字节数组
keyGenerator.init(128);
// 产生原始对称密钥
SecretKey secretKey = keyGenerator.generateKey();
// 获得原始对称密钥的字节数组
byte[] keyBytes = secretKey.getEncoded();
// key转换,根据字节数组生成AES密钥
return new SecretKeySpec(keyBytes, "AES");
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
return null;
}
}
public static void main(String[] args) {
String data = "hello Test symmetric encry";
Key key = createKey();
byte[] encryData = encrypt(data, key);
System.out.println("encryData = " + new String(encryData));
byte[] decryData = decrypt(encryData, key);
System.out.println("decryData = " + new String(decryData));
}