From dffb8a67e3e92500651db3eca516dbcfc275311a Mon Sep 17 00:00:00 2001 From: Jussi Kivilinna Date: Thu, 30 Mar 2017 07:38:37 -0600 Subject: [PATCH] Add entropy pool and strong random number generator Entropy pool gathers environmental noise from device drivers, user-space, etc., and returns good random numbers, suitable for cryptographic use. Based on entropy pool design from *BSDs and uses BLAKE2Xs algorithm for CSPRNG output. Patch also adds /dev/urandom support for using entropy pool RNG and new 'getrandom' system call for getting randomness without file-descriptor usage (thus avoiding file-descriptor exhaustion attacks). The 'getrandom' interface is similar as 'getentropy' and 'getrandom' available on OpenBSD and Linux respectively. --- configs/Kconfig | 21 ++ crypto/Kconfig | 31 ++ crypto/Makefile | 14 +- crypto/blake2s.c | 606 +++++++++++++++++++++++++++++++ crypto/random_pool.c | 561 ++++++++++++++++++++++++++++ drivers/Kconfig | 9 + drivers/analog/adc.c | 5 + drivers/dev_urandom.c | 72 +++- drivers/input/ads7843e.c | 3 + drivers/input/ajoystick.c | 3 + drivers/input/button_upper.c | 3 + drivers/input/djoystick.c | 3 + drivers/input/max11802.c | 3 + drivers/input/mxt.c | 3 + drivers/input/stmpe811_temp.c | 3 + drivers/input/stmpe811_tsc.c | 3 + drivers/input/tsc2007.c | 5 +- drivers/sensors/adxl345_base.c | 4 + drivers/sensors/bh1750fvi.c | 3 + drivers/sensors/bmg160.c | 5 + drivers/sensors/bmp180.c | 5 + drivers/sensors/kxtj9.c | 7 + drivers/sensors/l3gd20.c | 5 + drivers/sensors/lis331dl.c | 6 + drivers/sensors/lis3dsh.c | 5 + drivers/sensors/lis3mdl.c | 6 + drivers/sensors/lm75.c | 3 + drivers/sensors/lm92.c | 3 + drivers/sensors/lsm9ds1.c | 10 + drivers/sensors/max31855.c | 5 + drivers/sensors/max6675.c | 5 + drivers/sensors/mb7040.c | 5 + drivers/sensors/mcp9844.c | 5 + drivers/sensors/mlx90393.c | 6 + drivers/sensors/mpl115a.c | 6 + drivers/sensors/ms58xx.c | 3 + drivers/sensors/veml6070.c | 5 + drivers/sensors/xen1210.c | 7 + include/nuttx/board.h | 16 + include/nuttx/crypto/blake2s.h | 197 ++++++++++ include/nuttx/random.h | 171 +++++++++ include/string.h | 2 + include/sys/random.h | 77 ++++ include/sys/syscall.h | 15 +- libc/string/Make.defs | 1 + libc/string/lib_explicit_bzero.c | 56 +++ sched/irq/irq_dispatch.c | 9 +- syscall/syscall.csv | 1 + syscall/syscall_lookup.h | 7 + syscall/syscall_stublookup.c | 5 + 50 files changed, 2005 insertions(+), 9 deletions(-) create mode 100644 crypto/blake2s.c create mode 100644 crypto/random_pool.c create mode 100644 include/nuttx/crypto/blake2s.h create mode 100644 include/nuttx/random.h create mode 100644 include/sys/random.h create mode 100644 libc/string/lib_explicit_bzero.c diff --git a/configs/Kconfig b/configs/Kconfig index aef29eecd6..27d98e0821 100644 --- a/configs/Kconfig +++ b/configs/Kconfig @@ -2015,6 +2015,27 @@ config BOARD_RESET_ON_CRASH If selected the board_crashdump should reset the machine after saveing the state of the machine +config BOARD_ENTROPY_POOL + bool "Enable Board level storing of entropy pool structure" + default n + depends on CRYPTO_RANDOM_POOL + ---help--- + Entropy pool structure can be provided by board source. + Use for this is, for example, to allocate entropy pool + from special area of RAM which content is kept over + system reset. + +config BOARD_INITRNGSEED + bool "Enable Board level initial seeding of entropy pool RNG" + default n + depends on CRYPTO_RANDOM_POOL + ---help--- + If enabled, entropy pool random number generator will call + board_init_rndseed() upon initialization. This function + can then provide early entropy seed to the pool through + entropy injection APIs provided at 'nuttx/random.h'. +#endif + config LIB_BOARDCTL bool "Enable boardctl() interface" default n diff --git a/crypto/Kconfig b/crypto/Kconfig index 022fce7a05..0c93eaaa99 100644 --- a/crypto/Kconfig +++ b/crypto/Kconfig @@ -50,4 +50,35 @@ config CRYPTO_SW_AES implemenations. This needs to support up_aesinitialize() and aes_cypher() per include/nuttx/crypto/crypto.h. +config CRYPTO_BLAKE2S + bool "BLAKE2s hash algorithm" + default n + ---help--- + Enable the BLAKE2s hash algorithm + +config CRYPTO_RANDOM_POOL + bool "Entropy pool and strong randon number generator" + default n + select CRYPTO_BLAKE2S + ---help--- + Entropy pool gathers environmental noise from device drivers, + user-space, etc., and returns good random numbers, suitable + for cryptographic use. Based on entropy pool design from + *BSDs and uses BLAKE2Xs algorithm for CSPRNG output. + + NOTE: May not actually be cyptographically secure, if + not enough entropy is made available to the entropy pool. + +if CRYPTO_RANDOM_POOL + +config CRYPTO_RANDOM_POOL_COLLECT_IRQ_RANDOMNESS + bool "Use interrupts to feed timing randomness to entropy pool" + default y + ---help--- + Feed entropy pool with interrupt randomness from interrupt + dispatch function 'irq_dispatch'. This adds some overhead + for every interrupt handled. + +endif # CRYPTO_RANDOM_POOL + endif # CRYPTO diff --git a/crypto/Makefile b/crypto/Makefile index 23b4cf137e..56b75b6517 100644 --- a/crypto/Makefile +++ b/crypto/Makefile @@ -56,6 +56,18 @@ ifeq ($(CONFIG_CRYPTO_SW_AES),y) CRYPTO_CSRCS += aes.c endif +# BLAKE2s hash algorithm + +ifeq ($(CONFIG_CRYPTO_BLAKE2S),y) + CRYPTO_CSRCS += blake2s.c +endif + +# Entropy pool random number generator + +ifeq ($(CONFIG_CRYPTO_RANDOM_POOL),y) + CRYPTO_CSRCS += random_pool.c +endif + endif # CONFIG_CRYPTO ASRCS = $(CRYPTO_ASRCS) @@ -97,4 +109,4 @@ distclean: clean $(call DELFILE, Make.dep) $(call DELFILE, .depend) --include Make.dep \ No newline at end of file +-include Make.dep diff --git a/crypto/blake2s.c b/crypto/blake2s.c new file mode 100644 index 0000000000..a88ed045c5 --- /dev/null +++ b/crypto/blake2s.c @@ -0,0 +1,606 @@ +/**************************************************************************** + * crypto/blake2s.c + * + * This code is based on public-domain/CC0 BLAKE2 reference implementation + * by Samual Neves, at https://github.com/BLAKE2/BLAKE2/tree/master/ref + * Copyright 2012, Samuel Neves + * + * Copyright (C) 2017 Haltian Ltd. All rights reserved. + * Authors: Jussi Kivilinna + * + * 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, this list of conditions and the following disclaimer. + * 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. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS 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 ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +static const uint32_t blake2s_IV[8] = +{ + 0x6a09e667ul, 0xbb67ae85ul, 0x3c6ef372ul, 0xa54ff53aul, 0x510e527ful, + 0x9b05688cul, 0x1f83d9abul, 0x5be0cd19ul +}; + +static const uint8_t blake2s_sigma[10][16] = +{ + { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 }, + { 14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3 }, + { 11, 8, 12, 0, 5, 2, 15, 13, 10, 14, 3, 6, 7, 1, 9, 4 }, + { 7, 9, 3, 1, 13, 12, 11, 14, 2, 6, 5, 10, 4, 0, 15, 8 }, + { 9, 0, 5, 7, 2, 4, 10, 15, 14, 1, 11, 12, 6, 8, 3, 13 }, + { 2, 12, 6, 10, 0, 11, 8, 3, 4, 13, 7, 5, 15, 14, 1, 9 }, + { 12, 5, 1, 15, 14, 13, 4, 10, 0, 7, 6, 3, 9, 2, 8, 11 }, + { 13, 11, 7, 14, 12, 1, 3, 9, 5, 0, 15, 4, 8, 6, 2, 10 }, + { 6, 15, 14, 9, 11, 3, 0, 8, 12, 2, 13, 7, 1, 4, 10, 5 }, + { 10, 2, 8, 4, 7, 6, 1, 5, 15, 11, 9, 14, 3, 12, 13, 0 } +}; + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +static inline uint32_t rotr32(const uint32_t w, const unsigned int c) +{ + return (w >> (c & 31)) | (w << ((32 - c) & 31)); +} + +static void blake2_memcpy(FAR void *dst, FAR const void *src, size_t len) +{ +#ifdef BLAKE2_UNALIGNED + FAR uint32_alias_t *idst = dst; + FAR const uint32_alias_t *isrc = src; + FAR uint8_t *bdst; + FAR const uint8_t *bsrc; + + while (len >= sizeof(uint32_alias_t)) + { + *idst = *isrc; + idst++; + isrc++; + len -= sizeof(uint32_alias_t); + } + + bdst = (FAR uint8_t *)idst; + bsrc = (FAR const uint8_t *)isrc; + while (len) + { + *bdst = *bsrc; + bdst++; + bsrc++; + len--; + } +#else + memcpy(dst, set, len); +#endif +} + +static void blake2_memset(FAR void *dst, int set, size_t len) +{ +#ifdef BLAKE2_UNALIGNED + FAR uint32_alias_t *idst = dst; + FAR uint8_t *bdst; + uint32_t mset; + + set &= 0xff; + mset = (uint32_t)set * 0x01010101UL; + + while (len >= sizeof(uint32_alias_t)) + { + *idst = mset; + idst++; + len -= sizeof(uint32_alias_t); + } + + bdst = (FAR uint8_t *)idst; + set &= 0xff; + while (len) + { + *bdst = set; + bdst++; + len--; + } +#else + memset(dst, set, len); +#endif +} + +static inline void secure_zero_memory(FAR void *v, size_t n) +{ + explicit_bzero(v, n); +} + +/* Some helper functions, not necessarily useful */ + +static int blake2s_is_lastblock(FAR const blake2s_state *S) +{ + return S->f[0] != 0; +} + +static void blake2s_set_lastblock(FAR blake2s_state *S) +{ + S->f[0] = (uint32_t)-1; +} + +static void blake2s_increment_counter(FAR blake2s_state *S, const uint32_t inc) +{ + S->t[0] += inc; + S->t[1] += (S->t[0] < inc); +} + +static void blake2s_init0(FAR blake2s_state *S) +{ + size_t i; + + blake2_memset(S, 0, sizeof(*S) - sizeof(S->buf)); + + for (i = 0; i < 8; ++i) + S->h[i] = blake2s_IV[i]; +} + +static void blake2s_compress(FAR blake2s_state *S, + const uint8_t in[BLAKE2S_BLOCKBYTES]) +{ + uint32_t m[16]; + uint32_t v[16]; + size_t i; + unsigned int round; + + for (i = 0; i < 16; ++i) + { + m[i] = blake2_load32(in + i * sizeof(m[i])); + } + + for (i = 0; i < 8; ++i) + { + v[i] = S->h[i]; + } + + v[8] = blake2s_IV[0]; + v[9] = blake2s_IV[1]; + v[10] = blake2s_IV[2]; + v[11] = blake2s_IV[3]; + v[12] = S->t[0] ^ blake2s_IV[4]; + v[13] = S->t[1] ^ blake2s_IV[5]; + v[14] = S->f[0] ^ blake2s_IV[6]; + v[15] = S->f[1] ^ blake2s_IV[7]; + +#define G(r,i,a,b,c,d) \ + do { \ + a = a + b + m[blake2s_sigma[r][2*i+0]]; \ + d = rotr32(d ^ a, 16); \ + c = c + d; \ + b = rotr32(b ^ c, 12); \ + a = a + b + m[blake2s_sigma[r][2*i+1]]; \ + d = rotr32(d ^ a, 8); \ + c = c + d; \ + b = rotr32(b ^ c, 7); \ + } while(0) + +#define ROUND(r) \ + do { \ + G(r,0,v[ 0],v[ 4],v[ 8],v[12]); \ + G(r,1,v[ 1],v[ 5],v[ 9],v[13]); \ + G(r,2,v[ 2],v[ 6],v[10],v[14]); \ + G(r,3,v[ 3],v[ 7],v[11],v[15]); \ + G(r,4,v[ 0],v[ 5],v[10],v[15]); \ + G(r,5,v[ 1],v[ 6],v[11],v[12]); \ + G(r,6,v[ 2],v[ 7],v[ 8],v[13]); \ + G(r,7,v[ 3],v[ 4],v[ 9],v[14]); \ + } while(0) + + /* Size vs performance trade-off. With unrolling, on ARMv7-M function text + * is ~4 KiB and without ~1 KiB. Without unrolling we take ~25% performance + * hit. */ + +#if 1 + /* Smaller, slightly slower. */ + + for (round = 0; round < 10; round++) + { + ROUND(round); + } +#else + /* Larger, slightly faster. */ + + (void)(round=0); + ROUND(0); + ROUND(1); + ROUND(2); + ROUND(3); + ROUND(4); + ROUND(5); + ROUND(6); + ROUND(7); + ROUND(8); + ROUND(9); +#endif + +#undef G +#undef ROUND + + for (i = 0; i < 8; ++i) + { + S->h[i] = S->h[i] ^ v[i] ^ v[i + 8]; + } +} + +#ifdef CONFIG_BLAKE2_SELFTEST +/* BLAKE2s self-test from RFC 7693 */ + +static void selftest_seq(FAR uint8_t *out, size_t len, uint32_t seed) +{ + size_t i; + uint32_t t, a, b; + + a = 0xDEAD4BAD * seed; /* prime */ + b = 1; + /* fill the buf */ + for (i = 0; i < len; i++) + { + t = a + b; + a = b; + b = t; + out[i] = (t >> 24) & 0xFF; + } +} + +static int blake2s_selftest(void) +{ + /* Grand hash of hash results. */ + + static const uint8_t blake2s_res[32] = + { + 0x6a, 0x41, 0x1f, 0x08, 0xce, 0x25, 0xad, 0xcd, 0xfb, 0x02, 0xab, 0xa6, + 0x41, 0x45, 0x1c, 0xec, 0x53, 0xc5, 0x98, 0xb2, 0x4f, 0x4f, 0xc7, 0x87, + 0xfb, 0xdc, 0x88, 0x79, 0x7f, 0x4c, 0x1d, 0xfe + }; + + /* Parameter sets. */ + + static const size_t b2s_md_len[4] = { 16, 20, 28, 32 }; + static const size_t b2s_in_len[6] = { 0, 3, 64, 65, 255, 1024 }; + size_t i, j, outlen, inlen; + FAR uint8_t *in; + uint8_t md[32], key[32]; + blake2s_state ctx; + int ret = -1; + + in = malloc(1024); + if (!in) + { + goto out; + } + + /* 256-bit hash for testing. */ + + if (blake2s_init(&ctx, 32)) + { + goto out; + } + + for (i = 0; i < 4; i++) + { + outlen = b2s_md_len[i]; + for (j = 0; j < 6; j++) + { + inlen = b2s_in_len[j]; + + selftest_seq(in, inlen, inlen); /* unkeyed hash */ + blake2s(md, outlen, in, inlen, NULL, 0); + blake2s_update(&ctx, md, outlen); /* hash the hash */ + + selftest_seq(key, outlen, outlen); /* keyed hash */ + blake2s(md, outlen, in, inlen, key, outlen); + blake2s_update(&ctx, md, outlen); /* hash the hash */ + } + } + + /* Compute and compare the hash of hashes. */ + + blake2s_final(&ctx, md, 32); + for (i = 0; i < 32; i++) + { + if (md[i] != blake2s_res[i]) + goto out; + } + + ret = 0; + +out: + free(in); + return ret; +} +#endif + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/* init2 xors IV with input parameter block */ + +int blake2s_init_param(FAR blake2s_state *S, FAR const blake2s_param *P) +{ + FAR const unsigned char *p = (FAR const unsigned char *)(P); + size_t i; +#ifdef CONFIG_BLAKE2_SELFTEST + static bool selftest_done = false; + int ret; + + if (!selftest_done) + { + selftest_done = true; + ret = blake2s_selftest(); + DEBUGASSERT(ret == 0); + if (ret) + return -1; + } +#endif + + blake2s_init0(S); + + /* IV XOR ParamBlock */ + + for (i = 0; i < 8; ++i) + { + S->h[i] ^= blake2_load32(&p[i * 4]); + } + + S->outlen = P->digest_length; + return 0; +} + +/* Sequential blake2s initialization */ + +int blake2s_init(FAR blake2s_state *S, size_t outlen) +{ + blake2s_param P[1]; + + /* Move interval verification here? */ + + if ((!outlen) || (outlen > BLAKE2S_OUTBYTES)) + { + return -1; + } + + P->digest_length = (uint8_t)outlen; + P->key_length = 0; + P->fanout = 1; + P->depth = 1; + blake2_store32(P->leaf_length, 0); + blake2_store32(P->node_offset, 0); + blake2_store16(P->xof_length, 0); + P->node_depth = 0; + P->inner_length = 0; + /* memset(P->reserved, 0, sizeof(P->reserved)); */ + blake2_memset(P->salt, 0, sizeof(P->salt)); + blake2_memset(P->personal, 0, sizeof(P->personal)); + return blake2s_init_param(S, P); +} + +int blake2s_init_key(FAR blake2s_state *S, size_t outlen, FAR const void *key, + size_t keylen) +{ + blake2s_param P[1]; + uint8_t block[BLAKE2S_BLOCKBYTES]; + + if ((!outlen) || (outlen > BLAKE2S_OUTBYTES)) + { + return -1; + } + + if (!key || !keylen || keylen > BLAKE2S_KEYBYTES) + { + return -1; + } + + P->digest_length = (uint8_t) outlen; + P->key_length = (uint8_t) keylen; + P->fanout = 1; + P->depth = 1; + blake2_store32(P->leaf_length, 0); + blake2_store32(P->node_offset, 0); + blake2_store16(P->xof_length, 0); + P->node_depth = 0; + P->inner_length = 0; + /* memset(P->reserved, 0, sizeof(P->reserved)); */ + blake2_memset(P->salt, 0, sizeof(P->salt)); + blake2_memset(P->personal, 0, sizeof(P->personal)); + + blake2s_init_param(S, P); + + blake2_memset(block, 0, BLAKE2S_BLOCKBYTES); + blake2_memcpy(block, key, keylen); + blake2s_update(S, block, BLAKE2S_BLOCKBYTES); + secure_zero_memory(block, BLAKE2S_BLOCKBYTES); /* Burn the key from stack */ + + return 0; +} + +int blake2s_update(FAR blake2s_state *S, FAR const void *pin, size_t inlen) +{ + FAR const unsigned char * in = FAR (const unsigned char *)pin; + size_t left, fill; + + if (inlen <= 0) + { + return 0; + } + + left = S->buflen; + fill = BLAKE2S_BLOCKBYTES - left; + if (inlen > fill) + { + S->buflen = 0; + if (fill) + { + blake2_memcpy(S->buf + left, in, fill); /* Fill buffer */ + } + + blake2s_increment_counter(S, BLAKE2S_BLOCKBYTES); + blake2s_compress(S, S->buf); /* Compress */ + in += fill; + inlen -= fill; + while (inlen > BLAKE2S_BLOCKBYTES) + { + blake2s_increment_counter(S, BLAKE2S_BLOCKBYTES); + blake2s_compress(S, in); + in += BLAKE2S_BLOCKBYTES; + inlen -= BLAKE2S_BLOCKBYTES; + } + } + + blake2_memcpy(S->buf + S->buflen, in, inlen); + S->buflen += inlen; + + return 0; +} + +int blake2s_final(FAR blake2s_state *S, FAR void *out, size_t outlen) +{ + FAR uint8_t *outbuf = out; + uint32_t tmp = 0; + size_t outwords; + size_t padding; + size_t i; + + if (out == NULL || outlen < S->outlen) + { + return -1; + } + + if (blake2s_is_lastblock(S)) + { + return -1; + } + + blake2s_increment_counter(S, (uint32_t)S->buflen); + blake2s_set_lastblock(S); + padding = BLAKE2S_BLOCKBYTES - S->buflen; + if (padding) + { + blake2_memset(S->buf + S->buflen, 0, padding); + } + blake2s_compress(S, S->buf); + + /* Output hash to out buffer */ + + outwords = outlen / sizeof(uint32_t); + outwords = (outwords < 8) ? outwords : 8; + for (i = 0; i < outwords; ++i) + { + /* Store full words */ + + blake2_store32(outbuf, S->h[i]); + outlen -= sizeof(uint32_t); + outbuf += sizeof(uint32_t); + } + + if (outwords < 8 && outlen > 0 && outlen < sizeof(uint32_t)) + { + /* Store partial word */ + + blake2_store32(&tmp, S->h[i]); + blake2_memcpy(outbuf, &tmp, outlen); + } + + return 0; +} + +int blake2s(FAR void *out, size_t outlen, FAR const void *in, size_t inlen, + FAR const void *key, size_t keylen) +{ + blake2s_state S[1]; + + /* Verify parameters */ + + if (NULL == in && inlen > 0) + { + return -1; + } + + if (NULL == out) + { + return -1; + } + + if (NULL == key && keylen > 0) + { + return -1; + } + + if (!outlen || outlen > BLAKE2S_OUTBYTES) + { + return -1; + } + + if (keylen > BLAKE2S_KEYBYTES) + { + return -1; + } + + if (keylen > 0) + { + if (blake2s_init_key(S, outlen, key, keylen) < 0) + { + return -1; + } + } + else + { + if (blake2s_init(S, outlen) < 0) + { + return -1; + } + } + + blake2s_update(S, (const uint8_t *)in, inlen); + blake2s_final(S, out, outlen); + return 0; +} diff --git a/crypto/random_pool.c b/crypto/random_pool.c new file mode 100644 index 0000000000..fed59bd727 --- /dev/null +++ b/crypto/random_pool.c @@ -0,0 +1,561 @@ +/**************************************************************************** + * crypto/random_pool.c + * + * Copyright (C) 2015-2017 Haltian Ltd. All rights reserved. + * Authors: Juha Niskanen + * Jussi Kivilinna + * + * 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, this list of conditions and the following disclaimer. + * 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. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS 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 ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include + +/**************************************************************************** + * Definitions + ****************************************************************************/ + +#ifndef MIN +#define MIN(a,b) ((a) < (b) ? (a) : (b)) +#endif + +#define ROTL_32(x,n) ( ((x) << (n)) | ((x) >> (32-(n))) ) +#define ROTR_32(x,n) ( ((x) >> (n)) | ((x) << (32-(n))) ) + +/**************************************************************************** + * Private Function Prototypes + ****************************************************************************/ + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +struct blake2xs_rng_s +{ + uint32_t out_node_offset; + blake2s_param param; + blake2s_state ctx; + char out_root[BLAKE2S_OUTBYTES]; +}; + +struct rng_s +{ + sem_t rd_sem; /* Threads can only exclusively access the RNG */ + volatile uint32_t rd_addptr; + volatile uint32_t rd_newentr; + volatile uint8_t rd_rotate; + volatile uint8_t rd_prev_time; + volatile uint16_t rd_prev_irq; + bool output_initialized; + struct blake2xs_rng_s blake2xs; +}; + +enum +{ + POOL_SIZE = ENTROPY_POOL_SIZE, + POOL_MASK = (POOL_SIZE - 1), + + MIN_SEED_NEW_ENTROPY_WORDS = 128, + MAX_SEED_NEW_ENTROPY_WORDS = 1024 +}; + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +static struct rng_s g_rng; + +#ifdef CONFIG_BOARD_ENTROPY_POOL +/* Entropy pool structure can be provided by board source. Use for this is, + * for example, allocate entropy pool from special area of RAM which content + * is kept over system reset. */ + +# define entropy_pool board_entropy_pool +#else +static struct entropy_pool_s entropy_pool; +#endif + +/* Polynomial from paper "The Linux Pseudorandom Number Generator Revisited" + * x^POOL_SIZE + x^104 + x^76 + x^51 + x^25 + x + 1 */ + +static const uint32_t pool_stir[] = { POOL_SIZE, 104, 76, 51, 25, 1 }; + +/* Derived from IEEE 802.3 CRC-32 */ + +static const uint32_t pool_twist[8] = +{ + 0x00000000, 0x3b6e20c8, 0x76dc4190, 0x4db26158, + 0xedb88320, 0xd6d6a3e8, 0x9b64c2b0, 0xa00ae278 +}; + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Function: addentropy + * + * Description: + * + * This function adds a number of integers into the entropy pool. + * The pool is stirred with a polynomial of degree POOL_SIZE over GF(2). + * + * Code is inspired by add_entropy_words() function of OpenBSD kernel. + * + * Parameters: + * buf - Buffer of integers to be added + * n - Number of elements in buf + * inc_new - Count element as new entry + * + * Returned Value: + * None + * + ****************************************************************************/ + +static void addentropy(FAR const uint32_t *buf, size_t n, bool inc_new) +{ + /* Compile time check for that POOL_SIZE is power of two. */ + + static char pool_size_p2_check[1 - ((POOL_SIZE & (POOL_SIZE - 1)) * 2)]; + + UNUSED(pool_size_p2_check); + + while (n-- > 0) + { + uint32_t rotate; + uint32_t w; + uint32_t i; + + rotate = g_rng.rd_rotate; + w = ROTL_32(*buf, rotate); + i = g_rng.rd_addptr = (g_rng.rd_addptr - 1) & POOL_MASK; + + /* Normal round, we add 7 bits of rotation to the pool. + * At the beginning of the pool, we add extra 7 bits + * rotation, in order for successive passes spread the + * input bits across the pool evenly. + */ + + g_rng.rd_rotate = (rotate + (i ? 7 : 14)) & 31; + + /* XOR pool contents corresponding to polynomial terms */ + + w ^= entropy_pool.pool[(i + pool_stir[1]) & POOL_MASK]; + w ^= entropy_pool.pool[(i + pool_stir[2]) & POOL_MASK]; + w ^= entropy_pool.pool[(i + pool_stir[3]) & POOL_MASK]; + w ^= entropy_pool.pool[(i + pool_stir[4]) & POOL_MASK]; + w ^= entropy_pool.pool[(i + pool_stir[5]) & POOL_MASK]; + w ^= entropy_pool.pool[i]; /* 2^POOL_SIZE */ + + entropy_pool.pool[i] = (w >> 3) ^ pool_twist[w & 7]; + buf++; + + if (inc_new) + { + g_rng.rd_newentr += 1; + } + } +} + +/**************************************************************************** + * Function: getentropy + * + * Description: + * Hash entropy pool to BLAKE2s context. This is an internal interface for + * seeding out-facing BLAKE2Xs random bit generator from entropy pool. + * + * Code is inspired by extract_entropy() function of OpenBSD kernel. + * + * Note that this function cannot fail, other than by asserting. + * + * Warning: In protected kernel builds, this interface MUST NOT be + * exported to userspace. This interface MUST NOT be used as a + * general-purpose random bit generator! + * + * Parameters: + * S - BLAKE2s instance that will absorb entropy pool + * + * Returned Value: + * None + * + ****************************************************************************/ + +static void getentropy(FAR blake2s_state *S) +{ +#ifdef CONFIG_SCHED_CPULOAD + struct cpuload_s load; +#endif + uint32_t tmp; + + add_sw_randomness(g_rng.rd_newentr); + + /* Absorb the entropy pool */ + + blake2s_update(S, (FAR const uint32_t *)entropy_pool.pool, + sizeof(entropy_pool.pool)); + + /* Add something back so repeated calls to this function + * return different values. + */ + + tmp = sizeof(entropy_pool.pool); + tmp <<= 27; +#ifdef CONFIG_SCHED_CPULOAD + clock_cpuload(0, &load); + tmp += load.total ^ ROTL_32(load.active, 23); +#endif + add_sw_randomness(tmp); + + g_rng.rd_newentr = 0; +} + +/* The BLAKE2Xs based random number generator algorithm. + * + * BLAKE2X is a extensible-output function (XOF) variant of BLAKE2 hash + * function. One application of XOFs is use as deterministic random bit + * number generator (DRBG) as used here. BLAKE2 specification is available + * at https://blake2.net/ + * + * BLAKE2Xs here implementation is based on public-domain/CC0 BLAKE2 reference + * implementation by Samual Neves, at + * https://github.com/BLAKE2/BLAKE2/tree/master/ref + * Copyright 2012, Samuel Neves + */ + +static void rng_reseed(void) +{ + blake2s_param P = {}; + + /* Reset output node counter. */ + + g_rng.blake2xs.out_node_offset = 0; + + /* Initialize parameter block */ + + P.digest_length = BLAKE2S_OUTBYTES; + P.key_length = 0; + P.fanout = 1; + P.depth = 1; + blake2_store32(P.leaf_length, 0); + blake2_store32(P.node_offset, 0); + blake2_store16(P.xof_length, 0xffff); + P.node_depth = 0; + P.inner_length = 0; + g_rng.blake2xs.param = P; + + blake2s_init_param(&g_rng.blake2xs.ctx, &g_rng.blake2xs.param); + + /* Initialize with randomness from entropy pool */ + + getentropy(&g_rng.blake2xs.ctx); + + /* Absorb also the previous root */ + + blake2s_update(&g_rng.blake2xs.ctx, g_rng.blake2xs.out_root, + sizeof(g_rng.blake2xs.out_root)); + + /* Finalize the new root hash */ + + blake2s_final(&g_rng.blake2xs.ctx, g_rng.blake2xs.out_root, + BLAKE2S_OUTBYTES); + + explicit_bzero(&g_rng.blake2xs.ctx, sizeof(g_rng.blake2xs.ctx)); + + /* Setup parameters for output phase. */ + + g_rng.blake2xs.param.key_length = 0; + g_rng.blake2xs.param.fanout = 0; + blake2_store32(g_rng.blake2xs.param.leaf_length, BLAKE2S_OUTBYTES); + g_rng.blake2xs.param.inner_length = BLAKE2S_OUTBYTES; + g_rng.blake2xs.param.node_depth = 0; + + g_rng.output_initialized = true; +} + +static void rng_buf_internal(FAR void *bytes, size_t nbytes) +{ + if (!g_rng.output_initialized) + { + if (g_rng.rd_newentr < MIN_SEED_NEW_ENTROPY_WORDS) + { + cryptwarn("Entropy pool RNG initialized with very low entropy. " + " Consider implementing CONFIG_BOARD_INITRNGSEED!\n"); + } + + rng_reseed(); + } + else if (g_rng.rd_newentr >= MAX_SEED_NEW_ENTROPY_WORDS) + { + /* Initial entropy is low. Reseed when we have accumulated more. */ + + rng_reseed(); + } + else if (g_rng.blake2xs.out_node_offset == UINT32_MAX) + { + /* Maximum BLAKE2Xs output reached (2^32-1 output blocks, maximum 128 GiB + * bytes), reseed. */ + + rng_reseed(); + } + + /* Output phase for BLAKE2Xs. */ + + for (; nbytes > 0; ++g_rng.blake2xs.out_node_offset) + { + size_t block_size = MIN(nbytes, BLAKE2S_OUTBYTES); + + /* Initialize state */ + + g_rng.blake2xs.param.digest_length = block_size; + blake2_store32(g_rng.blake2xs.param.node_offset, + g_rng.blake2xs.out_node_offset); + blake2s_init_param(&g_rng.blake2xs.ctx, &g_rng.blake2xs.param); + + /* Process state and output random bytes */ + + blake2s_update(&g_rng.blake2xs.ctx, g_rng.blake2xs.out_root, + sizeof(g_rng.blake2xs.out_root)); + blake2s_final(&g_rng.blake2xs.ctx, bytes, block_size); + + bytes += block_size; + nbytes -= block_size; + } +} + +static void rng_init(void) +{ + crypinfo("Initializing RNG\n"); + + memset(&g_rng, 0, sizeof(struct rng_s)); + sem_init(&g_rng.rd_sem, 0, 1); + + /* We do not initialize output here because this is called + * quite early in boot and there may not be enough entropy. + * + * Board level may define CONFIG_BOARD_INITRNGSEED if it implements + * early random seeding. + */ +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Function: up_rngaddint + * + * Description: + * Add one integer to entropy pool, contributing a specific kind + * of entropy to pool. + * + * Parameters: + * kindof - Enumeration constant telling where val came from + * val - Integer to be added + * + * Returned Value: + * None + * + ****************************************************************************/ + +void up_rngaddint(enum rnd_source_t kindof, int val) +{ + uint32_t buf[1]; + + buf[0] = val; + + up_rngaddentropy(kindof, buf, 1); +} + +/**************************************************************************** + * Function: up_rngaddentropy + * + * Description: + * Add buffer of integers to entropy pool. + * + * Parameters: + * kindof - Enumeration constant telling where val came from + * buf - Buffer of integers to be added + * n - Number of elements in buf + * + * Returned Value: + * None + * + ****************************************************************************/ + +void up_rngaddentropy(enum rnd_source_t kindof, FAR const uint32_t *buf, + size_t n) +{ + uint32_t tbuf[1]; + struct timespec ts; + bool new_inc = true; + + if (kindof == RND_SRC_IRQ && n > 0) + { + /* Ignore interrupt randomness if previous interrupt was from same + * source. */ + + if (buf[0] == g_rng.rd_prev_irq) + { + return; + } + + g_rng.rd_prev_irq = buf[0]; + } + + /* We don't actually track what kind of entropy we receive, + * just add it all to pool. One exception is interrupt + * and timer randomness, where we limit rate of new pool entry + * counting to prevent high interrupt rate triggering RNG + * reseeding too fast. + */ + + (void)clock_gettime(CLOCK_REALTIME, &ts); + tbuf[0] = ROTL_32(ts.tv_nsec, 17) ^ ROTL_32(ts.tv_sec, 3); + tbuf[0] += ROTL_32(kindof, 27); + tbuf[0] += ROTL_32((uintptr_t)&tbuf[0], 11); + + if (kindof == RND_SRC_TIME || kindof == RND_SRC_IRQ) + { + uint8_t curr_time = ts.tv_sec * 8 + ts.tv_nsec / (NSEC_PER_SEC / 8); + + /* Allow interrupts/timers increase entropy counter at max rate + * of 8 Hz. */ + + if (g_rng.rd_prev_time == curr_time) + { + new_inc = false; + } + else + { + g_rng.rd_prev_time = curr_time; + } + } + + if (n > 0) + { + tbuf[0] ^= buf[0]; + buf++; + n--; + } + + addentropy(tbuf, 1, new_inc); + + if (n > 0) + { + addentropy(buf, n, new_inc); + } +} + +/**************************************************************************** + * Function: up_rngreseed + * + * Description: + * Force reseeding random number generator from entropy pool + * + ****************************************************************************/ + +void up_rngreseed(void) +{ + while (sem_wait(&g_rng.rd_sem) != 0) + { + assert(errno == EINTR); + } + + if (g_rng.rd_newentr >= MIN_SEED_NEW_ENTROPY_WORDS) + { + rng_reseed(); + } + + sem_post(&g_rng.rd_sem); +} + +/**************************************************************************** + * Function: up_randompool_initialize + * + * Description: + * Initialize entropy pool and random number generator + * + ****************************************************************************/ + +void up_randompool_initialize(void) +{ + rng_init(); + +#ifdef CONFIG_BOARD_INITRNGSEED + board_init_rngseed(); +#endif +} + +/**************************************************************************** + * Function: getrandom + * + * Description: + * Fill a buffer of arbitrary length with randomness. This is the + * preferred interface for getting random numbers. The traditional + * /dev/random approach is susceptible for things like the attacker + * exhausting file descriptors on purpose. + * + * Note that this function cannot fail, other than by asserting. + * + * Parameters: + * bytes - Buffer for returned random bytes + * nbytes - Number of bytes requested. + * + * Returned Value: + * None + * + ****************************************************************************/ + +void getrandom(FAR void *bytes, size_t nbytes) +{ + while (sem_wait(&g_rng.rd_sem) != 0) + { + assert(errno == EINTR); + } + + rng_buf_internal(bytes, nbytes); + sem_post(&g_rng.rd_sem); +} diff --git a/drivers/Kconfig b/drivers/Kconfig index 00adcc8f17..511d63c5f6 100644 --- a/drivers/Kconfig +++ b/drivers/Kconfig @@ -69,6 +69,15 @@ config DEV_URANDOM_CONGRUENTIAL NOTE: Not cyptographically secure +config DEV_URANDOM_RANDOM_POOL + bool "Entropy pool" + depends on CRYPTO_RANDOM_POOL + ---help--- + Use the entropy pool CPRNG output for urandom algorithm. + + NOTE: May or may not be cyptographically secure, depending upon the + quality entropy available to entropy pool. + config DEV_URANDOM_ARCH bool "Architecture-specific" depends on ARCH_HAVE_RNG diff --git a/drivers/analog/adc.c b/drivers/analog/adc.c index d81971f101..be1682e3cd 100644 --- a/drivers/analog/adc.c +++ b/drivers/analog/adc.c @@ -60,6 +60,7 @@ #include #include #include +#include #include @@ -296,6 +297,10 @@ static ssize_t adc_read(FAR struct file *filep, FAR char *buffer, size_t buflen) break; } + /* Feed ADC data to entropy pool */ + + add_sensor_randomness(msg->am_data); + /* Copy the message to the user buffer */ if (msglen == 1) diff --git a/drivers/dev_urandom.c b/drivers/dev_urandom.c index e7022cb9f5..5b59736907 100644 --- a/drivers/dev_urandom.c +++ b/drivers/dev_urandom.c @@ -49,11 +49,13 @@ #include #include #include +#include #include #include #include #include +#include #if defined(CONFIG_DEV_URANDOM) && !defined(CONFIG_DEV_URANDOM_ARCH) @@ -62,13 +64,18 @@ ****************************************************************************/ #if !defined(CONFIG_DEV_URANDOM_CONGRUENTIAL) && \ - !defined(CONFIG_DEV_URANDOM_XORSHIFT128) -# define CONFIG_DEV_URANDOM_XORSHIFT128 1 + !defined(CONFIG_DEV_URANDOM_XORSHIFT128) && \ + !defined(CONFIG_DEV_URANDOM_RANDOM_POOL) +# ifdef CONFIG_CRYPTO_RANDOM_POOL +# define CONFIG_DEV_URANDOM_RANDOM_POOL 1 +# else +# define CONFIG_DEV_URANDOM_XORSHIFT128 1 +# endif #endif #ifdef CONFIG_DEV_URANDOM_XORSHIFT128 # define PRNG() do_xorshift128() -#else /* CONFIG_DEV_URANDOM_CONGRUENTIAL */ +#elif defined(CONFIG_DEV_URANDOM_CONGRUENTIAL) # define PRNG() do_congruential() #endif @@ -158,6 +165,12 @@ static inline uint32_t do_congruential(void) static ssize_t devurand_read(FAR struct file *filep, FAR char *buffer, size_t len) { +#ifdef CONFIG_DEV_URANDOM_RANDOM_POOL + if (len) + { + getrandom(buffer, len); + } +#else size_t n; uint32_t rnd; @@ -208,6 +221,7 @@ static ssize_t devurand_read(FAR struct file *filep, FAR char *buffer, } while (--n > 0); } +#endif /* CONFIG_DEV_URANDOM_RANDOM_POOL */ return len; } @@ -228,6 +242,56 @@ static ssize_t devurand_write(FAR struct file *filep, FAR const char *buffer, memcpy(&seed, buffer, len); srand(seed); return len; +#elif defined(CONFIG_DEV_URANDOM_RANDOM_POOL) + const unsigned int alignmask = sizeof(uint32_t) - 1; + const size_t initlen = len; + uint32_t tmp = 0; + size_t currlen; + + if (!len) + { + return 0; + } + + /* Seed entropy pool with data from user. */ + + if ((uintptr_t)buffer & alignmask) + { + /* Make unaligned input aligned. */ + + currlen = min(sizeof(uint32_t) - ((uintptr_t)buffer & alignmask), len); + memcpy(&tmp, buffer, currlen); + up_rngaddint(RND_SRC_SW, tmp); + + len -= currlen; + buffer += currlen; + } + + if (len >= sizeof(uint32_t)) + { + /* Handle bulk aligned, word-sized data. */ + + DEBUGASSERT(((uintptr_t)buffer & alignmask) == 0); + currlen = len / sizeof(uint32_t); + up_rngaddentropy(RND_SRC_SW, (FAR uint32_t *)buffer, currlen); + buffer += currlen * sizeof(uint32_t); + len %= sizeof(uint32_t); + } + + if (len > 0) + { + /* Handle trailing bytes. */ + + DEBUGASSERT(len < sizeof(uint32_t)); + memcpy(&tmp, buffer, len); + up_rngaddint(RND_SRC_SW, tmp); + } + + /* Reseeding of random number generator from entropy pool. */ + + up_rngreseed(); + + return initlen; #else len = min(len, sizeof(g_prng.u)); memcpy(&g_prng.u, buffer, len); @@ -274,6 +338,8 @@ void devurandom_register(void) #ifdef CONFIG_DEV_URANDOM_CONGRUENTIAL srand(10197); +#elif defined(CONFIG_DEV_URANDOM_RANDOM_POOL) + up_randompool_initialize(); #else g_prng.state.w = 97; g_prng.state.x = 101; diff --git a/drivers/input/ads7843e.c b/drivers/input/ads7843e.c index d9c2c3b988..6e4e9395ec 100644 --- a/drivers/input/ads7843e.c +++ b/drivers/input/ads7843e.c @@ -70,6 +70,7 @@ #include #include #include +#include #include #include @@ -624,6 +625,8 @@ static void ads7843e_worker(FAR void *arg) y = ads7843e_sendcmd(priv, ADS7843_CMD_YPOSITION); #endif + add_ui_randomness((x << 16) | y); + /* Perform a thresholding operation so that the results will be more stable. * If the difference from the last sample is small, then ignore the event. * REVISIT: Should a large change in pressure also generate a event? diff --git a/drivers/input/ajoystick.c b/drivers/input/ajoystick.c index aaba021b95..6665b8fdd2 100644 --- a/drivers/input/ajoystick.c +++ b/drivers/input/ajoystick.c @@ -60,6 +60,7 @@ #include #include #include +#include #include @@ -321,6 +322,8 @@ static void ajoy_sample(FAR struct ajoy_upperhalf_s *priv) DEBUGASSERT(lower->al_buttons); sample = lower->al_buttons(lower); + add_ui_randomness(sample); + #if !defined(CONFIG_DISABLE_POLL) || !defined(CONFIG_DISABLE_SIGNALS) /* Determine which buttons have been newly pressed and which have been * newly released. diff --git a/drivers/input/button_upper.c b/drivers/input/button_upper.c index 2c03d3de3e..b4432cbad3 100644 --- a/drivers/input/button_upper.c +++ b/drivers/input/button_upper.c @@ -56,6 +56,7 @@ #include #include #include +#include #include @@ -317,6 +318,8 @@ static void btn_sample(FAR struct btn_upperhalf_s *priv) DEBUGASSERT(lower->bl_buttons); sample = lower->bl_buttons(lower); + add_ui_randomness(sample); + #if !defined(CONFIG_DISABLE_POLL) || !defined(CONFIG_DISABLE_SIGNALS) /* Determine which buttons have been newly pressed and which have been * newly released. diff --git a/drivers/input/djoystick.c b/drivers/input/djoystick.c index 1cc1b54004..bd3c9e4703 100644 --- a/drivers/input/djoystick.c +++ b/drivers/input/djoystick.c @@ -60,6 +60,7 @@ #include #include #include +#include #include @@ -321,6 +322,8 @@ static void djoy_sample(FAR struct djoy_upperhalf_s *priv) DEBUGASSERT(lower->dl_sample); sample = lower->dl_sample(lower); + add_ui_randomness(sample); + #if !defined(CONFIG_DISABLE_POLL) || !defined(CONFIG_DISABLE_SIGNALS) /* Determine which buttons have been newly pressed and which have been * newly released. diff --git a/drivers/input/max11802.c b/drivers/input/max11802.c index 82ad1f6689..7fb2087f06 100644 --- a/drivers/input/max11802.c +++ b/drivers/input/max11802.c @@ -64,6 +64,7 @@ #include #include #include +#include #include #include @@ -628,6 +629,8 @@ static void max11802_worker(FAR void *arg) } while (readycount < 2); + add_ui_randomness((x << 16) | y); + /* Continue to sample the position while the pen is down */ wd_start(priv->wdog, MAX11802_WDOG_DELAY, max11802_wdog, 1, diff --git a/drivers/input/mxt.c b/drivers/input/mxt.c index e115285171..01d11bc63b 100644 --- a/drivers/input/mxt.c +++ b/drivers/input/mxt.c @@ -64,6 +64,7 @@ #include #include #include +#include #include #include @@ -889,6 +890,8 @@ static void mxt_touch_event(FAR struct mxt_dev_s *priv, sample->pressure = pressure; sample->valid = true; + add_ui_randomness((x << 16) ^ y ^ (area << 9) ^ (pressure << 1)); + /* If this is not the first touch report, then report it as a move: * Same contact, same ID, but with a new, updated position. * The CONTACT_REPORT state means that a contacted has been detected, diff --git a/drivers/input/stmpe811_temp.c b/drivers/input/stmpe811_temp.c index 0cb5c686c7..5bbad0d455 100644 --- a/drivers/input/stmpe811_temp.c +++ b/drivers/input/stmpe811_temp.c @@ -48,6 +48,7 @@ #include #include +#include #include "stmpe811.h" @@ -139,6 +140,8 @@ uint16_t stmpe811_tempread(STMPE811_HANDLE handle) temp1 = stmpe811_getreg8(priv, STMPE811_SYS_CTRL2); temp2 = stmpe811_getreg8(priv, STMPE811_SYS_CTRL2+1); + add_sensor_randomness((temp1 << 8) | temp2); + /* Scale the temperature (where Vio is assumed to be .33) */ temp = ((uint32_t)(temp1 & 3) << 8) | temp2; diff --git a/drivers/input/stmpe811_tsc.c b/drivers/input/stmpe811_tsc.c index b58e9feebd..c49723c731 100644 --- a/drivers/input/stmpe811_tsc.c +++ b/drivers/input/stmpe811_tsc.c @@ -62,6 +62,7 @@ #include #include #include +#include #include #include @@ -534,6 +535,8 @@ static ssize_t stmpe811_read(FAR struct file *filep, FAR char *buffer, size_t le report->point[0].y = sample.y; report->point[0].pressure = sample.z; + add_ui_randomness((sample.x << 16) ^ (sample.y << 8) ^ sample.z); + /* Report the appropriate flags */ if (sample.contact == CONTACT_UP) diff --git a/drivers/input/tsc2007.c b/drivers/input/tsc2007.c index 8d49a2e070..fb82cc0557 100644 --- a/drivers/input/tsc2007.c +++ b/drivers/input/tsc2007.c @@ -68,6 +68,7 @@ #include #include #include +#include #include #include @@ -619,7 +620,7 @@ static void tsc2007_worker(FAR void *arg) * vertical or horizontal resistive network. The A/D converter converts * the voltage measured at the point where the panel is touched. A measurement * of the Y position of the pointing device is made by connecting the X+ - * input to a data converter chip, turning on the Y+ and Y– drivers, and + * input to a data converter chip, turning on the Y+ and Y- drivers, and * digitizing the voltage seen at the X+ input ..." * * "... it is recommended that whenever the host writes to the TSC2007, the @@ -698,6 +699,8 @@ static void tsc2007_worker(FAR void *arg) priv->sample.y = y; priv->sample.pressure = pressure; priv->sample.valid = true; + + add_ui_randomness((x << 16) ^ y ^ (pressure << 9)); } /* Note the availability of new measurements */ diff --git a/drivers/sensors/adxl345_base.c b/drivers/sensors/adxl345_base.c index 8a92d059eb..93ebf9cf45 100644 --- a/drivers/sensors/adxl345_base.c +++ b/drivers/sensors/adxl345_base.c @@ -48,6 +48,7 @@ #include #include +#include #include "adxl345.h" @@ -165,6 +166,9 @@ static ssize_t adxl345_read(FAR struct file *filep, FAR char *buffer, size_t len sample.data_z = adxl345_getreg8(priv, ADXL345_DATAZ1); sample.data_z = (sample.data_z << 8) | adxl345_getreg8(priv, ADXL345_DATAZ0); + add_sensor_randomness(sample.data_x); + add_sensor_randomness((sample.data_z << 16) | sample.data_y); + /* Return read sample */ buffer = (FAR char *) &sample; diff --git a/drivers/sensors/bh1750fvi.c b/drivers/sensors/bh1750fvi.c index 88ba994a38..c0c2d38de0 100644 --- a/drivers/sensors/bh1750fvi.c +++ b/drivers/sensors/bh1750fvi.c @@ -51,6 +51,7 @@ #include #include #include +#include #if defined(CONFIG_I2C) && defined(CONFIG_BH1750FVI) @@ -250,6 +251,8 @@ static ssize_t bh1750fvi_read(FAR struct file *filep, FAR char *buffer, buffer[0] = lux & 0xFF; buffer[1] = (lux & 0xFF00) >> 8; + add_sensor_randomness(lux); + return buflen; } diff --git a/drivers/sensors/bmg160.c b/drivers/sensors/bmg160.c index 03ad72a5d0..534985d133 100644 --- a/drivers/sensors/bmg160.c +++ b/drivers/sensors/bmg160.c @@ -51,6 +51,7 @@ #include #include +#include #if defined(CONFIG_SPI) && defined(CONFIG_BMG160) @@ -243,6 +244,10 @@ static void bmg160_read_measurement_data(FAR struct bmg160_dev_s *dev) /* Give back the semaphore */ sem_post(&dev->datasem); + + /* Feed sensor data to entropy pool */ + + add_sensor_randomness((x_gyr << 16) ^ (y_gyr << 8) ^ z_gyr); } /**************************************************************************** diff --git a/drivers/sensors/bmp180.c b/drivers/sensors/bmp180.c index 1a7d538c33..a0857d8e57 100644 --- a/drivers/sensors/bmp180.c +++ b/drivers/sensors/bmp180.c @@ -53,6 +53,7 @@ #include #include #include +#include #if defined(CONFIG_I2C) && defined(CONFIG_BMP180) @@ -464,6 +465,10 @@ static int bmp180_getpressure(FAR struct bmp180_dev_s *priv) bmp180_read_press_temp(priv); + /* Feed raw sensor data to entropy pool */ + + add_sensor_randomness((priv->bmp180_utemp << 16) ^ priv->bmp180_upress); + /* Calculate true temperature */ x1 = ((priv->bmp180_utemp - priv->bmp180_cal_ac6) * priv->bmp180_cal_ac5) >> 15; diff --git a/drivers/sensors/kxtj9.c b/drivers/sensors/kxtj9.c index 70ec5ec808..875a4486b4 100644 --- a/drivers/sensors/kxtj9.c +++ b/drivers/sensors/kxtj9.c @@ -51,6 +51,7 @@ #include #include #include +#include #if defined(CONFIG_I2C) && defined(CONFIG_SENSOR_KXTJ9) @@ -459,6 +460,12 @@ static int kxtj9_read_sensor_data(FAR struct kxtj9_dev_s *priv, kxtj9_reg_read(priv, INT_REL, &data, 1); sem_post(&priv->exclsem); + + /* Feed sensor data to entropy pool */ + + add_sensor_randomness((acc_data[0] << 16) ^ (acc_data[1] << 8) ^ + acc_data[2]); + return OK; } diff --git a/drivers/sensors/l3gd20.c b/drivers/sensors/l3gd20.c index d400f21308..10bcbeb77a 100644 --- a/drivers/sensors/l3gd20.c +++ b/drivers/sensors/l3gd20.c @@ -49,6 +49,7 @@ #include #include +#include #include @@ -257,6 +258,10 @@ static void l3gd20_read_measurement_data(FAR struct l3gd20_dev_s *dev) /* Give back the semaphore */ sem_post(&dev->datasem); + + /* Feed sensor data to entropy pool */ + + add_sensor_randomness((x_gyr << 16) ^ (y_gyr << 8) ^ (z_gyr << 0)); } /**************************************************************************** diff --git a/drivers/sensors/lis331dl.c b/drivers/sensors/lis331dl.c index f94a3b2ec2..deef62d705 100644 --- a/drivers/sensors/lis331dl.c +++ b/drivers/sensors/lis331dl.c @@ -48,6 +48,7 @@ #include #include #include +#include #if defined(CONFIG_I2C) && defined(CONFIG_LIS331DL) @@ -414,6 +415,11 @@ lis331dl_getreadings(FAR struct lis331dl_dev_s * dev) return NULL; } + /* Feed sensor data to entropy pool */ + + add_sensor_randomness((retval[2] << 16) ^ (retval[4] << 8) ^ + (retval[6] << 0)); + dev->a.x = retval[2]; dev->a.y = retval[4]; dev->a.z = retval[6]; diff --git a/drivers/sensors/lis3dsh.c b/drivers/sensors/lis3dsh.c index 243f89874d..80db21c3f4 100644 --- a/drivers/sensors/lis3dsh.c +++ b/drivers/sensors/lis3dsh.c @@ -48,6 +48,7 @@ #include #include +#include #include #include @@ -245,6 +246,10 @@ static void lis3dsh_read_measurement_data(FAR struct lis3dsh_dev_s *dev) /* Give back the semaphore */ sem_post(&dev->datasem); + + /* Feed sensor data to entropy pool */ + + add_sensor_randomness((x_acc << 16) ^ (y_acc << 8) ^ (z_acc << 0)); } /**************************************************************************** diff --git a/drivers/sensors/lis3mdl.c b/drivers/sensors/lis3mdl.c index cdb04e776e..64f33bae7a 100644 --- a/drivers/sensors/lis3mdl.c +++ b/drivers/sensors/lis3mdl.c @@ -47,6 +47,7 @@ #include #include +#include #include #include @@ -251,6 +252,11 @@ static void lis3mdl_read_measurement_data(FAR struct lis3mdl_dev_s *dev) /* Give back the semaphore */ sem_post(&dev->datasem); + + /* Feed sensor data to entropy pool */ + + add_sensor_randomness((x_mag << 16) ^ (y_mag << 10) ^ (z_mag << 2) ^ + temperature); } /**************************************************************************** diff --git a/drivers/sensors/lm75.c b/drivers/sensors/lm75.c index ce9445558b..6fa670e4e6 100644 --- a/drivers/sensors/lm75.c +++ b/drivers/sensors/lm75.c @@ -49,6 +49,7 @@ #include #include #include +#include #if defined(CONFIG_I2C) && defined(CONFIG_I2C_LM75) @@ -269,6 +270,8 @@ static int lm75_readtemp(FAR struct lm75_dev_s *priv, FAR b16_t *temp) return ret; } + add_sensor_randomness(temp16); + sninfo("Centigrade: %08x\n", temp16); /* Was fahrenheit requested? */ diff --git a/drivers/sensors/lm92.c b/drivers/sensors/lm92.c index c801e6633c..63ea40db38 100644 --- a/drivers/sensors/lm92.c +++ b/drivers/sensors/lm92.c @@ -51,6 +51,7 @@ #include #include #include +#include #if defined(CONFIG_I2C) && defined(CONFIG_LM92) @@ -272,6 +273,8 @@ static int lm92_readtemp(FAR struct lm92_dev_s *priv, FAR b16_t *temp) return ret; } + add_sensor_randomness(temp16); + sninfo("Centigrade: %08x\n", temp16); /* Was Fahrenheit requested? */ diff --git a/drivers/sensors/lsm9ds1.c b/drivers/sensors/lsm9ds1.c index ae69bd68c7..d54cdce379 100644 --- a/drivers/sensors/lsm9ds1.c +++ b/drivers/sensors/lsm9ds1.c @@ -50,6 +50,7 @@ #include #include #include +#include #if defined(CONFIG_I2C) && defined(CONFIG_SN_LSM9DS1) @@ -1244,6 +1245,7 @@ static ssize_t lsm9ds1_read(FAR struct file *filep, FAR char *buffer, uint8_t regaddr; uint8_t lo; uint8_t hi; + uint32_t merge = 0; /* Sanity check */ @@ -1301,6 +1303,10 @@ static ssize_t lsm9ds1_read(FAR struct file *filep, FAR char *buffer, data = ((uint16_t)hi << 8) | (uint16_t)lo; + /* Collect entropy */ + + merge += data ^ (merge >> 16); + /* The value is positive */ if (data < 0x8000) @@ -1329,6 +1335,10 @@ static ssize_t lsm9ds1_read(FAR struct file *filep, FAR char *buffer, } } + /* Feed sensor data to entropy pool */ + + add_sensor_randomness(merge); + return nsamples * samplesize; } diff --git a/drivers/sensors/max31855.c b/drivers/sensors/max31855.c index 19800a1c59..97b56f42ec 100644 --- a/drivers/sensors/max31855.c +++ b/drivers/sensors/max31855.c @@ -54,6 +54,7 @@ #include #include #include +#include #if defined(CONFIG_SPI) && defined(CONFIG_MAX31855) @@ -220,6 +221,10 @@ static ssize_t max31855_read(FAR struct file *filep, FAR char *buffer, size_t bu sninfo("Read from MAX31855 = 0x%08X\n", regval); + /* Feed sensor data to entropy pool */ + + add_sensor_randomness(regval); + /* If negative, fix signal bits */ if (regval & 0x80000000) diff --git a/drivers/sensors/max6675.c b/drivers/sensors/max6675.c index 0d205a049b..71a0e2d142 100644 --- a/drivers/sensors/max6675.c +++ b/drivers/sensors/max6675.c @@ -54,6 +54,7 @@ #include #include #include +#include #if defined(CONFIG_SPI) && defined(CONFIG_MAX6675) @@ -230,6 +231,10 @@ static ssize_t max6675_read(FAR struct file *filep, FAR char *buffer, size_t buf ret = -EINVAL; } + /* Feed sensor data to entropy pool */ + + add_sensor_randomness(regval); + /* Get the temperature */ *temp = (regval & MAX6675_TEMP_COUPLE) >> 3; diff --git a/drivers/sensors/mb7040.c b/drivers/sensors/mb7040.c index 2bdaecee0e..125825cab0 100644 --- a/drivers/sensors/mb7040.c +++ b/drivers/sensors/mb7040.c @@ -51,6 +51,7 @@ #include #include #include +#include #if defined(CONFIG_I2C) && defined(CONFIG_MB7040) @@ -323,6 +324,10 @@ static int mb7040_ioctl(FAR struct file *filep, int cmd, unsigned long arg) if (ret == OK) { *ptr = (int32_t)range; + + /* Feed sensor data to entropy pool */ + + add_sensor_randomness(range); } sninfo("range: %04x ret: %d\n", *ptr, ret); diff --git a/drivers/sensors/mcp9844.c b/drivers/sensors/mcp9844.c index 77dcee773e..f895d86152 100644 --- a/drivers/sensors/mcp9844.c +++ b/drivers/sensors/mcp9844.c @@ -50,6 +50,7 @@ #include #include #include +#include #if defined(CONFIG_I2C) && defined(CONFIG_MCP9844) @@ -274,6 +275,10 @@ static int mcp9844_ioctl(FAR struct file *filep, int cmd, unsigned long arg) if (ret == OK) { + /* Feed sensor data to entropy pool */ + + add_sensor_randomness(raw_temperature); + /* BIT15 - 13 contain information if preset temperature values * have been exceeded or undercut. BIT12 is now not any longer * needed since we do have the sign information retrieved. diff --git a/drivers/sensors/mlx90393.c b/drivers/sensors/mlx90393.c index 93a53ef871..d5b27b801e 100644 --- a/drivers/sensors/mlx90393.c +++ b/drivers/sensors/mlx90393.c @@ -50,6 +50,7 @@ #include #include +#include #if defined(CONFIG_SPI) && defined(CONFIG_MLX90393) @@ -232,6 +233,11 @@ static void mlx90393_read_measurement_data(FAR struct mlx90393_dev_s *dev) /* Give back the semaphore */ sem_post(&dev->datasem); + + /* Feed sensor data to entropy pool */ + + add_sensor_randomness((x_mag << 17) ^ (y_mag << 9) ^ (z_mag << 1) ^ + temperature); } /**************************************************************************** diff --git a/drivers/sensors/mpl115a.c b/drivers/sensors/mpl115a.c index 38763f5c71..c23df63eaf 100644 --- a/drivers/sensors/mpl115a.c +++ b/drivers/sensors/mpl115a.c @@ -50,6 +50,7 @@ #include #include #include +#include #if defined(CONFIG_SPI) && defined(CONFIG_MPL115A) @@ -227,6 +228,11 @@ static void mpl115a_read_press_temp(FAR struct mpl115a_dev_s *priv) priv->mpl115a_temperature >>= 6; /* Tadc is 10bit unsigned */ sninfo("Temperature = %d\n", priv->mpl115a_temperature); + + /* Feed sensor data to entropy pool */ + + add_sensor_randomness((priv->mpl115a_pressure << 16) ^ + priv->mpl115a_temperature); } /**************************************************************************** diff --git a/drivers/sensors/ms58xx.c b/drivers/sensors/ms58xx.c index 47f04e57ca..3efdda2713 100644 --- a/drivers/sensors/ms58xx.c +++ b/drivers/sensors/ms58xx.c @@ -53,6 +53,7 @@ #include #include #include +#include #if defined(CONFIG_I2C) && defined(CONFIG_MS58XX) @@ -725,6 +726,8 @@ static int ms58xx_measure(FAR struct ms58xx_dev_s *priv) return ret; } + add_sensor_randomness(rawpress ^ rawtemp); + diff = (int32_t)rawtemp - (int32_t)priv->c5 * ((int32_t)1 << 8); temp = (int32_t)((int64_t)2000 + (int64_t)diff * (int64_t)priv->c6 / ((int64_t)1 << 23)); diff --git a/drivers/sensors/veml6070.c b/drivers/sensors/veml6070.c index 28030ba7ce..443782458a 100644 --- a/drivers/sensors/veml6070.c +++ b/drivers/sensors/veml6070.c @@ -48,6 +48,7 @@ #include #include #include +#include #if defined(CONFIG_I2C) && defined(CONFIG_VEML6070) @@ -272,6 +273,10 @@ static ssize_t veml6070_read(FAR struct file *filep, FAR char *buffer, buffer[0] = regdata; + /* Feed sensor data to entropy pool */ + + add_sensor_randomness((buffer[1] << 16) ^ buffer[0]); + return buflen; } diff --git a/drivers/sensors/xen1210.c b/drivers/sensors/xen1210.c index 0f7bfd2b1e..a14350921c 100644 --- a/drivers/sensors/xen1210.c +++ b/drivers/sensors/xen1210.c @@ -49,6 +49,7 @@ #include #include #include +#include #include "xen1210.h" @@ -442,6 +443,12 @@ void xen1210_getdata(FAR struct xen1210_dev_s *priv) #ifdef CONFIG_XEN1210_REGDEBUG _err("%02x->%02x\n", regaddr, regval); #endif + + /* Feed sensor data to entropy pool */ + + add_sensor_randomness((priv->sample.data_x << 8) ^ + (priv->sample.data_y << 4) ^ + (priv->sample.data_z << 4)); } /**************************************************************************** diff --git a/include/nuttx/board.h b/include/nuttx/board.h index cd08aceddd..0525499021 100644 --- a/include/nuttx/board.h +++ b/include/nuttx/board.h @@ -646,4 +646,20 @@ void board_crashdump(uintptr_t currentsp, FAR void *tcb, int lineno); #endif +/**************************************************************************** + * Name: board_initrngseed + * + * Description: + * If CONFIG_BOARD_INITRNGSEED is selected then board_init_rngseed is + * called at up_randompool_initialize() to feed initial random seed + * to RNG. Implemenation of this functions should feed at least + * MIN_SEED_NEW_ENTROPY_WORDS 32-bit random words to entropy-pool using + * up_rngaddentropy() or up_rngaddint(). + * + ****************************************************************************/ + +#ifdef CONFIG_BOARD_INITRNGSEED +void board_init_rngseed(void); +#endif + #endif /* __INCLUDE_NUTTX_BOARD_H */ diff --git a/include/nuttx/crypto/blake2s.h b/include/nuttx/crypto/blake2s.h new file mode 100644 index 0000000000..fa6667fb6f --- /dev/null +++ b/include/nuttx/crypto/blake2s.h @@ -0,0 +1,197 @@ +/**************************************************************************** + * include/nuttx/crypto/blake2s.h + * + * This code is based on public-domain/CC0 BLAKE2 reference implementation + * by Samual Neves, at https://github.com/BLAKE2/BLAKE2/tree/master/ref + * Copyright 2012, Samuel Neves + * + * Copyright (C) 2017 Haltian Ltd. All rights reserved. + * Authors: Jussi Kivilinna + * + * 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, this list of conditions and the following disclaimer. + * 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. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS 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 ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +#ifndef __INCLUDE_NUTTX_CRYPTO_BLAKE2S_H +#define __INCLUDE_NUTTX_CRYPTO_BLAKE2S_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include + +#ifdef __cplusplus +extern "C" +{ +#endif + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/**************************************************************************** + * Public Types + ****************************************************************************/ + +enum blake2s_constant +{ + BLAKE2S_BLOCKBYTES = 64, + BLAKE2S_OUTBYTES = 32, + BLAKE2S_KEYBYTES = 32, + BLAKE2S_SALTBYTES = 8, + BLAKE2S_PERSONALBYTES = 8 +}; + +typedef struct blake2s_state__ +{ + uint32_t h[8]; + uint32_t t[2]; + uint32_t f[2]; + size_t buflen; + size_t outlen; + uint8_t buf[BLAKE2S_BLOCKBYTES]; +} blake2s_state; + +typedef struct blake2s_param__ +{ + uint8_t digest_length; /* 1 */ + uint8_t key_length; /* 2 */ + uint8_t fanout; /* 3 */ + uint8_t depth; /* 4 */ + uint8_t leaf_length[4]; /* 8 */ + uint8_t node_offset[4]; /* 12 */ + uint8_t xof_length[2]; /* 14 */ + uint8_t node_depth; /* 15 */ + uint8_t inner_length; /* 16 */ + /* uint8_t reserved[0]; */ + uint8_t salt[BLAKE2S_SALTBYTES]; /* 24 */ + uint8_t personal[BLAKE2S_PERSONALBYTES]; /* 32 */ +} blake2s_param; + +#ifdef __GNUC__ > 3 +#define BLAKE2_UNALIGNED 1 +typedef uint32_t uint32_alias_t __attribute__((may_alias, aligned(1))); +typedef uint16_t uint16_alias_t __attribute__((may_alias, aligned(1))); +#endif + +/**************************************************************************** + * Public Function Prototypes + ****************************************************************************/ + +/* Streaming API */ + +int blake2s_init(FAR blake2s_state *S, size_t outlen); +int blake2s_init_key(FAR blake2s_state *S, size_t outlen, FAR const void *key, + size_t keylen); +int blake2s_init_param(FAR blake2s_state *S, FAR const blake2s_param *P); +int blake2s_update(FAR blake2s_state *S, FAR const void *in, size_t inlen); +int blake2s_final(FAR blake2s_state *S, FAR void *out, size_t outlen); + +/* Simple API */ + +int blake2s(FAR void *out, size_t outlen, FAR const void *in, size_t inlen, + FAR const void *key, size_t keylen); + +/**************************************************************************** + * Public Inline Functions + ****************************************************************************/ + +static inline uint32_t blake2_load32(FAR const void *src) +{ +#if defined(BLAKE2_UNALIGNED) && !defined(CONFIG_ENDIAN_BIG) + return *(FAR uint32_alias_t *)src; +#elif !defined(CONFIG_ENDIAN_BIG) + FAR const uint8_t *p = (FAR const uint8_t *)src; + return ((uint32_t)(p[0]) << 24) | + ((uint32_t)(p[1]) << 16) | + ((uint32_t)(p[2]) << 8) | + ((uint32_t)(p[3]) << 0); +#else + FAR const uint8_t *p = (FAR const uint8_t *)src; + return ((uint32_t)(p[0]) << 0) | + ((uint32_t)(p[1]) << 8) | + ((uint32_t)(p[2]) << 16) | + ((uint32_t)(p[3]) << 24); +#endif +} + +static inline uint16_t blake2_load16(FAR const void *src) +{ +#if defined(BLAKE2_UNALIGNED) && !defined(CONFIG_ENDIAN_BIG) + return *(FAR uint16_alias_t *)src; +#elif !defined(CONFIG_ENDIAN_BIG) + const uint8_t *p = (FAR const uint8_t *)src; + return ((uint16_t)(p[0]) << 8) | ((uint16_t)(p[1]) << 0); +#else + const uint8_t *p = (FAR const uint8_t *)src; + return ((uint16_t)(p[0]) << 0) | ((uint16_t)(p[1]) << 8); +#endif +} + +static inline void blake2_store16(FAR void *dst, uint16_t w) +{ +#if defined(BLAKE2_UNALIGNED) && !defined(CONFIG_ENDIAN_BIG) + *(FAR uint16_alias_t *)dst = w; +#elif !defined(CONFIG_ENDIAN_BIG) + FAR uint8_t *p = (FAR uint8_t *)dst; + p[1] = (uint8_t)w; w >>= 8; + p[0] = (uint8_t)w; +#else + FAR uint8_t *p = (FAR uint8_t *)dst; + p[0] = (uint8_t)w; w >>= 8; + p[1] = (uint8_t)w; +#endif +} + +static inline void blake2_store32(FAR void *dst, uint32_t w) +{ +#if defined(BLAKE2_UNALIGNED) && !defined(CONFIG_ENDIAN_BIG) + *(FAR uint32_alias_t *)dst = w; +#elif !defined(CONFIG_ENDIAN_BIG) + FAR uint8_t *p = (FAR uint8_t *) dst; + p[0] = (uint8_t)(w >> 24); + p[1] = (uint8_t)(w >> 16); + p[2] = (uint8_t)(w >> 8); + p[3] = (uint8_t)(w >> 0); +#else + FAR uint8_t *p = (FAR uint8_t *) dst; + p[0] = (uint8_t)(w >> 0); + p[1] = (uint8_t)(w >> 8); + p[2] = (uint8_t)(w >> 16); + p[3] = (uint8_t)(w >> 24); +#endif +} + +#ifdef __cplusplus +} +#endif + +#endif /* __INCLUDE_NUTTX_CRYPTO_BLAKE2S_H */ diff --git a/include/nuttx/random.h b/include/nuttx/random.h new file mode 100644 index 0000000000..d3413e62fb --- /dev/null +++ b/include/nuttx/random.h @@ -0,0 +1,171 @@ +/**************************************************************************** + * include/nuttx/random.h + * + * Copyright (C) 2015-2017 Haltian Ltd. All rights reserved. + * Authors: Juha Niskanen + * Jussi Kivilinna + * + * 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, this list of conditions and the following disclaimer. + * 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. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS 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 ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +#ifndef __INCLUDE_NUTTX_RANDOM_H +#define __INCLUDE_NUTTX_RANDOM_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include +#include + +#include /* getrandom() */ + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/* Size of entropy pool in 32-bit integers, must be power of two */ + +#define ENTROPY_POOL_SIZE 128 + +#define add_irq_randomness(x) up_rngaddint(RND_SRC_IRQ, (x)) +#define add_sensor_randomness(x) up_rngaddint(RND_SRC_SENSOR, (x)) +#define add_time_randomness(x) up_rngaddint(RND_SRC_TIME, (x)) +#define add_hw_randomness(x) up_rngaddint(RND_SRC_HW, (x)) +#define add_sw_randomness(x) up_rngaddint(RND_SRC_SW, (x)) +#define add_ui_randomness(x) up_rngaddint(RND_SRC_UI, (x)) + +/* Allow above macros to always exist in source without ifdefs */ + +#ifndef CONFIG_CRYPTO_RANDOM_POOL +# define up_rngaddint(k, x) ((void)(k),(void)(x)) +# define up_rngaddentropy(k, buf, n) ((void)(k),(void)(buf),(void)(x)) +#endif + +/**************************************************************************** + * Public Type Definitions + ****************************************************************************/ + +/* Entropy pool structure */ + +struct entropy_pool_s +{ + volatile uint32_t pool[ENTROPY_POOL_SIZE]; +}; + +/* Randomness sources */ + +enum rnd_source_t +{ + RND_SRC_TIME = 0, + RND_SRC_IRQ, + RND_SRC_SENSOR, + RND_SRC_HW, /* unique per HW UID or coming from factory line. */ + RND_SRC_SW, /* unique per SW version. */ + RND_SRC_UI /* buttons etc. user-visible interface elements. */ +}; + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +#ifdef CONFIG_BOARD_ENTROPY_POOL +/* Entropy pool structure can be provided by board source. Use for this is, + * for example, allocate entropy pool from special area of RAM which content + * is kept over system reset. */ + +extern struct entropy_pool_s board_entropy_pool; +#endif + +/**************************************************************************** + * Public Function Prototypes + ****************************************************************************/ + +#ifdef CONFIG_CRYPTO_RANDOM_POOL + +/**************************************************************************** + * Function: up_rngaddint + * + * Description: + * Add one integer to entropy pool, contributing a specific kind + * of entropy to pool. + * + * Parameters: + * kindof - Enumeration constant telling where val came from + * val - Integer to be added + * + * Returned Value: + * None + * + ****************************************************************************/ + +void up_rngaddint(enum rnd_source_t kindof, int val); + +/**************************************************************************** + * Function: up_rngaddentropy + * + * Description: + * Add buffer of integers to entropy pool. + * + * Parameters: + * kindof - Enumeration constant telling where val came from + * buf - Buffer of integers to be added + * n - Number of elements in buf + * + * Returned Value: + * None + * + ****************************************************************************/ + +void up_rngaddentropy(enum rnd_source_t kindof, FAR const uint32_t *buf, + size_t n); + +/**************************************************************************** + * Function: up_rngreseed + * + * Description: + * Force reseeding random number generator from entropy pool + * + ****************************************************************************/ + +void up_rngreseed(void); + +/**************************************************************************** + * Function: up_randompool_initialize + * + * Description: + * Initialize entropy pool and random number generator + * + ****************************************************************************/ + +void up_randompool_initialize(void); + +#endif /* CONFIG_CRYPTO_RANDOM_POOL */ + +#endif /* __INCLUDE_NUTTX_RANDOM_H */ diff --git a/include/string.h b/include/string.h index 92df7f85b5..f3dbc2aaf6 100644 --- a/include/string.h +++ b/include/string.h @@ -93,6 +93,8 @@ FAR void *memcpy(FAR void *dest, FAR const void *src, size_t n); FAR void *memmove(FAR void *dest, FAR const void *src, size_t count); FAR void *memset(FAR void *s, int c, size_t n); +void explicit_bzero(FAR void *s, size_t n); + #undef EXTERN #if defined(__cplusplus) } diff --git a/include/sys/random.h b/include/sys/random.h new file mode 100644 index 0000000000..7856ca007e --- /dev/null +++ b/include/sys/random.h @@ -0,0 +1,77 @@ +/**************************************************************************** + * include/sys/random.h + * + * Copyright (C) 2015-2017 Haltian Ltd. All rights reserved. + * Authors: Juha Niskanen + * Jussi Kivilinna + * + * 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, this list of conditions and the following disclaimer. + * 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. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS 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 ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +#ifndef __INCLUDE_SYS_RANDOM_H +#define __INCLUDE_SYS_RANDOM_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include +#include + +/**************************************************************************** + * Public Function Prototypes + ****************************************************************************/ + +#ifdef CONFIG_CRYPTO_RANDOM_POOL + +/**************************************************************************** + * Function: getrandom + * + * Description: + * Fill a buffer of arbitrary length with randomness. This is the + * preferred interface for getting random numbers. The traditional + * /dev/random approach is susceptible for things like the attacker + * exhausting file descriptors on purpose. + * + * Note that this function cannot fail, other than by asserting. + * + * Parameters: + * bytes - Buffer for returned random bytes + * nbytes - Number of bytes requested. + * + * Returned Value: + * None + * + ****************************************************************************/ + +void getrandom(FAR void *bytes, size_t nbytes); + +#endif /* CONFIG_CRYPTO_RANDOM_POOL */ + +#endif /* __INCLUDE_SYS_RANDOM_H */ diff --git a/include/sys/syscall.h b/include/sys/syscall.h index 56319b772d..6f1911c6c4 100644 --- a/include/sys/syscall.h +++ b/include/sys/syscall.h @@ -524,10 +524,19 @@ /* The following is defined only if CONFIG_TASK_NAME_SIZE > 0 */ #if CONFIG_TASK_NAME_SIZE > 0 -# define SYS_prctl (SYS_nnetsocket+0) -# define SYS_maxsyscall (SYS_nnetsocket+1) +# define SYS_prctl (SYS_nnetsocket+1) #else -# define SYS_maxsyscall SYS_nnetsocket +# define SYS_prctl SYS_nnetsocket +#endif + +/* The following is defined only if entropy pool random number generator + * is enabled. */ + +#ifdef CONFIG_CRYPTO_RANDOM_POOL +# define SYS_getrandom (SYS_prctl+1) +# define SYS_maxsyscall (SYS_prctl+2) +#else +# define SYS_maxsyscall SYS_prctl #endif /* Note that the reported number of system calls does *NOT* include the diff --git a/libc/string/Make.defs b/libc/string/Make.defs index 72cb8354d5..0b82b6af8d 100644 --- a/libc/string/Make.defs +++ b/libc/string/Make.defs @@ -44,6 +44,7 @@ CSRCS += lib_strerror.c lib_strlen.c lib_strnlen.c lib_strncasecmp.c CSRCS += lib_strncat.c lib_strncmp.c lib_strncpy.c lib_strndup.c CSRCS += lib_strcasestr.c lib_strpbrk.c lib_strrchr.c lib_strspn.c CSRCS += lib_strstr.c lib_strtok.c lib_strtokr.c lib_strerrorr.c +CSRCS += lib_explicit_bzero.c ifneq ($(CONFIG_LIBC_ARCH_MEMCPY),y) ifeq ($(CONFIG_MEMCPY_VIK),y) diff --git a/libc/string/lib_explicit_bzero.c b/libc/string/lib_explicit_bzero.c new file mode 100644 index 0000000000..ab862ed1a8 --- /dev/null +++ b/libc/string/lib_explicit_bzero.c @@ -0,0 +1,56 @@ +/**************************************************************************** + * libc/string/lib_explicit_bzero.c + * + * Copyright (C) 2015,2017 Haltian Ltd. All rights reserved. + * Author: Juha Niskanen + * Jussi Kivilinna + * + * 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, this list of conditions and the following disclaimer. + * 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. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS 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 ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +/**************************************************************************** + * Global Functions + ****************************************************************************/ + +/* memset that must not be optimized away by compiler (not even with LTO). */ + +void explicit_bzero(FAR void *s, size_t n) +{ + static FAR void *(*FAR const volatile memset_v)(FAR void *, int, size_t) = + &memset; + + memset_v(s, 0, n); +} diff --git a/sched/irq/irq_dispatch.c b/sched/irq/irq_dispatch.c index b507c065b1..b311e8a2c1 100644 --- a/sched/irq/irq_dispatch.c +++ b/sched/irq/irq_dispatch.c @@ -42,6 +42,7 @@ #include #include #include +#include #include "irq/irq.h" @@ -53,7 +54,7 @@ * Name: irq_dispatch * * Description: - * This function must be called from the achitecture-specific logic in + * This function must be called from the architecture-specific logic in * order to dispatch an interrupt to the appropriate, registered handling * logic. * @@ -97,6 +98,12 @@ void irq_dispatch(int irq, FAR void *context) arg = NULL; #endif +#ifdef CONFIG_CRYPTO_RANDOM_POOL_COLLECT_IRQ_RANDOMNESS + /* Add interrupt timing randomness to entropy pool */ + + add_irq_randomness(irq); +#endif + /* Then dispatch to the interrupt handler */ vector(irq, context, arg); diff --git a/syscall/syscall.csv b/syscall/syscall.csv index 66babafb5e..1ff6948d74 100644 --- a/syscall/syscall.csv +++ b/syscall/syscall.csv @@ -30,6 +30,7 @@ "get_errno_ptr","errno.h","defined(__DIRECT_ERRNO_ACCESS)","FAR int*" "getenv","stdlib.h","!defined(CONFIG_DISABLE_ENVIRON)","FAR char*","FAR const char*" "getpid","unistd.h","","pid_t" +"getrandom","sys/random.h","defined(CONFIG_CRYPTO_RANDOM_POOL)","void","FAR void*","size_t" "getsockopt","sys/socket.h","CONFIG_NSOCKET_DESCRIPTORS > 0 && defined(CONFIG_NET)","int","int","int","int","FAR void*","FAR socklen_t*" "insmod","nuttx/module.h","defined(CONFIG_MODULE)","FAR void *","FAR const char *","FAR const char *" "ioctl","sys/ioctl.h","!defined(CONFIG_LIBC_IOCTL_VARIADIC) && (CONFIG_NSOCKET_DESCRIPTORS > 0 || CONFIG_NFILE_DESCRIPTORS > 0)","int","int","int","unsigned long" diff --git a/syscall/syscall_lookup.h b/syscall/syscall_lookup.h index 6ed2e54e78..0719358487 100644 --- a/syscall/syscall_lookup.h +++ b/syscall/syscall_lookup.h @@ -379,6 +379,13 @@ SYSCALL_LOOKUP(up_assert, 2, STUB_up_assert) SYSCALL_LOOKUP(prctl, 5, STUB_prctl) #endif +/* The following is defined only if entropy pool random number generator + * is enabled. */ + +#ifdef CONFIG_CRYPTO_RANDOM_POOL + SYSCALL_LOOKUP(getrandom, 2, STUB_getrandom) +#endif + /**************************************************************************** * Private Functions ****************************************************************************/ diff --git a/syscall/syscall_stublookup.c b/syscall/syscall_stublookup.c index ddcffd5506..2cc52ad0a3 100644 --- a/syscall/syscall_stublookup.c +++ b/syscall/syscall_stublookup.c @@ -391,6 +391,11 @@ uintptr_t STUB_socket(int nbr, uintptr_t parm1, uintptr_t parm2, uintptr_t STUB_prctl(int nbr, uintptr_t parm1, uintptr_t parm2, uintptr_t parm3, uintptr_t parm4, uintptr_t parm5); +/* The following is defined only if entropy pool random number generator + * is enabled. */ + +uintptr_t STUB_getrandom(int nbr, uintptr_t parm1, uintptr_t parm2); + /**************************************************************************** * Public Data ****************************************************************************/