eccrypto爲用於瀏覽器和Node的橢圓曲線加密庫。
動機
沒有任何同構的ECC庫爲Node.js和瀏覽器提供ECDSA、ECDH和ECIES,並且使用最快的實現(例如secp256k1-node比其他庫快得多,但只能在Node.js上使用)。所以eccrypto是一種創造的嘗試。
實現細節
在Browserify的幫助下,eccrypto使用相同的API爲瀏覽器和Node.js提供了不同的實現。因爲WebCryptoAPI定義了異步promise-drive的API,所以Node的實現也需要使用promises 。
在可能的情況下,使用Node.js加密模塊/庫綁定,在可能的情況下使用WebCryptoAPI,只有secp256k1曲線,只有sha-512(Kdf),hmac-sha-256(Hmac)和aes-256-cbc,用於ECIES壓縮密鑰支持。
本地加密API限制
crypto
ECDH僅在Node 0.11+中運行(請參閱https://github.com/joyent/node/pull/5854),ECDSA僅支持PEM格式的密鑰(請參見https://github.com/joyent/node/issues/6904 ),根本不支持ECIES。
WebCryptoAPI
Chrome只在Windows上支持ECDSA和ECDH(參見bug 338883),Firefox不支持ECDSA和ECDH(僅在36.0+中修復,請參見bug 1034854;請參見功能矩陣),而且WebCryptoAPI草案中根本沒有定義ECIES。另外,WebCryptoAPI目前只定義了NIST推薦的曲線,這意味着不支持Secp256k1(K-256)曲線(另請參閱:[1],[2])。因此,我們在Node中使用seck256k1庫進行ECDSA,在瀏覽器中使用橢圓庫實現ECDSA和ECDH,並藉助本機密碼API手動實現ECIES。
可能的未來目標
支持其他曲線/kdf/mac/對稱加密方案
用法
ECDSA
//適用於數字貨幣賬戶體系
var crypto = require("crypto"); //官方庫
var eccrypto = require("eccrypto"); //橢圓曲線加密庫
//一個新的隨機的32字節私鑰。
var privateKey = eccrypto.generatePrivate();
//私鑰對應的未壓縮(65字節)公鑰。
var publicKey = eccrypto.getPublic(privateKey);
//字符串
var str = "message to sign";
//使用sha256哈希字符串
var msg = crypto.createHash("sha256").update(str).digest();
//使用私鑰簽名哈希數據
eccrypto.sign(privateKey, msg).then(function(sig) {
console.log("Signature in DER format:", sig);
//使用公鑰驗證簽名數據和哈希數據是否匹配
eccrypto.verify(publicKey, msg, sig).then(function() {
console.log("Signature is OK");
}).catch(function() {
console.log("Signature is BAD");
});
});
ECDH
//適用於點對點通信加密
var eccrypto = require("eccrypto");
//獲得兩對公私玥
var privateKeyA = eccrypto.generatePrivate();
var publicKeyA = eccrypto.getPublic(privateKeyA);
var privateKeyB = eccrypto.generatePrivate();
var publicKeyB = eccrypto.getPublic(privateKeyB);
//使用A私鑰和B公鑰生成雙方通信的加密私鑰
eccrypto.derive(privateKeyA, publicKeyB).then(function(sharedKey1) {
//使用B的私鑰和A的公鑰生成雙方通信的加密私鑰
eccrypto.derive(privateKeyB, publicKeyA).then(function(sharedKey2) {
//ECDH算法該加密私鑰應該相等
console.log("Both shared keys are equal:", sharedKey1, sharedKey2);
});
});
ECIES
//適用於對數據進行非對稱加密
var eccrypto = require("eccrypto");
//生成兩對公私鑰
var privateKeyA = eccrypto.generatePrivate();
var publicKeyA = eccrypto.getPublic(privateKeyA);
var privateKeyB = eccrypto.generatePrivate();
var publicKeyB = eccrypto.getPublic(privateKeyB);
//使用B的公鑰加密字符串字節
eccrypto.encrypt(publicKeyB, Buffer.from("msg to b")).then(function(encrypted) {
//使用B的私鑰解密字符串字節
eccrypto.decrypt(privateKeyB, encrypted).then(function(plaintext) {
console.log("Message to part B:", plaintext.toString());
});
});
//使用A的公鑰加密字符串字節
eccrypto.encrypt(publicKeyA, Buffer.from("msg to a")).then(function(encrypted) {
//使用A的私鑰解密字符串字節
eccrypto.decrypt(privateKeyA, encrypted).then(function(plaintext) {
console.log("Message to part A:", plaintext.toString());
});
});