I2P Address: [http://git.idk.i2p]

Skip to content
Snippets Groups Projects
Commit 6dd0b23c authored by zzz's avatar zzz
Browse files

Ratchet: Remove ID and DI from ACKREQ block

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