SPAKE2/SPAKE2+ password-authenticated key exchange for OCaml
OCaml 92.3%
Dune 2.6%
Other 5.1%
22 1 0

Clone this repository

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

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

Download tar.gz
README.md

spake2#

SPAKE2 and SPAKE2+ Password-Authenticated Key Exchange for OCaml.

Overview#

This library implements the SPAKE2 (RFC 9382) and SPAKE2+ protocols for password-authenticated key exchange. These protocols allow two parties who share a password to derive a strong shared secret key without revealing the password to eavesdroppers or allowing offline dictionary attacks.

  • SPAKE2: Both parties derive the same values from the password
  • SPAKE2+: Augmented PAKE where the server stores only a verifier, not password-equivalent data

Security Notice#

This implementation uses Zarith for P-256 elliptic curve arithmetic, which is not constant-time. This means the implementation has timing side-channel vulnerabilities. For high-security deployments, consider using hardware security modules or ensuring operations occur on trusted networks only.

Installation#

opam install spake2

Usage#

SPAKE2#

let password = "secret" in

(* Party A *)
let state_a, msg_a = Spake2.init ~password `A in
(* send msg_a to B, receive msg_b from B *)
let key_a = Spake2.finish ~context:"myapp" state_a msg_b in

(* Party B *)
let state_b, msg_b = Spake2.init ~password `B in
(* send msg_b to A, receive msg_a from A *)
let key_b = Spake2.finish ~context:"myapp" state_b msg_a in

(* key_a = key_b *)

SPAKE2+#

(* Setup: derive verifier data from password *)
let salt = Spake2.Plus.generate_salt () in
let iterations = 1000 in
let w0, w1 = Spake2.Plus.derive_w ~password ~salt ~iterations in
let l = Spake2.Plus.compute_l ~w1 in
(* Server stores: w0, l, salt, iterations (NOT the password or w1) *)

(* Protocol run *)
let context = "myapp" in
let prover_state, pa = Spake2.Plus.prover_init ~w0 ~w1 ~context in
let verifier_state, pb = Spake2.Plus.verifier_init ~w0 ~l ~context in

(* Exchange pa and pb *)
let Ok (ke_prover, ca, _) = Spake2.Plus.prover_finish prover_state pb in
let Ok (ke_verifier, cb, _) = Spake2.Plus.verifier_finish verifier_state pa in

(* ke_prover = ke_verifier *)
(* ca and cb can be exchanged for key confirmation *)

API#

SPAKE2#

  • Spake2.init ~password role - Initialize protocol for A or B
  • Spake2.finish ?context ?id_a ?id_b state peer_msg - Complete protocol

SPAKE2+#

  • Spake2.Plus.derive_w ~password ~salt ~iterations - Derive w0, w1 from password
  • Spake2.Plus.compute_l ~w1 - Compute L for server storage
  • Spake2.Plus.prover_init ~w0 ~w1 ~context - Initialize as prover (client)
  • Spake2.Plus.verifier_init ~w0 ~l ~context - Initialize as verifier (server)
  • Spake2.Plus.prover_finish state pb - Complete as prover
  • Spake2.Plus.verifier_finish state pa - Complete as verifier

P-256 Curve#

  • Spake2.P256.scalar_mult k p - Scalar multiplication
  • Spake2.P256.add p q - Point addition
  • Spake2.P256.to_bytes p - Encode point (SEC1 uncompressed)
  • Spake2.P256.of_bytes s - Decode and validate point

References#

Licence#

MIT License. See LICENSE.md for details.