Path: blob/master/src/java.base/share/classes/javax/crypto/KeyGenerator.java
41152 views
/*1* Copyright (c) 1997, 2021, 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 javax.crypto;2627import java.util.*;2829import java.security.*;30import java.security.Provider.Service;31import java.security.spec.*;3233import sun.security.jca.*;34import sun.security.jca.GetInstance.Instance;35import sun.security.util.Debug;3637/**38* This class provides the functionality of a secret (symmetric) key generator.39*40* <p>Key generators are constructed using one of the {@code getInstance}41* class methods of this class.42*43* <p>KeyGenerator objects are reusable, i.e., after a key has been44* generated, the same KeyGenerator object can be re-used to generate further45* keys.46*47* <p>There are two ways to generate a key: in an algorithm-independent48* manner, and in an algorithm-specific manner.49* The only difference between the two is the initialization of the object:50*51* <ul>52* <li><b>Algorithm-Independent Initialization</b>53* <p>All key generators share the concepts of a <i>keysize</i> and a54* <i>source of randomness</i>.55* There is an56* {@link #init(int, java.security.SecureRandom) init}57* method in this KeyGenerator class that takes these two universally58* shared types of arguments. There is also one that takes just a59* {@code keysize} argument, and uses the SecureRandom implementation60* of the highest-priority installed provider as the source of randomness61* (or a system-provided source of randomness if none of the installed62* providers supply a SecureRandom implementation), and one that takes just a63* source of randomness.64*65* <p>Since no other parameters are specified when you call the above66* algorithm-independent {@code init} methods, it is up to the67* provider what to do about the algorithm-specific parameters (if any) to be68* associated with each of the keys.69*70* <li><b>Algorithm-Specific Initialization</b>71* <p>For situations where a set of algorithm-specific parameters already72* exists, there are two73* {@link #init(java.security.spec.AlgorithmParameterSpec) init}74* methods that have an {@code AlgorithmParameterSpec}75* argument. One also has a {@code SecureRandom} argument, while the76* other uses the SecureRandom implementation77* of the highest-priority installed provider as the source of randomness78* (or a system-provided source of randomness if none of the installed79* providers supply a SecureRandom implementation).80* </ul>81*82* <p>In case the client does not explicitly initialize the KeyGenerator83* (via a call to an {@code init} method), each provider must84* supply (and document) a default initialization.85* See the Keysize Restriction sections of the86* {@extLink security_guide_jdk_providers JDK Providers}87* document for information on the KeyGenerator defaults used by88* JDK providers.89* However, note that defaults may vary across different providers.90* Additionally, the default value for a provider may change in a future91* version. Therefore, it is recommended to explicitly initialize the92* KeyGenerator instead of relying on provider-specific defaults.93*94* <p> Every implementation of the Java platform is required to support the95* following standard {@code KeyGenerator} algorithms with the keysizes in96* parentheses:97* <ul>98* <li>{@code AES} (128)</li>99* <li>{@code DESede} (168)</li>100* <li>{@code HmacSHA1}</li>101* <li>{@code HmacSHA256}</li>102* </ul>103* These algorithms are described in the <a href=104* "{@docRoot}/../specs/security/standard-names.html#keygenerator-algorithms">105* KeyGenerator section</a> of the106* Java Security Standard Algorithm Names Specification.107* Consult the release documentation for your implementation to see if any108* other algorithms are supported.109*110* @author Jan Luehe111*112* @see SecretKey113* @since 1.4114*/115116public class KeyGenerator {117118private static final Debug pdebug =119Debug.getInstance("provider", "Provider");120private static final boolean skipDebug =121Debug.isOn("engine=") && !Debug.isOn("keygenerator");122123// see java.security.KeyPairGenerator for failover notes124125private static final int I_NONE = 1;126private static final int I_RANDOM = 2;127private static final int I_PARAMS = 3;128private static final int I_SIZE = 4;129130// The provider131private Provider provider;132133// The provider implementation (delegate)134private volatile KeyGeneratorSpi spi;135136// The algorithm137private final String algorithm;138139private final Object lock = new Object();140141private Iterator<Service> serviceIterator;142143private int initType;144private int initKeySize;145private AlgorithmParameterSpec initParams;146private SecureRandom initRandom;147148/**149* Creates a KeyGenerator object.150*151* @param keyGenSpi the delegate152* @param provider the provider153* @param algorithm the algorithm154*/155protected KeyGenerator(KeyGeneratorSpi keyGenSpi, Provider provider,156String algorithm) {157this.spi = keyGenSpi;158this.provider = provider;159this.algorithm = algorithm;160161if (!skipDebug && pdebug != null) {162pdebug.println("KeyGenerator." + algorithm + " algorithm from: " +163getProviderName());164}165}166167private KeyGenerator(String algorithm) throws NoSuchAlgorithmException {168this.algorithm = algorithm;169List<Service> list =170GetInstance.getServices("KeyGenerator", algorithm);171serviceIterator = list.iterator();172initType = I_NONE;173// fetch and instantiate initial spi174if (nextSpi(null, false) == null) {175throw new NoSuchAlgorithmException176(algorithm + " KeyGenerator not available");177}178179if (!skipDebug && pdebug != null) {180pdebug.println("KeyGenerator." + algorithm + " algorithm from: " +181getProviderName());182}183}184185private String getProviderName() {186return (provider == null) ? "(no provider)" : provider.getName();187}188189/**190* Returns the algorithm name of this {@code KeyGenerator} object.191*192* <p>This is the same name that was specified in one of the193* {@code getInstance} calls that created this194* {@code KeyGenerator} object.195*196* @return the algorithm name of this {@code KeyGenerator} object.197*/198public final String getAlgorithm() {199return this.algorithm;200}201202/**203* Returns a {@code KeyGenerator} object that generates secret keys204* for the specified algorithm.205*206* <p> This method traverses the list of registered security Providers,207* starting with the most preferred Provider.208* A new KeyGenerator object encapsulating the209* KeyGeneratorSpi implementation from the first210* Provider that supports the specified algorithm is returned.211*212* <p> Note that the list of registered providers may be retrieved via213* the {@link Security#getProviders() Security.getProviders()} method.214*215* @implNote216* The JDK Reference Implementation additionally uses the217* {@code jdk.security.provider.preferred}218* {@link Security#getProperty(String) Security} property to determine219* the preferred provider order for the specified algorithm. This220* may be different than the order of providers returned by221* {@link Security#getProviders() Security.getProviders()}.222*223* @param algorithm the standard name of the requested key algorithm.224* See the KeyGenerator section in the <a href=225* "{@docRoot}/../specs/security/standard-names.html#keygenerator-algorithms">226* Java Security Standard Algorithm Names Specification</a>227* for information about standard algorithm names.228*229* @return the new {@code KeyGenerator} object230*231* @throws NoSuchAlgorithmException if no {@code Provider} supports a232* {@code KeyGeneratorSpi} implementation for the233* specified algorithm234*235* @throws NullPointerException if {@code algorithm} is {@code null}236*237* @see java.security.Provider238*/239public static final KeyGenerator getInstance(String algorithm)240throws NoSuchAlgorithmException {241Objects.requireNonNull(algorithm, "null algorithm name");242return new KeyGenerator(algorithm);243}244245/**246* Returns a {@code KeyGenerator} object that generates secret keys247* for the specified algorithm.248*249* <p> A new KeyGenerator object encapsulating the250* KeyGeneratorSpi implementation from the specified provider251* is returned. The specified provider must be registered252* in the security provider list.253*254* <p> Note that the list of registered providers may be retrieved via255* the {@link Security#getProviders() Security.getProviders()} method.256*257* @param algorithm the standard name of the requested key algorithm.258* See the KeyGenerator section in the <a href=259* "{@docRoot}/../specs/security/standard-names.html#keygenerator-algorithms">260* Java Security Standard Algorithm Names Specification</a>261* for information about standard algorithm names.262*263* @param provider the name of the provider.264*265* @return the new {@code KeyGenerator} object266*267* @throws IllegalArgumentException if the {@code provider}268* is {@code null} or empty269*270* @throws NoSuchAlgorithmException if a {@code KeyGeneratorSpi}271* implementation for the specified algorithm is not272* available from the specified provider273*274* @throws NoSuchProviderException if the specified provider is not275* registered in the security provider list276*277* @throws NullPointerException if {@code algorithm} is {@code null}278*279* @see java.security.Provider280*/281public static final KeyGenerator getInstance(String algorithm,282String provider) throws NoSuchAlgorithmException,283NoSuchProviderException {284Objects.requireNonNull(algorithm, "null algorithm name");285Instance instance = JceSecurity.getInstance("KeyGenerator",286KeyGeneratorSpi.class, algorithm, provider);287return new KeyGenerator((KeyGeneratorSpi)instance.impl,288instance.provider, algorithm);289}290291/**292* Returns a {@code KeyGenerator} object that generates secret keys293* for the specified algorithm.294*295* <p> A new KeyGenerator object encapsulating the296* KeyGeneratorSpi implementation from the specified Provider297* object is returned. Note that the specified Provider object298* does not have to be registered in the provider list.299*300* @param algorithm the standard name of the requested key algorithm.301* See the KeyGenerator section in the <a href=302* "{@docRoot}/../specs/security/standard-names.html#keygenerator-algorithms">303* Java Security Standard Algorithm Names Specification</a>304* for information about standard algorithm names.305*306* @param provider the provider.307*308* @return the new {@code KeyGenerator} object309*310* @throws IllegalArgumentException if the {@code provider}311* is {@code null}312*313* @throws NoSuchAlgorithmException if a {@code KeyGeneratorSpi}314* implementation for the specified algorithm is not available315* from the specified {@code Provider} object316*317* @throws NullPointerException if {@code algorithm} is {@code null}318*319* @see java.security.Provider320*/321public static final KeyGenerator getInstance(String algorithm,322Provider provider) throws NoSuchAlgorithmException {323Objects.requireNonNull(algorithm, "null algorithm name");324Instance instance = JceSecurity.getInstance("KeyGenerator",325KeyGeneratorSpi.class, algorithm, provider);326return new KeyGenerator((KeyGeneratorSpi)instance.impl,327instance.provider, algorithm);328}329330/**331* Returns the provider of this {@code KeyGenerator} object.332*333* @return the provider of this {@code KeyGenerator} object334*/335public final Provider getProvider() {336synchronized (lock) {337disableFailover();338return provider;339}340}341342/**343* Update the active spi of this class and return the next344* implementation for failover. If no more implementations are345* available, this method returns null. However, the active spi of346* this class is never set to null.347*/348private KeyGeneratorSpi nextSpi(KeyGeneratorSpi oldSpi,349boolean reinit) {350synchronized (lock) {351// somebody else did a failover concurrently352// try that spi now353if ((oldSpi != null) && (oldSpi != spi)) {354return spi;355}356if (serviceIterator == null) {357return null;358}359while (serviceIterator.hasNext()) {360Service s = serviceIterator.next();361if (JceSecurity.canUseProvider(s.getProvider()) == false) {362continue;363}364try {365Object inst = s.newInstance(null);366// ignore non-spis367if (inst instanceof KeyGeneratorSpi == false) {368continue;369}370KeyGeneratorSpi spi = (KeyGeneratorSpi)inst;371if (reinit) {372if (initType == I_SIZE) {373spi.engineInit(initKeySize, initRandom);374} else if (initType == I_PARAMS) {375spi.engineInit(initParams, initRandom);376} else if (initType == I_RANDOM) {377spi.engineInit(initRandom);378} else if (initType != I_NONE) {379throw new AssertionError380("KeyGenerator initType: " + initType);381}382}383provider = s.getProvider();384this.spi = spi;385return spi;386} catch (Exception e) {387// ignore388}389}390disableFailover();391return null;392}393}394395void disableFailover() {396serviceIterator = null;397initType = 0;398initParams = null;399initRandom = null;400}401402/**403* Initializes this key generator.404*405* @param random the source of randomness for this generator406*/407public final void init(SecureRandom random) {408if (serviceIterator == null) {409spi.engineInit(random);410return;411}412RuntimeException failure = null;413KeyGeneratorSpi mySpi = spi;414do {415try {416mySpi.engineInit(random);417initType = I_RANDOM;418initKeySize = 0;419initParams = null;420initRandom = random;421return;422} catch (RuntimeException e) {423if (failure == null) {424failure = e;425}426mySpi = nextSpi(mySpi, false);427}428} while (mySpi != null);429throw failure;430}431432/**433* Initializes this key generator with the specified parameter set.434*435* <p> If this key generator requires any random bytes, it will get them436* using the437* {@link java.security.SecureRandom}438* implementation of the highest-priority installed439* provider as the source of randomness.440* (If none of the installed providers supply an implementation of441* SecureRandom, a system-provided source of randomness will be used.)442*443* @param params the key generation parameters444*445* @exception InvalidAlgorithmParameterException if the given parameters446* are inappropriate for this key generator447*/448public final void init(AlgorithmParameterSpec params)449throws InvalidAlgorithmParameterException450{451init(params, JCAUtil.getDefSecureRandom());452}453454/**455* Initializes this key generator with the specified parameter456* set and a user-provided source of randomness.457*458* @param params the key generation parameters459* @param random the source of randomness for this key generator460*461* @exception InvalidAlgorithmParameterException if {@code params} is462* inappropriate for this key generator463*/464public final void init(AlgorithmParameterSpec params, SecureRandom random)465throws InvalidAlgorithmParameterException466{467if (serviceIterator == null) {468spi.engineInit(params, random);469return;470}471Exception failure = null;472KeyGeneratorSpi mySpi = spi;473do {474try {475mySpi.engineInit(params, random);476initType = I_PARAMS;477initKeySize = 0;478initParams = params;479initRandom = random;480return;481} catch (Exception e) {482if (failure == null) {483failure = e;484}485mySpi = nextSpi(mySpi, false);486}487} while (mySpi != null);488if (failure instanceof InvalidAlgorithmParameterException) {489throw (InvalidAlgorithmParameterException)failure;490}491if (failure instanceof RuntimeException) {492throw (RuntimeException)failure;493}494throw new InvalidAlgorithmParameterException("init() failed", failure);495}496497/**498* Initializes this key generator for a certain keysize.499*500* <p> If this key generator requires any random bytes, it will get them501* using the502* {@link java.security.SecureRandom}503* implementation of the highest-priority installed504* provider as the source of randomness.505* (If none of the installed providers supply an implementation of506* SecureRandom, a system-provided source of randomness will be used.)507*508* @param keysize the keysize. This is an algorithm-specific metric,509* specified in number of bits.510*511* @exception InvalidParameterException if the keysize is wrong or not512* supported.513*/514public final void init(int keysize) {515init(keysize, JCAUtil.getDefSecureRandom());516}517518/**519* Initializes this key generator for a certain keysize, using a520* user-provided source of randomness.521*522* @param keysize the keysize. This is an algorithm-specific metric,523* specified in number of bits.524* @param random the source of randomness for this key generator525*526* @exception InvalidParameterException if the keysize is wrong or not527* supported.528*/529public final void init(int keysize, SecureRandom random) {530if (serviceIterator == null) {531spi.engineInit(keysize, random);532return;533}534RuntimeException failure = null;535KeyGeneratorSpi mySpi = spi;536do {537try {538mySpi.engineInit(keysize, random);539initType = I_SIZE;540initKeySize = keysize;541initParams = null;542initRandom = random;543return;544} catch (RuntimeException e) {545if (failure == null) {546failure = e;547}548mySpi = nextSpi(mySpi, false);549}550} while (mySpi != null);551throw failure;552}553554/**555* Generates a secret key.556*557* @return the new key558*/559public final SecretKey generateKey() {560if (serviceIterator == null) {561return spi.engineGenerateKey();562}563RuntimeException failure = null;564KeyGeneratorSpi mySpi = spi;565do {566try {567return mySpi.engineGenerateKey();568} catch (RuntimeException e) {569if (failure == null) {570failure = e;571}572mySpi = nextSpi(mySpi, true);573}574} while (mySpi != null);575throw failure;576}577}578579580