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