upstream: https://github.com/mirage/mirage-crypto

Add untracked directories

+155
+15
fuzz/dune
··· 1 + ; Crowbar fuzz testing for crypto 2 + ; 3 + ; To run: dune exec ocaml-crypto/fuzz/fuzz_crypto.exe 4 + ; With AFL: afl-fuzz -i fuzz/corpus -o fuzz/findings -- ./_build/default/ocaml-crypto/fuzz/fuzz_crypto.exe @@ 5 + 6 + (executable 7 + (name fuzz_crypto) 8 + (modules fuzz_crypto) 9 + (libraries crypto crowbar)) 10 + 11 + (rule 12 + (alias fuzz) 13 + (deps fuzz_crypto.exe) 14 + (action 15 + (run %{exe:fuzz_crypto.exe})))
+140
fuzz/fuzz_crypto.ml
··· 1 + (*--------------------------------------------------------------------------- 2 + Copyright (c) 2025 Thomas Gazagnaire. All rights reserved. 3 + SPDX-License-Identifier: MIT 4 + ---------------------------------------------------------------------------*) 5 + 6 + (* Crowbar-based fuzz testing for cryptographic primitives *) 7 + 8 + open Crowbar 9 + 10 + (* AES key sizes: 16, 24, or 32 bytes *) 11 + let valid_aes_key_sizes = [ 16; 24; 32 ] 12 + 13 + (* AES block size: 16 bytes *) 14 + let aes_block_size = 16 15 + 16 + (* Generate a padded key of valid size *) 17 + let make_key size input = 18 + if String.length input >= size then String.sub input 0 size 19 + else input ^ String.make (size - String.length input) '\x00' 20 + 21 + (* Test AES ECB roundtrip for valid key sizes *) 22 + let test_aes_ecb_roundtrip key_input plaintext = 23 + List.iter 24 + (fun key_size -> 25 + let key_str = make_key key_size key_input in 26 + let key = Crypto.AES.ECB.of_secret key_str in 27 + (* Pad plaintext to block size *) 28 + let pt_len = String.length plaintext in 29 + let padded_len = 30 + if pt_len = 0 then aes_block_size 31 + else ((pt_len + aes_block_size - 1) / aes_block_size) * aes_block_size 32 + in 33 + let padded_pt = 34 + if pt_len >= padded_len then String.sub plaintext 0 padded_len 35 + else plaintext ^ String.make (padded_len - pt_len) '\x00' 36 + in 37 + let ciphertext = Crypto.AES.ECB.encrypt ~key padded_pt in 38 + let decrypted = Crypto.AES.ECB.decrypt ~key ciphertext in 39 + check_eq ~pp:Format.pp_print_string padded_pt decrypted) 40 + valid_aes_key_sizes 41 + 42 + (* Test AES CBC roundtrip *) 43 + let test_aes_cbc_roundtrip key_input iv_input plaintext = 44 + List.iter 45 + (fun key_size -> 46 + let key_str = make_key key_size key_input in 47 + let key = Crypto.AES.CBC.of_secret key_str in 48 + let iv = make_key aes_block_size iv_input in 49 + (* Pad plaintext to block size *) 50 + let pt_len = String.length plaintext in 51 + let padded_len = 52 + if pt_len = 0 then aes_block_size 53 + else ((pt_len + aes_block_size - 1) / aes_block_size) * aes_block_size 54 + in 55 + let padded_pt = 56 + if pt_len >= padded_len then String.sub plaintext 0 padded_len 57 + else plaintext ^ String.make (padded_len - pt_len) '\x00' 58 + in 59 + let ciphertext = Crypto.AES.CBC.encrypt ~key ~iv padded_pt in 60 + let decrypted = Crypto.AES.CBC.decrypt ~key ~iv ciphertext in 61 + check_eq ~pp:Format.pp_print_string padded_pt decrypted) 62 + valid_aes_key_sizes 63 + 64 + (* Test AES CTR roundtrip *) 65 + let test_aes_ctr_roundtrip key_input ctr_input plaintext = 66 + if String.length plaintext = 0 then () 67 + else 68 + List.iter 69 + (fun key_size -> 70 + let key_str = make_key key_size key_input in 71 + let key = Crypto.AES.CTR.of_secret key_str in 72 + let ctr_str = make_key aes_block_size ctr_input in 73 + let ctr = Crypto.AES.CTR.ctr_of_octets ctr_str in 74 + let ciphertext = Crypto.AES.CTR.encrypt ~key ~ctr plaintext in 75 + let decrypted = Crypto.AES.CTR.decrypt ~key ~ctr ciphertext in 76 + check_eq ~pp:Format.pp_print_string plaintext decrypted) 77 + valid_aes_key_sizes 78 + 79 + (* Test AES GCM roundtrip *) 80 + let test_aes_gcm_roundtrip key_input nonce_input plaintext = 81 + List.iter 82 + (fun key_size -> 83 + let key_str = make_key key_size key_input in 84 + let key = Crypto.AES.GCM.of_secret key_str in 85 + (* GCM nonce should be 12 bytes for optimal performance *) 86 + let nonce = make_key 12 nonce_input in 87 + let adata = "" in 88 + let result = Crypto.AES.GCM.authenticate_encrypt ~key ~nonce ~adata plaintext in 89 + match Crypto.AES.GCM.authenticate_decrypt ~key ~nonce ~adata result with 90 + | Some decrypted -> check_eq ~pp:Format.pp_print_string plaintext decrypted 91 + | None -> fail "GCM decryption failed") 92 + valid_aes_key_sizes 93 + 94 + (* Test AES CCM roundtrip *) 95 + let test_aes_ccm_roundtrip key_input nonce_input plaintext = 96 + if String.length plaintext = 0 then () 97 + else 98 + List.iter 99 + (fun key_size -> 100 + let key_str = make_key key_size key_input in 101 + let key = Crypto.AES.CCM16.of_secret key_str in 102 + (* CCM nonce should be 7-13 bytes; use 12 *) 103 + let nonce = make_key 12 nonce_input in 104 + let adata = "" in 105 + let result = 106 + Crypto.AES.CCM16.authenticate_encrypt ~key ~nonce ~adata plaintext 107 + in 108 + match Crypto.AES.CCM16.authenticate_decrypt ~key ~nonce ~adata result with 109 + | Some decrypted -> 110 + check_eq ~pp:Format.pp_print_string plaintext decrypted 111 + | None -> fail "CCM decryption failed") 112 + valid_aes_key_sizes 113 + 114 + (* Test ChaCha20-Poly1305 roundtrip *) 115 + let test_chacha20_poly1305_roundtrip key_input nonce_input plaintext = 116 + (* ChaCha20 key is 32 bytes, nonce is 12 bytes *) 117 + let key_str = make_key 32 key_input in 118 + let key = Crypto.Chacha20.of_secret key_str in 119 + let nonce = make_key 12 nonce_input in 120 + let adata = "" in 121 + let result = 122 + Crypto.Chacha20.authenticate_encrypt ~key ~nonce ~adata plaintext 123 + in 124 + match Crypto.Chacha20.authenticate_decrypt ~key ~nonce ~adata result with 125 + | Some decrypted -> check_eq ~pp:Format.pp_print_string plaintext decrypted 126 + | None -> fail "ChaCha20-Poly1305 decryption failed" 127 + 128 + let () = 129 + add_test ~name:"crypto: aes ecb roundtrip" [ bytes; bytes ] 130 + test_aes_ecb_roundtrip; 131 + add_test ~name:"crypto: aes cbc roundtrip" [ bytes; bytes; bytes ] 132 + test_aes_cbc_roundtrip; 133 + add_test ~name:"crypto: aes ctr roundtrip" [ bytes; bytes; bytes ] 134 + test_aes_ctr_roundtrip; 135 + add_test ~name:"crypto: aes gcm roundtrip" [ bytes; bytes; bytes ] 136 + test_aes_gcm_roundtrip; 137 + add_test ~name:"crypto: aes ccm roundtrip" [ bytes; bytes; bytes ] 138 + test_aes_ccm_roundtrip; 139 + add_test ~name:"crypto: chacha20-poly1305 roundtrip" [ bytes; bytes; bytes ] 140 + test_chacha20_poly1305_roundtrip