|
1 | 1 | /* |
2 | | - * Copyright IBM Corp. 2023, 2025 |
| 2 | + * Copyright IBM Corp. 2023, 2026 |
3 | 3 | * |
4 | 4 | * This code is free software; you can redistribute it and/or modify it |
5 | 5 | * under the terms provided by IBM in the LICENSE file that accompanied |
|
9 | 9 | package ibm.jceplus.junit.base; |
10 | 10 |
|
11 | 11 | import java.math.BigInteger; |
| 12 | +import java.nio.charset.StandardCharsets; |
12 | 13 | import java.security.KeyFactory; |
13 | 14 | import java.security.KeyPair; |
14 | 15 | import java.security.KeyPairGenerator; |
15 | 16 | import java.security.PrivateKey; |
16 | 17 | import java.security.PublicKey; |
| 18 | +import java.security.Signature; |
17 | 19 | import java.security.spec.ECField; |
18 | 20 | import java.security.spec.ECFieldFp; |
19 | 21 | import java.security.spec.ECGenParameterSpec; |
|
24 | 26 | import java.security.spec.PKCS8EncodedKeySpec; |
25 | 27 | import java.security.spec.X509EncodedKeySpec; |
26 | 28 | import java.util.Arrays; |
| 29 | +import java.util.Base64; |
27 | 30 | import java.util.HexFormat; |
28 | 31 | import org.junit.jupiter.api.Test; |
29 | 32 | import sun.security.pkcs.PKCS8Key; |
30 | 33 | import sun.security.x509.X509Key; |
31 | 34 | import static org.junit.jupiter.api.Assertions.assertArrayEquals; |
| 35 | +import static org.junit.jupiter.api.Assertions.assertNotNull; |
32 | 36 | import static org.junit.jupiter.api.Assertions.assertTrue; |
33 | 37 |
|
34 | 38 | public class BaseTestECKeyImport extends BaseTestJunit5 { |
@@ -82,7 +86,37 @@ public class BaseTestECKeyImport extends BaseTestJunit5 { |
82 | 86 | + "9C57C30FAA2DEF09DDDAD4E8748C442325B8EDB94EF7AA9" |
83 | 87 | + "78D4A56F0B601448B0DDFA4CC4B0555EAE67354C442A3AC" |
84 | 88 | + "E9D04BE186765A1921962FC08D1A58C53A"; |
85 | | - |
| 89 | + |
| 90 | + private static final String private_secp256r1_parameters_publickey = |
| 91 | + "MIGTAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBHkwdwIBAQQg15U0PERqsupn6Hy5" + |
| 92 | + "Jlk6HKBiJlBvMWVSxEWYNipV2SOgCgYIKoZIzj0DAQehRANCAARFcF00hBK8Es2M" + |
| 93 | + "H29DmA3fsYf4qWFSloVWoFct4CxffJ7hG0O4TXkMaPrAjgXc42SPdKRb7FcO0Lhz" + |
| 94 | + "EVpYquVY"; |
| 95 | + private static final String public_secp256r1_parameters_publickey = |
| 96 | + "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAERXBdNIQSvBLNjB9vQ5gN37GH+Klh" + |
| 97 | + "UpaFVqBXLeAsX3ye4RtDuE15DGj6wI4F3ONkj3SkW+xXDtC4cxFaWKrlWA=="; |
| 98 | + |
| 99 | + private static final String private_secp256r1_publickey_only = |
| 100 | + "MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgn5K03bpTLjEtFQRa" + |
| 101 | + "JUtx22gtmGEvvSUSQdimhGthdtihRANCAARv72fTmp9ed8dRvTG1Ak1Lgl5KLoiM" + |
| 102 | + "59bk2pyG8qd8l7L1WQnNHtAcu44RJ1/GVHurxghaCKHeJYsZ8H7DEeI6"; |
| 103 | + private static final String public_secp256r1_publickey_only = |
| 104 | + "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEb+9n05qfXnfHUb0xtQJNS4JeSi6I" + |
| 105 | + "jOfW5NqchvKnfJey9VkJzR7QHLuOESdfxlR7q8YIWgih3iWLGfB+wxHiOg=="; |
| 106 | + |
| 107 | + private static final String private_secp256r1_parameters_only = |
| 108 | + "ME0CAQAwEwYHKoZIzj0CAQYIKoZIzj0DAQcEMzAxAgEBBCDQG6sBj2l7SbIwjb4f" + |
| 109 | + "4AVQdtE717IaMXiRBzGboI7IWaAKBggqhkjOPQMBBw=="; |
| 110 | + private static final String public_secp256r1_parameters_only = |
| 111 | + "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAESaogWgFBKmRm5SUKilBVhNx/l/60" + |
| 112 | + "H/OTNDAz1OUi+Gy1MkrKMktPmpRw6gq26jxRXhRYFJhMuU0R1fktCXcG3g=="; |
| 113 | + |
| 114 | + private static final String private_secp256r1_no_parameters_no_public = |
| 115 | + "MEECAQAwEwYHKoZIzj0CAQYIKoZIzj0DAQcEJzAlAgEBBCDlySzNwwln6W+zDiDk" + |
| 116 | + "K7OvyaalUUdkOd6CrThHqenrfg=="; |
| 117 | + private static final String public_secp256r1_no_parameters_no_public = |
| 118 | + "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEG9JA6mkSGkIKBSsKxDDtmhHMEo+P" + |
| 119 | + "MNHwWo60TKvsYpEWYqGLvaqmhwqIyf+qVQD5/9hU4WFiB/t3jV+sO2RuHA=="; |
86 | 120 |
|
87 | 121 | /** |
88 | 122 | * Generate a KeyPair using ECGEenParam and then import the key pair |
@@ -305,5 +339,75 @@ public void testImportHardcoded() throws Exception { |
305 | 339 |
|
306 | 340 | assertTrue(((X509Key) importPublicKey).getAlgorithmId().toString().contains("secp521r1"), "Curve is not what is expected."); |
307 | 341 | } |
| 342 | + |
| 343 | + @Test |
| 344 | + public void testECPrivateKeyWithVariousOptionalFields() throws Exception { |
| 345 | + KeyFactory kf = KeyFactory.getInstance("EC", getProviderName()); |
| 346 | + Signature signature = Signature.getInstance("SHA256withECDSA", getProviderName()); |
| 347 | + |
| 348 | + // 1) parameters + publicKey |
| 349 | + testSignAndVerify( |
| 350 | + "parameters and publicKey", |
| 351 | + kf, |
| 352 | + signature, |
| 353 | + private_secp256r1_parameters_publickey, |
| 354 | + public_secp256r1_parameters_publickey |
| 355 | + ); |
| 356 | + |
| 357 | + // 2) publicKey only |
| 358 | + testSignAndVerify( |
| 359 | + "publicKey only", |
| 360 | + kf, |
| 361 | + signature, |
| 362 | + private_secp256r1_publickey_only, |
| 363 | + public_secp256r1_publickey_only |
| 364 | + ); |
| 365 | + |
| 366 | + // 3) parameters only |
| 367 | + testSignAndVerify( |
| 368 | + "parameters only", |
| 369 | + kf, |
| 370 | + signature, |
| 371 | + private_secp256r1_parameters_only, |
| 372 | + public_secp256r1_parameters_only |
| 373 | + ); |
| 374 | + |
| 375 | + // 4) no parameters + no publicKey |
| 376 | + testSignAndVerify( |
| 377 | + "no parameters and no publickey", |
| 378 | + kf, |
| 379 | + signature, |
| 380 | + private_secp256r1_no_parameters_no_public, |
| 381 | + public_secp256r1_no_parameters_no_public |
| 382 | + ); |
| 383 | + System.out.println("ALL tests completed."); |
| 384 | + } |
| 385 | + |
| 386 | + private static void testSignAndVerify( |
| 387 | + String label, |
| 388 | + KeyFactory kf, |
| 389 | + Signature sig, |
| 390 | + String pkcs8Base64, |
| 391 | + String x509PublicBase64 |
| 392 | + ) throws Exception { |
| 393 | + PrivateKey priv = kf.generatePrivate(new PKCS8EncodedKeySpec(Base64.getMimeDecoder().decode(pkcs8Base64))); |
| 394 | + |
| 395 | + // Sign |
| 396 | + byte[] msg = ("msg-" + label).getBytes(StandardCharsets.UTF_8); |
| 397 | + sig.initSign(priv); |
| 398 | + sig.update(msg); |
| 399 | + byte[] signed = sig.sign(); |
| 400 | + assertNotNull(signed, "Signature is null for: " + label); |
| 401 | + assertTrue(signed.length > 0, "Signature should not be empty for: " + label); |
| 402 | + System.out.println("sign OK"); |
| 403 | + |
| 404 | + // Verify |
| 405 | + PublicKey pub = kf.generatePublic(new X509EncodedKeySpec(Base64.getMimeDecoder().decode(x509PublicBase64))); |
| 406 | + sig.initVerify(pub); |
| 407 | + sig.update(msg); |
| 408 | + boolean verified = sig.verify(signed); |
| 409 | + assertTrue(verified, "Signature verification failed for: " + label); |
| 410 | + System.out.println("verify OK"); |
| 411 | + } |
308 | 412 | } |
309 | 413 |
|
0 commit comments