Save This Page
Home » openjdk-7 » com.sun.crypto » provider » [javadoc | source]
    1   /*
    2    * Copyright (c) 1997, 2009, 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 com.sun.crypto.provider;
   27   
   28   import java.util;
   29   import java.lang;
   30   import java.math.BigInteger;
   31   import java.security.InvalidAlgorithmParameterException;
   32   import java.security.InvalidKeyException;
   33   import java.security.Key;
   34   import java.security.NoSuchAlgorithmException;
   35   import java.security.SecureRandom;
   36   import java.security.spec.AlgorithmParameterSpec;
   37   import java.security.spec.InvalidKeySpecException;
   38   import javax.crypto.KeyAgreementSpi;
   39   import javax.crypto.ShortBufferException;
   40   import javax.crypto.SecretKey;
   41   import javax.crypto.spec;
   42   
   43   /**
   44    * This class implements the Diffie-Hellman key agreement protocol between
   45    * any number of parties.
   46    *
   47    * @author Jan Luehe
   48    *
   49    */
   50   
   51   public final class DHKeyAgreement
   52   extends KeyAgreementSpi {
   53   
   54       private boolean generateSecret = false;
   55       private BigInteger init_p = null;
   56       private BigInteger init_g = null;
   57       private BigInteger x = BigInteger.ZERO; // the private value
   58       private BigInteger y = BigInteger.ZERO;
   59   
   60       /**
   61        * Empty constructor
   62        */
   63       public DHKeyAgreement() {
   64       }
   65   
   66       /**
   67        * Initializes this key agreement with the given key and source of
   68        * randomness. The given key is required to contain all the algorithm
   69        * parameters required for this key agreement.
   70        *
   71        * <p> If the key agreement algorithm requires random bytes, it gets them
   72        * from the given source of randomness, <code>random</code>.
   73        * However, if the underlying
   74        * algorithm implementation does not require any random bytes,
   75        * <code>random</code> is ignored.
   76        *
   77        * @param key the party's private information. For example, in the case
   78        * of the Diffie-Hellman key agreement, this would be the party's own
   79        * Diffie-Hellman private key.
   80        * @param random the source of randomness
   81        *
   82        * @exception InvalidKeyException if the given key is
   83        * inappropriate for this key agreement, e.g., is of the wrong type or
   84        * has an incompatible algorithm type.
   85        */
   86       protected void engineInit(Key key, SecureRandom random)
   87           throws InvalidKeyException
   88       {
   89           try {
   90               engineInit(key, null, random);
   91           } catch (InvalidAlgorithmParameterException e) {
   92               // never happens, because we did not pass any parameters
   93           }
   94       }
   95   
   96       /**
   97        * Initializes this key agreement with the given key, set of
   98        * algorithm parameters, and source of randomness.
   99        *
  100        * @param key the party's private information. For example, in the case
  101        * of the Diffie-Hellman key agreement, this would be the party's own
  102        * Diffie-Hellman private key.
  103        * @param params the key agreement parameters
  104        * @param random the source of randomness
  105        *
  106        * @exception InvalidKeyException if the given key is
  107        * inappropriate for this key agreement, e.g., is of the wrong type or
  108        * has an incompatible algorithm type.
  109        * @exception InvalidAlgorithmParameterException if the given parameters
  110        * are inappropriate for this key agreement.
  111        */
  112       protected void engineInit(Key key, AlgorithmParameterSpec params,
  113                                 SecureRandom random)
  114           throws InvalidKeyException, InvalidAlgorithmParameterException
  115       {
  116           // ignore "random" parameter, because our implementation does not
  117           // require any source of randomness
  118           generateSecret = false;
  119           init_p = null;
  120           init_g = null;
  121   
  122           if ((params != null) && !(params instanceof DHParameterSpec)) {
  123               throw new InvalidAlgorithmParameterException
  124                   ("Diffie-Hellman parameters expected");
  125           }
  126           if (!(key instanceof javax.crypto.interfaces.DHPrivateKey)) {
  127               throw new InvalidKeyException("Diffie-Hellman private key "
  128                                             + "expected");
  129           }
  130           javax.crypto.interfaces.DHPrivateKey dhPrivKey;
  131           dhPrivKey = (javax.crypto.interfaces.DHPrivateKey)key;
  132   
  133           // check if private key parameters are compatible with
  134           // initialized ones
  135           if (params != null) {
  136               init_p = ((DHParameterSpec)params).getP();
  137               init_g = ((DHParameterSpec)params).getG();
  138           }
  139           BigInteger priv_p = dhPrivKey.getParams().getP();
  140           BigInteger priv_g = dhPrivKey.getParams().getG();
  141           if (init_p != null && priv_p != null && !(init_p.equals(priv_p))) {
  142               throw new InvalidKeyException("Incompatible parameters");
  143           }
  144           if (init_g != null && priv_g != null && !(init_g.equals(priv_g))) {
  145               throw new InvalidKeyException("Incompatible parameters");
  146           }
  147           if ((init_p == null && priv_p == null)
  148               || (init_g == null && priv_g == null)) {
  149               throw new InvalidKeyException("Missing parameters");
  150           }
  151           init_p = priv_p;
  152           init_g = priv_g;
  153   
  154           // store the x value
  155           this.x = dhPrivKey.getX();
  156       }
  157   
  158       /**
  159        * Executes the next phase of this key agreement with the given
  160        * key that was received from one of the other parties involved in this key
  161        * agreement.
  162        *
  163        * @param key the key for this phase. For example, in the case of
  164        * Diffie-Hellman between 2 parties, this would be the other party's
  165        * Diffie-Hellman public key.
  166        * @param lastPhase flag which indicates whether or not this is the last
  167        * phase of this key agreement.
  168        *
  169        * @return the (intermediate) key resulting from this phase, or null if
  170        * this phase does not yield a key
  171        *
  172        * @exception InvalidKeyException if the given key is inappropriate for
  173        * this phase.
  174        * @exception IllegalStateException if this key agreement has not been
  175        * initialized.
  176        */
  177       protected Key engineDoPhase(Key key, boolean lastPhase)
  178           throws InvalidKeyException, IllegalStateException
  179       {
  180           if (!(key instanceof javax.crypto.interfaces.DHPublicKey)) {
  181               throw new InvalidKeyException("Diffie-Hellman public key "
  182                                             + "expected");
  183           }
  184           javax.crypto.interfaces.DHPublicKey dhPubKey;
  185           dhPubKey = (javax.crypto.interfaces.DHPublicKey)key;
  186   
  187           if (init_p == null || init_g == null) {
  188               throw new IllegalStateException("Not initialized");
  189           }
  190   
  191           // check if public key parameters are compatible with
  192           // initialized ones
  193           BigInteger pub_p = dhPubKey.getParams().getP();
  194           BigInteger pub_g = dhPubKey.getParams().getG();
  195           if (pub_p != null && !(init_p.equals(pub_p))) {
  196               throw new InvalidKeyException("Incompatible parameters");
  197           }
  198           if (pub_g != null && !(init_g.equals(pub_g))) {
  199               throw new InvalidKeyException("Incompatible parameters");
  200           }
  201   
  202           // store the y value
  203           this.y = dhPubKey.getY();
  204   
  205           // we've received a public key (from one of the other parties),
  206           // so we are ready to create the secret, which may be an
  207           // intermediate secret, in which case we wrap it into a
  208           // Diffie-Hellman public key object and return it.
  209           generateSecret = true;
  210           if (lastPhase == false) {
  211               byte[] intermediate = engineGenerateSecret();
  212               return new DHPublicKey(new BigInteger(1, intermediate),
  213                                      init_p, init_g);
  214           } else {
  215               return null;
  216           }
  217       }
  218   
  219       /**
  220        * Generates the shared secret and returns it in a new buffer.
  221        *
  222        * <p>This method resets this <code>KeyAgreementSpi</code> object,
  223        * so that it
  224        * can be reused for further key agreements. Unless this key agreement is
  225        * reinitialized with one of the <code>engineInit</code> methods, the same
  226        * private information and algorithm parameters will be used for
  227        * subsequent key agreements.
  228        *
  229        * @return the new buffer with the shared secret
  230        *
  231        * @exception IllegalStateException if this key agreement has not been
  232        * completed yet
  233        */
  234       protected byte[] engineGenerateSecret()
  235           throws IllegalStateException
  236       {
  237           if (generateSecret == false) {
  238               throw new IllegalStateException
  239                   ("Key agreement has not been completed yet");
  240           }
  241   
  242           // Reset the key agreement here (in case anything goes wrong)
  243           generateSecret = false;
  244   
  245           // get the modulus
  246           BigInteger modulus = init_p;
  247   
  248           BigInteger tmpResult = y.modPow(x, modulus);
  249           byte[] secret = tmpResult.toByteArray();
  250   
  251           /*
  252            * BigInteger.toByteArray will sometimes put a sign byte up front, but
  253            * we NEVER want one.
  254            */
  255           if ((tmpResult.bitLength() % 8) == 0) {
  256               byte retval[] = new byte[secret.length - 1];
  257               System.arraycopy(secret, 1, retval, 0, retval.length);
  258               return retval;
  259           } else {
  260               return secret;
  261           }
  262       }
  263   
  264       /**
  265        * Generates the shared secret, and places it into the buffer
  266        * <code>sharedSecret</code>, beginning at <code>offset</code>.
  267        *
  268        * <p>If the <code>sharedSecret</code> buffer is too small to hold the
  269        * result, a <code>ShortBufferException</code> is thrown.
  270        * In this case, this call should be repeated with a larger output buffer.
  271        *
  272        * <p>This method resets this <code>KeyAgreementSpi</code> object,
  273        * so that it
  274        * can be reused for further key agreements. Unless this key agreement is
  275        * reinitialized with one of the <code>engineInit</code> methods, the same
  276        * private information and algorithm parameters will be used for
  277        * subsequent key agreements.
  278        *
  279        * @param sharedSecret the buffer for the shared secret
  280        * @param offset the offset in <code>sharedSecret</code> where the
  281        * shared secret will be stored
  282        *
  283        * @return the number of bytes placed into <code>sharedSecret</code>
  284        *
  285        * @exception IllegalStateException if this key agreement has not been
  286        * completed yet
  287        * @exception ShortBufferException if the given output buffer is too small
  288        * to hold the secret
  289        */
  290       protected int engineGenerateSecret(byte[] sharedSecret, int offset)
  291           throws IllegalStateException, ShortBufferException
  292       {
  293           if (generateSecret == false) {
  294               throw new IllegalStateException
  295                   ("Key agreement has not been completed yet");
  296           }
  297   
  298           if (sharedSecret == null) {
  299               throw new ShortBufferException
  300                   ("No buffer provided for shared secret");
  301           }
  302   
  303           BigInteger modulus = init_p;
  304           byte[] secret = this.y.modPow(this.x, modulus).toByteArray();
  305   
  306           // BigInteger.toByteArray will sometimes put a sign byte up front,
  307           // but we NEVER want one.
  308           if ((secret.length << 3) != modulus.bitLength()) {
  309               if ((sharedSecret.length - offset) < (secret.length - 1)) {
  310                   throw new ShortBufferException
  311                       ("Buffer too short for shared secret");
  312               }
  313               System.arraycopy(secret, 1, sharedSecret, offset,
  314                                secret.length - 1);
  315   
  316               // Reset the key agreement here (not earlier!), so that people
  317               // can recover from ShortBufferException above without losing
  318               // internal state
  319               generateSecret = false;
  320   
  321               return secret.length - 1;
  322   
  323           } else {
  324               if ((sharedSecret.length - offset) < secret.length) {
  325                   throw new ShortBufferException
  326                       ("Buffer too short to hold shared secret");
  327               }
  328               System.arraycopy(secret, 0, sharedSecret, offset, secret.length);
  329   
  330               // Reset the key agreement here (not earlier!), so that people
  331               // can recover from ShortBufferException above without losing
  332               // internal state
  333               generateSecret = false;
  334   
  335               return secret.length;
  336           }
  337       }
  338   
  339       /**
  340        * Creates the shared secret and returns it as a secret key object
  341        * of the requested algorithm type.
  342        *
  343        * <p>This method resets this <code>KeyAgreementSpi</code> object,
  344        * so that it
  345        * can be reused for further key agreements. Unless this key agreement is
  346        * reinitialized with one of the <code>engineInit</code> methods, the same
  347        * private information and algorithm parameters will be used for
  348        * subsequent key agreements.
  349        *
  350        * @param algorithm the requested secret key algorithm
  351        *
  352        * @return the shared secret key
  353        *
  354        * @exception IllegalStateException if this key agreement has not been
  355        * completed yet
  356        * @exception NoSuchAlgorithmException if the requested secret key
  357        * algorithm is not available
  358        * @exception InvalidKeyException if the shared secret key material cannot
  359        * be used to generate a secret key of the requested algorithm type (e.g.,
  360        * the key material is too short)
  361        */
  362       protected SecretKey engineGenerateSecret(String algorithm)
  363           throws IllegalStateException, NoSuchAlgorithmException,
  364               InvalidKeyException
  365       {
  366           if (algorithm == null) {
  367               throw new NoSuchAlgorithmException("null algorithm");
  368           }
  369           byte[] secret = engineGenerateSecret();
  370           if (algorithm.equalsIgnoreCase("DES")) {
  371               // DES
  372               return new DESKey(secret);
  373           } else if (algorithm.equalsIgnoreCase("DESede")
  374                      || algorithm.equalsIgnoreCase("TripleDES")) {
  375               // Triple DES
  376               return new DESedeKey(secret);
  377           } else if (algorithm.equalsIgnoreCase("Blowfish")) {
  378               // Blowfish
  379               int keysize = secret.length;
  380               if (keysize >= BlowfishConstants.BLOWFISH_MAX_KEYSIZE)
  381                   keysize = BlowfishConstants.BLOWFISH_MAX_KEYSIZE;
  382               SecretKeySpec skey = new SecretKeySpec(secret, 0, keysize,
  383                                                      "Blowfish");
  384               return skey;
  385           } else if (algorithm.equalsIgnoreCase("AES")) {
  386               // AES
  387               int keysize = secret.length;
  388               SecretKeySpec skey = null;
  389               int idx = AESConstants.AES_KEYSIZES.length - 1;
  390               while (skey == null && idx >= 0) {
  391                   // Generate the strongest key using the shared secret
  392                   // assuming the key sizes in AESConstants class are
  393                   // in ascending order
  394                   if (keysize >= AESConstants.AES_KEYSIZES[idx]) {
  395                       keysize = AESConstants.AES_KEYSIZES[idx];
  396                       skey = new SecretKeySpec(secret, 0, keysize, "AES");
  397                   }
  398                   idx--;
  399               }
  400               if (skey == null) {
  401                   throw new InvalidKeyException("Key material is too short");
  402               }
  403               return skey;
  404           } else if (algorithm.equals("TlsPremasterSecret")) {
  405               // return entire secret
  406               return new SecretKeySpec(secret, "TlsPremasterSecret");
  407           } else {
  408               throw new NoSuchAlgorithmException("Unsupported secret key "
  409                                                  + "algorithm: "+ algorithm);
  410           }
  411       }
  412   }

Save This Page
Home » openjdk-7 » com.sun.crypto » provider » [javadoc | source]