--- old/src/java.base/share/classes/com/sun/crypto/provider/HmacCore.java 2016-04-01 19:17:45.000000000 +0800
+++ new/src/java.base/share/classes/com/sun/crypto/provider/HmacCore.java 2016-04-01 19:17:45.000000000 +0800
@@ -262,4 +262,14 @@
super("SHA-512", 128);
}
}
+ public static final class HmacSHA512_224 extends HmacCore {
+ public HmacSHA512_224() throws NoSuchAlgorithmException {
+ super("SHA-512/224", 128);
+ }
+ }
+ public static final class HmacSHA512_256 extends HmacCore {
+ public HmacSHA512_256() throws NoSuchAlgorithmException {
+ super("SHA-512/256", 128);
+ }
+ }
}
--- old/src/java.base/share/classes/com/sun/crypto/provider/SunJCE.java 2016-04-01 19:17:46.000000000 +0800
+++ new/src/java.base/share/classes/com/sun/crypto/provider/SunJCE.java 2016-04-01 19:17:46.000000000 +0800
@@ -704,6 +704,12 @@
put("Alg.Alias.Mac.OID.1.2.840.113549.2.11", "HmacSHA512");
put("Alg.Alias.Mac.1.2.840.113549.2.11", "HmacSHA512");
+ // TODO: aliases with OIDs
+ put("Mac.HmacSHA512/224",
+ "com.sun.crypto.provider.HmacCore$HmacSHA512_224");
+ put("Mac.HmacSHA512/256",
+ "com.sun.crypto.provider.HmacCore$HmacSHA512_256");
+
put("Mac.HmacPBESHA1",
"com.sun.crypto.provider.HmacPKCS12PBESHA1");
--- old/src/java.base/share/classes/java/security/Provider.java 2016-04-01 19:17:47.000000000 +0800
+++ new/src/java.base/share/classes/java/security/Provider.java 2016-04-01 19:17:47.000000000 +0800
@@ -142,8 +142,23 @@
Constructor<?> con = clazz.getConstructor();
return con.newInstance();
} else {
- Constructor<?> con = clazz.getConstructor(ctrParamClz);
- return con.newInstance(ctorParamObj);
+ // Looking for the constructor with a params first and fallback
+ // to one without if not found. This is to support the enhanced
+ // SecureRandom. Before jdk9, there was no params support
+ // (only getInstance(alg)) and an impl only had the no-params
+ // constructor. Since jdk9, there is getInstance(alg,params)
+ // and an impl can contain a Impl(params) constructor.
+ try {
+ Constructor<?> con = clazz.getConstructor(ctrParamClz);
+ return con.newInstance(ctorParamObj);
+ } catch (NoSuchMethodException nsme) {
+ if (ctorParamObj == null) {
+ Constructor<?> con = clazz.getConstructor();
+ return con.newInstance();
+ } else {
+ throw new IllegalArgumentException(nsme);
+ }
+ }
}
}
@@ -1384,7 +1399,8 @@
addEngine("KeyPairGenerator", false, null);
addEngine("KeyStore", false, null);
addEngine("MessageDigest", false, null);
- addEngine("SecureRandom", false, null);
+ addEngine("SecureRandom", false,
+ "java.security.SecureRandomInstantiateParameters");
addEngine("Signature", true, null);
addEngine("CertificateFactory", false, null);
addEngine("CertPathBuilder", false, null);
@@ -1678,6 +1694,7 @@
}
}
}
+ // constructorParameter can be null if not provided
return newInstanceUtil(getImplClass(), ctrParamClz, constructorParameter);
} catch (NoSuchAlgorithmException e) {
throw e;
--- old/src/java.base/share/classes/java/security/SecureRandom.java 2016-04-01 19:17:48.000000000 +0800
+++ new/src/java.base/share/classes/java/security/SecureRandom.java 2016-04-01 19:17:48.000000000 +0800
@@ -44,46 +44,82 @@
* <a href="http://csrc.nist.gov/publications/fips/fips140-2/fips1402.pdf">
* <i>FIPS 140-2, Security Requirements for Cryptographic Modules</i></a>,
* section 4.9.1.
- * Additionally, SecureRandom must produce non-deterministic output.
- * Therefore any seed material passed to a SecureRandom object must be
- * unpredictable, and all SecureRandom output sequences must be
+ * Additionally, {@code SecureRandom} must produce non-deterministic output.
+ * Therefore any seed material passed to a {@code SecureRandom} object must be
+ * unpredictable, and all {@code SecureRandom} output sequences must be
* cryptographically strong, as described in
* <a href="http://tools.ietf.org/html/rfc4086">
* <i>RFC 4086: Randomness Requirements for Security</i></a>.
*
- * <p>A caller obtains a SecureRandom instance via the
- * no-argument constructor or one of the {@code getInstance} methods:
- *
- * <pre>
- * SecureRandom random = new SecureRandom();
- * </pre>
- *
- * <p> Many SecureRandom implementations are in the form of a pseudo-random
- * number generator (PRNG), which means they use a deterministic algorithm
- * to produce a pseudo-random sequence from a true random seed.
+ * <p> Many {@code SecureRandom} implementations are in the form of a pseudo-random
+ * number generator (PRNG, also known as deterministic random bits generator
+ * or DRBG), which means they use a deterministic algorithm
+ * to produce a pseudo-random sequence from a random seed.
* Other implementations may produce true random numbers,
* and yet others may use a combination of both techniques.
*
- * <p> Typical callers of SecureRandom invoke the following methods
+ * <p>A caller obtains a {@code SecureRandom} instance via the
+ * no-argument constructor or one of the {@code getInstance} methods.
+ * For example:
+ *
+ * <blockquote><pre>
+ * SecureRandom r1 = new SecureRandom();
+ * SecureRandom r2 = SecureRandom.getInstance("NativePRNG");
+ * SecureRandom r3 = SecureRandom("DRBG",
+ * DrbgParameters.Instantiate(128, RESEED_ONLY, null));
+ * </pre></blockquote>
+ *
+ * <p> The third statement above returns a {@code SecureRandom} object of the
+ * specific algorithm supporting the specific instantiate parameters.
+ * The effective instantiate parameters used in the instantiation must match
+ * this minimum request but is not necessarily the same. For example,
+ * even if the request does not require a certain feature, the actual
+ * instantiation can provide the feature. An implementation may lazily
+ * instantiate a {@code SecureRandom} until it's actually used, but the effective
+ * instantiate parameters must be determined at the beginning and returned by
+ * {@link #getParameters()} unchanged.
+ *
+ * <p> Typical callers of {@code SecureRandom} invoke the following methods
* to retrieve random bytes:
*
- * <pre>
- * SecureRandom random = new SecureRandom();
- * byte[] bytes = new byte[20];
- * random.nextBytes(bytes);
- * </pre>
+ * <blockquote><pre>
+ * SecureRandom random = new SecureRandom();
+ * byte[] bytes = new byte[20];
+ * random.nextBytes(bytes);
+ * </pre></blockquote>
*
- * <p> Callers may also invoke the {@code generateSeed} method
+ * <p> Callers may also invoke the {@link #generateSeed} method
* to generate a given number of seed bytes (to seed other random number
* generators, for example):
- * <pre>
- * byte[] seed = random.generateSeed(20);
- * </pre>
- *
- * Note: Depending on the implementation, the {@code generateSeed} and
- * {@code nextBytes} methods may block as entropy is being gathered,
- * for example, if they need to read from /dev/random on various Unix-like
- * operating systems.
+ *
+ * <blockquote><pre>
+ * byte[] seed = random.generateSeed(20);
+ * </pre></blockquote>
+ *
+ * <p> A newly created PRNG {@code SecureRandom} object is not seeded (except if
+ * it is created by {@link #SecureRandom(byte[])}). The first call to
+ * {@code nextBytes} will force it to seed itself from an implementation-
+ * specific entropy source. This self-seeding will not occur if {@code setSeed}
+ * was previously called.
+ *
+ * <p> A {@code SecureRandom} can be reseeded at any time by calling the
+ * {@code reseed} or {@code setSeed} method. The {@code reseed} method
+ * reads entropy input from its entropy source to reseed itself.
+ * The {@code setSeed} method requires the caller to provide the seed.
+ *
+ * <p> Please note that {@code reseed} is not always supported.
+ *
+ * <p> Some {@code SecureRandom} implementations may accept a
+ * {@link SecureRandomNextBytesParameters} parameter in its
+ * {@link #nextBytes(byte[], SecureRandomNextBytesParameters)} method and a
+ * {@link SecureRandomReseedParameters} in its
+ * {@link #reseed(SecureRandomReseedParameters)} method to further
+ * control the behavior of the methods.
+ *
+ * <p> Note: Depending on the implementation, the {@code generateSeed},
+ * {@code reseed} and {@code nextBytes} methods may block as entropy is being
+ * gathered, for example, if the entropy source is /dev/random on various
+ * Unix-like operating systems.
*
* @see java.security.SecureRandomSpi
* @see java.util.Random
@@ -132,26 +168,19 @@
*
* <p> This constructor traverses the list of registered security Providers,
* starting with the most preferred Provider.
- * A new SecureRandom object encapsulating the
- * SecureRandomSpi implementation from the first
- * Provider that supports a SecureRandom (RNG) algorithm is returned.
+ * A new {@code SecureRandom} object encapsulating the
+ * {@code SecureRandomSpi} implementation from the first
+ * Provider that supports a {@code SecureRandom} (RNG) algorithm is returned.
* If none of the Providers support a RNG algorithm,
* then an implementation-specific default is returned.
*
* <p> Note that the list of registered providers may be retrieved via
* the {@link Security#getProviders() Security.getProviders()} method.
*
- * <p> See the SecureRandom section in the <a href=
+ * <p> See the {@code SecureRandom} section in the <a href=
* "{@docRoot}/../technotes/guides/security/StandardNames.html#SecureRandom">
* Java Cryptography Architecture Standard Algorithm Name Documentation</a>
* for information about standard RNG algorithm names.
- *
- * <p> The returned SecureRandom object has not been seeded. To seed the
- * returned object, call the {@code setSeed} method.
- * If {@code setSeed} is not called, the first call to
- * {@code nextBytes} will force the SecureRandom object to seed itself.
- * This self-seeding will not occur if {@code setSeed} was
- * previously called.
*/
public SecureRandom() {
/*
@@ -166,20 +195,20 @@
/**
* Constructs a secure random number generator (RNG) implementing the
* default random number algorithm.
- * The SecureRandom instance is seeded with the specified seed bytes.
+ * The {@code SecureRandom} instance is seeded with the specified seed bytes.
*
* <p> This constructor traverses the list of registered security Providers,
* starting with the most preferred Provider.
- * A new SecureRandom object encapsulating the
- * SecureRandomSpi implementation from the first
- * Provider that supports a SecureRandom (RNG) algorithm is returned.
+ * A new {@code SecureRandom} object encapsulating the
+ * {@code SecureRandomSpi} implementation from the first
+ * Provider that supports a {@code SecureRandom} (RNG) algorithm is returned.
* If none of the Providers support a RNG algorithm,
* then an implementation-specific default is returned.
*
* <p> Note that the list of registered providers may be retrieved via
* the {@link Security#getProviders() Security.getProviders()} method.
*
- * <p> See the SecureRandom section in the <a href=
+ * <p> See the {@code SecureRandom} section in the <a href=
* "{@docRoot}/../technotes/guides/security/StandardNames.html#SecureRandom">
* Java Cryptography Architecture Standard Algorithm Name Documentation</a>
* for information about standard RNG algorithm names.
@@ -199,7 +228,7 @@
this.secureRandomSpi = new sun.security.provider.SecureRandom();
this.provider = Providers.getSunProvider();
if (setSeed) {
- this.secureRandomSpi.engineSetSeed(seed);
+ this.setSeed(seed);
}
} else {
try {
@@ -207,7 +236,7 @@
this.secureRandomSpi = random.getSecureRandomSpi();
this.provider = random.getProvider();
if (setSeed) {
- this.secureRandomSpi.engineSetSeed(seed);
+ this.setSeed(seed);
}
} catch (NoSuchAlgorithmException nsae) {
// never happens, because we made sure the algorithm exists
@@ -225,9 +254,9 @@
}
/**
- * Creates a SecureRandom object.
+ * Creates a {@code SecureRandom} object.
*
- * @param secureRandomSpi the SecureRandom implementation.
+ * @param secureRandomSpi the {@code SecureRandom} implementation.
* @param provider the provider.
*/
protected SecureRandom(SecureRandomSpi secureRandomSpi,
@@ -249,25 +278,18 @@
}
/**
- * Returns a SecureRandom object that implements the specified
+ * Returns a {@code SecureRandom} object that implements the specified
* Random Number Generator (RNG) algorithm.
*
* <p> This method traverses the list of registered security Providers,
* starting with the most preferred Provider.
- * A new SecureRandom object encapsulating the
- * SecureRandomSpi implementation from the first
+ * A new {@code SecureRandom} object encapsulating the
+ * {@code SecureRandomSpi} implementation from the first
* Provider that supports the specified algorithm is returned.
*
* <p> Note that the list of registered providers may be retrieved via
* the {@link Security#getProviders() Security.getProviders()} method.
*
- * <p> The returned SecureRandom object has not been seeded. To seed the
- * returned object, call the {@code setSeed} method.
- * If {@code setSeed} is not called, the first call to
- * {@code nextBytes} will force the SecureRandom object to seed itself.
- * This self-seeding will not occur if {@code setSeed} was
- * previously called.
- *
* @implNote
* The JDK Reference Implementation additionally uses the
* {@code jdk.security.provider.preferred} property to determine
@@ -276,15 +298,15 @@
* {@link Security#getProviders() Security.getProviders()}.
*
* @param algorithm the name of the RNG algorithm.
- * See the SecureRandom section in the <a href=
+ * See the {@code SecureRandom} section in the <a href=
* "{@docRoot}/../technotes/guides/security/StandardNames.html#SecureRandom">
* Java Cryptography Architecture Standard Algorithm Name Documentation</a>
* for information about standard RNG algorithm names.
*
- * @return the new SecureRandom object.
+ * @return the new {@code SecureRandom} object.
*
* @exception NoSuchAlgorithmException if no Provider supports a
- * SecureRandomSpi implementation for the
+ * {@code SecureRandomSpi} implementation for the
* specified algorithm.
*
* @see Provider
@@ -294,49 +316,42 @@
public static SecureRandom getInstance(String algorithm)
throws NoSuchAlgorithmException {
Instance instance = GetInstance.getInstance("SecureRandom",
- SecureRandomSpi.class, algorithm);
+ SecureRandomSpi.class, algorithm);
return new SecureRandom((SecureRandomSpi)instance.impl,
- instance.provider, algorithm);
+ instance.provider, algorithm);
}
/**
- * Returns a SecureRandom object that implements the specified
+ * Returns a {@code SecureRandom} object that implements the specified
* Random Number Generator (RNG) algorithm.
*
- * <p> A new SecureRandom object encapsulating the
- * SecureRandomSpi implementation from the specified provider
+ * <p> A new {@code SecureRandom} object encapsulating the
+ * {@code SecureRandomSpi} implementation from the specified provider
* is returned. The specified provider must be registered
* in the security provider list.
*
* <p> Note that the list of registered providers may be retrieved via
* the {@link Security#getProviders() Security.getProviders()} method.
*
- * <p> The returned SecureRandom object has not been seeded. To seed the
- * returned object, call the {@code setSeed} method.
- * If {@code setSeed} is not called, the first call to
- * {@code nextBytes} will force the SecureRandom object to seed itself.
- * This self-seeding will not occur if {@code setSeed} was
- * previously called.
- *
* @param algorithm the name of the RNG algorithm.
- * See the SecureRandom section in the <a href=
+ * See the {@code SecureRandom} section in the <a href=
* "{@docRoot}/../technotes/guides/security/StandardNames.html#SecureRandom">
* Java Cryptography Architecture Standard Algorithm Name Documentation</a>
* for information about standard RNG algorithm names.
*
* @param provider the name of the provider.
*
- * @return the new SecureRandom object.
+ * @return the new {@code SecureRandom} object.
*
- * @exception NoSuchAlgorithmException if a SecureRandomSpi
- * implementation for the specified algorithm is not
- * available from the specified provider.
+ * @throws NoSuchAlgorithmException if a {@code SecureRandomSpi}
+ * implementation for the specified algorithm is not
+ * available from the specified provider.
*
- * @exception NoSuchProviderException if the specified provider is not
- * registered in the security provider list.
+ * @throws NoSuchProviderException if the specified provider is not
+ * registered in the security provider list.
*
- * @exception IllegalArgumentException if the provider name is null
- * or empty.
+ * @throws IllegalArgumentException if the provider name is null
+ * or empty.
*
* @see Provider
*
@@ -351,36 +366,29 @@
}
/**
- * Returns a SecureRandom object that implements the specified
+ * Returns a {@code SecureRandom} object that implements the specified
* Random Number Generator (RNG) algorithm.
*
- * <p> A new SecureRandom object encapsulating the
- * SecureRandomSpi implementation from the specified Provider
- * object is returned. Note that the specified Provider object
+ * <p> A new {@code SecureRandom} object encapsulating the
+ * {@code SecureRandomSpi} implementation from the specified {@code Provider}
+ * object is returned. Note that the specified {@code Provider} object
* does not have to be registered in the provider list.
*
- * <p> The returned SecureRandom object has not been seeded. To seed the
- * returned object, call the {@code setSeed} method.
- * If {@code setSeed} is not called, the first call to
- * {@code nextBytes} will force the SecureRandom object to seed itself.
- * This self-seeding will not occur if {@code setSeed} was
- * previously called.
- *
* @param algorithm the name of the RNG algorithm.
- * See the SecureRandom section in the <a href=
+ * See the {@code SecureRandom} section in the <a href=
* "{@docRoot}/../technotes/guides/security/StandardNames.html#SecureRandom">
* Java Cryptography Architecture Standard Algorithm Name Documentation</a>
* for information about standard RNG algorithm names.
*
* @param provider the provider.
*
- * @return the new SecureRandom object.
+ * @return the new {@code SecureRandom} object.
*
- * @exception NoSuchAlgorithmException if a SecureRandomSpi
- * implementation for the specified algorithm is not available
- * from the specified Provider object.
+ * @throws NoSuchAlgorithmException if a {@code SecureRandomSpi}
+ * implementation for the specified algorithm is not available
+ * from the specified {@code Provider} object.
*
- * @exception IllegalArgumentException if the specified provider is null.
+ * @throws IllegalArgumentException if the specified provider is null.
*
* @see Provider
*
@@ -395,23 +403,177 @@
}
/**
- * Returns the SecureRandomSpi of this SecureRandom object.
+ * Returns a {@code SecureRandom} object that implements the specified Random
+ * Number Generator (RNG) algorithm and supports the specified
+ * {@code SecureRandomInstantiateParameters} request.
+ *
+ * <p> This method traverses the list of registered security Providers,
+ * starting with the most preferred Provider.
+ * A new {@code SecureRandom} object encapsulating the
+ * {@code SecureRandomSpi} implementation from the first
+ * Provider that supports the specified algorithm and the specified
+ * {@code SecureRandomInstantiateParameters} is returned.
+ *
+ * <p> Note that the list of registered providers may be retrieved via
+ * the {@link Security#getProviders() Security.getProviders()} method.
+ *
+ * @implNote
+ * The JDK Reference Implementation additionally uses the
+ * {@code jdk.security.provider.preferred} property to determine
+ * the preferred provider order for the specified algorithm. This
+ * may be different than the order of providers returned by
+ * {@link Security#getProviders() Security.getProviders()}.
+ *
+ * @param algorithm the name of the RNG algorithm.
+ * See the {@code SecureRandom} section in the <a href=
+ * "{@docRoot}/../technotes/guides/security/StandardNames.html#SecureRandom">
+ * Java Cryptography Architecture Standard Algorithm Name Documentation</a>
+ * for information about standard RNG algorithm names.
+ *
+ * @param params the {@code SecureRandomInstantiateParameters}
+ * the newly created {@code SecureRandom} object must support.
+ *
+ * @return the new {@code SecureRandom} object.
+ *
+ * @throws NoSuchAlgorithmException if no Provider supports a
+ * {@code SecureRandomSpi} implementation for the specified algorithm
+ * and parameters.
+ *
+ * @throws IllegalArgumentException if the specified params is null.
+ *
+ * @see Provider
+ *
+ * @since 9
+ */
+ public static SecureRandom getInstance(
+ String algorithm, SecureRandomInstantiateParameters params)
+ throws NoSuchAlgorithmException {
+ if (params == null) {
+ throw new IllegalArgumentException("params cannot be null");
+ }
+ Instance instance = GetInstance.getInstance("SecureRandom",
+ SecureRandomSpi.class, algorithm, params);
+ SecureRandomSpi spi = (SecureRandomSpi) instance.impl;
+ SecureRandom r = new SecureRandom(spi, instance.provider, algorithm);
+ return r;
+ }
+
+ /**
+ * Returns a {@code SecureRandom} object that implements the specified Random
+ * Number Generator (RNG) algorithm and supports the specified
+ * {@code SecureRandomInstantiateParameters} request.
+ *
+ * <p> A new {@code SecureRandom} object encapsulating the
+ * {@code SecureRandomSpi} implementation from the specified provider
+ * is returned. The specified provider must be registered
+ * in the security provider list.
+ *
+ * <p> Note that the list of registered providers may be retrieved via
+ * the {@link Security#getProviders() Security.getProviders()} method.
+ *
+ * @param algorithm the name of the RNG algorithm.
+ * See the {@code SecureRandom} section in the <a href=
+ * "{@docRoot}/../technotes/guides/security/StandardNames.html#SecureRandom">
+ * Java Cryptography Architecture Standard Algorithm Name Documentation</a>
+ * for information about standard RNG algorithm names.
+ *
+ * @param params the {@code SecureRandomInstantiateParameters}
+ * the newly created {@code SecureRandom} object must support.
+ *
+ * @param provider the name of the provider.
+ *
+ * @return the new {@code SecureRandom} object.
+ *
+ * @throws NoSuchAlgorithmException if the specified provider does not
+ * support a {@code SecureRandomSpi} implementation for the specified
+ * algorithm and parameters.
+ *
+ * @throws NoSuchProviderException if the specified provider is not
+ * registered in the security provider list.
+ *
+ * @throws IllegalArgumentException if the provider name is null
+ * or empty, or params is null.
+ *
+ * @see Provider
+ *
+ * @since 9
+ */
+ public static SecureRandom getInstance(String algorithm,
+ SecureRandomInstantiateParameters params, String provider)
+ throws NoSuchAlgorithmException, NoSuchProviderException {
+ if (params == null) {
+ throw new IllegalArgumentException("params cannot be null");
+ }
+ Instance instance = GetInstance.getInstance("SecureRandom",
+ SecureRandomSpi.class, algorithm, params, provider);
+ SecureRandomSpi spi = (SecureRandomSpi)instance.impl;
+ return new SecureRandom(spi, instance.provider, algorithm);
+ }
+
+ /**
+ * Returns a {@code SecureRandom} object that implements the specified Random
+ * Number Generator (RNG) algorithm and supports the specified
+ * {@code SecureRandomInstantiateParameters} request.
+ *
+ * <p> A new {@code SecureRandom} object encapsulating the
+ * {@code SecureRandomSpi} implementation from the specified {@code Provider}
+ * object is returned. Note that the specified {@code Provider} object
+ * does not have to be registered in the provider list.
+ *
+ * @param algorithm the name of the RNG algorithm.
+ * See the {@code SecureRandom} section in the <a href=
+ * "{@docRoot}/../technotes/guides/security/StandardNames.html#SecureRandom">
+ * Java Cryptography Architecture Standard Algorithm Name Documentation</a>
+ * for information about standard RNG algorithm names.
+ *
+ * @param params the {@code SecureRandomInstantiateParameters}
+ * the newly created {@code SecureRandom} object must support.
+ *
+ * @param provider the provider.
+ *
+ * @return the new {@code SecureRandom} object.
+ *
+ * @throws NoSuchAlgorithmException if the specified provider does not
+ * support a {@code SecureRandomSpi} implementation for the specified
+ * algorithm and parameters.
+ *
+ * @throws IllegalArgumentException if the specified provider or params
+ * is null.
+ *
+ * @see Provider
+ *
+ * @since 9
+ */
+ public static SecureRandom getInstance(String algorithm,
+ SecureRandomInstantiateParameters params, Provider provider)
+ throws NoSuchAlgorithmException {
+ if (params == null) {
+ throw new IllegalArgumentException("params cannot be null");
+ }
+ Instance instance = GetInstance.getInstance("SecureRandom",
+ SecureRandomSpi.class, algorithm, params, provider);
+ SecureRandomSpi spi = (SecureRandomSpi)instance.impl;
+ return new SecureRandom(spi, instance.provider, algorithm);
+ }
+
+ /**
+ * Returns the {@code SecureRandomSpi} of this {@code SecureRandom} object.
*/
SecureRandomSpi getSecureRandomSpi() {
return secureRandomSpi;
}
/**
- * Returns the provider of this SecureRandom object.
+ * Returns the provider of this {@code SecureRandom} object.
*
- * @return the provider of this SecureRandom object.
+ * @return the provider of this {@code SecureRandom} object.
*/
public final Provider getProvider() {
return provider;
}
/**
- * Returns the name of the algorithm implemented by this SecureRandom
+ * Returns the name of the algorithm implemented by this {@code SecureRandom}
* object.
*
* @return the name of the algorithm or {@code unknown}
@@ -422,10 +584,42 @@
return Objects.toString(algorithm, "unknown");
}
+ @Override
+ public String toString() {
+ return secureRandomSpi.toString();
+ }
+
/**
- * Reseeds this random object. The given seed supplements, rather than
- * replaces, the existing seed. Thus, repeated calls are guaranteed
- * never to reduce randomness.
+ * Returns the effective {@link SecureRandomInstantiateParameters} that
+ * is actually used to instantiate this {@code SecureRandom}.
+ * <p>
+ * The returned value can be different from the
+ * {@code SecureRandomInstantiateParameters} object passed into
+ * a {@code getInstance} method, but it cannot change during the lifetime
+ * of this {@code SecureRandom} object.
+ * <p>
+ * A caller can use the returned value to find out what features this
+ * {@code SecureRandom} supports.
+ *
+ * @return the parameters used in instantiation, or {@code null} if no
+ * parameters were used.
+ *
+ * @since 9
+ * @see SecureRandomSpi
+ */
+ public SecureRandomInstantiateParameters getParameters() {
+ return secureRandomSpi.engineGetParameters();
+ }
+
+ /**
+ * Reseeds this random object with the given seed. The seed supplements,
+ * rather than replaces, the existing seed. Thus, repeated calls are
+ * guaranteed never to reduce randomness.
+ * <p>
+ * A PRNG {@code SecureRandom} will not seed itself automatically if {@code setSeed}
+ * is called before any {@code nextBytes} or {@code reseed} calls.
+ * The caller should make sure that the {@code seed} argument contains
+ * enough entropy for the security of this {@code SecureRandom}.
*
* @param seed the seed.
*
@@ -457,23 +651,43 @@
* yet been initialized at that point.
*/
if (seed != 0) {
- secureRandomSpi.engineSetSeed(longToByteArray(seed));
+ setSeed(longToByteArray(seed));
}
}
/**
* Generates a user-specified number of random bytes.
*
- * <p> If a call to {@code setSeed} had not occurred previously,
- * the first call to this method forces this SecureRandom object
- * to seed itself. This self-seeding will not occur if
- * {@code setSeed} was previously called.
- *
* @param bytes the array to be filled in with random bytes.
+ *
+ * @throws NullPointerException if {@code bytes} is null.
*/
@Override
public void nextBytes(byte[] bytes) {
- secureRandomSpi.engineNextBytes(bytes);
+ secureRandomSpi.engineNextBytes(
+ Objects.requireNonNull(bytes));
+ }
+
+ /**
+ * Generates a user-specified number of random bytes with
+ * additional parameters.
+ *
+ * @param bytes the array to be filled in with random bytes
+ * @param params additional parameters
+ * @throws NullPointerException if {@code bytes} is null
+ * @throws UnsupportedOperationException if the underlying provider
+ * implementation has not overridden this method.
+ * @throws IllegalArgumentException if {@code params} is {@code null},
+ * unrecognizable or unsupported by this {@code SecureRandom}
+ *
+ * @since 9
+ */
+ public synchronized void nextBytes(
+ byte[] bytes, SecureRandomNextBytesParameters params) {
+ if (params == null) {
+ throw new IllegalArgumentException("params cannot be null");
+ }
+ secureRandomSpi.engineNextBytes(Objects.requireNonNull(bytes), params);
}
/**
@@ -511,7 +725,7 @@
*
* <p>This method is only included for backwards compatibility.
* The caller is encouraged to use one of the alternative
- * {@code getInstance} methods to obtain a SecureRandom object, and
+ * {@code getInstance} methods to obtain a {@code SecureRandom} object, and
* then call the {@code generateSeed} method to obtain seed bytes
* from that object.
*
@@ -536,10 +750,13 @@
* call may be used to seed other random number generators.
*
* @param numBytes the number of seed bytes to generate.
- *
+ * @throws IllegalArgumentException if {@code numBytes} is negative
* @return the seed bytes.
*/
public byte[] generateSeed(int numBytes) {
+ if (numBytes < 0) {
+ throw new IllegalArgumentException("numBytes cannot be negative");
+ }
return secureRandomSpi.engineGenerateSeed(numBytes);
}
@@ -561,8 +778,8 @@
/**
* Gets a default PRNG algorithm by looking through all registered
* providers. Returns the first PRNG algorithm of the first provider that
- * has registered a SecureRandom implementation, or null if none of the
- * registered providers supplies a SecureRandom implementation.
+ * has registered a {@code SecureRandom} implementation, or null if none of the
+ * registered providers supplies a {@code SecureRandom} implementation.
*/
private static String getPrngAlgorithm() {
for (Provider p : Providers.getProviderList().providers()) {
@@ -666,6 +883,42 @@
"No strong SecureRandom impls available: " + property);
}
+ /**
+ * Reseeds this {@code SecureRandom} with entropy input read from its
+ * entropy source.
+ *
+ * @throws UnsupportedOperationException if the underlying provider
+ * implementation has not overridden this method.
+ *
+ * @since 9
+ */
+ public synchronized void reseed() {
+ secureRandomSpi.engineReseed(null);
+ }
+
+ /**
+ * Reseeds this {@code SecureRandom} with entropy input read from its
+ * entropy source with additional parameters.
+ * <p>
+ * Note that entropy is obtained from an entropy source. While
+ * some data in {@code params} may contain entropy, its main usage is to
+ * provide diversity.
+ *
+ * @param params extra parameters
+ * @throws UnsupportedOperationException if the underlying provider
+ * implementation has not overridden this method.
+ * @throws IllegalArgumentException if {@code params} is {@code null},
+ * unrecognizable or unsupported by this {@code SecureRandom}
+ *
+ * @since 9
+ */
+ public synchronized void reseed(SecureRandomReseedParameters params) {
+ if (params == null) {
+ throw new IllegalArgumentException("params cannot be null");
+ }
+ secureRandomSpi.engineReseed(params);
+ }
+
// Declare serialVersionUID to be compatible with JDK1.1
static final long serialVersionUID = 4940670005562187L;
@@ -684,7 +937,7 @@
* We know that the MessageDigest class does not implement
* java.io.Serializable. However, since this field is no longer
* used, it will always be NULL and won't affect the serialization
- * of the SecureRandom class itself.
+ * of the {@code SecureRandom} class itself.
*/
private byte[] randomBytes;
/**
--- old/src/java.base/share/classes/java/security/SecureRandomSpi.java 2016-04-01 19:17:49.000000000 +0800
+++ new/src/java.base/share/classes/java/security/SecureRandomSpi.java 2016-04-01 19:17:49.000000000 +0800
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1998, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1998, 2016, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -27,13 +27,38 @@
/**
* This class defines the <i>Service Provider Interface</i> (<b>SPI</b>)
- * for the {@code SecureRandom} class.
+ * for the {@link SecureRandom} class.
+ * <p>
* All the abstract methods in this class must be implemented by each
* service provider who wishes to supply the implementation
* of a cryptographically strong pseudo-random number generator.
*
+ * @implSpec
+ * If the {@link #SecureRandomSpi(SecureRandomInstantiateParameters)}
+ * constructor is overridden in an implementation, it will always be called
+ * whenever a {@code SecureRandom} is instantiated. Precisely, if an object is
+ * instantiated with one of {@code SecureRandom}'s {@code getInstance} methods
+ * <em>without</em> a {@link SecureRandomInstantiateParameters} parameter,
+ * the constructor will be called with a {@code null} argument and the
+ * implementation is responsible for creating its own
+ * {@code SecureRandomInstantiateParameters} parameter for use when
+ * {@link #engineGetParameters()} is called. If an object
+ * is instantiated with one of {@code SecureRandom}'s {@code getInstance}
+ * methods <em>with</em> a {@code SecureRandomInstantiateParameters} argument,
+ * the constructor will be called with that argument. The
+ * {@link #engineGetParameters()} method must not return {@code null}.
+ * <p>
+ * Otherwise, if the {@code SecureRandomSpi(SecureRandomInstantiateParameters)}
+ * constructor is not overridden in an implementation, the
+ * {@link #SecureRandomSpi()} constructor must be overridden and it will be
+ * called if an object is instantiated with one of {@code SecureRandom}'s
+ * {@code getInstance} methods <em>without</em> a
+ * {@code SecureRandomInstantiateParameters} argument. Calling one of
+ * {@code SecureRandom}'s {@code getInstance} methods <em>with</em>
+ * a {@code SecureRandomInstantiateParameters} argument will never
+ * return an instance of this implementation. The
+ * {@link #engineGetParameters()} method must return {@code null}.
*
- * @see SecureRandom
* @since 1.2
*/
@@ -42,9 +67,30 @@
private static final long serialVersionUID = -2991854161009191830L;
/**
- * Reseeds this random object. The given seed supplements, rather than
- * replaces, the existing seed. Thus, repeated calls are guaranteed
- * never to reduce randomness.
+ * Constructor without a parameter.
+ */
+ public SecureRandomSpi() {
+ // ignored
+ }
+
+ /**
+ * Constructor with a parameter.
+ *
+ * @param params the {@link SecureRandomInstantiateParameters} object.
+ * This argument can be {@code null}.
+ * @throws IllegalArgumentException if {@code params} is
+ * unrecognizable or unsupported by this {@code SecureRandom}
+ *
+ * @since 9
+ */
+ protected SecureRandomSpi(SecureRandomInstantiateParameters params) {
+ // ignored
+ }
+
+ /**
+ * Reseeds this random object with the given seed. The seed supplements,
+ * rather than replaces, the existing seed. Thus, repeated calls
+ * are guaranteed never to reduce randomness.
*
* @param seed the seed.
*/
@@ -53,16 +99,32 @@
/**
* Generates a user-specified number of random bytes.
*
- * <p> If a call to {@code engineSetSeed} had not occurred previously,
- * the first call to this method forces this SecureRandom implementation
- * to seed itself. This self-seeding will not occur if
- * {@code engineSetSeed} was previously called.
- *
* @param bytes the array to be filled in with random bytes.
*/
protected abstract void engineNextBytes(byte[] bytes);
/**
+ * Generates a user-specified number of random bytes with
+ * additional parameters.
+ *
+ * @implSpec The default implementation throws
+ * an {@link UnsupportedOperationException}.
+ *
+ * @param bytes the array to be filled in with random bytes
+ * @param params additional parameters
+ * @throws UnsupportedOperationException if the implementation
+ * has not overridden this method
+ * @throws IllegalArgumentException if {@code params} is {@code null},
+ * unrecognizable or unsupported by this {@code SecureRandom}
+ *
+ * @since 9
+ */
+ protected void engineNextBytes(
+ byte[] bytes, SecureRandomNextBytesParameters params) {
+ throw new UnsupportedOperationException("not supported");
+ }
+
+ /**
* Returns the given number of seed bytes. This call may be used to
* seed other random number generators.
*
@@ -70,5 +132,47 @@
*
* @return the seed bytes.
*/
- protected abstract byte[] engineGenerateSeed(int numBytes);
+ protected abstract byte[] engineGenerateSeed(int numBytes);
+
+ /**
+ * Reseeds this random object with entropy input read from its
+ * entropy source with additional parameters.
+ * <p>
+ * If this method is called by {@link SecureRandom#reseed()},
+ * {@code params} will be {@code null}.
+ *
+ * @implSpec The default implementation throws
+ * an {@link UnsupportedOperationException}.
+ *
+ * @param params extra parameters, can be {@code null}.
+ * @throws UnsupportedOperationException if the implementation
+ * has not overridden this method
+ * @throws IllegalArgumentException if {@code params} is
+ * unrecognizable or unsupported by this {@code SecureRandom}
+ *
+ * @since 9
+ */
+ protected void engineReseed(SecureRandomReseedParameters params) {
+ throw new UnsupportedOperationException("not supported");
+ }
+
+ /**
+ * Returns the effective {@link SecureRandomInstantiateParameters}
+ * that is actually used to instantiate this {@code SecureRandom}.
+ *
+ * @implSpec The default implementation returns {@code null}.
+ *
+ * @return the parameters used in instantiation, or {@code null} if no
+ * parameters were used.
+ *
+ * @since 9
+ */
+ protected SecureRandomInstantiateParameters engineGetParameters() {
+ return null;
+ }
+
+ @Override
+ public String toString() {
+ return getClass().getSimpleName();
+ }
}
--- old/src/java.base/share/classes/sun/security/provider/ByteArrayAccess.java 2016-04-01 19:17:50.000000000 +0800
+++ new/src/java.base/share/classes/sun/security/provider/ByteArrayAccess.java 2016-04-01 19:17:50.000000000 +0800
@@ -448,10 +448,12 @@
out[outOfs++] = (byte)(i >> 48);
out[outOfs++] = (byte)(i >> 40);
out[outOfs++] = (byte)(i >> 32);
- out[outOfs++] = (byte)(i >> 24);
- out[outOfs++] = (byte)(i >> 16);
- out[outOfs++] = (byte)(i >> 8);
- out[outOfs++] = (byte)(i );
+ if (outOfs < len) { // SHA-512/224 is 28 bytes
+ out[outOfs++] = (byte) (i >> 24);
+ out[outOfs++] = (byte) (i >> 16);
+ out[outOfs++] = (byte) (i >> 8);
+ out[outOfs++] = (byte) (i);
+ }
}
}
}
--- old/src/java.base/share/classes/sun/security/provider/SHA5.java 2016-04-01 19:17:51.000000000 +0800
+++ new/src/java.base/share/classes/sun/security/provider/SHA5.java 2016-04-01 19:17:51.000000000 +0800
@@ -306,4 +306,31 @@
super("SHA-384", 48, INITIAL_HASHES);
}
}
+ public static final class SHA512_224 extends SHA5 {
+
+ private static final long[] INITIAL_HASHES = {
+ 0x8C3D37C819544DA2L, 0x73E1996689DCD4D6L,
+ 0x1DFAB7AE32FF9C82L, 0x679DD514582F9FCFL,
+ 0x0F6D2B697BD44DA8L, 0x77E36F7304C48942L,
+ 0x3F9D85A86A1D36C8L, 0x1112E6AD91D692A1L
+ };
+
+ public SHA512_224() {
+ super("SHA-512/224", 28, INITIAL_HASHES);
+ }
+ }
+
+ public static final class SHA512_256 extends SHA5 {
+
+ private static final long[] INITIAL_HASHES = {
+ 0x22312194FC2BF72CL, 0x9F555FA3C84C64C2L,
+ 0x2393B86B6F53B151L, 0x963877195940EABDL,
+ 0x96283EE2A88EFFE3L, 0xBE5E1E2553863992L,
+ 0x2B0199FC2C85B8AAL, 0x0EB72DDC81C52CA2L
+ };
+
+ public SHA512_256() {
+ super("SHA-512/256", 32, INITIAL_HASHES);
+ }
+ }
}
--- old/src/java.base/share/classes/sun/security/provider/SunEntries.java 2016-04-01 19:17:52.000000000 +0800
+++ new/src/java.base/share/classes/sun/security/provider/SunEntries.java 2016-04-01 19:17:52.000000000 +0800
@@ -97,6 +97,9 @@
map.put("SecureRandom.NativePRNG",
"sun.security.provider.NativePRNG");
}
+
+ map.put("SecureRandom.DRBG", "sun.security.provider.DRBG");
+
map.put("SecureRandom.SHA1PRNG",
"sun.security.provider.SecureRandom");
if (nativeAvailable && !useNativePRNG) {
@@ -199,6 +202,14 @@
map.put("Alg.Alias.MessageDigest.2.16.840.1.101.3.4.2.3", "SHA-512");
map.put("Alg.Alias.MessageDigest.OID.2.16.840.1.101.3.4.2.3",
"SHA-512");
+ map.put("MessageDigest.SHA-512/224", "sun.security.provider.SHA5$SHA512_224");
+ map.put("Alg.Alias.MessageDigest.2.16.840.1.101.3.4.2.5", "SHA-512/224");
+ map.put("Alg.Alias.MessageDigest.OID.2.16.840.1.101.3.4.2.5",
+ "SHA-512/224");
+ map.put("MessageDigest.SHA-512/256", "sun.security.provider.SHA5$SHA512_256");
+ map.put("Alg.Alias.MessageDigest.2.16.840.1.101.3.4.2.6", "SHA-512/256");
+ map.put("Alg.Alias.MessageDigest.OID.2.16.840.1.101.3.4.2.6",
+ "SHA-512/256");
/*
* Algorithm Parameter Generator engines
--- old/src/java.base/share/classes/sun/security/util/Debug.java 2016-04-01 19:17:53.000000000 +0800
+++ new/src/java.base/share/classes/sun/security/util/Debug.java 2016-04-01 19:17:53.000000000 +0800
@@ -89,6 +89,7 @@
System.err.println("pkcs12 PKCS12 KeyStore debugging");
System.err.println("sunpkcs11 SunPKCS11 provider debugging");
System.err.println("scl permissions SecureClassLoader assigns");
+ System.err.println("securerandom SecureRandom");
System.err.println("ts timestamping");
System.err.println();
System.err.println("The following can be used with access:");
--- old/src/java.base/share/conf/security/java.security 2016-04-01 19:17:54.000000000 +0800
+++ new/src/java.base/share/conf/security/java.security 2016-04-01 19:17:54.000000000 +0800
@@ -120,23 +120,23 @@
#
# Sun Provider SecureRandom seed source.
#
-# Select the primary source of seed data for the "SHA1PRNG" and
+# Select the primary source of seed data for the "DRBG", "SHA1PRNG" and
# "NativePRNG" SecureRandom implementations in the "Sun" provider.
# (Other SecureRandom implementations might also use this property.)
#
# On Unix-like systems (for example, Solaris/Linux/MacOS), the
-# "NativePRNG" and "SHA1PRNG" implementations obtains seed data from
+# "NativePRNG", "DRBG", and "SHA1PRNG" implementations obtains seed data from
# special device files such as file:/dev/random.
#
# On Windows systems, specifying the URLs "file:/dev/random" or
# "file:/dev/urandom" will enable the native Microsoft CryptoAPI seeding
-# mechanism for SHA1PRNG.
+# mechanism for DRBG and SHA1PRNG.
#
# By default, an attempt is made to use the entropy gathering device
# specified by the "securerandom.source" Security property. If an
# exception occurs while accessing the specified URL:
#
-# SHA1PRNG:
+# DRBG and SHA1PRNG:
# the traditional system/thread activity algorithm will be used.
#
# NativePRNG:
@@ -154,7 +154,7 @@
#
# In addition, if "file:/dev/random" or "file:/dev/urandom" is
# specified, the "NativePRNG" implementation will be more preferred than
-# SHA1PRNG in the Sun provider.
+# DRBG and SHA1PRNG in the Sun provider.
#
securerandom.source=file:/dev/random
@@ -169,13 +169,65 @@
# entries.
#
#ifdef windows
-securerandom.strongAlgorithms=Windows-PRNG:SunMSCAPI,SHA1PRNG:SUN
+securerandom.strongAlgorithms=Windows-PRNG:SunMSCAPI,DRBG:SUN
#endif
#ifndef windows
securerandom.strongAlgorithms=NativePRNGBlocking:SUN
#endif
#
+# Sun provider DRBG configuration and default instantiation request.
+#
+# NIST SP 800-90Ar1 lists several DRBG mechanisms, each can be configured with
+# a DRBG algorithm name, and can be instantiated with a security strength,
+# prediction resistance support, etc. This property defines the configuration
+# and the default instantiation request of "DRBG" SecureRandom implemented in
+# the SUN provider. Applications can request different instantiation parameters
+# like security strength/capability/personalization strings using
+# the getInstance(...,SecureRandomInstantiateParameters,...) APIs, but
+# other settings such as the mechanism and DRBG algorithm names are not
+# configurable by any API.
+#
+# Please note that the SUN implementation of DRBG always supports reseeding.
+#
+# The value of this property is a slash-separated list of all configurable
+# aspects. The aspects can appear in any order but the same aspect can only
+# appear at most once. Its BNF-style definition is:
+#
+# Value:
+# aspect { "," aspect }
+#
+# aspect:
+# mech_name | algorithm_name | strength | capability | df
+#
+# mech_name: default "Hash_DRBG"
+# "Hash_DRBG" | "HMAC_DRBG" | "CTR_DRBG"
+#
+# algorithm_name: For Hash_DRBG and HMAC_DRBG, default to "SHA-256".
+# For CTR_DRBG, default to "AES-128" when using the limited
+# cryptographic policy files, or "AES-256" for unlimited.
+# Any supported MessageDigest or Cipher algorithm name as described
+# in Section 10 of SP 800-90Ar1
+#
+# strength: default "128", or "112" if mech_name is CTR_DRBG
+# and algorithm_name is "3 Key TDEA"
+# "112" | "128" | "192" | "256"
+#
+# pr: default "none"
+# "pr_and_reseed" | "reseed_only" | "none"
+#
+# df: default "use_df", only applicable to CTR_DRBG
+# "use_df" | "no_df"
+#
+# Examples,
+# drbg=Hash_DRBG,SHA-1,112,none
+# drbg=CTR_DRBG,AES-256,256,pr_and_reseed,use_df
+#
+# The default value is an empty string, which is equivalent to
+# drbg=Hash_DRBG,SHA-256,128,none
+drbg=
+
+#
# Class to instantiate as the javax.security.auth.login.Configuration
# provider.
#
--- old/test/java/security/SecureRandom/Serialize.java 2016-04-01 19:17:55.000000000 +0800
+++ new/test/java/security/SecureRandom/Serialize.java 2016-04-01 19:17:55.000000000 +0800
@@ -31,16 +31,68 @@
public class Serialize {
- public static void main(String args[]) throws IOException {
+ public static void main(String args[]) throws Exception {
+ for (String alg: new String[]{
+ "SHA1PRNG", "DRBG", "Hash_DRBG", "HMAC_DRBG", "CTR_DRBG"}) {
+ System.out.println("Testing " + alg);
- FileOutputStream fos = new FileOutputStream("t.tmp");
- ObjectOutputStream oos = new ObjectOutputStream(fos);
+ // Even unseeded object can be serialized and deserialized
+ SecureRandom s1 = getInstance(alg);
+ revive(s1).nextInt();
+ if (alg.contains("DRBG")) {
+ revive(s1).reseed();
+ }
- SecureRandom secRandom = new SecureRandom();
+ // After seeded, deserialized object should emit same random data
+ s1 = getInstance(alg);
+ s1.nextInt(); // state set
+ SecureRandom s2 = revive(s1);
+ int n1 = s1.nextInt();
+ int n2 = s2.nextInt();
+ if (n1 != n2) {
+ throw new Exception();
+ }
- // serialize and write out
- oos.writeObject(secRandom);
- oos.flush();
- oos.close();
+ // Or seeded with user-provided data
+ s1.setSeed(42);
+ s2.setSeed(42);
+ n1 = s1.nextInt();
+ n2 = s2.nextInt();
+ if (n1 != n2) {
+ throw new Exception();
+ }
+
+ // But not after automatic reseed
+ if (alg.contains("DRBG")) {
+ s1.reseed();
+ s2.reseed();
+ n1 = s1.nextInt();
+ n2 = s2.nextInt();
+ if (n1 == n2) {
+ throw new Exception();
+ }
+ }
+ }
+ }
+
+ private static SecureRandom getInstance(String alg) throws Exception {
+ if (alg.equals("SHA1PRNG") || alg.equals("DRBG")) {
+ return SecureRandom.getInstance(alg);
+ } else {
+ String old = Security.getProperty("drbg");
+ try {
+ Security.setProperty("drbg", alg);
+ return SecureRandom.getInstance("DRBG");
+ } finally {
+ Security.setProperty("drbg", old);
+ }
+ }
+ }
+
+ private static SecureRandom revive(SecureRandom sr) throws Exception {
+ ByteArrayOutputStream bout = new ByteArrayOutputStream();
+ new ObjectOutputStream(bout).writeObject(sr);
+ return (SecureRandom) new ObjectInputStream(
+ new ByteArrayInputStream(bout.toByteArray())).readObject();
}
}
--- /dev/null 2016-04-01 19:17:56.000000000 +0800
+++ new/src/java.base/share/classes/java/security/DrbgParameters.java 2016-04-01 19:17:56.000000000 +0800
@@ -0,0 +1,486 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code 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
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.security;
+
+import java.util.Locale;
+import java.util.Objects;
+
+/**
+ * This class specifies the parameters used by a DRBG.
+ * <p>
+ * According to
+ * <a href="http://nvlpubs.nist.gov/nistpubs/SpecialPublications/NIST.SP.800-90Ar1.pdf">
+ * NIST Special Publication 800-90A Revision 1, Recommendation for Random Number
+ * Generation Using Deterministic Random Bit Generators</a>,
+ * <blockquote>
+ * A DRBG is based on a DRBG mechanism as specified in this Recommendation
+ * and includes a source of randomness. A DRBG mechanism uses an algorithm
+ * (i.e., a DRBG algorithm) that produces a sequence of bits from an initial
+ * value that is determined by a seed that is determined from the output of
+ * the randomness source."
+ * </blockquote>
+ * <p>
+ * A DRBG implementation has a configuration, including but not limited to,
+ * <ul>
+ * <li> an entropy source,
+ * <li> a DRBG mechanism (for example, Hash_DRBG),
+ * <li> a DRBG algorithm (for example, SHA-256 for Hash_DRBG and AES-256
+ * for CTR_DRBG. Please note that it is not the algorithm used in
+ * {@link SecureRandom#getInstance}, which we will call
+ * a <em>SecureRandom algorithm</em> below),
+ * <li> optionally supported features, including prediction resistance and reseed,
+ * <li> highest security strength
+ * </ul>
+ * <p>
+ * The configuration is defined by the implementation and not managed
+ * by the {@code SecureRandom} API.
+ * <p>
+ * A DRBG instance is instantiated with parameters from an {@code Instantiate}
+ * object and other information (for example, the nonce, which is not managed
+ * by this API). This maps to the {@code Instantiate_function} defined in
+ * NIST SP 800-90A.
+ * <p>
+ * Calling {@link SecureRandom#nextBytes(byte[], SecureRandomNextBytesParameters)}
+ * and {@link SecureRandom#reseed(SecureRandomReseedParameters)} map to the
+ * {@code Reseed_function} and {@code Generate_function} defined in
+ * NIST SP 800-90A, separately. Calling {@link SecureRandom#nextBytes(byte[])}
+ * is equivalent to calling
+ * {@link SecureRandom#nextBytes(byte[], SecureRandomNextBytesParameters)}
+ * with the instantiated strength and prediction resistance flag (as returned
+ * in {@link SecureRandom#getParameters()}) with no additional input.
+ * Calling {@link SecureRandom#reseed()} is equivalent to calling
+ * {@link SecureRandom#reseed(SecureRandomReseedParameters)} with the
+ * instantiated prediction resistance flag (as returned in
+ * {@link SecureRandom#getParameters()}) with no additional input.
+ * <p>
+ * A DRBG should be implemented as a subclass of {@link SecureRandomSpi}.
+ * It is recommended that the implementation contain
+ * {@linkplain SecureRandomSpi#SecureRandomSpi(SecureRandomInstantiateParameters) a constructor}
+ * that has a {@link DrbgParameters.Instantiate} argument. If implemented this way,
+ * this implementation can be chosen by any {@code SecureRandom.getInstance()}
+ * method. If it is chosen by a {@code SecureRandom.getInstance()} with a
+ * {@link SecureRandomInstantiateParameters} parameter, the parameter is passed
+ * into this constructor. If it is chosen by a {@code SecureRandom.getInstance()}
+ * without a {@link SecureRandomInstantiateParameters} parameter, the constructor
+ * is called with a {@code null} argument and the implementation should choose
+ * its own parameters. Its {@link SecureRandom#getParameters()} must always
+ * return a non-null effective {@link Instantiate} object that reflects how the DRBG
+ * is actually instantiated. A caller can use this information to determine
+ * whether a {@code SecureRandom} object is a DRBG and what features it supports.
+ * Please note that the returned value does not necessarily equal to the
+ * {@code Instantiate} object passed into the {@code SecureRandom.getInstance()}
+ * call. For example, the requested capability can be {@link Capability#NONE}
+ * but the returned capability can be {@link Capability#RESEED_ONLY} if the
+ * implementation supports reseeding. The implementation must implement the
+ * {@link SecureRandomSpi#engineNextBytes(byte[], SecureRandomNextBytesParameters)}
+ * method which takes a {@link NextBytes} parameter. Unless the result of
+ * {@link SecureRandom#getParameters()} has its
+ * {@linkplain Instantiate#getCapability() capability} being
+ * {@link Capability#NONE NONE}, it must implement
+ * {@link SecureRandomSpi#engineReseed(SecureRandomReseedParameters)}
+ * which takes a {@link Reseed} parameter.
+ * <p>
+ * On the other hand, if a DRBG implementation does not contain a
+ * constructor that has an {@link Instantiate} argument (not recommended),
+ * it can only be chosen by a {@code SecureRandom.getInstance()}
+ * without a {@link SecureRandomInstantiateParameters} parameter, but will not be chosen if a {@code getInstance} method with a
+ * {@link SecureRandomInstantiateParameters} parameter is called. If
+ * implemented this way, its {@link SecureRandom#getParameters()} must return
+ * {@code null}, and it does not need to implement either
+ * {@link SecureRandomSpi#engineNextBytes(byte[], SecureRandomNextBytesParameters)}
+ * or {@link SecureRandomSpi#engineReseed(SecureRandomReseedParameters)}.
+ * <p>
+ * A DRBG might reseed itself automatically if the seed period is bigger
+ * than the maximum seed life defined by the DRBG mechanism.
+ * <p>
+ * Examples:
+ * <blockquote><pre>
+ * SecureRandom drbg;
+ * byte[] buffer = new byte[32];
+ *
+ * // Any DRBG is OK
+ * drbg = SecureRandom.getInstance("DRBG");
+ * drbg.nextBytes(buffer);
+ *
+ * SecureRandomInstantiateParameters params = drbg.getParameters();
+ * if (params instanceof DrbgParameters.Instantiate) {
+ * DrbgParameters.Instantiate ins = (DrbgParameters.Instantiate) params;
+ * if (ins.getCapability() != NONE) {
+ * drbg.reseed();
+ * }
+ * }
+ *
+ * // This might return a weak DRBG instance. It is only guaranteed to support
+ * // 112 bits of security strength.
+ * drbg = SecureRandom.getInstance("DRBG",
+ * DrbgParameters.instantiate(112, NONE, null);
+ *
+ * // Both the next two calls will likely fail, because drbg could be
+ * // instantiated with a smaller strength with no prediction resistance
+ * // support.
+ * drbg.nextBytes(buffer,
+ * DrbgParameters.nextBytes(256, false, "more".getBytes()));
+ * drbg.nextBytes(buffer,
+ * DrbgParameters.nextBytes(112, true, "more".getBytes()));
+ *
+ * // This returns a strong DRBG instance, with a personalization string.
+ * // It is guaranteed to support 256 bits of security strength with
+ * // prediction resistance turned on.
+ * drbg = SecureRandom.getInstance("DRBG",
+ * DrbgParameters.instantiate(256, PR_AND_RESEED, "hello".getBytes()));
+ *
+ * // Prediction resistance is not requested in this single call,
+ * // but an additional input is used.
+ * drbg.nextBytes(buffer,
+ * DrbgParameters.nextBytes(-1, false, "more".getBytes()));
+ *
+ * // Same for this call.
+ * drbg.reseed(DrbgParameters.reseed(false, "extra".getBytes()));
+ * </pre></blockquote>
+ *
+ * @implSpec
+ * By convention, a provider should name its primary DRBG implementation
+ * with the <a href=
+ * "{@docRoot}/../technotes/guides/security/StandardNames.html#SecureRandom">
+ * standard {@code SecureRandom} algorithm name</a> "DRBG". How this implementation
+ * is configured is provider-specific. A provider is free to add other DRBG
+ * implementations with specific configurations using different {@code SecureRandom}
+ * algorithm names (for example, "Hash_DRBG/SHA-512").
+ *
+ * @implNote
+ * The following notes apply to the "DRBG" implementation in the SUN provider
+ * of the JDK reference implementation.
+ * <p>
+ * This implementation supports the Hash_DRBG and HMAC_DRBG mechanisms with
+ * DRBG algorithm names SHA-1, SHA-224, SHA-512/224, SHA-256, SHA-512/256,
+ * SHA-384 and SHA-512, and CTR_DRBG (both using derivation function and
+ * not using derivation function) with DRBG algorithm names DESede
+ * (aka 3 Key TDEA), AES-128, AES-192 and AES-256.
+ * <p>
+ * The mechanism name and DRBG algorithm name can be configured with the
+ * {@linkplain Security#getProperty(String) security property} {@code drbg}.
+ * The default configuration is Hash_DRBG with SHA-256.
+ * <p>
+ * For each combination, the security strength can be requested from 112
+ * up to the highest strength it supports. Reseeding is supported, and
+ * prediction resistance can be turned on or off.
+ * <p>
+ * Personalization string is supported through the
+ * {@link DrbgParameters.Instantiate} class and additional input is supported
+ * through the {@link DrbgParameters.NextBytes}
+ * and {@link DrbgParameters.Reseed} classes.
+ * <p>
+ * If a DRBG is not instantiated with a {@link DrbgParameters.Instantiate}
+ * object explicitly, this implementation instantiates it with a default
+ * requested strength of 128 bits, no prediction resistance request, and
+ * no personalization string. These default instantiation parameters can also
+ * be customized with the {@code drbg} security property.
+ * <p>
+ * This implementation reads fresh entropy from the system default entropy
+ * source determined by the security property {@code securerandom.source}.
+ * <p>
+ * This implementation has passed all tests included in the 20151104 version of
+ * <a href="http://csrc.nist.gov/groups/STM/cavp/documents/drbg/drbgtestvectors.zip">
+ * The DRBG Test Vectors</a>.
+ * <p>
+ * Calling {@link SecureRandom#generateSeed(int)} will directly read
+ * from a DRBG's entropy source.
+ *
+ * @since 9
+ */
+public class DrbgParameters {
+
+ private DrbgParameters() {
+ // This class should not be instantiated
+ }
+
+ /**
+ * The reseedable and prediction resistance capabilities of a DRBG.
+ * <p>
+ * When this object is used in a {@code SecureRandom.getInstance()} call,
+ * it means the required minimum capability. When used in
+ * {@code SecureRandom.getParameters()}, it means the effective capability.
+ * <p>
+ * A DRBG implementation supporting prediction resistance must also
+ * support reseeding.
+ *
+ * @see Instantiate#getCapability()
+ * @since 9
+ */
+ public enum Capability {
+ /** Both prediction resistance and reseed. */
+ PR_AND_RESEED,
+ /** Reseed but no prediction resistance. */
+ RESEED_ONLY,
+ /** Neither prediction resistance nor reseed. */
+ NONE;
+
+ @Override
+ public String toString() {
+ return name().toLowerCase(Locale.ROOT);
+ }
+ }
+
+ /**
+ * DRBG parameters for instantiation.
+ * <p>
+ * When used in
+ * {@link SecureRandom#getInstance(String, SecureRandomInstantiateParameters)}
+ * or one of the other similar {@code getInstance} calls that take a
+ * {@code SecureRandomInstantiateParameters} parameter, it means the
+ * requested instantiate parameters the newly created {@code SecureRandom} object
+ * must support. When used as the return value of the
+ * {@link SecureRandom#getParameters()} method, it means the effective
+ * instantiate parameters of the {@code SecureRandom} object.
+ *
+ * @since 9
+ */
+ public static final class Instantiate
+ implements SecureRandomInstantiateParameters {
+
+ private final int strength;
+ private final Capability capability;
+ private final byte[] personalizationString;
+
+ /**
+ * Returns the strength.
+ *
+ * @return if used in {@code getInstance}, returns the minimum strength
+ * requested, or -1 if there is no specific request on the strength.
+ * If used in {@code getParameters}, returns the actual initiated strength.
+ * The actual strength must be greater than or equal to the minimum
+ * strength requested.
+ */
+ public int getStrength() {
+ return strength;
+ }
+
+ /**
+ * Returns the capability.
+ * <p>
+ * Please note that while the {@code Instantiate_function} defined in
+ * NIST SP 800-90A only includes a {@code prediction_resistance_flag}
+ * parameter, the {@code Capability} type includes extra values
+ * for reseeding. If {@code NONE} or {@code RESEED_ONLY} is used in
+ * an {@code Instantiate} object in calling the
+ * {@code SecureRandom.getInstance} method, the returned DRBG instance
+ * is not guaranteed to support reseed. If {@code RESEED_ONLY} or
+ * {@code PR_AND_RESEED} is used, the instance must support reseed.
+ * <p>
+ * The table below lists possible effective values if a certain
+ * capability is requested, i.e.
+ * <blockquote><pre>
+ * Capability req = ...;
+ * SecureRandom s = SecureRandom.getInstance("DRBG",
+ * DrbgParameters(-1, req, null));
+ * Capability eff = ((DrbgParametes.Initiate) s.getParameters())
+ * .getCapability();
+ * </pre></blockquote>
+ * <table border=1 summary="requested and effective capabilities">
+ * <tr>
+ * <th>Requested Value ({@code req})</th>
+ * <th>Possible Effective Values ({@code eff})</th>
+ * </tr>
+ * <tr><td>NONE</td><td>NONE, RESEED_ONLY, PR_AND_RESEED</td></tr>
+ * <tr><td>RESEED_ONLY</td><td>RESEED_ONLY, PR_AND_RESEED</td></tr>
+ * <tr><td>PR_AND_RESEED</td><td>PR_AND_RESEED</td></tr>
+ * </table>
+ *
+ * @return If used in {@code getInstance}, returns the minimum capability
+ * requested. If used in {@code getParameters}, returns how the DRBG
+ * is actually instantiated and whether it supports reseeding.
+ */
+ public Capability getCapability() {
+ return capability;
+ }
+
+ /**
+ * Returns the personalization string as a byte array.
+ *
+ * @return If used in {@code getInstance}, returns the requested
+ * personalization string as a newly allocated array, or {@code null}
+ * if no personalization string is requested. The same string
+ * should be returned in {@code getParameters}
+ * as a new copy, or {@code null} if no personalization string
+ * is requested in {@code getInstance}.
+ */
+ public byte[] getPersonalizationString() {
+ return personalizationString == null?
+ null: personalizationString.clone();
+ }
+
+ private Instantiate(int strength, Capability capability,
+ byte[] personalizationString) {
+ this.strength = strength;
+ this.capability = capability;
+ this.personalizationString = personalizationString == null
+ ? null: personalizationString.clone();
+ }
+
+ @Override
+ public String toString() {
+ // I don't care what personalizationString looks like
+ return strength + "," + capability + "," + personalizationString;
+ }
+ }
+
+ /**
+ * DRBG parameters for random bits generation. It is used in
+ * {@link SecureRandom#nextBytes(byte[], SecureRandomNextBytesParameters)}.
+ *
+ * @since 9
+ */
+ public static final class NextBytes
+ implements SecureRandomNextBytesParameters {
+ private final int strength;
+ private final boolean predictionResistance;
+ private final byte[] additionalInput;
+
+ /**
+ * Returns the strength requested.
+ *
+ * @return the strength requested, or -1 if the instantiated strength
+ * should be used.
+ */
+ public int getStrength() {
+ return strength;
+ }
+
+ /**
+ * Returns whether prediction resistance is requested.
+ *
+ * @return whether prediction resistance is requested
+ */
+ public boolean getPredictionResistance() {
+ return predictionResistance;
+ }
+
+ /**
+ * Returns the requested additional input.
+ *
+ * @return the requested additional input, {@code null} if
+ * not requested. A new byte array is returned each time this method
+ * is called.
+ */
+ public byte[] getAdditionalInput() {
+ return additionalInput == null? null: additionalInput.clone();
+ }
+
+ private NextBytes(int strength, boolean predictionResistance,
+ byte[] additionalInput) {
+ this.strength = strength;
+ this.predictionResistance = predictionResistance;
+ this.additionalInput = additionalInput == null?
+ null: additionalInput.clone();
+ }
+ }
+
+ /**
+ * DRBG parameters for reseed. It is used in
+ * {@link SecureRandom#reseed(SecureRandomReseedParameters)}.
+ *
+ * @since 9
+ */
+ public static final class Reseed implements SecureRandomReseedParameters {
+
+ private final byte[] additionalInput;
+ private final boolean predictionResistance;
+
+ /**
+ * Returns whether prediction resistance is requested.
+ *
+ * @return whether prediction resistance is requested
+ */
+ public boolean getPredictionResistance() {
+ return predictionResistance;
+ }
+
+ /**
+ * Returns the requested additional input.
+ *
+ * @return the requested additional input, {@code null} if
+ * not requested. A new byte array is returned each time this method
+ * is called.
+ */
+ public byte[] getAdditionalInput() {
+ return additionalInput == null? null: additionalInput.clone();
+ }
+
+ private Reseed(boolean predictionResistance, byte[] additionalInput) {
+ this.predictionResistance = predictionResistance;
+ this.additionalInput = additionalInput == null?
+ null: additionalInput.clone();
+ }
+ }
+
+ /**
+ * Generates a {@link DrbgParameters.Instantiate} object.
+ *
+ * @param strength security strength, -1 for a default strength if used
+ * in {@code getInstance}.
+ * @param capability capability
+ * @param personalizationString personalization string as a byte array,
+ * can be {@code null}. The content of this
+ * byte array will be copied.
+ * @return a new {@code Instantiate} object
+ * @throws NullPointerException if {@code capacity} is {@code null}.
+ */
+ public static Instantiate instantiate(int strength,
+ Capability capability,
+ byte[] personalizationString) {
+ return new Instantiate(strength, Objects.requireNonNull(capability),
+ personalizationString);
+ }
+
+ /**
+ * Generates a {@link NextBytes} object.
+ *
+ * @param strength requested strength, -1 means the effective instantiated
+ * strength should be used.
+ * @param predictionResistance prediction resistance requested
+ * @param additionalInput additional input, can be {@code null}.
+ * The content of this byte array will be copied.
+ * @return a new {@code NextBytes} object
+ */
+ public static NextBytes nextBytes(int strength,
+ boolean predictionResistance,
+ byte[] additionalInput) {
+ return new NextBytes(strength, predictionResistance, additionalInput);
+ }
+
+ /**
+ * Generates a {@link Reseed} object.
+ *
+ * @param predictionResistance prediction resistance requested
+ * @param additionalInput additional input, can be {@code null}.
+ * The content of this byte array will be copied.
+ * @return a new {@code Reseed} object
+ */
+ public static Reseed reseed(
+ boolean predictionResistance, byte[] additionalInput) {
+ return new Reseed(predictionResistance, additionalInput);
+ }
+}
--- /dev/null 2016-04-01 19:17:57.000000000 +0800
+++ new/src/java.base/share/classes/java/security/SecureRandomInstantiateParameters.java 2016-04-01 19:17:57.000000000 +0800
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code 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
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.security;
+
+/**
+ * A marker interface for parameters used in {@code SecureRandom} instantiation.
+ * <p>
+ * {@link SecureRandom#getInstance(String, SecureRandomInstantiateParameters)}
+ * uses it to request certain features, and {@link SecureRandom#getParameters()}
+ * returns it as the effective parameters used in instantiation.
+ */
+public interface SecureRandomInstantiateParameters {
+}
--- /dev/null 2016-04-01 19:17:58.000000000 +0800
+++ new/src/java.base/share/classes/java/security/SecureRandomNextBytesParameters.java 2016-04-01 19:17:58.000000000 +0800
@@ -0,0 +1,32 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code 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
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.security;
+
+/**
+ * A marker interface for the parameters used in
+ * {@link SecureRandom#nextBytes(byte[], SecureRandomNextBytesParameters)}.
+ */
+public interface SecureRandomNextBytesParameters {
+}
--- /dev/null 2016-04-01 19:18:00.000000000 +0800
+++ new/src/java.base/share/classes/java/security/SecureRandomReseedParameters.java 2016-04-01 19:17:59.000000000 +0800
@@ -0,0 +1,32 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code 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
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.security;
+
+/**
+ * A marker interface for the parameters used in
+ * {@link SecureRandom#reseed(SecureRandomReseedParameters)}.
+ */
+public interface SecureRandomReseedParameters {
+}
--- /dev/null 2016-04-01 19:18:01.000000000 +0800
+++ new/src/java.base/share/classes/sun/security/provider/AbstractDrbg.java 2016-04-01 19:18:01.000000000 +0800
@@ -0,0 +1,730 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code 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
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package sun.security.provider;
+
+import sun.security.util.Debug;
+
+import java.security.*;
+import java.util.Arrays;
+import java.util.Map;
+import java.util.concurrent.atomic.AtomicLong;
+import static java.security.DrbgParameters.Capability.*;
+
+/**
+ * The abstract base class for all DRBGs.
+ * <p>
+ * This class creates 5 new abstract methods. 3 are defined by the SP800-90A:
+ * <ol>
+ * <li>{@link #generateAlgorithm(byte[], byte[])}
+ * <li>{@link #reseedAlgorithm(byte[], byte[])} (might not be supported)
+ * <li>{@link #instantiateAlgorithm(byte[])}
+ * </ol>
+ * and 2 for implementation purpose:
+ * <ol>
+ * <li>{@link #initEngine()}
+ * <li>{@link #chooseAlgorithmAndStrength}
+ * </ol>
+ * All existing {@link SecureRandomSpi} methods are implemented based on the
+ * methods above as final. The instantiate process is divided into 2 phases:
+ * configuration is eagerly called to set up parameters, and instantiation
+ * is lazily called only when nextBytes or reseed is called.
+ */
+public abstract class AbstractDrbg extends SecureRandomSpi {
+
+ // synchronized keyword should be added to all externally callable engine
+ // methods including engineGenerateSeed, engineReseed, engineSetSeed
+ // and engineNextBytes. Internally engine methods like engineConfigure
+ // and instantiateAlgorithm are not synchronized. They will either be
+ // called in a constructor or in another synchronized method.
+
+ // Precisely engineGenerateSeed does not need to be synchronized since
+ // it does not modify any internal states after configuration is
+ // complete, but the configuration itself can be called by other engine
+ // methods and should be synchronized. My understanding is that the
+ // engineGenerateSeed method is not used much and it's not worth
+ // creating a lock for the configuration itself.
+
+ private static final long serialVersionUID = 9L;
+
+ /**
+ * This field is not null if {@code -Djava.security.debug=securerandom} is
+ * specified on the command line. An implementation can print useful
+ * debug info.
+ */
+ protected static final Debug debug = Debug.getInstance(
+ "securerandom", "drbg");
+
+ // Common working status
+
+ private boolean instantiated = false;
+
+ /**
+ * Reseed counter of a DRBG instance. A mechanism should increment it
+ * after each random bits generation and reset it in reseed. A mechanism
+ * does <em>not</em> need to compare it to {@link #reseedInterval}.
+ */
+ protected int reseedCounter = 0;
+
+ // Mech features. If not same as below, must be redefined in constructor.
+
+ /**
+ * Default strength of a DRBG instance if it is not configured.
+ * 128 is considered secure enough now. A mechanism
+ * can change it in a constructor.
+ *
+ * The default here is described in comments of the "drbg" security property.
+ */
+ protected static final int defaultStrength = 128;
+
+ /**
+ * Mechanism name, say, {@code HashDRBG}. Must be set in constructor.
+ * This value will be used in {@code toString}.
+ */
+ protected String mechName = "DRBG";
+
+ /**
+ * highest_supported_security_strength of this mechanism for all algorithms
+ * it supports. A mechanism should update the value in its constructor
+ * if the value is not 256.
+ */
+ protected int highestSecurity = 256;
+
+ /**
+ * Whether prediction resistance is supported. A mechanism should update
+ * the value in its constructor if it is <em>not</em> supported.
+ */
+ protected boolean supportPr = true;
+
+ /**
+ * Whether reseed is supported. A mechanism should update
+ * the value in its constructor if it is <em>not</em> supported.
+ */
+ protected boolean supportReseed = true;
+
+ // Strength features. If not same as below, must be redefined in
+ // chooseAlgorithmAndStrength. Among these, minLength and seedLen have no
+ // default value and must be redefined. If personalization string or
+ // additional input is not supported, set maxPsLength or
+ // maxAiLength to -1.
+
+ /**
+ * Minimum entropy input length in bytes for this DRBG instance.
+ * Must be assigned in {@link #chooseAlgorithmAndStrength}.
+ */
+ protected int minLength;
+
+ /**
+ * Maximum entropy input length in bytes for this DRBG instance.
+ * Should be assigned in {@link #chooseAlgorithmAndStrength} if it is not
+ * {@link Integer#MAX_VALUE}.
+ */
+ protected int maxLength = Integer.MAX_VALUE;
+
+ /**
+ * Maximum personalization string length in bytes for this DRBG instance.
+ * Should be assigned in {@link #chooseAlgorithmAndStrength} if it is not
+ * {@link Integer#MAX_VALUE}.
+ */
+ protected int maxPsLength = Integer.MAX_VALUE;
+
+ /**
+ * Maximum additional input length in bytes for this DRBG instance.
+ * Should be assigned in {@link #chooseAlgorithmAndStrength} if it is not
+ * {@link Integer#MAX_VALUE}.
+ */
+ protected int maxAiLength = Integer.MAX_VALUE;
+
+ /**
+ * max_number_of_bits_per_request in bytes for this DRBG instance.
+ * Should be assigned in {@link #chooseAlgorithmAndStrength} if it is not
+ * {@link Integer#MAX_VALUE}.
+ */
+ protected int maxNbLength = Integer.MAX_VALUE;
+
+ /**
+ * Maximum number of requests between reseeds for this DRBG instance.
+ * Should be assigned in {@link #chooseAlgorithmAndStrength} if it is not
+ * {@link Integer#MAX_VALUE}.
+ */
+ protected int reseedInterval = Integer.MAX_VALUE;
+
+
+ /**
+ * Algorithm used by this instance (SHA-512 or AES-256). Must be assigned
+ * in {@link #chooseAlgorithmAndStrength}. This field is used in
+ * {@link #toString()}.
+ */
+ protected String algorithm;
+
+ // Configurable parameters
+
+ /**
+ * Security strength for this instance. Must be assigned in
+ * {@link #chooseAlgorithmAndStrength}. Should be at least the requested
+ * strength. Might be smaller than the highest strength
+ * {@link #algorithm} supports. Must not be -1.
+ */
+ protected int strength; // in bits
+
+ /**
+ * Strength requested in {@link DrbgParameters.Instantiate}.
+ * The real strength is based on it. Do not modify it in a mechanism.
+ */
+ protected int requestedStrength = -1;
+
+ /**
+ * The personalization string used by this instance. Set inside
+ * {@link #engineConfigure(SecureRandomInstantiateParameters)} and
+ * can be used in a mechanism. Do not modify it in a mechanism.
+ */
+ protected byte[] ps;
+
+ /**
+ * The prediction resistance flag used by this instance. Set inside
+ * {@link #engineConfigure(SecureRandomInstantiateParameters)}.
+ */
+ private boolean isPr;
+
+ // Non-standard configurable parameters
+
+ /**
+ * Whether a derivation function is used. Requested in
+ * {@link MoreDrbgParameters}. Only CtrDRBG uses it.
+ * Do not modify it in a mechanism.
+ */
+ protected boolean usedf;
+
+ /**
+ * The nonce for this instance. Set in {@link #instantiateIfNecessary}.
+ * After instantiation, this field is not null. Do not modify it
+ * in a mechanism.
+ */
+ protected byte[] nonce;
+
+ /**
+ * Requested nonce in {@link MoreDrbgParameters}. If set to null,
+ * nonce will be chosen by system, and a reinstantiated DRBG will get a
+ * new system-provided nonce.
+ */
+ private byte[] requestedNonce;
+
+ /**
+ * Requested algorithm in {@link MoreDrbgParameters}.
+ * Do not modify it in a mechanism.
+ */
+ protected String requestedAlgorithm;
+
+ /**
+ * The prediction resistance flag used by this instance. Set inside
+ * {@link #engineConfigure(SecureRandomInstantiateParameters)}. This field
+ * can be null. {@link #getEntropyInput} will take care of null check.
+ */
+ private transient EntropySource es;
+
+ // Five abstract methods for SP 800-90A DRBG
+
+ /**
+ * Decides what algorithm and strength to use (SHA-256 or AES-256,
+ * 128 or 256). Strength related fields must also be defined or redefined
+ * here. Called in {@link #engineConfigure}. A mechanism uses
+ * {@link #requestedAlgorithm}, {@link #requestedStrength}, and
+ * {@link #defaultStrength} to decide which algorithm and strength to use.
+ * <p>
+ * If {@code requestedAlgorithm} is provided, it will always be used.
+ * If {@code requestedStrength} is also provided, the algorithm will use
+ * the strength (an exception will be thrown if the strength is not
+ * supported), otherwise, the smaller one of the highest supported strength
+ * of the algorithm and the default strength will be used.
+ * <p>
+ * If {@code requestedAlgorithm} is not provided, an algorithm will be
+ * chosen that supports {@code requestedStrength}
+ * (or {@code defaultStrength} if there is no request).
+ * <p>
+ * Since every call to {@link #engineConfigure} will call this method,
+ * make sure to the calls do not contradict with each other.
+ * <p>
+ * Here are some examples of the algorithm and strength chosen (suppose
+ * {@code defaultStrength} is 128) for HashDRBG:
+ * <pre>
+ * (requestedAlg,requestedStrength) Algorithm Strength
+ * (SHA-1, -1) SHA-1 128
+ * (SHA-1, 112) SHA-1 112
+ * (SHA-1, 192) error error
+ * (SHA-256, -1) SHA-256 128
+ * (SHA-256, 128) SHA-256 128
+ * (SHA-3, -1) error error
+ * (null, -1) SHA-256 128
+ * (null, 112) SHA-256 112
+ * (null, 192) SHA-256 192
+ * (null, 256) SHA-256 256
+ * (null, 384) error error
+ * </pre>
+ *
+ * @throws IllegalArgumentException if the requested parameters
+ * can not be supported or contradict with each other.
+ */
+ protected abstract void chooseAlgorithmAndStrength();
+
+ /**
+ * Initiates security engines ({@code MessageDigest}, {@code Mac},
+ * or {@code Cipher}). Must be called in deserialization. Please note
+ * that before instantiation the algorithm might not be available yet.
+ * In this case, just return and this method will be called
+ * automatically at instantiation.
+ */
+ protected abstract void initEngine();
+
+ /**
+ * Instantiates a DRBG. Called automatically before the first
+ * {@code nextBytes} call.
+ * <p>
+ * Note that the other parameters (nonce, strength, ps) are already
+ * stored inside at configuration.
+ *
+ * @param ei the entropy input, its length is already conditioned to be
+ * between {@link #minLength} and {@link #maxLength}.
+ */
+ protected abstract void instantiateAlgorithm(byte[] ei);
+
+ /**
+ * The generate function.
+ *
+ * @param result fill result here, not null
+ * @param additionalInput additional input, can be null. If not null,
+ * its length is smaller than {@link #maxAiLength}
+ */
+ protected abstract void generateAlgorithm(
+ byte[] result, byte[] additionalInput);
+
+ /**
+ * The reseed function.
+ *
+ * @param ei the entropy input, its length is already conditioned to be
+ * between {@link #minLength} and {@link #maxLength}.
+ * @param additionalInput additional input, can be null. If not null,
+ * its length is smaller than {@link #maxAiLength}
+ * @throws UnsupportedOperationException if reseed is not supported
+ */
+ protected void reseedAlgorithm(
+ byte[] ei, byte[] additionalInput) {
+ throw new UnsupportedOperationException("No reseed function");
+ }
+
+ // SecureRandomSpi methods taken care of here. All final.
+
+ @Override
+ protected final void engineNextBytes(byte[] result) {
+ engineNextBytes(result, DrbgParameters.nextBytes(-1, isPr, null));
+ }
+
+ @Override
+ protected final void engineNextBytes(
+ byte[] result, SecureRandomNextBytesParameters params) {
+ if (debug != null) {
+ debug.println("nextBytes");
+ }
+ if (params instanceof DrbgParameters.NextBytes) {
+ DrbgParameters.NextBytes dp = (DrbgParameters.NextBytes) params;
+ if (!isPr && dp.getPredictionResistance()) {
+ throw new IllegalArgumentException("pr not available");
+ }
+ if (dp.getStrength() > strength) {
+ throw new IllegalArgumentException("strength too high");
+ }
+ if (result.length > maxNbLength) {
+ throw new IllegalArgumentException("result too long");
+ }
+ byte[] ai = dp.getAdditionalInput();
+ if (dp.getAdditionalInput() != null && dp.getAdditionalInput().length > maxAiLength) {
+ throw new IllegalArgumentException("ai too long");
+ }
+ instantiateIfNecessary(null);
+ if (reseedCounter > reseedInterval || dp.getPredictionResistance()) {
+ reseedAlgorithm(getEntropyInput(dp.getPredictionResistance()), ai);
+ ai = null;
+ }
+ generateAlgorithm(result, ai);
+ } else {
+ throw new IllegalArgumentException("unknown params type");
+ }
+ }
+
+ @Override
+ public final void engineReseed(SecureRandomReseedParameters params) {
+ if (debug != null) {
+ debug.println("reseed with params");
+ }
+ if (!supportReseed) {
+ throw new UnsupportedOperationException("Reseed not supported");
+ }
+ if (params == null) {
+ params = DrbgParameters.reseed(isPr, null);
+ }
+ if (params instanceof DrbgParameters.Reseed) {
+ DrbgParameters.Reseed dp = (DrbgParameters.Reseed) params;
+ if (!isPr && dp.getPredictionResistance()) {
+ throw new IllegalArgumentException("pr not available");
+ }
+ if (dp.getAdditionalInput() != null && dp.getAdditionalInput().length > maxAiLength) {
+ throw new IllegalArgumentException("ai too long");
+ }
+ instantiateIfNecessary(null);
+ reseedAlgorithm(getEntropyInput(dp.getPredictionResistance()),
+ dp.getAdditionalInput());
+ } else {
+ throw new IllegalArgumentException("unknown params type");
+ }
+ }
+
+ /**
+ * Returns the given number of seed bytes. A DRBG always uses its
+ * {@code EntropySource} to get an array with full-entropy.
+ *
+ * @param numBytes the number of seed bytes to generate.
+ * @return the seed bytes.
+ */
+ @Override
+ public final synchronized byte[] engineGenerateSeed(int numBytes) {
+ return getEntropyInput(numBytes, numBytes, numBytes, isPr);
+ }
+
+ /**
+ * Reseeds this random object with the given seed. A DRBG always expands
+ * or truncates the input to be between {@link #minLength} and
+ * {@link #maxLength} and uses it to instantiate or reseed itself
+ * (depending on whether the DRBG is instantiated).
+ *
+ * @param input the seed
+ */
+ @Override
+ public final synchronized void engineSetSeed(byte[] input) {
+ // TODO: Will truncate be insecure? hashDF?
+ if (debug != null) {
+ debug.println("setSeed");
+ }
+ if (input.length < minLength) {
+ input = Arrays.copyOf(input, minLength);
+ } else if (input.length > maxLength) {
+ input = Arrays.copyOf(input, maxLength);
+ }
+ if (!instantiated) {
+ instantiateIfNecessary(input);
+ } else {
+ reseedAlgorithm(input, null);
+ }
+ }
+
+ // get_entropy_input
+
+ private byte[] getEntropyInput(boolean isPr) {
+ // Should the 1st arg be strength or minLength?
+ //
+ // Precisely I think it should be strength, but CtrDRBG
+ // (not using derivation function) is so confusing
+ // (does it need only strength or seedlen of entropy?)
+ // that maybe it's safer to assume minLength.
+ return getEntropyInput(minLength, minLength, maxLength, isPr);
+ }
+
+ private byte[] getEntropyInput(int security, int min, int max, boolean pr) {
+ if (debug != null) {
+ debug.println("getEntropy(" + security + "," + min + "," + max
+ + "," + pr + ")");
+ }
+ EntropySource esNow = es;
+ if (esNow == null) {
+ esNow = pr? SeederHolder.prseeder: SeederHolder.seeder;
+ }
+ return esNow.getEntropy(security, min, max, pr);
+ }
+
+ // Defaults
+
+ /**
+ * The default {@code EntropySource} determined by system property
+ * "java.security.egd" or security property "securerandom.source".
+ * <p>
+ * This object uses {@link SeedGenerator#generateSeed(byte[])} to
+ * return a byte array containing {@code minLength} bytes. It is
+ * assumed to support prediction resistance and always contains
+ * full-entropy. A trusted application can update this field.
+ */
+ public static EntropySource defaultES = (entropy, minLen, maxLen, pr) -> {
+ byte[] result = new byte[minLen];
+ SeedGenerator.generateSeed(result);
+ return result;
+ };
+
+ private static class SeederHolder {
+
+ /**
+ * Default EntropySource for SecureRandom with prediction resistance,
+ */
+ static final EntropySource prseeder;
+
+ /**
+ * Default EntropySource for SecureRandom without prediction resistance,
+ * which is backed by a DRBG whose EntropySource is {@link #prseeder}.
+ */
+ static final EntropySource seeder;
+
+ static {
+ prseeder = defaultES;
+ HashDrbg drbg = new HashDrbg(null);
+ // According to SP800-90C section 7, a DRBG without live
+ // entropy (drbg here, with pr being false) can instantiate
+ // another DRBG with weaker strength. So we choose highest
+ // strength we support.
+ drbg.engineConfigure(new MoreDrbgParameters(
+ prseeder, null, null, null, false,
+ DrbgParameters.instantiate(
+ 256, NONE,
+ SeedGenerator.getSystemEntropy())));
+ seeder = (entropy, minLen, maxLen, pr) -> {
+ if (pr) {
+ // This SEI does not support pr
+ throw new IllegalArgumentException();
+ }
+ byte[] result = new byte[minLen];
+ drbg.engineNextBytes(result);
+ return result;
+ };
+ }
+ }
+
+ // Constructor called by overridden methods, initializer...
+
+ /**
+ * A constructor without argument so that an implementation does not
+ * need to always write {@code super(params)}.
+ */
+ protected AbstractDrbg() {
+ // Nothing
+ }
+
+ /**
+ * A mechanism shall override this constructor to setup {@link #mechName},
+ * {@link #highestSecurity}, {@link #supportPr}, {@link #supportReseed}
+ * or other features like {@link #defaultStrength}. Finally it shall
+ * call {@link #configureInternal} on {@code params}.
+ *
+ * @param params the {@link SecureRandomInstantiateParameters} object.
+ * This argument can be {@code null}.
+ * @throws IllegalArgumentException if {@code params} is
+ * inappropriate for this SecureRandom.
+ */
+ protected AbstractDrbg(SecureRandomInstantiateParameters params) {
+ // Nothing
+ }
+
+ protected void register(Map<Object, Object> map) {
+ String name = "SecureRandom." + mechName;
+ map.put(name, this.getClass().getName());
+ map.put(name + " ImplementedIn", "Software");
+ map.put(name + " DRBG.supportPr", Boolean.toString(supportPr));
+ map.put(name + " DRBG.highestSecurity", Integer.toString(highestSecurity));
+ map.put(name + " DRBG.supportReseed", Boolean.toString(supportReseed));
+ map.put(name + " DRBG.defaultStrength", Integer.toString(defaultStrength));
+ }
+
+ /**
+ * Returns the current configuration as a {@link DrbgParameters.Instantiate}
+ * object.
+ *
+ * @return the curent configuration
+ */
+ @Override
+ protected SecureRandomInstantiateParameters engineGetParameters() {
+ // Or read from variable.
+ return DrbgParameters.instantiate(
+ strength,
+ isPr? PR_AND_RESEED: (supportReseed? RESEED_ONLY: NONE),
+ ps);
+ }
+
+ /**
+ * A helper function that calls {@link #engineConfigure}.
+ *
+ * @param params if null, default configuration (default strength,
+ * pr_false, no personalization string) will be used.
+ * @throws IllegalArgumentException if {@code params} is
+ * inappropriate for this SecureRandom.
+ */
+ protected void configureInternal(SecureRandomInstantiateParameters params) {
+ if (params == null) {
+ params = DrbgParameters.instantiate(-1, RESEED_ONLY, null);
+ }
+ engineConfigure(params);
+ }
+
+ /**
+ * Configure this DRBG. This method calls {@link #chooseAlgorithmAndStrength()}
+ * and {@link #initEngine()} but does not do the actual instantiation.
+ *
+ * @param params configuration, cannot be null
+ * @throws IllegalArgumentException if {@code params} is
+ * inappropriate for this SecureRandom.
+ */
+ //@Override
+ protected final synchronized void engineConfigure(
+ SecureRandomInstantiateParameters params) {
+ if (debug != null) {
+ debug.println("configure " + this + " with " + params);
+ }
+ if (params instanceof MoreDrbgParameters) {
+ MoreDrbgParameters m = (MoreDrbgParameters)params;
+ this.requestedNonce = m.nonce;
+ this.es = m.es;
+ this.requestedAlgorithm = m.algorithm;
+ this.usedf = m.usedf;
+ params = m.config;
+ }
+ if (params != null) {
+ if (params instanceof DrbgParameters.Instantiate) {
+ DrbgParameters.Instantiate config = (DrbgParameters.Instantiate) params;
+ if (config.getStrength() > highestSecurity) {
+ throw new IllegalArgumentException("strength too big");
+ }
+ if (config.getPersonalizationString() != null && config.getPersonalizationString().length > maxPsLength) {
+ throw new IllegalArgumentException("ps too long");
+ }
+ if ((config.getCapability() == PR_AND_RESEED)
+ && !supportPr) {
+ throw new IllegalArgumentException("pr not supported");
+ }
+ if ((config.getCapability() == PR_AND_RESEED || config.getCapability() == RESEED_ONLY)
+ && !supportReseed) {
+ throw new IllegalArgumentException("reseed not supported");
+ }
+ this.ps = config.getPersonalizationString();
+ this.isPr = config.getCapability() == PR_AND_RESEED;
+ this.requestedStrength = config.getStrength();
+ } else {
+ throw new IllegalArgumentException("unknown params");
+ }
+ }
+ chooseAlgorithmAndStrength();
+ instantiated = false;
+ if (debug != null) {
+ debug.println("configured " + this);
+ }
+ }
+
+ /**
+ * Instantiate if necessary,
+ *
+ * @param entropy a user-provided entropy, the length is already good.
+ * If null, will fetch entropy input automatically.
+ */
+ private synchronized void instantiateIfNecessary(byte[] entropy) {
+ if (!instantiated) {
+ if (debug != null) {
+ debug.println("instantiate");
+ }
+ if (strength <= 0) { // not configured at all
+ chooseAlgorithmAndStrength();
+ }
+ // 1-4. strength/ps/pr check
+ // 5. Null
+ // 6/7. Get entropy. TODO: 1st arg security strength?
+ if (entropy == null) {
+ entropy = getEntropyInput(isPr);
+ }
+ // 8. nonce
+ if (requestedNonce != null) {
+ nonce = requestedNonce;
+ } else {
+ nonce = longToByteArray(cc.incrementAndGet());
+ }
+ // 9. instantiate
+ initEngine();
+ instantiateAlgorithm(entropy);
+ instantiated = true;
+ }
+ }
+
+ // Nonce provider
+
+ /**
+ * Helper function to convert a long into a byte array (least significant
+ * byte first).
+ */
+ private static byte[] longToByteArray(long l) {
+ byte[] retVal = new byte[16];
+ retVal[0] = 's';
+ retVal[1] = 'u';
+ retVal[2] = 'n';
+ retVal[3] = '.';
+ retVal[4] = 'd';
+ retVal[5] = 'r';
+ retVal[6] = 'b';
+ retVal[7] = 'g';
+ for (int i = 0; i < 8; i++) {
+ retVal[i+8] = (byte) l;
+ l >>= 8;
+ }
+ return retVal;
+ }
+
+ private static AtomicLong cc = new AtomicLong(0);
+
+ // Misc
+
+ /** A handy method returning hexdump string with no colon or new line.
+ *
+ * @param in input byte array
+ * @return the hexdump string
+ */
+ protected static String hex(byte[] in) {
+ StringBuilder sb = new StringBuilder();
+ for (byte b: in) {
+ sb.append(String.format("%02x", b&0xff));
+ }
+ return sb.toString();
+ }
+
+ /**
+ * Returns the smallest standard strength (112, 128, 192, 256) that is
+ * greater or equal to the input.
+ *
+ * @param input the input strength
+ * @return the standard strength
+ */
+ protected static int getStandardStrength(int input) {
+ if (input <= 112) return 112;
+ if (input <= 128) return 128;
+ if (input <= 192) return 192;
+ if (input <= 256) return 256;
+ throw new IllegalArgumentException("input too big: " + input);
+ }
+
+ @Override
+ public String toString() {
+ return mechName + "," + algorithm
+ + "," + strength + ","
+ + (isPr?"pr_and_reseed":(supportReseed?"reseed_only":"none"));
+ }
+}
--- /dev/null 2016-04-01 19:18:02.000000000 +0800
+++ new/src/java.base/share/classes/sun/security/provider/AbstractHashDrbg.java 2016-04-01 19:18:02.000000000 +0800
@@ -0,0 +1,144 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code 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
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package sun.security.provider;
+
+import sun.security.util.HexDumpEncoder;
+
+import java.util.Arrays;
+import java.util.Locale;
+
+public abstract class AbstractHashDrbg extends AbstractDrbg {
+
+ private static final long serialVersionUID = 9L;
+
+ protected int outLen;
+ protected int seedLen;
+
+ private static int alg2strength(String algorithm) {
+ switch (algorithm.toUpperCase(Locale.ROOT)) {
+ case "SHA-1":
+ return 128;
+ case "SHA-224":
+ case "SHA-512/224":
+ return 192;
+ case "SHA-256":
+ case "SHA-512/256":
+ case "SHA-384":
+ case "SHA-512":
+ return 256;
+ default:
+ throw new IllegalArgumentException(algorithm +
+ " not supported in Hash_DBRG");
+ }
+ }
+
+ protected void chooseAlgorithmAndStrength() {
+ if (requestedAlgorithm != null) {
+ algorithm = requestedAlgorithm.toUpperCase(Locale.ROOT);
+ int supportedStrength = alg2strength(algorithm);
+ if (requestedStrength >= 0) {
+ int tryStrength = getStandardStrength(requestedStrength);
+ if (tryStrength > supportedStrength) {
+ throw new IllegalArgumentException(
+ algorithm + " does not support strength " + requestedStrength);
+ }
+ this.strength = tryStrength;
+ } else {
+ this.strength = defaultStrength > supportedStrength?
+ supportedStrength: defaultStrength;
+ }
+ } else {
+ int tryStrength =
+ requestedStrength<0? defaultStrength: requestedStrength;
+ tryStrength = getStandardStrength(tryStrength);
+ // The default algorithm which is enough for all strengths.
+ // Also described in comments of the "drbg" security property.
+ algorithm = "SHA-256";
+ this.strength = tryStrength;
+ }
+ switch (algorithm.toUpperCase(Locale.ROOT)) {
+ case "SHA-1":
+ this.seedLen = 440/8;
+ this.outLen = 160/8;
+ break;
+ case "SHA-224":
+ case "SHA-512/224":
+ this.seedLen = 440/8;
+ this.outLen = 224/8;
+ break;
+ case "SHA-256":
+ case "SHA-512/256":
+ this.seedLen = 440/8;
+ this.outLen = 256/8;
+ break;
+ case "SHA-384":
+ this.seedLen = 888/8;
+ this.outLen = 384/8;
+ break;
+ case "SHA-512":
+ this.seedLen = 888/8;
+ this.outLen = 512/8;
+ break;
+ default:
+ throw new IllegalArgumentException(algorithm +
+ " not supported in Hash_DBRG");
+ }
+ this.minLength = this.strength/8;
+ }
+
+ @Override
+ public void instantiateAlgorithm(byte[] entropy) {
+ byte[] seed = Arrays.copyOf(entropy, entropy.length + nonce.length +
+ (ps == null? 0: ps.length));
+ System.arraycopy(nonce, 0, seed, entropy.length, nonce.length);
+ if (ps != null) {
+ System.arraycopy(ps, 0, seed, entropy.length + nonce.length,
+ ps.length);
+ }
+ hashReseedInternal(seed);
+ }
+
+ @Override
+ protected void reseedAlgorithm(
+ byte[] ei,
+ byte[] additionalInput) {
+ if (debug != null) {
+ debug.println("reseedAlgorithm");
+ debug.println(new HexDumpEncoder().encodeBuffer(ei));
+ if (additionalInput != null) {
+ debug.println(new HexDumpEncoder().encodeBuffer(additionalInput));
+ }
+ }
+ if (additionalInput != null) {
+ ei = Arrays.copyOf(ei, ei.length + additionalInput.length);
+ System.arraycopy(additionalInput, 0, ei,
+ ei.length - additionalInput.length, additionalInput.length);
+ }
+ hashReseedInternal(ei);
+ }
+
+ protected abstract void hashReseedInternal(byte[] seed);
+}
--- /dev/null 2016-04-01 19:18:04.000000000 +0800
+++ new/src/java.base/share/classes/sun/security/provider/CtrDrbg.java 2016-04-01 19:18:03.000000000 +0800
@@ -0,0 +1,460 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code 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
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package sun.security.provider;
+
+import javax.crypto.Cipher;
+import javax.crypto.NoSuchPaddingException;
+import javax.crypto.SecretKey;
+import javax.crypto.spec.SecretKeySpec;
+import java.io.IOException;
+import java.security.*;
+import java.util.Arrays;
+import java.util.Locale;
+
+public class CtrDrbg extends AbstractDrbg {
+
+ private static final long serialVersionUID = 9L;
+ static final int aesLimit;
+
+ static {
+ try {
+ aesLimit = Cipher.getMaxAllowedKeyLength("AES");
+ } catch (Exception e) {
+ // should not happen
+ throw new AssertionError("Cannot detect AES");
+ }
+ }
+
+ private transient Cipher cipher;
+
+ private String cipherAlg;
+ protected String keyAlg;
+
+ private int ctrLen;
+ private int blockLen;
+ private int keyLen;
+ private int seedLen;
+
+ private byte[] v;
+ private byte[] k;
+
+ public CtrDrbg(SecureRandomInstantiateParameters params) {
+ mechName = "CTR_DRBG";
+ configureInternal(params);
+ }
+
+ private static int alg2strength(String algorithm) {
+ switch (algorithm.toUpperCase(Locale.ROOT)) {
+ case "TDEA":
+ case "3KEYTDEA":
+ case "3 KEY TDEA":
+ case "DESEDE":
+ return 112;
+ case "AES-128":
+ return 128;
+ case "AES-192":
+ return 192;
+ case "AES-256":
+ return 256;
+ default:
+ throw new IllegalArgumentException(algorithm +
+ " not supported in CTR_DBRG");
+ }
+ }
+
+ protected void chooseAlgorithmAndStrength() {
+ if (requestedAlgorithm != null) {
+ algorithm = requestedAlgorithm.toUpperCase();
+ int supportedStrength = alg2strength(algorithm);
+ if (requestedStrength >= 0) {
+ int tryStrength = getStandardStrength(requestedStrength);
+ if (tryStrength > supportedStrength) {
+ throw new IllegalArgumentException(
+ algorithm + " does not support strength " + requestedStrength);
+ }
+ this.strength = tryStrength;
+ } else {
+ this.strength = defaultStrength > supportedStrength?
+ supportedStrength: defaultStrength;
+ }
+ } else {
+ int tryStrength =
+ requestedStrength<0? defaultStrength: requestedStrength;
+ tryStrength = getStandardStrength(tryStrength);
+ // Default algorithm, use AES-128 if AES-256 is not available
+ // Also described in comments of the "drbg" security property.
+ if (tryStrength <= 128 && aesLimit < 256) {
+ algorithm = "AES-128";
+ } else if (aesLimit >= 256) {
+ algorithm = "AES-256";
+ } else {
+ throw new IllegalArgumentException(
+ "unsupported strength " + requestedStrength);
+ }
+ this.strength = tryStrength;
+ }
+ switch (algorithm.toUpperCase(Locale.ROOT)) {
+ case "TDEA":
+ case "3KEYTDEA":
+ case "3 KEY TDEA":
+ case "DESEDE":
+ algorithm = "DESede";
+ this.keyAlg = "DESede";
+ this.cipherAlg = "DESede/ECB/NoPadding";
+ this.blockLen = 64/8;
+ this.keyLen = 168/8;
+ break;
+ case "AES-128":
+ case "AES-192":
+ case "AES-256":
+ this.keyAlg = "AES";
+ this.cipherAlg = "AES/ECB/NoPadding";
+ switch (algorithm) {
+ case "AES-128":
+ this.keyLen = 128/8;
+ break;
+ case "AES-192":
+ this.keyLen = 192/8;
+ if (aesLimit < 192) {
+ throw new IllegalArgumentException(algorithm +
+ " not supported in CTR_DBRG");
+ }
+ break;
+ case "AES-256":
+ this.keyLen = 256/8;
+ if (aesLimit < 256) {
+ throw new IllegalArgumentException(algorithm +
+ " not supported in CTR_DBRG");
+ }
+ break;
+ default:
+ throw new IllegalArgumentException(algorithm +
+ " not supported in CTR_DBRG");
+ }
+ this.blockLen = 128/8;
+ break;
+ default:
+ throw new IllegalArgumentException(algorithm +
+ " not supported in CTR_DBRG");
+ }
+ this.seedLen = this.blockLen + this.keyLen;
+ this.ctrLen = this.blockLen; // TODO
+ if (usedf) {
+ this.minLength = this.strength / 8;
+ } else {
+ this.minLength = this.maxLength =
+ this.maxPsLength = this.maxAiLength = seedLen;
+ }
+ }
+
+ /**
+ * This call, used by the constructors, instantiates the digest.
+ */
+ @Override
+ protected void initEngine() {
+ if (cipherAlg == null) {
+ return;
+ }
+ try {
+ /*
+ * Use the local SUN implementation to avoid native
+ * performance overhead.
+ */
+ cipher = Cipher.getInstance(cipherAlg, "SunJCE");
+ } catch (NoSuchProviderException | NoSuchAlgorithmException
+ | NoSuchPaddingException e) {
+ // Fallback to any available.
+ try {
+ cipher = Cipher.getInstance(cipherAlg);
+ } catch (NoSuchAlgorithmException | NoSuchPaddingException exc) {
+ throw new InternalError(
+ "internal error: " + cipherAlg + " not available.", exc);
+ }
+ }
+ }
+
+ private void status() {
+ if (debug != null) {
+ debug.println("Key = " + hex(k));
+ debug.println("V = " + hex(v));
+ debug.println("reseed counter = " + reseedCounter);
+ }
+ }
+
+ private void update(byte[] input) {
+ if (input.length != seedLen) {
+ // Should not happen
+ throw new IllegalArgumentException("input must be of seedlen bytes");
+ }
+ try {
+ int m = (seedLen + blockLen - 1) / blockLen;
+ byte[] temp = new byte[m * blockLen];
+ for (int i = 0; i < m; i++) {
+ if (ctrLen < blockLen) {
+ byte[] inc = addBytes(ctrLen, v, new byte[]{1});
+ System.arraycopy(inc, 0, v, blockLen - ctrLen, ctrLen);
+ } else {
+ v = addBytes(blockLen, v, new byte[]{1});
+ }
+ cipher.init(Cipher.ENCRYPT_MODE, getKey(keyAlg, k));
+ cipher.doFinal(v, 0, blockLen, temp, i * blockLen);
+ }
+ temp = Arrays.copyOf(temp, seedLen);
+ for (int i=0; i<seedLen; i++) {
+ temp[i] ^= input[i];
+ }
+ k = Arrays.copyOf(temp, keyLen);
+ v = Arrays.copyOfRange(temp, seedLen-blockLen, seedLen);
+ } catch (GeneralSecurityException e) {
+ throw new InternalError(e);
+ }
+ }
+
+ @Override
+ protected void instantiateAlgorithm(byte[] ei) {
+ byte[] more;
+ if (usedf) {
+ if (ps == null) {
+ more = nonce;
+ } else {
+ more = Arrays.copyOf(nonce, nonce.length + ps.length);
+ System.arraycopy(ps, 0, more, nonce.length, ps.length);
+ }
+ } else {
+ more = ps;
+ }
+ reseedAlgorithm(ei, more);
+ }
+
+ private byte[] df(byte[] input) {
+ int l = input.length;
+ int n = seedLen;
+ int slen = 4 + 4 + l + 1;
+ byte[] s = new byte[(slen + blockLen - 1) / blockLen * blockLen];
+ s[0] = (byte)(l >> 24);
+ s[1] = (byte)(l >> 16);
+ s[2] = (byte)(l >> 8);
+ s[3] = (byte)(l);
+ s[4] = (byte)(n >> 24);
+ s[5] = (byte)(n >> 16);
+ s[6] = (byte)(n >> 8);
+ s[7] = (byte)(n);
+ System.arraycopy(input, 0, s, 8, l);
+ s[8+l] = (byte)0x80;
+
+ byte[] k = new byte[keyLen];
+ for (int i=0; i<k.length; i++) {
+ k[i] = (byte)i;
+ }
+
+ byte[] temp = new byte[seedLen];
+
+ for (int i=0; i*blockLen < temp.length; i++) {
+ byte[] iv = new byte[blockLen + s.length];
+ iv[0] = (byte)(i >> 24);
+ iv[1] = (byte)(i >> 16);
+ iv[2] = (byte)(i >> 8);
+ iv[3] = (byte)(i);
+ System.arraycopy(s, 0, iv, blockLen, s.length);
+ int tailLen = temp.length - blockLen*i;
+ if (tailLen > blockLen) tailLen = blockLen;
+ System.arraycopy(bcc(k, iv), 0, temp, blockLen*i, tailLen);
+ }
+
+ k = Arrays.copyOf(temp, keyLen);
+ byte[] x = Arrays.copyOfRange(temp, keyLen, temp.length);
+
+ for (int i=0; i*blockLen < seedLen; i++) {
+ try {
+ cipher.init(Cipher.ENCRYPT_MODE, getKey(keyAlg, k));
+ int tailLen = temp.length - blockLen*i;
+ if (tailLen > blockLen) tailLen = blockLen;
+ x = cipher.doFinal(x);
+ System.arraycopy(x, 0, temp, blockLen * i, tailLen);
+ } catch (GeneralSecurityException e) {
+ throw new InternalError(e);
+ }
+ }
+ return temp;
+ }
+
+ private byte[] bcc(byte[] k, byte[] data) {
+ byte[] chain = new byte[blockLen];
+ int n = data.length / blockLen;
+ for (int i=0; i<n; i++) {
+ byte[] inputBlock = Arrays.copyOfRange(
+ data, i*blockLen, i*blockLen+blockLen);
+ for (int j=0; j<blockLen; j++) {
+ inputBlock[j] ^= chain[j];
+ }
+ try {
+ cipher.init(Cipher.ENCRYPT_MODE, getKey(keyAlg, k));
+ chain = cipher.doFinal(inputBlock);
+ } catch (GeneralSecurityException e) {
+ throw new InternalError(e);
+ }
+ }
+ return chain;
+ }
+
+ @Override
+ protected void reseedAlgorithm(
+ byte[] ei,
+ byte[] additionalInput) {
+ if (usedf) {
+ if (additionalInput != null) {
+ byte[] temp = Arrays.copyOf(
+ ei, ei.length + additionalInput.length);
+ System.arraycopy(additionalInput, 0, temp, ei.length, additionalInput.length);
+ ei = temp;
+ }
+ ei = df(ei);
+ } else {
+ if (additionalInput != null) {
+ for (int i = 0; i < seedLen && i < additionalInput.length; i++) {
+ ei[i] ^= additionalInput[i];
+ }
+ }
+ }
+
+ // Also called by instantiateAlgorithm.
+ if (v == null) {
+ k = new byte[keyLen];
+ v = new byte[blockLen];
+ }
+ status();
+ update(ei);
+ reseedCounter = 1;
+ status();
+ }
+
+ private static byte[] addBytes(int len, byte[]... data) {
+ byte[] out = new byte[len];
+ for (byte[] d: data) {
+ int dlen = d.length;
+ int carry = 0;
+ for (int i=0; i<len; i++) {
+ int sum = (out[len-i-1] & 0xff) + carry;
+ if (i < dlen) {
+ sum += (d[dlen - i - 1] & 0xff);
+ }
+ out[len - i - 1] = (byte) sum;
+ carry = sum >> 8;
+ if (i >= dlen && carry == 0) break;
+ }
+ }
+ return out;
+ }
+
+ @Override
+ public synchronized void generateAlgorithm(
+ byte[] result, byte[] additionalInput) {
+
+ if (additionalInput != null) {
+ if (usedf) {
+ additionalInput = df(additionalInput);
+ } else {
+ additionalInput = Arrays.copyOf(additionalInput, seedLen);
+ }
+ update(additionalInput);
+ }
+
+ // Step 3.
+ int pos = 0;
+
+ // Step 4.
+ while (pos < result.length) {
+ int tailLen = result.length - pos;
+ // Step 4.1.
+ if (ctrLen < blockLen) {
+ byte[] inc = addBytes(ctrLen, v, new byte[]{1});
+ System.arraycopy(inc, 0, v, blockLen - ctrLen, ctrLen);
+ } else {
+ v = addBytes(blockLen, v, new byte[]{1});
+ }
+ try {
+ // Step 4.2.
+ cipher.init(Cipher.ENCRYPT_MODE, getKey(keyAlg, k));
+ byte[] out = cipher.doFinal(v);
+
+ // Step 4.3 and 5.
+ System.arraycopy(out, 0, result, pos,
+ tailLen > blockLen ? blockLen: tailLen);
+ } catch (GeneralSecurityException e) {
+ throw new InternalError(e);
+ }
+ pos += blockLen;
+ }
+
+ // Step 6.
+ update(additionalInput != null? additionalInput: new byte[seedLen]);
+
+ // Step 7.
+ reseedCounter++;
+
+ status();
+ }
+
+ private static void des7to8(byte[] key56, int off56, byte[] key64, int off64) {
+ key64[off64+0] = (byte) (key56[off56+0] & 0xFE); // << 0
+ key64[off64+1] = (byte) ((key56[off56+0] << 7) | ((key56[off56+1] & 0xFF) >>> 1));
+ key64[off64+2] = (byte) ((key56[off56+1] << 6) | ((key56[off56+2] & 0xFF) >>> 2));
+ key64[off64+3] = (byte) ((key56[off56+2] << 5) | ((key56[off56+3] & 0xFF) >>> 3));
+ key64[off64+4] = (byte) ((key56[off56+3] << 4) | ((key56[off56+4] & 0xFF) >>> 4));
+ key64[off64+5] = (byte) ((key56[off56+4] << 3) | ((key56[off56+5] & 0xFF) >>> 5));
+ key64[off64+6] = (byte) ((key56[off56+5] << 2) | ((key56[off56+6] & 0xFF) >>> 6));
+ key64[off64+7] = (byte) (key56[off56+6] << 1);
+
+ for (int i = 0; i < 8; i++) {
+ // if even # bits, make uneven, take last bit of count so XOR with 1
+ // for uneven # bits, make even, take last bit of count so XOR with 0
+ key64[off64+i] ^= Integer.bitCount(key64[off64+i] ^ 1) & 1;
+ }
+ }
+
+ private static SecretKey getKey(String keyAlg, byte[] k) {
+ if (keyAlg.equals("DESede")) {
+ byte[] k2 = new byte[24];
+ des7to8(k, 0, k2, 0);
+ des7to8(k, 7, k2, 8);
+ des7to8(k, 14, k2, 16);
+ k = k2;
+ }
+ return new SecretKeySpec(k, keyAlg);
+ }
+
+ private void readObject(java.io.ObjectInputStream s)
+ throws IOException, ClassNotFoundException {
+ s.defaultReadObject ();
+ initEngine();
+ }
+
+ @Override
+ public String toString() {
+ return super.toString() + "/"
+ + (usedf?"use_df":"no_df");
+ }
+}
--- /dev/null 2016-04-01 19:18:05.000000000 +0800
+++ new/src/java.base/share/classes/sun/security/provider/DRBG.java 2016-04-01 19:18:05.000000000 +0800
@@ -0,0 +1,240 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code 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
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package sun.security.provider;
+
+import java.security.AccessController;
+import java.security.DrbgParameters;
+import java.security.PrivilegedAction;
+import java.security.SecureRandomInstantiateParameters;
+import java.security.SecureRandomNextBytesParameters;
+import java.security.SecureRandomReseedParameters;
+import java.security.SecureRandomSpi;
+import java.security.Security;
+import java.util.Locale;
+import static java.security.DrbgParameters.Capability.*;
+
+/**
+ * Implement the "SecureRandom.DRBG" algorithm.
+ */
+public final class DRBG extends SecureRandomSpi {
+
+ private static final long serialVersionUID = 9L;
+
+ private final AbstractDrbg impl;
+
+ public DRBG(SecureRandomInstantiateParameters params) {
+
+ // All parameters at unset status (null or -1).
+
+ // Configurable with security property "drbg"
+ String mech = null;
+ Boolean usedf = null;
+ String algorithm = null;
+
+ // Default instantiate parameters configurable with "drbg",
+ // and can be changed with params in getInstance("drbg", params)
+ int strength = -1;
+ DrbgParameters.Capability cap = null;
+ byte[] ps = null;
+
+ // Not configurable with public interfaces, but is a part of
+ // MoreDrbgParameters
+ EntropySource es = null;
+ byte[] nonce = null;
+
+ // Can be configured with a security property
+
+ String config = AccessController.doPrivileged((PrivilegedAction<String>)
+ () -> Security.getProperty("drbg"));
+
+ if (config != null && !config.isEmpty()) {
+ for (String part: config.split(",")) {
+ part = part.trim();
+ switch (part.toLowerCase(Locale.ROOT)) {
+ case "":
+ throw new IllegalArgumentException(
+ "aspect in drbg cannot be empty");
+ case "pr_and_reseed":
+ checkTwice(cap != null, "capability");
+ cap = PR_AND_RESEED;
+ break;
+ case "reseed_only":
+ checkTwice(cap != null, "capability");
+ cap = RESEED_ONLY;
+ break;
+ case "none":
+ checkTwice(cap != null, "capability");
+ cap = NONE;
+ break;
+ case "hash_drbg":
+ case "hmac_drbg":
+ case "ctr_drbg":
+ checkTwice(mech != null, "mechanism name");
+ mech = part;
+ break;
+ case "no_df":
+ checkTwice(usedf != null, "usedf flag");
+ usedf = false;
+ break;
+ case "use_df":
+ checkTwice(usedf != null, "usedf flag");
+ usedf = true;
+ break;
+ default:
+ // For all other parts of the property, it is
+ // either an algorithm name or a strength
+ try {
+ checkTwice(strength >= 0, "strength");
+ strength = Integer.parseInt(part);
+ if (strength < 0) {
+ throw new IllegalArgumentException(
+ "strength in drbg cannot be negative");
+ }
+ } catch (NumberFormatException e) {
+ checkTwice(algorithm != null, "algorithm name");
+ algorithm = part;
+ }
+ }
+ }
+ }
+
+ // Can be updated by params
+
+ if (params != null) {
+ if (params instanceof MoreDrbgParameters) {
+ MoreDrbgParameters m = (MoreDrbgParameters)params;
+ params = m.config;
+
+ // No need to check null for es and nonce, they are still null
+ es = m.es;
+ nonce = m.nonce;
+
+ if (m.mech != null) {
+ mech = m.mech;
+ }
+ if (m.algorithm != null) {
+ algorithm = m.algorithm;
+ }
+ usedf = m.usedf;
+ }
+ if (params instanceof DrbgParameters.Instantiate) {
+ DrbgParameters.Instantiate dp =
+ (DrbgParameters.Instantiate) params;
+
+ // ps is still null by now
+ ps = dp.getPersonalizationString();
+
+ if (dp.getStrength() != -1) {
+ strength = dp.getStrength();
+ }
+ cap = dp.getCapability();
+ } else {
+ throw new IllegalArgumentException("Unsupported params");
+ }
+ }
+
+ // Hardcoded defaults. The info below is duplicated in comments
+ // of the "drbg" security property in java.security.
+
+ if (cap == null) {
+ cap = NONE;
+ }
+ if (mech == null) {
+ mech = "Hash_DRBG";
+ }
+ if (usedf == null) {
+ usedf = true;
+ }
+
+ MoreDrbgParameters m = new MoreDrbgParameters(
+ es, mech, algorithm, nonce, usedf,
+ DrbgParameters.instantiate(strength, cap, ps));
+
+ switch (mech.toLowerCase(Locale.ROOT)) {
+ case "hash_drbg":
+ impl = new HashDrbg(m);
+ break;
+ case "hmac_drbg":
+ impl = new HmacDrbg(m);
+ break;
+ case "ctr_drbg":
+ impl = new CtrDrbg(m);
+ break;
+ default:
+ throw new IllegalArgumentException("Unsupported mech");
+ }
+ }
+
+ @Override
+ protected void engineSetSeed(byte[] seed) {
+ impl.engineSetSeed(seed);
+ }
+
+ @Override
+ protected void engineNextBytes(byte[] bytes) {
+ impl.engineNextBytes(bytes);
+ }
+
+ @Override
+ protected byte[] engineGenerateSeed(int numBytes) {
+ return impl.engineGenerateSeed(numBytes);
+ }
+
+ @Override
+ protected void engineNextBytes(
+ byte[] bytes, SecureRandomNextBytesParameters params) {
+ impl.engineNextBytes(bytes, params);
+ }
+
+ @Override
+ protected void engineReseed(SecureRandomReseedParameters params) {
+ impl.engineReseed(params);
+ }
+
+ @Override
+ protected SecureRandomInstantiateParameters engineGetParameters() {
+ return impl.engineGetParameters();
+ }
+
+ @Override
+ public String toString() {
+ return impl.toString();
+ }
+
+ /**
+ * Ensures an aspect is not set more than once.
+ *
+ * @param flag true if set more than once
+ * @param name the name of aspect shown in IAE
+ * @throws IllegalArgumentException if it happens
+ */
+ private static void checkTwice(boolean flag, String name) {
+ if (flag) {
+ throw new IllegalArgumentException(name
+ + " cannot be provided more than once in drbg");
+ }
+ }
+}
--- /dev/null 2016-04-01 19:18:06.000000000 +0800
+++ new/src/java.base/share/classes/sun/security/provider/EntropySource.java 2016-04-01 19:18:06.000000000 +0800
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code 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
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package sun.security.provider;
+
+/**
+ * An interface of a source of entropy input.
+ *
+ * @since 9
+ */
+public interface EntropySource {
+ /**
+ * Returns a byte array containing entropy.
+ *
+ * @param entropy minimum entropy required, in bytes
+ * @param minLength minimum length of output, in bytes
+ * @param maxLength maximum length of output, in bytes
+ * @param pr whether prediction resistance is required
+ * @return the byte array containing entropy
+ */
+ byte[] getEntropy(int entropy, int minLength, int maxLength, boolean pr);
+}
--- /dev/null 2016-04-01 19:18:07.000000000 +0800
+++ new/src/java.base/share/classes/sun/security/provider/HashDrbg.java 2016-04-01 19:18:07.000000000 +0800
@@ -0,0 +1,239 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code 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
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package sun.security.provider;
+
+import java.io.IOException;
+import java.math.BigInteger;
+import java.security.DigestException;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.security.NoSuchProviderException;
+import java.security.SecureRandomInstantiateParameters;
+import java.util.Arrays;
+
+public class HashDrbg extends AbstractHashDrbg {
+
+ private static final long serialVersionUID = 9L;
+
+ private static final byte[] ZERO= new byte[1];
+ private static final byte[] ONE = new byte[]{1};
+
+ private transient MessageDigest digest;
+
+ private byte[] v;
+ private byte[] c;
+
+ public HashDrbg(SecureRandomInstantiateParameters params) {
+ mechName = "Hash_DRBG";
+ configureInternal(params);
+ }
+
+ /**
+ * This call, used by the constructors, instantiates the digest.
+ */
+ @Override
+ protected void initEngine() {
+ if (algorithm == null) {
+ return;
+ }
+ try {
+ /*
+ * Use the local SUN implementation to avoid native
+ * performance overhead.
+ */
+ digest = MessageDigest.getInstance(algorithm, "SUN");
+ } catch (NoSuchProviderException | NoSuchAlgorithmException e) {
+ // Fallback to any available.
+ try {
+ digest = MessageDigest.getInstance(algorithm);
+ } catch (NoSuchAlgorithmException exc) {
+ throw new InternalError(
+ "internal error: " + algorithm + " not available.", exc);
+ }
+ }
+ }
+
+ private byte[] hashDf(int requested, byte[]... inputs) {
+ return hashDf(digest, outLen, requested, inputs);
+ }
+
+ /**
+ * A hash-based derivation function defined in NIST SP 800-90Ar1 10.3.1.
+ * The function is used inside Hash_DRBG, and can also be used as an
+ * approved conditioning function as described in 800-90B 6.4.2.2.
+ *
+ * @param digest a {@code MessageDigest} object in reset state
+ * @param outLen {@link MessageDigest#getDigestLength} of {@code digest}
+ * @param requested requested output length, in bytes
+ * @param inputs input data
+ * @return the condensed/expanded output
+ */
+ public static byte[] hashDf(MessageDigest digest, int outLen,
+ int requested, byte[]... inputs) {
+ int len = (requested + outLen - 1) / outLen;
+ byte[] temp = new byte[len * outLen];
+ int counter = 1;
+
+ for (int i=0; i<len; i++) {
+ digest.update((byte) counter);
+ digest.update((byte)(requested >> 21)); // requested*8 as int32
+ digest.update((byte)(requested >> 13));
+ digest.update((byte)(requested >> 5));
+ digest.update((byte)(requested << 3));
+ for (byte[] input: inputs) {
+ digest.update(input);
+ }
+ try {
+ digest.digest(temp, i * outLen, outLen);
+ } catch (DigestException e) {
+ throw new AssertionError("will not happen");
+ }
+ counter++;
+ }
+ return temp.length == requested? temp: Arrays.copyOf(temp, requested);
+ }
+
+ // For seeding, input is entropy_input || nonce || personalization_string;
+ // for reseeding, input is entropy_input || additional_input
+ @Override
+ protected final void hashReseedInternal(byte[] input) {
+ byte[] seed;
+ if (v != null) {
+ seed = hashDf(seedLen, ONE, v, input);
+ } else {
+ seed = hashDf(seedLen, input);
+ }
+ v = seed;
+ c = hashDf(seedLen, ZERO, v);
+ reseedCounter = 1;
+ status();
+ }
+
+ private void status() {
+ if (debug != null) {
+ debug.println("V = " + hex(v));
+ debug.println("C = " + hex(c));
+ debug.println("reseed counter = " + reseedCounter);
+ }
+ }
+
+ /**
+ * Adds byte arrays into an existing one.
+ *
+ * @param out existing array
+ * @param data more arrays, can be of different length
+ */
+ private static void addBytes(byte[] out, int len, byte[]... data) {
+ for (byte[] d: data) {
+ int dlen = d.length;
+ int carry = 0;
+ for (int i=0; i<len; i++) {
+ int sum = (out[len-i-1] & 0xff) + carry;
+ if (i < dlen) {
+ sum += (d[dlen - i - 1] & 0xff);
+ }
+ out[len - i - 1] = (byte) sum;
+ carry = sum >> 8;
+ if (i >= dlen - 1 && carry == 0) break;
+ }
+ }
+ }
+
+ /**
+ * Generates a user-specified number of random bytes.
+ *
+ * @param result the array to be filled in with random bytes.
+ */
+ @Override
+ public final synchronized void generateAlgorithm(
+ byte[] result, byte[] additionalInput) {
+
+ if (debug != null) {
+ debug.println("generateAlgorithm");
+ }
+ if (additionalInput != null) {
+ digest.update((byte)2);
+ digest.update(v);
+ digest.update(additionalInput);
+ addBytes(v, seedLen, digest.digest());
+ }
+
+ // Step 3.
+ hashGen(result, result.length, v);
+
+ // Step 4.
+ digest.update((byte)3);
+ digest.update(v);
+ byte[] h = digest.digest();
+
+ // Step 5.
+ byte[] rcBytes;
+ if (reseedCounter < 256) {
+ rcBytes = new byte[]{(byte)reseedCounter};
+ } else {
+ rcBytes = BigInteger.valueOf(reseedCounter).toByteArray();
+ }
+ addBytes(v, seedLen, h, c, rcBytes);
+
+ // Step 6.
+ reseedCounter++;
+
+ status();
+ }
+
+ private void hashGen(byte[] output, int len, byte[] v) {
+ int m = (len + outLen - 1) / outLen;
+ byte[] data = v;
+ for (int i=0; i<m; i++) {
+ int tailLen = len - i * outLen;
+ if (tailLen < outLen) {
+ System.arraycopy(digest.digest(data), 0, output, i * outLen,
+ tailLen);
+ } else {
+ try {
+ digest.update(data);
+ digest.digest(output, i*outLen, outLen);
+ } catch (DigestException e) {
+ throw new AssertionError("will not happen");
+ }
+ }
+ // Unless this is the last around, we will need to increment data.
+ // but we cannot change v, so a copy is made.
+ if (i != m - 1) {
+ if (data == v) {
+ data = Arrays.copyOf(v, v.length);
+ }
+ addBytes(data, seedLen, ONE);
+ }
+ }
+ }
+
+ private void readObject(java.io.ObjectInputStream s)
+ throws IOException, ClassNotFoundException {
+ s.defaultReadObject ();
+ initEngine();
+ }
+}
--- /dev/null 2016-04-01 19:18:08.000000000 +0800
+++ new/src/java.base/share/classes/sun/security/provider/HmacDrbg.java 2016-04-01 19:18:08.000000000 +0800
@@ -0,0 +1,177 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code 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
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package sun.security.provider;
+
+import javax.crypto.Mac;
+import javax.crypto.spec.SecretKeySpec;
+import java.io.IOException;
+import java.security.InvalidKeyException;
+import java.security.NoSuchAlgorithmException;
+import java.security.NoSuchProviderException;
+import java.security.SecureRandomInstantiateParameters;
+import java.util.Arrays;
+
+public class HmacDrbg extends AbstractHashDrbg {
+
+ private static final long serialVersionUID = 9L;
+
+ private transient Mac mac;
+
+ private String macAlg;
+
+ private byte[] v;
+ private byte[] k;
+
+ public HmacDrbg(SecureRandomInstantiateParameters params) {
+ mechName = "HMAC_DRBG";
+ configureInternal(params);
+ }
+
+ private void status() {
+ if (debug != null) {
+ debug.println("V = " + hex(v));
+ debug.println("Key = " + hex(k));
+ debug.println("reseed counter = " + reseedCounter);
+ }
+ }
+
+ private void update(byte[]... inputs) {
+ try {
+ // Step 1.
+ mac.init(new SecretKeySpec(k, macAlg));
+ mac.update(v);
+ mac.update((byte) 0);
+ for (byte[] input: inputs) {
+ mac.update(input);
+ }
+ k = mac.doFinal();
+ // Step 2.
+ mac.init(new SecretKeySpec(k, macAlg));
+ v = mac.doFinal(v);
+ // Step 4.
+ if (inputs.length != 0) {
+ mac.update(v);
+ mac.update((byte) 1);
+ for (byte[] input: inputs) {
+ mac.update(input);
+ }
+ k = mac.doFinal();
+ mac.init(new SecretKeySpec(k, macAlg));
+ v = mac.doFinal(v);
+ }
+ } catch (InvalidKeyException e) {
+ throw new InternalError(e);
+ }
+ }
+
+ /**
+ * This call, used by the constructors, instantiates the digest.
+ */
+ @Override
+ protected void initEngine() {
+ if (algorithm == null) {
+ return;
+ }
+ macAlg = "HmacSHA" + algorithm.substring(4);
+ try {
+ mac = Mac.getInstance(macAlg, "SunJCE");
+ } catch (NoSuchProviderException | NoSuchAlgorithmException e) {
+ // Fallback to any available.
+ try {
+ mac = Mac.getInstance(macAlg);
+ } catch (NoSuchAlgorithmException exc) {
+ throw new InternalError(
+ "internal error: " + macAlg + " not available.", exc);
+ }
+ }
+ }
+
+ // For seeding, input is entropy_input || nonce || personalization_string;
+ // for reseeding, input is entropy_input || additional_input
+ @Override
+ protected final void hashReseedInternal(byte[] input) {
+ if (v == null) {
+ k = new byte[outLen];
+ v = new byte[outLen];
+ Arrays.fill(v, (byte) 1);
+ }
+ update(input);
+ reseedCounter = 1;
+ status();
+ }
+
+ /**
+ * Generates a user-specified number of random bytes.
+ *
+ * @param result the array to be filled in with random bytes.
+ */
+ @Override
+ public synchronized void generateAlgorithm(
+ byte[] result, byte[] additionalInput) {
+
+ // Step 2.
+ if (additionalInput != null) {
+ update(additionalInput);
+ }
+
+ // Step 3.
+ int pos = 0;
+
+ // Step 4.
+ while (pos < result.length) {
+ int tailLen = result.length - pos;
+ // Step 4.1.
+ try {
+ mac.init(new SecretKeySpec(k, macAlg));
+ } catch (InvalidKeyException e) {
+ throw new InternalError(e);
+ }
+ v = mac.doFinal(v);
+ // Step 4.2 and 5.
+ System.arraycopy(v, 0, result, pos,
+ tailLen > outLen ? outLen : tailLen);
+ pos += outLen;
+ }
+
+ // Step 6.
+ if (additionalInput != null) {
+ update(additionalInput);
+ } else {
+ update();
+ }
+
+ // Step 7.
+ reseedCounter++;
+
+ status();
+ }
+
+ private void readObject(java.io.ObjectInputStream s)
+ throws IOException, ClassNotFoundException {
+ s.defaultReadObject ();
+ initEngine();
+ }
+}
--- /dev/null 2016-04-01 19:18:09.000000000 +0800
+++ new/src/java.base/share/classes/sun/security/provider/MoreDrbgParameters.java 2016-04-01 19:18:09.000000000 +0800
@@ -0,0 +1,66 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code 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
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package sun.security.provider;
+
+import java.security.DrbgParameters;
+import java.security.SecureRandomInstantiateParameters;
+
+/**
+ * Extra non-standard parameters that can be used by DRBGs.
+ */
+public class MoreDrbgParameters implements SecureRandomInstantiateParameters {
+
+ final String mech;
+ final String algorithm;
+ final EntropySource es;
+ final byte[] nonce;
+ final boolean usedf;
+ final DrbgParameters.Instantiate config;
+
+ /**
+ * Creates a new {@code MoreDrbgParameters} object.
+ *
+ * @param es the {@link EntropySource} to use, set to {@code null}
+ * and a default entropy source will be used.
+ * @param mech mech name, can be {@code null}
+ * @param algorithm the requested algorithm to use, set to {@code null}
+ * and the algorithm will be decided by strength.
+ * @param nonce the nonce to use, set to {@code null} and
+ * a nonce will be assigned.
+ * @param usedf whether a derivation function should be used
+ * @param config a {@link DrbgParameters.Instantiate} object
+ */
+ public MoreDrbgParameters(EntropySource es, String mech,
+ String algorithm, byte[] nonce,
+ boolean usedf, DrbgParameters.Instantiate config) {
+ this.mech = mech;
+ this.algorithm = algorithm;
+ this.es = es;
+ this.nonce = nonce;
+ this.usedf = usedf;
+ this.config = config;
+ }
+}
--- /dev/null 2016-04-01 19:18:10.000000000 +0800
+++ new/test/com/sun/crypto/provider/Mac/HmacSHA512.java 2016-04-01 19:18:10.000000000 +0800
@@ -0,0 +1,79 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+import jdk.testlibrary.Asserts;
+
+import javax.crypto.Mac;
+import javax.crypto.spec.SecretKeySpec;
+import java.util.Arrays;
+
+/**
+ * @test
+ * @bug 8051408
+ * @library /lib/testlibrary
+ * @summary testing HmacSHA512/224 and HmacSHA512/256.
+ */
+public class HmacSHA512 {
+ public static void main(String[] args) throws Exception {
+
+ Mac mac;
+
+ // Test vectors obtained from
+ // https://groups.google.com/d/msg/sci.crypt/OolWgsgQD-8/IUR2KhCcfEkJ
+ mac = Mac.getInstance("HmacSHA512/224");
+ mac.init(new SecretKeySpec(xeh("4a656665"), "HmacSHA512/224"));
+ mac.update("what do ya want for nothing?".getBytes());
+ Asserts.assertTrue(Arrays.equals(mac.doFinal(),
+ xeh("4a530b31a79ebcce36916546317c45f247d83241dfb818fd37254bde")));
+
+ mac = Mac.getInstance("HmacSHA512/256");
+ mac.init(new SecretKeySpec(xeh("4a656665"), "HmacSHA512/256"));
+ mac.update("what do ya want for nothing?".getBytes());
+ Asserts.assertTrue(Arrays.equals(mac.doFinal(),
+ xeh("6df7b24630d5ccb2ee335407081a87188c221489768fa2020513b2d593359456")));
+
+ mac = Mac.getInstance("HmacSHA512/224");
+ mac.init(new SecretKeySpec(xeh("0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b"),
+ "HmacSHA512/224"));
+ mac.update("Hi There".getBytes());
+ Asserts.assertTrue(Arrays.equals(mac.doFinal(),
+ xeh("b244ba01307c0e7a8ccaad13b1067a4cf6b961fe0c6a20bda3d92039")));
+
+ mac = Mac.getInstance("HmacSHA512/256");
+ mac.init(new SecretKeySpec(xeh("0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b"),
+ "HmacSHA512/256"));
+ mac.update("Hi There".getBytes());
+ Asserts.assertTrue(Arrays.equals(mac.doFinal(),
+ xeh("9f9126c3d9c3c330d760425ca8a217e31feae31bfe70196ff81642b868402eab")));
+ }
+
+ static byte[] xeh(String in) {
+ in = in.replaceAll(" ", "");
+ int len = in.length()/2;
+ byte[] out = new byte[len];
+ for (int i=0; i<len; i++) {
+ out[i] = (byte)Integer.parseInt(in.substring(i*2, i*2+2), 16);
+ }
+ return out;
+ }
+}
--- /dev/null 2016-04-01 19:18:11.000000000 +0800
+++ new/test/sun/security/provider/MessageDigest/SHA512.java 2016-04-01 19:18:11.000000000 +0800
@@ -0,0 +1,70 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+import jdk.testlibrary.Asserts;
+
+import java.security.MessageDigest;
+import java.util.Arrays;
+
+/**
+ * @test
+ * @bug 8051408
+ * @library /lib/testlibrary
+ * @summary testing SHA-512/224 and SHA-512/256.
+ */
+public class SHA512 {
+ public static void main(String[] args) throws Exception {
+
+ MessageDigest md;
+
+ // Test vectors obtained from
+ // http://csrc.nist.gov/groups/ST/toolkit/documents/Examples/SHA512_224.pdf
+ md = MessageDigest.getInstance("SHA-512/224");
+ Asserts.assertTrue(Arrays.equals(md.digest("abc".getBytes()),
+ xeh("4634270F 707B6A54 DAAE7530 460842E2 0E37ED26 5CEEE9A4 3E8924AA")));
+ Asserts.assertTrue(Arrays.equals(md.digest((
+ "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmn" +
+ "hijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu").getBytes()),
+ xeh("23FEC5BB 94D60B23 30819264 0B0C4533 35D66473 4FE40E72 68674AF9")));
+
+ // Test vectors obtained from
+ // http://csrc.nist.gov/groups/ST/toolkit/documents/Examples/SHA512_256.pdf
+ md = MessageDigest.getInstance("SHA-512/256");
+ Asserts.assertTrue(Arrays.equals(md.digest("abc".getBytes()),
+ xeh("53048E26 81941EF9 9B2E29B7 6B4C7DAB E4C2D0C6 34FC6D46 E0E2F131 07E7AF23")));
+ Asserts.assertTrue(Arrays.equals(md.digest((
+ "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmn" +
+ "hijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu").getBytes()),
+ xeh("3928E184 FB8690F8 40DA3988 121D31BE 65CB9D3E F83EE614 6FEAC861 E19B563A")));
+ }
+
+ static byte[] xeh(String in) {
+ in = in.replaceAll(" ", "");
+ int len = in.length()/2;
+ byte[] out = new byte[len];
+ for (int i=0; i<len; i++) {
+ out[i] = (byte)Integer.parseInt(in.substring(i*2, i*2+2), 16);
+ }
+ return out;
+ }
+}
--- /dev/null 2016-04-01 19:18:12.000000000 +0800
+++ new/test/sun/security/provider/SecureRandom/AbstractDrbgSpec.java 2016-04-01 19:18:12.000000000 +0800
@@ -0,0 +1,306 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/* @test
+ * @bug 8051408
+ * @modules java.base/sun.security.provider
+ * @summary check the AbstractDrbg API etc
+ */
+
+import java.security.*;
+import sun.security.provider.AbstractDrbg;
+import static java.security.DrbgParameters.Capability.*;
+
+/**
+ * This test makes sure the AbstractDrbg API works as specified. It also
+ * checks the SecureRandom API.
+ */
+public class AbstractDrbgSpec {
+
+ public static void main(String args[]) throws Exception {
+
+ // getInstance from a provider.
+
+ Provider p = new All("A", 0, "");
+ byte[] bytes = new byte[100];
+
+ // A non-DRBG
+ iae(() -> SecureRandom.getInstance("S1", null, p));
+ nsae(() -> SecureRandom.getInstance("S1",
+ new SecureRandomInstantiateParameters() {}, p));
+
+ SecureRandom s1 = SecureRandom.getInstance("S1", p);
+ if (s1.getParameters() != null) {
+ throw new Exception();
+ }
+
+ npe(() -> s1.nextBytes(null));
+ iae(() -> s1.nextBytes(bytes, null));
+ uoe(() -> s1.nextBytes(bytes, new SecureRandomNextBytesParameters() {}));
+ uoe(() -> s1.reseed());
+ iae(() -> s1.reseed(null));
+ uoe(() -> s1.reseed(new SecureRandomReseedParameters() {}));
+
+ // A weak DRBG
+ iae(() -> SecureRandom.getInstance("S2", null, p));
+ nsae(() -> SecureRandom.getInstance("S2",
+ new SecureRandomInstantiateParameters() {}, p));
+ nsae(() -> SecureRandom.getInstance("S2",
+ DrbgParameters.instantiate(256, NONE, null), p));
+ nsae(() -> SecureRandom.getInstance("S2",
+ DrbgParameters.instantiate(-1, PR_AND_RESEED, null), p));
+ nsae(() -> SecureRandom.getInstance("S2",
+ DrbgParameters.instantiate(-1, RESEED_ONLY, null), p));
+
+ SecureRandom s2 = SecureRandom.getInstance("S2",
+ DrbgParameters.instantiate(-1, NONE, null), p);
+ equals(s2, "S2,SQUEEZE,128,none");
+ equals(s2.getParameters(), "128,none,null");
+
+ npe(() -> s2.nextBytes(null));
+ iae(() -> s2.nextBytes(bytes, null));
+ iae(() -> s2.nextBytes(bytes, new SecureRandomNextBytesParameters() {}));
+ uoe(() -> s2.reseed());
+ iae(() -> s2.reseed(null));
+
+ iae(() -> s2.nextBytes(bytes, DrbgParameters.nextBytes(-1, false, new byte[101])));
+ iae(() -> s2.nextBytes(new byte[101], DrbgParameters.nextBytes(-1, false, new byte[100])));
+ s2.nextBytes(bytes, DrbgParameters.nextBytes(-1, false, new byte[100]));
+
+ // A strong DRBG
+ iae(() -> SecureRandom.getInstance("S3", null, p));
+ nsae(() -> SecureRandom.getInstance("S3",
+ new SecureRandomInstantiateParameters() {}, p));
+ SecureRandom.getInstance("S3",
+ DrbgParameters.instantiate(192, PR_AND_RESEED, null), p);
+
+ SecureRandom s3 = SecureRandom.getInstance("S3", p);
+ equals(s3, "S3,SQUEEZE,128,reseed_only");
+ equals(s3.getParameters(), "128,reseed_only,null");
+
+ iae(() -> s3.nextBytes(bytes, DrbgParameters.nextBytes(192, false, null)));
+ iae(() -> s3.nextBytes(bytes, DrbgParameters.nextBytes(112, true, null)));
+ iae(() -> s3.reseed(new SecureRandomReseedParameters() {}));
+
+ SecureRandom s32 = SecureRandom.getInstance(
+ "S3", DrbgParameters.instantiate(192, PR_AND_RESEED, null), p);
+ equals(s32, "S3,SQUEEZE,192,pr_and_reseed");
+ equals(s32.getParameters(), "192,pr_and_reseed,null");
+
+ s32.nextBytes(bytes, DrbgParameters.nextBytes(192, false, null));
+ s32.nextBytes(bytes, DrbgParameters.nextBytes(112, true, null));
+ s32.reseed();
+ s32.reseed(DrbgParameters.reseed(true, new byte[100]));
+
+ // getInstance from competitive providers.
+
+ Provider l = new Legacy("L", 0, "");
+ Provider w = new Weak("W", 0, "");
+ Provider s = new Strong("S", 0, "");
+
+ Security.addProvider(l);
+ Security.addProvider(w);
+ Security.addProvider(s);
+
+ SecureRandom s4;
+
+ try {
+ s4 = SecureRandom.getInstance("S");
+ if (s4.getProvider() != l) {
+ throw new Exception();
+ }
+
+ nsae(() -> SecureRandom.getInstance(
+ "S", DrbgParameters.instantiate(256, NONE, null)));
+
+ s4 = SecureRandom.getInstance(
+ "S", DrbgParameters.instantiate(192, NONE, null));
+ if (s4.getProvider() != s) {
+ throw new Exception();
+ }
+
+ s4 = SecureRandom.getInstance(
+ "S", DrbgParameters.instantiate(128, PR_AND_RESEED, null));
+ if (s4.getProvider() != s) {
+ throw new Exception();
+ }
+
+ s4 = SecureRandom.getInstance(
+ "S", DrbgParameters.instantiate(128, RESEED_ONLY, null));
+ if (s4.getProvider() != s) {
+ throw new Exception();
+ }
+
+ s4 = SecureRandom.getInstance(
+ "S", DrbgParameters.instantiate(128, NONE, null));
+ if (s4.getProvider() != w) {
+ throw new Exception();
+ }
+ } finally {
+ Security.removeProvider("L");
+ Security.removeProvider("W");
+ Security.removeProvider("S");
+ }
+ }
+
+ public static class All extends Provider {
+ protected All(String name, double version, String info) {
+ super(name, version, info);
+ put("SecureRandom.S1", S1.class.getName());
+ put("SecureRandom.S2", S2.class.getName());
+ put("SecureRandom.S3", S3.class.getName());
+ }
+ }
+
+ // Providing S with no params support
+ public static class Legacy extends Provider {
+ protected Legacy(String name, double version, String info) {
+ super(name, version, info);
+ put("SecureRandom.S", S1.class.getName());
+ }
+ }
+
+ public static class Weak extends Provider {
+ protected Weak(String name, double version, String info) {
+ super(name, version, info);
+ put("SecureRandom.S", S2.class.getName());
+ }
+ }
+
+ public static class Strong extends Provider {
+ protected Strong(String name, double version, String info) {
+ super(name, version, info);
+ put("SecureRandom.S", S3.class.getName());
+ }
+ }
+
+ // This is not a DRBG.
+ public static class S1 extends SecureRandomSpi {
+ @Override
+ protected void engineSetSeed(byte[] seed) {
+ }
+
+ @Override
+ protected void engineNextBytes(byte[] bytes) {
+ }
+
+ @Override
+ protected byte[] engineGenerateSeed(int numBytes) {
+ return new byte[numBytes];
+ }
+ }
+
+ // This is a strong DRBG.
+ public static class S3 extends AbstractDrbg {
+
+ public S3(SecureRandomInstantiateParameters params) {
+ supportPr = true;
+ supportReseed = true;
+ highestSecurity = 192;
+ mechName = "S3";
+ algorithm = "SQUEEZE";
+ configureInternal(params);
+ }
+ protected void chooseAlgorithmAndStrength() {
+ if (requestedStrength < 0) {
+ strength = defaultStrength;
+ } else {
+ strength = requestedStrength;
+ }
+ minLength = strength / 8;
+ maxAiLength = maxPsLength = maxNbLength = 100;
+ }
+
+ @Override
+ protected void initEngine() {
+
+ }
+
+ @Override
+ protected void instantiateAlgorithm(byte[] ei) {
+
+ }
+
+ @Override
+ protected void generateAlgorithm(byte[] result, byte[] additionalInput) {
+
+ }
+
+ @Override
+ protected void reseedAlgorithm(byte[] ei, byte[] additionalInput) {
+
+ }
+ }
+
+ // This is a weak DRBG. maximum strength is 192 and does
+ // not support prediction resistance or reseed.
+ public static class S2 extends S3 {
+ public S2(SecureRandomInstantiateParameters params) {
+ super(null);
+ mechName = "S2";
+ highestSecurity = 128;
+ supportPr = false;
+ supportReseed = false;
+ configureInternal(params);
+ }
+ }
+
+ static void nsae(RunnableWithException r) throws Exception {
+ checkException(r, NoSuchAlgorithmException.class);
+ }
+
+ static void iae(RunnableWithException r) throws Exception {
+ checkException(r, IllegalArgumentException.class);
+ }
+
+ static void uoe(RunnableWithException r) throws Exception {
+ checkException(r, UnsupportedOperationException.class);
+ }
+
+ static void npe(RunnableWithException r) throws Exception {
+ checkException(r, NullPointerException.class);
+ }
+
+ interface RunnableWithException {
+ void run() throws Exception;
+ }
+
+ static void checkException(RunnableWithException r, Class ex)
+ throws Exception {
+ try {
+ r.run();
+ } catch (Exception e) {
+ if (ex.isAssignableFrom(e.getClass())) {
+ return;
+ }
+ throw e;
+ }
+ throw new Exception("No exception thrown");
+ }
+
+ static void equals(Object o, String s) throws Exception {
+ if (!o.toString().equals(s)) {
+ throw new Exception(o.toString() + " is not " + s);
+ }
+ }
+}
--- /dev/null 2016-04-01 19:18:13.000000000 +0800
+++ new/test/sun/security/provider/SecureRandom/AutoReseed.java 2016-04-01 19:18:13.000000000 +0800
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+import java.security.SecureRandom;
+import java.security.Security;
+
+/**
+ * @test
+ * @bug 8051408
+ * @summary make sure nextBytes etc can be called before setSeed
+ */
+public class AutoReseed {
+
+ public static void main(String[] args) throws Exception {
+ SecureRandom sr;
+ String old = Security.getProperty("drbg");
+ try {
+ for (String mech : new String[]{"Hash_DRBG", "HMAC_DRBG", "CTR_DRBG"}) {
+ System.out.println("Testing " + mech + "...");
+ Security.setProperty("drbg", mech);
+
+ // Check auto reseed works
+ sr = SecureRandom.getInstance("DRBG");
+ sr.nextInt();
+ sr = SecureRandom.getInstance("DRBG");
+ sr.reseed();
+ sr = SecureRandom.getInstance("DRBG");
+ sr.generateSeed(10);
+ }
+ } finally {
+ Security.setProperty("drbg", old);
+ }
+ }
+}
--- /dev/null 2016-04-01 19:18:14.000000000 +0800
+++ new/test/sun/security/provider/SecureRandom/CommonSeeder.java 2016-04-01 19:18:14.000000000 +0800
@@ -0,0 +1,123 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+import sun.security.provider.AbstractDrbg;
+import sun.security.provider.EntropySource;
+import java.security.DrbgParameters;
+import java.security.SecureRandom;
+import java.security.Security;
+
+/**
+ * @test
+ * @bug 8051408
+ * @modules java.base/sun.security.provider
+ * @run main/othervm CommonSeeder
+ * @summary check entropy reading of DRBGs
+ */
+public class CommonSeeder {
+
+ static class MyES implements EntropySource {
+ int count = 100;
+ int lastCount = 100;
+
+ @Override
+ public byte[] getEntropy(int entropy, int minLength,
+ int maxLength, boolean pr) {
+ count--;
+ return new byte[minLength];
+ }
+
+ /**
+ * Confirms genEntropy() has been called {@code less} times
+ * since last check.
+ */
+ public void checkUsage(int less) throws Exception {
+ if (lastCount != count + less) {
+ throw new Exception(String.format(
+ "lastCount = %d, count = %d, less = %d",
+ lastCount, count, less));
+ }
+ lastCount = count;
+ }
+ }
+
+ public static void main(String[] args) throws Exception {
+
+ byte[] result = new byte[10];
+ MyES es = new MyES();
+
+ // Set es as the default entropy source, overriding SeedGenerator.
+ setDefaultSeeder(es);
+
+ // Nothing happened yet
+ es.checkUsage(0);
+
+ SecureRandom sr;
+ sr = SecureRandom.getInstance("DRBG");
+
+ // No entropy reading if only getInstance
+ es.checkUsage(0);
+
+ // Entropy is read at 1st nextBytes of the 1st DRBG
+ sr.nextInt();
+ es.checkUsage(1);
+
+ for (String mech: new String[]{"Hash_DRBG", "HMAC_DRBG", "CTR_DRBG"}) {
+ System.out.println("Testing " + mech + "...");
+
+ // DRBG with pr_false will never read entropy again no matter
+ // if nextBytes or reseed is called.
+
+ Security.setProperty("drbg", mech);
+ sr = SecureRandom.getInstance("DRBG");
+ sr.nextInt();
+ sr.reseed();
+ es.checkUsage(0);
+
+ // DRBG with pr_true always read from default entropy, and
+ // its nextBytes always reseed itself
+
+ Security.setProperty("drbg", mech + ",pr_and_reseed");
+ sr = SecureRandom.getInstance("DRBG");
+
+ sr.nextInt();
+ es.checkUsage(2); // one instantiate, one reseed
+ sr.nextInt();
+ es.checkUsage(1); // one reseed in nextBytes
+ sr.reseed();
+ es.checkUsage(1); // one reseed
+ sr.nextBytes(result, DrbgParameters.nextBytes(-1, false, null));
+ es.checkUsage(0); // pr_false for this call
+ sr.nextBytes(result, DrbgParameters.nextBytes(-1, true, null));
+ es.checkUsage(1); // pr_true for this call
+ sr.reseed(DrbgParameters.reseed(true, null));
+ es.checkUsage(1); // reseed from es
+ sr.reseed(DrbgParameters.reseed(false, null));
+ es.checkUsage(0); // reseed from AbstractDrbg.SeederHolder.seeder
+ }
+ }
+
+ static void setDefaultSeeder(EntropySource es) throws Exception {
+ AbstractDrbg.defaultES = es;
+ }
+}
--- /dev/null 2016-04-01 19:18:16.000000000 +0800
+++ new/test/sun/security/provider/SecureRandom/DRBGAlg.java 2016-04-01 19:18:15.000000000 +0800
@@ -0,0 +1,141 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+import sun.security.provider.MoreDrbgParameters;
+
+import java.security.DrbgParameters;
+import java.security.NoSuchAlgorithmException;
+import java.security.SecureRandom;
+import java.security.SecureRandomInstantiateParameters;
+import java.security.Security;
+
+import static java.security.DrbgParameters.Capability.*;
+
+/**
+ * @test
+ * @bug 8051408
+ * @modules java.base/sun.security.provider
+ * @summary make sure DRBG alg can be defined and instantiated freely
+ */
+public class DRBGAlg {
+
+ public static void main(String[] args) throws Exception {
+ check(null, "Hash_DRBG", "SHA-256", "reseed_only", ",128");
+ check("", "Hash_DRBG", "SHA-256", "reseed_only", ",128");
+ check("sha-1", "Hash_DRBG", "SHA-1", "reseed_only", ",128");
+ check("sha-256", "Hash_DRBG", "SHA-256", "reseed_only", ",128");
+ check("SHA-3");
+ check("hash_drbg", "Hash_DRBG", "SHA-256", "reseed_only", ",128");
+ check("hmac_drbg", "HMAC_DRBG", "SHA-256", "reseed_only", ",128");
+ check("ctr_drbg", "CTR_DRBG", "AES-", "reseed_only", ",128", "use_df");
+ check("hash_drbg,sha-512,Pr_and_Reseed,192",
+ "Hash_DRBG", "SHA-512", "pr_and_reseed", ",192");
+
+ check("Hash_DRBG,Hmac_DRBG");
+ check("SHA-1,SHA-256");
+ check("128,256");
+ check("none,reseed_only");
+ check("use_df,no_df");
+ check("Hash_DRBG,,SHA-1");
+
+ check(null, DrbgParameters.instantiate(112, PR_AND_RESEED, null),
+ "Hash_DRBG", "SHA-256", "pr_and_reseed", ",112");
+ check(null, DrbgParameters.instantiate(256, PR_AND_RESEED, null),
+ "Hash_DRBG", "SHA-256", "pr_and_reseed", ",256");
+ check(null, DrbgParameters.instantiate(384, PR_AND_RESEED, null));
+ check("sha-1", DrbgParameters.instantiate(112, PR_AND_RESEED, null),
+ "Hash_DRBG", "SHA-1", "pr_and_reseed", ",112");
+ check("sha-1", DrbgParameters.instantiate(192, PR_AND_RESEED, null));
+ check("hash_drbg,sha-512,Pr_and_Reseed,192",
+ DrbgParameters.instantiate(112, NONE, null),
+ "Hash_DRBG", "SHA-512", "reseed_only", ",112");
+ check("hash_drbg,sha-512,Pr_and_Reseed,192",
+ DrbgParameters.instantiate(-1, NONE, null),
+ "Hash_DRBG", "SHA-512", "reseed_only", ",192");
+ // getInstance params can be stronger than definition
+ check("hash_drbg,sha-256,None,112",
+ DrbgParameters.instantiate(192, PR_AND_RESEED, null),
+ "Hash_DRBG", "SHA-256", "pr_and_reseed", ",192");
+
+ check("hash_drbg,sha-1", new MoreDrbgParameters(null, null, "sha-512", null, false,
+ DrbgParameters.instantiate(-1, NONE, null)),
+ "Hash_DRBG", "SHA-512");
+ check("hash_drbg,sha-1", new MoreDrbgParameters(null, null, null, null, false,
+ DrbgParameters.instantiate(-1, NONE, null)),
+ "Hash_DRBG", "SHA-1");
+ check("hash_drbg", new MoreDrbgParameters(null, "hmac_drbg", null, null, false,
+ DrbgParameters.instantiate(-1, NONE, null)),
+ "HMAC_DRBG", "SHA-256");
+
+ check("hash_drbg,sha-1", new MoreDrbgParameters(null, null, "sha-3", null, false,
+ DrbgParameters.instantiate(-1, NONE, null)));
+ check("hash_drbg,sha-1", new MoreDrbgParameters(null, "Unknown_DRBG", null, null, false,
+ DrbgParameters.instantiate(-1, NONE, null)));
+ }
+
+ /**
+ * Checks DRBG definition for getInstance(alg, params).
+ *
+ * @param define DRBG
+ * @param params getInstance request (null if none)
+ * @param expected expected actual instantiate params, empty if should fail
+ */
+ static void check(String define, SecureRandomInstantiateParameters params,
+ String... expected) throws Exception {
+ System.out.println("Testing " + define + " with " + params + "...");
+ String old = Security.getProperty("drbg");
+ if (define != null) {
+ Security.setProperty("drbg", define);
+ }
+ try {
+ String result = params != null ?
+ SecureRandom.getInstance("DRBG", params).toString() :
+ SecureRandom.getInstance("DRBG").toString();
+ System.out.println("Result " + result);
+ if (expected.length == 0) {
+ throw new Exception("should fail");
+ }
+ for (String s : expected) {
+ if (!result.contains(s)) {
+ throw new Exception(result);
+ }
+ }
+ } catch (NoSuchAlgorithmException e) {
+ System.out.println("Result NSAE");
+ if (expected.length > 0) {
+ throw e;
+ }
+ } finally {
+ Security.setProperty("drbg", old);
+ }
+ }
+
+ /**
+ * Checks DRBG definition for getInstance(alg).
+ *
+ * @param define DRBG
+ * @param expected expected actual instantiate params, empty if should fail
+ */
+ static void check(String define, String... expected) throws Exception {
+ check(define, null, expected);
+ }
+}
--- old/test/sun/security/provider/SecureRandom/SelfSeed.java 2016-04-01 19:18:17.000000000 +0800
+++ /dev/null 2016-04-01 19:18:17.000000000 +0800
@@ -1,66 +0,0 @@
-/*
- * Copyright (c) 1998, 2003, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code 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
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-/**
- * @test
- * @bug 4168409
- * @summary SecureRandom forces all instances to self-seed, even if a seed is
- * provided
- */
-
-import java.security.SecureRandom;
-
-public class SelfSeed {
-
- private static final int NUM_BYTES = 5;
- private static byte seed[] = { (byte)0xaa, (byte)0x11, (byte)0xa1 };
-
- public static void main(String[] args) {
-
- try {
- SecureRandom sr1 = SecureRandom.getInstance("SHA1PRNG");
- sr1.setSeed(seed);
- byte randomBytes[] = new byte[NUM_BYTES];
- sr1.nextBytes(randomBytes);
-
- SecureRandom sr2 = new SecureRandom(seed);
- if (sr2.getAlgorithm().equals("SHA1PRNG") == false) {
- System.out.println("Default PRNG is not SHA1PRNG, skipping test");
- return;
- }
- byte otherRandomBytes[] = new byte[NUM_BYTES];
- sr2.nextBytes(otherRandomBytes);
-
- // make sure the random bytes generated are the same
- for (int i = 0; i < NUM_BYTES; i++) {
- if (randomBytes[i] != otherRandomBytes[i])
- throw new SecurityException("FAILURE: " +
- "Returned bytes not equal");
- }
-
- // success
- } catch (Exception e) {
- throw new SecurityException("FAILURE: " + e.toString());
- }
- }
-}