Quick Start

Create an HPKE instance

Use the main HPKE class with algorithm identifiers, or the convenience function create_hpke() for the default ciphersuite (X25519 + HKDF-SHA256 + AES-128-GCM):

from rfc9180 import HPKE, KEMID, KDFID, AEADID, create_hpke

# Explicit ciphersuite
hpke = HPKE(KEMID.DHKEM_X25519_HKDF_SHA256, KDFID.HKDF_SHA256, AEADID.AES_128_GCM)

# Or defaults
hpke = create_hpke()

Key generation and serialization

# Generate recipient key pair
skR, pkR = hpke.generate_key_pair()

# Serialize for storage or transmission
pk_bytes = hpke.serialize_public_key(pkR)
sk_bytes = hpke.serialize_private_key(skR)

# seal/open accept both bytes and key objects
enc, ct = hpke.seal_base(pk_bytes, info, aad, pt)

Derive a key pair from a seed (deterministic key generation):

seed = b"your-32-byte-or-longer-secret-seed-material"
skR, pkR = hpke.derive_key_pair(seed)

Single-shot encryption (Base mode)

info = b"application-info"
aad = b"additional-data"
plaintext = b"secret message"

enc, ciphertext = hpke.seal_base(pkR, info, aad, plaintext)
decrypted = hpke.open_base(enc, skR, info, aad, ciphertext)
assert decrypted == plaintext

Other single-shot modes

PSK mode (pre-shared key; must have at least 32 bytes of entropy):

psk = b"pre-shared-key-with-sufficient-entropy"
psk_id = b"psk-identifier"
enc, ct = hpke.seal_psk(pkR, info, aad, pt, psk, psk_id)
pt = hpke.open_psk(enc, skR, info, aad, ct, psk, psk_id)

Auth mode (sender authentication):

skS, pkS = hpke.generate_key_pair()
enc, ct = hpke.seal_auth(pkR, info, aad, pt, skS)
pt = hpke.open_auth(enc, skR, info, aad, ct, pkS)

AuthPSK mode (authenticated + pre-shared key):

enc, ct = hpke.seal_auth_psk(pkR, info, aad, pt, psk, psk_id, skS)
pt = hpke.open_auth_psk(enc, skR, info, aad, ct, psk, psk_id, pkS)

Multi-shot (context) API

Use the setup methods to get sender/recipient contexts, then seal/open multiple messages:

enc, ctx_sender = hpke.setup.setup_base_sender(pkR, info)
ctx_recipient = hpke.setup.setup_base_recipient(enc, skR, info)

ct1 = ctx_sender.seal(aad, b"message 1")
ct2 = ctx_sender.seal(aad, b"message 2")

pt1 = ctx_recipient.open(aad, ct1)
pt2 = ctx_recipient.open(aad, ct2)

Secret export

Setup a context and export a secret (no encryption, just key agreement + export):

enc, ctx_sender = hpke.setup.setup_base_sender(pkR, info)
secret = ctx_sender.export(b"exporter-context", 32)

# Recipient side:
ctx_recipient = hpke.setup.setup_base_recipient(enc, skR, info)
secret = ctx_recipient.export(b"exporter-context", 32)

Message encoding helpers

Encode/parse a self-describing wire format (header + enc + ct):

from rfc9180 import append_header, parse_header
from rfc9180.constants import HPKEMode

enc, ct = hpke.seal_base(pkR, info, aad, pt)
msg = append_header(
    enc, ct,
    int(hpke.kem_id), int(hpke.kdf_id), int(hpke.aead_id),
    int(HPKEMode.MODE_BASE),
)

kem_id, kdf_id, aead_id, mode, enc2, ct2 = parse_header(msg, enc_len=hpke.kem.Nenc)
pt2 = hpke.open_base(enc2, skR, info, aad, ct2)

Using different ciphersuites

# ChaCha20-Poly1305 (no AES dependency)
hpke_chacha = HPKE(
    KEMID.DHKEM_X25519_HKDF_SHA256,
    KDFID.HKDF_SHA256,
    AEADID.CHACHA20_POLY1305,
)

# P-256 for NIST compliance
hpke_p256 = HPKE(
    KEMID.DHKEM_P256_HKDF_SHA256,
    KDFID.HKDF_SHA256,
    AEADID.AES_128_GCM,
)

Using keys from JWK or PEM

from rfc9180 import HPKE, KEMKey, create_hpke

hpke = create_hpke()

# From JWK (JSON Web Key)
jwk_dict = {"kty": "OKP", "crv": "X25519", "x": "base64url-public-key"}
pkR = KEMKey.from_jwk(jwk_dict)
enc, ct = hpke.seal_base(pkR, info, aad, pt)

# From PEM
pem_str = "-----BEGIN PUBLIC KEY-----\n..."
pkR = KEMKey.from_pem(pem_str)

Error handling

from rfc9180.exceptions import (
    OpenError,
    MessageLimitReachedError,
    DeserializeError,
    DecapError,
)

try:
    pt = hpke.open_base(enc, skR, info, aad, ct)
except OpenError:
    # Decryption failed (wrong key, tampered data, etc.)
    pass
except DecapError:
    # Invalid encapsulated key or decapsulation failed
    pass

For full API details, see API Reference. For more complete examples, see Examples.