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 | |