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