blob: 34ddfad41d644cd7b6576ca8c699bb73ab445412 [file] [log] [blame]
J. Duke319a3b92007-12-01 00:00:00 +00001/*
2 * Copyright 1997-2006 Sun Microsystems, Inc. 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. Sun designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
22 * CA 95054 USA or visit www.sun.com if you need additional information or
23 * have any questions.
24 */
25
26package sun.security.provider;
27
28import java.math.BigInteger;
29import java.security.AlgorithmParameterGeneratorSpi;
30import java.security.AlgorithmParameters;
31import java.security.InvalidAlgorithmParameterException;
32import java.security.NoSuchAlgorithmException;
33import java.security.NoSuchProviderException;
34import java.security.InvalidParameterException;
35import java.security.SecureRandom;
36import java.security.spec.AlgorithmParameterSpec;
37import java.security.spec.InvalidParameterSpecException;
38import java.security.spec.DSAParameterSpec;
39
40/**
41 * This class generates parameters for the DSA algorithm. It uses a default
42 * prime modulus size of 1024 bits, which can be overwritten during
43 * initialization.
44 *
45 * @author Jan Luehe
46 *
47 *
48 * @see java.security.AlgorithmParameters
49 * @see java.security.spec.AlgorithmParameterSpec
50 * @see DSAParameters
51 *
52 * @since 1.2
53 */
54
55public class DSAParameterGenerator extends AlgorithmParameterGeneratorSpi {
56
57 // the modulus length
58 private int modLen = 1024; // default
59
60 // the source of randomness
61 private SecureRandom random;
62
63 // useful constants
64 private static final BigInteger ZERO = BigInteger.valueOf(0);
65 private static final BigInteger ONE = BigInteger.valueOf(1);
66 private static final BigInteger TWO = BigInteger.valueOf(2);
67
68 // Make a SHA-1 hash function
69 private SHA sha;
70
71 public DSAParameterGenerator() {
72 this.sha = new SHA();
73 }
74
75 /**
76 * Initializes this parameter generator for a certain strength
77 * and source of randomness.
78 *
79 * @param strength the strength (size of prime) in bits
80 * @param random the source of randomness
81 */
82 protected void engineInit(int strength, SecureRandom random) {
83 /*
84 * Bruce Schneier, "Applied Cryptography", 2nd Edition,
85 * Description of DSA:
86 * [...] The algorithm uses the following parameter:
87 * p=a prime number L bits long, when L ranges from 512 to 1024 and is
88 * a multiple of 64. [...]
89 */
90 if ((strength < 512) || (strength > 1024) || (strength % 64 != 0)) {
91 throw new InvalidParameterException
92 ("Prime size must range from 512 to 1024 "
93 + "and be a multiple of 64");
94 }
95 this.modLen = strength;
96 this.random = random;
97 }
98
99 /**
100 * Initializes this parameter generator with a set of
101 * algorithm-specific parameter generation values.
102 *
103 * @param params the set of algorithm-specific parameter 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 protected void engineInit(AlgorithmParameterSpec genParamSpec,
110 SecureRandom random)
111 throws InvalidAlgorithmParameterException {
112 throw new InvalidAlgorithmParameterException("Invalid parameter");
113 }
114
115 /**
116 * Generates the parameters.
117 *
118 * @return the new AlgorithmParameters object
119 */
120 protected AlgorithmParameters engineGenerateParameters() {
121 AlgorithmParameters algParams = null;
122 try {
123 if (this.random == null) {
124 this.random = new SecureRandom();
125 }
126
127 BigInteger[] pAndQ = generatePandQ(this.random, this.modLen);
128 BigInteger paramP = pAndQ[0];
129 BigInteger paramQ = pAndQ[1];
130 BigInteger paramG = generateG(paramP, paramQ);
131
132 DSAParameterSpec dsaParamSpec = new DSAParameterSpec(paramP,
133 paramQ,
134 paramG);
135 algParams = AlgorithmParameters.getInstance("DSA", "SUN");
136 algParams.init(dsaParamSpec);
137 } catch (InvalidParameterSpecException e) {
138 // this should never happen
139 throw new RuntimeException(e.getMessage());
140 } catch (NoSuchAlgorithmException e) {
141 // this should never happen, because we provide it
142 throw new RuntimeException(e.getMessage());
143 } catch (NoSuchProviderException e) {
144 // this should never happen, because we provide it
145 throw new RuntimeException(e.getMessage());
146 }
147
148 return algParams;
149 }
150
151 /*
152 * Generates the prime and subprime parameters for DSA,
153 * using the provided source of randomness.
154 * This method will generate new seeds until a suitable
155 * seed has been found.
156 *
157 * @param random the source of randomness to generate the
158 * seed
159 * @param L the size of <code>p</code>, in bits.
160 *
161 * @return an array of BigInteger, with <code>p</code> at index 0 and
162 * <code>q</code> at index 1.
163 */
164 BigInteger[] generatePandQ(SecureRandom random, int L) {
165 BigInteger[] result = null;
166 byte[] seed = new byte[20];
167
168 while(result == null) {
169 for (int i = 0; i < 20; i++) {
170 seed[i] = (byte)random.nextInt();
171 }
172 result = generatePandQ(seed, L);
173 }
174 return result;
175 }
176
177 /*
178 * Generates the prime and subprime parameters for DSA.
179 *
180 * <p>The seed parameter corresponds to the <code>SEED</code> parameter
181 * referenced in the FIPS specification of the DSA algorithm,
182 * and L is the size of <code>p</code>, in bits.
183 *
184 * @param seed the seed to generate the parameters
185 * @param L the size of <code>p</code>, in bits.
186 *
187 * @return an array of BigInteger, with <code>p</code> at index 0,
188 * <code>q</code> at index 1, the seed at index 2, and the counter value
189 * at index 3, or null if the seed does not yield suitable numbers.
190 */
191 BigInteger[] generatePandQ(byte[] seed, int L) {
192
193 /* Useful variables */
194 int g = seed.length * 8;
195 int n = (L - 1) / 160;
196 int b = (L - 1) % 160;
197
198 BigInteger SEED = new BigInteger(1, seed);
199 BigInteger TWOG = TWO.pow(2 * g);
200
201 /* Step 2 (Step 1 is getting seed). */
202 byte[] U1 = SHA(seed);
203 byte[] U2 = SHA(toByteArray((SEED.add(ONE)).mod(TWOG)));
204
205 xor(U1, U2);
206 byte[] U = U1;
207
208 /* Step 3: For q by setting the msb and lsb to 1 */
209 U[0] |= 0x80;
210 U[19] |= 1;
211 BigInteger q = new BigInteger(1, U);
212
213 /* Step 5 */
214 if (!q.isProbablePrime(80)) {
215 return null;
216
217 } else {
218 BigInteger V[] = new BigInteger[n + 1];
219 BigInteger offset = TWO;
220
221 /* Step 6 */
222 for (int counter = 0; counter < 4096; counter++) {
223
224 /* Step 7 */
225 for (int k = 0; k <= n; k++) {
226 BigInteger K = BigInteger.valueOf(k);
227 BigInteger tmp = (SEED.add(offset).add(K)).mod(TWOG);
228 V[k] = new BigInteger(1, SHA(toByteArray(tmp)));
229 }
230
231 /* Step 8 */
232 BigInteger W = V[0];
233 for (int i = 1; i < n; i++) {
234 W = W.add(V[i].multiply(TWO.pow(i * 160)));
235 }
236 W = W.add((V[n].mod(TWO.pow(b))).multiply(TWO.pow(n * 160)));
237
238 BigInteger TWOLm1 = TWO.pow(L - 1);
239 BigInteger X = W.add(TWOLm1);
240
241 /* Step 9 */
242 BigInteger c = X.mod(q.multiply(TWO));
243 BigInteger p = X.subtract(c.subtract(ONE));
244
245 /* Step 10 - 13 */
246 if (p.compareTo(TWOLm1) > -1 && p.isProbablePrime(80)) {
247 BigInteger[] result = {p, q, SEED,
248 BigInteger.valueOf(counter)};
249 return result;
250 }
251 offset = offset.add(BigInteger.valueOf(n)).add(ONE);
252 }
253 return null;
254 }
255 }
256
257 /*
258 * Generates the <code>g</code> parameter for DSA.
259 *
260 * @param p the prime, <code>p</code>.
261 * @param q the subprime, <code>q</code>.
262 *
263 * @param the <code>g</code>
264 */
265 BigInteger generateG(BigInteger p, BigInteger q) {
266 BigInteger h = ONE;
267 BigInteger pMinusOneOverQ = (p.subtract(ONE)).divide(q);
268 BigInteger g = ONE;
269 while (g.compareTo(TWO) < 0) {
270 g = h.modPow(pMinusOneOverQ, p);
271 h = h.add(ONE);
272 }
273 return g;
274 }
275
276 /*
277 * Returns the SHA-1 digest of some data
278 */
279 private byte[] SHA(byte[] array) {
280 sha.engineReset();
281 sha.engineUpdate(array, 0, array.length);
282 return sha.engineDigest();
283 }
284
285 /*
286 * Converts the result of a BigInteger.toByteArray call to an exact
287 * signed magnitude representation for any positive number.
288 */
289 private byte[] toByteArray(BigInteger bigInt) {
290 byte[] result = bigInt.toByteArray();
291 if (result[0] == 0) {
292 byte[] tmp = new byte[result.length - 1];
293 System.arraycopy(result, 1, tmp, 0, tmp.length);
294 result = tmp;
295 }
296 return result;
297 }
298
299 /*
300 * XORs U2 into U1
301 */
302 private void xor(byte[] U1, byte[] U2) {
303 for (int i = 0; i < U1.length; i++) {
304 U1[i] ^= U2[i];
305 }
306 }
307}