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());
});
});