1 #include <sys/param.h> 2 #include <sys/systm.h> 3 #include <sys/kernel.h> 4 #include <sys/spinlock.h> 5 #include <sys/spinlock2.h> 6 #include <sys/csprng.h> 7 8 /* 9 * Minimum amount of bytes in pool before we consider it 10 * good enough. 11 * It's 64 + the hash digest size because we always 12 * reinitialize the pools with a hash of the previous chunk 13 * of entropy. 14 */ 15 #define MIN_POOL_SIZE 64 + SHA256_DIGEST_LENGTH 16 17 /* Minimum reseed interval */ 18 #define MIN_RESEED_INTERVAL hz/10 19 20 /* Lock macros */ 21 #define POOL_LOCK_INIT(pool) \ 22 spin_init(&(pool)->lock) 23 24 #define POOL_LOCK(pool) \ 25 spin_lock(&pool->lock) 26 27 #define POOL_TRYLOCK(pool) \ 28 spin_trylock(&pool->lock) 29 30 #define POOL_UNLOCK(pool) \ 31 spin_unlock(&pool->lock) 32 33 34 #define STATE_LOCK_INIT(state) \ 35 spin_init(&state->lock) 36 37 #define STATE_LOCK(state) \ 38 spin_lock(&state->lock) 39 40 #define STATE_UNLOCK(state) \ 41 spin_unlock(&state->lock) 42 43 static void csprng_reseed_callout(void *arg); 44 static int csprng_reseed(struct csprng_state *state); 45 46 static struct timeval csprng_reseed_interval = { 0, 100000 }; 47 48 static 49 int 50 csprng_pool_init(struct csprng_pool *pool, uint8_t *buf, size_t len) 51 { 52 pool->bytes = 0; 53 SHA256_Init(&pool->hash_ctx); 54 55 if (len > 0) 56 SHA256_Update(&pool->hash_ctx, buf, len); 57 58 return 0; 59 } 60 61 int 62 csprng_init(struct csprng_state *state) 63 { 64 int i, r; 65 66 bzero(state->key, sizeof(state->key)); 67 bzero(&state->cipher_ctx, sizeof(state->cipher_ctx)); 68 bzero(state->src_pool_idx, sizeof(state->src_pool_idx)); 69 bzero(&state->last_reseed, sizeof(state->last_reseed)); 70 71 state->nonce = 0; 72 state->ctr = 0; 73 state->reseed_cnt = 0; 74 state->failed_reseeds = 0; 75 state->callout_based_reseed = 0; 76 77 STATE_LOCK_INIT(state); 78 79 for (i = 0; i < 32; i++) { 80 r = csprng_pool_init(&state->pool[i], NULL, 0); 81 if (r != 0) 82 break; 83 POOL_LOCK_INIT(&state->pool[i]); 84 } 85 86 return r; 87 } 88 89 int 90 csprng_init_reseed(struct csprng_state *state) 91 { 92 state->callout_based_reseed = 1; 93 94 callout_init_mp(&state->reseed_callout); 95 callout_reset(&state->reseed_callout, MIN_RESEED_INTERVAL, 96 csprng_reseed_callout, state); 97 98 return 0; 99 } 100 101 /* 102 * XXX: 103 * Sources don't really a uniquely-allocated src id... 104 * another way we could do that is by simply using 105 * (uint8_t)__LINE__ as the source id... cheap & cheerful. 106 */ 107 108 static 109 int 110 encrypt_bytes(struct csprng_state *state, uint8_t *out, uint8_t *in, size_t bytes) 111 { 112 /* Update nonce whenever the counter is about to overflow */ 113 if (chacha_check_counter(&state->cipher_ctx)) { 114 ++state->nonce; 115 chacha_ivsetup(&state->cipher_ctx, (const uint8_t *)&state->nonce); 116 } 117 118 chacha_encrypt_bytes(&state->cipher_ctx, in, out, (uint32_t)bytes); 119 120 return 0; 121 } 122 123 /* 124 * XXX: flags is currently unused, but could be used to know whether 125 * it's a /dev/random or /dev/urandom read, and make sure that 126 * enough entropy has been collected recently, etc. 127 */ 128 int 129 csprng_get_random(struct csprng_state *state, uint8_t *out, int bytes, 130 int flags __unused) 131 { 132 int cnt; 133 int total_bytes = 0; 134 135 /* 136 * XXX: can optimize a bit by digging into chacha_encrypt_bytes 137 * and removing the xor of the stream with the input - that 138 * way we don't have to xor the output (which we provide 139 * as input). 140 */ 141 bzero(out, bytes); 142 143 STATE_LOCK(state); 144 145 if (!state->callout_based_reseed && 146 ratecheck(&state->last_reseed, &csprng_reseed_interval)) { 147 csprng_reseed(state); 148 } 149 150 KKASSERT(state->reseed_cnt > 0); 151 152 while (bytes > 0) { 153 /* Limit amount of output without rekeying to 2^20 */ 154 cnt = (bytes > (1 << 20)) ? (1 << 20) : bytes; 155 156 encrypt_bytes(state, out, out, cnt); 157 158 /* Update key and rekey cipher */ 159 encrypt_bytes(state, state->key, state->key, sizeof(state->key)); 160 chacha_keysetup(&state->cipher_ctx, state->key, 161 8*sizeof(state->key)); 162 163 out += cnt; 164 bytes -= cnt; 165 total_bytes += cnt; 166 } 167 168 STATE_UNLOCK(state); 169 170 return total_bytes; 171 } 172 173 static 174 int 175 csprng_reseed(struct csprng_state *state) 176 { 177 int i; 178 struct csprng_pool *pool; 179 SHA256_CTX hash_ctx; 180 uint8_t digest[SHA256_DIGEST_LENGTH]; 181 182 /* 183 * If there's not enough entropy in the first 184 * pool, don't reseed. 185 */ 186 if (state->pool[0].bytes < MIN_POOL_SIZE) { 187 ++state->failed_reseeds; 188 return 1; 189 } 190 191 SHA256_Init(&hash_ctx); 192 193 /* 194 * Update hash that will result in new key with the 195 * old key. 196 */ 197 SHA256_Update(&hash_ctx, state->key, sizeof(state->key)); 198 199 state->reseed_cnt++; 200 201 for (i = 0; i < 32; i++) { 202 if ((state->reseed_cnt % (1 << i)) != 0) 203 break; 204 205 pool = &state->pool[i]; 206 POOL_LOCK(pool); 207 208 /* 209 * Finalize hash of the entropy in this pool. 210 */ 211 SHA256_Final(digest, &pool->hash_ctx); 212 213 /* 214 * Reinitialize pool with a hash of the old pool digest. 215 * This is a slight deviation from Fortuna as per reference, 216 * but is in line with other Fortuna implementations. 217 */ 218 csprng_pool_init(pool, digest, sizeof(digest)); 219 220 POOL_UNLOCK(pool); 221 222 /* 223 * Update hash that will result in new key with this 224 * pool's hashed entropy. 225 */ 226 SHA256_Update(&hash_ctx, digest, sizeof(digest)); 227 } 228 229 SHA256_Final(state->key, &hash_ctx); 230 231 /* Update key and rekey cipher */ 232 chacha_keysetup(&state->cipher_ctx, state->key, 233 8*sizeof(state->key)); 234 235 /* Increment the nonce if the counter overflows */ 236 if (chacha_incr_counter(&state->cipher_ctx)) { 237 ++state->nonce; 238 chacha_ivsetup(&state->cipher_ctx, (const uint8_t *)&state->nonce); 239 } 240 241 return 0; 242 } 243 244 static 245 void 246 csprng_reseed_callout(void *arg) 247 { 248 struct csprng_state *state = (struct csprng_state *)arg; 249 int reseed_interval = MIN_RESEED_INTERVAL; 250 251 STATE_LOCK(state); 252 253 csprng_reseed(arg); 254 255 STATE_UNLOCK(state); 256 257 callout_reset(&state->reseed_callout, reseed_interval, 258 csprng_reseed_callout, state); 259 } 260 261 int 262 csprng_add_entropy(struct csprng_state *state, int src_id, 263 const uint8_t *entropy, size_t bytes, int flags) 264 { 265 struct csprng_pool *pool; 266 int pool_id; 267 268 /* 269 * Pick the next pool for this source on a round-robin 270 * basis. 271 */ 272 src_id &= 0xff; 273 pool_id = state->src_pool_idx[src_id]++ & 0x1f; 274 pool = &state->pool[pool_id]; 275 276 if (flags & CSPRNG_TRYLOCK) { 277 /* 278 * If we are asked to just try the lock instead 279 * of spinning until we get it, return if we 280 * can't get a hold of the lock right now. 281 */ 282 if (!POOL_TRYLOCK(pool)) 283 return -1; 284 } else { 285 POOL_LOCK(pool); 286 } 287 288 SHA256_Update(&pool->hash_ctx, (const uint8_t *)&src_id, sizeof(src_id)); 289 SHA256_Update(&pool->hash_ctx, (const uint8_t *)&bytes, sizeof(bytes)); 290 SHA256_Update(&pool->hash_ctx, entropy, bytes); 291 292 pool->bytes += bytes; 293 294 POOL_UNLOCK(pool); 295 296 return 0; 297 } 298