Path: blob/aarch64-shenandoah-jdk8u272-b10/jdk/src/share/classes/javax/crypto/SecretKeyFactory.java
38829 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 DES secret-key factory supplied by the "SunJCE" provider55* supports {@code DESKeySpec} as a transparent representation of DES56* keys, and that provider's secret-key factory for Triple DES keys supports57* {@code DESedeKeySpec} as a transparent representation of Triple DES58* keys.59*60* <p> Every implementation of the Java platform is required to support the61* following standard {@code SecretKeyFactory} algorithms:62* <ul>63* <li>{@code DES}</li>64* <li>{@code DESede}</li>65* </ul>66* These algorithms are described in the <a href=67* "{@docRoot}/../technotes/guides/security/StandardNames.html#SecretKeyFactory">68* SecretKeyFactory section</a> of the69* Java Cryptography Architecture Standard Algorithm Name Documentation.70* Consult the release documentation for your implementation to see if any71* other algorithms are supported.72*73* @author Jan Luehe74*75* @see SecretKey76* @see javax.crypto.spec.DESKeySpec77* @see javax.crypto.spec.DESedeKeySpec78* @see javax.crypto.spec.PBEKeySpec79* @since 1.480*/8182public class SecretKeyFactory {8384// The provider85private Provider provider;8687// The algorithm associated with this factory88private final String algorithm;8990// The provider implementation (delegate)91private volatile SecretKeyFactorySpi spi;9293// lock for mutex during provider selection94private final Object lock = new Object();9596// remaining services to try in provider selection97// null once provider is selected98private Iterator<Service> serviceIterator;99100/**101* Creates a SecretKeyFactory object.102*103* @param keyFacSpi the delegate104* @param provider the provider105* @param algorithm the secret-key algorithm106*/107protected SecretKeyFactory(SecretKeyFactorySpi keyFacSpi,108Provider provider, String algorithm) {109this.spi = keyFacSpi;110this.provider = provider;111this.algorithm = algorithm;112}113114private SecretKeyFactory(String algorithm) throws NoSuchAlgorithmException {115this.algorithm = algorithm;116List<Service> list =117GetInstance.getServices("SecretKeyFactory", algorithm);118serviceIterator = list.iterator();119// fetch and instantiate initial spi120if (nextSpi(null) == null) {121throw new NoSuchAlgorithmException122(algorithm + " SecretKeyFactory not available");123}124}125126/**127* Returns a {@code SecretKeyFactory} object that converts128* 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 the133* SecretKeyFactorySpi implementation from the first134* Provider that supports the specified algorithm is returned.135*136* <p> Note that the list of registered providers may be retrieved via137* the {@link Security#getProviders() Security.getProviders()} method.138*139* @param algorithm the standard name of the requested secret-key140* 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} object.147*148* @exception NullPointerException if the specified algorithm149* is null.150*151* @exception NoSuchAlgorithmException if no Provider supports a152* SecretKeyFactorySpi implementation for the153* specified algorithm.154*155* @see java.security.Provider156*/157public static final SecretKeyFactory getInstance(String algorithm)158throws NoSuchAlgorithmException {159return new SecretKeyFactory(algorithm);160}161162/**163* Returns a {@code SecretKeyFactory} object that converts164* secret keys of the specified algorithm.165*166* <p> A new SecretKeyFactory object encapsulating the167* SecretKeyFactorySpi implementation from the specified provider168* is returned. The specified provider must be registered169* in the security provider list.170*171* <p> Note that the list of registered providers may be retrieved via172* the {@link Security#getProviders() Security.getProviders()} method.173*174* @param algorithm the standard name of the requested secret-key175* 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} object.184*185* @exception NoSuchAlgorithmException if a SecretKeyFactorySpi186* implementation for the specified algorithm is not187* available from the specified provider.188*189* @exception NullPointerException if the specified algorithm190* is null.191*192* @throws NoSuchProviderException if the specified provider is not193* registered in the security provider list.194*195* @exception IllegalArgumentException if the {@code provider}196* is null or empty.197*198* @see java.security.Provider199*/200public static final SecretKeyFactory getInstance(String algorithm,201String provider) throws NoSuchAlgorithmException,202NoSuchProviderException {203Instance instance = JceSecurity.getInstance("SecretKeyFactory",204SecretKeyFactorySpi.class, algorithm, provider);205return new SecretKeyFactory((SecretKeyFactorySpi)instance.impl,206instance.provider, algorithm);207}208209/**210* Returns a {@code SecretKeyFactory} object that converts211* secret keys of the specified algorithm.212*213* <p> A new SecretKeyFactory object encapsulating the214* SecretKeyFactorySpi implementation from the specified Provider215* object is returned. Note that the specified Provider object216* does not have to be registered in the provider list.217*218* @param algorithm the standard name of the requested secret-key219* 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} object.228*229* @exception NullPointerException if the specified algorithm230* is null.231*232* @exception NoSuchAlgorithmException if a SecretKeyFactorySpi233* implementation for the specified algorithm is not available234* from the specified Provider object.235*236* @exception IllegalArgumentException if the {@code provider}237* is null.238*239* @see java.security.Provider240*/241public static final SecretKeyFactory getInstance(String algorithm,242Provider provider) throws NoSuchAlgorithmException {243Instance instance = JceSecurity.getInstance("SecretKeyFactory",244SecretKeyFactorySpi.class, algorithm, provider);245return new SecretKeyFactory((SecretKeyFactorySpi)instance.impl,246instance.provider, algorithm);247}248249/**250* Returns the provider of this {@code SecretKeyFactory} object.251*252* @return the provider of this {@code SecretKeyFactory} object253*/254public final Provider getProvider() {255synchronized (lock) {256// disable further failover after this call257serviceIterator = null;258return provider;259}260}261262/**263* Returns the algorithm name of this {@code SecretKeyFactory} object.264*265* <p>This is the same name that was specified in one of the266* {@code getInstance} calls that created this267* {@code SecretKeyFactory} object.268*269* @return the algorithm name of this {@code SecretKeyFactory}270* object.271*/272public final String getAlgorithm() {273return this.algorithm;274}275276/**277* Update the active spi of this class and return the next278* implementation for failover. If no more implemenations are279* available, this method returns null. However, the active spi of280* this class is never set to null.281*/282private SecretKeyFactorySpi nextSpi(SecretKeyFactorySpi oldSpi) {283synchronized (lock) {284// somebody else did a failover concurrently285// try that spi now286if ((oldSpi != null) && (oldSpi != spi)) {287return spi;288}289if (serviceIterator == null) {290return null;291}292while (serviceIterator.hasNext()) {293Service s = serviceIterator.next();294if (JceSecurity.canUseProvider(s.getProvider()) == false) {295continue;296}297try {298Object obj = s.newInstance(null);299if (obj instanceof SecretKeyFactorySpi == false) {300continue;301}302SecretKeyFactorySpi spi = (SecretKeyFactorySpi)obj;303provider = s.getProvider();304this.spi = spi;305return spi;306} catch (NoSuchAlgorithmException e) {307// ignore308}309}310serviceIterator = null;311return null;312}313}314315/**316* Generates a {@code SecretKey} object from the provided key317* specification (key material).318*319* @param keySpec the specification (key material) of the secret key320*321* @return the secret key322*323* @exception InvalidKeySpecException if the given key specification324* is inappropriate for this secret-key factory to produce a secret key.325*/326public final SecretKey generateSecret(KeySpec keySpec)327throws InvalidKeySpecException {328if (serviceIterator == null) {329return spi.engineGenerateSecret(keySpec);330}331Exception failure = null;332SecretKeyFactorySpi mySpi = spi;333do {334try {335return mySpi.engineGenerateSecret(keySpec);336} catch (Exception e) {337if (failure == null) {338failure = e;339}340mySpi = nextSpi(mySpi);341}342} while (mySpi != null);343if (failure instanceof InvalidKeySpecException) {344throw (InvalidKeySpecException)failure;345}346throw new InvalidKeySpecException347("Could not generate secret key", failure);348}349350/**351* Returns a specification (key material) of the given key object352* in the requested format.353*354* @param key the key355* @param keySpec the requested format in which the key material shall be356* returned357*358* @return the underlying key specification (key material) in the359* requested format360*361* @exception InvalidKeySpecException if the requested key specification is362* inappropriate for the given key (e.g., the algorithms associated with363* {@code key} and {@code keySpec} do not match, or364* {@code key} references a key on a cryptographic hardware device365* whereas {@code keySpec} is the specification of a software-based366* key), or the given key cannot be dealt with367* (e.g., the given key has an algorithm or format not supported by this368* secret-key factory).369*/370public final KeySpec getKeySpec(SecretKey key, Class<?> keySpec)371throws InvalidKeySpecException {372if (serviceIterator == null) {373return spi.engineGetKeySpec(key, keySpec);374}375Exception failure = null;376SecretKeyFactorySpi mySpi = spi;377do {378try {379return mySpi.engineGetKeySpec(key, keySpec);380} catch (Exception e) {381if (failure == null) {382failure = e;383}384mySpi = nextSpi(mySpi);385}386} while (mySpi != null);387if (failure instanceof InvalidKeySpecException) {388throw (InvalidKeySpecException)failure;389}390throw new InvalidKeySpecException391("Could not get key spec", failure);392}393394/**395* Translates a key object, whose provider may be unknown or potentially396* untrusted, into a corresponding key object of this secret-key factory.397*398* @param key the key whose provider is unknown or untrusted399*400* @return the translated key401*402* @exception InvalidKeyException if the given key cannot be processed403* by this secret-key factory.404*/405public final SecretKey translateKey(SecretKey key)406throws InvalidKeyException {407if (serviceIterator == null) {408return spi.engineTranslateKey(key);409}410Exception failure = null;411SecretKeyFactorySpi mySpi = spi;412do {413try {414return mySpi.engineTranslateKey(key);415} catch (Exception e) {416if (failure == null) {417failure = e;418}419mySpi = nextSpi(mySpi);420}421} while (mySpi != null);422if (failure instanceof InvalidKeyException) {423throw (InvalidKeyException)failure;424}425throw new InvalidKeyException426("Could not translate key", failure);427}428}429430431