深入淺出AES算法
AES算法
高級(jí)加密標(biāo)準(zhǔn)(Advanced Encryption Standard,AES)是美帝2001年發(fā)布的塊加密算法,AES是屬于塊加密算法框架中的一個(gè)組件,所以理解AES的關(guān)鍵是搞清楚塊加密算法。(塊加密算法是一個(gè)“框”,AES只是“框”中的一個(gè)東西)
塊加密算法工作原理
塊加密算法也叫分組密碼工作模式(block mode of operation)它會(huì)把明文按等長(zhǎng)的塊(Block)分組然后利用某種加密算法進(jìn)行加密——AES就屬于“某種加密算法”中的一種。用一幅圖表示二者關(guān)系:
塊加密算法有三個(gè)關(guān)鍵部分
- 填充方式,負(fù)責(zé)把明文切分成一塊一塊的。塊加密要求數(shù)據(jù)一定要符合塊大小,以AES為例它規(guī)定每個(gè)數(shù)據(jù)塊的大小是128個(gè)bit位(16字節(jié)),如果數(shù)據(jù)不足16字節(jié)那么必須**填充**到16字節(jié)。填充的數(shù)據(jù)是字節(jié)長(zhǎng)度,比如一個(gè)5字節(jié)的塊需要填充到16個(gè)字節(jié),那么剩下的9個(gè)字節(jié)就全部寫上09 09 09……。 PKCS5Padding和PKCS7Padding是分別出在不同規(guī)范的兩個(gè)標(biāo)準(zhǔn),PKCS5規(guī)定了塊大小是8字節(jié);PKCS7沒(méi)有限制。由于AES已經(jīng)限制了塊的大小,所以它們兩個(gè)在AES里面其實(shí)沒(méi)有什么區(qū)別。所以在Java里面只提供了AES+PKC5Padding(AES+PKCS7Padding,這個(gè)說(shuō)法不對(duì),AES已經(jīng)限制了塊大小)。
- 加密算法,負(fù)責(zé)對(duì)每一塊的明文進(jìn)行加密。對(duì)算法輸入明文和密鑰,算法輸出加密后的密文塊,常見(jiàn)的算法是AES、DES。
- 工作方式,塊加密非常靈活利用不同的工作模式可以實(shí)現(xiàn)**并行、密文可變(每次加密得到的密文都不一樣)、容錯(cuò)**
塊加密算法的五種工作方式
按照塊加密算法的不同工作模式常見(jiàn)的有5種(為了簡(jiǎn)化問(wèn)題我只貼加密過(guò)程):
Key是密鑰,Plaintext是明文,中間的Block Cipher Encryption是加密算法(比如AES就是其中一種)。密鑰和明文作為輸入經(jīng)過(guò)加密之后得到密文——Ciphertext。
ECB工作模式非常簡(jiǎn)單,可以并行處理;一個(gè)線程負(fù)責(zé)把數(shù)據(jù)切分成N塊后由N個(gè)線程同時(shí)進(jìn)行加密。它的缺點(diǎn)是同樣的密鑰每次執(zhí)行加密出來(lái)的數(shù)據(jù)都是相同的。正常人看——比如我,這太正常了,但是“密碼專家”們認(rèn)為這太弱雞了(囧)。所以他們?cè)O(shè)計(jì)了一種特別的算法,通過(guò)一個(gè)叫“初始向量(IV,Initialization Vector)”的變量讓每次進(jìn)行加密得到的密文都不一樣(即便密鑰相同)。剩下的4種塊工作模式都屬于這種牛B的類型。
這里的輸入多了一個(gè)叫Initialization Vector(IV)的變量;明文和IV異或之后通過(guò)作為加密算法的一個(gè)變量輸入,密鑰作為另一個(gè)變量輸入。
CBC加密算法是一個(gè)串行算法,第二塊的加密依賴于***塊密文作為IV。所以計(jì)算它的時(shí)候只能按部就班一塊一塊的計(jì)算。
之前的塊加密都沒(méi)有解決容錯(cuò)問(wèn)題——如果我一個(gè)數(shù)據(jù)塊壞掉了那么能不能解密出其余的數(shù)據(jù)塊。于是就有了CFB工作模式,注意觀察上圖,解密的時(shí)候如果***個(gè)密文塊損壞那么可以無(wú)視這塊內(nèi)容,直接用第二個(gè)密文作為輸入對(duì)第三個(gè)密文塊進(jìn)行解密。
CBC雖然狂屌炸(每次都能算出不同的密文)但是不能并行,對(duì)于“時(shí)間就是金錢”的計(jì)算機(jī)來(lái)說(shuō)是無(wú)法容忍的。于是就有了***次改進(jìn)——OFB。
注意IV和密鑰經(jīng)過(guò)加密后這里是可以并行的,其中一個(gè)線程用于和明文的異或;一個(gè)線程可以立馬計(jì)算“下次”加密。
OFB算法的并行度太低,僅僅實(shí)現(xiàn)一部分并行,于是就有了第二次改進(jìn)——CTR算法,同時(shí)保證了并行度和密文可變性。
CTR算法中的IV變成了兩部分,***個(gè)是Nonce可以是一個(gè)隨機(jī)序列,第二部分是計(jì)數(shù)器(Countter),是一個(gè)遞增的數(shù)字。于是加密的時(shí)候通過(guò)組合Nonce和計(jì)算器就可以對(duì)得到有規(guī)律但是不相同的(每次密文都不同的關(guān)鍵是IV的可變)“IV”。
總結(jié)
從三個(gè)維度理解五種工作模式——密文是否固定、是否可以并行、有沒(méi)有容錯(cuò)
- ECB密文固定,全并行
- CBC密文可變,不可并行
- CFB密文容錯(cuò),密文可變,不可并行
- OFB密文可變,部分并行
- CTR密文可變,全并行
需要注意的是除非數(shù)據(jù)量特別大否則我們不必在乎是否并行;容錯(cuò)在小數(shù)據(jù)量的時(shí)候也凸顯不出效果,所以CBC一般是***的選擇。
如何跨語(yǔ)言
很多朋友都碰到一個(gè)語(yǔ)言寫的AES加密在另個(gè)一語(yǔ)言解密不了的問(wèn)題,究其原因是由于根本沒(méi)有理解AES的工作模式(可能就是Google了一下AES加密,然后代碼貼上收工)。所以我覺(jué)得跨語(yǔ)言的***步不是找到一種能在所有語(yǔ)言通用的工作模式——所有工作模式每個(gè)語(yǔ)言幾乎都支持;而是搞清楚你加密出來(lái)的數(shù)據(jù)是那種工作模式,有沒(méi)有用到IV?IV是通過(guò)什么方式傳遞給對(duì)方的?
比如下面的Java代碼:
我使用了CBC加密模式,這種模式涉及到IV,我們可以用一個(gè)固定的IV(比如用key作為IV)——但是意味著沒(méi)有了CBC的好處,密文可變。所以我用一個(gè)隨機(jī)16字節(jié)作為IV,返回的時(shí)候把它作為***個(gè)數(shù)據(jù)塊;解密的時(shí)候只要取出***個(gè)數(shù)據(jù)塊作為IV,然后再對(duì)余下的數(shù)據(jù)進(jìn)行解密。
如果我們不指定IV參數(shù)(init函數(shù)的第三個(gè)參數(shù)),那么iv就是一個(gè)隨機(jī)數(shù)。Java是不會(huì)主動(dòng)把IV附加到密文上,所以這種加密出來(lái)的數(shù)據(jù)是誰(shuí)也沒(méi)有辦法解出來(lái)的。
【本文是51CTO專欄作者“邢森”的原創(chuàng)文章,轉(zhuǎn)載請(qǐng)聯(lián)系作者本人獲取授權(quán)】