ECDH (Browser)

This commit is contained in:
Kagami Hiiragi 2015-01-12 22:17:29 +03:00
parent e723993d1c
commit 9a9555a797
2 changed files with 59 additions and 26 deletions

View File

@ -21,6 +21,8 @@ function assert(condition, message) {
} }
exports.getPublic = function(privateKey) { exports.getPublic = function(privateKey) {
// This function has sync API so we throw an error immediately.
// (`elliptic` doesn't do this).
assert(privateKey.length === 32, "Bad private key"); assert(privateKey.length === 32, "Bad private key");
// XXX(Kagami): `elliptic.utils.encode` returns array for every // XXX(Kagami): `elliptic.utils.encode` returns array for every
// encoding except `hex`. // encoding except `hex`.
@ -28,15 +30,24 @@ exports.getPublic = function(privateKey) {
}; };
exports.sign = function(privateKey, msg) { exports.sign = function(privateKey, msg) {
var key = ec.keyPair(privateKey);
return new Promise(function(resolve) { return new Promise(function(resolve) {
var key = ec.keyPair(privateKey);
resolve(new Buffer(key.sign(msg).toDER())); resolve(new Buffer(key.sign(msg).toDER()));
}); });
}; };
exports.verify = function(key, msg, sig) { exports.verify = function(key, msg, sig) {
key = ec.keyPair(key);
return new Promise(function(resolve, reject) { return new Promise(function(resolve, reject) {
key = ec.keyPair(key);
return key.verify(msg, sig) ? resolve() : reject(); return key.verify(msg, sig) ? resolve() : reject();
}); });
}; };
exports.derive = function(privateKeyA, publicKeyB) {
return new Promise(function(resolve) {
var keyA = ec.keyPair(privateKeyA);
var keyB = ec.keyPair(publicKeyB);
var Px = keyA.derive(keyB.getPublic()); // BN instance
resolve(new Buffer(Px.toString(16), "hex"));
});
};

54
test.js
View File

@ -2,11 +2,20 @@ var expect = require("chai").expect;
var crypto = require("crypto"); var crypto = require("crypto");
var eccrypto = require("./"); var eccrypto = require("./");
var msg = crypto.createHash("sha256").update("test").digest();
var otherMsg = crypto.createHash("sha256").update("test2").digest();
var privateKey = Buffer(32); var privateKey = Buffer(32);
privateKey.fill(1); privateKey.fill(1);
var publicKey = eccrypto.getPublic(privateKey); var publicKey = eccrypto.getPublic(privateKey);
var msg = crypto.createHash("sha256").update("test").digest();
var otherMsg = crypto.createHash("sha256").update("test2").digest(); var privateKeyA = Buffer(32);
privateKeyA.fill(2);
var publicKeyA = eccrypto.getPublic(privateKeyA);
var privateKeyB = Buffer(32);
privateKeyB.fill(3);
var publicKeyB = eccrypto.getPublic(privateKeyB);
describe("Key convertion", function() { describe("Key convertion", function() {
it("should allow to convert private key to public", function() { it("should allow to convert private key to public", function() {
@ -22,8 +31,7 @@ describe("Key convertion", function() {
describe("ECDSA", function() { describe("ECDSA", function() {
it("should allow to sign and verify message", function() { it("should allow to sign and verify message", function() {
return eccrypto.sign(privateKey, msg) return eccrypto.sign(privateKey, msg).then(function(sig) {
.then(function(sig) {
expect(Buffer.isBuffer(sig)).to.be.true; expect(Buffer.isBuffer(sig)).to.be.true;
expect(sig.toString("hex")).to.equal("3044022078c15897a34de6566a0d396fdef660698c59fef56d34ee36bef14ad89ee0f6f8022016e02e8b7285d93feafafbe745702f142973a77d5c2fa6293596357e17b3b47c"); expect(sig.toString("hex")).to.equal("3044022078c15897a34de6566a0d396fdef660698c59fef56d34ee36bef14ad89ee0f6f8022016e02e8b7285d93feafafbe745702f142973a77d5c2fa6293596357e17b3b47c");
return eccrypto.verify(publicKey, msg, sig); return eccrypto.verify(publicKey, msg, sig);
@ -39,14 +47,13 @@ describe("ECDSA", function() {
}); });
it("shouldn't verify incorrect signature", function(done) { it("shouldn't verify incorrect signature", function(done) {
eccrypto.sign(privateKey, msg) eccrypto.sign(privateKey, msg).then(function(sig) {
.then(function(sig) {
expect(Buffer.isBuffer(sig)).to.be.true; expect(Buffer.isBuffer(sig)).to.be.true;
return eccrypto.verify(publicKey, otherMsg, sig); eccrypto.verify(publicKey, otherMsg, sig).catch(function() {
}).catch(function() {
done(); done();
}); });
}); });
});
it("should reject promise on invalid key when signing", function(done) { it("should reject promise on invalid key when signing", function(done) {
eccrypto.sign(Buffer("test"), msg).catch(function() { eccrypto.sign(Buffer("test"), msg).catch(function() {
@ -55,23 +62,38 @@ describe("ECDSA", function() {
}); });
it("should reject promise on invalid key when verifying", function(done) { it("should reject promise on invalid key when verifying", function(done) {
eccrypto.sign(privateKey, msg) eccrypto.sign(privateKey, msg).then(function(sig) {
.then(function(sig) {
expect(Buffer.isBuffer(sig)).to.be.true; expect(Buffer.isBuffer(sig)).to.be.true;
return eccrypto.verify(Buffer("test"), msg, sig); eccrypto.verify(Buffer("test"), msg, sig).catch(function() {
}).catch(function() {
done(); done();
}); });
}); });
});
it("should reject promise on invalid sig when verifying", function(done) { it("should reject promise on invalid sig when verifying", function(done) {
eccrypto.sign(privateKey, msg) eccrypto.sign(privateKey, msg).then(function(sig) {
.then(function(sig) {
expect(Buffer.isBuffer(sig)).to.be.true; expect(Buffer.isBuffer(sig)).to.be.true;
sig[0] ^= 1; sig[0] ^= 1;
return eccrypto.verify(publicKey, msg, sig); eccrypto.verify(publicKey, msg, sig).catch(function() {
}).catch(function() {
done(); done();
}); });
}); });
});
}); });
if (typeof window !== "undefined") {
describe("ECDH", function() {
it("should derive shared secret from privkey A and pubkey B", function() {
return eccrypto.derive(privateKeyA, publicKeyB).then(function(Px) {
expect(Buffer.isBuffer(Px)).to.be.true;
expect(Px.length).to.equal(32);
expect(Px.toString("hex")).to.equal("aca78f27d5f23b2e7254a0bb8df128e7c0f922d47ccac72814501e07b7291886");
return eccrypto.derive(privateKeyB, publicKeyA).then(function(Px2) {
expect(Buffer.isBuffer(Px2)).to.be.true;
expect(Px2.length).to.equal(32);
expect(Px.toString("hex")).to.equal(Px2.toString("hex"));
});
});
});
});
}