Skip to content

Commit

Permalink
eliptical curves
Browse files Browse the repository at this point in the history
  • Loading branch information
Calvin Metcalf committed Nov 16, 2014
1 parent f975416 commit 17745d2
Show file tree
Hide file tree
Showing 11 changed files with 118 additions and 41 deletions.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
node_modules
npm-debug.log
10 changes: 10 additions & 0 deletions algos.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,3 +18,13 @@ exports['RSA-SHA512'] = exports.sha512WithRSAEncryption = {
hash: 'sha512',
id: new Buffer('3051300d060960864801650304020305000440', 'hex')
};
exports['RSA-SHA1'] = {
sign: 'rsa',
hash: 'sha1',
id: new Buffer('3021300906052b0e03021a05000414', 'hex')
}
exports['ecdsa-with-SHA1'] = {
sign: 'ecdsa',
hash: 'sha1',
id: new Buffer(/*'3021300906052b0e03021a05000414'*/'', 'hex')
}
53 changes: 22 additions & 31 deletions asn1.js
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,16 @@ exports.RSAPublicKey = RSAPublicKey;

var PublicKey = rfc3280.SubjectPublicKeyInfo;
exports.PublicKey = PublicKey;
var ECPublicKey = asn1.define('ECPublicKey', function() {
this.seq().obj(
this.key('algorithm').seq().obj(
this.key('id').objid(),
this.key('curve').objid()
),
this.key('subjectPrivateKey').bitstr()
);
});
exports.ECPublicKey = ECPublicKey;
var PrivateKeyInfo = asn1.define('PrivateKeyInfo', function() {
this.seq().obj(
this.key('version').int(),
Expand Down Expand Up @@ -59,39 +69,20 @@ var EncryptedPrivateKeyInfo = asn1.define('EncryptedPrivateKeyInfo', function()
);
});
exports.EncryptedPrivateKey = EncryptedPrivateKeyInfo;
var GeneralName = asn1.define('GeneralName', function() {
this.choice({
dNSName: this.implicit(2).ia5str()
});
});
exports.GeneralName = GeneralName;

var GeneralNames = asn1.define('GeneralNames', function() {
this.seqof(GeneralName);
});
exports.GeneralNames = GeneralNames;

var Signature = asn1.define('Signature', function() {

var ECPrivateKey = asn1.define('ECPrivateKey', function() {
this.seq().obj(
this.key('algorithm').seq().obj(
this.key('algorithm').objid(),
this.null_()
),
this.key('digest').octstr()
this.key('version').int(),
this.key('privateKey').octstr(),
this.key('parameters').optional().explicit(0).use(ECParameters),
this.key('publicKey').optional().explicit(1).bitstr()
);
});
exports.Signature = Signature;

var IA5Str = asn1.define('IA5Str', function() {
this.ia5str();
});
exports.IA5Str = IA5Str;

exports.SHA256 = [ 2, 16, 840, 1, 101, 3, 4, 2, 1 ];
exports.SHA256RSA = [ 1, 2, 840, 113549, 1, 1, 11 ];
exports.RSA = [ 1, 2, 840, 113549, 1, 1, 1 ];
exports.COMMONNAME = [ 2, 5, 4, 3 ];
exports.ALTNAME = [ 2, 5, 29, 17 ];

exports.TBSCertificate = rfc3280.TBSCertificate;
exports.Certificate = rfc3280.Certificate;
exports.ECPrivateKey = ECPrivateKey;
var ECParameters = asn1.define('ECParameters', function() {
this.choice({
namedCurve: this.objid()
});
});
6 changes: 6 additions & 0 deletions inject.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,9 @@ inherits(Sign, Writable);
function Sign(algorithm, crypto) {
Writable.call(this);
var data = algos[algorithm];
if (!data) {
throw new Error('Unknown message digest');
}
this._hash = crypto.createHash(data.hash);
this._tag = data.id;
this._crypto = crypto;
Expand Down Expand Up @@ -46,6 +49,9 @@ inherits(Verify, Writable);
function Verify(algorithm, crypto) {
Writable.call(this);
var data = algos[algorithm];
if (!data) {
throw new Error('Unknown message digest');
}
this._hash = crypto.createHash(data.hash);
this._tag = data.id;
};
Expand Down
7 changes: 4 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,12 @@
"author": "",
"license": "ISC",
"dependencies": {
"pemstrip": "0.0.1",
"asn1.js": "^0.6.4",
"asn1.js-rfc3280": "^0.5.1",
"inherits": "^2.0.1",
"bn.js": "^0.15.2",
"asn1.js": "^0.6.4",
"elliptic": "^0.15.14",
"inherits": "^2.0.1",
"pemstrip": "0.0.1",
"readable-stream": "^1.0.33"
},
"devDependencies": {
Expand Down
15 changes: 11 additions & 4 deletions parseKeys.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,14 +12,19 @@ function parseKeys(buffer, crypto) {
var stripped = pemstrip.strip(buffer);
var type = stripped.tag;
var data = new Buffer(stripped.base64, 'base64');
var subtype
var subtype,ndata;
switch (type) {
case 'PUBLIC KEY':
data = asn1.PublicKey.decode(data, 'der');
subtype = data.algorithm.algorithm.join('.');
ndata = asn1.PublicKey.decode(data, 'der');
subtype = ndata.algorithm.algorithm.join('.');
switch(subtype) {
case '1.2.840.113549.1.1.1':
return asn1.RSAPublicKey.decode(data.subjectPublicKey.data, 'der');
return asn1.RSAPublicKey.decode(ndata.subjectPublicKey.data, 'der');
case '1.2.840.10045.2.1':
return {
type: 'ec',
data: asn1.ECPublicKey.decode(data, 'der')
};
default: throw new Error('unknown key id ' + subtype);
}
throw new Error('unknown key type ' + type);
Expand All @@ -40,6 +45,8 @@ function parseKeys(buffer, crypto) {
return asn1.RSAPublicKey.decode(data, 'der');
case 'RSA PRIVATE KEY':
return asn1.RSAPrivateKey.decode(data, 'der');
case 'EC PRIVATE KEY':
return asn1.ECPrivateKey.decode(data, 'der');
default: throw new Error('unknown key type ' + type);
}
}
Expand Down
15 changes: 15 additions & 0 deletions sign.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,13 @@
// much of this based on https://github.com/indutny/self-signed/blob/gh-pages/lib/rsa.js
var parseKeys = require('./parseKeys');
var bn = require('bn.js');
var elliptic = require('elliptic');
module.exports = sign;
function sign(hash, key, crypto) {
var priv = parseKeys(key, crypto);
if (priv.parameters && priv.parameters.type === 'namedCurve') {
return ecSign(hash, priv, crypto);
}
var len = priv.modulus.byteLength();
var pad = [ 0, 1 ];
while (hash.length + pad.length + 1 < len) {
Expand Down Expand Up @@ -37,4 +41,15 @@ function crt(msg, priv) {
h.imul(q);
m2.iadd(h);
return new Buffer(m2.toArray());
}
function ecSign(hash, priv, crypto) {
elliptic.rand = crypto.randomBytes;
var curve;
if (priv.parameters.value.join('.') === '1.3.132.0.10') {
curve = new elliptic.ec('secp256k1');
}
var key = curve.genKeyPair();
key._importPrivate(priv.privateKey);
var out = key.sign(hash);
return new Buffer(out.toDER());
}
5 changes: 5 additions & 0 deletions test/ec.priv
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
-----BEGIN EC PRIVATE KEY-----
MHQCAQEEIDF6Xv8Sv//wGUWD+c780ppGrU0QdZWCAzxAQPQX8r/uoAcGBSuBBAAK
oUQDQgAEIZeowDylls4K/wfBjO18bYo7gGx8nYQRija4e/qEMikOHJai7geeUreU
r5Xky/Ax7s2dGtegsPNsPgGe5MpQvg==
-----END EC PRIVATE KEY-----
4 changes: 4 additions & 0 deletions test/ec.pub
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
-----BEGIN PUBLIC KEY-----
MFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEIZeowDylls4K/wfBjO18bYo7gGx8nYQR
ija4e/qEMikOHJai7geeUreUr5Xky/Ax7s2dGtegsPNsPgGe5MpQvg==
-----END PUBLIC KEY-----
26 changes: 26 additions & 0 deletions test/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,10 @@ var pass1024 = {
},
public: fs.readFileSync(__dirname + '/pass.1024.pub')
}
var ec = {
private: fs.readFileSync(__dirname + '/ec.priv'),
public: fs.readFileSync(__dirname + '/ec.pub')
}
function isNode10() {
return process.version && process.version.split('.').length === 3 && parseInt(process.version.split('.')[1], 10) <= 10;
}
Expand All @@ -42,7 +46,28 @@ function testIt(keys, message, scheme) {
t.ok(myVer.update(message).verify(pub, nodeSig), 'me validate node sig');
});
}
function ectestIt(keys, message, scheme) {
var pub = keys.public;
var priv = keys.private;
test(message.toString(), function (t) {
t.plan(3);

var nodeSign = nodeCrypto.createSign(scheme);
var mySign = myCrypto.createSign(scheme);
var mySig = mySign.update(message).sign(priv);
var nodeSig = nodeSign.update(message).sign(priv);
t.notEqual(mySig.toString('hex'), nodeSig.toString('hex'), 'not equal sigs');
var myVer = myCrypto.createVerify(scheme);
var nodeVer = nodeCrypto.createVerify(scheme);
t.ok(nodeVer.update(message).verify(pub, mySig), 'node validate my sig');
t.ok(myVer.update(message).verify(pub, nodeSig), 'me validate node sig');
});
}
ectestIt(ec, new Buffer('ecdsa with 1024 keys'), 'ecdsa-with-SHA1');

testIt(rsa1024, new Buffer('sha1 with 1024 keys'), 'RSA-SHA1');
testIt(rsa2028, new Buffer('sha1 with 2028 keys'), 'RSA-SHA1');
testIt(nonrsa1024, new Buffer('sha1 with 1024 keys non-rsa key'), 'RSA-SHA1');
testIt(rsa1024, new Buffer('sha224 with 1024 keys'), 'RSA-SHA224');
testIt(nonrsa1024, new Buffer('sha224 with 1024 keys non-rsa key'), 'RSA-SHA224');
testIt(rsa2028, new Buffer('sha224 with 2028 keys'), 'RSA-SHA224');
Expand All @@ -56,6 +81,7 @@ testIt(rsa1024, new Buffer('SHA512 with 1024 keys'), 'RSA-SHA512');
testIt(nonrsa1024, new Buffer('sha512 with 1024 keys non-rsa key'), 'RSA-SHA512');
testIt(rsa2028, new Buffer('SHA512 with 2028 keys'), 'RSA-SHA512');
if (!isNode10()) {
testIt(pass1024, new Buffer('sha1 with 1024 keys and password'), 'RSA-SHA1');
testIt(pass1024, new Buffer('sha224 with 1024 keys and password'), 'RSA-SHA224');
testIt(pass1024, new Buffer('sha256 with 1024 keys and password'), 'RSA-SHA256');
testIt(pass1024, new Buffer('sha384 with 1024 keys and password'), 'RSA-SHA384');
Expand Down
16 changes: 13 additions & 3 deletions verify.js
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
// much of this based on https://github.com/indutny/self-signed/blob/gh-pages/lib/rsa.js
var parseKeys = require('./parseKeys');

var elliptic = require('elliptic');
var bn = require('bn.js');
module.exports = verify;
function verify(sig, hash, key) {
var pub = parseKeys(key);

if (pub.type === 'ec') {
return ecVerify(sig, hash, pub);
}
var red = bn.mont(pub.modulus);
sig = new bn(sig).toRed(red);

Expand All @@ -20,4 +22,12 @@ function verify(sig, hash, key) {
out += (sig[i] ^ hash[i]);
}
return !out;
}
}
function ecVerify(sig, hash, pub) {
var curve;
if (pub.data.algorithm.curve.join('.') === '1.3.132.0.10') {
curve = new elliptic.ec('secp256k1');
}
var pubkey = pub.data.subjectPrivateKey.data;
return curve.verify(hash.toString('hex'), sig.toString('hex'), pubkey.toString('hex'));
}

0 comments on commit 17745d2

Please sign in to comment.