2005-04-16 jrandom

* Migrated to Bouncycastle's SHA256 and HMAC implementations for efficiency
(also lots of udp fixes)
This commit is contained in:
jrandom
2005-04-17 00:59:48 +00:00
committed by zzz
parent 9e5fe7d2b6
commit 7389cec78f
27 changed files with 929 additions and 614 deletions

View File

@ -13,7 +13,6 @@ import java.io.InputStream;
import java.io.OutputStream;
import net.i2p.I2PAppContext;
import net.i2p.crypto.SHA256EntryCache;
import net.i2p.data.DataFormatException;
import net.i2p.data.DataHelper;
import net.i2p.data.DataStructureImpl;
@ -80,11 +79,9 @@ public abstract class I2NPMessageImpl extends DataStructureImpl implements I2NPM
cur += numRead;
}
SHA256EntryCache.CacheEntry cache = _context.sha().cache().acquire(size);
Hash calc = _context.sha().calculateHash(buffer, 0, size, cache);
Hash calc = _context.sha().calculateHash(buffer, 0, size);
//boolean eq = calc.equals(h);
boolean eq = DataHelper.eq(checksum, 0, calc.getData(), 0, CHECKSUM_LENGTH);
_context.sha().cache().release(cache);
if (!eq)
throw new I2NPMessageException("Hash does not match for " + getClass().getName());
@ -125,11 +122,9 @@ public abstract class I2NPMessageImpl extends DataStructureImpl implements I2NPM
+ " cur=" + cur
+ " wanted=" + size + "]: " + getClass().getName());
SHA256EntryCache.CacheEntry cache = _context.sha().cache().acquire(size);
Hash calc = _context.sha().calculateHash(data, cur, size, cache);
Hash calc = _context.sha().calculateHash(data, cur, size);
//boolean eq = calc.equals(h);
boolean eq = DataHelper.eq(hdata, 0, calc.getData(), 0, CHECKSUM_LENGTH);
_context.sha().cache().release(cache);
if (!eq)
throw new I2NPMessageException("Hash does not match for " + getClass().getName());
@ -204,8 +199,7 @@ public abstract class I2NPMessageImpl extends DataStructureImpl implements I2NPM
try {
int writtenLen = writeMessageBody(buffer, prefixLen);
int payloadLen = writtenLen - prefixLen;
SHA256EntryCache.CacheEntry cache = _context.sha().cache().acquire(payloadLen);
Hash h = _context.sha().calculateHash(buffer, prefixLen, payloadLen, cache);
Hash h = _context.sha().calculateHash(buffer, prefixLen, payloadLen);
int off = 0;
DataHelper.toLong(buffer, off, 1, getType());
@ -217,7 +211,6 @@ public abstract class I2NPMessageImpl extends DataStructureImpl implements I2NPM
DataHelper.toLong(buffer, off, 2, payloadLen);
off += 2;
System.arraycopy(h.getData(), 0, buffer, off, CHECKSUM_LENGTH);
_context.sha().cache().release(cache);
long time = _context.clock().now() - start;
//if (time > 50)

View File

@ -15,9 +15,9 @@ import net.i2p.CoreVersion;
*
*/
public class RouterVersion {
public final static String ID = "$Revision: 1.183 $ $Date: 2005/04/06 11:38:38 $";
public final static String ID = "$Revision: 1.184 $ $Date: 2005/04/12 10:22:12 $";
public final static String VERSION = "0.5.0.6";
public final static long BUILD = 1;
public final static long BUILD = 2;
public static void main(String args[]) {
System.out.println("I2P Router version: " + VERSION);
System.out.println("Router ID: " + RouterVersion.ID);

View File

@ -27,7 +27,7 @@ public class InboundMessageState {
private long _receiveBegin;
/** expire after 30s */
private static final long MAX_RECEIVE_TIME = 30*1000;
private static final long MAX_RECEIVE_TIME = 10*1000;
private static final int MAX_FRAGMENTS = 32;
private static final ByteCache _fragmentCache = ByteCache.getInstance(64, 2048);

View File

@ -119,6 +119,7 @@ public class OutboundMessageFragments {
if (state.isComplete()) {
_activeMessages.remove(i);
_transport.succeeded(state.getMessage());
state.releaseResources();
i--;
} else if (state.isExpired()) {
_activeMessages.remove(i);
@ -132,6 +133,7 @@ public class OutboundMessageFragments {
if (_log.shouldLog(Log.WARN))
_log.warn("Unable to send an expired direct message: " + state);
}
state.releaseResources();
i--;
} else if (state.getPushCount() > MAX_VOLLEYS) {
_activeMessages.remove(i);
@ -147,8 +149,8 @@ public class OutboundMessageFragments {
if (_log.shouldLog(Log.WARN))
_log.warn("Unable to send a direct message after too many volleys: " + state);
}
state.releaseResources();
i--;
}
}
}
@ -182,6 +184,7 @@ public class OutboundMessageFragments {
_transport.failed(state.getMessage());
if (_log.shouldLog(Log.WARN))
_log.warn("Peer disconnected for " + state);
state.releaseResources();
i--;
} else {
if (!state.isFragmented()) {
@ -210,7 +213,7 @@ public class OutboundMessageFragments {
if (state.getPushCount() != oldVolley) {
_context.statManager().addRateData("udp.sendVolleyTime", state.getLifetime(), state.getFragmentCount());
state.setNextSendTime(now + (1000-(now%1000)) + _context.random().nextInt(2000));
state.setNextSendTime(now + (1000-(now%1000)) + _context.random().nextInt(4000));
} else {
if (peer.getSendWindowBytesRemaining() > 0)
state.setNextSendTime(now);
@ -316,7 +319,9 @@ public class OutboundMessageFragments {
if ( (numSends > 1) && (state.getPeer() != null) )
state.getPeer().congestionOccurred();
_transport.succeeded(state.getMessage());
return state.getFragmentCount();
int numFragments = state.getFragmentCount();
state.releaseResources();
return numFragments;
} else {
if (_log.shouldLog(Log.ERROR))
_log.error("Received an ACK for a message not pending: " + messageId);
@ -360,6 +365,7 @@ public class OutboundMessageFragments {
_context.statManager().addRateData("udp.sendConfirmTime", state.getLifetime(), state.getLifetime());
_context.statManager().addRateData("udp.sendConfirmFragments", state.getFragmentCount(), state.getLifetime());
_transport.succeeded(state.getMessage());
state.releaseResources();
}
}
}

View File

@ -91,6 +91,11 @@ public class OutboundMessageState {
_log.debug("Raw byte array for " + _messageId + ": " + Base64.encode(_messageBuf.getData(), 0, len));
}
public void releaseResources() {
_cache.release(_messageBuf);
_messageBuf = null;
}
public OutNetMessage getMessage() { return _message; }
public long getMessageId() { return _messageId; }
public PeerState getPeer() { return _peer; }

View File

@ -77,7 +77,7 @@ public class PacketBuilder {
off += 16 - (off % 16);
packet.getPacket().setLength(off);
authenticate(packet, peer.getCurrentCipherKey(), peer.getCurrentMACKey());
setTo(packet, peer.getRemoteIP(), peer.getRemotePort());
setTo(packet, peer.getRemoteIPAddress(), peer.getRemotePort());
return packet;
}
@ -119,7 +119,7 @@ public class PacketBuilder {
off += 16 - (off % 16);
packet.getPacket().setLength(off);
authenticate(packet, peer.getCurrentCipherKey(), peer.getCurrentMACKey());
setTo(packet, peer.getRemoteIP(), peer.getRemotePort());
setTo(packet, peer.getRemoteIPAddress(), peer.getRemotePort());
return packet;
}
@ -137,8 +137,9 @@ public class PacketBuilder {
*/
public UDPPacket buildSessionCreatedPacket(InboundEstablishState state, int externalPort, SessionKey ourIntroKey) {
UDPPacket packet = UDPPacket.acquire(_context);
InetAddress to = null;
try {
packet.getPacket().setAddress(InetAddress.getByAddress(state.getSentIP()));
to = InetAddress.getByAddress(state.getSentIP());
} catch (UnknownHostException uhe) {
if (_log.shouldLog(Log.ERROR))
_log.error("How did we think this was a valid IP? " + state.getRemoteHostInfo());
@ -209,7 +210,7 @@ public class PacketBuilder {
off += 16 - (off % 16);
packet.getPacket().setLength(off);
authenticate(packet, ourIntroKey, ourIntroKey, iv);
setTo(packet, state.getSentIP(), state.getSentPort());
setTo(packet, to, state.getSentPort());
_ivCache.release(iv);
return packet;
}
@ -228,8 +229,9 @@ public class PacketBuilder {
*/
public UDPPacket buildSessionRequestPacket(OutboundEstablishState state) {
UDPPacket packet = UDPPacket.acquire(_context);
InetAddress to = null;
try {
packet.getPacket().setAddress(InetAddress.getByAddress(state.getSentIP()));
to = InetAddress.getByAddress(state.getSentIP());
} catch (UnknownHostException uhe) {
if (_log.shouldLog(Log.ERROR))
_log.error("How did we think this was a valid IP? " + state.getRemoteHostInfo());
@ -266,7 +268,7 @@ public class PacketBuilder {
off += 16 - (off % 16);
packet.getPacket().setLength(off);
authenticate(packet, state.getIntroKey(), state.getIntroKey());
setTo(packet, state.getSentIP(), state.getSentPort());
setTo(packet, to, state.getSentPort());
return packet;
}
@ -303,8 +305,9 @@ public class PacketBuilder {
*/
public UDPPacket buildSessionConfirmedPacket(OutboundEstablishState state, int fragmentNum, int numFragments, byte identity[]) {
UDPPacket packet = UDPPacket.acquire(_context);
InetAddress to = null;
try {
packet.getPacket().setAddress(InetAddress.getByAddress(state.getSentIP()));
to = InetAddress.getByAddress(state.getSentIP());
} catch (UnknownHostException uhe) {
if (_log.shouldLog(Log.ERROR))
_log.error("How did we think this was a valid IP? " + state.getRemoteHostInfo());
@ -370,19 +373,13 @@ public class PacketBuilder {
authenticate(packet, state.getIntroKey(), state.getIntroKey());
}
setTo(packet, state.getSentIP(), state.getSentPort());
setTo(packet, to, state.getSentPort());
return packet;
}
private void setTo(UDPPacket packet, byte ip[], int port) {
try {
InetAddress to = InetAddress.getByAddress(ip);
packet.getPacket().setAddress(to);
packet.getPacket().setPort(port);
} catch (UnknownHostException uhe) {
if (_log.shouldLog(Log.ERROR))
_log.error("Invalid IP? ", uhe);
}
private void setTo(UDPPacket packet, InetAddress ip, int port) {
packet.getPacket().setAddress(ip);
packet.getPacket().setPort(port);
}
/**

View File

@ -29,7 +29,7 @@ public class PacketHandler {
private InboundMessageFragments _inbound;
private boolean _keepReading;
private static final int NUM_HANDLERS = 4;
private static final int NUM_HANDLERS = 1;
public PacketHandler(RouterContext ctx, UDPTransport transport, UDPEndpoint endpoint, EstablishmentManager establisher, InboundMessageFragments inbound) {
_context = ctx;

View File

@ -4,6 +4,7 @@ import java.util.ArrayList;
import java.util.List;
import java.net.InetAddress;
import java.net.UnknownHostException;
import net.i2p.I2PAppContext;
import net.i2p.data.Hash;
@ -89,6 +90,8 @@ public class PeerState {
private int _slowStartThreshold;
/** what IP is the peer sending and receiving packets on? */
private byte[] _remoteIP;
/** cached IP address */
private transient InetAddress _remoteIPAddress;
/** what port is the peer sending and receiving packets on? */
private int _remotePort;
/** cached remoteIP + port, used to find the peerState by remote info */
@ -214,6 +217,17 @@ public class PeerState {
public int getSendWindowBytesRemaining() { return _sendWindowBytesRemaining; }
/** what IP is the peer sending and receiving packets on? */
public byte[] getRemoteIP() { return _remoteIP; }
public InetAddress getRemoteIPAddress() {
if (_remoteIPAddress == null) {
try {
_remoteIPAddress = InetAddress.getByAddress(_remoteIP);
} catch (UnknownHostException uhe) {
if (_log.shouldLog(Log.ERROR))
_log.error("Invalid IP? ", uhe);
}
}
return _remoteIPAddress;
}
/** what port is the peer sending and receiving packets on? */
public int getRemotePort() { return _remotePort; }
/** if we need to contact them, do we need to talk to an introducer? */
@ -325,6 +339,7 @@ public class PeerState {
/** what IP+port is the peer sending and receiving packets on? */
public void setRemoteAddress(byte ip[], int port) {
_remoteIP = ip;
_remoteIPAddress = null;
_remotePort = port;
_remoteHostString = calculateRemoteHostString(ip, port);
}
@ -391,7 +406,7 @@ public class PeerState {
if (_sendWindowBytes <= _slowStartThreshold) {
_sendWindowBytes += bytesACKed;
} else {
double prob = bytesACKed / _sendWindowBytes;
double prob = ((double)bytesACKed) / ((double)_sendWindowBytes);
if (_context.random().nextDouble() <= prob)
_sendWindowBytes += bytesACKed;
}

View File

@ -19,12 +19,14 @@ class UDPFlooder implements Runnable {
private UDPTransport _transport;
private List _peers;
private boolean _alive;
private static final byte _floodData[] = new byte[4096];
public UDPFlooder(RouterContext ctx, UDPTransport transport) {
_context = ctx;
_log = ctx.logManager().getLog(UDPFlooder.class);
_transport = transport;
_peers = new ArrayList(4);
ctx.random().nextBytes(_floodData);
}
public void addPeer(PeerState peer) {
@ -61,8 +63,8 @@ class UDPFlooder implements Runnable {
for (int i = 0; i < _peers.size(); i++) {
PeerState peer = (PeerState)_peers.get(i);
DataMessage m = new DataMessage(_context);
byte data[] = new byte[4096];
_context.random().nextBytes(data);
byte data[] = _floodData; // new byte[4096];
//_context.random().nextBytes(data);
m.setData(data);
m.setMessageExpiration(_context.clock().now() + 10*1000);
m.setUniqueId(_context.random().nextLong(I2NPMessage.MAX_ID_VALUE));

View File

@ -8,6 +8,7 @@ import java.util.ArrayList;
import java.util.List;
import net.i2p.I2PAppContext;
import net.i2p.crypto.HMACSHA256Generator;
import net.i2p.data.Base64;
import net.i2p.data.ByteArray;
import net.i2p.data.DataHelper;
@ -29,6 +30,7 @@ public class UDPPacket {
private long _initializeTime;
private long _expiration;
private byte[] _data;
private ByteArray _dataBuf;
private static final List _packetCache;
static {
@ -61,11 +63,13 @@ public class UDPPacket {
private static final int MAX_VALIDATE_SIZE = MAX_PACKET_SIZE;
private static final ByteCache _validateCache = ByteCache.getInstance(16, MAX_VALIDATE_SIZE);
private static final ByteCache _ivCache = ByteCache.getInstance(16, IV_SIZE);
private static final ByteCache _dataCache = ByteCache.getInstance(64, MAX_PACKET_SIZE);
private UDPPacket(I2PAppContext ctx) {
_context = ctx;
_log = ctx.logManager().getLog(UDPPacket.class);
_data = new byte[MAX_PACKET_SIZE];
_dataBuf = _dataCache.acquire();
_data = _dataBuf.getData();
_packet = new DatagramPacket(_data, MAX_PACKET_SIZE);
_initializeTime = _context.clock().now();
}
@ -113,7 +117,7 @@ public class UDPPacket {
DataHelper.toLong(buf.getData(), off, 2, payloadLength);
off += 2;
Hash calculated = _context.hmac().calculate(macKey, buf.getData(), 0, off);
Hash hmac = _context.hmac().calculate(macKey, buf.getData(), 0, off);
if (_log.shouldLog(Log.DEBUG)) {
StringBuffer str = new StringBuffer(128);
@ -123,12 +127,12 @@ public class UDPPacket {
str.append("\nIV2: ").append(Base64.encode(_data, MAC_SIZE, IV_SIZE));
str.append("\nlen: ").append(DataHelper.fromLong(buf.getData(), payloadLength + IV_SIZE, 2));
str.append("\nMAC key: ").append(macKey.toBase64());
str.append("\ncalc HMAC: ").append(calculated.toBase64());
str.append("\ncalc HMAC: ").append(Base64.encode(hmac.getData()));
str.append("\nread HMAC: ").append(Base64.encode(_data, _packet.getOffset(), MAC_SIZE));
str.append("\nraw: ").append(Base64.encode(_data, _packet.getOffset(), _packet.getLength()));
_log.debug(str.toString());
}
eq = DataHelper.eq(calculated.getData(), 0, _data, _packet.getOffset(), MAC_SIZE);
eq = DataHelper.eq(hmac.getData(), 0, _data, _packet.getOffset(), MAC_SIZE);
} else {
if (_log.shouldLog(Log.WARN))
_log.warn("Payload length is " + payloadLength);
@ -177,6 +181,7 @@ public class UDPPacket {
}
public void release() {
_dataCache.release(_dataBuf);
if (!CACHE) return;
synchronized (_packetCache) {
_packet.setLength(0);

View File

@ -139,7 +139,7 @@ public class UDPSender {
}
// back to the cache
//packet.release();
packet.release();
}
}
}

View File

@ -5,7 +5,6 @@ import java.util.HashMap;
import java.util.Map;
import net.i2p.I2PAppContext;
import net.i2p.crypto.SHA256EntryCache;
import net.i2p.data.Base64;
import net.i2p.data.ByteArray;
import net.i2p.data.DataHelper;
@ -138,8 +137,7 @@ public class FragmentHandler {
if (_log.shouldLog(Log.DEBUG))
_log.debug("endpoint IV: " + Base64.encode(preV, validLength - HopProcessor.IV_LENGTH, HopProcessor.IV_LENGTH));
SHA256EntryCache.CacheEntry cache = _context.sha().cache().acquire(TrivialPreprocessor.PREPROCESSED_SIZE);
Hash v = _context.sha().calculateHash(preV, 0, validLength, cache);
Hash v = _context.sha().calculateHash(preV, 0, validLength);
//Hash v = _context.sha().calculateHash(preV, 0, validLength);
boolean eq = DataHelper.eq(v.getData(), 0, preprocessed, offset + HopProcessor.IV_LENGTH, 4);
@ -152,7 +150,6 @@ public class FragmentHandler {
+ Base64.encode(preprocessed, offset, length));
}
_context.sha().cache().release(cache);
_validateCache.release(ba);
if (eq) {

View File

@ -4,7 +4,6 @@ import java.util.ArrayList;
import java.util.List;
import net.i2p.I2PAppContext;
import net.i2p.crypto.SHA256EntryCache;
import net.i2p.data.Base64;
import net.i2p.data.ByteArray;
import net.i2p.data.DataHelper;
@ -103,11 +102,9 @@ public class TrivialPreprocessor implements TunnelGateway.QueuePreprocessor {
byte iv[] = ivBuf.getData(); // new byte[IV_SIZE];
_context.random().nextBytes(iv);
SHA256EntryCache.CacheEntry cache = _context.sha().cache().acquire(PREPROCESSED_SIZE);
// payload ready, now H(instructions+payload+IV)
System.arraycopy(iv, 0, fragments, fragmentLength, IV_SIZE);
Hash h = _context.sha().calculateHash(fragments, 0, fragmentLength + IV_SIZE, cache);
Hash h = _context.sha().calculateHash(fragments, 0, fragmentLength + IV_SIZE);
//Hash h = _context.sha().calculateHash(target, 0, offset + IV_SIZE);
//_log.debug("before shift: " + Base64.encode(target));
// now shiiiiiift
@ -128,7 +125,6 @@ public class TrivialPreprocessor implements TunnelGateway.QueuePreprocessor {
offset += 4;
//_log.debug("before pad : " + Base64.encode(target));
_context.sha().cache().release(cache);
_ivCache.release(ivBuf);
// fits in a single message, so may be smaller than the full size