From e729e349405b913f01d355b1d16ae722e14b26f2 Mon Sep 17 00:00:00 2001 From: w Date: Tue, 26 Jan 2016 18:41:02 -0800 Subject: [PATCH 01/13] It's a sad day when we're using JS for portability. --- install.js | 11 +++++++++++ install.sh | 17 ----------------- package.json | 2 +- 3 files changed, 12 insertions(+), 18 deletions(-) create mode 100644 install.js delete mode 100755 install.sh diff --git a/install.js b/install.js new file mode 100644 index 0000000..f715501 --- /dev/null +++ b/install.js @@ -0,0 +1,11 @@ +var child_process = require('child_process'); +child_process.exec('npm -v', function (error, stdout, stderr) { + var version = stdout.toString(); + var pure_js = version[0] === '2'; + console.log(pure_js); + if (pure_js) { + console.log('PURE JS'); + } else { + child_process.exec('npm install git+https://github.com/rynomad/ecc.git'); + } +}); diff --git a/install.sh b/install.sh deleted file mode 100755 index 01f548a..0000000 --- a/install.sh +++ /dev/null @@ -1,17 +0,0 @@ -#!/bin/bash - -export VERSION=`npm -v` - -if [ "${VERSION:0:1}" == "2" ] -then - export PURE_JS=true -fi - -echo $PURE_JS - -if [ "$PURE_JS" == "true" ] -then - echo "PURE JS" -else - npm install git+https://github.com/rynomad/ecc.git -fi diff --git a/package.json b/package.json index 76b9c45..9341225 100644 --- a/package.json +++ b/package.json @@ -4,7 +4,7 @@ "description": "crypto.subtle for node.js", "main": "src/main.js", "scripts": { - "install": "./install.sh", + "install": "node install.js", "test": "echo \"Error: no test specified\" && exit 1" }, "keywords": [ From 5b7e63e74923547572b52f01cd7f271e4ff74d30 Mon Sep 17 00:00:00 2001 From: Mitar Date: Wed, 27 Jan 2016 23:30:32 -0800 Subject: [PATCH 02/13] Fixing spki header. --- src/node/algorithms/shared/ECC.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/node/algorithms/shared/ECC.js b/src/node/algorithms/shared/ECC.js index 60dbd5a..69f047e 100644 --- a/src/node/algorithms/shared/ECC.js +++ b/src/node/algorithms/shared/ECC.js @@ -1,5 +1,5 @@ var ecc = require("./ecc.node.js") - , spkiECCPad = new Buffer("3056301006042b81047006082a8648ce3d030107034200","hex"); + , spkiECCPad = new Buffer("3059301306072a8648ce3d020106082a8648ce3d030107034200","hex"); function getCurveKey(namedCurve){ return ("sec" + namedCurve.replace(/-/g, '').toLowerCase() + "r1"); @@ -16,7 +16,6 @@ function spki_export(Key){ } function raw_export(Key){ - console.log("raw ecc export") return new Buffer(Key.PublicKey); } From aeb63b996d54a01b949a568fe2f848cadfdb0aeb Mon Sep 17 00:00:00 2001 From: Mitar Date: Thu, 28 Jan 2016 09:52:32 -0800 Subject: [PATCH 03/13] Correctly convert arguments. --- src/bufferize.js | 10 ++++++++++ src/main.js | 9 +-------- src/node/algorithms/AES-GCM.js | 10 ++++++++-- 3 files changed, 19 insertions(+), 10 deletions(-) create mode 100644 src/bufferize.js diff --git a/src/bufferize.js b/src/bufferize.js new file mode 100644 index 0000000..a263d37 --- /dev/null +++ b/src/bufferize.js @@ -0,0 +1,10 @@ +function Bufferize (result){ + if (result instanceof ArrayBuffer) + result = new Uint8Array(result); + if (result instanceof Uint8Array) + result = new Buffer(result); + + return result; +} + +module.exports = Bufferize; diff --git a/src/main.js b/src/main.js index 0e6c4e7..b40d583 100644 --- a/src/main.js +++ b/src/main.js @@ -1,6 +1,7 @@ var Browser = require("./use_node.js") var OPS = ["generateKey", "importKey", "exportKey", "sign", "verify", "encrypt", "decrypt", "digest", "deriveKey", "deriveBits"] var nonce = require("crypto").randomBytes(64).toString("hex") +var Bufferize = require('./bufferize') global.FORGE = require("./forgeless.js") global.Promise = require("polyfill-promise") var Subtle = {} @@ -25,14 +26,6 @@ function makeArgArray (args){ return ar; } -function Bufferize (result){ - if (result instanceof ArrayBuffer) - result = new Uint8Array(result); - if (result instanceof Uint8Array) - result = new Buffer(result); - - return result; -} function makeRoutine(routine){ return function(){ var routineArgs = makeArgArray(arguments) diff --git a/src/node/algorithms/AES-GCM.js b/src/node/algorithms/AES-GCM.js index 7b84eea..d29b729 100644 --- a/src/node/algorithms/AES-GCM.js +++ b/src/node/algorithms/AES-GCM.js @@ -1,5 +1,6 @@ var sjcl = require("sjcl") , Algorithm = require("./abstract")("AES-GCM") + , Bufferize = require('./../../bufferize') , AES = require("./shared/AES") , secret = Algorithm.types.secret.usage @@ -11,8 +12,13 @@ secret.decrypt = createDecrypt; module.exports = Algorithm; function getParams(alg, data){ - return { iv : sjcl.codec.hex.toBits(alg.iv.toString('hex')) - , add : sjcl.codec.hex.toBits(alg.additionalData.toString('hex')) + var iv = Bufferize(alg.iv); + var additionalData = alg.additionalData ? Bufferize(alg.additionalData) : new Buffer([]); + + data = data ? Bufferize(data) : new Buffer([]); + + return { iv : sjcl.codec.hex.toBits(iv.toString('hex')) + , add : sjcl.codec.hex.toBits(additionalData.toString('hex')) , data : sjcl.codec.hex.toBits(data.toString('hex')) }; } From 513d318d820b62f76b89b06321283b3f65e73f90 Mon Sep 17 00:00:00 2001 From: Mitar Date: Fri, 29 Jan 2016 00:50:00 -0800 Subject: [PATCH 04/13] Fixed RSA key size setting. --- src/node/algorithms/shared/RSA.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/node/algorithms/shared/RSA.js b/src/node/algorithms/shared/RSA.js index bd444f4..0be7771 100644 --- a/src/node/algorithms/shared/RSA.js +++ b/src/node/algorithms/shared/RSA.js @@ -35,7 +35,7 @@ function generate(algorithm){ pos++; } - return forge.rsa.generateKeyPair({bits: algorithm.modulousLength , e: exp}); + return forge.rsa.generateKeyPair({bits: algorithm.modulusLength , e: exp}); } From e6d56e276ac60f730dd652edc8fa98f7c7eb6ff4 Mon Sep 17 00:00:00 2001 From: Mitar Date: Mon, 1 Feb 2016 23:42:00 -0800 Subject: [PATCH 05/13] 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 06/13] 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 b91730bfbf69278f55ed01b0c947d052aa2c03d5 Mon Sep 17 00:00:00 2001 From: Mitar Date: Tue, 2 Feb 2016 01:04:41 -0800 Subject: [PATCH 07/13] Bugfix. --- src/node/algorithms/shared/ECC.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/node/algorithms/shared/ECC.js b/src/node/algorithms/shared/ECC.js index 0c95054..e1c5cca 100644 --- a/src/node/algorithms/shared/ECC.js +++ b/src/node/algorithms/shared/ECC.js @@ -1,5 +1,5 @@ var ecc = require("./ecc.node.js") - , spkiECCPad = new Buffer("3059301306072a8648ce3d020106082a8648ce3d030107034200","hex"); + , spkiECCPad = new Buffer("3059301306072a8648ce3d020106082a8648ce3d030107034200","hex") , pkcsPad1 = new Buffer("308187020100301306072A8648CE3D020106082A8648CE3D030107046D306B0201010420", "hex") , pkcsPad2 = new Buffer("A144034200", "hex"); From fe790e7136702d1fc9301cc716dd5073c94c9404 Mon Sep 17 00:00:00 2001 From: Mitar Date: Tue, 2 Feb 2016 01:05:42 -0800 Subject: [PATCH 08/13] 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 db71238ea6e0d2e8360aa1f4c6b62f5a606148b3 Mon Sep 17 00:00:00 2001 From: w Date: Tue, 2 Feb 2016 17:09:04 -0800 Subject: [PATCH 09/13] Use ecc that compiles on Windows. --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 591e9d1..6124e2a 100644 --- a/package.json +++ b/package.json @@ -22,7 +22,7 @@ "license": "MIT", "dependencies": { "ecc-jsbn": "0.0.1", - "ecc-qj": "git+https://github.com/rynomad/ecc.git", + "ecc-qj": "git+https://github.com/mitar/ecc.git#4087e38646d2a375c3c2ce0a3d1881b3c35d9dab", "node-forge": "^0.6.20", "polyfill-promise": "^4.0.1", "sjcl": "^1.0.3" From 1aade2bbcc5bf5eb8329ad224100d1da1e025e34 Mon Sep 17 00:00:00 2001 From: Mitar Date: Tue, 2 Feb 2016 21:00:31 -0800 Subject: [PATCH 10/13] 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 11/13] 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 ab49860a468e74f9f98859aa2ea6948a172f89cc Mon Sep 17 00:00:00 2001 From: Mitar Date: Wed, 3 Feb 2016 02:25:46 -0800 Subject: [PATCH 12/13] Bugfix. --- src/node/algorithms/shared/ECC.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/node/algorithms/shared/ECC.js b/src/node/algorithms/shared/ECC.js index 60db061..2f79ec0 100644 --- a/src/node/algorithms/shared/ECC.js +++ b/src/node/algorithms/shared/ECC.js @@ -1,5 +1,5 @@ var ecc = require("./ecc.node.js") - , spkiECCPad = new Buffer("3056301006042b81047006082a8648ce3d030107034200","hex") + , spkiECCPad = new Buffer("3059301306072a8648ce3d020106082a8648ce3d030107034200","hex") , pkcsPad1 = new Buffer("308187020100301306072A8648CE3D020106082A8648CE3D030107046D306B0201010420", "hex") , pkcsPad2 = new Buffer("A144034200", "hex"); From 3a6baf8de7e2e6475db8daa71ed8404ee842c306 Mon Sep 17 00:00:00 2001 From: Mitar Date: Sun, 7 Feb 2016 03:19:59 -0800 Subject: [PATCH 13/13] Added AES key generation. --- src/node/algorithms/shared/AES.js | 14 +++++++++----- src/node/generateKey.js | 7 ++++++- 2 files changed, 15 insertions(+), 6 deletions(-) diff --git a/src/node/algorithms/shared/AES.js b/src/node/algorithms/shared/AES.js index d1f58f3..c962aef 100644 --- a/src/node/algorithms/shared/AES.js +++ b/src/node/algorithms/shared/AES.js @@ -1,20 +1,24 @@ -var sjcl = require("sjcl"); +var sjcl = require("sjcl"), + crypto = require("crypto"); -function AES_generateKey(noop){ - return; +function AES_generateKey(algorithm){ + return raw_import(crypto.randomBytes(algorithm.length / 8)); } function raw_import(buf){ - return new sjcl.cipher.aes(sjcl.codec.hex.toBits(buf.toString("hex"))); + var key = new sjcl.cipher.aes(sjcl.codec.hex.toBits(buf.toString("hex"))); + key._raw = buf; + return key; } function raw_export(key){ - return key; + return key._raw; } function AES(Algorithm){ Algorithm.formats.raw.import = raw_import; Algorithm.formats.raw.export = raw_export; + Algorithm.generate = AES_generateKey; return; } diff --git a/src/node/generateKey.js b/src/node/generateKey.js index 838ae27..dc5d545 100644 --- a/src/node/generateKey.js +++ b/src/node/generateKey.js @@ -58,7 +58,12 @@ function generateKey(algorithm, exportable, usages, nonce){ //construct the return object from the scaffold Object.keys(_scaf).forEach(function(type){ - _res[_alg.types[type].returnLabel] = new CryptoKey(_key, type, _scaf[type]._exp, _scaf[type]._uses, nonce); + if (_alg.types[type].returnLabel) { + _res[_alg.types[type].returnLabel] = new CryptoKey(_key, type, _scaf[type]._exp, _scaf[type]._uses, nonce); + } + else { + _res = new CryptoKey(_key, type, _scaf[type]._exp, _scaf[type]._uses, nonce); + } }) //special case... ECDH public keys don't have they're own usage, but are still needed as params in deriveKey/Bits