Skip to content

Commit bb897c5

Browse files
smuellerDDherbertx
authored andcommitted
crypto: jitter - replace LFSR with SHA3-256
Using the kernel crypto API, the SHA3-256 algorithm is used as conditioning element to replace the LFSR in the Jitter RNG. All other parts of the Jitter RNG are unchanged. The application and use of the SHA-3 conditioning operation is identical to the user space Jitter RNG 3.4.0 by applying the following concept: - the Jitter RNG initializes a SHA-3 state which acts as the "entropy pool" when the Jitter RNG is allocated. - When a new time delta is obtained, it is inserted into the "entropy pool" with a SHA-3 update operation. Note, this operation in most of the cases is a simple memcpy() onto the SHA-3 stack. - To cause a true SHA-3 operation for each time delta operation, a second SHA-3 operation is performed hashing Jitter RNG status information. The final message digest is also inserted into the "entropy pool" with a SHA-3 update operation. Yet, this data is not considered to provide any entropy, but it shall stir the entropy pool. - To generate a random number, a SHA-3 final operation is performed to calculate a message digest followed by an immediate SHA-3 init to re-initialize the "entropy pool". The obtained message digest is one block of the Jitter RNG that is returned to the caller. Mathematically speaking, the random number generated by the Jitter RNG is: aux_t = SHA-3(Jitter RNG state data) Jitter RNG block = SHA-3(time_i || aux_i || time_(i-1) || aux_(i-1) || ... || time_(i-255) || aux_(i-255)) when assuming that the OSR = 1, i.e. the default value. This operation implies that the Jitter RNG has an output-blocksize of 256 bits instead of the 64 bits of the LFSR-based Jitter RNG that is replaced with this patch. The patch also replaces the varying number of invocations of the conditioning function with one fixed number of invocations. The use of the conditioning function consistent with the userspace Jitter RNG library version 3.4.0. The code is tested with a system that exhibited the least amount of entropy generated by the Jitter RNG: the SiFive Unmatched RISC-V system. The measured entropy rate is well above the heuristically implied entropy value of 1 bit of entropy per time delta. On all other tested systems, the measured entropy rate is even higher by orders of magnitude. The measurement was performed using updated tooling provided with the user space Jitter RNG library test framework. The performance of the Jitter RNG with this patch is about en par with the performance of the Jitter RNG without the patch. Signed-off-by: Stephan Mueller <[email protected]> Signed-off-by: Herbert Xu <[email protected]>
1 parent 3908edf commit bb897c5

File tree

4 files changed

+219
-120
lines changed

4 files changed

+219
-120
lines changed

crypto/Kconfig

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1277,6 +1277,7 @@ endif # if CRYPTO_DRBG_MENU
12771277
config CRYPTO_JITTERENTROPY
12781278
tristate "CPU Jitter Non-Deterministic RNG (Random Number Generator)"
12791279
select CRYPTO_RNG
1280+
select CRYPTO_SHA3
12801281
help
12811282
CPU Jitter RNG (Random Number Generator) from the Jitterentropy library
12821283

crypto/jitterentropy-kcapi.c

Lines changed: 163 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
* Non-physical true random number generator based on timing jitter --
33
* Linux Kernel Crypto API specific code
44
*
5-
* Copyright Stephan Mueller <[email protected]>, 2015
5+
* Copyright Stephan Mueller <[email protected]>, 2015 - 2023
66
*
77
* Redistribution and use in source and binary forms, with or without
88
* modification, are permitted provided that the following conditions
@@ -37,6 +37,8 @@
3737
* DAMAGE.
3838
*/
3939

40+
#include <crypto/hash.h>
41+
#include <crypto/sha3.h>
4042
#include <linux/fips.h>
4143
#include <linux/kernel.h>
4244
#include <linux/module.h>
@@ -46,6 +48,8 @@
4648

4749
#include "jitterentropy.h"
4850

51+
#define JENT_CONDITIONING_HASH "sha3-256-generic"
52+
4953
/***************************************************************************
5054
* Helper function
5155
***************************************************************************/
@@ -60,11 +64,6 @@ void jent_zfree(void *ptr)
6064
kfree_sensitive(ptr);
6165
}
6266

63-
void jent_memcpy(void *dest, const void *src, unsigned int n)
64-
{
65-
memcpy(dest, src, n);
66-
}
67-
6867
/*
6968
* Obtain a high-resolution time stamp value. The time stamp is used to measure
7069
* the execution time of a given code path and its variations. Hence, the time
@@ -91,39 +90,174 @@ void jent_get_nstime(__u64 *out)
9190
*out = tmp;
9291
}
9392

93+
int jent_hash_time(void *hash_state, __u64 time, u8 *addtl,
94+
unsigned int addtl_len, __u64 hash_loop_cnt,
95+
unsigned int stuck)
96+
{
97+
struct shash_desc *hash_state_desc = (struct shash_desc *)hash_state;
98+
SHASH_DESC_ON_STACK(desc, hash_state_desc->tfm);
99+
u8 intermediary[SHA3_256_DIGEST_SIZE];
100+
__u64 j = 0;
101+
int ret;
102+
103+
desc->tfm = hash_state_desc->tfm;
104+
105+
if (sizeof(intermediary) != crypto_shash_digestsize(desc->tfm)) {
106+
pr_warn_ratelimited("Unexpected digest size\n");
107+
return -EINVAL;
108+
}
109+
110+
/*
111+
* This loop fills a buffer which is injected into the entropy pool.
112+
* The main reason for this loop is to execute something over which we
113+
* can perform a timing measurement. The injection of the resulting
114+
* data into the pool is performed to ensure the result is used and
115+
* the compiler cannot optimize the loop away in case the result is not
116+
* used at all. Yet that data is considered "additional information"
117+
* considering the terminology from SP800-90A without any entropy.
118+
*
119+
* Note, it does not matter which or how much data you inject, we are
120+
* interested in one Keccack1600 compression operation performed with
121+
* the crypto_shash_final.
122+
*/
123+
for (j = 0; j < hash_loop_cnt; j++) {
124+
ret = crypto_shash_init(desc) ?:
125+
crypto_shash_update(desc, intermediary,
126+
sizeof(intermediary)) ?:
127+
crypto_shash_finup(desc, addtl, addtl_len, intermediary);
128+
if (ret)
129+
goto err;
130+
}
131+
132+
/*
133+
* Inject the data from the previous loop into the pool. This data is
134+
* not considered to contain any entropy, but it stirs the pool a bit.
135+
*/
136+
ret = crypto_shash_update(desc, intermediary, sizeof(intermediary));
137+
if (ret)
138+
goto err;
139+
140+
/*
141+
* Insert the time stamp into the hash context representing the pool.
142+
*
143+
* If the time stamp is stuck, do not finally insert the value into the
144+
* entropy pool. Although this operation should not do any harm even
145+
* when the time stamp has no entropy, SP800-90B requires that any
146+
* conditioning operation to have an identical amount of input data
147+
* according to section 3.1.5.
148+
*/
149+
if (!stuck) {
150+
ret = crypto_shash_update(hash_state_desc, (u8 *)&time,
151+
sizeof(__u64));
152+
}
153+
154+
err:
155+
shash_desc_zero(desc);
156+
memzero_explicit(intermediary, sizeof(intermediary));
157+
158+
return ret;
159+
}
160+
161+
int jent_read_random_block(void *hash_state, char *dst, unsigned int dst_len)
162+
{
163+
struct shash_desc *hash_state_desc = (struct shash_desc *)hash_state;
164+
u8 jent_block[SHA3_256_DIGEST_SIZE];
165+
/* Obtain data from entropy pool and re-initialize it */
166+
int ret = crypto_shash_final(hash_state_desc, jent_block) ?:
167+
crypto_shash_init(hash_state_desc) ?:
168+
crypto_shash_update(hash_state_desc, jent_block,
169+
sizeof(jent_block));
170+
171+
if (!ret && dst_len)
172+
memcpy(dst, jent_block, dst_len);
173+
174+
memzero_explicit(jent_block, sizeof(jent_block));
175+
return ret;
176+
}
177+
94178
/***************************************************************************
95179
* Kernel crypto API interface
96180
***************************************************************************/
97181

98182
struct jitterentropy {
99183
spinlock_t jent_lock;
100184
struct rand_data *entropy_collector;
185+
struct crypto_shash *tfm;
186+
struct shash_desc *sdesc;
101187
};
102188

103-
static int jent_kcapi_init(struct crypto_tfm *tfm)
189+
static void jent_kcapi_cleanup(struct crypto_tfm *tfm)
104190
{
105191
struct jitterentropy *rng = crypto_tfm_ctx(tfm);
106-
int ret = 0;
107192

108-
rng->entropy_collector = jent_entropy_collector_alloc(1, 0);
109-
if (!rng->entropy_collector)
110-
ret = -ENOMEM;
193+
spin_lock(&rng->jent_lock);
111194

112-
spin_lock_init(&rng->jent_lock);
113-
return ret;
114-
}
195+
if (rng->sdesc) {
196+
shash_desc_zero(rng->sdesc);
197+
kfree(rng->sdesc);
198+
}
199+
rng->sdesc = NULL;
115200

116-
static void jent_kcapi_cleanup(struct crypto_tfm *tfm)
117-
{
118-
struct jitterentropy *rng = crypto_tfm_ctx(tfm);
201+
if (rng->tfm)
202+
crypto_free_shash(rng->tfm);
203+
rng->tfm = NULL;
119204

120-
spin_lock(&rng->jent_lock);
121205
if (rng->entropy_collector)
122206
jent_entropy_collector_free(rng->entropy_collector);
123207
rng->entropy_collector = NULL;
124208
spin_unlock(&rng->jent_lock);
125209
}
126210

211+
static int jent_kcapi_init(struct crypto_tfm *tfm)
212+
{
213+
struct jitterentropy *rng = crypto_tfm_ctx(tfm);
214+
struct crypto_shash *hash;
215+
struct shash_desc *sdesc;
216+
int size, ret = 0;
217+
218+
spin_lock_init(&rng->jent_lock);
219+
220+
/*
221+
* Use SHA3-256 as conditioner. We allocate only the generic
222+
* implementation as we are not interested in high-performance. The
223+
* execution time of the SHA3 operation is measured and adds to the
224+
* Jitter RNG's unpredictable behavior. If we have a slower hash
225+
* implementation, the execution timing variations are larger. When
226+
* using a fast implementation, we would need to call it more often
227+
* as its variations are lower.
228+
*/
229+
hash = crypto_alloc_shash(JENT_CONDITIONING_HASH, 0, 0);
230+
if (IS_ERR(hash)) {
231+
pr_err("Cannot allocate conditioning digest\n");
232+
return PTR_ERR(hash);
233+
}
234+
rng->tfm = hash;
235+
236+
size = sizeof(struct shash_desc) + crypto_shash_descsize(hash);
237+
sdesc = kmalloc(size, GFP_KERNEL);
238+
if (!sdesc) {
239+
ret = -ENOMEM;
240+
goto err;
241+
}
242+
243+
sdesc->tfm = hash;
244+
crypto_shash_init(sdesc);
245+
rng->sdesc = sdesc;
246+
247+
rng->entropy_collector = jent_entropy_collector_alloc(1, 0, sdesc);
248+
if (!rng->entropy_collector) {
249+
ret = -ENOMEM;
250+
goto err;
251+
}
252+
253+
spin_lock_init(&rng->jent_lock);
254+
return 0;
255+
256+
err:
257+
jent_kcapi_cleanup(tfm);
258+
return ret;
259+
}
260+
127261
static int jent_kcapi_random(struct crypto_rng *tfm,
128262
const u8 *src, unsigned int slen,
129263
u8 *rdata, unsigned int dlen)
@@ -180,15 +314,24 @@ static struct rng_alg jent_alg = {
180314
.cra_module = THIS_MODULE,
181315
.cra_init = jent_kcapi_init,
182316
.cra_exit = jent_kcapi_cleanup,
183-
184317
}
185318
};
186319

187320
static int __init jent_mod_init(void)
188321
{
322+
SHASH_DESC_ON_STACK(desc, tfm);
323+
struct crypto_shash *tfm;
189324
int ret = 0;
190325

191-
ret = jent_entropy_init();
326+
tfm = crypto_alloc_shash(JENT_CONDITIONING_HASH, 0, 0);
327+
if (IS_ERR(tfm))
328+
return PTR_ERR(tfm);
329+
330+
desc->tfm = tfm;
331+
crypto_shash_init(desc);
332+
ret = jent_entropy_init(desc);
333+
shash_desc_zero(desc);
334+
crypto_free_shash(tfm);
192335
if (ret) {
193336
/* Handle permanent health test error */
194337
if (fips_enabled)

0 commit comments

Comments
 (0)