This commit is contained in:
parent
aa2ff7b2f0
commit
2f3113f55d
11742 changed files with 1223940 additions and 0 deletions
303
unikernel/duniverse/mirage-crypto/rng/mirage_crypto_rng.mli
Normal file
303
unikernel/duniverse/mirage-crypto/rng/mirage_crypto_rng.mli
Normal file
|
|
@ -0,0 +1,303 @@
|
|||
(** {1 Randomness} *)
|
||||
|
||||
(** Secure random number generation.
|
||||
|
||||
There are several parts of this module:
|
||||
|
||||
{ul
|
||||
{- The {{!Generator}signature} of generator modules, together with a
|
||||
facility to convert such modules into actual {{!g}generators}, and
|
||||
functions that operate on this representation.}
|
||||
{- A global generator instance, which needs to be initialized by calling
|
||||
{!set_default_generator}.}}
|
||||
*)
|
||||
|
||||
(** {1 Usage notes} *)
|
||||
|
||||
(** {b TL;DR} Don't forget to seed; don't maintain your own [g].
|
||||
|
||||
For common operations on Unix (independent of your asynchronous task
|
||||
library, you can use /dev/urandom or getentropy(3) (actually getrandom(3) on
|
||||
Linux, getentropy() on macOS and BSD systems, BCryptGenRandom on Windows).
|
||||
|
||||
Please ensure to call [Mirage_crypto_rng_unix.use_default], or
|
||||
[Mirage_crypto_rng_unix.use_dev_urandom] (if you only want to use
|
||||
/dev/urandom), or [Mirage_crypto_rng_unix.use_getentropy] (if you only want
|
||||
to use getrandom/getentropy/BCryptGenRandom).
|
||||
|
||||
For fine-grained control (doing entropy harvesting, etc.), please continue
|
||||
reading the documentation below. {b Please be aware that the feeding of
|
||||
Fortuna and producing random numbers is not thread-safe} (it is on Miou_unix
|
||||
via Pfortuna).
|
||||
|
||||
Suitable entropy feeding of generators are provided by other libraries
|
||||
{{!Mirage_crypto_rng_mirage}mirage-crypto-rng-mirage} (for MirageOS),
|
||||
and {{!Mirage_crypto_rng_miou_unix}mirage-crypto-miou-unix} (for Miou_unix).
|
||||
|
||||
The intention is that "initialize" in the respective sub-library is called
|
||||
once, which sets the default generator and registers entropy
|
||||
harvesting asynchronous tasks. The semantics is that the entropy is always
|
||||
fed to the {{!default_generator}default generator}, which is not necessarily
|
||||
the one set by "initialize". The reasoning behind this is that the default
|
||||
generator should be used in most setting, and that should be fed a constant
|
||||
stream of entropy.
|
||||
|
||||
The RNGs here are merely the deterministic part of a full random number
|
||||
generation suite. For proper operation, they need to be seeded with a
|
||||
high-quality entropy source.
|
||||
|
||||
Although this module exposes a more fine-grained interface, e.g. allowing
|
||||
manual seeding of generators, this is intended either for implementing
|
||||
entropy-harvesting modules, or very specialized purposes. Users of this
|
||||
library should almost certainly use one of the above entropy libraries, and
|
||||
avoid manually managing the generator seeding.
|
||||
|
||||
Similarly, although it is possible to swap the default generator and gain
|
||||
control over the random stream, this is also intended for specialized
|
||||
applications such as testing or similar scenarios where the RNG needs to be
|
||||
fully deterministic (RFC 6979, deterministic usage of DSA), or as a
|
||||
component of deterministic algorithms which internally rely on pseudorandom
|
||||
streams.
|
||||
|
||||
In the general case, users should not maintain their local instances of
|
||||
{{!g}g}. All of the generators in a process have to compete for entropy, and
|
||||
it is likely that the overall result will have lower effective
|
||||
unpredictability.
|
||||
|
||||
The recommended way to use these functions is either to accept an optional
|
||||
generator and pass it down, or to ignore the generator altogether, as
|
||||
illustrated in the {{!rng_examples}examples}.
|
||||
*)
|
||||
|
||||
(** {1 Interface} *)
|
||||
|
||||
type g
|
||||
(** A generator (PRNG) with its state. *)
|
||||
|
||||
exception Unseeded_generator
|
||||
(** Thrown when using an uninitialized {{!g}generator}. *)
|
||||
|
||||
exception No_default_generator
|
||||
(** Thrown when {!set_default_generator} has not been called. *)
|
||||
|
||||
(** Entropy sources and collection *)
|
||||
module Entropy : sig
|
||||
|
||||
(** Entropy sources. *)
|
||||
type source
|
||||
|
||||
val sources : unit -> source list
|
||||
(** [sources ()] returns the list of available sources. *)
|
||||
|
||||
val pp_source : Format.formatter -> source -> unit
|
||||
(** [pp_source ppf source] pretty-prints the entropy [source] on [ppf]. *)
|
||||
|
||||
val register_source : string -> source
|
||||
(** [register_source name] registers [name] as entropy source. *)
|
||||
|
||||
(** {1 Bootstrap} *)
|
||||
|
||||
val whirlwind_bootstrap : int -> string
|
||||
(** [whirlwind_bootstrap id] exploits CPU-level data races which lead to
|
||||
execution-time variability. It returns 200 bytes random data prefixed
|
||||
by [id].
|
||||
|
||||
See {{:http://www.ieee-security.org/TC/SP2014/papers/Not-So-RandomNumbersinVirtualizedLinuxandtheWhirlwindRNG.pdf}}
|
||||
for further details. *)
|
||||
|
||||
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). 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 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
|
||||
[whirlwind_bootstrap] if not. *)
|
||||
|
||||
(** {1 Timer source} *)
|
||||
|
||||
val interrupt_hook : unit -> string
|
||||
(** [interrupt_hook] collects lower bytes from the cycle counter, to be
|
||||
used for entropy collection in the event loop. *)
|
||||
|
||||
val timer_accumulator : g option -> unit -> unit
|
||||
(** [timer_accumulator g] is the accumulator for the timer source,
|
||||
applying {!interrupt_hook} on each call. *)
|
||||
|
||||
(** {1 Periodic pulled sources} *)
|
||||
|
||||
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, [`Not_supported] is returned. *)
|
||||
|
||||
val rdrand_calls : unit -> int
|
||||
(** [rdrand_calls ()] returns the number of rdrand calls. *)
|
||||
|
||||
val rdrand_failures : unit -> int
|
||||
(** [rdrand_failures ()] returns the number of rdrand failures. *)
|
||||
|
||||
val rdseed_calls : unit -> int
|
||||
(** [rdseed_calls ()] returns the number of rdseed calls. *)
|
||||
|
||||
val rdseed_failures : unit -> int
|
||||
(** [rdseed_failures ()] returns the number of rdseed failures. *)
|
||||
|
||||
(**/**)
|
||||
val id : source -> int
|
||||
(** [id source] is the identifier used for [source]. *)
|
||||
|
||||
val header : int -> string -> string
|
||||
(** [header id data] constructs a unique header with [id], length of [data],
|
||||
and [data]. *)
|
||||
(**/**)
|
||||
end
|
||||
|
||||
(** A single PRNG algorithm. *)
|
||||
module type Generator = sig
|
||||
|
||||
type g
|
||||
(** State type for this generator. *)
|
||||
|
||||
val block : int
|
||||
(** Internally, this generator's {{!generate}generate} always produces
|
||||
[k * block] bytes. *)
|
||||
|
||||
val create : ?time:(unit -> int64) -> unit -> g
|
||||
(** Create a new, unseeded {{!g}g}. *)
|
||||
|
||||
val generate_into : g:g -> bytes -> off:int -> int -> unit
|
||||
[@@alert unsafe "Does not do bounds checks. Use Mirage_crypto_rng.generate_into instead."]
|
||||
(** [generate_into ~g buf ~off n] produces [n] uniformly distributed random
|
||||
bytes into [buf] at offset [off], updating the state of [g].
|
||||
|
||||
Assumes that [buf] is at least [off + n] bytes long. Also assumes that
|
||||
[off] and [n] are positive integers. Caution: do not use in your
|
||||
application, use [Mirage_crypto_rng.generate_into] instead.
|
||||
*)
|
||||
|
||||
val reseed : g:g -> string -> unit
|
||||
(** [reseed ~g bytes] directly updates [g]. Its new state depends both on
|
||||
[bytes] and the previous state.
|
||||
|
||||
A generator is seded after a single application of [reseed]. *)
|
||||
|
||||
val accumulate : g:g -> Entropy.source -> [`Acc of string -> unit]
|
||||
(** [accumulate ~g] is a closure suitable for incrementally feeding
|
||||
small amounts of environmentally sourced entropy into [g].
|
||||
|
||||
Its operation should be fast enough for repeated calling from e.g.
|
||||
event loops. Systems with several distinct, stable entropy sources
|
||||
should use stable [source] to distinguish their sources. *)
|
||||
|
||||
val seeded : g:g -> bool
|
||||
(** [seeded ~g] is [true] iff operations won't throw
|
||||
{{!Unseeded_generator}Unseeded_generator}. *)
|
||||
|
||||
val pools : int
|
||||
(** [pools] is the amount of pools if any. *)
|
||||
end
|
||||
|
||||
type 'a generator = (module Generator with type g = 'a)
|
||||
|
||||
(** Ready-to-use RNG algorithms. *)
|
||||
|
||||
(** {b Fortuna}, a CSPRNG {{: https://www.schneier.com/fortuna.html} proposed}
|
||||
by Schneier. *)
|
||||
module Fortuna : Generator
|
||||
|
||||
(** {b HMAC_DRBG}: A NIST-specified RNG based on HMAC construction over the
|
||||
provided hash. *)
|
||||
module Hmac_drbg (H : Digestif.S) : Generator
|
||||
|
||||
val create : ?g:'a -> ?seed:string -> ?strict:bool ->
|
||||
?time:(unit -> int64) -> 'a generator -> g
|
||||
(** [create ~g ~seed ~strict ~time module] uses a module conforming to the
|
||||
{{!Generator}Generator} signature to instantiate the generic generator
|
||||
{{!g}g}.
|
||||
|
||||
[g] is the state to use, otherwise a fresh one is created.
|
||||
|
||||
[seed] can be provided to immediately reseed the generator with.
|
||||
|
||||
[strict] puts the generator into a more standards-conformant, but slighty
|
||||
slower mode. Useful if the outputs need to match published test-vectors.
|
||||
|
||||
[time] is used to limit the amount of reseedings. Fortuna uses at most once
|
||||
every second. *)
|
||||
|
||||
val default_generator : unit -> g
|
||||
(** [default_generator ()] is the default generator. Functions in this module
|
||||
use this generator when not explicitly supplied one.
|
||||
|
||||
@raise No_default_generator if {!set_default_generator} has not been called. *)
|
||||
|
||||
val set_default_generator : g -> unit
|
||||
(** [set_default_generator g] sets the default generator to [g]. This function
|
||||
must be called once. *)
|
||||
|
||||
(**/**)
|
||||
(* This function is only used by eio to set the default generator to None when
|
||||
the entropy harvesting tasks are finished. *)
|
||||
val unset_default_generator : unit -> unit
|
||||
(** [unset_default_generator ()] sets the default generator to [None]. *)
|
||||
(**/**)
|
||||
|
||||
val generate_into : ?g:g -> bytes -> ?off:int -> int -> unit
|
||||
(** [generate_into ~g buf ~off len] invokes
|
||||
{{!Generator.generate_into}generate_into} on [g] or
|
||||
{{!generator}default generator}. The random data is put into [buf] starting
|
||||
at [off] (defaults to 0) with [len] bytes.
|
||||
|
||||
@raise Invalid_argument if buffer is too small (it must be: [Bytes.length
|
||||
buf - off >= n]) or [off] or [n] are negative.
|
||||
*)
|
||||
|
||||
val generate : ?g:g -> int -> string
|
||||
(** Invoke {!generate_into} on [g] or {{!generator}default generator} and a
|
||||
freshly allocated string. *)
|
||||
|
||||
val block : g option -> int
|
||||
(** {{!Generator.block}Block} size of [g] or
|
||||
{{!generator}default generator}. *)
|
||||
|
||||
(**/**)
|
||||
|
||||
(* The following functions expose the seeding interface. They are meant to
|
||||
* connect the RNG with entropy-providing libraries and subject to change.
|
||||
* Client applications should not use them directly. *)
|
||||
|
||||
val reseed : ?g:g -> string -> unit
|
||||
val accumulate : g option -> Entropy.source -> [`Acc of string -> unit]
|
||||
val seeded : g option -> bool
|
||||
val pools : g option -> int
|
||||
val strict : g option -> bool
|
||||
(**/**)
|
||||
|
||||
|
||||
(** {1:rng_examples Examples}
|
||||
|
||||
Generating a random 13-byte string:
|
||||
{[let cs = Rng.generate 13]}
|
||||
|
||||
Generating a list of string, passing down an optional {{!g}generator}:
|
||||
{[let rec f1 ?g ~n i =
|
||||
if i < 1 then [] else Rng.generate ?g n :: f1 ?g ~n (i - 1)]}
|
||||
|
||||
Generating a [Z.t] smaller than [10]:
|
||||
{[let f2 ?g () = Mirage_crypto_pk.Z_extra.gen ?g Z.(~$10)]}
|
||||
|
||||
Creating a local Fortuna instance and using it as a key-derivation function:
|
||||
{[let f3 secret =
|
||||
let g = Rng.(create ~seed:secret (module Generators.Fortuna)) in
|
||||
Rng.generate ~g 32]}
|
||||
*)
|
||||
Loading…
Add table
Add a link
Reference in a new issue