crypto: implement subtle api for browser.

This commit is contained in:
Christopher Jeffrey 2016-11-21 00:55:52 -08:00
parent 4245cd6bf1
commit f376289684
No known key found for this signature in database
GPG Key ID: 8962AB9DE6666BBD
31 changed files with 1009 additions and 377 deletions

View File

@ -8,6 +8,7 @@
var assert = require('assert'); var assert = require('assert');
var util = require('../utils/util'); var util = require('../utils/util');
var co = require('../utils/co');
var crypto = require('../crypto/crypto'); var crypto = require('../crypto/crypto');
var x509 = require('./x509'); var x509 = require('./x509');
var PEM = require('../utils/pem'); var PEM = require('../utils/pem');
@ -226,6 +227,34 @@ PaymentRequest.prototype.verifyChain = function verifyChain() {
return x509.verifyChain(this.getChain()); return x509.verifyChain(this.getChain());
}; };
PaymentRequest.prototype.verifyAsync = co(function* verifyAsync() {
var alg, msg, sig, chain;
if (!this.pkiType || this.pkiType === 'none')
return true;
if (!this.signature)
return false;
alg = this.getAlgorithm();
if (!alg)
return false;
msg = this.signatureData();
sig = this.signature;
chain = this.getChain();
return yield x509.verifySubjectAsync(alg.hash, msg, sig, chain);
});
PaymentRequest.prototype.verifyChainAsync = co(function* verifyChain() {
if (!this.pkiType || this.pkiType === 'none')
return true;
return yield x509.verifyChainAsync(this.getChain());
});
PaymentRequest.prototype.getCA = function getCA() { PaymentRequest.prototype.getCA = function getCA() {
var chain, root; var chain, root;

View File

@ -7,6 +7,7 @@
'use strict'; 'use strict';
var pk = require('../crypto/pk'); var pk = require('../crypto/pk');
var co = require('../utils/co');
exports._verify = function verify(hash, msg, sig, key) { exports._verify = function verify(hash, msg, sig, key) {
switch (key.alg) { switch (key.alg) {
@ -41,3 +42,37 @@ exports.sign = function sign(hash, msg, key) {
throw new Error('Unsupported algorithm.'); throw new Error('Unsupported algorithm.');
} }
}; };
exports._verifyAsync = co(function* verifyAsync(hash, msg, sig, key) {
switch (key.alg) {
case 'dsa':
return yield pk.dsa.verifyAsync(hash, msg, sig, key.data, key.params);
case 'rsa':
return yield pk.rsa.verifyAsync(hash, msg, sig, key.data);
case 'ecdsa':
return yield pk.ecdsa.verifyAsync(key.curve, hash, msg, sig, key.data);
default:
throw new Error('Unsupported algorithm.');
}
});
exports.verifyAsync = co(function* verifyAsync(hash, msg, sig, key) {
try {
return yield exports._verifyAsync(hash, msg, sig, key);
} catch (e) {
return false;
}
});
exports.signAsync = co(function* signAsync(hash, msg, key) {
switch (key.alg) {
case 'dsa':
return yield pk.dsa.signAsync(hash, msg, key.data, key.params);
case 'rsa':
return yield pk.rsa.signAsync(hash, msg, key.data);
case 'ecdsa':
return yield pk.ecdsa.signAsync(key.curve, hash, msg, key.data);
default:
throw new Error('Unsupported algorithm.');
}
});

View File

@ -12,6 +12,7 @@ var PEM = require('../utils/pem');
var util = require('../utils/util'); var util = require('../utils/util');
var crypto = require('../crypto/crypto'); var crypto = require('../crypto/crypto');
var pk = require('./pk'); var pk = require('./pk');
var co = require('../utils/co');
var x509 = exports; var x509 = exports;
x509.getSubjectOID = function getSubjectOID(cert, oid) { x509.getSubjectOID = function getSubjectOID(cert, oid) {
@ -177,11 +178,11 @@ x509.getPublicKey = function getPublicKey(cert) {
x509.verifyTime = function verifyTime(cert) { x509.verifyTime = function verifyTime(cert) {
var time = cert.tbs.validity; var time = cert.tbs.validity;
var now = Math.floor(Date.now() / 1000); var now = util.now();
return now > time.notBefore && now < time.notAfter; return now > time.notBefore && now < time.notAfter;
}; };
x509.signSubject = function signSubject(hash, msg, key, chain) { x509.getSigningKey = function getSigningKey(key, chain) {
var cert, pub, curve; var cert, pub, curve;
assert(chain.length !== 0, 'No chain available.'); assert(chain.length !== 0, 'No chain available.');
@ -210,10 +211,20 @@ x509.signSubject = function signSubject(hash, msg, key, chain) {
}; };
} }
return pk.sign(hash, msg, key); return key;
}; };
x509.verifySubject = function verifySubject(hash, msg, sig, chain) { x509.signSubject = function signSubject(hash, msg, key, chain) {
var priv = x509.getSigningKey(key, chain);
return pk.sign(hash, msg, priv);
};
x509.signSubjectAsync = co(function* signSubjectAsync(hash, msg, key, chain) {
var priv = x509.getSigningKey(key, chain);
return yield pk.signAsync(hash, msg, priv);
});
x509.getVerifyKey = function getVerifyKey(chain) {
var cert, key; var cert, key;
if (chain.length === 0) if (chain.length === 0)
@ -229,27 +240,82 @@ x509.verifySubject = function verifySubject(hash, msg, sig, chain) {
if (!key) if (!key)
return false; return false;
return key;
};
x509.verifySubject = function verifySubject(hash, msg, sig, chain) {
var key = x509.getVerifyKey(chain);
return pk.verify(hash, msg, sig, key); return pk.verify(hash, msg, sig, key);
}; };
x509.verifyChain = function verifyChain(chain) { x509.verifySubjectAsync = co(function* verifySubjectAsync(hash, msg, sig, chain) {
var key = x509.getVerifyKey(chain);
return yield pk.verifyAsync(hash, msg, sig, key);
});
x509.parseChain = function parseChain(chain) {
var certs = [];
var i, cert;
for (i = 0; i < chain.length; i++) {
cert = x509.parse(chain[i]);
if (!cert)
return;
certs.push(cert);
}
return certs;
};
x509.verifyTimes = function verifyTimes(chain) {
var i, cert;
for (i = 0; i < chain.length; i++) {
cert = chain[i];
if (!x509.verifyTime(cert))
return false;
}
return true;
};
x509.verifyTrust = function verifyTrust(chain) {
var i, cert;
// If trust hasn't been
// setup, just return.
if (x509.allowUntrusted)
return true;
// Make sure we trust one
// of the certs in the chain.
for (i = 0; i < chain.length; i++) {
cert = chain[i];
// If any certificate in the chain
// is trusted, assume we also trust
// the parent.
if (x509.isTrusted(cert))
return true;
}
// No trusted certs present.
return false;
};
x509.verifyChain = function verifyChain(certs) {
var chain = x509.parseChain(certs);
var i, child, parent, alg, key, sig, msg; var i, child, parent, alg, key, sig, msg;
chain = chain.slice(); if (!chain)
return false;
// Parse certificates and // Parse certificates and
// check validity time. // check validity time.
for (i = 0; i < chain.length; i++) { if (!x509.verifyTimes(chain))
child = x509.parse(chain[i]); return false;
if (!child)
return false;
chain[i] = child;
if (!x509.verifyTime(child))
return false;
}
// Verify signatures. // Verify signatures.
for (i = 1; i < chain.length; i++) { for (i = 1; i < chain.length; i++) {
@ -271,26 +337,47 @@ x509.verifyChain = function verifyChain(chain) {
return false; return false;
} }
// If trust hasn't been // Make sure we trust one
// setup, just return. // of the certs in the chain.
if (x509.allowUntrusted) return x509.verifyTrust(chain);
return true; };
x509.verifyChainAsync = co(function* verifyChainAsync(certs) {
var chain = x509.parseChain(certs);
var i, child, parent, alg, key, sig, msg;
if (!chain)
return false;
// Parse certificates and
// check validity time.
if (!x509.verifyTimes(chain))
return false;
// Verify signatures.
for (i = 1; i < chain.length; i++) {
child = chain[i - 1];
parent = chain[i];
alg = x509.getSigAlgorithm(child);
msg = child.tbs.raw;
sig = child.sig;
key = x509.getPublicKey(parent);
if (!alg || !alg.hash)
return false;
if (!key)
return false;
if (!(yield pk.verifyAsync(alg.hash, msg, sig, key)))
return false;
}
// Make sure we trust one // Make sure we trust one
// of the certs in the chain. // of the certs in the chain.
for (i = 0; i < chain.length; i++) { return x509.verifyTrust(chain);
child = chain[i]; });
// If any certificate in the chain
// is trusted, assume we also trust
// the parent.
if (x509.isTrusted(child))
return true;
}
// No trusted certs present.
return false;
};
function isHash(data) { function isHash(data) {
if (typeof data === 'string') if (typeof data === 'string')

View File

@ -1318,6 +1318,8 @@ Chain.prototype._add = co(function* add(block) {
'error parsing message', 'error parsing message',
100); 100);
} }
if (util.isBrowser)
yield block.cacheHashes();
} }
// Update the block height early // Update the block height early

View File

@ -33,14 +33,22 @@ function AESKey(key, bits) {
this.userKey = key; this.userKey = key;
this.bits = bits; this.bits = bits;
if (this.bits === 128) switch (this.bits) {
this.rounds = 10; case 128:
else if (this.bits === 192) this.rounds = 10;
this.rounds = 12; break;
else if (this.bits === 256) case 192:
this.rounds = 14; this.rounds = 12;
else break;
throw new Error('Bad key size.'); case 256:
this.rounds = 14;
break;
default:
throw new Error('Bad key size.');
}
assert(Buffer.isBuffer(key));
assert(key.length === this.bits / 8);
this.decryptKey = null; this.decryptKey = null;
this.encryptKey = null; this.encryptKey = null;
@ -688,6 +696,8 @@ AES.ecb = {};
*/ */
AES.ecb.encrypt = function encrypt(data, key) { AES.ecb.encrypt = function encrypt(data, key) {
assert(Buffer.isBuffer(data));
assert(key.length === 32);
return AES.encrypt(data, key, null, 256, 'ecb'); return AES.encrypt(data, key, null, 256, 'ecb');
}; };
@ -699,6 +709,8 @@ AES.ecb.encrypt = function encrypt(data, key) {
*/ */
AES.ecb.decrypt = function decrypt(data, key) { AES.ecb.decrypt = function decrypt(data, key) {
assert(Buffer.isBuffer(data));
assert(key.length === 32);
return AES.decrypt(data, key, null, 256, 'ecb'); return AES.decrypt(data, key, null, 256, 'ecb');
}; };
@ -717,6 +729,9 @@ AES.cbc = {};
*/ */
AES.cbc.encrypt = function encrypt(data, key, iv) { AES.cbc.encrypt = function encrypt(data, key, iv) {
assert(Buffer.isBuffer(data));
assert(key.length === 32);
assert(iv.length === 16);
return AES.encrypt(data, key, iv, 256, 'cbc'); return AES.encrypt(data, key, iv, 256, 'cbc');
}; };
@ -729,6 +744,9 @@ AES.cbc.encrypt = function encrypt(data, key, iv) {
*/ */
AES.cbc.decrypt = function decrypt(data, key, iv) { AES.cbc.decrypt = function decrypt(data, key, iv) {
assert(Buffer.isBuffer(data));
assert(key.length === 32);
assert(iv.length === 16);
return AES.decrypt(data, key, iv, 256, 'cbc'); return AES.decrypt(data, key, iv, 256, 'cbc');
}; };

View File

@ -4,57 +4,168 @@
* https://github.com/bcoin-org/bcoin * https://github.com/bcoin-org/bcoin
*/ */
/* jshint worker: true */
'use strict'; 'use strict';
var assert = require('assert'); var assert = require('assert');
var hashjs = require('hash.js'); var hashjs = require('hash.js');
var util = require('../utils/util');
var aes = require('./aes'); var aes = require('./aes');
var global = util.global;
var crypto = global.crypto || global.msCrypto || {};
var subtle = crypto.subtle && crypto.subtle.importKey ? crypto.subtle : {};
var backend = exports; var backend = exports;
var global, crypto, subtle;
global = (function() { /*
if (typeof window !== 'undefined') * Hashing
return window; */
if (typeof self !== 'undefined') backend.hash = function _hash(alg, data) {
return self; var hash = hashjs[alg];
assert(hash != null, 'Unknown algorithm.');
throw new Error('No global found.'); return new Buffer(hash().update(data).digest());
})();
crypto = global.crypto || global.msCrypto;
subtle = crypto ? crypto.subtle : null;
backend.hash = function hash(alg, data) {
return new Buffer(hashjs[alg]().update(data).digest());
}; };
backend.hmac = function hmac(alg, data, salt) { backend.ripemd160 = function ripemd160(data) {
return backend.hash('ripemd160', data);
};
backend.sha1 = function sha1(data) {
return backend.hash('sha1', data);
};
backend.sha256 = function sha256(data) {
return backend.hash('sha256', data);
};
backend.hash160 = function hash160(data) {
return backend.ripemd160(backend.sha256(data));
};
backend.hash256 = function hash256(data) {
return backend.sha256(backend.sha256(data));
};
backend.hmac = function _hmac(alg, data, key) {
var hash = hashjs[alg]; var hash = hashjs[alg];
var hmac; var hmac;
assert(hash != null, 'Unknown algorithm.'); assert(hash != null, 'Unknown algorithm.');
hmac = hashjs.hmac(hash, salt); hmac = hashjs.hmac(hash, key);
return new Buffer(hmac.update(data).digest()); return new Buffer(hmac.update(data).digest());
}; };
backend.pbkdf2 = null; backend.hashAsync = function hashAsync(alg, data) {
var name = backend.getHash(alg);
var result;
if (!name) {
try {
result = backend.hash(alg, data);
} catch (e) {
return Promise.reject(e);
}
return Promise.resolve(result);
}
return subtle.digest(name, data).then(function(hash) {
return new Buffer(hash);
});
};
if (!subtle.digest)
backend.hashAsync = util.promisify(backend.hash);
backend.hash256Async = function hash256Async(data) {
return backend.hashAsync('sha256', data).then(function(hash) {
return backend.hashAsync('sha256', hash);
});
};
backend.hmacAsync = function _hmacAsync(alg, data, key) {
var name = backend.getHash(alg);
var use = ['sign'];
var algo, promise, result;
if (!name) {
try {
result = backend.hmac(alg, data, key);
} catch (e) {
return Promise.reject(e);
}
return Promise.resolve(result);
}
algo = {
name: 'HMAC',
hash: name
};
promise = subtle.importKey('raw', key, algo, true, use);
return promise.then(function(key) {
return subtle.sign('HMAC', key, data);
}).then(function(data) {
return new Buffer(data);
});
};
if (!subtle.sign)
backend.hmacAsync = util.promisify(backend.hmac);
/*
* Key Derivation
*/
backend.pbkdf2 = function pbkdf2(key, salt, iter, len, alg) {
var size = backend.hash(alg, new Buffer(0)).length;
var blocks = Math.ceil(len / size);
var out = new Buffer(len);
var buf = new Buffer(salt.length + 4);
var block = new Buffer(size);
var pos = 0;
var i, j, k, mac;
salt.copy(buf, 0);
for (i = 0; i < blocks; i++) {
buf.writeUInt32BE(i + 1, salt.length, true);
mac = backend.hmac(alg, buf, key);
mac.copy(block, 0);
for (j = 1; j < iter; j++) {
mac = backend.hmac(alg, mac, key);
for (k = 0; k < size; k++)
block[k] ^= mac[k];
}
block.copy(out, pos);
pos += size;
}
return out;
};
backend.pbkdf2Async = function pbkdf2Async(key, salt, iter, len, alg) { backend.pbkdf2Async = function pbkdf2Async(key, salt, iter, len, alg) {
var algo = { name: 'PBKDF2' }; var algo = { name: 'PBKDF2' };
var use = ['deriveBits']; var use = ['deriveBits'];
var name = backend.getHash(alg);
var length = len * 8; var length = len * 8;
var options, promise; var options, promise, result;
if (!name) {
try {
result = backend.pbkdf2(key, salt, iter, len, alg);
} catch (e) {
return Promise.reject(e);
}
return Promise.resolve(result);
}
options = { options = {
name: 'PBKDF2', name: 'PBKDF2',
salt: salt, salt: salt,
iterations: iter, iterations: iter,
hash: getHash(alg) hash: name
}; };
promise = subtle.importKey('raw', key, algo, false, use); promise = subtle.importKey('raw', key, algo, false, use);
@ -66,8 +177,12 @@ backend.pbkdf2Async = function pbkdf2Async(key, salt, iter, len, alg) {
}); });
}; };
if (!subtle || !subtle.importKey || !subtle.deriveBits) if (!subtle.deriveBits)
backend.pbkdf2Async = null; backend.pbkdf2Async = util.promisify(backend.pbkdf2);
/*
* Ciphers
*/
backend.encipher = function encipher(data, key, iv) { backend.encipher = function encipher(data, key, iv) {
return aes.cbc.encrypt(data, key, iv); return aes.cbc.encrypt(data, key, iv);
@ -81,13 +196,53 @@ backend.decipher = function decipher(data, key, iv) {
} }
}; };
backend.encipherAsync = function encipherAsync(data, key, iv) {
var algo = { name: 'AES-CBC' };
var use = ['encrypt'];
var options = { name: 'AES-CBC', iv: iv };
var promise;
promise = subtle.importKey('raw', key, algo, false, use);
return promise.then(function(key) {
return subtle.encrypt(options, key, data);
}).then(function(result) {
return new Buffer(result);
});
};
if (!subtle.encrypt)
backend.encipherAsync = util.promisify(backend.encipher);
backend.decipherAsync = function decipherAsync(data, key, iv) {
var algo = { name: 'AES-CBC' };
var use = ['decrypt'];
var options = { name: 'AES-CBC', iv: iv };
var promise;
promise = subtle.importKey('raw', key, algo, false, use);
return promise.then(function(key) {
return subtle.decrypt(options, key, data);
}).then(function(result) {
return new Buffer(result);
});
};
if (!subtle.decrypt)
backend.decipherAsync = util.promisify(backend.decipher);
/*
* Misc
*/
backend.randomBytes = function randomBytes(n) { backend.randomBytes = function randomBytes(n) {
var data = new Uint8Array(n); var data = new Uint8Array(n);
crypto.getRandomValues(data); crypto.getRandomValues(data);
return new Buffer(data.buffer); return new Buffer(data.buffer);
}; };
if (!crypto || !crypto.getRandomValues) { if (!crypto.getRandomValues) {
// Out of luck here. Use bad randomness for now. // Out of luck here. Use bad randomness for now.
backend.randomBytes = function randomBytes(n) { backend.randomBytes = function randomBytes(n) {
var data = new Buffer(n); var data = new Buffer(n);
@ -100,7 +255,7 @@ if (!crypto || !crypto.getRandomValues) {
}; };
} }
function getHash(name) { backend.getHash = function getHash(name) {
switch (name) { switch (name) {
case 'sha1': case 'sha1':
return 'SHA-1'; return 'SHA-1';
@ -111,6 +266,9 @@ function getHash(name) {
case 'sha512': case 'sha512':
return 'SHA-512'; return 'SHA-512';
default: default:
throw new Error('Unknown hash.'); return null;
} }
} };
backend.crypto = crypto;
backend.subtle = subtle;

View File

@ -7,31 +7,78 @@
'use strict'; 'use strict';
var util = require('../utils/util'); var util = require('../utils/util');
var co = require('../utils/co');
var crypto = require('crypto'); var crypto = require('crypto');
var native = require('../utils/native').binding;
var backend = exports; var backend = exports;
if (!crypto.pbkdf2Sync)
throw new Error('This modules requires node.js v0.11.0 or above.');
/*
* Hashing
*/
backend.hash = function hash(alg, data) { backend.hash = function hash(alg, data) {
return crypto.createHash(alg).update(data).digest(); return crypto.createHash(alg).update(data).digest();
}; };
backend.hmac = function hmac(alg, data, salt) { backend.ripemd160 = function ripemd160(data) {
var hmac = crypto.createHmac(alg, salt); return backend.hash('ripemd160', data);
};
backend.sha1 = function sha1(data) {
return backend.hash('sha1', data);
};
backend.sha256 = function sha256(data) {
return backend.hash('sha256', data);
};
backend.hash160 = function hash160(data) {
return backend.ripemd160(backend.sha256(data));
};
backend.hash256 = function hash256(data) {
return backend.sha256(backend.sha256(data));
};
backend.hmac = function hmac(alg, data, key) {
var hmac = crypto.createHmac(alg, key);
return hmac.update(data).digest(); return hmac.update(data).digest();
}; };
if (native) {
backend.hash = native.hash;
backend.hmac = native.hmac;
backend.ripemd160 = native.ripemd160;
backend.sha1 = native.sha1;
backend.sha256 = native.sha256;
backend.hash160 = native.hash160;
backend.hash256 = native.hash256;
}
backend.hashAsync = util.promisify(backend.hash);
backend.hash256Async = util.promisify(backend.hash256);
backend.hmacAsync = util.promisify(backend.hmac);
/*
* Key Derivation
*/
backend.pbkdf2 = function pbkdf2(key, salt, iter, len, alg) { backend.pbkdf2 = function pbkdf2(key, salt, iter, len, alg) {
return crypto.pbkdf2Sync(key, salt, iter, len, alg); return crypto.pbkdf2Sync(key, salt, iter, len, alg);
}; };
if (!crypto.pbkdf2Sync) backend.pbkdf2Async = function pbkdf2Async(key, salt, iter, len, alg) {
backend.pbkdf2 = null; return new Promise(function(resolve, reject) {
crypto.pbkdf2(key, salt, iter, len, alg, co.wrap(resolve, reject));
backend.pbkdf2Async = function pbkdf2Async(key, salt, iter, len, alg, callback) { });
return crypto.pbkdf2(key, salt, iter, len, alg, callback);
}; };
if (!crypto.pbkdf2) /*
backend.pbkdf2Async = null; * Ciphers
*/
backend.encipher = function encipher(data, key, iv) { backend.encipher = function encipher(data, key, iv) {
var cipher = crypto.createCipheriv('aes-256-cbc', key, iv); var cipher = crypto.createCipheriv('aes-256-cbc', key, iv);
@ -47,4 +94,16 @@ backend.decipher = function decipher(data, key, iv) {
} }
}; };
if (native) {
backend.encipher = native.encipher;
backend.decipher = native.decipher;
}
backend.encipherAsync = util.promisify(backend.encipher);
backend.decipherAsync = util.promisify(backend.decipher);
/*
* Misc
*/
backend.randomBytes = crypto.randomBytes; backend.randomBytes = crypto.randomBytes;

View File

@ -7,114 +7,111 @@
'use strict'; 'use strict';
var assert = require('assert'); var backend = require('./backend');
var native = require('../utils/native').binding;
var scrypt = require('./scrypt'); var scrypt = require('./scrypt');
var scryptAsync = require('./scrypt-async'); var scryptAsync = require('./scrypt-async');
var co = require('../utils/co');
var native = require('../utils/native').binding;
var backend = require('./backend');
var crypto = exports; var crypto = exports;
/** /**
* Hash with chosen algorithm. * Hash with chosen algorithm.
* @function
* @param {String} alg * @param {String} alg
* @param {Buffer} data * @param {Buffer} data
* @returns {Buffer} * @returns {Buffer}
*/ */
crypto.hash = function _hash(alg, data) { crypto.hash = backend.hash;
return backend.hash(alg, data);
};
if (native) /**
crypto.hash = native.hash; * Hash with chosen algorithm (async).
* @function
* @param {String} alg
* @param {Buffer} data
* @returns {Buffer}
*/
crypto.hashAsync = backend.hashAsync;
/** /**
* Hash with ripemd160. * Hash with ripemd160.
* @function
* @param {Buffer} data * @param {Buffer} data
* @returns {Buffer} * @returns {Buffer}
*/ */
crypto.ripemd160 = function ripemd160(data) { crypto.ripemd160 = backend.ripemd160;
return crypto.hash('ripemd160', data);
};
/** /**
* Hash with sha1. * Hash with sha1.
* @function
* @param {Buffer} data * @param {Buffer} data
* @returns {Buffer} * @returns {Buffer}
*/ */
crypto.sha1 = function sha1(data) { crypto.sha1 = backend.sha1;
return crypto.hash('sha1', data);
};
/** /**
* Hash with sha256. * Hash with sha256.
* @function
* @param {Buffer} data * @param {Buffer} data
* @returns {Buffer} * @returns {Buffer}
*/ */
crypto.sha256 = function sha256(data) { crypto.sha256 = backend.sha256;
return crypto.hash('sha256', data);
};
if (native)
crypto.sha256 = native.sha256;
/** /**
* Hash with sha256 and ripemd160 (OP_HASH160). * Hash with sha256 and ripemd160 (OP_HASH160).
* @function
* @param {Buffer} data * @param {Buffer} data
* @returns {Buffer} * @returns {Buffer}
*/ */
crypto.hash160 = function hash160(data) { crypto.hash160 = backend.hash160;
return crypto.ripemd160(crypto.sha256(data));
};
if (native)
crypto.hash160 = native.hash160;
/** /**
* Hash with sha256 twice (OP_HASH256). * Hash with sha256 twice (OP_HASH256).
* @function
* @param {Buffer} data * @param {Buffer} data
* @returns {Buffer} * @returns {Buffer}
*/ */
crypto.hash256 = function hash256(data) { crypto.hash256 = backend.hash256;
return crypto.sha256(crypto.sha256(data));
};
if (native)
crypto.hash256 = native.hash256;
/** /**
* Create a sha256 checksum (common in bitcoin). * Hash with sha256 twice (async).
* @function
* @param {Buffer} data * @param {Buffer} data
* @returns {Buffer} * @returns {Buffer}
*/ */
crypto.checksum = function checksum(data) { crypto.hash256Async = backend.hash256Async;
return crypto.hash256(data).slice(0, 4);
};
/** /**
* Create an HMAC. * Create an HMAC.
* @function
* @param {String} alg * @param {String} alg
* @param {Buffer} data * @param {Buffer} data
* @param {Buffer} salt * @param {Buffer} key
* @returns {Buffer} HMAC * @returns {Buffer} HMAC
*/ */
crypto.hmac = function hmac(alg, data, salt) { crypto.hmac = backend.hmac;
return backend.hmac(alg, data, salt);
};
if (native) /**
crypto.hmac = native.hmac; * Create an HMAC (async).
* @function
* @param {String} alg
* @param {Buffer} data
* @param {Buffer} key
* @returns {Buffer} HMAC
*/
crypto.hmacAsync = backend.hmacAsync;
/** /**
* Perform key derivation using PBKDF2. * Perform key derivation using PBKDF2.
* @function
* @param {Buffer} key * @param {Buffer} key
* @param {Buffer} salt * @param {Buffer} salt
* @param {Number} iter * @param {Number} iter
@ -123,21 +120,11 @@ if (native)
* @returns {Buffer} * @returns {Buffer}
*/ */
crypto.pbkdf2 = function pbkdf2(key, salt, iter, len, alg) { crypto.pbkdf2 = backend.pbkdf2;
if (typeof key === 'string')
key = new Buffer(key, 'utf8');
if (typeof salt === 'string')
salt = new Buffer(salt, 'utf8');
if (backend.pbkdf2)
return backend.pbkdf2(key, salt, iter, len, alg);
return crypto._pbkdf2(key, salt, iter, len, alg);
};
/** /**
* Execute pbkdf2 asynchronously. * Execute pbkdf2 asynchronously.
* @function
* @param {Buffer} key * @param {Buffer} key
* @param {Buffer} salt * @param {Buffer} salt
* @param {Number} iter * @param {Number} iter
@ -146,32 +133,11 @@ crypto.pbkdf2 = function pbkdf2(key, salt, iter, len, alg) {
* @returns {Promise} * @returns {Promise}
*/ */
crypto.pbkdf2Async = function pbkdf2Async(key, salt, iter, len, alg) { crypto.pbkdf2Async = backend.pbkdf2Async;
var result;
if (typeof key === 'string')
key = new Buffer(key, 'utf8');
if (typeof salt === 'string')
salt = new Buffer(salt, 'utf8');
if (backend.pbkdf2Async) {
return new Promise(function(resolve, reject) {
backend.pbkdf2Async(key, salt, iter, len, alg, co.wrap(resolve, reject));
});
}
try {
result = crypto._pbkdf2(key, salt, iter, len, alg);
} catch (e) {
return Promise.reject(e);
}
return Promise.resolve(result);
};
/** /**
* Perform key derivation using scrypt. * Perform key derivation using scrypt.
* @function
* @param {Buffer} passwd * @param {Buffer} passwd
* @param {Buffer} salt * @param {Buffer} salt
* @param {Number} N * @param {Number} N
@ -181,18 +147,11 @@ crypto.pbkdf2Async = function pbkdf2Async(key, salt, iter, len, alg) {
* @returns {Buffer} * @returns {Buffer}
*/ */
crypto.scrypt = function _scrypt(passwd, salt, N, r, p, len) { crypto.scrypt = scrypt;
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. * Execute scrypt asynchronously.
* @function
* @param {Buffer} passwd * @param {Buffer} passwd
* @param {Buffer} salt * @param {Buffer} salt
* @param {Number} N * @param {Number} N
@ -202,66 +161,18 @@ crypto.scrypt = function _scrypt(passwd, salt, N, r, p, len) {
* @returns {Promise} * @returns {Promise}
*/ */
crypto.scryptAsync = function _scrypt(passwd, salt, N, r, p, len) { crypto.scryptAsync = scryptAsync;
if (typeof passwd === 'string')
passwd = new Buffer(passwd, 'utf8');
if (typeof salt === 'string')
salt = new Buffer(salt, 'utf8');
return new Promise(function(resolve, reject) {
scryptAsync(passwd, salt, N, r, p, len, co.wrap(resolve, reject));
});
};
/**
* Perform key derivation using PBKDF2.
* @private
* @param {Buffer} key
* @param {Buffer} salt
* @param {Number} iter
* @param {Number} len
* @param {String} alg
* @returns {Buffer}
*/
crypto._pbkdf2 = function pbkdf2(key, salt, iter, len, alg) {
var size = crypto.hash(alg, new Buffer(0)).length;
var blocks = Math.ceil(len / size);
var out = new Buffer(len);
var buf = new Buffer(salt.length + 4);
var block = new Buffer(size);
var pos = 0;
var i, j, k, mac;
salt.copy(buf, 0);
for (i = 0; i < blocks; i++) {
buf.writeUInt32BE(i + 1, salt.length, true);
mac = crypto.hmac(alg, buf, key);
mac.copy(block, 0);
for (j = 1; j < iter; j++) {
mac = crypto.hmac(alg, mac, key);
for (k = 0; k < size; k++)
block[k] ^= mac[k];
}
block.copy(out, pos);
pos += size;
}
return out;
};
/** /**
* Perform hkdf extraction. * Perform hkdf extraction.
* @param {Buffer} ikm * @param {Buffer} ikm
* @param {Buffer} salt * @param {Buffer} key
* @param {String} alg * @param {String} alg
* @returns {Buffer} * @returns {Buffer}
*/ */
crypto.hkdfExtract = function hkdfExtract(ikm, salt, alg) { crypto.hkdfExtract = function hkdfExtract(ikm, key, alg) {
return crypto.hmac(alg, ikm, salt); return crypto.hmac(alg, ikm, key);
}; };
/** /**
@ -424,38 +335,47 @@ if (native)
/** /**
* Encrypt with aes-256-cbc. * Encrypt with aes-256-cbc.
* @function
* @param {Buffer} data * @param {Buffer} data
* @param {Buffer} key - 256 bit key. * @param {Buffer} key - 256 bit key.
* @param {Buffer} iv - 128 bit initialization vector. * @param {Buffer} iv - 128 bit initialization vector.
* @returns {Buffer} * @returns {Buffer}
*/ */
crypto.encipher = function encipher(data, key, iv) { crypto.encipher = backend.encipher;
assert(Buffer.isBuffer(data));
assert(Buffer.isBuffer(key));
assert(Buffer.isBuffer(iv));
assert(key.length === 32);
assert(iv.length === 16);
return backend.encipher(data, key, iv); /**
}; * Encrypt with aes-256-cbc (async).
* @function
* @param {Buffer} data
* @param {Buffer} key - 256 bit key.
* @param {Buffer} iv - 128 bit initialization vector.
* @returns {Promise}
*/
crypto.encipherAsync = backend.encipherAsync;
/** /**
* Decrypt with aes-256-cbc. * Decrypt with aes-256-cbc.
* @function
* @param {Buffer} data * @param {Buffer} data
* @param {Buffer} key - 256 bit key. * @param {Buffer} key - 256 bit key.
* @param {Buffer} iv - 128 bit initialization vector. * @param {Buffer} iv - 128 bit initialization vector.
* @returns {Buffer} * @returns {Buffer}
*/ */
crypto.decipher = function decipher(data, key, iv) { crypto.decipher = backend.decipher;
assert(Buffer.isBuffer(data));
assert(Buffer.isBuffer(key)); /**
assert(Buffer.isBuffer(iv)); * Decrypt with aes-256-cbc (async).
assert(key.length === 32); * @function
assert(iv.length === 16); * @param {Buffer} data
return backend.decipher(data, key, iv); * @param {Buffer} key - 256 bit key.
}; * @param {Buffer} iv - 128 bit initialization vector.
* @returns {Promise}
*/
crypto.decipherAsync = backend.decipherAsync;
/** /**
* memcmp in constant time (can only return true or false). * memcmp in constant time (can only return true or false).
@ -488,21 +408,6 @@ crypto.ccmp = function ccmp(a, b) {
return res === 0; return res === 0;
}; };
/**
* Compare two bytes in constant time.
* @param {Number} a
* @param {Number} b
* @returns {Boolean}
*/
crypto.ceq = function ceq(a, b) {
var r = ~(a ^ b) & 0xff;
r &= r >>> 4;
r &= r >>> 2;
r &= r >>> 1;
return r === 1;
};
/** /**
* A maybe-secure memzero. * A maybe-secure memzero.
* @param {Buffer} data * @param {Buffer} data

View File

@ -9,7 +9,7 @@
var assert = require('assert'); var assert = require('assert');
var util = require('../utils/util'); var util = require('../utils/util');
var crypto = require('./crypto'); var backend = require('./backend');
var secp256k1 = require('secp256k1'); var secp256k1 = require('secp256k1');
/* /*
@ -40,7 +40,7 @@ ec.generatePrivateKey = function generatePrivateKey() {
var priv; var priv;
do { do {
priv = crypto.randomBytes(32); priv = backend.randomBytes(32);
} while (!secp256k1.privateKeyVerify(priv)); } while (!secp256k1.privateKeyVerify(priv));
return priv; return priv;

View File

@ -4,13 +4,15 @@ var crypto = require('./crypto');
exports.crypto = crypto; exports.crypto = crypto;
exports.hash = crypto.hash; exports.hash = crypto.hash;
exports.hashAsync = crypto.hashAsync;
exports.ripemd160 = crypto.ripemd160; exports.ripemd160 = crypto.ripemd160;
exports.sha1 = crypto.sha1; exports.sha1 = crypto.sha1;
exports.sha256 = crypto.sha256; exports.sha256 = crypto.sha256;
exports.hash160 = crypto.hash160; exports.hash160 = crypto.hash160;
exports.hash256 = crypto.hash256; exports.hash256 = crypto.hash256;
exports.checksum = crypto.checksum; exports.hash256Async = crypto.hash256Async;
exports.hmac = crypto.hmac; exports.hmac = crypto.hmac;
exports.hmacAsync = crypto.hmacAsync;
exports.pbkdf2 = crypto.pbkdf2; exports.pbkdf2 = crypto.pbkdf2;
exports.pbkdf2Async = crypto.pbkdf2Async; exports.pbkdf2Async = crypto.pbkdf2Async;
exports.scrypt = crypto.scrypt; exports.scrypt = crypto.scrypt;
@ -24,7 +26,6 @@ exports.checkMerkleBranch = crypto.checkMerkleBranch;
exports.encipher = crypto.encipher; exports.encipher = crypto.encipher;
exports.decipher = crypto.decipher; exports.decipher = crypto.decipher;
exports.ccmp = crypto.ccmp; exports.ccmp = crypto.ccmp;
exports.ceq = crypto.ceq;
exports.cleanse = crypto.cleanse; exports.cleanse = crypto.cleanse;
exports.randomBytes = crypto.randomBytes; exports.randomBytes = crypto.randomBytes;
exports.randomInt = crypto.randomInt; exports.randomInt = crypto.randomInt;

View File

@ -9,8 +9,11 @@
var assert = require('assert'); var assert = require('assert');
var BN = require('bn.js'); var BN = require('bn.js');
var ASN1 = require('../utils/asn1'); var ASN1 = require('../utils/asn1');
var util = require('../utils/util');
var co = require('../utils/co');
var elliptic = require('elliptic'); var elliptic = require('elliptic');
var crypto = require('./crypto'); var backend = require('./backend');
var subtle = backend.subtle;
var dsa, rsa, ecdsa; var dsa, rsa, ecdsa;
/* /*
@ -23,10 +26,14 @@ dsa.verify = function verify(alg, msg, sig, key, params) {
throw new Error('DSA not implemented.'); throw new Error('DSA not implemented.');
}; };
dsa.verifyAsync = util.promisify(dsa.verify);
dsa.sign = function sign(alg, msg, key, params) { dsa.sign = function sign(alg, msg, key, params) {
throw new Error('DSA not implemented.'); throw new Error('DSA not implemented.');
}; };
dsa.signAsync = util.promisify(dsa.sign);
/* /*
* RSA * RSA
*/ */
@ -52,7 +59,7 @@ rsa.verify = function verify(alg, msg, sig, key) {
if (!prefix) if (!prefix)
throw new Error('Unknown PKCS prefix.'); throw new Error('Unknown PKCS prefix.');
hash = crypto.hash(alg, msg); hash = backend.hash(alg, msg);
len = prefix.length + hash.length; len = prefix.length + hash.length;
pub = ASN1.parseRSAPublic(key); pub = ASN1.parseRSAPublic(key);
@ -66,14 +73,14 @@ rsa.verify = function verify(alg, msg, sig, key) {
m = rsa.encrypt(N, e, sig); m = rsa.encrypt(N, e, sig);
em = leftpad(m, k); em = leftpad(m, k);
ok = crypto.ceq(em[0], 0x00); ok = ceq(em[0], 0x00);
ok &= crypto.ceq(em[1], 0x01); ok &= ceq(em[1], 0x01);
ok &= crypto.ccmp(em.slice(k - hash.length, k), hash); ok &= backend.ccmp(em.slice(k - hash.length, k), hash);
ok &= crypto.ccmp(em.slice(k - len, k - hash.length), prefix); ok &= backend.ccmp(em.slice(k - len, k - hash.length), prefix);
ok &= crypto.ceq(em[k - len - 1], 0x00); ok &= ceq(em[k - len - 1], 0x00);
for (i = 2; i < k - len - 1; i++) for (i = 2; i < k - len - 1; i++)
ok &= crypto.ceq(em[i], 0xff); ok &= ceq(em[i], 0xff);
return ok === 1; return ok === 1;
}; };
@ -86,7 +93,7 @@ rsa.sign = function sign(alg, msg, key) {
if (!prefix) if (!prefix)
throw new Error('Unknown PKCS prefix.'); throw new Error('Unknown PKCS prefix.');
hash = crypto.hash(alg, msg); hash = backend.hash(alg, msg);
len = prefix.length + hash.length; len = prefix.length + hash.length;
priv = ASN1.parseRSAPrivate(key); priv = ASN1.parseRSAPrivate(key);
@ -110,6 +117,82 @@ rsa.sign = function sign(alg, msg, key) {
return rsa.decrypt(N, D, em); return rsa.decrypt(N, D, em);
}; };
rsa.verifyAsync = co(function* verifyAsync(alg, msg, sig, key) {
var use = ['verify'];
var name = backend.getHash(alg);
var pub, data, algo, ckey;
if (!name)
return rsa.verify(alg, msg, sig, key);
pub = ASN1.parseRSAPublic(key);
data = {
kty: 'RSA',
n: toBase64(pub.modulus),
e: toBase64(pub.publicExponent),
alg: 'RS256',
ext: true
};
algo = {
name: 'RSASSA-PKCS1-v1_5',
hash: { name: name }
};
ckey = yield subtle.importKey('jwk', data, algo, false, use);
algo = {
name: 'RSASSA-PKCS1-v1_5',
};
return yield subtle.verify(algo, ckey, sig, msg);
});
if (!subtle.verify)
rsa.verifyAsync = util.promisify(rsa.verify);
rsa.signAsync = co(function* signAsync(alg, msg, key) {
var use = ['sign'];
var name = backend.getHash(alg);
var pub, data, algo, ckey;
if (!name)
return rsa.sign(alg, msg, key);
pub = ASN1.parseRSAPrivate(key);
data = {
kty: 'RSA',
n: toBase64(pub.modulus),
e: toBase64(pub.publicExponent),
d: toBase64(pub.privateExponent),
p: toBase64(pub.prime1),
q: toBase64(pub.prime2),
dp: toBase64(pub.exponent1),
dq: toBase64(pub.exponent2),
qi: toBase64(pub.coefficient),
alg: 'RS256',
ext: true
};
algo = {
name: 'RSASSA-PKCS1-v1_5',
hash: { name: name }
};
ckey = yield subtle.importKey('jwk', data, algo, false, use);
algo = {
name: 'RSASSA-PKCS1-v1_5',
};
return yield subtle.sign(algo, ckey, msg);
});
if (!subtle.sign)
rsa.signAsync = util.promisify(rsa.sign);
rsa.decrypt = function decrypt(N, D, m) { rsa.decrypt = function decrypt(N, D, m) {
var c = new BN(m); var c = new BN(m);
@ -137,28 +220,91 @@ rsa.encrypt = function encrypt(N, e, m) {
ecdsa = {}; ecdsa = {};
ecdsa.verify = function verify(curve, msg, alg, key, sig) { ecdsa.verify = function verify(curve, alg, msg, key, sig) {
var ec, hash; var ec, hash;
assert(curve, 'No curve selected.'); assert(curve, 'No curve selected.');
ec = elliptic.ec(curve); ec = elliptic.ec(curve);
hash = crypto.hash(alg, msg); hash = backend.hash(alg, msg);
return ec.verify(hash, sig, key); return ec.verify(hash, sig, key);
}; };
ecdsa.sign = function sign(curve, msg, alg, key) { ecdsa.sign = function sign(curve, alg, msg, key) {
var ec, hash; var ec, hash;
assert(curve, 'No curve selected.'); assert(curve, 'No curve selected.');
ec = elliptic.ec(curve); ec = elliptic.ec(curve);
hash = crypto.hash(alg, msg); hash = backend.hash(alg, msg);
return new Buffer(ec.sign(hash, key)); return new Buffer(ec.sign(hash, key));
}; };
ecdsa.verifyAsync = co(function* verifyAsync(curve, alg, msg, sig, key) {
var use = ['verify'];
var name = backend.getHash(alg);
var curveName = getCurve(curve);
var pub, data, algo, ckey;
if (!name || !curveName)
return ecdsa.verify(curve, alg, msg, sig, key);
pub = parseECPublic(key, curve);
data = {
kty: 'EC',
x: toBase64(pub.x),
y: toBase64(pub.y),
ext: true
};
algo = {
name: 'ECDSA',
namedCurve: curveName
};
ckey = yield subtle.importKey('jwk', data, algo, false, use);
algo = {
name: 'ECDSA',
hash: name
};
return yield subtle.verify(algo, ckey, sig, msg);
});
if (!subtle.verify)
ecdsa.verifyAsync = util.promisify(ecdsa.verify);
ecdsa.signAsync = co(function* signAsync(curve, alg, msg, key) {
var use = ['sign'];
var name = backend.getHash(alg);
var curveName = getCurve(curve);
var algo, ckey;
if (!name || !curveName)
return ecdsa.sign(curve, alg, msg, key);
algo = {
name: 'ECDSA',
namedCurve: curveName
};
ckey = yield subtle.importKey('raw', key, algo, false, use);
algo = {
name: 'ECDSA',
hash: name
};
return yield subtle.sign(algo, ckey, msg);
});
if (!subtle.sign)
ecdsa.signAsync = util.promisify(ecdsa.sign);
/* /*
* Helpers * Helpers
*/ */
@ -178,6 +324,44 @@ function leftpad(input, size) {
return out; return out;
} }
function toBase64(data) {
var str = data.toString('base64');
str = str.replace(/\+/g, '-');
str = str.replace(/\//g, '_');
str = str.replace(/=+$/, '');
return str;
}
function getCurve(name) {
switch (name) {
case 'p256':
return 'P-256';
case 'p384':
return 'P-384';
case 'p521':
return 'P-521';
default:
return null;
}
}
function parseECPublic(data, curve) {
var ec = elliptic.ec(curve).curve;
var point = ec.decodePoint(data);
return {
x: point.toArrayLike(Buffer, 'be', 32),
y: point.toArrayLike(Buffer, 'be', 32)
};
}
function ceq(a, b) {
var r = ~(a ^ b) & 0xff;
r &= r >>> 4;
r &= r >>> 2;
r &= r >>> 1;
return r === 1;
}
/* /*
* Expose * Expose
*/ */

View File

@ -9,7 +9,8 @@
var assert = require('assert'); var assert = require('assert');
var PEM = require('../utils/pem'); var PEM = require('../utils/pem');
var elliptic = require('elliptic'); var elliptic = require('elliptic');
var crypto = require('./crypto'); var util = require('../utils/util');
var backend = require('./backend');
var nodeCrypto = require('crypto'); var nodeCrypto = require('crypto');
var dsa, rsa, ecdsa; var dsa, rsa, ecdsa;
@ -29,6 +30,9 @@ dsa.sign = function _sign(alg, msg, key, params) {
return sign('dsa', alg, msg, pem); return sign('dsa', alg, msg, pem);
}; };
dsa.verifyAsync = util.promisify(dsa.verify);
dsa.signAsync = util.promisify(dsa.sign);
/* /*
* RSA * RSA
*/ */
@ -45,6 +49,9 @@ rsa.sign = function _sign(alg, msg, key) {
return sign('rsa', alg, msg, pem); return sign('rsa', alg, msg, pem);
}; };
rsa.verifyAsync = util.promisify(rsa.verify);
rsa.signAsync = util.promisify(rsa.sign);
/* /*
* ECDSA * ECDSA
*/ */
@ -57,7 +64,7 @@ ecdsa.verify = function verify(curve, msg, alg, key, sig) {
assert(curve, 'No curve selected.'); assert(curve, 'No curve selected.');
ec = elliptic.ec(curve); ec = elliptic.ec(curve);
hash = crypto.hash(alg, msg); hash = backend.hash(alg, msg);
return ec.verify(hash, sig, key); return ec.verify(hash, sig, key);
}; };
@ -68,11 +75,14 @@ ecdsa.sign = function sign(curve, msg, alg, key) {
assert(curve, 'No curve selected.'); assert(curve, 'No curve selected.');
ec = elliptic.ec(curve); ec = elliptic.ec(curve);
hash = crypto.hash(alg, msg); hash = backend.hash(alg, msg);
return new Buffer(ec.sign(hash, key)); return new Buffer(ec.sign(hash, key));
}; };
ecdsa.verifyAsync = util.promisify(ecdsa.verify);
ecdsa.signAsync = util.promisify(ecdsa.sign);
/* /*
* Helpers * Helpers
*/ */

View File

@ -10,7 +10,7 @@ var BN = require('bn.js');
var elliptic = require('elliptic'); var elliptic = require('elliptic');
var Signature = require('elliptic/lib/elliptic/ec/signature'); var Signature = require('elliptic/lib/elliptic/ec/signature');
var hmacDRBG = require('elliptic/lib/elliptic/hmac-drbg'); var hmacDRBG = require('elliptic/lib/elliptic/hmac-drbg');
var sha256 = require('./crypto').sha256; var sha256 = require('./backend').sha256;
var secp256k1 = elliptic.ec('secp256k1'); var secp256k1 = elliptic.ec('secp256k1');
var curve = secp256k1.curve; var curve = secp256k1.curve;
var curves = elliptic.curves; var curves = elliptic.curves;

View File

@ -33,10 +33,11 @@
'use strict'; 'use strict';
var util = require('../utils/util'); var co = require('../utils/co');
var crypto = require('./crypto'); var backend = require('./backend');
var native = require('../utils/native').binding; var native = require('../utils/native').binding;
var U32Array = typeof Uint32Array === 'function' ? Uint32Array : Array; var U32Array = typeof Uint32Array === 'function' ? Uint32Array : Array;
var scryptAsync, smix;
/** /**
* Javascript scrypt implementation. Scrypt is * Javascript scrypt implementation. Scrypt is
@ -51,35 +52,28 @@ var U32Array = typeof Uint32Array === 'function' ? Uint32Array : Array;
* @returns {Buffer} * @returns {Buffer}
*/ */
function scryptAsync(passwd, salt, N, r, p, len, callback) { scryptAsync = co(function* scryptAsync(passwd, salt, N, r, p, len) {
var V, XY; var i, B, V, XY;
if (r * p >= (1 << 30)) if (r * p >= (1 << 30))
return callback(new Error('EFBIG')); throw new Error('EFBIG');
if ((N & (N - 1)) !== 0 || N === 0) if ((N & (N - 1)) !== 0 || N === 0)
return callback(new Error('EINVAL')); throw new Error('EINVAL');
if (N > 0xffffffff) if (N > 0xffffffff)
return callback(new Error('EINVAL')); throw new Error('EINVAL');
XY = new Buffer(256 * r); XY = new Buffer(256 * r);
V = new Buffer(128 * r * N); V = new Buffer(128 * r * N);
crypto.pbkdf2Async(passwd, salt, 1, p * 128 * r, 'sha256', function(err, B) { B = yield backend.pbkdf2Async(passwd, salt, 1, p * 128 * r, 'sha256');
if (err)
return callback(err);
forRangeSerial(0, p, function(i, next) { for (i = 0; i < p; i++)
smix(B, i * 128 * r, r, N, V, XY, next); yield smix(B, i * 128 * r, r, N, V, XY);
}, function(err) {
if (err)
return callback(err);
crypto.pbkdf2Async(passwd, B, 1, len, 'sha256', callback); return yield backend.pbkdf2Async(passwd, B, 1, len, 'sha256');
}); });
});
}
if (native) if (native)
scryptAsync = native.scryptAsync; scryptAsync = native.scryptAsync;
@ -148,7 +142,7 @@ function R(a, b) {
return (a << b) | (a >>> (32 - b)); return (a << b) | (a >>> (32 - b));
} }
function blockmix_salsa8(B, Y, Yo, r, callback) { function blockmix_salsa8(B, Y, Yo, r) {
var X = new Buffer(64); var X = new Buffer(64);
var i; var i;
@ -165,42 +159,35 @@ function blockmix_salsa8(B, Y, Yo, r, callback) {
for (i = 0; i < r; i++) for (i = 0; i < r; i++)
blkcpy(B, Y, (i + r) * 64, Yo + (i * 2 + 1) * 64, 64); blkcpy(B, Y, (i + r) * 64, Yo + (i * 2 + 1) * 64, 64);
util.nextTick(callback);
} }
function integerify(B, r) { function integerify(B, r) {
return B.readUInt32LE((2 * r - 1) * 64, true); return B.readUInt32LE((2 * r - 1) * 64, true);
} }
function smix(B, Bo, r, N, V, XY, callback) { smix = co(function* smix(B, Bo, r, N, V, XY) {
var X = XY; var X = XY;
var Y = XY; var Y = XY;
var i;
var j; var j;
blkcpy(X, B, 0, Bo, 128 * r); blkcpy(X, B, 0, Bo, 128 * r);
forRangeSerial(0, N, function(i, next) { for (i = 0; i < N; i++) {
blkcpy(V, X, i * (128 * r), 0, 128 * r); blkcpy(V, X, i * (128 * r), 0, 128 * r);
blockmix_salsa8(X, Y, 128 * r, r, next); blockmix_salsa8(X, Y, 128 * r, r);
}, function(err) { yield co.wait();
if (err) }
return callback(err);
forRangeSerial(0, N, function(i, next) { for (i = 0; i < N; i++) {
j = integerify(X, r) & (N - 1); j = integerify(X, r) & (N - 1);
blkxor(X, V, 0, j * (128 * r), 128 * r); blkxor(X, V, 0, j * (128 * r), 128 * r);
blockmix_salsa8(X, Y, 128 * r, r, next); blockmix_salsa8(X, Y, 128 * r, r);
}, function(err) { yield co.wait();
if (err) }
return callback(err);
blkcpy(B, X, Bo, 0, 128 * r); blkcpy(B, X, Bo, 0, 128 * r);
});
callback();
});
});
}
function blkcpy(dest, src, s1, s2, len) { function blkcpy(dest, src, s1, s2, len) {
src.copy(dest, s1, s2, s2 + len); src.copy(dest, s1, s2, s2 + len);
@ -211,17 +198,6 @@ function blkxor(dest, src, s1, s2, len) {
dest[s1 + i] ^= src[s2 + i]; dest[s1 + i] ^= src[s2 + i];
} }
function forRangeSerial(from, to, iter, callback) {
(function next(err) {
if (err)
return callback(err);
if (from >= to)
return callback();
from++;
iter(from - 1, next, from - 1);
})();
}
/* /*
* Expose * Expose
*/ */

View File

@ -33,7 +33,7 @@
'use strict'; 'use strict';
var crypto = require('./crypto'); var backend = require('./backend');
var native = require('../utils/native').binding; var native = require('../utils/native').binding;
var U32Array = typeof Uint32Array === 'function' ? Uint32Array : Array; var U32Array = typeof Uint32Array === 'function' ? Uint32Array : Array;
@ -65,12 +65,12 @@ 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.pbkdf2(passwd, salt, 1, p * 128 * r, 'sha256'); B = backend.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.pbkdf2(passwd, B, 1, len, 'sha256'); return backend.pbkdf2(passwd, B, 1, len, 'sha256');
} }
if (native) if (native)

View File

@ -135,14 +135,19 @@ Mnemonic.prototype.destroy = function destroy() {
*/ */
Mnemonic.prototype.toSeed = function toSeed(passphrase) { Mnemonic.prototype.toSeed = function toSeed(passphrase) {
var phrase, passwd;
if (!passphrase) if (!passphrase)
passphrase = this.passphrase; passphrase = this.passphrase;
this.passphrase = passphrase; this.passphrase = passphrase;
phrase = nfkd(this.getPhrase());
passwd = nfkd('mnemonic' + passphrase);
return crypto.pbkdf2( return crypto.pbkdf2(
nfkd(this.getPhrase()), new Buffer(phrase, 'utf8'),
nfkd('mnemonic' + passphrase), new Buffer(passwd, 'utf8'),
2048, 64, 'sha512'); 2048, 64, 'sha512');
}; };

View File

@ -349,7 +349,7 @@ CompactBlock.prototype.fromBlock = function fromBlock(block, witness, nonce) {
this.totalTX = block.totalTX; this.totalTX = block.totalTX;
if (!nonce) if (!nonce)
nonce = util.nonce(true); nonce = util.nonce();
this.keyNonce = nonce; this.keyNonce = nonce;

View File

@ -7,7 +7,6 @@
'use strict'; 'use strict';
var BN = require('bn.js');
var constants = require('../protocol/constants'); var constants = require('../protocol/constants');
var util = require('../utils/util'); var util = require('../utils/util');
var assert = require('assert'); var assert = require('assert');
@ -122,7 +121,7 @@ function VersionPacket(options) {
this.ts = time.now(); this.ts = time.now();
this.recv = new NetworkAddress(); this.recv = new NetworkAddress();
this.from = new NetworkAddress(); this.from = new NetworkAddress();
this.nonce = new BN(0); this.nonce = constants.ZERO_U64;
this.agent = constants.USER_AGENT; this.agent = constants.USER_AGENT;
this.height = 0; this.height = 0;
this.relay = true; this.relay = true;
@ -196,7 +195,7 @@ VersionPacket.prototype.toRaw = function toRaw(writer) {
p.write64(this.ts); p.write64(this.ts);
this.recv.toRaw(false, p); this.recv.toRaw(false, p);
this.from.toRaw(false, p); this.from.toRaw(false, p);
p.writeU64(this.nonce); p.writeBytes(this.nonce);
p.writeVarString(this.agent, 'ascii'); p.writeVarString(this.agent, 'ascii');
p.write32(this.height); p.write32(this.height);
p.writeU8(this.relay ? 1 : 0); p.writeU8(this.relay ? 1 : 0);
@ -278,7 +277,7 @@ VersionPacket.prototype.fromRaw = function fromRaw(data) {
if (p.left() > 0) { if (p.left() > 0) {
this.from.fromRaw(p, false); this.from.fromRaw(p, false);
this.nonce = p.readU64(); this.nonce = p.readBytes(8);
} }
if (p.left() > 0) if (p.left() > 0)
@ -392,7 +391,7 @@ PingPacket.prototype.toRaw = function toRaw(writer) {
var p = BufferWriter(writer); var p = BufferWriter(writer);
if (this.nonce) if (this.nonce)
p.writeU64(this.nonce); p.writeBytes(this.nonce);
if (!writer) if (!writer)
p = p.render(); p = p.render();
@ -409,7 +408,7 @@ PingPacket.prototype.toRaw = function toRaw(writer) {
PingPacket.prototype.fromRaw = function fromRaw(data) { PingPacket.prototype.fromRaw = function fromRaw(data) {
var p = BufferReader(data); var p = BufferReader(data);
if (p.left() >= 8) if (p.left() >= 8)
this.nonce = p.readU64(); this.nonce = p.readBytes(8);
return this; return this;
}; };
@ -440,7 +439,7 @@ function PongPacket(nonce) {
Packet.call(this); Packet.call(this);
this.nonce = nonce || new BN(0); this.nonce = nonce || constants.ZERO_U64;
} }
util.inherits(PongPacket, Packet); util.inherits(PongPacket, Packet);
@ -456,7 +455,7 @@ PongPacket.prototype.type = exports.types.PONG;
PongPacket.prototype.toRaw = function toRaw(writer) { PongPacket.prototype.toRaw = function toRaw(writer) {
var p = BufferWriter(writer); var p = BufferWriter(writer);
p.writeU64(this.nonce); p.writeBytes(this.nonce);
if (!writer) if (!writer)
p = p.render(); p = p.render();
@ -472,7 +471,7 @@ PongPacket.prototype.toRaw = function toRaw(writer) {
PongPacket.prototype.fromRaw = function fromRaw(data) { PongPacket.prototype.fromRaw = function fromRaw(data) {
var p = BufferReader(data); var p = BufferReader(data);
this.nonce = p.readU64(); this.nonce = p.readBytes(8);
return this; return this;
}; };

View File

@ -1439,7 +1439,7 @@ Peer.prototype._handleVersion = co(function* _handleVersion(version) {
throw new Error('Peer sent a duplicate version.'); throw new Error('Peer sent a duplicate version.');
if (!this.network.selfConnect) { if (!this.network.selfConnect) {
if (version.nonce.cmp(this.pool.localNonce) === 0) { if (util.equal(version.nonce, this.pool.localNonce)) {
this.ignore(); this.ignore();
throw new Error('We connected to ourself. Oops.'); throw new Error('We connected to ourself. Oops.');
} }
@ -1869,8 +1869,8 @@ Peer.prototype._handlePong = function _handlePong(packet) {
return; return;
} }
if (nonce.cmp(this.challenge) !== 0) { if (!util.equal(nonce, this.challenge)) {
if (nonce.cmpn(0) === 0) { if (util.equal(nonce, constants.ZERO_U64)) {
this.logger.debug('Peer sent a zero nonce (%s).', this.hostname); this.logger.debug('Peer sent a zero nonce (%s).', this.hostname);
this.challenge = null; this.challenge = null;
return; return;

View File

@ -917,6 +917,9 @@ Pool.prototype._handleBlock = co(function* _handleBlock(block, peer) {
// Fulfill the load request. // Fulfill the load request.
requested = this.fulfill(block); requested = this.fulfill(block);
if (util.isBrowser)
yield block.hashAsync();
// Someone is sending us blocks without // Someone is sending us blocks without
// us requesting them. // us requesting them.
if (!requested) { if (!requested) {
@ -1330,6 +1333,9 @@ Pool.prototype.hasReject = function hasReject(hash) {
Pool.prototype._handleTX = co(function* _handleTX(tx, peer) { Pool.prototype._handleTX = co(function* _handleTX(tx, peer) {
var i, requested, missing; var i, requested, missing;
if (util.isBrowser)
yield tx.hashAsync();
// Fulfill the load request. // Fulfill the load request.
requested = this.fulfill(tx); requested = this.fulfill(tx);

View File

@ -10,6 +10,7 @@
var assert = require('assert'); var assert = require('assert');
var constants = require('../protocol/constants'); var constants = require('../protocol/constants');
var util = require('../utils/util'); var util = require('../utils/util');
var co = require('../utils/co');
var crypto = require('../crypto/crypto'); var crypto = require('../crypto/crypto');
var btcutils = require('../btc/utils'); var btcutils = require('../btc/utils');
var VerifyResult = require('../btc/errors').VerifyResult; var VerifyResult = require('../btc/errors').VerifyResult;
@ -160,6 +161,54 @@ AbstractBlock.prototype.hash = function hash(enc) {
return hash; return hash;
}; };
/**
* Hash the block headers (async).
* @param {String?} enc - Can be `'hex'` or `null`.
* @returns {Hash|Buffer} hash
*/
AbstractBlock.prototype.hashAsync = co(function* hashAsync(enc) {
var hash = this._hash;
var hex;
if (!hash) {
hash = yield crypto.hash256Async(this.abbr());
if (!this.mutable)
this._hash = hash;
}
if (enc === 'hex') {
hex = this._hhash;
if (!hex) {
hex = hash.toString('hex');
if (!this.mutable)
this._hhash = hex;
}
hash = hex;
}
return hash;
});
/**
* Cache hashes.
* @private
*/
AbstractBlock.prototype.cacheHashes = co(function* cacheHashes() {
var i, tx;
yield this.hashAsync();
if (!this.txs)
return;
for (i = 0; i < this.txs.length; i++) {
tx = this.txs[i];
yield tx.hashAsync();
}
});
/** /**
* Serialize the block headers. * Serialize the block headers.
* @returns {Buffer} * @returns {Buffer}

View File

@ -78,6 +78,22 @@ MemBlock.fromOptions = function fromOptions(options) {
return new MemBlock().fromOptions(options); return new MemBlock().fromOptions(options);
}; };
/**
* Serialize the block headers.
* @returns {Buffer}
*/
MemBlock.prototype.abbr = function abbr(writer) {
var data = this.raw.slice(0, 80);
if (writer) {
writer.writeBytes(data);
return writer;
}
return data;
};
/** /**
* Get the full block size. * Get the full block size.
* @returns {Number} * @returns {Number}

View File

@ -9,6 +9,7 @@
var assert = require('assert'); var assert = require('assert');
var util = require('../utils/util'); var util = require('../utils/util');
var co = require('../utils/co');
var crypto = require('../crypto/crypto'); var crypto = require('../crypto/crypto');
var btcutils = require('../btc/utils'); var btcutils = require('../btc/utils');
var Amount = require('../btc/amount'); var Amount = require('../btc/amount');
@ -241,6 +242,35 @@ TX.prototype.hash = function _hash(enc) {
return hash; return hash;
}; };
/**
* Hash the transaction with the non-witness serialization (async).
* @param {String?} enc - Can be `'hex'` or `null`.
* @returns {Hash|Buffer} hash
*/
TX.prototype.hashAsync = co(function* _hashAsync(enc) {
var hash = this._hash;
var hex;
if (!hash) {
hash = yield crypto.hash256Async(this.toNormal());
if (!this.mutable)
this._hash = hash;
}
if (enc === 'hex') {
hex = this._hhash;
if (!hex) {
hex = hash.toString('hex');
if (!this.mutable)
this._hhash = hex;
}
hash = hex;
}
return hash;
});
/** /**
* Hash the transaction with the witness * Hash the transaction with the witness
* serialization, return the wtxid (normal * serialization, return the wtxid (normal

View File

@ -698,6 +698,22 @@ exports.ZERO_SIG64 = new Buffer(''
'hex' 'hex'
); );
/**
* 4 zero bytes.
* @const {Buffer}
* @default
*/
exports.ZERO_U32 = new Buffer('00000000', 'hex');
/**
* 8 zero bytes.
* @const {Buffer}
* @default
*/
exports.ZERO_U64 = new Buffer('0000000000000000', 'hex');
/** /**
* BCoin version. * BCoin version.
* @const {String} * @const {String}

View File

@ -595,7 +595,7 @@ BufferReader.prototype.readNullString = function readNullString(enc) {
BufferReader.prototype.createChecksum = function createChecksum() { BufferReader.prototype.createChecksum = function createChecksum() {
var start = this.stack[this.stack.length - 1] || 0; var start = this.stack[this.stack.length - 1] || 0;
var data = this.data.slice(start, this.offset); var data = this.data.slice(start, this.offset);
return crypto.checksum(data).readUInt32LE(0, true); return crypto.hash256(data).readUInt32LE(0, true);
}; };
/** /**

View File

@ -13,7 +13,6 @@ var assert = require('assert');
var nodeUtil = require('util'); var nodeUtil = require('util');
var fs = require('fs'); var fs = require('fs');
var os = require('os'); var os = require('os');
var BN = require('bn.js');
var util = exports; var util = exports;
var Number, Math, Date; var Number, Math, Date;
@ -542,38 +541,14 @@ util.time = function time(date) {
/** /**
* Create a 64 bit nonce. * Create a 64 bit nonce.
* @returns {BN} * @returns {Buffer}
*/ */
util.nonce = function _nonce(buffer) { util.nonce = function _nonce() {
var nonce = new Buffer(8); var nonce = new Buffer(8);
nonce.writeUInt32LE((Math.random() * 0x100000000) >>> 0, 0, true); nonce.writeUInt32LE((Math.random() * 0x100000000) >>> 0, 0, true);
nonce.writeUInt32LE((Math.random() * 0x100000000) >>> 0, 4, true); nonce.writeUInt32LE((Math.random() * 0x100000000) >>> 0, 4, true);
return nonce;
if (buffer)
return nonce;
return new BN(nonce);
};
/**
* Test whether a buffer is all zeroes.
* @param {Buffer} data
* @returns {Boolean}
*/
util.isZero = function isZero(data) {
var i;
assert(Buffer.isBuffer(data));
for (i = 0; i < data.length; i++) {
if (data[i] !== 0)
return false;
}
return true;
}; };
/** /**
@ -1015,3 +990,21 @@ util._paths = {};
util.fastProp = function fastProp(obj) { util.fastProp = function fastProp(obj) {
({ __proto__: obj }); ({ __proto__: obj });
}; };
/**
* Promisify a function.
* @param {Function} func
* @returns {Function}
*/
util.promisify = function promisify(func) {
return function() {
var result;
try {
result = func.apply(this, arguments);
} catch (e) {
return Promise.reject(e);
}
return Promise.resolve(result);
};
};

View File

@ -105,7 +105,7 @@ BufferWriter.prototype.render = function render(keep) {
case BYTES: off += item[1].copy(data, off); break; case BYTES: off += item[1].copy(data, off); break;
case STR: off += data.write(item[1], off, item[2]); break; case STR: off += data.write(item[1], off, item[2]); break;
case CHECKSUM: case CHECKSUM:
off += crypto.checksum(data.slice(0, off)).copy(data, off); off += crypto.hash256(data.slice(0, off)).copy(data, off, 0, 4);
break; break;
case FILL: case FILL:
data.fill(item[1], off, off + item[2]); data.fill(item[1], off, off + item[2]);

View File

@ -15,6 +15,12 @@ var BufferReader = require('../utils/reader');
var BufferWriter = require('../utils/writer'); var BufferWriter = require('../utils/writer');
var HD = require('../hd/hd'); var HD = require('../hd/hd');
/*
* Constants
*/
var BCOIN_SALT = new Buffer('bcoin', 'ascii');
/** /**
* Master BIP32 key which can exist * Master BIP32 key which can exist
* in a timed out encrypted state. * in a timed out encrypted state.
@ -234,11 +240,14 @@ MasterKey.prototype.stop = function stop() {
*/ */
MasterKey.prototype.derive = function derive(passwd) { MasterKey.prototype.derive = function derive(passwd) {
if (typeof passwd === 'string')
passwd = new Buffer(passwd, 'utf8');
switch (this.alg) { switch (this.alg) {
case MasterKey.alg.PBKDF2: case MasterKey.alg.PBKDF2:
return crypto.pbkdf2Async(passwd, 'bcoin', this.N, 32, 'sha256'); return crypto.pbkdf2Async(passwd, BCOIN_SALT, this.N, 32, 'sha256');
case MasterKey.alg.SCRYPT: case MasterKey.alg.SCRYPT:
return crypto.scryptAsync(passwd, 'bcoin', this.N, this.r, this.p, 32); return crypto.scryptAsync(passwd, BCOIN_SALT, this.N, this.r, this.p, 32);
default: default:
return Promise.reject(new Error('Unknown algorithm: ' + this.alg)); return Promise.reject(new Error('Unknown algorithm: ' + this.alg));
} }

View File

@ -41,7 +41,7 @@
"elliptic": "6.3.2" "elliptic": "6.3.2"
}, },
"optionalDependencies": { "optionalDependencies": {
"bcoin-native": "0.0.9", "bcoin-native": "0.0.10",
"leveldown": "1.5.0", "leveldown": "1.5.0",
"secp256k1": "3.2.0", "secp256k1": "3.2.0",
"socket.io": "1.4.8", "socket.io": "1.4.8",

View File

@ -58,6 +58,38 @@ describe('AES', function() {
]); ]);
} }
function bencrypt(data, passphrase) {
var key, cipher;
assert(nativeCrypto, 'No crypto module available.');
assert(passphrase, 'No passphrase.');
if (typeof data === 'string')
data = new Buffer(data, 'utf8');
if (typeof passphrase === 'string')
passphrase = new Buffer(passphrase, 'utf8');
key = pbkdf2key(passphrase, 2048, 32, 16);
return crypto.encipher(data, key.key, key.iv);
}
function bdecrypt(data, passphrase) {
var key, decipher;
assert(nativeCrypto, 'No crypto module available.');
assert(passphrase, 'No passphrase.');
if (typeof data === 'string')
data = new Buffer(data, 'hex');
if (typeof passphrase === 'string')
passphrase = new Buffer(passphrase, 'utf8');
key = pbkdf2key(passphrase, 2048, 32, 16);
return crypto.decipher(data, key.key, key.iv);
}
function encrypt(data, passphrase) { function encrypt(data, passphrase) {
var key, cipher; var key, cipher;
@ -101,9 +133,14 @@ describe('AES', function() {
var enchash2 = nencrypt(hash2, 'foo'); var enchash2 = nencrypt(hash2, 'foo');
var dechash2 = ndecrypt(enchash2, 'foo'); var dechash2 = ndecrypt(enchash2, 'foo');
var hash3 = crypto.sha256(new Buffer([]));
var enchash3 = bencrypt(hash3, 'foo');
var dechash3 = bdecrypt(enchash3, 'foo');
assert.deepEqual(hash, hash2); assert.deepEqual(hash, hash2);
assert.deepEqual(enchash, enchash2); assert.deepEqual(enchash, enchash2);
assert.deepEqual(dechash, dechash2); assert.deepEqual(dechash, dechash2);
assert.deepEqual(dechash, dechash3);
}); });
it('should encrypt and decrypt a hash with uneven blocks', function() { it('should encrypt and decrypt a hash with uneven blocks', function() {

View File

@ -5,7 +5,9 @@ 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() {
var result = scrypt('', '', 16, 1, 1, 64); var pass = new Buffer('');
var salt = new Buffer('');
var result = scrypt(pass, salt, 16, 1, 1, 64);
assert.equal(result.toString('hex'), '' assert.equal(result.toString('hex'), ''
+ '77d6576238657b203b19ca42c18a0497f16b4844e3074ae8dfdffa3f' + '77d6576238657b203b19ca42c18a0497f16b4844e3074ae8dfdffa3f'
+ 'ede21442fcd0069ded0948f8326a753a0fc81f17e8d3e0fb2e0d3628' + 'ede21442fcd0069ded0948f8326a753a0fc81f17e8d3e0fb2e0d3628'
@ -13,7 +15,9 @@ 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 pass = new Buffer('password');
var salt = new Buffer('NaCl');
var result = scrypt(pass, salt, 1024, 8, 16, 64);
assert.equal(result.toString('hex'), '' assert.equal(result.toString('hex'), ''
+ 'fdbabe1c9d3472007856e7190d01e9fe7c6ad7cbc8237830e773' + 'fdbabe1c9d3472007856e7190d01e9fe7c6ad7cbc8237830e773'
+ '76634b3731622eaf30d92e22a3886ff109279d9830dac727afb9' + '76634b3731622eaf30d92e22a3886ff109279d9830dac727afb9'
@ -21,7 +25,9 @@ describe('Scrypt', function() {
}); });
it('should perform scrypt with N=16384', function() { it('should perform scrypt with N=16384', function() {
var result = scrypt('pleaseletmein', 'SodiumChloride', 16384, 8, 1, 64); var pass = new Buffer('pleaseletmein');
var salt = new Buffer('SodiumChloride');
var result = scrypt(pass, salt, 16384, 8, 1, 64);
assert.equal(result.toString('hex'), '' assert.equal(result.toString('hex'), ''
+ '7023bdcb3afd7348461c06cd81fd38ebfda8fbba904f8e3ea9b54' + '7023bdcb3afd7348461c06cd81fd38ebfda8fbba904f8e3ea9b54'
+ '3f6545da1f2d5432955613f0fcf62d49705242a9af9e61e85dc0d' + '3f6545da1f2d5432955613f0fcf62d49705242a9af9e61e85dc0d'
@ -30,7 +36,9 @@ describe('Scrypt', function() {
// Only enable if you want to wait a while. // Only enable if you want to wait a while.
// it('should perform scrypt with N=1048576', function() { // it('should perform scrypt with N=1048576', function() {
// var result = scrypt('pleaseletmein', 'SodiumChloride', 1048576, 8, 1, 64); // var pass = new Buffer('pleaseletmein');
// var salt = new Buffer('SodiumChloride');
// var result = scrypt(pass, salt, 1048576, 8, 1, 64);
// assert.equal(result.toString('hex'), '' // assert.equal(result.toString('hex'), ''
// + '2101cb9b6a511aaeaddbbe09cf70f881ec568d574a2ffd4dabe5' // + '2101cb9b6a511aaeaddbbe09cf70f881ec568d574a2ffd4dabe5'
// + 'ee9820adaa478e56fd8f4ba5d09ffa1c6d927c40f4c337304049' // + 'ee9820adaa478e56fd8f4ba5d09ffa1c6d927c40f4c337304049'