crypto: implement subtle api for browser.
This commit is contained in:
parent
4245cd6bf1
commit
f376289684
@ -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;
|
||||||
|
|
||||||
|
|||||||
@ -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.');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|||||||
@ -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')
|
||||||
|
|||||||
@ -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
|
||||||
|
|||||||
@ -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');
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@ -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;
|
||||||
|
|||||||
@ -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;
|
||||||
|
|||||||
@ -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
|
||||||
|
|||||||
@ -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;
|
||||||
|
|||||||
@ -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;
|
||||||
|
|||||||
@ -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
|
||||||
*/
|
*/
|
||||||
|
|||||||
@ -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
|
||||||
*/
|
*/
|
||||||
|
|||||||
@ -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;
|
||||||
|
|||||||
@ -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
|
||||||
*/
|
*/
|
||||||
|
|||||||
@ -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)
|
||||||
|
|||||||
@ -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');
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@ -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;
|
||||||
|
|
||||||
|
|||||||
@ -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;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@ -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;
|
||||||
|
|||||||
@ -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);
|
||||||
|
|
||||||
|
|||||||
@ -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}
|
||||||
|
|||||||
@ -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}
|
||||||
|
|||||||
@ -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
|
||||||
|
|||||||
@ -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}
|
||||||
|
|||||||
@ -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);
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@ -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);
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|||||||
@ -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]);
|
||||||
|
|||||||
@ -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));
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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",
|
||||||
|
|||||||
@ -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() {
|
||||||
|
|||||||
@ -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'
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user