diff --git a/history.txt b/history.txt index 8a4443def8d93c9afc2b044fed8373ab5f78972b..5569308c91a023e20db2e29d2f7d302eb58ffab7 100644 --- a/history.txt +++ b/history.txt @@ -1,3 +1,30 @@ +2020-10-15 zzz + * Router: + - More efficient initialization of Noise state + - Destroy ratchet HandshakeState after NS failure + - Add support for ratchet zero key (proposals #144, #156) + +2020-10-12 zzz + * DTG: Enable by default for Linux KDE and LXDE; + Hide option on /configservice if not supported + * New translations for Kurdish, Turkmen, Argentinian Spanish + * NTCP: + - Fix sending termination on idle timeout (ticket #2777) + - Catch possible race IAE in Reader + +2020-10-11 zzz + * Installer: Disable pack200 (ticket #2778) + +2020-10-10 zzz + * i2psnark: Cache length of metainfo + * Transport: Improved IPv6 address validation + +2020-10-09 zzz + * NetDB: + - Don't use DSA-SHA1 routers for lookups, stores, or tunnel peers + - Don't use non-ElGamal routers for lookups or stores + - Prevent DSA-SHA1 routers from auto-floodfill + 2020-10-07 zzz * Build: - Set javac release property (ticket #2775) @@ -5,6 +32,7 @@ - Drop support for Xenial package build - Fix up BOB build configuration - Fix i2psnark standalone build + * i2ptunnel: Filter server response headers even if not compressing 2020-10-03 zzz * Router: Support building tunnels through ECIES routers (proposal 152) diff --git a/router/java/src/net/i2p/router/RouterVersion.java b/router/java/src/net/i2p/router/RouterVersion.java index c10128fe6223a59f4fa2320e38c3309487438a87..fecba78d6973d87e9930d631de787e05fec2a510 100644 --- a/router/java/src/net/i2p/router/RouterVersion.java +++ b/router/java/src/net/i2p/router/RouterVersion.java @@ -18,7 +18,7 @@ public class RouterVersion { /** deprecated */ public final static String ID = "Monotone"; public final static String VERSION = CoreVersion.VERSION; - public final static long BUILD = 6; + public final static long BUILD = 7; /** for example "-test" */ public final static String EXTRA = ""; diff --git a/router/java/src/net/i2p/router/message/GarlicMessageBuilder.java b/router/java/src/net/i2p/router/message/GarlicMessageBuilder.java index 70e7b1eef11761f71b2678b30432fd3fe9883d4d..3e4bcd9709000edac7876f0f354c9f3585f0f1d0 100644 --- a/router/java/src/net/i2p/router/message/GarlicMessageBuilder.java +++ b/router/java/src/net/i2p/router/message/GarlicMessageBuilder.java @@ -275,16 +275,14 @@ public class GarlicMessageBuilder { * Called by OCMJH only. * * @param ctx scope - * @param config how/what to wrap - * @param target public key of the location being garlic routed to (may be null if we - * know the encryptKey and encryptTag) + * @param config how/what to wrap, must have key set with setRecipientPublicKey() * @param callback may be null * @return null if expired or on other errors * @throws IllegalArgumentException on error * @since 0.9.44 */ static GarlicMessage buildECIESMessage(RouterContext ctx, GarlicConfig config, - PublicKey target, Hash from, Destination to, SessionKeyManager skm, + Hash from, Destination to, SessionKeyManager skm, ReplyCallback callback) { PublicKey key = config.getRecipientPublicKey(); if (key.getType() != EncType.ECIES_X25519) @@ -315,7 +313,7 @@ public class GarlicMessageBuilder { log.warn("No SKM for " + from.toBase32()); return null; } - byte encData[] = ctx.eciesEngine().encrypt(cloveSet, target, to, priv, rskm, callback); + byte encData[] = ctx.eciesEngine().encrypt(cloveSet, key, to, priv, rskm, callback); if (encData == null) { if (log.shouldWarn()) log.warn("Encrypt fail for " + from.toBase32()); @@ -334,6 +332,42 @@ public class GarlicMessageBuilder { return msg; } + /** + * Encrypt from an anonymous source. + * ECIES_X25519 only. + * Called by MessageWrapper only. + * + * @param ctx scope + * @param config how/what to wrap, must have key set with setRecipientPublicKey() + * @throws IllegalArgumentException on error + * @since 0.9.48 + */ + public static GarlicMessage buildECIESMessage(RouterContext ctx, GarlicConfig config) { + PublicKey key = config.getRecipientPublicKey(); + if (key.getType() != EncType.ECIES_X25519) + throw new IllegalArgumentException(); + Log log = ctx.logManager().getLog(GarlicMessageBuilder.class); + GarlicMessage msg = new GarlicMessage(ctx); + CloveSet cloveSet = buildECIESCloveSet(ctx, config); + byte encData[] = ctx.eciesEngine().encrypt(cloveSet, key); + if (encData == null) { + if (log.shouldWarn()) + log.warn("Encrypt fail for " + config); + return null; + } + msg.setData(encData); + msg.setMessageExpiration(config.getExpiration()); + long timeFromNow = config.getExpiration() - ctx.clock().now(); + if (timeFromNow < 1*1000) { + if (log.shouldDebug()) + log.debug("Building a message expiring in " + timeFromNow + "ms: " + config, new Exception("created by")); + return null; + } + if (log.shouldDebug()) + log.debug("Built ECIES CloveSet (" + config.getCloveCount() + " cloves) in " + msg); + return msg; + } + /**** private static void noteWrap(RouterContext ctx, GarlicMessage wrapper, GarlicConfig contained) { for (int i = 0; i < contained.getCloveCount(); i++) { diff --git a/router/java/src/net/i2p/router/message/OutboundClientMessageJobHelper.java b/router/java/src/net/i2p/router/message/OutboundClientMessageJobHelper.java index 9d4bc3ea8150e216e353b48d7b19323b4d201363..ac462bcfcee5bc922f6d950262c7533005c83d1c 100644 --- a/router/java/src/net/i2p/router/message/OutboundClientMessageJobHelper.java +++ b/router/java/src/net/i2p/router/message/OutboundClientMessageJobHelper.java @@ -131,7 +131,7 @@ class OutboundClientMessageJobHelper { return null; GarlicMessage msg; if (isECIES) { - msg = GarlicMessageBuilder.buildECIESMessage(ctx, config, recipientPK, from, dest, skm, callback); + msg = GarlicMessageBuilder.buildECIESMessage(ctx, config, from, dest, skm, callback); } else { // no use sending tags unless we have a reply token set up already int tagsToSend = replyToken >= 0 ? (tagsToSendOverride > 0 ? tagsToSendOverride : skm.getTagsToSend()) : 0; @@ -146,6 +146,8 @@ class OutboundClientMessageJobHelper { * Make the top-level config, with a data clove, an optional ack clove, and * an optional leaseset clove. * + * The returned GarlicConfig will have the recipientPublicKey set. + * * @param dataClove may be null for ECIES-layer ack * @param replyTunnel non-null if requireAck is true or bundledReplyLeaseSet is non-null * @param requireAck if true, bundle replyToken in an ack clove diff --git a/router/java/src/net/i2p/router/networkdb/kademlia/MessageWrapper.java b/router/java/src/net/i2p/router/networkdb/kademlia/MessageWrapper.java index d7dca37e1e7926c07dd94ee2ecd57ba2c63a469c..ce5e0af322c1cd00b542f3ceadfdc111b8350d7f 100644 --- a/router/java/src/net/i2p/router/networkdb/kademlia/MessageWrapper.java +++ b/router/java/src/net/i2p/router/networkdb/kademlia/MessageWrapper.java @@ -125,16 +125,13 @@ public class MessageWrapper { /** * Garlic wrap a message from nobody, destined for a router, * to hide the contents from the OBEP. - * Forces ElGamal. + * Forces full asymmetric encryption. * - * @param to must be ELGAMAL_2048 EncType + * @param to must be ELGAMAL_2048 or ECIES_X25519 EncType * @return null on encrypt failure * @since 0.9.5 */ static GarlicMessage wrap(RouterContext ctx, I2NPMessage m, RouterInfo to) { - PublicKey key = to.getIdentity().getPublicKey(); - if (key.getType() != EncType.ELGAMAL_2048) - return null; PayloadGarlicConfig payload = new PayloadGarlicConfig(Certificate.NULL_CERT, ctx.random().nextLong(I2NPMessage.MAX_ID_VALUE), @@ -142,9 +139,19 @@ public class MessageWrapper { DeliveryInstructions.LOCAL, m); payload.setRecipient(to); - SessionKey sentKey = ctx.keyGenerator().generateSessionKey(); - GarlicMessage msg = GarlicMessageBuilder.buildMessage(ctx, payload, null, - key, sentKey, null); + PublicKey key = to.getIdentity().getPublicKey(); + EncType type = key.getType(); + GarlicMessage msg; + if (type == EncType.ELGAMAL_2048) { + SessionKey sentKey = ctx.keyGenerator().generateSessionKey(); + msg = GarlicMessageBuilder.buildMessage(ctx, payload, null, key, sentKey, null); + } else if (type == EncType.ECIES_X25519) { + payload.setRecipientPublicKey(key); + msg = GarlicMessageBuilder.buildECIESMessage(ctx, payload); + } else { + // unsupported + msg = null; + } return msg; }