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