1 /*
2  * Copyright (c) 1997, 2018, Oracle and/or its affiliates. All rights reserved.
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
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
7  * published by the Free Software Foundation.  Oracle designates this
8  * particular file as subject to the "Classpath" exception as provided
9  * by Oracle in the LICENSE file that accompanied this code.
10  *
11  * This code is distributed in the hope that it will be useful, but WITHOUT
12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14  * version 2 for more details (a copy is included in the LICENSE file that
15  * accompanied this code).
16  *
17  * You should have received a copy of the GNU General Public License version
18  * 2 along with this work; if not, write to the Free Software Foundation,
19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20  *
21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22  * or visit www.oracle.com if you need additional information or have any
23  * questions.
24  */
25 
26 package sun.security.provider;
27 
28 import java.math.BigInteger;
29 
30 import java.security.*;
31 import java.security.SecureRandom;
32 import java.security.interfaces.DSAParams;
33 import java.security.spec.AlgorithmParameterSpec;
34 import java.security.spec.InvalidParameterSpecException;
35 import java.security.spec.DSAParameterSpec;
36 
37 import sun.security.jca.JCAUtil;
38 import static sun.security.util.SecurityProviderConstants.DEF_DSA_KEY_SIZE;
39 import static sun.security.util.SecurityProviderConstants.getDefDSASubprimeSize;
40 
41 /**
42  * This class generates DSA key parameters and public/private key
43  * pairs according to the DSS standard NIST FIPS 186. It uses the
44  * updated version of SHA, SHA-1 as described in FIPS 180-1.
45  *
46  * @author Benjamin Renaud
47  * @author Andreas Sterbenz
48  *
49  */
50 class DSAKeyPairGenerator extends KeyPairGenerator {
51 
52     /* Length for prime P and subPrime Q in bits */
53     private int plen;
54     private int qlen;
55 
56     /* whether to force new parameters to be generated for each KeyPair */
57     boolean forceNewParameters;
58 
59     /* preset algorithm parameters. */
60     private DSAParameterSpec params;
61 
62     /* The source of random bits to use */
63     private SecureRandom random;
64 
DSAKeyPairGenerator(int defaultKeySize)65     DSAKeyPairGenerator(int defaultKeySize) {
66         super("DSA");
67         initialize(defaultKeySize, null);
68     }
69 
checkStrength(int sizeP, int sizeQ)70     private static void checkStrength(int sizeP, int sizeQ) {
71         if ((sizeP >= 512) && (sizeP <= 1024) && (sizeP % 64 == 0)
72             && sizeQ == 160) {
73             // traditional - allow for backward compatibility
74             // L=multiples of 64 and between 512 and 1024 (inclusive)
75             // N=160
76         } else if (sizeP == 2048 && (sizeQ == 224 || sizeQ == 256)) {
77             // L=2048, N=224 or 256
78         } else if (sizeP == 3072 && sizeQ == 256) {
79             // L=3072, N=256
80         } else {
81             throw new InvalidParameterException
82                 ("Unsupported prime and subprime size combination: " +
83                  sizeP + ", " + sizeQ);
84         }
85     }
86 
initialize(int modlen, SecureRandom random)87     public void initialize(int modlen, SecureRandom random) {
88         init(modlen, random, false);
89     }
90 
91     /**
92      * Initializes the DSA object using a parameter object.
93      *
94      * @param params the parameter set to be used to generate
95      * the keys.
96      * @param random the source of randomness for this generator.
97      *
98      * @exception InvalidAlgorithmParameterException if the given parameters
99      * are inappropriate for this key pair generator
100      */
initialize(AlgorithmParameterSpec params, SecureRandom random)101     public void initialize(AlgorithmParameterSpec params, SecureRandom random)
102             throws InvalidAlgorithmParameterException {
103         if (!(params instanceof DSAParameterSpec)) {
104             throw new InvalidAlgorithmParameterException
105                 ("Inappropriate parameter");
106         }
107         init((DSAParameterSpec)params, random, false);
108     }
109 
init(int modlen, SecureRandom random, boolean forceNew)110     void init(int modlen, SecureRandom random, boolean forceNew) {
111         int subPrimeLen = getDefDSASubprimeSize(modlen);
112         checkStrength(modlen, subPrimeLen);
113         this.plen = modlen;
114         this.qlen = subPrimeLen;
115         this.params = null;
116         this.random = random;
117         this.forceNewParameters = forceNew;
118     }
119 
init(DSAParameterSpec params, SecureRandom random, boolean forceNew)120     void init(DSAParameterSpec params, SecureRandom random,
121         boolean forceNew) {
122         int sizeP = params.getP().bitLength();
123         int sizeQ = params.getQ().bitLength();
124         checkStrength(sizeP, sizeQ);
125         this.plen = sizeP;
126         this.qlen = sizeQ;
127         this.params = params;
128         this.random = random;
129         this.forceNewParameters = forceNew;
130     }
131 
132     /**
133      * Generates a pair of keys usable by any JavaSecurity compliant
134      * DSA implementation.
135      */
generateKeyPair()136     public KeyPair generateKeyPair() {
137         if (random == null) {
138             random = JCAUtil.getSecureRandom();
139         }
140         DSAParameterSpec spec;
141         try {
142             if (forceNewParameters) {
143                 // generate new parameters each time
144                 spec = ParameterCache.getNewDSAParameterSpec(plen, qlen, random);
145             } else {
146                 if (params == null) {
147                     params =
148                         ParameterCache.getDSAParameterSpec(plen, qlen, random);
149                 }
150                 spec = params;
151             }
152         } catch (GeneralSecurityException e) {
153             throw new ProviderException(e);
154         }
155         return generateKeyPair(spec.getP(), spec.getQ(), spec.getG(), random);
156     }
157 
generateKeyPair(BigInteger p, BigInteger q, BigInteger g, SecureRandom random)158     private KeyPair generateKeyPair(BigInteger p, BigInteger q, BigInteger g,
159                                    SecureRandom random) {
160 
161         BigInteger x = generateX(random, q);
162         BigInteger y = generateY(x, p, g);
163 
164         try {
165 
166             // See the comments in DSAKeyFactory, 4532506, and 6232513.
167 
168             DSAPublicKey pub;
169             pub = new DSAPublicKeyImpl(y, p, q, g);
170             DSAPrivateKey priv = new DSAPrivateKey(x, p, q, g);
171 
172             KeyPair pair = new KeyPair(pub, priv);
173             return pair;
174         } catch (InvalidKeyException e) {
175             throw new ProviderException(e);
176         }
177     }
178 
179     /**
180      * Generate the private key component of the key pair using the
181      * provided source of random bits. This method uses the random but
182      * source passed to generate a seed and then calls the seed-based
183      * generateX method.
184      */
generateX(SecureRandom random, BigInteger q)185     private BigInteger generateX(SecureRandom random, BigInteger q) {
186         BigInteger x = null;
187         byte[] temp = new byte[qlen];
188         while (true) {
189             random.nextBytes(temp);
190             x = new BigInteger(1, temp).mod(q);
191             if (x.signum() > 0 && (x.compareTo(q) < 0)) {
192                 return x;
193             }
194         }
195     }
196 
197     /**
198      * Generate the public key component y of the key pair.
199      *
200      * @param x the private key component.
201      *
202      * @param p the base parameter.
203      */
generateY(BigInteger x, BigInteger p, BigInteger g)204     BigInteger generateY(BigInteger x, BigInteger p, BigInteger g) {
205         BigInteger y = g.modPow(x, p);
206         return y;
207     }
208 
209     public static final class Current extends DSAKeyPairGenerator {
Current()210         public Current() {
211             super(DEF_DSA_KEY_SIZE);
212         }
213     }
214 
215     public static final class Legacy extends DSAKeyPairGenerator
216         implements java.security.interfaces.DSAKeyPairGenerator {
217 
Legacy()218         public Legacy() {
219             super(1024);
220         }
221 
222         /**
223          * Initializes the DSA key pair generator. If <code>genParams</code>
224          * is false, a set of pre-computed parameters is used.
225          */
226         @Override
initialize(int modlen, boolean genParams, SecureRandom random)227         public void initialize(int modlen, boolean genParams,
228             SecureRandom random) throws InvalidParameterException {
229             if (genParams) {
230                 super.init(modlen, random, true);
231             } else {
232                 DSAParameterSpec cachedParams =
233                     ParameterCache.getCachedDSAParameterSpec(modlen,
234                         getDefDSASubprimeSize(modlen));
235                 if (cachedParams == null) {
236                     throw new InvalidParameterException
237                         ("No precomputed parameters for requested modulus" +
238                          " size available");
239                 }
240                 super.init(cachedParams, random, false);
241             }
242         }
243 
244         /**
245          * Initializes the DSA object using a DSA parameter object.
246          *
247          * @param params a fully initialized DSA parameter object.
248          */
249         @Override
initialize(DSAParams params, SecureRandom random)250         public void initialize(DSAParams params, SecureRandom random)
251             throws InvalidParameterException {
252             if (params == null) {
253                 throw new InvalidParameterException("Params must not be null");
254              }
255              DSAParameterSpec spec = new DSAParameterSpec
256                  (params.getP(), params.getQ(), params.getG());
257              super.init(spec, random, false);
258         }
259     }
260 }
261