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