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 import java.security.AlgorithmParameterGeneratorSpi; 30 import java.security.AlgorithmParameters; 31 import java.security.InvalidAlgorithmParameterException; 32 import java.security.NoSuchAlgorithmException; 33 import java.security.NoSuchProviderException; 34 import java.security.InvalidParameterException; 35 import java.security.MessageDigest; 36 import java.security.SecureRandom; 37 import java.security.spec.AlgorithmParameterSpec; 38 import java.security.spec.InvalidParameterSpecException; 39 import java.security.spec.DSAParameterSpec; 40 import java.security.spec.DSAGenParameterSpec; 41 42 /** 43 * This class generates parameters for the DSA algorithm. It uses a default 44 * prime modulus size of 1024 bits, which can be overwritten during 45 * initialization. 46 * 47 * @author Jan Luehe 48 * 49 * 50 * @see java.security.AlgorithmParameters 51 * @see java.security.spec.AlgorithmParameterSpec 52 * @see DSAParameters 53 * 54 * @since 1.2 55 */ 56 57 public class DSAParameterGenerator extends AlgorithmParameterGeneratorSpi { 58 59 // the default parameters 60 private static final DSAGenParameterSpec DEFAULTS = 61 new DSAGenParameterSpec(1024, 160, 160); 62 63 // the length of prime P, subPrime Q, and seed in bits 64 private int valueL = -1; 65 private int valueN = -1; 66 private int seedLen = -1; 67 68 // the source of randomness 69 private SecureRandom random; 70 71 public DSAParameterGenerator() { 72 } 73 74 /** 75 * Initializes this parameter generator for a certain strength 76 * and source of randomness. 77 * 78 * @param strength the strength (size of prime) in bits 79 * @param random the source of randomness 80 */ 81 @Override 82 protected void engineInit(int strength, SecureRandom random) { 83 if ((strength >= 512) && (strength <= 1024) && (strength % 64 == 0)) { 84 this.valueN = 160; 85 } else if (strength == 2048) { 86 this.valueN = 224; 87 } else if (strength == 3072) { 88 this.valueN = 256; 89 } else { 90 throw new InvalidParameterException 91 ("Prime size should be 512 - 1024, or 2048, 3072"); 92 } 93 this.valueL = strength; 94 this.seedLen = valueN; 95 this.random = random; 96 } 97 98 /** 99 * Initializes this parameter generator with a set of 100 * algorithm-specific parameter generation values. 101 * 102 * @param genParamSpec the set of algorithm-specific parameter 103 * generation values 104 * @param random the source of randomness 105 * 106 * @exception InvalidAlgorithmParameterException if the given parameter 107 * generation values are inappropriate for this parameter generator 108 */ 109 @Override 110 protected void engineInit(AlgorithmParameterSpec genParamSpec, 111 SecureRandom random) throws InvalidAlgorithmParameterException { 112 113 if (!(genParamSpec instanceof DSAGenParameterSpec)) { 114 throw new InvalidAlgorithmParameterException("Invalid parameter"); 115 } 116 DSAGenParameterSpec dsaGenParams = (DSAGenParameterSpec)genParamSpec; 117 118 // directly initialize using the already validated values 119 this.valueL = dsaGenParams.getPrimePLength(); 120 this.valueN = dsaGenParams.getSubprimeQLength(); 121 this.seedLen = dsaGenParams.getSeedLength(); 122 this.random = random; 123 } 124 125 /** 126 * Generates the parameters. 127 * 128 * @return the new AlgorithmParameters object 129 */ 130 @Override 131 protected AlgorithmParameters engineGenerateParameters() { 132 AlgorithmParameters algParams = null; 133 try { 134 if (this.random == null) { 135 this.random = new SecureRandom(); 136 } 137 if (valueL == -1) { 138 try { 139 engineInit(DEFAULTS, this.random); 140 } catch (InvalidAlgorithmParameterException iape) { 141 // should never happen 142 } 143 } 144 BigInteger[] pAndQ = generatePandQ(this.random, valueL, 145 valueN, seedLen); 146 BigInteger paramP = pAndQ[0]; 147 BigInteger paramQ = pAndQ[1]; 148 BigInteger paramG = generateG(paramP, paramQ); 149 150 DSAParameterSpec dsaParamSpec = 151 new DSAParameterSpec(paramP, paramQ, paramG); 152 algParams = AlgorithmParameters.getInstance("DSA", "SUN"); 153 algParams.init(dsaParamSpec); 154 } catch (InvalidParameterSpecException e) { 155 // this should never happen 156 throw new RuntimeException(e.getMessage()); 157 } catch (NoSuchAlgorithmException e) { 158 // this should never happen, because we provide it 159 throw new RuntimeException(e.getMessage()); 160 } catch (NoSuchProviderException e) { 161 // this should never happen, because we provide it 162 throw new RuntimeException(e.getMessage()); 163 } 164 165 return algParams; 166 } 167 168 /* 169 * Generates the prime and subprime parameters for DSA, 170 * using the provided source of randomness. 171 * This method will generate new seeds until a suitable 172 * seed has been found. 173 * 174 * @param random the source of randomness to generate the 175 * seed 176 * @param valueL the size of <code>p</code>, in bits. 177 * @param valueN the size of <code>q</code>, in bits. 178 * @param seedLen the length of <code>seed</code>, in bits. 179 * 180 * @return an array of BigInteger, with <code>p</code> at index 0 and 181 * <code>q</code> at index 1, the seed at index 2, and the counter value 182 * at index 3. 183 */ 184 private static BigInteger[] generatePandQ(SecureRandom random, int valueL, 185 int valueN, int seedLen) { 186 String hashAlg = null; 187 if (valueN == 160) { 188 hashAlg = "SHA"; 189 } else if (valueN == 224) { 190 hashAlg = "SHA-224"; 191 } else if (valueN == 256) { 192 hashAlg = "SHA-256"; 193 } 194 MessageDigest hashObj = null; 195 try { 196 hashObj = MessageDigest.getInstance(hashAlg); 197 } catch (NoSuchAlgorithmException nsae) { 198 // should never happen 199 nsae.printStackTrace(); 200 } 201 202 /* Step 3, 4: Useful variables */ 203 int outLen = hashObj.getDigestLength()*8; 204 int n = (valueL - 1) / outLen; 205 int b = (valueL - 1) % outLen; 206 byte[] seedBytes = new byte[seedLen/8]; 207 BigInteger twoSl = BigInteger.TWO.pow(seedLen); 208 int primeCertainty = 80; // for 1024-bit prime P 209 if (valueL == 2048) { 210 primeCertainty = 112; 211 } else if (valueL == 3072) { 212 // primeCertainty = 256; 213 primeCertainty = 128; 214 } 215 216 BigInteger resultP, resultQ, seed = null; 217 int counter; 218 while (true) { 219 do { 220 /* Step 5 */ 221 random.nextBytes(seedBytes); 222 seed = new BigInteger(1, seedBytes); 223 224 /* Step 6 */ 225 BigInteger U = new BigInteger(1, hashObj.digest(seedBytes)). 226 mod(BigInteger.TWO.pow(valueN - 1)); 227 228 /* Step 7 */ 229 resultQ = BigInteger.TWO.pow(valueN - 1) 230 .add(U) 231 .add(BigInteger.ONE) 232 .subtract(U.mod(BigInteger.TWO)); 233 } while (!resultQ.isProbablePrime(primeCertainty)); 234 235 /* Step 10 */ 236 BigInteger offset = BigInteger.ONE; 237 /* Step 11 */ 238 for (counter = 0; counter < 4*valueL; counter++) { 239 BigInteger[] V = new BigInteger[n + 1]; 240 /* Step 11.1 */ 241 for (int j = 0; j <= n; j++) { 242 BigInteger J = BigInteger.valueOf(j); 243 BigInteger tmp = (seed.add(offset).add(J)).mod(twoSl); 244 byte[] vjBytes = hashObj.digest(toByteArray(tmp)); 245 V[j] = new BigInteger(1, vjBytes); 246 } 247 /* Step 11.2 */ 248 BigInteger W = V[0]; 249 for (int i = 1; i < n; i++) { 250 W = W.add(V[i].multiply(BigInteger.TWO.pow(i * outLen))); 251 } 252 W = W.add((V[n].mod(BigInteger.TWO.pow(b))) 253 .multiply(BigInteger.TWO.pow(n * outLen))); 254 /* Step 11.3 */ 255 BigInteger twoLm1 = BigInteger.TWO.pow(valueL - 1); 256 BigInteger X = W.add(twoLm1); 257 /* Step 11.4, 11.5 */ 258 BigInteger c = X.mod(resultQ.multiply(BigInteger.TWO)); 259 resultP = X.subtract(c.subtract(BigInteger.ONE)); 260 /* Step 11.6, 11.7 */ 261 if (resultP.compareTo(twoLm1) > -1 262 && resultP.isProbablePrime(primeCertainty)) { 263 /* Step 11.8 */ 264 BigInteger[] result = {resultP, resultQ, seed, 265 BigInteger.valueOf(counter)}; 266 return result; 267 } 268 /* Step 11.9 */ 269 offset = offset.add(BigInteger.valueOf(n)).add(BigInteger.ONE); 270 } 271 } 272 273 } 274 275 /* 276 * Generates the <code>g</code> parameter for DSA. 277 * 278 * @param p the prime, <code>p</code>. 279 * @param q the subprime, <code>q</code>. 280 * 281 * @param the <code>g</code> 282 */ 283 private static BigInteger generateG(BigInteger p, BigInteger q) { 284 BigInteger h = BigInteger.ONE; 285 /* Step 1 */ 286 BigInteger pMinusOneOverQ = (p.subtract(BigInteger.ONE)).divide(q); 287 BigInteger resultG = BigInteger.ONE; 288 while (resultG.compareTo(BigInteger.TWO) < 0) { 289 /* Step 3 */ 290 resultG = h.modPow(pMinusOneOverQ, p); 291 h = h.add(BigInteger.ONE); 292 } 293 return resultG; 294 } 295 296 /* 297 * Converts the result of a BigInteger.toByteArray call to an exact 298 * signed magnitude representation for any positive number. 299 */ 300 private static byte[] toByteArray(BigInteger bigInt) { 301 byte[] result = bigInt.toByteArray(); 302 if (result[0] == 0) { 303 byte[] tmp = new byte[result.length - 1]; 304 System.arraycopy(result, 1, tmp, 0, tmp.length); 305 result = tmp; 306 } 307 return result; 308 } 309 }