本文同時發表在https://github.com/zhangyachen/zhangyachen.github.io/issues/27
總結下《圖解密碼技術》的核心點,自己忘的時候瞅一眼。
密碼
對稱密碼(symmetric cryptography)
加密和解密使用同一密匙。
公鑰密碼(public-key cryptography)
加密和解密使用不同密鑰的方式。
單向散列函數(one-way hash function)
計算散列值,保證的不是機密性,而是完整性。
消息認證碼(message authentication code)
確認消息是否被篡改,而且能夠確認消息是否來自所期待的通信對象。
數字簽名(digital signature)
為了防止通信方的否認
偽隨機數生成器(pseudo random number generator,PRNG)
模擬產生隨機數的算法
對稱密碼
DES(Data Encryption Standard)
1977年美國聯邦信息處理標准所采用的一種對稱密碼,現在已經能被暴力破解。
DES是一種將64比特的明文加密成64比特密文的對稱密碼算法,密匙長度是56比特。但由於每隔7比特會設置用於錯誤檢查的比特,因此密匙長度實際是56比特。
DES基本結構也被稱為Feistel網絡,加密的各個步驟稱為輪,整個加密的過程就是進行若干次輪的循環。DES是一種16輪循環的Feistel網絡。
但是這樣一來右側根本沒有加密,因此我們需要用不同的子密匙對一輪的處理重復若干次,並在兩輪處理之間將左側和右側數據對調。
DES破解消息:http://wenku.baidu.com/link?url=0UrkWjEU0SsXN4uA059-vm_e32e3YxflhD4X6J3dU_aupbTSog70EabsJ4u6YMldfygILs8BX1q7DI0GuAhdw2Qud6IywUVXt04ybUrB44K
AES(Advanced Encryption Standard)
取代DES成為新標准的一種對稱密碼算法。在2000年從候選算法中選出了一種名為Rijndael的對稱密碼算法。
分組長度是128比特。在AES規格中,密匙長度只有128、1192、256比特三種。
- 逐個的對16字節的輸入數據進行SubBytes處理。即以每個字節的值(0~255)為索引進行替換,即將一個字節的值替換成另一個字節的值。
- 將輸出以字節為單位進行打亂處理(有規律的)
- 以一個4字節的值進行比特運算,將其變成另外一個4字節的值。
- 將輸出與輪密匙進行XOR。
Rijndael需要重復進行10~14輪計算。
目前為止還沒有出現針對Rijndael的有效攻擊。
分組密碼的模式
模式
分組密碼只能加密固定長度的分組,但是我們要加密的長度可能會超過分組密碼的分組長度,這是就需要對分組密碼算法進行迭代,迭代的方法就是分組密碼的模式。
ECB模式
相同的明文會被轉換為相同的密文。只要觀察一下密文,就知道明文存在怎樣的重復組合,並以此為線索破解密碼。並且在ECB模式中,每個明文分組都各自獨立的加密和解密,攻擊者可以改變密文分組的順序。
不推薦使用。
CBC模式
每次加密時都會隨機產生一個不同的比特序列來作為初始化向量。
CFB模式
OFB模式
CTR模式
計數器
前8字節為nonce,這個值在每次加密時必須不同(防止具有相同的分組序號的相同明文加密后產生相同的密文)。后8字節為分組序號,這個部分會逐次累加。
能夠以任意順序處理分組,就意味着能夠實現並行計算。
公鑰密碼
解決密匙配送問題:
- 共享密匙
- 密匙分配中心
- Diffie-Hellman
- 公鑰密碼
公鑰密碼處理速度只有對稱密碼的幾百分之一。
RSA
一種公鑰算法。
http://www.ruanyifeng.com/blog/2013/06/rsa_algorithm_part_one.html
一旦發現了對大整數進行質因數分解的高效算法,RSA就能被破譯。
中間人攻擊
僅靠公鑰密碼本身,是無法防御中間人攻擊的。要防御中間人攻擊,還需要一種手段來確認所收到的公鑰是否真的屬於Bob,這種手段稱為認證。
混合密碼系統
公鑰密碼的問題:
- 處理速度遠低於對稱密碼。
- 難以抵御中間人攻擊。
混合密碼系統的組成機制:
- 用對稱密碼加密消息
- 通過偽隨機數生成對稱密碼加密中使用的會話密鑰
- 用公鑰密碼加密會話密鑰
- 從混合密碼系統外部賦予公鑰密碼加密時使用的密鑰
用對稱密碼提升明文的加密速度,用公鑰密碼提升對稱密碼的密匙的安全性(因為對稱密碼的密匙長度相對於明文長度很短,所以公鑰密碼速度慢的問題可以被忽略)。
單向散列函數
也叫消息摘要函數,哈希函數或者雜湊函數。
用來確認明文的完整性,或者是否被篡改。
單向散列函數有一個輸入和輸出,輸入稱為消息,輸出稱為散列值。
弱抗碰撞性
找到和該消息具有相同散列值的另一條消息是非常困難的。
強抗碰撞性
找到相同散列值的兩條不同的消息是非常困難的。
具體例子
MD4、MD5
MD4產生128比特的散列值,現在已經不安全。
MD5產生28比特的散列值,目前MD5的強碰撞性已經被攻破。
SHA-1、SHA-256、SHA-384、SHA-512
SHA-1產生160比特的散列值,強碰撞性於2005年被攻破。
SHA-256、SHA-384、SHA-512統稱SHA-2,散列長度分別為256,384,512比特。
SHA-2尚未被攻破。
查看php支持的哈希函數
<?php
print_r(hash_algos());
php使用哈希函數范例:
<?php
echo hash('sha256', 'abc');
echo hash('sha512', 'abc');
// md5, sha1.. 等等也都可以用此寫法
echo hash('md5', 'abc');
echo hash('sha1', 'abc');
單向散列函數並不是加密算法
針對單向散列函數的攻擊
暴力破解
為了破解弱抗碰撞性,可以使用暴力破解。以SHA-1為例,散列值長度值為160比特,因此最多嘗試2的160次方就能找到目標消息了。
生日攻擊
為了破解強抗碰撞性。
設想在N個人中,如果要保證至少兩個人的生日一樣的概率大於二分之一,N至少多少?
先算N個人生日全都不一樣的概率(過程略了),N=23。
當Y非常大時,N約等於Y的平方根。
以160比特的散列值為例,N=2^80時,生日攻擊有二分之一的概率成功。
單向散列函數可以辨別篡改,但是無法辨別偽裝。此時我們需要認證技術。
參考:php處理密碼的幾種方式
https://jellybool.com/post/php-password-hash-in-the-right-way
消息認證碼
message authentication code(MAC),輸入包括消息和共享密鑰,可以輸出固定長度的數據。
但是還是那個恆久的問題:共享密鑰配送問題。如果共享密鑰落入第三方手中,消息認證碼就無法發揮作用了(解決方法還是上面提過的四種解決方法)。
實現方法
- 單向散列函數實現
使用SHA-1、MD5之類的單向散列函數可以實現,其中一種實現方法叫做HMAC。 - 分組密碼實現
HMAC
H是HASH的意思。
對消息認證碼的攻擊
重放攻擊
防御方法:
- 序號
約定每次發送都發送一個遞增的編號,並在計算MAC值時將序號也包含在消息中,這樣攻擊者無法計算序號遞增之后的MAC值。 - 時間戳
約定發送消息時包含當前時間,如果收到以前的消息即使MAC正確也丟棄。但是需要考慮通信延遲,必須在時間的判斷上留下緩沖。 - nonce
在通信之前,接受者先向發送者發送一個一次性的隨機數nonce。發送者在消息中包含這個nonce並計算MAC值。由於每次nonce都會變化,因此無法重放攻擊。
無法解決的問題
- 對第三方的證明
- 防止否認
數字簽名
消息認證碼之所以無法防止否認,是因為發送者和接受者共享密鑰。對於第三方來說,我們無法證明這條消息是由發送發生成的,因為接收方也可以偽造此消息。
所以,我們可以模仿公鑰密碼,發送方使用只有自己知道的密鑰。這樣只有發送方可以正確解密的消息,這樣就可以防止發送方的否認。
但是如果數字簽名的生成者說:“我的私鑰被別人竊取了”,怎么辦?報警吧,哈哈哈
但是數字簽名還是無法防止中間人攻擊,要防止,必須確認自己得到的公鑰是否真的屬於自己的通信對象。可以打電話核對公鑰的散列值,也可以使用公鑰證書。
證書
公鑰證書記有姓名、組織、郵箱地址等個人信息,以及屬於此人的公鑰,並由認證機構(CA)施加數字簽名。只要看到公鑰證書,我們就知道認證機構認定該公鑰的確屬於此人。
其中(1)(2)(3)僅在注冊新公鑰才會進行,並不是每次通信需要,(4)僅在發送方第一次用公鑰密碼向接受者發送消息才會進行,公鑰可以保存在電腦中。
公鑰基礎設施(PKI)
公鑰基礎設施,為了更有效的運用公鑰而制定的一系列規范和規格的總稱。
規范包括證書由誰頒發,如何頒發,私鑰泄露時應該如何作廢證書,計算機之間的數據交換應該采用怎樣的格式。
基本要素
- 用戶
- 認證機構
- 倉庫
認證機構(CA)
認證機構的工作:
- 生成密鑰對(也可由用戶生成)
- 注冊公鑰時對本人身份進行認證
- 生成並頒發證書
- 作廢證書
作廢證書與CRL
做作廢證書,認證機構需要制作一張證書作廢清單CRL,PKI用戶需要從認證機構獲取最新的CRL,並查詢自己要用於驗證簽名的公鑰是否作廢。
證書層級結構
對證書的攻擊
- 在公鑰注冊之前攻擊
- 注冊相似人名進行攻擊
- 竊取私鑰
- 偽裝成認證機構
- 鑽CRL空子
隨機數
性質
- 隨機性
- 不可預測
- 不可重現
偽隨機數生成器的算法是公開的,但是種子是保密的。
僅靠軟件無法生成真隨機數。
具體的偽隨機數生成器
線性同余法
不具備不可預測性,不可用於密碼技術。C語言的庫函數rand,Java的java.util.Random類采用此方法。
單向散列函數
具備不可預測性。
密碼法
要破解不可預測性,必須破譯密碼。
對種子攻擊
如果被攻擊者知道了種子,那么就能知道這個偽隨機數生成器生成的全部偽隨機數列。
要避免種子被攻擊者知道,我們需要使用不可重現性的真隨機數作為種子。例如Linux系統中的/dev/random文件就是一個根據硬件設備驅動收集的背景噪聲存儲真隨機數的隨機數池。
密鑰
會話密鑰:僅限於本次通信,下次通信不能使用。
主密鑰:一直被重復使用。
基於口令的密碼(PBE)
我們需要保證消息的重要性,需要用密鑰(CEK)對消息進行加密,但是需要保證CEK的機密性,用另一個密鑰(KEK)對CEK進行加密,但是還是需要保證KEK的機密性,陷入了死循環?
- 生成KEK
- 生成會話密鑰並加密
- 加密消息
鹽的作用
防御字典攻擊。字典攻擊是一種實現進行計算並准備好候選密鑰列表的方法。
字典攻擊:http://baike.baidu.com/link?url=Zma4cc9nFzhmdM0cmLiHLvGm65dUQRXzfLiK_o5SRPge05lCfh1MQnLGgx937mZuRMycHWJ_njK9zfX3KA-ISK