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