jdk/src/share/classes/sun/security/provider/DSAParameterGenerator.java
changeset 13672 604588823b5a
parent 5506 202f599c92aa
child 14003 53c498ff6b0b
equal deleted inserted replaced
13670:1b01d62872eb 13672:604588823b5a
     1 /*
     1 /*
     2  * Copyright (c) 1997, 2006, Oracle and/or its affiliates. All rights reserved.
     2  * Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved.
     3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
     3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
     4  *
     4  *
     5  * This code is free software; you can redistribute it and/or modify it
     5  * This code is free software; you can redistribute it and/or modify it
     6  * under the terms of the GNU General Public License version 2 only, as
     6  * under the terms of the GNU General Public License version 2 only, as
     7  * published by the Free Software Foundation.  Oracle designates this
     7  * published by the Free Software Foundation.  Oracle designates this
    30 import java.security.AlgorithmParameters;
    30 import java.security.AlgorithmParameters;
    31 import java.security.InvalidAlgorithmParameterException;
    31 import java.security.InvalidAlgorithmParameterException;
    32 import java.security.NoSuchAlgorithmException;
    32 import java.security.NoSuchAlgorithmException;
    33 import java.security.NoSuchProviderException;
    33 import java.security.NoSuchProviderException;
    34 import java.security.InvalidParameterException;
    34 import java.security.InvalidParameterException;
       
    35 import java.security.MessageDigest;
    35 import java.security.SecureRandom;
    36 import java.security.SecureRandom;
    36 import java.security.spec.AlgorithmParameterSpec;
    37 import java.security.spec.AlgorithmParameterSpec;
    37 import java.security.spec.InvalidParameterSpecException;
    38 import java.security.spec.InvalidParameterSpecException;
    38 import java.security.spec.DSAParameterSpec;
    39 import java.security.spec.DSAParameterSpec;
       
    40 import java.security.spec.DSAGenParameterSpec;
    39 
    41 
    40 /**
    42 /**
    41  * This class generates parameters for the DSA algorithm. It uses a default
    43  * This class generates parameters for the DSA algorithm. It uses a default
    42  * prime modulus size of 1024 bits, which can be overwritten during
    44  * prime modulus size of 1024 bits, which can be overwritten during
    43  * initialization.
    45  * initialization.
    52  * @since 1.2
    54  * @since 1.2
    53  */
    55  */
    54 
    56 
    55 public class DSAParameterGenerator extends AlgorithmParameterGeneratorSpi {
    57 public class DSAParameterGenerator extends AlgorithmParameterGeneratorSpi {
    56 
    58 
    57     // the modulus length
    59     // the default parameters
    58     private int modLen = 1024; // default
    60     private static final DSAGenParameterSpec DEFAULTS =
       
    61         new DSAGenParameterSpec(1024, 160, 160);
       
    62 
       
    63     // the length of prime P, subPrime Q, and seed in bits
       
    64     private int valueL = -1;
       
    65     private int valueN = -1;
       
    66     private int seedLen = -1;
    59 
    67 
    60     // the source of randomness
    68     // the source of randomness
    61     private SecureRandom random;
    69     private SecureRandom random;
    62 
    70 
    63     // useful constants
    71     // useful constants
    64     private static final BigInteger ZERO = BigInteger.valueOf(0);
    72     private static final BigInteger ZERO = BigInteger.valueOf(0);
    65     private static final BigInteger ONE = BigInteger.valueOf(1);
    73     private static final BigInteger ONE = BigInteger.valueOf(1);
    66     private static final BigInteger TWO = BigInteger.valueOf(2);
    74     private static final BigInteger TWO = BigInteger.valueOf(2);
    67 
    75 
    68     // Make a SHA-1 hash function
       
    69     private SHA sha;
       
    70 
       
    71     public DSAParameterGenerator() {
    76     public DSAParameterGenerator() {
    72         this.sha = new SHA();
       
    73     }
    77     }
    74 
    78 
    75     /**
    79     /**
    76      * Initializes this parameter generator for a certain strength
    80      * Initializes this parameter generator for a certain strength
    77      * and source of randomness.
    81      * and source of randomness.
    78      *
    82      *
    79      * @param strength the strength (size of prime) in bits
    83      * @param strength the strength (size of prime) in bits
    80      * @param random the source of randomness
    84      * @param random the source of randomness
    81      */
    85      */
    82     protected void engineInit(int strength, SecureRandom random) {
    86     protected void engineInit(int strength, SecureRandom random) {
    83         /*
    87         if ((strength >= 512) && (strength <= 1024) && (strength % 64 == 0)) {
    84          * Bruce Schneier, "Applied Cryptography", 2nd Edition,
    88             this.valueN = 160;
    85          * Description of DSA:
    89         } else if (strength == 2048) {
    86          * [...] The algorithm uses the following parameter:
    90             this.valueN = 224;
    87          * p=a prime number L bits long, when L ranges from 512 to 1024 and is
    91 //      } else if (strength == 3072) {
    88          * a multiple of 64. [...]
    92 //          this.valueN = 256;
    89          */
    93         } else {
    90         if ((strength < 512) || (strength > 1024) || (strength % 64 != 0)) {
       
    91             throw new InvalidParameterException
    94             throw new InvalidParameterException
    92                 ("Prime size must range from 512 to 1024 "
    95                 ("Prime size should be 512 - 1024, or 2048");
    93                  + "and be a multiple of 64");
    96         }
    94         }
    97         this.valueL = strength;
    95         this.modLen = strength;
    98         this.seedLen = valueN;
    96         this.random = random;
    99         this.random = random;
    97     }
   100     }
    98 
   101 
    99     /**
   102     /**
   100      * Initializes this parameter generator with a set of
   103      * Initializes this parameter generator with a set of
   101      * algorithm-specific parameter generation values.
   104      * algorithm-specific parameter generation values.
   102      *
   105      *
   103      * @param params the set of algorithm-specific parameter generation values
   106      * @param genParamSpec the set of algorithm-specific parameter generation values
   104      * @param random the source of randomness
   107      * @param random the source of randomness
   105      *
   108      *
   106      * @exception InvalidAlgorithmParameterException if the given parameter
   109      * @exception InvalidAlgorithmParameterException if the given parameter
   107      * generation values are inappropriate for this parameter generator
   110      * generation values are inappropriate for this parameter generator
   108      */
   111      */
   109     protected void engineInit(AlgorithmParameterSpec genParamSpec,
   112     protected void engineInit(AlgorithmParameterSpec genParamSpec,
   110                               SecureRandom random)
   113                               SecureRandom random)
   111         throws InvalidAlgorithmParameterException {
   114         throws InvalidAlgorithmParameterException {
       
   115         if (!(genParamSpec instanceof DSAGenParameterSpec)) {
   112             throw new InvalidAlgorithmParameterException("Invalid parameter");
   116             throw new InvalidAlgorithmParameterException("Invalid parameter");
       
   117         }
       
   118         DSAGenParameterSpec dsaGenParams = (DSAGenParameterSpec) genParamSpec;
       
   119         if (dsaGenParams.getPrimePLength() > 2048) {
       
   120             throw new InvalidParameterException
       
   121                 ("Prime size should be 512 - 1024, or 2048");
       
   122         }
       
   123         // directly initialize using the already validated values
       
   124         this.valueL = dsaGenParams.getPrimePLength();
       
   125         this.valueN = dsaGenParams.getSubprimeQLength();
       
   126         this.seedLen = dsaGenParams.getSeedLength();
       
   127         this.random = random;
   113     }
   128     }
   114 
   129 
   115     /**
   130     /**
   116      * Generates the parameters.
   131      * Generates the parameters.
   117      *
   132      *
   121         AlgorithmParameters algParams = null;
   136         AlgorithmParameters algParams = null;
   122         try {
   137         try {
   123             if (this.random == null) {
   138             if (this.random == null) {
   124                 this.random = new SecureRandom();
   139                 this.random = new SecureRandom();
   125             }
   140             }
   126 
   141             if (valueL == -1) {
   127             BigInteger[] pAndQ = generatePandQ(this.random, this.modLen);
   142                 try {
       
   143                     engineInit(DEFAULTS, this.random);
       
   144                 } catch (InvalidAlgorithmParameterException iape) {
       
   145                     // should never happen
       
   146                 }
       
   147             }
       
   148             BigInteger[] pAndQ = generatePandQ(this.random, valueL,
       
   149                                                valueN, seedLen);
   128             BigInteger paramP = pAndQ[0];
   150             BigInteger paramP = pAndQ[0];
   129             BigInteger paramQ = pAndQ[1];
   151             BigInteger paramQ = pAndQ[1];
   130             BigInteger paramG = generateG(paramP, paramQ);
   152             BigInteger paramG = generateG(paramP, paramQ);
   131 
   153 
   132             DSAParameterSpec dsaParamSpec = new DSAParameterSpec(paramP,
   154             DSAParameterSpec dsaParamSpec =
   133                                                                  paramQ,
   155                 new DSAParameterSpec(paramP, paramQ, paramG);
   134                                                                  paramG);
       
   135             algParams = AlgorithmParameters.getInstance("DSA", "SUN");
   156             algParams = AlgorithmParameters.getInstance("DSA", "SUN");
   136             algParams.init(dsaParamSpec);
   157             algParams.init(dsaParamSpec);
   137         } catch (InvalidParameterSpecException e) {
   158         } catch (InvalidParameterSpecException e) {
   138             // this should never happen
   159             // this should never happen
   139             throw new RuntimeException(e.getMessage());
   160             throw new RuntimeException(e.getMessage());
   154      * This method will generate new seeds until a suitable
   175      * This method will generate new seeds until a suitable
   155      * seed has been found.
   176      * seed has been found.
   156      *
   177      *
   157      * @param random the source of randomness to generate the
   178      * @param random the source of randomness to generate the
   158      * seed
   179      * seed
   159      * @param L the size of <code>p</code>, in bits.
   180      * @param valueL the size of <code>p</code>, in bits.
       
   181      * @param valueN the size of <code>q</code>, in bits.
       
   182      * @param seedLen the length of <code>seed</code>, in bits.
   160      *
   183      *
   161      * @return an array of BigInteger, with <code>p</code> at index 0 and
   184      * @return an array of BigInteger, with <code>p</code> at index 0 and
   162      * <code>q</code> at index 1.
       
   163      */
       
   164     BigInteger[] generatePandQ(SecureRandom random, int L) {
       
   165         BigInteger[] result = null;
       
   166         byte[] seed = new byte[20];
       
   167 
       
   168         while(result == null) {
       
   169             for (int i = 0; i < 20; i++) {
       
   170                 seed[i] = (byte)random.nextInt();
       
   171             }
       
   172             result = generatePandQ(seed, L);
       
   173         }
       
   174         return result;
       
   175     }
       
   176 
       
   177     /*
       
   178      * Generates the prime and subprime parameters for DSA.
       
   179      *
       
   180      * <p>The seed parameter corresponds to the <code>SEED</code> parameter
       
   181      * referenced in the FIPS specification of the DSA algorithm,
       
   182      * and L is the size of <code>p</code>, in bits.
       
   183      *
       
   184      * @param seed the seed to generate the parameters
       
   185      * @param L the size of <code>p</code>, in bits.
       
   186      *
       
   187      * @return an array of BigInteger, with <code>p</code> at index 0,
       
   188      * <code>q</code> at index 1, the seed at index 2, and the counter value
   185      * <code>q</code> at index 1, the seed at index 2, and the counter value
   189      * at index 3, or null if the seed does not yield suitable numbers.
   186      * at index 3.
   190      */
   187      */
   191     BigInteger[] generatePandQ(byte[] seed, int L) {
   188     private static BigInteger[] generatePandQ(SecureRandom random, int valueL,
   192 
   189                                               int valueN, int seedLen) {
   193         /* Useful variables */
   190         String hashAlg = null;
   194         int g = seed.length * 8;
   191         if (valueN == 160) {
   195         int n = (L - 1) / 160;
   192             hashAlg = "SHA";
   196         int b = (L - 1) % 160;
   193         } else if (valueN == 224) {
   197 
   194             hashAlg = "SHA-224";
   198         BigInteger SEED = new BigInteger(1, seed);
   195         } else if (valueN == 256) {
   199         BigInteger TWOG = TWO.pow(2 * g);
   196             hashAlg = "SHA-256";
   200 
   197         }
   201         /* Step 2 (Step 1 is getting seed). */
   198         MessageDigest hashObj = null;
   202         byte[] U1 = SHA(seed);
   199         try {
   203         byte[] U2 = SHA(toByteArray((SEED.add(ONE)).mod(TWOG)));
   200             hashObj = MessageDigest.getInstance(hashAlg);
   204 
   201         } catch (NoSuchAlgorithmException nsae) {
   205         xor(U1, U2);
   202             // should never happen
   206         byte[] U = U1;
   203             nsae.printStackTrace();
   207 
   204         }
   208         /* Step 3: For q by setting the msb and lsb to 1 */
   205 
   209         U[0] |= 0x80;
   206         /* Step 3, 4: Useful variables */
   210         U[19] |= 1;
   207         int outLen = hashObj.getDigestLength()*8;
   211         BigInteger q = new BigInteger(1, U);
   208         int n = (valueL - 1) / outLen;
   212 
   209         int b = (valueL - 1) % outLen;
   213         /* Step 5 */
   210         byte[] seedBytes = new byte[seedLen/8];
   214          if (!q.isProbablePrime(80)) {
   211         BigInteger twoSl = TWO.pow(seedLen);
   215              return null;
   212         int primeCertainty = 80; // for 1024-bit prime P
   216 
   213         if (valueL == 2048) {
   217          } else {
   214             primeCertainty = 112;
   218              BigInteger V[] = new BigInteger[n + 1];
   215             //} else if (valueL == 3072) {
   219              BigInteger offset = TWO;
   216             //    primeCertainty = 128;
   220 
   217         }
   221              /* Step 6 */
   218 
   222              for (int counter = 0; counter < 4096; counter++) {
   219         BigInteger resultP, resultQ, seed = null;
   223 
   220         int counter;
   224                  /* Step 7 */
   221         while (true) {
   225                  for (int k = 0; k <= n; k++) {
   222             do {
   226                      BigInteger K = BigInteger.valueOf(k);
   223                 /* Step 5 */
   227                      BigInteger tmp = (SEED.add(offset).add(K)).mod(TWOG);
   224                 random.nextBytes(seedBytes);
   228                      V[k] = new BigInteger(1, SHA(toByteArray(tmp)));
   225                 seed = new BigInteger(1, seedBytes);
   229                  }
   226 
   230 
   227                 /* Step 6 */
   231                  /* Step 8 */
   228                 BigInteger U = new BigInteger(1, hashObj.digest(seedBytes)).
   232                  BigInteger W = V[0];
   229                     mod(TWO.pow(valueN - 1));
   233                  for (int i = 1; i < n; i++) {
   230 
   234                      W = W.add(V[i].multiply(TWO.pow(i * 160)));
   231                 /* Step 7 */
   235                  }
   232                 resultQ = TWO.pow(valueN - 1).add(U).add(ONE). subtract(U.mod(TWO));
   236                  W = W.add((V[n].mod(TWO.pow(b))).multiply(TWO.pow(n * 160)));
   233             } while (!resultQ.isProbablePrime(primeCertainty));
   237 
   234 
   238                  BigInteger TWOLm1 = TWO.pow(L - 1);
   235             /* Step 10 */
   239                  BigInteger X = W.add(TWOLm1);
   236             BigInteger offset = ONE;
   240 
   237             /* Step 11 */
   241                  /* Step 9 */
   238             for (counter = 0; counter < 4*valueL; counter++) {
   242                  BigInteger c = X.mod(q.multiply(TWO));
   239                 BigInteger V[] = new BigInteger[n + 1];
   243                  BigInteger p = X.subtract(c.subtract(ONE));
   240                 /* Step 11.1 */
   244 
   241                 for (int j = 0; j <= n; j++) {
   245                  /* Step 10 - 13 */
   242                     BigInteger J = BigInteger.valueOf(j);
   246                  if (p.compareTo(TWOLm1) > -1 && p.isProbablePrime(80)) {
   243                     BigInteger tmp = (seed.add(offset).add(J)).mod(twoSl);
   247                      BigInteger[] result = {p, q, SEED,
   244                     byte[] vjBytes = hashObj.digest(toByteArray(tmp));
   248                                             BigInteger.valueOf(counter)};
   245                     V[j] = new BigInteger(1, vjBytes);
   249                      return result;
   246                 }
   250                  }
   247                 /* Step 11.2 */
   251                  offset = offset.add(BigInteger.valueOf(n)).add(ONE);
   248                 BigInteger W = V[0];
       
   249                 for (int i = 1; i < n; i++) {
       
   250                     W = W.add(V[i].multiply(TWO.pow(i * outLen)));
       
   251                 }
       
   252                 W = W.add((V[n].mod(TWO.pow(b))).multiply(TWO.pow(n * outLen)));
       
   253                 /* Step 11.3 */
       
   254                 BigInteger twoLm1 = TWO.pow(valueL - 1);
       
   255                 BigInteger X = W.add(twoLm1);
       
   256                 /* Step 11.4, 11.5 */
       
   257                 BigInteger c = X.mod(resultQ.multiply(TWO));
       
   258                 resultP = X.subtract(c.subtract(ONE));
       
   259                 /* Step 11.6, 11.7 */
       
   260                 if (resultP.compareTo(twoLm1) > -1
       
   261                     && resultP.isProbablePrime(primeCertainty)) {
       
   262                     /* Step 11.8 */
       
   263                     BigInteger[] result = {resultP, resultQ, seed,
       
   264                                            BigInteger.valueOf(counter)};
       
   265                     return result;
       
   266                 }
       
   267                 /* Step 11.9 */
       
   268                 offset = offset.add(BigInteger.valueOf(n)).add(ONE);
   252              }
   269              }
   253              return null;
   270         }
   254          }
   271 
   255     }
   272     }
   256 
   273 
   257     /*
   274     /*
   258      * Generates the <code>g</code> parameter for DSA.
   275      * Generates the <code>g</code> parameter for DSA.
   259      *
   276      *
   260      * @param p the prime, <code>p</code>.
   277      * @param p the prime, <code>p</code>.
   261      * @param q the subprime, <code>q</code>.
   278      * @param q the subprime, <code>q</code>.
   262      *
   279      *
   263      * @param the <code>g</code>
   280      * @param the <code>g</code>
   264      */
   281      */
   265     BigInteger generateG(BigInteger p, BigInteger q) {
   282     private static BigInteger generateG(BigInteger p, BigInteger q) {
   266         BigInteger h = ONE;
   283         BigInteger h = ONE;
       
   284         /* Step 1 */
   267         BigInteger pMinusOneOverQ = (p.subtract(ONE)).divide(q);
   285         BigInteger pMinusOneOverQ = (p.subtract(ONE)).divide(q);
   268         BigInteger g = ONE;
   286         BigInteger resultG = ONE;
   269         while (g.compareTo(TWO) < 0) {
   287         while (resultG.compareTo(TWO) < 0) {
   270             g = h.modPow(pMinusOneOverQ, p);
   288             /* Step 3 */
       
   289             resultG = h.modPow(pMinusOneOverQ, p);
   271             h = h.add(ONE);
   290             h = h.add(ONE);
   272         }
   291         }
   273         return g;
   292         return resultG;
   274     }
       
   275 
       
   276     /*
       
   277      * Returns the SHA-1 digest of some data
       
   278      */
       
   279     private byte[] SHA(byte[] array) {
       
   280         sha.engineReset();
       
   281         sha.engineUpdate(array, 0, array.length);
       
   282         return sha.engineDigest();
       
   283     }
   293     }
   284 
   294 
   285     /*
   295     /*
   286      * Converts the result of a BigInteger.toByteArray call to an exact
   296      * Converts the result of a BigInteger.toByteArray call to an exact
   287      * signed magnitude representation for any positive number.
   297      * signed magnitude representation for any positive number.
   288      */
   298      */
   289     private byte[] toByteArray(BigInteger bigInt) {
   299     private static byte[] toByteArray(BigInteger bigInt) {
   290         byte[] result = bigInt.toByteArray();
   300         byte[] result = bigInt.toByteArray();
   291         if (result[0] == 0) {
   301         if (result[0] == 0) {
   292             byte[] tmp = new byte[result.length - 1];
   302             byte[] tmp = new byte[result.length - 1];
   293             System.arraycopy(result, 1, tmp, 0, tmp.length);
   303             System.arraycopy(result, 1, tmp, 0, tmp.length);
   294             result = tmp;
   304             result = tmp;
   295         }
   305         }
   296         return result;
   306         return result;
   297     }
   307     }
   298 
       
   299     /*
       
   300      * XORs U2 into U1
       
   301      */
       
   302     private void xor(byte[] U1, byte[] U2) {
       
   303         for (int i = 0; i < U1.length; i++) {
       
   304             U1[i] ^= U2[i];
       
   305         }
       
   306     }
       
   307 }
   308 }