1 /* 2 * Copyright (c) 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. 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 8171277 8206915 27 * @summary Test XDH key agreement 28 * @library /test/lib 29 * @build jdk.test.lib.Convert 30 * @run main TestXDH 31 */ 32 33 import java.security.*; 34 import java.security.spec.*; 35 import javax.crypto.*; 36 import java.util.Arrays; 37 import java.math.BigInteger; 38 import jdk.test.lib.Convert; 39 40 public class TestXDH { 41 main(String[] args)42 public static void main(String[] args) throws Exception { 43 44 runBasicTests(); 45 runKAT(); 46 runSmallOrderTest(); 47 runNonCanonicalTest(); 48 runCurveMixTest(); 49 } 50 runBasicTests()51 private static void runBasicTests() throws Exception { 52 runBasicTest("XDH", null); 53 runBasicTest("XDH", 255); 54 runBasicTest("XDH", 448); 55 runBasicTest("XDH", "X25519"); 56 runBasicTest("XDH", "X448"); 57 runBasicTest("X25519", null); 58 runBasicTest("X448", null); 59 runBasicTest("1.3.101.110", null); 60 runBasicTest("1.3.101.111", null); 61 runBasicTest("OID.1.3.101.110", null); 62 runBasicTest("OID.1.3.101.111", null); 63 } 64 runBasicTest(String name, Object param)65 private static void runBasicTest(String name, Object param) 66 throws Exception { 67 68 KeyPairGenerator kpg = KeyPairGenerator.getInstance(name); 69 AlgorithmParameterSpec paramSpec = null; 70 if (param instanceof Integer) { 71 kpg.initialize((Integer) param); 72 } else if (param instanceof String) { 73 paramSpec = new NamedParameterSpec((String) param); 74 kpg.initialize(paramSpec); 75 } 76 KeyPair kp = kpg.generateKeyPair(); 77 78 KeyAgreement ka = KeyAgreement.getInstance(name); 79 ka.init(kp.getPrivate(), paramSpec); 80 ka.doPhase(kp.getPublic(), true); 81 82 byte[] secret = ka.generateSecret(); 83 84 KeyFactory kf = KeyFactory.getInstance(name); 85 // Test with X509 and PKCS8 key specs 86 X509EncodedKeySpec pubSpec = 87 kf.getKeySpec(kp.getPublic(), X509EncodedKeySpec.class); 88 PKCS8EncodedKeySpec priSpec = 89 kf.getKeySpec(kp.getPrivate(), PKCS8EncodedKeySpec.class); 90 91 PublicKey pubKey = kf.generatePublic(pubSpec); 92 PrivateKey priKey = kf.generatePrivate(priSpec); 93 94 ka.init(priKey); 95 ka.doPhase(pubKey, true); 96 byte[] secret2 = ka.generateSecret(); 97 if (!Arrays.equals(secret, secret2)) { 98 throw new RuntimeException("Arrays not equal"); 99 } 100 101 // make sure generateSecret() resets the state to after init() 102 try { 103 ka.generateSecret(); 104 throw new RuntimeException("generateSecret does not reset state"); 105 } catch (IllegalStateException ex) { 106 // do nothing---this is expected 107 } 108 ka.doPhase(pubKey, true); 109 ka.generateSecret(); 110 111 // test with XDH key specs 112 XECPublicKeySpec xdhPublic = 113 kf.getKeySpec(kp.getPublic(), XECPublicKeySpec.class); 114 XECPrivateKeySpec xdhPrivate = 115 kf.getKeySpec(kp.getPrivate(), XECPrivateKeySpec.class); 116 PublicKey pubKey2 = kf.generatePublic(xdhPublic); 117 PrivateKey priKey2 = kf.generatePrivate(xdhPrivate); 118 ka.init(priKey2); 119 ka.doPhase(pubKey2, true); 120 byte[] secret3 = ka.generateSecret(); 121 if (!Arrays.equals(secret, secret3)) { 122 throw new RuntimeException("Arrays not equal"); 123 } 124 } 125 runSmallOrderTest()126 private static void runSmallOrderTest() throws Exception { 127 // Ensure that small-order points are rejected 128 129 // X25519 130 // 0 131 testSmallOrder( 132 "X25519", 133 "77076D0A7318A57D3C16C17251B26645DF4C2F87EBC0992AB177FBA51DB92C2A", 134 "0000000000000000000000000000000000000000000000000000000000000000", 135 "0000000000000000000000000000000000000000000000000000000000000000"); 136 // 1 and -1 137 testSmallOrder( 138 "X25519", 139 "77076D0A7318A57D3C16C17251B26645DF4C2F87EBC0992AB177FBA51DB92C2A", 140 "0100000000000000000000000000000000000000000000000000000000000000", 141 "0000000000000000000000000000000000000000000000000000000000000000"); 142 testSmallOrder( 143 "X25519", 144 "77076D0A7318A57D3C16C17251B26645DF4C2F87EBC0992AB177FBA51DB92C2A", 145 "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f", 146 "0000000000000000000000000000000000000000000000000000000000000000"); 147 148 // order 8 points 149 testSmallOrder( 150 "X25519", 151 "77076D0A7318A57D3C16C17251B26645DF4C2F87EBC0992AB177FBA51DB92C2A", 152 "5f9c95bca3508c24b1d0b1559c83ef5b04445cc4581c8e86d8224eddd09f1157", 153 "0000000000000000000000000000000000000000000000000000000000000000"); 154 testSmallOrder( 155 "X25519", 156 "77076D0A7318A57D3C16C17251B26645DF4C2F87EBC0992AB177FBA51DB92C2A", 157 "e0eb7a7c3b41b8ae1656e3faf19fc46ada098deb9c32b1fd866205165f49b800", 158 "0000000000000000000000000000000000000000000000000000000000000000"); 159 160 // X448 161 // 0 162 testSmallOrder( 163 "X448", 164 "9A8F4925D1519F5775CF46B04B5800D4EE9EE8BAE8BC5565D498C28DD9C9BA" + 165 "F574A9419744897391006382A6F127AB1D9AC2D8C0A598726B", 166 "00000000000000000000000000000000000000000000000000000000000000" + 167 "00000000000000000000000000000000000000000000000000", 168 "00000000000000000000000000000000000000000000000000000000000000" + 169 "00000000000000000000000000000000000000000000000000"); 170 // 1 and -1 171 testSmallOrder( 172 "X448", 173 "9A8F4925D1519F5775CF46B04B5800D4EE9EE8BAE8BC5565D498C28DD9C9BA" + 174 "F574A9419744897391006382A6F127AB1D9AC2D8C0A598726B", 175 "01000000000000000000000000000000000000000000000000000000000000" + 176 "00000000000000000000000000000000000000000000000000", 177 "00000000000000000000000000000000000000000000000000000000000000" + 178 "00000000000000000000000000000000000000000000000000"); 179 testSmallOrder( 180 "X448", 181 "9A8F4925D1519F5775CF46B04B5800D4EE9EE8BAE8BC5565D498C28DD9C9BAF" + 182 "574A9419744897391006382A6F127AB1D9AC2D8C0A598726B", 183 "fefffffffffffffffffffffffffffffffffffffffffffffffffffffffefffff" + 184 "fffffffffffffffffffffffffffffffffffffffffffffffff", 185 "000000000000000000000000000000000000000000000000000000000000000" + 186 "0000000000000000000000000000000000000000000000000"); 187 } 188 testSmallOrder(String name, String a_pri, String b_pub, String result)189 private static void testSmallOrder(String name, String a_pri, 190 String b_pub, String result) throws Exception { 191 192 try { 193 runDiffieHellmanTest(name, a_pri, b_pub, result); 194 } catch (InvalidKeyException ex) { 195 return; 196 } 197 198 throw new RuntimeException("No exception on small-order point"); 199 } 200 runNonCanonicalTest()201 private static void runNonCanonicalTest() throws Exception { 202 // Test non-canonical values 203 204 // high bit of public key set 205 // X25519 206 runDiffieHellmanTest( 207 "X25519", 208 "77076D0A7318A57D3C16C17251B26645DF4C2F87EBC0992AB177FBA51DB92C2A", 209 "DE9EDB7D7B7DC1B4D35B61C2ECE435373F8343C85B78674DADFC7E146F882B8F", 210 "954e472439316f118ae158b65619eecff9e6bcf51ab29add66f3fd088681e233"); 211 212 runDiffieHellmanTest( 213 "3030020100300706032b656e05000422042077076d0a7318a57d3c16c1725" + 214 "1b26645df4c2f87ebc0992ab177fba51db92c2a", 215 "302c300706032b656e0500032100de9edb7d7b7dc1b4d35b61c2ece435373f" + 216 "8343c85b78674dadfc7e146f882b8f", 217 "954e472439316f118ae158b65619eecff9e6bcf51ab29add66f3fd088681e233"); 218 219 // large public key 220 221 // X25519 222 // public key value is 2^255-2 223 runDiffieHellmanTest( 224 "X25519", 225 "77076D0A7318A57D3C16C17251B26645DF4C2F87EBC0992AB177FBA51DB92C2A", 226 "FEFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF7F", 227 "81a02a45014594332261085128959869fc0540c6b12380f51db4b41380de2c2c"); 228 229 runDiffieHellmanTest( 230 "3030020100300706032b656e05000422042077076d0a7318a57d3c16c17251" + 231 "b26645df4c2f87ebc0992ab177fba51db92c2a", 232 "302c300706032b656e0500032100FEFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF" + 233 "FFFFFFFFFFFFFFFFFFFFFFFFFFFF7F", 234 "81a02a45014594332261085128959869fc0540c6b12380f51db4b41380de2c2c"); 235 236 // X448 237 // public key value is 2^448-2 238 runDiffieHellmanTest( 239 "X448", 240 "9A8F4925D1519F5775CF46B04B5800D4EE9EE8BAE8BC5565D498C28DD9C9BA" + 241 "F574A9419744897391006382A6F127AB1D9AC2D8C0A598726B", 242 "FEFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF" + 243 "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF", 244 "66e2e682b1f8e68c809f1bb3e406bd826921d9c1a5bfbfcbab7ae72feecee6" + 245 "3660eabd54934f3382061d17607f581a90bdac917a064959fb"); 246 247 runDiffieHellmanTest( 248 "3048020100300706032B656F0500043A04389A8F4925D1519F5775CF46B04B" + 249 "5800D4EE9EE8BAE8BC5565D498C28DD9C9BAF574A9419744897391006382A6" + 250 "F127AB1D9AC2D8C0A598726B", 251 "3044300706032B656F0500033900FEFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF" + 252 "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF" + 253 "FFFFFFFFFFFFFFFF", 254 "66e2e682b1f8e68c809f1bb3e406bd826921d9c1a5bfbfcbab7ae72feecee6" + 255 "3660eabd54934f3382061d17607f581a90bdac917a064959fb"); 256 257 } 258 runKAT()259 private static void runKAT() throws Exception { 260 // Test both sides of the key exchange using vectors in RFC 7748 261 262 // X25519 263 // raw 264 runDiffieHellmanTest( 265 "X25519", 266 "77076D0A7318A57D3C16C17251B26645DF4C2F87EBC0992AB177FBA51DB92C2A", 267 "DE9EDB7D7B7DC1B4D35B61C2ECE435373F8343C85B78674DADFC7E146F882B4F", 268 "4a5d9d5ba4ce2de1728e3bf480350f25e07e21c947d19e3376f09b3c1e161742"); 269 270 runDiffieHellmanTest( 271 "X25519", 272 "5DAB087E624A8A4B79E17F8B83800EE66F3BB1292618B6FD1C2F8B27FF88E0EB", 273 "8520F0098930A754748B7DDCB43EF75A0DBF3A0D26381AF4EBA4A98EAA9B4E6A", 274 "4a5d9d5ba4ce2de1728e3bf480350f25e07e21c947d19e3376f09b3c1e161742"); 275 276 // encoded 277 runDiffieHellmanTest( 278 "3030020100300706032B656E05000422042077076D0A7318A57D3C16C17251" + 279 "B26645DF4C2F87EBC0992AB177FBA51DB92C2A", 280 "302C300706032B656E0500032100DE9EDB7D7B7DC1B4D35B61C2ECE435373F" + 281 "8343C85B78674DADFC7E146F882B4F", 282 "4a5d9d5ba4ce2de1728e3bf480350f25e07e21c947d19e3376f09b3c1e161742"); 283 284 runDiffieHellmanTest( 285 "3030020100300706032B656E0500042204205DAB087E624A8A4B79E17F8B83" + 286 "800EE66F3BB1292618B6FD1C2F8B27FF88E0EB", 287 "302C300706032B656E05000321008520F0098930A754748B7DDCB43EF75A0D" + 288 "BF3A0D26381AF4EBA4A98EAA9B4E6A", 289 "4a5d9d5ba4ce2de1728e3bf480350f25e07e21c947d19e3376f09b3c1e161742"); 290 291 // X448 292 //raw 293 runDiffieHellmanTest( 294 "X448", 295 "9A8F4925D1519F5775CF46B04B5800D4EE9EE8BAE8BC5565D498C28DD9C9BA" + 296 "F574A9419744897391006382A6F127AB1D9AC2D8C0A598726B", 297 "3EB7A829B0CD20F5BCFC0B599B6FECCF6DA4627107BDB0D4F345B43027D8B9" + 298 "72FC3E34FB4232A13CA706DCB57AEC3DAE07BDC1C67BF33609", 299 "07fff4181ac6cc95ec1c16a94a0f74d12da232ce40a77552281d282bb60c0b" + 300 "56fd2464c335543936521c24403085d59a449a5037514a879d"); 301 302 runDiffieHellmanTest( 303 "X448", 304 "1C306A7AC2A0E2E0990B294470CBA339E6453772B075811D8FAD0D1D6927C1" + 305 "20BB5EE8972B0D3E21374C9C921B09D1B0366F10B65173992D", 306 "9B08F7CC31B7E3E67D22D5AEA121074A273BD2B83DE09C63FAA73D2C22C5D9" + 307 "BBC836647241D953D40C5B12DA88120D53177F80E532C41FA0", 308 "07fff4181ac6cc95ec1c16a94a0f74d12da232ce40a77552281d282bb60c0b" + 309 "56fd2464c335543936521c24403085d59a449a5037514a879d"); 310 311 //encoded 312 runDiffieHellmanTest( 313 "3048020100300706032B656F0500043A04389A8F4925D1519F5775CF46B04B" + 314 "5800D4EE9EE8BAE8BC5565D498C28DD9C9BAF574A9419744897391006382A6" + 315 "F127AB1D9AC2D8C0A598726B", 316 "3044300706032B656F05000339003EB7A829B0CD20F5BCFC0B599B6FECCF6D" + 317 "A4627107BDB0D4F345B43027D8B972FC3E34FB4232A13CA706DCB57AEC3DAE" + 318 "07BDC1C67BF33609", 319 "07fff4181ac6cc95ec1c16a94a0f74d12da232ce40a77552281d282bb60c0b" + 320 "56fd2464c335543936521c24403085d59a449a5037514a879d"); 321 322 runDiffieHellmanTest( 323 "3048020100300706032B656F0500043A04381C306A7AC2A0E2E0990B294470" + 324 "CBA339E6453772B075811D8FAD0D1D6927C120BB5EE8972B0D3E21374C9C92" + 325 "1B09D1B0366F10B65173992D", 326 "3044300706032B656F05000339009B08F7CC31B7E3E67D22D5AEA121074A27" + 327 "3BD2B83DE09C63FAA73D2C22C5D9BBC836647241D953D40C5B12DA88120D53" + 328 "177F80E532C41FA0", 329 "07fff4181ac6cc95ec1c16a94a0f74d12da232ce40a77552281d282bb60c0b" + 330 "56fd2464c335543936521c24403085d59a449a5037514a879d"); 331 } 332 runDiffieHellmanTest(String a_pri, String b_pub, String result)333 private static void runDiffieHellmanTest(String a_pri, 334 String b_pub, String result) throws Exception { 335 336 KeyFactory kf = KeyFactory.getInstance("XDH"); 337 byte[] a_pri_ba = Convert.hexStringToByteArray(a_pri); 338 KeySpec privateSpec = new PKCS8EncodedKeySpec(a_pri_ba); 339 PrivateKey privateKey = kf.generatePrivate(privateSpec); 340 byte[] b_pub_ba = Convert.hexStringToByteArray(b_pub); 341 KeySpec publicSpec = new X509EncodedKeySpec(b_pub_ba); 342 PublicKey publicKey = kf.generatePublic(publicSpec); 343 344 KeyAgreement ka = KeyAgreement.getInstance("XDH"); 345 ka.init(privateKey); 346 ka.doPhase(publicKey, true); 347 348 byte[] sharedSecret = ka.generateSecret(); 349 byte[] expectedResult = Convert.hexStringToByteArray(result); 350 if (!Arrays.equals(sharedSecret, expectedResult)) { 351 throw new RuntimeException("fail: expected=" + result + ", actual=" 352 + Convert.byteArrayToHexString(sharedSecret)); 353 } 354 355 } 356 runDiffieHellmanTest(String curveName, String a_pri, String b_pub, String result)357 private static void runDiffieHellmanTest(String curveName, String a_pri, 358 String b_pub, String result) throws Exception { 359 360 NamedParameterSpec paramSpec = new NamedParameterSpec(curveName); 361 KeyFactory kf = KeyFactory.getInstance("XDH"); 362 KeySpec privateSpec = new XECPrivateKeySpec(paramSpec, 363 Convert.hexStringToByteArray(a_pri)); 364 PrivateKey privateKey = kf.generatePrivate(privateSpec); 365 boolean clearHighBit = curveName.equals("X25519"); 366 KeySpec publicSpec = new XECPublicKeySpec(paramSpec, 367 Convert.hexStringToBigInteger(clearHighBit, b_pub)); 368 PublicKey publicKey = kf.generatePublic(publicSpec); 369 370 byte[] encodedPrivateKey = privateKey.getEncoded(); 371 System.out.println("Encoded private: " + 372 Convert.byteArrayToHexString(encodedPrivateKey)); 373 byte[] encodedPublicKey = publicKey.getEncoded(); 374 System.out.println("Encoded public: " + 375 Convert.byteArrayToHexString(encodedPublicKey)); 376 377 KeyAgreement ka = KeyAgreement.getInstance("XDH"); 378 ka.init(privateKey); 379 ka.doPhase(publicKey, true); 380 381 byte[] sharedSecret = ka.generateSecret(); 382 byte[] expectedResult = Convert.hexStringToByteArray(result); 383 if (!Arrays.equals(sharedSecret, expectedResult)) { 384 throw new RuntimeException("fail: expected=" + result + ", actual=" 385 + Convert.byteArrayToHexString(sharedSecret)); 386 } 387 } 388 389 /* 390 * Ensure that SunEC rejects parameters/points for the wrong curve 391 * when the algorithm ID for a specific curve is specified. 392 */ runCurveMixTest()393 private static void runCurveMixTest() throws Exception { 394 runCurveMixTest("SunEC", "X25519", 448); 395 runCurveMixTest("SunEC", "X25519", "X448"); 396 runCurveMixTest("SunEC", "X448", 255); 397 runCurveMixTest("SunEC", "X448", "X25519"); 398 } 399 runCurveMixTest(String providerName, String name, Object param)400 private static void runCurveMixTest(String providerName, String name, 401 Object param) throws Exception { 402 403 KeyPairGenerator kpg = KeyPairGenerator.getInstance(name, 404 providerName); 405 406 try { 407 if (param instanceof Integer) { 408 kpg.initialize((Integer) param); 409 } else if (param instanceof String) { 410 kpg.initialize(new NamedParameterSpec((String) param)); 411 } 412 throw new RuntimeException(name + " KeyPairGenerator accepted " 413 + param.toString() + " parameters"); 414 } catch (InvalidParameterException ex) { 415 // expected 416 } 417 418 // the rest of the test uses the parameter as an algorithm name to 419 // produce keys 420 if (param instanceof Integer) { 421 return; 422 } 423 String otherName = (String) param; 424 KeyPairGenerator otherKpg = KeyPairGenerator.getInstance(otherName, 425 providerName); 426 KeyPair otherKp = otherKpg.generateKeyPair(); 427 428 // ensure the KeyFactory rejects incorrect keys 429 KeyFactory kf = KeyFactory.getInstance(name, providerName); 430 try { 431 kf.getKeySpec(otherKp.getPublic(), XECPublicKeySpec.class); 432 throw new RuntimeException(name + " KeyFactory accepted " 433 + param.toString() + " key"); 434 } catch (InvalidKeySpecException ex) { 435 // expected 436 } 437 try { 438 kf.getKeySpec(otherKp.getPrivate(), XECPrivateKeySpec.class); 439 throw new RuntimeException(name + " KeyFactory accepted " 440 + param.toString() + " key"); 441 } catch (InvalidKeySpecException ex) { 442 // expected 443 } 444 445 try { 446 kf.translateKey(otherKp.getPublic()); 447 throw new RuntimeException(name + " KeyFactory accepted " 448 + param.toString() + " key"); 449 } catch (InvalidKeyException ex) { 450 // expected 451 } 452 try { 453 kf.translateKey(otherKp.getPrivate()); 454 throw new RuntimeException(name + " KeyFactory accepted " 455 + param.toString() + " key"); 456 } catch (InvalidKeyException ex) { 457 // expected 458 } 459 460 KeyFactory otherKf = KeyFactory.getInstance(otherName, providerName); 461 XECPublicKeySpec otherPubSpec = otherKf.getKeySpec(otherKp.getPublic(), 462 XECPublicKeySpec.class); 463 try { 464 kf.generatePublic(otherPubSpec); 465 throw new RuntimeException(name + " KeyFactory accepted " 466 + param.toString() + " key"); 467 } catch (InvalidKeySpecException ex) { 468 // expected 469 } 470 XECPrivateKeySpec otherPriSpec = 471 otherKf.getKeySpec(otherKp.getPrivate(), XECPrivateKeySpec.class); 472 try { 473 kf.generatePrivate(otherPriSpec); 474 throw new RuntimeException(name + " KeyFactory accepted " 475 + param.toString() + " key"); 476 } catch (InvalidKeySpecException ex) { 477 // expected 478 } 479 480 // ensure the KeyAgreement rejects incorrect keys 481 KeyAgreement ka = KeyAgreement.getInstance(name, providerName); 482 try { 483 ka.init(otherKp.getPrivate()); 484 throw new RuntimeException(name + " KeyAgreement accepted " 485 + param.toString() + " key"); 486 } catch (InvalidKeyException ex) { 487 // expected 488 } 489 KeyPair kp = kpg.generateKeyPair(); 490 ka.init(kp.getPrivate()); 491 try { 492 // This should always be rejected because it doesn't match the key 493 // passed to init, but it is tested here for good measure. 494 ka.doPhase(otherKp.getPublic(), true); 495 throw new RuntimeException(name + " KeyAgreement accepted " 496 + param.toString() + " key"); 497 } catch (InvalidKeyException ex) { 498 // expected 499 } 500 } 501 } 502 503