--- 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 @@ * * FIPS 140-2, Security Requirements for Cryptographic Modules, * 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 * * RFC 4086: Randomness Requirements for Security. * - *

A caller obtains a SecureRandom instance via the - * no-argument constructor or one of the {@code getInstance} methods: - * - *

- *      SecureRandom random = new SecureRandom();
- * 
- * - *

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. + *

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. * - *

Typical callers of SecureRandom invoke the following methods + *

A caller obtains a {@code SecureRandom} instance via the + * no-argument constructor or one of the {@code getInstance} methods. + * For example: + * + *

+ * SecureRandom r1 = new SecureRandom();
+ * SecureRandom r2 = SecureRandom.getInstance("NativePRNG");
+ * SecureRandom r3 = SecureRandom("DRBG",
+ *         DrbgParameters.Instantiate(128, RESEED_ONLY, null));
+ * 
+ * + *

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. + * + *

Typical callers of {@code SecureRandom} invoke the following methods * to retrieve random bytes: * - *

- *      SecureRandom random = new SecureRandom();
- *      byte[] bytes = new byte[20];
- *      random.nextBytes(bytes);
- * 
+ *
+ * SecureRandom random = new SecureRandom();
+ * byte[] bytes = new byte[20];
+ * random.nextBytes(bytes);
+ * 
* - *

Callers may also invoke the {@code generateSeed} method + *

Callers may also invoke the {@link #generateSeed} method * to generate a given number of seed bytes (to seed other random number * generators, for example): - *

- *      byte[] seed = random.generateSeed(20);
- * 
- * - * 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. + * + *
+ * byte[] seed = random.generateSeed(20);
+ * 
+ * + *

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. + * + *

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. + * + *

Please note that {@code reseed} is not always supported. + * + *

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. + * + *

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 @@ * *

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. * *

Note that the list of registered providers may be retrieved via * the {@link Security#getProviders() Security.getProviders()} method. * - *

See the SecureRandom section in the See the {@code SecureRandom} section in the * Java Cryptography Architecture Standard Algorithm Name Documentation * for information about standard RNG algorithm names. - * - *

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. * *

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. * *

Note that the list of registered providers may be retrieved via * the {@link Security#getProviders() Security.getProviders()} method. * - *

See the SecureRandom section in the See the {@code SecureRandom} section in the * Java Cryptography Architecture Standard Algorithm Name Documentation * 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. * *

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. * *

Note that the list of registered providers may be retrieved via * the {@link Security#getProviders() Security.getProviders()} method. * - *

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 * Java Cryptography Architecture Standard Algorithm Name Documentation * 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. * - *

A new SecureRandom object encapsulating the - * SecureRandomSpi implementation from the specified provider + *

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. * *

Note that the list of registered providers may be retrieved via * the {@link Security#getProviders() Security.getProviders()} method. * - *

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 * Java Cryptography Architecture Standard Algorithm Name Documentation * 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. * - *

A new SecureRandom object encapsulating the - * SecureRandomSpi implementation from the specified Provider - * object is returned. Note that the specified Provider object + *

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. * - *

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 * Java Cryptography Architecture Standard Algorithm Name Documentation * 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. + * + *

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. + * + *

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 + * Java Cryptography Architecture Standard Algorithm Name Documentation + * 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. + * + *

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. + * + *

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 + * Java Cryptography Architecture Standard Algorithm Name Documentation + * 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. + * + *

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 + * Java Cryptography Architecture Standard Algorithm Name Documentation + * 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}. + *

+ * 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. + *

+ * 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. + *

+ * 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. * - *

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 @@ * *

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. + *

+ * 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 Service Provider Interface (SPI) - * for the {@code SecureRandom} class. + * for the {@link SecureRandom} class. + *

* 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 + * without 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 with a {@code SecureRandomInstantiateParameters} argument, + * the constructor will be called with that argument. The + * {@link #engineGetParameters()} method must not return {@code null}. + *

+ * 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 without a + * {@code SecureRandomInstantiateParameters} argument. Calling one of + * {@code SecureRandom}'s {@code getInstance} methods with + * 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. * - *

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. + *

+ * 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. + *

+ * According to + * + * NIST Special Publication 800-90A Revision 1, Recommendation for Random Number + * Generation Using Deterministic Random Bit Generators, + *

+ * 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." + *
+ *

+ * A DRBG implementation has a configuration, including but not limited to, + *

+ *

+ * The configuration is defined by the implementation and not managed + * by the {@code SecureRandom} API. + *

+ * 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. + *

+ * 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. + *

+ * 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. + *

+ * 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)}. + *

+ * A DRBG might reseed itself automatically if the seed period is bigger + * than the maximum seed life defined by the DRBG mechanism. + *

+ * Examples: + *

+ * 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()));
+ * 
+ * + * @implSpec + * By convention, a provider should name its primary DRBG implementation + * with the + * standard {@code SecureRandom} algorithm name "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. + *

+ * 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. + *

+ * 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. + *

+ * 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. + *

+ * 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. + *

+ * 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. + *

+ * This implementation reads fresh entropy from the system default entropy + * source determined by the security property {@code securerandom.source}. + *

+ * This implementation has passed all tests included in the 20151104 version of + * + * The DRBG Test Vectors. + *

+ * 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. + *

+ * 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. + *

+ * 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. + *

+ * 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. + *

+ * 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. + *

+ * The table below lists possible effective values if a certain + * capability is requested, i.e. + *

+         * Capability req = ...;
+         * SecureRandom s = SecureRandom.getInstance("DRBG",
+         *         DrbgParameters(-1, req, null));
+         * Capability eff = ((DrbgParametes.Initiate) s.getParameters())
+         *         .getCapability();
+         * 
+ * + * + * + * + * + * + * + * + *
Requested Value ({@code req})Possible Effective Values ({@code eff})
NONENONE, RESEED_ONLY, PR_AND_RESEED
RESEED_ONLYRESEED_ONLY, PR_AND_RESEED
PR_AND_RESEEDPR_AND_RESEED
+ * + * @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. + *

+ * {@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. + *

+ * This class creates 5 new abstract methods. 3 are defined by the SP800-90A: + *

    + *
  1. {@link #generateAlgorithm(byte[], byte[])} + *
  2. {@link #reseedAlgorithm(byte[], byte[])} (might not be supported) + *
  3. {@link #instantiateAlgorithm(byte[])} + *
+ * and 2 for implementation purpose: + *
    + *
  1. {@link #initEngine()} + *
  2. {@link #chooseAlgorithmAndStrength} + *
+ * 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 not 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 not supported. + */ + protected boolean supportPr = true; + + /** + * Whether reseed is supported. A mechanism should update + * the value in its constructor if it is not 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. + *

+ * 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. + *

+ * If {@code requestedAlgorithm} is not provided, an algorithm will be + * chosen that supports {@code requestedStrength} + * (or {@code defaultStrength} if there is no request). + *

+ * Since every call to {@link #engineConfigure} will call this method, + * make sure to the calls do not contradict with each other. + *

+ * Here are some examples of the algorithm and strength chosen (suppose + * {@code defaultStrength} is 128) for HashDRBG: + *

+     * (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
+     * 
+ * + * @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. + *

+ * 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". + *

+ * 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 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> 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> 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> 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) + () -> 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> 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> 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 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 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()); - } - } -}