xref: /xnu-12377.41.6/EXTERNAL_HEADERS/corecrypto/ccrng_fortuna.h (revision bbb1b6f9e71b8cdde6e5cd6f4841f207dee3d828)
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 
79 struct 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 
92 struct 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.
110 typedef int32_t (*ccrng_fortuna_getentropy)(size_t *entropy_nbytes,
111                                             void *entropy,
112                                             void *arg);
113 
114 struct 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 */
166 void 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 */
180 bool 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 */
196 int ccrng_fortuna_generate(struct ccrng_fortuna_ctx *ctx, size_t nbytes, void *out);
197 
198 #endif /* _CORECRYPTO_CCRNG_FORTUNA_H_ */
199