From d4cc22e1c56027442acef938518cc06ea7b3e0ca Mon Sep 17 00:00:00 2001 From: Christopher Jeffrey Date: Tue, 27 Jun 2017 06:34:22 -0700 Subject: [PATCH] refactor: crypto. --- bench/bech32.js | 4 +- bench/chacha.js | 11 +- bench/script.js | 4 +- bench/tx.js | 6 +- bench/walletdb.js | 4 +- browser/wsproxy.js | 4 +- examples/wallet.js | 4 +- lib/bip70/paymentrequest.js | 4 +- lib/bip70/x509.js | 6 +- lib/blockchain/chainentry.js | 4 +- lib/crypto/aead.js | 174 ++++ lib/crypto/aes-browser.js | 1329 ++++++++++++++++++++++++++++++ lib/crypto/aes.js | 1367 +------------------------------ lib/crypto/backend-browser.js | 177 ---- lib/crypto/backend.js | 102 --- lib/crypto/bn.js | 10 + lib/crypto/ccmp.js | 39 + lib/crypto/chacha20.js | 209 +++++ lib/crypto/chachapoly.js | 667 --------------- lib/crypto/cleanse.js | 34 + lib/crypto/crypto.js | 451 ---------- lib/crypto/digest-browser.js | 105 +++ lib/crypto/digest.js | 98 +++ lib/crypto/ecdsa.js | 6 +- lib/crypto/hkdf.js | 65 ++ lib/crypto/hmac-drbg.js | 16 +- lib/crypto/index.js | 373 +-------- lib/crypto/merkle.js | 164 ++++ lib/crypto/pbkdf2-browser.js | 108 +++ lib/crypto/pbkdf2.js | 44 + lib/crypto/poly1305.js | 309 +++++++ lib/crypto/random-browser.js | 64 ++ lib/crypto/random.js | 44 + lib/crypto/rsa-browser.js | 11 +- lib/crypto/schnorr.js | 2 +- lib/crypto/scrypt.js | 125 ++- lib/crypto/secp256k1-native.js | 4 +- lib/hd/index.js | 6 + lib/hd/mnemonic.js | 15 +- lib/hd/private.js | 22 +- lib/hd/public.js | 15 +- lib/http/base.js | 21 +- lib/http/rpc.js | 11 +- lib/http/server.js | 10 +- lib/mempool/mempool.js | 4 +- lib/mining/mine.js | 4 +- lib/mining/template.js | 15 +- lib/net/bip150.js | 18 +- lib/net/bip151.js | 29 +- lib/net/bip152.js | 4 +- lib/net/framer.js | 4 +- lib/net/parser.js | 4 +- lib/net/proxysocket.js | 4 +- lib/primitives/abstractblock.js | 4 +- lib/primitives/address.js | 12 +- lib/primitives/block.js | 9 +- lib/primitives/keyring.js | 6 +- lib/primitives/merkleblock.js | 6 +- lib/primitives/tx.js | 18 +- lib/script/script.js | 29 +- lib/utils/gcs.js | 6 +- lib/utils/reader.js | 4 +- lib/utils/staticwriter.js | 4 +- lib/utils/writer.js | 4 +- lib/wallet/http.js | 10 +- lib/wallet/masterkey.js | 28 +- lib/wallet/rpc.js | 4 +- lib/wallet/wallet.js | 15 +- lib/wallet/walletdb.js | 9 +- lib/workers/jobs.js | 2 +- migrate/ensure-tip-index.js | 4 +- package.json | 7 +- scripts/fuzz.js | 43 +- test/aes-test.js | 23 +- test/chachapoly-test.js | 7 +- test/gcs-test.js | 4 +- test/hd-test.js | 4 +- test/mempool-test.js | 14 +- test/scrypt-test.js | 10 +- test/tx-test.js | 4 +- test/utils-test.js | 13 +- test/wallet-test.js | 9 +- 82 files changed, 3228 insertions(+), 3418 deletions(-) create mode 100644 lib/crypto/aead.js create mode 100644 lib/crypto/aes-browser.js delete mode 100644 lib/crypto/backend-browser.js delete mode 100644 lib/crypto/backend.js create mode 100644 lib/crypto/ccmp.js create mode 100644 lib/crypto/chacha20.js delete mode 100644 lib/crypto/chachapoly.js create mode 100644 lib/crypto/cleanse.js delete mode 100644 lib/crypto/crypto.js create mode 100644 lib/crypto/digest-browser.js create mode 100644 lib/crypto/digest.js create mode 100644 lib/crypto/hkdf.js create mode 100644 lib/crypto/merkle.js create mode 100644 lib/crypto/pbkdf2-browser.js create mode 100644 lib/crypto/pbkdf2.js create mode 100644 lib/crypto/poly1305.js create mode 100644 lib/crypto/random-browser.js create mode 100644 lib/crypto/random.js diff --git a/bench/bech32.js b/bench/bech32.js index 34aeb353..1d169e1e 100644 --- a/bench/bech32.js +++ b/bench/bech32.js @@ -1,7 +1,7 @@ 'use strict'; var Address = require('../lib/primitives/address'); -var crypto = require('../lib/crypto/crypto'); +var random = require('../lib/crypto/random'); var bench = require('./bench'); var i, end, addr; @@ -10,7 +10,7 @@ var addrs = []; end = bench('serialize'); for (i = 0; i < 100000; i++) { - addr = Address.fromProgram(0, crypto.randomBytes(20)); + addr = Address.fromProgram(0, random.randomBytes(20)); addrs.push(addr.toBech32()); } end(i); diff --git a/bench/chacha.js b/bench/chacha.js index 9d1f2673..5163cd8d 100644 --- a/bench/chacha.js +++ b/bench/chacha.js @@ -1,13 +1,14 @@ 'use strict'; -var chachapoly = require('../lib/crypto/chachapoly'); -var crypto = require('../lib/crypto/crypto'); +var ChaCha20 = require('../lib/crypto/chacha20'); +var Poly1305 = require('../lib/crypto/poly1305'); +var digest = require('../lib/crypto/digest'); var bench = require('./bench'); var i, chacha, iv, poly, key, data, end; console.log('note: rate measured in kb/s'); -chacha = new chachapoly.ChaCha20(); +chacha = new ChaCha20(); key = Buffer.allocUnsafe(32); key.fill(2); iv = Buffer.from('0102030405060708', 'hex'); @@ -20,7 +21,7 @@ for (i = 0; i < 1000000; i++) chacha.encrypt(data); end(i * 32 / 1024); -poly = new chachapoly.Poly1305(); +poly = new Poly1305(); key = Buffer.allocUnsafe(32); key.fill(2); poly.init(key); @@ -45,5 +46,5 @@ end(i * 32 / 1024); // For reference: end = bench('sha256'); for (i = 0; i < 1000000; i++) - crypto.hash256(data); + digest.hash256(data); end(i * 32 / 1024); diff --git a/bench/script.js b/bench/script.js index 43d985b3..2f01efef 100644 --- a/bench/script.js +++ b/bench/script.js @@ -1,7 +1,7 @@ 'use strict'; var assert = require('assert'); -var crypto = require('../lib/crypto/crypto'); +var random = require('../lib/crypto/random'); var Script = require('../lib/script/script'); var bench = require('./bench'); var opcodes = Script.opcodes; @@ -24,7 +24,7 @@ Script.fromPubkeyhashOld = function fromScripthash(hash) { hashes = []; for (i = 0; i < 100000; i++) - hashes.push(crypto.randomBytes(20)); + hashes.push(random.randomBytes(20)); end = bench('old'); for (i = 0; i < hashes.length; i++) diff --git a/bench/tx.js b/bench/tx.js index f640ba70..e4996b8e 100644 --- a/bench/tx.js +++ b/bench/tx.js @@ -9,7 +9,7 @@ var MTX = require('../lib/primitives/mtx'); var Coin = require('../lib/primitives/coin'); var CoinView = require('../lib/coins/coinview'); var encoding = require('../lib/utils/encoding'); -var crypto = require('../lib/crypto/crypto'); +var random = require('../lib/crypto/random'); var bench = require('./bench'); var json = require('../test/data/block300025.json'); @@ -117,11 +117,11 @@ for (i = 0; i < 100; i++) { }, script: [ Buffer.allocUnsafe(9), - crypto.randomBytes(33) + random.randomBytes(33) ] }); tx.addOutput({ - address: Address.fromHash(crypto.randomBytes(20)), + address: Address.fromHash(random.randomBytes(20)), value: 0 }); } diff --git a/bench/walletdb.js b/bench/walletdb.js index 8f076f0b..e2547495 100644 --- a/bench/walletdb.js +++ b/bench/walletdb.js @@ -1,14 +1,14 @@ 'use strict'; var bench = require('./bench'); -var crypto = require('../lib/crypto/crypto'); +var random = require('../lib/crypto/random'); var WalletDB = require('../lib/wallet/walletdb'); var MTX = require('../lib/primitives/mtx'); var Outpoint = require('../lib/primitives/outpoint'); var walletdb; function dummy() { - var hash = crypto.randomBytes(32).toString('hex'); + var hash = random.randomBytes(32).toString('hex'); return new Outpoint(hash, 0); } diff --git a/browser/wsproxy.js b/browser/wsproxy.js index 46807708..80b27a04 100644 --- a/browser/wsproxy.js +++ b/browser/wsproxy.js @@ -4,7 +4,7 @@ var net = require('net'); var EventEmitter = require('events').EventEmitter; var IOServer = require('socket.io'); var util = require('../lib/utils/util'); -var crypto = require('../lib/crypto/crypto'); +var digest = require('../lib/crypto/digest'); var IP = require('../lib/utils/ip'); var BufferWriter = require('../lib/utils/writer'); @@ -100,7 +100,7 @@ WSProxy.prototype._handleConnect = function _handleConnect(ws, port, host, nonce pow.writeString(host, 'ascii'); pow = pow.render(); - if (crypto.hash256(pow).compare(this.target) > 0) { + if (digest.hash256(pow).compare(this.target) > 0) { this.log('Client did not solve proof of work (%s).', state.host); ws.emit('tcp close'); ws.disconnect(); diff --git a/examples/wallet.js b/examples/wallet.js index dbec0667..f0043c79 100644 --- a/examples/wallet.js +++ b/examples/wallet.js @@ -1,13 +1,13 @@ 'use strict'; -var crypto = require('bcoin/lib/crypto/crypto'); +var random = require('bcoin/lib/crypto/random'); var WalletDB = require('bcoin/lib/wallet/walletdb'); var MTX = require('bcoin/lib/primitives/mtx'); var Outpoint = require('bcoin/lib/primitives/outpoint'); var walletdb; function dummy() { - var hash = crypto.randomBytes(32).toString('hex'); + var hash = random.randomBytes(32).toString('hex'); return new Outpoint(hash, 0); } diff --git a/lib/bip70/paymentrequest.js b/lib/bip70/paymentrequest.js index ddc3b498..da510ab0 100644 --- a/lib/bip70/paymentrequest.js +++ b/lib/bip70/paymentrequest.js @@ -8,7 +8,7 @@ var assert = require('assert'); var util = require('../utils/util'); -var crypto = require('../crypto/crypto'); +var digest = require('../crypto/digest'); var x509 = require('./x509'); var PEM = require('../utils/pem'); var protobuf = require('../utils/protobuf'); @@ -195,7 +195,7 @@ PaymentRequest.prototype.signatureData = function signatureData() { PaymentRequest.prototype.signatureHash = function signatureHash() { var alg = this.getAlgorithm(); - return crypto.hash(alg.hash, this.signatureData()); + return digest.hash(alg.hash, this.signatureData()); }; /** diff --git a/lib/bip70/x509.js b/lib/bip70/x509.js index ed7631e1..064478d6 100644 --- a/lib/bip70/x509.js +++ b/lib/bip70/x509.js @@ -10,7 +10,7 @@ var assert = require('assert'); var ASN1 = require('../utils/asn1'); var PEM = require('../utils/pem'); var util = require('../utils/util'); -var crypto = require('../crypto/crypto'); +var digest = require('../crypto/digest'); var pk = require('./pk'); var certs = require('./certs'); @@ -127,7 +127,7 @@ x509.getCAName = function getCAName(cert) { */ x509.isTrusted = function isTrusted(cert) { - var fingerprint = crypto.sha256(cert.raw); + var fingerprint = digest.sha256(cert.raw); var hash = fingerprint.toString('hex'); return x509.trusted[hash] === true; }; @@ -155,7 +155,7 @@ x509.setTrust = function setTrust(certs) { cert = x509.parse(cert); - hash = crypto.sha256(cert.raw); + hash = digest.sha256(cert.raw); hash = hash.toString('hex'); x509.trusted[hash] = true; diff --git a/lib/blockchain/chainentry.js b/lib/blockchain/chainentry.js index f76f092c..078865eb 100644 --- a/lib/blockchain/chainentry.js +++ b/lib/blockchain/chainentry.js @@ -11,7 +11,7 @@ var assert = require('assert'); var BN = require('../crypto/bn'); var consensus = require('../protocol/consensus'); var util = require('../utils/util'); -var crypto = require('../crypto/crypto'); +var digest = require('../crypto/digest'); var encoding = require('../utils/encoding'); var BufferReader = require('../utils/reader'); var StaticWriter = require('../utils/staticwriter'); @@ -405,7 +405,7 @@ ChainEntry.prototype.toRaw = function toRaw() { ChainEntry.prototype.fromRaw = function fromRaw(data) { var br = new BufferReader(data, true); - var hash = crypto.hash256(br.readBytes(80)); + var hash = digest.hash256(br.readBytes(80)); br.seek(-80); diff --git a/lib/crypto/aead.js b/lib/crypto/aead.js new file mode 100644 index 00000000..1fc8ef37 --- /dev/null +++ b/lib/crypto/aead.js @@ -0,0 +1,174 @@ +/*! + * aead.js - aead for bcoin + * Copyright (c) 2016-2017, Christopher Jeffrey (MIT License). + * https://github.com/bcoin-org/bcoin + */ + +'use strict'; + +var assert = require('assert'); +var ChaCha20 = require('./chacha20'); +var Poly1305 = require('./poly1305'); + +/** + * AEAD (used for bip151) + * @alias module:crypto.AEAD + * @constructor + * @see https://github.com/openssh/openssh-portable + * @see https://tools.ietf.org/html/rfc7539#section-2.8 + */ + +function AEAD() { + if (!(this instanceof AEAD)) + return new AEAD(); + + this.chacha20 = new ChaCha20(); + this.poly1305 = new Poly1305(); + this.aadLen = 0; + this.cipherLen = 0; + this.polyKey = null; +} + +/** + * Initialize the AEAD with a key and iv. + * @param {Buffer} key + * @param {Buffer} iv - IV / packet sequence number. + */ + +AEAD.prototype.init = function init(key, iv) { + var polyKey = Buffer.allocUnsafe(32); + polyKey.fill(0); + + this.chacha20.init(key, iv); + this.chacha20.encrypt(polyKey); + this.poly1305.init(polyKey); + + // We need to encrypt a full block + // to get the cipher in the correct state. + this.chacha20.encrypt(Buffer.allocUnsafe(32)); + + // Counter should be one. + assert(this.chacha20.getCounter() === 1); + + // Expose for debugging. + this.polyKey = polyKey; + + this.aadLen = 0; + this.cipherLen = 0; +}; + +/** + * Update the aad (will be finalized + * on an encrypt/decrypt call). + * @param {Buffer} aad + */ + +AEAD.prototype.aad = function _aad(aad) { + assert(this.cipherLen === 0, 'Cannot update aad.'); + this.poly1305.update(aad); + this.aadLen += aad.length; +}; + +/** + * Encrypt a piece of data. + * @param {Buffer} data + */ + +AEAD.prototype.encrypt = function encrypt(data) { + if (this.cipherLen === 0) + this.pad16(this.aadLen); + + this.chacha20.encrypt(data); + this.poly1305.update(data); + this.cipherLen += data.length; + + return data; +}; + +/** + * Decrypt a piece of data. + * @param {Buffer} data + */ + +AEAD.prototype.decrypt = function decrypt(data) { + if (this.cipherLen === 0) + this.pad16(this.aadLen); + + this.cipherLen += data.length; + this.poly1305.update(data); + this.chacha20.encrypt(data); + + return data; +}; + +/** + * Authenticate data without decrypting. + * @param {Buffer} data + */ + +AEAD.prototype.auth = function auth(data) { + if (this.cipherLen === 0) + this.pad16(this.aadLen); + + this.cipherLen += data.length; + this.poly1305.update(data); + + return data; +}; + +/** + * Finalize the aead and generate a MAC. + * @returns {Buffer} MAC + */ + +AEAD.prototype.finish = function finish() { + var len = Buffer.allocUnsafe(16); + var lo, hi; + + // The RFC says these are supposed to be + // uint32le, but their own fucking test + // cases fail unless they are uint64le's. + lo = this.aadLen % 0x100000000; + hi = (this.aadLen - lo) / 0x100000000; + len.writeUInt32LE(lo, 0, true); + len.writeUInt32LE(hi, 4, true); + + lo = this.cipherLen % 0x100000000; + hi = (this.cipherLen - lo) / 0x100000000; + len.writeUInt32LE(lo, 8, true); + len.writeUInt32LE(hi, 12, true); + + if (this.cipherLen === 0) + this.pad16(this.aadLen); + + this.pad16(this.cipherLen); + this.poly1305.update(len); + + return this.poly1305.finish(); +}; + +/** + * Pad a chunk before updating mac. + * @private + * @param {Number} size + */ + +AEAD.prototype.pad16 = function pad16(size) { + var pad; + + size %= 16; + + if (size === 0) + return; + + pad = Buffer.allocUnsafe(16 - size); + pad.fill(0); + + this.poly1305.update(pad); +}; + +/* + * Expose + */ + +module.exports = AEAD; diff --git a/lib/crypto/aes-browser.js b/lib/crypto/aes-browser.js new file mode 100644 index 00000000..3848311c --- /dev/null +++ b/lib/crypto/aes-browser.js @@ -0,0 +1,1329 @@ +/*! + * aes.js - aes128/192/256 for bcoin + * Copyright (c) 2016-2017, Christopher Jeffrey (MIT License). + * https://github.com/bcoin-org/bcoin + * + * Ported from: + * https://github.com/openssl/openssl/blob/master/crypto/aes/aes_core.c + * Entered into the public domain by Vincent Rijmen. + */ + +'use strict'; + +var assert = require('assert'); + +/** + * @exports crypto.aes-browser + * @ignore + */ + +var AES = exports; + +/** + * An AES key object for encrypting + * and decrypting blocks. + * @constructor + * @ignore + * @param {Buffer} key + * @param {Number} bits + */ + +function AESKey(key, bits) { + if (!(this instanceof AESKey)) + return new AESKey(key, bits); + + this.rounds = null; + this.userKey = key; + this.bits = bits; + + 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; +} + +/** + * Destroy the object and zero the keys. + */ + +AESKey.prototype.destroy = function destroy() { + var i; + + assert(this.userKey, 'Already destroyed.'); + + // User should zero this. + this.userKey = null; + + if (this.decryptKey) { + for (i = 0; i < this.decryptKey.length; i++) + this.decryptKey[i] = 0; + this.decryptKey = null; + } + + if (this.encryptKey) { + for (i = 0; i < this.encryptKey.length; i++) + this.encryptKey[i] = 0; + this.encryptKey = null; + } +}; + +/** + * Convert the user key into an encryption key. + * @returns {Uint32Array} key + */ + +AESKey.prototype.getEncryptKey = function getEncryptKey() { + var i = 0; + var key, kp, tmp; + + assert(this.userKey, 'Cannot use key once it is destroyed.'); + + if (this.encryptKey) + return this.encryptKey; + + key = new Uint32Array(60); + kp = 0; + + key[kp + 0] = readU32(this.userKey, 0); + key[kp + 1] = readU32(this.userKey, 4); + key[kp + 2] = readU32(this.userKey, 8); + key[kp + 3] = readU32(this.userKey, 12); + + this.encryptKey = key; + + if (this.bits === 128) { + for (;;) { + tmp = key[kp + 3]; + + key[kp + 4] = key[kp + 0] + ^ (TE2[(tmp >>> 16) & 0xff] & 0xff000000) + ^ (TE3[(tmp >>> 8) & 0xff] & 0x00ff0000) + ^ (TE0[(tmp >>> 0) & 0xff] & 0x0000ff00) + ^ (TE1[(tmp >>> 24) & 0xff] & 0x000000ff) + ^ RCON[i]; + key[kp + 5] = key[kp + 1] ^ key[kp + 4]; + key[kp + 6] = key[kp + 2] ^ key[kp + 5]; + key[kp + 7] = key[kp + 3] ^ key[kp + 6]; + + if (++i === 10) + return key; + + kp += 4; + } + } + + key[kp + 4] = readU32(this.userKey, 16); + key[kp + 5] = readU32(this.userKey, 20); + + if (this.bits === 192) { + for (;;) { + tmp = key[kp + 5]; + + key[kp + 6] = key[kp + 0] + ^ (TE2[(tmp >>> 16) & 0xff] & 0xff000000) + ^ (TE3[(tmp >>> 8) & 0xff] & 0x00ff0000) + ^ (TE0[(tmp >>> 0) & 0xff] & 0x0000ff00) + ^ (TE1[(tmp >>> 24) & 0xff] & 0x000000ff) + ^ RCON[i]; + key[kp + 7] = key[kp + 1] ^ key[kp + 6]; + key[kp + 8] = key[kp + 2] ^ key[kp + 7]; + key[kp + 9] = key[kp + 3] ^ key[kp + 8]; + + if (++i === 8) + return key; + + key[kp + 10] = key[kp + 4] ^ key[kp + 9]; + key[kp + 11] = key[kp + 5] ^ key[kp + 10]; + kp += 6; + } + } + + key[kp + 6] = readU32(this.userKey, 24); + key[kp + 7] = readU32(this.userKey, 28); + + if (this.bits === 256) { + for (;;) { + tmp = key[kp + 7]; + + key[kp + 8] = key[kp + 0] + ^ (TE2[(tmp >>> 16) & 0xff] & 0xff000000) + ^ (TE3[(tmp >>> 8) & 0xff] & 0x00ff0000) + ^ (TE0[(tmp >>> 0) & 0xff] & 0x0000ff00) + ^ (TE1[(tmp >>> 24) & 0xff] & 0x000000ff) + ^ RCON[i]; + key[kp + 9] = key[kp + 1] ^ key[kp + 8]; + key[kp + 10] = key[kp + 2] ^ key[kp + 9]; + key[kp + 11] = key[kp + 3] ^ key[kp + 10]; + + if (++i === 7) + return key; + + tmp = key[kp + 11]; + + key[kp + 12] = key[kp + 4] + ^ (TE2[(tmp >>> 24) & 0xff] & 0xff000000) + ^ (TE3[(tmp >>> 16) & 0xff] & 0x00ff0000) + ^ (TE0[(tmp >>> 8) & 0xff] & 0x0000ff00) + ^ (TE1[(tmp >>> 0) & 0xff] & 0x000000ff); + key[kp + 13] = key[kp + 5] ^ key[kp + 12]; + key[kp + 14] = key[kp + 6] ^ key[kp + 13]; + key[kp + 15] = key[kp + 7] ^ key[kp + 14]; + + kp += 8; + } + } + + return key; +}; + +/** + * Convert the user key into a decryption key. + * @returns {Uint32Array} key + */ + +AESKey.prototype.getDecryptKey = function getDecryptKey() { + var i, j, kp, enc, key, tmp; + + assert(this.userKey, 'Cannot use key once it is destroyed.'); + + if (this.decryptKey) + return this.decryptKey; + + // First, start with an encryption schedule. + enc = this.getEncryptKey(); + key = new Uint32Array(60); + kp = 0; + + for (i = 0; i < enc.length; i++) + key[i] = enc[i]; + + this.decryptKey = key; + + // Invert the order of the round keys. + for (i = 0, j = 4 * this.rounds; i < j; i += 4, j -= 4) { + tmp = key[kp + i + 0]; + key[kp + i + 0] = key[kp + j + 0]; + key[kp + j + 0] = tmp; + + tmp = key[kp + i + 1]; + key[kp + i + 1] = key[kp + j + 1]; + key[kp + j + 1] = tmp; + + tmp = key[kp + i + 2]; + key[kp + i + 2] = key[kp + j + 2]; + key[kp + j + 2] = tmp; + + tmp = key[kp + i + 3]; + key[kp + i + 3] = key[kp + j + 3]; + key[kp + j + 3] = tmp; + } + + // Apply the inverse MixColumn transform to + // all round keys but the first and the last. + for (i = 1; i < this.rounds; i++) { + kp += 4; + key[kp + 0] = TD0[TE1[(key[kp + 0] >>> 24) & 0xff] & 0xff] + ^ TD1[TE1[(key[kp + 0] >>> 16) & 0xff] & 0xff] + ^ TD2[TE1[(key[kp + 0] >>> 8) & 0xff] & 0xff] + ^ TD3[TE1[(key[kp + 0] >>> 0) & 0xff] & 0xff]; + key[kp + 1] = TD0[TE1[(key[kp + 1] >>> 24) & 0xff] & 0xff] + ^ TD1[TE1[(key[kp + 1] >>> 16) & 0xff] & 0xff] + ^ TD2[TE1[(key[kp + 1] >>> 8) & 0xff] & 0xff] + ^ TD3[TE1[(key[kp + 1] >>> 0) & 0xff] & 0xff]; + key[kp + 2] = TD0[TE1[(key[kp + 2] >>> 24) & 0xff] & 0xff] + ^ TD1[TE1[(key[kp + 2] >>> 16) & 0xff] & 0xff] + ^ TD2[TE1[(key[kp + 2] >>> 8) & 0xff] & 0xff] + ^ TD3[TE1[(key[kp + 2] >>> 0) & 0xff] & 0xff]; + key[kp + 3] = TD0[TE1[(key[kp + 3] >>> 24) & 0xff] & 0xff] + ^ TD1[TE1[(key[kp + 3] >>> 16) & 0xff] & 0xff] + ^ TD2[TE1[(key[kp + 3] >>> 8) & 0xff] & 0xff] + ^ TD3[TE1[(key[kp + 3] >>> 0) & 0xff] & 0xff]; + } + + return key; +}; + +/** + * Encrypt a 16 byte block of data. + * @param {Buffer} input + * @returns {Buffer} + */ + +AESKey.prototype.encryptBlock = function encryptBlock(input) { + var output, kp, key, r, s0, s1, s2, s3, t0, t1, t2, t3; + + assert(this.userKey, 'Cannot use key once it is destroyed.'); + + key = this.getEncryptKey(); + kp = 0; + + // Map byte array block to cipher + // state and add initial round key. + s0 = readU32(input, 0) ^ key[0]; + s1 = readU32(input, 4) ^ key[1]; + s2 = readU32(input, 8) ^ key[2]; + s3 = readU32(input, 12) ^ key[3]; + + // Nr - 1 full rounds + r = this.rounds >>> 1; + + for (;;) { + t0 = TE0[(s0 >>> 24) & 0xff] + ^ TE1[(s1 >>> 16) & 0xff] + ^ TE2[(s2 >>> 8) & 0xff] + ^ TE3[(s3 >>> 0) & 0xff] + ^ key[kp + 4]; + t1 = TE0[(s1 >>> 24) & 0xff] + ^ TE1[(s2 >>> 16) & 0xff] + ^ TE2[(s3 >>> 8) & 0xff] + ^ TE3[(s0 >>> 0) & 0xff] + ^ key[kp + 5]; + t2 = TE0[(s2 >>> 24) & 0xff] + ^ TE1[(s3 >>> 16) & 0xff] + ^ TE2[(s0 >>> 8) & 0xff] + ^ TE3[(s1 >>> 0) & 0xff] + ^ key[kp + 6]; + t3 = TE0[(s3 >>> 24) & 0xff] + ^ TE1[(s0 >>> 16) & 0xff] + ^ TE2[(s1 >>> 8) & 0xff] + ^ TE3[(s2 >>> 0) & 0xff] + ^ key[kp + 7]; + + kp += 8; + + if (--r === 0) + break; + + s0 = TE0[(t0 >>> 24) & 0xff] + ^ TE1[(t1 >>> 16) & 0xff] + ^ TE2[(t2 >>> 8) & 0xff] + ^ TE3[(t3 >>> 0) & 0xff] + ^ key[kp + 0]; + s1 = TE0[(t1 >>> 24) & 0xff] + ^ TE1[(t2 >>> 16) & 0xff] + ^ TE2[(t3 >>> 8) & 0xff] + ^ TE3[(t0 >>> 0) & 0xff] + ^ key[kp + 1]; + s2 = TE0[(t2 >>> 24) & 0xff] + ^ TE1[(t3 >>> 16) & 0xff] + ^ TE2[(t0 >>> 8) & 0xff] + ^ TE3[(t1 >>> 0) & 0xff] + ^ key[kp + 2]; + s3 = TE0[(t3 >>> 24) & 0xff] + ^ TE1[(t0 >>> 16) & 0xff] + ^ TE2[(t1 >>> 8) & 0xff] + ^ TE3[(t2 >>> 0) & 0xff] + ^ key[kp + 3]; + } + + // Apply last round and map cipher + // state to byte array block. + s0 = (TE2[(t0 >>> 24) & 0xff] & 0xff000000) + ^ (TE3[(t1 >>> 16) & 0xff] & 0x00ff0000) + ^ (TE0[(t2 >>> 8) & 0xff] & 0x0000ff00) + ^ (TE1[(t3 >>> 0) & 0xff] & 0x000000ff) + ^ key[kp + 0]; + s1 = (TE2[(t1 >>> 24) & 0xff] & 0xff000000) + ^ (TE3[(t2 >>> 16) & 0xff] & 0x00ff0000) + ^ (TE0[(t3 >>> 8) & 0xff] & 0x0000ff00) + ^ (TE1[(t0 >>> 0) & 0xff] & 0x000000ff) + ^ key[kp + 1]; + s2 = (TE2[(t2 >>> 24) & 0xff] & 0xff000000) + ^ (TE3[(t3 >>> 16) & 0xff] & 0x00ff0000) + ^ (TE0[(t0 >>> 8) & 0xff] & 0x0000ff00) + ^ (TE1[(t1 >>> 0) & 0xff] & 0x000000ff) + ^ key[kp + 2]; + s3 = (TE2[(t3 >>> 24) & 0xff] & 0xff000000) + ^ (TE3[(t0 >>> 16) & 0xff] & 0x00ff0000) + ^ (TE0[(t1 >>> 8) & 0xff] & 0x0000ff00) + ^ (TE1[(t2 >>> 0) & 0xff] & 0x000000ff) + ^ key[kp + 3]; + + output = Buffer.allocUnsafe(16); + writeU32(output, s0, 0); + writeU32(output, s1, 4); + writeU32(output, s2, 8); + writeU32(output, s3, 12); + + return output; +}; + +/** + * Decrypt a 16 byte block of data. + * @param {Buffer} input + * @returns {Buffer} + */ + +AESKey.prototype.decryptBlock = function decryptBlock(input) { + var output, kp, key, r, s0, s1, s2, s3, t0, t1, t2, t3; + + assert(this.userKey, 'Cannot use AESKey once it is destroyed.'); + + key = this.getDecryptKey(); + kp = 0; + + // Map byte array block to cipher + // state and add initial round key. + s0 = readU32(input, 0) ^ key[kp + 0]; + s1 = readU32(input, 4) ^ key[kp + 1]; + s2 = readU32(input, 8) ^ key[kp + 2]; + s3 = readU32(input, 12) ^ key[kp + 3]; + + // Nr - 1 full rounds + r = this.rounds >>> 1; + + for (;;) { + t0 = TD0[(s0 >>> 24) & 0xff] + ^ TD1[(s3 >>> 16) & 0xff] + ^ TD2[(s2 >>> 8) & 0xff] + ^ TD3[(s1 >>> 0) & 0xff] + ^ key[kp + 4]; + t1 = TD0[(s1 >>> 24) & 0xff] + ^ TD1[(s0 >>> 16) & 0xff] + ^ TD2[(s3 >>> 8) & 0xff] + ^ TD3[(s2 >>> 0) & 0xff] + ^ key[kp + 5]; + t2 = TD0[(s2 >>> 24) & 0xff] + ^ TD1[(s1 >>> 16) & 0xff] + ^ TD2[(s0 >>> 8) & 0xff] + ^ TD3[(s3 >>> 0) & 0xff] + ^ key[kp + 6]; + t3 = TD0[(s3 >>> 24) & 0xff] + ^ TD1[(s2 >>> 16) & 0xff] + ^ TD2[(s1 >>> 8) & 0xff] + ^ TD3[(s0 >>> 0) & 0xff] + ^ key[kp + 7]; + + kp += 8; + + if (--r === 0) + break; + + s0 = TD0[(t0 >>> 24) & 0xff] + ^ TD1[(t3 >>> 16) & 0xff] + ^ TD2[(t2 >>> 8) & 0xff] + ^ TD3[(t1 >>> 0) & 0xff] + ^ key[kp + 0]; + s1 = TD0[(t1 >>> 24) & 0xff] + ^ TD1[(t0 >>> 16) & 0xff] + ^ TD2[(t3 >>> 8) & 0xff] + ^ TD3[(t2 >>> 0) & 0xff] + ^ key[kp + 1]; + s2 = TD0[(t2 >>> 24) & 0xff] + ^ TD1[(t1 >>> 16) & 0xff] + ^ TD2[(t0 >>> 8) & 0xff] + ^ TD3[(t3 >>> 0) & 0xff] + ^ key[kp + 2]; + s3 = TD0[(t3 >>> 24) & 0xff] + ^ TD1[(t2 >>> 16) & 0xff] + ^ TD2[(t1 >>> 8) & 0xff] + ^ TD3[(t0 >>> 0) & 0xff] + ^ key[kp + 3]; + } + + // Apply last round and map cipher + // state to byte array block. + s0 = (TD4[(t0 >>> 24) & 0xff] << 24) + ^ (TD4[(t3 >>> 16) & 0xff] << 16) + ^ (TD4[(t2 >>> 8) & 0xff] << 8) + ^ (TD4[(t1 >>> 0) & 0xff] << 0) + ^ key[kp + 0]; + s1 = (TD4[(t1 >>> 24) & 0xff] << 24) + ^ (TD4[(t0 >>> 16) & 0xff] << 16) + ^ (TD4[(t3 >>> 8) & 0xff] << 8) + ^ (TD4[(t2 >>> 0) & 0xff] << 0) + ^ key[kp + 1]; + s2 = (TD4[(t2 >>> 24) & 0xff] << 24) + ^ (TD4[(t1 >>> 16) & 0xff] << 16) + ^ (TD4[(t0 >>> 8) & 0xff] << 8) + ^ (TD4[(t3 >>> 0) & 0xff] << 0) + ^ key[kp + 2]; + s3 = (TD4[(t3 >>> 24) & 0xff] << 24) + ^ (TD4[(t2 >>> 16) & 0xff] << 16) + ^ (TD4[(t1 >>> 8) & 0xff] << 8) + ^ (TD4[(t0 >>> 0) & 0xff] << 0) + ^ key[kp + 3]; + + output = Buffer.allocUnsafe(16); + writeU32(output, s0, 0); + writeU32(output, s1, 4); + writeU32(output, s2, 8); + writeU32(output, s3, 12); + + return output; +}; + +/** + * AES cipher. + * @constructor + * @ignore + * @param {Buffer} key + * @param {Buffer} iv + * @param {Number} bits + * @param {String} mode + */ + +function AESCipher(key, iv, bits, mode) { + if (!(this instanceof AESCipher)) + return new AESCipher(key, iv, mode); + + assert(mode === 'ecb' || mode === 'cbc', 'Unknown mode.'); + + this.key = new AESKey(key, bits); + this.mode = mode; + this.prev = iv; + this.waiting = null; +} + +/** + * Encrypt blocks of data. + * @param {Buffer} data + * @returns {Buffer} + */ + +AESCipher.prototype.update = function update(data) { + var blocks = []; + var i, len, trailing, block; + + if (this.waiting) { + data = concat(this.waiting, data); + this.waiting = null; + } + + trailing = data.length % 16; + len = data.length - trailing; + + // Encrypt all blocks except for the last. + for (i = 0; i < len; i += 16) { + block = data.slice(i, i + 16); + if (this.mode === 'cbc') + block = xor(block, this.prev); + this.prev = this.key.encryptBlock(block); + blocks.push(this.prev); + } + + if (trailing > 0) + this.waiting = data.slice(len); + + return Buffer.concat(blocks); +}; + +/** + * Finalize the cipher. + * @returns {Buffer} + */ + +AESCipher.prototype.final = function final() { + var block, left, pad; + + // Handle padding on the last block. + if (!this.waiting) { + block = Buffer.allocUnsafe(16); + block.fill(16); + } else { + block = this.waiting; + left = 16 - block.length; + pad = Buffer.allocUnsafe(left); + pad.fill(left); + block = concat(block, pad); + } + + // Encrypt the last block, + // as well as the padding. + if (this.mode === 'cbc') + block = xor(block, this.prev); + + block = this.key.encryptBlock(block); + + this.key.destroy(); + + return block; +}; + +/** + * AES decipher. + * @constructor + * @ignore + * @param {Buffer} key + * @param {Buffer} iv + * @param {Number} bits + * @param {String} mode + */ + +function AESDecipher(key, iv, bits, mode) { + if (!(this instanceof AESDecipher)) + return new AESDecipher(key, iv, mode); + + assert(mode === 'ecb' || mode === 'cbc', 'Unknown mode.'); + + this.key = new AESKey(key, bits); + this.mode = mode; + this.prev = iv; + this.waiting = null; + this.lastBlock = null; +} + +/** + * Decrypt blocks of data. + * @param {Buffer} data + */ + +AESDecipher.prototype.update = function update(data) { + var blocks = []; + var i, chunk, block, len, trailing; + + if (this.waiting) { + data = concat(this.waiting, data); + this.waiting = null; + } + + trailing = data.length % 16; + len = data.length - trailing; + + // Decrypt all blocks. + for (i = 0; i < len; i += 16) { + chunk = this.prev; + this.prev = data.slice(i, i + 16); + block = this.key.decryptBlock(this.prev); + if (this.mode === 'cbc') + block = xor(block, chunk); + blocks.push(block); + } + + if (trailing > 0) + this.waiting = data.slice(len); + + if (this.lastBlock) { + blocks.unshift(this.lastBlock); + this.lastBlock = null; + } + + // Keep a reference to the last + // block for the padding check. + this.lastBlock = blocks.pop(); + + return Buffer.concat(blocks); +}; + +/** + * Finalize the decipher. + * @returns {Buffer} + */ + +AESDecipher.prototype.final = function final() { + var i, b, n, block; + + this.key.destroy(); + + assert(!this.waiting, 'Bad decrypt (trailing bytes).'); + assert(this.lastBlock, 'Bad decrypt (no data).'); + + // Check padding on the last block. + block = this.lastBlock; + b = 16; + n = block[b - 1]; + + if (n === 0 || n > b) + throw new Error('Bad decrypt (padding).'); + + for (i = 0; i < n; i++) { + if (block[--b] !== n) + throw new Error('Bad decrypt (padding).'); + } + + // Slice off the padding unless + // the entire block was padding. + if (n === 16) + return Buffer.alloc(0); + + block = block.slice(0, -n); + + return block; +}; + +/** + * Encrypt data with aes 256. + * @param {Buffer} data + * @param {Buffer} key + * @param {Buffer} iv + * @param {String} mode + * @returns {Buffer} + */ + +AES.encrypt = function encrypt(data, key, iv, bits, mode) { + var cipher = new AESCipher(key, iv, bits, mode); + return concat(cipher.update(data), cipher.final()); +}; + +/** + * Decrypt data with aes 256. + * @param {Buffer} data + * @param {Buffer} key + * @param {Buffer|null} iv + * @param {Number} bits + * @param {String} mode + * @returns {Buffer} + */ + +AES.decrypt = function decrypt(data, key, iv, bits, mode) { + var decipher = new AESDecipher(key, iv, bits, mode); + return concat(decipher.update(data), decipher.final()); +}; + +/** + * Encrypt data with aes 256 cbc. + * @param {Buffer} data + * @param {Buffer} key + * @param {Buffer} iv + * @returns {Buffer} + */ + +AES.encipher = function encipher(data, key, iv) { + assert(Buffer.isBuffer(data)); + assert(key.length === 32); + assert(iv.length === 16); + return AES.encrypt(data, key, iv, 256, 'cbc'); +}; + +/** + * Decrypt data with aes 256 cbc. + * @param {Buffer} data + * @param {Buffer} key + * @param {Buffer} iv + * @returns {Buffer} + */ + +AES.decipher = function decipher(data, key, iv) { + assert(Buffer.isBuffer(data)); + assert(key.length === 32); + assert(iv.length === 16); + return AES.decrypt(data, key, iv, 256, 'cbc'); +}; + +/* + * Helpers + */ + +function xor(v1, v2) { + var out = Buffer.allocUnsafe(v1.length); + for (var i = 0; i < v1.length; i++) + out[i] = v1[i] ^ v2[i]; + return out; +} + +function readU32(data, i) { + return (data[i + 0] << 24) + ^ (data[i + 1] << 16) + ^ (data[i + 2] << 8) + ^ data[i + 3]; +} + +function writeU32(data, value, i) { + data[i + 0] = (value >>> 24) & 0xff; + data[i + 1] = (value >>> 16) & 0xff; + data[i + 2] = (value >>> 8) & 0xff; + data[i + 3] = value & 0xff; +} + +function concat(a, b) { + var data = Buffer.allocUnsafe(a.length + b.length); + a.copy(data, 0); + b.copy(data, a.length); + return data; +} + +/* + * Tables + */ + +var TE0 = [ + 0xc66363a5, 0xf87c7c84, 0xee777799, 0xf67b7b8d, + 0xfff2f20d, 0xd66b6bbd, 0xde6f6fb1, 0x91c5c554, + 0x60303050, 0x02010103, 0xce6767a9, 0x562b2b7d, + 0xe7fefe19, 0xb5d7d762, 0x4dababe6, 0xec76769a, + 0x8fcaca45, 0x1f82829d, 0x89c9c940, 0xfa7d7d87, + 0xeffafa15, 0xb25959eb, 0x8e4747c9, 0xfbf0f00b, + 0x41adadec, 0xb3d4d467, 0x5fa2a2fd, 0x45afafea, + 0x239c9cbf, 0x53a4a4f7, 0xe4727296, 0x9bc0c05b, + 0x75b7b7c2, 0xe1fdfd1c, 0x3d9393ae, 0x4c26266a, + 0x6c36365a, 0x7e3f3f41, 0xf5f7f702, 0x83cccc4f, + 0x6834345c, 0x51a5a5f4, 0xd1e5e534, 0xf9f1f108, + 0xe2717193, 0xabd8d873, 0x62313153, 0x2a15153f, + 0x0804040c, 0x95c7c752, 0x46232365, 0x9dc3c35e, + 0x30181828, 0x379696a1, 0x0a05050f, 0x2f9a9ab5, + 0x0e070709, 0x24121236, 0x1b80809b, 0xdfe2e23d, + 0xcdebeb26, 0x4e272769, 0x7fb2b2cd, 0xea75759f, + 0x1209091b, 0x1d83839e, 0x582c2c74, 0x341a1a2e, + 0x361b1b2d, 0xdc6e6eb2, 0xb45a5aee, 0x5ba0a0fb, + 0xa45252f6, 0x763b3b4d, 0xb7d6d661, 0x7db3b3ce, + 0x5229297b, 0xdde3e33e, 0x5e2f2f71, 0x13848497, + 0xa65353f5, 0xb9d1d168, 0x00000000, 0xc1eded2c, + 0x40202060, 0xe3fcfc1f, 0x79b1b1c8, 0xb65b5bed, + 0xd46a6abe, 0x8dcbcb46, 0x67bebed9, 0x7239394b, + 0x944a4ade, 0x984c4cd4, 0xb05858e8, 0x85cfcf4a, + 0xbbd0d06b, 0xc5efef2a, 0x4faaaae5, 0xedfbfb16, + 0x864343c5, 0x9a4d4dd7, 0x66333355, 0x11858594, + 0x8a4545cf, 0xe9f9f910, 0x04020206, 0xfe7f7f81, + 0xa05050f0, 0x783c3c44, 0x259f9fba, 0x4ba8a8e3, + 0xa25151f3, 0x5da3a3fe, 0x804040c0, 0x058f8f8a, + 0x3f9292ad, 0x219d9dbc, 0x70383848, 0xf1f5f504, + 0x63bcbcdf, 0x77b6b6c1, 0xafdada75, 0x42212163, + 0x20101030, 0xe5ffff1a, 0xfdf3f30e, 0xbfd2d26d, + 0x81cdcd4c, 0x180c0c14, 0x26131335, 0xc3ecec2f, + 0xbe5f5fe1, 0x359797a2, 0x884444cc, 0x2e171739, + 0x93c4c457, 0x55a7a7f2, 0xfc7e7e82, 0x7a3d3d47, + 0xc86464ac, 0xba5d5de7, 0x3219192b, 0xe6737395, + 0xc06060a0, 0x19818198, 0x9e4f4fd1, 0xa3dcdc7f, + 0x44222266, 0x542a2a7e, 0x3b9090ab, 0x0b888883, + 0x8c4646ca, 0xc7eeee29, 0x6bb8b8d3, 0x2814143c, + 0xa7dede79, 0xbc5e5ee2, 0x160b0b1d, 0xaddbdb76, + 0xdbe0e03b, 0x64323256, 0x743a3a4e, 0x140a0a1e, + 0x924949db, 0x0c06060a, 0x4824246c, 0xb85c5ce4, + 0x9fc2c25d, 0xbdd3d36e, 0x43acacef, 0xc46262a6, + 0x399191a8, 0x319595a4, 0xd3e4e437, 0xf279798b, + 0xd5e7e732, 0x8bc8c843, 0x6e373759, 0xda6d6db7, + 0x018d8d8c, 0xb1d5d564, 0x9c4e4ed2, 0x49a9a9e0, + 0xd86c6cb4, 0xac5656fa, 0xf3f4f407, 0xcfeaea25, + 0xca6565af, 0xf47a7a8e, 0x47aeaee9, 0x10080818, + 0x6fbabad5, 0xf0787888, 0x4a25256f, 0x5c2e2e72, + 0x381c1c24, 0x57a6a6f1, 0x73b4b4c7, 0x97c6c651, + 0xcbe8e823, 0xa1dddd7c, 0xe874749c, 0x3e1f1f21, + 0x964b4bdd, 0x61bdbddc, 0x0d8b8b86, 0x0f8a8a85, + 0xe0707090, 0x7c3e3e42, 0x71b5b5c4, 0xcc6666aa, + 0x904848d8, 0x06030305, 0xf7f6f601, 0x1c0e0e12, + 0xc26161a3, 0x6a35355f, 0xae5757f9, 0x69b9b9d0, + 0x17868691, 0x99c1c158, 0x3a1d1d27, 0x279e9eb9, + 0xd9e1e138, 0xebf8f813, 0x2b9898b3, 0x22111133, + 0xd26969bb, 0xa9d9d970, 0x078e8e89, 0x339494a7, + 0x2d9b9bb6, 0x3c1e1e22, 0x15878792, 0xc9e9e920, + 0x87cece49, 0xaa5555ff, 0x50282878, 0xa5dfdf7a, + 0x038c8c8f, 0x59a1a1f8, 0x09898980, 0x1a0d0d17, + 0x65bfbfda, 0xd7e6e631, 0x844242c6, 0xd06868b8, + 0x824141c3, 0x299999b0, 0x5a2d2d77, 0x1e0f0f11, + 0x7bb0b0cb, 0xa85454fc, 0x6dbbbbd6, 0x2c16163a +]; + +var TE1 = [ + 0xa5c66363, 0x84f87c7c, 0x99ee7777, 0x8df67b7b, + 0x0dfff2f2, 0xbdd66b6b, 0xb1de6f6f, 0x5491c5c5, + 0x50603030, 0x03020101, 0xa9ce6767, 0x7d562b2b, + 0x19e7fefe, 0x62b5d7d7, 0xe64dabab, 0x9aec7676, + 0x458fcaca, 0x9d1f8282, 0x4089c9c9, 0x87fa7d7d, + 0x15effafa, 0xebb25959, 0xc98e4747, 0x0bfbf0f0, + 0xec41adad, 0x67b3d4d4, 0xfd5fa2a2, 0xea45afaf, + 0xbf239c9c, 0xf753a4a4, 0x96e47272, 0x5b9bc0c0, + 0xc275b7b7, 0x1ce1fdfd, 0xae3d9393, 0x6a4c2626, + 0x5a6c3636, 0x417e3f3f, 0x02f5f7f7, 0x4f83cccc, + 0x5c683434, 0xf451a5a5, 0x34d1e5e5, 0x08f9f1f1, + 0x93e27171, 0x73abd8d8, 0x53623131, 0x3f2a1515, + 0x0c080404, 0x5295c7c7, 0x65462323, 0x5e9dc3c3, + 0x28301818, 0xa1379696, 0x0f0a0505, 0xb52f9a9a, + 0x090e0707, 0x36241212, 0x9b1b8080, 0x3ddfe2e2, + 0x26cdebeb, 0x694e2727, 0xcd7fb2b2, 0x9fea7575, + 0x1b120909, 0x9e1d8383, 0x74582c2c, 0x2e341a1a, + 0x2d361b1b, 0xb2dc6e6e, 0xeeb45a5a, 0xfb5ba0a0, + 0xf6a45252, 0x4d763b3b, 0x61b7d6d6, 0xce7db3b3, + 0x7b522929, 0x3edde3e3, 0x715e2f2f, 0x97138484, + 0xf5a65353, 0x68b9d1d1, 0x00000000, 0x2cc1eded, + 0x60402020, 0x1fe3fcfc, 0xc879b1b1, 0xedb65b5b, + 0xbed46a6a, 0x468dcbcb, 0xd967bebe, 0x4b723939, + 0xde944a4a, 0xd4984c4c, 0xe8b05858, 0x4a85cfcf, + 0x6bbbd0d0, 0x2ac5efef, 0xe54faaaa, 0x16edfbfb, + 0xc5864343, 0xd79a4d4d, 0x55663333, 0x94118585, + 0xcf8a4545, 0x10e9f9f9, 0x06040202, 0x81fe7f7f, + 0xf0a05050, 0x44783c3c, 0xba259f9f, 0xe34ba8a8, + 0xf3a25151, 0xfe5da3a3, 0xc0804040, 0x8a058f8f, + 0xad3f9292, 0xbc219d9d, 0x48703838, 0x04f1f5f5, + 0xdf63bcbc, 0xc177b6b6, 0x75afdada, 0x63422121, + 0x30201010, 0x1ae5ffff, 0x0efdf3f3, 0x6dbfd2d2, + 0x4c81cdcd, 0x14180c0c, 0x35261313, 0x2fc3ecec, + 0xe1be5f5f, 0xa2359797, 0xcc884444, 0x392e1717, + 0x5793c4c4, 0xf255a7a7, 0x82fc7e7e, 0x477a3d3d, + 0xacc86464, 0xe7ba5d5d, 0x2b321919, 0x95e67373, + 0xa0c06060, 0x98198181, 0xd19e4f4f, 0x7fa3dcdc, + 0x66442222, 0x7e542a2a, 0xab3b9090, 0x830b8888, + 0xca8c4646, 0x29c7eeee, 0xd36bb8b8, 0x3c281414, + 0x79a7dede, 0xe2bc5e5e, 0x1d160b0b, 0x76addbdb, + 0x3bdbe0e0, 0x56643232, 0x4e743a3a, 0x1e140a0a, + 0xdb924949, 0x0a0c0606, 0x6c482424, 0xe4b85c5c, + 0x5d9fc2c2, 0x6ebdd3d3, 0xef43acac, 0xa6c46262, + 0xa8399191, 0xa4319595, 0x37d3e4e4, 0x8bf27979, + 0x32d5e7e7, 0x438bc8c8, 0x596e3737, 0xb7da6d6d, + 0x8c018d8d, 0x64b1d5d5, 0xd29c4e4e, 0xe049a9a9, + 0xb4d86c6c, 0xfaac5656, 0x07f3f4f4, 0x25cfeaea, + 0xafca6565, 0x8ef47a7a, 0xe947aeae, 0x18100808, + 0xd56fbaba, 0x88f07878, 0x6f4a2525, 0x725c2e2e, + 0x24381c1c, 0xf157a6a6, 0xc773b4b4, 0x5197c6c6, + 0x23cbe8e8, 0x7ca1dddd, 0x9ce87474, 0x213e1f1f, + 0xdd964b4b, 0xdc61bdbd, 0x860d8b8b, 0x850f8a8a, + 0x90e07070, 0x427c3e3e, 0xc471b5b5, 0xaacc6666, + 0xd8904848, 0x05060303, 0x01f7f6f6, 0x121c0e0e, + 0xa3c26161, 0x5f6a3535, 0xf9ae5757, 0xd069b9b9, + 0x91178686, 0x5899c1c1, 0x273a1d1d, 0xb9279e9e, + 0x38d9e1e1, 0x13ebf8f8, 0xb32b9898, 0x33221111, + 0xbbd26969, 0x70a9d9d9, 0x89078e8e, 0xa7339494, + 0xb62d9b9b, 0x223c1e1e, 0x92158787, 0x20c9e9e9, + 0x4987cece, 0xffaa5555, 0x78502828, 0x7aa5dfdf, + 0x8f038c8c, 0xf859a1a1, 0x80098989, 0x171a0d0d, + 0xda65bfbf, 0x31d7e6e6, 0xc6844242, 0xb8d06868, + 0xc3824141, 0xb0299999, 0x775a2d2d, 0x111e0f0f, + 0xcb7bb0b0, 0xfca85454, 0xd66dbbbb, 0x3a2c1616 +]; + +var TE2 = [ + 0x63a5c663, 0x7c84f87c, 0x7799ee77, 0x7b8df67b, + 0xf20dfff2, 0x6bbdd66b, 0x6fb1de6f, 0xc55491c5, + 0x30506030, 0x01030201, 0x67a9ce67, 0x2b7d562b, + 0xfe19e7fe, 0xd762b5d7, 0xabe64dab, 0x769aec76, + 0xca458fca, 0x829d1f82, 0xc94089c9, 0x7d87fa7d, + 0xfa15effa, 0x59ebb259, 0x47c98e47, 0xf00bfbf0, + 0xadec41ad, 0xd467b3d4, 0xa2fd5fa2, 0xafea45af, + 0x9cbf239c, 0xa4f753a4, 0x7296e472, 0xc05b9bc0, + 0xb7c275b7, 0xfd1ce1fd, 0x93ae3d93, 0x266a4c26, + 0x365a6c36, 0x3f417e3f, 0xf702f5f7, 0xcc4f83cc, + 0x345c6834, 0xa5f451a5, 0xe534d1e5, 0xf108f9f1, + 0x7193e271, 0xd873abd8, 0x31536231, 0x153f2a15, + 0x040c0804, 0xc75295c7, 0x23654623, 0xc35e9dc3, + 0x18283018, 0x96a13796, 0x050f0a05, 0x9ab52f9a, + 0x07090e07, 0x12362412, 0x809b1b80, 0xe23ddfe2, + 0xeb26cdeb, 0x27694e27, 0xb2cd7fb2, 0x759fea75, + 0x091b1209, 0x839e1d83, 0x2c74582c, 0x1a2e341a, + 0x1b2d361b, 0x6eb2dc6e, 0x5aeeb45a, 0xa0fb5ba0, + 0x52f6a452, 0x3b4d763b, 0xd661b7d6, 0xb3ce7db3, + 0x297b5229, 0xe33edde3, 0x2f715e2f, 0x84971384, + 0x53f5a653, 0xd168b9d1, 0x00000000, 0xed2cc1ed, + 0x20604020, 0xfc1fe3fc, 0xb1c879b1, 0x5bedb65b, + 0x6abed46a, 0xcb468dcb, 0xbed967be, 0x394b7239, + 0x4ade944a, 0x4cd4984c, 0x58e8b058, 0xcf4a85cf, + 0xd06bbbd0, 0xef2ac5ef, 0xaae54faa, 0xfb16edfb, + 0x43c58643, 0x4dd79a4d, 0x33556633, 0x85941185, + 0x45cf8a45, 0xf910e9f9, 0x02060402, 0x7f81fe7f, + 0x50f0a050, 0x3c44783c, 0x9fba259f, 0xa8e34ba8, + 0x51f3a251, 0xa3fe5da3, 0x40c08040, 0x8f8a058f, + 0x92ad3f92, 0x9dbc219d, 0x38487038, 0xf504f1f5, + 0xbcdf63bc, 0xb6c177b6, 0xda75afda, 0x21634221, + 0x10302010, 0xff1ae5ff, 0xf30efdf3, 0xd26dbfd2, + 0xcd4c81cd, 0x0c14180c, 0x13352613, 0xec2fc3ec, + 0x5fe1be5f, 0x97a23597, 0x44cc8844, 0x17392e17, + 0xc45793c4, 0xa7f255a7, 0x7e82fc7e, 0x3d477a3d, + 0x64acc864, 0x5de7ba5d, 0x192b3219, 0x7395e673, + 0x60a0c060, 0x81981981, 0x4fd19e4f, 0xdc7fa3dc, + 0x22664422, 0x2a7e542a, 0x90ab3b90, 0x88830b88, + 0x46ca8c46, 0xee29c7ee, 0xb8d36bb8, 0x143c2814, + 0xde79a7de, 0x5ee2bc5e, 0x0b1d160b, 0xdb76addb, + 0xe03bdbe0, 0x32566432, 0x3a4e743a, 0x0a1e140a, + 0x49db9249, 0x060a0c06, 0x246c4824, 0x5ce4b85c, + 0xc25d9fc2, 0xd36ebdd3, 0xacef43ac, 0x62a6c462, + 0x91a83991, 0x95a43195, 0xe437d3e4, 0x798bf279, + 0xe732d5e7, 0xc8438bc8, 0x37596e37, 0x6db7da6d, + 0x8d8c018d, 0xd564b1d5, 0x4ed29c4e, 0xa9e049a9, + 0x6cb4d86c, 0x56faac56, 0xf407f3f4, 0xea25cfea, + 0x65afca65, 0x7a8ef47a, 0xaee947ae, 0x08181008, + 0xbad56fba, 0x7888f078, 0x256f4a25, 0x2e725c2e, + 0x1c24381c, 0xa6f157a6, 0xb4c773b4, 0xc65197c6, + 0xe823cbe8, 0xdd7ca1dd, 0x749ce874, 0x1f213e1f, + 0x4bdd964b, 0xbddc61bd, 0x8b860d8b, 0x8a850f8a, + 0x7090e070, 0x3e427c3e, 0xb5c471b5, 0x66aacc66, + 0x48d89048, 0x03050603, 0xf601f7f6, 0x0e121c0e, + 0x61a3c261, 0x355f6a35, 0x57f9ae57, 0xb9d069b9, + 0x86911786, 0xc15899c1, 0x1d273a1d, 0x9eb9279e, + 0xe138d9e1, 0xf813ebf8, 0x98b32b98, 0x11332211, + 0x69bbd269, 0xd970a9d9, 0x8e89078e, 0x94a73394, + 0x9bb62d9b, 0x1e223c1e, 0x87921587, 0xe920c9e9, + 0xce4987ce, 0x55ffaa55, 0x28785028, 0xdf7aa5df, + 0x8c8f038c, 0xa1f859a1, 0x89800989, 0x0d171a0d, + 0xbfda65bf, 0xe631d7e6, 0x42c68442, 0x68b8d068, + 0x41c38241, 0x99b02999, 0x2d775a2d, 0x0f111e0f, + 0xb0cb7bb0, 0x54fca854, 0xbbd66dbb, 0x163a2c16 +]; + +var TE3 = [ + 0x6363a5c6, 0x7c7c84f8, 0x777799ee, 0x7b7b8df6, + 0xf2f20dff, 0x6b6bbdd6, 0x6f6fb1de, 0xc5c55491, + 0x30305060, 0x01010302, 0x6767a9ce, 0x2b2b7d56, + 0xfefe19e7, 0xd7d762b5, 0xababe64d, 0x76769aec, + 0xcaca458f, 0x82829d1f, 0xc9c94089, 0x7d7d87fa, + 0xfafa15ef, 0x5959ebb2, 0x4747c98e, 0xf0f00bfb, + 0xadadec41, 0xd4d467b3, 0xa2a2fd5f, 0xafafea45, + 0x9c9cbf23, 0xa4a4f753, 0x727296e4, 0xc0c05b9b, + 0xb7b7c275, 0xfdfd1ce1, 0x9393ae3d, 0x26266a4c, + 0x36365a6c, 0x3f3f417e, 0xf7f702f5, 0xcccc4f83, + 0x34345c68, 0xa5a5f451, 0xe5e534d1, 0xf1f108f9, + 0x717193e2, 0xd8d873ab, 0x31315362, 0x15153f2a, + 0x04040c08, 0xc7c75295, 0x23236546, 0xc3c35e9d, + 0x18182830, 0x9696a137, 0x05050f0a, 0x9a9ab52f, + 0x0707090e, 0x12123624, 0x80809b1b, 0xe2e23ddf, + 0xebeb26cd, 0x2727694e, 0xb2b2cd7f, 0x75759fea, + 0x09091b12, 0x83839e1d, 0x2c2c7458, 0x1a1a2e34, + 0x1b1b2d36, 0x6e6eb2dc, 0x5a5aeeb4, 0xa0a0fb5b, + 0x5252f6a4, 0x3b3b4d76, 0xd6d661b7, 0xb3b3ce7d, + 0x29297b52, 0xe3e33edd, 0x2f2f715e, 0x84849713, + 0x5353f5a6, 0xd1d168b9, 0x00000000, 0xeded2cc1, + 0x20206040, 0xfcfc1fe3, 0xb1b1c879, 0x5b5bedb6, + 0x6a6abed4, 0xcbcb468d, 0xbebed967, 0x39394b72, + 0x4a4ade94, 0x4c4cd498, 0x5858e8b0, 0xcfcf4a85, + 0xd0d06bbb, 0xefef2ac5, 0xaaaae54f, 0xfbfb16ed, + 0x4343c586, 0x4d4dd79a, 0x33335566, 0x85859411, + 0x4545cf8a, 0xf9f910e9, 0x02020604, 0x7f7f81fe, + 0x5050f0a0, 0x3c3c4478, 0x9f9fba25, 0xa8a8e34b, + 0x5151f3a2, 0xa3a3fe5d, 0x4040c080, 0x8f8f8a05, + 0x9292ad3f, 0x9d9dbc21, 0x38384870, 0xf5f504f1, + 0xbcbcdf63, 0xb6b6c177, 0xdada75af, 0x21216342, + 0x10103020, 0xffff1ae5, 0xf3f30efd, 0xd2d26dbf, + 0xcdcd4c81, 0x0c0c1418, 0x13133526, 0xecec2fc3, + 0x5f5fe1be, 0x9797a235, 0x4444cc88, 0x1717392e, + 0xc4c45793, 0xa7a7f255, 0x7e7e82fc, 0x3d3d477a, + 0x6464acc8, 0x5d5de7ba, 0x19192b32, 0x737395e6, + 0x6060a0c0, 0x81819819, 0x4f4fd19e, 0xdcdc7fa3, + 0x22226644, 0x2a2a7e54, 0x9090ab3b, 0x8888830b, + 0x4646ca8c, 0xeeee29c7, 0xb8b8d36b, 0x14143c28, + 0xdede79a7, 0x5e5ee2bc, 0x0b0b1d16, 0xdbdb76ad, + 0xe0e03bdb, 0x32325664, 0x3a3a4e74, 0x0a0a1e14, + 0x4949db92, 0x06060a0c, 0x24246c48, 0x5c5ce4b8, + 0xc2c25d9f, 0xd3d36ebd, 0xacacef43, 0x6262a6c4, + 0x9191a839, 0x9595a431, 0xe4e437d3, 0x79798bf2, + 0xe7e732d5, 0xc8c8438b, 0x3737596e, 0x6d6db7da, + 0x8d8d8c01, 0xd5d564b1, 0x4e4ed29c, 0xa9a9e049, + 0x6c6cb4d8, 0x5656faac, 0xf4f407f3, 0xeaea25cf, + 0x6565afca, 0x7a7a8ef4, 0xaeaee947, 0x08081810, + 0xbabad56f, 0x787888f0, 0x25256f4a, 0x2e2e725c, + 0x1c1c2438, 0xa6a6f157, 0xb4b4c773, 0xc6c65197, + 0xe8e823cb, 0xdddd7ca1, 0x74749ce8, 0x1f1f213e, + 0x4b4bdd96, 0xbdbddc61, 0x8b8b860d, 0x8a8a850f, + 0x707090e0, 0x3e3e427c, 0xb5b5c471, 0x6666aacc, + 0x4848d890, 0x03030506, 0xf6f601f7, 0x0e0e121c, + 0x6161a3c2, 0x35355f6a, 0x5757f9ae, 0xb9b9d069, + 0x86869117, 0xc1c15899, 0x1d1d273a, 0x9e9eb927, + 0xe1e138d9, 0xf8f813eb, 0x9898b32b, 0x11113322, + 0x6969bbd2, 0xd9d970a9, 0x8e8e8907, 0x9494a733, + 0x9b9bb62d, 0x1e1e223c, 0x87879215, 0xe9e920c9, + 0xcece4987, 0x5555ffaa, 0x28287850, 0xdfdf7aa5, + 0x8c8c8f03, 0xa1a1f859, 0x89898009, 0x0d0d171a, + 0xbfbfda65, 0xe6e631d7, 0x4242c684, 0x6868b8d0, + 0x4141c382, 0x9999b029, 0x2d2d775a, 0x0f0f111e, + 0xb0b0cb7b, 0x5454fca8, 0xbbbbd66d, 0x16163a2c +]; + +var TD0 = [ + 0x51f4a750, 0x7e416553, 0x1a17a4c3, 0x3a275e96, + 0x3bab6bcb, 0x1f9d45f1, 0xacfa58ab, 0x4be30393, + 0x2030fa55, 0xad766df6, 0x88cc7691, 0xf5024c25, + 0x4fe5d7fc, 0xc52acbd7, 0x26354480, 0xb562a38f, + 0xdeb15a49, 0x25ba1b67, 0x45ea0e98, 0x5dfec0e1, + 0xc32f7502, 0x814cf012, 0x8d4697a3, 0x6bd3f9c6, + 0x038f5fe7, 0x15929c95, 0xbf6d7aeb, 0x955259da, + 0xd4be832d, 0x587421d3, 0x49e06929, 0x8ec9c844, + 0x75c2896a, 0xf48e7978, 0x99583e6b, 0x27b971dd, + 0xbee14fb6, 0xf088ad17, 0xc920ac66, 0x7dce3ab4, + 0x63df4a18, 0xe51a3182, 0x97513360, 0x62537f45, + 0xb16477e0, 0xbb6bae84, 0xfe81a01c, 0xf9082b94, + 0x70486858, 0x8f45fd19, 0x94de6c87, 0x527bf8b7, + 0xab73d323, 0x724b02e2, 0xe31f8f57, 0x6655ab2a, + 0xb2eb2807, 0x2fb5c203, 0x86c57b9a, 0xd33708a5, + 0x302887f2, 0x23bfa5b2, 0x02036aba, 0xed16825c, + 0x8acf1c2b, 0xa779b492, 0xf307f2f0, 0x4e69e2a1, + 0x65daf4cd, 0x0605bed5, 0xd134621f, 0xc4a6fe8a, + 0x342e539d, 0xa2f355a0, 0x058ae132, 0xa4f6eb75, + 0x0b83ec39, 0x4060efaa, 0x5e719f06, 0xbd6e1051, + 0x3e218af9, 0x96dd063d, 0xdd3e05ae, 0x4de6bd46, + 0x91548db5, 0x71c45d05, 0x0406d46f, 0x605015ff, + 0x1998fb24, 0xd6bde997, 0x894043cc, 0x67d99e77, + 0xb0e842bd, 0x07898b88, 0xe7195b38, 0x79c8eedb, + 0xa17c0a47, 0x7c420fe9, 0xf8841ec9, 0x00000000, + 0x09808683, 0x322bed48, 0x1e1170ac, 0x6c5a724e, + 0xfd0efffb, 0x0f853856, 0x3daed51e, 0x362d3927, + 0x0a0fd964, 0x685ca621, 0x9b5b54d1, 0x24362e3a, + 0x0c0a67b1, 0x9357e70f, 0xb4ee96d2, 0x1b9b919e, + 0x80c0c54f, 0x61dc20a2, 0x5a774b69, 0x1c121a16, + 0xe293ba0a, 0xc0a02ae5, 0x3c22e043, 0x121b171d, + 0x0e090d0b, 0xf28bc7ad, 0x2db6a8b9, 0x141ea9c8, + 0x57f11985, 0xaf75074c, 0xee99ddbb, 0xa37f60fd, + 0xf701269f, 0x5c72f5bc, 0x44663bc5, 0x5bfb7e34, + 0x8b432976, 0xcb23c6dc, 0xb6edfc68, 0xb8e4f163, + 0xd731dcca, 0x42638510, 0x13972240, 0x84c61120, + 0x854a247d, 0xd2bb3df8, 0xaef93211, 0xc729a16d, + 0x1d9e2f4b, 0xdcb230f3, 0x0d8652ec, 0x77c1e3d0, + 0x2bb3166c, 0xa970b999, 0x119448fa, 0x47e96422, + 0xa8fc8cc4, 0xa0f03f1a, 0x567d2cd8, 0x223390ef, + 0x87494ec7, 0xd938d1c1, 0x8ccaa2fe, 0x98d40b36, + 0xa6f581cf, 0xa57ade28, 0xdab78e26, 0x3fadbfa4, + 0x2c3a9de4, 0x5078920d, 0x6a5fcc9b, 0x547e4662, + 0xf68d13c2, 0x90d8b8e8, 0x2e39f75e, 0x82c3aff5, + 0x9f5d80be, 0x69d0937c, 0x6fd52da9, 0xcf2512b3, + 0xc8ac993b, 0x10187da7, 0xe89c636e, 0xdb3bbb7b, + 0xcd267809, 0x6e5918f4, 0xec9ab701, 0x834f9aa8, + 0xe6956e65, 0xaaffe67e, 0x21bccf08, 0xef15e8e6, + 0xbae79bd9, 0x4a6f36ce, 0xea9f09d4, 0x29b07cd6, + 0x31a4b2af, 0x2a3f2331, 0xc6a59430, 0x35a266c0, + 0x744ebc37, 0xfc82caa6, 0xe090d0b0, 0x33a7d815, + 0xf104984a, 0x41ecdaf7, 0x7fcd500e, 0x1791f62f, + 0x764dd68d, 0x43efb04d, 0xccaa4d54, 0xe49604df, + 0x9ed1b5e3, 0x4c6a881b, 0xc12c1fb8, 0x4665517f, + 0x9d5eea04, 0x018c355d, 0xfa877473, 0xfb0b412e, + 0xb3671d5a, 0x92dbd252, 0xe9105633, 0x6dd64713, + 0x9ad7618c, 0x37a10c7a, 0x59f8148e, 0xeb133c89, + 0xcea927ee, 0xb761c935, 0xe11ce5ed, 0x7a47b13c, + 0x9cd2df59, 0x55f2733f, 0x1814ce79, 0x73c737bf, + 0x53f7cdea, 0x5ffdaa5b, 0xdf3d6f14, 0x7844db86, + 0xcaaff381, 0xb968c43e, 0x3824342c, 0xc2a3405f, + 0x161dc372, 0xbce2250c, 0x283c498b, 0xff0d9541, + 0x39a80171, 0x080cb3de, 0xd8b4e49c, 0x6456c190, + 0x7bcb8461, 0xd532b670, 0x486c5c74, 0xd0b85742 +]; + +var TD1 = [ + 0x5051f4a7, 0x537e4165, 0xc31a17a4, 0x963a275e, + 0xcb3bab6b, 0xf11f9d45, 0xabacfa58, 0x934be303, + 0x552030fa, 0xf6ad766d, 0x9188cc76, 0x25f5024c, + 0xfc4fe5d7, 0xd7c52acb, 0x80263544, 0x8fb562a3, + 0x49deb15a, 0x6725ba1b, 0x9845ea0e, 0xe15dfec0, + 0x02c32f75, 0x12814cf0, 0xa38d4697, 0xc66bd3f9, + 0xe7038f5f, 0x9515929c, 0xebbf6d7a, 0xda955259, + 0x2dd4be83, 0xd3587421, 0x2949e069, 0x448ec9c8, + 0x6a75c289, 0x78f48e79, 0x6b99583e, 0xdd27b971, + 0xb6bee14f, 0x17f088ad, 0x66c920ac, 0xb47dce3a, + 0x1863df4a, 0x82e51a31, 0x60975133, 0x4562537f, + 0xe0b16477, 0x84bb6bae, 0x1cfe81a0, 0x94f9082b, + 0x58704868, 0x198f45fd, 0x8794de6c, 0xb7527bf8, + 0x23ab73d3, 0xe2724b02, 0x57e31f8f, 0x2a6655ab, + 0x07b2eb28, 0x032fb5c2, 0x9a86c57b, 0xa5d33708, + 0xf2302887, 0xb223bfa5, 0xba02036a, 0x5ced1682, + 0x2b8acf1c, 0x92a779b4, 0xf0f307f2, 0xa14e69e2, + 0xcd65daf4, 0xd50605be, 0x1fd13462, 0x8ac4a6fe, + 0x9d342e53, 0xa0a2f355, 0x32058ae1, 0x75a4f6eb, + 0x390b83ec, 0xaa4060ef, 0x065e719f, 0x51bd6e10, + 0xf93e218a, 0x3d96dd06, 0xaedd3e05, 0x464de6bd, + 0xb591548d, 0x0571c45d, 0x6f0406d4, 0xff605015, + 0x241998fb, 0x97d6bde9, 0xcc894043, 0x7767d99e, + 0xbdb0e842, 0x8807898b, 0x38e7195b, 0xdb79c8ee, + 0x47a17c0a, 0xe97c420f, 0xc9f8841e, 0x00000000, + 0x83098086, 0x48322bed, 0xac1e1170, 0x4e6c5a72, + 0xfbfd0eff, 0x560f8538, 0x1e3daed5, 0x27362d39, + 0x640a0fd9, 0x21685ca6, 0xd19b5b54, 0x3a24362e, + 0xb10c0a67, 0x0f9357e7, 0xd2b4ee96, 0x9e1b9b91, + 0x4f80c0c5, 0xa261dc20, 0x695a774b, 0x161c121a, + 0x0ae293ba, 0xe5c0a02a, 0x433c22e0, 0x1d121b17, + 0x0b0e090d, 0xadf28bc7, 0xb92db6a8, 0xc8141ea9, + 0x8557f119, 0x4caf7507, 0xbbee99dd, 0xfda37f60, + 0x9ff70126, 0xbc5c72f5, 0xc544663b, 0x345bfb7e, + 0x768b4329, 0xdccb23c6, 0x68b6edfc, 0x63b8e4f1, + 0xcad731dc, 0x10426385, 0x40139722, 0x2084c611, + 0x7d854a24, 0xf8d2bb3d, 0x11aef932, 0x6dc729a1, + 0x4b1d9e2f, 0xf3dcb230, 0xec0d8652, 0xd077c1e3, + 0x6c2bb316, 0x99a970b9, 0xfa119448, 0x2247e964, + 0xc4a8fc8c, 0x1aa0f03f, 0xd8567d2c, 0xef223390, + 0xc787494e, 0xc1d938d1, 0xfe8ccaa2, 0x3698d40b, + 0xcfa6f581, 0x28a57ade, 0x26dab78e, 0xa43fadbf, + 0xe42c3a9d, 0x0d507892, 0x9b6a5fcc, 0x62547e46, + 0xc2f68d13, 0xe890d8b8, 0x5e2e39f7, 0xf582c3af, + 0xbe9f5d80, 0x7c69d093, 0xa96fd52d, 0xb3cf2512, + 0x3bc8ac99, 0xa710187d, 0x6ee89c63, 0x7bdb3bbb, + 0x09cd2678, 0xf46e5918, 0x01ec9ab7, 0xa8834f9a, + 0x65e6956e, 0x7eaaffe6, 0x0821bccf, 0xe6ef15e8, + 0xd9bae79b, 0xce4a6f36, 0xd4ea9f09, 0xd629b07c, + 0xaf31a4b2, 0x312a3f23, 0x30c6a594, 0xc035a266, + 0x37744ebc, 0xa6fc82ca, 0xb0e090d0, 0x1533a7d8, + 0x4af10498, 0xf741ecda, 0x0e7fcd50, 0x2f1791f6, + 0x8d764dd6, 0x4d43efb0, 0x54ccaa4d, 0xdfe49604, + 0xe39ed1b5, 0x1b4c6a88, 0xb8c12c1f, 0x7f466551, + 0x049d5eea, 0x5d018c35, 0x73fa8774, 0x2efb0b41, + 0x5ab3671d, 0x5292dbd2, 0x33e91056, 0x136dd647, + 0x8c9ad761, 0x7a37a10c, 0x8e59f814, 0x89eb133c, + 0xeecea927, 0x35b761c9, 0xede11ce5, 0x3c7a47b1, + 0x599cd2df, 0x3f55f273, 0x791814ce, 0xbf73c737, + 0xea53f7cd, 0x5b5ffdaa, 0x14df3d6f, 0x867844db, + 0x81caaff3, 0x3eb968c4, 0x2c382434, 0x5fc2a340, + 0x72161dc3, 0x0cbce225, 0x8b283c49, 0x41ff0d95, + 0x7139a801, 0xde080cb3, 0x9cd8b4e4, 0x906456c1, + 0x617bcb84, 0x70d532b6, 0x74486c5c, 0x42d0b857 +]; + +var TD2 = [ + 0xa75051f4, 0x65537e41, 0xa4c31a17, 0x5e963a27, + 0x6bcb3bab, 0x45f11f9d, 0x58abacfa, 0x03934be3, + 0xfa552030, 0x6df6ad76, 0x769188cc, 0x4c25f502, + 0xd7fc4fe5, 0xcbd7c52a, 0x44802635, 0xa38fb562, + 0x5a49deb1, 0x1b6725ba, 0x0e9845ea, 0xc0e15dfe, + 0x7502c32f, 0xf012814c, 0x97a38d46, 0xf9c66bd3, + 0x5fe7038f, 0x9c951592, 0x7aebbf6d, 0x59da9552, + 0x832dd4be, 0x21d35874, 0x692949e0, 0xc8448ec9, + 0x896a75c2, 0x7978f48e, 0x3e6b9958, 0x71dd27b9, + 0x4fb6bee1, 0xad17f088, 0xac66c920, 0x3ab47dce, + 0x4a1863df, 0x3182e51a, 0x33609751, 0x7f456253, + 0x77e0b164, 0xae84bb6b, 0xa01cfe81, 0x2b94f908, + 0x68587048, 0xfd198f45, 0x6c8794de, 0xf8b7527b, + 0xd323ab73, 0x02e2724b, 0x8f57e31f, 0xab2a6655, + 0x2807b2eb, 0xc2032fb5, 0x7b9a86c5, 0x08a5d337, + 0x87f23028, 0xa5b223bf, 0x6aba0203, 0x825ced16, + 0x1c2b8acf, 0xb492a779, 0xf2f0f307, 0xe2a14e69, + 0xf4cd65da, 0xbed50605, 0x621fd134, 0xfe8ac4a6, + 0x539d342e, 0x55a0a2f3, 0xe132058a, 0xeb75a4f6, + 0xec390b83, 0xefaa4060, 0x9f065e71, 0x1051bd6e, + 0x8af93e21, 0x063d96dd, 0x05aedd3e, 0xbd464de6, + 0x8db59154, 0x5d0571c4, 0xd46f0406, 0x15ff6050, + 0xfb241998, 0xe997d6bd, 0x43cc8940, 0x9e7767d9, + 0x42bdb0e8, 0x8b880789, 0x5b38e719, 0xeedb79c8, + 0x0a47a17c, 0x0fe97c42, 0x1ec9f884, 0x00000000, + 0x86830980, 0xed48322b, 0x70ac1e11, 0x724e6c5a, + 0xfffbfd0e, 0x38560f85, 0xd51e3dae, 0x3927362d, + 0xd9640a0f, 0xa621685c, 0x54d19b5b, 0x2e3a2436, + 0x67b10c0a, 0xe70f9357, 0x96d2b4ee, 0x919e1b9b, + 0xc54f80c0, 0x20a261dc, 0x4b695a77, 0x1a161c12, + 0xba0ae293, 0x2ae5c0a0, 0xe0433c22, 0x171d121b, + 0x0d0b0e09, 0xc7adf28b, 0xa8b92db6, 0xa9c8141e, + 0x198557f1, 0x074caf75, 0xddbbee99, 0x60fda37f, + 0x269ff701, 0xf5bc5c72, 0x3bc54466, 0x7e345bfb, + 0x29768b43, 0xc6dccb23, 0xfc68b6ed, 0xf163b8e4, + 0xdccad731, 0x85104263, 0x22401397, 0x112084c6, + 0x247d854a, 0x3df8d2bb, 0x3211aef9, 0xa16dc729, + 0x2f4b1d9e, 0x30f3dcb2, 0x52ec0d86, 0xe3d077c1, + 0x166c2bb3, 0xb999a970, 0x48fa1194, 0x642247e9, + 0x8cc4a8fc, 0x3f1aa0f0, 0x2cd8567d, 0x90ef2233, + 0x4ec78749, 0xd1c1d938, 0xa2fe8cca, 0x0b3698d4, + 0x81cfa6f5, 0xde28a57a, 0x8e26dab7, 0xbfa43fad, + 0x9de42c3a, 0x920d5078, 0xcc9b6a5f, 0x4662547e, + 0x13c2f68d, 0xb8e890d8, 0xf75e2e39, 0xaff582c3, + 0x80be9f5d, 0x937c69d0, 0x2da96fd5, 0x12b3cf25, + 0x993bc8ac, 0x7da71018, 0x636ee89c, 0xbb7bdb3b, + 0x7809cd26, 0x18f46e59, 0xb701ec9a, 0x9aa8834f, + 0x6e65e695, 0xe67eaaff, 0xcf0821bc, 0xe8e6ef15, + 0x9bd9bae7, 0x36ce4a6f, 0x09d4ea9f, 0x7cd629b0, + 0xb2af31a4, 0x23312a3f, 0x9430c6a5, 0x66c035a2, + 0xbc37744e, 0xcaa6fc82, 0xd0b0e090, 0xd81533a7, + 0x984af104, 0xdaf741ec, 0x500e7fcd, 0xf62f1791, + 0xd68d764d, 0xb04d43ef, 0x4d54ccaa, 0x04dfe496, + 0xb5e39ed1, 0x881b4c6a, 0x1fb8c12c, 0x517f4665, + 0xea049d5e, 0x355d018c, 0x7473fa87, 0x412efb0b, + 0x1d5ab367, 0xd25292db, 0x5633e910, 0x47136dd6, + 0x618c9ad7, 0x0c7a37a1, 0x148e59f8, 0x3c89eb13, + 0x27eecea9, 0xc935b761, 0xe5ede11c, 0xb13c7a47, + 0xdf599cd2, 0x733f55f2, 0xce791814, 0x37bf73c7, + 0xcdea53f7, 0xaa5b5ffd, 0x6f14df3d, 0xdb867844, + 0xf381caaf, 0xc43eb968, 0x342c3824, 0x405fc2a3, + 0xc372161d, 0x250cbce2, 0x498b283c, 0x9541ff0d, + 0x017139a8, 0xb3de080c, 0xe49cd8b4, 0xc1906456, + 0x84617bcb, 0xb670d532, 0x5c74486c, 0x5742d0b8 +]; + +var TD3 = [ + 0xf4a75051, 0x4165537e, 0x17a4c31a, 0x275e963a, + 0xab6bcb3b, 0x9d45f11f, 0xfa58abac, 0xe303934b, + 0x30fa5520, 0x766df6ad, 0xcc769188, 0x024c25f5, + 0xe5d7fc4f, 0x2acbd7c5, 0x35448026, 0x62a38fb5, + 0xb15a49de, 0xba1b6725, 0xea0e9845, 0xfec0e15d, + 0x2f7502c3, 0x4cf01281, 0x4697a38d, 0xd3f9c66b, + 0x8f5fe703, 0x929c9515, 0x6d7aebbf, 0x5259da95, + 0xbe832dd4, 0x7421d358, 0xe0692949, 0xc9c8448e, + 0xc2896a75, 0x8e7978f4, 0x583e6b99, 0xb971dd27, + 0xe14fb6be, 0x88ad17f0, 0x20ac66c9, 0xce3ab47d, + 0xdf4a1863, 0x1a3182e5, 0x51336097, 0x537f4562, + 0x6477e0b1, 0x6bae84bb, 0x81a01cfe, 0x082b94f9, + 0x48685870, 0x45fd198f, 0xde6c8794, 0x7bf8b752, + 0x73d323ab, 0x4b02e272, 0x1f8f57e3, 0x55ab2a66, + 0xeb2807b2, 0xb5c2032f, 0xc57b9a86, 0x3708a5d3, + 0x2887f230, 0xbfa5b223, 0x036aba02, 0x16825ced, + 0xcf1c2b8a, 0x79b492a7, 0x07f2f0f3, 0x69e2a14e, + 0xdaf4cd65, 0x05bed506, 0x34621fd1, 0xa6fe8ac4, + 0x2e539d34, 0xf355a0a2, 0x8ae13205, 0xf6eb75a4, + 0x83ec390b, 0x60efaa40, 0x719f065e, 0x6e1051bd, + 0x218af93e, 0xdd063d96, 0x3e05aedd, 0xe6bd464d, + 0x548db591, 0xc45d0571, 0x06d46f04, 0x5015ff60, + 0x98fb2419, 0xbde997d6, 0x4043cc89, 0xd99e7767, + 0xe842bdb0, 0x898b8807, 0x195b38e7, 0xc8eedb79, + 0x7c0a47a1, 0x420fe97c, 0x841ec9f8, 0x00000000, + 0x80868309, 0x2bed4832, 0x1170ac1e, 0x5a724e6c, + 0x0efffbfd, 0x8538560f, 0xaed51e3d, 0x2d392736, + 0x0fd9640a, 0x5ca62168, 0x5b54d19b, 0x362e3a24, + 0x0a67b10c, 0x57e70f93, 0xee96d2b4, 0x9b919e1b, + 0xc0c54f80, 0xdc20a261, 0x774b695a, 0x121a161c, + 0x93ba0ae2, 0xa02ae5c0, 0x22e0433c, 0x1b171d12, + 0x090d0b0e, 0x8bc7adf2, 0xb6a8b92d, 0x1ea9c814, + 0xf1198557, 0x75074caf, 0x99ddbbee, 0x7f60fda3, + 0x01269ff7, 0x72f5bc5c, 0x663bc544, 0xfb7e345b, + 0x4329768b, 0x23c6dccb, 0xedfc68b6, 0xe4f163b8, + 0x31dccad7, 0x63851042, 0x97224013, 0xc6112084, + 0x4a247d85, 0xbb3df8d2, 0xf93211ae, 0x29a16dc7, + 0x9e2f4b1d, 0xb230f3dc, 0x8652ec0d, 0xc1e3d077, + 0xb3166c2b, 0x70b999a9, 0x9448fa11, 0xe9642247, + 0xfc8cc4a8, 0xf03f1aa0, 0x7d2cd856, 0x3390ef22, + 0x494ec787, 0x38d1c1d9, 0xcaa2fe8c, 0xd40b3698, + 0xf581cfa6, 0x7ade28a5, 0xb78e26da, 0xadbfa43f, + 0x3a9de42c, 0x78920d50, 0x5fcc9b6a, 0x7e466254, + 0x8d13c2f6, 0xd8b8e890, 0x39f75e2e, 0xc3aff582, + 0x5d80be9f, 0xd0937c69, 0xd52da96f, 0x2512b3cf, + 0xac993bc8, 0x187da710, 0x9c636ee8, 0x3bbb7bdb, + 0x267809cd, 0x5918f46e, 0x9ab701ec, 0x4f9aa883, + 0x956e65e6, 0xffe67eaa, 0xbccf0821, 0x15e8e6ef, + 0xe79bd9ba, 0x6f36ce4a, 0x9f09d4ea, 0xb07cd629, + 0xa4b2af31, 0x3f23312a, 0xa59430c6, 0xa266c035, + 0x4ebc3774, 0x82caa6fc, 0x90d0b0e0, 0xa7d81533, + 0x04984af1, 0xecdaf741, 0xcd500e7f, 0x91f62f17, + 0x4dd68d76, 0xefb04d43, 0xaa4d54cc, 0x9604dfe4, + 0xd1b5e39e, 0x6a881b4c, 0x2c1fb8c1, 0x65517f46, + 0x5eea049d, 0x8c355d01, 0x877473fa, 0x0b412efb, + 0x671d5ab3, 0xdbd25292, 0x105633e9, 0xd647136d, + 0xd7618c9a, 0xa10c7a37, 0xf8148e59, 0x133c89eb, + 0xa927eece, 0x61c935b7, 0x1ce5ede1, 0x47b13c7a, + 0xd2df599c, 0xf2733f55, 0x14ce7918, 0xc737bf73, + 0xf7cdea53, 0xfdaa5b5f, 0x3d6f14df, 0x44db8678, + 0xaff381ca, 0x68c43eb9, 0x24342c38, 0xa3405fc2, + 0x1dc37216, 0xe2250cbc, 0x3c498b28, 0x0d9541ff, + 0xa8017139, 0x0cb3de08, 0xb4e49cd8, 0x56c19064, + 0xcb84617b, 0x32b670d5, 0x6c5c7448, 0xb85742d0 +]; + +var TD4 = [ + 0x52, 0x09, 0x6a, 0xd5, 0x30, 0x36, 0xa5, 0x38, + 0xbf, 0x40, 0xa3, 0x9e, 0x81, 0xf3, 0xd7, 0xfb, + 0x7c, 0xe3, 0x39, 0x82, 0x9b, 0x2f, 0xff, 0x87, + 0x34, 0x8e, 0x43, 0x44, 0xc4, 0xde, 0xe9, 0xcb, + 0x54, 0x7b, 0x94, 0x32, 0xa6, 0xc2, 0x23, 0x3d, + 0xee, 0x4c, 0x95, 0x0b, 0x42, 0xfa, 0xc3, 0x4e, + 0x08, 0x2e, 0xa1, 0x66, 0x28, 0xd9, 0x24, 0xb2, + 0x76, 0x5b, 0xa2, 0x49, 0x6d, 0x8b, 0xd1, 0x25, + 0x72, 0xf8, 0xf6, 0x64, 0x86, 0x68, 0x98, 0x16, + 0xd4, 0xa4, 0x5c, 0xcc, 0x5d, 0x65, 0xb6, 0x92, + 0x6c, 0x70, 0x48, 0x50, 0xfd, 0xed, 0xb9, 0xda, + 0x5e, 0x15, 0x46, 0x57, 0xa7, 0x8d, 0x9d, 0x84, + 0x90, 0xd8, 0xab, 0x00, 0x8c, 0xbc, 0xd3, 0x0a, + 0xf7, 0xe4, 0x58, 0x05, 0xb8, 0xb3, 0x45, 0x06, + 0xd0, 0x2c, 0x1e, 0x8f, 0xca, 0x3f, 0x0f, 0x02, + 0xc1, 0xaf, 0xbd, 0x03, 0x01, 0x13, 0x8a, 0x6b, + 0x3a, 0x91, 0x11, 0x41, 0x4f, 0x67, 0xdc, 0xea, + 0x97, 0xf2, 0xcf, 0xce, 0xf0, 0xb4, 0xe6, 0x73, + 0x96, 0xac, 0x74, 0x22, 0xe7, 0xad, 0x35, 0x85, + 0xe2, 0xf9, 0x37, 0xe8, 0x1c, 0x75, 0xdf, 0x6e, + 0x47, 0xf1, 0x1a, 0x71, 0x1d, 0x29, 0xc5, 0x89, + 0x6f, 0xb7, 0x62, 0x0e, 0xaa, 0x18, 0xbe, 0x1b, + 0xfc, 0x56, 0x3e, 0x4b, 0xc6, 0xd2, 0x79, 0x20, + 0x9a, 0xdb, 0xc0, 0xfe, 0x78, 0xcd, 0x5a, 0xf4, + 0x1f, 0xdd, 0xa8, 0x33, 0x88, 0x07, 0xc7, 0x31, + 0xb1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xec, 0x5f, + 0x60, 0x51, 0x7f, 0xa9, 0x19, 0xb5, 0x4a, 0x0d, + 0x2d, 0xe5, 0x7a, 0x9f, 0x93, 0xc9, 0x9c, 0xef, + 0xa0, 0xe0, 0x3b, 0x4d, 0xae, 0x2a, 0xf5, 0xb0, + 0xc8, 0xeb, 0xbb, 0x3c, 0x83, 0x53, 0x99, 0x61, + 0x17, 0x2b, 0x04, 0x7e, 0xba, 0x77, 0xd6, 0x26, + 0xe1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0c, 0x7d +]; + +var RCON = [ + 0x01000000, 0x02000000, 0x04000000, 0x08000000, + 0x10000000, 0x20000000, 0x40000000, 0x80000000, + 0x1B000000, 0x36000000 +]; diff --git a/lib/crypto/aes.js b/lib/crypto/aes.js index 9cabecad..6bb5f3ab 100644 --- a/lib/crypto/aes.js +++ b/lib/crypto/aes.js @@ -1,729 +1,18 @@ /*! - * aes.js - aes128/192/256 for bcoin - * Copyright (c) 2016-2017, Christopher Jeffrey (MIT License). + * aes.js - aes for bcoin + * Copyright (c) 2014-2017, Christopher Jeffrey (MIT License). * https://github.com/bcoin-org/bcoin - * - * Ported from: - * https://github.com/openssl/openssl/blob/master/crypto/aes/aes_core.c - * Entered into the public domain by Vincent Rijmen. */ -/* jshint latedef: false */ - 'use strict'; -var assert = require('assert'); - /** - * @exports crypto/aes - * @ignore + * @module crypto.aes */ -var AES = exports; - -/** - * An AES key object for encrypting - * and decrypting blocks. - * @alias module:crypto/aes.AESKey - * @constructor - * @param {Buffer} key - * @param {Number} bits - */ - -function AESKey(key, bits) { - if (!(this instanceof AESKey)) - return new AESKey(key, bits); - - this.rounds = null; - this.userKey = key; - this.bits = bits; - - 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; -} - -/** - * Destroy the object and zero the keys. - */ - -AESKey.prototype.destroy = function destroy() { - var i; - - assert(this.userKey, 'Already destroyed.'); - - // User should zero this. - this.userKey = null; - - if (this.decryptKey) { - for (i = 0; i < this.decryptKey.length; i++) - this.decryptKey[i] = 0; - this.decryptKey = null; - } - - if (this.encryptKey) { - for (i = 0; i < this.encryptKey.length; i++) - this.encryptKey[i] = 0; - this.encryptKey = null; - } -}; - -/** - * Convert the user key into an encryption key. - * @returns {Uint32Array} key - */ - -AESKey.prototype.getEncryptKey = function getEncryptKey() { - var i = 0; - var key, kp, tmp; - - assert(this.userKey, 'Cannot use key once it is destroyed.'); - - if (this.encryptKey) - return this.encryptKey; - - key = new Uint32Array(60); - kp = 0; - - key[kp + 0] = readU32(this.userKey, 0); - key[kp + 1] = readU32(this.userKey, 4); - key[kp + 2] = readU32(this.userKey, 8); - key[kp + 3] = readU32(this.userKey, 12); - - this.encryptKey = key; - - if (this.bits === 128) { - for (;;) { - tmp = key[kp + 3]; - - key[kp + 4] = key[kp + 0] - ^ (TE2[(tmp >>> 16) & 0xff] & 0xff000000) - ^ (TE3[(tmp >>> 8) & 0xff] & 0x00ff0000) - ^ (TE0[(tmp >>> 0) & 0xff] & 0x0000ff00) - ^ (TE1[(tmp >>> 24) & 0xff] & 0x000000ff) - ^ RCON[i]; - key[kp + 5] = key[kp + 1] ^ key[kp + 4]; - key[kp + 6] = key[kp + 2] ^ key[kp + 5]; - key[kp + 7] = key[kp + 3] ^ key[kp + 6]; - - if (++i === 10) - return key; - - kp += 4; - } - } - - key[kp + 4] = readU32(this.userKey, 16); - key[kp + 5] = readU32(this.userKey, 20); - - if (this.bits === 192) { - for (;;) { - tmp = key[kp + 5]; - - key[kp + 6] = key[kp + 0] - ^ (TE2[(tmp >>> 16) & 0xff] & 0xff000000) - ^ (TE3[(tmp >>> 8) & 0xff] & 0x00ff0000) - ^ (TE0[(tmp >>> 0) & 0xff] & 0x0000ff00) - ^ (TE1[(tmp >>> 24) & 0xff] & 0x000000ff) - ^ RCON[i]; - key[kp + 7] = key[kp + 1] ^ key[kp + 6]; - key[kp + 8] = key[kp + 2] ^ key[kp + 7]; - key[kp + 9] = key[kp + 3] ^ key[kp + 8]; - - if (++i === 8) - return key; - - key[kp + 10] = key[kp + 4] ^ key[kp + 9]; - key[kp + 11] = key[kp + 5] ^ key[kp + 10]; - kp += 6; - } - } - - key[kp + 6] = readU32(this.userKey, 24); - key[kp + 7] = readU32(this.userKey, 28); - - if (this.bits === 256) { - for (;;) { - tmp = key[kp + 7]; - - key[kp + 8] = key[kp + 0] - ^ (TE2[(tmp >>> 16) & 0xff] & 0xff000000) - ^ (TE3[(tmp >>> 8) & 0xff] & 0x00ff0000) - ^ (TE0[(tmp >>> 0) & 0xff] & 0x0000ff00) - ^ (TE1[(tmp >>> 24) & 0xff] & 0x000000ff) - ^ RCON[i]; - key[kp + 9] = key[kp + 1] ^ key[kp + 8]; - key[kp + 10] = key[kp + 2] ^ key[kp + 9]; - key[kp + 11] = key[kp + 3] ^ key[kp + 10]; - - if (++i === 7) - return key; - - tmp = key[kp + 11]; - - key[kp + 12] = key[kp + 4] - ^ (TE2[(tmp >>> 24) & 0xff] & 0xff000000) - ^ (TE3[(tmp >>> 16) & 0xff] & 0x00ff0000) - ^ (TE0[(tmp >>> 8) & 0xff] & 0x0000ff00) - ^ (TE1[(tmp >>> 0) & 0xff] & 0x000000ff); - key[kp + 13] = key[kp + 5] ^ key[kp + 12]; - key[kp + 14] = key[kp + 6] ^ key[kp + 13]; - key[kp + 15] = key[kp + 7] ^ key[kp + 14]; - - kp += 8; - } - } - - return key; -}; - -/** - * Convert the user key into a decryption key. - * @returns {Uint32Array} key - */ - -AESKey.prototype.getDecryptKey = function getDecryptKey() { - var i, j, kp, enc, key, tmp; - - assert(this.userKey, 'Cannot use key once it is destroyed.'); - - if (this.decryptKey) - return this.decryptKey; - - // First, start with an encryption schedule. - enc = this.getEncryptKey(); - key = new Uint32Array(60); - kp = 0; - - for (i = 0; i < enc.length; i++) - key[i] = enc[i]; - - this.decryptKey = key; - - // Invert the order of the round keys. - for (i = 0, j = 4 * this.rounds; i < j; i += 4, j -= 4) { - tmp = key[kp + i + 0]; - key[kp + i + 0] = key[kp + j + 0]; - key[kp + j + 0] = tmp; - - tmp = key[kp + i + 1]; - key[kp + i + 1] = key[kp + j + 1]; - key[kp + j + 1] = tmp; - - tmp = key[kp + i + 2]; - key[kp + i + 2] = key[kp + j + 2]; - key[kp + j + 2] = tmp; - - tmp = key[kp + i + 3]; - key[kp + i + 3] = key[kp + j + 3]; - key[kp + j + 3] = tmp; - } - - // Apply the inverse MixColumn transform to - // all round keys but the first and the last. - for (i = 1; i < this.rounds; i++) { - kp += 4; - key[kp + 0] = TD0[TE1[(key[kp + 0] >>> 24) & 0xff] & 0xff] - ^ TD1[TE1[(key[kp + 0] >>> 16) & 0xff] & 0xff] - ^ TD2[TE1[(key[kp + 0] >>> 8) & 0xff] & 0xff] - ^ TD3[TE1[(key[kp + 0] >>> 0) & 0xff] & 0xff]; - key[kp + 1] = TD0[TE1[(key[kp + 1] >>> 24) & 0xff] & 0xff] - ^ TD1[TE1[(key[kp + 1] >>> 16) & 0xff] & 0xff] - ^ TD2[TE1[(key[kp + 1] >>> 8) & 0xff] & 0xff] - ^ TD3[TE1[(key[kp + 1] >>> 0) & 0xff] & 0xff]; - key[kp + 2] = TD0[TE1[(key[kp + 2] >>> 24) & 0xff] & 0xff] - ^ TD1[TE1[(key[kp + 2] >>> 16) & 0xff] & 0xff] - ^ TD2[TE1[(key[kp + 2] >>> 8) & 0xff] & 0xff] - ^ TD3[TE1[(key[kp + 2] >>> 0) & 0xff] & 0xff]; - key[kp + 3] = TD0[TE1[(key[kp + 3] >>> 24) & 0xff] & 0xff] - ^ TD1[TE1[(key[kp + 3] >>> 16) & 0xff] & 0xff] - ^ TD2[TE1[(key[kp + 3] >>> 8) & 0xff] & 0xff] - ^ TD3[TE1[(key[kp + 3] >>> 0) & 0xff] & 0xff]; - } - - return key; -}; - -/** - * Encrypt a 16 byte block of data. - * @param {Buffer} input - * @returns {Buffer} - */ - -AESKey.prototype.encryptBlock = function encryptBlock(input) { - var output, kp, key, r, s0, s1, s2, s3, t0, t1, t2, t3; - - assert(this.userKey, 'Cannot use key once it is destroyed.'); - - key = this.getEncryptKey(); - kp = 0; - - // Map byte array block to cipher - // state and add initial round key. - s0 = readU32(input, 0) ^ key[0]; - s1 = readU32(input, 4) ^ key[1]; - s2 = readU32(input, 8) ^ key[2]; - s3 = readU32(input, 12) ^ key[3]; - - // Nr - 1 full rounds - r = this.rounds >>> 1; - - for (;;) { - t0 = TE0[(s0 >>> 24) & 0xff] - ^ TE1[(s1 >>> 16) & 0xff] - ^ TE2[(s2 >>> 8) & 0xff] - ^ TE3[(s3 >>> 0) & 0xff] - ^ key[kp + 4]; - t1 = TE0[(s1 >>> 24) & 0xff] - ^ TE1[(s2 >>> 16) & 0xff] - ^ TE2[(s3 >>> 8) & 0xff] - ^ TE3[(s0 >>> 0) & 0xff] - ^ key[kp + 5]; - t2 = TE0[(s2 >>> 24) & 0xff] - ^ TE1[(s3 >>> 16) & 0xff] - ^ TE2[(s0 >>> 8) & 0xff] - ^ TE3[(s1 >>> 0) & 0xff] - ^ key[kp + 6]; - t3 = TE0[(s3 >>> 24) & 0xff] - ^ TE1[(s0 >>> 16) & 0xff] - ^ TE2[(s1 >>> 8) & 0xff] - ^ TE3[(s2 >>> 0) & 0xff] - ^ key[kp + 7]; - - kp += 8; - - if (--r === 0) - break; - - s0 = TE0[(t0 >>> 24) & 0xff] - ^ TE1[(t1 >>> 16) & 0xff] - ^ TE2[(t2 >>> 8) & 0xff] - ^ TE3[(t3 >>> 0) & 0xff] - ^ key[kp + 0]; - s1 = TE0[(t1 >>> 24) & 0xff] - ^ TE1[(t2 >>> 16) & 0xff] - ^ TE2[(t3 >>> 8) & 0xff] - ^ TE3[(t0 >>> 0) & 0xff] - ^ key[kp + 1]; - s2 = TE0[(t2 >>> 24) & 0xff] - ^ TE1[(t3 >>> 16) & 0xff] - ^ TE2[(t0 >>> 8) & 0xff] - ^ TE3[(t1 >>> 0) & 0xff] - ^ key[kp + 2]; - s3 = TE0[(t3 >>> 24) & 0xff] - ^ TE1[(t0 >>> 16) & 0xff] - ^ TE2[(t1 >>> 8) & 0xff] - ^ TE3[(t2 >>> 0) & 0xff] - ^ key[kp + 3]; - } - - // Apply last round and map cipher - // state to byte array block. - s0 = (TE2[(t0 >>> 24) & 0xff] & 0xff000000) - ^ (TE3[(t1 >>> 16) & 0xff] & 0x00ff0000) - ^ (TE0[(t2 >>> 8) & 0xff] & 0x0000ff00) - ^ (TE1[(t3 >>> 0) & 0xff] & 0x000000ff) - ^ key[kp + 0]; - s1 = (TE2[(t1 >>> 24) & 0xff] & 0xff000000) - ^ (TE3[(t2 >>> 16) & 0xff] & 0x00ff0000) - ^ (TE0[(t3 >>> 8) & 0xff] & 0x0000ff00) - ^ (TE1[(t0 >>> 0) & 0xff] & 0x000000ff) - ^ key[kp + 1]; - s2 = (TE2[(t2 >>> 24) & 0xff] & 0xff000000) - ^ (TE3[(t3 >>> 16) & 0xff] & 0x00ff0000) - ^ (TE0[(t0 >>> 8) & 0xff] & 0x0000ff00) - ^ (TE1[(t1 >>> 0) & 0xff] & 0x000000ff) - ^ key[kp + 2]; - s3 = (TE2[(t3 >>> 24) & 0xff] & 0xff000000) - ^ (TE3[(t0 >>> 16) & 0xff] & 0x00ff0000) - ^ (TE0[(t1 >>> 8) & 0xff] & 0x0000ff00) - ^ (TE1[(t2 >>> 0) & 0xff] & 0x000000ff) - ^ key[kp + 3]; - - output = Buffer.allocUnsafe(16); - writeU32(output, s0, 0); - writeU32(output, s1, 4); - writeU32(output, s2, 8); - writeU32(output, s3, 12); - - return output; -}; - -/** - * Decrypt a 16 byte block of data. - * @param {Buffer} input - * @returns {Buffer} - */ - -AESKey.prototype.decryptBlock = function decryptBlock(input) { - var output, kp, key, r, s0, s1, s2, s3, t0, t1, t2, t3; - - assert(this.userKey, 'Cannot use AESKey once it is destroyed.'); - - key = this.getDecryptKey(); - kp = 0; - - // Map byte array block to cipher - // state and add initial round key. - s0 = readU32(input, 0) ^ key[kp + 0]; - s1 = readU32(input, 4) ^ key[kp + 1]; - s2 = readU32(input, 8) ^ key[kp + 2]; - s3 = readU32(input, 12) ^ key[kp + 3]; - - // Nr - 1 full rounds - r = this.rounds >>> 1; - - for (;;) { - t0 = TD0[(s0 >>> 24) & 0xff] - ^ TD1[(s3 >>> 16) & 0xff] - ^ TD2[(s2 >>> 8) & 0xff] - ^ TD3[(s1 >>> 0) & 0xff] - ^ key[kp + 4]; - t1 = TD0[(s1 >>> 24) & 0xff] - ^ TD1[(s0 >>> 16) & 0xff] - ^ TD2[(s3 >>> 8) & 0xff] - ^ TD3[(s2 >>> 0) & 0xff] - ^ key[kp + 5]; - t2 = TD0[(s2 >>> 24) & 0xff] - ^ TD1[(s1 >>> 16) & 0xff] - ^ TD2[(s0 >>> 8) & 0xff] - ^ TD3[(s3 >>> 0) & 0xff] - ^ key[kp + 6]; - t3 = TD0[(s3 >>> 24) & 0xff] - ^ TD1[(s2 >>> 16) & 0xff] - ^ TD2[(s1 >>> 8) & 0xff] - ^ TD3[(s0 >>> 0) & 0xff] - ^ key[kp + 7]; - - kp += 8; - - if (--r === 0) - break; - - s0 = TD0[(t0 >>> 24) & 0xff] - ^ TD1[(t3 >>> 16) & 0xff] - ^ TD2[(t2 >>> 8) & 0xff] - ^ TD3[(t1 >>> 0) & 0xff] - ^ key[kp + 0]; - s1 = TD0[(t1 >>> 24) & 0xff] - ^ TD1[(t0 >>> 16) & 0xff] - ^ TD2[(t3 >>> 8) & 0xff] - ^ TD3[(t2 >>> 0) & 0xff] - ^ key[kp + 1]; - s2 = TD0[(t2 >>> 24) & 0xff] - ^ TD1[(t1 >>> 16) & 0xff] - ^ TD2[(t0 >>> 8) & 0xff] - ^ TD3[(t3 >>> 0) & 0xff] - ^ key[kp + 2]; - s3 = TD0[(t3 >>> 24) & 0xff] - ^ TD1[(t2 >>> 16) & 0xff] - ^ TD2[(t1 >>> 8) & 0xff] - ^ TD3[(t0 >>> 0) & 0xff] - ^ key[kp + 3]; - } - - // Apply last round and map cipher - // state to byte array block. - s0 = (TD4[(t0 >>> 24) & 0xff] << 24) - ^ (TD4[(t3 >>> 16) & 0xff] << 16) - ^ (TD4[(t2 >>> 8) & 0xff] << 8) - ^ (TD4[(t1 >>> 0) & 0xff] << 0) - ^ key[kp + 0]; - s1 = (TD4[(t1 >>> 24) & 0xff] << 24) - ^ (TD4[(t0 >>> 16) & 0xff] << 16) - ^ (TD4[(t3 >>> 8) & 0xff] << 8) - ^ (TD4[(t2 >>> 0) & 0xff] << 0) - ^ key[kp + 1]; - s2 = (TD4[(t2 >>> 24) & 0xff] << 24) - ^ (TD4[(t1 >>> 16) & 0xff] << 16) - ^ (TD4[(t0 >>> 8) & 0xff] << 8) - ^ (TD4[(t3 >>> 0) & 0xff] << 0) - ^ key[kp + 2]; - s3 = (TD4[(t3 >>> 24) & 0xff] << 24) - ^ (TD4[(t2 >>> 16) & 0xff] << 16) - ^ (TD4[(t1 >>> 8) & 0xff] << 8) - ^ (TD4[(t0 >>> 0) & 0xff] << 0) - ^ key[kp + 3]; - - output = Buffer.allocUnsafe(16); - writeU32(output, s0, 0); - writeU32(output, s1, 4); - writeU32(output, s2, 8); - writeU32(output, s3, 12); - - return output; -}; - -/** - * AES cipher. - * @alias module:crypto/aes.AESCipher - * @constructor - * @param {Buffer} key - * @param {Buffer} iv - * @param {Number} bits - * @param {String} mode - */ - -function AESCipher(key, iv, bits, mode) { - if (!(this instanceof AESCipher)) - return new AESCipher(key, iv, mode); - - assert(mode === 'ecb' || mode === 'cbc', 'Unknown mode.'); - - this.key = new AESKey(key, bits); - this.mode = mode; - this.prev = iv; - this.waiting = null; -} - -/** - * Encrypt blocks of data. - * @param {Buffer} data - * @returns {Buffer} - */ - -AESCipher.prototype.update = function update(data) { - var blocks = []; - var i, len, trailing, block; - - if (this.waiting) { - data = concat(this.waiting, data); - this.waiting = null; - } - - trailing = data.length % 16; - len = data.length - trailing; - - // Encrypt all blocks except for the last. - for (i = 0; i < len; i += 16) { - block = data.slice(i, i + 16); - if (this.mode === 'cbc') - block = xor(block, this.prev); - this.prev = this.key.encryptBlock(block); - blocks.push(this.prev); - } - - if (trailing > 0) - this.waiting = data.slice(len); - - return Buffer.concat(blocks); -}; - -/** - * Finalize the cipher. - * @returns {Buffer} - */ - -AESCipher.prototype.final = function final() { - var block, left, pad; - - // Handle padding on the last block. - if (!this.waiting) { - block = Buffer.allocUnsafe(16); - block.fill(16); - } else { - block = this.waiting; - left = 16 - block.length; - pad = Buffer.allocUnsafe(left); - pad.fill(left); - block = concat(block, pad); - } - - // Encrypt the last block, - // as well as the padding. - if (this.mode === 'cbc') - block = xor(block, this.prev); - - block = this.key.encryptBlock(block); - - this.key.destroy(); - - return block; -}; - -/** - * AES decipher. - * @alias module:crypto/aes.AESDecipher - * @constructor - * @param {Buffer} key - * @param {Buffer} iv - * @param {Number} bits - * @param {String} mode - */ - -function AESDecipher(key, iv, bits, mode) { - if (!(this instanceof AESDecipher)) - return new AESDecipher(key, iv, mode); - - assert(mode === 'ecb' || mode === 'cbc', 'Unknown mode.'); - - this.key = new AESKey(key, bits); - this.mode = mode; - this.prev = iv; - this.waiting = null; - this.lastBlock = null; -} - -/** - * Decrypt blocks of data. - * @param {Buffer} data - */ - -AESDecipher.prototype.update = function update(data) { - var blocks = []; - var i, chunk, block, len, trailing; - - if (this.waiting) { - data = concat(this.waiting, data); - this.waiting = null; - } - - trailing = data.length % 16; - len = data.length - trailing; - - // Decrypt all blocks. - for (i = 0; i < len; i += 16) { - chunk = this.prev; - this.prev = data.slice(i, i + 16); - block = this.key.decryptBlock(this.prev); - if (this.mode === 'cbc') - block = xor(block, chunk); - blocks.push(block); - } - - if (trailing > 0) - this.waiting = data.slice(len); - - if (this.lastBlock) { - blocks.unshift(this.lastBlock); - this.lastBlock = null; - } - - // Keep a reference to the last - // block for the padding check. - this.lastBlock = blocks.pop(); - - return Buffer.concat(blocks); -}; - -/** - * Finalize the decipher. - * @returns {Buffer} - */ - -AESDecipher.prototype.final = function final() { - var i, b, n, block; - - this.key.destroy(); - - assert(!this.waiting, 'Bad decrypt (trailing bytes).'); - assert(this.lastBlock, 'Bad decrypt (no data).'); - - // Check padding on the last block. - block = this.lastBlock; - b = 16; - n = block[b - 1]; - - if (n === 0 || n > b) - throw new Error('Bad decrypt (padding).'); - - for (i = 0; i < n; i++) { - if (block[--b] !== n) - throw new Error('Bad decrypt (padding).'); - } - - // Slice off the padding unless - // the entire block was padding. - if (n === 16) - return Buffer.alloc(0); - - block = block.slice(0, -n); - - return block; -}; - -/** - * Encrypt data with aes 256. - * @param {Buffer} data - * @param {Buffer} key - * @param {Buffer} iv - * @param {String} mode - * @returns {Buffer} - */ - -AES.encrypt = function encrypt(data, key, iv, bits, mode) { - var cipher = new AESCipher(key, iv, bits, mode); - return concat(cipher.update(data), cipher.final()); -}; - -/** - * Decrypt data with aes 256. - * @param {Buffer} data - * @param {Buffer} key - * @param {Buffer|null} iv - * @param {Number} bits - * @param {String} mode - * @returns {Buffer} - */ - -AES.decrypt = function decrypt(data, key, iv, bits, mode) { - var decipher = new AESDecipher(key, iv, bits, mode); - return concat(decipher.update(data), decipher.final()); -}; - -/** - * Electronic codebook mode. - */ - -AES.ecb = {}; - -/** - * Encrypt data with aes 256 ecb. - * @param {Buffer} data - * @param {Buffer} key - * @returns {Buffer} - */ - -AES.ecb.encrypt = function encrypt(data, key) { - assert(Buffer.isBuffer(data)); - assert(key.length === 32); - return AES.encrypt(data, key, null, 256, 'ecb'); -}; - -/** - * Decrypt data with aes 256 ecb. - * @param {Buffer} data - * @param {Buffer} key - * @returns {Buffer} - */ - -AES.ecb.decrypt = function decrypt(data, key) { - assert(Buffer.isBuffer(data)); - assert(key.length === 32); - return AES.decrypt(data, key, null, 256, 'ecb'); -}; - -/** - * Cipher block chaining mode. - */ - -AES.cbc = {}; +var crypto = require('crypto'); +var util = require('../utils/util'); +var native = require('../utils/native').binding; /** * Encrypt data with aes 256 cbc. @@ -733,11 +22,9 @@ AES.cbc = {}; * @returns {Buffer} */ -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'); +exports.encipher = function encipher(data, key, iv) { + var cipher = crypto.createCipheriv('aes-256-cbc', key, iv); + return util.concat(cipher.update(data), cipher.final()); }; /** @@ -748,632 +35,16 @@ AES.cbc.encrypt = function encrypt(data, key, iv) { * @returns {Buffer} */ -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'); +exports.decipher = function decipher(data, key, iv) { + var decipher = crypto.createDecipheriv('aes-256-cbc', key, iv); + try { + return util.concat(decipher.update(data), decipher.final()); + } catch (e) { + throw new Error('Bad key for decryption.'); + } }; -/* - * Expose - */ - -AES.Key = AESKey; -AES.Cipher = AESCipher; -AES.Decipher = AESDecipher; -AES.encipher = AES.cbc.encrypt; -AES.decipher = AES.cbc.decrypt; - -/* - * Helpers - */ - -function xor(v1, v2) { - var out = Buffer.allocUnsafe(v1.length); - for (var i = 0; i < v1.length; i++) - out[i] = v1[i] ^ v2[i]; - return out; +if (native) { + exports.encipher = native.encipher; + exports.decipher = native.decipher; } - -function readU32(data, i) { - return (data[i + 0] << 24) - ^ (data[i + 1] << 16) - ^ (data[i + 2] << 8) - ^ data[i + 3]; -} - -function writeU32(data, value, i) { - data[i + 0] = (value >>> 24) & 0xff; - data[i + 1] = (value >>> 16) & 0xff; - data[i + 2] = (value >>> 8) & 0xff; - data[i + 3] = value & 0xff; -} - -function concat(a, b) { - var data = Buffer.allocUnsafe(a.length + b.length); - a.copy(data, 0); - b.copy(data, a.length); - return data; -} - -/* - * Tables - */ - -var TE0 = [ - 0xc66363a5, 0xf87c7c84, 0xee777799, 0xf67b7b8d, - 0xfff2f20d, 0xd66b6bbd, 0xde6f6fb1, 0x91c5c554, - 0x60303050, 0x02010103, 0xce6767a9, 0x562b2b7d, - 0xe7fefe19, 0xb5d7d762, 0x4dababe6, 0xec76769a, - 0x8fcaca45, 0x1f82829d, 0x89c9c940, 0xfa7d7d87, - 0xeffafa15, 0xb25959eb, 0x8e4747c9, 0xfbf0f00b, - 0x41adadec, 0xb3d4d467, 0x5fa2a2fd, 0x45afafea, - 0x239c9cbf, 0x53a4a4f7, 0xe4727296, 0x9bc0c05b, - 0x75b7b7c2, 0xe1fdfd1c, 0x3d9393ae, 0x4c26266a, - 0x6c36365a, 0x7e3f3f41, 0xf5f7f702, 0x83cccc4f, - 0x6834345c, 0x51a5a5f4, 0xd1e5e534, 0xf9f1f108, - 0xe2717193, 0xabd8d873, 0x62313153, 0x2a15153f, - 0x0804040c, 0x95c7c752, 0x46232365, 0x9dc3c35e, - 0x30181828, 0x379696a1, 0x0a05050f, 0x2f9a9ab5, - 0x0e070709, 0x24121236, 0x1b80809b, 0xdfe2e23d, - 0xcdebeb26, 0x4e272769, 0x7fb2b2cd, 0xea75759f, - 0x1209091b, 0x1d83839e, 0x582c2c74, 0x341a1a2e, - 0x361b1b2d, 0xdc6e6eb2, 0xb45a5aee, 0x5ba0a0fb, - 0xa45252f6, 0x763b3b4d, 0xb7d6d661, 0x7db3b3ce, - 0x5229297b, 0xdde3e33e, 0x5e2f2f71, 0x13848497, - 0xa65353f5, 0xb9d1d168, 0x00000000, 0xc1eded2c, - 0x40202060, 0xe3fcfc1f, 0x79b1b1c8, 0xb65b5bed, - 0xd46a6abe, 0x8dcbcb46, 0x67bebed9, 0x7239394b, - 0x944a4ade, 0x984c4cd4, 0xb05858e8, 0x85cfcf4a, - 0xbbd0d06b, 0xc5efef2a, 0x4faaaae5, 0xedfbfb16, - 0x864343c5, 0x9a4d4dd7, 0x66333355, 0x11858594, - 0x8a4545cf, 0xe9f9f910, 0x04020206, 0xfe7f7f81, - 0xa05050f0, 0x783c3c44, 0x259f9fba, 0x4ba8a8e3, - 0xa25151f3, 0x5da3a3fe, 0x804040c0, 0x058f8f8a, - 0x3f9292ad, 0x219d9dbc, 0x70383848, 0xf1f5f504, - 0x63bcbcdf, 0x77b6b6c1, 0xafdada75, 0x42212163, - 0x20101030, 0xe5ffff1a, 0xfdf3f30e, 0xbfd2d26d, - 0x81cdcd4c, 0x180c0c14, 0x26131335, 0xc3ecec2f, - 0xbe5f5fe1, 0x359797a2, 0x884444cc, 0x2e171739, - 0x93c4c457, 0x55a7a7f2, 0xfc7e7e82, 0x7a3d3d47, - 0xc86464ac, 0xba5d5de7, 0x3219192b, 0xe6737395, - 0xc06060a0, 0x19818198, 0x9e4f4fd1, 0xa3dcdc7f, - 0x44222266, 0x542a2a7e, 0x3b9090ab, 0x0b888883, - 0x8c4646ca, 0xc7eeee29, 0x6bb8b8d3, 0x2814143c, - 0xa7dede79, 0xbc5e5ee2, 0x160b0b1d, 0xaddbdb76, - 0xdbe0e03b, 0x64323256, 0x743a3a4e, 0x140a0a1e, - 0x924949db, 0x0c06060a, 0x4824246c, 0xb85c5ce4, - 0x9fc2c25d, 0xbdd3d36e, 0x43acacef, 0xc46262a6, - 0x399191a8, 0x319595a4, 0xd3e4e437, 0xf279798b, - 0xd5e7e732, 0x8bc8c843, 0x6e373759, 0xda6d6db7, - 0x018d8d8c, 0xb1d5d564, 0x9c4e4ed2, 0x49a9a9e0, - 0xd86c6cb4, 0xac5656fa, 0xf3f4f407, 0xcfeaea25, - 0xca6565af, 0xf47a7a8e, 0x47aeaee9, 0x10080818, - 0x6fbabad5, 0xf0787888, 0x4a25256f, 0x5c2e2e72, - 0x381c1c24, 0x57a6a6f1, 0x73b4b4c7, 0x97c6c651, - 0xcbe8e823, 0xa1dddd7c, 0xe874749c, 0x3e1f1f21, - 0x964b4bdd, 0x61bdbddc, 0x0d8b8b86, 0x0f8a8a85, - 0xe0707090, 0x7c3e3e42, 0x71b5b5c4, 0xcc6666aa, - 0x904848d8, 0x06030305, 0xf7f6f601, 0x1c0e0e12, - 0xc26161a3, 0x6a35355f, 0xae5757f9, 0x69b9b9d0, - 0x17868691, 0x99c1c158, 0x3a1d1d27, 0x279e9eb9, - 0xd9e1e138, 0xebf8f813, 0x2b9898b3, 0x22111133, - 0xd26969bb, 0xa9d9d970, 0x078e8e89, 0x339494a7, - 0x2d9b9bb6, 0x3c1e1e22, 0x15878792, 0xc9e9e920, - 0x87cece49, 0xaa5555ff, 0x50282878, 0xa5dfdf7a, - 0x038c8c8f, 0x59a1a1f8, 0x09898980, 0x1a0d0d17, - 0x65bfbfda, 0xd7e6e631, 0x844242c6, 0xd06868b8, - 0x824141c3, 0x299999b0, 0x5a2d2d77, 0x1e0f0f11, - 0x7bb0b0cb, 0xa85454fc, 0x6dbbbbd6, 0x2c16163a -]; - -var TE1 = [ - 0xa5c66363, 0x84f87c7c, 0x99ee7777, 0x8df67b7b, - 0x0dfff2f2, 0xbdd66b6b, 0xb1de6f6f, 0x5491c5c5, - 0x50603030, 0x03020101, 0xa9ce6767, 0x7d562b2b, - 0x19e7fefe, 0x62b5d7d7, 0xe64dabab, 0x9aec7676, - 0x458fcaca, 0x9d1f8282, 0x4089c9c9, 0x87fa7d7d, - 0x15effafa, 0xebb25959, 0xc98e4747, 0x0bfbf0f0, - 0xec41adad, 0x67b3d4d4, 0xfd5fa2a2, 0xea45afaf, - 0xbf239c9c, 0xf753a4a4, 0x96e47272, 0x5b9bc0c0, - 0xc275b7b7, 0x1ce1fdfd, 0xae3d9393, 0x6a4c2626, - 0x5a6c3636, 0x417e3f3f, 0x02f5f7f7, 0x4f83cccc, - 0x5c683434, 0xf451a5a5, 0x34d1e5e5, 0x08f9f1f1, - 0x93e27171, 0x73abd8d8, 0x53623131, 0x3f2a1515, - 0x0c080404, 0x5295c7c7, 0x65462323, 0x5e9dc3c3, - 0x28301818, 0xa1379696, 0x0f0a0505, 0xb52f9a9a, - 0x090e0707, 0x36241212, 0x9b1b8080, 0x3ddfe2e2, - 0x26cdebeb, 0x694e2727, 0xcd7fb2b2, 0x9fea7575, - 0x1b120909, 0x9e1d8383, 0x74582c2c, 0x2e341a1a, - 0x2d361b1b, 0xb2dc6e6e, 0xeeb45a5a, 0xfb5ba0a0, - 0xf6a45252, 0x4d763b3b, 0x61b7d6d6, 0xce7db3b3, - 0x7b522929, 0x3edde3e3, 0x715e2f2f, 0x97138484, - 0xf5a65353, 0x68b9d1d1, 0x00000000, 0x2cc1eded, - 0x60402020, 0x1fe3fcfc, 0xc879b1b1, 0xedb65b5b, - 0xbed46a6a, 0x468dcbcb, 0xd967bebe, 0x4b723939, - 0xde944a4a, 0xd4984c4c, 0xe8b05858, 0x4a85cfcf, - 0x6bbbd0d0, 0x2ac5efef, 0xe54faaaa, 0x16edfbfb, - 0xc5864343, 0xd79a4d4d, 0x55663333, 0x94118585, - 0xcf8a4545, 0x10e9f9f9, 0x06040202, 0x81fe7f7f, - 0xf0a05050, 0x44783c3c, 0xba259f9f, 0xe34ba8a8, - 0xf3a25151, 0xfe5da3a3, 0xc0804040, 0x8a058f8f, - 0xad3f9292, 0xbc219d9d, 0x48703838, 0x04f1f5f5, - 0xdf63bcbc, 0xc177b6b6, 0x75afdada, 0x63422121, - 0x30201010, 0x1ae5ffff, 0x0efdf3f3, 0x6dbfd2d2, - 0x4c81cdcd, 0x14180c0c, 0x35261313, 0x2fc3ecec, - 0xe1be5f5f, 0xa2359797, 0xcc884444, 0x392e1717, - 0x5793c4c4, 0xf255a7a7, 0x82fc7e7e, 0x477a3d3d, - 0xacc86464, 0xe7ba5d5d, 0x2b321919, 0x95e67373, - 0xa0c06060, 0x98198181, 0xd19e4f4f, 0x7fa3dcdc, - 0x66442222, 0x7e542a2a, 0xab3b9090, 0x830b8888, - 0xca8c4646, 0x29c7eeee, 0xd36bb8b8, 0x3c281414, - 0x79a7dede, 0xe2bc5e5e, 0x1d160b0b, 0x76addbdb, - 0x3bdbe0e0, 0x56643232, 0x4e743a3a, 0x1e140a0a, - 0xdb924949, 0x0a0c0606, 0x6c482424, 0xe4b85c5c, - 0x5d9fc2c2, 0x6ebdd3d3, 0xef43acac, 0xa6c46262, - 0xa8399191, 0xa4319595, 0x37d3e4e4, 0x8bf27979, - 0x32d5e7e7, 0x438bc8c8, 0x596e3737, 0xb7da6d6d, - 0x8c018d8d, 0x64b1d5d5, 0xd29c4e4e, 0xe049a9a9, - 0xb4d86c6c, 0xfaac5656, 0x07f3f4f4, 0x25cfeaea, - 0xafca6565, 0x8ef47a7a, 0xe947aeae, 0x18100808, - 0xd56fbaba, 0x88f07878, 0x6f4a2525, 0x725c2e2e, - 0x24381c1c, 0xf157a6a6, 0xc773b4b4, 0x5197c6c6, - 0x23cbe8e8, 0x7ca1dddd, 0x9ce87474, 0x213e1f1f, - 0xdd964b4b, 0xdc61bdbd, 0x860d8b8b, 0x850f8a8a, - 0x90e07070, 0x427c3e3e, 0xc471b5b5, 0xaacc6666, - 0xd8904848, 0x05060303, 0x01f7f6f6, 0x121c0e0e, - 0xa3c26161, 0x5f6a3535, 0xf9ae5757, 0xd069b9b9, - 0x91178686, 0x5899c1c1, 0x273a1d1d, 0xb9279e9e, - 0x38d9e1e1, 0x13ebf8f8, 0xb32b9898, 0x33221111, - 0xbbd26969, 0x70a9d9d9, 0x89078e8e, 0xa7339494, - 0xb62d9b9b, 0x223c1e1e, 0x92158787, 0x20c9e9e9, - 0x4987cece, 0xffaa5555, 0x78502828, 0x7aa5dfdf, - 0x8f038c8c, 0xf859a1a1, 0x80098989, 0x171a0d0d, - 0xda65bfbf, 0x31d7e6e6, 0xc6844242, 0xb8d06868, - 0xc3824141, 0xb0299999, 0x775a2d2d, 0x111e0f0f, - 0xcb7bb0b0, 0xfca85454, 0xd66dbbbb, 0x3a2c1616 -]; - -var TE2 = [ - 0x63a5c663, 0x7c84f87c, 0x7799ee77, 0x7b8df67b, - 0xf20dfff2, 0x6bbdd66b, 0x6fb1de6f, 0xc55491c5, - 0x30506030, 0x01030201, 0x67a9ce67, 0x2b7d562b, - 0xfe19e7fe, 0xd762b5d7, 0xabe64dab, 0x769aec76, - 0xca458fca, 0x829d1f82, 0xc94089c9, 0x7d87fa7d, - 0xfa15effa, 0x59ebb259, 0x47c98e47, 0xf00bfbf0, - 0xadec41ad, 0xd467b3d4, 0xa2fd5fa2, 0xafea45af, - 0x9cbf239c, 0xa4f753a4, 0x7296e472, 0xc05b9bc0, - 0xb7c275b7, 0xfd1ce1fd, 0x93ae3d93, 0x266a4c26, - 0x365a6c36, 0x3f417e3f, 0xf702f5f7, 0xcc4f83cc, - 0x345c6834, 0xa5f451a5, 0xe534d1e5, 0xf108f9f1, - 0x7193e271, 0xd873abd8, 0x31536231, 0x153f2a15, - 0x040c0804, 0xc75295c7, 0x23654623, 0xc35e9dc3, - 0x18283018, 0x96a13796, 0x050f0a05, 0x9ab52f9a, - 0x07090e07, 0x12362412, 0x809b1b80, 0xe23ddfe2, - 0xeb26cdeb, 0x27694e27, 0xb2cd7fb2, 0x759fea75, - 0x091b1209, 0x839e1d83, 0x2c74582c, 0x1a2e341a, - 0x1b2d361b, 0x6eb2dc6e, 0x5aeeb45a, 0xa0fb5ba0, - 0x52f6a452, 0x3b4d763b, 0xd661b7d6, 0xb3ce7db3, - 0x297b5229, 0xe33edde3, 0x2f715e2f, 0x84971384, - 0x53f5a653, 0xd168b9d1, 0x00000000, 0xed2cc1ed, - 0x20604020, 0xfc1fe3fc, 0xb1c879b1, 0x5bedb65b, - 0x6abed46a, 0xcb468dcb, 0xbed967be, 0x394b7239, - 0x4ade944a, 0x4cd4984c, 0x58e8b058, 0xcf4a85cf, - 0xd06bbbd0, 0xef2ac5ef, 0xaae54faa, 0xfb16edfb, - 0x43c58643, 0x4dd79a4d, 0x33556633, 0x85941185, - 0x45cf8a45, 0xf910e9f9, 0x02060402, 0x7f81fe7f, - 0x50f0a050, 0x3c44783c, 0x9fba259f, 0xa8e34ba8, - 0x51f3a251, 0xa3fe5da3, 0x40c08040, 0x8f8a058f, - 0x92ad3f92, 0x9dbc219d, 0x38487038, 0xf504f1f5, - 0xbcdf63bc, 0xb6c177b6, 0xda75afda, 0x21634221, - 0x10302010, 0xff1ae5ff, 0xf30efdf3, 0xd26dbfd2, - 0xcd4c81cd, 0x0c14180c, 0x13352613, 0xec2fc3ec, - 0x5fe1be5f, 0x97a23597, 0x44cc8844, 0x17392e17, - 0xc45793c4, 0xa7f255a7, 0x7e82fc7e, 0x3d477a3d, - 0x64acc864, 0x5de7ba5d, 0x192b3219, 0x7395e673, - 0x60a0c060, 0x81981981, 0x4fd19e4f, 0xdc7fa3dc, - 0x22664422, 0x2a7e542a, 0x90ab3b90, 0x88830b88, - 0x46ca8c46, 0xee29c7ee, 0xb8d36bb8, 0x143c2814, - 0xde79a7de, 0x5ee2bc5e, 0x0b1d160b, 0xdb76addb, - 0xe03bdbe0, 0x32566432, 0x3a4e743a, 0x0a1e140a, - 0x49db9249, 0x060a0c06, 0x246c4824, 0x5ce4b85c, - 0xc25d9fc2, 0xd36ebdd3, 0xacef43ac, 0x62a6c462, - 0x91a83991, 0x95a43195, 0xe437d3e4, 0x798bf279, - 0xe732d5e7, 0xc8438bc8, 0x37596e37, 0x6db7da6d, - 0x8d8c018d, 0xd564b1d5, 0x4ed29c4e, 0xa9e049a9, - 0x6cb4d86c, 0x56faac56, 0xf407f3f4, 0xea25cfea, - 0x65afca65, 0x7a8ef47a, 0xaee947ae, 0x08181008, - 0xbad56fba, 0x7888f078, 0x256f4a25, 0x2e725c2e, - 0x1c24381c, 0xa6f157a6, 0xb4c773b4, 0xc65197c6, - 0xe823cbe8, 0xdd7ca1dd, 0x749ce874, 0x1f213e1f, - 0x4bdd964b, 0xbddc61bd, 0x8b860d8b, 0x8a850f8a, - 0x7090e070, 0x3e427c3e, 0xb5c471b5, 0x66aacc66, - 0x48d89048, 0x03050603, 0xf601f7f6, 0x0e121c0e, - 0x61a3c261, 0x355f6a35, 0x57f9ae57, 0xb9d069b9, - 0x86911786, 0xc15899c1, 0x1d273a1d, 0x9eb9279e, - 0xe138d9e1, 0xf813ebf8, 0x98b32b98, 0x11332211, - 0x69bbd269, 0xd970a9d9, 0x8e89078e, 0x94a73394, - 0x9bb62d9b, 0x1e223c1e, 0x87921587, 0xe920c9e9, - 0xce4987ce, 0x55ffaa55, 0x28785028, 0xdf7aa5df, - 0x8c8f038c, 0xa1f859a1, 0x89800989, 0x0d171a0d, - 0xbfda65bf, 0xe631d7e6, 0x42c68442, 0x68b8d068, - 0x41c38241, 0x99b02999, 0x2d775a2d, 0x0f111e0f, - 0xb0cb7bb0, 0x54fca854, 0xbbd66dbb, 0x163a2c16 -]; - -var TE3 = [ - 0x6363a5c6, 0x7c7c84f8, 0x777799ee, 0x7b7b8df6, - 0xf2f20dff, 0x6b6bbdd6, 0x6f6fb1de, 0xc5c55491, - 0x30305060, 0x01010302, 0x6767a9ce, 0x2b2b7d56, - 0xfefe19e7, 0xd7d762b5, 0xababe64d, 0x76769aec, - 0xcaca458f, 0x82829d1f, 0xc9c94089, 0x7d7d87fa, - 0xfafa15ef, 0x5959ebb2, 0x4747c98e, 0xf0f00bfb, - 0xadadec41, 0xd4d467b3, 0xa2a2fd5f, 0xafafea45, - 0x9c9cbf23, 0xa4a4f753, 0x727296e4, 0xc0c05b9b, - 0xb7b7c275, 0xfdfd1ce1, 0x9393ae3d, 0x26266a4c, - 0x36365a6c, 0x3f3f417e, 0xf7f702f5, 0xcccc4f83, - 0x34345c68, 0xa5a5f451, 0xe5e534d1, 0xf1f108f9, - 0x717193e2, 0xd8d873ab, 0x31315362, 0x15153f2a, - 0x04040c08, 0xc7c75295, 0x23236546, 0xc3c35e9d, - 0x18182830, 0x9696a137, 0x05050f0a, 0x9a9ab52f, - 0x0707090e, 0x12123624, 0x80809b1b, 0xe2e23ddf, - 0xebeb26cd, 0x2727694e, 0xb2b2cd7f, 0x75759fea, - 0x09091b12, 0x83839e1d, 0x2c2c7458, 0x1a1a2e34, - 0x1b1b2d36, 0x6e6eb2dc, 0x5a5aeeb4, 0xa0a0fb5b, - 0x5252f6a4, 0x3b3b4d76, 0xd6d661b7, 0xb3b3ce7d, - 0x29297b52, 0xe3e33edd, 0x2f2f715e, 0x84849713, - 0x5353f5a6, 0xd1d168b9, 0x00000000, 0xeded2cc1, - 0x20206040, 0xfcfc1fe3, 0xb1b1c879, 0x5b5bedb6, - 0x6a6abed4, 0xcbcb468d, 0xbebed967, 0x39394b72, - 0x4a4ade94, 0x4c4cd498, 0x5858e8b0, 0xcfcf4a85, - 0xd0d06bbb, 0xefef2ac5, 0xaaaae54f, 0xfbfb16ed, - 0x4343c586, 0x4d4dd79a, 0x33335566, 0x85859411, - 0x4545cf8a, 0xf9f910e9, 0x02020604, 0x7f7f81fe, - 0x5050f0a0, 0x3c3c4478, 0x9f9fba25, 0xa8a8e34b, - 0x5151f3a2, 0xa3a3fe5d, 0x4040c080, 0x8f8f8a05, - 0x9292ad3f, 0x9d9dbc21, 0x38384870, 0xf5f504f1, - 0xbcbcdf63, 0xb6b6c177, 0xdada75af, 0x21216342, - 0x10103020, 0xffff1ae5, 0xf3f30efd, 0xd2d26dbf, - 0xcdcd4c81, 0x0c0c1418, 0x13133526, 0xecec2fc3, - 0x5f5fe1be, 0x9797a235, 0x4444cc88, 0x1717392e, - 0xc4c45793, 0xa7a7f255, 0x7e7e82fc, 0x3d3d477a, - 0x6464acc8, 0x5d5de7ba, 0x19192b32, 0x737395e6, - 0x6060a0c0, 0x81819819, 0x4f4fd19e, 0xdcdc7fa3, - 0x22226644, 0x2a2a7e54, 0x9090ab3b, 0x8888830b, - 0x4646ca8c, 0xeeee29c7, 0xb8b8d36b, 0x14143c28, - 0xdede79a7, 0x5e5ee2bc, 0x0b0b1d16, 0xdbdb76ad, - 0xe0e03bdb, 0x32325664, 0x3a3a4e74, 0x0a0a1e14, - 0x4949db92, 0x06060a0c, 0x24246c48, 0x5c5ce4b8, - 0xc2c25d9f, 0xd3d36ebd, 0xacacef43, 0x6262a6c4, - 0x9191a839, 0x9595a431, 0xe4e437d3, 0x79798bf2, - 0xe7e732d5, 0xc8c8438b, 0x3737596e, 0x6d6db7da, - 0x8d8d8c01, 0xd5d564b1, 0x4e4ed29c, 0xa9a9e049, - 0x6c6cb4d8, 0x5656faac, 0xf4f407f3, 0xeaea25cf, - 0x6565afca, 0x7a7a8ef4, 0xaeaee947, 0x08081810, - 0xbabad56f, 0x787888f0, 0x25256f4a, 0x2e2e725c, - 0x1c1c2438, 0xa6a6f157, 0xb4b4c773, 0xc6c65197, - 0xe8e823cb, 0xdddd7ca1, 0x74749ce8, 0x1f1f213e, - 0x4b4bdd96, 0xbdbddc61, 0x8b8b860d, 0x8a8a850f, - 0x707090e0, 0x3e3e427c, 0xb5b5c471, 0x6666aacc, - 0x4848d890, 0x03030506, 0xf6f601f7, 0x0e0e121c, - 0x6161a3c2, 0x35355f6a, 0x5757f9ae, 0xb9b9d069, - 0x86869117, 0xc1c15899, 0x1d1d273a, 0x9e9eb927, - 0xe1e138d9, 0xf8f813eb, 0x9898b32b, 0x11113322, - 0x6969bbd2, 0xd9d970a9, 0x8e8e8907, 0x9494a733, - 0x9b9bb62d, 0x1e1e223c, 0x87879215, 0xe9e920c9, - 0xcece4987, 0x5555ffaa, 0x28287850, 0xdfdf7aa5, - 0x8c8c8f03, 0xa1a1f859, 0x89898009, 0x0d0d171a, - 0xbfbfda65, 0xe6e631d7, 0x4242c684, 0x6868b8d0, - 0x4141c382, 0x9999b029, 0x2d2d775a, 0x0f0f111e, - 0xb0b0cb7b, 0x5454fca8, 0xbbbbd66d, 0x16163a2c -]; - -var TD0 = [ - 0x51f4a750, 0x7e416553, 0x1a17a4c3, 0x3a275e96, - 0x3bab6bcb, 0x1f9d45f1, 0xacfa58ab, 0x4be30393, - 0x2030fa55, 0xad766df6, 0x88cc7691, 0xf5024c25, - 0x4fe5d7fc, 0xc52acbd7, 0x26354480, 0xb562a38f, - 0xdeb15a49, 0x25ba1b67, 0x45ea0e98, 0x5dfec0e1, - 0xc32f7502, 0x814cf012, 0x8d4697a3, 0x6bd3f9c6, - 0x038f5fe7, 0x15929c95, 0xbf6d7aeb, 0x955259da, - 0xd4be832d, 0x587421d3, 0x49e06929, 0x8ec9c844, - 0x75c2896a, 0xf48e7978, 0x99583e6b, 0x27b971dd, - 0xbee14fb6, 0xf088ad17, 0xc920ac66, 0x7dce3ab4, - 0x63df4a18, 0xe51a3182, 0x97513360, 0x62537f45, - 0xb16477e0, 0xbb6bae84, 0xfe81a01c, 0xf9082b94, - 0x70486858, 0x8f45fd19, 0x94de6c87, 0x527bf8b7, - 0xab73d323, 0x724b02e2, 0xe31f8f57, 0x6655ab2a, - 0xb2eb2807, 0x2fb5c203, 0x86c57b9a, 0xd33708a5, - 0x302887f2, 0x23bfa5b2, 0x02036aba, 0xed16825c, - 0x8acf1c2b, 0xa779b492, 0xf307f2f0, 0x4e69e2a1, - 0x65daf4cd, 0x0605bed5, 0xd134621f, 0xc4a6fe8a, - 0x342e539d, 0xa2f355a0, 0x058ae132, 0xa4f6eb75, - 0x0b83ec39, 0x4060efaa, 0x5e719f06, 0xbd6e1051, - 0x3e218af9, 0x96dd063d, 0xdd3e05ae, 0x4de6bd46, - 0x91548db5, 0x71c45d05, 0x0406d46f, 0x605015ff, - 0x1998fb24, 0xd6bde997, 0x894043cc, 0x67d99e77, - 0xb0e842bd, 0x07898b88, 0xe7195b38, 0x79c8eedb, - 0xa17c0a47, 0x7c420fe9, 0xf8841ec9, 0x00000000, - 0x09808683, 0x322bed48, 0x1e1170ac, 0x6c5a724e, - 0xfd0efffb, 0x0f853856, 0x3daed51e, 0x362d3927, - 0x0a0fd964, 0x685ca621, 0x9b5b54d1, 0x24362e3a, - 0x0c0a67b1, 0x9357e70f, 0xb4ee96d2, 0x1b9b919e, - 0x80c0c54f, 0x61dc20a2, 0x5a774b69, 0x1c121a16, - 0xe293ba0a, 0xc0a02ae5, 0x3c22e043, 0x121b171d, - 0x0e090d0b, 0xf28bc7ad, 0x2db6a8b9, 0x141ea9c8, - 0x57f11985, 0xaf75074c, 0xee99ddbb, 0xa37f60fd, - 0xf701269f, 0x5c72f5bc, 0x44663bc5, 0x5bfb7e34, - 0x8b432976, 0xcb23c6dc, 0xb6edfc68, 0xb8e4f163, - 0xd731dcca, 0x42638510, 0x13972240, 0x84c61120, - 0x854a247d, 0xd2bb3df8, 0xaef93211, 0xc729a16d, - 0x1d9e2f4b, 0xdcb230f3, 0x0d8652ec, 0x77c1e3d0, - 0x2bb3166c, 0xa970b999, 0x119448fa, 0x47e96422, - 0xa8fc8cc4, 0xa0f03f1a, 0x567d2cd8, 0x223390ef, - 0x87494ec7, 0xd938d1c1, 0x8ccaa2fe, 0x98d40b36, - 0xa6f581cf, 0xa57ade28, 0xdab78e26, 0x3fadbfa4, - 0x2c3a9de4, 0x5078920d, 0x6a5fcc9b, 0x547e4662, - 0xf68d13c2, 0x90d8b8e8, 0x2e39f75e, 0x82c3aff5, - 0x9f5d80be, 0x69d0937c, 0x6fd52da9, 0xcf2512b3, - 0xc8ac993b, 0x10187da7, 0xe89c636e, 0xdb3bbb7b, - 0xcd267809, 0x6e5918f4, 0xec9ab701, 0x834f9aa8, - 0xe6956e65, 0xaaffe67e, 0x21bccf08, 0xef15e8e6, - 0xbae79bd9, 0x4a6f36ce, 0xea9f09d4, 0x29b07cd6, - 0x31a4b2af, 0x2a3f2331, 0xc6a59430, 0x35a266c0, - 0x744ebc37, 0xfc82caa6, 0xe090d0b0, 0x33a7d815, - 0xf104984a, 0x41ecdaf7, 0x7fcd500e, 0x1791f62f, - 0x764dd68d, 0x43efb04d, 0xccaa4d54, 0xe49604df, - 0x9ed1b5e3, 0x4c6a881b, 0xc12c1fb8, 0x4665517f, - 0x9d5eea04, 0x018c355d, 0xfa877473, 0xfb0b412e, - 0xb3671d5a, 0x92dbd252, 0xe9105633, 0x6dd64713, - 0x9ad7618c, 0x37a10c7a, 0x59f8148e, 0xeb133c89, - 0xcea927ee, 0xb761c935, 0xe11ce5ed, 0x7a47b13c, - 0x9cd2df59, 0x55f2733f, 0x1814ce79, 0x73c737bf, - 0x53f7cdea, 0x5ffdaa5b, 0xdf3d6f14, 0x7844db86, - 0xcaaff381, 0xb968c43e, 0x3824342c, 0xc2a3405f, - 0x161dc372, 0xbce2250c, 0x283c498b, 0xff0d9541, - 0x39a80171, 0x080cb3de, 0xd8b4e49c, 0x6456c190, - 0x7bcb8461, 0xd532b670, 0x486c5c74, 0xd0b85742 -]; - -var TD1 = [ - 0x5051f4a7, 0x537e4165, 0xc31a17a4, 0x963a275e, - 0xcb3bab6b, 0xf11f9d45, 0xabacfa58, 0x934be303, - 0x552030fa, 0xf6ad766d, 0x9188cc76, 0x25f5024c, - 0xfc4fe5d7, 0xd7c52acb, 0x80263544, 0x8fb562a3, - 0x49deb15a, 0x6725ba1b, 0x9845ea0e, 0xe15dfec0, - 0x02c32f75, 0x12814cf0, 0xa38d4697, 0xc66bd3f9, - 0xe7038f5f, 0x9515929c, 0xebbf6d7a, 0xda955259, - 0x2dd4be83, 0xd3587421, 0x2949e069, 0x448ec9c8, - 0x6a75c289, 0x78f48e79, 0x6b99583e, 0xdd27b971, - 0xb6bee14f, 0x17f088ad, 0x66c920ac, 0xb47dce3a, - 0x1863df4a, 0x82e51a31, 0x60975133, 0x4562537f, - 0xe0b16477, 0x84bb6bae, 0x1cfe81a0, 0x94f9082b, - 0x58704868, 0x198f45fd, 0x8794de6c, 0xb7527bf8, - 0x23ab73d3, 0xe2724b02, 0x57e31f8f, 0x2a6655ab, - 0x07b2eb28, 0x032fb5c2, 0x9a86c57b, 0xa5d33708, - 0xf2302887, 0xb223bfa5, 0xba02036a, 0x5ced1682, - 0x2b8acf1c, 0x92a779b4, 0xf0f307f2, 0xa14e69e2, - 0xcd65daf4, 0xd50605be, 0x1fd13462, 0x8ac4a6fe, - 0x9d342e53, 0xa0a2f355, 0x32058ae1, 0x75a4f6eb, - 0x390b83ec, 0xaa4060ef, 0x065e719f, 0x51bd6e10, - 0xf93e218a, 0x3d96dd06, 0xaedd3e05, 0x464de6bd, - 0xb591548d, 0x0571c45d, 0x6f0406d4, 0xff605015, - 0x241998fb, 0x97d6bde9, 0xcc894043, 0x7767d99e, - 0xbdb0e842, 0x8807898b, 0x38e7195b, 0xdb79c8ee, - 0x47a17c0a, 0xe97c420f, 0xc9f8841e, 0x00000000, - 0x83098086, 0x48322bed, 0xac1e1170, 0x4e6c5a72, - 0xfbfd0eff, 0x560f8538, 0x1e3daed5, 0x27362d39, - 0x640a0fd9, 0x21685ca6, 0xd19b5b54, 0x3a24362e, - 0xb10c0a67, 0x0f9357e7, 0xd2b4ee96, 0x9e1b9b91, - 0x4f80c0c5, 0xa261dc20, 0x695a774b, 0x161c121a, - 0x0ae293ba, 0xe5c0a02a, 0x433c22e0, 0x1d121b17, - 0x0b0e090d, 0xadf28bc7, 0xb92db6a8, 0xc8141ea9, - 0x8557f119, 0x4caf7507, 0xbbee99dd, 0xfda37f60, - 0x9ff70126, 0xbc5c72f5, 0xc544663b, 0x345bfb7e, - 0x768b4329, 0xdccb23c6, 0x68b6edfc, 0x63b8e4f1, - 0xcad731dc, 0x10426385, 0x40139722, 0x2084c611, - 0x7d854a24, 0xf8d2bb3d, 0x11aef932, 0x6dc729a1, - 0x4b1d9e2f, 0xf3dcb230, 0xec0d8652, 0xd077c1e3, - 0x6c2bb316, 0x99a970b9, 0xfa119448, 0x2247e964, - 0xc4a8fc8c, 0x1aa0f03f, 0xd8567d2c, 0xef223390, - 0xc787494e, 0xc1d938d1, 0xfe8ccaa2, 0x3698d40b, - 0xcfa6f581, 0x28a57ade, 0x26dab78e, 0xa43fadbf, - 0xe42c3a9d, 0x0d507892, 0x9b6a5fcc, 0x62547e46, - 0xc2f68d13, 0xe890d8b8, 0x5e2e39f7, 0xf582c3af, - 0xbe9f5d80, 0x7c69d093, 0xa96fd52d, 0xb3cf2512, - 0x3bc8ac99, 0xa710187d, 0x6ee89c63, 0x7bdb3bbb, - 0x09cd2678, 0xf46e5918, 0x01ec9ab7, 0xa8834f9a, - 0x65e6956e, 0x7eaaffe6, 0x0821bccf, 0xe6ef15e8, - 0xd9bae79b, 0xce4a6f36, 0xd4ea9f09, 0xd629b07c, - 0xaf31a4b2, 0x312a3f23, 0x30c6a594, 0xc035a266, - 0x37744ebc, 0xa6fc82ca, 0xb0e090d0, 0x1533a7d8, - 0x4af10498, 0xf741ecda, 0x0e7fcd50, 0x2f1791f6, - 0x8d764dd6, 0x4d43efb0, 0x54ccaa4d, 0xdfe49604, - 0xe39ed1b5, 0x1b4c6a88, 0xb8c12c1f, 0x7f466551, - 0x049d5eea, 0x5d018c35, 0x73fa8774, 0x2efb0b41, - 0x5ab3671d, 0x5292dbd2, 0x33e91056, 0x136dd647, - 0x8c9ad761, 0x7a37a10c, 0x8e59f814, 0x89eb133c, - 0xeecea927, 0x35b761c9, 0xede11ce5, 0x3c7a47b1, - 0x599cd2df, 0x3f55f273, 0x791814ce, 0xbf73c737, - 0xea53f7cd, 0x5b5ffdaa, 0x14df3d6f, 0x867844db, - 0x81caaff3, 0x3eb968c4, 0x2c382434, 0x5fc2a340, - 0x72161dc3, 0x0cbce225, 0x8b283c49, 0x41ff0d95, - 0x7139a801, 0xde080cb3, 0x9cd8b4e4, 0x906456c1, - 0x617bcb84, 0x70d532b6, 0x74486c5c, 0x42d0b857 -]; - -var TD2 = [ - 0xa75051f4, 0x65537e41, 0xa4c31a17, 0x5e963a27, - 0x6bcb3bab, 0x45f11f9d, 0x58abacfa, 0x03934be3, - 0xfa552030, 0x6df6ad76, 0x769188cc, 0x4c25f502, - 0xd7fc4fe5, 0xcbd7c52a, 0x44802635, 0xa38fb562, - 0x5a49deb1, 0x1b6725ba, 0x0e9845ea, 0xc0e15dfe, - 0x7502c32f, 0xf012814c, 0x97a38d46, 0xf9c66bd3, - 0x5fe7038f, 0x9c951592, 0x7aebbf6d, 0x59da9552, - 0x832dd4be, 0x21d35874, 0x692949e0, 0xc8448ec9, - 0x896a75c2, 0x7978f48e, 0x3e6b9958, 0x71dd27b9, - 0x4fb6bee1, 0xad17f088, 0xac66c920, 0x3ab47dce, - 0x4a1863df, 0x3182e51a, 0x33609751, 0x7f456253, - 0x77e0b164, 0xae84bb6b, 0xa01cfe81, 0x2b94f908, - 0x68587048, 0xfd198f45, 0x6c8794de, 0xf8b7527b, - 0xd323ab73, 0x02e2724b, 0x8f57e31f, 0xab2a6655, - 0x2807b2eb, 0xc2032fb5, 0x7b9a86c5, 0x08a5d337, - 0x87f23028, 0xa5b223bf, 0x6aba0203, 0x825ced16, - 0x1c2b8acf, 0xb492a779, 0xf2f0f307, 0xe2a14e69, - 0xf4cd65da, 0xbed50605, 0x621fd134, 0xfe8ac4a6, - 0x539d342e, 0x55a0a2f3, 0xe132058a, 0xeb75a4f6, - 0xec390b83, 0xefaa4060, 0x9f065e71, 0x1051bd6e, - 0x8af93e21, 0x063d96dd, 0x05aedd3e, 0xbd464de6, - 0x8db59154, 0x5d0571c4, 0xd46f0406, 0x15ff6050, - 0xfb241998, 0xe997d6bd, 0x43cc8940, 0x9e7767d9, - 0x42bdb0e8, 0x8b880789, 0x5b38e719, 0xeedb79c8, - 0x0a47a17c, 0x0fe97c42, 0x1ec9f884, 0x00000000, - 0x86830980, 0xed48322b, 0x70ac1e11, 0x724e6c5a, - 0xfffbfd0e, 0x38560f85, 0xd51e3dae, 0x3927362d, - 0xd9640a0f, 0xa621685c, 0x54d19b5b, 0x2e3a2436, - 0x67b10c0a, 0xe70f9357, 0x96d2b4ee, 0x919e1b9b, - 0xc54f80c0, 0x20a261dc, 0x4b695a77, 0x1a161c12, - 0xba0ae293, 0x2ae5c0a0, 0xe0433c22, 0x171d121b, - 0x0d0b0e09, 0xc7adf28b, 0xa8b92db6, 0xa9c8141e, - 0x198557f1, 0x074caf75, 0xddbbee99, 0x60fda37f, - 0x269ff701, 0xf5bc5c72, 0x3bc54466, 0x7e345bfb, - 0x29768b43, 0xc6dccb23, 0xfc68b6ed, 0xf163b8e4, - 0xdccad731, 0x85104263, 0x22401397, 0x112084c6, - 0x247d854a, 0x3df8d2bb, 0x3211aef9, 0xa16dc729, - 0x2f4b1d9e, 0x30f3dcb2, 0x52ec0d86, 0xe3d077c1, - 0x166c2bb3, 0xb999a970, 0x48fa1194, 0x642247e9, - 0x8cc4a8fc, 0x3f1aa0f0, 0x2cd8567d, 0x90ef2233, - 0x4ec78749, 0xd1c1d938, 0xa2fe8cca, 0x0b3698d4, - 0x81cfa6f5, 0xde28a57a, 0x8e26dab7, 0xbfa43fad, - 0x9de42c3a, 0x920d5078, 0xcc9b6a5f, 0x4662547e, - 0x13c2f68d, 0xb8e890d8, 0xf75e2e39, 0xaff582c3, - 0x80be9f5d, 0x937c69d0, 0x2da96fd5, 0x12b3cf25, - 0x993bc8ac, 0x7da71018, 0x636ee89c, 0xbb7bdb3b, - 0x7809cd26, 0x18f46e59, 0xb701ec9a, 0x9aa8834f, - 0x6e65e695, 0xe67eaaff, 0xcf0821bc, 0xe8e6ef15, - 0x9bd9bae7, 0x36ce4a6f, 0x09d4ea9f, 0x7cd629b0, - 0xb2af31a4, 0x23312a3f, 0x9430c6a5, 0x66c035a2, - 0xbc37744e, 0xcaa6fc82, 0xd0b0e090, 0xd81533a7, - 0x984af104, 0xdaf741ec, 0x500e7fcd, 0xf62f1791, - 0xd68d764d, 0xb04d43ef, 0x4d54ccaa, 0x04dfe496, - 0xb5e39ed1, 0x881b4c6a, 0x1fb8c12c, 0x517f4665, - 0xea049d5e, 0x355d018c, 0x7473fa87, 0x412efb0b, - 0x1d5ab367, 0xd25292db, 0x5633e910, 0x47136dd6, - 0x618c9ad7, 0x0c7a37a1, 0x148e59f8, 0x3c89eb13, - 0x27eecea9, 0xc935b761, 0xe5ede11c, 0xb13c7a47, - 0xdf599cd2, 0x733f55f2, 0xce791814, 0x37bf73c7, - 0xcdea53f7, 0xaa5b5ffd, 0x6f14df3d, 0xdb867844, - 0xf381caaf, 0xc43eb968, 0x342c3824, 0x405fc2a3, - 0xc372161d, 0x250cbce2, 0x498b283c, 0x9541ff0d, - 0x017139a8, 0xb3de080c, 0xe49cd8b4, 0xc1906456, - 0x84617bcb, 0xb670d532, 0x5c74486c, 0x5742d0b8 -]; - -var TD3 = [ - 0xf4a75051, 0x4165537e, 0x17a4c31a, 0x275e963a, - 0xab6bcb3b, 0x9d45f11f, 0xfa58abac, 0xe303934b, - 0x30fa5520, 0x766df6ad, 0xcc769188, 0x024c25f5, - 0xe5d7fc4f, 0x2acbd7c5, 0x35448026, 0x62a38fb5, - 0xb15a49de, 0xba1b6725, 0xea0e9845, 0xfec0e15d, - 0x2f7502c3, 0x4cf01281, 0x4697a38d, 0xd3f9c66b, - 0x8f5fe703, 0x929c9515, 0x6d7aebbf, 0x5259da95, - 0xbe832dd4, 0x7421d358, 0xe0692949, 0xc9c8448e, - 0xc2896a75, 0x8e7978f4, 0x583e6b99, 0xb971dd27, - 0xe14fb6be, 0x88ad17f0, 0x20ac66c9, 0xce3ab47d, - 0xdf4a1863, 0x1a3182e5, 0x51336097, 0x537f4562, - 0x6477e0b1, 0x6bae84bb, 0x81a01cfe, 0x082b94f9, - 0x48685870, 0x45fd198f, 0xde6c8794, 0x7bf8b752, - 0x73d323ab, 0x4b02e272, 0x1f8f57e3, 0x55ab2a66, - 0xeb2807b2, 0xb5c2032f, 0xc57b9a86, 0x3708a5d3, - 0x2887f230, 0xbfa5b223, 0x036aba02, 0x16825ced, - 0xcf1c2b8a, 0x79b492a7, 0x07f2f0f3, 0x69e2a14e, - 0xdaf4cd65, 0x05bed506, 0x34621fd1, 0xa6fe8ac4, - 0x2e539d34, 0xf355a0a2, 0x8ae13205, 0xf6eb75a4, - 0x83ec390b, 0x60efaa40, 0x719f065e, 0x6e1051bd, - 0x218af93e, 0xdd063d96, 0x3e05aedd, 0xe6bd464d, - 0x548db591, 0xc45d0571, 0x06d46f04, 0x5015ff60, - 0x98fb2419, 0xbde997d6, 0x4043cc89, 0xd99e7767, - 0xe842bdb0, 0x898b8807, 0x195b38e7, 0xc8eedb79, - 0x7c0a47a1, 0x420fe97c, 0x841ec9f8, 0x00000000, - 0x80868309, 0x2bed4832, 0x1170ac1e, 0x5a724e6c, - 0x0efffbfd, 0x8538560f, 0xaed51e3d, 0x2d392736, - 0x0fd9640a, 0x5ca62168, 0x5b54d19b, 0x362e3a24, - 0x0a67b10c, 0x57e70f93, 0xee96d2b4, 0x9b919e1b, - 0xc0c54f80, 0xdc20a261, 0x774b695a, 0x121a161c, - 0x93ba0ae2, 0xa02ae5c0, 0x22e0433c, 0x1b171d12, - 0x090d0b0e, 0x8bc7adf2, 0xb6a8b92d, 0x1ea9c814, - 0xf1198557, 0x75074caf, 0x99ddbbee, 0x7f60fda3, - 0x01269ff7, 0x72f5bc5c, 0x663bc544, 0xfb7e345b, - 0x4329768b, 0x23c6dccb, 0xedfc68b6, 0xe4f163b8, - 0x31dccad7, 0x63851042, 0x97224013, 0xc6112084, - 0x4a247d85, 0xbb3df8d2, 0xf93211ae, 0x29a16dc7, - 0x9e2f4b1d, 0xb230f3dc, 0x8652ec0d, 0xc1e3d077, - 0xb3166c2b, 0x70b999a9, 0x9448fa11, 0xe9642247, - 0xfc8cc4a8, 0xf03f1aa0, 0x7d2cd856, 0x3390ef22, - 0x494ec787, 0x38d1c1d9, 0xcaa2fe8c, 0xd40b3698, - 0xf581cfa6, 0x7ade28a5, 0xb78e26da, 0xadbfa43f, - 0x3a9de42c, 0x78920d50, 0x5fcc9b6a, 0x7e466254, - 0x8d13c2f6, 0xd8b8e890, 0x39f75e2e, 0xc3aff582, - 0x5d80be9f, 0xd0937c69, 0xd52da96f, 0x2512b3cf, - 0xac993bc8, 0x187da710, 0x9c636ee8, 0x3bbb7bdb, - 0x267809cd, 0x5918f46e, 0x9ab701ec, 0x4f9aa883, - 0x956e65e6, 0xffe67eaa, 0xbccf0821, 0x15e8e6ef, - 0xe79bd9ba, 0x6f36ce4a, 0x9f09d4ea, 0xb07cd629, - 0xa4b2af31, 0x3f23312a, 0xa59430c6, 0xa266c035, - 0x4ebc3774, 0x82caa6fc, 0x90d0b0e0, 0xa7d81533, - 0x04984af1, 0xecdaf741, 0xcd500e7f, 0x91f62f17, - 0x4dd68d76, 0xefb04d43, 0xaa4d54cc, 0x9604dfe4, - 0xd1b5e39e, 0x6a881b4c, 0x2c1fb8c1, 0x65517f46, - 0x5eea049d, 0x8c355d01, 0x877473fa, 0x0b412efb, - 0x671d5ab3, 0xdbd25292, 0x105633e9, 0xd647136d, - 0xd7618c9a, 0xa10c7a37, 0xf8148e59, 0x133c89eb, - 0xa927eece, 0x61c935b7, 0x1ce5ede1, 0x47b13c7a, - 0xd2df599c, 0xf2733f55, 0x14ce7918, 0xc737bf73, - 0xf7cdea53, 0xfdaa5b5f, 0x3d6f14df, 0x44db8678, - 0xaff381ca, 0x68c43eb9, 0x24342c38, 0xa3405fc2, - 0x1dc37216, 0xe2250cbc, 0x3c498b28, 0x0d9541ff, - 0xa8017139, 0x0cb3de08, 0xb4e49cd8, 0x56c19064, - 0xcb84617b, 0x32b670d5, 0x6c5c7448, 0xb85742d0 -]; - -var TD4 = [ - 0x52, 0x09, 0x6a, 0xd5, 0x30, 0x36, 0xa5, 0x38, - 0xbf, 0x40, 0xa3, 0x9e, 0x81, 0xf3, 0xd7, 0xfb, - 0x7c, 0xe3, 0x39, 0x82, 0x9b, 0x2f, 0xff, 0x87, - 0x34, 0x8e, 0x43, 0x44, 0xc4, 0xde, 0xe9, 0xcb, - 0x54, 0x7b, 0x94, 0x32, 0xa6, 0xc2, 0x23, 0x3d, - 0xee, 0x4c, 0x95, 0x0b, 0x42, 0xfa, 0xc3, 0x4e, - 0x08, 0x2e, 0xa1, 0x66, 0x28, 0xd9, 0x24, 0xb2, - 0x76, 0x5b, 0xa2, 0x49, 0x6d, 0x8b, 0xd1, 0x25, - 0x72, 0xf8, 0xf6, 0x64, 0x86, 0x68, 0x98, 0x16, - 0xd4, 0xa4, 0x5c, 0xcc, 0x5d, 0x65, 0xb6, 0x92, - 0x6c, 0x70, 0x48, 0x50, 0xfd, 0xed, 0xb9, 0xda, - 0x5e, 0x15, 0x46, 0x57, 0xa7, 0x8d, 0x9d, 0x84, - 0x90, 0xd8, 0xab, 0x00, 0x8c, 0xbc, 0xd3, 0x0a, - 0xf7, 0xe4, 0x58, 0x05, 0xb8, 0xb3, 0x45, 0x06, - 0xd0, 0x2c, 0x1e, 0x8f, 0xca, 0x3f, 0x0f, 0x02, - 0xc1, 0xaf, 0xbd, 0x03, 0x01, 0x13, 0x8a, 0x6b, - 0x3a, 0x91, 0x11, 0x41, 0x4f, 0x67, 0xdc, 0xea, - 0x97, 0xf2, 0xcf, 0xce, 0xf0, 0xb4, 0xe6, 0x73, - 0x96, 0xac, 0x74, 0x22, 0xe7, 0xad, 0x35, 0x85, - 0xe2, 0xf9, 0x37, 0xe8, 0x1c, 0x75, 0xdf, 0x6e, - 0x47, 0xf1, 0x1a, 0x71, 0x1d, 0x29, 0xc5, 0x89, - 0x6f, 0xb7, 0x62, 0x0e, 0xaa, 0x18, 0xbe, 0x1b, - 0xfc, 0x56, 0x3e, 0x4b, 0xc6, 0xd2, 0x79, 0x20, - 0x9a, 0xdb, 0xc0, 0xfe, 0x78, 0xcd, 0x5a, 0xf4, - 0x1f, 0xdd, 0xa8, 0x33, 0x88, 0x07, 0xc7, 0x31, - 0xb1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xec, 0x5f, - 0x60, 0x51, 0x7f, 0xa9, 0x19, 0xb5, 0x4a, 0x0d, - 0x2d, 0xe5, 0x7a, 0x9f, 0x93, 0xc9, 0x9c, 0xef, - 0xa0, 0xe0, 0x3b, 0x4d, 0xae, 0x2a, 0xf5, 0xb0, - 0xc8, 0xeb, 0xbb, 0x3c, 0x83, 0x53, 0x99, 0x61, - 0x17, 0x2b, 0x04, 0x7e, 0xba, 0x77, 0xd6, 0x26, - 0xe1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0c, 0x7d -]; - -var RCON = [ - 0x01000000, 0x02000000, 0x04000000, 0x08000000, - 0x10000000, 0x20000000, 0x40000000, 0x80000000, - 0x1B000000, 0x36000000 -]; diff --git a/lib/crypto/backend-browser.js b/lib/crypto/backend-browser.js deleted file mode 100644 index c0028761..00000000 --- a/lib/crypto/backend-browser.js +++ /dev/null @@ -1,177 +0,0 @@ -/*! - * backend-browser.js - browser crypto backend for bcoin - * Copyright (c) 2014-2017, Christopher Jeffrey (MIT License). - * https://github.com/bcoin-org/bcoin - */ - -'use strict'; - -var assert = require('assert'); -var hashjs = require('hash.js'); -var aes = require('./aes'); -var sha256 = require('./sha256'); -var crypto = global.crypto || global.msCrypto || {}; -var subtle = crypto.subtle && crypto.subtle.importKey ? crypto.subtle : {}; -var backend = exports; - -/* - * Hashing - */ - -backend.hash = function hash(alg, data) { - var hash; - - if (alg === 'sha256') - return sha256.digest(data); - - hash = hashjs[alg]; - - assert(hash != null, 'Unknown algorithm.'); - - return Buffer.from(hash().update(data).digest()); -}; - -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 sha256.digest(data); -}; - -backend.hash160 = function hash160(data) { - return backend.hash('ripemd160', sha256.digest(data)); -}; - -backend.hash256 = function hash256(data) { - return sha256.hash256(data); -}; - -backend.hmac = function _hmac(alg, data, key) { - var hash = hashjs[alg]; - var hmac; - - assert(hash != null, 'Unknown algorithm.'); - - hmac = hashjs.hmac(hash, key); - - return Buffer.from(hmac.update(data).digest()); -}; - -/* - * Key Derivation - */ - -backend.pbkdf2 = function pbkdf2(key, salt, iter, len, alg) { - var size = backend.hash(alg, Buffer.alloc(0)).length; - var blocks = Math.ceil(len / size); - var out = Buffer.allocUnsafe(len); - var buf = Buffer.allocUnsafe(salt.length + 4); - var block = Buffer.allocUnsafe(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; - - options = { - name: 'PBKDF2', - salt: salt, - iterations: iter, - hash: name - }; - - promise = subtle.importKey('raw', key, algo, false, use); - - return promise.then(function(key) { - return subtle.deriveBits(options, key, length); - }).then(function(result) { - return Buffer.from(result); - }); -}; - -if (!subtle.deriveBits) - backend.pbkdf2Async = backend.pbkdf2; - -/* - * Ciphers - */ - -backend.encipher = function encipher(data, key, iv) { - return aes.cbc.encrypt(data, key, iv); -}; - -backend.decipher = function decipher(data, key, iv) { - try { - return aes.cbc.decrypt(data, key, iv); - } catch (e) { - throw new Error('Bad key for decryption.'); - } -}; - -/* - * Misc - */ - -backend.randomBytes = function randomBytes(n) { - var data = new Uint8Array(n); - crypto.getRandomValues(data); - return Buffer.from(data.buffer); -}; - -if (!crypto.getRandomValues) { - // Out of luck here. Use bad randomness for now. - backend.randomBytes = function randomBytes(n) { - var data = Buffer.allocUnsafe(n); - var i; - - for (i = 0; i < data.length; i++) - data[i] = Math.floor(Math.random() * 256); - - return data; - }; -} - -backend.getHash = function getHash(name) { - switch (name) { - case 'sha1': - return 'SHA-1'; - case 'sha256': - return 'SHA-256'; - case 'sha384': - return 'SHA-384'; - case 'sha512': - return 'SHA-512'; - default: - throw new Error('Algorithm not supported: ' + name); - } -}; - -backend.crypto = crypto; -backend.subtle = subtle; diff --git a/lib/crypto/backend.js b/lib/crypto/backend.js deleted file mode 100644 index f06e6786..00000000 --- a/lib/crypto/backend.js +++ /dev/null @@ -1,102 +0,0 @@ -/*! - * backend.js - crypto backend for bcoin - * Copyright (c) 2014-2017, Christopher Jeffrey (MIT License). - * https://github.com/bcoin-org/bcoin - */ - -'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.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; -} - -/* - * Key Derivation - */ - -backend.pbkdf2 = function pbkdf2(key, salt, iter, len, alg) { - return crypto.pbkdf2Sync(key, salt, iter, len, alg); -}; - -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)); - }); -}; - -/* - * Ciphers - */ - -backend.encipher = function encipher(data, key, iv) { - var cipher = crypto.createCipheriv('aes-256-cbc', key, iv); - return util.concat(cipher.update(data), cipher.final()); -}; - -backend.decipher = function decipher(data, key, iv) { - var decipher = crypto.createDecipheriv('aes-256-cbc', key, iv); - try { - return util.concat(decipher.update(data), decipher.final()); - } catch (e) { - throw new Error('Bad key for decryption.'); - } -}; - -if (native) { - backend.encipher = native.encipher; - backend.decipher = native.decipher; -} - -/* - * Misc - */ - -backend.randomBytes = crypto.randomBytes; diff --git a/lib/crypto/bn.js b/lib/crypto/bn.js index b978d68a..1cfaa76c 100644 --- a/lib/crypto/bn.js +++ b/lib/crypto/bn.js @@ -6,4 +6,14 @@ 'use strict'; +/** + * @module crypto.BN + */ + +/** + * bn.js + * @constructor + * @see https://github.com/indutny/bn.js + */ + module.exports = require('bn.js'); diff --git a/lib/crypto/ccmp.js b/lib/crypto/ccmp.js new file mode 100644 index 00000000..1235f540 --- /dev/null +++ b/lib/crypto/ccmp.js @@ -0,0 +1,39 @@ +/*! + * ccmp.js - constant-time compare for bcoin + * Copyright (c) 2016-2017, Christopher Jeffrey (MIT License). + * https://github.com/bcoin-org/bcoin + */ + +'use strict'; + +/** + * memcmp in constant time (can only return true or false). + * This protects us against timing attacks when + * comparing an input against a secret string. + * @alias module:crypto.ccmp + * @see https://cryptocoding.net/index.php/Coding_rules + * @see `$ man 3 memcmp` (NetBSD's consttime_memequal) + * @param {Buffer} a + * @param {Buffer} b + * @returns {Boolean} + */ + +module.exports = function ccmp(a, b) { + var i, res; + + if (!Buffer.isBuffer(a)) + return false; + + if (!Buffer.isBuffer(b)) + return false; + + if (b.length === 0) + return a.length === 0; + + res = a.length ^ b.length; + + for (i = 0; i < a.length; i++) + res |= a[i] ^ b[i % b.length]; + + return res === 0; +}; diff --git a/lib/crypto/chacha20.js b/lib/crypto/chacha20.js new file mode 100644 index 00000000..d30e7158 --- /dev/null +++ b/lib/crypto/chacha20.js @@ -0,0 +1,209 @@ +/*! + * chacha20.js - chacha20 for bcoin + * Copyright (c) 2016-2017, Christopher Jeffrey (MIT License). + * https://github.com/bcoin-org/bcoin + */ + +'use strict'; + +var assert = require('assert'); +var native = require('../utils/native').binding; + +var BIG_ENDIAN = new Int8Array(new Int16Array([1]).buffer)[0] === 0; + +/** + * ChaCha20 (used for bip151) + * @alias module:crypto.ChaCha20 + * @constructor + * @see https://tools.ietf.org/html/rfc7539#section-2 + */ + +function ChaCha20() { + if (!(this instanceof ChaCha20)) + return new ChaCha20(); + + this.state = new Uint32Array(16); + this.stream = new Uint32Array(16); + this.bytes = new Uint8Array(this.stream.buffer); + + if (BIG_ENDIAN) + this.bytes = Buffer.allocUnsafe(64); + + this.pos = 0; + this.ivSize = 0; +} + +/** + * Initialize chacha20 with a key, iv, and counter. + * @param {Buffer} key + * @param {Buffer} iv + * @param {Number} counter + */ + +ChaCha20.prototype.init = function init(key, iv, counter) { + if (key) + this.initKey(key); + + if (iv) + this.initIV(iv, counter); +}; + +/** + * Set key. + * @param {Buffer} key + */ + +ChaCha20.prototype.initKey = function initKey(key) { + this.state[0] = 0x61707865; + this.state[1] = 0x3320646e; + this.state[2] = 0x79622d32; + this.state[3] = 0x6b206574; + + this.state[4] = key.readUInt32LE(0, true); + this.state[5] = key.readUInt32LE(4, true); + this.state[6] = key.readUInt32LE(8, true); + this.state[7] = key.readUInt32LE(12, true); + this.state[8] = key.readUInt32LE(16, true); + this.state[9] = key.readUInt32LE(20, true); + this.state[10] = key.readUInt32LE(24, true); + this.state[11] = key.readUInt32LE(28, true); + + this.state[12] = 0; + + this.pos = 0xffffffff; +}; + +/** + * Set IV and counter. + * @param {Buffer} iv + * @param {Number} counter + */ + +ChaCha20.prototype.initIV = function initIV(iv, counter) { + if (iv.length === 8) { + this.state[13] = 0; + this.state[14] = iv.readUInt32LE(0, true); + this.state[15] = iv.readUInt32LE(4, true); + } else if (iv.length === 12) { + this.state[13] = iv.readUInt32LE(0, true); + this.state[14] = iv.readUInt32LE(4, true); + this.state[15] = iv.readUInt32LE(8, true); + } else { + assert(false, 'Bad iv size.'); + } + + this.ivSize = iv.length * 8; + + this.setCounter(counter); +}; + +/** + * Encrypt/decrypt data. + * @param {Buffer} data - Will be mutated. + */ + +ChaCha20.prototype.encrypt = function encrypt(data) { + var i, j; + + for (i = 0; i < data.length; i++) { + if (this.pos >= 64) { + for (j = 0; j < 16; j++) + this.stream[j] = this.state[j]; + + for (j = 0; j < 10; j++) { + qround(this.stream, 0, 4, 8, 12); + qround(this.stream, 1, 5, 9, 13); + qround(this.stream, 2, 6, 10, 14); + qround(this.stream, 3, 7, 11, 15); + qround(this.stream, 0, 5, 10, 15); + qround(this.stream, 1, 6, 11, 12); + qround(this.stream, 2, 7, 8, 13); + qround(this.stream, 3, 4, 9, 14); + } + + for (j = 0; j < 16; j++) { + this.stream[j] += this.state[j]; + if (BIG_ENDIAN) + this.bytes.writeUInt32LE(this.stream[j], j * 4, true); + } + + this.state[12]++; + + if (this.state[12] === 0) { + assert(this.ivSize === 64, 'Counter overflow.'); + this.state[13]++; + assert(this.state[13] !== 0, 'Counter overflow.'); + } + + this.pos = 0; + } + + data[i] ^= this.bytes[this.pos++]; + } + + return data; +}; + +/** + * Artificially set the counter. + * @param {Number} counter + */ + +ChaCha20.prototype.setCounter = function setCounter(counter) { + var lo, hi; + + if (!counter) + counter = 0; + + lo = counter % 0x100000000; + hi = (counter - lo) / 0x100000000; + + this.state[12] = lo; + + if (this.ivSize === 64) + this.state[13] = hi; +}; + +/** + * Get the counter as a uint64. + * @returns {Number} + */ + +ChaCha20.prototype.getCounter = function getCounter() { + var lo = this.state[12]; + var hi = this.state[13]; + if (this.ivSize === 64) + return hi * 0x100000000 + lo; + return lo; +}; + +if (native) + ChaCha20 = native.ChaCha20; + +/* + * Helpers + */ + +function qround(x, a, b, c, d) { + x[a] += x[b]; + x[d] = rotl32(x[d] ^ x[a], 16); + + x[c] += x[d]; + x[b] = rotl32(x[b] ^ x[c], 12); + + x[a] += x[b]; + x[d] = rotl32(x[d] ^ x[a], 8); + + x[c] += x[d]; + x[b] = rotl32(x[b] ^ x[c], 7); +} + +function rotl32(w, b) { + return (w << b) | (w >>> (32 - b)); +} + +/* + * Expose + */ + +module.exports = ChaCha20; diff --git a/lib/crypto/chachapoly.js b/lib/crypto/chachapoly.js deleted file mode 100644 index faafed09..00000000 --- a/lib/crypto/chachapoly.js +++ /dev/null @@ -1,667 +0,0 @@ -/*! - * chachapoly.js - chacha20/poly1305 for bcoin - * Copyright (c) 2016-2017, Christopher Jeffrey (MIT License). - * https://github.com/bcoin-org/bcoin - */ - -'use strict'; - -var assert = require('assert'); -var native = require('../utils/native').binding; - -var BIG_ENDIAN = new Int8Array(new Int16Array([1]).buffer)[0] === 0; - -/** - * @module crypto/chachapoly - */ - -/** - * ChaCha20 (used for bip151) - * @see https://tools.ietf.org/html/rfc7539#section-2 - * @alias module:crypto/chachapoly.ChaCha20 - * @constructor - */ - -function ChaCha20() { - if (!(this instanceof ChaCha20)) - return new ChaCha20(); - - this.state = new Uint32Array(16); - this.stream = new Uint32Array(16); - this.bytes = new Uint8Array(this.stream.buffer); - - if (BIG_ENDIAN) - this.bytes = Buffer.allocUnsafe(64); - - this.pos = 0; - this.ivSize = 0; -} - -/** - * Initialize chacha20 with a key, iv, and counter. - * @param {Buffer} key - * @param {Buffer} iv - * @param {Number} counter - */ - -ChaCha20.prototype.init = function init(key, iv, counter) { - if (key) - this.initKey(key); - - if (iv) - this.initIV(iv, counter); -}; - -/** - * Set key. - * @param {Buffer} key - */ - -ChaCha20.prototype.initKey = function initKey(key) { - this.state[0] = 0x61707865; - this.state[1] = 0x3320646e; - this.state[2] = 0x79622d32; - this.state[3] = 0x6b206574; - - this.state[4] = key.readUInt32LE(0, true); - this.state[5] = key.readUInt32LE(4, true); - this.state[6] = key.readUInt32LE(8, true); - this.state[7] = key.readUInt32LE(12, true); - this.state[8] = key.readUInt32LE(16, true); - this.state[9] = key.readUInt32LE(20, true); - this.state[10] = key.readUInt32LE(24, true); - this.state[11] = key.readUInt32LE(28, true); - - this.state[12] = 0; - - this.pos = 0xffffffff; -}; - -/** - * Set IV and counter. - * @param {Buffer} iv - * @param {Number} counter - */ - -ChaCha20.prototype.initIV = function initIV(iv, counter) { - if (iv.length === 8) { - this.state[13] = 0; - this.state[14] = iv.readUInt32LE(0, true); - this.state[15] = iv.readUInt32LE(4, true); - } else if (iv.length === 12) { - this.state[13] = iv.readUInt32LE(0, true); - this.state[14] = iv.readUInt32LE(4, true); - this.state[15] = iv.readUInt32LE(8, true); - } else { - assert(false, 'Bad iv size.'); - } - - this.ivSize = iv.length * 8; - - this.setCounter(counter); -}; - -/** - * Encrypt/decrypt data. - * @param {Buffer} data - Will be mutated. - */ - -ChaCha20.prototype.encrypt = function encrypt(data) { - var i, j; - - for (i = 0; i < data.length; i++) { - if (this.pos >= 64) { - for (j = 0; j < 16; j++) - this.stream[j] = this.state[j]; - - for (j = 0; j < 10; j++) { - qround(this.stream, 0, 4, 8, 12); - qround(this.stream, 1, 5, 9, 13); - qround(this.stream, 2, 6, 10, 14); - qround(this.stream, 3, 7, 11, 15); - qround(this.stream, 0, 5, 10, 15); - qround(this.stream, 1, 6, 11, 12); - qround(this.stream, 2, 7, 8, 13); - qround(this.stream, 3, 4, 9, 14); - } - - for (j = 0; j < 16; j++) { - this.stream[j] += this.state[j]; - if (BIG_ENDIAN) - this.bytes.writeUInt32LE(this.stream[j], j * 4, true); - } - - this.state[12]++; - - if (this.state[12] === 0) { - assert(this.ivSize === 64, 'Counter overflow.'); - this.state[13]++; - assert(this.state[13] !== 0, 'Counter overflow.'); - } - - this.pos = 0; - } - - data[i] ^= this.bytes[this.pos++]; - } - - return data; -}; - -/** - * Artificially set the counter. - * @param {Number} counter - */ - -ChaCha20.prototype.setCounter = function setCounter(counter) { - var lo, hi; - - if (!counter) - counter = 0; - - lo = counter % 0x100000000; - hi = (counter - lo) / 0x100000000; - - this.state[12] = lo; - - if (this.ivSize === 64) - this.state[13] = hi; -}; - -/** - * Get the counter as a uint64. - * @returns {Number} - */ - -ChaCha20.prototype.getCounter = function getCounter() { - var lo = this.state[12]; - var hi = this.state[13]; - if (this.ivSize === 64) - return hi * 0x100000000 + lo; - return lo; -}; - -if (native) - ChaCha20 = native.ChaCha20; - -/* - * Helpers - */ - -function qround(x, a, b, c, d) { - x[a] += x[b]; - x[d] = rotl32(x[d] ^ x[a], 16); - - x[c] += x[d]; - x[b] = rotl32(x[b] ^ x[c], 12); - - x[a] += x[b]; - x[d] = rotl32(x[d] ^ x[a], 8); - - x[c] += x[d]; - x[b] = rotl32(x[b] ^ x[c], 7); -} - -function rotl32(w, b) { - return (w << b) | (w >>> (32 - b)); -} - -/** - * Poly1305 (used for bip151) - * @see https://github.com/floodyberry/poly1305-donna - * @see https://tools.ietf.org/html/rfc7539#section-2.5 - * @alias module:crypto/chachapoly.Poly1305 - * @constructor - */ - -function Poly1305() { - if (!(this instanceof Poly1305)) - return new Poly1305(); - - this.r = new Uint16Array(10); - this.h = new Uint16Array(10); - this.pad = new Uint16Array(8); - this.fin = 0; - this.leftover = 0; - this.buffer = Buffer.allocUnsafe(16); -} - -/** - * Initialize poly1305 with a key. - * @param {Buffer} key - */ - -Poly1305.prototype.init = function init(key) { - var t0, t1, t2, t3, t4, t5, t6, t7, i; - - // r &= 0xffffffc0ffffffc0ffffffc0fffffff - t0 = key.readUInt16LE(0, true); - t1 = key.readUInt16LE(2, true); - t2 = key.readUInt16LE(4, true); - t3 = key.readUInt16LE(6, true); - t4 = key.readUInt16LE(8, true); - t5 = key.readUInt16LE(10, true); - t6 = key.readUInt16LE(12, true); - t7 = key.readUInt16LE(14, true); - - this.r[0] = t0 & 0x1fff; - this.r[1] = ((t0 >>> 13) | (t1 << 3)) & 0x1fff; - this.r[2] = ((t1 >>> 10) | (t2 << 6)) & 0x1f03; - this.r[3] = ((t2 >>> 7) | (t3 << 9)) & 0x1fff; - this.r[4] = ((t3 >>> 4) | (t4 << 12)) & 0x00ff; - this.r[5] = (t4 >>> 1) & 0x1ffe; - this.r[6] = ((t4 >>> 14) | (t5 << 2)) & 0x1fff; - this.r[7] = ((t5 >>> 11) | (t6 << 5)) & 0x1f81; - this.r[8] = ((t6 >>> 8) | (t7 << 8)) & 0x1fff; - this.r[9] = (t7 >>> 5) & 0x007f; - - // h = 0 - for (i = 0; i < 10; i++) - this.h[i] = 0; - - // save pad for later - for (i = 0; i < 8; i++) - this.pad[i] = key.readUInt16LE(16 + (2 * i), true); - - this.leftover = 0; - this.fin = 0; -}; - -/** - * Process 16 byte blocks. - * @param {Buffer} data - Blocks. - * @param {Number} bytes - Size. - * @param {Number} m - Offset pointer. - */ - -Poly1305.prototype.blocks = function blocks(data, bytes, m) { - var hibit = this.fin ? 0 : (1 << 11); // 1 << 128 - var d = new Uint32Array(10); - var i, j, t0, t1, t2, t3, t4, t5, t6, t7, c; - - while (bytes >= 16) { - // h += m[i] - t0 = data.readUInt16LE(m + 0, true); - t1 = data.readUInt16LE(m + 2, true); - t2 = data.readUInt16LE(m + 4, true); - t3 = data.readUInt16LE(m + 6, true); - t4 = data.readUInt16LE(m + 8, true); - t5 = data.readUInt16LE(m + 10, true); - t6 = data.readUInt16LE(m + 12, true); - t7 = data.readUInt16LE(m + 14, true); - - this.h[0] += t0 & 0x1fff; - this.h[1] += ((t0 >>> 13) | (t1 << 3)) & 0x1fff; - this.h[2] += ((t1 >>> 10) | (t2 << 6)) & 0x1fff; - this.h[3] += ((t2 >>> 7) | (t3 << 9)) & 0x1fff; - this.h[4] += ((t3 >>> 4) | (t4 << 12)) & 0x1fff; - this.h[5] += ((t4 >>> 1)) & 0x1fff; - this.h[6] += ((t4 >>> 14) | (t5 << 2)) & 0x1fff; - this.h[7] += ((t5 >>> 11) | (t6 << 5)) & 0x1fff; - this.h[8] += ((t6 >>> 8) | (t7 << 8)) & 0x1fff; - this.h[9] += ((t7 >>> 5)) | hibit; - - // h *= r, (partial) h %= p - for (i = 0, c = 0; i < 10; i++) { - d[i] = c; - for (j = 0; j < 10; j++) { - d[i] += this.h[j] * (j <= i - ? this.r[i - j] - : 5 * this.r[i + 10 - j]); - // Sum(h[i] * r[i] * 5) will overflow slightly - // above 6 products with an unclamped r, so - // carry at 5 - if (j === 4) { - c = d[i] >>> 13; - d[i] &= 0x1fff; - } - } - c += d[i] >>> 13; - d[i] &= 0x1fff; - } - c = (c << 2) + c; // c *= 5 - c += d[0]; - d[0] = (c & 0x1fff); - c = c >>> 13; - d[1] += c; - - for (i = 0; i < 10; i++) - this.h[i] = d[i]; - - m += 16; - bytes -= 16; - } -}; - -/** - * Update the MAC with data (will be - * processed as 16 byte blocks). - * @param {Buffer} data - */ - -Poly1305.prototype.update = function update(data) { - var bytes = data.length; - var m = 0; - var i, want; - - // handle leftover - if (this.leftover) { - want = 16 - this.leftover; - if (want > bytes) - want = bytes; - for (i = 0; i < want; i++) - this.buffer[this.leftover + i] = data[m + i]; - bytes -= want; - m += want; - this.leftover += want; - if (this.leftover < 16) - return; - this.blocks(this.buffer, 16, 0); - this.leftover = 0; - } - - // process full blocks - if (bytes >= 16) { - want = bytes & ~(16 - 1); - this.blocks(data, want, m); - m += want; - bytes -= want; - } - - // store leftover - if (bytes) { - for (i = 0; i < bytes; i++) - this.buffer[this.leftover + i] = data[m + i]; - this.leftover += bytes; - } -}; - -/** - * Finalize and return a 16-byte MAC. - * @returns {Buffer} - */ - -Poly1305.prototype.finish = function finish() { - var mac = Buffer.allocUnsafe(16); - var g = new Uint16Array(10); - var c, mask, f, i; - - // process the remaining block - if (this.leftover) { - i = this.leftover; - this.buffer[i++] = 1; - for (; i < 16; i++) - this.buffer[i] = 0; - this.fin = 1; - this.blocks(this.buffer, 16, 0); - } - - // fully carry h - c = this.h[1] >>> 13; - this.h[1] &= 0x1fff; - for (i = 2; i < 10; i++) { - this.h[i] += c; - c = this.h[i] >>> 13; - this.h[i] &= 0x1fff; - } - this.h[0] += c * 5; - c = this.h[0] >>> 13; - this.h[0] &= 0x1fff; - this.h[1] += c; - c = this.h[1] >>> 13; - this.h[1] &= 0x1fff; - this.h[2] += c; - - // compute h + -p - g[0] = this.h[0] + 5; - c = g[0] >>> 13; - g[0] &= 0x1fff; - for (i = 1; i < 10; i++) { - g[i] = this.h[i] + c; - c = g[i] >>> 13; - g[i] &= 0x1fff; - } - - // select h if h < p, or h + -p if h >= p - mask = (c ^ 1) - 1; - for (i = 0; i < 10; i++) - g[i] &= mask; - mask = ~mask; - for (i = 0; i < 10; i++) - this.h[i] = (this.h[i] & mask) | g[i]; - - // h = h % (2^128) - this.h[0] = ((this.h[0]) | (this.h[1] << 13)) & 0xffff; - this.h[1] = ((this.h[1] >>> 3) | (this.h[2] << 10)) & 0xffff; - this.h[2] = ((this.h[2] >>> 6) | (this.h[3] << 7)) & 0xffff; - this.h[3] = ((this.h[3] >>> 9) | (this.h[4] << 4)) & 0xffff; - this.h[4] = ((this.h[4] >>> 12) - | (this.h[5] << 1) | (this.h[6] << 14)) & 0xffff; - this.h[5] = ((this.h[6] >>> 2) | (this.h[7] << 11)) & 0xffff; - this.h[6] = ((this.h[7] >>> 5) | (this.h[8] << 8)) & 0xffff; - this.h[7] = ((this.h[8] >>> 8) | (this.h[9] << 5)) & 0xffff; - - // mac = (h + pad) % (2^128) - f = this.h[0] + this.pad[0]; - this.h[0] = f; - for (i = 1; i < 8; i++) { - f = this.h[i] + this.pad[i] + (f >>> 16); - this.h[i] = f; - } - - for (i = 0; i < 8; i++) - mac.writeUInt16LE(this.h[i], i * 2, true); - - // zero out the state - for (i = 0; i < 10; i++) - this.h[i] = 0; - for (i = 0; i < 10; i++) - this.r[i] = 0; - for (i = 0; i < 8; i++) - this.pad[i] = 0; - - return mac; -}; - -/** - * Return a MAC for a message and key. - * @param {Buffer} msg - * @param {Buffer} key - * @returns {Buffer} MAC - */ - -Poly1305.auth = function auth(msg, key) { - var poly = new Poly1305(); - poly.init(key); - poly.update(msg); - return poly.finish(); -}; - -/** - * Compare two MACs in constant time. - * @param {Buffer} mac1 - * @param {Buffer} mac2 - * @returns {Boolean} - */ - -Poly1305.verify = function verify(mac1, mac2) { - var dif = 0; - var i; - - // Compare in constant time. - for (i = 0; i < 16; i++) - dif |= mac1[i] ^ mac2[i]; - - dif = (dif - 1) >>> 31; - - return (dif & 1) !== 0; -}; - -if (native) - Poly1305 = native.Poly1305; - -/** - * AEAD (used for bip151) - * @exports AEAD - * @see https://github.com/openssh/openssh-portable - * @see https://tools.ietf.org/html/rfc7539#section-2.8 - * @alias module:crypto/chachapoly.AEAD - * @constructor - */ - -function AEAD() { - if (!(this instanceof AEAD)) - return new AEAD(); - - this.chacha20 = new ChaCha20(); - this.poly1305 = new Poly1305(); - this.aadLen = 0; - this.cipherLen = 0; - this.polyKey = null; -} - -/** - * Initialize the AEAD with a key and iv. - * @param {Buffer} key - * @param {Buffer} iv - IV / packet sequence number. - */ - -AEAD.prototype.init = function init(key, iv) { - var polyKey = Buffer.allocUnsafe(32); - polyKey.fill(0); - - this.chacha20.init(key, iv); - this.chacha20.encrypt(polyKey); - this.poly1305.init(polyKey); - - // We need to encrypt a full block - // to get the cipher in the correct state. - this.chacha20.encrypt(Buffer.allocUnsafe(32)); - - // Counter should be one. - assert(this.chacha20.getCounter() === 1); - - // Expose for debugging. - this.polyKey = polyKey; - - this.aadLen = 0; - this.cipherLen = 0; -}; - -/** - * Update the aad (will be finalized - * on an encrypt/decrypt call). - * @param {Buffer} aad - */ - -AEAD.prototype.aad = function _aad(aad) { - assert(this.cipherLen === 0, 'Cannot update aad.'); - this.poly1305.update(aad); - this.aadLen += aad.length; -}; - -/** - * Encrypt a piece of data. - * @param {Buffer} data - */ - -AEAD.prototype.encrypt = function encrypt(data) { - if (this.cipherLen === 0) - this.pad16(this.aadLen); - - this.chacha20.encrypt(data); - this.poly1305.update(data); - this.cipherLen += data.length; - - return data; -}; - -/** - * Decrypt a piece of data. - * @param {Buffer} data - */ - -AEAD.prototype.decrypt = function decrypt(data) { - if (this.cipherLen === 0) - this.pad16(this.aadLen); - - this.cipherLen += data.length; - this.poly1305.update(data); - this.chacha20.encrypt(data); - - return data; -}; - -/** - * Authenticate data without decrypting. - * @param {Buffer} data - */ - -AEAD.prototype.auth = function auth(data) { - if (this.cipherLen === 0) - this.pad16(this.aadLen); - - this.cipherLen += data.length; - this.poly1305.update(data); - - return data; -}; - -/** - * Finalize the aead and generate a MAC. - * @returns {Buffer} MAC - */ - -AEAD.prototype.finish = function finish() { - var len = Buffer.allocUnsafe(16); - var lo, hi; - - // The RFC says these are supposed to be - // uint32le, but their own fucking test - // cases fail unless they are uint64le's. - lo = this.aadLen % 0x100000000; - hi = (this.aadLen - lo) / 0x100000000; - len.writeUInt32LE(lo, 0, true); - len.writeUInt32LE(hi, 4, true); - - lo = this.cipherLen % 0x100000000; - hi = (this.cipherLen - lo) / 0x100000000; - len.writeUInt32LE(lo, 8, true); - len.writeUInt32LE(hi, 12, true); - - if (this.cipherLen === 0) - this.pad16(this.aadLen); - - this.pad16(this.cipherLen); - this.poly1305.update(len); - - return this.poly1305.finish(); -}; - -/** - * Pad a chunk before updating mac. - * @private - * @param {Number} size - */ - -AEAD.prototype.pad16 = function pad16(size) { - var pad; - - size %= 16; - - if (size === 0) - return; - - pad = Buffer.allocUnsafe(16 - size); - pad.fill(0); - - this.poly1305.update(pad); -}; - -/* - * Expose - */ - -exports.ChaCha20 = ChaCha20; -exports.Poly1305 = Poly1305; -exports.AEAD = AEAD; diff --git a/lib/crypto/cleanse.js b/lib/crypto/cleanse.js new file mode 100644 index 00000000..a6b45dfe --- /dev/null +++ b/lib/crypto/cleanse.js @@ -0,0 +1,34 @@ +/*! + * cleanse.js - memzero for bcoin + * Copyright (c) 2016-2017, Christopher Jeffrey (MIT License). + * https://github.com/bcoin-org/bcoin + */ + +'use strict'; + +/** + * @module crypto.cleanse + */ + +var native = require('../utils/native').binding; +var counter = 0; + +/** + * A maybe-secure memzero. + * @param {Buffer} data + */ + +module.exports = function cleanse(data) { + var ctr = counter; + var i; + + for (i = 0; i < data.length; i++) { + data[i] = ctr & 0xff; + ctr += i; + } + + counter = ctr >>> 0; +}; + +if (native) + exports.cleanse = native.cleanse; diff --git a/lib/crypto/crypto.js b/lib/crypto/crypto.js deleted file mode 100644 index 9a098a8d..00000000 --- a/lib/crypto/crypto.js +++ /dev/null @@ -1,451 +0,0 @@ -/*! - * crypto.js - crypto for bcoin - * Copyright (c) 2014-2015, Fedor Indutny (MIT License) - * Copyright (c) 2014-2017, Christopher Jeffrey (MIT License). - * https://github.com/bcoin-org/bcoin - */ - -'use strict'; - -var backend = require('./backend'); -var native = require('../utils/native').binding; -var scrypt = require('./scrypt'); - -/** - * @exports crypto/crypto - * @ignore - */ - -var crypto = exports; - -/** - * Hash with chosen algorithm. - * @function - * @param {String} alg - * @param {Buffer} data - * @returns {Buffer} - */ - -crypto.hash = backend.hash; - -/** - * Hash with ripemd160. - * @function - * @param {Buffer} data - * @returns {Buffer} - */ - -crypto.ripemd160 = backend.ripemd160; - -/** - * Hash with sha1. - * @function - * @param {Buffer} data - * @returns {Buffer} - */ - -crypto.sha1 = backend.sha1; - -/** - * Hash with sha256. - * @function - * @param {Buffer} data - * @returns {Buffer} - */ - -crypto.sha256 = backend.sha256; - -/** - * Hash with sha256 and ripemd160 (OP_HASH160). - * @function - * @param {Buffer} data - * @returns {Buffer} - */ - -crypto.hash160 = backend.hash160; - -/** - * Hash with sha256 twice (OP_HASH256). - * @function - * @param {Buffer} data - * @returns {Buffer} - */ - -crypto.hash256 = backend.hash256; - -/** - * Create an HMAC. - * @function - * @param {String} alg - * @param {Buffer} data - * @param {Buffer} key - * @returns {Buffer} HMAC - */ - -crypto.hmac = backend.hmac; - -/** - * Perform key derivation using PBKDF2. - * @function - * @param {Buffer} key - * @param {Buffer} salt - * @param {Number} iter - * @param {Number} len - * @param {String} alg - * @returns {Buffer} - */ - -crypto.pbkdf2 = backend.pbkdf2; - -/** - * Execute pbkdf2 asynchronously. - * @function - * @param {Buffer} key - * @param {Buffer} salt - * @param {Number} iter - * @param {Number} len - * @param {String} alg - * @returns {Promise} - */ - -crypto.pbkdf2Async = backend.pbkdf2Async; - -/** - * Perform key derivation using scrypt. - * @function - * @param {Buffer} passwd - * @param {Buffer} salt - * @param {Number} N - * @param {Number} r - * @param {Number} p - * @param {Number} len - * @returns {Buffer} - */ - -crypto.scrypt = scrypt.scrypt; - -/** - * Execute scrypt asynchronously. - * @function - * @param {Buffer} passwd - * @param {Buffer} salt - * @param {Number} N - * @param {Number} r - * @param {Number} p - * @param {Number} len - * @returns {Promise} - */ - -crypto.scryptAsync = scrypt.scryptAsync; - -/** - * Perform hkdf extraction. - * @param {Buffer} ikm - * @param {Buffer} key - * @param {String} alg - * @returns {Buffer} - */ - -crypto.hkdfExtract = function hkdfExtract(ikm, key, alg) { - return crypto.hmac(alg, ikm, key); -}; - -/** - * Perform hkdf expansion. - * @param {Buffer} prk - * @param {Buffer} info - * @param {Number} len - * @param {String} alg - * @returns {Buffer} - */ - -crypto.hkdfExpand = function hkdfExpand(prk, info, len, alg) { - var size = crypto.hash(alg, Buffer.alloc(0)).length; - var blocks = Math.ceil(len / size); - var i, okm, buf, out; - - if (blocks > 255) - throw new Error('Too many blocks.'); - - okm = Buffer.allocUnsafe(len); - - if (blocks === 0) - return okm; - - buf = Buffer.allocUnsafe(size + info.length + 1); - - // First round: - info.copy(buf, size); - buf[buf.length - 1] = 1; - out = crypto.hmac(alg, buf.slice(size), prk); - out.copy(okm, 0); - - for (i = 1; i < blocks; i++) { - out.copy(buf, 0); - buf[buf.length - 1]++; - out = crypto.hmac(alg, buf, prk); - out.copy(okm, i * size); - } - - return okm; -}; - -/** - * Build a merkle tree from leaves. - * Note that this will mutate the `leaves` array! - * @param {Buffer[]} leaves - * @returns {MerkleTree} - */ - -crypto.createMerkleTree = function createMerkleTree(leaves) { - var nodes = leaves; - var size = leaves.length; - var malleated = false; - var i, j, k, hash, left, right, lr; - - if (size === 0) { - hash = Buffer.allocUnsafe(32); - hash.fill(0); - nodes.push(hash); - return new MerkleTree(nodes, malleated); - } - - lr = Buffer.allocUnsafe(64); - - for (j = 0; size > 1; size = ((size + 1) / 2) | 0) { - for (i = 0; i < size; i += 2) { - k = Math.min(i + 1, size - 1); - left = nodes[j + i]; - right = nodes[j + k]; - - if (k === i + 1 && k + 1 === size - && left.equals(right)) { - malleated = true; - } - - left.copy(lr, 0); - right.copy(lr, 32); - - hash = crypto.hash256(lr); - - nodes.push(hash); - } - j += size; - } - - return new MerkleTree(nodes, malleated); -}; - -if (native) - crypto.createMerkleTree = native.createMerkleTree; - -/** - * Calculate merkle root from leaves. - * @param {Buffer[]} leaves - * @returns {MerkleRoot} - */ - -crypto.createMerkleRoot = function createMerkleRoot(leaves) { - var tree = crypto.createMerkleTree(leaves); - var hash = tree.nodes[tree.nodes.length - 1]; - var malleated = tree.malleated; - return new MerkleRoot(hash, malleated); -}; - -/** - * Collect a merkle branch at vector index. - * @param {Number} index - * @param {Buffer[]} leaves - * @returns {Buffer[]} branch - */ - -crypto.createMerkleBranch = function createMerkleBranch(index, leaves) { - var size = leaves.length; - var tree = crypto.createMerkleTree(leaves); - var branch = []; - var j = 0; - var i; - - for (; size > 1; size = (size + 1) / 2 | 0) { - i = Math.min(index ^ 1, size - 1); - branch.push(tree.nodes[j + i]); - index >>>= 1; - j += size; - } - - return branch; -}; - -/** - * Check a merkle branch at vector index. - * @param {Buffer} hash - * @param {Buffer[]} branch - * @param {Number} index - * @returns {Buffer} Hash. - */ - -crypto.verifyMerkleBranch = function verifyMerkleBranch(hash, branch, index) { - var i, otherside, lr; - - if (branch.length === 0) - return hash; - - lr = Buffer.allocUnsafe(64); - - for (i = 0; i < branch.length; i++) { - otherside = branch[i]; - - if (index & 1) { - otherside.copy(lr, 0); - hash.copy(lr, 32); - } else { - hash.copy(lr, 0); - otherside.copy(lr, 32); - } - - hash = crypto.hash256(lr); - index >>>= 1; - } - - return hash; -}; - -if (native) - crypto.verifyMerkleBranch = native.verifyMerkleBranch; - -/** - * 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 = backend.encipher; - -/** - * 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 = backend.decipher; - -/** - * memcmp in constant time (can only return true or false). - * This protects us against timing attacks when - * comparing an input against a secret string. - * @see https://cryptocoding.net/index.php/Coding_rules - * @see `$ man 3 memcmp` (NetBSD's consttime_memequal) - * @param {Buffer} a - * @param {Buffer} b - * @returns {Boolean} - */ - -crypto.ccmp = function ccmp(a, b) { - var i, res; - - if (!Buffer.isBuffer(a)) - return false; - - if (!Buffer.isBuffer(b)) - return false; - - if (b.length === 0) - return a.length === 0; - - res = a.length ^ b.length; - - for (i = 0; i < a.length; i++) - res |= a[i] ^ b[i % b.length]; - - return res === 0; -}; - -/** - * A maybe-secure memzero. - * @param {Buffer} data - */ - -crypto.cleanse = function cleanse(data) { - var ctr = crypto._counter; - var i; - - for (i = 0; i < data.length; i++) { - data[i] = ctr & 0xff; - ctr += i; - } - - crypto._counter = ctr >>> 0; -}; - -crypto._counter = 0; - -if (native) - crypto.cleanse = native.cleanse; - -/** - * Generate some random bytes. - * @function - * @param {Number} size - * @returns {Buffer} - */ - -crypto.randomBytes = backend.randomBytes; - -/** - * Generate a random uint32. - * Probably more cryptographically sound than - * `Math.random()`. - * @function - * @returns {Number} - */ - -crypto.randomInt = function randomInt() { - return crypto.randomBytes(4).readUInt32LE(0, true); -}; - -/** - * Generate a random number within a range. - * Probably more cryptographically sound than - * `Math.random()`. - * @function - * @param {Number} min - Inclusive. - * @param {Number} max - Exclusive. - * @returns {Number} - */ - -crypto.randomRange = function randomRange(min, max) { - var num = crypto.randomInt(); - return Math.floor((num / 0x100000000) * (max - min) + min); -}; - -/** - * Merkle Tree - * @constructor - * @ignore - * @param {Buffer[]} nodes - * @param {Boolean} malleated - */ - -function MerkleTree(nodes, malleated) { - this.nodes = nodes; - this.malleated = malleated; -} - -/** - * Merkle Root - * @constructor - * @ignore - * @param {Buffer} hash - * @param {Boolean} malleated - */ - -function MerkleRoot(hash, malleated) { - this.hash = hash; - this.malleated = malleated; -} diff --git a/lib/crypto/digest-browser.js b/lib/crypto/digest-browser.js new file mode 100644 index 00000000..8d758013 --- /dev/null +++ b/lib/crypto/digest-browser.js @@ -0,0 +1,105 @@ +/*! + * digest-browser.js - hash functions for bcoin + * Copyright (c) 2014-2017, Christopher Jeffrey (MIT License). + * https://github.com/bcoin-org/bcoin + */ + +'use strict'; + +/** + * @module crypto.digest-browser + * @ignore + */ + +var assert = require('assert'); +var hashjs = require('hash.js'); +var sha256 = require('./sha256'); + +/** + * Hash with chosen algorithm. + * @param {String} alg + * @param {Buffer} data + * @returns {Buffer} + */ + +exports.hash = function _hash(alg, data) { + var hash; + + if (alg === 'sha256') + return sha256.digest(data); + + hash = hashjs[alg]; + + assert(hash != null, 'Unknown algorithm.'); + + return Buffer.from(hash().update(data).digest()); +}; + +/** + * Hash with ripemd160. + * @param {Buffer} data + * @returns {Buffer} + */ + +exports.ripemd160 = function ripemd160(data) { + return exports.hash('ripemd160', data); +}; + +/** + * Hash with sha1. + * @param {Buffer} data + * @returns {Buffer} + */ + +exports.sha1 = function sha1(data) { + return exports.hash('sha1', data); +}; + +/** + * Hash with sha256. + * @param {Buffer} data + * @returns {Buffer} + */ + +exports.sha256 = function _sha256(data) { + return sha256.digest(data); +}; + +/** + * Hash with sha256 and ripemd160 (OP_HASH160). + * @param {Buffer} data + * @returns {Buffer} + */ + +exports.hash160 = function hash160(data) { + return exports.hash('ripemd160', sha256.digest(data)); +}; + +/** + * Hash with sha256 twice (OP_HASH256). + * @param {Buffer} data + * @returns {Buffer} + */ + +exports.hash256 = function hash256(data) { + return sha256.hash256(data); +}; + +/** + * Create an HMAC. + * @param {String} alg + * @param {Buffer} data + * @param {Buffer} key + * @returns {Buffer} HMAC + */ + +exports.hmac = function _hmac(alg, data, key) { + var hash = hashjs[alg]; + var hmac; + + assert(hash != null, 'Unknown algorithm.'); + + hmac = hashjs.hmac(hash, key); + + return Buffer.from(hmac.update(data).digest()); +}; diff --git a/lib/crypto/digest.js b/lib/crypto/digest.js new file mode 100644 index 00000000..730f4d4c --- /dev/null +++ b/lib/crypto/digest.js @@ -0,0 +1,98 @@ +/*! + * digest.js - hash functions for bcoin + * Copyright (c) 2014-2017, Christopher Jeffrey (MIT License). + * https://github.com/bcoin-org/bcoin + */ + +'use strict'; + +/** + * @module crypto.digest + */ + +var crypto = require('crypto'); +var native = require('../utils/native').binding; + +/** + * Hash with chosen algorithm. + * @param {String} alg + * @param {Buffer} data + * @returns {Buffer} + */ + +exports.hash = function hash(alg, data) { + return crypto.createHash(alg).update(data).digest(); +}; + +/** + * Hash with ripemd160. + * @param {Buffer} data + * @returns {Buffer} + */ + +exports.ripemd160 = function ripemd160(data) { + return exports.hash('ripemd160', data); +}; + +/** + * Hash with sha1. + * @param {Buffer} data + * @returns {Buffer} + */ + +exports.sha1 = function sha1(data) { + return exports.hash('sha1', data); +}; + +/** + * Hash with sha256. + * @param {Buffer} data + * @returns {Buffer} + */ + +exports.sha256 = function sha256(data) { + return exports.hash('sha256', data); +}; + +/** + * Hash with sha256 and ripemd160 (OP_HASH160). + * @param {Buffer} data + * @returns {Buffer} + */ + +exports.hash160 = function hash160(data) { + return exports.ripemd160(exports.sha256(data)); +}; + +/** + * Hash with sha256 twice (OP_HASH256). + * @param {Buffer} data + * @returns {Buffer} + */ + +exports.hash256 = function hash256(data) { + return exports.sha256(exports.sha256(data)); +}; + +/** + * Create an HMAC. + * @param {String} alg + * @param {Buffer} data + * @param {Buffer} key + * @returns {Buffer} HMAC + */ + +exports.hmac = function hmac(alg, data, key) { + var hmac = crypto.createHmac(alg, key); + return hmac.update(data).digest(); +}; + +if (native) { + exports.hash = native.hash; + exports.hmac = native.hmac; + exports.ripemd160 = native.ripemd160; + exports.sha1 = native.sha1; + exports.sha256 = native.sha256; + exports.hash160 = native.hash160; + exports.hash256 = native.hash256; +} diff --git a/lib/crypto/ecdsa.js b/lib/crypto/ecdsa.js index ebc67027..70a7e658 100644 --- a/lib/crypto/ecdsa.js +++ b/lib/crypto/ecdsa.js @@ -12,7 +12,7 @@ var assert = require('assert'); var elliptic = require('elliptic'); -var backend = require('./backend'); +var digest = require('./digest'); /** * Verify ECDSA signature. @@ -34,7 +34,7 @@ exports.verify = function verify(curve, alg, msg, sig, key) { assert(Buffer.isBuffer(key)); ec = elliptic.ec(curve); - hash = backend.hash(alg, msg); + hash = digest.hash(alg, msg); try { return ec.verify(hash, sig, key); @@ -62,7 +62,7 @@ exports.sign = function sign(curve, alg, msg, key) { assert(Buffer.isBuffer(key)); ec = elliptic.ec(curve); - hash = backend.hash(alg, msg); + hash = digest.hash(alg, msg); sig = ec.sign(hash, key, { canonical: true }); diff --git a/lib/crypto/hkdf.js b/lib/crypto/hkdf.js new file mode 100644 index 00000000..5d0bdaf5 --- /dev/null +++ b/lib/crypto/hkdf.js @@ -0,0 +1,65 @@ +/*! + * hkdf.js - hkdf for bcoin + * Copyright (c) 2014-2017, Christopher Jeffrey (MIT License). + * https://github.com/bcoin-org/bcoin + */ + +'use strict'; + +/** + * @module crypto/hkdf + */ + +var digest = require('./digest'); + +/** + * Perform hkdf extraction. + * @param {Buffer} ikm + * @param {Buffer} key + * @param {String} alg + * @returns {Buffer} + */ + +exports.extract = function extract(ikm, key, alg) { + return digest.hmac(alg, ikm, key); +}; + +/** + * Perform hkdf expansion. + * @param {Buffer} prk + * @param {Buffer} info + * @param {Number} len + * @param {String} alg + * @returns {Buffer} + */ + +exports.expand = function expand(prk, info, len, alg) { + var size = digest.hash(alg, Buffer.alloc(0)).length; + var blocks = Math.ceil(len / size); + var i, okm, buf, out; + + if (blocks > 255) + throw new Error('Too many blocks.'); + + okm = Buffer.allocUnsafe(len); + + if (blocks === 0) + return okm; + + buf = Buffer.allocUnsafe(size + info.length + 1); + + // First round: + info.copy(buf, size); + buf[buf.length - 1] = 1; + out = digest.hmac(alg, buf.slice(size), prk); + out.copy(okm, 0); + + for (i = 1; i < blocks; i++) { + out.copy(buf, 0); + buf[buf.length - 1]++; + out = digest.hmac(alg, buf, prk); + out.copy(okm, i * size); + } + + return okm; +}; diff --git a/lib/crypto/hmac-drbg.js b/lib/crypto/hmac-drbg.js index d9949e4d..4739c257 100644 --- a/lib/crypto/hmac-drbg.js +++ b/lib/crypto/hmac-drbg.js @@ -8,7 +8,7 @@ 'use strict'; var assert = require('assert'); -var backend = require('./backend'); +var digest = require('./digest'); /* * Constants @@ -73,8 +73,8 @@ HmacDRBG.prototype.iterate = function iterate() { this.V.copy(data, 0); data[HASH_SIZE] = 0x00; - this.K = backend.hmac(HASH_ALG, data, this.K); - this.V = backend.hmac(HASH_ALG, this.V, this.K); + this.K = digest.hmac(HASH_ALG, data, this.K); + this.V = digest.hmac(HASH_ALG, this.V, this.K); }; HmacDRBG.prototype.update = function update(seed) { @@ -87,13 +87,13 @@ HmacDRBG.prototype.update = function update(seed) { data[HASH_SIZE] = 0x00; seed.copy(data, HASH_SIZE + 1); - this.K = backend.hmac(HASH_ALG, data, this.K); - this.V = backend.hmac(HASH_ALG, this.V, this.K); + this.K = digest.hmac(HASH_ALG, data, this.K); + this.V = digest.hmac(HASH_ALG, this.V, this.K); data[HASH_SIZE] = 0x01; - this.K = backend.hmac(HASH_ALG, data, this.K); - this.V = backend.hmac(HASH_ALG, this.V, this.K); + this.K = digest.hmac(HASH_ALG, data, this.K); + this.V = digest.hmac(HASH_ALG, this.V, this.K); }; HmacDRBG.prototype.generate = function generate(len) { @@ -104,7 +104,7 @@ HmacDRBG.prototype.generate = function generate(len) { throw new Error('Reseed is required.'); while (pos < len) { - this.V = backend.hmac(HASH_ALG, this.V, this.K); + this.V = digest.hmac(HASH_ALG, this.V, this.K); this.V.copy(data, pos); pos += HASH_SIZE; } diff --git a/lib/crypto/index.js b/lib/crypto/index.js index 40c3266d..f7af5683 100644 --- a/lib/crypto/index.js +++ b/lib/crypto/index.js @@ -1,349 +1,50 @@ +/*! + * crypto/index.js - crypto for bcoin + * Copyright (c) 2014-2016, Christopher Jeffrey (MIT License). + * https://github.com/bcoin-org/bcoin + */ + 'use strict'; /** * @module crypto */ -var crypto = require('./crypto'); - -/** - * Crypto module. - * @ignore - */ - -exports.crypto = crypto; - -/** - * Hash with chosen algorithm. - * @function - * @param {String} alg - * @param {Buffer} data - * @returns {Buffer} - */ - -exports.hash = crypto.hash; - -/** - * Hash with ripemd160. - * @function - * @param {Buffer} data - * @returns {Buffer} - */ - -exports.ripemd160 = crypto.ripemd160; - -/** - * Hash with sha1. - * @function - * @param {Buffer} data - * @returns {Buffer} - */ - -exports.sha1 = crypto.sha1; - -/** - * Hash with sha256. - * @function - * @param {Buffer} data - * @returns {Buffer} - */ - -exports.sha256 = crypto.sha256; - -/** - * Hash with sha256 and ripemd160 (OP_HASH160). - * @function - * @param {Buffer} data - * @returns {Buffer} - */ - -exports.hash160 = crypto.hash160; - -/** - * Hash with sha256 twice (OP_HASH256). - * @function - * @param {Buffer} data - * @returns {Buffer} - */ - -exports.hash256 = crypto.hash256; - -/** - * Create an HMAC. - * @function - * @param {String} alg - * @param {Buffer} data - * @param {Buffer} key - * @returns {Buffer} HMAC - */ - -exports.hmac = crypto.hmac; - -/** - * Perform key derivation using PBKDF2. - * @function - * @param {Buffer} key - * @param {Buffer} salt - * @param {Number} iter - * @param {Number} len - * @param {String} alg - * @returns {Buffer} - */ - -exports.pbkdf2 = crypto.pbkdf2; - -/** - * Execute pbkdf2 asynchronously. - * @function - * @param {Buffer} key - * @param {Buffer} salt - * @param {Number} iter - * @param {Number} len - * @param {String} alg - * @returns {Promise} - */ - -exports.pbkdf2Async = crypto.pbkdf2Async; - -/** - * Perform key derivation using scrypt. - * @function - * @param {Buffer} passwd - * @param {Buffer} salt - * @param {Number} N - * @param {Number} r - * @param {Number} p - * @param {Number} len - * @returns {Buffer} - */ - -exports.scrypt = crypto.scrypt; - -/** - * Execute scrypt asynchronously. - * @function - * @param {Buffer} passwd - * @param {Buffer} salt - * @param {Number} N - * @param {Number} r - * @param {Number} p - * @param {Number} len - * @returns {Promise} - */ - -exports.scryptAsync = crypto.scryptAsync; - -/** - * Perform hkdf extraction. - * @function - * @param {Buffer} ikm - * @param {Buffer} key - * @param {String} alg - * @returns {Buffer} - */ - -exports.hkdfExtract = crypto.hkdfExtract; - -/** - * Perform hkdf expansion. - * @function - * @param {Buffer} prk - * @param {Buffer} info - * @param {Number} len - * @param {String} alg - * @returns {Buffer} - */ - -exports.hkdfExpand = crypto.hkdfExpand; - -/** - * Build a merkle tree from leaves. - * Note that this will mutate the `leaves` array! - * @function - * @param {Buffer[]} leaves - * @returns {MerkleTree} - */ - -exports.createMerkleTree = crypto.createMerkleTree; - -/** - * Calculate merkle root from leaves. - * @function - * @param {Buffer[]} leaves - * @returns {MerkleRoot} - */ - -exports.createMerkleRoot = crypto.createMerkleRoot; - -/** - * Collect a merkle branch at vector index. - * @function - * @param {Number} index - * @param {Buffer[]} leaves - * @returns {Buffer[]} branch - */ - -exports.createMerkleBranch = crypto.createMerkleBranch; - -/** - * Check a merkle branch at vector index. - * @function - * @param {Buffer} hash - * @param {Buffer[]} branch - * @param {Number} index - * @returns {Buffer} Hash. - */ - -exports.verifyMerkleBranch = crypto.verifyMerkleBranch; - -/** - * Encrypt with aes-256-cbc. - * @function - * @param {Buffer} data - * @param {Buffer} key - 256 bit key. - * @param {Buffer} iv - 128 bit initialization vector. - * @returns {Buffer} - */ - -exports.encipher = crypto.encipher; - -/** - * Decrypt with aes-256-cbc. - * @function - * @param {Buffer} data - * @param {Buffer} key - 256 bit key. - * @param {Buffer} iv - 128 bit initialization vector. - * @returns {Buffer} - */ - -exports.decipher = crypto.decipher; - -/** - * memcmp in constant time (can only return true or false). - * This protects us against timing attacks when - * comparing an input against a secret string. - * @function - * @see https://cryptocoding.net/index.php/Coding_rules - * @see `$ man 3 memcmp` (NetBSD's consttime_memequal) - * @param {Buffer} a - * @param {Buffer} b - * @returns {Boolean} - */ - -exports.ccmp = crypto.ccmp; - -/** - * A maybe-secure memzero. - * @function - * @param {Buffer} data - */ - -exports.cleanse = crypto.cleanse; - -/** - * Generate some random bytes. - * @function - * @param {Number} size - * @returns {Buffer} - */ - -exports.randomBytes = crypto.randomBytes; - -/** - * Generate a random uint32. - * Probably more cryptographically sound than - * `Math.random()`. - * @function - * @returns {Number} - */ - -exports.randomInt = crypto.randomInt; - -/** - * Generate a random number within a range. - * Probably more cryptographically sound than - * `Math.random()`. - * @function - * @param {Number} min - Inclusive. - * @param {Number} max - Exclusive. - * @returns {Number} - */ - -exports.randomRange = crypto.randomRange; - -/** - * chachapoly module - * @see module:crypto/chachapoly - */ - -exports.chachapoly = require('./chachapoly'); - -/** - * ChaCha20 - * @see module:crypto/chachapoly.ChaCha20 - */ - -exports.ChaCha20 = exports.chachapoly.ChaCha20; - -/** - * Poly1305 - * @see module:crypto/chachapoly.Poly1305 - */ - -exports.Poly1305 = exports.chachapoly.Poly1305; - -/** - * AEAD - * @see module:crypto/chachapoly.AEAD - */ - -exports.AEAD = exports.chachapoly.AEAD; - -/** - * BN - * @see https://github.com/indutny/bn.js - */ +var digest = require('./digest'); +var random = require('./random'); +var aes = require('./aes'); +exports.aes = require('./aes'); +exports.AEAD = require('./aead'); exports.BN = require('./bn'); - -/** - * RSA - * @see module:crypto/rsa - */ - -exports.rsa = require('./rsa'); - -/** - * ECDSA - * @see module:crypto/ecdsa - */ - +exports.ccmp = require('./ccmp'); +exports.ChaCha20 = require('./chacha20'); +exports.cleanse = require('./cleanse'); +exports.digest = require('./digest'); exports.ecdsa = require('./ecdsa'); - -/** - * secp256k1 module - * @see module:crypto/secp256k1 - */ - -exports.secp256k1 = require('./secp256k1'); - -/** - * schnorr module - * @see module:crypto/schnorr - */ - +exports.hkdf = require('./hkdf'); +exports.HmacDRBG = require('./hmac-drbg'); +exports.merkle = require('./merkle'); +exports.pbkdf2 = require('./pbkdf2'); +exports.Poly1305 = require('./poly1305'); +exports.random = require('./random'); +exports.rsa = require('./rsa'); exports.schnorr = require('./schnorr'); - -/** - * siphash module - * @see module:crypto/siphash - */ - +exports.scrypt = require('./scrypt'); +exports.secp256k1 = require('./secp256k1'); exports.siphash = require('./siphash'); -/** - * siphash256 - * @see module:crypto/siphash.siphash256 - */ +exports.hash = digest.hash; +exports.ripemd160 = digest.ripemd160; +exports.sha1 = digest.sha1; +exports.sha256 = digest.sha256; +exports.hash160 = digest.hash160; +exports.hash256 = digest.hash256; +exports.hmac = digest.hmac; -exports.siphash256 = exports.siphash.siphash256; +exports.encipher = aes.encipher; +exports.decipher = aes.decipher; + +exports.randomBytes = random.randomBytes; +exports.randomInt = random.randomInt; +exports.randomRange = random.randomRange; diff --git a/lib/crypto/merkle.js b/lib/crypto/merkle.js new file mode 100644 index 00000000..a9a62751 --- /dev/null +++ b/lib/crypto/merkle.js @@ -0,0 +1,164 @@ +/*! + * merkle.js - merkle trees for bcoin + * Copyright (c) 2014-2015, Fedor Indutny (MIT License) + * Copyright (c) 2014-2017, Christopher Jeffrey (MIT License). + * https://github.com/bcoin-org/bcoin + */ + +'use strict'; + +/** + * @module crypto/merkle + */ + +var digest = require('./digest'); +var native = require('../utils/native').binding; + +/** + * Build a merkle tree from leaves. + * Note that this will mutate the `leaves` array! + * @param {Buffer[]} leaves + * @returns {MerkleTree} + */ + +exports.createTree = function createTree(leaves) { + var nodes = leaves; + var size = leaves.length; + var malleated = false; + var i, j, k, hash, left, right, lr; + + if (size === 0) { + hash = Buffer.allocUnsafe(32); + hash.fill(0); + nodes.push(hash); + return new MerkleTree(nodes, malleated); + } + + lr = Buffer.allocUnsafe(64); + + for (j = 0; size > 1; size = ((size + 1) / 2) | 0) { + for (i = 0; i < size; i += 2) { + k = Math.min(i + 1, size - 1); + left = nodes[j + i]; + right = nodes[j + k]; + + if (k === i + 1 && k + 1 === size + && left.equals(right)) { + malleated = true; + } + + left.copy(lr, 0); + right.copy(lr, 32); + + hash = digest.hash256(lr); + + nodes.push(hash); + } + j += size; + } + + return new MerkleTree(nodes, malleated); +}; + +if (native) + exports.createTree = native.createMerkleTree; + +/** + * Calculate merkle root from leaves. + * @param {Buffer[]} leaves + * @returns {MerkleRoot} + */ + +exports.createRoot = function createRoot(leaves) { + var tree = exports.createTree(leaves); + var hash = tree.nodes[tree.nodes.length - 1]; + var malleated = tree.malleated; + return new MerkleRoot(hash, malleated); +}; + +/** + * Collect a merkle branch at vector index. + * @param {Number} index + * @param {Buffer[]} leaves + * @returns {Buffer[]} branch + */ + +exports.createBranch = function createBranch(index, leaves) { + var size = leaves.length; + var tree = exports.createTree(leaves); + var branch = []; + var j = 0; + var i; + + for (; size > 1; size = (size + 1) / 2 | 0) { + i = Math.min(index ^ 1, size - 1); + branch.push(tree.nodes[j + i]); + index >>>= 1; + j += size; + } + + return branch; +}; + +/** + * Check a merkle branch at vector index. + * @param {Buffer} hash + * @param {Buffer[]} branch + * @param {Number} index + * @returns {Buffer} Hash. + */ + +exports.verifyBranch = function verifyBranch(hash, branch, index) { + var i, otherside, lr; + + if (branch.length === 0) + return hash; + + lr = Buffer.allocUnsafe(64); + + for (i = 0; i < branch.length; i++) { + otherside = branch[i]; + + if (index & 1) { + otherside.copy(lr, 0); + hash.copy(lr, 32); + } else { + hash.copy(lr, 0); + otherside.copy(lr, 32); + } + + hash = digest.hash256(lr); + index >>>= 1; + } + + return hash; +}; + +if (native) + exports.verifyBranch = native.verifyMerkleBranch; + +/** + * Merkle Tree + * @constructor + * @ignore + * @param {Buffer[]} nodes + * @param {Boolean} malleated + */ + +function MerkleTree(nodes, malleated) { + this.nodes = nodes; + this.malleated = malleated; +} + +/** + * Merkle Root + * @constructor + * @ignore + * @param {Buffer} hash + * @param {Boolean} malleated + */ + +function MerkleRoot(hash, malleated) { + this.hash = hash; + this.malleated = malleated; +} diff --git a/lib/crypto/pbkdf2-browser.js b/lib/crypto/pbkdf2-browser.js new file mode 100644 index 00000000..9ecd1849 --- /dev/null +++ b/lib/crypto/pbkdf2-browser.js @@ -0,0 +1,108 @@ +/*! + * pbkdf2.js - pbkdf2 for bcoin + * Copyright (c) 2014-2017, Christopher Jeffrey (MIT License). + * https://github.com/bcoin-org/bcoin + */ + +'use strict'; + +/** + * @module crypto.pbkdf2-browser + * @ignore + */ + +var digest = require('./digest'); +var crypto = global.crypto || global.msCrypto || {}; +var subtle = crypto.subtle && crypto.subtle.importKey ? crypto.subtle : {}; + +/** + * Perform key derivation using PBKDF2. + * @param {Buffer} key + * @param {Buffer} salt + * @param {Number} iter + * @param {Number} len + * @param {String} alg + * @returns {Buffer} + */ + +exports.derive = function derive(key, salt, iter, len, alg) { + var size = digest.hash(alg, Buffer.alloc(0)).length; + var blocks = Math.ceil(len / size); + var out = Buffer.allocUnsafe(len); + var buf = Buffer.allocUnsafe(salt.length + 4); + var block = Buffer.allocUnsafe(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 = digest.hmac(alg, buf, key); + mac.copy(block, 0); + for (j = 1; j < iter; j++) { + mac = digest.hmac(alg, mac, key); + for (k = 0; k < size; k++) + block[k] ^= mac[k]; + } + block.copy(out, pos); + pos += size; + } + + return out; +}; + +/** + * Execute pbkdf2 asynchronously. + * @param {Buffer} key + * @param {Buffer} salt + * @param {Number} iter + * @param {Number} len + * @param {String} alg + * @returns {Promise} + */ + +exports.deriveAsync = function deriveAsync(key, salt, iter, len, alg) { + var algo = { name: 'PBKDF2' }; + var use = ['deriveBits']; + var name = getHash(alg); + var length = len * 8; + var options, promise; + + options = { + name: 'PBKDF2', + salt: salt, + iterations: iter, + hash: name + }; + + promise = subtle.importKey('raw', key, algo, false, use); + + return promise.then(function(key) { + return subtle.deriveBits(options, key, length); + }).then(function(result) { + return Buffer.from(result); + }); +}; + +if (!subtle.deriveBits) + exports.pbkdf2Async = exports.pbkdf2; + +/* + * Helpers + */ + +function getHash(name) { + switch (name) { + case 'sha1': + return 'SHA-1'; + case 'sha256': + return 'SHA-256'; + case 'sha384': + return 'SHA-384'; + case 'sha512': + return 'SHA-512'; + default: + throw new Error('Algorithm not supported: ' + name); + } +} diff --git a/lib/crypto/pbkdf2.js b/lib/crypto/pbkdf2.js new file mode 100644 index 00000000..ac37b170 --- /dev/null +++ b/lib/crypto/pbkdf2.js @@ -0,0 +1,44 @@ +/*! + * pbkdf2.js - pbkdf2 for bcoin + * Copyright (c) 2014-2017, Christopher Jeffrey (MIT License). + * https://github.com/bcoin-org/bcoin + */ + +'use strict'; + +/** + * @module crypto.pbkdf2 + */ + +var co = require('../utils/co'); +var crypto = require('crypto'); + +/** + * Perform key derivation using PBKDF2. + * @param {Buffer} key + * @param {Buffer} salt + * @param {Number} iter + * @param {Number} len + * @param {String} alg + * @returns {Buffer} + */ + +exports.derive = function derive(key, salt, iter, len, alg) { + return crypto.pbkdf2Sync(key, salt, iter, len, alg); +}; + +/** + * Execute pbkdf2 asynchronously. + * @param {Buffer} key + * @param {Buffer} salt + * @param {Number} iter + * @param {Number} len + * @param {String} alg + * @returns {Promise} + */ + +exports.deriveAsync = function deriveAsync(key, salt, iter, len, alg) { + return new Promise(function(resolve, reject) { + crypto.pbkdf2(key, salt, iter, len, alg, co.wrap(resolve, reject)); + }); +}; diff --git a/lib/crypto/poly1305.js b/lib/crypto/poly1305.js new file mode 100644 index 00000000..940f54d8 --- /dev/null +++ b/lib/crypto/poly1305.js @@ -0,0 +1,309 @@ +/*! + * poly1305.js - poly1305 for bcoin + * Copyright (c) 2016-2017, Christopher Jeffrey (MIT License). + * https://github.com/bcoin-org/bcoin + */ + +'use strict'; + +var native = require('../utils/native').binding; + +/** + * Poly1305 (used for bip151) + * @alias module:crypto.Poly1305 + * @constructor + * @see https://github.com/floodyberry/poly1305-donna + * @see https://tools.ietf.org/html/rfc7539#section-2.5 + */ + +function Poly1305() { + if (!(this instanceof Poly1305)) + return new Poly1305(); + + this.r = new Uint16Array(10); + this.h = new Uint16Array(10); + this.pad = new Uint16Array(8); + this.fin = 0; + this.leftover = 0; + this.buffer = Buffer.allocUnsafe(16); +} + +/** + * Initialize poly1305 with a key. + * @param {Buffer} key + */ + +Poly1305.prototype.init = function init(key) { + var t0, t1, t2, t3, t4, t5, t6, t7, i; + + // r &= 0xffffffc0ffffffc0ffffffc0fffffff + t0 = key.readUInt16LE(0, true); + t1 = key.readUInt16LE(2, true); + t2 = key.readUInt16LE(4, true); + t3 = key.readUInt16LE(6, true); + t4 = key.readUInt16LE(8, true); + t5 = key.readUInt16LE(10, true); + t6 = key.readUInt16LE(12, true); + t7 = key.readUInt16LE(14, true); + + this.r[0] = t0 & 0x1fff; + this.r[1] = ((t0 >>> 13) | (t1 << 3)) & 0x1fff; + this.r[2] = ((t1 >>> 10) | (t2 << 6)) & 0x1f03; + this.r[3] = ((t2 >>> 7) | (t3 << 9)) & 0x1fff; + this.r[4] = ((t3 >>> 4) | (t4 << 12)) & 0x00ff; + this.r[5] = (t4 >>> 1) & 0x1ffe; + this.r[6] = ((t4 >>> 14) | (t5 << 2)) & 0x1fff; + this.r[7] = ((t5 >>> 11) | (t6 << 5)) & 0x1f81; + this.r[8] = ((t6 >>> 8) | (t7 << 8)) & 0x1fff; + this.r[9] = (t7 >>> 5) & 0x007f; + + // h = 0 + for (i = 0; i < 10; i++) + this.h[i] = 0; + + // save pad for later + for (i = 0; i < 8; i++) + this.pad[i] = key.readUInt16LE(16 + (2 * i), true); + + this.leftover = 0; + this.fin = 0; +}; + +/** + * Process 16 byte blocks. + * @param {Buffer} data - Blocks. + * @param {Number} bytes - Size. + * @param {Number} m - Offset pointer. + */ + +Poly1305.prototype.blocks = function blocks(data, bytes, m) { + var hibit = this.fin ? 0 : (1 << 11); // 1 << 128 + var d = new Uint32Array(10); + var i, j, t0, t1, t2, t3, t4, t5, t6, t7, c; + + while (bytes >= 16) { + // h += m[i] + t0 = data.readUInt16LE(m + 0, true); + t1 = data.readUInt16LE(m + 2, true); + t2 = data.readUInt16LE(m + 4, true); + t3 = data.readUInt16LE(m + 6, true); + t4 = data.readUInt16LE(m + 8, true); + t5 = data.readUInt16LE(m + 10, true); + t6 = data.readUInt16LE(m + 12, true); + t7 = data.readUInt16LE(m + 14, true); + + this.h[0] += t0 & 0x1fff; + this.h[1] += ((t0 >>> 13) | (t1 << 3)) & 0x1fff; + this.h[2] += ((t1 >>> 10) | (t2 << 6)) & 0x1fff; + this.h[3] += ((t2 >>> 7) | (t3 << 9)) & 0x1fff; + this.h[4] += ((t3 >>> 4) | (t4 << 12)) & 0x1fff; + this.h[5] += ((t4 >>> 1)) & 0x1fff; + this.h[6] += ((t4 >>> 14) | (t5 << 2)) & 0x1fff; + this.h[7] += ((t5 >>> 11) | (t6 << 5)) & 0x1fff; + this.h[8] += ((t6 >>> 8) | (t7 << 8)) & 0x1fff; + this.h[9] += ((t7 >>> 5)) | hibit; + + // h *= r, (partial) h %= p + for (i = 0, c = 0; i < 10; i++) { + d[i] = c; + for (j = 0; j < 10; j++) { + d[i] += this.h[j] * (j <= i + ? this.r[i - j] + : 5 * this.r[i + 10 - j]); + // Sum(h[i] * r[i] * 5) will overflow slightly + // above 6 products with an unclamped r, so + // carry at 5 + if (j === 4) { + c = d[i] >>> 13; + d[i] &= 0x1fff; + } + } + c += d[i] >>> 13; + d[i] &= 0x1fff; + } + c = (c << 2) + c; // c *= 5 + c += d[0]; + d[0] = (c & 0x1fff); + c = c >>> 13; + d[1] += c; + + for (i = 0; i < 10; i++) + this.h[i] = d[i]; + + m += 16; + bytes -= 16; + } +}; + +/** + * Update the MAC with data (will be + * processed as 16 byte blocks). + * @param {Buffer} data + */ + +Poly1305.prototype.update = function update(data) { + var bytes = data.length; + var m = 0; + var i, want; + + // handle leftover + if (this.leftover) { + want = 16 - this.leftover; + if (want > bytes) + want = bytes; + for (i = 0; i < want; i++) + this.buffer[this.leftover + i] = data[m + i]; + bytes -= want; + m += want; + this.leftover += want; + if (this.leftover < 16) + return; + this.blocks(this.buffer, 16, 0); + this.leftover = 0; + } + + // process full blocks + if (bytes >= 16) { + want = bytes & ~(16 - 1); + this.blocks(data, want, m); + m += want; + bytes -= want; + } + + // store leftover + if (bytes) { + for (i = 0; i < bytes; i++) + this.buffer[this.leftover + i] = data[m + i]; + this.leftover += bytes; + } +}; + +/** + * Finalize and return a 16-byte MAC. + * @returns {Buffer} + */ + +Poly1305.prototype.finish = function finish() { + var mac = Buffer.allocUnsafe(16); + var g = new Uint16Array(10); + var c, mask, f, i; + + // process the remaining block + if (this.leftover) { + i = this.leftover; + this.buffer[i++] = 1; + for (; i < 16; i++) + this.buffer[i] = 0; + this.fin = 1; + this.blocks(this.buffer, 16, 0); + } + + // fully carry h + c = this.h[1] >>> 13; + this.h[1] &= 0x1fff; + for (i = 2; i < 10; i++) { + this.h[i] += c; + c = this.h[i] >>> 13; + this.h[i] &= 0x1fff; + } + this.h[0] += c * 5; + c = this.h[0] >>> 13; + this.h[0] &= 0x1fff; + this.h[1] += c; + c = this.h[1] >>> 13; + this.h[1] &= 0x1fff; + this.h[2] += c; + + // compute h + -p + g[0] = this.h[0] + 5; + c = g[0] >>> 13; + g[0] &= 0x1fff; + for (i = 1; i < 10; i++) { + g[i] = this.h[i] + c; + c = g[i] >>> 13; + g[i] &= 0x1fff; + } + + // select h if h < p, or h + -p if h >= p + mask = (c ^ 1) - 1; + for (i = 0; i < 10; i++) + g[i] &= mask; + mask = ~mask; + for (i = 0; i < 10; i++) + this.h[i] = (this.h[i] & mask) | g[i]; + + // h = h % (2^128) + this.h[0] = ((this.h[0]) | (this.h[1] << 13)) & 0xffff; + this.h[1] = ((this.h[1] >>> 3) | (this.h[2] << 10)) & 0xffff; + this.h[2] = ((this.h[2] >>> 6) | (this.h[3] << 7)) & 0xffff; + this.h[3] = ((this.h[3] >>> 9) | (this.h[4] << 4)) & 0xffff; + this.h[4] = ((this.h[4] >>> 12) + | (this.h[5] << 1) | (this.h[6] << 14)) & 0xffff; + this.h[5] = ((this.h[6] >>> 2) | (this.h[7] << 11)) & 0xffff; + this.h[6] = ((this.h[7] >>> 5) | (this.h[8] << 8)) & 0xffff; + this.h[7] = ((this.h[8] >>> 8) | (this.h[9] << 5)) & 0xffff; + + // mac = (h + pad) % (2^128) + f = this.h[0] + this.pad[0]; + this.h[0] = f; + for (i = 1; i < 8; i++) { + f = this.h[i] + this.pad[i] + (f >>> 16); + this.h[i] = f; + } + + for (i = 0; i < 8; i++) + mac.writeUInt16LE(this.h[i], i * 2, true); + + // zero out the state + for (i = 0; i < 10; i++) + this.h[i] = 0; + for (i = 0; i < 10; i++) + this.r[i] = 0; + for (i = 0; i < 8; i++) + this.pad[i] = 0; + + return mac; +}; + +/** + * Return a MAC for a message and key. + * @param {Buffer} msg + * @param {Buffer} key + * @returns {Buffer} MAC + */ + +Poly1305.auth = function auth(msg, key) { + var poly = new Poly1305(); + poly.init(key); + poly.update(msg); + return poly.finish(); +}; + +/** + * Compare two MACs in constant time. + * @param {Buffer} mac1 + * @param {Buffer} mac2 + * @returns {Boolean} + */ + +Poly1305.verify = function verify(mac1, mac2) { + var dif = 0; + var i; + + // Compare in constant time. + for (i = 0; i < 16; i++) + dif |= mac1[i] ^ mac2[i]; + + dif = (dif - 1) >>> 31; + + return (dif & 1) !== 0; +}; + +if (native) + Poly1305 = native.Poly1305; + +/* + * Expose + */ + +module.exports = Poly1305; diff --git a/lib/crypto/random-browser.js b/lib/crypto/random-browser.js new file mode 100644 index 00000000..7c7b9086 --- /dev/null +++ b/lib/crypto/random-browser.js @@ -0,0 +1,64 @@ +/*! + * random-browser.js - randomness for bcoin + * Copyright (c) 2014-2017, Christopher Jeffrey (MIT License). + * https://github.com/bcoin-org/bcoin + */ + +'use strict'; + +/** + * @module crypto.random-browser + * @ignore + */ + +var crypto = global.crypto || global.msCrypto || {}; + +/** + * Generate some random bytes. + * @param {Number} size + * @returns {Buffer} + */ + +exports.randomBytes = function randomBytes(n) { + var data = new Uint8Array(n); + crypto.getRandomValues(data); + return Buffer.from(data.buffer); +}; + +if (!crypto.getRandomValues) { + // Out of luck here. Use bad randomness for now. + exports.randomBytes = function randomBytes(n) { + var data = Buffer.allocUnsafe(n); + var i; + + for (i = 0; i < data.length; i++) + data[i] = Math.floor(Math.random() * 256); + + return data; + }; +} + +/** + * Generate a random uint32. + * Probably more cryptographically sound than + * `Math.random()`. + * @returns {Number} + */ + +exports.randomInt = function randomInt() { + return exports.randomBytes(4).readUInt32LE(0, true); +}; + +/** + * Generate a random number within a range. + * Probably more cryptographically sound than + * `Math.random()`. + * @param {Number} min - Inclusive. + * @param {Number} max - Exclusive. + * @returns {Number} + */ + +exports.randomRange = function randomRange(min, max) { + var num = exports.randomInt(); + return Math.floor((num / 0x100000000) * (max - min) + min); +}; diff --git a/lib/crypto/random.js b/lib/crypto/random.js new file mode 100644 index 00000000..7c044d79 --- /dev/null +++ b/lib/crypto/random.js @@ -0,0 +1,44 @@ +/*! + * random.js - randomness for bcoin + * Copyright (c) 2014-2017, Christopher Jeffrey (MIT License). + * https://github.com/bcoin-org/bcoin + */ + +'use strict'; + +/** + * @module crypto.random + */ + +var crypto = require('crypto'); + +/* + * Misc + */ + +exports.randomBytes = crypto.randomBytes; + +/** + * Generate a random uint32. + * Probably more cryptographically sound than + * `Math.random()`. + * @returns {Number} + */ + +exports.randomInt = function randomInt() { + return exports.randomBytes(4).readUInt32LE(0, true); +}; + +/** + * Generate a random number within a range. + * Probably more cryptographically sound than + * `Math.random()`. + * @param {Number} min - Inclusive. + * @param {Number} max - Exclusive. + * @returns {Number} + */ + +exports.randomRange = function randomRange(min, max) { + var num = exports.randomInt(); + return Math.floor((num / 0x100000000) * (max - min) + min); +}; diff --git a/lib/crypto/rsa-browser.js b/lib/crypto/rsa-browser.js index 855b213f..d75269c1 100644 --- a/lib/crypto/rsa-browser.js +++ b/lib/crypto/rsa-browser.js @@ -9,7 +9,8 @@ var assert = require('assert'); var BN = require('./bn'); var ASN1 = require('../utils/asn1'); -var backend = require('./backend'); +var digest = require('./digest'); +var ccmp = require('./ccmp'); /** * @exports crypto/rsa @@ -55,7 +56,7 @@ rsa.verify = function verify(alg, msg, sig, key) { if (!prefix) throw new Error('Unknown PKCS prefix.'); - hash = backend.hash(alg, msg); + hash = digest.hash(alg, msg); len = prefix.length + hash.length; pub = ASN1.parseRSAPublic(key); @@ -71,8 +72,8 @@ rsa.verify = function verify(alg, msg, sig, key) { 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 &= ccmp(em.slice(k - hash.length, k), hash); + ok &= ccmp(em.slice(k - len, k - hash.length), prefix); ok &= ceq(em[k - len - 1], 0x00); for (i = 2; i < k - len - 1; i++) @@ -101,7 +102,7 @@ rsa.sign = function sign(alg, msg, key) { if (!prefix) throw new Error('Unknown PKCS prefix.'); - hash = backend.hash(alg, msg); + hash = digest.hash(alg, msg); len = prefix.length + hash.length; priv = ASN1.parseRSAPrivate(key); diff --git a/lib/crypto/schnorr.js b/lib/crypto/schnorr.js index aeace3c0..b72f45b3 100644 --- a/lib/crypto/schnorr.js +++ b/lib/crypto/schnorr.js @@ -11,7 +11,7 @@ var elliptic = require('elliptic'); var Signature = require('elliptic/lib/elliptic/ec/signature'); var BN = require('./bn'); var HmacDRBG = require('./hmac-drbg'); -var sha256 = require('./backend').sha256; +var sha256 = require('./digest').sha256; var curve = elliptic.ec('secp256k1').curve; var POOL64 = Buffer.allocUnsafe(64); diff --git a/lib/crypto/scrypt.js b/lib/crypto/scrypt.js index d8935d69..e2112a2f 100644 --- a/lib/crypto/scrypt.js +++ b/lib/crypto/scrypt.js @@ -35,19 +35,17 @@ /** * @module crypto/scrypt - * @ignore */ var co = require('../utils/co'); -var backend = require('./backend'); +var pbkdf2 = require('./pbkdf2'); var native = require('../utils/native').binding; -var U32Array = typeof Uint32Array === 'function' ? Uint32Array : Array; /** * Javascript scrypt implementation. Scrypt is * used in bip38. Bcoin doesn't support bip38 * yet, but here it is, just in case. - * @alias module:crypto/scrypt.scrypt + * @alias module:crypto/scrypt.derive * @param {Buffer} passwd * @param {Buffer} salt * @param {Number} N @@ -57,7 +55,7 @@ var U32Array = typeof Uint32Array === 'function' ? Uint32Array : Array; * @returns {Buffer} */ -function scrypt(passwd, salt, N, r, p, len) { +function derive(passwd, salt, N, r, p, len) { var i, B, V, XY; if (r * p >= (1 << 30)) @@ -72,20 +70,63 @@ function scrypt(passwd, salt, N, r, p, len) { XY = Buffer.allocUnsafe(256 * r); V = Buffer.allocUnsafe(128 * r * N); - B = backend.pbkdf2(passwd, salt, 1, p * 128 * r, 'sha256'); + B = pbkdf2.derive(passwd, salt, 1, p * 128 * r, 'sha256'); for (i = 0; i < p; i++) smix(B, i * 128 * r, r, N, V, XY); - return backend.pbkdf2(passwd, B, 1, len, 'sha256'); + return pbkdf2.derive(passwd, B, 1, len, 'sha256'); } if (native) - scrypt = native.scrypt; + derive = native.scrypt; + +/** + * Asynchronous scrypt implementation. + * @alias module:crypto/scrypt.deriveAsync + * @function + * @param {Buffer} passwd + * @param {Buffer} salt + * @param {Number} N + * @param {Number} r + * @param {Number} p + * @param {Number} len + * @returns {Promise} + */ + +async function deriveAsync(passwd, salt, N, r, p, len) { + var i, B, V, XY; + + if (r * p >= (1 << 30)) + throw new Error('EFBIG'); + + if ((N & (N - 1)) !== 0 || N === 0) + throw new Error('EINVAL'); + + if (N > 0xffffffff) + throw new Error('EINVAL'); + + XY = Buffer.allocUnsafe(256 * r); + V = Buffer.allocUnsafe(128 * r * N); + + B = await pbkdf2.deriveAsync(passwd, salt, 1, p * 128 * r, 'sha256'); + + for (i = 0; i < p; i++) + await smixAsync(B, i * 128 * r, r, N, V, XY); + + return await pbkdf2.deriveAsync(passwd, B, 1, len, 'sha256'); +} + +if (native) + deriveAsync = native.scryptAsync; + +/* + * Helpers + */ function salsa20_8(B) { - var B32 = new U32Array(16); - var x = new U32Array(16); + var B32 = new Uint32Array(16); + var x = new Uint32Array(16); var i; for (i = 0; i < 16; i++) @@ -192,54 +233,6 @@ function smix(B, Bo, r, N, V, XY) { blkcpy(B, X, Bo, 0, 128 * r); } -function blkcpy(dest, src, s1, s2, len) { - src.copy(dest, s1, s2, s2 + len); -} - -function blkxor(dest, src, s1, s2, len) { - for (var i = 0; i < len; i++) - dest[s1 + i] ^= src[s2 + i]; -} - -/** - * Asynchronous scrypt implementation. - * @alias module:crypto/scrypt.scryptAsync - * @function - * @param {Buffer} passwd - * @param {Buffer} salt - * @param {Number} N - * @param {Number} r - * @param {Number} p - * @param {Number} len - * @returns {Promise} - */ - -async function scryptAsync(passwd, salt, N, r, p, len) { - var i, B, V, XY; - - if (r * p >= (1 << 30)) - throw new Error('EFBIG'); - - if ((N & (N - 1)) !== 0 || N === 0) - throw new Error('EINVAL'); - - if (N > 0xffffffff) - throw new Error('EINVAL'); - - XY = Buffer.allocUnsafe(256 * r); - V = Buffer.allocUnsafe(128 * r * N); - - B = await backend.pbkdf2Async(passwd, salt, 1, p * 128 * r, 'sha256'); - - for (i = 0; i < p; i++) - await smixAsync(B, i * 128 * r, r, N, V, XY); - - return await backend.pbkdf2Async(passwd, B, 1, len, 'sha256'); -} - -if (native) - scryptAsync = native.scryptAsync; - async function smixAsync(B, Bo, r, N, V, XY) { var X = XY; var Y = XY; @@ -264,12 +257,18 @@ async function smixAsync(B, Bo, r, N, V, XY) { blkcpy(B, X, Bo, 0, 128 * r); } +function blkcpy(dest, src, s1, s2, len) { + src.copy(dest, s1, s2, s2 + len); +} + +function blkxor(dest, src, s1, s2, len) { + for (var i = 0; i < len; i++) + dest[s1 + i] ^= src[s2 + i]; +} + /* * Expose */ -exports = scrypt; -exports.scrypt = scrypt; -exports.scryptAsync = scryptAsync; - -module.exports = exports; +exports.derive = derive; +exports.deriveAsync = deriveAsync; diff --git a/lib/crypto/secp256k1-native.js b/lib/crypto/secp256k1-native.js index f14712e0..a7a0b0a1 100644 --- a/lib/crypto/secp256k1-native.js +++ b/lib/crypto/secp256k1-native.js @@ -8,7 +8,7 @@ 'use strict'; var assert = require('assert'); -var backend = require('./backend'); +var random = require('./random'); var secp256k1 = require('secp256k1'); /** @@ -47,7 +47,7 @@ ec.generatePrivateKey = function generatePrivateKey() { var priv; do { - priv = backend.randomBytes(32); + priv = random.randomBytes(32); } while (!secp256k1.privateKeyVerify(priv)); return priv; diff --git a/lib/hd/index.js b/lib/hd/index.js index 02675b8e..17c832b6 100644 --- a/lib/hd/index.js +++ b/lib/hd/index.js @@ -1,3 +1,9 @@ +/*! + * hd/index.js - hd keys for bcoin + * Copyright (c) 2014-2016, Christopher Jeffrey (MIT License). + * https://github.com/bcoin-org/bcoin + */ + 'use strict'; module.exports = require('./hd'); diff --git a/lib/hd/mnemonic.js b/lib/hd/mnemonic.js index 02cb14d4..0e933311 100644 --- a/lib/hd/mnemonic.js +++ b/lib/hd/mnemonic.js @@ -8,7 +8,10 @@ var assert = require('assert'); var util = require('../utils/util'); -var crypto = require('../crypto/crypto'); +var digest = require('../crypto/digest'); +var cleanse = require('../crypto/cleanse'); +var random = require('../crypto/random'); +var pbkdf2 = require('../crypto/pbkdf2'); var StaticWriter = require('../utils/staticwriter'); var BufferReader = require('../utils/reader'); var encoding = require('../utils/encoding'); @@ -123,7 +126,7 @@ Mnemonic.prototype.destroy = function destroy() { this.bits = common.MIN_ENTROPY; this.language = 'english'; if (this.entropy) { - crypto.cleanse(this.entropy); + cleanse(this.entropy); this.entropy = null; } this.phrase = null; @@ -147,7 +150,7 @@ Mnemonic.prototype.toSeed = function toSeed(passphrase) { phrase = nfkd(this.getPhrase()); passwd = nfkd('mnemonic' + passphrase); - return crypto.pbkdf2( + return pbkdf2.derive( Buffer.from(phrase, 'utf8'), Buffer.from(passwd, 'utf8'), 2048, 64, 'sha512'); @@ -160,7 +163,7 @@ Mnemonic.prototype.toSeed = function toSeed(passphrase) { Mnemonic.prototype.getEntropy = function getEntropy() { if (!this.entropy) - this.entropy = crypto.randomBytes(this.bits / 8); + this.entropy = random.randomBytes(this.bits / 8); assert(this.bits / 8 === this.entropy.length); @@ -194,7 +197,7 @@ Mnemonic.prototype.getPhrase = function getPhrase() { // the checksum bits. entropy = Buffer.allocUnsafe(Math.ceil(bits / 8)); ent.copy(entropy, 0); - crypto.sha256(ent).copy(entropy, ent.length); + digest.sha256(ent).copy(entropy, ent.length); // Build the mnemonic by reading // 11 bit indexes from the entropy. @@ -268,7 +271,7 @@ Mnemonic.prototype.fromPhrase = function fromPhrase(phrase) { entropy = ent.slice(0, ent.length - cbytes); ent = ent.slice(ent.length - cbytes); - chk = crypto.sha256(entropy); + chk = digest.sha256(entropy); for (i = 0; i < cbits; i++) { bit = i % 8; diff --git a/lib/hd/private.js b/lib/hd/private.js index 572589d8..a8f0dd19 100644 --- a/lib/hd/private.js +++ b/lib/hd/private.js @@ -8,7 +8,9 @@ var assert = require('assert'); var util = require('../utils/util'); -var crypto = require('../crypto/crypto'); +var digest = require('../crypto/digest'); +var cleanse = require('../crypto/cleanse'); +var random = require('../crypto/random'); var secp256k1 = require('../crypto/secp256k1'); var Network = require('../protocol/network'); var StaticWriter = require('../utils/staticwriter'); @@ -149,13 +151,13 @@ HDPrivateKey.prototype.destroy = function destroy(pub) { this.depth = 0; this.childIndex = 0; - crypto.cleanse(this.parentFingerPrint); - crypto.cleanse(this.chainCode); - crypto.cleanse(this.privateKey); - crypto.cleanse(this.publicKey); + cleanse(this.parentFingerPrint); + cleanse(this.chainCode); + cleanse(this.privateKey); + cleanse(this.publicKey); if (this.fingerPrint) { - crypto.cleanse(this.fingerPrint); + cleanse(this.fingerPrint); this.fingerPrint = null; } @@ -208,7 +210,7 @@ HDPrivateKey.prototype.derive = function derive(index, hardened) { data = bw.render(); - hash = crypto.hmac('sha512', data, this.chainCode); + hash = digest.hmac('sha512', data, this.chainCode); left = hash.slice(0, 32); right = hash.slice(32, 64); @@ -219,7 +221,7 @@ HDPrivateKey.prototype.derive = function derive(index, hardened) { } if (!this.fingerPrint) - this.fingerPrint = crypto.hash160(this.publicKey).slice(0, 4); + this.fingerPrint = digest.hash160(this.publicKey).slice(0, 4); child = new HDPrivateKey(); child.network = this.network; @@ -465,7 +467,7 @@ HDPrivateKey.prototype.fromSeed = function fromSeed(seed, network) { throw new Error('Entropy not in range.'); } - hash = crypto.hmac('sha512', seed, common.SEED_SALT); + hash = digest.hmac('sha512', seed, common.SEED_SALT); left = hash.slice(0, 32); right = hash.slice(32, 64); @@ -583,7 +585,7 @@ HDPrivateKey.fromKey = function fromKey(key, entropy, network) { HDPrivateKey.generate = function generate(network) { var key = secp256k1.generatePrivateKey(); - var entropy = crypto.randomBytes(32); + var entropy = random.randomBytes(32); return HDPrivateKey.fromKey(key, entropy, network); }; diff --git a/lib/hd/public.js b/lib/hd/public.js index 6396a367..f5bdbac3 100644 --- a/lib/hd/public.js +++ b/lib/hd/public.js @@ -8,7 +8,8 @@ var assert = require('assert'); var util = require('../utils/util'); -var crypto = require('../crypto/crypto'); +var digest = require('../crypto/digest'); +var cleanse = require('../crypto/cleanse'); var secp256k1 = require('../crypto/secp256k1'); var Network = require('../protocol/network'); var StaticWriter = require('../utils/staticwriter'); @@ -129,12 +130,12 @@ HDPublicKey.prototype.destroy = function destroy() { this.depth = 0; this.childIndex = 0; - crypto.cleanse(this.parentFingerPrint); - crypto.cleanse(this.chainCode); - crypto.cleanse(this.publicKey); + cleanse(this.parentFingerPrint); + cleanse(this.chainCode); + cleanse(this.publicKey); if (this.fingerPrint) { - crypto.cleanse(this.fingerPrint); + cleanse(this.fingerPrint); this.fingerPrint = null; } @@ -175,7 +176,7 @@ HDPublicKey.prototype.derive = function derive(index, hardened) { bw.writeU32BE(index); data = bw.render(); - hash = crypto.hmac('sha512', data, this.chainCode); + hash = digest.hmac('sha512', data, this.chainCode); left = hash.slice(0, 32); right = hash.slice(32, 64); @@ -186,7 +187,7 @@ HDPublicKey.prototype.derive = function derive(index, hardened) { } if (!this.fingerPrint) - this.fingerPrint = crypto.hash160(this.publicKey).slice(0, 4); + this.fingerPrint = digest.hash160(this.publicKey).slice(0, 4); child = new HDPublicKey(); child.network = this.network; diff --git a/lib/http/base.js b/lib/http/base.js index 5991d287..5ceb050e 100644 --- a/lib/http/base.js +++ b/lib/http/base.js @@ -19,7 +19,8 @@ var co = require('../utils/co'); var Validator = require('../utils/validator'); var List = require('../utils/list'); var fs = require('../utils/fs'); -var crypto = require('../crypto/crypto'); +var digest = require('../crypto/digest'); +var ccmp = require('../crypto/ccmp'); var ListItem = List.Item; /** @@ -198,14 +199,14 @@ HTTPBase.prototype.basicAuth = function basicAuth(options) { if (typeof user === 'string') user = Buffer.from(user, 'utf8'); assert(Buffer.isBuffer(user)); - user = crypto.hash256(user); + user = digest.hash256(user); } if (typeof pass === 'string') pass = Buffer.from(pass, 'utf8'); assert(Buffer.isBuffer(pass)); - pass = crypto.hash256(pass); + pass = digest.hash256(pass); if (!realm) realm = 'server'; @@ -220,7 +221,7 @@ HTTPBase.prototype.basicAuth = function basicAuth(options) { return async function(req, res) { var auth = req.headers['authorization']; - var parts, username, password, digest; + var parts, username, password, hash; if (!auth) return fail(res); @@ -240,17 +241,17 @@ HTTPBase.prototype.basicAuth = function basicAuth(options) { password = parts.join(':'); if (user) { - digest = Buffer.from(username, 'utf8'); - digest = crypto.hash256(digest); + hash = Buffer.from(username, 'utf8'); + hash = digest.hash256(hash); - if (!crypto.ccmp(digest, user)) + if (!ccmp(hash, user)) return fail(res); } - digest = Buffer.from(password, 'utf8'); - digest = crypto.hash256(digest); + hash = Buffer.from(password, 'utf8'); + hash = digest.hash256(hash); - if (!crypto.ccmp(digest, pass)) + if (!ccmp(hash, pass)) return fail(res); req.username = username; diff --git a/lib/http/rpc.js b/lib/http/rpc.js index 3817aa23..594954e9 100644 --- a/lib/http/rpc.js +++ b/lib/http/rpc.js @@ -8,7 +8,8 @@ var util = require('../utils/util'); var co = require('../utils/co'); -var crypto = require('../crypto/crypto'); +var digest = require('../crypto/digest'); +var ccmp = require('../crypto/ccmp'); var assert = require('assert'); var common = require('../blockchain/common'); var secp256k1 = require('../crypto/secp256k1'); @@ -2065,16 +2066,16 @@ RPC.prototype.verifyMessage = async function verifyMessage(args, help) { addr = parseAddress(b58, this.network); msg = Buffer.from(MAGIC_STRING + msg, 'utf8'); - msg = crypto.hash256(msg); + msg = digest.hash256(msg); key = secp256k1.recover(msg, sig, 0, true); if (!key) return false; - key = crypto.hash160(key); + key = digest.hash160(key); - return crypto.ccmp(key, addr.hash); + return ccmp(key, addr.hash); }; RPC.prototype.signMessageWithPrivkey = async function signMessageWithPrivkey(args, help) { @@ -2090,7 +2091,7 @@ RPC.prototype.signMessageWithPrivkey = async function signMessageWithPrivkey(arg key = parseSecret(key, this.network); msg = Buffer.from(MAGIC_STRING + msg, 'utf8'); - msg = crypto.hash256(msg); + msg = digest.hash256(msg); sig = key.sign(msg); diff --git a/lib/http/server.js b/lib/http/server.js index b1257d3f..68b85b43 100644 --- a/lib/http/server.js +++ b/lib/http/server.js @@ -15,7 +15,9 @@ var Amount = require('../btc/amount'); var Bloom = require('../utils/bloom'); var TX = require('../primitives/tx'); var Outpoint = require('../primitives/outpoint'); -var crypto = require('../crypto/crypto'); +var digest = require('../crypto/digest'); +var random = require('../crypto/random'); +var ccmp = require('../crypto/ccmp'); var Network = require('../protocol/network'); var Validator = require('../utils/validator'); var pkg = require('../pkg'); @@ -389,7 +391,7 @@ HTTPServer.prototype.handleSocket = function handleSocket(socket) { throw new Error('Already authed.'); if (!this.options.noAuth) { - if (!crypto.ccmp(hash256(key), hash)) + if (!ccmp(hash256(key), hash)) throw new Error('Bad key.'); } @@ -739,7 +741,7 @@ function HTTPOptions(options) { this.network = Network.primary; this.logger = null; this.node = null; - this.apiKey = base58.encode(crypto.randomBytes(20)); + this.apiKey = base58.encode(random.randomBytes(20)); this.apiHash = hash256(this.apiKey); this.noAuth = false; @@ -854,7 +856,7 @@ function hash256(data) { if (data.length > 200) return Buffer.alloc(0); - return crypto.hash256(Buffer.from(data, 'utf8')); + return digest.hash256(Buffer.from(data, 'utf8')); } function enforce(value, msg) { diff --git a/lib/mempool/mempool.js b/lib/mempool/mempool.js index 1bf8c242..59fbf0b4 100644 --- a/lib/mempool/mempool.js +++ b/lib/mempool/mempool.js @@ -11,7 +11,7 @@ var AsyncObject = require('../utils/asyncobject'); var common = require('../blockchain/common'); var policy = require('../protocol/policy'); var util = require('../utils/util'); -var crypto = require('../crypto/crypto'); +var random = require('../crypto/random'); var errors = require('../protocol/errors'); var Bloom = require('../utils/bloom'); var Address = require('../primitives/address'); @@ -1667,7 +1667,7 @@ Mempool.prototype.limitOrphans = function limitOrphans() { if (this.totalOrphans < this.options.maxOrphans) return false; - index = crypto.randomRange(0, hashes.length); + index = random.randomRange(0, hashes.length); hash = hashes[index]; this.logger.debug('Removing orphan %s from mempool.', util.revHex(hash)); diff --git a/lib/mining/mine.js b/lib/mining/mine.js index 03af95fd..287c73e0 100644 --- a/lib/mining/mine.js +++ b/lib/mining/mine.js @@ -7,7 +7,7 @@ 'use strict'; var assert = require('assert'); -var crypto = require('../crypto/crypto'); +var digest = require('../crypto/digest'); /** * Hash until the nonce overflows. @@ -27,7 +27,7 @@ function mine(data, target, min, max) { // The heart and soul of the miner: match the target. while (nonce <= max) { // Hash and test against the next target. - if (rcmp(crypto.hash256(data), target) <= 0) + if (rcmp(digest.hash256(data), target) <= 0) return nonce; // Increment the nonce to get a different hash. diff --git a/lib/mining/template.js b/lib/mining/template.js index f5507df5..0425c81c 100644 --- a/lib/mining/template.js +++ b/lib/mining/template.js @@ -9,7 +9,8 @@ var assert = require('assert'); var util = require('../utils/util'); -var crypto = require('../crypto/crypto'); +var digest = require('../crypto/digest'); +var merkle = require('../crypto/merkle'); var BN = require('../crypto/bn'); var StaticWriter = require('../utils/staticwriter'); var Address = require('../primitives/address'); @@ -181,13 +182,13 @@ BlockTemplate.prototype.getWitnessHash = function getWitnessHash() { leaves.push(item.tx.witnessHash()); } - root = crypto.createMerkleRoot(leaves); + root = merkle.createRoot(leaves); assert(!root.malleated); data = util.concat(root.hash, nonce); - return crypto.hash256(data); + return digest.hash256(data); }; /** @@ -389,7 +390,7 @@ BlockTemplate.prototype.getRawCoinbase = function getRawCoinbase(nonce1, nonce2) BlockTemplate.prototype.getRoot = function getRoot(nonce1, nonce2) { var raw = this.getRawCoinbase(nonce1, nonce2); - var hash = crypto.hash256(raw); + var hash = digest.hash256(raw); return this.tree.withFirst(hash); }; @@ -426,7 +427,7 @@ BlockTemplate.prototype.getHeader = function getHeader(root, ts, nonce) { BlockTemplate.prototype.getProof = function getProof(nonce1, nonce2, ts, nonce) { var root = this.getRoot(nonce1, nonce2); var data = this.getHeader(root, ts, nonce); - var hash = crypto.hash256(data); + var hash = digest.hash256(data); return new BlockProof(hash, root, nonce1, nonce2, ts, nonce); }; @@ -705,7 +706,7 @@ MerkleTree.prototype.withFirst = function withFirst(hash) { for (i = 0; i < this.steps.length; i++) { step = this.steps[i]; data = util.concat(hash, step); - hash = crypto.hash256(data); + hash = digest.hash256(data); } return hash; @@ -773,7 +774,7 @@ MerkleTree.prototype.fromLeaves = function fromLeaves(leaves) { for (i = 2; i < len; i += 2) { data = util.concat(leaves[i], leaves[i + 1]); - hash = crypto.hash256(data); + hash = digest.hash256(data); hashes.push(hash); } diff --git a/lib/net/bip150.js b/lib/net/bip150.js index e652ba02..0c67cf9f 100644 --- a/lib/net/bip150.js +++ b/lib/net/bip150.js @@ -13,7 +13,9 @@ var path = require('path'); var EventEmitter = require('events').EventEmitter; var util = require('../utils/util'); var co = require('../utils/co'); -var crypto = require('../crypto/crypto'); +var digest = require('../crypto/digest'); +var random = require('../crypto/random'); +var ccmp = require('../crypto/ccmp'); var packets = require('./packets'); var secp256k1 = require('../crypto/secp256k1'); var StaticWriter = require('../utils/staticwriter'); @@ -131,7 +133,7 @@ BIP150.prototype.challenge = function challenge(hash) { msg = this.hash(this.input.sid, type, this.publicKey); - if (!crypto.ccmp(hash, msg)) + if (!ccmp(hash, msg)) return encoding.ZERO_SIG64; if (this.isAuthed()) { @@ -165,7 +167,7 @@ BIP150.prototype.reply = function reply(data) { throw new Error('Auth failure.'); if (!this.peerIdentity) - return crypto.randomBytes(32); + return random.randomBytes(32); sig = secp256k1.toDER(data); msg = this.hash(this.output.sid, type, this.peerIdentity); @@ -173,7 +175,7 @@ BIP150.prototype.reply = function reply(data) { result = secp256k1.verify(msg, sig, this.peerIdentity); if (!result) - return crypto.randomBytes(32); + return random.randomBytes(32); if (this.isAuthed()) { this.auth = true; @@ -257,7 +259,7 @@ BIP150.prototype.rekey = function rekey(sid, key, req, res) { key.copy(seed, 32); req.copy(seed, 64); res.copy(seed, 97); - return crypto.hash256(seed); + return digest.hash256(seed); }; /** @@ -301,7 +303,7 @@ BIP150.prototype.hash = function hash(sid, ch, key) { sid.copy(data, 0); data[32] = ch.charCodeAt(0); key.copy(data, 33); - return crypto.hash256(data); + return digest.hash256(data); }; /** @@ -325,7 +327,7 @@ BIP150.prototype.findAuthorized = function findAuthorized(hash) { // XXX Do we really need a constant // time compare here? Do it just to // be safe I guess. - if (crypto.ccmp(msg, hash)) + if (ccmp(msg, hash)) return key; } }; @@ -454,7 +456,7 @@ BIP150.address = function address(key) { var bw = new StaticWriter(27); bw.writeU8(0x0f); bw.writeU16BE(0xff01); - bw.writeBytes(crypto.hash160(key)); + bw.writeBytes(digest.hash160(key)); bw.writeChecksum(); return base58.encode(bw.render()); }; diff --git a/lib/net/bip151.js b/lib/net/bip151.js index 84f21c65..b0f91206 100644 --- a/lib/net/bip151.js +++ b/lib/net/bip151.js @@ -12,14 +12,17 @@ 'use strict'; +var assert = require('assert'); var EventEmitter = require('events').EventEmitter; var util = require('../utils/util'); var co = require('../utils/co'); -var crypto = require('../crypto/crypto'); -var assert = require('assert'); -var chachapoly = require('../crypto/chachapoly'); -var packets = require('./packets'); +var digest = require('../crypto/digest'); +var ChaCha20 = require('../crypto/chacha20'); +var Poly1305 = require('../crypto/poly1305'); +var AEAD = require('../crypto/aead'); +var hkdf = require('../crypto/hkdf'); var secp256k1 = require('../crypto/secp256k1'); +var packets = require('./packets'); var StaticWriter = require('../utils/staticwriter'); var BufferReader = require('../utils/reader'); var encoding = require('../utils/encoding'); @@ -74,8 +77,8 @@ function BIP151Stream(cipher) { this.cipher = cipher; } - this.chacha = new chachapoly.ChaCha20(); - this.aead = new chachapoly.AEAD(); + this.chacha = new ChaCha20(); + this.aead = new AEAD(); this.tag = null; this.seq = 0; this.iv = Buffer.allocUnsafe(8); @@ -100,10 +103,10 @@ BIP151Stream.prototype.init = function init(publicKey) { bw.writeBytes(this.secret); bw.writeU8(this.cipher); - this.prk = crypto.hkdfExtract(bw.render(), HKDF_SALT, 'sha256'); - this.k1 = crypto.hkdfExpand(this.prk, INFO_KEY1, 32, 'sha256'); - this.k2 = crypto.hkdfExpand(this.prk, INFO_KEY2, 32, 'sha256'); - this.sid = crypto.hkdfExpand(this.prk, INFO_SID, 32, 'sha256'); + this.prk = hkdf.extract(bw.render(), HKDF_SALT, 'sha256'); + this.k1 = hkdf.expand(this.prk, INFO_KEY1, 32, 'sha256'); + this.k2 = hkdf.expand(this.prk, INFO_KEY2, 32, 'sha256'); + this.sid = hkdf.expand(this.prk, INFO_SID, 32, 'sha256'); this.seq = 0; @@ -153,10 +156,10 @@ BIP151Stream.prototype.rekey = function rekey(k1, k2) { this.sid.copy(seed, 0); this.k1.copy(seed, 32); - this.k1 = crypto.hash256(seed); + this.k1 = digest.hash256(seed); this.k2.copy(seed, 32); - this.k2 = crypto.hash256(seed); + this.k2 = digest.hash256(seed); } else { this.k1 = k1; this.k2 = k2; @@ -279,7 +282,7 @@ BIP151Stream.prototype.finish = function finish() { */ BIP151Stream.prototype.verify = function verify(tag) { - return chachapoly.Poly1305.verify(this.tag, tag); + return Poly1305.verify(this.tag, tag); }; /** diff --git a/lib/net/bip152.js b/lib/net/bip152.js index b9a8de27..5b672b7a 100644 --- a/lib/net/bip152.js +++ b/lib/net/bip152.js @@ -17,7 +17,7 @@ var BufferWriter = require('../utils/writer'); var StaticWriter = require('../utils/staticwriter'); var encoding = require('../utils/encoding'); var consensus = require('../protocol/consensus'); -var crypto = require('../crypto/crypto'); +var digest = require('../crypto/digest'); var siphash256 = require('../crypto/siphash').siphash256; var AbstractBlock = require('../primitives/abstractblock'); var TX = require('../primitives/tx'); @@ -412,7 +412,7 @@ CompactBlock.prototype.hasIndex = function hasIndex(index) { CompactBlock.prototype.initKey = function initKey() { var data = util.concat(this.abbr(), this.keyNonce); - var hash = crypto.sha256(data); + var hash = digest.sha256(data); this.sipKey = hash.slice(0, 16); }; diff --git a/lib/net/framer.js b/lib/net/framer.js index e042bfc1..ab88f076 100644 --- a/lib/net/framer.js +++ b/lib/net/framer.js @@ -9,7 +9,7 @@ var assert = require('assert'); var Network = require('../protocol/network'); -var crypto = require('../crypto/crypto'); +var digest = require('../crypto/digest'); /** * Protocol packet framer @@ -55,7 +55,7 @@ Framer.prototype.packet = function packet(cmd, payload, checksum) { packet.writeUInt32LE(payload.length, 16, true); if (!checksum) - checksum = crypto.hash256(payload); + checksum = digest.hash256(payload); // Checksum checksum.copy(packet, 20, 0, 4); diff --git a/lib/net/parser.js b/lib/net/parser.js index d8f6034c..2f6a5337 100644 --- a/lib/net/parser.js +++ b/lib/net/parser.js @@ -11,7 +11,7 @@ var assert = require('assert'); var EventEmitter = require('events').EventEmitter; var Network = require('../protocol/network'); var util = require('../utils/util'); -var crypto = require('../crypto/crypto'); +var digest = require('../crypto/digest'); var common = require('./common'); var packets = require('./packets'); @@ -98,7 +98,7 @@ Parser.prototype.parse = function parse(data) { return; } - checksum = crypto.hash256(data).readUInt32LE(0, true); + checksum = digest.hash256(data).readUInt32LE(0, true); if (checksum !== this.header.checksum) { this.waiting = 24; diff --git a/lib/net/proxysocket.js b/lib/net/proxysocket.js index e59df7e8..19df7748 100644 --- a/lib/net/proxysocket.js +++ b/lib/net/proxysocket.js @@ -1,7 +1,7 @@ 'use strict'; var util = require('../utils/util'); -var crypto = require('../crypto/crypto'); +var digest = require('../crypto/digest'); var BufferWriter = require('../utils/writer'); var assert = require('assert'); var EventEmitter = require('events').EventEmitter; @@ -129,7 +129,7 @@ ProxySocket.prototype.connect = function connect(port, host) { nonce++; assert(nonce <= 0xffffffff, 'Could not create socket.'); pow.writeUInt32LE(nonce, 0, true); - } while (crypto.hash256(pow).compare(this.target) > 0); + } while (digest.hash256(pow).compare(this.target) > 0); util.log('Solved proof of work: %d', nonce); } diff --git a/lib/primitives/abstractblock.js b/lib/primitives/abstractblock.js index 97781794..de48f20e 100644 --- a/lib/primitives/abstractblock.js +++ b/lib/primitives/abstractblock.js @@ -9,7 +9,7 @@ var assert = require('assert'); var util = require('../utils/util'); -var crypto = require('../crypto/crypto'); +var digest = require('../crypto/digest'); var StaticWriter = require('../utils/staticwriter'); var InvItem = require('./invitem'); var encoding = require('../utils/encoding'); @@ -160,7 +160,7 @@ AbstractBlock.prototype.hash = function hash(enc) { var hex; if (!hash) { - hash = crypto.hash256(this.abbr()); + hash = digest.hash256(this.abbr()); if (!this.mutable) this._hash = hash; } diff --git a/lib/primitives/address.js b/lib/primitives/address.js index 1374dcd4..3221774c 100644 --- a/lib/primitives/address.js +++ b/lib/primitives/address.js @@ -11,7 +11,7 @@ var assert = require('assert'); var Network = require('../protocol/network'); var encoding = require('../utils/encoding'); var util = require('../utils/util'); -var crypto = require('../crypto/crypto'); +var digest = require('../crypto/digest'); var BufferReader = require('../utils/reader'); var StaticWriter = require('../utils/staticwriter'); var base58 = require('../utils/base58'); @@ -411,7 +411,7 @@ Address.fromBech32 = function fromBech32(data, network) { Address.prototype.fromScript = function fromScript(script) { if (script.isPubkey()) { - this.hash = crypto.hash160(script.get(0)); + this.hash = digest.hash160(script.get(0)); this.type = Address.types.PUBKEYHASH; this.version = -1; return this; @@ -471,14 +471,14 @@ Address.prototype.fromWitness = function fromWitness(witness) { // We're pretty much screwed here // since we can't get the version. if (witness.isPubkeyhashInput()) { - this.hash = crypto.hash160(witness.get(1)); + this.hash = digest.hash160(witness.get(1)); this.type = Address.types.WITNESS; this.version = 0; return this; } if (witness.isScripthashInput()) { - this.hash = crypto.sha256(witness.get(witness.length - 1)); + this.hash = digest.sha256(witness.get(witness.length - 1)); this.type = Address.types.WITNESS; this.version = 0; return this; @@ -493,14 +493,14 @@ Address.prototype.fromWitness = function fromWitness(witness) { Address.prototype.fromInputScript = function fromInputScript(script) { if (script.isPubkeyhashInput()) { - this.hash = crypto.hash160(script.get(1)); + this.hash = digest.hash160(script.get(1)); this.type = Address.types.PUBKEYHASH; this.version = -1; return this; } if (script.isScripthashInput()) { - this.hash = crypto.hash160(script.get(script.length - 1)); + this.hash = digest.hash160(script.get(script.length - 1)); this.type = Address.types.SCRIPTHASH; this.version = -1; return this; diff --git a/lib/primitives/block.js b/lib/primitives/block.js index 6d9d8e3a..ef59dba4 100644 --- a/lib/primitives/block.js +++ b/lib/primitives/block.js @@ -10,7 +10,8 @@ var assert = require('assert'); var util = require('../utils/util'); var encoding = require('../utils/encoding'); -var crypto = require('../crypto/crypto'); +var digest = require('../crypto/digest'); +var merkle = require('../crypto/merkle'); var consensus = require('../protocol/consensus'); var AbstractBlock = require('./abstractblock'); var VerifyResult = require('../protocol/errors').VerifyResult; @@ -293,7 +294,7 @@ Block.prototype.createMerkleRoot = function createMerkleRoot(enc) { leaves.push(tx.hash()); } - root = crypto.createMerkleRoot(leaves); + root = merkle.createRoot(leaves); if (root.malleated) return null; @@ -333,14 +334,14 @@ Block.prototype.createCommitmentHash = function createCommitmentHash(enc) { leaves.push(tx.witnessHash()); } - root = crypto.createMerkleRoot(leaves); + root = merkle.createRoot(leaves); // Note: malleation check ignored here. // assert(!root.malleated); data = util.concat(root.hash, nonce); - hash = crypto.hash256(data); + hash = digest.hash256(data); return enc === 'hex' ? hash.toString('hex') diff --git a/lib/primitives/keyring.js b/lib/primitives/keyring.js index 5f8948f3..ffacf6fe 100644 --- a/lib/primitives/keyring.js +++ b/lib/primitives/keyring.js @@ -9,7 +9,7 @@ var assert = require('assert'); var encoding = require('../utils/encoding'); -var crypto = require('../crypto/crypto'); +var digest = require('../crypto/digest'); var Network = require('../protocol/network'); var BufferReader = require('../utils/reader'); var StaticWriter = require('../utils/staticwriter'); @@ -418,7 +418,7 @@ KeyRing.prototype.getProgram = function getProgram() { if (!this._program) { if (!this.script) { - hash = crypto.hash160(this.publicKey); + hash = digest.hash160(this.publicKey); program = Script.fromProgram(0, hash); } else { hash = this.script.sha256(); @@ -564,7 +564,7 @@ KeyRing.prototype.getScriptAddress = function getScriptAddress(enc) { KeyRing.prototype.getKeyHash = function getKeyHash(enc) { if (!this._keyHash) - this._keyHash = crypto.hash160(this.publicKey); + this._keyHash = digest.hash160(this.publicKey); return enc === 'hex' ? this._keyHash.toString('hex') diff --git a/lib/primitives/merkleblock.js b/lib/primitives/merkleblock.js index bf19896a..0e701524 100644 --- a/lib/primitives/merkleblock.js +++ b/lib/primitives/merkleblock.js @@ -9,7 +9,7 @@ var assert = require('assert'); var util = require('../utils/util'); -var crypto = require('../crypto/crypto'); +var digest = require('../crypto/digest'); var AbstractBlock = require('./abstractblock'); var VerifyResult = require('../protocol/errors').VerifyResult; var BufferReader = require('../utils/reader'); @@ -243,7 +243,7 @@ MerkleBlock.prototype.extractTree = function extractTree() { left.copy(buf, 0); right.copy(buf, 32); - return crypto.hash256(buf); + return digest.hash256(buf); } if (totalTX === 0) @@ -602,7 +602,7 @@ MerkleBlock.fromMatches = function fromMatches(block, matches) { left.copy(buf, 0); right.copy(buf, 32); - return crypto.hash256(buf); + return digest.hash256(buf); } function traverse(height, pos, leaves, matches) { diff --git a/lib/primitives/tx.js b/lib/primitives/tx.js index 6ac2bc78..58d8871f 100644 --- a/lib/primitives/tx.js +++ b/lib/primitives/tx.js @@ -10,7 +10,7 @@ var assert = require('assert'); var util = require('../utils/util'); var encoding = require('../utils/encoding'); -var crypto = require('../crypto/crypto'); +var digest = require('../crypto/digest'); var secp256k1 = require('../crypto/secp256k1'); var Amount = require('../btc/amount'); var Network = require('../protocol/network'); @@ -188,7 +188,7 @@ TX.prototype.hash = function _hash(enc) { var hex; if (!hash) { - hash = crypto.hash256(this.toNormal()); + hash = digest.hash256(this.toNormal()); if (!this.mutable) this._hash = hash; } @@ -222,7 +222,7 @@ TX.prototype.witnessHash = function witnessHash(enc) { return this.hash(enc); if (!hash) { - hash = crypto.hash256(this.toRaw()); + hash = digest.hash256(this.toRaw()); if (!this.mutable) this._whash = hash; } @@ -563,7 +563,7 @@ TX.prototype.signatureHashV0 = function signatureHashV0(index, prev, type) { // Append the hash type. bw.writeU32(type); - return crypto.hash256(bw.render()); + return digest.hash256(bw.render()); }; /** @@ -644,7 +644,7 @@ TX.prototype.signatureHashV1 = function signatureHashV1(index, prev, value, type input.prevout.toWriter(bw); } - prevouts = crypto.hash256(bw.render()); + prevouts = digest.hash256(bw.render()); if (!this.mutable) this._hashPrevouts = prevouts; @@ -664,7 +664,7 @@ TX.prototype.signatureHashV1 = function signatureHashV1(index, prev, value, type bw.writeU32(input.sequence); } - sequences = crypto.hash256(bw.render()); + sequences = digest.hash256(bw.render()); if (!this.mutable) this._hashSequence = sequences; @@ -690,14 +690,14 @@ TX.prototype.signatureHashV1 = function signatureHashV1(index, prev, value, type output.toWriter(bw); } - outputs = crypto.hash256(bw.render()); + outputs = digest.hash256(bw.render()); if (!this.mutable) this._hashOutputs = outputs; } } else if ((type & 0x1f) === Script.hashType.SINGLE && index < this.outputs.length) { output = this.outputs[index]; - outputs = crypto.hash256(output.toRaw()); + outputs = digest.hash256(output.toRaw()); } input = this.inputs[index]; @@ -717,7 +717,7 @@ TX.prototype.signatureHashV1 = function signatureHashV1(index, prev, value, type bw.writeU32(this.locktime); bw.writeU32(type); - return crypto.hash256(bw.render()); + return digest.hash256(bw.render()); }; /** diff --git a/lib/script/script.js b/lib/script/script.js index acc5b15f..78fc7947 100644 --- a/lib/script/script.js +++ b/lib/script/script.js @@ -12,7 +12,8 @@ var BN = require('../crypto/bn'); var consensus = require('../protocol/consensus'); var policy = require('../protocol/policy'); var util = require('../utils/util'); -var crypto = require('../crypto/crypto'); +var digest = require('../crypto/digest'); +var merkle = require('../crypto/merkle'); var BufferWriter = require('../utils/writer'); var BufferReader = require('../utils/reader'); var StaticWriter = require('../utils/staticwriter'); @@ -1058,35 +1059,35 @@ Script.prototype.execute = function execute(stack, flags, tx, index, value, vers if (stack.length === 0) throw new ScriptError('INVALID_STACK_OPERATION', op, ip); - stack.push(crypto.ripemd160(stack.pop())); + stack.push(digest.ripemd160(stack.pop())); break; } case opcodes.OP_SHA1: { if (stack.length === 0) throw new ScriptError('INVALID_STACK_OPERATION', op, ip); - stack.push(crypto.sha1(stack.pop())); + stack.push(digest.sha1(stack.pop())); break; } case opcodes.OP_SHA256: { if (stack.length === 0) throw new ScriptError('INVALID_STACK_OPERATION', op, ip); - stack.push(crypto.sha256(stack.pop())); + stack.push(digest.sha256(stack.pop())); break; } case opcodes.OP_HASH160: { if (stack.length === 0) throw new ScriptError('INVALID_STACK_OPERATION', op, ip); - stack.push(crypto.hash160(stack.pop())); + stack.push(digest.hash160(stack.pop())); break; } case opcodes.OP_HASH256: { if (stack.length === 0) throw new ScriptError('INVALID_STACK_OPERATION', op, ip); - stack.push(crypto.hash256(stack.pop())); + stack.push(digest.hash256(stack.pop())); break; } case opcodes.OP_CODESEPARATOR: { @@ -1836,7 +1837,7 @@ Script.prototype.getAddress = function getAddress() { */ Script.prototype.hash160 = function hash160(enc) { - var hash = crypto.hash160(this.toRaw()); + var hash = digest.hash160(this.toRaw()); if (enc === 'hex') hash = hash.toString('hex'); return hash; @@ -1849,7 +1850,7 @@ Script.prototype.hash160 = function hash160(enc) { */ Script.prototype.sha256 = function sha256(enc) { - var hash = crypto.sha256(this.toRaw()); + var hash = digest.sha256(this.toRaw()); if (enc === 'hex') hash = hash.toString('hex'); return hash; @@ -2083,7 +2084,7 @@ Script.prototype.forWitness = function() { return this; if (this.isPubkey()) { - hash = crypto.hash160(this.get(0)); + hash = digest.hash160(this.get(0)); return Script.fromProgram(0, hash); } @@ -2923,7 +2924,7 @@ Script.verifyProgram = function verifyProgram(witness, output, flags, tx, i, val witnessScript = stack.pop(); - if (!crypto.sha256(witnessScript).equals(program.data)) + if (!digest.sha256(witnessScript).equals(program.data)) throw new ScriptError('WITNESS_PROGRAM_MISMATCH'); redeem = new Script(witnessScript); @@ -3073,15 +3074,15 @@ Script.verifyMast = function verifyMast(program, stack, output, flags, tx, i, va if ((scripts.written + script.length) > consensus.MAX_SCRIPT_SIZE) throw new ScriptError('SCRIPT_SIZE'); } - scriptRoot.writeBytes(crypto.hash256(script)); + scriptRoot.writeBytes(digest.hash256(script)); scripts.writeBytes(script); } - scriptRoot = crypto.hash256(scriptRoot.render()); - scriptRoot = crypto.verifyMerkleBranch(scriptRoot, path, pos); + scriptRoot = digest.hash256(scriptRoot.render()); + scriptRoot = merkle.verifyBranch(scriptRoot, path, pos); mastRoot.writeBytes(scriptRoot); - mastRoot = crypto.hash256(mastRoot.render()); + mastRoot = digest.hash256(mastRoot.render()); if (!mastRoot.equals(program.data)) throw new ScriptError('WITNESS_PROGRAM_MISMATCH'); diff --git a/lib/utils/gcs.js b/lib/utils/gcs.js index cfe1f8a2..96b3893f 100644 --- a/lib/utils/gcs.js +++ b/lib/utils/gcs.js @@ -8,7 +8,7 @@ var assert = require('assert'); var Int64 = require('./int64'); -var crypto = require('../crypto/crypto'); +var digest = require('../crypto/digest'); var siphash24 = require('../crypto/siphash'); var SCRATCH = Buffer.allocUnsafe(64); var DUMMY = Buffer.allocUnsafe(0); @@ -28,7 +28,7 @@ function GCSFilter() { } GCSFilter.prototype.hash = function _hash(enc) { - var hash = crypto.hash256(this.data); + var hash = digest.hash256(this.data); return enc === 'hex' ? hash.toString('hex') : hash; }; @@ -37,7 +37,7 @@ GCSFilter.prototype.header = function header(prev) { var hash = this.hash(); hash.copy(data, 0); prev.copy(data, 32); - return crypto.hash256(data); + return digest.hash256(data); }; GCSFilter.prototype.match = function match(key, data) { diff --git a/lib/utils/reader.js b/lib/utils/reader.js index 0d71877f..91dc7d33 100644 --- a/lib/utils/reader.js +++ b/lib/utils/reader.js @@ -9,7 +9,7 @@ var assert = require('assert'); var encoding = require('./encoding'); -var crypto = require('../crypto/crypto'); +var digest = require('../crypto/digest'); /** * An object that allows reading of buffers in a sane manner. @@ -673,7 +673,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.hash256(data).readUInt32LE(0, true); + return digest.hash256(data).readUInt32LE(0, true); }; /** diff --git a/lib/utils/staticwriter.js b/lib/utils/staticwriter.js index 833832ae..df7dea00 100644 --- a/lib/utils/staticwriter.js +++ b/lib/utils/staticwriter.js @@ -8,7 +8,7 @@ var assert = require('assert'); var encoding = require('./encoding'); -var crypto = require('../crypto/crypto'); +var digest = require('../crypto/digest'); /** * Statically allocated buffer writer. @@ -417,7 +417,7 @@ StaticWriter.prototype.writeNullString = function writeNullString(value, enc) { StaticWriter.prototype.writeChecksum = function writeChecksum() { var data = this.data.slice(0, this.written); - var hash = crypto.hash256(data); + var hash = digest.hash256(data); hash.copy(this.data, this.written, 0, 4); this.written += 4; }; diff --git a/lib/utils/writer.js b/lib/utils/writer.js index d2c20155..c9d8c709 100644 --- a/lib/utils/writer.js +++ b/lib/utils/writer.js @@ -9,7 +9,7 @@ var assert = require('assert'); var encoding = require('./encoding'); -var crypto = require('../crypto/crypto'); +var digest = require('../crypto/digest'); /* * Constants @@ -101,7 +101,7 @@ BufferWriter.prototype.render = function render(keep) { case BYTES: off += op.value.copy(data, off); break; case STR: off += data.write(op.value, off, op.enc); break; case CHECKSUM: - off += crypto.hash256(data.slice(0, off)).copy(data, off, 0, 4); + off += digest.hash256(data.slice(0, off)).copy(data, off, 0, 4); break; case FILL: data.fill(op.value, off, off + op.size); diff --git a/lib/wallet/http.js b/lib/wallet/http.js index ed2042e7..ab214962 100644 --- a/lib/wallet/http.js +++ b/lib/wallet/http.js @@ -14,7 +14,9 @@ var base58 = require('../utils/base58'); var MTX = require('../primitives/mtx'); var Outpoint = require('../primitives/outpoint'); var Script = require('../script/script'); -var crypto = require('../crypto/crypto'); +var digest = require('../crypto/digest'); +var random = require('../crypto/random'); +var ccmp = require('../crypto/ccmp'); var Network = require('../protocol/network'); var Validator = require('../utils/validator'); var common = require('./common'); @@ -887,7 +889,7 @@ HTTPServer.prototype.handleSocket = function handleSocket(socket) { if (!self.options.noAuth) { hash = hash256(key); - if (!crypto.ccmp(hash, self.options.apiHash)) + if (!ccmp(hash, self.options.apiHash)) throw new Error('Bad key.'); } @@ -973,7 +975,7 @@ function HTTPOptions(options) { this.network = Network.primary; this.logger = null; this.walletdb = null; - this.apiKey = base58.encode(crypto.randomBytes(20)); + this.apiKey = base58.encode(random.randomBytes(20)); this.apiHash = hash256(this.apiKey); this.serviceHash = this.apiHash; this.noAuth = false; @@ -1094,7 +1096,7 @@ function hash256(data) { if (data.length > 200) return Buffer.alloc(0); - return crypto.hash256(Buffer.from(data, 'utf8')); + return digest.hash256(Buffer.from(data, 'utf8')); } function enforce(value, msg) { diff --git a/lib/wallet/masterkey.js b/lib/wallet/masterkey.js index bf7c2d98..59214754 100644 --- a/lib/wallet/masterkey.js +++ b/lib/wallet/masterkey.js @@ -9,7 +9,11 @@ var assert = require('assert'); var util = require('../utils/util'); var Lock = require('../utils/lock'); -var crypto = require('../crypto/crypto'); +var random = require('../crypto/random'); +var cleanse = require('../crypto/cleanse'); +var aes = require('../crypto/aes'); +var pbkdf2 = require('../crypto/pbkdf2'); +var scrypt = require('../crypto/scrypt'); var BufferReader = require('../utils/reader'); var StaticWriter = require('../utils/staticwriter'); var encoding = require('../utils/encoding'); @@ -199,7 +203,7 @@ MasterKey.prototype._unlock = async function _unlock(passphrase, timeout) { assert(this.encrypted); key = await this.derive(passphrase); - data = crypto.decipher(this.ciphertext, key, this.iv); + data = aes.decipher(this.ciphertext, key, this.iv); this.fromKeyRaw(data); @@ -259,9 +263,9 @@ MasterKey.prototype.derive = async function derive(passwd) { switch (this.alg) { case MasterKey.alg.PBKDF2: - return await crypto.pbkdf2Async(passwd, salt, N, 32, 'sha256'); + return await pbkdf2.deriveAsync(passwd, salt, N, 32, 'sha256'); case MasterKey.alg.SCRYPT: - return await crypto.scryptAsync(passwd, salt, N, r, p, 32); + return await scrypt.deriveAsync(passwd, salt, N, r, p, 32); default: throw new Error('Unknown algorithm: ' + this.alg); } @@ -281,7 +285,7 @@ MasterKey.prototype.encipher = function encipher(data, iv) { if (typeof iv === 'string') iv = Buffer.from(iv, 'hex'); - return crypto.encipher(data, this.aesKey, iv.slice(0, 16)); + return aes.encipher(data, this.aesKey, iv.slice(0, 16)); }; /** @@ -298,7 +302,7 @@ MasterKey.prototype.decipher = function decipher(data, iv) { if (typeof iv === 'string') iv = Buffer.from(iv, 'hex'); - return crypto.decipher(data, this.aesKey, iv.slice(0, 16)); + return aes.decipher(data, this.aesKey, iv.slice(0, 16)); }; /** @@ -338,7 +342,7 @@ MasterKey.prototype._lock = function lock() { } if (this.aesKey) { - crypto.cleanse(this.aesKey); + cleanse(this.aesKey); this.aesKey = null; } }; @@ -386,7 +390,7 @@ MasterKey.prototype._decrypt = async function decrypt(passphrase, clean) { this._lock(); key = await this.derive(passphrase); - data = crypto.decipher(this.ciphertext, key, this.iv); + data = aes.decipher(this.ciphertext, key, this.iv); this.fromKeyRaw(data); this.encrypted = false; @@ -394,7 +398,7 @@ MasterKey.prototype._decrypt = async function decrypt(passphrase, clean) { this.ciphertext = null; if (!clean) { - crypto.cleanse(key); + cleanse(key); return; } @@ -433,12 +437,12 @@ MasterKey.prototype._encrypt = async function encrypt(passphrase, clean) { throw new Error('No passphrase provided.'); data = this.toKeyRaw(); - iv = crypto.randomBytes(16); + iv = random.randomBytes(16); this.stop(); key = await this.derive(passphrase); - data = crypto.encipher(data, key, iv); + data = aes.encipher(data, key, iv); this.key = null; this.mnemonic = null; @@ -447,7 +451,7 @@ MasterKey.prototype._encrypt = async function encrypt(passphrase, clean) { this.ciphertext = data; if (!clean) { - crypto.cleanse(key); + cleanse(key); return; } diff --git a/lib/wallet/rpc.js b/lib/wallet/rpc.js index 8d51f280..fd381e63 100644 --- a/lib/wallet/rpc.js +++ b/lib/wallet/rpc.js @@ -9,7 +9,7 @@ var assert = require('assert'); var fs = require('../utils/fs'); var util = require('../utils/util'); -var crypto = require('../crypto/crypto'); +var digest = require('../crypto/digest'); var Amount = require('../btc/amount'); var Script = require('../script/script'); var Address = require('../primitives/address'); @@ -1484,7 +1484,7 @@ RPC.prototype.signMessage = async function signMessage(args, help) { throw new RPCError(errs.WALLET_UNLOCK_NEEDED, 'Wallet is locked.'); msg = Buffer.from(MAGIC_STRING + msg, 'utf8'); - msg = crypto.hash256(msg); + msg = digest.hash256(msg); sig = ring.sign(msg); diff --git a/lib/wallet/wallet.js b/lib/wallet/wallet.js index d6c92ec1..ae7a42df 100644 --- a/lib/wallet/wallet.js +++ b/lib/wallet/wallet.js @@ -13,7 +13,8 @@ var Network = require('../protocol/network'); var util = require('../utils/util'); var encoding = require('../utils/encoding'); var Lock = require('../utils/lock'); -var crypto = require('../crypto/crypto'); +var digest = require('../crypto/digest'); +var cleanse = require('../crypto/cleanse'); var BufferReader = require('../utils/reader'); var StaticWriter = require('../utils/staticwriter'); var base58 = require('../utils/base58'); @@ -408,12 +409,12 @@ Wallet.prototype._encrypt = async function encrypt(passphrase) { try { await this.db.encryptKeys(this, key); } catch (e) { - crypto.cleanse(key); + cleanse(key); this.drop(); throw e; } - crypto.cleanse(key); + cleanse(key); this.save(); @@ -450,12 +451,12 @@ Wallet.prototype._decrypt = async function decrypt(passphrase) { try { await this.db.decryptKeys(this, key); } catch (e) { - crypto.cleanse(key); + cleanse(key); this.drop(); throw e; } - crypto.cleanse(key); + cleanse(key); this.save(); @@ -621,7 +622,7 @@ Wallet.prototype.getID = function getID() { bw.writeBytes(key.publicKey); bw.writeU32(this.network.magic); - hash = crypto.hash160(bw.render()); + hash = digest.hash160(bw.render()); bw = new StaticWriter(27); bw.writeU8(0x03); @@ -653,7 +654,7 @@ Wallet.prototype.getToken = function getToken(nonce) { bw.writeBytes(key.privateKey); bw.writeU32(nonce); - return crypto.hash256(bw.render()); + return digest.hash256(bw.render()); }; /** diff --git a/lib/wallet/walletdb.js b/lib/wallet/walletdb.js index 67c2204b..f1fdba3d 100644 --- a/lib/wallet/walletdb.js +++ b/lib/wallet/walletdb.js @@ -13,7 +13,8 @@ var util = require('../utils/util'); var Lock = require('../utils/lock'); var LRU = require('../utils/lru'); var encoding = require('../utils/encoding'); -var crypto = require('../crypto/crypto'); +var ccmp = require('../crypto/ccmp'); +var aes = require('../crypto/aes'); var Network = require('../protocol/network'); var Path = require('./path'); var common = require('./common'); @@ -1011,7 +1012,7 @@ WalletDB.prototype.auth = async function auth(wid, token) { } // Compare in constant time: - if (!crypto.ccmp(token, wallet.token)) + if (!ccmp(token, wallet.token)) throw new Error('WDB: Authentication error.'); return wallet; @@ -1422,7 +1423,7 @@ WalletDB.prototype.encryptKeys = async function encryptKeys(wallet, key) { iv = iv.slice(0, 16); path = path.clone(); - path.data = crypto.encipher(path.data, key, iv); + path.data = aes.encipher(path.data, key, iv); path.encrypted = true; wallet.pathCache.push(path.hash, path); @@ -1456,7 +1457,7 @@ WalletDB.prototype.decryptKeys = async function decryptKeys(wallet, key) { iv = iv.slice(0, 16); path = path.clone(); - path.data = crypto.decipher(path.data, key, iv); + path.data = aes.decipher(path.data, key, iv); path.encrypted = false; wallet.pathCache.push(path.hash, path); diff --git a/lib/workers/jobs.js b/lib/workers/jobs.js index ccb6c43b..e95e8dbb 100644 --- a/lib/workers/jobs.js +++ b/lib/workers/jobs.js @@ -175,6 +175,6 @@ jobs.mine = function _mine(data, target, min, max) { */ jobs.scrypt = function _scrypt(passwd, salt, N, r, p, len) { - var key = scrypt(passwd, salt, N, r, p, len); + var key = scrypt.derive(passwd, salt, N, r, p, len); return new packets.ScryptResultPacket(key); }; diff --git a/migrate/ensure-tip-index.js b/migrate/ensure-tip-index.js index 642ea4ca..536c3434 100644 --- a/migrate/ensure-tip-index.js +++ b/migrate/ensure-tip-index.js @@ -3,7 +3,7 @@ var assert = require('assert'); var encoding = require('../lib/utils/encoding'); var BufferReader = require('../lib/utils/reader'); -var crypto = require('../lib/crypto/crypto'); +var digest = require('../lib/crypto/digest'); var util = require('../lib/utils/util'); var LDB = require('../lib/db/ldb'); var BN = require('../lib/crypto/bn'); @@ -42,7 +42,7 @@ async function checkVersion() { function entryFromRaw(data) { var p = new BufferReader(data, true); - var hash = crypto.hash256(p.readBytes(80)); + var hash = digest.hash256(p.readBytes(80)); var entry = {}; p.seek(-80); diff --git a/package.json b/package.json index 8a147b87..20b7f299 100644 --- a/package.json +++ b/package.json @@ -78,9 +78,12 @@ "socket.io": "./browser/empty.js", "./lib/bcoin": "./lib/bcoin-browser.js", "./lib/blockchain/layout.js": "./lib/blockchain/layout-browser.js", - "./lib/crypto/backend.js": "./lib/crypto/backend-browser.js", - "./lib/crypto/secp256k1.js": "./lib/crypto/secp256k1-elliptic.js", + "./lib/crypto/aes.js": "./lib/crypto/aes-browser.js", + "./lib/crypto/digest.js": "./lib/crypto/digest-browser.js", + "./lib/crypto/pbkdf2.js": "./lib/crypto/pbkdf2-browser.js", + "./lib/crypto/random.js": "./lib/crypto/random-browser.js", "./lib/crypto/rsa.js": "./lib/crypto/rsa-browser.js", + "./lib/crypto/secp256k1.js": "./lib/crypto/secp256k1-elliptic.js", "./lib/db/backends.js": "./lib/db/backends-browser.js", "./lib/hd/wordlist": "./lib/hd/wordlist-browser.js", "./lib/http/base": "./browser/empty.js", diff --git a/scripts/fuzz.js b/scripts/fuzz.js index b2384aed..83624c6b 100644 --- a/scripts/fuzz.js +++ b/scripts/fuzz.js @@ -1,21 +1,22 @@ var assert = require('assert'); var bcoin = require('../'); -var util = bcoin.util; -var Script = bcoin.script; -var Stack = bcoin.stack; -var Witness = bcoin.witness; -var Input = bcoin.input; -var Output = bcoin.output; -var Outpoint = bcoin.outpoint; -var TX = bcoin.tx; -var crypto = bcoin.crypto; -var consensus = bcoin.consensus; +var util = require('../lib/utils/util'); +var Script = require('../lib/script/script'); +var Stack = require('../lib/script/stack'); +var Witness = require('../lib/script/witness'); +var Input = require('../lib/primitives/input'); +var Output = require('../lib/primitives/output'); +var Outpoint = require('../lib/primitives/outpoint'); +var TX = require('../lib/primitives/tx'); +var digest = require('../lib/crypto/digest'); +var random = require('../lib/crypto/random'); +var consensus = require('../lib/protocol/consensus'); var MANDATORY = Script.flags.MANDATORY_VERIFY_FLAGS | Script.flags.VERIFY_WITNESS; var STANDARD = Script.flags.STANDARD_VERIFY_FLAGS; function randomOutpoint() { - var hash = crypto.randomBytes(32).toString('hex'); + var hash = random.randomBytes(32).toString('hex'); return new Outpoint(hash, util.random(0, 0xffffffff)); } @@ -61,7 +62,7 @@ function randomWitness(redeem) { for (i = 0; i < size; i++) { len = util.random(0, 100); - witness.push(crypto.randomBytes(len)); + witness.push(random.randomBytes(len)); } if (redeem) @@ -79,7 +80,7 @@ function randomInputScript(redeem) { for (i = 0; i < size; i++) { len = util.random(0, 100); - script.push(crypto.randomBytes(len)); + script.push(random.randomBytes(len)); } if (redeem) @@ -92,7 +93,7 @@ function randomInputScript(redeem) { function randomOutputScript() { var size = util.random(1, 10000); - return Script.fromRaw(crypto.randomBytes(size)); + return Script.fromRaw(random.randomBytes(size)); } function isPushOnly(script) { @@ -121,11 +122,11 @@ function isPushOnly(script) { function randomPubkey() { var len = util.random(0, 2) === 0 ? 33 : 65; - return Script.fromPubkey(crypto.randomBytes(len)); + return Script.fromPubkey(random.randomBytes(len)); } function randomPubkeyhash() { - return Script.fromPubkeyhash(crypto.randomBytes(20)); + return Script.fromPubkeyhash(random.randomBytes(20)); } function randomMultisig() { @@ -136,28 +137,28 @@ function randomMultisig() { for (i = 0; i < n; i++) { len = util.random(0, 2) === 0 ? 33 : 65; - keys.push(crypto.randomBytes(len)); + keys.push(random.randomBytes(len)); } return Script.fromMultisig(m, n, keys); } function randomScripthash() { - return Script.fromScripthash(crypto.randomBytes(20)); + return Script.fromScripthash(random.randomBytes(20)); } function randomWitnessPubkeyhash() { - return Script.fromProgram(0, crypto.randomBytes(20)); + return Script.fromProgram(0, random.randomBytes(20)); } function randomWitnessScripthash() { - return Script.fromProgram(0, crypto.randomBytes(32)); + return Script.fromProgram(0, random.randomBytes(32)); } function randomProgram() { var version = util.random(0, 16); var size = util.random(2, 41); - return Script.fromProgram(version, crypto.randomBytes(size)); + return Script.fromProgram(version, random.randomBytes(size)); } function randomRedeem() { diff --git a/test/aes-test.js b/test/aes-test.js index f3e06430..285dd7bf 100644 --- a/test/aes-test.js +++ b/test/aes-test.js @@ -1,13 +1,14 @@ 'use strict'; var assert = require('assert'); -var crypto = require('../lib/crypto/crypto'); +var digest = require('../lib/crypto/digest'); var aes = require('../lib/crypto/aes'); +var pbkdf2 = require('../lib/crypto/pbkdf2'); var nativeCrypto = require('crypto'); describe('AES', function() { function pbkdf2key(passphrase, iterations, dkLen, ivLen, alg) { - var key = crypto.pbkdf2(passphrase, '', iterations, dkLen + ivLen, 'sha512'); + var key = pbkdf2.derive(passphrase, '', iterations, dkLen + ivLen, 'sha512'); return { key: key.slice(0, dkLen), iv: key.slice(dkLen, dkLen + ivLen) @@ -69,7 +70,7 @@ describe('AES', function() { passphrase = Buffer.from(passphrase, 'utf8'); key = pbkdf2key(passphrase, 2048, 32, 16); - return crypto.encipher(data, key.key, key.iv); + return aes.encipher(data, key.key, key.iv); } function bdecrypt(data, passphrase) { @@ -85,7 +86,7 @@ describe('AES', function() { passphrase = Buffer.from(passphrase, 'utf8'); key = pbkdf2key(passphrase, 2048, 32, 16); - return crypto.decipher(data, key.key, key.iv); + return aes.decipher(data, key.key, key.iv); } function encrypt(data, passphrase) { @@ -102,7 +103,7 @@ describe('AES', function() { key = pbkdf2key(passphrase, 2048, 32, 16); - return aes.cbc.encrypt(data, key.key, key.iv); + return aes.encipher(data, key.key, key.iv); } function decrypt(data, passphrase) { @@ -119,19 +120,19 @@ describe('AES', function() { key = pbkdf2key(passphrase, 2048, 32, 16); - return aes.cbc.decrypt(data, key.key, key.iv); + return aes.decipher(data, key.key, key.iv); } it('should encrypt and decrypt a hash with 2 blocks', function() { - var hash = crypto.sha256(Buffer.alloc(0)); + var hash = digest.sha256(Buffer.alloc(0)); var enchash = encrypt(hash, 'foo'); var dechash = decrypt(enchash, 'foo'); - var hash2 = crypto.sha256(Buffer.alloc(0)); + var hash2 = digest.sha256(Buffer.alloc(0)); var enchash2 = nencrypt(hash2, 'foo'); var dechash2 = ndecrypt(enchash2, 'foo'); - var hash3 = crypto.sha256(Buffer.alloc(0)); + var hash3 = digest.sha256(Buffer.alloc(0)); var enchash3 = bencrypt(hash3, 'foo'); var dechash3 = bdecrypt(enchash3, 'foo'); @@ -142,11 +143,11 @@ describe('AES', function() { }); it('should encrypt and decrypt a hash with uneven blocks', function() { - var hash = Buffer.concat([crypto.sha256(Buffer.alloc(0)), Buffer.from([1,2,3])]); + var hash = Buffer.concat([digest.sha256(Buffer.alloc(0)), Buffer.from([1,2,3])]); var enchash = encrypt(hash, 'foo'); var dechash = decrypt(enchash, 'foo'); - var hash2 = Buffer.concat([crypto.sha256(Buffer.alloc(0)), Buffer.from([1,2,3])]); + var hash2 = Buffer.concat([digest.sha256(Buffer.alloc(0)), Buffer.from([1,2,3])]); var enchash2 = nencrypt(hash2, 'foo'); var dechash2 = ndecrypt(enchash2, 'foo'); diff --git a/test/chachapoly-test.js b/test/chachapoly-test.js index fd9e88c0..965e0b93 100644 --- a/test/chachapoly-test.js +++ b/test/chachapoly-test.js @@ -1,10 +1,9 @@ 'use strict'; var assert = require('assert'); -var chachapoly = require('../lib/crypto/chachapoly'); -var ChaCha20 = chachapoly.ChaCha20; -var Poly1305 = chachapoly.Poly1305; -var AEAD = chachapoly.AEAD; +var ChaCha20 = require('../lib/crypto/chacha20'); +var Poly1305 = require('../lib/crypto/poly1305'); +var AEAD = require('../lib/crypto/aead'); describe('ChaCha20 / Poly1305 / AEAD', function() { function testChaCha(options) { diff --git a/test/gcs-test.js b/test/gcs-test.js index 74eabd68..5beed9d9 100644 --- a/test/gcs-test.js +++ b/test/gcs-test.js @@ -3,7 +3,7 @@ var assert = require('assert'); var fs = require('../lib/utils/fs'); var GCSFilter = require('../lib/utils/gcs'); -var crypto = require('../lib/crypto/crypto'); +var random = require('../lib/crypto/random'); var Block = require('../lib/primitives/block'); var Outpoint = require('../lib/primitives/outpoint'); var Address = require('../lib/primitives/address'); @@ -12,7 +12,7 @@ var raw = fs.readFileSync(__dirname + '/data/block928927.raw'); var block = Block.fromRaw(raw); describe('GCS', function() { - var key = crypto.randomBytes(16); + var key = random.randomBytes(16); var P = 20; var filter1, filter2, filter3, filter4, filter5; var contents1, contents2; diff --git a/test/hd-test.js b/test/hd-test.js index d27f7377..3a408375 100644 --- a/test/hd-test.js +++ b/test/hd-test.js @@ -3,7 +3,7 @@ var assert = require('assert'); var HD = require('../lib/hd'); var base58 = require('../lib/utils/base58'); -var crypto = require('../lib/crypto/crypto'); +var pbkdf2 = require('../lib/crypto/pbkdf2'); var vectors = require('./data/hd.json'); var vector1 = vectors.vector1; var vector2 = vectors.vector2; @@ -21,7 +21,7 @@ describe('HD', function() { var master, child1, child2, child3, child4, child5, child6; it('should create a pbkdf2 seed', function() { - var seed = crypto.pbkdf2(vectors.phrase, 'mnemonicfoo', 2048, 64, 'sha512'); + var seed = pbkdf2.derive(vectors.phrase, 'mnemonicfoo', 2048, 64, 'sha512'); assert.equal(seed.toString('hex'), vectors.seed); }); diff --git a/test/mempool-test.js b/test/mempool-test.js index 83ff8b77..d6a3ff81 100644 --- a/test/mempool-test.js +++ b/test/mempool-test.js @@ -2,7 +2,7 @@ var assert = require('assert'); var encoding = require('../lib/utils/encoding'); -var crypto = require('../lib/crypto/crypto'); +var random = require('../lib/crypto/random'); var MempoolEntry = require('../lib/mempool/mempoolentry'); var Mempool = require('../lib/mempool/mempool'); var Chain = require('../lib/blockchain/chain'); @@ -161,7 +161,7 @@ describe('Mempool', function() { tx.addOutput(w.getAddress(), 10000); prev = Script.fromPubkey(kp.publicKey); - prevHash = crypto.randomBytes(32).toString('hex'); + prevHash = random.randomBytes(32).toString('hex'); tx.addCoin(dummy(prev, prevHash)); tx.setLocktime(200); @@ -187,7 +187,7 @@ describe('Mempool', function() { tx.addOutput(w.getAddress(), 10000); prev = Script.fromPubkey(kp.publicKey); - prevHash = crypto.randomBytes(32).toString('hex'); + prevHash = random.randomBytes(32).toString('hex'); tx.addCoin(dummy(prev, prevHash)); tx.setLocktime(200); @@ -220,7 +220,7 @@ describe('Mempool', function() { tx.addOutput(w.getAddress(), 10000); prev = Script.fromProgram(0, kp.getKeyHash()); - prevHash = crypto.randomBytes(32).toString('hex'); + prevHash = random.randomBytes(32).toString('hex'); tx.addCoin(dummy(prev, prevHash)); @@ -252,7 +252,7 @@ describe('Mempool', function() { tx.addOutput(w.getAddress(), 10000); prev = Script.fromPubkey(kp.publicKey); - prevHash = crypto.randomBytes(32).toString('hex'); + prevHash = random.randomBytes(32).toString('hex'); tx.addCoin(dummy(prev, prevHash)); @@ -283,7 +283,7 @@ describe('Mempool', function() { tx.addOutput(w.getAddress(), 10000); prev = Script.fromProgram(0, kp.getKeyHash()); - prevHash = crypto.randomBytes(32).toString('hex'); + prevHash = random.randomBytes(32).toString('hex'); tx.addCoin(dummy(prev, prevHash)); @@ -310,7 +310,7 @@ describe('Mempool', function() { tx.addOutput(w.getAddress(), 10000); prev = Script.fromPubkey(kp.publicKey); - prevHash = crypto.randomBytes(32).toString('hex'); + prevHash = random.randomBytes(32).toString('hex'); tx.addCoin(dummy(prev, prevHash)); diff --git a/test/scrypt-test.js b/test/scrypt-test.js index da03af9c..ed264269 100644 --- a/test/scrypt-test.js +++ b/test/scrypt-test.js @@ -1,13 +1,13 @@ 'use strict'; var assert = require('assert'); -var scrypt = require('../lib/crypto/crypto').scrypt; +var scrypt = require('../lib/crypto/scrypt'); describe('Scrypt', function() { it('should perform scrypt with N=16', function() { var pass = Buffer.from(''); var salt = Buffer.from(''); - var result = scrypt(pass, salt, 16, 1, 1, 64); + var result = scrypt.derive(pass, salt, 16, 1, 1, 64); assert.equal(result.toString('hex'), '' + '77d6576238657b203b19ca42c18a0497f16b4844e3074ae8dfdffa3f' + 'ede21442fcd0069ded0948f8326a753a0fc81f17e8d3e0fb2e0d3628' @@ -17,7 +17,7 @@ describe('Scrypt', function() { it('should perform scrypt with N=1024', function() { var pass = Buffer.from('password'); var salt = Buffer.from('NaCl'); - var result = scrypt(pass, salt, 1024, 8, 16, 64); + var result = scrypt.derive(pass, salt, 1024, 8, 16, 64); assert.equal(result.toString('hex'), '' + 'fdbabe1c9d3472007856e7190d01e9fe7c6ad7cbc8237830e773' + '76634b3731622eaf30d92e22a3886ff109279d9830dac727afb9' @@ -27,7 +27,7 @@ describe('Scrypt', function() { it('should perform scrypt with N=16384', function() { var pass = Buffer.from('pleaseletmein'); var salt = Buffer.from('SodiumChloride'); - var result = scrypt(pass, salt, 16384, 8, 1, 64); + var result = scrypt.derive(pass, salt, 16384, 8, 1, 64); assert.equal(result.toString('hex'), '' + '7023bdcb3afd7348461c06cd81fd38ebfda8fbba904f8e3ea9b54' + '3f6545da1f2d5432955613f0fcf62d49705242a9af9e61e85dc0d' @@ -38,7 +38,7 @@ describe('Scrypt', function() { // it('should perform scrypt with N=1048576', function() { // var pass = Buffer.from('pleaseletmein'); // var salt = Buffer.from('SodiumChloride'); - // var result = scrypt(pass, salt, 1048576, 8, 1, 64); + // var result = scrypt.derive(pass, salt, 1048576, 8, 1, 64); // assert.equal(result.toString('hex'), '' // + '2101cb9b6a511aaeaddbbe09cf70f881ec568d574a2ffd4dabe5' // + 'ee9820adaa478e56fd8f4ba5d09ffa1c6d927c40f4c337304049' diff --git a/test/tx-test.js b/test/tx-test.js index 0c20bb73..e8830de2 100644 --- a/test/tx-test.js +++ b/test/tx-test.js @@ -3,7 +3,7 @@ var assert = require('assert'); var util = require('../lib/utils/util'); var encoding = require('../lib/utils/encoding'); -var crypto = require('../lib/crypto/crypto'); +var random = require('../lib/crypto/random'); var consensus = require('../lib/protocol/consensus'); var TX = require('../lib/primitives/tx'); var Coin = require('../lib/primitives/coin'); @@ -355,7 +355,7 @@ describe('TX', function() { }); function createInput(value, view) { - var hash = crypto.randomBytes(32).toString('hex'); + var hash = random.randomBytes(32).toString('hex'); var output = new Output(); output.value = value; view.addOutput(hash, 0, output); diff --git a/test/utils-test.js b/test/utils-test.js index f415f8eb..79acfa69 100644 --- a/test/utils-test.js +++ b/test/utils-test.js @@ -5,7 +5,8 @@ var BN = require('../lib/crypto/bn'); var secp256k1 = require('../lib/crypto/secp256k1'); var base58 = require('../lib/utils/base58'); var encoding = require('../lib/utils/encoding'); -var crypto = require('../lib/crypto/crypto'); +var digest = require('../lib/crypto/digest'); +var hkdf = require('../lib/crypto/hkdf'); var schnorr = require('../lib/crypto/schnorr'); var Amount = require('../lib/btc/amount'); var consensus = require('../lib/protocol/consensus'); @@ -271,8 +272,8 @@ describe('Utils', function() { salt = Buffer.from(salt, 'hex'); info = Buffer.from(info, 'hex'); - prk = crypto.hkdfExtract(ikm, salt, alg); - okm = crypto.hkdfExpand(prk, info, len, alg); + prk = hkdf.extract(ikm, salt, alg); + okm = hkdf.expand(prk, info, len, alg); assert.equal(prk.toString('hex'), prkE); assert.equal(okm.toString('hex'), okmE); @@ -313,8 +314,8 @@ describe('Utils', function() { salt = Buffer.from(salt, 'hex'); info = Buffer.from(info, 'hex'); - prk = crypto.hkdfExtract(ikm, salt, alg); - okm = crypto.hkdfExpand(prk, info, len, alg); + prk = hkdf.extract(ikm, salt, alg); + okm = hkdf.expand(prk, info, len, alg); assert.equal(prk.toString('hex'), prkE); assert.equal(okm.toString('hex'), okmE); @@ -323,7 +324,7 @@ describe('Utils', function() { it('should do proper schnorr', function() { var key = secp256k1.generatePrivateKey(); var pub = secp256k1.publicKeyCreate(key, true); - var msg = crypto.hash256(Buffer.from('foo', 'ascii')); + var msg = digest.hash256(Buffer.from('foo', 'ascii')); var sig = schnorr.sign(msg, key); assert(schnorr.verify(msg, sig, pub)); assert.deepEqual(schnorr.recover(sig, msg), pub); diff --git a/test/wallet-test.js b/test/wallet-test.js index 8462ca94..947d2b80 100644 --- a/test/wallet-test.js +++ b/test/wallet-test.js @@ -4,7 +4,8 @@ var assert = require('assert'); var consensus = require('../lib/protocol/consensus'); var util = require('../lib/utils/util'); var encoding = require('../lib/utils/encoding'); -var crypto = require('../lib/crypto/crypto'); +var digest = require('../lib/crypto/digest'); +var random = require('../lib/crypto/random'); var WalletDB = require('../lib/wallet/walletdb'); var Address = require('../lib/primitives/address'); var MTX = require('../lib/primitives/mtx'); @@ -30,8 +31,8 @@ function nextBlock(height) { if (height == null) height = globalHeight++; - hash = crypto.hash256(encoding.U32(height)).toString('hex'); - prev = crypto.hash256(encoding.U32(height - 1)).toString('hex'); + hash = digest.hash256(encoding.U32(height)).toString('hex'); + prev = digest.hash256(encoding.U32(height - 1)).toString('hex'); return { hash: hash, @@ -46,7 +47,7 @@ function nextBlock(height) { function dummy(hash) { if (!hash) - hash = crypto.randomBytes(32).toString('hex'); + hash = random.randomBytes(32).toString('hex'); return Input.fromOutpoint(new Outpoint(hash, 0)); }