hpke
An idiomatic OCaml implementation of Hybrid Public Key Encryption,
RFC 9180. The
Base, PSK, Auth, and AuthPSK modes live under the explicitly versioned
Hpke.Rfc9180 module; elliptic-curve, hash, and AEAD
primitives are delegated to
Mirage Crypto,
curve448,
Digestif, and
kdf.
- 45 encryption ciphersuites and 15 export-only suites, from a closed registry.
- Secret keys and message contexts are abstract; a suite's capability keeps export-only suites out of
seal. - Every operation returns a
result. Peer-controlled failures at protocol boundaries normalize to one error. - Randomness is a parameter, never a global: the caller passes an explicit generator.
| Component | Algorithms | Count |
|---|---|---|
| KEM | DHKEM over P-256, P-384, P-521, X25519, X448 | 5 |
| KDF | HKDF-SHA256, HKDF-SHA384, HKDF-SHA512 | 3 |
| AEAD | AES-128-GCM, AES-256-GCM, ChaCha20-Poly1305 | 3 |
| Modes | Base, PSK, Auth, AuthPSK | 4 |
Every KEM/KDF/AEAD combination is exercised by the test suite, and export-only operation is a separate suite type rather than a special AEAD value. Codepoints, sizes, and deliberate omissions: suites.
Release 0.2.0 is for interoperability review. It has not received an independent cryptographic audit. Read the security model before using it with sensitive data.
| Release | 0.2.0 |
|---|---|
| OCaml | 4.14 or newer |
| Dune | 3.12 or newer |
| Modes | Base, PSK, Auth, and AuthPSK |
| Ciphersuites | 45, plus 15 export-only |
| License | ISC |
Quick start
opam install hpke
opam-repository takes a new release only after review, so it can trail the newest tag. Pinning a release from source until it catches up: install.
Depend on the library, and on a Unix RNG entry point for applications:
(executable
(name main)
(libraries hpke mirage-crypto-rng.unix))
Seal one message and open it again:
open Hpke
let () =
Mirage_crypto_rng_unix.use_default ();
let rng = Mirage_crypto_rng.default_generator () in
let suite =
Suite.create ~kem:Kem.X25519 ~kdf:Kdf.Hkdf_sha256
~aead:Aead.Chacha20_poly1305
in
match generate_key_pair ~rng Kem.X25519 with
| Error error -> Format.eprintf "keygen: %a@." Error.pp error
| Ok (private_key, public_key) -> (
match
Rfc9180.seal_base ~rng suite ~recipient:public_key
~info:"application-v1" ~aad:"message-metadata"
~plaintext:"secret payload"
with
| Error error -> Format.eprintf "seal: %a@." Error.pp error
| Ok ciphertext -> (
match
Rfc9180.open_base suite ~recipient:private_key
~info:"application-v1" ~aad:"message-metadata"
~ciphertext
with
| Ok text -> assert (String.equal text "secret payload")
| Error error ->
Format.eprintf "open: %a@." Error.pp error))
The result carries encapsulated_key and
ciphertext as separate fields. The library does not invent
an application wire format: framing those two strings, and binding them
to the surrounding protocol, is the application's job.
Choose an API
- Single-shot
- Best default.
seal_baseandopen_baseestablish a context, move one message, and discard it. Peer-controlled failures come back asOpen_error. - Stateful context
- Use
setup_base_senderandsetup_base_receiverwhen one encapsulation carries many messages. Each successful operation consumes exactly one nonce. - Export-only
- Build a suite with
Suite.export_onlyto derive keys for another protocol. Such a suite cannot be passed toseal— the type checker rejects it.
Continue with usage, or read the security model for what this library does and does not defend against.