DES要點說明
- DES走的是分組加密,每次處理對象的是8位byte,所以對字符串加解密的時候,會涉及字符編碼格式和補齊8位的問題。
- DES的密鑰是固定8位的byte的,其中前7位是加解密用的,最後一位是校驗碼。
- 3DES的增強型的DES,帶3個key,如果3個key一樣,就是DES,也有一種變種是1、3是一樣的。但都是固定8位的。
- 3DES通常是EDE,就是先加密(k1)再解密(k2)再加密(k3)
目前,項目代碼中有3個和DES實現相關的類,下面看看他們有哪些問題:
案例1
- 從字符串到byte的轉換,有指定編碼格式GBK,這個是可以接受的。
- 使用的是DESede,就是3DES的EDE加密方式,但是3個key是一樣的,沒有意義。
- 加密時代碼先自行進行了補齊操作(補\0),但是補齊是在字符串上操作的,不是在字節上操作,導致實際上可能沒有對齊(中文情況)。
- 調用加密API時,沒有指定補齊方式,會採用默認補齊,造成重複補齊(當然也修復了上面的補齊操作)。
- 解密指定NoPadding,和加密Padding方式不一樣,造成解密結果最後會出現很多多餘的字節。所以結果必須得trim一下才行。
參考代碼如下:
補齊實現有誤:
public String encrypt(String in) throws Exception {
String strIn = in;
if (null == strIn || "".equals(strIn)) {
return "";
}
int i = 0;
i = strIn.length() % 8;
if (0 == i) {
for (i = 0; i < 8; i++) {
strIn += "\0";
}
} else {
while (i > 0) {
strIn += "\0";
i--;
}
}
byte[] bytes = strIn.getBytes(CHARSET);
byte[] enbytes = encryptCipher.doFinal(bytes);
return byteArrToHexStr(enbytes);
}
key是一樣的,補齊方式沒對應上:
public DESedeEncrypt() {
byte[] buffer = new byte[] {
0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31,
0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31
};
SecretKeySpec key = new SecretKeySpec(buffer, "DESede");
try {
encryptCipher = Cipher.getInstance(KEY_ALGORITHM);
encryptCipher.init(Cipher.ENCRYPT_MODE, key);
decryptCipher = Cipher.getInstance("DESede/ECB/NoPadding");
decryptCipher.init(Cipher.DECRYPT_MODE, key);
} catch (NoSuchAlgorithmException e) {
Throwables.propagate(e);
} catch (NoSuchPaddingException e) {
Throwables.propagate(e);
} catch (InvalidKeyException e) {
Throwables.propagate(e);
}
}
案例2
- 從字符串到byte的轉換,採用了系統默認編碼,存在平臺移植性問題。
- 密鑰key的長度佈置8位,有多餘字符(雖然只取前8位避免出錯),造成混亂。
key的格式不標準,有多餘字符:
private static String strDefaultKey = "mywebsite123456%";
private Key getKey(byte[] arrBTmp) throws Exception {
byte[] arrB = new byte[8];
for (int i = 0; i < arrBTmp.length && i < arrB.length; i++) {
arrB[i] = arrBTmp[i];
}
Key key = new javax.crypto.spec.SecretKeySpec(arrB, "DES");
return key;
}
案例3
- 從字符串到byte的轉換,採用了系統默認編碼,存在平臺移植性問題。
- 實現不是標準的DES,或3DES,是在DES基礎上定義了一套加密。
- 根據目前key的長度,比標準3DES都要慢很多,另外沒有采用JDK帶的API。
key的長度不標準:
public class DesUtil {
public static final String firstKey = "com.xxx.xxxpro";
public static final String secondKey = "xxx_web";
public static final String thirdKey = "xxxservice";
}
實現方式是對每個key補齊8位,再切割形成每組多個8位的key,再採用EEE的方式進行處理:
for (x = 0; x < firstLength; x++) {
tempBt = enc(tempBt, (int[]) firstKeyBt.get(x));
}
for (y = 0; y < secondLength; y++) {
tempBt = enc(tempBt, (int[]) secondKeyBt.get(y));
}
for (z = 0; z < thirdLength; z++) {
tempBt = enc(tempBt, (int[]) thirdKeyBt.get(z));
}