forked from I2P_Developers/i2p.i2p
Ratchet: Increase callback timeout
- Mark tagsets after ratchet, and single tagsets, as acked so we don't go searching for the reverse tagset or adjust the expiration downward - Eliminate redundant split() calculation
This commit is contained in:
@ -509,17 +509,15 @@ public final class ECIESAEADEngine {
|
||||
_log.debug("State after decrypt new session reply: " + state);
|
||||
|
||||
// split()
|
||||
byte[] ck = state.getChainingKey();
|
||||
byte[] k_ab = new byte[32];
|
||||
byte[] k_ba = new byte[32];
|
||||
_hkdf.calculate(ck, ZEROLEN, k_ab, k_ba, 0);
|
||||
// Noise does it too but it trashes the keys
|
||||
SplitKeys split = new SplitKeys(state, _hkdf);
|
||||
CipherStatePair ckp = state.split();
|
||||
CipherState rcvr = ckp.getReceiver();
|
||||
byte[] hash = state.getHandshakeHash();
|
||||
|
||||
// part 2 - payload
|
||||
byte[] encpayloadkey = new byte[32];
|
||||
_hkdf.calculate(k_ba, ZEROLEN, INFO_6, encpayloadkey);
|
||||
_hkdf.calculate(split.k_ba.getData(), ZEROLEN, INFO_6, encpayloadkey);
|
||||
rcvr.initializeKey(encpayloadkey, 0);
|
||||
byte[] payload = new byte[data.length - (TAGLEN + KEYLEN + MACLEN + MACLEN)];
|
||||
try {
|
||||
@ -561,7 +559,7 @@ public final class ECIESAEADEngine {
|
||||
|
||||
// tell the SKM
|
||||
PublicKey bob = new PublicKey(EncType.ECIES_X25519, bobPK);
|
||||
keyManager.updateSession(bob, oldState, state, null);
|
||||
keyManager.updateSession(bob, oldState, state, null, split);
|
||||
|
||||
if (pc.cloveSet.isEmpty()) {
|
||||
if (_log.shouldWarn())
|
||||
@ -842,17 +840,15 @@ public final class ECIESAEADEngine {
|
||||
eph.getEncodedPublicKey(enc, TAGLEN);
|
||||
|
||||
// split()
|
||||
byte[] ck = state.getChainingKey();
|
||||
byte[] k_ab = new byte[32];
|
||||
byte[] k_ba = new byte[32];
|
||||
_hkdf.calculate(ck, ZEROLEN, k_ab, k_ba, 0);
|
||||
// Noise does it too but it trashes the keys
|
||||
SplitKeys split = new SplitKeys(state, _hkdf);
|
||||
CipherStatePair ckp = state.split();
|
||||
CipherState sender = ckp.getSender();
|
||||
byte[] hash = state.getHandshakeHash();
|
||||
|
||||
// part 2 - payload
|
||||
byte[] encpayloadkey = new byte[32];
|
||||
_hkdf.calculate(k_ba, ZEROLEN, INFO_6, encpayloadkey);
|
||||
_hkdf.calculate(split.k_ba.getData(), ZEROLEN, INFO_6, encpayloadkey);
|
||||
sender.initializeKey(encpayloadkey, 0);
|
||||
try {
|
||||
sender.encryptWithAd(hash, payload, 0, enc, TAGLEN + KEYLEN + MACLEN, payload.length);
|
||||
@ -862,7 +858,7 @@ public final class ECIESAEADEngine {
|
||||
return null;
|
||||
}
|
||||
// tell the SKM
|
||||
keyManager.updateSession(target, null, state, callback);
|
||||
keyManager.updateSession(target, null, state, callback, split);
|
||||
|
||||
return enc;
|
||||
}
|
||||
|
@ -222,7 +222,8 @@ public class RatchetSKM extends SessionKeyManager implements SessionTagListener
|
||||
* @param oldState null for inbound, pre-clone for outbound
|
||||
* @return true if this was the first NSR received
|
||||
*/
|
||||
boolean updateSession(PublicKey target, HandshakeState oldState, HandshakeState state, ReplyCallback callback) {
|
||||
boolean updateSession(PublicKey target, HandshakeState oldState, HandshakeState state,
|
||||
ReplyCallback callback, SplitKeys split) {
|
||||
EncType type = target.getType();
|
||||
if (type != EncType.ECIES_X25519)
|
||||
throw new IllegalArgumentException("Bad public key type " + type);
|
||||
@ -238,7 +239,7 @@ public class RatchetSKM extends SessionKeyManager implements SessionTagListener
|
||||
// TODO can we recover?
|
||||
return false;
|
||||
}
|
||||
sess.updateSession(state, callback);
|
||||
sess.updateSession(state, callback, split);
|
||||
} else {
|
||||
// we are Alice, NSR received
|
||||
if (_log.shouldInfo())
|
||||
@ -258,7 +259,7 @@ public class RatchetSKM extends SessionKeyManager implements SessionTagListener
|
||||
if (oldState.equals(pstate)) {
|
||||
if (!found) {
|
||||
found = true;
|
||||
sess.updateSession(state, null);
|
||||
sess.updateSession(state, null, split);
|
||||
boolean ok = addSession(sess, false);
|
||||
if (_log.shouldDebug()) {
|
||||
if (ok)
|
||||
@ -966,12 +967,8 @@ public class RatchetSKM extends SessionKeyManager implements SessionTagListener
|
||||
* @param state current state
|
||||
* @param callback only for inbound (NSR sent by Bob), may be null
|
||||
*/
|
||||
void updateSession(HandshakeState state, ReplyCallback callback) {
|
||||
byte[] ck = state.getChainingKey();
|
||||
byte[] k_ab = new byte[32];
|
||||
byte[] k_ba = new byte[32];
|
||||
_hkdf.calculate(ck, ZEROLEN, k_ab, k_ba, 0);
|
||||
SessionKey rk = new SessionKey(ck);
|
||||
void updateSession(HandshakeState state, ReplyCallback callback, SplitKeys split) {
|
||||
SessionKey rk = split.ck;
|
||||
long now = _context.clock().now();
|
||||
_lastUsed = now;
|
||||
_lastReceived = now;
|
||||
@ -979,15 +976,17 @@ public class RatchetSKM extends SessionKeyManager implements SessionTagListener
|
||||
if (isInbound) {
|
||||
// We are Bob
|
||||
// This is an OUTBOUND NSR, we make an INBOUND tagset for ES
|
||||
RatchetTagSet tagset_ab = new RatchetTagSet(_hkdf, RatchetSKM.this, _target, rk, new SessionKey(k_ab),
|
||||
RatchetTagSet tagset_ab = new RatchetTagSet(_hkdf, RatchetSKM.this, _target, rk, split.k_ab,
|
||||
now, 0, -1,
|
||||
MIN_RCV_WINDOW_ES, MAX_RCV_WINDOW_ES);
|
||||
// and a pending outbound one
|
||||
RatchetTagSet tagset_ba = new RatchetTagSet(_hkdf, rk, new SessionKey(k_ba),
|
||||
// TODO - We could just save rk and k_ba, and defer
|
||||
// creation of the OB ES tagset to firstTagConsumed() below
|
||||
RatchetTagSet tagset_ba = new RatchetTagSet(_hkdf, rk, split.k_ba,
|
||||
now, 0, -1);
|
||||
if (_log.shouldDebug()) {
|
||||
_log.debug("Update IB Session, rk = " + rk + " tk = " + Base64.encode(k_ab) + " ES tagset:\n" + tagset_ab);
|
||||
_log.debug("Pending OB Session, rk = " + rk + " tk = " + Base64.encode(k_ba) + " ES tagset:\n" + tagset_ba);
|
||||
_log.debug("Update IB Session, rk = " + rk + " tk = " + split.k_ab + " ES tagset:\n" + tagset_ab);
|
||||
_log.debug("Pending OB Session, rk = " + rk + " tk = " + split.k_ba + " ES tagset:\n" + tagset_ba);
|
||||
}
|
||||
synchronized (_unackedTagSets) {
|
||||
_unackedTagSets.add(tagset_ba);
|
||||
@ -996,15 +995,15 @@ public class RatchetSKM extends SessionKeyManager implements SessionTagListener
|
||||
} else {
|
||||
// We are Alice
|
||||
// This is an INBOUND NSR, we make an OUTBOUND tagset for ES
|
||||
RatchetTagSet tagset_ab = new RatchetTagSet(_hkdf, rk, new SessionKey(k_ab),
|
||||
RatchetTagSet tagset_ab = new RatchetTagSet(_hkdf, rk, split.k_ab,
|
||||
now, 0, -1);
|
||||
// and an inbound one
|
||||
RatchetTagSet tagset_ba = new RatchetTagSet(_hkdf, RatchetSKM.this, _target, rk, new SessionKey(k_ba),
|
||||
RatchetTagSet tagset_ba = new RatchetTagSet(_hkdf, RatchetSKM.this, _target, rk, split.k_ba,
|
||||
now, 0, -1,
|
||||
MIN_RCV_WINDOW_ES, MAX_RCV_WINDOW_ES);
|
||||
if (_log.shouldDebug()) {
|
||||
_log.debug("Update OB Session, rk = " + rk + " tk = " + Base64.encode(k_ab) + " ES tagset:\n" + tagset_ab);
|
||||
_log.debug("Update IB Session, rk = " + rk + " tk = " + Base64.encode(k_ba) + " ES tagset:\n" + tagset_ba);
|
||||
_log.debug("Update OB Session, rk = " + rk + " tk = " + split.k_ab + " ES tagset:\n" + tagset_ab);
|
||||
_log.debug("Update IB Session, rk = " + rk + " tk = " + split.k_ba + " ES tagset:\n" + tagset_ba);
|
||||
}
|
||||
synchronized (_unackedTagSets) {
|
||||
_tagSet = tagset_ab;
|
||||
|
@ -173,6 +173,9 @@ class RatchetTagSet implements TagSetHandle {
|
||||
_sessionTags = null;
|
||||
_sessionKeys = null;
|
||||
}
|
||||
// prevent adjusted expiration and search for matching OB ts
|
||||
if (tagsetid > 0 && tagsetid <= 65535)
|
||||
_acked = true;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -200,6 +203,8 @@ class RatchetTagSet implements TagSetHandle {
|
||||
hkdf = null;
|
||||
_sessionTags = null;
|
||||
_sessionKeys = null;
|
||||
// prevent adjusted expiration and search for matching OB ts
|
||||
_acked = true;
|
||||
}
|
||||
|
||||
public void clear() {
|
||||
|
29
router/java/src/net/i2p/router/crypto/ratchet/SplitKeys.java
Normal file
29
router/java/src/net/i2p/router/crypto/ratchet/SplitKeys.java
Normal file
@ -0,0 +1,29 @@
|
||||
package net.i2p.router.crypto.ratchet;
|
||||
|
||||
import com.southernstorm.noise.protocol.HandshakeState;
|
||||
|
||||
import net.i2p.crypto.HKDF;
|
||||
import net.i2p.data.SessionKey;
|
||||
|
||||
/**
|
||||
* Standard Noise split().
|
||||
* Passed from the engine to the SKM so we don't have
|
||||
* to do it twice.
|
||||
*
|
||||
* @since 0.9.46
|
||||
*/
|
||||
class SplitKeys {
|
||||
|
||||
private static final byte[] ZEROLEN = new byte[0];
|
||||
public final SessionKey ck, k_ab, k_ba;
|
||||
|
||||
public SplitKeys(HandshakeState state, HKDF hkdf) {
|
||||
byte[] ckd = state.getChainingKey();
|
||||
byte[] ab = new byte[32];
|
||||
byte[] ba = new byte[32];
|
||||
hkdf.calculate(ckd, ZEROLEN, ab, ba, 0);
|
||||
ck = new SessionKey(ckd);
|
||||
k_ab = new SessionKey(ab);
|
||||
k_ba = new SessionKey(ba);
|
||||
}
|
||||
}
|
@ -147,6 +147,8 @@ public class OutboundClientMessageOneShotJob extends JobImpl {
|
||||
private final static long LS_LOOKUP_TIMEOUT = 15*1000;
|
||||
private final static long OVERALL_TIMEOUT_NOLS_MIN = OVERALL_TIMEOUT_MS_MIN + LS_LOOKUP_TIMEOUT;
|
||||
private final static long REPLY_TIMEOUT_MS_MIN = OVERALL_TIMEOUT_MS_DEFAULT - 5*1000;
|
||||
// callback timeout. Longer so we can have success-after-failure
|
||||
private final static long RATCHET_REPLY_TIMEOUT_MS_MIN = 30*1000;
|
||||
|
||||
/**
|
||||
* NOTE: Changed as of 0.9.2.
|
||||
@ -1152,8 +1154,8 @@ public class OutboundClientMessageOneShotJob extends JobImpl {
|
||||
}
|
||||
|
||||
public long getExpiration() {
|
||||
// same as SendTimeoutJob
|
||||
return Math.max(_overallExpiration, _start + REPLY_TIMEOUT_MS_MIN);
|
||||
// longer timeout so we can have success-after-failure via ratchet
|
||||
return Math.max(_overallExpiration, _start + RATCHET_REPLY_TIMEOUT_MS_MIN);
|
||||
}
|
||||
|
||||
public void onReply() {
|
||||
|
Reference in New Issue
Block a user