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