自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

玩轉(zhuǎn)混合加密

安全 數(shù)據(jù)安全
數(shù)據(jù)加密,是一門歷史悠久的技術(shù),指通過加密算法和加密密鑰將明文轉(zhuǎn)變?yōu)槊芪?,而解密則是通過解密算法和解密密鑰將密文恢復(fù)為明文。它的核心是密碼學(xué)。

本文轉(zhuǎn)載自微信公眾號(hào)「全棧修仙之路」,作者阿寶哥 。轉(zhuǎn)載本文請(qǐng)聯(lián)系全棧修仙之路公眾號(hào)。

數(shù)據(jù)加密,是一門歷史悠久的技術(shù),指通過加密算法和加密密鑰將明文轉(zhuǎn)變?yōu)槊芪?,而解密則是通過解密算法和解密密鑰將密文恢復(fù)為明文。它的核心是密碼學(xué)。

數(shù)據(jù)加密仍是計(jì)算機(jī)系統(tǒng)對(duì)信息進(jìn)行保護(hù)的一種最可靠的辦法。它利用密碼技術(shù)對(duì)信息進(jìn)行加密,實(shí)現(xiàn)信息隱蔽,從而起到保護(hù)信息的安全的作用。

本文阿寶哥將介紹如何對(duì)數(shù)據(jù)進(jìn)行混合加密,即使用對(duì)稱加密算法與非對(duì)稱加密算法對(duì)數(shù)據(jù)進(jìn)行加密,從而進(jìn)一步保證數(shù)據(jù)的安全性。閱讀完本文,你將了解以下內(nèi)容:

  • 什么是對(duì)稱加密、對(duì)稱加密的過程、對(duì)稱加密的優(yōu)缺點(diǎn)及 AES 對(duì)稱加密算法的使用;
  • 什么是非對(duì)稱加密、非對(duì)稱加密的過程、非對(duì)稱加密的優(yōu)缺點(diǎn)及 RSA 非對(duì)稱加密算法的使用;
  • 什么是混合加密、混合加密的過程及如何實(shí)現(xiàn)混合加密。

在最后的 阿寶哥有話說 環(huán)節(jié),阿寶哥還將簡(jiǎn)單介紹一下什么是消息摘要算法和什么是 MD5 算法及其用途與缺陷。

好的,現(xiàn)在讓我們步入正題。為了讓剛接觸混合加密的小伙伴更好地了解并掌握混合加密,阿寶哥將乘坐 “時(shí)光機(jī)” 帶大家來到某個(gè)發(fā)版的夜晚...

[[334543]]

 

那一晚我們團(tuán)隊(duì)的小伙伴正在等服務(wù)端數(shù)據(jù)升級(jí),為了讓大家 “忘記” 這個(gè)漫漫的升級(jí)過程,阿寶哥就立馬組織了一場(chǎng)關(guān)于混合加密的技術(shù)分享會(huì)。在阿寶哥 “威逼利誘” 之下,團(tuán)隊(duì)的小伙伴們很快就到齊了,之后阿寶哥以以下對(duì)話拉開了分享會(huì)的序幕:

 

幾分鐘過后,小哥講完了,基本關(guān)鍵點(diǎn)都有回答上來,但還遺漏了一些內(nèi)容。為了讓小伙伴們更好地理解對(duì)稱加密,阿寶哥對(duì)小哥表述的內(nèi)容進(jìn)行了重新梳理,下面讓我們來一起認(rèn)識(shí)一下對(duì)稱加密。

一、對(duì)稱加密

1.1 什么是對(duì)稱加密

對(duì)稱密鑰算法(英語:Symmetric-key algorithm)又稱為對(duì)稱加密、私鑰加密、共享密鑰加密,是密碼學(xué)中的一類加密算法。這類算法在加密和解密時(shí)使用相同的密鑰,或是使用兩個(gè)可以簡(jiǎn)單地相互推算的密鑰。

1.2 對(duì)稱加密的優(yōu)點(diǎn)

算法公開、計(jì)算量小、加密速度快、加密效率高,適合對(duì)大量數(shù)據(jù)進(jìn)行加密的場(chǎng)景。 比如 HLS(HTTP Live Streaming)普通加密場(chǎng)景中,一般會(huì)使用 AES-128 對(duì)稱加密算法對(duì) TS 切片進(jìn)行加密,以保證多媒體資源安全。

1.3 對(duì)稱加密的過程

發(fā)送方使用密鑰將明文數(shù)據(jù)加密成密文,然后發(fā)送出去,接收方收到密文后,使用同一個(gè)密鑰將密文解密成明文讀取。

 

1.4 對(duì)稱加密的使用示例

常見的對(duì)稱加密算法有 AES、ChaCha20、3DES、Salsa20、DES、Blowfish、IDEA、RC5、RC6、Camellia。這里我們以常見的 AES 算法為例,來介紹一下 AES(Advanced Encryption Standard)對(duì)稱加密與解密的過程。

下面阿寶哥將使用 crypto-js 這個(gè)庫(kù)來介紹 AES 算法的加密與解密,該庫(kù)提供了 CryptoJS.AES.encrypt() 方法用于實(shí)現(xiàn) AES 加密,而 AES 解密對(duì)應(yīng)的方法是 CryptoJS.AES.decrypt()。

基于上述兩個(gè)方法阿寶哥進(jìn)一步封裝了 aesEncrypt() 和 aesDecrypt() 這兩個(gè)方法,它們分別用于 AES 加密與解密,其具體實(shí)現(xiàn)如下所示:

1.4.1 AES 加密方法

  1. // AES加密 
  2. function aesEncrypt(content) { 
  3.   let text = CryptoJS.enc.Utf8.parse(JSON.stringify(content)); 
  4.   let encrypted = CryptoJS.AES.encrypt(text, key, { 
  5.     iv: iv, 
  6.     mode: CryptoJS.mode.CBC, 
  7.     padding: CryptoJS.pad.Pkcs7, 
  8.   }); 
  9.   return encrypted.toString(); 

1.4.2 AES 解密方法

  1. // AES解密 
  2. function aesDecrypt(content) { 
  3.   let decrypt = CryptoJS.AES.decrypt(content, key, { 
  4.     iv: iv, 
  5.     mode: CryptoJS.mode.CBC, 
  6.     padding: CryptoJS.pad.Pkcs7, 
  7.   }); 
  8.   return decrypt.toString(CryptoJS.enc.Utf8); 

1.4.3 AES 加密與解密示例

 

在以上示例中,我們?cè)陧撁嫔蟿?chuàng)建了 3 個(gè) textarea,分別用于存放明文、加密后的密文和解密后的明文。當(dāng)用戶點(diǎn)擊 加密 按鈕時(shí),會(huì)對(duì)用戶輸入的明文進(jìn)行 AES 加密,完成加密后,會(huì)把密文顯示在密文對(duì)應(yīng)的 textarea 中,當(dāng)用戶點(diǎn)擊 解密 按鈕時(shí),會(huì)對(duì)密文進(jìn)行 AES 解密,完成解密后,會(huì)把解密后的明文顯示在對(duì)應(yīng)的 textarea 中。

以上示例對(duì)應(yīng)的完整代碼如下所示:

  1. <!DOCTYPE html> 
  2. <html> 
  3.   <head> 
  4.     <meta charset="UTF-8" /> 
  5.     <meta name="viewport" content="width=device-width, initial-scale=1.0" /> 
  6.     <title>AES 對(duì)稱加密與解密示例</title> 
  7.     <style> 
  8.       .block { 
  9.         flex: 1; 
  10.       } 
  11.     </style> 
  12.   </head> 
  13.   <body> 
  14.     <h3>阿寶哥:AES 對(duì)稱加密與解密示例(CBC 模式)</h3> 
  15.     <div style="display: flex;"
  16.       <div class="block"
  17.         <p>①明文加密 => <button onclick="encrypt()">加密</button></p> 
  18.         <textarea id="plaintext" rows="5" cols="15"></textarea> 
  19.       </div> 
  20.       <div class="block"
  21.         <p>②密文解密 => <button onclick="decrypt()">解密</button></p> 
  22.         <textarea id="ciphertext" rows="5" cols="15"></textarea> 
  23.       </div> 
  24.       <div class="block"
  25.         <p>③解密后的明文</p> 
  26.         <textarea id="decryptedCiphertext" rows="5" cols="15"></textarea> 
  27.       </div> 
  28.     </div> 
  29.     <!-- 引入 CDN Crypto.js AES加密 --> 
  30.     <script src="https://cdn.bootcdn.net/ajax/libs/crypto-js/4.0.0/core.min.js"></script> 
  31.     <script src="https://cdn.bootcdn.net/ajax/libs/crypto-js/4.0.0/enc-base64.min.js"></script> 
  32.     <script src="https://cdn.bootcdn.net/ajax/libs/crypto-js/4.0.0/cipher-core.min.js"></script> 
  33.     <script src="https://cdn.bootcdn.net/ajax/libs/crypto-js/4.0.0/aes.min.js"></script> 
  34.     <script src="https://cdn.bootcdn.net/ajax/libs/crypto-js/4.0.0/pad-pkcs7.min.js"></script> 
  35.     <script src="https://cdn.bootcdn.net/ajax/libs/crypto-js/4.0.0/enc-utf8.min.js"></script> 
  36.     <!-- 引入 CDN Crypto.js 結(jié)束 --> 
  37.     <script> 
  38.       const key = CryptoJS.enc.Utf8.parse("0123456789abcdef"); // 密鑰 
  39.       const iv = CryptoJS.enc.Utf8.parse("abcdef0123456789"); // 初始向量 
  40.       const plaintextEle = document.querySelector("#plaintext"); 
  41.       const ciphertextEle = document.querySelector("#ciphertext"); 
  42.       const decryptedCiphertextEle = document.querySelector( 
  43.         "#decryptedCiphertext" 
  44.       ); 
  45.  
  46.       function encrypt() { 
  47.         let plaintext = plaintextEle.value; 
  48.         ciphertextEle.value = aesEncrypt(plaintext); 
  49.       } 
  50.  
  51.       function decrypt() { 
  52.         let ciphertext = ciphertextEle.value; 
  53.         decryptedCiphertextEle.value = aesDecrypt(ciphertext).replace(/\"/g,''); 
  54.       } 
  55.  
  56.       // AES加密 
  57.       function aesEncrypt(content) { 
  58.         let text = CryptoJS.enc.Utf8.parse(JSON.stringify(content)); 
  59.         let encrypted = CryptoJS.AES.encrypt(text, key, { 
  60.           iv: iv, 
  61.           mode: CryptoJS.mode.CBC, 
  62.           padding: CryptoJS.pad.Pkcs7, 
  63.         }); 
  64.         return encrypted.toString(); 
  65.       } 
  66.  
  67.       // AES解密 
  68.       function aesDecrypt(content) { 
  69.         let decrypt = CryptoJS.AES.decrypt(content, key, { 
  70.           iv: iv, 
  71.           mode: CryptoJS.mode.CBC, 
  72.           padding: CryptoJS.pad.Pkcs7, 
  73.         }); 
  74.         return decrypt.toString(CryptoJS.enc.Utf8); 
  75.       } 
  76.     </script> 
  77.   </body> 
  78. </html> 

 

在上面的示例中,我們通過 AES 對(duì)稱加密算法,對(duì) “我是阿寶哥” 明文進(jìn)行加密,從而實(shí)現(xiàn)信息隱蔽。

 

那么使用對(duì)稱加密算法就可以解決我們前面的問題么?答案是否定,這是因?yàn)閷?duì)稱加密存在一些的缺點(diǎn)。

1.5 對(duì)稱加密的缺點(diǎn)

通過使用對(duì)稱加密算法,我們已經(jīng)把明文加密成密文。雖然這解決了數(shù)據(jù)的安全性,但同時(shí)也帶來了另一個(gè)新的問題。因?yàn)閷?duì)稱加密算法,加密和解密時(shí)使用的是同一個(gè)密鑰,所以對(duì)稱加密的安全性就不僅僅取決于加密算法本身的強(qiáng)度,更取決于密鑰是否被安全的傳輸或保管。

另外對(duì)于實(shí)際應(yīng)用場(chǎng)景,為了避免單一的密鑰被攻破,從而導(dǎo)致所有的加密數(shù)據(jù)被破解,對(duì)于不同的數(shù)據(jù),我們一般會(huì)使用不同的密鑰進(jìn)行加密,這樣雖然提高了安全性,但也增加了密鑰管理的難度。

由于對(duì)稱加密存在以上的問題,因此它并不是一種好的解決方案。為了找到更好的方案,阿寶哥開始了另一輪新的對(duì)話。

 

 

 

 

二、非對(duì)稱加密

2.1 什么是非對(duì)稱加密

非對(duì)稱加密算法需要兩個(gè)密鑰:公開密鑰(publickey:簡(jiǎn)稱公鑰)和私有密鑰(privatekey:簡(jiǎn)稱私鑰)。公鑰與私鑰是一對(duì),如果用公鑰對(duì)數(shù)據(jù)進(jìn)行加密,只有用對(duì)應(yīng)的私鑰才能解密。 因?yàn)榧用芎徒饷苁褂玫氖莾蓚€(gè)不同的密鑰,所以這種算法叫作非對(duì)稱加密算法。

2.2 非對(duì)稱加密的優(yōu)點(diǎn)

安全性更高,公鑰是公開的,私鑰是自己保存的,不需要將私鑰提供給別人。

2.3 非對(duì)稱加密的過程

 

2.4 非對(duì)稱加密的使用示例

常見的非對(duì)稱加密算法有 RSA、Elgamal、背包算法、Rabin、D-H、ECC(橢圓曲線加密算法)。這里我們以常見的 RSA 算法為例,來介紹一下 RSA 非對(duì)稱加密與解密的過程。

RSA 是 1977 年由羅納德·李維斯特(Ron Rivest)、阿迪·薩莫爾(Adi Shamir)和倫納德·阿德曼(Leonard Adleman)一起提出的。當(dāng)時(shí)他們?nèi)硕荚诼槭±砉W(xué)院工作。RSA 就是他們?nèi)诵帐祥_頭字母拼在一起組成的。

下面阿寶哥將使用 jsencrypt 這個(gè)庫(kù)來介紹 RSA 算法的加密與解密,該庫(kù)提供了 encrypt() 方法用于實(shí)現(xiàn) RSA 加密,而 RSA 解密對(duì)應(yīng)的方法是 decrypt()。

2.4.1 創(chuàng)建公私鑰

使用 jsencrypt 這個(gè)庫(kù)之前,我們需要先生成公鑰和私鑰。接下來阿寶哥以 macOS 系統(tǒng)為例,來介紹一下如何生成公私鑰。

首先我們先來生成私鑰,在命令行輸入以下命令:

  1. $ openssl genrsa -out rsa_1024_priv.pem 1024 

在該命令成功運(yùn)行之后,在當(dāng)前目錄下會(huì)生成一個(gè) rsa_1024_priv.pem 文件,該文件的內(nèi)容如下:

  1. -----BEGIN RSA PRIVATE KEY----- 
  2. MIICWwIBAAKBgQDocWYwnJ4DYur0BjxFjJkLv4QRJpTJnwjiwxkuJZe1HTIIuLbu 
  3. /yHyHLhc2MAHKL0Ob+8tcKXKsL1oxs467+q0jA+glOUtBXFcUnutWBbnf9qIDkKP 
  4. ... 
  5. bKkRJNJ2PpfWA45Vdq6u+izrn9e2TabKjWIfTfT/ZQ== 
  6. -----END RSA PRIVATE KEY----- 

然后我們來生成公鑰,同樣在命令行輸入以下命令:

  1. $ openssl rsa -pubout -in rsa_1024_priv.pem -out rsa_1024_pub.pem 

在該命令成功運(yùn)行之后,在當(dāng)前目錄下會(huì)生成一個(gè) rsa_1024_pub.pem 文件,該文件的內(nèi)容如下:

  1. -----BEGIN PUBLIC KEY----- 
  2. MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDocWYwnJ4DYur0BjxFjJkLv4QR 
  3. JpTJnwjiwxkuJZe1HTIIuLbu/yHyHLhc2MAHKL0Ob+8tcKXKsL1oxs467+q0jA+g 
  4. lOUtBXFcUnutWBbnf9qIDkKP2uoDdZ//LUeW7jibVrVJbXU2hxB8bQpBkltZf/xs 
  5. cyhRIeiXxs13vlSHVwIDAQAB 
  6. -----END PUBLIC KEY----- 

2.4.2 創(chuàng)建 RSA 加密器和解密器

創(chuàng)建完公私鑰之后,我們就可以進(jìn)一步創(chuàng)建 RSA 加密器和解密器,具體代碼如下:

  1. const PUBLIC_KEY = `-----BEGIN PUBLIC KEY----- 
  2. MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDocWYwnJ4DYur0BjxFjJkLv4QR 
  3. ... 
  4. cyhRIeiXxs13vlSHVwIDAQAB 
  5. -----END PUBLIC KEY-----`; 
  6.  
  7. const PRIVATE_KEY = `-----BEGIN RSA PRIVATE KEY----- 
  8. MIICWwIBAAKBgQDocWYwnJ4DYur0BjxFjJkLv4QRJpTJnwjiwxkuJZe1HTIIuLbu 
  9. ... 
  10. bKkRJNJ2PpfWA45Vdq6u+izrn9e2TabKjWIfTfT/ZQ== 
  11. -----END RSA PRIVATE KEY-----`; 
  12.  
  13. const encryptor = new JSEncrypt(); // RSA加密器 
  14. encryptor.setPublicKey(PUBLIC_KEY); 
  15.  
  16. const decryptor = new JSEncrypt(); // RSA解密器 
  17. decryptor.setPrivateKey(PRIVATE_KEY); 

2.4.3 RSA 加密與解密示例(下圖標(biāo)題為 RSA非對(duì)稱加密)

 

在以上示例中,我們?cè)陧撁嫔蟿?chuàng)建了 3 個(gè) textarea,分別用于存放明文、加密后的密文和解密后的明文。當(dāng)用戶點(diǎn)擊 加密 按鈕時(shí),會(huì)對(duì)用戶輸入的明文進(jìn)行 RSA 加密,完成加密后,會(huì)把密文顯示在密文對(duì)應(yīng)的 textarea 中,當(dāng)用戶點(diǎn)擊 解密 按鈕時(shí),會(huì)對(duì)密文進(jìn)行 RSA 解密,完成解密后,會(huì)把解密后的明文顯示在對(duì)應(yīng)的 textarea 中。

以上示例對(duì)應(yīng)的完整代碼如下所示:

阿寶哥:RSA 非對(duì)稱加密與解密示例

  1. <!DOCTYPE html> 
  2. <html> 
  3.   <head> 
  4.     <meta charset="UTF-8" /> 
  5.     <meta name="viewport" content="width=device-width, initial-scale=1.0" /> 
  6.     <title>RSA 非對(duì)稱加密與解密示例</title> 
  7.     <style> 
  8.       .block { 
  9.         flex: 1; 
  10.       } 
  11.     </style> 
  12.   </head> 
  13.   <body> 
  14.     <h3>阿寶哥:RSA 非對(duì)稱加密與解密示例</h3> 
  15.     <div style="display: flex;"
  16.       <div class="block"
  17.         <p>①明文加密 => <button onclick="encrypt()">加密</button></p> 
  18.         <textarea id="plaintext" rows="5" cols="15"></textarea> 
  19.       </div> 
  20.       <div class="block"
  21.         <p>②密文解密 => <button onclick="decrypt()">解密</button></p> 
  22.         <textarea id="ciphertext" rows="5" cols="15"></textarea> 
  23.       </div> 
  24.       <div class="block"
  25.         <p>③解密后的明文</p> 
  26.         <textarea id="decryptedCiphertext" rows="5" cols="15"></textarea> 
  27.       </div> 
  28.     </div> 
  29.     <script src="https://cdn.bootcdn.net/ajax/libs/jsencrypt/2.3.1/jsencrypt.min.js"></script> 
  30.     <script> 
  31.       const PUBLIC_KEY = `-----BEGIN PUBLIC KEY----- 
  32. MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDocWYwnJ4DYur0BjxFjJkLv4QR 
  33. JpTJnwjiwxkuJZe1HTIIuLbu/yHyHLhc2MAHKL0Ob+8tcKXKsL1oxs467+q0jA+g 
  34. lOUtBXFcUnutWBbnf9qIDkKP2uoDdZ//LUeW7jibVrVJbXU2hxB8bQpBkltZf/xs 
  35. cyhRIeiXxs13vlSHVwIDAQAB 
  36. -----END PUBLIC KEY-----`; 
  37.       const PRIVATE_KEY = `-----BEGIN RSA PRIVATE KEY----- 
  38. MIICWwIBAAKBgQDocWYwnJ4DYur0BjxFjJkLv4QRJpTJnwjiwxkuJZe1HTIIuLbu 
  39. /yHyHLhc2MAHKL0Ob+8tcKXKsL1oxs467+q0jA+glOUtBXFcUnutWBbnf9qIDkKP 
  40. 2uoDdZ//LUeW7jibVrVJbXU2hxB8bQpBkltZf/xscyhRIeiXxs13vlSHVwIDAQAB 
  41. AoGAKOarYKpuc5IYXdArEuHmnFaa2pm7XK8LVTuXVrNuuoPkpfw61Fs4ke3T0yKg 
  42. x6G3gq7Xm1tTEROAgMtaxqwo1D5n1H0nkyDFggLB0K9Ws0frp7HENtSQwdNSry1A 
  43. iD8TLxkhoWo7BS0VViLT1gKOfnw4YeMJP+CcOQ+DQjCsUMECQQD0Nc0vKBTlK6GT 
  44. 28gcIMVoQy2KicjiH222A9/TLCNAQ9DEeZDYEptuTfrlbggfWdgQ3nc6CyvGf6c5 
  45. 6uBPi/+5AkEA86oqqZPi7ekkUVHx0VSkp0mTlD1tAPhDE8cLX8vyImGExS+tTznz 
  46. ROyzm3T1M1PisdQIU8Wd5rqvHP6dB0enjwJAauhKpMQ1MYYCPApQ9g9anCQcgbOD 
  47. 34nGq5HSoE2IOQ/3Cqv1PsIWjRlSJrIemCrqrafWJfDR/xnPCUnLXMd68QJAPNwG 
  48. 1d4zMvslcA5ImOFMUuBEtST2geSAVINFqwK0krPKxrmWzxAJW/DHF5AJ4m0UVRhB 
  49. kDLusn90V4iczgGurwJAZUz6w01OeoLhsOuWNvkbTq+IV0NQ5GAEGA721Ck5zp86 
  50. bKkRJNJ2PpfWA45Vdq6u+izrn9e2TabKjWIfTfT/ZQ== 
  51. -----END RSA PRIVATE KEY-----`; 
  52.  
  53.       const encryptor = new JSEncrypt(); // RSA加密器 
  54.       encryptor.setPublicKey(PUBLIC_KEY); 
  55.  
  56.       const decryptor = new JSEncrypt(); // RSA解密器 
  57.       decryptor.setPrivateKey(PRIVATE_KEY); 
  58.  
  59.       const plaintextEle = document.querySelector("#plaintext"); 
  60.       const ciphertextEle = document.querySelector("#ciphertext"); 
  61.       const decryptedCiphertextEle = document.querySelector( 
  62.         "#decryptedCiphertext" 
  63.       ); 
  64.  
  65.       function encrypt() { 
  66.         let plaintext = plaintextEle.value; 
  67.         ciphertextEle.value = encryptor.encrypt(plaintext); 
  68.       } 
  69.  
  70.       function decrypt() { 
  71.         let ciphertext = ciphertextEle.value; 
  72.         decryptedCiphertextEle.value = decryptor.decrypt(ciphertext); 
  73.       } 
  74.     </script> 
  75.   </body> 
  76. </html> 

 

在上面的示例中,我們通過 RSA 非對(duì)稱加密算法,對(duì) “我是阿寶哥” 明文進(jìn)行加密,從而實(shí)現(xiàn)信息隱蔽。

 

那么使用非對(duì)稱加密算法就可以解決我們前面的問題么?答案是否定,這是因?yàn)榉菍?duì)稱加密也存在一些的缺點(diǎn)。

2.5 非對(duì)稱加密的缺點(diǎn)

非對(duì)稱加密算法加密和解密花費(fèi)時(shí)間長(zhǎng)、速度慢,只適合對(duì)少量數(shù)據(jù)進(jìn)行加密。因?yàn)槲覀円峁┑氖峭ㄓ玫慕鉀Q方案,即要同時(shí)考慮到少量數(shù)據(jù)和大量數(shù)據(jù)的情況,所以非對(duì)稱加密也不是一個(gè)好的解決方案。為了解決問題,阿寶哥又重新開啟了一輪新的對(duì)話。

 

三、混合加密

3.1 什么是混合加密

混合加密是結(jié)合 對(duì)稱加密 和 非對(duì)稱加密 各自優(yōu)點(diǎn)的一種加密方式。其具體的實(shí)現(xiàn)思路是先使用 對(duì)稱加密算法 對(duì)數(shù)據(jù)進(jìn)行加密,然后使用非對(duì)稱加密算法對(duì) 對(duì)稱加密的密鑰進(jìn)行非對(duì)稱加密,之后再把加密后的密鑰和加密后的數(shù)據(jù)發(fā)送給接收方。

為了讓小伙伴們更加直觀理解上述的過程,阿寶哥花了點(diǎn)心思畫了一張圖,用來進(jìn)一步說明混合加密的過程,下面我們就一起來看圖吧。

3.2 混合加密的過程

 

3.3 混合加密的實(shí)現(xiàn)

了解完 “混合加密數(shù)據(jù)傳輸流程”,阿寶哥跟小伙伴一起來實(shí)現(xiàn)一下上述的混合加密流程。這里我們會(huì)基于前面介紹過的對(duì)稱加密和非對(duì)稱加密的示例進(jìn)行開發(fā),即以下示例會(huì)直接利用前面非對(duì)稱加密示例中用到的公私鑰。

3.3.1 創(chuàng)建生成隨機(jī) AES 密鑰的函數(shù)

  1. function getRandomAESKey() { 
  2.   return ( 
  3.     Math.random().toString(36).substring(2, 10) + 
  4.     Math.random().toString(36).substring(2, 10) 
  5.   ); 

3.3.2 創(chuàng)建 AES 加密和解密函數(shù)

  1. // AES加密 
  2. function aesEncrypt(key, iv, content) { 
  3.   let text = CryptoJS.enc.Utf8.parse(JSON.stringify(content)); 
  4.   let encrypted = CryptoJS.AES.encrypt(text, key, { 
  5.     iv: iv, 
  6.     mode: CryptoJS.mode.CBC, 
  7.     padding: CryptoJS.pad.Pkcs7, 
  8.   }); 
  9.   return encrypted.toString(); 
  10.  
  11. // AES解密 
  12. function aesDecrypt(key, iv, content) { 
  13.   let decrypt = CryptoJS.AES.decrypt(content, key, { 
  14.     iv: iv, 
  15.     mode: CryptoJS.mode.CBC, 
  16.     padding: CryptoJS.pad.Pkcs7, 
  17.   }); 
  18.   return decrypt.toString(CryptoJS.enc.Utf8); 

3.3.3 創(chuàng)建 RSA 加密器和解密器

  1. const PUBLIC_KEY = `-----BEGIN PUBLIC KEY----- 
  2. MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDocWYwnJ4DYur0BjxFjJkLv4QR 
  3. ... 
  4. cyhRIeiXxs13vlSHVwIDAQAB 
  5. -----END PUBLIC KEY-----`; 
  6.  
  7. const PRIVATE_KEY = `-----BEGIN RSA PRIVATE KEY----- 
  8. MIICWwIBAAKBgQDocWYwnJ4DYur0BjxFjJkLv4QRJpTJnwjiwxkuJZe1HTIIuLbu 
  9. ... 
  10. bKkRJNJ2PpfWA45Vdq6u+izrn9e2TabKjWIfTfT/ZQ== 
  11. -----END RSA PRIVATE KEY-----`; 
  12.  
  13. const rsaEncryptor = new JSEncrypt(); // RSA加密器 
  14. rsaEncryptor.setPublicKey(PUBLIC_KEY); 
  15.  
  16. const rsaDecryptor = new JSEncrypt(); // RSA解密器 
  17. rsaDecryptor.setPrivateKey(PRIVATE_KEY); 

3.3.4 創(chuàng)建混合加密加密和解密函數(shù)

  1. function hybirdEncrypt(data) { 
  2.   const iv = getRandomAESKey(); 
  3.   const key = getRandomAESKey(); 
  4.   const encryptedData = aesEncrypt(key, iv, data); 
  5.   const encryptedIv = rsaEncryptor.encrypt(iv); 
  6.   const encryptedKey = rsaEncryptor.encrypt(key); 
  7.   return { 
  8.     iv: encryptedIv, 
  9.     key: encryptedKey, 
  10.     data: encryptedData, 
  11.    }; 
  12.  
  13. function hybirdDecrypt(encryptedResult) { 
  14.   const iv = rsaDecryptor.decrypt(encryptedResult.iv); 
  15.   const key = rsaDecryptor.decrypt(encryptedResult.key); 
  16.   const data = encryptedResult.data; 
  17.   return aesDecrypt(key, iv, data); 

3.3.5 混合加密與解密示例

以上步驟完成之后,我們基本已經(jīng)完成了混合加密的功能,在看完整代碼之前,我們先來看一下實(shí)際的運(yùn)行效果:

 

備注:密文解密下方對(duì)應(yīng)的 textarea 文本框中,除了加密的數(shù)據(jù)之外,還會(huì)包含使用 RSA 加密過的 AES CBC 模式中的 iv 和 key。

在以上示例中,我們?cè)陧撁嫔蟿?chuàng)建了 3 個(gè) textarea,分別用于存放明文、加密后的數(shù)據(jù)和解密后的明文。當(dāng)用戶點(diǎn)擊 加密 按鈕時(shí),會(huì)對(duì)用戶輸入的明文進(jìn)行混合加密,完成加密后,會(huì)把加密的數(shù)據(jù)顯示在密文對(duì)應(yīng)的 textarea 中,當(dāng)用戶點(diǎn)擊 解密 按鈕時(shí),會(huì)對(duì)密文進(jìn)行 混合解密,即先使用 RSA 私鑰解密 AES 的 key 和 iv,然后再使用它們對(duì) AES 加密過的密文進(jìn)行 AES 解密,完成解密后,會(huì)把解密后的明文顯示在對(duì)應(yīng)的 textarea 中。

以上示例對(duì)應(yīng)的完整代碼如下所示:

阿寶哥:混合加密與解密示例

  1. <!DOCTYPE html> 
  2. <html> 
  3.   <head> 
  4.     <meta charset="UTF-8" /> 
  5.     <meta name="viewport" content="width=device-width, initial-scale=1.0" /> 
  6.     <title>混合加密與解密示例</title> 
  7.     <style> 
  8.       .block { 
  9.         flex: 1; 
  10.       } 
  11.     </style> 
  12.   </head> 
  13.   <body> 
  14.     <h3>阿寶哥:混合加密與解密示例</h3> 
  15.     <div style="display: flex;"
  16.       <div class="block"
  17.         <p>①明文加密 => <button onclick="encrypt()">加密</button></p> 
  18.         <textarea id="plaintext" rows="5" cols="15"></textarea> 
  19.       </div> 
  20.       <div class="block"
  21.         <p>②密文解密 => <button onclick="decrypt()">解密</button></p> 
  22.         <textarea id="ciphertext" rows="5" cols="15"></textarea> 
  23.       </div> 
  24.       <div class="block"
  25.         <p>③解密后的明文</p> 
  26.         <textarea id="decryptedCiphertext" rows="5" cols="15"></textarea> 
  27.       </div> 
  28.     </div> 
  29.     <!-- 引入 CDN Crypto.js AES加密 --> 
  30.     <script src="https://cdn.bootcdn.net/ajax/libs/crypto-js/4.0.0/core.min.js"></script> 
  31.     <script src="https://cdn.bootcdn.net/ajax/libs/crypto-js/4.0.0/enc-base64.min.js"></script> 
  32.     <script src="https://cdn.bootcdn.net/ajax/libs/crypto-js/4.0.0/md5.min.js"></script> 
  33.     <script src="https://cdn.bootcdn.net/ajax/libs/crypto-js/4.0.0/evpkdf.min.js"></script> 
  34.     <script src="https://cdn.bootcdn.net/ajax/libs/crypto-js/4.0.0/cipher-core.min.js"></script> 
  35.     <script src="https://cdn.bootcdn.net/ajax/libs/crypto-js/4.0.0/aes.min.js"></script> 
  36.     <script src="https://cdn.bootcdn.net/ajax/libs/crypto-js/4.0.0/pad-pkcs7.min.js"></script> 
  37.     <script src="https://cdn.bootcdn.net/ajax/libs/crypto-js/4.0.0/enc-utf8.min.js"></script> 
  38.     <!-- 引入 CDN Crypto.js 結(jié)束 --> 
  39.     <script src="https://cdn.bootcdn.net/ajax/libs/jsencrypt/2.3.1/jsencrypt.min.js"></script> 
  40.     <script> 
  41.       const PUBLIC_KEY = `-----BEGIN PUBLIC KEY----- 
  42. MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDocWYwnJ4DYur0BjxFjJkLv4QR 
  43. JpTJnwjiwxkuJZe1HTIIuLbu/yHyHLhc2MAHKL0Ob+8tcKXKsL1oxs467+q0jA+g 
  44. lOUtBXFcUnutWBbnf9qIDkKP2uoDdZ//LUeW7jibVrVJbXU2hxB8bQpBkltZf/xs 
  45. cyhRIeiXxs13vlSHVwIDAQAB 
  46. -----END PUBLIC KEY-----`; 
  47.       const PRIVATE_KEY = `-----BEGIN RSA PRIVATE KEY----- 
  48. MIICWwIBAAKBgQDocWYwnJ4DYur0BjxFjJkLv4QRJpTJnwjiwxkuJZe1HTIIuLbu 
  49. /yHyHLhc2MAHKL0Ob+8tcKXKsL1oxs467+q0jA+glOUtBXFcUnutWBbnf9qIDkKP 
  50. 2uoDdZ//LUeW7jibVrVJbXU2hxB8bQpBkltZf/xscyhRIeiXxs13vlSHVwIDAQAB 
  51. AoGAKOarYKpuc5IYXdArEuHmnFaa2pm7XK8LVTuXVrNuuoPkpfw61Fs4ke3T0yKg 
  52. x6G3gq7Xm1tTEROAgMtaxqwo1D5n1H0nkyDFggLB0K9Ws0frp7HENtSQwdNSry1A 
  53. iD8TLxkhoWo7BS0VViLT1gKOfnw4YeMJP+CcOQ+DQjCsUMECQQD0Nc0vKBTlK6GT 
  54. 28gcIMVoQy2KicjiH222A9/TLCNAQ9DEeZDYEptuTfrlbggfWdgQ3nc6CyvGf6c5 
  55. 6uBPi/+5AkEA86oqqZPi7ekkUVHx0VSkp0mTlD1tAPhDE8cLX8vyImGExS+tTznz 
  56. ROyzm3T1M1PisdQIU8Wd5rqvHP6dB0enjwJAauhKpMQ1MYYCPApQ9g9anCQcgbOD 
  57. 34nGq5HSoE2IOQ/3Cqv1PsIWjRlSJrIemCrqrafWJfDR/xnPCUnLXMd68QJAPNwG 
  58. 1d4zMvslcA5ImOFMUuBEtST2geSAVINFqwK0krPKxrmWzxAJW/DHF5AJ4m0UVRhB 
  59. kDLusn90V4iczgGurwJAZUz6w01OeoLhsOuWNvkbTq+IV0NQ5GAEGA721Ck5zp86 
  60. bKkRJNJ2PpfWA45Vdq6u+izrn9e2TabKjWIfTfT/ZQ== 
  61. -----END RSA PRIVATE KEY-----`; 
  62.  
  63.       const rsaEncryptor = new JSEncrypt(); // RSA加密器 
  64.       rsaEncryptor.setPublicKey(PUBLIC_KEY); 
  65.  
  66.       const rsaDecryptor = new JSEncrypt(); // RSA解密器 
  67.       rsaDecryptor.setPrivateKey(PRIVATE_KEY); 
  68.  
  69.       const plaintextEle = document.querySelector("#plaintext"); 
  70.       const ciphertextEle = document.querySelector("#ciphertext"); 
  71.       const decryptedCiphertextEle = document.querySelector( 
  72.         "#decryptedCiphertext" 
  73.       ); 
  74.  
  75.       function getRandomAESKey() { 
  76.         return ( 
  77.           Math.random().toString(36).substring(2, 10) + 
  78.           Math.random().toString(36).substring(2, 10) 
  79.         ); 
  80.       } 
  81.  
  82.       // AES加密 
  83.       function aesEncrypt(key, iv, content) { 
  84.         let text = CryptoJS.enc.Utf8.parse(JSON.stringify(content)); 
  85.         let encrypted = CryptoJS.AES.encrypt(text, key, { 
  86.           iv: iv, 
  87.           mode: CryptoJS.mode.CBC, 
  88.           padding: CryptoJS.pad.Pkcs7, 
  89.         }); 
  90.         return encrypted.toString(); 
  91.       } 
  92.  
  93.       // AES解密 
  94.       function aesDecrypt(key, iv, content) { 
  95.         let decrypt = CryptoJS.AES.decrypt(content, key, { 
  96.           iv: iv, 
  97.           mode: CryptoJS.mode.CBC, 
  98.           padding: CryptoJS.pad.Pkcs7, 
  99.         }); 
  100.         return decrypt.toString(CryptoJS.enc.Utf8); 
  101.       } 
  102.  
  103.       function hybirdEncrypt(data) { 
  104.         const iv = getRandomAESKey(); 
  105.         const key = getRandomAESKey(); 
  106.         const encryptedData = aesEncrypt(key, iv, data); 
  107.         const encryptedIv = rsaEncryptor.encrypt(iv); 
  108.         const encryptedKey = rsaEncryptor.encrypt(key); 
  109.         return { 
  110.           iv: encryptedIv, 
  111.           key: encryptedKey, 
  112.           data: encryptedData, 
  113.         }; 
  114.       } 
  115.  
  116.       function hybirdDecrypt(encryptedResult) { 
  117.         const iv = rsaDecryptor.decrypt(encryptedResult.iv); 
  118.         const key = rsaDecryptor.decrypt(encryptedResult.key); 
  119.         const data = encryptedResult.data; 
  120.         return aesDecrypt(key, iv, data); 
  121.       } 
  122.  
  123.       function encrypt() { 
  124.         let plaintext = plaintextEle.value; 
  125.         const encryptedResult = hybirdEncrypt(plaintext); 
  126.         ciphertextEle.value = JSON.stringify(encryptedResult); 
  127.       } 
  128.  
  129.       function decrypt() { 
  130.         let ciphertext = ciphertextEle.value; 
  131.         const encryptedResult = JSON.parse(ciphertext); 
  132.         decryptedCiphertextEle.value = hybirdDecrypt(encryptedResult).replace(/\"/g,''); 
  133.       } 
  134.     </script> 
  135.   </body> 
  136. </html> 

 

3.4 混合加密方案分析

通過這個(gè)示例,相信大家對(duì)混合加密已經(jīng)有了一定的了解。但在實(shí)際 Web 項(xiàng)目中,我們一般不會(huì)在客戶端進(jìn)行數(shù)據(jù)解密,而是會(huì)把數(shù)據(jù)提交到服務(wù)端,然后由服務(wù)端進(jìn)行數(shù)據(jù)解密和數(shù)據(jù)處理。

HTTP 協(xié)議對(duì)大多數(shù) Web 開發(fā)者來說,都不會(huì)陌生。HTTP 協(xié)議是基于請(qǐng)求和響應(yīng),具體如下圖所示:

 

在對(duì)數(shù)據(jù)安全要求較高的場(chǎng)景或傳輸敏感數(shù)據(jù)時(shí),我們就可以考慮利用前面的混合加密方案對(duì)提交到服務(wù)端的數(shù)據(jù)進(jìn)行混合加密,當(dāng)服務(wù)端接收到對(duì)應(yīng)的加密數(shù)據(jù)時(shí),再使用對(duì)應(yīng)的解密算法對(duì)加密的數(shù)據(jù)進(jìn)行解密,從而進(jìn)一步進(jìn)行數(shù)據(jù)處理。

但是如果服務(wù)端也要返回敏感數(shù)據(jù)時(shí),應(yīng)該怎么辦呢?這里阿寶哥給大家介紹一種方案,該方案只需使用一對(duì)公私鑰。當(dāng)然該方案僅供大家參考,如果你有好的方案,歡迎給阿寶哥留言或跟阿寶哥交流喲。

下面我們來看一下該方案的具體操作流程:

① 生成一個(gè)唯一的 reqId(請(qǐng)求 ID),用于標(biāo)識(shí)當(dāng)前請(qǐng)求;

② 分別生成一個(gè)隨機(jī)的 AES Key 和 AES IV(采用 AES CBC 模式);

③ 采用 RSA 非對(duì)稱加密算法,分別對(duì) AES Key 和 AES IV 進(jìn)行 RSA 非對(duì)稱加密;

④ 采用隨機(jī)生成的 AES Key 和 AES IV 對(duì)敏感數(shù)據(jù)進(jìn)行 AES 對(duì)稱加密;

⑤ 把 reqId 作為 key,AES Key 和 AES IV 組成的對(duì)象作為 value 保存到 Map 或 {} 對(duì)象中;

⑥ 把 reqId、加密后的 AES Key、AES IV 和加密后的數(shù)據(jù)保存到對(duì)象中提交到服務(wù)端;

⑦ 當(dāng)服務(wù)端接收到數(shù)據(jù)后,對(duì)接收的數(shù)據(jù)進(jìn)行解密,然后使用客戶端傳過來的解密后的 AES Key 和 AES IV 對(duì)響應(yīng)數(shù)據(jù)進(jìn)行 AES 對(duì)稱加密;

⑧ 服務(wù)端在完成數(shù)據(jù)加密后,把 reqId 和加密后的數(shù)據(jù)包裝成響應(yīng)對(duì)象,返回給客戶端;

⑨ 當(dāng)客戶端成功接收服務(wù)端的響應(yīng)后,先獲取 reqId,進(jìn)而從保存 AES Key 和 IV 的 Map 獲取該 reqId 對(duì)應(yīng)的 AES 加密信息;

⑩ 客戶端使用當(dāng)前 reqId 對(duì)應(yīng)的加密信息,對(duì)服務(wù)端返回的數(shù)據(jù)進(jìn)行解密,當(dāng)完成解密之后,從 Map 或 {} 對(duì)象中刪除已有記錄。

現(xiàn)在我們來對(duì)上述流程做個(gè)簡(jiǎn)單分析,首先 AES 加密信息都是隨機(jī)生成的且根據(jù)每個(gè)請(qǐng)求獨(dú)立地保存到內(nèi)存中,把 AES 加密信息中的 Key 和 IV 提交到服務(wù)端的時(shí)候都會(huì)使用 RSA 非對(duì)稱加密算法進(jìn)行加密。

在服務(wù)端返回?cái)?shù)據(jù)的時(shí)候,會(huì)使用當(dāng)前請(qǐng)求對(duì)應(yīng)的 AES 加密信息對(duì)返回的結(jié)果進(jìn)行加密,同時(shí)返回當(dāng)前請(qǐng)求對(duì)應(yīng)的 reqId(請(qǐng)求 ID)。即服務(wù)端不需要再生成新的 AES 加密信息,來對(duì)響應(yīng)數(shù)據(jù)進(jìn)行加密,這樣就不需要在響應(yīng)對(duì)象中傳遞 AES 加密信息。

該方案看似挺完美的,由于我們加密的信息還是存在內(nèi)存中,如果使用開發(fā)者工具對(duì) Web 應(yīng)用進(jìn)行調(diào)試時(shí),那么還是可以看到每個(gè)請(qǐng)求對(duì)應(yīng)的加密信息。那么這個(gè)問題該如何解決呢?能不能防止使用開發(fā)者工具對(duì)我們的 Web 應(yīng)用進(jìn)行調(diào)試,答案是有的。

不過這里阿寶哥就不繼續(xù)展開了,后面可能會(huì)單獨(dú)寫一篇文章來介紹如何防止使用開發(fā)者工具調(diào)試 Web 應(yīng)用,感興趣的小伙伴可以給我留言喲。

四、阿寶哥有話說

4.1 什么是消息摘要算法

其實(shí)在日常工作中,除了對(duì)稱加密和非對(duì)稱加密算法之外。還有一種用得比較廣的消息摘要算法。消息摘要算法是密碼學(xué)算法中非常重要的一個(gè)分支,它通過對(duì)所有數(shù)據(jù)提取指紋信息以實(shí)現(xiàn)數(shù)據(jù)簽名、數(shù)據(jù)完整性校驗(yàn)等功能,由于其不可逆性,有時(shí)候會(huì)被用做敏感信息的加密。消息摘要算法也被稱為哈希(Hash)算法或散列算法。

任何消息經(jīng)過散列函數(shù)處理后,都會(huì)獲得唯一的散列值,這一過程稱為 “消息摘要”,其散列值稱為 “數(shù)字指紋”,其算法自然就是 “消息摘要算法”了。 換句話說,如果其數(shù)字指紋一致,就說明其消息是一致的。

 

(圖片來源 —— https://zh.wikipedia.org/wiki/散列函數(shù))

消息摘要算法的主要特征是加密過程不需要密鑰,并且經(jīng)過加密的數(shù)據(jù)無法被解密,目前可以解密逆向的只有 CRC32 算法,只有輸入相同的明文數(shù)據(jù)經(jīng)過相同的消息摘要算法才能得到相同的密文。 消息摘要算法不存在密鑰的管理與分發(fā)問題,適合于分布式網(wǎng)絡(luò)上使用。消息摘要算法主要應(yīng)用在 “數(shù)字簽名” 領(lǐng)域,作為對(duì)明文的摘要算法。著名的摘要算法有 RSA 公司的 MD5 算法和 SHA-1 算法及其大量的變體。

消息摘要算法擁有以下特點(diǎn):

  • 無論輸入的消息有多長(zhǎng),計(jì)算出來的消息摘要的長(zhǎng)度總是固定的。 例如應(yīng)用 MD5 算法摘要的消息有 128 個(gè)比特位,用 SHA-1 算法摘要的消息最終有 160 個(gè)比特位的輸出,SHA-1的變體可以產(chǎn)生 192 個(gè)比特位和 256 個(gè)比特位的消息摘要。一般認(rèn)為,摘要的最終輸出越長(zhǎng),該摘要算法就越安全。
  • 消息摘要看起來是 “隨機(jī)的”。 這些比特看上去是胡亂的雜湊在一起的,可以用大量的輸入來檢驗(yàn)其輸出是否相同,一般,不同的輸入會(huì)有不同的輸出,而且輸出的摘要消息可以通過隨機(jī)性檢驗(yàn)。一般地,只要輸入的消息不同,對(duì)其進(jìn)行摘要以后產(chǎn)生的摘要消息也必不相同;但相同的輸入必會(huì)產(chǎn)生相同的輸出。
  • 消息摘要函數(shù)是單向函數(shù),即只能進(jìn)行正向的信息摘要,而無法從摘要中恢復(fù)出任何的消息,甚至根本就找不到任何與原信息相關(guān)的信息。
  • 好的摘要算法,沒有人能從中找到 “碰撞” 或者說極度難找到,雖然 “碰撞” 是肯定存在的(碰撞即不同的內(nèi)容產(chǎn)生相同的摘要)。

4.2 什么是 MD5 算法

MD5(Message Digest Algorithm 5,消息摘要算法版本5),它由 MD2、MD3、MD4 發(fā)展而來,由 Ron Rivest(RSA 公司)在 1992 年提出,目前被廣泛應(yīng)用于數(shù)據(jù)完整性校驗(yàn)、數(shù)據(jù)(消息)摘要、數(shù)據(jù)簽名等。MD2、MD4、MD5 都產(chǎn)生 16 字節(jié)(128 位)的校驗(yàn)值,一般用 32 位十六進(jìn)制數(shù)表示。MD2 的算法較慢但相對(duì)安全,MD4 速度很快,但安全性下降,MD5 比 MD4 更安全、速度更快。

隨著計(jì)算機(jī)技術(shù)的發(fā)展和計(jì)算水平的不斷提高,MD5 算法暴露出來的漏洞也越來越多。1996 年后被證實(shí)存在弱點(diǎn),可以被加以破解,對(duì)于需要高度安全性的數(shù)據(jù),專家一般建議改用其他算法,如 SHA-2。2004 年,證實(shí) MD5 算法無法防止碰撞(collision),因此不適用于安全性認(rèn)證,如 SSL 公開密鑰認(rèn)證或是數(shù)字簽名等用途。

4.2.1 MD5 特點(diǎn)

  • 穩(wěn)定、運(yùn)算速度快。
  • 壓縮性:輸入任意長(zhǎng)度的數(shù)據(jù),輸出長(zhǎng)度固定(128 比特位)。
  • 運(yùn)算不可逆:已知運(yùn)算結(jié)果的情況下,無法通過通過逆運(yùn)算得到原始字符串。
  • 高度離散:輸入的微小變化,可導(dǎo)致運(yùn)算結(jié)果差異巨大。

4.2.2 MD5 散列

128 位的 MD5 散列在大多數(shù)情況下會(huì)被表示為 32 位十六進(jìn)制數(shù)字。以下是一個(gè) 43 位長(zhǎng)的僅 ASCII 字母列的MD5 散列:

  1. MD5("The quick brown fox jumps over the lazy dog"
  2. = 9e107d9d372bb6826bd81d3542a419d6 

即使在原文中作一個(gè)小變化(比如把 dog 改為 cog,只改變一個(gè)字符)其散列也會(huì)發(fā)生巨大的變化:

  1. MD5("The quick brown fox jumps over the lazy cog"
  2. = 1055d3e698d289f2af8663725127bd4b 

接著我們?cè)賮砼e幾個(gè) MD5 散列的例子:

  1.       MD5("") -> d41d8cd98f00b204e9800998ecf8427e  
  2. ("semlinker") -> 688881f1c8aa6ffd3fcec471e0391e4d 
  3. MD5("kakuqo") -> e18c3c4dd05aef020946e6afbf9e04ef 

4.2.3 MD5 算法的用途

文件分發(fā)防篡改

在互聯(lián)網(wǎng)上分發(fā)軟件安裝包時(shí),出于安全性考慮,為了防止軟件被篡改,比如在軟件安裝程序中添加木馬程序。軟件開發(fā)者通常會(huì)使用消息摘要算法,比如 MD5 算法產(chǎn)生一個(gè)與文件匹配的數(shù)字指紋,這樣接收者在接收到文件后,就可以利用一些現(xiàn)成的工具來檢查文件完整性。

消息傳輸防篡改

假設(shè)在網(wǎng)絡(luò)上你需要發(fā)送電子文檔給你的朋友,在文件發(fā)送前,先對(duì)文檔的內(nèi)容進(jìn)行 MD5 運(yùn)算,得出該電子文檔的 “數(shù)字指紋”,并把該 “數(shù)字指紋” 隨電子文檔一同發(fā)送給對(duì)方。當(dāng)對(duì)方接收到電子文檔之后,也使用 MD5 算法對(duì)文檔的內(nèi)容進(jìn)行哈希運(yùn)算,在運(yùn)算完成后也會(huì)得到一個(gè)對(duì)應(yīng) “數(shù)字指紋”,當(dāng)該指紋與你所發(fā)送文檔的 “數(shù)字指紋” 一致時(shí),表示文檔在傳輸過程中未被篡改。

4.2.4 MD5 算法的缺陷

哈希碰撞是指不同的輸入?yún)s產(chǎn)生了相同的輸出,好的哈希算法,應(yīng)該沒有人能從中找到 “碰撞” 或者說極度難找到,雖然 “碰撞” 是肯定存在的。

2005 年山東大學(xué)的王小云教授發(fā)布算法可以輕易構(gòu)造 MD5 碰撞實(shí)例,此后 2007 年,有國(guó)外學(xué)者在王小云教授算法的基礎(chǔ)上,提出了更進(jìn)一步的 MD5 前綴碰撞構(gòu)造算法 “chosen prefix collision”,此后還有專家陸續(xù)提供了MD5 碰撞構(gòu)造的開源的庫(kù)。

2009 年,中國(guó)科學(xué)院的謝濤和馮登國(guó)僅用了 220.96 的碰撞算法復(fù)雜度,破解了 MD5 的碰撞抵抗,該攻擊在普通計(jì)算機(jī)上運(yùn)行只需要數(shù)秒鐘。

MD5 碰撞很容易構(gòu)造,基于 MD5 來驗(yàn)證數(shù)據(jù)完整性已不可靠,考慮到近期谷歌已成功構(gòu)造了 SHA-1(英語:Secure Hash Algorithm 1,中文名:安全散列算法1)的碰撞實(shí)例,對(duì)于數(shù)據(jù)完整性,應(yīng)使用 SHA256 或更強(qiáng)的算法代替。

其實(shí) MD5 的相關(guān)知識(shí)還有挺多,比如 MD5 密文反向查詢、密碼加鹽和實(shí)現(xiàn)內(nèi)容資源防盜鏈等。這里阿寶哥就不繼續(xù)展開了,感興趣的小伙伴可以閱讀阿寶哥之前寫的 ”一文讀懂 MD5 算法“ 這篇文章。

五、參考資源

百度百科 - 數(shù)據(jù)加密

百度百科 - 對(duì)稱加密

 

 

責(zé)任編輯:武曉燕 來源: 全棧修仙之路
相關(guān)推薦

2019-05-13 09:11:41

加密解密Python攻擊

2021-08-24 15:57:08

戴爾

2020-03-04 10:27:17

GitGo語言云計(jì)算

2011-05-19 10:57:45

DNSSEC密鑰加密

2014-06-13 14:27:46

2014-01-22 09:14:27

2022-08-15 11:35:09

去中心化加密貨幣制裁

2016-07-21 09:33:23

甲骨文

2017-08-01 18:06:56

2016-08-22 13:22:11

混合云云計(jì)算

2017-03-01 15:38:01

混合云模式正確

2016-01-13 13:47:04

云計(jì)算混合云私有云

2010-08-26 11:15:47

LinuxICMP后門

2023-10-10 09:07:23

2017-01-11 19:00:05

Android嵌套滾動(dòng)移動(dòng)開發(fā)

2010-09-06 14:32:55

CISCO PPP配置

2009-11-17 09:32:32

PHP數(shù)值函數(shù)

2021-03-01 19:20:32

多云IT架構(gòu)

2021-03-10 11:11:44

混合云IT云數(shù)據(jù)

2019-05-16 13:31:29

混合云企業(yè)IT廠商
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)