SPAKE2/SPAKE2+ password-authenticated key exchange for OCaml
0
fork

Configure Feed

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

at main 121 lines 3.6 kB view raw view rendered
1# spake2 2 3SPAKE2 and SPAKE2+ Password-Authenticated Key Exchange for OCaml. 4 5## Overview 6 7This library implements the SPAKE2 (RFC 9382) and SPAKE2+ protocols for 8password-authenticated key exchange. These protocols allow two parties who 9share a password to derive a strong shared secret key without revealing the 10password to eavesdroppers or allowing offline dictionary attacks. 11 12- **SPAKE2**: Both parties derive the same values from the password 13- **SPAKE2+**: Augmented PAKE where the server stores only a verifier, not password-equivalent data 14 15## Security Notice 16 17This implementation uses mirage-crypto-ec for P-256 elliptic curve operations, 18which provides **constant-time** arithmetic via code generated by fiat-crypto. 19Scalar operations use Zarith but only for protocol-level math (not secret-dependent 20branching). The P-256 point operations are constant-time. 21 22## Installation 23 24Install with opam: 25 26<!-- $MDX skip --> 27```sh 28$ opam install spake2 29``` 30 31If opam cannot find the package, it may not yet be released in the public 32`opam-repository`. Add the overlay repository, then install it: 33 34<!-- $MDX skip --> 35```sh 36$ opam repo add samoht https://tangled.org/gazagnaire.org/opam-overlay.git 37$ opam update 38$ opam install spake2 39``` 40 41## Usage 42 43### SPAKE2 44 45```ocaml 46let () = Crypto_rng_unix.use_default () 47 48let password = "secret" 49 50(* Party A sends msg_a to B, receives msg_b from B. *) 51let state_a, msg_a = Spake2.init ~password `A 52 53(* Party B sends msg_b to A, receives msg_a from A. *) 54let state_b, msg_b = Spake2.init ~password `B 55 56let () = 57 match 58 ( Spake2.finish ~context:"myapp" state_a msg_b, 59 Spake2.finish ~context:"myapp" state_b msg_a ) 60 with 61 | Ok key_a, Ok key_b -> assert (String.equal key_a key_b) 62 | _ -> failwith "finish failed" 63``` 64 65### SPAKE2+ 66 67```ocaml 68let password = "secret" 69 70(* Setup: derive verifier data from password. *) 71let salt = Spake2.Plus.generate_salt () 72let iterations = 1000 73let w0, w1 = Spake2.Plus.derive_w ~password ~salt ~iterations 74let l = Spake2.Plus.compute_l ~w1 75 76(* Protocol run: exchange pa and pb between prover and verifier. *) 77let context = "myapp" 78let prover_state, pa = Spake2.Plus.prover_init ~w0 ~w1 ~context 79let verifier_state, pb = Spake2.Plus.verifier_init ~w0 ~l ~context 80 81let () = 82 match 83 ( Spake2.Plus.prover_finish prover_state pb, 84 Spake2.Plus.verifier_finish verifier_state pa ) 85 with 86 | Ok (ke_prover, _ca, _), Ok (ke_verifier, _cb, _) -> 87 assert (String.equal ke_prover ke_verifier) 88 | _ -> failwith "spake2+ exchange failed" 89``` 90 91## API 92 93### SPAKE2 94 95- `Spake2.init ~password role` - Initialize protocol for `A or `B 96- `Spake2.finish ?context ?id_a ?id_b state peer_msg` - Complete protocol 97 98### SPAKE2+ 99 100- `Spake2.Plus.derive_w ~password ~salt ~iterations` - Derive w0, w1 from password 101- `Spake2.Plus.compute_l ~w1` - Compute L for server storage 102- `Spake2.Plus.prover_init ~w0 ~w1 ~context` - Initialize as prover (client) 103- `Spake2.Plus.verifier_init ~w0 ~l ~context` - Initialize as verifier (server) 104- `Spake2.Plus.prover_finish state pb` - Complete as prover 105- `Spake2.Plus.verifier_finish state pa` - Complete as verifier 106 107### P-256 Curve 108 109- `Spake2.P256.add p q` - Point addition 110- `Spake2.P256.negate p` - Point negation 111- `Spake2.P256.to_bytes p` - Encode point (SEC1 uncompressed) 112- `Spake2.P256.of_bytes s` - Decode and validate point 113 114## References 115 116- [RFC 9382 - SPAKE2](https://www.rfc-editor.org/rfc/rfc9382.html) 117- [SPAKE2+ Draft](https://datatracker.ietf.org/doc/draft-bar-cfrg-spake2plus/) 118 119## Licence 120 121MIT License. See [LICENSE.md](LICENSE.md) for details.