Router: MessageWrapper.wrap() and GMB support for ECIES (prop. #156 WIP)

NetDB parts still TODO
Remove PK param from GMB.buildECIESMessage(), already in config
This commit is contained in:
zzz
2020-10-15 11:50:11 +00:00
parent b2f060795c
commit e54950e02e
5 changed files with 86 additions and 15 deletions

View File

@ -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 2020-10-07 zzz
* Build: * Build:
- Set javac release property (ticket #2775) - Set javac release property (ticket #2775)
@ -5,6 +32,7 @@
- Drop support for Xenial package build - Drop support for Xenial package build
- Fix up BOB build configuration - Fix up BOB build configuration
- Fix i2psnark standalone build - Fix i2psnark standalone build
* i2ptunnel: Filter server response headers even if not compressing
2020-10-03 zzz 2020-10-03 zzz
* Router: Support building tunnels through ECIES routers (proposal 152) * Router: Support building tunnels through ECIES routers (proposal 152)

View File

@ -18,7 +18,7 @@ public class RouterVersion {
/** deprecated */ /** deprecated */
public final static String ID = "Monotone"; public final static String ID = "Monotone";
public final static String VERSION = CoreVersion.VERSION; public final static String VERSION = CoreVersion.VERSION;
public final static long BUILD = 6; public final static long BUILD = 7;
/** for example "-test" */ /** for example "-test" */
public final static String EXTRA = ""; public final static String EXTRA = "";

View File

@ -275,16 +275,14 @@ public class GarlicMessageBuilder {
* Called by OCMJH only. * Called by OCMJH only.
* *
* @param ctx scope * @param ctx scope
* @param config how/what to wrap * @param config how/what to wrap, must have key set with setRecipientPublicKey()
* @param target public key of the location being garlic routed to (may be null if we
* know the encryptKey and encryptTag)
* @param callback may be null * @param callback may be null
* @return null if expired or on other errors * @return null if expired or on other errors
* @throws IllegalArgumentException on error * @throws IllegalArgumentException on error
* @since 0.9.44 * @since 0.9.44
*/ */
static GarlicMessage buildECIESMessage(RouterContext ctx, GarlicConfig config, static GarlicMessage buildECIESMessage(RouterContext ctx, GarlicConfig config,
PublicKey target, Hash from, Destination to, SessionKeyManager skm, Hash from, Destination to, SessionKeyManager skm,
ReplyCallback callback) { ReplyCallback callback) {
PublicKey key = config.getRecipientPublicKey(); PublicKey key = config.getRecipientPublicKey();
if (key.getType() != EncType.ECIES_X25519) if (key.getType() != EncType.ECIES_X25519)
@ -315,7 +313,7 @@ public class GarlicMessageBuilder {
log.warn("No SKM for " + from.toBase32()); log.warn("No SKM for " + from.toBase32());
return null; 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 (encData == null) {
if (log.shouldWarn()) if (log.shouldWarn())
log.warn("Encrypt fail for " + from.toBase32()); log.warn("Encrypt fail for " + from.toBase32());
@ -334,6 +332,42 @@ public class GarlicMessageBuilder {
return msg; 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) { private static void noteWrap(RouterContext ctx, GarlicMessage wrapper, GarlicConfig contained) {
for (int i = 0; i < contained.getCloveCount(); i++) { for (int i = 0; i < contained.getCloveCount(); i++) {

View File

@ -131,7 +131,7 @@ class OutboundClientMessageJobHelper {
return null; return null;
GarlicMessage msg; GarlicMessage msg;
if (isECIES) { if (isECIES) {
msg = GarlicMessageBuilder.buildECIESMessage(ctx, config, recipientPK, from, dest, skm, callback); msg = GarlicMessageBuilder.buildECIESMessage(ctx, config, from, dest, skm, callback);
} else { } else {
// no use sending tags unless we have a reply token set up already // no use sending tags unless we have a reply token set up already
int tagsToSend = replyToken >= 0 ? (tagsToSendOverride > 0 ? tagsToSendOverride : skm.getTagsToSend()) : 0; 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 * Make the top-level config, with a data clove, an optional ack clove, and
* an optional leaseset clove. * an optional leaseset clove.
* *
* The returned GarlicConfig will have the recipientPublicKey set.
*
* @param dataClove may be null for ECIES-layer ack * @param dataClove may be null for ECIES-layer ack
* @param replyTunnel non-null if requireAck is true or bundledReplyLeaseSet is non-null * @param replyTunnel non-null if requireAck is true or bundledReplyLeaseSet is non-null
* @param requireAck if true, bundle replyToken in an ack clove * @param requireAck if true, bundle replyToken in an ack clove

View File

@ -125,16 +125,13 @@ public class MessageWrapper {
/** /**
* Garlic wrap a message from nobody, destined for a router, * Garlic wrap a message from nobody, destined for a router,
* to hide the contents from the OBEP. * 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 * @return null on encrypt failure
* @since 0.9.5 * @since 0.9.5
*/ */
static GarlicMessage wrap(RouterContext ctx, I2NPMessage m, RouterInfo to) { 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, PayloadGarlicConfig payload = new PayloadGarlicConfig(Certificate.NULL_CERT,
ctx.random().nextLong(I2NPMessage.MAX_ID_VALUE), ctx.random().nextLong(I2NPMessage.MAX_ID_VALUE),
@ -142,9 +139,19 @@ public class MessageWrapper {
DeliveryInstructions.LOCAL, m); DeliveryInstructions.LOCAL, m);
payload.setRecipient(to); payload.setRecipient(to);
PublicKey key = to.getIdentity().getPublicKey();
EncType type = key.getType();
GarlicMessage msg;
if (type == EncType.ELGAMAL_2048) {
SessionKey sentKey = ctx.keyGenerator().generateSessionKey(); SessionKey sentKey = ctx.keyGenerator().generateSessionKey();
GarlicMessage msg = GarlicMessageBuilder.buildMessage(ctx, payload, null, msg = GarlicMessageBuilder.buildMessage(ctx, payload, null, key, sentKey, null);
key, sentKey, null); } else if (type == EncType.ECIES_X25519) {
payload.setRecipientPublicKey(key);
msg = GarlicMessageBuilder.buildECIESMessage(ctx, payload);
} else {
// unsupported
msg = null;
}
return msg; return msg;
} }