bip151: fix rekeying. replicate openssh more.

This commit is contained in:
Christopher Jeffrey 2016-07-26 01:08:42 -07:00
parent 4af5273c0e
commit f37946abb7
No known key found for this signature in database
GPG Key ID: 8962AB9DE6666BBD
3 changed files with 31 additions and 23 deletions

View File

@ -75,35 +75,45 @@ BIP151Stream.prototype.init = function init(publicKey) {
this.aead.init(this.k2, this.iv());
this.aead.aad(this.sid);
this.lastRekey = utils.ms();
this.lastRekey = utils.now();
};
BIP151Stream.prototype.maybeRekey = function maybeRekey(data) {
var now = utils.now();
this.processed += data.length;
if (this.processed >= this.highWaterMark) {
if (now > this.lastRekey + 10
|| this.processed >= this.highWaterMark) {
this.lastRekey = utils.now();
this.processed -= this.highWaterMark;
this.rekey();
this.emit('rekey');
this.rekey();
}
};
BIP151Stream.prototype.rekey = function rekey() {
assert(this.prk, 'Cannot rekey before initialization.');
// All state is reinitialized
// aside from the sequence number.
this.k1 = utils.hash256(this.k1);
this.k2 = utils.hash256(this.k2);
this.seq = 0;
this.chacha.init(this.k1, this.iv());
this.aead.init(this.k2, this.iv());
this.aead.aad(this.sid);
this.lastRekey = utils.ms();
};
BIP151Stream.prototype.sequence = function sequence() {
this.seq++;
// Wrap sequence number a la openssh.
if (this.seq === 0xffffffff)
this.seq = 0;
// State of the ciphers is
// unaltered aside from the iv.
this.chacha.init(null, this.iv());
this.aead.init(null, this.iv());
this.aead.aad(this.sid);
@ -152,8 +162,6 @@ BIP151Stream.prototype.verify = function verify(tag) {
BIP151Stream.prototype.feed = function feed(data) {
var chunk, payload, tag, p, cmd, body;
this.maybeRekey(data);
while (data) {
if (!this.hasHeader) {
this.pendingHeaderTotal += data.length;
@ -246,13 +254,13 @@ BIP151Stream.prototype.packet = function packet(cmd, body) {
packet = new Buffer(4 + payload.length + 16);
this.maybeRekey(packet);
this.encryptSize(payload.length).copy(packet, 0);
this.encrypt(payload).copy(packet, 4);
this.finish().copy(packet, 4 + payload.length);
this.sequence();
this.maybeRekey(packet);
return packet;
};
@ -263,7 +271,7 @@ function BIP151(cipher) {
EventEmitter.call(this);
this.input = new BIP151Stream(cipher);
this.output = null;
this.output = new BIP151Stream(cipher);
this.initReceived = false;
this.ackReceived = false;
@ -282,7 +290,7 @@ utils.inherits(BIP151, EventEmitter);
BIP151.prototype._init = function _init() {
var self = this;
this.input.on('rekey', function() {
this.output.on('rekey', function() {
self.emit('rekey');
});
@ -320,7 +328,7 @@ BIP151.prototype.encack = function encack(data) {
if (utils.equal(publicKey, constants.ZERO_KEY)) {
assert(this.handshake, 'No initialization before rekey.');
this.output.rekey();
this.input.rekey();
return;
}
@ -338,10 +346,11 @@ BIP151.prototype.encack = function encack(data) {
BIP151.prototype.encinit = function encinit(data) {
var p = bcoin.reader(data);
var publicKey = p.readBytes(33);
var cipher = p.readU8();
assert(!this.initReceived, 'Already initialized.');
assert(cipher === this.output.cipher, 'Cipher mismatch.');
this.output = new BIP151Stream(p.readU8());
this.output.init(publicKey);
this.initReceived = true;

View File

@ -241,6 +241,7 @@ Peer.prototype._init = function init() {
self._error(err, true);
});
this.bip151.on('rekey', function() {
self.logger.debug('Rekeying with peer (%s).', self.hostname);
self.write(self.framer.encack(self.bip151.toRekey()));
});
}

View File

@ -85,7 +85,7 @@ describe('BIP151', function() {
it('client should rekey', function() {
var rekeyed = false;
var bytes = client.input.processed;
var bytes = client.output.processed;
client.once('rekey', function() {
rekeyed = true;
@ -101,15 +101,13 @@ describe('BIP151', function() {
});
// Force a rekey after 1gb processed.
client.input.maybeRekey({ length: 1024 * (1 << 20) });
client.output.maybeRekey({ length: 1024 * (1 << 20) });
utils.nextTick(function() {
assert(rekeyed);
assert(rekeyed);
// Reset so as not to mess up
// the symmetry of client and server.
client.input.processed = bytes + 33 + 31;
});
// Reset so as not to mess up
// the symmetry of client and server.
client.output.processed = bytes + 33 + 31;
});
it('should encrypt payload from client to server after rekey', function() {