Skip to content

Commit

Permalink
Reuse EVP_HPKE_KEY when using BoringSSLOHttpCryptoProvider.setupHPKEB…
Browse files Browse the repository at this point in the history
…aseR(...)

Motivation:

When we generate the BoringSSLAsymmetricCipherKeyPair we can also just store the EVP_HPE_KEY in the object and so use it directly when setupHPKEBaseR(...) is used.
This will make things cheaper.

Modifications:

Store the pointer to EVP_HPE_KEY in BoringSSLAsymmetricCipherKeyPair and use a PhantomReference to free it later.

Result:

Less overhead
  • Loading branch information
normanmaurer committed Dec 22, 2023
1 parent 731410f commit 4775440
Show file tree
Hide file tree
Showing 7 changed files with 64 additions and 18 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -54,8 +54,8 @@ int execute(long ctx, long ad, int adLen, long in, int inLen, long out, int outL
}
};

BoringSSLAEADContext(long ctx, int aeadMaxOverhead, byte[] baseNonce) {
super(ctx);
BoringSSLAEADContext(BoringSSLOHttpCryptoProvider cryptoProvider, long ctx, int aeadMaxOverhead, byte[] baseNonce) {
super(cryptoProvider, ctx);
this.baseNonce = Unpooled.directBuffer(baseNonce.length).writeBytes(baseNonce);
this.baseNonceAddress = BoringSSL.memory_address(this.baseNonce);
this.baseNonceLen = this.baseNonce.readableBytes();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,11 @@
final class BoringSSLAsymmetricCipherKeyPair implements AsymmetricCipherKeyPair {
private final BoringSSLAsymmetricKeyParameter privateKey;
private final BoringSSLAsymmetricKeyParameter publicKey;
final long key;

BoringSSLAsymmetricCipherKeyPair(byte[] privateKeyBytes, byte[] publicKeyBytes) {
BoringSSLAsymmetricCipherKeyPair(long key, byte[] privateKeyBytes, byte[] publicKeyBytes) {
assert key != -1;
this.key = key;
privateKey = new BoringSSLAsymmetricKeyParameter(privateKeyBytes, true);
publicKey = new BoringSSLAsymmetricKeyParameter(publicKeyBytes, false);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,10 +24,13 @@
*/
abstract class BoringSSLCryptoContext implements CryptoContext {

private final BoringSSLOHttpCryptoProvider cryptoProvider;

// We use an AtomicLong to reduce the possibility of crashing after the user called close().
private final AtomicLong ctxRef;

BoringSSLCryptoContext(long ctx) {
BoringSSLCryptoContext(BoringSSLOHttpCryptoProvider cryptoProvider, long ctx) {
this.cryptoProvider = cryptoProvider;
assert ctx != -1;
this.ctxRef = new AtomicLong(ctx);
}
Expand All @@ -51,6 +54,7 @@ public final void close() {
long ctx = ctxRef.getAndSet(-1);
if (ctx != -1) {
destroyCtx(ctx);
cryptoProvider.free_EVP_HPKE_KEYS();
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,8 @@
*/
class BoringSSLHPKEContext extends BoringSSLCryptoContext implements HPKEContext {

BoringSSLHPKEContext(long hpkeCtx) {
super(hpkeCtx);
BoringSSLHPKEContext(BoringSSLOHttpCryptoProvider cryptoProvider, long hpkeCtx) {
super(cryptoProvider, hpkeCtx);
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,8 @@ int execute(long ctx, long ad, int adLen, long in, int inLen, long out, int outL
}
};

BoringSSLHPKERecipientContext(long hpkeCtx) {
super(hpkeCtx);
BoringSSLHPKERecipientContext(BoringSSLOHttpCryptoProvider cryptoProvider, long hpkeCtx) {
super(cryptoProvider, hpkeCtx);
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,8 +41,8 @@ int execute(long ctx, long ad, int adLen, long in, int inLen, long out, int outL

private final byte[] encapsulation;

BoringSSLHPKESenderContext(long hpkeCtx, byte[] encapsulation) {
super(hpkeCtx);
BoringSSLHPKESenderContext(BoringSSLOHttpCryptoProvider cryptoProvider, long hpkeCtx, byte[] encapsulation) {
super(cryptoProvider, hpkeCtx);
this.encapsulation = encapsulation;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@
import io.netty.incubator.codec.hpke.HPKESenderContext;
import io.netty.incubator.codec.hpke.OHttpCryptoProvider;

import java.lang.ref.PhantomReference;
import java.lang.ref.ReferenceQueue;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
Expand All @@ -38,6 +40,15 @@ public final class BoringSSLOHttpCryptoProvider implements OHttpCryptoProvider {
private static final List<Mode> SUPPORTED_MODE_LIST = Collections.singletonList(Mode.Base);
private static final List<KEM> SUPPORTED_KEM_LIST = Collections.singletonList(KEM.X25519_SHA256);
private static final List<KDF> SUPPORTED_KDF_LIST = Collections.singletonList(KDF.HKDF_SHA256);
private final ReferenceQueue<BoringSSLAsymmetricCipherKeyPair> keyPairRefQueue = new ReferenceQueue<>();
private static final class EVP_HPKE_KEY_PhantomRef extends PhantomReference<BoringSSLAsymmetricCipherKeyPair> {
private final long key;
public EVP_HPKE_KEY_PhantomRef(BoringSSLAsymmetricCipherKeyPair referent,
ReferenceQueue<BoringSSLAsymmetricCipherKeyPair> q) {
super(referent, q);
this.key = referent.key;
}
}

/**
* {@link BoringSSLOHttpCryptoProvider} instance.
Expand All @@ -61,7 +72,7 @@ public AEADContext setupAEAD(AEAD aead, byte[] key, byte[] baseNonce) {
int maxOverhead = BoringSSL.EVP_AEAD_max_overhead(boringSSLAead);
long ctx = BoringSSL.EVP_AEAD_CTX_new_or_throw(boringSSLAead, key, BoringSSL.EVP_AEAD_DEFAULT_TAG_LENGTH);
try {
BoringSSLAEADContext aeadCtx = new BoringSSLAEADContext(ctx, maxOverhead, baseNonce);
BoringSSLAEADContext aeadCtx = new BoringSSLAEADContext(this, ctx, maxOverhead, baseNonce);
ctx = -1;
return aeadCtx;
} finally {
Expand Down Expand Up @@ -144,7 +155,7 @@ public HPKESenderContext setupHPKEBaseS(
throw new IllegalStateException("Unable to setup EVP_HPKE_CTX");
}
BoringSSLHPKESenderContext hpkeCtx =
new BoringSSLHPKESenderContext(ctx, encapsulation);
new BoringSSLHPKESenderContext(this, ctx, encapsulation);
ctx = -1;
return hpkeCtx;
} finally {
Expand Down Expand Up @@ -173,19 +184,28 @@ public HPKERecipientContext setupHPKEBaseR(Mode mode, KEM kem, KDF kdf, AEAD aea

long ctx = -1;
long key = -1;
boolean freeKey = true;
try {
byte[] privateKeyBytes = encodedAsymmetricKeyParameter(skR.privateParameters());
key = BoringSSL.EVP_HPKE_KEY_new_and_init_or_throw(boringSSLKem, privateKeyBytes);
if (skR instanceof BoringSSLAsymmetricCipherKeyPair) {
key = ((BoringSSLAsymmetricCipherKeyPair) skR).key;
freeKey = false;
} else {
byte[] privateKeyBytes = encodedAsymmetricKeyParameter(skR.privateParameters());
key = BoringSSL.EVP_HPKE_KEY_new_and_init_or_throw(boringSSLKem, privateKeyBytes);
}

ctx = BoringSSL.EVP_HPKE_CTX_new_or_throw();
if (BoringSSL.EVP_HPKE_CTX_setup_recipient(ctx, key, boringSSLKdf, boringSSLAead, enc, info) != 1) {
throw new IllegalStateException("Unable to setup EVP_HPKE_CTX");
}

BoringSSLHPKERecipientContext hpkeCtx = new BoringSSLHPKERecipientContext(ctx);
BoringSSLHPKERecipientContext hpkeCtx = new BoringSSLHPKERecipientContext(this, ctx);
ctx = -1;
return hpkeCtx;
} finally {
BoringSSL.EVP_HPKE_KEY_cleanup_and_free(key);
if (freeKey && key != -1) {
BoringSSL.EVP_HPKE_KEY_cleanup_and_free(key);
}
if (ctx != -1) {
BoringSSL.EVP_HPKE_CTX_cleanup_and_free(ctx);
}
Expand All @@ -206,9 +226,15 @@ public AsymmetricCipherKeyPair deserializePrivateKey(KEM kem, byte[] privateKeyB
"publicKeyBytes does not contain a valid public key: " + Arrays.toString(publicKeyBytes));
}
// No need to clone extractedPublicKey as it was returned by our native call.
return new BoringSSLAsymmetricCipherKeyPair(privateKeyBytes.clone(), extractedPublicKey);
BoringSSLAsymmetricCipherKeyPair pair =
new BoringSSLAsymmetricCipherKeyPair(key, privateKeyBytes.clone(), extractedPublicKey);
new EVP_HPKE_KEY_PhantomRef(pair, keyPairRefQueue);
key = -1;
return pair;
} finally {
BoringSSL.EVP_HPKE_KEY_cleanup_and_free(key);
if (key != -1) {
BoringSSL.EVP_HPKE_KEY_cleanup_and_free(key);
}
}
}

Expand Down Expand Up @@ -243,4 +269,17 @@ public List<KDF> supportedKDF() {
public List<Mode> supportedMode() {
return SUPPORTED_MODE_LIST;
}

/**
* Try to free enqueued {@code EVP_HPKE_KEY}s.
*/
void free_EVP_HPKE_KEYS() {
for (;;) {
EVP_HPKE_KEY_PhantomRef ref = (EVP_HPKE_KEY_PhantomRef) keyPairRefQueue.poll();
if (ref == null) {
return;
}
BoringSSL.EVP_HPKE_KEY_cleanup_and_free(ref.key);
}
}
}

0 comments on commit 4775440

Please sign in to comment.