1 /*
2  * Copyright (c) 1997, 2017, 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 java.security;
27 
28 import dalvik.annotation.compat.VersionCodes;
29 import dalvik.system.VMRuntime;
30 
31 import java.io.*;
32 import java.security.spec.AlgorithmParameterSpec;
33 import java.security.spec.InvalidParameterSpecException;
34 import java.util.Objects;
35 
36 import sun.security.jca.Providers;
37 
38 /**
39  * This class is used as an opaque representation of cryptographic parameters.
40  *
41  * <p>An {@code AlgorithmParameters} object for managing the parameters
42  * for a particular algorithm can be obtained by
43  * calling one of the {@code getInstance} factory methods
44  * (static methods that return instances of a given class).
45  *
46  * <p>Once an {@code AlgorithmParameters} object is obtained, it must be
47  * initialized via a call to {@code init}, using an appropriate parameter
48  * specification or parameter encoding.
49  *
50  * <p>A transparent parameter specification is obtained from an
51  * {@code AlgorithmParameters} object via a call to
52  * {@code getParameterSpec}, and a byte encoding of the parameters is
53  * obtained via a call to {@code getEncoded}.
54  *
55  * <p> Android provides the following <code>AlgorithmParameters</code> algorithms:
56  * <table>
57  *   <thead>
58  *     <tr>
59  *       <th>Algorithm</th>
60  *       <th>Supported API Levels</th>
61  *     </tr>
62  *   </thead>
63  *   <tbody>
64  *     <tr>
65  *       <td>AES</td>
66  *       <td>1+</td>
67  *     </tr>
68  *     <tr>
69  *       <td>BLOWFISH</td>
70  *       <td>10+</td>
71  *     </tr>
72  *     <tr>
73  *       <td>ChaCha20</td>
74  *       <td>28+</td>
75  *     </tr>
76  *     <tr>
77  *       <td>DES</td>
78  *       <td>1+</td>
79  *     </tr>
80  *     <tr>
81  *       <td>DESede</td>
82  *       <td>1+</td>
83  *     </tr>
84  *     <tr>
85  *       <td>DH</td>
86  *       <td>1+</td>
87  *     </tr>
88  *     <tr>
89  *       <td>DSA</td>
90  *       <td>1+</td>
91  *     </tr>
92  *     <tr>
93  *       <td>EC</td>
94  *       <td>26+</td>
95  *     </tr>
96  *     <tr>
97  *       <td>GCM</td>
98  *       <td>22+</td>
99  *     </tr>
100  *     <tr class="deprecated">
101  *       <td>IES</td>
102  *       <td>1-8</td>
103  *     </tr>
104  *     <tr>
105  *       <td>OAEP</td>
106  *       <td>1+</td>
107  *     </tr>
108  *     <tr>
109  *       <td>PBEwithHmacSHA1AndAES_128</td>
110  *       <td>26+</td>
111  *     </tr>
112  *     <tr>
113  *       <td>PBEwithHmacSHA1AndAES_256</td>
114  *       <td>26+</td>
115  *     </tr>
116  *     <tr>
117  *       <td>PBEwithHmacSHA224AndAES_128</td>
118  *       <td>26+</td>
119  *     </tr>
120  *     <tr>
121  *       <td>PBEwithHmacSHA224AndAES_256</td>
122  *       <td>26+</td>
123  *     </tr>
124  *     <tr>
125  *       <td>PBEwithHmacSHA256AndAES_128</td>
126  *       <td>26+</td>
127  *     </tr>
128  *     <tr>
129  *       <td>PBEwithHmacSHA256AndAES_256</td>
130  *       <td>26+</td>
131  *     </tr>
132  *     <tr>
133  *       <td>PBEwithHmacSHA384AndAES_128</td>
134  *       <td>26+</td>
135  *     </tr>
136  *     <tr>
137  *       <td>PBEwithHmacSHA384AndAES_256</td>
138  *       <td>26+</td>
139  *     </tr>
140  *     <tr>
141  *       <td>PBEwithHmacSHA512AndAES_128</td>
142  *       <td>26+</td>
143  *     </tr>
144  *     <tr>
145  *       <td>PBEwithHmacSHA512AndAES_256</td>
146  *       <td>26+</td>
147  *     </tr>
148  *     <tr>
149  *       <td>PKCS12PBE</td>
150  *       <td>1+</td>
151  *     </tr>
152  *     <tr>
153  *       <td>PSS</td>
154  *       <td>1-8,24+</td>
155  *     </tr>
156  *   </tbody>
157  * </table>
158  *
159  * @author Jan Luehe
160  *
161  *
162  * @see java.security.spec.AlgorithmParameterSpec
163  * @see java.security.spec.DSAParameterSpec
164  * @see KeyPairGenerator
165  *
166  * @since 1.2
167  */
168 
169 public class AlgorithmParameters {
170 
171     // The provider
172     private Provider provider;
173 
174     // The provider implementation (delegate)
175     private AlgorithmParametersSpi paramSpi;
176 
177     // The algorithm
178     private String algorithm;
179 
180     // Has this object been initialized?
181     private boolean initialized = false;
182 
183     /**
184      * Creates an AlgorithmParameters object.
185      *
186      * @param paramSpi the delegate
187      * @param provider the provider
188      * @param algorithm the algorithm
189      */
AlgorithmParameters(AlgorithmParametersSpi paramSpi, Provider provider, String algorithm)190     protected AlgorithmParameters(AlgorithmParametersSpi paramSpi,
191                                   Provider provider, String algorithm)
192     {
193         this.paramSpi = paramSpi;
194         this.provider = provider;
195         this.algorithm = algorithm;
196     }
197 
198     /**
199      * Returns the name of the algorithm associated with this parameter object.
200      *
201      * @return the algorithm name.
202      */
getAlgorithm()203     public final String getAlgorithm() {
204         return this.algorithm;
205     }
206 
207     // Android-changed: javadoc to throw on Android 14 or above.
208     /**
209      * Returns a parameter object for the specified algorithm.
210      *
211      * <p> This method traverses the list of registered security Providers,
212      * starting with the most preferred Provider.
213      * A new AlgorithmParameters object encapsulating the
214      * AlgorithmParametersSpi implementation from the first
215      * Provider that supports the specified algorithm is returned.
216      *
217      * <p> Note that the list of registered providers may be retrieved via
218      * the {@link Security#getProviders() Security.getProviders()} method.
219      *
220      * <p> The returned parameter object must be initialized via a call to
221      * {@code init}, using an appropriate parameter specification or
222      * parameter encoding.
223      *
224      * @param algorithm the name of the algorithm requested.
225      *
226      * @return the new parameter object
227      *
228      * @throws NoSuchAlgorithmException if no {@code Provider} supports an
229      *         {@code AlgorithmParametersSpi} implementation for the
230      *         specified algorithm
231      *
232      * @throws NullPointerException if {@code algorithm} is {@code null} on Android 14 or above
233      *
234      * @see Provider
235      */
getInstance(String algorithm)236     public static AlgorithmParameters getInstance(String algorithm)
237     throws NoSuchAlgorithmException {
238         // Android-changed: To be compat with the older Android, don't throw NPE on Android 13-.
239         // Objects.requireNonNull(algorithm, "null algorithm name");
240         if (VMRuntime.getSdkVersion() >= VersionCodes.UPSIDE_DOWN_CAKE) {
241             Objects.requireNonNull(algorithm, "null algorithm name");
242         }
243         try {
244             Object[] objs = Security.getImpl(algorithm, "AlgorithmParameters",
245                                              (String)null);
246             return new AlgorithmParameters((AlgorithmParametersSpi)objs[0],
247                                            (Provider)objs[1],
248                                            algorithm);
249         } catch(NoSuchProviderException e) {
250             throw new NoSuchAlgorithmException(algorithm + " not found");
251         }
252     }
253 
254     // Android-changed: javadoc to throw on Android 14 or above.
255     /**
256      * Returns a parameter object for the specified algorithm.
257      *
258      * <p> A new AlgorithmParameters object encapsulating the
259      * AlgorithmParametersSpi implementation from the specified provider
260      * is returned.  The specified provider must be registered
261      * in the security provider list.
262      *
263      * <p> Note that the list of registered providers may be retrieved via
264      * the {@link Security#getProviders() Security.getProviders()} method.
265      *
266      * <p>The returned parameter object must be initialized via a call to
267      * {@code init}, using an appropriate parameter specification or
268      * parameter encoding.
269      *
270      * @param algorithm the name of the algorithm requested.
271      *
272      * @param provider the name of the provider.
273      *
274      * @return the new parameter object
275      *
276      * @throws IllegalArgumentException if the provider name is {@code null}
277      *         or empty
278      *
279      * @throws NoSuchAlgorithmException if an {@code AlgorithmParametersSpi}
280      *         implementation for the specified algorithm is not
281      *         available from the specified provider
282      *
283      * @throws NoSuchProviderException if the specified provider is not
284      *         registered in the security provider list
285      *
286      * @throws NullPointerException if {@code algorithm} is {@code null} on Android 14 or above
287      *
288      * @see Provider
289      */
getInstance(String algorithm, String provider)290     public static AlgorithmParameters getInstance(String algorithm,
291                                                   String provider)
292         throws NoSuchAlgorithmException, NoSuchProviderException
293     {
294         // Android-changed: To be compat with the older Android, don't throw NPE on Android 13-.
295         // Objects.requireNonNull(algorithm, "null algorithm name");
296         if (VMRuntime.getSdkVersion() >= VersionCodes.UPSIDE_DOWN_CAKE) {
297             Objects.requireNonNull(algorithm, "null algorithm name");
298         }
299         if (provider == null || provider.isEmpty())
300             throw new IllegalArgumentException("missing provider");
301         // Android-added: Check for Bouncy Castle deprecation
302         Providers.checkBouncyCastleDeprecation(provider, "AlgorithmParameters", algorithm);
303         Object[] objs = Security.getImpl(algorithm, "AlgorithmParameters",
304                                          provider);
305         return new AlgorithmParameters((AlgorithmParametersSpi)objs[0],
306                                        (Provider)objs[1],
307                                        algorithm);
308     }
309 
310     // Android-changed: javadoc to throw on Android 14 or above.
311     /**
312      * Returns a parameter object for the specified algorithm.
313      *
314      * <p> A new AlgorithmParameters object encapsulating the
315      * AlgorithmParametersSpi implementation from the specified Provider
316      * object is returned.  Note that the specified Provider object
317      * does not have to be registered in the provider list.
318      *
319      * <p>The returned parameter object must be initialized via a call to
320      * {@code init}, using an appropriate parameter specification or
321      * parameter encoding.
322      *
323      * @param algorithm the name of the algorithm requested.
324      *
325      * @param provider the name of the provider.
326      *
327      * @return the new parameter object
328      *
329      * @throws IllegalArgumentException if the provider is {@code null}
330      *
331      * @throws NoSuchAlgorithmException if an
332      *         {@code AlgorithmParameterGeneratorSpi}
333      *         implementation for the specified algorithm is not available
334      *         from the specified {@code Provider} object
335      *
336      * @throws NullPointerException if {@code algorithm} is {@code null} on Android 14 or above
337      *
338      * @see Provider
339      *
340      * @since 1.4
341      */
getInstance(String algorithm, Provider provider)342     public static AlgorithmParameters getInstance(String algorithm,
343                                                   Provider provider)
344         throws NoSuchAlgorithmException
345     {
346         // Android-changed: To be compat with the older Android, don't throw NPE on Android 13-.
347         // Objects.requireNonNull(algorithm, "null algorithm name");
348         if (VMRuntime.getSdkVersion() >= VersionCodes.UPSIDE_DOWN_CAKE) {
349             Objects.requireNonNull(algorithm, "null algorithm name");
350         }
351         if (provider == null)
352             throw new IllegalArgumentException("missing provider");
353         // Android-added: Check for Bouncy Castle deprecation
354         Providers.checkBouncyCastleDeprecation(provider, "AlgorithmParameters", algorithm);
355         Object[] objs = Security.getImpl(algorithm, "AlgorithmParameters",
356                                          provider);
357         return new AlgorithmParameters((AlgorithmParametersSpi)objs[0],
358                                        (Provider)objs[1],
359                                        algorithm);
360     }
361 
362     /**
363      * Returns the provider of this parameter object.
364      *
365      * @return the provider of this parameter object
366      */
getProvider()367     public final Provider getProvider() {
368         return this.provider;
369     }
370 
371     /**
372      * Initializes this parameter object using the parameters
373      * specified in {@code paramSpec}.
374      *
375      * @param paramSpec the parameter specification.
376      *
377      * @exception InvalidParameterSpecException if the given parameter
378      * specification is inappropriate for the initialization of this parameter
379      * object, or if this parameter object has already been initialized.
380      */
init(AlgorithmParameterSpec paramSpec)381     public final void init(AlgorithmParameterSpec paramSpec)
382         throws InvalidParameterSpecException
383     {
384         if (this.initialized)
385             throw new InvalidParameterSpecException("already initialized");
386         paramSpi.engineInit(paramSpec);
387         this.initialized = true;
388     }
389 
390     /**
391      * Imports the specified parameters and decodes them according to the
392      * primary decoding format for parameters. The primary decoding
393      * format for parameters is ASN.1, if an ASN.1 specification for this type
394      * of parameters exists.
395      *
396      * @param params the encoded parameters.
397      *
398      * @exception IOException on decoding errors, or if this parameter object
399      * has already been initialized.
400      */
init(byte[] params)401     public final void init(byte[] params) throws IOException {
402         if (this.initialized)
403             throw new IOException("already initialized");
404         paramSpi.engineInit(params);
405         this.initialized = true;
406     }
407 
408     /**
409      * Imports the parameters from {@code params} and decodes them
410      * according to the specified decoding scheme.
411      * If {@code format} is null, the
412      * primary decoding format for parameters is used. The primary decoding
413      * format is ASN.1, if an ASN.1 specification for these parameters
414      * exists.
415      *
416      * @param params the encoded parameters.
417      *
418      * @param format the name of the decoding scheme.
419      *
420      * @exception IOException on decoding errors, or if this parameter object
421      * has already been initialized.
422      */
init(byte[] params, String format)423     public final void init(byte[] params, String format) throws IOException {
424         if (this.initialized)
425             throw new IOException("already initialized");
426         paramSpi.engineInit(params, format);
427         this.initialized = true;
428     }
429 
430     /**
431      * Returns a (transparent) specification of this parameter object.
432      * {@code paramSpec} identifies the specification class in which
433      * the parameters should be returned. It could, for example, be
434      * {@code DSAParameterSpec.class}, to indicate that the
435      * parameters should be returned in an instance of the
436      * {@code DSAParameterSpec} class.
437      *
438      * @param <T> the type of the parameter specification to be returrned
439      * @param paramSpec the specification class in which
440      * the parameters should be returned.
441      *
442      * @return the parameter specification.
443      *
444      * @exception InvalidParameterSpecException if the requested parameter
445      * specification is inappropriate for this parameter object, or if this
446      * parameter object has not been initialized.
447      */
448     public final <T extends AlgorithmParameterSpec>
getParameterSpec(Class<T> paramSpec)449         T getParameterSpec(Class<T> paramSpec)
450         throws InvalidParameterSpecException
451     {
452         if (this.initialized == false) {
453             throw new InvalidParameterSpecException("not initialized");
454         }
455         return paramSpi.engineGetParameterSpec(paramSpec);
456     }
457 
458     /**
459      * Returns the parameters in their primary encoding format.
460      * The primary encoding format for parameters is ASN.1, if an ASN.1
461      * specification for this type of parameters exists.
462      *
463      * @return the parameters encoded using their primary encoding format.
464      *
465      * @exception IOException on encoding errors, or if this parameter object
466      * has not been initialized.
467      */
getEncoded()468     public final byte[] getEncoded() throws IOException
469     {
470         if (this.initialized == false) {
471             throw new IOException("not initialized");
472         }
473         return paramSpi.engineGetEncoded();
474     }
475 
476     /**
477      * Returns the parameters encoded in the specified scheme.
478      * If {@code format} is null, the
479      * primary encoding format for parameters is used. The primary encoding
480      * format is ASN.1, if an ASN.1 specification for these parameters
481      * exists.
482      *
483      * @param format the name of the encoding format.
484      *
485      * @return the parameters encoded using the specified encoding scheme.
486      *
487      * @exception IOException on encoding errors, or if this parameter object
488      * has not been initialized.
489      */
getEncoded(String format)490     public final byte[] getEncoded(String format) throws IOException
491     {
492         if (this.initialized == false) {
493             throw new IOException("not initialized");
494         }
495         return paramSpi.engineGetEncoded(format);
496     }
497 
498     /**
499      * Returns a formatted string describing the parameters.
500      *
501      * @return a formatted string describing the parameters, or null if this
502      * parameter object has not been initialized.
503      */
toString()504     public final String toString() {
505         if (this.initialized == false) {
506             return null;
507         }
508         return paramSpi.engineToString();
509     }
510 }
511