this repo has no description
at main 6.4 kB view raw
1open Swim.Crypto 2 3let valid_key = String.make 16 '\x00' 4 5let test_roundtrip_property random = 6 QCheck.Test.make ~count:500 ~name:"crypto roundtrip" Generators.arb_cstruct 7 (fun plaintext -> 8 match init_key valid_key with 9 | Error _ -> false 10 | Ok key -> ( 11 let ciphertext = encrypt ~key ~random plaintext in 12 match decrypt ~key ciphertext with 13 | Ok decrypted -> Cstruct.equal plaintext decrypted 14 | Error _ -> false)) 15 16let test_encrypt_increases_size random = 17 QCheck.Test.make ~count:100 ~name:"encrypt increases size by overhead" 18 Generators.arb_cstruct (fun plaintext -> 19 match init_key valid_key with 20 | Error _ -> false 21 | Ok key -> 22 let ciphertext = encrypt ~key ~random plaintext in 23 Cstruct.length ciphertext = Cstruct.length plaintext + overhead) 24 25let test_different_plaintexts_different_ciphertexts random = 26 QCheck.Test.make ~count:100 27 ~name:"different plaintexts produce different ciphertexts" 28 (QCheck.pair Generators.arb_cstruct Generators.arb_cstruct) (fun (p1, p2) -> 29 if Cstruct.equal p1 p2 then true 30 else 31 match init_key valid_key with 32 | Error _ -> false 33 | Ok key -> 34 let c1 = encrypt ~key ~random p1 in 35 let c2 = encrypt ~key ~random p2 in 36 not (Cstruct.equal c1 c2)) 37 38let test_init_key_valid_length () = 39 match init_key (String.make 16 'a') with 40 | Ok _ -> () 41 | Error _ -> Alcotest.fail "expected valid key" 42 43let test_init_key_15_bytes_rejected () = 44 match init_key (String.make 15 'a') with 45 | Error `Invalid_key_length -> () 46 | _ -> Alcotest.fail "expected Invalid_key_length" 47 48let test_init_key_17_bytes_rejected () = 49 match init_key (String.make 17 'a') with 50 | Error `Invalid_key_length -> () 51 | _ -> Alcotest.fail "expected Invalid_key_length" 52 53let test_init_key_empty_rejected () = 54 match init_key "" with 55 | Error `Invalid_key_length -> () 56 | _ -> Alcotest.fail "expected Invalid_key_length" 57 58let test_tampered_ciphertext_fails random () = 59 match init_key valid_key with 60 | Error _ -> Alcotest.fail "key init failed" 61 | Ok key -> ( 62 let plaintext = Cstruct.of_string "hello world" in 63 let ciphertext = encrypt ~key ~random plaintext in 64 let tampered = Cstruct.of_string (Cstruct.to_string ciphertext) in 65 let pos = Cstruct.length tampered - 1 in 66 Cstruct.set_uint8 tampered pos 67 ((Cstruct.get_uint8 tampered pos + 1) land 0xFF); 68 match decrypt ~key tampered with 69 | Error `Decryption_failed -> () 70 | _ -> Alcotest.fail "expected Decryption_failed") 71 72let test_truncated_ciphertext_fails random () = 73 match init_key valid_key with 74 | Error _ -> Alcotest.fail "key init failed" 75 | Ok key -> ( 76 let plaintext = Cstruct.of_string "hello world" in 77 let ciphertext = encrypt ~key ~random plaintext in 78 let truncated = Cstruct.sub ciphertext 0 (overhead - 1) in 79 match decrypt ~key truncated with 80 | Error `Too_short -> () 81 | _ -> Alcotest.fail "expected Too_short") 82 83let test_wrong_key_fails random () = 84 match (init_key valid_key, init_key (String.make 16 '\xFF')) with 85 | Ok key1, Ok key2 -> ( 86 let plaintext = Cstruct.of_string "secret message" in 87 let ciphertext = encrypt ~key:key1 ~random plaintext in 88 match decrypt ~key:key2 ciphertext with 89 | Error `Decryption_failed -> () 90 | _ -> Alcotest.fail "expected Decryption_failed") 91 | _ -> Alcotest.fail "key init failed" 92 93let test_empty_plaintext random () = 94 match init_key valid_key with 95 | Error _ -> Alcotest.fail "key init failed" 96 | Ok key -> ( 97 let plaintext = Cstruct.empty in 98 let ciphertext = encrypt ~key ~random plaintext in 99 Alcotest.(check int) 100 "ciphertext size" overhead 101 (Cstruct.length ciphertext); 102 match decrypt ~key ciphertext with 103 | Ok decrypted -> 104 Alcotest.(check int) "decrypted size" 0 (Cstruct.length decrypted) 105 | Error _ -> Alcotest.fail "decrypt failed") 106 107let test_nonce_uniqueness random () = 108 match init_key valid_key with 109 | Error _ -> Alcotest.fail "key init failed" 110 | Ok key -> 111 let plaintext = Cstruct.of_string "test" in 112 let c1 = encrypt ~key ~random plaintext in 113 let c2 = encrypt ~key ~random plaintext in 114 let nonce1 = Cstruct.sub c1 1 nonce_size in 115 let nonce2 = Cstruct.sub c2 1 nonce_size in 116 if Cstruct.equal nonce1 nonce2 then 117 Alcotest.fail "nonces should be different" 118 else () 119 120let test_ciphertext_differs_from_plaintext random () = 121 match init_key valid_key with 122 | Error _ -> Alcotest.fail "key init failed" 123 | Ok key -> 124 let plaintext = Cstruct.of_string "hello world secret" in 125 let ciphertext = encrypt ~key ~random plaintext in 126 let ciphertext_body = 127 Cstruct.sub ciphertext (1 + nonce_size) 128 (Cstruct.length ciphertext - 1 - nonce_size) 129 in 130 if 131 Cstruct.equal plaintext 132 (Cstruct.sub ciphertext_body 0 133 (min (Cstruct.length plaintext) (Cstruct.length ciphertext_body))) 134 then Alcotest.fail "ciphertext should differ from plaintext" 135 else () 136 137let () = 138 Eio_main.run @@ fun env -> 139 let random = Eio.Stdenv.secure_random env in 140 let qcheck_tests = 141 List.map QCheck_alcotest.to_alcotest 142 [ 143 test_roundtrip_property random; 144 test_encrypt_increases_size random; 145 test_different_plaintexts_different_ciphertexts random; 146 ] 147 in 148 let unit_tests = 149 [ 150 ("init_key_valid_length", `Quick, test_init_key_valid_length); 151 ("init_key_15_bytes_rejected", `Quick, test_init_key_15_bytes_rejected); 152 ("init_key_17_bytes_rejected", `Quick, test_init_key_17_bytes_rejected); 153 ("init_key_empty_rejected", `Quick, test_init_key_empty_rejected); 154 ( "tampered_ciphertext_fails", 155 `Quick, 156 test_tampered_ciphertext_fails random ); 157 ( "truncated_ciphertext_fails", 158 `Quick, 159 test_truncated_ciphertext_fails random ); 160 ("wrong_key_fails", `Quick, test_wrong_key_fails random); 161 ("empty_plaintext", `Quick, test_empty_plaintext random); 162 ("nonce_uniqueness", `Quick, test_nonce_uniqueness random); 163 ( "ciphertext_differs_from_plaintext", 164 `Quick, 165 test_ciphertext_differs_from_plaintext random ); 166 ] 167 in 168 Alcotest.run "crypto" [ ("property", qcheck_tests); ("unit", unit_tests) ]