Home | History | Annotate | Download | only in crypto
      1 /*
      2  * Copyright (c) 1997, 2011, Oracle and/or its affiliates. All rights reserved.
      3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
      4  *
      5  * This code is free software; you can redistribute it and/or modify it
      6  * under the terms of the GNU General Public License version 2 only, as
      7  * published by the Free Software Foundation.  Oracle designates this
      8  * particular file as subject to the "Classpath" exception as provided
      9  * by Oracle in the LICENSE file that accompanied this code.
     10  *
     11  * This code is distributed in the hope that it will be useful, but WITHOUT
     12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
     13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
     14  * version 2 for more details (a copy is included in the LICENSE file that
     15  * accompanied this code).
     16  *
     17  * You should have received a copy of the GNU General Public License version
     18  * 2 along with this work; if not, write to the Free Software Foundation,
     19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
     20  *
     21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
     22  * or visit www.oracle.com if you need additional information or have any
     23  * questions.
     24  */
     25 
     26 package javax.crypto;
     27 
     28 import java.util.*;
     29 
     30 import java.security.*;
     31 import java.security.Provider.Service;
     32 import java.security.spec.*;
     33 
     34 import sun.security.jca.*;
     35 import sun.security.jca.GetInstance.Instance;
     36 
     37 /**
     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</code>
     41  * class methods of this class.
     42  *
     43  * <p>KeyGenerator objects are reusable, i.e., after a key has been
     44  * generated, the same KeyGenerator object can be re-used to generate further
     45  * keys.
     46  *
     47  * <p>There are two ways to generate a key: in an algorithm-independent
     48  * 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 a
     54  * <i>source of randomness</i>.
     55  * There is an
     56  * {@link #init(int, java.security.SecureRandom) init}
     57  * method in this KeyGenerator class that takes these two universally
     58  * shared types of arguments. There is also one that takes just a
     59  * <code>keysize</code> argument, and uses the SecureRandom implementation
     60  * of the highest-priority installed provider as the source of randomness
     61  * (or a system-provided source of randomness if none of the installed
     62  * providers supply a SecureRandom implementation), and one that takes just a
     63  * source of randomness.
     64  *
     65  * <p>Since no other parameters are specified when you call the above
     66  * algorithm-independent <code>init</code> methods, it is up to the
     67  * provider what to do about the algorithm-specific parameters (if any) to be
     68  * associated with each of the keys.
     69  * <p>
     70  *
     71  * <li><b>Algorithm-Specific Initialization</b>
     72  * <p>For situations where a set of algorithm-specific parameters already
     73  * exists, there are two
     74  * {@link #init(java.security.spec.AlgorithmParameterSpec) init}
     75  * methods that have an <code>AlgorithmParameterSpec</code>
     76  * argument. One also has a <code>SecureRandom</code> argument, while the
     77  * other uses the SecureRandom implementation
     78  * of the highest-priority installed provider as the source of randomness
     79  * (or a system-provided source of randomness if none of the installed
     80  * providers supply a SecureRandom implementation).
     81  * </ul>
     82  *
     83  * <p>In case the client does not explicitly initialize the KeyGenerator
     84  * (via a call to an <code>init</code> method), each provider must
     85  * supply (and document) a default initialization.
     86  *
     87  * <p> Android provides the following <code>KeyGenerator</code> algorithms:
     88  * <table>
     89  *     <thead>
     90  *         <tr>
     91  *             <th>Name</th>
     92  *             <th>Supported (API Levels)</th>
     93  *         </tr>
     94  *     </thead>
     95  *     <tbody>
     96  *         <tr>
     97  *             <td>AES</td>
     98  *             <td>1+</td>
     99  *         </tr>
    100  *         <tr>
    101  *             <td>AESWRAP</td>
    102  *             <td>1&ndash;8</td>
    103  *         </tr>
    104  *         <tr>
    105  *             <td>ARC4</td>
    106  *             <td>14+</td>
    107  *         </tr>
    108  *         <tr>
    109  *             <td>Blowfish</td>
    110  *             <td>10+</td>
    111  *         </tr>
    112  *         <tr>
    113  *             <td>DES</td>
    114  *             <td>1+</td>
    115  *         </tr>
    116  *         <tr>
    117  *             <td>DESede</td>
    118  *             <td>1+</td>
    119  *         </tr>
    120  *         <tr>
    121  *             <td>DESedeWRAP</td>
    122  *             <td>1&ndash;8</td>
    123  *         </tr>
    124  *         <tr>
    125  *             <td>HmacMD5</td>
    126  *             <td>1+</td>
    127  *         </tr>
    128  *         <tr>
    129  *             <td>HmacSHA1</td>
    130  *             <td>1+</td>
    131  *         </tr>
    132  *         <tr>
    133  *             <td>HmacSHA224</td>
    134  *             <td>1&ndash;8,22+</td>
    135  *         </tr>
    136  *         <tr>
    137  *             <td>HmacSHA256</td>
    138  *             <td>1+</td>
    139  *         </tr>
    140  *         <tr>
    141  *             <td>HmacSHA384</td>
    142  *             <td>1+</td>
    143  *         </tr>
    144  *         <tr>
    145  *             <td>HmacSHA512</td>
    146  *             <td>1+</td>
    147  *         </tr>
    148  *         <tr>
    149  *             <td>RC4</td>
    150  *             <td>10&ndash;13</td>
    151  *         </tr>
    152  *     </tbody>
    153  * </table>
    154  *
    155  * These algorithms are described in the <a href=
    156  * "{@docRoot}openjdk-redirect.html?v=8&path=/technotes/guides/security/StandardNames.html#KeyGenerator">
    157  * KeyGenerator section</a> of the
    158  * Java Cryptography Architecture Standard Algorithm Name Documentation.
    159  *
    160  * @author Jan Luehe
    161  *
    162  * @see SecretKey
    163  * @since 1.4
    164  */
    165 
    166 public class KeyGenerator {
    167 
    168     // see java.security.KeyPairGenerator for failover notes
    169 
    170     private final static int I_NONE   = 1;
    171     private final static int I_RANDOM = 2;
    172     private final static int I_PARAMS = 3;
    173     private final static int I_SIZE   = 4;
    174 
    175     // The provider
    176     private Provider provider;
    177 
    178     // The provider implementation (delegate)
    179     private volatile KeyGeneratorSpi spi;
    180 
    181     // The algorithm
    182     private final String algorithm;
    183 
    184     private final Object lock = new Object();
    185 
    186     private Iterator serviceIterator;
    187 
    188     private int initType;
    189     private int initKeySize;
    190     private AlgorithmParameterSpec initParams;
    191     private SecureRandom initRandom;
    192 
    193     /**
    194      * Creates a KeyGenerator object.
    195      *
    196      * @param keyGenSpi the delegate
    197      * @param provider the provider
    198      * @param algorithm the algorithm
    199      */
    200     protected KeyGenerator(KeyGeneratorSpi keyGenSpi, Provider provider,
    201                            String algorithm) {
    202         this.spi = keyGenSpi;
    203         this.provider = provider;
    204         this.algorithm = algorithm;
    205     }
    206 
    207     private KeyGenerator(String algorithm) throws NoSuchAlgorithmException {
    208         this.algorithm = algorithm;
    209         List list = GetInstance.getServices("KeyGenerator", algorithm);
    210         serviceIterator = list.iterator();
    211         initType = I_NONE;
    212         // fetch and instantiate initial spi
    213         if (nextSpi(null, false) == null) {
    214             throw new NoSuchAlgorithmException
    215                 (algorithm + " KeyGenerator not available");
    216         }
    217     }
    218 
    219     /**
    220      * Returns the algorithm name of this <code>KeyGenerator</code> object.
    221      *
    222      * <p>This is the same name that was specified in one of the
    223      * <code>getInstance</code> calls that created this
    224      * <code>KeyGenerator</code> object.
    225      *
    226      * @return the algorithm name of this <code>KeyGenerator</code> object.
    227      */
    228     public final String getAlgorithm() {
    229         return this.algorithm;
    230     }
    231 
    232     /**
    233      * Returns a <code>KeyGenerator</code> object that generates secret keys
    234      * for the specified algorithm.
    235      *
    236      * <p> This method traverses the list of registered security Providers,
    237      * starting with the most preferred Provider.
    238      * A new KeyGenerator object encapsulating the
    239      * KeyGeneratorSpi implementation from the first
    240      * Provider that supports the specified algorithm is returned.
    241      *
    242      * <p> Note that the list of registered providers may be retrieved via
    243      * the {@link Security#getProviders() Security.getProviders()} method.
    244      *
    245      * @param algorithm the standard name of the requested key algorithm.
    246      * See the KeyGenerator section in the <a href=
    247      * "{@docRoot}openjdk-redirect.html?v=8&path=/technotes/guides/security/StandardNames.html#KeyGenerator">
    248      * Java Cryptography Architecture Standard Algorithm Name Documentation</a>
    249      * for information about standard algorithm names.
    250      *
    251      * @return the new <code>KeyGenerator</code> object.
    252      *
    253      * @exception NullPointerException if the specified algorithm is null.
    254      *
    255      * @exception NoSuchAlgorithmException if no Provider supports a
    256      *          KeyGeneratorSpi implementation for the
    257      *          specified algorithm.
    258      *
    259      * @see java.security.Provider
    260      */
    261     public static final KeyGenerator getInstance(String algorithm)
    262             throws NoSuchAlgorithmException {
    263         return new KeyGenerator(algorithm);
    264     }
    265 
    266     /**
    267      * Returns a <code>KeyGenerator</code> object that generates secret keys
    268      * for the specified algorithm.
    269      *
    270      * <p> A new KeyGenerator object encapsulating the
    271      * KeyGeneratorSpi implementation from the specified provider
    272      * is returned.  The specified provider must be registered
    273      * in the security provider list.
    274      *
    275      * <p> Note that the list of registered providers may be retrieved via
    276      * the {@link Security#getProviders() Security.getProviders()} method.
    277      *
    278      * @param algorithm the standard name of the requested key algorithm.
    279      * See the KeyGenerator section in the <a href=
    280      * "{@docRoot}openjdk-redirect.html?v=8&path=/technotes/guides/security/StandardNames.html#KeyGenerator">
    281      * Java Cryptography Architecture Standard Algorithm Name Documentation</a>
    282      * for information about standard algorithm names.
    283      *
    284      * @param provider the name of the provider.
    285      *
    286      * @return the new <code>KeyGenerator</code> object.
    287      *
    288      * @exception NullPointerException if the specified algorithm is null.
    289      *
    290      * @exception NoSuchAlgorithmException if a KeyGeneratorSpi
    291      *          implementation for the specified algorithm is not
    292      *          available from the specified provider.
    293      *
    294      * @exception NoSuchProviderException if the specified provider is not
    295      *          registered in the security provider list.
    296      *
    297      * @exception IllegalArgumentException if the <code>provider</code>
    298      *          is null or empty.
    299      *
    300      * @see java.security.Provider
    301      */
    302     public static final KeyGenerator getInstance(String algorithm,
    303             String provider) throws NoSuchAlgorithmException,
    304             NoSuchProviderException {
    305         Instance instance = JceSecurity.getInstance("KeyGenerator",
    306                 KeyGeneratorSpi.class, algorithm, provider);
    307         return new KeyGenerator((KeyGeneratorSpi)instance.impl,
    308                 instance.provider, algorithm);
    309     }
    310 
    311     /**
    312      * Returns a <code>KeyGenerator</code> object that generates secret keys
    313      * for the specified algorithm.
    314      *
    315      * <p> A new KeyGenerator object encapsulating the
    316      * KeyGeneratorSpi implementation from the specified Provider
    317      * object is returned.  Note that the specified Provider object
    318      * does not have to be registered in the provider list.
    319      *
    320      * @param algorithm the standard name of the requested key algorithm.
    321      * See the KeyGenerator section in the <a href=
    322      * "{@docRoot}openjdk-redirect.html?v=8&path=/technotes/guides/security/StandardNames.html#KeyGenerator">
    323      * Java Cryptography Architecture Standard Algorithm Name Documentation</a>
    324      * for information about standard algorithm names.
    325      *
    326      * @param provider the provider.
    327      *
    328      * @return the new <code>KeyGenerator</code> object.
    329      *
    330      * @exception NullPointerException if the specified algorithm is null.
    331      *
    332      * @exception NoSuchAlgorithmException if a KeyGeneratorSpi
    333      *          implementation for the specified algorithm is not available
    334      *          from the specified Provider object.
    335      *
    336      * @exception IllegalArgumentException if the <code>provider</code>
    337      *          is null.
    338      *
    339      * @see java.security.Provider
    340      */
    341     public static final KeyGenerator getInstance(String algorithm,
    342             Provider provider) throws NoSuchAlgorithmException {
    343         Instance instance = JceSecurity.getInstance("KeyGenerator",
    344                 KeyGeneratorSpi.class, algorithm, provider);
    345         return new KeyGenerator((KeyGeneratorSpi)instance.impl,
    346                 instance.provider, algorithm);
    347     }
    348 
    349     /**
    350      * Returns the provider of this <code>KeyGenerator</code> object.
    351      *
    352      * @return the provider of this <code>KeyGenerator</code> object
    353      */
    354     public final Provider getProvider() {
    355         synchronized (lock) {
    356             disableFailover();
    357             return provider;
    358         }
    359     }
    360 
    361     /**
    362      * Update the active spi of this class and return the next
    363      * implementation for failover. If no more implemenations are
    364      * available, this method returns null. However, the active spi of
    365      * this class is never set to null.
    366      */
    367     private KeyGeneratorSpi nextSpi(KeyGeneratorSpi oldSpi,
    368             boolean reinit) {
    369         synchronized (lock) {
    370             // somebody else did a failover concurrently
    371             // try that spi now
    372             if ((oldSpi != null) && (oldSpi != spi)) {
    373                 return spi;
    374             }
    375             if (serviceIterator == null) {
    376                 return null;
    377             }
    378             while (serviceIterator.hasNext()) {
    379                 Service s = (Service)serviceIterator.next();
    380                 if (JceSecurity.canUseProvider(s.getProvider()) == false) {
    381                     continue;
    382                 }
    383                 try {
    384                     Object inst = s.newInstance(null);
    385                     // ignore non-spis
    386                     if (inst instanceof KeyGeneratorSpi == false) {
    387                         continue;
    388                     }
    389                     KeyGeneratorSpi spi = (KeyGeneratorSpi)inst;
    390                     if (reinit) {
    391                         if (initType == I_SIZE) {
    392                             spi.engineInit(initKeySize, initRandom);
    393                         } else if (initType == I_PARAMS) {
    394                             spi.engineInit(initParams, initRandom);
    395                         } else if (initType == I_RANDOM) {
    396                             spi.engineInit(initRandom);
    397                         } else if (initType != I_NONE) {
    398                             throw new AssertionError
    399                                 ("KeyGenerator initType: " + initType);
    400                         }
    401                     }
    402                     provider = s.getProvider();
    403                     this.spi = spi;
    404                     return spi;
    405                 } catch (Exception e) {
    406                     // ignore
    407                 }
    408             }
    409             disableFailover();
    410             return null;
    411         }
    412     }
    413 
    414     void disableFailover() {
    415         serviceIterator = null;
    416         initType = 0;
    417         initParams = null;
    418         initRandom = null;
    419     }
    420 
    421     /**
    422      * Initializes this key generator.
    423      *
    424      * @param random the source of randomness for this generator
    425      */
    426     public final void init(SecureRandom random) {
    427         if (serviceIterator == null) {
    428             spi.engineInit(random);
    429             return;
    430         }
    431         RuntimeException failure = null;
    432         KeyGeneratorSpi mySpi = spi;
    433         do {
    434             try {
    435                 mySpi.engineInit(random);
    436                 initType = I_RANDOM;
    437                 initKeySize = 0;
    438                 initParams = null;
    439                 initRandom = random;
    440                 return;
    441             } catch (RuntimeException e) {
    442                 if (failure == null) {
    443                     failure = e;
    444                 }
    445                 mySpi = nextSpi(mySpi, false);
    446             }
    447         } while (mySpi != null);
    448         throw failure;
    449     }
    450 
    451     /**
    452      * Initializes this key generator with the specified parameter set.
    453      *
    454      * <p> If this key generator requires any random bytes, it will get them
    455      * using the
    456      * {@link SecureRandom <code>SecureRandom</code>}
    457      * implementation of the highest-priority installed
    458      * provider as the source of randomness.
    459      * (If none of the installed providers supply an implementation of
    460      * SecureRandom, a system-provided source of randomness will be used.)
    461      *
    462      * @param params the key generation parameters
    463      *
    464      * @exception InvalidAlgorithmParameterException if the given parameters
    465      * are inappropriate for this key generator
    466      */
    467     public final void init(AlgorithmParameterSpec params)
    468         throws InvalidAlgorithmParameterException
    469     {
    470         init(params, JceSecurity.RANDOM);
    471     }
    472 
    473     /**
    474      * Initializes this key generator with the specified parameter
    475      * set and a user-provided source of randomness.
    476      *
    477      * @param params the key generation parameters
    478      * @param random the source of randomness for this key generator
    479      *
    480      * @exception InvalidAlgorithmParameterException if <code>params</code> is
    481      * inappropriate for this key generator
    482      */
    483     public final void init(AlgorithmParameterSpec params, SecureRandom random)
    484         throws InvalidAlgorithmParameterException
    485     {
    486         if (serviceIterator == null) {
    487             spi.engineInit(params, random);
    488             return;
    489         }
    490         Exception failure = null;
    491         KeyGeneratorSpi mySpi = spi;
    492         do {
    493             try {
    494                 mySpi.engineInit(params, random);
    495                 initType = I_PARAMS;
    496                 initKeySize = 0;
    497                 initParams = params;
    498                 initRandom = random;
    499                 return;
    500             } catch (Exception e) {
    501                 if (failure == null) {
    502                     failure = e;
    503                 }
    504                 mySpi = nextSpi(mySpi, false);
    505             }
    506         } while (mySpi != null);
    507         if (failure instanceof InvalidAlgorithmParameterException) {
    508             throw (InvalidAlgorithmParameterException)failure;
    509         }
    510         if (failure instanceof RuntimeException) {
    511             throw (RuntimeException)failure;
    512         }
    513         throw new InvalidAlgorithmParameterException("init() failed", failure);
    514     }
    515 
    516     /**
    517      * Initializes this key generator for a certain keysize.
    518      *
    519      * <p> If this key generator requires any random bytes, it will get them
    520      * using the
    521      * {@link SecureRandom <code>SecureRandom</code>}
    522      * implementation of the highest-priority installed
    523      * provider as the source of randomness.
    524      * (If none of the installed providers supply an implementation of
    525      * SecureRandom, a system-provided source of randomness will be used.)
    526      *
    527      * @param keysize the keysize. This is an algorithm-specific metric,
    528      * specified in number of bits.
    529      *
    530      * @exception InvalidParameterException if the keysize is wrong or not
    531      * supported.
    532      */
    533     public final void init(int keysize) {
    534         init(keysize, JceSecurity.RANDOM);
    535     }
    536 
    537     /**
    538      * Initializes this key generator for a certain keysize, using a
    539      * user-provided source of randomness.
    540      *
    541      * @param keysize the keysize. This is an algorithm-specific metric,
    542      * specified in number of bits.
    543      * @param random the source of randomness for this key generator
    544      *
    545      * @exception InvalidParameterException if the keysize is wrong or not
    546      * supported.
    547      */
    548     public final void init(int keysize, SecureRandom random) {
    549         if (serviceIterator == null) {
    550             spi.engineInit(keysize, random);
    551             return;
    552         }
    553         RuntimeException failure = null;
    554         KeyGeneratorSpi mySpi = spi;
    555         do {
    556             try {
    557                 mySpi.engineInit(keysize, random);
    558                 initType = I_SIZE;
    559                 initKeySize = keysize;
    560                 initParams = null;
    561                 initRandom = random;
    562                 return;
    563             } catch (RuntimeException e) {
    564                 if (failure == null) {
    565                     failure = e;
    566                 }
    567                 mySpi = nextSpi(mySpi, false);
    568             }
    569         } while (mySpi != null);
    570         throw failure;
    571     }
    572 
    573     /**
    574      * Generates a secret key.
    575      *
    576      * @return the new key
    577      */
    578     public final SecretKey generateKey() {
    579         if (serviceIterator == null) {
    580             return spi.engineGenerateKey();
    581         }
    582         RuntimeException failure = null;
    583         KeyGeneratorSpi mySpi = spi;
    584         do {
    585             try {
    586                 return mySpi.engineGenerateKey();
    587             } catch (RuntimeException e) {
    588                 if (failure == null) {
    589                     failure = e;
    590                 }
    591                 mySpi = nextSpi(mySpi, true);
    592             }
    593         } while (mySpi != null);
    594         throw failure;
    595    }
    596 }
    597