1 /* 2 * Copyright (c) 1997, 2015, 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} property to determine 143 * the preferred provider order for the specified algorithm. This 144 * may be different than the order of providers returned by 145 * {@link Security#getProviders() Security.getProviders()}. 146 * 147 * @param algorithm the standard name of the requested secret-key 148 * algorithm. 149 * See the SecretKeyFactory section in the <a href= 150 * "{@docRoot}/../technotes/guides/security/StandardNames.html#SecretKeyFactory"> 151 * Java Cryptography Architecture Standard Algorithm Name Documentation</a> 152 * for information about standard algorithm names. 153 * 154 * @return the new {@code SecretKeyFactory} object. 155 * 156 * @exception NullPointerException if the specified algorithm 157 * is null. 158 * 159 * @exception NoSuchAlgorithmException if no Provider supports a 160 * SecretKeyFactorySpi implementation for the 161 * specified algorithm. 162 * 163 * @see java.security.Provider 164 */ 165 public static final SecretKeyFactory getInstance(String algorithm) 166 throws NoSuchAlgorithmException { 167 return new SecretKeyFactory(algorithm); 168 } 169 170 /** 171 * Returns a {@code SecretKeyFactory} object that converts 172 * secret keys of the specified algorithm. 173 * 174 * <p> A new SecretKeyFactory object encapsulating the 175 * SecretKeyFactorySpi implementation from the specified provider 176 * is returned. The specified provider must be registered 177 * in the security provider list. 178 * 179 * <p> Note that the list of registered providers may be retrieved via 180 * the {@link Security#getProviders() Security.getProviders()} method. 181 * 182 * @param algorithm the standard name of the requested secret-key 183 * algorithm. 184 * See the SecretKeyFactory section in the <a href= 185 * "{@docRoot}/../technotes/guides/security/StandardNames.html#SecretKeyFactory"> 186 * Java Cryptography Architecture Standard Algorithm Name Documentation</a> 187 * for information about standard algorithm names. 188 * 189 * @param provider the name of the provider. 190 * 191 * @return the new {@code SecretKeyFactory} object. 192 * 193 * @exception NoSuchAlgorithmException if a SecretKeyFactorySpi 194 * implementation for the specified algorithm is not 195 * available from the specified provider. 196 * 197 * @exception NullPointerException if the specified algorithm 198 * is null. 199 * 200 * @throws NoSuchProviderException if the specified provider is not 201 * registered in the security provider list. 202 * 203 * @exception IllegalArgumentException if the {@code provider} 204 * is null or empty. 205 * 206 * @see java.security.Provider 207 */ 208 public static final SecretKeyFactory getInstance(String algorithm, 209 String provider) throws NoSuchAlgorithmException, 210 NoSuchProviderException { 211 Instance instance = JceSecurity.getInstance("SecretKeyFactory", 212 SecretKeyFactorySpi.class, algorithm, provider); 213 return new SecretKeyFactory((SecretKeyFactorySpi)instance.impl, 214 instance.provider, algorithm); 215 } 216 217 /** 218 * Returns a {@code SecretKeyFactory} object that converts 219 * secret keys of the specified algorithm. 220 * 221 * <p> A new SecretKeyFactory object encapsulating the 222 * SecretKeyFactorySpi implementation from the specified Provider 223 * object is returned. Note that the specified Provider object 224 * does not have to be registered in the provider list. 225 * 226 * @param algorithm the standard name of the requested secret-key 227 * algorithm. 228 * See the SecretKeyFactory section in the <a href= 229 * "{@docRoot}/../technotes/guides/security/StandardNames.html#SecretKeyFactory"> 230 * Java Cryptography Architecture Standard Algorithm Name Documentation</a> 231 * for information about standard algorithm names. 232 * 233 * @param provider the provider. 234 * 235 * @return the new {@code SecretKeyFactory} object. 236 * 237 * @exception NullPointerException if the specified algorithm 238 * is null. 239 * 240 * @exception NoSuchAlgorithmException if a SecretKeyFactorySpi 241 * implementation for the specified algorithm is not available 242 * from the specified Provider object. 243 * 244 * @exception IllegalArgumentException if the {@code provider} 245 * is null. 246 * 247 * @see java.security.Provider 248 */ 249 public static final SecretKeyFactory getInstance(String algorithm, 250 Provider provider) throws NoSuchAlgorithmException { 251 Instance instance = JceSecurity.getInstance("SecretKeyFactory", 252 SecretKeyFactorySpi.class, algorithm, provider); 253 return new SecretKeyFactory((SecretKeyFactorySpi)instance.impl, 254 instance.provider, algorithm); 255 } 256 257 /** 258 * Returns the provider of this {@code SecretKeyFactory} object. 259 * 260 * @return the provider of this {@code SecretKeyFactory} object 261 */ 262 public final Provider getProvider() { 263 synchronized (lock) { 264 // disable further failover after this call 265 serviceIterator = null; 266 return provider; 267 } 268 } 269 270 /** 271 * Returns the algorithm name of this {@code SecretKeyFactory} object. 272 * 273 * <p>This is the same name that was specified in one of the 274 * {@code getInstance} calls that created this 275 * {@code SecretKeyFactory} object. 276 * 277 * @return the algorithm name of this {@code SecretKeyFactory} 278 * object. 279 */ 280 public final String getAlgorithm() { 281 return this.algorithm; 282 } 283 284 /** 285 * Update the active spi of this class and return the next 286 * implementation for failover. If no more implemenations are 287 * available, this method returns null. However, the active spi of 288 * this class is never set to null. 289 */ 290 private SecretKeyFactorySpi nextSpi(SecretKeyFactorySpi oldSpi) { 291 synchronized (lock) { 292 // somebody else did a failover concurrently 293 // try that spi now 294 if ((oldSpi != null) && (oldSpi != spi)) { 295 return spi; 296 } 297 if (serviceIterator == null) { 298 return null; 299 } 300 while (serviceIterator.hasNext()) { 301 Service s = serviceIterator.next(); 302 if (JceSecurity.canUseProvider(s.getProvider()) == false) { 303 continue; 304 } 305 try { 306 Object obj = s.newInstance(null); 307 if (obj instanceof SecretKeyFactorySpi == false) { 308 continue; 309 } 310 SecretKeyFactorySpi spi = (SecretKeyFactorySpi)obj; 311 provider = s.getProvider(); 312 this.spi = spi; 313 return spi; 314 } catch (NoSuchAlgorithmException e) { 315 // ignore 316 } 317 } 318 serviceIterator = null; 319 return null; 320 } 321 } 322 323 /** 324 * Generates a {@code SecretKey} object from the provided key 325 * specification (key material). 326 * 327 * @param keySpec the specification (key material) of the secret key 328 * 329 * @return the secret key 330 * 331 * @exception InvalidKeySpecException if the given key specification 332 * is inappropriate for this secret-key factory to produce a secret key. 333 */ 334 public final SecretKey generateSecret(KeySpec keySpec) 335 throws InvalidKeySpecException { 336 if (serviceIterator == null) { 337 return spi.engineGenerateSecret(keySpec); 338 } 339 Exception failure = null; 340 SecretKeyFactorySpi mySpi = spi; 341 do { 342 try { 343 return mySpi.engineGenerateSecret(keySpec); 344 } catch (Exception e) { 345 if (failure == null) { 346 failure = e; 347 } 348 mySpi = nextSpi(mySpi); 349 } 350 } while (mySpi != null); 351 if (failure instanceof InvalidKeySpecException) { 352 throw (InvalidKeySpecException)failure; 353 } 354 throw new InvalidKeySpecException 355 ("Could not generate secret key", failure); 356 } 357 358 /** 359 * Returns a specification (key material) of the given key object 360 * in the requested format. 361 * 362 * @param key the key 363 * @param keySpec the requested format in which the key material shall be 364 * returned 365 * 366 * @return the underlying key specification (key material) in the 367 * requested format 368 * 369 * @exception InvalidKeySpecException if the requested key specification is 370 * inappropriate for the given key (e.g., the algorithms associated with 371 * {@code key} and {@code keySpec} do not match, or 372 * {@code key} references a key on a cryptographic hardware device 373 * whereas {@code keySpec} is the specification of a software-based 374 * key), or the given key cannot be dealt with 375 * (e.g., the given key has an algorithm or format not supported by this 376 * secret-key factory). 377 */ 378 public final KeySpec getKeySpec(SecretKey key, Class<?> keySpec) 379 throws InvalidKeySpecException { 380 if (serviceIterator == null) { 381 return spi.engineGetKeySpec(key, keySpec); 382 } 383 Exception failure = null; 384 SecretKeyFactorySpi mySpi = spi; 385 do { 386 try { 387 return mySpi.engineGetKeySpec(key, keySpec); 388 } catch (Exception e) { 389 if (failure == null) { 390 failure = e; 391 } 392 mySpi = nextSpi(mySpi); 393 } 394 } while (mySpi != null); 395 if (failure instanceof InvalidKeySpecException) { 396 throw (InvalidKeySpecException)failure; 397 } 398 throw new InvalidKeySpecException 399 ("Could not get key spec", failure); 400 } 401 402 /** 403 * Translates a key object, whose provider may be unknown or potentially 404 * untrusted, into a corresponding key object of this secret-key factory. 405 * 406 * @param key the key whose provider is unknown or untrusted 407 * 408 * @return the translated key 409 * 410 * @exception InvalidKeyException if the given key cannot be processed 411 * by this secret-key factory. 412 */ 413 public final SecretKey translateKey(SecretKey key) 414 throws InvalidKeyException { 415 if (serviceIterator == null) { 416 return spi.engineTranslateKey(key); 417 } 418 Exception failure = null; 419 SecretKeyFactorySpi mySpi = spi; 420 do { 421 try { 422 return mySpi.engineTranslateKey(key); 423 } catch (Exception e) { 424 if (failure == null) { 425 failure = e; 426 } 427 mySpi = nextSpi(mySpi); 428 } 429 } while (mySpi != null); 430 if (failure instanceof InvalidKeyException) { 431 throw (InvalidKeyException)failure; 432 } 433 throw new InvalidKeyException 434 ("Could not translate key", failure); 435 } 436 }