diff --git a/jdk/src/java.base/share/classes/com/sun/crypto/provider/HmacCore.java b/jdk/src/java.base/share/classes/com/sun/crypto/provider/HmacCore.java index bc865c63f47..68a263ce219 100644 --- a/jdk/src/java.base/share/classes/com/sun/crypto/provider/HmacCore.java +++ b/jdk/src/java.base/share/classes/com/sun/crypto/provider/HmacCore.java @@ -262,4 +262,14 @@ abstract class HmacCore extends MacSpi implements Cloneable { 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); + } + } } diff --git a/jdk/src/java.base/share/classes/com/sun/crypto/provider/SunJCE.java b/jdk/src/java.base/share/classes/com/sun/crypto/provider/SunJCE.java index 089a662dce5..e7ab016b5d9 100644 --- a/jdk/src/java.base/share/classes/com/sun/crypto/provider/SunJCE.java +++ b/jdk/src/java.base/share/classes/com/sun/crypto/provider/SunJCE.java @@ -704,6 +704,12 @@ public final class SunJCE extends Provider { 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"); diff --git a/jdk/src/java.base/share/classes/java/security/DrbgParameters.java b/jdk/src/java.base/share/classes/java/security/DrbgParameters.java new file mode 100644 index 00000000000..f30c80da2e3 --- /dev/null +++ b/jdk/src/java.base/share/classes/java/security/DrbgParameters.java @@ -0,0 +1,543 @@ +/* + * 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 (Deterministic + * Random Bit Generator). + *
+ * According to + * + * NIST Special Publication 800-90A Revision 1, Recommendation for Random + * Number Generation Using Deterministic Random Bit Generators (800-90Ar1), + *
+ * 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." + *+ *
+ * The 800-90Ar1 specification allows for a variety of DRBG implementation + * choices, such as: + *
+ * These choices are set in each implementation and are not directly + * managed by the {@code SecureRandom} API. Check your DRBG provider's + * documentation to find an appropriate implementation for the situation. + *
+ * On the other hand, the 800-90Ar1 specification does have some configurable + * options, such as: + *
+ * A DRBG instance can be instantiated with parameters from an + * {@link DrbgParameters.Instantiation} 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-90Ar1. + *
+ * A DRBG instance can be reseeded with parameters from a + * {@link DrbgParameters.Reseed} object. This maps to the + * {@code Reseed_function} defined in NIST SP 800-90Ar1. Calling + * {@link SecureRandom#reseed()} is equivalent to calling + * {@link SecureRandom#reseed(SecureRandomParameters)} with the effective + * instantiated prediction resistance flag (as returned by + * {@link SecureRandom#getParameters()}) with no additional input. + *
+ * A DRBG instance generates data with additional parameters from a + * {@link DrbgParameters.NextBytes} object. This maps to the + * {@code Generate_function} defined in NIST SP 800-90Ar1. Calling + * {@link SecureRandom#nextBytes(byte[])} is equivalent to calling + * {@link SecureRandom#nextBytes(byte[], SecureRandomParameters)} + * with the effective instantiated strength and prediction resistance flag + * (as returned by {@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 the 1-arg + * {@linkplain SecureRandomSpi#SecureRandomSpi(SecureRandomParameters) constructor} + * that takes a {@code DrbgParameters.Instantiation} 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 SecureRandomParameters} + * parameter, the parameter is passed into this constructor. If it is chosen + * by a {@code SecureRandom.getInstance()} without a + * {@code SecureRandomParameters} 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 {@code DrbgParameters.Instantiation} 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 DrbgParameters.Instantiation} object passed + * into the {@code SecureRandom.getInstance()} call. For example, + * the requested capability can be {@link DrbgParameters.Capability#NONE} + * but the effective value can be {@link DrbgParameters.Capability#RESEED_ONLY} + * if the implementation supports reseeding. The implementation must implement + * the {@link SecureRandomSpi#engineNextBytes(byte[], SecureRandomParameters)} + * method which takes a {@code DrbgParameters.NextBytes} parameter. Unless + * the result of {@link SecureRandom#getParameters()} has its + * {@linkplain DrbgParameters.Instantiation#getCapability() capability} being + * {@link Capability#NONE NONE}, it must implement + * {@link SecureRandomSpi#engineReseed(SecureRandomParameters)} which takes + * a {@code DrbgParameters.Reseed} parameter. + *
+ * On the other hand, if a DRBG implementation does not contain a constructor + * that has an {@code DrbgParameters.Instantiation} argument (not recommended), + * it can only be chosen by a {@code SecureRandom.getInstance()} without + * a {@code SecureRandomParameters} parameter, but will not be chosen if + * a {@code getInstance} method with a {@code SecureRandomParameters} 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[], SecureRandomParameters)} + * or {@link SecureRandomSpi#engineReseed(SecureRandomParameters)}. + *
+ * A DRBG might reseed itself automatically if the seed period is bigger + * than the maximum seed life defined by the DRBG mechanism. + *
+ * A DRBG implementation should support serialization and deserialization + * by retaining the configuration and effective parameters, but the internal + * state must not be serialized and the deserialized object must be + * reinstantiated. + *
+ * Examples: + *
+ * + * @implSpec + * By convention, a provider should name its primary DRBG implementation + * with the + * standard {@code SecureRandom} algorithm name "DRBG". + * + * @implNote + * The following notes apply to the "DRBG" implementation in the SUN provider + * of the JDK reference implementation. + *+ * SecureRandom drbg; + * byte[] buffer = new byte[32]; + * + * // Any DRBG is OK + * drbg = SecureRandom.getInstance("DRBG"); + * drbg.nextBytes(buffer); + * + * SecureRandomParameters params = drbg.getParameters(); + * if (params instanceof DrbgParameters.Instantiation) { + * DrbgParameters.Instantiation ins = (DrbgParameters.Instantiation) params; + * if (ins.getCapability().supportsReseeding()) { + * drbg.reseed(); + * } + * } + * + * // The following call requests a weak DRBG instance. It is only + * // guaranteed to support 112 bits of security strength. + * drbg = SecureRandom.getInstance("DRBG", + * DrbgParameters.instantiation(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())); + * + * // The following call requests a strong DRBG instance, with a + * // personalization string. If it successfully returns an instance, + * // that instance is guaranteed to support 256 bits of security strength + * // with prediction resistance available. + * drbg = SecureRandom.getInstance("DRBG", DrbgParameters.instantiation( + * 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()));+ *
+ * This implementation supports the Hash_DRBG and HMAC_DRBG mechanisms with + * DRBG algorithm 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 3KeyTDEA + * (also known as DESede in JCE), AES-128, AES-192 and AES-256. + *
+ * The mechanism name and DRBG algorithm name are determined by the + * {@linkplain Security#getProperty(String) security property} + * {@code securerandom.drbg.config}. The default choice is Hash_DRBG + * with SHA-256. + *
+ * For each combination, the security strength can be requested from 112 + * up to the highest strength it supports. Both reseeding and prediction + * resistance are supported. + *
+ * Personalization string is supported through the + * {@link DrbgParameters.Instantiation} 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.Instantiation} + * object explicitly, this implementation instantiates it with a default + * requested strength of 128 bits (112 bits for CTR_DRBG with 3KeyTDEA), + * no prediction resistance request, and no personalization string. + * These default instantiation parameters can also be customized with + * the {@code securerandom.drbg.config} security property. + *
+ * This implementation reads fresh entropy from the system default entropy + * source determined by the security property {@code securerandom.source}. + *
+ * Calling {@link SecureRandom#generateSeed(int)} will directly read + * from this system default entropy source. + *
+ * This implementation has passed all tests included in the 20151104 version of + * + * The DRBG Test Vectors. + * + * @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 passed to a {@code SecureRandom.getInstance()} call, + * it is the requested minimum capability. When it's returned from + * {@code SecureRandom.getParameters()}, it is the effective capability. + *
+ * Please note that while the {@code Instantiate_function} defined in + * NIST SP 800-90Ar1 only includes a {@code prediction_resistance_flag} + * parameter, the {@code Capability} type includes an extra value + * {@link #RESEED_ONLY} because reseeding is an optional function. + * If {@code NONE} is used in an {@code Instantiation} object in calling the + * {@code SecureRandom.getInstance} method, the returned DRBG instance + * is not guaranteed to support reseeding. If {@code RESEED_ONLY} or + * {@code PR_AND_RESEED} is used, the instance must support reseeding. + *
+ * The table below lists possible effective values if a certain + * capability is requested, i.e. + *
+ *+ * Capability requested = ...; + * SecureRandom s = SecureRandom.getInstance("DRBG", + * DrbgParameters(-1, requested, null)); + * Capability effective = ((DrbgParametes.Initiate) s.getParameters()) + * .getCapability();+ *
Requested Value | + *Possible Effective Values | + *
---|---|
NONE | NONE, RESEED_ONLY, PR_AND_RESEED |
RESEED_ONLY | RESEED_ONLY, PR_AND_RESEED |
PR_AND_RESEED | PR_AND_RESEED |
+ * A DRBG implementation supporting prediction resistance must also + * support reseeding. + * + * @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); + } + + /** + * Returns whether this capability supports reseeding. + * + * @return {@code true} for {@link #PR_AND_RESEED} and + * {@link #RESEED_ONLY}, and {@code false} for {@link #NONE} + */ + public boolean supportsReseeding() { + return this != NONE; + } + + /** + * Returns whether this capability supports prediction resistance. + * + * @return {@code true} for {@link #PR_AND_RESEED}, and {@code false} + * for {@link #RESEED_ONLY} and {@link #NONE} + */ + public boolean supportsPredictionResistance() { + return this == PR_AND_RESEED; + } + } + + /** + * DRBG parameters for instantiation. + *
+ * When used in + * {@link SecureRandom#getInstance(String, SecureRandomParameters)} + * or one of the other similar {@code getInstance} calls that take a + * {@code SecureRandomParameters} parameter, it means the + * requested instantiate parameters the newly created {@code SecureRandom} + * object must minimally 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 Instantiation + implements SecureRandomParameters { + + private final int strength; + private final Capability capability; + private final byte[] personalizationString; + + /** + * Returns the security strength in bits. + * + * @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 effective strength. + * The effective strength must be greater than or equal to the minimum + * strength requested. + */ + public int getStrength() { + return strength; + } + + /** + * Returns the capability. + * + * @return If used in {@code getInstance}, returns the minimum + * capability requested. If used in {@code getParameters}, returns + * information on the effective prediction resistance flag 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 Instantiation(int strength, Capability capability, + byte[] personalizationString) { + this.strength = strength; + this.capability = capability; + this.personalizationString = (personalizationString == null) ? + null : personalizationString.clone(); + } + + /** + * Returns a Human-readable string representation of this + * {@code Instantiation}. + * + * @return the string representation + */ + @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[], SecureRandomParameters)}. + * + * @since 9 + */ + public static final class NextBytes + implements SecureRandomParameters { + private final int strength; + private final boolean predictionResistance; + private final byte[] additionalInput; + + /** + * Returns the security strength requested in bits. + * + * @return the strength requested, or -1 if the effective 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(SecureRandomParameters)}. + * + * @since 9 + */ + public static final class Reseed implements SecureRandomParameters { + + 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, or {@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.Instantiation} object. + * + * @param strength security strength in bits, -1 for 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 Instantiation} object + * @throws NullPointerException if {@code capability} is {@code null} + */ + public static Instantiation instantiation(int strength, + Capability capability, + byte[] personalizationString) { + return new Instantiation(strength, Objects.requireNonNull(capability), + personalizationString); + } + + /** + * Generates a {@link NextBytes} object. + * + * @param strength requested security strength in bits. If set to -1, the + * effective strength will 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); + } +} diff --git a/jdk/src/java.base/share/classes/java/security/Provider.java b/jdk/src/java.base/share/classes/java/security/Provider.java index e192d23cbbe..7e3249cec18 100644 --- a/jdk/src/java.base/share/classes/java/security/Provider.java +++ b/jdk/src/java.base/share/classes/java/security/Provider.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2015, Oracle and/or its affiliates. All rights reserved + * Copyright (c) 1996, 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 @@ -142,8 +142,35 @@ public abstract class Provider extends Properties { 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 where both styles of constructors are supported. + // Before jdk9, there was no params support (only getInstance(alg)) + // and an impl only had the params-less constructor. Since jdk9, + // there is getInstance(alg,params) and an impl can contain + // an Impl(params) constructor. + try { + Constructor> con = clazz.getConstructor(ctrParamClz); + return con.newInstance(ctorParamObj); + } catch (NoSuchMethodException nsme) { + // For pre-jdk9 SecureRandom implementations, they only + // have params-less constructors which still works when + // the input ctorParamObj is null. + // + // For other primitives using params, ctorParamObj should not + // be null and nsme is thrown, just like before. + if (ctorParamObj == null) { + try { + Constructor> con = clazz.getConstructor(); + return con.newInstance(); + } catch (NoSuchMethodException nsme2) { + nsme.addSuppressed(nsme2); + throw nsme; + } + } else { + throw nsme; + } + } } } @@ -1384,7 +1411,8 @@ public abstract class Provider extends Properties { addEngine("KeyPairGenerator", false, null); addEngine("KeyStore", false, null); addEngine("MessageDigest", false, null); - addEngine("SecureRandom", false, null); + addEngine("SecureRandom", false, + "java.security.SecureRandomParameters"); addEngine("Signature", true, null); addEngine("CertificateFactory", false, null); addEngine("CertPathBuilder", false, null); @@ -1678,6 +1706,7 @@ public abstract class Provider extends Properties { } } } + // constructorParameter can be null if not provided return newInstanceUtil(getImplClass(), ctrParamClz, constructorParameter); } catch (NoSuchAlgorithmException e) { throw e; diff --git a/jdk/src/java.base/share/classes/java/security/SecureRandom.java b/jdk/src/java.base/share/classes/java/security/SecureRandom.java index da7329fb9e3..f8832f049ce 100644 --- a/jdk/src/java.base/share/classes/java/security/SecureRandom.java +++ b/jdk/src/java.base/share/classes/java/security/SecureRandom.java @@ -38,52 +38,87 @@ import sun.security.util.Debug; * This class provides a cryptographically strong random number * generator (RNG). * - *
A cryptographically strong random number - * minimally complies with the statistical random number generator tests - * specified in + *
A cryptographically strong random number minimally complies with the + * statistical random number generator tests specified in * * 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.Instantiation(128, RESEED_ONLY, null));+ *
The third statement above returns a {@code SecureRandom} object of the + * specific algorithm supporting the specific instantiate parameters. The + * implementation's effective instantiated parameters 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 right after it's created and {@link #getParameters()} should + * always return the same result 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} may not be supported by all + * {@code SecureRandom} implementations. + * + *
Some {@code SecureRandom} implementations may accept a + * {@link SecureRandomParameters} parameter in its + * {@link #nextBytes(byte[], SecureRandomParameters)} and + * {@link #reseed(SecureRandomParameters)} methods 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 +167,19 @@ public class SecureRandom extends java.util.Random { * *
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 +194,20 @@ public class SecureRandom extends java.util.Random { /** * 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. @@ -225,9 +253,9 @@ public class SecureRandom extends java.util.Random { } /** - * 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 +277,18 @@ public class SecureRandom extends java.util.Random { } /** - * 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} @@ -277,15 +298,15 @@ public class SecureRandom extends java.util.Random { * {@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 @@ -295,49 +316,42 @@ public class SecureRandom extends java.util.Random { 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 * @@ -352,36 +366,29 @@ public class SecureRandom extends java.util.Random { } /** - * 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 * @@ -396,24 +403,178 @@ public class SecureRandom extends java.util.Random { } /** - * 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 SecureRandomParameters} 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 SecureRandomParameters} 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 SecureRandomParameters} + * 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, SecureRandomParameters params) + throws NoSuchAlgorithmException { + if (params == null) { + throw new IllegalArgumentException("params cannot be null"); + } + Instance instance = GetInstance.getInstance("SecureRandom", + SecureRandomSpi.class, algorithm, params); + return new SecureRandom((SecureRandomSpi)instance.impl, + instance.provider, algorithm); + } + + /** + * Returns a {@code SecureRandom} object that implements the specified + * Random Number Generator (RNG) algorithm and supports the specified + * {@code SecureRandomParameters} 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 SecureRandomParameters} + * 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, + SecureRandomParameters 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); + return new SecureRandom((SecureRandomSpi)instance.impl, + instance.provider, algorithm); + } + + /** + * Returns a {@code SecureRandom} object that implements the specified + * Random Number Generator (RNG) algorithm and supports the specified + * {@code SecureRandomParameters} 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 SecureRandomParameters} + * 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, + SecureRandomParameters 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); + return new SecureRandom((SecureRandomSpi)instance.impl, + 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 - * object. + * Returns the name of the algorithm implemented by this + * {@code SecureRandom} object. * * @return the name of the algorithm or {@code unknown} * if the algorithm name cannot be determined. @@ -424,9 +585,49 @@ public class SecureRandom extends java.util.Random { } /** - * Reseeds this random object. The given seed supplements, rather than - * replaces, the existing seed. Thus, repeated calls are guaranteed - * never to reduce randomness. + * Returns a Human-readable string representation of this + * {@code SecureRandom}. + * + * @return the string representation + * + * @since 9 + */ + @Override + public String toString() { + return secureRandomSpi.toString(); + } + + /** + * Returns the effective {@link SecureRandomParameters} for this + * {@code SecureRandom} instance. + *
+ * The returned value can be different from the + * {@code SecureRandomParameters} 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 effective {@link SecureRandomParameters} parameters, + * or {@code null} if no parameters were used. + * + * @since 9 + * @see SecureRandomSpi + */ + public SecureRandomParameters 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. * @@ -458,18 +659,13 @@ public class SecureRandom extends java.util.Random { * yet been initialized at that point. */ if (seed != 0) { - secureRandomSpi.engineSetSeed(longToByteArray(seed)); + this.secureRandomSpi.engineSetSeed(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. */ @Override @@ -477,6 +673,28 @@ public class SecureRandom extends java.util.Random { secureRandomSpi.engineNextBytes(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}, + * illegal or unsupported by this {@code SecureRandom} + * + * @since 9 + */ + public synchronized void nextBytes( + byte[] bytes, SecureRandomParameters params) { + if (params == null) { + throw new IllegalArgumentException("params cannot be null"); + } + secureRandomSpi.engineNextBytes(Objects.requireNonNull(bytes), params); + } + /** * Generates an integer containing the user-specified number of * pseudo-random bits (right justified, with leading zeros). This @@ -512,7 +730,7 @@ public class SecureRandom extends java.util.Random { * *
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. * @@ -537,10 +755,13 @@ public class SecureRandom extends java.util.Random { * 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); } @@ -562,8 +783,8 @@ public class SecureRandom extends java.util.Random { /** * 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()) { @@ -667,6 +888,42 @@ public class SecureRandom extends java.util.Random { "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}, + * illegal or unsupported by this {@code SecureRandom} + * + * @since 9 + */ + public synchronized void reseed(SecureRandomParameters 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; @@ -685,7 +942,7 @@ public class SecureRandom extends java.util.Random { * 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; /** diff --git a/jdk/src/java.base/share/classes/java/security/SecureRandomParameters.java b/jdk/src/java.base/share/classes/java/security/SecureRandomParameters.java new file mode 100644 index 00000000000..bedf94e4ea5 --- /dev/null +++ b/jdk/src/java.base/share/classes/java/security/SecureRandomParameters.java @@ -0,0 +1,38 @@ +/* + * 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 various {@code SecureRandom} + * methods. + *
+ * Some {@code SecureRandom} implementations might require additional + * operational parameters. Objects of classes which implement this interface + * can be passed to those implementations that support them. + * + * @see DrbgParameters + */ +public interface SecureRandomParameters { +} diff --git a/jdk/src/java.base/share/classes/java/security/SecureRandomSpi.java b/jdk/src/java.base/share/classes/java/security/SecureRandomSpi.java index ef6c2433630..9aa24f57bc8 100644 --- a/jdk/src/java.base/share/classes/java/security/SecureRandomSpi.java +++ b/jdk/src/java.base/share/classes/java/security/SecureRandomSpi.java @@ -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 @@ package java.security; /** * 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(SecureRandomParameters)} + * 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 SecureRandomParameters} parameter, + * the constructor will be called with a {@code null} argument and the + * implementation is responsible for creating its own + * {@code SecureRandomParameters} 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 SecureRandomParameters} argument, + * the constructor will be called with that argument. The + * {@link #engineGetParameters()} method must not return {@code null}. + *
+ * Otherwise, if the {@code SecureRandomSpi(SecureRandomParameters)} + * 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 SecureRandomParameters} argument. Calling one of + * {@code SecureRandom}'s {@code getInstance} methods with + * a {@code SecureRandomParameters} 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 @@ public abstract class SecureRandomSpi implements java.io.Serializable { 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 SecureRandomParameters} object. + * This argument can be {@code null}. + * @throws IllegalArgumentException if {@code params} is + * unrecognizable or unsupported by this {@code SecureRandom} + * + * @since 9 + */ + protected SecureRandomSpi(SecureRandomParameters 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. */ @@ -52,16 +98,44 @@ public abstract class SecureRandomSpi implements java.io.Serializable { /** * 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. + *
+ * Some random number generators can only generate a limited amount + * of random bytes per invocation. If the size of {@code bytes} + * is greater than this limit, the implementation should invoke + * its generation process multiple times to completely fill the + * buffer before returning from this method. * * @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. + *
+ * Some random number generators can only generate a limited amount + * of random bytes per invocation. If the size of {@code bytes} + * is greater than this limit, the implementation should invoke + * its generation process multiple times to completely fill the + * buffer before returning from this method. + * + * @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}, + * illegal or unsupported by this {@code SecureRandom} + * + * @since 9 + */ + protected void engineNextBytes( + byte[] bytes, SecureRandomParameters params) { + throw new UnsupportedOperationException(); + } + /** * Returns the given number of seed bytes. This call may be used to * seed other random number generators. @@ -70,5 +144,58 @@ public abstract class SecureRandomSpi implements java.io.Serializable { * * @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}. + *
+ * Do not override this method if the implementation does not + * support reseeding. + * + * @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 + * illegal or unsupported by this {@code SecureRandom} + * + * @since 9 + */ + protected void engineReseed(SecureRandomParameters params) { + throw new UnsupportedOperationException(); + } + + /** + * Returns the effective {@link SecureRandomParameters} for this + * {@code SecureRandom} instance. + * + * @implSpec The default implementation returns {@code null}. + * + * @return the effective {@link SecureRandomParameters} parameters, + * or {@code null} if no parameters were used. + * + * @since 9 + */ + protected SecureRandomParameters engineGetParameters() { + return null; + } + + /** + * Returns a Human-readable string representation of this + * {@code SecureRandom}. + * + * @return the string representation + * + * @since 9 + */ + @Override + public String toString() { + return getClass().getSimpleName(); + } } diff --git a/jdk/src/java.base/share/classes/sun/security/provider/AbstractDrbg.java b/jdk/src/java.base/share/classes/sun/security/provider/AbstractDrbg.java new file mode 100644 index 00000000000..c4091eb39d5 --- /dev/null +++ b/jdk/src/java.base/share/classes/sun/security/provider/AbstractDrbg.java @@ -0,0 +1,771 @@ +/* + * 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.Objects; +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: + *
+ * Synchronized keyword should be added to all externally callable engine + * methods including {@link #engineReseed}, {@link #engineSetSeed}, and + * {@link #engineNextBytes} (but not {@link #engineGenerateSeed}). + * Internal methods like {@link #configure} and {@link #instantiateAlgorithm} + * are not synchronized. They will either be called in a constructor or + * in another synchronized method. + */ +public abstract class AbstractDrbg extends SecureRandomSpi { + + 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 transient 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 transient 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. + * + * Remember to sync with "securerandom.drbg.config" in java.security. + */ + protected static final int DEFAULT_STRENGTH = 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 highestSupportedSecurityStrength = 256; + + /** + * Whether prediction resistance is supported. A mechanism should update + * the value in its constructor if it is not supported. + */ + protected boolean supportPredictionResistance = true; + + /** + * Whether reseed is supported. A mechanism should update + * the value in its constructor if it is not supported. + */ + protected boolean supportReseeding = 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 maxPersonalizationStringLength + // or maxAdditionalInputLength 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}. + *
+ * In theory this value (and the values below) can be bigger than + * {@code Integer.MAX_VALUE} but a Java array can only have an int32 index. + */ + 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 maxPersonalizationStringLength = 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 maxAdditionalInputLength = 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 maxNumberOfBytesPerRequest = 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()} and {@link DRBG#algorithmName}. + */ + 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 securityStrength; // in bits + + /** + * Strength requested in {@link DrbgParameters.Instantiation}. + * The real strength is based on it. Do not modify it in a mechanism. + */ + protected int requestedInstantiationSecurityStrength = -1; + + /** + * The personalization string used by this instance. Set inside + * {@link #configure(SecureRandomParameters)} and + * can be used in a mechanism. Do not modify it in a mechanism. + */ + protected byte[] personalizationString; + + /** + * The prediction resistance flag used by this instance. Set inside + * {@link #configure(SecureRandomParameters)}. + */ + private boolean predictionResistanceFlag; + + // 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 transient 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 entropy source used by this instance. Set inside + * {@link #configure(SecureRandomParameters)}. 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 #configure}. A mechanism uses + * {@link #requestedAlgorithm}, + * {@link #requestedInstantiationSecurityStrength}, and + * {@link #DEFAULT_STRENGTH} to decide which algorithm and strength to use. + *
+ * If {@code requestedAlgorithm} is provided, it will always be used. + * If {@code requestedInstantiationSecurityStrength} 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 requestedInstantiationSecurityStrength} + * (or {@code DEFAULT_STRENGTH} if there is no request). + *
+ * Since every call to {@link #configure} 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 DEFAULT_STRENGTH} is 128) for HashDRBG: + *
+ * requested effective + * (SHA-1, -1) (SHA-1,128) + * (SHA-1, 112) (SHA-1,112) + * (SHA-1, 192) IAE + * (SHA-256, -1) (SHA-256,128) + * (SHA-256, 128) (SHA-256,128) + * (SHA-3, -1) IAE + * (null, -1) (SHA-256,128) + * (null, 112) (SHA-256,112) + * (null, 192) (SHA-256,192) + * (null, 256) (SHA-256,256) + * (null, 384) IAE + *+ * + * @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 #maxAdditionalInputLength} + */ + 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 #maxAdditionalInputLength} + * @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, predictionResistanceFlag, null)); + } + + @Override + protected final void engineNextBytes( + byte[] result, SecureRandomParameters params) { + + Objects.requireNonNull(result); + + if (debug != null) { + debug.println(this, "nextBytes"); + } + if (params instanceof DrbgParameters.NextBytes) { + + // 800-90Ar1 9.3: Generate Process. + + DrbgParameters.NextBytes dp = (DrbgParameters.NextBytes) params; + + // Step 2: max_number_of_bits_per_request + if (result.length > maxNumberOfBytesPerRequest) { + // generateAlgorithm should be called multiple times to fill + // up result. Unimplemented since maxNumberOfBytesPerRequest + // is now Integer.MAX_VALUE. + } + + // Step 3: check requested_security_strength + if (dp.getStrength() > securityStrength) { + throw new IllegalArgumentException("strength too high: " + + dp.getStrength()); + } + + // Step 4: check max_additional_input_length + byte[] ai = dp.getAdditionalInput(); + if (ai != null && ai.length > maxAdditionalInputLength) { + throw new IllegalArgumentException("ai too long: " + + ai.length); + } + + // Step 5: check prediction_resistance_flag + boolean pr = dp.getPredictionResistance(); + if (!predictionResistanceFlag && pr) { + throw new IllegalArgumentException("pr not available"); + } + + instantiateIfNecessary(null); + + // Step 7: Auto reseed + if (reseedCounter > reseedInterval || pr) { + reseedAlgorithm(getEntropyInput(pr), ai); + ai = null; + } + + // Step 8, 10: Generate_algorithm + // Step 9: Unnecessary. reseedCounter only updated after generation + generateAlgorithm(result, ai); + + // Step 11: Return + } else { + throw new IllegalArgumentException("unknown params type:" + + params.getClass()); + } + } + + @Override + public final void engineReseed(SecureRandomParameters params) { + if (debug != null) { + debug.println(this, "reseed with params"); + } + if (!supportReseeding) { + throw new UnsupportedOperationException("Reseed not supported"); + } + if (params == null) { + params = DrbgParameters.reseed(predictionResistanceFlag, null); + } + if (params instanceof DrbgParameters.Reseed) { + DrbgParameters.Reseed dp = (DrbgParameters.Reseed) params; + + // 800-90Ar1 9.2: Reseed Process. + + // Step 2: Check prediction_resistance_request + boolean pr = dp.getPredictionResistance(); + if (!predictionResistanceFlag && pr) { + throw new IllegalArgumentException("pr not available"); + } + + // Step 3: Check additional_input length + byte[] ai = dp.getAdditionalInput(); + if (ai != null && ai.length > maxAdditionalInputLength) { + throw new IllegalArgumentException("ai too long: " + + ai.length); + } + instantiateIfNecessary(null); + + // Step 4: Get_entropy_input + // Step 5: Check step 4 + // Step 6-7: Reseed_algorithm + reseedAlgorithm(getEntropyInput(pr), ai); + + // Step 8: Return + } else { + throw new IllegalArgumentException("unknown params type: " + + params.getClass()); + } + } + + /** + * Returns the given number of seed bytes. A DRBG always uses + * {@link SeedGenerator} to get an array with full-entropy. + *
+ * The implementation is identical to SHA1PRNG's + * {@link SecureRandom#engineGenerateSeed}. + * + * @param numBytes the number of seed bytes to generate. + * @return the seed bytes. + */ + @Override + public final byte[] engineGenerateSeed(int numBytes) { + byte[] b = new byte[numBytes]; + SeedGenerator.generateSeed(b); + return b; + } + + /** + * 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) { + if (debug != null) { + debug.println(this, "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 minEntropy or minLength? + // + // Technically it should be minEntropy, but CtrDRBG + // (not using derivation function) is so confusing + // (does it need only strength or seedlen of entropy?) + // that it's safer to assume minLength. In all other + // cases minLength equals to minEntropy. + return getEntropyInput(minLength, minLength, maxLength, isPr); + } + + private byte[] getEntropyInput(int minEntropy, int minLength, + int maxLength, boolean pr) { + if (debug != null) { + debug.println(this, "getEntropy(" + minEntropy + "," + minLength + + "," + maxLength + "," + pr + ")"); + } + EntropySource esNow = es; + if (esNow == null) { + esNow = pr ? SeederHolder.prseeder : SeederHolder.seeder; + } + return esNow.getEntropy(minEntropy, minLength, maxLength, 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.
+ */
+ private final static EntropySource defaultES =
+ (minE, 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;
+ // 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.
+ HashDrbg first = new HashDrbg(new MoreDrbgParameters(
+ prseeder, null, "SHA-256", null, false,
+ DrbgParameters.instantiation(
+ 256, NONE,
+ SeedGenerator.getSystemEntropy())));
+ seeder = (entropy, minLen, maxLen, pr) -> {
+ if (pr) {
+ // This SEI does not support pr
+ throw new IllegalArgumentException("pr not supported");
+ }
+ byte[] result = new byte[minLen];
+ first.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 #highestSupportedSecurityStrength},
+ * {@link #supportPredictionResistance}, {@link #supportReseeding}
+ * or other features like {@link #DEFAULT_STRENGTH}. Finally it shall
+ * call {@link #configure} on {@code params}.
+ *
+ * @param params the {@link SecureRandomParameters} object.
+ * This argument can be {@code null}.
+ * @throws IllegalArgumentException if {@code params} is
+ * inappropriate for this SecureRandom.
+ */
+ protected AbstractDrbg(SecureRandomParameters params) {
+ // Nothing
+ }
+
+ /**
+ * Returns the current configuration as a {@link DrbgParameters.Instantiation}
+ * object.
+ *
+ * @return the curent configuration
+ */
+ @Override
+ protected SecureRandomParameters engineGetParameters() {
+ // Or read from variable.
+ return DrbgParameters.instantiation(
+ securityStrength,
+ predictionResistanceFlag ? PR_AND_RESEED :
+ (supportReseeding ? RESEED_ONLY : NONE),
+ personalizationString);
+ }
+
+ /**
+ * Configure this DRBG. This method calls
+ * {@link #chooseAlgorithmAndStrength()} and {@link #initEngine()}
+ * but does not do the actual instantiation.
+ *
+ * @param params configuration, if null, default configuration (default
+ * strength, pr_false, no personalization string) is used.
+ * @throws IllegalArgumentException if {@code params} is
+ * inappropriate for this SecureRandom.
+ */
+ protected final synchronized void configure(
+ SecureRandomParameters params) {
+ if (debug != null) {
+ debug.println(this, "configure " + this + " with " + params);
+ }
+ if (params == null) {
+ params = DrbgParameters.instantiation(-1, RESEED_ONLY, null);
+ }
+ 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.Instantiation) {
+ DrbgParameters.Instantiation inst =
+ (DrbgParameters.Instantiation) params;
+
+ // 800-90Ar1 9.1: Instantiate Process. Steps 1-5.
+
+ // Step 1: Check requested_instantiation_security_strength
+ if (inst.getStrength() > highestSupportedSecurityStrength) {
+ throw new IllegalArgumentException("strength too big: "
+ + inst.getStrength());
+ }
+
+ // Step 2: Check prediction_resistance_flag
+ if (inst.getCapability().supportsPredictionResistance()
+ && !supportPredictionResistance) {
+ throw new IllegalArgumentException("pr not supported");
+ }
+
+ // Step 3: Check personalization_string
+ byte[] ps = inst.getPersonalizationString();
+ if (ps != null && ps.length > maxPersonalizationStringLength) {
+ throw new IllegalArgumentException("ps too long: "
+ + ps.length);
+ }
+
+ if (inst.getCapability().supportsReseeding()
+ && !supportReseeding) {
+ throw new IllegalArgumentException("reseed not supported");
+ }
+ this.personalizationString = ps;
+ this.predictionResistanceFlag =
+ inst.getCapability().supportsPredictionResistance();
+ this.requestedInstantiationSecurityStrength = inst.getStrength();
+ } else {
+ throw new IllegalArgumentException("unknown params: "
+ + params.getClass());
+ }
+ }
+
+ // Step 4: Set security_strength
+ chooseAlgorithmAndStrength();
+ instantiated = false;
+
+ // Step 5: no-op.
+
+ if (debug != null) {
+ debug.println(this, "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) {
+
+ // 800-90Ar1 9.1: Instantiate Process. Steps 6-12.
+
+ // Step 6: Get_entropy_input
+ // Step 7: check error (getEntropyInput throw no exception now)
+ if (entropy == null) {
+ entropy = getEntropyInput(predictionResistanceFlag);
+ }
+
+ // Step 8. nonce
+ if (requestedNonce != null) {
+ nonce = requestedNonce;
+ } else {
+ nonce = NonceProvider.next();
+ }
+ initEngine();
+
+ // Step 9-11: Instantiate_algorithm
+ instantiateAlgorithm(entropy);
+ instantiated = true;
+
+ // Step 12: Return
+ }
+ }
+
+ // Nonce provider
+
+ private static class NonceProvider {
+
+ // 128 bits of nonce can be used by 256-bit strength DRBG
+ private static final byte[] block = new byte[16];
+
+ private static synchronized byte[] next() {
+ int k = 15;
+ while ((k >= 0) && (++block[k] == 0)) {
+ k--;
+ }
+ return block.clone();
+ }
+ }
+
+ // 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
+ + "," + securityStrength + ","
+ + (predictionResistanceFlag ? "pr_and_reseed"
+ : (supportReseeding ? "reseed_only" : "none"));
+ }
+}
diff --git a/jdk/src/java.base/share/classes/sun/security/provider/AbstractHashDrbg.java b/jdk/src/java.base/share/classes/sun/security/provider/AbstractHashDrbg.java
new file mode 100644
index 00000000000..75edd923aca
--- /dev/null
+++ b/jdk/src/java.base/share/classes/sun/security/provider/AbstractHashDrbg.java
@@ -0,0 +1,160 @@
+/*
+ * 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 (requestedInstantiationSecurityStrength >= 0) {
+ int tryStrength = getStandardStrength(
+ requestedInstantiationSecurityStrength);
+ if (tryStrength > supportedStrength) {
+ throw new IllegalArgumentException(algorithm +
+ " does not support strength " +
+ requestedInstantiationSecurityStrength);
+ }
+ this.securityStrength = tryStrength;
+ } else {
+ this.securityStrength = DEFAULT_STRENGTH > supportedStrength ?
+ supportedStrength : DEFAULT_STRENGTH;
+ }
+ } else {
+ int tryStrength = (requestedInstantiationSecurityStrength < 0) ?
+ DEFAULT_STRENGTH : requestedInstantiationSecurityStrength;
+ tryStrength = getStandardStrength(tryStrength);
+ // The default algorithm which is enough for all strengths.
+ // Remember to sync with "securerandom.drbg.config" in java.security
+ algorithm = "SHA-256";
+ this.securityStrength = 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.securityStrength / 8;
+ }
+
+ @Override
+ public void instantiateAlgorithm(byte[] entropy) {
+ if (debug != null) {
+ debug.println(this, "instantiate");
+ }
+
+ // 800-90Ar1 10.1.1.2: Hash_DRBG Instantiate Process.
+ // 800-90Ar1 10.1.2.3: Hmac_DRBG Instantiate Process.
+
+ // Step 1: entropy_input || nonce || personalization_string.
+ byte[] seed = Arrays.copyOf(entropy, entropy.length + nonce.length +
+ ((personalizationString == null) ? 0
+ : personalizationString.length));
+ System.arraycopy(nonce, 0, seed, entropy.length, nonce.length);
+ if (personalizationString != null) {
+ System.arraycopy(personalizationString, 0,
+ seed, entropy.length + nonce.length,
+ personalizationString.length);
+ }
+ hashReseedInternal(seed);
+ }
+
+ @Override
+ protected void reseedAlgorithm(
+ byte[] ei,
+ byte[] additionalInput) {
+ if (debug != null) {
+ debug.println(this, "reseedAlgorithm\n" +
+ new HexDumpEncoder().encodeBuffer(ei) + "\n" +
+ ((additionalInput == null) ? "" :
+ new HexDumpEncoder().encodeBuffer(additionalInput)));
+ }
+
+ // 800-90Ar1 10.1.1.3: Hash_DRBG Reseed Process.
+ // 800-90Ar1 10.1.2.4: Hmac_DRBG Reseed Process.
+
+ // Step 1: entropy_input || additional_input.
+ 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);
+}
diff --git a/jdk/src/java.base/share/classes/sun/security/provider/CtrDrbg.java b/jdk/src/java.base/share/classes/sun/security/provider/CtrDrbg.java
new file mode 100644
index 00000000000..e1904cbbbbf
--- /dev/null
+++ b/jdk/src/java.base/share/classes/sun/security/provider/CtrDrbg.java
@@ -0,0 +1,530 @@
+/*
+ * 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;
+ private static final int AES_LIMIT;
+
+ static {
+ try {
+ AES_LIMIT = Cipher.getMaxAllowedKeyLength("AES");
+ } catch (Exception e) {
+ // should not happen
+ throw new AssertionError("Cannot detect AES", e);
+ }
+ }
+
+ private transient Cipher cipher;
+
+ private String cipherAlg;
+ private String keyAlg;
+
+ private int ctrLen;
+ private int blockLen;
+ private int keyLen;
+ private int seedLen;
+
+ private transient byte[] v;
+ private transient byte[] k;
+
+ public CtrDrbg(SecureRandomParameters params) {
+ mechName = "CTR_DRBG";
+ configure(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");
+ }
+ }
+
+ @Override
+ protected void chooseAlgorithmAndStrength() {
+ if (requestedAlgorithm != null) {
+ algorithm = requestedAlgorithm.toUpperCase();
+ int supportedStrength = alg2strength(algorithm);
+ if (requestedInstantiationSecurityStrength >= 0) {
+ int tryStrength = getStandardStrength(
+ requestedInstantiationSecurityStrength);
+ if (tryStrength > supportedStrength) {
+ throw new IllegalArgumentException(algorithm +
+ " does not support strength " +
+ requestedInstantiationSecurityStrength);
+ }
+ this.securityStrength = tryStrength;
+ } else {
+ this.securityStrength = (DEFAULT_STRENGTH > supportedStrength) ?
+ supportedStrength : DEFAULT_STRENGTH;
+ }
+ } else {
+ int tryStrength = (requestedInstantiationSecurityStrength < 0) ?
+ DEFAULT_STRENGTH : requestedInstantiationSecurityStrength;
+ tryStrength = getStandardStrength(tryStrength);
+ // Default algorithm, use AES-128 if AES-256 is not available.
+ // Remember to sync with "securerandom.drbg.config" in java.security
+ if (tryStrength <= 128 && AES_LIMIT < 256) {
+ algorithm = "AES-128";
+ } else if (AES_LIMIT >= 256) {
+ algorithm = "AES-256";
+ } else {
+ throw new IllegalArgumentException("unsupported strength " +
+ requestedInstantiationSecurityStrength);
+ }
+ this.securityStrength = 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 (AES_LIMIT < 192) {
+ throw new IllegalArgumentException(algorithm +
+ " not available (because policy) in CTR_DBRG");
+ }
+ break;
+ case "AES-256":
+ this.keyLen = 256 / 8;
+ if (AES_LIMIT < 256) {
+ throw new IllegalArgumentException(algorithm +
+ " not available (because policy) 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.securityStrength / 8;
+ } else {
+ this.minLength = this.maxLength =
+ this.maxPersonalizationStringLength =
+ this.maxAdditionalInputLength = seedLen;
+ }
+ }
+
+ /**
+ * This call, used by the constructors, instantiates the digest.
+ */
+ @Override
+ protected void initEngine() {
+ 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(this, "Key = " + hex(k));
+ debug.println(this, "V = " + hex(v));
+ debug.println(this, "reseed counter = " + reseedCounter);
+ }
+ }
+
+ // 800-90Ar1 10.2.1.2. CTR_DRBG_Update
+ private void update(byte[] input) {
+ if (input.length != seedLen) {
+ // Should not happen
+ throw new IllegalArgumentException("input length not seedLen: "
+ + input.length);
+ }
+ try {
+
+ int m = (seedLen + blockLen - 1) / blockLen;
+ byte[] temp = new byte[m * blockLen];
+
+ // Step 1. temp = Null.
+
+ // Step 2. Loop
+ for (int i = 0; i < m; i++) {
+ // Step 2.1. Increment
+ addOne(v, ctrLen);
+ // Step 2.2. Block_Encrypt
+ cipher.init(Cipher.ENCRYPT_MODE, getKey(keyAlg, k));
+ // Step 2.3. Encrypt into right position, no need to cat
+ cipher.doFinal(v, 0, blockLen, temp, i * blockLen);
+ }
+
+ // Step 3. Truncate
+ temp = Arrays.copyOf(temp, seedLen);
+
+ // Step 4: Add
+ for (int i = 0; i < seedLen; i++) {
+ temp[i] ^= input[i];
+ }
+
+ // Step 5: leftmost
+ k = Arrays.copyOf(temp, keyLen);
+
+ // Step 6: rightmost
+ v = Arrays.copyOfRange(temp, seedLen - blockLen, seedLen);
+
+ // Step 7. Return
+ } catch (GeneralSecurityException e) {
+ throw new InternalError(e);
+ }
+ }
+
+ @Override
+ protected void instantiateAlgorithm(byte[] ei) {
+ if (debug != null) {
+ debug.println(this, "instantiate");
+ }
+ byte[] more;
+ if (usedf) {
+ // 800-90Ar1 10.2.1.3.2 Step 1-2. cat bytes
+ if (personalizationString == null) {
+ more = nonce;
+ } else {
+ more = Arrays.copyOf(
+ nonce, nonce.length + personalizationString.length);
+ System.arraycopy(personalizationString, 0, more, nonce.length,
+ personalizationString.length);
+ }
+ } else {
+ // 800-90Ar1 10.2.1.3.1
+ // Step 1-2, no need to expand personalizationString, we only XOR
+ // with shorter length
+ more = personalizationString;
+ }
+ reseedAlgorithm(ei, more);
+ }
+
+ private byte[] df(byte[] input) {
+ int l = input.length;
+ int n = seedLen;
+ int slen = 4 + 4 + l + 1;
+ byte[] s = new byte[(slen + blockLen - 1) / blockLen * blockLen];
+ s[0] = (byte)(l >> 24);
+ s[1] = (byte)(l >> 16);
+ s[2] = (byte)(l >> 8);
+ s[3] = (byte)(l);
+ s[4] = (byte)(n >> 24);
+ s[5] = (byte)(n >> 16);
+ s[6] = (byte)(n >> 8);
+ s[7] = (byte)(n);
+ System.arraycopy(input, 0, s, 8, l);
+ s[8+l] = (byte)0x80;
+
+ byte[] k = new byte[keyLen];
+ for (int i = 0; i < k.length; i++) {
+ k[i] = (byte)i;
+ }
+
+ byte[] temp = new byte[seedLen];
+
+ for (int i = 0; i * blockLen < temp.length; i++) {
+ byte[] iv = new byte[blockLen + s.length];
+ iv[0] = (byte)(i >> 24);
+ iv[1] = (byte)(i >> 16);
+ iv[2] = (byte)(i >> 8);
+ iv[3] = (byte)(i);
+ System.arraycopy(s, 0, iv, blockLen, s.length);
+ int tailLen = temp.length - blockLen*i;
+ if (tailLen > blockLen) {
+ tailLen = blockLen;
+ }
+ System.arraycopy(bcc(k, iv), 0, temp, blockLen*i, tailLen);
+ }
+
+ k = Arrays.copyOf(temp, keyLen);
+ byte[] x = Arrays.copyOfRange(temp, keyLen, temp.length);
+
+ for (int i = 0; i * blockLen < seedLen; i++) {
+ try {
+ cipher.init(Cipher.ENCRYPT_MODE, getKey(keyAlg, k));
+ int tailLen = temp.length - blockLen*i;
+ if (tailLen > blockLen) {
+ tailLen = blockLen;
+ }
+ x = cipher.doFinal(x);
+ System.arraycopy(x, 0, temp, blockLen * i, tailLen);
+ } catch (GeneralSecurityException e) {
+ throw new InternalError(e);
+ }
+ }
+ return temp;
+ }
+
+ private byte[] bcc(byte[] k, byte[] data) {
+ byte[] chain = new byte[blockLen];
+ int n = data.length / blockLen;
+ for (int i = 0; i < n; i++) {
+ byte[] inputBlock = Arrays.copyOfRange(
+ data, i * blockLen, i * blockLen + blockLen);
+ for (int j = 0; j < blockLen; j++) {
+ inputBlock[j] ^= chain[j];
+ }
+ try {
+ cipher.init(Cipher.ENCRYPT_MODE, getKey(keyAlg, k));
+ chain = cipher.doFinal(inputBlock);
+ } catch (GeneralSecurityException e) {
+ throw new InternalError(e);
+ }
+ }
+ return chain;
+ }
+
+ @Override
+ protected void reseedAlgorithm(
+ byte[] ei,
+ byte[] additionalInput) {
+ if (usedf) {
+ // 800-90Ar1 10.2.1.3.2 Instantiate.
+ // 800-90Ar1 10.2.1.4.2 Reseed.
+
+ // Step 1: cat bytes
+ if (additionalInput != null) {
+ byte[] temp = Arrays.copyOf(
+ ei, ei.length + additionalInput.length);
+ System.arraycopy(additionalInput, 0, temp, ei.length,
+ additionalInput.length);
+ ei = temp;
+ }
+ // Step 2. df (seed_material, seedlen).
+ ei = df(ei);
+ } else {
+ // 800-90Ar1 10.2.1.3.1 Instantiate
+ // 800-90Ar1 10.2.1.4.1 Reseed
+ // Step 1-2. Needless
+ // Step 3. seed_material = entropy_input XOR more
+ if (additionalInput != null) {
+ // additionalInput.length <= seedLen
+ for (int i = 0; i < additionalInput.length; i++) {
+ ei[i] ^= additionalInput[i];
+ }
+ }
+ }
+
+ if (v == null) {
+ // 800-90Ar1 10.2.1.3.2 Instantiate. Step 3-4
+ // 800-90Ar1 10.2.1.3.1 Instantiate. Step 4-5
+ k = new byte[keyLen];
+ v = new byte[blockLen];
+ }
+ //status();
+
+ // 800-90Ar1 10.2.1.3.1 Instantiate. Step 6
+ // 800-90Ar1 10.2.1.3.2 Instantiate. Step 5
+ // 800-90Ar1 10.2.1.4.1 Reseed. Step 4
+ // 800-90Ar1 10.2.1.4.2 Reseed. Step 3
+ update(ei);
+ // 800-90Ar1 10.2.1.3.1 Instantiate. Step 7
+ // 800-90Ar1 10.2.1.3.2 Instantiate. Step 6
+ // 800-90Ar1 10.2.1.4.1 Reseed. Step 5
+ // 800-90Ar1 10.2.1.4.2 Reseed. Step 4
+ reseedCounter = 1;
+ //status();
+
+ // Whatever step. Return
+ }
+
+ /**
+ * Add one to data, only touch the last len bytes.
+ */
+ private static void addOne(byte[] data, int len) {
+ for (int i = 0; i < len; i++) {
+ data[data.length - 1 - i]++;
+ if (data[data.length - 1 - i] != 0) {
+ break;
+ }
+ }
+ }
+
+ @Override
+ public synchronized void generateAlgorithm(
+ byte[] result, byte[] additionalInput) {
+
+ if (debug != null) {
+ debug.println(this, "generateAlgorithm");
+ }
+
+ // 800-90Ar1 10.2.1.5.1 Generate
+ // 800-90Ar1 10.2.1.5.2 Generate
+
+ // Step 1: Check reseed_counter. Will not fail. Already checked in
+ // AbstractDrbg#engineNextBytes.
+
+ if (additionalInput != null) {
+ if (usedf) {
+ // 10.2.1.5.2 Step 2.1
+ additionalInput = df(additionalInput);
+ } else {
+ // 10.2.1.5.1 Step 2.1-2.2
+ additionalInput = Arrays.copyOf(additionalInput, seedLen);
+ }
+ // 10.2.1.5.1 Step 2.3
+ // 10.2.1.5.2 Step 2.2
+ update(additionalInput);
+ } else {
+ // 10.2.1.5.1 Step 2 Else
+ // 10.2.1.5.2 Step 2 Else
+ additionalInput = new byte[seedLen];
+ }
+
+ // Step 3. temp = Null
+ int pos = 0;
+
+ // Step 4. Loop
+ while (pos < result.length) {
+ int tailLen = result.length - pos;
+ // Step 4.1. Increment
+ addOne(v, ctrLen);
+ try {
+ // Step 4.2. Encrypt
+ cipher.init(Cipher.ENCRYPT_MODE, getKey(keyAlg, k));
+ byte[] out = cipher.doFinal(v);
+
+ // Step 4.3 and 5. Cat bytes and leftmost
+ System.arraycopy(out, 0, result, pos,
+ (tailLen > blockLen) ? blockLen : tailLen);
+ } catch (GeneralSecurityException e) {
+ throw new InternalError(e);
+ }
+ pos += blockLen;
+ }
+
+ // Step 6. Update
+ update(additionalInput);
+
+ // Step 7. reseed_counter++
+ reseedCounter++;
+
+ //status();
+
+ // Step 8. Return
+ }
+
+ 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, XOR with 1 (uneven & 1)
+ // for uneven # bits, make even, XOR with 0 (even & 1)
+ 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");
+ }
+}
diff --git a/jdk/src/java.base/share/classes/sun/security/provider/DRBG.java b/jdk/src/java.base/share/classes/sun/security/provider/DRBG.java
new file mode 100644
index 00000000000..b5fa3c4c4d2
--- /dev/null
+++ b/jdk/src/java.base/share/classes/sun/security/provider/DRBG.java
@@ -0,0 +1,271 @@
+/*
+ * 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.SecureRandomParameters;
+import java.security.SecureRandomSpi;
+import java.security.Security;
+import java.util.Locale;
+import static java.security.DrbgParameters.Capability.*;
+
+/**
+ * Implement the "SecureRandom.DRBG" algorithm.
+ *
+ * About the default "securerandom.drbg.config" value:
+ *
+ * The default value in java.security is set to "". This is because
+ * the default values of different aspects are dependent (For example,
+ * strength depends on algorithm) and if we write a full string there
+ * it will be difficult to modify one and keep all others legal.
+ *
+ * When changing default values, touch all places including:
+ *
+ * 1. comments of the security property in java.security
+ * 2. Default mech, cap, usedf set in this class
+ * 3. Default algorithm set in final implementation of each mech
+ * 4. Default strength set in AbstractDrbg, but the effective
+ * value can be smaller if an algorithm does not support it.
+ *
+ * The default value is also mentioned in the @implNote part of
+ * {@link DrbgParameters} class.
+ */
+public final class DRBG extends SecureRandomSpi {
+
+ private static final String PROP_NAME = "securerandom.drbg.config";
+
+ private static final long serialVersionUID = 9L;
+
+ private final AbstractDrbg impl;
+
+ private final String mechName;
+
+ private final String algorithmName;
+
+ public DRBG(SecureRandomParameters params) {
+
+ // All parameters at unset status (null or -1).
+
+ // Configurable with the "securerandom.drbg.config" security property
+ String mech = null;
+ Boolean usedf = null;
+ String algorithm = null;
+
+ // Default instantiate parameters also configurable with
+ // "securerandom.drbg.config", 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
+ * This maps to the {@code Get_entropy_input} function defined in
+ * Section 9 of NIST SP 800-90Ar1.
+ *
+ * @param minEntropy 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 minEntropy, int minLength, int maxLength, boolean pr);
+}
diff --git a/jdk/src/java.base/share/classes/sun/security/provider/HashDrbg.java b/jdk/src/java.base/share/classes/sun/security/provider/HashDrbg.java
new file mode 100644
index 00000000000..0b59f7d4c33
--- /dev/null
+++ b/jdk/src/java.base/share/classes/sun/security/provider/HashDrbg.java
@@ -0,0 +1,276 @@
+/*
+ * 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.SecureRandomParameters;
+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 transient byte[] v;
+ private transient byte[] c;
+
+ public HashDrbg(SecureRandomParameters params) {
+ mechName = "Hash_DRBG";
+ configure(params);
+ }
+
+ /**
+ * This call, used by the constructors, instantiates the digest.
+ */
+ @Override
+ protected void initEngine() {
+ 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