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