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