aboutsummaryrefslogtreecommitdiff
path: root/common/src/test/java/org/conscrypt/HpkeContextRecipientTest.java
diff options
context:
space:
mode:
Diffstat (limited to 'common/src/test/java/org/conscrypt/HpkeContextRecipientTest.java')
-rw-r--r--common/src/test/java/org/conscrypt/HpkeContextRecipientTest.java194
1 files changed, 194 insertions, 0 deletions
diff --git a/common/src/test/java/org/conscrypt/HpkeContextRecipientTest.java b/common/src/test/java/org/conscrypt/HpkeContextRecipientTest.java
new file mode 100644
index 00000000..b429bb41
--- /dev/null
+++ b/common/src/test/java/org/conscrypt/HpkeContextRecipientTest.java
@@ -0,0 +1,194 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package org.conscrypt;
+
+import static org.conscrypt.HpkeFixture.DEFAULT_AAD;
+import static org.conscrypt.HpkeFixture.DEFAULT_CT;
+import static org.conscrypt.HpkeFixture.DEFAULT_ENC;
+import static org.conscrypt.HpkeFixture.DEFAULT_EXPORTER_CONTEXT;
+import static org.conscrypt.HpkeFixture.DEFAULT_EXPORTER_LENGTH;
+import static org.conscrypt.HpkeFixture.DEFAULT_INFO;
+import static org.conscrypt.HpkeFixture.DEFAULT_PK;
+import static org.conscrypt.HpkeFixture.DEFAULT_PT;
+import static org.conscrypt.HpkeFixture.DEFAULT_SK;
+import static org.conscrypt.HpkeFixture.DEFAULT_SUITE_NAME;
+import static org.conscrypt.HpkeFixture.createDefaultHpkeContextRecipient;
+import static org.conscrypt.HpkeFixture.createPrivateKey;
+import static org.conscrypt.TestUtils.decodeHex;
+import static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertThrows;
+
+import java.nio.charset.StandardCharsets;
+import java.security.GeneralSecurityException;
+import java.security.InvalidKeyException;
+import java.security.NoSuchAlgorithmException;
+import java.security.NoSuchProviderException;
+import java.security.PrivateKey;
+import java.security.Provider;
+
+import org.conscrypt.java.security.DefaultKeys;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+@RunWith(JUnit4.class)
+public class HpkeContextRecipientTest {
+ @Test
+ public void testGetInstance() throws Exception {
+ assertThrows(NoSuchAlgorithmException.class,
+ () -> HpkeContextRecipient.getInstance(null));
+ assertThrows(NoSuchAlgorithmException.class,
+ () -> HpkeContextRecipient.getInstance("No/Such/Thing"));
+ assertThrows(IllegalArgumentException.class,
+ () -> HpkeContextRecipient.getInstance(DEFAULT_SUITE_NAME, (String) null));
+ assertThrows(IllegalArgumentException.class,
+ () -> HpkeContextRecipient.getInstance(DEFAULT_SUITE_NAME, (Provider) null));
+ assertThrows(NoSuchProviderException.class,
+ () -> HpkeContextRecipient.getInstance(DEFAULT_SUITE_NAME, "NonsenseProviderName"));
+ HpkeContextRecipient recipient = HpkeContextRecipient.getInstance(DEFAULT_SUITE_NAME);
+ assertNotNull(recipient);
+ }
+
+ @Test
+ public void testInitBaseMode() throws Exception {
+ HpkeContextRecipient recipient = HpkeContextRecipient.getInstance(DEFAULT_SUITE_NAME);
+ final PrivateKey invalidKey = DefaultKeys.getPrivateKey("DH");
+
+
+ assertThrows(NullPointerException.class,
+ () -> recipient.init(/* enc= */ null, DEFAULT_SK, DEFAULT_INFO));
+
+ assertThrows(InvalidKeyException.class,
+ () -> recipient.init(DEFAULT_ENC, /* privateKey= */ null, DEFAULT_INFO));
+
+ // Incorrect enc size
+ assertThrows(InvalidKeyException.class,
+ () -> recipient.init(new byte[1], DEFAULT_SK, DEFAULT_INFO));
+
+ assertThrows(InvalidKeyException.class,
+ () -> recipient.init(DEFAULT_ENC, invalidKey, DEFAULT_INFO));
+
+ // Should succeed
+ recipient.init(DEFAULT_ENC, DEFAULT_SK, DEFAULT_INFO);
+
+ // Can't initialise twice
+ assertThrows(IllegalStateException.class,
+ () -> recipient.init(DEFAULT_ENC, DEFAULT_SK, DEFAULT_INFO));
+
+ HpkeContextRecipient recipient2 = HpkeContextRecipient.getInstance(DEFAULT_SUITE_NAME);
+ // null is explicitly allowed
+ recipient2.init(DEFAULT_ENC, DEFAULT_SK, /* info= */ null);
+ }
+
+ @Test
+ public void testInitUnsupportedModes() throws Exception {
+ HpkeContextRecipient recipient = HpkeContextRecipient.getInstance(DEFAULT_SUITE_NAME);
+ byte[] psk = "Shhh! Secret!".getBytes(StandardCharsets.UTF_8);
+ byte[] psk_id = "id".getBytes(StandardCharsets.UTF_8);
+
+ assertThrows(UnsupportedOperationException.class, () ->
+ recipient.init(DEFAULT_ENC, DEFAULT_SK, DEFAULT_INFO, DEFAULT_PK));
+ assertThrows(UnsupportedOperationException.class, () ->
+ recipient.init(DEFAULT_ENC, DEFAULT_SK, DEFAULT_INFO, psk, psk_id));
+ assertThrows(UnsupportedOperationException.class, () ->
+ recipient.init(DEFAULT_ENC, DEFAULT_SK, DEFAULT_INFO, DEFAULT_PK, psk, psk_id));
+ }
+
+ @Test
+ public void testOpen_successfully() throws Exception {
+ final HpkeSuite suite = new HpkeSuite(HpkeSuite.KEM_DHKEM_X25519_HKDF_SHA256,
+ HpkeSuite.KDF_HKDF_SHA256, HpkeSuite.AEAD_AES_128_GCM);
+ final HpkeContextRecipient ctxRecipient = HpkeContextRecipient.getInstance(suite.name());
+ ctxRecipient.init(DEFAULT_ENC, DEFAULT_SK, DEFAULT_INFO);
+ byte[] plaintext = ctxRecipient.open(DEFAULT_CT, DEFAULT_AAD);
+ assertNotNull(plaintext);
+ assertArrayEquals(DEFAULT_PT, plaintext);
+ }
+
+ @Test
+ public void testOpen_missingRequiredParameters_throwNullException() throws Exception {
+ final HpkeContextRecipient ctxRecipient =
+ HpkeContextRecipient.getInstance(DEFAULT_SUITE_NAME);
+ ctxRecipient.init(DEFAULT_ENC, DEFAULT_SK, DEFAULT_INFO);
+
+ assertThrows(NullPointerException.class,
+ () -> ctxRecipient.open(/* ciphertext= */ null, DEFAULT_AAD));
+ }
+
+ @Test
+ public void testOpen_validSkButNotTheRightOne_throwStateException() throws Exception {
+ final PrivateKey privateKey = createPrivateKey(
+ decodeHex("497b4502664cfea5d5af0b39934dac72242a74f8480451e1aee7d6a53320333d"));
+ final HpkeContextRecipient ctxRecipient =
+ HpkeContextRecipient.getInstance(DEFAULT_SUITE_NAME);
+ ctxRecipient.init(DEFAULT_ENC, privateKey, DEFAULT_INFO);
+ assertThrows(GeneralSecurityException.class,
+ () -> ctxRecipient.open(DEFAULT_CT, DEFAULT_AAD));
+ }
+
+ @Test
+ public void testOpen_validSkButWrongEnc_throwStateException() throws Exception {
+ final byte[] enc =
+ decodeHex("6c93e09869df3402d7bf231bf540fadd35cd56be14f97178f0954db94b7fc256");
+ final HpkeContextRecipient ctxRecipient =
+ HpkeContextRecipient.getInstance(DEFAULT_SUITE_NAME);
+ ctxRecipient.init(enc, DEFAULT_SK, DEFAULT_INFO);
+
+ assertThrows(GeneralSecurityException.class, () -> ctxRecipient.open(DEFAULT_CT, DEFAULT_AAD));
+ }
+
+ @Test
+ public void testOpen_invalidCiphertext_throwStateException() throws Exception {
+ final HpkeContextRecipient ctxRecipient =
+ HpkeContextRecipient.getInstance(DEFAULT_SUITE_NAME);
+ ctxRecipient.init(DEFAULT_ENC, DEFAULT_SK, DEFAULT_INFO);
+
+ assertThrows(GeneralSecurityException.class,
+ () -> ctxRecipient.open(/* ct= */ new byte[32], DEFAULT_AAD));
+ }
+
+ @Test
+ public void testExport_withNullValue() throws Exception {
+ final HpkeContextRecipient ctxRecipient = createDefaultHpkeContextRecipient(DEFAULT_ENC);
+ final byte[] export =
+ ctxRecipient.export(DEFAULT_EXPORTER_LENGTH, /* exporterContext= */ null);
+ assertNotNull(export);
+ assertEquals(DEFAULT_EXPORTER_LENGTH, export.length);
+ }
+
+ @Test
+ public void testExport_verifyOutputLength() throws Exception {
+ final HpkeContextRecipient ctxRecipient = createDefaultHpkeContextRecipient(DEFAULT_ENC);
+ for (int i = 0; i < 8_000; i += 500) {
+ final byte[] export = ctxRecipient.export(i, DEFAULT_EXPORTER_CONTEXT);
+ assertNotNull(export);
+ assertEquals(i, export.length);
+ }
+ }
+
+ @Test
+ public void testExport_lowerEdgeLength() throws Exception {
+ final HpkeContextRecipient ctxRecipient = createDefaultHpkeContextRecipient(DEFAULT_ENC);
+ final byte[] export = ctxRecipient.export(/* length= */ 0, DEFAULT_EXPORTER_CONTEXT);
+ assertNotNull(export);
+ final IllegalArgumentException e = assertThrows(IllegalArgumentException.class,
+ () -> ctxRecipient.export(/* length= */ -1, DEFAULT_EXPORTER_CONTEXT));
+ assertEquals("Export length (L) must be between 0 and 8160, but was -1", e.getMessage());
+ }
+}