8051408: NIST SP 800-90A SecureRandom implementations
Reviewed-by: wetmore, xuelei, coffeys
This commit is contained in:
parent
45aab5eb6d
commit
b932c60a85
@ -262,4 +262,14 @@ abstract class HmacCore extends MacSpi implements Cloneable {
|
|||||||
super("SHA-512", 128);
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -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.OID.1.2.840.113549.2.11", "HmacSHA512");
|
||||||
put("Alg.Alias.Mac.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",
|
put("Mac.HmacPBESHA1",
|
||||||
"com.sun.crypto.provider.HmacPKCS12PBESHA1");
|
"com.sun.crypto.provider.HmacPKCS12PBESHA1");
|
||||||
|
|
||||||
|
@ -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).
|
||||||
|
* <p>
|
||||||
|
* According to
|
||||||
|
* <a href="http://nvlpubs.nist.gov/nistpubs/SpecialPublications/NIST.SP.800-90Ar1.pdf">
|
||||||
|
* NIST Special Publication 800-90A Revision 1, Recommendation for Random
|
||||||
|
* Number Generation Using Deterministic Random Bit Generators</a> (800-90Ar1),
|
||||||
|
* <blockquote>
|
||||||
|
* A DRBG is based on a DRBG mechanism as specified in this Recommendation
|
||||||
|
* and includes a source of randomness. A DRBG mechanism uses an algorithm
|
||||||
|
* (i.e., a DRBG algorithm) that produces a sequence of bits from an initial
|
||||||
|
* value that is determined by a seed that is determined from the output of
|
||||||
|
* the randomness source."
|
||||||
|
* </blockquote>
|
||||||
|
* <p>
|
||||||
|
* The 800-90Ar1 specification allows for a variety of DRBG implementation
|
||||||
|
* choices, such as:
|
||||||
|
* <ul>
|
||||||
|
* <li> an entropy source,
|
||||||
|
* <li> a DRBG mechanism (for example, Hash_DRBG),
|
||||||
|
* <li> a DRBG algorithm (for example, SHA-256 for Hash_DRBG and AES-256
|
||||||
|
* for CTR_DRBG. Please note that it is not the algorithm used in
|
||||||
|
* {@link SecureRandom#getInstance}, which we will call a
|
||||||
|
* <em>SecureRandom algorithm</em> below),
|
||||||
|
* <li> optionally features, including prediction resistance
|
||||||
|
* and reseeding supports.
|
||||||
|
* <li> highest security strength.
|
||||||
|
* </ul>
|
||||||
|
* <p>
|
||||||
|
* 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.
|
||||||
|
* <p>
|
||||||
|
* On the other hand, the 800-90Ar1 specification does have some configurable
|
||||||
|
* options, such as:
|
||||||
|
* <ul>
|
||||||
|
* <li> required security strength,
|
||||||
|
* <li> if prediction resistance is required,
|
||||||
|
* <li> personalization string and additional input.
|
||||||
|
* </ul>
|
||||||
|
* <p>
|
||||||
|
* 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.
|
||||||
|
* <p>
|
||||||
|
* 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.
|
||||||
|
* <p>
|
||||||
|
* 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.
|
||||||
|
* <p>
|
||||||
|
* 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.
|
||||||
|
* <p>
|
||||||
|
* 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)}.
|
||||||
|
* <p>
|
||||||
|
* A DRBG might reseed itself automatically if the seed period is bigger
|
||||||
|
* than the maximum seed life defined by the DRBG mechanism.
|
||||||
|
* <p>
|
||||||
|
* 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.
|
||||||
|
* <p>
|
||||||
|
* Examples:
|
||||||
|
* <blockquote><pre>
|
||||||
|
* 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()));</pre>
|
||||||
|
* </blockquote>
|
||||||
|
*
|
||||||
|
* @implSpec
|
||||||
|
* By convention, a provider should name its primary DRBG implementation
|
||||||
|
* with the <a href=
|
||||||
|
* "{@docRoot}/../technotes/guides/security/StandardNames.html#SecureRandom">
|
||||||
|
* standard {@code SecureRandom} algorithm name</a> "DRBG".
|
||||||
|
*
|
||||||
|
* @implNote
|
||||||
|
* The following notes apply to the "DRBG" implementation in the SUN provider
|
||||||
|
* of the JDK reference implementation.
|
||||||
|
* <p>
|
||||||
|
* This implementation supports the Hash_DRBG and HMAC_DRBG mechanisms with
|
||||||
|
* DRBG algorithm 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.
|
||||||
|
* <p>
|
||||||
|
* 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.
|
||||||
|
* <p>
|
||||||
|
* 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.
|
||||||
|
* <p>
|
||||||
|
* 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.
|
||||||
|
* <p>
|
||||||
|
* 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.
|
||||||
|
* <p>
|
||||||
|
* This implementation reads fresh entropy from the system default entropy
|
||||||
|
* source determined by the security property {@code securerandom.source}.
|
||||||
|
* <p>
|
||||||
|
* Calling {@link SecureRandom#generateSeed(int)} will directly read
|
||||||
|
* from this system default entropy source.
|
||||||
|
* <p>
|
||||||
|
* This implementation has passed all tests included in the 20151104 version of
|
||||||
|
* <a href="http://csrc.nist.gov/groups/STM/cavp/documents/drbg/drbgtestvectors.zip">
|
||||||
|
* The DRBG Test Vectors</a>.
|
||||||
|
*
|
||||||
|
* @since 9
|
||||||
|
*/
|
||||||
|
public class DrbgParameters {
|
||||||
|
|
||||||
|
private DrbgParameters() {
|
||||||
|
// This class should not be instantiated
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The reseedable and prediction resistance capabilities of a DRBG.
|
||||||
|
* <p>
|
||||||
|
* When this object is 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.
|
||||||
|
* <p>
|
||||||
|
* 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.
|
||||||
|
* <p>
|
||||||
|
* The table below lists possible effective values if a certain
|
||||||
|
* capability is requested, i.e.
|
||||||
|
* <blockquote><pre>
|
||||||
|
* Capability requested = ...;
|
||||||
|
* SecureRandom s = SecureRandom.getInstance("DRBG",
|
||||||
|
* DrbgParameters(-1, requested, null));
|
||||||
|
* Capability effective = ((DrbgParametes.Initiate) s.getParameters())
|
||||||
|
* .getCapability();</pre>
|
||||||
|
* </blockquote>
|
||||||
|
* <table border=1 summary="requested and effective capabilities">
|
||||||
|
* <tr>
|
||||||
|
* <th>Requested Value</th>
|
||||||
|
* <th>Possible Effective Values</th>
|
||||||
|
* </tr>
|
||||||
|
* <tr><td>NONE</td><td>NONE, RESEED_ONLY, PR_AND_RESEED</td></tr>
|
||||||
|
* <tr><td>RESEED_ONLY</td><td>RESEED_ONLY, PR_AND_RESEED</td></tr>
|
||||||
|
* <tr><td>PR_AND_RESEED</td><td>PR_AND_RESEED</td></tr>
|
||||||
|
* </table>
|
||||||
|
* <p>
|
||||||
|
* 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.
|
||||||
|
* <p>
|
||||||
|
* 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);
|
||||||
|
}
|
||||||
|
}
|
@ -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.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* 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();
|
Constructor<?> con = clazz.getConstructor();
|
||||||
return con.newInstance();
|
return con.newInstance();
|
||||||
} else {
|
} else {
|
||||||
Constructor<?> con = clazz.getConstructor(ctrParamClz);
|
// Looking for the constructor with a params first and fallback
|
||||||
return con.newInstance(ctorParamObj);
|
// 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("KeyPairGenerator", false, null);
|
||||||
addEngine("KeyStore", false, null);
|
addEngine("KeyStore", false, null);
|
||||||
addEngine("MessageDigest", false, null);
|
addEngine("MessageDigest", false, null);
|
||||||
addEngine("SecureRandom", false, null);
|
addEngine("SecureRandom", false,
|
||||||
|
"java.security.SecureRandomParameters");
|
||||||
addEngine("Signature", true, null);
|
addEngine("Signature", true, null);
|
||||||
addEngine("CertificateFactory", false, null);
|
addEngine("CertificateFactory", false, null);
|
||||||
addEngine("CertPathBuilder", 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);
|
return newInstanceUtil(getImplClass(), ctrParamClz, constructorParameter);
|
||||||
} catch (NoSuchAlgorithmException e) {
|
} catch (NoSuchAlgorithmException e) {
|
||||||
throw e;
|
throw e;
|
||||||
|
@ -38,52 +38,87 @@ import sun.security.util.Debug;
|
|||||||
* This class provides a cryptographically strong random number
|
* This class provides a cryptographically strong random number
|
||||||
* generator (RNG).
|
* generator (RNG).
|
||||||
*
|
*
|
||||||
* <p>A cryptographically strong random number
|
* <p>A cryptographically strong random number minimally complies with the
|
||||||
* minimally complies with the statistical random number generator tests
|
* statistical random number generator tests specified in
|
||||||
* specified in
|
|
||||||
* <a href="http://csrc.nist.gov/publications/fips/fips140-2/fips1402.pdf">
|
* <a href="http://csrc.nist.gov/publications/fips/fips140-2/fips1402.pdf">
|
||||||
* <i>FIPS 140-2, Security Requirements for Cryptographic Modules</i></a>,
|
* <i>FIPS 140-2, Security Requirements for Cryptographic Modules</i></a>,
|
||||||
* section 4.9.1.
|
* section 4.9.1.
|
||||||
* Additionally, SecureRandom must produce non-deterministic output.
|
* Additionally, {@code SecureRandom} must produce non-deterministic output.
|
||||||
* Therefore any seed material passed to a SecureRandom object must be
|
* Therefore any seed material passed to a {@code SecureRandom} object must be
|
||||||
* unpredictable, and all SecureRandom output sequences must be
|
* unpredictable, and all {@code SecureRandom} output sequences must be
|
||||||
* cryptographically strong, as described in
|
* cryptographically strong, as described in
|
||||||
* <a href="http://tools.ietf.org/html/rfc4086">
|
* <a href="http://tools.ietf.org/html/rfc4086">
|
||||||
* <i>RFC 4086: Randomness Requirements for Security</i></a>.
|
* <i>RFC 4086: Randomness Requirements for Security</i></a>.
|
||||||
*
|
*
|
||||||
* <p>A caller obtains a SecureRandom instance via the
|
* <p> Many {@code SecureRandom} implementations are in the form of a
|
||||||
* no-argument constructor or one of the {@code getInstance} methods:
|
* pseudo-random number generator (PRNG, also known as deterministic random
|
||||||
*
|
* bits generator or DRBG), which means they use a deterministic algorithm
|
||||||
* <pre>
|
* to produce a pseudo-random sequence from a random seed.
|
||||||
* SecureRandom random = new SecureRandom();
|
|
||||||
* </pre>
|
|
||||||
*
|
|
||||||
* <p> Many SecureRandom implementations are in the form of a pseudo-random
|
|
||||||
* number generator (PRNG), which means they use a deterministic algorithm
|
|
||||||
* to produce a pseudo-random sequence from a true random seed.
|
|
||||||
* Other implementations may produce true random numbers,
|
* Other implementations may produce true random numbers,
|
||||||
* and yet others may use a combination of both techniques.
|
* and yet others may use a combination of both techniques.
|
||||||
*
|
*
|
||||||
* <p> Typical callers of SecureRandom invoke the following methods
|
* <p>A caller obtains a {@code SecureRandom} instance via the
|
||||||
|
* no-argument constructor or one of the {@code getInstance} methods.
|
||||||
|
* For example:
|
||||||
|
*
|
||||||
|
* <blockquote><pre>
|
||||||
|
* SecureRandom r1 = new SecureRandom();
|
||||||
|
* SecureRandom r2 = SecureRandom.getInstance("NativePRNG");
|
||||||
|
* SecureRandom r3 = SecureRandom("DRBG",
|
||||||
|
* DrbgParameters.Instantiation(128, RESEED_ONLY, null));</pre>
|
||||||
|
* </blockquote>
|
||||||
|
*
|
||||||
|
* <p> The third statement above returns a {@code SecureRandom} object of the
|
||||||
|
* specific algorithm supporting the specific instantiate parameters. The
|
||||||
|
* 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.
|
||||||
|
*
|
||||||
|
* <p> Typical callers of {@code SecureRandom} invoke the following methods
|
||||||
* to retrieve random bytes:
|
* to retrieve random bytes:
|
||||||
*
|
*
|
||||||
* <pre>
|
* <blockquote><pre>
|
||||||
* SecureRandom random = new SecureRandom();
|
* SecureRandom random = new SecureRandom();
|
||||||
* byte[] bytes = new byte[20];
|
* byte[] bytes = new byte[20];
|
||||||
* random.nextBytes(bytes);
|
* random.nextBytes(bytes);</pre>
|
||||||
* </pre>
|
* </blockquote>
|
||||||
*
|
*
|
||||||
* <p> Callers may also invoke the {@code generateSeed} method
|
* <p> Callers may also invoke the {@link #generateSeed} method
|
||||||
* to generate a given number of seed bytes (to seed other random number
|
* to generate a given number of seed bytes (to seed other random number
|
||||||
* generators, for example):
|
* generators, for example):
|
||||||
* <pre>
|
|
||||||
* byte[] seed = random.generateSeed(20);
|
|
||||||
* </pre>
|
|
||||||
*
|
*
|
||||||
* Note: Depending on the implementation, the {@code generateSeed} and
|
* <blockquote><pre>
|
||||||
* {@code nextBytes} methods may block as entropy is being gathered,
|
* byte[] seed = random.generateSeed(20);</pre>
|
||||||
* for example, if they need to read from /dev/random on various Unix-like
|
* </blockquote>
|
||||||
* operating systems.
|
*
|
||||||
|
* <p> A newly created PRNG {@code SecureRandom} object is not seeded (except
|
||||||
|
* if it is created by {@link #SecureRandom(byte[])}). The first call to
|
||||||
|
* {@code nextBytes} will force it to seed itself from an implementation-
|
||||||
|
* specific entropy source. This self-seeding will not occur if {@code setSeed}
|
||||||
|
* was previously called.
|
||||||
|
*
|
||||||
|
* <p> A {@code SecureRandom} can be reseeded at any time by calling the
|
||||||
|
* {@code reseed} or {@code setSeed} method. The {@code reseed} method
|
||||||
|
* reads entropy input from its entropy source to reseed itself.
|
||||||
|
* The {@code setSeed} method requires the caller to provide the seed.
|
||||||
|
*
|
||||||
|
* <p> Please note that {@code reseed} may not be supported by all
|
||||||
|
* {@code SecureRandom} implementations.
|
||||||
|
*
|
||||||
|
* <p> 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.
|
||||||
|
*
|
||||||
|
* <p> Note: Depending on the implementation, the {@code generateSeed},
|
||||||
|
* {@code reseed} and {@code nextBytes} methods may block as entropy is being
|
||||||
|
* gathered, for example, if the entropy source is /dev/random on various
|
||||||
|
* Unix-like operating systems.
|
||||||
*
|
*
|
||||||
* @see java.security.SecureRandomSpi
|
* @see java.security.SecureRandomSpi
|
||||||
* @see java.util.Random
|
* @see java.util.Random
|
||||||
@ -132,26 +167,19 @@ public class SecureRandom extends java.util.Random {
|
|||||||
*
|
*
|
||||||
* <p> This constructor traverses the list of registered security Providers,
|
* <p> This constructor traverses the list of registered security Providers,
|
||||||
* starting with the most preferred Provider.
|
* starting with the most preferred Provider.
|
||||||
* A new SecureRandom object encapsulating the
|
* A new {@code SecureRandom} object encapsulating the
|
||||||
* SecureRandomSpi implementation from the first
|
* {@code SecureRandomSpi} implementation from the first
|
||||||
* Provider that supports a SecureRandom (RNG) algorithm is returned.
|
* Provider that supports a {@code SecureRandom} (RNG) algorithm is returned.
|
||||||
* If none of the Providers support a RNG algorithm,
|
* If none of the Providers support a RNG algorithm,
|
||||||
* then an implementation-specific default is returned.
|
* then an implementation-specific default is returned.
|
||||||
*
|
*
|
||||||
* <p> Note that the list of registered providers may be retrieved via
|
* <p> Note that the list of registered providers may be retrieved via
|
||||||
* the {@link Security#getProviders() Security.getProviders()} method.
|
* the {@link Security#getProviders() Security.getProviders()} method.
|
||||||
*
|
*
|
||||||
* <p> See the SecureRandom section in the <a href=
|
* <p> See the {@code SecureRandom} section in the <a href=
|
||||||
* "{@docRoot}/../technotes/guides/security/StandardNames.html#SecureRandom">
|
* "{@docRoot}/../technotes/guides/security/StandardNames.html#SecureRandom">
|
||||||
* Java Cryptography Architecture Standard Algorithm Name Documentation</a>
|
* Java Cryptography Architecture Standard Algorithm Name Documentation</a>
|
||||||
* for information about standard RNG algorithm names.
|
* for information about standard RNG algorithm names.
|
||||||
*
|
|
||||||
* <p> The returned SecureRandom object has not been seeded. To seed the
|
|
||||||
* returned object, call the {@code setSeed} method.
|
|
||||||
* If {@code setSeed} is not called, the first call to
|
|
||||||
* {@code nextBytes} will force the SecureRandom object to seed itself.
|
|
||||||
* This self-seeding will not occur if {@code setSeed} was
|
|
||||||
* previously called.
|
|
||||||
*/
|
*/
|
||||||
public SecureRandom() {
|
public SecureRandom() {
|
||||||
/*
|
/*
|
||||||
@ -166,20 +194,20 @@ public class SecureRandom extends java.util.Random {
|
|||||||
/**
|
/**
|
||||||
* Constructs a secure random number generator (RNG) implementing the
|
* Constructs a secure random number generator (RNG) implementing the
|
||||||
* default random number algorithm.
|
* default random number algorithm.
|
||||||
* The SecureRandom instance is seeded with the specified seed bytes.
|
* The {@code SecureRandom} instance is seeded with the specified seed bytes.
|
||||||
*
|
*
|
||||||
* <p> This constructor traverses the list of registered security Providers,
|
* <p> This constructor traverses the list of registered security Providers,
|
||||||
* starting with the most preferred Provider.
|
* starting with the most preferred Provider.
|
||||||
* A new SecureRandom object encapsulating the
|
* A new {@code SecureRandom} object encapsulating the
|
||||||
* SecureRandomSpi implementation from the first
|
* {@code SecureRandomSpi} implementation from the first
|
||||||
* Provider that supports a SecureRandom (RNG) algorithm is returned.
|
* Provider that supports a {@code SecureRandom} (RNG) algorithm is returned.
|
||||||
* If none of the Providers support a RNG algorithm,
|
* If none of the Providers support a RNG algorithm,
|
||||||
* then an implementation-specific default is returned.
|
* then an implementation-specific default is returned.
|
||||||
*
|
*
|
||||||
* <p> Note that the list of registered providers may be retrieved via
|
* <p> Note that the list of registered providers may be retrieved via
|
||||||
* the {@link Security#getProviders() Security.getProviders()} method.
|
* the {@link Security#getProviders() Security.getProviders()} method.
|
||||||
*
|
*
|
||||||
* <p> See the SecureRandom section in the <a href=
|
* <p> See the {@code SecureRandom} section in the <a href=
|
||||||
* "{@docRoot}/../technotes/guides/security/StandardNames.html#SecureRandom">
|
* "{@docRoot}/../technotes/guides/security/StandardNames.html#SecureRandom">
|
||||||
* Java Cryptography Architecture Standard Algorithm Name Documentation</a>
|
* Java Cryptography Architecture Standard Algorithm Name Documentation</a>
|
||||||
* for information about standard RNG algorithm names.
|
* 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.
|
* @param provider the provider.
|
||||||
*/
|
*/
|
||||||
protected SecureRandom(SecureRandomSpi secureRandomSpi,
|
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.
|
* Random Number Generator (RNG) algorithm.
|
||||||
*
|
*
|
||||||
* <p> This method traverses the list of registered security Providers,
|
* <p> This method traverses the list of registered security Providers,
|
||||||
* starting with the most preferred Provider.
|
* starting with the most preferred Provider.
|
||||||
* A new SecureRandom object encapsulating the
|
* A new {@code SecureRandom} object encapsulating the
|
||||||
* SecureRandomSpi implementation from the first
|
* {@code SecureRandomSpi} implementation from the first
|
||||||
* Provider that supports the specified algorithm is returned.
|
* Provider that supports the specified algorithm is returned.
|
||||||
*
|
*
|
||||||
* <p> Note that the list of registered providers may be retrieved via
|
* <p> Note that the list of registered providers may be retrieved via
|
||||||
* the {@link Security#getProviders() Security.getProviders()} method.
|
* the {@link Security#getProviders() Security.getProviders()} method.
|
||||||
*
|
*
|
||||||
* <p> The returned SecureRandom object has not been seeded. To seed the
|
|
||||||
* returned object, call the {@code setSeed} method.
|
|
||||||
* If {@code setSeed} is not called, the first call to
|
|
||||||
* {@code nextBytes} will force the SecureRandom object to seed itself.
|
|
||||||
* This self-seeding will not occur if {@code setSeed} was
|
|
||||||
* previously called.
|
|
||||||
*
|
|
||||||
* @implNote
|
* @implNote
|
||||||
* The JDK Reference Implementation additionally uses the
|
* The JDK Reference Implementation additionally uses the
|
||||||
* {@code jdk.security.provider.preferred}
|
* {@code jdk.security.provider.preferred}
|
||||||
@ -277,15 +298,15 @@ public class SecureRandom extends java.util.Random {
|
|||||||
* {@link Security#getProviders() Security.getProviders()}.
|
* {@link Security#getProviders() Security.getProviders()}.
|
||||||
*
|
*
|
||||||
* @param algorithm the name of the RNG algorithm.
|
* @param algorithm the name of the RNG algorithm.
|
||||||
* See the SecureRandom section in the <a href=
|
* See the {@code SecureRandom} section in the <a href=
|
||||||
* "{@docRoot}/../technotes/guides/security/StandardNames.html#SecureRandom">
|
* "{@docRoot}/../technotes/guides/security/StandardNames.html#SecureRandom">
|
||||||
* Java Cryptography Architecture Standard Algorithm Name Documentation</a>
|
* Java Cryptography Architecture Standard Algorithm Name Documentation</a>
|
||||||
* for information about standard RNG algorithm names.
|
* 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
|
* @exception NoSuchAlgorithmException if no Provider supports a
|
||||||
* SecureRandomSpi implementation for the
|
* {@code SecureRandomSpi} implementation for the
|
||||||
* specified algorithm.
|
* specified algorithm.
|
||||||
*
|
*
|
||||||
* @see Provider
|
* @see Provider
|
||||||
@ -295,49 +316,42 @@ public class SecureRandom extends java.util.Random {
|
|||||||
public static SecureRandom getInstance(String algorithm)
|
public static SecureRandom getInstance(String algorithm)
|
||||||
throws NoSuchAlgorithmException {
|
throws NoSuchAlgorithmException {
|
||||||
Instance instance = GetInstance.getInstance("SecureRandom",
|
Instance instance = GetInstance.getInstance("SecureRandom",
|
||||||
SecureRandomSpi.class, algorithm);
|
SecureRandomSpi.class, algorithm);
|
||||||
return new SecureRandom((SecureRandomSpi)instance.impl,
|
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.
|
* Random Number Generator (RNG) algorithm.
|
||||||
*
|
*
|
||||||
* <p> A new SecureRandom object encapsulating the
|
* <p> A new {@code SecureRandom} object encapsulating the
|
||||||
* SecureRandomSpi implementation from the specified provider
|
* {@code SecureRandomSpi} implementation from the specified provider
|
||||||
* is returned. The specified provider must be registered
|
* is returned. The specified provider must be registered
|
||||||
* in the security provider list.
|
* in the security provider list.
|
||||||
*
|
*
|
||||||
* <p> Note that the list of registered providers may be retrieved via
|
* <p> Note that the list of registered providers may be retrieved via
|
||||||
* the {@link Security#getProviders() Security.getProviders()} method.
|
* the {@link Security#getProviders() Security.getProviders()} method.
|
||||||
*
|
*
|
||||||
* <p> The returned SecureRandom object has not been seeded. To seed the
|
|
||||||
* returned object, call the {@code setSeed} method.
|
|
||||||
* If {@code setSeed} is not called, the first call to
|
|
||||||
* {@code nextBytes} will force the SecureRandom object to seed itself.
|
|
||||||
* This self-seeding will not occur if {@code setSeed} was
|
|
||||||
* previously called.
|
|
||||||
*
|
|
||||||
* @param algorithm the name of the RNG algorithm.
|
* @param algorithm the name of the RNG algorithm.
|
||||||
* See the SecureRandom section in the <a href=
|
* See the {@code SecureRandom} section in the <a href=
|
||||||
* "{@docRoot}/../technotes/guides/security/StandardNames.html#SecureRandom">
|
* "{@docRoot}/../technotes/guides/security/StandardNames.html#SecureRandom">
|
||||||
* Java Cryptography Architecture Standard Algorithm Name Documentation</a>
|
* Java Cryptography Architecture Standard Algorithm Name Documentation</a>
|
||||||
* for information about standard RNG algorithm names.
|
* for information about standard RNG algorithm names.
|
||||||
*
|
*
|
||||||
* @param provider the name of the provider.
|
* @param provider the name of the provider.
|
||||||
*
|
*
|
||||||
* @return the new SecureRandom object.
|
* @return the new {@code SecureRandom} object.
|
||||||
*
|
*
|
||||||
* @exception NoSuchAlgorithmException if a SecureRandomSpi
|
* @throws NoSuchAlgorithmException if a {@code SecureRandomSpi}
|
||||||
* implementation for the specified algorithm is not
|
* implementation for the specified algorithm is not
|
||||||
* available from the specified provider.
|
* available from the specified provider.
|
||||||
*
|
*
|
||||||
* @exception NoSuchProviderException if the specified provider is not
|
* @throws NoSuchProviderException if the specified provider is not
|
||||||
* registered in the security provider list.
|
* registered in the security provider list.
|
||||||
*
|
*
|
||||||
* @exception IllegalArgumentException if the provider name is null
|
* @throws IllegalArgumentException if the provider name is null
|
||||||
* or empty.
|
* or empty.
|
||||||
*
|
*
|
||||||
* @see Provider
|
* @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.
|
* Random Number Generator (RNG) algorithm.
|
||||||
*
|
*
|
||||||
* <p> A new SecureRandom object encapsulating the
|
* <p> A new {@code SecureRandom} object encapsulating the
|
||||||
* SecureRandomSpi implementation from the specified Provider
|
* {@code SecureRandomSpi} implementation from the specified {@code Provider}
|
||||||
* object is returned. Note that the specified Provider object
|
* object is returned. Note that the specified {@code Provider} object
|
||||||
* does not have to be registered in the provider list.
|
* does not have to be registered in the provider list.
|
||||||
*
|
*
|
||||||
* <p> The returned SecureRandom object has not been seeded. To seed the
|
|
||||||
* returned object, call the {@code setSeed} method.
|
|
||||||
* If {@code setSeed} is not called, the first call to
|
|
||||||
* {@code nextBytes} will force the SecureRandom object to seed itself.
|
|
||||||
* This self-seeding will not occur if {@code setSeed} was
|
|
||||||
* previously called.
|
|
||||||
*
|
|
||||||
* @param algorithm the name of the RNG algorithm.
|
* @param algorithm the name of the RNG algorithm.
|
||||||
* See the SecureRandom section in the <a href=
|
* See the {@code SecureRandom} section in the <a href=
|
||||||
* "{@docRoot}/../technotes/guides/security/StandardNames.html#SecureRandom">
|
* "{@docRoot}/../technotes/guides/security/StandardNames.html#SecureRandom">
|
||||||
* Java Cryptography Architecture Standard Algorithm Name Documentation</a>
|
* Java Cryptography Architecture Standard Algorithm Name Documentation</a>
|
||||||
* for information about standard RNG algorithm names.
|
* for information about standard RNG algorithm names.
|
||||||
*
|
*
|
||||||
* @param provider the provider.
|
* @param provider the provider.
|
||||||
*
|
*
|
||||||
* @return the new SecureRandom object.
|
* @return the new {@code SecureRandom} object.
|
||||||
*
|
*
|
||||||
* @exception NoSuchAlgorithmException if a SecureRandomSpi
|
* @throws NoSuchAlgorithmException if a {@code SecureRandomSpi}
|
||||||
* implementation for the specified algorithm is not available
|
* implementation for the specified algorithm is not available
|
||||||
* from the specified Provider object.
|
* from the specified {@code Provider} object.
|
||||||
*
|
*
|
||||||
* @exception IllegalArgumentException if the specified provider is null.
|
* @throws IllegalArgumentException if the specified provider is null.
|
||||||
*
|
*
|
||||||
* @see Provider
|
* @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.
|
||||||
|
*
|
||||||
|
* <p> This method traverses the list of registered security Providers,
|
||||||
|
* starting with the most preferred Provider.
|
||||||
|
* A new {@code SecureRandom} object encapsulating the
|
||||||
|
* {@code SecureRandomSpi} implementation from the first
|
||||||
|
* Provider that supports the specified algorithm and the specified
|
||||||
|
* {@code SecureRandomParameters} is returned.
|
||||||
|
*
|
||||||
|
* <p> Note that the list of registered providers may be retrieved via
|
||||||
|
* the {@link Security#getProviders() Security.getProviders()} method.
|
||||||
|
*
|
||||||
|
* @implNote
|
||||||
|
* The JDK Reference Implementation additionally uses the
|
||||||
|
* {@code jdk.security.provider.preferred} property to determine
|
||||||
|
* the preferred provider order for the specified algorithm. This
|
||||||
|
* may be different than the order of providers returned by
|
||||||
|
* {@link Security#getProviders() Security.getProviders()}.
|
||||||
|
*
|
||||||
|
* @param algorithm the name of the RNG algorithm.
|
||||||
|
* See the {@code SecureRandom} section in the <a href=
|
||||||
|
* "{@docRoot}/../technotes/guides/security/StandardNames.html#SecureRandom">
|
||||||
|
* Java Cryptography Architecture Standard Algorithm Name Documentation</a>
|
||||||
|
* for information about standard RNG algorithm names.
|
||||||
|
*
|
||||||
|
* @param params the {@code 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.
|
||||||
|
*
|
||||||
|
* <p> A new {@code SecureRandom} object encapsulating the
|
||||||
|
* {@code SecureRandomSpi} implementation from the specified provider
|
||||||
|
* is returned. The specified provider must be registered
|
||||||
|
* in the security provider list.
|
||||||
|
*
|
||||||
|
* <p> Note that the list of registered providers may be retrieved via
|
||||||
|
* the {@link Security#getProviders() Security.getProviders()} method.
|
||||||
|
*
|
||||||
|
* @param algorithm the name of the RNG algorithm.
|
||||||
|
* See the {@code SecureRandom} section in the <a href=
|
||||||
|
* "{@docRoot}/../technotes/guides/security/StandardNames.html#SecureRandom">
|
||||||
|
* Java Cryptography Architecture Standard Algorithm Name Documentation</a>
|
||||||
|
* for information about standard RNG algorithm names.
|
||||||
|
*
|
||||||
|
* @param params the {@code 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.
|
||||||
|
*
|
||||||
|
* <p> A new {@code SecureRandom} object encapsulating the
|
||||||
|
* {@code SecureRandomSpi} implementation from the specified
|
||||||
|
* {@code Provider} object is returned. Note that the specified
|
||||||
|
* {@code Provider} object does not have to be registered in the
|
||||||
|
* provider list.
|
||||||
|
*
|
||||||
|
* @param algorithm the name of the RNG algorithm.
|
||||||
|
* See the {@code SecureRandom} section in the <a href=
|
||||||
|
* "{@docRoot}/../technotes/guides/security/StandardNames.html#SecureRandom">
|
||||||
|
* Java Cryptography Architecture Standard Algorithm Name Documentation</a>
|
||||||
|
* for information about standard RNG algorithm names.
|
||||||
|
*
|
||||||
|
* @param params the {@code 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() {
|
SecureRandomSpi getSecureRandomSpi() {
|
||||||
return secureRandomSpi;
|
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() {
|
public final Provider getProvider() {
|
||||||
return provider;
|
return provider;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the name of the algorithm implemented by this SecureRandom
|
* Returns the name of the algorithm implemented by this
|
||||||
* object.
|
* {@code SecureRandom} object.
|
||||||
*
|
*
|
||||||
* @return the name of the algorithm or {@code unknown}
|
* @return the name of the algorithm or {@code unknown}
|
||||||
* if the algorithm name cannot be determined.
|
* 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
|
* Returns a Human-readable string representation of this
|
||||||
* replaces, the existing seed. Thus, repeated calls are guaranteed
|
* {@code SecureRandom}.
|
||||||
* never to reduce randomness.
|
*
|
||||||
|
* @return the string representation
|
||||||
|
*
|
||||||
|
* @since 9
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return secureRandomSpi.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the effective {@link SecureRandomParameters} for this
|
||||||
|
* {@code SecureRandom} instance.
|
||||||
|
* <p>
|
||||||
|
* 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.
|
||||||
|
* <p>
|
||||||
|
* 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.
|
||||||
|
* <p>
|
||||||
|
* A PRNG {@code SecureRandom} will not seed itself automatically if
|
||||||
|
* {@code setSeed} is called before any {@code nextBytes} or {@code reseed}
|
||||||
|
* calls. The caller should make sure that the {@code seed} argument
|
||||||
|
* contains enough entropy for the security of this {@code SecureRandom}.
|
||||||
*
|
*
|
||||||
* @param seed the seed.
|
* @param seed the seed.
|
||||||
*
|
*
|
||||||
@ -458,18 +659,13 @@ public class SecureRandom extends java.util.Random {
|
|||||||
* yet been initialized at that point.
|
* yet been initialized at that point.
|
||||||
*/
|
*/
|
||||||
if (seed != 0) {
|
if (seed != 0) {
|
||||||
secureRandomSpi.engineSetSeed(longToByteArray(seed));
|
this.secureRandomSpi.engineSetSeed(longToByteArray(seed));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Generates a user-specified number of random bytes.
|
* Generates a user-specified number of random bytes.
|
||||||
*
|
*
|
||||||
* <p> If a call to {@code setSeed} had not occurred previously,
|
|
||||||
* the first call to this method forces this SecureRandom object
|
|
||||||
* to seed itself. This self-seeding will not occur if
|
|
||||||
* {@code setSeed} was previously called.
|
|
||||||
*
|
|
||||||
* @param bytes the array to be filled in with random bytes.
|
* @param bytes the array to be filled in with random bytes.
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
@ -477,6 +673,28 @@ public class SecureRandom extends java.util.Random {
|
|||||||
secureRandomSpi.engineNextBytes(bytes);
|
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
|
* Generates an integer containing the user-specified number of
|
||||||
* pseudo-random bits (right justified, with leading zeros). This
|
* pseudo-random bits (right justified, with leading zeros). This
|
||||||
@ -512,7 +730,7 @@ public class SecureRandom extends java.util.Random {
|
|||||||
*
|
*
|
||||||
* <p>This method is only included for backwards compatibility.
|
* <p>This method is only included for backwards compatibility.
|
||||||
* The caller is encouraged to use one of the alternative
|
* 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
|
* then call the {@code generateSeed} method to obtain seed bytes
|
||||||
* from that object.
|
* from that object.
|
||||||
*
|
*
|
||||||
@ -537,10 +755,13 @@ public class SecureRandom extends java.util.Random {
|
|||||||
* call may be used to seed other random number generators.
|
* call may be used to seed other random number generators.
|
||||||
*
|
*
|
||||||
* @param numBytes the number of seed bytes to generate.
|
* @param numBytes the number of seed bytes to generate.
|
||||||
*
|
* @throws IllegalArgumentException if {@code numBytes} is negative
|
||||||
* @return the seed bytes.
|
* @return the seed bytes.
|
||||||
*/
|
*/
|
||||||
public byte[] generateSeed(int numBytes) {
|
public byte[] generateSeed(int numBytes) {
|
||||||
|
if (numBytes < 0) {
|
||||||
|
throw new IllegalArgumentException("numBytes cannot be negative");
|
||||||
|
}
|
||||||
return secureRandomSpi.engineGenerateSeed(numBytes);
|
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
|
* Gets a default PRNG algorithm by looking through all registered
|
||||||
* providers. Returns the first PRNG algorithm of the first provider that
|
* providers. Returns the first PRNG algorithm of the first provider that
|
||||||
* has registered a SecureRandom implementation, or null if none of the
|
* has registered a {@code SecureRandom} implementation, or null if none of
|
||||||
* registered providers supplies a SecureRandom implementation.
|
* the registered providers supplies a {@code SecureRandom} implementation.
|
||||||
*/
|
*/
|
||||||
private static String getPrngAlgorithm() {
|
private static String getPrngAlgorithm() {
|
||||||
for (Provider p : Providers.getProviderList().providers()) {
|
for (Provider p : Providers.getProviderList().providers()) {
|
||||||
@ -667,6 +888,42 @@ public class SecureRandom extends java.util.Random {
|
|||||||
"No strong SecureRandom impls available: " + property);
|
"No strong SecureRandom impls available: " + property);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reseeds this {@code SecureRandom} with entropy input read from its
|
||||||
|
* entropy source.
|
||||||
|
*
|
||||||
|
* @throws UnsupportedOperationException if the underlying provider
|
||||||
|
* implementation has not overridden this method.
|
||||||
|
*
|
||||||
|
* @since 9
|
||||||
|
*/
|
||||||
|
public synchronized void reseed() {
|
||||||
|
secureRandomSpi.engineReseed(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reseeds this {@code SecureRandom} with entropy input read from its
|
||||||
|
* entropy source with additional parameters.
|
||||||
|
* <p>
|
||||||
|
* Note that entropy is obtained from an entropy source. While
|
||||||
|
* some data in {@code params} may contain entropy, its main usage is to
|
||||||
|
* provide diversity.
|
||||||
|
*
|
||||||
|
* @param params extra parameters
|
||||||
|
* @throws UnsupportedOperationException if the underlying provider
|
||||||
|
* implementation has not overridden this method.
|
||||||
|
* @throws IllegalArgumentException if {@code params} is {@code null},
|
||||||
|
* 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
|
// Declare serialVersionUID to be compatible with JDK1.1
|
||||||
static final long serialVersionUID = 4940670005562187L;
|
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
|
* We know that the MessageDigest class does not implement
|
||||||
* java.io.Serializable. However, since this field is no longer
|
* java.io.Serializable. However, since this field is no longer
|
||||||
* used, it will always be NULL and won't affect the serialization
|
* 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;
|
private byte[] randomBytes;
|
||||||
/**
|
/**
|
||||||
|
@ -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.
|
||||||
|
* <p>
|
||||||
|
* 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 {
|
||||||
|
}
|
@ -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.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
@ -27,13 +27,38 @@ package java.security;
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* This class defines the <i>Service Provider Interface</i> (<b>SPI</b>)
|
* This class defines the <i>Service Provider Interface</i> (<b>SPI</b>)
|
||||||
* for the {@code SecureRandom} class.
|
* for the {@link SecureRandom} class.
|
||||||
|
* <p>
|
||||||
* All the abstract methods in this class must be implemented by each
|
* All the abstract methods in this class must be implemented by each
|
||||||
* service provider who wishes to supply the implementation
|
* service provider who wishes to supply the implementation
|
||||||
* of a cryptographically strong pseudo-random number generator.
|
* 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
|
||||||
|
* <em>without</em> 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 <em>with</em> a {@code SecureRandomParameters} argument,
|
||||||
|
* the constructor will be called with that argument. The
|
||||||
|
* {@link #engineGetParameters()} method must not return {@code null}.
|
||||||
|
* <p>
|
||||||
|
* 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 <em>without</em> a
|
||||||
|
* {@code SecureRandomParameters} argument. Calling one of
|
||||||
|
* {@code SecureRandom}'s {@code getInstance} methods <em>with</em>
|
||||||
|
* 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
|
* @since 1.2
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@ -42,9 +67,30 @@ public abstract class SecureRandomSpi implements java.io.Serializable {
|
|||||||
private static final long serialVersionUID = -2991854161009191830L;
|
private static final long serialVersionUID = -2991854161009191830L;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Reseeds this random object. The given seed supplements, rather than
|
* Constructor without a parameter.
|
||||||
* replaces, the existing seed. Thus, repeated calls are guaranteed
|
*/
|
||||||
* never to reduce randomness.
|
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.
|
* @param seed the seed.
|
||||||
*/
|
*/
|
||||||
@ -52,16 +98,44 @@ public abstract class SecureRandomSpi implements java.io.Serializable {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Generates a user-specified number of random bytes.
|
* Generates a user-specified number of random bytes.
|
||||||
*
|
* <p>
|
||||||
* <p> If a call to {@code engineSetSeed} had not occurred previously,
|
* Some random number generators can only generate a limited amount
|
||||||
* the first call to this method forces this SecureRandom implementation
|
* of random bytes per invocation. If the size of {@code bytes}
|
||||||
* to seed itself. This self-seeding will not occur if
|
* is greater than this limit, the implementation should invoke
|
||||||
* {@code engineSetSeed} was previously called.
|
* 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.
|
* @param bytes the array to be filled in with random bytes.
|
||||||
*/
|
*/
|
||||||
protected abstract void engineNextBytes(byte[] bytes);
|
protected abstract void engineNextBytes(byte[] bytes);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generates a user-specified number of random bytes with
|
||||||
|
* additional parameters.
|
||||||
|
* <p>
|
||||||
|
* 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
|
* Returns the given number of seed bytes. This call may be used to
|
||||||
* seed other random number generators.
|
* seed other random number generators.
|
||||||
@ -70,5 +144,58 @@ public abstract class SecureRandomSpi implements java.io.Serializable {
|
|||||||
*
|
*
|
||||||
* @return the seed bytes.
|
* @return the seed bytes.
|
||||||
*/
|
*/
|
||||||
protected abstract byte[] engineGenerateSeed(int numBytes);
|
protected abstract byte[] engineGenerateSeed(int numBytes);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reseeds this random object with entropy input read from its
|
||||||
|
* entropy source with additional parameters.
|
||||||
|
* <p>
|
||||||
|
* If this method is called by {@link SecureRandom#reseed()},
|
||||||
|
* {@code params} will be {@code null}.
|
||||||
|
* <p>
|
||||||
|
* 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();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -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.
|
||||||
|
* <p>
|
||||||
|
* This class creates 5 new abstract methods. 3 are defined by the SP800-90A:
|
||||||
|
* <ol>
|
||||||
|
* <li>{@link #generateAlgorithm(byte[], byte[])}
|
||||||
|
* <li>{@link #reseedAlgorithm(byte[], byte[])} (might not be supported)
|
||||||
|
* <li>{@link #instantiateAlgorithm(byte[])}
|
||||||
|
* </ol>
|
||||||
|
* and 2 for implementation purpose:
|
||||||
|
* <ol>
|
||||||
|
* <li>{@link #initEngine()}
|
||||||
|
* <li>{@link #chooseAlgorithmAndStrength}
|
||||||
|
* </ol>
|
||||||
|
* All existing {@link SecureRandomSpi} methods are implemented based on the
|
||||||
|
* methods above as final. The initialization process is divided into 2 phases:
|
||||||
|
* configuration is eagerly called to set up parameters, and instantiation
|
||||||
|
* is lazily called only when nextBytes or reseed is called.
|
||||||
|
* <p>
|
||||||
|
* 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 <em>not</em> 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 <em>not</em> supported.
|
||||||
|
*/
|
||||||
|
protected boolean supportPredictionResistance = true;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether reseed is supported. A mechanism should update
|
||||||
|
* the value in its constructor if it is <em>not</em> 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}.
|
||||||
|
* <p>
|
||||||
|
* 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.
|
||||||
|
* <p>
|
||||||
|
* 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.
|
||||||
|
* <p>
|
||||||
|
* If {@code requestedAlgorithm} is not provided, an algorithm will be
|
||||||
|
* chosen that supports {@code requestedInstantiationSecurityStrength}
|
||||||
|
* (or {@code DEFAULT_STRENGTH} if there is no request).
|
||||||
|
* <p>
|
||||||
|
* Since every call to {@link #configure} will call this method,
|
||||||
|
* make sure to the calls do not contradict with each other.
|
||||||
|
* <p>
|
||||||
|
* Here are some examples of the algorithm and strength chosen (suppose
|
||||||
|
* {@code DEFAULT_STRENGTH} is 128) for HashDRBG:
|
||||||
|
* <pre>
|
||||||
|
* 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
|
||||||
|
* </pre>
|
||||||
|
*
|
||||||
|
* @throws IllegalArgumentException if the requested parameters
|
||||||
|
* can not be supported or contradict with each other.
|
||||||
|
*/
|
||||||
|
protected abstract void chooseAlgorithmAndStrength();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initiates security engines ({@code MessageDigest}, {@code Mac},
|
||||||
|
* or {@code Cipher}). Must be called in deserialization. Please note
|
||||||
|
* that before instantiation the algorithm might not be available yet.
|
||||||
|
* In this case, just return and this method will be called
|
||||||
|
* automatically at instantiation.
|
||||||
|
*/
|
||||||
|
protected abstract void initEngine();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Instantiates a DRBG. Called automatically before the first
|
||||||
|
* {@code nextBytes} call.
|
||||||
|
* <p>
|
||||||
|
* Note that the other parameters (nonce, strength, ps) are already
|
||||||
|
* stored inside at configuration.
|
||||||
|
*
|
||||||
|
* @param ei the entropy input, its length is already conditioned to be
|
||||||
|
* between {@link #minLength} and {@link #maxLength}.
|
||||||
|
*/
|
||||||
|
protected abstract void instantiateAlgorithm(byte[] ei);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The generate function.
|
||||||
|
*
|
||||||
|
* @param result fill result here, not null
|
||||||
|
* @param additionalInput additional input, can be null. If not null,
|
||||||
|
* its length is smaller than {@link #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.
|
||||||
|
* <p>
|
||||||
|
* 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".
|
||||||
|
* <p>
|
||||||
|
* This object uses {@link SeedGenerator#generateSeed(byte[])} to
|
||||||
|
* return a byte array containing {@code minLength} bytes. It is
|
||||||
|
* assumed to support prediction resistance and always contains
|
||||||
|
* full-entropy. A trusted application can update this field.
|
||||||
|
*/
|
||||||
|
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"));
|
||||||
|
}
|
||||||
|
}
|
@ -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);
|
||||||
|
}
|
@ -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");
|
||||||
|
}
|
||||||
|
}
|
271
jdk/src/java.base/share/classes/sun/security/provider/DRBG.java
Normal file
271
jdk/src/java.base/share/classes/sun/security/provider/DRBG.java
Normal file
@ -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<String>)
|
||||||
|
() -> Security.getProperty(PROP_NAME));
|
||||||
|
|
||||||
|
if (config != null && !config.isEmpty()) {
|
||||||
|
for (String part : config.split(",")) {
|
||||||
|
part = part.trim();
|
||||||
|
switch (part.toLowerCase(Locale.ROOT)) {
|
||||||
|
case "":
|
||||||
|
throw new IllegalArgumentException(
|
||||||
|
"aspect in " + PROP_NAME + " cannot be empty");
|
||||||
|
case "pr_and_reseed":
|
||||||
|
checkTwice(cap != null, "capability");
|
||||||
|
cap = PR_AND_RESEED;
|
||||||
|
break;
|
||||||
|
case "reseed_only":
|
||||||
|
checkTwice(cap != null, "capability");
|
||||||
|
cap = RESEED_ONLY;
|
||||||
|
break;
|
||||||
|
case "none":
|
||||||
|
checkTwice(cap != null, "capability");
|
||||||
|
cap = NONE;
|
||||||
|
break;
|
||||||
|
case "hash_drbg":
|
||||||
|
case "hmac_drbg":
|
||||||
|
case "ctr_drbg":
|
||||||
|
checkTwice(mech != null, "mechanism name");
|
||||||
|
mech = part;
|
||||||
|
break;
|
||||||
|
case "no_df":
|
||||||
|
checkTwice(usedf != null, "usedf flag");
|
||||||
|
usedf = false;
|
||||||
|
break;
|
||||||
|
case "use_df":
|
||||||
|
checkTwice(usedf != null, "usedf flag");
|
||||||
|
usedf = true;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
// For all other parts of the property, it is
|
||||||
|
// either an algorithm name or a strength
|
||||||
|
try {
|
||||||
|
int tmp = Integer.parseInt(part);
|
||||||
|
if (tmp < 0) {
|
||||||
|
throw new IllegalArgumentException(
|
||||||
|
"strength in " + PROP_NAME +
|
||||||
|
" cannot be negative: " + part);
|
||||||
|
}
|
||||||
|
checkTwice(strength >= 0, "strength");
|
||||||
|
strength = tmp;
|
||||||
|
} catch (NumberFormatException e) {
|
||||||
|
checkTwice(algorithm != null, "algorithm name");
|
||||||
|
algorithm = part;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Can be updated by params
|
||||||
|
|
||||||
|
if (params != null) {
|
||||||
|
// MoreDrbgParameters is used for testing.
|
||||||
|
if (params instanceof MoreDrbgParameters) {
|
||||||
|
MoreDrbgParameters m = (MoreDrbgParameters)params;
|
||||||
|
params = m.config;
|
||||||
|
|
||||||
|
// No need to check null for es and nonce, they are still null
|
||||||
|
es = m.es;
|
||||||
|
nonce = m.nonce;
|
||||||
|
|
||||||
|
if (m.mech != null) {
|
||||||
|
mech = m.mech;
|
||||||
|
}
|
||||||
|
if (m.algorithm != null) {
|
||||||
|
algorithm = m.algorithm;
|
||||||
|
}
|
||||||
|
usedf = m.usedf;
|
||||||
|
}
|
||||||
|
if (params instanceof DrbgParameters.Instantiation) {
|
||||||
|
DrbgParameters.Instantiation dp =
|
||||||
|
(DrbgParameters.Instantiation) params;
|
||||||
|
|
||||||
|
// ps is still null by now
|
||||||
|
ps = dp.getPersonalizationString();
|
||||||
|
|
||||||
|
int tmp = dp.getStrength();
|
||||||
|
if (tmp != -1) {
|
||||||
|
strength = tmp;
|
||||||
|
}
|
||||||
|
cap = dp.getCapability();
|
||||||
|
} else {
|
||||||
|
throw new IllegalArgumentException("Unsupported params: "
|
||||||
|
+ params.getClass());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Hardcoded defaults.
|
||||||
|
// Remember to sync with "securerandom.drbg.config" in java.security.
|
||||||
|
|
||||||
|
if (cap == null) {
|
||||||
|
cap = NONE;
|
||||||
|
}
|
||||||
|
if (mech == null) {
|
||||||
|
mech = "Hash_DRBG";
|
||||||
|
}
|
||||||
|
if (usedf == null) {
|
||||||
|
usedf = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
MoreDrbgParameters m = new MoreDrbgParameters(
|
||||||
|
es, mech, algorithm, nonce, usedf,
|
||||||
|
DrbgParameters.instantiation(strength, cap, ps));
|
||||||
|
|
||||||
|
switch (mech.toLowerCase(Locale.ROOT)) {
|
||||||
|
case "hash_drbg":
|
||||||
|
impl = new HashDrbg(m);
|
||||||
|
break;
|
||||||
|
case "hmac_drbg":
|
||||||
|
impl = new HmacDrbg(m);
|
||||||
|
break;
|
||||||
|
case "ctr_drbg":
|
||||||
|
impl = new CtrDrbg(m);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new IllegalArgumentException("Unsupported mech: " + mech);
|
||||||
|
}
|
||||||
|
|
||||||
|
mechName = mech;
|
||||||
|
algorithmName = impl.algorithm;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void engineSetSeed(byte[] seed) {
|
||||||
|
impl.engineSetSeed(seed);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void engineNextBytes(byte[] bytes) {
|
||||||
|
impl.engineNextBytes(bytes);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected byte[] engineGenerateSeed(int numBytes) {
|
||||||
|
return impl.engineGenerateSeed(numBytes);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void engineNextBytes(
|
||||||
|
byte[] bytes, SecureRandomParameters params) {
|
||||||
|
impl.engineNextBytes(bytes, params);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void engineReseed(SecureRandomParameters params) {
|
||||||
|
impl.engineReseed(params);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected SecureRandomParameters engineGetParameters() {
|
||||||
|
return impl.engineGetParameters();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return impl.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Ensures an aspect is not set more than once.
|
||||||
|
*
|
||||||
|
* @param flag true if set more than once
|
||||||
|
* @param name the name of aspect shown in IAE
|
||||||
|
* @throws IllegalArgumentException if it happens
|
||||||
|
*/
|
||||||
|
private static void checkTwice(boolean flag, String name) {
|
||||||
|
if (flag) {
|
||||||
|
throw new IllegalArgumentException(name
|
||||||
|
+ " cannot be provided more than once in " + PROP_NAME);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,47 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
|
||||||
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
|
*
|
||||||
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms of the GNU General Public License version 2 only, as
|
||||||
|
* published by the Free Software Foundation. Oracle designates this
|
||||||
|
* particular file as subject to the "Classpath" exception as provided
|
||||||
|
* by Oracle in the LICENSE file that accompanied this code.
|
||||||
|
*
|
||||||
|
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||||
|
* version 2 for more details (a copy is included in the LICENSE file that
|
||||||
|
* accompanied this code).
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License version
|
||||||
|
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||||
|
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
|
*
|
||||||
|
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||||
|
* or visit www.oracle.com if you need additional information or have any
|
||||||
|
* questions.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package sun.security.provider;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An interface of a source of entropy input.
|
||||||
|
*
|
||||||
|
* @since 9
|
||||||
|
*/
|
||||||
|
public interface EntropySource {
|
||||||
|
/**
|
||||||
|
* Returns a byte array containing entropy.
|
||||||
|
* <p>
|
||||||
|
* 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);
|
||||||
|
}
|
@ -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<len; i++) {
|
||||||
|
digest.update((byte) counter);
|
||||||
|
digest.update((byte)(requested >> 21)); // requested*8 as int32
|
||||||
|
digest.update((byte)(requested >> 13));
|
||||||
|
digest.update((byte)(requested >> 5));
|
||||||
|
digest.update((byte)(requested << 3));
|
||||||
|
for (byte[] input : inputs) {
|
||||||
|
digest.update(input);
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
digest.digest(temp, i * outLen, outLen);
|
||||||
|
} catch (DigestException e) {
|
||||||
|
throw new AssertionError("will not happen", e);
|
||||||
|
}
|
||||||
|
counter++;
|
||||||
|
}
|
||||||
|
return temp.length == requested? temp: Arrays.copyOf(temp, requested);
|
||||||
|
}
|
||||||
|
|
||||||
|
// This method is used by both instantiation and reseeding.
|
||||||
|
@Override
|
||||||
|
protected final void hashReseedInternal(byte[] input) {
|
||||||
|
|
||||||
|
// 800-90Ar1 10.1.1.2: Instantiate Process.
|
||||||
|
// 800-90Ar1 10.1.1.3: Reseed Process.
|
||||||
|
byte[] seed;
|
||||||
|
|
||||||
|
// Step 2: seed = Hash_df (seed_material, seedlen).
|
||||||
|
if (v != null) {
|
||||||
|
// Step 1 of 10.1.1.3: Prepend 0x01 || V
|
||||||
|
seed = hashDf(seedLen, ONE, v, input);
|
||||||
|
} else {
|
||||||
|
seed = hashDf(seedLen, input);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Step 3. V = seed.
|
||||||
|
v = seed;
|
||||||
|
|
||||||
|
// Step 4. C = Hash_df ((0x00 || V), seedlen).
|
||||||
|
c = hashDf(seedLen, ZERO, v);
|
||||||
|
|
||||||
|
// Step 5. reseed_counter = 1.
|
||||||
|
reseedCounter = 1;
|
||||||
|
|
||||||
|
//status();
|
||||||
|
|
||||||
|
// Step 6: Return
|
||||||
|
}
|
||||||
|
|
||||||
|
private void status() {
|
||||||
|
if (debug != null) {
|
||||||
|
debug.println(this, "V = " + hex(v));
|
||||||
|
debug.println(this, "C = " + hex(c));
|
||||||
|
debug.println(this, "reseed counter = " + reseedCounter);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds byte arrays into an existing one.
|
||||||
|
*
|
||||||
|
* @param out existing array
|
||||||
|
* @param data more arrays, can be of different length
|
||||||
|
*/
|
||||||
|
private static void addBytes(byte[] out, int len, byte[]... data) {
|
||||||
|
for (byte[] d: data) {
|
||||||
|
int dlen = d.length;
|
||||||
|
int carry = 0;
|
||||||
|
for (int i = 0; i < len; i++) {
|
||||||
|
int sum = (out[len - i - 1] & 0xff) + carry;
|
||||||
|
if (i < dlen) {
|
||||||
|
sum += (d[dlen - i - 1] & 0xff);
|
||||||
|
}
|
||||||
|
out[len - i - 1] = (byte) sum;
|
||||||
|
carry = sum >> 8;
|
||||||
|
if (i >= dlen - 1 && carry == 0) break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generates a user-specified number of random bytes.
|
||||||
|
*
|
||||||
|
* @param result the array to be filled in with random bytes.
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public final synchronized void generateAlgorithm(
|
||||||
|
byte[] result, byte[] additionalInput) {
|
||||||
|
|
||||||
|
if (debug != null) {
|
||||||
|
debug.println(this, "generateAlgorithm");
|
||||||
|
}
|
||||||
|
|
||||||
|
// 800-90Ar1 10.1.1.4: Hash_DRBG_Generate Process
|
||||||
|
|
||||||
|
// Step 1: Check reseed_counter. Will not fail. Already checked in
|
||||||
|
// AbstractDrbg#engineNextBytes.
|
||||||
|
|
||||||
|
// Step 2: additional_input
|
||||||
|
if (additionalInput != null) {
|
||||||
|
digest.update((byte)2);
|
||||||
|
digest.update(v);
|
||||||
|
digest.update(additionalInput);
|
||||||
|
addBytes(v, seedLen, digest.digest());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Step 3. Hashgen (requested_number_of_bits, V).
|
||||||
|
hashGen(result, result.length, v);
|
||||||
|
|
||||||
|
// Step 4. H = Hash (0x03 || V).
|
||||||
|
digest.update((byte)3);
|
||||||
|
digest.update(v);
|
||||||
|
byte[] h = digest.digest();
|
||||||
|
|
||||||
|
// Step 5. V = (V + H + C + reseed_counter) mod 2seedlen.
|
||||||
|
byte[] rcBytes;
|
||||||
|
if (reseedCounter < 256) {
|
||||||
|
rcBytes = new byte[]{(byte)reseedCounter};
|
||||||
|
} else {
|
||||||
|
rcBytes = BigInteger.valueOf(reseedCounter).toByteArray();
|
||||||
|
}
|
||||||
|
addBytes(v, seedLen, h, c, rcBytes);
|
||||||
|
|
||||||
|
// Step 6. reseed_counter = reseed_counter + 1.
|
||||||
|
reseedCounter++;
|
||||||
|
|
||||||
|
//status();
|
||||||
|
|
||||||
|
// Step 7: Return.
|
||||||
|
}
|
||||||
|
|
||||||
|
// 800-90Ar1 10.1.1.4: Hashgen
|
||||||
|
private void hashGen(byte[] output, int len, byte[] v) {
|
||||||
|
|
||||||
|
// Step 1. m
|
||||||
|
int m = (len + outLen - 1) / outLen;
|
||||||
|
|
||||||
|
// Step 2. data = V
|
||||||
|
byte[] data = v;
|
||||||
|
|
||||||
|
// Step 3: W is output not filled
|
||||||
|
|
||||||
|
// Step 4: For i = 1 to m
|
||||||
|
for (int i = 0; i < m; i++) {
|
||||||
|
int tailLen = len - i * outLen;
|
||||||
|
if (tailLen < outLen) {
|
||||||
|
// Step 4.1 w = Hash (data).
|
||||||
|
// Step 4.2 W = W || w.
|
||||||
|
System.arraycopy(digest.digest(data), 0, output, i * outLen,
|
||||||
|
tailLen);
|
||||||
|
} else {
|
||||||
|
try {
|
||||||
|
// Step 4.1 w = Hash (data).
|
||||||
|
digest.update(data);
|
||||||
|
// Step 4.2 digest into right position, no need to cat
|
||||||
|
digest.digest(output, i*outLen, outLen);
|
||||||
|
} catch (DigestException e) {
|
||||||
|
throw new AssertionError("will not happen", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Unless this is the last around, we will need to increment data.
|
||||||
|
// but we cannot change v, so a copy is made.
|
||||||
|
if (i != m - 1) {
|
||||||
|
if (data == v) {
|
||||||
|
data = Arrays.copyOf(v, v.length);
|
||||||
|
}
|
||||||
|
// Step 4.3 data = (data + 1) mod 2^seedlen.
|
||||||
|
addBytes(data, seedLen, ONE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Step 5: No need to truncate
|
||||||
|
// Step 6: Return
|
||||||
|
}
|
||||||
|
|
||||||
|
private void readObject(java.io.ObjectInputStream s)
|
||||||
|
throws IOException, ClassNotFoundException {
|
||||||
|
s.defaultReadObject ();
|
||||||
|
initEngine();
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,203 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
|
||||||
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
|
*
|
||||||
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms of the GNU General Public License version 2 only, as
|
||||||
|
* published by the Free Software Foundation. Oracle designates this
|
||||||
|
* particular file as subject to the "Classpath" exception as provided
|
||||||
|
* by Oracle in the LICENSE file that accompanied this code.
|
||||||
|
*
|
||||||
|
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||||
|
* version 2 for more details (a copy is included in the LICENSE file that
|
||||||
|
* accompanied this code).
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License version
|
||||||
|
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||||
|
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
|
*
|
||||||
|
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||||
|
* or visit www.oracle.com if you need additional information or have any
|
||||||
|
* questions.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package sun.security.provider;
|
||||||
|
|
||||||
|
import javax.crypto.Mac;
|
||||||
|
import javax.crypto.spec.SecretKeySpec;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.security.InvalidKeyException;
|
||||||
|
import java.security.NoSuchAlgorithmException;
|
||||||
|
import java.security.NoSuchProviderException;
|
||||||
|
import java.security.SecureRandomParameters;
|
||||||
|
import java.util.Arrays;
|
||||||
|
|
||||||
|
public class HmacDrbg extends AbstractHashDrbg {
|
||||||
|
|
||||||
|
private static final long serialVersionUID = 9L;
|
||||||
|
|
||||||
|
private transient Mac mac;
|
||||||
|
|
||||||
|
private String macAlg;
|
||||||
|
|
||||||
|
private transient byte[] v;
|
||||||
|
private transient byte[] k;
|
||||||
|
|
||||||
|
public HmacDrbg(SecureRandomParameters params) {
|
||||||
|
mechName = "HMAC_DRBG";
|
||||||
|
configure(params);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void status() {
|
||||||
|
if (debug != null) {
|
||||||
|
debug.println(this, "V = " + hex(v));
|
||||||
|
debug.println(this, "Key = " + hex(k));
|
||||||
|
debug.println(this, "reseed counter = " + reseedCounter);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 800-90Ar1 10.1.2.2: HMAC_DRBG Update Process
|
||||||
|
private void update(byte[]... inputs) {
|
||||||
|
try {
|
||||||
|
// Step 1. K = HMAC (K, V || 0x00 || provided_data).
|
||||||
|
mac.init(new SecretKeySpec(k, macAlg));
|
||||||
|
mac.update(v);
|
||||||
|
mac.update((byte) 0);
|
||||||
|
for (byte[] input: inputs) {
|
||||||
|
mac.update(input);
|
||||||
|
}
|
||||||
|
k = mac.doFinal();
|
||||||
|
|
||||||
|
// Step 2. V = HMAC (K, V).
|
||||||
|
mac.init(new SecretKeySpec(k, macAlg));
|
||||||
|
v = mac.doFinal(v);
|
||||||
|
|
||||||
|
if (inputs.length != 0) {
|
||||||
|
// Step 4. K = HMAC (K, V || 0x01 || provided_data).
|
||||||
|
mac.update(v);
|
||||||
|
mac.update((byte) 1);
|
||||||
|
for (byte[] input: inputs) {
|
||||||
|
mac.update(input);
|
||||||
|
}
|
||||||
|
k = mac.doFinal();
|
||||||
|
|
||||||
|
// Step 5. V=HMAC(K,V).
|
||||||
|
mac.init(new SecretKeySpec(k, macAlg));
|
||||||
|
v = mac.doFinal(v);
|
||||||
|
} // else Step 3
|
||||||
|
|
||||||
|
// Step 6. Return
|
||||||
|
} catch (InvalidKeyException e) {
|
||||||
|
throw new InternalError(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This call, used by the constructors, instantiates the digest.
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
protected void initEngine() {
|
||||||
|
macAlg = "HmacSHA" + algorithm.substring(4);
|
||||||
|
try {
|
||||||
|
mac = Mac.getInstance(macAlg, "SunJCE");
|
||||||
|
} catch (NoSuchProviderException | NoSuchAlgorithmException e) {
|
||||||
|
// Fallback to any available.
|
||||||
|
try {
|
||||||
|
mac = Mac.getInstance(macAlg);
|
||||||
|
} catch (NoSuchAlgorithmException exc) {
|
||||||
|
throw new InternalError(
|
||||||
|
"internal error: " + macAlg + " not available.", exc);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// This method is used by both instantiation and reseeding.
|
||||||
|
@Override
|
||||||
|
protected final void hashReseedInternal(byte[] input) {
|
||||||
|
|
||||||
|
// 800-90Ar1 10.1.2.3: Instantiate Process.
|
||||||
|
// 800-90Ar1 10.1.2.4: Reseed Process.
|
||||||
|
if (v == null) {
|
||||||
|
k = new byte[outLen];
|
||||||
|
v = new byte[outLen];
|
||||||
|
Arrays.fill(v, (byte) 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Step 2: HMAC_DRBG_Update
|
||||||
|
update(input);
|
||||||
|
|
||||||
|
// Step 3: reseed_counter = 1.
|
||||||
|
reseedCounter = 1;
|
||||||
|
//status();
|
||||||
|
|
||||||
|
// Step 4: Return
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generates a user-specified number of random bytes.
|
||||||
|
*
|
||||||
|
* @param result the array to be filled in with random bytes.
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public synchronized void generateAlgorithm(
|
||||||
|
byte[] result, byte[] additionalInput) {
|
||||||
|
|
||||||
|
if (debug != null) {
|
||||||
|
debug.println(this, "generateAlgorithm");
|
||||||
|
}
|
||||||
|
|
||||||
|
// 800-90Ar1 10.1.2.5: HMAC_DRBG_Generate Process
|
||||||
|
|
||||||
|
// Step 1: Check reseed_counter. Will not fail. Already checked in
|
||||||
|
// AbstractDrbg#engineNextBytes.
|
||||||
|
|
||||||
|
// Step 2. HMAC_DRBG_Update
|
||||||
|
if (additionalInput != null) {
|
||||||
|
update(additionalInput);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Step 3. temp = Null.
|
||||||
|
int pos = 0;
|
||||||
|
|
||||||
|
// Step 4. Loop
|
||||||
|
while (pos < result.length) {
|
||||||
|
int tailLen = result.length - pos;
|
||||||
|
|
||||||
|
// Step 4.1 V = HMAC (Key, V).
|
||||||
|
try {
|
||||||
|
mac.init(new SecretKeySpec(k, macAlg));
|
||||||
|
} catch (InvalidKeyException e) {
|
||||||
|
throw new InternalError(e);
|
||||||
|
}
|
||||||
|
v = mac.doFinal(v);
|
||||||
|
// Step 4.2 temp = temp || V.
|
||||||
|
System.arraycopy(v, 0, result, pos,
|
||||||
|
tailLen > outLen ? outLen : tailLen);
|
||||||
|
pos += outLen;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Step 5: No need to truncate
|
||||||
|
|
||||||
|
// Step 6. HMAC_DRBG_Update (additional_input, Key, V).
|
||||||
|
if (additionalInput != null) {
|
||||||
|
update(additionalInput);
|
||||||
|
} else {
|
||||||
|
update();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Step 7. reseed_counter = reseed_counter + 1.
|
||||||
|
reseedCounter++;
|
||||||
|
|
||||||
|
//status();
|
||||||
|
|
||||||
|
// Step 8. Return
|
||||||
|
}
|
||||||
|
|
||||||
|
private void readObject(java.io.ObjectInputStream s)
|
||||||
|
throws IOException, ClassNotFoundException {
|
||||||
|
s.defaultReadObject ();
|
||||||
|
initEngine();
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,73 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
|
||||||
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
|
*
|
||||||
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms of the GNU General Public License version 2 only, as
|
||||||
|
* published by the Free Software Foundation. Oracle designates this
|
||||||
|
* particular file as subject to the "Classpath" exception as provided
|
||||||
|
* by Oracle in the LICENSE file that accompanied this code.
|
||||||
|
*
|
||||||
|
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||||
|
* version 2 for more details (a copy is included in the LICENSE file that
|
||||||
|
* accompanied this code).
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License version
|
||||||
|
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||||
|
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
|
*
|
||||||
|
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||||
|
* or visit www.oracle.com if you need additional information or have any
|
||||||
|
* questions.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package sun.security.provider;
|
||||||
|
|
||||||
|
import java.security.DrbgParameters;
|
||||||
|
import java.security.SecureRandomParameters;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Extra non-standard parameters that can be used by DRBGs.
|
||||||
|
*/
|
||||||
|
public class MoreDrbgParameters implements SecureRandomParameters {
|
||||||
|
|
||||||
|
final String mech;
|
||||||
|
final String algorithm;
|
||||||
|
final EntropySource es;
|
||||||
|
final byte[] nonce;
|
||||||
|
final boolean usedf;
|
||||||
|
final DrbgParameters.Instantiation config;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new {@code MoreDrbgParameters} object.
|
||||||
|
*
|
||||||
|
* @param es the {@link EntropySource} to use. If set to {@code null},
|
||||||
|
* a default entropy source will be used.
|
||||||
|
* @param mech mech name. If set to {@code null}, the one in
|
||||||
|
* securerandom.drbg.config is used. This argument is ignored
|
||||||
|
* when passing to HashDrbg/HmacDrbg/CtrDrbg.
|
||||||
|
* @param algorithm the requested algorithm to use. If set to {@code null},
|
||||||
|
* the algorithm will be decided by strength.
|
||||||
|
* @param nonce the nonce to use. If set to {@code null},
|
||||||
|
* a nonce will be assigned.
|
||||||
|
* @param usedf whether a derivation function should be used
|
||||||
|
* @param config a {@link DrbgParameters.Instantiation} object
|
||||||
|
*/
|
||||||
|
public MoreDrbgParameters(EntropySource es, String mech,
|
||||||
|
String algorithm, byte[] nonce, boolean usedf,
|
||||||
|
DrbgParameters.Instantiation config) {
|
||||||
|
this.mech = mech;
|
||||||
|
this.algorithm = algorithm;
|
||||||
|
this.es = es;
|
||||||
|
this.nonce = nonce;
|
||||||
|
this.usedf = usedf;
|
||||||
|
this.config = config;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return mech + "," + algorithm + "," + usedf + "," + config;
|
||||||
|
}
|
||||||
|
}
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2002, 2012, Oracle and/or its affiliates. All rights reserved.
|
* Copyright (c) 2002, 2016, Oracle and/or its affiliates. All rights reserved.
|
||||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
@ -25,9 +25,7 @@
|
|||||||
|
|
||||||
package sun.security.provider;
|
package sun.security.provider;
|
||||||
|
|
||||||
import java.security.*;
|
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
import java.math.BigInteger;
|
|
||||||
|
|
||||||
import jdk.internal.HotSpotIntrinsicCandidate;
|
import jdk.internal.HotSpotIntrinsicCandidate;
|
||||||
import static sun.security.provider.ByteArrayAccess.*;
|
import static sun.security.provider.ByteArrayAccess.*;
|
||||||
@ -118,7 +116,14 @@ abstract class SHA5 extends DigestBase {
|
|||||||
i2bBig4((int)bitsProcessed, buffer, 124);
|
i2bBig4((int)bitsProcessed, buffer, 124);
|
||||||
implCompress(buffer, 0);
|
implCompress(buffer, 0);
|
||||||
|
|
||||||
l2bBig(state, 0, out, ofs, engineGetDigestLength());
|
int len = engineGetDigestLength();
|
||||||
|
if (len == 28) {
|
||||||
|
// Special case for SHA-512/224
|
||||||
|
l2bBig(state, 0, out, ofs, 24);
|
||||||
|
i2bBig4((int)(state[3] >> 32), out, ofs + 24);
|
||||||
|
} else {
|
||||||
|
l2bBig(state, 0, out, ofs, len);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -306,4 +311,31 @@ abstract class SHA5 extends DigestBase {
|
|||||||
super("SHA-384", 48, INITIAL_HASHES);
|
super("SHA-384", 48, INITIAL_HASHES);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
public static final class SHA512_224 extends SHA5 {
|
||||||
|
|
||||||
|
private static final long[] INITIAL_HASHES = {
|
||||||
|
0x8C3D37C819544DA2L, 0x73E1996689DCD4D6L,
|
||||||
|
0x1DFAB7AE32FF9C82L, 0x679DD514582F9FCFL,
|
||||||
|
0x0F6D2B697BD44DA8L, 0x77E36F7304C48942L,
|
||||||
|
0x3F9D85A86A1D36C8L, 0x1112E6AD91D692A1L
|
||||||
|
};
|
||||||
|
|
||||||
|
public SHA512_224() {
|
||||||
|
super("SHA-512/224", 28, INITIAL_HASHES);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static final class SHA512_256 extends SHA5 {
|
||||||
|
|
||||||
|
private static final long[] INITIAL_HASHES = {
|
||||||
|
0x22312194FC2BF72CL, 0x9F555FA3C84C64C2L,
|
||||||
|
0x2393B86B6F53B151L, 0x963877195940EABDL,
|
||||||
|
0x96283EE2A88EFFE3L, 0xBE5E1E2553863992L,
|
||||||
|
0x2B0199FC2C85B8AAL, 0x0EB72DDC81C52CA2L
|
||||||
|
};
|
||||||
|
|
||||||
|
public SHA512_256() {
|
||||||
|
super("SHA-512/256", 32, INITIAL_HASHES);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -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.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
@ -97,6 +97,9 @@ final class SunEntries {
|
|||||||
map.put("SecureRandom.NativePRNG",
|
map.put("SecureRandom.NativePRNG",
|
||||||
"sun.security.provider.NativePRNG");
|
"sun.security.provider.NativePRNG");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
map.put("SecureRandom.DRBG", "sun.security.provider.DRBG");
|
||||||
|
|
||||||
map.put("SecureRandom.SHA1PRNG",
|
map.put("SecureRandom.SHA1PRNG",
|
||||||
"sun.security.provider.SecureRandom");
|
"sun.security.provider.SecureRandom");
|
||||||
if (nativeAvailable && !useNativePRNG) {
|
if (nativeAvailable && !useNativePRNG) {
|
||||||
@ -199,6 +202,14 @@ final class SunEntries {
|
|||||||
map.put("Alg.Alias.MessageDigest.2.16.840.1.101.3.4.2.3", "SHA-512");
|
map.put("Alg.Alias.MessageDigest.2.16.840.1.101.3.4.2.3", "SHA-512");
|
||||||
map.put("Alg.Alias.MessageDigest.OID.2.16.840.1.101.3.4.2.3",
|
map.put("Alg.Alias.MessageDigest.OID.2.16.840.1.101.3.4.2.3",
|
||||||
"SHA-512");
|
"SHA-512");
|
||||||
|
map.put("MessageDigest.SHA-512/224", "sun.security.provider.SHA5$SHA512_224");
|
||||||
|
map.put("Alg.Alias.MessageDigest.2.16.840.1.101.3.4.2.5", "SHA-512/224");
|
||||||
|
map.put("Alg.Alias.MessageDigest.OID.2.16.840.1.101.3.4.2.5",
|
||||||
|
"SHA-512/224");
|
||||||
|
map.put("MessageDigest.SHA-512/256", "sun.security.provider.SHA5$SHA512_256");
|
||||||
|
map.put("Alg.Alias.MessageDigest.2.16.840.1.101.3.4.2.6", "SHA-512/256");
|
||||||
|
map.put("Alg.Alias.MessageDigest.OID.2.16.840.1.101.3.4.2.6",
|
||||||
|
"SHA-512/256");
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Algorithm Parameter Generator engines
|
* Algorithm Parameter Generator engines
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 1998, 2015, 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.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
@ -87,6 +87,7 @@ public class Debug {
|
|||||||
System.err.println("pkcs12 PKCS12 KeyStore debugging");
|
System.err.println("pkcs12 PKCS12 KeyStore debugging");
|
||||||
System.err.println("sunpkcs11 SunPKCS11 provider debugging");
|
System.err.println("sunpkcs11 SunPKCS11 provider debugging");
|
||||||
System.err.println("scl permissions SecureClassLoader assigns");
|
System.err.println("scl permissions SecureClassLoader assigns");
|
||||||
|
System.err.println("securerandom SecureRandom");
|
||||||
System.err.println("ts timestamping");
|
System.err.println("ts timestamping");
|
||||||
System.err.println();
|
System.err.println();
|
||||||
System.err.println("The following can be used with access:");
|
System.err.println("The following can be used with access:");
|
||||||
@ -174,6 +175,16 @@ public class Debug {
|
|||||||
System.err.println(prefix + ": "+message);
|
System.err.println(prefix + ": "+message);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* print a message to stderr that is prefixed with the prefix
|
||||||
|
* created from the call to getInstance and obj.
|
||||||
|
*/
|
||||||
|
public void println(Object obj, String message)
|
||||||
|
{
|
||||||
|
System.err.println(prefix + " [" + obj.getClass().getSimpleName() +
|
||||||
|
"@" + System.identityHashCode(obj) + "]: "+message);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* print a blank line to stderr that is prefixed with the prefix.
|
* print a blank line to stderr that is prefixed with the prefix.
|
||||||
*/
|
*/
|
||||||
|
@ -120,30 +120,30 @@ jdk.security.provider.preferred=AES:SunJCE, RSA:SunRsaSign
|
|||||||
#
|
#
|
||||||
# Sun Provider SecureRandom seed source.
|
# Sun Provider SecureRandom seed source.
|
||||||
#
|
#
|
||||||
# Select the primary source of seed data for the "SHA1PRNG" and
|
# Select the primary source of seed data for the "NativePRNG", "SHA1PRNG"
|
||||||
# "NativePRNG" SecureRandom implementations in the "Sun" provider.
|
# and "DRBG" SecureRandom implementations in the "Sun" provider.
|
||||||
# (Other SecureRandom implementations might also use this property.)
|
# (Other SecureRandom implementations might also use this property.)
|
||||||
#
|
#
|
||||||
# On Unix-like systems (for example, Solaris/Linux/MacOS), the
|
# On Unix-like systems (for example, Solaris/Linux/MacOS), the
|
||||||
# "NativePRNG" and "SHA1PRNG" implementations obtains seed data from
|
# "NativePRNG", "SHA1PRNG" and "DRBG" implementations obtains seed data from
|
||||||
# special device files such as file:/dev/random.
|
# special device files such as file:/dev/random.
|
||||||
#
|
#
|
||||||
# On Windows systems, specifying the URLs "file:/dev/random" or
|
# On Windows systems, specifying the URLs "file:/dev/random" or
|
||||||
# "file:/dev/urandom" will enable the native Microsoft CryptoAPI seeding
|
# "file:/dev/urandom" will enable the native Microsoft CryptoAPI seeding
|
||||||
# mechanism for SHA1PRNG.
|
# mechanism for SHA1PRNG and DRBG.
|
||||||
#
|
#
|
||||||
# By default, an attempt is made to use the entropy gathering device
|
# By default, an attempt is made to use the entropy gathering device
|
||||||
# specified by the "securerandom.source" Security property. If an
|
# specified by the "securerandom.source" Security property. If an
|
||||||
# exception occurs while accessing the specified URL:
|
# exception occurs while accessing the specified URL:
|
||||||
#
|
#
|
||||||
# SHA1PRNG:
|
|
||||||
# the traditional system/thread activity algorithm will be used.
|
|
||||||
#
|
|
||||||
# NativePRNG:
|
# NativePRNG:
|
||||||
# a default value of /dev/random will be used. If neither
|
# a default value of /dev/random will be used. If neither
|
||||||
# are available, the implementation will be disabled.
|
# are available, the implementation will be disabled.
|
||||||
# "file" is the only currently supported protocol type.
|
# "file" is the only currently supported protocol type.
|
||||||
#
|
#
|
||||||
|
# SHA1PRNG and DRBG:
|
||||||
|
# the traditional system/thread activity algorithm will be used.
|
||||||
|
#
|
||||||
# The entropy gathering device can also be specified with the System
|
# The entropy gathering device can also be specified with the System
|
||||||
# property "java.security.egd". For example:
|
# property "java.security.egd". For example:
|
||||||
#
|
#
|
||||||
@ -154,7 +154,7 @@ jdk.security.provider.preferred=AES:SunJCE, RSA:SunRsaSign
|
|||||||
#
|
#
|
||||||
# In addition, if "file:/dev/random" or "file:/dev/urandom" is
|
# In addition, if "file:/dev/random" or "file:/dev/urandom" is
|
||||||
# specified, the "NativePRNG" implementation will be more preferred than
|
# specified, the "NativePRNG" implementation will be more preferred than
|
||||||
# SHA1PRNG in the Sun provider.
|
# DRBG and SHA1PRNG in the Sun provider.
|
||||||
#
|
#
|
||||||
securerandom.source=file:/dev/random
|
securerandom.source=file:/dev/random
|
||||||
|
|
||||||
@ -169,12 +169,78 @@ securerandom.source=file:/dev/random
|
|||||||
# entries.
|
# entries.
|
||||||
#
|
#
|
||||||
#ifdef windows
|
#ifdef windows
|
||||||
securerandom.strongAlgorithms=Windows-PRNG:SunMSCAPI,SHA1PRNG:SUN
|
securerandom.strongAlgorithms=Windows-PRNG:SunMSCAPI,DRBG:SUN
|
||||||
#endif
|
#endif
|
||||||
#ifndef windows
|
#ifndef windows
|
||||||
securerandom.strongAlgorithms=NativePRNGBlocking:SUN
|
securerandom.strongAlgorithms=NativePRNGBlocking:SUN,DRBG:SUN
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#
|
||||||
|
# Sun provider DRBG configuration and default instantiation request.
|
||||||
|
#
|
||||||
|
# NIST SP 800-90Ar1 lists several DRBG mechanisms. Each can be configured
|
||||||
|
# with a DRBG algorithm name, and can be instantiated with a security strength,
|
||||||
|
# prediction resistance support, etc. This property defines the configuration
|
||||||
|
# and the default instantiation request of "DRBG" SecureRandom implementations
|
||||||
|
# in the SUN provider. (Other DRBG implementations can also use this property.)
|
||||||
|
# Applications can request different instantiation parameters like security
|
||||||
|
# strength, capability, personalization string using one of the
|
||||||
|
# getInstance(...,SecureRandomParameters,...) methods with a
|
||||||
|
# DrbgParameters.Instantiation argument, but other settings such as the
|
||||||
|
# mechanism and DRBG algorithm names are not currently configurable by any API.
|
||||||
|
#
|
||||||
|
# Please note that the SUN implementation of DRBG always supports reseeding.
|
||||||
|
#
|
||||||
|
# The value of this property is a comma-separated list of all configurable
|
||||||
|
# aspects. The aspects can appear in any order but the same aspect can only
|
||||||
|
# appear at most once. Its BNF-style definition is:
|
||||||
|
#
|
||||||
|
# Value:
|
||||||
|
# aspect { "," aspect }
|
||||||
|
#
|
||||||
|
# aspect:
|
||||||
|
# mech_name | algorithm_name | strength | capability | df
|
||||||
|
#
|
||||||
|
# // The DRBG mechanism to use. Default "Hash_DRBG"
|
||||||
|
# mech_name:
|
||||||
|
# "Hash_DRBG" | "HMAC_DRBG" | "CTR_DRBG"
|
||||||
|
#
|
||||||
|
# // The DRBG algorithm name. The "SHA-***" names are for Hash_DRBG and
|
||||||
|
# // HMAC_DRBG, default "SHA-256". "3KeyTDEA" and "AES-***" names are for
|
||||||
|
# // CTR_DRBG, default "AES-128" when using the limited cryptographic
|
||||||
|
# // or "AES-256" when using the unlimited.
|
||||||
|
# algorithm_name:
|
||||||
|
# "SHA-1" | "SHA-224" | "SHA-512/224" | "SHA-256" |
|
||||||
|
# "SHA-512/256" | "SHA-384" | "SHA-512" |
|
||||||
|
# "3KeyTDEA" | "AES-128" | "AES-192" | "AES-256"
|
||||||
|
#
|
||||||
|
# // Security strength requested. Default "128", or "112"
|
||||||
|
# // if mech_name is CTR_DRBG and algorithm_name is "3KeyTDEA"
|
||||||
|
# strength:
|
||||||
|
# "112" | "128" | "192" | "256"
|
||||||
|
#
|
||||||
|
# // Prediction resistance and reseeding request. Default "none"
|
||||||
|
# // "pr_and_reseed" - Both prediction resistance and reseeding
|
||||||
|
# // support requested
|
||||||
|
# // "reseed_only" - Only reseeding support requested
|
||||||
|
# // "none" - Neither prediction resistance not reseeding
|
||||||
|
# // support requested
|
||||||
|
# pr:
|
||||||
|
# "pr_and_reseed" | "reseed_only" | "none"
|
||||||
|
#
|
||||||
|
# // Whether a derivation function should be used. only applicable
|
||||||
|
# // to CTR_DRBG. Default "use_df"
|
||||||
|
# df:
|
||||||
|
# "use_df" | "no_df"
|
||||||
|
#
|
||||||
|
# Examples,
|
||||||
|
# securerandom.drbg.config=Hash_DRBG,SHA-1,112,none
|
||||||
|
# securerandom.drbg.config=CTR_DRBG,AES-256,192,pr_and_reseed,use_df
|
||||||
|
#
|
||||||
|
# The default value is an empty string, which is equivalent to
|
||||||
|
# securerandom.drbg.config=Hash_DRBG,SHA-256,128,none
|
||||||
|
securerandom.drbg.config=
|
||||||
|
|
||||||
#
|
#
|
||||||
# Class to instantiate as the javax.security.auth.login.Configuration
|
# Class to instantiate as the javax.security.auth.login.Configuration
|
||||||
# provider.
|
# provider.
|
||||||
|
79
jdk/test/com/sun/crypto/provider/Mac/HmacSHA512.java
Normal file
79
jdk/test/com/sun/crypto/provider/Mac/HmacSHA512.java
Normal file
@ -0,0 +1,79 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
|
||||||
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
|
*
|
||||||
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms of the GNU General Public License version 2 only, as
|
||||||
|
* published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||||
|
* version 2 for more details (a copy is included in the LICENSE file that
|
||||||
|
* accompanied this code).
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License version
|
||||||
|
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||||
|
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
|
*
|
||||||
|
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||||
|
* or visit www.oracle.com if you need additional information or have any
|
||||||
|
* questions.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import jdk.testlibrary.Asserts;
|
||||||
|
|
||||||
|
import javax.crypto.Mac;
|
||||||
|
import javax.crypto.spec.SecretKeySpec;
|
||||||
|
import java.util.Arrays;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @test
|
||||||
|
* @bug 8051408
|
||||||
|
* @library /lib/testlibrary
|
||||||
|
* @summary testing HmacSHA512/224 and HmacSHA512/256.
|
||||||
|
*/
|
||||||
|
public class HmacSHA512 {
|
||||||
|
public static void main(String[] args) throws Exception {
|
||||||
|
|
||||||
|
Mac mac;
|
||||||
|
|
||||||
|
// Test vectors obtained from
|
||||||
|
// https://groups.google.com/d/msg/sci.crypt/OolWgsgQD-8/IUR2KhCcfEkJ
|
||||||
|
mac = Mac.getInstance("HmacSHA512/224");
|
||||||
|
mac.init(new SecretKeySpec(xeh("4a656665"), "HmacSHA512/224"));
|
||||||
|
mac.update("what do ya want for nothing?".getBytes());
|
||||||
|
Asserts.assertTrue(Arrays.equals(mac.doFinal(),
|
||||||
|
xeh("4a530b31a79ebcce36916546317c45f247d83241dfb818fd37254bde")));
|
||||||
|
|
||||||
|
mac = Mac.getInstance("HmacSHA512/256");
|
||||||
|
mac.init(new SecretKeySpec(xeh("4a656665"), "HmacSHA512/256"));
|
||||||
|
mac.update("what do ya want for nothing?".getBytes());
|
||||||
|
Asserts.assertTrue(Arrays.equals(mac.doFinal(),
|
||||||
|
xeh("6df7b24630d5ccb2ee335407081a87188c221489768fa2020513b2d593359456")));
|
||||||
|
|
||||||
|
mac = Mac.getInstance("HmacSHA512/224");
|
||||||
|
mac.init(new SecretKeySpec(xeh("0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b"),
|
||||||
|
"HmacSHA512/224"));
|
||||||
|
mac.update("Hi There".getBytes());
|
||||||
|
Asserts.assertTrue(Arrays.equals(mac.doFinal(),
|
||||||
|
xeh("b244ba01307c0e7a8ccaad13b1067a4cf6b961fe0c6a20bda3d92039")));
|
||||||
|
|
||||||
|
mac = Mac.getInstance("HmacSHA512/256");
|
||||||
|
mac.init(new SecretKeySpec(xeh("0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b"),
|
||||||
|
"HmacSHA512/256"));
|
||||||
|
mac.update("Hi There".getBytes());
|
||||||
|
Asserts.assertTrue(Arrays.equals(mac.doFinal(),
|
||||||
|
xeh("9f9126c3d9c3c330d760425ca8a217e31feae31bfe70196ff81642b868402eab")));
|
||||||
|
}
|
||||||
|
|
||||||
|
static byte[] xeh(String in) {
|
||||||
|
in = in.replaceAll(" ", "");
|
||||||
|
int len = in.length() / 2;
|
||||||
|
byte[] out = new byte[len];
|
||||||
|
for (int i = 0; i < len; i++) {
|
||||||
|
out[i] = (byte)Integer.parseInt(in.substring(i * 2, i * 2 + 2), 16);
|
||||||
|
}
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
}
|
104
jdk/test/java/security/SecureRandom/DrbgParametersSpec.java
Normal file
104
jdk/test/java/security/SecureRandom/DrbgParametersSpec.java
Normal file
@ -0,0 +1,104 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
|
||||||
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
|
*
|
||||||
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms of the GNU General Public License version 2 only, as
|
||||||
|
* published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||||
|
* version 2 for more details (a copy is included in the LICENSE file that
|
||||||
|
* accompanied this code).
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License version
|
||||||
|
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||||
|
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
|
*
|
||||||
|
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||||
|
* or visit www.oracle.com if you need additional information or have any
|
||||||
|
* questions.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* @test
|
||||||
|
* @bug 8051408
|
||||||
|
* @summary Make sure DrbgParameters coded as specified
|
||||||
|
* @library /test/lib/share/classes
|
||||||
|
*/
|
||||||
|
|
||||||
|
import jdk.test.lib.Asserts;
|
||||||
|
|
||||||
|
import java.security.DrbgParameters;
|
||||||
|
import java.util.Arrays;
|
||||||
|
|
||||||
|
import static java.security.DrbgParameters.Capability.*;
|
||||||
|
|
||||||
|
public class DrbgParametersSpec {
|
||||||
|
|
||||||
|
public static void main(String args[]) throws Exception {
|
||||||
|
|
||||||
|
byte[] p, np1, np2;
|
||||||
|
|
||||||
|
// Capability
|
||||||
|
Asserts.assertTrue(PR_AND_RESEED.supportsPredictionResistance());
|
||||||
|
Asserts.assertTrue(PR_AND_RESEED.supportsReseeding());
|
||||||
|
Asserts.assertFalse(RESEED_ONLY.supportsPredictionResistance());
|
||||||
|
Asserts.assertTrue(RESEED_ONLY.supportsReseeding());
|
||||||
|
Asserts.assertFalse(NONE.supportsPredictionResistance());
|
||||||
|
Asserts.assertFalse(NONE.supportsReseeding());
|
||||||
|
|
||||||
|
// Instantiation
|
||||||
|
p = "Instantiation".getBytes();
|
||||||
|
DrbgParameters.Instantiation ins = DrbgParameters
|
||||||
|
.instantiation(192, RESEED_ONLY, p);
|
||||||
|
Asserts.assertTrue(ins.getStrength() == 192);
|
||||||
|
Asserts.assertTrue(ins.getCapability() == RESEED_ONLY);
|
||||||
|
np1 = ins.getPersonalizationString();
|
||||||
|
np2 = ins.getPersonalizationString();
|
||||||
|
// Getter outputs have same content but not the same object
|
||||||
|
Asserts.assertTrue(Arrays.equals(np1, p));
|
||||||
|
Asserts.assertTrue(Arrays.equals(np2, p));
|
||||||
|
Asserts.assertNE(np1, np2);
|
||||||
|
// Changes to original input has no affect on object
|
||||||
|
p[0] = 'X';
|
||||||
|
np2 = ins.getPersonalizationString();
|
||||||
|
Asserts.assertTrue(Arrays.equals(np1, np2));
|
||||||
|
|
||||||
|
ins = DrbgParameters.instantiation(-1, NONE, null);
|
||||||
|
Asserts.assertNull(ins.getPersonalizationString());
|
||||||
|
|
||||||
|
// NextBytes
|
||||||
|
p = "NextBytes".getBytes();
|
||||||
|
DrbgParameters.NextBytes nb = DrbgParameters
|
||||||
|
.nextBytes(192, true, p);
|
||||||
|
Asserts.assertTrue(nb.getStrength() == 192);
|
||||||
|
Asserts.assertTrue(nb.getPredictionResistance());
|
||||||
|
np1 = nb.getAdditionalInput();
|
||||||
|
np2 = nb.getAdditionalInput();
|
||||||
|
// Getter outputs have same content but not the same object
|
||||||
|
Asserts.assertTrue(Arrays.equals(np1, p));
|
||||||
|
Asserts.assertTrue(Arrays.equals(np2, p));
|
||||||
|
Asserts.assertNE(np1, np2);
|
||||||
|
// Changes to original input has no affect on object
|
||||||
|
p[0] = 'X';
|
||||||
|
np2 = nb.getAdditionalInput();
|
||||||
|
Asserts.assertTrue(Arrays.equals(np1, np2));
|
||||||
|
|
||||||
|
// Reseed
|
||||||
|
p = "Reseed".getBytes();
|
||||||
|
DrbgParameters.Reseed rs = DrbgParameters
|
||||||
|
.reseed(true, p);
|
||||||
|
Asserts.assertTrue(rs.getPredictionResistance());
|
||||||
|
np1 = rs.getAdditionalInput();
|
||||||
|
np2 = rs.getAdditionalInput();
|
||||||
|
// Getter outputs have same content but not the same object
|
||||||
|
Asserts.assertTrue(Arrays.equals(np1, p));
|
||||||
|
Asserts.assertTrue(Arrays.equals(np2, p));
|
||||||
|
Asserts.assertNE(np1, np2);
|
||||||
|
// Changes to original input has no affect on object
|
||||||
|
p[0] = 'X';
|
||||||
|
np2 = rs.getAdditionalInput();
|
||||||
|
Asserts.assertTrue(Arrays.equals(np1, np2));
|
||||||
|
}
|
||||||
|
}
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 1998, 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.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
@ -31,16 +31,73 @@ import java.io.*;
|
|||||||
|
|
||||||
public class Serialize {
|
public class Serialize {
|
||||||
|
|
||||||
public static void main(String args[]) throws IOException {
|
public static void main(String args[]) throws Exception {
|
||||||
|
for (String alg: new String[]{
|
||||||
|
"SHA1PRNG", "DRBG", "Hash_DRBG", "HMAC_DRBG", "CTR_DRBG",
|
||||||
|
"Hash_DRBG,SHA-512,192,pr_and_reseed"}) {
|
||||||
|
|
||||||
FileOutputStream fos = new FileOutputStream("t.tmp");
|
System.out.println("Testing " + alg);
|
||||||
ObjectOutputStream oos = new ObjectOutputStream(fos);
|
SecureRandom s1;
|
||||||
|
|
||||||
SecureRandom secRandom = new SecureRandom();
|
// A SecureRandom can be s11ned and des11ned at any time.
|
||||||
|
|
||||||
// serialize and write out
|
// Brand new.
|
||||||
oos.writeObject(secRandom);
|
s1 = getInstance(alg);
|
||||||
oos.flush();
|
revive(s1).nextInt();
|
||||||
oos.close();
|
if (alg.contains("DRBG")) {
|
||||||
|
revive(s1).reseed();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Used
|
||||||
|
s1 = getInstance(alg);
|
||||||
|
s1.nextInt(); // state set
|
||||||
|
revive(s1).nextInt();
|
||||||
|
if (alg.contains("DRBG")) {
|
||||||
|
revive(s1).reseed();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Automatically reseeded
|
||||||
|
s1 = getInstance(alg);
|
||||||
|
if (alg.contains("DRBG")) {
|
||||||
|
s1.reseed();
|
||||||
|
}
|
||||||
|
revive(s1).nextInt();
|
||||||
|
if (alg.contains("DRBG")) {
|
||||||
|
revive(s1).reseed();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Manually seeded
|
||||||
|
s1 = getInstance(alg);
|
||||||
|
s1.setSeed(1L);
|
||||||
|
revive(s1).nextInt();
|
||||||
|
if (alg.contains("DRBG")) {
|
||||||
|
revive(s1).reseed();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static SecureRandom getInstance(String alg) throws Exception {
|
||||||
|
if (alg.equals("SHA1PRNG") || alg.equals("DRBG")) {
|
||||||
|
return SecureRandom.getInstance(alg);
|
||||||
|
} else {
|
||||||
|
String old = Security.getProperty("securerandom.drbg.config");
|
||||||
|
try {
|
||||||
|
Security.setProperty("securerandom.drbg.config", alg);
|
||||||
|
return SecureRandom.getInstance("DRBG");
|
||||||
|
} finally {
|
||||||
|
Security.setProperty("securerandom.drbg.config", old);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static SecureRandom revive(SecureRandom oldOne) throws Exception {
|
||||||
|
ByteArrayOutputStream bout = new ByteArrayOutputStream();
|
||||||
|
new ObjectOutputStream(bout).writeObject(oldOne);
|
||||||
|
SecureRandom newOne = (SecureRandom) new ObjectInputStream(
|
||||||
|
new ByteArrayInputStream(bout.toByteArray())).readObject();
|
||||||
|
if (!oldOne.toString().equals(newOne.toString())) {
|
||||||
|
throw new Exception(newOne + " is not " + oldOne);
|
||||||
|
}
|
||||||
|
return newOne;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
70
jdk/test/sun/security/provider/MessageDigest/SHA512.java
Normal file
70
jdk/test/sun/security/provider/MessageDigest/SHA512.java
Normal file
@ -0,0 +1,70 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
|
||||||
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
|
*
|
||||||
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms of the GNU General Public License version 2 only, as
|
||||||
|
* published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||||
|
* version 2 for more details (a copy is included in the LICENSE file that
|
||||||
|
* accompanied this code).
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License version
|
||||||
|
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||||
|
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
|
*
|
||||||
|
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||||
|
* or visit www.oracle.com if you need additional information or have any
|
||||||
|
* questions.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import jdk.testlibrary.Asserts;
|
||||||
|
|
||||||
|
import java.security.MessageDigest;
|
||||||
|
import java.util.Arrays;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @test
|
||||||
|
* @bug 8051408
|
||||||
|
* @library /lib/testlibrary
|
||||||
|
* @summary testing SHA-512/224 and SHA-512/256.
|
||||||
|
*/
|
||||||
|
public class SHA512 {
|
||||||
|
public static void main(String[] args) throws Exception {
|
||||||
|
|
||||||
|
MessageDigest md;
|
||||||
|
|
||||||
|
// Test vectors obtained from
|
||||||
|
// http://csrc.nist.gov/groups/ST/toolkit/documents/Examples/SHA512_224.pdf
|
||||||
|
md = MessageDigest.getInstance("SHA-512/224");
|
||||||
|
Asserts.assertTrue(Arrays.equals(md.digest("abc".getBytes()),
|
||||||
|
xeh("4634270F 707B6A54 DAAE7530 460842E2 0E37ED26 5CEEE9A4 3E8924AA")));
|
||||||
|
Asserts.assertTrue(Arrays.equals(md.digest((
|
||||||
|
"abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmn" +
|
||||||
|
"hijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu").getBytes()),
|
||||||
|
xeh("23FEC5BB 94D60B23 30819264 0B0C4533 35D66473 4FE40E72 68674AF9")));
|
||||||
|
|
||||||
|
// Test vectors obtained from
|
||||||
|
// http://csrc.nist.gov/groups/ST/toolkit/documents/Examples/SHA512_256.pdf
|
||||||
|
md = MessageDigest.getInstance("SHA-512/256");
|
||||||
|
Asserts.assertTrue(Arrays.equals(md.digest("abc".getBytes()),
|
||||||
|
xeh("53048E26 81941EF9 9B2E29B7 6B4C7DAB E4C2D0C6 34FC6D46 E0E2F131 07E7AF23")));
|
||||||
|
Asserts.assertTrue(Arrays.equals(md.digest((
|
||||||
|
"abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmn" +
|
||||||
|
"hijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu").getBytes()),
|
||||||
|
xeh("3928E184 FB8690F8 40DA3988 121D31BE 65CB9D3E F83EE614 6FEAC861 E19B563A")));
|
||||||
|
}
|
||||||
|
|
||||||
|
static byte[] xeh(String in) {
|
||||||
|
in = in.replaceAll(" ", "");
|
||||||
|
int len = in.length() / 2;
|
||||||
|
byte[] out = new byte[len];
|
||||||
|
for (int i = 0; i < len; i++) {
|
||||||
|
out[i] = (byte)Integer.parseInt(in.substring(i * 2, i * 2 + 2), 16);
|
||||||
|
}
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,310 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
|
||||||
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
|
*
|
||||||
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms of the GNU General Public License version 2 only, as
|
||||||
|
* published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||||
|
* version 2 for more details (a copy is included in the LICENSE file that
|
||||||
|
* accompanied this code).
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License version
|
||||||
|
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||||
|
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
|
*
|
||||||
|
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||||
|
* or visit www.oracle.com if you need additional information or have any
|
||||||
|
* questions.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* @test
|
||||||
|
* @bug 8051408
|
||||||
|
* @modules java.base/sun.security.provider
|
||||||
|
* @summary check the AbstractDrbg API etc
|
||||||
|
*/
|
||||||
|
|
||||||
|
import java.security.*;
|
||||||
|
import sun.security.provider.AbstractDrbg;
|
||||||
|
import static java.security.DrbgParameters.Capability.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This test makes sure the AbstractDrbg API works as specified. It also
|
||||||
|
* checks the SecureRandom API.
|
||||||
|
*/
|
||||||
|
public class AbstractDrbgSpec {
|
||||||
|
|
||||||
|
public static void main(String args[]) throws Exception {
|
||||||
|
|
||||||
|
// getInstance from a provider.
|
||||||
|
|
||||||
|
Provider p = new All("A", 0, "");
|
||||||
|
byte[] bytes = new byte[100];
|
||||||
|
|
||||||
|
// A non-DRBG
|
||||||
|
iae(() -> SecureRandom.getInstance("S1", null, p));
|
||||||
|
nsae(() -> SecureRandom.getInstance("S1",
|
||||||
|
new SecureRandomParameters() {}, p));
|
||||||
|
|
||||||
|
SecureRandom s1 = SecureRandom.getInstance("S1", p);
|
||||||
|
if (s1.getParameters() != null) {
|
||||||
|
throw new Exception();
|
||||||
|
}
|
||||||
|
|
||||||
|
iae(() -> s1.nextBytes(bytes, null));
|
||||||
|
uoe(() -> s1.nextBytes(bytes, new SecureRandomParameters() {}));
|
||||||
|
uoe(() -> s1.reseed());
|
||||||
|
iae(() -> s1.reseed(null));
|
||||||
|
uoe(() -> s1.reseed(new SecureRandomParameters() {}));
|
||||||
|
|
||||||
|
// A weak DRBG
|
||||||
|
iae(() -> SecureRandom.getInstance("S2", null, p));
|
||||||
|
nsae(() -> SecureRandom.getInstance("S2",
|
||||||
|
new SecureRandomParameters() {}, p));
|
||||||
|
nsae(() -> SecureRandom.getInstance("S2",
|
||||||
|
DrbgParameters.instantiation(256, NONE, null), p));
|
||||||
|
nsae(() -> SecureRandom.getInstance("S2",
|
||||||
|
DrbgParameters.instantiation(-1, PR_AND_RESEED, null), p));
|
||||||
|
nsae(() -> SecureRandom.getInstance("S2",
|
||||||
|
DrbgParameters.instantiation(-1, RESEED_ONLY, null), p));
|
||||||
|
|
||||||
|
SecureRandom s2 = SecureRandom.getInstance("S2",
|
||||||
|
DrbgParameters.instantiation(-1, NONE, null), p);
|
||||||
|
equals(s2, "S2,SQUEEZE,128,none");
|
||||||
|
equals(s2.getParameters(), "128,none,null");
|
||||||
|
|
||||||
|
npe(() -> s2.nextBytes(null));
|
||||||
|
iae(() -> s2.nextBytes(bytes, null));
|
||||||
|
iae(() -> s2.nextBytes(bytes, new SecureRandomParameters() {}));
|
||||||
|
uoe(() -> s2.reseed());
|
||||||
|
iae(() -> s2.reseed(null));
|
||||||
|
|
||||||
|
iae(() -> s2.nextBytes(bytes,
|
||||||
|
DrbgParameters.nextBytes(-1, false, new byte[101])));
|
||||||
|
s2.nextBytes(new byte[101],
|
||||||
|
DrbgParameters.nextBytes(-1, false, new byte[100]));
|
||||||
|
s2.nextBytes(bytes,
|
||||||
|
DrbgParameters.nextBytes(-1, false, new byte[100]));
|
||||||
|
|
||||||
|
// A strong DRBG
|
||||||
|
iae(() -> SecureRandom.getInstance("S3", null, p));
|
||||||
|
nsae(() -> SecureRandom.getInstance("S3",
|
||||||
|
new SecureRandomParameters() {}, p));
|
||||||
|
SecureRandom.getInstance("S3",
|
||||||
|
DrbgParameters.instantiation(192, PR_AND_RESEED, null), p);
|
||||||
|
|
||||||
|
SecureRandom s3 = SecureRandom.getInstance("S3", p);
|
||||||
|
equals(s3, "S3,SQUEEZE,128,reseed_only");
|
||||||
|
equals(s3.getParameters(), "128,reseed_only,null");
|
||||||
|
|
||||||
|
iae(() -> s3.nextBytes(bytes,
|
||||||
|
DrbgParameters.nextBytes(192, false, null)));
|
||||||
|
iae(() -> s3.nextBytes(bytes,
|
||||||
|
DrbgParameters.nextBytes(112, true, null)));
|
||||||
|
iae(() -> s3.reseed(new SecureRandomParameters() {}));
|
||||||
|
|
||||||
|
SecureRandom s32 = SecureRandom.getInstance(
|
||||||
|
"S3", DrbgParameters.instantiation(192, PR_AND_RESEED, null), p);
|
||||||
|
equals(s32, "S3,SQUEEZE,192,pr_and_reseed");
|
||||||
|
equals(s32.getParameters(), "192,pr_and_reseed,null");
|
||||||
|
|
||||||
|
s32.nextBytes(bytes, DrbgParameters.nextBytes(192, false, null));
|
||||||
|
s32.nextBytes(bytes, DrbgParameters.nextBytes(112, true, null));
|
||||||
|
s32.reseed();
|
||||||
|
s32.reseed(DrbgParameters.reseed(true, new byte[100]));
|
||||||
|
|
||||||
|
// getInstance from competitive providers.
|
||||||
|
|
||||||
|
Provider l = new Legacy("L", 0, "");
|
||||||
|
Provider w = new Weak("W", 0, "");
|
||||||
|
Provider s = new Strong("S", 0, "");
|
||||||
|
|
||||||
|
Security.addProvider(l);
|
||||||
|
Security.addProvider(w);
|
||||||
|
Security.addProvider(s);
|
||||||
|
|
||||||
|
SecureRandom s4;
|
||||||
|
|
||||||
|
try {
|
||||||
|
s4 = SecureRandom.getInstance("S");
|
||||||
|
if (s4.getProvider() != l) {
|
||||||
|
throw new Exception();
|
||||||
|
}
|
||||||
|
|
||||||
|
nsae(() -> SecureRandom.getInstance(
|
||||||
|
"S", DrbgParameters.instantiation(256, NONE, null)));
|
||||||
|
|
||||||
|
s4 = SecureRandom.getInstance(
|
||||||
|
"S", DrbgParameters.instantiation(192, NONE, null));
|
||||||
|
if (s4.getProvider() != s) {
|
||||||
|
throw new Exception();
|
||||||
|
}
|
||||||
|
|
||||||
|
s4 = SecureRandom.getInstance(
|
||||||
|
"S", DrbgParameters.instantiation(128, PR_AND_RESEED, null));
|
||||||
|
if (s4.getProvider() != s) {
|
||||||
|
throw new Exception();
|
||||||
|
}
|
||||||
|
|
||||||
|
s4 = SecureRandom.getInstance(
|
||||||
|
"S", DrbgParameters.instantiation(128, RESEED_ONLY, null));
|
||||||
|
if (s4.getProvider() != s) {
|
||||||
|
throw new Exception();
|
||||||
|
}
|
||||||
|
|
||||||
|
s4 = SecureRandom.getInstance(
|
||||||
|
"S", DrbgParameters.instantiation(128, NONE, null));
|
||||||
|
if (s4.getProvider() != w) {
|
||||||
|
throw new Exception();
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
Security.removeProvider("L");
|
||||||
|
Security.removeProvider("W");
|
||||||
|
Security.removeProvider("S");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class All extends Provider {
|
||||||
|
protected All(String name, double version, String info) {
|
||||||
|
super(name, version, info);
|
||||||
|
put("SecureRandom.S1", S1.class.getName());
|
||||||
|
put("SecureRandom.S2", S2.class.getName());
|
||||||
|
put("SecureRandom.S3", S3.class.getName());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Providing S with no params support
|
||||||
|
public static class Legacy extends Provider {
|
||||||
|
protected Legacy(String name, double version, String info) {
|
||||||
|
super(name, version, info);
|
||||||
|
put("SecureRandom.S", S1.class.getName());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class Weak extends Provider {
|
||||||
|
protected Weak(String name, double version, String info) {
|
||||||
|
super(name, version, info);
|
||||||
|
put("SecureRandom.S", S2.class.getName());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class Strong extends Provider {
|
||||||
|
protected Strong(String name, double version, String info) {
|
||||||
|
super(name, version, info);
|
||||||
|
put("SecureRandom.S", S3.class.getName());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// This is not a DRBG.
|
||||||
|
public static class S1 extends SecureRandomSpi {
|
||||||
|
@Override
|
||||||
|
protected void engineSetSeed(byte[] seed) {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void engineNextBytes(byte[] bytes) {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected byte[] engineGenerateSeed(int numBytes) {
|
||||||
|
return new byte[numBytes];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// This is a strong DRBG.
|
||||||
|
public static class S3 extends AbstractDrbg {
|
||||||
|
|
||||||
|
public S3(SecureRandomParameters params) {
|
||||||
|
supportPredictionResistance = true;
|
||||||
|
supportReseeding = true;
|
||||||
|
highestSupportedSecurityStrength = 192;
|
||||||
|
mechName = "S3";
|
||||||
|
algorithm = "SQUEEZE";
|
||||||
|
configure(params);
|
||||||
|
}
|
||||||
|
protected void chooseAlgorithmAndStrength() {
|
||||||
|
if (requestedInstantiationSecurityStrength < 0) {
|
||||||
|
securityStrength = DEFAULT_STRENGTH;
|
||||||
|
} else {
|
||||||
|
securityStrength = requestedInstantiationSecurityStrength;
|
||||||
|
}
|
||||||
|
minLength = securityStrength / 8;
|
||||||
|
maxAdditionalInputLength = maxPersonalizationStringLength = 100;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void initEngine() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void instantiateAlgorithm(byte[] ei) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void generateAlgorithm(byte[] result, byte[] additionalInput) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void reseedAlgorithm(byte[] ei, byte[] additionalInput) {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// This is a weak DRBG. maximum strength is 128 and does
|
||||||
|
// not support prediction resistance or reseed.
|
||||||
|
public static class S2 extends S3 {
|
||||||
|
public S2(SecureRandomParameters params) {
|
||||||
|
super(null);
|
||||||
|
mechName = "S2";
|
||||||
|
highestSupportedSecurityStrength = 128;
|
||||||
|
supportPredictionResistance = false;
|
||||||
|
supportReseeding = false;
|
||||||
|
configure(params);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void nsae(RunnableWithException r) throws Exception {
|
||||||
|
checkException(r, NoSuchAlgorithmException.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void iae(RunnableWithException r) throws Exception {
|
||||||
|
checkException(r, IllegalArgumentException.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void uoe(RunnableWithException r) throws Exception {
|
||||||
|
checkException(r, UnsupportedOperationException.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void npe(RunnableWithException r) throws Exception {
|
||||||
|
checkException(r, NullPointerException.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
interface RunnableWithException {
|
||||||
|
void run() throws Exception;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void checkException(RunnableWithException r, Class ex)
|
||||||
|
throws Exception {
|
||||||
|
try {
|
||||||
|
r.run();
|
||||||
|
} catch (Exception e) {
|
||||||
|
if (ex.isAssignableFrom(e.getClass())) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
throw new Exception("No exception thrown");
|
||||||
|
}
|
||||||
|
|
||||||
|
static void equals(Object o, String s) throws Exception {
|
||||||
|
if (!o.toString().equals(s)) {
|
||||||
|
throw new Exception(o.toString() + " is not " + s);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
54
jdk/test/sun/security/provider/SecureRandom/AutoReseed.java
Normal file
54
jdk/test/sun/security/provider/SecureRandom/AutoReseed.java
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
|
||||||
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
|
*
|
||||||
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms of the GNU General Public License version 2 only, as
|
||||||
|
* published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||||
|
* version 2 for more details (a copy is included in the LICENSE file that
|
||||||
|
* accompanied this code).
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License version
|
||||||
|
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||||
|
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
|
*
|
||||||
|
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||||
|
* or visit www.oracle.com if you need additional information or have any
|
||||||
|
* questions.
|
||||||
|
*/
|
||||||
|
import java.security.SecureRandom;
|
||||||
|
import java.security.Security;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @test
|
||||||
|
* @bug 8051408
|
||||||
|
* @summary make sure nextBytes etc can be called before setSeed
|
||||||
|
*/
|
||||||
|
public class AutoReseed {
|
||||||
|
|
||||||
|
public static void main(String[] args) throws Exception {
|
||||||
|
SecureRandom sr;
|
||||||
|
String old = Security.getProperty("securerandom.drbg.config");
|
||||||
|
try {
|
||||||
|
for (String mech :
|
||||||
|
new String[]{"Hash_DRBG", "HMAC_DRBG", "CTR_DRBG"}) {
|
||||||
|
System.out.println("Testing " + mech + "...");
|
||||||
|
Security.setProperty("securerandom.drbg.config", mech);
|
||||||
|
|
||||||
|
// Check auto reseed works
|
||||||
|
sr = SecureRandom.getInstance("DRBG");
|
||||||
|
sr.nextInt();
|
||||||
|
sr = SecureRandom.getInstance("DRBG");
|
||||||
|
sr.reseed();
|
||||||
|
sr = SecureRandom.getInstance("DRBG");
|
||||||
|
sr.generateSeed(10);
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
Security.setProperty("securerandom.drbg.config", old);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
132
jdk/test/sun/security/provider/SecureRandom/CommonSeeder.java
Normal file
132
jdk/test/sun/security/provider/SecureRandom/CommonSeeder.java
Normal file
@ -0,0 +1,132 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
|
||||||
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
|
*
|
||||||
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms of the GNU General Public License version 2 only, as
|
||||||
|
* published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||||
|
* version 2 for more details (a copy is included in the LICENSE file that
|
||||||
|
* accompanied this code).
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License version
|
||||||
|
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||||
|
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
|
*
|
||||||
|
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||||
|
* or visit www.oracle.com if you need additional information or have any
|
||||||
|
* questions.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import sun.security.provider.AbstractDrbg;
|
||||||
|
import sun.security.provider.EntropySource;
|
||||||
|
|
||||||
|
import java.lang.reflect.Field;
|
||||||
|
import java.lang.reflect.Modifier;
|
||||||
|
import java.security.DrbgParameters;
|
||||||
|
import java.security.SecureRandom;
|
||||||
|
import java.security.Security;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @test
|
||||||
|
* @bug 8051408
|
||||||
|
* @modules java.base/sun.security.provider
|
||||||
|
* @run main/othervm CommonSeeder
|
||||||
|
* @summary check entropy reading of DRBGs
|
||||||
|
*/
|
||||||
|
public class CommonSeeder {
|
||||||
|
|
||||||
|
static class MyES implements EntropySource {
|
||||||
|
int count = 100;
|
||||||
|
int lastCount = 100;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public byte[] getEntropy(int minEntropy, int minLength,
|
||||||
|
int maxLength, boolean pr) {
|
||||||
|
count--;
|
||||||
|
return new byte[minLength];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Confirms genEntropy() has been called {@code less} times
|
||||||
|
* since last check.
|
||||||
|
*/
|
||||||
|
public void checkUsage(int less) throws Exception {
|
||||||
|
if (lastCount != count + less) {
|
||||||
|
throw new Exception(String.format(
|
||||||
|
"lastCount = %d, count = %d, less = %d",
|
||||||
|
lastCount, count, less));
|
||||||
|
}
|
||||||
|
lastCount = count;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void main(String[] args) throws Exception {
|
||||||
|
|
||||||
|
byte[] result = new byte[10];
|
||||||
|
MyES es = new MyES();
|
||||||
|
|
||||||
|
// Set es as the default entropy source, overriding SeedGenerator.
|
||||||
|
setDefaultSeeder(es);
|
||||||
|
|
||||||
|
// Nothing happened yet
|
||||||
|
es.checkUsage(0);
|
||||||
|
|
||||||
|
SecureRandom sr;
|
||||||
|
sr = SecureRandom.getInstance("DRBG");
|
||||||
|
|
||||||
|
// No entropy reading if only getInstance
|
||||||
|
es.checkUsage(0);
|
||||||
|
|
||||||
|
// Entropy is read at 1st nextBytes of the 1st DRBG
|
||||||
|
sr.nextInt();
|
||||||
|
es.checkUsage(1);
|
||||||
|
|
||||||
|
for (String mech : new String[]{"Hash_DRBG", "HMAC_DRBG", "CTR_DRBG"}) {
|
||||||
|
System.out.println("Testing " + mech + "...");
|
||||||
|
|
||||||
|
// DRBG with pr_false will never read entropy again no matter
|
||||||
|
// if nextBytes or reseed is called.
|
||||||
|
|
||||||
|
Security.setProperty("securerandom.drbg.config", mech);
|
||||||
|
sr = SecureRandom.getInstance("DRBG");
|
||||||
|
sr.nextInt();
|
||||||
|
sr.reseed();
|
||||||
|
es.checkUsage(0);
|
||||||
|
|
||||||
|
// DRBG with pr_true always read from default entropy, and
|
||||||
|
// its nextBytes always reseed itself
|
||||||
|
|
||||||
|
Security.setProperty("securerandom.drbg.config",
|
||||||
|
mech + ",pr_and_reseed");
|
||||||
|
sr = SecureRandom.getInstance("DRBG");
|
||||||
|
|
||||||
|
sr.nextInt();
|
||||||
|
es.checkUsage(2); // one instantiate, one reseed
|
||||||
|
sr.nextInt();
|
||||||
|
es.checkUsage(1); // one reseed in nextBytes
|
||||||
|
sr.reseed();
|
||||||
|
es.checkUsage(1); // one reseed
|
||||||
|
sr.nextBytes(result, DrbgParameters.nextBytes(-1, false, null));
|
||||||
|
es.checkUsage(0); // pr_false for this call
|
||||||
|
sr.nextBytes(result, DrbgParameters.nextBytes(-1, true, null));
|
||||||
|
es.checkUsage(1); // pr_true for this call
|
||||||
|
sr.reseed(DrbgParameters.reseed(true, null));
|
||||||
|
es.checkUsage(1); // reseed from es
|
||||||
|
sr.reseed(DrbgParameters.reseed(false, null));
|
||||||
|
es.checkUsage(0); // reseed from AbstractDrbg.SeederHolder.seeder
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void setDefaultSeeder(EntropySource es) throws Exception {
|
||||||
|
Field f = AbstractDrbg.class.getDeclaredField("defaultES");
|
||||||
|
f.setAccessible(true); // no more private
|
||||||
|
Field f2 = Field.class.getDeclaredField("modifiers");
|
||||||
|
f2.setAccessible(true);
|
||||||
|
f2.setInt(f, f2.getInt(f) - Modifier.FINAL); // no more final
|
||||||
|
f.set(null, es);
|
||||||
|
}
|
||||||
|
}
|
180
jdk/test/sun/security/provider/SecureRandom/DRBGAlg.java
Normal file
180
jdk/test/sun/security/provider/SecureRandom/DRBGAlg.java
Normal file
@ -0,0 +1,180 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
|
||||||
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
|
*
|
||||||
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms of the GNU General Public License version 2 only, as
|
||||||
|
* published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||||
|
* version 2 for more details (a copy is included in the LICENSE file that
|
||||||
|
* accompanied this code).
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License version
|
||||||
|
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||||
|
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
|
*
|
||||||
|
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||||
|
* or visit www.oracle.com if you need additional information or have any
|
||||||
|
* questions.
|
||||||
|
*/
|
||||||
|
import sun.security.provider.MoreDrbgParameters;
|
||||||
|
|
||||||
|
import java.security.DrbgParameters;
|
||||||
|
import java.security.NoSuchAlgorithmException;
|
||||||
|
import java.security.SecureRandom;
|
||||||
|
import java.security.SecureRandomParameters;
|
||||||
|
import java.security.Security;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
import static java.security.DrbgParameters.Capability.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @test
|
||||||
|
* @bug 8051408
|
||||||
|
* @modules java.base/sun.security.provider
|
||||||
|
* @summary make sure DRBG alg can be defined and instantiated freely
|
||||||
|
*/
|
||||||
|
public class DRBGAlg {
|
||||||
|
|
||||||
|
public static void main(String[] args) throws Exception {
|
||||||
|
|
||||||
|
check(null, "Hash_DRBG", "SHA-256", "reseed_only", ",128");
|
||||||
|
check("", "Hash_DRBG", "SHA-256", "reseed_only", ",128");
|
||||||
|
check("sha-1", "Hash_DRBG", "SHA-1", "reseed_only", ",128");
|
||||||
|
check("sha-256", "Hash_DRBG", "SHA-256", "reseed_only", ",128");
|
||||||
|
check("SHA-3");
|
||||||
|
check("hash_drbg", "Hash_DRBG", "SHA-256", "reseed_only", ",128");
|
||||||
|
check("hmac_drbg", "HMAC_DRBG", "SHA-256", "reseed_only", ",128");
|
||||||
|
check("ctr_drbg", "CTR_DRBG", "AES-", "reseed_only", ",128", "use_df");
|
||||||
|
|
||||||
|
// trying all permutations
|
||||||
|
checkPermutations(
|
||||||
|
Collections.emptyList(),
|
||||||
|
Arrays.asList("hash_drbg","sha-512","Pr_and_Reseed","192"),
|
||||||
|
"Hash_DRBG", "SHA-512", "pr_and_reseed", ",192");
|
||||||
|
|
||||||
|
check("Hash_DRBG,Hmac_DRBG");
|
||||||
|
check("SHA-1,SHA-256");
|
||||||
|
check("128,256");
|
||||||
|
check("none,reseed_only");
|
||||||
|
check("use_df,no_df");
|
||||||
|
check("Hash_DRBG,,SHA-1");
|
||||||
|
|
||||||
|
check(null, DrbgParameters.instantiation(112, PR_AND_RESEED, null),
|
||||||
|
"Hash_DRBG", "SHA-256", "pr_and_reseed", ",112");
|
||||||
|
check(null, DrbgParameters.instantiation(256, PR_AND_RESEED, null),
|
||||||
|
"Hash_DRBG", "SHA-256", "pr_and_reseed", ",256");
|
||||||
|
check(null, DrbgParameters.instantiation(384, PR_AND_RESEED, null));
|
||||||
|
check("sha-1", DrbgParameters.instantiation(112, PR_AND_RESEED, null),
|
||||||
|
"Hash_DRBG", "SHA-1", "pr_and_reseed", ",112");
|
||||||
|
check("sha-1", DrbgParameters.instantiation(192, PR_AND_RESEED, null));
|
||||||
|
check("hash_drbg,sha-512,Pr_and_Reseed,192",
|
||||||
|
DrbgParameters.instantiation(112, NONE, null),
|
||||||
|
"Hash_DRBG", "SHA-512", "reseed_only", ",112");
|
||||||
|
check("hash_drbg,sha-512,Pr_and_Reseed,192",
|
||||||
|
DrbgParameters.instantiation(-1, NONE, null),
|
||||||
|
"Hash_DRBG", "SHA-512", "reseed_only", ",192");
|
||||||
|
// getInstance params can be stronger than definition
|
||||||
|
check("hash_drbg,sha-256,None,112",
|
||||||
|
DrbgParameters.instantiation(192, PR_AND_RESEED, null),
|
||||||
|
"Hash_DRBG", "SHA-256", "pr_and_reseed", ",192");
|
||||||
|
|
||||||
|
check("hash_drbg,sha-1", new MoreDrbgParameters(
|
||||||
|
null, null, "sha-512", null, false,
|
||||||
|
DrbgParameters.instantiation(-1, NONE, null)),
|
||||||
|
"Hash_DRBG", "SHA-512");
|
||||||
|
check("hash_drbg,sha-1", new MoreDrbgParameters(
|
||||||
|
null, null, null, null, false,
|
||||||
|
DrbgParameters.instantiation(-1, NONE, null)),
|
||||||
|
"Hash_DRBG", "SHA-1");
|
||||||
|
check("hash_drbg", new MoreDrbgParameters(
|
||||||
|
null, "hmac_drbg", null, null, false,
|
||||||
|
DrbgParameters.instantiation(-1, NONE, null)),
|
||||||
|
"HMAC_DRBG", "SHA-256");
|
||||||
|
|
||||||
|
check("hash_drbg,sha-1", new MoreDrbgParameters(
|
||||||
|
null, null, "sha-3", null, false,
|
||||||
|
DrbgParameters.instantiation(-1, NONE, null)));
|
||||||
|
check("hash_drbg,sha-1", new MoreDrbgParameters(
|
||||||
|
null, "Unknown_DRBG", null, null, false,
|
||||||
|
DrbgParameters.instantiation(-1, NONE, null)));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks all permutatins of a config. This is a recursive method and
|
||||||
|
* should be called with checkPermutations(empty,config,expected).
|
||||||
|
*
|
||||||
|
* @param current the current chosen aspects
|
||||||
|
* @param remains the remaining
|
||||||
|
* @param expected the expected effective config
|
||||||
|
* @throws Exception when check fails
|
||||||
|
*/
|
||||||
|
private static void checkPermutations(List<String> current,
|
||||||
|
List<String> remains, String... expected) throws Exception {
|
||||||
|
if (remains.isEmpty()) {
|
||||||
|
check(current.stream().collect(Collectors.joining(",")), expected);
|
||||||
|
} else {
|
||||||
|
for (String r : remains) {
|
||||||
|
List<String> newCurrent = new ArrayList<>(current);
|
||||||
|
newCurrent.add(r);
|
||||||
|
List<String> newRemains = new ArrayList<>(remains);
|
||||||
|
newRemains.remove(r);
|
||||||
|
checkPermutations(newCurrent, newRemains, expected);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks DRBG definition for getInstance(alg, params).
|
||||||
|
*
|
||||||
|
* @param define DRBG
|
||||||
|
* @param params getInstance request (null if none)
|
||||||
|
* @param expected expected actual instantiate params, empty if should fail
|
||||||
|
*/
|
||||||
|
static void check(String define, SecureRandomParameters params,
|
||||||
|
String... expected) throws Exception {
|
||||||
|
System.out.println("Testing " + define + " with " + params + "...");
|
||||||
|
String old = Security.getProperty("securerandom.drbg.config");
|
||||||
|
if (define != null) {
|
||||||
|
Security.setProperty("securerandom.drbg.config", define);
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
String result = params != null ?
|
||||||
|
SecureRandom.getInstance("DRBG", params).toString() :
|
||||||
|
SecureRandom.getInstance("DRBG").toString();
|
||||||
|
System.out.println("Result " + result);
|
||||||
|
if (expected.length == 0) {
|
||||||
|
throw new Exception("should fail");
|
||||||
|
}
|
||||||
|
for (String s : expected) {
|
||||||
|
if (!result.contains(s)) {
|
||||||
|
throw new Exception(result);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (NoSuchAlgorithmException e) {
|
||||||
|
System.out.println("Result NSAE");
|
||||||
|
if (expected.length > 0) {
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
Security.setProperty("securerandom.drbg.config", old);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks DRBG definition for getInstance(alg).
|
||||||
|
*
|
||||||
|
* @param define DRBG
|
||||||
|
* @param expected expected actual instantiate params, empty if should fail
|
||||||
|
*/
|
||||||
|
static void check(String define, String... expected) throws Exception {
|
||||||
|
check(define, null, expected);
|
||||||
|
}
|
||||||
|
}
|
422
jdk/test/sun/security/provider/SecureRandom/DrbgCavp.java
Normal file
422
jdk/test/sun/security/provider/SecureRandom/DrbgCavp.java
Normal file
@ -0,0 +1,422 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
|
||||||
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
|
*
|
||||||
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms of the GNU General Public License version 2 only, as
|
||||||
|
* published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||||
|
* version 2 for more details (a copy is included in the LICENSE file that
|
||||||
|
* accompanied this code).
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License version
|
||||||
|
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||||
|
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
|
*
|
||||||
|
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||||
|
* or visit www.oracle.com if you need additional information or have any
|
||||||
|
* questions.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import sun.security.provider.EntropySource;
|
||||||
|
import sun.security.provider.MoreDrbgParameters;
|
||||||
|
|
||||||
|
import javax.crypto.Cipher;
|
||||||
|
import java.io.BufferedReader;
|
||||||
|
import java.io.ByteArrayOutputStream;
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.io.InputStreamReader;
|
||||||
|
import java.io.PrintStream;
|
||||||
|
import java.lang.*;
|
||||||
|
import java.security.NoSuchAlgorithmException;
|
||||||
|
import java.security.SecureRandom;
|
||||||
|
import java.security.DrbgParameters;
|
||||||
|
import java.util.ArrayDeque;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.Queue;
|
||||||
|
import java.util.stream.Stream;
|
||||||
|
import java.util.zip.ZipEntry;
|
||||||
|
import java.util.zip.ZipFile;
|
||||||
|
import java.util.zip.ZipInputStream;
|
||||||
|
|
||||||
|
import static java.security.DrbgParameters.Capability.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The Known-output DRBG test. The test vector can be obtained from
|
||||||
|
* http://csrc.nist.gov/groups/STM/cavp/documents/drbg/drbgtestvectors.zip.
|
||||||
|
*
|
||||||
|
* Manually run this test with
|
||||||
|
*
|
||||||
|
* java DrbgCavp drbgtestvectors.zip
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public class DrbgCavp {
|
||||||
|
|
||||||
|
// the current nonce
|
||||||
|
private static byte[] nonce;
|
||||||
|
|
||||||
|
// A buffer to store test materials for the current call and
|
||||||
|
// can be printed out of an error occurs.
|
||||||
|
private static ByteArrayOutputStream bout = new ByteArrayOutputStream();
|
||||||
|
|
||||||
|
// Save err for restoring
|
||||||
|
private static PrintStream err = System.err;
|
||||||
|
|
||||||
|
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");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void main(String[] args) throws Exception {
|
||||||
|
|
||||||
|
if (args.length != 1) {
|
||||||
|
System.out.println("Usage: java DrbgCavp drbgtestvectors.zip");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
File tv = new File(args[0]);
|
||||||
|
|
||||||
|
EntropySource es = new TestEntropySource();
|
||||||
|
System.setErr(new PrintStream(bout));
|
||||||
|
|
||||||
|
// The testsuite is a zip file containing more zip files for different
|
||||||
|
// working modes. Each internal zip file contains test materials for
|
||||||
|
// different mechanisms.
|
||||||
|
|
||||||
|
try (ZipFile zf = new ZipFile(tv)) {
|
||||||
|
String[] modes = {"no_reseed", "pr_false", "pr_true"};
|
||||||
|
for (String mode : modes) {
|
||||||
|
try (ZipInputStream zis = new ZipInputStream(zf.getInputStream(
|
||||||
|
zf.getEntry("drbgvectors_" + mode + ".zip")))) {
|
||||||
|
while (true) {
|
||||||
|
ZipEntry ze = zis.getNextEntry();
|
||||||
|
if (ze == null) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
String fname = ze.getName();
|
||||||
|
if (fname.equals("Hash_DRBG.txt")
|
||||||
|
|| fname.equals("HMAC_DRBG.txt")
|
||||||
|
|| fname.equals("CTR_DRBG.txt")) {
|
||||||
|
String algorithm
|
||||||
|
= fname.substring(0, fname.length() - 4);
|
||||||
|
test(mode, algorithm, es, zis);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
System.setErr(err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A special entropy source you can set entropy input at will.
|
||||||
|
*/
|
||||||
|
private static class TestEntropySource implements EntropySource {
|
||||||
|
|
||||||
|
private static Queue<byte[]> data = new ArrayDeque<>();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public byte[] getEntropy(int minEntropy, int minLength,
|
||||||
|
int maxLength, boolean pr) {
|
||||||
|
byte[] result = data.poll();
|
||||||
|
if (result == null
|
||||||
|
|| result.length < minLength
|
||||||
|
|| result.length > maxLength) {
|
||||||
|
throw new RuntimeException("Invalid entropy: " +
|
||||||
|
"need [" + minLength + ", " + maxLength + "], " +
|
||||||
|
(result == null ? "none" : "has " + result.length));
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void setEntropy(byte[] input) {
|
||||||
|
data.offer(input);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void clearEntropy() {
|
||||||
|
data.clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The test.
|
||||||
|
*
|
||||||
|
* // Algorithm line, might contain usedf flag
|
||||||
|
* [AES-128 use df]
|
||||||
|
* // Ignored, use mode argument
|
||||||
|
* [PredictionResistance = True]
|
||||||
|
* // Ignored, just read EntropyInput
|
||||||
|
* [EntropyInputLen = 128]
|
||||||
|
* // Ignored, just read Nonce
|
||||||
|
* [NonceLen = 64]
|
||||||
|
* // Ignored, just read PersonalizationString
|
||||||
|
* [PersonalizationStringLen = 128]
|
||||||
|
* // Ignored, just read AdditionalInput
|
||||||
|
* [AdditionalInputLen = 128]
|
||||||
|
* // Used to allocate buffer for nextBytes() call
|
||||||
|
* [ReturnedBitsLen = 512]
|
||||||
|
*
|
||||||
|
* // A sign we can ignore old unused entropy input
|
||||||
|
* COUNT = 0
|
||||||
|
*
|
||||||
|
* // Instantiate
|
||||||
|
* EntropyInput = 92898f...
|
||||||
|
* Nonce = c2a4d9...
|
||||||
|
* PersonalizationString = ea65ee... // Enough to call getInstance()
|
||||||
|
*
|
||||||
|
* // Reseed
|
||||||
|
* EntropyInputReseed = bfd503...
|
||||||
|
* AdditionalInputReseed = 009e0b... // Enough to call reseed()
|
||||||
|
*
|
||||||
|
* // Generation
|
||||||
|
* AdditionalInput = 1a40fa.... // Enough to call nextBytes() for PR off
|
||||||
|
* EntropyInputPR = 20728a... // Enough to call nextBytes() for PR on
|
||||||
|
* ReturnedBits = 5a3539... // Compare this to last nextBytes() output
|
||||||
|
*
|
||||||
|
* @param mode one of "no_reseed", "pr_false", "pr_true"
|
||||||
|
* @param mech one of "Hash_DRBG", "HMAC_DRBG", "CTR_DRBG"
|
||||||
|
* @param es our own entropy source
|
||||||
|
* @param is test material
|
||||||
|
*/
|
||||||
|
private static void test(String mode, String mech, EntropySource es,
|
||||||
|
InputStream is) throws Exception {
|
||||||
|
|
||||||
|
SecureRandom hd = null;
|
||||||
|
|
||||||
|
// Expected output length in bits as in [ReturnedBitsLen]
|
||||||
|
int outLen = 0;
|
||||||
|
|
||||||
|
// DRBG algorithm as in the algorithm line
|
||||||
|
String algorithm = null;
|
||||||
|
|
||||||
|
// When CTR_DRBG uses a derivation function as in the algorithm line
|
||||||
|
boolean usedf = false;
|
||||||
|
|
||||||
|
// Additional input as in "AdditionalInput"
|
||||||
|
byte[] additional = null;
|
||||||
|
|
||||||
|
// Random bits generated
|
||||||
|
byte[] output = null;
|
||||||
|
|
||||||
|
// Prediction resistance flag, determined by mode
|
||||||
|
boolean isPr = false;
|
||||||
|
|
||||||
|
StringBuilder sb = new StringBuilder();
|
||||||
|
|
||||||
|
int lineno = 0;
|
||||||
|
|
||||||
|
System.out.println(mode + "/" + mech);
|
||||||
|
|
||||||
|
try (Stream<String> lines =
|
||||||
|
new BufferedReader(new InputStreamReader(is)).lines()) {
|
||||||
|
for (String s: (Iterable<String>) lines::iterator) {
|
||||||
|
lineno++;
|
||||||
|
err.print(hd == null ? '-' : '*');
|
||||||
|
Line l = new Line(s);
|
||||||
|
if (l.key.contains("no df") || l.key.contains("use df") ||
|
||||||
|
l.key.startsWith("SHA-")) {
|
||||||
|
sb = new StringBuilder();
|
||||||
|
bout.reset();
|
||||||
|
}
|
||||||
|
sb.append(String.format(
|
||||||
|
"%9s %4s %5d %s\n", mode, mech, lineno, s));
|
||||||
|
switch (l.key) {
|
||||||
|
case "3KeyTDEA no df":
|
||||||
|
case "AES-128 no df":
|
||||||
|
case "AES-192 no df":
|
||||||
|
case "AES-256 no df":
|
||||||
|
case "3KeyTDEA use df":
|
||||||
|
case "AES-128 use df":
|
||||||
|
case "AES-192 use df":
|
||||||
|
case "AES-256 use df":
|
||||||
|
algorithm = l.key.split(" ")[0];
|
||||||
|
usedf = l.key.contains("use df");
|
||||||
|
break;
|
||||||
|
case "ReturnedBitsLen":
|
||||||
|
outLen = l.vint();
|
||||||
|
output = new byte[outLen / 8];
|
||||||
|
break;
|
||||||
|
case "EntropyInput":
|
||||||
|
TestEntropySource.setEntropy(l.vdata());
|
||||||
|
break;
|
||||||
|
case "Nonce":
|
||||||
|
nonce = l.vdata();
|
||||||
|
break;
|
||||||
|
case "COUNT":
|
||||||
|
// Remove unused entropy (say, when AES-256 is skipped)
|
||||||
|
TestEntropySource.clearEntropy();
|
||||||
|
break;
|
||||||
|
case "PersonalizationString":
|
||||||
|
try {
|
||||||
|
isPr = mode.equals("pr_true");
|
||||||
|
byte[] ps = null;
|
||||||
|
if (l.vdata().length != 0) {
|
||||||
|
ps = l.vdata();
|
||||||
|
}
|
||||||
|
|
||||||
|
// MoreDrbgParameters must be used because we
|
||||||
|
// want to set entropy input and nonce. Since
|
||||||
|
// it can also set mechanism, algorithm and usedf,
|
||||||
|
// we don't need to touch securerandom.drbg.config.
|
||||||
|
hd = SecureRandom.getInstance("DRBG",
|
||||||
|
new MoreDrbgParameters(es, mech, algorithm,
|
||||||
|
nonce, usedf,
|
||||||
|
DrbgParameters.instantiation(
|
||||||
|
-1,
|
||||||
|
isPr ? PR_AND_RESEED
|
||||||
|
: RESEED_ONLY,
|
||||||
|
ps)),
|
||||||
|
"SUN");
|
||||||
|
} catch (NoSuchAlgorithmException iae) {
|
||||||
|
// AES-256 might not be available. This is OK.
|
||||||
|
if ((algorithm.equals("AES-192")
|
||||||
|
|| algorithm.equals("AES-256"))
|
||||||
|
&& AES_LIMIT == 128) {
|
||||||
|
hd = null;
|
||||||
|
} else {
|
||||||
|
throw iae;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case "EntropyInputReseed":
|
||||||
|
TestEntropySource.setEntropy(l.vdata());
|
||||||
|
break;
|
||||||
|
case "AdditionalInputReseed":
|
||||||
|
if (l.vdata().length == 0) {
|
||||||
|
additional = null;
|
||||||
|
} else {
|
||||||
|
additional = l.vdata();
|
||||||
|
}
|
||||||
|
if (hd != null) {
|
||||||
|
if (additional == null) {
|
||||||
|
hd.reseed();
|
||||||
|
} else {
|
||||||
|
hd.reseed(DrbgParameters.reseed(
|
||||||
|
isPr, additional));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case "EntropyInputPR":
|
||||||
|
if (l.vdata().length != 0) {
|
||||||
|
TestEntropySource.setEntropy(l.vdata());
|
||||||
|
}
|
||||||
|
if (mode.equals("pr_true")) {
|
||||||
|
if (hd != null) {
|
||||||
|
if (additional == null) {
|
||||||
|
hd.nextBytes(output);
|
||||||
|
} else {
|
||||||
|
hd.nextBytes(output,
|
||||||
|
DrbgParameters.nextBytes(
|
||||||
|
-1, isPr, additional));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case "AdditionalInput":
|
||||||
|
if (l.vdata().length == 0) {
|
||||||
|
additional = null;
|
||||||
|
} else {
|
||||||
|
additional = l.vdata();
|
||||||
|
}
|
||||||
|
if (!mode.equals("pr_true")) {
|
||||||
|
if (hd != null) {
|
||||||
|
if (additional == null) {
|
||||||
|
hd.nextBytes(output);
|
||||||
|
} else {
|
||||||
|
hd.nextBytes(output,
|
||||||
|
DrbgParameters.nextBytes(
|
||||||
|
-1, isPr, additional));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case "ReturnedBits":
|
||||||
|
if (hd != null) {
|
||||||
|
if (!Arrays.equals(output, l.vdata())) {
|
||||||
|
throw new Exception("\nExpected: " +
|
||||||
|
l.value + "\n Actual: " + hex(output));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
// Algorithm line for Hash_DRBG and HMAC_DRBG
|
||||||
|
if (l.key.startsWith("SHA-")) {
|
||||||
|
algorithm = l.key;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
err.println();
|
||||||
|
} catch (Exception e) {
|
||||||
|
err.println();
|
||||||
|
err.println(sb.toString());
|
||||||
|
err.println(bout.toString());
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parse a line from test material.
|
||||||
|
*
|
||||||
|
* Brackets are removed. Key and value separated.
|
||||||
|
*/
|
||||||
|
static class Line {
|
||||||
|
|
||||||
|
final String key;
|
||||||
|
final String value;
|
||||||
|
|
||||||
|
Line(String s) {
|
||||||
|
s = s.trim();
|
||||||
|
if (s.length() >= 2) {
|
||||||
|
if (s.charAt(0) == '[') {
|
||||||
|
s = s.substring(1, s.length() - 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (s.indexOf('=') < 0) {
|
||||||
|
key = s;
|
||||||
|
value = null;
|
||||||
|
} else {
|
||||||
|
key = s.substring(0, s.indexOf('=')).trim();
|
||||||
|
value = s.substring(s.indexOf('=') + 1).trim();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int vint() {
|
||||||
|
return Integer.parseInt(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
byte[] vdata() {
|
||||||
|
return xeh(value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Bytes to HEX
|
||||||
|
private static String hex(byte[] in) {
|
||||||
|
StringBuilder sb = new StringBuilder();
|
||||||
|
for (byte b: in) {
|
||||||
|
sb.append(String.format("%02x", b&0xff));
|
||||||
|
}
|
||||||
|
return sb.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
// HEX to bytes
|
||||||
|
private static byte[] xeh(String in) {
|
||||||
|
in = in.replaceAll(" ", "");
|
||||||
|
int len = in.length() / 2;
|
||||||
|
byte[] out = new byte[len];
|
||||||
|
for (int i = 0; i < len; i++) {
|
||||||
|
out[i] = (byte) Integer.parseInt(
|
||||||
|
in.substring(i * 2, i * 2 + 2), 16);
|
||||||
|
}
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
}
|
@ -1,66 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) 1998, 2003, Oracle and/or its affiliates. All rights reserved.
|
|
||||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
|
||||||
*
|
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
|
||||||
* under the terms of the GNU General Public License version 2 only, as
|
|
||||||
* published by the Free Software Foundation.
|
|
||||||
*
|
|
||||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
|
||||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
||||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
|
||||||
* version 2 for more details (a copy is included in the LICENSE file that
|
|
||||||
* accompanied this code).
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License version
|
|
||||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
|
||||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
|
||||||
*
|
|
||||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
|
||||||
* or visit www.oracle.com if you need additional information or have any
|
|
||||||
* questions.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @test
|
|
||||||
* @bug 4168409
|
|
||||||
* @summary SecureRandom forces all instances to self-seed, even if a seed is
|
|
||||||
* provided
|
|
||||||
*/
|
|
||||||
|
|
||||||
import java.security.SecureRandom;
|
|
||||||
|
|
||||||
public class SelfSeed {
|
|
||||||
|
|
||||||
private static final int NUM_BYTES = 5;
|
|
||||||
private static byte seed[] = { (byte)0xaa, (byte)0x11, (byte)0xa1 };
|
|
||||||
|
|
||||||
public static void main(String[] args) {
|
|
||||||
|
|
||||||
try {
|
|
||||||
SecureRandom sr1 = SecureRandom.getInstance("SHA1PRNG");
|
|
||||||
sr1.setSeed(seed);
|
|
||||||
byte randomBytes[] = new byte[NUM_BYTES];
|
|
||||||
sr1.nextBytes(randomBytes);
|
|
||||||
|
|
||||||
SecureRandom sr2 = new SecureRandom(seed);
|
|
||||||
if (sr2.getAlgorithm().equals("SHA1PRNG") == false) {
|
|
||||||
System.out.println("Default PRNG is not SHA1PRNG, skipping test");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
byte otherRandomBytes[] = new byte[NUM_BYTES];
|
|
||||||
sr2.nextBytes(otherRandomBytes);
|
|
||||||
|
|
||||||
// make sure the random bytes generated are the same
|
|
||||||
for (int i = 0; i < NUM_BYTES; i++) {
|
|
||||||
if (randomBytes[i] != otherRandomBytes[i])
|
|
||||||
throw new SecurityException("FAILURE: " +
|
|
||||||
"Returned bytes not equal");
|
|
||||||
}
|
|
||||||
|
|
||||||
// success
|
|
||||||
} catch (Exception e) {
|
|
||||||
throw new SecurityException("FAILURE: " + e.toString());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -59,6 +59,7 @@ public class StrongSeedReader {
|
|||||||
System.setProperty("java.security.egd", file.toURI().toString());
|
System.setProperty("java.security.egd", file.toURI().toString());
|
||||||
testSeed("NativePRNG");
|
testSeed("NativePRNG");
|
||||||
testSeed("SHA1PRNG");
|
testSeed("SHA1PRNG");
|
||||||
|
testSeed("DRBG");
|
||||||
} finally {
|
} finally {
|
||||||
if (file != null) {
|
if (file != null) {
|
||||||
file.delete();
|
file.delete();
|
||||||
|
Loading…
Reference in New Issue
Block a user