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