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