通常,大多數的分組加密算法都是把數據按照64位分組的方式進行加密和解密。但是幾乎所有的加密工作所涉及的數據量都遠遠大於64位,因此就需要不斷地重復加密過程,直到處理完所有的分組。這種分組加密中所涉及的重復性方式稱為分組加密模式。
處理多個數據分組最簡單的方式是將每一個生成的密文分組添加到之前生成的密文分組之后。這種簡單的方式被稱為ECB,或者電子碼本(electronic code book)。這種方法的簡單性使其比較流行,但它相對來說是不安全的。主要問題是,對於任意給定的密鑰,相同的明文分組加密之后得到的密文結果總是一樣的,即明文和密文的分組是一一對應的關系。假如黑客破解了哪怕一小段數據,他就可以以此建立一個密碼本,來對其他數據段進行破解。
一種更好的方法是CBC或被稱為密碼分組鏈接的模式。
CBC模式通過對分組密碼增加簡單的操作和反饋避免ECB中出現的問題。反饋使得密文的每個分組都同之前執行的操作在一定程度上有依賴關系(ECB中每個分組的加密和解密都是獨立的)。在CBC模式中,用之前的密文分組作為反饋,這樣就算是明文中的同一個分組,每次都好像加密成另一個不同的密文分組一樣。
對於之前作為反饋的密文分組,在加密一個明文分組前,將前一個輸出的密文分組與該明文分組求異或,然后再加密。
當解密時,將前一個輸出的明文分組同接下來待解密的密文分組求異或,然后再解密。這兩種方式可以簡單的表示為:
Ci = Ek(Pi ⊕ Ci-1)
Pi = Ci-1 ⊕ Dk(Ci)
這里Ci和Pi為緩沖區C和P中的第(i)個密文和明文分組,而Ek和Dk是使用密鑰K進行的加密和解密操作。
通常,會在明文的開始處增加一個隨機的數據塊。這是因為即使有黑客知道明文的第一個分組包含的信息,它也不能用於模擬鏈接的順序。這個增加的隨機數據塊稱為 初始向量。按照正常的方式對其加密,這里不需要任何反饋。然后,將加密后的初始向量作為接下來加密和解密第一個分組數據的反饋。
下面的示例中給出了兩個函數(cbc_encipher和cbc_decipher)的實現。它們采用DES算法中的CBC模式來對緩沖區中的數據做加密和解密的動作。
函數cbc_encipher接受一個size字節大小的明文緩沖區作為參數,使用key作為密鑰來對其加密。該函數假設明文的第一個分組是64位的初始向量。
函數cbc_decipher接受一個size字節大小的密文緩沖區作為參數,使用key作為密鑰來對期解密。為了保持對稱性,初始化向量也要解密,並作為明文的第一個分組返回。
兩個函數的時間復雜度都是O(n),這里n代表加密或解密的分組數量。這是因為這兩個函數都只是簡單地調用復雜度同為O(1)的des_encipher和dex_decipher,每處理一個分組調用一次。
示例:DES算法的CBC模式實現
/*cbc.c*/ #include <stdlib.h> #include "bit.h" #include "cbc.h" #include "encipher.h" /*cbc_encipher DES算法中的cbc加密模式*/ void cbc_encipher(const unsigned char *plaintext, unsigned char *ciphertext, const unsigned char *key, int size) { unsigned char temp[8]; int i; /*加密初始化向量*/ des_encipher(&plaintext[0],&ciphertext[0],key); /*使用DES算法中的CBC模式加密緩沖區*/ i=8; while(i < size) { bit_xor(&plaintext[i], &ciphertext[i-8], temp, 64); /*temp = Pi XOR Ci-1*/ des_encipher(temp,&ciphertext[i],NULL); /*Ek(temp)*/ i=i+8; } return; } /*cbc_descipher DES算法中的cbc解密模式*/ void cbc_decipher(const unsigned char *ciphertext, unsigned char *plaintext, const unsigned char *key, int size) { unsigned char temp[8]; int i; /*解密初始化向量*/ des_decipher(&ciphertext[0], &plaintext[0], key); /*使用DES算法中的CBC模式解密緩沖區*/ i=8; while(i < size) { des_decipher(&ciphertext[i],temp,NULL); /*temp = Dk(Ci)*/ bit_xor(&ciphertext[i-8], temp, &plaintext[i], 64); /*Ci-1 XOR temp*/ i=i+8; } return; }
