1 /*
   2  * Copyright (c) 1999, 2010, 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      */
  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      */
  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}/../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      */
 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}/../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      */
 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}/../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      */
 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      */
 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      */
 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      */
 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      */
 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      */
 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      */
 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      */
 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      */
 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      */
 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      */
 482     protected void finalize() {
 483         keyStored = null;
 484         // Are there anything else we could do?
 485     }
 486 }