1 /* 2 * Copyright (c) 1997, 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.util.*; 29 30 import java.security.*; 31 import java.security.Provider.Service; 32 import java.security.spec.*; 33 34 import sun.security.jca.*; 35 import sun.security.jca.GetInstance.Instance; 36 37 /** 38 * This class represents a factory for secret keys. 39 * 40 * <P> Key factories are used to convert <I>keys</I> (opaque 41 * cryptographic keys of type {@code Key}) into <I>key specifications</I> 42 * (transparent representations of the underlying key material), and vice 43 * versa. 44 * Secret key factories operate only on secret (symmetric) keys. 45 * 46 * <P> Key factories are bi-directional, i.e., they allow to build an opaque 47 * key object from a given key specification (key material), or to retrieve 48 * the underlying key material of a key object in a suitable format. 49 * 50 * <P> Application developers should refer to their provider's documentation 51 * to find out which key specifications are supported by the 52 * {@link #generateSecret(java.security.spec.KeySpec) generateSecret} and 53 * {@link #getKeySpec(javax.crypto.SecretKey, java.lang.Class) getKeySpec} 54 * methods. 55 * For example, the DES secret-key factory supplied by the "SunJCE" provider 56 * supports {@code DESKeySpec} as a transparent representation of DES 57 * keys, and that provider's secret-key factory for Triple DES keys supports 58 * {@code DESedeKeySpec} as a transparent representation of Triple DES 59 * keys. 60 * 61 * <p> Every implementation of the Java platform is required to support the 62 * following standard {@code SecretKeyFactory} algorithms: 63 * <ul> 64 * <li>{@code DES}</li> 65 * <li>{@code DESede}</li> 66 * </ul> 67 * These algorithms are described in the <a href= 68 * "{@docRoot}/../technotes/guides/security/StandardNames.html#SecretKeyFactory"> 69 * SecretKeyFactory section</a> of the 70 * Java Cryptography Architecture Standard Algorithm Name Documentation. 71 * Consult the release documentation for your implementation to see if any 72 * other algorithms are supported. 73 * 74 * @author Jan Luehe 75 * 76 * @see SecretKey 77 * @see javax.crypto.spec.DESKeySpec 78 * @see javax.crypto.spec.DESedeKeySpec 79 * @see javax.crypto.spec.PBEKeySpec 80 * @since 1.4 81 */ 82 83 public class SecretKeyFactory { 84 85 // The provider 86 private Provider provider; 87 88 // The algorithm associated with this factory 89 private final String algorithm; 90 91 // The provider implementation (delegate) 92 private volatile SecretKeyFactorySpi spi; 93 94 // lock for mutex during provider selection 95 private final Object lock = new Object(); 96 97 // remaining services to try in provider selection 98 // null once provider is selected 99 private Iterator<Service> serviceIterator; 100 101 /** 102 * Creates a SecretKeyFactory object. 103 * 104 * @param keyFacSpi the delegate 105 * @param provider the provider 106 * @param algorithm the secret-key algorithm 107 */ 108 protected SecretKeyFactory(SecretKeyFactorySpi keyFacSpi, 109 Provider provider, String algorithm) { 110 this.spi = keyFacSpi; 111 this.provider = provider; 112 this.algorithm = algorithm; 113 } 114 115 private SecretKeyFactory(String algorithm) throws NoSuchAlgorithmException { 116 this.algorithm = algorithm; 117 List<Service> list = 118 GetInstance.getServices("SecretKeyFactory", algorithm); 119 serviceIterator = list.iterator(); 120 // fetch and instantiate initial spi 121 if (nextSpi(null) == null) { 122 throw new NoSuchAlgorithmException 123 (algorithm + " SecretKeyFactory not available"); 124 } 125 } 126 127 /** 128 * Returns a {@code SecretKeyFactory} object that converts 129 * secret keys of the specified algorithm. 130 * 131 * <p> This method traverses the list of registered security Providers, 132 * starting with the most preferred Provider. 133 * A new SecretKeyFactory object encapsulating the 134 * SecretKeyFactorySpi implementation from the first 135 * Provider that supports the specified algorithm is returned. 136 * 137 * <p> Note that the list of registered providers may be retrieved via 138 * the {@link Security#getProviders() Security.getProviders()} method. 139 * 140 * @implNote 141 * The JDK Reference Implementation additionally uses the 142 * {@code jdk.security.provider.preferred} 143 * {@link Security#getProperty(String) Security} property to determine 144 * the preferred provider order for the specified algorithm. This 145 * may be different than the order of providers returned by 146 * {@link Security#getProviders() Security.getProviders()}. 147 * 148 * @param algorithm the standard name of the requested secret-key 149 * algorithm. 150 * See the SecretKeyFactory section in the <a href= 151 * "{@docRoot}/../technotes/guides/security/StandardNames.html#SecretKeyFactory"> 152 * Java Cryptography Architecture Standard Algorithm Name Documentation</a> 153 * for information about standard algorithm names. 154 * 155 * @return the new {@code SecretKeyFactory} object 156 * 157 * @throws NoSuchAlgorithmException if no {@code Provider} supports a 158 * {@code SecretKeyFactorySpi} implementation for the 159 * specified algorithm 160 * 161 * @throws NullPointerException if {@code algorithm} is {@code null} 162 * 163 * @see java.security.Provider 164 */ 165 public static final SecretKeyFactory getInstance(String algorithm) 166 throws NoSuchAlgorithmException { 167 Objects.requireNonNull(algorithm, "null algorithm name"); 168 return new SecretKeyFactory(algorithm); 169 } 170 171 /** 172 * Returns a {@code SecretKeyFactory} object that converts 173 * secret keys of the specified algorithm. 174 * 175 * <p> A new SecretKeyFactory object encapsulating the 176 * SecretKeyFactorySpi implementation from the specified provider 177 * is returned. The specified provider must be registered 178 * in the security provider list. 179 * 180 * <p> Note that the list of registered providers may be retrieved via 181 * the {@link Security#getProviders() Security.getProviders()} method. 182 * 183 * @param algorithm the standard name of the requested secret-key 184 * algorithm. 185 * See the SecretKeyFactory section in the <a href= 186 * "{@docRoot}/../technotes/guides/security/StandardNames.html#SecretKeyFactory"> 187 * Java Cryptography Architecture Standard Algorithm Name Documentation</a> 188 * for information about standard algorithm names. 189 * 190 * @param provider the name of the provider. 191 * 192 * @return the new {@code SecretKeyFactory} object 193 * 194 * @throws IllegalArgumentException if the {@code provider} 195 * is {@code null} or empty 196 * 197 * @throws NoSuchAlgorithmException if a {@code SecretKeyFactorySpi} 198 * implementation for the specified algorithm is not 199 * available from the specified provider 200 * 201 * @throws NoSuchProviderException if the specified provider is not 202 * registered in the security provider list 203 * 204 * @throws NullPointerException if {@code algorithm} is {@code null} 205 * 206 * @see java.security.Provider 207 */ 208 public static final SecretKeyFactory getInstance(String algorithm, 209 String provider) throws NoSuchAlgorithmException, 210 NoSuchProviderException { 211 Objects.requireNonNull(algorithm, "null algorithm name"); 212 Instance instance = JceSecurity.getInstance("SecretKeyFactory", 213 SecretKeyFactorySpi.class, algorithm, provider); 214 return new SecretKeyFactory((SecretKeyFactorySpi)instance.impl, 215 instance.provider, algorithm); 216 } 217 218 /** 219 * Returns a {@code SecretKeyFactory} object that converts 220 * secret keys of the specified algorithm. 221 * 222 * <p> A new SecretKeyFactory object encapsulating the 223 * SecretKeyFactorySpi implementation from the specified Provider 224 * object is returned. Note that the specified Provider object 225 * does not have to be registered in the provider list. 226 * 227 * @param algorithm the standard name of the requested secret-key 228 * algorithm. 229 * See the SecretKeyFactory section in the <a href= 230 * "{@docRoot}/../technotes/guides/security/StandardNames.html#SecretKeyFactory"> 231 * Java Cryptography Architecture Standard Algorithm Name Documentation</a> 232 * for information about standard algorithm names. 233 * 234 * @param provider the provider. 235 * 236 * @return the new {@code SecretKeyFactory} object 237 * 238 * @throws IllegalArgumentException if the {@code provider} 239 * is {@code null} 240 * 241 * @throws NoSuchAlgorithmException if a {@code SecretKeyFactorySpi} 242 * implementation for the specified algorithm is not available 243 * from the specified {@code Provider} object 244 * 245 * @throws NullPointerException if {@code algorithm} is {@code null} 246 * 247 * @see java.security.Provider 248 */ 249 public static final SecretKeyFactory getInstance(String algorithm, 250 Provider provider) throws NoSuchAlgorithmException { 251 Objects.requireNonNull(algorithm, "null algorithm name"); 252 Instance instance = JceSecurity.getInstance("SecretKeyFactory", 253 SecretKeyFactorySpi.class, algorithm, provider); 254 return new SecretKeyFactory((SecretKeyFactorySpi)instance.impl, 255 instance.provider, algorithm); 256 } 257 258 /** 259 * Returns the provider of this {@code SecretKeyFactory} object. 260 * 261 * @return the provider of this {@code SecretKeyFactory} object 262 */ 263 public final Provider getProvider() { 264 synchronized (lock) { 265 // disable further failover after this call 266 serviceIterator = null; 267 return provider; 268 } 269 } 270 271 /** 272 * Returns the algorithm name of this {@code SecretKeyFactory} object. 273 * 274 * <p>This is the same name that was specified in one of the 275 * {@code getInstance} calls that created this 276 * {@code SecretKeyFactory} object. 277 * 278 * @return the algorithm name of this {@code SecretKeyFactory} 279 * object. 280 */ 281 public final String getAlgorithm() { 282 return this.algorithm; 283 } 284 285 /** 286 * Update the active spi of this class and return the next 287 * implementation for failover. If no more implemenations are 288 * available, this method returns null. However, the active spi of 289 * this class is never set to null. 290 */ 291 private SecretKeyFactorySpi nextSpi(SecretKeyFactorySpi oldSpi) { 292 synchronized (lock) { 293 // somebody else did a failover concurrently 294 // try that spi now 295 if ((oldSpi != null) && (oldSpi != spi)) { 296 return spi; 297 } 298 if (serviceIterator == null) { 299 return null; 300 } 301 while (serviceIterator.hasNext()) { 302 Service s = serviceIterator.next(); 303 if (JceSecurity.canUseProvider(s.getProvider()) == false) { 304 continue; 305 } 306 try { 307 Object obj = s.newInstance(null); 308 if (obj instanceof SecretKeyFactorySpi == false) { 309 continue; 310 } 311 SecretKeyFactorySpi spi = (SecretKeyFactorySpi)obj; 312 provider = s.getProvider(); 313 this.spi = spi; 314 return spi; 315 } catch (NoSuchAlgorithmException e) { 316 // ignore 317 } 318 } 319 serviceIterator = null; 320 return null; 321 } 322 } 323 324 /** 325 * Generates a {@code SecretKey} object from the provided key 326 * specification (key material). 327 * 328 * @param keySpec the specification (key material) of the secret key 329 * 330 * @return the secret key 331 * 332 * @exception InvalidKeySpecException if the given key specification 333 * is inappropriate for this secret-key factory to produce a secret key. 334 */ 335 public final SecretKey generateSecret(KeySpec keySpec) 336 throws InvalidKeySpecException { 337 if (serviceIterator == null) { 338 return spi.engineGenerateSecret(keySpec); 339 } 340 Exception failure = null; 341 SecretKeyFactorySpi mySpi = spi; 342 do { 343 try { 344 return mySpi.engineGenerateSecret(keySpec); 345 } catch (Exception e) { 346 if (failure == null) { 347 failure = e; 348 } 349 mySpi = nextSpi(mySpi); 350 } 351 } while (mySpi != null); 352 if (failure instanceof InvalidKeySpecException) { 353 throw (InvalidKeySpecException)failure; 354 } 355 throw new InvalidKeySpecException 356 ("Could not generate secret key", failure); 357 } 358 359 /** 360 * Returns a specification (key material) of the given key object 361 * in the requested format. 362 * 363 * @param key the key 364 * @param keySpec the requested format in which the key material shall be 365 * returned 366 * 367 * @return the underlying key specification (key material) in the 368 * requested format 369 * 370 * @exception InvalidKeySpecException if the requested key specification is 371 * inappropriate for the given key (e.g., the algorithms associated with 372 * {@code key} and {@code keySpec} do not match, or 373 * {@code key} references a key on a cryptographic hardware device 374 * whereas {@code keySpec} is the specification of a software-based 375 * key), or the given key cannot be dealt with 376 * (e.g., the given key has an algorithm or format not supported by this 377 * secret-key factory). 378 */ 379 public final KeySpec getKeySpec(SecretKey key, Class<?> keySpec) 380 throws InvalidKeySpecException { 381 if (serviceIterator == null) { 382 return spi.engineGetKeySpec(key, keySpec); 383 } 384 Exception failure = null; 385 SecretKeyFactorySpi mySpi = spi; 386 do { 387 try { 388 return mySpi.engineGetKeySpec(key, keySpec); 389 } catch (Exception e) { 390 if (failure == null) { 391 failure = e; 392 } 393 mySpi = nextSpi(mySpi); 394 } 395 } while (mySpi != null); 396 if (failure instanceof InvalidKeySpecException) { 397 throw (InvalidKeySpecException)failure; 398 } 399 throw new InvalidKeySpecException 400 ("Could not get key spec", failure); 401 } 402 403 /** 404 * Translates a key object, whose provider may be unknown or potentially 405 * untrusted, into a corresponding key object of this secret-key factory. 406 * 407 * @param key the key whose provider is unknown or untrusted 408 * 409 * @return the translated key 410 * 411 * @exception InvalidKeyException if the given key cannot be processed 412 * by this secret-key factory. 413 */ 414 public final SecretKey translateKey(SecretKey key) 415 throws InvalidKeyException { 416 if (serviceIterator == null) { 417 return spi.engineTranslateKey(key); 418 } 419 Exception failure = null; 420 SecretKeyFactorySpi mySpi = spi; 421 do { 422 try { 423 return mySpi.engineTranslateKey(key); 424 } catch (Exception e) { 425 if (failure == null) { 426 failure = e; 427 } 428 mySpi = nextSpi(mySpi); 429 } 430 } while (mySpi != null); 431 if (failure instanceof InvalidKeyException) { 432 throw (InvalidKeyException)failure; 433 } 434 throw new InvalidKeyException 435 ("Could not translate key", failure); 436 } 437 }