From a99caa14da7d327be57bbcffdc6552c8af8cbd78 Mon Sep 17 00:00:00 2001 From: Andrew John Hughes Date: Tue, 3 Feb 2009 21:02:57 +0000 Subject: 2009-01-22 Mario Torre PR classpath/38417: * gnu/java/security/jce/prng/SecureRandomAdapter.java: (getSeed(int)): New; retrieve seed from source specified by securerandom.source property or failing that, use VMSecureRandom. * gnu/javax/crypto/jce/prng/ARCFourRandomSpi.java: (engineGenerateSeed(int)): Use SecureRandomAdapter. (engineNextBytes(byte[])): Initialise using new seed. * gnu/javax/crypto/jce/prng/CSPRNGSpi.java: (engineGenerateSeed(int)): Use SecureRandomAdapter. (engineNextBytes(byte[])): Initialise using new seed. * gnu/javax/crypto/jce/prng/FortunaImpl.java: (engineSetSeed(byte[])): Initialise with new seed if unused. (engineGenerateSeed(int)): Use SecureRandomAdapter. * gnu/javax/crypto/jce/prng/ICMRandomSpi.java: (engineGenerateSeed(int)): Use SecureRandomAdapter. (engineNextBytes(byte[])): Initialise using new seed. * gnu/javax/crypto/jce/prng/UMacRandomSpi.java: (engineGenerateSeed(int)): Use SecureRandomAdapter. (engineNextBytes(byte[])): Initialise using new seed. * gnu/javax/crypto/prng/ICMGenerator.java: (setup(Map)): Call fillBlock(). --- ChangeLog | 25 +++++ .../security/jce/prng/SecureRandomAdapter.java | 122 +++++++++++++++++---- gnu/javax/crypto/jce/prng/ARCFourRandomSpi.java | 15 +-- gnu/javax/crypto/jce/prng/CSPRNGSpi.java | 17 +-- gnu/javax/crypto/jce/prng/FortunaImpl.java | 23 +++- gnu/javax/crypto/jce/prng/ICMRandomSpi.java | 21 +--- gnu/javax/crypto/jce/prng/UMacRandomSpi.java | 10 +- gnu/javax/crypto/prng/ICMGenerator.java | 9 ++ 8 files changed, 178 insertions(+), 64 deletions(-) diff --git a/ChangeLog b/ChangeLog index 5d92e1c2e..11f04c61c 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,28 @@ +2009-01-22 Mario Torre + + PR classpath/38417: + * gnu/java/security/jce/prng/SecureRandomAdapter.java: + (getSeed(int)): New; retrieve seed from source specified + by securerandom.source property or failing that, use + VMSecureRandom. + * gnu/javax/crypto/jce/prng/ARCFourRandomSpi.java: + (engineGenerateSeed(int)): Use SecureRandomAdapter. + (engineNextBytes(byte[])): Initialise using new seed. + * gnu/javax/crypto/jce/prng/CSPRNGSpi.java: + (engineGenerateSeed(int)): Use SecureRandomAdapter. + (engineNextBytes(byte[])): Initialise using new seed. + * gnu/javax/crypto/jce/prng/FortunaImpl.java: + (engineSetSeed(byte[])): Initialise with new seed if unused. + (engineGenerateSeed(int)): Use SecureRandomAdapter. + * gnu/javax/crypto/jce/prng/ICMRandomSpi.java: + (engineGenerateSeed(int)): Use SecureRandomAdapter. + (engineNextBytes(byte[])): Initialise using new seed. + * gnu/javax/crypto/jce/prng/UMacRandomSpi.java: + (engineGenerateSeed(int)): Use SecureRandomAdapter. + (engineNextBytes(byte[])): Initialise using new seed. + * gnu/javax/crypto/prng/ICMGenerator.java: + (setup(Map)): Call fillBlock(). + 2009-01-22 Mark Wielaard * tools/gnu/classpath/tools/gjdoc/Main.java (getGjdocVersion): diff --git a/gnu/java/security/jce/prng/SecureRandomAdapter.java b/gnu/java/security/jce/prng/SecureRandomAdapter.java index 5be402ff0..a17c6eb1b 100644 --- a/gnu/java/security/jce/prng/SecureRandomAdapter.java +++ b/gnu/java/security/jce/prng/SecureRandomAdapter.java @@ -38,35 +38,58 @@ exception statement from your version. */ package gnu.java.security.jce.prng; +import gnu.java.security.action.GetSecurityPropertyAction; +import gnu.classpath.SystemProperties; import gnu.java.security.prng.LimitReachedException; import gnu.java.security.prng.MDGenerator; +import java.security.AccessController; +import java.security.SecureRandom; +import java.security.VMSecureRandom; import java.security.SecureRandomSpi; + import java.util.Collections; +import java.util.logging.Level; +import java.util.logging.Logger; + +import java.io.InputStream; +import java.io.IOException; + +import java.net.MalformedURLException; +import java.net.URL; /** - * The implementation of a generic {@link java.security.SecureRandom} adapter - * class to wrap GNU PRNG instances based on Message Digest algorithms. - *

- * This class defines the Service Provider Interface (SPI) for + *

The implementation of a generic {@link java.security.SecureRandom} adapter + * class to wrap gnu.crypto prng instances based on Message Digest algorithms.

+ * + *

This class defines the Service Provider Interface (SPI) for * the {@link java.security.SecureRandom} class, which provides the - * functionality of a cryptographically strong pseudo-random number generator. - *

- * All the abstract methods in the {@link SecureRandomSpi} class are implemented - * by this class and all its sub-classes. + * functionality of a cryptographically strong pseudo-random number generator.

+ * + *

All the abstract methods in the {@link SecureRandomSpi} class are + * implemented by this class and all its sub-classes.

*/ -abstract class SecureRandomAdapter - extends SecureRandomSpi +public abstract class SecureRandomAdapter + extends SecureRandomSpi { + + private boolean isSeeded = false; + /** Our underlying prng instance. */ private MDGenerator adaptee = new MDGenerator(); /** The name of the message digest algorithm used by the adaptee. */ private String mdName; + private static final Logger logger = + Logger.getLogger(SecureRandom.class.getName()); + + private static final String SECURERANDOM_SOURCE = "securerandom.source"; + private static final String JAVA_SECURITY_EGD = "java.security.egd"; + /** - * Trivial protected constructor. - * + *

Trivial protected constructor.

+ * * @param mdName the canonical name of the underlying hash algorithm. */ protected SecureRandomAdapter(String mdName) @@ -74,23 +97,77 @@ abstract class SecureRandomAdapter super(); this.mdName = mdName; - adaptee.init(Collections.singletonMap(MDGenerator.MD_NAME, mdName)); + adaptee.init (Collections.singletonMap (MDGenerator.MD_NAME, mdName)); } - public byte[] engineGenerateSeed(int numBytes) + public static final byte[] getSeed(int numBytes) { - if (numBytes < 1) - return new byte[0]; + URL sourceUrl = null; + String urlStr = null; + + byte[] buffer = new byte[numBytes]; - byte[] result = new byte[numBytes]; - this.engineNextBytes(result); - return result; + GetSecurityPropertyAction action = + new GetSecurityPropertyAction(SECURERANDOM_SOURCE); + try + { + urlStr = (String) AccessController.doPrivileged(action); + if (urlStr != null) + sourceUrl = new URL(urlStr); + } + catch (MalformedURLException ignored) + { + logger.log(Level.WARNING, + SECURERANDOM_SOURCE + " property is malformed: {0}", + urlStr); + } + + if (sourceUrl == null) + { + try + { + urlStr = SystemProperties.getProperty(JAVA_SECURITY_EGD); + if (urlStr != null) + sourceUrl = new URL(urlStr); + } + catch (MalformedURLException mue) + { + logger.log(Level.WARNING, + JAVA_SECURITY_EGD + " property is malformed: {0}", + urlStr); + } + } + + if (sourceUrl != null) + { + try + { + InputStream in = sourceUrl.openStream(); + in.read(buffer); + return buffer; + } + catch (IOException ioe) + { + logger.log(Level.FINE, "error reading random bytes", ioe); + } + } + + // If we get here, we did not get any seed from a property URL. + VMSecureRandom.generateSeed(buffer, 0, buffer.length); + return buffer; + } + + public byte[] engineGenerateSeed(int numBytes) + { + return getSeed(numBytes); } public void engineNextBytes(byte[] bytes) { - if (! adaptee.isInitialised()) - this.engineSetSeed(new byte[0]); + if (!isSeeded) + { + engineSetSeed(engineGenerateSeed(32)); + } try { adaptee.nextBytes(bytes, 0, bytes.length); @@ -102,6 +179,7 @@ abstract class SecureRandomAdapter public void engineSetSeed(byte[] seed) { - adaptee.addRandomBytes(seed); + adaptee.addRandomBytes (seed); + isSeeded = true; } } diff --git a/gnu/javax/crypto/jce/prng/ARCFourRandomSpi.java b/gnu/javax/crypto/jce/prng/ARCFourRandomSpi.java index 652793b04..1129d5dfb 100644 --- a/gnu/javax/crypto/jce/prng/ARCFourRandomSpi.java +++ b/gnu/javax/crypto/jce/prng/ARCFourRandomSpi.java @@ -39,12 +39,17 @@ exception statement from your version. */ package gnu.javax.crypto.jce.prng; import gnu.java.security.Registry; -import gnu.javax.crypto.prng.ARCFour; + +import gnu.java.security.jce.prng.SecureRandomAdapter; + import gnu.java.security.prng.IRandom; import gnu.java.security.prng.LimitReachedException; + +import gnu.javax.crypto.prng.ARCFour; import gnu.javax.crypto.prng.PRNGFactory; import java.security.SecureRandomSpi; + import java.util.HashMap; /** @@ -71,17 +76,13 @@ public class ARCFourRandomSpi public byte[] engineGenerateSeed(int numBytes) { - if (numBytes < 1) - return new byte[0]; - byte[] result = new byte[numBytes]; - this.engineNextBytes(result); - return result; + return SecureRandomAdapter.getSeed(numBytes); } public void engineNextBytes(byte[] bytes) { if (virgin) - this.engineSetSeed(new byte[0]); + this.engineSetSeed(engineGenerateSeed(32)); try { adaptee.nextBytes(bytes, 0, bytes.length); diff --git a/gnu/javax/crypto/jce/prng/CSPRNGSpi.java b/gnu/javax/crypto/jce/prng/CSPRNGSpi.java index 6ded636aa..96d66f052 100644 --- a/gnu/javax/crypto/jce/prng/CSPRNGSpi.java +++ b/gnu/javax/crypto/jce/prng/CSPRNGSpi.java @@ -40,6 +40,7 @@ package gnu.javax.crypto.jce.prng; import gnu.java.security.prng.IRandom; import gnu.java.security.prng.LimitReachedException; +import gnu.java.security.jce.prng.SecureRandomAdapter; import gnu.javax.crypto.prng.CSPRNG; import java.net.MalformedURLException; @@ -53,6 +54,7 @@ public class CSPRNGSpi extends SecureRandomSpi { private final IRandom adaptee; + private boolean virgin = true; public CSPRNGSpi() throws ClassNotFoundException, MalformedURLException, NumberFormatException @@ -62,21 +64,19 @@ public class CSPRNGSpi adaptee = CSPRNG.getSystemInstance(); } - protected byte[] engineGenerateSeed(final int count) + protected byte[] engineGenerateSeed(final int numBytes) { - if (count < 0) - throw new IllegalArgumentException("count must be nonnegative"); - byte[] buf = new byte[count]; - if (count == 0) - return buf; - engineNextBytes(buf); - return buf; + return SecureRandomAdapter.getSeed(numBytes); } protected void engineNextBytes(final byte[] buffer) { if (buffer == null) throw new NullPointerException(); + if (virgin) + { + engineSetSeed(engineGenerateSeed(32)); + } try { adaptee.nextBytes(buffer, 0, buffer.length); @@ -92,5 +92,6 @@ public class CSPRNGSpi if (seed == null) throw new NullPointerException(); adaptee.addRandomBytes(seed, 0, seed.length); + virgin = false; } } diff --git a/gnu/javax/crypto/jce/prng/FortunaImpl.java b/gnu/javax/crypto/jce/prng/FortunaImpl.java index 8e3782ef0..add5b9ee0 100644 --- a/gnu/javax/crypto/jce/prng/FortunaImpl.java +++ b/gnu/javax/crypto/jce/prng/FortunaImpl.java @@ -39,6 +39,9 @@ exception statement from your version. */ package gnu.javax.crypto.jce.prng; import gnu.java.security.prng.LimitReachedException; + +import gnu.java.security.jce.prng.SecureRandomAdapter; + import gnu.javax.crypto.prng.Fortuna; import java.security.SecureRandomSpi; @@ -47,19 +50,27 @@ import java.util.Collections; public final class FortunaImpl extends SecureRandomSpi { + private boolean virgin = true; private final Fortuna adaptee; public FortunaImpl() { adaptee = new Fortuna(); - adaptee.init(Collections.singletonMap(Fortuna.SEED, new byte[0])); } protected void engineSetSeed(byte[] seed) { synchronized (adaptee) { - adaptee.addRandomBytes(seed); + if (virgin) + { + adaptee.init (Collections.singletonMap (Fortuna.SEED, seed)); + virgin = false; + } + else + { + adaptee.addRandomBytes (seed); + } } } @@ -67,6 +78,10 @@ public final class FortunaImpl { synchronized (adaptee) { + if (virgin) + { + this.engineSetSeed(engineGenerateSeed(32)); + } try { adaptee.nextBytes(buffer); @@ -80,8 +95,6 @@ public final class FortunaImpl protected byte[] engineGenerateSeed(int numbytes) { - byte[] seed = new byte[numbytes]; - engineNextBytes(seed); - return seed; + return SecureRandomAdapter.getSeed(numBytes); } } diff --git a/gnu/javax/crypto/jce/prng/ICMRandomSpi.java b/gnu/javax/crypto/jce/prng/ICMRandomSpi.java index 9855f95bd..a02fd147e 100644 --- a/gnu/javax/crypto/jce/prng/ICMRandomSpi.java +++ b/gnu/javax/crypto/jce/prng/ICMRandomSpi.java @@ -40,6 +40,7 @@ package gnu.javax.crypto.jce.prng; import gnu.java.security.Configuration; import gnu.java.security.Registry; +import gnu.java.security.jce.prng.SecureRandomAdapter; import gnu.java.security.prng.LimitReachedException; import gnu.javax.crypto.cipher.IBlockCipher; import gnu.javax.crypto.prng.ICMGenerator; @@ -107,19 +108,7 @@ public class ICMRandomSpi public byte[] engineGenerateSeed(int numBytes) { - if (Configuration.DEBUG) - log.entering(this.getClass().getName(), "engineGenerateSeed"); - if (numBytes < 1) - { - if (Configuration.DEBUG) - log.exiting(this.getClass().getName(), "engineGenerateSeed"); - return new byte[0]; - } - byte[] result = new byte[numBytes]; - this.engineNextBytes(result); - if (Configuration.DEBUG) - log.exiting(this.getClass().getName(), "engineGenerateSeed"); - return result; + return SecureRandomAdapter.getSeed(numBytes); } public void engineNextBytes(byte[] bytes) @@ -127,7 +116,7 @@ public class ICMRandomSpi if (Configuration.DEBUG) log.entering(this.getClass().getName(), "engineNextBytes"); if (! adaptee.isInitialised()) - this.engineSetSeed(new byte[0]); + this.engineSetSeed(engineGenerateSeed(32)); while (true) { try @@ -207,8 +196,8 @@ public class ICMRandomSpi System.arraycopy(material, 16, offset, 0, 16); attributes.put(ICMGenerator.OFFSET, offset); // specify the index - byte[] index = new byte[8]; - System.arraycopy(material, 32, index, 0, 8); + byte[] index = new byte[4]; + System.arraycopy(material, 32, index, 0, 4); attributes.put(ICMGenerator.SEGMENT_INDEX, new BigInteger(1, index)); adaptee.init(attributes); if (Configuration.DEBUG) diff --git a/gnu/javax/crypto/jce/prng/UMacRandomSpi.java b/gnu/javax/crypto/jce/prng/UMacRandomSpi.java index f6949dd8d..2faebe8eb 100644 --- a/gnu/javax/crypto/jce/prng/UMacRandomSpi.java +++ b/gnu/javax/crypto/jce/prng/UMacRandomSpi.java @@ -41,6 +41,7 @@ package gnu.javax.crypto.jce.prng; import gnu.java.security.Configuration; import gnu.java.security.Registry; import gnu.java.security.prng.LimitReachedException; +import gnu.java.security.jce.prng.SecureRandomAdapter; import gnu.javax.crypto.cipher.IBlockCipher; import gnu.javax.crypto.prng.UMacGenerator; @@ -57,6 +58,7 @@ public class UMacRandomSpi extends SecureRandomSpi { private static final Logger log = Logger.getLogger(UMacRandomSpi.class.getName()); + /** Class-wide prng to generate random material for the underlying prng. */ private static final UMacGenerator prng; // blank final static @@ -88,17 +90,13 @@ public class UMacRandomSpi public byte[] engineGenerateSeed(int numBytes) { - if (numBytes < 1) - return new byte[0]; - byte[] result = new byte[numBytes]; - this.engineNextBytes(result); - return result; + return SecureRandomAdapter.getSeed(numBytes); } public void engineNextBytes(byte[] bytes) { if (! adaptee.isInitialised()) - this.engineSetSeed(new byte[0]); + engineSetSeed(engineGenerateSeed(32)); while (true) { try diff --git a/gnu/javax/crypto/prng/ICMGenerator.java b/gnu/javax/crypto/prng/ICMGenerator.java index 5b0bd4f8b..d8205cfb4 100644 --- a/gnu/javax/crypto/prng/ICMGenerator.java +++ b/gnu/javax/crypto/prng/ICMGenerator.java @@ -263,6 +263,15 @@ public class ICMGenerator // C[0] = (s * (256^BLOCK_INDEX_LENGTH) + r) modulo (256^BLOCK_LENGTH) C0 = segmentNdx.multiply(TWO_FIFTY_SIX.pow(blockNdxLength)) .add(r).modPow(BigInteger.ONE, counterRange); + try + { + fillBlock(); + } + catch (LimitReachedException impossible) + { + throw (InternalError) + new InternalError().initCause(impossible); + } } public void fillBlock() throws LimitReachedException -- cgit v1.2.1