Skip to content

Commit

Permalink
cpu_rng_bootstrap: use rdrand if rdseed fails.
Browse files Browse the repository at this point in the history
if rdseed fails, take 512 times rdrand.

if rdrand fails 512 times (* 10 from the RETRIES in C), fail
  • Loading branch information
hannesm committed Jan 8, 2025
1 parent 276ffe2 commit a55afa4
Show file tree
Hide file tree
Showing 3 changed files with 42 additions and 10 deletions.
2 changes: 1 addition & 1 deletion rng/dune
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
(library
(name mirage_crypto_rng)
(public_name mirage-crypto-rng)
(libraries mirage-crypto digestif)
(libraries mirage-crypto digestif logs)
(private_modules entropy fortuna hmac_drbg rng))
40 changes: 35 additions & 5 deletions rng/entropy.ml
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,9 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*)

let src = Logs.Src.create "mirage-crypto-rng-entropy" ~doc:"Mirage crypto RNG Entropy"
module Log = (val Logs.src_log src : Logs.LOG)

let rdrand_calls = Atomic.make 0
let rdrand_failures = Atomic.make 0
let rdseed_calls = Atomic.make 0
Expand Down Expand Up @@ -128,23 +131,50 @@ let whirlwind_bootstrap id =
Bytes.unsafe_to_string buf

let cpu_rng_bootstrap =
let rdrand_bootstrap id =
let rec go acc = function
| 0 -> acc
| n ->
let buf = Bytes.create 10 in
let r = cpu_rng `Rdrand buf 2 in
write_header id buf;
if not r then
go acc (pred n)
else
go (Bytes.unsafe_to_string buf :: acc) (pred n)
in
let result = go [] 512 |> String.concat "" in
if String.length result = 0 then
failwith "Too many RDRAND failures"
else
result
in
match random `Rdseed with
| None -> Error `Not_supported
| Some insn ->
| Some `Rdseed ->
let cpu_rng_bootstrap id =
let buf = Bytes.create 10 in
let r = cpu_rng insn buf 2 in
if not r then failwith "Mirage_crypto_rng.Entropy: CPU RNG broken";
let r = cpu_rng `Rdseed buf 2 in
write_header id buf;
Bytes.unsafe_to_string buf
if not r then
if List.mem `Rdrand Cpu_native.cpu_rng then
rdrand_bootstrap id
else
failwith "RDSEED failed, and RDRAND not available"
else
Bytes.unsafe_to_string buf
in
Ok cpu_rng_bootstrap
| Some `Rdrand -> Ok rdrand_bootstrap

let bootstrap id =
match cpu_rng_bootstrap with
| Error `Not_supported -> whirlwind_bootstrap id
| Ok cpu_rng_bootstrap ->
try cpu_rng_bootstrap id with Failure _ -> whirlwind_bootstrap id
try cpu_rng_bootstrap id with
| Failure f ->
Log.err (fun m -> m "CPU RNG bootstrap failed: %s, using whirlwind" f);
whirlwind_bootstrap id

let interrupt_hook () =
let buf = Bytes.create 4 in
Expand Down
10 changes: 6 additions & 4 deletions rng/mirage_crypto_rng.mli
Original file line number Diff line number Diff line change
Expand Up @@ -114,11 +114,13 @@ module Entropy : sig

val cpu_rng_bootstrap : (int -> string, [`Not_supported]) Result.t
(** [cpu_rng_bootstrap id] returns 8 bytes of random data using the CPU
RNG (rdseed or rdrand). On 32bit platforms, only 4 bytes are filled.
The [id] is used as prefix.
RNG (rdseed). On 32bit platforms, only 4 bytes are filled.
The [id] is used as prefix. If only rdrand is available, the return
value is the concatenation of 512 calls to rdrand.
@raise Failure if no CPU RNG is available, or if it doesn't return a
random value. *)
@raise Failure if rdrand fails 512 times, or if rdseed fails and rdrand
is not available.
*)

val bootstrap : int -> string
(** [bootstrap id] is either [cpu_rng_bootstrap], if the CPU supports it, or
Expand Down

0 comments on commit a55afa4

Please sign in to comment.