前置知識
不瞭解對稱加密與非對稱加密的小夥伴可以看看下面的文章,想詳細學習與區塊鏈有關的加密演算法可以戳這裡
對稱與非對稱加密
https://blog.csdn.net/u013320868/article/details/54090295
ECC
ECC橢圓曲線詳解(有具體例項) - Kalafinaian - 部落格園 (cnblogs.com)
AES
維基百科:https://zh.wikipedia.org/wiki/%E9%AB%98%E7%BA%A7%E5%8A%A0%E5%AF%86%E6%A0%87%E5%87%86
ECC+AES
Bob給Alice發訊息,Bob用AES金鑰mB加密訊息得到密文M,用Alice的公鑰PA加密AES的金鑰mB得到mB',將M和mB'發給Alice,Alice拿到後用自己的私鑰解密mB'得到mB,再用mB解密M得到明文。
為什麼不能直接用ECC進行非對稱加密,要用ECC加密AES的金鑰?
如果單獨使用AES,沒有經過加密的金鑰不方便傳遞,很容易在傳輸中被截獲。
如果單獨使用ECC,非對稱加密的速度慢、加密效率低。
因此對稱與非對稱加密結合可以兼顧效率和安全性,也在微信等成熟通訊軟體中被廣泛使用。
程式碼
ECC橢圓曲線加密演算法目前的應用還不是很成熟,crypto-js中沒有應用ECC的加密函式。
通過npm搜尋eccrypto會找到一些由個人釋出的package,大多涉及JavaScript中的Promise物件,不熟悉的小夥伴可以先了解一下Promise。
Promise - 廖雪峰的官方網站 (liaoxuefeng.com)
我選擇了使用eccrypto-js(www.npmjs.com),這個package包含了實現AES和ECC的函式,且引數型別都是buffer,如果不能同時包含就要import不同的package,引數型別等可能不相容,會帶來一些麻煩。
該示例是前端加解密的示例,在實際應用中適用於端對端加密,不涉及伺服器的加解密。
由於文章只能給出一個加密示例,沒有具體的通訊介面,所以我就用註釋Alice來表示Alice端,Bob來表示Bob端,並模擬Alice向Bob通訊的過程,Bob向Alice通訊就是反向過程,不多贅述。加解密得到的資訊輸出到控制檯中。
PS:
1.在程式碼中,ECC的公私鑰和AES的金鑰都是隨機產生的,實際生產中私鑰通常和錢包或者賬戶關聯。
2.加解密和通訊過程中都是使用buffer型別,在控制檯顯示時注意轉換成string。
import * as eccryptoJS from 'eccrypto-js' //加解密函式的引數都是buffer類 //Alice //一個新的隨機的32位元組私鑰,私鑰對應的未壓縮(65位元組)公鑰。 const keyPairA = eccryptoJS.generateKeyPair(); console.info("privateKey:", keyPairA.privateKey); console.info("publicKey:", keyPairA.publicKey); //send publicKey to Bob //Bob //隨機生成AES的金鑰 const AESKey = eccryptoJS.randomBytes(32); console.info("AESKey:", AESKey); const iv = eccryptoJS.randomBytes(16); //用ECC加密AES金鑰 const EncryptedAESKey = await eccryptoJS.encrypt(keyPairA.publicKey, AESKey); console.info("EncryptedAESKey:", EncryptedAESKey); //待傳送的明文str,先轉成buffer格式 const str = 'test message to encrypt'; const msg = eccryptoJS.utf8ToBuffer(str); //用未加密的AES金鑰加密明文 const ciphertext = await eccryptoJS.aesCbcEncrypt(iv, AESKey, msg); console.info("ciphertext:", ciphertext); //send 密文encrypt_str and AESKeyEncrypt to Alice,iv? //Alice //用私鑰解密加密後的AES金鑰 const DecryptedAESKey = await eccryptoJS.decrypt(keyPairA.privateKey, EncryptedAESKey); console.info("decryptedAESKey:", DecryptedAESKey); //用AES金鑰解密明文 const decrypted = await eccryptoJS.aesCbcDecrypt(iv, DecryptedAESKey, ciphertext); console.info("decrypted:", decrypted.toString());