先说AES,看代码:
public static byte[] doEncrypt(byte[] key, byte[] initialVector, byte[] text) {
try {
SecretKeySpec secretKeySpec = new SecretKeySpec(key, "AES");
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");//"算法/模式/补码方式"
IvParameterSpec iv = new IvParameterSpec(initialVector);//使用CBC模式,需要一个向量iv,可增加加密算法的强度
cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec, iv);
byte[] encrypted = cipher.doFinal(text);
return encrypted;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
public static byte[] doEncryptByRandom(int length, byte[] key, byte[] initialVector, byte[] text) {
try {
KeyGenerator kgen = KeyGenerator.getInstance("AES");
SecureRandom secureRandom = SecureRandom.getInstance("SHA1PRNG");
secureRandom.setSeed(key);
kgen.init(length, secureRandom);
SecretKey secretKey = kgen.generateKey();
byte[] enCodeFormat = secretKey.getEncoded();
//return doEncrypt(enCodeFormat, initialVector, text);
SecretKeySpec secretKeySpec = new SecretKeySpec(enCodeFormat, "AES");
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");//"算法/模式/补码方式"
if (initialVector==null){
initialVector = new byte[length/8];
}else if (initialVector.length*8!=length){
byte[] tmp = new byte[length/8];
if (tmp.length>initialVector.length){
System.arraycopy(initialVector, 0, tmp, 0, initialVector.length);
}else{
System.arraycopy(initialVector, 0, tmp, 0, tmp.length);
}
initialVector = tmp;
}
IvParameterSpec iv = new IvParameterSpec(initialVector);//使用CBC模式,需要一个向量iv,可增加加密算法的强度
cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec, iv);
byte[] encrypted = cipher.doFinal(text);
return encrypted;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
这是之前遇到的问题,
doEncrypt是给定密钥和向量进行加密,是最基本的加密算法。
而doEncryptByRandom则是对密钥进行了变换之后加密的,变换主要是对密钥不足的部分进行补充,内容以给定密钥作为种子,进行随机生成,并且只要给定同一密钥,随机后的结果应该是一致的。
So, doEncryptByRandom方法中,
byte[] enCodeFormat = secretKey.getEncoded();
把后面
//return doEncrypt(enCodeFormat, initialVector, text);
的注释打开,并注释掉后面的部分,与操作之前得出的加解密结果是一致的。
3DES,代码:
public static byte[] doTripleEncrypt(byte[] rawKeyData, byte[] plainText) throws Exception {
byte[] k = new byte[24];
int len = plainText.length;
if (plainText.length % 8 != 0) {
len = plainText.length - plainText.length % 8 + 8;
}
byte[] needData = null;
if (len != 0){
needData = new byte[len];
}
for (int i = 0; i < len; i++) {
needData[i] = 0x00;
}
System.arraycopy(plainText, 0, needData, 0, plainText.length);
if (rawKeyData.length == 16) {
System.arraycopy(rawKeyData, 0, k, 0, rawKeyData.length);
System.arraycopy(rawKeyData, 0, k, 16, 8);
} else {
System.arraycopy(rawKeyData, 0, k, 0, 24);
}
KeySpec ks = new DESedeKeySpec(k);
SecretKeyFactory kf = SecretKeyFactory.getInstance("DESede");
SecretKey ky = kf.generateSecret(ks);
Cipher DESedecipher = Cipher.getInstance("DESede/ECB/NoPadding");
DESedecipher.init(Cipher.ENCRYPT_MODE, ky);
return DESedecipher.doFinal(needData);
}
根据定义,3DES密钥是由3个密钥单位构成的:K1+K2+K3;结合到具体的加解密,即:EnK3(DeK2(EnK1(明文)));而我们在分发密钥时,有可能只分发其中的一部分,即K1,或K1+K2,缺失的部分,需要自行补齐,在PHP中,缺失部分可能会被填充0x00,所以,我们在分发3DES密钥时应该主动补齐缺失的部分,以防止疏漏。
