Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add OHttpCryptoProvider.newRandomPrivateKey(...) #30

Merged
merged 2 commits into from Dec 27, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
Expand Up @@ -39,10 +39,13 @@
import org.bouncycastle.util.encoders.Hex;

import java.math.BigInteger;
import java.security.SecureRandom;

public final class BouncyCastleOHttpCryptoProvider implements OHttpCryptoProvider {
public static final BouncyCastleOHttpCryptoProvider INSTANCE = new BouncyCastleOHttpCryptoProvider();

private final SecureRandom random = new SecureRandom();

private BouncyCastleOHttpCryptoProvider() { }

@Override
Expand Down Expand Up @@ -184,6 +187,26 @@ private static ECDomainParameters ecDomainParameters(KEM kem) {
}
}

@Override
public AsymmetricCipherKeyPair newRandomPrivateKey(KEM kem) {
return new BouncyCastleAsymmetricCipherKeyPair(newRandomPair(kem, random));
}

private static org.bouncycastle.crypto.AsymmetricCipherKeyPair newRandomPair(KEM kem, SecureRandom random) {
switch (kem) {
case X25519_SHA256:
X25519PrivateKeyParameters x25519PrivateKey = new X25519PrivateKeyParameters(random);
return new org.bouncycastle.crypto.AsymmetricCipherKeyPair(
x25519PrivateKey.generatePublicKey(), x25519PrivateKey);
case X448_SHA512:
X448PrivateKeyParameters x448PrivateKey = new X448PrivateKeyParameters(random);
return new org.bouncycastle.crypto.AsymmetricCipherKeyPair(
x448PrivateKey.generatePublicKey(), x448PrivateKey);
default:
throw new UnsupportedOperationException("Can't generate random key for kem: " + kem);
}
}

@Override
public boolean isSupported(AEAD aead) {
if (aead == null) {
Expand Down
Expand Up @@ -105,6 +105,8 @@ static native byte[] EVP_HPKE_CTX_export(
static native int EVP_HPKE_CTX_max_overhead(long ctx);

static native long EVP_HPKE_KEY_new();

static native int EVP_HPKE_KEY_generate(long key, long kem);
static native void EVP_HPKE_KEY_free(long key);
static native void EVP_HPKE_KEY_cleanup(long key);

Expand Down Expand Up @@ -184,6 +186,15 @@ static void EVP_HPKE_KEY_init_or_throw(long key, long kem, byte[] privateKeyByte
}
}

static long EVP_HPKE_KEY_new_and_generate_or_throw(long kem) {
long key = EVP_HPKE_KEY_new_or_throw();
if (EVP_HPKE_KEY_generate(key, kem) != 1) {
EVP_HPKE_KEY_cleanup_and_free(key);
throw new IllegalStateException("Unable to generate key for KEM: " + kem);
}
return key;
}

static void EVP_HPKE_KEY_cleanup_and_free(long key) {
if (key != -1) {
BoringSSL.EVP_HPKE_KEY_cleanup(key);
Expand Down
Expand Up @@ -222,6 +222,24 @@ public AsymmetricKeyParameter deserializePublicKey(KEM kem, byte[] publicKeyByte
return new BoringSSLAsymmetricKeyParameter(publicKeyBytes.clone(), false);
}

@Override
public AsymmetricCipherKeyPair newRandomPrivateKey(KEM kem) {
// Validate that KEM is supported by BoringSSL.
long boringSSLKem = boringSSLKEM(kem);

long key = BoringSSL.EVP_HPKE_KEY_new_and_generate_or_throw(boringSSLKem);
try {
byte[] privateKeyBytes = BoringSSL.EVP_HPKE_KEY_private_key(key);
byte[] publicKeyBytes = BoringSSL.EVP_HPKE_KEY_public_key(key);
if (privateKeyBytes == null || publicKeyBytes == null) {
throw new IllegalStateException("Unable to generate random key");
}
return new BoringSSLAsymmetricCipherKeyPair(privateKeyBytes, publicKeyBytes);
} finally {
BoringSSL.EVP_HPKE_KEY_cleanup_and_free(key);
}
}

@Override
public boolean isSupported(AEAD aead) {
if (aead == null) {
Expand Down
Expand Up @@ -218,12 +218,16 @@ static jlong netty_incubator_codec_ohttp_hpke_boringssl_EVP_HPKE_KEY_new(JNIEnv*
return (jlong) EVP_HPKE_KEY_new();
}

static void netty_incubator_codec_ohttp_hpke_boringssl_EVP_HPKE_KEY_free(JNIEnv* env, jclass clazz, jlong key) {
EVP_HPKE_KEY_free((EVP_HPKE_KEY *) key);
}

static void netty_incubator_codec_ohttp_hpke_boringssl_EVP_HPKE_KEY_cleanup(JNIEnv* env, jclass clazz, jlong key) {
EVP_HPKE_KEY_cleanup((EVP_HPKE_KEY *) key);
}

static void netty_incubator_codec_ohttp_hpke_boringssl_EVP_HPKE_KEY_free(JNIEnv* env, jclass clazz, jlong key) {
EVP_HPKE_KEY_free((EVP_HPKE_KEY *) key);
static jint netty_incubator_codec_ohttp_hpke_boringssl_EVP_HPKE_KEY_generate(JNIEnv* env, jclass clazz, jlong key, jlong kem) {
return (jint) EVP_HPKE_KEY_generate((EVP_HPKE_KEY *) key, (const EVP_HPKE_KEM *) kem);
}

static jint netty_incubator_codec_ohttp_hpke_boringssl_EVP_HPKE_KEY_init(JNIEnv* env, jclass clazz, jlong key, jlong kem, jbyteArray priv_key_array) {
Expand Down Expand Up @@ -394,6 +398,7 @@ static const JNINativeMethod fixed_method_table[] = {
{ "EVP_HPKE_KEY_new", "()J", (void *) netty_incubator_codec_ohttp_hpke_boringssl_EVP_HPKE_KEY_new },
{ "EVP_HPKE_KEY_cleanup", "(J)V", (void *) netty_incubator_codec_ohttp_hpke_boringssl_EVP_HPKE_KEY_cleanup },
{ "EVP_HPKE_KEY_free", "(J)V", (void *) netty_incubator_codec_ohttp_hpke_boringssl_EVP_HPKE_KEY_free },
{ "EVP_HPKE_KEY_generate", "(JJ)I", (void *) netty_incubator_codec_ohttp_hpke_boringssl_EVP_HPKE_KEY_generate },
{ "EVP_HPKE_KEY_init", "(JJ[B)I", (void *) netty_incubator_codec_ohttp_hpke_boringssl_EVP_HPKE_KEY_init },
{ "EVP_HPKE_KEY_public_key", "(J)[B", (void *) netty_incubator_codec_ohttp_hpke_boringssl_EVP_HPKE_KEY_public_key },
{ "EVP_HPKE_KEY_private_key", "(J)[B", (void *) netty_incubator_codec_ohttp_hpke_boringssl_EVP_HPKE_KEY_private_key },
Expand Down
Expand Up @@ -80,6 +80,16 @@ HPKERecipientContext setupHPKEBaseR(HPKEMode mode, KEM kem, KDF kdf, AEAD aead,
*/
AsymmetricKeyParameter deserializePublicKey(KEM kem, byte[] publicKeyBytes);


/**
* Generate a random private key. Please note that this might not be possible for all of the {@link KEM} and so
* this method might throw an {@link UnsupportedOperationException}.
*
* @param kem the {@link KEM} that is used.
* @return the generated key.
*/
AsymmetricCipherKeyPair newRandomPrivateKey(KEM kem);

/**
* Returns {@code true} if the given {@link AEAD} is supported by the implementation, {@code false} otherwise.
*
Expand Down