1 /*
   2  * Copyright (c) 1997, 2013, 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.math.BigInteger;
  29 import java.security.*;
  30 import java.security.spec.AlgorithmParameterSpec;
  31 import java.security.spec.InvalidParameterSpecException;
  32 import javax.crypto.spec.DHParameterSpec;
  33 import javax.crypto.spec.DHGenParameterSpec;
  34 
  35 import sun.security.provider.ParameterCache;
  36 
  37 /**
  38  * This class represents the key pair generator for Diffie-Hellman key pairs.
  39  *
  40  * <p>This key pair generator may be initialized in two different ways:
  41  *
  42  * <ul>
  43  * <li>By providing the size in bits of the prime modulus -
  44  * This will be used to create a prime modulus and base generator, which will
  45  * then be used to create the Diffie-Hellman key pair. The default size of the
  46  * prime modulus is 1024 bits.
  47  * <li>By providing a prime modulus and base generator
  48  * </ul>
  49  *
  50  * @author Jan Luehe
  51  *
  52  *
  53  * @see java.security.KeyPairGenerator
  54  */
  55 public final class DHKeyPairGenerator extends KeyPairGeneratorSpi {
  56 
  57     // parameters to use or null if not specified
  58     private DHParameterSpec params;
  59 
  60     // The size in bits of the prime modulus
  61     private int pSize;
  62 
  63     // The size in bits of the random exponent (private value)
  64     private int lSize;
  65 
  66     // The source of randomness
  67     private SecureRandom random;
  68 
  69     public DHKeyPairGenerator() {
  70         super();
  71         initialize(1024, null);
  72     }
  73 
  74     private static void checkKeySize(int keysize)
  75             throws InvalidParameterException {
  76 
  77         if ((keysize < 512) || (keysize > 2048) || ((keysize & 0x3F) != 0)) {
  78             throw new InvalidParameterException(
  79                     "DH key size must be multiple of 64, and can only range " +
  80                     "from 512 to 2048 (inclusive). " +
  81                     "The specific key size " + keysize + " is not supported");
  82         }
  83     }
  84 
  85     /**
  86      * Initializes this key pair generator for a certain keysize and source of
  87      * randomness.
  88      * The keysize is specified as the size in bits of the prime modulus.
  89      *
  90      * @param keysize the keysize (size of prime modulus) in bits
  91      * @param random the source of randomness
  92      */
  93     public void initialize(int keysize, SecureRandom random) {
  94         checkKeySize(keysize);
  95 
  96         this.pSize = keysize;
  97         this.lSize = 0;
  98         this.random = random;
  99         this.params = null;
 100     }
 101 
 102     /**
 103      * Initializes this key pair generator for the specified parameter
 104      * set and source of randomness.
 105      *
 106      * <p>The given parameter set contains the prime modulus, the base
 107      * generator, and optionally the requested size in bits of the random
 108      * exponent (private value).
 109      *
 110      * @param params the parameter set used to generate the key pair
 111      * @param random the source of randomness
 112      *
 113      * @exception InvalidAlgorithmParameterException if the given parameters
 114      * are inappropriate for this key pair generator
 115      */
 116     public void initialize(AlgorithmParameterSpec algParams,
 117             SecureRandom random) throws InvalidAlgorithmParameterException {
 118         if (!(algParams instanceof DHParameterSpec)){
 119             throw new InvalidAlgorithmParameterException
 120                 ("Inappropriate parameter type");
 121         }
 122 
 123         params = (DHParameterSpec)algParams;
 124         pSize = params.getP().bitLength();
 125         try {
 126             checkKeySize(pSize);
 127         } catch (InvalidParameterException ipe) {
 128             throw new InvalidAlgorithmParameterException(ipe.getMessage());
 129         }
 130 
 131         // exponent size is optional, could be 0
 132         lSize = params.getL();
 133 
 134         // Require exponentSize < primeSize
 135         if ((lSize != 0) && (lSize > pSize)) {
 136             throw new InvalidAlgorithmParameterException
 137                 ("Exponent size must not be larger than modulus size");
 138         }
 139         this.random = random;
 140     }
 141 
 142     /**
 143      * Generates a key pair.
 144      *
 145      * @return the new key pair
 146      */
 147     public KeyPair generateKeyPair() {
 148         if (random == null) {
 149             random = SunJCE.getRandom();
 150         }
 151 
 152         if (params == null) {
 153             try {
 154                 params = ParameterCache.getDHParameterSpec(pSize, random);
 155             } catch (GeneralSecurityException e) {
 156                 // should never happen
 157                 throw new ProviderException(e);
 158             }
 159         }
 160 
 161         BigInteger p = params.getP();
 162         BigInteger g = params.getG();
 163 
 164         if (lSize <= 0) {
 165             lSize = pSize >> 1;
 166             // use an exponent size of (pSize / 2) but at least 384 bits
 167             if (lSize < 384) {
 168                 lSize = 384;
 169             }
 170         }
 171 
 172         BigInteger x;
 173         BigInteger pMinus2 = p.subtract(BigInteger.valueOf(2));
 174 
 175         //
 176         // PKCS#3 section 7.1 "Private-value generation"
 177         // Repeat if either of the followings does not hold:
 178         //     0 < x < p-1
 179         //     2^(lSize-1) <= x < 2^(lSize)
 180         //
 181         do {
 182             // generate random x up to 2^lSize bits long
 183             x = new BigInteger(lSize, random);
 184         } while ((x.compareTo(BigInteger.ONE) < 0) ||
 185             ((x.compareTo(pMinus2) > 0)) || (x.bitLength() != lSize));
 186 
 187         // calculate public value y
 188         BigInteger y = g.modPow(x, p);
 189 
 190         DHPublicKey pubKey = new DHPublicKey(y, p, g, lSize);
 191         DHPrivateKey privKey = new DHPrivateKey(x, p, g, lSize);
 192         return new KeyPair(pubKey, privKey);
 193     }
 194 }