Path: blob/aarch64-shenandoah-jdk8u272-b10/jdk/src/share/classes/java/security/KeyFactory.java
38829 views
/*1* Copyright (c) 1997, 2013, 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}/../technotes/guides/security/StandardNames.html#KeyFactory">78* KeyFactory section</a> of the79* Java Cryptography Architecture Standard Algorithm Name Documentation.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* @param algorithm the name of the requested key algorithm.156* See the KeyFactory section in the <a href=157* "{@docRoot}/../technotes/guides/security/StandardNames.html#KeyFactory">158* Java Cryptography Architecture Standard Algorithm Name Documentation</a>159* for information about standard algorithm names.160*161* @return the new KeyFactory object.162*163* @exception NoSuchAlgorithmException if no Provider supports a164* KeyFactorySpi implementation for the165* specified algorithm.166*167* @see Provider168*/169public static KeyFactory getInstance(String algorithm)170throws NoSuchAlgorithmException {171return new KeyFactory(algorithm);172}173174/**175* Returns a KeyFactory object that converts176* public/private keys of the specified algorithm.177*178* <p> A new KeyFactory object encapsulating the179* KeyFactorySpi implementation from the specified provider180* is returned. The specified provider must be registered181* in the security provider list.182*183* <p> Note that the list of registered providers may be retrieved via184* the {@link Security#getProviders() Security.getProviders()} method.185*186* @param algorithm the name of the requested key algorithm.187* See the KeyFactory section in the <a href=188* "{@docRoot}/../technotes/guides/security/StandardNames.html#KeyFactory">189* Java Cryptography Architecture Standard Algorithm Name Documentation</a>190* for information about standard algorithm names.191*192* @param provider the name of the provider.193*194* @return the new KeyFactory object.195*196* @exception NoSuchAlgorithmException if a KeyFactorySpi197* implementation for the specified algorithm is not198* available from the specified provider.199*200* @exception NoSuchProviderException if the specified provider is not201* registered in the security provider list.202*203* @exception IllegalArgumentException if the provider name is null204* or empty.205*206* @see Provider207*/208public static KeyFactory getInstance(String algorithm, String provider)209throws NoSuchAlgorithmException, NoSuchProviderException {210Instance instance = GetInstance.getInstance("KeyFactory",211KeyFactorySpi.class, algorithm, provider);212return new KeyFactory((KeyFactorySpi)instance.impl,213instance.provider, algorithm);214}215216/**217* Returns a KeyFactory object that converts218* public/private keys of the specified algorithm.219*220* <p> A new KeyFactory object encapsulating the221* KeyFactorySpi implementation from the specified Provider222* object is returned. Note that the specified Provider object223* does not have to be registered in the provider list.224*225* @param algorithm the name of the requested key algorithm.226* See the KeyFactory section in the <a href=227* "{@docRoot}/../technotes/guides/security/StandardNames.html#KeyFactory">228* Java Cryptography Architecture Standard Algorithm Name Documentation</a>229* for information about standard algorithm names.230*231* @param provider the provider.232*233* @return the new KeyFactory object.234*235* @exception NoSuchAlgorithmException if a KeyFactorySpi236* implementation for the specified algorithm is not available237* from the specified Provider object.238*239* @exception IllegalArgumentException if the specified provider is null.240*241* @see Provider242*243* @since 1.4244*/245public static KeyFactory getInstance(String algorithm, Provider provider)246throws NoSuchAlgorithmException {247Instance instance = GetInstance.getInstance("KeyFactory",248KeyFactorySpi.class, algorithm, provider);249return new KeyFactory((KeyFactorySpi)instance.impl,250instance.provider, algorithm);251}252253/**254* Returns the provider of this key factory object.255*256* @return the provider of this key factory object257*/258public final Provider getProvider() {259synchronized (lock) {260// disable further failover after this call261serviceIterator = null;262return provider;263}264}265266/**267* Gets the name of the algorithm268* associated with this {@code KeyFactory}.269*270* @return the name of the algorithm associated with this271* {@code KeyFactory}272*/273public final String getAlgorithm() {274return this.algorithm;275}276277/**278* Update the active KeyFactorySpi of this class and return the next279* implementation for failover. If no more implemenations are280* available, this method returns null. However, the active spi of281* this class is never set to null.282*/283private KeyFactorySpi nextSpi(KeyFactorySpi oldSpi) {284synchronized (lock) {285// somebody else did a failover concurrently286// try that spi now287if ((oldSpi != null) && (oldSpi != spi)) {288return spi;289}290if (serviceIterator == null) {291return null;292}293while (serviceIterator.hasNext()) {294Service s = serviceIterator.next();295try {296Object obj = s.newInstance(null);297if (obj instanceof KeyFactorySpi == false) {298continue;299}300KeyFactorySpi spi = (KeyFactorySpi)obj;301provider = s.getProvider();302this.spi = spi;303return spi;304} catch (NoSuchAlgorithmException e) {305// ignore306}307}308serviceIterator = null;309return null;310}311}312313/**314* Generates a public key object from the provided key specification315* (key material).316*317* @param keySpec the specification (key material) of the public key.318*319* @return the public key.320*321* @exception InvalidKeySpecException if the given key specification322* is inappropriate for this key factory to produce a public key.323*/324public final PublicKey generatePublic(KeySpec keySpec)325throws InvalidKeySpecException {326if (serviceIterator == null) {327return spi.engineGeneratePublic(keySpec);328}329Exception failure = null;330KeyFactorySpi mySpi = spi;331do {332try {333return mySpi.engineGeneratePublic(keySpec);334} catch (Exception e) {335if (failure == null) {336failure = e;337}338mySpi = nextSpi(mySpi);339}340} while (mySpi != null);341if (failure instanceof RuntimeException) {342throw (RuntimeException)failure;343}344if (failure instanceof InvalidKeySpecException) {345throw (InvalidKeySpecException)failure;346}347throw new InvalidKeySpecException348("Could not generate public key", failure);349}350351/**352* Generates a private key object from the provided key specification353* (key material).354*355* @param keySpec the specification (key material) of the private key.356*357* @return the private key.358*359* @exception InvalidKeySpecException if the given key specification360* is inappropriate for this key factory to produce a private key.361*/362public final PrivateKey generatePrivate(KeySpec keySpec)363throws InvalidKeySpecException {364if (serviceIterator == null) {365return spi.engineGeneratePrivate(keySpec);366}367Exception failure = null;368KeyFactorySpi mySpi = spi;369do {370try {371return mySpi.engineGeneratePrivate(keySpec);372} catch (Exception e) {373if (failure == null) {374failure = e;375}376mySpi = nextSpi(mySpi);377}378} while (mySpi != null);379if (failure instanceof RuntimeException) {380throw (RuntimeException)failure;381}382if (failure instanceof InvalidKeySpecException) {383throw (InvalidKeySpecException)failure;384}385throw new InvalidKeySpecException386("Could not generate private key", failure);387}388389/**390* Returns a specification (key material) of the given key object.391* {@code keySpec} identifies the specification class in which392* the key material should be returned. It could, for example, be393* {@code DSAPublicKeySpec.class}, to indicate that the394* key material should be returned in an instance of the395* {@code DSAPublicKeySpec} class.396*397* @param <T> the type of the key specification to be returned398*399* @param key the key.400*401* @param keySpec the specification class in which402* the key material should be returned.403*404* @return the underlying key specification (key material) in an instance405* of the requested specification class.406*407* @exception InvalidKeySpecException if the requested key specification is408* inappropriate for the given key, or the given key cannot be processed409* (e.g., the given key has an unrecognized algorithm or format).410*/411public final <T extends KeySpec> T getKeySpec(Key key, Class<T> keySpec)412throws InvalidKeySpecException {413if (serviceIterator == null) {414return spi.engineGetKeySpec(key, keySpec);415}416Exception failure = null;417KeyFactorySpi mySpi = spi;418do {419try {420return mySpi.engineGetKeySpec(key, keySpec);421} catch (Exception e) {422if (failure == null) {423failure = e;424}425mySpi = nextSpi(mySpi);426}427} while (mySpi != null);428if (failure instanceof RuntimeException) {429throw (RuntimeException)failure;430}431if (failure instanceof InvalidKeySpecException) {432throw (InvalidKeySpecException)failure;433}434throw new InvalidKeySpecException435("Could not get key spec", failure);436}437438/**439* Translates a key object, whose provider may be unknown or potentially440* untrusted, into a corresponding key object of this key factory.441*442* @param key the key whose provider is unknown or untrusted.443*444* @return the translated key.445*446* @exception InvalidKeyException if the given key cannot be processed447* by this key factory.448*/449public final Key translateKey(Key key) throws InvalidKeyException {450if (serviceIterator == null) {451return spi.engineTranslateKey(key);452}453Exception failure = null;454KeyFactorySpi mySpi = spi;455do {456try {457return mySpi.engineTranslateKey(key);458} catch (Exception e) {459if (failure == null) {460failure = e;461}462mySpi = nextSpi(mySpi);463}464} while (mySpi != null);465if (failure instanceof RuntimeException) {466throw (RuntimeException)failure;467}468if (failure instanceof InvalidKeyException) {469throw (InvalidKeyException)failure;470}471throw new InvalidKeyException472("Could not translate key", failure);473}474475}476477478