package hpke
Install
dune-project
Dependency
Authors
Maintainers
Sources
md5=af35c94697402d005548f08f797328f2
sha512=5caedd58fcd45e81fc089a4970697af1b8e282ab2c01b5a2b28d567d034b266b47786203a319f2f0efb3f5a97f55e73de2c0ad880739a3d2d3fce1f6a6245ae7
Description
An idiomatic, misuse-resistant implementation of the RFC 9180 HPKE Base, PSK, Auth, and AuthPSK modes, with Diffie-Hellman, post-quantum ML-KEM, and post-quantum/traditional hybrid KEMs such as X-Wing. Cryptographic primitives are delegated to Mirage Crypto, curve448, mlkem, Digestif, and kdf.
README
hpke
Hybrid Public Key Encryption (RFC 9180) for OCaml. Encrypt to a recipient's public key; decrypt with their private key.
Requires 64-bit OCaml 4.14+ and Dune 3.12+. No release is supported for production use yet. Read the security policy.
Run an example
In an initialized opam switch:
opam install hpke
mkdir hpke-example
cd hpke-exampleCreate dune-project:
(lang dune 3.12)Create dune:
(executable
(name main)
(libraries hpke mirage-crypto-rng.unix))Create main.ml:
open Hpke
let ( let* ) = Result.bind
let round_trip ~rng =
let suite =
Suite.create ~kem:Kem.X25519 ~kdf:Kdf.Hkdf_sha256
~aead:Aead.Chacha20_poly1305
in
let* private_key, public_key =
generate_key_pair ~rng Kem.X25519
in
let info = "example-v1" and aad = "message-1" in
let* ciphertext =
Rfc9180.seal_base ~rng suite ~recipient:public_key ~info ~aad
~plaintext:"Hello, HPKE."
in
Rfc9180.open_base suite ~recipient:private_key ~info ~aad
~ciphertext
let () =
Mirage_crypto_rng_unix.use_default ();
let rng = Mirage_crypto_rng.default_generator () in
match round_trip ~rng with
| Ok plaintext -> print_endline plaintext
| Error error ->
Format.eprintf "%a@." Error.pp error;
exit 1Run it:
opam exec -- dune exec ./main.exeOutput: Hello, HPKE.
The example keeps both keys in one process. In an application, the sender needs a trusted copy of the recipient's public key; only the recipient needs the private key.
seal_basereturns two byte strings:encapsulated_keyandciphertext. Send both; your protocol defines their encoding.infoidentifies the protocol or purpose.aadis authenticated message metadata. Neither is encrypted or sent by the library; both must match exactly when opening.- Base mode does not authenticate the sender. Use PSK, Auth, or AuthPSK when your protocol requires sender authentication.
Choose an API
Need | API |
|---|---|
One independent message |
|
A pre-shared secret |
|
A sender key |
|
Several ordered messages |
|
Derived keys without encryption |
|
The seal, open, setup, and context operations are under Hpke.Rfc9180. Keep context operations serial and messages in order. Single-shot opens report peer-controlled failures as Open_error.
Algorithms and versions
- KEM: P-256, P-384, P-521, X25519, X448; ML-KEM-512, -768, -1024; MLKEM768-P256, MLKEM768-X25519 (X-Wing), MLKEM1024-P384.
- KDF: HKDF-SHA256, -SHA384, -SHA512.
Hpke.Draft_hpke_04also has SHAKE128 and SHAKE256. - AEAD: AES-128-GCM, AES-256-GCM, ChaCha20-Poly1305.
ML-KEM and hybrid KEMs support Base and PSK only. Hpke.Draft_hpke_04 implements the successor draft with those two modes; Hpke.Rfc9180 keeps its RFC wire behavior. Hybrid KEMs and Draft_hpke_04 require 0.4.0 or newer; see installation options.
Documentation
- Usage: keys, modes, contexts, exports, errors.
- Ciphersuites: identifiers, sizes, draft support.
- API reference: signatures and error contracts.
- Development: builds, tests, contributions.
- Changelog and test-vector sources.
To build this checkout in an initialized opam switch:
opam install . --deps-only --with-test --with-doc
opam exec -- dune build @all @doc
opam exec -- dune runtestLicense
ISC. Independent implementation; prior OCaml work: FantomeBeignet/ohpke.
Dependencies (10)
-
eqaf
>= "0.10" -
digestif
>= "1.3.1" -
kdf
>= "1.1.0" -
mlkem
>= "0.1.1" -
curve448
>= "0.1.0" -
mirage-crypto-rng
>= "2.4.0" -
mirage-crypto-ec
>= "2.4.0" -
mirage-crypto
>= "2.4.0" -
dune
>= "3.12" -
ocaml
>= "4.14"
Dev Dependencies (6)
-
ocamlformat
with-dev-setup & = "0.29.0" -
odoc
with-doc -
yojson
with-test & >= "2.0.0" -
crowbar
with-test & >= "0.2.1" -
qcheck-alcotest
with-test & >= "0.25" -
alcotest
with-test & >= "1.7.0"
Used by
None
Conflicts
None