diff options
author | Tor Brede Vekterli <vekterli@yahooinc.com> | 2022-10-19 12:40:34 +0200 |
---|---|---|
committer | Tor Brede Vekterli <vekterli@yahooinc.com> | 2022-10-19 12:40:34 +0200 |
commit | 82c8d614762c3e4bb0abc14148a1fba1ca3182e5 (patch) | |
tree | bcbd539039e4e0b3ed4c35f41959eecb54994fbd /security-utils/src/main/java/com/yahoo/security | |
parent | 9bd0a86bba6280aded2ff575ba095a446d6aa4e7 (diff) |
Add X25519 private to public key extraction and use for HPKE opening
Avoids the need to pass the full key pair when opening a sealed piece
of ciphertext, since we can just extract the public key on-demand.
Uses BouncyCastle X25519 utils under the hood.
Diffstat (limited to 'security-utils/src/main/java/com/yahoo/security')
4 files changed, 18 insertions, 16 deletions
diff --git a/security-utils/src/main/java/com/yahoo/security/KeyUtils.java b/security-utils/src/main/java/com/yahoo/security/KeyUtils.java index 9fe64baa80a..cef0dd9a62e 100644 --- a/security-utils/src/main/java/com/yahoo/security/KeyUtils.java +++ b/security-utils/src/main/java/com/yahoo/security/KeyUtils.java @@ -13,6 +13,7 @@ import org.bouncycastle.jce.spec.ECParameterSpec; import org.bouncycastle.jce.spec.ECPublicKeySpec; import org.bouncycastle.math.ec.ECPoint; import org.bouncycastle.math.ec.FixedPointCombMultiplier; +import org.bouncycastle.math.ec.rfc7748.X25519; import org.bouncycastle.openssl.PEMKeyPair; import org.bouncycastle.openssl.PEMParser; import org.bouncycastle.openssl.jcajce.JcaPEMWriter; @@ -317,6 +318,14 @@ public class KeyUtils { } } + // TODO unify with extractPublicKey() + public static XECPublicKey extractX25519PublicKey(XECPrivateKey privateKey) { + byte[] privScalar = toRawX25519PrivateKeyBytes(privateKey); + byte[] pubPoint = new byte[X25519.POINT_SIZE]; + X25519.generatePublicKey(privScalar, 0, pubPoint, 0); // scalarMultBase => public key point + return fromRawX25519PublicKey(pubPoint); + } + /** * Computes a shared secret using the Elliptic Curve Diffie-Hellman (ECDH) protocol for X25519 curves. * <p> diff --git a/security-utils/src/main/java/com/yahoo/security/hpke/DHKemX25519HkdfSha256.java b/security-utils/src/main/java/com/yahoo/security/hpke/DHKemX25519HkdfSha256.java index 430a9d57097..8f6dffcb9c2 100644 --- a/security-utils/src/main/java/com/yahoo/security/hpke/DHKemX25519HkdfSha256.java +++ b/security-utils/src/main/java/com/yahoo/security/hpke/DHKemX25519HkdfSha256.java @@ -118,18 +118,13 @@ final class DHKemX25519HkdfSha256 implements Kem { * shared_secret = ExtractAndExpand(dh, kem_context) * return shared_secret * </pre> - * - * Implementation note: we take in the key pair to avoid needing to compute the public key (TODO!) */ @Override - public byte[] decap(byte[] enc, KeyPair kpR) { + public byte[] decap(byte[] enc, XECPrivateKey skR) { var pkE = deserializePublicKey(enc); - - var skR = (XECPrivateKey)kpR.getPrivate(); - var pkR = (XECPublicKey)kpR.getPublic(); byte[] dh = KeyUtils.ecdh(skR, pkE); - byte[] pkRm = serializePublicKey(pkR); + byte[] pkRm = serializePublicKey(KeyUtils.extractX25519PublicKey(skR)); byte[] kemContext = concat(enc, pkRm); return extractAndExpand(dh, kemContext); diff --git a/security-utils/src/main/java/com/yahoo/security/hpke/Hpke.java b/security-utils/src/main/java/com/yahoo/security/hpke/Hpke.java index e3f233285a8..133798faa99 100644 --- a/security-utils/src/main/java/com/yahoo/security/hpke/Hpke.java +++ b/security-utils/src/main/java/com/yahoo/security/hpke/Hpke.java @@ -2,6 +2,7 @@ package com.yahoo.security.hpke; import java.security.KeyPair; +import java.security.interfaces.XECPrivateKey; import java.security.interfaces.XECPublicKey; import java.util.Arrays; @@ -246,11 +247,9 @@ public final class Hpke { * return KeyScheduleR(mode_base, shared_secret, info, * default_psk, default_psk_id) * </pre> - * - * TODO only take private key, not key pair. Need functionality for X25519 priv -> pub extraction first. */ - ContextR setupBaseR(byte[] enc, KeyPair kpR, byte[] info) { - byte[] sharedSecret = kem.decap(enc, kpR); + ContextR setupBaseR(byte[] enc, XECPrivateKey skR, byte[] info) { + byte[] sharedSecret = kem.decap(enc, skR); return new ContextR(keySchedule(MODE_BASE, sharedSecret, info, DEFAULT_PSK, DEFAULT_PSK_ID)); } @@ -310,8 +309,8 @@ public final class Hpke { * return pt * </pre> */ - public byte[] openBase(byte[] enc, KeyPair kpR, byte[] info, byte[] aad, byte[] ct) { - var ctx = setupBaseR(enc, kpR, info); + public byte[] openBase(byte[] enc, XECPrivateKey skR, byte[] info, byte[] aad, byte[] ct) { + var ctx = setupBaseR(enc, skR, info); var base = ctx.base; // TODO wrap any exceptions in OpenError et al? return aead.open(base.key(), base.nonce(), aad, ct); diff --git a/security-utils/src/main/java/com/yahoo/security/hpke/Kem.java b/security-utils/src/main/java/com/yahoo/security/hpke/Kem.java index 7bbb2df0960..99c019a9d0b 100644 --- a/security-utils/src/main/java/com/yahoo/security/hpke/Kem.java +++ b/security-utils/src/main/java/com/yahoo/security/hpke/Kem.java @@ -4,6 +4,7 @@ package com.yahoo.security.hpke; import com.yahoo.security.KeyUtils; import java.security.KeyPair; +import java.security.interfaces.XECPrivateKey; import java.security.interfaces.XECPublicKey; /** @@ -30,10 +31,8 @@ public interface Kem { * "Deterministic algorithm using the private key <code>skR</code> to recover the * ephemeral symmetric key (the KEM shared secret) from its encapsulated * representation <code>enc</code>." - * - * TODO just take skR instead of entire key pair */ - byte[] decap(byte[] enc, KeyPair kpR); + byte[] decap(byte[] enc, XECPrivateKey skR); /** The length in bytes of a KEM shared secret produced by this KEM. */ short nSecret(); |