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