1 /* DSSKeyPairGenerator.java --
2    Copyright 2001, 2002, 2003, 2006, 2010 Free Software Foundation, Inc.
3 
4 This file is a part of GNU Classpath.
5 
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.
10 
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.
15 
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
19 USA
20 
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
24 combination.
25 
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.  */
37 
38 
39 package gnu.java.security.key.dss;
40 
41 import gnu.java.security.Configuration;
42 import gnu.java.security.Registry;
43 import gnu.java.security.hash.Sha160;
44 import gnu.java.security.key.IKeyPairGenerator;
45 import gnu.java.security.util.PRNG;
46 
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;
52 import java.security.spec.DSAParameterSpec;
53 import java.util.Map;
54 import java.util.logging.Logger;
55 
56 /**
57  * A key-pair generator for asymetric keys to use in conjunction with the DSS
58  * (Digital Signature Standard).
59  * <p>
60  * References:
61  * <p>
62  * <a href="http://www.itl.nist.gov/fipspubs/fip186.htm">Digital Signature
63  * Standard (DSS)</a>, Federal Information Processing Standards Publication
64  * 186. National Institute of Standards and Technology.
65  */
66 public class DSSKeyPairGenerator
67     implements IKeyPairGenerator
68 {
69   private static final Logger log = Configuration.DEBUG ?
70                 Logger.getLogger(DSSKeyPairGenerator.class.getName()) : null;
71 
72   /** The BigInteger constant 2. */
73   private static final BigInteger TWO = BigInteger.valueOf(2L);
74 
75   /** Property name of the length (Integer) of the modulus (p) of a DSS key. */
76   public static final String MODULUS_LENGTH = "gnu.crypto.dss.L";
77 
78   /**
79    * Property name of the Boolean indicating wether or not to use default pre-
80    * computed values of <code>p</code>, <code>q</code> and <code>g</code>
81    * for a given modulus length. The ultimate behaviour of this generator with
82    * regard to using pre-computed parameter sets will depend on the value of
83    * this property and of the following one {@link #STRICT_DEFAULTS}:
84    * <ol>
85    * <li>If this property is {@link Boolean#FALSE} then this generator will
86    * accept being setup for generating parameters for any modulus length
87    * provided the modulus length is between <code>512</code> and
88    * <code>1024</code>, and is of the form <code>512 + 64 * n</code>. In
89    * addition, a new paramter set will always be generated; i.e. no pre-
90    * computed values are used.</li>
91    * <li>If this property is {@link Boolean#TRUE} and the value of
92    * {@link #STRICT_DEFAULTS} is also {@link Boolean#TRUE} then this generator
93    * will only accept being setup for generating parameters for modulus lengths
94    * of <code>512</code>, <code>768</code> and <code>1024</code>. Any
95    * other value, of the modulus length, even if between <code>512</code> and
96    * <code>1024</code>, and of the form <code>512 + 64 * n</code>, will
97    * cause an {@link IllegalArgumentException} to be thrown. When those modulus
98    * length (<code>512</code>, <code>768</code>, and <code>1024</code>)
99    * are specified, the paramter set is always the same.</li>
100    * <li>Finally, if this property is {@link Boolean#TRUE} and the value of
101    * {@link #STRICT_DEFAULTS} is {@link Boolean#FALSE} then this generator will
102    * behave as in point 1 above, except that it will use pre-computed values
103    * when possible; i.e. the modulus length is one of <code>512</code>,
104    * <code>768</code>, or <code>1024</code>.</li>
105    * </ol>
106    * The default value of this property is {@link Boolean#TRUE}.
107    */
108   public static final String USE_DEFAULTS = "gnu.crypto.dss.use.defaults";
109 
110   /**
111    * Property name of the Boolean indicating wether or not to generate new
112    * parameters, even if the modulus length <i>L</i> is not one of the pre-
113    * computed defaults (value {@link Boolean#FALSE}), or throw an exception
114    * (value {@link Boolean#TRUE}) -- the exception in this case is an
115    * {@link IllegalArgumentException}. The default value for this property is
116    * {@link Boolean#FALSE}. The ultimate behaviour of this generator will
117    * depend on the values of this and {@link #USE_DEFAULTS} properties -- see
118    * {@link #USE_DEFAULTS} for more information.
119    */
120   public static final String STRICT_DEFAULTS = "gnu.crypto.dss.strict.defaults";
121 
122   /**
123    * Property name of an optional {@link SecureRandom} instance to use. The
124    * default is to use a classloader singleton from {@link PRNG}.
125    */
126   public static final String SOURCE_OF_RANDOMNESS = "gnu.crypto.dss.prng";
127 
128   /**
129    * Property name of an optional {@link DSAParameterSpec} instance to use for
130    * this generator's <code>p</code>, <code>q</code>, and <code>g</code>
131    * values. The default is to generate these values or use pre-computed ones,
132    * depending on the value of the <code>USE_DEFAULTS</code> attribute.
133    */
134   public static final String DSS_PARAMETERS = "gnu.crypto.dss.params";
135 
136   /**
137    * Property name of the preferred encoding format to use when externalizing
138    * generated instance of key-pairs from this generator. The property is taken
139    * to be an {@link Integer} that encapsulates an encoding format identifier.
140    */
141   public static final String PREFERRED_ENCODING_FORMAT = "gnu.crypto.dss.encoding";
142 
143   /** Default value for the modulus length. */
144   public static final int DEFAULT_MODULUS_LENGTH = 1024;
145 
146   /** Default encoding format to use when none was specified. */
147   private static final int DEFAULT_ENCODING_FORMAT = Registry.RAW_ENCODING_ID;
148 
149   /** Initial SHS context. */
150   private static final int[] T_SHS = new int[] {
151       0x67452301, 0xEFCDAB89, 0x98BADCFE, 0x10325476, 0xC3D2E1F0
152   };
153 
154   // from jdk1.3.1/docs/guide/security/CryptoSpec.html#AppB
155   public static final DSAParameterSpec KEY_PARAMS_512 = new DSAParameterSpec(
156       new BigInteger(
157           "fca682ce8e12caba26efccf7110e526db078b05edecbcd1eb4a208f3ae1617ae"
158         + "01f35b91a47e6df63413c5e12ed0899bcd132acd50d99151bdc43ee737592e17", 16),
159       new BigInteger("962eddcc369cba8ebb260ee6b6a126d9346e38c5", 16),
160       new BigInteger(
161           "678471b27a9cf44ee91a49c5147db1a9aaf244f05a434d6486931d2d14271b9e"
162         + "35030b71fd73da179069b32e2935630e1c2062354d0da20a6c416e50be794ca4", 16));
163   public static final DSAParameterSpec KEY_PARAMS_768 = new DSAParameterSpec(
164       new BigInteger(
165           "e9e642599d355f37c97ffd3567120b8e25c9cd43e927b3a9670fbec5d8901419"
166         + "22d2c3b3ad2480093799869d1e846aab49fab0ad26d2ce6a22219d470bce7d77"
167         + "7d4a21fbe9c270b57f607002f3cef8393694cf45ee3688c11a8c56ab127a3daf", 16),
168       new BigInteger("9cdbd84c9f1ac2f38d0f80f42ab952e7338bf511", 16),
169       new BigInteger(
170           "30470ad5a005fb14ce2d9dcd87e38bc7d1b1c5facbaecbe95f190aa7a31d23c4"
171         + "dbbcbe06174544401a5b2c020965d8c2bd2171d3668445771f74ba084d2029d8"
172         + "3c1c158547f3a9f1a2715be23d51ae4d3e5a1f6a7064f316933a346d3f529252", 16));
173   public static final DSAParameterSpec KEY_PARAMS_1024 = new DSAParameterSpec(
174       new BigInteger(
175           "fd7f53811d75122952df4a9c2eece4e7f611b7523cef4400c31e3f80b6512669"
176         + "455d402251fb593d8d58fabfc5f5ba30f6cb9b556cd7813b801d346ff26660b7"
177         + "6b9950a5a49f9fe8047b1022c24fbba9d7feb7c61bf83b57e7c6a8a6150f04fb"
178         + "83f6d3c51ec3023554135a169132f675f3ae2b61d72aeff22203199dd14801c7", 16),
179       new BigInteger("9760508f15230bccb292b982a2eb840bf0581cf5", 16),
180       new BigInteger(
181           "f7e1a085d69b3ddecbbcab5c36b857b97994afbbfa3aea82f9574c0b3d078267"
182         + "5159578ebad4594fe67107108180b449167123e84c281613b7cf09328cc8a6e1"
183         + "3c167a8b547c8d28e0a3ae1e2bb3a675916ea37f0bfa213562f1fb627a01243b"
184         + "cca4f1bea8519089a883dfe15ae59f06928b665e807b552564014c3bfecf492a", 16));
185 
186   private static final BigInteger TWO_POW_160 = TWO.pow(160);
187 
188   /** The length of the modulus of DSS keys generated by this instance. */
189   private int L;
190 
191   /** The optional {@link SecureRandom} instance to use. */
192   private SecureRandom rnd = null;
193 
194   private BigInteger seed;
195 
196   private BigInteger counter;
197 
198   private BigInteger p;
199 
200   private BigInteger q;
201 
202   private BigInteger e;
203 
204   private BigInteger g;
205 
206   private BigInteger XKEY;
207 
208   /** Our default source of randomness. */
209   private PRNG prng = null;
210 
211   /** Preferred encoding format of generated keys. */
212   private int preferredFormat;
213 
name()214   public String name()
215   {
216     return Registry.DSS_KPG;
217   }
218 
219   /**
220    * Configures this instance.
221    *
222    * @param attributes the map of name/value pairs to use.
223    * @exception IllegalArgumentException if the designated MODULUS_LENGTH value
224    *              is not greater than 512, less than 1024 and not of the form
225    *              <code>512 + 64j</code>.
226    */
setup(Map attributes)227   public void setup(Map attributes)
228   {
229     // find out the modulus length
230     Integer l = (Integer) attributes.get(MODULUS_LENGTH);
231     L = (l == null ? DEFAULT_MODULUS_LENGTH : l.intValue());
232     if ((L % 64) != 0 || L < 512 || L > 1024)
233       throw new IllegalArgumentException(MODULUS_LENGTH);
234 
235     // should we use the default pre-computed params?
236     Boolean useDefaults = (Boolean) attributes.get(USE_DEFAULTS);
237     if (useDefaults == null)
238       useDefaults = Boolean.TRUE;
239 
240     Boolean strictDefaults = (Boolean) attributes.get(STRICT_DEFAULTS);
241     if (strictDefaults == null)
242       strictDefaults = Boolean.FALSE;
243 
244     // are we given a set of DSA params or we shall use/generate our own?
245     DSAParameterSpec params = (DSAParameterSpec) attributes.get(DSS_PARAMETERS);
246     if (params != null)
247       {
248         p = params.getP();
249         q = params.getQ();
250         g = params.getG();
251       }
252     else if (useDefaults.equals(Boolean.TRUE))
253       {
254         switch (L)
255           {
256           case 512:
257             p = KEY_PARAMS_512.getP();
258             q = KEY_PARAMS_512.getQ();
259             g = KEY_PARAMS_512.getG();
260             break;
261           case 768:
262             p = KEY_PARAMS_768.getP();
263             q = KEY_PARAMS_768.getQ();
264             g = KEY_PARAMS_768.getG();
265             break;
266           case 1024:
267             p = KEY_PARAMS_1024.getP();
268             q = KEY_PARAMS_1024.getQ();
269             g = KEY_PARAMS_1024.getG();
270             break;
271           default:
272             if (strictDefaults.equals(Boolean.TRUE))
273               throw new IllegalArgumentException(
274                   "Does not provide default parameters for " + L
275                   + "-bit modulus length");
276             else
277               {
278                 p = null;
279                 q = null;
280                 g = null;
281               }
282           }
283       }
284     else
285       {
286         p = null;
287         q = null;
288         g = null;
289       }
290     // do we have a SecureRandom, or should we use our own?
291     rnd = (SecureRandom) attributes.get(SOURCE_OF_RANDOMNESS);
292     // what is the preferred encoding format
293     Integer formatID = (Integer) attributes.get(PREFERRED_ENCODING_FORMAT);
294     preferredFormat = formatID == null ? DEFAULT_ENCODING_FORMAT
295                                        : formatID.intValue();
296     // set the seed-key
297     byte[] kb = new byte[20]; // we need 160 bits of randomness
298     nextRandomBytes(kb);
299     XKEY = new BigInteger(1, kb).setBit(159).setBit(0);
300   }
301 
generate()302   public KeyPair generate()
303   {
304     if (p == null)
305       {
306         BigInteger[] params = new FIPS186(L, rnd).generateParameters();
307         seed = params[FIPS186.DSA_PARAMS_SEED];
308         counter = params[FIPS186.DSA_PARAMS_COUNTER];
309         q = params[FIPS186.DSA_PARAMS_Q];
310         p = params[FIPS186.DSA_PARAMS_P];
311         e = params[FIPS186.DSA_PARAMS_E];
312         g = params[FIPS186.DSA_PARAMS_G];
313         if (Configuration.DEBUG)
314           {
315             log.fine("seed: " + seed.toString(16));
316             log.fine("counter: " + counter.intValue());
317             log.fine("q: " + q.toString(16));
318             log.fine("p: " + p.toString(16));
319             log.fine("e: " + e.toString(16));
320             log.fine("g: " + g.toString(16));
321           }
322       }
323     BigInteger x = nextX();
324     BigInteger y = g.modPow(x, p);
325     PublicKey pubK = new DSSPublicKey(preferredFormat, p, q, g, y);
326     PrivateKey secK = new DSSPrivateKey(preferredFormat, p, q, g, x);
327     return new KeyPair(pubK, secK);
328   }
329 
330   /**
331    * This method applies the following algorithm described in 3.1 of FIPS-186:
332    * <ol>
333    * <li>XSEED = optional user input.</li>
334    * <li>XVAL = (XKEY + XSEED) mod 2<sup>b</sup>.</li>
335    * <li>x = G(t, XVAL) mod q.</li>
336    * <li>XKEY = (1 + XKEY + x) mod 2<sup>b</sup>.</li>
337    * </ol>
338    * <p>
339    * Where <code>b</code> is the length of a secret b-bit seed-key (XKEY).
340    * <p>
341    * Note that in this implementation, XSEED, the optional user input, is always
342    * zero.
343    */
nextX()344   private synchronized BigInteger nextX()
345   {
346     byte[] xk = XKEY.toByteArray();
347     byte[] in = new byte[64]; // 512-bit block for SHS
348     System.arraycopy(xk, 0, in, 0, xk.length);
349     int[] H = Sha160.G(T_SHS[0], T_SHS[1], T_SHS[2], T_SHS[3], T_SHS[4], in, 0);
350     byte[] h = new byte[20];
351     for (int i = 0, j = 0; i < 5; i++)
352       {
353         h[j++] = (byte)(H[i] >>> 24);
354         h[j++] = (byte)(H[i] >>> 16);
355         h[j++] = (byte)(H[i] >>> 8);
356         h[j++] = (byte) H[i];
357       }
358     BigInteger result = new BigInteger(1, h).mod(q);
359     XKEY = XKEY.add(result).add(BigInteger.ONE).mod(TWO_POW_160);
360     return result;
361   }
362 
363   /**
364    * Fills the designated byte array with random data.
365    *
366    * @param buffer the byte array to fill with random data.
367    */
nextRandomBytes(byte[] buffer)368   private void nextRandomBytes(byte[] buffer)
369   {
370     if (rnd != null)
371       rnd.nextBytes(buffer);
372     else
373       getDefaultPRNG().nextBytes(buffer);
374   }
375 
getDefaultPRNG()376   private PRNG getDefaultPRNG()
377   {
378     if (prng == null)
379       prng = PRNG.getInstance();
380 
381     return prng;
382   }
383 }
384