123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801 |
- From af72f4e73aa5a951d998e88260154082c5ffd340 Mon Sep 17 00:00:00 2001
- From: Theodore Ts'o <tytso@mit.edu>
- Date: Sun, 12 Jun 2016 18:13:36 -0400
- Subject: [PATCH 19/32] random: replace non-blocking pool with a Chacha20-based
- CRNG
- The CRNG is faster, and we don't pretend to track entropy usage in the
- CRNG any more.
- Signed-off-by: Theodore Ts'o <tytso@mit.edu>
- ---
- crypto/chacha20_generic.c | 61 --------
- drivers/char/random.c | 378 +++++++++++++++++++++++++++++++++-------------
- include/crypto/chacha20.h | 1 +
- lib/Makefile | 2 +-
- lib/chacha20.c | 79 ++++++++++
- 5 files changed, 357 insertions(+), 164 deletions(-)
- create mode 100644 lib/chacha20.c
- diff --git a/crypto/chacha20_generic.c b/crypto/chacha20_generic.c
- index da9c89968223..1cab83146e33 100644
- --- a/crypto/chacha20_generic.c
- +++ b/crypto/chacha20_generic.c
- @@ -15,72 +15,11 @@
- #include <linux/module.h>
- #include <crypto/chacha20.h>
-
- -static inline u32 rotl32(u32 v, u8 n)
- -{
- - return (v << n) | (v >> (sizeof(v) * 8 - n));
- -}
- -
- static inline u32 le32_to_cpuvp(const void *p)
- {
- return le32_to_cpup(p);
- }
-
- -static void chacha20_block(u32 *state, void *stream)
- -{
- - u32 x[16], *out = stream;
- - int i;
- -
- - for (i = 0; i < ARRAY_SIZE(x); i++)
- - x[i] = state[i];
- -
- - for (i = 0; i < 20; i += 2) {
- - x[0] += x[4]; x[12] = rotl32(x[12] ^ x[0], 16);
- - x[1] += x[5]; x[13] = rotl32(x[13] ^ x[1], 16);
- - x[2] += x[6]; x[14] = rotl32(x[14] ^ x[2], 16);
- - x[3] += x[7]; x[15] = rotl32(x[15] ^ x[3], 16);
- -
- - x[8] += x[12]; x[4] = rotl32(x[4] ^ x[8], 12);
- - x[9] += x[13]; x[5] = rotl32(x[5] ^ x[9], 12);
- - x[10] += x[14]; x[6] = rotl32(x[6] ^ x[10], 12);
- - x[11] += x[15]; x[7] = rotl32(x[7] ^ x[11], 12);
- -
- - x[0] += x[4]; x[12] = rotl32(x[12] ^ x[0], 8);
- - x[1] += x[5]; x[13] = rotl32(x[13] ^ x[1], 8);
- - x[2] += x[6]; x[14] = rotl32(x[14] ^ x[2], 8);
- - x[3] += x[7]; x[15] = rotl32(x[15] ^ x[3], 8);
- -
- - x[8] += x[12]; x[4] = rotl32(x[4] ^ x[8], 7);
- - x[9] += x[13]; x[5] = rotl32(x[5] ^ x[9], 7);
- - x[10] += x[14]; x[6] = rotl32(x[6] ^ x[10], 7);
- - x[11] += x[15]; x[7] = rotl32(x[7] ^ x[11], 7);
- -
- - x[0] += x[5]; x[15] = rotl32(x[15] ^ x[0], 16);
- - x[1] += x[6]; x[12] = rotl32(x[12] ^ x[1], 16);
- - x[2] += x[7]; x[13] = rotl32(x[13] ^ x[2], 16);
- - x[3] += x[4]; x[14] = rotl32(x[14] ^ x[3], 16);
- -
- - x[10] += x[15]; x[5] = rotl32(x[5] ^ x[10], 12);
- - x[11] += x[12]; x[6] = rotl32(x[6] ^ x[11], 12);
- - x[8] += x[13]; x[7] = rotl32(x[7] ^ x[8], 12);
- - x[9] += x[14]; x[4] = rotl32(x[4] ^ x[9], 12);
- -
- - x[0] += x[5]; x[15] = rotl32(x[15] ^ x[0], 8);
- - x[1] += x[6]; x[12] = rotl32(x[12] ^ x[1], 8);
- - x[2] += x[7]; x[13] = rotl32(x[13] ^ x[2], 8);
- - x[3] += x[4]; x[14] = rotl32(x[14] ^ x[3], 8);
- -
- - x[10] += x[15]; x[5] = rotl32(x[5] ^ x[10], 7);
- - x[11] += x[12]; x[6] = rotl32(x[6] ^ x[11], 7);
- - x[8] += x[13]; x[7] = rotl32(x[7] ^ x[8], 7);
- - x[9] += x[14]; x[4] = rotl32(x[4] ^ x[9], 7);
- - }
- -
- - for (i = 0; i < ARRAY_SIZE(x); i++)
- - out[i] = cpu_to_le32(x[i] + state[i]);
- -
- - state[12]++;
- -}
- -
- static void chacha20_docrypt(u32 *state, u8 *dst, const u8 *src,
- unsigned int bytes)
- {
- diff --git a/drivers/char/random.c b/drivers/char/random.c
- index 2916d08ee30e..6d2abeae9434 100644
- --- a/drivers/char/random.c
- +++ b/drivers/char/random.c
- @@ -260,6 +260,7 @@
- #include <linux/irq.h>
- #include <linux/syscalls.h>
- #include <linux/completion.h>
- +#include <crypto/chacha20.h>
-
- #include <asm/processor.h>
- #include <asm/uaccess.h>
- @@ -412,6 +413,31 @@ static struct fasync_struct *fasync;
- static DEFINE_SPINLOCK(random_ready_list_lock);
- static LIST_HEAD(random_ready_list);
-
- +struct crng_state {
- + __u32 state[16];
- + unsigned long init_time;
- + spinlock_t lock;
- +};
- +
- +struct crng_state primary_crng = {
- + .lock = __SPIN_LOCK_UNLOCKED(primary_crng.lock),
- +};
- +
- +/*
- + * crng_init = 0 --> Uninitialized
- + * 1 --> Initialized
- + * 2 --> Initialized from input_pool
- + *
- + * crng_init is protected by primary_crng->lock, and only increases
- + * its value (from 0->1->2).
- + */
- +static int crng_init = 0;
- +#define crng_ready() (likely(crng_init > 0))
- +static int crng_init_cnt = 0;
- +#define CRNG_INIT_CNT_THRESH (2*CHACHA20_KEY_SIZE)
- +static void extract_crng(__u8 out[CHACHA20_BLOCK_SIZE]);
- +static void process_random_ready_list(void);
- +
- /**********************************************************************
- *
- * OS independent entropy store. Here are the functions which handle
- @@ -441,10 +467,15 @@ struct entropy_store {
- __u8 last_data[EXTRACT_SIZE];
- };
-
- +static ssize_t extract_entropy(struct entropy_store *r, void *buf,
- + size_t nbytes, int min, int rsvd);
- +static ssize_t _extract_entropy(struct entropy_store *r, void *buf,
- + size_t nbytes, int fips);
- +
- +static void crng_reseed(struct crng_state *crng, struct entropy_store *r);
- static void push_to_pool(struct work_struct *work);
- static __u32 input_pool_data[INPUT_POOL_WORDS];
- static __u32 blocking_pool_data[OUTPUT_POOL_WORDS];
- -static __u32 nonblocking_pool_data[OUTPUT_POOL_WORDS];
-
- static struct entropy_store input_pool = {
- .poolinfo = &poolinfo_table[0],
- @@ -465,16 +496,6 @@ static struct entropy_store blocking_pool = {
- push_to_pool),
- };
-
- -static struct entropy_store nonblocking_pool = {
- - .poolinfo = &poolinfo_table[1],
- - .name = "nonblocking",
- - .pull = &input_pool,
- - .lock = __SPIN_LOCK_UNLOCKED(nonblocking_pool.lock),
- - .pool = nonblocking_pool_data,
- - .push_work = __WORK_INITIALIZER(nonblocking_pool.push_work,
- - push_to_pool),
- -};
- -
- static __u32 const twist_table[8] = {
- 0x00000000, 0x3b6e20c8, 0x76dc4190, 0x4db26158,
- 0xedb88320, 0xd6d6a3e8, 0x9b64c2b0, 0xa00ae278 };
- @@ -677,12 +698,6 @@ retry:
- if (!r->initialized && r->entropy_total > 128) {
- r->initialized = 1;
- r->entropy_total = 0;
- - if (r == &nonblocking_pool) {
- - prandom_reseed_late();
- - process_random_ready_list();
- - wake_up_all(&urandom_init_wait);
- - pr_notice("random: %s pool is initialized\n", r->name);
- - }
- }
-
- trace_credit_entropy_bits(r->name, nbits,
- @@ -692,30 +707,27 @@ retry:
- if (r == &input_pool) {
- int entropy_bits = entropy_count >> ENTROPY_SHIFT;
-
- + if (crng_init < 2 && entropy_bits >= 128) {
- + crng_reseed(&primary_crng, r);
- + entropy_bits = r->entropy_count >> ENTROPY_SHIFT;
- + }
- +
- /* should we wake readers? */
- if (entropy_bits >= random_read_wakeup_bits) {
- wake_up_interruptible(&random_read_wait);
- kill_fasync(&fasync, SIGIO, POLL_IN);
- }
- /* If the input pool is getting full, send some
- - * entropy to the two output pools, flipping back and
- - * forth between them, until the output pools are 75%
- - * full.
- + * entropy to the blocking pool until it is 75% full.
- */
- if (entropy_bits > random_write_wakeup_bits &&
- r->initialized &&
- r->entropy_total >= 2*random_read_wakeup_bits) {
- - static struct entropy_store *last = &blocking_pool;
- struct entropy_store *other = &blocking_pool;
-
- - if (last == &blocking_pool)
- - other = &nonblocking_pool;
- if (other->entropy_count <=
- - 3 * other->poolinfo->poolfracbits / 4)
- - last = other;
- - if (last->entropy_count <=
- - 3 * last->poolinfo->poolfracbits / 4) {
- - schedule_work(&last->push_work);
- + 3 * other->poolinfo->poolfracbits / 4) {
- + schedule_work(&other->push_work);
- r->entropy_total = 0;
- }
- }
- @@ -736,6 +748,152 @@ static int credit_entropy_bits_safe(struct entropy_store *r, int nbits)
- return 0;
- }
-
- +/*********************************************************************
- + *
- + * CRNG using CHACHA20
- + *
- + *********************************************************************/
- +
- +#define CRNG_RESEED_INTERVAL (300*HZ)
- +
- +static DECLARE_WAIT_QUEUE_HEAD(crng_init_wait);
- +
- +static void crng_initialize(struct crng_state *crng)
- +{
- + int i;
- + unsigned long rv;
- +
- + memcpy(&crng->state[0], "expand 32-byte k", 16);
- + if (crng == &primary_crng)
- + _extract_entropy(&input_pool, &crng->state[4],
- + sizeof(__u32) * 12, 0);
- + else
- + get_random_bytes(&crng->state[4], sizeof(__u32) * 12);
- + for (i = 4; i < 16; i++) {
- + if (!arch_get_random_seed_long(&rv) &&
- + !arch_get_random_long(&rv))
- + rv = random_get_entropy();
- + crng->state[i] ^= rv;
- + }
- + crng->init_time = jiffies - CRNG_RESEED_INTERVAL - 1;
- +}
- +
- +static int crng_fast_load(const char *cp, size_t len)
- +{
- + unsigned long flags;
- + char *p;
- +
- + if (!spin_trylock_irqsave(&primary_crng.lock, flags))
- + return 0;
- + if (crng_ready()) {
- + spin_unlock_irqrestore(&primary_crng.lock, flags);
- + return 0;
- + }
- + p = (unsigned char *) &primary_crng.state[4];
- + while (len > 0 && crng_init_cnt < CRNG_INIT_CNT_THRESH) {
- + p[crng_init_cnt % CHACHA20_KEY_SIZE] ^= *cp;
- + cp++; crng_init_cnt++; len--;
- + }
- + if (crng_init_cnt >= CRNG_INIT_CNT_THRESH) {
- + crng_init = 1;
- + wake_up_interruptible(&crng_init_wait);
- + pr_notice("random: fast init done\n");
- + }
- + spin_unlock_irqrestore(&primary_crng.lock, flags);
- + return 1;
- +}
- +
- +static void crng_reseed(struct crng_state *crng, struct entropy_store *r)
- +{
- + unsigned long flags;
- + int i, num;
- + union {
- + __u8 block[CHACHA20_BLOCK_SIZE];
- + __u32 key[8];
- + } buf;
- +
- + if (r) {
- + num = extract_entropy(r, &buf, 32, 16, 0);
- + if (num == 0)
- + return;
- + } else
- + extract_crng(buf.block);
- + spin_lock_irqsave(&primary_crng.lock, flags);
- + for (i = 0; i < 8; i++) {
- + unsigned long rv;
- + if (!arch_get_random_seed_long(&rv) &&
- + !arch_get_random_long(&rv))
- + rv = random_get_entropy();
- + crng->state[i+4] ^= buf.key[i] ^ rv;
- + }
- + memzero_explicit(&buf, sizeof(buf));
- + crng->init_time = jiffies;
- + if (crng == &primary_crng && crng_init < 2) {
- + crng_init = 2;
- + process_random_ready_list();
- + wake_up_interruptible(&crng_init_wait);
- + pr_notice("random: crng init done\n");
- + }
- + spin_unlock_irqrestore(&primary_crng.lock, flags);
- +}
- +
- +static inline void crng_wait_ready(void)
- +{
- + wait_event_interruptible(crng_init_wait, crng_ready());
- +}
- +
- +static void extract_crng(__u8 out[CHACHA20_BLOCK_SIZE])
- +{
- + unsigned long v, flags;
- + struct crng_state *crng = &primary_crng;
- +
- + if (crng_init > 1 &&
- + time_after(jiffies, crng->init_time + CRNG_RESEED_INTERVAL))
- + crng_reseed(crng, &input_pool);
- + spin_lock_irqsave(&crng->lock, flags);
- + if (arch_get_random_long(&v))
- + crng->state[14] ^= v;
- + chacha20_block(&crng->state[0], out);
- + if (crng->state[12] == 0)
- + crng->state[13]++;
- + spin_unlock_irqrestore(&crng->lock, flags);
- +}
- +
- +static ssize_t extract_crng_user(void __user *buf, size_t nbytes)
- +{
- + ssize_t ret = 0, i;
- + __u8 tmp[CHACHA20_BLOCK_SIZE];
- + int large_request = (nbytes > 256);
- +
- + while (nbytes) {
- + if (large_request && need_resched()) {
- + if (signal_pending(current)) {
- + if (ret == 0)
- + ret = -ERESTARTSYS;
- + break;
- + }
- + schedule();
- + }
- +
- + extract_crng(tmp);
- + i = min_t(int, nbytes, CHACHA20_BLOCK_SIZE);
- + if (copy_to_user(buf, tmp, i)) {
- + ret = -EFAULT;
- + break;
- + }
- +
- + nbytes -= i;
- + buf += i;
- + ret += i;
- + }
- +
- + /* Wipe data just written to memory */
- + memzero_explicit(tmp, sizeof(tmp));
- +
- + return ret;
- +}
- +
- +
- /*********************************************************************
- *
- * Entropy input management
- @@ -752,12 +910,12 @@ struct timer_rand_state {
- #define INIT_TIMER_RAND_STATE { INITIAL_JIFFIES, };
-
- /*
- - * Add device- or boot-specific data to the input and nonblocking
- - * pools to help initialize them to unique values.
- + * Add device- or boot-specific data to the input pool to help
- + * initialize it.
- *
- - * None of this adds any entropy, it is meant to avoid the
- - * problem of the nonblocking pool having similar initial state
- - * across largely identical devices.
- + * None of this adds any entropy; it is meant to avoid the problem of
- + * the entropy pool having similar initial state across largely
- + * identical devices.
- */
- void add_device_randomness(const void *buf, unsigned int size)
- {
- @@ -769,11 +927,6 @@ void add_device_randomness(const void *buf, unsigned int size)
- _mix_pool_bytes(&input_pool, buf, size);
- _mix_pool_bytes(&input_pool, &time, sizeof(time));
- spin_unlock_irqrestore(&input_pool.lock, flags);
- -
- - spin_lock_irqsave(&nonblocking_pool.lock, flags);
- - _mix_pool_bytes(&nonblocking_pool, buf, size);
- - _mix_pool_bytes(&nonblocking_pool, &time, sizeof(time));
- - spin_unlock_irqrestore(&nonblocking_pool.lock, flags);
- }
- EXPORT_SYMBOL(add_device_randomness);
-
- @@ -804,7 +957,7 @@ static void add_timer_randomness(struct timer_rand_state *state, unsigned num)
- sample.jiffies = jiffies;
- sample.cycles = random_get_entropy();
- sample.num = num;
- - r = nonblocking_pool.initialized ? &input_pool : &nonblocking_pool;
- + r = &input_pool;
- mix_pool_bytes(r, &sample, sizeof(sample));
-
- /*
- @@ -924,11 +1077,21 @@ void add_interrupt_randomness(int irq, int irq_flags)
- fast_mix(fast_pool);
- add_interrupt_bench(cycles);
-
- + if (!crng_ready()) {
- + if ((fast_pool->count >= 64) &&
- + crng_fast_load((char *) fast_pool->pool,
- + sizeof(fast_pool->pool))) {
- + fast_pool->count = 0;
- + fast_pool->last = now;
- + }
- + return;
- + }
- +
- if ((fast_pool->count < 64) &&
- !time_after(now, fast_pool->last + HZ))
- return;
-
- - r = nonblocking_pool.initialized ? &input_pool : &nonblocking_pool;
- + r = &input_pool;
- if (!spin_trylock(&r->lock))
- return;
-
- @@ -972,9 +1135,6 @@ EXPORT_SYMBOL_GPL(add_disk_randomness);
- *
- *********************************************************************/
-
- -static ssize_t extract_entropy(struct entropy_store *r, void *buf,
- - size_t nbytes, int min, int rsvd);
- -
- /*
- * This utility inline function is responsible for transferring entropy
- * from the primary pool to the secondary extraction pool. We make
- @@ -1149,6 +1309,36 @@ static void extract_buf(struct entropy_store *r, __u8 *out)
- memzero_explicit(&hash, sizeof(hash));
- }
-
- +static ssize_t _extract_entropy(struct entropy_store *r, void *buf,
- + size_t nbytes, int fips)
- +{
- + ssize_t ret = 0, i;
- + __u8 tmp[EXTRACT_SIZE];
- + unsigned long flags;
- +
- + while (nbytes) {
- + extract_buf(r, tmp);
- +
- + if (fips) {
- + spin_lock_irqsave(&r->lock, flags);
- + if (!memcmp(tmp, r->last_data, EXTRACT_SIZE))
- + panic("Hardware RNG duplicated output!\n");
- + memcpy(r->last_data, tmp, EXTRACT_SIZE);
- + spin_unlock_irqrestore(&r->lock, flags);
- + }
- + i = min_t(int, nbytes, EXTRACT_SIZE);
- + memcpy(buf, tmp, i);
- + nbytes -= i;
- + buf += i;
- + ret += i;
- + }
- +
- + /* Wipe data just returned from memory */
- + memzero_explicit(tmp, sizeof(tmp));
- +
- + return ret;
- +}
- +
- /*
- * This function extracts randomness from the "entropy pool", and
- * returns it in a buffer.
- @@ -1161,7 +1351,6 @@ static void extract_buf(struct entropy_store *r, __u8 *out)
- static ssize_t extract_entropy(struct entropy_store *r, void *buf,
- size_t nbytes, int min, int reserved)
- {
- - ssize_t ret = 0, i;
- __u8 tmp[EXTRACT_SIZE];
- unsigned long flags;
-
- @@ -1185,27 +1374,7 @@ static ssize_t extract_entropy(struct entropy_store *r, void *buf,
- xfer_secondary_pool(r, nbytes);
- nbytes = account(r, nbytes, min, reserved);
-
- - while (nbytes) {
- - extract_buf(r, tmp);
- -
- - if (fips_enabled) {
- - spin_lock_irqsave(&r->lock, flags);
- - if (!memcmp(tmp, r->last_data, EXTRACT_SIZE))
- - panic("Hardware RNG duplicated output!\n");
- - memcpy(r->last_data, tmp, EXTRACT_SIZE);
- - spin_unlock_irqrestore(&r->lock, flags);
- - }
- - i = min_t(int, nbytes, EXTRACT_SIZE);
- - memcpy(buf, tmp, i);
- - nbytes -= i;
- - buf += i;
- - ret += i;
- - }
- -
- - /* Wipe data just returned from memory */
- - memzero_explicit(tmp, sizeof(tmp));
- -
- - return ret;
- + return _extract_entropy(r, buf, nbytes, fips_enabled);
- }
-
- /*
- @@ -1260,15 +1429,26 @@ static ssize_t extract_entropy_user(struct entropy_store *r, void __user *buf,
- */
- void get_random_bytes(void *buf, int nbytes)
- {
- + __u8 tmp[CHACHA20_BLOCK_SIZE];
- +
- #if DEBUG_RANDOM_BOOT > 0
- - if (unlikely(nonblocking_pool.initialized == 0))
- + if (!crng_ready())
- printk(KERN_NOTICE "random: %pF get_random_bytes called "
- - "with %d bits of entropy available\n",
- - (void *) _RET_IP_,
- - nonblocking_pool.entropy_total);
- + "with crng_init = %d\n", (void *) _RET_IP_, crng_init);
- #endif
- trace_get_random_bytes(nbytes, _RET_IP_);
- - extract_entropy(&nonblocking_pool, buf, nbytes, 0, 0);
- +
- + while (nbytes >= CHACHA20_BLOCK_SIZE) {
- + extract_crng(buf);
- + buf += CHACHA20_BLOCK_SIZE;
- + nbytes -= CHACHA20_BLOCK_SIZE;
- + }
- +
- + if (nbytes > 0) {
- + extract_crng(tmp);
- + memcpy(buf, tmp, nbytes);
- + memzero_explicit(tmp, nbytes);
- + }
- }
- EXPORT_SYMBOL(get_random_bytes);
-
- @@ -1286,7 +1466,7 @@ int add_random_ready_callback(struct random_ready_callback *rdy)
- unsigned long flags;
- int err = -EALREADY;
-
- - if (likely(nonblocking_pool.initialized))
- + if (crng_ready())
- return err;
-
- owner = rdy->owner;
- @@ -1294,7 +1474,7 @@ int add_random_ready_callback(struct random_ready_callback *rdy)
- return -ENOENT;
-
- spin_lock_irqsave(&random_ready_list_lock, flags);
- - if (nonblocking_pool.initialized)
- + if (crng_ready())
- goto out;
-
- owner = NULL;
- @@ -1358,7 +1538,7 @@ void get_random_bytes_arch(void *buf, int nbytes)
- }
-
- if (nbytes)
- - extract_entropy(&nonblocking_pool, p, nbytes, 0, 0);
- + get_random_bytes(p, nbytes);
- }
- EXPORT_SYMBOL(get_random_bytes_arch);
-
- @@ -1403,7 +1583,7 @@ static int rand_initialize(void)
- {
- init_std_data(&input_pool);
- init_std_data(&blocking_pool);
- - init_std_data(&nonblocking_pool);
- + crng_initialize(&primary_crng);
- return 0;
- }
- early_initcall(rand_initialize);
- @@ -1465,22 +1645,22 @@ random_read(struct file *file, char __user *buf, size_t nbytes, loff_t *ppos)
- static ssize_t
- urandom_read(struct file *file, char __user *buf, size_t nbytes, loff_t *ppos)
- {
- + unsigned long flags;
- static int maxwarn = 10;
- int ret;
-
- - if (unlikely(nonblocking_pool.initialized == 0) &&
- - maxwarn > 0) {
- + if (!crng_ready() && maxwarn > 0) {
- maxwarn--;
- printk(KERN_NOTICE "random: %s: uninitialized urandom read "
- - "(%zd bytes read, %d bits of entropy available)\n",
- - current->comm, nbytes, nonblocking_pool.entropy_total);
- + "(%zd bytes read)\n",
- + current->comm, nbytes);
- + spin_lock_irqsave(&primary_crng.lock, flags);
- + crng_init_cnt = 0;
- + spin_unlock_irqrestore(&primary_crng.lock, flags);
- }
- -
- nbytes = min_t(size_t, nbytes, INT_MAX >> (ENTROPY_SHIFT + 3));
- - ret = extract_entropy_user(&nonblocking_pool, buf, nbytes);
- -
- - trace_urandom_read(8 * nbytes, ENTROPY_BITS(&nonblocking_pool),
- - ENTROPY_BITS(&input_pool));
- + ret = extract_crng_user(buf, nbytes);
- + trace_urandom_read(8 * nbytes, 0, ENTROPY_BITS(&input_pool));
- return ret;
- }
-
- @@ -1534,10 +1714,7 @@ static ssize_t random_write(struct file *file, const char __user *buffer,
- {
- size_t ret;
-
- - ret = write_pool(&blocking_pool, buffer, count);
- - if (ret)
- - return ret;
- - ret = write_pool(&nonblocking_pool, buffer, count);
- + ret = write_pool(&input_pool, buffer, count);
- if (ret)
- return ret;
-
- @@ -1586,7 +1763,6 @@ static long random_ioctl(struct file *f, unsigned int cmd, unsigned long arg)
- if (!capable(CAP_SYS_ADMIN))
- return -EPERM;
- input_pool.entropy_count = 0;
- - nonblocking_pool.entropy_count = 0;
- blocking_pool.entropy_count = 0;
- return 0;
- default:
- @@ -1628,11 +1804,10 @@ SYSCALL_DEFINE3(getrandom, char __user *, buf, size_t, count,
- if (flags & GRND_RANDOM)
- return _random_read(flags & GRND_NONBLOCK, buf, count);
-
- - if (unlikely(nonblocking_pool.initialized == 0)) {
- + if (!crng_ready()) {
- if (flags & GRND_NONBLOCK)
- return -EAGAIN;
- - wait_event_interruptible(urandom_init_wait,
- - nonblocking_pool.initialized);
- + crng_wait_ready();
- if (signal_pending(current))
- return -ERESTARTSYS;
- }
- @@ -1888,18 +2063,17 @@ void add_hwgenerator_randomness(const char *buffer, size_t count,
- {
- struct entropy_store *poolp = &input_pool;
-
- - if (unlikely(nonblocking_pool.initialized == 0))
- - poolp = &nonblocking_pool;
- - else {
- - /* Suspend writing if we're above the trickle
- - * threshold. We'll be woken up again once below
- - * random_write_wakeup_thresh, or when the calling
- - * thread is about to terminate.
- - */
- - wait_event_interruptible(random_write_wait,
- - kthread_should_stop() ||
- - ENTROPY_BITS(&input_pool) <= random_write_wakeup_bits);
- + if (!crng_ready()) {
- + crng_fast_load(buffer, count);
- + return;
- }
- +
- + /* Suspend writing if we're above the trickle threshold.
- + * We'll be woken up again once below random_write_wakeup_thresh,
- + * or when the calling thread is about to terminate.
- + */
- + wait_event_interruptible(random_write_wait, kthread_should_stop() ||
- + ENTROPY_BITS(&input_pool) <= random_write_wakeup_bits);
- mix_pool_bytes(poolp, buffer, count);
- credit_entropy_bits(poolp, entropy);
- }
- diff --git a/include/crypto/chacha20.h b/include/crypto/chacha20.h
- index 274bbaeeed0f..20d20f681a72 100644
- --- a/include/crypto/chacha20.h
- +++ b/include/crypto/chacha20.h
- @@ -16,6 +16,7 @@ struct chacha20_ctx {
- u32 key[8];
- };
-
- +void chacha20_block(u32 *state, void *stream);
- void crypto_chacha20_init(u32 *state, struct chacha20_ctx *ctx, u8 *iv);
- int crypto_chacha20_setkey(struct crypto_tfm *tfm, const u8 *key,
- unsigned int keysize);
- diff --git a/lib/Makefile b/lib/Makefile
- index 34a7460c7005..c9ab674107ef 100644
- --- a/lib/Makefile
- +++ b/lib/Makefile
- @@ -10,7 +10,7 @@ endif
- lib-y := ctype.o string.o vsprintf.o cmdline.o \
- rbtree.o radix-tree.o dump_stack.o timerqueue.o\
- idr.o int_sqrt.o extable.o \
- - sha1.o md5.o irq_regs.o argv_split.o \
- + sha1.o chacha20.o md5.o irq_regs.o argv_split.o \
- proportions.o flex_proportions.o ratelimit.o show_mem.o \
- is_single_threaded.o plist.o decompress.o kobject_uevent.o \
- earlycpio.o seq_buf.o siphash.o nmi_backtrace.o
- diff --git a/lib/chacha20.c b/lib/chacha20.c
- new file mode 100644
- index 000000000000..250ceed9ec9a
- --- /dev/null
- +++ b/lib/chacha20.c
- @@ -0,0 +1,79 @@
- +/*
- + * ChaCha20 256-bit cipher algorithm, RFC7539
- + *
- + * Copyright (C) 2015 Martin Willi
- + *
- + * This program is free software; you can redistribute it and/or modify
- + * it under the terms of the GNU General Public License as published by
- + * the Free Software Foundation; either version 2 of the License, or
- + * (at your option) any later version.
- + */
- +
- +#include <linux/kernel.h>
- +#include <linux/export.h>
- +#include <linux/bitops.h>
- +#include <linux/cryptohash.h>
- +#include <asm/unaligned.h>
- +#include <crypto/chacha20.h>
- +
- +static inline u32 rotl32(u32 v, u8 n)
- +{
- + return (v << n) | (v >> (sizeof(v) * 8 - n));
- +}
- +
- +extern void chacha20_block(u32 *state, void *stream)
- +{
- + u32 x[16], *out = stream;
- + int i;
- +
- + for (i = 0; i < ARRAY_SIZE(x); i++)
- + x[i] = state[i];
- +
- + for (i = 0; i < 20; i += 2) {
- + x[0] += x[4]; x[12] = rotl32(x[12] ^ x[0], 16);
- + x[1] += x[5]; x[13] = rotl32(x[13] ^ x[1], 16);
- + x[2] += x[6]; x[14] = rotl32(x[14] ^ x[2], 16);
- + x[3] += x[7]; x[15] = rotl32(x[15] ^ x[3], 16);
- +
- + x[8] += x[12]; x[4] = rotl32(x[4] ^ x[8], 12);
- + x[9] += x[13]; x[5] = rotl32(x[5] ^ x[9], 12);
- + x[10] += x[14]; x[6] = rotl32(x[6] ^ x[10], 12);
- + x[11] += x[15]; x[7] = rotl32(x[7] ^ x[11], 12);
- +
- + x[0] += x[4]; x[12] = rotl32(x[12] ^ x[0], 8);
- + x[1] += x[5]; x[13] = rotl32(x[13] ^ x[1], 8);
- + x[2] += x[6]; x[14] = rotl32(x[14] ^ x[2], 8);
- + x[3] += x[7]; x[15] = rotl32(x[15] ^ x[3], 8);
- +
- + x[8] += x[12]; x[4] = rotl32(x[4] ^ x[8], 7);
- + x[9] += x[13]; x[5] = rotl32(x[5] ^ x[9], 7);
- + x[10] += x[14]; x[6] = rotl32(x[6] ^ x[10], 7);
- + x[11] += x[15]; x[7] = rotl32(x[7] ^ x[11], 7);
- +
- + x[0] += x[5]; x[15] = rotl32(x[15] ^ x[0], 16);
- + x[1] += x[6]; x[12] = rotl32(x[12] ^ x[1], 16);
- + x[2] += x[7]; x[13] = rotl32(x[13] ^ x[2], 16);
- + x[3] += x[4]; x[14] = rotl32(x[14] ^ x[3], 16);
- +
- + x[10] += x[15]; x[5] = rotl32(x[5] ^ x[10], 12);
- + x[11] += x[12]; x[6] = rotl32(x[6] ^ x[11], 12);
- + x[8] += x[13]; x[7] = rotl32(x[7] ^ x[8], 12);
- + x[9] += x[14]; x[4] = rotl32(x[4] ^ x[9], 12);
- +
- + x[0] += x[5]; x[15] = rotl32(x[15] ^ x[0], 8);
- + x[1] += x[6]; x[12] = rotl32(x[12] ^ x[1], 8);
- + x[2] += x[7]; x[13] = rotl32(x[13] ^ x[2], 8);
- + x[3] += x[4]; x[14] = rotl32(x[14] ^ x[3], 8);
- +
- + x[10] += x[15]; x[5] = rotl32(x[5] ^ x[10], 7);
- + x[11] += x[12]; x[6] = rotl32(x[6] ^ x[11], 7);
- + x[8] += x[13]; x[7] = rotl32(x[7] ^ x[8], 7);
- + x[9] += x[14]; x[4] = rotl32(x[4] ^ x[9], 7);
- + }
- +
- + for (i = 0; i < ARRAY_SIZE(x); i++)
- + out[i] = cpu_to_le32(x[i] + state[i]);
- +
- + state[12]++;
- +}
- +EXPORT_SYMBOL(chacha20_block);
- --
- 2.16.4
|