1 /* 2 * Copyright (c) 1999, 2016, 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 * @implNote 116 * The JDK Reference Implementation additionally uses the 117 * {@code jdk.security.provider.preferred} 118 * {@link Security#getProperty(String) Security} property to determine 119 * the preferred provider order for the specified algorithm. This 120 * may be different than the order of providers returned by 121 * {@link Security#getProviders() Security.getProviders()}. 122 * 123 * @param algorithm the standard name of the requested exemption 124 * mechanism. 125 * See the ExemptionMechanism section in the 126 * <a href= 127 * "{@docRoot}/../technotes/guides/security/StandardNames.html#Exemption"> 128 * Java Cryptography Architecture Standard Algorithm Name Documentation</a> 129 * for information about standard exemption mechanism names. 130 * 131 * @return the new <code>ExemptionMechanism</code> object. 132 * 133 * @exception NullPointerException if <code>algorithm</code> 134 * is null. 135 * 136 * @exception NoSuchAlgorithmException if no Provider supports an 137 * ExemptionMechanismSpi implementation for the 138 * specified algorithm. 139 * 140 * @see java.security.Provider 141 */ 142 public static final ExemptionMechanism getInstance(String algorithm) 143 throws NoSuchAlgorithmException { 144 Instance instance = JceSecurity.getInstance("ExemptionMechanism", 145 ExemptionMechanismSpi.class, algorithm); 146 return new ExemptionMechanism((ExemptionMechanismSpi)instance.impl, 147 instance.provider, algorithm); 148 } 149 150 151 /** 152 * Returns an <code>ExemptionMechanism</code> object that implements the 153 * specified exemption mechanism algorithm. 154 * 155 * <p> A new ExemptionMechanism object encapsulating the 156 * ExemptionMechanismSpi implementation from the specified provider 157 * is returned. The specified provider must be registered 158 * in the security provider list. 159 * 160 * <p> Note that the list of registered providers may be retrieved via 161 * the {@link Security#getProviders() Security.getProviders()} method. 162 163 * @param algorithm the standard name of the requested exemption mechanism. 164 * See the ExemptionMechanism section in the 165 * <a href= 166 * "{@docRoot}/../technotes/guides/security/StandardNames.html#Exemption"> 167 * Java Cryptography Architecture Standard Algorithm Name Documentation</a> 168 * for information about standard exemption mechanism names. 169 * 170 * @param provider the name of the provider. 171 * 172 * @return the new <code>ExemptionMechanism</code> object. 173 * 174 * @exception NullPointerException if <code>algorithm</code> 175 * is null. 176 * 177 * @exception NoSuchAlgorithmException if an ExemptionMechanismSpi 178 * implementation for the specified algorithm is not 179 * available from the specified provider. 180 * 181 * @exception NoSuchProviderException if the specified provider is not 182 * registered in the security provider list. 183 * 184 * @exception IllegalArgumentException if the <code>provider</code> 185 * is null or empty. 186 * 187 * @see java.security.Provider 188 */ 189 public static final ExemptionMechanism getInstance(String algorithm, 190 String provider) throws NoSuchAlgorithmException, 191 NoSuchProviderException { 192 Instance instance = JceSecurity.getInstance("ExemptionMechanism", 193 ExemptionMechanismSpi.class, algorithm, provider); 194 return new ExemptionMechanism((ExemptionMechanismSpi)instance.impl, 195 instance.provider, algorithm); 196 } 197 198 /** 199 * Returns an <code>ExemptionMechanism</code> object that implements the 200 * specified exemption mechanism algorithm. 201 * 202 * <p> A new ExemptionMechanism object encapsulating the 203 * ExemptionMechanismSpi implementation from the specified Provider 204 * object is returned. Note that the specified Provider object 205 * does not have to be registered in the provider list. 206 * 207 * @param algorithm the standard name of the requested exemption mechanism. 208 * See the ExemptionMechanism section in the 209 * <a href= 210 * "{@docRoot}/../technotes/guides/security/StandardNames.html#Exemption"> 211 * Java Cryptography Architecture Standard Algorithm Name Documentation</a> 212 * for information about standard exemption mechanism names. 213 * 214 * @param provider the provider. 215 * 216 * @return the new <code>ExemptionMechanism</code> object. 217 * 218 * @exception NullPointerException if <code>algorithm</code> 219 * is null. 220 * 221 * @exception NoSuchAlgorithmException if an ExemptionMechanismSpi 222 * implementation for the specified algorithm is not available 223 * from the specified Provider object. 224 * 225 * @exception IllegalArgumentException if the <code>provider</code> 226 * is null. 227 * 228 * @see java.security.Provider 229 */ 230 public static final ExemptionMechanism getInstance(String algorithm, 231 Provider provider) throws NoSuchAlgorithmException { 232 Instance instance = JceSecurity.getInstance("ExemptionMechanism", 233 ExemptionMechanismSpi.class, algorithm, provider); 234 return new ExemptionMechanism((ExemptionMechanismSpi)instance.impl, 235 instance.provider, algorithm); 236 } 237 238 /** 239 * Returns the provider of this <code>ExemptionMechanism</code> object. 240 * 241 * @return the provider of this <code>ExemptionMechanism</code> object. 242 */ 243 public final Provider getProvider() { 244 return this.provider; 245 } 246 247 /** 248 * Returns whether the result blob has been generated successfully by this 249 * exemption mechanism. 250 * 251 * <p>The method also makes sure that the key passed in is the same as 252 * the one this exemption mechanism used in initializing and generating 253 * phases. 254 * 255 * @param key the key the crypto is going to use. 256 * 257 * @return whether the result blob of the same key has been generated 258 * successfully by this exemption mechanism; false if <code>key</code> 259 * is null. 260 * 261 * @exception ExemptionMechanismException if problem(s) encountered 262 * while determining whether the result blob has been generated successfully 263 * by this exemption mechanism object. 264 */ 265 public final boolean isCryptoAllowed(Key key) 266 throws ExemptionMechanismException { 267 boolean ret = false; 268 if (done && (key != null)) { 269 // Check if the key passed in is the same as the one 270 // this exemption mechanism used. 271 ret = keyStored.equals(key); 272 } 273 return ret; 274 } 275 276 /** 277 * Returns the length in bytes that an output buffer would need to be in 278 * order to hold the result of the next 279 * {@link #genExemptionBlob(byte[]) genExemptionBlob} 280 * operation, given the input length <code>inputLen</code> (in bytes). 281 * 282 * <p>The actual output length of the next 283 * {@link #genExemptionBlob(byte[]) genExemptionBlob} 284 * call may be smaller than the length returned by this method. 285 * 286 * @param inputLen the input length (in bytes) 287 * 288 * @return the required output buffer size (in bytes) 289 * 290 * @exception IllegalStateException if this exemption mechanism is in a 291 * wrong state (e.g., has not yet been initialized) 292 */ 293 public final int getOutputSize(int inputLen) throws IllegalStateException { 294 if (!initialized) { 295 throw new IllegalStateException( 296 "ExemptionMechanism not initialized"); 297 } 298 if (inputLen < 0) { 299 throw new IllegalArgumentException( 300 "Input size must be equal to " + "or greater than zero"); 301 } 302 return exmechSpi.engineGetOutputSize(inputLen); 303 } 304 305 /** 306 * Initializes this exemption mechanism with a key. 307 * 308 * <p>If this exemption mechanism requires any algorithm parameters 309 * that cannot be derived from the given <code>key</code>, the 310 * underlying exemption mechanism implementation is supposed to 311 * generate the required parameters itself (using provider-specific 312 * default values); in the case that algorithm parameters must be 313 * specified by the caller, an <code>InvalidKeyException</code> is raised. 314 * 315 * @param key the key for this exemption mechanism 316 * 317 * @exception InvalidKeyException if the given key is inappropriate for 318 * this exemption mechanism. 319 * @exception ExemptionMechanismException if problem(s) encountered in the 320 * process of initializing. 321 */ 322 public final void init(Key key) 323 throws InvalidKeyException, ExemptionMechanismException { 324 done = false; 325 initialized = false; 326 327 keyStored = key; 328 exmechSpi.engineInit(key); 329 initialized = true; 330 } 331 332 /** 333 * Initializes this exemption mechanism with a key and a set of algorithm 334 * parameters. 335 * 336 * <p>If this exemption mechanism requires any algorithm parameters 337 * and <code>params</code> is null, the underlying exemption 338 * mechanism implementation is supposed to generate the required 339 * parameters itself (using provider-specific default values); in the case 340 * that algorithm parameters must be specified by the caller, an 341 * <code>InvalidAlgorithmParameterException</code> is raised. 342 * 343 * @param key the key for this exemption mechanism 344 * @param params the algorithm parameters 345 * 346 * @exception InvalidKeyException if the given key is inappropriate for 347 * this exemption mechanism. 348 * @exception InvalidAlgorithmParameterException if the given algorithm 349 * parameters are inappropriate for this exemption mechanism. 350 * @exception ExemptionMechanismException if problem(s) encountered in the 351 * process of initializing. 352 */ 353 public final void init(Key key, AlgorithmParameterSpec params) 354 throws InvalidKeyException, InvalidAlgorithmParameterException, 355 ExemptionMechanismException { 356 done = false; 357 initialized = false; 358 359 keyStored = key; 360 exmechSpi.engineInit(key, params); 361 initialized = true; 362 } 363 364 /** 365 * Initializes this exemption mechanism with a key and a set of algorithm 366 * parameters. 367 * 368 * <p>If this exemption mechanism requires any algorithm parameters 369 * and <code>params</code> is null, the underlying exemption mechanism 370 * implementation is supposed to generate the required parameters itself 371 * (using provider-specific default values); in the case that algorithm 372 * parameters must be specified by the caller, an 373 * <code>InvalidAlgorithmParameterException</code> is raised. 374 * 375 * @param key the key for this exemption mechanism 376 * @param params the algorithm parameters 377 * 378 * @exception InvalidKeyException if the given key is inappropriate for 379 * this exemption mechanism. 380 * @exception InvalidAlgorithmParameterException if the given algorithm 381 * parameters are inappropriate for this exemption mechanism. 382 * @exception ExemptionMechanismException if problem(s) encountered in the 383 * process of initializing. 384 */ 385 public final void init(Key key, AlgorithmParameters params) 386 throws InvalidKeyException, InvalidAlgorithmParameterException, 387 ExemptionMechanismException { 388 done = false; 389 initialized = false; 390 391 keyStored = key; 392 exmechSpi.engineInit(key, params); 393 initialized = true; 394 } 395 396 /** 397 * Generates the exemption mechanism key blob. 398 * 399 * @return the new buffer with the result key blob. 400 * 401 * @exception IllegalStateException if this exemption mechanism is in 402 * a wrong state (e.g., has not been initialized). 403 * @exception ExemptionMechanismException if problem(s) encountered in the 404 * process of generating. 405 */ 406 public final byte[] genExemptionBlob() throws IllegalStateException, 407 ExemptionMechanismException { 408 if (!initialized) { 409 throw new IllegalStateException( 410 "ExemptionMechanism not initialized"); 411 } 412 byte[] blob = exmechSpi.engineGenExemptionBlob(); 413 done = true; 414 return blob; 415 } 416 417 /** 418 * Generates the exemption mechanism key blob, and stores the result in 419 * the <code>output</code> buffer. 420 * 421 * <p>If the <code>output</code> buffer is too small to hold the result, 422 * a <code>ShortBufferException</code> is thrown. In this case, repeat this 423 * call with a larger output buffer. Use 424 * {@link #getOutputSize(int) getOutputSize} to determine how big 425 * the output buffer should be. 426 * 427 * @param output the buffer for the result 428 * 429 * @return the number of bytes stored in <code>output</code> 430 * 431 * @exception IllegalStateException if this exemption mechanism is in 432 * a wrong state (e.g., has not been initialized). 433 * @exception ShortBufferException if the given output buffer is too small 434 * to hold the result. 435 * @exception ExemptionMechanismException if problem(s) encountered in the 436 * process of generating. 437 */ 438 public final int genExemptionBlob(byte[] output) 439 throws IllegalStateException, ShortBufferException, 440 ExemptionMechanismException { 441 if (!initialized) { 442 throw new IllegalStateException 443 ("ExemptionMechanism not initialized"); 444 } 445 int n = exmechSpi.engineGenExemptionBlob(output, 0); 446 done = true; 447 return n; 448 } 449 450 /** 451 * Generates the exemption mechanism key blob, and stores the result in 452 * the <code>output</code> buffer, starting at <code>outputOffset</code> 453 * inclusive. 454 * 455 * <p>If the <code>output</code> buffer is too small to hold the result, 456 * a <code>ShortBufferException</code> is thrown. In this case, repeat this 457 * call with a larger output buffer. Use 458 * {@link #getOutputSize(int) getOutputSize} to determine how big 459 * the output buffer should be. 460 * 461 * @param output the buffer for the result 462 * @param outputOffset the offset in <code>output</code> where the result 463 * is stored 464 * 465 * @return the number of bytes stored in <code>output</code> 466 * 467 * @exception IllegalStateException if this exemption mechanism is in 468 * a wrong state (e.g., has not been initialized). 469 * @exception ShortBufferException if the given output buffer is too small 470 * to hold the result. 471 * @exception ExemptionMechanismException if problem(s) encountered in the 472 * process of generating. 473 */ 474 public final int genExemptionBlob(byte[] output, int outputOffset) 475 throws IllegalStateException, ShortBufferException, 476 ExemptionMechanismException { 477 if (!initialized) { 478 throw new IllegalStateException 479 ("ExemptionMechanism not initialized"); 480 } 481 int n = exmechSpi.engineGenExemptionBlob(output, outputOffset); 482 done = true; 483 return n; 484 } 485 }