diff --git a/core/java/src/net/i2p/crypto/CryptixAESEngine.java b/core/java/src/net/i2p/crypto/CryptixAESEngine.java index 4febf45e47a6a320e0b7fc5b58ef248cf5ef00e3..6d8e0da07579f0c4012feece0173d3dfa173766f 100644 --- a/core/java/src/net/i2p/crypto/CryptixAESEngine.java +++ b/core/java/src/net/i2p/crypto/CryptixAESEngine.java @@ -21,8 +21,8 @@ import net.i2p.I2PAppContext; import net.i2p.data.ByteArray; import net.i2p.data.DataHelper; import net.i2p.data.SessionKey; -import net.i2p.util.ByteCache; import net.i2p.util.Log; +import net.i2p.util.SimpleByteCache; /** * Wrapper for AES cypher operation using Cryptix's Rijndael implementation. Implements @@ -38,8 +38,6 @@ public class CryptixAESEngine extends AESEngine { // keys are now cached in the SessionKey objects //private CryptixAESKeyCache _cache; - private static final ByteCache _prevCache = ByteCache.getInstance(16, 16); - /**** see comments for main() below private static final boolean USE_SYSTEM_AES; static { @@ -166,10 +164,8 @@ public class CryptixAESEngine extends AESEngine { int numblock = length / 16; if (length % 16 != 0) numblock++; - ByteArray prevA = _prevCache.acquire(); - byte prev[] = prevA.getData(); - ByteArray curA = _prevCache.acquire(); - byte cur[] = curA.getData(); + byte prev[] = SimpleByteCache.acquire(16); + byte cur[] = SimpleByteCache.acquire(16); System.arraycopy(iv, ivOffset, prev, 0, 16); for (int x = 0; x < numblock; x++) { @@ -190,8 +186,8 @@ public class CryptixAESEngine extends AESEngine { } */ - _prevCache.release(prevA); - _prevCache.release(curA); + SimpleByteCache.release(prev); + SimpleByteCache.release(cur); } /** encrypt exactly 16 bytes using the session key diff --git a/core/java/src/net/i2p/data/SDSCache.java b/core/java/src/net/i2p/data/SDSCache.java index 474e96479142c57289e6863fe3acc22634c6d5d6..e8f7d302d61498b0c1cab5d9221d88ebd2a95903 100644 --- a/core/java/src/net/i2p/data/SDSCache.java +++ b/core/java/src/net/i2p/data/SDSCache.java @@ -98,6 +98,11 @@ public class SDSCache<V extends SimpleDataStructure> { } /** + * WARNING - If the SDS is found in the cache, the passed-in + * byte array will be returned to the SimpleByteCache for reuse. + * Do NOT save a reference to the passed-in data, or use or modify it, + * after this call. + * * @param data non-null, the byte array for the SimpleDataStructure * @return the cached value if available, otherwise * makes a new object and returns it diff --git a/core/java/src/net/i2p/util/ByteCache.java b/core/java/src/net/i2p/util/ByteCache.java index d4ea7132d5bf00e8664b142b3e7224ad25fd22ac..7253a472e89a8fa3630863b093abffdc4854b5aa 100644 --- a/core/java/src/net/i2p/util/ByteCache.java +++ b/core/java/src/net/i2p/util/ByteCache.java @@ -13,22 +13,14 @@ import net.i2p.data.ByteArray; * Cache the objects frequently used to reduce memory churn. The ByteArray * should be held onto as long as the data referenced in it is needed. * + * For small arrays where the management of valid bytes in ByteArray + * and prezeroing isn't required, use SimpleByteArray instead. + * * Heap size control - survey of usage (April 2010) : * * <pre> Size Max MaxMem From - 16 16 256 CryptixAESEngine - 16 32 512 BloomFilterIVValidator - 16 64 1K UDP PacketBuilder - 16 128 2K tunnel HopProcessor - 16 128 2K tunnel TrivialPreprocessor - 16 128 2K tunnel InboundEndpointProcessor - 16 128 2K tunnel OutboundGatewayProcessor - - 32 64 2K UDP PacketBuilder - 32 128 4K tunnel TrivialPreprocessor - 1K 32 32K tunnel TrivialPreprocessor 1K 512 512K tunnel FragmentHandler 1K 512 512K I2NP TunnelDataMessage diff --git a/core/java/src/net/i2p/util/SimpleByteCache.java b/core/java/src/net/i2p/util/SimpleByteCache.java index 01d116abea1c04eb23fc0d35ab8cce987c15d98d..b41f9ad9b5bf87acedd4aebd7ad8d591b262732f 100644 --- a/core/java/src/net/i2p/util/SimpleByteCache.java +++ b/core/java/src/net/i2p/util/SimpleByteCache.java @@ -18,7 +18,7 @@ public final class SimpleByteCache { private static final Map<Integer, SimpleByteCache> _caches = new ConcurrentHashMap(8); - private static final int DEFAULT_SIZE = 16; + private static final int DEFAULT_SIZE = 64; /** up to this, use ABQ to minimize object churn and for performance; above this, use LBQ for two locks */ private static final int MAX_FOR_ABQ = 64; 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 8af7c67323d7bc5351179c9d3f0ed9abbc70d945..d6bb57806345e1a0e770aaf0a667e777e2a1599b 100644 --- a/router/java/src/net/i2p/router/transport/udp/PacketBuilder.java +++ b/router/java/src/net/i2p/router/transport/udp/PacketBuilder.java @@ -16,9 +16,9 @@ import net.i2p.data.Hash; import net.i2p.data.RouterIdentity; import net.i2p.data.SessionKey; import net.i2p.data.Signature; -import net.i2p.util.ByteCache; import net.i2p.util.Addresses; import net.i2p.util.Log; +import net.i2p.util.SimpleByteCache; /** * Big ol' class to do all our packet formatting. The UDPPackets generated are @@ -102,9 +102,6 @@ class PacketBuilder { private final Log _log; private final UDPTransport _transport; - private static final ByteCache _ivCache = ByteCache.getInstance(64, UDPPacket.IV_SIZE); - private static final ByteCache _hmacCache = ByteCache.getInstance(64, Hash.HASH_LENGTH); - /** * For debugging and stats only - does not go out on the wire. * These are chosen to be higher than the highest I2NP message type, @@ -607,12 +604,12 @@ class PacketBuilder { // ok, now the full data is in there, but we also need to encrypt // the signature, which means we need the IV - ByteArray iv = _ivCache.acquire(); - _context.random().nextBytes(iv.getData()); + byte[] iv = SimpleByteCache.acquire(UDPPacket.IV_SIZE); + _context.random().nextBytes(iv); int encrWrite = Signature.SIGNATURE_BYTES + 8; int sigBegin = off - encrWrite; - _context.aes().encrypt(data, sigBegin, data, sigBegin, state.getCipherKey(), iv.getData(), encrWrite); + _context.aes().encrypt(data, sigBegin, data, sigBegin, state.getCipherKey(), iv, encrWrite); // pad up so we're on the encryption boundary if ( (off % 16) != 0) @@ -620,7 +617,7 @@ class PacketBuilder { packet.getPacket().setLength(off); authenticate(packet, ourIntroKey, ourIntroKey, iv); setTo(packet, to, state.getSentPort()); - _ivCache.release(iv); + SimpleByteCache.release(iv); packet.setMessageType(TYPE_CREAT); return packet; } @@ -1290,10 +1287,10 @@ class PacketBuilder { * @param macKey key to generate the, er, MAC */ private void authenticate(UDPPacket packet, SessionKey cipherKey, SessionKey macKey) { - ByteArray iv = _ivCache.acquire(); - _context.random().nextBytes(iv.getData()); + byte[] iv = SimpleByteCache.acquire(UDPPacket.IV_SIZE); + _context.random().nextBytes(iv); authenticate(packet, cipherKey, macKey, iv); - _ivCache.release(iv); + SimpleByteCache.release(iv); } /** @@ -1308,38 +1305,38 @@ class PacketBuilder { * @param macKey key to generate the, er, MAC * @param iv IV to deliver */ - private void authenticate(UDPPacket packet, SessionKey cipherKey, SessionKey macKey, ByteArray iv) { + private void authenticate(UDPPacket packet, SessionKey cipherKey, SessionKey macKey, byte[] iv) { long before = System.currentTimeMillis(); int encryptOffset = packet.getPacket().getOffset() + UDPPacket.IV_SIZE + UDPPacket.MAC_SIZE; int encryptSize = packet.getPacket().getLength() - UDPPacket.IV_SIZE - UDPPacket.MAC_SIZE - packet.getPacket().getOffset(); byte data[] = packet.getPacket().getData(); - _context.aes().encrypt(data, encryptOffset, data, encryptOffset, cipherKey, iv.getData(), encryptSize); + _context.aes().encrypt(data, encryptOffset, data, encryptOffset, cipherKey, iv, encryptSize); // ok, now we need to prepare things for the MAC, which requires reordering int off = packet.getPacket().getOffset(); System.arraycopy(data, encryptOffset, data, off, encryptSize); off += encryptSize; - System.arraycopy(iv.getData(), 0, data, off, UDPPacket.IV_SIZE); + System.arraycopy(iv, 0, data, off, UDPPacket.IV_SIZE); off += UDPPacket.IV_SIZE; DataHelper.toLong(data, off, 2, encryptSize ^ PROTOCOL_VERSION); int hmacOff = packet.getPacket().getOffset(); int hmacLen = encryptSize + UDPPacket.IV_SIZE + 2; //Hash hmac = _context.hmac().calculate(macKey, data, hmacOff, hmacLen); - ByteArray ba = _hmacCache.acquire(); - _context.hmac().calculate(macKey, data, hmacOff, hmacLen, ba.getData(), 0); + byte[] ba = SimpleByteCache.acquire(Hash.HASH_LENGTH); + _context.hmac().calculate(macKey, data, hmacOff, hmacLen, ba, 0); if (_log.shouldLog(Log.DEBUG)) _log.debug("Authenticating " + packet.getPacket().getLength() + - "\nIV: " + Base64.encode(iv.getData()) + - "\nraw mac: " + Base64.encode(ba.getData()) + + "\nIV: " + Base64.encode(iv) + + "\nraw mac: " + Base64.encode(ba) + "\nMAC key: " + macKey); // ok, now lets put it back where it belongs... System.arraycopy(data, hmacOff, data, encryptOffset, encryptSize); //System.arraycopy(hmac.getData(), 0, data, hmacOff, UDPPacket.MAC_SIZE); - System.arraycopy(ba.getData(), 0, data, hmacOff, UDPPacket.MAC_SIZE); - System.arraycopy(iv.getData(), 0, data, hmacOff + UDPPacket.MAC_SIZE, UDPPacket.IV_SIZE); - _hmacCache.release(ba); + System.arraycopy(ba, 0, data, hmacOff, UDPPacket.MAC_SIZE); + System.arraycopy(iv, 0, data, hmacOff + UDPPacket.MAC_SIZE, UDPPacket.IV_SIZE); + SimpleByteCache.release(ba); long timeToAuth = System.currentTimeMillis() - before; _context.statManager().addRateData("udp.packetAuthTime", timeToAuth, timeToAuth); if (timeToAuth > 100) diff --git a/router/java/src/net/i2p/router/tunnel/BloomFilterIVValidator.java b/router/java/src/net/i2p/router/tunnel/BloomFilterIVValidator.java index 58944818ea120c6da4a91a02fb7847934e5614d8..857c7fdecd846f9988e98bf4901fb5ac73cdf07f 100644 --- a/router/java/src/net/i2p/router/tunnel/BloomFilterIVValidator.java +++ b/router/java/src/net/i2p/router/tunnel/BloomFilterIVValidator.java @@ -5,7 +5,7 @@ import net.i2p.data.DataHelper; import net.i2p.router.RouterContext; import net.i2p.router.util.DecayingBloomFilter; import net.i2p.router.util.DecayingHashSet; -import net.i2p.util.ByteCache; +import net.i2p.util.SimpleByteCache; /** * Manage the IV validation for all of the router's tunnels by way of a big @@ -15,7 +15,6 @@ import net.i2p.util.ByteCache; class BloomFilterIVValidator implements IVValidator { private final RouterContext _context; private final DecayingBloomFilter _filter; - private final ByteCache _ivXorCache = ByteCache.getInstance(32, HopProcessor.IV_LENGTH); /** * After 2*halflife, an entry is completely forgotten from the bloom filter. @@ -57,10 +56,10 @@ class BloomFilterIVValidator implements IVValidator { } public boolean receiveIV(byte ivData[], int ivOffset, byte payload[], int payloadOffset) { - ByteArray buf = _ivXorCache.acquire(); - DataHelper.xor(ivData, ivOffset, payload, payloadOffset, buf.getData(), 0, HopProcessor.IV_LENGTH); - boolean dup = _filter.add(buf.getData()); - _ivXorCache.release(buf); + byte[] buf = SimpleByteCache.acquire(HopProcessor.IV_LENGTH); + DataHelper.xor(ivData, ivOffset, payload, payloadOffset, buf, 0, HopProcessor.IV_LENGTH); + boolean dup = _filter.add(buf); + SimpleByteCache.release(buf); if (dup) _context.statManager().addRateData("tunnel.duplicateIV", 1); return !dup; // return true if it is OK, false if it isn't } diff --git a/router/java/src/net/i2p/router/tunnel/HopProcessor.java b/router/java/src/net/i2p/router/tunnel/HopProcessor.java index 792288a773188ad130cb51a994d8e868235498f9..386f96d798709d6fa41cd90d374b489b69e6dc50 100644 --- a/router/java/src/net/i2p/router/tunnel/HopProcessor.java +++ b/router/java/src/net/i2p/router/tunnel/HopProcessor.java @@ -2,7 +2,6 @@ package net.i2p.router.tunnel; import net.i2p.I2PAppContext; import net.i2p.data.Hash; -import net.i2p.util.ByteCache; import net.i2p.util.Log; /** @@ -29,7 +28,6 @@ class HopProcessor { */ static final boolean USE_DOUBLE_IV_ENCRYPTION = true; static final int IV_LENGTH = 16; - private static final ByteCache _cache = ByteCache.getInstance(128, IV_LENGTH); /** @deprecated unused */ public HopProcessor(I2PAppContext ctx, HopConfig config) { diff --git a/router/java/src/net/i2p/router/tunnel/InboundEndpointProcessor.java b/router/java/src/net/i2p/router/tunnel/InboundEndpointProcessor.java index bd362055b6f8a7af6c18467e9dcd67358132c625..2fd0b26c07ff9792ec12f7ff11ab111d5a85bf5c 100644 --- a/router/java/src/net/i2p/router/tunnel/InboundEndpointProcessor.java +++ b/router/java/src/net/i2p/router/tunnel/InboundEndpointProcessor.java @@ -3,8 +3,8 @@ package net.i2p.router.tunnel; import net.i2p.data.ByteArray; import net.i2p.data.Hash; import net.i2p.router.RouterContext; -import net.i2p.util.ByteCache; import net.i2p.util.Log; +import net.i2p.util.SimpleByteCache; /** * Receive the inbound tunnel message, removing all of the layers @@ -21,7 +21,6 @@ class InboundEndpointProcessor { private final IVValidator _validator; static final boolean USE_ENCRYPTION = HopProcessor.USE_ENCRYPTION; - private static final ByteCache _cache = ByteCache.getInstance(128, HopProcessor.IV_LENGTH); /** @deprecated unused */ public InboundEndpointProcessor(RouterContext ctx, TunnelCreatorConfig cfg) { @@ -54,8 +53,7 @@ class InboundEndpointProcessor { return false; } - ByteArray ba = _cache.acquire(); - byte iv[] = ba.getData(); //new byte[HopProcessor.IV_LENGTH]; + byte iv[] = SimpleByteCache.acquire(HopProcessor.IV_LENGTH); System.arraycopy(orig, offset, iv, 0, iv.length); //if (_config.getLength() > 1) // _log.debug("IV at inbound endpoint before decrypt: " + Base64.encode(iv)); @@ -64,7 +62,7 @@ class InboundEndpointProcessor { if (!ok) { if (_log.shouldLog(Log.WARN)) _log.warn("Invalid IV, dropping at IBEP " + _config); - _cache.release(ba); + SimpleByteCache.release(iv); return false; } @@ -72,7 +70,7 @@ class InboundEndpointProcessor { if (USE_ENCRYPTION) decrypt(_context, _config, iv, orig, offset, length); - _cache.release(ba); + SimpleByteCache.release(iv); if (_config.getLength() > 0) { int rtt = 0; // dunno... may not be related to an rtt @@ -91,8 +89,7 @@ class InboundEndpointProcessor { */ private void decrypt(RouterContext ctx, TunnelCreatorConfig cfg, byte iv[], byte orig[], int offset, int length) { //Log log = ctx.logManager().getLog(OutboundGatewayProcessor.class); - ByteArray ba = _cache.acquire(); - byte cur[] = ba.getData(); // new byte[HopProcessor.IV_LENGTH]; // so we dont malloc + byte cur[] = SimpleByteCache.acquire(HopProcessor.IV_LENGTH); for (int i = cfg.getLength()-2; i >= 0; i--) { // dont include the endpoint, since that is the creator OutboundGatewayProcessor.decrypt(ctx, iv, orig, offset, length, cur, cfg.getConfig(i)); //if (log.shouldLog(Log.DEBUG)) { @@ -100,7 +97,7 @@ class InboundEndpointProcessor { //log.debug("hop " + i + ": " + Base64.encode(orig, offset + HopProcessor.IV_LENGTH, length - HopProcessor.IV_LENGTH)); //} } - _cache.release(ba); + SimpleByteCache.release(cur); } } diff --git a/router/java/src/net/i2p/router/tunnel/OutboundGatewayProcessor.java b/router/java/src/net/i2p/router/tunnel/OutboundGatewayProcessor.java index 4deb3bed173881d94f5eaedc7f8a8cd68a522a66..3d86d230ff75b27e70690bfc1c434bcfffcd81aa 100644 --- a/router/java/src/net/i2p/router/tunnel/OutboundGatewayProcessor.java +++ b/router/java/src/net/i2p/router/tunnel/OutboundGatewayProcessor.java @@ -3,8 +3,8 @@ package net.i2p.router.tunnel; import net.i2p.I2PAppContext; import net.i2p.data.Base64; import net.i2p.data.ByteArray; -import net.i2p.util.ByteCache; import net.i2p.util.Log; +import net.i2p.util.SimpleByteCache; /** * Turn the preprocessed tunnel data into something that can be delivered to the @@ -18,7 +18,6 @@ class OutboundGatewayProcessor { private final TunnelCreatorConfig _config; static final boolean USE_ENCRYPTION = HopProcessor.USE_ENCRYPTION; - private static final ByteCache _cache = ByteCache.getInstance(128, HopProcessor.IV_LENGTH); public OutboundGatewayProcessor(I2PAppContext ctx, TunnelCreatorConfig cfg) { _context = ctx; @@ -35,8 +34,7 @@ class OutboundGatewayProcessor { * @param length how much of orig can we write to (must be a multiple of 16). */ public void process(byte orig[], int offset, int length) { - ByteArray ba = _cache.acquire(); - byte iv[] = ba.getData(); // new byte[HopProcessor.IV_LENGTH]; + byte iv[] = SimpleByteCache.acquire(HopProcessor.IV_LENGTH); //_context.random().nextBytes(iv); //System.arraycopy(iv, 0, orig, offset, HopProcessor.IV_LENGTH); System.arraycopy(orig, offset, iv, 0, HopProcessor.IV_LENGTH); @@ -49,7 +47,7 @@ class OutboundGatewayProcessor { decrypt(_context, _config, iv, orig, offset, length); if (_log.shouldLog(Log.DEBUG)) _log.debug("finished processing the preprocessed data"); - _cache.release(ba); + SimpleByteCache.release(iv); } /** @@ -58,8 +56,7 @@ class OutboundGatewayProcessor { */ private void decrypt(I2PAppContext ctx, TunnelCreatorConfig cfg, byte iv[], byte orig[], int offset, int length) { Log log = ctx.logManager().getLog(OutboundGatewayProcessor.class); - ByteArray ba = _cache.acquire(); - byte cur[] = ba.getData(); // new byte[HopProcessor.IV_LENGTH]; // so we dont malloc + byte cur[] = SimpleByteCache.acquire(HopProcessor.IV_LENGTH); for (int i = cfg.getLength()-1; i >= 1; i--) { // dont include hop 0, since that is the creator decrypt(ctx, iv, orig, offset, length, cur, cfg.getConfig(i)); if (log.shouldLog(Log.DEBUG)) { @@ -67,7 +64,7 @@ class OutboundGatewayProcessor { //log.debug("hop " + i + ": " + Base64.encode(orig, offset + HopProcessor.IV_LENGTH, length - HopProcessor.IV_LENGTH)); } } - _cache.release(ba); + SimpleByteCache.release(cur); } /** diff --git a/router/java/src/net/i2p/router/tunnel/TrivialPreprocessor.java b/router/java/src/net/i2p/router/tunnel/TrivialPreprocessor.java index c9655e6873120a1e1a6225ab6d76105592c6fe13..e6edc3c85e35f46fb4cba1d183658c1b211d6ed5 100644 --- a/router/java/src/net/i2p/router/tunnel/TrivialPreprocessor.java +++ b/router/java/src/net/i2p/router/tunnel/TrivialPreprocessor.java @@ -9,6 +9,7 @@ import net.i2p.data.Hash; import net.i2p.router.RouterContext; import net.i2p.util.ByteCache; import net.i2p.util.Log; +import net.i2p.util.SimpleByteCache; /** * Do the simplest thing possible for preprocessing - for each message available, @@ -33,9 +34,6 @@ class TrivialPreprocessor implements TunnelGateway.QueuePreprocessor { */ protected static final ByteCache _dataCache = ByteCache.getInstance(32, PREPROCESSED_SIZE); - private static final ByteCache _ivCache = ByteCache.getInstance(128, IV_SIZE); - private static final ByteCache _hashCache = ByteCache.getInstance(128, Hash.HASH_LENGTH); - public TrivialPreprocessor(RouterContext ctx) { _context = ctx; _log = ctx.logManager().getLog(getClass()); @@ -63,16 +61,15 @@ class TrivialPreprocessor implements TunnelGateway.QueuePreprocessor { * @param fragmentLength fragments[0:fragmentLength] is used */ protected void preprocess(byte fragments[], int fragmentLength) { - ByteArray ivBuf = _ivCache.acquire(); - byte iv[] = ivBuf.getData(); // new byte[IV_SIZE]; + byte iv[] = SimpleByteCache.acquire(IV_SIZE); _context.random().nextBytes(iv); // payload ready, now H(instructions+payload+IV) System.arraycopy(iv, 0, fragments, fragmentLength, IV_SIZE); - ByteArray hashBuf = _hashCache.acquire(); + byte[] hashBuf = SimpleByteCache.acquire(Hash.HASH_LENGTH); //Hash h = _context.sha().calculateHash(fragments, 0, fragmentLength + IV_SIZE); - _context.sha().calculateHash(fragments, 0, fragmentLength + IV_SIZE, hashBuf.getData(), 0); + _context.sha().calculateHash(fragments, 0, fragmentLength + IV_SIZE, hashBuf, 0); //Hash h = _context.sha().calculateHash(target, 0, offset + IV_SIZE); //_log.debug("before shift: " + Base64.encode(target)); @@ -91,12 +88,12 @@ class TrivialPreprocessor implements TunnelGateway.QueuePreprocessor { System.arraycopy(iv, 0, fragments, offset, IV_SIZE); offset += IV_SIZE; //System.arraycopy(h.getData(), 0, fragments, offset, 4); - System.arraycopy(hashBuf.getData(), 0, fragments, offset, 4); + System.arraycopy(hashBuf, 0, fragments, offset, 4); offset += 4; //_log.debug("before pad : " + Base64.encode(target)); - _hashCache.release(hashBuf); - _ivCache.release(ivBuf); + SimpleByteCache.release(hashBuf); + SimpleByteCache.release(iv); // fits in a single message, so may be smaller than the full size int numPadBytes = PREPROCESSED_SIZE // max