1 /*
2  * Copyright (C) 2014 The Android Open Source Project
3  * Copyright (c) 1997, 2017, Oracle and/or its affiliates. All rights reserved.
4  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5  *
6  * This code is free software; you can redistribute it and/or modify it
7  * under the terms of the GNU General Public License version 2 only, as
8  * published by the Free Software Foundation.  Oracle designates this
9  * particular file as subject to the "Classpath" exception as provided
10  * by Oracle in the LICENSE file that accompanied this code.
11  *
12  * This code is distributed in the hope that it will be useful, but WITHOUT
13  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
15  * version 2 for more details (a copy is included in the LICENSE file that
16  * accompanied this code).
17  *
18  * You should have received a copy of the GNU General Public License version
19  * 2 along with this work; if not, write to the Free Software Foundation,
20  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
21  *
22  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
23  * or visit www.oracle.com if you need additional information or have any
24  * questions.
25  */
26 
27 package javax.crypto;
28 
29 import java.util.*;
30 
31 import java.security.*;
32 import java.security.Provider.Service;
33 import java.security.spec.*;
34 
35 import sun.security.jca.*;
36 import sun.security.jca.GetInstance.Instance;
37 
38 /**
39  * This class provides the functionality of a key agreement (or key
40  * exchange) protocol.
41  * <p>
42  * The keys involved in establishing a shared secret are created by one of the
43  * key generators ({@code KeyPairGenerator} or
44  * {@code KeyGenerator}), a {@code KeyFactory}, or as a result from
45  * an intermediate phase of the key agreement protocol.
46  *
47  * <p> For each of the correspondents in the key exchange, {@code doPhase}
48  * needs to be called. For example, if this key exchange is with one other
49  * party, {@code doPhase} needs to be called once, with the
50  * {@code lastPhase} flag set to {@code true}.
51  * If this key exchange is
52  * with two other parties, {@code doPhase} needs to be called twice,
53  * the first time setting the {@code lastPhase} flag to
54  * {@code false}, and the second time setting it to {@code true}.
55  * There may be any number of parties involved in a key exchange.
56  *
57  * <p> Android provides the following <code>KeyAgreement</code> algorithms:
58  * <table>
59  *   <thead>
60  *     <tr>
61  *       <th>Algorithm</th>
62  *       <th>Supported API Levels</th>
63  *     </tr>
64  *   </thead>
65  *   <tbody>
66  *     <tr>
67  *       <td>DH</td>
68  *       <td>1+</td>
69  *     </tr>
70  *     <tr>
71  *       <td>ECDH</td>
72  *       <td>11+</td>
73  *     </tr>
74  *     <tr>
75  *       <td>XDH</td>
76  *       <td>33+</td>
77  *     </tr>
78  *   </tbody>
79  * </table>
80  *
81  * This algorithm is described in the <a href=
82  * "{@docRoot}/../specs/security/standard-names.html#keyagreement-algorithms">
83  * KeyAgreement section</a> of the
84  * Java Cryptography Architecture Standard Algorithm Name Documentation.
85  *
86  * @author Jan Luehe
87  *
88  * @see KeyGenerator
89  * @see SecretKey
90  * @since 1.4
91  */
92 
93 public class KeyAgreement {
94 
95     // Android-removed: this debugging mechanism is not used in Android.
96     /*
97     private static final Debug debug =
98                         Debug.getInstance("jca", "KeyAgreement");
99 
100     private static final Debug pdebug =
101                         Debug.getInstance("provider", "Provider");
102     private static final boolean skipDebug =
103         Debug.isOn("engine=") && !Debug.isOn("keyagreement");
104     */
105 
106     // The provider
107     private Provider provider;
108 
109     // The provider implementation (delegate)
110     private KeyAgreementSpi spi;
111 
112     // The name of the key agreement algorithm.
113     private final String algorithm;
114 
115     // BEGIN Android-removed: Redo the provider selection logic to allow reselecting provider.
116     // When only the algorithm is specified, we want to allow the KeyAgreement provider for that
117     // algorithm to change if multiple providers exist and they support different subsets of
118     // keys.  To that end, we don't hold an iterator and exhaust it when we need to choose
119     // a provider like the upstream implementation, we reestablish the list of providers
120     // each time.
121     /*
122     // next service to try in provider selection
123     // null once provider is selected
124     private Service firstService;
125 
126     // remaining services to try in provider selection
127     // null once provider is selected
128     private Iterator<Service> serviceIterator;
129     */
130     // END Android-removed: Redo the provider selection logic to allow reselecting provider.
131 
132     private final Object lock;
133 
134     /**
135      * Creates a KeyAgreement object.
136      *
137      * @param keyAgreeSpi the delegate
138      * @param provider the provider
139      * @param algorithm the algorithm
140      */
KeyAgreement(KeyAgreementSpi keyAgreeSpi, Provider provider, String algorithm)141     protected KeyAgreement(KeyAgreementSpi keyAgreeSpi, Provider provider,
142                            String algorithm) {
143         this.spi = keyAgreeSpi;
144         this.provider = provider;
145         this.algorithm = algorithm;
146         lock = null;
147     }
148 
149     // Android-changed: Remove Service and Iterator from constructor args.
KeyAgreement(String algorithm)150     private KeyAgreement(String algorithm) {
151         this.algorithm = algorithm;
152         lock = new Object();
153     }
154 
155     /**
156      * Returns the algorithm name of this {@code KeyAgreement} object.
157      *
158      * <p>This is the same name that was specified in one of the
159      * {@code getInstance} calls that created this
160      * {@code KeyAgreement} object.
161      *
162      * @return the algorithm name of this {@code KeyAgreement} object.
163      */
getAlgorithm()164     public final String getAlgorithm() {
165         return this.algorithm;
166     }
167 
168     /**
169      * Returns a {@code KeyAgreement} object that implements the
170      * specified key agreement algorithm.
171      *
172      * <p> This method traverses the list of registered security Providers,
173      * starting with the most preferred Provider.
174      * A new KeyAgreement object encapsulating the
175      * KeyAgreementSpi implementation from the first
176      * Provider that supports the specified algorithm is returned.
177      *
178      * <p> Note that the list of registered providers may be retrieved via
179      * the {@link Security#getProviders() Security.getProviders()} method.
180      *
181      * @param algorithm the standard name of the requested key agreement
182      * algorithm.
183      * See the KeyAgreement section in the <a href=
184      * "{@docRoot}/../specs/security/standard-names.html#keyagreement-algorithms">
185      * Java Security Standard Algorithm Names Specification</a>
186      * for information about standard algorithm names.
187      *
188      * @return the new {@code KeyAgreement} object
189      *
190      * @exception NullPointerException if the specified algorithm
191      *          is null.
192      *
193      * @exception NoSuchAlgorithmException if no Provider supports a
194      *          KeyAgreementSpi implementation for the
195      *          specified algorithm.
196      *
197      * @see java.security.Provider
198      */
getInstance(String algorithm)199     public static final KeyAgreement getInstance(String algorithm)
200             throws NoSuchAlgorithmException {
201         List<Service> services =
202                 GetInstance.getServices("KeyAgreement", algorithm);
203         // make sure there is at least one service from a signed provider
204         Iterator<Service> t = services.iterator();
205         while (t.hasNext()) {
206             Service s = t.next();
207             if (JceSecurity.canUseProvider(s.getProvider()) == false) {
208                 continue;
209             }
210             // Android-changed: Remove Service and Iterator from constructor args.
211             // return new KeyAgreement(s, t, algorithm);
212             return new KeyAgreement(algorithm);
213         }
214         throw new NoSuchAlgorithmException
215                                 ("Algorithm " + algorithm + " not available");
216     }
217 
218     /**
219      * Returns a {@code KeyAgreement} object that implements the
220      * specified key agreement algorithm.
221      *
222      * <p> A new KeyAgreement object encapsulating the
223      * KeyAgreementSpi implementation from the specified provider
224      * is returned.  The specified provider must be registered
225      * in the security provider list.
226      *
227      * <p> Note that the list of registered providers may be retrieved via
228      * the {@link Security#getProviders() Security.getProviders()} method.
229      *
230      * @param algorithm the standard name of the requested key agreement
231      * algorithm.
232      * See the KeyAgreement section in the <a href=
233      * "{@docRoot}/../specs/security/standard-names.html#keyagreement-algorithms">
234      * Java Security Standard Algorithm Names Specification</a>
235      * for information about standard algorithm names.
236      *
237      * @param provider the name of the provider.
238      *
239      * @return the new {@code KeyAgreement} object
240      *
241      * @exception NullPointerException if the specified algorithm
242      *          is null.
243      *
244      * @exception NoSuchAlgorithmException if a KeyAgreementSpi
245      *          implementation for the specified algorithm is not
246      *          available from the specified provider.
247      *
248      * @exception NoSuchProviderException if the specified provider is not
249      *          registered in the security provider list.
250      *
251      * @exception IllegalArgumentException if the <code>provider</code>
252      *          is null or empty.
253      *
254      * @see java.security.Provider
255      */
getInstance(String algorithm, String provider)256     public static final KeyAgreement getInstance(String algorithm,
257             String provider) throws NoSuchAlgorithmException,
258             NoSuchProviderException {
259         // Android-added: Check for Bouncy Castle deprecation
260         Providers.checkBouncyCastleDeprecation(provider, "KeyAgreement", algorithm);
261         Instance instance = JceSecurity.getInstance
262                 ("KeyAgreement", KeyAgreementSpi.class, algorithm, provider);
263         return new KeyAgreement((KeyAgreementSpi)instance.impl,
264                 instance.provider, algorithm);
265     }
266 
267     /**
268      * Returns a {@code KeyAgreement} object that implements the
269      * specified key agreement algorithm.
270      *
271      * <p> A new KeyAgreement object encapsulating the
272      * KeyAgreementSpi implementation from the specified Provider
273      * object is returned.  Note that the specified Provider object
274      * does not have to be registered in the provider list.
275      *
276      * @param algorithm the standard name of the requested key agreement
277      * algorithm.
278      * See the KeyAgreement section in the <a href=
279      * "{@docRoot}/../specs/security/standard-names.html#keyagreement-algorithms">
280      * Java Security Standard Algorithm Names Specification</a>
281      * for information about standard algorithm names.
282      *
283      * @param provider the provider.
284      *
285      * @return the new {@code KeyAgreement} object
286      *
287      * @exception NullPointerException if the specified algorithm
288      *          is null.
289      *
290      * @exception NoSuchAlgorithmException if a KeyAgreementSpi
291      *          implementation for the specified algorithm is not available
292      *          from the specified Provider object.
293      *
294      * @exception IllegalArgumentException if the <code>provider</code>
295      *          is null.
296      *
297      * @see java.security.Provider
298      */
getInstance(String algorithm, Provider provider)299     public static final KeyAgreement getInstance(String algorithm,
300             Provider provider) throws NoSuchAlgorithmException {
301         // Android-added: Check for Bouncy Castle deprecation
302         Providers.checkBouncyCastleDeprecation(provider, "KeyAgreement", algorithm);
303         Instance instance = JceSecurity.getInstance
304                 ("KeyAgreement", KeyAgreementSpi.class, algorithm, provider);
305         return new KeyAgreement((KeyAgreementSpi)instance.impl,
306                 instance.provider, algorithm);
307     }
308 
309     // max number of debug warnings to print from chooseFirstProvider()
310     private static int warnCount = 10;
311 
312     /**
313      * Choose the Spi from the first provider available. Used if
314      * delayed provider selection is not possible because init()
315      * is not the first method called.
316      */
chooseFirstProvider()317     void chooseFirstProvider() {
318         if (spi != null) {
319             return;
320         }
321         synchronized (lock) {
322             if (spi != null) {
323                 return;
324             }
325             // Android-removed: this debugging mechanism is not used in Android.
326             /*
327             if (debug != null) {
328                 int w = --warnCount;
329                 if (w >= 0) {
330                     debug.println("KeyAgreement.init() not first method "
331                         + "called, disabling delayed provider selection");
332                     if (w == 0) {
333                         debug.println("Further warnings of this type will "
334                             + "be suppressed");
335                     }
336                     new Exception("Call trace").printStackTrace();
337                 }
338             }
339             */
340             Exception lastException = null;
341             // Android-changed: Provider selection; loop over a new list each time.
342             for (Service s : GetInstance.getServices("KeyAgreement", algorithm)) {
343                 if (JceSecurity.canUseProvider(s.getProvider()) == false) {
344                     continue;
345                 }
346                 try {
347                     Object obj = s.newInstance(null);
348                     if (obj instanceof KeyAgreementSpi == false) {
349                         continue;
350                     }
351                     spi = (KeyAgreementSpi)obj;
352                     provider = s.getProvider();
353                     // Android-removed: Provider selection; loop over a new list each time.
354                     /*
355                     // not needed any more
356                     firstService = null;
357                     serviceIterator = null;
358                     */
359                     return;
360                 } catch (Exception e) {
361                     lastException = e;
362                 }
363             }
364             ProviderException e = new ProviderException
365                     ("Could not construct KeyAgreementSpi instance");
366             if (lastException != null) {
367                 e.initCause(lastException);
368             }
369             throw e;
370         }
371     }
372 
373     private static final int I_NO_PARAMS = 1;
374     private static final int I_PARAMS    = 2;
375 
implInit(KeyAgreementSpi spi, int type, Key key, AlgorithmParameterSpec params, SecureRandom random)376     private void implInit(KeyAgreementSpi spi, int type, Key key,
377             AlgorithmParameterSpec params, SecureRandom random)
378             throws InvalidKeyException, InvalidAlgorithmParameterException {
379         if (type == I_NO_PARAMS) {
380             spi.engineInit(key, random);
381         } else { // I_PARAMS
382             spi.engineInit(key, params, random);
383         }
384     }
385 
chooseProvider(int initType, Key key, AlgorithmParameterSpec params, SecureRandom random)386     private void chooseProvider(int initType, Key key,
387             AlgorithmParameterSpec params, SecureRandom random)
388             throws InvalidKeyException, InvalidAlgorithmParameterException {
389         synchronized (lock) {
390             // Android-changed: Use the currently-selected provider only if no key was provided.
391             // if (spi != null) {
392             if (spi != null && key == null) {
393                 implInit(spi, initType, key, params, random);
394                 return;
395             }
396             Exception lastException = null;
397             // Android-changed: Provider selection; loop over a new list each time.
398             for (Service s : GetInstance.getServices("KeyAgreement", algorithm)) {
399                 // if provider says it does not support this key, ignore it
400                 if (s.supportsParameter(key) == false) {
401                     continue;
402                 }
403                 if (JceSecurity.canUseProvider(s.getProvider()) == false) {
404                     continue;
405                 }
406                 try {
407                     KeyAgreementSpi spi = (KeyAgreementSpi)s.newInstance(null);
408                     implInit(spi, initType, key, params, random);
409                     provider = s.getProvider();
410                     this.spi = spi;
411                     // Android-removed: Provider selection; loop over a new list each time.
412                     /*
413                     firstService = null;
414                     serviceIterator = null;
415                     */
416                     return;
417                 } catch (Exception e) {
418                     // NoSuchAlgorithmException from newInstance()
419                     // InvalidKeyException from init()
420                     // RuntimeException (ProviderException) from init()
421                     if (lastException == null) {
422                         lastException = e;
423                     }
424                 }
425             }
426             // no working provider found, fail
427             if (lastException instanceof InvalidKeyException) {
428                 throw (InvalidKeyException)lastException;
429             }
430             if (lastException instanceof InvalidAlgorithmParameterException) {
431                 throw (InvalidAlgorithmParameterException)lastException;
432             }
433             if (lastException instanceof RuntimeException) {
434                 throw (RuntimeException)lastException;
435             }
436             String kName = (key != null) ? key.getClass().getName() : "(null)";
437             throw new InvalidKeyException
438                 ("No installed provider supports this key: "
439                 + kName, lastException);
440         }
441     }
442 
443     /**
444      * Returns the provider of this {@code KeyAgreement} object.
445      *
446      * @return the provider of this {@code KeyAgreement} object
447      */
getProvider()448     public final Provider getProvider() {
449         chooseFirstProvider();
450         return this.provider;
451     }
452 
453     /**
454      * Initializes this key agreement with the given key, which is required to
455      * contain all the algorithm parameters required for this key agreement.
456      *
457      * <p> If this key agreement requires any random bytes, it will get
458      * them using the
459      * {@link java.security.SecureRandom}
460      * implementation of the highest-priority
461      * installed provider as the source of randomness.
462      * (If none of the installed providers supply an implementation of
463      * SecureRandom, a system-provided source of randomness will be used.)
464      *
465      * @param key the party's private information. For example, in the case
466      * of the Diffie-Hellman key agreement, this would be the party's own
467      * Diffie-Hellman private key.
468      *
469      * @exception InvalidKeyException if the given key is
470      * inappropriate for this key agreement, e.g., is of the wrong type or
471      * has an incompatible algorithm type.
472      */
init(Key key)473     public final void init(Key key) throws InvalidKeyException {
474         init(key, JceSecurity.RANDOM);
475     }
476 
477     /**
478      * Initializes this key agreement with the given key and source of
479      * randomness. The given key is required to contain all the algorithm
480      * parameters required for this key agreement.
481      *
482      * <p> If the key agreement algorithm requires random bytes, it gets them
483      * from the given source of randomness, {@code random}.
484      * However, if the underlying
485      * algorithm implementation does not require any random bytes,
486      * {@code random} is ignored.
487      *
488      * @param key the party's private information. For example, in the case
489      * of the Diffie-Hellman key agreement, this would be the party's own
490      * Diffie-Hellman private key.
491      * @param random the source of randomness
492      *
493      * @exception InvalidKeyException if the given key is
494      * inappropriate for this key agreement, e.g., is of the wrong type or
495      * has an incompatible algorithm type.
496      */
init(Key key, SecureRandom random)497     public final void init(Key key, SecureRandom random)
498             throws InvalidKeyException {
499         // Android-changed: Use the currently-selected provider only if no key was provided.
500         // if (spi != null) {
501         if (spi != null && (key == null || lock == null)) {
502             spi.engineInit(key, random);
503         } else {
504             try {
505                 chooseProvider(I_NO_PARAMS, key, null, random);
506             } catch (InvalidAlgorithmParameterException e) {
507                 // should never occur
508                 throw new InvalidKeyException(e);
509             }
510         }
511 
512         // Android-removed: this debugging mechanism is not used in Android.
513         /*
514         if (!skipDebug && pdebug != null) {
515             pdebug.println("KeyAgreement." + algorithm + " algorithm from: " +
516                 getProviderName());
517         }
518         */
519     }
520 
521     /**
522      * Initializes this key agreement with the given key and set of
523      * algorithm parameters.
524      *
525      * <p> If this key agreement requires any random bytes, it will get
526      * them using the
527      * {@link java.security.SecureRandom}
528      * implementation of the highest-priority
529      * installed provider as the source of randomness.
530      * (If none of the installed providers supply an implementation of
531      * SecureRandom, a system-provided source of randomness will be used.)
532      *
533      * @param key the party's private information. For example, in the case
534      * of the Diffie-Hellman key agreement, this would be the party's own
535      * Diffie-Hellman private key.
536      * @param params the key agreement parameters
537      *
538      * @exception InvalidKeyException if the given key is
539      * inappropriate for this key agreement, e.g., is of the wrong type or
540      * has an incompatible algorithm type.
541      * @exception InvalidAlgorithmParameterException if the given parameters
542      * are inappropriate for this key agreement.
543      */
init(Key key, AlgorithmParameterSpec params)544     public final void init(Key key, AlgorithmParameterSpec params)
545         throws InvalidKeyException, InvalidAlgorithmParameterException
546     {
547         init(key, params, JceSecurity.RANDOM);
548     }
549 
getProviderName()550     private String getProviderName() {
551         return (provider == null) ? "(no provider)" : provider.getName();
552     }
553 
554     /**
555      * Initializes this key agreement with the given key, set of
556      * algorithm parameters, and source of randomness.
557      *
558      * @param key the party's private information. For example, in the case
559      * of the Diffie-Hellman key agreement, this would be the party's own
560      * Diffie-Hellman private key.
561      * @param params the key agreement parameters
562      * @param random the source of randomness
563      *
564      * @exception InvalidKeyException if the given key is
565      * inappropriate for this key agreement, e.g., is of the wrong type or
566      * has an incompatible algorithm type.
567      * @exception InvalidAlgorithmParameterException if the given parameters
568      * are inappropriate for this key agreement.
569      */
init(Key key, AlgorithmParameterSpec params, SecureRandom random)570     public final void init(Key key, AlgorithmParameterSpec params,
571                            SecureRandom random)
572         throws InvalidKeyException, InvalidAlgorithmParameterException
573     {
574         if (spi != null) {
575             spi.engineInit(key, params, random);
576         } else {
577             chooseProvider(I_PARAMS, key, params, random);
578         }
579 
580         // Android-removed: this debugging mechanism is not used in Android.
581         /*
582         if (!skipDebug && pdebug != null) {
583             pdebug.println("KeyAgreement." + algorithm + " algorithm from: " +
584                 getProviderName());
585         }
586         */
587     }
588 
589     /**
590      * Executes the next phase of this key agreement with the given
591      * key that was received from one of the other parties involved in this key
592      * agreement.
593      *
594      * @param key the key for this phase. For example, in the case of
595      * Diffie-Hellman between 2 parties, this would be the other party's
596      * Diffie-Hellman public key.
597      * @param lastPhase flag which indicates whether or not this is the last
598      * phase of this key agreement.
599      *
600      * @return the (intermediate) key resulting from this phase, or null
601      * if this phase does not yield a key
602      *
603      * @exception InvalidKeyException if the given key is inappropriate for
604      * this phase.
605      * @exception IllegalStateException if this key agreement has not been
606      * initialized.
607      */
doPhase(Key key, boolean lastPhase)608     public final Key doPhase(Key key, boolean lastPhase)
609         throws InvalidKeyException, IllegalStateException
610     {
611         chooseFirstProvider();
612         return spi.engineDoPhase(key, lastPhase);
613     }
614 
615     /**
616      * Generates the shared secret and returns it in a new buffer.
617      *
618      * <p>This method resets this {@code KeyAgreement} object, so that it
619      * can be reused for further key agreements. Unless this key agreement is
620      * reinitialized with one of the {@code init} methods, the same
621      * private information and algorithm parameters will be used for
622      * subsequent key agreements.
623      *
624      * @return the new buffer with the shared secret
625      *
626      * @exception IllegalStateException if this key agreement has not been
627      * completed yet
628      */
generateSecret()629     public final byte[] generateSecret() throws IllegalStateException {
630         chooseFirstProvider();
631         return spi.engineGenerateSecret();
632     }
633 
634     /**
635      * Generates the shared secret, and places it into the buffer
636      * {@code sharedSecret}, beginning at {@code offset} inclusive.
637      *
638      * <p>If the {@code sharedSecret} buffer is too small to hold the
639      * result, a {@code ShortBufferException} is thrown.
640      * In this case, this call should be repeated with a larger output buffer.
641      *
642      * <p>This method resets this {@code KeyAgreement} object, so that it
643      * can be reused for further key agreements. Unless this key agreement is
644      * reinitialized with one of the {@code init} methods, the same
645      * private information and algorithm parameters will be used for
646      * subsequent key agreements.
647      *
648      * @param sharedSecret the buffer for the shared secret
649      * @param offset the offset in {@code sharedSecret} where the
650      * shared secret will be stored
651      *
652      * @return the number of bytes placed into {@code sharedSecret}
653      *
654      * @exception IllegalStateException if this key agreement has not been
655      * completed yet
656      * @exception ShortBufferException if the given output buffer is too small
657      * to hold the secret
658      */
generateSecret(byte[] sharedSecret, int offset)659     public final int generateSecret(byte[] sharedSecret, int offset)
660         throws IllegalStateException, ShortBufferException
661     {
662         chooseFirstProvider();
663         return spi.engineGenerateSecret(sharedSecret, offset);
664     }
665 
666     /**
667      * Creates the shared secret and returns it as a {@code SecretKey}
668      * object of the specified algorithm.
669      *
670      * <p>This method resets this {@code KeyAgreement} object, so that it
671      * can be reused for further key agreements. Unless this key agreement is
672      * reinitialized with one of the {@code init} methods, the same
673      * private information and algorithm parameters will be used for
674      * subsequent key agreements.
675      *
676      * @param algorithm the requested secret-key algorithm
677      *
678      * @return the shared secret key
679      *
680      * @exception IllegalStateException if this key agreement has not been
681      * completed yet
682      * @exception NoSuchAlgorithmException if the specified secret-key
683      * algorithm is not available
684      * @exception InvalidKeyException if the shared secret-key material cannot
685      * be used to generate a secret key of the specified algorithm (e.g.,
686      * the key material is too short)
687      */
generateSecret(String algorithm)688     public final SecretKey generateSecret(String algorithm)
689         throws IllegalStateException, NoSuchAlgorithmException,
690             InvalidKeyException
691     {
692         chooseFirstProvider();
693         return spi.engineGenerateSecret(algorithm);
694     }
695 
696     // BEGIN Android-added: Allow access to the current SPI for testing purposes.
697     /**
698      * Returns the {@code KeyAgreementSpi} backing this {@code KeyAgreement} or
699      * {@code null} if no {@code KeyAgreementSpi} is backing this {@code KeyAgreement}.
700      *
701      * @hide
702      */
getCurrentSpi()703     public KeyAgreementSpi getCurrentSpi() {
704         return spi;
705     }
706     // END Android-added: Allow access to the current SPI for testing purposes.
707 }
708