Path: blob/master/src/java.base/share/classes/java/security/KeyFactory.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 java.security;2627import java.util.*;2829import java.security.Provider.Service;30import java.security.spec.KeySpec;31import java.security.spec.InvalidKeySpecException;3233import sun.security.util.Debug;34import sun.security.jca.*;35import sun.security.jca.GetInstance.Instance;3637/**38* Key factories are used to convert <I>keys</I> (opaque39* cryptographic keys of type {@code Key}) into <I>key specifications</I>40* (transparent representations of the underlying key material), and vice41* versa.42*43* <P> Key factories are bi-directional. That is, they allow you to build an44* opaque key object from a given key specification (key material), or to45* retrieve the underlying key material of a key object in a suitable format.46*47* <P> Multiple compatible key specifications may exist for the same key.48* For example, a DSA public key may be specified using49* {@code DSAPublicKeySpec} or50* {@code X509EncodedKeySpec}. A key factory can be used to translate51* between compatible key specifications.52*53* <P> The following is an example of how to use a key factory in order to54* instantiate a DSA public key from its encoding.55* Assume Alice has received a digital signature from Bob.56* Bob also sent her his public key (in encoded format) to verify57* his signature. Alice then performs the following actions:58*59* <pre>60* X509EncodedKeySpec bobPubKeySpec = new X509EncodedKeySpec(bobEncodedPubKey);61* KeyFactory keyFactory = KeyFactory.getInstance("DSA");62* PublicKey bobPubKey = keyFactory.generatePublic(bobPubKeySpec);63* Signature sig = Signature.getInstance("DSA");64* sig.initVerify(bobPubKey);65* sig.update(data);66* sig.verify(signature);67* </pre>68*69* <p> Every implementation of the Java platform is required to support the70* following standard {@code KeyFactory} algorithms:71* <ul>72* <li>{@code DiffieHellman}</li>73* <li>{@code DSA}</li>74* <li>{@code RSA}</li>75* </ul>76* These algorithms are described in the <a href=77* "{@docRoot}/../specs/security/standard-names.html#keyfactory-algorithms">78* KeyFactory section</a> of the79* Java Security Standard Algorithm Names Specification.80* Consult the release documentation for your implementation to see if any81* other algorithms are supported.82*83* @author Jan Luehe84*85* @see Key86* @see PublicKey87* @see PrivateKey88* @see java.security.spec.KeySpec89* @see java.security.spec.DSAPublicKeySpec90* @see java.security.spec.X509EncodedKeySpec91*92* @since 1.293*/9495public class KeyFactory {9697private static final Debug debug =98Debug.getInstance("jca", "KeyFactory");99100// The algorithm associated with this key factory101private final String algorithm;102103// The provider104private Provider provider;105106// The provider implementation (delegate)107private volatile KeyFactorySpi spi;108109// lock for mutex during provider selection110private final Object lock = new Object();111112// remaining services to try in provider selection113// null once provider is selected114private Iterator<Service> serviceIterator;115116/**117* Creates a KeyFactory object.118*119* @param keyFacSpi the delegate120* @param provider the provider121* @param algorithm the name of the algorithm122* to associate with this {@code KeyFactory}123*/124protected KeyFactory(KeyFactorySpi keyFacSpi, Provider provider,125String algorithm) {126this.spi = keyFacSpi;127this.provider = provider;128this.algorithm = algorithm;129}130131private KeyFactory(String algorithm) throws NoSuchAlgorithmException {132this.algorithm = algorithm;133List<Service> list = GetInstance.getServices("KeyFactory", algorithm);134serviceIterator = list.iterator();135// fetch and instantiate initial spi136if (nextSpi(null) == null) {137throw new NoSuchAlgorithmException138(algorithm + " KeyFactory not available");139}140}141142/**143* Returns a KeyFactory object that converts144* public/private keys of the specified algorithm.145*146* <p> This method traverses the list of registered security Providers,147* starting with the most preferred Provider.148* A new KeyFactory object encapsulating the149* KeyFactorySpi implementation from the first150* Provider that supports the specified algorithm is returned.151*152* <p> Note that the list of registered providers may be retrieved via153* the {@link Security#getProviders() Security.getProviders()} method.154*155* @implNote156* The JDK Reference Implementation additionally uses the157* {@code jdk.security.provider.preferred}158* {@link Security#getProperty(String) Security} property to determine159* the preferred provider order for the specified algorithm. This160* may be different than the order of providers returned by161* {@link Security#getProviders() Security.getProviders()}.162*163* @param algorithm the name of the requested key algorithm.164* See the KeyFactory section in the <a href=165* "{@docRoot}/../specs/security/standard-names.html#keyfactory-algorithms">166* Java Security Standard Algorithm Names Specification</a>167* for information about standard algorithm names.168*169* @return the new {@code KeyFactory} object170*171* @throws NoSuchAlgorithmException if no {@code Provider} supports a172* {@code KeyFactorySpi} implementation for the173* specified algorithm174*175* @throws NullPointerException if {@code algorithm} is {@code null}176*177* @see Provider178*/179public static KeyFactory getInstance(String algorithm)180throws NoSuchAlgorithmException {181Objects.requireNonNull(algorithm, "null algorithm name");182return new KeyFactory(algorithm);183}184185/**186* Returns a KeyFactory object that converts187* public/private keys of the specified algorithm.188*189* <p> A new KeyFactory object encapsulating the190* KeyFactorySpi implementation from the specified provider191* is returned. The specified provider must be registered192* in the security provider list.193*194* <p> Note that the list of registered providers may be retrieved via195* the {@link Security#getProviders() Security.getProviders()} method.196*197* @param algorithm the name of the requested key algorithm.198* See the KeyFactory section in the <a href=199* "{@docRoot}/../specs/security/standard-names.html#keyfactory-algorithms">200* Java Security Standard Algorithm Names Specification</a>201* for information about standard algorithm names.202*203* @param provider the name of the provider.204*205* @return the new {@code KeyFactory} object206*207* @throws IllegalArgumentException if the provider name is {@code null}208* or empty209*210* @throws NoSuchAlgorithmException if a {@code KeyFactorySpi}211* implementation for the specified algorithm is not212* available from the specified provider213*214* @throws NoSuchProviderException if the specified provider is not215* registered in the security provider list216*217* @throws NullPointerException if {@code algorithm} is {@code null}218*219* @see Provider220*/221public static KeyFactory getInstance(String algorithm, String provider)222throws NoSuchAlgorithmException, NoSuchProviderException {223Objects.requireNonNull(algorithm, "null algorithm name");224Instance instance = GetInstance.getInstance("KeyFactory",225KeyFactorySpi.class, algorithm, provider);226return new KeyFactory((KeyFactorySpi)instance.impl,227instance.provider, algorithm);228}229230/**231* Returns a KeyFactory object that converts232* public/private keys of the specified algorithm.233*234* <p> A new KeyFactory object encapsulating the235* KeyFactorySpi implementation from the specified Provider236* object is returned. Note that the specified Provider object237* does not have to be registered in the provider list.238*239* @param algorithm the name of the requested key algorithm.240* See the KeyFactory section in the <a href=241* "{@docRoot}/../specs/security/standard-names.html#keyfactory-algorithms">242* Java Security Standard Algorithm Names Specification</a>243* for information about standard algorithm names.244*245* @param provider the provider.246*247* @return the new {@code KeyFactory} object248*249* @throws IllegalArgumentException if the specified provider is250* {@code null}251*252* @throws NoSuchAlgorithmException if a {@code KeyFactorySpi}253* implementation for the specified algorithm is not available254* from the specified {@code Provider} object255*256* @throws NullPointerException if {@code algorithm} is {@code null}257*258* @see Provider259*260* @since 1.4261*/262public static KeyFactory getInstance(String algorithm, Provider provider)263throws NoSuchAlgorithmException {264Objects.requireNonNull(algorithm, "null algorithm name");265Instance instance = GetInstance.getInstance("KeyFactory",266KeyFactorySpi.class, algorithm, provider);267return new KeyFactory((KeyFactorySpi)instance.impl,268instance.provider, algorithm);269}270271/**272* Returns the provider of this key factory object.273*274* @return the provider of this key factory object275*/276public final Provider getProvider() {277synchronized (lock) {278// disable further failover after this call279serviceIterator = null;280return provider;281}282}283284/**285* Gets the name of the algorithm286* associated with this {@code KeyFactory}.287*288* @return the name of the algorithm associated with this289* {@code KeyFactory}290*/291public final String getAlgorithm() {292return this.algorithm;293}294295/**296* Update the active KeyFactorySpi of this class and return the next297* implementation for failover. If no more implemenations are298* available, this method returns null. However, the active spi of299* this class is never set to null.300*/301private KeyFactorySpi nextSpi(KeyFactorySpi oldSpi) {302synchronized (lock) {303// somebody else did a failover concurrently304// try that spi now305if ((oldSpi != null) && (oldSpi != spi)) {306return spi;307}308if (serviceIterator == null) {309return null;310}311while (serviceIterator.hasNext()) {312Service s = serviceIterator.next();313try {314Object obj = s.newInstance(null);315if (!(obj instanceof KeyFactorySpi spi)) {316continue;317}318provider = s.getProvider();319this.spi = spi;320return spi;321} catch (NoSuchAlgorithmException e) {322// ignore323}324}325serviceIterator = null;326return null;327}328}329330/**331* Generates a public key object from the provided key specification332* (key material).333*334* @param keySpec the specification (key material) of the public key.335*336* @return the public key.337*338* @throws InvalidKeySpecException if the given key specification339* is inappropriate for this key factory to produce a public key.340*/341public final PublicKey generatePublic(KeySpec keySpec)342throws InvalidKeySpecException {343if (serviceIterator == null) {344return spi.engineGeneratePublic(keySpec);345}346Exception failure = null;347KeyFactorySpi mySpi = spi;348do {349try {350return mySpi.engineGeneratePublic(keySpec);351} catch (Exception e) {352if (failure == null) {353failure = e;354}355mySpi = nextSpi(mySpi);356}357} while (mySpi != null);358if (failure instanceof RuntimeException) {359throw (RuntimeException)failure;360}361if (failure instanceof InvalidKeySpecException) {362throw (InvalidKeySpecException)failure;363}364throw new InvalidKeySpecException365("Could not generate public key", failure);366}367368/**369* Generates a private key object from the provided key specification370* (key material).371*372* @param keySpec the specification (key material) of the private key.373*374* @return the private key.375*376* @throws InvalidKeySpecException if the given key specification377* is inappropriate for this key factory to produce a private key.378*/379public final PrivateKey generatePrivate(KeySpec keySpec)380throws InvalidKeySpecException {381if (serviceIterator == null) {382return spi.engineGeneratePrivate(keySpec);383}384Exception failure = null;385KeyFactorySpi mySpi = spi;386do {387try {388return mySpi.engineGeneratePrivate(keySpec);389} catch (Exception e) {390if (failure == null) {391failure = e;392}393mySpi = nextSpi(mySpi);394}395} while (mySpi != null);396if (failure instanceof RuntimeException) {397throw (RuntimeException)failure;398}399if (failure instanceof InvalidKeySpecException) {400throw (InvalidKeySpecException)failure;401}402throw new InvalidKeySpecException403("Could not generate private key", failure);404}405406/**407* Returns a specification (key material) of the given key object.408* {@code keySpec} identifies the specification class in which409* the key material should be returned. It could, for example, be410* {@code DSAPublicKeySpec.class}, to indicate that the411* key material should be returned in an instance of the412* {@code DSAPublicKeySpec} class.413*414* @param <T> the type of the key specification to be returned415*416* @param key the key.417*418* @param keySpec the specification class in which419* the key material should be returned.420*421* @return the underlying key specification (key material) in an instance422* of the requested specification class.423*424* @throws InvalidKeySpecException if the requested key specification is425* inappropriate for the given key, or the given key cannot be processed426* (e.g., the given key has an unrecognized algorithm or format).427*/428public final <T extends KeySpec> T getKeySpec(Key key, Class<T> keySpec)429throws InvalidKeySpecException {430if (serviceIterator == null) {431return spi.engineGetKeySpec(key, keySpec);432}433Exception failure = null;434KeyFactorySpi mySpi = spi;435do {436try {437return mySpi.engineGetKeySpec(key, keySpec);438} catch (Exception e) {439if (failure == null) {440failure = e;441}442mySpi = nextSpi(mySpi);443}444} while (mySpi != null);445if (failure instanceof RuntimeException) {446throw (RuntimeException)failure;447}448if (failure instanceof InvalidKeySpecException) {449throw (InvalidKeySpecException)failure;450}451throw new InvalidKeySpecException452("Could not get key spec", failure);453}454455/**456* Translates a key object, whose provider may be unknown or potentially457* untrusted, into a corresponding key object of this key factory.458*459* @param key the key whose provider is unknown or untrusted.460*461* @return the translated key.462*463* @throws InvalidKeyException if the given key cannot be processed464* by this key factory.465*/466public final Key translateKey(Key key) throws InvalidKeyException {467if (serviceIterator == null) {468return spi.engineTranslateKey(key);469}470Exception failure = null;471KeyFactorySpi mySpi = spi;472do {473try {474return mySpi.engineTranslateKey(key);475} catch (Exception e) {476if (failure == null) {477failure = e;478}479mySpi = nextSpi(mySpi);480}481} while (mySpi != null);482if (failure instanceof RuntimeException) {483throw (RuntimeException)failure;484}485if (failure instanceof InvalidKeyException) {486throw (InvalidKeyException)failure;487}488throw new InvalidKeyException489("Could not translate key", failure);490}491492}493494495