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