Skip to content

Commit

Permalink
Ratchet: Hook in MuxedEngine decrypt
Browse files Browse the repository at this point in the history
  • Loading branch information
zzz committed Nov 6, 2019
1 parent b7f6cfb commit 07b7ab4
Show file tree
Hide file tree
Showing 4 changed files with 82 additions and 19 deletions.
19 changes: 16 additions & 3 deletions router/java/src/net/i2p/router/crypto/ratchet/ECIESAEADEngine.java
Expand Up @@ -14,7 +14,6 @@
import com.southernstorm.noise.protocol.DHState;
import com.southernstorm.noise.protocol.HandshakeState;

import net.i2p.I2PAppContext;
import net.i2p.crypto.EncType;
import net.i2p.crypto.HKDF;
import net.i2p.crypto.SessionKeyManager;
Expand All @@ -29,6 +28,7 @@
import net.i2p.data.SessionTag;
import net.i2p.data.i2np.GarlicClove;
import static net.i2p.router.crypto.ratchet.RatchetPayload.*;
import net.i2p.router.RouterContext;
import net.i2p.router.message.CloveSet;
import net.i2p.util.Log;
import net.i2p.util.SimpleByteCache;
Expand All @@ -42,8 +42,9 @@
* @since 0.9.44
*/
public final class ECIESAEADEngine {
private final I2PAppContext _context;
private final RouterContext _context;
private final Log _log;
private final MuxedEngine _muxedEngine;
private final HKDF _hkdf;
private final Elg2KeyFactory _edhThread;
private boolean _isRunning;
Expand All @@ -70,9 +71,10 @@ public final class ECIESAEADEngine {
*
* startup() is called from RatchetSKM constructor so it's deferred until we need it.
*/
public ECIESAEADEngine(I2PAppContext ctx) {
public ECIESAEADEngine(RouterContext ctx) {
_context = ctx;
_log = _context.logManager().getLog(ECIESAEADEngine.class);
_muxedEngine = new MuxedEngine(ctx);
_hkdf = new HKDF(ctx);
_edhThread = new Elg2KeyFactory(ctx);

Expand Down Expand Up @@ -113,6 +115,17 @@ public synchronized void shutdown() {

//// start decrypt ////

/**
* Try to decrypt the message with one or both of the given private keys
*
* @param elgKey must be ElG, non-null
* @param ecKey must be EC, non-null
* @return decrypted data or null on failure
*/
public CloveSet decrypt(byte data[], PrivateKey elgKey, PrivateKey ecKey, MuxedSKM keyManager) throws DataFormatException {
return _muxedEngine.decrypt(data, elgKey, ecKey, keyManager);
}

/**
* Decrypt the message using the given private key
* and using tags from the specified key manager.
Expand Down
11 changes: 7 additions & 4 deletions router/java/src/net/i2p/router/crypto/ratchet/MuxedEngine.java
@@ -1,7 +1,5 @@
package net.i2p.router.crypto.ratchet;

import java.util.List;

import net.i2p.crypto.EncType;
import net.i2p.data.DataFormatException;
import net.i2p.data.PrivateKey;
Expand All @@ -15,7 +13,7 @@
*
* @since 0.9.44
*/
public final class MuxedEngine {
final class MuxedEngine {
private final RouterContext _context;
private final Log _log;

Expand All @@ -27,6 +25,8 @@ public MuxedEngine(RouterContext ctx) {
/**
* Decrypt the message with the given private keys
*
* @param elgKey must be ElG, non-null
* @param ecKey must be EC, non-null
* @return decrypted data or null on failure
*/
public CloveSet decrypt(byte data[], PrivateKey elgKey, PrivateKey ecKey, MuxedSKM keyManager) throws DataFormatException {
Expand All @@ -51,10 +51,13 @@ public CloveSet decrypt(byte data[], PrivateKey elgKey, PrivateKey ecKey, MuxedS
if (_log.shouldWarn())
_log.warn("ElG decrypt failed, trying ECIES", dfe);
}
} else {
if (_log.shouldWarn())
_log.warn("ElG decrypt failed, trying ECIES");
}
}
if (rv == null) {
rv = _context.eciesEngine().decrypt(data, ecKey, keyManager.getECSKM());
rv = _context.eciesEngine().decrypt(data, ecKey, keyManager.getECSKM());
}
return rv;
}
Expand Down
47 changes: 43 additions & 4 deletions router/java/src/net/i2p/router/message/GarlicMessageParser.java
Expand Up @@ -31,7 +31,7 @@
public class GarlicMessageParser {
private final Log _log;
private final RouterContext _context;

/**
* Huge limit just to reduce chance of trouble. Typ. usage is 3.
* As of 0.9.12. Was 255.
Expand All @@ -42,11 +42,11 @@ public GarlicMessageParser(RouterContext context) {
_context = context;
_log = _context.logManager().getLog(GarlicMessageParser.class);
}

/**
* Supports both ELGAMAL_2048 and ECIES_X25519.
*
* @param encryptionKey either type TODO need both for muxed
* @param encryptionKey either type
* @param skm use tags from this session key manager
* @return null on error
*/
Expand Down Expand Up @@ -108,7 +108,46 @@ CloveSet getGarlicCloves(GarlicMessage message, PrivateKey encryptionKey, Sessio
}
}
}


/**
* Supports both ELGAMAL_2048 and ECIES_X25519.
*
* @param elgKey must be ElG, non-null
* @param ecKey must be EC, non-null
* @param skm use tags from this session key manager
* @return null on error
* @since 0.9.44
*/
CloveSet getGarlicCloves(GarlicMessage message, PrivateKey elgKey, PrivateKey ecKey, SessionKeyManager skm) {
byte encData[] = message.getData();
CloveSet rv;
try {
if (skm instanceof MuxedSKM) {
MuxedSKM mskm = (MuxedSKM) skm;
rv = _context.eciesEngine().decrypt(encData, elgKey, ecKey, mskm);
} else if (skm instanceof RatchetSKM) {
// unlikely, if we have two keys we should have a MuxedSKM
RatchetSKM rskm = (RatchetSKM) skm;
rv = _context.eciesEngine().decrypt(encData, ecKey, rskm);
} else {
// unlikely, if we have two keys we should have a MuxedSKM
byte[] decrData = _context.elGamalAESEngine().decrypt(encData, elgKey, skm);
if (decrData != null) {
rv = readCloveSet(decrData, 0);
} else {
rv = null;
}
}
} catch (DataFormatException dfe) {
if (_log.shouldLog(Log.WARN))
_log.warn("Muxed decrypt fail", dfe);
rv = null;
}
if (rv == null &&_log.shouldWarn())
_log.warn("Muxed decrypt fail");
return rv;
}

/**
* ElGamal only
*
Expand Down
24 changes: 16 additions & 8 deletions router/java/src/net/i2p/router/message/GarlicMessageReceiver.java
Expand Up @@ -57,20 +57,24 @@ public GarlicMessageReceiver(RouterContext context, CloveReceiver receiver, Hash

public void receive(GarlicMessage message) {
PrivateKey decryptionKey;
PrivateKey decryptionKey2 = null;
SessionKeyManager skm;
if (_clientDestination != null) {
LeaseSetKeys keys = _context.keyManager().getKeys(_clientDestination);
skm = _context.clientManager().getClientSessionKeyManager(_clientDestination);
if (keys != null && skm != null) {
// TODO need to pass both keys if available for muxed decrypt
decryptionKey = keys.getDecryptionKey();
decryptionKey2 = keys.getDecryptionKey(EncType.ECIES_X25519);
if (decryptionKey == null && decryptionKey2 == null) {
if (_log.shouldWarn())
_log.warn("No key to decrypt for " + _clientDestination.toBase32());
return;
}
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;
}
// swap
decryptionKey = decryptionKey2;
decryptionKey2 = null;
}
} else {
if (_log.shouldLog(Log.WARN))
Expand All @@ -82,8 +86,12 @@ public void receive(GarlicMessage message) {
skm = _context.sessionKeyManager();
}

// TODO need to pass both keys if available for muxed decrypt
CloveSet set = _context.garlicMessageParser().getGarlicCloves(message, decryptionKey, skm);
// Pass both keys if available for muxed decrypt
CloveSet set;
if (decryptionKey2 != null)
set = _context.garlicMessageParser().getGarlicCloves(message, decryptionKey, decryptionKey2, skm);
else
set = _context.garlicMessageParser().getGarlicCloves(message, decryptionKey, skm);
if (set != null) {
for (int i = 0; i < set.getCloveCount(); i++) {
GarlicClove clove = set.getClove(i);
Expand Down

0 comments on commit 07b7ab4

Please sign in to comment.