crypto: expose scrypt.

This commit is contained in:
Christopher Jeffrey 2016-09-12 22:55:47 -07:00
parent a52f239f3c
commit 2dba490d02
No known key found for this signature in database
GPG Key ID: 8962AB9DE6666BBD
7 changed files with 66 additions and 34 deletions

View File

@ -9,6 +9,8 @@
var assert = require('assert'); var assert = require('assert');
var random = require('./random'); var random = require('./random');
var scrypt = require('./scrypt');
var scryptAsync = require('./scrypt-async');
var native = require('../utils/native'); var native = require('../utils/native');
var nativeCrypto, supersha, hash, aes; var nativeCrypto, supersha, hash, aes;
@ -139,7 +141,7 @@ if (native)
crypto.hmac = native.hmac; crypto.hmac = native.hmac;
/** /**
* Perform key stretching using PBKDF2. * Perform key derivation using PBKDF2.
* @param {Buffer} key * @param {Buffer} key
* @param {Buffer} salt * @param {Buffer} salt
* @param {Number} iter * @param {Number} iter
@ -148,7 +150,7 @@ if (native)
* @returns {Buffer} * @returns {Buffer}
*/ */
crypto.pbkdf2Sync = function pbkdf2Sync(key, salt, iter, len, alg) { crypto.pbkdf2 = function pbkdf2(key, salt, iter, len, alg) {
if (typeof key === 'string') if (typeof key === 'string')
key = new Buffer(key, 'utf8'); key = new Buffer(key, 'utf8');
@ -171,7 +173,7 @@ crypto.pbkdf2Sync = function pbkdf2Sync(key, salt, iter, len, alg) {
* @param {Function} callback * @param {Function} callback
*/ */
crypto.pbkdf2 = function pbkdf2(key, salt, iter, len, alg, callback) { crypto.pbkdf2Async = function pbkdf2Async(key, salt, iter, len, alg, callback) {
var result; var result;
if (typeof key === 'string') if (typeof key === 'string')
@ -192,6 +194,48 @@ crypto.pbkdf2 = function pbkdf2(key, salt, iter, len, alg, callback) {
return callback(null, result); return callback(null, result);
}; };
/**
* Perform key derivation using scrypt.
* @param {Buffer} passwd
* @param {Buffer} salt
* @param {Number} N
* @param {Number} r
* @param {Number} p
* @param {Number} len
* @returns {Buffer}
*/
crypto.scrypt = function _scrypt(passwd, salt, N, r, p, len) {
if (typeof passwd === 'string')
passwd = new Buffer(passwd, 'utf8');
if (typeof salt === 'string')
salt = new Buffer(salt, 'utf8');
return scrypt(passwd, salt, N, r, p, len);
};
/**
* Execute scrypt asynchronously.
* @param {Buffer} passwd
* @param {Buffer} salt
* @param {Number} N
* @param {Number} r
* @param {Number} p
* @param {Number} len
* @param {Function} callback
*/
crypto.scryptAsync = function _scryptAsync(passwd, salt, N, r, p, len, callback) {
if (typeof passwd === 'string')
passwd = new Buffer(passwd, 'utf8');
if (typeof salt === 'string')
salt = new Buffer(salt, 'utf8');
return scryptAsync(passwd, salt, N, r, p, len, callback);
};
/** /**
* Derive a key using pbkdf2 with 50,000 iterations. * Derive a key using pbkdf2 with 50,000 iterations.
* @param {Buffer|String} passphrase * @param {Buffer|String} passphrase
@ -199,7 +243,7 @@ crypto.pbkdf2 = function pbkdf2(key, salt, iter, len, alg, callback) {
*/ */
crypto.derive = function derive(passphrase, callback) { crypto.derive = function derive(passphrase, callback) {
crypto.pbkdf2(passphrase, 'bcoin', 50000, 32, 'sha256', callback); crypto.pbkdf2Async(passphrase, 'bcoin', 50000, 32, 'sha256', callback);
}; };
/** /**
@ -304,7 +348,7 @@ crypto.decipher = function decipher(data, key, iv) {
}; };
/** /**
* Perform key stretching using PBKDF2. * Perform key derivation using PBKDF2.
* @private * @private
* @param {Buffer} key * @param {Buffer} key
* @param {Buffer} salt * @param {Buffer} salt

View File

@ -51,18 +51,9 @@ var U32Array = typeof Uint32Array === 'function' ? Uint32Array : Array;
* @returns {Buffer} * @returns {Buffer}
*/ */
function scrypt(passwd, salt, N, r, p, len, callback) { function scryptAsync(passwd, salt, N, r, p, len, callback) {
var V, XY; var V, XY;
if (typeof passwd === 'string')
passwd = new Buffer(passwd, 'utf8');
if (typeof salt === 'string')
salt = new Buffer(salt, 'utf8');
if (native)
return native.scryptAsync(passwd, salt, N, r, p, len, callback);
if (r * p >= (1 << 30)) if (r * p >= (1 << 30))
return callback(new Error('EFBIG')); return callback(new Error('EFBIG'));
@ -75,7 +66,7 @@ function scrypt(passwd, salt, N, r, p, len, callback) {
XY = new Buffer(256 * r); XY = new Buffer(256 * r);
V = new Buffer(128 * r * N); V = new Buffer(128 * r * N);
crypto.pbkdf2(passwd, salt, 1, p * 128 * r, 'sha256', function(err, B) { crypto.pbkdf2Async(passwd, salt, 1, p * 128 * r, 'sha256', function(err, B) {
if (err) if (err)
return callback(err); return callback(err);
@ -85,11 +76,14 @@ function scrypt(passwd, salt, N, r, p, len, callback) {
if (err) if (err)
return callback(err); return callback(err);
crypto.pbkdf2(passwd, B, 1, len, 'sha256', callback); crypto.pbkdf2Async(passwd, B, 1, len, 'sha256', callback);
}); });
}); });
} }
if (native)
scryptAsync = native.scryptAsync;
function salsa20_8(B) { function salsa20_8(B) {
var B32 = new U32Array(16); var B32 = new U32Array(16);
var x = new U32Array(16); var x = new U32Array(16);
@ -232,4 +226,4 @@ function forRangeSerial(from, to, iter, callback) {
* Expose * Expose
*/ */
module.exports = scrypt; module.exports = scryptAsync;

View File

@ -53,15 +53,6 @@ var U32Array = typeof Uint32Array === 'function' ? Uint32Array : Array;
function scrypt(passwd, salt, N, r, p, len) { function scrypt(passwd, salt, N, r, p, len) {
var i, B, V, XY; var i, B, V, XY;
if (typeof passwd === 'string')
passwd = new Buffer(passwd, 'utf8');
if (typeof salt === 'string')
salt = new Buffer(salt, 'utf8');
if (native)
return native.scrypt(passwd, salt, N, r, p, len);
if (r * p >= (1 << 30)) if (r * p >= (1 << 30))
throw new Error('EFBIG'); throw new Error('EFBIG');
@ -74,14 +65,17 @@ function scrypt(passwd, salt, N, r, p, len) {
XY = new Buffer(256 * r); XY = new Buffer(256 * r);
V = new Buffer(128 * r * N); V = new Buffer(128 * r * N);
B = crypto.pbkdf2Sync(passwd, salt, 1, p * 128 * r, 'sha256'); B = crypto.pbkdf2(passwd, salt, 1, p * 128 * r, 'sha256');
for (i = 0; i < p; i++) for (i = 0; i < p; i++)
smix(B, i * 128 * r, r, N, V, XY); smix(B, i * 128 * r, r, N, V, XY);
return crypto.pbkdf2Sync(passwd, B, 1, len, 'sha256'); return crypto.pbkdf2(passwd, B, 1, len, 'sha256');
} }
if (native)
scrypt = native.scrypt;
function salsa20_8(B) { function salsa20_8(B) {
var B32 = new U32Array(16); var B32 = new U32Array(16);
var x = new U32Array(16); var x = new U32Array(16);

View File

@ -142,7 +142,7 @@ Mnemonic.prototype.toSeed = function toSeed(passphrase) {
this.passphrase = passphrase; this.passphrase = passphrase;
return crypto.pbkdf2Sync( return crypto.pbkdf2(
nfkd(this.getPhrase()), nfkd(this.getPhrase()),
nfkd('mnemonic' + passphrase), nfkd('mnemonic' + passphrase),
2048, 64, 'sha512'); 2048, 64, 'sha512');

View File

@ -9,7 +9,7 @@ var nativeCrypto = require('crypto');
describe('AES', function() { describe('AES', function() {
function pbkdf2key(passphrase, iterations, dkLen, ivLen, alg) { function pbkdf2key(passphrase, iterations, dkLen, ivLen, alg) {
var key = crypto.pbkdf2Sync(passphrase, '', iterations, dkLen + ivLen, 'sha512'); var key = crypto.pbkdf2(passphrase, '', iterations, dkLen + ivLen, 'sha512');
return { return {
key: key.slice(0, dkLen), key: key.slice(0, dkLen),
iv: key.slice(dkLen, dkLen + ivLen) iv: key.slice(dkLen, dkLen + ivLen)

View File

@ -91,7 +91,7 @@ describe('HD', function() {
var master, child1, child2, child3, child4, child5, child6; var master, child1, child2, child3, child4, child5, child6;
it('should create a pbkdf2 seed', function() { it('should create a pbkdf2 seed', function() {
var checkSeed = crypto.pbkdf2Sync( var checkSeed = crypto.pbkdf2(
phrase, 'mnemonic' + 'foo', 2048, 64, 'sha512').toString('hex'); phrase, 'mnemonic' + 'foo', 2048, 64, 'sha512').toString('hex');
assert.equal(checkSeed, seed); assert.equal(checkSeed, seed);
}); });

View File

@ -1,7 +1,7 @@
'use strict'; 'use strict';
var assert = require('assert'); var assert = require('assert');
var scrypt = require('../lib/crypto/scrypt'); var scrypt = require('../lib/crypto/crypto').scrypt;
describe('Scrypt', function() { describe('Scrypt', function() {
it('should perform scrypt with N=16', function() { it('should perform scrypt with N=16', function() {
@ -13,7 +13,7 @@ describe('Scrypt', function() {
}); });
it('should perform scrypt with N=1024', function() { it('should perform scrypt with N=1024', function() {
var result = scrypt('password', 'NaCl', 1024, 8, 16, 64) var result = scrypt('password', 'NaCl', 1024, 8, 16, 64);
assert.equal(result.toString('hex'), '' assert.equal(result.toString('hex'), ''
+ 'fdbabe1c9d3472007856e7190d01e9fe7c6ad7cbc8237830e773' + 'fdbabe1c9d3472007856e7190d01e9fe7c6ad7cbc8237830e773'
+ '76634b3731622eaf30d92e22a3886ff109279d9830dac727afb9' + '76634b3731622eaf30d92e22a3886ff109279d9830dac727afb9'