SSU1 removal part 7/n

This commit is contained in:
zzz
2024-05-21 12:15:52 +00:00
parent 1d96b5b3df
commit e2661985c4
11 changed files with 1 additions and 2236 deletions

View File

@@ -989,32 +989,12 @@ class EstablishmentManager {
RouterIdentity remote = state.getConfirmedIdentity(); RouterIdentity remote = state.getConfirmedIdentity();
PeerState peer; PeerState peer;
int version = state.getVersion();
InboundEstablishState2 state2 = (InboundEstablishState2) state; InboundEstablishState2 state2 = (InboundEstablishState2) state;
peer = state2.getPeerState(); peer = state2.getPeerState();
// now handled in IES2.createPeerState() // now handled in IES2.createPeerState()
//peer.setWeRelayToThemAs(state.getSentRelayTag()); //peer.setWeRelayToThemAs(state.getSentRelayTag());
if (version == 1) {
// Lookup the peer's MTU from the netdb, since it isn't included in the protocol setup (yet)
// TODO if we don't have RI then we will get it shortly, but too late.
// Perhaps netdb should notify transport when it gets a new RI...
RouterInfo info = _context.netDb().lookupRouterInfoLocally(remote.calculateHash());
if (info != null) {
RouterAddress addr = _transport.getTargetAddress(info);
if (addr != null) {
String smtu = addr.getOption(UDPAddress.PROP_MTU);
if (smtu != null) {
try {
boolean isIPv6 = state.getSentIP().length == 16;
int mtu = MTU.rectify(isIPv6, Integer.parseInt(smtu));
peer.setHisMTU(mtu);
} catch (NumberFormatException nfe) {}
}
}
}
} // else IES2 sets PS2 MTU
// 0 is the default // 0 is the default
//peer.setTheyRelayToUsAs(0); //peer.setTheyRelayToUsAs(0);

View File

@@ -1,198 +0,0 @@
package net.i2p.router.transport.udp;
/*
* Copyright (c) 2000 - 2004 The Legion Of The Bouncy Castle
* (http://www.bouncycastle.org)
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated
* documentation files (the "Software"), to deal in the Software
* without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or
* sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following
* conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*
*/
import java.security.DigestException;
import java.security.MessageDigest;
import java.util.Arrays;
import net.i2p.util.SimpleByteCache;
/**
* HMAC implementation based on RFC2104
*
* H(K XOR opad, H(K XOR ipad, text))
*
* modified by jrandom to use the session key byte array directly and to cache
* a frequently used buffer (called on doFinal). changes released into the public
* domain in 2005.
*
* This is renamed from HMac because the constructor HMac(digest, sz) does not exist
* in the standard bouncycastle library, thus it conflicts in JVMs that contain the
* standard library (Android).
*
* As of 0.9.12, refactored to use standard MessageDigest.
*
* Deprecated - Do not use outside of router or Syndie.
* Not a public API - Not for external use!
*
* @since 0.9.43 moved from org.bouncycastle.oldcrypto.macs
*/
class I2PHMac
{
private final static int BLOCK_LENGTH = 64;
private final static byte IPAD = (byte)0x36;
private final static byte OPAD = (byte)0x5C;
private final MessageDigest digest;
private final int digestSize;
private final byte[] inputPad = new byte[BLOCK_LENGTH];
private final byte[] outputPad = new byte[BLOCK_LENGTH];
/**
* Standard HMAC, size == digest size.
* @deprecated Use javax.crypto.Mac
*/
@Deprecated
public I2PHMac(MessageDigest digest) {
this(digest, digest.getDigestLength());
}
/**
* @param sz override the digest's size, nonstandard if different.
* SEE NOTES in HMACGenerator about why this isn't compatible with standard HmacMD5
*/
public I2PHMac(MessageDigest digest, int sz) {
this.digest = digest;
this.digestSize = sz;
}
public String getAlgorithmName()
{
return digest.getAlgorithm() + "/HMAC";
}
public MessageDigest getUnderlyingDigest()
{
return digest;
}
//public void init(
// CipherParameters params)
//{
public void init(byte key[])
{
digest.reset();
//byte[] key = ((KeyParameter)params).getKey();
if (key.length > BLOCK_LENGTH)
{
digest.update(key, 0, key.length);
try {
digest.digest(inputPad, 0, digestSize);
} catch (DigestException de) {
digest.reset();
throw new IllegalArgumentException(de);
}
for (int i = digestSize; i < inputPad.length; i++)
{
inputPad[i] = 0;
}
}
else
{
System.arraycopy(key, 0, inputPad, 0, key.length);
for (int i = key.length; i < inputPad.length; i++)
{
inputPad[i] = 0;
}
}
// why reallocate? it hasn't changed sizes, and the arraycopy
// below fills it completely...
//outputPad = new byte[inputPad.length];
System.arraycopy(inputPad, 0, outputPad, 0, inputPad.length);
for (int i = 0; i < inputPad.length; i++)
{
inputPad[i] ^= IPAD;
}
for (int i = 0; i < outputPad.length; i++)
{
outputPad[i] ^= OPAD;
}
digest.update(inputPad, 0, inputPad.length);
}
public int getMacSize() {
return digestSize;
}
public void update(byte in) {
digest.update(in);
}
public void update(byte[] in, int inOff, int len) {
digest.update(in, inOff, len);
}
public int doFinal(byte[] out, int outOff) {
byte[] tmp = acquireTmp(digestSize);
//byte[] tmp = new byte[digestSize];
try {
digest.digest(tmp, 0, digestSize);
digest.update(outputPad, 0, outputPad.length);
digest.update(tmp, 0, tmp.length);
return digest.digest(out, outOff, digestSize);
} catch (DigestException de) {
throw new IllegalArgumentException(de);
} finally {
releaseTmp(tmp);
reset();
}
}
private static byte[] acquireTmp(int sz) {
byte[] rv = SimpleByteCache.acquire(sz);
Arrays.fill(rv, (byte)0x0);
return rv;
}
private static void releaseTmp(byte buf[]) {
SimpleByteCache.release(buf);
}
/**
* Reset the mac generator.
*/
public void reset()
{
/*
* reset the underlying digest.
*/
digest.reset();
/*
* reinitialize the digest.
*/
digest.update(inputPad, 0, inputPad.length);
}
}

View File

@@ -13,11 +13,9 @@ import net.i2p.data.DataFormatException;
import net.i2p.data.DataHelper; import net.i2p.data.DataHelper;
import net.i2p.data.Hash; import net.i2p.data.Hash;
import net.i2p.data.router.RouterIdentity; import net.i2p.data.router.RouterIdentity;
import net.i2p.data.SessionKey;
import net.i2p.data.Signature; import net.i2p.data.Signature;
import net.i2p.router.OutNetMessage; import net.i2p.router.OutNetMessage;
import net.i2p.router.RouterContext; import net.i2p.router.RouterContext;
import net.i2p.router.transport.crypto.DHSessionKeyBuilder;
import net.i2p.util.Addresses; import net.i2p.util.Addresses;
import net.i2p.util.Log; import net.i2p.util.Log;
@@ -35,21 +33,15 @@ class InboundEstablishState {
private byte _receivedX[]; private byte _receivedX[];
protected byte _bobIP[]; protected byte _bobIP[];
protected final int _bobPort; protected final int _bobPort;
private final DHSessionKeyBuilder _keyBuilder;
// SessionCreated message // SessionCreated message
private byte _sentY[];
protected final byte _aliceIP[]; protected final byte _aliceIP[];
protected final int _alicePort; protected final int _alicePort;
protected long _sentRelayTag; protected long _sentRelayTag;
private long _sentSignedOnTime; private long _sentSignedOnTime;
private SessionKey _sessionKey;
private SessionKey _macKey;
private Signature _sentSignature;
// SessionConfirmed messages - fragmented in theory but not in practice - see below // SessionConfirmed messages - fragmented in theory but not in practice - see below
private byte _receivedIdentity[][]; private byte _receivedIdentity[][];
private long _receivedSignedOnTime; private long _receivedSignedOnTime;
private byte _receivedSignature[]; private byte _receivedSignature[];
private boolean _verificationAttempted;
// sig not verified // sig not verified
protected RouterIdentity _receivedUnconfirmedIdentity; protected RouterIdentity _receivedUnconfirmedIdentity;
// identical to uncomfirmed, but sig now verified // identical to uncomfirmed, but sig now verified
@@ -115,25 +107,6 @@ class InboundEstablishState {
*/ */
protected static final long MAX_DELAY = EstablishmentManager.MAX_IB_ESTABLISH_TIME; protected static final long MAX_DELAY = EstablishmentManager.MAX_IB_ESTABLISH_TIME;
/**
* @param localPort Must be our external port, otherwise the signature of the
* SessionCreated message will be bad if the external port != the internal port.
*/
public InboundEstablishState(RouterContext ctx, byte remoteIP[], int remotePort, int localPort,
DHSessionKeyBuilder dh, UDPPacketReader.SessionRequestReader req) {
_context = ctx;
_log = ctx.logManager().getLog(InboundEstablishState.class);
_aliceIP = remoteIP;
_alicePort = remotePort;
_remoteHostId = new RemoteHostId(_aliceIP, _alicePort);
_bobPort = localPort;
_currentState = InboundState.IB_STATE_UNKNOWN;
_establishBegin = ctx.clock().now();
_keyBuilder = dh;
_queuedMessages = new LinkedBlockingQueue<OutNetMessage>();
_introductionRequested = true;
receiveSessionRequest(req);
}
/** /**
* For SSU2 * For SSU2
@@ -149,7 +122,6 @@ class InboundEstablishState {
_bobPort = 0; _bobPort = 0;
_currentState = InboundState.IB_STATE_UNKNOWN; _currentState = InboundState.IB_STATE_UNKNOWN;
_establishBegin = ctx.clock().now(); _establishBegin = ctx.clock().now();
_keyBuilder = null;
_queuedMessages = new LinkedBlockingQueue<OutNetMessage>(); _queuedMessages = new LinkedBlockingQueue<OutNetMessage>();
} }
@@ -193,26 +165,6 @@ class InboundEstablishState {
return _queuedMessages.poll(); return _queuedMessages.poll();
} }
public synchronized void receiveSessionRequest(UDPPacketReader.SessionRequestReader req) {
if (_receivedX == null)
_receivedX = new byte[UDPPacketReader.SessionRequestReader.X_LENGTH];
req.readX(_receivedX, 0);
if (_bobIP == null)
_bobIP = new byte[req.readIPSize()];
req.readIP(_bobIP, 0);
byte[] ext = req.readExtendedOptions();
if (ext != null && ext.length >= UDPPacket.SESS_REQ_MIN_EXT_OPTIONS_LENGTH) {
_introductionRequested = (ext[1] & (byte) UDPPacket.SESS_REQ_EXT_FLAG_REQUEST_RELAY_TAG) != 0;
if (_log.shouldInfo())
_log.info("got sess req. w/ ext. options, need intro? " + _introductionRequested + ' ' + this);
}
if (_log.shouldLog(Log.DEBUG))
_log.debug("Receive sessionRequest, BobIP = " + Addresses.toString(_bobIP));
if (_currentState == InboundState.IB_STATE_UNKNOWN)
_currentState = InboundState.IB_STATE_REQUEST_RECEIVED;
packetReceived();
}
public synchronized boolean sessionRequestReceived() { return _receivedX != null; } public synchronized boolean sessionRequestReceived() { return _receivedX != null; }
public synchronized byte[] getReceivedX() { return _receivedX; } public synchronized byte[] getReceivedX() { return _receivedX; }
public synchronized byte[] getReceivedOurIP() { return _bobIP; } public synchronized byte[] getReceivedOurIP() { return _bobIP; }
@@ -223,40 +175,12 @@ class InboundEstablishState {
*/ */
public synchronized boolean isIntroductionRequested() { return _introductionRequested; } public synchronized boolean isIntroductionRequested() { return _introductionRequested; }
/**
* Generates session key and mac key.
*/
public synchronized void generateSessionKey() throws DHSessionKeyBuilder.InvalidPublicParameterException {
if (_sessionKey != null) return;
try {
_keyBuilder.setPeerPublicValue(_receivedX);
} catch (IllegalStateException ise) {
throw new DHSessionKeyBuilder.InvalidPublicParameterException("reused keys?", ise);
}
_sessionKey = _keyBuilder.getSessionKey();
ByteArray extra = _keyBuilder.getExtraBytes();
_macKey = new SessionKey(new byte[SessionKey.KEYSIZE_BYTES]);
System.arraycopy(extra.getData(), 0, _macKey.getData(), 0, SessionKey.KEYSIZE_BYTES);
if (_log.shouldLog(Log.DEBUG))
_log.debug("Established inbound keys. cipher: " + Base64.encode(_sessionKey.getData())
+ " mac: " + Base64.encode(_macKey.getData()));
}
public synchronized SessionKey getCipherKey() { return _sessionKey; }
public synchronized SessionKey getMACKey() { return _macKey; }
/** what IP do they appear to be on? */ /** what IP do they appear to be on? */
public byte[] getSentIP() { return _aliceIP; } public byte[] getSentIP() { return _aliceIP; }
/** what port number do they appear to be coming from? */ /** what port number do they appear to be coming from? */
public int getSentPort() { return _alicePort; } public int getSentPort() { return _alicePort; }
public synchronized byte[] getSentY() {
if (_sentY == null)
_sentY = _keyBuilder.getMyPublicValueBytes();
return _sentY;
}
public synchronized void fail() { public synchronized void fail() {
_currentState = InboundState.IB_STATE_FAILED; _currentState = InboundState.IB_STATE_FAILED;
} }
@@ -265,59 +189,6 @@ class InboundEstablishState {
public synchronized void setSentRelayTag(long tag) { _sentRelayTag = tag; } public synchronized void setSentRelayTag(long tag) { _sentRelayTag = tag; }
public synchronized long getSentSignedOnTime() { return _sentSignedOnTime; } public synchronized long getSentSignedOnTime() { return _sentSignedOnTime; }
public synchronized void prepareSessionCreated() {
if (_sentSignature == null) signSessionCreated();
}
public synchronized Signature getSentSignature() { return _sentSignature; }
/**
* Sign: Alice's IP + Alice's port + Bob's IP + Bob's port + Alice's
* new relay tag + Bob's signed on time
*/
private void signSessionCreated() {
byte signed[] = new byte[256 + 256 // X + Y
+ _aliceIP.length + 2
+ _bobIP.length + 2
+ 4 // sent relay tag
+ 4 // signed on time
];
_sentSignedOnTime = _context.clock().now() / 1000;
int off = 0;
System.arraycopy(_receivedX, 0, signed, off, _receivedX.length);
off += _receivedX.length;
getSentY();
System.arraycopy(_sentY, 0, signed, off, _sentY.length);
off += _sentY.length;
System.arraycopy(_aliceIP, 0, signed, off, _aliceIP.length);
off += _aliceIP.length;
DataHelper.toLong(signed, off, 2, _alicePort);
off += 2;
System.arraycopy(_bobIP, 0, signed, off, _bobIP.length);
off += _bobIP.length;
DataHelper.toLong(signed, off, 2, _bobPort);
off += 2;
DataHelper.toLong(signed, off, 4, _sentRelayTag);
off += 4;
DataHelper.toLong(signed, off, 4, _sentSignedOnTime);
_sentSignature = _context.dsa().sign(signed, _context.keyManager().getSigningPrivateKey());
if (_log.shouldLog(Log.DEBUG)) {
StringBuilder buf = new StringBuilder(128);
buf.append("Signing sessionCreated:");
//buf.append(" ReceivedX: ").append(Base64.encode(_receivedX));
//buf.append(" SentY: ").append(Base64.encode(_sentY));
buf.append(" Alice: ").append(Addresses.toString(_aliceIP, _alicePort));
buf.append(" Bob: ").append(Addresses.toString(_bobIP, _bobPort));
buf.append(" RelayTag: ").append(_sentRelayTag);
buf.append(" SignedOn: ").append(_sentSignedOnTime);
buf.append(" signature: ").append(Base64.encode(_sentSignature.getData()));
_log.debug(buf.toString());
}
}
/** note that we just sent a SessionCreated packet */ /** note that we just sent a SessionCreated packet */
public synchronized void createdPacketSent() { public synchronized void createdPacketSent() {
_lastSend = _context.clock().now(); _lastSend = _context.clock().now();
@@ -357,79 +228,6 @@ class InboundEstablishState {
/** RemoteHostId, uniquely identifies an attempt */ /** RemoteHostId, uniquely identifies an attempt */
RemoteHostId getRemoteHostId() { return _remoteHostId; } RemoteHostId getRemoteHostId() { return _remoteHostId; }
/**
* Note that while a SessionConfirmed could in theory be fragmented,
* in practice a RouterIdentity is 387 bytes and a single fragment is 512 bytes max,
* so it will never be fragmented.
*/
public synchronized void receiveSessionConfirmed(UDPPacketReader.SessionConfirmedReader conf) {
if (_receivedIdentity == null)
_receivedIdentity = new byte[conf.readTotalFragmentNum()][];
int cur = conf.readCurrentFragmentNum();
if (cur >= _receivedIdentity.length) {
// avoid AIOOBE
// should do more than this, but what? disconnect?
fail();
packetReceived();
return;
}
if (_receivedIdentity[cur] == null) {
byte fragment[] = new byte[conf.readCurrentFragmentSize()];
conf.readFragmentData(fragment, 0);
_receivedIdentity[cur] = fragment;
}
if (cur == _receivedIdentity.length-1) {
_receivedSignedOnTime = conf.readFinalFragmentSignedOnTime();
// TODO verify time to prevent replay attacks
buildIdentity();
if (_receivedUnconfirmedIdentity != null) {
SigType type = _receivedUnconfirmedIdentity.getSigningPublicKey().getType();
if (type != null) {
int sigLen = type.getSigLen();
if (_receivedSignature == null)
_receivedSignature = new byte[sigLen];
conf.readFinalSignature(_receivedSignature, 0, sigLen);
} else {
if (_log.shouldLog(Log.WARN))
_log.warn("Unsupported sig type from: " + toString());
// _x() in UDPTransport
_context.banlist().banlistRouterForever(_receivedUnconfirmedIdentity.calculateHash(),
"Unsupported signature type");
fail();
}
Hash h = _receivedUnconfirmedIdentity.calculateHash();
if (_context.banlist().isBanlistedForever(h)) {
// validate sig to prevent spoofing
if (getConfirmedIdentity() != null)
_context.blocklist().add(_aliceIP);
if (_log.shouldLog(Log.WARN))
_log.warn("Router is banned: " + h.toBase64() + " on " + this);
fail();
}
} else {
if (_log.shouldLog(Log.WARN))
_log.warn("Bad ident from: " + toString());
fail();
}
}
if ( (_currentState == InboundState.IB_STATE_UNKNOWN) ||
(_currentState == InboundState.IB_STATE_REQUEST_RECEIVED) ||
(_currentState == InboundState.IB_STATE_CREATED_SENT) ) {
if (confirmedFullyReceived())
_currentState = InboundState.IB_STATE_CONFIRMED_COMPLETELY;
else
_currentState = InboundState.IB_STATE_CONFIRMED_PARTIALLY;
}
if (_createdSentCount == 1) {
_rtt = (int) ( _context.clock().now() - _lastSend );
}
packetReceived();
}
/** /**
* Have we fully received the SessionConfirmed messages from Alice? * Have we fully received the SessionConfirmed messages from Alice?
* Caller must synch on this. * Caller must synch on this.
@@ -452,111 +250,9 @@ class InboundEstablishState {
* Note that this isn't really confirmed - see below. * Note that this isn't really confirmed - see below.
*/ */
public synchronized RouterIdentity getConfirmedIdentity() { public synchronized RouterIdentity getConfirmedIdentity() {
if (!_verificationAttempted) {
verifyIdentity();
_verificationAttempted = true;
}
return _receivedConfirmedIdentity; return _receivedConfirmedIdentity;
} }
/**
* Construct Alice's RouterIdentity.
* Must have received all fragments.
* Sets _receivedUnconfirmedIdentity, unless invalid.
*
* Caller must synch on this.
*
* @since 0.9.16 was in verifyIdentity()
*/
private void buildIdentity() {
if (_receivedUnconfirmedIdentity != null)
return; // dup pkt?
int frags = _receivedIdentity.length;
byte[] ident;
if (frags > 1) {
int identSize = 0;
for (int i = 0; i < _receivedIdentity.length; i++)
identSize += _receivedIdentity[i].length;
ident = new byte[identSize];
int off = 0;
for (int i = 0; i < _receivedIdentity.length; i++) {
int len = _receivedIdentity[i].length;
System.arraycopy(_receivedIdentity[i], 0, ident, off, len);
off += len;
}
} else {
// no need to copy
ident = _receivedIdentity[0];
}
ByteArrayInputStream in = new ByteArrayInputStream(ident);
RouterIdentity peer = new RouterIdentity();
try {
peer.readBytes(in);
_receivedUnconfirmedIdentity = peer;
} catch (DataFormatException dfe) {
if (_log.shouldLog(Log.WARN))
_log.warn("Improperly formatted yet fully received ident", dfe);
} catch (IOException ioe) {
if (_log.shouldLog(Log.WARN))
_log.warn("Improperly formatted yet fully received ident", ioe);
}
}
/**
* Determine if Alice sent us a valid confirmation packet. The
* identity signs: Alice's IP + Alice's port + Bob's IP + Bob's port
* + Alice's new relay key + Alice's signed on time
*
* Note that the protocol does not include a signature of the RouterIdentity,
* which could be a problem?
*
* Caller must synch on this.
*/
private void verifyIdentity() {
if (_receivedUnconfirmedIdentity == null)
return; // either not yet recvd or bad ident
if (_receivedSignature == null)
return; // either not yet recvd or bad sig
byte signed[] = new byte[256+256 // X + Y
+ _aliceIP.length + 2
+ _bobIP.length + 2
+ 4 // Alice's relay key
+ 4 // signed on time
];
int off = 0;
System.arraycopy(_receivedX, 0, signed, off, _receivedX.length);
off += _receivedX.length;
getSentY();
System.arraycopy(_sentY, 0, signed, off, _sentY.length);
off += _sentY.length;
System.arraycopy(_aliceIP, 0, signed, off, _aliceIP.length);
off += _aliceIP.length;
DataHelper.toLong(signed, off, 2, _alicePort);
off += 2;
System.arraycopy(_bobIP, 0, signed, off, _bobIP.length);
off += _bobIP.length;
DataHelper.toLong(signed, off, 2, _bobPort);
off += 2;
DataHelper.toLong(signed, off, 4, _sentRelayTag);
off += 4;
DataHelper.toLong(signed, off, 4, _receivedSignedOnTime);
Signature sig = new Signature(_receivedUnconfirmedIdentity.getSigType(), _receivedSignature);
boolean ok = _context.dsa().verifySignature(sig, signed, _receivedUnconfirmedIdentity.getSigningPublicKey());
if (ok) {
// todo partial spoof detection - get peer.calculateHash(),
// lookup in netdb locally, if not equal, fail?
_receivedConfirmedIdentity = _receivedUnconfirmedIdentity;
} else {
if (_log.shouldLog(Log.WARN))
_log.warn("Signature failed from " + _receivedUnconfirmedIdentity + "\non: " + this);
// we can't ban the hash because it could be spoofed, but we can block the IP
_context.blocklist().add(_aliceIP);
}
}
/** /**
* Call from synchronized method only * Call from synchronized method only
*/ */
@@ -569,15 +265,9 @@ class InboundEstablishState {
StringBuilder buf = new StringBuilder(128); StringBuilder buf = new StringBuilder(128);
buf.append("IES "); buf.append("IES ");
buf.append(Addresses.toString(_aliceIP, _alicePort)); buf.append(Addresses.toString(_aliceIP, _alicePort));
//if (_receivedX != null)
// buf.append(" ReceivedX: ").append(Base64.encode(_receivedX, 0, 4));
//if (_sentY != null)
// buf.append(" SentY: ").append(Base64.encode(_sentY, 0, 4));
//buf.append(" Bob: ").append(Addresses.toString(_bobIP, _bobPort));
buf.append(" lifetime: ").append(DataHelper.formatDuration(getLifetime())); buf.append(" lifetime: ").append(DataHelper.formatDuration(getLifetime()));
if (_sentRelayTag > 0) if (_sentRelayTag > 0)
buf.append(" RelayTag: ").append(_sentRelayTag); buf.append(" RelayTag: ").append(_sentRelayTag);
//buf.append(" SignedOn: ").append(_sentSignedOnTime);
buf.append(' ').append(_currentState); buf.append(' ').append(_currentState);
return buf.toString(); return buf.toString();
} }

View File

@@ -552,11 +552,6 @@ class InboundEstablishState2 extends InboundEstablishState implements SSU2Payloa
super.fail(); super.fail();
} }
// SSU 1 unsupported things
@Override
public void generateSessionKey() { throw new UnsupportedOperationException(); }
// SSU 2 things // SSU 2 things
public long getSendConnID() { return _sendConnID; } public long getSendConnID() { return _sendConnID; }

View File

@@ -14,7 +14,6 @@ import net.i2p.data.i2np.DatabaseStoreMessage;
import net.i2p.data.i2np.I2NPMessage; import net.i2p.data.i2np.I2NPMessage;
import net.i2p.router.OutNetMessage; import net.i2p.router.OutNetMessage;
import net.i2p.router.RouterContext; import net.i2p.router.RouterContext;
import net.i2p.router.transport.crypto.DHSessionKeyBuilder;
import net.i2p.util.Addresses; import net.i2p.util.Addresses;
import net.i2p.util.Log; import net.i2p.util.Log;
@@ -31,23 +30,18 @@ class OutboundEstablishState {
private byte _sentX[]; private byte _sentX[];
protected byte _bobIP[]; protected byte _bobIP[];
protected int _bobPort; protected int _bobPort;
private final DHSessionKeyBuilder.Factory _keyFactory;
private DHSessionKeyBuilder _keyBuilder;
// SessionCreated message // SessionCreated message
private byte _receivedY[]; private byte _receivedY[];
protected byte _aliceIP[]; protected byte _aliceIP[];
protected int _alicePort; protected int _alicePort;
protected long _receivedRelayTag; protected long _receivedRelayTag;
private long _receivedSignedOnTime; private long _receivedSignedOnTime;
private SessionKey _sessionKey;
private SessionKey _macKey;
private Signature _receivedSignature; private Signature _receivedSignature;
// includes trailing padding to mod 16 // includes trailing padding to mod 16
private byte[] _receivedEncryptedSignature; private byte[] _receivedEncryptedSignature;
private byte[] _receivedIV; private byte[] _receivedIV;
// SessionConfirmed messages // SessionConfirmed messages
private long _sentSignedOnTime; private long _sentSignedOnTime;
private Signature _sentSignature;
// general status // general status
protected final long _establishBegin; protected final long _establishBegin;
//private long _lastReceive; //private long _lastReceive;
@@ -130,51 +124,6 @@ class OutboundEstablishState {
private static final long WAIT_FOR_HOLE_PUNCH_DELAY = 500; private static final long WAIT_FOR_HOLE_PUNCH_DELAY = 500;
/**
* @param claimedAddress an IP/port based RemoteHostId, or null if unknown
* @param remoteHostId non-null, == claimedAddress if direct, or a hash-based one if indirect
* @param remotePeer must have supported sig type
* @param allowExtendedOptions are we allowed to send extended options to Bob?
* @param needIntroduction should we ask Bob to be an introducer for us?
ignored unless allowExtendedOptions is true
* @param introKey Bob's introduction key, as published in the netdb
* @param addr non-null
*/
public OutboundEstablishState(RouterContext ctx, RemoteHostId claimedAddress,
RemoteHostId remoteHostId,
RouterIdentity remotePeer, boolean allowExtendedOptions,
boolean needIntroduction,
SessionKey introKey, UDPAddress addr,
DHSessionKeyBuilder.Factory dh) {
_context = ctx;
_log = ctx.logManager().getLog(OutboundEstablishState.class);
if (claimedAddress != null) {
_bobIP = claimedAddress.getIP();
_bobPort = claimedAddress.getPort();
} else {
//_bobIP = null;
_bobPort = -1;
}
_claimedAddress = claimedAddress;
_remoteHostId = remoteHostId;
_allowExtendedOptions = allowExtendedOptions;
_needIntroduction = needIntroduction;
_remotePeer = remotePeer;
_introKey = introKey;
_queuedMessages = new LinkedBlockingQueue<OutNetMessage>();
_establishBegin = ctx.clock().now();
_remoteAddress = addr;
_introductionNonce = -1;
_keyFactory = dh;
if (addr.getIntroducerCount() > 0) {
if (_log.shouldLog(Log.DEBUG))
_log.debug("new outbound establish to " + remotePeer.calculateHash() + ", with address: " + addr);
_currentState = OutboundState.OB_STATE_PENDING_INTRO;
} else {
_currentState = OutboundState.OB_STATE_UNKNOWN;
}
}
/** /**
* For SSU2 * For SSU2
* *
@@ -204,7 +153,6 @@ class OutboundEstablishState {
_establishBegin = ctx.clock().now(); _establishBegin = ctx.clock().now();
_remoteAddress = addr; _remoteAddress = addr;
_introductionNonce = -1; _introductionNonce = -1;
_keyFactory = null;
if (addr.getIntroducerCount() > 0) { if (addr.getIntroducerCount() > 0) {
if (_log.shouldLog(Log.DEBUG)) if (_log.shouldLog(Log.DEBUG))
_log.debug("new outbound establish to " + remotePeer.calculateHash() + ", with address: " + addr); _log.debug("new outbound establish to " + remotePeer.calculateHash() + ", with address: " + addr);
@@ -294,29 +242,6 @@ class OutboundEstablishState {
*/ */
public SessionKey getIntroKey() { return _introKey; } public SessionKey getIntroKey() { return _introKey; }
/** caller must synch - only call once */
private void prepareSessionRequest() {
_keyBuilder = _keyFactory.getBuilder();
byte X[] = _keyBuilder.getMyPublicValue().toByteArray();
if (X.length == 257) {
_sentX = new byte[256];
System.arraycopy(X, 1, _sentX, 0, _sentX.length);
} else if (X.length == 256) {
_sentX = X;
} else {
_sentX = new byte[256];
System.arraycopy(X, 0, _sentX, _sentX.length - X.length, X.length);
}
}
public synchronized byte[] getSentX() {
// We defer keygen until now so that it gets done in the Establisher loop,
// and so that we don't waste entropy on failed introductions
if (_sentX == null)
prepareSessionRequest();
return _sentX;
}
/** /**
* The remote side (Bob) - note that in some places he's called Charlie. * The remote side (Bob) - note that in some places he's called Charlie.
* Warning - may change after introduction. May be null before introduction. * Warning - may change after introduction. May be null before introduction.
@@ -329,62 +254,6 @@ class OutboundEstablishState {
*/ */
public synchronized int getSentPort() { return _bobPort; } public synchronized int getSentPort() { return _bobPort; }
public synchronized void receiveSessionCreated(UDPPacketReader.SessionCreatedReader reader) {
if (_currentState == OutboundState.OB_STATE_VALIDATION_FAILED) {
if (_log.shouldLog(Log.WARN))
_log.warn("Session created already failed");
return;
}
if (_receivedY != null) {
if (_log.shouldLog(Log.DEBUG))
_log.debug("Session created already received, ignoring");
return; // already received
}
_receivedY = new byte[UDPPacketReader.SessionCreatedReader.Y_LENGTH];
reader.readY(_receivedY, 0);
if (_aliceIP == null)
_aliceIP = new byte[reader.readIPSize()];
reader.readIP(_aliceIP, 0);
_alicePort = reader.readPort();
_receivedRelayTag = reader.readRelayTag();
_receivedSignedOnTime = reader.readSignedOnTime();
// handle variable signature size
SigType type = _remotePeer.getSigningPublicKey().getType();
if (type == null) {
// shouldn't happen, we only connect to supported peers
fail();
packetReceived();
return;
}
int sigLen = type.getSigLen();
int mod = sigLen % 16;
int pad = (mod == 0) ? 0 : (16 - mod);
int esigLen = sigLen + pad;
_receivedEncryptedSignature = new byte[esigLen];
reader.readEncryptedSignature(_receivedEncryptedSignature, 0, esigLen);
_receivedIV = new byte[UDPPacket.IV_SIZE];
reader.readIV(_receivedIV, 0);
if (_log.shouldLog(Log.DEBUG))
_log.debug("Receive session created:Sig: " + Base64.encode(_receivedEncryptedSignature)
+ "receivedIV: " + Base64.encode(_receivedIV)
+ "AliceIP: " + Addresses.toString(_aliceIP)
+ " RelayTag: " + _receivedRelayTag
+ " SignedOn: " + _receivedSignedOnTime
+ ' ' + this.toString());
if (_currentState == OutboundState.OB_STATE_UNKNOWN ||
_currentState == OutboundState.OB_STATE_REQUEST_SENT ||
_currentState == OutboundState.OB_STATE_INTRODUCED ||
_currentState == OutboundState.OB_STATE_PENDING_INTRO)
_currentState = OutboundState.OB_STATE_CREATED_RECEIVED;
if (_requestSentCount == 1) {
_rtt = (int) (_context.clock().now() - _requestSentTime);
}
packetReceived();
}
/** /**
* Blocking call (run in the establisher thread) to determine if the * Blocking call (run in the establisher thread) to determine if the
* session was created properly. If it wasn't, all the SessionCreated * session was created properly. If it wasn't, all the SessionCreated
@@ -396,38 +265,7 @@ class OutboundEstablishState {
* @return true if valid * @return true if valid
*/ */
public synchronized boolean validateSessionCreated() { public synchronized boolean validateSessionCreated() {
if (_currentState == OutboundState.OB_STATE_VALIDATION_FAILED) { throw new UnsupportedOperationException("see override");
if (_log.shouldLog(Log.WARN))
_log.warn("Session created already failed");
return false;
}
if (_receivedSignature != null) {
if (_log.shouldLog(Log.DEBUG))
_log.debug("Session created already validated");
return true;
}
boolean valid = true;
try {
generateSessionKey();
} catch (DHSessionKeyBuilder.InvalidPublicParameterException ippe) {
if (_log.shouldLog(Log.WARN))
_log.warn("Peer " + getRemoteHostId() + " sent us an invalid DH parameter", ippe);
valid = false;
}
if (valid)
decryptSignature();
if (valid && verifySessionCreated()) {
if (_log.shouldLog(Log.DEBUG))
_log.debug("Session created passed validation");
return true;
} else {
if (_log.shouldLog(Log.WARN))
_log.warn("Session created failed validation, clearing state for " + _remoteHostId.toString());
fail();
return false;
}
} }
/** /**
@@ -441,11 +279,6 @@ class OutboundEstablishState {
_receivedEncryptedSignature = null; _receivedEncryptedSignature = null;
_receivedIV = null; _receivedIV = null;
_receivedSignature = null; _receivedSignature = null;
if (_keyBuilder != null) {
//if (_keyBuilder.getPeerPublicValue() == null)
// _keyFactory.returnUnused(_keyBuilder);
_keyBuilder = null;
}
// sure, there's a chance the packet was corrupted, but in practice // sure, there's a chance the packet was corrupted, but in practice
// this means that Bob doesn't know his external port, so give up. // this means that Bob doesn't know his external port, so give up.
_currentState = OutboundState.OB_STATE_VALIDATION_FAILED; _currentState = OutboundState.OB_STATE_VALIDATION_FAILED;
@@ -453,155 +286,12 @@ class OutboundEstablishState {
_nextSend = _context.clock().now(); _nextSend = _context.clock().now();
} }
/**
* Generates session key and mac key.
* Caller must synch on this.
*/
private void generateSessionKey() throws DHSessionKeyBuilder.InvalidPublicParameterException {
if (_sessionKey != null) return;
if (_keyBuilder == null)
throw new DHSessionKeyBuilder.InvalidPublicParameterException("Illegal state - never generated a key builder");
try {
_keyBuilder.setPeerPublicValue(_receivedY);
} catch (IllegalStateException ise) {
throw new DHSessionKeyBuilder.InvalidPublicParameterException("reused keys?", ise);
}
_sessionKey = _keyBuilder.getSessionKey();
ByteArray extra = _keyBuilder.getExtraBytes();
_macKey = new SessionKey(new byte[SessionKey.KEYSIZE_BYTES]);
System.arraycopy(extra.getData(), 0, _macKey.getData(), 0, SessionKey.KEYSIZE_BYTES);
if (_log.shouldLog(Log.DEBUG))
_log.debug("Established outbound keys. cipher: " + _sessionKey
+ " mac: " + _macKey);
}
/**
* decrypt the signature (and subsequent pad bytes) with the
* additional layer of encryption using the negotiated key along side
* the packet's IV
*
* Caller must synch on this.
* Only call this once! Decrypts in-place.
*/
private void decryptSignature() {
if (_receivedEncryptedSignature == null) throw new NullPointerException("encrypted signature is null! this=" + this.toString());
if (_sessionKey == null) throw new NullPointerException("SessionKey is null!");
if (_receivedIV == null) throw new NullPointerException("IV is null!");
_context.aes().decrypt(_receivedEncryptedSignature, 0, _receivedEncryptedSignature, 0,
_sessionKey, _receivedIV, _receivedEncryptedSignature.length);
// handle variable signature size
SigType type = _remotePeer.getSigningPublicKey().getType();
// if type == null throws NPE
int sigLen = type.getSigLen();
int mod = sigLen % 16;
if (mod != 0) {
byte signatureBytes[] = new byte[sigLen];
System.arraycopy(_receivedEncryptedSignature, 0, signatureBytes, 0, sigLen);
_receivedSignature = new Signature(type, signatureBytes);
} else {
_receivedSignature = new Signature(type, _receivedEncryptedSignature);
}
if (_log.shouldLog(Log.DEBUG))
_log.debug("Decrypted received signature: " + Base64.encode(_receivedSignature.getData()));
}
/**
* Verify: Alice's IP + Alice's port + Bob's IP + Bob's port + Alice's
* new relay tag + Bob's signed on time
* Caller must synch on this.
*/
private boolean verifySessionCreated() {
byte signed[] = new byte[256+256 // X + Y
+ _aliceIP.length + 2
+ _bobIP.length + 2
+ 4 // sent relay tag
+ 4 // signed on time
];
int off = 0;
System.arraycopy(_sentX, 0, signed, off, _sentX.length);
off += _sentX.length;
System.arraycopy(_receivedY, 0, signed, off, _receivedY.length);
off += _receivedY.length;
System.arraycopy(_aliceIP, 0, signed, off, _aliceIP.length);
off += _aliceIP.length;
DataHelper.toLong(signed, off, 2, _alicePort);
off += 2;
System.arraycopy(_bobIP, 0, signed, off, _bobIP.length);
off += _bobIP.length;
DataHelper.toLong(signed, off, 2, _bobPort);
off += 2;
DataHelper.toLong(signed, off, 4, _receivedRelayTag);
off += 4;
DataHelper.toLong(signed, off, 4, _receivedSignedOnTime);
boolean valid = _context.dsa().verifySignature(_receivedSignature, signed, _remotePeer.getSigningPublicKey());
if (_log.shouldLog(Log.DEBUG) || (_log.shouldLog(Log.WARN) && !valid)) {
StringBuilder buf = new StringBuilder(128);
buf.append("Signed sessionCreated:");
buf.append(" Alice: ").append(Addresses.toString(_aliceIP, _alicePort));
buf.append(" Bob: ").append(Addresses.toString(_bobIP, _bobPort));
buf.append(" RelayTag: ").append(_receivedRelayTag);
buf.append(" SignedOn: ").append(_receivedSignedOnTime);
buf.append(" signature: ").append(Base64.encode(_receivedSignature.getData()));
if (valid)
_log.debug(buf.toString());
else if (_log.shouldLog(Log.WARN))
_log.warn("INVALID: " + buf.toString());
}
return valid;
}
public synchronized SessionKey getCipherKey() { return _sessionKey; }
public synchronized SessionKey getMACKey() { return _macKey; }
public synchronized long getReceivedRelayTag() { return _receivedRelayTag; } public synchronized long getReceivedRelayTag() { return _receivedRelayTag; }
public synchronized long getSentSignedOnTime() { return _sentSignedOnTime; } public synchronized long getSentSignedOnTime() { return _sentSignedOnTime; }
public synchronized long getReceivedSignedOnTime() { return _receivedSignedOnTime; } public synchronized long getReceivedSignedOnTime() { return _receivedSignedOnTime; }
public synchronized byte[] getReceivedIP() { return _aliceIP; } public synchronized byte[] getReceivedIP() { return _aliceIP; }
public synchronized int getReceivedPort() { return _alicePort; } public synchronized int getReceivedPort() { return _alicePort; }
/**
* Let's sign everything so we can fragment properly.
*
* Note that while a SessionConfirmed could in theory be fragmented,
* in practice a RouterIdentity is 387 bytes and a single fragment is 512 bytes max,
* so it will never be fragmented.
*/
public synchronized void prepareSessionConfirmed() {
if (_sentSignedOnTime > 0)
return;
byte signed[] = new byte[256+256 // X + Y
+ _aliceIP.length + 2
+ _bobIP.length + 2
+ 4 // Alice's relay key
+ 4 // signed on time
];
_sentSignedOnTime = _context.clock().now() / 1000;
int off = 0;
System.arraycopy(_sentX, 0, signed, off, _sentX.length);
off += _sentX.length;
System.arraycopy(_receivedY, 0, signed, off, _receivedY.length);
off += _receivedY.length;
System.arraycopy(_aliceIP, 0, signed, off, _aliceIP.length);
off += _aliceIP.length;
DataHelper.toLong(signed, off, 2, _alicePort);
off += 2;
System.arraycopy(_bobIP, 0, signed, off, _bobIP.length);
off += _bobIP.length;
DataHelper.toLong(signed, off, 2, _bobPort);
off += 2;
DataHelper.toLong(signed, off, 4, _receivedRelayTag);
off += 4;
DataHelper.toLong(signed, off, 4, _sentSignedOnTime);
// BUG - if SigningPrivateKey is null, _sentSignature will be null, leading to NPE later
// should we throw something from here?
_sentSignature = _context.dsa().sign(signed, _context.keyManager().getSigningPrivateKey());
}
public synchronized Signature getSentSignature() { return _sentSignature; }
/** note that we just sent the SessionConfirmed packet */ /** note that we just sent the SessionConfirmed packet */
public synchronized void confirmedPacketsSent() { public synchronized void confirmedPacketsSent() {
_lastSend = _context.clock().now(); _lastSend = _context.clock().now();

View File

@@ -1,183 +0,0 @@
package net.i2p.router.transport.udp;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Arrays;
import java.util.concurrent.LinkedBlockingQueue;
// following are for main() tests
//import java.security.InvalidKeyException;
//import java.security.Key;
//import java.security.NoSuchAlgorithmException;
//import javax.crypto.spec.SecretKeySpec;
//import net.i2p.data.Base64;
import net.i2p.crypto.HMACGenerator;
import net.i2p.data.DataHelper;
import net.i2p.data.Hash;
import net.i2p.data.SessionKey;
import net.i2p.util.SimpleByteCache;
/**
* Calculate the HMAC-MD5-128 of a key+message. All the good stuff occurs
* in {@link I2PHMac}
*
* Keys are always 32 bytes.
* This is used only by UDP.
* Use deprecated outside the router, this may move to router.jar.
*
* NOTE THIS IS NOT COMPATIBLE with javax.crypto.Mac.getInstance("HmacMD5")
* as we tell I2PHMac that the digest length is 32 bytes, so it generates
* a different result.
*
* Quote jrandom:
* "The HMAC is hardcoded to use SHA256 digest size
* for backwards compatability. next time we have a backwards
* incompatible change, we should update this."
*
* Does this mean he intended it to be compatible with MD5?
* See also 2005-07-05 status notes.
*
* @since 0.9.42 moved from net.i2p.crypto.HMACGenerator
*/
class SSUHMACGenerator extends HMACGenerator {
/** set of available HMAC instances for calculate */
private final LinkedBlockingQueue<I2PHMac> _available;
public SSUHMACGenerator() {
super();
_available = new LinkedBlockingQueue<I2PHMac>(32);
}
/**
* Calculate the HMAC of the data with the given key
*
* @param target out parameter the first 16 bytes contain the HMAC, the last 16 bytes are zero
* @param targetOffset offset into target to put the hmac
* @throws IllegalArgumentException for bad key or target too small
*/
public void calculate(SessionKey key, byte data[], int offset, int length, byte target[], int targetOffset) {
if ((key == null) || (key.getData() == null) || (data == null))
throw new NullPointerException("Null arguments for HMAC");
I2PHMac mac = acquire();
mac.init(key.getData());
mac.update(data, offset, length);
mac.doFinal(target, targetOffset);
release(mac);
}
/**
* Verify the MAC inline, reducing some unnecessary memory churn.
*
* @param key session key to verify the MAC with
* @param curData MAC to verify
* @param curOffset index into curData to MAC
* @param curLength how much data in curData do we want to run the HMAC over
* @param origMAC what do we expect the MAC of curData to equal
* @param origMACOffset index into origMAC
* @param origMACLength how much of the MAC do we want to verify
* @throws IllegalArgumentException for bad key
*/
public boolean verify(SessionKey key, byte curData[], int curOffset, int curLength,
byte origMAC[], int origMACOffset, int origMACLength) {
if ((key == null) || (key.getData() == null) || (curData == null))
throw new NullPointerException("Null arguments for HMAC");
I2PHMac mac = acquire();
mac.init(key.getData());
mac.update(curData, curOffset, curLength);
byte rv[] = acquireTmp();
mac.doFinal(rv, 0);
release(mac);
boolean eq = DataHelper.eqCT(rv, 0, origMAC, origMACOffset, origMACLength);
releaseTmp(rv);
return eq;
}
private I2PHMac acquire() {
I2PHMac rv = _available.poll();
if (rv != null)
return rv;
// the HMAC is hardcoded to use SHA256 digest size
// for backwards compatability. next time we have a backwards
// incompatible change, we should update this by removing ", 32"
// SEE NOTES ABOVE
try {
MessageDigest md = MessageDigest.getInstance("MD5");
return new I2PHMac(md, 32);
} catch (NoSuchAlgorithmException nsae) {
throw new UnsupportedOperationException("MD5");
}
}
private void release(I2PHMac mac) {
_available.offer(mac);
}
/**
* @since 0.9.42
*/
public void clearCache() {
_available.clear();
}
//private static final int RUNS = 100000;
/**
* Test the BC and the JVM's implementations for speed
*/
/**** All this did was prove that we aren't compatible with standard HmacMD5
public static void main(String args[]) {
if (args.length != 2) {
System.err.println("Usage: HMACGenerator keySeedString dataString");
return;
}
byte[] rand = SHA256Generator.getInstance().calculateHash(args[0].getBytes()).getData();
byte[] data = args[1].getBytes();
Key keyObj = new SecretKeySpec(rand, "HmacMD5");
byte[] keyBytes = keyObj.getEncoded();
System.out.println("key bytes (" + keyBytes.length + ") is [" + Base64.encode(keyBytes) + "]");
SessionKey key = new SessionKey(keyBytes);
System.out.println("session key is [" + key);
System.out.println("key object is [" + keyObj);
HMACGenerator gen = new HMACGenerator(I2PAppContext.getGlobalContext());
byte[] result = new byte[16];
long start = System.currentTimeMillis();
for (int i = 0; i < RUNS; i++) {
gen.calculate(key, data, 0, data.length, result, 0);
if (i == 0)
System.out.println("MAC [" + Base64.encode(result) + "]");
}
long time = System.currentTimeMillis() - start;
System.out.println("Time for " + RUNS + " HMAC-MD5 computations:");
System.out.println("BC time (ms): " + time);
start = System.currentTimeMillis();
javax.crypto.Mac mac;
try {
mac = javax.crypto.Mac.getInstance("HmacMD5");
} catch (NoSuchAlgorithmException e) {
System.err.println("Fatal: " + e);
return;
}
for (int i = 0; i < RUNS; i++) {
try {
mac.init(keyObj);
} catch (InvalidKeyException e) {
System.err.println("Fatal: " + e);
}
byte[] sha = mac.doFinal(data);
if (i == 0)
System.out.println("MAC [" + Base64.encode(sha) + "]");
}
time = System.currentTimeMillis() - start;
System.out.println("JVM time (ms): " + time);
}
****/
}

View File

@@ -241,100 +241,6 @@ class UDPPacket implements CDPQEntry {
} }
return _remoteHost; return _remoteHost;
} }
/**
* Validate the packet against the MAC specified, returning true if the
* MAC matches, false otherwise.
*
*/
public synchronized boolean validate(SessionKey macKey, HMACGenerator hmac) {
verifyNotReleased();
//_beforeValidate = _context.clock().now();
boolean eq = false;
Arrays.fill(_validateBuf, (byte)0);
// validate by comparing _data[0:15] and
// HMAC(payload + IV + (payloadLength ^ protocolVersion), macKey)
int payloadLength = _packet.getLength() - MAC_SIZE - IV_SIZE;
if (payloadLength > 0) {
int off = 0;
System.arraycopy(_data, _packet.getOffset() + MAC_SIZE + IV_SIZE, _validateBuf, off, payloadLength);
off += payloadLength;
System.arraycopy(_data, _packet.getOffset() + MAC_SIZE, _validateBuf, off, IV_SIZE);
off += IV_SIZE;
// version is zero, unlikely to ever change
int plval = payloadLength /* ^ PacketBuilder.PROTOCOL_VERSION */ ;
// network ID cross-check, proposal 147
int netid = _context.router().getNetworkID();
if (netid != 2) {
plval ^= (netid - 2) << 8;
}
DataHelper.toLong(_validateBuf, off, 2, plval);
off += 2;
eq = hmac.verify(macKey, _validateBuf, 0, off, _data, _packet.getOffset(), MAC_SIZE);
if (!eq) {
// this is relatively frequent, as you can get old keys in PacketHandler.
Log log = _context.logManager().getLog(UDPPacket.class);
if (log.shouldLog(Log.INFO)) {
byte[] calc = new byte[32];
hmac.calculate(macKey, _validateBuf, 0, off, calc, 0);
StringBuilder str = new StringBuilder(512);
str.append("Bad HMAC:\n\t");
str.append(_packet.getLength()).append(" byte pkt, ");
str.append(payloadLength).append(" byte payload");
str.append("\n\tFrom: ").append(getRemoteHost().toString());
str.append("\n\tIV: ").append(Base64.encode(_validateBuf, payloadLength, IV_SIZE));
str.append("\n\tIV2: ").append(Base64.encode(_data, MAC_SIZE, IV_SIZE));
str.append("\n\tGiven Len: ").append(DataHelper.fromLong(_validateBuf, payloadLength + IV_SIZE, 2));
str.append("\n\tCalc HMAC: ").append(Base64.encode(calc, 0, MAC_SIZE));
str.append("\n\tRead HMAC: ").append(Base64.encode(_data, _packet.getOffset(), MAC_SIZE));
str.append("\n\tUsing key: ").append(macKey.toBase64());
if (DataHelper.eq(macKey.getData(), 0, _context.routerHash().getData(), 0, 32))
str.append(" (Intro)");
else
str.append(" (Session)");
str.append("\n\tRaw: ").append(Base64.encode(_data, _packet.getOffset(), _packet.getLength()));
log.info(str.toString(), new Exception());
}
}
} else {
Log log = _context.logManager().getLog(UDPPacket.class);
if (log.shouldLog(Log.WARN))
log.warn("Payload length is " + payloadLength + ", too short! From: " + getRemoteHost() + '\n' +
net.i2p.util.HexDump.dump(_data, _packet.getOffset(), _packet.getLength()));
}
//_afterValidate = _context.clock().now();
_validateCount++;
return eq;
}
/**
* Decrypt this valid packet, overwriting the _data buffer's payload
* with the decrypted data (leaving the MAC and IV unaltered)
*
* SSU 1 only.
* SSU 2 decryption is in PacketHandler.
*
*/
public synchronized void decrypt(SessionKey cipherKey) {
verifyNotReleased();
System.arraycopy(_data, MAC_SIZE, _ivBuf, 0, IV_SIZE);
int len = _packet.getLength();
// As of 0.9.7, ignore padding beyond the last mod 16,
// it could otherwise blow up in decryption.
// This allows for better obfuscation.
// Probably works without this since _data is bigger than necessary, but let's not
// bother decrypting and risk overrun.
int rem = len & 0x0f;
if (rem != 0)
len -= rem;
int off = _packet.getOffset() + MAC_SIZE + IV_SIZE;
_context.aes().decrypt(_data, off, _data, off, cipherKey, _ivBuf, len - MAC_SIZE - IV_SIZE);
}
/** /**
* For CDQ * For CDQ

View File

@@ -1,922 +0,0 @@
package net.i2p.router.transport.udp;
import net.i2p.I2PAppContext;
import net.i2p.data.Base64;
import net.i2p.data.DataFormatException;
import net.i2p.data.DataHelper;
import net.i2p.data.SessionKey;
import net.i2p.data.Signature;
import net.i2p.util.Log;
/**
* To read a packet, initialize this reader with the data and fetch out
* the appropriate fields. If the interesting bits are in message specific
* elements, grab the appropriate subreader.
*
* Many of the methods here and in the subclasses will throw AIOOBE on
* malformed packets, that should be caught also.
*
*/
class UDPPacketReader {
//private final I2PAppContext _context;
//private final Log _log;
private byte _message[];
private int _payloadBeginOffset;
private int _payloadLength;
private final SessionRequestReader _sessionRequestReader;
private final SessionCreatedReader _sessionCreatedReader;
private final SessionConfirmedReader _sessionConfirmedReader;
private final DataReader _dataReader;
private final PeerTestReader _peerTestReader;
private final RelayRequestReader _relayRequestReader;
private final RelayIntroReader _relayIntroReader;
private final RelayResponseReader _relayResponseReader;
private static final int KEYING_MATERIAL_LENGTH = 64;
/**
* @param ctx unused
*/
public UDPPacketReader(I2PAppContext ctx) {
//_context = ctx;
//_log = ctx.logManager().getLog(UDPPacketReader.class);
_sessionRequestReader = new SessionRequestReader();
_sessionCreatedReader = new SessionCreatedReader();
_sessionConfirmedReader = new SessionConfirmedReader();
_dataReader = new DataReader();
_peerTestReader = new PeerTestReader();
_relayRequestReader = new RelayRequestReader();
_relayIntroReader = new RelayIntroReader();
_relayResponseReader = new RelayResponseReader();
}
public void initialize(UDPPacket packet) {
int off = packet.getPacket().getOffset();
int len = packet.getPacket().getLength();
off += UDPPacket.MAC_SIZE + UDPPacket.IV_SIZE;
len -= UDPPacket.MAC_SIZE + UDPPacket.IV_SIZE;
initialize(packet.getPacket().getData(), off, len);
}
private void initialize(byte message[], int payloadOffset, int payloadLength) {
_message = message;
_payloadBeginOffset = payloadOffset;
_payloadLength = payloadLength;
}
/** what type of payload is in here? */
public int readPayloadType() {
// 4 highest order bits == payload type
return (_message[_payloadBeginOffset] & 0xFF) >>> 4;
}
/**
* Does this packet include rekeying data in the header?
* Unused, should always be false.
*/
public boolean isRekeyingIncluded() {
return (_message[_payloadBeginOffset] & UDPPacket.HEADER_FLAG_REKEY) != 0;
}
/**
* Does this packet include extended options in the header?
*/
public boolean isExtendedOptionsIncluded() {
return (_message[_payloadBeginOffset] & UDPPacket.HEADER_FLAG_EXTENDED_OPTIONS) != 0;
}
/** @return seconds */
public long readTimestamp() {
// Note, this is unsigned, so we're good until February 2106
return DataHelper.fromLong(_message, _payloadBeginOffset + 1, 4);
}
/**
* Returns rekeying data (64 bytes), or null if none.
* Unused, should always return null.
*
* @deprecated unused
*/
@Deprecated
public byte[] readKeyingMaterial() {
if (!isRekeyingIncluded())
return null;
byte[] rv = new byte[KEYING_MATERIAL_LENGTH];
System.arraycopy(_message, _payloadBeginOffset + 1 + 4, rv, 0, KEYING_MATERIAL_LENGTH);
return rv;
}
/**
* Returns extended option data, 0-255 bytes, or null if none.
* Returned array does NOT include the length byte.
*
* @return extended options or null if none is included
* @since 0.9.24
*/
public byte[] readExtendedOptions() {
if (!isExtendedOptionsIncluded())
return null;
int offset = _payloadBeginOffset + 1 + 4;
if (isRekeyingIncluded())
offset += KEYING_MATERIAL_LENGTH;
int optionsSize = _message[offset++] & 0xff;
byte[] rv = new byte[optionsSize];
System.arraycopy(_message, offset, rv, 0, optionsSize);
return rv;
}
/** index into the message where the body begins */
private int readBodyOffset() {
int offset = _payloadBeginOffset + 1 + 4;
if (isRekeyingIncluded())
offset += KEYING_MATERIAL_LENGTH;
if (isExtendedOptionsIncluded()) {
int optionsSize = _message[offset] & 0xff;
offset += optionsSize + 1;
}
return offset;
}
public SessionRequestReader getSessionRequestReader() { return _sessionRequestReader; }
public SessionCreatedReader getSessionCreatedReader() { return _sessionCreatedReader; }
public SessionConfirmedReader getSessionConfirmedReader() { return _sessionConfirmedReader; }
public DataReader getDataReader() { return _dataReader; }
public PeerTestReader getPeerTestReader() { return _peerTestReader; }
public RelayRequestReader getRelayRequestReader() { return _relayRequestReader; }
public RelayIntroReader getRelayIntroReader() { return _relayIntroReader; }
public RelayResponseReader getRelayResponseReader() { return _relayResponseReader; }
@Override
public String toString() {
int type = readPayloadType();
switch (type) {
case UDPPacket.PAYLOAD_TYPE_DATA:
return _dataReader.toString();
case UDPPacket.PAYLOAD_TYPE_SESSION_CONFIRMED:
return "Session confirmed packet";
case UDPPacket.PAYLOAD_TYPE_SESSION_CREATED:
return "Session created packet";
case UDPPacket.PAYLOAD_TYPE_SESSION_REQUEST:
return "Session request packet";
case UDPPacket.PAYLOAD_TYPE_TEST:
return "Peer test packet";
case UDPPacket.PAYLOAD_TYPE_RELAY_INTRO:
return "Relay intro packet";
case UDPPacket.PAYLOAD_TYPE_RELAY_REQUEST:
return "Relay request packet";
case UDPPacket.PAYLOAD_TYPE_RELAY_RESPONSE:
return "Relay response packet";
case UDPPacket.PAYLOAD_TYPE_SESSION_DESTROY:
return "Session destroyed packet";
default:
return "Unknown packet type " + type;
}
}
public void toRawString(StringBuilder buf) {
if (_message != null)
buf.append(Base64.encode(_message, _payloadBeginOffset, _payloadLength));
}
/* ------- Begin Reader Classes ------- */
/**
* Base
*
* @since 0.9.24
*/
public abstract class Reader {
/**
* Returns extended option data from the header, 0-255 bytes, or null if none.
* Returned array does NOT include the length byte.
*
* @return extended options or null if none is included
* @since 0.9.24
*/
public byte[] readExtendedOptions() {
return UDPPacketReader.this.readExtendedOptions();
}
}
/** Help read the SessionRequest payload */
public class SessionRequestReader extends Reader {
public static final int X_LENGTH = 256;
public void readX(byte target[], int targetOffset) {
int readOffset = readBodyOffset();
System.arraycopy(_message, readOffset, target, targetOffset, X_LENGTH);
}
public int readIPSize() {
int offset = readBodyOffset() + X_LENGTH;
return _message[offset] & 0xff;
}
/** what IP bob is reachable on */
public void readIP(byte target[], int targetOffset) {
int offset = readBodyOffset() + X_LENGTH;
int size = _message[offset] & 0xff;
offset++;
System.arraycopy(_message, offset, target, targetOffset, size);
}
}
/** Help read the SessionCreated payload */
public class SessionCreatedReader extends Reader {
public static final int Y_LENGTH = 256;
public void readY(byte target[], int targetOffset) {
int readOffset = readBodyOffset();
System.arraycopy(_message, readOffset, target, targetOffset, Y_LENGTH);
}
/** sizeof(IP) */
public int readIPSize() {
int offset = readBodyOffset() + Y_LENGTH;
return _message[offset] & 0xff;
}
/** what IP do they think we are coming on? */
public void readIP(byte target[], int targetOffset) {
int offset = readBodyOffset() + Y_LENGTH;
int size = _message[offset] & 0xff;
offset++;
System.arraycopy(_message, offset, target, targetOffset, size);
}
/** what port do they think we are coming from? */
public int readPort() {
int offset = readBodyOffset() + Y_LENGTH + 1 + readIPSize();
return (int)DataHelper.fromLong(_message, offset, 2);
}
/** read in the 4 byte relayAs tag */
public long readRelayTag() {
int offset = readBodyOffset() + Y_LENGTH + 1 + readIPSize() + 2;
return DataHelper.fromLong(_message, offset, 4);
}
public long readSignedOnTime() {
int offset = readBodyOffset() + Y_LENGTH + 1 + readIPSize() + 2 + 4;
long rv = DataHelper.fromLong(_message, offset, 4);
//if (_log.shouldLog(Log.DEBUG))
// _log.debug("Signed on time offset: " + offset + " val: " + rv
// + "\nRawCreated: " + Base64.encode(_message, _payloadBeginOffset, _payloadLength));
return rv;
}
/** @param size the amount to be copied, including padding to mod 16 */
public void readEncryptedSignature(byte target[], int targetOffset, int size) {
int offset = readBodyOffset() + Y_LENGTH + 1 + readIPSize() + 2 + 4 + 4;
System.arraycopy(_message, offset, target, targetOffset, size);
}
public void readIV(byte target[], int targetOffset) {
int offset = _payloadBeginOffset - UDPPacket.IV_SIZE;
System.arraycopy(_message, offset, target, targetOffset, UDPPacket.IV_SIZE);
}
}
/** parse out the confirmed message */
public class SessionConfirmedReader extends Reader {
/** which fragment is this? */
public int readCurrentFragmentNum() {
int readOffset = readBodyOffset();
return (_message[readOffset] & 0xFF) >>> 4;
}
/** how many fragments will there be? */
public int readTotalFragmentNum() {
int readOffset = readBodyOffset();
return (_message[readOffset] & 0xF);
}
public int readCurrentFragmentSize() {
int readOffset = readBodyOffset() + 1;
return (int)DataHelper.fromLong(_message, readOffset, 2);
}
/** read the fragment data from the nonterminal sessionConfirmed packet */
public void readFragmentData(byte target[], int targetOffset) {
int readOffset = readBodyOffset() + 1 + 2;
int len = readCurrentFragmentSize();
System.arraycopy(_message, readOffset, target, targetOffset, len);
}
/**
* Read the time at which the signature was generated.
* TODO must be completely in final fragment.
* Time and sig cannot be split across fragments.
*/
public long readFinalFragmentSignedOnTime() {
if (readCurrentFragmentNum() != readTotalFragmentNum()-1)
throw new IllegalStateException("This is not the final fragment");
int readOffset = readBodyOffset() + 1 + 2 + readCurrentFragmentSize();
return DataHelper.fromLong(_message, readOffset, 4);
}
/**
* Read the signature from the final sessionConfirmed packet.
* TODO must be completely in final fragment.
* Time and sig cannot be split across fragments.
* @param size not including padding
*/
public void readFinalSignature(byte target[], int targetOffset, int size) {
if (readCurrentFragmentNum() != readTotalFragmentNum()-1)
throw new IllegalStateException("This is not the final fragment");
int readOffset = _payloadBeginOffset + _payloadLength - size;
if (readOffset < readBodyOffset() + (1 + 2 + 4))
throw new IllegalStateException("Sig split across fragments");
System.arraycopy(_message, readOffset, target, targetOffset, size);
}
}
/** parse out the data message */
public class DataReader extends Reader {
/**
* @return the data size, NOT including IP header, UDP header, IV, or MAC
*/
public int getPacketSize() { return _payloadLength; }
public boolean readACKsIncluded() {
return flagSet(UDPPacket.DATA_FLAG_EXPLICIT_ACK);
}
public boolean readACKBitfieldsIncluded() {
return flagSet(UDPPacket.DATA_FLAG_ACK_BITFIELDS);
}
public boolean readECN() {
return flagSet(UDPPacket.DATA_FLAG_ECN);
}
public boolean readWantPreviousACKs() {
return flagSet(UDPPacket.DATA_FLAG_WANT_ACKS);
}
public boolean readReplyRequested() {
return flagSet(UDPPacket.DATA_FLAG_WANT_REPLY);
}
public boolean readExtendedDataIncluded() {
return flagSet(UDPPacket.DATA_FLAG_EXTENDED);
}
public int readACKCount() {
if (!readACKsIncluded()) return 0;
int off = readBodyOffset() + 1;
return _message[off] & 0xff;
}
public long readACK(int index) {
if (!readACKsIncluded()) return -1;
int off = readBodyOffset() + 1;
//int num = (int)DataHelper.fromLong(_message, off, 1);
off++;
return DataHelper.fromLong(_message, off + (4 * index), 4);
}
public ACKBitfield[] readACKBitfields() throws DataFormatException {
if (!readACKBitfieldsIncluded()) return null;
int off = readBodyOffset() + 1;
if (readACKsIncluded()) {
int numACKs = _message[off] & 0xff;
off++;
off += 4 * numACKs;
}
int numBitfields = _message[off] & 0xff;
off++;
PacketACKBitfield rv[] = new PacketACKBitfield[numBitfields];
for (int i = 0; i < numBitfields; i++) {
rv[i] = new PacketACKBitfield(off);
off += rv[i].getByteLength();
}
return rv;
}
public int readFragmentCount() throws DataFormatException {
int off = readBodyOffset() + 1;
if (readACKsIncluded()) {
int numACKs = _message[off] & 0xff;
off++;
off += 4 * numACKs;
}
if (readACKBitfieldsIncluded()) {
int numBitfields = _message[off] & 0xff;
off++;
for (int i = 0; i < numBitfields; i++) {
PacketACKBitfield bf = new PacketACKBitfield(off);
off += bf.getByteLength();
}
}
if (readExtendedDataIncluded()) {
int size = _message[off] & 0xff;
off++;
off += size;
}
return _message[off];
}
public long readMessageId(int fragmentNum) throws DataFormatException {
int fragmentBegin = getFragmentBegin(fragmentNum);
return DataHelper.fromLong(_message, fragmentBegin, 4);
}
public int readMessageFragmentNum(int fragmentNum) throws DataFormatException {
int off = getFragmentBegin(fragmentNum);
off += 4; // messageId
return (_message[off] & 0xFF) >>> 1;
}
public boolean readMessageIsLast(int fragmentNum) throws DataFormatException {
int off = getFragmentBegin(fragmentNum);
off += 4; // messageId
return ((_message[off] & 1) != 0);
}
public int readMessageFragmentSize(int fragmentNum) throws DataFormatException {
int off = getFragmentBegin(fragmentNum);
off += 5; // messageId + fragment info
return ((int)DataHelper.fromLong(_message, off, 2)) & 0x3FFF;
}
public void readMessageFragment(int fragmentNum, byte target[], int targetOffset)
throws DataFormatException {
int off = getFragmentBegin(fragmentNum);
off += 5; // messageId + fragment info
int size = ((int)DataHelper.fromLong(_message, off, 2)) & 0x3FFF;
off += 2;
System.arraycopy(_message, off, target, targetOffset, size);
}
private int getFragmentBegin(int fragmentNum) throws DataFormatException {
int off = readBodyOffset() + 1;
if (readACKsIncluded()) {
int numACKs = _message[off] & 0xff;
off++;
off += 4 * numACKs;
}
if (readACKBitfieldsIncluded()) {
int numBitfields = _message[off] & 0xff;
off++;
PacketACKBitfield bf[] = new PacketACKBitfield[numBitfields];
for (int i = 0; i < numBitfields; i++) {
bf[i] = new PacketACKBitfield(off);
off += bf[i].getByteLength();
}
}
if (readExtendedDataIncluded()) {
int size = _message[off] & 0xff;
off++;
off += size;
}
off++; // # fragments
if (fragmentNum > 0) {
for (int i = 0; i < fragmentNum; i++) {
off += 5; // messageId+info
off += ((int)DataHelper.fromLong(_message, off, 2)) & 0x3FFF;
off += 2;
}
}
return off;
}
private boolean flagSet(byte flag) {
int flagOffset = readBodyOffset();
return ((_message[flagOffset] & flag) != 0);
}
@Override
public String toString() {
StringBuilder buf = new StringBuilder(512);
long msAgo = System.currentTimeMillis() - readTimestamp()*1000;
buf.append("Data packet sent ").append(msAgo).append("ms ago ");
buf.append("IV ");
buf.append(Base64.encode(_message, _payloadBeginOffset-UDPPacket.IV_SIZE, UDPPacket.IV_SIZE));
buf.append(" ");
int off = readBodyOffset() + 1;
if (readACKsIncluded()) {
int numACKs = _message[off] & 0xff;
off++;
buf.append("with ACKs for ");
for (int i = 0; i < numACKs; i++) {
buf.append(DataHelper.fromLong(_message, off, 4)).append(' ');
off += 4;
}
}
if (readACKBitfieldsIncluded()) {
int numBitfields = _message[off] & 0xff;
off++;
buf.append("with partial ACKs for ");
try {
for (int i = 0; i < numBitfields; i++) {
PacketACKBitfield bf = new PacketACKBitfield(off);
buf.append(bf.getMessageId()).append(' ');
off += bf.getByteLength();
}
} catch (DataFormatException dfe) {
buf.append("CORRUPT");
return buf.toString();
}
}
if (readExtendedDataIncluded()) {
int size = _message[off] & 0xff;
off++;
buf.append("with extended size of ");
buf.append(size);
buf.append(' ');
off += size;
}
int numFragments = _message[off] & 0xff;
off++;
buf.append("with fragmentCount of ");
buf.append(numFragments);
buf.append(' ');
for (int i = 0; i < numFragments; i++) {
buf.append("containing messageId ");
buf.append(DataHelper.fromLong(_message, off, 4));
off += 4;
int fragNum = (_message[off] & 0xFF) >>> 1;
boolean isLast = (_message[off] & 1) != 0;
off++;
buf.append(" frag# ").append(fragNum);
buf.append(" isLast? ").append(isLast);
buf.append(" info ").append(_message[off-1]);
int size = ((int)DataHelper.fromLong(_message, off, 2)) & 0x3FFF;
off += 2;
buf.append(" with ").append(size).append(" bytes; ");
off += size;
}
return buf.toString();
}
public void toRawString(StringBuilder buf) throws DataFormatException {
UDPPacketReader.this.toRawString(buf);
buf.append(" payload: ");
int off = getFragmentBegin(0); // first fragment
off += 4 + 1; // messageId + fragment info
int size = ((int)DataHelper.fromLong(_message, off, 2)) & 0x3FFF;
off += 2;
buf.append(Base64.encode(_message, off, size));
}
}
/**
* Helper class to fetch the particular bitfields from the raw packet
*/
private class PacketACKBitfield implements ACKBitfield {
private final int _start;
private final int _bitfieldStart;
private final int _bitfieldSize;
public PacketACKBitfield(int start) throws DataFormatException {
_start = start;
_bitfieldStart = start + 4;
int bfsz = 1;
// bitfield is an array of bytes where the high bit is 1 if
// further bytes in the bitfield follow
while ((_message[_bitfieldStart + bfsz - 1] & UDPPacket.BITFIELD_CONTINUATION) != 0x0) {
bfsz++;
//if (bfsz > InboundMessageState.MAX_PARTIAL_BITFIELD_BYTES)
// throw new DataFormatException();
}
if (bfsz > InboundMessageState.MAX_PARTIAL_BITFIELD_BYTES)
throw new DataFormatException("bitfield size: " + bfsz);
_bitfieldSize = bfsz;
}
public long getMessageId() { return DataHelper.fromLong(_message, _start, 4); }
public int getByteLength() { return 4 + _bitfieldSize; }
public int fragmentCount() { return _bitfieldSize * 7; }
public boolean receivedComplete() { return false; }
/**
* Number of fragments acked in this bitfield.
* Faster than looping through received()
* @since 0.9.16
*/
public int ackCount() {
int rv = 0;
for (int i = _bitfieldStart; i < _bitfieldStart + _bitfieldSize; i++) {
byte b = _message[i];
if ((b & 0x7f) != 0) {
for (int j = 0; j < 7; j++) {
if ((b & 0x01) != 0)
rv++;
b >>= 1;
}
}
}
return rv;
}
/**
* Highest fragment number acked in this bitfield.
* @return highest fragment number acked, or -1 if none
* @since 0.9.16
*/
public int highestReceived() {
for (int i = _bitfieldSize - 1; i >= 0; i--) {
byte b = _message[_bitfieldStart + i];
if ((b & 0x7f) == 0)
continue;
for (int j = 6; j >= 0; j--) {
if ((b & 0x40) != 0)
return (7 * i) + j;
b <<= 1;
}
}
return -1;
}
public boolean received(int fragmentNum) {
if ( (fragmentNum < 0) || (fragmentNum >= _bitfieldSize*7) )
return false;
// the fragment has been received if the bit is set
int byteNum = _bitfieldStart + (fragmentNum/7);
int flagNum = fragmentNum % 7;
return (_message[byteNum] & (1 << flagNum)) != 0x0;
}
@Override
public String toString() {
StringBuilder buf = new StringBuilder(64);
buf.append("IB Partial ACK of ");
buf.append(getMessageId());
buf.append(" highest: ").append(highestReceived());
buf.append(" with ACKs for: [");
int numFrags = fragmentCount();
for (int i = 0; i < numFrags; i++) {
if (received(i))
buf.append(i).append(' ');
}
buf.append("] / ").append(numFrags);
return buf.toString();
}
}
/** Help read the PeerTest payload */
public class PeerTestReader extends Reader {
private static final int NONCE_LENGTH = 4;
public long readNonce() {
int readOffset = readBodyOffset();
return DataHelper.fromLong(_message, readOffset, NONCE_LENGTH);
}
public int readIPSize() {
int offset = readBodyOffset() + NONCE_LENGTH;
return _message[offset] & 0xff;
}
/** what IP Alice is reachable on */
public void readIP(byte target[], int targetOffset) {
int offset = readBodyOffset() + NONCE_LENGTH;
int size = _message[offset] & 0xff;
offset++;
System.arraycopy(_message, offset, target, targetOffset, size);
}
/** what IP Alice is reachable on */
public int readPort() {
int offset = readBodyOffset() + NONCE_LENGTH;
int size = _message[offset] & 0xff;
offset++;
offset += size; // skip the IP
return (int)DataHelper.fromLong(_message, offset, 2);
}
/** what Alice's intro key is (if known - if unknown, the key is INVALID_KEY) */
public void readIntroKey(byte target[], int targetOffset) {
int offset = readBodyOffset() + NONCE_LENGTH;
int size = _message[offset] & 0xff;
offset += 1 + 2; // skip the size + port
offset += size; // skip the IP
System.arraycopy(_message, offset, target, targetOffset, SessionKey.KEYSIZE_BYTES);
}
}
/** Help read the RelayRequest payload */
public class RelayRequestReader extends Reader {
public long readTag() {
long rv = DataHelper.fromLong(_message, readBodyOffset(), 4);
//if (_log.shouldLog(Log.DEBUG))
// _log.debug("read alice tag: " + rv);
return rv;
}
public int readIPSize() {
int offset = readBodyOffset() + 4;
int rv = _message[offset] & 0xff;
//if (_log.shouldLog(Log.DEBUG))
// _log.debug("read alice ip size: " + rv);
return rv;
}
/** what IP Alice is reachable on */
public void readIP(byte target[], int targetOffset) {
int offset = readBodyOffset() + 4;
int size = _message[offset] & 0xff;
offset++;
System.arraycopy(_message, offset, target, targetOffset, size);
//if (_log.shouldLog(Log.DEBUG))
// _log.debug("read alice ip: " + Base64.encode(target, targetOffset, size));
}
public int readPort() {
int offset = readBodyOffset() + 4;
offset += _message[offset] & 0xff;
offset++;
int rv = (int)DataHelper.fromLong(_message, offset, 2);
//if (_log.shouldLog(Log.DEBUG))
// _log.debug("read alice port: " + rv);
return rv;
}
/** unused */
public int readChallengeSize() {
int offset = readBodyOffset() + 4;
offset += _message[offset] & 0xff;
offset += 1 + 2;
int rv = _message[offset] & 0xff;
//if (_log.shouldLog(Log.DEBUG))
// _log.debug("read challenge size: " + rv);
return rv;
}
/** unused */
public void readChallengeData(byte target[], int targetOffset) {
int offset = readBodyOffset() + 4;
offset += _message[offset] & 0xff;
offset += 1 + 2;
int sz = _message[offset] & 0xff;
offset++;
System.arraycopy(_message, offset, target, targetOffset, sz);
//if (_log.shouldLog(Log.DEBUG))
// _log.debug("read challenge data: " + Base64.encode(target));
}
public void readAliceIntroKey(byte target[], int targetOffset) {
int offset = readBodyOffset() + 4;
offset += _message[offset] & 0xff;
offset += 1 + 2;
int sz = _message[offset] & 0xff;
offset++;
offset += sz;
System.arraycopy(_message, offset, target, targetOffset, SessionKey.KEYSIZE_BYTES);
//if (_log.shouldLog(Log.DEBUG))
// _log.debug("read alice intro key: " + Base64.encode(target, targetOffset, SessionKey.KEYSIZE_BYTES)
// + " packet size: " + _payloadLength + " off: " + offset + " data: " + Base64.encode(_message));
}
public long readNonce() {
int offset = readBodyOffset() + 4;
offset += _message[offset] & 0xff;
offset += 1 + 2;
int sz = _message[offset] & 0xff;
offset++;
offset += sz;
offset += SessionKey.KEYSIZE_BYTES;
long rv = DataHelper.fromLong(_message, offset, 4);
//if (_log.shouldLog(Log.DEBUG))
// _log.debug("read request nonce: " + rv);
return rv;
}
}
/** Help read the RelayIntro payload */
public class RelayIntroReader extends Reader {
public int readIPSize() {
int offset = readBodyOffset();
return _message[offset] & 0xff;
}
/** what IP Alice is reachable on */
public void readIP(byte target[], int targetOffset) {
int offset = readBodyOffset();
int size = _message[offset] & 0xff;
offset++;
System.arraycopy(_message, offset, target, targetOffset, size);
}
public int readPort() {
int offset = readBodyOffset();
offset += _message[offset] & 0xff;
offset++;
return (int)DataHelper.fromLong(_message, offset, 2);
}
/** unused */
public int readChallengeSize() {
int offset = readBodyOffset();
offset += _message[offset] & 0xff;
offset += 1 + 2;
return _message[offset] & 0xff;
}
/** unused */
public void readChallengeData(byte target[], int targetOffset) {
int offset = readBodyOffset();
offset += _message[offset] & 0xff;
offset += 1 + 2;
int sz = _message[offset] & 0xff;
offset++;
System.arraycopy(_message, offset, target, targetOffset, sz);
}
}
/** Help read the RelayResponse payload */
public class RelayResponseReader extends Reader {
public int readCharlieIPSize() {
int offset = readBodyOffset();
return _message[offset] & 0xff;
}
/** what IP charlie is reachable on */
public void readCharlieIP(byte target[], int targetOffset) {
int offset = readBodyOffset();
int size = _message[offset] & 0xff;
offset++;
System.arraycopy(_message, offset, target, targetOffset, size);
}
/** what port charlie is reachable on */
public int readCharliePort() {
int offset = readBodyOffset();
offset += _message[offset] & 0xff;
offset++;
return (int)DataHelper.fromLong(_message, offset, 2);
}
/** @deprecated unused */
@Deprecated
public int readAliceIPSize() {
int offset = readBodyOffset();
offset += _message[offset] & 0xff;
offset += 1 + 2;
return _message[offset] & 0xff;
}
/** @deprecated unused */
@Deprecated
public void readAliceIP(byte target[], int targetOffset) {
int offset = readBodyOffset();
offset += _message[offset] & 0xff;
offset += 1 + 2;
int sz = _message[offset] & 0xff;
offset++;
System.arraycopy(_message, offset, target, targetOffset, sz);
}
/** @deprecated unused */
@Deprecated
public int readAlicePort() {
int offset = readBodyOffset();
offset += _message[offset] & 0xff;
offset += 1 + 2;
int sz = _message[offset] & 0xff;
offset++;
offset += sz;
return (int)DataHelper.fromLong(_message, offset, 2);
}
public long readNonce() {
int offset = readBodyOffset();
offset += _message[offset] & 0xff;
offset += 1 + 2;
int sz = _message[offset] & 0xff;
offset += 1 + 2; // sz + port
offset += sz;
return DataHelper.fromLong(_message, offset, 4);
}
}
/* ------- End Reader Classes ------- */
/******
public static void main(String args[]) {
I2PAppContext ctx = I2PAppContext.getGlobalContext();
try {
PacketBuilder b = new PacketBuilder(ctx, null);
InetAddress introHost = InetAddress.getLocalHost();
int introPort = 1234;
byte introKey[] = new byte[SessionKey.KEYSIZE_BYTES];
ctx.random().nextBytes(introKey);
long introTag = ctx.random().nextLong(0xFFFFFFFFl);
long introNonce = ctx.random().nextLong(0xFFFFFFFFl);
SessionKey ourIntroKey = ctx.keyGenerator().generateSessionKey();
UDPPacket packet = b.buildRelayRequest(introHost, introPort, introKey, introTag, ourIntroKey, introNonce, false);
UDPPacketReader r = new UDPPacketReader(ctx);
r.initialize(packet);
RelayRequestReader reader = r.getRelayRequestReader();
System.out.println("Nonce: " + reader.readNonce() + " / " + introNonce);
System.out.println("Tag : " + reader.readTag() + " / " + introTag);
byte readKey[] = new byte[SessionKey.KEYSIZE_BYTES];
reader.readAliceIntroKey(readKey, 0);
System.out.println("Key : " + Base64.encode(readKey) + " / " + ourIntroKey.toBase64());
} catch (Exception e) {
e.printStackTrace();
}
}
*******/
}

View File

@@ -23,7 +23,6 @@ import java.util.concurrent.CopyOnWriteArrayList;
import net.i2p.CoreVersion; import net.i2p.CoreVersion;
import net.i2p.crypto.EncType; import net.i2p.crypto.EncType;
import net.i2p.crypto.HMACGenerator;
import net.i2p.crypto.KeyPair; import net.i2p.crypto.KeyPair;
import net.i2p.crypto.SigType; import net.i2p.crypto.SigType;
import net.i2p.data.Base64; import net.i2p.data.Base64;
@@ -102,7 +101,6 @@ public class UDPTransport extends TransportImpl implements TimedWeightedPriority
private long _v6IntroducersSelectedOn; private long _v6IntroducersSelectedOn;
private long _lastInboundReceivedOn; private long _lastInboundReceivedOn;
private final DHSessionKeyBuilder.Factory _dhFactory; private final DHSessionKeyBuilder.Factory _dhFactory;
private final SSUHMACGenerator _hmac;
private int _mtu = PeerState.MIN_MTU; private int _mtu = PeerState.MIN_MTU;
private int _mtu_ipv6 = PeerState.MIN_IPV6_MTU; private int _mtu_ipv6 = PeerState.MIN_IPV6_MTU;
private int _mtu_ssu2; private int _mtu_ssu2;
@@ -421,7 +419,6 @@ public class UDPTransport extends TransportImpl implements TimedWeightedPriority
_v4IntroducersSelectedOn = -1; _v4IntroducersSelectedOn = -1;
_v6IntroducersSelectedOn = -1; _v6IntroducersSelectedOn = -1;
_lastInboundReceivedOn = -1; _lastInboundReceivedOn = -1;
_hmac = (dh != null) ? new SSUHMACGenerator() : null;
_mtu = PeerState.LARGE_MTU; _mtu = PeerState.LARGE_MTU;
_mtu_ipv6 = PeerState.MIN_IPV6_MTU; _mtu_ipv6 = PeerState.MIN_IPV6_MTU;
setupPort(); setupPort();
@@ -939,8 +936,6 @@ public class UDPTransport extends TransportImpl implements TimedWeightedPriority
UDPPacket.clearCache(); UDPPacket.clearCache();
UDPAddress.clearCache(); UDPAddress.clearCache();
_lastInboundIPv6 = 0; _lastInboundIPv6 = 0;
if (_hmac != null)
_hmac.clearCache();
} }
/** /**
@@ -3707,22 +3702,6 @@ public class UDPTransport extends TransportImpl implements TimedWeightedPriority
// _log.debug("UDP transport returning " + skews.size() + " peer clock skews."); // _log.debug("UDP transport returning " + skews.size() + " peer clock skews.");
return skews; return skews;
} }
/**
* @return a new DHSessionKeyBuilder, or null if SSU1 disabled
* @since 0.9
*/
DHSessionKeyBuilder getDHBuilder() {
return _enableSSU1 ? _dhFactory.getBuilder() : null;
}
/**
* @return the factory, or null if SSU1 disabled
* @since 0.9.2
*/
DHSessionKeyBuilder.Factory getDHFactory() {
return _dhFactory;
}
/** /**
* @return null if not configured for SSU2 * @return null if not configured for SSU2
@@ -3732,14 +3711,6 @@ public class UDPTransport extends TransportImpl implements TimedWeightedPriority
return _xdhFactory; return _xdhFactory;
} }
/**
* @return the SSU HMAC, or null if SSU1 disabled
* @since 0.9.42
*/
HMACGenerator getHMAC() {
return _hmac;
}
/** /**
* @return null if not configured for SSU2 * @return null if not configured for SSU2
* @since 0.9.54 * @since 0.9.54

View File

@@ -1,124 +0,0 @@
package net.i2p.router.transport.udp;
/*
* Copyright (c) 2003, TheCrypto
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* - Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
* - Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* - Neither the name of the TheCrypto may be used to endorse or promote
* products derived from this software without specific prior written
* permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
import java.util.Properties;
import net.i2p.I2PAppContext;
import net.i2p.data.DataHelper;
import net.i2p.data.Hash;
import net.i2p.data.SessionKey;
/**
* Warning, misnamed, this tests the SSU HMAC,
* not net.i2p.crypto.HMAC256Generator
*/
public class HMACSHA256Bench {
public static void main(String args[]) {
runTest(new I2PAppContext());
System.out.println("Running as MD5");
Properties props = new Properties();
//props.setProperty("i2p.fakeHMAC", "true");
props.setProperty("i2p.HMACMD5", "true");
runTest(new I2PAppContext(props));
}
private static void runTest(I2PAppContext ctx) {
SessionKey key = ctx.keyGenerator().generateSessionKey();
byte[] output = new byte[32];
SSUHMACGenerator hmac = new SSUHMACGenerator();
hmac.calculate(key, "qwerty".getBytes(), 0, 6, output, 0);
int times = 100000;
long shorttime = 0;
long medtime = 0;
long longtime = 0;
long minShort = 0;
long maxShort = 0;
long minMed = 0;
long maxMed = 0;
long minLong = 0;
long maxLong = 0;
long shorttime1 = 0;
long medtime1 = 0;
long longtime1 = 0;
long minShort1 = 0;
long maxShort1 = 0;
long minMed1 = 0;
long maxMed1 = 0;
long minLong1 = 0;
long maxLong1 = 0;
byte[] smess = "abc".getBytes();
StringBuilder buf = new StringBuilder();
for (int x = 0; x < 2*1024; x++) {
buf.append("a");
}
byte[] mmess = DataHelper.getASCII(buf.toString()); // new String("abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq").getBytes();
buf = new StringBuilder();
for (int x = 0; x < 10000; x++) {
buf.append("a");
}
byte[] lmess = DataHelper.getASCII(buf.toString());
// warm up the engines
hmac.calculate(key, smess, 0, smess.length, output, 0);
hmac.calculate(key, mmess, 0, mmess.length, output, 0);
hmac.calculate(key, lmess, 0, lmess.length, output, 0);
long before = System.currentTimeMillis();
for (int x = 0; x < times; x++)
hmac.calculate(key, smess, 0, smess.length, output, 0);
long after = System.currentTimeMillis();
display(times, before, after, smess.length, "3 byte");
before = System.currentTimeMillis();
for (int x = 0; x < times; x++)
hmac.calculate(key, mmess, 0, mmess.length, output, 0);
after = System.currentTimeMillis();
display(times, before, after, mmess.length, "2KB");
before = System.currentTimeMillis();
for (int x = 0; x < times; x++)
hmac.calculate(key, lmess, 0, lmess.length, output, 0);
after = System.currentTimeMillis();
display(times, before, after, lmess.length, "10KB");
}
private static void display(int times, long before, long after, int len, String name) {
double rate = times/(((double)after-(double)before)/1000.0d);
double kbps = (len/1024.0d)*times/(((double)after-(double)before)/1000.0d);
System.out.println(name + " HMAC pulled " + kbps + "KBps or " + rate + " calcs per second");
}
}

View File

@@ -1,40 +0,0 @@
package net.i2p.router.transport.udp;
/*
* free (adj.): unencumbered; not under the control of others
* Written by jrandom in 2003 and released into the public domain
* with no warranty of any kind, either expressed or implied.
* It probably won't make your computer catch on fire, or eat
* your children, but it might. Use at your own risk.
*
*/
import junit.framework.TestCase;
import net.i2p.I2PAppContext;
import net.i2p.data.SessionKey;
/**
* Warning, misnamed, this tests the SSU HMAC,
* not net.i2p.crypto.HMAC256Generator
*/
public class HMACSHA256Test extends TestCase{
private I2PAppContext _context;
protected void setUp() {
_context = I2PAppContext.getGlobalContext();
}
public void testMultiple(){
SSUHMACGenerator hmac = new SSUHMACGenerator();
int size = 1;
for(int i = 0; i < 16; i++){
SessionKey key = _context.keyGenerator().generateSessionKey();
byte[] message = new byte[size];
size*=2;
_context.random().nextBytes(message);
byte[] output = new byte[32];
hmac.calculate(key, message, 0, message.length, output, 0);
}
}
}