Home » openjdk-7 » javax » crypto » [javadoc | source]

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

Home » openjdk-7 » javax » crypto » [javadoc | source]