對稱加密(2) 對稱加密算法
經典的對稱加密算法是DES算法,后來又衍生出3DES、TripleDES等增強型的DES算法。此外,.NET還提供了RC2、Rijndael等對稱加密算法。下面分別詳細介紹。
DES加密算法
對稱加密算法中最經典的算法莫過於DES加密算法。DES加密采用的是分組加密的方法,使用56位密鑰加密64位明文,最后產生64位密文。DES算法的基本流程如圖6-2所示。
圖6-2 DES加密算法基本流程
現在對圖6-2的整個流程做簡要的分析。DES對64位的明文分組M進行操作,M經過一個初始置換IP置換成m0,將m0明文分成左半部分和右半部分m0=(L0,R0),各32位長。然后進行16輪完全相同的運算,這些運算稱為函數f,在運算過程中,數據與密匙結合。經過16輪運算之后,可以看到第16輪運算,將右側第15輪運算的結果(R15)作為左側運算的最終結果(L16),而右側最后的結果(R16)為左側第15輪運算結果(L15)和函數f運算結果的異或運算所得。此后,再將左、右部分合在一起經過一個逆置換,輸出密文。
實際加密過程要分成兩個同時進行的過程,即加密過程和密鑰生成過程,如圖6-3所示。結合圖6-2和圖6-3簡單講解密鑰生成過程。
圖6-3 加密與密鑰生成
如圖6-3所示,在16輪循環的每一輪中,密匙位移位,然后再從密匙的64位中選出48位。通過一個擴展置換將數據的右半部分擴展成48位,並通過一個異或操作替代成新的32位數據,在將其置換一次。這四步運算構成了圖6-2中的函數f。然后,通過另一個異或運算,函數f的輸出與左半部分結合,其結果成為新的右半部分,原來的右半部分成為新的左半部分。該操作重復16次。
DES算法的解密過程和加密過程幾乎完全相同,只是使用密鑰的順序相反。
關於DES算法的更加詳細的細節不在本書的講解范圍之內,請讀者參考相關資料。
NIST(National Institute of Standards and Technology,美國國家標准技術研究院)在1999年發布了新的DES加密標准,3DES取代DES成為新的加密標准。3DES采用168位的密鑰,三重加密,但速度較慢。之后,又出現了AES(Advanced Encryption Standard,先進加密標准)等高級對稱機密算法。
TripleDES加密算法
由於DES算法安全性方面的原因,為了提高DES算法的抗攻擊性,因此提出了Triple-DES算法。
Triple-DES算法的基本原理是:用兩個密鑰對數據進行3次加密/解密運算。即首先使用第一個密鑰對數據進行加密,然后用第二個密鑰對其進行解密,最后用第一個密鑰再加密。這兩個密鑰可以是同一個,也可以不同,它們也可以來源於一個128位密鑰,只是在加密/解密時將其分割成兩個64位的密鑰,分別輪換使用這兩個64位密鑰去完成加密/解密運算。Triple-DES算法保留了DES算法運算速度快的特點,通過增加運算次數和密鑰長度(兩個64位密鑰相當於128位密鑰)來增加破解者的破解時間,但是從密碼學本身來說,其安全強度並沒有增加。
RC系列算法
現在我們用到的RC系列算法包括RC2、RC4、RC5、RC6算法,其中RC4是序列密碼算法,其他三種是分組密碼算法。
(1) RC2算法
該算法設計的目的是用來取代DES算法,它采用密鑰長度可變的對明文采取64位分組的分組加密算法,屬於Festel網絡結構。
(2) RC4算法
該算法是一個密鑰長度可變的面向字節流的加密算法,以隨機置換為基礎。該算法執行速度快,每輸出1字節的結果僅需要8~16字節的機器指令。RC4算法比較容易描述,它首先用8~2048位可變長度的密鑰初始化一個256字節的狀態矢量S。S的成員標記為S[0],S[1],…,S[255],整個置換過程都包含0~255的8比特數。對於加密和解密,設字節數據為K,由S中256個元素按一定方式選出一個元素生成,每生成一個K值,元素中的數據就要被重新置換一次。RC4初始化的偽代碼如代碼清單6-1所示。
代碼清單6-1 RC4初始化的偽代碼
for i=0 to 255
{
S[i]=i;
T[i]=K[i mod KeyLen ];
}
j=0;
for i=0 to 255
{
j=(j+T[i]+S[i]) mod 256;
swap(S[i],S[j];
}
如代碼清單6-1所示,初始化開始時,S的元素按從0到255依次賦值,同時建立一個臨時矢量T。如果密鑰K的長度為256字節,則將K賦值給T。否則,若密鑰長度為KeyLen字節,則將K的值賦給T的前KeyLen個元素,並循環重復用K余下的元素賦給T剩下的元素。從“j=0”開始,用T產生S的初始置換。從S[0]~S[255],對每個S[i]根據T[i]確定的方案,將S[i]置換成S中的另一字節。
在完成S的初始化之后,輸入密鑰將被拋棄,接下來將使用密鑰流,生成密鑰流的偽代碼如代碼清單6-2所示。
代碼清單6-2 生成密鑰流
i=0;
j=0;
while(true)
{
i=(i+1) mod 256;
j=(j+S[i]) mod 256;
swap(S[i],j[i];
T=(S[i]+S[j]) mod 256;
K=S[T];
}
如代碼清單6-2所示,密鑰流的生成是從S[0]到S[255],對每個S[i]根據當前S的值將S[i]與S中的另一字節替換,當S[255]完成置換后操作繼續重復。在加密過程中將K的值與下一明文字節異或,解密過程中將K的值與下一密文字節異或即可。
(3) RC5算法
該算法是一種分組長度、密鑰長度、加密迭代輪數都可變的分組加密算法。該算法主要包含三部分內容:密鑰擴展、加密算法和解密算法。該算法包含三個參數:w(字的長度,單位:位)、r(迭代次數)、b(密鑰長度,單位:字節)。由於RC5算法需要(2r+2)個w位密鑰,所以需要密鑰擴展。
通過密鑰擴展,把密鑰K擴展成密鑰陣S,它由K所決定的t=2(r+1)個隨機二進制字構成。密鑰擴展算法利用了兩個幻常數:
函數Odd(x)的結果為與x最近的奇整數。密鑰擴展的第一步是將密鑰K轉換成字格式,利用K的各字節構造字陣L。密鑰擴展的第二步是利用模232線性同余算法初始化S陣。密鑰擴展的第三步是L陣和S陣混合。
加密過程也很簡單。假設選用的數據分組長度為2w位(w允許的值有16、32和64),迭代次數為r輪(r為0~255)。首先將明文划分成兩個w位的字A和B,運算過程如代碼清單6-3所示。
代碼清單6-3 RC5算法加密過程
A=A+S0;
B=B+S1;
for i=1 to r
{
A=((A+B)<<<B))+S2i;
B= ((B+A) <<<A)) +S2i+1;
}
代碼清單6-3的結果輸出到寄存器A和B中。
解密過程是加密過程的逆運算,基本過程如代碼清單6-4所示。
代碼清單6-4 RC5算法解密過程
for i=r down to 1
{
B=((B- S2i+1)>>>A)+A;
A=((A- S2i)>>>B)+B;
}
B=B-S1;
A=A-S0;
說明 加密和解密過程中的加減都是模2w的,表示逐位異或。<<<表示循環左移,>>>表示循環右移。
(4) RC6算法
RC6秉承了RC5設計簡單、廣泛使用數據相關的循環移位思想,同時增強了抵抗攻擊的能力,改進了RC5中循環移位的位數依賴於寄存器中所有位的不足。
RC6的特點是輸入的明文由原先2個區塊擴展為4個區塊,另外,在運算方面則是使用了整數乘法,而整數乘法的使用則在每一個運算回合中增加了擴散(diffusion)的行為,並且使得即使很少的回合數也有很高的安全性。同時,RC6中所用的操作可以在大部分處理器上高效率地實現,提高了加密速度。RC6是一種安全、架構完整而且簡單的區塊加密法。它提供了較好的測試結果和參數方面相當大的彈性。RC6可以抵抗所有已知的攻擊,能夠提供AES所要求的安全性,可以說是近幾年來相當優秀的一種加密法。
Rijndael算法
Rijndael是一個反復運算的加密算法,它允許可變動的數據區塊及密鑰的長度。數據區塊與密鑰長度的變動是各自獨立的。
在Rijndael算法中定義了兩個名詞:
1) State:在運算過程中所產生的中間值,是一個4×Nb的矩陣,Nb可由數據長度除以32位求得,也就是把數據分割成Nb個區塊。
2) Cipher Key:用來做加密運算的密鑰,形式是一個4×Nk的矩陣,Nk可由金鑰長度除以32位求得,也就是把密鑰分割成Nk個32位的子密鑰。
在Rijndael算法中,運算的回合數(Nr)是由Nb及Nk決定的,回合數的變動定義如表6-1所示。
表6-1 Rijndael算法回合變動定義
Nr |
Nb=4 |
Nb=6 |
Nb=8 |
Nk=4 |
10 |
12 |
14 |
Nk=6 |
12 |
12 |
14 |
Nk=8 |
14 |
14 |
14 |
在Rijndael中使用了許多字節層級的運算,而這些運算是以GF(28)為基礎架構。也有一些采用了4-byte的字組運算。各種運算的定義如下:
(1) GF(28)的定義
假設一個字節b由b7b6b5b4b3b2b1b0組成,可以把這些bi想象成一個7次多項式的系數,而這些系數不是0就是1:
b7 x7+ b6 x6+ b5 x5+ b4 x4+ b3 x3+ b2 x2+ b1 x + b0
例如,(57)16的二進制表示法為(0101,0111)2,表示成多項式,則為:
x6+ x4+ x2+ x + 1
(2)加法
兩個多項式的加法,則是定義為相同指數項的系數和再模2,簡單地說,就是作EXOR運算(1+1=0)。例如:
(57)16+(83)16=(01010111)2+(10000011)2 = (11010100)2 = (D4)16
或是
(x6+x4+x2+x+1)+(x7+x+1)=x7+x6+x4+x2
(3)乘法
在乘法運算中,多項式相乘之后的結果很容易造成溢位的問題,解決溢位的方式是把相乘的結果,再模余一個不可分解的多項式m(x)。在Rijndael中,定義一個這樣的多項式為m(x)=x8+x4+x3+x+1或是(11B)16例如:
(57)16‧(83)16
=(x6+ x4+ x2+ x + 1)‧(x7+ x + 1)
=x13+ x11+ x9+ x8+ x7+x7+ x5+ x3+ x2+x+x6+ x4+ x2+ x + 1
=(x13+x11+x9+x8+x6+x5+x4+x3+1+x13+x11+x9+x8+x6+x5+x4+x3+1)mod(x8+x4+x3+x+1)
= x7+ x6+ 1
=(C1)16
(4)乘以x
若把b(x)乘以x,得到
b7 x8+ b6 x7+ b5 x6+ b4 x5+ b3 x4+ b2 x3+ b1 x2 + b0x
若b7=0,不會發生溢位問題,答案即是正確的;若b7=1,發生溢位問題,必須減去m(x)。可以把這種運算表示為xtime(x),其運算方式為left shift(若溢位則和(1B)16做EXOR運算),例如:
‘57’· ‘13’ = ‘FE’
‘57’ · ‘02’ = xtime(57) = ‘AE’
‘57’ · ‘04’ = xtime(AE) = ‘47’
‘57’ · ‘08’ = xtime(47) = ‘8E’
‘57’ · ‘10’ = xtime(8E) = ‘07’
‘57’ · ‘13’ = ‘57’ · (‘01’⊕‘02’⊕‘10’) = ‘57’⊕‘AE’⊕‘07’ = ‘FE’
Rijndael算法分為四個步驟:
步驟 1 字節轉換。
字節轉換是一個以字節為單位的非線性取代運算,取代表(S-box)是經過2個運算過程而建立,並且是可逆的。首先找出每個字節在GF(28)中的乘法反元素;接着經過1個仿射(Affine)轉換運算,轉換運算的定義如圖6-4所示。
圖6-4 轉換運算定義
取代表生成之后就可以進行字節取代運算。取代運算的示意圖如圖6-5所示。
圖6-5 取代運算示意圖
進行如圖6-5的取代運算之后,結果如圖6-6所示。
圖6-6 取代運算后的S-Box
說明 字節取代轉換的反運算:計算仿射對應之后的相反運算可得到S-1-box,以此S-1-box做字節取代(Subbytes)即可。
步驟 2 移行轉換。
在這個轉換中,State的每一行以不同的偏移量做環狀位移:第0 行不動,第1 行位移1 C個字節,第2 行位移2 C個字節,第3 行位移3 C個字節。位移的偏移量C1,C2,C3跟區塊的數目(Nb)有關,關系見圖6-7。
圖6-7 C1、 C2、 C3與區塊數目(Nb)的關系
移行轉換(Shift rows)運算對於State 的影響如圖6-8所示。
圖6-8 移行轉換對State的影響
說明 移行轉換的反運算:對第2、第3 及第4 行做Nb-C1、、Nb-C2、Nb-C3個字節的環狀位移即可。
步驟 3 混列轉換。
在這個轉換中,把State當做一個GF(28)中的多項式。並且對一個固定的多項式c(x)作乘法,如果發生溢位,則再模x4 +1. 表示如下:
c(x) ='03' x3 +'01' x2 +'01' x +'02'
c(x)與x4 +1互質,令
b(x) = c(x)⊕ a(x)
以矩陣乘法表示如圖6-9所示。
圖6-9 混列轉換的矩陣乘法表示
State經過混列(Mix columns)運算之后的變化如圖6-9所示。
圖6-9 混列運算對State的影響
說明 混列轉換的反運算是乘以一個特殊的多項式d(x):
('03' x3 +'01' x2 +'01' x +'02' )⊕ d(x)
='01' d(x)
='0B' x3 +'0D' x2 +'09' x +'0E'。
步驟 4 輪密鑰加。
這個運算主要是把每一個回合密鑰(Roundkey)透過簡單的Bitwise exor加入到每一個State中,如圖6-10所示。
圖6-10 Bitwise exor加入后的State
說明 此時Add round key的逆是它自身。