1 /* 2 * Copyright (c) 1997, 2012, 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 // useful constants 72 private static final BigInteger ZERO = BigInteger.valueOf(0); 73 private static final BigInteger ONE = BigInteger.valueOf(1); 74 private static final BigInteger TWO = BigInteger.valueOf(2); 75 76 public DSAParameterGenerator() { 77 } 78 79 /** 80 * Initializes this parameter generator for a certain strength 81 * and source of randomness. 82 * 83 * @param strength the strength (size of prime) in bits 84 * @param random the source of randomness 85 */ 86 protected void engineInit(int strength, SecureRandom random) { 87 if ((strength >= 512) && (strength <= 1024) && (strength % 64 == 0)) { 88 this.valueN = 160; 89 } else if (strength == 2048) { 90 this.valueN = 224; 91 // } else if (strength == 3072) { 92 // this.valueN = 256; 93 } else { 94 throw new InvalidParameterException 95 ("Prime size should be 512 - 1024, or 2048"); 96 } 97 this.valueL = strength; 98 this.seedLen = valueN; 99 this.random = random; 100 } 101 102 /** 103 * Initializes this parameter generator with a set of 104 * algorithm-specific parameter generation values. 105 * 106 * @param genParamSpec the set of algorithm-specific parameter generation values 107 * @param random the source of randomness 108 * 109 * @exception InvalidAlgorithmParameterException if the given parameter 110 * generation values are inappropriate for this parameter generator 111 */ 112 protected void engineInit(AlgorithmParameterSpec genParamSpec, 113 SecureRandom random) 114 throws InvalidAlgorithmParameterException { 115 if (!(genParamSpec instanceof DSAGenParameterSpec)) { 116 throw new InvalidAlgorithmParameterException("Invalid parameter"); 117 } 118 DSAGenParameterSpec dsaGenParams = (DSAGenParameterSpec) genParamSpec; 119 int primePLen = dsaGenParams.getPrimePLength(); 120 if (primePLen > 2048) { 121 throw new InvalidParameterException 122 ("No support for prime size " + primePLen); 123 } 124 // directly initialize using the already validated values 125 this.valueL = primePLen; 126 this.valueN = dsaGenParams.getSubprimeQLength(); 127 this.seedLen = dsaGenParams.getSeedLength(); 128 this.random = random; 129 } 130 131 /** 132 * Generates the parameters. 133 * 134 * @return the new AlgorithmParameters object 135 */ 136 protected AlgorithmParameters engineGenerateParameters() { 137 AlgorithmParameters algParams = null; 138 try { 139 if (this.random == null) { 140 this.random = new SecureRandom(); 141 } 142 if (valueL == -1) { 143 try { 144 engineInit(DEFAULTS, this.random); 145 } catch (InvalidAlgorithmParameterException iape) { 146 // should never happen 147 } 148 } 149 BigInteger[] pAndQ = generatePandQ(this.random, valueL, 150 valueN, seedLen); 151 BigInteger paramP = pAndQ[0]; 152 BigInteger paramQ = pAndQ[1]; 153 BigInteger paramG = generateG(paramP, paramQ); 154 155 DSAParameterSpec dsaParamSpec = 156 new DSAParameterSpec(paramP, paramQ, paramG); 157 algParams = AlgorithmParameters.getInstance("DSA", "SUN"); 158 algParams.init(dsaParamSpec); 159 } catch (InvalidParameterSpecException e) { 160 // this should never happen 161 throw new RuntimeException(e.getMessage()); 162 } catch (NoSuchAlgorithmException e) { 163 // this should never happen, because we provide it 164 throw new RuntimeException(e.getMessage()); 165 } catch (NoSuchProviderException e) { 166 // this should never happen, because we provide it 167 throw new RuntimeException(e.getMessage()); 168 } 169 170 return algParams; 171 } 172 173 /* 174 * Generates the prime and subprime parameters for DSA, 175 * using the provided source of randomness. 176 * This method will generate new seeds until a suitable 177 * seed has been found. 178 * 179 * @param random the source of randomness to generate the 180 * seed 181 * @param valueL the size of <code>p</code>, in bits. 182 * @param valueN the size of <code>q</code>, in bits. 183 * @param seedLen the length of <code>seed</code>, in bits. 184 * 185 * @return an array of BigInteger, with <code>p</code> at index 0 and 186 * <code>q</code> at index 1, the seed at index 2, and the counter value 187 * at index 3. 188 */ 189 private static BigInteger[] generatePandQ(SecureRandom random, int valueL, 190 int valueN, int seedLen) { 191 String hashAlg = null; 192 if (valueN == 160) { 193 hashAlg = "SHA"; 194 } else if (valueN == 224) { 195 hashAlg = "SHA-224"; 196 } else if (valueN == 256) { 197 hashAlg = "SHA-256"; 198 } 199 MessageDigest hashObj = null; 200 try { 201 hashObj = MessageDigest.getInstance(hashAlg); 202 } catch (NoSuchAlgorithmException nsae) { 203 // should never happen 204 nsae.printStackTrace(); 205 } 206 207 /* Step 3, 4: Useful variables */ 208 int outLen = hashObj.getDigestLength()*8; 209 int n = (valueL - 1) / outLen; 210 int b = (valueL - 1) % outLen; 211 byte[] seedBytes = new byte[seedLen/8]; 212 BigInteger twoSl = TWO.pow(seedLen); 213 int primeCertainty = 80; // for 1024-bit prime P 214 if (valueL == 2048) { 215 primeCertainty = 112; 216 //} else if (valueL == 3072) { 217 // primeCertainty = 128; 218 } 219 220 BigInteger resultP, resultQ, seed = null; 221 int counter; 222 while (true) { 223 do { 224 /* Step 5 */ 225 random.nextBytes(seedBytes); 226 seed = new BigInteger(1, seedBytes); 227 228 /* Step 6 */ 229 BigInteger U = new BigInteger(1, hashObj.digest(seedBytes)). 230 mod(TWO.pow(valueN - 1)); 231 232 /* Step 7 */ 233 resultQ = TWO.pow(valueN - 1).add(U).add(ONE). subtract(U.mod(TWO)); 234 } while (!resultQ.isProbablePrime(primeCertainty)); 235 236 /* Step 10 */ 237 BigInteger offset = ONE; 238 /* Step 11 */ 239 for (counter = 0; counter < 4*valueL; counter++) { 240 BigInteger V[] = new BigInteger[n + 1]; 241 /* Step 11.1 */ 242 for (int j = 0; j <= n; j++) { 243 BigInteger J = BigInteger.valueOf(j); 244 BigInteger tmp = (seed.add(offset).add(J)).mod(twoSl); 245 byte[] vjBytes = hashObj.digest(toByteArray(tmp)); 246 V[j] = new BigInteger(1, vjBytes); 247 } 248 /* Step 11.2 */ 249 BigInteger W = V[0]; 250 for (int i = 1; i < n; i++) { 251 W = W.add(V[i].multiply(TWO.pow(i * outLen))); 252 } 253 W = W.add((V[n].mod(TWO.pow(b))).multiply(TWO.pow(n * outLen))); 254 /* Step 11.3 */ 255 BigInteger twoLm1 = TWO.pow(valueL - 1); 256 BigInteger X = W.add(twoLm1); 257 /* Step 11.4, 11.5 */ 258 BigInteger c = X.mod(resultQ.multiply(TWO)); 259 resultP = X.subtract(c.subtract(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(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 = ONE; 285 /* Step 1 */ 286 BigInteger pMinusOneOverQ = (p.subtract(ONE)).divide(q); 287 BigInteger resultG = ONE; 288 while (resultG.compareTo(TWO) < 0) { 289 /* Step 3 */ 290 resultG = h.modPow(pMinusOneOverQ, p); 291 h = h.add(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 }