forked from I2P_Developers/i2p.i2p
OCMOSJ: Select target key in LS based on local client's support
Hook new SKMs and ending into Garlic Message encryption/decryption Remove unused wrappedKey param from buildMessage() Log tweaks and javadoc fixes WIP
This commit is contained in:
@ -14,17 +14,22 @@ import java.util.Date;
|
|||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
|
import net.i2p.crypto.EncType;
|
||||||
import net.i2p.crypto.SessionKeyManager;
|
import net.i2p.crypto.SessionKeyManager;
|
||||||
import net.i2p.data.DataFormatException;
|
import net.i2p.data.DataFormatException;
|
||||||
import net.i2p.data.DataHelper;
|
import net.i2p.data.DataHelper;
|
||||||
import net.i2p.data.Hash;
|
import net.i2p.data.Hash;
|
||||||
|
import net.i2p.data.PrivateKey;
|
||||||
import net.i2p.data.PublicKey;
|
import net.i2p.data.PublicKey;
|
||||||
import net.i2p.data.SessionKey;
|
import net.i2p.data.SessionKey;
|
||||||
import net.i2p.data.SessionTag;
|
import net.i2p.data.SessionTag;
|
||||||
import net.i2p.data.i2np.GarlicClove;
|
import net.i2p.data.i2np.GarlicClove;
|
||||||
import net.i2p.data.i2np.GarlicMessage;
|
import net.i2p.data.i2np.GarlicMessage;
|
||||||
import net.i2p.data.i2np.I2NPMessage;
|
import net.i2p.data.i2np.I2NPMessage;
|
||||||
|
import net.i2p.router.LeaseSetKeys;
|
||||||
import net.i2p.router.RouterContext;
|
import net.i2p.router.RouterContext;
|
||||||
|
import net.i2p.router.crypto.ratchet.MuxedSKM;
|
||||||
|
import net.i2p.router.crypto.ratchet.RatchetSKM;
|
||||||
import net.i2p.util.Log;
|
import net.i2p.util.Log;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -34,10 +39,14 @@ import net.i2p.util.Log;
|
|||||||
public class GarlicMessageBuilder {
|
public class GarlicMessageBuilder {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* ELGAMAL_2048 only.
|
||||||
|
*
|
||||||
* @param local non-null; do not use this method for the router's SessionKeyManager
|
* @param local non-null; do not use this method for the router's SessionKeyManager
|
||||||
* @param minTagOverride 0 for no override, > 0 to override SKM's settings
|
* @param minTagOverride 0 for no override, > 0 to override SKM's settings
|
||||||
*/
|
*/
|
||||||
static boolean needsTags(RouterContext ctx, PublicKey key, Hash local, int minTagOverride) {
|
static boolean needsTags(RouterContext ctx, PublicKey key, Hash local, int minTagOverride) {
|
||||||
|
if (key.getType() == EncType.ECIES_X25519)
|
||||||
|
return false;
|
||||||
SessionKeyManager skm = ctx.clientManager().getClientSessionKeyManager(local);
|
SessionKeyManager skm = ctx.clientManager().getClientSessionKeyManager(local);
|
||||||
if (skm == null)
|
if (skm == null)
|
||||||
return true;
|
return true;
|
||||||
@ -51,6 +60,7 @@ public class GarlicMessageBuilder {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Unused and probably a bad idea.
|
* Unused and probably a bad idea.
|
||||||
|
* ELGAMAL_2048 only.
|
||||||
*
|
*
|
||||||
* Used below only on a recursive call if the garlic message contains a garlic message.
|
* Used below only on a recursive call if the garlic message contains a garlic message.
|
||||||
* We don't need the SessionKey or SesssionTags returned
|
* We don't need the SessionKey or SesssionTags returned
|
||||||
@ -60,6 +70,7 @@ public class GarlicMessageBuilder {
|
|||||||
*
|
*
|
||||||
* @param ctx scope
|
* @param ctx scope
|
||||||
* @param config how/what to wrap
|
* @param config how/what to wrap
|
||||||
|
* @return null if expired
|
||||||
* @throws IllegalArgumentException on error
|
* @throws IllegalArgumentException on error
|
||||||
*/
|
*/
|
||||||
private static GarlicMessage buildMessage(RouterContext ctx, GarlicConfig config) {
|
private static GarlicMessage buildMessage(RouterContext ctx, GarlicConfig config) {
|
||||||
@ -70,14 +81,17 @@ public class GarlicMessageBuilder {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Now unused, since we have to generate a reply token first in OCMOSJ but we don't know if tags are required yet.
|
* Now unused, since we have to generate a reply token first in OCMOSJ but we don't know if tags are required yet.
|
||||||
|
* ELGAMAL_2048 only.
|
||||||
*
|
*
|
||||||
* @param ctx scope
|
* @param ctx scope
|
||||||
* @param config how/what to wrap
|
* @param config how/what to wrap
|
||||||
* @param wrappedKey output parameter that will be filled with the sessionKey used
|
* @param wrappedKey non-null with null data,
|
||||||
|
* output parameter that will be filled with the SessionKey used
|
||||||
* @param wrappedTags Output parameter that will be filled with the sessionTags used.
|
* @param wrappedTags Output parameter that will be filled with the sessionTags used.
|
||||||
If non-empty on return you must call skm.tagsDelivered() when sent
|
If non-empty on return you must call skm.tagsDelivered() when sent
|
||||||
and then call skm.tagsAcked() or skm.failTags() later.
|
and then call skm.tagsAcked() or skm.failTags() later.
|
||||||
* @param skm non-null
|
* @param skm non-null
|
||||||
|
* @return null if expired
|
||||||
* @throws IllegalArgumentException on error
|
* @throws IllegalArgumentException on error
|
||||||
*/
|
*/
|
||||||
public static GarlicMessage buildMessage(RouterContext ctx, GarlicConfig config, SessionKey wrappedKey, Set<SessionTag> wrappedTags,
|
public static GarlicMessage buildMessage(RouterContext ctx, GarlicConfig config, SessionKey wrappedKey, Set<SessionTag> wrappedTags,
|
||||||
@ -94,11 +108,13 @@ public class GarlicMessageBuilder {
|
|||||||
***/
|
***/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* called by OCMJH
|
* ELGAMAL_2048 only.
|
||||||
|
* Called by OCMJH.
|
||||||
*
|
*
|
||||||
* @param ctx scope
|
* @param ctx scope
|
||||||
* @param config how/what to wrap
|
* @param config how/what to wrap
|
||||||
* @param wrappedKey output parameter that will be filled with the sessionKey used
|
* @param wrappedKey non-null with null data,
|
||||||
|
* output parameter that will be filled with the SessionKey used
|
||||||
* @param wrappedTags Output parameter that will be filled with the sessionTags used.
|
* @param wrappedTags Output parameter that will be filled with the sessionTags used.
|
||||||
If non-empty on return you must call skm.tagsDelivered() when sent
|
If non-empty on return you must call skm.tagsDelivered() when sent
|
||||||
and then call skm.tagsAcked() or skm.failTags() later.
|
and then call skm.tagsAcked() or skm.failTags() later.
|
||||||
@ -106,6 +122,7 @@ public class GarlicMessageBuilder {
|
|||||||
Set to zero to disable tag delivery. You must set to zero if you are not
|
Set to zero to disable tag delivery. You must set to zero if you are not
|
||||||
equipped to confirm delivery and call skm.tagsAcked() or skm.failTags() later.
|
equipped to confirm delivery and call skm.tagsAcked() or skm.failTags() later.
|
||||||
* @param skm non-null
|
* @param skm non-null
|
||||||
|
* @return null if expired
|
||||||
* @throws IllegalArgumentException on error
|
* @throws IllegalArgumentException on error
|
||||||
*/
|
*/
|
||||||
public static GarlicMessage buildMessage(RouterContext ctx, GarlicConfig config, SessionKey wrappedKey, Set<SessionTag> wrappedTags,
|
public static GarlicMessage buildMessage(RouterContext ctx, GarlicConfig config, SessionKey wrappedKey, Set<SessionTag> wrappedTags,
|
||||||
@ -114,11 +131,13 @@ public class GarlicMessageBuilder {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* called by netdb and above
|
* ELGAMAL_2048 only.
|
||||||
|
* Called by netdb and above.
|
||||||
*
|
*
|
||||||
* @param ctx scope
|
* @param ctx scope
|
||||||
* @param config how/what to wrap
|
* @param config how/what to wrap
|
||||||
* @param wrappedKey output parameter that will be filled with the sessionKey used
|
* @param wrappedKey non-null with null data,
|
||||||
|
* output parameter that will be filled with the SessionKey used
|
||||||
* @param wrappedTags Output parameter that will be filled with the sessionTags used.
|
* @param wrappedTags Output parameter that will be filled with the sessionTags used.
|
||||||
If non-empty on return you must call skm.tagsDelivered() when sent
|
If non-empty on return you must call skm.tagsDelivered() when sent
|
||||||
and then call skm.tagsAcked() or skm.failTags() later.
|
and then call skm.tagsAcked() or skm.failTags() later.
|
||||||
@ -128,6 +147,7 @@ public class GarlicMessageBuilder {
|
|||||||
If this is always 0, it forces ElGamal every time.
|
If this is always 0, it forces ElGamal every time.
|
||||||
* @param lowTagsThreshold the threshold
|
* @param lowTagsThreshold the threshold
|
||||||
* @param skm non-null
|
* @param skm non-null
|
||||||
|
* @return null if expired
|
||||||
* @throws IllegalArgumentException on error
|
* @throws IllegalArgumentException on error
|
||||||
*/
|
*/
|
||||||
public static GarlicMessage buildMessage(RouterContext ctx, GarlicConfig config, SessionKey wrappedKey, Set<SessionTag> wrappedTags,
|
public static GarlicMessage buildMessage(RouterContext ctx, GarlicConfig config, SessionKey wrappedKey, Set<SessionTag> wrappedTags,
|
||||||
@ -144,14 +164,14 @@ public class GarlicMessageBuilder {
|
|||||||
} else
|
} else
|
||||||
key = config.getRecipient().getIdentity().getPublicKey();
|
key = config.getRecipient().getIdentity().getPublicKey();
|
||||||
}
|
}
|
||||||
|
if (key.getType() != EncType.ELGAMAL_2048)
|
||||||
|
throw new IllegalArgumentException();
|
||||||
|
|
||||||
if (log.shouldLog(Log.INFO))
|
if (log.shouldLog(Log.INFO))
|
||||||
log.info("Encrypted with public key to expire on " + new Date(config.getExpiration()));
|
log.info("Encrypted with public key to expire on " + new Date(config.getExpiration()));
|
||||||
|
|
||||||
SessionKey curKey = skm.getCurrentOrNewKey(key);
|
SessionKey curKey = skm.getCurrentOrNewKey(key);
|
||||||
SessionTag curTag = null;
|
SessionTag curTag = skm.consumeNextAvailableTag(key, curKey);
|
||||||
|
|
||||||
curTag = skm.consumeNextAvailableTag(key, curKey);
|
|
||||||
|
|
||||||
if (log.shouldLog(Log.DEBUG)) {
|
if (log.shouldLog(Log.DEBUG)) {
|
||||||
int availTags = skm.getAvailableTags(key, curKey);
|
int availTags = skm.getAvailableTags(key, curKey);
|
||||||
@ -167,25 +187,26 @@ public class GarlicMessageBuilder {
|
|||||||
|
|
||||||
wrappedKey.setData(curKey.getData());
|
wrappedKey.setData(curKey.getData());
|
||||||
|
|
||||||
return buildMessage(ctx, config, wrappedKey, wrappedTags, key, curKey, curTag);
|
return buildMessage(ctx, config, wrappedTags, key, curKey, curTag);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* used by TestJob and directly above
|
* ELGAMAL_2048 only.
|
||||||
* and for encrypting DatabaseLookupMessages
|
* Used by TestJob, and directly above,
|
||||||
|
* and by MessageWrapper for encrypting DatabaseLookupMessages
|
||||||
*
|
*
|
||||||
* @param ctx scope
|
* @param ctx scope
|
||||||
* @param config how/what to wrap
|
* @param config how/what to wrap
|
||||||
* @param wrappedKey unused - why??
|
|
||||||
* @param wrappedTags New tags to be sent along with the message.
|
* @param wrappedTags New tags to be sent along with the message.
|
||||||
* 200 max enforced at receiver; null OK
|
* 200 max enforced at receiver; null OK
|
||||||
* @param target public key of the location being garlic routed to (may be null if we
|
* @param target public key of the location being garlic routed to (may be null if we
|
||||||
* know the encryptKey and encryptTag)
|
* know the encryptKey and encryptTag)
|
||||||
* @param encryptKey sessionKey used to encrypt the current message, non-null
|
* @param encryptKey sessionKey used to encrypt the current message, non-null
|
||||||
* @param encryptTag sessionTag used to encrypt the current message, null to force ElG
|
* @param encryptTag sessionTag used to encrypt the current message, null to force ElG
|
||||||
|
* @return null if expired
|
||||||
* @throws IllegalArgumentException on error
|
* @throws IllegalArgumentException on error
|
||||||
*/
|
*/
|
||||||
public static GarlicMessage buildMessage(RouterContext ctx, GarlicConfig config, SessionKey wrappedKey, Set<SessionTag> wrappedTags,
|
public static GarlicMessage buildMessage(RouterContext ctx, GarlicConfig config, Set<SessionTag> wrappedTags,
|
||||||
PublicKey target, SessionKey encryptKey, SessionTag encryptTag) {
|
PublicKey target, SessionKey encryptKey, SessionTag encryptTag) {
|
||||||
Log log = ctx.logManager().getLog(GarlicMessageBuilder.class);
|
Log log = ctx.logManager().getLog(GarlicMessageBuilder.class);
|
||||||
if (config == null)
|
if (config == null)
|
||||||
@ -199,6 +220,11 @@ public class GarlicMessageBuilder {
|
|||||||
|
|
||||||
// TODO - 128 is the minimum padded size - should it be more? less? random?
|
// TODO - 128 is the minimum padded size - should it be more? less? random?
|
||||||
byte encData[] = ctx.elGamalAESEngine().encrypt(cloveSet, target, encryptKey, wrappedTags, encryptTag, 128);
|
byte encData[] = ctx.elGamalAESEngine().encrypt(cloveSet, target, encryptKey, wrappedTags, encryptTag, 128);
|
||||||
|
if (encData == null) {
|
||||||
|
if (log.shouldWarn())
|
||||||
|
log.warn("ElG encrypt fail");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
msg.setData(encData);
|
msg.setData(encData);
|
||||||
msg.setMessageExpiration(config.getExpiration());
|
msg.setMessageExpiration(config.getExpiration());
|
||||||
|
|
||||||
@ -216,6 +242,69 @@ public class GarlicMessageBuilder {
|
|||||||
return msg;
|
return msg;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ECIES_X25519 only.
|
||||||
|
* Called by GarlicMessageBuilder 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)
|
||||||
|
* @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, SessionKeyManager skm) {
|
||||||
|
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);
|
||||||
|
byte cloveSet[] = buildCloveSet(ctx, config);
|
||||||
|
LeaseSetKeys lsk = ctx.keyManager().getKeys(from);
|
||||||
|
if (lsk == null) {
|
||||||
|
if (log.shouldWarn())
|
||||||
|
log.warn("No LSK for " + from.toBase32());
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
PrivateKey priv = lsk.getDecryptionKey(EncType.ECIES_X25519);
|
||||||
|
if (priv == null) {
|
||||||
|
if (log.shouldWarn())
|
||||||
|
log.warn("No key for " + from.toBase32());
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
RatchetSKM rskm;
|
||||||
|
if (skm instanceof RatchetSKM) {
|
||||||
|
rskm = (RatchetSKM) skm;
|
||||||
|
} else if (skm instanceof MuxedSKM) {
|
||||||
|
rskm = ((MuxedSKM) skm).getECSKM();
|
||||||
|
} else {
|
||||||
|
if (log.shouldWarn())
|
||||||
|
log.warn("No SKM for " + from.toBase32());
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
byte encData[] = ctx.eciesEngine().encrypt(cloveSet, target, priv, rskm, config.getExpiration());
|
||||||
|
if (encData == null) {
|
||||||
|
if (log.shouldWarn())
|
||||||
|
log.warn("Encrypt fail for " + from.toBase32());
|
||||||
|
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("CloveSet (" + config.getCloveCount() + " cloves) for message " + msg.getUniqueId() + " is " + cloveSet.length
|
||||||
|
+ " bytes and encrypted message data is " + encData.length + " bytes");
|
||||||
|
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++) {
|
||||||
@ -237,8 +326,7 @@ public class GarlicMessageBuilder {
|
|||||||
* @throws IllegalArgumentException on error
|
* @throws IllegalArgumentException on error
|
||||||
*/
|
*/
|
||||||
private static byte[] buildCloveSet(RouterContext ctx, GarlicConfig config) {
|
private static byte[] buildCloveSet(RouterContext ctx, GarlicConfig config) {
|
||||||
ByteArrayOutputStream baos = null;
|
ByteArrayOutputStream baos;
|
||||||
Log log = ctx.logManager().getLog(GarlicMessageBuilder.class);
|
|
||||||
try {
|
try {
|
||||||
if (config instanceof PayloadGarlicConfig) {
|
if (config instanceof PayloadGarlicConfig) {
|
||||||
byte clove[] = buildClove(ctx, (PayloadGarlicConfig)config);
|
byte clove[] = buildClove(ctx, (PayloadGarlicConfig)config);
|
||||||
@ -253,7 +341,7 @@ public class GarlicMessageBuilder {
|
|||||||
//log.debug("Subclove IS a payload garlic clove");
|
//log.debug("Subclove IS a payload garlic clove");
|
||||||
cloves[i] = buildClove(ctx, (PayloadGarlicConfig)c);
|
cloves[i] = buildClove(ctx, (PayloadGarlicConfig)c);
|
||||||
} else {
|
} else {
|
||||||
log.debug("Subclove IS NOT a payload garlic clove");
|
//log.debug("Subclove IS NOT a payload garlic clove");
|
||||||
// See notes below
|
// See notes below
|
||||||
cloves[i] = buildClove(ctx, c);
|
cloves[i] = buildClove(ctx, c);
|
||||||
}
|
}
|
||||||
@ -271,10 +359,8 @@ public class GarlicMessageBuilder {
|
|||||||
DataHelper.writeLong(baos, 4, config.getId());
|
DataHelper.writeLong(baos, 4, config.getId());
|
||||||
DataHelper.writeLong(baos, DataHelper.DATE_LENGTH, config.getExpiration());
|
DataHelper.writeLong(baos, DataHelper.DATE_LENGTH, config.getExpiration());
|
||||||
} catch (IOException ioe) {
|
} catch (IOException ioe) {
|
||||||
log.error("Error building the clove set", ioe);
|
|
||||||
throw new IllegalArgumentException("Error building the clove set", ioe);
|
throw new IllegalArgumentException("Error building the clove set", ioe);
|
||||||
} catch (DataFormatException dfe) {
|
} catch (DataFormatException dfe) {
|
||||||
log.error("Error building the clove set", dfe);
|
|
||||||
throw new IllegalArgumentException("Error building the clove set", dfe);
|
throw new IllegalArgumentException("Error building the clove set", dfe);
|
||||||
}
|
}
|
||||||
return baos.toByteArray();
|
return baos.toByteArray();
|
||||||
|
@ -10,6 +10,7 @@ package net.i2p.router.message;
|
|||||||
|
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
|
|
||||||
|
import net.i2p.crypto.EncType;
|
||||||
import net.i2p.crypto.SessionKeyManager;
|
import net.i2p.crypto.SessionKeyManager;
|
||||||
import net.i2p.data.Certificate;
|
import net.i2p.data.Certificate;
|
||||||
import net.i2p.data.DataFormatException;
|
import net.i2p.data.DataFormatException;
|
||||||
@ -18,6 +19,8 @@ import net.i2p.data.PrivateKey;
|
|||||||
import net.i2p.data.i2np.GarlicClove;
|
import net.i2p.data.i2np.GarlicClove;
|
||||||
import net.i2p.data.i2np.GarlicMessage;
|
import net.i2p.data.i2np.GarlicMessage;
|
||||||
import net.i2p.router.RouterContext;
|
import net.i2p.router.RouterContext;
|
||||||
|
import net.i2p.router.crypto.ratchet.MuxedSKM;
|
||||||
|
import net.i2p.router.crypto.ratchet.RatchetSKM;
|
||||||
import net.i2p.util.Log;
|
import net.i2p.util.Log;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -41,16 +44,45 @@ public class GarlicMessageParser {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* Supports both ELGAMAL_2048 and ECIES_X25519.
|
||||||
|
*
|
||||||
|
* @param encryptionKey either type TODO need both for muxed
|
||||||
* @param skm use tags from this session key manager
|
* @param skm use tags from this session key manager
|
||||||
* @return null on error
|
* @return null on error
|
||||||
*/
|
*/
|
||||||
public CloveSet getGarlicCloves(GarlicMessage message, PrivateKey encryptionKey, SessionKeyManager skm) {
|
CloveSet getGarlicCloves(GarlicMessage message, PrivateKey encryptionKey, SessionKeyManager skm) {
|
||||||
byte encData[] = message.getData();
|
byte encData[] = message.getData();
|
||||||
byte decrData[];
|
byte decrData[];
|
||||||
try {
|
try {
|
||||||
if (_log.shouldLog(Log.DEBUG))
|
if (_log.shouldLog(Log.DEBUG))
|
||||||
_log.debug("Decrypting with private key " + encryptionKey);
|
_log.debug("Decrypting with private key " + encryptionKey);
|
||||||
decrData = _context.elGamalAESEngine().decrypt(encData, encryptionKey, skm);
|
EncType type = encryptionKey.getType();
|
||||||
|
if (type == EncType.ELGAMAL_2048) {
|
||||||
|
decrData = _context.elGamalAESEngine().decrypt(encData, encryptionKey, skm);
|
||||||
|
} else if (type == EncType.ECIES_X25519) {
|
||||||
|
RatchetSKM rskm;
|
||||||
|
if (skm instanceof RatchetSKM) {
|
||||||
|
rskm = (RatchetSKM) skm;
|
||||||
|
} else if (skm instanceof MuxedSKM) {
|
||||||
|
rskm = ((MuxedSKM) skm).getECSKM();
|
||||||
|
} else {
|
||||||
|
if (_log.shouldWarn())
|
||||||
|
_log.warn("No SKM to decrypt ECIES");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
decrData = _context.eciesEngine().decrypt(encData, encryptionKey, rskm);
|
||||||
|
if (decrData != null) {
|
||||||
|
if (_log.shouldWarn())
|
||||||
|
_log.warn("ECIES decrypt success, length: " + decrData.length);
|
||||||
|
} else {
|
||||||
|
if (_log.shouldWarn())
|
||||||
|
_log.warn("ECIES decrypt fail");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (_log.shouldWarn())
|
||||||
|
_log.warn("Can't decrypt with key type " + type);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
} catch (DataFormatException dfe) {
|
} catch (DataFormatException dfe) {
|
||||||
if (_log.shouldLog(Log.WARN))
|
if (_log.shouldLog(Log.WARN))
|
||||||
_log.warn("Error decrypting", dfe);
|
_log.warn("Error decrypting", dfe);
|
||||||
@ -63,7 +95,10 @@ public class GarlicMessageParser {
|
|||||||
return null;
|
return null;
|
||||||
} else {
|
} else {
|
||||||
try {
|
try {
|
||||||
return readCloveSet(decrData);
|
CloveSet rv = readCloveSet(decrData, 0);
|
||||||
|
if (_log.shouldDebug())
|
||||||
|
_log.debug("Got cloves: " + rv.getCloveCount());
|
||||||
|
return rv;
|
||||||
} catch (DataFormatException dfe) {
|
} catch (DataFormatException dfe) {
|
||||||
if (_log.shouldLog(Log.WARN))
|
if (_log.shouldLog(Log.WARN))
|
||||||
_log.warn("Unable to read cloveSet", dfe);
|
_log.warn("Unable to read cloveSet", dfe);
|
||||||
@ -72,13 +107,15 @@ public class GarlicMessageParser {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private CloveSet readCloveSet(byte data[]) throws DataFormatException {
|
/**
|
||||||
int offset = 0;
|
* @param offset where in data to start
|
||||||
|
* @return non-null, throws on all errors
|
||||||
|
*/
|
||||||
|
private CloveSet readCloveSet(byte data[], int offset) throws DataFormatException {
|
||||||
int numCloves = data[offset] & 0xff;
|
int numCloves = data[offset] & 0xff;
|
||||||
offset++;
|
offset++;
|
||||||
if (_log.shouldLog(Log.DEBUG))
|
//if (_log.shouldLog(Log.DEBUG))
|
||||||
_log.debug("# cloves to read: " + numCloves);
|
// _log.debug("# cloves to read: " + numCloves);
|
||||||
if (numCloves <= 0 || numCloves > MAX_CLOVES)
|
if (numCloves <= 0 || numCloves > MAX_CLOVES)
|
||||||
throw new DataFormatException("bad clove count " + numCloves);
|
throw new DataFormatException("bad clove count " + numCloves);
|
||||||
GarlicClove[] cloves = new GarlicClove[numCloves];
|
GarlicClove[] cloves = new GarlicClove[numCloves];
|
||||||
|
@ -8,6 +8,7 @@ package net.i2p.router.message;
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
import net.i2p.crypto.EncType;
|
||||||
import net.i2p.crypto.SessionKeyManager;
|
import net.i2p.crypto.SessionKeyManager;
|
||||||
import net.i2p.data.DataHelper;
|
import net.i2p.data.DataHelper;
|
||||||
import net.i2p.data.Hash;
|
import net.i2p.data.Hash;
|
||||||
@ -21,7 +22,7 @@ import net.i2p.router.RouterContext;
|
|||||||
import net.i2p.util.Log;
|
import net.i2p.util.Log;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Unencrypt a garlic message and pass off any valid cloves to the configured
|
* Decrypt a garlic message and pass off any valid cloves to the configured
|
||||||
* receiver to dispatch as they choose.
|
* receiver to dispatch as they choose.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
@ -61,7 +62,16 @@ public class GarlicMessageReceiver {
|
|||||||
LeaseSetKeys keys = _context.keyManager().getKeys(_clientDestination);
|
LeaseSetKeys keys = _context.keyManager().getKeys(_clientDestination);
|
||||||
skm = _context.clientManager().getClientSessionKeyManager(_clientDestination);
|
skm = _context.clientManager().getClientSessionKeyManager(_clientDestination);
|
||||||
if (keys != null && skm != null) {
|
if (keys != null && skm != null) {
|
||||||
|
// TODO need to pass both keys if available for muxed decrypt
|
||||||
decryptionKey = keys.getDecryptionKey();
|
decryptionKey = keys.getDecryptionKey();
|
||||||
|
if (decryptionKey == null) {
|
||||||
|
decryptionKey = keys.getDecryptionKey(EncType.ECIES_X25519);
|
||||||
|
if (decryptionKey == null) {
|
||||||
|
if (_log.shouldWarn())
|
||||||
|
_log.warn("No key to decrypt for " + _clientDestination.toBase32());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
if (_log.shouldLog(Log.WARN))
|
if (_log.shouldLog(Log.WARN))
|
||||||
_log.warn("Not trying to decrypt a garlic routed message to a disconnected client");
|
_log.warn("Not trying to decrypt a garlic routed message to a disconnected client");
|
||||||
@ -72,6 +82,7 @@ public class GarlicMessageReceiver {
|
|||||||
skm = _context.sessionKeyManager();
|
skm = _context.sessionKeyManager();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO need to pass both keys if available for muxed decrypt
|
||||||
CloveSet set = _context.garlicMessageParser().getGarlicCloves(message, decryptionKey, skm);
|
CloveSet set = _context.garlicMessageParser().getGarlicCloves(message, decryptionKey, skm);
|
||||||
if (set != null) {
|
if (set != null) {
|
||||||
for (int i = 0; i < set.getCloveCount(); i++) {
|
for (int i = 0; i < set.getCloveCount(); i++) {
|
||||||
@ -79,9 +90,13 @@ public class GarlicMessageReceiver {
|
|||||||
handleClove(clove);
|
handleClove(clove);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (_log.shouldLog(Log.WARN))
|
if (_log.shouldLog(Log.WARN)) {
|
||||||
_log.warn("CloveMessageParser failed to decrypt the message [" + message.getUniqueId()
|
String d = (_clientDestination != null) ? _clientDestination.toBase32() : "the router";
|
||||||
+ "]", new Exception("Decrypt garlic failed"));
|
_log.warn("CloveMessageParser failed to decrypt the " + message.getData().length +
|
||||||
|
" byte message [" + message.getUniqueId()
|
||||||
|
+ "] for " + d + " with key " + decryptionKey.getType(),
|
||||||
|
new Exception("Decrypt garlic failed"));
|
||||||
|
}
|
||||||
_context.statManager().addRateData("crypto.garlic.decryptFail", 1);
|
_context.statManager().addRateData("crypto.garlic.decryptFail", 1);
|
||||||
_context.messageHistory().messageProcessingError(message.getUniqueId(),
|
_context.messageHistory().messageProcessingError(message.getUniqueId(),
|
||||||
message.getClass().getName(),
|
message.getClass().getName(),
|
||||||
@ -110,10 +125,10 @@ public class GarlicMessageReceiver {
|
|||||||
boolean rv = invalidReason == null;
|
boolean rv = invalidReason == null;
|
||||||
if (!rv) {
|
if (!rv) {
|
||||||
String howLongAgo = DataHelper.formatDuration(_context.clock().now()-clove.getExpiration().getTime());
|
String howLongAgo = DataHelper.formatDuration(_context.clock().now()-clove.getExpiration().getTime());
|
||||||
if (_log.shouldLog(Log.DEBUG))
|
if (_log.shouldInfo())
|
||||||
_log.debug("Clove is NOT valid: id=" + clove.getCloveId()
|
_log.info("Clove is NOT valid: id=" + clove.getCloveId()
|
||||||
+ " expiration " + howLongAgo + " ago", new Exception("Invalid within..."));
|
+ " expiration " + howLongAgo + " ago", new Exception("Invalid within..."));
|
||||||
else if (_log.shouldLog(Log.WARN))
|
else if (_log.shouldWarn())
|
||||||
_log.warn("Clove is NOT valid: id=" + clove.getCloveId()
|
_log.warn("Clove is NOT valid: id=" + clove.getCloveId()
|
||||||
+ " expiration " + howLongAgo + " ago: " + invalidReason + ": " + clove);
|
+ " expiration " + howLongAgo + " ago: " + invalidReason + ": " + clove);
|
||||||
_context.messageHistory().messageProcessingError(clove.getCloveId(),
|
_context.messageHistory().messageProcessingError(clove.getCloveId(),
|
||||||
|
@ -10,6 +10,7 @@ package net.i2p.router.message;
|
|||||||
|
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
|
import net.i2p.crypto.EncType;
|
||||||
import net.i2p.crypto.SessionKeyManager;
|
import net.i2p.crypto.SessionKeyManager;
|
||||||
import net.i2p.data.Certificate;
|
import net.i2p.data.Certificate;
|
||||||
import net.i2p.data.Destination;
|
import net.i2p.data.Destination;
|
||||||
@ -72,9 +73,8 @@ class OutboundClientMessageJobHelper {
|
|||||||
*
|
*
|
||||||
* For now, its just a tunneled DeliveryStatusMessage
|
* For now, its just a tunneled DeliveryStatusMessage
|
||||||
*
|
*
|
||||||
* Unused?
|
* @param wrappedKey non-null with null data,
|
||||||
*
|
* output parameter that will be filled with the SessionKey used
|
||||||
* @param wrappedKey output parameter that will be filled with the sessionKey used
|
|
||||||
* @param wrappedTags output parameter that will be filled with the sessionTags used
|
* @param wrappedTags output parameter that will be filled with the sessionTags used
|
||||||
* @param bundledReplyLeaseSet if specified, the given LeaseSet will be packaged with the message (allowing
|
* @param bundledReplyLeaseSet if specified, the given LeaseSet will be packaged with the message (allowing
|
||||||
* much faster replies, since their netDb search will return almost instantly)
|
* much faster replies, since their netDb search will return almost instantly)
|
||||||
@ -101,7 +101,8 @@ class OutboundClientMessageJobHelper {
|
|||||||
*
|
*
|
||||||
* @param tagsToSendOverride if > 0, use this instead of skm's default
|
* @param tagsToSendOverride if > 0, use this instead of skm's default
|
||||||
* @param lowTagsOverride if > 0, use this instead of skm's default
|
* @param lowTagsOverride if > 0, use this instead of skm's default
|
||||||
* @param wrappedKey output parameter that will be filled with the sessionKey used
|
* @param wrappedKey non-null with null data,
|
||||||
|
* output parameter that will be filled with the SessionKey used
|
||||||
* @param wrappedTags output parameter that will be filled with the sessionTags used
|
* @param wrappedTags output parameter that will be filled with the sessionTags used
|
||||||
* @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
|
||||||
@ -120,11 +121,16 @@ class OutboundClientMessageJobHelper {
|
|||||||
from, dest, replyTunnel, requireAck, bundledReplyLeaseSet, skm);
|
from, dest, replyTunnel, requireAck, bundledReplyLeaseSet, skm);
|
||||||
if (config == null)
|
if (config == null)
|
||||||
return null;
|
return null;
|
||||||
// no use sending tags unless we have a reply token set up already
|
GarlicMessage msg;
|
||||||
int tagsToSend = replyToken >= 0 ? (tagsToSendOverride > 0 ? tagsToSendOverride : skm.getTagsToSend()) : 0;
|
if (recipientPK.getType() == EncType.ECIES_X25519) {
|
||||||
int lowThreshold = lowTagsOverride > 0 ? lowTagsOverride : skm.getLowThreshold();
|
msg = GarlicMessageBuilder.buildECIESMessage(ctx, config, recipientPK, from, skm);
|
||||||
GarlicMessage msg = GarlicMessageBuilder.buildMessage(ctx, config, wrappedKey, wrappedTags,
|
} else {
|
||||||
tagsToSend, lowThreshold, skm);
|
// no use sending tags unless we have a reply token set up already
|
||||||
|
int tagsToSend = replyToken >= 0 ? (tagsToSendOverride > 0 ? tagsToSendOverride : skm.getTagsToSend()) : 0;
|
||||||
|
int lowThreshold = lowTagsOverride > 0 ? lowTagsOverride : skm.getLowThreshold();
|
||||||
|
msg = GarlicMessageBuilder.buildMessage(ctx, config, wrappedKey, wrappedTags,
|
||||||
|
tagsToSend, lowThreshold, skm);
|
||||||
|
}
|
||||||
return msg;
|
return msg;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -150,7 +156,8 @@ class OutboundClientMessageJobHelper {
|
|||||||
ctx.random().nextLong(I2NPMessage.MAX_ID_VALUE),
|
ctx.random().nextLong(I2NPMessage.MAX_ID_VALUE),
|
||||||
expiration, DeliveryInstructions.LOCAL);
|
expiration, DeliveryInstructions.LOCAL);
|
||||||
|
|
||||||
if (requireAck) {
|
// for now, skip this for ratchet
|
||||||
|
if (requireAck && recipientPK.getType() == EncType.ELGAMAL_2048) {
|
||||||
// extend the expiration of the return message
|
// extend the expiration of the return message
|
||||||
PayloadGarlicConfig ackClove = buildAckClove(ctx, from, replyTunnel, replyToken,
|
PayloadGarlicConfig ackClove = buildAckClove(ctx, from, replyTunnel, replyToken,
|
||||||
expiration + ACK_EXTRA_EXPIRATION, skm);
|
expiration + ACK_EXTRA_EXPIRATION, skm);
|
||||||
|
@ -32,6 +32,7 @@ import net.i2p.data.i2np.GarlicMessage;
|
|||||||
import net.i2p.data.i2np.I2NPMessage;
|
import net.i2p.data.i2np.I2NPMessage;
|
||||||
import net.i2p.router.ClientMessage;
|
import net.i2p.router.ClientMessage;
|
||||||
import net.i2p.router.JobImpl;
|
import net.i2p.router.JobImpl;
|
||||||
|
import net.i2p.router.LeaseSetKeys;
|
||||||
import net.i2p.router.MessageSelector;
|
import net.i2p.router.MessageSelector;
|
||||||
import net.i2p.router.ReplyJob;
|
import net.i2p.router.ReplyJob;
|
||||||
import net.i2p.router.Router;
|
import net.i2p.router.Router;
|
||||||
@ -116,6 +117,8 @@ public class OutboundClientMessageOneShotJob extends JobImpl {
|
|||||||
private LeaseSet _leaseSet;
|
private LeaseSet _leaseSet;
|
||||||
/** Actual lease the message is being routed through */
|
/** Actual lease the message is being routed through */
|
||||||
private Lease _lease;
|
private Lease _lease;
|
||||||
|
/** Actual target encryption key from the LS being used */
|
||||||
|
private PublicKey _encryptionKey;
|
||||||
private final long _start;
|
private final long _start;
|
||||||
/** note we can succeed after failure, but not vice versa */
|
/** note we can succeed after failure, but not vice versa */
|
||||||
private enum Result {NONE, FAIL, SUCCESS}
|
private enum Result {NONE, FAIL, SUCCESS}
|
||||||
@ -373,8 +376,13 @@ public class OutboundClientMessageOneShotJob extends JobImpl {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Choose a lease from his leaseset to send the message to. Sets _lease.
|
* Choose a lease from his leaseset to send the message to.
|
||||||
|
*
|
||||||
|
* Side effects:
|
||||||
|
* Sets _lease.
|
||||||
* Sets _wantACK if it's new or changed.
|
* Sets _wantACK if it's new or changed.
|
||||||
|
* Sets _encryptionKey.
|
||||||
|
*
|
||||||
* Does several checks to see if we can actually send to this leaseset,
|
* Does several checks to see if we can actually send to this leaseset,
|
||||||
* and returns nonzero failure code if unable to.
|
* and returns nonzero failure code if unable to.
|
||||||
*
|
*
|
||||||
@ -399,12 +407,21 @@ public class OutboundClientMessageOneShotJob extends JobImpl {
|
|||||||
lsType != DatabaseEntry.KEY_TYPE_LS2) {
|
lsType != DatabaseEntry.KEY_TYPE_LS2) {
|
||||||
return MessageStatusMessage.STATUS_SEND_FAILURE_BAD_LEASESET;
|
return MessageStatusMessage.STATUS_SEND_FAILURE_BAD_LEASESET;
|
||||||
}
|
}
|
||||||
PublicKey pk = _leaseSet.getEncryptionKey();
|
|
||||||
if (pk == null)
|
// select an encryption key from the leaseset
|
||||||
|
Set<EncType> supported;
|
||||||
|
LeaseSetKeys ourKeys = getContext().keyManager().getKeys(_from);
|
||||||
|
if (ourKeys != null)
|
||||||
|
supported = ourKeys.getSupportedEncryption();
|
||||||
|
else
|
||||||
|
supported = LeaseSetKeys.SET_ELG;
|
||||||
|
_encryptionKey = _leaseSet.getEncryptionKey(supported);
|
||||||
|
if (_encryptionKey == null) {
|
||||||
|
if (_leaseSet.getEncryptionKey() != null)
|
||||||
|
return MessageStatusMessage.STATUS_SEND_FAILURE_UNSUPPORTED_ENCRYPTION;
|
||||||
|
// no keys at all?
|
||||||
return MessageStatusMessage.STATUS_SEND_FAILURE_BAD_LEASESET;
|
return MessageStatusMessage.STATUS_SEND_FAILURE_BAD_LEASESET;
|
||||||
EncType encType = pk.getType();
|
}
|
||||||
if (encType == null || !encType.isAvailable())
|
|
||||||
return MessageStatusMessage.STATUS_SEND_FAILURE_UNSUPPORTED_ENCRYPTION;
|
|
||||||
|
|
||||||
// Use the same lease if it's still good
|
// Use the same lease if it's still good
|
||||||
// Even if _leaseSet changed, _leaseSet.getEncryptionKey() didn't...
|
// Even if _leaseSet changed, _leaseSet.getEncryptionKey() didn't...
|
||||||
@ -590,7 +607,7 @@ public class OutboundClientMessageOneShotJob extends JobImpl {
|
|||||||
int tagsRequired = SendMessageOptions.getTagThreshold(sendFlags);
|
int tagsRequired = SendMessageOptions.getTagThreshold(sendFlags);
|
||||||
boolean wantACK = _wantACK ||
|
boolean wantACK = _wantACK ||
|
||||||
shouldRequestReply ||
|
shouldRequestReply ||
|
||||||
GarlicMessageBuilder.needsTags(getContext(), _leaseSet.getEncryptionKey(),
|
GarlicMessageBuilder.needsTags(getContext(), _encryptionKey,
|
||||||
_from.calculateHash(), tagsRequired);
|
_from.calculateHash(), tagsRequired);
|
||||||
|
|
||||||
LeaseSet replyLeaseSet;
|
LeaseSet replyLeaseSet;
|
||||||
@ -627,17 +644,14 @@ public class OutboundClientMessageOneShotJob extends JobImpl {
|
|||||||
dieFatal(MessageStatusMessage.STATUS_SEND_FAILURE_UNSUPPORTED_ENCRYPTION);
|
dieFatal(MessageStatusMessage.STATUS_SEND_FAILURE_UNSUPPORTED_ENCRYPTION);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
//if (_log.shouldLog(Log.DEBUG))
|
|
||||||
// _log.debug(getJobId() + ": Clove built to " + _toString);
|
|
||||||
|
|
||||||
PublicKey key = _leaseSet.getEncryptionKey();
|
|
||||||
SessionKey sessKey = new SessionKey();
|
SessionKey sessKey = new SessionKey();
|
||||||
Set<SessionTag> tags = new HashSet<SessionTag>();
|
Set<SessionTag> tags = new HashSet<SessionTag>();
|
||||||
|
|
||||||
// Per-message flag > 0 overrides per-session option
|
// Per-message flag > 0 overrides per-session option
|
||||||
int tagsToSend = SendMessageOptions.getTagsToSend(sendFlags);
|
int tagsToSend = SendMessageOptions.getTagsToSend(sendFlags);
|
||||||
GarlicMessage msg = OutboundClientMessageJobHelper.createGarlicMessage(getContext(), token,
|
GarlicMessage msg = OutboundClientMessageJobHelper.createGarlicMessage(getContext(), token,
|
||||||
_overallExpiration, key,
|
_overallExpiration, _encryptionKey,
|
||||||
clove, _from.calculateHash(),
|
clove, _from.calculateHash(),
|
||||||
_to, _inTunnel, tagsToSend,
|
_to, _inTunnel, tagsToSend,
|
||||||
tagsRequired, sessKey, tags,
|
tagsRequired, sessKey, tags,
|
||||||
@ -664,7 +678,7 @@ public class OutboundClientMessageOneShotJob extends JobImpl {
|
|||||||
if (!tags.isEmpty()) {
|
if (!tags.isEmpty()) {
|
||||||
SessionKeyManager skm = getContext().clientManager().getClientSessionKeyManager(_from.calculateHash());
|
SessionKeyManager skm = getContext().clientManager().getClientSessionKeyManager(_from.calculateHash());
|
||||||
if (skm != null)
|
if (skm != null)
|
||||||
tsh = skm.tagsDelivered(_leaseSet.getEncryptionKey(), sessKey, tags);
|
tsh = skm.tagsDelivered(_encryptionKey, sessKey, tags);
|
||||||
}
|
}
|
||||||
onReply = new SendSuccessJob(getContext(), sessKey, tsh);
|
onReply = new SendSuccessJob(getContext(), sessKey, tsh);
|
||||||
onFail = new SendTimeoutJob(getContext(), sessKey, tsh);
|
onFail = new SendTimeoutJob(getContext(), sessKey, tsh);
|
||||||
@ -1019,7 +1033,7 @@ public class OutboundClientMessageOneShotJob extends JobImpl {
|
|||||||
if (_key != null && _tags != null && _leaseSet != null) {
|
if (_key != null && _tags != null && _leaseSet != null) {
|
||||||
SessionKeyManager skm = getContext().clientManager().getClientSessionKeyManager(_from.calculateHash());
|
SessionKeyManager skm = getContext().clientManager().getClientSessionKeyManager(_from.calculateHash());
|
||||||
if (skm != null)
|
if (skm != null)
|
||||||
skm.tagsAcked(_leaseSet.getEncryptionKey(), _key, _tags);
|
skm.tagsAcked(_encryptionKey, _key, _tags);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1110,7 +1124,7 @@ public class OutboundClientMessageOneShotJob extends JobImpl {
|
|||||||
if (_key != null && _tags != null && _leaseSet != null) {
|
if (_key != null && _tags != null && _leaseSet != null) {
|
||||||
SessionKeyManager skm = getContext().clientManager().getClientSessionKeyManager(_from.calculateHash());
|
SessionKeyManager skm = getContext().clientManager().getClientSessionKeyManager(_from.calculateHash());
|
||||||
if (skm != null)
|
if (skm != null)
|
||||||
skm.failTags(_leaseSet.getEncryptionKey(), _key, _tags);
|
skm.failTags(_encryptionKey, _key, _tags);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (old == Result.NONE)
|
if (old == Result.NONE)
|
||||||
|
@ -139,7 +139,7 @@ public class MessageWrapper {
|
|||||||
payload.setRecipient(to);
|
payload.setRecipient(to);
|
||||||
|
|
||||||
SessionKey sentKey = ctx.keyGenerator().generateSessionKey();
|
SessionKey sentKey = ctx.keyGenerator().generateSessionKey();
|
||||||
GarlicMessage msg = GarlicMessageBuilder.buildMessage(ctx, payload, null, null,
|
GarlicMessage msg = GarlicMessageBuilder.buildMessage(ctx, payload, null,
|
||||||
key, sentKey, null);
|
key, sentKey, null);
|
||||||
return msg;
|
return msg;
|
||||||
}
|
}
|
||||||
@ -234,7 +234,7 @@ public class MessageWrapper {
|
|||||||
m.getMessageExpiration(),
|
m.getMessageExpiration(),
|
||||||
DeliveryInstructions.LOCAL, m);
|
DeliveryInstructions.LOCAL, m);
|
||||||
|
|
||||||
GarlicMessage msg = GarlicMessageBuilder.buildMessage(ctx, payload, null, null,
|
GarlicMessage msg = GarlicMessageBuilder.buildMessage(ctx, payload, null,
|
||||||
null, encryptKey, encryptTag);
|
null, encryptKey, encryptTag);
|
||||||
return msg;
|
return msg;
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user