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