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
27package javax.crypto;
28
29import java.util.*;
30
31import java.security.*;
32import java.security.Provider.Service;
33import java.security.spec.*;
34
35/* Android-removed: this debugging mechanism is not used in Android.
36import sun.security.util.Debug;
37*/
38import sun.security.jca.*;
39import 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
92public 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     */
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
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     */
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     */
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     */
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     */
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     */
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
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
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     */
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     */
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     */
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     */
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     */
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     */
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     */
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     */
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     */
636    public final SecretKey generateSecret(String algorithm)
637        throws IllegalStateException, NoSuchAlgorithmException,
638            InvalidKeyException
639    {
640        chooseFirstProvider();
641        return spi.engineGenerateSecret(algorithm);
642    }
643}
644