From 1ae18d227f914d4bb064fe02fccc583d3c262f93 Mon Sep 17 00:00:00 2001 From: Braydon Fuller Date: Tue, 28 Oct 2014 16:19:02 -0400 Subject: [PATCH 1/8] replace bitcore with elliptic, hashjs and bs58 to produce a smaller browser build --- lib/bitauth.js | 197 ++++++++++++++++++++++++++++++++----------- package.json | 8 +- scripts/make-dist.sh | 11 +-- test/test.bitauth.js | 44 ++++++++-- 4 files changed, 191 insertions(+), 69 deletions(-) diff --git a/lib/bitauth.js b/lib/bitauth.js index 3a6a886..fb06aa2 100644 --- a/lib/bitauth.js +++ b/lib/bitauth.js @@ -1,76 +1,171 @@ -var bitcore = require('bitcore'); -var Key = bitcore.Key; -var SIN = bitcore.SIN; -var SINKey = bitcore.SINKey -var util = bitcore.util; +var elliptic = require('elliptic'); +var ecdsa = new elliptic.ec(elliptic.curves.secp256k1); +var hashjs = require('hash.js'); +var bs58 = require('bs58'); -var BitAuth = {}; +var BitAuth = {}; +/** + * Will return a key pair and identity + * + * @example + * var keys = BitAuth.generateSin(); + * + * @returns {Object} An object with keys: created, priv, pub and sin + */ BitAuth.generateSin = function() { - var sk = new SINKey(); - sk.generate(); - return sk.storeObj(); -}; -BitAuth.getPublicKeyFromPrivateKey = function(privkey) { - try { - var key = new Key(); + var keys = ecdsa.genKeyPair(); - key.private = new Buffer(privkey, 'hex'); - key.regenerateSync(); + var publicKey = this.getPublicKeyFromPrivateKey(keys.getPrivate('hex')); + var sin = this.getSinFromPublicKey(publicKey); - return key.public.toString('hex'); - } catch (err) { - console.log(err); - return null; + var sinObj = { + created: new Date().getTime(), + priv: keys.getPrivate('hex'), + pub: publicKey, + sin: sin } + + return sinObj; }; + +/** + * Will return an public key from a private key + * + * @param {String} A private key in hex + * @returns {String} A compressed public key in hex + */ +BitAuth.getPublicKeyFromPrivateKey = function(privkey) { + + var keys = ecdsa.keyPair(privkey, 'hex'); + + // compressed public key + var pubKey = keys.getPublic(); + var xbuf = new Buffer(pubKey.x.toString('hex'), 'hex'); + var ybuf = new Buffer(pubKey.y.toString('hex'), 'hex'); + if (ybuf[ybuf.length-1] % 2) { //odd + var pub = Buffer.concat([new Buffer([3]), xbuf]); + } + else { //even + var pub = Buffer.concat([new Buffer([2]), xbuf]); + } + + var hexPubKey = pub.toString('hex'); + + return hexPubKey; + +}; + +/** + * Will return a SIN from a compressed private key + * + * @param {String} A public key in hex + * @returns {String} A SIN identity + */ BitAuth.getSinFromPublicKey = function(pubkey) { - var pubkeyHash = util.sha256ripe160(new Buffer(pubkey, 'hex')); - var sin = new SIN(SIN.SIN_EPHEM, pubkeyHash); - return sin.toString(); + + // sha256 hash the pubkey + var pubHash = (new hashjs.sha256()).update(new Buffer(pubkey, 'hex')).digest('hex'); + + // get the ripemd160 hash of the pubkey + var pubRipe = (new hashjs.ripemd160()).update(new Buffer(pubHash, 'hex')).digest('hex'); + + // add the version + var pubPrefixed = '0f02'+pubRipe; + + // two rounds of hashing to generate the checksum + var hash1 = (new hashjs.sha256()).update(new Buffer(pubPrefixed, 'hex')).digest('hex'); + var checksumTotal = (new hashjs.sha256()).update(new Buffer(hash1, 'hex')).digest('hex'); + + // slice the hash to arrive at the checksum + var checksum = checksumTotal.slice(0,8); + + // add the checksum to the ripemd160 pubkey + var pubWithChecksum = pubPrefixed + checksum; + + // encode into base58 + var sin = bs58.encode(new Buffer(pubWithChecksum, 'hex')); + + return sin; + } +/** + * Will return a signature from a private key + * + * @param {String} data - A string of data to be signed + * @param {String} privKey - A private key in hex + * @returns {String} signature - A DER signature in hex + */ BitAuth.sign = function(data, privkey) { - var hash = util.sha256(data); + var hash = (new hashjs.sha256()).update(new Buffer(data, 'ascii')).digest('hex'); + var signature = ecdsa.sign(hash, privkey); + var hexsignature = signature.toDER('hex'); + return hexsignature; +}; - try { - var key = new Key(); - key.private = new Buffer(privkey, 'hex'); - return key.signSync(hash).toString('hex'); - } catch (err) { - console.log(err.stack); - console.log(err); - return null; +/** + * Will verify a signature + * + * @param {String} data - A string of data that has been signed + * @param {String} pubkey - The public identity that has signed the data + * @param {String} hexsignature - A DER signature in hex + * @returns {Function|Boolean} - If the signature is valid + */ +BitAuth.verifySignature = function(data, pubkey, hexsignature, callback) { + var hash = (new hashjs.sha256()).update(new Buffer(data, 'ascii')).digest('hex'); + var signature = new Buffer(hexsignature, 'hex'); + var valid = ecdsa.verify(hash, signature, pubkey); + if ( callback ){ + return callback(null, valid); + } else { + return valid; } }; -BitAuth.verifySignature = function(data, pubkey, signature, callback) { - var hash = util.sha256(data); - - try { - var key = new Key(); - key.public = new Buffer(pubkey, 'hex'); - key.verifySignature(hash, new Buffer(signature, 'hex'), callback); - } catch (err) { - callback(err, false); - } -}; +/** + * Will verify that a SIN is valid + * + * @param {String} sin - A SIN identity + * @returns {Function|Boolean} - If the SIN identity is valid + */ BitAuth.validateSin = function(sin, callback) { - var s = new SIN(sin); - try { - s.validate() - } catch(err) { - if ( callback ) - callback(err); + var decoded = bs58.decode(sin); + var pubWithChecksum = new Buffer(decoded, 'hex').toString('hex'); + + // check the version + if ( pubWithChecksum.slice(0, 4) != '0f02' ) { + if ( callback ) { + return callback(new Error('Invalid prefix or SIN version')); + } return false; } - if ( callback ) - callback(null); - return true; + + // get the checksum + var checksum = pubWithChecksum.slice(pubWithChecksum.length-8, pubWithChecksum.length); + var pubPrefixed = pubWithChecksum.slice(0, pubWithChecksum.length-8); + + // two rounds of hashing to generate the checksum + var hash1 = (new hashjs.sha256()).update(new Buffer(pubPrefixed, 'hex')).digest('hex'); + var checksumTotal = (new hashjs.sha256()).update(new Buffer(hash1, 'hex')).digest('hex'); + + // check the checksum + if ( checksumTotal.slice(0,8) == checksum ) { + if ( callback ) { + return callback(null); + } + return true + } else { + if ( callback ) { + return callback(new Error('Checksum does not match')); + } + return false; + } + }; module.exports = BitAuth; diff --git a/package.json b/package.json index c91e004..0ce9c22 100644 --- a/package.json +++ b/package.json @@ -1,4 +1,3 @@ - { "name": "bitauth", "description": "Passwordless authentication using Bitcoin cryptography", @@ -22,13 +21,14 @@ ], "scripts": { "make-dist": "sh scripts/make-dist.sh", - "test": "mocha test/*.js --reporter spec", - "postinstall": "npm run make-dist" + "test": "mocha test/*.js --reporter spec" }, "main": "index.js", "version": "0.1.1", "dependencies": { - "bitcore": "0.1.32", + "elliptic": "=0.15.11", + "hash.js": "=0.3.2", + "bs58": "=2.0.0", "request": "^2.36.0", "express": "^4.3.1", "base58-native": "^0.1.4", diff --git a/scripts/make-dist.sh b/scripts/make-dist.sh index 6b01c4b..200c97b 100644 --- a/scripts/make-dist.sh +++ b/scripts/make-dist.sh @@ -1,10 +1,5 @@ -cd node_modules/bitcore -echo "Building browser bundle for bitcore..." -node browser/build -s lib/Key,lib/SINKey,lib/SIN,util/util -cd ../../ -cp node_modules/bitcore/browser/bundle.js dist/bitcore.bundle.js echo "Building browser bundle for bitauth..." -node_modules/.bin/browserify lib/bitauth.js -s bitauth -x buffertools -x bitcore -o dist/bitauth.bundle.js -echo "Minifying bitcore and bitauth..." -node_modules/.bin/uglifyjs dist/bitcore.bundle.js dist/bitauth.bundle.js -o dist/bitauth.browser.min.js +node_modules/.bin/browserify lib/bitauth.js -s bitauth -o dist/bitauth.bundle.js +echo "Minifying bitauth..." +node_modules/.bin/uglifyjs dist/bitauth.bundle.js -o dist/bitauth.browser.min.js echo "Done!" diff --git a/test/test.bitauth.js b/test/test.bitauth.js index 67bd572..f008fbc 100644 --- a/test/test.bitauth.js +++ b/test/test.bitauth.js @@ -12,12 +12,28 @@ describe('bitauth', function() { var should = chai.should(); + // previously known keys for comparison + var keysKnown = { + priv: '97811b691dd7ebaeb67977d158e1da2c4d3eaa4ee4e2555150628acade6b344c', + pub: '02326209e52f6f17e987ec27c56a1321acf3d68088b8fb634f232f12ccbc9a4575', + sin: 'Tf3yr5tYvccKNVrE26BrPs6LWZRh8woHwjR' + } + + // keys generated var keys = null; - var sin = 'Tf1Jc1xSbqasm5QLwwSQc5umddx2h7mAMHX'; - var sinb = 'Tf1Jc1xSbqasm5QLwwSQc5umddx2h7mAMhX'; + + // invalid checksum + var sinbad = 'Tf1Jc1xSbqasm5QLwwSQc5umddx2h7mAMhX'; + + // valid sin + var singood = 'TfG4ScDgysrSpodWD4Re5UtXmcLbY5CiUHA'; + + // data to sign var contract = 'keyboard cat'; var secret = 'o hai, nsa. how i do teh cryptos?'; var password = 's4705hiru13z!'; + + // signature from generate keys var signature = null; var enc = null; @@ -41,6 +57,11 @@ describe('bitauth', function() { done(); }); + it('should properly get compressed public key from a previously known private key', function(done) { + bitauth.getPublicKeyFromPrivateKey(keysKnown.priv).should.equal(keysKnown.pub); + done(); + }); + }); describe('#getSinFromPublicKey', function() { @@ -50,6 +71,11 @@ describe('bitauth', function() { done(); }); + it('should properly get the sin from a previously known compressed public key', function(done) { + bitauth.getSinFromPublicKey(keysKnown.pub).should.equal(keysKnown.sin); + done(); + }); + }); describe('#sign', function() { @@ -65,7 +91,12 @@ describe('bitauth', function() { describe('#verifySignature', function() { it('should verify the signature', function(done) { - bitauth.verifySignature(contract, keys.pub, signature, done); + bitauth.verifySignature(contract, keys.pub, signature, function(err, valid){ + should.not.exist(err); + should.exist(valid); + valid.should.equal(true); + done(); + }); }); }); @@ -73,7 +104,7 @@ describe('bitauth', function() { describe('#validateSinTrue', function() { it('should validate the sin as true', function(done) { - var valid = bitauth.validateSin(sin); + var valid = bitauth.validateSin(singood); should.equal(true, valid); done(); }); @@ -83,7 +114,7 @@ describe('bitauth', function() { describe('#validateSinFalse', function() { it('should validate the sin as false', function(done) { - var valid = bitauth.validateSin(sinb); + var valid = bitauth.validateSin(sinbad); should.equal(false, valid); done(); }); @@ -93,8 +124,9 @@ describe('bitauth', function() { describe('#validateSinCallback', function() { it('should receive error callback', function(done) { - var valid = bitauth.validateSin(sinb, function(err){ + var valid = bitauth.validateSin(sinbad, function(err){ should.exist(err); + err.message.should.equal('Checksum does not match'); done(); }); }); From 74cecb7fdfc0ff2a9889186eff0923a9526ccf16 Mon Sep 17 00:00:00 2001 From: Braydon Fuller Date: Wed, 29 Oct 2014 19:09:53 -0400 Subject: [PATCH 2/8] add padding of leading zeros --- lib/bitauth.js | 22 ++++++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/lib/bitauth.js b/lib/bitauth.js index fb06aa2..83be89a 100644 --- a/lib/bitauth.js +++ b/lib/bitauth.js @@ -5,6 +5,18 @@ var bs58 = require('bs58'); var BitAuth = {}; +/** + * Will add leading zeros to hex string + * + * @returns {String} A hex string + */ +BitAuth._addPaddingToHex = function(hex){ + while( hex.length < 64 ){ + hex = '0'+hex; + } + return hex; +} + /** * Will return a key pair and identity * @@ -17,12 +29,13 @@ BitAuth.generateSin = function() { var keys = ecdsa.genKeyPair(); - var publicKey = this.getPublicKeyFromPrivateKey(keys.getPrivate('hex')); + var privateKey = this._addPaddingToHex(keys.getPrivate('hex')); + var publicKey = this.getPublicKeyFromPrivateKey(privateKey); var sin = this.getSinFromPublicKey(publicKey); var sinObj = { created: new Date().getTime(), - priv: keys.getPrivate('hex'), + priv: privateKey, pub: publicKey, sin: sin } @@ -43,8 +56,9 @@ BitAuth.getPublicKeyFromPrivateKey = function(privkey) { // compressed public key var pubKey = keys.getPublic(); - var xbuf = new Buffer(pubKey.x.toString('hex'), 'hex'); - var ybuf = new Buffer(pubKey.y.toString('hex'), 'hex'); + var xbuf = new Buffer(this._addPaddingToHex(pubKey.x.toString('hex')), 'hex'); + var ybuf = new Buffer(this._addPaddingToHex(pubKey.y.toString('hex')), 'hex'); + if (ybuf[ybuf.length-1] % 2) { //odd var pub = Buffer.concat([new Buffer([3]), xbuf]); } From a4309b8f3bbf5cce582a8cc8b645faa1260a2504 Mon Sep 17 00:00:00 2001 From: Braydon Fuller Date: Sun, 2 Nov 2014 16:14:23 -0500 Subject: [PATCH 3/8] updated to use the new version of elliptic that includes hex padding --- lib/bitauth.js | 22 +++++----------------- package.json | 6 +++--- 2 files changed, 8 insertions(+), 20 deletions(-) diff --git a/lib/bitauth.js b/lib/bitauth.js index 83be89a..082a4dc 100644 --- a/lib/bitauth.js +++ b/lib/bitauth.js @@ -5,18 +5,6 @@ var bs58 = require('bs58'); var BitAuth = {}; -/** - * Will add leading zeros to hex string - * - * @returns {String} A hex string - */ -BitAuth._addPaddingToHex = function(hex){ - while( hex.length < 64 ){ - hex = '0'+hex; - } - return hex; -} - /** * Will return a key pair and identity * @@ -29,7 +17,7 @@ BitAuth.generateSin = function() { var keys = ecdsa.genKeyPair(); - var privateKey = this._addPaddingToHex(keys.getPrivate('hex')); + var privateKey = keys.getPrivate('hex'); var publicKey = this.getPublicKeyFromPrivateKey(privateKey); var sin = this.getSinFromPublicKey(publicKey); @@ -56,8 +44,8 @@ BitAuth.getPublicKeyFromPrivateKey = function(privkey) { // compressed public key var pubKey = keys.getPublic(); - var xbuf = new Buffer(this._addPaddingToHex(pubKey.x.toString('hex')), 'hex'); - var ybuf = new Buffer(this._addPaddingToHex(pubKey.y.toString('hex')), 'hex'); + var xbuf = new Buffer(pubKey.x.toString('hex', 2), 'hex'); + var ybuf = new Buffer(pubKey.y.toString('hex', 2), 'hex'); if (ybuf[ybuf.length-1] % 2) { //odd var pub = Buffer.concat([new Buffer([3]), xbuf]); @@ -114,7 +102,7 @@ BitAuth.getSinFromPublicKey = function(pubkey) { * @returns {String} signature - A DER signature in hex */ BitAuth.sign = function(data, privkey) { - var hash = (new hashjs.sha256()).update(new Buffer(data, 'ascii')).digest('hex'); + var hash = (new hashjs.sha256()).update(new Buffer(data)).digest('hex'); var signature = ecdsa.sign(hash, privkey); var hexsignature = signature.toDER('hex'); return hexsignature; @@ -129,7 +117,7 @@ BitAuth.sign = function(data, privkey) { * @returns {Function|Boolean} - If the signature is valid */ BitAuth.verifySignature = function(data, pubkey, hexsignature, callback) { - var hash = (new hashjs.sha256()).update(new Buffer(data, 'ascii')).digest('hex'); + var hash = (new hashjs.sha256()).update(new Buffer(data)).digest('hex'); var signature = new Buffer(hexsignature, 'hex'); var valid = ecdsa.verify(hash, signature, pubkey); if ( callback ){ diff --git a/package.json b/package.json index 0ce9c22..522c6ad 100644 --- a/package.json +++ b/package.json @@ -26,9 +26,9 @@ "main": "index.js", "version": "0.1.1", "dependencies": { - "elliptic": "=0.15.11", - "hash.js": "=0.3.2", - "bs58": "=2.0.0", + "elliptic": "^0.15.12", + "hash.js": "^0.3.2", + "bs58": "^2.0.0", "request": "^2.36.0", "express": "^4.3.1", "base58-native": "^0.1.4", From e6bcf1293408c22f053b5ab4ad0f024be90b4799 Mon Sep 17 00:00:00 2001 From: Braydon Fuller Date: Mon, 3 Nov 2014 12:05:33 -0500 Subject: [PATCH 4/8] fixed an issue with verifying a signature with a public key with leading zeros --- lib/bitauth.js | 4 ++-- test/test.bitauth.js | 21 +++++++++++++++++++++ 2 files changed, 23 insertions(+), 2 deletions(-) diff --git a/lib/bitauth.js b/lib/bitauth.js index 082a4dc..5de5aa6 100644 --- a/lib/bitauth.js +++ b/lib/bitauth.js @@ -44,8 +44,8 @@ BitAuth.getPublicKeyFromPrivateKey = function(privkey) { // compressed public key var pubKey = keys.getPublic(); - var xbuf = new Buffer(pubKey.x.toString('hex', 2), 'hex'); - var ybuf = new Buffer(pubKey.y.toString('hex', 2), 'hex'); + var xbuf = new Buffer(pubKey.x.toString('hex', 64), 'hex'); + var ybuf = new Buffer(pubKey.y.toString('hex', 64), 'hex'); if (ybuf[ybuf.length-1] % 2) { //odd var pub = Buffer.concat([new Buffer([3]), xbuf]); diff --git a/test/test.bitauth.js b/test/test.bitauth.js index f008fbc..8149c51 100644 --- a/test/test.bitauth.js +++ b/test/test.bitauth.js @@ -19,6 +19,9 @@ describe('bitauth', function() { sin: 'Tf3yr5tYvccKNVrE26BrPs6LWZRh8woHwjR' } + // a private key that will produce a public key with a leading zero + var privateKeyToZero = 'c6b7f6bfe5bb19b1e390e55ed4ba5df8af6068d0eb89379a33f9c19aacf6c08c'; + // keys generated var keys = null; @@ -99,6 +102,24 @@ describe('bitauth', function() { }); }); + it('should verify the signature with leading zero public key', function(done) { + + var leadingZeroKeys = { + priv: privateKeyToZero, + pub: bitauth.getPublicKeyFromPrivateKey(privateKeyToZero) + }; + + signature = bitauth.sign(contract, leadingZeroKeys.priv); + bitauth.verifySignature(contract, leadingZeroKeys.pub, signature, function(err, valid){ + should.not.exist(err); + should.exist(valid); + valid.should.equal(true); + }); + + done(); + + }); + }); describe('#validateSinTrue', function() { From 81bc5c9779b97e618935ade80943a878b79bea0f Mon Sep 17 00:00:00 2001 From: Braydon Fuller Date: Mon, 3 Nov 2014 13:30:11 -0500 Subject: [PATCH 5/8] remove unnecessary buffers, handle non-base58 chars in validateSin, and add postinstall --- lib/bitauth.js | 27 +++++++++++++++++---------- package.json | 1 + test/test.bitauth.js | 8 +++++++- 3 files changed, 25 insertions(+), 11 deletions(-) diff --git a/lib/bitauth.js b/lib/bitauth.js index 5de5aa6..c567319 100644 --- a/lib/bitauth.js +++ b/lib/bitauth.js @@ -69,17 +69,17 @@ BitAuth.getPublicKeyFromPrivateKey = function(privkey) { BitAuth.getSinFromPublicKey = function(pubkey) { // sha256 hash the pubkey - var pubHash = (new hashjs.sha256()).update(new Buffer(pubkey, 'hex')).digest('hex'); + var pubHash = (new hashjs.sha256()).update(pubkey, 'hex').digest('hex'); // get the ripemd160 hash of the pubkey - var pubRipe = (new hashjs.ripemd160()).update(new Buffer(pubHash, 'hex')).digest('hex'); + var pubRipe = (new hashjs.ripemd160()).update(pubHash, 'hex').digest('hex'); // add the version var pubPrefixed = '0f02'+pubRipe; // two rounds of hashing to generate the checksum - var hash1 = (new hashjs.sha256()).update(new Buffer(pubPrefixed, 'hex')).digest('hex'); - var checksumTotal = (new hashjs.sha256()).update(new Buffer(hash1, 'hex')).digest('hex'); + var hash1 = (new hashjs.sha256()).update(pubPrefixed, 'hex').digest('hex'); + var checksumTotal = (new hashjs.sha256()).update(hash1, 'hex').digest('hex'); // slice the hash to arrive at the checksum var checksum = checksumTotal.slice(0,8); @@ -102,7 +102,7 @@ BitAuth.getSinFromPublicKey = function(pubkey) { * @returns {String} signature - A DER signature in hex */ BitAuth.sign = function(data, privkey) { - var hash = (new hashjs.sha256()).update(new Buffer(data)).digest('hex'); + var hash = (new hashjs.sha256()).update(data).digest('hex'); var signature = ecdsa.sign(hash, privkey); var hexsignature = signature.toDER('hex'); return hexsignature; @@ -117,7 +117,7 @@ BitAuth.sign = function(data, privkey) { * @returns {Function|Boolean} - If the signature is valid */ BitAuth.verifySignature = function(data, pubkey, hexsignature, callback) { - var hash = (new hashjs.sha256()).update(new Buffer(data)).digest('hex'); + var hash = (new hashjs.sha256()).update(data).digest('hex'); var signature = new Buffer(hexsignature, 'hex'); var valid = ecdsa.verify(hash, signature, pubkey); if ( callback ){ @@ -136,8 +136,15 @@ BitAuth.verifySignature = function(data, pubkey, hexsignature, callback) { */ BitAuth.validateSin = function(sin, callback) { - var decoded = bs58.decode(sin); - var pubWithChecksum = new Buffer(decoded, 'hex').toString('hex'); + try { + var pubWithChecksum = new Buffer(bs58.decode(sin), 'hex').toString('hex'); + } catch( err ) { + if ( callback ) { + return callback( err ); + } else { + return false; + } + } // check the version if ( pubWithChecksum.slice(0, 4) != '0f02' ) { @@ -152,8 +159,8 @@ BitAuth.validateSin = function(sin, callback) { var pubPrefixed = pubWithChecksum.slice(0, pubWithChecksum.length-8); // two rounds of hashing to generate the checksum - var hash1 = (new hashjs.sha256()).update(new Buffer(pubPrefixed, 'hex')).digest('hex'); - var checksumTotal = (new hashjs.sha256()).update(new Buffer(hash1, 'hex')).digest('hex'); + var hash1 = (new hashjs.sha256()).update(pubPrefixed, 'hex').digest('hex'); + var checksumTotal = (new hashjs.sha256()).update(hash1, 'hex').digest('hex'); // check the checksum if ( checksumTotal.slice(0,8) == checksum ) { diff --git a/package.json b/package.json index 522c6ad..d0185c1 100644 --- a/package.json +++ b/package.json @@ -21,6 +21,7 @@ ], "scripts": { "make-dist": "sh scripts/make-dist.sh", + "postinstall": "npm run make-dist", "test": "mocha test/*.js --reporter spec" }, "main": "index.js", diff --git a/test/test.bitauth.js b/test/test.bitauth.js index 8149c51..81b27f0 100644 --- a/test/test.bitauth.js +++ b/test/test.bitauth.js @@ -134,12 +134,18 @@ describe('bitauth', function() { describe('#validateSinFalse', function() { - it('should validate the sin as false', function(done) { + it('should validate the sin as false because of bad checksum', function(done) { var valid = bitauth.validateSin(sinbad); should.equal(false, valid); done(); }); + it('should validate the sin as false because of non-base58', function(done) { + var valid = bitauth.validateSin('not#base!58'); + should.equal(false, valid); + done(); + }); + }); describe('#validateSinCallback', function() { From 7f4a10f72b1fc4a4d344b6023fbac0f71340421c Mon Sep 17 00:00:00 2001 From: Braydon Fuller Date: Mon, 3 Nov 2014 13:44:03 -0500 Subject: [PATCH 6/8] fixed formatting and docs --- lib/bitauth.js | 55 ++++++++++++++++++++++++-------------------------- 1 file changed, 26 insertions(+), 29 deletions(-) diff --git a/lib/bitauth.js b/lib/bitauth.js index c567319..2d3a386 100644 --- a/lib/bitauth.js +++ b/lib/bitauth.js @@ -1,7 +1,7 @@ -var elliptic = require('elliptic'); -var ecdsa = new elliptic.ec(elliptic.curves.secp256k1); -var hashjs = require('hash.js'); -var bs58 = require('bs58'); +var elliptic = require('elliptic'); +var ecdsa = new elliptic.ec(elliptic.curves.secp256k1); +var hashjs = require('hash.js'); +var bs58 = require('bs58'); var BitAuth = {}; @@ -26,7 +26,7 @@ BitAuth.generateSin = function() { priv: privateKey, pub: publicKey, sin: sin - } + }; return sinObj; }; @@ -46,12 +46,12 @@ BitAuth.getPublicKeyFromPrivateKey = function(privkey) { var pubKey = keys.getPublic(); var xbuf = new Buffer(pubKey.x.toString('hex', 64), 'hex'); var ybuf = new Buffer(pubKey.y.toString('hex', 64), 'hex'); + var pub; if (ybuf[ybuf.length-1] % 2) { //odd - var pub = Buffer.concat([new Buffer([3]), xbuf]); - } - else { //even - var pub = Buffer.concat([new Buffer([2]), xbuf]); + pub = Buffer.concat([new Buffer([3]), xbuf]); + } else { //even + pub = Buffer.concat([new Buffer([2]), xbuf]); } var hexPubKey = pub.toString('hex'); @@ -61,7 +61,7 @@ BitAuth.getPublicKeyFromPrivateKey = function(privkey) { }; /** - * Will return a SIN from a compressed private key + * Will return a SIN from a compressed public key * * @param {String} A public key in hex * @returns {String} A SIN identity @@ -92,13 +92,13 @@ BitAuth.getSinFromPublicKey = function(pubkey) { return sin; -} +}; /** * Will return a signature from a private key * * @param {String} data - A string of data to be signed - * @param {String} privKey - A private key in hex + * @param {String} privkey - A private key in hex * @returns {String} signature - A DER signature in hex */ BitAuth.sign = function(data, privkey) { @@ -120,11 +120,9 @@ BitAuth.verifySignature = function(data, pubkey, hexsignature, callback) { var hash = (new hashjs.sha256()).update(data).digest('hex'); var signature = new Buffer(hexsignature, 'hex'); var valid = ecdsa.verify(hash, signature, pubkey); - if ( callback ){ + if ( callback ) return callback(null, valid); - } else { - return valid; - } + return valid; }; @@ -136,26 +134,27 @@ BitAuth.verifySignature = function(data, pubkey, hexsignature, callback) { */ BitAuth.validateSin = function(sin, callback) { + var pubWithChecksum; + + // check for non-base58 characters try { - var pubWithChecksum = new Buffer(bs58.decode(sin), 'hex').toString('hex'); + pubWithChecksum = new Buffer(bs58.decode(sin), 'hex').toString('hex'); } catch( err ) { - if ( callback ) { + if ( callback ) return callback( err ); - } else { - return false; - } + return false; } // check the version if ( pubWithChecksum.slice(0, 4) != '0f02' ) { - if ( callback ) { + if ( callback ) return callback(new Error('Invalid prefix or SIN version')); - } return false; } // get the checksum - var checksum = pubWithChecksum.slice(pubWithChecksum.length-8, pubWithChecksum.length); + var checksum = pubWithChecksum.slice(pubWithChecksum.length-8, + pubWithChecksum.length); var pubPrefixed = pubWithChecksum.slice(0, pubWithChecksum.length-8); // two rounds of hashing to generate the checksum @@ -164,14 +163,12 @@ BitAuth.validateSin = function(sin, callback) { // check the checksum if ( checksumTotal.slice(0,8) == checksum ) { - if ( callback ) { + if ( callback ) return callback(null); - } - return true + return true; } else { - if ( callback ) { + if ( callback ) return callback(new Error('Checksum does not match')); - } return false; } From f39f5a9b61d1ade21d2abf47cb41185a5802eb29 Mon Sep 17 00:00:00 2001 From: Braydon Fuller Date: Tue, 4 Nov 2014 09:45:20 -0500 Subject: [PATCH 7/8] include compress param in make-dist --- scripts/make-dist.sh | 2 +- test/test.bitauth.js | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/scripts/make-dist.sh b/scripts/make-dist.sh index 200c97b..ddc6545 100644 --- a/scripts/make-dist.sh +++ b/scripts/make-dist.sh @@ -1,5 +1,5 @@ echo "Building browser bundle for bitauth..." node_modules/.bin/browserify lib/bitauth.js -s bitauth -o dist/bitauth.bundle.js echo "Minifying bitauth..." -node_modules/.bin/uglifyjs dist/bitauth.bundle.js -o dist/bitauth.browser.min.js +node_modules/.bin/uglifyjs dist/bitauth.bundle.js --compress --mangle -o dist/bitauth.browser.min.js echo "Done!" diff --git a/test/test.bitauth.js b/test/test.bitauth.js index 81b27f0..037c228 100644 --- a/test/test.bitauth.js +++ b/test/test.bitauth.js @@ -26,10 +26,10 @@ describe('bitauth', function() { var keys = null; // invalid checksum - var sinbad = 'Tf1Jc1xSbqasm5QLwwSQc5umddx2h7mAMhX'; + var sinbad = 'Tf1Jc1xSbqasm5QLwwSQc5umddx2h7mAMhX'; // valid sin - var singood = 'TfG4ScDgysrSpodWD4Re5UtXmcLbY5CiUHA'; + var singood = 'TfG4ScDgysrSpodWD4Re5UtXmcLbY5CiUHA'; // data to sign var contract = 'keyboard cat'; From 7f0d542a6a75ddd77718faf6d27ac170e3c824bf Mon Sep 17 00:00:00 2001 From: Braydon Fuller Date: Tue, 4 Nov 2014 10:53:37 -0500 Subject: [PATCH 8/8] cleanup docs and formatting --- lib/bitauth.js | 33 ++++++++++++++------------------- package.json | 4 ++++ 2 files changed, 18 insertions(+), 19 deletions(-) diff --git a/lib/bitauth.js b/lib/bitauth.js index 2d3a386..536d8e1 100644 --- a/lib/bitauth.js +++ b/lib/bitauth.js @@ -2,15 +2,11 @@ var elliptic = require('elliptic'); var ecdsa = new elliptic.ec(elliptic.curves.secp256k1); var hashjs = require('hash.js'); var bs58 = require('bs58'); - -var BitAuth = {}; +var BitAuth = {}; /** * Will return a key pair and identity * - * @example - * var keys = BitAuth.generateSin(); - * * @returns {Object} An object with keys: created, priv, pub and sin */ BitAuth.generateSin = function() { @@ -22,7 +18,7 @@ BitAuth.generateSin = function() { var sin = this.getSinFromPublicKey(publicKey); var sinObj = { - created: new Date().getTime(), + created: Math.round(Date.now() / 1000), priv: privateKey, pub: publicKey, sin: sin @@ -31,9 +27,8 @@ BitAuth.generateSin = function() { return sinObj; }; - /** - * Will return an public key from a private key + * Will return a public key from a private key * * @param {String} A private key in hex * @returns {String} A compressed public key in hex @@ -95,7 +90,7 @@ BitAuth.getSinFromPublicKey = function(pubkey) { }; /** - * Will return a signature from a private key + * Will sign a string of data with a private key * * @param {String} data - A string of data to be signed * @param {String} privkey - A private key in hex @@ -112,7 +107,7 @@ BitAuth.sign = function(data, privkey) { * Will verify a signature * * @param {String} data - A string of data that has been signed - * @param {String} pubkey - The public identity that has signed the data + * @param {String} pubkey - The compressed public key in hex that has signed the data * @param {String} hexsignature - A DER signature in hex * @returns {Function|Boolean} - If the signature is valid */ @@ -120,7 +115,7 @@ BitAuth.verifySignature = function(data, pubkey, hexsignature, callback) { var hash = (new hashjs.sha256()).update(data).digest('hex'); var signature = new Buffer(hexsignature, 'hex'); var valid = ecdsa.verify(hash, signature, pubkey); - if ( callback ) + if (callback) return callback(null, valid); return valid; }; @@ -139,15 +134,15 @@ BitAuth.validateSin = function(sin, callback) { // check for non-base58 characters try { pubWithChecksum = new Buffer(bs58.decode(sin), 'hex').toString('hex'); - } catch( err ) { - if ( callback ) - return callback( err ); + } catch(err) { + if (callback) + return callback(err); return false; } // check the version - if ( pubWithChecksum.slice(0, 4) != '0f02' ) { - if ( callback ) + if (pubWithChecksum.slice(0, 4) !== '0f02') { + if (callback) return callback(new Error('Invalid prefix or SIN version')); return false; } @@ -162,12 +157,12 @@ BitAuth.validateSin = function(sin, callback) { var checksumTotal = (new hashjs.sha256()).update(hash1, 'hex').digest('hex'); // check the checksum - if ( checksumTotal.slice(0,8) == checksum ) { - if ( callback ) + if (checksumTotal.slice(0,8) === checksum) { + if (callback) return callback(null); return true; } else { - if ( callback ) + if (callback) return callback(new Error('Checksum does not match')); return false; } diff --git a/package.json b/package.json index d0185c1..754e0c5 100644 --- a/package.json +++ b/package.json @@ -17,6 +17,10 @@ { "name": "Gordon Hall", "email": "gordon@bitpay.com" + }, + { + "name": "Braydon Fuller", + "email": "braydon@bitpay.com" } ], "scripts": {