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