1 /*
2  * Copyright (c) 1999, 2013, 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.security.AlgorithmParameters;
29 import java.security.Provider;
30 import java.security.Key;
31 import java.security.Security;
32 import java.security.NoSuchAlgorithmException;
33 import java.security.NoSuchProviderException;
34 import java.security.InvalidKeyException;
35 import java.security.InvalidAlgorithmParameterException;
36 import java.security.spec.AlgorithmParameterSpec;
37 
38 import sun.security.jca.GetInstance.Instance;
39 
40 /**
41  * This class provides the functionality of an exemption mechanism, examples
42  * of which are <i>key recovery</i>, <i>key weakening</i>, and
43  * <i>key escrow</i>.
44  *
45  * <p>Applications or applets that use an exemption mechanism may be granted
46  * stronger encryption capabilities than those which don't.
47  *
48  * @since 1.4
49  */
50 
51 public class ExemptionMechanism {
52 
53     // The provider
54     private Provider provider;
55 
56     // The provider implementation (delegate)
57     private ExemptionMechanismSpi exmechSpi;
58 
59     // The name of the exemption mechanism.
60     private String mechanism;
61 
62     // Flag which indicates whether this ExemptionMechanism
63     // result is generated successfully.
64     private boolean done = false;
65 
66     // State information
67     private boolean initialized = false;
68 
69     // Store away the key at init() time for later comparison.
70     private Key keyStored = null;
71 
72     /**
73      * Creates a ExemptionMechanism object.
74      *
75      * @param exmechSpi the delegate
76      * @param provider the provider
77      * @param mechanism the exemption mechanism
78      */
ExemptionMechanism(ExemptionMechanismSpi exmechSpi, Provider provider, String mechanism)79     protected ExemptionMechanism(ExemptionMechanismSpi exmechSpi,
80                                  Provider provider,
81                                  String mechanism) {
82         this.exmechSpi = exmechSpi;
83         this.provider = provider;
84         this.mechanism = mechanism;
85     }
86 
87     /**
88      * Returns the exemption mechanism name of this
89      * <code>ExemptionMechanism</code> object.
90      *
91      * <p>This is the same name that was specified in one of the
92      * <code>getInstance</code> calls that created this
93      * <code>ExemptionMechanism</code> object.
94      *
95      * @return the exemption mechanism name of this
96      * <code>ExemptionMechanism</code> object.
97      */
getName()98     public final String getName() {
99         return this.mechanism;
100     }
101 
102     /**
103      * Returns an <code>ExemptionMechanism</code> object that implements the
104      * specified exemption mechanism algorithm.
105      *
106      * <p> This method traverses the list of registered security Providers,
107      * starting with the most preferred Provider.
108      * A new ExemptionMechanism object encapsulating the
109      * ExemptionMechanismSpi implementation from the first
110      * Provider that supports the specified algorithm is returned.
111      *
112      * <p> Note that the list of registered providers may be retrieved via
113      * the {@link Security#getProviders() Security.getProviders()} method.
114      *
115      * @param algorithm the standard name of the requested exemption
116      * mechanism.
117      * See the ExemptionMechanism section in the
118      * <a href=
119      *   "{@docRoot}openjdk-redirect.html?v=8&path=/technotes/guides/security/StandardNames.html#Exemption">
120      * Java Cryptography Architecture Standard Algorithm Name Documentation</a>
121      * for information about standard exemption mechanism names.
122      *
123      * @return the new <code>ExemptionMechanism</code> object.
124      *
125      * @exception NullPointerException if <code>algorithm</code>
126      *          is null.
127      *
128      * @exception NoSuchAlgorithmException if no Provider supports an
129      *          ExemptionMechanismSpi implementation for the
130      *          specified algorithm.
131      *
132      * @see java.security.Provider
133      */
getInstance(String algorithm)134     public static final ExemptionMechanism getInstance(String algorithm)
135             throws NoSuchAlgorithmException {
136         Instance instance = JceSecurity.getInstance("ExemptionMechanism",
137                 ExemptionMechanismSpi.class, algorithm);
138         return new ExemptionMechanism((ExemptionMechanismSpi)instance.impl,
139                 instance.provider, algorithm);
140     }
141 
142 
143     /**
144      * Returns an <code>ExemptionMechanism</code> object that implements the
145      * specified exemption mechanism algorithm.
146      *
147      * <p> A new ExemptionMechanism object encapsulating the
148      * ExemptionMechanismSpi implementation from the specified provider
149      * is returned.  The specified provider must be registered
150      * in the security provider list.
151      *
152      * <p> Note that the list of registered providers may be retrieved via
153      * the {@link Security#getProviders() Security.getProviders()} method.
154 
155      * @param algorithm the standard name of the requested exemption mechanism.
156      * See the ExemptionMechanism section in the
157      * <a href=
158      *   "{@docRoot}openjdk-redirect.html?v=8&path=/technotes/guides/security/StandardNames.html#Exemption">
159      * Java Cryptography Architecture Standard Algorithm Name Documentation</a>
160      * for information about standard exemption mechanism names.
161      *
162      * @param provider the name of the provider.
163      *
164      * @return the new <code>ExemptionMechanism</code> object.
165      *
166      * @exception NullPointerException if <code>algorithm</code>
167      *          is null.
168      *
169      * @exception NoSuchAlgorithmException if an ExemptionMechanismSpi
170      *          implementation for the specified algorithm is not
171      *          available from the specified provider.
172      *
173      * @exception NoSuchProviderException if the specified provider is not
174      *          registered in the security provider list.
175      *
176      * @exception IllegalArgumentException if the <code>provider</code>
177      *          is null or empty.
178      *
179      * @see java.security.Provider
180      */
getInstance(String algorithm, String provider)181     public static final ExemptionMechanism getInstance(String algorithm,
182             String provider) throws NoSuchAlgorithmException,
183             NoSuchProviderException {
184         Instance instance = JceSecurity.getInstance("ExemptionMechanism",
185                 ExemptionMechanismSpi.class, algorithm, provider);
186         return new ExemptionMechanism((ExemptionMechanismSpi)instance.impl,
187                 instance.provider, algorithm);
188     }
189 
190     /**
191      * Returns an <code>ExemptionMechanism</code> object that implements the
192      * specified exemption mechanism algorithm.
193      *
194      * <p> A new ExemptionMechanism object encapsulating the
195      * ExemptionMechanismSpi implementation from the specified Provider
196      * object is returned.  Note that the specified Provider object
197      * does not have to be registered in the provider list.
198      *
199      * @param algorithm the standard name of the requested exemption mechanism.
200      * See the ExemptionMechanism section in the
201      * <a href=
202      *   "{@docRoot}openjdk-redirect.html?v=8&path=/technotes/guides/security/StandardNames.html#Exemption">
203      * Java Cryptography Architecture Standard Algorithm Name Documentation</a>
204      * for information about standard exemption mechanism names.
205      *
206      * @param provider the provider.
207      *
208      * @return the new <code>ExemptionMechanism</code> object.
209      *
210      * @exception NullPointerException if <code>algorithm</code>
211      *          is null.
212      *
213      * @exception NoSuchAlgorithmException if an ExemptionMechanismSpi
214      *          implementation for the specified algorithm is not available
215      *          from the specified Provider object.
216      *
217      * @exception IllegalArgumentException if the <code>provider</code>
218      *          is null.
219      *
220      * @see java.security.Provider
221      */
getInstance(String algorithm, Provider provider)222     public static final ExemptionMechanism getInstance(String algorithm,
223             Provider provider) throws NoSuchAlgorithmException {
224         Instance instance = JceSecurity.getInstance("ExemptionMechanism",
225                 ExemptionMechanismSpi.class, algorithm, provider);
226         return new ExemptionMechanism((ExemptionMechanismSpi)instance.impl,
227                 instance.provider, algorithm);
228     }
229 
230     /**
231      * Returns the provider of this <code>ExemptionMechanism</code> object.
232      *
233      * @return the provider of this <code>ExemptionMechanism</code> object.
234      */
getProvider()235     public final Provider getProvider() {
236         return this.provider;
237     }
238 
239     /**
240      * Returns whether the result blob has been generated successfully by this
241      * exemption mechanism.
242      *
243      * <p>The method also makes sure that the key passed in is the same as
244      * the one this exemption mechanism used in initializing and generating
245      * phases.
246      *
247      * @param key the key the crypto is going to use.
248      *
249      * @return whether the result blob of the same key has been generated
250      * successfully by this exemption mechanism; false if <code>key</code>
251      * is null.
252      *
253      * @exception ExemptionMechanismException if problem(s) encountered
254      * while determining whether the result blob has been generated successfully
255      * by this exemption mechanism object.
256      */
isCryptoAllowed(Key key)257     public final boolean isCryptoAllowed(Key key)
258             throws ExemptionMechanismException {
259         boolean ret = false;
260         if (done && (key != null)) {
261             // Check if the key passed in is the same as the one
262             // this exemption mechanism used.
263             ret = keyStored.equals(key);
264         }
265         return ret;
266      }
267 
268     /**
269      * Returns the length in bytes that an output buffer would need to be in
270      * order to hold the result of the next
271      * {@link #genExemptionBlob(byte[]) genExemptionBlob}
272      * operation, given the input length <code>inputLen</code> (in bytes).
273      *
274      * <p>The actual output length of the next
275      * {@link #genExemptionBlob(byte[]) genExemptionBlob}
276      * call may be smaller than the length returned by this method.
277      *
278      * @param inputLen the input length (in bytes)
279      *
280      * @return the required output buffer size (in bytes)
281      *
282      * @exception IllegalStateException if this exemption mechanism is in a
283      * wrong state (e.g., has not yet been initialized)
284      */
getOutputSize(int inputLen)285     public final int getOutputSize(int inputLen) throws IllegalStateException {
286         if (!initialized) {
287             throw new IllegalStateException(
288                 "ExemptionMechanism not initialized");
289         }
290         if (inputLen < 0) {
291             throw new IllegalArgumentException(
292                 "Input size must be equal to " + "or greater than zero");
293         }
294         return exmechSpi.engineGetOutputSize(inputLen);
295     }
296 
297     /**
298      * Initializes this exemption mechanism with a key.
299      *
300      * <p>If this exemption mechanism requires any algorithm parameters
301      * that cannot be derived from the given <code>key</code>, the
302      * underlying exemption mechanism implementation is supposed to
303      * generate the required parameters itself (using provider-specific
304      * default values); in the case that algorithm parameters must be
305      * specified by the caller, an <code>InvalidKeyException</code> is raised.
306      *
307      * @param key the key for this exemption mechanism
308      *
309      * @exception InvalidKeyException if the given key is inappropriate for
310      * this exemption mechanism.
311      * @exception ExemptionMechanismException if problem(s) encountered in the
312      * process of initializing.
313      */
init(Key key)314     public final void init(Key key)
315             throws InvalidKeyException, ExemptionMechanismException {
316         done = false;
317         initialized = false;
318 
319         keyStored = key;
320         exmechSpi.engineInit(key);
321         initialized = true;
322     }
323 
324     /**
325      * Initializes this exemption mechanism with a key and a set of algorithm
326      * parameters.
327      *
328      * <p>If this exemption mechanism requires any algorithm parameters
329      * and <code>params</code> is null, the underlying exemption
330      * mechanism implementation is supposed to generate the required
331      * parameters itself (using provider-specific default values); in the case
332      * that algorithm parameters must be specified by the caller, an
333      * <code>InvalidAlgorithmParameterException</code> is raised.
334      *
335      * @param key the key for this exemption mechanism
336      * @param params the algorithm parameters
337      *
338      * @exception InvalidKeyException if the given key is inappropriate for
339      * this exemption mechanism.
340      * @exception InvalidAlgorithmParameterException if the given algorithm
341      * parameters are inappropriate for this exemption mechanism.
342      * @exception ExemptionMechanismException if problem(s) encountered in the
343      * process of initializing.
344      */
init(Key key, AlgorithmParameterSpec params)345     public final void init(Key key, AlgorithmParameterSpec params)
346             throws InvalidKeyException, InvalidAlgorithmParameterException,
347             ExemptionMechanismException {
348         done = false;
349         initialized = false;
350 
351         keyStored = key;
352         exmechSpi.engineInit(key, params);
353         initialized = true;
354     }
355 
356     /**
357      * Initializes this exemption mechanism with a key and a set of algorithm
358      * parameters.
359      *
360      * <p>If this exemption mechanism requires any algorithm parameters
361      * and <code>params</code> is null, the underlying exemption mechanism
362      * implementation is supposed to generate the required parameters itself
363      * (using provider-specific default values); in the case that algorithm
364      * parameters must be specified by the caller, an
365      * <code>InvalidAlgorithmParameterException</code> is raised.
366      *
367      * @param key the key for this exemption mechanism
368      * @param params the algorithm parameters
369      *
370      * @exception InvalidKeyException if the given key is inappropriate for
371      * this exemption mechanism.
372      * @exception InvalidAlgorithmParameterException if the given algorithm
373      * parameters are inappropriate for this exemption mechanism.
374      * @exception ExemptionMechanismException if problem(s) encountered in the
375      * process of initializing.
376      */
init(Key key, AlgorithmParameters params)377     public final void init(Key key, AlgorithmParameters params)
378             throws InvalidKeyException, InvalidAlgorithmParameterException,
379             ExemptionMechanismException {
380         done = false;
381         initialized = false;
382 
383         keyStored = key;
384         exmechSpi.engineInit(key, params);
385         initialized = true;
386     }
387 
388     /**
389      * Generates the exemption mechanism key blob.
390      *
391      * @return the new buffer with the result key blob.
392      *
393      * @exception IllegalStateException if this exemption mechanism is in
394      * a wrong state (e.g., has not been initialized).
395      * @exception ExemptionMechanismException if problem(s) encountered in the
396      * process of generating.
397      */
genExemptionBlob()398     public final byte[] genExemptionBlob() throws IllegalStateException,
399             ExemptionMechanismException {
400         if (!initialized) {
401             throw new IllegalStateException(
402                 "ExemptionMechanism not initialized");
403         }
404         byte[] blob = exmechSpi.engineGenExemptionBlob();
405         done = true;
406         return blob;
407     }
408 
409     /**
410      * Generates the exemption mechanism key blob, and stores the result in
411      * the <code>output</code> buffer.
412      *
413      * <p>If the <code>output</code> buffer is too small to hold the result,
414      * a <code>ShortBufferException</code> is thrown. In this case, repeat this
415      * call with a larger output buffer. Use
416      * {@link #getOutputSize(int) getOutputSize} to determine how big
417      * the output buffer should be.
418      *
419      * @param output the buffer for the result
420      *
421      * @return the number of bytes stored in <code>output</code>
422      *
423      * @exception IllegalStateException if this exemption mechanism is in
424      * a wrong state (e.g., has not been initialized).
425      * @exception ShortBufferException if the given output buffer is too small
426      * to hold the result.
427      * @exception ExemptionMechanismException if problem(s) encountered in the
428      * process of generating.
429      */
genExemptionBlob(byte[] output)430     public final int genExemptionBlob(byte[] output)
431             throws IllegalStateException, ShortBufferException,
432             ExemptionMechanismException {
433         if (!initialized) {
434             throw new IllegalStateException
435             ("ExemptionMechanism not initialized");
436         }
437         int n = exmechSpi.engineGenExemptionBlob(output, 0);
438         done = true;
439         return n;
440     }
441 
442     /**
443      * Generates the exemption mechanism key blob, and stores the result in
444      * the <code>output</code> buffer, starting at <code>outputOffset</code>
445      * inclusive.
446      *
447      * <p>If the <code>output</code> buffer is too small to hold the result,
448      * a <code>ShortBufferException</code> is thrown. In this case, repeat this
449      * call with a larger output buffer. Use
450      * {@link #getOutputSize(int) getOutputSize} to determine how big
451      * the output buffer should be.
452      *
453      * @param output the buffer for the result
454      * @param outputOffset the offset in <code>output</code> where the result
455      * is stored
456      *
457      * @return the number of bytes stored in <code>output</code>
458      *
459      * @exception IllegalStateException if this exemption mechanism is in
460      * a wrong state (e.g., has not been initialized).
461      * @exception ShortBufferException if the given output buffer is too small
462      * to hold the result.
463      * @exception ExemptionMechanismException if problem(s) encountered in the
464      * process of generating.
465      */
genExemptionBlob(byte[] output, int outputOffset)466     public final int genExemptionBlob(byte[] output, int outputOffset)
467             throws IllegalStateException, ShortBufferException,
468             ExemptionMechanismException {
469         if (!initialized) {
470             throw new IllegalStateException
471             ("ExemptionMechanism not initialized");
472         }
473         int n = exmechSpi.engineGenExemptionBlob(output, outputOffset);
474         done = true;
475         return n;
476     }
477 
478     /**
479      * Ensures that the key stored away by this ExemptionMechanism
480      * object will be wiped out when there are no more references to it.
481      */
finalize()482     protected void finalize() {
483         keyStored = null;
484         // Are there anything else we could do?
485     }
486 }
487