From 5c1700c2ab3cdbc87dd1374458fefa3f6bd9ce51 Mon Sep 17 00:00:00 2001 From: zzz Date: Fri, 20 Mar 2020 19:01:56 +0000 Subject: [PATCH] Ratchet: Make DI optional in ACK request Don't put ACK request in NS or NSR --- .../crypto/ratchet/ECIESAEADEngine.java | 11 ++++-- .../router/crypto/ratchet/RatchetPayload.java | 34 ++++++++++++++----- 2 files changed, 33 insertions(+), 12 deletions(-) diff --git a/router/java/src/net/i2p/router/crypto/ratchet/ECIESAEADEngine.java b/router/java/src/net/i2p/router/crypto/ratchet/ECIESAEADEngine.java index 743860592..19c74065b 100644 --- a/router/java/src/net/i2p/router/crypto/ratchet/ECIESAEADEngine.java +++ b/router/java/src/net/i2p/router/crypto/ratchet/ECIESAEADEngine.java @@ -583,7 +583,8 @@ public final class ECIESAEADEngine { if (re == null) { if (_log.shouldDebug()) _log.debug("Encrypting as NS to " + target); - return encryptNewSession(cloves, target, priv, keyManager, replyDI); + // no ack in NS + return encryptNewSession(cloves, target, priv, keyManager, null); } HandshakeState state = re.key.getHandshakeState(); @@ -597,7 +598,8 @@ public final class ECIESAEADEngine { } if (_log.shouldDebug()) _log.debug("Encrypting as NSR to " + target + " with tag " + re.tag.toBase64()); - return encryptNewSessionReply(cloves, target, state, re.tag, keyManager, replyDI); + // no ack in NSR + return encryptNewSessionReply(cloves, target, state, re.tag, keyManager, null); } if (_log.shouldDebug()) _log.debug("Encrypting as ES to " + target + " with key " + re.key + " and tag " + re.tag.toBase64()); @@ -812,6 +814,7 @@ public final class ECIESAEADEngine { public final List cloveSet = new ArrayList(3); public long datetime; public NextSessionKey nextKey; + public boolean ackRequested; public void gotDateTime(long time) { if (_log.shouldDebug()) @@ -846,6 +849,7 @@ public final class ECIESAEADEngine { public void gotAckRequest(int id, DeliveryInstructions di) { if (_log.shouldDebug()) _log.debug("Got ACK REQUEST block: " + di); + ackRequested = true; } public void gotTermination(int reason, long count) { @@ -890,7 +894,8 @@ public final class ECIESAEADEngine { } if (replyDI != null) { // put after the cloves so recipient has any LS garlic - Block block = new AckRequestBlock(0, replyDI); + // ignore actual DI + Block block = new AckRequestBlock(0, null); blocks.add(block); len += block.getTotalLength(); } diff --git a/router/java/src/net/i2p/router/crypto/ratchet/RatchetPayload.java b/router/java/src/net/i2p/router/crypto/ratchet/RatchetPayload.java index 0290131c4..836d1db44 100644 --- a/router/java/src/net/i2p/router/crypto/ratchet/RatchetPayload.java +++ b/router/java/src/net/i2p/router/crypto/ratchet/RatchetPayload.java @@ -68,6 +68,7 @@ class RatchetPayload { public void gotAck(int id, int n); /** + * @param di may be null * @since 0.9.46 */ public void gotAckRequest(int id, DeliveryInstructions di); @@ -148,7 +149,7 @@ class RatchetPayload { case BLOCK_ACKKEY: { if (len < 4 || (len % 4) != 0) - throw new IOException("Bad length for REPLYDI: " + len); + throw new IOException("Bad length for ACKKEY: " + len); for (int j = i; j < i + len; j += 4) { int id = (int) DataHelper.fromLong(payload, j, 2); int n = (int) DataHelper.fromLong(payload, j + 2, 2); @@ -159,11 +160,16 @@ class RatchetPayload { case BLOCK_REPLYDI: { - if (len < 6) + if (len < 3) throw new IOException("Bad length for REPLYDI: " + len); - int id = (int) DataHelper.fromLong(payload, i, 4); - DeliveryInstructions di = new DeliveryInstructions(); - di.readBytes(payload, i + 5); + int id = (int) DataHelper.fromLong(payload, i, 2); + DeliveryInstructions di; + if ((payload[2] & 0x01) != 0) { + di = new DeliveryInstructions(); + di.readBytes(payload, i + 3); + } else { + di = null; + } cb.gotAckRequest(id, di); } break; @@ -383,12 +389,22 @@ class RatchetPayload { public static class AckRequestBlock extends Block { private final byte[] data; + /** + * @param sessionID 0 - 65535 + * @param di may be null + */ public AckRequestBlock(int sessionID, DeliveryInstructions di) { super(BLOCK_REPLYDI); - data = new byte[5 + di.getSize()]; - DataHelper.toLong(data, 0, 4, sessionID); - // flag is zero - di.writeBytes(data, 5); + int len = 3; + if (di != null) + len += di.getSize(); + data = new byte[len]; + DataHelper.toLong(data, 0, 2, sessionID); + if (di != null) { + data[2] = 0x01; + di.writeBytes(data, 3); + } + // else flag is zero } public int getDataLength() {