bip151: fix rekeying. replicate openssh more.
This commit is contained in:
parent
4af5273c0e
commit
f37946abb7
@ -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;
|
||||
|
||||
@ -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()));
|
||||
});
|
||||
}
|
||||
|
||||
@ -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() {
|
||||
|
||||
Loading…
Reference in New Issue
Block a user