diff --git a/lib/bcoin/bip151.js b/lib/bcoin/bip151.js index f462b084..7646fe46 100644 --- a/lib/bcoin/bip151.js +++ b/lib/bcoin/bip151.js @@ -95,6 +95,7 @@ utils.inherits(BIP151Stream, EventEmitter); BIP151Stream.prototype.init = function init(publicKey) { var p = bcoin.writer(); + var iv; this.publicKey = publicKey; this.secret = bcoin.ec.ecdh(this.publicKey, this.privateKey); @@ -110,8 +111,10 @@ BIP151Stream.prototype.init = function init(publicKey) { this.seqHi = 0; this.seqLo = 0; - this.chacha.init(this.k1, this.iv()); - this.aead.init(this.k2, this.iv()); + iv = this.iv(); + + this.chacha.init(this.k1, iv); + this.aead.init(this.k2, iv); this.lastRekey = utils.now(); }; @@ -142,6 +145,8 @@ BIP151Stream.prototype.maybeRekey = function maybeRekey(data) { */ BIP151Stream.prototype.rekey = function rekey() { + var iv; + assert(this.prk, 'Cannot rekey before initialization.'); // All state is reinitialized @@ -149,8 +154,10 @@ BIP151Stream.prototype.rekey = function rekey() { this.k1 = utils.hash256(this.k1); this.k2 = utils.hash256(this.k2); - this.chacha.init(this.k1, this.iv()); - this.aead.init(this.k2, this.iv()); + iv = this.iv(); + + this.chacha.init(this.k1, iv); + this.aead.init(this.k2, iv); }; /** @@ -161,6 +168,8 @@ BIP151Stream.prototype.rekey = function rekey() { */ BIP151Stream.prototype.sequence = function sequence() { + var iv; + // Wrap sequence number a la openssh. if (++this.seqLo === 0x100000000) { this.seqLo = 0; @@ -168,10 +177,12 @@ BIP151Stream.prototype.sequence = function sequence() { this.seqHi = 0; } + iv = this.iv(); + // State of the ciphers is // unaltered aside from the iv. - this.chacha.init(null, this.iv()); - this.aead.init(null, this.iv()); + this.chacha.init(null, iv); + this.aead.init(null, iv); }; /** @@ -179,12 +190,12 @@ BIP151Stream.prototype.sequence = function sequence() { * @returns {Buffer} */ -BIP151Stream.prototype.iv = function iv() { - var p = bcoin.writer(); - p.writeU32(this.seqLo); - p.writeU32(this.seqHi); - p.writeU32(0); - return p.render(); +BIP151Stream.prototype.iv = function _iv() { + var iv = new Buffer(12); + iv.writeUInt32LE(this.seqLo, 0, true); + iv.writeUInt32LE(this.seqHi, 4, true); + iv.writeUInt32LE(0, 8, true); + return iv; }; /** @@ -289,7 +300,7 @@ BIP151Stream.prototype.feed = function feed(data) { if (this.pendingHeaderTotal < 4) break; - chunk = Buffer.concat(this.pendingHeader); + chunk = concat(this.pendingHeader); this.pendingHeaderTotal = 0; this.pendingHeader.length = 0; @@ -321,7 +332,7 @@ BIP151Stream.prototype.feed = function feed(data) { if (this.pendingTotal < this.waiting) break; - chunk = Buffer.concat(this.pending); + chunk = concat(this.pending); payload = chunk.slice(0, this.waiting - 16); tag = chunk.slice(this.waiting - 16, this.waiting); data = chunk.slice(this.waiting); @@ -637,6 +648,16 @@ BIP151.prototype.packet = function packet(cmd, body) { return this.output.packet(cmd, body); }; +/* + * Helpers + */ + +function concat(buffers) { + return buffers.length > 1 + ? Buffer.concat(buffers) + : buffers[0]; +} + /* * Expose */