Loading...
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 | /* Copyright (c) (2018-2022) Apple Inc. All rights reserved. * * corecrypto is licensed under Apple Inc.’s Internal Use License Agreement (which * is contained in the License.txt file distributed with corecrypto) and only to * people who accept that license. IMPORTANT: Any license rights granted to you by * Apple Inc. (if any) are limited to internal use within your organization only on * devices and computers you own or control, for the sole purpose of verifying the * security characteristics and correct functioning of the Apple Software. You may * not, directly or indirectly, redistribute the Apple Software or any portions thereof. */ #ifndef _CORECRYPTO_CCKPRNG_H_ #define _CORECRYPTO_CCKPRNG_H_ #include <corecrypto/cc.h> #include "ccrng_fortuna.h" #include "ccrng_crypto.h" #include <corecrypto/ccrng_schedule.h> #include <corecrypto/ccentropy.h> #include <corecrypto/ccdrbg.h> #include "cc_lock.h" // This is a Fortuna-inspired PRNG. While it differs from Fortuna in // many minor details, the biggest difference is its support for // multiple independent output generators. This is to make it suitable // for use in concurrent environments. // // This PRNG targets a 256-bit security level. // // First, the user should call cckprng_init. The user must specify the // maximum number of output generators that might be // needed. (Typically, users should align this argument with the // number of available CPUs.) // // The user must also provide a read-only handle to an entropy // source. This is a fixed-size buffer that will receive entropy // updates out of band from the PRNG (e.g. in an interrupt // handler). The PRNG will consume entropy from this buffer according // to an internal schedule driven by calls to cckprng_refresh (see // below). // // The user should call cckprng_initgen for as many output generators // as are needed. The numeric argument is an identifier to be reused // during calls to cckprng_generate (see below) and must be less than // the maximum number of generators specified to cckprng_init. // // After initialization, the user is free to call cckprng_generate to // generate random bytes. The user must specify the generator in this // call using a numeric identifier passed in the call to // cckprng_initgen. // // Output generation is limited to 256 bytes per request. Users should // make multiple requests if more output is needed. // // The user is expected to call cckprng_refresh regularly. This // function consumes entropy and mixes it into the output generators // according to an internal schedule. // // This implementation is thread-safe. Internally, a set of mutexes // guard access to internal state. Most functions rely on a single // mutex to protect shared state. The main exception is the // cckprng_generate function, which uses a per-generator mutex to // allow concurrent output generation on different threads. // // Another important exception is cckprng_refresh. While this function // relies on the shared mutex, it returns immediately if it cannot // acquire it. // // The PRNG also supports user-initiated reseeds. This is to support a // user-writable random device. // // This PRNG supports reseeds concurrent with output generation, // i.e. it is safe to call cckprng_reseed or cckprng_refresh while // another thread is calling cckprng_generate. #define CCKPRNG_SEED_NBYTES 32 // A function pointer to fill an entropy buffer. It should return some // estimate of entropy (e.g. the number of timing samples resident in // the buffer). The implementation may return zero if no entropy is // available. The implementation should return negative in case of an // error (e.g. a failure in continuous health tests). // // The caller should set entropy_nbytes to the maximum size of the // input buffer, and the implementation should set it to the number of // bytes it has initialized. The third argument is arbitrary state the // implementation provides and receives back on each call. typedef ccrng_fortuna_getentropy cckprng_getentropy; #define CCKPRNG_ENTROPY_SIZE 64 #define CCKPRNG_DRBG_STATE_MAX_SIZE ((size_t)1280) #define CCKPRNG_CACHED_BUF_SIZE ((size_t)256) #define CCKPRNG_MAX_REQUEST_SIZE ((size_t)4096) struct cckprng_ctx { // A flag set every time Fortuna reseeds itself ccrng_schedule_atomic_flag_ctx_t schedule_ctx; ccentropy_rng_ctx_t entropy_ctx; cc_lock_ctx_t lock_ctx; struct ccdrbg_info drbg_info; uint8_t drbg_state[CCKPRNG_DRBG_STATE_MAX_SIZE]; ccdrbg_df_bc_ctx_t drbg_df_ctx; uint8_t cache[CCKPRNG_CACHED_BUF_SIZE]; ccrng_crypto_ctx_t rng_ctx; struct ccrng_fortuna_ctx fortuna_ctx; }; // This collection of function pointers is just a convenience for // registering the PRNG with xnu struct cckprng_funcs { void (*CC_SPTR(cckprng_funcs, init))(struct cckprng_ctx *ctx, size_t seed_nbytes, const void *seed, size_t nonce_nbytes, const void *nonce, cckprng_getentropy getentropy, void *getentropy_arg); void (*CC_SPTR(cckprng_funcs, initgen))(struct cckprng_ctx *ctx, unsigned gen_idx); void (*CC_SPTR(cckprng_funcs, reseed))(struct cckprng_ctx *ctx, size_t nbytes, const void *seed); void (*CC_SPTR(cckprng_funcs, refresh))(struct cckprng_ctx *ctx); void (*CC_SPTR(cckprng_funcs, generate))(struct cckprng_ctx *ctx, unsigned gen_idx, size_t nbytes, void *out); void (*CC_SPTR(cckprng_funcs, init_with_getentropy))(struct cckprng_ctx *ctx, unsigned max_ngens, size_t seed_nbytes, const void *seed, size_t nonce_nbytes, const void *nonce, cckprng_getentropy getentropy, void *getentropy_arg); }; /* @function cckprng_init @abstract Initialize a kernel PRNG context. @param ctx Context for this instance @param seed_nbytes Length of the seed in bytes @param seed Pointer to a high-entropy seed @param nonce_nbytes Length of the nonce in bytes @param nonce Pointer to a single-use nonce @param getentropy A function pointer to fill an entropy buffer @param getentropy_arg State provided to the entropy function @discussion See the @p cckprng_getentropy type definition for discussion on its semantics. */ void cckprng_init(struct cckprng_ctx *ctx, size_t seed_nbytes, const void *seed, size_t nonce_nbytes, const void *nonce, cckprng_getentropy getentropy, void *getentropy_arg); /* @function cckprng_init_with_getentropy @abstract Initialize a kernel PRNG context. @param ctx Context for this instance @param max_ngens Maximum count of generators that may be allocated @param seed_nbytes Length of the seed in bytes @param seed Pointer to a high-entropy seed @param nonce_nbytes Length of the nonce in bytes @param nonce Pointer to a single-use nonce @param getentropy A function pointer to fill an entropy buffer @param getentropy_arg State provided to the entropy function @discussion @p max_ngens should be set based on an upper bound of CPUs available on the device. See the @p cckprng_getentropy type definition for discussion on its semantics. */ void cckprng_init_with_getentropy(struct cckprng_ctx *ctx, unsigned max_ngens, size_t seed_nbytes, const void *seed, size_t nonce_nbytes, const void *nonce, cckprng_getentropy getentropy, void *getentropy_arg); /* @function cckprng_initgen @abstract Initialize an output generator. @param ctx Context for this instance @param gen_idx Index of the generator @discussion @p gen_idx must be less than @p max_ngens provided to @cckprng_init and must be unique within the lifetime of a PRNG context. This function will abort if these contracts are violated. */ void cckprng_initgen(struct cckprng_ctx *ctx, unsigned gen_idx); /* @function cckprng_reseed @abstract Reseed a kernel PRNG context with a user-supplied seed. @param ctx Context for this instance @param nbytes Length of the seed in bytes @param seed Pointer to a high-entropy seed @discussion It is safe to expose this function to attacker-controlled requests (e.g. writes to /dev/random). */ void cckprng_reseed(struct cckprng_ctx *ctx, size_t nbytes, const void *seed); /* @function cckprng_refresh @abstract Consume entropy and reseed according to an internal schedule. @param ctx Context for this instance @discussion This function should be called on a regular basis. (For example, it is reasonable to call this inline before a call to @p cckprng_generate.) This function will not necessarily consume entropy or reseed the internal state on any given invocation. To force an immediate reseed, call @p cckprng_reseed. */ void cckprng_refresh(struct cckprng_ctx *ctx); #define CCKPRNG_GENERATE_MAX_NBYTES 256 /* @function cckprng_generate @abstract Generate random values for use in applications. @param ctx Context for this instance @param gen_idx Index of the output generator @param nbytes Length of the desired output in bytes @param out Pointer to the output buffer @discussion @p gen_idx must be a previous argument to @p cckprng_initgen. @p nbytes must be less than or equal to @p CCKPRNG_GENERATE_MAX_NBYTES. (Callers may invoke this function in a loop to generate larger outputs.) This function will abort if these contracts are violated. */ void cckprng_generate(struct cckprng_ctx *ctx, unsigned gen_idx, size_t nbytes, void *out); #endif /* _CORECRYPTO_CCKPRNG_H_ */ |