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 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 if (DSAKeyFactory.SERIAL_INTEROP) { 170 pub = new DSAPublicKey(y, p, q, g); 171 } else { 172 pub = new DSAPublicKeyImpl(y, p, q, g); 173 } 174 DSAPrivateKey priv = new DSAPrivateKey(x, p, q, g); 175 176 KeyPair pair = new KeyPair(pub, priv); 177 return pair; 178 } catch (InvalidKeyException e) { 179 throw new ProviderException(e); 180 } 181 } 182 183 /** 184 * Generate the private key component of the key pair using the 185 * provided source of random bits. This method uses the random but 186 * source passed to generate a seed and then calls the seed-based 187 * generateX method. 188 */ generateX(SecureRandom random, BigInteger q)189 private BigInteger generateX(SecureRandom random, BigInteger q) { 190 BigInteger x = null; 191 byte[] temp = new byte[qlen]; 192 while (true) { 193 random.nextBytes(temp); 194 x = new BigInteger(1, temp).mod(q); 195 if (x.signum() > 0 && (x.compareTo(q) < 0)) { 196 return x; 197 } 198 } 199 } 200 201 /** 202 * Generate the public key component y of the key pair. 203 * 204 * @param x the private key component. 205 * 206 * @param p the base parameter. 207 */ generateY(BigInteger x, BigInteger p, BigInteger g)208 BigInteger generateY(BigInteger x, BigInteger p, BigInteger g) { 209 BigInteger y = g.modPow(x, p); 210 return y; 211 } 212 213 public static final class Current extends DSAKeyPairGenerator { Current()214 public Current() { 215 super(DEF_DSA_KEY_SIZE); 216 } 217 } 218 219 public static final class Legacy extends DSAKeyPairGenerator 220 implements java.security.interfaces.DSAKeyPairGenerator { 221 Legacy()222 public Legacy() { 223 super(1024); 224 } 225 226 /** 227 * Initializes the DSA key pair generator. If <code>genParams</code> 228 * is false, a set of pre-computed parameters is used. 229 */ 230 @Override initialize(int modlen, boolean genParams, SecureRandom random)231 public void initialize(int modlen, boolean genParams, 232 SecureRandom random) throws InvalidParameterException { 233 if (genParams) { 234 super.init(modlen, random, true); 235 } else { 236 DSAParameterSpec cachedParams = 237 ParameterCache.getCachedDSAParameterSpec(modlen, 238 getDefDSASubprimeSize(modlen)); 239 if (cachedParams == null) { 240 throw new InvalidParameterException 241 ("No precomputed parameters for requested modulus" + 242 " size available"); 243 } 244 super.init(cachedParams, random, false); 245 } 246 } 247 248 /** 249 * Initializes the DSA object using a DSA parameter object. 250 * 251 * @param params a fully initialized DSA parameter object. 252 */ 253 @Override initialize(DSAParams params, SecureRandom random)254 public void initialize(DSAParams params, SecureRandom random) 255 throws InvalidParameterException { 256 if (params == null) { 257 throw new InvalidParameterException("Params must not be null"); 258 } 259 DSAParameterSpec spec = new DSAParameterSpec 260 (params.getP(), params.getQ(), params.getG()); 261 super.init(spec, random, false); 262 } 263 } 264 } 265