Source for gnu.java.security.key.rsa.RSAKeyPairGenerator

   1: /* RSAKeyPairGenerator.java -- 
   2:    Copyright 2001, 2002, 2003, 2006 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.rsa;
  40: 
  41: import gnu.java.security.Configuration;
  42: import gnu.java.security.Registry;
  43: import gnu.java.security.key.IKeyPairGenerator;
  44: import gnu.java.security.util.PRNG;
  45: 
  46: import java.math.BigInteger;
  47: import java.security.KeyPair;
  48: import java.security.PrivateKey;
  49: import java.security.PublicKey;
  50: import java.security.SecureRandom;
  51: import java.security.spec.RSAKeyGenParameterSpec;
  52: import java.util.Map;
  53: import java.util.logging.Logger;
  54: 
  55: /**
  56:  * A key-pair generator for asymetric keys to use in conjunction with the RSA
  57:  * scheme.
  58:  * <p>
  59:  * Reference:
  60:  * <ol>
  61:  * <li><a
  62:  * href="http://www.cosic.esat.kuleuven.ac.be/nessie/workshop/submissions/rsa-pss.zip">
  63:  * RSA-PSS Signature Scheme with Appendix</a>, part B. Primitive specification
  64:  * and supporting documentation. Jakob Jonsson and Burt Kaliski. </li>
  65:  * <li><a href="http://www.cacr.math.uwaterloo.ca/hac/">Handbook of Applied
  66:  * Cryptography</a>, Alfred J. Menezes, Paul C. van Oorschot and Scott A.
  67:  * Vanstone. Section 11.3 RSA and related signature schemes.</li>
  68:  * </ol>
  69:  */
  70: public class RSAKeyPairGenerator
  71:     implements IKeyPairGenerator
  72: {
  73:   private static final Logger log = Logger.getLogger(RSAKeyPairGenerator.class.getName());
  74: 
  75:   /** The BigInteger constant 1. */
  76:   private static final BigInteger ONE = BigInteger.ONE;
  77: 
  78:   /** The BigInteger constant 2. */
  79:   private static final BigInteger TWO = BigInteger.valueOf(2L);
  80: 
  81:   /** Property name of the length (Integer) of the modulus of an RSA key. */
  82:   public static final String MODULUS_LENGTH = "gnu.crypto.rsa.L";
  83: 
  84:   /**
  85:    * Property name of an optional {@link SecureRandom} instance to use. The
  86:    * default is to use a classloader singleton from {@link PRNG}.
  87:    */
  88:   public static final String SOURCE_OF_RANDOMNESS = "gnu.crypto.rsa.prng";
  89: 
  90:   /**
  91:    * Property name of an optional {@link RSAKeyGenParameterSpec} instance to use
  92:    * for this generator's <code>n</code>, and <code>e</code> values. The
  93:    * default is to generate <code>n</code> and use a fixed value for
  94:    * <code>e</.code> (Fermat's F4 number).
  95:    */
  96:   public static final String RSA_PARAMETERS = "gnu.crypto.rsa.params";
  97: 
  98:   /**
  99:    * Property name of the preferred encoding format to use when externalizing
 100:    * generated instance of key-pairs from this generator. The property is taken
 101:    * to be an {@link Integer} that encapsulates an encoding format identifier.
 102:    */
 103:   public static final String PREFERRED_ENCODING_FORMAT = "gnu.crypto.rsa.encoding";
 104: 
 105:   /** Default value for the modulus length. */
 106:   private static final int DEFAULT_MODULUS_LENGTH = 1024;
 107: 
 108:   /** Default encoding format to use when none was specified. */
 109:   private static final int DEFAULT_ENCODING_FORMAT = Registry.RAW_ENCODING_ID;
 110: 
 111:   /** The desired bit length of the modulus. */
 112:   private int L;
 113: 
 114:   /**
 115:    * This implementation uses, by default, Fermat's F4 number as the public
 116:    * exponent.
 117:    */
 118:   private BigInteger e = BigInteger.valueOf(65537L);
 119: 
 120:   /** The optional {@link SecureRandom} instance to use. */
 121:   private SecureRandom rnd = null;
 122: 
 123:   /** Our default source of randomness. */
 124:   private PRNG prng = null;
 125: 
 126:   /** Preferred encoding format of generated keys. */
 127:   private int preferredFormat;
 128: 
 129:   // implicit 0-arguments constructor
 130: 
 131:   public String name()
 132:   {
 133:     return Registry.RSA_KPG;
 134:   }
 135: 
 136:   /**
 137:    * Configures this instance.
 138:    * 
 139:    * @param attributes the map of name/value pairs to use.
 140:    * @exception IllegalArgumentException if the designated MODULUS_LENGTH value
 141:    *              is less than 1024.
 142:    */
 143:   public void setup(Map attributes)
 144:   {
 145:     if (Configuration.DEBUG)
 146:       log.entering(this.getClass().getName(), "setup", attributes);
 147:     // do we have a SecureRandom, or should we use our own?
 148:     rnd = (SecureRandom) attributes.get(SOURCE_OF_RANDOMNESS);
 149:     // are we given a set of RSA params or we shall use our own?
 150:     RSAKeyGenParameterSpec params = (RSAKeyGenParameterSpec) attributes.get(RSA_PARAMETERS);
 151:     // find out the modulus length
 152:     if (params != null)
 153:       {
 154:         L = params.getKeysize();
 155:         e = params.getPublicExponent();
 156:       }
 157:     else
 158:       {
 159:         Integer l = (Integer) attributes.get(MODULUS_LENGTH);
 160:         L = (l == null ? DEFAULT_MODULUS_LENGTH : l.intValue());
 161:       }
 162:     if (L < 1024)
 163:       throw new IllegalArgumentException(MODULUS_LENGTH);
 164: 
 165:     // what is the preferred encoding format
 166:     Integer formatID = (Integer) attributes.get(PREFERRED_ENCODING_FORMAT);
 167:     preferredFormat = formatID == null ? DEFAULT_ENCODING_FORMAT
 168:                                        : formatID.intValue();
 169:     if (Configuration.DEBUG)
 170:       log.exiting(this.getClass().getName(), "setup");
 171:   }
 172: 
 173:   /**
 174:    * <p>
 175:    * The algorithm used here is described in <i>nessie-pss-B.pdf</i> document
 176:    * which is part of the RSA-PSS submission to NESSIE.
 177:    * </p>
 178:    * 
 179:    * @return an RSA keypair.
 180:    */
 181:   public KeyPair generate()
 182:   {
 183:     if (Configuration.DEBUG)
 184:       log.entering(this.getClass().getName(), "generate");
 185:     BigInteger p, q, n, d;
 186:     // 1. Generate a prime p in the interval [2**(M-1), 2**M - 1], where
 187:     // M = CEILING(L/2), and such that GCD(p, e) = 1
 188:     int M = (L + 1) / 2;
 189:     BigInteger lower = TWO.pow(M - 1);
 190:     BigInteger upper = TWO.pow(M).subtract(ONE);
 191:     byte[] kb = new byte[(M + 7) / 8]; // enough bytes to frame M bits
 192:     step1: while (true)
 193:       {
 194:         nextRandomBytes(kb);
 195:         p = new BigInteger(1, kb).setBit(0);
 196:         if (p.compareTo(lower) >= 0 && p.compareTo(upper) <= 0
 197:             && p.isProbablePrime(80) && p.gcd(e).equals(ONE))
 198:           break step1;
 199:       }
 200:     // 2. Generate a prime q such that the product of p and q is an L-bit
 201:     // number, and such that GCD(q, e) = 1
 202:     step2: while (true)
 203:       {
 204:         nextRandomBytes(kb);
 205:         q = new BigInteger(1, kb).setBit(0);
 206:         n = p.multiply(q);
 207:         if (n.bitLength() == L && q.isProbablePrime(80) && q.gcd(e).equals(ONE))
 208:           break step2;
 209:         // TODO: test for p != q
 210:       }
 211:     // TODO: ensure p < q
 212:     // 3. Put n = pq. The public key is (n, e).
 213:     // 4. Compute the parameters necessary for the private key K (see
 214:     // Section 2.2).
 215:     BigInteger phi = p.subtract(ONE).multiply(q.subtract(ONE));
 216:     d = e.modInverse(phi);
 217:     // 5. Output the public key and the private key.
 218:     PublicKey pubK = new GnuRSAPublicKey(preferredFormat, n, e);
 219:     PrivateKey secK = new GnuRSAPrivateKey(preferredFormat, p, q, e, d);
 220:     KeyPair result = new KeyPair(pubK, secK);
 221:     if (Configuration.DEBUG)
 222:       log.exiting(this.getClass().getName(), "generate", result);
 223:     return result;
 224:   }
 225: 
 226:   /**
 227:    * Fills the designated byte array with random data.
 228:    * 
 229:    * @param buffer the byte array to fill with random data.
 230:    */
 231:   private void nextRandomBytes(byte[] buffer)
 232:   {
 233:     if (rnd != null)
 234:       rnd.nextBytes(buffer);
 235:     else
 236:       getDefaultPRNG().nextBytes(buffer);
 237:   }
 238: 
 239:   private PRNG getDefaultPRNG()
 240:   {
 241:     if (prng == null)
 242:       prng = PRNG.getInstance();
 243: 
 244:     return prng;
 245:   }
 246: }