* [PATCH v6 3/5] crypto: Linux Random Number Generator
From: Stephan Mueller @ 2016-08-11 12:25 UTC (permalink / raw)
To: herbert
Cc: Ted Tso, sandyinchina, Jason Cooper, John Denker, H. Peter Anvin,
Joe Perches, Pavel Machek, George Spelvin, linux-crypto,
linux-kernel
In-Reply-To: <4723196.TTQvcXsLCG@positron.chronox.de>
The LRNG with the following properties:
* noise source: interrupts timing with fast boot time seeding
* lockless LFSR to collect raw entropy
* use of kernel crypto API DRBG
* in case kernel crypto API is not compiled, use standalone
ChaCha20 based RNG
* used cipher types for hashes and DRBG is selectable at
compile time
* "atomic" seeding of secondary DRBG to ensure full entropy
transport
* instantiate one DRBG per NUMA node
Further details including the rationale for the design choices and
properties of the LRNG together with testing is provided at [1].
In addition, the documentation explains the conducted regression
tests to verify that the LRNG is API and ABI compatible with the
legacy /dev/random implementation.
Signed-off-by: Stephan Mueller <smueller@chronox.de>
---
crypto/lrng_base.c | 1960 +++++++++++++++++++++++++++++++++++++++++++++++++++
crypto/lrng_kcapi.c | 167 +++++
2 files changed, 2127 insertions(+)
create mode 100644 crypto/lrng_base.c
create mode 100644 crypto/lrng_kcapi.c
diff --git a/crypto/lrng_base.c b/crypto/lrng_base.c
new file mode 100644
index 0000000..ab92298
--- /dev/null
+++ b/crypto/lrng_base.c
@@ -0,0 +1,1960 @@
+/*
+ * Linux Random Number Generator (LRNG)
+ *
+ * Documentation and test code: http://www.chronox.de/lrng.html
+ *
+ * Copyright (C) 2016, Stephan Mueller <smueller@chronox.de>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, and the entire permission notice in its entirety,
+ * including the disclaimer of warranties.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote
+ * products derived from this software without specific prior
+ * written permission.
+ *
+ * ALTERNATIVELY, this product may be distributed under the terms of
+ * the GNU General Public License, in which case the provisions of the GPL2
+ * are required INSTEAD OF the above restrictions. (This clause is
+ * necessary due to a potential bad interaction between the GPL and
+ * the restrictions contained in a BSD-style copyright.)
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ALL OF
+ * WHICH ARE HEREBY DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
+ * USE OF THIS SOFTWARE, EVEN IF NOT ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/timex.h>
+#include <linux/percpu.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/fs.h>
+#include <linux/spinlock.h>
+#include <linux/kthread.h>
+#include <linux/random.h>
+#include <linux/workqueue.h>
+#include <linux/poll.h>
+#include <linux/cryptohash.h>
+#include <linux/syscalls.h>
+#include <linux/uuid.h>
+#include <linux/fips.h>
+#include <linux/slab.h>
+
+/*
+ * Define a DRBG plus a hash / MAC used to extract data from the entropy pool.
+ * For LRNG_HASH_NAME you can use a hash or a MAC (HMAC or CMAC) of your choice
+ * (Note, you should use the suggested selections below -- using SHA-1 or MD5
+ * is not wise). The idea is that the used cipher primitive can be selected to
+ * be the same as used for the DRBG. I.e. the LRNG only uses one cipher
+ * primitive using the same cipher implementation with the options offered in
+ * the following. This means, if the CTR DRBG is selected and AES-NI is present,
+ * both the CTR DRBG and the selected cmac(aes) use AES-NI.
+ *
+ * The security strengths of the DRBGs are taken from SP800-57 section 5.6.1.
+ *
+ * This definition is allowed to be changed.
+ */
+#ifdef CONFIG_CRYPTO_DRBG_CTR
+# define LRNG_HASH_NAME "cmac(aes)"
+# if 0
+# define LRNG_DRBG_BLOCKLEN_BYTES 16
+# define LRNG_DRBG_SECURITY_STRENGTH_BYTES 16
+# define LRNG_DRBG_CORE "drbg_nopr_ctr_aes128" /* CTR DRBG AES-128 */
+# else
+# define LRNG_DRBG_BLOCKLEN_BYTES 16
+# define LRNG_DRBG_SECURITY_STRENGTH_BYTES 32
+# define LRNG_DRBG_CORE "drbg_nopr_ctr_aes256" /* CTR DRBG AES-256 */
+# endif
+#elif defined CONFIG_CRYPTO_DRBG_HMAC
+# if 0
+# define LRNG_DRBG_BLOCKLEN_BYTES 32
+# define LRNG_DRBG_SECURITY_STRENGTH_BYTES 16
+# define LRNG_DRBG_CORE "drbg_nopr_hmac_sha256" /* HMAC DRBG SHA-256 */
+# define LRNG_HASH_NAME "sha256"
+# else
+# define LRNG_DRBG_BLOCKLEN_BYTES 64
+# define LRNG_DRBG_SECURITY_STRENGTH_BYTES 32
+# define LRNG_DRBG_CORE "drbg_nopr_hmac_sha512" /* HMAC DRBG SHA-512 */
+# define LRNG_HASH_NAME "sha512"
+# endif
+#elif defined CONFIG_CRYPTO_DRBG_HASH
+# if 0
+# define LRNG_DRBG_BLOCKLEN_BYTES 32
+# define LRNG_DRBG_SECURITY_STRENGTH_BYTES 16
+# define LRNG_DRBG_CORE "drbg_nopr_sha256" /* Hash DRBG SHA-256 */
+# define LRNG_HASH_NAME "sha256"
+# else
+# define LRNG_DRBG_BLOCKLEN_BYTES 64
+# define LRNG_DRBG_SECURITY_STRENGTH_BYTES 32
+# define LRNG_DRBG_CORE "drbg_nopr_sha512" /* Hash DRBG SHA-512 */
+# define LRNG_HASH_NAME "sha512"
+# endif
+#else
+# define LRNG_DRBG_BLOCKLEN_BYTES 64
+# define LRNG_DRBG_SECURITY_STRENGTH_BYTES 32
+# define LRNG_DRBG_CORE "ChaCha20" /* ChaCha20 */
+# define LRNG_HASH_NAME "sha1"
+#endif
+
+#define LRNG_DRBG_SECURITY_STRENGTH_BITS (LRNG_DRBG_SECURITY_STRENGTH_BYTES * 8)
+
+/* Alignmask which should cover all cipher implementations */
+#define LRNG_KCAPI_ALIGN 8
+
+/* Primary DRBG state handle */
+struct lrng_pdrbg {
+ void *pdrbg; /* DRNG handle */
+ bool pdrbg_fully_seeded; /* Is DRBG fully seeded? */
+ bool pdrbg_min_seeded; /* Is DRBG minimally seeded? */
+ u32 pdrbg_entropy_bits; /* Is DRBG entropy level */
+ struct work_struct lrng_seed_work; /* (re)seed work queue */
+ spinlock_t lock;
+};
+
+/* Secondary DRBG state handle */
+struct lrng_sdrbg {
+ void *sdrbg; /* DRNG handle */
+ atomic_t requests; /* Number of DRBG requests */
+ unsigned long last_seeded; /* Last time it was seeded */
+ bool fully_seeded; /* Is DRBG fully seeded? */
+ spinlock_t lock;
+};
+
+/*
+ * SP800-90A defines a maximum request size of 1<<16 bytes. The given value is
+ * considered a safer margin. This applies to secondary DRBG.
+ *
+ * This value is allowed to be changed.
+ */
+#define LRNG_DRBG_MAX_REQSIZE (1<<12)
+
+/*
+ * SP800-90A defines a maximum number of requests between reseeds of 1<<48.
+ * The given value is considered a much safer margin, balancing requests for
+ * frequent reseeds with the need to conserve entropy. This value MUST NOT be
+ * larger than INT_MAX because it is used in an atomic_t. This applies to
+ * secondary DRBG.
+ *
+ * This value is allowed to be changed.
+ */
+#define LRNG_DRBG_RESEED_THRESH (1<<12)
+
+/* Status information about IRQ noise source */
+struct lrng_irq_info {
+ atomic_t num_events; /* Number of non-stuck IRQs since last read */
+ atomic_t num_events_thresh; /* Reseed threshold */
+ atomic_t last_time; /* Stuck test: time of previous IRQ */
+ atomic_t last_delta; /* Stuck test: delta of previous IRQ */
+ atomic_t last_delta2; /* Stuck test: 2. time derivation of prev IRQ */
+ atomic_t reseed_in_progress; /* Flag for on executing reseed */
+ atomic_t crngt_ctr; /* FIPS 140-2 CRNGT counter */
+ bool irq_highres_timer; /* Is high-resolution timer available? */
+ u32 irq_entropy_bits; /* LRNG_IRQ_ENTROPY_BITS? */
+};
+
+/*
+ * According to FIPS 140-2 IG 9.8, our C threshold is at 3 back to back stuck
+ * values. It should be highly unlikely that we see three consecutive
+ * identical time stamps.
+ *
+ * This value is allowed to be changed.
+ */
+#define LRNG_FIPS_CRNGT 3
+
+/*
+ * This is the entropy pool used by the slow noise source. Its size should
+ * be at least as large as the interrupt entropy estimate.
+ *
+ * The pool array is aligned to 8 bytes to comfort the kernel crypto API cipher
+ * implementations: for some accelerated implementations, we need an alignment
+ * to avoid a realignment which involes memcpy(). The alignment to 8 bytes
+ * should satisfy all crypto implementations.
+ *
+ * LRNG_POOL_SIZE is allowed to be changed only if the taps for the LFSR are
+ * changed as well. The size must be in powers of 2 due to the mask handling in
+ * lrng_pool_lfsr which uses AND instead of modulo.
+ *
+ * The polynomials for the LFSR are taken from the following URL
+ * which lists primitive polynomials
+ * http://courses.cse.tamu.edu/csce680/walker/lfsr_table.pdf. The first
+ * polynomial is from "Primitive Binary Polynomials" by Wayne Stahnke (1993)
+ * and is primitive as well as irreducible.
+ *
+ * Note, the tap values are smaller by one compared to the documentation because
+ * they are used as an index into an array where the index starts by zero.
+ *
+ * All polynomials were also checked to be primitive with magma.
+ */
+static u32 const lrng_lfsr_polynomial[] =
+ { 127, 28, 26, 1 }; /* 128 words by Stahnke */
+ /* { 255, 253, 250, 245 }; */ /* 256 words */
+ /* { 511, 509, 506, 503 }; */ /* 512 words */
+ /* { 1023, 1014, 1001, 1000 }; */ /* 1024 words */
+ /* { 2047, 2034, 2033, 2028 }; */ /* 2048 words */
+ /* { 4095, 4094, 4080, 4068 }; */ /* 4096 words */
+struct lrng_pool {
+#define LRNG_POOL_SIZE 128
+#define LRNG_POOL_WORD_BYTES (sizeof(atomic_t))
+#define LRNG_POOL_SIZE_BYTES (LRNG_POOL_SIZE * LRNG_POOL_WORD_BYTES)
+#define LRNG_POOL_SIZE_BITS (LRNG_POOL_SIZE_BYTES * 8)
+#define LRNG_POOL_WORD_BITS (LRNG_POOL_WORD_BYTES * 8)
+ atomic_t pool[LRNG_POOL_SIZE] __aligned(LRNG_KCAPI_ALIGN); /* Pool */
+ atomic_t pool_ptr; /* Ptr into pool for next IRQ word injection */
+ atomic_t input_rotate; /* rotate for LFSR */
+ u32 last_numa_node; /* Last NUMA node */
+ void *lrng_hash;
+ struct lrng_irq_info irq_info; /* IRQ noise source status info */
+};
+
+/*
+ * Number of interrupts to be recorded to assume that DRBG security strength
+ * bits of entropy are received.
+ * Note: a value below the DRBG security strength should not be defined as this
+ * may imply the DRBG can never be fully seeded in case other noise
+ * sources are unavailable.
+ *
+ * This value is allowed to be changed.
+ */
+#define LRNG_IRQ_ENTROPY_BYTES (LRNG_DRBG_SECURITY_STRENGTH_BYTES)
+#define LRNG_IRQ_ENTROPY_BITS (LRNG_IRQ_ENTROPY_BYTES * 8)
+
+/*
+ * Leave given amount of entropy in bits entropy pool to serve /dev/random while
+ * /dev/urandom is stressed.
+ *
+ * This value is allowed to be changed.
+ */
+#define LRNG_EMERG_ENTROPY (LRNG_DRBG_SECURITY_STRENGTH_BITS * 2)
+
+/*
+ * Min required seed entropy is 112 bits as per FIPS 140-2 and AIS20/31.
+ *
+ * This value is allowed to be changed.
+ */
+#define LRNG_MIN_SEED_ENTROPY_BITS 112
+
+#define LRNG_INIT_ENTROPY_BITS 32
+/*
+ * Oversampling factor of IRQ events to obtain
+ * LRNG_DRBG_SECURITY_STRENGTH_BYTES. This factor is used when a
+ * high-resolution time stamp is not available. In this case, jiffies and
+ * register contents are used to fill the entropy pool. These noise sources
+ * are much less entropic than the high-resolution timer. The entropy content
+ * is the entropy content assumed with LRNG_IRQ_ENTROPY_BYTES divided by
+ * LRNG_IRQ_OVERSAMPLING_FACTOR.
+ *
+ * This value is allowed to be changed.
+ */
+#define LRNG_IRQ_OVERSAMPLING_FACTOR 10
+
+static struct lrng_pdrbg lrng_pdrbg = {
+ .lock = __SPIN_LOCK_UNLOCKED(lrng.pdrbg.lock)
+};
+
+static struct lrng_sdrbg **lrng_sdrbg __read_mostly;
+
+static struct lrng_pool lrng_pool = {
+ .irq_info = {
+ .crngt_ctr = ATOMIC_INIT(LRNG_FIPS_CRNGT),
+ },
+};
+
+static LIST_HEAD(lrng_ready_list);
+static DEFINE_SPINLOCK(lrng_ready_list_lock);
+
+static atomic_t lrng_pdrbg_avail = ATOMIC_INIT(0);
+static atomic_t lrng_initrng_bytes = ATOMIC_INIT(0);
+static DEFINE_SPINLOCK(lrng_init_rng_lock); /* Lock the init RNG state */
+
+static DECLARE_WAIT_QUEUE_HEAD(lrng_read_wait);
+static DECLARE_WAIT_QUEUE_HEAD(lrng_write_wait);
+static DECLARE_WAIT_QUEUE_HEAD(lrng_pdrbg_init_wait);
+static struct fasync_struct *fasync;
+
+/*
+ * Estimated entropy of data is a 32th of LRNG_DRBG_SECURITY_STRENGTH_BITS.
+ * As we have no ability to review the implementation of those noise sources,
+ * it is prudent to have a conservative estimate here.
+ */
+static u32 archrandom = LRNG_DRBG_SECURITY_STRENGTH_BITS>>5;
+module_param(archrandom, uint, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
+MODULE_PARM_DESC(archrandom, "Entropy in bits of 256 data bits from CPU noise source (e.g. RDRAND)");
+
+/*
+ * If the entropy count falls under this number of bits, then we
+ * should wake up processes which are selecting or polling on write
+ * access to /dev/random.
+ */
+static u32 lrng_write_wakeup_bits = LRNG_DRBG_SECURITY_STRENGTH_BITS;
+
+/*
+ * The minimum number of bits of entropy before we wake up a read on
+ * /dev/random.
+ */
+static u32 lrng_read_wakeup_bits = LRNG_POOL_WORD_BITS * 2;
+
+/*
+ * Maximum number of seconds between DRBG reseed intervals of the secondary
+ * DRBG. Note, this is enforced with the next request of random numbers from
+ * the secondary DRBG. Setting this value to zero implies a reseeding attempt
+ * before every generated random number.
+ */
+static int lrng_sdrbg_reseed_max_time = 600;
+
+/************************** Crypto Implementations ***************************/
+
+/**
+ * Allocate DRNG -- the provided integers should be used for sanity checks.
+ * @return: allocated data structure or NULL on error
+ */
+void *lrng_drng_alloc(u8 *drng_name, u32 blocklen_bytes, u32 sec_strength);
+
+/* Deallocate DRNG */
+void lrng_drng_dealloc(void *drng);
+
+/**
+ * Seed the DRNG with data of arbitrary length
+ * @drng: is pointer to data structure allocated with lrng_drng_alloc
+ * @return: >= 0 on success, < 0 on error
+ */
+int lrng_drng_seed_helper(void *drng, const u8 *inbuf, u32 inbuflen);
+
+/**
+ * Generate random numbers from the DRNG with arbitrary length
+ * @return: generated number of bytes, < 0 on error
+ */
+int lrng_drng_generate_helper(void *drng, u8 *outbuf, u32 outbuflen);
+
+/**
+ * Allocate the hash for reading the entropy pool
+ * @return: allocated data structure (NULL is success too) or ERR_PTR on error
+ */
+void *lrng_hash_alloc(u8 *hashname, u8 *key, u32 keylen);
+
+/**
+ * Return the digestsize for the used hash to read out entropy pool
+ * @hash: is pointer to data structure allocated with lrng_hash_alloc
+ * @return: size of digest of hash in bytes
+ */
+u32 lrng_hash_digestsize(void *hash);
+
+/**
+ * Generate hash
+ * @hash: is pointer to data structure allocated with lrng_hash_alloc
+ * @return: 0 on success, < 0 on error
+ */
+int lrng_hash_buffer(void *hash, u8 *inbuf, u32 inbuflen, u8 *digest);
+
+/********************************** Helper ***********************************/
+
+static inline u32 atomic_read_u32(atomic_t *v)
+{
+ return (u32)atomic_read(v);
+}
+
+static inline u32 atomic_xchg_u32(atomic_t *v, u32 x)
+{
+ return (u32)atomic_xchg(v, x);
+}
+
+static inline u32 lrng_entropy_to_data(u32 entropy_bits)
+{
+ return ((entropy_bits * lrng_pool.irq_info.irq_entropy_bits) /
+ LRNG_DRBG_SECURITY_STRENGTH_BITS);
+}
+
+static inline u32 lrng_data_to_entropy(u32 irqnum)
+{
+ return ((irqnum * LRNG_DRBG_SECURITY_STRENGTH_BITS) /
+ lrng_pool.irq_info.irq_entropy_bits);
+}
+
+static inline u32 lrng_avail_entropy(void)
+{
+ return min_t(u32, LRNG_POOL_SIZE_BITS,
+ lrng_data_to_entropy(atomic_read_u32(
+ &lrng_pool.irq_info.num_events)));
+}
+
+static inline void lrng_set_entropy_thresh(u32 new)
+{
+ atomic_set(&lrng_pool.irq_info.num_events_thresh,
+ lrng_entropy_to_data(new));
+}
+
+/* Is the primary DRBG seed level too low? */
+static inline bool lrng_need_entropy(void)
+{
+ return (lrng_pdrbg.pdrbg_entropy_bits < lrng_write_wakeup_bits);
+}
+
+/* Is the entropy pool filled for /dev/random pull or DRBG fully seeded? */
+static inline bool lrng_have_entropy_full(void)
+{
+ return ((lrng_avail_entropy() >= lrng_read_wakeup_bits) ||
+ lrng_pdrbg.pdrbg_entropy_bits >=
+ LRNG_DRBG_SECURITY_STRENGTH_BITS);
+}
+
+/*********************** Fast soise source processing ************************/
+
+/**
+ * Get CPU noise source entropy
+ *
+ * @outbuf: buffer to store entropy of size LRNG_DRBG_SECURITY_STRENGTH_BYTES
+ * @return: > 0 on success where value provides the added entropy in bits
+ * 0 if no fast source was available
+ */
+static inline u32 lrng_get_arch(u8 *outbuf)
+{
+ u32 i;
+ u32 ent_bits = archrandom;
+
+ /* operate on full blocks */
+ BUILD_BUG_ON(LRNG_DRBG_SECURITY_STRENGTH_BYTES % sizeof(unsigned long));
+
+ if (!ent_bits)
+ return 0;
+
+ for (i = 0; i < LRNG_DRBG_SECURITY_STRENGTH_BYTES;
+ i += sizeof(unsigned long)) {
+ if (!arch_get_random_long((unsigned long *)(outbuf + i))) {
+ archrandom = 0;
+ return 0;
+ }
+ }
+
+ /* Obtain entropy statement -- cap entropy to buffer size in bits */
+ ent_bits = min_t(u32, ent_bits, LRNG_DRBG_SECURITY_STRENGTH_BITS);
+ pr_debug("obtained %u bits of entropy from CPU RNG noise source\n",
+ ent_bits);
+ return ent_bits;
+}
+
+/************************ Slow noise source processing ************************/
+
+/*
+ * Implement a (modified) twisted Generalized Feedback Shift Register. (See M.
+ * Matsumoto & Y. Kurita, 1992. Twisted GFSR generators. ACM Transactions on
+ * Modeling and Computer Simulation 2(3):179-194. Also see M. Matsumoto & Y.
+ * Kurita, 1994. Twisted GFSR generators II. ACM Transactions on Modeling and
+ * Computer Simulation 4:254-266).
+ */
+static u32 const lrng_twist_table[8] = {
+ 0x00000000, 0x3b6e20c8, 0x76dc4190, 0x4db26158,
+ 0xedb88320, 0xd6d6a3e8, 0x9b64c2b0, 0xa00ae278 };
+
+/**
+ * Hot code path - inject data into entropy pool using LFSR
+ */
+static void lrng_pool_lfsr(const u8 *buf, u32 buflen)
+{
+ u32 mask = (LRNG_POOL_SIZE - 1);
+
+ while (buflen--) {
+ u32 ptr = (u32)atomic_add_return(1, &lrng_pool.pool_ptr) & mask;
+ /*
+ * Add 7 bits of rotation to the pool. At the beginning of the
+ * pool, add an extra 7 bits rotation, so that successive passes
+ * spread the input bits across the pool evenly.
+ */
+ u32 input_rotate = (u32)atomic_add_return((ptr ? 7 : 14),
+ &lrng_pool.input_rotate) & 31;
+ u32 word = rol32(*buf++, input_rotate);
+
+ BUILD_BUG_ON(LRNG_POOL_SIZE - 1 != lrng_lfsr_polynomial[0]);
+ word ^= atomic_read_u32(&lrng_pool.pool[ptr]);
+ word ^= atomic_read_u32(&lrng_pool.pool[
+ (ptr + lrng_lfsr_polynomial[0]) & mask]);
+ word ^= atomic_read_u32(&lrng_pool.pool[
+ (ptr + lrng_lfsr_polynomial[1]) & mask]);
+ word ^= atomic_read_u32(&lrng_pool.pool[
+ (ptr + lrng_lfsr_polynomial[2]) & mask]);
+ word ^= atomic_read_u32(&lrng_pool.pool[
+ (ptr + lrng_lfsr_polynomial[3]) & mask]);
+
+ word = (word >> 3) ^ lrng_twist_table[word & 7];
+ atomic_set(&lrng_pool.pool[ptr], word);
+ }
+}
+
+/**
+ * Hot code path - Stuck test by checking the:
+ * 1st derivation of the event occurrence (time delta)
+ * 2nd derivation of the event occurrence (delta of time deltas)
+ * 3rd derivation of the event occurrence (delta of delta of time deltas)
+ *
+ * All values must always be non-zero. This is also the FIPS 140-2 CRNGT.
+ *
+ * @irq_info: Reference to IRQ information
+ * @now: Event time
+ * @return: 0 event occurrence not stuck (good bit)
+ * 1 event occurrence stuck (reject bit)
+ */
+static int lrng_irq_stuck(struct lrng_irq_info *irq_info, u32 now_time)
+{
+ u32 delta = now_time - atomic_xchg_u32(&irq_info->last_time, now_time);
+ int delta2 = delta - atomic_xchg_u32(&irq_info->last_delta, delta);
+ int delta3 = delta2 - atomic_xchg(&irq_info->last_delta2, delta2);
+
+#ifdef CONFIG_CRYPTO_FIPS
+ if (fips_enabled) {
+ if (!delta) {
+ if (atomic_dec_and_test(&irq_info->crngt_ctr))
+ panic("FIPS 140-2 continuous random number generator test failed\n");
+ } else
+ atomic_set(&irq_info->crngt_ctr, LRNG_FIPS_CRNGT);
+ }
+#endif
+
+ if (!delta || !delta2 || !delta3)
+ return 1;
+
+ return 0;
+}
+
+/**
+ * Hot code path - mix data into entropy pool
+ */
+static inline void lrng_pool_mixin(const u8 *buf, u32 buflen, u32 irq_num)
+{
+ lrng_pool_lfsr(buf, buflen);
+
+ /* Should we wake readers? */
+ if (irq_num == lrng_entropy_to_data(lrng_read_wakeup_bits)) {
+ wake_up_interruptible(&lrng_read_wait);
+ kill_fasync(&fasync, SIGIO, POLL_IN);
+ }
+
+ /* Only try to reseed if the DRBG is alive. */
+ if (!atomic_read(&lrng_pdrbg_avail))
+ return;
+
+ /*
+ * Once all secondary DRBGs are fully seeded, the interrupt noise
+ * sources will not trigger any reseeding any more.
+ */
+ if (lrng_sdrbg[lrng_pool.last_numa_node]->fully_seeded)
+ return;
+
+ /* Only trigger the DRBG reseed if we have collected enough IRQs. */
+ if (atomic_read_u32(&lrng_pool.irq_info.num_events) <
+ atomic_read_u32(&lrng_pool.irq_info.num_events_thresh))
+ return;
+
+ /* Ensure that the seeding only occurs once at any given time. */
+ if (atomic_cmpxchg(&lrng_pool.irq_info.reseed_in_progress, 0, 1))
+ return;
+
+ /* Seed the DRBG with IRQ noise. */
+ schedule_work(&lrng_pdrbg.lrng_seed_work);
+}
+
+/**
+ * Hot code path - Callback for interrupt handler
+ */
+void add_interrupt_randomness(int irq, int irq_flags)
+{
+ u32 now_time = random_get_entropy();
+ struct lrng_irq_info *irq_info = &lrng_pool.irq_info;
+ u32 irq_num = (u32)atomic_add_return(1, &irq_info->num_events);
+
+ if (lrng_pool.irq_info.irq_highres_timer) {
+ if (lrng_irq_stuck(irq_info, now_time))
+ return;
+ lrng_pool_mixin((u8 *)&now_time, sizeof(now_time), irq_num);
+ } else {
+ struct pt_regs *regs = get_irq_regs();
+ static atomic_t reg_idx = ATOMIC_INIT(0);
+
+ struct {
+ long jiffies;
+ int irq;
+ int irq_flags;
+ u64 ip;
+ u32 curr_reg;
+ } data;
+
+ data.jiffies = jiffies;
+ data.irq = irq;
+ data.irq_flags = irq_flags;
+ if (regs) {
+ u32 *ptr = (u32 *)regs;
+
+ data.ip = instruction_pointer(regs);
+ if (atomic_read(®_idx) >=
+ sizeof(struct pt_regs) / sizeof(u32))
+ atomic_set(®_idx, 0);
+ data.curr_reg = *(ptr + atomic_add_return(1, ®_idx));
+ }
+
+ lrng_pool_mixin((u8 *)&data, sizeof(data), irq_num);
+ }
+}
+EXPORT_SYMBOL(add_interrupt_randomness);
+
+/**
+ * Callback for HID layer
+ */
+void add_input_randomness(unsigned int type, unsigned int code,
+ unsigned int value)
+{
+ static unsigned char last_value;
+ unsigned int val;
+
+ /* ignore autorepeat and the like */
+ if (value == last_value)
+ return;
+
+ last_value = value;
+
+ val = (type << 4) ^ code ^ (code >> 4) ^ value;
+ lrng_pool_mixin((u8 *)&val, sizeof(val), 0);
+}
+EXPORT_SYMBOL_GPL(add_input_randomness);
+
+/**
+ * Read the entropy pool out for use. The caller must ensure this function
+ * is only called once at a time.
+ *
+ * This function handles the translation from the number of received interrupts
+ * into an entropy statement. The conversion depends on LRNG_IRQ_ENTROPY_BYTES
+ * which defines how many interrupts must be received to obtain 256 bits of
+ * entropy. With this value, the function lrng_data_to_entropy converts a given
+ * data size (received interrupts, requested amount of data, etc.) into an
+ * entropy statement. lrng_entropy_to_data does the reverse.
+ *
+ * Both functions are agnostic about the type of data: when the number of
+ * interrupts is processed by these functions, the resulting entropy value is in
+ * bits as we assume the entropy of interrupts is measured in bits. When data is
+ * processed, the entropy value is in bytes as the data is measured in bytes.
+ *
+ * @outbuf: buffer to store data in with size LRNG_DRBG_SECURITY_STRENGTH_BYTES
+ * @requested_entropy_bits: requested bits of entropy -- the function will
+ * return at least this amount of entropy if available
+ * @drain: boolean indicating that that all entropy of pool can be used
+ * (otherwise some emergency amount of entropy is left)
+ * @return: estimated entropy from the IRQs that went into the pool since last
+ * readout.
+ */
+static u32 lrng_get_pool(u8 *outbuf, u32 requested_entropy_bits, bool drain)
+{
+ u32 i, avail_entropy_bytes, irq_num_events_used, irq_num_event_back;
+ /* How many unused interrupts are in entropy pool? */
+ u32 irq_num_events = atomic_xchg_u32(&lrng_pool.irq_info.num_events, 0);
+ /* Convert available interrupts into entropy statement */
+ u32 avail_entropy_bits = lrng_data_to_entropy(irq_num_events);
+ u32 digestsize = lrng_hash_digestsize(lrng_pool.lrng_hash);
+ u8 digest[digestsize] __aligned(LRNG_KCAPI_ALIGN);
+
+ /* Cap available entropy to pool size */
+ avail_entropy_bits =
+ min_t(u32, avail_entropy_bits, LRNG_POOL_SIZE_BITS);
+
+ /* How much entropy we need to and can we use? */
+ if (drain)
+ avail_entropy_bits = min_t(u32, avail_entropy_bits,
+ requested_entropy_bits);
+ else
+ avail_entropy_bits = min_t(u32, (avail_entropy_bits -
+ min_t(u32, LRNG_EMERG_ENTROPY, avail_entropy_bits)),
+ requested_entropy_bits);
+
+ /* Hash is a compression function: we generate entropy amount of data */
+ avail_entropy_bits = round_down(avail_entropy_bits, 8);
+ avail_entropy_bytes = avail_entropy_bits >> 3;
+ BUG_ON(avail_entropy_bytes > LRNG_DRBG_SECURITY_STRENGTH_BYTES);
+
+ /* Hash the entire entropy pool */
+ for (i = 0;
+ i < LRNG_DRBG_SECURITY_STRENGTH_BYTES && avail_entropy_bytes > 0;
+ i += digestsize) {
+ u32 tocopy = min3(avail_entropy_bytes, digestsize,
+ (LRNG_DRBG_SECURITY_STRENGTH_BYTES - i));
+
+ if (lrng_hash_buffer(lrng_pool.lrng_hash, (u8 *)lrng_pool.pool,
+ LRNG_POOL_SIZE_BYTES, digest))
+ return 0;
+
+ /* Mix read data back into pool for backtracking resistance */
+ lrng_pool_lfsr(digest, digestsize);
+ /* Copy the data out to the caller */
+ memcpy(outbuf + i, digest, tocopy);
+ avail_entropy_bytes -= tocopy;
+ }
+ memzero_explicit(digest, digestsize);
+
+ /* There may be new events that came in while we processed this logic */
+ irq_num_events += atomic_xchg_u32(&lrng_pool.irq_info.num_events, 0);
+ /* Convert used entropy into interrupt number for subtraction */
+ irq_num_events_used = lrng_entropy_to_data(avail_entropy_bits);
+ /* Cap the number of events we say we have left to not reuse events */
+ irq_num_event_back = min_t(u32, irq_num_events - irq_num_events_used,
+ lrng_entropy_to_data(LRNG_POOL_SIZE_BITS) -
+ irq_num_events_used);
+ /* Add the unused interrupt number back to the state variable */
+ atomic_add(irq_num_event_back, &lrng_pool.irq_info.num_events);
+
+ /* Obtain entropy statement in bits from the used entropy */
+ pr_debug("obtained %u bits of entropy from %u newly collected interrupts - not using %u interrupts\n",
+ avail_entropy_bits, irq_num_events_used, irq_num_event_back);
+
+ return avail_entropy_bits;
+}
+
+/****************************** DRBG processing *******************************/
+
+/**
+ * Ping all kernel internal callers waiting until the DRBG is fully
+ * seeded that the DRBG is now fully seeded.
+ */
+static void lrng_process_ready_list(void)
+{
+ unsigned long flags;
+ struct random_ready_callback *rdy, *tmp;
+
+ spin_lock_irqsave(&lrng_ready_list_lock, flags);
+ list_for_each_entry_safe(rdy, tmp, &lrng_ready_list, list) {
+ struct module *owner = rdy->owner;
+
+ list_del_init(&rdy->list);
+ rdy->func(rdy);
+ module_put(owner);
+ }
+ spin_unlock_irqrestore(&lrng_ready_list_lock, flags);
+}
+
+/**
+ * Set the slow noise source reseed trigger threshold. The initial threshold
+ * is set to the minimum data size that can be read from the pool: a word. Upon
+ * reaching this value, the next seed threshold of 112 bits is set followed
+ * by 256 bits.
+ *
+ * @entropy_bits: size of entropy currently injected into DRBG
+ */
+static void lrng_pdrbg_init_ops(u32 entropy_bits)
+{
+ if (lrng_pdrbg.pdrbg_fully_seeded)
+ return;
+
+ /* DRBG is seeded with full security strength */
+ if (entropy_bits >= LRNG_DRBG_SECURITY_STRENGTH_BITS) {
+ lrng_pdrbg.pdrbg_fully_seeded = true;
+ lrng_pdrbg.pdrbg_min_seeded = true;
+ pr_info("primary DRBG fully seeded with %u bits of entropy\n",
+ entropy_bits);
+ lrng_process_ready_list();
+ wake_up_all(&lrng_pdrbg_init_wait);
+
+ } else if (!lrng_pdrbg.pdrbg_min_seeded) {
+
+ /* DRBG is seeded with at least 112 bits of entropy */
+ if (entropy_bits >= LRNG_MIN_SEED_ENTROPY_BITS) {
+ lrng_pdrbg.pdrbg_min_seeded = true;
+ pr_info("primary DRBG minimally seeded with %u bits of entropy\n",
+ entropy_bits);
+ lrng_set_entropy_thresh(
+ LRNG_DRBG_SECURITY_STRENGTH_BITS);
+
+ /* DRBG is seeded with at least LRNG_INIT_ENTROPY_BITS bits */
+ } else if (entropy_bits >= LRNG_INIT_ENTROPY_BITS) {
+ pr_info("primary DRBG initially seeded with %u bits of entropy\n",
+ entropy_bits);
+ lrng_set_entropy_thresh(LRNG_MIN_SEED_ENTROPY_BITS);
+ }
+ }
+}
+
+/* Caller must hold lrng_pdrbg.lock */
+static int lrng_pdrbg_generate(u8 *outbuf, u32 outbuflen, bool fullentropy)
+{
+ int ret;
+
+ /* /dev/random only works from a fully seeded DRBG */
+ if (fullentropy && !lrng_pdrbg.pdrbg_fully_seeded)
+ return 0;
+
+ /*
+ * Only deliver as many bytes as the DRBG is seeded with except during
+ * initialization to provide a first seed to the secondary DRBG.
+ */
+ if (lrng_pdrbg.pdrbg_min_seeded)
+ outbuflen = min_t(u32, outbuflen,
+ lrng_pdrbg.pdrbg_entropy_bits>>3);
+ else
+ outbuflen = min_t(u32, outbuflen,
+ LRNG_MIN_SEED_ENTROPY_BITS>>3);
+
+ ret = lrng_drng_generate_helper(lrng_pdrbg.pdrbg, outbuf, outbuflen);
+ if (ret != outbuflen) {
+ pr_warn("getting random data from primary DRBG failed (%d)\n",
+ ret);
+ return ret;
+ }
+
+ if (lrng_pdrbg.pdrbg_entropy_bits > (u32)(ret<<3))
+ lrng_pdrbg.pdrbg_entropy_bits -= ret<<3;
+ else
+ lrng_pdrbg.pdrbg_entropy_bits = 0;
+ pr_debug("obtained %d bytes of random data from primary DRBG\n", ret);
+ pr_debug("primary DRBG entropy level at %u bits\n",
+ lrng_pdrbg.pdrbg_entropy_bits);
+
+ return ret;
+}
+
+/**
+ * Inject data into the primary DRBG with a given entropy value. The function
+ * calls the DRBG's update function. This function also generates random data
+ * if requested by caller. The caller is only returned the amount of random
+ * data that is at most equal to the amount of entropy that just seeded the
+ * DRBG.
+ *
+ * Note, this function seeds the primary DRBG and generates data from it
+ * in an atomic operation.
+ *
+ * @inbuf: buffer to inject
+ * @inbuflen: length of inbuf
+ * @entropy_bits: entropy value of the data in inbuf in bits
+ * @outbuf: buffer to fill immediately after seeding to get full entropy
+ * @outbuflen: length of outbuf
+ * @fullentropy: start /dev/random output only after the DRBG was fully seeded
+ * @return: number of bytes written to outbuf, 0 if outbuf is not supplied,
+ * or < 0 in case of error
+ */
+static int lrng_pdrbg_inject(const u8 *inbuf, u32 inbuflen, u32 entropy_bits,
+ u8 *outbuf, u32 outbuflen, bool fullentropy)
+{
+ int ret;
+ unsigned long flags;
+
+ /* cap the maximum entropy value to the provided data length */
+ entropy_bits = min_t(u32, entropy_bits, inbuflen<<3);
+
+ spin_lock_irqsave(&lrng_pdrbg.lock, flags);
+ ret = lrng_drng_seed_helper(lrng_pdrbg.pdrbg, inbuf, inbuflen);
+ if (ret < 0) {
+ pr_warn("(re)seeding of primary DRBG failed\n");
+ goto unlock;
+ }
+ pr_debug("inject %u bytes with %u bits of entropy into primary DRBG\n",
+ inbuflen, entropy_bits);
+
+ /* Adjust the fill level indicator to at most the DRBG sec strength */
+ lrng_pdrbg.pdrbg_entropy_bits =
+ min_t(u32, lrng_pdrbg.pdrbg_entropy_bits + entropy_bits,
+ LRNG_DRBG_SECURITY_STRENGTH_BITS);
+ lrng_pdrbg_init_ops(lrng_pdrbg.pdrbg_entropy_bits);
+
+ if (outbuf && outbuflen)
+ ret = lrng_pdrbg_generate(outbuf, outbuflen, fullentropy);
+
+unlock:
+ spin_unlock_irqrestore(&lrng_pdrbg.lock, flags);
+
+ if (lrng_have_entropy_full()) {
+ /* Wake readers */
+ wake_up_interruptible(&lrng_read_wait);
+ kill_fasync(&fasync, SIGIO, POLL_IN);
+ }
+
+ return ret;
+}
+
+/**
+ * Seed the DRBG from the internal noise sources.
+ */
+static int lrng_pdrbg_seed_internal(u8 *outbuf, u32 outbuflen, bool fullentropy,
+ bool drain)
+{
+ u32 total_entropy_bits, now;
+ u8 entropy_buf[(LRNG_DRBG_SECURITY_STRENGTH_BYTES * 2) + sizeof(now)]
+ __aligned(LRNG_KCAPI_ALIGN);
+ int ret;
+
+ /* No reseeding if sufficient entropy in primary DRBG */
+ if (lrng_pdrbg.pdrbg_entropy_bits >= outbuflen<<3) {
+ unsigned long flags;
+
+ spin_lock_irqsave(&lrng_pdrbg.lock, flags);
+ ret = lrng_pdrbg_generate(outbuf, outbuflen, fullentropy);
+ spin_unlock_irqrestore(&lrng_pdrbg.lock, flags);
+ if (ret == outbuflen)
+ goto out;
+ }
+
+ /*
+ * drain the pool completely during init and when /dev/random calls.
+ *
+ * lrng_get_pool must be guaranteed to be called with multiples of 8
+ * (bits) of entropy as it can only operate byte-wise.
+ */
+ total_entropy_bits = lrng_get_pool(entropy_buf,
+ LRNG_DRBG_SECURITY_STRENGTH_BITS,
+ drain);
+
+ /*
+ * Prevent domination of fast noise sources over slow noise sources
+ * in case /dev/random calls. Only when the slow noise sources have
+ * some entropy, pull from the fast noise sources and inject all
+ * into the DRBG.
+ */
+ if (!total_entropy_bits && drain) {
+ ret = 0;
+ goto memzero;
+ }
+
+ /*
+ * Concatenate the output of the noise sources. This would be the
+ * spot to add an entropy extractor logic if desired. Note, this
+ * entirety should have the ability to collect entropy equal or larger
+ * than the DRBG strength to be able to feed /dev/random.
+ */
+ total_entropy_bits += lrng_get_arch(entropy_buf +
+ LRNG_DRBG_SECURITY_STRENGTH_BYTES);
+
+ pr_debug("reseed primary DRBG from internal noise sources with %u bits of entropy\n",
+ total_entropy_bits);
+
+ /* also reseed the DRBG with the current time stamp */
+ now = random_get_entropy();
+ memcpy(entropy_buf + (LRNG_DRBG_SECURITY_STRENGTH_BYTES * 2), &now,
+ sizeof(now));
+
+ ret = lrng_pdrbg_inject(entropy_buf, sizeof(entropy_buf),
+ total_entropy_bits,
+ outbuf, outbuflen, fullentropy);
+
+memzero:
+ memzero_explicit(entropy_buf, sizeof(entropy_buf));
+
+ /*
+ * Shall we wake up user space writers? This location covers
+ * /dev/urandom as well, but also ensures that the user space provider
+ * does not dominate the internal noise sources since in case the
+ * first call of this function finds sufficient entropy in the primary
+ * DRBG, it will not trigger the wakeup. This implies that when the next
+ * /dev/urandom read happens, the primary DRBG is drained and the
+ * internal noise sources are asked to feed the primary DRBG.
+ */
+ if (lrng_need_entropy()) {
+ wake_up_interruptible(&lrng_write_wait);
+ kill_fasync(&fasync, SIGIO, POLL_OUT);
+ }
+
+out:
+ /* Allow the seeding operation to be called again */
+ atomic_set(&lrng_pool.irq_info.reseed_in_progress, 0);
+
+ return ret;
+}
+
+/**
+ * Inject a data buffer into the secondary DRBG
+ *
+ * @sdrbg: reference to secondary DRBG
+ * @inbuf: buffer with data to inject
+ * @inbuflen: buffer length
+ * @internal: did random data originate from internal sources? Update the
+ * reseed threshold and the reseed timer when seeded with entropic
+ * data from noise sources to prevent unprivileged users from
+ * stopping reseeding the secondary DRBG with entropic data.
+ */
+static void lrng_sdrbg_inject(struct lrng_sdrbg *sdrbg,
+ u8 *inbuf, u32 inbuflen, bool internal)
+{
+ unsigned long flags;
+
+ BUILD_BUG_ON(LRNG_DRBG_RESEED_THRESH > INT_MAX);
+ pr_debug("seeding secondary DRBG with %u bytes\n", inbuflen);
+ spin_lock_irqsave(&sdrbg->lock, flags);
+ if (lrng_drng_seed_helper(sdrbg->sdrbg, inbuf, inbuflen) < 0) {
+ pr_warn("seeding of secondary DRBG failed\n");
+ atomic_set(&sdrbg->requests, 1);
+ } else if (internal) {
+ pr_debug("secondary DRBG stats since last seeding: %lu secs; generate calls: %d\n",
+ (jiffies - sdrbg->last_seeded) / HZ,
+ (LRNG_DRBG_RESEED_THRESH -
+ atomic_read(&sdrbg->requests)));
+ sdrbg->last_seeded = jiffies;
+ atomic_set(&sdrbg->requests, LRNG_DRBG_RESEED_THRESH);
+ }
+ spin_unlock_irqrestore(&sdrbg->lock, flags);
+}
+
+/**
+ * Try to seed the secondary DRBG
+ *
+ * @sdrbg: reference to secondary DRBG
+ * @seedfunc: function to use to seed and obtain random data from primary DRBG
+ */
+static void lrng_sdrbg_seed(struct lrng_sdrbg *sdrbg,
+ int (*seed_func)(u8 *outbuf, u32 outbuflen, bool fullentropy,
+ bool drain))
+{
+ u8 seedbuf[LRNG_DRBG_SECURITY_STRENGTH_BYTES];
+ int ret;
+
+ BUILD_BUG_ON(LRNG_MIN_SEED_ENTROPY_BITS >
+ LRNG_DRBG_SECURITY_STRENGTH_BITS);
+
+ pr_debug("reseed of secondary DRBG triggered\n");
+ ret = seed_func(seedbuf, LRNG_DRBG_SECURITY_STRENGTH_BYTES, false,
+ !sdrbg->fully_seeded);
+ /* Update the DRBG state even though we received zero random data */
+ if (ret < 0) {
+ /*
+ * Try to reseed at next round - note if EINPROGRESS is returned
+ * the request counter may fall below zero in case of parallel
+ * operations. We accept such "underflow" temporarily as the
+ * counter will be set back to a positive number in the course
+ * of the reseed. For these few generate operations under
+ * heavy parallel strain of /dev/urandom we therefore exceed
+ * the LRNG_DRBG_RESEED_THRESH threshold.
+ */
+ if (ret != -EINPROGRESS)
+ atomic_set(&sdrbg->requests, 1);
+ return;
+ }
+
+ lrng_sdrbg_inject(sdrbg, seedbuf, ret, true);
+ memzero_explicit(seedbuf, ret);
+
+ if (ret >= LRNG_DRBG_SECURITY_STRENGTH_BYTES)
+ sdrbg->fully_seeded = true;
+}
+
+/**
+ * DRBG reseed trigger: Kernel thread handler triggered by the schedule_work()
+ */
+static void lrng_pdrbg_seed_work(struct work_struct *dummy)
+{
+ u32 node;
+
+ for (node = 0; node <= lrng_pool.last_numa_node; node++) {
+ struct lrng_sdrbg *sdrbg = lrng_sdrbg[node];
+
+ if (!sdrbg->fully_seeded) {
+ pr_debug("reseed triggered by interrupt noise source for secondary DRBG on NUMA node %d\n", node);
+ lrng_sdrbg_seed(sdrbg, lrng_pdrbg_seed_internal);
+ if (node && sdrbg->fully_seeded) {
+ /* Prevent reseed storm */
+ sdrbg->last_seeded += node * 100 * HZ;
+ /* Prevent draining of pool on idle systems */
+ lrng_sdrbg_reseed_max_time += 100;
+ }
+ return;
+ }
+ }
+}
+
+/**
+ * DRBG reseed trigger: Synchronous reseed request
+ */
+static int lrng_pdrbg_seed(u8 *outbuf, u32 outbuflen, bool fullentropy,
+ bool drain)
+{
+ /* Ensure that the seeding only occurs once at any given time */
+ if (atomic_cmpxchg(&lrng_pool.irq_info.reseed_in_progress, 0, 1))
+ return -EINPROGRESS;
+ return lrng_pdrbg_seed_internal(outbuf, outbuflen, fullentropy, drain);
+}
+
+/**
+ * Obtain random data from DRBG with information theoretical entropy by
+ * triggering a reseed. The primary DRBG will only return as many random
+ * bytes as it was seeded with.
+ *
+ * @outbuf: buffer to store the random data in
+ * @outbuflen: length of outbuf
+ * @return: < 0 on error
+ * >= 0 the number of bytes that were obtained
+ */
+static int lrng_pdrbg_get(u8 *outbuf, u32 outbuflen)
+{
+ int ret;
+
+ if (!outbuf || !outbuflen)
+ return 0;
+
+ /* DRBG is not yet available */
+ if (!atomic_read(&lrng_pdrbg_avail))
+ return 0;
+
+ ret = lrng_pdrbg_seed(outbuf, outbuflen, true, true);
+ pr_debug("read %u bytes of full entropy data from primary DRBG\n", ret);
+
+ return ret;
+}
+
+/**
+ * Initial RNG provides random data with as much entropy as we have
+ * at boot time until the DRBG becomes available during late_initcall() but
+ * before user space boots. When the DRBG is initialized, the initial RNG
+ * is retired.
+ *
+ * Note: until retirement of this RNG, the system did not generate too much
+ * entropy yet. Hence, a proven DRNG like a DRBG is not necessary here anyway.
+ *
+ * The RNG is using the following as noise source:
+ * * high resolution time stamps
+ * * the collected IRQ state
+ * * CPU noise source if available
+ *
+ * Input/output: it is a drop-in replacement for lrng_sdrbg_get.
+ */
+static u32 lrng_init_state[SHA_WORKSPACE_WORDS];
+static int lrng_init_rng(u8 *outbuf, u32 outbuflen)
+{
+ u32 hash[SHA_DIGEST_WORDS];
+ u32 outbuflen_orig = outbuflen;
+ u32 workspace[SHA_WORKSPACE_WORDS];
+
+ BUILD_BUG_ON(sizeof(lrng_init_state[0]) != LRNG_POOL_WORD_BYTES);
+
+ sha_init(hash);
+ while (outbuflen) {
+ unsigned int arch;
+ u32 i;
+ u32 todo = min_t(u32, outbuflen,
+ SHA_WORKSPACE_WORDS * sizeof(u32));
+
+ /* Update init RNG state with CPU RNG and timer data */
+ for (i = 0; i < SHA_WORKSPACE_WORDS; i++) {
+ if (arch_get_random_int(&arch))
+ lrng_init_state[i] ^= arch;
+ lrng_init_state[i] ^= random_get_entropy();
+ }
+ /* SHA-1 update using the init RNG state */
+ sha_transform(hash, (u8 *)&lrng_init_state, workspace);
+
+ /* SHA-1 update with all words of the entropy pool */
+ BUILD_BUG_ON(LRNG_POOL_SIZE % 16);
+ for (i = 0; i < LRNG_POOL_SIZE; i += 16)
+ sha_transform(hash, (u8 *)(lrng_pool.pool + i),
+ workspace);
+
+ /* Mix generated data into state for backtracking resistance */
+ for (i = 0; i < SHA_DIGEST_WORDS; i++)
+ lrng_init_state[i] ^= hash[i];
+
+ memcpy(outbuf, hash, todo);
+ outbuf += todo;
+ outbuflen -= todo;
+ atomic_add(todo, &lrng_initrng_bytes);
+ }
+ memzero_explicit(hash, sizeof(hash));
+ memzero_explicit(workspace, sizeof(workspace));
+
+ return outbuflen_orig;
+}
+
+static inline struct lrng_sdrbg *lrng_get_current_sdrbg(void)
+{
+ struct lrng_sdrbg *sdrbg = lrng_sdrbg[numa_node_id()];
+
+ return (sdrbg->fully_seeded) ? sdrbg : lrng_sdrbg[0];
+}
+
+/**
+ * Get random data out of the secondary DRBG which is reseeded frequently. In
+ * the worst case, the DRBG may generate random numbers without being reseeded
+ * for LRNG_DRBG_RESEED_THRESH requests times LRNG_DRBG_MAX_REQSIZE bytes.
+ *
+ * If the DRBG is not yet initialized, use the initial RNG output.
+ *
+ * @outbuf: buffer for storing random data
+ * @outbuflen: length of outbuf
+ * @return: < 0 in error case (DRBG generation or update failed)
+ * >=0 returning the returned number of bytes
+ */
+static int lrng_sdrbg_get(u8 *outbuf, u32 outbuflen)
+{
+ u32 processed = 0;
+ struct lrng_sdrbg *sdrbg;
+ unsigned long flags;
+ int ret;
+
+ if (!outbuf || !outbuflen)
+ return 0;
+
+ outbuflen = min_t(size_t, outbuflen, INT_MAX);
+
+ /* DRBG is not yet available */
+ if (!atomic_read(&lrng_pdrbg_avail)) {
+ spin_lock_irqsave(&lrng_init_rng_lock, flags);
+ /* Prevent race with lrng_init */
+ if (!atomic_read(&lrng_pdrbg_avail)) {
+ ret = lrng_init_rng(outbuf, outbuflen);
+ spin_unlock_irqrestore(&lrng_init_rng_lock, flags);
+ return ret;
+ }
+ spin_unlock_irqrestore(&lrng_init_rng_lock, flags);
+ }
+
+ sdrbg = lrng_get_current_sdrbg();
+ while (outbuflen) {
+ unsigned long now = jiffies;
+ u32 todo = min_t(u32, outbuflen, LRNG_DRBG_MAX_REQSIZE);
+
+ if (atomic_dec_and_test(&sdrbg->requests) ||
+ time_after(now, sdrbg->last_seeded +
+ lrng_sdrbg_reseed_max_time * HZ))
+ lrng_sdrbg_seed(sdrbg, lrng_pdrbg_seed);
+
+ spin_lock_irqsave(&sdrbg->lock, flags);
+ ret = lrng_drng_generate_helper(sdrbg->sdrbg,
+ outbuf + processed, todo);
+ spin_unlock_irqrestore(&sdrbg->lock, flags);
+ if (ret <= 0) {
+ pr_warn("getting random data from secondary DRBG failed (%d)\n",
+ ret);
+ return -EFAULT;
+ }
+ processed += ret;
+ outbuflen -= ret;
+ }
+
+ return processed;
+}
+
+static int lrng_drngs_alloc(void)
+{
+ unsigned long flags;
+ struct drbg_state *pdrbg;
+ u32 node;
+ u32 num_nodes = num_possible_nodes();
+
+ pdrbg = lrng_drng_alloc(LRNG_DRBG_CORE, LRNG_DRBG_BLOCKLEN_BYTES,
+ LRNG_DRBG_SECURITY_STRENGTH_BYTES);
+ if (!pdrbg)
+ return -ENOMEM;
+
+ spin_lock_irqsave(&lrng_pdrbg.lock, flags);
+ if (lrng_pdrbg.pdrbg) {
+ lrng_drng_dealloc(pdrbg);
+ kfree(pdrbg);
+ } else {
+ lrng_pdrbg.pdrbg = pdrbg;
+ INIT_WORK(&lrng_pdrbg.lrng_seed_work, lrng_pdrbg_seed_work);
+ pr_info("primary DRBG allocated\n");
+ }
+
+ lrng_pool.last_numa_node = num_nodes - 1;
+
+ spin_unlock_irqrestore(&lrng_pdrbg.lock, flags);
+
+ lrng_sdrbg = kmalloc_array(num_nodes, sizeof(void *),
+ GFP_KERNEL|__GFP_NOFAIL);
+ for (node = 0; node < num_nodes; node++) {
+ struct lrng_sdrbg *sdrbg;
+
+ sdrbg = kmalloc_node(sizeof(struct lrng_sdrbg),
+ GFP_KERNEL|__GFP_NOFAIL, node);
+ if (!sdrbg)
+ goto err;
+ memset(sdrbg, 0, sizeof(lrng_sdrbg));
+ lrng_sdrbg[node] = sdrbg;
+
+ sdrbg->sdrbg = lrng_drng_alloc(LRNG_DRBG_CORE,
+ LRNG_DRBG_BLOCKLEN_BYTES,
+ LRNG_DRBG_SECURITY_STRENGTH_BYTES);
+ if (!sdrbg->sdrbg)
+ goto err;
+
+ atomic_set(&sdrbg->requests, 1);
+ spin_lock_init(&sdrbg->lock);
+ sdrbg->last_seeded = jiffies;
+ sdrbg->fully_seeded = false;
+
+ pr_info("secondary DRBG for NUMA node %d allocated\n", node);
+ }
+
+ return 0;
+
+err:
+ for (node = 0; node < num_nodes; node++) {
+ struct lrng_sdrbg *sdrbg = lrng_sdrbg[node];
+
+ if (sdrbg) {
+ if (sdrbg->sdrbg)
+ lrng_drng_dealloc(sdrbg->sdrbg);
+ kfree(sdrbg);
+ }
+ }
+ kfree(lrng_sdrbg);
+
+ lrng_drng_dealloc(pdrbg);
+ kfree(pdrbg);
+
+ return -ENOMEM;
+}
+
+static int lrng_alloc(void)
+{
+ u8 key[LRNG_DRBG_SECURITY_STRENGTH_BYTES] __aligned(LRNG_KCAPI_ALIGN);
+ int ret = lrng_drngs_alloc();
+
+ if (ret)
+ return ret;
+
+ /* If the used hash is no MAC, ignore the ENOSYS return code */
+ lrng_init_rng(key, sizeof(key));
+ lrng_pool.lrng_hash = lrng_hash_alloc(LRNG_HASH_NAME, key, sizeof(key));
+ memzero_explicit(key, sizeof(key));
+ if (IS_ERR(lrng_pool.lrng_hash))
+ return -PTR_ERR(lrng_pool.lrng_hash);
+
+ return 0;
+}
+
+/************************** LRNG kernel interfaces ***************************/
+
+void get_random_bytes(void *buf, int nbytes)
+{
+ lrng_sdrbg_get((u8 *)buf, (u32)nbytes);
+}
+EXPORT_SYMBOL(get_random_bytes);
+
+/**
+ * This function will use the architecture-specific hardware random
+ * number generator if it is available. The arch-specific hw RNG will
+ * almost certainly be faster than what we can do in software, but it
+ * is impossible to verify that it is implemented securely (as
+ * opposed, to, say, the AES encryption of a sequence number using a
+ * key known by the NSA). So it's useful if we need the speed, but
+ * only if we're willing to trust the hardware manufacturer not to
+ * have put in a back door.
+ *
+ * @buf: buffer allocated by caller to store the random data in
+ * @nbytes: length of outbuf
+ */
+void get_random_bytes_arch(void *buf, int nbytes)
+{
+ u8 *p = buf;
+
+ while (nbytes) {
+ unsigned long v;
+ int chunk = min_t(int, nbytes, sizeof(unsigned long));
+
+ if (!arch_get_random_long(&v))
+ break;
+
+ memcpy(p, &v, chunk);
+ p += chunk;
+ nbytes -= chunk;
+ }
+
+ if (nbytes)
+ lrng_sdrbg_get((u8 *)p, (u32)nbytes);
+}
+EXPORT_SYMBOL(get_random_bytes_arch);
+
+/**
+ * Interface for in-kernel drivers of true hardware RNGs.
+ * Those devices may produce endless random bits and will be throttled
+ * when our pool is full.
+ *
+ * @buffer: buffer holding the entropic data from HW noise sources to be used to
+ * (re)seed the DRBG.
+ * @count: length of buffer
+ * @entropy_bits: amount of entropy in buffer (value is in bits)
+ */
+void add_hwgenerator_randomness(const char *buffer, size_t count,
+ size_t entropy_bits)
+{
+ /* DRBG is not yet online */
+ if (!atomic_read(&lrng_pdrbg_avail))
+ return;
+ /*
+ * Suspend writing if we are fully loaded with entropy.
+ * We'll be woken up again once below lrng_write_wakeup_thresh,
+ * or when the calling thread is about to terminate.
+ */
+ wait_event_interruptible(lrng_write_wait,
+ kthread_should_stop() || lrng_need_entropy());
+ lrng_pdrbg_inject(buffer, count, entropy_bits, NULL, 0, false);
+}
+EXPORT_SYMBOL_GPL(add_hwgenerator_randomness);
+
+/**
+ * Delete a previously registered readiness callback function.
+ */
+void del_random_ready_callback(struct random_ready_callback *rdy)
+{
+ unsigned long flags;
+ struct module *owner = NULL;
+
+ spin_lock_irqsave(&lrng_ready_list_lock, flags);
+ if (!list_empty(&rdy->list)) {
+ list_del_init(&rdy->list);
+ owner = rdy->owner;
+ }
+ spin_unlock_irqrestore(&lrng_ready_list_lock, flags);
+
+ module_put(owner);
+}
+EXPORT_SYMBOL(del_random_ready_callback);
+
+/**
+ * Add a callback function that will be invoked when the DRBG is fully seeded.
+ *
+ * @return: 0 if callback is successfully added
+ * -EALREADY if pool is already initialised (callback not called)
+ * -ENOENT if module for callback is not alive
+ */
+int add_random_ready_callback(struct random_ready_callback *rdy)
+{
+ struct module *owner;
+ unsigned long flags;
+ int err = -EALREADY;
+
+ if (likely(lrng_pdrbg.pdrbg_fully_seeded))
+ return err;
+
+ owner = rdy->owner;
+ if (!try_module_get(owner))
+ return -ENOENT;
+
+ spin_lock_irqsave(&lrng_ready_list_lock, flags);
+ if (lrng_pdrbg.pdrbg_fully_seeded)
+ goto out;
+
+ owner = NULL;
+
+ list_add(&rdy->list, &lrng_ready_list);
+ err = 0;
+
+out:
+ spin_unlock_irqrestore(&lrng_ready_list_lock, flags);
+
+ module_put(owner);
+
+ return err;
+}
+EXPORT_SYMBOL(add_random_ready_callback);
+
+/************************ LRNG user space interfaces *************************/
+
+static ssize_t lrng_read_common(char __user *buf, size_t nbytes,
+ int (*lrng_read_random)(u8 *outbuf, u32 outbuflen))
+{
+ ssize_t ret = 0;
+ u8 tmpbuf[64] __aligned(LRNG_KCAPI_ALIGN);
+ u8 *tmp_large = NULL;
+ u8 *tmp = tmpbuf;
+ u32 tmplen = sizeof(tmpbuf);
+
+ if (nbytes == 0)
+ return 0;
+
+ /*
+ * Satisfy large read requests -- as the common case are smaller
+ * request sizes, such as 16 or 32 bytes, avoid a kmalloc overhead for
+ * those by using the stack variable of tmpbuf.
+ */
+ if (nbytes > 64) {
+ tmplen = min_t(u32, nbytes, LRNG_DRBG_MAX_REQSIZE);
+ tmp_large = kmalloc(tmplen + LRNG_KCAPI_ALIGN, GFP_KERNEL);
+ if (!tmp_large)
+ tmplen = sizeof(tmpbuf);
+ else
+ tmp = PTR_ALIGN(tmp_large, LRNG_KCAPI_ALIGN);
+ }
+
+ while (nbytes) {
+ u32 todo = min_t(u32, nbytes, tmplen);
+ int rc = 0;
+
+ if (tmp_large && need_resched()) {
+ if (signal_pending(current)) {
+ if (ret == 0)
+ ret = -ERESTARTSYS;
+ break;
+ }
+ schedule();
+ }
+
+ rc = lrng_read_random(tmp, todo);
+ if (rc <= 0)
+ break;
+ if (copy_to_user(buf, tmp, rc)) {
+ ret = -EFAULT;
+ break;
+ }
+
+ nbytes -= rc;
+ buf += rc;
+ ret += rc;
+ }
+
+ /* Wipe data just returned from memory */
+ if (tmp_large)
+ kzfree(tmp_large);
+ else
+ memzero_explicit(tmpbuf, sizeof(tmpbuf));
+
+ return ret;
+}
+
+static ssize_t
+lrng_pdrbg_read_common(int nonblock, char __user *buf, size_t nbytes)
+{
+ if (nbytes == 0)
+ return 0;
+
+ nbytes = min_t(u32, nbytes, LRNG_DRBG_BLOCKLEN_BYTES);
+ while (1) {
+ ssize_t n;
+
+ n = lrng_read_common(buf, nbytes, lrng_pdrbg_get);
+ if (n < 0)
+ return n;
+ if (n > 0)
+ return n;
+
+ /* No entropy available. Maybe wait and retry. */
+ if (nonblock)
+ return -EAGAIN;
+
+ wait_event_interruptible(lrng_read_wait,
+ lrng_have_entropy_full());
+ if (signal_pending(current))
+ return -ERESTARTSYS;
+ }
+}
+
+static ssize_t lrng_pdrbg_read(struct file *file, char __user *buf,
+ size_t nbytes, loff_t *ppos)
+{
+ return lrng_pdrbg_read_common(file->f_flags & O_NONBLOCK, buf, nbytes);
+}
+
+static unsigned int lrng_pdrbg_poll(struct file *file, poll_table *wait)
+{
+ unsigned int mask;
+
+ poll_wait(file, &lrng_read_wait, wait);
+ poll_wait(file, &lrng_write_wait, wait);
+ mask = 0;
+ if (lrng_have_entropy_full())
+ mask |= POLLIN | POLLRDNORM;
+ if (lrng_need_entropy())
+ mask |= POLLOUT | POLLWRNORM;
+ return mask;
+}
+
+static ssize_t lrng_drbg_write_common(const char __user *buffer, size_t count,
+ u32 entropy_bits, bool sdrbg)
+{
+ ssize_t ret = 0;
+ u8 buf[64] __aligned(LRNG_KCAPI_ALIGN);
+ const char __user *p = buffer;
+
+ if (!atomic_read(&lrng_pdrbg_avail))
+ return -EAGAIN;
+
+ count = min_t(size_t, count, INT_MAX);
+ while (count > 0) {
+ size_t bytes = min_t(size_t, count, sizeof(buf));
+ u32 ent = min_t(u32, bytes<<3, entropy_bits);
+
+ if (copy_from_user(&buf, p, bytes))
+ return -EFAULT;
+ /* Inject data into primary DRBG */
+ lrng_pdrbg_inject(buf, bytes, ent, NULL, 0, false);
+ /* Data from /dev/[|u]random is injected into secondary DRBG */
+ if (sdrbg) {
+ u32 node;
+ int num_nodes = num_possible_nodes();
+
+ for (node = 0; node < num_nodes; node++)
+ lrng_sdrbg_inject(lrng_sdrbg[node], buf, bytes,
+ false);
+ }
+
+ count -= bytes;
+ p += bytes;
+ ret += bytes;
+ entropy_bits -= ent;
+
+ cond_resched();
+ }
+
+ return ret;
+}
+
+static ssize_t lrng_sdrbg_read(struct file *file, char __user *buf,
+ size_t nbytes, loff_t *ppos)
+{
+ return lrng_read_common(buf, nbytes, lrng_sdrbg_get);
+}
+
+static ssize_t lrng_drbg_write(struct file *file, const char __user *buffer,
+ size_t count, loff_t *ppos)
+{
+ return lrng_drbg_write_common(buffer, count, 0, true);
+}
+
+static long lrng_ioctl(struct file *f, unsigned int cmd, unsigned long arg)
+{
+ int size, ent_count_bits;
+ int __user *p = (int __user *)arg;
+
+ switch (cmd) {
+ case RNDGETENTCNT:
+ ent_count_bits = lrng_avail_entropy();
+ if (put_user(ent_count_bits, p))
+ return -EFAULT;
+ return 0;
+ case RNDADDTOENTCNT:
+ if (!capable(CAP_SYS_ADMIN))
+ return -EPERM;
+ if (get_user(ent_count_bits, p))
+ return -EFAULT;
+ ent_count_bits = (int)lrng_avail_entropy() + ent_count_bits;
+ if (ent_count_bits < 0)
+ ent_count_bits = 0;
+ if (ent_count_bits > LRNG_POOL_SIZE_BITS)
+ ent_count_bits = LRNG_POOL_SIZE_BITS;
+ atomic_set(&lrng_pool.irq_info.num_events,
+ lrng_entropy_to_data(ent_count_bits));
+ return 0;
+ case RNDADDENTROPY:
+ if (!capable(CAP_SYS_ADMIN))
+ return -EPERM;
+ if (get_user(ent_count_bits, p++))
+ return -EFAULT;
+ if (ent_count_bits < 0)
+ return -EINVAL;
+ if (get_user(size, p++))
+ return -EFAULT;
+ if (size < 0)
+ return -EINVAL;
+ /* there cannot be more entropy than data */
+ ent_count_bits = min(ent_count_bits, size<<3);
+ return lrng_drbg_write_common((const char __user *)p, size,
+ ent_count_bits, false);
+ case RNDZAPENTCNT:
+ case RNDCLEARPOOL:
+ /* Clear the entropy pool counter. */
+ if (!capable(CAP_SYS_ADMIN))
+ return -EPERM;
+ atomic_set(&lrng_pool.irq_info.num_events, 0);
+ return 0;
+ default:
+ return -EINVAL;
+ }
+}
+
+static int lrng_fasync(int fd, struct file *filp, int on)
+{
+ return fasync_helper(fd, filp, on, &fasync);
+}
+
+const struct file_operations random_fops = {
+ .read = lrng_pdrbg_read,
+ .write = lrng_drbg_write,
+ .poll = lrng_pdrbg_poll,
+ .unlocked_ioctl = lrng_ioctl,
+ .fasync = lrng_fasync,
+ .llseek = noop_llseek,
+};
+
+const struct file_operations urandom_fops = {
+ .read = lrng_sdrbg_read,
+ .write = lrng_drbg_write,
+ .unlocked_ioctl = lrng_ioctl,
+ .fasync = lrng_fasync,
+ .llseek = noop_llseek,
+};
+
+SYSCALL_DEFINE3(getrandom, char __user *, buf, size_t, count,
+ unsigned int, flags)
+{
+ if (flags & ~(GRND_NONBLOCK|GRND_RANDOM))
+ return -EINVAL;
+
+ if (count > INT_MAX)
+ count = INT_MAX;
+
+ if (flags & GRND_RANDOM)
+ return lrng_pdrbg_read_common(flags & GRND_NONBLOCK, buf,
+ count);
+
+ if (unlikely(!lrng_pdrbg.pdrbg_fully_seeded)) {
+ if (flags & GRND_NONBLOCK)
+ return -EAGAIN;
+ wait_event_interruptible(lrng_pdrbg_init_wait,
+ lrng_pdrbg.pdrbg_fully_seeded);
+ if (signal_pending(current))
+ return -ERESTARTSYS;
+ }
+ return lrng_sdrbg_read(NULL, buf, count, NULL);
+}
+
+/*************************** LRNG proc interfaces ****************************/
+
+#ifdef CONFIG_SYSCTL
+
+#include <linux/sysctl.h>
+
+static int lrng_min_read_thresh = LRNG_POOL_WORD_BITS;
+static int lrng_min_write_thresh;
+static int lrng_max_read_thresh = LRNG_POOL_SIZE_BITS;
+static int lrng_max_write_thresh = LRNG_DRBG_SECURITY_STRENGTH_BITS;
+static char lrng_sysctl_bootid[16];
+static int lrng_sdrbg_reseed_max_min;
+
+/*
+ * This function is used to return both the bootid UUID, and random
+ * UUID. The difference is in whether table->data is NULL; if it is,
+ * then a new UUID is generated and returned to the user.
+ *
+ * If the user accesses this via the proc interface, the UUID will be
+ * returned as an ASCII string in the standard UUID format; if via the
+ * sysctl system call, as 16 bytes of binary data.
+ */
+static int lrng_proc_do_uuid(struct ctl_table *table, int write,
+ void __user *buffer, size_t *lenp, loff_t *ppos)
+{
+ struct ctl_table fake_table;
+ unsigned char buf[64], tmp_uuid[16], *uuid;
+
+ uuid = table->data;
+ if (!uuid) {
+ uuid = tmp_uuid;
+ generate_random_uuid(uuid);
+ } else {
+ static DEFINE_SPINLOCK(bootid_spinlock);
+
+ spin_lock(&bootid_spinlock);
+ if (!uuid[8])
+ generate_random_uuid(uuid);
+ spin_unlock(&bootid_spinlock);
+ }
+
+ sprintf(buf, "%pU", uuid);
+
+ fake_table.data = buf;
+ fake_table.maxlen = sizeof(buf);
+
+ return proc_dostring(&fake_table, write, buffer, lenp, ppos);
+}
+
+static int lrng_proc_do_type(struct ctl_table *table, int write,
+ void __user *buffer, size_t *lenp, loff_t *ppos)
+{
+ struct ctl_table fake_table;
+ unsigned char buf[130];
+
+ snprintf(buf, sizeof(buf), "%s: %s\nDRNG security strength: %u bits\nentropy pool read hash: %s",
+#ifdef CONFIG_CRYPTO_DRBG_CTR
+ "CTR DRBG",
+#elif defined CONFIG_CRYPTO_DRBG_HMAC
+ "HMAC DRBG",
+#elif defined CONFIG_CRYPTO_DRBG_HASH
+ "HASH DRBG",
+#else
+ "DRNG",
+#endif
+ LRNG_DRBG_CORE, LRNG_DRBG_SECURITY_STRENGTH_BITS,
+ LRNG_HASH_NAME);
+
+ fake_table.data = buf;
+ fake_table.maxlen = sizeof(buf);
+
+ return proc_dostring(&fake_table, write, buffer, lenp, ppos);
+}
+
+/* Return entropy available scaled to integral bits */
+static int lrng_proc_do_entropy(struct ctl_table *table, int write,
+ void __user *buffer, size_t *lenp, loff_t *ppos)
+{
+ struct ctl_table fake_table;
+ int entropy_count;
+
+ entropy_count = lrng_avail_entropy();
+
+ fake_table.data = &entropy_count;
+ fake_table.maxlen = sizeof(entropy_count);
+
+ return proc_dointvec(&fake_table, write, buffer, lenp, ppos);
+}
+
+static int lrng_proc_bool(struct ctl_table *table, int write,
+ void __user *buffer, size_t *lenp, loff_t *ppos)
+{
+ struct ctl_table fake_table;
+ int loc_boolean = 0;
+ bool *boolean = (bool *)table->data;
+
+ if (*boolean)
+ loc_boolean = 1;
+
+ fake_table.data = &loc_boolean;
+ fake_table.maxlen = sizeof(loc_boolean);
+
+ return proc_dointvec(&fake_table, write, buffer, lenp, ppos);
+}
+
+static int lrng_sysctl_poolsize = LRNG_POOL_SIZE_BITS;
+static int pdrbg_security_strength = LRNG_DRBG_SECURITY_STRENGTH_BYTES;
+extern struct ctl_table random_table[];
+struct ctl_table random_table[] = {
+ {
+ .procname = "poolsize",
+ .data = &lrng_sysctl_poolsize,
+ .maxlen = sizeof(int),
+ .mode = 0444,
+ .proc_handler = proc_dointvec,
+ },
+ {
+ .procname = "entropy_avail",
+ .maxlen = sizeof(int),
+ .mode = 0444,
+ .proc_handler = lrng_proc_do_entropy,
+ },
+ {
+ .procname = "read_wakeup_threshold",
+ .data = &lrng_read_wakeup_bits,
+ .maxlen = sizeof(int),
+ .mode = 0644,
+ .proc_handler = proc_dointvec_minmax,
+ .extra1 = &lrng_min_read_thresh,
+ .extra2 = &lrng_max_read_thresh,
+ },
+ {
+ .procname = "write_wakeup_threshold",
+ .data = &lrng_write_wakeup_bits,
+ .maxlen = sizeof(int),
+ .mode = 0644,
+ .proc_handler = proc_dointvec_minmax,
+ .extra1 = &lrng_min_write_thresh,
+ .extra2 = &lrng_max_write_thresh,
+ },
+ {
+ .procname = "boot_id",
+ .data = &lrng_sysctl_bootid,
+ .maxlen = 16,
+ .mode = 0444,
+ .proc_handler = lrng_proc_do_uuid,
+ },
+ {
+ .procname = "uuid",
+ .maxlen = 16,
+ .mode = 0444,
+ .proc_handler = lrng_proc_do_uuid,
+ },
+ {
+ .procname = "urandom_min_reseed_secs",
+ .data = &lrng_sdrbg_reseed_max_time,
+ .maxlen = sizeof(int),
+ .mode = 0644,
+ .proc_handler = proc_dointvec,
+ .extra1 = &lrng_sdrbg_reseed_max_min,
+ },
+ {
+ .procname = "drbg_fully_seeded",
+ .data = &lrng_pdrbg.pdrbg_fully_seeded,
+ .maxlen = sizeof(int),
+ .mode = 0444,
+ .proc_handler = lrng_proc_bool,
+ },
+ {
+ .procname = "drbg_minimally_seeded",
+ .data = &lrng_pdrbg.pdrbg_min_seeded,
+ .maxlen = sizeof(int),
+ .mode = 0444,
+ .proc_handler = lrng_proc_bool,
+ },
+ {
+ .procname = "lrng_type",
+ .maxlen = 30,
+ .mode = 0444,
+ .proc_handler = lrng_proc_do_type,
+ },
+ {
+ .procname = "drbg_security_strength",
+ .data = &pdrbg_security_strength,
+ .maxlen = sizeof(int),
+ .mode = 0444,
+ .proc_handler = proc_dointvec,
+ },
+ {
+ .procname = "high_resolution_timer",
+ .data = &lrng_pool.irq_info.irq_highres_timer,
+ .maxlen = sizeof(int),
+ .mode = 0444,
+ .proc_handler = lrng_proc_bool,
+ },
+ { }
+};
+#endif /* CONFIG_SYSCTL */
+
+/***************************** Initialize DRBG *******************************/
+
+static int __init lrng_init(void)
+{
+ unsigned long flags;
+
+ BUG_ON(lrng_alloc());
+
+ /*
+ * As we use the IRQ entropic input data processed by the init RNG
+ * again during lrng_pdrbg_seed_internal, we must not claim that
+ * the init RNG state has any entropy when injecting its contents as
+ * an initial seed into the DRBG.
+ */
+ spin_lock_irqsave(&lrng_init_rng_lock, flags);
+
+ if (random_get_entropy() || random_get_entropy()) {
+ lrng_pool.irq_info.irq_highres_timer = true;
+ lrng_pool.irq_info.irq_entropy_bits = LRNG_IRQ_ENTROPY_BITS;
+ } else {
+ lrng_pool.irq_info.irq_entropy_bits =
+ LRNG_IRQ_ENTROPY_BITS * LRNG_IRQ_OVERSAMPLING_FACTOR;
+ if (fips_enabled) {
+ pr_warn("LRNG not suitable for FIPS 140-2 use cases\n");
+ WARN_ON(1);
+ }
+ pr_warn("operating without high-resolution timer and applying IRQ oversampling factor %u\n",
+ LRNG_IRQ_OVERSAMPLING_FACTOR);
+ }
+ lrng_set_entropy_thresh(LRNG_INIT_ENTROPY_BITS);
+
+ lrng_pdrbg_inject((u8 *)&lrng_init_state,
+ SHA_WORKSPACE_WORDS * sizeof(lrng_init_state[0]),
+ 0, NULL, 0, false);
+ lrng_sdrbg_seed(lrng_sdrbg[0], lrng_pdrbg_seed);
+ atomic_inc(&lrng_pdrbg_avail);
+ memzero_explicit(&lrng_init_state,
+ SHA_WORKSPACE_WORDS * sizeof(lrng_init_state[0]));
+ spin_unlock_irqrestore(&lrng_init_rng_lock, flags);
+ pr_info("deactivating initial RNG - %d bytes delivered\n",
+ atomic_read(&lrng_initrng_bytes));
+ return 0;
+}
+
+/* A late init implies that more interrupts are collected for initial seeding */
+late_initcall(lrng_init);
+
+MODULE_LICENSE("Dual BSD/GPL");
+MODULE_AUTHOR("Stephan Mueller <smueller@chronox.de>");
+MODULE_DESCRIPTION("Linux Random Number Generator");
diff --git a/crypto/lrng_kcapi.c b/crypto/lrng_kcapi.c
new file mode 100644
index 0000000..25c37c5
--- /dev/null
+++ b/crypto/lrng_kcapi.c
@@ -0,0 +1,167 @@
+/*
+ * Backend for the LRNG providing the cryptographic primitives using the
+ * kernel crypto API.
+ *
+ * Copyright (C) 2016, Stephan Mueller <smueller@chronox.de>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, and the entire permission notice in its entirety,
+ * including the disclaimer of warranties.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote
+ * products derived from this software without specific prior
+ * written permission.
+ *
+ * ALTERNATIVELY, this product may be distributed under the terms of
+ * the GNU General Public License, in which case the provisions of the GPL2
+ * are required INSTEAD OF the above restrictions. (This clause is
+ * necessary due to a potential bad interaction between the GPL and
+ * the restrictions contained in a BSD-style copyright.)
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ALL OF
+ * WHICH ARE HEREBY DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
+ * USE OF THIS SOFTWARE, EVEN IF NOT ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <crypto/drbg.h>
+
+struct lrng_hash_info {
+ struct shash_desc shash;
+ char ctx[];
+};
+
+int lrng_drng_seed_helper(void *drng, const u8 *inbuf, u32 inbuflen)
+{
+ struct drbg_state *drbg = (struct drbg_state *)drng;
+ LIST_HEAD(seedlist);
+ struct drbg_string data;
+ int ret;
+
+ drbg_string_fill(&data, inbuf, inbuflen);
+ list_add_tail(&data.list, &seedlist);
+ ret = drbg->d_ops->update(drbg, &seedlist, drbg->seeded);
+
+ if (ret >= 0)
+ drbg->seeded = true;
+
+ return ret;
+}
+
+int lrng_drng_generate_helper(void *drng, u8 *outbuf, u32 outbuflen)
+{
+ struct drbg_state *drbg = (struct drbg_state *)drng;
+
+ return drbg->d_ops->generate(drbg, outbuf, outbuflen, NULL);
+}
+
+void *lrng_drng_alloc(u8 *drng_name, u32 blocklen_bytes, u32 sec_strength)
+{
+ struct drbg_state *drbg = NULL;
+ int coreref = -1;
+ bool pr = false;
+ int ret;
+
+ drbg_convert_tfm_core(drng_name, &coreref, &pr);
+ if (coreref < 0)
+ return NULL;
+
+ drbg = kzalloc(sizeof(struct drbg_state), GFP_KERNEL);
+ if (!drbg)
+ return NULL;
+
+ drbg->core = &drbg_cores[coreref];
+ drbg->seeded = false;
+ ret = drbg_alloc_state(drbg);
+ if (ret)
+ goto err;
+
+ if (blocklen_bytes != drbg->core->blocklen_bytes)
+ goto dealloc;
+ if (sec_strength > drbg_sec_strength(drbg->core->flags))
+ goto dealloc;
+
+ pr_info("DRBG with %s core allocated\n", drbg->core->backend_cra_name);
+
+ return drbg;
+
+dealloc:
+ if (drbg->d_ops)
+ drbg->d_ops->crypto_fini(drbg);
+ drbg_dealloc_state(drbg);
+err:
+ kfree(drbg);
+ return NULL;
+}
+
+void lrng_drng_dealloc(void *drng)
+{
+ struct drbg_state *drbg = (struct drbg_state *)drng;
+
+ drbg_dealloc_state(drbg);
+ kzfree(drbg);
+}
+
+void *lrng_hash_alloc(u8 *hashname, u8 *key, u32 keylen)
+{
+ struct lrng_hash_info *lrng_hash;
+ struct crypto_shash *tfm;
+ int size, ret;
+
+ tfm = crypto_alloc_shash(hashname, 0, 0);
+ if (IS_ERR(tfm)) {
+ pr_err("could not allocate hash %s\n", hashname);
+ return ERR_PTR(PTR_ERR(tfm));
+ }
+
+ size = sizeof(struct lrng_hash_info) + crypto_shash_descsize(tfm);
+ lrng_hash = kmalloc(size, GFP_KERNEL);
+ if (!lrng_hash) {
+ crypto_free_shash(tfm);
+ return ERR_PTR(-ENOMEM);
+ }
+
+ lrng_hash->shash.tfm = tfm;
+ lrng_hash->shash.flags = 0x0;
+
+ ret = crypto_shash_setkey(tfm, key, keylen);
+ if (ret && ret != -ENOSYS) {
+ pr_err("could not set the key for MAC\n");
+ crypto_free_shash(tfm);
+ kfree(lrng_hash);
+ return ERR_PTR(ret);
+ }
+
+ return lrng_hash;
+}
+
+u32 lrng_hash_digestsize(void *hash)
+{
+ struct lrng_hash_info *lrng_hash = (struct lrng_hash_info *)hash;
+ struct shash_desc *shash = &lrng_hash->shash;
+
+ return crypto_shash_digestsize(shash->tfm);
+}
+
+int lrng_hash_buffer(void *hash, u8 *inbuf, u32 inbuflen, u8 *digest)
+{
+ struct lrng_hash_info *lrng_hash = (struct lrng_hash_info *)hash;
+ struct shash_desc *shash = &lrng_hash->shash;
+
+ return crypto_shash_digest(shash, inbuf, inbuflen, digest);
+}
--
2.7.4
^ permalink raw reply related
* [PATCH v6 2/5] random: conditionally compile code depending on LRNG
From: Stephan Mueller @ 2016-08-11 12:25 UTC (permalink / raw)
To: herbert
Cc: Ted Tso, sandyinchina, Jason Cooper, John Denker, H. Peter Anvin,
Joe Perches, Pavel Machek, George Spelvin, linux-crypto,
linux-kernel
In-Reply-To: <4723196.TTQvcXsLCG@positron.chronox.de>
When selecting the LRNG for compilation, disable the legacy /dev/random
implementation.
The LRNG is a drop-in replacement for the legacy /dev/random which
implements the same in-kernel and user space API. Only the hooks of
/dev/random into other parts of the kernel need to be disabled.
Signed-off-by: Stephan Mueller <smueller@chronox.de>
---
drivers/char/random.c | 8 ++++++++
include/linux/genhd.h | 5 +++++
include/linux/random.h | 7 ++++++-
3 files changed, 19 insertions(+), 1 deletion(-)
diff --git a/drivers/char/random.c b/drivers/char/random.c
index 3efb3bf..730a12e 100644
--- a/drivers/char/random.c
+++ b/drivers/char/random.c
@@ -270,6 +270,8 @@
#include <asm/irq_regs.h>
#include <asm/io.h>
+#ifndef CONFIG_CRYPTO_LRNG
+
#define CREATE_TRACE_POINTS
#include <trace/events/random.h>
@@ -1898,6 +1900,7 @@ SYSCALL_DEFINE3(getrandom, char __user *, buf, size_t, count,
}
return urandom_read(NULL, buf, count, NULL);
}
+#endif /* CONFIG_CRYPTO_LRNG */
/********************************************************************
*
@@ -1905,6 +1908,7 @@ SYSCALL_DEFINE3(getrandom, char __user *, buf, size_t, count,
*
********************************************************************/
+#ifndef CONFIG_CRYPTO_LRNG
#ifdef CONFIG_SYSCTL
#include <linux/sysctl.h>
@@ -2042,6 +2046,8 @@ struct ctl_table random_table[] = {
};
#endif /* CONFIG_SYSCTL */
+#endif /* CONFIG_CRYPTO_LRNG */
+
static u32 random_int_secret[MD5_MESSAGE_BYTES / 4] ____cacheline_aligned;
int random_int_secret_init(void)
@@ -2119,6 +2125,7 @@ randomize_range(unsigned long start, unsigned long end, unsigned long len)
return PAGE_ALIGN(get_random_int() % range + start);
}
+#ifndef CONFIG_CRYPTO_LRNG
/* Interface for in-kernel drivers of true hardware RNGs.
* Those devices may produce endless random bits and will be throttled
* when our pool is full.
@@ -2143,3 +2150,4 @@ void add_hwgenerator_randomness(const char *buffer, size_t count,
credit_entropy_bits(poolp, entropy);
}
EXPORT_SYMBOL_GPL(add_hwgenerator_randomness);
+#endif /* CONFIG_CRYPTO_LRNG */
diff --git a/include/linux/genhd.h b/include/linux/genhd.h
index 1dbf52f..387770d1 100644
--- a/include/linux/genhd.h
+++ b/include/linux/genhd.h
@@ -437,8 +437,13 @@ extern void disk_flush_events(struct gendisk *disk, unsigned int mask);
extern unsigned int disk_clear_events(struct gendisk *disk, unsigned int mask);
/* drivers/char/random.c */
+#ifdef CONFIG_CRYPTO_LRNG
+#define add_disk_randomness(disk) do {} while (0)
+#define rand_initialize_disk(disk) do {} while (0)
+#else
extern void add_disk_randomness(struct gendisk *disk);
extern void rand_initialize_disk(struct gendisk *disk);
+#endif
static inline sector_t get_start_sect(struct block_device *bdev)
{
diff --git a/include/linux/random.h b/include/linux/random.h
index 3d6e981..fd39c11 100644
--- a/include/linux/random.h
+++ b/include/linux/random.h
@@ -17,10 +17,15 @@ struct random_ready_callback {
struct module *owner;
};
-extern void add_device_randomness(const void *, unsigned int);
extern void add_input_randomness(unsigned int type, unsigned int code,
unsigned int value);
extern void add_interrupt_randomness(int irq, int irq_flags);
+#ifdef CONFIG_CRYPTO_LRNG
+#define add_device_randomness(buf, nbytes) do {} while (0)
+#else /* CONFIG_CRYPTO_LRNG */
+extern void add_device_randomness(const void *, unsigned int);
+#define lrng_irq_process()
+#endif /* CONFIG_CRYPTO_LRNG */
extern void get_random_bytes(void *buf, int nbytes);
extern int add_random_ready_callback(struct random_ready_callback *rdy);
--
2.7.4
^ permalink raw reply related
* [PATCH v6 1/5] crypto: DRBG - externalize DRBG functions for LRNG
From: Stephan Mueller @ 2016-08-11 12:24 UTC (permalink / raw)
To: herbert
Cc: Ted Tso, sandyinchina, Jason Cooper, John Denker, H. Peter Anvin,
Joe Perches, Pavel Machek, George Spelvin, linux-crypto,
linux-kernel
In-Reply-To: <4723196.TTQvcXsLCG@positron.chronox.de>
This patch allows several DRBG functions to be called by the LRNG kernel
code paths outside the drbg.c file.
Signed-off-by: Stephan Mueller <smueller@chronox.de>
---
crypto/drbg.c | 11 +++++------
include/crypto/drbg.h | 7 +++++++
2 files changed, 12 insertions(+), 6 deletions(-)
diff --git a/crypto/drbg.c b/crypto/drbg.c
index f752da3..42084c2 100644
--- a/crypto/drbg.c
+++ b/crypto/drbg.c
@@ -113,7 +113,7 @@
* the SHA256 / AES 256 over other ciphers. Thus, the favored
* DRBGs are the latest entries in this array.
*/
-static const struct drbg_core drbg_cores[] = {
+const struct drbg_core drbg_cores[] = {
#ifdef CONFIG_CRYPTO_DRBG_CTR
{
.flags = DRBG_CTR | DRBG_STRENGTH128,
@@ -205,7 +205,7 @@ static int drbg_uninstantiate(struct drbg_state *drbg);
* Return: normalized strength in *bytes* value or 32 as default
* to counter programming errors
*/
-static inline unsigned short drbg_sec_strength(drbg_flag_t flags)
+unsigned short drbg_sec_strength(drbg_flag_t flags)
{
switch (flags & DRBG_STRENGTH_MASK) {
case DRBG_STRENGTH128:
@@ -1128,7 +1128,7 @@ static int drbg_seed(struct drbg_state *drbg, struct drbg_string *pers,
}
/* Free all substructures in a DRBG state without the DRBG state structure */
-static inline void drbg_dealloc_state(struct drbg_state *drbg)
+void drbg_dealloc_state(struct drbg_state *drbg)
{
if (!drbg)
return;
@@ -1147,7 +1147,7 @@ static inline void drbg_dealloc_state(struct drbg_state *drbg)
* Allocate all sub-structures for a DRBG state.
* The DRBG state structure must already be allocated.
*/
-static inline int drbg_alloc_state(struct drbg_state *drbg)
+int drbg_alloc_state(struct drbg_state *drbg)
{
int ret = -ENOMEM;
unsigned int sb_size = 0;
@@ -1781,8 +1781,7 @@ static int drbg_kcapi_sym_ctr(struct drbg_state *drbg,
*
* return: flags
*/
-static inline void drbg_convert_tfm_core(const char *cra_driver_name,
- int *coreref, bool *pr)
+void drbg_convert_tfm_core(const char *cra_driver_name, int *coreref, bool *pr)
{
int i = 0;
size_t start = 0;
diff --git a/include/crypto/drbg.h b/include/crypto/drbg.h
index 61580b1..1755d07 100644
--- a/include/crypto/drbg.h
+++ b/include/crypto/drbg.h
@@ -280,4 +280,11 @@ enum drbg_prefixes {
DRBG_PREFIX3
};
+extern int drbg_alloc_state(struct drbg_state *drbg);
+extern void drbg_dealloc_state(struct drbg_state *drbg);
+extern void drbg_convert_tfm_core(const char *cra_driver_name, int *coreref,
+ bool *pr);
+extern const struct drbg_core drbg_cores[];
+extern unsigned short drbg_sec_strength(drbg_flag_t flags);
+
#endif /* _DRBG_H */
--
2.7.4
^ permalink raw reply related
* [PATCH v6 0/5] /dev/random - a new approach
From: Stephan Mueller @ 2016-08-11 12:24 UTC (permalink / raw)
To: herbert, Ted Tso
Cc: sandyinchina, Jason Cooper, John Denker, H. Peter Anvin,
Joe Perches, Pavel Machek, George Spelvin, linux-crypto,
linux-kernel
Hi Herbert, Ted,
The following patch set provides a different approach to /dev/random which
I call Linux Random Number Generator (LRNG) to collect entropy within the Linux
kernel. The main improvements compared to the legacy /dev/random is to provide
sufficient entropy during boot time as well as in virtual environments and when
using SSDs. A secondary design goal is to limit the impact of the entropy
collection on massive parallel systems and also allow the use accelerated
cryptographic primitives. Also, all steps of the entropic data processing are
testable. Finally massive performance improvements are visible at /dev/urandom
and get_random_bytes.
The design and implementation is driven by a set of goals described in [1]
that the LRNG completely implements. Furthermore, [1] includes a
comparison with RNG design suggestions such as SP800-90B, SP800-90C, and
AIS20/31.
Changes v6:
* port to 4.8-rc1
* add missing memzero_explicit to ChaCha20 DRNG
* use kernel-doc documentation style
* use of min3 in lrng_get_pool to beautify code
* prevent fast noise sources from dominating slow noise sources
in case of /dev/random
* set read wakeup threshold to 64 bits to comply with legacy /dev/random
* simplify the interrupt to entropy amount conversion code
* move wakeup call of entropy-providers to a code location where /dev/urandom
will benefit from the wake up as well (i.e. when the primary DRBG entropy
runs low because of /dev/urandom reseeds, the entropy provider is woken up)
* inject current time into primary DRBG at the time of seeding from noise
sources (suggested by Sandy Harris)
Changes v5:
* fix treating LRNG_POOL_SIZE_BITS as entropy value in lrng_get_pool
* use CTR DRBG with AES256 as default due to its superior speed -- on X86_64
executing within a KVM I get read speeds of up to 850 MB/s now. When using a
fake NUMA system with 4 nodes on 4 CPUs, I still get up to 430 MB/s read speed
with four parallel reads. Note, this patch applies to the current
cryptodev-2.6 tree.
* simplify lrng_get_arch
* use DRBG security strengths as defined in SP800-57 section 5.6.1
* add security strength to /proc/sys/kernel/random/lrng_type
* add ChaCha20 DRNG: in case the kernel crypto API is not compiled, the ChaCha20
DRNG with the SHA-1 C implementations are used to drive the cryptographic part
of the LRNG.The ChaCha20 RNG is described in [1]. I analyzed it with a user
space version of it.
* Editorial changes requested by checkpatch.pl
Changes v4:
* port to 4.7-rc1
* Use classical twisted LFSR approach to collect entropic data as requested by
George Spelvin. The LFSR is based on a primitive and irreducible polynomial
whose taps are not too close to the location the current byte is mixed in.
Primitive polynomials for other entropy pool sizes are offered in the code.
* The reading of the entropy pool is performed with a hash. The hash can be
specified at compile time. The pre-defined hashes are the same as used for
the DRBG type (e.g. a SHA256 Hash DRBG implies the use of SHA-256, an AES256
CTR DRBG implies the use of CMAC-AES).
* Addition of the example defines for a CTR DRBG with AES128 which can be
enabled during compile time.
* Entropy estimate: one bit of entropy per interrupt. In case a system does
not have a high-resolution timer, apply 1/10th bit of entropy per interrupt.
The interrupt estimates can be changed arbitrarily at compile time.
* Use kmalloc_node for the per-NUMA node secondary DRBGs.
* Add boot time entropy tests discussed in section 3.4.3 [1].
* Align all buffers that are processed by the kernel crypto API to an 8 byte
boundary. This boundary covers all currently existing cipher implementations.
Changes v3:
* Convert debug printk to pr_debug as suggested by Joe Perches
* Add missing \n as suggested by Joe Perches
* Do not mix in struck IRQ measurements as requested by Pavel Machek
* Add handling logic for systems without high-res timer as suggested by Pavel
Machek -- it uses ideas from the add_interrupt_randomness of the legacy
/dev/random implementation
* add per NUMA node secondary DRBGs as suggested by Andi Kleen -- the
explanation of how the logic works is given in section 2.1.1 of my
documentation [1], especially how the initial seeding is performed.
Changes v2:
* Removal of the Jitter RNG fast noise source as requested by Ted
* Addition of processing of add_input_randomness as suggested by Ted
* Update documentation and testing in [1] to cover the updates
* Addition of a SystemTap script to test add_input_randomness
* To clarify the question whether sufficient entropy is present during boot
I added one more test in 3.3.1 [1] which demonstrates the providing of
sufficient entropy during initialization. In the worst case of no fast noise
sources, in the worst case of a virtual machine with only very few hardware
devices, the testing shows that the secondary DRBG is fully seeded with 256
bits of entropy before user space injects the random data obtained
during shutdown of the previous boot (i.e. the requirement phrased by the
legacy /dev/random implementation). As the writing of the random data into
/dev/random by user space will happen before any cryptographic service
is initialized in user space, this test demonstrates that sufficient
entropy is already present in the LRNG at the time user space requires it
for seeding cryptographic daemons. Note, this test result was obtained
for different architectures, such as x86 64 bit, x86 32 bit, ARM 32 bit and
MIPS 32 bit.
[1] http://www.chronox.de/lrng/doc/lrng.pdf
[2] http://www.chronox.de/lrng.html
Stephan Mueller (5):
crypto: DRBG - externalize DRBG functions for LRNG
random: conditionally compile code depending on LRNG
crypto: Linux Random Number Generator
crypto: LRNG - enable compile
crypto: LRNG - add ChaCha20 support
crypto/Kconfig | 10 +
crypto/Makefile | 7 +
crypto/drbg.c | 11 +-
crypto/lrng_base.c | 1960 ++++++++++++++++++++++++++++++++++++++++++++++
crypto/lrng_kcapi.c | 167 ++++
crypto/lrng_standalone.c | 220 ++++++
drivers/char/random.c | 8 +
include/crypto/drbg.h | 7 +
include/linux/genhd.h | 5 +
include/linux/random.h | 7 +-
10 files changed, 2395 insertions(+), 7 deletions(-)
create mode 100644 crypto/lrng_base.c
create mode 100644 crypto/lrng_kcapi.c
create mode 100644 crypto/lrng_standalone.c
--
2.7.4
^ permalink raw reply
* [PATCH] X.509: Fix double free in x509_cert_parse().
From: Artem Savkov @ 2016-08-11 12:18 UTC (permalink / raw)
To: tadeusz.struk; +Cc: dhowells, linux-crypto, linux-kernel, Artem Savkov
Patch "crypto: KEYS: convert public key and digsig asym to the akcipher
api" introduced double freeing of cert->pub->key. There is no need to free
it in error_decode label as it is later freed in x509_free_certificate().
Signed-off-by: Artem Savkov <asavkov@redhat.com>
---
crypto/asymmetric_keys/x509_cert_parser.c | 1 -
1 file changed, 1 deletion(-)
diff --git a/crypto/asymmetric_keys/x509_cert_parser.c b/crypto/asymmetric_keys/x509_cert_parser.c
index 1f1899d..9157071 100644
--- a/crypto/asymmetric_keys/x509_cert_parser.c
+++ b/crypto/asymmetric_keys/x509_cert_parser.c
@@ -133,7 +133,6 @@ struct x509_certificate *x509_cert_parse(const void *data, size_t datalen)
return cert;
error_decode:
- kfree(cert->pub->key);
kfree(ctx);
error_no_ctx:
x509_free_certificate(cert);
--
2.7.4
^ permalink raw reply related
* Re: [PATCH 2/2] ath9k: disable RNG by default
From: miaoqing @ 2016-08-11 2:54 UTC (permalink / raw)
To: Jason Cooper
Cc: Pan, Miaoqing, Stephan Mueller, Herbert Xu, Matt Mackall,
Valo, Kalle, linux-wireless, ath9k-devel, linux-crypto,
Sepehrdad, Pouyan
In-Reply-To: <20160810132449.GH2013@io.lakedaemon.net>
Hi Jason,
On 2016-08-10 21:24, Jason Cooper wrote:
> *gentle reminder: others are reading which may not be directly included
> in the conversation. Including the archives. Please avoid top
> posting.
> :)
Thanks:)
> The fact is, barring userspace expectations of /dev/hwrng, hw_random is
> the appropriate place for it. It's not a devicetree blob, mac address,
> or pci config space. Which are things we feed in once for the heck of
> it. This is a *continuous* source or questionable quality.
>
> I'm seriously considering putting this and timeriomem-rng into a
> subdirectory under hw_random/, maybe environ/. Anything in there gets
> quality=0 for default, and *doesn't* contribute to /dev/hwrng.
>
> Regardless which path we take, I think we should include 'adc' in the
> name. I've heard countless times about "Atheros cards come with an rng
> on board". :-/
If I understand correctly, you want to bind the ADC source to
/dev/hwrng,
and then change rng-tools to set the entropy to zero in the ioctl call ?
There are two major problems with that approach,
1) We already tried once before to bind our solution to /dev/hwrng, and
got
so much complaints. The conclusion was that maybe we know that the
output of
/dev/hwrng does not have perfect entropy, but a normal user does not
know and
will misuse it. You mentioned in
https://www.kernel.org/doc/Documentation/hw_random.txt
we have
"This data is NOT CHECKED by any
fitness tests, and could potentially be bogus (if the
hardware is faulty or has been tampered with). Data is only
output if the hardware "has-data" flag is set, but nevertheless
a security-conscious person would run fitness tests on the
data before assuming it is truly random."
But this is not enough to convince upstream to switch to /dev/hwrng. I
think the
concern of users misusing the solution is a very valid concern.
2) If we set the entropy to zero in rng-tools, we cannot tolerate the
load.
Rng-tools is not a timer-based solution. Similar to our solution, it is
based on
/proc/sys/kernel/random/write_wakeup_threshold. If we do not increase
the entropy
counter, rng-tools keep writing into the pool, and both rng-tools and
WiFi chip will
be overloaded.
Thanks,
Miaoqing
^ permalink raw reply
* Re: [PATCH v2] RANDOM: ATH9K RNG delivers zero bits of entropy
From: Theodore Ts'o @ 2016-08-10 23:44 UTC (permalink / raw)
To: Jason Cooper
Cc: Pan, Miaoqing, Stephan Mueller, Sepehrdad, Pouyan,
herbert@gondor.apana.org.au, linux-kernel@vger.kernel.org,
linux-crypto@vger.kernel.org, ath9k-devel,
linux-wireless@vger.kernel.org, ath9k-devel@lists.ath9k.org,
Kalle Valo
In-Reply-To: <20160809140444.GB2013@io.lakedaemon.net>
On Tue, Aug 09, 2016 at 02:04:44PM +0000, Jason Cooper wrote:
>
> iiuc, Ted, you're saying using the hw_random framework would be
> disasterous because despite most drivers having a default quality of 0,
> rngd assumes 1 bit of entropy for every bit read?
Sorry, what I was trying to say (but failed) was that bypassing the
hwrng framework and injecting entropy directly the entropy pool was
disatrous.
> Thankfully, most hw_random drivers don't set the quality. So unless the
> user sets the default_quality param, it's zero.
The fact that this is "most" and not "all" does scare me a little.
As far as I'm concerned *all* hw_random drivers should set quality to
zero, since it should be up to the system administrator. Perhaps the
one exception is virtio_rng, since if you don't trust the hypvervisor,
the security of the VM is hopeless. That being said, I have seen
configurations of KVM which use:
-object rng-random,filename=/dev/urandom,id=rng0 \
-device virtio-rng-pci,rng=rng0
Which is somewhat non-ideal. (Try running od -x /dev/random on such a
guest system....)
- Ted
^ permalink raw reply
* Re: [PATCH] crypto: XTS - remove test that will fail in FIPS mode
From: Tapas Sarangi @ 2016-08-10 22:08 UTC (permalink / raw)
To: Stephan Mueller, herbert@gondor.apana.org.au; +Cc: linux-crypto@vger.kernel.org
In-Reply-To: <3590892.3HIz2aNZPY@positron.chronox.de>
Hi Stephan,
Thanks. Sorry for a late reply to this.
I did test your patch for testmgr.h with the vanilla kernel 4.7 source.
This doesn¹t solve the xts(aes) self-test failure in FIPS mode. I get the
exact same error as before.
Thanks
-Tapas
On 8/10/16, 12:49 AM, "Stephan Mueller" <smueller@chronox.de> wrote:
>Hi Tapas, Herbert,
>
>Tapas: this patch should fix it. Can you please test?
>
>Herbert: The reason why I have to caught this issue in my tests is the
>following: I compile xts-aes-aesni statically as you can see below. The
>self test is marked as passed, although there is no XTS test performed.
>When you boot in FIPS mode, the testmgr prints out all tests. But XTS is
>not among them. Do you have an idea why that happens?
>
>name : xts(aes)
>driver : xts-aes-aesni
>module : kernel
>priority : 400
>refcnt : 1
>selftest : passed
>internal : no
>type : ablkcipher
>async : yes
>blocksize : 16
>min keysize : 32
>max keysize : 64
>ivsize : 16
>geniv : <default>
>
>---8<---
>
>In FIPS mode, setting XTS keys where the AES key is identical to the
>tweak key is forbidden. Thus, the self test with such property will fail
>in FIPS mode.
>
>As we have other tests available for XTS, this patch simply removes the
>offending test vectors.
>
>Reported-by: Tapas Sarangi <TSarangi@trustwave.com>
>Signed-off-by: Stephan Mueller <smueller@chronox.de>
>---
> crypto/testmgr.h | 36 ------------------------------------
> 1 file changed, 36 deletions(-)
>
>diff --git a/crypto/testmgr.h b/crypto/testmgr.h
>index acb6bbf..e4b58f5 100644
>--- a/crypto/testmgr.h
>+++ b/crypto/testmgr.h
>@@ -10179,24 +10179,6 @@ static struct cipher_testvec
>tf_lrw_dec_tv_template[] = {
> static struct cipher_testvec tf_xts_enc_tv_template[] = {
> /* Generated from AES-XTS test vectors */
> {
>- .key = "\x00\x00\x00\x00\x00\x00\x00\x00"
>- "\x00\x00\x00\x00\x00\x00\x00\x00"
>- "\x00\x00\x00\x00\x00\x00\x00\x00"
>- "\x00\x00\x00\x00\x00\x00\x00\x00",
>- .klen = 32,
>- .iv = "\x00\x00\x00\x00\x00\x00\x00\x00"
>- "\x00\x00\x00\x00\x00\x00\x00\x00",
>- .input = "\x00\x00\x00\x00\x00\x00\x00\x00"
>- "\x00\x00\x00\x00\x00\x00\x00\x00"
>- "\x00\x00\x00\x00\x00\x00\x00\x00"
>- "\x00\x00\x00\x00\x00\x00\x00\x00",
>- .ilen = 32,
>- .result = "\x4b\xc9\x44\x4a\x11\xa3\xef\xac"
>- "\x30\x74\xe4\x44\x52\x77\x97\x43"
>- "\xa7\x60\xb2\x45\x2e\xf9\x00\x90"
>- "\x9f\xaa\xfd\x89\x6e\x9d\x4a\xe0",
>- .rlen = 32,
>- }, {
> .key = "\x11\x11\x11\x11\x11\x11\x11\x11"
> "\x11\x11\x11\x11\x11\x11\x11\x11"
> "\x22\x22\x22\x22\x22\x22\x22\x22"
>@@ -10522,24 +10504,6 @@ static struct cipher_testvec
>tf_xts_dec_tv_template[] = {
> /* Generated from AES-XTS test vectors */
> /* same as enc vectors with input and result reversed */
> {
>- .key = "\x00\x00\x00\x00\x00\x00\x00\x00"
>- "\x00\x00\x00\x00\x00\x00\x00\x00"
>- "\x00\x00\x00\x00\x00\x00\x00\x00"
>- "\x00\x00\x00\x00\x00\x00\x00\x00",
>- .klen = 32,
>- .iv = "\x00\x00\x00\x00\x00\x00\x00\x00"
>- "\x00\x00\x00\x00\x00\x00\x00\x00",
>- .input = "\x4b\xc9\x44\x4a\x11\xa3\xef\xac"
>- "\x30\x74\xe4\x44\x52\x77\x97\x43"
>- "\xa7\x60\xb2\x45\x2e\xf9\x00\x90"
>- "\x9f\xaa\xfd\x89\x6e\x9d\x4a\xe0",
>- .ilen = 32,
>- .result = "\x00\x00\x00\x00\x00\x00\x00\x00"
>- "\x00\x00\x00\x00\x00\x00\x00\x00"
>- "\x00\x00\x00\x00\x00\x00\x00\x00"
>- "\x00\x00\x00\x00\x00\x00\x00\x00",
>- .rlen = 32,
>- }, {
> .key = "\x11\x11\x11\x11\x11\x11\x11\x11"
> "\x11\x11\x11\x11\x11\x11\x11\x11"
> "\x22\x22\x22\x22\x22\x22\x22\x22"
>--
>2.7.4
>
>
________________________________
This transmission may contain information that is privileged, confidential, and/or exempt from disclosure under applicable law. If you are not the intended recipient, you are hereby notified that any disclosure, copying, distribution, or use of the information contained herein (including any reliance thereon) is strictly prohibited. If you received this transmission in error, please immediately contact the sender and destroy the material in its entirety, whether in electronic or hard copy format.
^ permalink raw reply
* [PATCH] crypto: CCP - build error: label 'e_hwrng' undefined
From: Gary R Hook @ 2016-08-10 17:45 UTC (permalink / raw)
To: linux-crypto; +Cc: thomas.lendacky, gary.hook, herbert, davem
Fix goto target for when registration fails
Reported-by: kbuild test robot <fengguang.wu@intel.com>
Signed-off-by: Gary R Hook <gary.hook@amd.com>
---
drivers/crypto/ccp/ccp-dev-v5.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/crypto/ccp/ccp-dev-v5.c b/drivers/crypto/ccp/ccp-dev-v5.c
index 4086714..114675e 100644
--- a/drivers/crypto/ccp/ccp-dev-v5.c
+++ b/drivers/crypto/ccp/ccp-dev-v5.c
@@ -835,7 +835,7 @@ static int ccp5_init(struct ccp_device *ccp)
/* Register the DMA engine support */
ret = ccp_dmaengine_register(ccp);
if (ret)
- goto e_hwrng;
+ goto e_kthread;
return 0;
^ permalink raw reply related
* [PATCH 6/6] crypto: sun4i-ss: fix indentation of two crypto alg
From: LABBE Corentin @ 2016-08-10 9:45 UTC (permalink / raw)
To: herbert, davem, maxime.ripard, wens
Cc: linux-crypto, linux-kernel, LABBE Corentin
In-Reply-To: <1470822334-20672-1-git-send-email-clabbe.montjoie@gmail.com>
Two crypto alg are badly indented, this patch fix this style issue.
Signed-off-by: LABBE Corentin <clabbe.montjoie@gmail.com>
---
drivers/crypto/sunxi-ss/sun4i-ss-core.c | 68 ++++++++++++++++-----------------
1 file changed, 34 insertions(+), 34 deletions(-)
diff --git a/drivers/crypto/sunxi-ss/sun4i-ss-core.c b/drivers/crypto/sunxi-ss/sun4i-ss-core.c
index 107cd2a..3ac6c6c 100644
--- a/drivers/crypto/sunxi-ss/sun4i-ss-core.c
+++ b/drivers/crypto/sunxi-ss/sun4i-ss-core.c
@@ -172,45 +172,45 @@ static struct sun4i_ss_alg_template ss_algs[] = {
},
{ .type = CRYPTO_ALG_TYPE_ABLKCIPHER,
.alg.crypto = {
- .cra_name = "cbc(des3_ede)",
- .cra_driver_name = "cbc-des3-sun4i-ss",
- .cra_priority = 300,
- .cra_blocksize = DES3_EDE_BLOCK_SIZE,
- .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER,
- .cra_ctxsize = sizeof(struct sun4i_req_ctx),
- .cra_module = THIS_MODULE,
- .cra_alignmask = 3,
- .cra_type = &crypto_ablkcipher_type,
- .cra_init = sun4i_ss_cipher_init,
- .cra_u.ablkcipher = {
- .min_keysize = DES3_EDE_KEY_SIZE,
- .max_keysize = DES3_EDE_KEY_SIZE,
- .ivsize = DES3_EDE_BLOCK_SIZE,
- .setkey = sun4i_ss_des3_setkey,
- .encrypt = sun4i_ss_cbc_des3_encrypt,
- .decrypt = sun4i_ss_cbc_des3_decrypt,
+ .cra_name = "cbc(des3_ede)",
+ .cra_driver_name = "cbc-des3-sun4i-ss",
+ .cra_priority = 300,
+ .cra_blocksize = DES3_EDE_BLOCK_SIZE,
+ .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER,
+ .cra_ctxsize = sizeof(struct sun4i_req_ctx),
+ .cra_module = THIS_MODULE,
+ .cra_alignmask = 3,
+ .cra_type = &crypto_ablkcipher_type,
+ .cra_init = sun4i_ss_cipher_init,
+ .cra_u.ablkcipher = {
+ .min_keysize = DES3_EDE_KEY_SIZE,
+ .max_keysize = DES3_EDE_KEY_SIZE,
+ .ivsize = DES3_EDE_BLOCK_SIZE,
+ .setkey = sun4i_ss_des3_setkey,
+ .encrypt = sun4i_ss_cbc_des3_encrypt,
+ .decrypt = sun4i_ss_cbc_des3_decrypt,
}
}
},
{ .type = CRYPTO_ALG_TYPE_ABLKCIPHER,
.alg.crypto = {
- .cra_name = "ecb(des3_ede)",
- .cra_driver_name = "ecb-des3-sun4i-ss",
- .cra_priority = 300,
- .cra_blocksize = DES3_EDE_BLOCK_SIZE,
- .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER,
- .cra_ctxsize = sizeof(struct sun4i_req_ctx),
- .cra_module = THIS_MODULE,
- .cra_alignmask = 3,
- .cra_type = &crypto_ablkcipher_type,
- .cra_init = sun4i_ss_cipher_init,
- .cra_u.ablkcipher = {
- .min_keysize = DES3_EDE_KEY_SIZE,
- .max_keysize = DES3_EDE_KEY_SIZE,
- .ivsize = DES3_EDE_BLOCK_SIZE,
- .setkey = sun4i_ss_des3_setkey,
- .encrypt = sun4i_ss_ecb_des3_encrypt,
- .decrypt = sun4i_ss_ecb_des3_decrypt,
+ .cra_name = "ecb(des3_ede)",
+ .cra_driver_name = "ecb-des3-sun4i-ss",
+ .cra_priority = 300,
+ .cra_blocksize = DES3_EDE_BLOCK_SIZE,
+ .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER,
+ .cra_ctxsize = sizeof(struct sun4i_req_ctx),
+ .cra_module = THIS_MODULE,
+ .cra_alignmask = 3,
+ .cra_type = &crypto_ablkcipher_type,
+ .cra_init = sun4i_ss_cipher_init,
+ .cra_u.ablkcipher = {
+ .min_keysize = DES3_EDE_KEY_SIZE,
+ .max_keysize = DES3_EDE_KEY_SIZE,
+ .ivsize = DES3_EDE_BLOCK_SIZE,
+ .setkey = sun4i_ss_des3_setkey,
+ .encrypt = sun4i_ss_ecb_des3_encrypt,
+ .decrypt = sun4i_ss_ecb_des3_decrypt,
}
}
},
--
2.7.3
^ permalink raw reply related
* [cryptodev:master 17/45] drivers/crypto/ccp/ccp-dev-v5.c:838:3: error: label 'e_hwrng' used but not defined
From: kbuild test robot @ 2016-08-10 15:30 UTC (permalink / raw)
To: Gary R Hook; +Cc: kbuild-all, linux-crypto, Herbert Xu
[-- Attachment #1: Type: text/plain, Size: 1266 bytes --]
tree: https://git.kernel.org/pub/scm/linux/kernel/git/herbert/cryptodev-2.6.git master
head: 47856204146ba6fd0f198dbb23c4ed7ad1c3fd99
commit: 99d90b2ebd8b327c0c496798db99009b30c70945 [17/45] crypto: ccp - Enable DMA service on a v5 CCP
config: i386-randconfig-h1-08102150 (attached as .config)
compiler: gcc-6 (Debian 6.1.1-9) 6.1.1 20160705
reproduce:
git checkout 99d90b2ebd8b327c0c496798db99009b30c70945
# save the attached .config to linux build tree
make ARCH=i386
Note: the cryptodev/master HEAD 47856204146ba6fd0f198dbb23c4ed7ad1c3fd99 builds fine.
It only hurts bisectibility.
All errors (new ones prefixed by >>):
drivers/crypto/ccp/ccp-dev-v5.c: In function 'ccp5_init':
>> drivers/crypto/ccp/ccp-dev-v5.c:838:3: error: label 'e_hwrng' used but not defined
goto e_hwrng;
^~~~
vim +/e_hwrng +838 drivers/crypto/ccp/ccp-dev-v5.c
832 if (ret)
833 goto e_kthread;
834
835 /* Register the DMA engine support */
836 ret = ccp_dmaengine_register(ccp);
837 if (ret)
> 838 goto e_hwrng;
839
840 return 0;
841
---
0-DAY kernel test infrastructure Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all Intel Corporation
[-- Attachment #2: .config.gz --]
[-- Type: application/octet-stream, Size: 27609 bytes --]
^ permalink raw reply
* [PATCH] crypto: XTS - remove test that will fail in FIPS mode
From: Stephan Mueller @ 2016-08-10 5:49 UTC (permalink / raw)
To: Tapas Sarangi, herbert@gondor.apana.org.au; +Cc: linux-crypto@vger.kernel.org
In-Reply-To: <D3CFBBE7.2B1D%tsarangi@trustwave.com>
Hi Tapas, Herbert,
Tapas: this patch should fix it. Can you please test?
Herbert: The reason why I have to caught this issue in my tests is the following: I compile xts-aes-aesni statically as you can see below. The self test is marked as passed, although there is no XTS test performed. When you boot in FIPS mode, the testmgr prints out all tests. But XTS is not among them. Do you have an idea why that happens?
name : xts(aes)
driver : xts-aes-aesni
module : kernel
priority : 400
refcnt : 1
selftest : passed
internal : no
type : ablkcipher
async : yes
blocksize : 16
min keysize : 32
max keysize : 64
ivsize : 16
geniv : <default>
---8<---
In FIPS mode, setting XTS keys where the AES key is identical to the
tweak key is forbidden. Thus, the self test with such property will fail
in FIPS mode.
As we have other tests available for XTS, this patch simply removes the
offending test vectors.
Reported-by: Tapas Sarangi <TSarangi@trustwave.com>
Signed-off-by: Stephan Mueller <smueller@chronox.de>
---
crypto/testmgr.h | 36 ------------------------------------
1 file changed, 36 deletions(-)
diff --git a/crypto/testmgr.h b/crypto/testmgr.h
index acb6bbf..e4b58f5 100644
--- a/crypto/testmgr.h
+++ b/crypto/testmgr.h
@@ -10179,24 +10179,6 @@ static struct cipher_testvec tf_lrw_dec_tv_template[] = {
static struct cipher_testvec tf_xts_enc_tv_template[] = {
/* Generated from AES-XTS test vectors */
{
- .key = "\x00\x00\x00\x00\x00\x00\x00\x00"
- "\x00\x00\x00\x00\x00\x00\x00\x00"
- "\x00\x00\x00\x00\x00\x00\x00\x00"
- "\x00\x00\x00\x00\x00\x00\x00\x00",
- .klen = 32,
- .iv = "\x00\x00\x00\x00\x00\x00\x00\x00"
- "\x00\x00\x00\x00\x00\x00\x00\x00",
- .input = "\x00\x00\x00\x00\x00\x00\x00\x00"
- "\x00\x00\x00\x00\x00\x00\x00\x00"
- "\x00\x00\x00\x00\x00\x00\x00\x00"
- "\x00\x00\x00\x00\x00\x00\x00\x00",
- .ilen = 32,
- .result = "\x4b\xc9\x44\x4a\x11\xa3\xef\xac"
- "\x30\x74\xe4\x44\x52\x77\x97\x43"
- "\xa7\x60\xb2\x45\x2e\xf9\x00\x90"
- "\x9f\xaa\xfd\x89\x6e\x9d\x4a\xe0",
- .rlen = 32,
- }, {
.key = "\x11\x11\x11\x11\x11\x11\x11\x11"
"\x11\x11\x11\x11\x11\x11\x11\x11"
"\x22\x22\x22\x22\x22\x22\x22\x22"
@@ -10522,24 +10504,6 @@ static struct cipher_testvec tf_xts_dec_tv_template[] = {
/* Generated from AES-XTS test vectors */
/* same as enc vectors with input and result reversed */
{
- .key = "\x00\x00\x00\x00\x00\x00\x00\x00"
- "\x00\x00\x00\x00\x00\x00\x00\x00"
- "\x00\x00\x00\x00\x00\x00\x00\x00"
- "\x00\x00\x00\x00\x00\x00\x00\x00",
- .klen = 32,
- .iv = "\x00\x00\x00\x00\x00\x00\x00\x00"
- "\x00\x00\x00\x00\x00\x00\x00\x00",
- .input = "\x4b\xc9\x44\x4a\x11\xa3\xef\xac"
- "\x30\x74\xe4\x44\x52\x77\x97\x43"
- "\xa7\x60\xb2\x45\x2e\xf9\x00\x90"
- "\x9f\xaa\xfd\x89\x6e\x9d\x4a\xe0",
- .ilen = 32,
- .result = "\x00\x00\x00\x00\x00\x00\x00\x00"
- "\x00\x00\x00\x00\x00\x00\x00\x00"
- "\x00\x00\x00\x00\x00\x00\x00\x00"
- "\x00\x00\x00\x00\x00\x00\x00\x00",
- .rlen = 32,
- }, {
.key = "\x11\x11\x11\x11\x11\x11\x11\x11"
"\x11\x11\x11\x11\x11\x11\x11\x11"
"\x22\x22\x22\x22\x22\x22\x22\x22"
--
2.7.4
^ permalink raw reply related
* Re: [PATCH 2/2] ath9k: disable RNG by default
From: Stephan Mueller @ 2016-08-10 6:51 UTC (permalink / raw)
To: Pan, Miaoqing
Cc: Herbert Xu, Matt Mackall, miaoqing@codeaurora.org, Valo, Kalle,
linux-wireless@vger.kernel.org, ath9k-devel,
linux-crypto@vger.kernel.org, jason@lakedaemon.net,
Sepehrdad, Pouyan
In-Reply-To: <82844e4b56c9475fabf22b3fe12b53bb@aptaiexm02f.ap.qualcomm.com>
Am Mittwoch, 10. August 2016, 06:46:31 CEST schrieb Pan, Miaoqing:
Hi Miaoqing,
> Hi Stephan,
>
> Would you please provide a recent NIST document which asks the entropy
> source to pass the NIST randomness tests ?
See FIPS 140-2 IG 7.15 which explicitly references SP800-22.
Ciao
Stephan
^ permalink raw reply
* [PATCH 3/6] crypto: sun4i-ss: clean unused ss
From: LABBE Corentin @ 2016-08-10 9:45 UTC (permalink / raw)
To: herbert, davem, maxime.ripard, wens
Cc: linux-crypto, linux-kernel, LABBE Corentin
In-Reply-To: <1470822334-20672-1-git-send-email-clabbe.montjoie@gmail.com>
The ss variable is never used, remove it.
Signed-off-by: LABBE Corentin <clabbe.montjoie@gmail.com>
---
drivers/crypto/sunxi-ss/sun4i-ss-hash.c | 2 --
1 file changed, 2 deletions(-)
diff --git a/drivers/crypto/sunxi-ss/sun4i-ss-hash.c b/drivers/crypto/sunxi-ss/sun4i-ss-hash.c
index 2fb0684..7841d73 100644
--- a/drivers/crypto/sunxi-ss/sun4i-ss-hash.c
+++ b/drivers/crypto/sunxi-ss/sun4i-ss-hash.c
@@ -32,12 +32,10 @@ int sun4i_hash_init(struct ahash_request *areq)
struct crypto_ahash *tfm = crypto_ahash_reqtfm(areq);
struct ahash_alg *alg = __crypto_ahash_alg(tfm->base.__crt_alg);
struct sun4i_ss_alg_template *algt;
- struct sun4i_ss_ctx *ss;
memset(op, 0, sizeof(struct sun4i_req_ctx));
algt = container_of(alg, struct sun4i_ss_alg_template, alg.hash);
- ss = algt->ss;
op->ss = algt->ss;
op->mode = algt->mode;
--
2.7.3
^ permalink raw reply related
* [PATCH 1/6] crypto: sun4i-ss: fix a few signed warning
From: LABBE Corentin @ 2016-08-10 9:45 UTC (permalink / raw)
To: herbert, davem, maxime.ripard, wens
Cc: linux-crypto, linux-kernel, LABBE Corentin
The variable i is always checked against unsigned value and cannot be
negative.
This patch set it as unsigned.
Signed-off-by: LABBE Corentin <clabbe.montjoie@gmail.com>
---
drivers/crypto/sunxi-ss/sun4i-ss-cipher.c | 6 ++++--
1 file changed, 4 insertions(+), 2 deletions(-)
diff --git a/drivers/crypto/sunxi-ss/sun4i-ss-cipher.c b/drivers/crypto/sunxi-ss/sun4i-ss-cipher.c
index 3830d7c..90efd10 100644
--- a/drivers/crypto/sunxi-ss/sun4i-ss-cipher.c
+++ b/drivers/crypto/sunxi-ss/sun4i-ss-cipher.c
@@ -29,7 +29,8 @@ static int sun4i_ss_opti_poll(struct ablkcipher_request *areq)
u32 tx_cnt = 0;
u32 spaces;
u32 v;
- int i, err = 0;
+ int err = 0;
+ unsigned int i;
unsigned int ileft = areq->nbytes;
unsigned int oleft = areq->nbytes;
unsigned int todo;
@@ -139,7 +140,8 @@ static int sun4i_ss_cipher_poll(struct ablkcipher_request *areq)
u32 tx_cnt = 0;
u32 v;
u32 spaces;
- int i, err = 0;
+ int err = 0;
+ unsigned int i;
unsigned int ileft = areq->nbytes;
unsigned int oleft = areq->nbytes;
unsigned int todo;
--
2.7.3
^ permalink raw reply related
* Re: [cryptodev:master 17/45] drivers/crypto/ccp/ccp-dev-v5.c:838:3: error: label 'e_hwrng' used but not defined
From: Gary R Hook @ 2016-08-10 16:48 UTC (permalink / raw)
To: linux-crypto; +Cc: Herbert Xu
In-Reply-To: <201608102355.WhiXil4y%fengguang.wu@intel.com>
A patch for this will be submitted shortly.
On 08/10/2016 10:30 AM, kbuild test robot wrote:
> tree: https://git.kernel.org/pub/scm/linux/kernel/git/herbert/cryptodev-2.6.git master
> head: 47856204146ba6fd0f198dbb23c4ed7ad1c3fd99
> commit: 99d90b2ebd8b327c0c496798db99009b30c70945 [17/45] crypto: ccp - Enable DMA service on a v5 CCP
> config: i386-randconfig-h1-08102150 (attached as .config)
> compiler: gcc-6 (Debian 6.1.1-9) 6.1.1 20160705
> reproduce:
> git checkout 99d90b2ebd8b327c0c496798db99009b30c70945
> # save the attached .config to linux build tree
> make ARCH=i386
>
> Note: the cryptodev/master HEAD 47856204146ba6fd0f198dbb23c4ed7ad1c3fd99 builds fine.
> It only hurts bisectibility.
>
> All errors (new ones prefixed by >>):
>
> drivers/crypto/ccp/ccp-dev-v5.c: In function 'ccp5_init':
>>> drivers/crypto/ccp/ccp-dev-v5.c:838:3: error: label 'e_hwrng' used but not defined
> goto e_hwrng;
> ^~~~
>
> vim +/e_hwrng +838 drivers/crypto/ccp/ccp-dev-v5.c
>
> 832 if (ret)
> 833 goto e_kthread;
> 834
> 835 /* Register the DMA engine support */
> 836 ret = ccp_dmaengine_register(ccp);
> 837 if (ret)
> > 838 goto e_hwrng;
> 839
> 840 return 0;
> 841
>
> ---
> 0-DAY kernel test infrastructure Open Source Technology Center
> https://lists.01.org/pipermail/kbuild-all Intel Corporation
>
^ permalink raw reply
* [PATCH v4] KEYS: add SP800-56A KDF support for DH
From: Stephan Mueller @ 2016-08-10 5:15 UTC (permalink / raw)
To: Mat Martineau; +Cc: David Howells, keyrings, linux-crypto
In-Reply-To: <alpine.OSX.2.20.1608091546100.24354@mjmartin-mac01.local>
SP800-56A defines the use of DH with key derivation function based on a
counter. The input to the KDF is defined as (DH shared secret || other
information). The value for the "other information" is to be provided by
the caller.
The KDF is provided by the kernel crypto API. The SP800-56A KDF is equal
to the SP800-108 counter KDF. However, the caller is allowed to specify
the KDF type that he wants to use to derive the key material allowing
the use of the other KDFs provided with the kernel crypto API.
As the KDF implements the proper truncation of the DH shared secret to
the requested size, this patch fills the caller buffer up to its size.
The patch is tested with a new test added to the keyutils user space
code which uses a CAVS test vector testing the compliance with
SP800-56A.
Signed-off-by: Stephan Mueller <smueller@chronox.de>
---
Documentation/security/keys.txt | 35 ++++++++++---
include/linux/compat.h | 7 +++
include/uapi/linux/keyctl.h | 7 +++
security/keys/Kconfig | 1 +
security/keys/Makefile | 3 +-
security/keys/compat.c | 5 +-
security/keys/compat_dh.c | 36 +++++++++++++
security/keys/dh.c | 110 +++++++++++++++++++++++++++++++++++-----
security/keys/internal.h | 21 +++++++-
security/keys/keyctl.c | 2 +-
10 files changed, 201 insertions(+), 26 deletions(-)
create mode 100644 security/keys/compat_dh.c
diff --git a/Documentation/security/keys.txt b/Documentation/security/keys.txt
index 3849814..9df0605 100644
--- a/Documentation/security/keys.txt
+++ b/Documentation/security/keys.txt
@@ -827,7 +827,7 @@ The keyctl syscall functions are:
long keyctl(KEYCTL_DH_COMPUTE, struct keyctl_dh_params *params,
char *buffer, size_t buflen,
- void *reserved);
+ struct keyctl_kdf_params *kdf);
The params struct contains serial numbers for three keys:
@@ -844,18 +844,37 @@ The keyctl syscall functions are:
public key. If the base is the remote public key, the result is
the shared secret.
- The reserved argument must be set to NULL.
+ If the parameter kdf is NULL, the following applies:
- The buffer length must be at least the length of the prime, or zero.
+ - The buffer length must be at least the length of the prime, or zero.
- If the buffer length is nonzero, the length of the result is
- returned when it is successfully calculated and copied in to the
- buffer. When the buffer length is zero, the minimum required
- buffer length is returned.
+ - If the buffer length is nonzero, the length of the result is
+ returned when it is successfully calculated and copied in to the
+ buffer. When the buffer length is zero, the minimum required
+ buffer length is returned.
+
+ The kdf parameter allows the caller to apply a key derivation function
+ (KDF) on the Diffie-Hellman computation where only the result
+ of the KDF is returned to the caller. The KDF is characterized with
+ struct keyctl_kdf_params as follows:
+
+ - char *kdfname specifies the NUL terminated string identifying
+ the KDF function used from the kernel crypto API. As of now,
+ only non-keyed KDFs are supported, such as kdf_ctr(sha256),
+ kdf_fb(sha1) or kdf_dpi(sha512). The use of kdf_ctr() complies
+ with SP800-56A.
+
+ - char *otherinfo specifies the OtherInfo data as documented in
+ SP800-56A section 5.8.1.2. The length of the buffer is given with
+ otherinfolen. The format of OtherInfo is defined by the caller.
+ The otherinfo pointer may be NULL if no OtherInfo shall be used.
This function will return error EOPNOTSUPP if the key type is not
supported, error ENOKEY if the key could not be found, or error
- EACCES if the key is not readable by the caller.
+ EACCES if the key is not readable by the caller. In addition, the
+ function will return EMSGSIZE when the parameter kdf is non-NULL
+ and either the buffer length or the OtherInfo length exceeds the
+ allowed length.
===============
KERNEL SERVICES
diff --git a/include/linux/compat.h b/include/linux/compat.h
index f964ef7..00f348f 100644
--- a/include/linux/compat.h
+++ b/include/linux/compat.h
@@ -295,6 +295,13 @@ struct compat_old_sigaction {
};
#endif
+struct compat_keyctl_kdf_params {
+ compat_uptr_t kdfname;
+ compat_uptr_t otherinfo;
+ __u32 otherinfolen;
+ __u32 __spare[8];
+};
+
struct compat_statfs;
struct compat_statfs64;
struct compat_old_linux_dirent;
diff --git a/include/uapi/linux/keyctl.h b/include/uapi/linux/keyctl.h
index 86eddd6..0abe048 100644
--- a/include/uapi/linux/keyctl.h
+++ b/include/uapi/linux/keyctl.h
@@ -68,4 +68,11 @@ struct keyctl_dh_params {
__s32 base;
};
+struct keyctl_kdf_params {
+ char *kdfname;
+ char *otherinfo;
+ __u32 otherinfolen;
+ __u32 __spare[8];
+};
+
#endif /* _LINUX_KEYCTL_H */
diff --git a/security/keys/Kconfig b/security/keys/Kconfig
index f826e87..56491fe 100644
--- a/security/keys/Kconfig
+++ b/security/keys/Kconfig
@@ -90,6 +90,7 @@ config KEY_DH_OPERATIONS
bool "Diffie-Hellman operations on retained keys"
depends on KEYS
select MPILIB
+ select CRYPTO_KDF
help
This option provides support for calculating Diffie-Hellman
public keys and shared secrets using values stored as keys
diff --git a/security/keys/Makefile b/security/keys/Makefile
index 1fd4a16..57dff0c 100644
--- a/security/keys/Makefile
+++ b/security/keys/Makefile
@@ -15,7 +15,8 @@ obj-y := \
request_key.o \
request_key_auth.o \
user_defined.o
-obj-$(CONFIG_KEYS_COMPAT) += compat.o
+compat-obj-$(CONFIG_KEY_DH_OPERATIONS) += compat_dh.o
+obj-$(CONFIG_KEYS_COMPAT) += compat.o $(compat-obj-y)
obj-$(CONFIG_PROC_FS) += proc.o
obj-$(CONFIG_SYSCTL) += sysctl.o
obj-$(CONFIG_PERSISTENT_KEYRINGS) += persistent.o
diff --git a/security/keys/compat.c b/security/keys/compat.c
index 36c80bf..b674886 100644
--- a/security/keys/compat.c
+++ b/security/keys/compat.c
@@ -133,8 +133,9 @@ COMPAT_SYSCALL_DEFINE5(keyctl, u32, option,
return keyctl_get_persistent(arg2, arg3);
case KEYCTL_DH_COMPUTE:
- return keyctl_dh_compute(compat_ptr(arg2), compat_ptr(arg3),
- arg4, compat_ptr(arg5));
+ return compat_keyctl_dh_compute(compat_ptr(arg2),
+ compat_ptr(arg3),
+ arg4, compat_ptr(arg5));
default:
return -EOPNOTSUPP;
diff --git a/security/keys/compat_dh.c b/security/keys/compat_dh.c
new file mode 100644
index 0000000..dc93e95e
--- /dev/null
+++ b/security/keys/compat_dh.c
@@ -0,0 +1,36 @@
+/* 32-bit compatibility syscall for 64-bit systems for DH operations
+ *
+ * Copyright (C) 2016 Stephan Mueller <smueller@chronox.de>
+ *
+ * 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 "internal.h"
+
+/*
+ * Perform the DH computation or DH based key derivation.
+ *
+ * If successful, 0 will be returned.
+ */
+long compat_keyctl_dh_compute(struct keyctl_dh_params __user *params,
+ char __user *buffer, size_t buflen,
+ struct compat_keyctl_kdf_params __user *kdf)
+{
+ struct keyctl_kdf_params kdfcopy;
+ struct compat_keyctl_kdf_params compat_kdfcopy;
+
+ if (!kdf)
+ return __keyctl_dh_compute(params, buffer, buflen, NULL);
+
+ if (copy_from_user(&compat_kdfcopy, kdf, sizeof(compat_kdfcopy)) != 0)
+ return -EFAULT;
+
+ kdfcopy.kdfname = compat_ptr(compat_kdfcopy.kdfname);
+ kdfcopy.otherinfo = compat_ptr(compat_kdfcopy.otherinfo);
+ kdfcopy.otherinfolen = compat_kdfcopy.otherinfolen;
+
+ return __keyctl_dh_compute(params, buffer, buflen, &kdfcopy);
+}
diff --git a/security/keys/dh.c b/security/keys/dh.c
index 531ed2e..8054454 100644
--- a/security/keys/dh.c
+++ b/security/keys/dh.c
@@ -77,9 +77,35 @@ error:
return ret;
}
-long keyctl_dh_compute(struct keyctl_dh_params __user *params,
- char __user *buffer, size_t buflen,
- void __user *reserved)
+static int keyctl_dh_compute_kdf(struct crypto_rng *tfm,
+ char __user *buffer, size_t buflen,
+ uint8_t *kbuf, size_t kbuflen)
+{
+ uint8_t *outbuf = NULL;
+ int ret;
+
+ outbuf = kmalloc(buflen, GFP_KERNEL);
+ if (!outbuf) {
+ ret = -ENOMEM;
+ goto err;
+ }
+
+ ret = crypto_rng_generate(tfm, kbuf, kbuflen, outbuf, buflen);
+ if (ret)
+ goto err;
+
+ ret = buflen;
+ if (copy_to_user(buffer, outbuf, buflen) != 0)
+ ret = -EFAULT;
+
+err:
+ kzfree(outbuf);
+ return ret;
+}
+
+long __keyctl_dh_compute(struct keyctl_dh_params __user *params,
+ char __user *buffer, size_t buflen,
+ struct keyctl_kdf_params *kdfcopy)
{
long ret;
MPI base, private, prime, result;
@@ -88,6 +114,7 @@ long keyctl_dh_compute(struct keyctl_dh_params __user *params,
uint8_t *kbuf;
ssize_t keylen;
size_t resultlen;
+ struct crypto_rng *tfm = NULL;
if (!params || (!buffer && buflen)) {
ret = -EINVAL;
@@ -98,12 +125,36 @@ long keyctl_dh_compute(struct keyctl_dh_params __user *params,
goto out;
}
- if (reserved) {
- ret = -EINVAL;
- goto out;
+ if (kdfcopy) {
+ char *kdfname;
+
+ if (buflen > KEYCTL_KDF_MAX_OUTPUT_LEN ||
+ kdfcopy->otherinfolen > KEYCTL_KDF_MAX_OI_LEN) {
+ ret = -EMSGSIZE;
+ goto out;
+ }
+
+ /* get KDF name string */
+ kdfname = strndup_user(kdfcopy->kdfname, CRYPTO_MAX_ALG_NAME);
+ if (IS_ERR(kdfname)) {
+ ret = PTR_ERR(kdfname);
+ goto out;
+ }
+
+ /* allocate KDF from the kernel crypto API */
+ tfm = crypto_alloc_rng(kdfname, 0, 0);
+ kfree(kdfname);
+ if (IS_ERR(tfm)) {
+ ret = PTR_ERR(tfm);
+ goto out;
+ }
}
- keylen = mpi_from_key(pcopy.prime, buflen, &prime);
+ /*
+ * If the caller requests postprocessing with a KDF, allow an
+ * arbitrary output buffer size since the KDF ensures proper truncation.
+ */
+ keylen = mpi_from_key(pcopy.prime, kdfcopy ? SIZE_MAX : buflen, &prime);
if (keylen < 0 || !prime) {
/* buflen == 0 may be used to query the required buffer size,
* which is the prime key length.
@@ -133,12 +184,25 @@ long keyctl_dh_compute(struct keyctl_dh_params __user *params,
goto error3;
}
- kbuf = kmalloc(resultlen, GFP_KERNEL);
+ /* allocate space for DH shared secret and SP800-56A otherinfo */
+ kbuf = kmalloc(kdfcopy ? (resultlen + kdfcopy->otherinfolen) : resultlen,
+ GFP_KERNEL);
if (!kbuf) {
ret = -ENOMEM;
goto error4;
}
+ /*
+ * Concatenate SP800-56A otherinfo past DH shared secret -- the
+ * input to the KDF is (DH shared secret || otherinfo)
+ */
+ if (kdfcopy && kdfcopy->otherinfo &&
+ copy_from_user(kbuf + resultlen, kdfcopy->otherinfo,
+ kdfcopy->otherinfolen) != 0) {
+ ret = -EFAULT;
+ goto error5;
+ }
+
ret = do_dh(result, base, private, prime);
if (ret)
goto error5;
@@ -147,12 +211,17 @@ long keyctl_dh_compute(struct keyctl_dh_params __user *params,
if (ret != 0)
goto error5;
- ret = nbytes;
- if (copy_to_user(buffer, kbuf, nbytes) != 0)
- ret = -EFAULT;
+ if (kdfcopy) {
+ ret = keyctl_dh_compute_kdf(tfm, buffer, buflen, kbuf,
+ resultlen + kdfcopy->otherinfolen);
+ } else {
+ ret = nbytes;
+ if (copy_to_user(buffer, kbuf, nbytes) != 0)
+ ret = -EFAULT;
+ }
error5:
- kfree(kbuf);
+ kzfree(kbuf);
error4:
mpi_free(result);
error3:
@@ -162,5 +231,22 @@ error2:
error1:
mpi_free(prime);
out:
+ if (tfm)
+ crypto_free_rng(tfm);
return ret;
}
+
+long keyctl_dh_compute(struct keyctl_dh_params __user *params,
+ char __user *buffer, size_t buflen,
+ struct keyctl_kdf_params __user *kdf)
+{
+ struct keyctl_kdf_params kdfcopy;
+
+ if (!kdf)
+ return __keyctl_dh_compute(params, buffer, buflen, NULL);
+
+ if (copy_from_user(&kdfcopy, kdf, sizeof(kdfcopy)) != 0)
+ return -EFAULT;
+
+ return __keyctl_dh_compute(params, buffer, buflen, &kdfcopy);
+}
diff --git a/security/keys/internal.h b/security/keys/internal.h
index a705a7d..cb5aec9 100644
--- a/security/keys/internal.h
+++ b/security/keys/internal.h
@@ -16,6 +16,8 @@
#include <linux/key-type.h>
#include <linux/task_work.h>
#include <linux/keyctl.h>
+#include <crypto/rng.h>
+#include <linux/compat.h>
struct iovec;
@@ -260,14 +262,29 @@ static inline long keyctl_get_persistent(uid_t uid, key_serial_t destring)
#ifdef CONFIG_KEY_DH_OPERATIONS
extern long keyctl_dh_compute(struct keyctl_dh_params __user *, char __user *,
- size_t, void __user *);
+ size_t, struct keyctl_kdf_params __user *);
+extern long __keyctl_dh_compute(struct keyctl_dh_params __user *, char __user *,
+ size_t, struct keyctl_kdf_params *);
+extern long compat_keyctl_dh_compute(struct keyctl_dh_params __user *params,
+ char __user *buffer, size_t buflen,
+ struct compat_keyctl_kdf_params __user *kdf);
+#define KEYCTL_KDF_MAX_OUTPUT_LEN 1024 /* max length of KDF output */
+#define KEYCTL_KDF_MAX_OI_LEN 64 /* max length of otherinfo */
#else
static inline long keyctl_dh_compute(struct keyctl_dh_params __user *params,
char __user *buffer, size_t buflen,
- void __user *reserved)
+ struct keyctl_kdf_params __user *kdf)
{
return -EOPNOTSUPP;
}
+
+static inline long compat_keyctl_dh_compute(
+ struct keyctl_dh_params __user *params,
+ char __user *buffer, size_t buflen,
+ struct keyctl_kdf_params __user *kdf)
+{
+ return -EOPNOTSUPP
+}
#endif
/*
diff --git a/security/keys/keyctl.c b/security/keys/keyctl.c
index d580ad0..b106898 100644
--- a/security/keys/keyctl.c
+++ b/security/keys/keyctl.c
@@ -1689,7 +1689,7 @@ SYSCALL_DEFINE5(keyctl, int, option, unsigned long, arg2, unsigned long, arg3,
case KEYCTL_DH_COMPUTE:
return keyctl_dh_compute((struct keyctl_dh_params __user *) arg2,
(char __user *) arg3, (size_t) arg4,
- (void __user *) arg5);
+ (struct keyctl_kdf_params __user *) arg5);
default:
return -EOPNOTSUPP;
--
2.7.4
^ permalink raw reply related
* Re: [PATCH 2/2] ath9k: disable RNG by default
From: Stephan Mueller @ 2016-08-10 6:25 UTC (permalink / raw)
To: Pan, Miaoqing
Cc: Herbert Xu, Matt Mackall, miaoqing@codeaurora.org, Valo, Kalle,
linux-wireless@vger.kernel.org, ath9k-devel,
linux-crypto@vger.kernel.org, jason@lakedaemon.net,
Sepehrdad, Pouyan
In-Reply-To: <866e31b50f364a87aabe94d2af03ecb8@aptaiexm02f.ap.qualcomm.com>
Am Mittwoch, 10. August 2016, 06:04:32 CEST schrieb Pan, Miaoqing:
Hi Miaoqing,
> Hi Stephan,
>
> FIPS RNG test is supposed to be run on the output of an RNG, and not on the
> RNG entropy source. It is not surprising that the RNG input fails the
> entropy tests from NIST. Check the following example.
>
> Imagine you have a perfectly random sequence, a_1, a_2, .., a_n, where each
> a_i is a byte. And imagine, this sequence passes all randomness tests.
>
> Now, let's say I create a new sequence a_1, 0, a_2, 0, a_3, 0, ..., 0, a_n,
> where each zero is a byte
>
> If you give this sequence (as an entropy source) to a randomness test, it
> will fail most of the tests, if not all. This does not mean this sequence
> is not appropriate as an entropy source, it just means we need twice more
> bytes to gain the same amount of entropy.
Agreed. But that is a very simplistic view.
>
> I can give this 2n byte sequence to an RNG as an entropy source and it
> provides the same amount of security as if I give the n byte stream.
Well, I am working with standards bodies like NIST and BSI on RNG
assessments. They all require that the noise source (pre-whitening, of
course) pass statistical tests like the AIS20 tests, SP800-22 and similar. If
you fail, you better have a good argument.
And the only argument that is kind of allowed is that you oversample your
noise source to seed a DRNG from (i.e. have an entropy to data ratio of
significantly below 1). And the argument for the oversampling rate is always
a very interesting discussion. You apply 10/32. In private, I am wondering
about that ratio, but this should not be discussed here as I hope you have a
valid argument for that.
As we are talking about the current rngd, we have to consider that it does
*not* perform an oversampling (yet) as mentioned in the previous emails.
Do not get me wrong on my initial patch: your RNG may provide some entropy.
But there are quite some folks who want to understand and audit a noise
source before using it. Your current implementation simply does not allow
switching the noise source off to feed the input_pool with data that
increases the entropy estimator (at runtime).
Ciao
Stephan
^ permalink raw reply
* [PATCH v4] DH support: add KDF handling support
From: Stephan Mueller @ 2016-08-10 5:16 UTC (permalink / raw)
To: Mat Martineau; +Cc: David Howells, keyrings, linux-crypto
In-Reply-To: <alpine.OSX.2.20.1608091536470.24354@mjmartin-mac01.local>
Add the interface logic to support DH with KDF handling support.
The dh_compute code now allows the following options:
- no KDF support / output of raw DH shared secret:
dh_compute <private> <prime> <base>
- KDF support without "other information" string:
dh_compute_kdf <private> <prime> <base> <output length> <KDF type>
- KDF support with "other information string:
dh_compute_kdf_oi <private> <prime> <base> <output length> <KDF type>
where the OI string is provided on STDIN.
The test to verify the code is based on a test vector used for the CAVS
testing of SP800-56A.
Signed-off-by: Stephan Mueller <smueller@chronox.de>
---
Makefile | 1 +
keyctl.c | 133 ++++++++++++++++++++++++
keyutils.c | 14 +++
keyutils.h | 11 ++
man/keyctl_dh_compute.3 | 58 +++++++++++
tests/keyctl/dh_compute/valid/runtest.sh | 168 +++++++++++++++++++++++++++++++
tests/toolbox.inc.sh | 44 ++++++++
version.lds | 2 +
8 files changed, 431 insertions(+)
diff --git a/Makefile b/Makefile
index 824bbbf..90fc33f 100644
--- a/Makefile
+++ b/Makefile
@@ -195,6 +195,7 @@ endif
$(LNS) keyctl_read.3 $(DESTDIR)$(MAN3)/keyctl_read_alloc.3
$(LNS) recursive_key_scan.3 $(DESTDIR)$(MAN3)/recursive_session_key_scan.3
$(LNS) keyctl_dh_compute.3 $(DESTDIR)$(MAN3)/keyctl_dh_compute_alloc.3
+ $(LNS) keyctl_dh_compute.3 $(DESTDIR)$(MAN3)/keyctl_dh_compute_kdf.3
$(INSTALL) -D -m 0644 keyutils.h $(DESTDIR)$(INCLUDEDIR)/keyutils.h
###############################################################################
diff --git a/keyctl.c b/keyctl.c
index edb03de..fcf2f02 100644
--- a/keyctl.c
+++ b/keyctl.c
@@ -20,6 +20,7 @@
#include <errno.h>
#include <asm/unistd.h>
#include "keyutils.h"
+#include <limits.h>
struct command {
void (*action)(int argc, char *argv[]) __attribute__((noreturn));
@@ -67,6 +68,8 @@ static nr void act_keyctl_purge(int argc, char *argv[]);
static nr void act_keyctl_invalidate(int argc, char *argv[]);
static nr void act_keyctl_get_persistent(int argc, char *argv[]);
static nr void act_keyctl_dh_compute(int argc, char *argv[]);
+static nr void act_keyctl_dh_compute_kdf(int argc, char *argv[]);
+static nr void act_keyctl_dh_compute_kdf_oi(int argc, char *argv[]);
const struct command commands[] = {
{ act_keyctl___version, "--version", "" },
@@ -76,6 +79,8 @@ const struct command commands[] = {
{ act_keyctl_clear, "clear", "<keyring>" },
{ act_keyctl_describe, "describe", "<keyring>" },
{ act_keyctl_dh_compute, "dh_compute", "<private> <prime> <base>" },
+ { act_keyctl_dh_compute_kdf, "dh_compute_kdf", "<private> <prime> <base> <len> <kdf>" },
+ { act_keyctl_dh_compute_kdf_oi, "dh_compute_kdf_oi", "<private> <prime> <base> <len> <kdf>" },
{ act_keyctl_instantiate, "instantiate","<key> <data> <keyring>" },
{ act_keyctl_invalidate,"invalidate", "<key>" },
{ act_keyctl_get_persistent, "get_persistent", "<keyring> [<uid>]" },
@@ -1663,6 +1668,7 @@ static void act_keyctl_dh_compute(int argc, char *argv[])
}
printf("%02hhx", *p);
+ *p = 0x00; /* zeroize buffer */
p++;
col++;
@@ -1674,6 +1680,133 @@ static void act_keyctl_dh_compute(int argc, char *argv[])
} while (--ret > 0);
printf("\n");
+
+ free(buffer);
+
+ exit(0);
+}
+
+static void act_keyctl_dh_compute_kdf(int argc, char *argv[])
+{
+ key_serial_t private, prime, base;
+ char *buffer;
+ char *p;
+ int ret, sep, col;
+ unsigned long buflen = 0;
+
+ if (argc != 6)
+ format();
+
+ private = get_key_id(argv[1]);
+ prime = get_key_id(argv[2]);
+ base = get_key_id(argv[3]);
+
+ buflen = strtoul(argv[4], NULL, 10);
+ if (buflen == ULONG_MAX)
+ error("dh_compute: cannot convert generated length value");
+
+ buffer = malloc(buflen);
+ if (!buffer)
+ error("dh_compute: cannot allocate memory");
+
+ ret = keyctl_dh_compute_kdf(private, prime, base, argv[5], NULL, 0,
+ buffer, buflen);
+ if (ret < 0)
+ error("keyctl_dh_compute_alloc");
+
+ /* hexdump the contents */
+ printf("%u bytes of data in result:\n", ret);
+
+ sep = 0;
+ col = 0;
+ p = buffer;
+
+ do {
+ if (sep) {
+ putchar(sep);
+ sep = 0;
+ }
+
+ printf("%02hhx", *p);
+ *p = 0x00; /* zeroize buffer */
+ p++;
+
+ col++;
+ if (col % 32 == 0)
+ sep = '\n';
+ else if (col % 4 == 0)
+ sep = ' ';
+
+ } while (--ret > 0);
+
+ printf("\n");
+
+ free(buffer);
+
+ exit(0);
+}
+
+static void act_keyctl_dh_compute_kdf_oi(int argc, char *argv[])
+{
+ key_serial_t private, prime, base;
+ char *buffer;
+ char *p;
+ int ret, sep, col;
+ unsigned long buflen = 0;
+ size_t oilen;
+ void *oi;
+
+ if (argc != 6)
+ format();
+
+ private = get_key_id(argv[1]);
+ prime = get_key_id(argv[2]);
+ base = get_key_id(argv[3]);
+
+ buflen = strtoul(argv[4], NULL, 10);
+ if (buflen == ULONG_MAX)
+ error("dh_compute: cannot convert generated length value");
+
+ buffer = malloc(buflen);
+ if (!buffer)
+ error("dh_compute: cannot allocate memory");
+
+ oi = grab_stdin(&oilen);
+
+ ret = keyctl_dh_compute_kdf(private, prime, base, argv[5], oi, oilen,
+ buffer, buflen);
+ if (ret < 0)
+ error("keyctl_dh_compute_alloc");
+
+ /* hexdump the contents */
+ printf("%u bytes of data in result:\n", ret);
+
+ sep = 0;
+ col = 0;
+ p = buffer;
+
+ do {
+ if (sep) {
+ putchar(sep);
+ sep = 0;
+ }
+
+ printf("%02hhx", *p);
+ *p = 0x00; /* zeroize buffer */
+ p++;
+
+ col++;
+ if (col % 32 == 0)
+ sep = '\n';
+ else if (col % 4 == 0)
+ sep = ' ';
+
+ } while (--ret > 0);
+
+ printf("\n");
+
+ free(buffer);
+
exit(0);
}
diff --git a/keyutils.c b/keyutils.c
index 2a69304..2c3c4e6 100644
--- a/keyutils.c
+++ b/keyutils.c
@@ -244,6 +244,20 @@ long keyctl_dh_compute(key_serial_t private, key_serial_t prime,
return keyctl(KEYCTL_DH_COMPUTE, ¶ms, buffer, buflen, 0);
}
+long keyctl_dh_compute_kdf(key_serial_t private, key_serial_t prime,
+ key_serial_t base, char *kdfname, char *otherinfo,
+ size_t otherinfolen, char *buffer, size_t buflen)
+{
+ struct keyctl_dh_params params = { .private = private,
+ .prime = prime,
+ .base = base };
+ struct keyctl_kdf_params kdfparams = { .kdfname = kdfname,
+ .otherinfo = otherinfo,
+ .otherinfolen = otherinfolen };
+
+ return keyctl(KEYCTL_DH_COMPUTE, ¶ms, buffer, buflen, &kdfparams);
+}
+
/*****************************************************************************/
/*
* fetch key description into an allocated buffer
diff --git a/keyutils.h b/keyutils.h
index b321aa8..65df9fd 100644
--- a/keyutils.h
+++ b/keyutils.h
@@ -108,6 +108,13 @@ struct keyctl_dh_params {
key_serial_t base;
};
+struct keyctl_kdf_params {
+ char *kdfname;
+ char *otherinfo;
+ uint32_t otherinfolen;
+ uint32_t __spare[8];
+};
+
/*
* syscall wrappers
*/
@@ -163,6 +170,10 @@ extern long keyctl_invalidate(key_serial_t id);
extern long keyctl_get_persistent(uid_t uid, key_serial_t id);
extern long keyctl_dh_compute(key_serial_t private, key_serial_t prime,
key_serial_t base, char *buffer, size_t buflen);
+extern long keyctl_dh_compute_kdf(key_serial_t private, key_serial_t prime,
+ key_serial_t base, char *kdfname,
+ char *otherinfo, size_t otherinfolen,
+ char *buffer, size_t buflen);
/*
* utilities
diff --git a/man/keyctl_dh_compute.3 b/man/keyctl_dh_compute.3
index b06d39e..f630dc3 100644
--- a/man/keyctl_dh_compute.3
+++ b/man/keyctl_dh_compute.3
@@ -11,6 +11,8 @@
.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
.SH NAME
keyctl_dh_compute \- Compute a Diffie-Hellman shared secret or public key
+.br
+keyctl_dh_compute_kdf \- Derive key from a Diffie-Hellman shared secret
.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
.SH SYNOPSIS
.nf
@@ -21,6 +23,10 @@ keyctl_dh_compute \- Compute a Diffie-Hellman shared secret or public key
.sp
.BI "long keyctl_dh_compute_alloc(key_serial_t " private,
.BI "key_serial_t " prime ", key_serial_t " base ", void **" _buffer ");"
+.sp
+.BI "long keyctl_dh_compute_kdf(key_serial_t " private ", key_serial_t " prime ,
+.BI "key_serial_t " base ", char *" kdfname ", char *" otherinfo ",
+.BI "size_t " otherinfolen ", char *" buffer ", size_t " buflen ");"
.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
.SH DESCRIPTION
.BR keyctl_dh_compute ()
@@ -64,6 +70,49 @@ places the data in it. If successful, a pointer to the buffer is placed in
.IR *_buffer .
The caller must free the buffer.
.P
+.BR keyctl_dh_compute_kdf ()
+derives a key from a Diffie-Hellman shared secret according to the protocol
+specified in SP800-56A. The Diffie-Hellman computation is based on the same
+primitives as discussed
+for
+.BR keyctl_dh_compute ().
+.P
+To implement the protocol of SP800-56A
+.I base
+is a key containing the remote public key to compute the Diffie-Hellman
+shared secret. That shared secret is post-processed with a key derivation
+function.
+.P
+The
+.I kdfname
+specifies the Linux kernel crypto API name for a key derivation function
+using a non-keyed hash, such as kdf_ctr(sha256). Using the counter KDF function
+specified with kdf_ctr() makes the key derivation compliant to SP800-56A.
+The
+.I kdfname
+must be a NULL terminated string.
+.P
+Following the specification of SP800-56A section 5.8.1.2 the
+.I otherinfo
+parameter may be provided. The format of the OtherInfo field is defined
+by the caller. The caller may also specify NULL as a valid argument when
+no OtherInfo data shall be processed. The length of the
+.I otherinfo
+parameter is specified with
+.I otherinfolen
+and is restricted to a maximum length by the kernel.
+.P
+The KDF returns the requested number of bytes specified with the
+.I genlen
+or the
+.I buflen
+parameter depending on the invoked function.
+.P
+.I buffer
+and
+.I buflen
+specify the buffer into which the computed result will be placed.
+.P
.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
.SH RETURN VALUE
On success
@@ -91,6 +140,15 @@ The buffer pointer is invalid or buflen is too small.
.TP
.B EOPNOTSUPP
One of the keys was not a valid user key.
+.TP
+.B EMSGSIZE
+When using
+.BR keyctl_dh_compute_kdf (),
+the size of either
+.I otherinfolen
+or
+.I buflen
+is too big.
.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
.SH LINKING
This is a library function that can be found in
diff --git a/tests/keyctl/dh_compute/valid/runtest.sh b/tests/keyctl/dh_compute/valid/runtest.sh
index f2aace6..d8e338b 100644
--- a/tests/keyctl/dh_compute/valid/runtest.sh
+++ b/tests/keyctl/dh_compute/valid/runtest.sh
@@ -84,5 +84,173 @@ expect_multiline payload "$public"
echo "++++ FINISHED TEST: $result" >>$OUTPUTFILE
+
+################################################################
+# Testing DH compute with KDF according to SP800-56A
+#
+# test vectors from http://csrc.nist.gov/groups/STM/cavp/documents/keymgmt/KASTestVectorsFFC2014.zip
+################################################################
+
+# SHA-256
+
+# XephemCAVS
+private="\x81\xb2\xc6\x5f\x5c\xba\xc0\x0b\x13\x53\xac\x38\xbd\x77\xa2\x5a"
+private+="\x86\x50\xed\x48\x5e\x41\x3e\xac\x1d\x6c\x48\x85"
+
+# P
+prime="\xa3\xcc\x62\x23\xe5\x0c\x6e\x3f\x7b\xb0\x58\x1d\xcb\x9e\x9f\xf0"
+prime+="\x2c\x58\x07\x68\x32\x8a\x15\x20\x7b\x1c\x32\x31\x7f\xb7\x84\x96"
+prime+="\x81\x5e\x3c\xf7\xf9\xd0\x9c\xcb\x9f\xa8\x40\xff\x47\x98\x51\x1a"
+prime+="\x17\xb5\x59\x28\x72\x1e\x5d\xfb\xcc\xc5\x41\x47\xe0\xf0\x5f\x85"
+prime+="\xb3\xac\x41\x0b\x6a\xe3\xf5\x9b\x79\x6f\x3f\xea\xc7\xfc\x52\x49"
+prime+="\x21\x7e\xb2\xa0\x45\x88\x29\x3a\x5a\xde\x22\x78\x79\xf4\x6c\xeb"
+prime+="\x56\x45\x7b\x5c\x43\x12\x93\xe5\xe1\x04\xd1\xb9\x64\xbd\x2c\xdf"
+prime+="\xde\xff\xa0\x40\x49\xa9\x1e\x67\xee\x8c\x86\xe9\x44\xf0\x4f\x94"
+prime+="\x4a\x30\xe3\x61\xf8\xd1\x5d\x17\xe5\x01\x0c\xab\xb4\xef\x40\xc0"
+prime+="\xeb\xa5\xf4\xa2\x52\xd4\xfd\x6c\xf9\xda\xe6\x0e\x86\xe4\xb3\x00"
+prime+="\x9b\x1d\xfc\x92\x66\x70\x35\x72\x61\x58\x7a\xd0\x5c\x00\xa6\xc6"
+prime+="\xf0\x10\x6c\xec\x8f\xc5\x91\x31\x51\x50\x84\xa8\x70\x59\x41\x65"
+prime+="\xb4\x93\x90\xdb\x2d\x00\xe7\x53\x8f\x23\x0d\x53\x2f\x4a\x4e\xca"
+prime+="\x83\x09\xd7\x07\xc0\xb3\x83\x5c\xee\x04\xf3\xca\x55\x8a\x22\xc6"
+prime+="\xb5\x20\xfe\x25\xde\x6f\xfa\x90\xef\xda\x49\x27\xd0\x18\x59\x4c"
+prime+="\x0c\x0b\x77\x06\x73\x93\xb7\xf1\xe0\xfc\x7c\xf2\x16\xaf\xf3\x9f"
+
+# YephemIUT
+xa="\x9a\x70\x82\x2d\x3f\x06\x12\x3d\x0e\x51\x8e\xe1\x16\x51\xe5\xf6"
+xa+="\xb1\x19\xdc\x3b\x97\xd5\xb1\xc0\xa2\xa6\xf6\xde\x94\x25\x64\xba"
+xa+="\x10\x06\x1e\xec\xde\xb7\x36\x9c\xa5\x37\x49\x9e\x04\xb0\x36\xe9"
+xa+="\x7f\x44\x5a\x95\x6f\x63\x69\xae\x6e\x63\xfd\x27\xea\xe3\xe3\x47"
+xa+="\x85\x54\x47\xd3\xba\xc1\xc6\x0c\x10\xe7\x35\x07\x72\xc6\xc0\xc6"
+xa+="\xfb\xf9\xca\x3e\x38\xf0\xe8\x65\x88\x25\xd3\xb2\x0f\x1f\x02\x8f"
+xa+="\x35\xe3\x4d\x12\x35\x10\x3d\xf2\x33\x9b\x5b\x09\x9d\x3f\xe3\xe5"
+xa+="\x34\x6a\x69\x16\x42\xba\xc5\xb0\xbb\x03\xcd\x5d\x04\xd7\x56\x26"
+xa+="\x21\x49\x3f\xf1\xc4\x27\x3b\x6a\x45\xc5\xec\xb0\xb5\xe9\x08\xa0"
+xa+="\xf9\xf5\x62\x28\x2e\x85\x3e\xfc\x9a\x7e\xa1\x12\xe9\x47\x4f\xf6"
+xa+="\x94\x18\xf7\xc4\x7a\xe9\x66\xd4\x52\x4c\xa1\x70\x1b\x60\xa4\xbe"
+xa+="\x15\xc7\x5e\x27\xb4\x05\x80\x64\x68\x15\x6e\x02\xcb\xc5\x8f\xf4"
+xa+="\x66\x3c\x96\xac\x0c\x87\x36\x81\x35\xfa\x9b\x0b\xb6\x33\x7a\xe2"
+xa+="\x58\x52\x1d\x7d\x60\xc2\xa9\x1b\x4e\xd7\x72\xad\x65\x03\x40\x49"
+xa+="\x97\xf6\x79\x9d\xf6\x63\xa8\x99\x9c\xfd\x74\x7f\xa0\x67\xb9\x05"
+xa+="\x8a\xb3\x3b\xc1\x45\x94\x36\x6f\x28\xf5\xa2\xd9\x00\xb6\x46\x7a"
+
+# Z
+read -d '' shared <<"EOF"
+0fdbd9a2 ebf50cba 489b4e4d 7cd6924a 42ee6324 a26988b2 22bc38e6 9cc445f1
+eb47c1a4 62eca39f 39bcd7b8 19dede51 30bc38da ec99c16f 40a4e5c1 9c97b796
+8b41823d a0650e37 13c73e6f 5f2a9dff 2e67dbf5 40ee66f4 e694c28f ba1d604b
+71b57b8a eeb67a35 ba425a38 490b6fb9 f713db22 6f893b7a 8962f426 ba3046fb
+cff8538c 16f583e8 ae947672 0ba55ff9 75b440d0 c4565cc7 5837d23a fea61a39
+e0b7f6c4 e24c2154 7eb19fce f8dbed10 b06a9cce 971c0f0f ba7c1d5c b5035eaa
+4fddd3ba fe757339 e3321e3e 4ebfe9e7 9c6c0401 4df63cf9 28d0a2c0 5b2d5521
+030c35f1 c84c97fe 64cad509 8012a003 d52d24c4 1a1f9348 b7575251 3facb02f
+EOF
+
+# OI
+otherinfo="\xa1\xb2\xc3\xd4\xe5\x43\x41\x56\x53\x69\x64\x0d\x64\xc1\xb2"
+otherinfo+="\x33\x61\xb2\x61\xde\x78\x68\x8e\xa8\x65\xfc\xff\x11\x3c\x84"
+
+# DKM
+read -d '' derived <<"EOF"
+8284e313 02c8a26b 393ec52d 9f9e0882
+EOF
+
+pcreate_key "-e $prime" user dh:prime @s
+expect_keyid primeid
+
+pcreate_key "-e $xa" user dh:xa @s
+expect_keyid xaid
+
+pcreate_key "-e $private" user dh:private @s
+expect_keyid privateid
+
+marker "COMPUTE DH SHARED SECRET"
+dh_compute $privateid $primeid $xaid
+expect_multiline payload "$shared"
+
+marker "COMPUTE DERIVED KEY FROM DH SHARED SECRET (SHA-256)"
+echo -e -n $otherinfo | dh_compute_kdf_oi $privateid $primeid $xaid 16 "kdf_ctr(sha256)"
+expect_multiline payload "$derived"
+
+
+# SHA-224
+
+# XephemCAVS
+private="\x86\x1b\xa2\x59\xab\xa6\xaa\x57\x7d\xe2\x2f\x50\x8e\xcb\xbc\x26"
+private+="\xc5\xac\xfc\xcb\x9e\xa2\x3b\x43\x4d\x6d\x2b\x79"
+
+# P
+prime="\xa5\xb1\x76\x4e\x13\xc8\x16\x99\xab\xa3\x8f\x0d\xc0\xd1\x5e\x15"
+prime+="\xf5\x0f\xcd\x5c\xf7\xc2\x23\x72\xca\xfc\x5e\xd7\x62\x94\x1b\xd9"
+prime+="\xe0\xfb\x9a\xab\xee\x74\x66\xd2\xc8\x29\xaa\xb0\x31\xdb\x7b\x1b"
+prime+="\x5a\x64\xe6\x8e\xd5\x3b\xaf\xb2\x83\xba\x0f\x01\x8b\xeb\x3e\xdc"
+prime+="\x95\x7f\xe4\x53\xbe\x0d\xaa\xb6\x1b\x32\x28\x76\x3e\x80\x75\x8c"
+prime+="\x6d\x8c\x28\x3c\xf6\x30\xed\xd9\xd7\x0a\x8a\xf3\x30\xdd\x0a\xf6"
+prime+="\xa8\xd5\x94\xc2\x3c\xdd\x24\xc8\xad\x3f\xcf\xea\x41\x75\x77\x72"
+prime+="\xce\xed\x92\x1e\x63\x86\x2f\x24\x6e\x6f\x49\xd8\x74\x7e\x44\xae"
+prime+="\xf0\x1e\x30\x9b\x6d\xcc\x80\xd4\x50\x38\x3b\xb1\xf9\x4d\xd5\x90"
+prime+="\x84\xf8\xe9\x6f\x85\x6e\xc7\xc8\x33\x5e\xdb\x05\x5f\x8e\xc6\xc4"
+prime+="\x81\x52\x0b\x3f\x28\xe8\x0b\x62\x09\xb8\xae\x61\xcc\x86\x0e\x24"
+prime+="\xc8\x22\xb6\x6c\x4f\x97\x80\x49\x93\xbc\xd0\xa9\x72\xb3\x53\x54"
+prime+="\x01\x33\x0e\xbe\x4b\x2e\x92\x3f\x18\x9b\x63\x35\x62\xe4\x68\xeb"
+prime+="\x99\xa4\xbc\x88\xcc\xbf\xf8\xdf\x0f\xd5\xaf\xcf\xe6\xae\x19\x18"
+prime+="\x42\x14\xab\x3f\xef\xb7\xf0\x66\x8b\x8b\x26\x83\xbe\xbd\x56\x51"
+prime+="\xa4\xc6\x38\x43\xb9\xb1\x4b\xc7\x38\xd5\x20\xb1\xb7\x21\x2c\x69"
+
+# YephemIUT
+xa="\x17\xd7\x1a\xf4\x35\x3c\x22\x12\x2a\xeb\x2a\x06\x19\xcc\x2c\xf7"
+xa+="\x35\x53\xf2\x8e\x9f\xb1\x91\xfd\xb2\x86\xb1\x15\xb9\xfd\xa8\x66"
+xa+="\x2d\xe5\x17\x3b\x1a\xff\x70\x48\x8d\x9b\xc8\x48\xe5\x37\xd7\xe5"
+xa+="\x02\x16\x49\xd3\x7d\xc7\x8c\x94\x36\x9d\xb9\x0c\x27\x84\xc9\x4d"
+xa+="\x97\x0a\xc9\xb5\xe3\x5e\xfd\x22\xd4\x18\xd3\x1b\x68\xd9\x55\x0b"
+xa+="\xaa\x77\x16\xe9\x8e\xa6\x78\x3b\xb3\xa8\x45\x05\x9f\xba\xa4\xa6"
+xa+="\x72\x0a\x6a\x23\xc5\x6b\xa5\x2b\x4d\x9b\x72\x6e\x00\x68\xe9\xeb"
+xa+="\x4d\x17\x5b\xff\x43\x69\xf3\xd2\xa4\xaf\x66\xee\xcd\x62\xef\x7b"
+xa+="\x23\xc3\x37\xd4\x70\x95\x2b\x17\x67\xc8\xbf\x78\x2f\x0b\x58\xb4"
+xa+="\xfc\x82\x45\xf8\x40\x78\x71\x70\xf4\xb0\xa5\x1b\x5e\xb4\x60\x75"
+xa+="\x8a\xdd\xc9\xf4\x4a\x73\xa3\xf6\x07\x60\x3b\xd3\x50\x73\xd1\xa6"
+xa+="\x9a\x20\x3a\x04\x94\xa8\xc2\x02\x1b\xa0\xda\x1f\x04\x95\xf5\x60"
+xa+="\xc0\xba\x81\x79\x4e\xee\xeb\x82\x5d\x1b\xd3\x43\x16\xa5\x2a\xe1"
+xa+="\xc9\x00\x10\x0c\x0d\x6f\xa0\x25\x46\xed\x7a\x9c\x38\xa6\xa3\x43"
+xa+="\xd6\x86\x59\xee\xb5\x9c\xf3\x81\x04\xa9\x6b\xb2\x5a\x6d\xbb\xf0"
+xa+="\xcb\xc0\xed\xe7\x3a\x7b\xba\x67\x51\x81\xe0\xcd\x2e\x7b\x9f\x89"
+
+# Z
+read -d '' shared <<"EOF"
+057c22b8 c5872fef 08ebe852 fafab4b7 c2c2ffbb 376d71bd a941b16e 32614adf
+ebb82aeb d50f29d3 cec63d10 77f50e21 cf381b87 a818c614 52c5cce2 af85f40c
+06615b97 fe8c3a80 68990ac5 83957b52 8dd6d52d a3b51e84 aec355fd 4a3fe5ce
+faa3b17c 9e71cb4d 28ecab6d 21297280 e52397b7 ccb1b62d 8d5d3ce4 1d26b2a3
+bdbf880b b39e8b02 8a745ff2 9f0984da efe97084 5d850884 525403ca d2a52956
+f55b9a89 b2d801f1 710333c0 479c5955 b54c8163 83c65ad9 c78b8c67 cc1b211b
+208b9fab b9c99a68 18293e6a 8da069e6 75eb4317 668a7d4b 6f235533 f3ff4ed0
+4f8ad579 f9ad14e7 f68ae183 41d603d9 d6297123 00716c98 bbbf16eb 2a2cc92f
+EOF
+
+# OI
+otherinfo="\xa1\xb2\xc3\xd4\xe5\x43\x41\x56\x53\x69\x64\xaa\x27\xe2\x49"
+otherinfo+="\xbf\x0a\x12\x76\x46\x8d\x80\x82\x59\xf3\xb8\xe2\x68\x78\x51"
+
+# DKM
+read -d '' derived <<"EOF"
+88bf39c0 08eec33a dc3b4430 054ba262
+EOF
+
+pcreate_key "-e $prime" user dh:prime @s
+expect_keyid primeid
+
+pcreate_key "-e $xa" user dh:xa @s
+expect_keyid xaid
+
+pcreate_key "-e $private" user dh:private @s
+expect_keyid privateid
+
+marker "COMPUTE DH SHARED SECRET"
+dh_compute $privateid $primeid $xaid
+expect_multiline payload "$shared"
+
+marker "COMPUTE DERIVED KEY FROM DH SHARED SECRET (SHA-224)"
+echo -e -n $otherinfo | dh_compute_kdf_oi $privateid $primeid $xaid 16 "kdf_ctr(sha224)"
+expect_multiline payload "$derived"
+
# --- then report the results in the database ---
toolbox_report_result $TEST $result
diff --git a/tests/toolbox.inc.sh b/tests/toolbox.inc.sh
index 7f19a02..27b253f 100644
--- a/tests/toolbox.inc.sh
+++ b/tests/toolbox.inc.sh
@@ -1106,6 +1106,50 @@ function dh_compute ()
###############################################################################
#
+# Do a DH computation post-processed by a KDF
+#
+###############################################################################
+function dh_compute_kdf ()
+{
+ my_exitval=0
+ if [ "x$1" = "x--fail" ]
+ then
+ my_exitval=1
+ shift
+ fi
+
+ echo keyctl dh_compute_kdf $@ >>$OUTPUTFILE
+ keyctl dh_compute_kdf $@ >>$OUTPUTFILE 2>&1
+ if [ $? != $my_exitval ]
+ then
+ failed
+ fi
+}
+
+###############################################################################
+#
+# Do a DH computation post-processed by a KDF with other information
+#
+###############################################################################
+function dh_compute_kdf_oi ()
+{
+ my_exitval=0
+ if [ "x$1" = "x--fail" ]
+ then
+ my_exitval=1
+ shift
+ fi
+
+ echo keyctl dh_compute_kdf_oi $@ >>$OUTPUTFILE
+ keyctl dh_compute_kdf_oi $@ >>$OUTPUTFILE 2>&1
+ if [ $? != $my_exitval ]
+ then
+ failed
+ fi
+}
+
+###############################################################################
+#
# Make sure we sleep at least N seconds
#
###############################################################################
diff --git a/version.lds b/version.lds
index 2bfed13..b8eebfb 100644
--- a/version.lds
+++ b/version.lds
@@ -66,5 +66,7 @@ KEYUTILS_1.6 {
/* management functions */
keyctl_dh_compute;
keyctl_dh_compute_alloc;
+ keyctl_dh_compute_kdf;
+ keyctl_dh_compute_kdf_alloc;
} KEYUTILS_1.5;
--
2.7.4
^ permalink raw reply related
* RE: [PATCH 2/2] ath9k: disable RNG by default
From: Pan, Miaoqing @ 2016-08-10 7:15 UTC (permalink / raw)
To: Stephan Mueller
Cc: Herbert Xu, Matt Mackall, miaoqing@codeaurora.org, Valo, Kalle,
linux-wireless@vger.kernel.org, ath9k-devel,
linux-crypto@vger.kernel.org, jason@lakedaemon.net,
Sepehrdad, Pouyan
In-Reply-To: <1526134.1iUazSISyZ@positron.chronox.de>
Hi Stephan,
NIST SP 800-22-rev1a and NIST SP 800-90B are used together to evaluate the amount of min entropy the source provides, and not to decide if the source has passed the tests or failed. See
https://github.com/usnistgov/SP800-90B_EntropyAssessment
The goal is often to make sure the input entropy is more than the entropy we expect from the output.
Thanks,
Miaoqing
-----Original Message-----
From: Stephan Mueller [mailto:smueller@chronox.de]
Sent: Wednesday, August 10, 2016 2:52 PM
To: Pan, Miaoqing <miaoqing@qti.qualcomm.com>
Cc: Herbert Xu <herbert@gondor.apana.org.au>; Matt Mackall <mpm@selenic.com>; miaoqing@codeaurora.org; Valo, Kalle <kvalo@qca.qualcomm.com>; linux-wireless@vger.kernel.org; ath9k-devel <ath9k-devel@qca.qualcomm.com>; linux-crypto@vger.kernel.org; jason@lakedaemon.net; Sepehrdad, Pouyan <pouyans@qti.qualcomm.com>
Subject: Re: [PATCH 2/2] ath9k: disable RNG by default
Am Mittwoch, 10. August 2016, 06:46:31 CEST schrieb Pan, Miaoqing:
Hi Miaoqing,
> Hi Stephan,
>
> Would you please provide a recent NIST document which asks the entropy
> source to pass the NIST randomness tests ?
See FIPS 140-2 IG 7.15 which explicitly references SP800-22.
Ciao
Stephan
^ permalink raw reply
* Re: [PATCH v3] KEYS: add SP800-56A KDF support for DH
From: Stephan Mueller @ 2016-08-10 5:06 UTC (permalink / raw)
To: Mat Martineau; +Cc: David Howells, keyrings, linux-crypto
In-Reply-To: <alpine.OSX.2.20.1608091546100.24354@mjmartin-mac01.local>
Am Dienstag, 9. August 2016, 15:48:00 CEST schrieb Mat Martineau:
Hi Mat,
> On Sat, 6 Aug 2016, Stephan Mueller wrote:
> > diff --git a/security/keys/internal.h b/security/keys/internal.h
> > index a705a7d..7659b52 100644
> > --- a/security/keys/internal.h
> > +++ b/security/keys/internal.h
> > @@ -259,15 +259,32 @@ static inline long keyctl_get_persistent(uid_t uid,
> > key_serial_t destring) #endif
> >
> > #ifdef CONFIG_KEY_DH_OPERATIONS
> > +#include <crypto/rng.h>
> > +#include <linux/compat.h>
>
> These may belong at the top of the file, even if they are only used when
> CONFIG_KEY_DH_OPERATIONS is defined.
Sure. As I have seen also this coding style in the kernel, I thought it would
make sense here too. But I will move it.
>
> > extern long keyctl_dh_compute(struct keyctl_dh_params __user *, char
> > __user *, - size_t, void __user *);
> > + size_t, struct keyctl_kdf_params __user *);
> > +extern long __keyctl_dh_compute(struct keyctl_dh_params __user *, char
> > __user *, + size_t, struct keyctl_kdf_params *);
> > +extern long compat_keyctl_dh_compute(struct keyctl_dh_params __user
> > *params, + char __user *buffer, size_t buflen,
> > + struct compat_keyctl_kdf_params __user *kdf);
> > +#define KEYCTL_KDF_MAX_OUTPUT_LEN 1024 /* max length of KDF output */
> > +#define KEYCTL_KDF_MAX_OI_LEN 64 /* max length of otherinfo */
> > #else
> > static inline long keyctl_dh_compute(struct keyctl_dh_params __user
> > *params,>
> > char __user *buffer, size_t buflen,
> >
> > - void __user *reserved)
> > + struct keyctl_kdf_params __user *kdf)
> > {
> >
> > return -EOPNOTSUPP;
> >
> > }
> > +
> > +static inline long compat_keyctl_dh_compute(
> > + struct keyctl_dh_params __user *params,
> > + char __user *buffer, size_t buflen,
> > + struct keyctl_kdf_params __user *kdf)
> > +{
> > + return -EOPNOTSUPP
> > +}
> > #endif
> >
> > /*
> > diff --git a/security/keys/keyctl.c b/security/keys/keyctl.c
> > index d580ad0..b106898 100644
> > --- a/security/keys/keyctl.c
> > +++ b/security/keys/keyctl.c
> > @@ -1689,7 +1689,7 @@ SYSCALL_DEFINE5(keyctl, int, option, unsigned long,
> > arg2, unsigned long, arg3,>
> > case KEYCTL_DH_COMPUTE:
> > return keyctl_dh_compute((struct keyctl_dh_params __user *) arg2,
> >
> > (char __user *) arg3, (size_t) arg4,
> >
> > - (void __user *) arg5);
> > + (struct keyctl_kdf_params __user *) arg5);
> >
> > default:
> > return -EOPNOTSUPP;
>
> Regards,
> --
> Mat Martineau
> Intel OTC
Ciao
Stephan
^ permalink raw reply
* Re: [PATCH 2/2] ath9k: disable RNG by default
From: Jason Cooper @ 2016-08-10 13:24 UTC (permalink / raw)
To: Pan, Miaoqing
Cc: Stephan Mueller, Herbert Xu, Matt Mackall,
miaoqing-sgV2jX0FEOL9JmXXK+q4OQ@public.gmane.org, Valo, Kalle,
linux-wireless-u79uwXL29TY76Z2rM5mHXA@public.gmane.org,
ath9k-devel, linux-crypto-u79uwXL29TY76Z2rM5mHXA@public.gmane.org,
Sepehrdad, Pouyan
In-Reply-To: <389c3c1fdde2447aacf31a8b4aadfc08-fhY3XlRGNI1pWAYlkNb9jaRtKmQZhJ7pQQ4Iyu8u01E@public.gmane.org>
Hi Miaoqing Pan, Stephen,
*gentle reminder: others are reading which may not be directly included
in the conversation. Including the archives. Please avoid top posting.
:)
On Wed, Aug 10, 2016 at 07:43:45AM +0000, Pan, Miaoqing wrote:
> The problem with using the add_device_randomness is that we do not
> know when to call that API, and we have to make our solution either
> timer-based or interrupt based, which is not really the correct way of
> implementing this feature.
Exactly. I think we're dancing around the problem by discussing the
quality of what the ath9k adc provides.
The fact is, barring userspace expectations of /dev/hwrng, hw_random is
the appropriate place for it. It's not a devicetree blob, mac address,
or pci config space. Which are things we feed in once for the heck of
it. This is a *continuous* source or questionable quality.
I'm seriously considering putting this and timeriomem-rng into a
subdirectory under hw_random/, maybe environ/. Anything in there gets
quality=0 for default, and *doesn't* contribute to /dev/hwrng.
Regardless which path we take, I think we should include 'adc' in the
name. I've heard countless times about "Atheros cards come with an rng
on board". :-/
thx,
Jason.
--
To unsubscribe from this list: send the line "unsubscribe linux-wireless" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply
* [PATCH 5/6] crypto: sun4i-ss: Always use sun4i_tfm_ctx for storing pointer to dev ss
From: LABBE Corentin @ 2016-08-10 9:45 UTC (permalink / raw)
To: herbert, davem, maxime.ripard, wens
Cc: linux-crypto, linux-kernel, LABBE Corentin
In-Reply-To: <1470822334-20672-1-git-send-email-clabbe.montjoie@gmail.com>
The dev *ss is stored both in sun4i_tfm_ctx and sun4i_req_ctx.
Since this pointer will never be changed during tfm life, it is better
to remove it from sun4i_req_ctx.
Signed-off-by: LABBE Corentin <clabbe.montjoie@gmail.com>
---
drivers/crypto/sunxi-ss/sun4i-ss-hash.c | 13 +++++++++++--
drivers/crypto/sunxi-ss/sun4i-ss.h | 1 -
2 files changed, 11 insertions(+), 3 deletions(-)
diff --git a/drivers/crypto/sunxi-ss/sun4i-ss-hash.c b/drivers/crypto/sunxi-ss/sun4i-ss-hash.c
index 60031e0..2ee3b59 100644
--- a/drivers/crypto/sunxi-ss/sun4i-ss-hash.c
+++ b/drivers/crypto/sunxi-ss/sun4i-ss-hash.c
@@ -20,6 +20,15 @@
int sun4i_hash_crainit(struct crypto_tfm *tfm)
{
+ struct sun4i_tfm_ctx *op = crypto_tfm_ctx(tfm);
+ struct ahash_alg *alg = __crypto_ahash_alg(tfm->__crt_alg);
+ struct sun4i_ss_alg_template *algt;
+
+ memset(op, 0, sizeof(struct sun4i_tfm_ctx));
+
+ algt = container_of(alg, struct sun4i_ss_alg_template, alg.hash);
+ op->ss = algt->ss;
+
crypto_ahash_set_reqsize(__crypto_ahash_cast(tfm),
sizeof(struct sun4i_req_ctx));
return 0;
@@ -36,7 +45,6 @@ int sun4i_hash_init(struct ahash_request *areq)
memset(op, 0, sizeof(struct sun4i_req_ctx));
algt = container_of(alg, struct sun4i_ss_alg_template, alg.hash);
- op->ss = algt->ss;
op->mode = algt->mode;
return 0;
@@ -168,8 +176,9 @@ int sun4i_hash(struct ahash_request *areq)
*/
struct sun4i_req_ctx *op = ahash_request_ctx(areq);
- struct sun4i_ss_ctx *ss = op->ss;
struct crypto_ahash *tfm = crypto_ahash_reqtfm(areq);
+ struct sun4i_tfm_ctx *tfmctx = crypto_ahash_ctx(tfm);
+ struct sun4i_ss_ctx *ss = tfmctx->ss;
unsigned int in_i = 0; /* advancement in the current SG */
unsigned int end;
/*
diff --git a/drivers/crypto/sunxi-ss/sun4i-ss.h b/drivers/crypto/sunxi-ss/sun4i-ss.h
index ece5a1c..f04c0f8 100644
--- a/drivers/crypto/sunxi-ss/sun4i-ss.h
+++ b/drivers/crypto/sunxi-ss/sun4i-ss.h
@@ -163,7 +163,6 @@ struct sun4i_req_ctx {
u32 hash[5]; /* for storing SS_IVx register */
char buf[64];
unsigned int len;
- struct sun4i_ss_ctx *ss;
int flags;
};
--
2.7.3
^ permalink raw reply related
* [PATCH 4/6] crypto: sun4i-ss: fix spelling
From: LABBE Corentin @ 2016-08-10 9:45 UTC (permalink / raw)
To: herbert, davem, maxime.ripard, wens
Cc: linux-crypto, linux-kernel, LABBE Corentin
In-Reply-To: <1470822334-20672-1-git-send-email-clabbe.montjoie@gmail.com>
Two words are badly spelled, this patch respell them.
Signed-off-by: LABBE Corentin <clabbe.montjoie@gmail.com>
---
drivers/crypto/sunxi-ss/sun4i-ss-hash.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/drivers/crypto/sunxi-ss/sun4i-ss-hash.c b/drivers/crypto/sunxi-ss/sun4i-ss-hash.c
index 7841d73..60031e0 100644
--- a/drivers/crypto/sunxi-ss/sun4i-ss-hash.c
+++ b/drivers/crypto/sunxi-ss/sun4i-ss-hash.c
@@ -372,7 +372,7 @@ int sun4i_hash(struct ahash_request *areq)
* I do not check RX FIFO size in this function since the size is 32
* after each enabling and this function neither write more than 32 words.
* If we come from the update part, we cannot have more than
- * 3 remainings bytes to write and SS is fast enought to not care about it.
+ * 3 remaining bytes to write and SS is fast enough to not care about it.
*/
hash_final:
@@ -436,7 +436,7 @@ hash_final:
/*
* Wait for SS to finish the hash.
- * The timeout could happen only in case of bad overcloking
+ * The timeout could happen only in case of bad overclocking
* or driver bug.
*/
i = 0;
--
2.7.3
^ permalink raw reply related
* [PATCH 2/6] crypto: sun4i-ss: unify update/final function
From: LABBE Corentin @ 2016-08-10 9:45 UTC (permalink / raw)
To: herbert, davem, maxime.ripard, wens
Cc: linux-crypto, linux-kernel, LABBE Corentin
In-Reply-To: <1470822334-20672-1-git-send-email-clabbe.montjoie@gmail.com>
The update and final functions have lots of common action.
This patch mix them in one function.
This will give some improvements:
- This will permit asynchronous support more easily
- This will permit to use finup/digest functions with some performance
improvements
Signed-off-by: LABBE Corentin <clabbe.montjoie@gmail.com>
---
drivers/crypto/sunxi-ss/sun4i-ss-hash.c | 147 ++++++++++++++++++--------------
drivers/crypto/sunxi-ss/sun4i-ss.h | 1 +
2 files changed, 85 insertions(+), 63 deletions(-)
diff --git a/drivers/crypto/sunxi-ss/sun4i-ss-hash.c b/drivers/crypto/sunxi-ss/sun4i-ss-hash.c
index ff80314..2fb0684 100644
--- a/drivers/crypto/sunxi-ss/sun4i-ss-hash.c
+++ b/drivers/crypto/sunxi-ss/sun4i-ss-hash.c
@@ -129,6 +129,9 @@ int sun4i_hash_import_sha1(struct ahash_request *areq, const void *in)
return 0;
}
+#define SS_HASH_UPDATE 1
+#define SS_HASH_FINAL 2
+
/*
* sun4i_hash_update: update hash engine
*
@@ -156,7 +159,7 @@ int sun4i_hash_import_sha1(struct ahash_request *areq, const void *in)
* write remaining data in op->buf
* final state op->len=56
*/
-int sun4i_hash_update(struct ahash_request *areq)
+int sun4i_hash(struct ahash_request *areq)
{
u32 v, ivmode = 0;
unsigned int i = 0;
@@ -180,22 +183,30 @@ int sun4i_hash_update(struct ahash_request *areq)
u32 spaces, rx_cnt = SS_RX_DEFAULT;
size_t copied = 0;
struct sg_mapping_iter mi;
+ unsigned int j = 0;
+ int zeros;
+ unsigned int index, padlen;
+ __be64 bits;
+ u32 bf[32];
+ u32 wb = 0;
+ unsigned int nwait, nbw = 0;
+ struct scatterlist *in_sg = areq->src;
dev_dbg(ss->dev, "%s %s bc=%llu len=%u mode=%x wl=%u h0=%0x",
__func__, crypto_tfm_alg_name(areq->base.tfm),
op->byte_count, areq->nbytes, op->mode,
op->len, op->hash[0]);
- if (areq->nbytes == 0)
+ if (unlikely(areq->nbytes == 0) && (op->flags & SS_HASH_FINAL) == 0)
return 0;
/* protect against overflow */
- if (areq->nbytes > UINT_MAX - op->len) {
+ if (unlikely(areq->nbytes > UINT_MAX - op->len)) {
dev_err(ss->dev, "Cannot process too large request\n");
return -EINVAL;
}
- if (op->len + areq->nbytes < 64) {
+ if (op->len + areq->nbytes < 64 && (op->flags & SS_HASH_FINAL) == 0) {
/* linearize data to op->buf */
copied = sg_pcopy_to_buffer(areq->src, sg_nents(areq->src),
op->buf + op->len, areq->nbytes, 0);
@@ -203,14 +214,6 @@ int sun4i_hash_update(struct ahash_request *areq)
return 0;
}
- end = ((areq->nbytes + op->len) / 64) * 64 - op->len;
-
- if (end > areq->nbytes || areq->nbytes - end > 63) {
- dev_err(ss->dev, "ERROR: Bound error %u %u\n",
- end, areq->nbytes);
- return -EINVAL;
- }
-
spin_lock_bh(&ss->slock);
/*
@@ -225,6 +228,33 @@ int sun4i_hash_update(struct ahash_request *areq)
/* Enable the device */
writel(op->mode | SS_ENABLED | ivmode, ss->base + SS_CTL);
+ if ((op->flags & SS_HASH_UPDATE) == 0)
+ goto hash_final;
+
+ /* start of handling data */
+ if ((op->flags & SS_HASH_FINAL) == 0) {
+ end = ((areq->nbytes + op->len) / 64) * 64 - op->len;
+
+ if (end > areq->nbytes || areq->nbytes - end > 63) {
+ dev_err(ss->dev, "ERROR: Bound error %u %u\n",
+ end, areq->nbytes);
+ return -EINVAL;
+ }
+ } else {
+ /* Since we have the flag final, we can go up to modulo 4 */
+ end = ((areq->nbytes + op->len) / 4) * 4 - op->len;
+ }
+
+ /* TODO if SGlen % 4 and op->len == 0 then DMA */
+ i = 1;
+ while (in_sg && i == 1) {
+ if ((in_sg->length % 4) != 0)
+ i = 0;
+ in_sg = sg_next(in_sg);
+ }
+ if (i == 1 && op->len == 0)
+ dev_dbg(ss->dev, "We can DMA\n");
+
i = 0;
sg_miter_start(&mi, areq->src, sg_nents(areq->src),
SG_MITER_FROM_SG | SG_MITER_ATOMIC);
@@ -285,7 +315,11 @@ int sun4i_hash_update(struct ahash_request *areq)
}
}
} while (i < end);
- /* final linear */
+
+ /*
+ * Now we have written to the device all that we can,
+ * store the remaining bytes in op->buf
+ */
if ((areq->nbytes - i) < 64) {
while (i < areq->nbytes && in_i < mi.length && op->len < 64) {
/* how many bytes we can read from current SG */
@@ -304,13 +338,21 @@ int sun4i_hash_update(struct ahash_request *areq)
sg_miter_stop(&mi);
+ /*
+ * End of data process
+ * Now if we have the flag final go to finalize part
+ * If not, store the partial hash
+ */
+ if ((op->flags & SS_HASH_FINAL) > 0)
+ goto hash_final;
+
writel(op->mode | SS_ENABLED | SS_DATA_END, ss->base + SS_CTL);
i = 0;
do {
v = readl(ss->base + SS_CTL);
i++;
} while (i < SS_TIMEOUT && (v & SS_DATA_END) > 0);
- if (i >= SS_TIMEOUT) {
+ if (unlikely(i >= SS_TIMEOUT)) {
dev_err_ratelimited(ss->dev,
"ERROR: hash end timeout %d>%d ctl=%x len=%u\n",
i, SS_TIMEOUT, v, areq->nbytes);
@@ -318,56 +360,24 @@ int sun4i_hash_update(struct ahash_request *areq)
goto release_ss;
}
- /* get the partial hash only if something was written */
for (i = 0; i < crypto_ahash_digestsize(tfm) / 4; i++)
op->hash[i] = readl(ss->base + SS_MD0 + i * 4);
-release_ss:
- writel(0, ss->base + SS_CTL);
- spin_unlock_bh(&ss->slock);
- return err;
-}
+ goto release_ss;
/*
- * sun4i_hash_final: finalize hashing operation
+ * hash_final: finalize hashing operation
*
* If we have some remaining bytes, we write them.
* Then ask the SS for finalizing the hashing operation
*
* I do not check RX FIFO size in this function since the size is 32
* after each enabling and this function neither write more than 32 words.
+ * If we come from the update part, we cannot have more than
+ * 3 remainings bytes to write and SS is fast enought to not care about it.
*/
-int sun4i_hash_final(struct ahash_request *areq)
-{
- u32 v, ivmode = 0;
- unsigned int i;
- unsigned int j = 0;
- int zeros, err = 0;
- unsigned int index, padlen;
- __be64 bits;
- struct sun4i_req_ctx *op = ahash_request_ctx(areq);
- struct sun4i_ss_ctx *ss = op->ss;
- struct crypto_ahash *tfm = crypto_ahash_reqtfm(areq);
- u32 bf[32];
- u32 wb = 0;
- unsigned int nwait, nbw = 0;
- dev_dbg(ss->dev, "%s: byte=%llu len=%u mode=%x wl=%u h=%x",
- __func__, op->byte_count, areq->nbytes, op->mode,
- op->len, op->hash[0]);
-
- spin_lock_bh(&ss->slock);
-
- /*
- * if we have already written something,
- * restore the partial hash state
- */
- if (op->byte_count > 0) {
- ivmode = SS_IV_ARBITRARY;
- for (i = 0; i < crypto_ahash_digestsize(tfm) / 4; i++)
- writel(op->hash[i], ss->base + SS_IV0 + i * 4);
- }
- writel(op->mode | SS_ENABLED | ivmode, ss->base + SS_CTL);
+hash_final:
/* write the remaining words of the wait buffer */
if (op->len > 0) {
@@ -436,7 +446,7 @@ int sun4i_hash_final(struct ahash_request *areq)
v = readl(ss->base + SS_CTL);
i++;
} while (i < SS_TIMEOUT && (v & SS_DATA_END) > 0);
- if (i >= SS_TIMEOUT) {
+ if (unlikely(i >= SS_TIMEOUT)) {
dev_err_ratelimited(ss->dev,
"ERROR: hash end timeout %d>%d ctl=%x len=%u\n",
i, SS_TIMEOUT, v, areq->nbytes);
@@ -463,30 +473,41 @@ release_ss:
return err;
}
+int sun4i_hash_final(struct ahash_request *areq)
+{
+ struct sun4i_req_ctx *op = ahash_request_ctx(areq);
+
+ op->flags = SS_HASH_FINAL;
+ return sun4i_hash(areq);
+}
+
+int sun4i_hash_update(struct ahash_request *areq)
+{
+ struct sun4i_req_ctx *op = ahash_request_ctx(areq);
+
+ op->flags = SS_HASH_UPDATE;
+ return sun4i_hash(areq);
+}
+
/* sun4i_hash_finup: finalize hashing operation after an update */
int sun4i_hash_finup(struct ahash_request *areq)
{
- int err;
-
- err = sun4i_hash_update(areq);
- if (err != 0)
- return err;
+ struct sun4i_req_ctx *op = ahash_request_ctx(areq);
- return sun4i_hash_final(areq);
+ op->flags = SS_HASH_UPDATE | SS_HASH_FINAL;
+ return sun4i_hash(areq);
}
/* combo of init/update/final functions */
int sun4i_hash_digest(struct ahash_request *areq)
{
int err;
+ struct sun4i_req_ctx *op = ahash_request_ctx(areq);
err = sun4i_hash_init(areq);
if (err != 0)
return err;
- err = sun4i_hash_update(areq);
- if (err != 0)
- return err;
-
- return sun4i_hash_final(areq);
+ op->flags = SS_HASH_UPDATE | SS_HASH_FINAL;
+ return sun4i_hash(areq);
}
diff --git a/drivers/crypto/sunxi-ss/sun4i-ss.h b/drivers/crypto/sunxi-ss/sun4i-ss.h
index 8e9c05f..ece5a1c 100644
--- a/drivers/crypto/sunxi-ss/sun4i-ss.h
+++ b/drivers/crypto/sunxi-ss/sun4i-ss.h
@@ -164,6 +164,7 @@ struct sun4i_req_ctx {
char buf[64];
unsigned int len;
struct sun4i_ss_ctx *ss;
+ int flags;
};
int sun4i_hash_crainit(struct crypto_tfm *tfm);
--
2.7.3
^ permalink raw reply related
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox