diff --git a/router/java/src/net/i2p/router/tunnel/BuildMessageGenerator.java b/router/java/src/net/i2p/router/tunnel/BuildMessageGenerator.java index 0cc9b5523..491be3af9 100644 --- a/router/java/src/net/i2p/router/tunnel/BuildMessageGenerator.java +++ b/router/java/src/net/i2p/router/tunnel/BuildMessageGenerator.java @@ -96,12 +96,10 @@ public abstract class BuildMessageGenerator { } SessionKey layerKey = hopConfig.getLayerKey(); SessionKey ivKey = hopConfig.getIVKey(); - SessionKey replyKey = hopConfig.getReplyKey(); - byte iv[] = hopConfig.getReplyIV(); + SessionKey replyKey = cfg.getAESReplyKey(hop); + byte iv[] = cfg.getAESReplyIV(hop); if (iv == null) { - iv = new byte[BuildRequestRecord.IV_SIZE]; - ctx.random().nextBytes(iv); - hopConfig.setReplyIV(iv); + throw new IllegalStateException(); } boolean isInGW = (cfg.isInbound() && (hop == 0)); boolean isOutEnd = (!cfg.isInbound() && (hop + 1 >= cfg.getLength())); @@ -152,9 +150,8 @@ public abstract class BuildMessageGenerator { // ok, now decrypt the record with all of the reply keys from cfg.getConfig(0) through hop-1 int stop = (cfg.isInbound() ? 0 : 1); for (int j = hop-1; j >= stop; j--) { - HopConfig hopConfig = cfg.getConfig(j); - SessionKey key = hopConfig.getReplyKey(); - byte iv[] = hopConfig.getReplyIV(); + SessionKey key = cfg.getAESReplyKey(j); + byte iv[] = cfg.getAESReplyIV(j); // corrupts the SDS ctx.aes().decrypt(rec.getData(), 0, rec.getData(), 0, key, iv, TunnelBuildMessage.RECORD_SIZE); } diff --git a/router/java/src/net/i2p/router/tunnel/BuildReplyHandler.java b/router/java/src/net/i2p/router/tunnel/BuildReplyHandler.java index 6ba5681e3..730d67f8e 100644 --- a/router/java/src/net/i2p/router/tunnel/BuildReplyHandler.java +++ b/router/java/src/net/i2p/router/tunnel/BuildReplyHandler.java @@ -108,9 +108,8 @@ public class BuildReplyHandler { end++; // do we need to adjust this for the endpoint? for (int j = start; j >= end; j--) { - HopConfig hopConfig = cfg.getConfig(j); - SessionKey replyKey = hopConfig.getReplyKey(); - byte replyIV[] = hopConfig.getReplyIV(); + SessionKey replyKey = cfg.getAESReplyKey(j); + byte replyIV[] = cfg.getAESReplyIV(j); if (log.shouldLog(Log.DEBUG)) { log.debug(reply.getUniqueId() + ": Decrypting record " + recordNum + "/" + hop + "/" + j + " with replyKey " + replyKey.toBase64() + "/" + Base64.encode(replyIV) + ": " + cfg); diff --git a/router/java/src/net/i2p/router/tunnel/HopConfig.java b/router/java/src/net/i2p/router/tunnel/HopConfig.java index b19e7b1bb..e1dc40b77 100644 --- a/router/java/src/net/i2p/router/tunnel/HopConfig.java +++ b/router/java/src/net/i2p/router/tunnel/HopConfig.java @@ -37,9 +37,6 @@ public class HopConfig { //private int _messagesSent; //private int _oldMessagesSent; - /** IV length for {@link #getReplyIV} */ - public static final int REPLY_IV_LENGTH = 16; - public HopConfig() { _creation = -1; _expiration = -1; @@ -90,35 +87,6 @@ public class HopConfig { public SessionKey getIVKey() { return _ivKey; } public void setIVKey(SessionKey key) { _ivKey = key; } - /** - * Key to encrypt the reply sent for the tunnel creation crypto. - * Not used for participating tunnels, will return null, - * candidate for moving to TunnelCreatorConfig. - * @return key or null - */ - public SessionKey getReplyKey() { return _replyKey; } - public void setReplyKey(SessionKey key) { _replyKey = key; } - - /** - * IV used to encrypt the reply sent for the tunnel creation crypto. - * Not used for participating tunnels, will return null, - * candidate for moving to TunnelCreatorConfig. - * - * @return 16 bytes or null - */ - public byte[] getReplyIV() { return _replyIV; } - - /** - * IV used to encrypt the reply sent for the tunnel creation crypto - * - * @throws IllegalArgumentException if not 16 bytes - */ - public void setReplyIV(byte[] iv) { - if (iv.length != REPLY_IV_LENGTH) - throw new IllegalArgumentException(); - _replyIV = iv; - } - /** when does this tunnel expire (in ms since the epoch)? */ public long getExpiration() { return _expiration; } public void setExpiration(long when) { _expiration = when; } diff --git a/router/java/src/net/i2p/router/tunnel/TunnelCreatorConfig.java b/router/java/src/net/i2p/router/tunnel/TunnelCreatorConfig.java index 175f27544..fb8bb6cdb 100644 --- a/router/java/src/net/i2p/router/tunnel/TunnelCreatorConfig.java +++ b/router/java/src/net/i2p/router/tunnel/TunnelCreatorConfig.java @@ -41,8 +41,16 @@ public abstract class TunnelCreatorConfig implements TunnelInfo { private long _peakThroughputCurrentTotal; private long _peakThroughputLastCoallesce = System.currentTimeMillis(); private Hash _blankHash; - private SessionKey[] _replyKeys; - private byte[][] _replyADs; + private SessionKey[] _ChaReplyKeys; + private byte[][] _ChaReplyADs; + private final SessionKey[] _AESReplyKeys; + private final byte[][] _AESReplyIVs; + + /** + * IV length for {@link #getAESReplyIV} + * @since 0.9.48 moved from HopConfig + */ + public static final int REPLY_IV_LENGTH = 16; // Make configurable? - but can't easily get to pool options from here private static final int MAX_CONSECUTIVE_TEST_FAILURES = 3; @@ -70,6 +78,8 @@ public abstract class TunnelCreatorConfig implements TunnelInfo { } _isInbound = isInbound; _destination = destination; + _AESReplyKeys = new SessionKey[length]; + _AESReplyIVs = new byte[length][]; } /** @@ -243,6 +253,36 @@ public abstract class TunnelCreatorConfig implements TunnelInfo { */ public void setPriority(int priority) { _priority = priority; } + /** + * Key and IV to encrypt the reply sent for the tunnel creation crypto. + * + * @throws IllegalArgumentException if iv not 16 bytes + * @since 0.9.48 moved from HopConfig + */ + public void setAESReplyKeys(int hop, SessionKey key, byte[] iv) { + if (iv.length != REPLY_IV_LENGTH) + throw new IllegalArgumentException(); + _AESReplyKeys[hop] = key; + _AESReplyIVs[hop] = iv; + } + + /** + * Key to encrypt the reply sent for the tunnel creation crypto. + * + * @return key or null + * @throws IllegalArgumentException if iv not 16 bytes + * @since 0.9.48 moved from HopConfig + */ + public SessionKey getAESReplyKey(int hop) { return _AESReplyKeys[hop]; } + + /** + * IV used to encrypt the reply sent for the tunnel creation crypto. + * + * @return 16 bytes or null + * @since 0.9.48 moved from HopConfig + */ + public byte[] getAESReplyIV(int hop) { return _AESReplyIVs[hop]; } + /** * Checksum for blank record * @since 0.9.48 @@ -260,12 +300,12 @@ public abstract class TunnelCreatorConfig implements TunnelInfo { * @since 0.9.48 */ public void setChaChaReplyKeys(int hop, SessionKey key, byte[] ad) { - if (_replyKeys == null) { - _replyKeys = new SessionKey[_config.length]; - _replyADs = new byte[_config.length][]; + if (_ChaReplyKeys == null) { + _ChaReplyKeys = new SessionKey[_config.length]; + _ChaReplyADs = new byte[_config.length][]; } - _replyKeys[hop] = key; - _replyADs[hop] = ad; + _ChaReplyKeys[hop] = key; + _ChaReplyADs[hop] = ad; } /** @@ -273,9 +313,9 @@ public abstract class TunnelCreatorConfig implements TunnelInfo { * @since 0.9.48 */ public boolean isEC(int hop) { - if (_replyKeys == null) + if (_ChaReplyKeys == null) return false; - return _replyKeys[hop] != null; + return _ChaReplyKeys[hop] != null; } /** @@ -283,9 +323,9 @@ public abstract class TunnelCreatorConfig implements TunnelInfo { * @since 0.9.48 */ public SessionKey getChaChaReplyKey(int hop) { - if (_replyKeys == null) + if (_ChaReplyKeys == null) return null; - return _replyKeys[hop]; + return _ChaReplyKeys[hop]; } /** @@ -293,9 +333,9 @@ public abstract class TunnelCreatorConfig implements TunnelInfo { * @since 0.9.48 */ public byte[] getChaChaReplyAD(int hop) { - if (_replyADs == null) + if (_ChaReplyADs == null) return null; - return _replyADs[hop]; + return _ChaReplyADs[hop]; } @Override diff --git a/router/java/src/net/i2p/router/tunnel/pool/BuildRequestor.java b/router/java/src/net/i2p/router/tunnel/pool/BuildRequestor.java index 65a198d83..9c4891c86 100644 --- a/router/java/src/net/i2p/router/tunnel/pool/BuildRequestor.java +++ b/router/java/src/net/i2p/router/tunnel/pool/BuildRequestor.java @@ -19,6 +19,7 @@ import net.i2p.router.TunnelManagerFacade; import net.i2p.router.TunnelPoolSettings; import net.i2p.router.tunnel.BuildMessageGenerator; import net.i2p.router.tunnel.HopConfig; +import net.i2p.router.tunnel.TunnelCreatorConfig; import net.i2p.util.Log; import net.i2p.util.VersionComparator; @@ -104,10 +105,9 @@ abstract class BuildRequestor { if (i > 0) cfg.getConfig(i-1).setSendTunnelId(hop.getReceiveTunnelId()); - byte iv[] = new byte[16]; + byte iv[] = new byte[TunnelCreatorConfig.REPLY_IV_LENGTH]; ctx.random().nextBytes(iv); - hop.setReplyIV(iv); - hop.setReplyKey(ctx.keyGenerator().generateSessionKey()); + cfg.setAESReplyKeys(i, ctx.keyGenerator().generateSessionKey(), iv); } // This is in BuildExecutor.buildTunnel() now // And it was overwritten by the one in createTunnelBuildMessage() anyway! diff --git a/router/java/test/junit/net/i2p/router/tunnel/BuildMessageTestStandalone.java b/router/java/test/junit/net/i2p/router/tunnel/BuildMessageTestStandalone.java index 649cbe7ba..e640491c5 100644 --- a/router/java/test/junit/net/i2p/router/tunnel/BuildMessageTestStandalone.java +++ b/router/java/test/junit/net/i2p/router/tunnel/BuildMessageTestStandalone.java @@ -172,10 +172,9 @@ public class BuildMessageTestStandalone extends TestCase { hop.setExpiration(now+10*60*1000); hop.setIVKey(ctx.keyGenerator().generateSessionKey()); hop.setLayerKey(ctx.keyGenerator().generateSessionKey()); - hop.setReplyKey(ctx.keyGenerator().generateSessionKey()); byte iv[] = new byte[BuildRequestRecord.IV_SIZE]; Arrays.fill(iv, (byte)i); // consistent for repeatability - hop.setReplyIV(iv); + cfg.setAESReplyKeys(i, ctx.keyGenerator().generateSessionKey(), iv); hop.setReceiveTunnelId(new TunnelId(i+1)); } return cfg;