1/* Copyright (c) (2018-2022) Apple Inc. All rights reserved.
2 *
3 * corecrypto is licensed under Apple Inc.’s Internal Use License Agreement (which
4 * is contained in the License.txt file distributed with corecrypto) and only to
5 * people who accept that license. IMPORTANT: Any license rights granted to you by
6 * Apple Inc. (if any) are limited to internal use within your organization only on
7 * devices and computers you own or control, for the sole purpose of verifying the
8 * security characteristics and correct functioning of the Apple Software. You may
9 * not, directly or indirectly, redistribute the Apple Software or any portions thereof.
10 */
11
12#ifndef _CORECRYPTO_CCRNG_FORTUNA_H_
13#define _CORECRYPTO_CCRNG_FORTUNA_H_
14
15#include <corecrypto/cc.h>
16#include <corecrypto/ccrng.h>
17#include "cc_lock.h"
18
19// This is a Fortuna-inspired PRNG. While it differs from Fortuna in
20// many minor details, the biggest difference is its support for
21// multiple independent output generators. This is to make it suitable
22// for use in concurrent environments.
23//
24// This PRNG targets a 256-bit security level.
25//
26// First, the user should call ccrng_fortuna_init. The user must
27// specify the maximum number of output generators that might be
28// needed. (Typically, users should align this argument with the
29// number of available CPUs.)
30//
31// The user must also provide a read-only handle to an entropy
32// source. This is a fixed-size buffer that will receive entropy
33// updates out of band from the PRNG (e.g. in an interrupt
34// handler). The PRNG will consume entropy from this buffer according
35// to an internal schedule driven by calls to ccrng_fortuna_refresh
36// (see below).
37//
38// The user should call ccrng_fortuna_initgen for as many output
39// generators as are needed. The numeric argument is an identifier to
40// be reused during calls to ccrng_fortuna_generate (see below) and
41// must be less than the maximum number of generators specified to
42// ccrng_fortuna_init.
43//
44// After initialization, the user is free to call
45// ccrng_fortuna_generate to generate random bytes. The user must
46// specify the generator in this call using a numeric identifier
47// passed in the call to ccrng_fortuna_initgen.
48//
49// Output generation is limited to 256 bytes per request. Users should
50// make multiple requests if more output is needed.
51//
52// The user is expected to call ccrng_fortuna_refresh regularly. This
53// function consumes entropy and mixes it into the output generators
54// according to an internal schedule.
55//
56// This implementation is thread-safe. Internally, a set of mutexes
57// guard access to internal state. Most functions rely on a single
58// mutex to protect shared state. The main exception is the
59// ccrng_fortuna_generate function, which uses a per-generator mutex
60// to allow concurrent output generation on different threads.
61//
62// Another important exception is ccrng_fortuna_refresh. While this
63// function relies on the shared mutex, it returns immediately if it
64// cannot acquire it.
65//
66// The PRNG also supports user-initiated reseeds. This is to support a
67// user-writable random device.
68//
69// This PRNG supports reseeds concurrent with output generation,
70// i.e. it is safe to call ccrng_fortuna_reseed or
71// ccrng_fortuna_refresh while another thread is calling
72// ccrng_fortuna_generate.
73
74#define CCRNG_FORTUNA_NPOOLS 32
75#define CCRNG_FORTUNA_SEED_NBYTES 32
76#define CCRNG_FORTUNA_POOL_NBYTES 32
77#define CCRNG_FORTUNA_KEY_NBYTES 32
78
79struct ccrng_fortuna_pool_ctx {
80 uint8_t data[CCRNG_FORTUNA_POOL_NBYTES];
81
82 // The number of samples currently resident in the pool
83 uint64_t nsamples;
84
85 // The number of times this pool has been drained in a reseed
86 uint64_t ndrains;
87
88 // The maximum number of samples this pool has held at any one time
89 uint64_t nsamples_max;
90};
91
92struct ccrng_fortuna_sched_ctx {
93 // A counter governing the set of entropy pools to drain
94 uint64_t reseed_sched;
95
96 // An index used to add entropy to pools in a round-robin style
97 unsigned pool_idx;
98};
99
100// A function pointer to fill an entropy buffer. It should return some
101// estimate of entropy (e.g. the number of timing samples resident in
102// the buffer). The implementation may return zero if no entropy is
103// available. The implementation should return negative in case of an
104// error (e.g. a failure in continuous health tests).
105//
106// The caller should set entropy_nbytes to the maximum size of the
107// input buffer, and the implementation should set it to the number of
108// bytes it has initialized. The third argument is arbitrary state the
109// implementation provides and receives back on each call.
110typedef int32_t (*ccrng_fortuna_getentropy)(size_t *entropy_nbytes,
111 void *entropy,
112 void *arg);
113
114struct ccrng_fortuna_ctx {
115 CCRNG_STATE_COMMON
116
117 // The root secret of the PRNG
118 uint8_t key[CCRNG_FORTUNA_KEY_NBYTES];
119
120 // A counter used in CTR mode (with the root secret)
121 uint8_t ctr[16];
122
123 // State used to schedule entropy consumption and reseeds
124 struct ccrng_fortuna_sched_ctx sched;
125
126 // A mutex governing access to shared state
127 cc_lock_ctx_t lock;
128
129 // A set of entropy pools
130 struct ccrng_fortuna_pool_ctx pools[CCRNG_FORTUNA_NPOOLS];
131
132 // A function pointer to get entropy
133 CC_SPTR(ccrng_fortuna_ctx, ccrng_fortuna_getentropy) getentropy;
134
135 // An arbitrary piece of state to be provided to the entropy function
136 void *getentropy_arg;
137
138 // A flag describing whether the instance has been seeded with
139 // sufficient entropy. This flag is set when a set of pools
140 // containing a minimum threshold of entropy inputs is
141 // drained. The PRNG will not generate output until this flag is
142 // set. This flag is reset if the entropy source signals a
143 // failure.
144 bool seeded;
145
146 // The number of scheduled reseeds
147 uint64_t nreseeds;
148
149 // The maximum number of samples included in any one scheduler reseed
150 uint64_t schedreseed_nsamples_max;
151
152 // The maximum number of samples included in any one entropy input
153 uint64_t addentropy_nsamples_max;
154};
155
156/*
157 @function ccrng_fortuna_init
158 @abstract Initialize a kernel PRNG context.
159
160 @param ctx Context for this instance
161 @param getentropy A function pointer to fill an entropy buffer
162 @param getentropy_arg State provided to the entropy function
163
164 @discussion @p max_ngens should be set based on an upper bound of CPUs available on the device. See the @p ccrng_fortuna_getentropy type definition for discussion on its semantics.
165*/
166void ccrng_fortuna_init(struct ccrng_fortuna_ctx *ctx,
167 ccrng_fortuna_getentropy getentropy,
168 void *getentropy_arg);
169
170/*
171 @function ccrng_fortuna_refresh
172 @abstract Consume entropy and reseed according to an internal schedule.
173
174 @param ctx Context for this instance
175
176 @return True if a reseed occurred, false otherwise.
177
178 @discussion This function should be called on a regular basis. (For example, it is reasonable to call this inline before a call to @p ccrng_fortuna_generate.) This function will not necessarily consume entropy or reseed the internal state on any given invocation. To force an immediate reseed, call @p ccrng_fortuna_reseed.
179*/
180bool ccrng_fortuna_refresh(struct ccrng_fortuna_ctx *ctx);
181
182#define CCRNG_FORTUNA_GENERATE_MAX_NBYTES 256
183
184/*
185 @function ccrng_fortuna_generate
186 @abstract Generate random values for use in applications.
187
188 @param ctx Context for this instance
189 @param nbytes Length of the desired output in bytes
190 @param out Pointer to the output buffer
191
192 @return 0 on success, negative otherwise.
193
194 @discussion @p gen_idx must be a previous argument to @p ccrng_fortuna_initgen. @p nbytes must be less than or equal to @p CCRNG_FORTUNA_GENERATE_MAX_NBYTES. (Callers may invoke this function in a loop to generate larger outputs.) This function will abort if these contracts are violated.
195*/
196int ccrng_fortuna_generate(struct ccrng_fortuna_ctx *ctx, size_t nbytes, void *out);
197
198#endif /* _CORECRYPTO_CCRNG_FORTUNA_H_ */
199