Path: blob/master/src/java.base/share/classes/javax/crypto/SecretKeyFactory.java
41152 views
/*1* Copyright (c) 1997, 2019, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation. Oracle designates this7* particular file as subject to the "Classpath" exception as provided8* by Oracle in the LICENSE file that accompanied this code.9*10* This code is distributed in the hope that it will be useful, but WITHOUT11* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or12* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License13* version 2 for more details (a copy is included in the LICENSE file that14* accompanied this code).15*16* You should have received a copy of the GNU General Public License version17* 2 along with this work; if not, write to the Free Software Foundation,18* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.19*20* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA21* or visit www.oracle.com if you need additional information or have any22* questions.23*/2425package javax.crypto;2627import java.util.*;2829import java.security.*;30import java.security.Provider.Service;31import java.security.spec.*;3233import sun.security.jca.*;34import sun.security.jca.GetInstance.Instance;3536/**37* This class represents a factory for secret keys.38*39* <P> Key factories are used to convert <I>keys</I> (opaque40* cryptographic keys of type {@code Key}) into <I>key specifications</I>41* (transparent representations of the underlying key material), and vice42* versa.43* Secret key factories operate only on secret (symmetric) keys.44*45* <P> Key factories are bi-directional, i.e., they allow to build an opaque46* key object from a given key specification (key material), or to retrieve47* the underlying key material of a key object in a suitable format.48*49* <P> Application developers should refer to their provider's documentation50* to find out which key specifications are supported by the51* {@link #generateSecret(java.security.spec.KeySpec) generateSecret} and52* {@link #getKeySpec(javax.crypto.SecretKey, java.lang.Class) getKeySpec}53* methods.54* For example, the DESede (Triple DES) secret-key factory supplied by the55* "SunJCE" provider supports {@code DESedeKeySpec} as a transparent56* representation of Triple DES keys.57*58* <p> Every implementation of the Java platform is required to support the59* following standard {@code SecretKeyFactory} algorithms:60* <ul>61* <li>{@code DESede}</li>62* </ul>63* These algorithms are described in the <a href=64* "{@docRoot}/../specs/security/standard-names.html#secretkeyfactory-algorithms">65* SecretKeyFactory section</a> of the66* Java Security Standard Algorithm Names Specification.67* Consult the release documentation for your implementation to see if any68* other algorithms are supported.69*70* @author Jan Luehe71*72* @see SecretKey73* @see javax.crypto.spec.DESedeKeySpec74* @see javax.crypto.spec.PBEKeySpec75* @since 1.476*/7778public class SecretKeyFactory {7980// The provider81private Provider provider;8283// The algorithm associated with this factory84private final String algorithm;8586// The provider implementation (delegate)87private volatile SecretKeyFactorySpi spi;8889// lock for mutex during provider selection90private final Object lock = new Object();9192// remaining services to try in provider selection93// null once provider is selected94private Iterator<Service> serviceIterator;9596/**97* Creates a SecretKeyFactory object.98*99* @param keyFacSpi the delegate100* @param provider the provider101* @param algorithm the secret-key algorithm102*/103protected SecretKeyFactory(SecretKeyFactorySpi keyFacSpi,104Provider provider, String algorithm) {105this.spi = keyFacSpi;106this.provider = provider;107this.algorithm = algorithm;108}109110private SecretKeyFactory(String algorithm) throws NoSuchAlgorithmException {111this.algorithm = algorithm;112List<Service> list =113GetInstance.getServices("SecretKeyFactory", algorithm);114serviceIterator = list.iterator();115// fetch and instantiate initial spi116if (nextSpi(null) == null) {117throw new NoSuchAlgorithmException118(algorithm + " SecretKeyFactory not available");119}120}121122/**123* Returns a {@code SecretKeyFactory} object that converts124* secret keys of the specified algorithm.125*126* <p> This method traverses the list of registered security Providers,127* starting with the most preferred Provider.128* A new SecretKeyFactory object encapsulating the129* SecretKeyFactorySpi implementation from the first130* Provider that supports the specified algorithm is returned.131*132* <p> Note that the list of registered providers may be retrieved via133* the {@link Security#getProviders() Security.getProviders()} method.134*135* @implNote136* The JDK Reference Implementation additionally uses the137* {@code jdk.security.provider.preferred}138* {@link Security#getProperty(String) Security} property to determine139* the preferred provider order for the specified algorithm. This140* may be different than the order of providers returned by141* {@link Security#getProviders() Security.getProviders()}.142*143* @param algorithm the standard name of the requested secret-key144* algorithm.145* See the SecretKeyFactory section in the <a href=146* "{@docRoot}/../specs/security/standard-names.html#secretkeyfactory-algorithms">147* Java Security Standard Algorithm Names Specification</a>148* for information about standard algorithm names.149*150* @return the new {@code SecretKeyFactory} object151*152* @throws NoSuchAlgorithmException if no {@code Provider} supports a153* {@code SecretKeyFactorySpi} implementation for the154* specified algorithm155*156* @throws NullPointerException if {@code algorithm} is {@code null}157*158* @see java.security.Provider159*/160public static final SecretKeyFactory getInstance(String algorithm)161throws NoSuchAlgorithmException {162Objects.requireNonNull(algorithm, "null algorithm name");163return new SecretKeyFactory(algorithm);164}165166/**167* Returns a {@code SecretKeyFactory} object that converts168* secret keys of the specified algorithm.169*170* <p> A new SecretKeyFactory object encapsulating the171* SecretKeyFactorySpi implementation from the specified provider172* is returned. The specified provider must be registered173* in the security provider list.174*175* <p> Note that the list of registered providers may be retrieved via176* the {@link Security#getProviders() Security.getProviders()} method.177*178* @param algorithm the standard name of the requested secret-key179* algorithm.180* See the SecretKeyFactory section in the <a href=181* "{@docRoot}/../specs/security/standard-names.html#secretkeyfactory-algorithms">182* Java Security Standard Algorithm Names Specification</a>183* for information about standard algorithm names.184*185* @param provider the name of the provider.186*187* @return the new {@code SecretKeyFactory} object188*189* @throws IllegalArgumentException if the {@code provider}190* is {@code null} or empty191*192* @throws NoSuchAlgorithmException if a {@code SecretKeyFactorySpi}193* implementation for the specified algorithm is not194* available from the specified provider195*196* @throws NoSuchProviderException if the specified provider is not197* registered in the security provider list198*199* @throws NullPointerException if {@code algorithm} is {@code null}200*201* @see java.security.Provider202*/203public static final SecretKeyFactory getInstance(String algorithm,204String provider) throws NoSuchAlgorithmException,205NoSuchProviderException {206Objects.requireNonNull(algorithm, "null algorithm name");207Instance instance = JceSecurity.getInstance("SecretKeyFactory",208SecretKeyFactorySpi.class, algorithm, provider);209return new SecretKeyFactory((SecretKeyFactorySpi)instance.impl,210instance.provider, algorithm);211}212213/**214* Returns a {@code SecretKeyFactory} object that converts215* secret keys of the specified algorithm.216*217* <p> A new SecretKeyFactory object encapsulating the218* SecretKeyFactorySpi implementation from the specified Provider219* object is returned. Note that the specified Provider object220* does not have to be registered in the provider list.221*222* @param algorithm the standard name of the requested secret-key223* algorithm.224* See the SecretKeyFactory section in the <a href=225* "{@docRoot}/../specs/security/standard-names.html#secretkeyfactory-algorithms">226* Java Security Standard Algorithm Names Specification</a>227* for information about standard algorithm names.228*229* @param provider the provider.230*231* @return the new {@code SecretKeyFactory} object232*233* @throws IllegalArgumentException if the {@code provider}234* is {@code null}235*236* @throws NoSuchAlgorithmException if a {@code SecretKeyFactorySpi}237* implementation for the specified algorithm is not available238* from the specified {@code Provider} object239*240* @throws NullPointerException if {@code algorithm} is {@code null}241*242* @see java.security.Provider243*/244public static final SecretKeyFactory getInstance(String algorithm,245Provider provider) throws NoSuchAlgorithmException {246Objects.requireNonNull(algorithm, "null algorithm name");247Instance instance = JceSecurity.getInstance("SecretKeyFactory",248SecretKeyFactorySpi.class, algorithm, provider);249return new SecretKeyFactory((SecretKeyFactorySpi)instance.impl,250instance.provider, algorithm);251}252253/**254* Returns the provider of this {@code SecretKeyFactory} object.255*256* @return the provider of this {@code SecretKeyFactory} object257*/258public final Provider getProvider() {259synchronized (lock) {260// disable further failover after this call261serviceIterator = null;262return provider;263}264}265266/**267* Returns the algorithm name of this {@code SecretKeyFactory} object.268*269* <p>This is the same name that was specified in one of the270* {@code getInstance} calls that created this271* {@code SecretKeyFactory} object.272*273* @return the algorithm name of this {@code SecretKeyFactory}274* object.275*/276public final String getAlgorithm() {277return this.algorithm;278}279280/**281* Update the active spi of this class and return the next282* implementation for failover. If no more implemenations are283* available, this method returns null. However, the active spi of284* this class is never set to null.285*/286private SecretKeyFactorySpi nextSpi(SecretKeyFactorySpi oldSpi) {287synchronized (lock) {288// somebody else did a failover concurrently289// try that spi now290if ((oldSpi != null) && (oldSpi != spi)) {291return spi;292}293if (serviceIterator == null) {294return null;295}296while (serviceIterator.hasNext()) {297Service s = serviceIterator.next();298if (JceSecurity.canUseProvider(s.getProvider()) == false) {299continue;300}301try {302Object obj = s.newInstance(null);303if (obj instanceof SecretKeyFactorySpi == false) {304continue;305}306SecretKeyFactorySpi spi = (SecretKeyFactorySpi)obj;307provider = s.getProvider();308this.spi = spi;309return spi;310} catch (NoSuchAlgorithmException e) {311// ignore312}313}314serviceIterator = null;315return null;316}317}318319/**320* Generates a {@code SecretKey} object from the provided key321* specification (key material).322*323* @param keySpec the specification (key material) of the secret key324*325* @return the secret key326*327* @exception InvalidKeySpecException if the given key specification328* is inappropriate for this secret-key factory to produce a secret key.329*/330public final SecretKey generateSecret(KeySpec keySpec)331throws InvalidKeySpecException {332if (serviceIterator == null) {333return spi.engineGenerateSecret(keySpec);334}335Exception failure = null;336SecretKeyFactorySpi mySpi = spi;337do {338try {339return mySpi.engineGenerateSecret(keySpec);340} catch (Exception e) {341if (failure == null) {342failure = e;343}344mySpi = nextSpi(mySpi);345}346} while (mySpi != null);347if (failure instanceof InvalidKeySpecException) {348throw (InvalidKeySpecException)failure;349}350throw new InvalidKeySpecException351("Could not generate secret key", failure);352}353354/**355* Returns a specification (key material) of the given key object356* in the requested format.357*358* @param key the key359* @param keySpec the requested format in which the key material shall be360* returned361*362* @return the underlying key specification (key material) in the363* requested format364*365* @exception InvalidKeySpecException if the requested key specification is366* inappropriate for the given key (e.g., the algorithms associated with367* {@code key} and {@code keySpec} do not match, or368* {@code key} references a key on a cryptographic hardware device369* whereas {@code keySpec} is the specification of a software-based370* key), or the given key cannot be dealt with371* (e.g., the given key has an algorithm or format not supported by this372* secret-key factory).373*/374public final KeySpec getKeySpec(SecretKey key, Class<?> keySpec)375throws InvalidKeySpecException {376if (serviceIterator == null) {377return spi.engineGetKeySpec(key, keySpec);378}379Exception failure = null;380SecretKeyFactorySpi mySpi = spi;381do {382try {383return mySpi.engineGetKeySpec(key, keySpec);384} catch (Exception e) {385if (failure == null) {386failure = e;387}388mySpi = nextSpi(mySpi);389}390} while (mySpi != null);391if (failure instanceof InvalidKeySpecException) {392throw (InvalidKeySpecException)failure;393}394throw new InvalidKeySpecException395("Could not get key spec", failure);396}397398/**399* Translates a key object, whose provider may be unknown or potentially400* untrusted, into a corresponding key object of this secret-key factory.401*402* @param key the key whose provider is unknown or untrusted403*404* @return the translated key405*406* @exception InvalidKeyException if the given key cannot be processed407* by this secret-key factory.408*/409public final SecretKey translateKey(SecretKey key)410throws InvalidKeyException {411if (serviceIterator == null) {412return spi.engineTranslateKey(key);413}414Exception failure = null;415SecretKeyFactorySpi mySpi = spi;416do {417try {418return mySpi.engineTranslateKey(key);419} catch (Exception e) {420if (failure == null) {421failure = e;422}423mySpi = nextSpi(mySpi);424}425} while (mySpi != null);426if (failure instanceof InvalidKeyException) {427throw (InvalidKeyException)failure;428}429throw new InvalidKeyException430("Could not translate key", failure);431}432}433434435