From 774231f347ffd8f44221372d4237ec60e770a579 Mon Sep 17 00:00:00 2001 From: jrandom <jrandom> Date: Tue, 28 Sep 2004 20:33:23 +0000 Subject: [PATCH] * started reducing the temporary buffers created within various crypto methods , as we've got some pretty heavy GC churn when under load. rough estimate is we allocate 5-8x as much data as we need, copying it all over the place before forwarding it (or processing it). this should cut down a few of those copies, but not enough yet. it'd be great to get that down to 2x. * lots of logging --- core/java/src/net/i2p/I2PAppContext.java | 2 +- core/java/src/net/i2p/crypto/AESEngine.java | 61 +++---- .../src/net/i2p/crypto/AESInputStream.java | 54 +++--- .../src/net/i2p/crypto/AESOutputStream.java | 28 ++-- .../src/net/i2p/crypto/CryptixAESEngine.java | 156 +++++++++--------- .../net/i2p/crypto/DHSessionKeyBuilder.java | 6 +- .../src/net/i2p/crypto/ElGamalAESEngine.java | 6 +- core/java/src/net/i2p/data/DataHelper.java | 30 +++- .../java/test/net/i2p/crypto/AES256Bench.java | 22 ++- .../net/i2p/crypto/ElGamalAESEngineTest.java | 6 +- .../src/net/i2p/data/i2np/TunnelMessage.java | 2 +- .../src/net/i2p/router/InNetMessagePool.java | 7 + .../src/net/i2p/router/OutNetMessagePool.java | 7 + .../message/HandleTunnelMessageJob.java | 4 +- .../router/message/SendTunnelMessageJob.java | 2 +- .../transport/tcp/ConnectionBuilder.java | 8 +- .../transport/tcp/ConnectionHandler.java | 6 +- .../transport/tcp/ConnectionRunner.java | 5 + .../router/transport/tcp/MessageHandler.java | 7 + .../router/transport/tcp/TCPConnection.java | 1 + 20 files changed, 245 insertions(+), 175 deletions(-) diff --git a/core/java/src/net/i2p/I2PAppContext.java b/core/java/src/net/i2p/I2PAppContext.java index b782378e26..c36f45eca1 100644 --- a/core/java/src/net/i2p/I2PAppContext.java +++ b/core/java/src/net/i2p/I2PAppContext.java @@ -284,7 +284,7 @@ public class I2PAppContext { * matter. Though for the crazy people out there, we do expose a way to * disable it. */ - public AESEngine AESEngine() { + public AESEngine aes() { if (!_AESEngineInitialized) initializeAESEngine(); return _AESEngine; } diff --git a/core/java/src/net/i2p/crypto/AESEngine.java b/core/java/src/net/i2p/crypto/AESEngine.java index 1d1068ae38..2d474bffb0 100644 --- a/core/java/src/net/i2p/crypto/AESEngine.java +++ b/core/java/src/net/i2p/crypto/AESEngine.java @@ -37,21 +37,16 @@ public class AESEngine { /** Encrypt the payload with the session key * @param payload data to be encrypted + * @param payloadIndex index into the payload to start encrypting + * @param out where to store the result + * @param outIndex where in out to start writing * @param sessionKey private esession key to encrypt to - * @param initializationVector IV for CBC - * @return encrypted data + * @param iv IV for CBC + * @param length how much data to encrypt */ - public byte[] encrypt(byte payload[], SessionKey sessionKey, byte initializationVector[]) { - if ((initializationVector == null) || (payload == null) || (sessionKey == null) - || (initializationVector.length != 16)) return null; - - byte cyphertext[] = null; - if ((payload.length % 16) == 0) - cyphertext = new byte[payload.length]; - else - cyphertext = new byte[payload.length + (16 - (payload.length % 16))]; - System.arraycopy(payload, 0, cyphertext, 0, payload.length); - return cyphertext; + public void encrypt(byte payload[], int payloadIndex, byte out[], int outIndex, SessionKey sessionKey, byte iv[], int length) { + System.arraycopy(payload, payloadIndex, out, outIndex, length); + _log.warn("Warning: AES is disabled"); } public byte[] safeEncrypt(byte payload[], SessionKey sessionKey, byte iv[], int paddedSize) { @@ -72,13 +67,17 @@ public class AESEngine { _log.error("Error writing data", dfe); return null; } - return encrypt(baos.toByteArray(), sessionKey, iv); + byte orig[] = baos.toByteArray(); + byte rv[] = new byte[orig.length]; + encrypt(orig, 0, rv, 0, sessionKey, iv, rv.length); + return rv; } public byte[] safeDecrypt(byte payload[], SessionKey sessionKey, byte iv[]) { if ((iv == null) || (payload == null) || (sessionKey == null) || (iv.length != 16)) return null; - byte decr[] = decrypt(payload, sessionKey, iv); + byte decr[] = new byte[payload.length]; + decrypt(payload, 0, decr, 0, sessionKey, iv, payload.length); if (decr == null) { _log.error("Error decrypting the data - payload " + payload.length + " decrypted to null"); return null; @@ -110,19 +109,19 @@ public class AESEngine { } } - /** decrypt the data with the session key provided - * @param cyphertext encrypted data - * @param sessionKey private session key - * @param initializationVector IV for CBC - * @return unencrypted data - */ - public byte[] decrypt(byte cyphertext[], SessionKey sessionKey, byte initializationVector[]) { - if ((initializationVector == null) || (cyphertext == null) || (sessionKey == null) - || (initializationVector.length != 16)) return null; - byte payload[] = new byte[cyphertext.length]; + /** Decrypt the data with the session key + * @param payload data to be decrypted + * @param payloadIndex index into the payload to start decrypting + * @param out where to store the cleartext + * @param outIndex where in out to start writing + * @param sessionKey private session key to decrypt to + * @param iv IV for CBC + * @param length how much data to decrypt + */ + public void decrypt(byte payload[], int payloadIndex, byte out[], int outIndex, SessionKey sessionKey, byte iv[], int length) { + System.arraycopy(payload, payloadIndex, out, outIndex, length); _log.warn("Warning: AES is disabled"); - return cyphertext; } public static void main(String args[]) { @@ -133,14 +132,16 @@ public class AESEngine { byte sbuf[] = new byte[16]; RandomSource.getInstance().nextBytes(sbuf); - byte se[] = ctx.AESEngine().encrypt(sbuf, key, iv); - byte sd[] = ctx.AESEngine().decrypt(se, key, iv); + byte se[] = new byte[16]; + ctx.aes().encrypt(sbuf, 0, se, 0, key, iv, sbuf.length); + byte sd[] = new byte[16]; + ctx.aes().decrypt(se, 0, sd, 0, key, iv, se.length); ctx.logManager().getLog(AESEngine.class).debug("Short test: " + DataHelper.eq(sd, sbuf)); byte lbuf[] = new byte[1024]; RandomSource.getInstance().nextBytes(sbuf); - byte le[] = ctx.AESEngine().safeEncrypt(lbuf, key, iv, 2048); - byte ld[] = ctx.AESEngine().safeDecrypt(le, key, iv); + byte le[] = ctx.aes().safeEncrypt(lbuf, key, iv, 2048); + byte ld[] = ctx.aes().safeDecrypt(le, key, iv); ctx.logManager().getLog(AESEngine.class).debug("Long test: " + DataHelper.eq(ld, lbuf)); } } \ No newline at end of file diff --git a/core/java/src/net/i2p/crypto/AESInputStream.java b/core/java/src/net/i2p/crypto/AESInputStream.java index e5012cffc2..2e1220e77f 100644 --- a/core/java/src/net/i2p/crypto/AESInputStream.java +++ b/core/java/src/net/i2p/crypto/AESInputStream.java @@ -230,22 +230,21 @@ public class AESInputStream extends FilterInputStream { _log.info(encrypted.length + " bytes makes up " + numBlocks + " blocks to decrypt normally"); } - byte block[] = new byte[BLOCK_SIZE]; for (int i = 0; i < numBlocks; i++) { - System.arraycopy(encrypted, i * BLOCK_SIZE, block, 0, BLOCK_SIZE); - byte decrypted[] = _context.AESEngine().decrypt(block, _key, _lastBlock); - byte data[] = DataHelper.xor(decrypted, _lastBlock); - int cleaned[] = stripPadding(data); - for (int j = 0; j < cleaned.length; j++) { - if (cleaned[j] <= 0) { - cleaned[j] += 256; - //_log.error("(modified: " + cleaned[j] + ")"); - } - _readyBuf.add(new Integer(cleaned[j])); + _context.aes().decrypt(encrypted, i * BLOCK_SIZE, encrypted, i * BLOCK_SIZE, _key, _lastBlock, BLOCK_SIZE); + DataHelper.xor(encrypted, i * BLOCK_SIZE, _lastBlock, 0, encrypted, i * BLOCK_SIZE, BLOCK_SIZE); + int payloadBytes = countBlockPayload(encrypted, i * BLOCK_SIZE); + + for (int j = 0; j < payloadBytes; j++) { + int c = encrypted[j + i * BLOCK_SIZE]; + if (c <= 0) + c += 256; + _readyBuf.add(new Integer(c)); } - _cumulativePrepared += cleaned.length; - //_log.debug("Updating last block for inputStream"); - System.arraycopy(decrypted, 0, _lastBlock, 0, BLOCK_SIZE); + _cumulativePaddingStripped += BLOCK_SIZE - payloadBytes; + _cumulativePrepared += payloadBytes; + + System.arraycopy(encrypted, i * BLOCK_SIZE, _lastBlock, 0, BLOCK_SIZE); } int remaining = encrypted.length % BLOCK_SIZE; @@ -263,6 +262,9 @@ public class AESInputStream extends FilterInputStream { } /** + * How many non-padded bytes are there in the block starting at the given + * location. + * * PKCS#5 specifies the padding for the block has the # of padding bytes * located in the last byte of the block, and each of the padding bytes are * equal to that value. @@ -275,31 +277,29 @@ public class AESInputStream extends FilterInputStream { * * We use 16 byte blocks in this AES implementation * + * @throws IOException if the padding is invalid */ - private int[] stripPadding(byte data[]) throws IOException { - int numPadBytes = data[data.length - 1]; - if ((numPadBytes >= data.length) || (numPadBytes <= 0)) { + private int countBlockPayload(byte data[], int startIndex) throws IOException { + int numPadBytes = data[startIndex + BLOCK_SIZE - 1]; + if ((numPadBytes >= BLOCK_SIZE) || (numPadBytes <= 0)) { if (_log.shouldLog(Log.DEBUG)) - _log.debug("stripPadding from block " + DataHelper.toHexString(data) + " (" + data.length + "bytes): " + _log.debug("countBlockPayload on block index " + startIndex + numPadBytes + " is an invalid # of pad bytes"); throw new IOException("Invalid number of pad bytes (" + numPadBytes - + ") for " + data.length + " bytes"); + + ") for " + startIndex + " index"); } - int rv[] = new int[data.length - numPadBytes]; // optional, but a really good idea: verify the padding if (true) { - for (int i = data.length - numPadBytes; i < data.length; i++) { - if (data[i] != (byte) numPadBytes) { + for (int i = BLOCK_SIZE - numPadBytes; i < BLOCK_SIZE; i++) { + if (data[startIndex + i] != (byte) numPadBytes) { throw new IOException("Incorrect padding on decryption: data[" + i - + "] = " + data[i] + " not " + numPadBytes); + + "] = " + data[startIndex + i] + " not " + numPadBytes); } } } - for (int i = 0; i < rv.length; i++) - rv[i] = data[i]; - _cumulativePaddingStripped += numPadBytes; - return rv; + + return BLOCK_SIZE - numPadBytes; } int remainingBytes() { diff --git a/core/java/src/net/i2p/crypto/AESOutputStream.java b/core/java/src/net/i2p/crypto/AESOutputStream.java index f50b39f6c0..4b6a63b3ab 100644 --- a/core/java/src/net/i2p/crypto/AESOutputStream.java +++ b/core/java/src/net/i2p/crypto/AESOutputStream.java @@ -106,18 +106,16 @@ public class AESOutputStream extends FilterOutputStream { int numBlocks = src.length / (BLOCK_SIZE - 1); byte block[] = new byte[BLOCK_SIZE]; - block[BLOCK_SIZE - 1] = 0x01; // the padding byte for "full" blocks for (int i = 0; i < numBlocks; i++) { - System.arraycopy(src, i * 15, block, 0, 15); - byte data[] = DataHelper.xor(block, _lastBlock); - byte encrypted[] = _context.AESEngine().encrypt(data, _key, _lastBlock); - _cumulativeWritten += encrypted.length; + DataHelper.xor(src, i * 15, _lastBlock, 0, block, 0, 15); + // the padding byte for "full" blocks + block[BLOCK_SIZE - 1] = (byte)(_lastBlock[BLOCK_SIZE - 1] ^ 0x01); + _context.aes().encrypt(block, 0, block, 0, _key, _lastBlock, BLOCK_SIZE); if (_log.shouldLog(Log.DEBUG)) - _log.debug("Padding block " + i + " of " + numBlocks + " with 1 byte. orig= " - + DataHelper.toHexString(data) + " (size=" + data.length + ") encrypted= " - + DataHelper.toHexString(encrypted) + " (size=" + encrypted.length + ")"); - out.write(encrypted); - System.arraycopy(encrypted, encrypted.length - BLOCK_SIZE, _lastBlock, 0, BLOCK_SIZE); + _log.debug("Padding block " + i + " of " + numBlocks + " with 1 byte"); + out.write(block); + System.arraycopy(block, 0, _lastBlock, 0, BLOCK_SIZE); + _cumulativeWritten += BLOCK_SIZE; _cumulativePadding++; } @@ -129,12 +127,12 @@ public class AESOutputStream extends FilterOutputStream { _log.debug("Padding " + src.length + " with " + paddingBytes + " bytes in " + numBlocks + " blocks"); System.arraycopy(src, numBlocks * 15, block, 0, remainingBytes); Arrays.fill(block, remainingBytes, BLOCK_SIZE, (byte) paddingBytes); - byte data[] = DataHelper.xor(block, _lastBlock); - byte encrypted[] = _context.AESEngine().encrypt(data, _key, _lastBlock); - out.write(encrypted); - System.arraycopy(encrypted, encrypted.length - BLOCK_SIZE, _lastBlock, 0, BLOCK_SIZE); + DataHelper.xor(block, 0, _lastBlock, 0, block, 0, BLOCK_SIZE); + _context.aes().encrypt(block, 0, block, 0, _key, _lastBlock, BLOCK_SIZE); + out.write(block); + System.arraycopy(block, 0, _lastBlock, 0, BLOCK_SIZE); _cumulativePadding += paddingBytes; - _cumulativeWritten += encrypted.length; + _cumulativeWritten += BLOCK_SIZE; } } diff --git a/core/java/src/net/i2p/crypto/CryptixAESEngine.java b/core/java/src/net/i2p/crypto/CryptixAESEngine.java index 51658f77bd..8b1454fef6 100644 --- a/core/java/src/net/i2p/crypto/CryptixAESEngine.java +++ b/core/java/src/net/i2p/crypto/CryptixAESEngine.java @@ -12,6 +12,7 @@ package net.i2p.crypto; import java.security.InvalidKeyException; import net.i2p.I2PAppContext; +import net.i2p.data.DataHelper; import net.i2p.data.SessionKey; import net.i2p.util.Log; @@ -33,104 +34,63 @@ public class CryptixAESEngine extends AESEngine { super(context); _log = context.logManager().getLog(CryptixAESEngine.class); } - - public byte[] encrypt(byte payload[], SessionKey sessionKey, byte initializationVector[]) { - if ((initializationVector == null) || (payload == null) || (payload.length <= 0) || (sessionKey == null) - || (initializationVector.length != 16)) return null; + + public void encrypt(byte payload[], int payloadIndex, byte out[], int outIndex, SessionKey sessionKey, byte iv[], int length) { + if ( (payload == null) || (out == null) || (sessionKey == null) || (iv == null) || (iv.length != 16) ) + throw new NullPointerException("invalid args to aes"); + if (payload.length < payloadIndex + length) + throw new IllegalArgumentException("Payload is too short"); + if (out.length < outIndex + length) + throw new IllegalArgumentException("Output is too short"); + if (length <= 0) + throw new IllegalArgumentException("Length is too small"); + if (length % 16 != 0) + throw new IllegalArgumentException("Only lengths mod 16 are supported here"); if (USE_FAKE_CRYPTO) { _log.warn("AES Crypto disabled! Using trivial XOR"); - byte rv[] = new byte[payload.length]; - for (int i = 0; i < rv.length; i++) - rv[i] = (byte) (payload[i] ^ FAKE_KEY); - return rv; - } - - int numblock = payload.length / 16; - if (payload.length % 16 != 0) numblock++; - byte[][] plain = new byte[numblock][16]; - for (int x = 0; x < numblock; x++) { - for (int y = 0; y < 16; y++) { - plain[x][y] = payload[x * 16 + y]; - } + System.arraycopy(payload, payloadIndex, out, outIndex, length); + return; } - byte[][] cipher = new byte[numblock][16]; - cipher[0] = encrypt(xor(initializationVector, plain[0]), sessionKey); + int numblock = length / 16; + + DataHelper.xor(iv, 0, payload, payloadIndex, out, outIndex, 16); + encryptBlock(out, outIndex, sessionKey, out, outIndex); for (int x = 1; x < numblock; x++) { - cipher[x] = encrypt(xor(cipher[x - 1], plain[x]), sessionKey); + DataHelper.xor(out, outIndex + (x-1) * 16, payload, payloadIndex + x * 16, out, outIndex + x * 16, 16); + encryptBlock(out, outIndex + x * 16, sessionKey, out, outIndex + x * 16); } - - byte[] ret = new byte[numblock * 16]; - for (int x = 0; x < numblock; x++) { - for (int y = 0; y < 16; y++) { - ret[x * 16 + y] = cipher[x][y]; - } - } - - return ret; } - public byte[] decrypt(byte payload[], SessionKey sessionKey, byte initializationVector[]) { - if ((initializationVector == null) || (payload == null) || (payload.length <= 0) || (sessionKey == null) - || (initializationVector.length != 16)) return null; + public void decrypt(byte payload[], int payloadIndex, byte out[], int outIndex, SessionKey sessionKey, byte iv[], int length) { + if ((iv== null) || (payload == null) || (payload.length <= 0) || (sessionKey == null) + || (iv.length != 16)) + throw new IllegalArgumentException("bad setup"); if (USE_FAKE_CRYPTO) { _log.warn("AES Crypto disabled! Using trivial XOR"); - byte rv[] = new byte[payload.length]; - for (int i = 0; i < rv.length; i++) - rv[i] = (byte) (payload[i] ^ FAKE_KEY); - return rv; + System.arraycopy(payload, payloadIndex, out, outIndex, length); + return ; } int numblock = payload.length / 16; if (payload.length % 16 != 0) numblock++; - byte[][] cipher = new byte[numblock][16]; - for (int x = 0; x < numblock; x++) { - for (int y = 0; y < 16; y++) { - cipher[x][y] = payload[x * 16 + y]; - } - } - byte[][] plain = new byte[numblock][16]; - plain[0] = xor(decrypt(cipher[0], sessionKey), initializationVector); + decryptBlock(payload, 0, sessionKey, out, 0); + DataHelper.xor(out, 0, iv, 0, out, 0, 16); for (int x = 1; x < numblock; x++) { - plain[x] = xor(decrypt(cipher[x], sessionKey), cipher[x - 1]); - } - - byte[] ret = new byte[numblock * 16]; - for (int x = 0; x < numblock; x++) { - for (int y = 0; y < 16; y++) { - ret[x * 16 + y] = plain[x][y]; - } + decryptBlock(payload, x * 16, sessionKey, out, x * 16); + DataHelper.xor(out, x * 16, payload, (x - 1) * 16, out, x * 16, 16); } - - return ret; - } - - final static byte[] xor(byte[] a, byte[] b) { - if ((a == null) || (b == null) || (a.length != b.length)) return null; - byte[] ret = new byte[a.length]; - for (int x = 0; x < a.length; x++) { - ret[x] = (byte) (a[x] ^ b[x]); - } - return ret; } - /** Encrypt the payload with the session key - * @param payload data to be encrypted - * @param sessionKey private esession key to encrypt to - * @return encrypted data - */ - final byte[] encrypt(byte payload[], SessionKey sessionKey) { + final void encryptBlock(byte payload[], int inIndex, SessionKey sessionKey, byte out[], int outIndex) { try { Object key = CryptixRijndael_Algorithm.makeKey(sessionKey.getData(), 16); - byte rv[] = new byte[payload.length]; - CryptixRijndael_Algorithm.blockEncrypt(payload, rv, 0, key, 16); - return rv; + CryptixRijndael_Algorithm.blockEncrypt(payload, out, inIndex, outIndex, key, 16); } catch (InvalidKeyException ike) { _log.error("Invalid key", ike); - return null; } } @@ -139,15 +99,55 @@ public class CryptixAESEngine extends AESEngine { * @param sessionKey private session key * @return unencrypted data */ - final byte[] decrypt(byte payload[], SessionKey sessionKey) { + final void decryptBlock(byte payload[], int inIndex, SessionKey sessionKey, byte rv[], int outIndex) { try { Object key = CryptixRijndael_Algorithm.makeKey(sessionKey.getData(), 16); - byte rv[] = new byte[payload.length]; - CryptixRijndael_Algorithm.blockDecrypt(payload, rv, 0, key, 16); - return rv; + CryptixRijndael_Algorithm.blockDecrypt(payload, rv, inIndex, outIndex, key, 16); } catch (InvalidKeyException ike) { _log.error("Invalid key", ike); - return null; } } + + public static void main(String args[]) { + I2PAppContext ctx = new I2PAppContext(); + try { + testEDBlock(ctx); + testED(ctx); + } catch (Exception e) { + e.printStackTrace(); + } + try { Thread.sleep(5*1000); } catch (InterruptedException ie) {} + } + private static void testED(I2PAppContext ctx) { + SessionKey key = ctx.keyGenerator().generateSessionKey(); + byte iv[] = new byte[16]; + byte orig[] = new byte[128]; + byte encrypted[] = new byte[128]; + byte decrypted[] = new byte[128]; + ctx.random().nextBytes(iv); + ctx.random().nextBytes(orig); + CryptixAESEngine aes = new CryptixAESEngine(ctx); + aes.encrypt(orig, 0, encrypted, 0, key, iv, orig.length); + aes.decrypt(encrypted, 0, decrypted, 0, key, iv, encrypted.length); + if (!DataHelper.eq(decrypted,orig)) + throw new RuntimeException("full D(E(orig)) != orig"); + else + System.out.println("full D(E(orig)) == orig"); + } + private static void testEDBlock(I2PAppContext ctx) { + SessionKey key = ctx.keyGenerator().generateSessionKey(); + byte iv[] = new byte[16]; + byte orig[] = new byte[16]; + byte encrypted[] = new byte[16]; + byte decrypted[] = new byte[16]; + ctx.random().nextBytes(iv); + ctx.random().nextBytes(orig); + CryptixAESEngine aes = new CryptixAESEngine(ctx); + aes.encryptBlock(orig, 0, key, encrypted, 0); + aes.decryptBlock(encrypted, 0, key, decrypted, 0); + if (!DataHelper.eq(decrypted,orig)) + throw new RuntimeException("block D(E(orig)) != orig"); + else + System.out.println("block D(E(orig)) == orig"); + } } \ No newline at end of file diff --git a/core/java/src/net/i2p/crypto/DHSessionKeyBuilder.java b/core/java/src/net/i2p/crypto/DHSessionKeyBuilder.java index 5b205541a5..804aff1af7 100644 --- a/core/java/src/net/i2p/crypto/DHSessionKeyBuilder.java +++ b/core/java/src/net/i2p/crypto/DHSessionKeyBuilder.java @@ -352,8 +352,10 @@ public class DHSessionKeyBuilder { byte iv[] = new byte[16]; RandomSource.getInstance().nextBytes(iv); String origVal = "1234567890123456"; // 16 bytes max using AESEngine - byte enc[] = ctx.AESEngine().encrypt(origVal.getBytes(), key1, iv); - byte dec[] = ctx.AESEngine().decrypt(enc, key2, iv); + byte enc[] = new byte[16]; + byte dec[] = new byte[16]; + ctx.aes().encrypt(origVal.getBytes(), 0, enc, 0, key1, iv, 16); + ctx.aes().decrypt(enc, 0, dec, 0, key2, iv, 16); String tranVal = new String(dec); if (origVal.equals(tranVal)) _log.debug("**Success: D(E(val)) == val"); diff --git a/core/java/src/net/i2p/crypto/ElGamalAESEngine.java b/core/java/src/net/i2p/crypto/ElGamalAESEngine.java index bf9ae0e4c0..1b6e501ee3 100644 --- a/core/java/src/net/i2p/crypto/ElGamalAESEngine.java +++ b/core/java/src/net/i2p/crypto/ElGamalAESEngine.java @@ -248,7 +248,8 @@ public class ElGamalAESEngine { SessionKey foundKey) throws DataFormatException { //_log.debug("iv for decryption: " + DataHelper.toString(iv, 16)); //_log.debug("decrypting AES block. encr.length = " + (encrypted == null? -1 : encrypted.length) + " sentTag: " + DataHelper.toString(sentTag, 32)); - byte decrypted[] = _context.AESEngine().decrypt(encrypted, key, iv); + byte decrypted[] = new byte[encrypted.length]; + _context.aes().decrypt(encrypted, 0, decrypted, 0, key, iv, encrypted.length); //Hash h = _context.sha().calculateHash(decrypted); //_log.debug("Hash of entire aes block after decryption: \n" + DataHelper.toString(h.getData(), 32)); try { @@ -503,7 +504,8 @@ public class ElGamalAESEngine { byte aesUnencr[] = aesSrc.toByteArray(); //Hash h = _context.sha().calculateHash(aesUnencr); //_log.debug("Hash of entire aes block before encryption: (len=" + aesUnencr.length + ")\n" + DataHelper.toString(h.getData(), 32)); - byte aesEncr[] = _context.AESEngine().encrypt(aesUnencr, key, iv); + byte aesEncr[] = new byte[aesUnencr.length]; + _context.aes().encrypt(aesUnencr, 0, aesEncr, 0, key, iv, aesEncr.length); //_log.debug("Encrypted length: " + aesEncr.length); return aesEncr; } catch (IOException ioe) { diff --git a/core/java/src/net/i2p/data/DataHelper.java b/core/java/src/net/i2p/data/DataHelper.java index 84f69aa018..b2e5b4ad0e 100644 --- a/core/java/src/net/i2p/data/DataHelper.java +++ b/core/java/src/net/i2p/data/DataHelper.java @@ -467,12 +467,38 @@ public class DataHelper { public final static byte[] xor(byte lhs[], byte rhs[]) { if ((lhs == null) || (rhs == null) || (lhs.length != rhs.length)) return null; + byte rv[] = new byte[lhs.length]; + byte diff[] = new byte[lhs.length]; - for (int i = 0; i < lhs.length; i++) - diff[i] = (byte) (lhs[i] ^ rhs[i]); + xor(lhs, 0, rhs, 0, diff, 0, lhs.length); return diff; } + /** + * xor the lhs with the rhs, storing the result in out. + * + * @param lhs one of the source arrays + * @param startLeft starting index in the lhs array to begin the xor + * @param rhs the other source array + * @param startRight starting index in the rhs array to begin the xor + * @param out output array + * @param startOut starting index in the out array to store the result + * @param len how many bytes into the various arrays to xor + */ + public final static void xor(byte lhs[], int startLeft, byte rhs[], int startRight, byte out[], int startOut, int len) { + if ( (lhs == null) || (rhs == null) || (out == null) ) + throw new NullPointerException("Invalid params to xor (" + lhs + ", " + rhs + ", " + out + ")"); + if (lhs.length < startLeft + len) + throw new IllegalArgumentException("Left hand side is too short"); + if (rhs.length < startRight + len) + throw new IllegalArgumentException("Right hand side is too short"); + if (out.length < startOut + len) + throw new IllegalArgumentException("Result is too short"); + + for (int i = 0; i < len; i++) + out[startOut + i] = (byte) (lhs[startLeft + i] ^ rhs[startRight + i]); + } + // // The following hashcode helpers make it simpler to write consistently hashing // functions for objects based on their value, not JVM memory address diff --git a/core/java/test/net/i2p/crypto/AES256Bench.java b/core/java/test/net/i2p/crypto/AES256Bench.java index 60cce7cdf6..f4adb32819 100644 --- a/core/java/test/net/i2p/crypto/AES256Bench.java +++ b/core/java/test/net/i2p/crypto/AES256Bench.java @@ -72,22 +72,28 @@ public class AES256Bench { iv[x] = (byte)civ[x]; } - byte[] e = _context.AESEngine().encrypt(plain, key, iv); - byte[] d = _context.AESEngine().decrypt(e, key, iv); + byte[] e = new byte[plain.length]; + _context.aes().encrypt(plain, 0, e, 0, key, iv, plain.length); + byte[] d = new byte[e.length]; + _context.aes().decrypt(e, 0, d, 0, key, iv, d.length); boolean same = true; for (int x = 0; x < d.length; x++) { if (plain[x] != d[x]) { - same = false; + throw new RuntimeException("Failed decrypt at " + x); } } System.out.println("Standard test D(E(value)) == value? " + same); + if (!same) throw new RuntimeException("moo"); plain = "1234567890123456".getBytes(); - e = _context.AESEngine().encrypt(plain, key, iv); - d = _context.AESEngine().decrypt(e, key, iv); + e = new byte[plain.length]; + _context.aes().encrypt(plain, 0, e, 0, key, iv, plain.length); + d = new byte[e.length]; + _context.aes().decrypt(e, 0, d, 0, key, iv, d.length); same = DataHelper.eq(plain, d); System.out.println("Different value test D(E(value)) == value? " + same); + if (!same) throw new RuntimeException("moo"); System.out.println(); System.out.println(); @@ -104,9 +110,11 @@ public class AES256Bench { message[i] = (byte)((i%26)+'a'); for (int x = 0; x < times; x++) { long startencrypt = System.currentTimeMillis(); - e = _context.AESEngine().encrypt(message, key, iv); + e = new byte[message.length]; + d = new byte[e.length]; + _context.aes().encrypt(message, 0, e, 0, key, iv, message.length); long endencryptstartdecrypt = System.currentTimeMillis(); - d = _context.AESEngine().decrypt(e, key, iv); + _context.aes().decrypt(e, 0, d, 0, key, iv, d.length); long enddecrypt = System.currentTimeMillis(); System.out.print("."); encrypttime += endencryptstartdecrypt - startencrypt; diff --git a/core/java/test/net/i2p/crypto/ElGamalAESEngineTest.java b/core/java/test/net/i2p/crypto/ElGamalAESEngineTest.java index 9fc0a0a051..7bf7c90b84 100644 --- a/core/java/test/net/i2p/crypto/ElGamalAESEngineTest.java +++ b/core/java/test/net/i2p/crypto/ElGamalAESEngineTest.java @@ -145,8 +145,10 @@ class ElGamalAESEngineTest { String msg = "Hello world01234012345678901234501234567890123450123456789012345"; h = SHA256Generator.getInstance().calculateHash(msg.getBytes()); _log.debug("Hash of entire aes block before encryption: \n" + DataHelper.toString(h.getData(), 32)); - byte aesEncr[] = _context.AESEngine().encrypt(msg.getBytes(), sessionKey, iv); - byte aesDecr[] = _context.AESEngine().decrypt(aesEncr, sessionKey, iv); + byte aesEncr[] = new byte[msg.getBytes().length]; + byte aesDecr[] = new byte[aesEncr.length]; + _context.aes().encrypt(msg.getBytes(), 0, aesEncr, 0, sessionKey, iv, aesEncr.length); + _context.aes().decrypt(aesEncr, 0, aesDecr, 0, sessionKey, iv, aesEncr.length); h = SHA256Generator.getInstance().calculateHash(aesDecr); _log.debug("Hash of entire aes block after decryption: \n" + DataHelper.toString(h.getData(), 32)); if (msg.equals(new String(aesDecr))) { diff --git a/router/java/src/net/i2p/data/i2np/TunnelMessage.java b/router/java/src/net/i2p/data/i2np/TunnelMessage.java index aad4134a50..80da32abfc 100644 --- a/router/java/src/net/i2p/data/i2np/TunnelMessage.java +++ b/router/java/src/net/i2p/data/i2np/TunnelMessage.java @@ -89,7 +89,7 @@ public class TunnelMessage extends I2NPMessageImpl { if ( (_tunnelId == null) || (_data == null) || (_data.length <= 0) ) throw new I2NPMessageException("Not enough data to write out"); - ByteArrayOutputStream os = new ByteArrayOutputStream(4096); + ByteArrayOutputStream os = new ByteArrayOutputStream(64+_data.length); try { _tunnelId.writeBytes(os); if (_log.shouldLog(Log.DEBUG)) diff --git a/router/java/src/net/i2p/router/InNetMessagePool.java b/router/java/src/net/i2p/router/InNetMessagePool.java index 07965d0afc..38708d47d9 100644 --- a/router/java/src/net/i2p/router/InNetMessagePool.java +++ b/router/java/src/net/i2p/router/InNetMessagePool.java @@ -60,6 +60,13 @@ public class InNetMessagePool { I2NPMessage messageBody = msg.getMessage(); msg.processingComplete(); Date exp = messageBody.getMessageExpiration(); + + if (_log.shouldLog(Log.INFO)) + _log.info("Received inbound " + + " with id " + messageBody.getUniqueId() + + " expiring on " + exp + + " of type " + messageBody.getClass().getName()); + boolean valid = _context.messageValidator().validateMessage(messageBody.getUniqueId(), exp.getTime()); if (!valid) { if (_log.shouldLog(Log.WARN)) diff --git a/router/java/src/net/i2p/router/OutNetMessagePool.java b/router/java/src/net/i2p/router/OutNetMessagePool.java index dd1efb5d03..389c0636fa 100644 --- a/router/java/src/net/i2p/router/OutNetMessagePool.java +++ b/router/java/src/net/i2p/router/OutNetMessagePool.java @@ -41,6 +41,13 @@ public class OutNetMessagePool { * */ public void add(OutNetMessage msg) { + if (_log.shouldLog(Log.INFO)) + _log.info("Adding outbound message to " + + msg.getTarget().getIdentity().getHash().toBase64().substring(0,6) + + " with id " + msg.getMessage().getUniqueId() + + " expiring on " + msg.getMessage().getMessageExpiration() + + " of type " + msg.getMessageType()); + boolean valid = validate(msg); if (!valid) return; MessageSelector selector = msg.getReplySelector(); diff --git a/router/java/src/net/i2p/router/message/HandleTunnelMessageJob.java b/router/java/src/net/i2p/router/message/HandleTunnelMessageJob.java index 4de8c4930b..0877f9ec24 100644 --- a/router/java/src/net/i2p/router/message/HandleTunnelMessageJob.java +++ b/router/java/src/net/i2p/router/message/HandleTunnelMessageJob.java @@ -415,7 +415,7 @@ public class HandleTunnelMessageJob extends JobImpl { byte iv[] = new byte[16]; Hash h = getContext().sha().calculateHash(key.getData()); System.arraycopy(h.getData(), 0, iv, 0, iv.length); - byte decrypted[] = getContext().AESEngine().safeDecrypt(encryptedMessage, key, iv); + byte decrypted[] = getContext().aes().safeDecrypt(encryptedMessage, key, iv); if (decrypted == null) { if (_log.shouldLog(Log.ERROR)) _log.error("Error decrypting the message", getAddedBy()); @@ -429,7 +429,7 @@ public class HandleTunnelMessageJob extends JobImpl { byte iv[] = new byte[16]; Hash h = getContext().sha().calculateHash(key.getData()); System.arraycopy(h.getData(), 0, iv, 0, iv.length); - byte decrypted[] = getContext().AESEngine().safeDecrypt(encryptedInstructions, key, iv); + byte decrypted[] = getContext().aes().safeDecrypt(encryptedInstructions, key, iv); if (decrypted == null) { if (_log.shouldLog(Log.ERROR)) _log.error("Error decrypting the instructions", getAddedBy()); diff --git a/router/java/src/net/i2p/router/message/SendTunnelMessageJob.java b/router/java/src/net/i2p/router/message/SendTunnelMessageJob.java index 16fbcf6941..5490448856 100644 --- a/router/java/src/net/i2p/router/message/SendTunnelMessageJob.java +++ b/router/java/src/net/i2p/router/message/SendTunnelMessageJob.java @@ -396,7 +396,7 @@ public class SendTunnelMessageJob extends JobImpl { byte iv[] = new byte[16]; Hash h = getContext().sha().calculateHash(key.getData()); System.arraycopy(h.getData(), 0, iv, 0, iv.length); - return getContext().AESEngine().safeEncrypt(baos.toByteArray(), key, iv, paddedSize); + return getContext().aes().safeEncrypt(baos.toByteArray(), key, iv, paddedSize); } catch (IOException ioe) { if (_log.shouldLog(Log.ERROR)) _log.error("Error writing out data to encrypt", ioe); diff --git a/router/java/src/net/i2p/router/transport/tcp/ConnectionBuilder.java b/router/java/src/net/i2p/router/transport/tcp/ConnectionBuilder.java index d65c8fa5a0..dde09f2c23 100644 --- a/router/java/src/net/i2p/router/transport/tcp/ConnectionBuilder.java +++ b/router/java/src/net/i2p/router/transport/tcp/ConnectionBuilder.java @@ -307,8 +307,8 @@ public class ConnectionBuilder { byte pre[] = new byte[48]; System.arraycopy(_nonce.getData(), 0, pre, 0, 4); System.arraycopy(_connectionTag.getData(), 0, pre, 4, 32); - byte encr[] = _context.AESEngine().encrypt(pre, _key, _iv); - Hash h = _context.sha().calculateHash(encr); + _context.aes().encrypt(pre, 0, pre, 0, _key, _iv, pre.length); + Hash h = _context.sha().calculateHash(pre); _nextConnectionTag = new ByteArray(h.getData()); } @@ -638,7 +638,9 @@ public class ConnectionBuilder { private void establishComplete() { _connectionIn = new BandwidthLimitedInputStream(_context, _rawIn, _actualPeer.getIdentity()); OutputStream blos = new BandwidthLimitedOutputStream(_context, _rawOut, _actualPeer.getIdentity()); - _connectionOut = blos; + _connectionOut = blos; + //_connectionIn = _rawIn; + //_connectionOut = _rawOut; Hash peer = _actualPeer.getIdentity().getHash(); _context.netDb().store(peer, _actualPeer); diff --git a/router/java/src/net/i2p/router/transport/tcp/ConnectionHandler.java b/router/java/src/net/i2p/router/transport/tcp/ConnectionHandler.java index 8b35003377..e025198ae6 100644 --- a/router/java/src/net/i2p/router/transport/tcp/ConnectionHandler.java +++ b/router/java/src/net/i2p/router/transport/tcp/ConnectionHandler.java @@ -328,8 +328,8 @@ public class ConnectionHandler { byte pre[] = new byte[48]; System.arraycopy(_nonce.getData(), 0, pre, 0, 4); System.arraycopy(_connectionTag.getData(), 0, pre, 4, 32); - byte encr[] = _context.AESEngine().encrypt(pre, _key, _iv); - Hash h = _context.sha().calculateHash(encr); + _context.aes().encrypt(pre, 0, pre, 0, _key, _iv, pre.length); + Hash h = _context.sha().calculateHash(pre); _nextConnectionTag = new ByteArray(h.getData()); } @@ -804,6 +804,8 @@ public class ConnectionHandler { _connectionIn = new BandwidthLimitedInputStream(_context, _rawIn, _actualPeer.getIdentity()); OutputStream blos = new BandwidthLimitedOutputStream(_context, _rawOut, _actualPeer.getIdentity()); _connectionOut = blos; + //_connectionIn = _rawIn; + //_connectionOut = _rawOut; Hash peer = _actualPeer.getIdentity().getHash(); _context.netDb().store(peer, _actualPeer); diff --git a/router/java/src/net/i2p/router/transport/tcp/ConnectionRunner.java b/router/java/src/net/i2p/router/transport/tcp/ConnectionRunner.java index b60f3017e9..82b3cddb2b 100644 --- a/router/java/src/net/i2p/router/transport/tcp/ConnectionRunner.java +++ b/router/java/src/net/i2p/router/transport/tcp/ConnectionRunner.java @@ -74,6 +74,11 @@ class ConnectionRunner implements Runnable { out.flush(); after = _context.clock().now(); } + if (_log.shouldLog(Log.DEBUG)) + _log.debug("Just sent message " + msg.getMessageId() + " to " + + msg.getTarget().getIdentity().getHash().toBase64().substring(0,6) + + " writeTime = " + (after-before) +"ms" + + " lifetime = " + msg.getLifetime() + "ms"); ok = true; } catch (IOException ioe) { diff --git a/router/java/src/net/i2p/router/transport/tcp/MessageHandler.java b/router/java/src/net/i2p/router/transport/tcp/MessageHandler.java index d0bdeef221..f1ffd8d1f6 100644 --- a/router/java/src/net/i2p/router/transport/tcp/MessageHandler.java +++ b/router/java/src/net/i2p/router/transport/tcp/MessageHandler.java @@ -4,12 +4,14 @@ import net.i2p.data.Hash; import net.i2p.data.RouterIdentity; import net.i2p.data.i2np.I2NPMessageReader; import net.i2p.data.i2np.I2NPMessage; +import net.i2p.util.Log; /** * Receive messages from a message reader and bounce them off to the transport * for further enqueueing. */ public class MessageHandler implements I2NPMessageReader.I2NPMessageEventListener { + private Log _log; private TCPTransport _transport; private TCPConnection _con; private RouterIdentity _ident; @@ -20,6 +22,7 @@ public class MessageHandler implements I2NPMessageReader.I2NPMessageEventListene _con = con; _ident = con.getRemoteRouterIdentity(); _identHash = _ident.calculateHash(); + _log = con.getRouterContext().logManager().getLog(MessageHandler.class); } public void disconnected(I2NPMessageReader reader) { @@ -27,6 +30,10 @@ public class MessageHandler implements I2NPMessageReader.I2NPMessageEventListene } public void messageReceived(I2NPMessageReader reader, I2NPMessage message, long msToRead) { + if (_log.shouldLog(Log.DEBUG)) + _log.debug("Just received message " + message.getUniqueId() + " from " + + _identHash.toBase64().substring(0,6) + + " readTime = " + msToRead + "ms type = " + message.getClass().getName()); _transport.messageReceived(message, _ident, _identHash, msToRead, message.getSize()); } diff --git a/router/java/src/net/i2p/router/transport/tcp/TCPConnection.java b/router/java/src/net/i2p/router/transport/tcp/TCPConnection.java index a5ef912c34..e8a81d504b 100644 --- a/router/java/src/net/i2p/router/transport/tcp/TCPConnection.java +++ b/router/java/src/net/i2p/router/transport/tcp/TCPConnection.java @@ -202,6 +202,7 @@ public class TCPConnection { /** Have we been closed already? */ boolean getIsClosed() { return _closed; } + RouterContext getRouterContext() { return _context; } /** * The message was sent. -- GitLab