• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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      */
KeyGenerator(KeyGeneratorSpi keyGenSpi, Provider provider, String algorithm)200     protected KeyGenerator(KeyGeneratorSpi keyGenSpi, Provider provider,
201                            String algorithm) {
202         this.spi = keyGenSpi;
203         this.provider = provider;
204         this.algorithm = algorithm;
205     }
206 
KeyGenerator(String algorithm)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      */
getAlgorithm()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      */
getInstance(String algorithm)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      */
getInstance(String algorithm, String provider)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      */
getInstance(String algorithm, Provider provider)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      */
getProvider()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      */
nextSpi(KeyGeneratorSpi oldSpi, boolean reinit)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 
disableFailover()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      */
init(SecureRandom random)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      */
init(AlgorithmParameterSpec params)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      */
init(AlgorithmParameterSpec params, SecureRandom random)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      */
init(int keysize)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      */
init(int keysize, SecureRandom random)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      */
generateKey()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