DES 演算法簡介

DES 加密演算法屬於對稱密碼範疇,那麼什麼是對稱密碼呢?加密和解密過程中所使用的金鑰相同,就是對稱密碼,而且大多數對稱密碼演算法,加密解密過程都是互逆的。DES 演算法是一種資料加密演算法,明文按照 64 位進行分組,分組後的明文與金鑰按位替代或交換的方法形成密文組。 金鑰的長度是 64 位(其實是56位,其中有8位是奇偶校驗位)。

DES 工作模式簡介

1 . ECB(電子密碼密碼本模式)

這是最原始的一種加密工作模式,將明文分組成64位,與金鑰長度相同,然後按照加密演算法加密,得到 64位密文,最後將所有加密後的密文連線在一起即可,各段之間互不影響(當最後一段不足64位是要補足64位在進行計算)

可見,這種模式的優點是實現起來簡單,有利於並行運算,但是缺點是安全性比較低。
2 . CBC (密文連結模式)

這種模式相比於 ECB 就比較複雜了,讓我們來看看它是如何加密的

1. 首先將資料按照8個位元組一組進行分組得到D1D2......Dn(若資料不是8的整數倍,用指定的PADDING資料補位)
2. 第一組資料D1與初始化向量I異或後的結果進行DES加密得到第一組密文C1(初始化向量I為全零)
3. 第二組資料D2與第一組的加密結果C1異或以後的結果進行DES加密,得到第二組密文C2
4. 之後的資料以此類推,得到Cn
5. 按順序連為C1C2C3......Cn即為加密結果。

這種加密模式相比於上一中比較安全一些,但是有一個致命的缺點,就是誤差延續性,就是說只要有一個地方的密文出現錯誤,那麼底下的密文就都會出現錯誤,為什麼會這樣?仔細看看加密過程就能明白,這也就是為什麼這種模式叫做連結模式。
當然還有其他的模式,就不一一介紹了,一般還是利用以上兩種模式。

DES 填充模式

NoPadding
API或演算法本身不對資料進行處理,加密資料由加密雙方約定填補演算法。例如若對字串資料進行加解密,可以補充\0或者空格,然後trim。

PKCS5Padding
加密前:資料位元組長度對8取餘,餘數為m,若m>0,則補足8-m個位元組,位元組數值為8-m,即差幾個位元組就補幾個位元組,位元組數值即為補充的位元組數,若為0則補充8個位元組的8
填充模式就用於當明文不是64的倍數的時候,由於在加密的過程中需要對明文進行分塊,所以需要選擇填充模式。

DES 的使用

1 . 和 Hmac 演算法一樣,想要使用 DES,首先要獲取金鑰,這需要藉助於 JDK 自帶的 KeyGenerator

public static byte[] initKey() throws Exception {
KeyGenerator keyGenerator = KeyGenerator.getInstance("DES");
keyGenerator.init(56); // 56 可填可不填

SecretKey secretKey = keyGenerator.generateKey();
return secretKey.getEncoded();

}
2 . 接下來就是 DES 加密過程

public static byte[] encryptDES(byte[] key, byte[] data) throws Exception {

    SecretKey secretKey = new SecretKeySpec(key, "DES");

    Cipher cipher = Cipher.getInstance("DES");
    cipher.init(Cipher.ENCRYPT_MODE, secretKey);
    byte[] resultBytes = cipher.doFinal(data);
    return resultBytes;

}

傳進去一個 helloworld 看看結果

public static void main(String[] args) throws Exception {
String data = "helloworld";
byte[] key = initKey();

    byte[] resultBytes = encryptDES(key, data.getBytes());

    String resultString = byteToHexString(resultBytes);

    System.out.println(resultString);

}

結果為

215f9748bf31d5dc3d4eb5b77107643b

既然 DES 是用於資料加密,那麼我們總應該能把資料還原成明文把,不然其意義何在呢?其實解密過程和加密過程幾乎一模一樣,如下所示

public static String decryptDES(byte[] key, byte[] data) throws Exception {
SecretKey secretKey = new SecretKeySpec(key, "DES");

    Cipher cipher = Cipher.getInstance("DES");
    cipher.init(Cipher.DECRYPT_MODE, secretKey);

    byte[] resultBytes = cipher.doFinal(data);

    return new String(resultBytes);
}

這個時候傳進來的 key 必須和加密時使用的 key 是相同的,而且這個時候傳進來的 data 也必須是加密過後的密文。

咦,這個時候我們發現,我們開頭介紹的加密模式和填充模式好像都沒用到,其實我們一般是使用預設就可以了,如果有特殊需要,可以這樣使用

Cipher cipher = Cipher.getInstance("DES/ECB