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

Configure Feed

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

ocaml-linkedin: apply dune fmt

Pure formatting changes from `dune fmt`: doc comment placement moves
from above the binding to below it for `type`s, multi-line `match`
expressions collapse onto one line where they fit, and infix operator
applications pick up spaces (`Soup.($?)` -> `Soup.( $? )`). No
semantic changes.

+193 -26
+171 -26
README.md
··· 1 1 # crypto - Cryptographic primitives for OCaml 2 2 3 - > **Warning**: This is an experimental fork of [mirage-crypto](https://github.com/mirage/mirage-crypto). 4 - > Do not use in production. Use [mirage-crypto](https://github.com/mirage/mirage-crypto) instead. 3 + > **Warning.** This is a work-in-progress experimental fork of 4 + > [mirage-crypto](https://github.com/mirage/mirage-crypto). Do not use it 5 + > in production. As the experiments described under 6 + > [Why this fork](#why-this-fork) stabilise, the intent is to upstream 7 + > them back to `mirage/mirage-crypto` and retire the fork. Until that 8 + > happens, use `mirage-crypto` from opam directly for anything you care 9 + > about. 5 10 6 - This fork renames the packages and removes Lwt/Miou dependencies, keeping only 7 - Eio-compatible code. It is intended for experimentation only. 11 + ## What this fork adds 8 12 9 - ## Original mirage-crypto 13 + 1. **Vendored BearSSL constant-time AES.** `lib/c/bearssl/` imports the 14 + `aes_ct64` / `ghash_ctmul64` subset from 15 + [BearSSL](https://bearssl.org/). On architectures that have no 16 + hardware-accelerated AES, this is the fallback block implementation. 17 + The vendored files are auto-generated by `scripts/import.ml` so the 18 + import is reproducible against a pinned upstream commit. 19 + 2. **Pure-OCaml AES and GHASH backends.** `lib/ocaml/aes_pure.ml` is a 20 + bitsliced AES encryptor and `lib/ocaml/ghash_pure.ml` a constant-time 21 + GHASH over bitwise reduction. Both run under js_of_ocaml where no C 22 + compiler is available; upstream mirage-crypto requires C stubs. The 23 + OCaml GCM path glues these together so AEAD works in the browser. 24 + 3. **Packages renamed and Lwt/Miou bindings dropped.** Downstream 25 + Eio-based services that cannot pull in Lwt or Miou. Upstream leaks 26 + those into the dependency graph under some opam resolutions; this 27 + fork renames the packages so both can coexist in the same opam 28 + switch. 10 29 11 - mirage-crypto is a small cryptographic library that puts emphasis on the 12 - applicative style and ease of use. It includes basic ciphers (AES, 3DES, RC4, 13 - ChaCha20/Poly1305), AEAD primitives (AES-GCM, AES-CCM, ChaCha20/Poly1305), 14 - public-key primitives (RSA, DSA, DH), elliptic curves (NIST P-256, P-384, P-521, 15 - and curve 25519), and a strong RNG (Fortuna). 30 + The rest of the API mirrors the upstream modules with the packages 31 + renamed: 32 + 33 + | Upstream | This fork | 34 + |----------|-----------| 35 + | `mirage-crypto` | `crypto` | 36 + | `mirage-crypto-rng` | `crypto-rng` | 37 + | `mirage-crypto-rng.unix` | `crypto-rng.unix` | 38 + | `mirage-crypto-pk` | `crypto-pk` | 39 + | `mirage-crypto-ec` | `crypto-ec` | 16 40 17 - RSA timing attacks are countered by blinding. AES timing attacks are avoided by 18 - delegating to AES-NI. 41 + ## Installation 19 42 20 - Mirage-crypto is a fork of the 21 - [ocaml-nocrypto](https://github.com/mirleft/ocaml-nocrypto) written by David 22 - Kaloper. It was forked with the permission of the original author in order to 23 - facilitate changes (e.g. build system) required by Mirage that the upstream 24 - didn't have time to keep up with. 43 + <!-- $MDX skip --> 44 + ```sh 45 + $ opam install crypto crypto-rng crypto-pk crypto-ec 46 + ``` 25 47 26 - ## Build 48 + If opam cannot find the packages, they may not yet be released in the public 49 + `opam-repository`. Add the overlay repository, then install them: 27 50 28 - ```bash 29 - dune build 30 - dune runtest 51 + <!-- $MDX skip --> 52 + ```sh 53 + $ opam repo add samoht https://tangled.org/gazagnaire.org/opam-overlay.git 54 + $ opam update 55 + $ opam install crypto crypto-rng crypto-pk crypto-ec 31 56 ``` 32 57 33 - ## FAQ 58 + ## Usage 34 59 35 - #### RNG seeding 60 + ### Seed the RNG 36 61 37 - If RNG fails with `Fatal error: exception Unseeded_generator`, you need to 38 - seed it. 62 + Every key-generation or random-dependent operation fails with 63 + `Unseeded_generator` until a generator is installed. Call `use_default ()` 64 + once at program start: 39 65 40 - ```OCaml 66 + ```ocaml 41 67 let () = Crypto_rng_unix.use_default () 42 68 ``` 69 + 70 + On Linux this reads from `getrandom(2)`, on BSD/macOS from `getentropy(3)`, 71 + on Windows 10+ from `BCryptGenRandom`. Older Windows is unsupported. 72 + 73 + ### AEAD: AES-GCM and ChaCha20-Poly1305 74 + 75 + ```ocaml 76 + let aead_roundtrip () = 77 + let key = Crypto.AES.GCM.of_secret (Crypto_rng.generate 32) in 78 + let nonce = Crypto_rng.generate 12 in 79 + let adata = "headers" in 80 + let plaintext = "secret message" in 81 + let ciphertext = 82 + Crypto.AES.GCM.authenticate_encrypt ~key ~nonce ~adata plaintext 83 + in 84 + match 85 + Crypto.AES.GCM.authenticate_decrypt ~key ~nonce ~adata ciphertext 86 + with 87 + | Some recovered -> assert (recovered = plaintext) 88 + | None -> failwith "authentication failed" 89 + ``` 90 + 91 + `Crypto.Chacha20` and `Crypto.AES.CCM16` expose the same `AEAD` signature. 92 + Mismatched nonce/tag or tampered ciphertext return `None` -- never raise. 93 + 94 + ### Ed25519 signatures 95 + 96 + ```ocaml 97 + let sign_and_verify () = 98 + let priv, pub = Crypto_ec.Ed25519.generate () in 99 + let msg = "approved transfer of 42 units" in 100 + let sig_ = Crypto_ec.Ed25519.sign ~key:priv msg in 101 + assert (Crypto_ec.Ed25519.verify ~key:pub sig_ ~msg); 102 + (* Tampering the message invalidates the signature: *) 103 + assert (not (Crypto_ec.Ed25519.verify ~key:pub sig_ ~msg:"changed")) 104 + ``` 105 + 106 + ### X25519 key exchange 107 + 108 + ```ocaml 109 + let x25519_shared () = 110 + let a_priv, a_pub = Crypto_ec.X25519.gen_key () in 111 + let b_priv, b_pub = Crypto_ec.X25519.gen_key () in 112 + let a_shared = Crypto_ec.X25519.key_exchange a_priv b_pub in 113 + let b_shared = Crypto_ec.X25519.key_exchange b_priv a_pub in 114 + assert (a_shared = b_shared) 115 + ``` 116 + 117 + ### RSA 118 + 119 + ```ocaml 120 + let rsa_encrypt_decrypt () = 121 + let priv = Crypto_pk.Rsa.generate ~bits:2048 () in 122 + let pub = Crypto_pk.Rsa.pub_of_priv priv in 123 + let msg = "short message" in 124 + let ct = Crypto_pk.Rsa.PKCS1.encrypt ~key:pub msg in 125 + match Crypto_pk.Rsa.PKCS1.decrypt ~key:priv ct with 126 + | Some pt -> assert (pt = msg) 127 + | None -> failwith "decrypt failed" 128 + ``` 129 + 130 + Use `Rsa.OAEP` or `Rsa.PSS` for new designs; `Rsa.PKCS1` is kept for 131 + compatibility with older protocols and is vulnerable to Bleichenbacher- 132 + style oracle attacks if error paths leak timing. 133 + 134 + ## Modules 135 + 136 + | Package | Module | Purpose | 137 + |---------|--------|---------| 138 + | `crypto` | `Crypto.AES` | AES-128/192/256 in ECB/CBC/CTR/GCM/CCM | 139 + | `crypto` | `Crypto.DES` | DES in ECB/CBC/CTR (legacy) | 140 + | `crypto` | `Crypto.Chacha20` | ChaCha20-Poly1305 AEAD | 141 + | `crypto` | `Crypto.Poly1305` | Raw Poly1305 MAC | 142 + | `crypto` | `Crypto.ARC4` | RC4 stream cipher (legacy) | 143 + | `crypto-rng` | `Crypto_rng` | RNG interface, Fortuna, HMAC-DRBG | 144 + | `crypto-rng.unix` | `Crypto_rng_unix` | OS entropy seeders (getrandom, BCrypt) | 145 + | `crypto-pk` | `Crypto_pk.Rsa` | RSA keygen, PKCS1, OAEP, PSS | 146 + | `crypto-pk` | `Crypto_pk.Dsa` | FIPS 186-4 DSA | 147 + | `crypto-pk` | `Crypto_pk.Dh` | Finite-field Diffie-Hellman | 148 + | `crypto-ec` | `Crypto_ec.P256` / `P384` / `P521` | NIST curves (ECDH + ECDSA) | 149 + | `crypto-ec` | `Crypto_ec.X25519` | Curve25519 ECDH | 150 + | `crypto-ec` | `Crypto_ec.Ed25519` | Curve25519 EdDSA | 151 + 152 + ## Side-channel notes 153 + 154 + Inherited from upstream: RSA operations use blinding; AES operations 155 + delegate to AES-NI when available (`Crypto.accelerated` lists detected 156 + capabilities); P-256/P-384/P-521 point arithmetic uses constant-time code 157 + generated by fiat-crypto. This fork has **not** been re-audited; if a 158 + side-channel property matters to you, verify against upstream mirage-crypto 159 + and its review history. 160 + 161 + ## Why this fork 162 + 163 + The fork exists so we can explore the design space without churning 164 + upstream. Two pieces of work that `mirage-crypto` does not ship today: 165 + 166 + 1. A BearSSL-based constant-time AES fallback for platforms without 167 + AES-NI or equivalent hardware. 168 + 2. Pure-OCaml AES and GHASH so AEAD works under js_of_ocaml with no C 169 + stubs. 170 + 171 + The package-renaming and Lwt/Miou-removal is bookkeeping needed so the 172 + fork can live alongside upstream in the same opam switch while the above 173 + two pieces stabilise. Once they hold up under review and interop testing, 174 + the intent is to propose upstreaming them to `mirage/mirage-crypto`; if 175 + upstream agrees, this fork stops being a fork and the renamed packages 176 + get deprecated. 177 + 178 + No primitive algorithms are modified. Anything this fork gets wrong is 179 + upstream's fault, and anything this fork gets right is upstream's credit 180 + -- apart from the two additions above, which are the point of the fork. 181 + 182 + ## Licence 183 + 184 + ISC. See [LICENSE.md](LICENSE.md) for the original mirage-crypto notice and 185 + [LICENSE.md.mirage-crypto-ec](LICENSE.md.mirage-crypto-ec) and 186 + [LICENSE.md.mirage-crypto-rng-mirage](LICENSE.md.mirage-crypto-rng-mirage) 187 + for upstream-specific licence text.
+1
crypto-ec.opam
··· 21 21 "alcotest" {with-test & >= "0.8.1"} 22 22 "asn1-combinators" {with-test & >= "0.3.1"} 23 23 "ohex" {with-test & >= "0.2.0"} 24 + "mdx" {with-test} 24 25 "ounit2" {with-test} 25 26 "odoc" {with-doc} 26 27 ]
+1
crypto-pk.opam
··· 22 22 "crypto-rng" {= version} 23 23 "digestif" {>= "1.2.0"} 24 24 "zarith" {>= "1.13"} 25 + "mdx" {with-test} 25 26 "eqaf" {>= "0.8"} 26 27 "odoc" {with-doc} 27 28 ]
+1
crypto-rng.opam
··· 20 20 "digestif" {>= "1.1.4"} 21 21 "ounit2" {with-test} 22 22 "randomconv" {with-test & >= "0.2.0"} 23 + "mdx" {with-test} 23 24 "ohex" {with-test & >= "0.2.0"} 24 25 "odoc" {with-doc} 25 26 ]
+1
crypto.opam
··· 18 18 "fmt" 19 19 "ounit2" {with-test} 20 20 "ohex" {with-test & >= "0.2.0"} 21 + "mdx" {with-test} 21 22 "eqaf" {>= "0.8"} 22 23 "odoc" {with-doc} 23 24 ]
+4
dune
··· 1 1 (env 2 2 (dev 3 3 (flags :standard %{dune-warnings}))) 4 + 5 + (mdx 6 + (files README.md) 7 + (libraries crypto crypto.c crypto-ec crypto-pk crypto-rng crypto-rng.unix))
+5
dune-project
··· 1 1 (lang dune 3.21) 2 + (using mdx 0.4) 2 3 (name crypto) 3 4 (source (tangled gazagnaire.org/ocaml-crypto)) 4 5 (license ISC) ··· 22 23 fmt 23 24 (ounit2 :with-test) 24 25 (ohex (and :with-test (>= 0.2.0))) 26 + (mdx :with-test) 25 27 (eqaf (>= 0.8))) 26 28 (conflicts 27 29 ocaml-freestanding ··· 44 46 (crypto-rng (= :version)) 45 47 (digestif (>= 1.2.0)) 46 48 (zarith (>= 1.13)) 49 + (mdx :with-test) 47 50 (eqaf (>= 0.8))) 48 51 (conflicts ocaml-freestanding)) 49 52 ··· 62 65 (digestif (>= 1.1.4)) 63 66 (ounit2 :with-test) 64 67 (randomconv (and :with-test (>= 0.2.0))) 68 + (mdx :with-test) 65 69 (ohex (and :with-test (>= 0.2.0)))) 66 70 (conflicts (mirage-runtime (< 3.8.0)))) 67 71 ··· 81 85 (alcotest (and :with-test (>= 0.8.1))) 82 86 (asn1-combinators (and :with-test (>= 0.3.1))) 83 87 (ohex (and :with-test (>= 0.2.0))) 88 + (mdx :with-test) 84 89 (ounit2 :with-test)) 85 90 (conflicts ocaml-freestanding))
+6
ec/native/README.md
··· 16 16 ECDSA. The 64- and 32-bit tables must be respectively generated from a 64-bit or 17 17 32-bit build of `gen_tables`. 18 18 19 + <!-- $MDX non-deterministic=command --> 20 + ```sh 21 + $ make -C ec/native p256_64.h p384_64.h p521_64.h 22 + $ dune build @runtest 23 + ``` 24 + 19 25 # Code from BoringSSL 20 26 21 27 The code in "curve25519_tables.h", and large parts of
+3
ec/native/dune
··· 1 + (mdx 2 + (libraries crypto crypto.c crypto-ec crypto-pk crypto-rng crypto-rng.unix) 3 + (files README.md))