From eee21aa3015872a783ebb37633f94e0756fba82c Mon Sep 17 00:00:00 2001 From: jrandom Date: Sun, 26 Feb 2006 21:30:56 +0000 Subject: [PATCH] 2006-02-26 jrandom * Switch from the bouncycastle to the gnu-crypto implementation for SHA256, as benchmarks show a 10-30% speedup. * Removed some unnecessary object caches * Don't close i2psnark streams prematurely --- .../src/org/klomp/snark/I2PSnarkUtil.java | 6 +- core/java/src/gnu/crypto/hash/BaseHash.java | 198 ++++++++++++ .../src/gnu/crypto/hash/IMessageDigest.java | 141 +++++++++ .../src/gnu/crypto/hash/Sha256Standalone.java | 262 ++++++++++++++++ .../gnu/crypto/prng/FortunaStandalone.java | 26 +- core/java/src/net/i2p/I2PAppContext.java | 12 +- .../i2p/crypto/DummyHMACSHA256Generator.java | 52 ---- ...HA256Generator.java => HMACGenerator.java} | 51 +-- .../src/net/i2p/crypto/SHA256Generator.java | 49 ++- .../crypto/digests/SHA256Digest.java | 292 ------------------ history.txt | 8 +- .../src/net/i2p/router/RouterVersion.java | 4 +- .../i2p/router/transport/udp/UDPPacket.java | 53 ++-- .../router/transport/udp/UDPTransport.java | 2 + 14 files changed, 677 insertions(+), 479 deletions(-) create mode 100644 core/java/src/gnu/crypto/hash/BaseHash.java create mode 100644 core/java/src/gnu/crypto/hash/IMessageDigest.java create mode 100644 core/java/src/gnu/crypto/hash/Sha256Standalone.java delete mode 100644 core/java/src/net/i2p/crypto/DummyHMACSHA256Generator.java rename core/java/src/net/i2p/crypto/{HMACSHA256Generator.java => HMACGenerator.java} (69%) delete mode 100644 core/java/src/org/bouncycastle/crypto/digests/SHA256Digest.java diff --git a/apps/i2psnark/java/src/org/klomp/snark/I2PSnarkUtil.java b/apps/i2psnark/java/src/org/klomp/snark/I2PSnarkUtil.java index 142c60c8f..02f63c10e 100644 --- a/apps/i2psnark/java/src/org/klomp/snark/I2PSnarkUtil.java +++ b/apps/i2psnark/java/src/org/klomp/snark/I2PSnarkUtil.java @@ -93,9 +93,9 @@ public class I2PSnarkUtil { if (opts.getProperty("i2p.streaming.inactivityTimeout") == null) opts.setProperty("i2p.streaming.inactivityTimeout", "90000"); if (opts.getProperty("i2p.streaming.inactivityAction") == null) - opts.setProperty("i2p.streaming.inactivityAction", "1"); - if (opts.getProperty("i2p.streaming.writeTimeout") == null) - opts.setProperty("i2p.streaming.writeTimeout", "90000"); + opts.setProperty("i2p.streaming.inactivityAction", "2"); // 1 == disconnect, 2 == ping + //if (opts.getProperty("i2p.streaming.writeTimeout") == null) + // opts.setProperty("i2p.streaming.writeTimeout", "90000"); //if (opts.getProperty("i2p.streaming.readTimeout") == null) // opts.setProperty("i2p.streaming.readTimeout", "120000"); _manager = I2PSocketManagerFactory.createManager(_i2cpHost, _i2cpPort, opts); diff --git a/core/java/src/gnu/crypto/hash/BaseHash.java b/core/java/src/gnu/crypto/hash/BaseHash.java new file mode 100644 index 000000000..217b0ab44 --- /dev/null +++ b/core/java/src/gnu/crypto/hash/BaseHash.java @@ -0,0 +1,198 @@ +package gnu.crypto.hash; + +// ---------------------------------------------------------------------------- +// $Id: BaseHash.java,v 1.10 2005/10/06 04:24:14 rsdio Exp $ +// +// Copyright (C) 2001, 2002, Free Software Foundation, Inc. +// +// This file is part of GNU Crypto. +// +// GNU Crypto is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2, or (at your option) +// any later version. +// +// GNU Crypto is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; see the file COPYING. If not, write to the +// +// Free Software Foundation Inc., +// 51 Franklin Street, Fifth Floor, +// Boston, MA 02110-1301 +// USA +// +// Linking this library statically or dynamically with other modules is +// making a combined work based on this library. Thus, the terms and +// conditions of the GNU General Public License cover the whole +// combination. +// +// As a special exception, the copyright holders of this library give +// you permission to link this library with independent modules to +// produce an executable, regardless of the license terms of these +// independent modules, and to copy and distribute the resulting +// executable under terms of your choice, provided that you also meet, +// for each linked independent module, the terms and conditions of the +// license of that module. An independent module is a module which is +// not derived from or based on this library. If you modify this +// library, you may extend this exception to your version of the +// library, but you are not obligated to do so. If you do not wish to +// do so, delete this exception statement from your version. +// ---------------------------------------------------------------------------- + +/** + *

A base abstract class to facilitate hash implementations.

+ * + * @version $Revision: 1.10 $ + */ +public abstract class BaseHash implements IMessageDigest { + + // Constants and variables + // ------------------------------------------------------------------------- + + /** The canonical name prefix of the hash. */ + protected String name; + + /** The hash (output) size in bytes. */ + protected int hashSize; + + /** The hash (inner) block size in bytes. */ + protected int blockSize; + + /** Number of bytes processed so far. */ + protected long count; + + /** Temporary input buffer. */ + protected byte[] buffer; + + // Constructor(s) + // ------------------------------------------------------------------------- + + /** + *

Trivial constructor for use by concrete subclasses.

+ * + * @param name the canonical name prefix of this instance. + * @param hashSize the block size of the output in bytes. + * @param blockSize the block size of the internal transform. + */ + protected BaseHash(String name, int hashSize, int blockSize) { + super(); + + this.name = name; + this.hashSize = hashSize; + this.blockSize = blockSize; + this.buffer = new byte[blockSize]; + + resetContext(); + } + + // Class methods + // ------------------------------------------------------------------------- + + // Instance methods + // ------------------------------------------------------------------------- + + // IMessageDigest interface implementation --------------------------------- + + public String name() { + return name; + } + + public int hashSize() { + return hashSize; + } + + public int blockSize() { + return blockSize; + } + + public void update(byte b) { + // compute number of bytes still unhashed; ie. present in buffer + int i = (int)(count % blockSize); + count++; + buffer[i] = b; + if (i == (blockSize - 1)) { + transform(buffer, 0); + } + } + + public void update(byte[] b) { + update(b, 0, b.length); + } + + public void update(byte[] b, int offset, int len) { + int n = (int)(count % blockSize); + count += len; + int partLen = blockSize - n; + int i = 0; + + if (len >= partLen) { + System.arraycopy(b, offset, buffer, n, partLen); + transform(buffer, 0); + for (i = partLen; i + blockSize - 1 < len; i+= blockSize) { + transform(b, offset + i); + } + n = 0; + } + + if (i < len) { + System.arraycopy(b, offset + i, buffer, n, len - i); + } + } + + public byte[] digest() { + byte[] tail = padBuffer(); // pad remaining bytes in buffer + update(tail, 0, tail.length); // last transform of a message + byte[] result = getResult(); // make a result out of context + + reset(); // reset this instance for future re-use + + return result; + } + + public void reset() { // reset this instance for future re-use + count = 0L; + for (int i = 0; i < blockSize; ) { + buffer[i++] = 0; + } + + resetContext(); + } + + // methods to be implemented by concrete subclasses ------------------------ + + public abstract Object clone(); + + public abstract boolean selfTest(); + + /** + *

Returns the byte array to use as padding before completing a hash + * operation.

+ * + * @return the bytes to pad the remaining bytes in the buffer before + * completing a hash operation. + */ + protected abstract byte[] padBuffer(); + + /** + *

Constructs the result from the contents of the current context.

+ * + * @return the output of the completed hash operation. + */ + protected abstract byte[] getResult(); + + /** Resets the instance for future re-use. */ + protected abstract void resetContext(); + + /** + *

The block digest transformation per se.

+ * + * @param in the blockSize long block, as an array of bytes to digest. + * @param offset the index where the data to digest is located within the + * input buffer. + */ + protected abstract void transform(byte[] in, int offset); +} diff --git a/core/java/src/gnu/crypto/hash/IMessageDigest.java b/core/java/src/gnu/crypto/hash/IMessageDigest.java new file mode 100644 index 000000000..1b078485e --- /dev/null +++ b/core/java/src/gnu/crypto/hash/IMessageDigest.java @@ -0,0 +1,141 @@ +package gnu.crypto.hash; + +// ---------------------------------------------------------------------------- +// $Id: IMessageDigest.java,v 1.11 2005/10/06 04:24:14 rsdio Exp $ +// +// Copyright (C) 2001, 2002, Free Software Foundation, Inc. +// +// This file is part of GNU Crypto. +// +// GNU Crypto is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2, or (at your option) +// any later version. +// +// GNU Crypto is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; see the file COPYING. If not, write to the +// +// Free Software Foundation Inc., +// 51 Franklin Street, Fifth Floor, +// Boston, MA 02110-1301 +// USA +// +// Linking this library statically or dynamically with other modules is +// making a combined work based on this library. Thus, the terms and +// conditions of the GNU General Public License cover the whole +// combination. +// +// As a special exception, the copyright holders of this library give +// you permission to link this library with independent modules to +// produce an executable, regardless of the license terms of these +// independent modules, and to copy and distribute the resulting +// executable under terms of your choice, provided that you also meet, +// for each linked independent module, the terms and conditions of the +// license of that module. An independent module is a module which is +// not derived from or based on this library. If you modify this +// library, you may extend this exception to your version of the +// library, but you are not obligated to do so. If you do not wish to +// do so, delete this exception statement from your version. +// ---------------------------------------------------------------------------- + +/** + *

The basic visible methods of any hash algorithm.

+ * + *

A hash (or message digest) algorithm produces its output by iterating a + * basic compression function on blocks of data.

+ * + * @version $Revision: 1.11 $ + */ +public interface IMessageDigest extends Cloneable { + + // Constants + // ------------------------------------------------------------------------- + + // Methods + // ------------------------------------------------------------------------- + + /** + *

Returns the canonical name of this algorithm.

+ * + * @return the canonical name of this instance. + */ + String name(); + + /** + *

Returns the output length in bytes of this message digest algorithm.

+ * + * @return the output length in bytes of this message digest algorithm. + */ + int hashSize(); + + /** + *

Returns the algorithm's (inner) block size in bytes.

+ * + * @return the algorithm's inner block size in bytes. + */ + int blockSize(); + + /** + *

Continues a message digest operation using the input byte.

+ * + * @param b the input byte to digest. + */ + void update(byte b); + + /** + *

Continues a message digest operation, by filling the buffer, processing + * data in the algorithm's HASH_SIZE-bit block(s), updating the context and + * count, and buffering the remaining bytes in buffer for the next + * operation.

+ * + * @param in the input block. + */ + void update(byte[] in); + + /** + *

Continues a message digest operation, by filling the buffer, processing + * data in the algorithm's HASH_SIZE-bit block(s), updating the context and + * count, and buffering the remaining bytes in buffer for the next + * operation.

+ * + * @param in the input block. + * @param offset start of meaningful bytes in input block. + * @param length number of bytes, in input block, to consider. + */ + void update(byte[] in, int offset, int length); + + /** + *

Completes the message digest by performing final operations such as + * padding and resetting the instance.

+ * + * @return the array of bytes representing the hash value. + */ + byte[] digest(); + + /** + *

Resets the current context of this instance clearing any eventually cached + * intermediary values.

+ */ + void reset(); + + /** + *

A basic test. Ensures that the digest of a pre-determined message is equal + * to a known pre-computed value.

+ * + * @return true if the implementation passes a basic self-test. + * Returns false otherwise. + */ + boolean selfTest(); + + /** + *

Returns a clone copy of this instance.

+ * + * @return a clone copy of this instance. + */ + Object clone(); +} diff --git a/core/java/src/gnu/crypto/hash/Sha256Standalone.java b/core/java/src/gnu/crypto/hash/Sha256Standalone.java new file mode 100644 index 000000000..b10df43a5 --- /dev/null +++ b/core/java/src/gnu/crypto/hash/Sha256Standalone.java @@ -0,0 +1,262 @@ +package gnu.crypto.hash; + +// ---------------------------------------------------------------------------- +// $Id: Sha256.java,v 1.2 2005/10/06 04:24:14 rsdio Exp $ +// +// Copyright (C) 2003 Free Software Foundation, Inc. +// +// This file is part of GNU Crypto. +// +// GNU Crypto is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2, or (at your option) +// any later version. +// +// GNU Crypto is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; see the file COPYING. If not, write to the +// +// Free Software Foundation Inc., +// 51 Franklin Street, Fifth Floor, +// Boston, MA 02110-1301 +// USA +// +// Linking this library statically or dynamically with other modules is +// making a combined work based on this library. Thus, the terms and +// conditions of the GNU General Public License cover the whole +// combination. +// +// As a special exception, the copyright holders of this library give +// you permission to link this library with independent modules to +// produce an executable, regardless of the license terms of these +// independent modules, and to copy and distribute the resulting +// executable under terms of your choice, provided that you also meet, +// for each linked independent module, the terms and conditions of the +// license of that module. An independent module is a module which is +// not derived from or based on this library. If you modify this +// library, you may extend this exception to your version of the +// library, but you are not obligated to do so. If you do not wish to +// do so, delete this exception statement from your version. +// ---------------------------------------------------------------------------- + +//import gnu.crypto.util.Util; + +/** + *

Implementation of SHA2-1 [SHA-256] per the IETF Draft Specification.

+ * + *

References:

+ *
    + *
  1. + * Descriptions of SHA-256, SHA-384, and SHA-512,
  2. + *
  3. http://csrc.nist.gov/cryptval/shs/sha256-384-512.pdf
  4. + *
+ * + * Modified by jrandom@i2p.net to remove unnecessary gnu-crypto dependencies, and + * renamed from Sha256 to avoid conflicts with JVMs using gnu-crypto as their JCE + * provider. + * + * @version $Revision: 1.2 $ + */ +public class Sha256Standalone extends BaseHash { + // Constants and variables + // ------------------------------------------------------------------------- + private static final int[] k = { + 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, + 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5, + 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, + 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174, + 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, + 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da, + 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, + 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967, + 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, + 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85, + 0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, + 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070, + 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, + 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3, + 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, + 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2 + }; + + private static final int BLOCK_SIZE = 64; // inner block size in bytes + + private static final String DIGEST0 = + "BA7816BF8F01CFEA414140DE5DAE2223B00361A396177A9CB410FF61F20015AD"; + + private static final int[] w = new int[64]; + + /** caches the result of the correctness test, once executed. */ + private static Boolean valid; + + /** 256-bit interim result. */ + private int h0, h1, h2, h3, h4, h5, h6, h7; + + // Constructor(s) + // ------------------------------------------------------------------------- + + /** Trivial 0-arguments constructor. */ + public Sha256Standalone() { + super("sha256/standalone", 32, BLOCK_SIZE); + } + + /** + *

Private constructor for cloning purposes.

+ * + * @param md the instance to clone. + */ + private Sha256Standalone(Sha256Standalone md) { + this(); + + this.h0 = md.h0; + this.h1 = md.h1; + this.h2 = md.h2; + this.h3 = md.h3; + this.h4 = md.h4; + this.h5 = md.h5; + this.h6 = md.h6; + this.h7 = md.h7; + this.count = md.count; + this.buffer = (byte[]) md.buffer.clone(); + } + + // Class methods + // ------------------------------------------------------------------------- + + public static final int[] G(int hh0, int hh1, int hh2, int hh3, int hh4, + int hh5, int hh6, int hh7, byte[] in, int offset) { + return sha(hh0, hh1, hh2, hh3, hh4, hh5, hh6, hh7, in, offset); + } + + // Instance methods + // ------------------------------------------------------------------------- + + // java.lang.Cloneable interface implementation ---------------------------- + + public Object clone() { + return new Sha256Standalone(this); + } + + // Implementation of concrete methods in BaseHash -------------------------- + + protected void transform(byte[] in, int offset) { + int[] result = sha(h0, h1, h2, h3, h4, h5, h6, h7, in, offset); + + h0 = result[0]; + h1 = result[1]; + h2 = result[2]; + h3 = result[3]; + h4 = result[4]; + h5 = result[5]; + h6 = result[6]; + h7 = result[7]; + } + + protected byte[] padBuffer() { + int n = (int) (count % BLOCK_SIZE); + int padding = (n < 56) ? (56 - n) : (120 - n); + byte[] result = new byte[padding + 8]; + + // padding is always binary 1 followed by binary 0s + result[0] = (byte) 0x80; + + // save number of bits, casting the long to an array of 8 bytes + long bits = count << 3; + result[padding++] = (byte)(bits >>> 56); + result[padding++] = (byte)(bits >>> 48); + result[padding++] = (byte)(bits >>> 40); + result[padding++] = (byte)(bits >>> 32); + result[padding++] = (byte)(bits >>> 24); + result[padding++] = (byte)(bits >>> 16); + result[padding++] = (byte)(bits >>> 8); + result[padding ] = (byte) bits; + + return result; + } + + protected byte[] getResult() { + return new byte[] { + (byte)(h0 >>> 24), (byte)(h0 >>> 16), (byte)(h0 >>> 8), (byte) h0, + (byte)(h1 >>> 24), (byte)(h1 >>> 16), (byte)(h1 >>> 8), (byte) h1, + (byte)(h2 >>> 24), (byte)(h2 >>> 16), (byte)(h2 >>> 8), (byte) h2, + (byte)(h3 >>> 24), (byte)(h3 >>> 16), (byte)(h3 >>> 8), (byte) h3, + (byte)(h4 >>> 24), (byte)(h4 >>> 16), (byte)(h4 >>> 8), (byte) h4, + (byte)(h5 >>> 24), (byte)(h5 >>> 16), (byte)(h5 >>> 8), (byte) h5, + (byte)(h6 >>> 24), (byte)(h6 >>> 16), (byte)(h6 >>> 8), (byte) h6, + (byte)(h7 >>> 24), (byte)(h7 >>> 16), (byte)(h7 >>> 8), (byte) h7 + }; + } + + protected void resetContext() { + // magic SHA-256 initialisation constants + h0 = 0x6a09e667; + h1 = 0xbb67ae85; + h2 = 0x3c6ef372; + h3 = 0xa54ff53a; + h4 = 0x510e527f; + h5 = 0x9b05688c; + h6 = 0x1f83d9ab; + h7 = 0x5be0cd19; + } + + public boolean selfTest() { + if (valid == null) { + Sha256Standalone md = new Sha256Standalone(); + md.update((byte) 0x61); // a + md.update((byte) 0x62); // b + md.update((byte) 0x63); // c + String result = "broken"; //Util.toString(md.digest()); + valid = new Boolean(DIGEST0.equals(result)); + } + + return valid.booleanValue(); + } + + // SHA specific methods ---------------------------------------------------- + + private static final synchronized int[] + sha(int hh0, int hh1, int hh2, int hh3, int hh4, int hh5, int hh6, int hh7, byte[] in, int offset) { + int A = hh0; + int B = hh1; + int C = hh2; + int D = hh3; + int E = hh4; + int F = hh5; + int G = hh6; + int H = hh7; + int r, T, T2; + + for (r = 0; r < 16; r++) { + w[r] = in[offset++] << 24 | + (in[offset++] & 0xFF) << 16 | + (in[offset++] & 0xFF) << 8 | + (in[offset++] & 0xFF); + } + for (r = 16; r < 64; r++) { + T = w[r - 2]; + T2 = w[r - 15]; + w[r] = (((T >>> 17) | (T << 15)) ^ ((T >>> 19) | (T << 13)) ^ (T >>> 10)) + w[r - 7] + (((T2 >>> 7) | (T2 << 25)) ^ ((T2 >>> 18) | (T2 << 14)) ^ (T2 >>> 3)) + w[r - 16]; + } + + for (r = 0; r < 64; r++) { + T = H + (((E >>> 6) | (E << 26)) ^ ((E >>> 11) | (E << 21)) ^ ((E >>> 25) | (E << 7))) + ((E & F) ^ (~E & G)) + k[r] + w[r]; + T2 = (((A >>> 2) | (A << 30)) ^ ((A >>> 13) | (A << 19)) ^ ((A >>> 22) | (A << 10))) + ((A & B) ^ (A & C) ^ (B & C)); + H = G; + G = F; + F = E; + E = D + T; + D = C; + C = B; + B = A; + A = T + T2; + } + + return new int[] { + hh0 + A, hh1 + B, hh2 + C, hh3 + D, hh4 + E, hh5 + F, hh6 + G, hh7 + H + }; + } +} diff --git a/core/java/src/gnu/crypto/prng/FortunaStandalone.java b/core/java/src/gnu/crypto/prng/FortunaStandalone.java index 7de39436d..d6e267586 100644 --- a/core/java/src/gnu/crypto/prng/FortunaStandalone.java +++ b/core/java/src/gnu/crypto/prng/FortunaStandalone.java @@ -54,7 +54,7 @@ import java.util.Iterator; import java.util.Map; import java.util.HashMap; -import org.bouncycastle.crypto.digests.SHA256Digest; +import gnu.crypto.hash.Sha256Standalone; import net.i2p.crypto.CryptixRijndael_Algorithm; import net.i2p.crypto.CryptixAESKeyCache; @@ -91,7 +91,7 @@ import net.i2p.crypto.CryptixAESKeyCache; * Bruce Schneier). ISBN 0-471-22357-3. * * - * Modified by jrandom for I2P to use Bouncycastle's SHA256, Cryptix's AES, + * Modified by jrandom for I2P to use a standalone gnu-crypto SHA256, Cryptix's AES, * to strip out some unnecessary dependencies and increase the buffer size. * Renamed from Fortuna to FortunaStandalone so it doesn't conflict with the * gnu-crypto implementation, which has been imported into GNU/classpath @@ -106,7 +106,7 @@ public class FortunaStandalone extends BasePRNGStandalone implements Serializabl private static final int NUM_POOLS = 32; private static final int MIN_POOL_SIZE = 64; private final Generator generator; - private final SHA256Digest[] pools; + private final Sha256Standalone[] pools; private long lastReseed; private int pool; private int pool0Count; @@ -118,9 +118,9 @@ public class FortunaStandalone extends BasePRNGStandalone implements Serializabl { super("Fortuna i2p"); generator = new Generator(); - pools = new SHA256Digest[NUM_POOLS]; + pools = new Sha256Standalone[NUM_POOLS]; for (int i = 0; i < NUM_POOLS; i++) - pools[i] = new SHA256Digest(); + pools[i] = new Sha256Standalone(); lastReseed = 0; pool = 0; pool0Count = 0; @@ -143,8 +143,6 @@ public class FortunaStandalone extends BasePRNGStandalone implements Serializabl generator.init(attributes); } - /** fillBlock is not thread safe, so will be locked anyway */ - private byte fillBlockBuf[] = new byte[32]; public void fillBlock() { if (pool0Count >= MIN_POOL_SIZE @@ -155,9 +153,7 @@ public class FortunaStandalone extends BasePRNGStandalone implements Serializabl for (int i = 0; i < NUM_POOLS; i++) { if (reseedCount % (1 << i) == 0) { - byte buf[] = fillBlockBuf;//new byte[32]; - pools[i].doFinal(buf, 0); - generator.addRandomBytes(buf);//pools[i].digest()); + generator.addRandomBytes(pools[i].digest()); } } lastReseed = System.currentTimeMillis(); @@ -221,7 +217,7 @@ public class FortunaStandalone extends BasePRNGStandalone implements Serializabl private static final int LIMIT = 1 << 20; - private final SHA256Digest hash; + private final Sha256Standalone hash; private final byte[] counter; private final byte[] key; /** current encryption key built from the keying material */ @@ -232,7 +228,7 @@ public class FortunaStandalone extends BasePRNGStandalone implements Serializabl public Generator () { super("Fortuna.generator.i2p"); - this.hash = new SHA256Digest(); + this.hash = new Sha256Standalone(); counter = new byte[16]; //cipher.defaultBlockSize()]; buffer = new byte[16]; //cipher.defaultBlockSize()]; int keysize = 32; @@ -285,9 +281,9 @@ public class FortunaStandalone extends BasePRNGStandalone implements Serializabl { hash.update(key, 0, key.length); hash.update(seed, offset, length); - //byte[] newkey = hash.digest(); - //System.arraycopy(newkey, 0, key, 0, Math.min(key.length, newkey.length)); - hash.doFinal(key, 0); + byte[] newkey = hash.digest(); + System.arraycopy(newkey, 0, key, 0, Math.min(key.length, newkey.length)); + //hash.doFinal(key, 0); resetKey(); incrementCounter(); seeded = true; diff --git a/core/java/src/net/i2p/I2PAppContext.java b/core/java/src/net/i2p/I2PAppContext.java index 437d0c0d2..077326c6a 100644 --- a/core/java/src/net/i2p/I2PAppContext.java +++ b/core/java/src/net/i2p/I2PAppContext.java @@ -11,11 +11,10 @@ import net.i2p.crypto.CryptixAESEngine; import net.i2p.crypto.DSAEngine; import net.i2p.crypto.DummyDSAEngine; import net.i2p.crypto.DummyElGamalEngine; -import net.i2p.crypto.DummyHMACSHA256Generator; import net.i2p.crypto.DummyPooledRandomSource; import net.i2p.crypto.ElGamalAESEngine; import net.i2p.crypto.ElGamalEngine; -import net.i2p.crypto.HMACSHA256Generator; +import net.i2p.crypto.HMACGenerator; import net.i2p.crypto.KeyGenerator; import net.i2p.crypto.PersistentSessionKeyManager; import net.i2p.crypto.SHA256Generator; @@ -67,7 +66,7 @@ public class I2PAppContext { private ElGamalAESEngine _elGamalAESEngine; private AESEngine _AESEngine; private LogManager _logManager; - private HMACSHA256Generator _hmac; + private HMACGenerator _hmac; private SHA256Generator _sha; private Clock _clock; private DSAEngine _dsa; @@ -342,17 +341,14 @@ public class I2PAppContext { * other than for consistency, and perhaps later we'll want to * include some stats. */ - public HMACSHA256Generator hmac() { + public HMACGenerator hmac() { if (!_hmacInitialized) initializeHMAC(); return _hmac; } private void initializeHMAC() { synchronized (this) { if (_hmac == null) { - if ("true".equals(getProperty("i2p.fakeHMAC", "false"))) - _hmac = new DummyHMACSHA256Generator(this); - else - _hmac= new HMACSHA256Generator(this); + _hmac= new HMACGenerator(this); } _hmacInitialized = true; } diff --git a/core/java/src/net/i2p/crypto/DummyHMACSHA256Generator.java b/core/java/src/net/i2p/crypto/DummyHMACSHA256Generator.java deleted file mode 100644 index ec6bba514..000000000 --- a/core/java/src/net/i2p/crypto/DummyHMACSHA256Generator.java +++ /dev/null @@ -1,52 +0,0 @@ -package net.i2p.crypto; - -import java.util.Arrays; -import java.util.ArrayList; -import java.util.List; -import net.i2p.I2PAppContext; -import net.i2p.data.DataHelper; -import net.i2p.data.Hash; -import net.i2p.data.SessionKey; - -/** - * Calculate the HMAC-SHA256 of a key+message. All the good stuff occurs - * in {@link org.bouncycastle.crypto.macs.HMac} and - * {@link org.bouncycastle.crypto.digests.SHA256Digest}. - * - */ -public class DummyHMACSHA256Generator extends HMACSHA256Generator { - private I2PAppContext _context; - public DummyHMACSHA256Generator(I2PAppContext context) { - super(context); - _context = context; - } - - public static HMACSHA256Generator getInstance() { - return I2PAppContext.getGlobalContext().hmac(); - } - - /** - * Calculate the HMAC of the data with the given key - */ - public Hash calculate(SessionKey key, byte data[]) { - if ((key == null) || (key.getData() == null) || (data == null)) - throw new NullPointerException("Null arguments for HMAC"); - return calculate(key, data, 0, data.length); - } - - /** - * Calculate the HMAC of the data with the given key - */ - public Hash calculate(SessionKey key, byte data[], int offset, int length) { - if ((key == null) || (key.getData() == null) || (data == null)) - throw new NullPointerException("Null arguments for HMAC"); - - byte rv[] = new byte[Hash.HASH_LENGTH]; - System.arraycopy(key.getData(), 0, rv, 0, Hash.HASH_LENGTH); - if (Hash.HASH_LENGTH >= length) - DataHelper.xor(data, offset, rv, 0, rv, 0, length); - else - DataHelper.xor(data, offset, rv, 0, rv, 0, Hash.HASH_LENGTH); - return new Hash(rv); - } -} \ No newline at end of file diff --git a/core/java/src/net/i2p/crypto/HMACSHA256Generator.java b/core/java/src/net/i2p/crypto/HMACGenerator.java similarity index 69% rename from core/java/src/net/i2p/crypto/HMACSHA256Generator.java rename to core/java/src/net/i2p/crypto/HMACGenerator.java index 86bb80f9e..b369bb324 100644 --- a/core/java/src/net/i2p/crypto/HMACSHA256Generator.java +++ b/core/java/src/net/i2p/crypto/HMACGenerator.java @@ -8,46 +8,26 @@ import net.i2p.data.DataHelper; import net.i2p.data.Hash; import net.i2p.data.SessionKey; -import org.bouncycastle.crypto.digests.SHA256Digest; import org.bouncycastle.crypto.digests.MD5Digest; import org.bouncycastle.crypto.macs.HMac; /** - * Calculate the HMAC-SHA256 of a key+message. All the good stuff occurs + * Calculate the HMAC-MD5 of a key+message. All the good stuff occurs * in {@link org.bouncycastle.crypto.macs.HMac} and - * {@link org.bouncycastle.crypto.digests.SHA256Digest}. Alternately, if - * the context property "i2p.HMACMD5" is set to true, then this whole HMAC - * generator will be transformed into HMACMD5, maintaining the same size and - * using {@link org.bouncycastle.crypto.digests.MD5Digest}. + * {@link org.bouncycastle.crypto.digests.MD5Digest}. * */ -public class HMACSHA256Generator { +public class HMACGenerator { private I2PAppContext _context; /** set of available HMAC instances for calculate */ private List _available; /** set of available byte[] buffers for verify */ private List _availableTmp; - private boolean _useMD5; - private int _macSize; - public static final boolean DEFAULT_USE_MD5 = true; - - public HMACSHA256Generator(I2PAppContext context) { + public HMACGenerator(I2PAppContext context) { _context = context; _available = new ArrayList(32); _availableTmp = new ArrayList(32); - if ("true".equals(context.getProperty("i2p.HMACMD5", Boolean.toString(DEFAULT_USE_MD5).toLowerCase()))) - _useMD5 = true; - else - _useMD5 = false; - if ("true".equals(context.getProperty("i2p.HMACBrokenSize", "false"))) - _macSize = 32; - else - _macSize = (_useMD5 ? 16 : 32); - } - - public static HMACSHA256Generator getInstance() { - return I2PAppContext.getGlobalContext().hmac(); } /** @@ -61,24 +41,6 @@ public class HMACSHA256Generator { return new Hash(rv); } - /** - * Calculate the HMAC of the data with the given key - */ - /* - public Hash calculate(SessionKey key, byte data[], int offset, int length) { - if ((key == null) || (key.getData() == null) || (data == null)) - throw new NullPointerException("Null arguments for HMAC"); - - HMac mac = acquire(); - mac.init(key.getData()); - mac.update(data, offset, length); - byte rv[] = new byte[Hash.HASH_LENGTH]; - mac.doFinal(rv, 0); - release(mac); - return new Hash(rv); - } - */ - /** * Calculate the HMAC of the data with the given key */ @@ -131,10 +93,7 @@ public class HMACSHA256Generator { // the HMAC is hardcoded to use SHA256 digest size // for backwards compatability. next time we have a backwards // incompatible change, we should update this by removing ", 32" - if (_useMD5) - return new HMac(new MD5Digest(), 32); - else - return new HMac(new SHA256Digest(), 32); + return new HMac(new MD5Digest(), 32); } private void release(HMac mac) { synchronized (_available) { diff --git a/core/java/src/net/i2p/crypto/SHA256Generator.java b/core/java/src/net/i2p/crypto/SHA256Generator.java index acffc7569..96d533a1d 100644 --- a/core/java/src/net/i2p/crypto/SHA256Generator.java +++ b/core/java/src/net/i2p/crypto/SHA256Generator.java @@ -7,17 +7,19 @@ import net.i2p.I2PAppContext; import net.i2p.data.Base64; import net.i2p.data.Hash; -import org.bouncycastle.crypto.digests.SHA256Digest; +import gnu.crypto.hash.Sha256Standalone; /** * Defines a wrapper for SHA-256 operation. All the good stuff occurs - * in the Bouncycastle {@link org.bouncycastle.crypto.digests.SHA256Digest} + * in the GNU-Crypto {@link gnu.crypto.hash.Sha256Standalone} * */ public final class SHA256Generator { private List _digests; + private List _digestsGnu; public SHA256Generator(I2PAppContext context) { _digests = new ArrayList(32); + _digestsGnu = new ArrayList(32); } public static final SHA256Generator getInstance() { @@ -32,47 +34,44 @@ public final class SHA256Generator { return calculateHash(source, 0, source.length); } public final Hash calculateHash(byte[] source, int start, int len) { - byte rv[] = new byte[Hash.HASH_LENGTH]; - calculateHash(source, start, len, rv, 0); + Sha256Standalone digest = acquireGnu(); + digest.update(source, start, len); + byte rv[] = digest.digest(); + releaseGnu(digest); return new Hash(rv); } + public final void calculateHash(byte[] source, int start, int len, byte out[], int outOffset) { - SHA256Digest digest = acquire(); + Sha256Standalone digest = acquireGnu(); digest.update(source, start, len); - digest.doFinal(out, outOffset); - release(digest); + byte rv[] = digest.digest(); + releaseGnu(digest); + System.arraycopy(rv, 0, out, outOffset, rv.length); } - private SHA256Digest acquire() { - SHA256Digest rv = null; - synchronized (_digests) { - if (_digests.size() > 0) - rv = (SHA256Digest)_digests.remove(0); + private Sha256Standalone acquireGnu() { + Sha256Standalone rv = null; + synchronized (_digestsGnu) { + if (_digestsGnu.size() > 0) + rv = (Sha256Standalone)_digestsGnu.remove(0); } if (rv != null) rv.reset(); else - rv = new SHA256Digest(); + rv = new Sha256Standalone(); return rv; } - private void release(SHA256Digest digest) { - synchronized (_digests) { - if (_digests.size() < 32) { - _digests.add(digest); + + private void releaseGnu(Sha256Standalone digest) { + synchronized (_digestsGnu) { + if (_digestsGnu.size() < 32) { + _digestsGnu.add(digest); } } } public static void main(String args[]) { I2PAppContext ctx = I2PAppContext.getGlobalContext(); - byte orig[] = new byte[4096]; - ctx.random().nextBytes(orig); - Hash old = ctx.sha().calculateHash(orig); - SHA256Digest d = new SHA256Digest(); - d.update(orig, 0, orig.length); - byte out[] = new byte[Hash.HASH_LENGTH]; - d.doFinal(out, 0); - System.out.println("eq? " + net.i2p.data.DataHelper.eq(out, old.getData())); for (int i = 0; i < args.length; i++) System.out.println("SHA256 [" + args[i] + "] = [" + Base64.encode(ctx.sha().calculateHash(args[i].getBytes()).getData()) + "]"); } diff --git a/core/java/src/org/bouncycastle/crypto/digests/SHA256Digest.java b/core/java/src/org/bouncycastle/crypto/digests/SHA256Digest.java deleted file mode 100644 index d9a9f3e82..000000000 --- a/core/java/src/org/bouncycastle/crypto/digests/SHA256Digest.java +++ /dev/null @@ -1,292 +0,0 @@ -package org.bouncycastle.crypto.digests; -/* - * Copyright (c) 2000 - 2004 The Legion Of The Bouncy Castle - * (http://www.bouncycastle.org) - * - * Permission is hereby granted, free of charge, to any person - * obtaining a copy of this software and associated - * documentation files (the "Software"), to deal in the Software - * without restriction, including without limitation the rights to - * use, copy, modify, merge, publish, distribute, sublicense, and/or - * sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following - * conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES - * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT - * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, - * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR - * OTHER DEALINGS IN THE SOFTWARE. - * - */ - -/** - * FIPS 180-2 implementation of SHA-256. - * - *
- *         block  word  digest
- * SHA-1   512    32    160
- * SHA-256 512    32    256
- * SHA-384 1024   64    384
- * SHA-512 1024   64    512
- * 
- */ -public class SHA256Digest - extends GeneralDigest -{ - private static final int DIGEST_LENGTH = 32; - - private int H1, H2, H3, H4, H5, H6, H7, H8; - - private int[] X = new int[64]; - private int xOff; - - /** - * Standard constructor - */ - public SHA256Digest() - { - reset(); - } - - /** - * Copy constructor. This will copy the state of the provided - * message digest. - */ - public SHA256Digest(SHA256Digest t) - { - super(t); - - H1 = t.H1; - H2 = t.H2; - H3 = t.H3; - H4 = t.H4; - H5 = t.H5; - H6 = t.H6; - H7 = t.H7; - H8 = t.H8; - - System.arraycopy(t.X, 0, X, 0, t.X.length); - xOff = t.xOff; - } - - public String getAlgorithmName() - { - return "SHA-256"; - } - - public int getDigestSize() - { - return DIGEST_LENGTH; - } - - protected void processWord( - byte[] in, - int inOff) - { - X[xOff++] = ((in[inOff] & 0xff) << 24) | ((in[inOff + 1] & 0xff) << 16) - | ((in[inOff + 2] & 0xff) << 8) | ((in[inOff + 3] & 0xff)); - - if (xOff == 16) - { - processBlock(); - } - } - - private void unpackWord( - int word, - byte[] out, - int outOff) - { - out[outOff] = (byte)(word >>> 24); - out[outOff + 1] = (byte)(word >>> 16); - out[outOff + 2] = (byte)(word >>> 8); - out[outOff + 3] = (byte)word; - } - - protected void processLength( - long bitLength) - { - if (xOff > 14) - { - processBlock(); - } - - X[14] = (int)(bitLength >>> 32); - X[15] = (int)(bitLength & 0xffffffff); - } - - public int doFinal( - byte[] out, - int outOff) - { - finish(); - - unpackWord(H1, out, outOff); - unpackWord(H2, out, outOff + 4); - unpackWord(H3, out, outOff + 8); - unpackWord(H4, out, outOff + 12); - unpackWord(H5, out, outOff + 16); - unpackWord(H6, out, outOff + 20); - unpackWord(H7, out, outOff + 24); - unpackWord(H8, out, outOff + 28); - - reset(); - - return DIGEST_LENGTH; - } - - /** - * reset the chaining variables - */ - public void reset() - { - super.reset(); - - /* SHA-256 initial hash value - * The first 32 bits of the fractional parts of the square roots - * of the first eight prime numbers - */ - - H1 = 0x6a09e667; - H2 = 0xbb67ae85; - H3 = 0x3c6ef372; - H4 = 0xa54ff53a; - H5 = 0x510e527f; - H6 = 0x9b05688c; - H7 = 0x1f83d9ab; - H8 = 0x5be0cd19; - - xOff = 0; - for (int i = 0; i != X.length; i++) - { - X[i] = 0; - } - } - - protected void processBlock() - { - // - // expand 16 word block into 64 word blocks. - // - for (int t = 16; t <= 63; t++) - { - X[t] = Theta1(X[t - 2]) + X[t - 7] + Theta0(X[t - 15]) + X[t - 16]; - } - - // - // set up working variables. - // - int a = H1; - int b = H2; - int c = H3; - int d = H4; - int e = H5; - int f = H6; - int g = H7; - int h = H8; - - for (int t = 0; t <= 63; t++) - { - int T1, T2; - - T1 = h + Sum1(e) + Ch(e, f, g) + K[t] + X[t]; - T2 = Sum0(a) + Maj(a, b, c); - h = g; - g = f; - f = e; - e = d + T1; - d = c; - c = b; - b = a; - a = T1 + T2; - } - - H1 += a; - H2 += b; - H3 += c; - H4 += d; - H5 += e; - H6 += f; - H7 += g; - H8 += h; - - // - // reset the offset and clean out the word buffer. - // - xOff = 0; - for (int i = 0; i != X.length; i++) - { - X[i] = 0; - } - } - - private int rotateRight( - int x, - int n) - { - return (x >>> n) | (x << (32 - n)); - } - - /* SHA-256 functions */ - private int Ch( - int x, - int y, - int z) - { - return ((x & y) ^ ((~x) & z)); - } - - private int Maj( - int x, - int y, - int z) - { - return ((x & y) ^ (x & z) ^ (y & z)); - } - - private int Sum0( - int x) - { - return rotateRight(x, 2) ^ rotateRight(x, 13) ^ rotateRight(x, 22); - } - - private int Sum1( - int x) - { - return rotateRight(x, 6) ^ rotateRight(x, 11) ^ rotateRight(x, 25); - } - - private int Theta0( - int x) - { - return rotateRight(x, 7) ^ rotateRight(x, 18) ^ (x >>> 3); - } - - private int Theta1( - int x) - { - return rotateRight(x, 17) ^ rotateRight(x, 19) ^ (x >>> 10); - } - - /* SHA-256 Constants - * (represent the first 32 bits of the fractional parts of the - * cube roots of the first sixty-four prime numbers) - */ - static final int K[] = { - 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5, - 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174, - 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da, - 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967, - 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85, - 0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070, 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3, - 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2 - }; -} - diff --git a/history.txt b/history.txt index 06eb65cf8..da3d25d89 100644 --- a/history.txt +++ b/history.txt @@ -1,4 +1,10 @@ -$Id: history.txt,v 1.419 2006/02/24 04:35:52 jrandom Exp $ +$Id: history.txt,v 1.420 2006/02/25 15:41:52 jrandom Exp $ + +2006-02-26 jrandom + * Switch from the bouncycastle to the gnu-crypto implementation for + SHA256, as benchmarks show a 10-30% speedup. + * Removed some unnecessary object caches + * Don't close i2psnark streams prematurely 2006-02-25 jrandom * Made the Syndie permalinks in the thread view point to the blog view diff --git a/router/java/src/net/i2p/router/RouterVersion.java b/router/java/src/net/i2p/router/RouterVersion.java index b95a6e60e..fb3d758a0 100644 --- a/router/java/src/net/i2p/router/RouterVersion.java +++ b/router/java/src/net/i2p/router/RouterVersion.java @@ -15,9 +15,9 @@ import net.i2p.CoreVersion; * */ public class RouterVersion { - public final static String ID = "$Revision: 1.360 $ $Date: 2006/02/24 04:35:52 $"; + public final static String ID = "$Revision: 1.361 $ $Date: 2006/02/25 15:41:52 $"; public final static String VERSION = "0.6.1.11"; - public final static long BUILD = 5; + public final static long BUILD = 6; public static void main(String args[]) { System.out.println("I2P Router version: " + VERSION + "-" + BUILD); System.out.println("Router ID: " + RouterVersion.ID); diff --git a/router/java/src/net/i2p/router/transport/udp/UDPPacket.java b/router/java/src/net/i2p/router/transport/udp/UDPPacket.java index 59d02b7e5..a48fcdb8e 100644 --- a/router/java/src/net/i2p/router/transport/udp/UDPPacket.java +++ b/router/java/src/net/i2p/router/transport/udp/UDPPacket.java @@ -8,7 +8,6 @@ import java.util.ArrayList; import java.util.List; import net.i2p.I2PAppContext; -import net.i2p.crypto.HMACSHA256Generator; import net.i2p.data.Base64; import net.i2p.data.ByteArray; import net.i2p.data.DataHelper; @@ -29,8 +28,9 @@ public class UDPPacket { private volatile short _priority; private volatile long _initializeTime; private volatile long _expiration; - private volatile byte[] _data; - private volatile ByteArray _dataBuf; + private byte[] _data; + private byte[] _validateBuf; + private byte[] _ivBuf; private volatile int _markedType; private volatile RemoteHostId _remoteHost; private volatile boolean _released; @@ -78,9 +78,6 @@ public class UDPPacket { public static final byte BITFIELD_CONTINUATION = (byte)(1 << 7); private static final int MAX_VALIDATE_SIZE = MAX_PACKET_SIZE; - private static final ByteCache _validateCache = ByteCache.getInstance(64, MAX_VALIDATE_SIZE); - private static final ByteCache _ivCache = ByteCache.getInstance(64, IV_SIZE); - private static final ByteCache _dataCache = ByteCache.getInstance(64, MAX_PACKET_SIZE); private UDPPacket(I2PAppContext ctx, boolean inbound) { ctx.statManager().createRateStat("udp.packetsLiveInbound", "Number of live inbound packets in memory", "udp", new long[] { 60*1000, 5*60*1000 }); @@ -89,13 +86,16 @@ public class UDPPacket { ctx.statManager().createRateStat("udp.packetsLivePendingHandleInbound", "Number of live inbound packets not yet handled fully by the PacketHandler", "udp", new long[] { 60*1000, 5*60*1000 }); ctx.statManager().createRateStat("udp.fetchRemoteSlow", "How long it takes to grab the remote ip info", "udp", new long[] { 60*1000 }); // the data buffer is clobbered on init(..), but we need it to bootstrap - _packet = new DatagramPacket(new byte[MAX_PACKET_SIZE], MAX_PACKET_SIZE); + _data = new byte[MAX_PACKET_SIZE]; + _packet = new DatagramPacket(_data, MAX_PACKET_SIZE); + _validateBuf = new byte[MAX_VALIDATE_SIZE]; + _ivBuf = new byte[IV_SIZE]; init(ctx, inbound); } private void init(I2PAppContext ctx, boolean inbound) { _context = ctx; - _dataBuf = _dataCache.acquire(); - _data = _dataBuf.getData(); + //_dataBuf = _dataCache.acquire(); + Arrays.fill(_data, (byte)0); //_packet = new DatagramPacket(_data, MAX_PACKET_SIZE); _packet.setData(_data); _isInbound = inbound; @@ -106,21 +106,6 @@ public class UDPPacket { _released = false; } - /* - public void initialize(int priority, long expiration, InetAddress host, int port) { - _priority = (short)priority; - _expiration = expiration; - resetBegin(); - Arrays.fill(_data, (byte)0x00); - //_packet.setLength(0); - _packet.setAddress(host); - _packet.setPort(port); - _remoteHost = null; - _released = false; - _releasedBy = null; - } - */ - public void writeData(byte src[], int offset, int len) { verifyNotReleased(); System.arraycopy(src, offset, _data, 0, len); @@ -172,7 +157,7 @@ public class UDPPacket { verifyNotReleased(); _beforeValidate = _context.clock().now(); boolean eq = false; - ByteArray buf = _validateCache.acquire(); + Arrays.fill(_validateBuf, (byte)0); // validate by comparing _data[0:15] and // HMAC(payload + IV + (payloadLength ^ protocolVersion), macKey) @@ -180,14 +165,14 @@ public class UDPPacket { int payloadLength = _packet.getLength() - MAC_SIZE - IV_SIZE; if (payloadLength > 0) { int off = 0; - System.arraycopy(_data, _packet.getOffset() + MAC_SIZE + IV_SIZE, buf.getData(), off, payloadLength); + System.arraycopy(_data, _packet.getOffset() + MAC_SIZE + IV_SIZE, _validateBuf, off, payloadLength); off += payloadLength; - System.arraycopy(_data, _packet.getOffset() + MAC_SIZE, buf.getData(), off, IV_SIZE); + System.arraycopy(_data, _packet.getOffset() + MAC_SIZE, _validateBuf, off, IV_SIZE); off += IV_SIZE; - DataHelper.toLong(buf.getData(), off, 2, payloadLength ^ PacketBuilder.PROTOCOL_VERSION); + DataHelper.toLong(_validateBuf, off, 2, payloadLength ^ PacketBuilder.PROTOCOL_VERSION); off += 2; - eq = _context.hmac().verify(macKey, buf.getData(), 0, off, _data, _packet.getOffset(), MAC_SIZE); + eq = _context.hmac().verify(macKey, _validateBuf, 0, off, _data, _packet.getOffset(), MAC_SIZE); /* Hash hmac = _context.hmac().calculate(macKey, buf.getData(), 0, off); @@ -211,7 +196,6 @@ public class UDPPacket { _log.warn("Payload length is " + payloadLength); } - _validateCache.release(buf); _afterValidate = _context.clock().now(); _validateCount++; return eq; @@ -224,11 +208,10 @@ public class UDPPacket { */ public void decrypt(SessionKey cipherKey) { verifyNotReleased(); - ByteArray iv = _ivCache.acquire(); - System.arraycopy(_data, MAC_SIZE, iv.getData(), 0, IV_SIZE); + Arrays.fill(_ivBuf, (byte)0); + System.arraycopy(_data, MAC_SIZE, _ivBuf, 0, IV_SIZE); int len = _packet.getLength(); - _context.aes().decrypt(_data, _packet.getOffset() + MAC_SIZE + IV_SIZE, _data, _packet.getOffset() + MAC_SIZE + IV_SIZE, cipherKey, iv.getData(), len - MAC_SIZE - IV_SIZE); - _ivCache.release(iv); + _context.aes().decrypt(_data, _packet.getOffset() + MAC_SIZE + IV_SIZE, _data, _packet.getOffset() + MAC_SIZE + IV_SIZE, cipherKey, _ivBuf, len - MAC_SIZE - IV_SIZE); } /** the UDPReceiver has tossed it onto the inbound queue */ @@ -305,7 +288,7 @@ public class UDPPacket { //_releasedBy = new Exception("released by"); //_acquiredBy = null; // - _dataCache.release(_dataBuf); + //_dataCache.release(_dataBuf); if (!CACHE) return; synchronized (_packetCache) { diff --git a/router/java/src/net/i2p/router/transport/udp/UDPTransport.java b/router/java/src/net/i2p/router/transport/udp/UDPTransport.java index 72e2a41e3..f5e42c145 100644 --- a/router/java/src/net/i2p/router/transport/udp/UDPTransport.java +++ b/router/java/src/net/i2p/router/transport/udp/UDPTransport.java @@ -1291,6 +1291,8 @@ public class UDPTransport extends TransportImpl implements TimedWeightedPriority long idleIn = (now-peer.getLastReceiveTime())/1000; long idleOut = (now-peer.getLastSendTime())/1000; + if (idleIn < 0) idleIn = 0; + if (idleOut < 0) idleOut = 0; buf.append(""); buf.append(idleIn);