Merge branch 'master' of 127.0.0.1:i2p-hackers/i2p.i2p

This commit is contained in:
idk
2021-07-14 15:34:45 -04:00
10 changed files with 22 additions and 311 deletions

View File

@@ -31,6 +31,7 @@ import java.util.Properties;
import net.i2p.I2PAppContext;
import net.i2p.app.*;
import static net.i2p.app.ClientAppState.*;
import net.i2p.servlet.filters.XI2PLocationFilter;
import net.i2p.util.FileUtil;
import net.i2p.util.I2PAppThread;
import net.i2p.util.PortMapper;

View File

@@ -1,4 +1,4 @@
package net.i2p.jetty;
package net.i2p.servlet.filters;
import java.io.IOException;
import java.io.File;

View File

@@ -84,7 +84,7 @@ public class BuildResponseRecord {
* @param status the response 0-255
* @param replyAD 32 bytes
* @param options 116 bytes max when serialized
* @return a 236-byte response record
* @return a 218-byte response record
* @throws IllegalArgumentException if options too big or on encryption failure
* @since 0.9.51
*/
@@ -111,10 +111,10 @@ public class BuildResponseRecord {
/**
* Encrypts in place.
* Handles both standard (528) and short (236) byte records as of 0.9.51.
* Handles both standard (528) and short (218) byte records as of 0.9.51.
*
* @param ad non-null
* @param data 528 or 236 bytes, data will be encrypted in place.
* @param data 528 or 218 bytes, data will be encrypted in place.
* @return success
* @since 0.9.48
*/
@@ -131,12 +131,12 @@ public class BuildResponseRecord {
/*
* ChaCha/Poly only for ECIES routers.
* Handles both standard (528) and short (236) byte records as of 0.9.51.
* Handles both standard (528) and short (218) byte records as of 0.9.51.
* Decrypts in place.
* Status will be rec.getData()[511 or 219].
* Properties will be at rec.getData()[0].
*
* @param rec 528 or 236 bytes, data will be decrypted in place.
* @param rec 528 or 218 bytes, data will be decrypted in place.
* @param ad non-null
* @return success
* @since 0.9.48

View File

@@ -1,146 +0,0 @@
package net.i2p.data.i2np;
import net.i2p.I2PAppContext;
import net.i2p.data.DataHelper;
/**
* Sent from the tunnel creator to the IBGW via an outbound tunnel.
* Contains one plaintext variable-sized request record for the IBGW
* and a variable number of encrypted records for the following hops.
* This message must be garlic-encrypted to hide the contents from the OBEP.
*
* Preliminary, see proposal 157.
*
* @since 0.9.50
*/
public class InboundTunnelBuildMessage extends TunnelBuildMessage {
public static final int MESSAGE_TYPE = 27;
public static final int SHORT_RECORD_SIZE = ShortTunnelBuildMessage.SHORT_RECORD_SIZE;
public static final int MAX_PLAINTEXT_RECORD_SIZE = OutboundTunnelBuildReplyMessage.MAX_PLAINTEXT_RECORD_SIZE;
private int _plaintextSlot = -1;
private byte[] _plaintextRecord;
/** zero record count, will be set with readMessage() */
public InboundTunnelBuildMessage(I2PAppContext context) {
super(context, 0);
}
public InboundTunnelBuildMessage(I2PAppContext context, int records) {
super(context, records);
}
/**
* @param record must be ShortEncryptedBuildRecord or null
* @throws IllegalArgumentException on bad slot or record length.
*/
@Override
public void setRecord(int index, EncryptedBuildRecord record) {
if (record != null && (record.length() != SHORT_RECORD_SIZE || index == _plaintextSlot))
throw new IllegalArgumentException();
super.setRecord(index, record);
}
/**
* Set the slot and data for the plaintext record.
* @throws IllegalArgumentException on bad slot or data length.
*/
public void setPlaintextRecord(int slot, byte[] data) {
if (slot < 0 || slot >= RECORD_COUNT || data.length == 0 || data.length > MAX_PLAINTEXT_RECORD_SIZE ||
(_records != null && _records[slot] != null))
throw new IllegalArgumentException();
_plaintextSlot = slot;
_plaintextRecord = data;
}
/**
* Get the slot for the plaintext record.
* getRecord() for this slot will return null.
*/
public int getPlaintextSlot() {
return _plaintextSlot;
}
/**
* Get the data for the plaintext record.
*/
public byte[] getPlaintextRecord() {
return _plaintextRecord;
}
@Override
protected int calculateWrittenLength() {
if (_plaintextRecord == null)
throw new IllegalStateException("Plaintext record not set");
return 4 + _plaintextRecord.length + ((RECORD_COUNT - 1) * SHORT_RECORD_SIZE);
}
@Override
public int getType() { return MESSAGE_TYPE; }
@Override
public void readMessage(byte[] data, int offset, int dataSize, int type) throws I2NPMessageException {
if (type != MESSAGE_TYPE)
throw new I2NPMessageException("Message type is incorrect for this message");
int r = data[offset++];
if (r <= 0 || r > MAX_RECORD_COUNT)
throw new I2NPMessageException("Bad record count " + r);
RECORD_COUNT = r;
int _plaintextSlot = data[offset++] & 0xff;
if (_plaintextSlot >= r)
throw new I2NPMessageException("Bad slot " + _plaintextSlot);
int size = (int) DataHelper.fromLong(data, offset, 2);
if (size <= 0 || size > MAX_PLAINTEXT_RECORD_SIZE)
throw new I2NPMessageException("Bad size " + size);
offset += 2;
_plaintextRecord = new byte[size];
System.arraycopy(data, offset, _plaintextRecord, 0, size);
offset += size;
if (dataSize != calculateWrittenLength())
throw new I2NPMessageException("Wrong length (expects " + calculateWrittenLength() + ", recv " + dataSize + ")");
_records = new EncryptedBuildRecord[RECORD_COUNT];
for (int i = 0; i < RECORD_COUNT; i++) {
if (i == _plaintextSlot)
continue;
byte rec[] = new byte[SHORT_RECORD_SIZE];
System.arraycopy(data, offset, rec, 0, SHORT_RECORD_SIZE);
setRecord(i, new ShortEncryptedBuildRecord(rec));
offset += SHORT_RECORD_SIZE;
}
}
@Override
protected int writeMessageBody(byte[] out, int curIndex) throws I2NPMessageException {
if (_plaintextRecord == null)
throw new I2NPMessageException("Plaintext record not set");
int remaining = out.length - (curIndex + calculateWrittenLength());
if (remaining < 0)
throw new I2NPMessageException("Not large enough (too short by " + remaining + ")");
if (RECORD_COUNT <= 0 || RECORD_COUNT > MAX_RECORD_COUNT)
throw new I2NPMessageException("Bad record count " + RECORD_COUNT);
out[curIndex++] = (byte) RECORD_COUNT;
out[curIndex++] = (byte) _plaintextSlot;
DataHelper.toLong(out, curIndex, 2, _plaintextRecord.length);
curIndex += 2;
System.arraycopy(_plaintextRecord, 0, out, curIndex, _plaintextRecord.length);
curIndex += _plaintextRecord.length;
for (int i = 0; i < RECORD_COUNT; i++) {
if (i == _plaintextSlot)
continue;
System.arraycopy(_records[i].getData(), 0, out, curIndex, SHORT_RECORD_SIZE);
curIndex += SHORT_RECORD_SIZE;
}
return curIndex;
}
@Override
public String toString() {
StringBuilder buf = new StringBuilder(64);
buf.append("[InboundTunnelBuildMessage: " +
"\n\tID: ").append(getUniqueId())
.append("\n\tRecords: ").append(getRecordCount())
.append(']');
return buf.toString();
}
}

View File

@@ -10,8 +10,7 @@ import net.i2p.data.DataHelper;
/**
* Sent from the OBEP to the tunnel creator via an inbound tunnel.
* Contains one plaintext variable-sized reply record for the creator
* and a variable number of encrypted records for the following hops.
* Contains a variable number of encrypted records.
* This message must be garlic-encrypted to hide the contents from the OBGW.
*
* Preliminary, see proposal 157.
@@ -21,10 +20,6 @@ import net.i2p.data.DataHelper;
public class OutboundTunnelBuildReplyMessage extends TunnelBuildReplyMessage {
public static final int MESSAGE_TYPE = 26;
public static final int SHORT_RECORD_SIZE = ShortTunnelBuildMessage.SHORT_RECORD_SIZE;
public static final int MAX_PLAINTEXT_RECORD_SIZE = 172;
private int _plaintextSlot = -1;
private byte[] _plaintextRecord;
/** zero record count, will be set with readMessage() */
public OutboundTunnelBuildReplyMessage(I2PAppContext context) {
@@ -41,97 +36,14 @@ public class OutboundTunnelBuildReplyMessage extends TunnelBuildReplyMessage {
*/
@Override
public void setRecord(int index, EncryptedBuildRecord record) {
if (record != null && (record.length() != SHORT_RECORD_SIZE || index == _plaintextSlot))
if (record != null && record.length() != SHORT_RECORD_SIZE)
throw new IllegalArgumentException();
super.setRecord(index, record);
}
/**
* Set the slot and data for the plaintext record.
* Empty properties will be used.
*
* @param reply 0-255
* @throws IllegalArgumentException on bad slot or data length.
* @since 0.9.51
*/
public void setPlaintextRecord(int slot, int reply) {
// 00 00 reply
byte[] data = new byte[3];
data[2] = (byte) reply;
setPlaintextRecord(slot, data);
}
/**
* Set the slot and data for the plaintext record.
*
* @param reply 0-255
* @param props may be null
* @throws IllegalArgumentException on bad slot or data length.
* @since 0.9.51
*/
public void setPlaintextRecord(int slot, int reply, Properties props) throws DataFormatException {
if (props == null || props.isEmpty()) {
setPlaintextRecord(slot, reply);
return;
}
ByteArrayOutputStream baos = new ByteArrayOutputStream();
try {
DataHelper.writeProperties(baos, props);
} catch (IOException ioe) {}
baos.write((byte) reply);
setPlaintextRecord(slot, baos.toByteArray());
}
/**
* Set the slot and data for the plaintext record.
* @throws IllegalArgumentException on bad slot or data length.
*/
public void setPlaintextRecord(int slot, byte[] data) {
if (slot < 0 || slot >= RECORD_COUNT || data.length == 0 || data.length > MAX_PLAINTEXT_RECORD_SIZE ||
(_records != null && _records[slot] != null))
throw new IllegalArgumentException();
_plaintextSlot = slot;
_plaintextRecord = data;
}
/**
* Get the slot for the plaintext record.
* getRecord() for this slot will return null.
*/
public int getPlaintextSlot() {
return _plaintextSlot;
}
/**
* Get the data for the plaintext record.
*/
public byte[] getPlaintextRecord() {
return _plaintextRecord;
}
/**
* Get the data for the plaintext record.
* @since 0.9.51
*/
public int getPlaintextReply() {
return _plaintextRecord[_plaintextRecord.length - 1] & 0xff;
}
/**
* Get the data for the plaintext record.
* @since 0.9.51
*/
public Properties getPlaintextOptions() throws DataFormatException {
Properties props = new Properties();
DataHelper.fromProperties(_plaintextRecord, 0, props);
return props;
}
@Override
protected int calculateWrittenLength() {
if (_plaintextRecord == null)
throw new IllegalStateException("Plaintext record not set");
return 4 + _plaintextRecord.length + ((RECORD_COUNT - 1) * SHORT_RECORD_SIZE);
return 1 + (RECORD_COUNT * SHORT_RECORD_SIZE);
}
@Override
@@ -145,23 +57,10 @@ public class OutboundTunnelBuildReplyMessage extends TunnelBuildReplyMessage {
if (r <= 0 || r > MAX_RECORD_COUNT)
throw new I2NPMessageException("Bad record count " + r);
RECORD_COUNT = r;
_plaintextSlot = data[offset++] & 0xff;
if (_plaintextSlot < 0 || _plaintextSlot >= r)
throw new I2NPMessageException("Bad slot " + _plaintextSlot);
int size = (int) DataHelper.fromLong(data, offset, 2);
if (size <= 0 || size > MAX_PLAINTEXT_RECORD_SIZE)
throw new I2NPMessageException("Bad size " + size);
offset += 2;
_plaintextRecord = new byte[size];
System.arraycopy(data, offset, _plaintextRecord, 0, size);
offset += size;
if (dataSize != calculateWrittenLength())
throw new I2NPMessageException("Wrong length (expects " + calculateWrittenLength() + ", recv " + dataSize + ")");
_records = new EncryptedBuildRecord[RECORD_COUNT];
for (int i = 0; i < RECORD_COUNT; i++) {
if (i == _plaintextSlot)
continue;
byte rec[] = new byte[SHORT_RECORD_SIZE];
System.arraycopy(data, offset, rec, 0, SHORT_RECORD_SIZE);
setRecord(i, new ShortEncryptedBuildRecord(rec));
@@ -171,22 +70,13 @@ public class OutboundTunnelBuildReplyMessage extends TunnelBuildReplyMessage {
@Override
protected int writeMessageBody(byte[] out, int curIndex) throws I2NPMessageException {
if (_plaintextRecord == null)
throw new I2NPMessageException("Plaintext record not set");
int remaining = out.length - (curIndex + calculateWrittenLength());
if (remaining < 0)
throw new I2NPMessageException("Not large enough (too short by " + remaining + ")");
if (RECORD_COUNT <= 0 || RECORD_COUNT > MAX_RECORD_COUNT)
throw new I2NPMessageException("Bad record count " + RECORD_COUNT);
out[curIndex++] = (byte) RECORD_COUNT;
out[curIndex++] = (byte) _plaintextSlot;
DataHelper.toLong(out, curIndex, 2, _plaintextRecord.length);
curIndex += 2;
System.arraycopy(_plaintextRecord, 0, out, curIndex, _plaintextRecord.length);
curIndex += _plaintextRecord.length;
for (int i = 0; i < RECORD_COUNT; i++) {
if (i == _plaintextSlot)
continue;
System.arraycopy(_records[i].getData(), 0, out, curIndex, SHORT_RECORD_SIZE);
curIndex += SHORT_RECORD_SIZE;
}

View File

@@ -2,7 +2,7 @@ package net.i2p.data.i2np;
/**
* Small records.
* 236 bytes.
* 218 bytes.
* Preliminary, see proposal 157.
*
* Note that these are layer-encrypted and layer-decrypted in-place.

View File

@@ -1,7 +1,5 @@
package net.i2p.router.tunnel;
import java.util.Date;
import net.i2p.data.DataHelper;
import net.i2p.data.Hash;
import net.i2p.data.SessionKey;
@@ -21,8 +19,6 @@ public class HopConfig {
private Hash _sendTo;
private SessionKey _layerKey;
private SessionKey _ivKey;
private SessionKey _replyKey;
private byte[] _replyIV;
private long _creation;
private long _expiration;
//private Map _options;
@@ -179,20 +175,19 @@ public class HopConfig {
/** */
@Override
public String toString() {
StringBuilder buf = new StringBuilder(64);
StringBuilder buf = new StringBuilder(256);
if (_receiveTunnel != null) {
buf.append("recv on ");
buf.append(_receiveTunnel.getTunnelId());
buf.append(' ');
}
if (_sendTo != null) {
buf.append("send to ").append(_sendTo.toBase64().substring(0,4)).append(":");
buf.append(" send to ").append(_sendTo.toBase64().substring(0,4)).append(":");
if (_sendTunnel != null)
buf.append(_sendTunnel.getTunnelId());
}
buf.append(" exp. ").append(new Date(_expiration));
buf.append(" layer key: ").append(_layerKey);
buf.append(" IV key: ").append(_ivKey);
buf.append(" exp. ").append(DataHelper.formatTime(_expiration));
int messagesProcessed = getProcessedMessagesCount();
if (messagesProcessed > 0)
buf.append(" used ").append(messagesProcessed).append("KB");

View File

@@ -1012,7 +1012,6 @@ class BuildHandler implements Runnable {
TunnelBuildReplyMessage replyMsg;
if (state.msg.getType() == ShortTunnelBuildMessage.MESSAGE_TYPE) {
OutboundTunnelBuildReplyMessage otbrm = new OutboundTunnelBuildReplyMessage(_context, records);
otbrm.setPlaintextRecord(ourSlot, response);
replyMsg = otbrm;
} else if (records == TunnelBuildMessage.MAX_RECORD_COUNT) {
replyMsg = new TunnelBuildReplyMessage(_context);

View File

@@ -90,10 +90,6 @@ class BuildReplyHandler {
rv[i] = ok;
}
}
if (reply.getType() == OutboundTunnelBuildReplyMessage.MESSAGE_TYPE) {
OutboundTunnelBuildReplyMessage otbrm = (OutboundTunnelBuildReplyMessage) reply;
rv[otbrm.getPlaintextSlot()] = otbrm.getPlaintextReply();
}
return rv;
}
@@ -109,23 +105,10 @@ class BuildReplyHandler {
private int decryptRecord(TunnelBuildReplyMessage reply, TunnelCreatorConfig cfg, int recordNum, int hop) {
EncryptedBuildRecord rec = reply.getRecord(recordNum);
int type = reply.getType();
boolean isOTBRM = type == OutboundTunnelBuildReplyMessage.MESSAGE_TYPE;
if (rec == null) {
if (!isOTBRM) {
if (log.shouldWarn())
log.warn("Missing record " + recordNum);
return -1;
}
OutboundTunnelBuildReplyMessage otbrm = (OutboundTunnelBuildReplyMessage) reply;
if (otbrm.getPlaintextSlot() != recordNum) {
if (log.shouldWarn())
log.warn("Plaintext slot mismatch expected " + recordNum + " got " + otbrm.getPlaintextSlot());
return -1;
}
int rv = otbrm.getPlaintextReply();
if (log.shouldLog(Log.DEBUG))
log.debug(reply.getUniqueId() + ": Received: " + rv + " for plaintext record " + recordNum + "/" + hop);
return rv;
if (log.shouldWarn())
log.warn("Missing record " + recordNum);
return -1;
}
byte[] data = rec.getData();
int start = cfg.getLength() - 1;
@@ -137,6 +120,7 @@ class BuildReplyHandler {
if (isEC)
end++;
// do we need to adjust this for the endpoint?
boolean isOTBRM = type == OutboundTunnelBuildReplyMessage.MESSAGE_TYPE;
boolean isShort = isOTBRM || type == ShortTunnelBuildReplyMessage.MESSAGE_TYPE;
if (isShort) {
byte iv[] = new byte[12];

View File

@@ -158,6 +158,7 @@ public class BuildMessageTestStandalone extends TestCase {
for (int j = 0; j < TunnelBuildMessage.MAX_RECORD_COUNT; j++) {
if (msg.getRecord(j) == null) {
ourSlot = j;
msg.setRecord(j, reply);
break;
}
}
@@ -198,21 +199,8 @@ public class BuildMessageTestStandalone extends TestCase {
TunnelBuildReplyMessage reply;
if (testType == 3) {
OutboundTunnelBuildReplyMessage otbrm = new OutboundTunnelBuildReplyMessage(ctx, TunnelBuildMessage.MAX_RECORD_COUNT);
int ibep = _peers.length - 1;
int ibepSlot = -1;
for (int i = 0; i < order.size(); i++) {
int slot = order.get(i).intValue();
if (slot == ibep) {
ibepSlot = i;
break;
}
}
log.debug("OTBRM plaintext slot is " + ibepSlot);
for (int i = 0; i < TunnelBuildMessage.MAX_RECORD_COUNT; i++) {
if (i == ibepSlot)
otbrm.setPlaintextRecord(i, 0);
else
otbrm.setRecord(i, msg.getRecord(i));
otbrm.setRecord(i, msg.getRecord(i));
}
// test read/write
byte[] data = otbrm.toByteArray();