diff --git a/lib/bcoin/hd.js b/lib/bcoin/hd.js index 622f5cda..72ea8b28 100644 --- a/lib/bcoin/hd.js +++ b/lib/bcoin/hd.js @@ -455,7 +455,7 @@ HDPrivateKey.prototype.derive = function derive(index, hardened) { data = p.render(); - hash = utils.sha512hmac(data, this.chainCode); + hash = utils.hmac('sha512', data, this.chainCode); leftPart = new bn(hash.slice(0, 32)); chainCode = hash.slice(32, 64); @@ -699,7 +699,7 @@ HDPrivateKey.parseSeed = function parseSeed(seed, networkType) { throw new Error('Entropy not in range.'); } - hash = utils.sha512hmac(data, 'Bitcoin seed'); + hash = utils.hmac('sha512', data, 'Bitcoin seed'); return { version: networkType @@ -1045,7 +1045,7 @@ HDPublicKey.prototype.derive = function derive(index, hardened) { p.writeU32BE(index); data = p.render(); - hash = utils.sha512hmac(data, this.chainCode); + hash = utils.hmac('sha512', data, this.chainCode); leftPart = new bn(hash.slice(0, 32)); chainCode = hash.slice(32, 64); diff --git a/lib/bcoin/utils.js b/lib/bcoin/utils.js index bc16edcd..0c2e9bf3 100644 --- a/lib/bcoin/utils.js +++ b/lib/bcoin/utils.js @@ -197,6 +197,21 @@ utils.isBase58 = function isBase58(msg) { return typeof msg === 'string' && /^[1-9a-zA-Z]+$/.test(msg); }; +/** + * Hash with chosen algorithm. + * @param {String} alg + * @param {Buffer|String} data + * @param {String?} enc - Any buffer-supported encoding. + * @returns {Buffer} + */ + +utils.hash = function _hash(alg, data, enc) { + if (!crypto) + return new Buffer(hash[alg]().update(data, enc).digest()); + + return crypto.createHash(alg).update(data, enc).digest(); +}; + /** * Hash with ripemd160. * @param {Buffer|String} data @@ -205,10 +220,7 @@ utils.isBase58 = function isBase58(msg) { */ utils.ripemd160 = function ripemd160(data, enc) { - if (!crypto) - return new Buffer(hash.ripemd160().update(data, enc).digest()); - - return crypto.createHash('ripemd160').update(data, enc).digest(); + return utils.hash('ripemd160', data, enc); }; /** @@ -219,10 +231,18 @@ utils.ripemd160 = function ripemd160(data, enc) { */ utils.sha1 = function sha1(data, enc) { - if (!crypto) - return new Buffer(hash.sha1().update(data, enc).digest()); + return utils.hash('sha1', data, enc); +}; - return crypto.createHash('sha1').update(data, enc).digest(); +/** + * Hash with sha256. + * @param {Buffer|String} data + * @param {String?} enc - Any buffer-supported encoding. + * @returns {Buffer} + */ + +utils.sha256 = function sha256(data, enc) { + return utils.hash('sha256', data, enc); }; /** @@ -236,31 +256,6 @@ utils.ripesha = function ripesha(data, enc) { return utils.ripemd160(utils.sha256(data, enc)); }; -/** - * Create a sha256 checksum (common in bitcoin). - * @param {Buffer|String} data - * @param {String?} enc - Any buffer-supported encoding. - * @returns {Buffer} - */ - -utils.checksum = function checksum(data, enc) { - return utils.dsha256(data, enc).slice(0, 4); -}; - -/** - * Hash with sha256. - * @param {Buffer|String} data - * @param {String?} enc - Any buffer-supported encoding. - * @returns {Buffer} - */ - -utils.sha256 = function sha256(data, enc) { - if (!crypto) - return new Buffer(hash.sha256().update(data, enc).digest()); - - return crypto.createHash('sha256').update(data, enc).digest(); -}; - /** * Hash with sha256 twice (OP_HASH256). * @param {Buffer|String} data @@ -273,24 +268,34 @@ utils.dsha256 = function dsha256(data, enc) { }; /** - * Create a sha512 HMAC. + * Create a sha256 checksum (common in bitcoin). + * @param {Buffer|String} data + * @param {String?} enc - Any buffer-supported encoding. + * @returns {Buffer} + */ + +utils.checksum = function checksum(data, enc) { + return utils.dsha256(data, enc).slice(0, 4); +}; + +/** + * Create an HMAC. + * @param {String} alg * @param {Buffer} data * @param {Buffer} salt * @returns {Buffer} HMAC */ -utils.sha512hmac = function sha512hmac(data, salt) { - var hmac, result; +utils.hmac = function hmac(alg, data, salt) { + var hmac; if (!crypto) { - hmac = hash.hmac(hash.sha512, salt); + hmac = hash.hmac(hash[alg], salt); return new Buffer(hmac.update(data).digest()); } - hmac = crypto.createHmac('sha512', salt); - result = hmac.update(data).digest(); - - return result; + hmac = crypto.createHmac(alg, salt); + return hmac.update(data).digest(); }; /** @@ -299,6 +304,7 @@ utils.sha512hmac = function sha512hmac(data, salt) { * @param {Buffer} salt * @param {Number} iterations * @param {Number} dkLen - Output size. + * @param {String?} alg */ /*! @@ -308,9 +314,8 @@ utils.sha512hmac = function sha512hmac(data, salt) { * Copyright (c) 2014, JP Richardson */ -utils.pbkdf2 = function pbkdf2(key, salt, iterations, dkLen) { - var hLen = 64; - var DK, U, T, block1, l, r; +utils.pbkdf2 = function pbkdf2(key, salt, iterations, dkLen, alg) { + var hLen, DK, U, T, block, l, r; var i, j, k, destPos, len; if (typeof key === 'string') @@ -319,33 +324,44 @@ utils.pbkdf2 = function pbkdf2(key, salt, iterations, dkLen) { if (typeof salt === 'string') salt = new Buffer(salt, 'utf8'); + if (!alg) + alg = 'sha512'; + if (crypto && crypto.pbkdf2Sync) - return crypto.pbkdf2Sync(key, salt, iterations, dkLen, 'sha512'); + return crypto.pbkdf2Sync(key, salt, iterations, dkLen, alg); + + if (alg === 'sha512') + hLen = 64; + else if (alg === 'sha256') + hLen = 32; + else if (alg === 'sha1' || alg === 'ripemd160') + hLen = 20; + else if (alg === 'md5') + hLen = 16; assert(dkLen <= 0xffffffff * hLen, 'Requested key length too long'); DK = new Buffer(dkLen); - U = new Buffer(hLen); T = new Buffer(hLen); - block1 = new Buffer(salt.length + 4); + block = new Buffer(salt.length + 4); l = Math.ceil(dkLen / hLen); r = dkLen - (l - 1) * hLen; - salt.copy(block1, 0, 0, salt.length); + salt.copy(block, 0, 0, salt.length); for (i = 1; i <= l; i++) { - block1[salt.length + 0] = i >> 24 & 0xff; - block1[salt.length + 1] = i >> 16 & 0xff; - block1[salt.length + 2] = i >> 8 & 0xff; - block1[salt.length + 3] = i >> 0 & 0xff; + block[salt.length + 0] = (i >>> 24) & 0xff; + block[salt.length + 1] = (i >>> 16) & 0xff; + block[salt.length + 2] = (i >>> 8) & 0xff; + block[salt.length + 3] = (i >>> 0) & 0xff; - U = utils.sha512hmac(block1, key); + U = utils.hmac(alg, block, key); U.copy(T, 0, 0, hLen); for (j = 1; j < iterations; j++) { - U = utils.sha512hmac(U, key); + U = utils.hmac(alg, U, key); for (k = 0; k < hLen; k++) T[k] ^= U[k]; @@ -428,16 +444,17 @@ utils.decrypt = function decrypt(data, passphrase) { * @param {Buffer|String} passphrase * @param {(Buffer|String)?} salt * @param {Number} iterations - * @param {Number} keySize - Key size in bits. - * @param {Number} ivSize - IV size in bytes. + * @param {Number} dkLen + * @param {Number} ivLen + * @param {String?} alg * @returns {Buffer} */ -utils.pbkdf2key = function pbkdf2key(passphrase, salt, iterations, keySize, ivSize) { - var key = utils.pbkdf2(passphrase, salt || '', iterations, keySize + ivSize); +utils.pbkdf2key = function pbkdf2key(passphrase, salt, iterations, dkLen, ivLen, alg) { + var key = utils.pbkdf2(passphrase, salt || '', iterations, dkLen + ivLen, alg); return { - key: key.slice(0, keySize), - iv: key.slice(keySize) + key: key.slice(0, dkLen), + iv: key.slice(dkLen) }; };