forked from I2P_Developers/i2p.i2p
added entropy feeding interface, and hooked it up to the end of the DH exchange (source=DH) as well as the end of the ElGamal/AES decrypt (source=ElG/AES). the default RandomSource ignores this data
This commit is contained in:
@ -48,6 +48,7 @@ import net.i2p.util.RandomSource;
|
||||
* @author jrandom
|
||||
*/
|
||||
public class DHSessionKeyBuilder {
|
||||
private static I2PAppContext _context = I2PAppContext.getGlobalContext();
|
||||
private final static Log _log = new Log(DHSessionKeyBuilder.class);
|
||||
private static int MIN_NUM_BUILDERS = -1;
|
||||
private static int MAX_NUM_BUILDERS = -1;
|
||||
@ -68,7 +69,7 @@ public class DHSessionKeyBuilder {
|
||||
public final static String DEFAULT_DH_PRECALC_DELAY = "1000";
|
||||
|
||||
static {
|
||||
I2PAppContext ctx = I2PAppContext.getGlobalContext();
|
||||
I2PAppContext ctx = _context;
|
||||
try {
|
||||
int val = Integer.parseInt(ctx.getProperty(PROP_DH_PRECALC_MIN, DEFAULT_DH_PRECALC_MIN));
|
||||
MIN_NUM_BUILDERS = val;
|
||||
@ -305,6 +306,8 @@ public class DHSessionKeyBuilder {
|
||||
_log.debug("Storing " + remaining.length + " bytes from the DH exchange by SHA256 the session key");
|
||||
} else { // (buf.length >= val.length)
|
||||
System.arraycopy(buf, 0, val, 0, val.length);
|
||||
// feed the extra bytes into the PRNG
|
||||
_context.random().harvester().feedEntropy("DH", buf, val.length, buf.length-val.length);
|
||||
byte remaining[] = new byte[buf.length - val.length];
|
||||
System.arraycopy(buf, val.length, remaining, 0, remaining.length);
|
||||
_extraExchangedBytes.setData(remaining);
|
||||
|
@ -154,11 +154,14 @@ public class ElGamalAESEngine {
|
||||
|
||||
byte preIV[] = null;
|
||||
|
||||
int offset = 0;
|
||||
byte key[] = new byte[SessionKey.KEYSIZE_BYTES];
|
||||
System.arraycopy(elgDecr, 0, key, 0, SessionKey.KEYSIZE_BYTES);
|
||||
System.arraycopy(elgDecr, offset, key, 0, SessionKey.KEYSIZE_BYTES);
|
||||
offset += SessionKey.KEYSIZE_BYTES;
|
||||
usedKey.setData(key);
|
||||
preIV = new byte[32];
|
||||
System.arraycopy(elgDecr, SessionKey.KEYSIZE_BYTES, preIV, 0, 32);
|
||||
System.arraycopy(elgDecr, offset, preIV, 0, 32);
|
||||
offset += 32;
|
||||
|
||||
//_log.debug("Pre IV for decryptNewSession: " + DataHelper.toString(preIV, 32));
|
||||
//_log.debug("SessionKey for decryptNewSession: " + DataHelper.toString(key.getData(), 32));
|
||||
@ -168,6 +171,9 @@ public class ElGamalAESEngine {
|
||||
System.arraycopy(ivHash.getData(), 0, iv, 0, 16);
|
||||
_context.sha().cache().release(cache);
|
||||
|
||||
// feed the extra bytes into the PRNG
|
||||
_context.random().harvester().feedEntropy("ElG/AES", elgDecr, offset, elgDecr.length - offset);
|
||||
|
||||
byte aesDecr[] = decryptAESBlock(data, 514, data.length-514, usedKey, iv, null, foundTags, foundKey);
|
||||
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
@ -403,6 +409,8 @@ public class ElGamalAESEngine {
|
||||
elgEncr = elg;
|
||||
}
|
||||
//_log.debug("ElGamal encrypted length: " + elgEncr.length + " elGamal source length: " + elgSrc.toByteArray().length);
|
||||
|
||||
// should we also feed the encrypted elG block into the harvester?
|
||||
|
||||
SHA256EntryCache.CacheEntry cache = _context.sha().cache().acquire(preIV.length);
|
||||
Hash ivHash = _context.sha().calculateHash(preIV, cache);
|
||||
|
30
core/java/src/net/i2p/crypto/EntropyHarvester.java
Normal file
30
core/java/src/net/i2p/crypto/EntropyHarvester.java
Normal file
@ -0,0 +1,30 @@
|
||||
package net.i2p.crypto;
|
||||
|
||||
/**
|
||||
* Allow various components with some entropy to feed that entropy back
|
||||
* into some PRNG. The quality of the entropy provided varies, so anything
|
||||
* harvesting should discriminate based on the offered "source" of the
|
||||
* entropy, silently discarding insufficient entropy sources.
|
||||
*
|
||||
*/
|
||||
public interface EntropyHarvester {
|
||||
/**
|
||||
* Feed the entropy pools with data[offset:offset+len]
|
||||
*
|
||||
* @param source origin of the entropy, allowing the harvester to
|
||||
* determine how much to value the data
|
||||
* @param offset index into the data array to start
|
||||
* @param len how many bytes to use
|
||||
*/
|
||||
void feedEntropy(String source, byte data[], int offset, int len);
|
||||
/**
|
||||
* Feed the entropy pools with the bits in the data
|
||||
*
|
||||
* @param source origin of the entropy, allowing the harvester to
|
||||
* determine how much to value the data
|
||||
* @param bitoffset bit index into the data array to start
|
||||
* (using java standard big-endian)
|
||||
* @param bits how many bits to use
|
||||
*/
|
||||
void feedEntropy(String source, long data, int bitoffset, int bits);
|
||||
}
|
@ -12,6 +12,7 @@ package net.i2p.util;
|
||||
import java.security.SecureRandom;
|
||||
|
||||
import net.i2p.I2PAppContext;
|
||||
import net.i2p.crypto.EntropyHarvester;
|
||||
|
||||
/**
|
||||
* Singleton for whatever PRNG i2p uses.
|
||||
@ -20,10 +21,14 @@ import net.i2p.I2PAppContext;
|
||||
*/
|
||||
public class RandomSource extends SecureRandom {
|
||||
private Log _log;
|
||||
private EntropyHarvester _entropyHarvester;
|
||||
|
||||
public RandomSource(I2PAppContext context) {
|
||||
super();
|
||||
_log = context.logManager().getLog(RandomSource.class);
|
||||
// when we replace to have hooks for fortuna (etc), replace with
|
||||
// a factory (or just a factory method)
|
||||
_entropyHarvester = new DummyEntropyHarvester();
|
||||
}
|
||||
public static RandomSource getInstance() {
|
||||
return I2PAppContext.getGlobalContext().random();
|
||||
@ -62,4 +67,12 @@ public class RandomSource extends SecureRandom {
|
||||
super.nextBytes(bytes);
|
||||
}
|
||||
}
|
||||
|
||||
public EntropyHarvester harvester() { return _entropyHarvester; }
|
||||
|
||||
// noop
|
||||
private static class DummyEntropyHarvester implements EntropyHarvester {
|
||||
public void feedEntropy(String source, long data, int bitoffset, int bits) {}
|
||||
public void feedEntropy(String source, byte[] data, int offset, int len) {}
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user