001: package org.bouncycastle.crypto.generators;
002:
003: import org.bouncycastle.crypto.digests.SHA1Digest;
004: import org.bouncycastle.crypto.params.DSAParameters;
005: import org.bouncycastle.crypto.params.DSAValidationParameters;
006:
007: import java.math.BigInteger;
008: import java.security.SecureRandom;
009:
010: /**
011: * generate suitable parameters for DSA, in line with FIPS 186-2.
012: */
013: public class DSAParametersGenerator {
014: private int size;
015: private int certainty;
016: private SecureRandom random;
017:
018: private static final BigInteger ONE = BigInteger.valueOf(1);
019: private static final BigInteger TWO = BigInteger.valueOf(2);
020:
021: /**
022: * initialise the key generator.
023: *
024: * @param size size of the key (range 2^512 -> 2^1024 - 64 bit increments)
025: * @param certainty measure of robustness of prime (for FIPS 186-2 compliance this should be at least 80).
026: * @param random random byte source.
027: */
028: public void init(int size, int certainty, SecureRandom random) {
029: this .size = size;
030: this .certainty = certainty;
031: this .random = random;
032: }
033:
034: /**
035: * add value to b, returning the result in a. The a value is treated
036: * as a BigInteger of length (a.length * 8) bits. The result is
037: * modulo 2^a.length in case of overflow.
038: */
039: private void add(byte[] a, byte[] b, int value) {
040: int x = (b[b.length - 1] & 0xff) + value;
041:
042: a[b.length - 1] = (byte) x;
043: x >>>= 8;
044:
045: for (int i = b.length - 2; i >= 0; i--) {
046: x += (b[i] & 0xff);
047: a[i] = (byte) x;
048: x >>>= 8;
049: }
050: }
051:
052: /**
053: * which generates the p and g values from the given parameters,
054: * returning the DSAParameters object.
055: * <p>
056: * Note: can take a while...
057: */
058: public DSAParameters generateParameters() {
059: byte[] seed = new byte[20];
060: byte[] part1 = new byte[20];
061: byte[] part2 = new byte[20];
062: byte[] u = new byte[20];
063: SHA1Digest sha1 = new SHA1Digest();
064: int n = (size - 1) / 160;
065: byte[] w = new byte[size / 8];
066:
067: BigInteger q = null, p = null, g = null;
068: int counter = 0;
069: boolean primesFound = false;
070:
071: while (!primesFound) {
072: do {
073: random.nextBytes(seed);
074:
075: sha1.update(seed, 0, seed.length);
076:
077: sha1.doFinal(part1, 0);
078:
079: System.arraycopy(seed, 0, part2, 0, seed.length);
080:
081: add(part2, seed, 1);
082:
083: sha1.update(part2, 0, part2.length);
084:
085: sha1.doFinal(part2, 0);
086:
087: for (int i = 0; i != u.length; i++) {
088: u[i] = (byte) (part1[i] ^ part2[i]);
089: }
090:
091: u[0] |= (byte) 0x80;
092: u[19] |= (byte) 0x01;
093:
094: q = new BigInteger(1, u);
095: } while (!q.isProbablePrime(certainty));
096:
097: counter = 0;
098:
099: int offset = 2;
100:
101: while (counter < 4096) {
102: for (int k = 0; k < n; k++) {
103: add(part1, seed, offset + k);
104: sha1.update(part1, 0, part1.length);
105: sha1.doFinal(part1, 0);
106: System.arraycopy(part1, 0, w, w.length - (k + 1)
107: * part1.length, part1.length);
108: }
109:
110: add(part1, seed, offset + n);
111: sha1.update(part1, 0, part1.length);
112: sha1.doFinal(part1, 0);
113: System.arraycopy(part1, part1.length
114: - ((w.length - (n) * part1.length)), w, 0,
115: w.length - n * part1.length);
116:
117: w[0] |= (byte) 0x80;
118:
119: BigInteger x = new BigInteger(1, w);
120:
121: BigInteger c = x.mod(q.multiply(TWO));
122:
123: p = x.subtract(c.subtract(ONE));
124:
125: if (p.testBit(size - 1)) {
126: if (p.isProbablePrime(certainty)) {
127: primesFound = true;
128: break;
129: }
130: }
131:
132: counter += 1;
133: offset += n + 1;
134: }
135: }
136:
137: //
138: // calculate the generator g
139: //
140: BigInteger pMinusOneOverQ = p.subtract(ONE).divide(q);
141:
142: for (;;) {
143: BigInteger h = new BigInteger(size, random);
144:
145: if (h.compareTo(ONE) <= 0
146: || h.compareTo(p.subtract(ONE)) >= 0) {
147: continue;
148: }
149:
150: g = h.modPow(pMinusOneOverQ, p);
151: if (g.compareTo(ONE) <= 0) {
152: continue;
153: }
154:
155: break;
156: }
157:
158: return new DSAParameters(p, q, g, new DSAValidationParameters(
159: seed, counter));
160: }
161: }
|