package net.i2p.router.tunnel;
import net.i2p.data.Hash;
import net.i2p.router.RouterContext;
import net.i2p.util.Log;
import net.i2p.util.SimpleByteCache;
/**
* Receive the inbound tunnel message, removing all of the layers
* added by earlier hops to recover the preprocessed data sent
* by the gateway. This delegates the crypto to the
* OutboundGatewayProcessor, since the tunnel creator does the
* same thing in both instances.
*
*/
class InboundEndpointProcessor {
private final RouterContext _context;
private final Log _log;
private final TunnelCreatorConfig _config;
private final IVValidator _validator;
//static final boolean USE_ENCRYPTION = HopProcessor.USE_ENCRYPTION;
/**
* @deprecated used only by unit tests
*/
@Deprecated
InboundEndpointProcessor(RouterContext ctx, TunnelCreatorConfig cfg) {
this(ctx, cfg, DummyValidator.getInstance());
}
public InboundEndpointProcessor(RouterContext ctx, TunnelCreatorConfig cfg, IVValidator validator) {
_context = ctx;
_log = ctx.logManager().getLog(InboundEndpointProcessor.class);
_config = cfg;
_validator = validator;
}
public Hash getDestination() { return _config.getDestination(); }
public TunnelCreatorConfig getConfig() { return _config; }
/**
* Undo all of the encryption done by the peers in the tunnel, recovering the
* preprocessed data sent by the gateway.
*
* @return true if the data was recovered (and written in place to orig), false
* if it was a duplicate or from the wrong peer.
*/
public boolean retrievePreprocessedData(byte orig[], int offset, int length, Hash prev) {
Hash last = _config.getPeer(_config.getLength()-2);
if (!last.equals(prev)) {
// shouldn't happen now that we have good dup ID detection in BuildHandler
if (_log.shouldLog(Log.WARN))
_log.warn("Attempted IBEP injection from " + prev
+ ", expected " + last);
return false;
}
byte iv[] = SimpleByteCache.acquire(HopProcessor.IV_LENGTH);
System.arraycopy(orig, offset, iv, 0, iv.length);
//if (_config.getLength() > 1)
// _log.debug("IV at inbound endpoint before decrypt: " + Base64.encode(iv));
boolean ok = _validator.receiveIV(iv, 0, orig, offset + HopProcessor.IV_LENGTH);
if (!ok) {
if (_log.shouldLog(Log.WARN))
_log.warn("Invalid IV, dropping at IBEP " + _config);
SimpleByteCache.release(iv);
return false;
}
// inbound endpoints and outbound gateways have to undo the crypto in the same way
//if (USE_ENCRYPTION)
decrypt(_context, _config, iv, orig, offset, length);
SimpleByteCache.release(iv);
if (_config.getLength() > 0) {
int rtt = 0; // dunno... may not be related to an rtt
if (_log.shouldLog(Log.DEBUG))
_log.debug("Received a " + length + "byte message through tunnel " + _config);
for (int i = 0; i < _config.getLength(); i++)
_context.profileManager().tunnelDataPushed(_config.getPeer(i), rtt, length);
_config.incrementVerifiedBytesTransferred(length);
}
return true;
}
/**
* Iteratively undo the crypto that the various layers in the tunnel added.
*/
private void decrypt(RouterContext ctx, TunnelCreatorConfig cfg, byte iv[], byte orig[], int offset, int length) {
//Log log = ctx.logManager().getLog(OutboundGatewayProcessor.class);
byte cur[] = SimpleByteCache.acquire(HopProcessor.IV_LENGTH);
for (int i = cfg.getLength()-2; i >= 0; i--) { // dont include the endpoint, since that is the creator
OutboundGatewayProcessor.decrypt(ctx, iv, orig, offset, length, cur, cfg.getConfig(i));
//if (log.shouldLog(Log.DEBUG)) {
//log.debug("IV at hop " + i + ": " + Base64.encode(orig, offset, HopProcessor.IV_LENGTH));
//log.debug("hop " + i + ": " + Base64.encode(orig, offset + HopProcessor.IV_LENGTH, length - HopProcessor.IV_LENGTH));
//}
}
SimpleByteCache.release(cur);
}
}