I2P Address: [http://git.idk.i2p]

Skip to content
Snippets Groups Projects
Commit ccb1f491 authored by jrandom's avatar jrandom Committed by zzz
Browse files

use the first 16 bytes of the SHA256 for the columns & verification block,...

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)
parent 49fdac9b
No related branches found
No related tags found
No related merge requests found
<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> ...@@ -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> ...@@ -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 ...@@ -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> ...@@ -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> ...@@ -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> ...@@ -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, ...@@ -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 { ...@@ -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 { ...@@ -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 { ...@@ -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 { ...@@ -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 { ...@@ -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 { ...@@ -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 { ...@@ -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 { ...@@ -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 { ...@@ -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 { ...@@ -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; ...@@ -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 { ...@@ -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 { ...@@ -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 { ...@@ -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 { ...@@ -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) {
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment