This commit is contained in:
swrup 2025-11-11 02:07:51 +01:00
parent aa2ff7b2f0
commit 2f3113f55d
11742 changed files with 1223940 additions and 0 deletions

View file

@ -0,0 +1,5 @@
let rec until p f = let r = f () in if p r then r else until p f
let guard p err = if p then Ok () else Error err
let ( let* ) = Result.bind

View file

@ -0,0 +1,695 @@
open Mirage_crypto.Uncommon
open Common
exception Invalid_key
type group = {
p : Z.t ; (* The prime modulus *)
gg : Z.t ; (* Group generator *)
q : Z.t option ; (* `gg`'s order, maybe *)
}
let group ~p ~gg ?q () =
let* () =
guard (Z.(p > zero && is_odd p) && Z_extra.pseudoprime p)
(`Msg "invalid prime")
in
let* () =
guard Z.(one < gg && gg < p) (`Msg "invalid generator")
in
Ok { p ; gg ; q }
type secret = { group : group ; x : Z.t }
(*
* Estimates of equivalent-strength exponent sizes for the moduli sizes.
* 2048-8192 are taken from "Negotiated FF DHE Parameters for TLS."
* Sizes above and below are further guesswork.
*)
let exp_equivalent = [
(1024, 180); (2048, 225); (3072, 275); (4096, 325); (6144, 375); (8192, 400)
]
and exp_equivalent_max = 512
let exp_size bits =
try snd @@ List.find (fun (g, _) -> g >= bits) exp_equivalent
with Not_found -> exp_equivalent_max
let modulus_size { p; _ } = Z.numbits p
(*
* Current thinking:
* g^y < 0 || g^y >= p : obviously not computed mod p
* g^y = 0 || g^y = 1 : shared secret is 0, resp. 1
* g^y = p - 1 : order of g^y is 2
* g^y = g : y mod (p-1) is 1
*)
let bad_public_key { p; gg; _ } ggx =
ggx <= Z.one || ggx >= Z.(pred p) || ggx = gg
let valid_secret { p ; _ } s =
Z.(one < s && s < p)
let key_of_secret_z ({ p; gg; _ } as group) x =
if valid_secret group x then
match Z.(powm_sec gg x p) with
| ggx when bad_public_key group ggx -> raise_notrace Invalid_key
| ggx -> ({ group ; x }, Z_extra.to_octets_be ggx)
else
raise_notrace Invalid_key
let key_of_secret group ~s =
(* catches Invalid_private_key and re-raises with exception trace: *)
try key_of_secret_z group (Z_extra.of_octets_be s)
with Invalid_key -> raise Invalid_key
(* XXX
* - slightly weird distribution when bits > |q|
* - exponentiation time
*)
let rec gen_key ?g ?bits ({ p; q; _ } as group) =
let pb = Z.numbits p in
let s =
imin (Option.value bits ~default:pb |> exp_size)
(Option.fold ~none:pb ~some:Z.numbits q)
|> Z_extra.gen_bits ?g ~msb:1
in
try key_of_secret_z group s with Invalid_key -> gen_key ?g ?bits group
let shared { group ; x } cs =
match Z_extra.of_octets_be cs with
| ggy when bad_public_key group ggy -> None
| ggy -> Some (Z_extra.to_octets_be (Z.powm_sec ggy x group.p))
(* Finds a safe prime with [p = 2q + 1] and [2^q = 1 mod p]. *)
let rec gen_group ?g ~bits () =
let gg = Z.(~$2)
and (q, p) = Z_extra.safe_prime ?g (imax bits 1) in
if Z.(powm gg q p = one) then { p; gg; q = Some q } else gen_group ?g ~bits ()
module Group = struct
(* Safe-prime-style group: p = 2q + 1 && gg = 2 && gg^q = 1 mod p *)
let s_group ~p =
let p = Z_extra.of_octets_be p in
{ p ; gg = Z.(~$2) ; q = Some Z.(pred p / ~$2) }
(* Any old group. *)
let group ~p ~gg ~q =
let f = Z_extra.of_octets_be in
{ p = f p ; gg = f gg ; q = Some (f q) }
(* RFC2409 *)
let oakley_1 =
(* 2^768 - 2 ^704 - 1 + 2^64 * { [2^638 pi] + 149686 } *)
s_group ~p:
"\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xC9\x0F\xDA\xA2\x21\x68\xC2\x34\
\xC4\xC6\x62\x8B\x80\xDC\x1C\xD1\x29\x02\x4E\x08\x8A\x67\xCC\x74\
\x02\x0B\xBE\xA6\x3B\x13\x9B\x22\x51\x4A\x08\x79\x8E\x34\x04\xDD\
\xEF\x95\x19\xB3\xCD\x3A\x43\x1B\x30\x2B\x0A\x6D\xF2\x5F\x14\x37\
\x4F\xE1\x35\x6D\x6D\x51\xC2\x45\xE4\x85\xB5\x76\x62\x5E\x7E\xC6\
\xF4\x4C\x42\xE9\xA6\x3A\x36\x20\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
let oakley_2 =
(* 2^1024 - 2^960 - 1 + 2^64 * { [2^894 pi] + 129093 }. *)
s_group ~p:
"\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xC9\x0F\xDA\xA2\x21\x68\xC2\x34\
\xC4\xC6\x62\x8B\x80\xDC\x1C\xD1\x29\x02\x4E\x08\x8A\x67\xCC\x74\
\x02\x0B\xBE\xA6\x3B\x13\x9B\x22\x51\x4A\x08\x79\x8E\x34\x04\xDD\
\xEF\x95\x19\xB3\xCD\x3A\x43\x1B\x30\x2B\x0A\x6D\xF2\x5F\x14\x37\
\x4F\xE1\x35\x6D\x6D\x51\xC2\x45\xE4\x85\xB5\x76\x62\x5E\x7E\xC6\
\xF4\x4C\x42\xE9\xA6\x37\xED\x6B\x0B\xFF\x5C\xB6\xF4\x06\xB7\xED\
\xEE\x38\x6B\xFB\x5A\x89\x9F\xA5\xAE\x9F\x24\x11\x7C\x4B\x1F\xE6\
x49\x28\x66\x51\xEC\xE6\x53\x81\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
(* RFC3526 *)
let oakley_5 =
(* 2^1536 - 2^1472 - 1 + 2^64 * { [2^1406 pi] + 741804 } *)
s_group ~p:
"\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xC9\x0F\xDA\xA2\x21\x68\xC2\x34\
\xC4\xC6\x62\x8B\x80\xDC\x1C\xD1\x29\x02\x4E\x08\x8A\x67\xCC\x74\
\x02\x0B\xBE\xA6\x3B\x13\x9B\x22\x51\x4A\x08\x79\x8E\x34\x04\xDD\
\xEF\x95\x19\xB3\xCD\x3A\x43\x1B\x30\x2B\x0A\x6D\xF2\x5F\x14\x37\
\x4F\xE1\x35\x6D\x6D\x51\xC2\x45\xE4\x85\xB5\x76\x62\x5E\x7E\xC6\
\xF4\x4C\x42\xE9\xA6\x37\xED\x6B\x0B\xFF\x5C\xB6\xF4\x06\xB7\xED\
\xEE\x38\x6B\xFB\x5A\x89\x9F\xA5\xAE\x9F\x24\x11\x7C\x4B\x1F\xE6\
\x49\x28\x66\x51\xEC\xE4\x5B\x3D\xC2\x00\x7C\xB8\xA1\x63\xBF\x05\
\x98\xDA\x48\x36\x1C\x55\xD3\x9A\x69\x16\x3F\xA8\xFD\x24\xCF\x5F\
\x83\x65\x5D\x23\xDC\xA3\xAD\x96\x1C\x62\xF3\x56\x20\x85\x52\xBB\
\x9E\xD5\x29\x07\x70\x96\x96\x6D\x67\x0C\x35\x4E\x4A\xBC\x98\x04\
\xF1\x74\x6C\x08\xCA\x23\x73\x27\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
let oakley_14 =
(* 2^2048 - 2^1984 - 1 + 2^64 * { [2^1918 pi] + 124476 } *)
s_group ~p:
"\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xC9\x0F\xDA\xA2\x21\x68\xC2\x34\
\xC4\xC6\x62\x8B\x80\xDC\x1C\xD1\x29\x02\x4E\x08\x8A\x67\xCC\x74\
\x02\x0B\xBE\xA6\x3B\x13\x9B\x22\x51\x4A\x08\x79\x8E\x34\x04\xDD\
\xEF\x95\x19\xB3\xCD\x3A\x43\x1B\x30\x2B\x0A\x6D\xF2\x5F\x14\x37\
\x4F\xE1\x35\x6D\x6D\x51\xC2\x45\xE4\x85\xB5\x76\x62\x5E\x7E\xC6\
\xF4\x4C\x42\xE9\xA6\x37\xED\x6B\x0B\xFF\x5C\xB6\xF4\x06\xB7\xED\
\xEE\x38\x6B\xFB\x5A\x89\x9F\xA5\xAE\x9F\x24\x11\x7C\x4B\x1F\xE6\
\x49\x28\x66\x51\xEC\xE4\x5B\x3D\xC2\x00\x7C\xB8\xA1\x63\xBF\x05\
\x98\xDA\x48\x36\x1C\x55\xD3\x9A\x69\x16\x3F\xA8\xFD\x24\xCF\x5F\
\x83\x65\x5D\x23\xDC\xA3\xAD\x96\x1C\x62\xF3\x56\x20\x85\x52\xBB\
\x9E\xD5\x29\x07\x70\x96\x96\x6D\x67\x0C\x35\x4E\x4A\xBC\x98\x04\
\xF1\x74\x6C\x08\xCA\x18\x21\x7C\x32\x90\x5E\x46\x2E\x36\xCE\x3B\
\xE3\x9E\x77\x2C\x18\x0E\x86\x03\x9B\x27\x83\xA2\xEC\x07\xA2\x8F\
\xB5\xC5\x5D\xF0\x6F\x4C\x52\xC9\xDE\x2B\xCB\xF6\x95\x58\x17\x18\
\x39\x95\x49\x7C\xEA\x95\x6A\xE5\x15\xD2\x26\x18\x98\xFA\x05\x10\
\x15\x72\x8E\x5A\x8A\xAC\xAA\x68\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
let oakley_15 =
(* 2^3072 - 2^3008 - 1 + 2^64 * { [2^2942 pi] + 1690314 } *)
s_group ~p:
"\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xC9\x0F\xDA\xA2\x21\x68\xC2\x34\
\xC4\xC6\x62\x8B\x80\xDC\x1C\xD1\x29\x02\x4E\x08\x8A\x67\xCC\x74\
\x02\x0B\xBE\xA6\x3B\x13\x9B\x22\x51\x4A\x08\x79\x8E\x34\x04\xDD\
\xEF\x95\x19\xB3\xCD\x3A\x43\x1B\x30\x2B\x0A\x6D\xF2\x5F\x14\x37\
\x4F\xE1\x35\x6D\x6D\x51\xC2\x45\xE4\x85\xB5\x76\x62\x5E\x7E\xC6\
\xF4\x4C\x42\xE9\xA6\x37\xED\x6B\x0B\xFF\x5C\xB6\xF4\x06\xB7\xED\
\xEE\x38\x6B\xFB\x5A\x89\x9F\xA5\xAE\x9F\x24\x11\x7C\x4B\x1F\xE6\
\x49\x28\x66\x51\xEC\xE4\x5B\x3D\xC2\x00\x7C\xB8\xA1\x63\xBF\x05\
\x98\xDA\x48\x36\x1C\x55\xD3\x9A\x69\x16\x3F\xA8\xFD\x24\xCF\x5F\
\x83\x65\x5D\x23\xDC\xA3\xAD\x96\x1C\x62\xF3\x56\x20\x85\x52\xBB\
\x9E\xD5\x29\x07\x70\x96\x96\x6D\x67\x0C\x35\x4E\x4A\xBC\x98\x04\
\xF1\x74\x6C\x08\xCA\x18\x21\x7C\x32\x90\x5E\x46\x2E\x36\xCE\x3B\
\xE3\x9E\x77\x2C\x18\x0E\x86\x03\x9B\x27\x83\xA2\xEC\x07\xA2\x8F\
\xB5\xC5\x5D\xF0\x6F\x4C\x52\xC9\xDE\x2B\xCB\xF6\x95\x58\x17\x18\
\x39\x95\x49\x7C\xEA\x95\x6A\xE5\x15\xD2\x26\x18\x98\xFA\x05\x10\
\x15\x72\x8E\x5A\x8A\xAA\xC4\x2D\xAD\x33\x17\x0D\x04\x50\x7A\x33\
\xA8\x55\x21\xAB\xDF\x1C\xBA\x64\xEC\xFB\x85\x04\x58\xDB\xEF\x0A\
\x8A\xEA\x71\x57\x5D\x06\x0C\x7D\xB3\x97\x0F\x85\xA6\xE1\xE4\xC7\
\xAB\xF5\xAE\x8C\xDB\x09\x33\xD7\x1E\x8C\x94\xE0\x4A\x25\x61\x9D\
\xCE\xE3\xD2\x26\x1A\xD2\xEE\x6B\xF1\x2F\xFA\x06\xD9\x8A\x08\x64\
\xD8\x76\x02\x73\x3E\xC8\x6A\x64\x52\x1F\x2B\x18\x17\x7B\x20\x0C\
\xBB\xE1\x17\x57\x7A\x61\x5D\x6C\x77\x09\x88\xC0\xBA\xD9\x46\xE2\
\x08\xE2\x4F\xA0\x74\xE5\xAB\x31\x43\xDB\x5B\xFC\xE0\xFD\x10\x8E\
\x4B\x82\xD1\x20\xA9\x3A\xD2\xCA\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
let oakley_16 =
(* 2^4096 - 2^4032 - 1 + 2^64 * { [2^3966 pi] + 240904 } *)
s_group ~p:
"\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xC9\x0F\xDA\xA2\x21\x68\xC2\x34\
\xC4\xC6\x62\x8B\x80\xDC\x1C\xD1\x29\x02\x4E\x08\x8A\x67\xCC\x74\
\x02\x0B\xBE\xA6\x3B\x13\x9B\x22\x51\x4A\x08\x79\x8E\x34\x04\xDD\
\xEF\x95\x19\xB3\xCD\x3A\x43\x1B\x30\x2B\x0A\x6D\xF2\x5F\x14\x37\
\x4F\xE1\x35\x6D\x6D\x51\xC2\x45\xE4\x85\xB5\x76\x62\x5E\x7E\xC6\
\xF4\x4C\x42\xE9\xA6\x37\xED\x6B\x0B\xFF\x5C\xB6\xF4\x06\xB7\xED\
\xEE\x38\x6B\xFB\x5A\x89\x9F\xA5\xAE\x9F\x24\x11\x7C\x4B\x1F\xE6\
\x49\x28\x66\x51\xEC\xE4\x5B\x3D\xC2\x00\x7C\xB8\xA1\x63\xBF\x05\
\x98\xDA\x48\x36\x1C\x55\xD3\x9A\x69\x16\x3F\xA8\xFD\x24\xCF\x5F\
\x83\x65\x5D\x23\xDC\xA3\xAD\x96\x1C\x62\xF3\x56\x20\x85\x52\xBB\
\x9E\xD5\x29\x07\x70\x96\x96\x6D\x67\x0C\x35\x4E\x4A\xBC\x98\x04\
\xF1\x74\x6C\x08\xCA\x18\x21\x7C\x32\x90\x5E\x46\x2E\x36\xCE\x3B\
\xE3\x9E\x77\x2C\x18\x0E\x86\x03\x9B\x27\x83\xA2\xEC\x07\xA2\x8F\
\xB5\xC5\x5D\xF0\x6F\x4C\x52\xC9\xDE\x2B\xCB\xF6\x95\x58\x17\x18\
\x39\x95\x49\x7C\xEA\x95\x6A\xE5\x15\xD2\x26\x18\x98\xFA\x05\x10\
\x15\x72\x8E\x5A\x8A\xAA\xC4\x2D\xAD\x33\x17\x0D\x04\x50\x7A\x33\
\xA8\x55\x21\xAB\xDF\x1C\xBA\x64\xEC\xFB\x85\x04\x58\xDB\xEF\x0A\
\x8A\xEA\x71\x57\x5D\x06\x0C\x7D\xB3\x97\x0F\x85\xA6\xE1\xE4\xC7\
\xAB\xF5\xAE\x8C\xDB\x09\x33\xD7\x1E\x8C\x94\xE0\x4A\x25\x61\x9D\
\xCE\xE3\xD2\x26\x1A\xD2\xEE\x6B\xF1\x2F\xFA\x06\xD9\x8A\x08\x64\
\xD8\x76\x02\x73\x3E\xC8\x6A\x64\x52\x1F\x2B\x18\x17\x7B\x20\x0C\
\xBB\xE1\x17\x57\x7A\x61\x5D\x6C\x77\x09\x88\xC0\xBA\xD9\x46\xE2\
\x08\xE2\x4F\xA0\x74\xE5\xAB\x31\x43\xDB\x5B\xFC\xE0\xFD\x10\x8E\
\x4B\x82\xD1\x20\xA9\x21\x08\x01\x1A\x72\x3C\x12\xA7\x87\xE6\xD7\
\x88\x71\x9A\x10\xBD\xBA\x5B\x26\x99\xC3\x27\x18\x6A\xF4\xE2\x3C\
\x1A\x94\x68\x34\xB6\x15\x0B\xDA\x25\x83\xE9\xCA\x2A\xD4\x4C\xE8\
\xDB\xBB\xC2\xDB\x04\xDE\x8E\xF9\x2E\x8E\xFC\x14\x1F\xBE\xCA\xA6\
\x28\x7C\x59\x47\x4E\x6B\xC0\x5D\x99\xB2\x96\x4F\xA0\x90\xC3\xA2\
\x23\x3B\xA1\x86\x51\x5B\xE7\xED\x1F\x61\x29\x70\xCE\xE2\xD7\xAF\
\xB8\x1B\xDD\x76\x21\x70\x48\x1C\xD0\x06\x91\x27\xD5\xB0\x5A\xA9\
\x93\xB4\xEA\x98\x8D\x8F\xDD\xC1\x86\xFF\xB7\xDC\x90\xA6\xC0\x8F\
\x4D\xF4\x35\xC9\x34\x06\x31\x99\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
let oakley_17 =
(* 2^6144 - 2^6080 - 1 + 2^64 * { [2^6014 pi] + 929484 } *)
s_group ~p:
"\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xC9\x0F\xDA\xA2\x21\x68\xC2\x34\
\xC4\xC6\x62\x8B\x80\xDC\x1C\xD1\x29\x02\x4E\x08\x8A\x67\xCC\x74\
\x02\x0B\xBE\xA6\x3B\x13\x9B\x22\x51\x4A\x08\x79\x8E\x34\x04\xDD\
\xEF\x95\x19\xB3\xCD\x3A\x43\x1B\x30\x2B\x0A\x6D\xF2\x5F\x14\x37\
\x4F\xE1\x35\x6D\x6D\x51\xC2\x45\xE4\x85\xB5\x76\x62\x5E\x7E\xC6\
\xF4\x4C\x42\xE9\xA6\x37\xED\x6B\x0B\xFF\x5C\xB6\xF4\x06\xB7\xED\
\xEE\x38\x6B\xFB\x5A\x89\x9F\xA5\xAE\x9F\x24\x11\x7C\x4B\x1F\xE6\
\x49\x28\x66\x51\xEC\xE4\x5B\x3D\xC2\x00\x7C\xB8\xA1\x63\xBF\x05\
\x98\xDA\x48\x36\x1C\x55\xD3\x9A\x69\x16\x3F\xA8\xFD\x24\xCF\x5F\
\x83\x65\x5D\x23\xDC\xA3\xAD\x96\x1C\x62\xF3\x56\x20\x85\x52\xBB\
\x9E\xD5\x29\x07\x70\x96\x96\x6D\x67\x0C\x35\x4E\x4A\xBC\x98\x04\
\xF1\x74\x6C\x08\xCA\x18\x21\x7C\x32\x90\x5E\x46\x2E\x36\xCE\x3B\
\xE3\x9E\x77\x2C\x18\x0E\x86\x03\x9B\x27\x83\xA2\xEC\x07\xA2\x8F\
\xB5\xC5\x5D\xF0\x6F\x4C\x52\xC9\xDE\x2B\xCB\xF6\x95\x58\x17\x18\
\x39\x95\x49\x7C\xEA\x95\x6A\xE5\x15\xD2\x26\x18\x98\xFA\x05\x10\
\x15\x72\x8E\x5A\x8A\xAA\xC4\x2D\xAD\x33\x17\x0D\x04\x50\x7A\x33\
\xA8\x55\x21\xAB\xDF\x1C\xBA\x64\xEC\xFB\x85\x04\x58\xDB\xEF\x0A\
\x8A\xEA\x71\x57\x5D\x06\x0C\x7D\xB3\x97\x0F\x85\xA6\xE1\xE4\xC7\
\xAB\xF5\xAE\x8C\xDB\x09\x33\xD7\x1E\x8C\x94\xE0\x4A\x25\x61\x9D\
\xCE\xE3\xD2\x26\x1A\xD2\xEE\x6B\xF1\x2F\xFA\x06\xD9\x8A\x08\x64\
\xD8\x76\x02\x73\x3E\xC8\x6A\x64\x52\x1F\x2B\x18\x17\x7B\x20\x0C\
\xBB\xE1\x17\x57\x7A\x61\x5D\x6C\x77\x09\x88\xC0\xBA\xD9\x46\xE2\
\x08\xE2\x4F\xA0\x74\xE5\xAB\x31\x43\xDB\x5B\xFC\xE0\xFD\x10\x8E\
\x4B\x82\xD1\x20\xA9\x21\x08\x01\x1A\x72\x3C\x12\xA7\x87\xE6\xD7\
\x88\x71\x9A\x10\xBD\xBA\x5B\x26\x99\xC3\x27\x18\x6A\xF4\xE2\x3C\
\x1A\x94\x68\x34\xB6\x15\x0B\xDA\x25\x83\xE9\xCA\x2A\xD4\x4C\xE8\
\xDB\xBB\xC2\xDB\x04\xDE\x8E\xF9\x2E\x8E\xFC\x14\x1F\xBE\xCA\xA6\
\x28\x7C\x59\x47\x4E\x6B\xC0\x5D\x99\xB2\x96\x4F\xA0\x90\xC3\xA2\
\x23\x3B\xA1\x86\x51\x5B\xE7\xED\x1F\x61\x29\x70\xCE\xE2\xD7\xAF\
\xB8\x1B\xDD\x76\x21\x70\x48\x1C\xD0\x06\x91\x27\xD5\xB0\x5A\xA9\
\x93\xB4\xEA\x98\x8D\x8F\xDD\xC1\x86\xFF\xB7\xDC\x90\xA6\xC0\x8F\
\x4D\xF4\x35\xC9\x34\x02\x84\x92\x36\xC3\xFA\xB4\xD2\x7C\x70\x26\
\xC1\xD4\xDC\xB2\x60\x26\x46\xDE\xC9\x75\x1E\x76\x3D\xBA\x37\xBD\
\xF8\xFF\x94\x06\xAD\x9E\x53\x0E\xE5\xDB\x38\x2F\x41\x30\x01\xAE\
\xB0\x6A\x53\xED\x90\x27\xD8\x31\x17\x97\x27\xB0\x86\x5A\x89\x18\
\xDA\x3E\xDB\xEB\xCF\x9B\x14\xED\x44\xCE\x6C\xBA\xCE\xD4\xBB\x1B\
\xDB\x7F\x14\x47\xE6\xCC\x25\x4B\x33\x20\x51\x51\x2B\xD7\xAF\x42\
\x6F\xB8\xF4\x01\x37\x8C\xD2\xBF\x59\x83\xCA\x01\xC6\x4B\x92\xEC\
\xF0\x32\xEA\x15\xD1\x72\x1D\x03\xF4\x82\xD7\xCE\x6E\x74\xFE\xF6\
\xD5\x5E\x70\x2F\x46\x98\x0C\x82\xB5\xA8\x40\x31\x90\x0B\x1C\x9E\
\x59\xE7\xC9\x7F\xBE\xC7\xE8\xF3\x23\xA9\x7A\x7E\x36\xCC\x88\xBE\
\x0F\x1D\x45\xB7\xFF\x58\x5A\xC5\x4B\xD4\x07\xB2\x2B\x41\x54\xAA\
\xCC\x8F\x6D\x7E\xBF\x48\xE1\xD8\x14\xCC\x5E\xD2\x0F\x80\x37\xE0\
\xA7\x97\x15\xEE\xF2\x9B\xE3\x28\x06\xA1\xD5\x8B\xB7\xC5\xDA\x76\
\xF5\x50\xAA\x3D\x8A\x1F\xBF\xF0\xEB\x19\xCC\xB1\xA3\x13\xD5\x5C\
\xDA\x56\xC9\xEC\x2E\xF2\x96\x32\x38\x7F\xE8\xD7\x6E\x3C\x04\x68\
\x04\x3E\x8F\x66\x3F\x48\x60\xEE\x12\xBF\x2D\x5B\x0B\x74\x74\xD6\
\xE6\x94\xF9\x1E\x6D\xCC\x40\x24\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
let oakley_18 =
(* 2^8192 - 2^8128 - 1 + 2^64 * { [2^8062 pi] + 4743158 } *)
s_group ~p:
"\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xC9\x0F\xDA\xA2\x21\x68\xC2\x34\
\xC4\xC6\x62\x8B\x80\xDC\x1C\xD1\x29\x02\x4E\x08\x8A\x67\xCC\x74\
\x02\x0B\xBE\xA6\x3B\x13\x9B\x22\x51\x4A\x08\x79\x8E\x34\x04\xDD\
\xEF\x95\x19\xB3\xCD\x3A\x43\x1B\x30\x2B\x0A\x6D\xF2\x5F\x14\x37\
\x4F\xE1\x35\x6D\x6D\x51\xC2\x45\xE4\x85\xB5\x76\x62\x5E\x7E\xC6\
\xF4\x4C\x42\xE9\xA6\x37\xED\x6B\x0B\xFF\x5C\xB6\xF4\x06\xB7\xED\
\xEE\x38\x6B\xFB\x5A\x89\x9F\xA5\xAE\x9F\x24\x11\x7C\x4B\x1F\xE6\
\x49\x28\x66\x51\xEC\xE4\x5B\x3D\xC2\x00\x7C\xB8\xA1\x63\xBF\x05\
\x98\xDA\x48\x36\x1C\x55\xD3\x9A\x69\x16\x3F\xA8\xFD\x24\xCF\x5F\
\x83\x65\x5D\x23\xDC\xA3\xAD\x96\x1C\x62\xF3\x56\x20\x85\x52\xBB\
\x9E\xD5\x29\x07\x70\x96\x96\x6D\x67\x0C\x35\x4E\x4A\xBC\x98\x04\
\xF1\x74\x6C\x08\xCA\x18\x21\x7C\x32\x90\x5E\x46\x2E\x36\xCE\x3B\
\xE3\x9E\x77\x2C\x18\x0E\x86\x03\x9B\x27\x83\xA2\xEC\x07\xA2\x8F\
\xB5\xC5\x5D\xF0\x6F\x4C\x52\xC9\xDE\x2B\xCB\xF6\x95\x58\x17\x18\
\x39\x95\x49\x7C\xEA\x95\x6A\xE5\x15\xD2\x26\x18\x98\xFA\x05\x10\
\x15\x72\x8E\x5A\x8A\xAA\xC4\x2D\xAD\x33\x17\x0D\x04\x50\x7A\x33\
\xA8\x55\x21\xAB\xDF\x1C\xBA\x64\xEC\xFB\x85\x04\x58\xDB\xEF\x0A\
\x8A\xEA\x71\x57\x5D\x06\x0C\x7D\xB3\x97\x0F\x85\xA6\xE1\xE4\xC7\
\xAB\xF5\xAE\x8C\xDB\x09\x33\xD7\x1E\x8C\x94\xE0\x4A\x25\x61\x9D\
\xCE\xE3\xD2\x26\x1A\xD2\xEE\x6B\xF1\x2F\xFA\x06\xD9\x8A\x08\x64\
\xD8\x76\x02\x73\x3E\xC8\x6A\x64\x52\x1F\x2B\x18\x17\x7B\x20\x0C\
\xBB\xE1\x17\x57\x7A\x61\x5D\x6C\x77\x09\x88\xC0\xBA\xD9\x46\xE2\
\x08\xE2\x4F\xA0\x74\xE5\xAB\x31\x43\xDB\x5B\xFC\xE0\xFD\x10\x8E\
\x4B\x82\xD1\x20\xA9\x21\x08\x01\x1A\x72\x3C\x12\xA7\x87\xE6\xD7\
\x88\x71\x9A\x10\xBD\xBA\x5B\x26\x99\xC3\x27\x18\x6A\xF4\xE2\x3C\
\x1A\x94\x68\x34\xB6\x15\x0B\xDA\x25\x83\xE9\xCA\x2A\xD4\x4C\xE8\
\xDB\xBB\xC2\xDB\x04\xDE\x8E\xF9\x2E\x8E\xFC\x14\x1F\xBE\xCA\xA6\
\x28\x7C\x59\x47\x4E\x6B\xC0\x5D\x99\xB2\x96\x4F\xA0\x90\xC3\xA2\
\x23\x3B\xA1\x86\x51\x5B\xE7\xED\x1F\x61\x29\x70\xCE\xE2\xD7\xAF\
\xB8\x1B\xDD\x76\x21\x70\x48\x1C\xD0\x06\x91\x27\xD5\xB0\x5A\xA9\
\x93\xB4\xEA\x98\x8D\x8F\xDD\xC1\x86\xFF\xB7\xDC\x90\xA6\xC0\x8F\
\x4D\xF4\x35\xC9\x34\x02\x84\x92\x36\xC3\xFA\xB4\xD2\x7C\x70\x26\
\xC1\xD4\xDC\xB2\x60\x26\x46\xDE\xC9\x75\x1E\x76\x3D\xBA\x37\xBD\
\xF8\xFF\x94\x06\xAD\x9E\x53\x0E\xE5\xDB\x38\x2F\x41\x30\x01\xAE\
\xB0\x6A\x53\xED\x90\x27\xD8\x31\x17\x97\x27\xB0\x86\x5A\x89\x18\
\xDA\x3E\xDB\xEB\xCF\x9B\x14\xED\x44\xCE\x6C\xBA\xCE\xD4\xBB\x1B\
\xDB\x7F\x14\x47\xE6\xCC\x25\x4B\x33\x20\x51\x51\x2B\xD7\xAF\x42\
\x6F\xB8\xF4\x01\x37\x8C\xD2\xBF\x59\x83\xCA\x01\xC6\x4B\x92\xEC\
\xF0\x32\xEA\x15\xD1\x72\x1D\x03\xF4\x82\xD7\xCE\x6E\x74\xFE\xF6\
\xD5\x5E\x70\x2F\x46\x98\x0C\x82\xB5\xA8\x40\x31\x90\x0B\x1C\x9E\
\x59\xE7\xC9\x7F\xBE\xC7\xE8\xF3\x23\xA9\x7A\x7E\x36\xCC\x88\xBE\
\x0F\x1D\x45\xB7\xFF\x58\x5A\xC5\x4B\xD4\x07\xB2\x2B\x41\x54\xAA\
\xCC\x8F\x6D\x7E\xBF\x48\xE1\xD8\x14\xCC\x5E\xD2\x0F\x80\x37\xE0\
\xA7\x97\x15\xEE\xF2\x9B\xE3\x28\x06\xA1\xD5\x8B\xB7\xC5\xDA\x76\
\xF5\x50\xAA\x3D\x8A\x1F\xBF\xF0\xEB\x19\xCC\xB1\xA3\x13\xD5\x5C\
\xDA\x56\xC9\xEC\x2E\xF2\x96\x32\x38\x7F\xE8\xD7\x6E\x3C\x04\x68\
\x04\x3E\x8F\x66\x3F\x48\x60\xEE\x12\xBF\x2D\x5B\x0B\x74\x74\xD6\
\xE6\x94\xF9\x1E\x6D\xBE\x11\x59\x74\xA3\x92\x6F\x12\xFE\xE5\xE4\
\x38\x77\x7C\xB6\xA9\x32\xDF\x8C\xD8\xBE\xC4\xD0\x73\xB9\x31\xBA\
\x3B\xC8\x32\xB6\x8D\x9D\xD3\x00\x74\x1F\xA7\xBF\x8A\xFC\x47\xED\
\x25\x76\xF6\x93\x6B\xA4\x24\x66\x3A\xAB\x63\x9C\x5A\xE4\xF5\x68\
\x34\x23\xB4\x74\x2B\xF1\xC9\x78\x23\x8F\x16\xCB\xE3\x9D\x65\x2D\
\xE3\xFD\xB8\xBE\xFC\x84\x8A\xD9\x22\x22\x2E\x04\xA4\x03\x7C\x07\
\x13\xEB\x57\xA8\x1A\x23\xF0\xC7\x34\x73\xFC\x64\x6C\xEA\x30\x6B\
\x4B\xCB\xC8\x86\x2F\x83\x85\xDD\xFA\x9D\x4B\x7F\xA2\xC0\x87\xE8\
\x79\x68\x33\x03\xED\x5B\xDD\x3A\x06\x2B\x3C\xF5\xB3\xA2\x78\xA6\
\x6D\x2A\x13\xF8\x3F\x44\xF8\x2D\xDF\x31\x0E\xE0\x74\xAB\x6A\x36\
\x45\x97\xE8\x99\xA0\x25\x5D\xC1\x64\xF3\x1C\xC5\x08\x46\x85\x1D\
\xF9\xAB\x48\x19\x5D\xED\x7E\xA1\xB1\xD5\x10\xBD\x7E\xE7\x4D\x73\
\xFA\xF3\x6B\xC3\x1E\xCF\xA2\x68\x35\x90\x46\xF4\xEB\x87\x9F\x92\
\x40\x09\x43\x8B\x48\x1C\x6C\xD7\x88\x9A\x00\x2E\xD5\xEE\x38\x2B\
\xC9\x19\x0D\xA6\xFC\x02\x6E\x47\x95\x58\xE4\x47\x56\x77\xE9\xAA\
\x9E\x30\x50\xE2\x76\x56\x94\xDF\xC8\x1F\x56\xE8\x80\xB9\x6E\x71\
\x60\xC9\x80\xDD\x98\xED\xD3\xDF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
(* RFC5114 *)
(* 1024-bit, 160-bit subgroup *)
let rfc_5114_1 =
let p =
"\xB1\x0B\x8F\x96\xA0\x80\xE0\x1D\xDE\x92\xDE\x5E\xAE\x5D\x54\xEC\
\x52\xC9\x9F\xBC\xFB\x06\xA3\xC6\x9A\x6A\x9D\xCA\x52\xD2\x3B\x61\
\x60\x73\xE2\x86\x75\xA2\x3D\x18\x98\x38\xEF\x1E\x2E\xE6\x52\xC0\
\x13\xEC\xB4\xAE\xA9\x06\x11\x23\x24\x97\x5C\x3C\xD4\x9B\x83\xBF\
\xAC\xCB\xDD\x7D\x90\xC4\xBD\x70\x98\x48\x8E\x9C\x21\x9A\x73\x72\
\x4E\xFF\xD6\xFA\xE5\x64\x47\x38\xFA\xA3\x1A\x4F\xF5\x5B\xCC\xC0\
\xA1\x51\xAF\x5F\x0D\xC8\xB4\xBD\x45\xBF\x37\xDF\x36\x5C\x1A\x65\
\xE6\x8C\xFD\xA7\x6D\x4D\xA7\x08\xDF\x1F\xB2\xBC\x2E\x4A\x43\x71"
and gg =
"\xA4\xD1\xCB\xD5\xC3\xFD\x34\x12\x67\x65\xA4\x42\xEF\xB9\x99\x05\
\xF8\x10\x4D\xD2\x58\xAC\x50\x7F\xD6\x40\x6C\xFF\x14\x26\x6D\x31\
\x26\x6F\xEA\x1E\x5C\x41\x56\x4B\x77\x7E\x69\x0F\x55\x04\xF2\x13\
\x16\x02\x17\xB4\xB0\x1B\x88\x6A\x5E\x91\x54\x7F\x9E\x27\x49\xF4\
\xD7\xFB\xD7\xD3\xB9\xA9\x2E\xE1\x90\x9D\x0D\x22\x63\xF8\x0A\x76\
\xA6\xA2\x4C\x08\x7A\x09\x1F\x53\x1D\xBF\x0A\x01\x69\xB6\xA2\x8A\
\xD6\x62\xA4\xD1\x8E\x73\xAF\xA3\x2D\x77\x9D\x59\x18\xD0\x8B\xC8\
\x85\x8F\x4D\xCE\xF9\x7C\x2A\x24\\x85\x5E\x6E\xEB\x22\xB3\xB2\xE5"
and q =
"\xF5\x18\xAA\x87\x81\xA8\xDF\x27\x8A\xBA\x4E\x7D\x64\xB7\xCB\x9D\
\x49\x46\x23\x53"
in
group ~p ~gg ~q
(* 2048-bit, 224-bit subgroup *)
let rfc_5114_2 =
let p =
"\xAD\x10\x7E\x1E\x91\x23\xA9\xD0\xD6\x60\xFA\xA7\x95\x59\xC5\x1F\
\xA2\x0D\x64\xE5\x68\x3B\x9F\xD1\xB5\x4B\x15\x97\xB6\x1D\x0A\x75\
\xE6\xFA\x14\x1D\xF9\x5A\x56\xDB\xAF\x9A\x3C\x40\x7B\xA1\xDF\x15\
\xEB\x3D\x68\x8A\x30\x9C\x18\x0E\x1D\xE6\xB8\x5A\x12\x74\xA0\xA6\
\x6D\x3F\x81\x52\xAD\x6A\xC2\x12\x90\x37\xC9\xED\xEF\xDA\x4D\xF8\
\xD9\x1E\x8F\xEF\x55\xB7\x39\x4B\x7A\xD5\xB7\xD0\xB6\xC1\x22\x07\
\xC9\xF9\x8D\x11\xED\x34\xDB\xF6\xC6\xBA\x0B\x2C\x8B\xBC\x27\xBE\
\x6A\x00\xE0\xA0\xB9\xC4\x97\x08\xB3\xBF\x8A\x31\x70\x91\x88\x36\
\x81\x28\x61\x30\xBC\x89\x85\xDB\x16\x02\xE7\x14\x41\x5D\x93\x30\
\x27\x82\x73\xC7\xDE\x31\xEF\xDC\x73\x10\xF7\x12\x1F\xD5\xA0\x74\
\x15\x98\x7D\x9A\xDC\x0A\x48\x6D\xCD\xF9\x3A\xCC\x44\x32\x83\x87\
\x31\x5D\x75\xE1\x98\xC6\x41\xA4\x80\xCD\x86\xA1\xB9\xE5\x87\xE8\
\xBE\x60\xE6\x9C\xC9\x28\xB2\xB9\xC5\x21\x72\xE4\x13\x04\x2E\x9B\
\x23\xF1\x0B\x0E\x16\xE7\x97\x63\xC9\xB5\x3D\xCF\x4B\xA8\x0A\x29\
\xE3\xFB\x73\xC1\x6B\x8E\x75\xB9\x7E\xF3\x63\xE2\xFF\xA3\x1F\x71\
\xCF\x9D\xE5\x38\x4E\x71\xB8\x1C\x0A\xC4\xDF\xFE\x0C\x10\xE6\x4F"
and gg =
"\xAC\x40\x32\xEF\x4F\x2D\x9A\xE3\x9D\xF3\x0B\x5C\x8F\xFD\xAC\x50\
\x6C\xDE\xBE\x7B\x89\x99\x8C\xAF\x74\x86\x6A\x08\xCF\xE4\xFF\xE3\
\xA6\x82\x4A\x4E\x10\xB9\xA6\xF0\xDD\x92\x1F\x01\xA7\x0C\x4A\xFA\
\xAB\x73\x9D\x77\x00\xC2\x9F\x52\xC5\x7D\xB1\x7C\x62\x0A\x86\x52\
\xBE\x5E\x90\x01\xA8\xD6\x6A\xD7\xC1\x76\x69\x10\x19\x99\x02\x4A\
\xF4\xD0\x27\x27\x5A\xC1\x34\x8B\xB8\xA7\x62\xD0\x52\x1B\xC9\x8A\
\xE2\x47\x15\x04\x22\xEA\x1E\xD4\x09\x93\x9D\x54\xDA\x74\x60\xCD\
\xB5\xF6\xC6\xB2\x50\x71\x7C\xBE\xF1\x80\xEB\x34\x11\x8E\x98\xD1\
\x19\x52\x9A\x45\xD6\xF8\x34\x56\x6E\x30\x25\xE3\x16\xA3\x30\xEF\
\xBB\x77\xA8\x6F\x0C\x1A\xB1\x5B\x05\x1A\xE3\xD4\x28\xC8\xF8\xAC\
\xB7\x0A\x81\x37\x15\x0B\x8E\xEB\x10\xE1\x83\xED\xD1\x99\x63\xDD\
\xD9\xE2\x63\xE4\x77\x05\x89\xEF\x6A\xA2\x1E\x7F\x5F\x2F\xF3\x81\
\xB5\x39\xCC\xE3\x40\x9D\x13\xCD\x56\x6A\xFB\xB4\x8D\x6C\x01\x91\
\x81\xE1\xBC\xFE\x94\xB3\x02\x69\xED\xFE\x72\xFE\x9B\x6A\xA4\xBD\
\x7B\x5A\x0F\x1C\x71\xCF\xFF\x4C\x19\xC4\x18\xE1\xF6\xEC\x01\x79\
\x81\xBC\x08\x7F\x2A\x70\x65\xB3\x84\xB8\x90\xD3\x19\x1F\x2B\xFA"
and q =
"\x80\x1C\x0D\x34\xC5\x8D\x93\xFE\x99\x71\x77\x10\x1F\x80\x53\x5A\
\x47\x38\xCE\xBC\xBF\x38\x9A\x99\xB3\x63\x71\xEB"
in
group ~p ~gg ~q
(* 2048-bit, 256-bit subgroup *)
let rfc_5114_3 =
let p =
"\x87\xA8\xE6\x1D\xB4\xB6\x66\x3C\xFF\xBB\xD1\x9C\x65\x19\x59\x99\
\x8C\xEE\xF6\x08\x66\x0D\xD0\xF2\x5D\x2C\xEE\xD4\x43\x5E\x3B\x00\
\xE0\x0D\xF8\xF1\xD6\x19\x57\xD4\xFA\xF7\xDF\x45\x61\xB2\xAA\x30\
\x16\xC3\xD9\x11\x34\x09\x6F\xAA\x3B\xF4\x29\x6D\x83\x0E\x9A\x7C\
\x20\x9E\x0C\x64\x97\x51\x7A\xBD\x5A\x8A\x9D\x30\x6B\xCF\x67\xED\
\x91\xF9\xE6\x72\x5B\x47\x58\xC0\x22\xE0\xB1\xEF\x42\x75\xBF\x7B\
\x6C\x5B\xFC\x11\xD4\x5F\x90\x88\xB9\x41\xF5\x4E\xB1\xE5\x9B\xB8\
\xBC\x39\xA0\xBF\x12\x30\x7F\x5C\x4F\xDB\x70\xC5\x81\xB2\x3F\x76\
\xB6\x3A\xCA\xE1\xCA\xA6\xB7\x90\x2D\x52\x52\x67\x35\x48\x8A\x0E\
\xF1\x3C\x6D\x9A\x51\xBF\xA4\xAB\x3A\xD8\x34\x77\x96\x52\x4D\x8E\
\xF6\xA1\x67\xB5\xA4\x18\x25\xD9\x67\xE1\x44\xE5\x14\x05\x64\x25\
\x1C\xCA\xCB\x83\xE6\xB4\x86\xF6\xB3\xCA\x3F\x79\x71\x50\x60\x26\
\xC0\xB8\x57\xF6\x89\x96\x28\x56\xDE\xD4\x01\x0A\xBD\x0B\xE6\x21\
\xC3\xA3\x96\x0A\x54\xE7\x10\xC3\x75\xF2\x63\x75\xD7\x01\x41\x03\
\xA4\xB5\x43\x30\xC1\x98\xAF\x12\x61\x16\xD2\x27\x6E\x11\x71\x5F\
\x69\x38\x77\xFA\xD7\xEF\x09\xCA\xDB\x09\x4A\xE9\x1E\x1A\x15\x97"
and gg =
"\x3F\xB3\x2C\x9B\x73\x13\x4D\x0B\x2E\x77\x50\x66\x60\xED\xBD\x48\
\x4C\xA7\xB1\x8F\x21\xEF\x20\x54\x07\xF4\x79\x3A\x1A\x0B\xA1\x25\
\x10\xDB\xC1\x50\x77\xBE\x46\x3F\xFF\x4F\xED\x4A\xAC\x0B\xB5\x55\
\xBE\x3A\x6C\x1B\x0C\x6B\x47\xB1\xBC\x37\x73\xBF\x7E\x8C\x6F\x62\
\x90\x12\x28\xF8\xC2\x8C\xBB\x18\xA5\x5A\xE3\x13\x41\x00\x0A\x65\
\x01\x96\xF9\x31\xC7\x7A\x57\xF2\xDD\xF4\x63\xE5\xE9\xEC\x14\x4B\
\x77\x7D\xE6\x2A\xAA\xB8\xA8\x62\x8A\xC3\x76\xD2\x82\xD6\xED\x38\
\x64\xE6\x79\x82\x42\x8E\xBC\x83\x1D\x14\x34\x8F\x6F\x2F\x91\x93\
\xB5\x04\x5A\xF2\x76\x71\x64\xE1\xDF\xC9\x67\xC1\xFB\x3F\x2E\x55\
\xA4\xBD\x1B\xFF\xE8\x3B\x9C\x80\xD0\x52\xB9\x85\xD1\x82\xEA\x0A\
\xDB\x2A\x3B\x73\x13\xD3\xFE\x14\xC8\x48\x4B\x1E\x05\x25\x88\xB9\
\xB7\xD2\xBB\xD2\xDF\x01\x61\x99\xEC\xD0\x6E\x15\x57\xCD\x09\x15\
\xB3\x35\x3B\xBB\x64\xE0\xEC\x37\x7F\xD0\x28\x37\x0D\xF9\x2B\x52\
\xC7\x89\x14\x28\xCD\xC6\x7E\xB6\x18\x4B\x52\x3D\x1D\xB2\x46\xC3\
\x2F\x63\x07\x84\x90\xF0\x0E\xF8\xD6\x47\xD1\x48\xD4\x79\x54\x51\
\x5E\x23\x27\xCF\xEF\x98\xC5\x82\x66\x4B\x4C\x0F\x6C\xC4\x16\x59"
and q =
"\x8C\xF8\x36\x42\xA7\x09\xA0\x97\xB4\x47\x99\x76\x40\x12\x9D\xA2\
\x99\xB1\xA4\x7D\x1E\xB3\x75\x0B\xA3\x08\xB0\xFE\x64\xF5\xFB\xD3"
in
group ~p ~gg ~q
(* draft-ietf-tls-negotiated-ff-dhe-08 *)
let ffdhe2048 =
(* p = 2^2048 - 2^1984 + {[2^1918 * e] + 560316 } * 2^64 - 1 *)
(* The estimated symmetric-equivalent strength of this group is 103 bits.
Peers using ffdhe2048 that want to optimize their key exchange with a
short exponent (Section 5.2) should choose a secret key of at least
225 bits. *)
s_group ~p:
"\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xAD\xF8\x54\x58\xA2\xBB\x4A\x9A\
\xAF\xDC\x56\x20\x27\x3D\x3C\xF1\xD8\xB9\xC5\x83\xCE\x2D\x36\x95\
\xA9\xE1\x36\x41\x14\x64\x33\xFB\xCC\x93\x9D\xCE\x24\x9B\x3E\xF9\
\x7D\x2F\xE3\x63\x63\x0C\x75\xD8\xF6\x81\xB2\x02\xAE\xC4\x61\x7A\
\xD3\xDF\x1E\xD5\xD5\xFD\x65\x61\x24\x33\xF5\x1F\x5F\x06\x6E\xD0\
\x85\x63\x65\x55\x3D\xED\x1A\xF3\xB5\x57\x13\x5E\x7F\x57\xC9\x35\
\x98\x4F\x0C\x70\xE0\xE6\x8B\x77\xE2\xA6\x89\xDA\xF3\xEF\xE8\x72\
\x1D\xF1\x58\xA1\x36\xAD\xE7\x35\x30\xAC\xCA\x4F\x48\x3A\x79\x7A\
\xBC\x0A\xB1\x82\xB3\x24\xFB\x61\xD1\x08\xA9\x4B\xB2\xC8\xE3\xFB\
\xB9\x6A\xDA\xB7\x60\xD7\xF4\x68\x1D\x4F\x42\xA3\xDE\x39\x4D\xF4\
\xAE\x56\xED\xE7\x63\x72\xBB\x19\x0B\x07\xA7\xC8\xEE\x0A\x6D\x70\
\x9E\x02\xFC\xE1\xCD\xF7\xE2\xEC\xC0\x34\x04\xCD\x28\x34\x2F\x61\
\x91\x72\xFE\x9C\xE9\x85\x83\xFF\x8E\x4F\x12\x32\xEE\xF2\x81\x83\
\xC3\xFE\x3B\x1B\x4C\x6F\xAD\x73\x3B\xB5\xFC\xBC\x2E\xC2\x20\x05\
\xC5\x8E\xF1\x83\x7D\x16\x83\xB2\xC6\xF3\x4A\x26\xC1\xB2\xEF\xFA\
\x88\x6B\x42\x38\x61\x28\x5C\x97\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
let ffdhe3072 =
(* p = 2^3072 - 2^3008 + {[2^2942 * e] + 2625351} * 2^64 -1 *)
(* The estimated symmetric-equivalent strength of this group is 125 bits.
Peers using ffdhe3072 that want to optimize their key exchange with a
short exponent (Section 5.2) should choose a secret key of at least
275 bits. *)
s_group ~p:
"\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xAD\xF8\x54\x58\xA2\xBB\x4A\x9A\
\xAF\xDC\x56\x20\x27\x3D\x3C\xF1\xD8\xB9\xC5\x83\xCE\x2D\x36\x95\
\xA9\xE1\x36\x41\x14\x64\x33\xFB\xCC\x93\x9D\xCE\x24\x9B\x3E\xF9\
\x7D\x2F\xE3\x63\x63\x0C\x75\xD8\xF6\x81\xB2\x02\xAE\xC4\x61\x7A\
\xD3\xDF\x1E\xD5\xD5\xFD\x65\x61\x24\x33\xF5\x1F\x5F\x06\x6E\xD0\
\x85\x63\x65\x55\x3D\xED\x1A\xF3\xB5\x57\x13\x5E\x7F\x57\xC9\x35\
\x98\x4F\x0C\x70\xE0\xE6\x8B\x77\xE2\xA6\x89\xDA\xF3\xEF\xE8\x72\
\x1D\xF1\x58\xA1\x36\xAD\xE7\x35\x30\xAC\xCA\x4F\x48\x3A\x79\x7A\
\xBC\x0A\xB1\x82\xB3\x24\xFB\x61\xD1\x08\xA9\x4B\xB2\xC8\xE3\xFB\
\xB9\x6A\xDA\xB7\x60\xD7\xF4\x68\x1D\x4F\x42\xA3\xDE\x39\x4D\xF4\
\xAE\x56\xED\xE7\x63\x72\xBB\x19\x0B\x07\xA7\xC8\xEE\x0A\x6D\x70\
\x9E\x02\xFC\xE1\xCD\xF7\xE2\xEC\xC0\x34\x04\xCD\x28\x34\x2F\x61\
\x91\x72\xFE\x9C\xE9\x85\x83\xFF\x8E\x4F\x12\x32\xEE\xF2\x81\x83\
\xC3\xFE\x3B\x1B\x4C\x6F\xAD\x73\x3B\xB5\xFC\xBC\x2E\xC2\x20\x05\
\xC5\x8E\xF1\x83\x7D\x16\x83\xB2\xC6\xF3\x4A\x26\xC1\xB2\xEF\xFA\
\x88\x6B\x42\x38\x61\x1F\xCF\xDC\xDE\x35\x5B\x3B\x65\x19\x03\x5B\
\xBC\x34\xF4\xDE\xF9\x9C\x02\x38\x61\xB4\x6F\xC9\xD6\xE6\xC9\x07\
\x7A\xD9\x1D\x26\x91\xF7\xF7\xEE\x59\x8C\xB0\xFA\xC1\x86\xD9\x1C\
\xAE\xFE\x13\x09\x85\x13\x92\x70\xB4\x13\x0C\x93\xBC\x43\x79\x44\
\xF4\xFD\x44\x52\xE2\xD7\x4D\xD3\x64\xF2\xE2\x1E\x71\xF5\x4B\xFF\
\x5C\xAE\x82\xAB\x9C\x9D\xF6\x9E\xE8\x6D\x2B\xC5\x22\x36\x3A\x0D\
\xAB\xC5\x21\x97\x9B\x0D\xEA\xDA\x1D\xBF\x9A\x42\xD5\xC4\x48\x4E\
\x0A\xBC\xD0\x6B\xFA\x53\xDD\xEF\x3C\x1B\x20\xEE\x3F\xD5\x9D\x7C\
\x25\xE4\x1D\x2B\x66\xC6\x2E\x37\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
let ffdhe4096 =
(* p = 2^4096 - 2^4032 + {[2^3966 * e] + 5736041} * 2^64 - 1 *)
(* The estimated symmetric-equivalent strength of this group is 150 bits.
Peers using ffdhe4096 that want to optimize their key exchange with a
short exponent (Section 5.2) should choose a secret key of at least
325 bits. *)
s_group ~p:
"\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xAD\xF8\x54\x58\xA2\xBB\x4A\x9A\
\xAF\xDC\x56\x20\x27\x3D\x3C\xF1\xD8\xB9\xC5\x83\xCE\x2D\x36\x95\
\xA9\xE1\x36\x41\x14\x64\x33\xFB\xCC\x93\x9D\xCE\x24\x9B\x3E\xF9\
\x7D\x2F\xE3\x63\x63\x0C\x75\xD8\xF6\x81\xB2\x02\xAE\xC4\x61\x7A\
\xD3\xDF\x1E\xD5\xD5\xFD\x65\x61\x24\x33\xF5\x1F\x5F\x06\x6E\xD0\
\x85\x63\x65\x55\x3D\xED\x1A\xF3\xB5\x57\x13\x5E\x7F\x57\xC9\x35\
\x98\x4F\x0C\x70\xE0\xE6\x8B\x77\xE2\xA6\x89\xDA\xF3\xEF\xE8\x72\
\x1D\xF1\x58\xA1\x36\xAD\xE7\x35\x30\xAC\xCA\x4F\x48\x3A\x79\x7A\
\xBC\x0A\xB1\x82\xB3\x24\xFB\x61\xD1\x08\xA9\x4B\xB2\xC8\xE3\xFB\
\xB9\x6A\xDA\xB7\x60\xD7\xF4\x68\x1D\x4F\x42\xA3\xDE\x39\x4D\xF4\
\xAE\x56\xED\xE7\x63\x72\xBB\x19\x0B\x07\xA7\xC8\xEE\x0A\x6D\x70\
\x9E\x02\xFC\xE1\xCD\xF7\xE2\xEC\xC0\x34\x04\xCD\x28\x34\x2F\x61\
\x91\x72\xFE\x9C\xE9\x85\x83\xFF\x8E\x4F\x12\x32\xEE\xF2\x81\x83\
\xC3\xFE\x3B\x1B\x4C\x6F\xAD\x73\x3B\xB5\xFC\xBC\x2E\xC2\x20\x05\
\xC5\x8E\xF1\x83\x7D\x16\x83\xB2\xC6\xF3\x4A\x26\xC1\xB2\xEF\xFA\
\x88\x6B\x42\x38\x61\x1F\xCF\xDC\xDE\x35\x5B\x3B\x65\x19\x03\x5B\
\xBC\x34\xF4\xDE\xF9\x9C\x02\x38\x61\xB4\x6F\xC9\xD6\xE6\xC9\x07\
\x7A\xD9\x1D\x26\x91\xF7\xF7\xEE\x59\x8C\xB0\xFA\xC1\x86\xD9\x1C\
\xAE\xFE\x13\x09\x85\x13\x92\x70\xB4\x13\x0C\x93\xBC\x43\x79\x44\
\xF4\xFD\x44\x52\xE2\xD7\x4D\xD3\x64\xF2\xE2\x1E\x71\xF5\x4B\xFF\
\x5C\xAE\x82\xAB\x9C\x9D\xF6\x9E\xE8\x6D\x2B\xC5\x22\x36\x3A\x0D\
\xAB\xC5\x21\x97\x9B\x0D\xEA\xDA\x1D\xBF\x9A\x42\xD5\xC4\x48\x4E\
\x0A\xBC\xD0\x6B\xFA\x53\xDD\xEF\x3C\x1B\x20\xEE\x3F\xD5\x9D\x7C\
\x25\xE4\x1D\x2B\x66\x9E\x1E\xF1\x6E\x6F\x52\xC3\x16\x4D\xF4\xFB\
\x79\x30\xE9\xE4\xE5\x88\x57\xB6\xAC\x7D\x5F\x42\xD6\x9F\x6D\x18\
\x77\x63\xCF\x1D\x55\x03\x40\x04\x87\xF5\x5B\xA5\x7E\x31\xCC\x7A\
\x71\x35\xC8\x86\xEF\xB4\x31\x8A\xED\x6A\x1E\x01\x2D\x9E\x68\x32\
\xA9\x07\x60\x0A\x91\x81\x30\xC4\x6D\xC7\x78\xF9\x71\xAD\x00\x38\
\x09\x29\x99\xA3\x33\xCB\x8B\x7A\x1A\x1D\xB9\x3D\x71\x40\x00\x3C\
\x2A\x4E\xCE\xA9\xF9\x8D\x0A\xCC\x0A\x82\x91\xCD\xCE\xC9\x7D\xCF\
\x8E\xC9\xB5\x5A\x7F\x88\xA4\x6B\x4D\xB5\xA8\x51\xF4\x41\x82\xE1\
\xC6\x8A\x00\x7E\x5E\x65\x5F\x6A\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
let ffdhe6144 =
(* p = 2^6144 - 2^6080 + {[2^6014 * e] + 15705020} * 2^64 - 1 *)
(* The estimated symmetric-equivalent strength of this group is 175 bits.
Peers using ffdhe6144 that want to optimize their key exchange with a
short exponent (Section 5.2) should choose a secret key of at least
375 bits. *)
s_group ~p:
"\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xAD\xF8\x54\x58\xA2\xBB\x4A\x9A\
\xAF\xDC\x56\x20\x27\x3D\x3C\xF1\xD8\xB9\xC5\x83\xCE\x2D\x36\x95\
\xA9\xE1\x36\x41\x14\x64\x33\xFB\xCC\x93\x9D\xCE\x24\x9B\x3E\xF9\
\x7D\x2F\xE3\x63\x63\x0C\x75\xD8\xF6\x81\xB2\x02\xAE\xC4\x61\x7A\
\xD3\xDF\x1E\xD5\xD5\xFD\x65\x61\x24\x33\xF5\x1F\x5F\x06\x6E\xD0\
\x85\x63\x65\x55\x3D\xED\x1A\xF3\xB5\x57\x13\x5E\x7F\x57\xC9\x35\
\x98\x4F\x0C\x70\xE0\xE6\x8B\x77\xE2\xA6\x89\xDA\xF3\xEF\xE8\x72\
\x1D\xF1\x58\xA1\x36\xAD\xE7\x35\x30\xAC\xCA\x4F\x48\x3A\x79\x7A\
\xBC\x0A\xB1\x82\xB3\x24\xFB\x61\xD1\x08\xA9\x4B\xB2\xC8\xE3\xFB\
\xB9\x6A\xDA\xB7\x60\xD7\xF4\x68\x1D\x4F\x42\xA3\xDE\x39\x4D\xF4\
\xAE\x56\xED\xE7\x63\x72\xBB\x19\x0B\x07\xA7\xC8\xEE\x0A\x6D\x70\
\x9E\x02\xFC\xE1\xCD\xF7\xE2\xEC\xC0\x34\x04\xCD\x28\x34\x2F\x61\
\x91\x72\xFE\x9C\xE9\x85\x83\xFF\x8E\x4F\x12\x32\xEE\xF2\x81\x83\
\xC3\xFE\x3B\x1B\x4C\x6F\xAD\x73\x3B\xB5\xFC\xBC\x2E\xC2\x20\x05\
\xC5\x8E\xF1\x83\x7D\x16\x83\xB2\xC6\xF3\x4A\x26\xC1\xB2\xEF\xFA\
\x88\x6B\x42\x38\x61\x1F\xCF\xDC\xDE\x35\x5B\x3B\x65\x19\x03\x5B\
\xBC\x34\xF4\xDE\xF9\x9C\x02\x38\x61\xB4\x6F\xC9\xD6\xE6\xC9\x07\
\x7A\xD9\x1D\x26\x91\xF7\xF7\xEE\x59\x8C\xB0\xFA\xC1\x86\xD9\x1C\
\xAE\xFE\x13\x09\x85\x13\x92\x70\xB4\x13\x0C\x93\xBC\x43\x79\x44\
\xF4\xFD\x44\x52\xE2\xD7\x4D\xD3\x64\xF2\xE2\x1E\x71\xF5\x4B\xFF\
\x5C\xAE\x82\xAB\x9C\x9D\xF6\x9E\xE8\x6D\x2B\xC5\x22\x36\x3A\x0D\
\xAB\xC5\x21\x97\x9B\x0D\xEA\xDA\x1D\xBF\x9A\x42\xD5\xC4\x48\x4E\
\x0A\xBC\xD0\x6B\xFA\x53\xDD\xEF\x3C\x1B\x20\xEE\x3F\xD5\x9D\x7C\
\x25\xE4\x1D\x2B\x66\x9E\x1E\xF1\x6E\x6F\x52\xC3\x16\x4D\xF4\xFB\
\x79\x30\xE9\xE4\xE5\x88\x57\xB6\xAC\x7D\x5F\x42\xD6\x9F\x6D\x18\
\x77\x63\xCF\x1D\x55\x03\x40\x04\x87\xF5\x5B\xA5\x7E\x31\xCC\x7A\
\x71\x35\xC8\x86\xEF\xB4\x31\x8A\xED\x6A\x1E\x01\x2D\x9E\x68\x32\
\xA9\x07\x60\x0A\x91\x81\x30\xC4\x6D\xC7\x78\xF9\x71\xAD\x00\x38\
\x09\x29\x99\xA3\x33\xCB\x8B\x7A\x1A\x1D\xB9\x3D\x71\x40\x00\x3C\
\x2A\x4E\xCE\xA9\xF9\x8D\x0A\xCC\x0A\x82\x91\xCD\xCE\xC9\x7D\xCF\
\x8E\xC9\xB5\x5A\x7F\x88\xA4\x6B\x4D\xB5\xA8\x51\xF4\x41\x82\xE1\
\xC6\x8A\x00\x7E\x5E\x0D\xD9\x02\x0B\xFD\x64\xB6\x45\x03\x6C\x7A\
\x4E\x67\x7D\x2C\x38\x53\x2A\x3A\x23\xBA\x44\x42\xCA\xF5\x3E\xA6\
\x3B\xB4\x54\x32\x9B\x76\x24\xC8\x91\x7B\xDD\x64\xB1\xC0\xFD\x4C\
\xB3\x8E\x8C\x33\x4C\x70\x1C\x3A\xCD\xAD\x06\x57\xFC\xCF\xEC\x71\
\x9B\x1F\x5C\x3E\x4E\x46\x04\x1F\x38\x81\x47\xFB\x4C\xFD\xB4\x77\
\xA5\x24\x71\xF7\xA9\xA9\x69\x10\xB8\x55\x32\x2E\xDB\x63\x40\xD8\
\xA0\x0E\xF0\x92\x35\x05\x11\xE3\x0A\xBE\xC1\xFF\xF9\xE3\xA2\x6E\
\x7F\xB2\x9F\x8C\x18\x30\x23\xC3\x58\x7E\x38\xDA\x00\x77\xD9\xB4\
\x76\x3E\x4E\x4B\x94\xB2\xBB\xC1\x94\xC6\x65\x1E\x77\xCA\xF9\x92\
\xEE\xAA\xC0\x23\x2A\x28\x1B\xF6\xB3\xA7\x39\xC1\x22\x61\x16\x82\
\x0A\xE8\xDB\x58\x47\xA6\x7C\xBE\xF9\xC9\x09\x1B\x46\x2D\x53\x8C\
\xD7\x2B\x03\x74\x6A\xE7\x7F\x5E\x62\x29\x2C\x31\x15\x62\xA8\x46\
\x50\x5D\xC8\x2D\xB8\x54\x33\x8A\xE4\x9F\x52\x35\xC9\x5B\x91\x17\
\x8C\xCF\x2D\xD5\xCA\xCE\xF4\x03\xEC\x9D\x18\x10\xC6\x27\x2B\x04\
\x5B\x3B\x71\xF9\xDC\x6B\x80\xD6\x3F\xDD\x4A\x8E\x9A\xDB\x1E\x69\
\x62\xA6\x95\x26\xD4\x31\x61\xC1\xA4\x1D\x57\x0D\x79\x38\xDA\xD4\
\xA4\x0E\x32\x9C\xD0\xE4\x0E\x65\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
let ffdhe8192 =
(* p = 2^8192 - 2^8128 + {[2^8062 * e] + 10965728} * 2^64 - 1 *)
(* The estimated symmetric-equivalent strength of this group is 192 bits.
Peers using ffdhe8192 that want to optimize their key exchange with a
short exponent (Section 5.2) should choose a secret key of at least
400 bits. *)
s_group ~p:
"\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xAD\xF8\x54\x58\xA2\xBB\x4A\x9A\
\xAF\xDC\x56\x20\x27\x3D\x3C\xF1\xD8\xB9\xC5\x83\xCE\x2D\x36\x95\
\xA9\xE1\x36\x41\x14\x64\x33\xFB\xCC\x93\x9D\xCE\x24\x9B\x3E\xF9\
\x7D\x2F\xE3\x63\x63\x0C\x75\xD8\xF6\x81\xB2\x02\xAE\xC4\x61\x7A\
\xD3\xDF\x1E\xD5\xD5\xFD\x65\x61\x24\x33\xF5\x1F\x5F\x06\x6E\xD0\
\x85\x63\x65\x55\x3D\xED\x1A\xF3\xB5\x57\x13\x5E\x7F\x57\xC9\x35\
\x98\x4F\x0C\x70\xE0\xE6\x8B\x77\xE2\xA6\x89\xDA\xF3\xEF\xE8\x72\
\x1D\xF1\x58\xA1\x36\xAD\xE7\x35\x30\xAC\xCA\x4F\x48\x3A\x79\x7A\
\xBC\x0A\xB1\x82\xB3\x24\xFB\x61\xD1\x08\xA9\x4B\xB2\xC8\xE3\xFB\
\xB9\x6A\xDA\xB7\x60\xD7\xF4\x68\x1D\x4F\x42\xA3\xDE\x39\x4D\xF4\
\xAE\x56\xED\xE7\x63\x72\xBB\x19\x0B\x07\xA7\xC8\xEE\x0A\x6D\x70\
\x9E\x02\xFC\xE1\xCD\xF7\xE2\xEC\xC0\x34\x04\xCD\x28\x34\x2F\x61\
\x91\x72\xFE\x9C\xE9\x85\x83\xFF\x8E\x4F\x12\x32\xEE\xF2\x81\x83\
\xC3\xFE\x3B\x1B\x4C\x6F\xAD\x73\x3B\xB5\xFC\xBC\x2E\xC2\x20\x05\
\xC5\x8E\xF1\x83\x7D\x16\x83\xB2\xC6\xF3\x4A\x26\xC1\xB2\xEF\xFA\
\x88\x6B\x42\x38\x61\x1F\xCF\xDC\xDE\x35\x5B\x3B\x65\x19\x03\x5B\
\xBC\x34\xF4\xDE\xF9\x9C\x02\x38\x61\xB4\x6F\xC9\xD6\xE6\xC9\x07\
\x7A\xD9\x1D\x26\x91\xF7\xF7\xEE\x59\x8C\xB0\xFA\xC1\x86\xD9\x1C\
\xAE\xFE\x13\x09\x85\x13\x92\x70\xB4\x13\x0C\x93\xBC\x43\x79\x44\
\xF4\xFD\x44\x52\xE2\xD7\x4D\xD3\x64\xF2\xE2\x1E\x71\xF5\x4B\xFF\
\x5C\xAE\x82\xAB\x9C\x9D\xF6\x9E\xE8\x6D\x2B\xC5\x22\x36\x3A\x0D\
\xAB\xC5\x21\x97\x9B\x0D\xEA\xDA\x1D\xBF\x9A\x42\xD5\xC4\x48\x4E\
\x0A\xBC\xD0\x6B\xFA\x53\xDD\xEF\x3C\x1B\x20\xEE\x3F\xD5\x9D\x7C\
\x25\xE4\x1D\x2B\x66\x9E\x1E\xF1\x6E\x6F\x52\xC3\x16\x4D\xF4\xFB\
\x79\x30\xE9\xE4\xE5\x88\x57\xB6\xAC\x7D\x5F\x42\xD6\x9F\x6D\x18\
\x77\x63\xCF\x1D\x55\x03\x40\x04\x87\xF5\x5B\xA5\x7E\x31\xCC\x7A\
\x71\x35\xC8\x86\xEF\xB4\x31\x8A\xED\x6A\x1E\x01\x2D\x9E\x68\x32\
\xA9\x07\x60\x0A\x91\x81\x30\xC4\x6D\xC7\x78\xF9\x71\xAD\x00\x38\
\x09\x29\x99\xA3\x33\xCB\x8B\x7A\x1A\x1D\xB9\x3D\x71\x40\x00\x3C\
\x2A\x4E\xCE\xA9\xF9\x8D\x0A\xCC\x0A\x82\x91\xCD\xCE\xC9\x7D\xCF\
\x8E\xC9\xB5\x5A\x7F\x88\xA4\x6B\x4D\xB5\xA8\x51\xF4\x41\x82\xE1\
\xC6\x8A\x00\x7E\x5E\x0D\xD9\x02\x0B\xFD\x64\xB6\x45\x03\x6C\x7A\
\x4E\x67\x7D\x2C\x38\x53\x2A\x3A\x23\xBA\x44\x42\xCA\xF5\x3E\xA6\
\x3B\xB4\x54\x32\x9B\x76\x24\xC8\x91\x7B\xDD\x64\xB1\xC0\xFD\x4C\
\xB3\x8E\x8C\x33\x4C\x70\x1C\x3A\xCD\xAD\x06\x57\xFC\xCF\xEC\x71\
\x9B\x1F\x5C\x3E\x4E\x46\x04\x1F\x38\x81\x47\xFB\x4C\xFD\xB4\x77\
\xA5\x24\x71\xF7\xA9\xA9\x69\x10\xB8\x55\x32\x2E\xDB\x63\x40\xD8\
\xA0\x0E\xF0\x92\x35\x05\x11\xE3\x0A\xBE\xC1\xFF\xF9\xE3\xA2\x6E\
\x7F\xB2\x9F\x8C\x18\x30\x23\xC3\x58\x7E\x38\xDA\x00\x77\xD9\xB4\
\x76\x3E\x4E\x4B\x94\xB2\xBB\xC1\x94\xC6\x65\x1E\x77\xCA\xF9\x92\
\xEE\xAA\xC0\x23\x2A\x28\x1B\xF6\xB3\xA7\x39\xC1\x22\x61\x16\x82\
\x0A\xE8\xDB\x58\x47\xA6\x7C\xBE\xF9\xC9\x09\x1B\x46\x2D\x53\x8C\
\xD7\x2B\x03\x74\x6A\xE7\x7F\x5E\x62\x29\x2C\x31\x15\x62\xA8\x46\
\x50\x5D\xC8\x2D\xB8\x54\x33\x8A\xE4\x9F\x52\x35\xC9\x5B\x91\x17\
\x8C\xCF\x2D\xD5\xCA\xCE\xF4\x03\xEC\x9D\x18\x10\xC6\x27\x2B\x04\
\x5B\x3B\x71\xF9\xDC\x6B\x80\xD6\x3F\xDD\x4A\x8E\x9A\xDB\x1E\x69\
\x62\xA6\x95\x26\xD4\x31\x61\xC1\xA4\x1D\x57\x0D\x79\x38\xDA\xD4\
\xA4\x0E\x32\x9C\xCF\xF4\x6A\xAA\x36\xAD\x00\x4C\xF6\x00\xC8\x38\
\x1E\x42\x5A\x31\xD9\x51\xAE\x64\xFD\xB2\x3F\xCE\xC9\x50\x9D\x43\
\x68\x7F\xEB\x69\xED\xD1\xCC\x5E\x0B\x8C\xC3\xBD\xF6\x4B\x10\xEF\
\x86\xB6\x31\x42\xA3\xAB\x88\x29\x55\x5B\x2F\x74\x7C\x93\x26\x65\
\xCB\x2C\x0F\x1C\xC0\x1B\xD7\x02\x29\x38\x88\x39\xD2\xAF\x05\xE4\
\x54\x50\x4A\xC7\x8B\x75\x82\x82\x28\x46\xC0\xBA\x35\xC3\x5F\x5C\
\x59\x16\x0C\xC0\x46\xFD\x82\x51\x54\x1F\xC6\x8C\x9C\x86\xB0\x22\
\xBB\x70\x99\x87\x6A\x46\x0E\x74\x51\xA8\xA9\x31\x09\x70\x3F\xEE\
\x1C\x21\x7E\x6C\x38\x26\xE5\x2C\x51\xAA\x69\x1E\x0E\x42\x3C\xFC\
\x99\xE9\xE3\x16\x50\xC1\x21\x7B\x62\x48\x16\xCD\xAD\x9A\x95\xF9\
\xD5\xB8\x01\x94\x88\xD9\xC0\xA0\xA1\xFE\x30\x75\xA5\x77\xE2\x31\
\x83\xF8\x1D\x4A\x3F\x2F\xA4\x57\x1E\xFC\x8C\xE0\xBA\x8A\x4F\xE8\
\xB6\x85\x5D\xFE\x72\xB0\xA6\x6E\xDE\xD2\xFB\xAB\xFB\xE5\x8A\x30\
\xFA\xFA\xBE\x1C\x5D\x71\xA8\x7E\x2F\x74\x1E\xF8\xC1\xFE\x86\xFE\
\xA6\xBB\xFD\xE5\x30\x67\x7F\x0D\x97\xD1\x1D\x49\xF7\xA8\x44\x3D\
\x08\x22\xE5\x06\xA9\xF4\x61\x4E\x01\x1E\x2A\x94\x83\x8F\xF8\x8C\
\xD6\x8C\x8B\xB7\xC5\xC6\x42\x4C\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
end

View file

@ -0,0 +1,178 @@
open Mirage_crypto.Uncommon
open Common
type pub = { p : Z.t ; q : Z.t ; gg : Z.t ; y : Z.t }
let pub ?(fips = false) ~p ~q ~gg ~y () =
let* () = guard Z.(one < gg && gg < p) (`Msg "bad generator") in
let* () = guard (Z_extra.pseudoprime q) (`Msg "q is not prime") in
let* () = guard (Z.is_odd p && Z_extra.pseudoprime p) (`Msg "p is not prime") in
let* () = guard Z.(zero < y && y < p) (`Msg "y not in 0..p-1") in
let* () = guard (q < p) (`Msg "q is not smaller than p") in
let* () = guard Z.(zero = (pred p) mod q) (`Msg "p - 1 mod q <> 0") in
let* () =
if fips then
match Z.numbits p, Z.numbits q with
| 1024, 160 | 2048, 224 | 2048, 256 | 3072, 256 -> Ok ()
| _ -> Error (`Msg "bit length of p or q not FIPS specified")
else
Ok ()
in
Ok { p ; q ; gg ; y }
type priv =
{ p : Z.t ; q : Z.t ; gg : Z.t ; x : Z.t ; y : Z.t }
let priv ?fips ~p ~q ~gg ~x ~y () =
let* _ = pub ?fips ~p ~q ~gg ~y () in
let* () = guard Z.(zero < x && x < q) (`Msg "x not in 1..q-1") in
let* () = guard Z.(y = powm gg x p) (`Msg "y <> g ^ x mod p") in
Ok { p ; q ; gg ; x ; y }
let pub_of_priv { p; q; gg; y; _ } = { p; q; gg; y }
type keysize = [ `Fips1024 | `Fips2048 | `Fips3072 | `Exactly of int * int ]
let expand_size = function
| `Fips1024 -> (1024, 160)
| `Fips2048 -> (2048, 256)
| `Fips3072 -> (3072, 256)
| `Exactly (l, n) ->
if 3 <= l && 2 <= n then (l, n) else
invalid_arg "Dsa.generate: bits: `Exactly (%d, %d)" l n
type mask = [ `No | `Yes | `Yes_with of Mirage_crypto_rng.g ]
let expand_mask = function
| `No -> `No
| `Yes -> `Yes None
| `Yes_with g -> `Yes (Some g)
(*
* FIPS.186-4-style derivation:
* - p and q are derived using a method numerically like the one described in
* A.1.1.2, adapted to use the native rng.
* - g is derived as per A.2.1.
*)
let params ?g size =
let two = Z.(~$2) in
let (l, n) = expand_size size in
let q = Z_extra.prime ?g ~msb:1 n in
let p =
let q_q = Z.(q * two) in
until Z_extra.pseudoprime @@ fun () ->
let x = Z_extra.gen_bits ?g ~msb:1 l in
Z.(x - (x mod q_q) + one)
in
let gg =
let e = Z.(pred p / q) in
until ((<>) Z.one) @@ fun () ->
let h = Z_extra.gen_r ?g two Z.(pred p) in
Z.(powm h e p)
in
(* all checks above are already satisfied *)
(p, q, gg)
let generate ?g size =
let (p, q, gg) = params ?g size in
let x = Z_extra.gen_r ?g Z.one q in
let y = Z.(powm gg x p) in
(* checks are satisfied due to construction *)
{ p; q; gg; x; y }
module K_gen (H : Digestif.S) = struct
let drbg : 'a Mirage_crypto_rng.generator =
let module M = Mirage_crypto_rng.Hmac_drbg (H) in (module M)
let z_gen ~key:{ q; x; _ } z =
let repr = Z_extra.to_octets_be ~size:(Z.numbits q // 8) in
let g = Mirage_crypto_rng.create ~strict:true drbg in
Mirage_crypto_rng.reseed ~g (repr x ^ repr Z.(z mod q));
Z_extra.gen_r ~g Z.one q
let generate ~key buf =
z_gen ~key (Z_extra.of_octets_be ~bits:(Z.numbits key.q) buf)
end
module K_gen_sha256 = K_gen (Digestif.SHA256)
let sign_z ?(mask = `Yes) ?k:k0 ~key:({ p; q; gg; x; _ } as key) z =
let k = match k0 with Some k -> k | None -> K_gen_sha256.z_gen ~key z in
let k' = Z.invert k q
and b, b' = match expand_mask mask with
| `No -> Z.one, Z.one
| `Yes g ->
let m = Z_extra.gen_r ?g Z.one q in
m, Z.invert m q
in
let r = Z.(powm_sec gg k p mod q) in
(* normal DSA sign is: s = k^-1 * (z + r * x) mod q *)
(* we apply blinding where possible and compute:
s = k^-1 * b^-1 * (b * z + b * r * x) mod q
see https://github.com/openssl/openssl/pull/6524 for further details *)
let s =
let t1 =
let t11 = Z.(b * x mod q) in
Z.(t11 * r mod q)
in
let t2 = Z.(b * z mod q) in
let t3 = Z.((t1 + t2) mod q) in
let t4 = Z.(k' * t3 mod q) in
Z.(b' * t4 mod q)
in
if r = Z.zero || s = Z.zero then invalid_arg "k unsuitable" else (r, s)
let verify_z ~key:({ p; q; gg; y }: pub ) (r, s) z =
let v () =
let w = Z.invert s q in
let u1 = Z.(z * w mod q)
and u2 = Z.(r * w mod q) in
Z.((powm gg u1 p * powm y u2 p) mod p mod q) in
Z.zero < r && r < q && Z.zero < s && s < q && v () = r
let sign ?mask ?k ~(key : priv) digest =
let bits = Z.numbits key.q in
let size = bits // 8 in
let (r, s) = sign_z ?mask ?k ~key (Z_extra.of_octets_be ~bits digest) in
Z_extra.(to_octets_be ~size r, to_octets_be ~size s)
let verify ~(key : pub) (r, s) digest =
let z = Z_extra.of_octets_be ~bits:(Z.numbits key.q) digest
and (r, s) = Z_extra.(of_octets_be r, of_octets_be s) in
verify_z ~key (r, s) z
let rec shift_left_inplace buf = function
| 0 -> ()
| bits when bits mod 8 = 0 ->
let off = bits / 8 in
let to_blit = Bytes.length buf - off in
Bytes.unsafe_blit buf off buf 0 to_blit ;
Bytes.unsafe_fill buf to_blit (Bytes.length buf - to_blit) '\x00'
| bits when bits < 8 ->
let foo = 8 - bits in
for i = 0 to Bytes.length buf - 2 do
let b1 = Bytes.get_uint8 buf i
and b2 = Bytes.get_uint8 buf (i + 1) in
Bytes.set_uint8 buf i ((b1 lsl bits) lor (b2 lsr foo))
done ;
Bytes.set_uint8 buf (Bytes.length buf - 1)
(Bytes.get_uint8 buf (Bytes.length buf - 1) lsl bits)
| bits ->
shift_left_inplace buf (8 * (bits / 8)) ;
shift_left_inplace buf (bits mod 8)
let (lsl) buf bits =
let buf' = Bytes.of_string buf in
shift_left_inplace buf' bits;
Bytes.unsafe_to_string buf'
let massage ~key:({ q; _ }: pub) digest =
let bits = Z.numbits q in
if bits >= String.length digest * 8 then
digest
else
let buf = Z_extra.(to_octets_be Z.(of_octets_be digest mod q)) in
buf lsl ((8 - bits mod 8) mod 8)

View file

@ -0,0 +1,5 @@
(library
(name mirage_crypto_pk)
(public_name mirage-crypto-pk)
(libraries zarith mirage-crypto mirage-crypto-rng eqaf)
(private_modules common dh dsa rsa z_extra))

View file

@ -0,0 +1,4 @@
module Dh = Dh
module Dsa = Dsa
module Rsa = Rsa
module Z_extra = Z_extra

View file

@ -0,0 +1,520 @@
(** {1 Public-key cryptography} *)
(** Public and private key types are private, the constructors validate their
well-formedness as much as possible, esp. so that [powm_sec] will not raise
an exception (exponent > 1, or odd modulus). All modular exponentiations
(unless otherwise noted) use the {!Z.powm_sec} function, which uses a static
access pattern and operates in constant time (of the bit size of the input),
independent of which bits are set and not set. The performance is up to 20%
worse than [powm]. Additionally, blinding is applied to RSA and DSA by
default. *)
(** {b RSA} public-key cryptography algorithm. *)
module Rsa : sig
(** {1 Keys}
Messages are checked not to exceed the key size, and this is signalled via
the {!Insufficient_key} exception.
Private-key operations are optionally protected through RSA blinding. *)
exception Insufficient_key
(** Raised if the key is too small to transform the given message, i.e. if the
numerical interpretation of the (potentially padded) message is not
smaller than the modulus. *)
type pub = private {
e : Z.t ; (** Public exponent *)
n : Z.t ; (** Modulus *)
}
(** The public portion of the key. *)
val pub : e:Z.t -> n:Z.t -> (pub, [> `Msg of string ]) result
(** [pub ~e ~n] validates the public key: [1 < e < n], [n > 0],
[is_odd n], and [numbits n >= 89] (a requirement for PKCS1 operations). *)
type priv = private {
e : Z.t ; (** Public exponent *)
d : Z.t ; (** Private exponent *)
n : Z.t ; (** Modulus ([p q])*)
p : Z.t ; (** Prime factor [p] *)
q : Z.t ; (** Prime factor [q] *)
dp : Z.t ; (** [d mod (p-1)] *)
dq : Z.t ; (** [d mod (q-1)] *)
q' : Z.t ; (** [q^(-1) mod p] *)
}
(** Full private key (two-factor version).
{b Note} The key layout assumes that [p > q], which affects the quantity
[q'] (sometimes called [u]), and the computation of the private transform.
Some systems assume otherwise. When using keys produced by a system that
computes [u = p^(-1) mod q], either exchange [p] with [q] and [dp] with
[dq], or re-generate the full private key using
{{!priv_of_primes}[priv_of_primes]}. *)
val priv : e:Z.t -> d:Z.t -> n:Z.t -> p:Z.t -> q:Z.t -> dp:Z.t -> dq:Z.t ->
q':Z.t -> (priv, [> `Msg of string ]) result
(** [priv ~e ~d ~n ~p ~q ~dp ~dq ~q'] validates the private key: [e, n] must
be a valid {!type-pub}, [p] and [q] valid prime numbers [> 0], [odd],
probabilistically prime, [p <> q], [n = p * q], [e] probabilistically
prime and coprime to both [p] and [q], [q' = q ^ -1 mod p], [1 < d < n],
[dp = d mod (p - 1)], [dq = d mod (q - 1)],
and [d = e ^ -1 mod (p - 1) (q - 1)]. *)
val pub_bits : pub -> int
(** Bit-size of a public key. *)
val priv_bits : priv -> int
(** Bit-size of a private key. *)
val priv_of_primes : e:Z.t -> p:Z.t -> q:Z.t ->
(priv, [> `Msg of string ]) result
(** [priv_of_primes ~e ~p ~q] is the {{!type-priv}private key} derived from the
minimal description [(e, p, q)]. *)
val priv_of_exp : ?g:Mirage_crypto_rng.g -> ?attempts:int -> e:Z.t -> d:Z.t ->
n:Z.t -> unit -> (priv, [> `Msg of string ]) result
(** [priv_of_exp ?g ?attempts ~e ~d n] is the unique {{!type-priv}private key}
characterized by the public ([e]) and private ([d]) exponents, and modulus
[n]. This operation uses a probabilistic process that can fail to recover
the key.
[~attempts] is the number of trials. For triplets that form an RSA key,
the probability of failure is at most [2^(-attempts)]. [attempts] defaults
to an unspecified number that yields a very high probability of recovering
valid keys.
Note that no time masking is done for the computations in this function. *)
val pub_of_priv : priv -> pub
(** Extract the public component from a private key. *)
(** {1 The RSA transformation} *)
type 'a or_digest = [ `Message of 'a | `Digest of string ]
(** Either an ['a] or its digest, according to some hash algorithm. *)
type mask = [ `No | `Yes | `Yes_with of Mirage_crypto_rng.g ]
(** Masking (cryptographic blinding) mode for the RSA transform with the
private key. Masking does not change the result, but it does change the
timing profile of the operation.
{ul
{- [`No] disables masking. It is slightly faster but it {b exposes the
private key to timing-based attacks}.}
{- [`Yes] uses random masking with the global RNG instance. This is
the sane option.}
{- [`Yes_with g] uses random masking with the generator [g].}} *)
val encrypt : key:pub -> string -> string
(** [encrypt key message] is the encrypted [message].
@raise Insufficient_key (see {{!Insufficient_key}Insufficient_key})
@raise Invalid_argument if [message] is [0x00] or [0x01]. *)
val decrypt : ?crt_hardening:bool -> ?mask:mask -> key:priv ->
string -> string
(** [decrypt ~crt_hardening ~mask key ciphertext] is the decrypted
[ciphertext], left-padded with [0x00] up to [key] size.
[~crt_hardening] defaults to [false]. If [true] verifies that the
result is correct. This is to counter Chinese remainder theorem attacks to
factorize primes. If the computed signature is incorrect, it is again
computed in the classical way (c ^ d mod n) without the Chinese remainder
theorem optimization. The deterministic {{!PKCS1.sign}PKCS1 signing},
which is at danger, uses [true] as default.
[~mask] defaults to [`Yes].
@raise Insufficient_key (see {{!Insufficient_key}Insufficient_key}) *)
(** {1 Key generation} *)
val generate : ?g:Mirage_crypto_rng.g -> ?e:Z.t -> bits:int -> unit -> priv
(** [generate ~g ~e ~bits ()] is a new {{!type-priv}private key}. The new key is
guaranteed to be well formed, see {!val-priv}.
[e] defaults to [2^16+1].
{b Note} This process might diverge if there are no keys for the given
bit size. This can happen when [bits] is extremely small.
@raise Invalid_argument if [e] is not a prime number (checked
probabilistically) or not in the range [1 < e < 2^bits], or if
[bits < 89] (as above, required for PKCS1 operations). *)
(** {1 PKCS#1 padded modes} *)
(** {b PKCS v1.5} operations, as defined by {b PKCS #1 v1.5}.
For the operations that only add the raw padding, the key size must be at
least 11 bytes larger than the message. For full {{!PKCS1.sign}signing}, the
minimal key size varies according to the hash algorithm. In this case, the
key size is [priv_bits key / 8], rounded up. *)
module PKCS1 : sig
val encrypt : ?g:Mirage_crypto_rng.g -> key:pub -> string -> string
(** [encrypt g key message] is a PKCS1-padded (type 2) and encrypted
[message].
@raise Insufficient_key (see {{!Insufficient_key}Insufficient_key}) *)
val decrypt : ?crt_hardening:bool -> ?mask:mask -> key:priv ->
string -> string option
(** [decrypt ~crt_hardening ~mask ~key ciphertext] is [Some message] if
the [ciphertext] was produced by the corresponding {{!encrypt}encrypt}
operation, or [None] otherwise. [crt_hardening] defaults to
[false]. *)
val sig_encode : ?crt_hardening:bool -> ?mask:mask -> key:priv ->
string -> string
(** [sig_encode ~crt_hardening ~mask ~key message] is the PKCS1-padded
(type 1) [message] signed by the [key]. [crt_hardening] defaults to
[true] and verifies that the computed signature is correct.
{b Note} This operation performs only the padding and RSA transformation
steps of the PKCS 1.5 signature. The full signature is implemented by
{{!sign}[sign]}.
@raise Insufficient_key (see {{!Insufficient_key}Insufficient_key}) *)
val sig_decode : key:pub -> string -> string option
(** [sig_decode key signature] is [Some message] when the [signature]
was produced with the given [key] as per {{!sig_encode}sig_encode}, or
[None] *)
val min_key : [< Digestif.hash' > `MD5 `SHA1 `SHA224 `SHA256 `SHA384 `SHA512 ] -> int
(** [min_key hash] is the minimum key size required by {{!sign}[sign]}. *)
val sign : ?crt_hardening:bool -> ?mask:mask ->
hash:[< Digestif.hash' > `MD5 `SHA1 `SHA224 `SHA256 `SHA384 `SHA512 ] ->
key:priv -> string or_digest -> string
(** [sign ~crt_hardening ~mask ~hash ~key message] is the PKCS 1.5
signature of [message], signed by the [key], using the hash function
[hash]. This is the full signature, with the ASN-encoded message digest
as the payload. [crt_hardening] defaults to [true] and verifies that
the computed signature is correct.
[message] is either the actual message, or its digest.
@raise Insufficient_key (see {{!Insufficient_key}Insufficient_key})
@raise Invalid_argument if message is a [`Digest] of the wrong size. *)
val verify : hashp:([< Digestif.hash' > `MD5 `SHA1 `SHA224 `SHA256 `SHA384 `SHA512 ] -> bool) ->
key:pub -> signature:string -> string or_digest -> bool
(** [verify ~hashp ~key ~signature message] checks that [signature] is the
PKCS 1.5 signature of the [message] under the given [key].
[message] is either the actual message, or its digest.
[hashp] determines the allowed hash algorithms. Whenever [hashp] is
[false], [verify] is also [false].
@raise Invalid_argument if message is a [`Digest] of the wrong size. *)
end
(** {1 OAEP padded modes} *)
(** {b OAEP}-padded encryption, as defined by {b PKCS #1 v2.1}.
The same hash function is used for padding and MGF. MGF is {b MGF1} as
defined in {b PKCS #1 2.1}.
Keys must have a minimum of [2 + 2 * hlen + len(message)] bytes, where
[hlen] is the hash length. *)
module OAEP (H : Digestif.S) : sig
val encrypt : ?g:Mirage_crypto_rng.g -> ?label:string -> key:pub ->
string -> string
(** [encrypt ~g ~label ~key message] is {b OAEP}-padded and encrypted
[message], using the optional [label].
@raise Insufficient_key (see {{!Insufficient_key}Insufficient_key}) *)
val decrypt : ?crt_hardening:bool -> ?mask:mask -> ?label:string ->
key:priv -> string -> string option
(** [decrypt ~crt_hardening ~mask ~label ~key ciphertext] is
[Some message] if the [ciphertext] was produced by the corresponding
{{!encrypt}encrypt} operation, or [None] otherwise. [crt_hardening]
defaults to [false]. *)
end
(** {1 PSS signing} *)
(** {b PSS}-based signing, as defined by {b PKCS #1 v2.1}.
The same hash function is used for padding, MGF and computing message
digest. MGF is {b MGF1} as defined in {b PKCS #1 2.1}.
Keys must have a minimum of [2 + hlen + slen] bytes, where [hlen] is the
hash length and [slen] is the seed length. *)
module PSS (H: Digestif.S) : sig
val sign : ?g:Mirage_crypto_rng.g -> ?crt_hardening:bool ->
?mask:mask -> ?slen:int -> key:priv -> string or_digest -> string
(** [sign ~g ~crt_hardening ~mask ~slen ~key message] the [PSS]-padded
digest of [message], signed with the [key]. [crt_hardening] defaults
to [false].
[slen] is the optional seed length and defaults to the size of the
underlying hash function.
[message] is either the actual message, or its digest.
@raise Insufficient_key (see {{!Insufficient_key}Insufficient_key})
@raise Invalid_argument if message is a [`Digest] of the wrong size. *)
val verify : ?slen:int -> key:pub -> signature:string -> string or_digest -> bool
(** [verify ~slen ~key ~signature message] checks whether [signature] is a
valid {b PSS} signature of the [message] under the given [key].
[message] is either the actual message, or its digest.
@raise Invalid_argument if message is a [`Digest] of the wrong size. *)
end
end
(** {b DSA} digital signature algorithm. *)
module Dsa : sig
(** {1 DSA signature algorithm} *)
type priv = private {
p : Z.t ; (** Modulus *)
q : Z.t ; (** Subgroup order *)
gg : Z.t ; (** Group Generator *)
x : Z.t ; (** Private key proper *)
y : Z.t ; (** Public component *)
}
(** Private key. [p], [q] and [gg] comprise {i domain parameters}. *)
val priv : ?fips:bool -> p:Z.t -> q:Z.t -> gg:Z.t -> x:Z.t -> y:Z.t -> unit ->
(priv, [> `Msg of string ]) result
(** [priv ~fips ~p ~q ~gg ~x ~y ()] constructs a private DSA key from the given
numbers. Will result in an error if parameters are ill-formed: same as
{!val-pub}, and additionally [0 < x < q] and [y = g ^ x mod p]. Note that no
time masking is done on the modular exponentiation. *)
type pub = private {
p : Z.t ;
q : Z.t ;
gg : Z.t ;
y : Z.t ;
}
(** Public key, a subset of {{!type-priv}private key}. *)
val pub : ?fips:bool -> p:Z.t -> q:Z.t -> gg:Z.t -> y:Z.t -> unit ->
(pub, [> `Msg of string ]) result
(** [pub ~fips ~p ~q ~gg ~y ()] constructs a public DSA key from the given
numbers. Will result in an error if the parameters are not well-formed:
[one < gg < p], [q] probabilistically a prime, [p] probabilistically
prime and odd, [0 < y < p], [q < p], and [p - 1 mod q = 0]. If [fips] is
specified and [true] (defaults to [false]), only FIPS-specified bit length
for [p] and [q] are accepted. *)
type keysize = [ `Fips1024 | `Fips2048 | `Fips3072 | `Exactly of int * int ]
(** Key size request. Three {e Fips} variants refer to FIPS-standardized
L-values ([p] size) and imply the corresponding N ([q] size); The last
variants specifies L and N directly. *)
type mask = [ `No | `Yes | `Yes_with of Mirage_crypto_rng.g ]
(** Masking (cryptographic blinding) option. *)
val pub_of_priv : priv -> pub
(** Extract the public component from a private key. *)
val generate : ?g:Mirage_crypto_rng.g -> keysize -> priv
(** [generate g size] is a fresh {{!type-priv}private} key. The domain parameters
are derived using a modified FIPS.186-4 probabilistic process, but the
derivation can not be validated. Note that no time masking is done for the
modular exponentiations.
{b Note} The process might diverge if it is impossible to find parameters
with the given bit sizes. This happens when [n] gets too big for [l], if
the [size] was given as [`Exactly (l, n)].
@raise Invalid_argument if [size] is (`Exactly (l, n)), and either [l] or
[n] is ridiculously small. *)
val sign : ?mask:mask -> ?k:Z.t -> key:priv -> string -> string * string
(** [sign ~mask ~k ~key digest] is the signature, a pair of strings
representing [r] and [s] in big-endian.
[digest] is the full digest of the actual message.
[k], the random component, can either be provided, or is deterministically
derived as per RFC6979, using SHA256.
@raise Invalid_argument if [k] is unsuitable (leading to r or s being 0).
*)
val verify : key:pub -> string * string -> string -> bool
(** [verify ~key (r, s) digest] verifies that the pair [(r, s)] is the signature
of [digest], the message digest, under the private counterpart to [key]. *)
val massage : key:pub -> string -> string
(** [massage key digest] is the numeric value of [digest] taken modulo [q] and
represented in the leftmost [bits(q)] bits of the result.
Both FIPS.186-4 and RFC6979 specify that only the leftmost [bits(q)] bits of
[digest] are to be taken into account, but some implementations consider the
entire [digest]. In cases where {{!sign}sign} and {{!verify}verify} seem
incompatible with a given implementation (esp. if {{!sign}sign} produces
signatures with the [s] component different from the other
implementation's), it might help to pre-process [digest] using this
function (e.g. [sign ~key (massage ~key:(pub_of_priv key) digest)]). *)
(** [K_gen] can be instantiated over a hashing module to obtain an RFC6979
compliant [k]-generator for that hash. *)
module K_gen (H : Digestif.S) : sig
val generate : key:priv -> string -> Z.t
(** [generate key digest] deterministically takes the given private key and
message digest to a [k] suitable for seeding the signing process. *)
end
end
(** Diffie-Hellman, MODP version. *)
module Dh : sig
(** {1 Diffie-Hellman key exchange} *)
exception Invalid_key
(** Raised if the private key material is degenerate.
The following invariants are checked:
Secret key: [1 < secret < p]
Public key: [1 < public < p-1] && [public <> gg]
*)
type group = private {
p : Z.t ; (** modulus *)
gg : Z.t ; (** generator *)
q : Z.t option ; (** subgroup order; potentially unknown *)
}
(** A DH group. *)
val group : p:Z.t -> gg:Z.t -> ?q:Z.t -> unit ->
(group, [> `Msg of string ]) result
(** [group ~p ~gg ~q ()] constructs a group if [p] is odd, a prime number,
and greater than [zero]. [gg] must be in the range [1 < gg < p]. *)
type secret = private { group : group ; x : Z.t }
(** A private key. *)
val modulus_size : group -> int
(** Bit size of the modulus. *)
val key_of_secret : group -> s:string -> secret * string
(** [key_of_secret group s] is the {!secret} and the corresponding public
key which use [s] as the secret exponent.
@raise Invalid_key if [s] is degenerate. *)
val gen_key : ?g:Mirage_crypto_rng.g -> ?bits:int -> group -> secret * string
(** Generate a random {!secret} and the corresponding public key.
[bits] is the exact bit-size of {!secret} and defaults to a value
dependent on the {!type-group}'s [p].
{b Note} The process might diverge when [bits] is extremely small. *)
val shared : secret -> string -> string option
(** [shared secret public] is [Some shared_key] given a
a previously generated {!secret} (which specifies the [group])
and the other party's public key.
[shared_key] is the unpadded big-endian representation of the shared key.
It is [None] if these invariants do not hold for [public]:
[1 < public < p-1] && [public <> gg]. *)
val gen_group : ?g:Mirage_crypto_rng.g -> bits:int -> unit -> group
(** [gen_group ~g ~bits ()] generates a random {!type-group} with modulus size
[bits]. Uses a safe prime [p = 2q + 1] (with [q] prime) for the modulus
and [2] for the generator, such that [2^q = 1 mod p].
Runtime is on the order of a minute for 1024 bits.
Note that no time masking is done for the modular exponentiation.
{b Note} The process might diverge if there are no suitable groups. This
happens with extremely small [bits] values. *)
(** A small catalog of standardized {!type-group}s. *)
module Group : sig
(** From RFC 2409: *)
val oakley_1 : group
val oakley_2 : group
(** From RFC 3526: *)
val oakley_5 : group
val oakley_14 : group
val oakley_15 : group
val oakley_16 : group
val oakley_17 : group
val oakley_18 : group
(** From RFC 5114: *)
val rfc_5114_1 : group
val rfc_5114_2 : group
val rfc_5114_3 : group
(** From draft-ietf-tls-negotiated-ff-dhe-08 *)
val ffdhe2048 : group
val ffdhe3072 : group
val ffdhe4096 : group
val ffdhe6144 : group
val ffdhe8192 : group
end
end
(** {b Z} Convert Z to big endian string and generate random Z values. *)
module Z_extra : sig
(** {1 Conversion to and from string} *)
val of_octets_be : ?bits:int -> string -> Z.t
(** [of_octets_be ~bits buf] interprets the bit pattern of [buf] as a
{{!Z.t}[t]} in big-endian.
If [~bits] is not given, the operation considers the entire [buf],
otherwise the initial [min ~bits (bit-length buf)] bits of [buf].
Assuming [n] is the number of bits to extract, the [n]-bit in [buf] is
always the least significant bit of the result. Therefore:
{ul
{- if the bit size [k] of [t] is larger than [n], [k - n] most
significant bits in the result are [0]; and}
{- if [k] is smaller than [n], the result contains [k] last of the [n]
first bits of [buf].}} *)
val to_octets_be : ?size:int -> Z.t -> string
(** [to_octets_be ~size t] is the big-endian representation of [t].
If [~size] is not given, it defaults to the minimal number of bytes
needed to represent [t], which is [bits t / 8] rounded up.
The least-significant bit of [t] is always the last bit in the result.
If the size is larger than needed, the output is padded with zero bits.
If it is smaller, the high bits in [t] are dropped. *)
val into_octets_be : Z.t -> bytes -> unit
(** [into_octets_be t buf] writes the big-endian representation of [t] into
[buf]. It behaves like {{!to_octets_be}[to_octets_be]}, with [~size]
spanning the entire [buf]. *)
(** {1 Random generation} *)
val gen : ?g:Mirage_crypto_rng.g -> Z.t -> Z.t
(** [gen ~g n] picks a value in the interval [\[0, n - 1\]] uniformly at random. *)
val gen_r : ?g:Mirage_crypto_rng.g -> Z.t -> Z.t -> Z.t
(** [gen_r ~g low high] picks a value from the interval [\[low, high - 1\]]
uniformly at random. *)
end

View file

@ -0,0 +1,430 @@
open Mirage_crypto.Uncommon
open Common
let two = Z.(~$2)
and three = Z.(~$3)
(* A constant-time [find_uint8] with a default value. *)
let ct_find_uint8 ~default ?off ~f cs =
let res = Eqaf.find_uint8 ?off ~f cs in
Eqaf.select_int (res + 1) default res
let (&.) f g = fun h -> f (g h)
type 'a or_digest = [ `Message of 'a | `Digest of string ]
module Digest_or (H : Digestif.S) = struct
let digest_or = function
| `Message msg -> H.(digest_string msg |> to_raw_string)
| `Digest digest ->
let n = String.length digest and m = H.digest_size in
if n = m then digest else
invalid_arg "(`Digest _): %d bytes, expecting %d" n m
end
exception Insufficient_key
type pub = { e : Z.t ; n : Z.t }
(* due to PKCS1 *)
let minimum_octets = 12
let minimum_bits = 8 * minimum_octets - 7
let pub ~e ~n =
(* We cannot verify a public key being good (this would require to verify "n"
being the multiplication of two prime numbers - figuring out which primes
were used is the security property of RSA).
but we validate to ensure our usage of powm_sec does not lead to
exceptions, and we avoid tiny public keys where PKCS1 / PSS would lead to
infinite loops or not work due to insufficient space for the header. *)
let* () =
guard Z.(n > zero && is_odd n && numbits n >= minimum_bits)
(`Msg "invalid modulus")
in
let* () = guard Z.(one < e && e < n) (`Msg "invalid exponent") in
(* NOTE that we could check for e being odd, or a prime, or 2^16+1, but
these are not requirements, neither for RSA nor for powm_sec *)
Ok { e ; n }
type priv = {
e : Z.t ; d : Z.t ; n : Z.t ;
p : Z.t ; q : Z.t ; dp : Z.t ; dq : Z.t ; q' : Z.t
}
let valid_prime name p =
guard Z.(p > zero && is_odd p && Z_extra.pseudoprime p)
(`Msg ("invalid prime " ^ name))
let rprime a b = Z.(gcd a b = one)
let valid_e ~e ~p ~q =
let* () =
guard (rprime e (Z.pred p) && rprime e (Z.pred q))
(`Msg "e is not coprime of p and q")
in
guard (Z_extra.pseudoprime e) (`Msg "exponent e is not a pseudoprime")
let priv ~e ~d ~n ~p ~q ~dp ~dq ~q' =
let* _ = pub ~e ~n in
let* () = valid_prime "p" p in
let* () = valid_prime "q" q in
let* () = guard (p <> q) (`Msg "p and q are the same number") in
let* () = valid_e ~e ~p ~q in
(* p and q are prime, and not equal -> multiplicative inverse exists *)
let* () = guard Z.(q' = invert q p) (`Msg "q' <> q ^ -1 mod p") in
let* () = guard Z.(n = p * q) (`Msg "modulus is not the product of p and q") in
let* () = guard Z.(one < d && d < n) (`Msg "invalid private exponent") in
let* () = guard Z.(dp = d mod (pred p)) (`Msg "dp <> d mod (p - 1)") in
let* () = guard Z.(dq = d mod (pred q)) (`Msg "dq <> d mod (q - 1)") in
(* e has been checked (valid_e) to be coprime to p-1 and q-1 ->
muliplicative inverse exists *)
let* () =
guard Z.(one = d * e mod (lcm (pred p) (pred q)))
(`Msg "1 <> d * e mod lcm (p - 1) (q - 1)")
in
Ok { e ; d ; n ; p ; q ; dp ; dq ; q' }
let priv_of_primes ~e ~p ~q =
let* () = valid_prime "p" p in
let* () = valid_prime "q" q in
let* () = guard (p <> q) (`Msg "p and q are the same prime") in
let* () = valid_e ~e ~p ~q in
let n = Z.(p * q) in
let* _ = pub ~e ~n in
(* valid_e checks e coprime to p-1 and q-1, a multiplicative inverse exists *)
let d = Z.(invert e (lcm (pred p) (pred q))) in
let dp = Z.(d mod (pred p))
and dq = Z.(d mod (pred q))
in
(* above we checked that p and q both are primes and not equal -> there
should be a multiplicate inverse *)
let q' = Z.invert q p in
(* does not need to check valid_priv, since it is valid by construction *)
Ok { e; d; n; p; q; dp; dq; q' }
(* Handbook of applied cryptography, 8.2.2 (i). *)
let priv_of_exp ?g ?(attempts=100) ~e ~d ~n () =
let* _ = pub ~e ~n in
let* () = guard Z.(one < d && d < n) (`Msg "invalid private exponent") in
let rec doit ~attempts =
let factor s t =
let rec go ax = function
| 0 -> None
| i' ->
let ax2 = Z.(ax * ax mod n) in
if Z.(ax <> one && ax <> pred n && ax2 = one) then
Some ax
else
go ax2 (i' - 1)
in
Option.map Z.(gcd n &. pred) (go Z.(powm (Z_extra.gen ?g n) t n) s)
in
if attempts > 0 then
let* s, t = Z_extra.strip_factor ~f:two Z.(e * d |> pred) in
match s with
| 0 -> Error (`Msg "invalid factor 0")
| _ -> match factor s t with
| None -> doit ~attempts:(attempts - 1)
| Some p ->
let q = Z.(div n p) in
priv_of_primes ~e ~p:(max p q) ~q:(min p q)
else Error (`Msg "attempts exceeded")
in
doit ~attempts
let rec generate ?g ?(e = Z.(~$0x10001)) ~bits () =
if bits < minimum_bits || e < three ||
(bits <= Z.numbits e || not (Z_extra.pseudoprime e))
then
invalid_arg "Rsa.generate: e: %a, bits: %d" Z.pp_print e bits;
let (pb, qb) = (bits / 2, bits - bits / 2) in
let (p, q) = Z_extra.(prime ?g ~msb:2 pb, prime ?g ~msb:2 qb) in
match priv_of_primes ~e ~p:(max p q) ~q:(min p q) with
| Error _ -> generate ?g ~e ~bits ()
| Ok priv -> priv
let pub_of_priv ({ e; n; _ } : priv) = { e ; n }
let pub_bits ({ n; _ } : pub) = Z.numbits n
and priv_bits ({ n; _ } : priv) = Z.numbits n
type mask = [ `No | `Yes | `Yes_with of Mirage_crypto_rng.g ]
let encrypt_unsafe ~key: ({ e; n } : pub) msg = Z.(powm msg e n)
let decrypt_unsafe ~crt_hardening ~key:({ e; d; n; p; q; dp; dq; q'} : priv) c =
let m1 = Z.(powm_sec c dp p)
and m2 = Z.(powm_sec c dq q) in
(* NOTE: neither erem, nor the multiplications (addition, subtraction) are
guaranteed to be constant time by gmp *)
let h = Z.(erem (q' * (m1 - m2)) p) in
let m = Z.(h * q + m2) in
(* counter Arjen Lenstra's CRT attack by verifying the signature. Since the
public exponent is small, this is not very expensive. Mentioned again
"Factoring RSA keys with TLS Perfect Forward Secrecy" (Weimer, 2015). *)
if not crt_hardening || Z.(powm_sec m e n) = c then
m
else
Z.(powm_sec c d n)
let decrypt_blinded_unsafe ~crt_hardening ?g ~key:({ e; n; _} as key : priv) c =
let r = until (rprime n) (fun _ -> Z_extra.gen_r ?g two n) in
(* since r and n are coprime, there must be a multiplicative inverse *)
let r' = Z.(invert r n) in
let c' = Z.(powm_sec r e n * c mod n) in
let x = decrypt_unsafe ~crt_hardening ~key c' in
Z.(r' * x mod n)
let (encrypt_z, decrypt_z) =
let check_params n msg =
if msg < two then invalid_arg "Rsa: message: %a" Z.pp_print msg;
if n <= msg then raise Insufficient_key in
(fun ~(key : pub) msg -> check_params key.n msg ; encrypt_unsafe ~key msg),
(fun ~crt_hardening ~mask ~(key : priv) msg ->
check_params key.n msg ;
match mask with
| `No -> decrypt_unsafe ~crt_hardening ~key msg
| `Yes -> decrypt_blinded_unsafe ~crt_hardening ~key msg
| `Yes_with g -> decrypt_blinded_unsafe ~crt_hardening ~g ~key msg )
let reformat out f msg =
Z_extra.(of_octets_be msg |> f |> to_octets_be ~size:(out // 8))
let encrypt ~key = reformat (pub_bits key) (encrypt_z ~key)
let decrypt ?(crt_hardening=false) ?(mask=`Yes) ~key =
reformat (priv_bits key) (decrypt_z ~crt_hardening ~mask ~key)
let bx00, bx01 = "\x00", "\x01"
module PKCS1 = struct
let min_pad = 8
(* XXX Generalize this into `Rng.samplev` or something. *)
let generate_with ?g ~f n =
let buf = Bytes.create n
and k = let b = Mirage_crypto_rng.block g in (n // b * b) in
let rec go nonce i j =
if i = n then Bytes.unsafe_to_string buf else
if j = k then go Mirage_crypto_rng.(generate ?g k) i 0 else
match String.get_uint8 nonce j with
| b when f b -> Bytes.set_uint8 buf i b ; go nonce (succ i) (succ j)
| _ -> go nonce i (succ j) in
go Mirage_crypto_rng.(generate ?g k) 0 0
let pad ~mark ~padding k msg =
let pad = padding (k - String.length msg - 3 |> imax min_pad) in
String.concat "" [ bx00 ; mark ; pad ; bx00 ; msg ]
let unpad ~mark ~is_pad buf =
let f = not &. is_pad in
let i = ct_find_uint8 ~default:2 ~off:2 ~f buf in
let c1 = String.get_uint8 buf 0 = 0x00
and c2 = String.get_uint8 buf 1 = mark
and c3 = String.get_uint8 buf i = 0x00
and c4 = min_pad <= i - 2 in
if c1 && c2 && c3 && c4 then
Some (String.sub buf (i + 1) (String.length buf - i - 1))
else None
let pad_01 =
let padding size = String.make size '\xff' in
pad ~mark:"\x01" ~padding
let pad_02 ?g = pad ~mark:"\x02" ~padding:(generate_with ?g ~f:((<>) 0x00))
let unpad_01 = unpad ~mark:0x01 ~is_pad:((=) 0xff)
let unpad_02 = unpad ~mark:0x02 ~is_pad:((<>) 0x00)
let padded pad transform keybits msg =
let n = keybits // 8 in
let p = pad n msg in
if String.length p = n then transform p else raise Insufficient_key
let unpadded unpad transform keybits msg =
if String.length msg = keybits // 8 then
try unpad (transform msg) with Insufficient_key -> None
else None
let sig_encode ?(crt_hardening = true) ?mask ~key msg =
padded pad_01 (decrypt ~crt_hardening ?mask ~key) (priv_bits key) msg
let sig_decode ~key msg =
unpadded unpad_01 (encrypt ~key) (pub_bits key) msg
let encrypt ?g ~key msg =
padded (pad_02 ?g) (encrypt ~key) (pub_bits key) msg
let decrypt ?(crt_hardening = false) ?mask ~key msg =
unpadded unpad_02 (decrypt ~crt_hardening ?mask ~key) (priv_bits key) msg
let asn_of_hash, detect =
let map = [
`MD5, "\x30\x20\x30\x0c\x06\x08\x2a\x86\x48\x86\xf7\x0d\x02\x05\x05\x00\x04\x10" ;
`SHA1, "\x30\x21\x30\x09\x06\x05\x2b\x0e\x03\x02\x1a\x05\x00\x04\x14" ;
`SHA224, "\x30\x2d\x30\x0d\x06\x09\x60\x86\x48\x01\x65\x03\x04\x02\x04\x05\x00\x04\x1c" ;
`SHA256, "\x30\x31\x30\x0d\x06\x09\x60\x86\x48\x01\x65\x03\x04\x02\x01\x05\x00\x04\x20" ;
`SHA384, "\x30\x41\x30\x0d\x06\x09\x60\x86\x48\x01\x65\x03\x04\x02\x02\x05\x00\x04\x30" ;
`SHA512, "\x30\x51\x30\x0d\x06\x09\x60\x86\x48\x01\x65\x03\x04\x02\x03\x05\x00\x04\x40"
]
in
(fun h -> List.assoc h map),
(fun buf -> List.find_opt (fun (_, d) -> String.starts_with ~prefix:d buf) map)
let sign ?(crt_hardening = true) ?mask ~hash ~key msg =
let module H = (val Digestif.module_of_hash' (hash :> Digestif.hash')) in
let module D = Digest_or(H) in
let msg' = asn_of_hash hash ^ D.digest_or msg in
sig_encode ~crt_hardening ?mask ~key msg'
let verify ~hashp ~key ~signature msg =
let (>>=) = Option.bind
and (>>|) = Fun.flip Option.map
in
Option.value
(sig_decode ~key signature >>= fun buf ->
detect buf >>| fun (hash, asn) ->
let module H = (val Digestif.module_of_hash' (hash :> Digestif.hash')) in
let module D = Digest_or(H) in
hashp hash && Eqaf.equal (asn ^ D.digest_or msg) buf)
~default:false
let min_key hash =
let module H = (val Digestif.module_of_hash' (hash :> Digestif.hash')) in
(String.length (asn_of_hash hash) + H.digest_size + min_pad + 2) * 8 + 1
end
module MGF1 (H : Digestif.S) = struct
let repr n =
let buf = Bytes.create 4 in
Bytes.set_int32_be buf 0 n;
Bytes.unsafe_to_string buf
(* Assumes len < 2^32 * H.digest_size. *)
let mgf ~seed len =
let rec go acc c = function
| 0 -> Bytes.sub (Bytes.concat Bytes.empty (List.rev acc)) 0 len
| n ->
let h = Bytes.create H.digest_size in
H.get_into_bytes (H.feedi_string H.empty (iter2 seed (repr c))) h;
go (h :: acc) Int32.(succ c) (pred n)
in
go [] 0l (len // H.digest_size)
let mask ~seed buf =
let mgf_data = mgf ~seed (String.length buf) in
unsafe_xor_into buf ~src_off:0 mgf_data ~dst_off:0 (String.length buf);
mgf_data
end
module OAEP (H : Digestif.S) = struct
module MGF = MGF1 (H)
let hlen = H.digest_size
let max_msg_bytes k = k - 2 * hlen - 2
let eme_oaep_encode ?g ?(label = "") k msg =
let seed = Mirage_crypto_rng.generate ?g hlen
and pad = String.make (max_msg_bytes k - String.length msg) '\x00' in
let db = String.concat "" [ H.(digest_string label |> to_raw_string) ; pad ; bx01 ; msg ] in
let mdb = Bytes.unsafe_to_string (MGF.mask ~seed db) in
let mseed = Bytes.unsafe_to_string (MGF.mask ~seed:mdb seed) in
String.concat "" [ bx00 ; mseed ; mdb ]
let eme_oaep_decode ?(label = "") msg =
let b0 = String.sub msg 0 1
and ms = String.sub msg 1 hlen
and mdb = String.sub msg (1 + hlen) (String.length msg - 1 - hlen)
in
let db = Bytes.unsafe_to_string (MGF.mask ~seed:(Bytes.unsafe_to_string (MGF.mask ~seed:mdb ms)) mdb) in
let i = ct_find_uint8 ~default:0 ~off:hlen ~f:((<>) 0x00) db in
let c1 = Eqaf.equal (String.sub db 0 hlen) H.(digest_string label |> to_raw_string)
and c2 = String.get_uint8 b0 0 = 0x00
and c3 = String.get_uint8 db i = 0x01 in
if c1 && c2 && c3 then Some (String.sub db (i + 1) (String.length db - i - 1)) else None
let encrypt ?g ?label ~key msg =
let k = pub_bits key // 8 in
if String.length msg > max_msg_bytes k then raise Insufficient_key
else encrypt ~key @@ eme_oaep_encode ?g ?label k msg
let decrypt ?(crt_hardening = false) ?mask ?label ~key em =
let k = priv_bits key // 8 in
if String.length em <> k || max_msg_bytes k < 0 then None else
try eme_oaep_decode ?label @@ decrypt ~crt_hardening ?mask ~key em
with Insufficient_key -> None
(* XXX Review rfc3447 7.1.2 and
* http://archiv.infsec.ethz.ch/education/fs08/secsem/Manger01.pdf
* again for timing properties. *)
(* XXX expose seed for deterministic testing? *)
end
module PSS (H: Digestif.S) = struct
module MGF = MGF1 (H)
module H1 = Digest_or (H)
let hlen = H.digest_size
let bxbc = "\xbc"
let b0mask embits = 0xff lsr ((8 - embits mod 8) mod 8)
let zero_8 = String.make 8 '\x00'
let digest ~salt msg =
H.to_raw_string @@ H.digesti_string @@ iter3 zero_8 (H1.digest_or msg) salt
let emsa_pss_encode ?g slen emlen msg =
let n = emlen // 8
and salt = Mirage_crypto_rng.generate ?g slen in
let h = digest ~salt msg in
let db = String.concat "" [ String.make (n - slen - hlen - 2) '\x00' ; bx01 ; salt ] in
let mdb = MGF.mask ~seed:h db in
Bytes.set_uint8 mdb 0 @@ Bytes.get_uint8 mdb 0 land b0mask emlen ;
String.concat "" [ Bytes.unsafe_to_string mdb ; h ; bxbc ]
let emsa_pss_verify slen emlen em msg =
let mdb = String.sub em 0 (String.length em - hlen - 1)
and h = String.sub em (String.length em - hlen - 1) hlen
and bxx = String.get_uint8 em (String.length em - 1)
in
let db = MGF.mask ~seed:h mdb in
Bytes.set_uint8 db 0 (Bytes.get_uint8 db 0 land b0mask emlen) ;
let db = Bytes.unsafe_to_string db in
let salt = String.sub db (String.length db - slen) slen in
let h' = digest ~salt:salt msg
and i = ct_find_uint8 ~default:0 ~f:((<>) 0x00) db in
let c1 = lnot (b0mask emlen) land String.get_uint8 mdb 0 = 0x00
and c2 = i = String.length em - hlen - slen - 2
and c3 = String.get_uint8 db i = 0x01
and c4 = bxx = 0xbc
and c5 = Eqaf.equal h h' in
c1 && c2 && c3 && c4 && c5
let sufficient_key ~slen kbits =
hlen + slen + 2 <= kbits / 8 (* 8 * (hlen + slen + 1) + 2 <= kbits *)
let sign ?g ?(crt_hardening = false) ?mask ?(slen = hlen) ~key msg =
let b = priv_bits key in
if not (sufficient_key ~slen b) then raise Insufficient_key
else
let msg' = emsa_pss_encode ?g (imax 0 slen) (b - 1) msg in
decrypt ~crt_hardening ?mask ~key msg'
let verify ?(slen = hlen) ~key ~signature msg =
let b = pub_bits key
and s = String.length signature in
s = b // 8 && sufficient_key ~slen b && try
let em = encrypt ~key signature in
let to_see = s - (b - 1) // 8 in
emsa_pss_verify (imax 0 slen) (b - 1) (String.sub em to_see (String.length em - to_see)) msg
with Insufficient_key -> false
end

View file

@ -0,0 +1,135 @@
open Mirage_crypto.Uncommon
let bit_bound z = Z.size z * 64
let of_octets_be ?bits buf =
let rec loop acc i = function
| b when b >= 64 ->
let x = String.get_int64_be buf i in
let x = Z.of_int64_unsigned Int64.(shift_right_logical x 8) in
loop Z.(x + acc lsl 56) (i + 7) (b - 56)
| b when b >= 32 ->
let x = String.get_int32_be buf i in
let x = Z.of_int32_unsigned Int32.(shift_right_logical x 8) in
loop Z.(x + acc lsl 24) (i + 3) (b - 24)
| b when b >= 16 ->
let x = Z.of_int (String.get_uint16_be buf i) in
loop Z.(x + acc lsl 16) (i + 2) (b - 16)
| b when b >= 8 ->
let x = Z.of_int (String.get_uint8 buf i) in
loop Z.(x + acc lsl 8 ) (i + 1) (b - 8 )
| b when b > 0 ->
let x = String.get_uint8 buf i and b' = 8 - b in
Z.(of_int x asr b' + acc lsl b)
| _ -> acc in
loop Z.zero 0 @@ match bits with
| None -> String.length buf * 8
| Some b -> imin b (String.length buf * 8)
let byte1 = Z.of_int64 0xffL
and byte2 = Z.of_int64 0xffffL
and byte3 = Z.of_int64 0xffffffL
and byte7 = Z.of_int64 0xffffffffffffffL
let into_octets_be n buf =
let rec write n = function
| i when i >= 7 ->
Bytes.set_int64_be buf (i - 7) Z.(to_int64_unsigned (n land byte7)) ;
write Z.(n asr 56) (i - 7)
| i when i >= 3 ->
Bytes.set_int32_be buf (i - 3) Z.(to_int32_unsigned (n land byte3)) ;
write Z.(n asr 24) (i - 3)
| i when i >= 1 ->
Bytes.set_uint16_be buf (i - 1) Z.(to_int (n land byte2)) ;
write Z.(n asr 16) (i - 2)
| 0 -> Bytes.set_uint8 buf 0 Z.(to_int (n land byte1)) ;
| _ -> ()
in
write n (Bytes.length buf - 1)
let to_octets_be ?size n =
let buf = Bytes.create @@ match size with
| Some s -> imax 0 s
| None -> Z.numbits n // 8 in
into_octets_be n buf;
Bytes.unsafe_to_string buf
(* Handbook of Applied Cryptography, Table 4.4:
* Miller-Rabin rounds for composite probability <= 1/2^80. *)
let pseudoprime z =
let i = match Z.numbits z with
| i when i >= 1300 -> 2
| i when i >= 850 -> 3
| i when i >= 650 -> 4
| i when i >= 350 -> 8
| i when i >= 250 -> 12
| i when i >= 150 -> 18
| _ -> 27 in
Z.probab_prime z i <> 0
(* strip_factor ~f x = (s, t), where x = f^s t *)
let strip_factor ~f x =
let rec go n x =
let (x1, r) = Z.div_rem x f in
if r = Z.zero then go (succ n) x1 else Ok (n, x)
in
if Z.(~$2) <= f then
go 0 x
else
Error (`Msg ("factor_count: f: " ^ Z.to_string f))
let gen ?g n =
if n < Z.one then invalid_arg "Rng.gen: non-positive: %a" Z.pp_print n;
let bs = Mirage_crypto_rng.block g in
let bits = Z.(numbits (pred n)) in
let octets = bits // 8 in
let batch =
if Mirage_crypto_rng.strict g then octets else 2 * octets // bs * bs
in
let rec attempt buf =
if String.length buf >= octets then
let x = of_octets_be ~bits buf in
if x < n then x else attempt (String.sub buf octets (String.length buf - octets))
else attempt (Mirage_crypto_rng.generate ?g batch) in
attempt (Mirage_crypto_rng.generate ?g batch)
let rec gen_r ?g a b =
if Mirage_crypto_rng.strict g then
let x = gen ?g b in if x < a then gen_r ?g a b else x
else Z.(a + gen ?g (b - a))
let set_msb bits buf =
if bits > 0 then
let n = Bytes.length buf in
let rec go width = function
| i when i = n -> ()
| i when width < 8 ->
Bytes.set_uint8 buf i (Bytes.get_uint8 buf i lor (0xff lsl (8 - width)))
| i ->
Bytes.set_uint8 buf i 0xff ;
go (width - 8) (succ i)
in
go bits 0
let gen_bits ?g ?(msb = 0) bits =
let bytelen = bits // 8 in
let buf = Bytes.create bytelen in
Mirage_crypto_rng.generate_into ?g buf ~off:0 bytelen;
set_msb msb buf ;
of_octets_be ~bits (Bytes.unsafe_to_string buf)
(* Invalid combinations of ~bits and ~msb will loop forever, but there is no
* way to quickly determine upfront whether there are any primes in the
* interval.
* XXX Probability is distributed as inter-prime gaps. So?
*)
let rec prime ?g ?(msb = 1) bits =
let p = Z.(nextprime @@ gen_bits ?g ~msb bits) in
if p < Z.(one lsl bits) then p else prime ?g ~msb bits
(* XXX Add ~msb param for p? *)
let rec safe_prime ?g bits =
let q = prime ?g ~msb:1 (bits - 1) in
let p = Z.(q * ~$2 + ~$1) in
if pseudoprime p then (q, p) else safe_prime ?g bits