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,63 @@
(library
(name test_common)
(libraries mirage-crypto ounit2 ohex)
(modules test_common)
(optional))
(test
(name test_symmetric_runner)
(libraries test_common mirage-crypto ounit2)
(package mirage-crypto)
(modules test_base test_cipher test_symmetric_runner))
(test
(name test_random_runner)
(libraries test_common mirage-crypto mirage-crypto-rng mirage-crypto-rng.unix
randomconv ounit2)
(package mirage-crypto-rng)
(modules test_random_runner))
(test
(name test_pk_runner)
(libraries test_common mirage-crypto-pk mirage-crypto-rng.unix randomconv
ounit2)
(package mirage-crypto-pk)
(modules test_numeric test_dh test_dsa test_rsa test_pk_runner))
(test
(name test_entropy_collection)
(modules test_entropy_collection)
(package mirage-crypto-rng-mirage)
(libraries mirage-crypto-rng-mirage mirage-unix duration ohex))
(test
(name test_entropy)
(modules test_entropy)
(package mirage-crypto-rng)
(libraries mirage-crypto-rng ohex)
(enabled_if (and (<> %{architecture} "arm64") (<> %{architecture} "riscv64"))))
; see https://github.com/mirage/mirage-crypto/issues/216
(test
(name test_ec)
(modules test_ec)
(libraries test_common alcotest mirage-crypto-ec mirage-crypto-rng.unix)
(package mirage-crypto-ec))
(test
(name test_ec_wycheproof)
(modules test_ec_wycheproof)
(deps ecdh_secp256r1_test.json ecdsa_secp256r1_sha256_test.json
ecdsa_secp256r1_sha512_test.json ecdh_secp384r1_test.json
ecdsa_secp384r1_sha384_test.json ecdsa_secp384r1_sha512_test.json
ecdh_secp521r1_test.json ecdsa_secp521r1_sha512_test.json
x25519_test.json eddsa_test.json)
(libraries alcotest mirage-crypto-ec wycheproof digestif asn1-combinators)
(package mirage-crypto-ec))
(tests
(names test_miou_rng test_miou_entropy_collection)
(modules test_miou_rng test_miou_entropy_collection)
(libraries mirage-crypto-rng-miou-unix duration ohex)
(package mirage-crypto-rng-miou-unix)
(enabled_if (<> %{os_type} "Win32")))

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,135 @@
let mem f =
let t = Hashtbl.create 100 in
fun x ->
try Hashtbl.find t x with
| Not_found ->
let r = f x in ( Hashtbl.add t x r ; r )
(* An [admittedly primitive] implementation of Pollards p-1 factoring method. *)
module Pollard = struct
let primes_to n =
let rec scan = function
| p when p > n -> []
| p -> p :: scan Z.(nextprime p) in
scan (Z.of_int 2)
let max_pow limit x =
let rec expand lower upper =
if Z.(pow x upper) > limit then (lower, upper)
else expand upper (upper * 2)
and narrow lower upper =
if upper - lower = 1 then lower else
let mid = (lower + upper) / 2 in
if Z.(pow x mid) > limit then
narrow lower mid
else narrow mid upper
in
let (l, u) = expand 1 2 in
narrow l u
let ppowers_to n =
let rec scan = function
| p when p > n -> []
| p ->
let pp = Z.pow p (max_pow n p) in
pp :: scan Z.(nextprime p) in
scan (Z.of_int 2)
let note ~msg f =
Printf.printf "[%s] ->\n%!" msg ;
let r = f () in
Printf.printf "[%s] <-\n%!" msg ;
r
let prime_pows_to_prod = mem @@ fun n ->
let rec scan acc = function
| p when p > n -> acc
| p -> scan Z.(acc * (pow p (max_pow n p)))
Z.(nextprime p) in
note ~msg:"powers" @@ fun () ->
scan Z.one Z.(of_int 2)
let split ~limit n =
let a = Nums.Z.gen n in
match Z.gcd n a with
| d when d > Z.one -> a
| d ->
let rec scan a m =
let x = Z.(powm a (m * n) n) in
if Z.(x = one) then
if Z.(m mod of_int 2 = zero) then
scan a Z.(m / of_int 2)
else raise Not_found
else
let d = Z.(gcd (x - one) n) in
if Z.(d > one) then d else raise Not_found
in
scan a (prime_pows_to_prod limit)
end
module RSA_misc = struct
let slack = 8
(* Rivest's p-minus strong prime generator. *)
let rec pm_strong_prime ?g ~bits =
let a_lim = Z.(pow z_two slack - one)
in
let rec mul_seq p = function
| a when a > a_lim ->
Printf.printf "++ mul seq: falling off the cliff.\n%!";
None
| a ->
let p' = Z.(a * p + one) in
match Z.probab_prime p' 25 with
| 0 ->
Printf.printf "+ mul seq: climb.\n%!";
mul_seq p Z.(a + z_two)
| _ ->
Printf.printf "** mul seq: prime with %s\n%!" Z.(to_string a);
Some p'
in
let pmm = prime ?g ~bits in
match mul_seq pmm z_two with
| None -> pm_strong_prime ?g ~bits
| Some pm ->
match mul_seq pm z_two with
| None -> pm_strong_prime ?g ~bits
| Some p -> (pmm, pm, p)
let slim = Z.(pow z_two 8)
(* Williams/Schmid strong prime generator. *)
let rec p_strong_prime1 ?g ~bits =
let (bits1, bits2) = (bits / 2, bits - bits / 2)
in
let pmm = prime ?g ~bits:bits1
and pp = prime ?g ~bits:bits2 in
let r = Z.(pp - invert pmm pp)
in
let rec find_a = function
| a when a >= slim ->
Printf.printf "off the cliff...\n%!" ;
p_strong_prime1 ?g ~bits
| a ->
let pm = Z.(z_two * a * pmm * pp + z_two * r * pmm + one) in
match Z.probab_prime pm 25 with
| 0 -> find_a Z.(a + one)
| _ ->
let p = Z.(z_two * pm + one) in
match Z.probab_prime p 25 with
| 0 -> find_a Z.(a + one)
| _ ->
Printf.printf "found pm, p with %s\n%!" Z.(to_string a);
(pmm, pm, pp, p)
in
find_a z_two
end

View file

@ -0,0 +1,26 @@
open OUnit2
open Mirage_crypto
open Test_common
(* Xor *)
let xor_cases =
cases_of (f2_eq ~msg:"xor" Uncommon.xor) [
"00 01 02 03 04 05 06 07 08 09 0a 0b 0c" ,
"0c 0b 0a 09 08 07 06 05 04 03 02 01 00" ,
"0c 0a 08 0a 0c 02 00 02 0c 0a 08 0a 0c" ;
"00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f" ,
"0f 0e 0d 0c 0b 0a 09 08 07 06 05 04 03 02 01 00" ,
"0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f" ;
"00", "00", "00" ;
"", "", "" ;
]
let suite = [
"XOR" >::: [ "example" >::: xor_cases ];
]

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,68 @@
open OUnit2
let (prf, strf) = Format.(fprintf, asprintf)
let pp_map pp f ppf x = pp ppf (f x)
let pp_diff pp ppf (a, b) = prf ppf "@[<v>want: %a@,have: %a@]" pp a pp b
let of_hex ?(skip_ws = true) s =
let fold f acc str =
let st = ref acc in
String.iter (fun c -> st := f !st c) str;
!st
and digit c =
match c with
| '0'..'9' -> int_of_char c - 0x30
| 'A'..'F' -> int_of_char c - 0x41 + 10
| 'a'..'f' -> int_of_char c - 0x61 + 10
| _ -> invalid_arg "bad character"
and is_space = function
| ' ' | '\012' | '\n' | '\r' | '\t' -> true
| _ -> false
in
let chars, leftover =
fold (fun (chars, leftover) c ->
if skip_ws && is_space c then
chars, leftover
else
let c = digit c in
match leftover with
| None -> chars, Some (c lsl 4)
| Some c' -> (c' lor c) :: chars, None)
([], None) s
in
let chars = List.rev chars in
assert (leftover = None);
String.init (List.length chars) (fun i -> char_of_int (List.nth chars i))
let rec range a b =
if a > b then [] else a :: range (succ a) b
let rec times ~n f a =
if n > 0 then ( ignore (f a) ; times ~n:(pred n) f a )
let pp_opt pp ppf = Format.(function
| Some x -> fprintf ppf "Some(%a)" pp x
| None -> fprintf ppf "None")
let eq_opt eq a b = match (a, b) with
| (Some x, Some y) -> eq x y
| _ -> false
let pp_octets pp = pp (Ohex.pp_hexdump ())
let assert_oct_equal ?msg =
assert_equal ~cmp:String.equal ?msg ~pp_diff:(pp_octets pp_diff)
let iter_list xs f = List.iter f xs
let cases_of f =
List.map @@ fun params -> test_case (f params)
let any _ = true
let vx = Ohex.decode
let f1_eq ?msg f (a, b) _ =
assert_oct_equal ?msg (f (vx a)) (vx b)
let f2_eq ?msg f (a, b, c) = f1_eq ?msg (f (vx a)) (b, c)

View file

@ -0,0 +1,73 @@
open OUnit2
open Mirage_crypto_pk
open Test_common
let dh_selftest ~bits n =
"selftest" >:: times ~n @@ fun _ ->
let p = Dh.gen_group ~bits () in
let (s1, m1) = Dh.gen_key p
and (s2, m2) = Dh.gen_key p in
let sh1 = Dh.shared s1 m2
and sh2 = Dh.shared s2 m1 in
assert_equal sh1 sh2
~cmp:(eq_opt String.equal)
~pp_diff:(pp_diff (fun ppf -> function
| None -> Format.fprintf ppf "None"
| Some a -> Format.fprintf ppf "Some(%a)" (Ohex.pp_hexdump ()) a))
~msg:"shared secret"
let dh_shared_0 =
"shared_0" >:: fun _ ->
let gy = vx
"14 ac e2 c0 9c c0 0c 25 89 71 b2 d0 1c 94 58 21
02 23 b7 23 ec 3e 24 e5 a3 c2 fd 16 cc 49 f0 e2
87 62 a5 a0 73 f5 de 5b 9b eb c3 60 0b a4 03 38
0f e1 8c f2 80 b3 64 16 f2 af ab 2e ec 25 81 2c
84 ae 92 0a 0f 15 9b f3 d9 1f dc 08 7d 8d 27 3a
91 7d a5 89 dc 94 d6 bc 3f 9d 6d b3 f8 8e f2 37
86 54 ec 85 ea 4c a0 4c b1 f6 49 83 1c 62 a7 79
2b 8b 9c e7 fa 47 3e 34 6c c5 ae 12 a3 4e d5 ce
4b da ea 72 7a 8d c6 67 ef 7e f2 00 24 d7 21 42
a5 23 69 38 7e ec b5 fc 4b 89 42 c4 32 fa e5 58
6f 39 5d a7 4e cd b5 da dc 1e 52 fe a4 33 72 c1
82 48 8a 5b c1 44 bc 60 9b 38 5b 80 5f 44 14 93"
and s = vx
"f9 47 87 95 d2 a1 6d d1 7c c8 a9 c0 71 28 a2 82
71 95 7e 79 87 0b fc 34 a2 42 ec 42 ac cc 42 81
7b f6 c4 f5 80 a9 70 e3 35 93 9b a3 21 81 a4 e3
6b 65 3f 1c 5c ab 87 23 86 eb 76 29 66 26 5b e9
c4 d0 26 05 3f de 6c 2f a6 14 f6 bf 77 74 a0 e8
ef e7 12 62 a3 83 e5 66 d8 6c e5 c6 58 67 2a 61
f5 7b 7c 15 15 63 22 55 96 92 9e bd cc b3 bc 2b
5e e1 ac 5f 75 23 ca 2f 19 5a f1 18 6e 17 f8 c2
f7 11 c7 14 1d 81 bd be 02 31 3f 49 62 7d 02 11
29 22 63 6e bb 1a 7f 93 bd 98 db 20 94 f8 f0 2e
db ce 9d 79 db b9 a7 41 5f e5 29 a2 31 f8 e2 c3
30 6a 09 f2 16 a7 30 8c 2f 36 7b 71 99 1e 28 54"
and shared = vx
"a7 40 0d eb f0 4b 2b ec cb 90 3c 55 2d 3c 17 63
b2 4b 4e 1a ff 1e a0 24 c6 56 e3 5e 44 7b d0 01
ef b3 6b 57 20 0e 15 95 b1 53 1a 83 16 3a b1 61
06 65 f1 7e 64 63 6f 23 86 22 34 c3 fe a9 60 87
3f 18 c6 5d 44 3e ac e3 85 34 86 6f db aa 31 3b
4b 4d 68 f7 19 d7 91 a3 12 27 d6 5a ce 29 c8 1b
5a 59 74 10 8c ff 98 4e 4f 37 ef 5b 43 e8 e2 ad
a8 49 c9 7e c3 c5 3d 35 40 30 8e a4 41 69 1d 16
34 ba 9a 7e f3 ab d1 0e bb f2 81 15 e9 04 63 ee
1b bf cc 24 6d cb 41 c4 06 b2 f3 01 1b 31 3a 1e
dc e3 3b c7 cc 1d 19 95 d9 fe 6a 5c a7 57 46 dd
84 69 0c 45 37 2e 1f 52 96 05 d7 e5 01 9a c8"
in
let grp = Dh.Group.oakley_5 in
match Dh.(shared (fst (key_of_secret grp ~s)) gy) with
| None -> assert_failure "degenerate shared secret"
| Some shared' ->
assert_oct_equal ~msg:"shared secret" shared shared'
let suite = [
dh_selftest ~bits:16 1000 ;
dh_selftest ~bits:128 100 ;
dh_shared_0
]

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,856 @@
open Mirage_crypto_ec
open Test_common
module Testable = struct
let ok_or_error =
Alcotest.result Alcotest.unit (Alcotest.testable pp_error ( = ))
end
let pp_hex_le fmt buf =
let n = String.length buf in
let bbuf = Bytes.unsafe_of_string buf in
for i = n - 1 downto 0 do
let byte = Bytes.get_uint8 bbuf i in
Format.fprintf fmt "%02x" byte
done
let pp_result ppf = function
| Ok cs -> pp_hex_le ppf cs
| Error e -> Format.fprintf ppf "%a" pp_error e
let key_exchange =
let test ~name d p ~expected =
( name,
`Quick,
fun () ->
P256.Dh.key_exchange d p
|> Format.asprintf "%a" pp_result
|> Alcotest.check Alcotest.string __LOC__ expected )
in
let kp data =
match P256.Dh.secret_of_octets data with
| Ok (p, s) -> p, s
| Error _ -> assert false
in
let d_a, p_a =
kp (of_hex "200102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f")
and d_b, p_b =
kp (of_hex "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f")
in
[
test ~name:"b*A" d_b p_a
~expected:
"2e3e4065a62a7f425aaf8aae3d158f367c733300b5002e0b62f4bc6260789e1b";
test ~name:"a*B" d_a p_b
~expected:
"2e3e4065a62a7f425aaf8aae3d158f367c733300b5002e0b62f4bc6260789e1b";
test ~name:"a*A" d_a p_a
~expected:
"2ea4e810837da217a5bfd05f01d12459eeda830b6e0dec7f8afa425c5b55c507";
test ~name:"b*B" d_b p_b
~expected:
"a7666bcc3818472194460f7df22d80a5886da0e1679eac930175ce1ff733c7ca";
]
let scalar_mult =
let test ~n ~scalar ~point ~expected =
let scalar =
match P256.Dh.secret_of_octets scalar with
| Ok (p, _) -> p
| Error _ -> assert false
in
( Printf.sprintf "Scalar mult (#%d)" n,
`Quick,
fun () ->
P256.Dh.key_exchange scalar point
|> Format.asprintf "%a" pp_result
|> Alcotest.check Alcotest.string __LOC__ expected )
in
let point =
of_hex "046B17D1F2E12C4247F8BCE6E563A440F277037D812DEB33A0F4A13945D898C2964FE342E2FE1A7F9B8EE7EB4A7C0F9E162BCE33576B315ECECBB6406837BF51F5"
in
[
test ~n:0
~scalar:(of_hex "0000000000000000000000000000000000000000000000000000000000000001")
~point
~expected:"96c298d84539a1f4a033eb2d817d0377f240a463e5e6bcf847422ce1f2d1176b";
test ~n:1
~scalar:(of_hex "0000000000000000000000000000000000000000000000000000000000000002")
~point
~expected:"78996647fc480ba6351bf277e26989c0c31ab5040338528a7e4f038d187bf27c";
test ~n:2
~scalar:(of_hex "0000000000000000000000000000000000000000000000000000000000000004")
~point
~expected:"5208036b44029350ef965578dbe21f03d02be69e65de2da0bb8fd032354a53e2";
test ~n:3
~scalar:(of_hex "0612465c89a023ab17855b0a6bcebfd3febb53aef84138647b5352e02c10c346")
~point:(of_hex "0462d5bd3372af75fe85a040715d0f502428e07046868b0bfdfa61d731afe44f26ac333a93a9e70a81cd5a95b5bf8d13990eb741c8c38872b4a07d275a014e30cf")
~expected:"854271e19508bc935ab22b95cd2be13a0e78265f528b658b3219028b900d0253";
test ~n:4
~scalar:(of_hex "0a0d622a47e48f6bc1038ace438c6f528aa00ad2bd1da5f13ee46bf5f633d71a")
~point:(of_hex "043cbc1b31b43f17dc200dd70c2944c04c6cb1b082820c234a300b05b7763844c74fde0a4ef93887469793270eb2ff148287da9265b0334f9e2609aac16e8ad503")
~expected:"ffffffffffffffffffffffffffffffff3022cfeeffffffffffffffffffffff7f";
test ~n:5
~scalar:(of_hex "55d55f11bb8da1ea318bca7266f0376662441ea87270aa2077f1b770c4854a48")
~point:(of_hex "04000000000000000000000000000000000000000000000000000000000000000066485c780e2f83d72433bd5d84a06bb6541c2af31dae871728bf856a174f93f4")
~expected:"48e82c9b82c88cb9fc2a5cff9e7c41bc4255ff6bd3814538c9b130877c07e4cf";
]
let to_ok_or_error = function Ok _ -> Ok () | Error _ as e -> e
let point_validation =
let test ~name ~x ~y ~expected =
let scalar =
match P256.Dh.secret_of_octets (of_hex "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f") with
| Ok (p, _) -> p
| _ -> assert false
in
let point =
let s04 = String.make 1 '\004' in
s04 ^ x ^ y
in
( name,
`Quick,
fun () ->
P256.Dh.key_exchange scalar point
|> to_ok_or_error
|> Alcotest.check Testable.ok_or_error __LOC__ expected )
in
let zero = String.make 32 '\000' in
let sb = of_hex "66485c780e2f83d72433bd5d84a06bb6541c2af31dae871728bf856a174f93f4"
in
[
test ~name:"Ok"
~x:(of_hex "62d5bd3372af75fe85a040715d0f502428e07046868b0bfdfa61d731afe44f26")
~y:(of_hex "ac333a93a9e70a81cd5a95b5bf8d13990eb741c8c38872b4a07d275a014e30cf")
~expected:(Ok ());
test ~name:"P=0"
~x:(of_hex "0000000000000000000000000000000000000000000000000000000000000000")
~y:(of_hex "0000000000000000000000000000000000000000000000000000000000000000")
~expected:(Error `Not_on_curve);
test ~name:"(0, sqrt(b))" ~x:zero ~y:sb ~expected:(Ok ());
test ~name:"out of range"
~x:(of_hex "FFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFF")
~y:sb
~expected:(Error `Invalid_range);
]
let scalar_validation =
let ign_sec hex =
match P256.Dh.secret_of_octets (of_hex hex) with
| Ok _ -> Ok ()
| Error _ as e -> e
in
[ ("0", `Quick, fun () ->
Alcotest.check Testable.ok_or_error __LOC__
(Error `Invalid_range)
(ign_sec "0000000000000000000000000000000000000000000000000000000000000000")) ;
("1", `Quick, fun () ->
Alcotest.check Testable.ok_or_error __LOC__
(Ok ())
(ign_sec "0000000000000000000000000000000000000000000000000000000000000001")) ;
("n-1", `Quick, fun () ->
Alcotest.check Testable.ok_or_error __LOC__
(Ok ())
(ign_sec "FFFFFFFF00000000FFFFFFFFFFFFFFFFBCE6FAADA7179E84F3B9CAC2FC632550")) ;
("n", `Quick, fun () ->
Alcotest.check Testable.ok_or_error __LOC__
(Error `Invalid_range)
(ign_sec "FFFFFFFF00000000FFFFFFFFFFFFFFFFBCE6FAADA7179E84F3B9CAC2FC632551")) ;
]
let ecdsa_gen () =
let d = of_hex "C477F9F6 5C22CCE2 0657FAA5 B2D1D812 2336F851 A508A1ED 04E479C3 4985BF96" in
let p = match
P256.Dsa.pub_of_octets
(of_hex {|04
B7E08AFD FE94BAD3 F1DC8C73 4798BA1C 62B3A0AD 1E9EA2A3 8201CD08 89BC7A19
3603F747 959DBF7A 4BB226E4 19287290 63ADC7AE 43529E61 B563BBC6 06CC5E09|})
with
| Ok a -> a
| Error _ -> assert false
in
let pub = match P256.Dsa.priv_of_octets d with
| Ok p -> P256.Dsa.pub_of_priv p
| Error _ -> Alcotest.fail "couldn't decode private key"
in
let pub_eq a b =
String.equal (P256.Dsa.pub_to_octets a) (P256.Dsa.pub_to_octets b)
in
Alcotest.(check bool __LOC__ true (pub_eq pub p))
let ecdsa_sign () =
let d = of_hex "C477F9F6 5C22CCE2 0657FAA5 B2D1D812 2336F851 A508A1ED 04E479C3 4985BF96"
and k = of_hex "7A1A7E52 797FC8CA AA435D2A 4DACE391 58504BF2 04FBE19F 14DBB427 FAEE50AE"
and e = of_hex "A41A41A1 2A799548 211C410C 65D8133A FDE34D28 BDD542E4 B680CF28 99C8A8C4"
in
let r = of_hex "2B42F576 D07F4165 FF65D1F3 B1500F81 E44C316F 1F0B3EF5 7325B69A CA46104F"
and s = of_hex "DC42C212 2D6392CD 3E3A993A 89502A81 98C1886F E69D262C 4B329BDB 6B63FAF1"
in
let key = match P256.Dsa.priv_of_octets d with
| Ok p -> p
| Error _ -> Alcotest.fail "couldn't decode private key"
in
let (r', s') = P256.Dsa.sign ~key ~k e in
Alcotest.(check bool __LOC__ true (String.equal r r' && String.equal s s'))
let ecdsa_verify () =
let key =
match P256.Dsa.pub_of_octets
(of_hex {|04
B7E08AFD FE94BAD3 F1DC8C73 4798BA1C 62B3A0AD 1E9EA2A3 8201CD08 89BC7A19
3603F747 959DBF7A 4BB226E4 19287290 63ADC7AE 43529E61 B563BBC6 06CC5E09|})
with
| Ok a -> a
| Error _ -> assert false
and e = of_hex "A41A41A1 2A799548 211C410C 65D8133A FDE34D28 BDD542E4 B680CF28 99C8A8C4"
and r = of_hex "2B42F576 D07F4165 FF65D1F3 B1500F81 E44C316F 1F0B3EF5 7325B69A CA46104F"
and s = of_hex "DC42C212 2D6392CD 3E3A993A 89502A81 98C1886F E69D262C 4B329BDB 6B63FAF1"
in
Alcotest.(check bool __LOC__ true (P256.Dsa.verify ~key (r, s) e))
let ecdsa = [
(* from https://csrc.nist.rip/groups/ST/toolkit/documents/Examples/ECDSA_Prime.pdf *)
"ECDSA gen", `Quick, ecdsa_gen ;
"ECDSA sign", `Quick, ecdsa_sign ;
"ECDSA verify", `Quick, ecdsa_verify ;
]
let pub_key_compression (module Dsa:Mirage_crypto_ec.Dsa) () =
for _ = 1 to 20 do
let _, pub = Dsa.generate () in
let compressed = Dsa.pub_to_octets ~compress:true pub in
let decompressed = Dsa.pub_of_octets compressed in
match decompressed with
| Ok decompressed ->
let p1 = Dsa.pub_to_octets pub in
let p2 = Dsa.pub_to_octets decompressed in
Alcotest.(check string __LOC__ p1 p2);
let prefix = String.get_uint8 compressed 0 in
let expected = 2 + String.(get_uint8 p1 (length p1 - 1)) land 1 in
Alcotest.(check int __LOC__ expected prefix);
| Error e -> Alcotest.failf "%a" pp_error e
done
let ecdsa_rfc6979_p256 =
(* A.2.5 - P 256 *)
let priv, pub =
let data = of_hex "C9AFA9D845BA75166B5C215767B1D6934E50C3DB36E89B127B8A622B120F6721" in
match P256.Dsa.priv_of_octets data with
| Ok p -> p, P256.Dsa.pub_of_priv p
| Error _ -> assert false
in
let pub_rfc () =
let fst = String.make 1 '\004' in
let ux = of_hex "60FED4BA255A9D31C961EB74C6356D68C049B8923B61FA6CE669622E60F29FB6"
and uy = of_hex "7903FE1008B8BC99A41AE9E95628BC64F2F1B20C2D7E9F5177A3C294D4462299"
in
match P256.Dsa.pub_of_octets (fst ^ ux ^ uy) with
| Ok p ->
let pub_eq =
String.equal (P256.Dsa.pub_to_octets pub) (P256.Dsa.pub_to_octets p)
in
Alcotest.(check bool __LOC__ true pub_eq)
| Error _ -> Alcotest.fail "bad public key"
in
let case (type a) (hash : a Digestif.hash) ~message ~k ~r ~s () =
let msg =
let h = Digestif.(digest_string hash message |> to_raw_string hash) in
String.sub h 0 (min (String.length h) 32)
and k = of_hex k
in
let k' =
let module H = (val Digestif.module_of hash) in
let module K = P256.Dsa.K_gen (H) in
K.generate ~key:priv msg
in
Alcotest.(check bool __LOC__ true (String.equal k k'));
let sig_eq (r', s') =
String.equal (of_hex r) r' && String.equal (of_hex s) s'
in
let sig' = P256.Dsa.sign ~key:priv ~k msg in
Alcotest.(check bool __LOC__ true (sig_eq sig'))
in
let cases = [
case Digestif.sha1 ~message:"sample"
~k:"882905F1227FD620FBF2ABF21244F0BA83D0DC3A9103DBBEE43A1FB858109DB4"
~r:"61340C88C3AAEBEB4F6D667F672CA9759A6CCAA9FA8811313039EE4A35471D32"
~s:"6D7F147DAC089441BB2E2FE8F7A3FA264B9C475098FDCF6E00D7C996E1B8B7EB" ;
case Digestif.sha224 ~message:"sample"
~k:"103F90EE9DC52E5E7FB5132B7033C63066D194321491862059967C715985D473"
~r:"53B2FFF5D1752B2C689DF257C04C40A587FABABB3F6FC2702F1343AF7CA9AA3F"
~s:"B9AFB64FDC03DC1A131C7D2386D11E349F070AA432A4ACC918BEA988BF75C74C" ;
case Digestif.sha256 ~message:"sample"
~k:"A6E3C57DD01ABE90086538398355DD4C3B17AA873382B0F24D6129493D8AAD60"
~r:"EFD48B2AACB6A8FD1140DD9CD45E81D69D2C877B56AAF991C34D0EA84EAF3716"
~s:"F7CB1C942D657C41D436C7A1B6E29F65F3E900DBB9AFF4064DC4AB2F843ACDA8" ;
case Digestif.sha384 ~message:"sample"
~k:"09F634B188CEFD98E7EC88B1AA9852D734D0BC272F7D2A47DECC6EBEB375AAD4"
~r:"0EAFEA039B20E9B42309FB1D89E213057CBF973DC0CFC8F129EDDDC800EF7719"
~s:"4861F0491E6998B9455193E34E7B0D284DDD7149A74B95B9261F13ABDE940954" ;
case Digestif.sha512 ~message:"sample"
~k:"5FA81C63109BADB88C1F367B47DA606DA28CAD69AA22C4FE6AD7DF73A7173AA5"
~r:"8496A60B5E9B47C825488827E0495B0E3FA109EC4568FD3F8D1097678EB97F00"
~s:"2362AB1ADBE2B8ADF9CB9EDAB740EA6049C028114F2460F96554F61FAE3302FE" ;
case Digestif.sha1 ~message:"test"
~k:"8C9520267C55D6B980DF741E56B4ADEE114D84FBFA2E62137954164028632A2E"
~r:"0CBCC86FD6ABD1D99E703E1EC50069EE5C0B4BA4B9AC60E409E8EC5910D81A89"
~s:"01B9D7B73DFAA60D5651EC4591A0136F87653E0FD780C3B1BC872FFDEAE479B1" ;
case Digestif.sha224 ~message:"test"
~k:"669F4426F2688B8BE0DB3A6BD1989BDAEFFF84B649EEB84F3DD26080F667FAA7"
~r:"C37EDB6F0AE79D47C3C27E962FA269BB4F441770357E114EE511F662EC34A692"
~s:"C820053A05791E521FCAAD6042D40AEA1D6B1A540138558F47D0719800E18F2D" ;
case Digestif.sha256 ~message:"test"
~k:"D16B6AE827F17175E040871A1C7EC3500192C4C92677336EC2537ACAEE0008E0"
~r:"F1ABB023518351CD71D881567B1EA663ED3EFCF6C5132B354F28D3B0B7D38367"
~s:"019F4113742A2B14BD25926B49C649155F267E60D3814B4C0CC84250E46F0083" ;
case Digestif.sha384 ~message:"test"
~k:"16AEFFA357260B04B1DD199693960740066C1A8F3E8EDD79070AA914D361B3B8"
~r:"83910E8B48BB0C74244EBDF7F07A1C5413D61472BD941EF3920E623FBCCEBEB6"
~s:"8DDBEC54CF8CD5874883841D712142A56A8D0F218F5003CB0296B6B509619F2C" ;
case Digestif.sha512 ~message:"test"
~k:"6915D11632ACA3C40D5D51C08DAF9C555933819548784480E93499000D9F0B7F"
~r:"461D93F31B6540894788FD206C07CFA0CC35F46FA3C91816FFF1040AD1581A04"
~s:"39AF9F15DE0DB8D97E72719C74820D304CE5226E32DEDAE67519E840D1194E55" ;
] in
("public key matches", `Quick, pub_rfc) ::
("public key compression and decompression", `Quick, (pub_key_compression (module P256.Dsa))) ::
List.mapi (fun i c -> "RFC 6979 A.2.5 " ^ string_of_int i, `Quick, c) cases
let ecdsa_rfc6979_p384 =
(* A.2.6 - P 384 *)
let priv, pub =
let data = of_hex "6B9D3DAD2E1B8C1C05B19875B6659F4DE23C3B667BF297BA9AA47740787137D896D5724E4C70A825F872C9EA60D2EDF5" in
match P384.Dsa.priv_of_octets data with
| Ok p -> p, P384.Dsa.pub_of_priv p
| Error _ -> assert false
in
let pub_rfc () =
let fst = String.make 1 '\004' in
let ux = of_hex "EC3A4E415B4E19A4568618029F427FA5DA9A8BC4AE92E02E06AAE5286B300C64DEF8F0EA9055866064A254515480BC13"
and uy = of_hex "8015D9B72D7D57244EA8EF9AC0C621896708A59367F9DFB9F54CA84B3F1C9DB1288B231C3AE0D4FE7344FD2533264720"
in
match P384.Dsa.pub_of_octets (fst ^ ux ^ uy) with
| Ok p ->
let pub_eq =
String.equal (P384.Dsa.pub_to_octets pub) (P384.Dsa.pub_to_octets p)
in
Alcotest.(check bool __LOC__ true pub_eq)
| Error _ -> Alcotest.fail "bad public key"
in
let case (type a) (hash : a Digestif.hash) ~message ~k ~r ~s () =
let msg =
let h = Digestif.(digest_string hash message |> to_raw_string hash) in
String.sub h 0 (min (String.length h) 48)
and k = of_hex k
in
let k' =
let module H = (val Digestif.module_of hash) in
let module K = P384.Dsa.K_gen (H) in
K.generate ~key:priv msg
in
Alcotest.(check bool __LOC__ true (String.equal k k'));
let sig_eq (r', s') =
String.equal (of_hex r) r' && String.equal (of_hex s) s'
in
let sig' = P384.Dsa.sign ~key:priv ~k msg in
Alcotest.(check bool __LOC__ true (sig_eq sig'))
in
let cases = [
case Digestif.sha1 ~message:"sample"
~k:"4471EF7518BB2C7C20F62EAE1C387AD0C5E8E470995DB4ACF694466E6AB09663
0F29E5938D25106C3C340045A2DB01A7"
~r:"EC748D839243D6FBEF4FC5C4859A7DFFD7F3ABDDF72014540C16D73309834FA3
7B9BA002899F6FDA3A4A9386790D4EB2"
~s:"A3BCFA947BEEF4732BF247AC17F71676CB31A847B9FF0CBC9C9ED4C1A5B3FACF
26F49CA031D4857570CCB5CA4424A443";
case Digestif.sha224 ~message:"sample"
~k:"A4E4D2F0E729EB786B31FC20AD5D849E304450E0AE8E3E341134A5C1AFA03CAB
8083EE4E3C45B06A5899EA56C51B5879"
~r:"42356E76B55A6D9B4631C865445DBE54E056D3B3431766D0509244793C3F9366
450F76EE3DE43F5A125333A6BE060122"
~s:"9DA0C81787064021E78DF658F2FBB0B042BF304665DB721F077A4298B095E483
4C082C03D83028EFBF93A3C23940CA8D";
case Digestif.sha256 ~message:"sample"
~k:"180AE9F9AEC5438A44BC159A1FCB277C7BE54FA20E7CF404B490650A8ACC414E
375572342863C899F9F2EDF9747A9B60"
~r:"21B13D1E013C7FA1392D03C5F99AF8B30C570C6F98D4EA8E354B63A21D3DAA33
BDE1E888E63355D92FA2B3C36D8FB2CD"
~s:"F3AA443FB107745BF4BD77CB3891674632068A10CA67E3D45DB2266FA7D1FEEB
EFDC63ECCD1AC42EC0CB8668A4FA0AB0";
case Digestif.sha384 ~message:"sample"
~k:"94ED910D1A099DAD3254E9242AE85ABDE4BA15168EAF0CA87A555FD56D10FBCA
2907E3E83BA95368623B8C4686915CF9"
~r:"94EDBB92A5ECB8AAD4736E56C691916B3F88140666CE9FA73D64C4EA95AD133C
81A648152E44ACF96E36DD1E80FABE46"
~s:"99EF4AEB15F178CEA1FE40DB2603138F130E740A19624526203B6351D0A3A94F
A329C145786E679E7B82C71A38628AC8";
case Digestif.sha512 ~message:"sample"
~k:"92FC3C7183A883E24216D1141F1A8976C5B0DD797DFA597E3D7B32198BD35331
A4E966532593A52980D0E3AAA5E10EC3"
~r:"ED0959D5880AB2D869AE7F6C2915C6D60F96507F9CB3E047C0046861DA4A799C
FE30F35CC900056D7C99CD7882433709"
~s:"512C8CCEEE3890A84058CE1E22DBC2198F42323CE8ACA9135329F03C068E5112
DC7CC3EF3446DEFCEB01A45C2667FDD5";
case Digestif.sha1 ~message:"test"
~k:"66CC2C8F4D303FC962E5FF6A27BD79F84EC812DDAE58CF5243B64A4AD8094D47
EC3727F3A3C186C15054492E30698497"
~r:"4BC35D3A50EF4E30576F58CD96CE6BF638025EE624004A1F7789A8B8E43D0678
ACD9D29876DAF46638645F7F404B11C7"
~s:"D5A6326C494ED3FF614703878961C0FDE7B2C278F9A65FD8C4B7186201A29916
95BA1C84541327E966FA7B50F7382282";
case Digestif.sha224 ~message:"test"
~k:"18FA39DB95AA5F561F30FA3591DC59C0FA3653A80DAFFA0B48D1A4C6DFCBFF6E
3D33BE4DC5EB8886A8ECD093F2935726"
~r:"E8C9D0B6EA72A0E7837FEA1D14A1A9557F29FAA45D3E7EE888FC5BF954B5E624
64A9A817C47FF78B8C11066B24080E72"
~s:"07041D4A7A0379AC7232FF72E6F77B6DDB8F09B16CCE0EC3286B2BD43FA8C614
1C53EA5ABEF0D8231077A04540A96B66";
case Digestif.sha256 ~message:"test"
~k:"0CFAC37587532347DC3389FDC98286BBA8C73807285B184C83E62E26C401C0FA
A48DD070BA79921A3457ABFF2D630AD7"
~r:"6D6DEFAC9AB64DABAFE36C6BF510352A4CC27001263638E5B16D9BB51D451559
F918EEDAF2293BE5B475CC8F0188636B"
~s:"2D46F3BECBCC523D5F1A1256BF0C9B024D879BA9E838144C8BA6BAEB4B53B47D
51AB373F9845C0514EEFB14024787265";
case Digestif.sha384 ~message:"test"
~k:"015EE46A5BF88773ED9123A5AB0807962D193719503C527B031B4C2D225092AD
A71F4A459BC0DA98ADB95837DB8312EA"
~r:"8203B63D3C853E8D77227FB377BCF7B7B772E97892A80F36AB775D509D7A5FEB
0542A7F0812998DA8F1DD3CA3CF023DB"
~s:"DDD0760448D42D8A43AF45AF836FCE4DE8BE06B485E9B61B827C2F13173923E0
6A739F040649A667BF3B828246BAA5A5";
case Digestif.sha512 ~message:"test"
~k:"3780C4F67CB15518B6ACAE34C9F83568D2E12E47DEAB6C50A4E4EE5319D1E8CE
0E2CC8A136036DC4B9C00E6888F66B6C"
~r:"A0D5D090C9980FAF3C2CE57B7AE951D31977DD11C775D314AF55F76C676447D0
6FB6495CD21B4B6E340FC236584FB277"
~s:"976984E59B4C77B0E8E4460DCA3D9F20E07B9BB1F63BEEFAF576F6B2E8B22463
4A2092CD3792E0159AD9CEE37659C736"
] in
("public key matches", `Quick, pub_rfc) ::
("public key compression and decompression", `Quick, pub_key_compression (module P384.Dsa)) ::
List.mapi (fun i c -> "RFC 6979 A.2.6 " ^ string_of_int i, `Quick, c) cases
let ecdsa_rfc6979_p521 =
(* A.2.7 - P 521 *)
let of_h b = of_hex ((String.make 1 '0') ^ b) in
let priv, pub =
let data = of_h
"0FAD06DAA62BA3B25D2FB40133DA757205DE67F5BB0018FEE8C86E1B68C7E75C
AA896EB32F1F47C70855836A6D16FCC1466F6D8FBEC67DB89EC0C08B0E996B83
538"
in
match P521.Dsa.priv_of_octets data with
| Ok p -> p, P521.Dsa.pub_of_priv p
| Error _ -> assert false
in
let pub_rfc () =
let fst = String.make 1 '\004' in
let ux = of_h
"1894550D0785932E00EAA23B694F213F8C3121F86DC97A04E5A7167DB4E5BCD3
71123D46E45DB6B5D5370A7F20FB633155D38FFA16D2BD761DCAC474B9A2F502
3A4"
and uy = of_h
"0493101C962CD4D2FDDF782285E64584139C2F91B47F87FF82354D6630F746A2
8A0DB25741B5B34A828008B22ACC23F924FAAFBD4D33F81EA66956DFEAA2BFDF
CF5"
in
match P521.Dsa.pub_of_octets (fst ^ ux ^ uy) with
| Ok p ->
let pub_eq =
String.equal (P521.Dsa.pub_to_octets pub) (P521.Dsa.pub_to_octets p)
in
Alcotest.(check bool __LOC__ true pub_eq)
| Error _ -> Alcotest.fail "bad public key"
in
let case (type a) (hash : a Digestif.hash) ~message ~k ~r ~s () =
let msg = Digestif.(digest_string hash message |> to_raw_string hash)
and k = of_h k
in
let k' =
let module H = (val Digestif.module_of hash) in
let module K = P521.Dsa.K_gen (H) in
K.generate ~key:priv msg
in
Alcotest.(check bool __LOC__ true (String.equal k k'));
let sig_eq (r', s') =
String.equal (of_h r) r' && String.equal (of_h s) s'
in
let sig' = P521.Dsa.sign ~key:priv ~k msg in
Alcotest.(check bool __LOC__ true (sig_eq sig'))
in
let cases = [
case Digestif.sha1 ~message:"sample"
~k:"089C071B419E1C2820962321787258469511958E80582E95D8378E0C2CCDB3CB
42BEDE42F50E3FA3C71F5A76724281D31D9C89F0F91FC1BE4918DB1C03A5838D
0F9"
~r:"0343B6EC45728975EA5CBA6659BBB6062A5FF89EEA58BE3C80B619F322C87910
FE092F7D45BB0F8EEE01ED3F20BABEC079D202AE677B243AB40B5431D497C55D
75D"
~s:"0E7B0E675A9B24413D448B8CC119D2BF7B2D2DF032741C096634D6D65D0DBE3D
5694625FB9E8104D3B842C1B0E2D0B98BEA19341E8676AEF66AE4EBA3D5475D5
D16";
case Digestif.sha224 ~message:"sample"
~k:"121415EC2CD7726330A61F7F3FA5DE14BE9436019C4DB8CB4041F3B54CF31BE0
493EE3F427FB906393D895A19C9523F3A1D54BB8702BD4AA9C99DAB2597B9211
3F3"
~r:"1776331CFCDF927D666E032E00CF776187BC9FDD8E69D0DABB4109FFE1B5E2A3
0715F4CC923A4A5E94D2503E9ACFED92857B7F31D7152E0F8C00C15FF3D87E2E
D2E"
~s:"050CB5265417FE2320BBB5A122B8E1A32BD699089851128E360E620A30C7E17B
A41A666AF126CE100E5799B153B60528D5300D08489CA9178FB610A2006C254B
41F";
case Digestif.sha256 ~message:"sample"
~k:"0EDF38AFCAAECAB4383358B34D67C9F2216C8382AAEA44A3DAD5FDC9C3257576
1793FEF24EB0FC276DFC4F6E3EC476752F043CF01415387470BCBD8678ED2C7E
1A0"
~r:"1511BB4D675114FE266FC4372B87682BAECC01D3CC62CF2303C92B3526012659
D16876E25C7C1E57648F23B73564D67F61C6F14D527D54972810421E7D87589E
1A7"
~s:"04A171143A83163D6DF460AAF61522695F207A58B95C0644D87E52AA1A347916
E4F7A72930B1BC06DBE22CE3F58264AFD23704CBB63B29B931F7DE6C9D949A7E
CFC";
case Digestif.sha384 ~message:"sample"
~k:"1546A108BC23A15D6F21872F7DED661FA8431DDBD922D0DCDB77CC878C8553FF
AD064C95A920A750AC9137E527390D2D92F153E66196966EA554D9ADFCB109C4
211"
~r:"1EA842A0E17D2DE4F92C15315C63DDF72685C18195C2BB95E572B9C5136CA4B4
B576AD712A52BE9730627D16054BA40CC0B8D3FF035B12AE75168397F5D50C67
451"
~s:"1F21A3CEE066E1961025FB048BD5FE2B7924D0CD797BABE0A83B66F1E35EEAF5
FDE143FA85DC394A7DEE766523393784484BDF3E00114A1C857CDE1AA203DB65
D61";
case Digestif.sha512 ~message:"sample"
~k:"1DAE2EA071F8110DC26882D4D5EAE0621A3256FC8847FB9022E2B7D28E6F1019
8B1574FDD03A9053C08A1854A168AA5A57470EC97DD5CE090124EF52A2F7ECBF
FD3"
~r:"0C328FAFCBD79DD77850370C46325D987CB525569FB63C5D3BC53950E6D4C5F1
74E25A1EE9017B5D450606ADD152B534931D7D4E8455CC91F9B15BF05EC36E37
7FA"
~s:"0617CCE7CF5064806C467F678D3B4080D6F1CC50AF26CA209417308281B68AF2
82623EAA63E5B5C0723D8B8C37FF0777B1A20F8CCB1DCCC43997F1EE0E44DA4A
67A";
case Digestif.sha1 ~message:"test"
~k:"0BB9F2BF4FE1038CCF4DABD7139A56F6FD8BB1386561BD3C6A4FC818B20DF5DD
BA80795A947107A1AB9D12DAA615B1ADE4F7A9DC05E8E6311150F47F5C57CE8B
222"
~r:"13BAD9F29ABE20DE37EBEB823C252CA0F63361284015A3BF430A46AAA80B87B0
693F0694BD88AFE4E661FC33B094CD3B7963BED5A727ED8BD6A3A202ABE009D0
367"
~s:"1E9BB81FF7944CA409AD138DBBEE228E1AFCC0C890FC78EC8604639CB0DBDC90
F717A99EAD9D272855D00162EE9527567DD6A92CBD629805C0445282BBC91679
7FF";
case Digestif.sha224 ~message:"test"
~k:"040D09FCF3C8A5F62CF4FB223CBBB2B9937F6B0577C27020A99602C25A011369
87E452988781484EDBBCF1C47E554E7FC901BC3085E5206D9F619CFF07E73D6F
706"
~r:"1C7ED902E123E6815546065A2C4AF977B22AA8EADDB68B2C1110E7EA44D42086
BFE4A34B67DDC0E17E96536E358219B23A706C6A6E16BA77B65E1C595D43CAE1
7FB"
~s:"177336676304FCB343CE028B38E7B4FBA76C1C1B277DA18CAD2A8478B2A9A9F5
BEC0F3BA04F35DB3E4263569EC6AADE8C92746E4C82F8299AE1B8F1739F8FD51
9A4";
case Digestif.sha256 ~message:"test"
~k:"01DE74955EFAABC4C4F17F8E84D881D1310B5392D7700275F82F145C61E84384
1AF09035BF7A6210F5A431A6A9E81C9323354A9E69135D44EBD2FCAA7731B909
258"
~r:"00E871C4A14F993C6C7369501900C4BC1E9C7B0B4BA44E04868B30B41D807104
2EB28C4C250411D0CE08CD197E4188EA4876F279F90B3D8D74A3C76E6F1E4656
AA8"
~s:"0CD52DBAA33B063C3A6CD8058A1FB0A46A4754B034FCC644766CA14DA8CA5CA9
FDE00E88C1AD60CCBA759025299079D7A427EC3CC5B619BFBC828E7769BCD694
E86";
case Digestif.sha384 ~message:"test"
~k:"1F1FC4A349A7DA9A9E116BFDD055DC08E78252FF8E23AC276AC88B1770AE0B5D
CEB1ED14A4916B769A523CE1E90BA22846AF11DF8B300C38818F713DADD85DE0
C88"
~r:"14BEE21A18B6D8B3C93FAB08D43E739707953244FDBE924FA926D76669E7AC8C
89DF62ED8975C2D8397A65A49DCC09F6B0AC62272741924D479354D74FF60755
78C"
~s:"133330865C067A0EAF72362A65E2D7BC4E461E8C8995C3B6226A21BD1AA78F0E
D94FE536A0DCA35534F0CD1510C41525D163FE9D74D134881E35141ED5E8E95B
979";
case Digestif.sha512 ~message:"test"
~k:"16200813020EC986863BEDFC1B121F605C1215645018AEA1A7B215A564DE9EB1
B38A67AA1128B80CE391C4FB71187654AAA3431027BFC7F395766CA988C964DC
56D"
~r:"13E99020ABF5CEE7525D16B69B229652AB6BDF2AFFCAEF38773B4B7D08725F10
CDB93482FDCC54EDCEE91ECA4166B2A7C6265EF0CE2BD7051B7CEF945BABD47E
E6D"
~s:"1FBD0013C674AA79CB39849527916CE301C66EA7CE8B80682786AD60F98F7E78
A19CA69EFF5C57400E3B3A0AD66CE0978214D13BAF4E9AC60752F7B155E2DE4D
CE3"
] in
("public key matches", `Quick, pub_rfc) ::
("public key compression and decompression", `Quick, pub_key_compression (module P521.Dsa)) ::
List.mapi (fun i c -> "RFC 6979 A.2.7 " ^ string_of_int i, `Quick, c) cases
let x25519 () =
(* RFC 7748, 6.1 *)
let a = of_hex "77076d0a7318a57d3c16c17251b26645df4c2f87ebc0992ab177fba51db92c2a"
and apub = of_hex "8520f0098930a754748b7ddcb43ef75a0dbf3a0d26381af4eba4a98eaa9b4e6a"
and b = of_hex "5dab087e624a8a4b79e17f8b83800ee66f3bb1292618b6fd1c2f8b27ff88e0eb"
and bpub = of_hex "de9edb7d7b7dc1b4d35b61c2ece435373f8343c85b78674dadfc7e146f882b4f"
and shared = of_hex "4a5d9d5ba4ce2de1728e3bf480350f25e07e21c947d19e3376f09b3c1e161742"
in
let of_octets cs = match X25519.secret_of_octets cs with
| Ok (a, b) -> a, b
| Error _ -> Alcotest.fail "couldn't decode secret"
in
let apriv, apub' = of_octets a in
Alcotest.(check bool __LOC__ true (String.equal apub apub'));
let bpriv, bpub' = of_octets b in
Alcotest.(check bool __LOC__ true (String.equal bpub bpub'));
(match X25519.key_exchange apriv bpub with
| Ok shared' ->
Alcotest.(check bool __LOC__ true (String.equal shared shared'))
| Error e ->
Alcotest.failf "X25519 key exchange apriv bpub failed %a" pp_error e);
match X25519.key_exchange bpriv apub with
| Ok shared' ->
Alcotest.(check bool __LOC__ true (String.equal shared shared'))
| Error e ->
Alcotest.failf "X25519 key exchange bpriv apub failed %a" pp_error e
let ed25519 =
let test secret public msg signature =
Alcotest.(
check string "public key is ok" (Ed25519.pub_to_octets public)
Ed25519.(pub_to_octets (pub_of_priv secret)));
Alcotest.(check string "signature is ok" signature (Ed25519.sign ~key:secret msg));
Alcotest.(check bool "verify is ok" true
(Ed25519.verify ~key:public signature ~msg))
in
let case i ~secret ~public ~msg ~signature =
"RFC 8032 " ^ string_of_int i, `Quick, fun () ->
let s =
match Ed25519.priv_of_octets (of_hex secret) with
| Ok p ->
Alcotest.(check string "private key encoding is good"
(of_hex secret) (Ed25519.priv_to_octets p));
p
| Error _ -> Alcotest.fail "failed to decode private key"
and p =
match Ed25519.pub_of_octets (of_hex public) with
| Ok p ->
Alcotest.(check string "public key encoding is good"
(of_hex public) (Ed25519.pub_to_octets p));
p
| Error _ -> Alcotest.fail "failed to decode public key"
and m = of_hex msg
and si = of_hex signature
in
test s p m si
in
[
case 1
~secret:
"9d61b19deffd5a60ba844af492ec2cc4 4449c5697b326919703bac031cae7f60"
~public:
"d75a980182b10ab7d54bfed3c964073a 0ee172f3daa62325af021a68f707511a"
~msg:""
~signature:
{|
e5564300c360ac729086e2cc806e828a
84877f1eb8e5d974d873e06522490155
5fb8821590a33bacc61e39701cf9b46b
d25bf5f0595bbe24655141438e7a100b
|};
case 2
~secret:
"4ccd089b28ff96da9db6c346ec114e0f 5b8a319f35aba624da8cf6ed4fb8a6fb"
~public:
"3d4017c3e843895a92b70aa74d1b7ebc 9c982ccf2ec4968cc0cd55f12af4660c"
~msg:"72"
~signature:
{|
92a009a9f0d4cab8720e820b5f642540
a2b27b5416503f8fb3762223ebdb69da
085ac1e43e15996e458f3613d0f11d8c
387b2eaeb4302aeeb00d291612bb0c00
|};
case 3
~secret:
"c5aa8df43f9f837bedb7442f31dcb7b1 66d38535076f094b85ce3a2e0b4458f7"
~public:
"fc51cd8e6218a1a38da47ed00230f058 0816ed13ba3303ac5deb911548908025"
~msg:"af82"
~signature:
{|
6291d657deec24024827e69c3abe01a3
0ce548a284743a445e3680d7db5ac3ac
18ff9b538d16f290ae67f760984dc659
4a7c15e9716ed28dc027beceea1ec40a
|};
case 4
~secret:
"f5e5767cf153319517630f226876b86c 8160cc583bc013744c6bf255f5cc0ee5"
~public:
"278117fc144c72340f67d0f2316e8386 ceffbf2b2428c9c51fef7c597f1d426e"
~msg:
{|
08b8b2b733424243760fe426a4b54908
632110a66c2f6591eabd3345e3e4eb98
fa6e264bf09efe12ee50f8f54e9f77b1
e355f6c50544e23fb1433ddf73be84d8
79de7c0046dc4996d9e773f4bc9efe57
38829adb26c81b37c93a1b270b20329d
658675fc6ea534e0810a4432826bf58c
941efb65d57a338bbd2e26640f89ffbc
1a858efcb8550ee3a5e1998bd177e93a
7363c344fe6b199ee5d02e82d522c4fe
ba15452f80288a821a579116ec6dad2b
3b310da903401aa62100ab5d1a36553e
06203b33890cc9b832f79ef80560ccb9
a39ce767967ed628c6ad573cb116dbef
efd75499da96bd68a8a97b928a8bbc10
3b6621fcde2beca1231d206be6cd9ec7
aff6f6c94fcd7204ed3455c68c83f4a4
1da4af2b74ef5c53f1d8ac70bdcb7ed1
85ce81bd84359d44254d95629e9855a9
4a7c1958d1f8ada5d0532ed8a5aa3fb2
d17ba70eb6248e594e1a2297acbbb39d
502f1a8c6eb6f1ce22b3de1a1f40cc24
554119a831a9aad6079cad88425de6bd
e1a9187ebb6092cf67bf2b13fd65f270
88d78b7e883c8759d2c4f5c65adb7553
878ad575f9fad878e80a0c9ba63bcbcc
2732e69485bbc9c90bfbd62481d9089b
eccf80cfe2df16a2cf65bd92dd597b07
07e0917af48bbb75fed413d238f5555a
7a569d80c3414a8d0859dc65a46128ba
b27af87a71314f318c782b23ebfe808b
82b0ce26401d2e22f04d83d1255dc51a
ddd3b75a2b1ae0784504df543af8969b
e3ea7082ff7fc9888c144da2af58429e
c96031dbcad3dad9af0dcbaaaf268cb8
fcffead94f3c7ca495e056a9b47acdb7
51fb73e666c6c655ade8297297d07ad1
ba5e43f1bca32301651339e22904cc8c
42f58c30c04aafdb038dda0847dd988d
cda6f3bfd15c4b4c4525004aa06eeff8
ca61783aacec57fb3d1f92b0fe2fd1a8
5f6724517b65e614ad6808d6f6ee34df
f7310fdc82aebfd904b01e1dc54b2927
094b2db68d6f903b68401adebf5a7e08
d78ff4ef5d63653a65040cf9bfd4aca7
984a74d37145986780fc0b16ac451649
de6188a7dbdf191f64b5fc5e2ab47b57
f7f7276cd419c17a3ca8e1b939ae49e4
88acba6b965610b5480109c8b17b80e1
b7b750dfc7598d5d5011fd2dcc5600a3
2ef5b52a1ecc820e308aa342721aac09
43bf6686b64b2579376504ccc493d97e
6aed3fb0f9cd71a43dd497f01f17c0e2
cb3797aa2a2f256656168e6c496afc5f
b93246f6b1116398a346f1a641f3b041
e989f7914f90cc2c7fff357876e506b5
0d334ba77c225bc307ba537152f3f161
0e4eafe595f6d9d90d11faa933a15ef1
369546868a7f3a45a96768d40fd9d034
12c091c6315cf4fde7cb68606937380d
b2eaaa707b4c4185c32eddcdd306705e
4dc1ffc872eeee475a64dfac86aba41c
0618983f8741c5ef68d3a101e8a3b8ca
c60c905c15fc910840b94c00a0b9d0
|}
~signature:
{|
0aab4c900501b3e24d7cdf4663326a3a
87df5e4843b2cbdb67cbf6e460fec350
aa5371b1508f9f4528ecea23c436d94b
5e8fcd4f681e30a6ac00a9704a188a03
|};
case 5
~secret:
"833fe62409237b9d62ec77587520911e 9a759cec1d19755b7da901b96dca3d42"
~public:
"ec172b93ad5e563bf4932c70e1245034 c35467ef2efd4d64ebf819683467e2bf"
~msg:
{|
ddaf35a193617abacc417349ae204131
12e6fa4e89a97ea20a9eeee64b55d39a
2192992a274fc1a836ba3c23a3feebbd
454d4423643ce80e2a9ac94fa54ca49f
|}
~signature:
{|
dc2a4459e7369633a52b1bf277839a00
201009a3efbf3ecb69bea2186c26b589
09351fc9ac90b3ecfdfbc7c66431e030
3dca179c138ac17ad9bef1177331a704
|};
]
let p521_regression () =
let key = of_hex
"04 01 e4 f8 8a 40 3d fe 2f 65 a0 20 50 01 9b 87
86 2c 30 2f 64 58 de 68 63 ab 92 72 88 04 c6 20
7b 6f 9a 52 95 2d ff c7 80 df 50 44 b1 c4 91 e3
a7 65 39 e6 9c cf ed d2 2a eb 47 84 ea 0f 3d 05
dd 25 0e 00 95 6e 19 fb 7f b7 ce 47 5a 59 01 5f
35 33 fc 85 ac 34 1a b0 7a 67 86 e8 3e 31 fe 38
35 5c bb a1 b5 74 f4 47 a3 4c 0a f0 5f 6d 68 47
85 0f e9 79 74 23 e8 75 47 6e 2b e5 ea 1b 0a 36
b9 c3 94 ca b0"
and data = of_hex
"a8 98 57 b9 3f 58 02 c7 9a 37 e2 d7 89 d8 0b f4
2d 84 c2 24 7c 7f ff 5f 7b 65 c5 17 cf 79 7d 36
ff d3 9d 47 5e 68 90 57 f1 61 48 18 04 c3 fe ee
59 b2 15 2d 75 8b 9a 3c 52 60 96 5c 52 a8 55 9c"
and sigr = of_hex
"3a 2c 99 0b 61 a1 da 06 20 bf 6c fe 1f d3 f8 2a
cb f1 e5 0f 78 11 61 58 22 e4 a0 5f 18 81 8d 98
f8 7a ca 8b f8 f8 cc b8 95 f7 6f 03 54 1b 66 6e
cf c5 cb f1 7b 48 82 d2 c3 0e 0e 1b b4 ad e6 a4
5c"
and sigs = of_hex
"01 7b 8c 82 a5 aa 80 c5 ee 23 0f 91 55 89 a7 b0
3c 46 7f 56 ff b4 52 89 52 99 59 1e 5e b7 f2 c1
df f8 a0 4f d3 dd 1d f0 07 78 3a 2f 29 d6 61 61
55 dc 3b be 14 82 93 75 c2 0d be 7e ca 50 e4 3c
98 88"
in
match P521.Dsa.pub_of_octets key with
| Ok key ->
Alcotest.check Alcotest.bool "regression 1" true
(P521.Dsa.verify ~key (sigr, sigs) data)
| Error _ -> Alcotest.fail "regression failed"
let () =
Mirage_crypto_rng_unix.use_default ();
Alcotest.run "EC"
[
("P256 Key exchange", key_exchange);
("P256 Low level scalar mult", scalar_mult);
("P256 Point validation", point_validation);
("P256 Scalar validation when generating", scalar_validation);
("ECDSA NIST", ecdsa);
("ECDSA RFC 6979 P256", ecdsa_rfc6979_p256);
("ECDSA RFC 6979 P384", ecdsa_rfc6979_p384);
("ECDSA RFC 6979 P521", ecdsa_rfc6979_p521);
("X25519", [ "RFC 7748", `Quick, x25519 ]);
("ED25519", ed25519);
("ECDSA P521 regression", [ "regreesion1", `Quick, p521_regression ]);
]

View file

@ -0,0 +1,314 @@
open Wycheproof
open Mirage_crypto_ec
let ( let* ) = Result.bind
let hex = Alcotest.testable Wycheproof.pp_hex Wycheproof.equal_hex
module Asn = struct
let parse_point curve s =
let seq2 a b = Asn.S.(sequence2 (required a) (required b)) in
let term = Asn.S.(seq2 (seq2 oid oid) bit_string_octets) in
let ec_public_key = Asn.OID.(base 1 2 <|| [ 840; 10045; 2; 1 ]) in
let prime_oid = match curve with
| "secp256r1" -> Asn.OID.(base 1 2 <|| [ 840; 10045; 3; 1; 7 ])
| "secp384r1" -> Asn.OID.(base 1 3 <|| [ 132; 0; 34 ])
| "secp521r1" -> Asn.OID.(base 1 3 <|| [ 132; 0; 35 ])
| _ -> assert false
in
match Asn.decode (Asn.codec Asn.ber term) s with
| Error _ -> Error "ASN1 parse error"
| Ok (((oid1, oid2), data), rest) ->
if String.length rest <> 0 then Error "ASN1 leftover"
else if not (Asn.OID.equal oid1 ec_public_key) then
Error "ASN1: wrong oid 1"
else if not (Asn.OID.equal oid2 prime_oid) then Error "ASN1: wrong oid 2"
else Ok data
let parse_signature cs =
let asn = Asn.S.(sequence2 (required unsigned_integer) (required unsigned_integer)) in
match Asn.(decode (codec der asn) cs) with
| Error _ -> Error "ASN1 parse error"
| Ok (r_s, rest) ->
if String.length rest <> 0 then Error "ASN1 leftover"
else
Ok r_s
end
let to_string_result ~pp_error = function
| Ok _ as ok -> ok
| Error e ->
let msg = Format.asprintf "%a" pp_error e in
Error msg
let pad ~total_len buf =
match total_len - String.length buf with
| 0 -> Ok buf
| n when n < 0 ->
let is_zero = ref true in
for i = 0 to abs n - 1 do
if Bytes.(get_uint8 (Bytes.unsafe_of_string buf) i) <> 0 then
is_zero := false
done;
if !is_zero then
Ok (String.sub buf (abs n) total_len)
else
Error "input is too long"
| pad_len ->
Ok (String.make pad_len '\000' ^ buf)
let len = function
| "secp256r1" -> 32
| "secp384r1" -> 48
| "secp521r1" -> 66
| _ -> assert false
let parse_secret curve s =
let total_len = len curve in
pad ~total_len s
type test = {
public_key : string;
raw_private_key : string;
expected : string;
}
let perform_key_exchange curve ~public_key ~raw_private_key =
to_string_result ~pp_error
(match curve with
| "secp256r1" ->
begin match P256.Dh.secret_of_octets raw_private_key with
| Ok (p, _) -> P256.Dh.key_exchange p public_key
| Error _ -> assert false
end
| "secp384r1" ->
begin match P384.Dh.secret_of_octets raw_private_key with
| Ok (p, _) -> P384.Dh.key_exchange p public_key
| Error _ -> assert false
end
| "secp521r1" ->
begin match P521.Dh.secret_of_octets raw_private_key with
| Ok (p, _) -> P521.Dh.key_exchange p public_key
| Error _ -> assert false
end
| _ -> assert false)
let interpret_test ~tcId curve { public_key; raw_private_key; expected } () =
match perform_key_exchange curve ~public_key ~raw_private_key with
| Ok got -> Alcotest.check hex __LOC__ expected got
| Error err ->
Printf.ksprintf (fun s -> Alcotest.fail s) "While parsing %d: %s" tcId err
type invalid_test = { public : string; private_ : string }
let is_ok = function Ok _ -> true | Error _ -> false
let interpret_invalid_test curve { public; private_ } () =
let result =
let* public_key = Asn.parse_point curve public in
let* raw_private_key = parse_secret curve private_ in
perform_key_exchange curve ~public_key ~raw_private_key
in
Alcotest.check Alcotest.bool __LOC__ false (is_ok result)
type strategy = Test of test | Invalid_test of invalid_test | Skip
let make_ecdh_test curve (test : ecdh_test) =
let ignored_flags = ["UnnamedCurve"] in
let curve_compression_test curve =
let curves = ["secp256r1"; "secp384r1"; "secp521r1"] in
test.tcId = 2 && List.exists (fun x -> String.equal x curve) curves
in
match test.result with
| _ when has_ignored_flag test ~ignored_flags -> Ok Skip
| Invalid ->
Ok (Invalid_test { public = test.public; private_ = test.private_ })
| Acceptable when curve_compression_test curve ->
let* public_key = Asn.parse_point curve test.public in
let* raw_private_key = parse_secret curve test.private_ in
Ok (Test { public_key; raw_private_key; expected = test.shared })
| Acceptable -> Ok Skip
| Valid ->
let* public_key = Asn.parse_point curve test.public in
let* raw_private_key = parse_secret curve test.private_ in
Ok (Test { public_key; raw_private_key; expected = test.shared })
let to_ecdh_tests curve (x : ecdh_test) =
let name = Printf.sprintf "%d - %s" x.tcId x.comment in
match make_ecdh_test curve x with
| Ok (Test t) -> [ (name, `Quick, interpret_test ~tcId:x.tcId curve t) ]
| Ok (Invalid_test t) -> [ (name, `Quick, interpret_invalid_test curve t) ]
| Ok Skip -> []
| Error e -> Printf.ksprintf failwith "While parsing %d: %s" x.tcId e
let ecdh_tests file =
let data = load_file_exn file in
let groups : ecdh_test_group list =
List.map ecdh_test_group_exn data.testGroups
in
List.concat_map (fun (group : ecdh_test_group) ->
List.concat_map (to_ecdh_tests group.curve) group.tests)
groups
let make_ecdsa_test curve key hash (tst : dsa_test) =
let name = Printf.sprintf "%d - %s" tst.tcId tst.comment in
let size = len curve in
let msg =
let dgst =
match hash with
| "SHA-256" -> Digestif.SHA256.(digest_string tst.msg |> to_raw_string)
| "SHA-384" -> Digestif.SHA384.(digest_string tst.msg |> to_raw_string)
| "SHA-512" -> Digestif.SHA512.(digest_string tst.msg |> to_raw_string)
| "SHA-224" -> Digestif.SHA224.(digest_string tst.msg |> to_raw_string)
| _ -> assert false
in
String.sub dgst 0 (min size (String.length dgst))
in
let verified (r,s) =
match curve with
| "secp256r1" ->
begin match P256.Dsa.pub_of_octets key with
| Ok key -> P256.Dsa.verify ~key (r, s) msg
| Error _ -> assert false
end
| "secp384r1" ->
begin match P384.Dsa.pub_of_octets key with
| Ok key -> P384.Dsa.verify ~key (r, s) msg
| Error _ -> assert false
end
| "secp521r1" ->
begin match P521.Dsa.pub_of_octets key with
| Ok key -> P521.Dsa.verify ~key (r, s) msg
| Error _ -> assert false
end
| _ -> assert false
in
match tst.result with
| Acceptable
| Invalid ->
let f () =
match Asn.parse_signature tst.sig_ with
| Ok (r, s) -> Alcotest.(check bool __LOC__ false (verified (r, s)))
| Error _s -> ()
in
name, `Quick, f
| Valid ->
let f () =
match Asn.parse_signature tst.sig_ with
| Ok (r, s) -> Alcotest.(check bool __LOC__ true (verified (r, s)))
| Error s -> Alcotest.fail s
in
name, `Quick, f
let to_ecdsa_tests (x : ecdsa_test_group) =
List.map
(make_ecdsa_test x.key.curve x.key.uncompressed x.sha)
x.tests
let ecdsa_tests file =
let data = load_file_exn file in
let groups : ecdsa_test_group list =
List.map ecdsa_test_group_exn data.testGroups
in
List.concat_map to_ecdsa_tests groups
let to_x25519_test (x : ecdh_test) =
let name = Printf.sprintf "%d - %s" x.tcId x.comment
and priv =
match X25519.secret_of_octets x.private_ with
| Ok (p, _) -> p
| Error _ -> assert false
in
match x.result with
| Acceptable ->
let f () =
match
X25519.key_exchange priv x.public,
has_ignored_flag x ~ignored_flags:[ "LowOrderPublic" ]
with
| Ok _, true -> Alcotest.fail "acceptable should have errored"
| Ok r, false ->
Alcotest.(check bool __LOC__ true (String.equal r x.shared))
| Error _, true -> ()
| Error e, false -> Alcotest.failf "acceptable errored %a" pp_error e
in
name, `Quick, f
| Invalid ->
let f () =
match X25519.key_exchange priv x.public with
| Ok r -> Alcotest.(check bool __LOC__ false (String.equal r x.shared))
| Error e -> Alcotest.failf "invalid errored %a" pp_error e
in
name, `Quick, f
| Valid ->
let f () =
match X25519.key_exchange priv x.public with
| Ok r -> Alcotest.(check bool __LOC__ true (String.equal r x.shared))
| Error e -> Alcotest.failf "valid errored %a" pp_error e
in
name, `Quick, f
let x25519_tests =
let data = load_file_exn "x25519_test.json" in
let groups : ecdh_test_group list =
List.map ecdh_test_group_exn data.testGroups
in
List.concat_map (fun (group : ecdh_test_group) ->
List.map to_x25519_test group.tests)
groups
let to_ed25519_test (priv, pub) (x : dsa_test) =
let name = Printf.sprintf "%d - %s" x.tcId x.comment in
match x.result with
| Invalid ->
let f () =
Alcotest.(check bool __LOC__ false (Ed25519.verify ~key:pub x.sig_ ~msg:x.msg));
let s = Ed25519.sign ~key:priv x.msg in
Alcotest.(check bool __LOC__ false (String.equal s x.sig_))
in
name, `Quick, f
| Valid ->
let f () =
Alcotest.(check bool __LOC__ true (Ed25519.verify ~key:pub x.sig_ ~msg:x.msg));
let s = Ed25519.sign ~key:priv x.msg in
Alcotest.(check bool __LOC__ true (String.equal s x.sig_))
in
name, `Quick, f
| Acceptable -> assert false
let to_ed25519_keys (key : eddsa_key) =
match Ed25519.priv_of_octets key.sk, Ed25519.pub_of_octets key.pk with
| Ok priv, Ok pub ->
assert (String.equal Ed25519.(pub_to_octets (pub_of_priv priv)) key.pk);
priv, pub
| _ -> assert false
let ed25519_tests =
let data = load_file_exn "eddsa_test.json" in
let groups : eddsa_test_group list =
List.map eddsa_test_group_exn data.testGroups
in
List.concat_map (fun (group : eddsa_test_group) ->
let keys = to_ed25519_keys group.key in
List.map (to_ed25519_test keys) group.tests)
groups
let () =
Alcotest.run "Wycheproof NIST curves" [
("ECDH P256 test vectors", ecdh_tests "ecdh_secp256r1_test.json") ;
("ECDSA P256 test vectors (SHA256)",
ecdsa_tests "ecdsa_secp256r1_sha256_test.json") ;
("ECDSA P256 test vectors (SHA512)",
ecdsa_tests "ecdsa_secp256r1_sha512_test.json") ;
("ECDH P384 test vectors", ecdh_tests "ecdh_secp384r1_test.json") ;
("ECDSA P384 test vectors (SHA384)",
ecdsa_tests "ecdsa_secp384r1_sha384_test.json") ;
("ECDSA P384 test vectors (SHA512)",
ecdsa_tests "ecdsa_secp384r1_sha512_test.json") ;
("ECDH P521 test vectors", ecdh_tests "ecdh_secp521r1_test.json") ;
("ECDSA P521 test vectors (SHA512)",
ecdsa_tests "ecdsa_secp521r1_sha512_test.json") ;
("X25519 test vectors", x25519_tests) ;
("ED25519 test vectors", ed25519_tests) ;
]

View file

@ -0,0 +1,47 @@
let data = ref ""
let cpu_bootstrap_check () =
match Mirage_crypto_rng.Entropy.cpu_rng_bootstrap with
| Error `Not_supported -> print_endline "no CPU RNG available"
| Ok cpu_rng_bootstrap ->
match cpu_rng_bootstrap 1 with
| exception Failure _ -> print_endline "bad CPU RNG"
| data' ->
data := data';
for i = 0 to 10 do
try
let data' = cpu_rng_bootstrap 1 in
if String.equal !data data' then begin
Ohex.pp Format.std_formatter data';
failwith ("same data from CPU bootstrap at " ^ string_of_int i);
end;
data := data'
with Failure _ -> print_endline ("CPU RNG failed at " ^ string_of_int i)
done
let whirlwind_bootstrap_check () =
for i = 0 to 10 do
let data' = Mirage_crypto_rng.Entropy.whirlwind_bootstrap 1 in
if String.equal !data data' then begin
Ohex.pp Format.std_formatter data';
failwith ("same data from whirlwind bootstrap at " ^ string_of_int i);
end;
data := data'
done
let timer_check () =
for i = 0 to 10 do
let data' = Mirage_crypto_rng.Entropy.interrupt_hook () in
if String.equal !data data' then begin
Ohex.pp Format.std_formatter data';
failwith ("same data from timer at " ^ string_of_int i);
end;
data := data'
done
let () =
timer_check ();
cpu_bootstrap_check ();
whirlwind_bootstrap_check ();
print_endline "test entropy OK"

View file

@ -0,0 +1,36 @@
open Lwt.Infix
module Printing_rng = struct
type g = unit
let block = 16
let create ?time:_ () = ()
let generate_into ~g:_ _buf ~off:_ _len = assert false
let reseed ~g:_ data =
Format.printf "reseeding:@.%a@.%!" (Ohex.pp_hexdump ()) data
let accumulate ~g:_ source =
let print data =
Format.printf "accumulate: (src: %a) %a@.%!"
Mirage_crypto_rng.Entropy.pp_source source Ohex.pp data
in
`Acc print
let seeded ~g:_ = true
let pools = 1
end
let with_entropy act =
Mirage_crypto_rng_mirage.initialize (module Printing_rng) >>= fun () ->
Format.printf "entropy sources: %a@,%!"
(fun ppf -> List.iter (fun x ->
Mirage_crypto_rng.Entropy.pp_source ppf x;
Format.pp_print_space ppf ()))
(Mirage_crypto_rng.Entropy.sources ());
act ()
let () =
Unix_os.(Main.run (with_entropy (fun () -> Time.sleep_ns (Duration.of_sec 3))))

View file

@ -0,0 +1,31 @@
module Printing_rng = struct
type g = unit
let block = 16
let create ?time:_ () = ()
let generate_into ~g:_ _buf ~off:_ _len = assert false
let seeded ~g:_ = true
let pools = 1
let reseed ~g:_ data =
Format.printf "reseeding:@.%a@.%!" (Ohex.pp_hexdump ()) data
let accumulate ~g:_ source =
let print data =
Format.printf "accumulate: (src: %a) %a@.%!"
Mirage_crypto_rng.Entropy.pp_source source Ohex.pp data
in
`Acc print
end
let () =
Miou_unix.run @@ fun () ->
let rng = Mirage_crypto_rng_miou_unix.initialize (module Printing_rng) in
Format.printf "entropy sources: %a@,%!"
(fun ppf -> List.iter (fun x ->
Mirage_crypto_rng.Entropy.pp_source ppf x;
Format.pp_print_space ppf ()))
(Mirage_crypto_rng.Entropy.sources ());
let sleep = Duration.(of_sec 2 |> to_f) in
Miou_unix.sleep sleep;
Mirage_crypto_rng_miou_unix.kill rng

View file

@ -0,0 +1,16 @@
let () = Miou_unix.run @@ fun () ->
let rng = Mirage_crypto_rng_miou_unix.(initialize (module Pfortuna)) in
let random_num = Mirage_crypto_rng.generate 32 in
assert (String.length random_num = 32);
Printf.printf "32 bit random number: %s\n%!" (Ohex.encode random_num);
let random_num = Mirage_crypto_rng.generate 16 in
assert (String.length random_num = 16);
Printf.printf "16 bit random number: %s\n%!" (Ohex.encode random_num);
(* NOTE(dinosaure): the test below shows that [Pfortuna] is domain-safe when
run with TSan. If we use the Fortuna engine, TSan will report invalid
accesses between the domain that seeds the RNG and [dom0]. *)
for _ = 0 to 4 do
let _ = Mirage_crypto_rng.generate 16 in
Miou_unix.sleep 0.5;
done;
Mirage_crypto_rng_miou_unix.kill rng

View file

@ -0,0 +1,49 @@
open OUnit2
open Mirage_crypto.Uncommon
open Mirage_crypto_pk
open Test_common
let n_encode_decode_selftest ~typ ~bound n =
typ ^ "selftest" >:: times ~n @@ fun _ ->
let r = Z_extra.gen bound in
let s = Z_extra.(of_octets_be @@ to_octets_be r)
and t = Z_extra.(of_octets_be @@ to_octets_be ~size:24 r) in
assert_equal r s;
assert_equal r t
let n_decode_reencode_selftest ~typ ~bytes n =
typ ^ " selftest" >:: times ~n @@ fun _ ->
let cs = Mirage_crypto_rng.generate bytes in
let cs' = Z_extra.(to_octets_be ~size:bytes @@ of_octets_be cs) in
assert_oct_equal cs cs'
let random_n_selftest ~typ n bounds =
typ ^ " selftest" >::: (
bounds |> List.map @@ fun (lo, hi) ->
"selftest" >:: times ~n @@ fun _ ->
let x = Z_extra.gen_r lo hi in
if x < lo || x >= hi then assert_failure "range error"
)
let int_safe_bytes = Sys.word_size // 8 - 1
let suite = [
"Numeric extraction 1" >::: [
n_encode_decode_selftest
~typ:"z" ~bound:Z.(of_int64 Int64.max_int) 2000 ;
] ;
"Numeric extraction 2" >::: [
n_decode_reencode_selftest ~typ:"z" ~bytes:37 2000 ;
];
"RNG extraction" >::: [
random_n_selftest ~typ:"Z" 1000 [
Z.(of_int 7, of_int 135);
Z.(of_int 0, of_int 536870913);
Z.(of_int 0, of_int64 2305843009213693953L)
] ;
]
]

View file

@ -0,0 +1,13 @@
open OUnit2
let suite =
"All" >::: [
"Numeric" >::: Test_numeric.suite;
"DHE" >::: Test_dh.suite;
"DSA" >::: Test_dsa.suite;
"RSA" >::: Test_rsa.suite;
]
let () =
Mirage_crypto_rng_unix.use_default ();
run_test_tt_main suite

View file

@ -0,0 +1,109 @@
open OUnit2
open Mirage_crypto
open Test_common
let sample arr =
let ix =
Randomconv.int ~bound:(Array.length arr) Mirage_crypto_rng.generate
in
arr.(ix)
(* randomized selfies *)
let ecb_selftest (m : (module Block.ECB)) n =
let module C = ( val m ) in
"selftest" >:: times ~n @@ fun _ ->
let data = Mirage_crypto_rng.generate (C.block_size * 8)
and key = C.of_secret @@ Mirage_crypto_rng.generate (sample C.key_sizes) in
let data' =
C.( data |> encrypt ~key |> encrypt ~key
|> decrypt ~key |> decrypt ~key ) in
assert_oct_equal ~msg:"ecb mismatch" data data'
let cbc_selftest (m : (module Block.CBC)) n =
let module C = ( val m ) in
"selftest" >:: times ~n @@ fun _ ->
let data = Mirage_crypto_rng.generate (C.block_size * 8)
and iv = Mirage_crypto_rng.generate C.block_size
and key = C.of_secret @@ Mirage_crypto_rng.generate (sample C.key_sizes) in
assert_oct_equal ~msg:"CBC e->e->d->d" data
C.( data |> encrypt ~key ~iv |> encrypt ~key ~iv
|> decrypt ~key ~iv |> decrypt ~key ~iv );
let (d1, d2) =
String.sub data 0 (C.block_size * 4),
String.sub data (C.block_size * 4) (String.length data - C.block_size * 4)
in
assert_oct_equal ~msg:"CBC chain"
C.(encrypt ~key ~iv data)
C.( let e1 = encrypt ~key ~iv d1 in
e1 ^ encrypt ~key ~iv:(next_iv ~iv e1) d2)
let ctr_selftest (m : (module Block.CTR)) n =
let module M = (val m) in
let bs = M.block_size in
"selftest" >:: times ~n @@ fun _ ->
let key = M.of_secret @@ Mirage_crypto_rng.generate (sample M.key_sizes)
and ctr = Mirage_crypto_rng.generate bs |> M.ctr_of_octets
and data = Mirage_crypto_rng.(generate @@ bs + Randomconv.int ~bound:(20 * bs) Mirage_crypto_rng.generate) in
let enc = M.encrypt ~key ~ctr data in
let dec = M.decrypt ~key ~ctr enc in
assert_oct_equal ~msg:"CTR e->d" data dec;
let (d1, d2) =
let s = bs * Randomconv.int ~bound:(String.length data / bs) Mirage_crypto_rng.generate in
String.sub data 0 s, String.sub data s (String.length data - s)
in
assert_oct_equal ~msg:"CTR chain" enc @@
M.encrypt ~key ~ctr d1 ^ M.encrypt ~key ~ctr:(M.next_ctr ~ctr d1) d2
let ctr_offsets (type c) ~zero (m : (module Block.CTR with type ctr = c)) n =
let module M = (val m) in
"offsets" >:: fun _ ->
let key = M.of_secret @@ Mirage_crypto_rng.generate M.key_sizes.(0) in
for i = 0 to n - 1 do
let ctr = match i with
| 0 -> M.add_ctr zero (-1L)
| _ -> Mirage_crypto_rng.generate M.block_size |> M.ctr_of_octets
and gap = Randomconv.int ~bound:64 Mirage_crypto_rng.generate in
let s1 = M.stream ~key ~ctr ((gap + 1) * M.block_size)
and s2 = M.stream ~key ~ctr:(M.add_ctr ctr (Int64.of_int gap)) M.block_size in
assert_oct_equal ~msg:"shifted stream"
String.(sub s1 (gap * M.block_size) M.block_size) s2
done
let xor_selftest n =
"selftest" >:: times ~n @@ fun _ ->
let n = Randomconv.int ~bound:30 Mirage_crypto_rng.generate in
let (x, y, z) = Mirage_crypto_rng.(generate n, generate n, generate n) in
let xyz = Uncommon.(xor (xor x y) z)
and xyz' = Uncommon.(xor x (xor y z)) in
let x1 = Uncommon.(xor xyz (xor y z))
and x2 = Uncommon.(xor (xor z y) xyz) in
assert_oct_equal ~msg:"assoc" xyz xyz' ;
assert_oct_equal ~msg:"invert" x x1 ;
assert_oct_equal ~msg:"commut" x1 x2
let suite =
"All" >::: [
"XOR" >::: [ xor_selftest 300 ] ;
"3DES-ECB" >::: [ ecb_selftest (module DES.ECB) 100 ] ;
"3DES-CBC" >::: [ cbc_selftest (module DES.CBC) 100 ] ;
"3DES-CTR" >::: [ ctr_selftest (module DES.CTR) 100;
ctr_offsets (module DES.CTR) 100 ~zero:0L; ] ;
"AES-ECB" >::: [ ecb_selftest (module AES.ECB) 100 ] ;
"AES-CBC" >::: [ cbc_selftest (module AES.CBC) 100 ] ;
"AES-CTR" >::: [ ctr_selftest (module AES.CTR) 100;
ctr_offsets (module AES.CTR) 100 ~zero:(0L, 0L) ] ;
]
let () =
Mirage_crypto_rng_unix.use_default ();
run_test_tt_main suite

View file

@ -0,0 +1,326 @@
open OUnit2
open Mirage_crypto.Uncommon
open Mirage_crypto_pk
open Test_common
let vz = Z.of_string_base 16
module Null = struct
type g = string ref
let block = 1
let create ?time:_ () = ref ""
let generate_into ~g buf ~off n =
try
Bytes.blit_string !g 0 buf off n;
g := String.sub !g n (String.length !g - n)
with Invalid_argument _ -> raise Mirage_crypto_rng.Unseeded_generator
let reseed ~g buf = g := !g ^ buf
let seeded ~g = String.length !g > 0
let accumulate ~g _source = `Acc (reseed ~g)
let pools = 0
end
let random_is seed =
Mirage_crypto_rng.create ~seed:seed (module Null)
let gen_rsa ~bits =
let e = Z.(if bits < 24 then ~$3 else ~$0x10001) in
let key = Rsa.(generate ~e ~bits ()) in
assert_equal
~msg:Printf.(sprintf "key size not %d bits" bits)
bits Rsa.(priv_bits key);
key
let rsa_priv_of_primes_regression _ =
let e = Z.of_string "65537"
and p = Z.of_string "63541376186162969"
and q = Z.of_string "31114890003960709"
in
match Rsa.priv_of_primes ~e ~p ~q with
| exception _ -> assert_failure "expected an error"
| Error _ -> () (* expected since there's no multiplicative inverse of e with p and q (e is not coprime to q-1) *)
| Ok _ -> assert_failure "expected an error"
let rsa_priv_of_primes_regression_62 _ =
(* reported in https://github.com/mirage/mirage-crypto/issues/62 *)
let e = Z.of_string "65537"
and d = Z.of_string "3108431922676000487023821479912741349223115124336455693119108686758268939583975029271734799300422643496417197940166373626629291080744953934921341465364968117931378406446980227029856589807773725566867068344285160902403880508627911649654611750749193657211787605701986962527879646827816649512856008836705430283000626732452720870471763615388887743731833942366593788032394353874580439986226556671690116837426402890882760501726581078126288439928304880443426230837881572485961139412262011517513033934716366580117961709814170065275361576176352257579474519828879342959023237100172806323217608845596279839036960301580039126471"
and p = Z.of_string "153903575880038685371306078431309624429262243098160628077155385424784731704538502041682563231842507936315834999272165353754081206847521073697105321898935865522941018859502063500927758809727634595752231111149172755709224739427971151799944749671230555614514021717987321482212474581192462617805386071920647746527"
and q = Z.of_string "147755586168842154977618773600930512327712333912540690382962931855233965897097814139102488669702400832893695675498969512696944576662243412004204531041931249551207758395795244675585651830739018019197553505240463928167645984560980989768623533294470387237934457819888352229242173694504296968786124698140038767907"
in
match Rsa.priv_of_primes ~e ~p ~q with
| exception _ -> assert_failure "expected ok"
| Error _ -> assert_failure "expected ok"
| Ok priv -> assert_equal ~msg:"d is equal" d priv.Rsa.d
let rsa_priv_of_primes_regression_openssl _ =
let e = Z.of_string "65537"
and d = Z.of_string "21364966876797335224937981624977347791305770821352826744474497613118281825259093305200082888709328664041494911511266059341542974088052755771514853303591832823929488189866359158215383109671205375680439686889619887327157945061169995481249526193538164572824333945969914914389168250738641676992853978375324165227210205971488866002577771580610214948106221456525289283949750296156474480874426885065689443846254958870114957680850339336866525023540164187023510310849878330359224986984785647477789876024460216392539430087762483228942540109987168856343992537776070047681434965518603440527188618027182112877268689620116969210881"
and n = Z.of_string "26003711217261578550621411093788590465379160983527099623976249862031215614567566726273034808107255370042109943463095563849992606559609134476057069066550866318424151608276781565055186325047761889573394045234279585405785949661514281355247375815212099164453968239368389736365243837028903903448365174400765513065279734735815019879815099687407795902081216735845663253559329668423470162638675450802885820025108018425582646833277581392446992199509644421030247759098658756879463797225451870622102492377704722852444790028849818045531971545099489092363404165512101521453346604003075697381546910357245133314194790971809369935729"
and p = Z.of_string "167173249562998285344683400251639903569188485523881465771532263785652572249038345452185825418846021360573529483365315302293816993785521941622864243995179759923984427691147261149068664025532174455772795926386901753396733517983474861943826134177458663773607339275619054052496007070211507365125143035209397925137"
and q = Z.of_string "155549475081910328806496663071699269060677442531084543754539870945308062234020815068226104598610337898669482436828867339638346797527566740356018599563448611471831039630098224992256888467779107812081557864642282199069694603496263731994138092467683330232979926332910833392744391017831937213832896615543518213217"
and dp = Z.of_string "132755002521578387208427344594600716257302676970335642531907550489959907687702391789577781987250291220069407638925560669432220144720901230294648011268216967903380465305980866674430162359351152591303223998548604831679503169353677551841013279935481616452288331251969392085510508445032389174215678839807099891905"
and dq = Z.of_string "152169667453904159646778469559422238388806519569028538897642778063026012695267963386624048157997842343979683651561853178299789862671237414352891045879600543621061437719219486685819703226188594826677829613436846951019352886368859676966296527494096180039169354974776267777118591655496269139424576967397677391457"
and q' = Z.of_string "71680879219372822058570738508033808601658137476144867031269752035545521971293179931151996149323998570187762489030494773672093398051821155138733159825225031201464935294877263527756698979264488516898115736148932950739809310843167520947847241161602397933518005104012950660916455073023725039529353919943223042903"
in
match Rsa.priv ~e ~d ~n ~p ~q ~dp ~dq ~q' with
| exception _ -> assert_failure "expected ok"
| Error _ -> assert_failure "expected ok"
| Ok _ -> ()
let rsa_selftest ~bits n =
"selftest" >:: times ~n @@ fun _ ->
let msg =
let size = bits // 8 in
let buf = Bytes.create size in
Mirage_crypto_rng.generate_into buf ~off:0 size;
let i = 1 + Randomconv.int ~bound:(pred size) Mirage_crypto_rng.generate in
Bytes.set_uint8 buf 0 0;
Bytes.(set_uint8 buf i (get_uint8 buf i lor 2));
Bytes.unsafe_to_string buf
in
let key = gen_rsa ~bits in
let enc = Rsa.(encrypt ~key:(pub_of_priv key) msg) in
let dec = Rsa.(decrypt ~key enc) in
assert_oct_equal
~msg:Printf.(sprintf "failed decryption with")
msg dec
let show_key_size key =
Printf.sprintf "(%d bits)" (Rsa.priv_bits key)
let pkcs_message_for_bits bits =
let padding = 12 in
let size = bits // 8 - padding in
assert (size >= 0) ; Mirage_crypto_rng.generate size
let rsa_pkcs1_encode_selftest ~bits n =
"selftest" >:: times ~n @@ fun _ ->
let key = gen_rsa ~bits
and msg = pkcs_message_for_bits bits in
let sgn = Rsa.PKCS1.sig_encode ~key msg in
match Rsa.(PKCS1.sig_decode ~key:(pub_of_priv key) sgn) with
| None -> assert_failure ("unpad failure " ^ show_key_size key)
| Some dec -> assert_oct_equal msg dec
~msg:("recovery failure " ^ show_key_size key)
let rsa_pkcs1_sign_selftest n =
let open Digestif.SHA1 in
"selftest" >:: times ~n @@ fun _ ->
let key = gen_rsa ~bits:(Rsa.PKCS1.min_key `SHA1)
and msg = Mirage_crypto_rng.generate 47 in
let pkey = Rsa.pub_of_priv key in
assert_bool "invert 1" Rsa.PKCS1.(
verify ~key:pkey ~hashp:any (`Message msg)
~signature:(sign ~hash:`SHA1 ~key (`Digest (digest_string msg |> to_raw_string))) );
assert_bool "invert 2" Rsa.PKCS1.(
verify ~key:pkey ~hashp:any (`Digest (digest_string msg |> to_raw_string))
~signature:(sign ~hash:`SHA1 ~key (`Message msg)) )
let rsa_pkcs1_encrypt_selftest ~bits n =
"selftest" >:: times ~n @@ fun _ ->
let key = gen_rsa ~bits
and msg = pkcs_message_for_bits bits in
let enc = Rsa.(PKCS1.encrypt ~key:(pub_of_priv key) msg) in
match Rsa.PKCS1.decrypt ~key enc with
| None -> assert_failure ("unpad failure " ^ show_key_size key)
| Some dec -> assert_oct_equal msg dec
~msg:("recovery failure " ^ show_key_size key)
let rsa_oaep_encrypt_selftest ~bits n =
let module OAEP_MD5 = Rsa.OAEP (Digestif.MD5) in
let module OAEP_SHA1 = Rsa.OAEP (Digestif.SHA1) in
let module OAEP_SHA224 = Rsa.OAEP (Digestif.SHA224) in
let module OAEP_SHA256 = Rsa.OAEP (Digestif.SHA256) in
let module OAEP_SHA384 = Rsa.OAEP (Digestif.SHA384) in
"selftest" >:: times ~n @@ fun _ ->
let key = gen_rsa ~bits in
let msg = Mirage_crypto_rng.generate (bits // 8 - 2 * Digestif.MD5.digest_size - 2) in
let enc = OAEP_MD5.encrypt ~key:(Rsa.pub_of_priv key) msg in
(match OAEP_MD5.decrypt ~key enc with
| None -> assert_failure "unpad failure"
| Some dec -> assert_oct_equal msg dec ~msg:"recovery failure");
let msg = Mirage_crypto_rng.generate (bits // 8 - 2 * Digestif.SHA1.digest_size - 2) in
let enc = OAEP_SHA1.encrypt ~key:(Rsa.pub_of_priv key) msg in
(match OAEP_SHA1.decrypt ~key enc with
| None -> assert_failure "unpad failure"
| Some dec -> assert_oct_equal msg dec ~msg:"recovery failure");
let msg = Mirage_crypto_rng.generate (bits // 8 - 2 * Digestif.SHA224.digest_size - 2) in
let enc = OAEP_SHA224.encrypt ~key:(Rsa.pub_of_priv key) msg in
(match OAEP_SHA224.decrypt ~key enc with
| None -> assert_failure "unpad failure"
| Some dec -> assert_oct_equal msg dec ~msg:"recovery failure");
let msg = Mirage_crypto_rng.generate (bits // 8 - 2 * Digestif.SHA256.digest_size - 2) in
let enc = OAEP_SHA256.encrypt ~key:(Rsa.pub_of_priv key) msg in
(match OAEP_SHA256.decrypt ~key enc with
| None -> assert_failure "unpad failure"
| Some dec -> assert_oct_equal msg dec ~msg:"recovery failure");
let msg = Mirage_crypto_rng.generate (bits // 8 - 2 * Digestif.SHA384.digest_size - 2) in
let enc = OAEP_SHA384.encrypt ~key:(Rsa.pub_of_priv key) msg in
(match OAEP_SHA384.decrypt ~key enc with
| None -> assert_failure "unpad failure"
| Some dec -> assert_oct_equal msg dec ~msg:"recovery failure")
let rsa_pss_sign_selftest ~bits n =
let module Pss_sha1 = Rsa.PSS (Digestif.SHA1) in
"selftest" >:: times ~n @@ fun _ ->
let key = gen_rsa ~bits
and msg = Mirage_crypto_rng.generate 1024 in
let pkey = Rsa.pub_of_priv key in
let dgst = Digestif.SHA1.(digest_string msg |> to_raw_string) in
let signature = Pss_sha1.sign ~key (`Digest dgst) in
Pss_sha1.(verify ~key:pkey (`Message msg) ~signature) |> assert_bool "invert 1" ;
Pss_sha1.(verify ~key:pkey (`Digest dgst)
~signature:(Pss_sha1.sign ~key (`Message msg)))
|> assert_bool "invert 2"
let rsa_pkcs1_cases =
let key () =
let n = vz "c8a2069182394a2ab7c3f4190c15589c56a2d4bc42dca675b34cc950e24663048441e8aa593b2bc59e198b8c257e882120c62336e5cc745012c7ffb063eebe53f3c6504cba6cfe51baa3b6d1074b2f398171f4b1982f4d65caf882ea4d56f32ab57d0c44e6ad4e9cf57a4339eb6962406e350c1b15397183fbf1f0353c9fc991"
and d = vz "5dfcb111072d29565ba1db3ec48f57645d9d8804ed598a4d470268a89067a2c921dff24ba2e37a3ce834555000dc868ee6588b7493303528b1b3a94f0b71730cf1e86fca5aeedc3afa16f65c0189d810ddcd81049ebbd0391868c50edec958b3a2aaeff6a575897e2f20a3ab5455c1bfa55010ac51a7799b1ff8483644a3d425"
and e = vz "10001"
in
match Rsa.priv_of_exp ~e ~d ~n () with
| Error (`Msg m) -> invalid_arg "bad key %s" m
| Ok key -> key, Rsa.pub_of_priv key
in
let case ~hash ~msg ~sgn = test_case @@ fun _ ->
let msg = vx msg and sgn = vx sgn in
let key, public = key () in
Rsa.(PKCS1.sign ~hash ~key (`Message msg))
|> assert_oct_equal ~msg:"recomputing sig:" sgn ;
Rsa.(PKCS1.verify ~hashp:any ~key:public ~signature:sgn (`Message msg))
|> assert_bool "sig verification" in
"FIPS 186-2 Test Vectors (1024 bits)" >::: [
case ~hash:`SHA1
~msg:"e8312742ae23c456ef28a23142c4490895832765dadce02afe5be5d31b0048fbeee2cf218b1747ad4fd81a2e17e124e6af17c3888e6d2d40c00807f423a233cad62ce9eaefb709856c94af166dba08e7a06965d7fc0d8e5cb26559c460e47bc088589d2242c9b3e62da4896fab199e144ec136db8d84ab84bcba04ca3b90c8e5"
~sgn:"28928e19eb86f9c00070a59edf6bf8433a45df495cd1c73613c2129840f48c4a2c24f11df79bc5c0782bcedde97dbbb2acc6e512d19f085027cd575038453d04905413e947e6e1dddbeb3535cdb3d8971fe0200506941056f21243503c83eadde053ed866c0e0250beddd927a08212aa8ac0efd61631ef89d8d049efb36bb35f"
; case ~hash:`SHA1
~msg:"4c95073dac19d0256eaadff3505910e431dd50018136afeaf690b7d18069fcc980f6f54135c30acb769bee23a7a72f6ce6d90cbc858c86dbbd64ba48a07c6d7d50c0e9746f97086ad6c68ee38a91bbeeeb2221aa2f2fb4090fd820d4c0ce5ff025ba8adf43ddef89f5f3653de15edcf3aa8038d4686960fc55b2917ec8a8f9a8"
~sgn:"53ab600a41c71393a271b0f32f521963087e56ebd7ad040e4ee8aa7c450ad18ac3c6a05d4ae8913e763cfe9623bd9cb1eb4bed1a38200500fa7df3d95dea485f032a0ab0c6589678f9e8391b5c2b1392997ac9f82f1d168878916aace9ac7455808056af8155231a29f42904b7ab87a5d71ed6395ee0a9d024b0ca3d01fd7150"
; case ~hash:`SHA1
~msg:"e075ad4b0f9b5b20376e467a1a35e308793ba38ed983d03887b8b82eda630e68b8618dc45b93de5555d7bcfed23756401e61f5516757de6ec3687a71755fb4a66cfaa3db0c9e69b631485b4c71c762eea229a0469c7357a440950792ba9cd7ae022a36b9a923c2ebd2aa69897f4cceba0e7aee97033d03810725a9b731833f27"
~sgn:"642609ce084f479271df596480252e2f892b3e7982dff95994c3eeda787f80f3f6198bbce33ec5515378d4b571d7186078b75b43aed11d342547386c5696eb3799a0b28475e54cd4ca7d036dcd8a11f5e10806f7d3b8cc4fcb3e93e857be958344a34e126809c15b3d33661cf57bf5c338f07acced60f14019335c152d86b3b2"
; case ~hash:`SHA224
~msg:"e567a39ae4e5ef9b6801ea0561b72a5d4b5f385f0532fc9fe10a7570f869ae05c0bdedd6e0e22d4542e9ce826a188cac0731ae39c8f87f9771ef02132e64e2fb27ada8ff54b330dd93ad5e3ef82e0dda646248e35994bda10cf46e5abc98aa7443c03cddeb5ee2ab82d60100b1029631897970275f119d05daa2220a4a0defba"
~sgn:"5aa5033381bdd0acce332dd314daf008acaa9e835f832979891d1bda2b55d5eae35c479c06cac5bf33f432c8c0a5549d1d1b29c5e2589024d27800a0c235a61532c203cbc406ac6ecf63f52ae771b97c08e4b108ec916900e5a11b1d48cca86ca5a5a799ed32e99c815cef04cf8eb55223bfd4d9c3449264b60061bc3684bc82"
; case ~hash:`SHA256
~msg:"e567a39ae4e5ef9b6801ea0561b72a5d4b5f385f0532fc9fe10a7570f869ae05c0bdedd6e0e22d4542e9ce826a188cac0731ae39c8f87f9771ef02132e64e2fb27ada8ff54b330dd93ad5e3ef82e0dda646248e35994bda10cf46e5abc98aa7443c03cddeb5ee2ab82d60100b1029631897970275f119d05daa2220a4a0defba"
~sgn:"0e7cdd121e40323ca6115d1ec6d1f9561738455f0e9e1cd858e8b566ae2da5e8ee63d8f15c3cdd88027e13406db609369c88ca99b34fa156c7ee62bc5a3923bb5a1edabd45c1a422aafcbb47e0947f35cfef87970b4b713162b21916cafb8c864a3e5b9ffc989401d4eae992312a32c5bc88abbb45f99ac885b54d6b8e61b6ec"
; case ~hash:`SHA384
~msg:"e567a39ae4e5ef9b6801ea0561b72a5d4b5f385f0532fc9fe10a7570f869ae05c0bdedd6e0e22d4542e9ce826a188cac0731ae39c8f87f9771ef02132e64e2fb27ada8ff54b330dd93ad5e3ef82e0dda646248e35994bda10cf46e5abc98aa7443c03cddeb5ee2ab82d60100b1029631897970275f119d05daa2220a4a0defba"
~sgn:"1689a8523919ac77cc997ebc59cb908872d88b2855a309ead2779b888b22b4232da9b93bb19b32c1db77ad738c6e43361e9eb6b1a37c49a8f3c7c7ae7e784d19a62138741293e49b1831c0c3617eb43c56706d83314953470636441086419ab9e6fd1ec4f9d5cc6544815d1e02ed96a3ae64c6998b2cf238e79a12164352d12a"
; case ~hash:`SHA512
~msg:"e567a39ae4e5ef9b6801ea0561b72a5d4b5f385f0532fc9fe10a7570f869ae05c0bdedd6e0e22d4542e9ce826a188cac0731ae39c8f87f9771ef02132e64e2fb27ada8ff54b330dd93ad5e3ef82e0dda646248e35994bda10cf46e5abc98aa7443c03cddeb5ee2ab82d60100b1029631897970275f119d05daa2220a4a0defba"
~sgn:"bf3ff2c69675f1b8ed421021801fb4ce29a757f7f8869ce436d0d75ab749efc8b903d9f9cb214686147f12f3335fa936689c192f310ae3c5d75493f44b24bc1cd3501584aaa5004b65a8716d1eda7240ad8a529d5a0cf169f4054b450e076ee0d41a0011c557aa69a84a8104c909201d60fe39c79e684347ef4d144ea18f7a4e"
]
let rsa_pss_cases =
let key () =
let n = vz "bcb47b2e0dafcba81ff2a2b5cb115ca7e757184c9d72bcdcda707a146b3b4e29989ddc660bd694865b932b71ca24a335cf4d339c719183e6222e4c9ea6875acd528a49ba21863fe08147c3a47e41990b51a03f77d22137f8d74c43a5a45f4e9e18a2d15db051dc89385db9cf8374b63a8cc88113710e6d8179075b7dc79ee76b"
and d = vz "383a6f19e1ea27fd08c7fbc3bfa684bd6329888c0bbe4c98625e7181f411cfd0853144a3039404dda41bce2e31d588ec57c0e148146f0fa65b39008ba5835f829ba35ae2f155d61b8a12581b99c927fd2f22252c5e73cba4a610db3973e019ee0f95130d4319ed413432f2e5e20d5215cdd27c2164206b3f80edee51938a25c1"
and e = vz "10001"
in
match Rsa.priv_of_exp ~e ~d ~n () with
| Error (`Msg m) -> invalid_arg "bad key %s" m
| Ok key -> key, Rsa.pub_of_priv key
and salt = "6f2841166a64471d4f0b8ed0dbb7db32161da13b"
in
let case (type a) ~(hash : a Digestif.hash) ~msg ~sgn = test_case @@ fun _ ->
let module H = (val Digestif.module_of hash) in
let module Pss = Rsa.PSS (H) in
let msg = vx msg and sgn = vx sgn and salt = vx salt in
let key, public = key () in
let slen = String.length salt in
Pss.sign ~g:(random_is salt) ~slen ~mask:`No ~key (`Message msg)
|> assert_oct_equal ~msg:"recomputing sig:" sgn ;
Pss.verify ~key:public ~slen ~signature:sgn (`Message msg)
|> assert_bool "sig verification" in
"FIPS 186-2 Test Vectors (1024 bits)" >::: [
case ~hash:Digestif.sha1
~msg:"1248f62a4389f42f7b4bb131053d6c88a994db2075b912ccbe3ea7dc611714f14e075c104858f2f6e6cfd6abdedf015a821d03608bf4eba3169a6725ec422cd9069498b5515a9608ae7cc30e3d2ecfc1db6825f3e996ce9a5092926bc1cf61aa42d7f240e6f7aa0edb38bf81aa929d66bb5d890018088458720d72d569247b0c"
~sgn:"682cf53c1145d22a50caa9eb1a9ba70670c5915e0fdfde6457a765de2a8fe12de9794172a78d14e668d498acedad616504bb1764d094607070080592c3a69c343d982bd77865873d35e24822caf43443cc10249af6a1e26ef344f28b9ef6f14e09ad839748e5148bcceb0fd2aa63709cb48975cbf9c7b49abc66a1dc6cb5b31a"
; case ~hash:Digestif.sha1
~msg:"9968809a557bb4f892039ff2b6a0efcd06523624bc3b9ad359a7cf143c4942e874c797b9d37a563d436fe19d5db1aad738caa2617f87f50fc7fcf4361fc85212e89a9465e7f4c361982f64c8c5c0aa5258b9e94f6e934e8dac2ace7cd6095c909de85fe7b973632c384d0ebb165556050d28f236aee70e16b13a432d8a94c62b"
~sgn:"8f5ea7037367e0db75670504085790acd6d97d96f51e76df916a0c2e4cd66e1ab51c4cd8e2c3e4ef781f638ad65dc49c8d6d7f6930f80b6ae199ea283a8924925a50edab79bb3f34861ffa8b2f96fdf9f8cad3d3f8f025478c81f316da61b0d6a7f71b9068efdfb33c21983a922f4669280d8e84f963ff885ef56dd3f50381db"
; case ~hash:Digestif.sha224
~msg:"1248f62a4389f42f7b4bb131053d6c88a994db2075b912ccbe3ea7dc611714f14e075c104858f2f6e6cfd6abdedf015a821d03608bf4eba3169a6725ec422cd9069498b5515a9608ae7cc30e3d2ecfc1db6825f3e996ce9a5092926bc1cf61aa42d7f240e6f7aa0edb38bf81aa929d66bb5d890018088458720d72d569247b0c"
~sgn:"53d859c9f10abf1c00284a4b55bf2bd84d8e313b4f3c35b8dec7bc3afe39b9b8a155418ead1931895769ce2340be2091f2385bbcf10d9e92bcf5d0e2960d10e792e7d865c64e50d19ffa13e52817d7d8d8db34392c2374a2e9b69184f92a4ad9b1b8bae99ca614d204b65a438e38dbbfc8c7cc44ed5677af70ce6c4f951f0244"
; case ~hash:Digestif.sha256
~msg:"1248f62a4389f42f7b4bb131053d6c88a994db2075b912ccbe3ea7dc611714f14e075c104858f2f6e6cfd6abdedf015a821d03608bf4eba3169a6725ec422cd9069498b5515a9608ae7cc30e3d2ecfc1db6825f3e996ce9a5092926bc1cf61aa42d7f240e6f7aa0edb38bf81aa929d66bb5d890018088458720d72d569247b0c"
~sgn:"7b1d37278e549898d4084e2210c4a9961edfe7b5963550cca1904248c8681513539017820f0e9bd074b9f8a067b9fefff7f1fa20bf2d0c75015ff020b2210cc7f79034fedf68e8d44a007abf4dd82c26e8b00393723aea15abfbc22941c8cf79481718c008da713fb8f54cb3fca890bde1137314334b9b0a18515bfa48e5ccd0"
; case ~hash:Digestif.sha384
~msg:"1248f62a4389f42f7b4bb131053d6c88a994db2075b912ccbe3ea7dc611714f14e075c104858f2f6e6cfd6abdedf015a821d03608bf4eba3169a6725ec422cd9069498b5515a9608ae7cc30e3d2ecfc1db6825f3e996ce9a5092926bc1cf61aa42d7f240e6f7aa0edb38bf81aa929d66bb5d890018088458720d72d569247b0c"
~sgn:"8f16c807bef3ed6f74ee7ff5c360a5428c6c2f105178b58ff7d073e566dad6e7718d3129c768cd5a9666de2b6c947177b45709dc7cd0f43b0ba6fc75578e1196acc15ca3afe4a78c144cb6885c1cc815f7f98925bc04ad2ff20fc1068b045d9450e2a1dcf5a161ceabba2b0b66c7354fdb80fa1d729e5f976387f24a697a7e56"
; case ~hash:Digestif.sha512
~msg:"1248f62a4389f42f7b4bb131053d6c88a994db2075b912ccbe3ea7dc611714f14e075c104858f2f6e6cfd6abdedf015a821d03608bf4eba3169a6725ec422cd9069498b5515a9608ae7cc30e3d2ecfc1db6825f3e996ce9a5092926bc1cf61aa42d7f240e6f7aa0edb38bf81aa929d66bb5d890018088458720d72d569247b0c"
~sgn:"a833ba31634f8773e4fe6ea0c69e1a23766a939d34b32fc78b774b22e46a646c25e6e1062d234ed48b1aba0f830529ff6afc296cc8dc207bbc15391623beac5f6c3db557ca49d0e42c962de95b5ff548cff970f5c73f439cfe82d3907be60240f56b6a4259cc96dfd8fe02a0bfa26e0223f68214428fff0ae40162198cc5cbd1"
]
let suite = [
"RSA" >::: [
rsa_selftest ~bits:89 100 ;
rsa_selftest ~bits:131 100 ;
rsa_selftest ~bits:1024 10 ;
rsa_selftest ~bits:2048 10 ;
] ;
"RSA-PKCS1-ENC" >::: [
rsa_pkcs1_encrypt_selftest ~bits:111 1000 ;
rsa_pkcs1_encrypt_selftest ~bits:512 10 ;
] ;
"RSA-PKCS1-SIGN" >::: [
rsa_pkcs1_encode_selftest ~bits:111 100 ;
rsa_pkcs1_encode_selftest ~bits:512 10 ;
rsa_pkcs1_sign_selftest 10;
rsa_pkcs1_cases;
] ;
"RSA-OAEP(SHA1)-ENC" >::: [
rsa_oaep_encrypt_selftest ~bits:1023 15 ;
rsa_oaep_encrypt_selftest ~bits:1024 15 ;
rsa_oaep_encrypt_selftest ~bits:1025 15 ;
] ;
"RSA-PSS(SHA1)-END" >::: [
rsa_pss_sign_selftest ~bits:511 15 ;
rsa_pss_sign_selftest ~bits:512 15 ;
rsa_pss_sign_selftest ~bits:513 15 ;
rsa_pss_cases
] ;
"RSA-regression" >::: [
test_case rsa_priv_of_primes_regression ;
test_case rsa_priv_of_primes_regression_62 ;
test_case rsa_priv_of_primes_regression_openssl ;
] ;
]

View file

@ -0,0 +1,17 @@
open OUnit2
let () =
Format.printf "accel: %a\n%!"
(fun ppf -> List.iter @@ fun x ->
Format.fprintf ppf "%s " @@
match x with `XOR -> "XOR" | `AES -> "AES" | `GHASH -> "GHASH")
Mirage_crypto.accelerated
let suite =
"All" >::: [
"Basic" >::: Test_base.suite;
"Cipher" >::: Test_cipher.suite;
]
let () =
run_test_tt_main suite

View file

@ -0,0 +1,6 @@
(library
(name wycheproof)
(libraries yojson ppx_deriving_yojson.runtime)
(preprocess
(pps ppx_deriving.std ppx_deriving_yojson))
(optional))

View file

@ -0,0 +1,149 @@
type json = Yojson.Safe.t [@@deriving of_yojson]
let pp_json = Yojson.Safe.pretty_print
type hex = string [@@deriving eq]
let pp_hex fmt buf =
let n = String.length buf in
let bbuf = Bytes.unsafe_of_string buf in
for i = n - 1 downto 0 do
let byte = Bytes.get_uint8 bbuf i in
Format.fprintf fmt "%02x" byte
done
let hex_of_string s =
let fold f acc str =
let st = ref acc in
String.iter (fun c -> st := f !st c) str;
!st
and digit c =
match c with
| '0'..'9' -> int_of_char c - 0x30
| 'A'..'F' -> int_of_char c - 0x41 + 10
| 'a'..'f' -> int_of_char c - 0x61 + 10
| _ -> invalid_arg "bad character"
in
let out = Bytes.create (String.length s / 2) in
let _idx, leftover =
fold (fun (idx, leftover) c ->
let c = digit c in
match leftover with
| None -> idx, Some (c lsl 4)
| Some c' ->
Bytes.set_uint8 out idx (c' lor c);
succ idx, None)
(0, None) s
in
assert (leftover = None);
Bytes.unsafe_to_string out
let hex_of_yojson json =
let padded s = if String.length s mod 2 = 0 then s else "0" ^ s in
match [%of_yojson: string] json with
| Ok s -> Ok (hex_of_string (padded s))
| Error _ as e -> e
type test_result = Valid | Acceptable | Invalid [@@deriving show]
let test_result_of_yojson = function
| `String "valid" -> Ok Valid
| `String "acceptable" -> Ok Acceptable
| `String "invalid" -> Ok Invalid
| _ -> Error "test_result"
type ecdh_test = {
tcId : int;
comment : string;
curve : json option; [@yojson.default None]
public : hex;
private_ : hex; [@yojson.key "private"]
shared : hex;
result : test_result;
flags : string list;
}
[@@deriving of_yojson, show]
let has_ignored_flag test ~ignored_flags =
List.exists
(fun ignored_flag -> List.mem ignored_flag test.flags)
ignored_flags
type ecdh_test_group = {
curve : string;
tests : ecdh_test list;
encoding : json option; [@yojson.default None]
type_ : json option; [@yojson.default None] [@yojson.key "type"]
}
[@@deriving of_yojson, show]
type ecdsa_key = {
curve : string;
keySize : int;
type_ : json; [@yojson.key "type"]
uncompressed : hex;
wx : hex;
wy : hex;
}
[@@deriving of_yojson, show]
type dsa_test = {
tcId : int;
comment : string;
msg : hex;
sig_ : hex; [@yojson.key "sig"]
result : test_result;
flags : string list;
}
[@@deriving of_yojson, show]
type ecdsa_test_group = {
key : ecdsa_key;
keyDer : string;
keyPem : string;
sha : string;
tests : dsa_test list;
type_ : json option; [@yojson.default None] [@yojson.key "type"]
}
[@@deriving of_yojson, show]
type eddsa_key = {
curve : string;
keySize : int;
pk : hex;
sk : hex;
type_ : json; [@yojson.key "type"]
}
[@@deriving of_yojson, show]
type eddsa_test_group = {
jwk : json;
key : eddsa_key;
keyDer : string;
keyPem : string;
type_ : json; [@yojson.key "type"]
tests : dsa_test list;
}
[@@deriving of_yojson, show]
type test_file = {
algorithm : json;
generatorVersion : json;
header : json;
notes : json;
numberOfTests : json;
schema : json;
testGroups : json list;
}
[@@deriving of_yojson, show]
let get_json = function Ok x -> x | Error s -> failwith s
let load_file_exn path =
Yojson.Safe.from_file path |> [%of_yojson: test_file] |> get_json
let ecdh_test_group_exn json = [%of_yojson: ecdh_test_group] json |> get_json
let ecdsa_test_group_exn json = [%of_yojson: ecdsa_test_group] json |> get_json
let eddsa_test_group_exn json = [%of_yojson: eddsa_test_group] json |> get_json

View file

@ -0,0 +1,97 @@
type json
type hex = string [@@deriving eq]
val pp_hex : Format.formatter -> hex -> unit
type test_result = Valid | Acceptable | Invalid [@@deriving show]
type ecdh_test = {
tcId : int;
comment : string;
curve : json option;
public : hex;
private_ : hex;
shared : hex;
result : test_result;
flags : string list;
}
[@@deriving show]
val has_ignored_flag : ecdh_test -> ignored_flags:string list -> bool
type ecdh_test_group = {
curve : string;
tests : ecdh_test list;
encoding : json option;
type_ : json option;
}
[@@deriving show]
type ecdsa_key = {
curve : string;
keySize : int;
type_ : json;
uncompressed : hex;
wx : hex;
wy : hex;
}
[@@deriving show]
type dsa_test = {
tcId : int;
comment : string;
msg : hex;
sig_ : hex;
result : test_result;
flags : string list;
}
[@@deriving show]
type ecdsa_test_group = {
key : ecdsa_key;
keyDer : string;
keyPem : string;
sha : string;
tests : dsa_test list;
type_ : json option;
}
[@@deriving show]
type eddsa_key = {
curve : string;
keySize : int;
pk : hex;
sk : hex;
type_ : json; [@yojson.key "type"]
}
[@@deriving of_yojson, show]
type eddsa_test_group = {
jwk : json;
key : eddsa_key;
keyDer : string;
keyPem : string;
type_ : json; [@yojson.key "type"]
tests : dsa_test list;
}
[@@deriving of_yojson, show]
type test_file = {
algorithm : json;
generatorVersion : json;
header : json;
notes : json;
numberOfTests : json;
schema : json;
testGroups : json list;
}
[@@deriving show]
val load_file_exn : string -> test_file
val ecdh_test_group_exn : json -> ecdh_test_group
val ecdsa_test_group_exn : json -> ecdsa_test_group
val eddsa_test_group_exn : json -> eddsa_test_group

File diff suppressed because it is too large Load diff