博客地址:http://davidleee.com
原文鏈接:http://davidleee.com/2016/04/26/about-aes-encryption/
前段時(shí)間參加了部門(mén)的幾次分享會(huì)敢订,主題圍繞著數(shù)字簽名、數(shù)字證書(shū)和 https 相關(guān)的知識(shí)炒事。這些方面的內(nèi)容都不可避免的要涉及到數(shù)據(jù)加解密颗管,于是趁熱打鐵,準(zhǔn)備進(jìn)行一次加解密相關(guān)基礎(chǔ)的學(xué)習(xí)和分享蜂挪。順便擴(kuò)充一下博客數(shù)量重挑。
這一篇是針對(duì) AES 的學(xué)習(xí)筆記,主要的知識(shí)來(lái)源是維基百科和各種網(wǎng)絡(luò)資源棠涮。
因?yàn)闀r(shí)間有限谬哀,所以研究的不是非常深入,如果有不準(zhǔn)確和錯(cuò)誤的地方严肪,希望能指出來(lái)一起討論學(xué)習(xí)玻粪。
前世今生
AES 的出現(xiàn)就是為了取代原來(lái)的數(shù)據(jù)加密標(biāo)準(zhǔn)(DES),作為爺爺級(jí)的加密算法诬垂,DES 在風(fēng)光過(guò)后也是到了該退休的年紀(jì)了劲室。
關(guān)于 DES
在繼續(xù)了解 AES 之前,不妨先看看被它取代的 DES 是什么结窘。
它的全稱(chēng)為 Data Encryption Standard 很洋,是一種對(duì)稱(chēng)密鑰加密塊算法,大致的加密流程長(zhǎng)這個(gè)樣子:
在進(jìn)入到加密流程之前隧枫,64位的塊被拆分為兩個(gè)32位的子塊喉磁,并作為 IP 的兩個(gè)輸入。中間的 F 是 Feistel function官脓,算法中的密鑰就是在這個(gè)函數(shù)中被用到的协怒。
塊加密:Block cipher, 也叫作分組加密卑笨,是將明文分成多個(gè)等長(zhǎng)模塊(block)孕暇,使用確定的算法和對(duì)稱(chēng)密鑰對(duì)每組分別加密解密的方式。
DES 在1976年曾經(jīng)風(fēng)光一時(shí),被美國(guó)聯(lián)邦政府的國(guó)家標(biāo)準(zhǔn)局定為 聯(lián)邦資料處理標(biāo)準(zhǔn)(FIPS)妖滔。然而因?yàn)樗皇怯昧?6位的密鑰隧哮,所以在當(dāng)下已經(jīng)不是一種安全的加密方法。在1999年1月座舍,已經(jīng)有組織在22小時(shí)15分鐘內(nèi)公開(kāi)破解了一個(gè) DES 密鑰沮翔。
后來(lái)出現(xiàn)了一種改進(jìn)的 DES,叫 TDES 或 3DES曲秉。它本質(zhì)上就是把密鑰個(gè)數(shù)增加到了3個(gè)采蚀,并沒(méi)有算法上的改進(jìn)。(感覺(jué)很兒戲的樣子)
在2001年承二,DES 已經(jīng)不再是 國(guó)際標(biāo)準(zhǔn)科技協(xié)會(huì)(NIST榆鼠,前 FIPS)的一個(gè)標(biāo)準(zhǔn),而且也開(kāi)始慢慢被 AES 所取代矢洲。
言歸正傳
AES,全稱(chēng)為 Advanced Encryption Standard缩焦,原名叫做 Rijndael 加密法读虏。(還是新名字好念)
至于一開(kāi)始為什么有個(gè)這么拗口的名字,因?yàn)閮晌蛔髡叩拿质?Joan Daemen 和 Vincent Rijmen袁滥,發(fā)現(xiàn)為什么了嗎盖桥?這是不是密碼學(xué)家約定俗成的某種命名方式呢?
2001年11月26日题翻,美國(guó)的 NIST 公布了 AES 這一標(biāo)準(zhǔn)揩徊,并開(kāi)始了長(zhǎng)達(dá)5年的標(biāo)準(zhǔn)化進(jìn)程,直到 Rijndael 被選為最適合的方法嵌赠。
在2002年5月26日塑荒,AES 成為了一項(xiàng)聯(lián)邦政府標(biāo)準(zhǔn)。它還是聯(lián)邦安全局(NSA)批準(zhǔn)的唯一一種用來(lái)加密頂級(jí)機(jī)密信息的公開(kāi)加密方法姜挺。
也就是說(shuō)齿税,如果你想要黑 FBI 的話,可以試試看 AES 解密 :)
嚴(yán)格來(lái)說(shuō)炊豪,AES 和 Rijndael 并不完全一樣凌箕。AES 使用的是固定128位大小的塊,密鑰的大小只能是128位词渤、192位或256位牵舱;而 Rijndael 使用的塊大小和密鑰長(zhǎng)度可以是在128位和256位之間能被32整除的任意值,相對(duì)來(lái)說(shuō)靈活性高了很多缺虐。
主要過(guò)程
AES加密算法的組成可以分成4個(gè)主要部分:
- AddRoundKey
- SubBytes
- ShiftRows
- MixColumns
簡(jiǎn)單來(lái)說(shuō)芜壁,就是將上面的幾個(gè)部分組合起來(lái)形成三種不同的序列,然后把這些過(guò)程序列重復(fù)執(zhí)行若干個(gè)回合,具體的循環(huán)次數(shù)由密鑰的長(zhǎng)度決定:
- 128位密鑰:循環(huán)10次
- 192位密鑰:循環(huán)12次
- 256位密鑰:循環(huán)14次
這三種序列是:
- 首次循環(huán):
- AddRoundKey
- 一般循環(huán):
- SubBytes
- ShiftRows
- MixColumns
- AddRoundKey
- 末尾循環(huán):
- SubBytes
- ShiftRows
- AddRoundKey
那么這幾個(gè)部分到底是干了些什么呢沿盅?
AddRoundKey
在每一次循環(huán)中把篓,通過(guò) Rijndael 密鑰生成方案從主密鑰中生成一個(gè)子密鑰秸应,這個(gè)子密鑰的大小應(yīng)該等同于塊的大小敬惦,并且以列優(yōu)先的方式排列在一個(gè)矩陣?yán)铮總€(gè)塊也是以這樣的方式排列在矩陣?yán)锏模?br>
接下來(lái)將這個(gè)子密鑰的值與塊上對(duì)應(yīng)位置的值 XOR 起來(lái),形成一個(gè)新的矩陣旭等,到這里這一過(guò)程就算完成了窖铡。
SubBytes
這一步會(huì)使用到一個(gè)叫做 Rijndael S-box 的東西疗锐,它其實(shí)就是一個(gè)8位的代換表,每一個(gè)字節(jié)的數(shù)據(jù)都可以在表中查到對(duì)應(yīng)的代換結(jié)果费彼。只要這個(gè) S-box 在構(gòu)建的時(shí)候足夠好滑臊,就可以大大降低這次加密的線性關(guān)系。下面是一個(gè)6位 S-box 的例子箍铲,輸入的值是011011雇卷,輸出的值是1001:
將塊矩陣中的每一個(gè)元素通過(guò) S-box 進(jìn)行代換,組成一個(gè)代換后的矩陣颠猴,就是 SubBytes 這一步的工作关划。
ShiftRows
這一步容易理解,就是把塊矩陣中的每一行都進(jìn)行一個(gè)向左循環(huán)移位翘瓮,最后的效果是要讓輸出矩陣的每一列上的元素都屬于輸入矩陣原本不同的列贮折。
這樣做可以保證每一列上的元素都是非線性相關(guān)的。
MixColumns
這個(gè)部分會(huì)接受4個(gè)字節(jié)的輸入资盅,并輸出4個(gè)字節(jié)调榄,而且每一個(gè)字節(jié)輸入的字節(jié)都會(huì)對(duì)輸出造成影響,所以它跟上面的 ShiftRows 一起為加密算法提供了良好的擴(kuò)散性呵扛。
擴(kuò)散性(Diffusion):如果改變了任意1位的原文每庆,密文中一半以上的位也應(yīng)該會(huì)跟著改變;反過(guò)來(lái)今穿,改變了任意1位密文扣孟,得到的原文也應(yīng)該有一半以上的位被改變∪俑希—— Stallings, William (2014). Cryptography and Network Security (6th ed.)
簡(jiǎn)單來(lái)說(shuō)凤价,這一步就是講輸入矩陣的每一列與一個(gè)固定的多項(xiàng)式在一定條件下相乘。最終得到的將會(huì)是一個(gè)與輸入矩陣完全不一樣的輸出矩陣拔创。
更多資料
填充算法
對(duì)于塊加密算法來(lái)說(shuō)剩燥,如果數(shù)據(jù)的長(zhǎng)度不滿一個(gè)塊的大小慢逾,我們就需要主動(dòng)填充一些數(shù)據(jù)立倍,讓這個(gè)塊的大小可以滿足要求,于是侣滩,一個(gè)合適的填充算法就顯得尤為重要口注。
經(jīng)過(guò)導(dǎo)師的提醒并且在網(wǎng)上讀了一些博客之后發(fā)現(xiàn),Java端與iOS端使用的AES填充算法是不一樣的君珠,在 Java 端上使用的是 PKCS5Padding 寝志,而在iOS端上使用的是 PKCS7Padding 。所以就會(huì)導(dǎo)致在其中一端上加解密沒(méi)有問(wèn)題策添,但是把密文發(fā)到另一端上解密就會(huì)得到完全不同的結(jié)果材部。
P.S. 這里說(shuō)到的 Java 端 應(yīng)該是指服務(wù)器端,Android 端上不知道有沒(méi)有這個(gè)問(wèn)題唯竹。
PKCS5 相當(dāng)于是 PKCS7 的一個(gè)子集乐导,因?yàn)?PKCS7 理論上支持1~255字節(jié)的塊大小填充,而 PKCS5 只支持8字節(jié)的塊大小填充浸颓。其實(shí) PKCS5 更多是應(yīng)用在 DES/3DES 上物臂。
具體的填充過(guò)程也非常好理解,直接舉例子好了:比如說(shuō)塊大小為8字節(jié)的加密算法产上,現(xiàn)在有一串長(zhǎng)度為9的數(shù)據(jù):
FF FF FF FF FF FF FF FF FF
(9個(gè)FF)
使用 PKCS7 算法去填充的話棵磷,結(jié)果就是這樣的
FF FF FF FF FF FF FF FF FF 07 07 07 07 07 07 07
(9個(gè)FF和7個(gè)07)
填充的目的就是把塊給補(bǔ)滿,所以這里填充的長(zhǎng)度為7蒂秘;而采用 PKCS7 算法的話泽本,填充的每一個(gè)字節(jié)都是填充長(zhǎng)度的十六進(jìn)制數(shù)淘太,那就也是7姻僧。
有趣的是,如果采用 PKCS5 去填充蒲牧,因?yàn)樗哪繕?biāo)塊大小是8撇贺,所以這里會(huì)填充一個(gè)01。詳情可以參考Can AES use PKCS#5 padding里的最佳答案冰抢。
寫(xiě)在最后
從上面的流程可以看出松嘶,一個(gè)邏輯嚴(yán)密的加密算法其實(shí)就是由一個(gè)個(gè)結(jié)構(gòu)精巧的小算法構(gòu)成的。在我看來(lái)挎扰,不深入到每個(gè)算法的內(nèi)部翠订,而只是看看它們之間的聯(lián)系,還是蠻有意思的遵倦。研究算法的事情還是交給專(zhuān)業(yè)的人去做吧~