diff --git a/apps/routerconsole/jsp/help.jsp b/apps/routerconsole/jsp/help.jsp index 48520f410..d0b7278a2 100644 --- a/apps/routerconsole/jsp/help.jsp +++ b/apps/routerconsole/jsp/help.jsp @@ -16,10 +16,12 @@ hmm. we should probably have some help text here.

Legal stuff

The I2P router (router.jar) and SDK (i2p.jar) are almost entirely public domain, with a few notable exceptions:

On top of the I2P router are a series of client applications, each with their own set of diff --git a/core/java/src/net/i2p/crypto/AESEngine.java b/core/java/src/net/i2p/crypto/AESEngine.java index 4c3078d68..2dff6b435 100644 --- a/core/java/src/net/i2p/crypto/AESEngine.java +++ b/core/java/src/net/i2p/crypto/AESEngine.java @@ -66,13 +66,11 @@ public class AESEngine { int padding = ElGamalAESEngine.getPaddingSize(size, paddedSize); byte data[] = new byte[size + padding]; - SHA256EntryCache.CacheEntry cache = _context.sha().cache().acquire(iv.length); - Hash h = _context.sha().calculateHash(iv, cache); + Hash h = _context.sha().calculateHash(iv); int cur = 0; System.arraycopy(h.getData(), 0, data, cur, Hash.HASH_LENGTH); cur += Hash.HASH_LENGTH; - _context.sha().cache().release(cache); DataHelper.toLong(data, cur, 4, payload.length); cur += 4; @@ -96,18 +94,15 @@ public class AESEngine { } int cur = 0; - SHA256EntryCache.CacheEntry cache = _context.sha().cache().acquire(iv.length); - byte h[] = _context.sha().calculateHash(iv, cache).getData(); + byte h[] = _context.sha().calculateHash(iv).getData(); for (int i = 0; i < Hash.HASH_LENGTH; i++) { if (decr[i] != h[i]) { _log.error("Hash does not match [key=" + sessionKey + " / iv =" + DataHelper.toString(iv, iv.length) + "]", new Exception("Hash error")); - _context.sha().cache().release(cache); return null; } } cur += Hash.HASH_LENGTH; - _context.sha().cache().release(cache); long len = DataHelper.fromLong(decr, cur, 4); cur += 4; diff --git a/core/java/src/net/i2p/crypto/ElGamalAESEngine.java b/core/java/src/net/i2p/crypto/ElGamalAESEngine.java index 3785c202e..61b713609 100644 --- a/core/java/src/net/i2p/crypto/ElGamalAESEngine.java +++ b/core/java/src/net/i2p/crypto/ElGamalAESEngine.java @@ -163,11 +163,9 @@ public class ElGamalAESEngine { //_log.debug("Pre IV for decryptNewSession: " + DataHelper.toString(preIV, 32)); //_log.debug("SessionKey for decryptNewSession: " + DataHelper.toString(key.getData(), 32)); - SHA256EntryCache.CacheEntry cache = _context.sha().cache().acquire(preIV.length); - Hash ivHash = _context.sha().calculateHash(preIV, cache); + Hash ivHash = _context.sha().calculateHash(preIV); byte iv[] = new byte[16]; System.arraycopy(ivHash.getData(), 0, iv, 0, 16); - _context.sha().cache().release(cache); // feed the extra bytes into the PRNG _context.random().harvester().feedEntropy("ElG/AES", elgDecr, offset, elgDecr.length - offset); @@ -202,12 +200,10 @@ public class ElGamalAESEngine { SessionKey usedKey, SessionKey foundKey) throws DataFormatException { byte preIV[] = new byte[32]; System.arraycopy(data, 0, preIV, 0, preIV.length); - SHA256EntryCache.CacheEntry cache = _context.sha().cache().acquire(32); - Hash ivHash = _context.sha().calculateHash(preIV, cache); + Hash ivHash = _context.sha().calculateHash(preIV); byte iv[] = new byte[16]; System.arraycopy(ivHash.getData(), 0, iv, 0, 16); - _context.sha().cache().release(cache); - + usedKey.setData(key.getData()); //_log.debug("Pre IV for decryptExistingSession: " + DataHelper.toString(preIV, 32)); @@ -296,11 +292,9 @@ public class ElGamalAESEngine { byte unencrData[] = new byte[(int) len]; System.arraycopy(decrypted, cur, unencrData, 0, (int)len); cur += len; - SHA256EntryCache.CacheEntry cache = _context.sha().cache().acquire(unencrData.length); - Hash calcHash = _context.sha().calculateHash(unencrData, cache); + Hash calcHash = _context.sha().calculateHash(unencrData); boolean eq = calcHash.equals(readHash); - _context.sha().cache().release(cache); - + if (eq) { // everything matches. w00t. foundTags.addAll(tags); @@ -410,11 +404,9 @@ public class ElGamalAESEngine { // should we also feed the encrypted elG block into the harvester? - SHA256EntryCache.CacheEntry cache = _context.sha().cache().acquire(preIV.length); - Hash ivHash = _context.sha().calculateHash(preIV, cache); + Hash ivHash = _context.sha().calculateHash(preIV); byte iv[] = new byte[16]; System.arraycopy(ivHash.getData(), 0, iv, 0, 16); - _context.sha().cache().release(cache); byte aesEncr[] = encryptAESBlock(data, key, iv, tagsForDelivery, newKey, paddedSize); //_log.debug("AES encrypted length: " + aesEncr.length); @@ -448,12 +440,10 @@ public class ElGamalAESEngine { //_log.debug("Pre IV for encryptExistingSession (aka tag): " + currentTag.toString()); //_log.debug("SessionKey for encryptNewSession: " + DataHelper.toString(key.getData(), 32)); - SHA256EntryCache.CacheEntry cache = _context.sha().cache().acquire(rawTag.length); - Hash ivHash = _context.sha().calculateHash(rawTag, cache); + Hash ivHash = _context.sha().calculateHash(rawTag); byte iv[] = new byte[16]; System.arraycopy(ivHash.getData(), 0, iv, 0, 16); - _context.sha().cache().release(cache); - + byte aesEncr[] = encryptAESBlock(data, key, iv, tagsForDelivery, newKey, paddedSize, SessionTag.BYTE_LENGTH); // that prepended SessionTag.BYTE_LENGTH bytes at the beginning of the buffer System.arraycopy(rawTag, 0, aesEncr, 0, rawTag.length); @@ -507,12 +497,10 @@ public class ElGamalAESEngine { DataHelper.toLong(aesData, cur, 4, data.length); cur += 4; //_log.debug("data length: " + data.length); - SHA256EntryCache.CacheEntry cache = _context.sha().cache().acquire(data.length); - Hash hash = _context.sha().calculateHash(data, cache); + Hash hash = _context.sha().calculateHash(data); System.arraycopy(hash.getData(), 0, aesData, cur, Hash.HASH_LENGTH); cur += Hash.HASH_LENGTH; - _context.sha().cache().release(cache); - + //_log.debug("hash of data: " + DataHelper.toString(hash.getData(), 32)); if (newKey == null) { aesData[cur++] = 0x00; // don't rekey diff --git a/core/java/src/net/i2p/crypto/ElGamalEngine.java b/core/java/src/net/i2p/crypto/ElGamalEngine.java index 29837f26a..b0f170120 100644 --- a/core/java/src/net/i2p/crypto/ElGamalEngine.java +++ b/core/java/src/net/i2p/crypto/ElGamalEngine.java @@ -98,10 +98,8 @@ public class ElGamalEngine { byte d2[] = new byte[1+Hash.HASH_LENGTH+data.length]; d2[0] = (byte)0xFF; - SHA256EntryCache.CacheEntry cache = _context.sha().cache().acquire(data.length); - Hash hash = _context.sha().calculateHash(data, cache); + Hash hash = _context.sha().calculateHash(data); System.arraycopy(hash.getData(), 0, d2, 1, Hash.HASH_LENGTH); - _context.sha().cache().release(cache); System.arraycopy(data, 0, d2, 1+Hash.HASH_LENGTH, data.length); long t0 = _context.clock().now(); @@ -194,11 +192,9 @@ public class ElGamalEngine { byte rv[] = new byte[payloadLen]; System.arraycopy(val, i + 1 + Hash.HASH_LENGTH, rv, 0, rv.length); - SHA256EntryCache.CacheEntry cache = _context.sha().cache().acquire(payloadLen); - Hash calcHash = _context.sha().calculateHash(rv, cache); + Hash calcHash = _context.sha().calculateHash(rv); boolean ok = calcHash.equals(hash); - _context.sha().cache().release(cache); - + long end = _context.clock().now(); long diff = end - start; diff --git a/core/java/src/net/i2p/crypto/HMACSHA256Generator.java b/core/java/src/net/i2p/crypto/HMACSHA256Generator.java index b02181e43..09e7a054c 100644 --- a/core/java/src/net/i2p/crypto/HMACSHA256Generator.java +++ b/core/java/src/net/i2p/crypto/HMACSHA256Generator.java @@ -1,64 +1,34 @@ 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; +import org.bouncycastle.crypto.digests.SHA256Digest; +import org.bouncycastle.crypto.macs.HMac; + /** - * Calculate the HMAC-SHA256 of a key+message. + * 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 HMACSHA256Generator { private I2PAppContext _context; + private List _available; public HMACSHA256Generator(I2PAppContext context) { _context = context; + _available = new ArrayList(32); } public static HMACSHA256Generator getInstance() { return I2PAppContext.getGlobalContext().hmac(); } - private static final int PAD_LENGTH = 64; - - private static final byte[] _IPAD = new byte[PAD_LENGTH]; - private static final byte[] _OPAD = new byte[PAD_LENGTH]; - static { - for (int i = 0; i < _IPAD.length; i++) { - _IPAD[i] = 0x36; - _OPAD[i] = 0x5C; - } - } - - - public Buffer createBuffer(int dataLen) { return new Buffer(dataLen); } - - public class Buffer { - private byte padded[]; - private byte innerBuf[]; - private SHA256EntryCache.CacheEntry innerEntry; - private byte rv[]; - private byte outerBuf[]; - private SHA256EntryCache.CacheEntry outerEntry; - - public Buffer(int dataLength) { - padded = new byte[PAD_LENGTH]; - innerBuf = new byte[dataLength + PAD_LENGTH]; - innerEntry = _context.sha().cache().acquire(innerBuf.length); - rv = new byte[Hash.HASH_LENGTH]; - outerBuf = new byte[Hash.HASH_LENGTH + PAD_LENGTH]; - outerEntry = _context.sha().cache().acquire(outerBuf.length); - } - - public void releaseCached() { - _context.sha().cache().release(innerEntry); - _context.sha().cache().release(outerEntry); - } - - public byte[] getHash() { return rv; } - } - /** * Calculate the HMAC of the data with the given key */ @@ -75,43 +45,26 @@ public class HMACSHA256Generator { if ((key == null) || (key.getData() == null) || (data == null)) throw new NullPointerException("Null arguments for HMAC"); - Buffer buf = new Buffer(length); - calculate(key, data, offset, length, buf); - Hash rv = new Hash(buf.rv); - buf.releaseCached(); - return rv; + 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 - */ - public void calculate(SessionKey key, byte data[], Buffer buf) { - calculate(key, data, 0, data.length, buf); + private HMac acquire() { + synchronized (_available) { + if (_available.size() > 0) + return (HMac)_available.remove(0); + } + return new HMac(new SHA256Digest()); } - - /** - * Calculate the HMAC of the data with the given key - */ - public void calculate(SessionKey key, byte data[], int offset, int length, Buffer buf) { - // inner hash - padKey(key.getData(), _IPAD, buf.padded); - System.arraycopy(buf.padded, 0, buf.innerBuf, 0, PAD_LENGTH); - System.arraycopy(data, offset, buf.innerBuf, PAD_LENGTH, length); - - Hash h = _context.sha().calculateHash(buf.innerBuf, buf.innerEntry); - - // outer hash - padKey(key.getData(), _OPAD, buf.padded); - System.arraycopy(buf.padded, 0, buf.outerBuf, 0, PAD_LENGTH); - System.arraycopy(h.getData(), 0, buf.outerBuf, PAD_LENGTH, Hash.HASH_LENGTH); - - h = _context.sha().calculateHash(buf.outerBuf, buf.outerEntry); - System.arraycopy(h.getData(), 0, buf.rv, 0, Hash.HASH_LENGTH); - } - - private static final void padKey(byte key[], byte pad[], byte out[]) { - for (int i = 0; i < SessionKey.KEYSIZE_BYTES; i++) - out[i] = (byte) (key[i] ^ pad[i]); - Arrays.fill(out, SessionKey.KEYSIZE_BYTES, PAD_LENGTH, pad[0]); + private void release(HMac mac) { + synchronized (_available) { + if (_available.size() < 64) + _available.add(mac); + } } } \ No newline at end of file diff --git a/core/java/src/net/i2p/crypto/SHA256EntryCache.java b/core/java/src/net/i2p/crypto/SHA256EntryCache.java deleted file mode 100644 index 4b6abba37..000000000 --- a/core/java/src/net/i2p/crypto/SHA256EntryCache.java +++ /dev/null @@ -1,238 +0,0 @@ -package net.i2p.crypto; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; - -import net.i2p.I2PAppContext; -import net.i2p.data.Hash; - -/** - * Cache the objects used in SHA256Generator's calculate method to reduce - * memory churn. The CacheEntry should be held onto as long as the - * data referenced in it is needed (which often is only one or two lines - * of code) - * - */ -public final class SHA256EntryCache { - private static final int ONE_KB = 0; - private static final int FOUR_KB = 1; - private static final int EIGHT_KB = 2; - private static final int SIXTEEN_KB = 3; - private static final int THIRTYTWO_KB = 4; - private static final int FOURTYEIGHT_KB = 5; - private static final int LARGER = 6; - /** - * Array of Lists of free CacheEntry objects, indexed - * by the payload size they are capable of handling - */ - private List _available[] = new List[6]; - /** count up how often we use the cache for each size */ - private long _used[] = new long[7]; - private int _sizes[] = new int[] { 1024,4*1024,8*1024,16*1024,32*1024,48*1024 }; - - /** no more than 32 at each size level */ - private static final int MAX_CACHED = 64; - - public SHA256EntryCache() { - for (int i = 0; i < _available.length; i++) { - _available[i] = new ArrayList(MAX_CACHED); - //for (int j = 0; j < MAX_CACHED; j++) - // _available[i].add(new CacheEntry(_sizes[i])); - } - } - - /** - * Get the next available structure, either from the cache or a brand new one - * - */ - public final CacheEntry acquire(int payload) { - int entrySize = getBucket(payload); - switch (entrySize) { - case 1024: - _used[ONE_KB]++; - synchronized (_available[ONE_KB]) { - if (_available[ONE_KB].size() > 0) { - return (CacheEntry)_available[ONE_KB].remove(0); - } - } - break; - case 4*1024: - _used[FOUR_KB]++; - synchronized (_available[FOUR_KB]) { - if (_available[FOUR_KB].size() > 0) { - return (CacheEntry)_available[FOUR_KB].remove(0); - } - } - break; - case 8*1024: - _used[EIGHT_KB]++; - synchronized (_available[EIGHT_KB]) { - if (_available[EIGHT_KB].size() > 0) { - return (CacheEntry)_available[EIGHT_KB].remove(0); - } - } - break; - case 16*1024: - _used[SIXTEEN_KB]++; - synchronized (_available[SIXTEEN_KB]) { - if (_available[SIXTEEN_KB].size() > 0) { - return (CacheEntry)_available[SIXTEEN_KB].remove(0); - } - } - break; - case 32*1024: - _used[THIRTYTWO_KB]++; - synchronized (_available[THIRTYTWO_KB]) { - if (_available[THIRTYTWO_KB].size() > 0) { - return (CacheEntry)_available[THIRTYTWO_KB].remove(0); - } - } - break; - case 48*1024: - _used[FOURTYEIGHT_KB]++; - synchronized (_available[FOURTYEIGHT_KB]) { - if (_available[FOURTYEIGHT_KB].size() > 0) { - return (CacheEntry)_available[FOURTYEIGHT_KB].remove(0); - } - } - break; - default: - _used[LARGER]++; - // not for the bucket, so make it exact - return new CacheEntry(payload); - } - return new CacheEntry(entrySize); - } - - /** - * Put this structure back onto the available cache for reuse - * - */ - public final void release(CacheEntry entry) { - entry.reset(); - if (false) return; - switch (entry.bucket) { - case 1024: - synchronized (_available[ONE_KB]) { - if (_available[ONE_KB].size() < MAX_CACHED) { - _available[ONE_KB].add(entry); - } - } - return; - case 4*1024: - synchronized (_available[FOUR_KB]) { - if (_available[FOUR_KB].size() < MAX_CACHED) { - _available[FOUR_KB].add(entry); - } - } - return; - case 8*1024: - synchronized (_available[EIGHT_KB]) { - if (_available[EIGHT_KB].size() < MAX_CACHED) { - _available[EIGHT_KB].add(entry); - } - } - return; - case 16*1024: - synchronized (_available[SIXTEEN_KB]) { - if (_available[SIXTEEN_KB].size() < MAX_CACHED) { - _available[SIXTEEN_KB].add(entry); - } - } - return; - case 32*1024: - synchronized (_available[THIRTYTWO_KB]) { - if (_available[THIRTYTWO_KB].size() < MAX_CACHED) { - _available[THIRTYTWO_KB].add(entry); - } - } - return; - case 48*1024: - synchronized (_available[FOURTYEIGHT_KB]) { - if (_available[FOURTYEIGHT_KB].size() < MAX_CACHED) { - _available[FOURTYEIGHT_KB].add(entry); - } - } - return; - } - } - - /** - * all the data alloc'ed in a calculateHash call - */ - public static final class CacheEntry { - byte hashbytes[]; - int W[]; - int M0[]; - int H[]; - Hash hash; - int wordlength; - int bucket; - - public CacheEntry(int payload) { - wordlength = SHA256Generator.getWordlength(payload); - bucket = payload; - hashbytes = new byte[32]; - M0 = new int[wordlength]; - W = new int[64]; - H = new int[8]; - hash = new Hash(); - hash.setData(hashbytes); - } - - public final void reset() { - Arrays.fill(hashbytes, (byte)0x0); - Arrays.fill(M0, (byte)0x0); - Arrays.fill(W, (byte)0x0); - Arrays.fill(H, (byte)0x0); - } - } - - private static final int getBucket(int payload) { - if (payload <= 1024) - return 1024; - else if (payload <= 4*1024) - return 4*1024; - else if (payload <= 8*1024) - return 8*1024; - else if (payload <= 16*1024) - return 16*1024; - else if (payload <= 32*1024) - return 32*1024; - else if (payload <= 48*1024) - return 48*1024; - else - return payload; - } - - public static void main(String args[]) { - I2PAppContext ctx = new I2PAppContext(); - for (int i = 1; i < 20000; i+=2) { - test(ctx, i); - } - } - private static void test(I2PAppContext ctx, int size) { - System.out.print("Size = " + size); - for (int i = 0; i < 2; i++) { - byte orig[] = new byte[size]; - ctx.random().nextBytes(orig); - CacheEntry cache = ctx.sha().cache().acquire(orig.length); - try { - Hash h = ctx.sha().calculateHash(orig, cache); - Hash h2 = ctx.sha().calculateHash(orig); - boolean eq = h.equals(h2); - ctx.sha().cache().release(cache); - if (eq) { - System.out.print("."); - } else { - System.out.print("ERROR " + i); - break; - } - } catch (Exception e) { - e.printStackTrace(); - } - } - System.out.println(); - } -} diff --git a/core/java/src/net/i2p/crypto/SHA256Generator.java b/core/java/src/net/i2p/crypto/SHA256Generator.java index 38a84aaa8..82ca186fc 100644 --- a/core/java/src/net/i2p/crypto/SHA256Generator.java +++ b/core/java/src/net/i2p/crypto/SHA256Generator.java @@ -1,236 +1,47 @@ package net.i2p.crypto; -/* - * Copyright (c) 2003, TheCrypto - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * - Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - Neither the name of the TheCrypto may be used to endorse or promote - * products derived from this software without specific prior written - * permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ - import java.util.Arrays; import net.i2p.I2PAppContext; import net.i2p.data.Hash; -/** Defines a wrapper for SHA-256 operation - * - * This is done. Takes data of any size and hashes it. +import org.bouncycastle.crypto.digests.SHA256Digest; + +/** + * Defines a wrapper for SHA-256 operation. All the good stuff occurs + * in the Bouncycastle {@link org.bouncycastle.crypto.digests.SHA256Digest} * - * @author thecrypto,jrandom */ public final class SHA256Generator { - private final SHA256EntryCache _cache = new SHA256EntryCache(); - public SHA256Generator(I2PAppContext context) { // nop - } + public SHA256Generator(I2PAppContext context) {} public static final SHA256Generator getInstance() { return I2PAppContext.getGlobalContext().sha(); } - public final SHA256EntryCache cache() { return _cache; } - - 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}; - - static final int[] H0 = { 0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a, 0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19}; - - public static final int getWordlength(int sourceLength) { - long length = sourceLength * 8; - int k = 448 - (int) ((length + 1) % 512); - if (k < 0) { - k += 512; - } - int padbytes = k / 8; - int rv = sourceLength / 4 + padbytes / 4 + 3; - return rv; - } - - private final SHA256EntryCache.CacheEntry getNewEntry(int payloadSize) { - return new SHA256EntryCache.CacheEntry(payloadSize); - } - /** Calculate the SHA-256 has of the source * @param source what to hash * @return hash of the source */ public final Hash calculateHash(byte[] source) { - byte rv[] = new byte[Hash.HASH_LENGTH]; - SHA256EntryCache.CacheEntry cache = _cache.acquire(source.length); - Hash hash = calculateHash(source, 0, source.length, cache); - System.arraycopy(hash.getData(), 0, rv, 0, Hash.HASH_LENGTH); - _cache.release(cache); - return new Hash(rv); - } - public final Hash calculateHash(byte[] source, SHA256EntryCache.CacheEntry cache) { - return calculateHash(source, 0, source.length, cache); + return calculateHash(source, 0, source.length); } public final Hash calculateHash(byte[] source, int start, int len) { byte rv[] = new byte[Hash.HASH_LENGTH]; - SHA256EntryCache.CacheEntry cache = _cache.acquire(len); - Hash hash = calculateHash(source, start, len, cache); - System.arraycopy(hash.getData(), 0, rv, 0, Hash.HASH_LENGTH); - _cache.release(cache); + SHA256Digest digest = new SHA256Digest(); + digest.update(source, start, len); + digest.doFinal(rv, 0); return new Hash(rv); } - public final Hash calculateHash(byte[] source, int start, int len, SHA256EntryCache.CacheEntry cache) { - if (cache == null) - return calculateHash(source, start, len); - long length = len * 8; - int k = 448 - (int) ((length + 1) % 512); - if (k < 0) { - k += 512; - } - int padbytes = k / 8; - int wordlength = len / 4 + padbytes / 4 + 3; - if (wordlength != getWordlength(len)) - throw new RuntimeException("len = " + len + " wordlength = " + wordlength - + " getWordlength = " + getWordlength(len)); - int[] M0 = cache.M0; - int wordcount = 0; - int x = 0; - for (x = 0; x < (len / 4) * 4; x += 4) { - M0[wordcount] = source[x+start] << 24 >>> 24 << 24; - M0[wordcount] |= source[x+start + 1] << 24 >>> 24 << 16; - M0[wordcount] |= source[x+start + 2] << 24 >>> 24 << 8; - M0[wordcount] |= source[x+start + 3] << 24 >>> 24 << 0; - wordcount++; - } - switch (len - (wordcount + 1) * 4 + 4) { - case 0: - M0[wordcount] |= 0x80000000; - break; - case 1: - M0[wordcount] = source[x+start] << 24 >>> 24 << 24; - M0[wordcount] |= 0x00800000; - break; - case 2: - M0[wordcount] = source[x+start] << 24 >>> 24 << 24; - M0[wordcount] |= source[x+start + 1] << 24 >>> 24 << 16; - M0[wordcount] |= 0x00008000; - break; - case 3: - M0[wordcount] = source[x+start] << 24 >>> 24 << 24; - M0[wordcount] |= source[x+start + 1] << 24 >>> 24 << 16; - M0[wordcount] |= source[x+start + 2] << 24 >>> 24 << 8; - M0[wordcount] |= 0x00000080; - break; - } - M0[wordlength - 2] = (int) (length >>> 32); - M0[wordlength - 1] = (int) (length); - int[] H = cache.H; - for (x = 0; x < 8; x++) { - H[x] = H0[x]; - } - int blocks = wordlength / 16; - int[] W = cache.W; - for (int bl = 0; bl < blocks; bl++) { - int a = H[0]; - int b = H[1]; - int c = H[2]; - int d = H[3]; - int e = H[4]; - int f = H[5]; - int g = H[6]; - int h = H[7]; - Arrays.fill(W, 0); - for (x = 0; x < 64; x++) { - if (x < 16) { - W[x] = M0[bl * 16 + x]; - } else { - W[x] = add(o1(W[x - 2]), add(W[x - 7], add(o0(W[x - 15]), W[x - 16]))); - } - } - for (x = 0; x < 64; x++) { - int T1 = add(h, add(e1(e), add(Ch(e, f, g), add(K[x], W[x])))); - int T2 = add(e0(a), Maj(a, b, c)); - h = g; - g = f; - f = e; - e = add(d, T1); - d = c; - c = b; - b = a; - a = add(T1, T2); - } - H[0] = add(a, H[0]); - H[1] = add(b, H[1]); - H[2] = add(c, H[2]); - H[3] = add(d, H[3]); - H[4] = add(e, H[4]); - H[5] = add(f, H[5]); - H[6] = add(g, H[6]); - H[7] = add(h, H[7]); - } - byte[] hashbytes = cache.hashbytes; - for (x = 0; x < 8; x++) { - hashbytes[x * 4] = (byte) (H[x] << 0 >>> 24); - hashbytes[x * 4 + 1] = (byte) (H[x] << 8 >>> 24); - hashbytes[x * 4 + 2] = (byte) (H[x] << 16 >>> 24); - hashbytes[x * 4 + 3] = (byte) (H[x] << 24 >>> 24); - } - return cache.hash; - } - - private static final int Ch(int x, int y, int z) { - return (x & y) ^ (~x & z); - } - - private static final int Maj(int x, int y, int z) { - return (x & y) ^ (x & z) ^ (y & z); - } - - private static final int ROTR(int x, int n) { - return (x >>> n) | (x << 32 - n); - } - - private static final int e0(int x) { - return ROTR(x, 2) ^ ROTR(x, 13) ^ ROTR(x, 22); - } - - private static final int e1(int x) { - return ROTR(x, 6) ^ ROTR(x, 11) ^ ROTR(x, 25); - } - - private static final int SHR(int x, int n) { - return x >>> n; - } - - private static final int o0(int x) { - return ROTR(x, 7) ^ ROTR(x, 18) ^ SHR(x, 3); - } - - private static final int o1(int x) { - return ROTR(x, 17) ^ ROTR(x, 19) ^ SHR(x, 10); - } - - private static final int add(int x, int y) { - return x + y; + + 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())); } } \ No newline at end of file diff --git a/core/java/src/org/bouncycastle/crypto/Digest.java b/core/java/src/org/bouncycastle/crypto/Digest.java new file mode 100644 index 000000000..7ffa23954 --- /dev/null +++ b/core/java/src/org/bouncycastle/crypto/Digest.java @@ -0,0 +1,77 @@ +package org.bouncycastle.crypto; +/* + * 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. + * + */ + +/** + * interface that a message digest conforms to. + */ +public interface Digest +{ + /** + * return the algorithm name + * + * @return the algorithm name + */ + public String getAlgorithmName(); + + /** + * return the size, in bytes, of the digest produced by this message digest. + * + * @return the size, in bytes, of the digest produced by this message digest. + */ + public int getDigestSize(); + + /** + * update the message digest with a single byte. + * + * @param in the input byte to be entered. + */ + public void update(byte in); + + /** + * update the message digest with a block of bytes. + * + * @param in the byte array containing the data. + * @param inOff the offset into the byte array where the data starts. + * @param len the length of the data. + */ + public void update(byte[] in, int inOff, int len); + + /** + * close the digest, producing the final digest value. The doFinal + * call leaves the digest reset. + * + * @param out the array the digest is to be copied into. + * @param outOff the offset into the out array the digest is to start at. + */ + public int doFinal(byte[] out, int outOff); + + /** + * reset the digest back to it's initial state. + */ + public void reset(); +} diff --git a/core/java/src/org/bouncycastle/crypto/Mac.java b/core/java/src/org/bouncycastle/crypto/Mac.java new file mode 100644 index 000000000..336f88363 --- /dev/null +++ b/core/java/src/org/bouncycastle/crypto/Mac.java @@ -0,0 +1,97 @@ +package org.bouncycastle.crypto; +/* + * 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. + * + */ + + +/** + * The base interface for implementations of message authentication codes (MACs). + * + * modified by jrandom to use the session key byte array directly + */ +public interface Mac +{ + /** + * Initialise the MAC. + * + * @param key the key required by the MAC. + * @exception IllegalArgumentException if the params argument is + * inappropriate. + */ + public void init(byte key[]) + throws IllegalArgumentException; + + /** + * Return the name of the algorithm the MAC implements. + * + * @return the name of the algorithm the MAC implements. + */ + public String getAlgorithmName(); + + /** + * Return the block size for this cipher (in bytes). + * + * @return the block size for this cipher in bytes. + */ + public int getMacSize(); + + /** + * add a single byte to the mac for processing. + * + * @param in the byte to be processed. + * @exception IllegalStateException if the MAC is not initialised. + */ + public void update(byte in) + throws IllegalStateException; + + /** + * @param in the array containing the input. + * @param inOff the index in the array the data begins at. + * @param len the length of the input starting at inOff. + * @exception IllegalStateException if the MAC is not initialised. + */ + public void update(byte[] in, int inOff, int len) + throws IllegalStateException; + + /** + * Compute the final statge of the MAC writing the output to the out + * parameter. + *

+ * doFinal leaves the MAC in the same state it was after the last init. + * + * @param out the array the MAC is to be output to. + * @param outOff the offset into the out buffer the output is to start at. + * @exception IllegalStateException if the MAC is not initialised. + */ + public int doFinal(byte[] out, int outOff) + throws IllegalStateException; + + /** + * Reset the MAC. At the end of resetting the MAC should be in the + * in the same state it was after the last init (if there was one). + */ + public void reset(); +} diff --git a/core/java/src/org/bouncycastle/crypto/digests/GeneralDigest.java b/core/java/src/org/bouncycastle/crypto/digests/GeneralDigest.java new file mode 100644 index 000000000..09b72f9e7 --- /dev/null +++ b/core/java/src/org/bouncycastle/crypto/digests/GeneralDigest.java @@ -0,0 +1,154 @@ +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. + * + */ + +import org.bouncycastle.crypto.Digest; + +/** + * base implementation of MD4 family style digest as outlined in + * "Handbook of Applied Cryptography", pages 344 - 347. + */ +public abstract class GeneralDigest + implements Digest +{ + private byte[] xBuf; + private int xBufOff; + + private long byteCount; + + /** + * Standard constructor + */ + protected GeneralDigest() + { + xBuf = new byte[4]; + xBufOff = 0; + } + + /** + * Copy constructor. We are using copy constructors in place + * of the Object.clone() interface as this interface is not + * supported by J2ME. + */ + protected GeneralDigest(GeneralDigest t) + { + xBuf = new byte[t.xBuf.length]; + System.arraycopy(t.xBuf, 0, xBuf, 0, t.xBuf.length); + + xBufOff = t.xBufOff; + byteCount = t.byteCount; + } + + public void update( + byte in) + { + xBuf[xBufOff++] = in; + + if (xBufOff == xBuf.length) + { + processWord(xBuf, 0); + xBufOff = 0; + } + + byteCount++; + } + + public void update( + byte[] in, + int inOff, + int len) + { + // + // fill the current word + // + while ((xBufOff != 0) && (len > 0)) + { + update(in[inOff]); + + inOff++; + len--; + } + + // + // process whole words. + // + while (len > xBuf.length) + { + processWord(in, inOff); + + inOff += xBuf.length; + len -= xBuf.length; + byteCount += xBuf.length; + } + + // + // load in the remainder. + // + while (len > 0) + { + update(in[inOff]); + + inOff++; + len--; + } + } + + public void finish() + { + long bitLength = (byteCount << 3); + + // + // add the pad bytes. + // + update((byte)128); + + while (xBufOff != 0) + { + update((byte)0); + } + + processLength(bitLength); + + processBlock(); + } + + public void reset() + { + byteCount = 0; + + xBufOff = 0; + for ( int i = 0; i < xBuf.length; i++ ) { + xBuf[i] = 0; + } + } + + protected abstract void processWord(byte[] in, int inOff); + + protected abstract void processLength(long bitLength); + + protected abstract void processBlock(); +} diff --git a/core/java/src/org/bouncycastle/crypto/digests/SHA256Digest.java b/core/java/src/org/bouncycastle/crypto/digests/SHA256Digest.java new file mode 100644 index 000000000..d9a9f3e82 --- /dev/null +++ b/core/java/src/org/bouncycastle/crypto/digests/SHA256Digest.java @@ -0,0 +1,292 @@ +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/core/java/src/org/bouncycastle/crypto/macs/HMac.java b/core/java/src/org/bouncycastle/crypto/macs/HMac.java new file mode 100644 index 000000000..8cbd9d458 --- /dev/null +++ b/core/java/src/org/bouncycastle/crypto/macs/HMac.java @@ -0,0 +1,168 @@ +package org.bouncycastle.crypto.macs; +/* + * 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. + * + */ + +//import org.bouncycastle.crypto.CipherParameters; +import org.bouncycastle.crypto.Digest; +import org.bouncycastle.crypto.Mac; +//import org.bouncycastle.crypto.params.KeyParameter; +import java.util.Arrays; + +/** + * HMAC implementation based on RFC2104 + * + * H(K XOR opad, H(K XOR ipad, text)) + * + * modified by jrandom to use the session key byte array directly + */ +public class HMac +implements Mac +{ + private final static int BLOCK_LENGTH = 64; + + private final static byte IPAD = (byte)0x36; + private final static byte OPAD = (byte)0x5C; + + private Digest digest; + private int digestSize; + private byte[] inputPad = new byte[BLOCK_LENGTH]; + private byte[] outputPad = new byte[BLOCK_LENGTH]; + + public HMac( + Digest digest) + { + this.digest = digest; + digestSize = digest.getDigestSize(); + } + + public String getAlgorithmName() + { + return digest.getAlgorithmName() + "/HMAC"; + } + + public Digest getUnderlyingDigest() + { + return digest; + } + + //public void init( + // CipherParameters params) + //{ + public void init(byte key[]) + { + digest.reset(); + + //byte[] key = ((KeyParameter)params).getKey(); + + if (key.length > BLOCK_LENGTH) + { + digest.update(key, 0, key.length); + digest.doFinal(inputPad, 0); + for (int i = digestSize; i < inputPad.length; i++) + { + inputPad[i] = 0; + } + } + else + { + System.arraycopy(key, 0, inputPad, 0, key.length); + for (int i = key.length; i < inputPad.length; i++) + { + inputPad[i] = 0; + } + } + + // why reallocate? it hasn't changed sizes, and the arraycopy + // below fills it completely... + //outputPad = new byte[inputPad.length]; + System.arraycopy(inputPad, 0, outputPad, 0, inputPad.length); + + for (int i = 0; i < inputPad.length; i++) + { + inputPad[i] ^= IPAD; + } + + for (int i = 0; i < outputPad.length; i++) + { + outputPad[i] ^= OPAD; + } + + digest.update(inputPad, 0, inputPad.length); + } + + public int getMacSize() + { + return digestSize; + } + + public void update( + byte in) + { + digest.update(in); + } + + public void update( + byte[] in, + int inOff, + int len) + { + digest.update(in, inOff, len); + } + + public int doFinal( + byte[] out, + int outOff) + { + byte[] tmp = new byte[digestSize]; + digest.doFinal(tmp, 0); + + digest.update(outputPad, 0, outputPad.length); + digest.update(tmp, 0, tmp.length); + + int len = digest.doFinal(out, outOff); + + reset(); + + return len; + } + + /** + * Reset the mac generator. + */ + public void reset() + { + /* + * reset the underlying digest. + */ + digest.reset(); + + /* + * reinitialize the digest. + */ + digest.update(inputPad, 0, inputPad.length); + } +} diff --git a/history.txt b/history.txt index 23e4b8c00..824113629 100644 --- a/history.txt +++ b/history.txt @@ -1,4 +1,7 @@ -$Id: history.txt,v 1.191 2005/04/08 22:16:05 smeghead Exp $ +$Id: history.txt,v 1.192 2005/04/12 10:22:11 jrandom Exp $ + +2005-04-16 jrandom + * Migrated to Bouncycastle's SHA256 and HMAC implementations for efficiency 2005-04-12 jrandom * Make sure we don't get cached updates (thanks smeghead!) diff --git a/installer/resources/readme.license.txt b/installer/resources/readme.license.txt index 7324c894b..d707e557c 100644 --- a/installer/resources/readme.license.txt +++ b/installer/resources/readme.license.txt @@ -13,6 +13,7 @@ The base I2P router and SDK make use of the following non-public domain code: * TheCrypto's cryptographic routines (BSD) +* Bouncycastle's hash routines (MIT license) * Cryptix's AES routines (Cryptix license) * Adam Buckley's SNTP routines (BSD) diff --git a/router/java/src/net/i2p/data/i2np/I2NPMessageImpl.java b/router/java/src/net/i2p/data/i2np/I2NPMessageImpl.java index 8dd718e2d..b83c6b28b 100644 --- a/router/java/src/net/i2p/data/i2np/I2NPMessageImpl.java +++ b/router/java/src/net/i2p/data/i2np/I2NPMessageImpl.java @@ -13,7 +13,6 @@ import java.io.InputStream; import java.io.OutputStream; import net.i2p.I2PAppContext; -import net.i2p.crypto.SHA256EntryCache; import net.i2p.data.DataFormatException; import net.i2p.data.DataHelper; import net.i2p.data.DataStructureImpl; @@ -80,11 +79,9 @@ public abstract class I2NPMessageImpl extends DataStructureImpl implements I2NPM cur += numRead; } - SHA256EntryCache.CacheEntry cache = _context.sha().cache().acquire(size); - Hash calc = _context.sha().calculateHash(buffer, 0, size, cache); + Hash calc = _context.sha().calculateHash(buffer, 0, size); //boolean eq = calc.equals(h); boolean eq = DataHelper.eq(checksum, 0, calc.getData(), 0, CHECKSUM_LENGTH); - _context.sha().cache().release(cache); if (!eq) throw new I2NPMessageException("Hash does not match for " + getClass().getName()); @@ -125,11 +122,9 @@ public abstract class I2NPMessageImpl extends DataStructureImpl implements I2NPM + " cur=" + cur + " wanted=" + size + "]: " + getClass().getName()); - SHA256EntryCache.CacheEntry cache = _context.sha().cache().acquire(size); - Hash calc = _context.sha().calculateHash(data, cur, size, cache); + Hash calc = _context.sha().calculateHash(data, cur, size); //boolean eq = calc.equals(h); boolean eq = DataHelper.eq(hdata, 0, calc.getData(), 0, CHECKSUM_LENGTH); - _context.sha().cache().release(cache); if (!eq) throw new I2NPMessageException("Hash does not match for " + getClass().getName()); @@ -204,8 +199,7 @@ public abstract class I2NPMessageImpl extends DataStructureImpl implements I2NPM try { int writtenLen = writeMessageBody(buffer, prefixLen); int payloadLen = writtenLen - prefixLen; - SHA256EntryCache.CacheEntry cache = _context.sha().cache().acquire(payloadLen); - Hash h = _context.sha().calculateHash(buffer, prefixLen, payloadLen, cache); + Hash h = _context.sha().calculateHash(buffer, prefixLen, payloadLen); int off = 0; DataHelper.toLong(buffer, off, 1, getType()); @@ -217,7 +211,6 @@ public abstract class I2NPMessageImpl extends DataStructureImpl implements I2NPM DataHelper.toLong(buffer, off, 2, payloadLen); off += 2; System.arraycopy(h.getData(), 0, buffer, off, CHECKSUM_LENGTH); - _context.sha().cache().release(cache); long time = _context.clock().now() - start; //if (time > 50) diff --git a/router/java/src/net/i2p/router/RouterVersion.java b/router/java/src/net/i2p/router/RouterVersion.java index ef0953319..8f59afd63 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.183 $ $Date: 2005/04/06 11:38:38 $"; + public final static String ID = "$Revision: 1.184 $ $Date: 2005/04/12 10:22:12 $"; public final static String VERSION = "0.5.0.6"; - public final static long BUILD = 1; + public final static long BUILD = 2; public static void main(String args[]) { System.out.println("I2P Router version: " + VERSION); System.out.println("Router ID: " + RouterVersion.ID); diff --git a/router/java/src/net/i2p/router/transport/udp/InboundMessageState.java b/router/java/src/net/i2p/router/transport/udp/InboundMessageState.java index ba60ebf6a..7167a9978 100644 --- a/router/java/src/net/i2p/router/transport/udp/InboundMessageState.java +++ b/router/java/src/net/i2p/router/transport/udp/InboundMessageState.java @@ -27,7 +27,7 @@ public class InboundMessageState { private long _receiveBegin; /** expire after 30s */ - private static final long MAX_RECEIVE_TIME = 30*1000; + private static final long MAX_RECEIVE_TIME = 10*1000; private static final int MAX_FRAGMENTS = 32; private static final ByteCache _fragmentCache = ByteCache.getInstance(64, 2048); diff --git a/router/java/src/net/i2p/router/transport/udp/OutboundMessageFragments.java b/router/java/src/net/i2p/router/transport/udp/OutboundMessageFragments.java index 82cd9698d..fcc43492c 100644 --- a/router/java/src/net/i2p/router/transport/udp/OutboundMessageFragments.java +++ b/router/java/src/net/i2p/router/transport/udp/OutboundMessageFragments.java @@ -119,6 +119,7 @@ public class OutboundMessageFragments { if (state.isComplete()) { _activeMessages.remove(i); _transport.succeeded(state.getMessage()); + state.releaseResources(); i--; } else if (state.isExpired()) { _activeMessages.remove(i); @@ -132,6 +133,7 @@ public class OutboundMessageFragments { if (_log.shouldLog(Log.WARN)) _log.warn("Unable to send an expired direct message: " + state); } + state.releaseResources(); i--; } else if (state.getPushCount() > MAX_VOLLEYS) { _activeMessages.remove(i); @@ -147,8 +149,8 @@ public class OutboundMessageFragments { if (_log.shouldLog(Log.WARN)) _log.warn("Unable to send a direct message after too many volleys: " + state); } + state.releaseResources(); i--; - } } } @@ -182,6 +184,7 @@ public class OutboundMessageFragments { _transport.failed(state.getMessage()); if (_log.shouldLog(Log.WARN)) _log.warn("Peer disconnected for " + state); + state.releaseResources(); i--; } else { if (!state.isFragmented()) { @@ -210,7 +213,7 @@ public class OutboundMessageFragments { if (state.getPushCount() != oldVolley) { _context.statManager().addRateData("udp.sendVolleyTime", state.getLifetime(), state.getFragmentCount()); - state.setNextSendTime(now + (1000-(now%1000)) + _context.random().nextInt(2000)); + state.setNextSendTime(now + (1000-(now%1000)) + _context.random().nextInt(4000)); } else { if (peer.getSendWindowBytesRemaining() > 0) state.setNextSendTime(now); @@ -316,7 +319,9 @@ public class OutboundMessageFragments { if ( (numSends > 1) && (state.getPeer() != null) ) state.getPeer().congestionOccurred(); _transport.succeeded(state.getMessage()); - return state.getFragmentCount(); + int numFragments = state.getFragmentCount(); + state.releaseResources(); + return numFragments; } else { if (_log.shouldLog(Log.ERROR)) _log.error("Received an ACK for a message not pending: " + messageId); @@ -360,6 +365,7 @@ public class OutboundMessageFragments { _context.statManager().addRateData("udp.sendConfirmTime", state.getLifetime(), state.getLifetime()); _context.statManager().addRateData("udp.sendConfirmFragments", state.getFragmentCount(), state.getLifetime()); _transport.succeeded(state.getMessage()); + state.releaseResources(); } } } diff --git a/router/java/src/net/i2p/router/transport/udp/OutboundMessageState.java b/router/java/src/net/i2p/router/transport/udp/OutboundMessageState.java index b38d2a82c..0c67a2e12 100644 --- a/router/java/src/net/i2p/router/transport/udp/OutboundMessageState.java +++ b/router/java/src/net/i2p/router/transport/udp/OutboundMessageState.java @@ -91,6 +91,11 @@ public class OutboundMessageState { _log.debug("Raw byte array for " + _messageId + ": " + Base64.encode(_messageBuf.getData(), 0, len)); } + public void releaseResources() { + _cache.release(_messageBuf); + _messageBuf = null; + } + public OutNetMessage getMessage() { return _message; } public long getMessageId() { return _messageId; } public PeerState getPeer() { return _peer; } diff --git a/router/java/src/net/i2p/router/transport/udp/PacketBuilder.java b/router/java/src/net/i2p/router/transport/udp/PacketBuilder.java index 609eb3d4c..d91e10703 100644 --- a/router/java/src/net/i2p/router/transport/udp/PacketBuilder.java +++ b/router/java/src/net/i2p/router/transport/udp/PacketBuilder.java @@ -77,7 +77,7 @@ public class PacketBuilder { off += 16 - (off % 16); packet.getPacket().setLength(off); authenticate(packet, peer.getCurrentCipherKey(), peer.getCurrentMACKey()); - setTo(packet, peer.getRemoteIP(), peer.getRemotePort()); + setTo(packet, peer.getRemoteIPAddress(), peer.getRemotePort()); return packet; } @@ -119,7 +119,7 @@ public class PacketBuilder { off += 16 - (off % 16); packet.getPacket().setLength(off); authenticate(packet, peer.getCurrentCipherKey(), peer.getCurrentMACKey()); - setTo(packet, peer.getRemoteIP(), peer.getRemotePort()); + setTo(packet, peer.getRemoteIPAddress(), peer.getRemotePort()); return packet; } @@ -137,8 +137,9 @@ public class PacketBuilder { */ public UDPPacket buildSessionCreatedPacket(InboundEstablishState state, int externalPort, SessionKey ourIntroKey) { UDPPacket packet = UDPPacket.acquire(_context); + InetAddress to = null; try { - packet.getPacket().setAddress(InetAddress.getByAddress(state.getSentIP())); + to = InetAddress.getByAddress(state.getSentIP()); } catch (UnknownHostException uhe) { if (_log.shouldLog(Log.ERROR)) _log.error("How did we think this was a valid IP? " + state.getRemoteHostInfo()); @@ -209,7 +210,7 @@ public class PacketBuilder { off += 16 - (off % 16); packet.getPacket().setLength(off); authenticate(packet, ourIntroKey, ourIntroKey, iv); - setTo(packet, state.getSentIP(), state.getSentPort()); + setTo(packet, to, state.getSentPort()); _ivCache.release(iv); return packet; } @@ -228,8 +229,9 @@ public class PacketBuilder { */ public UDPPacket buildSessionRequestPacket(OutboundEstablishState state) { UDPPacket packet = UDPPacket.acquire(_context); + InetAddress to = null; try { - packet.getPacket().setAddress(InetAddress.getByAddress(state.getSentIP())); + to = InetAddress.getByAddress(state.getSentIP()); } catch (UnknownHostException uhe) { if (_log.shouldLog(Log.ERROR)) _log.error("How did we think this was a valid IP? " + state.getRemoteHostInfo()); @@ -266,7 +268,7 @@ public class PacketBuilder { off += 16 - (off % 16); packet.getPacket().setLength(off); authenticate(packet, state.getIntroKey(), state.getIntroKey()); - setTo(packet, state.getSentIP(), state.getSentPort()); + setTo(packet, to, state.getSentPort()); return packet; } @@ -303,8 +305,9 @@ public class PacketBuilder { */ public UDPPacket buildSessionConfirmedPacket(OutboundEstablishState state, int fragmentNum, int numFragments, byte identity[]) { UDPPacket packet = UDPPacket.acquire(_context); + InetAddress to = null; try { - packet.getPacket().setAddress(InetAddress.getByAddress(state.getSentIP())); + to = InetAddress.getByAddress(state.getSentIP()); } catch (UnknownHostException uhe) { if (_log.shouldLog(Log.ERROR)) _log.error("How did we think this was a valid IP? " + state.getRemoteHostInfo()); @@ -370,19 +373,13 @@ public class PacketBuilder { authenticate(packet, state.getIntroKey(), state.getIntroKey()); } - setTo(packet, state.getSentIP(), state.getSentPort()); + setTo(packet, to, state.getSentPort()); return packet; } - private void setTo(UDPPacket packet, byte ip[], int port) { - try { - InetAddress to = InetAddress.getByAddress(ip); - packet.getPacket().setAddress(to); - packet.getPacket().setPort(port); - } catch (UnknownHostException uhe) { - if (_log.shouldLog(Log.ERROR)) - _log.error("Invalid IP? ", uhe); - } + private void setTo(UDPPacket packet, InetAddress ip, int port) { + packet.getPacket().setAddress(ip); + packet.getPacket().setPort(port); } /** diff --git a/router/java/src/net/i2p/router/transport/udp/PacketHandler.java b/router/java/src/net/i2p/router/transport/udp/PacketHandler.java index b2f76c3df..92ba1989e 100644 --- a/router/java/src/net/i2p/router/transport/udp/PacketHandler.java +++ b/router/java/src/net/i2p/router/transport/udp/PacketHandler.java @@ -29,7 +29,7 @@ public class PacketHandler { private InboundMessageFragments _inbound; private boolean _keepReading; - private static final int NUM_HANDLERS = 4; + private static final int NUM_HANDLERS = 1; public PacketHandler(RouterContext ctx, UDPTransport transport, UDPEndpoint endpoint, EstablishmentManager establisher, InboundMessageFragments inbound) { _context = ctx; diff --git a/router/java/src/net/i2p/router/transport/udp/PeerState.java b/router/java/src/net/i2p/router/transport/udp/PeerState.java index 93d8da5bf..3c6d4928d 100644 --- a/router/java/src/net/i2p/router/transport/udp/PeerState.java +++ b/router/java/src/net/i2p/router/transport/udp/PeerState.java @@ -4,6 +4,7 @@ import java.util.ArrayList; import java.util.List; import java.net.InetAddress; +import java.net.UnknownHostException; import net.i2p.I2PAppContext; import net.i2p.data.Hash; @@ -89,6 +90,8 @@ public class PeerState { private int _slowStartThreshold; /** what IP is the peer sending and receiving packets on? */ private byte[] _remoteIP; + /** cached IP address */ + private transient InetAddress _remoteIPAddress; /** what port is the peer sending and receiving packets on? */ private int _remotePort; /** cached remoteIP + port, used to find the peerState by remote info */ @@ -214,6 +217,17 @@ public class PeerState { public int getSendWindowBytesRemaining() { return _sendWindowBytesRemaining; } /** what IP is the peer sending and receiving packets on? */ public byte[] getRemoteIP() { return _remoteIP; } + public InetAddress getRemoteIPAddress() { + if (_remoteIPAddress == null) { + try { + _remoteIPAddress = InetAddress.getByAddress(_remoteIP); + } catch (UnknownHostException uhe) { + if (_log.shouldLog(Log.ERROR)) + _log.error("Invalid IP? ", uhe); + } + } + return _remoteIPAddress; + } /** what port is the peer sending and receiving packets on? */ public int getRemotePort() { return _remotePort; } /** if we need to contact them, do we need to talk to an introducer? */ @@ -325,6 +339,7 @@ public class PeerState { /** what IP+port is the peer sending and receiving packets on? */ public void setRemoteAddress(byte ip[], int port) { _remoteIP = ip; + _remoteIPAddress = null; _remotePort = port; _remoteHostString = calculateRemoteHostString(ip, port); } @@ -391,7 +406,7 @@ public class PeerState { if (_sendWindowBytes <= _slowStartThreshold) { _sendWindowBytes += bytesACKed; } else { - double prob = bytesACKed / _sendWindowBytes; + double prob = ((double)bytesACKed) / ((double)_sendWindowBytes); if (_context.random().nextDouble() <= prob) _sendWindowBytes += bytesACKed; } diff --git a/router/java/src/net/i2p/router/transport/udp/UDPFlooder.java b/router/java/src/net/i2p/router/transport/udp/UDPFlooder.java index c737e31e1..8daaaa351 100644 --- a/router/java/src/net/i2p/router/transport/udp/UDPFlooder.java +++ b/router/java/src/net/i2p/router/transport/udp/UDPFlooder.java @@ -19,12 +19,14 @@ class UDPFlooder implements Runnable { private UDPTransport _transport; private List _peers; private boolean _alive; + private static final byte _floodData[] = new byte[4096]; public UDPFlooder(RouterContext ctx, UDPTransport transport) { _context = ctx; _log = ctx.logManager().getLog(UDPFlooder.class); _transport = transport; _peers = new ArrayList(4); + ctx.random().nextBytes(_floodData); } public void addPeer(PeerState peer) { @@ -61,8 +63,8 @@ class UDPFlooder implements Runnable { for (int i = 0; i < _peers.size(); i++) { PeerState peer = (PeerState)_peers.get(i); DataMessage m = new DataMessage(_context); - byte data[] = new byte[4096]; - _context.random().nextBytes(data); + byte data[] = _floodData; // new byte[4096]; + //_context.random().nextBytes(data); m.setData(data); m.setMessageExpiration(_context.clock().now() + 10*1000); m.setUniqueId(_context.random().nextLong(I2NPMessage.MAX_ID_VALUE)); 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 4fd392b34..d7e1403ae 100644 --- a/router/java/src/net/i2p/router/transport/udp/UDPPacket.java +++ b/router/java/src/net/i2p/router/transport/udp/UDPPacket.java @@ -8,6 +8,7 @@ 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,6 +30,7 @@ public class UDPPacket { private long _initializeTime; private long _expiration; private byte[] _data; + private ByteArray _dataBuf; private static final List _packetCache; static { @@ -61,11 +63,13 @@ public class UDPPacket { private static final int MAX_VALIDATE_SIZE = MAX_PACKET_SIZE; private static final ByteCache _validateCache = ByteCache.getInstance(16, MAX_VALIDATE_SIZE); private static final ByteCache _ivCache = ByteCache.getInstance(16, IV_SIZE); - + private static final ByteCache _dataCache = ByteCache.getInstance(64, MAX_PACKET_SIZE); + private UDPPacket(I2PAppContext ctx) { _context = ctx; _log = ctx.logManager().getLog(UDPPacket.class); - _data = new byte[MAX_PACKET_SIZE]; + _dataBuf = _dataCache.acquire(); + _data = _dataBuf.getData(); _packet = new DatagramPacket(_data, MAX_PACKET_SIZE); _initializeTime = _context.clock().now(); } @@ -113,7 +117,7 @@ public class UDPPacket { DataHelper.toLong(buf.getData(), off, 2, payloadLength); off += 2; - Hash calculated = _context.hmac().calculate(macKey, buf.getData(), 0, off); + Hash hmac = _context.hmac().calculate(macKey, buf.getData(), 0, off); if (_log.shouldLog(Log.DEBUG)) { StringBuffer str = new StringBuffer(128); @@ -123,12 +127,12 @@ public class UDPPacket { str.append("\nIV2: ").append(Base64.encode(_data, MAC_SIZE, IV_SIZE)); str.append("\nlen: ").append(DataHelper.fromLong(buf.getData(), payloadLength + IV_SIZE, 2)); str.append("\nMAC key: ").append(macKey.toBase64()); - str.append("\ncalc HMAC: ").append(calculated.toBase64()); + str.append("\ncalc HMAC: ").append(Base64.encode(hmac.getData())); str.append("\nread HMAC: ").append(Base64.encode(_data, _packet.getOffset(), MAC_SIZE)); str.append("\nraw: ").append(Base64.encode(_data, _packet.getOffset(), _packet.getLength())); _log.debug(str.toString()); } - eq = DataHelper.eq(calculated.getData(), 0, _data, _packet.getOffset(), MAC_SIZE); + eq = DataHelper.eq(hmac.getData(), 0, _data, _packet.getOffset(), MAC_SIZE); } else { if (_log.shouldLog(Log.WARN)) _log.warn("Payload length is " + payloadLength); @@ -177,6 +181,7 @@ public class UDPPacket { } public void release() { + _dataCache.release(_dataBuf); if (!CACHE) return; synchronized (_packetCache) { _packet.setLength(0); diff --git a/router/java/src/net/i2p/router/transport/udp/UDPSender.java b/router/java/src/net/i2p/router/transport/udp/UDPSender.java index e20cd2c30..ef1592c0a 100644 --- a/router/java/src/net/i2p/router/transport/udp/UDPSender.java +++ b/router/java/src/net/i2p/router/transport/udp/UDPSender.java @@ -139,7 +139,7 @@ public class UDPSender { } // back to the cache - //packet.release(); + packet.release(); } } } diff --git a/router/java/src/net/i2p/router/tunnel/FragmentHandler.java b/router/java/src/net/i2p/router/tunnel/FragmentHandler.java index ae95d0330..496eb930f 100644 --- a/router/java/src/net/i2p/router/tunnel/FragmentHandler.java +++ b/router/java/src/net/i2p/router/tunnel/FragmentHandler.java @@ -5,7 +5,6 @@ import java.util.HashMap; import java.util.Map; import net.i2p.I2PAppContext; -import net.i2p.crypto.SHA256EntryCache; import net.i2p.data.Base64; import net.i2p.data.ByteArray; import net.i2p.data.DataHelper; @@ -138,8 +137,7 @@ public class FragmentHandler { if (_log.shouldLog(Log.DEBUG)) _log.debug("endpoint IV: " + Base64.encode(preV, validLength - HopProcessor.IV_LENGTH, HopProcessor.IV_LENGTH)); - SHA256EntryCache.CacheEntry cache = _context.sha().cache().acquire(TrivialPreprocessor.PREPROCESSED_SIZE); - Hash v = _context.sha().calculateHash(preV, 0, validLength, cache); + Hash v = _context.sha().calculateHash(preV, 0, validLength); //Hash v = _context.sha().calculateHash(preV, 0, validLength); boolean eq = DataHelper.eq(v.getData(), 0, preprocessed, offset + HopProcessor.IV_LENGTH, 4); @@ -152,7 +150,6 @@ public class FragmentHandler { + Base64.encode(preprocessed, offset, length)); } - _context.sha().cache().release(cache); _validateCache.release(ba); if (eq) { diff --git a/router/java/src/net/i2p/router/tunnel/TrivialPreprocessor.java b/router/java/src/net/i2p/router/tunnel/TrivialPreprocessor.java index 62efac9b9..a435e28a4 100644 --- a/router/java/src/net/i2p/router/tunnel/TrivialPreprocessor.java +++ b/router/java/src/net/i2p/router/tunnel/TrivialPreprocessor.java @@ -4,7 +4,6 @@ import java.util.ArrayList; import java.util.List; import net.i2p.I2PAppContext; -import net.i2p.crypto.SHA256EntryCache; import net.i2p.data.Base64; import net.i2p.data.ByteArray; import net.i2p.data.DataHelper; @@ -103,11 +102,9 @@ public class TrivialPreprocessor implements TunnelGateway.QueuePreprocessor { byte iv[] = ivBuf.getData(); // new byte[IV_SIZE]; _context.random().nextBytes(iv); - SHA256EntryCache.CacheEntry cache = _context.sha().cache().acquire(PREPROCESSED_SIZE); - // payload ready, now H(instructions+payload+IV) System.arraycopy(iv, 0, fragments, fragmentLength, IV_SIZE); - Hash h = _context.sha().calculateHash(fragments, 0, fragmentLength + IV_SIZE, cache); + Hash h = _context.sha().calculateHash(fragments, 0, fragmentLength + IV_SIZE); //Hash h = _context.sha().calculateHash(target, 0, offset + IV_SIZE); //_log.debug("before shift: " + Base64.encode(target)); // now shiiiiiift @@ -128,7 +125,6 @@ public class TrivialPreprocessor implements TunnelGateway.QueuePreprocessor { offset += 4; //_log.debug("before pad : " + Base64.encode(target)); - _context.sha().cache().release(cache); _ivCache.release(ivBuf); // fits in a single message, so may be smaller than the full size