/** * CPU Jitter noise source -- this is the noise source based on the CPU * execution time jitter * * This function injects the individual bits of the time value into the * entropy pool using a hash. * * @ec [in] entropy collector struct * @time_delta [in] time delta to be injected * @loop_cnt [in] if a value not equal to 0 is set, use the given value as * number of loops to perform the hash operation * @stuck [in] Is the time delta identified as stuck? * * Output: * updated hash context */ static void jent_hash_time(struct rand_data *ec, uint64_t time_delta, uint64_t loop_cnt, unsigned int stuck) { HASH_CTX_ON_STACK(ctx); /* Size of intermediary ensures a Keccak operation during hash_update */ uint8_t intermediary[JENT_SHA3_MAX_SIZE_BLOCK] = { 0 }; uint64_t j = 0, output_value; #define MAX_HASH_LOOP 3 #define MIN_HASH_LOOP 0 /* Ensure that macros cannot overflow jent_loop_shuffle() */ BUILD_BUG_ON((MAX_HASH_LOOP + MIN_HASH_LOOP) > 63); uint64_t hash_loop_cnt = jent_loop_shuffle(ec, MAX_HASH_LOOP, MIN_HASH_LOOP); /* Ensure that everything will fit into the intermediary buffer. */ BUILD_BUG_ON(sizeof(intermediary) < (JENT_SHA3_256_SIZE_DIGEST + sizeof(uint64_t))); jent_sha3_256_init(&ctx); /* * testing purposes -- allow test app to set the counter, not * needed during runtime */ if (loop_cnt) hash_loop_cnt = loop_cnt; /* * This loop fills a buffer which is injected into the entropy pool. * The main reason for this loop is to execute something over which we * can perform a timing measurement. The injection of the resulting * data into the pool is performed to ensure the result is used and * the compiler cannot optimize the loop away in case the result is not * used at all. Yet that data is considered "additional information" * considering the terminology from SP800-90A without any entropy. * * Note, it does not matter which or how much data you inject, we are * interested in one Keccack1600 compression operation performed with * the sha3_final. */ for (j = 0; j < hash_loop_cnt; j++) { jent_sha3_update(&ctx, intermediary, JENT_SHA3_256_SIZE_DIGEST); jent_sha3_update(&ctx, (uint8_t *)&ec->rct_count, sizeof(ec->rct_count)); jent_sha3_update(&ctx, (uint8_t *)&ec->apt_cutoff, sizeof(ec->apt_cutoff)); jent_sha3_update(&ctx, (uint8_t *)&ec->apt_observations, sizeof(ec->apt_observations)); jent_sha3_update(&ctx, (uint8_t *)&ec->apt_count, sizeof(ec->apt_count)); jent_sha3_update(&ctx,(uint8_t *) &ec->apt_base, sizeof(ec->apt_base)); jent_sha3_update(&ctx, (uint8_t *)&j, sizeof(uint64_t)); jent_sha3_final(&ctx, intermediary); } /* * Insert the time stamp into the intermediary buffer after the message * digest of the intermediate data. * * If the time stamp is stuck, do not finally insert the value into the * intermediary buffer. Although this operation should not do any harm * even when the time stamp has no entropy, SP800-90B requires that any * conditioning operation to have an identical amount of input data * according to section 3.1.5. */ if (!stuck) { /* Insert the time. */ output_value = time_delta; } else { /* The time is considered stuck. Insert the fixed value 0. */ output_value = 0; } memcpy(intermediary + JENT_SHA3_256_SIZE_DIGEST, (uint8_t *)&output_value, sizeof(uint64_t)); /* * Inject the data from the intermediary buffer, including the hash we * are using for timing, and (if the timer is not stuck) the time stamp. * Only the time is considered to contain any entropy. The intermediary * buffer is exactly SHA3-256-rate-size to always cause a Keccak * operation. */ jent_sha3_update(ec->hash_state, intermediary, sizeof(intermediary)); jent_memset_secure(&ctx, JENT_SHA_MAX_CTX_SIZE); jent_memset_secure(intermediary, sizeof(intermediary)); }