diff --git a/openjdk/src/test/java/org/conscrypt/NativeCryptoTest.java b/openjdk/src/test/java/org/conscrypt/NativeCryptoTest.java index e5c352ebb..962179bbb 100644 --- a/openjdk/src/test/java/org/conscrypt/NativeCryptoTest.java +++ b/openjdk/src/test/java/org/conscrypt/NativeCryptoTest.java @@ -2918,24 +2918,7 @@ public void test_RSA_public_decrypt_NullArgumentFailure() throws Exception { * Test vector generation: * openssl rand -hex 16 */ - private static final byte[] AES_128_KEY = new byte[] { - (byte) 0x3d, - (byte) 0x4f, - (byte) 0x89, - (byte) 0x70, - (byte) 0xb1, - (byte) 0xf2, - (byte) 0x75, - (byte) 0x37, - (byte) 0xf4, - (byte) 0x0a, - (byte) 0x39, - (byte) 0x29, - (byte) 0x8a, - (byte) 0x41, - (byte) 0x55, - (byte) 0x5f, - }; + private static final byte[] AES_128_KEY = decodeHex("3d4f8970b1f27537f40a39298a41555f5f"); @Test public void testEC_GROUP() throws Exception { @@ -3334,6 +3317,139 @@ public void test_ecdsaSignVerify_works() throws Exception { () -> NativeCrypto.ECDSA_verify(data, invalidDataLen, signature, publicKey)); } + // HPKE constants. + // see: https://www.iana.org/assignments/hpke/hpke.xhtml + // KEM IDs + private static final int DHKEM_P256_HKDF_SHA256 = 0x0010; + private static final int DHKEM_P384_HKDF_SHA384 = 0x0011; + private static final int DHKEM_P521_HKDF_SHA512 = 0x0012; + private static final int DHKEM_X25519_HKDF_SHA256 = 0x0020; + private static final int DHKEM_X448_HKDF_SHA256 = 0x0021; + // KDF IDs + private static final int HKDF_SHA256 = 0x0001; + private static final int HKDF_SHA384 = 0x0002; + private static final int HKDF_SHA512 = 0x0003; + // AEAD IDs + private static final int AES_128_GCM = 0x0001; + private static final int AES_256_GCM = 0x0002; + private static final int CHACHA20_POLY1305 = 0x0003; + private static final int EXPORT_ONLY = 0xFFFF; + + @Test + public void hpkeWithX25519Sha256_sealAndOpen_success() throws Exception { + byte[] pkRecipient = new byte[32]; + byte[] skRecipient = new byte[32]; + NativeCrypto.X25519_keypair(pkRecipient, skRecipient); + + byte[] info = decodeHex("aa"); + byte[] plaintext = decodeHex("bb"); + byte[] aad = decodeHex("cc"); + + int[] supportedAeads = new int[] {AES_128_GCM, AES_256_GCM, CHACHA20_POLY1305}; + for (int aead : supportedAeads) { + Object[] result = NativeCrypto.EVP_HPKE_CTX_setup_base_mode_sender( + DHKEM_X25519_HKDF_SHA256, HKDF_SHA256, aead, pkRecipient, info); + NativeRef.EVP_HPKE_CTX ctxSender = (NativeRef.EVP_HPKE_CTX) result[0]; + byte[] encapsulated = (byte[]) result[1]; + byte[] ciphertext = NativeCrypto.EVP_HPKE_CTX_seal(ctxSender, plaintext, aad); + + NativeRef.EVP_HPKE_CTX ctxRecipient = + (NativeRef.EVP_HPKE_CTX) NativeCrypto.EVP_HPKE_CTX_setup_base_mode_recipient( + DHKEM_X25519_HKDF_SHA256, HKDF_SHA256, aead, skRecipient, encapsulated, + info); + byte[] output = NativeCrypto.EVP_HPKE_CTX_open(ctxRecipient, ciphertext, aad); + + assertArrayEquals(plaintext, output); + } + } + + @Test + public void hpkeWithUnsupportedAlgorithms_setup_throwsIllegalArgumentException() + throws Exception { + byte[] pkRecipient = new byte[32]; + byte[] skRecipient = new byte[32]; + NativeCrypto.X25519_keypair(pkRecipient, skRecipient); + byte[] info = decodeHex("aa"); + + // These KEM IDs are currently not supported in Conscrypt. + assertThrows(IllegalArgumentException.class, + () + -> NativeCrypto.EVP_HPKE_CTX_setup_base_mode_sender(DHKEM_P256_HKDF_SHA256, + HKDF_SHA256, AES_128_GCM, pkRecipient, info)); + assertThrows(IllegalArgumentException.class, + () + -> NativeCrypto.EVP_HPKE_CTX_setup_base_mode_sender(DHKEM_P384_HKDF_SHA384, + HKDF_SHA256, AES_128_GCM, pkRecipient, info)); + assertThrows(IllegalArgumentException.class, + () + -> NativeCrypto.EVP_HPKE_CTX_setup_base_mode_sender(DHKEM_P521_HKDF_SHA512, + HKDF_SHA256, AES_128_GCM, pkRecipient, info)); + assertThrows(IllegalArgumentException.class, + () + -> NativeCrypto.EVP_HPKE_CTX_setup_base_mode_sender(DHKEM_X448_HKDF_SHA256, + HKDF_SHA256, AES_128_GCM, pkRecipient, info)); + + // These KDF IDs are currently not supported in Conscrypt. + assertThrows(IllegalArgumentException.class, + () + -> NativeCrypto.EVP_HPKE_CTX_setup_base_mode_sender( + DHKEM_X25519_HKDF_SHA256, HKDF_SHA384, AES_128_GCM, pkRecipient, + info)); + assertThrows(IllegalArgumentException.class, + () + -> NativeCrypto.EVP_HPKE_CTX_setup_base_mode_sender( + DHKEM_X25519_HKDF_SHA256, HKDF_SHA512, AES_128_GCM, pkRecipient, + info)); + + // These AEAD IDs are currently not supported in Conscrypt. + assertThrows(IllegalArgumentException.class, + () + -> NativeCrypto.EVP_HPKE_CTX_setup_base_mode_sender( + DHKEM_X25519_HKDF_SHA256, HKDF_SHA256, EXPORT_ONLY, pkRecipient, + info)); + } + + @Test + public void hpkeWithX25519Sha256_openWithRfc9180TestVector_success() throws Exception { + // Test Vector from RFC 9180, Section A.1.1.1 + byte[] info = decodeHex("4f6465206f6e2061204772656369616e2055726e"); + byte[] skRecipient = + decodeHex("4612c550263fc8ad58375df3f557aac531d26850903e55a9f23f21d8534e8ac8"); + byte[] enc = decodeHex("37fda3567bdbd628e88668c3c8d7e97d1d1253b6d4ea6d44c150f741f1bf4431"); + byte[] pt = decodeHex("4265617574792069732074727574682c20747275746820626561757479"); + byte[] aad = decodeHex("436f756e742d30"); + byte[] ct = decodeHex("f938558b5d72f1a23810b4be2ab4f84331acc02fc97babc53a52ae8218a355a9" + + "6d8770ac83d07bea87e13c512a"); + + NativeRef.EVP_HPKE_CTX ctxRecipient = + (NativeRef.EVP_HPKE_CTX) NativeCrypto.EVP_HPKE_CTX_setup_base_mode_recipient( + DHKEM_X25519_HKDF_SHA256, HKDF_SHA256, AES_128_GCM, skRecipient, enc, info); + + byte[] openOutput = NativeCrypto.EVP_HPKE_CTX_open(ctxRecipient, ct, aad); + assertArrayEquals(pt, openOutput); + } + + @Test + public void hpkeWithX25519Sha256_export_returnsValueAsInRfc9180() throws Exception { + // Test Vector from RFC 9180, Section A.1.1.2 + byte[] info = decodeHex("4f6465206f6e2061204772656369616e2055726e"); + byte[] skRecipient = + decodeHex("4612c550263fc8ad58375df3f557aac531d26850903e55a9f23f21d8534e8ac8"); + byte[] enc = decodeHex("37fda3567bdbd628e88668c3c8d7e97d1d1253b6d4ea6d44c150f741f1bf4431"); + byte[] exporterContext = decodeHex(""); + int exporterLength = 32; + byte[] exportedValue = + decodeHex("3853fe2b4035195a573ffc53856e77058e15d9ea064de3e59f4961d0095250ee"); + + NativeRef.EVP_HPKE_CTX ctxRecipient = + (NativeRef.EVP_HPKE_CTX) NativeCrypto.EVP_HPKE_CTX_setup_base_mode_recipient( + DHKEM_X25519_HKDF_SHA256, HKDF_SHA256, AES_128_GCM, skRecipient, enc, info); + + byte[] output = + NativeCrypto.EVP_HPKE_CTX_export(ctxRecipient, exporterContext, exporterLength); + assertArrayEquals(exportedValue, output); + } + @Test public void test_mldsa65_works() throws Exception { byte[] privateKeySeed =