From 8ac8ad42383d19719e2092d1c2ee42a1a40588b6 Mon Sep 17 00:00:00 2001 From: zzz Date: Fri, 4 Apr 2025 12:00:55 +0000 Subject: [PATCH] PRNG: Switch to /dev/random by default --- .../crypto/prng/AsyncFortunaStandalone.java | 45 ++++++----------- core/java/src/gnu/crypto/prng/DevRandom.java | 12 +++-- .../gnu/crypto/prng/FortunaStandalone.java | 50 +++++++------------ .../src/net/i2p/router/RouterContext.java | 2 +- 4 files changed, 41 insertions(+), 68 deletions(-) diff --git a/core/java/src/gnu/crypto/prng/AsyncFortunaStandalone.java b/core/java/src/gnu/crypto/prng/AsyncFortunaStandalone.java index c0be6492b..c159a4cc7 100644 --- a/core/java/src/gnu/crypto/prng/AsyncFortunaStandalone.java +++ b/core/java/src/gnu/crypto/prng/AsyncFortunaStandalone.java @@ -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(_bufferCount); _fullBuffers = new LinkedBlockingQueue(_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 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); } /***** diff --git a/core/java/src/gnu/crypto/prng/DevRandom.java b/core/java/src/gnu/crypto/prng/DevRandom.java index a8f2cf2ff..d0845d0ff 100644 --- a/core/java/src/gnu/crypto/prng/DevRandom.java +++ b/core/java/src/gnu/crypto/prng/DevRandom.java @@ -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 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); } diff --git a/core/java/src/gnu/crypto/prng/FortunaStandalone.java b/core/java/src/gnu/crypto/prng/FortunaStandalone.java index 3856ebbd5..758fe283b 100644 --- a/core/java/src/gnu/crypto/prng/FortunaStandalone.java +++ b/core/java/src/gnu/crypto/prng/FortunaStandalone.java @@ -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 props = Collections.singletonMap(SEED, val); - init(props); - fillBlock(); + throw new UnsupportedOperationException("use override"); } public void setup(Map 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; diff --git a/router/java/src/net/i2p/router/RouterContext.java b/router/java/src/net/i2p/router/RouterContext.java index bb8e3e99c..bdd92e331 100644 --- a/router/java/src/net/i2p/router/RouterContext.java +++ b/router/java/src/net/i2p/router/RouterContext.java @@ -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)); }