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:
@ -1,4 +1,4 @@
|
|||||||
<code>$Id: tunnel.html,v 1.8 2005/01/15 01:43:35 jrandom Exp $</code>
|
<code>$Id: tunnel.html,v 1.9 2005/01/15 19:08:14 jrandom Exp $</code>
|
||||||
<pre>
|
<pre>
|
||||||
1) <a href="#tunnel.overview">Tunnel overview</a>
|
1) <a href="#tunnel.overview">Tunnel overview</a>
|
||||||
2) <a href="#tunnel.operation">Tunnel operation</a>
|
2) <a href="#tunnel.operation">Tunnel operation</a>
|
||||||
@ -146,8 +146,8 @@ verify the integrity of the checksum block. The specific details follow.</p>
|
|||||||
|
|
||||||
<p>The encryption used is such that decryption
|
<p>The encryption used is such that decryption
|
||||||
merely requires running over the data with AES in CBC mode, calculating the
|
merely requires running over the data with AES in CBC mode, calculating the
|
||||||
SHA256 of a certain fixed portion of the message (bytes 16 through $size-288),
|
SHA256 of a certain fixed portion of the message (bytes 16 through $size-144),
|
||||||
and searching for that hash in the checksum block. There is a fixed number
|
and searching for the first 16 bytes of that hash in the checksum block. There is a fixed number
|
||||||
of hops defined (8 peers) so that we can verify the message
|
of hops defined (8 peers) so that we can verify the message
|
||||||
without either leaking the position in the tunnel or having the message
|
without either leaking the position in the tunnel or having the message
|
||||||
continually "shrink" as layers are peeled off. For tunnels shorter than 8
|
continually "shrink" as layers are peeled off. For tunnels shorter than 8
|
||||||
@ -239,7 +239,7 @@ To visualize this a bit:</p>
|
|||||||
</table>
|
</table>
|
||||||
|
|
||||||
<p>In the above, P[7] is the same as the original data being passed through the
|
<p>In the above, P[7] is the same as the original data being passed through the
|
||||||
tunnel (the preprocessed messages), and V[7] is the SHA256 of eH[0-7] as seen on
|
tunnel (the preprocessed messages), and V[7] is the first 16 bytes of the SHA256 of eH[0-7] as seen on
|
||||||
peer7 after decryption. For
|
peer7 after decryption. For
|
||||||
cells in the matrix "higher up" than the hash, their value is derived by encrypting
|
cells in the matrix "higher up" than the hash, their value is derived by encrypting
|
||||||
the cell below it with the key for the peer below it, using the end of the column
|
the cell below it with the key for the peer below it, using the end of the column
|
||||||
@ -268,8 +268,8 @@ peer who is the first hop (usually the peer1.recv row) and forward that entirely
|
|||||||
|
|
||||||
<p>When a participant in a tunnel receives a message, they decrypt a layer with their
|
<p>When a participant in a tunnel receives a message, they decrypt a layer with their
|
||||||
tunnel key using AES256 in CBC mode with the first 16 bytes as the IV. They then
|
tunnel key using AES256 in CBC mode with the first 16 bytes as the IV. They then
|
||||||
calculate the hash of what they see as the payload (bytes 16 through $size-288) and
|
calculate the hash of what they see as the payload (bytes 16 through $size-144) and
|
||||||
search for that hash within the decrypted checksum block. If no match is found, the
|
search for that first 16 bytes of that hash within the decrypted checksum block. If no match is found, the
|
||||||
message is discarded. Otherwise, the IV is updated by decrypting it, XORing that value
|
message is discarded. Otherwise, the IV is updated by decrypting it, XORing that value
|
||||||
with the IV_WHITENER, and replacing it with the first 16 bytes of its hash. The
|
with the IV_WHITENER, and replacing it with the first 16 bytes of its hash. The
|
||||||
resulting message is then forwarded on to the next peer for processing.</p>
|
resulting message is then forwarded on to the next peer for processing.</p>
|
||||||
@ -287,7 +287,7 @@ contained in the tunnel.</p>
|
|||||||
<p>When a message reaches the tunnel endpoint, they decrypts and verifies it like
|
<p>When a message reaches the tunnel endpoint, they decrypts and verifies it like
|
||||||
a normal participant. If the checksum block has a valid match, the endpoint then
|
a normal participant. If the checksum block has a valid match, the endpoint then
|
||||||
computes the hash of the checksum block itself (as seen after decryption) and compares
|
computes the hash of the checksum block itself (as seen after decryption) and compares
|
||||||
that to the decrypted verification hash (the last 32 bytes). If that verification
|
that to the decrypted verification hash (the last 16 bytes). If that verification
|
||||||
hash does not match, the endpoint takes note of the tagging attempt by one of the
|
hash does not match, the endpoint takes note of the tagging attempt by one of the
|
||||||
tunnel participants and perhaps discards the message.</p>
|
tunnel participants and perhaps discards the message.</p>
|
||||||
|
|
||||||
@ -328,7 +328,7 @@ and handling fragmentation will not immediately be implemented.</p>
|
|||||||
|
|
||||||
<p>One alternative to the above process is to remove the checksum block
|
<p>One alternative to the above process is to remove the checksum block
|
||||||
completely and replace the verification hash with a plain hash of the payload.
|
completely and replace the verification hash with a plain hash of the payload.
|
||||||
This would simplify processing at the tunnel gateway and save 256 bytes of
|
This would simplify processing at the tunnel gateway and save 144 bytes of
|
||||||
bandwidth at each hop. On the other hand, attackers within the tunnel could
|
bandwidth at each hop. On the other hand, attackers within the tunnel could
|
||||||
trivially adjust the message size to one which is easily traceable by
|
trivially adjust the message size to one which is easily traceable by
|
||||||
colluding external observers in addition to later tunnel participants. The
|
colluding external observers in addition to later tunnel participants. The
|
||||||
@ -344,7 +344,7 @@ there are three alternatives that can be explored:</p>
|
|||||||
<ul>
|
<ul>
|
||||||
<li>Delay a message within a tunnel at an arbitrary hop for either a specified
|
<li>Delay a message within a tunnel at an arbitrary hop for either a specified
|
||||||
amount of time or a randomized period. This could be achieved by replacing the
|
amount of time or a randomized period. This could be achieved by replacing the
|
||||||
hash in the checksum block with e.g. the first 16 bytes of the hash, followed by
|
hash in the checksum block with e.g. the first 8 bytes of the hash, followed by
|
||||||
some delay instructions. Alternately, the instructions could tell the
|
some delay instructions. Alternately, the instructions could tell the
|
||||||
participant to actually interpret the raw payload as it is, and either discard
|
participant to actually interpret the raw payload as it is, and either discard
|
||||||
the message or continue to forward it down the path (where it would be
|
the message or continue to forward it down the path (where it would be
|
||||||
@ -378,12 +378,14 @@ minimize the worries of the predecessor attack, though if it were desired,
|
|||||||
it wouldn't be much trouble to build both the inbound and outbound tunnels
|
it wouldn't be much trouble to build both the inbound and outbound tunnels
|
||||||
along the same peers.</p>
|
along the same peers.</p>
|
||||||
|
|
||||||
<h4>2.7.4) <a name="tunnel.smallerhashes">Use smaller hashes</a></h4>
|
<h4>2.7.4) <a name="tunnel.smallerhashes">Use smaller blocksize</a></h4>
|
||||||
|
|
||||||
<p>At the moment, the plan is to reuse the existing SHA256 code and build
|
<p>At the moment, our use of AES limits our block size to 16 bytes, which
|
||||||
all of the checksum and verification hashes as 32 byte SHA256 values. 20
|
in turn provides the minimum size for each of the checksum block columns.
|
||||||
byte SHA1 would likely be more than sufficient, or perhaps smaller - first
|
If another algorithm was used with a smaller block size, or could otherwise
|
||||||
4 bytes of the SHA256.</p>
|
allow the safe building of the checksum block with smaller portions of the
|
||||||
|
hash, it might be worth exploring. The 16 bytes used now at each hop should
|
||||||
|
be more than sufficient.</p>
|
||||||
|
|
||||||
<h2>3) <a name="tunnel.building">Tunnel building</a></h2>
|
<h2>3) <a name="tunnel.building">Tunnel building</a></h2>
|
||||||
|
|
||||||
|
@ -53,6 +53,10 @@ public class GatewayMessage {
|
|||||||
private static final byte EMPTY[] = new byte[0];
|
private static final byte EMPTY[] = new byte[0];
|
||||||
private static final int COLUMNS = HOPS;
|
private static final int COLUMNS = HOPS;
|
||||||
private static final int HASH_ROWS = 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 */
|
/** used to munge the IV during per-hop translations */
|
||||||
static final byte IV_WHITENER[] = new byte[] { (byte)0x31, (byte)0xd6, (byte)0x74, (byte)0x17,
|
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];
|
_iv = new byte[HOPS-1][IV_SIZE];
|
||||||
_eIV = new byte[HOPS-1][IV_SIZE];
|
_eIV = new byte[HOPS-1][IV_SIZE];
|
||||||
_H = new byte[HOPS][Hash.HASH_LENGTH];
|
_H = new byte[HOPS][Hash.HASH_LENGTH];
|
||||||
_eH = new byte[COLUMNS][HASH_ROWS][Hash.HASH_LENGTH];
|
_eH = new byte[COLUMNS][HASH_ROWS][COLUMN_WIDTH];
|
||||||
_preV = new byte[HOPS*Hash.HASH_LENGTH];
|
_preV = new byte[HOPS*COLUMN_WIDTH];
|
||||||
_V = new byte[Hash.HASH_LENGTH];
|
_V = new byte[VERIFICATION_WIDTH];
|
||||||
_order = new int[HOPS];
|
_order = new int[HOPS];
|
||||||
_encrypted = false;
|
_encrypted = false;
|
||||||
_payloadSet = false;
|
_payloadSet = false;
|
||||||
@ -224,24 +228,19 @@ public class GatewayMessage {
|
|||||||
// which _H[hash] value are we rendering in this column?
|
// which _H[hash] value are we rendering in this column?
|
||||||
int hash = _order[column];
|
int hash = _order[column];
|
||||||
// fill in the cleartext version for this 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
|
// 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
|
// by encrypting _eH[column][row] with the peer's key, using the
|
||||||
// of the previous column (or _eIV[row-1]) as the IV
|
// previous column (or _eIV[row-1]) as the IV
|
||||||
for (int row = hash; row > 0; row--) {
|
for (int row = hash; row > 0; row--) {
|
||||||
SessionKey key = cfg.getSessionKey(row);
|
SessionKey key = cfg.getSessionKey(row);
|
||||||
// first half
|
|
||||||
if (column == 0) {
|
if (column == 0) {
|
||||||
DataHelper.xor(_eIV[row-1], 0, _eH[column][row], 0, _eH[column][row-1], 0, IV_SIZE);
|
DataHelper.xor(_eIV[row-1], 0, _eH[column][row], 0, _eH[column][row-1], 0, IV_SIZE);
|
||||||
} else {
|
} 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);
|
_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
|
// fill in the "later" rows by encrypting the previous rows with the
|
||||||
@ -255,10 +254,7 @@ public class GatewayMessage {
|
|||||||
if (column == 0)
|
if (column == 0)
|
||||||
DataHelper.xor(_eIV[row-1], 0, _eH[column][row], 0, _eH[column][row], 0, IV_SIZE);
|
DataHelper.xor(_eIV[row-1], 0, _eH[column][row], 0, _eH[column][row], 0, IV_SIZE);
|
||||||
else
|
else
|
||||||
DataHelper.xor(_eH[column-1][row-1], IV_SIZE, _eH[column][row], 0, _eH[column][row], 0, IV_SIZE);
|
DataHelper.xor(_eH[column-1][row-1], 0, _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);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -268,7 +264,7 @@ public class GatewayMessage {
|
|||||||
for (int column = 0; column < COLUMNS; column++) {
|
for (int column = 0; column < COLUMNS; column++) {
|
||||||
try {
|
try {
|
||||||
_log.debug("_eH[" + column + "][" + peer + "] = " + Base64.encode(_eH[column][peer])
|
_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) {
|
} catch (Exception e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
System.out.println("column="+column + " peer=" + peer);
|
System.out.println("column="+column + " peer=" + peer);
|
||||||
@ -285,9 +281,9 @@ public class GatewayMessage {
|
|||||||
*/
|
*/
|
||||||
private final void encryptVerificationHash(GatewayTunnelConfig cfg) {
|
private final void encryptVerificationHash(GatewayTunnelConfig cfg) {
|
||||||
for (int i = 0; i < COLUMNS; i++)
|
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);
|
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))
|
if (_log.shouldLog(Log.DEBUG))
|
||||||
_log.debug("_V final = " + Base64.encode(_V));
|
_log.debug("_V final = " + Base64.encode(_V));
|
||||||
@ -296,10 +292,8 @@ public class GatewayMessage {
|
|||||||
SessionKey key = cfg.getSessionKey(i);
|
SessionKey key = cfg.getSessionKey(i);
|
||||||
// xor the last block of the encrypted payload with the first block of _V to
|
// xor the last block of the encrypted payload with the first block of _V to
|
||||||
// continue the CTR operation
|
// 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);
|
_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))
|
if (_log.shouldLog(Log.DEBUG))
|
||||||
_log.debug("_V at peer " + i + " = " + Base64.encode(_V));
|
_log.debug("_V at peer " + i + " = " + Base64.encode(_V));
|
||||||
@ -317,8 +311,8 @@ public class GatewayMessage {
|
|||||||
public final int getExportedSize() {
|
public final int getExportedSize() {
|
||||||
return IV_SIZE +
|
return IV_SIZE +
|
||||||
_payload.length +
|
_payload.length +
|
||||||
COLUMNS * Hash.HASH_LENGTH +
|
COLUMNS * COLUMN_WIDTH +
|
||||||
Hash.HASH_LENGTH; // verification hash
|
VERIFICATION_WIDTH; // verification hash
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -343,11 +337,11 @@ public class GatewayMessage {
|
|||||||
System.arraycopy(_payload, 0, target, cur, _payload.length);
|
System.arraycopy(_payload, 0, target, cur, _payload.length);
|
||||||
cur += _payload.length;
|
cur += _payload.length;
|
||||||
for (int column = 0; column < COLUMNS; column++) {
|
for (int column = 0; column < COLUMNS; column++) {
|
||||||
System.arraycopy(_eH[column][0], 0, target, cur, Hash.HASH_LENGTH);
|
System.arraycopy(_eH[column][0], 0, target, cur, COLUMN_WIDTH);
|
||||||
cur += Hash.HASH_LENGTH;
|
cur += COLUMN_WIDTH;
|
||||||
}
|
}
|
||||||
System.arraycopy(_V, 0, target, cur, Hash.HASH_LENGTH);
|
System.arraycopy(_V, 0, target, cur, VERIFICATION_WIDTH);
|
||||||
cur += Hash.HASH_LENGTH;
|
cur += VERIFICATION_WIDTH;
|
||||||
return cur;
|
return cur;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -360,13 +354,13 @@ public class GatewayMessage {
|
|||||||
Log log = ctx.logManager().getLog(GatewayMessage.class);
|
Log log = ctx.logManager().getLog(GatewayMessage.class);
|
||||||
boolean match = true;
|
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++) {
|
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))
|
if (log.shouldLog(Log.DEBUG))
|
||||||
log.debug("checksum[" + column + "][" + (peer) + "] matches? " + ok);
|
log.debug("checksum[" + column + "][" + (peer) + "] matches? " + ok);
|
||||||
|
|
||||||
off += Hash.HASH_LENGTH;
|
off += COLUMN_WIDTH;
|
||||||
match = match && ok;
|
match = match && ok;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -14,6 +14,8 @@ import net.i2p.util.Log;
|
|||||||
public class TunnelMessageProcessor {
|
public class TunnelMessageProcessor {
|
||||||
private static final int IV_SIZE = GatewayMessage.IV_SIZE;
|
private static final int IV_SIZE = GatewayMessage.IV_SIZE;
|
||||||
private static final int HOPS = GatewayMessage.HOPS;
|
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.
|
* Unwrap the tunnel message, overwriting it with the decrypted version.
|
||||||
@ -28,8 +30,8 @@ public class TunnelMessageProcessor {
|
|||||||
|
|
||||||
int payloadLength = data.length
|
int payloadLength = data.length
|
||||||
- IV_SIZE // IV
|
- IV_SIZE // IV
|
||||||
- HOPS * Hash.HASH_LENGTH // checksum blocks
|
- HOPS * COLUMN_WIDTH // checksum blocks
|
||||||
- Hash.HASH_LENGTH; // verification of the checksum blocks
|
- VERIFICATION_WIDTH; // verification of the checksum blocks
|
||||||
|
|
||||||
Hash recvPayloadHash = ctx.sha().calculateHash(data, IV_SIZE, payloadLength);
|
Hash recvPayloadHash = ctx.sha().calculateHash(data, IV_SIZE, payloadLength);
|
||||||
if (log.shouldLog(Log.DEBUG))
|
if (log.shouldLog(Log.DEBUG))
|
||||||
@ -60,7 +62,7 @@ public class TunnelMessageProcessor {
|
|||||||
|
|
||||||
int numBlocks = (data.length - IV_SIZE) / IV_SIZE;
|
int numBlocks = (data.length - IV_SIZE) / IV_SIZE;
|
||||||
// for debugging, so we can compare eIV
|
// 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)
|
// prev == previous encrypted block (or IV for the first block)
|
||||||
byte prev[] = new byte[IV_SIZE];
|
byte prev[] = new byte[IV_SIZE];
|
||||||
@ -103,23 +105,23 @@ public class TunnelMessageProcessor {
|
|||||||
Log log = getLog(ctx);
|
Log log = getLog(ctx);
|
||||||
int matchFound = -1;
|
int matchFound = -1;
|
||||||
|
|
||||||
int off = data.length - (GatewayMessage.HOPS + 1) * Hash.HASH_LENGTH;
|
int off = data.length - HOPS * COLUMN_WIDTH - VERIFICATION_WIDTH;
|
||||||
for (int i = 0; i < GatewayMessage.HOPS; i++) {
|
for (int i = 0; i < HOPS; i++) {
|
||||||
if (DataHelper.eq(payloadHash.getData(), 0, data, off, Hash.HASH_LENGTH)) {
|
if (DataHelper.eq(payloadHash.getData(), 0, data, off, COLUMN_WIDTH)) {
|
||||||
matchFound = i;
|
matchFound = i;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
off += Hash.HASH_LENGTH;
|
off += COLUMN_WIDTH;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (log.shouldLog(Log.DEBUG)) {
|
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++)
|
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" : ""));
|
+ (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;
|
return matchFound != -1;
|
||||||
@ -132,15 +134,15 @@ public class TunnelMessageProcessor {
|
|||||||
* @return true if the checksum is valid, false if it has been modified
|
* @return true if the checksum is valid, false if it has been modified
|
||||||
*/
|
*/
|
||||||
public boolean verifyChecksum(I2PAppContext ctx, byte message[]) {
|
public boolean verifyChecksum(I2PAppContext ctx, byte message[]) {
|
||||||
int checksumSize = GatewayMessage.HOPS * Hash.HASH_LENGTH;
|
int checksumSize = HOPS * COLUMN_WIDTH;
|
||||||
int offset = message.length - (checksumSize + Hash.HASH_LENGTH);
|
int offset = message.length - (checksumSize + VERIFICATION_WIDTH);
|
||||||
Hash checksumHash = ctx.sha().calculateHash(message, offset, checksumSize);
|
Hash checksumHash = ctx.sha().calculateHash(message, offset, checksumSize);
|
||||||
getLog(ctx).debug("Measured checksum: " + checksumHash.toBase64());
|
getLog(ctx).debug("Measured checksum: " + checksumHash.toBase64());
|
||||||
byte expected[] = new byte[Hash.HASH_LENGTH];
|
byte expected[] = new byte[VERIFICATION_WIDTH];
|
||||||
System.arraycopy(message, message.length-Hash.HASH_LENGTH, expected, 0, Hash.HASH_LENGTH);
|
System.arraycopy(message, message.length-VERIFICATION_WIDTH, expected, 0, VERIFICATION_WIDTH);
|
||||||
getLog(ctx).debug("Expected checksum: " + Base64.encode(expected));
|
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) {
|
private static final Log getLog(I2PAppContext ctx) {
|
||||||
|
Reference in New Issue
Block a user