From e6d56e276ac60f730dd652edc8fa98f7c7eb6ff4 Mon Sep 17 00:00:00 2001 From: Mitar Date: Mon, 1 Feb 2016 23:42:00 -0800 Subject: [PATCH 1/6] Added node.js ECC package. --- package.json | 1 + 1 file changed, 1 insertion(+) diff --git a/package.json b/package.json index 76b9c45..39daddb 100644 --- a/package.json +++ b/package.json @@ -22,6 +22,7 @@ "license": "MIT", "dependencies": { "ecc-jsbn": "0.0.1", + "ecc-qj": "git+https://github.com/rynomad/ecc.git", "node-forge": "^0.6.20", "polyfill-promise": "^4.0.1", "sjcl": "^1.0.3" From 42c8a31f8fedc3b36286c1e3daad68db1b30922d Mon Sep 17 00:00:00 2001 From: Mitar Date: Mon, 1 Feb 2016 23:43:18 -0800 Subject: [PATCH 2/6] Initial ECDSA support. --- src/node/algorithms/ECDSA.js | 32 +++++++++++++++++++++++++++++++ src/node/algorithms/index.js | 1 + src/node/algorithms/shared/ECC.js | 21 +++++++++++++++++++- 3 files changed, 53 insertions(+), 1 deletion(-) create mode 100644 src/node/algorithms/ECDSA.js diff --git a/src/node/algorithms/ECDSA.js b/src/node/algorithms/ECDSA.js new file mode 100644 index 0000000..1678294 --- /dev/null +++ b/src/node/algorithms/ECDSA.js @@ -0,0 +1,32 @@ +var Algorithm = require("./abstract")("ECDSA") + , ECC = require("./shared/ECC") + , forge = require("node-forge") + , types = Algorithm.types + , public = types.public.usage + , private = types.private.usage; + +ECC(Algorithm); + +Algorithm.checkParams = checkParams; + +public.verify = createVerify; +private.sign = createSign; + +module.exports = Algorithm; + +function checkParams(format, algorithm, usages) { +} + +function createSign(key, alg1) { + return function ECDSA_SIGN(alg, buf) { + + }; +} + +function createVerify(key, alg1){ + return function ECDSA_VERIFY(alg, buf, sig) { + + } +} + +module.exports = Algorithm; diff --git a/src/node/algorithms/index.js b/src/node/algorithms/index.js index 677529d..03cdcee 100644 --- a/src/node/algorithms/index.js +++ b/src/node/algorithms/index.js @@ -5,3 +5,4 @@ exports["RSASSA-PKCS1-v1_5"] = require("./RSASSA-PKCS1-v1_5"); exports["HMAC"] = require("./HMAC") exports["AES-GCM"] = require("./AES-GCM") exports["ECDH"] = require("./ECDH") +exports["ECDSA"] = require("./ECDSA") diff --git a/src/node/algorithms/shared/ECC.js b/src/node/algorithms/shared/ECC.js index 60dbd5a..4d5e521 100644 --- a/src/node/algorithms/shared/ECC.js +++ b/src/node/algorithms/shared/ECC.js @@ -1,5 +1,7 @@ var ecc = require("./ecc.node.js") , spkiECCPad = new Buffer("3056301006042b81047006082a8648ce3d030107034200","hex"); + , pkcsPad1 = new Buffer("308187020100301306072A8648CE3D020106082A8648CE3D030107046D306B0201010420", "hex") + , pkcsPad2 = new Buffer("A144034200", "hex"); function getCurveKey(namedCurve){ return ("sec" + namedCurve.replace(/-/g, '').toLowerCase() + "r1"); @@ -29,6 +31,19 @@ function raw_import(publicBytes, alg){ return new ecc.ECKey(curve, publicBytes, true); } +function pkcs8_import(privateBytes, algorithm) { + var curvekey = getCurveKey(algorithm.namedCurve) + , curve = ecc.ECCurves[curvekey]; + + curve.legacy = true; + + return new ecc.ECKey(curve, privateBytes.slice(pkcsPad1.length, pkcsPad1.length + 32), false); +} + +function pkcs8_export(Key) { + return Buffer.concat([pkcsPad1, Key.PrivateKey, pkcsPad2, raw_export(Key)]); +} + function generate(alg){ var curvekey = getCurveKey(alg.namedCurve) , curve = ecc.ECCurves[curvekey]; @@ -41,7 +56,8 @@ function generate(alg){ function ECC(Algorithm){ var formats = Algorithm.formats , raw = formats.raw - , spki = formats.spki; + , spki = formats.spki + , pkcs8 = formats.pkcs8; // attach common generator Algorithm.generate = generate; @@ -53,6 +69,9 @@ function ECC(Algorithm){ spki.import = spki_import; spki.export = spki_export; + pkcs8.import = pkcs8_import; + pkcs8.export = pkcs8_export; + return; } From fe790e7136702d1fc9301cc716dd5073c94c9404 Mon Sep 17 00:00:00 2001 From: Mitar Date: Tue, 2 Feb 2016 01:05:42 -0800 Subject: [PATCH 3/6] Implement ECDSA signing and verification. --- src/node/algorithms/ECDSA.js | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/src/node/algorithms/ECDSA.js b/src/node/algorithms/ECDSA.js index 1678294..9c4d9b7 100644 --- a/src/node/algorithms/ECDSA.js +++ b/src/node/algorithms/ECDSA.js @@ -19,13 +19,21 @@ function checkParams(format, algorithm, usages) { function createSign(key, alg1) { return function ECDSA_SIGN(alg, buf) { - + var forgehashKey = alg.hash.name.replace(/-/g, '').toLowerCase(); + var md = forge.md[forgehashKey].create(); + md.update(buf.toString("binary")); + var digest = md.digest().toHex(); + return key.sign(new Buffer(digest, 'hex')); }; } function createVerify(key, alg1){ return function ECDSA_VERIFY(alg, buf, sig) { - + var forgehashKey = alg.hash.name.replace(/-/g, '').toLowerCase(); + var md = forge.md[forgehashKey].create(); + md.update(buf.toString("binary")); + var digest = md.digest().getBytes(); + return key.verifySignature(new Buffer(digest, 'binary'), sig); } } From 1aade2bbcc5bf5eb8329ad224100d1da1e025e34 Mon Sep 17 00:00:00 2001 From: Mitar Date: Tue, 2 Feb 2016 21:00:31 -0800 Subject: [PATCH 4/6] Typo. --- src/node/algorithms/shared/ECC.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/node/algorithms/shared/ECC.js b/src/node/algorithms/shared/ECC.js index 4d5e521..ea69345 100644 --- a/src/node/algorithms/shared/ECC.js +++ b/src/node/algorithms/shared/ECC.js @@ -1,7 +1,7 @@ var ecc = require("./ecc.node.js") - , spkiECCPad = new Buffer("3056301006042b81047006082a8648ce3d030107034200","hex"); - , pkcsPad1 = new Buffer("308187020100301306072A8648CE3D020106082A8648CE3D030107046D306B0201010420", "hex") - , pkcsPad2 = new Buffer("A144034200", "hex"); + , spkiECCPad = new Buffer("3056301006042b81047006082a8648ce3d030107034200","hex") + , pkcsPad1 = new Buffer("308187020100301306072A8648CE3D020106082A8648CE3D030107046D306B0201010420", "hex") + , pkcsPad2 = new Buffer("A144034200", "hex"); function getCurveKey(namedCurve){ return ("sec" + namedCurve.replace(/-/g, '').toLowerCase() + "r1"); From 41a5966d8ce85d19f1b8d97620eb29e76a9a3342 Mon Sep 17 00:00:00 2001 From: Mitar Date: Tue, 2 Feb 2016 21:01:00 -0800 Subject: [PATCH 5/6] Correctly export and import signatures. --- src/node/algorithms/ECDSA.js | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/src/node/algorithms/ECDSA.js b/src/node/algorithms/ECDSA.js index 9c4d9b7..307d930 100644 --- a/src/node/algorithms/ECDSA.js +++ b/src/node/algorithms/ECDSA.js @@ -23,7 +23,14 @@ function createSign(key, alg1) { var md = forge.md[forgehashKey].create(); md.update(buf.toString("binary")); var digest = md.digest().toHex(); - return key.sign(new Buffer(digest, 'hex')); + var signature = key.sign(new Buffer(digest, 'hex')); + // Signature is DER encoded, remove it. + var decodedSignature = forge.asn1.fromDer(signature.toString("binary")); + // We take only the last 32 bytes because values could be padded with 0 at the beginning. + return Buffer.concat([ + new Buffer(decodedSignature.value[0].value, 'binary').slice(-32), + new Buffer(decodedSignature.value[1].value, 'binary').slice(-32) + ]); }; } @@ -33,7 +40,14 @@ function createVerify(key, alg1){ var md = forge.md[forgehashKey].create(); md.update(buf.toString("binary")); var digest = md.digest().getBytes(); - return key.verifySignature(new Buffer(digest, 'binary'), sig); + var sigPart1 = sig.slice(0, 32); + var sigPart2 = sig.slice(32, 64); + var asn1 = forge.asn1; + var derSignature = asn1.toDer(asn1.create(asn1.Class.UNIVERSAL, asn1.Type.SEQUENCE, true, [ + asn1.create(asn1.Class.UNIVERSAL, asn1.Type.INTEGER, false, sigPart1.toString("binary")), + asn1.create(asn1.Class.UNIVERSAL, asn1.Type.INTEGER, false, sigPart2.toString("binary")) + ])).getBytes(); + return key.verifySignature(new Buffer(digest, 'binary'), new Buffer(derSignature, 'binary')); } } From d3ecb335afcbbffc920e866b9ac509636115feb5 Mon Sep 17 00:00:00 2001 From: Mitar Date: Mon, 9 May 2016 01:00:31 -0700 Subject: [PATCH 6/6] Pad correctly. --- src/node/algorithms/ECDSA.js | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/src/node/algorithms/ECDSA.js b/src/node/algorithms/ECDSA.js index 307d930..f65a412 100644 --- a/src/node/algorithms/ECDSA.js +++ b/src/node/algorithms/ECDSA.js @@ -34,18 +34,30 @@ function createSign(key, alg1) { }; } +function pad(buffer) { + if (buffer[0] & 0x80) { + // If the value starts with 1, we prepend a 0 to assure it is interpreted as a positive number. + return Buffer.concat([new Buffer([0]), buffer]) + } + else { + return buffer; + } +} + function createVerify(key, alg1){ return function ECDSA_VERIFY(alg, buf, sig) { var forgehashKey = alg.hash.name.replace(/-/g, '').toLowerCase(); var md = forge.md[forgehashKey].create(); md.update(buf.toString("binary")); var digest = md.digest().getBytes(); - var sigPart1 = sig.slice(0, 32); - var sigPart2 = sig.slice(32, 64); + var sigPart1 = pad(sig.slice(0, 32)); + var sigPart2 = pad(sig.slice(32, 64)); var asn1 = forge.asn1; + var integer1 = sigPart1.toString("binary"); + var integer2 = sigPart2.toString("binary"); var derSignature = asn1.toDer(asn1.create(asn1.Class.UNIVERSAL, asn1.Type.SEQUENCE, true, [ - asn1.create(asn1.Class.UNIVERSAL, asn1.Type.INTEGER, false, sigPart1.toString("binary")), - asn1.create(asn1.Class.UNIVERSAL, asn1.Type.INTEGER, false, sigPart2.toString("binary")) + asn1.create(asn1.Class.UNIVERSAL, asn1.Type.INTEGER, false, integer1), + asn1.create(asn1.Class.UNIVERSAL, asn1.Type.INTEGER, false, integer2) ])).getBytes(); return key.verifySignature(new Buffer(digest, 'binary'), new Buffer(derSignature, 'binary')); }