Path: blob/aarch64-shenandoah-jdk8u272-b10/jdk/src/share/classes/javax/crypto/KeyAgreement.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.util.Debug;34import sun.security.jca.*;35import sun.security.jca.GetInstance.Instance;3637/**38* This class provides the functionality of a key agreement (or key39* exchange) protocol.40* <p>41* The keys involved in establishing a shared secret are created by one of the42* key generators ({@code KeyPairGenerator} or43* {@code KeyGenerator}), a {@code KeyFactory}, or as a result from44* an intermediate phase of the key agreement protocol.45*46* <p> For each of the correspondents in the key exchange, {@code doPhase}47* needs to be called. For example, if this key exchange is with one other48* party, {@code doPhase} needs to be called once, with the49* {@code lastPhase} flag set to {@code true}.50* If this key exchange is51* with two other parties, {@code doPhase} needs to be called twice,52* the first time setting the {@code lastPhase} flag to53* {@code false}, and the second time setting it to {@code true}.54* There may be any number of parties involved in a key exchange.55*56* <p> Every implementation of the Java platform is required to support the57* following standard {@code KeyAgreement} algorithm:58* <ul>59* <li>{@code DiffieHellman}</li>60* </ul>61* This algorithm is described in the <a href=62* "{@docRoot}/../technotes/guides/security/StandardNames.html#KeyAgreement">63* KeyAgreement section</a> of the64* Java Cryptography Architecture Standard Algorithm Name Documentation.65* Consult the release documentation for your implementation to see if any66* other algorithms are supported.67*68* @author Jan Luehe69*70* @see KeyGenerator71* @see SecretKey72* @since 1.473*/7475public class KeyAgreement {7677private static final Debug debug =78Debug.getInstance("jca", "KeyAgreement");7980private static final Debug pdebug =81Debug.getInstance("provider", "Provider");82private static final boolean skipDebug =83Debug.isOn("engine=") && !Debug.isOn("keyagreement");8485// The provider86private Provider provider;8788// The provider implementation (delegate)89private KeyAgreementSpi spi;9091// The name of the key agreement algorithm.92private final String algorithm;9394// next service to try in provider selection95// null once provider is selected96private Service firstService;9798// remaining services to try in provider selection99// null once provider is selected100private Iterator<Service> serviceIterator;101102private final Object lock;103104/**105* Creates a KeyAgreement object.106*107* @param keyAgreeSpi the delegate108* @param provider the provider109* @param algorithm the algorithm110*/111protected KeyAgreement(KeyAgreementSpi keyAgreeSpi, Provider provider,112String algorithm) {113this.spi = keyAgreeSpi;114this.provider = provider;115this.algorithm = algorithm;116lock = null;117}118119private KeyAgreement(Service s, Iterator<Service> t, String algorithm) {120firstService = s;121serviceIterator = t;122this.algorithm = algorithm;123lock = new Object();124}125126/**127* Returns the algorithm name of this {@code KeyAgreement} object.128*129* <p>This is the same name that was specified in one of the130* {@code getInstance} calls that created this131* {@code KeyAgreement} object.132*133* @return the algorithm name of this {@code KeyAgreement} object.134*/135public final String getAlgorithm() {136return this.algorithm;137}138139/**140* Returns a {@code KeyAgreement} object that implements the141* specified key agreement algorithm.142*143* <p> This method traverses the list of registered security Providers,144* starting with the most preferred Provider.145* A new KeyAgreement object encapsulating the146* KeyAgreementSpi implementation from the first147* Provider that supports the specified algorithm is returned.148*149* <p> Note that the list of registered providers may be retrieved via150* the {@link Security#getProviders() Security.getProviders()} method.151*152* @param algorithm the standard name of the requested key agreement153* algorithm.154* See the KeyAgreement section in the <a href=155* "{@docRoot}/../technotes/guides/security/StandardNames.html#KeyAgreement">156* Java Cryptography Architecture Standard Algorithm Name Documentation</a>157* for information about standard algorithm names.158*159* @return the new {@code KeyAgreement} object.160*161* @exception NullPointerException if the specified algorithm162* is null.163*164* @exception NoSuchAlgorithmException if no Provider supports a165* KeyAgreementSpi implementation for the166* specified algorithm.167*168* @see java.security.Provider169*/170public static final KeyAgreement getInstance(String algorithm)171throws NoSuchAlgorithmException {172List<Service> services =173GetInstance.getServices("KeyAgreement", algorithm);174// make sure there is at least one service from a signed provider175Iterator<Service> t = services.iterator();176while (t.hasNext()) {177Service s = t.next();178if (JceSecurity.canUseProvider(s.getProvider()) == false) {179continue;180}181return new KeyAgreement(s, t, algorithm);182}183throw new NoSuchAlgorithmException184("Algorithm " + algorithm + " not available");185}186187/**188* Returns a {@code KeyAgreement} object that implements the189* specified key agreement algorithm.190*191* <p> A new KeyAgreement object encapsulating the192* KeyAgreementSpi implementation from the specified provider193* is returned. The specified provider must be registered194* in the security provider list.195*196* <p> Note that the list of registered providers may be retrieved via197* the {@link Security#getProviders() Security.getProviders()} method.198*199* @param algorithm the standard name of the requested key agreement200* algorithm.201* See the KeyAgreement section in the <a href=202* "{@docRoot}/../technotes/guides/security/StandardNames.html#KeyAgreement">203* Java Cryptography Architecture Standard Algorithm Name Documentation</a>204* for information about standard algorithm names.205*206* @param provider the name of the provider.207*208* @return the new {@code KeyAgreement} object.209*210* @exception NullPointerException if the specified algorithm211* is null.212*213* @exception NoSuchAlgorithmException if a KeyAgreementSpi214* implementation for the specified algorithm is not215* available from the specified provider.216*217* @exception NoSuchProviderException if the specified provider is not218* registered in the security provider list.219*220* @exception IllegalArgumentException if the {@code provider}221* is null or empty.222*223* @see java.security.Provider224*/225public static final KeyAgreement getInstance(String algorithm,226String provider) throws NoSuchAlgorithmException,227NoSuchProviderException {228Instance instance = JceSecurity.getInstance229("KeyAgreement", KeyAgreementSpi.class, algorithm, provider);230return new KeyAgreement((KeyAgreementSpi)instance.impl,231instance.provider, algorithm);232}233234/**235* Returns a {@code KeyAgreement} object that implements the236* specified key agreement algorithm.237*238* <p> A new KeyAgreement object encapsulating the239* KeyAgreementSpi implementation from the specified Provider240* object is returned. Note that the specified Provider object241* does not have to be registered in the provider list.242*243* @param algorithm the standard name of the requested key agreement244* algorithm.245* See the KeyAgreement section in the <a href=246* "{@docRoot}/../technotes/guides/security/StandardNames.html#KeyAgreement">247* Java Cryptography Architecture Standard Algorithm Name Documentation</a>248* for information about standard algorithm names.249*250* @param provider the provider.251*252* @return the new {@code KeyAgreement} object.253*254* @exception NullPointerException if the specified algorithm255* is null.256*257* @exception NoSuchAlgorithmException if a KeyAgreementSpi258* implementation for the specified algorithm is not available259* from the specified Provider object.260*261* @exception IllegalArgumentException if the {@code provider}262* is null.263*264* @see java.security.Provider265*/266public static final KeyAgreement getInstance(String algorithm,267Provider provider) throws NoSuchAlgorithmException {268Instance instance = JceSecurity.getInstance269("KeyAgreement", KeyAgreementSpi.class, algorithm, provider);270return new KeyAgreement((KeyAgreementSpi)instance.impl,271instance.provider, algorithm);272}273274// max number of debug warnings to print from chooseFirstProvider()275private static int warnCount = 10;276277/**278* Choose the Spi from the first provider available. Used if279* delayed provider selection is not possible because init()280* is not the first method called.281*/282void chooseFirstProvider() {283if (spi != null) {284return;285}286synchronized (lock) {287if (spi != null) {288return;289}290if (debug != null) {291int w = --warnCount;292if (w >= 0) {293debug.println("KeyAgreement.init() not first method "294+ "called, disabling delayed provider selection");295if (w == 0) {296debug.println("Further warnings of this type will "297+ "be suppressed");298}299new Exception("Call trace").printStackTrace();300}301}302Exception lastException = null;303while ((firstService != null) || serviceIterator.hasNext()) {304Service s;305if (firstService != null) {306s = firstService;307firstService = null;308} else {309s = serviceIterator.next();310}311if (JceSecurity.canUseProvider(s.getProvider()) == false) {312continue;313}314try {315Object obj = s.newInstance(null);316if (obj instanceof KeyAgreementSpi == false) {317continue;318}319spi = (KeyAgreementSpi)obj;320provider = s.getProvider();321// not needed any more322firstService = null;323serviceIterator = null;324return;325} catch (Exception e) {326lastException = e;327}328}329ProviderException e = new ProviderException330("Could not construct KeyAgreementSpi instance");331if (lastException != null) {332e.initCause(lastException);333}334throw e;335}336}337338private final static int I_NO_PARAMS = 1;339private final static int I_PARAMS = 2;340341private void implInit(KeyAgreementSpi spi, int type, Key key,342AlgorithmParameterSpec params, SecureRandom random)343throws InvalidKeyException, InvalidAlgorithmParameterException {344if (type == I_NO_PARAMS) {345spi.engineInit(key, random);346} else { // I_PARAMS347spi.engineInit(key, params, random);348}349}350351private void chooseProvider(int initType, Key key,352AlgorithmParameterSpec params, SecureRandom random)353throws InvalidKeyException, InvalidAlgorithmParameterException {354synchronized (lock) {355if (spi != null) {356implInit(spi, initType, key, params, random);357return;358}359Exception lastException = null;360while ((firstService != null) || serviceIterator.hasNext()) {361Service s;362if (firstService != null) {363s = firstService;364firstService = null;365} else {366s = serviceIterator.next();367}368// if provider says it does not support this key, ignore it369if (s.supportsParameter(key) == false) {370continue;371}372if (JceSecurity.canUseProvider(s.getProvider()) == false) {373continue;374}375try {376KeyAgreementSpi spi = (KeyAgreementSpi)s.newInstance(null);377implInit(spi, initType, key, params, random);378provider = s.getProvider();379this.spi = spi;380firstService = null;381serviceIterator = null;382return;383} catch (Exception e) {384// NoSuchAlgorithmException from newInstance()385// InvalidKeyException from init()386// RuntimeException (ProviderException) from init()387if (lastException == null) {388lastException = e;389}390}391}392// no working provider found, fail393if (lastException instanceof InvalidKeyException) {394throw (InvalidKeyException)lastException;395}396if (lastException instanceof InvalidAlgorithmParameterException) {397throw (InvalidAlgorithmParameterException)lastException;398}399if (lastException instanceof RuntimeException) {400throw (RuntimeException)lastException;401}402String kName = (key != null) ? key.getClass().getName() : "(null)";403throw new InvalidKeyException404("No installed provider supports this key: "405+ kName, lastException);406}407}408409/**410* Returns the provider of this {@code KeyAgreement} object.411*412* @return the provider of this {@code KeyAgreement} object413*/414public final Provider getProvider() {415chooseFirstProvider();416return this.provider;417}418419/**420* Initializes this key agreement with the given key, which is required to421* contain all the algorithm parameters required for this key agreement.422*423* <p> If this key agreement requires any random bytes, it will get424* them using the425* {@link java.security.SecureRandom}426* implementation of the highest-priority427* installed provider as the source of randomness.428* (If none of the installed providers supply an implementation of429* SecureRandom, a system-provided source of randomness will be used.)430*431* @param key the party's private information. For example, in the case432* of the Diffie-Hellman key agreement, this would be the party's own433* Diffie-Hellman private key.434*435* @exception InvalidKeyException if the given key is436* inappropriate for this key agreement, e.g., is of the wrong type or437* has an incompatible algorithm type.438*/439public final void init(Key key) throws InvalidKeyException {440init(key, JceSecurity.RANDOM);441}442443/**444* Initializes this key agreement with the given key and source of445* randomness. The given key is required to contain all the algorithm446* parameters required for this key agreement.447*448* <p> If the key agreement algorithm requires random bytes, it gets them449* from the given source of randomness, {@code random}.450* However, if the underlying451* algorithm implementation does not require any random bytes,452* {@code random} is ignored.453*454* @param key the party's private information. For example, in the case455* of the Diffie-Hellman key agreement, this would be the party's own456* Diffie-Hellman private key.457* @param random the source of randomness458*459* @exception InvalidKeyException if the given key is460* inappropriate for this key agreement, e.g., is of the wrong type or461* has an incompatible algorithm type.462*/463public final void init(Key key, SecureRandom random)464throws InvalidKeyException {465if (spi != null) {466spi.engineInit(key, random);467} else {468try {469chooseProvider(I_NO_PARAMS, key, null, random);470} catch (InvalidAlgorithmParameterException e) {471// should never occur472throw new InvalidKeyException(e);473}474}475476if (!skipDebug && pdebug != null) {477pdebug.println("KeyAgreement." + algorithm + " algorithm from: " +478this.provider.getName());479}480}481482/**483* Initializes this key agreement with the given key and set of484* algorithm parameters.485*486* <p> If this key agreement requires any random bytes, it will get487* them using the488* {@link java.security.SecureRandom}489* implementation of the highest-priority490* installed provider as the source of randomness.491* (If none of the installed providers supply an implementation of492* SecureRandom, a system-provided source of randomness will be used.)493*494* @param key the party's private information. For example, in the case495* of the Diffie-Hellman key agreement, this would be the party's own496* Diffie-Hellman private key.497* @param params the key agreement parameters498*499* @exception InvalidKeyException if the given key is500* inappropriate for this key agreement, e.g., is of the wrong type or501* has an incompatible algorithm type.502* @exception InvalidAlgorithmParameterException if the given parameters503* are inappropriate for this key agreement.504*/505public final void init(Key key, AlgorithmParameterSpec params)506throws InvalidKeyException, InvalidAlgorithmParameterException507{508init(key, params, JceSecurity.RANDOM);509}510511/**512* Initializes this key agreement with the given key, set of513* algorithm parameters, and source of randomness.514*515* @param key the party's private information. For example, in the case516* of the Diffie-Hellman key agreement, this would be the party's own517* Diffie-Hellman private key.518* @param params the key agreement parameters519* @param random the source of randomness520*521* @exception InvalidKeyException if the given key is522* inappropriate for this key agreement, e.g., is of the wrong type or523* has an incompatible algorithm type.524* @exception InvalidAlgorithmParameterException if the given parameters525* are inappropriate for this key agreement.526*/527public final void init(Key key, AlgorithmParameterSpec params,528SecureRandom random)529throws InvalidKeyException, InvalidAlgorithmParameterException530{531if (spi != null) {532spi.engineInit(key, params, random);533} else {534chooseProvider(I_PARAMS, key, params, random);535}536537if (!skipDebug && pdebug != null) {538pdebug.println("KeyAgreement." + algorithm + " algorithm from: " +539this.provider.getName());540}541}542543/**544* Executes the next phase of this key agreement with the given545* key that was received from one of the other parties involved in this key546* agreement.547*548* @param key the key for this phase. For example, in the case of549* Diffie-Hellman between 2 parties, this would be the other party's550* Diffie-Hellman public key.551* @param lastPhase flag which indicates whether or not this is the last552* phase of this key agreement.553*554* @return the (intermediate) key resulting from this phase, or null555* if this phase does not yield a key556*557* @exception InvalidKeyException if the given key is inappropriate for558* this phase.559* @exception IllegalStateException if this key agreement has not been560* initialized.561*/562public final Key doPhase(Key key, boolean lastPhase)563throws InvalidKeyException, IllegalStateException564{565chooseFirstProvider();566return spi.engineDoPhase(key, lastPhase);567}568569/**570* Generates the shared secret and returns it in a new buffer.571*572* <p>This method resets this {@code KeyAgreement} object, so that it573* can be reused for further key agreements. Unless this key agreement is574* reinitialized with one of the {@code init} methods, the same575* private information and algorithm parameters will be used for576* subsequent key agreements.577*578* @return the new buffer with the shared secret579*580* @exception IllegalStateException if this key agreement has not been581* completed yet582*/583public final byte[] generateSecret() throws IllegalStateException {584chooseFirstProvider();585return spi.engineGenerateSecret();586}587588/**589* Generates the shared secret, and places it into the buffer590* {@code sharedSecret}, beginning at {@code offset} inclusive.591*592* <p>If the {@code sharedSecret} buffer is too small to hold the593* result, a {@code ShortBufferException} is thrown.594* In this case, this call should be repeated with a larger output buffer.595*596* <p>This method resets this {@code KeyAgreement} object, so that it597* can be reused for further key agreements. Unless this key agreement is598* reinitialized with one of the {@code init} methods, the same599* private information and algorithm parameters will be used for600* subsequent key agreements.601*602* @param sharedSecret the buffer for the shared secret603* @param offset the offset in {@code sharedSecret} where the604* shared secret will be stored605*606* @return the number of bytes placed into {@code sharedSecret}607*608* @exception IllegalStateException if this key agreement has not been609* completed yet610* @exception ShortBufferException if the given output buffer is too small611* to hold the secret612*/613public final int generateSecret(byte[] sharedSecret, int offset)614throws IllegalStateException, ShortBufferException615{616chooseFirstProvider();617return spi.engineGenerateSecret(sharedSecret, offset);618}619620/**621* Creates the shared secret and returns it as a {@code SecretKey}622* object of the specified algorithm.623*624* <p>This method resets this {@code KeyAgreement} object, so that it625* can be reused for further key agreements. Unless this key agreement is626* reinitialized with one of the {@code init} methods, the same627* private information and algorithm parameters will be used for628* subsequent key agreements.629*630* @param algorithm the requested secret-key algorithm631*632* @return the shared secret key633*634* @exception IllegalStateException if this key agreement has not been635* completed yet636* @exception NoSuchAlgorithmException if the specified secret-key637* algorithm is not available638* @exception InvalidKeyException if the shared secret-key material cannot639* be used to generate a secret key of the specified algorithm (e.g.,640* the key material is too short)641*/642public final SecretKey generateSecret(String algorithm)643throws IllegalStateException, NoSuchAlgorithmException,644InvalidKeyException645{646chooseFirstProvider();647return spi.engineGenerateSecret(algorithm);648}649}650651652