Commit d34b1acb authored by Harald Freudenberger's avatar Harald Freudenberger Committed by Martin Schwidefsky

s390/prng: Adjust generation of entropy to produce real 256 bits.

The generate_entropy function used a sha256 for compacting
together 256 bits of entropy into 32 bytes hash. However, it
is questionable if a sha256 can really be used here, as
potential collisions may reduce the max entropy fitting into
a 32 byte hash value. So this batch introduces the use of
sha512 instead and the required buffer adjustments for the
calling functions.

Further more the working buffer for the generate_entropy
function has been widened from one page to two pages. So now
1024 stckf invocations are used to gather 256 bits of
entropy. This has been done to be on the save side if the
jitters of stckf values isn't as good as supposed.
Signed-off-by: default avatarHarald Freudenberger <freude@linux.vnet.ibm.com>
Signed-off-by: default avatarMartin Schwidefsky <schwidefsky@de.ibm.com>
parent a4f2779e
...@@ -110,22 +110,30 @@ static const u8 initial_parm_block[32] __initconst = { ...@@ -110,22 +110,30 @@ static const u8 initial_parm_block[32] __initconst = {
/*** helper functions ***/ /*** helper functions ***/
/*
* generate_entropy:
* This algorithm produces 64 bytes of entropy data based on 1024
* individual stckf() invocations assuming that each stckf() value
* contributes 0.25 bits of entropy. So the caller gets 256 bit
* entropy per 64 byte or 4 bits entropy per byte.
*/
static int generate_entropy(u8 *ebuf, size_t nbytes) static int generate_entropy(u8 *ebuf, size_t nbytes)
{ {
int n, ret = 0; int n, ret = 0;
u8 *pg, *h, hash[32]; u8 *pg, *h, hash[64];
pg = (u8 *) __get_free_page(GFP_KERNEL); /* allocate 2 pages */
pg = (u8 *) __get_free_pages(GFP_KERNEL, 1);
if (!pg) { if (!pg) {
prng_errorflag = PRNG_GEN_ENTROPY_FAILED; prng_errorflag = PRNG_GEN_ENTROPY_FAILED;
return -ENOMEM; return -ENOMEM;
} }
while (nbytes) { while (nbytes) {
/* fill page with urandom bytes */ /* fill pages with urandom bytes */
get_random_bytes(pg, PAGE_SIZE); get_random_bytes(pg, 2*PAGE_SIZE);
/* exor page with stckf values */ /* exor pages with 1024 stckf values */
for (n = 0; n < PAGE_SIZE / sizeof(u64); n++) { for (n = 0; n < 2 * PAGE_SIZE / sizeof(u64); n++) {
u64 *p = ((u64 *)pg) + n; u64 *p = ((u64 *)pg) + n;
*p ^= get_tod_clock_fast(); *p ^= get_tod_clock_fast();
} }
...@@ -134,8 +142,8 @@ static int generate_entropy(u8 *ebuf, size_t nbytes) ...@@ -134,8 +142,8 @@ static int generate_entropy(u8 *ebuf, size_t nbytes)
h = hash; h = hash;
else else
h = ebuf; h = ebuf;
/* generate sha256 from this page */ /* hash over the filled pages */
cpacf_kimd(CPACF_KIMD_SHA_256, h, pg, PAGE_SIZE); cpacf_kimd(CPACF_KIMD_SHA_512, h, pg, 2*PAGE_SIZE);
if (n < sizeof(hash)) if (n < sizeof(hash))
memcpy(ebuf, hash, n); memcpy(ebuf, hash, n);
ret += n; ret += n;
...@@ -143,7 +151,7 @@ static int generate_entropy(u8 *ebuf, size_t nbytes) ...@@ -143,7 +151,7 @@ static int generate_entropy(u8 *ebuf, size_t nbytes)
nbytes -= n; nbytes -= n;
} }
free_page((unsigned long)pg); free_pages((unsigned long)pg, 1);
return ret; return ret;
} }
...@@ -334,7 +342,7 @@ static int __init prng_sha512_selftest(void) ...@@ -334,7 +342,7 @@ static int __init prng_sha512_selftest(void)
static int __init prng_sha512_instantiate(void) static int __init prng_sha512_instantiate(void)
{ {
int ret, datalen; int ret, datalen;
u8 seed[64]; u8 seed[64 + 32 + 16];
pr_debug("prng runs in SHA-512 mode " pr_debug("prng runs in SHA-512 mode "
"with chunksize=%d and reseed_limit=%u\n", "with chunksize=%d and reseed_limit=%u\n",
...@@ -357,12 +365,12 @@ static int __init prng_sha512_instantiate(void) ...@@ -357,12 +365,12 @@ static int __init prng_sha512_instantiate(void)
if (ret) if (ret)
goto outfree; goto outfree;
/* generate initial seed bytestring, first 48 bytes of entropy */ /* generate initial seed bytestring, with 256 + 128 bits entropy */
ret = generate_entropy(seed, 48); ret = generate_entropy(seed, 64 + 32);
if (ret != 48) if (ret != 64 + 32)
goto outfree; goto outfree;
/* followed by 16 bytes of unique nonce */ /* followed by 16 bytes of unique nonce */
get_tod_clock_ext(seed + 48); get_tod_clock_ext(seed + 64 + 32);
/* initial seed of the ppno drng */ /* initial seed of the ppno drng */
cpacf_ppno(CPACF_PPNO_SHA512_DRNG_SEED, cpacf_ppno(CPACF_PPNO_SHA512_DRNG_SEED,
...@@ -395,9 +403,9 @@ static void prng_sha512_deinstantiate(void) ...@@ -395,9 +403,9 @@ static void prng_sha512_deinstantiate(void)
static int prng_sha512_reseed(void) static int prng_sha512_reseed(void)
{ {
int ret; int ret;
u8 seed[32]; u8 seed[64];
/* generate 32 bytes of fresh entropy */ /* fetch 256 bits of fresh entropy */
ret = generate_entropy(seed, sizeof(seed)); ret = generate_entropy(seed, sizeof(seed));
if (ret != sizeof(seed)) if (ret != sizeof(seed))
return ret; return ret;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment