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