1 /*
2  * Copyright (c) 2005, 2016, 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.
8  *
9  * This code is distributed in the hope that it will be useful, but WITHOUT
10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
12  * version 2 for more details (a copy is included in the LICENSE file that
13  * accompanied this code).
14  *
15  * You should have received a copy of the GNU General Public License version
16  * 2 along with this work; if not, write to the Free Software Foundation,
17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18  *
19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20  * or visit www.oracle.com if you need additional information or have any
21  * questions.
22  */
23 
24 /**
25  * @test
26  * @bug 6330287 6331386 7044060
27  * @summary verify that DHKeyPairGenerator returns keys of the expected size
28  * (modulus and exponent)
29  * -and-
30  *      DHKeyPairGenerator is using BigInteger.setBit
31  * @author Andreas Sterbenz
32  */
33 
34 import java.math.BigInteger;
35 import java.util.Arrays;
36 
37 import java.security.*;
38 import javax.crypto.*;
39 import javax.crypto.interfaces.*;
40 import javax.crypto.spec.*;
41 
42 /*
43  * NOTE:  BigInteger's bitlength() doesn't report leading zeros, only
44  * the number of bits needed to actually represent the number.  i.e.
45  *
46  *     new BigInteger("4").bitLength() = 3
47  *
48  * Since the private key x can vary 1 <= x <= p-2, we can't do any
49  * bitlength-based calculations here.  But we can check that p conforms
50  * as expected.
51  *
52  * If not specified, we're currently using an lsize of Math.max(384, psize/2).
53  */
54 public class TestExponentSize {
55 
56     /*
57      * Sizes and values for various lengths.
58      */
59     private enum Sizes {
60         two56(256), three84(384), five12(512), seven68(768), ten24(1024),
61         twenty48(2048);
62 
63         private final int intSize;
64         private final BigInteger bigIntValue;
65 
Sizes(int size)66         Sizes(int size) {
67             intSize = size;
68             byte [] bits = new byte[intSize/8];
69             Arrays.fill(bits, (byte)0xff);
70             bigIntValue = new BigInteger(1, bits);
71         }
72 
getIntSize()73         int getIntSize() {
74             return intSize;
75         }
76 
getBigIntValue()77         BigInteger getBigIntValue() {
78             return bigIntValue;
79         }
80     }
81 
main(String[] args)82     public static void main(String[] args) throws Exception {
83         KeyPair kp;
84         KeyPairGenerator kpg = KeyPairGenerator.getInstance("DH", "SunJCE");
85 
86         // Sun's default uses a default psize of 2048 and
87         // lsize of (pSize / 2) but at least 384 bits
88         kp = kpg.generateKeyPair();
89         checkKeyPair(kp, Sizes.twenty48, Sizes.ten24);
90 
91         DHPublicKey publicKey = (DHPublicKey)kp.getPublic();
92         BigInteger p = publicKey.getParams().getP();
93         BigInteger g = publicKey.getParams().getG();
94 
95         kpg.initialize(Sizes.ten24.getIntSize());
96         kp = kpg.generateKeyPair();
97         checkKeyPair(kp, Sizes.ten24, Sizes.five12);
98 
99         kpg.initialize(new DHParameterSpec(p, g, Sizes.ten24.getIntSize()));
100         kp = kpg.generateKeyPair();
101         checkKeyPair(kp, Sizes.twenty48, Sizes.ten24);
102 
103         kpg.initialize(new DHParameterSpec(p, g, Sizes.five12.getIntSize()));
104         kp = kpg.generateKeyPair();
105         checkKeyPair(kp, Sizes.twenty48, Sizes.five12);
106 
107         kpg.initialize(new DHParameterSpec(p, g, Sizes.two56.getIntSize()));
108         kp = kpg.generateKeyPair();
109         checkKeyPair(kp, Sizes.twenty48, Sizes.two56);
110 
111         kpg.initialize(Sizes.five12.getIntSize());
112         kp = kpg.generateKeyPair();
113         checkKeyPair(kp, Sizes.five12, Sizes.three84);
114 
115         kpg.initialize(Sizes.seven68.getIntSize());
116         kp = kpg.generateKeyPair();
117         checkKeyPair(kp, Sizes.seven68, Sizes.three84);
118 
119         // test w/ only pSize
120         kpg.initialize(Sizes.twenty48.getIntSize());
121         kp = kpg.generateKeyPair();
122         checkKeyPair(kp, Sizes.twenty48, Sizes.ten24);
123 
124         publicKey = (DHPublicKey)kp.getPublic();
125         p = publicKey.getParams().getP();
126         g = publicKey.getParams().getG();
127 
128         // test w/ all values specified
129         kpg.initialize(new DHParameterSpec(p, g, Sizes.five12.getIntSize()));
130         kp = kpg.generateKeyPair();
131         checkKeyPair(kp, Sizes.twenty48, Sizes.five12);
132 
133         System.out.println("OK");
134     }
135 
checkKeyPair(KeyPair kp, Sizes modulusSize, Sizes exponentSize)136     private static void checkKeyPair(KeyPair kp, Sizes modulusSize,
137             Sizes exponentSize) throws Exception {
138 
139         System.out.println("Checking (" + modulusSize + ", " +
140             exponentSize + ")");
141         DHPrivateKey privateKey = (DHPrivateKey)kp.getPrivate();
142         BigInteger p = privateKey.getParams().getP();
143         BigInteger x = privateKey.getX();
144 
145         if (p.bitLength() != modulusSize.getIntSize()) {
146             throw new Exception("Invalid modulus size: " + p.bitLength());
147         }
148 
149         if (x.bitLength() > exponentSize.getIntSize()) {
150             throw new Exception("X has more bits than expected: " +
151                 x.bitLength());
152         }
153 
154         BigInteger pMinus2 =
155             p.subtract(BigInteger.ONE).subtract(BigInteger.ONE);
156 
157         if ((x.compareTo(BigInteger.ONE) < 0 ||
158                 (x.compareTo(pMinus2)) > 0)) {
159             throw new Exception(
160                 "X outside range 1<=x<p-2:  x: " + x + " p: " + p);
161         }
162     }
163 }
164