1
/* GnuDHKeyPairGenerator.java --
2
Copyright (C) 2003, 2006 Free Software Foundation, Inc.
4
This file is a part of GNU Classpath.
6
GNU Classpath is free software; you can redistribute it and/or modify
7
it under the terms of the GNU General Public License as published by
8
the Free Software Foundation; either version 2 of the License, or (at
9
your option) any later version.
11
GNU Classpath is distributed in the hope that it will be useful, but
12
WITHOUT ANY WARRANTY; without even the implied warranty of
13
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14
General Public License for more details.
16
You should have received a copy of the GNU General Public License
17
along with GNU Classpath; if not, write to the Free Software
18
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
21
Linking this library statically or dynamically with other modules is
22
making a combined work based on this library. Thus, the terms and
23
conditions of the GNU General Public License cover the whole
26
As a special exception, the copyright holders of this library give you
27
permission to link this library with independent modules to produce an
28
executable, regardless of the license terms of these independent
29
modules, and to copy and distribute the resulting executable under
30
terms of your choice, provided that you also meet, for each linked
31
independent module, the terms and conditions of the license of that
32
module. An independent module is a module which is not derived from
33
or based on this library. If you modify this library, you may extend
34
this exception to your version of the library, but you are not
35
obligated to do so. If you do not wish to do so, delete this
36
exception statement from your version. */
39
package gnu.javax.crypto.key.dh;
41
import gnu.java.security.Registry;
42
import gnu.java.security.hash.Sha160;
43
import gnu.java.security.key.IKeyPairGenerator;
44
import gnu.java.security.util.PRNG;
46
import java.io.PrintWriter;
47
import java.math.BigInteger;
48
import java.security.KeyPair;
49
import java.security.PrivateKey;
50
import java.security.PublicKey;
51
import java.security.SecureRandom;
54
import javax.crypto.spec.DHGenParameterSpec;
55
import javax.crypto.spec.DHParameterSpec;
58
* <p>An implementation of a Diffie-Hellman keypair generator.</p>
62
* <li><a href="http://www.ietf.org/rfc/rfc2631.txt">Diffie-Hellman Key
63
* Agreement Method</a><br>
67
public class GnuDHKeyPairGenerator implements IKeyPairGenerator
70
// Debugging methods and variables
71
// -------------------------------------------------------------------------
73
private static final String NAME = "dh";
75
private static final boolean DEBUG = false;
77
private static final int debuglevel = 5;
79
private static final PrintWriter err = new PrintWriter(System.out, true);
81
private static void debug(String s)
83
err.println(">>> " + NAME + ": " + s);
86
// Constants and variables
87
// -------------------------------------------------------------------------
90
* Property name of an optional {@link SecureRandom} instance to use. The
91
* default is to use a classloader singleton from {@link PRNG}.
93
public static final String SOURCE_OF_RANDOMNESS = "gnu.crypto.dh.prng";
96
* Property name of an optional {@link DHGenParameterSpec} or
97
* {@link DHParameterSpec} instance to use for this generator.
99
public static final String DH_PARAMETERS = "gnu.crypto.dh.params";
101
/** Property name of the size in bits (Integer) of the public prime (p). */
102
public static final String PRIME_SIZE = "gnu.crypto.dh.L";
104
/** Property name of the size in bits (Integer) of the private exponent (x). */
105
public static final String EXPONENT_SIZE = "gnu.crypto.dh.m";
108
* Property name of the preferred encoding format to use when externalizing
109
* generated instance of key-pairs from this generator. The property is taken
110
* to be an {@link Integer} that encapsulates an encoding format identifier.
112
public static final String PREFERRED_ENCODING_FORMAT = "gnu.crypto.dh.encoding";
114
/** Default value for the size in bits of the public prime (p). */
115
// private static final int DEFAULT_PRIME_SIZE = 1024;
116
public static final int DEFAULT_PRIME_SIZE = 512;
118
/** Default value for the size in bits of the private exponent (x). */
119
public static final int DEFAULT_EXPONENT_SIZE = 160;
121
/** Default encoding format to use when none was specified. */
122
private static final int DEFAULT_ENCODING_FORMAT = Registry.RAW_ENCODING_ID;
124
/** The SHA instance to use. */
125
private Sha160 sha = new Sha160();
127
/** The optional {@link SecureRandom} instance to use. */
128
private SecureRandom rnd = null;
130
/** The desired size in bits of the public prime (p). */
133
/** The desired size in bits of the private exponent (x). */
136
private BigInteger seed;
138
private BigInteger counter;
140
private BigInteger q;
142
private BigInteger p;
144
private BigInteger j;
146
private BigInteger g;
148
/** Our default source of randomness. */
149
private PRNG prng = null;
151
/** Preferred encoding format of generated keys. */
152
private int preferredFormat;
155
// -------------------------------------------------------------------------
157
// default 0-arguments constructor
160
// -------------------------------------------------------------------------
163
// -------------------------------------------------------------------------
165
// gnu.crypto.keys.IKeyPairGenerator interface implementation ---------------
169
return Registry.DH_KPG;
172
public void setup(Map attributes)
174
// do we have a SecureRandom, or should we use our own?
175
rnd = (SecureRandom) attributes.get(SOURCE_OF_RANDOMNESS);
177
// are we given a set of Diffie-Hellman generation parameters or we shall
179
Object params = attributes.get(DH_PARAMETERS);
181
// find out the desired sizes
182
if (params instanceof DHGenParameterSpec)
184
DHGenParameterSpec jceSpec = (DHGenParameterSpec) params;
185
l = jceSpec.getPrimeSize();
186
m = jceSpec.getExponentSize();
188
else if (params instanceof DHParameterSpec)
190
// FIXME: I'm not sure this is correct. It seems to behave the
191
// same way as Sun's RI, but I don't know if this behavior is
192
// documented anywhere.
193
DHParameterSpec jceSpec = (DHParameterSpec) params;
199
// If no exponent size was given, generate an exponent as
200
// large as the prime.
206
Integer bi = (Integer) attributes.get(PRIME_SIZE);
207
l = (bi == null ? DEFAULT_PRIME_SIZE : bi.intValue());
208
bi = (Integer) attributes.get(EXPONENT_SIZE);
209
m = (bi == null ? DEFAULT_EXPONENT_SIZE : bi.intValue());
212
// if ((L % 256) != 0 || L < 1024) {
213
if ((l % 256) != 0 || l < DEFAULT_PRIME_SIZE)
215
throw new IllegalArgumentException("invalid modulus size");
217
if ((m % 8) != 0 || m < DEFAULT_EXPONENT_SIZE)
219
throw new IllegalArgumentException("invalid exponent size");
223
throw new IllegalArgumentException("exponent size > modulus size");
226
// what is the preferred encoding format
227
Integer formatID = (Integer) attributes.get(PREFERRED_ENCODING_FORMAT);
228
preferredFormat = formatID == null ? DEFAULT_ENCODING_FORMAT
229
: formatID.intValue();
232
public KeyPair generate()
236
BigInteger[] params = new RFC2631(m, l, rnd).generateParameters();
237
seed = params[RFC2631.DH_PARAMS_SEED];
238
counter = params[RFC2631.DH_PARAMS_COUNTER];
239
q = params[RFC2631.DH_PARAMS_Q];
240
p = params[RFC2631.DH_PARAMS_P];
241
j = params[RFC2631.DH_PARAMS_J];
242
g = params[RFC2631.DH_PARAMS_G];
243
if (DEBUG && debuglevel > 0)
245
debug("seed: 0x" + seed.toString(16));
246
debug("counter: " + counter.intValue());
247
debug("q: 0x" + q.toString(16));
248
debug("p: 0x" + p.toString(16));
249
debug("j: 0x" + j.toString(16));
250
debug("g: 0x" + g.toString(16));
254
// generate a private number x of length m such as: 1 < x < q - 1
255
BigInteger q_minus_1 = null;
257
q_minus_1 = q.subtract(BigInteger.ONE);
259
// We already check if m is modulo 8 in `setup.' This could just
261
byte[] mag = new byte[(m + 7) / 8];
265
nextRandomBytes(mag);
266
x = new BigInteger(1, mag);
267
if (x.bitLength() == m && x.compareTo(BigInteger.ONE) > 0
268
&& (q_minus_1 == null || x.compareTo(q_minus_1) < 0))
273
BigInteger y = g.modPow(x, p);
275
PrivateKey secK = new GnuDHPrivateKey(preferredFormat, q, p, g, x);
276
PublicKey pubK = new GnuDHPublicKey(preferredFormat, q, p, g, y);
278
return new KeyPair(pubK, secK);
281
// other methods -----------------------------------------------------------
284
* <p>Fills the designated byte array with random data.</p>
286
* @param buffer the byte array to fill with random data.
288
private void nextRandomBytes(byte[] buffer)
292
rnd.nextBytes(buffer);
295
getDefaultPRNG().nextBytes(buffer);
298
private PRNG getDefaultPRNG()
301
prng = PRNG.getInstance();