diff --git a/rng/async/mirage_crypto_rng_async.ml b/rng/async/mirage_crypto_rng_async.ml index 74335f60..ef4d282d 100644 --- a/rng/async/mirage_crypto_rng_async.ml +++ b/rng/async/mirage_crypto_rng_async.ml @@ -34,7 +34,7 @@ let periodically_collect_getrandom_entropy time_source span = let idx = ref 0 in let f () = incr idx; - String.sub random ~pos:(per_pool * (pred !idx)) ~len:per_pool + Ok (String.sub random ~pos:(per_pool * (pred !idx)) ~len:per_pool) in Entropy.feed_pools None source f) diff --git a/rng/eio/mirage_crypto_rng_eio.ml b/rng/eio/mirage_crypto_rng_eio.ml index e6095713..811f5b15 100644 --- a/rng/eio/mirage_crypto_rng_eio.ml +++ b/rng/eio/mirage_crypto_rng_eio.ml @@ -32,7 +32,7 @@ let periodically_feed_entropy env delta source = let idx = ref 0 in let f () = incr idx; - String.sub random (per_pool * (pred !idx)) per_pool + Ok (String.sub random (per_pool * (pred !idx)) per_pool) in Entropy.feed_pools None source f in diff --git a/rng/entropy.ml b/rng/entropy.ml index 8fe710be..036a2c9a 100644 --- a/rng/entropy.ml +++ b/rng/entropy.ml @@ -30,8 +30,8 @@ module Cpu_native = struct external cycles : unit -> int = "mc_cycle_counter" [@@noalloc] - external rdseed : unit -> int = "mc_cpu_rdseed" [@@noalloc] - external rdrand : unit -> int = "mc_cpu_rdrand" [@@noalloc] + external rdseed : bytes -> int -> bool = "mc_cpu_rdseed" [@@noalloc] + external rdrand : bytes -> int -> bool = "mc_cpu_rdrand" [@@noalloc] external rng_type : unit -> int = "mc_cpu_rng_type" [@@noalloc] let cpu_rng = @@ -119,10 +119,9 @@ let cpu_rng_bootstrap = | None -> Error `Not_supported | Some insn -> let cpu_rng_bootstrap id = - let r = cpu_rng insn () in - if r = 0 then failwith "Mirage_crypto_rng.Entropy: 0 is a bad CPU RNG value"; let buf = Bytes.create 10 in - Bytes.set_int64_le buf 2 (Int64.of_int r); + let r = cpu_rng insn buf 2 in + if not r then failwith "Mirage_crypto_rng.Entropy: CPU RNG broken"; write_header id buf; Bytes.unsafe_to_string buf in @@ -150,7 +149,11 @@ let feed_pools g source f = let g = match g with None -> Some (Rng.default_generator ()) | Some g -> Some g in let `Acc handle = Rng.accumulate g source in for _i = 0 to pred (Rng.pools g) do - handle (f ()) + match f () with + | Ok data -> handle data + | Error `No_random_available -> + (* should we log a message? *) + () done let cpu_rng = @@ -165,8 +168,10 @@ let cpu_rng = in let f () = let buf = Bytes.create 8 in - Bytes.set_int64_le buf 0 (Int64.of_int (randomf ())); - Bytes.unsafe_to_string buf + if randomf buf 0 then + Ok (Bytes.unsafe_to_string buf) + else + Error `No_random_available in fun () -> feed_pools g source f in diff --git a/rng/lwt/mirage_crypto_rng_lwt.ml b/rng/lwt/mirage_crypto_rng_lwt.ml index 9730e90b..001e8460 100644 --- a/rng/lwt/mirage_crypto_rng_lwt.ml +++ b/rng/lwt/mirage_crypto_rng_lwt.ml @@ -19,7 +19,7 @@ let getrandom_task delta source = let idx = ref 0 in let f () = incr idx; - String.sub random (per_pool * (pred !idx)) per_pool + Ok (String.sub random (per_pool * (pred !idx)) per_pool) in Entropy.feed_pools None source f in diff --git a/rng/miou/mirage_crypto_rng_miou_unix.ml b/rng/miou/mirage_crypto_rng_miou_unix.ml index 82ecdbf7..b17bc593 100644 --- a/rng/miou/mirage_crypto_rng_miou_unix.ml +++ b/rng/miou/mirage_crypto_rng_miou_unix.ml @@ -18,7 +18,10 @@ let getrandom delta source = let size = per_pool * pools None in let random = Mirage_crypto_rng_unix.getrandom size in let idx = ref 0 in - let fn () = incr idx; String.sub random (per_pool * (pred !idx)) per_pool in + let fn () = + incr idx; + Ok (String.sub random (per_pool * (pred !idx)) per_pool) + in Entropy.feed_pools None source fn in periodic fn delta diff --git a/rng/mirage_crypto_rng.mli b/rng/mirage_crypto_rng.mli index a483331d..ee60980a 100644 --- a/rng/mirage_crypto_rng.mli +++ b/rng/mirage_crypto_rng.mli @@ -136,14 +136,14 @@ module Entropy : sig (** {1 Periodic pulled sources} *) - val feed_pools : g option -> source -> (unit -> string) -> unit + val feed_pools : g option -> source -> (unit -> (string, [ `No_random_available ]) result) -> unit (** [feed_pools g source f] feeds all pools of [g] using [source] by executing [f] for each pool. *) val cpu_rng : (g option -> unit -> unit, [`Not_supported]) Result.t (** [cpu_rng g] uses the CPU RNG (rdrand or rdseed) to feed all pools of [g]. It uses {!feed_pools} internally. If neither rdrand nor rdseed - are available, [fun () -> ()] is returned. *) + are available, [`Not_supported] is returned. *) (**/**) val id : source -> int diff --git a/src/native/entropy_cpu_stubs.c b/src/native/entropy_cpu_stubs.c index cef0c1cf..37fe794d 100644 --- a/src/native/entropy_cpu_stubs.c +++ b/src/native/entropy_cpu_stubs.c @@ -15,11 +15,27 @@ #define random_t unsigned long long #define _rdseed_step _rdseed64_step #define _rdrand_step _rdrand64_step +#define fill_bytes(buf, off, data) { \ + (_bp_uint8_off(buf, off))[0] = (uint8_t)((data) >> 56); \ + (_bp_uint8_off(buf, off))[1] = (uint8_t)((data) >> 48); \ + (_bp_uint8_off(buf, off))[2] = (uint8_t)((data) >> 40); \ + (_bp_uint8_off(buf, off))[3] = (uint8_t)((data) >> 32); \ + (_bp_uint8_off(buf, off))[4] = (uint8_t)((data) >> 24); \ + (_bp_uint8_off(buf, off))[5] = (uint8_t)((data) >> 16); \ + (_bp_uint8_off(buf, off))[6] = (uint8_t)((data) >> 8); \ + (_bp_uint8_off(buf, off))[7] = (uint8_t)((data)); \ + } #elif defined (__i386__) #define random_t unsigned int #define _rdseed_step _rdseed32_step #define _rdrand_step _rdrand32_step +#define fill_bytes(buf, off, data) { \ + (_bp_uint8_off(buf, off))[0] = (uint8_t)((data) >> 24); \ + (_bp_uint8_off(buf, off))[1] = (uint8_t)((data) >> 16); \ + (_bp_uint8_off(buf, off))[2] = (uint8_t)((data) >> 8); \ + (_bp_uint8_off(buf, off))[3] = (uint8_t)((data)); \ + } #endif #endif /* __i386__ || __x86_64__ */ @@ -229,29 +245,31 @@ static void detect (void) { #endif } -CAMLprim value mc_cpu_rdseed (value __unused(unit)) { +CAMLprim value mc_cpu_rdseed (value buf, value off) { #ifdef __mc_ENTROPY__ random_t r = 0; int ok = 0; int i = RETRIES; do { ok = _rdseed_step (&r); _mm_pause (); } while ( !(ok | !--i) ); - return Val_long(r); + fill_bytes(buf, off, r); + return Val_bool (ok); #else /* ARM: CPU-assisted randomness here. */ - return Val_long (0); + return Val_bool (0); #endif } -CAMLprim value mc_cpu_rdrand (value __unused(unit)) { +CAMLprim value mc_cpu_rdrand (value buf, value off) { #ifdef __mc_ENTROPY__ random_t r = 0; int ok = 0; int i = RETRIES; do { ok = _rdrand_step (&r); } while ( !(ok | !--i) ); - return Val_long(r); + fill_bytes(buf, off, r); + return Val_bool (ok); #else /* ARM: CPU-assisted randomness here. */ - return Val_long (0); + return Val_bool (0); #endif }