Loading crypto/chacha20_generic.c +0 −61 Original line number Diff line number Diff line Loading @@ -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) { Loading drivers/char/random.c +276 −102 Original line number Diff line number Diff line Loading @@ -261,6 +261,7 @@ #include <linux/syscalls.h> #include <linux/completion.h> #include <linux/uuid.h> #include <crypto/chacha20.h> #include <asm/processor.h> #include <asm/uaccess.h> Loading Loading @@ -413,6 +414,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 Loading Loading @@ -442,10 +468,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], Loading @@ -466,16 +497,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 }; Loading Loading @@ -678,12 +699,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, Loading @@ -693,30 +708,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; } } Loading @@ -734,6 +746,152 @@ static void credit_entropy_bits_safe(struct entropy_store *r, int nbits) credit_entropy_bits(r, nbits); } /********************************************************************* * * 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 Loading @@ -750,12 +908,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) { Loading @@ -767,11 +925,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); Loading Loading @@ -802,7 +955,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)); /* Loading Loading @@ -918,11 +1071,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; Loading Loading @@ -966,9 +1129,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 Loading Loading @@ -1143,6 +1303,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. Loading @@ -1155,7 +1345,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; Loading @@ -1179,27 +1368,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); } /* Loading Loading @@ -1254,15 +1423,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); Loading @@ -1280,7 +1460,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; Loading @@ -1288,7 +1468,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; Loading Loading @@ -1352,7 +1532,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); Loading Loading @@ -1397,7 +1577,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); Loading Loading @@ -1459,22 +1639,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; } Loading Loading @@ -1520,10 +1700,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; Loading Loading @@ -1574,7 +1751,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: Loading Loading @@ -1616,11 +1792,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; } Loading Loading @@ -1856,18 +2031,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. 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() || 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); } Loading include/crypto/chacha20.h +1 −0 Original line number Diff line number Diff line Loading @@ -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); Loading lib/Makefile +1 −1 Original line number Diff line number Diff line Loading @@ -22,7 +22,7 @@ KCOV_INSTRUMENT_hweight.o := n 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 \ flex_proportions.o ratelimit.o show_mem.o \ is_single_threaded.o plist.o decompress.o kobject_uevent.o \ earlycpio.o seq_buf.o nmi_backtrace.o nodemask.o Loading lib/chacha20.c 0 → 100644 +79 −0 Original line number Diff line number Diff line /* * 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); Loading
crypto/chacha20_generic.c +0 −61 Original line number Diff line number Diff line Loading @@ -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) { Loading
drivers/char/random.c +276 −102 Original line number Diff line number Diff line Loading @@ -261,6 +261,7 @@ #include <linux/syscalls.h> #include <linux/completion.h> #include <linux/uuid.h> #include <crypto/chacha20.h> #include <asm/processor.h> #include <asm/uaccess.h> Loading Loading @@ -413,6 +414,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 Loading Loading @@ -442,10 +468,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], Loading @@ -466,16 +497,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 }; Loading Loading @@ -678,12 +699,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, Loading @@ -693,30 +708,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; } } Loading @@ -734,6 +746,152 @@ static void credit_entropy_bits_safe(struct entropy_store *r, int nbits) credit_entropy_bits(r, nbits); } /********************************************************************* * * 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 Loading @@ -750,12 +908,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) { Loading @@ -767,11 +925,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); Loading Loading @@ -802,7 +955,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)); /* Loading Loading @@ -918,11 +1071,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; Loading Loading @@ -966,9 +1129,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 Loading Loading @@ -1143,6 +1303,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. Loading @@ -1155,7 +1345,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; Loading @@ -1179,27 +1368,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); } /* Loading Loading @@ -1254,15 +1423,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); Loading @@ -1280,7 +1460,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; Loading @@ -1288,7 +1468,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; Loading Loading @@ -1352,7 +1532,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); Loading Loading @@ -1397,7 +1577,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); Loading Loading @@ -1459,22 +1639,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; } Loading Loading @@ -1520,10 +1700,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; Loading Loading @@ -1574,7 +1751,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: Loading Loading @@ -1616,11 +1792,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; } Loading Loading @@ -1856,18 +2031,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. 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() || 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); } Loading
include/crypto/chacha20.h +1 −0 Original line number Diff line number Diff line Loading @@ -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); Loading
lib/Makefile +1 −1 Original line number Diff line number Diff line Loading @@ -22,7 +22,7 @@ KCOV_INSTRUMENT_hweight.o := n 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 \ flex_proportions.o ratelimit.o show_mem.o \ is_single_threaded.o plist.o decompress.o kobject_uevent.o \ earlycpio.o seq_buf.o nmi_backtrace.o nodemask.o Loading
lib/chacha20.c 0 → 100644 +79 −0 Original line number Diff line number Diff line /* * 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);