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 72ba13439ba52ff47133f1fee148cd51a36b8ac8..6b92a20f024294e7ff3a0f63de9edb3fd853bbb7 100644 --- a/router/java/src/net/i2p/router/crypto/ratchet/ECIESAEADEngine.java +++ b/router/java/src/net/i2p/router/crypto/ratchet/ECIESAEADEngine.java @@ -26,7 +26,6 @@ import net.i2p.data.PrivateKey; import net.i2p.data.PublicKey; import net.i2p.data.SessionKey; import net.i2p.data.SessionTag; -import net.i2p.data.i2np.DeliveryInstructions; import net.i2p.data.i2np.GarlicClove; import static net.i2p.router.crypto.ratchet.RatchetPayload.*; import net.i2p.router.RouterContext; @@ -563,16 +562,15 @@ public final class ECIESAEADEngine { * * @param target public key to which the data should be encrypted. * @param priv local private key to encrypt with, from the leaseset - * @param replyDI non-null to request an ack, or null - * @param callback may be null + * @param callback may be null, if non-null an ack will be requested (except NS/NSR) * @return encrypted data or null on failure * */ public byte[] encrypt(CloveSet cloves, PublicKey target, PrivateKey priv, - RatchetSKM keyManager, DeliveryInstructions replyDI, + RatchetSKM keyManager, ReplyCallback callback) { try { - return x_encrypt(cloves, target, priv, keyManager, replyDI, callback); + return x_encrypt(cloves, target, priv, keyManager, callback); } catch (Exception e) { _log.error("ECIES encrypt error", e); return null; @@ -580,7 +578,7 @@ public final class ECIESAEADEngine { } private byte[] x_encrypt(CloveSet cloves, PublicKey target, PrivateKey priv, - RatchetSKM keyManager, DeliveryInstructions replyDI, + RatchetSKM keyManager, ReplyCallback callback) { if (target.getType() != EncType.ECIES_X25519) throw new IllegalArgumentException(); @@ -594,8 +592,7 @@ public final class ECIESAEADEngine { if (re == null) { if (_log.shouldDebug()) _log.debug("Encrypting as NS to " + target); - // no ack in NS - return encryptNewSession(cloves, target, priv, keyManager, null, callback); + return encryptNewSession(cloves, target, priv, keyManager, callback); } HandshakeState state = re.key.getHandshakeState(); @@ -609,12 +606,11 @@ public final class ECIESAEADEngine { } if (_log.shouldDebug()) _log.debug("Encrypting as NSR to " + target + " with tag " + re.tag.toBase64()); - // no ack in NSR - return encryptNewSessionReply(cloves, target, state, re.tag, keyManager, null, callback); + return encryptNewSessionReply(cloves, target, state, re.tag, keyManager, callback); } if (_log.shouldDebug()) _log.debug("Encrypting as ES to " + target + " with key " + re.key + " and tag " + re.tag.toBase64()); - byte rv[] = encryptExistingSession(cloves, target, re, replyDI, callback, keyManager); + byte rv[] = encryptExistingSession(cloves, target, re, callback, keyManager); return rv; } @@ -633,12 +629,11 @@ public final class ECIESAEADEngine { * - 16 byte MAC * </pre> * - * @param replyDI non-null to request an ack, or null * @param callback may be null * @return encrypted data or null on failure */ private byte[] encryptNewSession(CloveSet cloves, PublicKey target, PrivateKey priv, - RatchetSKM keyManager, DeliveryInstructions replyDI, + RatchetSKM keyManager, ReplyCallback callback) { HandshakeState state; try { @@ -653,7 +648,7 @@ public final class ECIESAEADEngine { if (_log.shouldDebug()) _log.debug("State before encrypt new session: " + state); - byte[] payload = createPayload(cloves, cloves.getExpiration(), replyDI, null, null); + byte[] payload = createPayload(cloves, cloves.getExpiration(), false, null, null); byte[] enc = new byte[KEYLEN + KEYLEN + MACLEN + payload.length + MACLEN]; try { @@ -699,13 +694,12 @@ public final class ECIESAEADEngine { * </pre> * * @param state must have already been cloned - * @param replyDI non-null to request an ack, or null * @param callback may be null * @return encrypted data or null on failure */ private byte[] encryptNewSessionReply(CloveSet cloves, PublicKey target, HandshakeState state, RatchetSessionTag currentTag, RatchetSKM keyManager, - DeliveryInstructions replyDI, ReplyCallback callback) { + ReplyCallback callback) { if (_log.shouldDebug()) _log.debug("State before encrypt new session reply: " + state); byte[] tag = currentTag.getData(); @@ -713,7 +707,7 @@ public final class ECIESAEADEngine { if (_log.shouldDebug()) _log.debug("State after mixhash tag before encrypt new session reply: " + state); - byte[] payload = createPayload(cloves, 0, replyDI, null, null); + byte[] payload = createPayload(cloves, 0, false, null, null); // part 1 - tag and empty payload byte[] enc = new byte[TAGLEN + KEYLEN + MACLEN + payload.length + MACLEN]; @@ -773,17 +767,14 @@ public final class ECIESAEADEngine { * </pre> * * @param target only used if callback is non-null to register it - * @param replyDI non-null to request an ack, or null * @return encrypted data or null on failure */ private byte[] encryptExistingSession(CloveSet cloves, PublicKey target, RatchetEntry re, - DeliveryInstructions replyDI, ReplyCallback callback, + ReplyCallback callback, RatchetSKM keyManager) { - // TODO remove DI, just make it a boolean - if (ACKREQ_IN_ES && replyDI == null) - replyDI = new DeliveryInstructions(); + boolean ackreq = callback != null || ACKREQ_IN_ES; byte rawTag[] = re.tag.getData(); - byte[] payload = createPayload(cloves, 0, replyDI, re.nextKey, re.acksToSend); + byte[] payload = createPayload(cloves, 0, ackreq, re.nextKey, re.acksToSend); SessionKeyAndNonce key = re.key; int nonce = key.getNonce(); byte encr[] = encryptAEADBlock(rawTag, payload, key, nonce); @@ -813,7 +804,7 @@ public final class ECIESAEADEngine { */ public byte[] encrypt(CloveSet cloves, SessionKey key, RatchetSessionTag tag) { byte rawTag[] = tag.getData(); - byte[] payload = createPayload(cloves, 0, null, null, null); + byte[] payload = createPayload(cloves, 0, false, null, null); byte encr[] = encryptAEADBlock(rawTag, payload, key, 0); System.arraycopy(rawTag, 0, encr, 0, TAGLEN); return encr; @@ -917,9 +908,9 @@ public final class ECIESAEADEngine { _log.warn("ACK in NS/NSR?"); } - public void gotAckRequest(int id, DeliveryInstructions di) { + public void gotAckRequest() { if (_log.shouldDebug()) - _log.debug("Got ACK REQUEST block: " + id + " / " + di); + _log.debug("Got ACK REQUEST block"); ackRequested = true; } @@ -941,17 +932,17 @@ public final class ECIESAEADEngine { /** * @param expiration if greater than zero, add a DateTime block - * @param replyDI non-null to request an ack, or null + * @param ackreq to request an ack, must be false for NS/NSR * @param acksTOSend may be null */ private byte[] createPayload(CloveSet cloves, long expiration, - DeliveryInstructions replyDI, NextSessionKey nextKey, + boolean ackreq, NextSessionKey nextKey, List<Integer> acksToSend) { int count = cloves.getCloveCount(); int numblocks = count + 1; if (expiration > 0) numblocks++; - if (replyDI != null) + if (ackreq) numblocks++; if (nextKey != null) numblocks++; @@ -975,10 +966,9 @@ public final class ECIESAEADEngine { blocks.add(block); len += block.getTotalLength(); } - if (replyDI != null) { + if (ackreq) { // put after the cloves so recipient has any LS garlic - // ignore actual DI - Block block = new AckRequestBlock(0, null); + Block block = new AckRequestBlock(); 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 8619b3ba3673cb79e48b491a99f8ae48e284e37b..f0e4c505925e5962f435aad10f685d75961efd62 100644 --- a/router/java/src/net/i2p/router/crypto/ratchet/RatchetPayload.java +++ b/router/java/src/net/i2p/router/crypto/ratchet/RatchetPayload.java @@ -8,7 +8,6 @@ import java.util.List; import net.i2p.I2PAppContext; import net.i2p.data.DataFormatException; import net.i2p.data.DataHelper; -import net.i2p.data.i2np.DeliveryInstructions; import net.i2p.data.i2np.GarlicClove; import net.i2p.data.i2np.GarlicMessage; import net.i2p.data.i2np.I2NPMessage; @@ -32,8 +31,8 @@ class RatchetPayload { private static final int BLOCK_OPTIONS = 5; private static final int BLOCK_MSGNUM = 6; private static final int BLOCK_NEXTKEY = 7; - private static final int BLOCK_ACKKEY = 8; - private static final int BLOCK_REPLYDI = 9; + private static final int BLOCK_ACK = 8; + private static final int BLOCK_ACKREQ = 9; private static final int BLOCK_GARLIC = 11; private static final int BLOCK_PADDING = 254; @@ -71,7 +70,7 @@ class RatchetPayload { * @param di may be null * @since 0.9.46 */ - public void gotAckRequest(int id, DeliveryInstructions di); + public void gotAckRequest(); /** * For stats. @@ -154,10 +153,10 @@ class RatchetPayload { } break; - case BLOCK_ACKKEY: + case BLOCK_ACK: { if (len < 4 || (len % 4) != 0) - throw new IOException("Bad length for ACKKEY: " + len); + throw new IOException("Bad length for ACK: " + 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); @@ -166,20 +165,10 @@ class RatchetPayload { } break; - case BLOCK_REPLYDI: - { - if (len < 3) - throw new IOException("Bad length for REPLYDI: " + len); - 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); - } + case BLOCK_ACKREQ: + if (len < 1) + throw new IOException("Bad length for ACKREQ: " + len); + cb.gotAckRequest(); break; case BLOCK_TERMINATION: @@ -384,7 +373,7 @@ class RatchetPayload { private final byte[] data; public AckBlock(int keyID, int n) { - super(BLOCK_ACKKEY); + super(BLOCK_ACK); data = new byte[4]; DataHelper.toLong(data, 0, 2, keyID); DataHelper.toLong(data, 2, 2, n); @@ -394,7 +383,7 @@ class RatchetPayload { * @param acks each is id << 16 | n */ public AckBlock(List<Integer> acks) { - super(BLOCK_ACKKEY); + super(BLOCK_ACK); data = new byte[4 * acks.size()]; int i = 0; for (Integer a : acks) { @@ -417,33 +406,19 @@ class RatchetPayload { * @since 0.9.46 */ 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); - 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 AckRequestBlock() { + super(BLOCK_ACKREQ); + // flag is zero } public int getDataLength() { - return data.length; + return 1; } public int writeData(byte[] tgt, int off) { - System.arraycopy(data, 0, tgt, off, data.length); - return off + data.length; + tgt[off] = 0; + return off + 1; } } diff --git a/router/java/src/net/i2p/router/message/GarlicMessageBuilder.java b/router/java/src/net/i2p/router/message/GarlicMessageBuilder.java index 836d5fd03926f14098875f01b0fc09cce81aec21..9cd344134ea0586887d3858c0120b3d579ea332a 100644 --- a/router/java/src/net/i2p/router/message/GarlicMessageBuilder.java +++ b/router/java/src/net/i2p/router/message/GarlicMessageBuilder.java @@ -277,7 +277,6 @@ public class GarlicMessageBuilder { * @param config how/what to wrap * @param target public key of the location being garlic routed to (may be null if we * know the encryptKey and encryptTag) - * @param replyDI non-null to request an ack, or null * @param callback may be null * @return null if expired or on other errors * @throws IllegalArgumentException on error @@ -285,7 +284,7 @@ public class GarlicMessageBuilder { */ static GarlicMessage buildECIESMessage(RouterContext ctx, GarlicConfig config, PublicKey target, Hash from, SessionKeyManager skm, - DeliveryInstructions replyDI, ReplyCallback callback) { + ReplyCallback callback) { PublicKey key = config.getRecipientPublicKey(); if (key.getType() != EncType.ECIES_X25519) throw new IllegalArgumentException(); @@ -315,7 +314,7 @@ public class GarlicMessageBuilder { log.warn("No SKM for " + from.toBase32()); return null; } - byte encData[] = ctx.eciesEngine().encrypt(cloveSet, target, priv, rskm, replyDI, callback); + byte encData[] = ctx.eciesEngine().encrypt(cloveSet, target, priv, rskm, callback); if (encData == null) { if (log.shouldWarn()) log.warn("Encrypt fail for " + from.toBase32()); diff --git a/router/java/src/net/i2p/router/message/OutboundClientMessageJobHelper.java b/router/java/src/net/i2p/router/message/OutboundClientMessageJobHelper.java index 30079313e863c5c85b486dd708691e8924e57093..830ac5519a079bbf842bcabdb6be1453b8e52fda 100644 --- a/router/java/src/net/i2p/router/message/OutboundClientMessageJobHelper.java +++ b/router/java/src/net/i2p/router/message/OutboundClientMessageJobHelper.java @@ -130,27 +130,7 @@ class OutboundClientMessageJobHelper { return null; GarlicMessage msg; if (isECIES) { - DeliveryInstructions di; - if (requireAck) { - // setup reply DI - di = new DeliveryInstructions(); - if (bundledReplyLeaseSet != null) { - di.setDeliveryMode(DeliveryInstructions.DELIVERY_MODE_DESTINATION); - di.setDestination(from); - } else if (replyTunnel != null) { - di.setDeliveryMode(DeliveryInstructions.DELIVERY_MODE_TUNNEL); - TunnelId replyToTunnelId = replyTunnel.getReceiveTunnelId(0); - Hash replyToTunnelRouter = replyTunnel.getPeer(0); - di.setRouter(replyToTunnelRouter); - di.setTunnelId(replyToTunnelId); - } else { - // shouldn't happen - di = null; - } - } else { - di = null; - } - msg = GarlicMessageBuilder.buildECIESMessage(ctx, config, recipientPK, from, skm, di, callback); + msg = GarlicMessageBuilder.buildECIESMessage(ctx, config, recipientPK, from, skm, callback); } else { // no use sending tags unless we have a reply token set up already int tagsToSend = replyToken >= 0 ? (tagsToSendOverride > 0 ? tagsToSendOverride : skm.getTagsToSend()) : 0;