From 79d50e92d429bccbf643e582a0a1298ce08cff3e Mon Sep 17 00:00:00 2001 From: Devrandom Date: Wed, 23 Apr 2014 13:29:51 -0400 Subject: [PATCH] BIP39 in browser --- bitcore.js | 2 +- browser/build.js | 3 +++ lib/browser/cryptox.js | 41 +++++++++++++++++++++++++++++++++ lib/cryptox.js | 52 ++++-------------------------------------- lib/node/cryptox.js | 49 +++++++++++++++++++++++++++++++++++++++ test/index.html | 1 + test/test.BIP39.js | 2 +- 7 files changed, 100 insertions(+), 50 deletions(-) create mode 100644 lib/browser/cryptox.js create mode 100644 lib/node/cryptox.js diff --git a/bitcore.js b/bitcore.js index 43de754..282a9c8 100644 --- a/bitcore.js +++ b/bitcore.js @@ -43,7 +43,7 @@ Object.defineProperty(module.exports, 'BIP32', {get: function() { return require('./lib/HierarchicalKey'); }}); requireWhenAccessed('BIP39', './lib/BIP39'); -requireWhenAccessed('BIP39WordlistEn', './BIP39WordlistEn'); +requireWhenAccessed('BIP39WordlistEn', './lib/BIP39WordlistEn'); requireWhenAccessed('Point', './lib/Point'); requireWhenAccessed('Opcode', './lib/Opcode'); requireWhenAccessed('Script', './lib/Script'); diff --git a/browser/build.js b/browser/build.js index e938663..364a986 100644 --- a/browser/build.js +++ b/browser/build.js @@ -27,6 +27,9 @@ var modules = [ 'lib/Armory', 'lib/Base58', 'lib/HierarchicalKey', + 'lib/BIP39', + 'lib/BIP39WordlistEn', + 'lib/cryptox', 'lib/Block', 'lib/Bloom', 'lib/Connection', diff --git a/lib/browser/cryptox.js b/lib/browser/cryptox.js new file mode 100644 index 0000000..71647ea --- /dev/null +++ b/lib/browser/cryptox.js @@ -0,0 +1,41 @@ +// Crypto extensions +// +// PBKDF2 with SHA512 - browser version + +var jssha = require('jssha') + +var pbkdf2_sha512 = function (password, salt, keylen, options) { + password = new Buffer(password); + salt = new Buffer(salt); + // Defaults + var iterations = options && options.iterations || 1; + + // Pseudo-random function + function PRF(password, salt) { + var j = new jssha(salt.toString('hex'), 'HEX'); + var hash = j.getHMAC(password.toString('hex'), "HEX", "SHA-512", "HEX"); + return new Buffer(hash, 'hex'); + } + + // Generate key + var derivedKeyBytes = new Buffer([]), + blockindex = 1; + while (derivedKeyBytes.length < keylen) { + var block = PRF(password, salt.concat([0, 0, 0, blockindex])); + for (var u = block, i = 1; i < iterations; i++) { + u = PRF(password, u); + for (var j = 0; j < block.length; j++) block[j] ^= u[j]; + } + derivedKeyBytes = derivedKeyBytes.concat(block); + blockindex++; + } + + // Truncate excess bytes - TODO + //derivedKeyBytes.length = keylen; + + return new Buffer(derivedKeyBytes); +}; + +exports.pbkdf2Sync_sha512 = function(password, salt, iterations, keylen) { + return pbkdf2_sha512(password, salt, keylen, {iterations: iterations}); +}; diff --git a/lib/cryptox.js b/lib/cryptox.js index 240736c..7f382df 100644 --- a/lib/cryptox.js +++ b/lib/cryptox.js @@ -1,49 +1,5 @@ -// Crypto extensions -// -// PBKDF2 with SHA512 - -var binding = require('bindings')('cryptox'); - -exports.pbkdf2_sha512 = function(password, salt, iterations, keylen, callback) { - if (typeof callback !== 'function') - throw new Error('No callback provided to pbkdf2'); - - return pbkdf2_sha512(password, salt, iterations, keylen, callback); -}; - - -exports.pbkdf2Sync_sha512 = function(password, salt, iterations, keylen) { - return pbkdf2_sha512(password, salt, iterations, keylen); -}; - -function toBuf(str, encoding) { - encoding = encoding || 'binary'; - if (typeof str === 'string') { - if (encoding === 'buffer') - encoding = 'binary'; - str = new Buffer(str, encoding); - } - return str; -} - -function pbkdf2_sha512(password, salt, iterations, keylen, callback) { - password = toBuf(password); - salt = toBuf(salt); - - if (exports.DEFAULT_ENCODING === 'buffer') - return binding.PBKDF2(password, salt, iterations, keylen, callback); - - // at this point, we need to handle encodings. - var encoding = exports.DEFAULT_ENCODING; - if (callback) { - binding.PBKDF2_sha512(password, salt, iterations, keylen, function(er, ret) { - if (ret) - ret = ret.toString(encoding); - callback(er, ret); - }); - } else { - var ret = binding.PBKDF2_sha512(password, salt, iterations, keylen); - //return ret.toString(encoding); - return ret; - } +if (process.versions) { + module.exports = require('./node/cryptox'); + return; } +module.exports = require('./browser/cryptox'); diff --git a/lib/node/cryptox.js b/lib/node/cryptox.js new file mode 100644 index 0000000..240736c --- /dev/null +++ b/lib/node/cryptox.js @@ -0,0 +1,49 @@ +// Crypto extensions +// +// PBKDF2 with SHA512 + +var binding = require('bindings')('cryptox'); + +exports.pbkdf2_sha512 = function(password, salt, iterations, keylen, callback) { + if (typeof callback !== 'function') + throw new Error('No callback provided to pbkdf2'); + + return pbkdf2_sha512(password, salt, iterations, keylen, callback); +}; + + +exports.pbkdf2Sync_sha512 = function(password, salt, iterations, keylen) { + return pbkdf2_sha512(password, salt, iterations, keylen); +}; + +function toBuf(str, encoding) { + encoding = encoding || 'binary'; + if (typeof str === 'string') { + if (encoding === 'buffer') + encoding = 'binary'; + str = new Buffer(str, encoding); + } + return str; +} + +function pbkdf2_sha512(password, salt, iterations, keylen, callback) { + password = toBuf(password); + salt = toBuf(salt); + + if (exports.DEFAULT_ENCODING === 'buffer') + return binding.PBKDF2(password, salt, iterations, keylen, callback); + + // at this point, we need to handle encodings. + var encoding = exports.DEFAULT_ENCODING; + if (callback) { + binding.PBKDF2_sha512(password, salt, iterations, keylen, function(er, ret) { + if (ret) + ret = ret.toString(encoding); + callback(er, ret); + }); + } else { + var ret = binding.PBKDF2_sha512(password, salt, iterations, keylen); + //return ret.toString(encoding); + return ret; + } +} diff --git a/test/index.html b/test/index.html index 7e036ce..c0bab93 100644 --- a/test/index.html +++ b/test/index.html @@ -20,6 +20,7 @@ + diff --git a/test/test.BIP39.js b/test/test.BIP39.js index 0f8d810..03118ec 100644 --- a/test/test.BIP39.js +++ b/test/test.BIP39.js @@ -154,7 +154,7 @@ describe('BIP39', function() { var mnemonic1 = BIP39.to_mnemonic(BIP39WordlistEn, new Buffer(code, 'hex')); var seed1 = BIP39.mnemonic_to_seed(mnemonic, 'TREZOR'); mnemonic1.should.equal(mnemonic); - seed1.toString().should.equal(new Buffer(seed, 'hex').toString()); + seed1.toString('hex').should.equal(seed) } }); });