1 /*
  2  * Copyright (c) 2018, 2020, 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 8184359
 27  * @summary KeyLength support test for DiffieHellman, EC, XDH.
 28  *  Arguments order <KeyExchangeAlgorithm> <Provider> <KeyGenAlgorithm> <keyLen>
 29  * @library /test/lib
 30  * @build jdk.test.lib.Convert
 31  * @run main KeySizeTest DiffieHellman SunJCE DiffieHellman 512
 32  * @run main KeySizeTest DiffieHellman SunJCE DiffieHellman 768
 33  * @run main KeySizeTest DiffieHellman SunJCE DiffieHellman 832
 34  * @run main KeySizeTest DiffieHellman SunJCE DiffieHellman 1024
 35  * @run main KeySizeTest DiffieHellman SunJCE DiffieHellman 2048
 36  * @run main KeySizeTest DiffieHellman SunJCE DiffieHellman 3072
 37  * @run main KeySizeTest DiffieHellman SunJCE DiffieHellman 4096
 38  * @run main KeySizeTest DiffieHellman SunJCE DiffieHellman 6144
 39  * @run main KeySizeTest DiffieHellman SunJCE DiffieHellman 8192
 40  * @run main/othervm -Djdk.sunec.disableNative=false KeySizeTest ECDH SunEC EC 128
 41  * @run main/othervm -Djdk.sunec.disableNative=false KeySizeTest ECDH SunEC EC 192
 42  * @run main/othervm KeySizeTest ECDH SunEC EC 256
 43  * @run main KeySizeTest XDH SunEC XDH 255
 44  * @run main KeySizeTest XDH SunEC XDH 448
 45  */
 46 import java.math.BigInteger;
 47 import java.security.KeyFactory;
 48 import java.security.KeyPair;
 49 import java.security.KeyPairGenerator;
 50 import java.security.interfaces.ECPrivateKey;
 51 import java.security.interfaces.ECPublicKey;
 52 import java.security.interfaces.XECPrivateKey;
 53 import java.security.interfaces.XECPublicKey;
 54 import java.security.spec.PKCS8EncodedKeySpec;
 55 import java.security.spec.X509EncodedKeySpec;
 56 import java.security.spec.NamedParameterSpec;
 57 import java.util.Arrays;
 58 import javax.crypto.KeyAgreement;
 59 import javax.crypto.interfaces.DHPrivateKey;
 60 import javax.crypto.interfaces.DHPublicKey;
 61 import jdk.test.lib.Convert;
 62 
 63 public class KeySizeTest {
 64 
 65     public static void main(String[] args) throws Exception {
 66 
 67         String kaAlgo = args[0];
 68         String provider = args[1];
 69         String kpgAlgo = args[2];
 70         int keySize = Integer.parseInt(args[3]);
 71         testKeyAgreement(provider, kaAlgo, kpgAlgo, keySize);
 72     }
 73 
 74     /**
 75      * Perform KeyAgreement operation.
 76      */
 77     private static void testKeyAgreement(String provider, String kaAlgo,
 78             String kpgAlgo, int keySize) throws Exception {
 79 
 80         KeyPairGenerator kpg = KeyPairGenerator.getInstance(kpgAlgo, provider);
 81         kpg.initialize(keySize);
 82         KeyPair kp = kpg.generateKeyPair();
 83         // Test standard Key attributes.
 84         testKeyAttributes(provider, kpgAlgo, kp, keySize);
 85         // Test KeyAgreement.
 86         KeyAgreement ka = KeyAgreement.getInstance(kaAlgo, provider);
 87         ka.init(kp.getPrivate());
 88         ka.doPhase(kp.getPublic(), true);
 89         ka.generateSecret();
 90     }
 91 
 92     /**
 93      * Test standard Key attributes.
 94      */
 95     private static void testKeyAttributes(String provider, String kpgAlgo,
 96             KeyPair kp, int keySize) throws Exception {
 97 
 98         KeyFactory kf = KeyFactory.getInstance(kpgAlgo, provider);
 99         switch (kpgAlgo) {
100             case "DiffieHellman":
101                 // Verify PrivateKey attributes.
102                 DHPrivateKey dhPri = (DHPrivateKey) kp.getPrivate();
103                 BigInteger p = dhPri.getParams().getP();
104                 if (p.bitLength() != keySize) {
105                     throw new Exception(String.format("Invalid modulus size: "
106                             + "%s/%s", p.bitLength(), keySize));
107                 }
108                 if (!p.isProbablePrime(128)) {
109                     throw new Exception("The modulus is composite!");
110                 }
111                 PKCS8EncodedKeySpec dhPriSpec
112                         = new PKCS8EncodedKeySpec(dhPri.getEncoded());
113                 DHPrivateKey dhPriDecod
114                         = (DHPrivateKey) kf.generatePrivate(dhPriSpec);
115                 equals(dhPri.getX(), dhPriDecod.getX());
116                 equals(dhPri.getFormat(), dhPriDecod.getFormat());
117                 equals(dhPri.getEncoded(), dhPriDecod.getEncoded());
118                 equals(dhPri.getParams().getG(), dhPriDecod.getParams().getG());
119                 equals(dhPri.getParams().getL(), dhPriDecod.getParams().getL());
120                 equals(dhPri.getParams().getP(), dhPriDecod.getParams().getP());
121 
122                 // Verify PublicKey attributes.
123                 DHPublicKey dhPub = (DHPublicKey) kp.getPublic();
124                 p = dhPub.getParams().getP();
125                 if (p.bitLength() != keySize) {
126                     throw new Exception(String.format("Invalid modulus size: "
127                             + "%s/%s", p.bitLength(), keySize));
128                 }
129                 X509EncodedKeySpec dhPubSpec
130                         = new X509EncodedKeySpec(dhPub.getEncoded());
131                 DHPublicKey dhPubDecod
132                         = (DHPublicKey) kf.generatePublic(dhPubSpec);
133                 equals(dhPub.getY(), dhPubDecod.getY());
134                 equals(dhPub.getFormat(), dhPubDecod.getFormat());
135                 equals(dhPub.getEncoded(), dhPubDecod.getEncoded());
136                 equals(dhPub.getParams().getG(), dhPubDecod.getParams().getG());
137                 equals(dhPub.getParams().getL(), dhPubDecod.getParams().getL());
138                 equals(dhPub.getParams().getP(), dhPubDecod.getParams().getP());
139 
140                 BigInteger left = BigInteger.ONE;
141                 BigInteger right = p.subtract(BigInteger.ONE);
142                 BigInteger x = dhPri.getX();
143                 if ((x.compareTo(left) <= 0) || (x.compareTo(right) >= 0)) {
144                     throw new Exception(
145                             "X outside range [2, p - 2]: x: " + x + " p: " + p);
146                 }
147                 BigInteger y = dhPub.getY();
148                 if ((y.compareTo(left) <= 0) || (y.compareTo(right) >= 0)) {
149                     throw new Exception(
150                             "Y outside range [2, p - 2]: x: " + x + " p: " + p);
151                 }
152                 break;
153             case "EC":
154                 // Verify PrivateKey attributes.
155                 ECPrivateKey ecPriv = (ECPrivateKey) kp.getPrivate();
156                 PKCS8EncodedKeySpec ecPriSpec
157                         = new PKCS8EncodedKeySpec(ecPriv.getEncoded());
158                 ECPrivateKey ecPriDecod
159                         = (ECPrivateKey) kf.generatePrivate(ecPriSpec);
160                 equals(ecPriv.getS(), ecPriDecod.getS());
161                 equals(ecPriv.getFormat(), ecPriDecod.getFormat());
162                 equals(ecPriv.getEncoded(), ecPriDecod.getEncoded());
163                 equals(ecPriv.getParams().getCofactor(),
164                         ecPriDecod.getParams().getCofactor());
165                 equals(ecPriv.getParams().getCurve(),
166                         ecPriDecod.getParams().getCurve());
167                 equals(ecPriv.getParams().getGenerator(),
168                         ecPriDecod.getParams().getGenerator());
169                 equals(ecPriv.getParams().getOrder(),
170                         ecPriDecod.getParams().getOrder());
171 
172                 // Verify PublicKey attributes.
173                 ECPublicKey ecPub = (ECPublicKey) kp.getPublic();
174                 X509EncodedKeySpec ecPubSpec
175                         = new X509EncodedKeySpec(ecPub.getEncoded());
176                 ECPublicKey ecPubDecod
177                         = (ECPublicKey) kf.generatePublic(ecPubSpec);
178                 equals(ecPub.getW(), ecPubDecod.getW());
179                 equals(ecPub.getFormat(), ecPubDecod.getFormat());
180                 equals(ecPub.getEncoded(), ecPubDecod.getEncoded());
181                 equals(ecPub.getParams().getCofactor(),
182                         ecPubDecod.getParams().getCofactor());
183                 equals(ecPub.getParams().getCurve(),
184                         ecPubDecod.getParams().getCurve());
185                 equals(ecPub.getParams().getGenerator(),
186                         ecPubDecod.getParams().getGenerator());
187                 equals(ecPub.getParams().getOrder(),
188                         ecPubDecod.getParams().getOrder());
189                 break;
190             case "XDH":
191                 // Verify PrivateKey attributes.
192                 XECPrivateKey xdhPri = (XECPrivateKey) kp.getPrivate();
193                 PKCS8EncodedKeySpec xdhPriSpec
194                         = new PKCS8EncodedKeySpec(xdhPri.getEncoded());
195                 XECPrivateKey xdhPriDec
196                         = (XECPrivateKey) kf.generatePrivate(xdhPriSpec);
197                 equals(xdhPri.getScalar().get(), xdhPriDec.getScalar().get());
198                 equals(xdhPri.getFormat(), xdhPriDec.getFormat());
199                 equals(xdhPri.getEncoded(), xdhPriDec.getEncoded());
200                 equals(((NamedParameterSpec) xdhPri.getParams()).getName(),
201                         ((NamedParameterSpec) xdhPriDec.getParams()).getName());
202 
203                 // Verify PublicKey attributes.
204                 XECPublicKey xdhPub = (XECPublicKey) kp.getPublic();
205                 X509EncodedKeySpec xdhPubSpec
206                         = new X509EncodedKeySpec(xdhPub.getEncoded());
207                 XECPublicKey xdhPubDec
208                         = (XECPublicKey) kf.generatePublic(xdhPubSpec);
209                 equals(xdhPub.getU(), xdhPubDec.getU());
210                 equals(xdhPub.getFormat(), xdhPubDec.getFormat());
211                 equals(xdhPub.getEncoded(), xdhPubDec.getEncoded());
212                 equals(((NamedParameterSpec) xdhPub.getParams()).getName(),
213                         ((NamedParameterSpec) xdhPubDec.getParams()).getName());
214                 break;
215             default:
216                 throw new RuntimeException("Invalid Algo name " + kpgAlgo);
217         }
218     }
219 
220     private static boolean equals(Object actual, Object expected) {
221         boolean equals = actual.equals(expected);
222         if (!equals) {
223             throw new RuntimeException(String.format("Actual: %s, Expected: %s",
224                     actual, expected));
225         }
226         return equals;
227     }
228 
229     private static boolean equals(byte[] actual, byte[] expected) {
230         boolean equals = Arrays.equals(actual, expected);
231         if (!equals) {
232             throw new RuntimeException(String.format("Actual array: %s, "
233                     + "Expected array:%s", Convert.byteArrayToHexString(actual),
234                     Convert.byteArrayToHexString(expected)));
235         }
236         return equals;
237     }
238 }