forked from I2P_Developers/i2p.i2p
Tunnels: Changes for new build messages (Prop. 157)
- Remove ITBM, change record length from 236 to 218 bytes - Fix check of blank record in BuildReplyHandler - Fix offset constants for short record in BuildRequestRecord - Fix BuildMessageTestStandalone test 6 (short inbound) - ITBM class removal TODO
This commit is contained in:
@@ -94,7 +94,7 @@ import net.i2p.router.RouterContext;
|
||||
*
|
||||
* ECIES short record format, ref: proposal 157:
|
||||
*
|
||||
* Holds the unencrypted 172-byte tunnel request record,
|
||||
* Holds the unencrypted 154-byte tunnel request record,
|
||||
* with a constructor for ECIES decryption and a method for ECIES encryption.
|
||||
* Iterative AES encryption/decryption is done elsewhere.
|
||||
*
|
||||
@@ -111,15 +111,15 @@ import net.i2p.router.RouterContext;
|
||||
* bytes 52-55: next message ID
|
||||
* bytes 56-x: tunnel build options (Mapping)
|
||||
* bytes x-x: other data as implied by flags or options
|
||||
* bytes x-171: random padding
|
||||
* bytes x-153: random padding
|
||||
* </pre>
|
||||
*
|
||||
* Encrypted:
|
||||
* <pre>
|
||||
* bytes 0-15: Hop's truncated identity hash
|
||||
* bytes 16-47: Sender's ephemeral X25519 public key
|
||||
* bytes 48-219: ChaCha20 encrypted BuildRequestRecord
|
||||
* bytes 220-235: Poly1305 MAC
|
||||
* bytes 48-201: ChaCha20 encrypted BuildRequestRecord
|
||||
* bytes 202-217: Poly1305 MAC
|
||||
* </pre>
|
||||
*
|
||||
*/
|
||||
@@ -189,10 +189,11 @@ public class BuildRequestRecord {
|
||||
private static final int OFF_FLAG_EC_SHORT = OFF_SEND_IDENT_EC + Hash.HASH_LENGTH;
|
||||
private static final int OFF_LAYER_ENC_TYPE = OFF_FLAG_EC_SHORT + 3;
|
||||
private static final int OFF_REQ_TIME_EC_SHORT = OFF_LAYER_ENC_TYPE + 1;
|
||||
private static final int OFF_EXPIRATION_SHORT = OFF_REQ_TIME_EC + 4;
|
||||
private static final int OFF_SEND_MSG_ID_EC_SHORT = OFF_EXPIRATION + 4;
|
||||
private static final int OFF_EXPIRATION_SHORT = OFF_REQ_TIME_EC_SHORT + 4;
|
||||
private static final int OFF_SEND_MSG_ID_EC_SHORT = OFF_EXPIRATION_SHORT + 4;
|
||||
private static final int OFF_OPTIONS_SHORT = OFF_SEND_MSG_ID_EC_SHORT + 4;
|
||||
private static final int LENGTH_EC_SHORT = 172;
|
||||
// 16 byte trunc. hash, 32 byte eph. key, 16 byte MAC
|
||||
private static final int LENGTH_EC_SHORT = ShortTunnelBuildMessage.SHORT_RECORD_SIZE - (16 + 32 + 16);
|
||||
private static final int MAX_OPTIONS_LENGTH_SHORT = LENGTH_EC_SHORT - OFF_OPTIONS_SHORT; // includes options length
|
||||
|
||||
private static final boolean TEST = false;
|
||||
@@ -644,7 +645,7 @@ public class BuildRequestRecord {
|
||||
* @param nextMsgId message ID to use when sending on to the next hop (or for the reply)
|
||||
* @param isInGateway are we the gateway of an inbound tunnel?
|
||||
* @param isOutEndpoint are we the endpoint of an outbound tunnel?
|
||||
* @param options 116 bytes max when serialized
|
||||
* @param options 98 bytes max when serialized
|
||||
* @since 0.9.51
|
||||
* @throws IllegalArgumentException if options too long
|
||||
*/
|
||||
|
||||
@@ -439,9 +439,6 @@ public abstract class I2NPMessageImpl implements I2NPMessage {
|
||||
case VariableTunnelBuildReplyMessage.MESSAGE_TYPE:
|
||||
return new VariableTunnelBuildReplyMessage(context);
|
||||
// since 0.9.51
|
||||
case InboundTunnelBuildMessage.MESSAGE_TYPE:
|
||||
return new InboundTunnelBuildMessage(context);
|
||||
// since 0.9.51
|
||||
case OutboundTunnelBuildReplyMessage.MESSAGE_TYPE:
|
||||
return new OutboundTunnelBuildReplyMessage(context);
|
||||
// since 0.9.51
|
||||
|
||||
@@ -10,7 +10,7 @@ import net.i2p.I2PAppContext;
|
||||
*/
|
||||
public class ShortTunnelBuildMessage extends TunnelBuildMessage {
|
||||
public static final int MESSAGE_TYPE = 25;
|
||||
public static final int SHORT_RECORD_SIZE = 236;
|
||||
public static final int SHORT_RECORD_SIZE = 218;
|
||||
|
||||
/** zero record count, will be set with readMessage() */
|
||||
public ShortTunnelBuildMessage(I2PAppContext context) {
|
||||
|
||||
@@ -79,7 +79,6 @@ class OutboundGatewayMessage extends PendingGatewayMessage implements CDPQEntry
|
||||
// these shouldn't go into a OBGW
|
||||
case DatabaseSearchReplyMessage.MESSAGE_TYPE:
|
||||
case DataMessage.MESSAGE_TYPE:
|
||||
case InboundTunnelBuildMessage.MESSAGE_TYPE:
|
||||
case OutboundTunnelBuildReplyMessage.MESSAGE_TYPE:
|
||||
case TunnelBuildReplyMessage.MESSAGE_TYPE:
|
||||
case TunnelDataMessage.MESSAGE_TYPE:
|
||||
|
||||
@@ -11,7 +11,6 @@ import net.i2p.data.DataHelper;
|
||||
import net.i2p.data.Hash;
|
||||
import net.i2p.data.TunnelId;
|
||||
import net.i2p.data.i2np.I2NPMessage;
|
||||
import net.i2p.data.i2np.InboundTunnelBuildMessage;
|
||||
import net.i2p.data.i2np.OutboundTunnelBuildReplyMessage;
|
||||
import net.i2p.data.i2np.ShortTunnelBuildMessage;
|
||||
import net.i2p.data.i2np.TunnelBuildMessage;
|
||||
@@ -785,7 +784,7 @@ public class TunnelDispatcher implements Service {
|
||||
} else if (loc == Location.IBGW) {
|
||||
// we don't need to check for VTBM/TBM as that happens at tunnel creation
|
||||
if (type == VariableTunnelBuildReplyMessage.MESSAGE_TYPE || type == TunnelBuildReplyMessage.MESSAGE_TYPE ||
|
||||
type == OutboundTunnelBuildReplyMessage.MESSAGE_TYPE || type == InboundTunnelBuildMessage.MESSAGE_TYPE)
|
||||
type == OutboundTunnelBuildReplyMessage.MESSAGE_TYPE)
|
||||
factor = 1 / (1.5f * 1.5f * 1.5f);
|
||||
else
|
||||
factor = 1 / 1.5f;
|
||||
|
||||
@@ -19,7 +19,6 @@ import net.i2p.data.i2np.BuildRequestRecord;
|
||||
import net.i2p.data.i2np.BuildResponseRecord;
|
||||
import net.i2p.data.i2np.EncryptedBuildRecord;
|
||||
import net.i2p.data.i2np.I2NPMessage;
|
||||
import net.i2p.data.i2np.InboundTunnelBuildMessage;
|
||||
import net.i2p.data.i2np.OutboundTunnelBuildReplyMessage;
|
||||
import net.i2p.data.i2np.ShortTunnelBuildMessage;
|
||||
import net.i2p.data.i2np.ShortTunnelBuildReplyMessage;
|
||||
@@ -173,7 +172,6 @@ class BuildHandler implements Runnable {
|
||||
ctx.inNetMessagePool().registerHandlerJobBuilder(TunnelBuildReplyMessage.MESSAGE_TYPE, tbrmhjb);
|
||||
ctx.inNetMessagePool().registerHandlerJobBuilder(VariableTunnelBuildMessage.MESSAGE_TYPE, tbmhjb);
|
||||
ctx.inNetMessagePool().registerHandlerJobBuilder(VariableTunnelBuildReplyMessage.MESSAGE_TYPE, tbrmhjb);
|
||||
ctx.inNetMessagePool().registerHandlerJobBuilder(InboundTunnelBuildMessage.MESSAGE_TYPE, tbmhjb);
|
||||
ctx.inNetMessagePool().registerHandlerJobBuilder(ShortTunnelBuildMessage.MESSAGE_TYPE, tbmhjb);
|
||||
ctx.inNetMessagePool().registerHandlerJobBuilder(OutboundTunnelBuildReplyMessage.MESSAGE_TYPE, tbrmhjb);
|
||||
}
|
||||
@@ -736,21 +734,6 @@ class BuildHandler implements Runnable {
|
||||
_log.warn("Dropping build request, we are the previous hop: " + req);
|
||||
return;
|
||||
}
|
||||
if (state.msg.getType() == InboundTunnelBuildMessage.MESSAGE_TYPE) {
|
||||
// can only be at IBGW
|
||||
_context.statManager().addRateData("tunnel.rejectHostile", 1);
|
||||
if (_log.shouldWarn())
|
||||
_log.warn("Dropping ITBM, we are not IBGW: " + req);
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
if (state.msg.getType() == ShortTunnelBuildMessage.MESSAGE_TYPE) {
|
||||
// cannot be at IBGW
|
||||
_context.statManager().addRateData("tunnel.rejectHostile", 1);
|
||||
if (_log.shouldWarn())
|
||||
_log.warn("Dropping STBM, we are IBGW: " + req);
|
||||
return;
|
||||
}
|
||||
}
|
||||
if ((!isOutEnd) && (!isInGW)) {
|
||||
// Previous and next hop the same? Don't help somebody be evil. Drop it without a reply.
|
||||
@@ -997,33 +980,13 @@ class BuildHandler implements Runnable {
|
||||
}
|
||||
int records = state.msg.getRecordCount();
|
||||
int ourSlot = -1;
|
||||
ShortTunnelBuildMessage stbm = null;
|
||||
if (state.msg.getType() == InboundTunnelBuildMessage.MESSAGE_TYPE) {
|
||||
if (!HANDLE_SHORT) {
|
||||
if (_log.shouldWarn())
|
||||
_log.warn("Unsupported ITBM");
|
||||
return;
|
||||
}
|
||||
// IBGW only (enforced above)
|
||||
// Create a ShortTunnelBuildMessage and populate it for sending
|
||||
InboundTunnelBuildMessage itbm = (InboundTunnelBuildMessage) state.msg;
|
||||
ourSlot = itbm.getPlaintextSlot();
|
||||
stbm = new ShortTunnelBuildMessage(_context, records);
|
||||
for (int j = 0; j < records; j++) {
|
||||
if (j == ourSlot)
|
||||
stbm.setRecord(j, reply);
|
||||
else
|
||||
stbm.setRecord(j, itbm.getRecord(j));
|
||||
}
|
||||
} else {
|
||||
for (int j = 0; j < records; j++) {
|
||||
if (state.msg.getRecord(j) == null) {
|
||||
ourSlot = j;
|
||||
if (!(isOutEnd && state.msg.getType() == ShortTunnelBuildMessage.MESSAGE_TYPE))
|
||||
state.msg.setRecord(j, reply);
|
||||
// else reply will be sent in plaintext
|
||||
break;
|
||||
}
|
||||
for (int j = 0; j < records; j++) {
|
||||
if (state.msg.getRecord(j) == null) {
|
||||
ourSlot = j;
|
||||
if (!(isOutEnd && state.msg.getType() == ShortTunnelBuildMessage.MESSAGE_TYPE))
|
||||
state.msg.setRecord(j, reply);
|
||||
// else reply will be sent in plaintext
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1035,11 +998,7 @@ class BuildHandler implements Runnable {
|
||||
// now actually send the response
|
||||
long expires = now + NEXT_HOP_SEND_TIMEOUT;
|
||||
if (!isOutEnd) {
|
||||
TunnelBuildMessage nextMessage;
|
||||
if (stbm != null)
|
||||
nextMessage = stbm;
|
||||
else
|
||||
nextMessage = state.msg;
|
||||
TunnelBuildMessage nextMessage = state.msg;
|
||||
nextMessage.setUniqueId(req.readReplyMessageId());
|
||||
nextMessage.setMessageExpiration(expires);
|
||||
OutNetMessage msg = new OutNetMessage(_context, nextMessage, expires, PRIORITY, nextPeerInfo);
|
||||
|
||||
@@ -12,7 +12,6 @@ import net.i2p.data.SessionKey;
|
||||
import net.i2p.data.i2np.BuildRequestRecord;
|
||||
import net.i2p.data.i2np.EncryptedBuildRecord;
|
||||
import net.i2p.data.i2np.I2NPMessage;
|
||||
import net.i2p.data.i2np.InboundTunnelBuildMessage;
|
||||
import net.i2p.data.i2np.ShortEncryptedBuildRecord;
|
||||
import net.i2p.data.i2np.ShortTunnelBuildMessage;
|
||||
import net.i2p.data.i2np.TunnelBuildMessage;
|
||||
@@ -41,7 +40,7 @@ abstract class BuildMessageGenerator {
|
||||
TunnelCreatorConfig cfg, Hash replyRouter,
|
||||
long replyTunnel, RouterContext ctx, PublicKey peerKey) {
|
||||
int mtype = msg.getType();
|
||||
boolean isShort = mtype == InboundTunnelBuildMessage.MESSAGE_TYPE || mtype == ShortTunnelBuildMessage.MESSAGE_TYPE;
|
||||
boolean isShort = mtype == ShortTunnelBuildMessage.MESSAGE_TYPE;
|
||||
EncryptedBuildRecord erec;
|
||||
if (peerKey != null) {
|
||||
boolean isEC = peerKey.getType() == EncType.ECIES_X25519;
|
||||
@@ -56,6 +55,7 @@ abstract class BuildMessageGenerator {
|
||||
Hash peer = cfg.getPeer(hop);
|
||||
if (isEC) {
|
||||
erec = req.encryptECIESRecord(ctx, peerKey, peer);
|
||||
// TODO if isShort, set derived keys in coonfig
|
||||
cfg.setChaChaReplyKeys(hop, req.getChaChaReplyKey(), req.getChaChaReplyAD());
|
||||
} else {
|
||||
erec = req.encryptRecord(ctx, peerKey, peer);
|
||||
@@ -163,7 +163,7 @@ abstract class BuildMessageGenerator {
|
||||
public static void layeredEncrypt(I2PAppContext ctx, TunnelBuildMessage msg,
|
||||
TunnelCreatorConfig cfg, List<Integer> order) {
|
||||
int mtype = msg.getType();
|
||||
boolean isShort = mtype == InboundTunnelBuildMessage.MESSAGE_TYPE || mtype == ShortTunnelBuildMessage.MESSAGE_TYPE;
|
||||
boolean isShort = mtype == ShortTunnelBuildMessage.MESSAGE_TYPE;
|
||||
int size = isShort ? ShortTunnelBuildMessage.SHORT_RECORD_SIZE : TunnelBuildMessage.RECORD_SIZE;
|
||||
byte[] chachaIV = isShort ? new byte[12] : null;
|
||||
// encrypt the records so that the right elements will be visible at the right time
|
||||
|
||||
@@ -62,7 +62,8 @@ class BuildReplyHandler {
|
||||
log.debug(reply.getUniqueId() + ": skipping record " + i + "/" + hop + " for: " + cfg);
|
||||
if (cfg.isInbound() && hop + 1 == cfg.getLength()) { // IBEP
|
||||
byte[] h1 = new byte[Hash.HASH_LENGTH];
|
||||
ctx.sha().calculateHash(reply.getRecord(i).getData(), 0, TunnelBuildReplyMessage.RECORD_SIZE, h1, 0);
|
||||
byte[] data = reply.getRecord(i).getData();
|
||||
ctx.sha().calculateHash(data, 0, data.length, h1, 0);
|
||||
// get stored hash put here by BuildMessageGenerator
|
||||
Hash h2 = cfg.getBlankHash();
|
||||
if (h2 != null && DataHelper.eq(h1, h2.getData())) {
|
||||
|
||||
@@ -11,7 +11,6 @@ import net.i2p.data.PublicKey;
|
||||
import net.i2p.data.router.RouterInfo;
|
||||
import net.i2p.data.TunnelId;
|
||||
import net.i2p.data.i2np.I2NPMessage;
|
||||
import net.i2p.data.i2np.InboundTunnelBuildMessage;
|
||||
import net.i2p.data.i2np.ShortTunnelBuildMessage;
|
||||
import net.i2p.data.i2np.TunnelBuildMessage;
|
||||
import net.i2p.data.i2np.VariableTunnelBuildMessage;
|
||||
@@ -211,8 +210,8 @@ abstract class BuildRequestor {
|
||||
//long beforeDispatch = System.currentTimeMillis();
|
||||
if (cfg.isInbound()) {
|
||||
Hash ibgw = cfg.getPeer(0);
|
||||
if (msg.getType() == InboundTunnelBuildMessage.MESSAGE_TYPE) {
|
||||
// ITBM is garlic encrypted to the IBGW, to hide it from the OBEP
|
||||
if (msg.getType() == ShortTunnelBuildMessage.MESSAGE_TYPE) {
|
||||
// STBM is garlic encrypted to the IBGW, to hide it from the OBEP
|
||||
RouterInfo peer = ctx.netDb().lookupRouterInfoLocally(ibgw);
|
||||
if (peer != null) {
|
||||
I2NPMessage enc = MessageWrapper.wrap(ctx, msg, peer);
|
||||
@@ -339,10 +338,7 @@ abstract class BuildRequestor {
|
||||
len = TunnelBuildMessage.MAX_RECORD_COUNT;
|
||||
order = new ArrayList<Integer>(ORDER);
|
||||
}
|
||||
if (cfg.isInbound())
|
||||
msg = new InboundTunnelBuildMessage(ctx, len);
|
||||
else
|
||||
msg = new ShortTunnelBuildMessage(ctx, len);
|
||||
msg = new ShortTunnelBuildMessage(ctx, len);
|
||||
} else if (useVariable) {
|
||||
if (cfg.getLength() <= SHORT_RECORDS) {
|
||||
msg = new VariableTunnelBuildMessage(ctx, SHORT_RECORDS);
|
||||
|
||||
@@ -24,7 +24,6 @@ import net.i2p.data.i2np.EncryptedBuildRecord;
|
||||
import net.i2p.data.i2np.I2NPMessage;
|
||||
import net.i2p.data.i2np.I2NPMessageException;
|
||||
import net.i2p.data.i2np.I2NPMessageHandler;
|
||||
import net.i2p.data.i2np.InboundTunnelBuildMessage;
|
||||
import net.i2p.data.i2np.OutboundTunnelBuildReplyMessage;
|
||||
import net.i2p.data.i2np.ShortTunnelBuildMessage;
|
||||
import net.i2p.data.i2np.ShortTunnelBuildReplyMessage;
|
||||
@@ -84,20 +83,8 @@ public class BuildMessageTestStandalone extends TestCase {
|
||||
|
||||
// populate and encrypt the message
|
||||
TunnelBuildMessage msg;
|
||||
if (testType == 3) {
|
||||
if (testType == 3 || testType == 6) {
|
||||
msg = new ShortTunnelBuildMessage(ctx, TunnelBuildMessage.MAX_RECORD_COUNT);
|
||||
} else if (testType == 6) {
|
||||
InboundTunnelBuildMessage itbm = new InboundTunnelBuildMessage(ctx, TunnelBuildMessage.MAX_RECORD_COUNT);
|
||||
// set plaintext record for ibgw
|
||||
for (int i = 0; i < order.size(); i++) {
|
||||
int hop = order.get(i).intValue();
|
||||
if (hop == 0) {
|
||||
// TODO
|
||||
itbm.setPlaintextRecord(i, new byte[100]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
msg = itbm;
|
||||
} else {
|
||||
msg = new TunnelBuildMessage(ctx);
|
||||
}
|
||||
@@ -109,9 +96,7 @@ public class BuildMessageTestStandalone extends TestCase {
|
||||
PublicKey key = null;
|
||||
if (hop < end)
|
||||
key = _pubKeys[hop];
|
||||
// don't do this for ibgw in itbm
|
||||
if (testType != 6 || hop != 0)
|
||||
BuildMessageGenerator.createRecord(i, hop, msg, cfg, _replyRouter, _replyTunnel, ctx, key);
|
||||
BuildMessageGenerator.createRecord(i, hop, msg, cfg, _replyRouter, _replyTunnel, ctx, key);
|
||||
}
|
||||
BuildMessageGenerator.layeredEncrypt(ctx, msg, cfg, order);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user