org.bouncycastle.crypto.hpke (Bouncy Castle Library 1.85 API Specification)
Date: 2026-07-12

# Package org.bouncycastle.crypto.hpke

Hybrid Public Key Encryption (HPKE) per RFC 9180.

See: Description

- Class Summary
  Class | Description
  --- | ---
  AEAD | AEAD wrapper backing `HPKEContext.seal(byte[], byte[])`/`HPKEContext.open(byte[], byte[])`.
  HPKE | Hybrid Public Key Encryption (HPKE) per RFC 9180.
  HPKEContext | An HPKE encryption / decryption context produced by one of the `HPKE.setup*R` (recipient) factory methods, or — via the `HPKEContextWithEncapsulation` subclass — by one of the `HPKE.setup*S` (sender) factories.
  HPKEContextWithEncapsulation | Sender-side `HPKEContext` that additionally carries the `enc` octet string produced by the KEM's encapsulation step.
  KEM | Abstract base for HPKE Key Encapsulation Mechanisms per RFC 9180 §4.

## Package org.bouncycastle.crypto.hpke Description

Hybrid Public Key Encryption (HPKE) per RFC 9180.

HPKE composes a Key Encapsulation Mechanism (KEM), a Key Derivation Function (KDF) and an Authenticated-Encryption-with-Additional-Data (AEAD) algorithm into a single hybrid public-key encryption scheme. It's the building block underneath MLS (RFC 9420), TLS Encrypted Client Hello, and Oblivious HTTP (RFC 9458).

## Supported parameter sets

The top-level facade `HPKE` exposes the full RFC 9180 algorithm matrix via `short` ID constants:

- Modes: `mode_base`, `mode_psk`, `mode_auth`, `mode_auth_psk`.
- KEMs: DHKEM(P-256, HKDF-SHA256), DHKEM(P-384, HKDF-SHA384), DHKEM(P-521, HKDF-SHA512), DHKEM(X25519, HKDF-SHA256), DHKEM(X448, HKDF-SHA512). External KEM implementations may be plugged in via the `KEM` abstract base and the `HPKE(mode, kemId, kdfId, aeadId, KEM, encSize)` constructor.
- KDFs: HKDF-SHA256, HKDF-SHA384, HKDF-SHA512.
- AEADs: AES-128-GCM, AES-256-GCM, ChaCha20-Poly1305, and the export-only sentinel (id 0xFFFF) for callers who only need `HPKEContext.export(byte[], int)` and not seal/open.

## Typical caller flow (mode_base)

Sender:

     HPKE hpke = new HPKE(HPKE.mode_base,
                          HPKE.kem_X25519_SHA256,
                          HPKE.kdf_HKDF_SHA256,
                          HPKE.aead_AES_GCM128);
     HPKEContextWithEncapsulation ctx = hpke.setupBaseS(recipientPub, info);
     byte[] enc = ctx.getEncapsulation();          // transmit alongside ct
     byte[] ct  = ctx.seal(aad, plaintext);        // ctx is stateful, advances nonce

Receiver:

     HPKEContext ctx = hpke.setupBaseR(enc, recipientKeyPair, info);
     byte[] pt = ctx.open(aad, ct);

For single-message use cases the `HPKE.seal(org.bouncycastle.crypto.params.AsymmetricKeyParameter, byte[], byte[], byte[], byte[], byte[], org.bouncycastle.crypto.AsymmetricCipherKeyPair)` and `HPKE.open(byte[], org.bouncycastle.crypto.AsymmetricCipherKeyPair, byte[], byte[], byte[], byte[], byte[], org.bouncycastle.crypto.params.AsymmetricKeyParameter)` convenience methods do both steps in one call and return `[enc, ct]` / the plaintext respectively.

## Sealing semantics

The contexts returned by `setup*S` and `setup*R` are stateful: each `seal` / `open` call advances an internal sequence number that's XOR-mixed into the AEAD nonce, so a single context can encrypt or decrypt many messages in order without nonce reuse. The `HPKEContextWithEncapsulation.getEncapsulation()` method returns the `enc` octet string that must be transmitted alongside the first ciphertext so the receiver can run the matching `setup*R`.