起點(diǎn)
最近空閑時間都在研究Google開源項(xiàng)目Tink的源碼,發(fā)現(xiàn)很多密碼學(xué)相關(guān)概念似懂非懂,直接導(dǎo)致越看越蒙圈。在通過谷歌度娘惡補(bǔ)基礎(chǔ)知識的過程中,發(fā)現(xiàn)密碼學(xué)理論艱深,概念繁多。寫這篇文章就是希望把關(guān)鍵點(diǎn)記錄下來,一來可以加深印象,留著以后溫故而知新;二來也許可以給有同樣需求的朋友一點(diǎn)捷徑。
這篇文章注定會很長,因?yàn)槲視M量把每個概念或名詞都附上詳細(xì)解釋,而我又不想分開來寫。本文是我在翻閱了很多網(wǎng)絡(luò)文章后,加入自己的理解后整理而成。所有出處和參考資料都在文章結(jié)尾,侵刪!
本人水平有限,錯誤難免,如果您發(fā)現(xiàn)錯誤,請務(wù)必指出,非常感謝!
密碼學(xué)的方法論
密碼學(xué)和軟件開發(fā)不同,軟件開發(fā)是工程,是手藝,造輪子是寫代碼的一大樂趣。開發(fā)過程中常常要做出多方面的權(quán)衡(例如CAP),難有明確的對錯。
密碼學(xué)就不一樣了。密碼學(xué)是科學(xué),不是工程,有嚴(yán)格的技術(shù)規(guī)范,嚴(yán)禁沒有經(jīng)過學(xué)術(shù)訓(xùn)練者隨意創(chuàng)造。要有嚴(yán)謹(jǐn)?shù)睦碚摻?,?yán)密的數(shù)學(xué)證明。少有需要權(quán)衡的地方,正確就是正確,錯誤就是錯誤。
密碼學(xué)有很多陷阱,設(shè)計(jì)密碼學(xué)協(xié)議或者軟件,是極其容易出錯的高風(fēng)險專業(yè)活動,單純的碼農(nóng)背景是做不了的。本著不作死就不會死的偉大理念,首先推薦讀者盡可能使用 TLS 這種標(biāo)準(zhǔn)化、開源、使用廣泛、久經(jīng)考驗(yàn)、高性能協(xié)議。
經(jīng)過幾十年的軍備競賽式發(fā)展,已經(jīng)發(fā)展出大量巧妙而狡猾的攻擊方法,我們使用的算法,都是在所有已知攻擊方法下都無法攻破的,由于大多數(shù)碼農(nóng)并沒有精力去了解最前沿的攻擊方法,我們也就沒有能力去評價一個加密算法,更沒有能力自己發(fā)明算法。所以最好跟著業(yè)界的主流技術(shù)走,肯定不會有大錯。
現(xiàn)在搞現(xiàn)代密碼學(xué)研究的主要都是數(shù)學(xué)家,在這領(lǐng)域里,以一個碼農(nóng)的知識背景,已經(jīng)很難理解最前沿的東西,連正確使用加密算法都是要謹(jǐn)慎謹(jǐn)慎再謹(jǐn)慎。一個碼農(nóng),能了解密碼學(xué)基本概念,跟進(jìn)密碼學(xué)的最新應(yīng)用趨勢,并正確配置部署TLS這種協(xié)議,就很不錯了。
本文也只是整理一些粗淺的密碼學(xué)常識,讀完這篇文章,并不能使你具有設(shè)計(jì)足夠安全的密碼學(xué)能力。
上面提到過的密碼學(xué)算法很難被正確地使用,各種細(xì)節(jié)非常容易出錯。 例如:
- 大多數(shù)碼農(nóng)都聽說過aes,可是你又了解多少細(xì)節(jié)呢,比如:aes應(yīng)該用哪種模式?應(yīng)該用哪種padding?IV/nonce應(yīng)該取多少bit?IV/nonce應(yīng)該怎么生成? key size應(yīng)該選多大?key應(yīng)該怎么生成?應(yīng)不應(yīng)該加MAC?MAC算法的選擇?MAC和加密應(yīng)該怎么組合?
- 大多數(shù)知道RSA的碼農(nóng)分不清 RSASSA-PKCS1-v1_5 、RSAES-OAEP 和 RSASSA-PSS?
- 更多錯誤參見 stackoverflow問答,強(qiáng)烈推薦仔細(xì)閱讀
有沒有被這一連串的問題弄懵逼?點(diǎn)開 stackoverflow 之后更是不知所云,備受打擊?沒關(guān)系,下面跟我一起來完成這個補(bǔ)完計(jì)劃吧。
下文我提到的每個算法都是當(dāng)前安全的,哪些過時或被破解的不在本文討論范圍內(nèi)
在各種適用場景下,你應(yīng)該使用的現(xiàn)代密碼學(xué)算法:
加密數(shù)據(jù)
適用場景:需要避免把明文數(shù)據(jù)在網(wǎng)絡(luò)上傳輸?shù)臅r候。
推薦選擇:(1) 首選NaCl,或者libsodium。使用crypto_secretbox() 或 crypto_secretbox_open() 函數(shù) ;(2) Chacha20-Poly1305算法;(3) AES-GCM 算法;
以上3種算法,都是AEAD類的算法,目前來看是最好的選擇。
并且,我們還應(yīng)該:
- 避免AES-ECB
- 避免AES-CTR
- 避免64bit塊大小的塊加密算法
- 避免OFB模式
- 不要使用RC4,RC4已經(jīng)被攻破
我們先看看 AES-ECB 和 AES-CTR 存在什么問題,再看 AES-GCM 是怎么解決的。
- Electronic Codebook Book (ECB)
電碼本模式,將整個明文進(jìn)行分組,分組長度可為128,256,或512bits,然后對每個小組進(jìn)行加密。
ECB.png
可以看出,明文中重復(fù)的排列會反映在密文中。并且,當(dāng)密文被篡改時,解密后對應(yīng)的明文分組也會出錯,且解密者察覺不到密文被篡改了。也就是說,ECB不能提供對密文的完整性校驗(yàn)。
因此,在任何情況下都不推薦使用ECB模式。
Ek
使用秘鑰k對輸入做對稱加密運(yùn)算
- CounTeR (CTR)
計(jì)數(shù)器模式,我們不再對密文進(jìn)行加密,而是對一個逐次累加的計(jì)數(shù)器進(jìn)行加密,用加密后的比特序列與明文分組進(jìn)行 XOR 得到密文。過程如下圖:
CTR.png
該模式下,每次與明文分組進(jìn)行XOR的比特序列是不同的,因此,計(jì)數(shù)器模式解決了ECB模式中,相同的明文會得到相同的密文的問題。
但CTR仍然不能提供密文消息完整性校驗(yàn)的功能。
有的人可能會想到,如果將密文的hash值隨密文一起發(fā)送,密文接收者對收到的密文計(jì)算hash值,與收到的hash值進(jìn)行比對,這樣是否就能校驗(yàn)消息的完整性呢?
再仔細(xì)想想,就能發(fā)現(xiàn)這其中的漏洞。當(dāng)篡改者截獲原始的密文消息時,先篡改密文,而后計(jì)算篡改后的密文hash, 替換掉原始消息中的密文hash。這樣,消息接收者仍然沒有辦法發(fā)現(xiàn)對源密文的篡改。
可見,使用單向散列函數(shù)計(jì)算hash值仍然不能解決消息完整性校驗(yàn)的問題。
XOR
異或,英文為exclusive OR。是一個數(shù)學(xué)運(yùn)算符,應(yīng)用于邏輯運(yùn)算。數(shù)學(xué)符號為“⊕”,計(jì)算機(jī)符號為“xor”。
異或也叫半加運(yùn)算,其運(yùn)算法則相當(dāng)于不帶進(jìn)位的二進(jìn)制加法。
運(yùn)算法則為:0⊕0=0,1⊕0=1,0⊕1=1,1⊕1=0(同為0,異為1)。
MAC (Message Authentication Code)
想要校驗(yàn)消息的完整性,必須引入另一個概念:消息驗(yàn)證碼。消息驗(yàn)證碼是一種與秘鑰相關(guān)的單項(xiàng)散列函數(shù)。
密文的收發(fā)雙方需要提前共享一個秘鑰,例如當(dāng)韓梅梅向李雷發(fā)送消息m時,不僅僅發(fā)送消息m,還要發(fā)送一個由MAC函數(shù)計(jì)算得到的MAC值。李雷會用自己的密鑰對收到的消息m再次進(jìn)行MAC計(jì)算,并判斷這個值與收到的MAC值是否相等,如果不匹配則說明可能消息m被篡改了。由于竊聽者不知道秘鑰,所以不能為篡改后的消息計(jì)算出正確的MAC值。-
GMAC (Galois message authentication code mode)
伽羅瓦消息驗(yàn)證碼,GMAC就是利用伽羅華域(Galois Field,GF,有限域)乘法運(yùn)算來計(jì)算消息的MAC值。假設(shè)秘鑰長度為128bits, 當(dāng)密文大于128bits時,需要將密文按128bits進(jìn)行分組。流程如下圖:
GMAC.png
Mh
將輸入與秘鑰h在有限域GF(2^128)上做乘法
- GCM (Galois/Counter Mode)
AES-GCM中的G就是指GMAC,C就是指CTR。是一種AEAD,是目前TLS的主力算法,互聯(lián)網(wǎng)上https流量的大部分依賴使用AES-GCM。
GCM可以提供對消息的加密和完整性校驗(yàn),另外,它還可以提供附加消息的完整性校驗(yàn)。在實(shí)際應(yīng)用場景中,有些信息是我們不需要保密,但信息的接收者需要確認(rèn)它的真實(shí)性的,例如源IP、源端口、目的IP和IV等等。因此,我們可以將這一部分作為附加消息加入到MAC值的計(jì)算當(dāng)中。
GCM.png
AEAD
在通常的密碼學(xué)應(yīng)用中,Confidentiality (保密) 用加密實(shí)現(xiàn),Message authentication (消息認(rèn)證) 用MAC實(shí)現(xiàn)。這兩種算法的配合方式,引發(fā)了很多安全漏洞,過去曾經(jīng)有3種方法:
- Encrypt-and-MAC
- MAC-then-Encrypt
- Encrypt-then-MAC
后來發(fā)現(xiàn),1和2都是有安全問題,所以2008年起,逐漸提出了“用一個算法在內(nèi)部同時實(shí)現(xiàn)cipher+MAC”的idea,稱為 AEAD(Authenticated encryption with additional data)。 在這種概念里,cipher+MAC 被 一個AEAD算法替換。Authenticated encryption
我們再看看另外幾個推薦的加密庫
NaCl
NaCl 是密碼學(xué)學(xué)術(shù)權(quán)威 Daniel J. Bernstein教授設(shè)計(jì)的一個密碼學(xué)算法庫,2008年發(fā)開始公布。NaCl的特點(diǎn)是:api簡潔而易用,高性能,高安全性,主要用于網(wǎng)絡(luò)通信、加密、解密、簽名等,NaCl提供了構(gòu)建高層密碼學(xué)工具的核心功能。目前僅有C和Python版。
libsodium
libsodium 是對NaCl庫的一個分支,進(jìn)一步改進(jìn)接口易用性,和可移植性。網(wǎng)站看上去清爽多了,還提供了GitHub地址
ChaCha20-poly1305
是一種AEAD,提出者是Daniel J. Bernstein教授。由 ChaCha20流密碼 和 Poly1305消息認(rèn)證碼( MAC )結(jié)合的一種應(yīng)用在互聯(lián)網(wǎng)安全協(xié)議中的認(rèn)證加密算法,由Google公司率先在Andriod移動平臺中的Chrome中代替 RC4 使用。由于其算法精簡、安全性強(qiáng)、兼容性強(qiáng)等特點(diǎn),目前Google致力于全面將其在移動端推廣。
對稱簽名
適用場景:安全加固一個API,各種開放API的調(diào)用方認(rèn)證
如果你需要對一個API做認(rèn)證( authenticating ),但是不需要做加密( encrypting ),記得千萬不要自己發(fā)明算法,你自己發(fā)明的MAC算法基本都有安全漏洞,如果不信,請Google一下 “長度擴(kuò)展攻擊” 長度擴(kuò)展攻擊 ,Flickr的漏洞案例
同時,必須要注意的是,要使用一個常數(shù)時間字符串對比算法(這個地方和碼農(nóng)的常識完全相反,請務(wù)必留意)
此外,應(yīng)該
- 避免自行設(shè)計(jì)的“帶密碼的hash”結(jié)構(gòu),你的設(shè)計(jì)基本都是有安全漏洞;
- 避免HMAC-MD5,避免HMAC-SHA1,使用HMAC-SHA256, HMAC-SHA512等;
- 避免復(fù)雜的多項(xiàng)式MAC;
- 避免加密hash值的結(jié)構(gòu);
- 避免CRC;
未完待續(xù)……



