Home | History | Annotate | Download | only in crypto
      1 /*
      2  * Copyright (C) 2014 The Android Open Source Project
      3  * Copyright (c) 1997, 2011, Oracle and/or its affiliates. All rights reserved.
      4  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
      5  *
      6  * This code is free software; you can redistribute it and/or modify it
      7  * under the terms of the GNU General Public License version 2 only, as
      8  * published by the Free Software Foundation.  Oracle designates this
      9  * particular file as subject to the "Classpath" exception as provided
     10  * by Oracle in the LICENSE file that accompanied this code.
     11  *
     12  * This code is distributed in the hope that it will be useful, but WITHOUT
     13  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
     14  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
     15  * version 2 for more details (a copy is included in the LICENSE file that
     16  * accompanied this code).
     17  *
     18  * You should have received a copy of the GNU General Public License version
     19  * 2 along with this work; if not, write to the Free Software Foundation,
     20  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
     21  *
     22  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
     23  * or visit www.oracle.com if you need additional information or have any
     24  * questions.
     25  */
     26 
     27 package javax.crypto;
     28 
     29 import java.util.*;
     30 
     31 import java.security.*;
     32 import java.security.Provider.Service;
     33 import java.security.spec.*;
     34 
     35 /* Android-removed: this debugging mechanism is not used in Android.
     36 import sun.security.util.Debug;
     37 */
     38 import sun.security.jca.*;
     39 import sun.security.jca.GetInstance.Instance;
     40 
     41 /**
     42  * This class provides the functionality of a key agreement (or key
     43  * exchange) protocol.
     44  * <p>
     45  * The keys involved in establishing a shared secret are created by one of the
     46  * key generators (<code>KeyPairGenerator</code> or
     47  * <code>KeyGenerator</code>), a <code>KeyFactory</code>, or as a result from
     48  * an intermediate phase of the key agreement protocol.
     49  *
     50  * <p> For each of the correspondents in the key exchange, <code>doPhase</code>
     51  * needs to be called. For example, if this key exchange is with one other
     52  * party, <code>doPhase</code> needs to be called once, with the
     53  * <code>lastPhase</code> flag set to <code>true</code>.
     54  * If this key exchange is
     55  * with two other parties, <code>doPhase</code> needs to be called twice,
     56  * the first time setting the <code>lastPhase</code> flag to
     57  * <code>false</code>, and the second time setting it to <code>true</code>.
     58  * There may be any number of parties involved in a key exchange.
     59  *
     60  * <p> Android provides the following <code>KeyAgreement</code> algorithms:
     61  * <table>
     62  *   <thead>
     63  *     <tr>
     64  *       <th>Algorithm</th>
     65  *       <th>Supported API Levels</th>
     66  *     </tr>
     67  *   </thead>
     68  *   <tbody>
     69  *     <tr>
     70  *       <td>DH</td>
     71  *       <td>1+</td>
     72  *     </tr>
     73  *     <tr>
     74  *       <td>ECDH</td>
     75  *       <td>11+</td>
     76  *     </tr>
     77  *   </tbody>
     78  * </table>
     79  *
     80  * This algorithm is described in the <a href=
     81  * "{@docRoot}openjdk-redirect.html?v=8&path=/technotes/guides/security/StandardNames.html#KeyAgreement">
     82  * KeyAgreement section</a> of the
     83  * Java Cryptography Architecture Standard Algorithm Name Documentation.
     84  *
     85  * @author Jan Luehe
     86  *
     87  * @see KeyGenerator
     88  * @see SecretKey
     89  * @since 1.4
     90  */
     91 
     92 public class KeyAgreement {
     93 
     94     /* Android-removed: this debugging mechanism is not used in Android.
     95     private static final Debug pdebug =
     96                         Debug.getInstance("provider", "Provider");
     97     private static final boolean skipDebug =
     98         Debug.isOn("engine=") && !Debug.isOn("keyagreement");
     99     */
    100 
    101     // The provider
    102     private Provider provider;
    103 
    104     // The provider implementation (delegate)
    105     private KeyAgreementSpi spi;
    106 
    107     // The name of the key agreement algorithm.
    108     private final String algorithm;
    109 
    110     private final Object lock;
    111 
    112     /**
    113      * Creates a KeyAgreement object.
    114      *
    115      * @param keyAgreeSpi the delegate
    116      * @param provider the provider
    117      * @param algorithm the algorithm
    118      */
    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