001: /*
002: * @(#)DSAKeyPairGenerator.java 1.22 06/10/10
003: *
004: * Copyright 1990-2006 Sun Microsystems, Inc. All Rights Reserved.
005: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER
006: *
007: * This program is free software; you can redistribute it and/or
008: * modify it under the terms of the GNU General Public License version
009: * 2 only, as published by the Free Software Foundation.
010: *
011: * This program is distributed in the hope that it will be useful, but
012: * WITHOUT ANY WARRANTY; without even the implied warranty of
013: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
014: * General Public License version 2 for more details (a copy is
015: * included at /legal/license.txt).
016: *
017: * You should have received a copy of the GNU General Public License
018: * version 2 along with this work; if not, write to the Free Software
019: * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
020: * 02110-1301 USA
021: *
022: * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
023: * Clara, CA 95054 or visit www.sun.com if you need additional
024: * information or have any questions.
025: *
026: */
027:
028: package sun.security.provider;
029:
030: import java.util.Hashtable;
031: import java.math.BigInteger;
032: import java.security.AlgorithmParameters;
033: import java.security.AlgorithmParameterGenerator;
034: import java.security.InvalidAlgorithmParameterException;
035: import java.security.InvalidKeyException;
036: import java.security.InvalidParameterException;
037: import java.security.NoSuchAlgorithmException;
038: import java.security.NoSuchProviderException;
039: import java.security.KeyPair;
040: import java.security.KeyPairGenerator;
041: import java.security.ProviderException;
042: import java.security.SecureRandom;
043: import java.security.interfaces.DSAParams;
044: import java.security.spec.AlgorithmParameterSpec;
045: import java.security.spec.InvalidParameterSpecException;
046: import java.security.spec.DSAParameterSpec;
047:
048: import sun.security.x509.AlgIdDSA;
049:
050: /**
051: * This class generates DSA key parameters and public/private key
052: * pairs according to the DSS standard NIST FIPS 186. It uses the
053: * updated version of SHA, SHA-1 as described in FIPS 180-1.
054: *
055: * @author Benjamin Renaud
056: *
057: * @version 1.14, 02/02/00
058: */
059:
060: public class DSAKeyPairGenerator extends KeyPairGenerator implements
061: java.security.interfaces.DSAKeyPairGenerator {
062:
063: private static Hashtable precomputedParams;
064:
065: static {
066:
067: /* We support precomputed parameter for 512, 768 and 1024 bit
068: moduli. In this file we provide both the seed and counter
069: value of the generation process for each of these seeds,
070: for validation purposes. We also include the test vectors
071: from the DSA specification, FIPS 186, and the FIPS 186
072: Change No 1, which updates the test vector using SHA-1
073: instead of SHA (for both the G function and the message
074: hash.
075: */
076:
077: precomputedParams = new Hashtable();
078:
079: /*
080: * L = 512
081: * SEED = b869c82b35d70e1b1ff91b28e37a62ecdc34409b
082: * counter = 123
083: */
084: BigInteger p512 = new BigInteger(
085: "fca682ce8e12caba26efccf7110e526db078b05edecb"
086: + "cd1eb4a208f3ae1617ae01f35b91a47e6df63413c5e1"
087: + "2ed0899bcd132acd50d99151bdc43ee737592e17",
088: 16);
089:
090: BigInteger q512 = new BigInteger(
091: "962eddcc369cba8ebb260ee6b6a126d9346e38c5", 16);
092:
093: BigInteger g512 = new BigInteger(
094: "678471b27a9cf44ee91a49c5147db1a9aaf244f05a43"
095: + "4d6486931d2d14271b9e35030b71fd73da179069b32e"
096: + "2935630e1c2062354d0da20a6c416e50be794ca4",
097: 16);
098:
099: /*
100: * L = 768
101: * SEED = 77d0f8c4dad15eb8c4f2f8d6726cefd96d5bb399
102: * counter = 263
103: */
104: BigInteger p768 = new BigInteger(
105: "e9e642599d355f37c97ffd3567120b8e25c9cd43e"
106: + "927b3a9670fbec5d890141922d2c3b3ad24800937"
107: + "99869d1e846aab49fab0ad26d2ce6a22219d470bc"
108: + "e7d777d4a21fbe9c270b57f607002f3cef8393694"
109: + "cf45ee3688c11a8c56ab127a3daf", 16);
110:
111: BigInteger q768 = new BigInteger(
112: "9cdbd84c9f1ac2f38d0f80f42ab952e7338bf511", 16);
113:
114: BigInteger g768 = new BigInteger(
115: "30470ad5a005fb14ce2d9dcd87e38bc7d1b1c5fac"
116: + "baecbe95f190aa7a31d23c4dbbcbe06174544401a"
117: + "5b2c020965d8c2bd2171d3668445771f74ba084d2"
118: + "029d83c1c158547f3a9f1a2715be23d51ae4d3e5a"
119: + "1f6a7064f316933a346d3f529252", 16);
120:
121: /*
122: * L = 1024
123: * SEED = 8d5155894229d5e689ee01e6018a237e2cae64cd
124: * counter = 92
125: */
126: BigInteger p1024 = new BigInteger(
127: "fd7f53811d75122952df4a9c2eece4e7f611b7523c"
128: + "ef4400c31e3f80b6512669455d402251fb593d8d58"
129: + "fabfc5f5ba30f6cb9b556cd7813b801d346ff26660"
130: + "b76b9950a5a49f9fe8047b1022c24fbba9d7feb7c6"
131: + "1bf83b57e7c6a8a6150f04fb83f6d3c51ec3023554"
132: + "135a169132f675f3ae2b61d72aeff22203199dd148"
133: + "01c7", 16);
134:
135: BigInteger q1024 = new BigInteger(
136: "9760508f15230bccb292b982a2eb840bf0581cf5", 16);
137:
138: BigInteger g1024 = new BigInteger(
139: "f7e1a085d69b3ddecbbcab5c36b857b97994afbbfa"
140: + "3aea82f9574c0b3d0782675159578ebad4594fe671"
141: + "07108180b449167123e84c281613b7cf09328cc8a6"
142: + "e13c167a8b547c8d28e0a3ae1e2bb3a675916ea37f"
143: + "0bfa213562f1fb627a01243bcca4f1bea8519089a8"
144: + "83dfe15ae59f06928b665e807b552564014c3bfecf"
145: + "492a", 16);
146:
147: try {
148: AlgIdDSA alg512 = new AlgIdDSA(p512, q512, g512);
149: AlgIdDSA alg768 = new AlgIdDSA(p768, q768, g768);
150: AlgIdDSA alg1024 = new AlgIdDSA(p1024, q1024, g1024);
151:
152: precomputedParams.put(new Integer(512), alg512);
153: precomputedParams.put(new Integer(768), alg768);
154: precomputedParams.put(new Integer(1024), alg1024);
155:
156: } catch (Exception e) {
157: throw new InternalError("initializing precomputed "
158: + "algorithm parameters for Sun DSA");
159: }
160: }
161:
162: /* The modulus length */
163: private int modlen = 1024;
164:
165: /* Generate new parameters, even if we have precomputed ones. */
166: boolean generateNewParameters = false;
167:
168: /* preset algorithm parameters. */
169: private BigInteger presetP, presetQ, presetG;
170:
171: /* The source of random bits to use */
172: SecureRandom random;
173:
174: public DSAKeyPairGenerator() {
175: super ("DSA");
176: // Bug 5079897, automatically initialize to 1024.
177: initialize(1024, null);
178: }
179:
180: public void initialize(int strength, SecureRandom random) {
181: if ((strength < 512) || (strength > 1024)
182: || (strength % 64 != 0)) {
183: throw new InvalidParameterException(
184: "Modulus size must range from 512 to 1024 "
185: + "and be a multiple of 64");
186: }
187:
188: /* Set the random */
189: this .random = random;
190: if (this .random == null) {
191: this .random = new SecureRandom();
192: }
193:
194: this .modlen = strength;
195: DSAParams params = null;
196:
197: /* Find the precomputed parameters, if any */
198: if (!generateNewParameters) {
199: Integer mod = new Integer(this .modlen);
200: params = (DSAParams) precomputedParams.get(mod);
201: }
202: if (params != null) {
203: setParams(params);
204: }
205: }
206:
207: /**
208: * Initializes the DSA key pair generator. If <code>genParams</code>
209: * is false, a set of pre-computed parameters is used. In this case,
210: * <code>modelen</code> must be 512, 768, or 1024.
211: */
212: public void initialize(int modlen, boolean genParams,
213: SecureRandom random) throws InvalidParameterException {
214: if (genParams == false && modlen != 512 && modlen != 768
215: && modlen != 1024) {
216: throw new InvalidParameterException(
217: "No precomputed parameters for requested modulus size "
218: + "available");
219: }
220: this .generateNewParameters = genParams;
221: initialize(modlen, random);
222: }
223:
224: /**
225: * Initializes the DSA object using a DSA parameter object.
226: *
227: * @param params a fully initialized DSA parameter object.
228: */
229: public void initialize(DSAParams params, SecureRandom random)
230: throws InvalidParameterException {
231: if (params == null) {
232: throw new InvalidParameterException(
233: "Params must not be null");
234: }
235: initialize(params.getP().bitLength(), random);
236: setParams(params);
237: }
238:
239: /**
240: * Initializes the DSA object using a parameter object.
241: *
242: * @param params the parameter set to be used to generate
243: * the keys.
244: * @param random the source of randomness for this generator.
245: *
246: * @exception InvalidAlgorithmParameterException if the given parameters
247: * are inappropriate for this key pair generator
248: */
249: public void initialize(AlgorithmParameterSpec params,
250: SecureRandom random)
251: throws InvalidAlgorithmParameterException {
252: if (!(params instanceof DSAParameterSpec)) {
253: throw new InvalidAlgorithmParameterException(
254: "Inappropriate parameter");
255: }
256: initialize(((DSAParameterSpec) params).getP().bitLength(),
257: random);
258: setParams((DSAParameterSpec) params);
259: }
260:
261: /**
262: * Generates a pair of keys usable by any JavaSecurity compliant
263: * DSA implementation.
264: *
265: * @param rnd the source of random bits from which the random key
266: * generation parameters are drawn. In particular, this includes
267: * the XSEED parameter.
268: *
269: * @exception InvalidParameterException if the modulus is not
270: * between 512 and 1024.
271: */
272: public KeyPair generateKeyPair() {
273:
274: // set random if initialize() method has been skipped
275: if (this .random == null) {
276: this .random = new SecureRandom();
277: }
278:
279: if (presetP == null || presetQ == null || presetG == null
280: || generateNewParameters) {
281:
282: AlgorithmParameterGenerator dsaParamGen;
283:
284: try {
285: dsaParamGen = AlgorithmParameterGenerator.getInstance(
286: "DSA", "SUN");
287: } catch (NoSuchAlgorithmException e) {
288: // this should never happen, because we provide it
289: throw new RuntimeException(e.getMessage());
290: } catch (NoSuchProviderException e) {
291: // this should never happen, because we provide it
292: throw new RuntimeException(e.getMessage());
293: }
294:
295: dsaParamGen.init(modlen, random);
296:
297: DSAParameterSpec dsaParamSpec;
298: try {
299: dsaParamSpec = (DSAParameterSpec) dsaParamGen
300: .generateParameters().getParameterSpec(
301: DSAParameterSpec.class);
302: } catch (InvalidParameterSpecException e) {
303: // this should never happen
304: throw new RuntimeException(e.getMessage());
305: }
306: presetP = dsaParamSpec.getP();
307: presetQ = dsaParamSpec.getQ();
308: presetG = dsaParamSpec.getG();
309: }
310:
311: return generateKeyPair(presetP, presetQ, presetG, random);
312: }
313:
314: public KeyPair generateKeyPair(BigInteger p, BigInteger q,
315: BigInteger g, SecureRandom random) {
316:
317: BigInteger x = generateX(random, q);
318: BigInteger y = generateY(x, p, g);
319:
320: try {
321: DSAPublicKey pub = new DSAPublicKey(y, p, q, g);
322: DSAPrivateKey priv = new DSAPrivateKey(x, p, q, g);
323:
324: KeyPair pair = new KeyPair(pub, priv);
325: return pair;
326:
327: } catch (InvalidKeyException e) {
328: throw new ProviderException(e.getMessage());
329: }
330: }
331:
332: /* Test vectors from the DSA specs. */
333:
334: private static int[] testXSeed = { 0xbd029bbe, 0x7f51960b,
335: 0xcf9edb2b, 0x61f06f0f, 0xeb5a38b6 };
336:
337: private int[] x_t = { 0x67452301, 0xefcdab89, 0x98badcfe,
338: 0x10325476, 0xc3d2e1f0 };
339:
340: /**
341: * Generate the private key component of the key pair using the
342: * provided source of random bits. This method uses the random but
343: * source passed to generate a seed and then calls the seed-based
344: * generateX method.
345: */
346: private BigInteger generateX(SecureRandom random, BigInteger q) {
347: BigInteger x = null;
348: while (true) {
349: int[] seed = new int[5];
350: for (int i = 0; i < 5; i++) {
351: seed[i] = random.nextInt();
352: }
353: x = generateX(seed, q);
354: if (x.signum() > 0 && (x.compareTo(q) < 0)) {
355: break;
356: }
357: }
358: return x;
359: }
360:
361: /**
362: * Given a seed, generate the private key component of the key
363: * pair. In the terminology used in the DSA specification
364: * (FIPS-186) seed is the XSEED quantity.
365: *
366: * @param seed the seed to use to generate the private key.
367: */
368: BigInteger generateX(int[] seed, BigInteger q) {
369:
370: /* Test vector
371: int[] tseed = { 0xbd029bbe, 0x7f51960b, 0xcf9edb2b,
372: 0x61f06f0f, 0xeb5a38b6 };
373: seed = tseed;
374: */
375: // check out t in the spec.
376: int[] t = { 0x67452301, 0xEFCDAB89, 0x98BADCFE, 0x10325476,
377: 0xC3D2E1F0 };
378: //
379:
380: int[] tmp = DSA.SHA_7(seed, t);
381: byte[] tmpBytes = new byte[tmp.length * 4];
382: for (int i = 0; i < tmp.length; i++) {
383: int k = tmp[i];
384: for (int j = 0; j < 4; j++) {
385: tmpBytes[(i * 4) + j] = (byte) (k >>> (24 - (j * 8)));
386: }
387: }
388: BigInteger x = new BigInteger(1, tmpBytes).mod(q);
389: return x;
390: }
391:
392: /**
393: * Generate the public key component y of the key pair.
394: *
395: * @param x the private key component.
396: *
397: * @param p the base parameter.
398: */
399: BigInteger generateY(BigInteger x, BigInteger p, BigInteger g) {
400: BigInteger y = g.modPow(x, p);
401: return y;
402: }
403:
404: /**
405: * Set the parameters.
406: */
407: private void setParams(DSAParams params) {
408: presetP = params.getP();
409: presetQ = params.getQ();
410: presetG = params.getG();
411: }
412:
413: /**
414: * Set the parameters.
415: */
416: private void setParams(DSAParameterSpec params) {
417: presetP = params.getP();
418: presetQ = params.getQ();
419: presetG = params.getG();
420: }
421: }
|