一、引子
在引出對稱加密之前,有必要先介紹一種位運算,XOR。XOR 的全稱是 exclusive or,中文翻譯是異或。
XOR 可以看成是“兩個數相同,異或為 0 ,不同則異或為 1”。
異或也叫半加運算,其運算法則相當于不帶進位的二進制加法:二進制下用1表示真,0表示假,則異或的運算法則為:
這些法則與加法是相同的,只是不帶進位,所以異或常被認作不進位加法。由異或的這種特點,也就引出了它的一個常用特性, 兩個相同的數進行 XOR 運算的結果一定為 0 。
對應的,我們也可以得到如下的運算法則:
上述這幾條法則推導過程就不贅述了,相信讀者都能明白。
異或的結合律可以用來做簡單的對稱加密。
試想,如果把異或數設置成一個完全隨機的二進制序列,那么被異或數和它進行一次異或運算以后,結果如同“密文”一樣。如果竊聽者不知道異或數是什么,很難短時間內解出原消息來。
消息接收者拿到密文以后,把密文再和異或數進行一起異或運算,就能拿到原文了。這個性質就是異或的結合律。
二、一次性加密本
只要通過暴力破解,對密鑰空間進行遍歷,密文總有一天一定能被破譯。只不過看密鑰空間有多大,需要花費的時間有多長。但是有一種加密方法卻是被證明永遠都無法被破解的,即便是暴力遍歷了所有密鑰空間,依舊無法被破解。
筆者第一次見到這個加密方法的時候,覺得非常神奇,還有這么強大的加密方法,那加密過程應該非常復雜,數學證明也應該非常完備吧。結果看到它的原理以后,發現并非如此。一次性密碼本的加密方法非常簡單,只用了上一章提到的 XOR 異或運算。
(一) 加密
一次性密碼本加密,舉個例子,假設要加密的原文是 midnight。
密鑰為一個隨機的二進制流。一次性密碼本加密的過程,是把明文和密鑰進行一次異或計算。
(二) 解密
一次性密碼本的解密過程是把密文和密鑰進行一次異或計算,得到原文明文。
看完這個加密解密過程,讀者肯定質疑這種方式很容易被破解啊,64 位隨機的二進制流暴力遍歷它的密鑰空間,一定能試出原文是什么。
那么現在就可以解開謎底了。確實用暴力破解能遍歷所有密鑰空間,假設有一個超級量子計算機可以一秒遍歷完 2^64^ 這么大的密鑰空間,但是依舊沒法破譯一次性密碼本。它的“神奇”之處在于,你在不斷嘗試的過程中,會嘗試出很多種情況,比如可能得到 abcdefg、aaaaa、plus、mine 這些原文,但是你無法判斷此時你是否破譯正確了。這也就是一次性密碼本無法破譯的原因,和密鑰空間大小無關。
一次性密碼本無法破譯這一特性是由香農(C.E.Shannon)于 1949 年通過數學方法加以證明的。一次性密碼本是 無條件安全的(unconditionally secure),理論上是無法破譯的(theoretically unbreakable) 。
(三) 缺點
一次性密碼本雖然這么強大,但是現實中沒有人用一次性密碼本進行加密。原因有一下幾點:
1. 密鑰如何發送給對方?
在一次性密碼本中,密鑰和原文是一樣長度的,試想如果有辦法能把密文安全的送達到對方,那么是否可以用這種方法把明文送達到對方呢?所以這是一個矛盾的問題。
2. 密鑰保存是一個問題
一次性密碼本的密鑰長度和原文一樣長,密鑰不能刪除也不能丟棄。丟棄了密鑰相當于丟棄了明文。所以“加密保護明文”的問題被轉換成了“如何安全的保護和明文一樣長度的密鑰”的問題,實際上問題還是沒有解決。
3. 密鑰無法重用
如果加密的原文很長,那么密鑰也要相同長度,并且密鑰每次還要不同,因為如果是相同的,密鑰一旦泄露7以后,過去所有用這個密鑰進行加密的原文全部都會被破譯。
4. 密鑰同步難
如果密鑰每次都變化,那么密鑰如何同步也是一個問題。密鑰在傳遞過程中不能有任何錯位,如果錯位,從錯位的那一位開始之后的每一位都無法解密。
5. 密鑰生成難
一次性密碼本想要真正的永遠無法破解,就需要生成大量的真正的隨機數,不能是計算機生成的偽隨機數。
據說國家之間的熱線電話用的就是一次性密碼本,但是是如何避免上述 5 點缺點的呢?國家會派專門的特工,用人肉的方式進行押送密鑰的任務,直接把密鑰交到對方的手中。
可見一次性密碼本雖然無法破譯,但是想要用它進行加密,“成本”非常高。如此可見一次性密碼本在日常使用中基本沒有任何使用價值。不過一次性密碼本的思路孕育了 流密碼(stream cipher) 。流密碼使用的不是真正的隨機比特序列,而是偽隨機數生成器產生的二進制比特序列。流密碼雖然不是無法破譯的,但只要使用高性能的偽隨機數生成器就能夠構建出強度較高的密碼系統。流密碼在下面章節會詳細分析。
三、對稱加密算法 DES
DES (Data Encryption Standard) 是 1977 年美國聯邦信息處理標準(FIPS)中所采用的一種對稱密碼(FIPS 46-3)。DES 一直以來被美國以及其他國家的政府和銀行所使用。
1997 年 DES Challenge I 比賽中用了 96 天破解了 DES 密鑰,1998 年的 DES Challenge II-1 比賽中用了 41 天就破解了密鑰。1998 年的 DES Challenge II-2 比賽中用了 56 個小時,1999 年的 DES Challenge III 比賽中只用了 22 小時 15 分鐘。目前來說,DES 已經不再安全了。除了用來解密以前老的 DES 密文以外,不再使用 DES 進行加密了。
(一) 加密
DES 是一種把 64 位明文加密成 64 位密文的對稱加密算法。它的密鑰長度為 64 比特,但是除去每 7 個二進制位會設置一個用于錯誤檢測的位以外,實際上密鑰為 56 比特。DES 會以 64 個二進制為一個 分組 進行加密。以分組為單位進行處理的密碼算法成為 分組密碼 ,DES 為分組密碼的一種。
DES 只能一次性加密 64 位明文,如果明文超過了 64 位,就要進行分組加密。反復迭代,迭代的方式成為 模式 。關于模式更加具體的討論見下一章節。
DES 加密的基本結構是 Feistel 網絡、Feistel 結構、Feistel 密碼 ,這個結構不僅僅用在 DES 中,還用在其他的加密算法中。
在 Feistel 網絡中,加密的各個步驟稱為 輪(round) ,整個加密過程就是若干次輪的循環。DES 是一種 16 輪循環的 Feistel 網絡。
上圖展示的是一次加密 64 位明文的過程。每次加密所用的密鑰都不同,由于它只在本輪使用,是一個局部密鑰,所以也被稱為子密鑰。
每輪的操作步驟如下:
- 將輸入的 64 位分為左右兩個 32 位。
- 將輸入右側的 32 位直接向下落到輸出的右側 32 位。
- 將輸入右側作為輪函數的入參輸入。
- 輪函數根據輸入右側的 32 位和 子密鑰兩個入參,生成一串看上去隨機的比特序列輸出。
- 將輪函數的輸出和輸入左側 32 位進行異或運算,結果向下落到輸出的左側 32 位。
這樣經過一輪以后,只加密了輸入的一半的數據,上例中右側就沒有被加密。我們可以用另外一個子密鑰加密右側的數據。
上圖是一個 3 輪的 Feistel 網絡。3 輪網絡有 3 個子密鑰和 3 個輪函數,中間有 2 次左右對調的過程。 注意:n 輪 Feistel 網絡只交換 n-1 次,最后一次不用交換 。
(二) 解密
DES 的解密過程和加密過程是相反的。解密也是 64 位分組解密。解密密鑰實質也是 56 位。
再來聊聊 Feistel 網絡的解密過程。
由于 XOR 具有交換律的特性,只要再次做一次異或運算,就能還原明文。
從上面這個圖中,可以看出 Feistel 網絡的加密和解密步驟完全相同 。
同樣也以 3 輪 Feistel 網絡的解密過程來舉例。
解密步驟也和加密步驟完全相同的,只不過子密鑰的順序是逆序的。因為要和之前加密的順序配合在一起。假設是 n 輪網絡,子密鑰 1 - n,要想還原成明文,異或的順序要逆序反過來,這樣才能利用 a ⊕ a = 0 ,異或的結合律,還原明文。
(三) 優點
Feistel 網絡的特點
- 加密的時候無論使用任何函數作為輪函數都可以正確的解密,無須擔心無法解密。就算輪函數輸出的結果無法逆向計算出輸入的值也無須擔心。Feistel 網絡把加密算法中核心的加密本質封裝成了這個輪函數,設計算法的人把所有的心思放在把輪函數設計的盡量負責即可。
- 加密和解密可以用完全相同的結構來實現。雖然每一輪只加密了一半的明文,放棄了加密效率,但是獲得了可以用相同結構來實現,對于加密硬件設備設計也變得更加容易。
由于 Feistel 網絡的這些優點,所以很多分組密碼選擇了它。比如 AES 候選算法中的 MARS、RC6、Twofish。不過最終 AES 定下的 Rijndael 算法并沒有選擇它,而是選擇的 SPN 網絡。
四、對稱加密算法 3DES
三重 DES (triple-DES) 是為了增加 DES 強度,所以將 DES 重復 3 次得到的一種算法。也稱為 TDEA (Triple Data Encryption Algorithm),通??s寫為 3DES。
(一) 加密
3DES 加密就是進行 3 次 DES 加密。DES 密鑰長度為 56 位,所以 3DES 密鑰長度為 56 * 3 = 168 位。
不過 3DES 有一個“奇怪”的地方,并不是用 DES 加密 3 次,而是加密-解密-加密,中間有一次解密的過程。IBM 公司之所以這么設計,目的是為了讓三重 DES 能兼容普通的 DES。如果三重加密中密鑰都完全相同,那么就退化成了普通的 DES 了。(加密一次解密一次就抵消了)所以也就具備了向下兼容性。
- 如果 3 次都用相同的密鑰,則退化成了 DES。
- 如果第一次和第三次用相同的密鑰,第二次用不同的密鑰,這種三重 DES 稱為 DES-EDE2 。EDE 是加密(Encryption) -> 解密(Decryption) -> 加密(Encryption) 的縮寫。
- 如果 3 次都用不同的密鑰,則稱 DES-EDE3。
(二) 解密
3DES 解密的過程和加密的過程正好相反,按照密鑰的逆序解密。
(三) 缺點
3DES 由于處理速度不高,除了兼容之前的 DES 以外,目前基本不再使用它了。
五、對稱加密算法 AES 和 Rijndael
AES (Advanced Encrytion Standard) 是取代前任標準 DES 而成為新標準的一種對稱密碼算法。在全世界的范圍內征集 AES 加密算法,最終于 2000 年從候選中選出了 Rijndael 算法,確定它為新的 AES。
1997 年開始征集 AES,1998 年滿足條件并最終進入評審的有 15 個算法:CAST-256、Crypton、DEAL、DFC、E2、Frog、HPC、LOK197、Magenta、MARS、RC6、Rijndael、SAFER+、Serpent、Twofish。2000 年 10 月 2 日,Rijndael 并定位 AES 標準。AES 可以免費的使用。
Rijndael 的分組長度和密鑰長度可以分別以 32 位比特為單位在 128 比特到 256 比特的范圍內進行選擇。不過在 AES 的規范中,分組長度被固定在 128 比特,密鑰長度只有 128、192 和 256 比特三種。
(一) 加密
AES 的加密也是由多個輪組成的,分為 4 輪,SubBytes、ShiftRows、MixColumns、AddRoundKey 這 4 步,即 SPN 網絡。
1. SubBytes 字節變換
Rijndael 的輸入分組默認為 128 比特,也就是 16 字節。第一步需要對每個字節進行 SubBytes 處理。以每個字節的值(0-255之間的任意值)為索引,從一張擁有 256 個值的替換表 S-Box 中查找出對應的值進行處理。
經過 SubBytes 變換以后,左邊 16 個字節(128 個比特)都變換成右邊的 16 個字節。
2. ShiftRows 移行操作
這一步以 4 字節為單位的行 row 進行左移操作,且每一行平移的字節數不同。
移動以后,每一行都“錯位”了。
3. MixColumns 混行操作
這一步以 4 字節為單位的列 column 進行矩陣運算。
經過這一步變換以后,每一列和之前的列都不同了。
4. AddRoundKey 異或運算
將上一步的輸出與輪密鑰進行 XOR,即進行 AddRoundKey 處理。
如上圖,左邊 16 字節每個字節一次與輪密鑰對應位置上的字節進行異或運算,計算完成以后得到最終的密文。
到這里為止,是一輪 Rijndael 結束。
完成的一輪解密如下圖:
一般整個算法要進行 10-14 輪計算。
(二) 解密
Rijndael 的解密過程為加密的逆過程。
在 Rijndael 加密過程中,每一輪處理的順序為:
SubBytes -> ShiftRows -> MixColumns -> AddRoundKey
在 Rijndael 解密過程中,每一輪處理的順序為:
AddRoundKey -> InvMixColumns -> InvShiftRows -> InvSubBytes
解密過程中除了第一步和加密完全一樣,其他三步都為加密的逆過程。
(三) 優點
SPN 網絡和 Feistel 網絡相比,加密效率更高,因為 SPN 一輪會加密所有位。所以加密所需輪數會更少。
還有一個優勢在于加密用的 4 步可以并行運算。
目前還沒有針對 AES 有效的攻擊破譯方式。
六、分組模式
由于 DES 和 AES 一次加密都只能加密固定長度的明文,如果需要加密任意長度的明文,就需要對分組密碼進行迭代,而分組密碼的迭代方式就稱為分組密碼的“模式”。
分組密碼有很多模式,如果模式選擇的不恰當就無法充分保障機密性。
**分組密碼(block cipher)**是每次只能處理特定長度的一塊數據的一類密碼算法,這里的“一塊”被稱為分組。一個分組的比特數稱為分組長度。例如 DES 和 3DES 的分組長度都是 64 位。AES 分組長度為 128 位。分組密碼處理完一個分組以后就結束,不需要記錄額外的狀態。
**流密碼(stream cipher)**是對數據流進行連續處理的一類密碼算法。流密碼中一般以 1 比特、8比特、32比特等單位進行加密和解密。例如一次性密碼本就屬于流密碼。流密碼處理完一串數據以后,還需要保持內部的狀態。
流密碼算法密鑰長度說明一次性密碼本和原文相同長度永遠無法破譯RC4可變密鑰長度,建議長度 2048 比特目前已經被證明不再安全ChaCha可變密鑰長度,建議長度 256 比特一種新型的流密碼算法
1. ECB 模式
ECB 模式是分組模式里面最簡單的,也是最沒有安全性的。所以使用的人很少。
ECB 模式全稱“Electronic CodeBook”模式,在 ECB 模式中,將明文分組加密之后的結果直接就是密文分組,中間不做任何的變換。
ECB 的加密和解密都非常直接。針對密文中存在多少種重復的組合就能以此推測明文,破譯密碼。所以 ECB 模式存在安全風險。
對 ECB 的攻擊
針對 ECB 的攻擊有很多種,最簡單的一種就是交換分組的位置。例如明文分組中 1,2 分組表示的明文消息是 付款方A 和 收錢方B,第 3 個分組中記錄著轉賬金額。攻擊者可以把 1,2 分組順序逆序一下,這樣消息的寓意完全顛倒。攻擊成功。
2. CBC 模式
CBC 模式的全稱是 Cipher Block Chaining 模式,密文分組鏈接模式。名字中也展示它的實質,像鏈條一樣相互鏈接在一起。
CBC 加密“鏈條”起始于一個初始化向量 IV,這個初始化向量 IV 是一個隨機的比特序列。
如果把 ECB 單個分組加密抽出來和 CBC 分組對比,如下:
ECB 模式只進行了加密,CBC 模式則在加密之前進行了一次 XOR。這樣也就完美了克服了 ECB 的缺點了。比如密文分組 1 和密文分組 2相同,ECB 加密以后 2 個密文分組也是相同的,但是 CBC 加密以后就不存在 2 個密文相同的情況,因為有 XOR 這一步。
CBC 加密必須是從“鏈條”頭開始加密,所以中間任何一個分組都無法單獨生成密文。
CBC 解密的時候,如果解密“鏈條”中間有一環“斷”了,會出現什么問題呢?
CBC 解密過程中如果有一環出現了問題,硬盤等問題出現了,但是整個鏈條長度沒變,如上圖的情況,那么一個壞的環會影響 2 個分組的解密。
如果鏈條長度也發生變化了,或者某個分組中的 1 個比特位在網絡傳輸過程中缺失了。那么影響的解密分組可能就不止 2 個分組了。因為會引起整個鏈條上重新分組,這樣一來導致原文無法解密(因為位數少于分組要求,解密的時候不會填充末尾分組不足的比特位)。
這一點算是 CBC 鏈式的一個“小缺點”。一個比特位的缺失會導致整個密文無法解析。
對 CBC 的攻擊
由于 CBC 是鏈式的,所以攻擊者可以考慮從“頭”開始攻擊,即攻擊初始化向量 IV,例如把初始化向量中的某些比特位進行 0,1 反轉。這樣的話,消息接收者在解密消息的時候,明文 1 分組會受到初始化向量的影響,出現錯誤。
還有一種攻擊辦法是直接攻擊密文。例如密文分組中的某個分組 n 被改變了,那么就會影響到明文分組 n+1 的解密。
分組密碼還存在一種模式叫 CTS 模式(Cipher Text Stealing 模式)。在分組密碼中,當明文長度不能被分組長度整除的時候,最后一個分組就需要進行填充,CTS 模式是使用最后一個分組的前一個密文分組數據來進行填充的,它通常和 ECB 模式以及 CBC 模式配合使用。根據最后一個分組的發送順序不同,CTS 模式有幾種不同的變體(CBC-CS1、CBC-CS2、CBC-CS3),下面舉一個 CBC-CS3 的例子:
3. CFB 模式
CFB 模式的全程是 Cipher FeedBack 模式(密文反饋模式)。在 CFB 模式中,前一個密文分組會被送到密碼算法的輸入端。所謂反饋,這里指的就是返回輸入端的意思。
注意上圖中解密過程,中間是加密而不是解密!因為這里需要保證明文和密文之間異或的對象不變。不變才能異或兩次還原明文。
如果把 CBC 單個分組加密抽出來和 CFB 分組對比,如下:
從上圖中我們可以看到,在 ECB 和 CBC 模式中,明文分組都是要通過加密算法處理的,但是 CFB 模式明文分組是沒有經過加密算法直接加密的。CFB 模式中,明文和一串比特序列 XOR 以后就變成了密文分組。
CFB 與流密碼
CFB 整個過程很像一次性密碼本,如果把明文分組前的加密部分全部都看成一個隨機比特序列,那么就和一次性密碼本的流程一樣了。這個由算法生成的比特序列稱為 密鑰流 。在 CFB 模式中,密碼算法就相當于用來生成密鑰流的偽隨機數生成器,初始化向量相當于是偽隨機數生成器的種子。也因為它是偽隨機數,所以 CFB 是不具備一次性密碼本絕對無法被破譯的性質的。所以說, CFB 是一種使用分組密碼來實現流密碼的方式之一 。
對 CFB 的攻擊
可以對 CFB 實施 重放攻擊(replay attack) 。
例如攻擊者可以把上一次會話中的部分分組截取出來放進下次會話隨機位置。這樣消息接收者在拿到密文以后進行解密,會導致其中一個分組出現錯誤(上圖中是明文分組 2 解密失敗),這個時候無法判斷是通信出錯還是被人攻擊所致。(想要判斷需要用到消息認證碼才行,而此處只是單純的 CFB)
4. OFB 模式
OFB 模式的全程是 Output-FeedBack 模式(輸出反饋模式)。在 OFB 模式中,密碼算法的輸出會反饋到密碼算法的輸入中。這里可以類比 CFB 模式。
OFB 也不直接對明文進行加密,也是通過利用明文和一串比特序列進行異或運算來得到密文。
同樣需要注意的是, OFB 的解密過程中,也是用加密,而不是解密 。原因和 CFB 是一樣的。因為異或運算只有異或相當的數才能還原明文。
OFB 與 CFB 對比
OFB 模式和 CFB 模式的區別僅僅在于密碼算法的輸入。OFB 模式是密碼算法的輸入是前一個密碼算法的輸出,所以稱為輸出反饋模式。CFB 模式是把前一個,密文分組輸入到密碼算法中,所以稱為輸入反饋模式。下圖是兩者的對比:
從上圖中我們可以看到,CFB 模式加密的過程是無法跳過某個分組對后面的分組加密的。因為它需要按照順序進行加密。密文分組會重新輸入到加密算法中。
而 CFB 模式就不同,加密算法和密文分組完全是分開的,也就是說只要生成好每次 XOR 運算所需的密鑰流,就可以“跳躍”加密任意分組了。這個看來,生成密鑰流的操作和進行 XOR 運算的操作是可以并行的。
5. CTR 模式
CTR 模式的全程是 CounTeR 模式(計數器模式)。CTR 模式是一種通過將逐次累加的計數器進行加密來生成密鑰流的流密碼。
注意上圖中解密過程,中間是加密而不是解密!因為這里需要保證明文和密文之間異或的對象不變。不變才能異或兩次還原明文。
計數器每次都會生成不同的 nonce 來作為計數器的初始值。這樣保證每次的值都不同。這種方法就是用分組密碼來模擬生成隨機的比特序列。
OFB 與 CTR 對比
CTR 模式和 OFB 模式都屬于流密碼。我們單獨看兩個加密過程,差異在輸入到加密算法中的值不一樣。CTR 模式輸入的值是計數器累加的值,而 OFB 模式輸入的值是上一次輸出的值。
CTR 模式加密和解密都用了完全相同的結構,這樣對程序實現來說,方便很多。更進一步,由于 CTR 模式每個密鑰有累加的關系,所以可以通過這個關系,對任意一個分組進行加密和解密。因為只要初始的密鑰確定以后,后面的每個密鑰都確定了。這樣看來,CTR 也是支持并行計算的。
對 CTR 的攻擊
在被攻擊方面 CTR 和 OFB 是差不多的。CTR 模式的密文分組中有一個比特被反轉了,則解密以后明文分組中僅有與之對應的比特會被反轉,這個錯誤不會被放大。
不過 CTR 模式比 OFB 模式相比有一個更好的優點在于,如果 OFB 模式某次密鑰流的一個分組進行加密以后生成的結果和前一次一樣,那么這個分組之后的每次密鑰流都不變了。CTR 模式就不會存在這一問題。
針對 CTR 模式,在它上面再加上認證功能,就變成了 GCM 模式(Galois/Counter Mode),這個模式能夠在 CTR 模式生成密文的同時生成用于認證的信息。從而判斷“密文是否通過合法的加密過程生成”。通過這一機制,即便主動攻擊者發送偽造的密文,我們也能識別出“這段密文是偽造的”。
6. 小結
模式名稱特點說明ECB 模式Electronic Codebook運算快速,支持并行運算,需要填充不推薦使用CBC 模式Cipher Block Chaining支持并行運算,需要填充推薦使用CFB 模式Cipher Feedback支持并行運算,不需要填充不推薦使用OFB 模式Output Feedback迭代運算使用流密碼模式,不需要填充不推薦使用CTR 模式Counter迭代運算使用流密碼模式,支持并行運算,不需要填充推薦使用XTS 模式XEX-based tweaked-codebook不需要填充用于本地硬盤存儲解決方案中