Path: blob/aarch64-shenandoah-jdk8u272-b10/jdk/src/share/classes/javax/crypto/KeyGenerator.java
38829 views
/*1* Copyright (c) 1997, 2019, 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*86* <p> Every implementation of the Java platform is required to support the87* following standard {@code KeyGenerator} algorithms with the keysizes in88* parentheses:89* <ul>90* <li>{@code AES} (128)</li>91* <li>{@code DES} (56)</li>92* <li>{@code DESede} (168)</li>93* <li>{@code HmacSHA1}</li>94* <li>{@code HmacSHA256}</li>95* </ul>96* These algorithms are described in the <a href=97* "{@docRoot}/../technotes/guides/security/StandardNames.html#KeyGenerator">98* KeyGenerator section</a> of the99* Java Cryptography Architecture Standard Algorithm Name Documentation.100* Consult the release documentation for your implementation to see if any101* other algorithms are supported.102*103* @author Jan Luehe104*105* @see SecretKey106* @since 1.4107*/108109public class KeyGenerator {110111private static final Debug pdebug =112Debug.getInstance("provider", "Provider");113private static final boolean skipDebug =114Debug.isOn("engine=") && !Debug.isOn("keygenerator");115116// see java.security.KeyPairGenerator for failover notes117118private final static int I_NONE = 1;119private final static int I_RANDOM = 2;120private final static int I_PARAMS = 3;121private final static int I_SIZE = 4;122123// The provider124private Provider provider;125126// The provider implementation (delegate)127private volatile KeyGeneratorSpi spi;128129// The algorithm130private final String algorithm;131132private final Object lock = new Object();133134private Iterator<Service> serviceIterator;135136private int initType;137private int initKeySize;138private AlgorithmParameterSpec initParams;139private SecureRandom initRandom;140141/**142* Creates a KeyGenerator object.143*144* @param keyGenSpi the delegate145* @param provider the provider146* @param algorithm the algorithm147*/148protected KeyGenerator(KeyGeneratorSpi keyGenSpi, Provider provider,149String algorithm) {150this.spi = keyGenSpi;151this.provider = provider;152this.algorithm = algorithm;153154if (!skipDebug && pdebug != null) {155pdebug.println("KeyGenerator." + algorithm + " algorithm from: " +156this.provider.getName());157}158}159160private KeyGenerator(String algorithm) throws NoSuchAlgorithmException {161this.algorithm = algorithm;162List<Service> list =163GetInstance.getServices("KeyGenerator", algorithm);164serviceIterator = list.iterator();165initType = I_NONE;166// fetch and instantiate initial spi167if (nextSpi(null, false) == null) {168throw new NoSuchAlgorithmException169(algorithm + " KeyGenerator not available");170}171172if (!skipDebug && pdebug != null) {173pdebug.println("KeyGenerator." + algorithm + " algorithm from: " +174this.provider.getName());175}176}177178/**179* Returns the algorithm name of this {@code KeyGenerator} object.180*181* <p>This is the same name that was specified in one of the182* {@code getInstance} calls that created this183* {@code KeyGenerator} object.184*185* @return the algorithm name of this {@code KeyGenerator} object.186*/187public final String getAlgorithm() {188return this.algorithm;189}190191/**192* Returns a {@code KeyGenerator} object that generates secret keys193* for the specified algorithm.194*195* <p> This method traverses the list of registered security Providers,196* starting with the most preferred Provider.197* A new KeyGenerator object encapsulating the198* KeyGeneratorSpi implementation from the first199* Provider that supports the specified algorithm is returned.200*201* <p> Note that the list of registered providers may be retrieved via202* the {@link Security#getProviders() Security.getProviders()} method.203*204* @param algorithm the standard name of the requested key algorithm.205* See the KeyGenerator section in the <a href=206* "{@docRoot}/../technotes/guides/security/StandardNames.html#KeyGenerator">207* Java Cryptography Architecture Standard Algorithm Name Documentation</a>208* for information about standard algorithm names.209*210* @return the new {@code KeyGenerator} object.211*212* @exception NullPointerException if the specified algorithm is null.213*214* @exception NoSuchAlgorithmException if no Provider supports a215* KeyGeneratorSpi implementation for the216* specified algorithm.217*218* @see java.security.Provider219*/220public static final KeyGenerator getInstance(String algorithm)221throws NoSuchAlgorithmException {222return new KeyGenerator(algorithm);223}224225/**226* Returns a {@code KeyGenerator} object that generates secret keys227* for the specified algorithm.228*229* <p> A new KeyGenerator object encapsulating the230* KeyGeneratorSpi implementation from the specified provider231* is returned. The specified provider must be registered232* in the security provider list.233*234* <p> Note that the list of registered providers may be retrieved via235* the {@link Security#getProviders() Security.getProviders()} method.236*237* @param algorithm the standard name of the requested key algorithm.238* See the KeyGenerator section in the <a href=239* "{@docRoot}/../technotes/guides/security/StandardNames.html#KeyGenerator">240* Java Cryptography Architecture Standard Algorithm Name Documentation</a>241* for information about standard algorithm names.242*243* @param provider the name of the provider.244*245* @return the new {@code KeyGenerator} object.246*247* @exception NullPointerException if the specified algorithm is null.248*249* @exception NoSuchAlgorithmException if a KeyGeneratorSpi250* implementation for the specified algorithm is not251* available from the specified provider.252*253* @exception NoSuchProviderException if the specified provider is not254* registered in the security provider list.255*256* @exception IllegalArgumentException if the {@code provider}257* is null or empty.258*259* @see java.security.Provider260*/261public static final KeyGenerator getInstance(String algorithm,262String provider) throws NoSuchAlgorithmException,263NoSuchProviderException {264Instance instance = JceSecurity.getInstance("KeyGenerator",265KeyGeneratorSpi.class, algorithm, provider);266return new KeyGenerator((KeyGeneratorSpi)instance.impl,267instance.provider, algorithm);268}269270/**271* Returns a {@code KeyGenerator} object that generates secret keys272* for the specified algorithm.273*274* <p> A new KeyGenerator object encapsulating the275* KeyGeneratorSpi implementation from the specified Provider276* object is returned. Note that the specified Provider object277* does not have to be registered in the provider list.278*279* @param algorithm the standard name of the requested key algorithm.280* See the KeyGenerator section in the <a href=281* "{@docRoot}/../technotes/guides/security/StandardNames.html#KeyGenerator">282* Java Cryptography Architecture Standard Algorithm Name Documentation</a>283* for information about standard algorithm names.284*285* @param provider the provider.286*287* @return the new {@code KeyGenerator} object.288*289* @exception NullPointerException if the specified algorithm is null.290*291* @exception NoSuchAlgorithmException if a KeyGeneratorSpi292* implementation for the specified algorithm is not available293* from the specified Provider object.294*295* @exception IllegalArgumentException if the {@code provider}296* is null.297*298* @see java.security.Provider299*/300public static final KeyGenerator getInstance(String algorithm,301Provider provider) throws NoSuchAlgorithmException {302Instance instance = JceSecurity.getInstance("KeyGenerator",303KeyGeneratorSpi.class, algorithm, provider);304return new KeyGenerator((KeyGeneratorSpi)instance.impl,305instance.provider, algorithm);306}307308/**309* Returns the provider of this {@code KeyGenerator} object.310*311* @return the provider of this {@code KeyGenerator} object312*/313public final Provider getProvider() {314synchronized (lock) {315disableFailover();316return provider;317}318}319320/**321* Update the active spi of this class and return the next322* implementation for failover. If no more implemenations are323* available, this method returns null. However, the active spi of324* this class is never set to null.325*/326private KeyGeneratorSpi nextSpi(KeyGeneratorSpi oldSpi,327boolean reinit) {328synchronized (lock) {329// somebody else did a failover concurrently330// try that spi now331if ((oldSpi != null) && (oldSpi != spi)) {332return spi;333}334if (serviceIterator == null) {335return null;336}337while (serviceIterator.hasNext()) {338Service s = serviceIterator.next();339if (JceSecurity.canUseProvider(s.getProvider()) == false) {340continue;341}342try {343Object inst = s.newInstance(null);344// ignore non-spis345if (inst instanceof KeyGeneratorSpi == false) {346continue;347}348KeyGeneratorSpi spi = (KeyGeneratorSpi)inst;349if (reinit) {350if (initType == I_SIZE) {351spi.engineInit(initKeySize, initRandom);352} else if (initType == I_PARAMS) {353spi.engineInit(initParams, initRandom);354} else if (initType == I_RANDOM) {355spi.engineInit(initRandom);356} else if (initType != I_NONE) {357throw new AssertionError358("KeyGenerator initType: " + initType);359}360}361provider = s.getProvider();362this.spi = spi;363return spi;364} catch (Exception e) {365// ignore366}367}368disableFailover();369return null;370}371}372373void disableFailover() {374serviceIterator = null;375initType = 0;376initParams = null;377initRandom = null;378}379380/**381* Initializes this key generator.382*383* @param random the source of randomness for this generator384*/385public final void init(SecureRandom random) {386if (serviceIterator == null) {387spi.engineInit(random);388return;389}390RuntimeException failure = null;391KeyGeneratorSpi mySpi = spi;392do {393try {394mySpi.engineInit(random);395initType = I_RANDOM;396initKeySize = 0;397initParams = null;398initRandom = random;399return;400} catch (RuntimeException e) {401if (failure == null) {402failure = e;403}404mySpi = nextSpi(mySpi, false);405}406} while (mySpi != null);407throw failure;408}409410/**411* Initializes this key generator with the specified parameter set.412*413* <p> If this key generator requires any random bytes, it will get them414* using the415* {@link java.security.SecureRandom}416* implementation of the highest-priority installed417* provider as the source of randomness.418* (If none of the installed providers supply an implementation of419* SecureRandom, a system-provided source of randomness will be used.)420*421* @param params the key generation parameters422*423* @exception InvalidAlgorithmParameterException if the given parameters424* are inappropriate for this key generator425*/426public final void init(AlgorithmParameterSpec params)427throws InvalidAlgorithmParameterException428{429init(params, JceSecurity.RANDOM);430}431432/**433* Initializes this key generator with the specified parameter434* set and a user-provided source of randomness.435*436* @param params the key generation parameters437* @param random the source of randomness for this key generator438*439* @exception InvalidAlgorithmParameterException if {@code params} is440* inappropriate for this key generator441*/442public final void init(AlgorithmParameterSpec params, SecureRandom random)443throws InvalidAlgorithmParameterException444{445if (serviceIterator == null) {446spi.engineInit(params, random);447return;448}449Exception failure = null;450KeyGeneratorSpi mySpi = spi;451do {452try {453mySpi.engineInit(params, random);454initType = I_PARAMS;455initKeySize = 0;456initParams = params;457initRandom = random;458return;459} catch (Exception e) {460if (failure == null) {461failure = e;462}463mySpi = nextSpi(mySpi, false);464}465} while (mySpi != null);466if (failure instanceof InvalidAlgorithmParameterException) {467throw (InvalidAlgorithmParameterException)failure;468}469if (failure instanceof RuntimeException) {470throw (RuntimeException)failure;471}472throw new InvalidAlgorithmParameterException("init() failed", failure);473}474475/**476* Initializes this key generator for a certain keysize.477*478* <p> If this key generator requires any random bytes, it will get them479* using the480* {@link java.security.SecureRandom}481* implementation of the highest-priority installed482* provider as the source of randomness.483* (If none of the installed providers supply an implementation of484* SecureRandom, a system-provided source of randomness will be used.)485*486* @param keysize the keysize. This is an algorithm-specific metric,487* specified in number of bits.488*489* @exception InvalidParameterException if the keysize is wrong or not490* supported.491*/492public final void init(int keysize) {493init(keysize, JceSecurity.RANDOM);494}495496/**497* Initializes this key generator for a certain keysize, using a498* user-provided source of randomness.499*500* @param keysize the keysize. This is an algorithm-specific metric,501* specified in number of bits.502* @param random the source of randomness for this key generator503*504* @exception InvalidParameterException if the keysize is wrong or not505* supported.506*/507public final void init(int keysize, SecureRandom random) {508if (serviceIterator == null) {509spi.engineInit(keysize, random);510return;511}512RuntimeException failure = null;513KeyGeneratorSpi mySpi = spi;514do {515try {516mySpi.engineInit(keysize, random);517initType = I_SIZE;518initKeySize = keysize;519initParams = null;520initRandom = random;521return;522} catch (RuntimeException e) {523if (failure == null) {524failure = e;525}526mySpi = nextSpi(mySpi, false);527}528} while (mySpi != null);529throw failure;530}531532/**533* Generates a secret key.534*535* @return the new key536*/537public final SecretKey generateKey() {538if (serviceIterator == null) {539return spi.engineGenerateKey();540}541RuntimeException failure = null;542KeyGeneratorSpi mySpi = spi;543do {544try {545return mySpi.engineGenerateKey();546} catch (RuntimeException e) {547if (failure == null) {548failure = e;549}550mySpi = nextSpi(mySpi, true);551}552} while (mySpi != null);553throw failure;554}555}556557558