forked from I2P_Developers/i2p.i2p
* SSU:
- Use session key for relay request/response if available (ticket #1206) - Remove packetAuthTime stats - Misc. cleanups and logging
This commit is contained in:
@ -3,6 +3,9 @@
|
||||
- Replace BC MD5 with JVM version, refactor I2PHMAC to use
|
||||
MessageDigest instead of BC Digest (ticket #1189)
|
||||
- Use JVM HmacSHA256 instead of I2PHMAC for Syndie since it is standard
|
||||
* SSU:
|
||||
- Use session key for relay request/response if available (ticket #1206)
|
||||
- Remove packetAuthTime stats
|
||||
|
||||
2014-02-14 zzz
|
||||
* I2CP:
|
||||
|
@ -18,7 +18,7 @@ public class RouterVersion {
|
||||
/** deprecated */
|
||||
public final static String ID = "Monotone";
|
||||
public final static String VERSION = CoreVersion.VERSION;
|
||||
public final static long BUILD = 5;
|
||||
public final static long BUILD = 6;
|
||||
|
||||
/** for example "-test" */
|
||||
public final static String EXTRA = "";
|
||||
|
@ -411,13 +411,34 @@ class IntroductionManager {
|
||||
// TODO throttle based on alice identity and/or intro tag?
|
||||
|
||||
_context.statManager().addRateData("udp.receiveRelayRequest", 1, 0);
|
||||
byte key[] = new byte[SessionKey.KEYSIZE_BYTES];
|
||||
reader.getRelayRequestReader().readAliceIntroKey(key, 0);
|
||||
SessionKey aliceIntroKey = new SessionKey(key);
|
||||
|
||||
// send that peer an introduction for alice
|
||||
_transport.send(_builder.buildRelayIntro(alice, charlie, reader.getRelayRequestReader()));
|
||||
|
||||
// send alice back charlie's info
|
||||
_transport.send(_builder.buildRelayResponse(alice, charlie, reader.getRelayRequestReader().readNonce(), aliceIntroKey));
|
||||
// lookup session so we can use session key if available
|
||||
SessionKey cipherKey = null;
|
||||
SessionKey macKey = null;
|
||||
PeerState aliceState = _transport.getPeerState(alice);
|
||||
if (aliceState != null) {
|
||||
// established session (since 0.9.12)
|
||||
cipherKey = aliceState.getCurrentCipherKey();
|
||||
macKey = aliceState.getCurrentMACKey();
|
||||
}
|
||||
if (cipherKey == null || macKey == null) {
|
||||
// no session, use intro key (was only way before 0.9.12)
|
||||
byte key[] = new byte[SessionKey.KEYSIZE_BYTES];
|
||||
reader.getRelayRequestReader().readAliceIntroKey(key, 0);
|
||||
cipherKey = new SessionKey(key);
|
||||
macKey = cipherKey;
|
||||
if (_log.shouldLog(Log.INFO))
|
||||
_log.info("Sending relay response (w/ intro key) to " + alice);
|
||||
} else {
|
||||
if (_log.shouldLog(Log.INFO))
|
||||
_log.info("Sending relay response (in-session) to " + alice);
|
||||
}
|
||||
_transport.send(_builder.buildRelayResponse(alice, charlie, reader.getRelayRequestReader().readNonce(),
|
||||
cipherKey, macKey));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -96,6 +96,7 @@ class OutboundEstablishState {
|
||||
/**
|
||||
* @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 introKey Bob's introduction key, as published in the netdb
|
||||
* @param addr non-null
|
||||
*/
|
||||
public OutboundEstablishState(RouterContext ctx, RemoteHostId claimedAddress,
|
||||
@ -163,6 +164,10 @@ class OutboundEstablishState {
|
||||
}
|
||||
|
||||
public RouterIdentity getRemoteIdentity() { return _remotePeer; }
|
||||
|
||||
/**
|
||||
* Bob's introduction key, as published in the netdb
|
||||
*/
|
||||
public SessionKey getIntroKey() { return _introKey; }
|
||||
|
||||
/** caller must synch - only call once */
|
||||
@ -327,8 +332,8 @@ class OutboundEstablishState {
|
||||
*/
|
||||
private void decryptSignature() {
|
||||
if (_receivedEncryptedSignature == null) throw new NullPointerException("encrypted signature is null! this=" + this.toString());
|
||||
else if (_sessionKey == null) throw new NullPointerException("SessionKey is null!");
|
||||
else if (_receivedIV == null) throw new NullPointerException("IV is null!");
|
||||
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);
|
||||
byte signatureBytes[] = new byte[Signature.SIGNATURE_BYTES];
|
||||
|
@ -957,7 +957,8 @@ class PacketBuilder {
|
||||
*
|
||||
* @return ready to send packet, or null if there was a problem
|
||||
*/
|
||||
public UDPPacket buildPeerTestToAlice(InetAddress aliceIP, int alicePort, SessionKey aliceIntroKey, SessionKey charlieIntroKey, long nonce) {
|
||||
public UDPPacket buildPeerTestToAlice(InetAddress aliceIP, int alicePort,
|
||||
SessionKey aliceIntroKey, SessionKey charlieIntroKey, long nonce) {
|
||||
UDPPacket packet = buildPacketHeader(PEER_TEST_FLAG_BYTE);
|
||||
DatagramPacket pkt = packet.getPacket();
|
||||
byte data[] = pkt.getData();
|
||||
@ -1031,7 +1032,9 @@ class PacketBuilder {
|
||||
*
|
||||
* @return ready to send packet, or null if there was a problem
|
||||
*/
|
||||
public UDPPacket buildPeerTestToBob(InetAddress bobIP, int bobPort, InetAddress aliceIP, int alicePort, SessionKey aliceIntroKey, long nonce, SessionKey bobCipherKey, SessionKey bobMACKey) {
|
||||
public UDPPacket buildPeerTestToBob(InetAddress bobIP, int bobPort, InetAddress aliceIP, int alicePort,
|
||||
SessionKey aliceIntroKey, long nonce,
|
||||
SessionKey bobCipherKey, SessionKey bobMACKey) {
|
||||
UDPPacket packet = buildPacketHeader(PEER_TEST_FLAG_BYTE);
|
||||
DatagramPacket pkt = packet.getPacket();
|
||||
byte data[] = pkt.getData();
|
||||
@ -1100,7 +1103,34 @@ class PacketBuilder {
|
||||
// TODO implement some sort of introducer banlist
|
||||
continue;
|
||||
}
|
||||
rv.add(buildRelayRequest(iaddr, iport, ikey, tag, ourIntroKey, state.getIntroNonce(), true));
|
||||
|
||||
// lookup session so we can use session key if available
|
||||
SessionKey cipherKey = null;
|
||||
SessionKey macKey = null;
|
||||
// first look up by ikey, it is equal to router hash for now
|
||||
PeerState bobState = transport.getPeerState(Hash.create(ikey));
|
||||
if (bobState == null) {
|
||||
RemoteHostId rhid = new RemoteHostId(iaddr.getAddress(), iport);
|
||||
bobState = transport.getPeerState(rhid);
|
||||
}
|
||||
if (bobState != null) {
|
||||
// established session (since 0.9.12)
|
||||
cipherKey = bobState.getCurrentCipherKey();
|
||||
macKey = bobState.getCurrentMACKey();
|
||||
}
|
||||
if (cipherKey == null || macKey == null) {
|
||||
// no session, use intro key (was only way before 0.9.12)
|
||||
cipherKey = new SessionKey(ikey);
|
||||
macKey = cipherKey;
|
||||
if (_log.shouldLog(Log.INFO))
|
||||
_log.info("Sending relay request (w/ intro key) to " + iaddr + ":" + iport);
|
||||
} else {
|
||||
if (_log.shouldLog(Log.INFO))
|
||||
_log.info("Sending relay request (in-session) to " + iaddr + ":" + iport);
|
||||
}
|
||||
|
||||
rv.add(buildRelayRequest(iaddr, iport, cipherKey, macKey, tag,
|
||||
ourIntroKey, state.getIntroNonce()));
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
@ -1110,8 +1140,9 @@ class PacketBuilder {
|
||||
* send a RelayRequest over IPv6
|
||||
*
|
||||
*/
|
||||
private UDPPacket buildRelayRequest(InetAddress introHost, int introPort, byte introKey[],
|
||||
long introTag, SessionKey ourIntroKey, long introNonce, boolean encrypt) {
|
||||
private UDPPacket buildRelayRequest(InetAddress introHost, int introPort,
|
||||
SessionKey cipherKey, SessionKey macKey,
|
||||
long introTag, SessionKey ourIntroKey, long introNonce) {
|
||||
UDPPacket packet = buildPacketHeader(PEER_RELAY_REQUEST_FLAG_BYTE);
|
||||
DatagramPacket pkt = packet.getPacket();
|
||||
byte data[] = pkt.getData();
|
||||
@ -1121,9 +1152,6 @@ class PacketBuilder {
|
||||
byte ourIP[] = getOurExplicitIP();
|
||||
int ourPort = getOurExplicitPort();
|
||||
|
||||
if (_log.shouldLog(Log.INFO))
|
||||
_log.info("Sending intro relay request to " + introHost + ":" + introPort); // + " regarding " + state.getRemoteIdentity().calculateHash().toBase64());
|
||||
|
||||
// now for the body
|
||||
DataHelper.toLong(data, off, 4, introTag);
|
||||
off += 4;
|
||||
@ -1160,8 +1188,7 @@ class PacketBuilder {
|
||||
off = pad1(data, off);
|
||||
off = pad2(data, off);
|
||||
pkt.setLength(off);
|
||||
if (encrypt)
|
||||
authenticate(packet, new SessionKey(introKey), new SessionKey(introKey));
|
||||
authenticate(packet, cipherKey, macKey);
|
||||
setTo(packet, introHost, introPort);
|
||||
packet.setMessageType(TYPE_RREQ);
|
||||
return packet;
|
||||
@ -1214,7 +1241,8 @@ class PacketBuilder {
|
||||
*/
|
||||
private static final byte PEER_RELAY_RESPONSE_FLAG_BYTE = (UDPPacket.PAYLOAD_TYPE_RELAY_RESPONSE << 4);
|
||||
|
||||
UDPPacket buildRelayResponse(RemoteHostId alice, PeerState charlie, long nonce, SessionKey aliceIntroKey) {
|
||||
UDPPacket buildRelayResponse(RemoteHostId alice, PeerState charlie, long nonce,
|
||||
SessionKey cipherKey, SessionKey macKey) {
|
||||
InetAddress aliceAddr = null;
|
||||
try {
|
||||
aliceAddr = InetAddress.getByAddress(alice.getIP());
|
||||
@ -1228,7 +1256,7 @@ class PacketBuilder {
|
||||
int off = HEADER_SIZE;
|
||||
|
||||
if (_log.shouldLog(Log.INFO))
|
||||
_log.info("Sending relay response to " + alice + " for " + charlie + " with alice's intro key " + aliceIntroKey);
|
||||
_log.info("Sending relay response to " + alice + " for " + charlie + " with key " + cipherKey);
|
||||
|
||||
// now for the body
|
||||
byte charlieIP[] = charlie.getRemoteIP();
|
||||
@ -1255,7 +1283,7 @@ class PacketBuilder {
|
||||
off = pad1(data, off);
|
||||
off = pad2(data, off);
|
||||
pkt.setLength(off);
|
||||
authenticate(packet, aliceIntroKey, aliceIntroKey);
|
||||
authenticate(packet, cipherKey, macKey);
|
||||
setTo(packet, aliceAddr, alice.getPort());
|
||||
packet.setMessageType(TYPE_RESP);
|
||||
return packet;
|
||||
@ -1416,7 +1444,7 @@ class PacketBuilder {
|
||||
* @param iv IV to deliver
|
||||
*/
|
||||
private void authenticate(UDPPacket packet, SessionKey cipherKey, SessionKey macKey, byte[] iv) {
|
||||
long before = System.currentTimeMillis();
|
||||
//long before = System.currentTimeMillis();
|
||||
DatagramPacket pkt = packet.getPacket();
|
||||
int off = pkt.getOffset();
|
||||
int hmacOff = off;
|
||||
@ -1454,9 +1482,10 @@ class PacketBuilder {
|
||||
System.arraycopy(ba, 0, data, hmacOff, UDPPacket.MAC_SIZE);
|
||||
SimpleByteCache.release(ba);
|
||||
System.arraycopy(iv, 0, data, hmacOff + UDPPacket.MAC_SIZE, UDPPacket.IV_SIZE);
|
||||
long timeToAuth = System.currentTimeMillis() - before;
|
||||
_context.statManager().addRateData("udp.packetAuthTime", timeToAuth, timeToAuth);
|
||||
if (timeToAuth > 100)
|
||||
_context.statManager().addRateData("udp.packetAuthTimeSlow", timeToAuth, timeToAuth);
|
||||
// avg. 0.06 ms on a 2005-era PC
|
||||
//long timeToAuth = System.currentTimeMillis() - before;
|
||||
//_context.statManager().addRateData("udp.packetAuthTime", timeToAuth, timeToAuth);
|
||||
//if (timeToAuth > 100)
|
||||
// _context.statManager().addRateData("udp.packetAuthTimeSlow", timeToAuth, timeToAuth);
|
||||
}
|
||||
}
|
||||
|
@ -266,8 +266,9 @@ class PeerTestManager {
|
||||
if (!expired()) {
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
_log.debug("Sending test to Bob: " + test);
|
||||
_transport.send(_packetBuilder.buildPeerTestFromAlice(test.getBobIP(), test.getBobPort(), test.getBobCipherKey(), test.getBobMACKey(), //_bobIntroKey,
|
||||
test.getNonce(), _transport.getIntroKey()));
|
||||
_transport.send(_packetBuilder.buildPeerTestFromAlice(test.getBobIP(), test.getBobPort(),
|
||||
test.getBobCipherKey(), test.getBobMACKey(), //_bobIntroKey,
|
||||
test.getNonce(), _transport.getIntroKey()));
|
||||
} else {
|
||||
_currentTest = null;
|
||||
}
|
||||
@ -279,8 +280,9 @@ class PeerTestManager {
|
||||
if (!expired()) {
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
_log.debug("Sending test to Charlie: " + test);
|
||||
_transport.send(_packetBuilder.buildPeerTestFromAlice(test.getCharlieIP(), test.getCharliePort(), test.getCharlieIntroKey(),
|
||||
test.getNonce(), _transport.getIntroKey()));
|
||||
_transport.send(_packetBuilder.buildPeerTestFromAlice(test.getCharlieIP(), test.getCharliePort(),
|
||||
test.getCharlieIntroKey(),
|
||||
test.getNonce(), _transport.getIntroKey()));
|
||||
} else {
|
||||
_currentTest = null;
|
||||
}
|
||||
@ -695,10 +697,13 @@ class PeerTestManager {
|
||||
_context.simpleScheduler().addEvent(new RemoveTest(nonce), MAX_CHARLIE_LIFETIME);
|
||||
}
|
||||
|
||||
UDPPacket packet = _packetBuilder.buildPeerTestToBob(bobIP, from.getPort(), aliceIP, alicePort, aliceIntroKey, nonce, state.getBobCipherKey(), state.getBobMACKey());
|
||||
UDPPacket packet = _packetBuilder.buildPeerTestToBob(bobIP, from.getPort(), aliceIP, alicePort,
|
||||
aliceIntroKey, nonce,
|
||||
state.getBobCipherKey(), state.getBobMACKey());
|
||||
_transport.send(packet);
|
||||
|
||||
packet = _packetBuilder.buildPeerTestToAlice(aliceIP, alicePort, aliceIntroKey, _transport.getIntroKey(), nonce);
|
||||
packet = _packetBuilder.buildPeerTestToAlice(aliceIP, alicePort, aliceIntroKey,
|
||||
_transport.getIntroKey(), nonce);
|
||||
_transport.send(packet);
|
||||
} catch (UnknownHostException uhe) {
|
||||
if (_log.shouldLog(Log.WARN))
|
||||
|
@ -7,8 +7,10 @@ import java.util.Queue;
|
||||
import java.util.concurrent.LinkedBlockingQueue;
|
||||
|
||||
import net.i2p.I2PAppContext;
|
||||
import net.i2p.data.Base64;
|
||||
import net.i2p.data.DataHelper;
|
||||
import net.i2p.data.SessionKey;
|
||||
import net.i2p.router.RouterContext;
|
||||
import net.i2p.router.util.CDQEntry;
|
||||
import net.i2p.util.Addresses;
|
||||
import net.i2p.util.Log;
|
||||
@ -206,24 +208,32 @@ class UDPPacket implements CDQEntry {
|
||||
off += 2;
|
||||
|
||||
eq = _context.hmac().verify(macKey, _validateBuf, 0, off, _data, _packet.getOffset(), MAC_SIZE);
|
||||
/*
|
||||
Hash hmac = _context.hmac().calculate(macKey, buf.getData(), 0, off);
|
||||
|
||||
if (_log.shouldLog(Log.DEBUG)) {
|
||||
StringBuilder str = new StringBuilder(128);
|
||||
str.append(_packet.getLength()).append(" byte packet received, payload length ");
|
||||
str.append(payloadLength);
|
||||
str.append("\nIV: ").append(Base64.encode(buf.getData(), payloadLength, IV_SIZE));
|
||||
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(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());
|
||||
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];
|
||||
_context.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, ((RouterContext)_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());
|
||||
}
|
||||
}
|
||||
eq = DataHelper.eq(hmac.getData(), 0, _data, _packet.getOffset(), MAC_SIZE);
|
||||
*/
|
||||
} else {
|
||||
//if (_log.shouldLog(Log.WARN))
|
||||
// _log.warn("Payload length is " + payloadLength);
|
||||
|
@ -51,7 +51,7 @@ class UDPPacketReader {
|
||||
initialize(packet.getPacket().getData(), off, len);
|
||||
}
|
||||
|
||||
public void initialize(byte message[], int payloadOffset, int payloadLength) {
|
||||
private void initialize(byte message[], int payloadOffset, int payloadLength) {
|
||||
_message = message;
|
||||
_payloadBeginOffset = payloadOffset;
|
||||
_payloadLength = payloadLength;
|
||||
@ -106,7 +106,8 @@ class UDPPacketReader {
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
switch (readPayloadType()) {
|
||||
int type = readPayloadType();
|
||||
switch (type) {
|
||||
case UDPPacket.PAYLOAD_TYPE_DATA:
|
||||
return _dataReader.toString();
|
||||
case UDPPacket.PAYLOAD_TYPE_SESSION_CONFIRMED:
|
||||
@ -126,7 +127,7 @@ class UDPPacketReader {
|
||||
case UDPPacket.PAYLOAD_TYPE_SESSION_DESTROY:
|
||||
return "Session destroyed packet";
|
||||
default:
|
||||
return "Other packet type...";
|
||||
return "Unknown packet type " + type;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -261,8 +261,8 @@ public class UDPTransport extends TransportImpl implements TimedWeightedPriority
|
||||
_context.statManager().createRateStat("udp.dropPeerDroplist", "How many peers currently have their packets dropped outright when a new peer is added to the list?", "udp", RATES);
|
||||
_context.statManager().createRateStat("udp.dropPeerConsecutiveFailures", "How many consecutive failed sends to a peer did we attempt before giving up and reestablishing a new session (lifetime is inactivity perood)", "udp", RATES);
|
||||
// following are for PacketBuider
|
||||
_context.statManager().createRateStat("udp.packetAuthTime", "How long it takes to encrypt and MAC a packet for sending", "udp", RATES);
|
||||
_context.statManager().createRateStat("udp.packetAuthTimeSlow", "How long it takes to encrypt and MAC a packet for sending (when its slow)", "udp", RATES);
|
||||
//_context.statManager().createRateStat("udp.packetAuthTime", "How long it takes to encrypt and MAC a packet for sending", "udp", RATES);
|
||||
//_context.statManager().createRateStat("udp.packetAuthTimeSlow", "How long it takes to encrypt and MAC a packet for sending (when its slow)", "udp", RATES);
|
||||
|
||||
_context.simpleScheduler().addPeriodicEvent(new PingIntroducers(), MIN_EXPIRE_TIMEOUT * 3 / 4);
|
||||
}
|
||||
|
Reference in New Issue
Block a user