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     /**
  75      * Initializes this key pair generator for a certain keysize and source of
  76      * randomness.
  77      * The keysize is specified as the size in bits of the prime modulus.
  78      *
  79      * @param keysize the keysize (size of prime modulus) in bits
  80      * @param random the source of randomness
  81      */
  82     public void initialize(int keysize, SecureRandom random) {
  83         if ((keysize < 512) || (keysize > 2048) || (keysize % 64 != 0)) {
  84             throw new InvalidParameterException("Keysize must be multiple "
  85                                                 + "of 64, and can only range "
  86                                                 + "from 512 to 2048 "
  87                                                 + "(inclusive)");
  88         }
  89         this.pSize = keysize;
  90         this.lSize = 0;
  91         this.random = random;
  92         this.params = null;
  93     }
  94 
  95     /**
  96      * Initializes this key pair generator for the specified parameter
  97      * set and source of randomness.
  98      *
  99      * <p>The given parameter set contains the prime modulus, the base
 100      * generator, and optionally the requested size in bits of the random
 101      * exponent (private value).
 102      *
 103      * @param params the parameter set used to generate the key pair
 104      * @param random the source of randomness
 105      *
 106      * @exception InvalidAlgorithmParameterException if the given parameters
 107      * are inappropriate for this key pair generator
 108      */
 109     public void initialize(AlgorithmParameterSpec algParams,
 110             SecureRandom random) throws InvalidAlgorithmParameterException {
 111         if (!(algParams instanceof DHParameterSpec)){
 112             throw new InvalidAlgorithmParameterException
 113                 ("Inappropriate parameter type");
 114         }
 115 
 116         params = (DHParameterSpec)algParams;
 117         pSize = params.getP().bitLength();
 118         if ((pSize < 512) || (pSize > 2048) ||
 119             (pSize % 64 != 0)) {
 120             throw new InvalidAlgorithmParameterException
 121                 ("Prime size must be multiple of 64, and can only range "
 122                  + "from 512 to 2048 (inclusive)");
 123         }
 124 
 125         // exponent size is optional, could be 0
 126         lSize = params.getL();
 127 
 128         // Require exponentSize < primeSize
 129         if ((lSize != 0) && (lSize > pSize)) {
 130             throw new InvalidAlgorithmParameterException
 131                 ("Exponent size must not be larger than modulus size");
 132         }
 133         this.random = random;
 134     }
 135 
 136     /**
 137      * Generates a key pair.
 138      *
 139      * @return the new key pair
 140      */
 141     public KeyPair generateKeyPair() {
 142         if (random == null) {
 143             random = SunJCE.getRandom();
 144         }
 145 
 146         if (params == null) {
 147             try {
 148                 params = ParameterCache.getDHParameterSpec(pSize, random);
 149             } catch (GeneralSecurityException e) {
 150                 // should never happen
 151                 throw new ProviderException(e);
 152             }
 153         }
 154 
 155         BigInteger p = params.getP();
 156         BigInteger g = params.getG();
 157 
 158         if (lSize <= 0) {
 159             lSize = pSize >> 1;
 160             // use an exponent size of (pSize / 2) but at least 384 bits
 161             if (lSize < 384) {
 162                 lSize = 384;
 163             }
 164         }
 165 
 166         BigInteger x;
 167         BigInteger pMinus2 = p.subtract(BigInteger.valueOf(2));
 168 
 169         //
 170         // PKCS#3 section 7.1 "Private-value generation"
 171         // Repeat if either of the followings does not hold:
 172         //     0 < x < p-1
 173         //     2^(lSize-1) <= x < 2^(lSize)
 174         //
 175         do {
 176             // generate random x up to 2^lSize bits long
 177             x = new BigInteger(lSize, random);
 178         } while ((x.compareTo(BigInteger.ONE) < 0) ||
 179             ((x.compareTo(pMinus2) > 0)) || (x.bitLength() != lSize));
 180 
 181         // calculate public value y
 182         BigInteger y = g.modPow(x, p);
 183 
 184         DHPublicKey pubKey = new DHPublicKey(y, p, g, lSize);
 185         DHPrivateKey privKey = new DHPrivateKey(x, p, g, lSize);
 186         return new KeyPair(pubKey, privKey);
 187     }
 188 }