0N/A/*
3909N/A * Copyright (c) 1997, 2011, Oracle and/or its affiliates. All rights reserved.
0N/A * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
0N/A *
0N/A * This code is free software; you can redistribute it and/or modify it
0N/A * under the terms of the GNU General Public License version 2 only, as
2362N/A * published by the Free Software Foundation. Oracle designates this
0N/A * particular file as subject to the "Classpath" exception as provided
2362N/A * by Oracle in the LICENSE file that accompanied this code.
0N/A *
0N/A * This code is distributed in the hope that it will be useful, but WITHOUT
0N/A * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
0N/A * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
0N/A * version 2 for more details (a copy is included in the LICENSE file that
0N/A * accompanied this code).
0N/A *
0N/A * You should have received a copy of the GNU General Public License version
0N/A * 2 along with this work; if not, write to the Free Software Foundation,
0N/A * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
0N/A *
2362N/A * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
2362N/A * or visit www.oracle.com if you need additional information or have any
2362N/A * questions.
0N/A */
0N/A
0N/Apackage javax.crypto;
0N/A
0N/Aimport java.util.*;
0N/A
0N/Aimport java.security.*;
0N/Aimport java.security.Provider.Service;
0N/Aimport java.security.spec.*;
0N/A
0N/Aimport sun.security.jca.*;
0N/Aimport sun.security.jca.GetInstance.Instance;
0N/A
0N/A/**
0N/A * This class provides the functionality of a secret (symmetric) key generator.
0N/A *
0N/A * <p>Key generators are constructed using one of the <code>getInstance</code>
0N/A * class methods of this class.
0N/A *
0N/A * <p>KeyGenerator objects are reusable, i.e., after a key has been
0N/A * generated, the same KeyGenerator object can be re-used to generate further
0N/A * keys.
0N/A *
0N/A * <p>There are two ways to generate a key: in an algorithm-independent
0N/A * manner, and in an algorithm-specific manner.
0N/A * The only difference between the two is the initialization of the object:
0N/A *
0N/A * <ul>
0N/A * <li><b>Algorithm-Independent Initialization</b>
0N/A * <p>All key generators share the concepts of a <i>keysize</i> and a
0N/A * <i>source of randomness</i>.
0N/A * There is an
0N/A * {@link #init(int, java.security.SecureRandom) init}
0N/A * method in this KeyGenerator class that takes these two universally
0N/A * shared types of arguments. There is also one that takes just a
0N/A * <code>keysize</code> argument, and uses the SecureRandom implementation
0N/A * of the highest-priority installed provider as the source of randomness
0N/A * (or a system-provided source of randomness if none of the installed
0N/A * providers supply a SecureRandom implementation), and one that takes just a
0N/A * source of randomness.
0N/A *
0N/A * <p>Since no other parameters are specified when you call the above
0N/A * algorithm-independent <code>init</code> methods, it is up to the
0N/A * provider what to do about the algorithm-specific parameters (if any) to be
0N/A * associated with each of the keys.
0N/A * <p>
0N/A *
0N/A * <li><b>Algorithm-Specific Initialization</b>
0N/A * <p>For situations where a set of algorithm-specific parameters already
0N/A * exists, there are two
0N/A * {@link #init(java.security.spec.AlgorithmParameterSpec) init}
0N/A * methods that have an <code>AlgorithmParameterSpec</code>
0N/A * argument. One also has a <code>SecureRandom</code> argument, while the
0N/A * other uses the SecureRandom implementation
0N/A * of the highest-priority installed provider as the source of randomness
0N/A * (or a system-provided source of randomness if none of the installed
0N/A * providers supply a SecureRandom implementation).
0N/A * </ul>
0N/A *
0N/A * <p>In case the client does not explicitly initialize the KeyGenerator
0N/A * (via a call to an <code>init</code> method), each provider must
0N/A * supply (and document) a default initialization.
0N/A *
3465N/A * <p> Every implementation of the Java platform is required to support the
3465N/A * following standard <code>KeyGenerator</code> algorithms with the keysizes in
3465N/A * parentheses:
3465N/A * <ul>
3465N/A * <li><tt>AES</tt> (128)</li>
3465N/A * <li><tt>DES</tt> (56)</li>
3465N/A * <li><tt>DESede</tt> (168)</li>
3465N/A * <li><tt>HmacSHA1</tt></li>
3465N/A * <li><tt>HmacSHA256</tt></li>
3465N/A * </ul>
3465N/A * These algorithms are described in the <a href=
3465N/A * "{@docRoot}/../technotes/guides/security/StandardNames.html#KeyGenerator">
3465N/A * KeyGenerator section</a> of the
3465N/A * Java Cryptography Architecture Standard Algorithm Name Documentation.
3465N/A * Consult the release documentation for your implementation to see if any
3465N/A * other algorithms are supported.
3465N/A *
0N/A * @author Jan Luehe
0N/A *
0N/A * @see SecretKey
0N/A * @since 1.4
0N/A */
0N/A
0N/Apublic class KeyGenerator {
0N/A
0N/A // see java.security.KeyPairGenerator for failover notes
0N/A
0N/A private final static int I_NONE = 1;
0N/A private final static int I_RANDOM = 2;
0N/A private final static int I_PARAMS = 3;
0N/A private final static int I_SIZE = 4;
0N/A
0N/A // The provider
0N/A private Provider provider;
0N/A
0N/A // The provider implementation (delegate)
0N/A private volatile KeyGeneratorSpi spi;
0N/A
0N/A // The algorithm
0N/A private final String algorithm;
0N/A
0N/A private final Object lock = new Object();
0N/A
0N/A private Iterator serviceIterator;
0N/A
0N/A private int initType;
0N/A private int initKeySize;
0N/A private AlgorithmParameterSpec initParams;
0N/A private SecureRandom initRandom;
0N/A
0N/A /**
0N/A * Creates a KeyGenerator object.
0N/A *
0N/A * @param keyGenSpi the delegate
0N/A * @param provider the provider
0N/A * @param algorithm the algorithm
0N/A */
0N/A protected KeyGenerator(KeyGeneratorSpi keyGenSpi, Provider provider,
0N/A String algorithm) {
0N/A this.spi = keyGenSpi;
0N/A this.provider = provider;
0N/A this.algorithm = algorithm;
0N/A }
0N/A
0N/A private KeyGenerator(String algorithm) throws NoSuchAlgorithmException {
0N/A this.algorithm = algorithm;
0N/A List list = GetInstance.getServices("KeyGenerator", algorithm);
0N/A serviceIterator = list.iterator();
0N/A initType = I_NONE;
0N/A // fetch and instantiate initial spi
0N/A if (nextSpi(null, false) == null) {
0N/A throw new NoSuchAlgorithmException
0N/A (algorithm + " KeyGenerator not available");
0N/A }
0N/A }
0N/A
0N/A /**
0N/A * Returns the algorithm name of this <code>KeyGenerator</code> object.
0N/A *
0N/A * <p>This is the same name that was specified in one of the
0N/A * <code>getInstance</code> calls that created this
0N/A * <code>KeyGenerator</code> object.
0N/A *
0N/A * @return the algorithm name of this <code>KeyGenerator</code> object.
0N/A */
0N/A public final String getAlgorithm() {
0N/A return this.algorithm;
0N/A }
0N/A
0N/A /**
0N/A * Returns a <code>KeyGenerator</code> object that generates secret keys
0N/A * for the specified algorithm.
0N/A *
0N/A * <p> This method traverses the list of registered security Providers,
0N/A * starting with the most preferred Provider.
0N/A * A new KeyGenerator object encapsulating the
0N/A * KeyGeneratorSpi implementation from the first
0N/A * Provider that supports the specified algorithm is returned.
0N/A *
0N/A * <p> Note that the list of registered providers may be retrieved via
0N/A * the {@link Security#getProviders() Security.getProviders()} method.
0N/A *
0N/A * @param algorithm the standard name of the requested key algorithm.
3465N/A * See the KeyGenerator section in the <a href=
3465N/A * "{@docRoot}/../technotes/guides/security/StandardNames.html#KeyGenerator">
3465N/A * Java Cryptography Architecture Standard Algorithm Name Documentation</a>
0N/A * for information about standard algorithm names.
0N/A *
0N/A * @return the new <code>KeyGenerator</code> object.
0N/A *
0N/A * @exception NullPointerException if the specified algorithm is null.
0N/A *
0N/A * @exception NoSuchAlgorithmException if no Provider supports a
0N/A * KeyGeneratorSpi implementation for the
0N/A * specified algorithm.
0N/A *
0N/A * @see java.security.Provider
0N/A */
0N/A public static final KeyGenerator getInstance(String algorithm)
0N/A throws NoSuchAlgorithmException {
0N/A return new KeyGenerator(algorithm);
0N/A }
0N/A
0N/A /**
0N/A * Returns a <code>KeyGenerator</code> object that generates secret keys
0N/A * for the specified algorithm.
0N/A *
0N/A * <p> A new KeyGenerator object encapsulating the
0N/A * KeyGeneratorSpi implementation from the specified provider
0N/A * is returned. The specified provider must be registered
0N/A * in the security provider list.
0N/A *
0N/A * <p> Note that the list of registered providers may be retrieved via
0N/A * the {@link Security#getProviders() Security.getProviders()} method.
0N/A *
0N/A * @param algorithm the standard name of the requested key algorithm.
3465N/A * See the KeyGenerator section in the <a href=
3465N/A * "{@docRoot}/../technotes/guides/security/StandardNames.html#KeyGenerator">
3465N/A * Java Cryptography Architecture Standard Algorithm Name Documentation</a>
0N/A * for information about standard algorithm names.
0N/A *
0N/A * @param provider the name of the provider.
0N/A *
0N/A * @return the new <code>KeyGenerator</code> object.
0N/A *
0N/A * @exception NullPointerException if the specified algorithm is null.
0N/A *
0N/A * @exception NoSuchAlgorithmException if a KeyGeneratorSpi
0N/A * implementation for the specified algorithm is not
0N/A * available from the specified provider.
0N/A *
0N/A * @exception NoSuchProviderException if the specified provider is not
0N/A * registered in the security provider list.
0N/A *
0N/A * @exception IllegalArgumentException if the <code>provider</code>
0N/A * is null or empty.
0N/A *
0N/A * @see java.security.Provider
0N/A */
0N/A public static final KeyGenerator getInstance(String algorithm,
0N/A String provider) throws NoSuchAlgorithmException,
0N/A NoSuchProviderException {
0N/A Instance instance = JceSecurity.getInstance("KeyGenerator",
0N/A KeyGeneratorSpi.class, algorithm, provider);
0N/A return new KeyGenerator((KeyGeneratorSpi)instance.impl,
0N/A instance.provider, algorithm);
0N/A }
0N/A
0N/A /**
0N/A * Returns a <code>KeyGenerator</code> object that generates secret keys
0N/A * for the specified algorithm.
0N/A *
0N/A * <p> A new KeyGenerator object encapsulating the
0N/A * KeyGeneratorSpi implementation from the specified Provider
0N/A * object is returned. Note that the specified Provider object
0N/A * does not have to be registered in the provider list.
0N/A *
0N/A * @param algorithm the standard name of the requested key algorithm.
3465N/A * See the KeyGenerator section in the <a href=
3465N/A * "{@docRoot}/../technotes/guides/security/StandardNames.html#KeyGenerator">
3465N/A * Java Cryptography Architecture Standard Algorithm Name Documentation</a>
0N/A * for information about standard algorithm names.
0N/A *
0N/A * @param provider the provider.
0N/A *
0N/A * @return the new <code>KeyGenerator</code> object.
0N/A *
0N/A * @exception NullPointerException if the specified algorithm is null.
0N/A *
0N/A * @exception NoSuchAlgorithmException if a KeyGeneratorSpi
0N/A * implementation for the specified algorithm is not available
0N/A * from the specified Provider object.
0N/A *
0N/A * @exception IllegalArgumentException if the <code>provider</code>
0N/A * is null.
0N/A *
0N/A * @see java.security.Provider
0N/A */
0N/A public static final KeyGenerator getInstance(String algorithm,
0N/A Provider provider) throws NoSuchAlgorithmException {
0N/A Instance instance = JceSecurity.getInstance("KeyGenerator",
0N/A KeyGeneratorSpi.class, algorithm, provider);
0N/A return new KeyGenerator((KeyGeneratorSpi)instance.impl,
0N/A instance.provider, algorithm);
0N/A }
0N/A
0N/A /**
0N/A * Returns the provider of this <code>KeyGenerator</code> object.
0N/A *
0N/A * @return the provider of this <code>KeyGenerator</code> object
0N/A */
0N/A public final Provider getProvider() {
0N/A synchronized (lock) {
0N/A disableFailover();
0N/A return provider;
0N/A }
0N/A }
0N/A
0N/A /**
0N/A * Update the active spi of this class and return the next
0N/A * implementation for failover. If no more implemenations are
0N/A * available, this method returns null. However, the active spi of
0N/A * this class is never set to null.
0N/A */
0N/A private KeyGeneratorSpi nextSpi(KeyGeneratorSpi oldSpi,
0N/A boolean reinit) {
0N/A synchronized (lock) {
0N/A // somebody else did a failover concurrently
0N/A // try that spi now
0N/A if ((oldSpi != null) && (oldSpi != spi)) {
0N/A return spi;
0N/A }
0N/A if (serviceIterator == null) {
0N/A return null;
0N/A }
0N/A while (serviceIterator.hasNext()) {
0N/A Service s = (Service)serviceIterator.next();
0N/A if (JceSecurity.canUseProvider(s.getProvider()) == false) {
0N/A continue;
0N/A }
0N/A try {
0N/A Object inst = s.newInstance(null);
0N/A // ignore non-spis
0N/A if (inst instanceof KeyGeneratorSpi == false) {
0N/A continue;
0N/A }
0N/A KeyGeneratorSpi spi = (KeyGeneratorSpi)inst;
0N/A if (reinit) {
0N/A if (initType == I_SIZE) {
0N/A spi.engineInit(initKeySize, initRandom);
0N/A } else if (initType == I_PARAMS) {
0N/A spi.engineInit(initParams, initRandom);
0N/A } else if (initType == I_RANDOM) {
0N/A spi.engineInit(initRandom);
0N/A } else if (initType != I_NONE) {
0N/A throw new AssertionError
0N/A ("KeyGenerator initType: " + initType);
0N/A }
0N/A }
0N/A provider = s.getProvider();
0N/A this.spi = spi;
0N/A return spi;
0N/A } catch (Exception e) {
0N/A // ignore
0N/A }
0N/A }
0N/A disableFailover();
0N/A return null;
0N/A }
0N/A }
0N/A
0N/A void disableFailover() {
0N/A serviceIterator = null;
0N/A initType = 0;
0N/A initParams = null;
0N/A initRandom = null;
0N/A }
0N/A
0N/A /**
0N/A * Initializes this key generator.
0N/A *
0N/A * @param random the source of randomness for this generator
0N/A */
0N/A public final void init(SecureRandom random) {
0N/A if (serviceIterator == null) {
0N/A spi.engineInit(random);
0N/A return;
0N/A }
0N/A RuntimeException failure = null;
0N/A KeyGeneratorSpi mySpi = spi;
0N/A do {
0N/A try {
0N/A mySpi.engineInit(random);
0N/A initType = I_RANDOM;
0N/A initKeySize = 0;
0N/A initParams = null;
0N/A initRandom = random;
0N/A return;
0N/A } catch (RuntimeException e) {
0N/A if (failure == null) {
0N/A failure = e;
0N/A }
0N/A mySpi = nextSpi(mySpi, false);
0N/A }
0N/A } while (mySpi != null);
0N/A throw failure;
0N/A }
0N/A
0N/A /**
0N/A * Initializes this key generator with the specified parameter set.
0N/A *
0N/A * <p> If this key generator requires any random bytes, it will get them
0N/A * using the
0N/A * {@link SecureRandom <code>SecureRandom</code>}
0N/A * implementation of the highest-priority installed
0N/A * provider as the source of randomness.
0N/A * (If none of the installed providers supply an implementation of
0N/A * SecureRandom, a system-provided source of randomness will be used.)
0N/A *
0N/A * @param params the key generation parameters
0N/A *
0N/A * @exception InvalidAlgorithmParameterException if the given parameters
0N/A * are inappropriate for this key generator
0N/A */
0N/A public final void init(AlgorithmParameterSpec params)
0N/A throws InvalidAlgorithmParameterException
0N/A {
0N/A init(params, JceSecurity.RANDOM);
0N/A }
0N/A
0N/A /**
0N/A * Initializes this key generator with the specified parameter
0N/A * set and a user-provided source of randomness.
0N/A *
0N/A * @param params the key generation parameters
0N/A * @param random the source of randomness for this key generator
0N/A *
0N/A * @exception InvalidAlgorithmParameterException if <code>params</code> is
0N/A * inappropriate for this key generator
0N/A */
0N/A public final void init(AlgorithmParameterSpec params, SecureRandom random)
0N/A throws InvalidAlgorithmParameterException
0N/A {
0N/A if (serviceIterator == null) {
0N/A spi.engineInit(params, random);
0N/A return;
0N/A }
0N/A Exception failure = null;
0N/A KeyGeneratorSpi mySpi = spi;
0N/A do {
0N/A try {
0N/A mySpi.engineInit(params, random);
0N/A initType = I_PARAMS;
0N/A initKeySize = 0;
0N/A initParams = params;
0N/A initRandom = random;
0N/A return;
0N/A } catch (Exception e) {
0N/A if (failure == null) {
0N/A failure = e;
0N/A }
0N/A mySpi = nextSpi(mySpi, false);
0N/A }
0N/A } while (mySpi != null);
0N/A if (failure instanceof InvalidAlgorithmParameterException) {
0N/A throw (InvalidAlgorithmParameterException)failure;
0N/A }
0N/A if (failure instanceof RuntimeException) {
0N/A throw (RuntimeException)failure;
0N/A }
0N/A throw new InvalidAlgorithmParameterException("init() failed", failure);
0N/A }
0N/A
0N/A /**
0N/A * Initializes this key generator for a certain keysize.
0N/A *
0N/A * <p> If this key generator requires any random bytes, it will get them
0N/A * using the
0N/A * {@link SecureRandom <code>SecureRandom</code>}
0N/A * implementation of the highest-priority installed
0N/A * provider as the source of randomness.
0N/A * (If none of the installed providers supply an implementation of
0N/A * SecureRandom, a system-provided source of randomness will be used.)
0N/A *
0N/A * @param keysize the keysize. This is an algorithm-specific metric,
0N/A * specified in number of bits.
0N/A *
0N/A * @exception InvalidParameterException if the keysize is wrong or not
0N/A * supported.
0N/A */
0N/A public final void init(int keysize) {
0N/A init(keysize, JceSecurity.RANDOM);
0N/A }
0N/A
0N/A /**
0N/A * Initializes this key generator for a certain keysize, using a
0N/A * user-provided source of randomness.
0N/A *
0N/A * @param keysize the keysize. This is an algorithm-specific metric,
0N/A * specified in number of bits.
0N/A * @param random the source of randomness for this key generator
0N/A *
0N/A * @exception InvalidParameterException if the keysize is wrong or not
0N/A * supported.
0N/A */
0N/A public final void init(int keysize, SecureRandom random) {
0N/A if (serviceIterator == null) {
0N/A spi.engineInit(keysize, random);
0N/A return;
0N/A }
0N/A RuntimeException failure = null;
0N/A KeyGeneratorSpi mySpi = spi;
0N/A do {
0N/A try {
0N/A mySpi.engineInit(keysize, random);
0N/A initType = I_SIZE;
0N/A initKeySize = keysize;
0N/A initParams = null;
0N/A initRandom = random;
0N/A return;
0N/A } catch (RuntimeException e) {
0N/A if (failure == null) {
0N/A failure = e;
0N/A }
0N/A mySpi = nextSpi(mySpi, false);
0N/A }
0N/A } while (mySpi != null);
0N/A throw failure;
0N/A }
0N/A
0N/A /**
0N/A * Generates a secret key.
0N/A *
0N/A * @return the new key
0N/A */
0N/A public final SecretKey generateKey() {
0N/A if (serviceIterator == null) {
0N/A return spi.engineGenerateKey();
0N/A }
0N/A RuntimeException failure = null;
0N/A KeyGeneratorSpi mySpi = spi;
0N/A do {
0N/A try {
0N/A return mySpi.engineGenerateKey();
0N/A } catch (RuntimeException e) {
0N/A if (failure == null) {
0N/A failure = e;
0N/A }
0N/A mySpi = nextSpi(mySpi, true);
0N/A }
0N/A } while (mySpi != null);
0N/A throw failure;
0N/A }
0N/A}