diff --git a/lib/aliases.js b/lib/aliases.js new file mode 100644 index 0000000..3b21ad7 --- /dev/null +++ b/lib/aliases.js @@ -0,0 +1,8 @@ +module.exports = { + p192: 'prime192v1', + p224: 'secp224r1', + p256: 'prime256v1', + p384: 'secp384r1', + p521: 'secp521r1' +} + diff --git a/lib/curves.js b/lib/curves.js new file mode 100644 index 0000000..5ccb872 --- /dev/null +++ b/lib/curves.js @@ -0,0 +1,45 @@ + +var EC = require('elliptic').ec +var aliases = require('./aliases') +var parameters = { + secp256k1: [1, 3, 132, 0, 10], + p192: [1, 2, 840, 10045, 3, 1, 1], + p224: [1, 3, 132, 0, 33], + p256: [1, 2, 840, 10045, 3, 1, 7], + p384: [1, 3, 132, 0, 34], + p521: [1, 3, 132, 0, 35] +} + +function toCurves (parameters) { + var curves = {} + Object.keys(parameters).forEach(function (curve) { + var cParams + // be lazy + Object.defineProperty(curves, curve, { + get: function () { + if (!cParams) { + cParams = { + curveParameters: parameters[curve], + privatePEMOptions: {label: 'EC PRIVATE KEY'}, + publicPEMOptions: {label: 'PUBLIC KEY'}, + curve: new EC(curve) + } + } + + return cParams + } + }) + + if (aliases[curve]) { + Object.defineProperty(curves, aliases[curve], { + get: function () { + return curves[curve] + } + }) + } + }) + + return curves +} + +module.exports = toCurves(parameters) diff --git a/lib/key-encoder.js b/lib/key-encoder.js index 286e522..2b4aa38 100644 --- a/lib/key-encoder.js +++ b/lib/key-encoder.js @@ -2,7 +2,8 @@ var asn1 = require('asn1.js'), BN = require('bn.js'), - EC = require('elliptic').ec + curves = require('./curves'), + aliases = require('./aliases') var ECPrivateKeyASN = asn1.define('ECPrivateKey', function() { this.seq().obj( @@ -23,15 +24,6 @@ var SubjectPublicKeyInfoASN = asn1.define('SubjectPublicKeyInfo', function() { ) }) -var curves = { - secp256k1: { - curveParameters: [1, 3, 132, 0, 10], - privatePEMOptions: {label: 'EC PRIVATE KEY'}, - publicPEMOptions: {label: 'PUBLIC KEY'}, - curve: new EC('secp256k1') - } -} - function assert(val, msg) { if (!val) { throw new Error(msg || 'Assertion failed') @@ -47,6 +39,8 @@ function KeyEncoder(options) { this.algorithmID = [1, 2, 840, 10045, 2, 1] } +KeyEncoder.aliases = aliases +KeyEncoder.curves = curves KeyEncoder.ECPrivateKeyASN = ECPrivateKeyASN KeyEncoder.SubjectPublicKeyInfoASN = SubjectPublicKeyInfoASN @@ -160,4 +154,4 @@ KeyEncoder.prototype.encodePublic = function(publicKey, originalFormat, destinat } } -module.exports = KeyEncoder \ No newline at end of file +module.exports = KeyEncoder diff --git a/test.js b/test.js index 492df4c..3d32c2c 100644 --- a/test.js +++ b/test.js @@ -2,7 +2,8 @@ var test = require('tape'), KeyEncoder = require('./index'), ECPrivateKeyASN = KeyEncoder.ECPrivateKeyASN, SubjectPublicKeyInfoASN = KeyEncoder.SubjectPublicKeyInfoASN, - BN = require('bn.js') + BN = require('bn.js'), + crypto = require('crypto') var keys = { rawPrivate: '844055cca13efd78ce79a4c3a4c5aba5db0ebeb7ae9d56906c03d333c5668d5b', @@ -128,3 +129,63 @@ test('encodePEMPublicKey', function(t) { var publicKeyDER = keyEncoder.encodePublic(keys.pemPublic, 'pem', 'der') t.equal(publicKeyDER, keys.derPublic, 'encoded DER public key should match the OpenSSL reference') }) + +var aliases = KeyEncoder.aliases +var curves = KeyEncoder.curves + +test('elliptic sign => native verify compact', function (t) { + var testData = 'some data', + hashingAlgorithm = 'sha256', + testDataHash = crypto.createHash(hashingAlgorithm).update(testData).digest() + + for (var curveName in aliases) { + var curve = curves[curveName].curve, + keyEncoder = new KeyEncoder(curveName) + t.ok(keyEncoder, 'curve ' + curveName + ': created a key encoder') + + var keypair = curve.genKeyPair(), + publixKeyHex = keypair.getPublic('hex'), + publicKeyPEM = keyEncoder.encodePublic(publixKeyHex, 'raw', 'pem') + + var signatureOfTestData = keypair.sign(testDataHash).toDER('hex') + t.ok(signatureOfTestData, 'curve ' + curveName + ': signed test data') + + var verified = crypto + .createVerify(hashingAlgorithm) + .update(testData) + .verify(publicKeyPEM, signatureOfTestData, 'hex') + t.ok(verified, 'curve ' + curveName + ': verified signature') + } + + t.end() +}) + +test('native sign => elliptic verify compact', function (t) { + var testData = 'some data', + hashingAlgorithm = 'sha256', + testDataHash = crypto.createHash(hashingAlgorithm).update(testData).digest() + + for (var curveName in aliases) { + var curve = curves[curveName].curve, + keyEncoder = new KeyEncoder(curveName) + t.ok(keyEncoder, 'curve ' + curveName + ': created a key encoder') + + var ecdh = crypto.createECDH(aliases[curveName]) + ecdh.generateKeys() + var privateKey = ecdh.getPrivateKey(), + privateKeyPEM = keyEncoder.encodePrivate(privateKey, 'raw', 'pem') + + var signatureOfTestData = crypto + .createSign(hashingAlgorithm) + .update(testData) + .sign(privateKeyPEM, 'hex') + t.ok(signatureOfTestData, 'curve ' + curveName + ': signed test data') + + var verified = curve + .keyFromPrivate(privateKey) + .verify(testDataHash, signatureOfTestData) + t.ok(verified, 'curve ' + curveName + ': verified signature') + } + + t.end() +})