Ratchet: Hook in MuxedEngine decrypt

This commit is contained in:
zzz
2019-11-06 16:20:14 +00:00
parent b7f6cfbf46
commit 07b7ab4262
4 changed files with 82 additions and 19 deletions

View File

@ -14,7 +14,6 @@ import com.southernstorm.noise.protocol.CipherStatePair;
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;
@ -29,6 +28,7 @@ import net.i2p.data.SessionKey;
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;
@ -42,8 +42,9 @@ import net.i2p.util.SimpleByteCache;
* @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;
@ -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);
@ -113,6 +115,17 @@ public final class ECIESAEADEngine {
//// 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.

View File

@ -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;
@ -15,7 +13,7 @@ import net.i2p.util.Log;
*
* @since 0.9.44
*/
public final class MuxedEngine {
final class MuxedEngine {
private final RouterContext _context;
private final Log _log;
@ -27,6 +25,8 @@ public final class MuxedEngine {
/**
* 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 {
@ -51,10 +51,13 @@ public final class MuxedEngine {
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;
}

View File

@ -31,7 +31,7 @@ import net.i2p.util.Log;
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.
@ -42,11 +42,11 @@ public class GarlicMessageParser {
_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
*/
@ -108,7 +108,46 @@ public class GarlicMessageParser {
}
}
}
/**
* 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
*

View File

@ -57,6 +57,7 @@ public class GarlicMessageReceiver {
public void receive(GarlicMessage message) {
PrivateKey decryptionKey;
PrivateKey decryptionKey2 = null;
SessionKeyManager skm;
if (_clientDestination != null) {
LeaseSetKeys keys = _context.keyManager().getKeys(_clientDestination);
@ -64,13 +65,16 @@ public class GarlicMessageReceiver {
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))
@ -82,8 +86,12 @@ public class GarlicMessageReceiver {
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);