162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * PRNG: Pseudo Random Number Generator
462306a36Sopenharmony_ci *       Based on NIST Recommended PRNG From ANSI X9.31 Appendix A.2.4 using
562306a36Sopenharmony_ci *       AES 128 cipher
662306a36Sopenharmony_ci *
762306a36Sopenharmony_ci *  (C) Neil Horman <nhorman@tuxdriver.com>
862306a36Sopenharmony_ci */
962306a36Sopenharmony_ci
1062306a36Sopenharmony_ci#include <crypto/internal/cipher.h>
1162306a36Sopenharmony_ci#include <crypto/internal/rng.h>
1262306a36Sopenharmony_ci#include <linux/err.h>
1362306a36Sopenharmony_ci#include <linux/init.h>
1462306a36Sopenharmony_ci#include <linux/module.h>
1562306a36Sopenharmony_ci#include <linux/moduleparam.h>
1662306a36Sopenharmony_ci#include <linux/string.h>
1762306a36Sopenharmony_ci
1862306a36Sopenharmony_ci#define DEFAULT_PRNG_KEY "0123456789abcdef"
1962306a36Sopenharmony_ci#define DEFAULT_PRNG_KSZ 16
2062306a36Sopenharmony_ci#define DEFAULT_BLK_SZ 16
2162306a36Sopenharmony_ci#define DEFAULT_V_SEED "zaybxcwdveuftgsh"
2262306a36Sopenharmony_ci
2362306a36Sopenharmony_ci/*
2462306a36Sopenharmony_ci * Flags for the prng_context flags field
2562306a36Sopenharmony_ci */
2662306a36Sopenharmony_ci
2762306a36Sopenharmony_ci#define PRNG_FIXED_SIZE 0x1
2862306a36Sopenharmony_ci#define PRNG_NEED_RESET 0x2
2962306a36Sopenharmony_ci
3062306a36Sopenharmony_ci/*
3162306a36Sopenharmony_ci * Note: DT is our counter value
3262306a36Sopenharmony_ci *	 I is our intermediate value
3362306a36Sopenharmony_ci *	 V is our seed vector
3462306a36Sopenharmony_ci * See http://csrc.nist.gov/groups/STM/cavp/documents/rng/931rngext.pdf
3562306a36Sopenharmony_ci * for implementation details
3662306a36Sopenharmony_ci */
3762306a36Sopenharmony_ci
3862306a36Sopenharmony_ci
3962306a36Sopenharmony_cistruct prng_context {
4062306a36Sopenharmony_ci	spinlock_t prng_lock;
4162306a36Sopenharmony_ci	unsigned char rand_data[DEFAULT_BLK_SZ];
4262306a36Sopenharmony_ci	unsigned char last_rand_data[DEFAULT_BLK_SZ];
4362306a36Sopenharmony_ci	unsigned char DT[DEFAULT_BLK_SZ];
4462306a36Sopenharmony_ci	unsigned char I[DEFAULT_BLK_SZ];
4562306a36Sopenharmony_ci	unsigned char V[DEFAULT_BLK_SZ];
4662306a36Sopenharmony_ci	u32 rand_data_valid;
4762306a36Sopenharmony_ci	struct crypto_cipher *tfm;
4862306a36Sopenharmony_ci	u32 flags;
4962306a36Sopenharmony_ci};
5062306a36Sopenharmony_ci
5162306a36Sopenharmony_cistatic int dbg;
5262306a36Sopenharmony_ci
5362306a36Sopenharmony_cistatic void hexdump(char *note, unsigned char *buf, unsigned int len)
5462306a36Sopenharmony_ci{
5562306a36Sopenharmony_ci	if (dbg) {
5662306a36Sopenharmony_ci		printk(KERN_CRIT "%s", note);
5762306a36Sopenharmony_ci		print_hex_dump(KERN_CONT, "", DUMP_PREFIX_OFFSET,
5862306a36Sopenharmony_ci				16, 1,
5962306a36Sopenharmony_ci				buf, len, false);
6062306a36Sopenharmony_ci	}
6162306a36Sopenharmony_ci}
6262306a36Sopenharmony_ci
6362306a36Sopenharmony_ci#define dbgprint(format, args...) do {\
6462306a36Sopenharmony_ciif (dbg)\
6562306a36Sopenharmony_ci	printk(format, ##args);\
6662306a36Sopenharmony_ci} while (0)
6762306a36Sopenharmony_ci
6862306a36Sopenharmony_cistatic void xor_vectors(unsigned char *in1, unsigned char *in2,
6962306a36Sopenharmony_ci			unsigned char *out, unsigned int size)
7062306a36Sopenharmony_ci{
7162306a36Sopenharmony_ci	int i;
7262306a36Sopenharmony_ci
7362306a36Sopenharmony_ci	for (i = 0; i < size; i++)
7462306a36Sopenharmony_ci		out[i] = in1[i] ^ in2[i];
7562306a36Sopenharmony_ci
7662306a36Sopenharmony_ci}
7762306a36Sopenharmony_ci/*
7862306a36Sopenharmony_ci * Returns DEFAULT_BLK_SZ bytes of random data per call
7962306a36Sopenharmony_ci * returns 0 if generation succeeded, <0 if something went wrong
8062306a36Sopenharmony_ci */
8162306a36Sopenharmony_cistatic int _get_more_prng_bytes(struct prng_context *ctx, int cont_test)
8262306a36Sopenharmony_ci{
8362306a36Sopenharmony_ci	int i;
8462306a36Sopenharmony_ci	unsigned char tmp[DEFAULT_BLK_SZ];
8562306a36Sopenharmony_ci	unsigned char *output = NULL;
8662306a36Sopenharmony_ci
8762306a36Sopenharmony_ci
8862306a36Sopenharmony_ci	dbgprint(KERN_CRIT "Calling _get_more_prng_bytes for context %p\n",
8962306a36Sopenharmony_ci		ctx);
9062306a36Sopenharmony_ci
9162306a36Sopenharmony_ci	hexdump("Input DT: ", ctx->DT, DEFAULT_BLK_SZ);
9262306a36Sopenharmony_ci	hexdump("Input I: ", ctx->I, DEFAULT_BLK_SZ);
9362306a36Sopenharmony_ci	hexdump("Input V: ", ctx->V, DEFAULT_BLK_SZ);
9462306a36Sopenharmony_ci
9562306a36Sopenharmony_ci	/*
9662306a36Sopenharmony_ci	 * This algorithm is a 3 stage state machine
9762306a36Sopenharmony_ci	 */
9862306a36Sopenharmony_ci	for (i = 0; i < 3; i++) {
9962306a36Sopenharmony_ci
10062306a36Sopenharmony_ci		switch (i) {
10162306a36Sopenharmony_ci		case 0:
10262306a36Sopenharmony_ci			/*
10362306a36Sopenharmony_ci			 * Start by encrypting the counter value
10462306a36Sopenharmony_ci			 * This gives us an intermediate value I
10562306a36Sopenharmony_ci			 */
10662306a36Sopenharmony_ci			memcpy(tmp, ctx->DT, DEFAULT_BLK_SZ);
10762306a36Sopenharmony_ci			output = ctx->I;
10862306a36Sopenharmony_ci			hexdump("tmp stage 0: ", tmp, DEFAULT_BLK_SZ);
10962306a36Sopenharmony_ci			break;
11062306a36Sopenharmony_ci		case 1:
11162306a36Sopenharmony_ci
11262306a36Sopenharmony_ci			/*
11362306a36Sopenharmony_ci			 * Next xor I with our secret vector V
11462306a36Sopenharmony_ci			 * encrypt that result to obtain our
11562306a36Sopenharmony_ci			 * pseudo random data which we output
11662306a36Sopenharmony_ci			 */
11762306a36Sopenharmony_ci			xor_vectors(ctx->I, ctx->V, tmp, DEFAULT_BLK_SZ);
11862306a36Sopenharmony_ci			hexdump("tmp stage 1: ", tmp, DEFAULT_BLK_SZ);
11962306a36Sopenharmony_ci			output = ctx->rand_data;
12062306a36Sopenharmony_ci			break;
12162306a36Sopenharmony_ci		case 2:
12262306a36Sopenharmony_ci			/*
12362306a36Sopenharmony_ci			 * First check that we didn't produce the same
12462306a36Sopenharmony_ci			 * random data that we did last time around through this
12562306a36Sopenharmony_ci			 */
12662306a36Sopenharmony_ci			if (!memcmp(ctx->rand_data, ctx->last_rand_data,
12762306a36Sopenharmony_ci					DEFAULT_BLK_SZ)) {
12862306a36Sopenharmony_ci				if (cont_test) {
12962306a36Sopenharmony_ci					panic("cprng %p Failed repetition check!\n",
13062306a36Sopenharmony_ci						ctx);
13162306a36Sopenharmony_ci				}
13262306a36Sopenharmony_ci
13362306a36Sopenharmony_ci				printk(KERN_ERR
13462306a36Sopenharmony_ci					"ctx %p Failed repetition check!\n",
13562306a36Sopenharmony_ci					ctx);
13662306a36Sopenharmony_ci
13762306a36Sopenharmony_ci				ctx->flags |= PRNG_NEED_RESET;
13862306a36Sopenharmony_ci				return -EINVAL;
13962306a36Sopenharmony_ci			}
14062306a36Sopenharmony_ci			memcpy(ctx->last_rand_data, ctx->rand_data,
14162306a36Sopenharmony_ci				DEFAULT_BLK_SZ);
14262306a36Sopenharmony_ci
14362306a36Sopenharmony_ci			/*
14462306a36Sopenharmony_ci			 * Lastly xor the random data with I
14562306a36Sopenharmony_ci			 * and encrypt that to obtain a new secret vector V
14662306a36Sopenharmony_ci			 */
14762306a36Sopenharmony_ci			xor_vectors(ctx->rand_data, ctx->I, tmp,
14862306a36Sopenharmony_ci				DEFAULT_BLK_SZ);
14962306a36Sopenharmony_ci			output = ctx->V;
15062306a36Sopenharmony_ci			hexdump("tmp stage 2: ", tmp, DEFAULT_BLK_SZ);
15162306a36Sopenharmony_ci			break;
15262306a36Sopenharmony_ci		}
15362306a36Sopenharmony_ci
15462306a36Sopenharmony_ci
15562306a36Sopenharmony_ci		/* do the encryption */
15662306a36Sopenharmony_ci		crypto_cipher_encrypt_one(ctx->tfm, output, tmp);
15762306a36Sopenharmony_ci
15862306a36Sopenharmony_ci	}
15962306a36Sopenharmony_ci
16062306a36Sopenharmony_ci	/*
16162306a36Sopenharmony_ci	 * Now update our DT value
16262306a36Sopenharmony_ci	 */
16362306a36Sopenharmony_ci	for (i = DEFAULT_BLK_SZ - 1; i >= 0; i--) {
16462306a36Sopenharmony_ci		ctx->DT[i] += 1;
16562306a36Sopenharmony_ci		if (ctx->DT[i] != 0)
16662306a36Sopenharmony_ci			break;
16762306a36Sopenharmony_ci	}
16862306a36Sopenharmony_ci
16962306a36Sopenharmony_ci	dbgprint("Returning new block for context %p\n", ctx);
17062306a36Sopenharmony_ci	ctx->rand_data_valid = 0;
17162306a36Sopenharmony_ci
17262306a36Sopenharmony_ci	hexdump("Output DT: ", ctx->DT, DEFAULT_BLK_SZ);
17362306a36Sopenharmony_ci	hexdump("Output I: ", ctx->I, DEFAULT_BLK_SZ);
17462306a36Sopenharmony_ci	hexdump("Output V: ", ctx->V, DEFAULT_BLK_SZ);
17562306a36Sopenharmony_ci	hexdump("New Random Data: ", ctx->rand_data, DEFAULT_BLK_SZ);
17662306a36Sopenharmony_ci
17762306a36Sopenharmony_ci	return 0;
17862306a36Sopenharmony_ci}
17962306a36Sopenharmony_ci
18062306a36Sopenharmony_ci/* Our exported functions */
18162306a36Sopenharmony_cistatic int get_prng_bytes(char *buf, size_t nbytes, struct prng_context *ctx,
18262306a36Sopenharmony_ci				int do_cont_test)
18362306a36Sopenharmony_ci{
18462306a36Sopenharmony_ci	unsigned char *ptr = buf;
18562306a36Sopenharmony_ci	unsigned int byte_count = (unsigned int)nbytes;
18662306a36Sopenharmony_ci	int err;
18762306a36Sopenharmony_ci
18862306a36Sopenharmony_ci
18962306a36Sopenharmony_ci	spin_lock_bh(&ctx->prng_lock);
19062306a36Sopenharmony_ci
19162306a36Sopenharmony_ci	err = -EINVAL;
19262306a36Sopenharmony_ci	if (ctx->flags & PRNG_NEED_RESET)
19362306a36Sopenharmony_ci		goto done;
19462306a36Sopenharmony_ci
19562306a36Sopenharmony_ci	/*
19662306a36Sopenharmony_ci	 * If the FIXED_SIZE flag is on, only return whole blocks of
19762306a36Sopenharmony_ci	 * pseudo random data
19862306a36Sopenharmony_ci	 */
19962306a36Sopenharmony_ci	err = -EINVAL;
20062306a36Sopenharmony_ci	if (ctx->flags & PRNG_FIXED_SIZE) {
20162306a36Sopenharmony_ci		if (nbytes < DEFAULT_BLK_SZ)
20262306a36Sopenharmony_ci			goto done;
20362306a36Sopenharmony_ci		byte_count = DEFAULT_BLK_SZ;
20462306a36Sopenharmony_ci	}
20562306a36Sopenharmony_ci
20662306a36Sopenharmony_ci	/*
20762306a36Sopenharmony_ci	 * Return 0 in case of success as mandated by the kernel
20862306a36Sopenharmony_ci	 * crypto API interface definition.
20962306a36Sopenharmony_ci	 */
21062306a36Sopenharmony_ci	err = 0;
21162306a36Sopenharmony_ci
21262306a36Sopenharmony_ci	dbgprint(KERN_CRIT "getting %d random bytes for context %p\n",
21362306a36Sopenharmony_ci		byte_count, ctx);
21462306a36Sopenharmony_ci
21562306a36Sopenharmony_ci
21662306a36Sopenharmony_ciremainder:
21762306a36Sopenharmony_ci	if (ctx->rand_data_valid == DEFAULT_BLK_SZ) {
21862306a36Sopenharmony_ci		if (_get_more_prng_bytes(ctx, do_cont_test) < 0) {
21962306a36Sopenharmony_ci			memset(buf, 0, nbytes);
22062306a36Sopenharmony_ci			err = -EINVAL;
22162306a36Sopenharmony_ci			goto done;
22262306a36Sopenharmony_ci		}
22362306a36Sopenharmony_ci	}
22462306a36Sopenharmony_ci
22562306a36Sopenharmony_ci	/*
22662306a36Sopenharmony_ci	 * Copy any data less than an entire block
22762306a36Sopenharmony_ci	 */
22862306a36Sopenharmony_ci	if (byte_count < DEFAULT_BLK_SZ) {
22962306a36Sopenharmony_ciempty_rbuf:
23062306a36Sopenharmony_ci		while (ctx->rand_data_valid < DEFAULT_BLK_SZ) {
23162306a36Sopenharmony_ci			*ptr = ctx->rand_data[ctx->rand_data_valid];
23262306a36Sopenharmony_ci			ptr++;
23362306a36Sopenharmony_ci			byte_count--;
23462306a36Sopenharmony_ci			ctx->rand_data_valid++;
23562306a36Sopenharmony_ci			if (byte_count == 0)
23662306a36Sopenharmony_ci				goto done;
23762306a36Sopenharmony_ci		}
23862306a36Sopenharmony_ci	}
23962306a36Sopenharmony_ci
24062306a36Sopenharmony_ci	/*
24162306a36Sopenharmony_ci	 * Now copy whole blocks
24262306a36Sopenharmony_ci	 */
24362306a36Sopenharmony_ci	for (; byte_count >= DEFAULT_BLK_SZ; byte_count -= DEFAULT_BLK_SZ) {
24462306a36Sopenharmony_ci		if (ctx->rand_data_valid == DEFAULT_BLK_SZ) {
24562306a36Sopenharmony_ci			if (_get_more_prng_bytes(ctx, do_cont_test) < 0) {
24662306a36Sopenharmony_ci				memset(buf, 0, nbytes);
24762306a36Sopenharmony_ci				err = -EINVAL;
24862306a36Sopenharmony_ci				goto done;
24962306a36Sopenharmony_ci			}
25062306a36Sopenharmony_ci		}
25162306a36Sopenharmony_ci		if (ctx->rand_data_valid > 0)
25262306a36Sopenharmony_ci			goto empty_rbuf;
25362306a36Sopenharmony_ci		memcpy(ptr, ctx->rand_data, DEFAULT_BLK_SZ);
25462306a36Sopenharmony_ci		ctx->rand_data_valid += DEFAULT_BLK_SZ;
25562306a36Sopenharmony_ci		ptr += DEFAULT_BLK_SZ;
25662306a36Sopenharmony_ci	}
25762306a36Sopenharmony_ci
25862306a36Sopenharmony_ci	/*
25962306a36Sopenharmony_ci	 * Now go back and get any remaining partial block
26062306a36Sopenharmony_ci	 */
26162306a36Sopenharmony_ci	if (byte_count)
26262306a36Sopenharmony_ci		goto remainder;
26362306a36Sopenharmony_ci
26462306a36Sopenharmony_cidone:
26562306a36Sopenharmony_ci	spin_unlock_bh(&ctx->prng_lock);
26662306a36Sopenharmony_ci	dbgprint(KERN_CRIT "returning %d from get_prng_bytes in context %p\n",
26762306a36Sopenharmony_ci		err, ctx);
26862306a36Sopenharmony_ci	return err;
26962306a36Sopenharmony_ci}
27062306a36Sopenharmony_ci
27162306a36Sopenharmony_cistatic void free_prng_context(struct prng_context *ctx)
27262306a36Sopenharmony_ci{
27362306a36Sopenharmony_ci	crypto_free_cipher(ctx->tfm);
27462306a36Sopenharmony_ci}
27562306a36Sopenharmony_ci
27662306a36Sopenharmony_cistatic int reset_prng_context(struct prng_context *ctx,
27762306a36Sopenharmony_ci			      const unsigned char *key, size_t klen,
27862306a36Sopenharmony_ci			      const unsigned char *V, const unsigned char *DT)
27962306a36Sopenharmony_ci{
28062306a36Sopenharmony_ci	int ret;
28162306a36Sopenharmony_ci	const unsigned char *prng_key;
28262306a36Sopenharmony_ci
28362306a36Sopenharmony_ci	spin_lock_bh(&ctx->prng_lock);
28462306a36Sopenharmony_ci	ctx->flags |= PRNG_NEED_RESET;
28562306a36Sopenharmony_ci
28662306a36Sopenharmony_ci	prng_key = (key != NULL) ? key : (unsigned char *)DEFAULT_PRNG_KEY;
28762306a36Sopenharmony_ci
28862306a36Sopenharmony_ci	if (!key)
28962306a36Sopenharmony_ci		klen = DEFAULT_PRNG_KSZ;
29062306a36Sopenharmony_ci
29162306a36Sopenharmony_ci	if (V)
29262306a36Sopenharmony_ci		memcpy(ctx->V, V, DEFAULT_BLK_SZ);
29362306a36Sopenharmony_ci	else
29462306a36Sopenharmony_ci		memcpy(ctx->V, DEFAULT_V_SEED, DEFAULT_BLK_SZ);
29562306a36Sopenharmony_ci
29662306a36Sopenharmony_ci	if (DT)
29762306a36Sopenharmony_ci		memcpy(ctx->DT, DT, DEFAULT_BLK_SZ);
29862306a36Sopenharmony_ci	else
29962306a36Sopenharmony_ci		memset(ctx->DT, 0, DEFAULT_BLK_SZ);
30062306a36Sopenharmony_ci
30162306a36Sopenharmony_ci	memset(ctx->rand_data, 0, DEFAULT_BLK_SZ);
30262306a36Sopenharmony_ci	memset(ctx->last_rand_data, 0, DEFAULT_BLK_SZ);
30362306a36Sopenharmony_ci
30462306a36Sopenharmony_ci	ctx->rand_data_valid = DEFAULT_BLK_SZ;
30562306a36Sopenharmony_ci
30662306a36Sopenharmony_ci	ret = crypto_cipher_setkey(ctx->tfm, prng_key, klen);
30762306a36Sopenharmony_ci	if (ret) {
30862306a36Sopenharmony_ci		dbgprint(KERN_CRIT "PRNG: setkey() failed flags=%x\n",
30962306a36Sopenharmony_ci			crypto_cipher_get_flags(ctx->tfm));
31062306a36Sopenharmony_ci		goto out;
31162306a36Sopenharmony_ci	}
31262306a36Sopenharmony_ci
31362306a36Sopenharmony_ci	ret = 0;
31462306a36Sopenharmony_ci	ctx->flags &= ~PRNG_NEED_RESET;
31562306a36Sopenharmony_ciout:
31662306a36Sopenharmony_ci	spin_unlock_bh(&ctx->prng_lock);
31762306a36Sopenharmony_ci	return ret;
31862306a36Sopenharmony_ci}
31962306a36Sopenharmony_ci
32062306a36Sopenharmony_cistatic int cprng_init(struct crypto_tfm *tfm)
32162306a36Sopenharmony_ci{
32262306a36Sopenharmony_ci	struct prng_context *ctx = crypto_tfm_ctx(tfm);
32362306a36Sopenharmony_ci
32462306a36Sopenharmony_ci	spin_lock_init(&ctx->prng_lock);
32562306a36Sopenharmony_ci	ctx->tfm = crypto_alloc_cipher("aes", 0, 0);
32662306a36Sopenharmony_ci	if (IS_ERR(ctx->tfm)) {
32762306a36Sopenharmony_ci		dbgprint(KERN_CRIT "Failed to alloc tfm for context %p\n",
32862306a36Sopenharmony_ci				ctx);
32962306a36Sopenharmony_ci		return PTR_ERR(ctx->tfm);
33062306a36Sopenharmony_ci	}
33162306a36Sopenharmony_ci
33262306a36Sopenharmony_ci	if (reset_prng_context(ctx, NULL, DEFAULT_PRNG_KSZ, NULL, NULL) < 0)
33362306a36Sopenharmony_ci		return -EINVAL;
33462306a36Sopenharmony_ci
33562306a36Sopenharmony_ci	/*
33662306a36Sopenharmony_ci	 * after allocation, we should always force the user to reset
33762306a36Sopenharmony_ci	 * so they don't inadvertently use the insecure default values
33862306a36Sopenharmony_ci	 * without specifying them intentially
33962306a36Sopenharmony_ci	 */
34062306a36Sopenharmony_ci	ctx->flags |= PRNG_NEED_RESET;
34162306a36Sopenharmony_ci	return 0;
34262306a36Sopenharmony_ci}
34362306a36Sopenharmony_ci
34462306a36Sopenharmony_cistatic void cprng_exit(struct crypto_tfm *tfm)
34562306a36Sopenharmony_ci{
34662306a36Sopenharmony_ci	free_prng_context(crypto_tfm_ctx(tfm));
34762306a36Sopenharmony_ci}
34862306a36Sopenharmony_ci
34962306a36Sopenharmony_cistatic int cprng_get_random(struct crypto_rng *tfm,
35062306a36Sopenharmony_ci			    const u8 *src, unsigned int slen,
35162306a36Sopenharmony_ci			    u8 *rdata, unsigned int dlen)
35262306a36Sopenharmony_ci{
35362306a36Sopenharmony_ci	struct prng_context *prng = crypto_rng_ctx(tfm);
35462306a36Sopenharmony_ci
35562306a36Sopenharmony_ci	return get_prng_bytes(rdata, dlen, prng, 0);
35662306a36Sopenharmony_ci}
35762306a36Sopenharmony_ci
35862306a36Sopenharmony_ci/*
35962306a36Sopenharmony_ci *  This is the cprng_registered reset method the seed value is
36062306a36Sopenharmony_ci *  interpreted as the tuple { V KEY DT}
36162306a36Sopenharmony_ci *  V and KEY are required during reset, and DT is optional, detected
36262306a36Sopenharmony_ci *  as being present by testing the length of the seed
36362306a36Sopenharmony_ci */
36462306a36Sopenharmony_cistatic int cprng_reset(struct crypto_rng *tfm,
36562306a36Sopenharmony_ci		       const u8 *seed, unsigned int slen)
36662306a36Sopenharmony_ci{
36762306a36Sopenharmony_ci	struct prng_context *prng = crypto_rng_ctx(tfm);
36862306a36Sopenharmony_ci	const u8 *key = seed + DEFAULT_BLK_SZ;
36962306a36Sopenharmony_ci	const u8 *dt = NULL;
37062306a36Sopenharmony_ci
37162306a36Sopenharmony_ci	if (slen < DEFAULT_PRNG_KSZ + DEFAULT_BLK_SZ)
37262306a36Sopenharmony_ci		return -EINVAL;
37362306a36Sopenharmony_ci
37462306a36Sopenharmony_ci	if (slen >= (2 * DEFAULT_BLK_SZ + DEFAULT_PRNG_KSZ))
37562306a36Sopenharmony_ci		dt = key + DEFAULT_PRNG_KSZ;
37662306a36Sopenharmony_ci
37762306a36Sopenharmony_ci	reset_prng_context(prng, key, DEFAULT_PRNG_KSZ, seed, dt);
37862306a36Sopenharmony_ci
37962306a36Sopenharmony_ci	if (prng->flags & PRNG_NEED_RESET)
38062306a36Sopenharmony_ci		return -EINVAL;
38162306a36Sopenharmony_ci	return 0;
38262306a36Sopenharmony_ci}
38362306a36Sopenharmony_ci
38462306a36Sopenharmony_ci#ifdef CONFIG_CRYPTO_FIPS
38562306a36Sopenharmony_cistatic int fips_cprng_get_random(struct crypto_rng *tfm,
38662306a36Sopenharmony_ci				 const u8 *src, unsigned int slen,
38762306a36Sopenharmony_ci				 u8 *rdata, unsigned int dlen)
38862306a36Sopenharmony_ci{
38962306a36Sopenharmony_ci	struct prng_context *prng = crypto_rng_ctx(tfm);
39062306a36Sopenharmony_ci
39162306a36Sopenharmony_ci	return get_prng_bytes(rdata, dlen, prng, 1);
39262306a36Sopenharmony_ci}
39362306a36Sopenharmony_ci
39462306a36Sopenharmony_cistatic int fips_cprng_reset(struct crypto_rng *tfm,
39562306a36Sopenharmony_ci			    const u8 *seed, unsigned int slen)
39662306a36Sopenharmony_ci{
39762306a36Sopenharmony_ci	u8 rdata[DEFAULT_BLK_SZ];
39862306a36Sopenharmony_ci	const u8 *key = seed + DEFAULT_BLK_SZ;
39962306a36Sopenharmony_ci	int rc;
40062306a36Sopenharmony_ci
40162306a36Sopenharmony_ci	struct prng_context *prng = crypto_rng_ctx(tfm);
40262306a36Sopenharmony_ci
40362306a36Sopenharmony_ci	if (slen < DEFAULT_PRNG_KSZ + DEFAULT_BLK_SZ)
40462306a36Sopenharmony_ci		return -EINVAL;
40562306a36Sopenharmony_ci
40662306a36Sopenharmony_ci	/* fips strictly requires seed != key */
40762306a36Sopenharmony_ci	if (!memcmp(seed, key, DEFAULT_PRNG_KSZ))
40862306a36Sopenharmony_ci		return -EINVAL;
40962306a36Sopenharmony_ci
41062306a36Sopenharmony_ci	rc = cprng_reset(tfm, seed, slen);
41162306a36Sopenharmony_ci
41262306a36Sopenharmony_ci	if (!rc)
41362306a36Sopenharmony_ci		goto out;
41462306a36Sopenharmony_ci
41562306a36Sopenharmony_ci	/* this primes our continuity test */
41662306a36Sopenharmony_ci	rc = get_prng_bytes(rdata, DEFAULT_BLK_SZ, prng, 0);
41762306a36Sopenharmony_ci	prng->rand_data_valid = DEFAULT_BLK_SZ;
41862306a36Sopenharmony_ci
41962306a36Sopenharmony_ciout:
42062306a36Sopenharmony_ci	return rc;
42162306a36Sopenharmony_ci}
42262306a36Sopenharmony_ci#endif
42362306a36Sopenharmony_ci
42462306a36Sopenharmony_cistatic struct rng_alg rng_algs[] = { {
42562306a36Sopenharmony_ci	.generate		= cprng_get_random,
42662306a36Sopenharmony_ci	.seed			= cprng_reset,
42762306a36Sopenharmony_ci	.seedsize		= DEFAULT_PRNG_KSZ + 2 * DEFAULT_BLK_SZ,
42862306a36Sopenharmony_ci	.base			=	{
42962306a36Sopenharmony_ci		.cra_name		= "stdrng",
43062306a36Sopenharmony_ci		.cra_driver_name	= "ansi_cprng",
43162306a36Sopenharmony_ci		.cra_priority		= 100,
43262306a36Sopenharmony_ci		.cra_ctxsize		= sizeof(struct prng_context),
43362306a36Sopenharmony_ci		.cra_module		= THIS_MODULE,
43462306a36Sopenharmony_ci		.cra_init		= cprng_init,
43562306a36Sopenharmony_ci		.cra_exit		= cprng_exit,
43662306a36Sopenharmony_ci	}
43762306a36Sopenharmony_ci#ifdef CONFIG_CRYPTO_FIPS
43862306a36Sopenharmony_ci}, {
43962306a36Sopenharmony_ci	.generate		= fips_cprng_get_random,
44062306a36Sopenharmony_ci	.seed			= fips_cprng_reset,
44162306a36Sopenharmony_ci	.seedsize		= DEFAULT_PRNG_KSZ + 2 * DEFAULT_BLK_SZ,
44262306a36Sopenharmony_ci	.base			=	{
44362306a36Sopenharmony_ci		.cra_name		= "fips(ansi_cprng)",
44462306a36Sopenharmony_ci		.cra_driver_name	= "fips_ansi_cprng",
44562306a36Sopenharmony_ci		.cra_priority		= 300,
44662306a36Sopenharmony_ci		.cra_ctxsize		= sizeof(struct prng_context),
44762306a36Sopenharmony_ci		.cra_module		= THIS_MODULE,
44862306a36Sopenharmony_ci		.cra_init		= cprng_init,
44962306a36Sopenharmony_ci		.cra_exit		= cprng_exit,
45062306a36Sopenharmony_ci	}
45162306a36Sopenharmony_ci#endif
45262306a36Sopenharmony_ci} };
45362306a36Sopenharmony_ci
45462306a36Sopenharmony_ci/* Module initalization */
45562306a36Sopenharmony_cistatic int __init prng_mod_init(void)
45662306a36Sopenharmony_ci{
45762306a36Sopenharmony_ci	return crypto_register_rngs(rng_algs, ARRAY_SIZE(rng_algs));
45862306a36Sopenharmony_ci}
45962306a36Sopenharmony_ci
46062306a36Sopenharmony_cistatic void __exit prng_mod_fini(void)
46162306a36Sopenharmony_ci{
46262306a36Sopenharmony_ci	crypto_unregister_rngs(rng_algs, ARRAY_SIZE(rng_algs));
46362306a36Sopenharmony_ci}
46462306a36Sopenharmony_ci
46562306a36Sopenharmony_ciMODULE_LICENSE("GPL");
46662306a36Sopenharmony_ciMODULE_DESCRIPTION("Software Pseudo Random Number Generator");
46762306a36Sopenharmony_ciMODULE_AUTHOR("Neil Horman <nhorman@tuxdriver.com>");
46862306a36Sopenharmony_cimodule_param(dbg, int, 0);
46962306a36Sopenharmony_ciMODULE_PARM_DESC(dbg, "Boolean to enable debugging (0/1 == off/on)");
47062306a36Sopenharmony_cisubsys_initcall(prng_mod_init);
47162306a36Sopenharmony_cimodule_exit(prng_mod_fini);
47262306a36Sopenharmony_ciMODULE_ALIAS_CRYPTO("stdrng");
47362306a36Sopenharmony_ciMODULE_ALIAS_CRYPTO("ansi_cprng");
47462306a36Sopenharmony_ciMODULE_IMPORT_NS(CRYPTO_INTERNAL);
475