Path: blob/master/src/java.base/share/classes/java/security/DrbgParameters.java
41152 views
/*1* Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation. Oracle designates this7* particular file as subject to the "Classpath" exception as provided8* by Oracle in the LICENSE file that accompanied this code.9*10* This code is distributed in the hope that it will be useful, but WITHOUT11* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or12* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License13* version 2 for more details (a copy is included in the LICENSE file that14* accompanied this code).15*16* You should have received a copy of the GNU General Public License version17* 2 along with this work; if not, write to the Free Software Foundation,18* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.19*20* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA21* or visit www.oracle.com if you need additional information or have any22* questions.23*/2425package java.security;2627import java.util.Locale;28import java.util.Objects;2930/**31* This class specifies the parameters used by a DRBG (Deterministic32* Random Bit Generator).33* <p>34* According to35* <a href="http://nvlpubs.nist.gov/nistpubs/SpecialPublications/NIST.SP.800-90Ar1.pdf">36* NIST Special Publication 800-90A Revision 1, Recommendation for Random37* Number Generation Using Deterministic Random Bit Generators</a> (800-90Ar1),38* <blockquote>39* A DRBG is based on a DRBG mechanism as specified in this Recommendation40* and includes a source of randomness. A DRBG mechanism uses an algorithm41* (i.e., a DRBG algorithm) that produces a sequence of bits from an initial42* value that is determined by a seed that is determined from the output of43* the randomness source."44* </blockquote>45* <p>46* The 800-90Ar1 specification allows for a variety of DRBG implementation47* choices, such as:48* <ul>49* <li> an entropy source,50* <li> a DRBG mechanism (for example, Hash_DRBG),51* <li> a DRBG algorithm (for example, SHA-256 for Hash_DRBG and AES-25652* for CTR_DRBG. Please note that it is not the algorithm used in53* {@link SecureRandom#getInstance}, which we will call a54* <em>SecureRandom algorithm</em> below),55* <li> optional features, including prediction resistance56* and reseeding supports,57* <li> highest security strength.58* </ul>59* <p>60* These choices are set in each implementation and are not directly61* managed by the {@code SecureRandom} API. Check your DRBG provider's62* documentation to find an appropriate implementation for the situation.63* <p>64* On the other hand, the 800-90Ar1 specification does have some configurable65* options, such as:66* <ul>67* <li> required security strength,68* <li> if prediction resistance is required,69* <li> personalization string and additional input.70* </ul>71* <p>72* A DRBG instance can be instantiated with parameters from an73* {@link DrbgParameters.Instantiation} object and other information74* (for example, the nonce, which is not managed by this API). This maps75* to the {@code Instantiate_function} defined in NIST SP 800-90Ar1.76* <p>77* A DRBG instance can be reseeded with parameters from a78* {@link DrbgParameters.Reseed} object. This maps to the79* {@code Reseed_function} defined in NIST SP 800-90Ar1. Calling80* {@link SecureRandom#reseed()} is equivalent to calling81* {@link SecureRandom#reseed(SecureRandomParameters)} with the effective82* instantiated prediction resistance flag (as returned by83* {@link SecureRandom#getParameters()}) with no additional input.84* <p>85* A DRBG instance generates data with additional parameters from a86* {@link DrbgParameters.NextBytes} object. This maps to the87* {@code Generate_function} defined in NIST SP 800-90Ar1. Calling88* {@link SecureRandom#nextBytes(byte[])} is equivalent to calling89* {@link SecureRandom#nextBytes(byte[], SecureRandomParameters)}90* with the effective instantiated strength and prediction resistance flag91* (as returned by {@link SecureRandom#getParameters()}) with no92* additional input.93* <p>94* A DRBG should be implemented as a subclass of {@link SecureRandomSpi}.95* It is recommended that the implementation contain the 1-arg96* {@linkplain SecureRandomSpi#SecureRandomSpi(SecureRandomParameters) constructor}97* that takes a {@code DrbgParameters.Instantiation} argument. If implemented98* this way, this implementation can be chosen by any99* {@code SecureRandom.getInstance()} method. If it is chosen by a100* {@code SecureRandom.getInstance()} with a {@link SecureRandomParameters}101* parameter, the parameter is passed into this constructor. If it is chosen102* by a {@code SecureRandom.getInstance()} without a103* {@code SecureRandomParameters} parameter, the constructor is called with104* a {@code null} argument and the implementation should choose its own105* parameters. Its {@link SecureRandom#getParameters()} must always return a106* non-null effective {@code DrbgParameters.Instantiation} object that reflects107* how the DRBG is actually instantiated. A caller can use this information108* to determine whether a {@code SecureRandom} object is a DRBG and what109* features it supports. Please note that the returned value does not110* necessarily equal to the {@code DrbgParameters.Instantiation} object passed111* into the {@code SecureRandom.getInstance()} call. For example,112* the requested capability can be {@link DrbgParameters.Capability#NONE}113* but the effective value can be {@link DrbgParameters.Capability#RESEED_ONLY}114* if the implementation supports reseeding. The implementation must implement115* the {@link SecureRandomSpi#engineNextBytes(byte[], SecureRandomParameters)}116* method which takes a {@code DrbgParameters.NextBytes} parameter. Unless117* the result of {@link SecureRandom#getParameters()} has its118* {@linkplain DrbgParameters.Instantiation#getCapability() capability} being119* {@link Capability#NONE NONE}, it must implement120* {@link SecureRandomSpi#engineReseed(SecureRandomParameters)} which takes121* a {@code DrbgParameters.Reseed} parameter.122* <p>123* On the other hand, if a DRBG implementation does not contain a constructor124* that has an {@code DrbgParameters.Instantiation} argument (not recommended),125* it can only be chosen by a {@code SecureRandom.getInstance()} without126* a {@code SecureRandomParameters} parameter, but will not be chosen if127* a {@code getInstance} method with a {@code SecureRandomParameters} parameter128* is called. If implemented this way, its {@link SecureRandom#getParameters()}129* must return {@code null}, and it does not need to implement either130* {@link SecureRandomSpi#engineNextBytes(byte[], SecureRandomParameters)}131* or {@link SecureRandomSpi#engineReseed(SecureRandomParameters)}.132* <p>133* A DRBG might reseed itself automatically if the seed period is bigger134* than the maximum seed life defined by the DRBG mechanism.135* <p>136* A DRBG implementation should support serialization and deserialization137* by retaining the configuration and effective parameters, but the internal138* state must not be serialized and the deserialized object must be139* reinstantiated.140* <p>141* Examples:142* <blockquote><pre>143* SecureRandom drbg;144* byte[] buffer = new byte[32];145*146* // Any DRBG is OK147* drbg = SecureRandom.getInstance("DRBG");148* drbg.nextBytes(buffer);149*150* SecureRandomParameters params = drbg.getParameters();151* if (params instanceof DrbgParameters.Instantiation) {152* DrbgParameters.Instantiation ins = (DrbgParameters.Instantiation) params;153* if (ins.getCapability().supportsReseeding()) {154* drbg.reseed();155* }156* }157*158* // The following call requests a weak DRBG instance. It is only159* // guaranteed to support 112 bits of security strength.160* drbg = SecureRandom.getInstance("DRBG",161* DrbgParameters.instantiation(112, NONE, null));162*163* // Both the next two calls will likely fail, because drbg could be164* // instantiated with a smaller strength with no prediction resistance165* // support.166* drbg.nextBytes(buffer,167* DrbgParameters.nextBytes(256, false, "more".getBytes()));168* drbg.nextBytes(buffer,169* DrbgParameters.nextBytes(112, true, "more".getBytes()));170*171* // The following call requests a strong DRBG instance, with a172* // personalization string. If it successfully returns an instance,173* // that instance is guaranteed to support 256 bits of security strength174* // with prediction resistance available.175* drbg = SecureRandom.getInstance("DRBG", DrbgParameters.instantiation(176* 256, PR_AND_RESEED, "hello".getBytes()));177*178* // Prediction resistance is not requested in this single call,179* // but an additional input is used.180* drbg.nextBytes(buffer,181* DrbgParameters.nextBytes(-1, false, "more".getBytes()));182*183* // Same for this call.184* drbg.reseed(DrbgParameters.reseed(false, "extra".getBytes()));</pre>185* </blockquote>186*187* @implSpec188* By convention, a provider should name its primary DRBG implementation189* with the <a href=190* "{@docRoot}/../specs/security/standard-names.html#securerandom-number-generation-algorithms">191* standard {@code SecureRandom} algorithm name</a> "DRBG".192*193* @implNote194* The following notes apply to the "DRBG" implementation in the SUN provider195* of the JDK reference implementation.196* <p>197* This implementation supports the Hash_DRBG and HMAC_DRBG mechanisms with198* DRBG algorithm SHA-224, SHA-512/224, SHA-256, SHA-512/256, SHA-384 and199* SHA-512, and CTR_DRBG (both using derivation function and not using200* derivation function) with DRBG algorithm AES-128, AES-192 and AES-256.201* <p>202* The mechanism name and DRBG algorithm name are determined by the203* {@linkplain Security#getProperty(String) security property}204* {@code securerandom.drbg.config}. The default choice is Hash_DRBG205* with SHA-256.206* <p>207* For each combination, the security strength can be requested from 112208* up to the highest strength it supports. Both reseeding and prediction209* resistance are supported.210* <p>211* Personalization string is supported through the212* {@link DrbgParameters.Instantiation} class and additional input is supported213* through the {@link DrbgParameters.NextBytes} and214* {@link DrbgParameters.Reseed} classes.215* <p>216* If a DRBG is not instantiated with a {@link DrbgParameters.Instantiation}217* object explicitly, this implementation instantiates it with a default218* requested strength of 128 bits, no prediction resistance request, and219* no personalization string. These default instantiation parameters can also220* be customized with the {@code securerandom.drbg.config} security property.221* <p>222* This implementation reads fresh entropy from the system default entropy223* source determined by the security property {@code securerandom.source}.224* <p>225* Calling {@link SecureRandom#generateSeed(int)} will directly read226* from this system default entropy source.227*228* @since 9229*/230public class DrbgParameters {231232private DrbgParameters() {233// This class should not be instantiated234}235236/**237* The reseedable and prediction resistance capabilities of a DRBG.238* <p>239* When this object is passed to a {@code SecureRandom.getInstance()} call,240* it is the requested minimum capability. When it's returned from241* {@code SecureRandom.getParameters()}, it is the effective capability.242* <p>243* Please note that while the {@code Instantiate_function} defined in244* NIST SP 800-90Ar1 only includes a {@code prediction_resistance_flag}245* parameter, the {@code Capability} type includes an extra value246* {@link #RESEED_ONLY} because reseeding is an optional function.247* If {@code NONE} is used in an {@code Instantiation} object in calling the248* {@code SecureRandom.getInstance} method, the returned DRBG instance249* is not guaranteed to support reseeding. If {@code RESEED_ONLY} or250* {@code PR_AND_RESEED} is used, the instance must support reseeding.251* <p>252* The table below lists possible effective values if a certain253* capability is requested, i.e.254* <blockquote><pre>255* Capability requested = ...;256* SecureRandom s = SecureRandom.getInstance("DRBG",257* DrbgParameters(-1, requested, null));258* Capability effective = ((DrbgParametes.Initiate) s.getParameters())259* .getCapability();</pre>260* </blockquote>261* <table class="striped">262* <caption style="display:none">requested and effective capabilities</caption>263* <thead>264* <tr>265* <th scope="col">Requested Value</th>266* <th scope="col">Possible Effective Values</th>267* </tr>268* </thead>269* <tbody style="text-align:left">270* <tr><th scope="row">NONE</th><td>NONE, RESEED_ONLY, PR_AND_RESEED</td></tr>271* <tr><th scope="row">RESEED_ONLY</th><td>RESEED_ONLY, PR_AND_RESEED</td></tr>272* <tr><th scope="row">PR_AND_RESEED</th><td>PR_AND_RESEED</td></tr>273* </tbody>274* </table>275* <p>276* A DRBG implementation supporting prediction resistance must also277* support reseeding.278*279* @since 9280*/281public enum Capability {282283/**284* Both prediction resistance and reseed.285*/286PR_AND_RESEED,287288/**289* Reseed but no prediction resistance.290*/291RESEED_ONLY,292293/**294* Neither prediction resistance nor reseed.295*/296NONE;297298@Override299public String toString() {300return name().toLowerCase(Locale.ROOT);301}302303/**304* Returns whether this capability supports reseeding.305*306* @return {@code true} for {@link #PR_AND_RESEED} and307* {@link #RESEED_ONLY}, and {@code false} for {@link #NONE}308*/309public boolean supportsReseeding() {310return this != NONE;311}312313/**314* Returns whether this capability supports prediction resistance.315*316* @return {@code true} for {@link #PR_AND_RESEED}, and {@code false}317* for {@link #RESEED_ONLY} and {@link #NONE}318*/319public boolean supportsPredictionResistance() {320return this == PR_AND_RESEED;321}322}323324/**325* DRBG parameters for instantiation.326* <p>327* When used in328* {@link SecureRandom#getInstance(String, SecureRandomParameters)}329* or one of the other similar {@code getInstance} calls that take a330* {@code SecureRandomParameters} parameter, it means the331* requested instantiate parameters the newly created {@code SecureRandom}332* object must minimally support. When used as the return value of the333* {@link SecureRandom#getParameters()} method, it means the effective334* instantiate parameters of the {@code SecureRandom} object.335*336* @since 9337*/338public static final class Instantiation339implements SecureRandomParameters {340341private final int strength;342private final Capability capability;343private final byte[] personalizationString;344345/**346* Returns the security strength in bits.347*348* @return If used in {@code getInstance}, returns the minimum strength349* requested, or -1 if there is no specific request on the strength.350* If used in {@code getParameters}, returns the effective strength.351* The effective strength must be greater than or equal to the minimum352* strength requested.353*/354public int getStrength() {355return strength;356}357358/**359* Returns the capability.360*361* @return If used in {@code getInstance}, returns the minimum362* capability requested. If used in {@code getParameters}, returns363* information on the effective prediction resistance flag and364* whether it supports reseeding.365*/366public Capability getCapability() {367return capability;368}369370/**371* Returns the personalization string as a byte array.372*373* @return If used in {@code getInstance}, returns the requested374* personalization string as a newly allocated array, or {@code null}375* if no personalization string is requested. The same string should376* be returned in {@code getParameters} as a new copy, or {@code null}377* if no personalization string is requested in {@code getInstance}.378*/379public byte[] getPersonalizationString() {380return (personalizationString == null) ?381null : personalizationString.clone();382}383384private Instantiation(int strength, Capability capability,385byte[] personalizationString) {386if (strength < -1) {387throw new IllegalArgumentException(388"Illegal security strength: " + strength);389}390this.strength = strength;391this.capability = capability;392this.personalizationString = (personalizationString == null) ?393null : personalizationString.clone();394}395396/**397* Returns a Human-readable string representation of this398* {@code Instantiation}.399*400* @return the string representation401*/402@Override403public String toString() {404// I don't care what personalizationString looks like405return strength + "," + capability + "," + personalizationString;406}407}408409/**410* DRBG parameters for random bits generation. It is used in411* {@link SecureRandom#nextBytes(byte[], SecureRandomParameters)}.412*413* @since 9414*/415public static final class NextBytes416implements SecureRandomParameters {417private final int strength;418private final boolean predictionResistance;419private final byte[] additionalInput;420421/**422* Returns the security strength requested in bits.423*424* @return the strength requested, or -1 if the effective strength425* should be used.426*/427public int getStrength() {428return strength;429}430431/**432* Returns whether prediction resistance is requested.433*434* @return whether prediction resistance is requested435*/436public boolean getPredictionResistance() {437return predictionResistance;438}439440/**441* Returns the requested additional input.442*443* @return the requested additional input, {@code null} if not444* requested. A new byte array is returned each time this method445* is called.446*/447public byte[] getAdditionalInput() {448return additionalInput == null? null: additionalInput.clone();449}450451private NextBytes(int strength, boolean predictionResistance,452byte[] additionalInput) {453if (strength < -1) {454throw new IllegalArgumentException(455"Illegal security strength: " + strength);456}457this.strength = strength;458this.predictionResistance = predictionResistance;459this.additionalInput = (additionalInput == null) ?460null : additionalInput.clone();461}462}463464/**465* DRBG parameters for reseed. It is used in466* {@link SecureRandom#reseed(SecureRandomParameters)}.467*468* @since 9469*/470public static final class Reseed implements SecureRandomParameters {471472private final byte[] additionalInput;473private final boolean predictionResistance;474475/**476* Returns whether prediction resistance is requested.477*478* @return whether prediction resistance is requested479*/480public boolean getPredictionResistance() {481return predictionResistance;482}483484/**485* Returns the requested additional input.486*487* @return the requested additional input, or {@code null} if488* not requested. A new byte array is returned each time this method489* is called.490*/491public byte[] getAdditionalInput() {492return additionalInput == null ? null : additionalInput.clone();493}494495private Reseed(boolean predictionResistance, byte[] additionalInput) {496this.predictionResistance = predictionResistance;497this.additionalInput = (additionalInput == null) ?498null : additionalInput.clone();499}500}501502/**503* Generates a {@link DrbgParameters.Instantiation} object.504*505* @param strength security strength in bits, -1 for default strength506* if used in {@code getInstance}.507* @param capability capability508* @param personalizationString personalization string as a byte array,509* can be {@code null}. The content of this510* byte array will be copied.511* @return a new {@code Instantiation} object512* @throws NullPointerException if {@code capability} is {@code null}513* @throws IllegalArgumentException if {@code strength} is less than -1514*/515public static Instantiation instantiation(int strength,516Capability capability,517byte[] personalizationString) {518return new Instantiation(strength, Objects.requireNonNull(capability),519personalizationString);520}521522/**523* Generates a {@link NextBytes} object.524*525* @param strength requested security strength in bits. If set to -1, the526* effective strength will be used.527* @param predictionResistance prediction resistance requested528* @param additionalInput additional input, can be {@code null}.529* The content of this byte array will be copied.530* @throws IllegalArgumentException if {@code strength} is less than -1531* @return a new {@code NextBytes} object532*/533public static NextBytes nextBytes(int strength,534boolean predictionResistance,535byte[] additionalInput) {536return new NextBytes(strength, predictionResistance, additionalInput);537}538539/**540* Generates a {@link Reseed} object.541*542* @param predictionResistance prediction resistance requested543* @param additionalInput additional input, can be {@code null}.544* The content of this byte array will be copied.545* @return a new {@code Reseed} object546*/547public static Reseed reseed(548boolean predictionResistance, byte[] additionalInput) {549return new Reseed(predictionResistance, additionalInput);550}551}552553554