upstream: https://github.com/mirage/mirage-crypto
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

C 90.1%
OCaml 9.6%
Makefile 0.1%
Dune 0.1%
Standard ML 0.1%
Other 0.2%
103 1 0

Clone this repository

https://tangled.org/gazagnaire.org/ocaml-crypto https://tangled.org/did:plc:jhift2vwcxhou52p3sewcrpx/ocaml-crypto
git@git.recoil.org:gazagnaire.org/ocaml-crypto git@git.recoil.org:did:plc:jhift2vwcxhou52p3sewcrpx/ocaml-crypto

For self-hosted knots, clone URLs may differ based on your setup.

Download tar.gz
README.md

crypto - Cryptographic primitives for OCaml#

Warning. This is a work-in-progress experimental fork of mirage-crypto. Do not use it in production. As the experiments described under Why this fork stabilise, the intent is to upstream them back to mirage/mirage-crypto and retire the fork. Until that happens, use mirage-crypto from opam directly for anything you care about.

What this fork adds#

  1. Vendored BearSSL constant-time AES. lib/c/bearssl/ imports the aes_ct64 / ghash_ctmul64 subset from BearSSL. On architectures that have no hardware-accelerated AES, this is the fallback block implementation. The vendored files are auto-generated by scripts/import.ml so the import is reproducible against a pinned upstream commit.
  2. Pure-OCaml AES and GHASH backends. lib/ocaml/aes_pure.ml is a bitsliced AES encryptor and lib/ocaml/ghash_pure.ml a constant-time GHASH over bitwise reduction. Both run under js_of_ocaml where no C compiler is available; upstream mirage-crypto requires C stubs. The OCaml GCM path glues these together so AEAD works in the browser.
  3. Packages renamed and Lwt/Miou bindings dropped. Downstream Eio-based services that cannot pull in Lwt or Miou. Upstream leaks those into the dependency graph under some opam resolutions; this fork renames the packages so both can coexist in the same opam switch.

The rest of the API mirrors the upstream modules with the packages renamed:

Upstream This fork
mirage-crypto crypto
mirage-crypto-rng crypto-rng
mirage-crypto-rng.unix crypto-rng.unix
mirage-crypto-pk crypto-pk
mirage-crypto-ec crypto-ec

Installation#

$ opam install nox-crypto nox-crypto-rng nox-crypto-pk nox-crypto-ec

If opam cannot find the packages, they may not yet be released in the public opam-repository. Add the overlay repository, then install them:

$ opam repo add samoht https://tangled.org/gazagnaire.org/opam-overlay.git
$ opam update
$ opam install nox-crypto nox-crypto-rng nox-crypto-pk nox-crypto-ec

Usage#

Seed the RNG#

Every key-generation or random-dependent operation fails with Unseeded_generator until a generator is installed. Call use_default () once at program start:

let () = Crypto_rng_unix.use_default ()

On Linux this reads from getrandom(2), on BSD/macOS from getentropy(3), on Windows 10+ from BCryptGenRandom. Older Windows is unsupported.

AEAD: AES-GCM and ChaCha20-Poly1305#

let aead_roundtrip () =
  let key = Crypto.AES.GCM.of_secret (Crypto_rng.generate 32) in
  let nonce = Crypto_rng.generate 12 in
  let adata = "headers" in
  let plaintext = "secret message" in
  let ciphertext =
    Crypto.AES.GCM.authenticate_encrypt ~key ~nonce ~adata plaintext
  in
  match
    Crypto.AES.GCM.authenticate_decrypt ~key ~nonce ~adata ciphertext
  with
  | Some recovered -> assert (recovered = plaintext)
  | None -> failwith "authentication failed"

Crypto.Chacha20 and Crypto.AES.CCM16 expose the same AEAD signature. Mismatched nonce/tag or tampered ciphertext return None -- never raise.

Ed25519 signatures#

let sign_and_verify () =
  let priv, pub = Crypto_ec.Ed25519.generate () in
  let msg = "approved transfer of 42 units" in
  let sig_ = Crypto_ec.Ed25519.sign ~key:priv msg in
  assert (Crypto_ec.Ed25519.verify ~key:pub sig_ ~msg);
  (* Tampering the message invalidates the signature: *)
  assert (not (Crypto_ec.Ed25519.verify ~key:pub sig_ ~msg:"changed"))

X25519 key exchange#

let x25519_shared () =
  let a_priv, a_pub = Crypto_ec.X25519.gen_key () in
  let b_priv, b_pub = Crypto_ec.X25519.gen_key () in
  let a_shared = Crypto_ec.X25519.key_exchange a_priv b_pub in
  let b_shared = Crypto_ec.X25519.key_exchange b_priv a_pub in
  assert (a_shared = b_shared)

RSA#

let rsa_encrypt_decrypt () =
  let priv = Crypto_pk.Rsa.generate ~bits:2048 () in
  let pub = Crypto_pk.Rsa.pub_of_priv priv in
  let msg = "short message" in
  let ct = Crypto_pk.Rsa.PKCS1.encrypt ~key:pub msg in
  match Crypto_pk.Rsa.PKCS1.decrypt ~key:priv ct with
  | Some pt -> assert (pt = msg)
  | None -> failwith "decrypt failed"

Use Rsa.OAEP or Rsa.PSS for new designs; Rsa.PKCS1 is kept for compatibility with older protocols and is vulnerable to Bleichenbacher- style oracle attacks if error paths leak timing.

Modules#

Package Module Purpose
crypto Crypto.AES AES-128/192/256 in ECB/CBC/CTR/GCM/CCM
crypto Crypto.DES DES in ECB/CBC/CTR (legacy)
crypto Crypto.Chacha20 ChaCha20-Poly1305 AEAD
crypto Crypto.Poly1305 Raw Poly1305 MAC
crypto Crypto.ARC4 RC4 stream cipher (legacy)
crypto-rng Crypto_rng RNG interface, Fortuna, HMAC-DRBG
crypto-rng.unix Crypto_rng_unix OS entropy seeders (getrandom, BCrypt)
crypto-pk Crypto_pk.Rsa RSA keygen, PKCS1, OAEP, PSS
crypto-pk Crypto_pk.Dsa FIPS 186-4 DSA
crypto-pk Crypto_pk.Dh Finite-field Diffie-Hellman
crypto-ec Crypto_ec.P256 / P384 / P521 NIST curves (ECDH + ECDSA)
crypto-ec Crypto_ec.X25519 Curve25519 ECDH
crypto-ec Crypto_ec.Ed25519 Curve25519 EdDSA

Side-channel notes#

Inherited from upstream: RSA operations use blinding; AES operations delegate to AES-NI when available (Crypto.accelerated lists detected capabilities); P-256/P-384/P-521 point arithmetic uses constant-time code generated by fiat-crypto. This fork has not been re-audited; if a side-channel property matters to you, verify against upstream mirage-crypto and its review history.

Why this fork#

The fork exists so we can explore the design space without churning upstream. Two pieces of work that mirage-crypto does not ship today:

  1. A BearSSL-based constant-time AES fallback for platforms without AES-NI or equivalent hardware.
  2. Pure-OCaml AES and GHASH so AEAD works under js_of_ocaml with no C stubs.

The package-renaming and Lwt/Miou-removal is bookkeeping needed so the fork can live alongside upstream in the same opam switch while the above two pieces stabilise. Once they hold up under review and interop testing, the intent is to propose upstreaming them to mirage/mirage-crypto; if upstream agrees, this fork stops being a fork and the renamed packages get deprecated.

No primitive algorithms are modified. Anything this fork gets wrong is upstream's fault, and anything this fork gets right is upstream's credit -- apart from the two additions above, which are the point of the fork.

Licence#

ISC. See LICENSE.md for the original mirage-crypto notice and LICENSE.md.mirage-crypto-ec and LICENSE.md.mirage-crypto-rng-mirage for upstream-specific licence text.