forked from I2P_Developers/i2p.i2p
Ratchet: Adaptive order of muxed decrypt based on previous traffic
This commit is contained in:
@ -35,12 +35,15 @@ final class MuxedEngine {
|
|||||||
throw new IllegalArgumentException();
|
throw new IllegalArgumentException();
|
||||||
CloveSet rv = null;
|
CloveSet rv = null;
|
||||||
// Try in-order from fastest to slowest
|
// Try in-order from fastest to slowest
|
||||||
// Ratchet Tag
|
boolean preferRatchet = keyManager.preferRatchet();
|
||||||
rv = _context.eciesEngine().decryptFast(data, ecKey, keyManager.getECSKM());
|
if (preferRatchet) {
|
||||||
if (rv != null)
|
// Ratchet Tag
|
||||||
return rv;
|
rv = _context.eciesEngine().decryptFast(data, ecKey, keyManager.getECSKM());
|
||||||
if (_log.shouldDebug())
|
if (rv != null)
|
||||||
_log.debug("Ratchet tag not found");
|
return rv;
|
||||||
|
if (_log.shouldDebug())
|
||||||
|
_log.debug("Ratchet tag not found before AES");
|
||||||
|
}
|
||||||
// AES Tag
|
// AES Tag
|
||||||
if (data.length >= 128 && (data.length & 0x0f) == 0) {
|
if (data.length >= 128 && (data.length & 0x0f) == 0) {
|
||||||
byte[] dec = _context.elGamalAESEngine().decryptFast(data, elgKey, keyManager.getElgSKM());
|
byte[] dec = _context.elGamalAESEngine().decryptFast(data, elgKey, keyManager.getElgSKM());
|
||||||
@ -48,39 +51,65 @@ final class MuxedEngine {
|
|||||||
try {
|
try {
|
||||||
rv = _context.garlicMessageParser().readCloveSet(dec, 0);
|
rv = _context.garlicMessageParser().readCloveSet(dec, 0);
|
||||||
if (rv == null && _log.shouldInfo())
|
if (rv == null && _log.shouldInfo())
|
||||||
_log.info("AES cloveset error");
|
_log.info("AES cloveset error after AES? " + preferRatchet);
|
||||||
} catch (DataFormatException dfe) {
|
} catch (DataFormatException dfe) {
|
||||||
if (_log.shouldInfo())
|
if (_log.shouldInfo())
|
||||||
_log.info("AES cloveset error", dfe);
|
_log.info("AES cloveset error after AES? " + preferRatchet, dfe);
|
||||||
}
|
}
|
||||||
return rv;
|
return rv;
|
||||||
} else {
|
} else {
|
||||||
if (_log.shouldDebug())
|
if (_log.shouldDebug())
|
||||||
_log.debug("AES tag not found");
|
_log.debug("AES tag not found after ratchet? " + preferRatchet);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Ratchet DH
|
if (!preferRatchet) {
|
||||||
rv = _context.eciesEngine().decryptSlow(data, ecKey, keyManager.getECSKM());
|
// Ratchet Tag
|
||||||
if (rv != null)
|
rv = _context.eciesEngine().decryptFast(data, ecKey, keyManager.getECSKM());
|
||||||
return rv;
|
if (rv != null)
|
||||||
if (_log.shouldDebug())
|
return rv;
|
||||||
_log.debug("Ratchet NS decrypt failed");
|
if (_log.shouldDebug())
|
||||||
|
_log.debug("Ratchet tag not found after AES");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (preferRatchet) {
|
||||||
|
// Ratchet DH
|
||||||
|
rv = _context.eciesEngine().decryptSlow(data, ecKey, keyManager.getECSKM());
|
||||||
|
boolean ok = rv != null;
|
||||||
|
keyManager.reportDecryptResult(true, ok);
|
||||||
|
if (ok)
|
||||||
|
return rv;
|
||||||
|
if (_log.shouldDebug())
|
||||||
|
_log.debug("Ratchet NS decrypt failed before ElG");
|
||||||
|
}
|
||||||
// ElG DH
|
// ElG DH
|
||||||
if (data.length >= 514 && (data.length & 0x0f) == 2) {
|
if (data.length >= 514 && (data.length & 0x0f) == 2) {
|
||||||
byte[] dec = _context.elGamalAESEngine().decryptSlow(data, elgKey, keyManager.getElgSKM());
|
byte[] dec = _context.elGamalAESEngine().decryptSlow(data, elgKey, keyManager.getElgSKM());
|
||||||
if (dec != null) {
|
if (dec != null) {
|
||||||
try {
|
try {
|
||||||
rv = _context.garlicMessageParser().readCloveSet(dec, 0);
|
rv = _context.garlicMessageParser().readCloveSet(dec, 0);
|
||||||
if (rv == null && _log.shouldInfo())
|
boolean ok = rv != null;
|
||||||
_log.info("ElG cloveset error");
|
keyManager.reportDecryptResult(false, ok);
|
||||||
|
if (ok)
|
||||||
|
return rv;
|
||||||
|
if (_log.shouldInfo())
|
||||||
|
_log.info("ElG cloveset error after ratchet? " + preferRatchet);
|
||||||
} catch (DataFormatException dfe) {
|
} catch (DataFormatException dfe) {
|
||||||
if (_log.shouldInfo())
|
if (_log.shouldInfo())
|
||||||
_log.info("ElG cloveset error", dfe);
|
_log.info("ElG cloveset error afterRatchet? " + preferRatchet, dfe);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (_log.shouldInfo())
|
if (_log.shouldInfo())
|
||||||
_log.info("ElG decrypt failed");
|
_log.info("ElG decrypt failed after Ratchet? " + preferRatchet);
|
||||||
}
|
}
|
||||||
|
keyManager.reportDecryptResult(false, false);
|
||||||
|
}
|
||||||
|
if (!preferRatchet) {
|
||||||
|
// Ratchet DH
|
||||||
|
rv = _context.eciesEngine().decryptSlow(data, ecKey, keyManager.getECSKM());
|
||||||
|
boolean ok = rv != null;
|
||||||
|
keyManager.reportDecryptResult(true, ok);
|
||||||
|
if (!ok && _log.shouldDebug())
|
||||||
|
_log.debug("Ratchet NS decrypt failed after ElG");
|
||||||
}
|
}
|
||||||
return rv;
|
return rv;
|
||||||
}
|
}
|
||||||
|
@ -3,6 +3,7 @@ package net.i2p.router.crypto.ratchet;
|
|||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.Writer;
|
import java.io.Writer;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
import java.util.concurrent.atomic.AtomicInteger;
|
||||||
|
|
||||||
import net.i2p.I2PAppContext;
|
import net.i2p.I2PAppContext;
|
||||||
import net.i2p.crypto.EncType;
|
import net.i2p.crypto.EncType;
|
||||||
@ -22,6 +23,11 @@ public class MuxedSKM extends SessionKeyManager {
|
|||||||
|
|
||||||
private final TransientSessionKeyManager _elg;
|
private final TransientSessionKeyManager _elg;
|
||||||
private final RatchetSKM _ec;
|
private final RatchetSKM _ec;
|
||||||
|
private final AtomicInteger _elgCounter = new AtomicInteger();
|
||||||
|
private final AtomicInteger _ecCounter = new AtomicInteger();
|
||||||
|
// ElG is about this much slower than EC
|
||||||
|
private static final int ELG_SLOW_FACTOR = 5;
|
||||||
|
private static final int RESTART_COUNTERS = 500;
|
||||||
|
|
||||||
public MuxedSKM(TransientSessionKeyManager elg, RatchetSKM ec) {
|
public MuxedSKM(TransientSessionKeyManager elg, RatchetSKM ec) {
|
||||||
_elg = elg;
|
_elg = elg;
|
||||||
@ -32,6 +38,42 @@ public class MuxedSKM extends SessionKeyManager {
|
|||||||
|
|
||||||
public RatchetSKM getECSKM() { return _ec; }
|
public RatchetSKM getECSKM() { return _ec; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Should we try the Ratchet slow decrypt before ElG slow decrypt?
|
||||||
|
* Adaptive test based on previous mix of traffic for this SKM,
|
||||||
|
* as reported by reportDecryptResult().
|
||||||
|
*
|
||||||
|
* @since 0.9.46
|
||||||
|
*/
|
||||||
|
boolean preferRatchet() {
|
||||||
|
int ec = _ecCounter.get();
|
||||||
|
int elg = _elgCounter.get();
|
||||||
|
if (ec > RESTART_COUNTERS / 10 &&
|
||||||
|
elg > RESTART_COUNTERS / 10 &&
|
||||||
|
ec + elg > RESTART_COUNTERS) {
|
||||||
|
_ecCounter.set(0);
|
||||||
|
_elgCounter.set(0);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return ec >= elg / ELG_SLOW_FACTOR;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Report the result of a slow decrypt attempt.
|
||||||
|
*
|
||||||
|
* @param isRatchet true for EC, false for ElG
|
||||||
|
* @param success true for successful decrypt
|
||||||
|
* @since 0.9.46
|
||||||
|
*/
|
||||||
|
void reportDecryptResult(boolean isRatchet, boolean success) {
|
||||||
|
if (success) {
|
||||||
|
if (isRatchet)
|
||||||
|
_ecCounter.incrementAndGet();
|
||||||
|
else
|
||||||
|
_elgCounter.incrementAndGet();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ElG only
|
* ElG only
|
||||||
*/
|
*/
|
||||||
|
Reference in New Issue
Block a user