一次可靠的通信
如何設計一次可靠的通信呢?
安全可靠的保障:
轉存失敗重新上傳取消
這幅圖看懂了嗎?
例子1:TLS的設計
TLS的設計目標是構建一個安全傳輸層(Transport Layer Security ),在基于連接的傳輸層(如tcp)之上提供:
1.密碼學安全
保密, message privacy (保密通過加密encryption實現,所有信息都加密傳輸,第三方無法竊聽 )
完整性, message integrity( 通過MAC校驗機制,一旦被篡改,通信雙方會立刻發現 )
認證, mutual authentication (雙方認證,雙方都可以配備證書,防止身份被冒充 )
2.互操作,通用性 ( 根據公開的rfc,任何符合rfc的軟件實現都可以互操作,不受限于任何專利技術)
3.可擴展性 ( 通過擴展機制 tls_ext可以添加功能,有大量的新功能,都是通過擴展添加的)
4.高效率 (通過session cache,恰當部署cache之后,tls的效率很高)
TLS的設計和實現,可以看我同事byronhe寫的一篇博文,這里不展開,請繼續往下看。
http://blog.helong.info/blog/2015/09/06/tls-protocol-analysis-and-crypto-protocol-design/
例子2:某xx協議
1.借鑒TLS的設計,用非對稱加密算法來協商通信密鑰,對稱加密算法來加密通信數據
2.同wx的xxoo協議實現不一樣,雙保險,增加破解成本
3.關注性能,越簡單越好
4.考慮異常情況下的處理,支持隨時降級。
使用優化后的ECDH+ECDSA算法來密鑰協商,自研的xxx+HMAC來加解密,支持用戶證書認證,防中間人和防重放。
下面分享幾個關鍵點。
首先,介紹一下ECDH
ECDH是基于ECC(Elliptic Curve Cryptosystems,橢圓曲線密碼體制,參看ECC)的DH( Diffie-Hellman)密鑰交換算法。交換雙方可以在不共享任何秘密的情況下協商出一個密鑰。ECC是建立在基于橢圓曲線的離散對數問題上的密碼體制,給定橢圓曲線上的一個點P,一個整數k,求解Q=kP很容易;給定一個點P、Q,知道Q=kP,求整數k確是一個難題。ECDH即建立在此數學難題之上。
簡單來說,兩端生成公私鑰對,然后分別把自己的公鑰傳輸給對方,最后雙方通過ECDH_compute_key這個函數計算出相同的key。
轉存失敗重新上傳取消
先看圖吧,看不懂再看下面這個例子:
客戶端隨機生成client[pri]、client[pub]
后臺隨機生成server[pri]、server[pub]
雙方交換公鑰,私鑰自己保存
客戶端key = ECDH_compute_key(client[pri],server[pub])
后臺key = ECDH_compute_key(server[pri],client[pub])
此時雙方就協商出一個相等的key了,這個key可以作為根密鑰派生出對稱加密密鑰。
采用ECDH協商,協商過程中信道只會傳輸密鑰材料,不會傳輸最終的key,比傳統的【A端生成RSA公私鑰對,然后把公鑰給B端,B端隨機生成key并傳輸RSA(key,pub)給A,A用pri來解密獲得key】的方式要安全。但ECDH不能防中間人,需要加上簽名認證算法,如ECDSA來保障。
再介紹一個陷阱
在密碼學歷史上,出現過3種加密和認證的組合方式:
Encrypt-and-MAC:加密后加上原串MAC
MAC-then-Encrypt:把(原串和原串MAC)加密
Encrypt-then-MAC:原串加密后,再整體MAC
在TLS協議初定的那個年代,人們還沒意識到這3種組合方式的安全性有什么差別,所以TLS協議規定使用 MAC-then-Encrypt,即先計算MAC,然后把 “明文+MAC” 再加密(塊加密或者流加密)的方式,做流加密+MAC,和塊加密+MAC。
但是,悲劇的是,近些年,人們發現 MAC-then-Encrypt 這種結構導致了 很容易構造padding oracle 相關的攻擊,例如這在TLS中,間接形成被攻擊者利用,這間接導致了 BEAST 攻擊 , Lucky 13攻擊 (CVE2013-0169) 和 POODLE 攻擊 (CVE2014-3566)。
目前因此,學術界已經一致同意: Encrypt-then-MAC才是最安全的!
tls使用的是 MAC-then-Encrypt的模式,導致了一些問題。具體比較,參見:
http://cseweb.ucsd.edu/~mihir/papers/oem.pdf
https://www.iacr.org/archive/crypto2001/21390309.pdf
http://crypto.stackexchange.com/questions/202/shouldwemacthenencryptorencryptthenmac
https://news.ycombinator.com/item?id=4779015
http://tozny.com/blog/encryptingstringsinandroidletsmakebettermistakes/
鑒于這個陷阱如此險惡,學術界有人就提出了,干脆把Encrypt和MAC直接集成為一個算法,在算法內部解決好安全問題,不再讓碼農選擇,避免眾碼農再被這個陷阱坑害,這就是AEAD(Authenticated Encryption With Addtional Data)類的算法,GCM模式就是AEAD最重要的一種。如果常用的AES-GCM。
然后,科普一下什么是HMAC
HMAC是密鑰相關的哈希運算消息認證碼(Hash-based Message Authentication Code),HMAC運算利用哈希算法,以一個密鑰和一個消息為輸入,生成一個消息摘要作為輸出。常用的HAMC有HMAC-MD5和HMAC-SHA。
算法公式 : HMAC(K,M)=H(K⊕opad∣H(K⊕ipad∣M))
H 代表所采用的HASH算法(如SHA-256)
K 代表認證密碼
Ko 代表HASH算法的密文
M 代表一個消息輸入
B 代表H中所處理的塊大小,這個大小是處理塊大小,而不是輸出hash的大小
一次HMAC運算相當于計算了兩次HASH。所以,一般來說,HMAC的性能是HASH算法的一半。
另外,還有一些坑要注意:
正確的簽名方式是,經過密碼學HASH后,對HASH結果進行簽名,這樣的實現能保證簽名有效性。
算法實現應該使用開源密碼學庫,不要自己搞
CBC操作模式的iv一定要通過隨機數生成器生成
最后給出一些算法的性能
在E5-2420@1.90GHz單核下使用openssl 1.0.2a測試:
ecdsa_sign—_256: 1.2w次/s(簽名串71B)
ecdsa_verify_256:5100次/s
RSA2048_sign:545.3次/s(簽名串256B)
RSA2048_verify:1.8w次/s
ECDH_compute_key_256: 7100次/s(32B)
這里看出,ECDSA簽名快驗證慢,RSA是簽名慢驗證快。在協商環節,如果后臺簽名客戶端驗簽,則后臺使用ecdsa比較好。另外ECDSA256簽名生成的簽名串長71B,比RSA2048的256B短多了,能有效減少報文大小,減少流量消耗。
怎么樣防重放?
這里先賣個關子,大家可以思考一下,要考慮通信過程中的丟包哦:)
總結一下,設計可靠的通信協議,如果只考慮密碼學安全是不夠的,還要綜合考慮性能和流量。密碼學安全,在設計和實現上稍有不當,很容易踩坑,所以還是盡量使用開源的標準實現吧。本文如有錯漏,請斧正。
據說新的chacha20-poly1305很不錯,是AEAD算法,而且在ARM架構下性能很好,實測了在TS8單核有130M/s。
TEA+HMAC-SHA256:60MB/s
AES-GCM:400MB/s(AES-NI下700MB/s)
Chacha20-poly1305:130MB/s
測試環境:TS8-Xeon E5-2420@ 1.90GHz單核-openssl 1.0.2a /libsodium 1.0.11
總結
- 上一篇: 大数据技术之kafka (第 3 章 K
- 下一篇: 【译】BINDER TRANSACTIO