| From foo@baz Mon Nov 6 10:07:35 CET 2017 |
| From: Harald Freudenberger <freude@linux.vnet.ibm.com> |
| Date: Sat, 7 Oct 2017 22:36:57 +0000 |
| Subject: s390/prng: Adjust generation of entropy to produce real 256 bits. |
| |
| From: Harald Freudenberger <freude@linux.vnet.ibm.com> |
| |
| |
| [ Upstream commit d34b1acb78af41b8b8d5c60972b6555ea19f7564 ] |
| |
| 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: Harald Freudenberger <freude@linux.vnet.ibm.com> |
| Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com> |
| Signed-off-by: Sasha Levin <alexander.levin@verizon.com> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| --- |
| arch/s390/crypto/prng.c | 40 ++++++++++++++++++++++++---------------- |
| 1 file changed, 24 insertions(+), 16 deletions(-) |
| |
| --- a/arch/s390/crypto/prng.c |
| +++ b/arch/s390/crypto/prng.c |
| @@ -110,22 +110,30 @@ static const u8 initial_parm_block[32] _ |
| |
| /*** 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) |
| { |
| 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) { |
| prng_errorflag = PRNG_GEN_ENTROPY_FAILED; |
| return -ENOMEM; |
| } |
| |
| while (nbytes) { |
| - /* fill page with urandom bytes */ |
| - get_random_bytes(pg, PAGE_SIZE); |
| - /* exor page with stckf values */ |
| - for (n = 0; n < PAGE_SIZE / sizeof(u64); n++) { |
| + /* fill pages with urandom bytes */ |
| + get_random_bytes(pg, 2*PAGE_SIZE); |
| + /* exor pages with 1024 stckf values */ |
| + for (n = 0; n < 2 * PAGE_SIZE / sizeof(u64); n++) { |
| u64 *p = ((u64 *)pg) + n; |
| *p ^= get_tod_clock_fast(); |
| } |
| @@ -134,8 +142,8 @@ static int generate_entropy(u8 *ebuf, si |
| h = hash; |
| else |
| h = ebuf; |
| - /* generate sha256 from this page */ |
| - cpacf_kimd(CPACF_KIMD_SHA_256, h, pg, PAGE_SIZE); |
| + /* hash over the filled pages */ |
| + cpacf_kimd(CPACF_KIMD_SHA_512, h, pg, 2*PAGE_SIZE); |
| if (n < sizeof(hash)) |
| memcpy(ebuf, hash, n); |
| ret += n; |
| @@ -143,7 +151,7 @@ static int generate_entropy(u8 *ebuf, si |
| nbytes -= n; |
| } |
| |
| - free_page((unsigned long)pg); |
| + free_pages((unsigned long)pg, 1); |
| return ret; |
| } |
| |
| @@ -334,7 +342,7 @@ static int __init prng_sha512_selftest(v |
| static int __init prng_sha512_instantiate(void) |
| { |
| int ret, datalen; |
| - u8 seed[64]; |
| + u8 seed[64 + 32 + 16]; |
| |
| pr_debug("prng runs in SHA-512 mode " |
| "with chunksize=%d and reseed_limit=%u\n", |
| @@ -357,12 +365,12 @@ static int __init prng_sha512_instantiat |
| if (ret) |
| goto outfree; |
| |
| - /* generate initial seed bytestring, first 48 bytes of entropy */ |
| - ret = generate_entropy(seed, 48); |
| - if (ret != 48) |
| + /* generate initial seed bytestring, with 256 + 128 bits entropy */ |
| + ret = generate_entropy(seed, 64 + 32); |
| + if (ret != 64 + 32) |
| goto outfree; |
| /* 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 */ |
| cpacf_ppno(CPACF_PPNO_SHA512_DRNG_SEED, |
| @@ -395,9 +403,9 @@ static void prng_sha512_deinstantiate(vo |
| static int prng_sha512_reseed(void) |
| { |
| 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)); |
| if (ret != sizeof(seed)) |
| return ret; |