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