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