use of net.i2p.data.SessionKey in project i2p.i2p by i2p.
the class IntroductionManager method receiveRelayRequest.
/**
* We are Bob and we got this from Alice.
* Send a RelayIntro to Charlie and a RelayResponse to Alice.
* We should already have a session with Charlie, but not necessarily with Alice.
*/
void receiveRelayRequest(RemoteHostId alice, UDPPacketReader reader) {
if (_context.router().isHidden())
return;
UDPPacketReader.RelayRequestReader rrReader = reader.getRelayRequestReader();
long tag = rrReader.readTag();
int ipSize = rrReader.readIPSize();
int port = rrReader.readPort();
// ip/port inside message should be 0:0, as it's unimplemented on send -
// see PacketBuilder.buildRelayRequest()
// and we don't read it here.
// FIXME implement for getting Alice's IPv4 in RelayRequest sent over IPv6?
// or is that just too easy to spoof?
byte[] aliceIP = alice.getIP();
int alicePort = alice.getPort();
if (!isValid(alice.getIP(), alice.getPort())) {
if (_log.shouldWarn())
_log.warn("Bad relay req from " + alice + " for " + Addresses.toString(aliceIP, alicePort));
_context.statManager().addRateData("udp.relayBadIP", 1);
return;
}
// TODO relay request over IPv6
if (ipSize != 0) {
byte[] ip = new byte[ipSize];
rrReader.readIP(ip, 0);
if (!Arrays.equals(aliceIP, ip)) {
if (_log.shouldWarn())
_log.warn("Bad relay req from " + alice + " for " + Addresses.toString(ip, port));
_context.statManager().addRateData("udp.relayBadIP", 1);
return;
}
}
// TODO relay request over IPv6
if (port != 0 && port != alicePort) {
if (_log.shouldWarn())
_log.warn("Bad relay req from " + alice + " for " + Addresses.toString(aliceIP, port));
_context.statManager().addRateData("udp.relayBadIP", 1);
return;
}
PeerState charlie = get(tag);
if (charlie == null) {
if (_log.shouldLog(Log.INFO))
_log.info("Receive relay request from " + alice + " with unknown tag");
_context.statManager().addRateData("udp.receiveRelayRequestBadTag", 1);
return;
}
if (_log.shouldLog(Log.INFO))
_log.info("Receive relay request from " + alice + " for tag " + tag + " and relaying with " + charlie);
// TODO throttle based on alice identity and/or intro tag?
_context.statManager().addRateData("udp.receiveRelayRequest", 1);
// send that peer an introduction for alice
_transport.send(_builder.buildRelayIntro(alice, charlie, reader.getRelayRequestReader()));
// send alice back charlie's info
// 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));
}
use of net.i2p.data.SessionKey in project i2p.i2p by i2p.
the class TestJob method sendTest.
private void sendTest(I2NPMessage m) {
// garlic route that DeliveryStatusMessage to ourselves so the endpoints and gateways
// can't tell its a test. to simplify this, we encrypt it with a random key and tag,
// remembering that key+tag so that we can decrypt it later. this means we can do the
// garlic encryption without any ElGamal (yay)
PayloadGarlicConfig payload = new PayloadGarlicConfig();
payload.setCertificate(Certificate.NULL_CERT);
payload.setId(getContext().random().nextLong(I2NPMessage.MAX_ID_VALUE));
payload.setPayload(m);
payload.setRecipient(getContext().router().getRouterInfo());
payload.setDeliveryInstructions(DeliveryInstructions.LOCAL);
payload.setExpiration(m.getMessageExpiration());
SessionKey encryptKey = getContext().keyGenerator().generateSessionKey();
SessionTag encryptTag = new SessionTag(true);
_encryptTag = encryptTag;
SessionKey sentKey = new SessionKey();
Set<SessionTag> sentTags = null;
GarlicMessage msg = GarlicMessageBuilder.buildMessage(getContext(), payload, sentKey, sentTags, getContext().keyManager().getPublicKey(), encryptKey, encryptTag);
if (msg == null) {
// overloaded / unknown peers / etc
scheduleRetest();
return;
}
Set<SessionTag> encryptTags = new RemovableSingletonSet<SessionTag>(encryptTag);
// Register the single tag with the appropriate SKM
if (_cfg.isInbound() && !_pool.getSettings().isExploratory()) {
SessionKeyManager skm = getContext().clientManager().getClientSessionKeyManager(_pool.getSettings().getDestination());
if (skm != null)
skm.tagsReceived(encryptKey, encryptTags);
} else {
getContext().sessionKeyManager().tagsReceived(encryptKey, encryptTags);
}
if (_log.shouldLog(Log.DEBUG))
_log.debug("Sending garlic test of " + _outTunnel + " / " + _replyTunnel);
getContext().tunnelDispatcher().dispatchOutbound(msg, _outTunnel.getSendTunnelId(0), _replyTunnel.getReceiveTunnelId(0), _replyTunnel.getPeer(0));
}
use of net.i2p.data.SessionKey in project i2p.i2p by i2p.
the class PacketBuilder method buildRelayRequest.
/**
* build intro packets for each of the published introducers
* @return empty list on failure
*/
public List<UDPPacket> buildRelayRequest(UDPTransport transport, OutboundEstablishState state, SessionKey ourIntroKey) {
UDPAddress addr = state.getRemoteAddress();
int count = addr.getIntroducerCount();
List<UDPPacket> rv = new ArrayList<UDPPacket>(count);
long cutoff = _context.clock().now() + 5 * 60 * 1000L;
for (int i = 0; i < count; i++) {
InetAddress iaddr = addr.getIntroducerHost(i);
int iport = addr.getIntroducerPort(i);
byte[] ikey = addr.getIntroducerKey(i);
long tag = addr.getIntroducerTag(i);
long exp = addr.getIntroducerExpiration(i);
// let's not use an introducer on a privileged port, sounds like trouble
if (ikey == null || !TransportUtil.isValidPort(iport) || iaddr == null || tag <= 0 || // must be IPv4 for now as we don't send Alice IP/port, see below
iaddr.getAddress().length != 4 || (!_transport.isValid(iaddr.getAddress())) || (exp > 0 && exp < cutoff) || (Arrays.equals(iaddr.getAddress(), _transport.getExternalIP()) && !_transport.allowLocal())) {
if (_log.shouldLog(Log.WARN))
_log.warn("Cannot build a relay request to " + state.getRemoteIdentity().calculateHash() + ", as their UDP address is invalid: addr=" + addr + " index=" + i);
// TODO implement some sort of introducer banlist
continue;
}
// 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 = null;
if (ikey.length == Hash.HASH_LENGTH) {
bobState = transport.getPeerState(new Hash(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;
}
use of net.i2p.data.SessionKey in project i2p.i2p by i2p.
the class GarlicMessageBuilder method needsTags.
/**
* @param local non-null; do not use this method for the router's SessionKeyManager
* @param minTagOverride 0 for no override, > 0 to override SKM's settings
*/
static boolean needsTags(RouterContext ctx, PublicKey key, Hash local, int minTagOverride) {
SessionKeyManager skm = ctx.clientManager().getClientSessionKeyManager(local);
if (skm == null)
return true;
SessionKey curKey = skm.getCurrentKey(key);
if (curKey == null)
return true;
if (minTagOverride > 0)
return skm.shouldSendTags(key, curKey, minTagOverride);
return skm.shouldSendTags(key, curKey);
}
use of net.i2p.data.SessionKey in project i2p.i2p by i2p.
the class GarlicMessageBuilder method buildMessage.
/**
* called by netdb and above
*
* @param ctx scope
* @param config how/what to wrap
* @param wrappedKey output parameter that will be filled with the sessionKey used
* @param wrappedTags Output parameter that will be filled with the sessionTags used.
* If non-empty on return you must call skm.tagsDelivered() when sent
* and then call skm.tagsAcked() or skm.failTags() later.
* @param numTagsToDeliver only if the estimated available tags are below the threshold.
* Set to zero to disable tag delivery. You must set to zero if you are not
* equipped to confirm delivery and call skm.tagsAcked() or failTags() later.
* If this is always 0, it forces ElGamal every time.
* @param lowTagsThreshold the threshold
* @param skm non-null
* @throws IllegalArgumentException on error
*/
public static GarlicMessage buildMessage(RouterContext ctx, GarlicConfig config, SessionKey wrappedKey, Set<SessionTag> wrappedTags, int numTagsToDeliver, int lowTagsThreshold, SessionKeyManager skm) {
Log log = ctx.logManager().getLog(GarlicMessageBuilder.class);
PublicKey key = config.getRecipientPublicKey();
if (key == null) {
if (config.getRecipient() == null) {
throw new IllegalArgumentException("Null recipient specified");
} else if (config.getRecipient().getIdentity() == null) {
throw new IllegalArgumentException("Null recipient.identity specified");
} else if (config.getRecipient().getIdentity().getPublicKey() == null) {
throw new IllegalArgumentException("Null recipient.identity.publicKey specified");
} else
key = config.getRecipient().getIdentity().getPublicKey();
}
if (log.shouldLog(Log.INFO))
log.info("Encrypted with public key to expire on " + new Date(config.getExpiration()));
SessionKey curKey = skm.getCurrentOrNewKey(key);
SessionTag curTag = null;
curTag = skm.consumeNextAvailableTag(key, curKey);
if (log.shouldLog(Log.DEBUG)) {
int availTags = skm.getAvailableTags(key, curKey);
log.debug("Available tags for encryption: " + availTags + " low threshold: " + lowTagsThreshold);
}
if (numTagsToDeliver > 0 && skm.shouldSendTags(key, curKey, lowTagsThreshold)) {
for (int i = 0; i < numTagsToDeliver; i++) wrappedTags.add(new SessionTag(true));
if (log.shouldLog(Log.INFO))
log.info("Too few tags available so we're including " + numTagsToDeliver);
}
wrappedKey.setData(curKey.getData());
return buildMessage(ctx, config, wrappedKey, wrappedTags, key, curKey, curTag);
}
Aggregations