PRNG: Switch to /dev/random by default

This commit is contained in:
zzz
2025-04-04 12:00:55 +00:00
parent ec1458d75d
commit 8ac8ad4238
4 changed files with 41 additions and 68 deletions

View File

@ -40,14 +40,13 @@ public class AsyncFortunaStandalone extends FortunaStandalone implements Runnabl
private AsyncBuffer _currentBuffer;
public AsyncFortunaStandalone(I2PAppContext context) {
super(context.getBooleanProperty("prng.useDevRandom") && !SystemVersion.isWindows() && !SystemVersion.isSlow());
super(context.getBooleanPropertyDefaultTrue("prng.useDevRandom") && !SystemVersion.isWindows() && !SystemVersion.isSlow());
_bufferCount = Math.max(context.getProperty("prng.buffers", DEFAULT_BUFFERS), 2);
_bufferSize = Math.max(context.getProperty("prng.bufferSize", DEFAULT_BUFSIZE), 16*1024);
_emptyBuffers = new LinkedBlockingQueue<AsyncBuffer>(_bufferCount);
_fullBuffers = new LinkedBlockingQueue<AsyncBuffer>(_bufferCount);
_context = context;
context.statManager().createRateStat("prng.bufferWaitTime", "Delay for random number buffer (ms)", "Encryption", new long[] { 60*1000, 10*60*1000, 60*60*1000 } );
context.statManager().createRateStat("prng.bufferFillTime", "Time to fill random number buffer (ms)", "Encryption", new long[] { 60*1000, 10*60*1000, 60*60*1000 } );
context.statManager().createRateStat("prng.bufferFillTime", "Time to fill random number buffer (ms)", "Encryption", new long[] { 60*60*1000 } );
_log = context.logManager().getLog(AsyncFortunaStandalone.class);
}
@ -80,12 +79,8 @@ public class AsyncFortunaStandalone extends FortunaStandalone implements Runnabl
public void seed(byte val[]) {
Map<String, byte[]> props = Collections.singletonMap(SEED, val);
init(props);
//fillBlock();
}
@Override
protected void allocBuffer() {}
private static class AsyncBuffer {
public final byte[] buffer;
@ -103,7 +98,6 @@ public class AsyncFortunaStandalone extends FortunaStandalone implements Runnabl
AsyncBuffer old = _currentBuffer;
if (old != null)
_emptyBuffers.offer(old);
long before = System.currentTimeMillis();
AsyncBuffer nextBuffer = null;
while (nextBuffer == null) {
@ -115,11 +109,6 @@ public class AsyncFortunaStandalone extends FortunaStandalone implements Runnabl
continue;
}
}
long waited = System.currentTimeMillis()-before;
_context.statManager().addRateData("prng.bufferWaitTime", waited, 0);
if (waited > 10*1000 && _log.shouldLog(Log.WARN))
_log.warn(Thread.currentThread().getName() + ": Took " + waited
+ "ms for a full PRNG buffer to be found");
_currentBuffer = nextBuffer;
buffer = nextBuffer.buffer;
}
@ -162,26 +151,22 @@ public class AsyncFortunaStandalone extends FortunaStandalone implements Runnabl
}
private void doFill(byte buf[]) {
//long start = System.currentTimeMillis();
if (pool0Count >= MIN_POOL_SIZE
&& System.currentTimeMillis() - lastReseed > 100)
{
reseedCount++;
//byte[] seed = new byte[0];
for (int i = 0; i < NUM_POOLS; i++)
if (pools != null) {
if (pool0Count >= MIN_POOL_SIZE
&& System.currentTimeMillis() - lastReseed > 100)
{
if (reseedCount % (1 << i) == 0) {
generator.addRandomBytes(pools[i].digest());
}
reseedCount++;
//byte[] seed = new byte[0];
for (int i = 0; i < NUM_POOLS; i++)
{
if (reseedCount % (1 << i) == 0) {
generator.addRandomBytes(pools[i].digest());
}
}
lastReseed = System.currentTimeMillis();
}
lastReseed = System.currentTimeMillis();
}
} // else we're using DevRandom
generator.nextBytes(buf);
//long now = System.currentTimeMillis();
//long diff = now-lastRefill;
//lastRefill = now;
//long refillTime = now-start;
//System.out.println("Refilling " + (++refillCount) + " after " + diff + " for the PRNG took " + refillTime);
}
/*****

View File

@ -18,10 +18,17 @@ class DevRandom implements IRandomStandalone {
private static final String F = "/dev/random";
private final File file = new File(F);
/**
* @since 0.9.66
*/
public static boolean isSupported() {
return (new File(F)).canRead();
}
public String name() { return F; }
public void init(Map<String, byte[]> attributes) {
if (!file.canRead())
if (!isSupported())
throw new IllegalStateException("Cannot open " + F);
}
@ -29,9 +36,6 @@ class DevRandom implements IRandomStandalone {
throw new IllegalStateException("unsupported");
}
/**
* @since 0.9.58 added to interface
*/
public void nextBytes(byte[] out) throws IllegalStateException {
nextBytes(out, 0, out.length);
}

View File

@ -48,7 +48,6 @@ import java.io.Serializable;
import java.security.InvalidKeyException;
import java.security.MessageDigest;
import java.util.Arrays;
import java.util.Collections;
import java.util.Map;
import net.i2p.crypto.CryptixAESKeyCache;
@ -104,6 +103,7 @@ public class FortunaStandalone extends BasePRNGStandalone implements Serializabl
static final int NUM_POOLS = 32;
static final int MIN_POOL_SIZE = 64;
protected final IRandomStandalone generator;
/** null if using DevRandom */
protected final MessageDigest[] pools;
protected long lastReseed;
private int pool;
@ -121,23 +121,22 @@ public class FortunaStandalone extends BasePRNGStandalone implements Serializabl
*/
public FortunaStandalone(boolean useDevRandom) {
super("Fortuna i2p");
if (useDevRandom && !DevRandom.isSupported())
useDevRandom = false;
generator = useDevRandom ? new DevRandom() : new Generator();
pools = new MessageDigest[NUM_POOLS];
for (int i = 0; i < NUM_POOLS; i++)
pools[i] = SHA256Generator.getDigestInstance();
allocBuffer();
}
/** Unused, see AsyncFortunaStandalone */
protected void allocBuffer() {
buffer = new byte[64*1024];
if (useDevRandom) {
pools = null;
} else {
pools = new MessageDigest[NUM_POOLS];
for (int i = 0; i < NUM_POOLS; i++) {
pools[i] = SHA256Generator.getDigestInstance();
}
}
}
/** Unused, see AsyncFortunaStandalone */
public void seed(byte val[]) {
Map<String, byte[]> props = Collections.singletonMap(SEED, val);
init(props);
fillBlock();
throw new UnsupportedOperationException("use override");
}
public void setup(Map<String, byte[]> attributes)
@ -152,31 +151,14 @@ public class FortunaStandalone extends BasePRNGStandalone implements Serializabl
/** Unused, see AsyncFortunaStandalone */
public void fillBlock()
{
//long start = System.currentTimeMillis();
if (pool0Count >= MIN_POOL_SIZE
&& System.currentTimeMillis() - lastReseed > 100)
{
reseedCount++;
//byte[] seed = new byte[0];
for (int i = 0; i < NUM_POOLS; i++)
{
if (reseedCount % (1 << i) == 0) {
generator.addRandomBytes(pools[i].digest());
}
}
lastReseed = System.currentTimeMillis();
}
generator.nextBytes(buffer);
//long now = System.currentTimeMillis();
//long diff = now-lastRefill;
//lastRefill = now;
//long refillTime = now-start;
//System.out.println("Refilling " + (++refillCount) + " after " + diff + " for the PRNG took " + refillTime);
throw new UnsupportedOperationException("use override");
}
@Override
public void addRandomByte(byte b)
{
if (pools == null)
return;
pools[pool].update(b);
if (pool == 0)
pool0Count++;
@ -186,6 +168,8 @@ public class FortunaStandalone extends BasePRNGStandalone implements Serializabl
@Override
public void addRandomBytes(byte[] buf, int offset, int length)
{
if (pools == null)
return;
pools[pool].update(buf, offset, length);
if (pool == 0)
pool0Count += length;

View File

@ -170,7 +170,7 @@ public class RouterContext extends I2PAppContext {
// or about 2 seconds per buffer - so about 200x faster
// to fill than to drain - so we don't need too many
long maxMemory = SystemVersion.getMaxMemory();
long maxBuffs = (SystemVersion.isAndroid() || SystemVersion.isARM()) ? 3 : 5;
long maxBuffs = 3;
long buffs = Math.min(maxBuffs, Math.max(2, maxMemory / (21 * 1024 * 1024)));
envProps.setProperty("prng.buffers", Long.toString(buffs));
}