diff options
author | Casey Marshall <csm@gnu.org> | 2006-04-14 18:33:42 +0000 |
---|---|---|
committer | Casey Marshall <csm@gnu.org> | 2006-04-14 18:33:42 +0000 |
commit | 5d9e591b317b07c4e05ea062a7dfc7c79f64e9ea (patch) | |
tree | 2dcea6fe9ecb3c27c0db363fa880452192e4e0b6 | |
parent | 4484590e69caf8a33d097cb68d0d0875156f3c0a (diff) | |
download | classpath-5d9e591b317b07c4e05ea062a7dfc7c79f64e9ea.tar.gz |
2006-04-14 Casey Marshall <csm@gnu.org>
Fixes PR classpath/24642
* NEWS: add note about SecureRandom changes, and addition of
VMSecureRandom.
* java/security/SecureRandom.java (isSeeded): new field.
(setSeed, setSeed): set `isSeeded' to `true.'
(nextBytes): seed this instance if `isSeeded' is false.
(getSeed): call `generateSeed.'
(SECURERANDOM_SOURCE, JAVA_SECURITY_EGD, logger): new constants.
(generateSeed, generateSeed): new methods.
* vm/reference/java/security/VMSecureRandom.java: new file.
-rw-r--r-- | ChangeLog | 13 | ||||
-rw-r--r-- | NEWS | 6 | ||||
-rw-r--r-- | java/security/SecureRandom.java | 78 | ||||
-rw-r--r-- | vm/reference/java/security/VMSecureRandom.java | 134 |
4 files changed, 228 insertions, 3 deletions
@@ -1,3 +1,16 @@ +2006-04-14 Casey Marshall <csm@gnu.org> + + Fixes PR classpath/24642 + * NEWS: add note about SecureRandom changes, and addition of + VMSecureRandom. + * java/security/SecureRandom.java (isSeeded): new field. + (setSeed, setSeed): set `isSeeded' to `true.' + (nextBytes): seed this instance if `isSeeded' is false. + (getSeed): call `generateSeed.' + (SECURERANDOM_SOURCE, JAVA_SECURITY_EGD, logger): new constants. + (generateSeed, generateSeed): new methods. + * vm/reference/java/security/VMSecureRandom.java: new file. + 2006-04-14 Robert Schuster <robertschuster@fsfe.org> * javax/swing/text/FieldView.java: @@ -18,6 +18,9 @@ New in release 0.91 (UNRELEASED) text components with the middle mouse button. Support cursor changes on various components when resizing. * Updated locale data information to CLDR 1.3. +* Various bugs in Classpath's SecureRandom implementations have been + fixed; that class now respects the "securerandom.source" security + property and the "java.security.egd" system property. Runtime interface changes: @@ -31,6 +34,9 @@ Runtime interface changes: this method. * The reference implementation of VMThread has been updated to handle the new Thread.UncaughtExceptionHandler support. +* A new class, java.security.VMSecureRandom, is now available that is + used to generate random numbers for seeding cryptographically-secure + pseudo-random number generators. New in release 0.90 (March 6, 2006) diff --git a/java/security/SecureRandom.java b/java/security/SecureRandom.java index 5ac9a4a8c..d403d4964 100644 --- a/java/security/SecureRandom.java +++ b/java/security/SecureRandom.java @@ -38,11 +38,19 @@ exception statement from your version. */ package java.security; +import gnu.classpath.SystemProperties; import gnu.java.security.Engine; +import gnu.java.security.action.GetSecurityPropertyAction; import gnu.java.security.jce.prng.Sha160RandomSpi; +import java.io.IOException; +import java.io.InputStream; +import java.net.MalformedURLException; +import java.net.URL; import java.util.Enumeration; import java.util.Random; +import java.util.logging.Level; +import java.util.logging.Logger; /** * An interface to a cryptographically secure pseudo-random number @@ -74,6 +82,8 @@ public class SecureRandom extends Random byte[] state = null; private String algorithm; + private boolean isSeeded = false; + // Constructors. // ------------------------------------------------------------------------ @@ -303,6 +313,7 @@ public class SecureRandom extends Random public void setSeed(byte[] seed) { secureRandomSpi.engineSetSeed(seed); + isSeeded = true; } /** @@ -330,6 +341,7 @@ public class SecureRandom extends Random (byte) (0xff & seed) }; secureRandomSpi.engineSetSeed(tmp); + isSeeded = true; } } @@ -341,6 +353,8 @@ public class SecureRandom extends Random */ public void nextBytes(byte[] bytes) { + if (!isSeeded) + setSeed(getSeed(32)); randomBytesUsed += bytes.length; counter++; secureRandomSpi.engineNextBytes(bytes); @@ -386,10 +400,8 @@ public class SecureRandom extends Random public static byte[] getSeed(int numBytes) { byte[] tmp = new byte[numBytes]; - - new Random().nextBytes(tmp); + generateSeed(tmp); return tmp; - //return secureRandomSpi.engineGenerateSeed( numBytes ); } /** @@ -404,4 +416,64 @@ public class SecureRandom extends Random return secureRandomSpi.engineGenerateSeed(numBytes); } + // Seed methods. + + private static final String SECURERANDOM_SOURCE = "securerandom.source"; + private static final String JAVA_SECURITY_EGD = "java.security.egd"; + private static final Logger logger = Logger.getLogger(SecureRandom.class.getName()); + + private static int generateSeed(byte[] buffer) + { + return generateSeed(buffer, 0, buffer.length); + } + + private static int generateSeed(byte[] buffer, int offset, int length) + { + URL sourceUrl = null; + String urlStr = null; + + 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(); + return in.read(buffer, offset, length); + } + 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. + return VMSecureRandom.generateSeed(buffer, offset, length); + } } diff --git a/vm/reference/java/security/VMSecureRandom.java b/vm/reference/java/security/VMSecureRandom.java new file mode 100644 index 000000000..dc67d8719 --- /dev/null +++ b/vm/reference/java/security/VMSecureRandom.java @@ -0,0 +1,134 @@ +/* VMSecureRandom.java -- random seed generator. + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.security; + +import gnu.classpath.SystemProperties; +import gnu.java.security.action.GetSecurityPropertyAction; + +import java.net.URL; + +/** + * VM-specific methods for generating real (or almost real) random + * seeds. VM implementors should write a version of this class that + * reads random bytes from some system source. + * + * <p>The default implementation of this class runs eight threads that + * increment counters in a tight loop, and XORs each counter to + * produce one byte of seed data. This is not very efficient, and is + * not guaranteed to be random (the thread scheduler is probably + * deterministic, after all). If possible, VM implementors should + * reimplement this class so it obtains a random seed from a system + * facility, such as a system entropy gathering device or hardware + * random number generator. + */ +final class VMSecureRandom +{ + + /** + * Generate a random seed. Implementations are free to generate + * fewer random bytes than are requested, and leave the remaining + * bytes of the destination buffer as zeros. Implementations SHOULD, + * however, make a best-effort attempt to satisfy the request. + * + * @param buffer The destination buffer. + * @param offset The offset in the buffer to start putting bytes. + * @param length The number of random bytes to generate. + */ + static int generateSeed(byte[] buffer, int offset, int length) + { + if (length < 0) + throw new IllegalArgumentException("length must be nonnegative"); + if (offset < 0 || offset + length > buffer.length) + throw new IndexOutOfBoundsException(); + + Spinner[] spinners = new Spinner[8]; + int n = 0x1; + for (int i = 0; i < spinners.length; i++) + { + spinners[i] = new Spinner((byte) n); + Thread t = new Thread(spinners[i]); + t.start(); + n <<= 1; + } + + // Wait until at least one spinner has started. + while (!(spinners[0].running || spinners[1].running || spinners[2].running + || spinners[3].running || spinners[4].running || spinners[5].running + || spinners[6].running || spinners[7].running)) + { + Thread.yield(); + } + + for (int i = offset; i < length; i++) + { + buffer[i] = (byte) (spinners[0].value ^ spinners[1].value ^ spinners[2].value + ^ spinners[3].value ^ spinners[4].value ^ spinners[5].value + ^ spinners[6].value ^ spinners[7].value); + Thread.yield(); + } + + for (int i = 0; i < spinners.length; i++) + spinners[i].stop(); + + return length; + } + + static class Spinner implements Runnable + { + volatile byte value; + volatile boolean running; + + Spinner(final byte initial) + { + value = initial; + } + + public void run() + { + running = true; + while (running) + value++; + } + + private void stop() + { + running = false; + } + } +}
\ No newline at end of file |