forked from I2P_Developers/i2p.i2p
use the first 16 bytes of the SHA256 for the columns & verification block, rather than all 32 bytes.
(AES won't let us go smaller. oh well)
This commit is contained in:
@ -53,6 +53,10 @@ public class GatewayMessage {
|
||||
private static final byte EMPTY[] = new byte[0];
|
||||
private static final int COLUMNS = HOPS;
|
||||
private static final int HASH_ROWS = HOPS;
|
||||
/** # bytes of the hash to maintain in each column */
|
||||
static final int COLUMN_WIDTH = IV_SIZE;
|
||||
/** # bytes of the verification hash to maintain */
|
||||
static final int VERIFICATION_WIDTH = IV_SIZE;
|
||||
|
||||
/** used to munge the IV during per-hop translations */
|
||||
static final byte IV_WHITENER[] = new byte[] { (byte)0x31, (byte)0xd6, (byte)0x74, (byte)0x17,
|
||||
@ -70,9 +74,9 @@ public class GatewayMessage {
|
||||
_iv = new byte[HOPS-1][IV_SIZE];
|
||||
_eIV = new byte[HOPS-1][IV_SIZE];
|
||||
_H = new byte[HOPS][Hash.HASH_LENGTH];
|
||||
_eH = new byte[COLUMNS][HASH_ROWS][Hash.HASH_LENGTH];
|
||||
_preV = new byte[HOPS*Hash.HASH_LENGTH];
|
||||
_V = new byte[Hash.HASH_LENGTH];
|
||||
_eH = new byte[COLUMNS][HASH_ROWS][COLUMN_WIDTH];
|
||||
_preV = new byte[HOPS*COLUMN_WIDTH];
|
||||
_V = new byte[VERIFICATION_WIDTH];
|
||||
_order = new int[HOPS];
|
||||
_encrypted = false;
|
||||
_payloadSet = false;
|
||||
@ -224,24 +228,19 @@ public class GatewayMessage {
|
||||
// which _H[hash] value are we rendering in this column?
|
||||
int hash = _order[column];
|
||||
// fill in the cleartext version for this column
|
||||
System.arraycopy(_H[hash], 0, _eH[column][hash], 0, Hash.HASH_LENGTH);
|
||||
System.arraycopy(_H[hash], 0, _eH[column][hash], 0, COLUMN_WIDTH);
|
||||
|
||||
// now fill in the "earlier" _eH[column][row-1] values for earlier hops
|
||||
// by encrypting _eH[column][row] with the peer's key, using the end
|
||||
// of the previous column (or _eIV[row-1]) as the IV
|
||||
// by encrypting _eH[column][row] with the peer's key, using the
|
||||
// previous column (or _eIV[row-1]) as the IV
|
||||
for (int row = hash; row > 0; row--) {
|
||||
SessionKey key = cfg.getSessionKey(row);
|
||||
// first half
|
||||
if (column == 0) {
|
||||
DataHelper.xor(_eIV[row-1], 0, _eH[column][row], 0, _eH[column][row-1], 0, IV_SIZE);
|
||||
} else {
|
||||
DataHelper.xor(_eH[column-1][row-1], IV_SIZE, _eH[column][row], 0, _eH[column][row-1], 0, IV_SIZE);
|
||||
DataHelper.xor(_eH[column-1][row-1], 0, _eH[column][row], 0, _eH[column][row-1], 0, IV_SIZE);
|
||||
}
|
||||
_context.aes().encryptBlock(_eH[column][row-1], 0, key, _eH[column][row-1], 0);
|
||||
|
||||
// second half
|
||||
DataHelper.xor(_eH[column][row-1], 0, _eH[column][row], IV_SIZE, _eH[column][row-1], IV_SIZE, IV_SIZE);
|
||||
_context.aes().encryptBlock(_eH[column][row-1], IV_SIZE, key, _eH[column][row-1], IV_SIZE);
|
||||
}
|
||||
|
||||
// fill in the "later" rows by encrypting the previous rows with the
|
||||
@ -255,10 +254,7 @@ public class GatewayMessage {
|
||||
if (column == 0)
|
||||
DataHelper.xor(_eIV[row-1], 0, _eH[column][row], 0, _eH[column][row], 0, IV_SIZE);
|
||||
else
|
||||
DataHelper.xor(_eH[column-1][row-1], IV_SIZE, _eH[column][row], 0, _eH[column][row], 0, IV_SIZE);
|
||||
|
||||
_context.aes().decryptBlock(_eH[column][row-1], IV_SIZE, key, _eH[column][row], IV_SIZE);
|
||||
DataHelper.xor(_eH[column][row-1], 0, _eH[column][row], IV_SIZE, _eH[column][row], IV_SIZE, IV_SIZE);
|
||||
DataHelper.xor(_eH[column-1][row-1], 0, _eH[column][row], 0, _eH[column][row], 0, IV_SIZE);
|
||||
}
|
||||
}
|
||||
|
||||
@ -268,7 +264,7 @@ public class GatewayMessage {
|
||||
for (int column = 0; column < COLUMNS; column++) {
|
||||
try {
|
||||
_log.debug("_eH[" + column + "][" + peer + "] = " + Base64.encode(_eH[column][peer])
|
||||
+ (peer == 0 ? "" : DataHelper.eq(_H[peer-1], _eH[column][peer]) ? " CLEARTEXT" : ""));
|
||||
+ (peer == 0 ? "" : DataHelper.eq(_H[peer-1], 0, _eH[column][peer], 0, COLUMN_WIDTH) ? " CLEARTEXT" : ""));
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
System.out.println("column="+column + " peer=" + peer);
|
||||
@ -285,9 +281,9 @@ public class GatewayMessage {
|
||||
*/
|
||||
private final void encryptVerificationHash(GatewayTunnelConfig cfg) {
|
||||
for (int i = 0; i < COLUMNS; i++)
|
||||
System.arraycopy(_eH[i][HASH_ROWS-1], 0, _preV, i * Hash.HASH_LENGTH, Hash.HASH_LENGTH);
|
||||
System.arraycopy(_eH[i][HASH_ROWS-1], 0, _preV, i * COLUMN_WIDTH, COLUMN_WIDTH);
|
||||
Hash v = _context.sha().calculateHash(_preV);
|
||||
System.arraycopy(v.getData(), 0, _V, 0, Hash.HASH_LENGTH);
|
||||
System.arraycopy(v.getData(), 0, _V, 0, VERIFICATION_WIDTH);
|
||||
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
_log.debug("_V final = " + Base64.encode(_V));
|
||||
@ -296,10 +292,8 @@ public class GatewayMessage {
|
||||
SessionKey key = cfg.getSessionKey(i);
|
||||
// xor the last block of the encrypted payload with the first block of _V to
|
||||
// continue the CTR operation
|
||||
DataHelper.xor(_V, 0, _eH[COLUMNS-1][i-1], IV_SIZE, _V, 0, IV_SIZE);
|
||||
DataHelper.xor(_V, 0, _eH[COLUMNS-1][i-1], 0, _V, 0, IV_SIZE);
|
||||
_context.aes().encryptBlock(_V, 0, key, _V, 0);
|
||||
DataHelper.xor(_V, 0, _V, IV_SIZE, _V, IV_SIZE, IV_SIZE);
|
||||
_context.aes().encryptBlock(_V, IV_SIZE, key, _V, IV_SIZE);
|
||||
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
_log.debug("_V at peer " + i + " = " + Base64.encode(_V));
|
||||
@ -317,8 +311,8 @@ public class GatewayMessage {
|
||||
public final int getExportedSize() {
|
||||
return IV_SIZE +
|
||||
_payload.length +
|
||||
COLUMNS * Hash.HASH_LENGTH +
|
||||
Hash.HASH_LENGTH; // verification hash
|
||||
COLUMNS * COLUMN_WIDTH +
|
||||
VERIFICATION_WIDTH; // verification hash
|
||||
}
|
||||
|
||||
/**
|
||||
@ -343,11 +337,11 @@ public class GatewayMessage {
|
||||
System.arraycopy(_payload, 0, target, cur, _payload.length);
|
||||
cur += _payload.length;
|
||||
for (int column = 0; column < COLUMNS; column++) {
|
||||
System.arraycopy(_eH[column][0], 0, target, cur, Hash.HASH_LENGTH);
|
||||
cur += Hash.HASH_LENGTH;
|
||||
System.arraycopy(_eH[column][0], 0, target, cur, COLUMN_WIDTH);
|
||||
cur += COLUMN_WIDTH;
|
||||
}
|
||||
System.arraycopy(_V, 0, target, cur, Hash.HASH_LENGTH);
|
||||
cur += Hash.HASH_LENGTH;
|
||||
System.arraycopy(_V, 0, target, cur, VERIFICATION_WIDTH);
|
||||
cur += VERIFICATION_WIDTH;
|
||||
return cur;
|
||||
}
|
||||
|
||||
@ -360,13 +354,13 @@ public class GatewayMessage {
|
||||
Log log = ctx.logManager().getLog(GatewayMessage.class);
|
||||
boolean match = true;
|
||||
|
||||
int off = message.length - (COLUMNS + 1) * Hash.HASH_LENGTH;
|
||||
int off = message.length - (COLUMNS + 1) * COLUMN_WIDTH;
|
||||
for (int column = 0; column < COLUMNS; column++) {
|
||||
boolean ok = DataHelper.eq(_eH[column][peer], 0, message, off, Hash.HASH_LENGTH);
|
||||
boolean ok = DataHelper.eq(_eH[column][peer], 0, message, off, COLUMN_WIDTH);
|
||||
if (log.shouldLog(Log.DEBUG))
|
||||
log.debug("checksum[" + column + "][" + (peer) + "] matches? " + ok);
|
||||
|
||||
off += Hash.HASH_LENGTH;
|
||||
off += COLUMN_WIDTH;
|
||||
match = match && ok;
|
||||
}
|
||||
|
||||
|
@ -14,6 +14,8 @@ import net.i2p.util.Log;
|
||||
public class TunnelMessageProcessor {
|
||||
private static final int IV_SIZE = GatewayMessage.IV_SIZE;
|
||||
private static final int HOPS = GatewayMessage.HOPS;
|
||||
private static final int COLUMN_WIDTH = GatewayMessage.COLUMN_WIDTH;
|
||||
private static final int VERIFICATION_WIDTH = GatewayMessage.VERIFICATION_WIDTH;
|
||||
|
||||
/**
|
||||
* Unwrap the tunnel message, overwriting it with the decrypted version.
|
||||
@ -28,8 +30,8 @@ public class TunnelMessageProcessor {
|
||||
|
||||
int payloadLength = data.length
|
||||
- IV_SIZE // IV
|
||||
- HOPS * Hash.HASH_LENGTH // checksum blocks
|
||||
- Hash.HASH_LENGTH; // verification of the checksum blocks
|
||||
- HOPS * COLUMN_WIDTH // checksum blocks
|
||||
- VERIFICATION_WIDTH; // verification of the checksum blocks
|
||||
|
||||
Hash recvPayloadHash = ctx.sha().calculateHash(data, IV_SIZE, payloadLength);
|
||||
if (log.shouldLog(Log.DEBUG))
|
||||
@ -60,7 +62,7 @@ public class TunnelMessageProcessor {
|
||||
|
||||
int numBlocks = (data.length - IV_SIZE) / IV_SIZE;
|
||||
// for debugging, so we can compare eIV
|
||||
int numPayloadBlocks = (data.length - IV_SIZE - 2 * IV_SIZE * (GatewayMessage.HOPS + 1)) / IV_SIZE;
|
||||
int numPayloadBlocks = (data.length - IV_SIZE - COLUMN_WIDTH * HOPS - VERIFICATION_WIDTH) / IV_SIZE;
|
||||
|
||||
// prev == previous encrypted block (or IV for the first block)
|
||||
byte prev[] = new byte[IV_SIZE];
|
||||
@ -103,23 +105,23 @@ public class TunnelMessageProcessor {
|
||||
Log log = getLog(ctx);
|
||||
int matchFound = -1;
|
||||
|
||||
int off = data.length - (GatewayMessage.HOPS + 1) * Hash.HASH_LENGTH;
|
||||
for (int i = 0; i < GatewayMessage.HOPS; i++) {
|
||||
if (DataHelper.eq(payloadHash.getData(), 0, data, off, Hash.HASH_LENGTH)) {
|
||||
int off = data.length - HOPS * COLUMN_WIDTH - VERIFICATION_WIDTH;
|
||||
for (int i = 0; i < HOPS; i++) {
|
||||
if (DataHelper.eq(payloadHash.getData(), 0, data, off, COLUMN_WIDTH)) {
|
||||
matchFound = i;
|
||||
break;
|
||||
}
|
||||
|
||||
off += Hash.HASH_LENGTH;
|
||||
off += COLUMN_WIDTH;
|
||||
}
|
||||
|
||||
if (log.shouldLog(Log.DEBUG)) {
|
||||
off = data.length - (GatewayMessage.HOPS + 1) * Hash.HASH_LENGTH;
|
||||
off = data.length - HOPS * COLUMN_WIDTH - VERIFICATION_WIDTH;
|
||||
for (int i = 0; i < HOPS; i++)
|
||||
log.debug("checksum[" + i + "] = " + Base64.encode(data, off + i*Hash.HASH_LENGTH, Hash.HASH_LENGTH)
|
||||
log.debug("checksum[" + i + "] = " + Base64.encode(data, off + i*COLUMN_WIDTH, COLUMN_WIDTH)
|
||||
+ (i == matchFound ? " * MATCH" : ""));
|
||||
|
||||
log.debug("verification = " + Base64.encode(data, data.length - Hash.HASH_LENGTH, Hash.HASH_LENGTH));
|
||||
log.debug("verification = " + Base64.encode(data, data.length - VERIFICATION_WIDTH, VERIFICATION_WIDTH));
|
||||
}
|
||||
|
||||
return matchFound != -1;
|
||||
@ -132,15 +134,15 @@ public class TunnelMessageProcessor {
|
||||
* @return true if the checksum is valid, false if it has been modified
|
||||
*/
|
||||
public boolean verifyChecksum(I2PAppContext ctx, byte message[]) {
|
||||
int checksumSize = GatewayMessage.HOPS * Hash.HASH_LENGTH;
|
||||
int offset = message.length - (checksumSize + Hash.HASH_LENGTH);
|
||||
int checksumSize = HOPS * COLUMN_WIDTH;
|
||||
int offset = message.length - (checksumSize + VERIFICATION_WIDTH);
|
||||
Hash checksumHash = ctx.sha().calculateHash(message, offset, checksumSize);
|
||||
getLog(ctx).debug("Measured checksum: " + checksumHash.toBase64());
|
||||
byte expected[] = new byte[Hash.HASH_LENGTH];
|
||||
System.arraycopy(message, message.length-Hash.HASH_LENGTH, expected, 0, Hash.HASH_LENGTH);
|
||||
byte expected[] = new byte[VERIFICATION_WIDTH];
|
||||
System.arraycopy(message, message.length-VERIFICATION_WIDTH, expected, 0, VERIFICATION_WIDTH);
|
||||
getLog(ctx).debug("Expected checksum: " + Base64.encode(expected));
|
||||
|
||||
return DataHelper.eq(checksumHash.getData(), 0, message, message.length-Hash.HASH_LENGTH, Hash.HASH_LENGTH);
|
||||
return DataHelper.eq(checksumHash.getData(), 0, message, message.length-VERIFICATION_WIDTH, VERIFICATION_WIDTH);
|
||||
}
|
||||
|
||||
private static final Log getLog(I2PAppContext ctx) {
|
||||
|
Reference in New Issue
Block a user