diff --git a/lib/bcoin/bip151.js b/lib/bcoin/bip151.js index a5ea0bea..e92390b5 100644 --- a/lib/bcoin/bip151.js +++ b/lib/bcoin/bip151.js @@ -203,7 +203,6 @@ BIP151Stream.prototype.encryptSize = function encryptSize(size) { var data = new Buffer(4); data.writeUInt32LE(size, 0, true); this.chacha.encrypt(data); - this.aead.aad(data); return data; }; @@ -215,7 +214,6 @@ BIP151Stream.prototype.encryptSize = function encryptSize(size) { BIP151Stream.prototype.decryptSize = function decryptSize(data) { data = data.slice(0, 4); - this.aead.aad(data); this.chacha.encrypt(data); return data.readUInt32LE(0, true); }; @@ -231,13 +229,23 @@ BIP151Stream.prototype.encrypt = function encrypt(data) { }; /** - * Decrypt payload with AEAD (update cipher and mac). + * Decrypt payload with AEAD (update cipher only). * @param {Buffer} data * @returns {Buffer} data */ BIP151Stream.prototype.decrypt = function decrypt(data) { - return this.aead.decrypt(data); + return this.aead.chacha20.encrypt(data); +}; + +/** + * Authenticate payload with AEAD (update mac only). + * @param {Buffer} data + * @returns {Buffer} data + */ + +BIP151Stream.prototype.auth = function auth(data) { + return this.aead.auth(data); }; /** @@ -318,20 +326,25 @@ BIP151Stream.prototype.feed = function feed(data) { if (data.length === 0) data = null; - this.decrypt(payload); - this.finish(); - this.sequence(); - this.pendingTotal = 0; this.pending.length = 0; this.hasHeader = false; this.waiting = 0; + // Authenticate payload before decrypting. + // This ensures the cipher state isn't altered + // if the payload integrity has been compromised. + this.auth(payload); + this.finish(); + if (!this.verify(tag)) { this.emit('error', new Error('Bad tag.')); continue; } + this.decrypt(payload); + this.sequence(); + p = bcoin.reader(payload, true); while (p.left()) { diff --git a/lib/bcoin/chachapoly.js b/lib/bcoin/chachapoly.js index fbee45c4..2f7c8ebb 100644 --- a/lib/bcoin/chachapoly.js +++ b/lib/bcoin/chachapoly.js @@ -573,6 +573,21 @@ AEAD.prototype.decrypt = function decrypt(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