2014-12-21 19:05:05 +01:00
|
|
|
var expect = require("chai").expect;
|
2015-01-20 21:17:25 +01:00
|
|
|
var createHash = require("crypto").createHash;
|
2015-01-13 14:21:11 +01:00
|
|
|
var bufferEqual = require("buffer-equal");
|
2014-12-23 21:28:40 +01:00
|
|
|
var eccrypto = require("./");
|
2014-12-21 19:05:05 +01:00
|
|
|
|
2015-01-20 21:17:25 +01:00
|
|
|
var msg = createHash("sha256").update("test").digest();
|
|
|
|
var otherMsg = createHash("sha256").update("test2").digest();
|
|
|
|
var shortMsg = createHash("sha1").update("test").digest();
|
2015-01-12 20:17:29 +01:00
|
|
|
|
2014-12-24 00:14:28 +01:00
|
|
|
var privateKey = Buffer(32);
|
|
|
|
privateKey.fill(1);
|
|
|
|
var publicKey = eccrypto.getPublic(privateKey);
|
2015-01-12 20:17:29 +01:00
|
|
|
|
|
|
|
var privateKeyA = Buffer(32);
|
|
|
|
privateKeyA.fill(2);
|
|
|
|
var publicKeyA = eccrypto.getPublic(privateKeyA);
|
|
|
|
|
|
|
|
var privateKeyB = Buffer(32);
|
|
|
|
privateKeyB.fill(3);
|
|
|
|
var publicKeyB = eccrypto.getPublic(privateKeyB);
|
2014-12-24 00:14:28 +01:00
|
|
|
|
2014-12-26 18:48:39 +01:00
|
|
|
describe("Key convertion", function() {
|
2014-12-24 00:14:28 +01:00
|
|
|
it("should allow to convert private key to public", function() {
|
2014-12-25 16:45:43 +01:00
|
|
|
expect(Buffer.isBuffer(publicKey)).to.be.true;
|
2014-12-24 00:14:28 +01:00
|
|
|
expect(publicKey.toString("hex")).to.equal("041b84c5567b126440995d3ed5aaba0565d71e1834604819ff9c17f5e9d5dd078f70beaf8f588b541507fed6a642c5ab42dfdf8120a7f639de5122d47a69a8e8d1");
|
|
|
|
});
|
2014-12-26 18:48:39 +01:00
|
|
|
|
|
|
|
it("should throw on invalid private key", function() {
|
2014-12-26 18:58:36 +01:00
|
|
|
expect(eccrypto.getPublic.bind(null, Buffer("00", "hex"))).to.throw(Error);
|
2014-12-27 13:47:25 +01:00
|
|
|
expect(eccrypto.getPublic.bind(null, Buffer("test"))).to.throw(Error);
|
2014-12-26 18:48:39 +01:00
|
|
|
});
|
2014-12-24 00:14:28 +01:00
|
|
|
});
|
|
|
|
|
|
|
|
describe("ECDSA", function() {
|
|
|
|
it("should allow to sign and verify message", function() {
|
2015-01-12 20:17:29 +01:00
|
|
|
return eccrypto.sign(privateKey, msg).then(function(sig) {
|
|
|
|
expect(Buffer.isBuffer(sig)).to.be.true;
|
|
|
|
expect(sig.toString("hex")).to.equal("3044022078c15897a34de6566a0d396fdef660698c59fef56d34ee36bef14ad89ee0f6f8022016e02e8b7285d93feafafbe745702f142973a77d5c2fa6293596357e17b3b47c");
|
|
|
|
return eccrypto.verify(publicKey, msg, sig);
|
|
|
|
});
|
2014-12-24 00:14:28 +01:00
|
|
|
});
|
|
|
|
|
|
|
|
it("shouldn't verify incorrect signature", function(done) {
|
2015-01-12 20:17:29 +01:00
|
|
|
eccrypto.sign(privateKey, msg).then(function(sig) {
|
|
|
|
expect(Buffer.isBuffer(sig)).to.be.true;
|
|
|
|
eccrypto.verify(publicKey, otherMsg, sig).catch(function() {
|
2014-12-24 00:14:28 +01:00
|
|
|
done();
|
|
|
|
});
|
2015-01-12 20:17:29 +01:00
|
|
|
});
|
2014-12-24 00:14:28 +01:00
|
|
|
});
|
|
|
|
|
|
|
|
it("should reject promise on invalid key when signing", function(done) {
|
2015-01-13 14:21:11 +01:00
|
|
|
var k4 = Buffer("test");
|
|
|
|
var k192 = Buffer("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", "hex");
|
|
|
|
var k384 = Buffer("bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", "hex");
|
|
|
|
eccrypto.sign(k4, msg).catch(function() {
|
|
|
|
eccrypto.sign(k192, msg).catch(function() {
|
|
|
|
eccrypto.sign(k384, msg).catch(function() {
|
|
|
|
done();
|
|
|
|
});
|
|
|
|
});
|
2014-12-24 00:14:28 +01:00
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
it("should reject promise on invalid key when verifying", function(done) {
|
2015-01-12 20:17:29 +01:00
|
|
|
eccrypto.sign(privateKey, msg).then(function(sig) {
|
|
|
|
expect(Buffer.isBuffer(sig)).to.be.true;
|
2015-01-18 21:23:16 +01:00
|
|
|
eccrypto.verify(Buffer("test"), msg, sig).catch(function() {
|
|
|
|
var badKey = new Buffer(65);
|
|
|
|
publicKey.copy(badKey);
|
|
|
|
badKey[0] ^= 1;
|
|
|
|
eccrypto.verify(badKey, msg, sig).catch(function() {
|
|
|
|
done();
|
|
|
|
});
|
2014-12-24 00:14:28 +01:00
|
|
|
});
|
2015-01-12 20:17:29 +01:00
|
|
|
});
|
2014-12-24 00:14:28 +01:00
|
|
|
});
|
|
|
|
|
|
|
|
it("should reject promise on invalid sig when verifying", function(done) {
|
2015-01-12 20:17:29 +01:00
|
|
|
eccrypto.sign(privateKey, msg).then(function(sig) {
|
|
|
|
expect(Buffer.isBuffer(sig)).to.be.true;
|
|
|
|
sig[0] ^= 1;
|
|
|
|
eccrypto.verify(publicKey, msg, sig).catch(function() {
|
2014-12-24 00:14:28 +01:00
|
|
|
done();
|
|
|
|
});
|
2015-01-12 20:17:29 +01:00
|
|
|
});
|
|
|
|
});
|
2015-01-20 21:17:25 +01:00
|
|
|
|
|
|
|
it("should allow to sign and verify messages less than 32 bytes", function() {
|
|
|
|
return eccrypto.sign(privateKey, shortMsg).then(function(sig) {
|
|
|
|
expect(Buffer.isBuffer(sig)).to.be.true;
|
2015-01-21 00:20:28 +01:00
|
|
|
expect(sig.toString("hex")).to.equal("304402204737396b697e5a3400e3aedd203d8be89879f97708647252bd0c17752ff4c8f302201d52ef234de82ce0719679fa220334c83b80e21b8505a781d32d94a27d9310aa");
|
2015-01-20 21:17:25 +01:00
|
|
|
return eccrypto.verify(publicKey, shortMsg, sig);
|
|
|
|
});
|
|
|
|
});
|
2015-01-21 01:04:56 +01:00
|
|
|
|
|
|
|
it("shouldn't sign and verify messages longer than 32 bytes", function(done) {
|
|
|
|
var longMsg = Buffer(40);
|
|
|
|
var someSig = Buffer("304402204737396b697e5a3400e3aedd203d8be89879f97708647252bd0c17752ff4c8f302201d52ef234de82ce0719679fa220334c83b80e21b8505a781d32d94a27d9310aa", "hex");
|
|
|
|
eccrypto.sign(privateKey, longMsg).catch(function() {
|
|
|
|
eccrypto.verify(privateKey, longMsg, someSig).catch(function(e) {
|
|
|
|
expect(e.message).to.not.match(/bad signature/i);
|
|
|
|
done();
|
|
|
|
});
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
it("shouldn't sign and verify empty messages", function(done) {
|
|
|
|
var emptyMsg = Buffer(0);
|
|
|
|
var someSig = Buffer("304402204737396b697e5a3400e3aedd203d8be89879f97708647252bd0c17752ff4c8f302201d52ef234de82ce0719679fa220334c83b80e21b8505a781d32d94a27d9310aa", "hex");
|
|
|
|
eccrypto.sign(privateKey, emptyMsg).catch(function() {
|
|
|
|
eccrypto.verify(publicKey, emptyMsg, someSig).catch(function(e) {
|
|
|
|
expect(e.message).to.not.match(/bad signature/i);
|
|
|
|
done();
|
|
|
|
});
|
|
|
|
});
|
|
|
|
});
|
2015-01-12 20:17:29 +01:00
|
|
|
});
|
|
|
|
|
|
|
|
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);
|
2015-01-13 20:39:37 +01:00
|
|
|
expect(bufferEqual(Px, Px2)).to.be.true;
|
2015-01-12 20:17:29 +01:00
|
|
|
});
|
|
|
|
});
|
2014-12-21 19:05:05 +01:00
|
|
|
});
|
2015-01-13 14:21:11 +01:00
|
|
|
|
|
|
|
it("should reject promise on bad keys", function(done) {
|
|
|
|
eccrypto.derive(Buffer("test"), publicKeyB).catch(function() {
|
|
|
|
eccrypto.derive(publicKeyB, publicKeyB).catch(function() {
|
|
|
|
eccrypto.derive(privateKeyA, privateKeyA).catch(function() {
|
|
|
|
eccrypto.derive(privateKeyB, Buffer("test")).catch(function() {
|
|
|
|
done();
|
|
|
|
});
|
|
|
|
});
|
|
|
|
});
|
|
|
|
});
|
|
|
|
});
|
2014-12-21 19:05:05 +01:00
|
|
|
});
|
2015-01-13 14:21:11 +01:00
|
|
|
|
|
|
|
describe("ECIES", function() {
|
|
|
|
var ephemPrivateKey = Buffer(32);
|
|
|
|
ephemPrivateKey.fill(4);
|
|
|
|
var ephemPublicKey = eccrypto.getPublic(ephemPrivateKey);
|
|
|
|
var iv = Buffer(16);
|
|
|
|
iv.fill(5);
|
2015-01-14 00:29:39 +01:00
|
|
|
var ciphertext = Buffer("bbf3f0e7486b552b0e2ba9c4ca8c4579", "hex");
|
2015-01-13 14:21:11 +01:00
|
|
|
var mac = Buffer("dbb14a9b53dbd6b763dba24dc99520f570cdf8095a8571db4bf501b535fda1ed", "hex");
|
|
|
|
var encOpts = {ephemPrivateKey: ephemPrivateKey, iv: iv};
|
2015-01-14 00:29:39 +01:00
|
|
|
var decOpts = {iv: iv, ephemPublicKey: ephemPublicKey, ciphertext: ciphertext, mac: mac};
|
2015-01-13 14:21:11 +01:00
|
|
|
|
|
|
|
it("should encrypt", function() {
|
|
|
|
return eccrypto.encrypt(publicKeyB, Buffer("test"), encOpts)
|
2015-01-14 00:29:39 +01:00
|
|
|
.then(function(enc) {
|
|
|
|
expect(bufferEqual(enc.iv, iv)).to.be.true;
|
|
|
|
expect(bufferEqual(enc.ephemPublicKey, ephemPublicKey)).to.be.true;
|
|
|
|
expect(bufferEqual(enc.ciphertext, ciphertext)).to.be.true;
|
|
|
|
expect(bufferEqual(enc.mac, mac)).to.be.true;
|
2015-01-13 14:21:11 +01:00
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
it("should decrypt", function() {
|
|
|
|
return eccrypto.decrypt(privateKeyB, decOpts)
|
|
|
|
.then(function(msg) {
|
|
|
|
expect(msg.toString()).to.equal("test");
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
it("should encrypt and decrypt", function() {
|
2015-01-14 00:29:39 +01:00
|
|
|
return eccrypto.encrypt(publicKeyA, Buffer("to a")).then(function(enc) {
|
|
|
|
return eccrypto.decrypt(privateKeyA, enc);
|
2015-01-13 14:21:11 +01:00
|
|
|
}).then(function(msg) {
|
2015-01-14 00:29:39 +01:00
|
|
|
expect(msg.toString()).to.equal("to a");
|
2015-01-13 14:21:11 +01:00
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
it("should reject promise on bad private key when decrypting", function(done) {
|
2015-01-14 00:29:39 +01:00
|
|
|
eccrypto.encrypt(publicKeyA, Buffer("test")).then(function(enc) {
|
|
|
|
eccrypto.decrypt(privateKeyB, enc).catch(function() {
|
2015-01-13 14:21:11 +01:00
|
|
|
done();
|
|
|
|
});
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
it("should reject promise on bad IV when decrypting", function(done) {
|
2015-01-14 00:29:39 +01:00
|
|
|
eccrypto.encrypt(publicKeyA, Buffer("test")).then(function(enc) {
|
|
|
|
enc.iv[0] ^= 1;
|
|
|
|
eccrypto.decrypt(privateKeyA, enc).catch(function() {
|
2015-01-13 14:21:11 +01:00
|
|
|
done();
|
|
|
|
});
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
it("should reject promise on bad R when decrypting", function(done) {
|
2015-01-14 00:29:39 +01:00
|
|
|
eccrypto.encrypt(publicKeyA, Buffer("test")).then(function(enc) {
|
|
|
|
enc.ephemPublicKey[0] ^= 1;
|
|
|
|
eccrypto.decrypt(privateKeyA, enc).catch(function() {
|
2015-01-13 14:21:11 +01:00
|
|
|
done();
|
|
|
|
});
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
2015-01-14 00:29:39 +01:00
|
|
|
it("should reject promise on bad ciphertext when decrypting", function(done) {
|
|
|
|
eccrypto.encrypt(publicKeyA, Buffer("test")).then(function(enc) {
|
|
|
|
enc.ciphertext[0] ^= 1;
|
|
|
|
eccrypto.decrypt(privateKeyA, enc).catch(function() {
|
2015-01-13 14:21:11 +01:00
|
|
|
done();
|
|
|
|
});
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
it("should reject promise on bad MAC when decrypting", function(done) {
|
2015-01-14 00:29:39 +01:00
|
|
|
eccrypto.encrypt(publicKeyA, Buffer("test")).then(function(enc) {
|
|
|
|
var origMac = enc.mac;
|
|
|
|
enc.mac = mac.slice(1);
|
|
|
|
eccrypto.decrypt(privateKeyA, enc).catch(function() {
|
|
|
|
enc.mac = origMac;
|
|
|
|
enc.mac[10] ^= 1;
|
|
|
|
eccrypto.decrypt(privateKeyA, enc).catch(function() {
|
|
|
|
done();
|
|
|
|
});
|
2015-01-13 14:21:11 +01:00
|
|
|
});
|
|
|
|
});
|
|
|
|
});
|
|
|
|
});
|