forked from I2P_Developers/i2p.i2p
Ratchet: Remove ID and DI from ACKREQ block
Use callback != null to specify request for ack
This commit is contained in:
@ -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();
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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());
|
||||
|
@ -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;
|
||||
|
Reference in New Issue
Block a user