ExIcaoVds.Crypto.HPKE (ex_icao_vds v0.3.2)

Copy Markdown

RFC 9180 HPKE Base Mode: DHKEM(P-256, HKDF-SHA256) + HKDF-SHA256 + AES-256-GCM.

Cipher suite IDs: kem=0x0010, kdf=0x0001, aead=0x0002.

Only Base mode (no sender auth, no PSK) is implemented. This is sufficient for encrypting VDS feature values to a static verifier public key.

Usage

# Encrypt
{pub, priv} = :crypto.generate_key(:ecdh, :secp256r1)
{:ok, enc, ct} = ExIcaoVds.Crypto.HPKE.seal(pub, "info", "aad", "hello")

# Decrypt
{:ok, plaintext} = ExIcaoVds.Crypto.HPKE.open(priv, pub, enc, "info", "aad", ct)

Summary

Functions

Single-shot HPKE Base Mode decryption (OpenBase).

Single-shot HPKE Base Mode encryption (SealBase).

Functions

open(recipient_priv_key, recipient_pub_key, enc, info, aad, ciphertext)

@spec open(binary(), binary(), binary(), binary(), binary(), binary()) ::
  {:ok, binary()} | {:error, term()}

Single-shot HPKE Base Mode decryption (OpenBase).

  • recipient_priv_key — 32-byte P-256 private scalar
  • recipient_pub_key — 65-byte uncompressed P-256 public key
  • enc — 65-byte ephemeral public key returned by seal/4
  • info — same context binding used during seal/4
  • aad — same AAD used during seal/4
  • ciphertext — value returned by seal/4 (includes 16-byte GCM tag)

Returns {:ok, plaintext} or {:error, reason}.

seal(recipient_pub_key, info, aad, plaintext)

@spec seal(binary(), binary(), binary(), binary()) ::
  {:ok, binary(), binary()} | {:error, term()}

Single-shot HPKE Base Mode encryption (SealBase).

  • recipient_pub_key — 65-byte uncompressed P-256 EC point (0x04 ‖ x ‖ y)
  • info — context binding binary (application-defined)
  • aad — additional authenticated data
  • plaintext — bytes to encrypt

Returns {:ok, enc, ciphertext} where enc is the 65-byte ephemeral public key and ciphertext is the AES-256-GCM ciphertext with 16-byte tag appended.