1 /* 2 * Copyright (c) 1997, 2016, 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 sun.security.provider; 27 28 import java.math.BigInteger; 29 30 import java.security.*; 31 import java.security.SecureRandom; 32 import java.security.interfaces.DSAParams; 33 import java.security.spec.AlgorithmParameterSpec; 34 import java.security.spec.InvalidParameterSpecException; 35 import java.security.spec.DSAParameterSpec; 36 37 import sun.security.jca.JCAUtil; 38 39 /** 40 * This class generates DSA key parameters and public/private key 41 * pairs according to the DSS standard NIST FIPS 186. It uses the 42 * updated version of SHA, SHA-1 as described in FIPS 180-1. 43 * 44 * @author Benjamin Renaud 45 * @author Andreas Sterbenz 46 * 47 */ 48 public class DSAKeyPairGenerator extends KeyPairGenerator 49 implements java.security.interfaces.DSAKeyPairGenerator { 50 51 /* Length for prime P and subPrime Q in bits */ 52 private int plen; 53 private int qlen; 54 55 /* whether to force new parameters to be generated for each KeyPair */ 56 private boolean forceNewParameters; 57 58 /* preset algorithm parameters. */ 59 private DSAParameterSpec params; 60 61 /* The source of random bits to use */ 62 private SecureRandom random; 63 64 public DSAKeyPairGenerator() { 65 super("DSA"); 66 initialize(1024, null); 67 } 68 69 private static void checkStrength(int sizeP, int sizeQ) { 70 if ((sizeP >= 512) && (sizeP <= 1024) && (sizeP % 64 == 0) 71 && sizeQ == 160) { 72 // traditional - allow for backward compatibility 73 // L=multiples of 64 and between 512 and 1024 (inclusive) 74 // N=160 75 } else if (sizeP == 2048 && (sizeQ == 224 || sizeQ == 256)) { 76 // L=2048, N=224 or 256 77 } else if (sizeP == 3072 && sizeQ == 256) { 78 // L=3072, N=256 79 } else { 80 throw new InvalidParameterException 81 ("Unsupported prime and subprime size combination: " + 82 sizeP + ", " + sizeQ); 83 } 84 } 85 86 public void initialize(int modlen, SecureRandom random) { 87 // generate new parameters when no precomputed ones available. 88 initialize(modlen, true, random); 89 this.forceNewParameters = false; 90 } 91 92 /** 93 * Initializes the DSA key pair generator. If <code>genParams</code> 94 * is false, a set of pre-computed parameters is used. 95 */ 96 @Override 97 public void initialize(int modlen, boolean genParams, SecureRandom random) 98 throws InvalidParameterException { 99 100 int subPrimeLen = -1; 101 if (modlen <= 1024) { 102 subPrimeLen = 160; 103 } else if (modlen == 2048) { 104 subPrimeLen = 224; 105 } else if (modlen == 3072) { 106 subPrimeLen = 256; 107 } 108 checkStrength(modlen, subPrimeLen); 109 if (genParams) { 110 params = null; 111 } else { 112 params = ParameterCache.getCachedDSAParameterSpec(modlen, 113 subPrimeLen); 114 if (params == null) { 115 throw new InvalidParameterException 116 ("No precomputed parameters for requested modulus size " 117 + "available"); 118 } 119 120 } 121 this.plen = modlen; 122 this.qlen = subPrimeLen; 123 this.random = random; 124 this.forceNewParameters = genParams; 125 } 126 127 /** 128 * Initializes the DSA object using a DSA parameter object. 129 * 130 * @param params a fully initialized DSA parameter object. 131 */ 132 @Override 133 public void initialize(DSAParams params, SecureRandom random) 134 throws InvalidParameterException { 135 136 if (params == null) { 137 throw new InvalidParameterException("Params must not be null"); 138 } 139 DSAParameterSpec spec = new DSAParameterSpec 140 (params.getP(), params.getQ(), params.getG()); 141 initialize0(spec, random); 142 } 143 144 /** 145 * Initializes the DSA object using a parameter object. 146 * 147 * @param params the parameter set to be used to generate 148 * the keys. 149 * @param random the source of randomness for this generator. 150 * 151 * @exception InvalidAlgorithmParameterException if the given parameters 152 * are inappropriate for this key pair generator 153 */ 154 public void initialize(AlgorithmParameterSpec params, SecureRandom random) 155 throws InvalidAlgorithmParameterException { 156 if (!(params instanceof DSAParameterSpec)) { 157 throw new InvalidAlgorithmParameterException 158 ("Inappropriate parameter"); 159 } 160 initialize0((DSAParameterSpec)params, random); 161 } 162 163 private void initialize0(DSAParameterSpec params, SecureRandom random) { 164 int sizeP = params.getP().bitLength(); 165 int sizeQ = params.getQ().bitLength(); 166 checkStrength(sizeP, sizeQ); 167 this.plen = sizeP; 168 this.qlen = sizeQ; 169 this.params = params; 170 this.random = random; 171 this.forceNewParameters = false; 172 } 173 174 /** 175 * Generates a pair of keys usable by any JavaSecurity compliant 176 * DSA implementation. 177 */ 178 public KeyPair generateKeyPair() { 179 if (random == null) { 180 random = JCAUtil.getSecureRandom(); 181 } 182 DSAParameterSpec spec; 183 try { 184 if (forceNewParameters) { 185 // generate new parameters each time 186 spec = ParameterCache.getNewDSAParameterSpec(plen, qlen, random); 187 } else { 188 if (params == null) { 189 params = 190 ParameterCache.getDSAParameterSpec(plen, qlen, random); 191 } 192 spec = params; 193 } 194 } catch (GeneralSecurityException e) { 195 throw new ProviderException(e); 196 } 197 return generateKeyPair(spec.getP(), spec.getQ(), spec.getG(), random); 198 } 199 200 public KeyPair generateKeyPair(BigInteger p, BigInteger q, BigInteger g, 201 SecureRandom random) { 202 203 BigInteger x = generateX(random, q); 204 BigInteger y = generateY(x, p, g); 205 206 try { 207 208 // See the comments in DSAKeyFactory, 4532506, and 6232513. 209 210 DSAPublicKey pub; 211 if (DSAKeyFactory.SERIAL_INTEROP) { 212 pub = new DSAPublicKey(y, p, q, g); 213 } else { 214 pub = new DSAPublicKeyImpl(y, p, q, g); 215 } 216 DSAPrivateKey priv = new DSAPrivateKey(x, p, q, g); 217 218 KeyPair pair = new KeyPair(pub, priv); 219 return pair; 220 } catch (InvalidKeyException e) { 221 throw new ProviderException(e); 222 } 223 } 224 225 /** 226 * Generate the private key component of the key pair using the 227 * provided source of random bits. This method uses the random but 228 * source passed to generate a seed and then calls the seed-based 229 * generateX method. 230 */ 231 private BigInteger generateX(SecureRandom random, BigInteger q) { 232 BigInteger x = null; 233 byte[] temp = new byte[qlen]; 234 while (true) { 235 random.nextBytes(temp); 236 x = new BigInteger(1, temp).mod(q); 237 if (x.signum() > 0 && (x.compareTo(q) < 0)) { 238 return x; 239 } 240 } 241 } 242 243 /** 244 * Generate the public key component y of the key pair. 245 * 246 * @param x the private key component. 247 * 248 * @param p the base parameter. 249 */ 250 BigInteger generateY(BigInteger x, BigInteger p, BigInteger g) { 251 BigInteger y = g.modPow(x, p); 252 return y; 253 } 254 255 }