From cc271de7df5f8431872dc7c4801f56aac753bd79 Mon Sep 17 00:00:00 2001 From: zzz Date: Mon, 22 Jul 2013 14:25:30 +0000 Subject: [PATCH] * BuildReplyHandler: - Make non-static - Don't pollute Hash cache with build response record hashes - Use SimpleByteCache - cleanups --- .../i2p/router/tunnel/BuildReplyHandler.java | 58 ++++++++++++------- .../i2p/router/tunnel/pool/BuildHandler.java | 4 +- 2 files changed, 40 insertions(+), 22 deletions(-) diff --git a/router/java/src/net/i2p/router/tunnel/BuildReplyHandler.java b/router/java/src/net/i2p/router/tunnel/BuildReplyHandler.java index 1b25138630..b2c7c84b30 100644 --- a/router/java/src/net/i2p/router/tunnel/BuildReplyHandler.java +++ b/router/java/src/net/i2p/router/tunnel/BuildReplyHandler.java @@ -10,22 +10,34 @@ import net.i2p.data.Hash; import net.i2p.data.SessionKey; import net.i2p.data.i2np.TunnelBuildReplyMessage; import net.i2p.util.Log; +import net.i2p.util.SimpleByteCache; /** * Decrypt the layers of a tunnel build reply message, determining whether the individual * hops agreed to participate in the tunnel, or if not, why not. * */ -public abstract class BuildReplyHandler { +public class BuildReplyHandler { + + private final I2PAppContext ctx; + private final Log log; /** - * Decrypt the tunnel build reply records. This overwrites the contents of the reply + * @since 0.9.8 (methods were static before) + */ + public BuildReplyHandler(I2PAppContext context) { + ctx = context; + log = ctx.logManager().getLog(BuildReplyHandler.class); + } + + /** + * Decrypt the tunnel build reply records. This overwrites the contents of the reply. + * Thread safe (no state). * * @return status for the records (in record order), or null if the replies were not valid. Fake records * always have 0 as their value */ - public static int[] decrypt(I2PAppContext ctx, TunnelBuildReplyMessage reply, TunnelCreatorConfig cfg, List recordOrder) { - Log log = ctx.logManager().getLog(BuildReplyHandler.class); + public int[] decrypt(TunnelBuildReplyMessage reply, TunnelCreatorConfig cfg, List recordOrder) { if (reply.getRecordCount() != recordOrder.size()) { // somebody messed with us log.error("Corrupted build reply, expected " + recordOrder.size() + " records, got " + reply.getRecordCount()); @@ -40,7 +52,7 @@ public abstract class BuildReplyHandler { log.debug(reply.getUniqueId() + ": no need to decrypt record " + i + "/" + hop + ", as its out of range: " + cfg); rv[i] = 0; } else { - int ok = decryptRecord(ctx, reply, cfg, i, hop); + int ok = decryptRecord(reply, cfg, i, hop); if (ok == -1) { if (log.shouldLog(Log.WARN)) log.warn(reply.getUniqueId() + ": decrypt record " + i + "/" + hop + " was not ok: " + cfg); @@ -60,14 +72,14 @@ public abstract class BuildReplyHandler { * * @return -1 on decrypt failure */ - private static int decryptRecord(I2PAppContext ctx, TunnelBuildReplyMessage reply, TunnelCreatorConfig cfg, int recordNum, int hop) { - Log log = ctx.logManager().getLog(BuildReplyHandler.class); + private int decryptRecord(TunnelBuildReplyMessage reply, TunnelCreatorConfig cfg, int recordNum, int hop) { if (BuildMessageGenerator.isBlank(cfg, hop)) { if (log.shouldLog(Log.DEBUG)) log.debug(reply.getUniqueId() + ": Record " + recordNum + "/" + hop + " is fake, so consider it valid..."); return 0; } ByteArray rec = reply.getRecord(recordNum); + byte[] data = rec.getData(); int off = rec.getOffset(); int start = cfg.getLength() - 1; if (cfg.isInbound()) @@ -78,29 +90,33 @@ public abstract class BuildReplyHandler { SessionKey replyKey = hopConfig.getReplyKey(); byte replyIV[] = hopConfig.getReplyIV().getData(); int replyIVOff = hopConfig.getReplyIV().getOffset(); - if (log.shouldLog(Log.DEBUG)) + if (log.shouldLog(Log.DEBUG)) { log.debug(reply.getUniqueId() + ": Decrypting record " + recordNum + "/" + hop + "/" + j + " with replyKey " + replyKey.toBase64() + "/" + Base64.encode(replyIV, replyIVOff, 16) + ": " + cfg); + log.debug(reply.getUniqueId() + ": before decrypt("+ off + "-"+(off+rec.getValid())+"): " + Base64.encode(data, off, rec.getValid())); + log.debug(reply.getUniqueId() + ": Full reply rec: offset=" + off + ", sz=" + data.length + "/" + rec.getValid() + ", data=" + Base64.encode(data, off, TunnelBuildReplyMessage.RECORD_SIZE)); + } + ctx.aes().decrypt(data, off, data, off, replyKey, replyIV, replyIVOff, TunnelBuildReplyMessage.RECORD_SIZE); if (log.shouldLog(Log.DEBUG)) - log.debug(reply.getUniqueId() + ": before decrypt("+ off + "-"+(off+rec.getValid())+"): " + Base64.encode(rec.getData(), off, rec.getValid())); - - if (log.shouldLog(Log.DEBUG)) - log.debug(reply.getUniqueId() + ": Full reply rec: offset=" + off + ", sz=" + rec.getData().length + "/" + rec.getValid() + ", data=" + Base64.encode(rec.getData(), off, TunnelBuildReplyMessage.RECORD_SIZE)); - ctx.aes().decrypt(rec.getData(), off, rec.getData(), off, replyKey, replyIV, replyIVOff, TunnelBuildReplyMessage.RECORD_SIZE); - if (log.shouldLog(Log.DEBUG)) - log.debug(reply.getUniqueId() + ": after decrypt: " + Base64.encode(rec.getData(), off, rec.getValid())); + log.debug(reply.getUniqueId() + ": after decrypt: " + Base64.encode(data, off, rec.getValid())); } // ok, all of the layered encryption is stripped, so lets verify it // (formatted per BuildResponseRecord.create) - Hash h = ctx.sha().calculateHash(rec.getData(), off + Hash.HASH_LENGTH, TunnelBuildReplyMessage.RECORD_SIZE-Hash.HASH_LENGTH); - if (!DataHelper.eq(h.getData(), 0, rec.getData(), off, Hash.HASH_LENGTH)) { + // don't cache the result + //Hash h = ctx.sha().calculateHash(data, off + Hash.HASH_LENGTH, TunnelBuildReplyMessage.RECORD_SIZE-Hash.HASH_LENGTH); + byte[] h = SimpleByteCache.acquire(Hash.HASH_LENGTH); + ctx.sha().calculateHash(data, off + Hash.HASH_LENGTH, TunnelBuildReplyMessage.RECORD_SIZE-Hash.HASH_LENGTH, h, 0); + boolean ok = DataHelper.eq(h, 0, data, off, Hash.HASH_LENGTH); + if (!ok) { if (log.shouldLog(Log.DEBUG)) - log.debug(reply.getUniqueId() + ": Failed verification on " + recordNum + "/" + hop + ": " + h.toBase64() + " calculated, " + - Base64.encode(rec.getData(), off, Hash.HASH_LENGTH) + " expected\n" + - "Record: " + Base64.encode(rec.getData(), off+Hash.HASH_LENGTH, TunnelBuildReplyMessage.RECORD_SIZE-Hash.HASH_LENGTH)); + log.debug(reply.getUniqueId() + ": Failed verification on " + recordNum + "/" + hop + ": " + Base64.encode(h) + " calculated, " + + Base64.encode(data, off, Hash.HASH_LENGTH) + " expected\n" + + "Record: " + Base64.encode(data, off+Hash.HASH_LENGTH, TunnelBuildReplyMessage.RECORD_SIZE-Hash.HASH_LENGTH)); + SimpleByteCache.release(h); return -1; } else { - int rv = (int)DataHelper.fromLong(rec.getData(), off + TunnelBuildReplyMessage.RECORD_SIZE - 1, 1); + SimpleByteCache.release(h); + int rv = (int)DataHelper.fromLong(data, off + TunnelBuildReplyMessage.RECORD_SIZE - 1, 1); if (log.shouldLog(Log.DEBUG)) log.debug(reply.getUniqueId() + ": Verified: " + rv + " for record " + recordNum + "/" + hop); return rv; diff --git a/router/java/src/net/i2p/router/tunnel/pool/BuildHandler.java b/router/java/src/net/i2p/router/tunnel/pool/BuildHandler.java index b50a1c80c1..a2f936965b 100644 --- a/router/java/src/net/i2p/router/tunnel/pool/BuildHandler.java +++ b/router/java/src/net/i2p/router/tunnel/pool/BuildHandler.java @@ -59,6 +59,7 @@ class BuildHandler implements Runnable { private final BuildMessageProcessor _processor; private final RequestThrottler _requestThrottler; private final ParticipatingThrottler _throttler; + private final BuildReplyHandler _buildReplyHandler; private final AtomicInteger _currentLookups = new AtomicInteger(); private volatile boolean _isRunning; @@ -134,6 +135,7 @@ class BuildHandler implements Runnable { _requestThrottler = new RequestThrottler(ctx); // used for previous and next hops, for successful builds only _throttler = new ParticipatingThrottler(ctx); + _buildReplyHandler = new BuildReplyHandler(ctx); _buildMessageHandlerJob = new TunnelBuildMessageHandlerJob(ctx); _buildReplyMessageHandlerJob = new TunnelBuildReplyMessageHandlerJob(ctx); TunnelBuildMessageHandlerJobBuilder tbmhjb = new TunnelBuildMessageHandlerJobBuilder(); @@ -246,7 +248,7 @@ class BuildHandler implements Runnable { _log.info(msg.getUniqueId() + ": Handling the reply after " + rtt + ", delayed " + delay + " waiting for " + cfg); List order = cfg.getReplyOrder(); - int statuses[] = BuildReplyHandler.decrypt(_context, msg, cfg, order); + int statuses[] = _buildReplyHandler.decrypt(msg, cfg, order); if (statuses != null) { boolean allAgree = true; // For each peer in the tunnel