crypto: implement subtle api for browser.
This commit is contained in:
parent
4245cd6bf1
commit
f376289684
@ -8,6 +8,7 @@
|
||||
|
||||
var assert = require('assert');
|
||||
var util = require('../utils/util');
|
||||
var co = require('../utils/co');
|
||||
var crypto = require('../crypto/crypto');
|
||||
var x509 = require('./x509');
|
||||
var PEM = require('../utils/pem');
|
||||
@ -226,6 +227,34 @@ PaymentRequest.prototype.verifyChain = function verifyChain() {
|
||||
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() {
|
||||
var chain, root;
|
||||
|
||||
|
||||
@ -7,6 +7,7 @@
|
||||
'use strict';
|
||||
|
||||
var pk = require('../crypto/pk');
|
||||
var co = require('../utils/co');
|
||||
|
||||
exports._verify = function verify(hash, msg, sig, key) {
|
||||
switch (key.alg) {
|
||||
@ -41,3 +42,37 @@ exports.sign = function sign(hash, msg, key) {
|
||||
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 crypto = require('../crypto/crypto');
|
||||
var pk = require('./pk');
|
||||
var co = require('../utils/co');
|
||||
var x509 = exports;
|
||||
|
||||
x509.getSubjectOID = function getSubjectOID(cert, oid) {
|
||||
@ -177,11 +178,11 @@ x509.getPublicKey = function getPublicKey(cert) {
|
||||
|
||||
x509.verifyTime = function verifyTime(cert) {
|
||||
var time = cert.tbs.validity;
|
||||
var now = Math.floor(Date.now() / 1000);
|
||||
var now = util.now();
|
||||
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;
|
||||
|
||||
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;
|
||||
|
||||
if (chain.length === 0)
|
||||
@ -229,27 +240,82 @@ x509.verifySubject = function verifySubject(hash, msg, sig, chain) {
|
||||
if (!key)
|
||||
return false;
|
||||
|
||||
return key;
|
||||
};
|
||||
|
||||
x509.verifySubject = function verifySubject(hash, msg, sig, chain) {
|
||||
var key = x509.getVerifyKey(chain);
|
||||
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;
|
||||
|
||||
chain = chain.slice();
|
||||
if (!chain)
|
||||
return false;
|
||||
|
||||
// Parse certificates and
|
||||
// check validity time.
|
||||
for (i = 0; i < chain.length; i++) {
|
||||
child = x509.parse(chain[i]);
|
||||
|
||||
if (!child)
|
||||
return false;
|
||||
|
||||
chain[i] = child;
|
||||
|
||||
if (!x509.verifyTime(child))
|
||||
return false;
|
||||
}
|
||||
if (!x509.verifyTimes(chain))
|
||||
return false;
|
||||
|
||||
// Verify signatures.
|
||||
for (i = 1; i < chain.length; i++) {
|
||||
@ -271,26 +337,47 @@ x509.verifyChain = function verifyChain(chain) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// If trust hasn't been
|
||||
// setup, just return.
|
||||
if (x509.allowUntrusted)
|
||||
return true;
|
||||
// Make sure we trust one
|
||||
// of the certs in the chain.
|
||||
return x509.verifyTrust(chain);
|
||||
};
|
||||
|
||||
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
|
||||
// of the certs in the chain.
|
||||
for (i = 0; i < chain.length; i++) {
|
||||
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;
|
||||
};
|
||||
return x509.verifyTrust(chain);
|
||||
});
|
||||
|
||||
function isHash(data) {
|
||||
if (typeof data === 'string')
|
||||
|
||||
@ -1318,6 +1318,8 @@ Chain.prototype._add = co(function* add(block) {
|
||||
'error parsing message',
|
||||
100);
|
||||
}
|
||||
if (util.isBrowser)
|
||||
yield block.cacheHashes();
|
||||
}
|
||||
|
||||
// Update the block height early
|
||||
|
||||
@ -33,14 +33,22 @@ function AESKey(key, bits) {
|
||||
this.userKey = key;
|
||||
this.bits = bits;
|
||||
|
||||
if (this.bits === 128)
|
||||
this.rounds = 10;
|
||||
else if (this.bits === 192)
|
||||
this.rounds = 12;
|
||||
else if (this.bits === 256)
|
||||
this.rounds = 14;
|
||||
else
|
||||
throw new Error('Bad key size.');
|
||||
switch (this.bits) {
|
||||
case 128:
|
||||
this.rounds = 10;
|
||||
break;
|
||||
case 192:
|
||||
this.rounds = 12;
|
||||
break;
|
||||
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.encryptKey = null;
|
||||
@ -688,6 +696,8 @@ AES.ecb = {};
|
||||
*/
|
||||
|
||||
AES.ecb.encrypt = function encrypt(data, key) {
|
||||
assert(Buffer.isBuffer(data));
|
||||
assert(key.length === 32);
|
||||
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) {
|
||||
assert(Buffer.isBuffer(data));
|
||||
assert(key.length === 32);
|
||||
return AES.decrypt(data, key, null, 256, 'ecb');
|
||||
};
|
||||
|
||||
@ -717,6 +729,9 @@ AES.cbc = {};
|
||||
*/
|
||||
|
||||
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');
|
||||
};
|
||||
|
||||
@ -729,6 +744,9 @@ AES.cbc.encrypt = function encrypt(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');
|
||||
};
|
||||
|
||||
|
||||
@ -4,57 +4,168 @@
|
||||
* https://github.com/bcoin-org/bcoin
|
||||
*/
|
||||
|
||||
/* jshint worker: true */
|
||||
|
||||
'use strict';
|
||||
|
||||
var assert = require('assert');
|
||||
var hashjs = require('hash.js');
|
||||
var util = require('../utils/util');
|
||||
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 global, crypto, subtle;
|
||||
|
||||
global = (function() {
|
||||
if (typeof window !== 'undefined')
|
||||
return window;
|
||||
/*
|
||||
* Hashing
|
||||
*/
|
||||
|
||||
if (typeof self !== 'undefined')
|
||||
return self;
|
||||
|
||||
throw new Error('No global found.');
|
||||
})();
|
||||
|
||||
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.hash = function _hash(alg, data) {
|
||||
var hash = hashjs[alg];
|
||||
assert(hash != null, 'Unknown algorithm.');
|
||||
return new Buffer(hash().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 hmac;
|
||||
|
||||
assert(hash != null, 'Unknown algorithm.');
|
||||
|
||||
hmac = hashjs.hmac(hash, salt);
|
||||
hmac = hashjs.hmac(hash, key);
|
||||
|
||||
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) {
|
||||
var algo = { name: 'PBKDF2' };
|
||||
var use = ['deriveBits'];
|
||||
var name = backend.getHash(alg);
|
||||
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 = {
|
||||
name: 'PBKDF2',
|
||||
salt: salt,
|
||||
iterations: iter,
|
||||
hash: getHash(alg)
|
||||
hash: name
|
||||
};
|
||||
|
||||
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)
|
||||
backend.pbkdf2Async = null;
|
||||
if (!subtle.deriveBits)
|
||||
backend.pbkdf2Async = util.promisify(backend.pbkdf2);
|
||||
|
||||
/*
|
||||
* Ciphers
|
||||
*/
|
||||
|
||||
backend.encipher = function encipher(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) {
|
||||
var data = new Uint8Array(n);
|
||||
crypto.getRandomValues(data);
|
||||
return new Buffer(data.buffer);
|
||||
};
|
||||
|
||||
if (!crypto || !crypto.getRandomValues) {
|
||||
if (!crypto.getRandomValues) {
|
||||
// Out of luck here. Use bad randomness for now.
|
||||
backend.randomBytes = function randomBytes(n) {
|
||||
var data = new Buffer(n);
|
||||
@ -100,7 +255,7 @@ if (!crypto || !crypto.getRandomValues) {
|
||||
};
|
||||
}
|
||||
|
||||
function getHash(name) {
|
||||
backend.getHash = function getHash(name) {
|
||||
switch (name) {
|
||||
case 'sha1':
|
||||
return 'SHA-1';
|
||||
@ -111,6 +266,9 @@ function getHash(name) {
|
||||
case 'sha512':
|
||||
return 'SHA-512';
|
||||
default:
|
||||
throw new Error('Unknown hash.');
|
||||
return null;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
backend.crypto = crypto;
|
||||
backend.subtle = subtle;
|
||||
|
||||
@ -7,31 +7,78 @@
|
||||
'use strict';
|
||||
|
||||
var util = require('../utils/util');
|
||||
var co = require('../utils/co');
|
||||
var crypto = require('crypto');
|
||||
var native = require('../utils/native').binding;
|
||||
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) {
|
||||
return crypto.createHash(alg).update(data).digest();
|
||||
};
|
||||
|
||||
backend.hmac = function hmac(alg, data, salt) {
|
||||
var hmac = crypto.createHmac(alg, 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 hmac = crypto.createHmac(alg, key);
|
||||
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) {
|
||||
return crypto.pbkdf2Sync(key, salt, iter, len, alg);
|
||||
};
|
||||
|
||||
if (!crypto.pbkdf2Sync)
|
||||
backend.pbkdf2 = null;
|
||||
|
||||
backend.pbkdf2Async = function pbkdf2Async(key, salt, iter, len, alg, callback) {
|
||||
return crypto.pbkdf2(key, salt, iter, len, alg, callback);
|
||||
backend.pbkdf2Async = function pbkdf2Async(key, salt, iter, len, alg) {
|
||||
return new Promise(function(resolve, reject) {
|
||||
crypto.pbkdf2(key, salt, iter, len, alg, co.wrap(resolve, reject));
|
||||
});
|
||||
};
|
||||
|
||||
if (!crypto.pbkdf2)
|
||||
backend.pbkdf2Async = null;
|
||||
/*
|
||||
* Ciphers
|
||||
*/
|
||||
|
||||
backend.encipher = function encipher(data, 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;
|
||||
|
||||
@ -7,114 +7,111 @@
|
||||
|
||||
'use strict';
|
||||
|
||||
var assert = require('assert');
|
||||
var backend = require('./backend');
|
||||
var native = require('../utils/native').binding;
|
||||
var scrypt = require('./scrypt');
|
||||
var scryptAsync = require('./scrypt-async');
|
||||
var co = require('../utils/co');
|
||||
var native = require('../utils/native').binding;
|
||||
var backend = require('./backend');
|
||||
var crypto = exports;
|
||||
|
||||
/**
|
||||
* Hash with chosen algorithm.
|
||||
* @function
|
||||
* @param {String} alg
|
||||
* @param {Buffer} data
|
||||
* @returns {Buffer}
|
||||
*/
|
||||
|
||||
crypto.hash = function _hash(alg, data) {
|
||||
return backend.hash(alg, data);
|
||||
};
|
||||
crypto.hash = backend.hash;
|
||||
|
||||
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.
|
||||
* @function
|
||||
* @param {Buffer} data
|
||||
* @returns {Buffer}
|
||||
*/
|
||||
|
||||
crypto.ripemd160 = function ripemd160(data) {
|
||||
return crypto.hash('ripemd160', data);
|
||||
};
|
||||
crypto.ripemd160 = backend.ripemd160;
|
||||
|
||||
/**
|
||||
* Hash with sha1.
|
||||
* @function
|
||||
* @param {Buffer} data
|
||||
* @returns {Buffer}
|
||||
*/
|
||||
|
||||
crypto.sha1 = function sha1(data) {
|
||||
return crypto.hash('sha1', data);
|
||||
};
|
||||
crypto.sha1 = backend.sha1;
|
||||
|
||||
/**
|
||||
* Hash with sha256.
|
||||
* @function
|
||||
* @param {Buffer} data
|
||||
* @returns {Buffer}
|
||||
*/
|
||||
|
||||
crypto.sha256 = function sha256(data) {
|
||||
return crypto.hash('sha256', data);
|
||||
};
|
||||
|
||||
if (native)
|
||||
crypto.sha256 = native.sha256;
|
||||
crypto.sha256 = backend.sha256;
|
||||
|
||||
/**
|
||||
* Hash with sha256 and ripemd160 (OP_HASH160).
|
||||
* @function
|
||||
* @param {Buffer} data
|
||||
* @returns {Buffer}
|
||||
*/
|
||||
|
||||
crypto.hash160 = function hash160(data) {
|
||||
return crypto.ripemd160(crypto.sha256(data));
|
||||
};
|
||||
|
||||
if (native)
|
||||
crypto.hash160 = native.hash160;
|
||||
crypto.hash160 = backend.hash160;
|
||||
|
||||
/**
|
||||
* Hash with sha256 twice (OP_HASH256).
|
||||
* @function
|
||||
* @param {Buffer} data
|
||||
* @returns {Buffer}
|
||||
*/
|
||||
|
||||
crypto.hash256 = function hash256(data) {
|
||||
return crypto.sha256(crypto.sha256(data));
|
||||
};
|
||||
|
||||
if (native)
|
||||
crypto.hash256 = native.hash256;
|
||||
crypto.hash256 = backend.hash256;
|
||||
|
||||
/**
|
||||
* Create a sha256 checksum (common in bitcoin).
|
||||
* Hash with sha256 twice (async).
|
||||
* @function
|
||||
* @param {Buffer} data
|
||||
* @returns {Buffer}
|
||||
*/
|
||||
|
||||
crypto.checksum = function checksum(data) {
|
||||
return crypto.hash256(data).slice(0, 4);
|
||||
};
|
||||
crypto.hash256Async = backend.hash256Async;
|
||||
|
||||
/**
|
||||
* Create an HMAC.
|
||||
* @function
|
||||
* @param {String} alg
|
||||
* @param {Buffer} data
|
||||
* @param {Buffer} salt
|
||||
* @param {Buffer} key
|
||||
* @returns {Buffer} HMAC
|
||||
*/
|
||||
|
||||
crypto.hmac = function hmac(alg, data, salt) {
|
||||
return backend.hmac(alg, data, salt);
|
||||
};
|
||||
crypto.hmac = backend.hmac;
|
||||
|
||||
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.
|
||||
* @function
|
||||
* @param {Buffer} key
|
||||
* @param {Buffer} salt
|
||||
* @param {Number} iter
|
||||
@ -123,21 +120,11 @@ if (native)
|
||||
* @returns {Buffer}
|
||||
*/
|
||||
|
||||
crypto.pbkdf2 = function pbkdf2(key, salt, iter, len, alg) {
|
||||
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);
|
||||
};
|
||||
crypto.pbkdf2 = backend.pbkdf2;
|
||||
|
||||
/**
|
||||
* Execute pbkdf2 asynchronously.
|
||||
* @function
|
||||
* @param {Buffer} key
|
||||
* @param {Buffer} salt
|
||||
* @param {Number} iter
|
||||
@ -146,32 +133,11 @@ crypto.pbkdf2 = function pbkdf2(key, salt, iter, len, alg) {
|
||||
* @returns {Promise}
|
||||
*/
|
||||
|
||||
crypto.pbkdf2Async = function pbkdf2Async(key, salt, iter, len, alg) {
|
||||
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);
|
||||
};
|
||||
crypto.pbkdf2Async = backend.pbkdf2Async;
|
||||
|
||||
/**
|
||||
* Perform key derivation using scrypt.
|
||||
* @function
|
||||
* @param {Buffer} passwd
|
||||
* @param {Buffer} salt
|
||||
* @param {Number} N
|
||||
@ -181,18 +147,11 @@ crypto.pbkdf2Async = function pbkdf2Async(key, salt, iter, len, alg) {
|
||||
* @returns {Buffer}
|
||||
*/
|
||||
|
||||
crypto.scrypt = function _scrypt(passwd, salt, N, r, p, len) {
|
||||
if (typeof passwd === 'string')
|
||||
passwd = new Buffer(passwd, 'utf8');
|
||||
|
||||
if (typeof salt === 'string')
|
||||
salt = new Buffer(salt, 'utf8');
|
||||
|
||||
return scrypt(passwd, salt, N, r, p, len);
|
||||
};
|
||||
crypto.scrypt = scrypt;
|
||||
|
||||
/**
|
||||
* Execute scrypt asynchronously.
|
||||
* @function
|
||||
* @param {Buffer} passwd
|
||||
* @param {Buffer} salt
|
||||
* @param {Number} N
|
||||
@ -202,66 +161,18 @@ crypto.scrypt = function _scrypt(passwd, salt, N, r, p, len) {
|
||||
* @returns {Promise}
|
||||
*/
|
||||
|
||||
crypto.scryptAsync = function _scrypt(passwd, salt, N, r, p, len) {
|
||||
if (typeof passwd === 'string')
|
||||
passwd = new Buffer(passwd, 'utf8');
|
||||
|
||||
if (typeof salt === 'string')
|
||||
salt = new Buffer(salt, 'utf8');
|
||||
|
||||
return 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;
|
||||
};
|
||||
crypto.scryptAsync = scryptAsync;
|
||||
|
||||
/**
|
||||
* Perform hkdf extraction.
|
||||
* @param {Buffer} ikm
|
||||
* @param {Buffer} salt
|
||||
* @param {Buffer} key
|
||||
* @param {String} alg
|
||||
* @returns {Buffer}
|
||||
*/
|
||||
|
||||
crypto.hkdfExtract = function hkdfExtract(ikm, salt, alg) {
|
||||
return crypto.hmac(alg, ikm, salt);
|
||||
crypto.hkdfExtract = function hkdfExtract(ikm, key, alg) {
|
||||
return crypto.hmac(alg, ikm, key);
|
||||
};
|
||||
|
||||
/**
|
||||
@ -424,38 +335,47 @@ if (native)
|
||||
|
||||
/**
|
||||
* Encrypt with aes-256-cbc.
|
||||
* @function
|
||||
* @param {Buffer} data
|
||||
* @param {Buffer} key - 256 bit key.
|
||||
* @param {Buffer} iv - 128 bit initialization vector.
|
||||
* @returns {Buffer}
|
||||
*/
|
||||
|
||||
crypto.encipher = function encipher(data, key, iv) {
|
||||
assert(Buffer.isBuffer(data));
|
||||
assert(Buffer.isBuffer(key));
|
||||
assert(Buffer.isBuffer(iv));
|
||||
assert(key.length === 32);
|
||||
assert(iv.length === 16);
|
||||
crypto.encipher = backend.encipher;
|
||||
|
||||
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.
|
||||
* @function
|
||||
* @param {Buffer} data
|
||||
* @param {Buffer} key - 256 bit key.
|
||||
* @param {Buffer} iv - 128 bit initialization vector.
|
||||
* @returns {Buffer}
|
||||
*/
|
||||
|
||||
crypto.decipher = function decipher(data, key, iv) {
|
||||
assert(Buffer.isBuffer(data));
|
||||
assert(Buffer.isBuffer(key));
|
||||
assert(Buffer.isBuffer(iv));
|
||||
assert(key.length === 32);
|
||||
assert(iv.length === 16);
|
||||
return backend.decipher(data, key, iv);
|
||||
};
|
||||
crypto.decipher = backend.decipher;
|
||||
|
||||
/**
|
||||
* Decrypt 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.decipherAsync = backend.decipherAsync;
|
||||
|
||||
/**
|
||||
* memcmp in constant time (can only return true or false).
|
||||
@ -488,21 +408,6 @@ crypto.ccmp = function ccmp(a, b) {
|
||||
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.
|
||||
* @param {Buffer} data
|
||||
|
||||
@ -9,7 +9,7 @@
|
||||
|
||||
var assert = require('assert');
|
||||
var util = require('../utils/util');
|
||||
var crypto = require('./crypto');
|
||||
var backend = require('./backend');
|
||||
var secp256k1 = require('secp256k1');
|
||||
|
||||
/*
|
||||
@ -40,7 +40,7 @@ ec.generatePrivateKey = function generatePrivateKey() {
|
||||
var priv;
|
||||
|
||||
do {
|
||||
priv = crypto.randomBytes(32);
|
||||
priv = backend.randomBytes(32);
|
||||
} while (!secp256k1.privateKeyVerify(priv));
|
||||
|
||||
return priv;
|
||||
|
||||
@ -4,13 +4,15 @@ var crypto = require('./crypto');
|
||||
|
||||
exports.crypto = crypto;
|
||||
exports.hash = crypto.hash;
|
||||
exports.hashAsync = crypto.hashAsync;
|
||||
exports.ripemd160 = crypto.ripemd160;
|
||||
exports.sha1 = crypto.sha1;
|
||||
exports.sha256 = crypto.sha256;
|
||||
exports.hash160 = crypto.hash160;
|
||||
exports.hash256 = crypto.hash256;
|
||||
exports.checksum = crypto.checksum;
|
||||
exports.hash256Async = crypto.hash256Async;
|
||||
exports.hmac = crypto.hmac;
|
||||
exports.hmacAsync = crypto.hmacAsync;
|
||||
exports.pbkdf2 = crypto.pbkdf2;
|
||||
exports.pbkdf2Async = crypto.pbkdf2Async;
|
||||
exports.scrypt = crypto.scrypt;
|
||||
@ -24,7 +26,6 @@ exports.checkMerkleBranch = crypto.checkMerkleBranch;
|
||||
exports.encipher = crypto.encipher;
|
||||
exports.decipher = crypto.decipher;
|
||||
exports.ccmp = crypto.ccmp;
|
||||
exports.ceq = crypto.ceq;
|
||||
exports.cleanse = crypto.cleanse;
|
||||
exports.randomBytes = crypto.randomBytes;
|
||||
exports.randomInt = crypto.randomInt;
|
||||
|
||||
@ -9,8 +9,11 @@
|
||||
var assert = require('assert');
|
||||
var BN = require('bn.js');
|
||||
var ASN1 = require('../utils/asn1');
|
||||
var util = require('../utils/util');
|
||||
var co = require('../utils/co');
|
||||
var elliptic = require('elliptic');
|
||||
var crypto = require('./crypto');
|
||||
var backend = require('./backend');
|
||||
var subtle = backend.subtle;
|
||||
var dsa, rsa, ecdsa;
|
||||
|
||||
/*
|
||||
@ -23,10 +26,14 @@ dsa.verify = function verify(alg, msg, sig, key, params) {
|
||||
throw new Error('DSA not implemented.');
|
||||
};
|
||||
|
||||
dsa.verifyAsync = util.promisify(dsa.verify);
|
||||
|
||||
dsa.sign = function sign(alg, msg, key, params) {
|
||||
throw new Error('DSA not implemented.');
|
||||
};
|
||||
|
||||
dsa.signAsync = util.promisify(dsa.sign);
|
||||
|
||||
/*
|
||||
* RSA
|
||||
*/
|
||||
@ -52,7 +59,7 @@ rsa.verify = function verify(alg, msg, sig, key) {
|
||||
if (!prefix)
|
||||
throw new Error('Unknown PKCS prefix.');
|
||||
|
||||
hash = crypto.hash(alg, msg);
|
||||
hash = backend.hash(alg, msg);
|
||||
len = prefix.length + hash.length;
|
||||
pub = ASN1.parseRSAPublic(key);
|
||||
|
||||
@ -66,14 +73,14 @@ rsa.verify = function verify(alg, msg, sig, key) {
|
||||
m = rsa.encrypt(N, e, sig);
|
||||
em = leftpad(m, k);
|
||||
|
||||
ok = crypto.ceq(em[0], 0x00);
|
||||
ok &= crypto.ceq(em[1], 0x01);
|
||||
ok &= crypto.ccmp(em.slice(k - hash.length, k), hash);
|
||||
ok &= crypto.ccmp(em.slice(k - len, k - hash.length), prefix);
|
||||
ok &= crypto.ceq(em[k - len - 1], 0x00);
|
||||
ok = ceq(em[0], 0x00);
|
||||
ok &= ceq(em[1], 0x01);
|
||||
ok &= backend.ccmp(em.slice(k - hash.length, k), hash);
|
||||
ok &= backend.ccmp(em.slice(k - len, k - hash.length), prefix);
|
||||
ok &= ceq(em[k - len - 1], 0x00);
|
||||
|
||||
for (i = 2; i < k - len - 1; i++)
|
||||
ok &= crypto.ceq(em[i], 0xff);
|
||||
ok &= ceq(em[i], 0xff);
|
||||
|
||||
return ok === 1;
|
||||
};
|
||||
@ -86,7 +93,7 @@ rsa.sign = function sign(alg, msg, key) {
|
||||
if (!prefix)
|
||||
throw new Error('Unknown PKCS prefix.');
|
||||
|
||||
hash = crypto.hash(alg, msg);
|
||||
hash = backend.hash(alg, msg);
|
||||
len = prefix.length + hash.length;
|
||||
priv = ASN1.parseRSAPrivate(key);
|
||||
|
||||
@ -110,6 +117,82 @@ rsa.sign = function sign(alg, msg, key) {
|
||||
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) {
|
||||
var c = new BN(m);
|
||||
|
||||
@ -137,28 +220,91 @@ rsa.encrypt = function encrypt(N, e, m) {
|
||||
|
||||
ecdsa = {};
|
||||
|
||||
ecdsa.verify = function verify(curve, msg, alg, key, sig) {
|
||||
ecdsa.verify = function verify(curve, alg, msg, key, sig) {
|
||||
var ec, hash;
|
||||
|
||||
assert(curve, 'No curve selected.');
|
||||
|
||||
ec = elliptic.ec(curve);
|
||||
hash = crypto.hash(alg, msg);
|
||||
hash = backend.hash(alg, msg);
|
||||
|
||||
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;
|
||||
|
||||
assert(curve, 'No curve selected.');
|
||||
|
||||
ec = elliptic.ec(curve);
|
||||
hash = crypto.hash(alg, msg);
|
||||
hash = backend.hash(alg, msg);
|
||||
|
||||
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
|
||||
*/
|
||||
@ -178,6 +324,44 @@ function leftpad(input, size) {
|
||||
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
|
||||
*/
|
||||
|
||||
@ -9,7 +9,8 @@
|
||||
var assert = require('assert');
|
||||
var PEM = require('../utils/pem');
|
||||
var elliptic = require('elliptic');
|
||||
var crypto = require('./crypto');
|
||||
var util = require('../utils/util');
|
||||
var backend = require('./backend');
|
||||
var nodeCrypto = require('crypto');
|
||||
var dsa, rsa, ecdsa;
|
||||
|
||||
@ -29,6 +30,9 @@ dsa.sign = function _sign(alg, msg, key, params) {
|
||||
return sign('dsa', alg, msg, pem);
|
||||
};
|
||||
|
||||
dsa.verifyAsync = util.promisify(dsa.verify);
|
||||
dsa.signAsync = util.promisify(dsa.sign);
|
||||
|
||||
/*
|
||||
* RSA
|
||||
*/
|
||||
@ -45,6 +49,9 @@ rsa.sign = function _sign(alg, msg, key) {
|
||||
return sign('rsa', alg, msg, pem);
|
||||
};
|
||||
|
||||
rsa.verifyAsync = util.promisify(rsa.verify);
|
||||
rsa.signAsync = util.promisify(rsa.sign);
|
||||
|
||||
/*
|
||||
* ECDSA
|
||||
*/
|
||||
@ -57,7 +64,7 @@ ecdsa.verify = function verify(curve, msg, alg, key, sig) {
|
||||
assert(curve, 'No curve selected.');
|
||||
|
||||
ec = elliptic.ec(curve);
|
||||
hash = crypto.hash(alg, msg);
|
||||
hash = backend.hash(alg, msg);
|
||||
|
||||
return ec.verify(hash, sig, key);
|
||||
};
|
||||
@ -68,11 +75,14 @@ ecdsa.sign = function sign(curve, msg, alg, key) {
|
||||
assert(curve, 'No curve selected.');
|
||||
|
||||
ec = elliptic.ec(curve);
|
||||
hash = crypto.hash(alg, msg);
|
||||
hash = backend.hash(alg, msg);
|
||||
|
||||
return new Buffer(ec.sign(hash, key));
|
||||
};
|
||||
|
||||
ecdsa.verifyAsync = util.promisify(ecdsa.verify);
|
||||
ecdsa.signAsync = util.promisify(ecdsa.sign);
|
||||
|
||||
/*
|
||||
* Helpers
|
||||
*/
|
||||
|
||||
@ -10,7 +10,7 @@ var BN = require('bn.js');
|
||||
var elliptic = require('elliptic');
|
||||
var Signature = require('elliptic/lib/elliptic/ec/signature');
|
||||
var hmacDRBG = require('elliptic/lib/elliptic/hmac-drbg');
|
||||
var sha256 = require('./crypto').sha256;
|
||||
var sha256 = require('./backend').sha256;
|
||||
var secp256k1 = elliptic.ec('secp256k1');
|
||||
var curve = secp256k1.curve;
|
||||
var curves = elliptic.curves;
|
||||
|
||||
@ -33,10 +33,11 @@
|
||||
|
||||
'use strict';
|
||||
|
||||
var util = require('../utils/util');
|
||||
var crypto = require('./crypto');
|
||||
var co = require('../utils/co');
|
||||
var backend = require('./backend');
|
||||
var native = require('../utils/native').binding;
|
||||
var U32Array = typeof Uint32Array === 'function' ? Uint32Array : Array;
|
||||
var scryptAsync, smix;
|
||||
|
||||
/**
|
||||
* Javascript scrypt implementation. Scrypt is
|
||||
@ -51,35 +52,28 @@ var U32Array = typeof Uint32Array === 'function' ? Uint32Array : Array;
|
||||
* @returns {Buffer}
|
||||
*/
|
||||
|
||||
function scryptAsync(passwd, salt, N, r, p, len, callback) {
|
||||
var V, XY;
|
||||
scryptAsync = co(function* scryptAsync(passwd, salt, N, r, p, len) {
|
||||
var i, B, V, XY;
|
||||
|
||||
if (r * p >= (1 << 30))
|
||||
return callback(new Error('EFBIG'));
|
||||
throw new Error('EFBIG');
|
||||
|
||||
if ((N & (N - 1)) !== 0 || N === 0)
|
||||
return callback(new Error('EINVAL'));
|
||||
throw new Error('EINVAL');
|
||||
|
||||
if (N > 0xffffffff)
|
||||
return callback(new Error('EINVAL'));
|
||||
throw new Error('EINVAL');
|
||||
|
||||
XY = new Buffer(256 * r);
|
||||
V = new Buffer(128 * r * N);
|
||||
|
||||
crypto.pbkdf2Async(passwd, salt, 1, p * 128 * r, 'sha256', function(err, B) {
|
||||
if (err)
|
||||
return callback(err);
|
||||
B = yield backend.pbkdf2Async(passwd, salt, 1, p * 128 * r, 'sha256');
|
||||
|
||||
forRangeSerial(0, p, function(i, next) {
|
||||
smix(B, i * 128 * r, r, N, V, XY, next);
|
||||
}, function(err) {
|
||||
if (err)
|
||||
return callback(err);
|
||||
for (i = 0; i < p; i++)
|
||||
yield smix(B, i * 128 * r, r, N, V, XY);
|
||||
|
||||
crypto.pbkdf2Async(passwd, B, 1, len, 'sha256', callback);
|
||||
});
|
||||
});
|
||||
}
|
||||
return yield backend.pbkdf2Async(passwd, B, 1, len, 'sha256');
|
||||
});
|
||||
|
||||
if (native)
|
||||
scryptAsync = native.scryptAsync;
|
||||
@ -148,7 +142,7 @@ function R(a, 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 i;
|
||||
|
||||
@ -165,42 +159,35 @@ function blockmix_salsa8(B, Y, Yo, r, callback) {
|
||||
|
||||
for (i = 0; i < r; i++)
|
||||
blkcpy(B, Y, (i + r) * 64, Yo + (i * 2 + 1) * 64, 64);
|
||||
|
||||
util.nextTick(callback);
|
||||
}
|
||||
|
||||
function integerify(B, r) {
|
||||
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 Y = XY;
|
||||
var i;
|
||||
var j;
|
||||
|
||||
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);
|
||||
blockmix_salsa8(X, Y, 128 * r, r, next);
|
||||
}, function(err) {
|
||||
if (err)
|
||||
return callback(err);
|
||||
blockmix_salsa8(X, Y, 128 * r, r);
|
||||
yield co.wait();
|
||||
}
|
||||
|
||||
forRangeSerial(0, N, function(i, next) {
|
||||
j = integerify(X, r) & (N - 1);
|
||||
blkxor(X, V, 0, j * (128 * r), 128 * r);
|
||||
blockmix_salsa8(X, Y, 128 * r, r, next);
|
||||
}, function(err) {
|
||||
if (err)
|
||||
return callback(err);
|
||||
for (i = 0; i < N; i++) {
|
||||
j = integerify(X, r) & (N - 1);
|
||||
blkxor(X, V, 0, j * (128 * r), 128 * r);
|
||||
blockmix_salsa8(X, Y, 128 * r, r);
|
||||
yield co.wait();
|
||||
}
|
||||
|
||||
blkcpy(B, X, Bo, 0, 128 * r);
|
||||
|
||||
callback();
|
||||
});
|
||||
});
|
||||
}
|
||||
blkcpy(B, X, Bo, 0, 128 * r);
|
||||
});
|
||||
|
||||
function blkcpy(dest, src, s1, 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];
|
||||
}
|
||||
|
||||
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
|
||||
*/
|
||||
|
||||
@ -33,7 +33,7 @@
|
||||
|
||||
'use strict';
|
||||
|
||||
var crypto = require('./crypto');
|
||||
var backend = require('./backend');
|
||||
var native = require('../utils/native').binding;
|
||||
var U32Array = typeof Uint32Array === 'function' ? Uint32Array : Array;
|
||||
|
||||
@ -65,12 +65,12 @@ function scrypt(passwd, salt, N, r, p, len) {
|
||||
XY = new Buffer(256 * r);
|
||||
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++)
|
||||
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)
|
||||
|
||||
@ -135,14 +135,19 @@ Mnemonic.prototype.destroy = function destroy() {
|
||||
*/
|
||||
|
||||
Mnemonic.prototype.toSeed = function toSeed(passphrase) {
|
||||
var phrase, passwd;
|
||||
|
||||
if (!passphrase)
|
||||
passphrase = this.passphrase;
|
||||
|
||||
this.passphrase = passphrase;
|
||||
|
||||
phrase = nfkd(this.getPhrase());
|
||||
passwd = nfkd('mnemonic' + passphrase);
|
||||
|
||||
return crypto.pbkdf2(
|
||||
nfkd(this.getPhrase()),
|
||||
nfkd('mnemonic' + passphrase),
|
||||
new Buffer(phrase, 'utf8'),
|
||||
new Buffer(passwd, 'utf8'),
|
||||
2048, 64, 'sha512');
|
||||
};
|
||||
|
||||
|
||||
@ -349,7 +349,7 @@ CompactBlock.prototype.fromBlock = function fromBlock(block, witness, nonce) {
|
||||
this.totalTX = block.totalTX;
|
||||
|
||||
if (!nonce)
|
||||
nonce = util.nonce(true);
|
||||
nonce = util.nonce();
|
||||
|
||||
this.keyNonce = nonce;
|
||||
|
||||
|
||||
@ -7,7 +7,6 @@
|
||||
|
||||
'use strict';
|
||||
|
||||
var BN = require('bn.js');
|
||||
var constants = require('../protocol/constants');
|
||||
var util = require('../utils/util');
|
||||
var assert = require('assert');
|
||||
@ -122,7 +121,7 @@ function VersionPacket(options) {
|
||||
this.ts = time.now();
|
||||
this.recv = new NetworkAddress();
|
||||
this.from = new NetworkAddress();
|
||||
this.nonce = new BN(0);
|
||||
this.nonce = constants.ZERO_U64;
|
||||
this.agent = constants.USER_AGENT;
|
||||
this.height = 0;
|
||||
this.relay = true;
|
||||
@ -196,7 +195,7 @@ VersionPacket.prototype.toRaw = function toRaw(writer) {
|
||||
p.write64(this.ts);
|
||||
this.recv.toRaw(false, p);
|
||||
this.from.toRaw(false, p);
|
||||
p.writeU64(this.nonce);
|
||||
p.writeBytes(this.nonce);
|
||||
p.writeVarString(this.agent, 'ascii');
|
||||
p.write32(this.height);
|
||||
p.writeU8(this.relay ? 1 : 0);
|
||||
@ -278,7 +277,7 @@ VersionPacket.prototype.fromRaw = function fromRaw(data) {
|
||||
|
||||
if (p.left() > 0) {
|
||||
this.from.fromRaw(p, false);
|
||||
this.nonce = p.readU64();
|
||||
this.nonce = p.readBytes(8);
|
||||
}
|
||||
|
||||
if (p.left() > 0)
|
||||
@ -392,7 +391,7 @@ PingPacket.prototype.toRaw = function toRaw(writer) {
|
||||
var p = BufferWriter(writer);
|
||||
|
||||
if (this.nonce)
|
||||
p.writeU64(this.nonce);
|
||||
p.writeBytes(this.nonce);
|
||||
|
||||
if (!writer)
|
||||
p = p.render();
|
||||
@ -409,7 +408,7 @@ PingPacket.prototype.toRaw = function toRaw(writer) {
|
||||
PingPacket.prototype.fromRaw = function fromRaw(data) {
|
||||
var p = BufferReader(data);
|
||||
if (p.left() >= 8)
|
||||
this.nonce = p.readU64();
|
||||
this.nonce = p.readBytes(8);
|
||||
return this;
|
||||
};
|
||||
|
||||
@ -440,7 +439,7 @@ function PongPacket(nonce) {
|
||||
|
||||
Packet.call(this);
|
||||
|
||||
this.nonce = nonce || new BN(0);
|
||||
this.nonce = nonce || constants.ZERO_U64;
|
||||
}
|
||||
|
||||
util.inherits(PongPacket, Packet);
|
||||
@ -456,7 +455,7 @@ PongPacket.prototype.type = exports.types.PONG;
|
||||
PongPacket.prototype.toRaw = function toRaw(writer) {
|
||||
var p = BufferWriter(writer);
|
||||
|
||||
p.writeU64(this.nonce);
|
||||
p.writeBytes(this.nonce);
|
||||
|
||||
if (!writer)
|
||||
p = p.render();
|
||||
@ -472,7 +471,7 @@ PongPacket.prototype.toRaw = function toRaw(writer) {
|
||||
|
||||
PongPacket.prototype.fromRaw = function fromRaw(data) {
|
||||
var p = BufferReader(data);
|
||||
this.nonce = p.readU64();
|
||||
this.nonce = p.readBytes(8);
|
||||
return this;
|
||||
};
|
||||
|
||||
|
||||
@ -1439,7 +1439,7 @@ Peer.prototype._handleVersion = co(function* _handleVersion(version) {
|
||||
throw new Error('Peer sent a duplicate version.');
|
||||
|
||||
if (!this.network.selfConnect) {
|
||||
if (version.nonce.cmp(this.pool.localNonce) === 0) {
|
||||
if (util.equal(version.nonce, this.pool.localNonce)) {
|
||||
this.ignore();
|
||||
throw new Error('We connected to ourself. Oops.');
|
||||
}
|
||||
@ -1869,8 +1869,8 @@ Peer.prototype._handlePong = function _handlePong(packet) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (nonce.cmp(this.challenge) !== 0) {
|
||||
if (nonce.cmpn(0) === 0) {
|
||||
if (!util.equal(nonce, this.challenge)) {
|
||||
if (util.equal(nonce, constants.ZERO_U64)) {
|
||||
this.logger.debug('Peer sent a zero nonce (%s).', this.hostname);
|
||||
this.challenge = null;
|
||||
return;
|
||||
|
||||
@ -917,6 +917,9 @@ Pool.prototype._handleBlock = co(function* _handleBlock(block, peer) {
|
||||
// Fulfill the load request.
|
||||
requested = this.fulfill(block);
|
||||
|
||||
if (util.isBrowser)
|
||||
yield block.hashAsync();
|
||||
|
||||
// Someone is sending us blocks without
|
||||
// us requesting them.
|
||||
if (!requested) {
|
||||
@ -1330,6 +1333,9 @@ Pool.prototype.hasReject = function hasReject(hash) {
|
||||
Pool.prototype._handleTX = co(function* _handleTX(tx, peer) {
|
||||
var i, requested, missing;
|
||||
|
||||
if (util.isBrowser)
|
||||
yield tx.hashAsync();
|
||||
|
||||
// Fulfill the load request.
|
||||
requested = this.fulfill(tx);
|
||||
|
||||
|
||||
@ -10,6 +10,7 @@
|
||||
var assert = require('assert');
|
||||
var constants = require('../protocol/constants');
|
||||
var util = require('../utils/util');
|
||||
var co = require('../utils/co');
|
||||
var crypto = require('../crypto/crypto');
|
||||
var btcutils = require('../btc/utils');
|
||||
var VerifyResult = require('../btc/errors').VerifyResult;
|
||||
@ -160,6 +161,54 @@ AbstractBlock.prototype.hash = function hash(enc) {
|
||||
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.
|
||||
* @returns {Buffer}
|
||||
|
||||
@ -78,6 +78,22 @@ MemBlock.fromOptions = function 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.
|
||||
* @returns {Number}
|
||||
|
||||
@ -9,6 +9,7 @@
|
||||
|
||||
var assert = require('assert');
|
||||
var util = require('../utils/util');
|
||||
var co = require('../utils/co');
|
||||
var crypto = require('../crypto/crypto');
|
||||
var btcutils = require('../btc/utils');
|
||||
var Amount = require('../btc/amount');
|
||||
@ -241,6 +242,35 @@ TX.prototype.hash = function _hash(enc) {
|
||||
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
|
||||
* serialization, return the wtxid (normal
|
||||
|
||||
@ -698,6 +698,22 @@ exports.ZERO_SIG64 = new Buffer(''
|
||||
'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.
|
||||
* @const {String}
|
||||
|
||||
@ -595,7 +595,7 @@ BufferReader.prototype.readNullString = function readNullString(enc) {
|
||||
BufferReader.prototype.createChecksum = function createChecksum() {
|
||||
var start = this.stack[this.stack.length - 1] || 0;
|
||||
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 fs = require('fs');
|
||||
var os = require('os');
|
||||
var BN = require('bn.js');
|
||||
var util = exports;
|
||||
var Number, Math, Date;
|
||||
|
||||
@ -542,38 +541,14 @@ util.time = function time(date) {
|
||||
|
||||
/**
|
||||
* Create a 64 bit nonce.
|
||||
* @returns {BN}
|
||||
* @returns {Buffer}
|
||||
*/
|
||||
|
||||
util.nonce = function _nonce(buffer) {
|
||||
util.nonce = function _nonce() {
|
||||
var nonce = new Buffer(8);
|
||||
|
||||
nonce.writeUInt32LE((Math.random() * 0x100000000) >>> 0, 0, true);
|
||||
nonce.writeUInt32LE((Math.random() * 0x100000000) >>> 0, 4, true);
|
||||
|
||||
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;
|
||||
return nonce;
|
||||
};
|
||||
|
||||
/**
|
||||
@ -1015,3 +990,21 @@ util._paths = {};
|
||||
util.fastProp = function fastProp(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 STR: off += data.write(item[1], off, item[2]); break;
|
||||
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;
|
||||
case FILL:
|
||||
data.fill(item[1], off, off + item[2]);
|
||||
|
||||
@ -15,6 +15,12 @@ var BufferReader = require('../utils/reader');
|
||||
var BufferWriter = require('../utils/writer');
|
||||
var HD = require('../hd/hd');
|
||||
|
||||
/*
|
||||
* Constants
|
||||
*/
|
||||
|
||||
var BCOIN_SALT = new Buffer('bcoin', 'ascii');
|
||||
|
||||
/**
|
||||
* Master BIP32 key which can exist
|
||||
* in a timed out encrypted state.
|
||||
@ -234,11 +240,14 @@ MasterKey.prototype.stop = function stop() {
|
||||
*/
|
||||
|
||||
MasterKey.prototype.derive = function derive(passwd) {
|
||||
if (typeof passwd === 'string')
|
||||
passwd = new Buffer(passwd, 'utf8');
|
||||
|
||||
switch (this.alg) {
|
||||
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:
|
||||
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:
|
||||
return Promise.reject(new Error('Unknown algorithm: ' + this.alg));
|
||||
}
|
||||
|
||||
@ -41,7 +41,7 @@
|
||||
"elliptic": "6.3.2"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"bcoin-native": "0.0.9",
|
||||
"bcoin-native": "0.0.10",
|
||||
"leveldown": "1.5.0",
|
||||
"secp256k1": "3.2.0",
|
||||
"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) {
|
||||
var key, cipher;
|
||||
|
||||
@ -101,9 +133,14 @@ describe('AES', function() {
|
||||
var enchash2 = nencrypt(hash2, '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(enchash, enchash2);
|
||||
assert.deepEqual(dechash, dechash2);
|
||||
assert.deepEqual(dechash, dechash3);
|
||||
});
|
||||
|
||||
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() {
|
||||
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'), ''
|
||||
+ '77d6576238657b203b19ca42c18a0497f16b4844e3074ae8dfdffa3f'
|
||||
+ 'ede21442fcd0069ded0948f8326a753a0fc81f17e8d3e0fb2e0d3628'
|
||||
@ -13,7 +15,9 @@ describe('Scrypt', 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'), ''
|
||||
+ 'fdbabe1c9d3472007856e7190d01e9fe7c6ad7cbc8237830e773'
|
||||
+ '76634b3731622eaf30d92e22a3886ff109279d9830dac727afb9'
|
||||
@ -21,7 +25,9 @@ describe('Scrypt', 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'), ''
|
||||
+ '7023bdcb3afd7348461c06cd81fd38ebfda8fbba904f8e3ea9b54'
|
||||
+ '3f6545da1f2d5432955613f0fcf62d49705242a9af9e61e85dc0d'
|
||||
@ -30,7 +36,9 @@ describe('Scrypt', function() {
|
||||
|
||||
// Only enable if you want to wait a while.
|
||||
// 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'), ''
|
||||
// + '2101cb9b6a511aaeaddbbe09cf70f881ec568d574a2ffd4dabe5'
|
||||
// + 'ee9820adaa478e56fd8f4ba5d09ffa1c6d927c40f4c337304049'
|
||||
|
||||
Loading…
Reference in New Issue
Block a user