From 47eff7ee863171edf516eca3c6c60e1c837c796c Mon Sep 17 00:00:00 2001 From: zzz Date: Sat, 31 Jan 2015 17:37:59 +0000 Subject: [PATCH] PRNG: Don't hang forever at startup waiting for SecureRandom init --- .../src/net/i2p/util/FortunaRandomSource.java | 5 ++ core/java/src/net/i2p/util/RandomSource.java | 53 +++++++++++++++++-- history.txt | 1 + .../src/net/i2p/router/RouterVersion.java | 2 +- 4 files changed, 57 insertions(+), 4 deletions(-) diff --git a/core/java/src/net/i2p/util/FortunaRandomSource.java b/core/java/src/net/i2p/util/FortunaRandomSource.java index 54a93b2a0..340b836a4 100644 --- a/core/java/src/net/i2p/util/FortunaRandomSource.java +++ b/core/java/src/net/i2p/util/FortunaRandomSource.java @@ -27,13 +27,18 @@ public class FortunaRandomSource extends RandomSource implements EntropyHarveste private double _nextGaussian; private boolean _haveNextGaussian; + /** + * May block up to 10 seconds or forever + */ public FortunaRandomSource(I2PAppContext context) { super(context); _fortuna = new AsyncFortunaStandalone(context); byte seed[] = new byte[1024]; + // may block for 10 seconds if (initSeed(seed)) { _fortuna.seed(seed); } else { + // may block forever SecureRandom sr = new SecureRandom(); sr.nextBytes(seed); _fortuna.seed(seed); diff --git a/core/java/src/net/i2p/util/RandomSource.java b/core/java/src/net/i2p/util/RandomSource.java index 56c97bb82..08c4a89d8 100644 --- a/core/java/src/net/i2p/util/RandomSource.java +++ b/core/java/src/net/i2p/util/RandomSource.java @@ -145,6 +145,9 @@ public class RandomSource extends SecureRandom implements EntropyHarvester { } } + /** + * May block up to 10 seconds + */ public void loadSeed() { byte buf[] = new byte[1024]; if (initSeed(buf)) @@ -172,12 +175,31 @@ public class RandomSource extends SecureRandom implements EntropyHarvester { } } + /** + * May block up to 10 seconds + */ public final boolean initSeed(byte buf[]) { boolean ok = false; + + final byte[] tbuf = new byte[buf.length]; + Thread t = new I2PThread(new SecureRandomInit(tbuf), "SecureRandomInit", true); + t.start(); try { - SecureRandom.getInstance("SHA1PRNG").nextBytes(buf); - ok = true; - } catch (NoSuchAlgorithmException e) {} + t.join(10*1000); + synchronized(tbuf) { + for (int i = 0; i < tbuf.length; i++) { + if (tbuf[i] != 0) { + ok = true; + break; + } + } + if (ok) + System.arraycopy(tbuf, 0, buf, 0, buf.length); + else + System.out.println("SecureRandom init failed or took too long"); + } + } catch (InterruptedException ie) {} + // why urandom? because /dev/random blocks ok = seedFromFile(new File("/dev/urandom"), buf) || ok; // we merge (XOR) in the data from /dev/urandom with our own seedfile @@ -186,6 +208,31 @@ public class RandomSource extends SecureRandom implements EntropyHarvester { return ok; } + /** + * Thread to prevent hanging on init, + * presumably due to /dev/random blocking, + * which is common in VMs. + * + * @since 0.9.18 + */ + private static class SecureRandomInit implements Runnable { + private final byte[] buf; + + public SecureRandomInit(byte[] buf) { + this.buf = buf; + } + + public void run() { + byte[] buf2 = new byte[buf.length]; + try { + SecureRandom.getInstance("SHA1PRNG").nextBytes(buf2); + synchronized(buf) { + System.arraycopy(buf2, 0, buf, 0, buf.length); + } + } catch (NoSuchAlgorithmException e) {} + } + } + /** * XORs the seed into buf * diff --git a/history.txt b/history.txt index fc2784793..24a130874 100644 --- a/history.txt +++ b/history.txt @@ -5,6 +5,7 @@ * NetDb: - Encrypt lookups for 32-bit x86 also - Disable floodfill in laptop mode + * PRNG: Don't hang forever at startup waiting for SecureRandom init * Transport: Set 4 MBps max bw due to bloom filter 2015-01-30 zzz diff --git a/router/java/src/net/i2p/router/RouterVersion.java b/router/java/src/net/i2p/router/RouterVersion.java index 8ab24107c..80cfb9c84 100644 --- a/router/java/src/net/i2p/router/RouterVersion.java +++ b/router/java/src/net/i2p/router/RouterVersion.java @@ -18,7 +18,7 @@ public class RouterVersion { /** deprecated */ public final static String ID = "Monotone"; public final static String VERSION = CoreVersion.VERSION; - public final static long BUILD = 17; + public final static long BUILD = 18; /** for example "-test" */ public final static String EXTRA = "";