fix up DH like YK
This commit is contained in:
@ -13,8 +13,7 @@ import java.io.IOException;
|
|||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.io.OutputStream;
|
import java.io.OutputStream;
|
||||||
import java.math.BigInteger;
|
import java.math.BigInteger;
|
||||||
import java.util.ArrayList;
|
import java.util.concurrent.LinkedBlockingQueue;
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import net.i2p.I2PAppContext;
|
import net.i2p.I2PAppContext;
|
||||||
import net.i2p.I2PException;
|
import net.i2p.I2PException;
|
||||||
@ -48,14 +47,15 @@ import net.i2p.util.RandomSource;
|
|||||||
* @author jrandom
|
* @author jrandom
|
||||||
*/
|
*/
|
||||||
public class DHSessionKeyBuilder {
|
public class DHSessionKeyBuilder {
|
||||||
private static I2PAppContext _context = I2PAppContext.getGlobalContext();
|
private static final I2PAppContext _context = I2PAppContext.getGlobalContext();
|
||||||
private final static Log _log = new Log(DHSessionKeyBuilder.class);
|
private static final Log _log;
|
||||||
private static int MIN_NUM_BUILDERS = -1;
|
private static final int MIN_NUM_BUILDERS;
|
||||||
private static int MAX_NUM_BUILDERS = -1;
|
private static final int MAX_NUM_BUILDERS;
|
||||||
private static int CALC_DELAY = -1;
|
private static final int CALC_DELAY;
|
||||||
/* FIXME this should be final if you syncronize FIXME */
|
private static final LinkedBlockingQueue<DHSessionKeyBuilder> _builders;
|
||||||
private static volatile List _builders = new ArrayList(50);
|
private static final Thread _precalcThread;
|
||||||
private static Thread _precalcThread = null;
|
|
||||||
|
// the data of importance
|
||||||
private BigInteger _myPrivateValue;
|
private BigInteger _myPrivateValue;
|
||||||
private BigInteger _myPublicValue;
|
private BigInteger _myPublicValue;
|
||||||
private BigInteger _peerValue;
|
private BigInteger _peerValue;
|
||||||
@ -65,17 +65,31 @@ public class DHSessionKeyBuilder {
|
|||||||
public final static String PROP_DH_PRECALC_MIN = "crypto.dh.precalc.min";
|
public final static String PROP_DH_PRECALC_MIN = "crypto.dh.precalc.min";
|
||||||
public final static String PROP_DH_PRECALC_MAX = "crypto.dh.precalc.max";
|
public final static String PROP_DH_PRECALC_MAX = "crypto.dh.precalc.max";
|
||||||
public final static String PROP_DH_PRECALC_DELAY = "crypto.dh.precalc.delay";
|
public final static String PROP_DH_PRECALC_DELAY = "crypto.dh.precalc.delay";
|
||||||
public final static int DEFAULT_DH_PRECALC_MIN = 5;
|
public final static int DEFAULT_DH_PRECALC_MIN = 15;
|
||||||
public final static int DEFAULT_DH_PRECALC_MAX = 50;
|
public final static int DEFAULT_DH_PRECALC_MAX = 40;
|
||||||
public final static int DEFAULT_DH_PRECALC_DELAY = 10000;
|
public final static int DEFAULT_DH_PRECALC_DELAY = 200;
|
||||||
|
|
||||||
|
/** check every 30 seconds whether we have less than the minimum */
|
||||||
|
private static long _checkDelay = 30 * 1000;
|
||||||
|
|
||||||
static {
|
static {
|
||||||
I2PAppContext ctx = _context;
|
I2PAppContext ctx = _context;
|
||||||
ctx.statManager().createRateStat("crypto.dhGeneratePublicTime", "How long it takes to create x and X", "Encryption", new long[] { 60*1000, 5*60*1000, 60*60*1000 });
|
_log = ctx.logManager().getLog(DHSessionKeyBuilder.class);
|
||||||
ctx.statManager().createRateStat("crypto.dhCalculateSessionTime", "How long it takes to create the session key", "Encryption", new long[] { 60*1000, 5*60*1000, 60*60*1000 });
|
ctx.statManager().createRateStat("crypto.dhGeneratePublicTime", "How long it takes to create x and X", "Encryption", new long[] { 60*60*1000 });
|
||||||
MIN_NUM_BUILDERS = ctx.getProperty(PROP_DH_PRECALC_MIN, DEFAULT_DH_PRECALC_MIN);
|
ctx.statManager().createRateStat("crypto.dhCalculateSessionTime", "How long it takes to create the session key", "Encryption", new long[] { 60*60*1000 });
|
||||||
MAX_NUM_BUILDERS = ctx.getProperty(PROP_DH_PRECALC_MAX, DEFAULT_DH_PRECALC_MAX);
|
ctx.statManager().createRateStat("crypto.DHUsed", "Need a DH from the queue", "Encryption", new long[] { 60*60*1000 });
|
||||||
|
ctx.statManager().createRateStat("crypto.DHEmpty", "DH queue empty", "Encryption", new long[] { 60*60*1000 });
|
||||||
|
|
||||||
|
// add to the defaults for every 128MB of RAM, up to 512MB
|
||||||
|
long maxMemory = Runtime.getRuntime().maxMemory();
|
||||||
|
int factor = Math.min(4, (int) (1 + (maxMemory / (128*1024*1024l))));
|
||||||
|
int defaultMin = DEFAULT_DH_PRECALC_MIN * factor;
|
||||||
|
int defaultMax = DEFAULT_DH_PRECALC_MAX * factor;
|
||||||
|
MIN_NUM_BUILDERS = ctx.getProperty(PROP_DH_PRECALC_MIN, defaultMin);
|
||||||
|
MAX_NUM_BUILDERS = ctx.getProperty(PROP_DH_PRECALC_MAX, defaultMax);
|
||||||
|
|
||||||
CALC_DELAY = ctx.getProperty(PROP_DH_PRECALC_DELAY, DEFAULT_DH_PRECALC_DELAY);
|
CALC_DELAY = ctx.getProperty(PROP_DH_PRECALC_DELAY, DEFAULT_DH_PRECALC_DELAY);
|
||||||
|
_builders = new LinkedBlockingQueue(MAX_NUM_BUILDERS);
|
||||||
|
|
||||||
if (_log.shouldLog(Log.DEBUG))
|
if (_log.shouldLog(Log.DEBUG))
|
||||||
_log.debug("DH Precalc (minimum: " + MIN_NUM_BUILDERS + " max: " + MAX_NUM_BUILDERS + ", delay: "
|
_log.debug("DH Precalc (minimum: " + MIN_NUM_BUILDERS + " max: " + MAX_NUM_BUILDERS + ", delay: "
|
||||||
@ -90,40 +104,33 @@ public class DHSessionKeyBuilder {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Construct a new DH key builder
|
* Construct a new DH key builder
|
||||||
*
|
* or pulls a prebuilt one from the queue.
|
||||||
*/
|
*/
|
||||||
public DHSessionKeyBuilder() {
|
public DHSessionKeyBuilder() {
|
||||||
this(false);
|
_context.statManager().addRateData("crypto.DHUsed", 1, 0);
|
||||||
DHSessionKeyBuilder builder = null;
|
DHSessionKeyBuilder builder = _builders.poll();
|
||||||
synchronized (_builders) {
|
|
||||||
if (!_builders.isEmpty()) {
|
|
||||||
builder = (DHSessionKeyBuilder) _builders.remove(0);
|
|
||||||
if (_log.shouldLog(Log.DEBUG)) _log.debug("Removing a builder. # left = " + _builders.size());
|
|
||||||
} else {
|
|
||||||
if (_log.shouldLog(Log.WARN)) _log.warn("NO MORE BUILDERS! creating one now");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (builder != null) {
|
if (builder != null) {
|
||||||
|
if (_log.shouldLog(Log.DEBUG)) _log.debug("Removing a builder. # left = " + _builders.size());
|
||||||
_myPrivateValue = builder._myPrivateValue;
|
_myPrivateValue = builder._myPrivateValue;
|
||||||
_myPublicValue = builder._myPublicValue;
|
_myPublicValue = builder._myPublicValue;
|
||||||
_peerValue = builder._peerValue;
|
// these two are still null after precalc
|
||||||
_sessionKey = builder._sessionKey;
|
//_peerValue = builder._peerValue;
|
||||||
|
//_sessionKey = builder._sessionKey;
|
||||||
_extraExchangedBytes = builder._extraExchangedBytes;
|
_extraExchangedBytes = builder._extraExchangedBytes;
|
||||||
} else {
|
} else {
|
||||||
_myPrivateValue = null;
|
if (_log.shouldLog(Log.INFO)) _log.info("No more builders, creating one now");
|
||||||
_myPublicValue = null;
|
_context.statManager().addRateData("crypto.DHEmpty", 1, 0);
|
||||||
_peerValue = null;
|
// sets _myPrivateValue as a side effect
|
||||||
_sessionKey = null;
|
|
||||||
_myPublicValue = generateMyValue();
|
_myPublicValue = generateMyValue();
|
||||||
_extraExchangedBytes = new ByteArray();
|
_extraExchangedBytes = new ByteArray();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public DHSessionKeyBuilder(boolean usePool) {
|
/**
|
||||||
_myPrivateValue = null;
|
* Only for internal use
|
||||||
_myPublicValue = null;
|
* @parameter usePool unused, just to make it different from other constructor
|
||||||
_peerValue = null;
|
*/
|
||||||
_sessionKey = null;
|
private DHSessionKeyBuilder(boolean usePool) {
|
||||||
_extraExchangedBytes = new ByteArray();
|
_extraExchangedBytes = new ByteArray();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -189,18 +196,12 @@ public class DHSessionKeyBuilder {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private static final int getSize() {
|
private static final int getSize() {
|
||||||
synchronized (_builders) {
|
|
||||||
return _builders.size();
|
return _builders.size();
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static final int addBuilder(DHSessionKeyBuilder builder) {
|
/** @return true if successful, false if full */
|
||||||
int sz = 0;
|
private static final boolean addBuilder(DHSessionKeyBuilder builder) {
|
||||||
synchronized (_builders) {
|
return _builders.offer(builder);
|
||||||
_builders.add(builder);
|
|
||||||
sz = _builders.size();
|
|
||||||
}
|
|
||||||
return sz;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -210,7 +211,7 @@ public class DHSessionKeyBuilder {
|
|||||||
*/
|
*/
|
||||||
public BigInteger generateMyValue() {
|
public BigInteger generateMyValue() {
|
||||||
long start = System.currentTimeMillis();
|
long start = System.currentTimeMillis();
|
||||||
_myPrivateValue = new NativeBigInteger(KeyGenerator.PUBKEY_EXPONENT_SIZE, RandomSource.getInstance());
|
_myPrivateValue = new NativeBigInteger(KeyGenerator.PUBKEY_EXPONENT_SIZE, _context.random());
|
||||||
BigInteger myValue = CryptoConstants.elgg.modPow(_myPrivateValue, CryptoConstants.elgp);
|
BigInteger myValue = CryptoConstants.elgg.modPow(_myPrivateValue, CryptoConstants.elgp);
|
||||||
long end = System.currentTimeMillis();
|
long end = System.currentTimeMillis();
|
||||||
long diff = end - start;
|
long diff = end - start;
|
||||||
@ -314,6 +315,7 @@ public class DHSessionKeyBuilder {
|
|||||||
* If there aren't enough bytes (with all of them being consumed by the 32 byte key),
|
* If there aren't enough bytes (with all of them being consumed by the 32 byte key),
|
||||||
* the SHA256 of the key itself is used.
|
* the SHA256 of the key itself is used.
|
||||||
*
|
*
|
||||||
|
* @return non-null (but rv.getData() may be null)
|
||||||
*/
|
*/
|
||||||
public ByteArray getExtraBytes() {
|
public ByteArray getExtraBytes() {
|
||||||
return _extraExchangedBytes;
|
return _extraExchangedBytes;
|
||||||
@ -406,6 +408,7 @@ public class DHSessionKeyBuilder {
|
|||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
/******
|
||||||
public static void main(String args[]) {
|
public static void main(String args[]) {
|
||||||
//if (true) { testValidation(); return; }
|
//if (true) { testValidation(); return; }
|
||||||
|
|
||||||
@ -419,7 +422,7 @@ public class DHSessionKeyBuilder {
|
|||||||
long negTime = 0;
|
long negTime = 0;
|
||||||
try {
|
try {
|
||||||
for (int i = 0; i < 5; i++) {
|
for (int i = 0; i < 5; i++) {
|
||||||
long startNeg = Clock.getInstance().now();
|
long startNeg = System.currentTimeMillis();
|
||||||
DHSessionKeyBuilder builder1 = new DHSessionKeyBuilder();
|
DHSessionKeyBuilder builder1 = new DHSessionKeyBuilder();
|
||||||
DHSessionKeyBuilder builder2 = new DHSessionKeyBuilder();
|
DHSessionKeyBuilder builder2 = new DHSessionKeyBuilder();
|
||||||
BigInteger pub1 = builder1.getMyPublicValue();
|
BigInteger pub1 = builder1.getMyPublicValue();
|
||||||
@ -428,7 +431,7 @@ public class DHSessionKeyBuilder {
|
|||||||
builder1.setPeerPublicValue(pub2);
|
builder1.setPeerPublicValue(pub2);
|
||||||
SessionKey key1 = builder1.getSessionKey();
|
SessionKey key1 = builder1.getSessionKey();
|
||||||
SessionKey key2 = builder2.getSessionKey();
|
SessionKey key2 = builder2.getSessionKey();
|
||||||
long endNeg = Clock.getInstance().now();
|
long endNeg = System.currentTimeMillis();
|
||||||
negTime += endNeg - startNeg;
|
negTime += endNeg - startNeg;
|
||||||
|
|
||||||
if (!key1.equals(key2))
|
if (!key1.equals(key2))
|
||||||
@ -458,10 +461,11 @@ public class DHSessionKeyBuilder {
|
|||||||
} catch (InterruptedException ie) { // nop
|
} catch (InterruptedException ie) { // nop
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
******/
|
||||||
|
|
||||||
private static class DHSessionKeyBuilderPrecalcRunner implements Runnable {
|
private static class DHSessionKeyBuilderPrecalcRunner implements Runnable {
|
||||||
private int _minSize;
|
private final int _minSize;
|
||||||
private int _maxSize;
|
private final int _maxSize;
|
||||||
|
|
||||||
private DHSessionKeyBuilderPrecalcRunner(int minSize, int maxSize) {
|
private DHSessionKeyBuilderPrecalcRunner(int minSize, int maxSize) {
|
||||||
_minSize = minSize;
|
_minSize = minSize;
|
||||||
@ -472,22 +476,28 @@ public class DHSessionKeyBuilder {
|
|||||||
while (true) {
|
while (true) {
|
||||||
|
|
||||||
int curSize = 0;
|
int curSize = 0;
|
||||||
long start = Clock.getInstance().now();
|
long start = System.currentTimeMillis();
|
||||||
int startSize = getSize();
|
int startSize = getSize();
|
||||||
|
// Adjust delay
|
||||||
|
if (startSize <= (_minSize * 2 / 3) && _checkDelay > 1000)
|
||||||
|
_checkDelay -= 1000;
|
||||||
|
else if (startSize > (_minSize * 3 / 2) && _checkDelay < 60*1000)
|
||||||
|
_checkDelay += 1000;
|
||||||
curSize = startSize;
|
curSize = startSize;
|
||||||
while (curSize < _minSize) {
|
if (curSize < _minSize) {
|
||||||
while (curSize < _maxSize) {
|
for (int i = curSize; i < _maxSize; i++) {
|
||||||
long curStart = System.currentTimeMillis();
|
long curStart = System.currentTimeMillis();
|
||||||
curSize = addBuilder(precalc(curSize));
|
if (!addBuilder(precalc()))
|
||||||
|
break;
|
||||||
long curCalc = System.currentTimeMillis() - curStart;
|
long curCalc = System.currentTimeMillis() - curStart;
|
||||||
// for some relief...
|
// for some relief...
|
||||||
try {
|
try {
|
||||||
Thread.sleep(CALC_DELAY + curCalc * 10);
|
Thread.sleep(CALC_DELAY + (curCalc * 3));
|
||||||
} catch (InterruptedException ie) { // nop
|
} catch (InterruptedException ie) { // nop
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
long end = Clock.getInstance().now();
|
long end = System.currentTimeMillis();
|
||||||
int numCalc = curSize - startSize;
|
int numCalc = curSize - startSize;
|
||||||
if (numCalc > 0) {
|
if (numCalc > 0) {
|
||||||
if (_log.shouldLog(Log.DEBUG))
|
if (_log.shouldLog(Log.DEBUG))
|
||||||
@ -496,16 +506,15 @@ public class DHSessionKeyBuilder {
|
|||||||
+ (CALC_DELAY * numCalc) + "ms relief). now sleeping");
|
+ (CALC_DELAY * numCalc) + "ms relief). now sleeping");
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
Thread.sleep(30 * 1000);
|
Thread.sleep(_checkDelay);
|
||||||
} catch (InterruptedException ie) { // nop
|
} catch (InterruptedException ie) { // nop
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private DHSessionKeyBuilder precalc(int i) {
|
private static DHSessionKeyBuilder precalc() {
|
||||||
DHSessionKeyBuilder builder = new DHSessionKeyBuilder(false);
|
DHSessionKeyBuilder builder = new DHSessionKeyBuilder(false);
|
||||||
builder.getMyPublicValue();
|
builder.getMyPublicValue();
|
||||||
//_log.debug("Precalc " + i + " complete");
|
|
||||||
return builder;
|
return builder;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user