aboutsummaryrefslogtreecommitdiff
path: root/common/src/main/java/org/conscrypt/HpkeContext.java
diff options
context:
space:
mode:
Diffstat (limited to 'common/src/main/java/org/conscrypt/HpkeContext.java')
-rw-r--r--common/src/main/java/org/conscrypt/HpkeContext.java119
1 files changed, 119 insertions, 0 deletions
diff --git a/common/src/main/java/org/conscrypt/HpkeContext.java b/common/src/main/java/org/conscrypt/HpkeContext.java
new file mode 100644
index 00000000..4317796e
--- /dev/null
+++ b/common/src/main/java/org/conscrypt/HpkeContext.java
@@ -0,0 +1,119 @@
+/*
+ * 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 java.security.NoSuchAlgorithmException;
+import java.security.NoSuchProviderException;
+import java.security.Provider;
+import java.security.Security;
+
+/**
+ * Hybrid Public Key Encryption (HPKE) sender APIs.
+ *
+ * @see <a href="https://www.rfc-editor.org/rfc/rfc9180.html#hpke-export">HPKE RFC 9180</a>
+ * <p>
+ * Base class for HPKE sender and recipient contexts.
+ * <p>
+ * This is the client API for HPKE usage, all operations are delegated to an implementation
+ * class implementing {@link HpkeSpi} which is located using the JCA {@link Provider}
+ * mechanism.
+ * <p>
+ * The implementation maintains the context for an HPKE exchange, including the key schedule
+ * to use for seal and open operations.
+ *
+ * Secret key material based on the context may also be generated and exported as per RFC 9180.
+ */
+public abstract class HpkeContext {
+ protected final HpkeSpi spi;
+
+ protected HpkeContext(HpkeSpi spi) {
+ this.spi = spi;
+ }
+
+ /**
+ * Exports secret key material from this HpkeContext as described in RFC 9180.
+ *
+ * @param length expected output length
+ * @param context optional context string, may be null or empty
+ * @return exported value
+ * @throws IllegalArgumentException if the length is not valid for the KDF in use
+ * @throws IllegalStateException if this HpkeContext has not been initialised
+ *
+ */
+ public byte[] export(int length, byte[] context) {
+ return spi.engineExport(length, context);
+ }
+
+ /**
+ * Returns the {@link HpkeSpi} being used by this HpkeContext.
+ *
+ * @return the SPI
+ */
+ public HpkeSpi getSpi() {
+ return spi;
+ }
+
+ protected static HpkeSpi findSpi(String algorithm) throws NoSuchAlgorithmException {
+ if (algorithm == null) {
+ // Same behaviour as Cipher.getInstance
+ throw new NoSuchAlgorithmException("null algorithm");
+ }
+ return findSpi(algorithm, findFirstProvider(algorithm));
+ }
+
+ private static Provider findFirstProvider(String algorithm) throws NoSuchAlgorithmException {
+ for (Provider p : Security.getProviders()) {
+ Provider.Service service = p.getService("ConscryptHpke", algorithm);
+ if (service != null) {
+ return service.getProvider();
+ }
+ }
+ throw new NoSuchAlgorithmException("No Provider found for: " + algorithm);
+ }
+
+ protected static HpkeSpi findSpi(String algorithm, String providerName) throws
+ NoSuchAlgorithmException, IllegalArgumentException, NoSuchProviderException {
+ if (providerName == null || providerName.isEmpty()) {
+ // Same behaviour as Cipher.getInstance
+ throw new IllegalArgumentException("Invalid provider name");
+ }
+ Provider provider = Security.getProvider(providerName);
+ if (provider == null) {
+ throw new NoSuchProviderException("Unknown Provider: " + providerName);
+ }
+ return findSpi(algorithm, provider);
+ }
+
+ protected static HpkeSpi findSpi(String algorithm, Provider provider) throws
+ NoSuchAlgorithmException, IllegalArgumentException {
+ if (provider == null) {
+ throw new IllegalArgumentException("null Provider");
+ }
+ Provider.Service service = provider.getService("ConscryptHpke", algorithm);
+ if (service == null) {
+ throw new NoSuchAlgorithmException("Unknown algorithm");
+ }
+ Object instance = service.newInstance(null);
+ HpkeSpi spi = (instance instanceof HpkeSpi) ? (HpkeSpi) instance
+ : DuckTypedHpkeSpi.newInstance(instance);
+ if (spi != null) {
+ return spi;
+ }
+ throw new IllegalStateException(
+ String.format("Provider %s is providing incorrect instances", provider.getName()));
+ }
+}