Tunnels: Use context AES for hop processing

and related cleanups
This commit is contained in:
zzz
2019-09-03 12:42:10 +00:00
parent 566221b732
commit b119d0be43
6 changed files with 92 additions and 101 deletions

View File

@ -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 = 1;
public final static long BUILD = 2;
/** for example "-test" */
public final static String EXTRA = "";

View File

@ -1,7 +1,10 @@
package net.i2p.router.tunnel;
import net.i2p.I2PAppContext;
import net.i2p.crypto.AESEngine;
import net.i2p.data.Base64;
import net.i2p.data.Hash;
import net.i2p.data.SessionKey;
import net.i2p.util.Log;
/**
@ -28,7 +31,6 @@ class HopProcessor {
*
* See: http://osdir.com/ml/network.i2p/2005-07/msg00031.html
*/
//static final boolean USE_DOUBLE_IV_ENCRYPTION = true;
static final int IV_LENGTH = 16;
/**
@ -62,7 +64,8 @@ class HopProcessor {
*
* @param orig IV+data of the message
* @param offset index into orig where the IV begins
* @param length how long after the offset does the message go for?
* @param length how long after the offset does the IV+message go for?
* Should always be 1024 bytes.
* @param prev previous hop in the tunnel, or null if we are the gateway
* @return true if the message was updated and valid, false if it was not.
*/
@ -88,35 +91,24 @@ class HopProcessor {
}
//if (_log.shouldLog(Log.DEBUG)) {
//_log.debug("IV received: " + Base64.encode(iv));
//_log.debug("Before:" + Base64.encode(orig, IV_LENGTH, orig.length - IV_LENGTH));
//}
//if (USE_ENCRYPTION) {
//if (USE_DOUBLE_IV_ENCRYPTION)
updateIV(orig, offset);
encrypt(orig, offset, length);
updateIV(orig, offset);
// _log.debug("IV received before decrypt: " + Base64.encode(orig, offset, IV_LENGTH));
// _log.debug("Data before processing:\n" + Base64.encode(orig, IV_LENGTH, orig.length - IV_LENGTH));
//}
SessionKey ivkey = _config.getIVKey();
AESEngine aes = _context.aes();
// double IV encryption
aes.encryptBlock(orig, offset, ivkey, orig, offset);
aes.encrypt(orig, offset + IV_LENGTH, orig, offset + IV_LENGTH, _config.getLayerKey(),
orig, offset, length - IV_LENGTH);
aes.encryptBlock(orig, offset, ivkey, orig, offset);
//if (_log.shouldLog(Log.DEBUG)) {
//_log.debug("Data after processing: " + Base64.encode(orig, IV_LENGTH, orig.length - IV_LENGTH));
//_log.debug("IV sent: " + Base64.encode(orig, 0, IV_LENGTH));
// _log.debug("IV sent: " + Base64.encode(orig, offset, IV_LENGTH));
// _log.debug("Data after processing:\n" + Base64.encode(orig, IV_LENGTH, orig.length - IV_LENGTH));
//}
return true;
}
private final void encrypt(byte data[], int offset, int length) {
for (int off = offset + IV_LENGTH; off < length; off += IV_LENGTH) {
//DataHelper.xor(data, off - IV_LENGTH, data, off, data, off, IV_LENGTH);
for (int j = 0; j < IV_LENGTH; j++) {
data[off + j] ^= data[(off - IV_LENGTH) + j];
}
_context.aes().encryptBlock(data, off, _config.getLayerKey(), data, off);
}
}
private final void updateIV(byte orig[], int offset) {
_context.aes().encryptBlock(orig, offset, _config.getIVKey(), orig, offset);
}
/**
* @since 0.8.12

View File

@ -16,6 +16,8 @@ public interface IVValidator {
* not the IV alone (since the tunnel is encrypted via AES/CBC). Thanks to
* dvorak for pointing out that tagging!
*
* @param iv data will not be modified
* @param iv payload will not be modified
*/
public boolean receiveIV(byte iv[], int ivOffset, byte payload[], int payloadOffset);
}

View File

@ -44,6 +44,10 @@ class InboundEndpointProcessor {
* Undo all of the encryption done by the peers in the tunnel, recovering the
* preprocessed data sent by the gateway.
*
* @param orig original data with an extra 16 byte IV prepended.
* @param offset index into the array where the extra 16 bytes (IV) begins
* @param length how much of orig can we write to (must be a multiple of 16).
* Should always be 1024 bytes.
* @return true if the data was recovered (and written in place to orig), false
* if it was a duplicate or from the wrong peer.
*/
@ -57,29 +61,23 @@ class InboundEndpointProcessor {
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);
boolean ok = _validator.receiveIV(orig, offset, 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);
decrypt(_context, _config, orig, offset, length);
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);
//if (_log.shouldLog(Log.DEBUG))
// _log.debug("Received a " + length + "byte message through tunnel " + _config);
ProfileManager pm = _context.profileManager();
// null for unit tests
if (pm != null) {
@ -95,18 +93,21 @@ class InboundEndpointProcessor {
/**
* Iteratively undo the crypto that the various layers in the tunnel added.
*
* @param orig original data with an extra 16 byte IV prepended.
* @param offset index into the array where the extra 16 bytes (IV) begins
* @param length how much of orig can we write to (must be a multiple of 16).
* Should always be 1024 bytes.
*/
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));
private void decrypt(RouterContext ctx, TunnelCreatorConfig cfg, byte orig[], int offset, int length) {
// dont include the endpoint, since that is the creator
for (int i = cfg.getLength() - 2; i >= 0; i--) {
OutboundGatewayProcessor.decrypt(ctx, orig, offset, length, 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);
}
}

View File

@ -1,7 +1,10 @@
package net.i2p.router.tunnel;
import net.i2p.I2PAppContext;
import net.i2p.crypto.AESEngine;
import net.i2p.data.Base64;
import net.i2p.data.SessionKey;
import static net.i2p.router.tunnel.HopProcessor.IV_LENGTH;
import net.i2p.util.Log;
import net.i2p.util.SimpleByteCache;
@ -13,14 +16,12 @@ import net.i2p.util.SimpleByteCache;
*/
class OutboundGatewayProcessor {
private final I2PAppContext _context;
private final Log _log;
//private final Log _log;
private final TunnelCreatorConfig _config;
//static final boolean USE_ENCRYPTION = HopProcessor.USE_ENCRYPTION;
public OutboundGatewayProcessor(I2PAppContext ctx, TunnelCreatorConfig cfg) {
_context = ctx;
_log = ctx.logManager().getLog(OutboundGatewayProcessor.class);
//_log = ctx.logManager().getLog(OutboundGatewayProcessor.class);
_config = cfg;
}
@ -31,73 +32,59 @@ class OutboundGatewayProcessor {
* @param orig original data with an extra 16 byte IV prepended.
* @param offset index into the array where the extra 16 bytes (IV) begins
* @param length how much of orig can we write to (must be a multiple of 16).
* Should always be 1024 bytes.
*/
public void process(byte orig[], int offset, int length) {
byte iv[] = SimpleByteCache.acquire(HopProcessor.IV_LENGTH);
//_context.random().nextBytes(iv);
//System.arraycopy(iv, 0, orig, offset, HopProcessor.IV_LENGTH);
System.arraycopy(orig, offset, iv, 0, HopProcessor.IV_LENGTH);
if (_log.shouldLog(Log.DEBUG)) {
_log.debug("Orig random IV: " + Base64.encode(iv));
//_log.debug("data: " + Base64.encode(orig, iv.length, length - iv.length));
}
//if (USE_ENCRYPTION)
decrypt(_context, _config, iv, orig, offset, length);
if (_log.shouldLog(Log.DEBUG))
_log.debug("finished processing the preprocessed data");
SimpleByteCache.release(iv);
//if (_log.shouldLog(Log.DEBUG)) {
// _log.debug("Orig random IV: " + Base64.encode(orig, offset, IV_LENGTH));
// _log.debug("data: " + Base64.encode(orig, IV_LENGTH, length - IV_LENGTH));
//}
decrypt(_config, orig, offset, length);
//if (_log.shouldLog(Log.DEBUG))
// _log.debug("finished processing the preprocessed data");
}
/**
* Iteratively undo the crypto that the various layers in the tunnel added. This is used
* by the outbound gateway (preemptively undoing the crypto peers will add).
*
* @param orig original data with an extra 16 byte IV prepended.
* @param offset index into the array where the extra 16 bytes (IV) begins
* @param length how much of orig can we write to (must be a multiple of 16).
* Should always be 1024 bytes.
*/
private void decrypt(I2PAppContext 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()-1; i >= 1; i--) { // dont include hop 0, since that is the creator
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));
}
private void decrypt(TunnelCreatorConfig cfg, byte orig[], int offset, int length) {
// dont include hop 0, since that is the creator
for (int i = cfg.getLength() - 1; i >= 1; i--) {
decrypt(_context, orig, offset, length, cfg.getConfig(i));
//if (_log.shouldDebug()) {
// _log.debug("IV at hop " + i + " before decrypt: " + Base64.encode(orig, offset, IV_LENGTH));
// _log.debug("hop " + i + ": " + Base64.encode(orig, offset + IV_LENGTH, length - IV_LENGTH));
//}
}
SimpleByteCache.release(cur);
}
/**
* Undo the crypto for a single hop. This is used
* by both the outbound gateway (preemptively undoing the crypto peers will add)
* and by the inbound endpoint.
*
* @param orig original data with an extra 16 byte IV prepended.
* @param offset index into the array where the extra 16 bytes (IV) begins
* @param length how much of orig can we write to (must be a multiple of 16).
* Should always be 1024 bytes.
*/
static void decrypt(I2PAppContext ctx, byte iv[], byte orig[], int offset, int length, byte cur[], HopConfig config) {
static void decrypt(I2PAppContext ctx, byte orig[], int offset, int length, HopConfig config) {
SessionKey ivkey = config.getIVKey();
AESEngine aes = ctx.aes();
// update the IV for the previous (next?) hop
ctx.aes().decryptBlock(orig, offset, config.getIVKey(), orig, offset);
int numBlocks = (length - HopProcessor.IV_LENGTH) / HopProcessor.IV_LENGTH;
// prev == previous encrypted block (or IV for the first block)
byte prev[] = iv;
System.arraycopy(orig, offset, prev, 0, HopProcessor.IV_LENGTH);
//_log.debug("IV at curHop: " + Base64.encode(iv));
//decrypt the whole row
for (int i = 0; i < numBlocks; i++) {
int off = (i + 1) * HopProcessor.IV_LENGTH + offset;
System.arraycopy(orig, off, cur, 0, HopProcessor.IV_LENGTH);
ctx.aes().decryptBlock(orig, off, config.getLayerKey(), orig, off);
//DataHelper.xor(prev, 0, orig, off, orig, off, HopProcessor.IV_LENGTH);
for (int j = 0; j < HopProcessor.IV_LENGTH; j++) {
orig[off + j] ^= prev[j];
}
byte xf[] = prev;
prev = cur;
cur = xf;
}
//if (HopProcessor.USE_DOUBLE_IV_ENCRYPTION)
ctx.aes().decryptBlock(orig, offset, config.getIVKey(), orig, offset);
aes.decryptBlock(orig, offset, ivkey, orig, offset);
//Log log = ctx.logManager().getLog(OutboundGatewayProcessor.class);
//log.debug("IV at curHop after decrypt: " + Base64.encode(orig, offset, IV_LENGTH));
aes.decrypt(orig, offset + IV_LENGTH, orig, offset + IV_LENGTH, config.getLayerKey(),
orig, offset, length - IV_LENGTH);
// double IV encryption
aes.decryptBlock(orig, offset, ivkey, orig, offset);
//log.debug("IV at curHop after double decrypt: " + Base64.encode(orig, offset, IV_LENGTH));
}
}