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