From e194153dd81b8d36d1b867dd35d1c4a143ca53ef Mon Sep 17 00:00:00 2001 From: Hannes Mehnert Date: Wed, 10 Apr 2024 11:33:06 +0200 Subject: [PATCH] mirage-crypto: skip Cipher_block / Cipher_stream module indirection fixes #224 --- bench/speed.ml | 4 +- rng/fortuna.ml | 2 +- src/cipher_block.ml | 18 +-- src/cipher_stream.ml | 2 +- src/mirage_crypto.ml | 4 +- src/mirage_crypto.mli | 266 +++++++++++++++------------------ tests/test_cipher.ml | 25 +--- tests/test_random_runner.ml | 24 +-- tests/test_symmetric_runner.ml | 2 +- 9 files changed, 153 insertions(+), 194 deletions(-) diff --git a/bench/speed.ml b/bench/speed.ml index 56801fa1..90d44425 100644 --- a/bench/speed.ml +++ b/bench/speed.ml @@ -1,7 +1,5 @@ open Mirage_crypto -open Cipher_block - module Time = struct let time ~n f a = @@ -418,7 +416,7 @@ let runv fs = (fun ppf -> List.iter @@ fun x -> Format.fprintf ppf "%s " @@ match x with `XOR -> "XOR" | `AES -> "AES" | `GHASH -> "GHASH") - Cipher_block.accelerated; + accelerated; Time.warmup () ; List.iter (fun f -> f ()) fs diff --git a/rng/fortuna.ml b/rng/fortuna.ml index 853a9b07..cf1b54f2 100644 --- a/rng/fortuna.ml +++ b/rng/fortuna.ml @@ -1,7 +1,7 @@ open Mirage_crypto open Mirage_crypto.Uncommon -module AES_CTR = Cipher_block.AES.CTR +module AES_CTR = AES.CTR module SHAd256 = struct open Digestif diff --git a/src/cipher_block.ml b/src/cipher_block.ml index 299c7094..ceabaf32 100644 --- a/src/cipher_block.ml +++ b/src/cipher_block.ml @@ -1,6 +1,6 @@ open Uncommon -module S = struct +module Block = struct module type Core = sig @@ -127,7 +127,7 @@ module Counters = struct end module Modes = struct - module ECB_of (Core : S.Core) : S.ECB = struct + module ECB_of (Core : Block.Core) : Block.ECB = struct type key = Core.ekey * Core.dkey @@ -148,7 +148,7 @@ module Modes = struct end - module CBC_of (Core : S.Core) : S.CBC = struct + module CBC_of (Core : Block.Core) : Block.CBC = struct type key = Core.ekey * Core.dkey @@ -193,8 +193,8 @@ module Modes = struct end - module CTR_of (Core : S.Core) (Ctr : Counters.S) : - S.CTR with type key = Core.ekey and type ctr = Ctr.ctr = + module CTR_of (Core : Block.Core) (Ctr : Counters.S) : + Block.CTR with type key = Core.ekey and type ctr = Ctr.ctr = struct (* FIXME: CTR has more room for speedups. Like stitching. *) @@ -252,7 +252,7 @@ module Modes = struct Bytes.unsafe_to_string res end - module GCM_of (C : S.Core) : S.GCM = struct + module GCM_of (C : Block.Core) : Block.GCM = struct let _ = assert (C.block = 16) module CTR = CTR_of (C) (Counters.C128be32) @@ -324,7 +324,7 @@ module Modes = struct authenticate_decrypt_tag ~key ~nonce ?adata ~tag cipher end - module CCM16_of (C : S.Core) : S.CCM16 = struct + module CCM16_of (C : Block.Core) : Block.CCM16 = struct let _ = assert (C.block = 16) @@ -365,7 +365,7 @@ end module AES = struct - module Core : S.Core = struct + module Core : Block.Core = struct let key = [| 16; 24; 32 |] let block = 16 @@ -413,7 +413,7 @@ end module DES = struct - module Core : S.Core = struct + module Core : Block.Core = struct let key = [| 24 |] let block = 8 diff --git a/src/cipher_stream.ml b/src/cipher_stream.ml index 87aaec0c..f3ee27da 100644 --- a/src/cipher_stream.ml +++ b/src/cipher_stream.ml @@ -1,6 +1,6 @@ open Uncommon -module type S = sig +module type Stream = sig type key type result = { message : string ; key : key } val of_secret : string -> key diff --git a/src/mirage_crypto.ml b/src/mirage_crypto.ml index 17118a9a..c32010b0 100644 --- a/src/mirage_crypto.ml +++ b/src/mirage_crypto.ml @@ -1,6 +1,6 @@ module Uncommon = Uncommon module Poly1305 = Poly1305.It module type AEAD = Aead.AEAD -module Cipher_block = Cipher_block +include Cipher_block module Chacha20 = Chacha20 -module Cipher_stream = Cipher_stream +include Cipher_stream diff --git a/src/mirage_crypto.mli b/src/mirage_crypto.mli index f0c6f0b9..c34d4373 100644 --- a/src/mirage_crypto.mli +++ b/src/mirage_crypto.mli @@ -150,201 +150,177 @@ end Each algorithm, and each mode of operation, is contained in its own separate module. *) -module Cipher_block : sig - (** Module types for various block cipher modes of operation. *) - module S : sig +(** Module types for various block cipher modes of operation. *) +module Block : sig - (** Raw block cipher in all its glory. + (** Modes of operation: *) - Make absolutely sure to check the arguments. Behavior is unspecified on - invalid inputs. *) - (* module type Core = sig *) + (** {e Electronic Codebook} "mode". *) + module type ECB = sig - (* type ekey *) - (* type dkey *) - - (* val of_secret : string -> ekey * dkey *) - (* val e_of_secret : string -> ekey *) - (* val d_of_secret : string -> dkey *) - - (* val key : int array *) - (* val block : int *) - - (* val encrypt : key:ekey -> blocks:int -> Native.buffer -> int -> Native.buffer -> int -> unit *) - (* val decrypt : key:dkey -> blocks:int -> Native.buffer -> int -> Native.buffer -> int -> unit *) - (* end *) - - (** Modes of operation: *) - - (** {e Electronic Codebook} "mode". *) - module type ECB = sig - - type key - val of_secret : string -> key + type key + val of_secret : string -> key - val key_sizes : int array - val block_size : int - val encrypt : key:key -> string -> string - val decrypt : key:key -> string -> string - end + val key_sizes : int array + val block_size : int + val encrypt : key:key -> string -> string + val decrypt : key:key -> string -> string + end - (** {e Cipher-block chaining} mode. *) - module type CBC = sig + (** {e Cipher-block chaining} mode. *) + module type CBC = sig - type key + type key - val of_secret : string -> key - (** Construct the encryption key corresponding to [secret]. + val of_secret : string -> key + (** Construct the encryption key corresponding to [secret]. - @raise Invalid_argument if the length of [secret] is not in - {{!key_sizes}[key_sizes]}. *) + @raise Invalid_argument if the length of [secret] is not in + {{!key_sizes}[key_sizes]}. *) - val key_sizes : int array - (** Key sizes allowed with this cipher. *) + val key_sizes : int array + (** Key sizes allowed with this cipher. *) - val block_size : int - (** The size of a single block. *) + val block_size : int + (** The size of a single block. *) - val encrypt : key:key -> iv:string -> string -> string - (** [encrypt ~key ~iv msg] is [msg] encrypted under [key], using [iv] as - the CBC initialization vector. + val encrypt : key:key -> iv:string -> string -> string + (** [encrypt ~key ~iv msg] is [msg] encrypted under [key], using [iv] as the + CBC initialization vector. - @raise Invalid_argument if [iv] is not [block_size], or [msg] is not - [k * block_size] long. *) + @raise Invalid_argument if [iv] is not [block_size], or [msg] is not + [k * block_size] long. *) - val decrypt : key:key -> iv:string -> string -> string - (** [decrypt ~key ~iv msg] is the inverse of [encrypt]. + val decrypt : key:key -> iv:string -> string -> string + (** [decrypt ~key ~iv msg] is the inverse of [encrypt]. - @raise Invalid_argument if [iv] is not [block_size], or [msg] is not - [k * block_size] long. *) + @raise Invalid_argument if [iv] is not [block_size], or [msg] is not + [k * block_size] long. *) - val next_iv : iv:string -> string -> string - (** [next_iv ~iv ciphertext] is the first [iv] {e following} the - encryption that used [iv] to produce [ciphertext]. + val next_iv : iv:string -> string -> string + (** [next_iv ~iv ciphertext] is the first [iv] {e following} the + encryption that used [iv] to produce [ciphertext]. - For protocols which perform inter-message chaining, this is the [iv] - for the next message. + For protocols which perform inter-message chaining, this is the [iv] + for the next message. - It is either [iv], when [len ciphertext = 0], or the last block of - [ciphertext]. Note that + It is either [iv], when [len ciphertext = 0], or the last block of + [ciphertext]. Note that {[encrypt ~iv msg1 || encrypt ~iv:(next_iv ~iv (encrypt ~iv msg1)) msg2 == encrypt ~iv (msg1 || msg2)]} - @raise Invalid_argument if the length of [iv] is not [block_size], or - the length of [ciphertext] is not [k * block_size] for some [k]. *) - end + @raise Invalid_argument if the length of [iv] is not [block_size], or + the length of [ciphertext] is not [k * block_size] for some [k]. *) + end - (** {e Counter} mode. *) - module type CTR = sig + (** {e Counter} mode. *) + module type CTR = sig - type key + type key - val of_secret : string -> key - (** Construct the encryption key corresponding to [secret]. + val of_secret : string -> key + (** Construct the encryption key corresponding to [secret]. - @raise Invalid_argument if the length of [secret] is not in - {{!key_sizes}[key_sizes]}. *) + @raise Invalid_argument if the length of [secret] is not in + {{!key_sizes}[key_sizes]}. *) - val key_sizes : int array - (** Key sizes allowed with this cipher. *) + val key_sizes : int array + (** Key sizes allowed with this cipher. *) - val block_size : int - (** The size of a single block. *) + val block_size : int + (** The size of a single block. *) - type ctr + type ctr - val stream : key:key -> ctr:ctr -> int -> string - (** [stream ~key ~ctr n] is the raw keystream. + val stream : key:key -> ctr:ctr -> int -> string + (** [stream ~key ~ctr n] is the raw keystream. - Keystream is the concatenation of successive encrypted counter states. - If [E(x)] is the single block [x] encrypted under [key], then keystream - is the first [n] bytes of - [E(ctr) || E(add ctr 1) || E(add ctr 2) || ...]. + Keystream is the concatenation of successive encrypted counter states. + If [E(x)] is the single block [x] encrypted under [key], then keystream + is the first [n] bytes of + [E(ctr) || E(add ctr 1) || E(add ctr 2) || ...]. - Note that + Note that {[stream ~key ~ctr (k * block_size) || stream ~key ~ctr:(add ctr k) x == stream ~key ~ctr (k * block_size + x)]} - In other words, it is possible to restart a keystream at [block_size] - boundaries by manipulating the counter. *) + In other words, it is possible to restart a keystream at [block_size] + boundaries by manipulating the counter. *) - val encrypt : key:key -> ctr:ctr -> string -> string - (** [encrypt ~key ~ctr msg] is + val encrypt : key:key -> ctr:ctr -> string -> string + (** [encrypt ~key ~ctr msg] is [stream ~key ~ctr ~off (len msg) lxor msg]. *) - val decrypt : key:key -> ctr:ctr -> string -> string - (** [decrypt] is [encrypt]. *) + val decrypt : key:key -> ctr:ctr -> string -> string + (** [decrypt] is [encrypt]. *) - val add_ctr : ctr -> int64 -> ctr - (** [add_ctr ctr n] adds [n] to [ctr]. *) + val add_ctr : ctr -> int64 -> ctr + (** [add_ctr ctr n] adds [n] to [ctr]. *) - val next_ctr : ctr:ctr -> string -> ctr - (** [next_ctr ~ctr msg] is the state of the counter after encrypting or - decrypting [msg] with the counter [ctr]. + val next_ctr : ctr:ctr -> string -> ctr + (** [next_ctr ~ctr msg] is the state of the counter after encrypting or + decrypting [msg] with the counter [ctr]. - For protocols which perform inter-message chaining, this is the - counter for the next message. + For protocols which perform inter-message chaining, this is the + counter for the next message. - It is computed as [C.add ctr (ceil (len msg / block_size))]. Note that - if [len msg1 = k * block_size], + It is computed as [C.add ctr (ceil (len msg / block_size))]. Note that + if [len msg1 = k * block_size], {[encrypt ~ctr msg1 || encrypt ~ctr:(next_ctr ~ctr msg1) msg2 == encrypt ~ctr (msg1 || msg2)]} - *) + *) - val ctr_of_octets : string -> ctr - (** [ctr_of_octets buf] converts the value of [buf] into a counter. *) - end + val ctr_of_octets : string -> ctr + (** [ctr_of_octets buf] converts the value of [buf] into a counter. *) + end - (** {e Galois/Counter Mode}. *) - module type GCM = sig + (** {e Galois/Counter Mode}. *) + module type GCM = sig - include AEAD + include AEAD - val key_sizes : int array - (** Key sizes allowed with this cipher. *) + val key_sizes : int array + (** Key sizes allowed with this cipher. *) - val block_size : int - (** The size of a single block. *) - end + val block_size : int + (** The size of a single block. *) + end - (** {e Counter with CBC-MAC} mode. *) - module type CCM16 = sig + (** {e Counter with CBC-MAC} mode. *) + module type CCM16 = sig - include AEAD + include AEAD - val key_sizes : int array - (** Key sizes allowed with this cipher. *) + val key_sizes : int array + (** Key sizes allowed with this cipher. *) - val block_size : int - (** The size of a single block. *) - end + val block_size : int + (** The size of a single block. *) end +end - module AES : sig -(* module Core : S.Core *) - module ECB : S.ECB - module CBC : S.CBC - module CTR : S.CTR with type ctr = int64 * int64 - module GCM : S.GCM - module CCM16 : S.CCM16 +module AES : sig + module ECB : Block.ECB + module CBC : Block.CBC + module CTR : Block.CTR with type ctr = int64 * int64 + module GCM : Block.GCM + module CCM16 : Block.CCM16 end - module DES : sig -(* module Core : S.Core *) - module ECB : S.ECB - module CBC : S.CBC - module CTR : S.CTR with type ctr = int64 - end +module DES : sig + module ECB : Block.ECB + module CBC : Block.CBC + module CTR : Block.CTR with type ctr = int64 +end - val accelerated : [`XOR | `AES | `GHASH] list - (** Operations using non-portable, hardware-dependent implementation in +val accelerated : [`XOR | `AES | `GHASH] list +(** Operations using non-portable, hardware-dependent implementation in this build of the library. *) -end (** The ChaCha20 cipher proposed by D.J. Bernstein. *) module Chacha20 : sig @@ -366,18 +342,14 @@ module Chacha20 : sig *) end -(** Streaming ciphers. *) -module Cipher_stream : sig - - (** General stream cipher type. *) - module type S = sig - type key - type result = { message : string ; key : key } - val of_secret : string -> key - val encrypt : key:key -> string -> result - val decrypt : key:key -> string -> result - end - - (** {e Alleged Rivest Cipher 4}. *) - module ARC4 : S +(** General stream cipher type. *) +module type Stream = sig + type key + type result = { message : string ; key : key } + val of_secret : string -> key + val encrypt : key:key -> string -> result + val decrypt : key:key -> string -> result end + +(** {e Alleged Rivest Cipher 4}. *) +module ARC4 : Stream diff --git a/tests/test_cipher.ml b/tests/test_cipher.ml index 24e6bac2..49617dea 100644 --- a/tests/test_cipher.ml +++ b/tests/test_cipher.ml @@ -5,8 +5,6 @@ open Mirage_crypto open Test_common let des_ecb_cases = - let open Cipher_block in - let case ~data ~key ~out = vx data, DES.ECB.of_secret (vx key), vx out and check (data, key, out) _ = @@ -29,8 +27,6 @@ let des_ecb_cases = ] let des_cbc_cases = - let open Cipher_block in - let case ~data ~key ~iv ~out = vx data, DES.CBC.of_secret (vx key), vx iv, vx out and check (data, key, iv, out) _ = @@ -57,7 +53,7 @@ f0e6 a329 e190 44ff 54e7 5eec 8296 6a58" let des_ctr_cases = let case ~data ~key ~ctr ~out = test_case @@ fun _ -> - let open Cipher_block.DES.CTR in + let open DES.CTR in let key = vx key |> of_secret and ctr = vx ctr |> ctr_of_octets and out = vx out @@ -101,8 +97,6 @@ let nist_sp_800_38a = vx f6 9f 24 45 df 4f 9b 17 ad 2b 41 7b e6 6c 37 10" let aes_ecb_cases = - let open Cipher_block in - let case ~key ~out = (AES.ECB.of_secret (vx key), vx out) and check (key, out) _ = @@ -134,8 +128,6 @@ let aes_ecb_cases = ] let aes_cbc_cases = - let open Cipher_block in - let case ~key ~iv ~out = (AES.CBC.of_secret (vx key), vx iv, vx out) and check (key, iv, out) _ = @@ -171,7 +163,7 @@ let aes_cbc_cases = let aes_ctr_cases = let case ~key ~ctr ~out ~ctr1 = test_case @@ fun _ -> - let open Cipher_block.AES.CTR in + let open AES.CTR in let key = vx key |> of_secret and ctr = vx ctr |> ctr_of_octets and ctr1 = vx ctr1 |> ctr_of_octets @@ -221,8 +213,6 @@ let aes_ctr_cases = (* aes gcm *) let gcm_cases = - let open Cipher_block in - let case ~key ~p ~a ~nonce ~c ~t = (AES.GCM.of_secret (vx key), vx p, vx a, vx nonce, vx c, vx t) in @@ -412,7 +402,7 @@ let ccm_cases = *) let ccm_regressions = - let open Cipher_block.AES.CCM16 in + let open AES.CCM16 in let no_vs_empty_ad _ = (* as reported in https://github.com/mirleft/ocaml-nocrypto/issues/166 *) (* see RFC 3610 Section 2.1, AD of length 0 should be same as no AD *) @@ -491,7 +481,7 @@ let ccm_regressions = ] let gcm_regressions = - let open Cipher_block.AES.GCM in + let open AES.GCM in let msg = vx "000102030405060708090a0b0c0d0e0f" in let key = of_secret msg and nonce = "" @@ -770,7 +760,6 @@ let poly1305_rfc8439_2_5_2 _ = (Poly1305.mac ~key data) output let empty_cases _ = - let open Cipher_block in let plain = "" and cipher = "" in @@ -845,9 +834,9 @@ let empty_cases _ = [| 16 ; 32 |] ; (* ARC4 *) - let key = Cipher_stream.ARC4.of_secret (String.make 16 '\x00') in - assert_oct_equal ~msg:"ARC4 encrypt" cipher (Cipher_stream.ARC4.(encrypt ~key plain).message) ; - assert_oct_equal ~msg:"ARC4 decrypt" plain (Cipher_stream.ARC4.(decrypt ~key cipher).message) + let key = ARC4.of_secret (String.make 16 '\x00') in + assert_oct_equal ~msg:"ARC4 encrypt" cipher (ARC4.(encrypt ~key plain).message) ; + assert_oct_equal ~msg:"ARC4 decrypt" plain (ARC4.(decrypt ~key cipher).message) let suite = [ "3DES-ECB" >::: des_ecb_cases ; diff --git a/tests/test_random_runner.ml b/tests/test_random_runner.ml index 092100c2..8a74eec4 100644 --- a/tests/test_random_runner.ml +++ b/tests/test_random_runner.ml @@ -12,7 +12,7 @@ let sample arr = (* randomized selfies *) -let ecb_selftest (m : (module Cipher_block.S.ECB)) n = +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) @@ -22,7 +22,7 @@ let ecb_selftest (m : (module Cipher_block.S.ECB)) n = |> decrypt ~key |> decrypt ~key ) in assert_oct_equal ~msg:"ecb mismatch" data data' -let cbc_selftest (m : (module Cipher_block.S.CBC)) n = +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) @@ -40,7 +40,7 @@ let cbc_selftest (m : (module Cipher_block.S.CBC)) n = C.( let e1 = encrypt ~key ~iv d1 in e1 ^ encrypt ~key ~iv:(next_iv ~iv e1) d2) -let ctr_selftest (m : (module Cipher_block.S.CTR)) n = +let ctr_selftest (m : (module Block.CTR)) n = let module M = (val m) in let bs = M.block_size in "selftest" >:: times ~n @@ fun _ -> @@ -57,7 +57,7 @@ let ctr_selftest (m : (module Cipher_block.S.CTR)) n = 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 Cipher_block.S.CTR with type ctr = c)) n = +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 @@ -90,17 +90,17 @@ let xor_selftest n = let suite = "All" >::: [ "XOR" >::: [ xor_selftest 300 ] ; - "3DES-ECB" >::: [ ecb_selftest (module Cipher_block.DES.ECB) 100 ] ; + "3DES-ECB" >::: [ ecb_selftest (module DES.ECB) 100 ] ; - "3DES-CBC" >::: [ cbc_selftest (module Cipher_block.DES.CBC) 100 ] ; + "3DES-CBC" >::: [ cbc_selftest (module DES.CBC) 100 ] ; - "3DES-CTR" >::: Cipher_block.[ ctr_selftest (module DES.CTR) 100; - ctr_offsets (module DES.CTR) 100 ~zero:0L; ] ; + "3DES-CTR" >::: [ ctr_selftest (module DES.CTR) 100; + ctr_offsets (module DES.CTR) 100 ~zero:0L; ] ; - "AES-ECB" >::: [ ecb_selftest (module Cipher_block.AES.ECB) 100 ] ; - "AES-CBC" >::: [ cbc_selftest (module Cipher_block.AES.CBC) 100 ] ; - "AES-CTR" >::: Cipher_block.[ ctr_selftest (module AES.CTR) 100; - ctr_offsets (module AES.CTR) 100 ~zero:(0L, 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) ] ; ] diff --git a/tests/test_symmetric_runner.ml b/tests/test_symmetric_runner.ml index bf22fa76..95bce19b 100644 --- a/tests/test_symmetric_runner.ml +++ b/tests/test_symmetric_runner.ml @@ -5,7 +5,7 @@ let () = (fun ppf -> List.iter @@ fun x -> Format.fprintf ppf "%s " @@ match x with `XOR -> "XOR" | `AES -> "AES" | `GHASH -> "GHASH") - Mirage_crypto.Cipher_block.accelerated + Mirage_crypto.accelerated let suite = "All" >::: [