1.DES簡介
DES是一種將64比特的明文加密成64比特密文的分組密碼算法,它的密鑰長度是56比特。盡管從規格上來說,DES的密鑰長度是64比特,但由於每隔7比特會設置一個用於錯誤檢查的比特,因此實質上其密鑰長度是56比特。
DES算法的核心主要包括兩部分,第一部分是Feistel結構,第二部分是16個子密鑰的生成。
2.總體流程

圖1所展示的是DES算法的總體流程。它主要包含兩部分內容。左側是一個Feistel結構,在Feistel結構中加密的各個步驟稱為輪,整個加密過程就是進行若干次輪的循環,DES是一種16輪循環的Feistel結構。如圖1左側所示,64比特的明文會首先經過一個初始置換,它的作用是對數據打亂重排。經過初始置換后數據被分為左右兩部分,每一部分均為32比特,左側以字母L表示,右側以字母R表示,又因為要經過若干輪迭代所以為L和R標記一個下標,下標從0開始代表第一輪迭代。右側所展示的是密鑰生成的部分,64比特的密鑰會通過一個子密鑰擴展算法進而產生出16個48比特的子密鑰K0到K15
對每一輪Feistel結構把Ki 輸進去,在將Li 、Ri 輸進去就可以得到Li+1 、Ri+1 總共迭代16輪。值得注意的一點是在最后一輪不在做左右交叉,最終計算出來的L16 和R16 在做一次逆初始置換就得到了最終的64比特密文。
以上就是DES算法的總體流程。通過對以上流程的理解我們可以把DES划分為兩個基本模塊來理解。一塊是怎么把64比特的密鑰擴展成16個48比特的子密鑰,另一塊是怎樣進行16輪的Feistel結構迭代。
注意圖中紅色線與綠色線,我們以第一輪為例其實不難發現其中R0並沒有做任何的運算便到了下一輪的L1,L0的計算則稍顯復雜,它首先要與函數F進行異或,而函數F是根據子密鑰與R0得到的。於是,對每一輪Feistel結構我們都有如下的數學等式,這其實是一個數學描述,描述的是DES加密過程,在這里通過與前面用文字語言來描述DES加密過程相比較,使用數學語言不但可以以更簡單的方式描述DES算法,而且對於編程實現也有極大的易處。
3.密鑰擴展
密鑰擴展總體上分為三步第一步置換選擇1、第二步循環移位、第三步置換選擇二,圖二所展示的是密鑰擴展的整體流程。

如果你擁有古典密碼學基礎可能會發現密鑰擴展本質上就是使用了古典密碼中的置換與移位。
我們首先看一下第一個置換選擇是怎么做的。置換選擇1的作用有兩個第一個打亂重排,第二個是將每8比特的最后一位去掉用於做奇偶校驗,這樣就將原來的64比特變為了56比特。經過置換選擇1后將56比特密鑰分成左右兩部分,左側用C表示右側用D表示,而每一側均為28比特。這里要額外說明一下DES中會事先定義很多置換表,下面表1便是置換選擇1的表格。我們可以將這個表格看做一個矩陣,矩陣第一個數字是57,表明原密鑰中的第57位移動到矩陣的第一位。

第一步結束后就要分別對左右兩部分數據進行循環移位,而每一輪移位的步數是不同的(見表2)。循環操作是根據循環移位表實現的,需要強調的一點是循環移位操作是對Ci、Di 分別循環移位。迭代次數為1時對於C0 循環移位得到C1 ,對於D0 循環移位得到D1。

最后一步是根據表3從Ci 和Di 中分別取出24比特形成48位的子密鑰Ki 。

以上就是DES密鑰的生成的過程。總共分三步:
1.64比特的密鑰通過置換選擇1篩掉8比特的奇偶校驗得到左右各28比特。
2.按照固定的步數進行循環移位。
3.使用置換選擇2篩選出48比特。
一共做16次就得到了16個48比特的鑰匙。
4.16輪Feistel
通過觀察前面的圖1。我們也可以將整個Feistel結構分成三個部分第一步是初始置換,第二步是輪函數F與Li做異或,第三步是逆置換,其中第二步循環執行16次。
先來理解一下初始置換與逆初始置換,初始置換就是根據表4把64位明文打亂重排並分為左右兩部分L0 、R0 ,逆初始始置換就是根據表5將的迭代后輸出的密文在打亂重排一下。初始置換與逆初始置換是互逆的。


在前面的數學描述中有一個很重要的數學抽象,那就是輪函數F。函數F有兩個輸入一個是48比特的密鑰,另一個是32比特的數據Ri,而輸出因為要和Li做異或,所以函數F會輸出一個32比特的數據。圖3所展示的就是函數F的運算流程。

從圖中可以總結出函數F主要分為三步。第一步是一個擴展置換,將32比特的數據擴充為48比特數據並與子密鑰做異或。擴充是通過表6實現的主要是通過使用重復數據實現擴充。

第二步將48比特數據分成8組,每一組6比特進入一個S盒共8個S盒,每一個S盒輸出4比特,8個S盒共輸出32比特。S盒是DES中唯一的非線性變換,是DES的核心,DES中共有8個S盒每個S盒都是不同的。表7所展示的是第一個S盒。因為一個S盒的輸入是6比特,所以可以用b1b2b3b4b5b6來表示這6比特的每一位。用b1b6組成的二進制數為行號,b2b3b4b5組成的二進制數為列號,行列交叉點即為輸出。

第三步根據表8進行打亂重排后與Li做異或。

5.關於解密
DES算法是一個對合運算,即加密和解密過程是一樣的。唯一的不同是子密鑰的使用順序不同,比如加密時使用K0K1...K15對數據進行加密,則解密時使用K15K14...K0對數據進行解密。
6.結語與參考
關於代碼的實現主要參考golang des包。本文對於加密模式、S盒的性質以及對合運算的證明等此類問題沒有深入探討。不過個人認為下面的參考可以解決以上諸多問題。
1.圖解密碼技術 第3.5節 第四章
2.應用密碼學:協議、算法與C源程序 第十二章
3.https://www.bilibili.com/video/BV1Kt411h7nP?from=search&seid=5692038074087274413 第3.1章