常見DES實現陷阱

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));
                        }
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章