diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-10 21:30:40 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-10 21:30:40 +0000 |
commit | 133a45c109da5310add55824db21af5239951f93 (patch) | |
tree | ba6ac4c0a950a0dda56451944315d66409923918 /contrib/libottery | |
parent | Initial commit. (diff) | |
download | rspamd-133a45c109da5310add55824db21af5239951f93.tar.xz rspamd-133a45c109da5310add55824db21af5239951f93.zip |
Adding upstream version 3.8.1.upstream/3.8.1upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'contrib/libottery')
-rw-r--r-- | contrib/libottery/CMakeLists.txt | 11 | ||||
-rw-r--r-- | contrib/libottery/aes_cryptobox.c | 181 | ||||
-rw-r--r-- | contrib/libottery/chacha_cryptobox.c | 64 | ||||
-rw-r--r-- | contrib/libottery/chacha_merged.c | 218 | ||||
-rw-r--r-- | contrib/libottery/chacha_merged_ecrypt.h | 133 | ||||
-rw-r--r-- | contrib/libottery/ottery-internal.h | 335 | ||||
-rw-r--r-- | contrib/libottery/ottery-threading.h | 96 | ||||
-rw-r--r-- | contrib/libottery/ottery.c | 847 | ||||
-rw-r--r-- | contrib/libottery/ottery.h | 143 | ||||
-rw-r--r-- | contrib/libottery/ottery_common.h | 351 | ||||
-rw-r--r-- | contrib/libottery/ottery_cpuinfo.c | 88 | ||||
-rw-r--r-- | contrib/libottery/ottery_entropy.c | 112 | ||||
-rw-r--r-- | contrib/libottery/ottery_entropy_cryptgenrandom.c | 51 | ||||
-rw-r--r-- | contrib/libottery/ottery_entropy_egd.c | 75 | ||||
-rw-r--r-- | contrib/libottery/ottery_entropy_rdrand.c | 58 | ||||
-rw-r--r-- | contrib/libottery/ottery_entropy_urandom.c | 117 | ||||
-rw-r--r-- | contrib/libottery/ottery_global.c | 116 | ||||
-rw-r--r-- | contrib/libottery/ottery_nolock.h | 190 | ||||
-rw-r--r-- | contrib/libottery/ottery_st.h | 184 | ||||
-rw-r--r-- | contrib/libottery/ottery_version.h.in | 28 |
20 files changed, 3398 insertions, 0 deletions
diff --git a/contrib/libottery/CMakeLists.txt b/contrib/libottery/CMakeLists.txt new file mode 100644 index 0000000..b8536f2 --- /dev/null +++ b/contrib/libottery/CMakeLists.txt @@ -0,0 +1,11 @@ +SET(OTTERYSRC chacha_merged.c + ottery.c + ottery_cpuinfo.c + ottery_entropy.c + ottery_global.c + chacha_cryptobox.c + aes_cryptobox.c) +ADD_LIBRARY(ottery STATIC ${OTTERYSRC}) + +SET(OTTERY_CFLAGS "-DBUILD_RSPAMD -DOTTERY_NO_PID_CHECK -DOTTERY_NO_INIT_CHECK -DOTTERY_NO_WIPE_STACK") +set_target_properties(ottery PROPERTIES COMPILE_FLAGS "${OTTERY_CFLAGS}")
\ No newline at end of file diff --git a/contrib/libottery/aes_cryptobox.c b/contrib/libottery/aes_cryptobox.c new file mode 100644 index 0000000..ea86dc7 --- /dev/null +++ b/contrib/libottery/aes_cryptobox.c @@ -0,0 +1,181 @@ +/* + * Copyright (c) 2017, Vsevolod Stakhov + * Copyright (c) 2017, Frank Denis + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * 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. + * + * THIS SOFTWARE IS PROVIDED BY AUTHOR ''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 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 ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "ottery-internal.h" +#include "cryptobox.h" + +#if defined(__x86_64__) && defined(RSPAMD_HAS_TARGET_ATTR) +#if defined(__GNUC__) && !defined(__clang__) +#pragma GCC push_options +#pragma GCC target("aes") +#endif +#ifndef __SSE2__ +#define __SSE2__ +#endif +#ifndef __SSE__ +#define __SSE__ +#endif +#ifndef __AES__ +#define __AES__ +#endif +#include <immintrin.h> +#define ROUNDS 10 + +typedef struct RSPAMD_ALIGNED(16) aes_rng_state { + __m128i round_keys[ROUNDS + 1]; + __m128i counter; +} aes_stream_state; + + +#define STATE_LEN sizeof(aes_stream_state) +#define STATE_BYTES 16 + +#define OUTPUT_LEN 1024 + +static void +aes_key_expand (__m128i round_keys[ROUNDS + 1], __m128i t) __attribute__((target("aes"))); + +static void +aes_key_expand (__m128i round_keys[ROUNDS + 1], __m128i t) +{ + __m128i t1; + +#define DO_ROUND_KEY(ROUND, RC) \ + do { \ + t1 = _mm_aeskeygenassist_si128(t, (RC)); \ + round_keys[ROUND] = t; \ + t = _mm_xor_si128(t, _mm_slli_si128(t, 4)); \ + t = _mm_xor_si128(t, _mm_slli_si128(t, 8)); \ + t = _mm_xor_si128(t, _mm_shuffle_epi32(t1, 0xff)); \ + } while (0) + + DO_ROUND_KEY(0, 1); + DO_ROUND_KEY(1, 2); + DO_ROUND_KEY(2, 4); + DO_ROUND_KEY(3, 8); + DO_ROUND_KEY(4, 16); + DO_ROUND_KEY(5, 32); + DO_ROUND_KEY(6, 64); + DO_ROUND_KEY(7, 128); + DO_ROUND_KEY(8, 27); + DO_ROUND_KEY(9, 54); + round_keys[10] = t; +} + +/* + * Computes one 128 bytes block and refresh keys + */ +static void +aes_round(unsigned char *buf, struct aes_rng_state *st) __attribute__((target("aes"))); +static void +aes_round(unsigned char *buf, struct aes_rng_state *st) +{ + const __m128i one = _mm_set_epi64x(0, 1); + __m128i *round_keys = st->round_keys; + __m128i c0, c1, c2, c3, c4, c5, c6, c7; + __m128i r0, r1, r2, r3, r4, r5, r6, r7; + __m128i s0, s1, s2, s3, s4, s5, s6, s7; + size_t i; + +#define COMPUTE_ROUNDS(N) \ + do { \ + r##N = _mm_aesenc_si128( _mm_xor_si128(c##N, round_keys[0]), round_keys[1]); \ + r##N = _mm_aesenc_si128(_mm_aesenc_si128(r##N, round_keys[2]), round_keys[3]); \ + r##N = _mm_aesenc_si128(_mm_aesenc_si128(r##N, round_keys[4]), round_keys[5]); \ + s##N = r##N; \ + r##N = _mm_aesenc_si128(_mm_aesenc_si128(r##N, round_keys[6]), round_keys[7]); \ + r##N = _mm_aesenc_si128(_mm_aesenc_si128(r##N, round_keys[8]), round_keys[9]); \ + r##N = _mm_xor_si128(s##N, _mm_aesenclast_si128(r##N, round_keys[10])); \ + } while (0) + + c0 = st->counter; + + for (i = 0; i < OUTPUT_LEN / 128; i ++) { + c1 = _mm_add_epi64 (c0, one); + c2 = _mm_add_epi64 (c1, one); + c3 = _mm_add_epi64 (c2, one); + c4 = _mm_add_epi64 (c3, one); + c5 = _mm_add_epi64 (c4, one); + c6 = _mm_add_epi64 (c5, one); + c7 = _mm_add_epi64 (c6, one); + COMPUTE_ROUNDS(0); + COMPUTE_ROUNDS(1); + COMPUTE_ROUNDS(2); + COMPUTE_ROUNDS(3); + COMPUTE_ROUNDS(4); + COMPUTE_ROUNDS(5); + COMPUTE_ROUNDS(6); + COMPUTE_ROUNDS(7); + c0 = _mm_add_epi64 (c7, one); + _mm_storeu_si128 ((__m128i *) (void *) (buf + 0), r0); + _mm_storeu_si128 ((__m128i *) (void *) (buf + 16), r1); + _mm_storeu_si128 ((__m128i *) (void *) (buf + 32), r2); + _mm_storeu_si128 ((__m128i *) (void *) (buf + 48), r3); + _mm_storeu_si128 ((__m128i *) (void *) (buf + 64), r4); + _mm_storeu_si128 ((__m128i *) (void *) (buf + 80), r5); + _mm_storeu_si128 ((__m128i *) (void *) (buf + 96), r6); + _mm_storeu_si128 ((__m128i *) (void *) (buf + 112), r7); + buf += 128; + } + + st->counter = c0; + c0 = _mm_setzero_si128(); + COMPUTE_ROUNDS(0); + aes_key_expand(round_keys, r0); +} + + +static void +aes_cryptobox_state_setup (void *state_, const uint8_t *bytes) +{ + struct aes_rng_state *x = state_; + + aes_key_expand (x->round_keys, + _mm_loadu_si128((const __m128i *) (const void *)bytes)); +} + +static void +aes_cryptobox_generate (void *state_, uint8_t *output, uint32_t idx) +{ + struct aes_rng_state *x = state_; + + aes_round(output, x); +} + +#define PRF_AES(r) { \ + "AES-" #r, \ + "AES-" #r "-NOSIMD", \ + "AES-" #r "-NOSIMD-DEFAULT", \ + STATE_LEN, \ + STATE_BYTES, \ + OUTPUT_LEN, \ + OTTERY_CPUCAP_AES, \ + aes_cryptobox_state_setup, \ + aes_cryptobox_generate \ +} + +const struct ottery_prf ottery_prf_aes_cryptobox_ = PRF_AES(128); +#endif /* x86_64 */ diff --git a/contrib/libottery/chacha_cryptobox.c b/contrib/libottery/chacha_cryptobox.c new file mode 100644 index 0000000..4e9cdae --- /dev/null +++ b/contrib/libottery/chacha_cryptobox.c @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2015, Vsevolod Stakhov + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * 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. + * + * THIS SOFTWARE IS PROVIDED BY AUTHOR ''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 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 ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "ottery-internal.h" +#include "libcryptobox/chacha20/chacha.h" + +#define STATE_LEN (sizeof(chacha_state)) +#define STATE_BYTES 40 + +#define IDX_STEP 16 +#define OUTPUT_LEN (IDX_STEP * 64) + +static void +chacha20_cryptobox_state_setup (void *state_, const uint8_t *bytes) +{ + chacha_state *x = state_; + chacha_init (x, (chacha_key *)bytes, (chacha_iv *)(bytes + 32), 20); +} + +static void +chacha20_cryptobox_generate (void *state_, uint8_t *output, uint32_t idx) +{ + chacha_state *x = state_; + + memset (output, 0, OUTPUT_LEN); + memcpy (output, &idx, sizeof (idx)); + chacha_update (x, output, output, OUTPUT_LEN); +} + +#define PRF_CHACHA(r) { \ + "CHACHA" #r "-CRYPTOBOX", \ + "CHACHA" #r "-CRYPTOBOX", \ + "CHACHA" #r "-CRYPTOBOX", \ + STATE_LEN, \ + STATE_BYTES, \ + OUTPUT_LEN, \ + 0, \ + chacha ## r ## _cryptobox_state_setup, \ + chacha ## r ## _cryptobox_generate \ +} + +const struct ottery_prf ottery_prf_chacha20_cryptobox_ = PRF_CHACHA(20); diff --git a/contrib/libottery/chacha_merged.c b/contrib/libottery/chacha_merged.c new file mode 100644 index 0000000..c31a8bb --- /dev/null +++ b/contrib/libottery/chacha_merged.c @@ -0,0 +1,218 @@ +/* + * This code is based on Dan Bernstein's pure C "merged" ChaCha + * implementation; details below. + * + * Note that I've ripped out all of the code that wasn't suitable for doing + * block-oriented operation, all (residual) support for 128-bit ChaCha keys, + * all support for counter values over 32 bits, the ability to xor the stream + * with a plaintext, and so on. + * + * Future versions of this might remove bigendian conversions too. DO NOT use + * this code for your stream cipher: go back to the original source. (I got + * this copy from SUPERCOP). + */ + +/* +chacha-merged.c version 20080118 +D. J. Bernstein +Public domain. +*/ +#include <string.h> +#include "ottery-internal.h" +#define u8 uint8_t +#define u32 uint32_t +#include "chacha_merged_ecrypt.h" + +#define ROTATE(v,c) (ROTL32(v,c)) +#define XOR(v,w) ((v) ^ (w)) +#define PLUS(v,w) (U32V((v) + (w))) +#define PLUSONE(v) (PLUS((v),1)) + +#define QUARTERROUND(a,b,c,d) \ + a = PLUS(a,b); d = ROTATE(XOR(d,a),16); \ + c = PLUS(c,d); b = ROTATE(XOR(b,c),12); \ + a = PLUS(a,b); d = ROTATE(XOR(d,a), 8); \ + c = PLUS(c,d); b = ROTATE(XOR(b,c), 7); + +static const char sigma[16] = "expand 32-byte k"; + +static void ECRYPT_keysetup(ECRYPT_ctx *x,const u8 *k,u32 ivbits) +{ + const char *constants; + (void)ivbits; + + x->input[4] = U8TO32_LITTLE(k + 0); + x->input[5] = U8TO32_LITTLE(k + 4); + x->input[6] = U8TO32_LITTLE(k + 8); + x->input[7] = U8TO32_LITTLE(k + 12); + k += 16; + constants = sigma; + x->input[8] = U8TO32_LITTLE(k + 0); + x->input[9] = U8TO32_LITTLE(k + 4); + x->input[10] = U8TO32_LITTLE(k + 8); + x->input[11] = U8TO32_LITTLE(k + 12); + x->input[0] = U8TO32_LITTLE(constants + 0); + x->input[1] = U8TO32_LITTLE(constants + 4); + x->input[2] = U8TO32_LITTLE(constants + 8); + x->input[3] = U8TO32_LITTLE(constants + 12); +} + +static void ECRYPT_ivsetup(ECRYPT_ctx *x,const u8 *iv) +{ + x->input[12] = 0; + x->input[13] = 0; + x->input[14] = U8TO32_LITTLE(iv + 0); + x->input[15] = U8TO32_LITTLE(iv + 4); +} + +#define IDX_STEP 16 +#define OUTPUT_LEN (IDX_STEP * 64) + +static inline void chacha_merged_getblocks(const int chacha_rounds, ECRYPT_ctx *x,u8 *c) __attribute__((always_inline)); + +/** Generate OUTPUT_LEN bytes of output using the key, nonce, and counter in x, + * and store them in c. + */ +static void chacha_merged_getblocks(const int chacha_rounds, ECRYPT_ctx *x,u8 *c) +{ + u32 x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15; + u32 j0, j1, j2, j3, j4, j5, j6, j7, j8, j9, j10, j11, j12, j13, j14, j15; + unsigned i, block; + + j0 = x->input[0]; + j1 = x->input[1]; + j2 = x->input[2]; + j3 = x->input[3]; + j4 = x->input[4]; + j5 = x->input[5]; + j6 = x->input[6]; + j7 = x->input[7]; + j8 = x->input[8]; + j9 = x->input[9]; + j10 = x->input[10]; + j11 = x->input[11]; + j12 = x->input[12]; + j13 = x->input[13]; + j14 = x->input[14]; + j15 = x->input[15]; + + for (block = 0; block < IDX_STEP; ++block) { + x0 = j0; + x1 = j1; + x2 = j2; + x3 = j3; + x4 = j4; + x5 = j5; + x6 = j6; + x7 = j7; + x8 = j8; + x9 = j9; + x10 = j10; + x11 = j11; + x12 = j12; + x13 = j13; + x14 = j14; + x15 = j15; + for (i = chacha_rounds;i > 0;i -= 2) { + QUARTERROUND( x0, x4, x8,x12) + QUARTERROUND( x1, x5, x9,x13) + QUARTERROUND( x2, x6,x10,x14) + QUARTERROUND( x3, x7,x11,x15) + QUARTERROUND( x0, x5,x10,x15) + QUARTERROUND( x1, x6,x11,x12) + QUARTERROUND( x2, x7, x8,x13) + QUARTERROUND( x3, x4, x9,x14) + } + x0 = PLUS(x0,j0); + x1 = PLUS(x1,j1); + x2 = PLUS(x2,j2); + x3 = PLUS(x3,j3); + x4 = PLUS(x4,j4); + x5 = PLUS(x5,j5); + x6 = PLUS(x6,j6); + x7 = PLUS(x7,j7); + x8 = PLUS(x8,j8); + x9 = PLUS(x9,j9); + x10 = PLUS(x10,j10); + x11 = PLUS(x11,j11); + x12 = PLUS(x12,j12); + x13 = PLUS(x13,j13); + x14 = PLUS(x14,j14); + x15 = PLUS(x15,j15); + + j12 = PLUSONE(j12); + /* Ottery: j13 can never need to be incremented. */ + + U32TO8_LITTLE(c + 0,x0); + U32TO8_LITTLE(c + 4,x1); + U32TO8_LITTLE(c + 8,x2); + U32TO8_LITTLE(c + 12,x3); + U32TO8_LITTLE(c + 16,x4); + U32TO8_LITTLE(c + 20,x5); + U32TO8_LITTLE(c + 24,x6); + + U32TO8_LITTLE(c + 28,x7); + U32TO8_LITTLE(c + 32,x8); + U32TO8_LITTLE(c + 36,x9); + U32TO8_LITTLE(c + 40,x10); + U32TO8_LITTLE(c + 44,x11); + U32TO8_LITTLE(c + 48,x12); + U32TO8_LITTLE(c + 52,x13); + U32TO8_LITTLE(c + 56,x14); + U32TO8_LITTLE(c + 60,x15); + + c += 64; + } +} + +#define STATE_LEN (sizeof(ECRYPT_ctx)) +#define STATE_BYTES 40 + +static void +chacha_merged_state_setup(void *state_, const uint8_t *bytes) +{ + ECRYPT_ctx *x = state_; + ECRYPT_keysetup(x, bytes, 0); + ECRYPT_ivsetup(x, bytes+32); +} + +static void +chacha8_merged_generate(void *state_, uint8_t *output, uint32_t idx) +{ + ECRYPT_ctx *x = state_; + x->input[12] = idx * IDX_STEP; + chacha_merged_getblocks(8, x, output); +} + +static void +chacha12_merged_generate(void *state_, uint8_t *output, uint32_t idx) +{ + ECRYPT_ctx *x = state_; + x->input[12] = idx * IDX_STEP; + chacha_merged_getblocks(12, x, output); +} + +static void +chacha20_merged_generate(void *state_, uint8_t *output, uint32_t idx) +{ + ECRYPT_ctx *x = state_; + x->input[12] = idx * IDX_STEP; + chacha_merged_getblocks(20, x, output); +} + +#define PRF_CHACHA(r) { \ + "CHACHA" #r, \ + "CHACHA" #r "-NOSIMD", \ + "CHACHA" #r "-NOSIMD-DEFAULT", \ + STATE_LEN, \ + STATE_BYTES, \ + OUTPUT_LEN, \ + 0, \ + chacha_merged_state_setup, \ + chacha ## r ## _merged_generate \ +} + +const struct ottery_prf ottery_prf_chacha8_merged_ = PRF_CHACHA(8); +const struct ottery_prf ottery_prf_chacha12_merged_ = PRF_CHACHA(12); +const struct ottery_prf ottery_prf_chacha20_merged_ = PRF_CHACHA(20); + diff --git a/contrib/libottery/chacha_merged_ecrypt.h b/contrib/libottery/chacha_merged_ecrypt.h new file mode 100644 index 0000000..5cc94a9 --- /dev/null +++ b/contrib/libottery/chacha_merged_ecrypt.h @@ -0,0 +1,133 @@ +/* Definitions for types and macros used in chacha_merged.c. Taken from + * supercop. + */ + +#include <limits.h> + +typedef struct +{ + u32 input[16]; /* could be compressed */ + /* + * [edit] + * + * Put here all state variable needed during the encryption process. + */ +} ECRYPT_ctx; +#if (UCHAR_MAX / 0xFFFFU > 0xFFFFU) +#ifndef I32T +#define I32T char +#define U32C(v) (v##U) +#endif +#endif + +#if (USHRT_MAX / 0xFFFFU > 0xFFFFU) +#ifndef I32T +#define I32T short +#define U32C(v) (v##U) +#endif +#endif + +#if (UINT_MAX / 0xFFFFU > 0xFFFFU) +#ifndef I32T +#define I32T int +#define U32C(v) (v##U) +#endif +#endif + +#if (ULONG_MAX / 0xFFFFUL > 0xFFFFUL) +#ifndef I32T +#define I32T long +#define U32C(v) (v##UL) +#endif +#endif + +#define U8C(v) (v ## U) +#define U32V(v) ((u32)(v) & U32C(0xFFFFFFFF)) +#define U8V(v) ((u8)(v) & U8C(0xFF)) + +#if (defined(WIN32) && defined(_MSC_VER)) +#include <stdlib.h> +#pragma intrinsic(_lrotl) /* compile rotations "inline" */ +#define ROTL32(v, n) _lrotl(v, n) +#else +#define ROTL32(v, n) \ + (U32V((v) << (n)) | ((v) >> (32 - (n)))) +#endif + + + +#if ECRYPT_LITTLE_ENDIAN +#define U32TO32_LITTLE(v) (v) +#endif +#ifdef ECRYPT_BIG_ENDIAN +#define SWAP32(v) \ + ((ROTL32(v, 8) & U32C(0x00FF00FF)) | \ + (ROTL32(v, 24) & U32C(0xFF00FF00))) + +#define U32TO32_LITTLE(v) SWAP32(v) +#endif + +#ifdef U32TO32_LITTLE +#define U8TO32_LITTLE(p) U32TO32_LITTLE(((u32*)(p))[0]) +#define U32TO8_LITTLE(p, v) (((u32*)(p))[0] = U32TO32_LITTLE(v)) +#else +#define U8TO32_LITTLE(p) \ + (((u32)((p)[0]) ) | \ + ((u32)((p)[1]) << 8) | \ + ((u32)((p)[2]) << 16) | \ + ((u32)((p)[3]) << 24)) +#define U32TO8_LITTLE(p, v) \ + do { \ + (p)[0] = U8V((v) ); \ + (p)[1] = U8V((v) >> 8); \ + (p)[2] = U8V((v) >> 16); \ + (p)[3] = U8V((v) >> 24); \ + } while (0) +#endif + +/* + * The LITTLE endian machines: + */ +#if defined(__ultrix) /* Older MIPS */ +#define ECRYPT_LITTLE_ENDIAN +#elif defined(__alpha) /* Alpha */ +#define ECRYPT_LITTLE_ENDIAN +#elif defined(i386) /* x86 (gcc) */ +#define ECRYPT_LITTLE_ENDIAN +#elif defined(__i386) /* x86 (gcc) */ +#define ECRYPT_LITTLE_ENDIAN +#elif defined(__x86_64) /* x86_64 (gcc) */ +#define ECRYPT_LITTLE_ENDIAN +#elif defined(_M_IX86) /* x86 (MSC, Borland) */ +#define ECRYPT_LITTLE_ENDIAN +#elif defined(_MSC_VER) /* x86 (surely MSC) */ +#define ECRYPT_LITTLE_ENDIAN +#elif defined(__INTEL_COMPILER) /* x86 (surely Intel compiler icl.exe) */ +#define ECRYPT_LITTLE_ENDIAN + +/* + * The BIG endian machines: + */ +#elif defined(__sparc) /* Newer Sparc's */ +#define ECRYPT_BIG_ENDIAN +#elif defined(__powerpc__) /* PowerPC */ +#define ECRYPT_BIG_ENDIAN +#elif defined(__ppc__) /* PowerPC */ +#define ECRYPT_BIG_ENDIAN +#elif defined(__hppa) /* HP-PA */ +#define ECRYPT_BIG_ENDIAN + +/* + * Finally machines with UNKNOWN endianness: + */ +#elif defined (_AIX) /* RS6000 */ +#define ECRYPT_UNKNOWN +#elif defined(__aux) /* 68K */ +#define ECRYPT_UNKNOWN +#elif defined(__dgux) /* 88K (but P6 in latest boxes) */ +#define ECRYPT_UNKNOWN +#elif defined(__sgi) /* Newer MIPS */ +#define ECRYPT_UNKNOWN +#else /* Any other processor */ +#define ECRYPT_UNKNOWN +#endif diff --git a/contrib/libottery/ottery-internal.h b/contrib/libottery/ottery-internal.h new file mode 100644 index 0000000..cc047f8 --- /dev/null +++ b/contrib/libottery/ottery-internal.h @@ -0,0 +1,335 @@ +/* Libottery by Nick Mathewson. + + This software has been dedicated to the public domain under the CC0 + public domain dedication. + + To the extent possible under law, the person who associated CC0 with + libottery has waived all copyright and related or neighboring rights + to libottery. + + You should have received a copy of the CC0 legalcode along with this + work in doc/cc0.txt. If not, see + <http://creativecommons.org/publicdomain/zero/1.0/>. + */ +#ifndef OTTERY_INTERNAL_H_HEADER_INCLUDED_ +#define OTTERY_INTERNAL_H_HEADER_INCLUDED_ +#include <stdint.h> +#include <sys/types.h> + +#ifdef BUILD_RSPAMD +#include "config.h" +#endif + +#include "ottery-threading.h" + + +/** + * Version number for Libottery. The first three bytes are the major number, + * minor number, and patch-level respectively. The final byte is 0 for a + * released version, and nonzero otherwise. + */ +#define OTTERY_VERSION 0x00000001 +/** + * Human-readable string representing the Libottery version. + */ +#define OTTERY_VERSION_STRING "0.0.0" + +/** Largest possible state_bytes value. */ +#define MAX_STATE_BYTES 64 +/** Largest possible state_len value. */ +#define MAX_STATE_LEN 256 +/** Largest possible output_len value. */ +#define MAX_OUTPUT_LEN 1024 + +/** + * @brief Flags for external entropy sources. + * + * @{ */ +/** An RNG that probably provides strong entropy. */ +#define OTTERY_ENTROPY_FL_STRONG 0x000001 +/** An RNG that runs very quickly. */ +#define OTTERY_ENTROPY_FL_FAST 0x000002 +/** @} */ + +/** + * @brief Identifying external entropy domains. + */ +/** An RNG provided by the operating system. */ +#define OTTERY_ENTROPY_DOM_OS 0x000100 +/** An RNG provided by the CPU. */ +#define OTTERY_ENTROPY_DOM_CPU 0x000200 +/** An EGD-style entropy source */ +#define OTTERY_ENTROPY_DOM_EGD 0x000400 +/** @} */ + +#define OTTERY_ENTROPY_FLAG_MASK 0x000000ff +#define OTTERY_ENTROPY_DOM_MASK 0x0000ff00 +#define OTTERY_ENTROPY_ALL_SOURCES 0x0fff0000 + +struct sockaddr; + +/** Configuration for the strong RNG the we use for entropy. */ +struct ottery_entropy_config { + /** The filename to use as /dev/urandom. Ignored if this + * is not a unix-like operating system. If this is NULL, we use + * the default value. */ + const char *urandom_fname; + /** An fd to use to access /dev/urandom. -1 if not set. Overrides + * urandom_fname. */ + int urandom_fd; + /** True if urandom_fd has been set. */ + unsigned urandom_fd_is_set; + /** Socket for egd */ + const struct sockaddr *egd_sockaddr; + /** Socklen for egd_sockaddr. */ + int egd_socklen; + /** Bitmask of sources to disable. */ + uint32_t disabled_sources; + /** Bitmask of sources to consider weak. */ + uint32_t weak_sources; + + /** If true, we don't enforce that urandom_fname must be a device file. + * This is for testing, and is not exposed to user code. + */ + unsigned allow_nondev_urandom; +}; + +struct ottery_entropy_state { + /* Cached value for the inode of the urandom device. If this value changes, + * we assume that somebody messed with the fd by accident. */ + uint64_t urandom_fd_inode; +}; + +/** + * Return the buffer size to allocate when getting at least n bytes from each + * entropy source. We might not actually need so many. */ +size_t ottery_get_entropy_bufsize_(size_t n); + +/** + * Interface to underlying strong RNGs. If this were fast, we'd just use it + * for everything, and forget about having a userspace PRNG. Unfortunately, + * it typically isn't. + * + * @param config A correctly set-up ottery_entropy_config. + * @param state A correctly set-up ottery_entropy_state. + * @param require_flags Only run entropy sources with *all* of these + * OTTERY_ENTROPY_* flags set. Set this to 0 to use all the sources + * that work. + * @param bytes A buffer to receive random bytes. + * @param n The number of bytes to try to get from each entropy source. + * @param bufsize The number of bytes available in the buffer; modified + * to hold the number of bytes actually written. + * @param flags_out Set to a bitwise OR of all of the OTTERY_ENTROPY_* flags + * for sources in the result. + * @return Zero on success, or an error code on failure. On failure, it is not + * safe to treat the contents of the buffer as random at all. + */ +int ottery_get_entropy_(const struct ottery_entropy_config *config, + struct ottery_entropy_state *state, + uint32_t require_flags, + uint8_t *bytes, size_t n, size_t *bufsize, + uint32_t *flags_out); + +/** + * Clear all bytes stored in a structure. Unlike memset, the compiler is not + * going to optimize this out of existence because the target is about to go + * out of scope. + * + * @param mem Pointer to the memory to erase. + * @param len The number of bytes to erase. + */ +void ottery_memclear_(void *mem, size_t len); + +/** + * Information on a single pseudorandom function that we can use to generate + * a bytestream which (we hope) an observer can't distinguish from random + * bytes. + * + * Broadly speaking, every ottery_prf has an underlying function from an + * (state_bytes)-byte state and a 4 byte counter to an output_len-byte + * output block. + **/ +struct ottery_prf { + /** The name of this algorithm. */ + const char *name; + /** The name of the implementation of this algorithm*/ + const char *impl; + /** The name of the flavor of the implementation of this algorithm*/ + const char *flav; + /** The length of the object that's used to hold the state (keys, nonces, + * subkeys as needed, etc) for this PRF. This can be longer than + * state_bytes because of key expansion or structure padding. It must be + * no greater than MAX_STATE_LEN. */ + unsigned state_len; + /** The number of bytes used to generate a state object. It must be no + * greater than MAX_STATE_BYTES. It must be no grater than output_len. */ + unsigned state_bytes; + /** The number of bytes generated by a single call to the generate + * function. It must be no larger than MAX_OUTPUT_LEN. + */ + unsigned output_len; + /** Bitmask of CPU flags required to run this PRF. */ + uint32_t required_cpucap; + /** Pointer to a function to initialize a state structure for the PRF. + * + * @param state An object of size at least (state_len) that will + * hold the state and any derived values. It must be aligned to + * a 16-byte boundary. + * @param bytes An array of (state_bytes) random bytes. + */ + void (*setup)(void *state, const uint8_t *bytes); + /** Pointer to a function that calculates the PRF. + * + * @param state A state object previously initialized by the setup + * function. + * @param output An array of (output_len) bytes in which to store the + * result of the function + * @param idx A counter value for the function. + */ + void (*generate)(void *state, uint8_t *output, uint32_t idx); +}; + +/** + * Evaluate the condition 'x', while hinting to the compiler that it is + * likely to be false. + */ +#ifdef __GNUC__ +#define UNLIKELY(x) __builtin_expect((x), 0) +#else +#define UNLIKELY(x) (x) +#endif + +#ifdef OTTERY_INTERNAL +struct ottery_config { + /** The PRF that we should use. If NULL, we use the default. */ + const struct ottery_prf *impl; + + /** Configuration for how we will set up our entropy sources. */ + struct ottery_entropy_config entropy_config; +}; + +#define ottery_state_nolock ottery_state + +struct RSPAMD_ALIGNED(16) ottery_state { + /** + * Holds up to prf.output_len bytes that have been generated by the + * pseudorandom function. */ + uint8_t buffer[MAX_OUTPUT_LEN] RSPAMD_ALIGNED(16); + /** + * Holds the state information (typically nonces and keys) used by the + * pseudorandom function. */ + + uint8_t state[MAX_STATE_LEN] RSPAMD_ALIGNED(16); + /** + * Parameters and function pointers for the cryptographic pseudorandom + * function that we're using. */ + struct ottery_prf prf; + /** + * Index of the *next* block counter to use when generating random bytes + * with prf. When this equals or exceeds prf.stir_after, we should stir + * the PRNG. */ + uint32_t block_counter; + /** + * Magic number; used to tell whether this state is initialized. + */ + uint32_t magic; + /** + * Index of the next byte in (buffer) to yield to the user. + * + * Invariant: this is less than prf.output_len. */ + uint16_t pos; + /** + * The pid of the process in which this PRF was most recently seeded + * from the OS. We use this to avoid use-after-fork problems; see + * ottery_st_rand_lock_and_check(). */ + pid_t pid; + /** + * Combined flags_out results from all calls to the entropy source that + * have influenced our current state. + */ + uint32_t entropy_src_flags; + /** + * flags_out result from our last call to the entropy source. + */ + uint32_t last_entropy_flags; + /** + * Configuration for the entropy source. + */ + struct ottery_entropy_config entropy_config; + /** State for the entropy source. + */ + struct ottery_entropy_state entropy_state; + /** + * @brief Locks for this structure. + * + * This lock will not necessarily be recursive. It's probably a + * spinlock. + * + * @{ + */ +DECL_LOCK(mutex) + /**@}*/ +}; +#endif + +struct ottery_config; +/** + * For testing: manually supply a PRF. + */ +void ottery_config_set_manual_prf_(struct ottery_config *cfg, + const struct ottery_prf *prf); + + +/** Called when a fatal error has occurred: Die horribly, or invoke + * ottery_fatal_handler. */ +void ottery_fatal_error_(int error); + +#define OTTERY_CPUCAP_SIMD (1<<0) +#define OTTERY_CPUCAP_SSSE3 (1<<1) +#define OTTERY_CPUCAP_AES (1<<2) +#define OTTERY_CPUCAP_RAND (1<<3) + +/** Return a mask of OTTERY_CPUCAP_* for what the CPU will offer us. */ +uint32_t ottery_get_cpu_capabilities_(void); + +/** Tell ottery_get_cpu_capabilities to never report certain capabilities as + * present. */ +void ottery_disable_cpu_capabilities_(uint32_t disable); + +/** + * @brief pure-C portable ChaCha implementations. + * + * @{ + */ +extern const struct ottery_prf ottery_prf_chacha8_merged_; +extern const struct ottery_prf ottery_prf_chacha12_merged_; +extern const struct ottery_prf ottery_prf_chacha20_merged_; + +#ifdef BUILD_RSPAMD +#ifdef __x86_64__ +extern const struct ottery_prf ottery_prf_aes_cryptobox_; +#endif +extern const struct ottery_prf ottery_prf_chacha20_cryptobox_; +#endif +/**@}*/ + +/** + * @brief SIMD-basd ChaCha implementations. + * + * These are much, much faster. + * + * @{ */ +#ifdef HAVE_SIMD_CHACHA +extern const struct ottery_prf ottery_prf_chacha8_krovetz_1_; +extern const struct ottery_prf ottery_prf_chacha12_krovetz_1_; +extern const struct ottery_prf ottery_prf_chacha20_krovetz_1_; +#endif + +#ifdef HAVE_SIMD_CHACHA_2 +extern const struct ottery_prf ottery_prf_chacha8_krovetz_2_; +extern const struct ottery_prf ottery_prf_chacha12_krovetz_2_; +extern const struct ottery_prf ottery_prf_chacha20_krovetz_2_; +#endif +/** @} */ + +#endif diff --git a/contrib/libottery/ottery-threading.h b/contrib/libottery/ottery-threading.h new file mode 100644 index 0000000..c5427ad --- /dev/null +++ b/contrib/libottery/ottery-threading.h @@ -0,0 +1,96 @@ +/* Libottery by Nick Mathewson. + + This software has been dedicated to the public domain under the CC0 + public domain dedication. + + To the extent possible under law, the person who associated CC0 with + libottery has waived all copyright and related or neighboring rights + to libottery. + + You should have received a copy of the CC0 legalcode along with this + work in doc/cc0.txt. If not, see + <http://creativecommons.org/publicdomain/zero/1.0/>. + */ +#ifndef OTTERY_LOCKING_H_HEADER_INCLUDED_ +#define OTTERY_LOCKING_H_HEADER_INCLUDED_ + +/* We don't need locks when building rspamd */ +#ifdef BUILD_RSPAMD +#define OTTERY_NO_LOCKS +#endif + +/* Locks */ +#ifdef OTTERY_NO_LOCKS +/* Nothing here. */ +#elif defined(__APPLE__) && !defined(OTTERY_NO_SPINLOCKS) +#define OTTERY_OSATOMIC_LOCKS +#include <libkern/OSAtomic.h> +#elif defined(_WIN32) +#define OTTERY_CRITICAL_SECTION +#include <windows.h> +#elif defined(HAVE_PTHREAD) +#define OTTERY_PTHREADS +#include <pthread.h> +#else +#define OTTERY_NO_LOCKS +#endif + +#ifdef OTTERY_NO_LOCKS +#define DECL_LOCK(mutex) +#elif defined(OTTERY_OSATOMIC_LOCKS) +#define DECL_LOCK(mutex) OSSpinLock mutex; +#elif defined(OTTERY_CRITICAL_SECTION) +#define DECL_LOCK(mutex) CRITICAL_SECTION mutex; +#elif defined(OTTERY_PTHREADS) +#define DECL_LOCK(mutex) pthread_mutex_t mutex; +#endif + +#if defined(OTTERY_PTHREADS) +#define INIT_LOCK(mutex) \ + (pthread_mutex_init((mutex), NULL) != 0) +/** Acquire the lock for the state "st". */ +#define ACQUIRE_LOCK(mutex) do { \ + pthread_mutex_lock(mutex); \ + } while (0) +/** Release the lock for the state "st". */ +#define RELEASE_LOCK(mutex) do { \ + pthread_mutex_unlock(mutex); \ + } while (0) +#define DESTROY_LOCK(mutex) do { \ + pthread_mutex_destroy(mutex); \ + } while (0) + +#elif defined(OTTERY_CRITICAL_SECTION) +#define INIT_LOCK(mutex) \ + (InitializeCriticalSectionAndSpinCount((mutex), 3000) == 0) +#define ACQUIRE_LOCK(mutex) do { \ + EnterCriticalSection(mutex); \ + } while (0) +#define RELEASE_LOCK(mutex) do { \ + LeaveCriticalSection(mutex); \ + } while (0) +#define DESTROY_LOCK(mutex) do { \ + DeleteCriticalSection(mutex); \ + } while (0) + +#elif defined(OTTERY_OSATOMIC_LOCKS) +#define INIT_LOCK(mutex) \ + ((*(mutex) = 0), 0) +#define ACQUIRE_LOCK(mutex) do { \ + OSSpinLockLock(mutex); \ + } while (0) +#define RELEASE_LOCK(mutex) do { \ + OSSpinLockUnlock(mutex); \ + } while (0) +#define DESTROY_LOCK(mutex) ((void)0) + +#elif defined(OTTERY_NO_LOCKS) +#define INIT_LOCK(mutex) (0) +#define DESTROY_LOCK(mutex) ((void)0) +#define ACQUIRE_LOCK(mutex) ((void)0) +#define RELEASE_LOCK(mutex) ((void)0) +#else +#error How do I lock? +#endif + +#endif diff --git a/contrib/libottery/ottery.c b/contrib/libottery/ottery.c new file mode 100644 index 0000000..c58a901 --- /dev/null +++ b/contrib/libottery/ottery.c @@ -0,0 +1,847 @@ +/* Libottery by Nick Mathewson. + + This software has been dedicated to the public domain under the CC0 + public domain dedication. + + To the extent possible under law, the person who associated CC0 with + libottery has waived all copyright and related or neighboring rights + to libottery. + + You should have received a copy of the CC0 legalcode along with this + work in doc/cc0.txt. If not, see + <http://creativecommons.org/publicdomain/zero/1.0/>. + */ +#define OTTERY_INTERNAL +#include "ottery-internal.h" +#include "ottery.h" +#include "ottery_st.h" +#include "ottery_nolock.h" +#include <stdlib.h> +#include <string.h> +#include <sys/types.h> +#include <unistd.h> +#include <limits.h> + +#include <stdio.h> + +/* I've added a few assertions to sanity-check for debugging, but they should + * never ever ever trigger. It's fine to build this code with NDEBUG. */ +#include <assert.h> + +#ifdef _WIN32 +/* On Windows, there is no fork(), so we don't need to worry about forking. */ +#define OTTERY_NO_PID_CHECK +#endif + +#ifdef BUILD_RSPAMD +#include "cryptobox.h" +#endif + +/** Magic number for deciding whether an ottery_state is initialized. */ +#define MAGIC_BASIS 0x11b07734 + +/** Macro: yield the correct magic number for an ottery_state, based on + * its position in RAM. */ +#define MAGIC(ptr) (((uint32_t)(uintptr_t)(ptr)) ^ MAGIC_BASIS) + +static inline int ottery_st_rand_lock_and_check(struct ottery_state *st) +__attribute__((always_inline)); +static int ottery_st_reseed(struct ottery_state *state); +static int ottery_st_add_seed_impl(struct ottery_state *st, const uint8_t *seed, size_t n, int locking, int check_magic); + +#ifndef OTTERY_NO_WIPE_STACK +static void ottery_wipe_stack_(void) __attribute__((noinline)); +#endif + +#define LOCK(st) ACQUIRE_LOCK(&(st)->mutex) +#define UNLOCK(st) RELEASE_LOCK(&(st)->mutex) + +size_t +ottery_get_sizeof_config(void) +{ + return sizeof(struct ottery_config); +} + +size_t +ottery_get_sizeof_state(void) +{ + return sizeof(struct ottery_state); +} + +size_t +ottery_get_sizeof_state_nolock(void) +{ + return sizeof(struct ottery_state_nolock); +} + +const char * +ottery_get_version_string(void) +{ + return OTTERY_VERSION_STRING; +} + +uint32_t +ottery_get_version(void) +{ + return OTTERY_VERSION; +} + +uint32_t +ottery_get_build_flags(void) +{ + uint32_t result = 0; +#ifdef OTTERY_NO_PID_CHECK + result |= OTTERY_BLDFLG_NO_PID_CHECK; +#endif +#ifdef OTTERY_NO_INIT_CHECK + result |= OTTERY_BLDFLG_NO_INIT_CHECK; +#endif +#ifdef OTTERY_NO_LOCKS + result |= OTTERY_BLDFLG_NO_LOCKING; +#endif +#ifdef OTTERY_NO_CLEAR_AFTER_YIELD + result |= OTTERY_BLDFLG_NO_CLEAR_AFTER_YIELD; +#endif +#ifdef OTTERY_NO_WIPE_STACK + result |= OTTERY_BLDFLG_NO_WIPE_STACK; +#endif +#ifdef OTTERY_NO_SIMD + result |= OTTERY_BLDFLG_NO_SIMD; +#endif + return result; +} + +#ifndef OTTERY_NO_CLEAR_AFTER_YIELD +/** Used to zero out the contents of our buffer after we've just given a few + * to the user. */ +#define CLEARBUF(ptr,n) do { memset((ptr), 0, (n)); } while (0) +#else +#define CLEARBUF(ptr,n) ((void)0) +#endif + +/** + * Volatile pointer to memset: we use this to keep the compiler from + * eliminating our call to memset. (Don't make this static.) + */ +void * (*volatile ottery_memset_volatile_)(void *, int, size_t) = memset; + + +void +ottery_memclear_(void *mem, size_t len) +{ + /* NOTE: whenever we change this, change test/test_memclear.c accordingly */ + ottery_memset_volatile_(mem, 0, len); +} + +#ifndef OTTERY_NO_WIPE_STACK + +/* Chosen more or less arbitrarily */ +#define WIPE_STACK_LEN 512 + +/** + * Try to clear memory on the stack to clean up after our PRF. This can't + * easily be done in standard C, so we're doing an ugly hack in hopes that it + * actually helps. + * + * This should never be necessary in a correct program, but if your program is + * doing something stupid like leaking uninitialized stack, it might keep an + * attacker from exploiting that. + **/ +static void +ottery_wipe_stack_(void) +{ + char buf[WIPE_STACK_LEN]; + ottery_memset_volatile_(buf, 0, sizeof(buf)); +} +#else +#define ottery_wipe_stack_() ((void)0) +#endif + +int +ottery_config_init(struct ottery_config *cfg) +{ + cfg->impl = NULL; + cfg->entropy_config.urandom_fname = NULL; + cfg->entropy_config.urandom_fd = -1; + cfg->entropy_config.urandom_fd_is_set = 0; + cfg->entropy_config.disabled_sources = 0; + cfg->entropy_config.weak_sources = 0; + cfg->entropy_config.egd_sockaddr = NULL; + cfg->entropy_config.egd_socklen = 0; + cfg->entropy_config.allow_nondev_urandom = 0; + return 0; +} + +static const struct ottery_prf * +ottery_get_impl(const char *impl) +{ + int i; + const struct ottery_prf *ALL_PRFS[] = { +#ifdef HAVE_SIMD_CHACHA_2 + &ottery_prf_chacha20_krovetz_2_, + &ottery_prf_chacha12_krovetz_2_, + &ottery_prf_chacha8_krovetz_2_, +#endif +#ifdef HAVE_SIMD_CHACHA + &ottery_prf_chacha20_krovetz_1_, + &ottery_prf_chacha12_krovetz_1_, + &ottery_prf_chacha8_krovetz_1_, +#endif + +#ifdef BUILD_RSPAMD +#if defined(__x86_64__) && defined(RSPAMD_HAS_TARGET_ATTR) + &ottery_prf_aes_cryptobox_, +#endif + &ottery_prf_chacha20_cryptobox_, +#endif + &ottery_prf_chacha20_merged_, + &ottery_prf_chacha12_merged_, + &ottery_prf_chacha8_merged_, + + NULL, + }; + const uint32_t cap = ottery_get_cpu_capabilities_(); + + for (i = 0; ALL_PRFS[i]; ++i) { + const struct ottery_prf *prf = ALL_PRFS[i]; + if ((prf->required_cpucap & cap) != prf->required_cpucap) + continue; + if (impl == NULL) + return prf; + if (!strcmp(impl, prf->name)) + return prf; + if (!strcmp(impl, prf->impl)) + return prf; + if (!strcmp(impl, prf->flav)) + return prf; + } + return NULL; +} + +int +ottery_config_force_implementation(struct ottery_config *cfg, + const char *impl) +{ + const struct ottery_prf *prf = ottery_get_impl(impl); + if (prf) { + cfg->impl = prf; + return 0; + } + return OTTERY_ERR_INVALID_ARGUMENT; +} + +void +ottery_config_set_manual_prf_(struct ottery_config *cfg, + const struct ottery_prf *prf) +{ + cfg->impl = prf; +} + +void +ottery_config_set_urandom_device(struct ottery_config *cfg, + const char *fname) +{ + cfg->entropy_config.urandom_fname = fname; +} + +void +ottery_config_set_urandom_fd(struct ottery_config *cfg, + int fd) +{ + cfg->entropy_config.urandom_fd = fd; + cfg->entropy_config.urandom_fd_is_set = (fd >= 0); +} + +void +ottery_config_set_egd_socket(struct ottery_config *cfg, + const struct sockaddr *addr, + int len) +{ + cfg->entropy_config.egd_sockaddr = addr; + cfg->entropy_config.egd_socklen = len; +} + +void +ottery_config_disable_entropy_sources(struct ottery_config *cfg, + uint32_t disabled_sources) +{ + cfg->entropy_config.disabled_sources = + (disabled_sources & OTTERY_ENTROPY_ALL_SOURCES); +} + +void +ottery_config_mark_entropy_sources_weak(struct ottery_config *cfg, + uint32_t disabled_sources) +{ + cfg->entropy_config.weak_sources = + (disabled_sources & OTTERY_ENTROPY_ALL_SOURCES); +} + +/** + * As ottery_st_nextblock_nolock(), but fill the entire block with + * entropy, and don't try to rekey the state. + */ +static void +ottery_st_nextblock_nolock_norekey(struct ottery_state *st) +{ + st->prf.generate(st->state, st->buffer, st->block_counter); + ottery_wipe_stack_(); + ++st->block_counter; +} + +/** + * Generate (st->output_len) bytes of pseudorandom data from the PRF into + * (st->buffer). Use the first st->prf.state_bytes of those bytes to replace + * the PRF state and advance (st->pos) to point after them. + * + * This function does not acquire the lock on the state; use it within + * another function that does. + * + * @param st The state to use when generating the block. + */ +static void +ottery_st_nextblock_nolock(struct ottery_state_nolock *st) +{ + ottery_st_nextblock_nolock_norekey(st); + st->prf.setup(st->state, st->buffer); + CLEARBUF(st->buffer, st->prf.state_bytes); + st->block_counter = 0; + st->pos = st->prf.state_bytes; +} + +/** + * Initialize or reinitialize a PRNG state. + * + * @param st The state to initialize or reinitialize. + * @param prf The configuration to use. (Ignored for reinit) + * @return An OTTERY_ERR_* value (zero on success, nonzero on failure). + */ +static int +ottery_st_initialize(struct ottery_state *st, + const struct ottery_config *config, + int locked) +{ + const struct ottery_prf *prf = NULL; + struct ottery_config cfg_tmp; + int err; + /* We really need our state to be aligned. If it isn't, let's give an + * error now, and not a crash when the SIMD instructions start to fail. + */ + if (((uintptr_t)st) & 0xf) + return OTTERY_ERR_STATE_ALIGNMENT; + + if (!config) { + ottery_config_init(&cfg_tmp); + config = &cfg_tmp; + } + + prf = config->impl; + + if (!prf) + prf = ottery_get_impl(NULL); + + memset(st, 0, sizeof(*st)); + + if (locked) { + /* Now set up the spinlock or mutex or hybrid thing. */ + if (INIT_LOCK(&st->mutex)) + return OTTERY_ERR_LOCK_INIT; + } + + /* Check invariants for PRF, in case we wrote some bad code. */ + if ((prf->state_len > MAX_STATE_LEN) || + (prf->state_bytes > MAX_STATE_BYTES) || + (prf->state_bytes > prf->output_len) || + (prf->output_len > MAX_OUTPUT_LEN)) + return OTTERY_ERR_INTERNAL; + + /* Check whether some of our structure size assumptions are right. */ + if ((sizeof(struct ottery_state) > OTTERY_STATE_DUMMY_SIZE_) || + (sizeof(struct ottery_config) > OTTERY_CONFIG_DUMMY_SIZE_)) + return OTTERY_ERR_INTERNAL; + + memcpy(&st->entropy_config, &config->entropy_config, + sizeof(struct ottery_entropy_config)); + + /* Copy the PRF into place. */ + memcpy(&st->prf, prf, sizeof(*prf)); + + if ((err = ottery_st_reseed(st))) + return err; + + /* Set the magic number last, or else we might look like we succeeded + * when we didn't */ + st->magic = MAGIC(st); + + st->pid = getpid(); + + return 0; +} + +static int +ottery_st_reseed(struct ottery_state *st) +{ + /* Now seed the PRF: Generate some random bytes from the OS, and use them + * as whatever keys/nonces/whatever the PRF wants to have. */ + /* XXXX Add seed rather than starting from scratch? */ + int err; + uint32_t flags=0; + size_t buflen = ottery_get_entropy_bufsize_(st->prf.state_bytes); + uint8_t *buf = alloca(buflen); + if (!buf) + return OTTERY_ERR_INIT_STRONG_RNG; + + if ((err = ottery_get_entropy_(&st->entropy_config, &st->entropy_state, 0, + buf, st->prf.state_bytes, + &buflen, + &flags))) + return err; + if (buflen < st->prf.state_bytes) + return OTTERY_ERR_ACCESS_STRONG_RNG; + /* The first state_bytes bytes become the initial key. */ + st->prf.setup(st->state, buf); + /* If there are more bytes, we mix them into the key with add_seed */ + if (buflen > st->prf.state_bytes) + ottery_st_add_seed_impl(st, + buf + st->prf.state_bytes, + buflen - st->prf.state_bytes, + 0, + 0); + ottery_memclear_(buf, buflen); + st->last_entropy_flags = flags; + st->entropy_src_flags = flags; + + /* Generate the first block of output. */ + st->block_counter = 0; + ottery_st_nextblock_nolock(st); + + return 0; +} + +int +ottery_st_init(struct ottery_state *st, const struct ottery_config *cfg) +{ + return ottery_st_initialize(st, cfg, 1); +} + +int +ottery_st_init_nolock(struct ottery_state_nolock *st, + const struct ottery_config *cfg) +{ + return ottery_st_initialize(st, cfg, 0); +} + +static int +ottery_st_add_seed_impl(struct ottery_state *st, const uint8_t *seed, size_t n, int locking, int check_magic) +{ +#ifndef OTTERY_NO_INIT_CHECK + if (check_magic && UNLIKELY(st->magic != MAGIC(st))) { + ottery_fatal_error_(OTTERY_ERR_STATE_INIT); + return OTTERY_ERR_STATE_INIT; + } +#endif + + /* If the user passed NULL, then we should reseed from the operating + * system. */ + uint8_t *tmp_seed = NULL; + size_t tmp_seed_len = 0; + uint32_t flags = 0; + + if (!seed || !n) { + int err; + tmp_seed_len = ottery_get_entropy_bufsize_(st->prf.state_bytes); + tmp_seed = alloca(tmp_seed_len); + if (!tmp_seed) + return OTTERY_ERR_INIT_STRONG_RNG; + n = tmp_seed_len; + if ((err = ottery_get_entropy_(&st->entropy_config, &st->entropy_state, 0, + tmp_seed, st->prf.state_bytes, + &n, + &flags))) + return err; + if (n < st->prf.state_bytes) + return OTTERY_ERR_ACCESS_STRONG_RNG; + seed = tmp_seed; + } + + if (locking) + LOCK(st); + /* The algorithm here is really easy. We grab a block of output from the + * PRNG, that the first (state_bytes) bytes of that, XOR it with up to + * (state_bytes) bytes of our new seed data, and use that to set our new + * state. We do this over and over until we have no more seed data to add. + */ + while (n) { + unsigned i; + size_t m = n > st->prf.state_bytes/2 ? st->prf.state_bytes/2 : n; + ottery_st_nextblock_nolock_norekey(st); + for (i = 0; i < m; ++i) { + st->buffer[i] ^= seed[i]; + } + st->prf.setup(st->state, st->buffer); + st->block_counter = 0; + n -= m; + seed += m; + } + + /* Now make sure that st->buffer is set up with the new state. */ + ottery_st_nextblock_nolock(st); + + st->entropy_src_flags |= flags; + st->last_entropy_flags = flags; + + if (locking) + UNLOCK(st); + + /* If we used stack-allocated seed material, wipe it. */ + if (tmp_seed) + ottery_memclear_(tmp_seed, tmp_seed_len); + + return 0; +} + +int +ottery_st_add_seed(struct ottery_state *st, const uint8_t *seed, size_t n) +{ + return ottery_st_add_seed_impl(st, seed, n, 1, 1); +} +int +ottery_st_add_seed_nolock(struct ottery_state_nolock *st, const uint8_t *seed, size_t n) +{ + return ottery_st_add_seed_impl(st, seed, n, 0, 1); +} + + +void +ottery_st_wipe(struct ottery_state *st) +{ + DESTROY_LOCK(&st->mutex); + + ottery_st_wipe_nolock(st); +} + +void +ottery_st_wipe_nolock(struct ottery_state_nolock *st) +{ + ottery_memclear_(st, sizeof(struct ottery_state)); +} + +void +ottery_st_prevent_backtracking_nolock(struct ottery_state_nolock *st) +{ +#ifdef OTTERY_NO_CLEAR_AFTER_YIELD + memset(st->buffer, 0, st->pos); +#else + (void)st; +#endif +} + +void +ottery_st_prevent_backtracking(struct ottery_state *st) +{ + LOCK(st); + ottery_st_prevent_backtracking_nolock(st); + UNLOCK(st); +} + +/** Function that's invoked on a fatal error. See + * ottery_set_fatal_handler() for more information. */ +static void (*ottery_fatal_handler)(int) = NULL; + +void +ottery_fatal_error_(int error) +{ + if (ottery_fatal_handler) + ottery_fatal_handler(error); + else + abort(); +} + +void +ottery_set_fatal_handler(void (*fn)(int)) +{ + ottery_fatal_handler = fn; +} + +/** + * Shared prologue for functions generating random bytes from an ottery_state. + * Make sure that the state is initialized. + */ +static inline int +ottery_st_rand_check_init(struct ottery_state *st) +{ +#ifndef OTTERY_NO_INIT_CHECK + if (UNLIKELY(st->magic != MAGIC(st))) { + ottery_fatal_error_(OTTERY_ERR_STATE_INIT); + return -1; + } +#else + (void)st; +#endif + return 0; +} + +/* XXXX */ +static inline int +ottery_st_rand_check_pid(struct ottery_state *st) +{ +#ifndef OTTERY_NO_PID_CHECK + if (UNLIKELY(st->pid != getpid())) { + int err; + if ((err = ottery_st_reseed(st))) { + ottery_fatal_error_(OTTERY_ERR_FLAG_POSTFORK_RESEED|err); + return -1; + } + st->pid = getpid(); + } +#else + (void) st; +#endif + return 0; +} + +static inline int +ottery_st_rand_lock_and_check(struct ottery_state *st) +{ + if (ottery_st_rand_check_init(st)) + return -1; + LOCK(st); + if (ottery_st_rand_check_pid(st)) { + UNLOCK(st); + return -1; + } + return 0; +} + +static inline int +ottery_st_rand_check_nolock(struct ottery_state_nolock *st) +{ + if (ottery_st_rand_check_init(st)) + return -1; + if (ottery_st_rand_check_pid(st)) + return -1; + return 0; +} + +/** + * Generate a small-ish number of bytes from an ottery_state, using + * buffered data. If there is insufficient data in the buffer right now, + * use what we have, and generate more. + * + * @param st The state to use. + * @param out A location to write to. + * @param n The number of bytes to write. Must not be greater than + * st->prf.output_len*2 - st->prf.state_bytes - st->pos - 1. + */ +static inline void +ottery_st_rand_bytes_from_buf(struct ottery_state *st, uint8_t *out, + size_t n) +{ + if (n + st->pos < st->prf.output_len) { + memcpy(out, st->buffer+st->pos, n); + CLEARBUF(st->buffer+st->pos, n); + st->pos += n; + } else { + unsigned cpy = st->prf.output_len - st->pos; + memcpy(out, st->buffer+st->pos, cpy); + n -= cpy; + out += cpy; + ottery_st_nextblock_nolock(st); + memcpy(out, st->buffer+st->pos, n); + CLEARBUF(st->buffer, n); + st->pos += n; + assert(st->pos < st->prf.output_len); + } +} + +static void +ottery_st_rand_bytes_impl(struct ottery_state *st, void *out_, + size_t n) +{ + uint8_t *out = out_; + size_t cpy; + + if (n + st->pos < st->prf.output_len * 2 - st->prf.state_bytes - 1) { + /* Fulfill it all from the buffer simply if possible. */ + ottery_st_rand_bytes_from_buf(st, out, n); + return; + } + + /* Okay. That's not going to happen. Well, take what we can... */ + cpy = st->prf.output_len - st->pos; + memcpy(out, st->buffer + st->pos, cpy); + out += cpy; + n -= cpy; + + /* Then take whole blocks so long as we need them, without stirring... */ + while (n >= st->prf.output_len) { + /* (We could save a memcpy here if we generated the block directly at out + * rather than doing the memcpy here. First we'd need to make sure that we + * had gotten the block aligned to a 16-byte boundary, though, and we'd + * have some other tricky bookkeeping to do. Let's call this good enough + * for now.) */ + ottery_st_nextblock_nolock_norekey(st); + memcpy(out, st->buffer, st->prf.output_len); + out += st->prf.output_len; + n -= st->prf.output_len; + } + + /* Then stir for the last part. */ + ottery_st_nextblock_nolock(st); + ottery_st_rand_bytes_from_buf(st, out, n); +} + +void +ottery_st_rand_bytes(struct ottery_state *st, void *out_, size_t n) +{ + if (ottery_st_rand_lock_and_check(st)) + return; + ottery_st_rand_bytes_impl(st, out_, n); + UNLOCK(st); +} + +void +ottery_st_rand_bytes_nolock(struct ottery_state_nolock *st, void *out_, size_t n) +{ + if (ottery_st_rand_check_nolock(st)) + return; + ottery_st_rand_bytes_impl(st, out_, n); +} + +/** + * Assign an integer type from bytes at a possibly unaligned pointer. + * + * @param type the type of integer to assign. + * @param r the integer lvalue to write to. + * @param p a pointer to the bytes to read from. + **/ +#define INT_ASSIGN_PTR(type, r, p) do { \ + memcpy(&r, p, sizeof(type)); \ +} while (0) + +/** + * Shared code for implementing rand_unsigned() and rand_uint64(). + * + * @param st The state to use. + * @param inttype The type of integer to generate. + **/ +#define OTTERY_RETURN_RAND_INTTYPE_IMPL(st, inttype, unlock) do { \ + inttype result; \ + if (sizeof(inttype) + (st)->pos <= (st)->prf.output_len) { \ + INT_ASSIGN_PTR(inttype, result, (st)->buffer + (st)->pos); \ + CLEARBUF((st)->buffer + (st)->pos, sizeof(inttype)); \ + (st)->pos += sizeof(inttype); \ + if (st->pos == (st)->prf.output_len) { \ + ottery_st_nextblock_nolock(st); \ + } \ + } else { \ + /* Our handling of this case here is significantly simpler */ \ + /* than that of ottery_st_rand_bytes_from_buf, at the expense */ \ + /* of wasting up to sizeof(inttype)-1 bytes. Since inttype */ \ + /* is at most 8 bytes long, that's not such a big deal. */ \ + ottery_st_nextblock_nolock(st); \ + INT_ASSIGN_PTR(inttype, result, (st)->buffer + (st)->pos); \ + CLEARBUF((st)->buffer, sizeof(inttype)); \ + (st)->pos += sizeof(inttype); \ + } \ + unlock; \ + return result; \ +} while (0) + +#define OTTERY_RETURN_RAND_INTTYPE(st, inttype) do { \ + if (ottery_st_rand_lock_and_check(st)) \ + return (inttype)0; \ + OTTERY_RETURN_RAND_INTTYPE_IMPL(st, inttype, UNLOCK(st)); \ +} while (0) + +#define OTTERY_RETURN_RAND_INTTYPE_NOLOCK(st, inttype) do { \ + if (ottery_st_rand_check_nolock(st)) \ + return (inttype)0; \ + OTTERY_RETURN_RAND_INTTYPE_IMPL(st, inttype, ); \ +} while (0) + +unsigned +ottery_st_rand_unsigned(struct ottery_state *st) +{ + OTTERY_RETURN_RAND_INTTYPE(st, unsigned); +} + +unsigned +ottery_st_rand_unsigned_nolock(struct ottery_state_nolock *st) +{ + OTTERY_RETURN_RAND_INTTYPE_NOLOCK(st, unsigned); +} + +uint32_t +ottery_st_rand_uint32(struct ottery_state *st) +{ + OTTERY_RETURN_RAND_INTTYPE(st, uint32_t); +} + +uint32_t +ottery_st_rand_uint32_nolock(struct ottery_state_nolock *st) +{ + OTTERY_RETURN_RAND_INTTYPE_NOLOCK(st, uint32_t); +} + +uint64_t +ottery_st_rand_uint64(struct ottery_state *st) +{ + OTTERY_RETURN_RAND_INTTYPE(st, uint64_t); +} + +uint64_t +ottery_st_rand_uint64_nolock(struct ottery_state_nolock *st) +{ + OTTERY_RETURN_RAND_INTTYPE_NOLOCK(st, uint64_t); +} + +unsigned +ottery_st_rand_range_nolock(struct ottery_state_nolock *st, unsigned upper) +{ + unsigned lim = upper+1; + unsigned divisor = lim ? (UINT_MAX / lim) : 1; + unsigned n; + do { + n = (ottery_st_rand_unsigned_nolock(st) / divisor); + } while (n > upper); + + return n; +} + +uint64_t +ottery_st_rand_range64_nolock(struct ottery_state_nolock *st, uint64_t upper) +{ + uint64_t lim = upper+1; + uint64_t divisor = lim ? (UINT64_MAX / lim) : 1; + uint64_t n; + do { + n = (ottery_st_rand_uint64_nolock(st) / divisor); + } while (n > upper); + + return n; +} + +unsigned +ottery_st_rand_range(struct ottery_state *state, unsigned upper) +{ + unsigned n; + if (ottery_st_rand_check_init(state)) + return 0; + LOCK(state); + n = ottery_st_rand_range_nolock(state, upper); + UNLOCK(state); + return n; +} + +uint64_t +ottery_st_rand_range64(struct ottery_state *state, uint64_t upper) +{ + uint64_t n; + if (ottery_st_rand_check_init(state)) + return 0; + LOCK(state); + n = ottery_st_rand_range64_nolock(state, upper); + UNLOCK(state); + return n; +} diff --git a/contrib/libottery/ottery.h b/contrib/libottery/ottery.h new file mode 100644 index 0000000..e2caac2 --- /dev/null +++ b/contrib/libottery/ottery.h @@ -0,0 +1,143 @@ +/* Libottery by Nick Mathewson. + + This software has been dedicated to the public domain under the CC0 + public domain dedication. + + To the extent possible under law, the person who associated CC0 with + libottery has waived all copyright and related or neighboring rights + to libottery. + + You should have received a copy of the CC0 legalcode along with this + work in doc/cc0.txt. If not, see + <http://creativecommons.org/publicdomain/zero/1.0/>. + */ +#ifndef OTTERY_H_HEADER_INCLUDED_ +#define OTTERY_H_HEADER_INCLUDED_ +#include <stdint.h> +#include <sys/types.h> + +#ifdef __cplusplus +extern "C" { +#endif + +#include "ottery_common.h" + +/** @file */ + +struct ottery_config; + +/* Functions that use an implicit global state */ + +/** + * Fill a buffer with random bytes. + * + * @param buf The buffer to fill. + * @param n The number of bytes to write. + */ +void ottery_rand_bytes(void *buf, size_t n); +/** + * Generate a random number of type unsigned. + * + * @return A random number between 0 and UINT_MAX included, + * chosen uniformly. + */ +unsigned ottery_rand_unsigned(void); +/** + * Generate a random number of type uint32_t. + * + * @return A random number between 0 and UINT32_MAX included, + * chosen uniformly. + */ +uint32_t ottery_rand_uint32(void); +/** + * Generate a random number of type uint64_t. + * + * @return A random number between 0 and UINT64_MAX included, + * chosen uniformly. + */ +uint64_t ottery_rand_uint64(void); +/** + * Generate a random number of type unsigned in a given range. + * + * @param top The upper bound of the range (inclusive). + * @return A random number no larger than top, and no less than 0, + * chosen uniformly. + */ +unsigned ottery_rand_range(unsigned top); +/** + * Generate a random number of type uint64_t in a given range. + * + * @param top The upper bound of the range (inclusive). + * @return A random number no larger than top, and no less than 0, + * chosen uniformly. + */ +uint64_t ottery_rand_range64(uint64_t top); + +/** + * Initialize the libottery global state. + * + * Most users should not need to use this function. If you use it, you must + * call it before any of: ottery_rand_bytes, ottery_rand_unsigned, + * ottery_rand_uint64, ottery_rand_range, ottery_rand_uint64_range, + * ottery_add_seed, ottery_wipe, ottery_stir. + * + * You would want to use this function if you want to select some non-default + * behavior using an ottery_config structure. + * + * @param cfg Either NULL, or an ottery_config structure that has been + * initialized with ottery_config_init(). + * @return Zero on success, or one of the OTTERY_ERR_* error codes on failure. + */ +int ottery_init(const struct ottery_config *cfg); + +/** + * Add more entropy to the libottery global state. + * + * Calling this function should be needless, if you trust your operating + * system's random number generator and entropy extraction features. You + * would want to use this function if you think the operating system's random + * number generator might be inadequate, and you want to add more entropy from + * EGD or something. + * + * You might also want to call this function if your belief system says that + * it's useful to periodically add more raw entropy to a well-seeded + * cryptographically strong PRNG. + * + * @param seed Bytes to add to the state. If this value is NULL, we take + * more random bytes from the OS. + * @param n The number of bytes to add. If this value is 0, we take more + * random bytes from the OS, regardless of the value of seed. + * @return Zero on success, or one of the OTTERY_ERR_* error codes on failure. + */ +int ottery_add_seed(const uint8_t *seed, size_t n); + +/** + * Destroy the libottery global state and release any resources that it might + * hold. + * + * Ordinarily, you would only want to call this at exit, if at all. + */ +void ottery_wipe(void); + +/** + * Explicitly tell libottery to prevent backtracking attacks. (Usually + * needless.) + * + * Once this function has been called, an attacker who compromises the state + * later on will not be able to recover bytes that have previously been + * returned by any of the ottery_rand_* functions. + * + * You should not usually need to call this function: Libottery provides + * backtracking resistance by default, so unless you have manually recompiled + * with the OTTERY_NO_CLEAR_AFTER_YIELD option, this function isn't + * necessary and has no effect. Even *with* OTTERY_NO_CLEAR_AFTER_YIELD, + * this function isn't necessary in ordinary operation: the libottery state is + * implicitly "stirred" every 1k or so. + */ +void ottery_prevent_backtracking(void); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/contrib/libottery/ottery_common.h b/contrib/libottery/ottery_common.h new file mode 100644 index 0000000..bac6f04 --- /dev/null +++ b/contrib/libottery/ottery_common.h @@ -0,0 +1,351 @@ +/* Libottery by Nick Mathewson. + + This software has been dedicated to the public domain under the CC0 + public domain dedication. + + To the extent possible under law, the person who associated CC0 with + libottery has waived all copyright and related or neighboring rights + to libottery. + + You should have received a copy of the CC0 legalcode along with this + work in doc/cc0.txt. If not, see + <http://creativecommons.org/publicdomain/zero/1.0/>. + */ +#ifndef OTTERY_COMMON_H_HEADER_INCLUDED_ +#define OTTERY_COMMON_H_HEADER_INCLUDED_ +#include <stdint.h> +#include <sys/types.h> + +/** @file */ + +struct ottery_config; + +/* Error codes */ + +/** + * @name libottery error codes and flags + * + * @{ + */ +/** No error has occurred. */ +#define OTTERY_ERR_NONE 0x0000 +/** We failed to allocate or initialize a lock. */ +#define OTTERY_ERR_LOCK_INIT 0x0001 +/** An internal error occurrred. This is probably a programming mistake + * in libottery. */ +#define OTTERY_ERR_INTERNAL 0x0002 +/** We were unable to connect to the operating system's strong RNG. */ +#define OTTERY_ERR_INIT_STRONG_RNG 0x0003 +/** We were unable to retrieve sufficient random bytes from the + * operating system's strong RNG. */ +#define OTTERY_ERR_ACCESS_STRONG_RNG 0x0004 +/** At least one argument to the function was invalid. */ +#define OTTERY_ERR_INVALID_ARGUMENT 0x0005 +/** An ottery_state structure was not aligned to a 16-byte boundary. */ +#define OTTERY_ERR_STATE_ALIGNMENT 0x0006 + +/** FATAL ERROR: An ottery_st function other than ottery_st_init() was + * called on and uninitialized state. */ +#define OTTERY_ERR_STATE_INIT 0x1000 +/** FLAG; FATAL ERROR: The error occurred while initializing the global + * state during the first call to an ottery_rand_* function. */ +#define OTTERY_ERR_FLAG_GLOBAL_PRNG_INIT 0x2000 +/** FLAG; FATAL ERROR: The error occurred while reinitializing a state + * after a fork(). (We need to do this, or else both processes would + * generate the same values, which could give dire results.) + */ +#define OTTERY_ERR_FLAG_POSTFORK_RESEED 0x4000 + +/** + * Checks whether an OTTERY_ERR value is a fatal error. + * + * @param err an OTTERY_ERR_* valuer + * @return True if err is fatal; false if it is not fatal. + */ +#define OTTERY_ERR_IS_FATAL(err) \ + (((err) & ~0xfff) != 0) + +/* Functions to interact with the library on a global level */ + +/** + * Override the behavior of libottery on a fatal error. + * + * By default, libottery will call abort() in a few circumstances, in + * order to keep the program from operating insecurely. If you want, + * you can provide another function to call instead. + * + * If your function does not itself abort() or exit() the process, or throw an + * exception (assuming some C family that has exceptions), libottery will + * continue running insecurely -- it might return predictable random numbers, + * leak secrets, or just return 0 for everything -- so you should really be + * very careful here. + * + * (The alternative to fatal errors would have been having all the + * ottery_rand_* functions able to return an error, and requiring users + * to check those codes. But experience suggests that C programmers + * frequently do not check error codes.) + * + * @param fn A function to call in place of abort(). It will receive as + * its argument one of the OTTERY_ERR_* error codes. + */ +void ottery_set_fatal_handler(void (*fn)(int errorcode)); + +/* Functions to manipulate parameters. */ + +/** + * @name Names of prfs for use with ottery_config_force_implementation + * + * @{ */ +#define OTTERY_PRF_CHACHA "CHACHA" +#define OTTERY_PRF_CHACHA8 "CHACHA8" +#define OTTERY_PRF_CHACHA12 "CHACHA12" +#define OTTERY_PRF_CHACHA20 "CHACHA20" +#define OTTERY_PRF_CHACHA_SIMD "CHACHA-SIMD" +#define OTTERY_PRF_CHACHA8_SIMD "CHACHA8-SIMD" +#define OTTERY_PRF_CHACHA12_SIMD "CHACHA12-SIMD" +#define OTTERY_PRF_CHACHA20_SIMD "CHACHA20-SIMD" +#define OTTERY_PRF_CHACHA_NO_SIMD "CHACHA-NOSIMD" +#define OTTERY_PRF_CHACHA8_NO_SIMD "CHACHA8-NOSIMD" +#define OTTERY_PRF_CHACHA12_NO_SIMD "CHACHA12-NOSIMD" +#define OTTERY_PRF_CHACHA20_NO_SIMD "CHACHA20-NOSIMD" +/** @} */ + +/** + * Initialize an ottery_config structure. + * + * You must call this function on any ottery_config structure before it + * can be passed to ottery_init() or ottery_st_init(). + * + * @param cfg The configuration object to initialize. + * @return Zero on success, or one of the OTTERY_ERR_* error codes on + * failure. + */ +int ottery_config_init(struct ottery_config *cfg); + +/** + * Try to force the use of a particular pseudorandom function for a given + * libottery instance. + * + * To use this function, you call it on an ottery_config structure after + * ottery_config_init(), and before passing that structure to + * ottery_st_init() or ottery_init(). + * + * @param cfg The configuration structure to configure. + * @param impl The name of a pseudorandom function. One of the + * OTTERY_PRF_* values. + * @return Zero on success, or one of the OTTERY_ERR_* error codes on + * failure. + */ +int ottery_config_force_implementation(struct ottery_config *cfg, + const char *impl); + +/** + * Set a device file to use as a source of strong entropy. + * + * To use this function, you call it on an ottery_config structure after + * ottery_config_init(), and before passing that structure to + * ottery_st_init() or ottery_init(). + * + * By default, libottery will try /dev/urandom on Unix-like systems. + * + * @param cfg The configuration structure to configure. + * @param fname The name of the device to use instead of /dev/urandom. This + * pointer is copied around, and must not be freed while any libottery state + * configured using this structure is still in use. + * + */ +void ottery_config_set_urandom_device(struct ottery_config *cfg, + const char *fname); + +/** + * Set a device file to use as a source of strong entropy from the operating + * system. + * + * To use this function, you call it on an ottery_config structure after + * ottery_config_init(), and before passing that structure to + * ottery_st_init() or ottery_init(). + * + * This function overrides the default behavior, and overrides any + * setting in ottery_config_set_urandom_device. + * + * You MUST NOT change the the file descriptor while any libottery PRNG + * configured with it is still running. For example, don't close it, or use + * dup2 to make it refer to a different file, or anything like that. + * + * It is probably a good idea to open the file with the CLOEXEC flag set. + * + * @param cfg The configuration structure to configure. + * @param fd A file descriptor to use as an OS rng source. + */ +void ottery_config_set_urandom_fd(struct ottery_config *cfg, + int fd); + +struct sockaddr; + +/** + * Configure a socket at which to find a local copy of some service + * implementing the EGD (entropy-gathering daemon) protocol. + * + * Unless this function is called, EGD is not used by default. + + * To use this function, you call it on an ottery_config structure after + * ottery_config_init(), and before passing that structure to + * ottery_st_init() or ottery_init(). + * + * TODO: This is not implemented for Windows yet. + * + * @param cfg The configuration structure to configure. + * @param addr The address of the daemon. Obviously, this should be + * some port on localhost, or a unix socket. This pointer is copied + * around, and must not be freed while any libottery state configured + * using this structure is still in use. + * @param len the length of the address. + * + */ +void ottery_config_set_egd_socket(struct ottery_config *cfg, + const struct sockaddr *addr, + int len); + +/** + * @brief External entropy sources. + * + * These can be passed as a bitmask to ottery_config_disable_entropy_sources. + * + * @{ */ +/** A unix-style /dev/urandom device. */ +#define OTTERY_ENTROPY_SRC_RANDOMDEV 0x0010000 +/** The Windows CryptGenRandom call. */ +#define OTTERY_ENTROPY_SRC_CRYPTGENRANDOM 0x0020000 +/** The Intel RDRAND instruction. */ +#define OTTERY_ENTROPY_SRC_RDRAND 0x0040000 +/** Some local server obeying the EGD protocol. Has no effect unless + * ottery_config_set_egd_socket was called. */ +#define OTTERY_ENTROPY_SRC_EGD 0x0080000 +/** @} */ + +/** + * Disable the use of one or more entropy sources. + * + * Note that if enough entropy sources are disabled, the state will + * not be able to get initialized, and libottery might not work. + * + * To use this function, you call it on an ottery_config structure after + * ottery_config_init(), and before passing that structure to + * ottery_st_init() or ottery_init(). + * + * @param cfg A configuration in which to disable one or more entropy sources. + * @param disabled_sources a bitwise combination of one or more + * OTTERY_ENTROPY_SRC_* values to disable. This will replace + * any previous bitmask of disabled sources. + * + */ +void ottery_config_disable_entropy_sources(struct ottery_config *cfg, + uint32_t disabled_sources); + +/** + * Mark one or more entropy sources as "weak". + * + * Unlike a disabled source, we will still try to read entropy from + * a weak source -- but we will fail if _only_ weak sources are available. + * + * Note that if enough entropy sources are disabled and/or weak sources are + * failing, the state will not be able to get initialized, and libottery might + * not work. + * + * To use this function, you call it on an ottery_config structure after + * ottery_config_init(), and before passing that structure to + * ottery_st_init() or ottery_init(). + * + * @param cfg A configuration in which to disable one or more entropy sources. + * @param weak_sources a bitwise combination of one or more + * OTTERY_ENTROPY_SRC_* values to mark as weak. This will replace + * any previous bitmask of weak sources. + */ +void ottery_config_mark_entropy_sources_weak(struct ottery_config *cfg, + uint32_t weak_source); + +/** Size reserved for struct ottery_config */ +#define OTTERY_CONFIG_DUMMY_SIZE_ 1024 + +#ifndef OTTERY_INTERNAL +/** + * A configuration object for setting up a libottery instance. + * + * An ottery_config structure is initialized with ottery_config_init, + * and passed to ottery_init() or ottery_st_init(). + * + * The contents of this structure are opaque; The definition here is + * defined to be large enough so that programs that allocate it will get + * more than enough room. + */ +struct ottery_config { + /** Nothing to see here */ + uint8_t dummy_[OTTERY_CONFIG_DUMMY_SIZE_]; +}; +#endif + +/** + * Get the minimal size for allocating an ottery_config. + * + * sizeof(ottery_config) will give an overestimate to allow binary + * compatibility with future versions of libottery. Use this function instead + * to get the minimal number of bytes to allocate. + * + * @return The minimal number of bytes to use when allocating an + * ottery_config structure. + */ +size_t ottery_get_sizeof_config(void); + +/** + * @name libottery build flag + * + * @see ottery_Get_build_flags() + * + * @{ + */ +/** Set if libottery was built with PID checking disabled. If this option is + * present, fork()ing can be dangerous. */ +#define OTTERY_BLDFLG_NO_PID_CHECK 0x00000001 +/** Set if libottery was built with initialization checking disabled. If this + * option is present, libottery might use an uninitialized, unseeded PRNGs. + */ +#define OTTERY_BLDFLG_NO_INIT_CHECK 0x00000002 +/** Set if locking was disabled. If this option is present, no libottery + * state, including the global state, is thread-safe. */ +#define OTTERY_BLDFLG_NO_LOCKING 0x00000004 +/** Set if the clear-after-yield feature was disabled. If this option is + * present, backtracking-resistance is somewhat compromised. */ +#define OTTERY_BLDFLG_NO_CLEAR_AFTER_YIELD 0x00000008 +/** Set if the stack-wiping feature was disabled. If this option is + * present, programs which accidentally read uninitialized data from the + * stack may leak some cryptographic state. */ +#define OTTERY_BLDFLG_NO_WIPE_STACK 0x00000010 +/** Set if SIMD support was disabled. This will make libottery slower. */ +#define OTTERY_BLDFLG_NO_SIMD 0x00010000 +/** @} */ + +/** A bitmask of any flags that might affect safe and secure program + * operation. */ +#define OTTERY_BLDFLG_MASK_SAFETY 0x0000ffff + +/** + * Return a bitmask of flags describing the compile-time options that this + * libottery instance was built with. Some of these flags might make the + * library less safe to use! + */ +uint32_t ottery_get_build_flags(void); + +/** + * Return a run-time version number for Libottery. The first three bytes are + * the major number, minor number, and patch-level respectively. The final + * byte is 0 for a released version, and nonzero otherwise. + */ +uint32_t ottery_get_version(void); +/** + * Return a human-readable string representing the run-time Libottery version. + */ +const char *ottery_get_version_string(void); + +const char *ottery_get_impl_name(void); + +#endif diff --git a/contrib/libottery/ottery_cpuinfo.c b/contrib/libottery/ottery_cpuinfo.c new file mode 100644 index 0000000..2e8bdaa --- /dev/null +++ b/contrib/libottery/ottery_cpuinfo.c @@ -0,0 +1,88 @@ +/* Libottery by Nick Mathewson. + + This software has been dedicated to the public domain under the CC0 + public domain dedication. + + To the extent possible under law, the person who associated CC0 with + libottery has waived all copyright and related or neighboring rights + to libottery. + + You should have received a copy of the CC0 legalcode along with this + work in doc/cc0.txt. If not, see + <http://creativecommons.org/publicdomain/zero/1.0/>. + */ +#include "ottery-internal.h" +#include <stdint.h> + +#if defined(i386) || \ + defined(__i386) || \ + defined(__M_IX86) || \ + defined(_M_IX86) +#define X86 +#elif defined(__x86_64) || \ + defined(_M_AMD64) +#define X86 +#define X86_64 +#endif + +#if defined(__arm__) || \ + defined(_M_ARM) +#define ARM +#endif + +#if defined(X86) +#ifdef _MSC_VER +#include <intrin.h> +#define cpuid(a,b) __cpuid((b), (a)) +#else +static void +cpuid(int index, int regs[4]) +{ + unsigned int eax, ebx, ecx, edx; +#ifdef X86_64 + __asm("cpuid" : "=a"(eax), "=b" (ebx), "=c"(ecx), "=d"(edx) + : "0"(index)); +#else + __asm volatile( + "xchgl %%ebx, %1; cpuid; xchgl %%ebx, %1" + : "=a" (eax), "=r" (ebx), "=c" (ecx), "=d" (edx) + : "0" (index) + : "cc" ); +#endif + + regs[0] = eax; + regs[1] = ebx; + regs[2] = ecx; + regs[3] = edx; +} +#endif +#endif + +static uint32_t disabled_cpu_capabilities = 0; + +void +ottery_disable_cpu_capabilities_(uint32_t disable) +{ + disabled_cpu_capabilities |= disable; +} + +uint32_t +ottery_get_cpu_capabilities_(void) +{ +#ifdef X86 + uint32_t cap = 0; + int res[4]; + cpuid(1, res); + if (res[3] & (1<<26)) + cap |= OTTERY_CPUCAP_SIMD; + if (res[2] & (1<<9)) + cap |= OTTERY_CPUCAP_SSSE3; + if (res[2] & (1<<25)) + cap |= OTTERY_CPUCAP_AES; + if (res[2] & (1<<30)) + cap |= OTTERY_CPUCAP_RAND; +#else + uint32_t cap = OTTERY_CPUCAP_SIMD; +#endif + return cap & ~disabled_cpu_capabilities; +} diff --git a/contrib/libottery/ottery_entropy.c b/contrib/libottery/ottery_entropy.c new file mode 100644 index 0000000..819a380 --- /dev/null +++ b/contrib/libottery/ottery_entropy.c @@ -0,0 +1,112 @@ +/* Libottery by Nick Mathewson. + + This software has been dedicated to the public domain under the CC0 + public domain dedication. + + To the extent possible under law, the person who associated CC0 with + libottery has waived all copyright and related or neighboring rights + to libottery. + + You should have received a copy of the CC0 legalcode along with this + work in doc/cc0.txt. If not, see + <http://creativecommons.org/publicdomain/zero/1.0/>. + */ +#define OTTERY_INTERNAL +#include "ottery-internal.h" +#include "ottery.h" +#include <sys/stat.h> +#include <fcntl.h> +#include <unistd.h> +#include <string.h> + +#define SRC(x) OTTERY_ENTROPY_SRC_ ## x +#define DOM(x) OTTERY_ENTROPY_DOM_ ## x +#define FL(x) OTTERY_ENTROPY_FL_ ## x + +#include "ottery_entropy_cryptgenrandom.c" +#include "ottery_entropy_urandom.c" +#include "ottery_entropy_rdrand.c" +#include "ottery_entropy_egd.c" + +/** Table of RNG functions and their properties. */ +static struct ottery_randbytes_source { + int (*fn)(const struct ottery_entropy_config *, + struct ottery_entropy_state *, + uint8_t *, size_t); + uint32_t flags; +} RAND_SOURCES[] = { +#ifdef ENTROPY_SOURCE_CRYPTGENRANDOM + ENTROPY_SOURCE_CRYPTGENRANDOM, +#endif +#ifdef ENTROPY_SOURCE_URANDOM + ENTROPY_SOURCE_URANDOM, +#endif +#ifdef ENTROPY_SOURCE_EGD + ENTROPY_SOURCE_EGD, +#endif +#ifdef ENTROPY_SOURCE_RDRAND + ENTROPY_SOURCE_RDRAND, +#endif + { NULL, 0 } +}; + +size_t +ottery_get_entropy_bufsize_(size_t n) +{ + return n * (sizeof(RAND_SOURCES)/sizeof(RAND_SOURCES[0]) - 1); +} + +int +ottery_get_entropy_(const struct ottery_entropy_config *config, + struct ottery_entropy_state *state, + uint32_t select_sources, + uint8_t *bytes, size_t n, size_t *buflen, + uint32_t *flags_out) +{ + ssize_t err = OTTERY_ERR_INIT_STRONG_RNG, last_err = 0; + int i; + uint32_t got = 0; + uint8_t *next; + const uint32_t disabled_sources = config ? config->disabled_sources : 0; + + memset(bytes, 0, *buflen); + next = bytes; + + *flags_out = 0; + + for (i=0; RAND_SOURCES[i].fn; ++i) { + uint32_t flags = RAND_SOURCES[i].flags; + /* Don't use a disabled source. */ + if (0 != (flags & disabled_sources)) + continue; + /* If some flags must be set, only use those. */ + if ((flags & select_sources) != select_sources) + continue; + /* If we already have input from a certain domain, we don't need more */ + if ((flags & (got & OTTERY_ENTROPY_DOM_MASK)) != 0) + continue; + /* If we can't write these bytes, don't try. */ + if (next + n > bytes + *buflen) + break; + err = RAND_SOURCES[i].fn(config, state, next, n); + if (err == 0) { + uint32_t flags = RAND_SOURCES[i].flags; + if (config && (flags & config->weak_sources)) + flags &= ~OTTERY_ENTROPY_FL_STRONG; + + got |= flags; + next += n; + } else { + last_err = err; + } + } + + /* Do not report success unless at least one source was strong. */ + if (0 == (got & OTTERY_ENTROPY_FL_STRONG)) + return last_err ? last_err : OTTERY_ERR_INIT_STRONG_RNG; + + *flags_out = got; + *buflen = next - bytes; + + return 0; +} diff --git a/contrib/libottery/ottery_entropy_cryptgenrandom.c b/contrib/libottery/ottery_entropy_cryptgenrandom.c new file mode 100644 index 0000000..d29d9d1 --- /dev/null +++ b/contrib/libottery/ottery_entropy_cryptgenrandom.c @@ -0,0 +1,51 @@ +/* Libottery by Nick Mathewson. + + This software has been dedicated to the public domain under the CC0 + public domain dedication. + + To the extent possible under law, the person who associated CC0 with + libottery has waived all copyright and related or neighboring rights + to libottery. + + You should have received a copy of the CC0 legalcode along with this + work in doc/cc0.txt. If not, see + <http://creativecommons.org/publicdomain/zero/1.0/>. + */ +#define OTTERY_INTERNAL +#include "ottery-internal.h" +#include "ottery.h" + +#ifdef _WIN32 + +/** Generate random bytes using the Windows CryptGenRandom operating-system + * RNG. */ +static int +ottery_get_entropy_cryptgenrandom(const struct ottery_entropy_config *cfg, + struct ottery_entropy_state *state, + uint8_t *out, size_t outlen) +{ + /* On Windows, CryptGenRandom is supposed to be a well-seeded + * cryptographically strong random number generator. */ + HCRYPTPROV provider; + int retval = 0; + (void) cfg; + (void) state; + + if (0 == CryptAcquireContext(&provider, NULL, NULL, PROV_RSA_FULL, + CRYPT_VERIFYCONTEXT)) + return OTTERY_ERR_INIT_STRONG_RNG; + + if (0 == CryptGenRandom(provider, outlen, out)) + retval = OTTERY_ERR_ACCESS_STRONG_RNG; + + CryptReleaseContext(provider, 0); + return retval; +} + +#define ENTROPY_SOURCE_CRYPTGENRANDOM \ + { ottery_get_entropy_cryptgenrandom, \ + SRC(CRYPTGENRANDOM)|DOM(OS)|FL(STRONG) } + +#endif + + diff --git a/contrib/libottery/ottery_entropy_egd.c b/contrib/libottery/ottery_entropy_egd.c new file mode 100644 index 0000000..7e9cb07 --- /dev/null +++ b/contrib/libottery/ottery_entropy_egd.c @@ -0,0 +1,75 @@ +/* Libottery by Nick Mathewson. + + This software has been dedicated to the public domain under the CC0 + public domain dedication. + + To the extent possible under law, the person who associated CC0 with + libottery has waived all copyright and related or neighboring rights + to libottery. + + You should have received a copy of the CC0 legalcode along with this + work in doc/cc0.txt. If not, see + <http://creativecommons.org/publicdomain/zero/1.0/>. + */ +#ifndef _WIN32 +/* TODO: Support win32. */ +#include <sys/socket.h> + +/** Implement an entropy-source that uses the EGD protocol. The + * Entropy-Gathering Daemon is program (actually, one of several programs) + * that watches system events, periodically runs commands whose outputs have + * high variance, and so on. It communicates over a simple socket-based + * protocol, of which we use only a tiny piece. */ +static int +ottery_get_entropy_egd(const struct ottery_entropy_config *cfg, + struct ottery_entropy_state *state, + uint8_t *out, size_t outlen) +{ + int sock, n, result; + unsigned char msg[2]; + (void) state; + + if (! cfg || ! cfg->egd_sockaddr || ! cfg->egd_socklen) + return OTTERY_ERR_INIT_STRONG_RNG; + if (outlen > 255) + return OTTERY_ERR_ACCESS_STRONG_RNG; + + sock = socket(cfg->egd_sockaddr->sa_family, SOCK_STREAM, 0); + if (sock < 0) + return OTTERY_ERR_INIT_STRONG_RNG; + + if (connect(sock, cfg->egd_sockaddr, cfg->egd_socklen) < 0) { + result = OTTERY_ERR_INIT_STRONG_RNG; + goto out; + } + + msg[0] = 1; /* nonblocking request */ + msg[1] = (unsigned char) outlen; /* for outlen bytes */ + + if (write(sock, msg, 2) != 2 || + read(sock, msg, 1) != 1) { + result = OTTERY_ERR_ACCESS_STRONG_RNG; + goto out; + } + + if (msg[0] != outlen) { + /* TODO Use any bytes we get, even if they aren't as many as we wanted. */ + result = OTTERY_ERR_ACCESS_STRONG_RNG; + goto out; + } + + n = ottery_read_n_bytes_from_file_(sock, out, outlen); + if (n < 0 || (size_t)n != outlen) { + result = OTTERY_ERR_ACCESS_STRONG_RNG; + goto out; + } + result = 0; + out: + close(sock); + return result; +} + +#define ENTROPY_SOURCE_EGD \ + { ottery_get_entropy_egd, SRC(EGD)|DOM(EGD)|FL(STRONG) } + +#endif diff --git a/contrib/libottery/ottery_entropy_rdrand.c b/contrib/libottery/ottery_entropy_rdrand.c new file mode 100644 index 0000000..4f227d3 --- /dev/null +++ b/contrib/libottery/ottery_entropy_rdrand.c @@ -0,0 +1,58 @@ +/* Libottery by Nick Mathewson. + + This software has been dedicated to the public domain under the CC0 + public domain dedication. + + To the extent possible under law, the person who associated CC0 with + libottery has waived all copyright and related or neighboring rights + to libottery. + + You should have received a copy of the CC0 legalcode along with this + work in doc/cc0.txt. If not, see + <http://creativecommons.org/publicdomain/zero/1.0/>. + */ + +#if defined(i386) || \ + defined(__i386) || \ + defined(__x86_64) || \ + defined(__M_IX86) || \ + defined(_M_IX86) || \ + defined(__INTEL_COMPILER) + +extern int ottery_valgrind_; +/** Helper: invoke the RDRAND instruction to get 4 random bytes in the output + * value. Return 1 on success, and 0 on failure. */ +#define rdrand32(x) ({ unsigned char err = 0; __asm volatile(".byte 0x0f; .byte 0xc7; .byte 0xf0; setc %1":"=a"(x), "=qm"(err) :"a"(0) :"cc"); err; }) + +/** Generate bytes using the Intel RDRAND instruction. */ +static int +ottery_get_entropy_rdrand(const struct ottery_entropy_config *cfg, + struct ottery_entropy_state *state, + uint8_t *out, size_t outlen) +{ + uint32_t up; + (void) cfg; + (void) state; + if (! (ottery_get_cpu_capabilities_() & OTTERY_CPUCAP_RAND) || ottery_valgrind_) + return OTTERY_ERR_INIT_STRONG_RNG; + while (outlen >= 4) { + if (rdrand32(up) != 1) + return OTTERY_ERR_INIT_STRONG_RNG; + memcpy (out, &up, sizeof (up)); + out += sizeof (up); + outlen -= 4; + } + + if (outlen) { + if (rdrand32(up) != 1) + return OTTERY_ERR_INIT_STRONG_RNG; + memcpy(out, &up, outlen); + } + return 0; +} + +#define ENTROPY_SOURCE_RDRAND \ + { ottery_get_entropy_rdrand, SRC(RDRAND)|DOM(CPU)|FL(FAST)|FL(STRONG) } + +#endif + diff --git a/contrib/libottery/ottery_entropy_urandom.c b/contrib/libottery/ottery_entropy_urandom.c new file mode 100644 index 0000000..9eb761b --- /dev/null +++ b/contrib/libottery/ottery_entropy_urandom.c @@ -0,0 +1,117 @@ +/* Libottery by Nick Mathewson. + + This software has been dedicated to the public domain under the CC0 + public domain dedication. + + To the extent possible under law, the person who associated CC0 with + libottery has waived all copyright and related or neighboring rights + to libottery. + + You should have received a copy of the CC0 legalcode along with this + work in doc/cc0.txt. If not, see + <http://creativecommons.org/publicdomain/zero/1.0/>. + */ + +#ifndef _WIN32 + +/** + * Read from a file into an n-byte buffer until the buffer is full or until + * we reach an error. Returns the number of bytes read. If the return + * value is less than n, an error occurred. + */ +static int +ottery_read_n_bytes_from_file_(int fd, uint8_t *out, size_t n) +{ + ssize_t r; + uint8_t *outp = out; + while (n) { + r = read(fd, outp, n); + if (r <= 0 || (size_t)r > n) + return outp - out; + outp += r; + n -= r; + } + return outp - out; +} + + +/** Generate random bytes using the unix-style /dev/urandom RNG, or another + * such device as configured in the configuration. */ +static int +ottery_get_entropy_urandom(const struct ottery_entropy_config *cfg, + struct ottery_entropy_state *state, + uint8_t *out, size_t outlen) +{ + /* On most unixes these days, you can get strong random numbers from + * /dev/urandom. + * + * That's assuming that /dev/urandom is seeded. For most applications, + * that won't be a problem. But for stuff that starts close to system + * startup, before the operating system has added any entropy to the pool, + * it can be pretty bad. + * + * You could use /dev/random instead, if you want, but that has another + * problem. It will block if the OS PRNG has received less entropy than + * it has emitted. If we assume that the OS PRNG isn't cryptographically + * weak, blocking in that case is simple overkill. + * + * It would be best if there were an alternative that blocked if the PRNG + * had _never_ been seeded. But most operating systems don't have that. + */ + int fd; + ssize_t n; + int result = 0; + const char *urandom_fname; + struct stat st; + int own_fd = 0; + int check_device = !cfg || !cfg->allow_nondev_urandom; +#ifndef O_CLOEXEC +#define O_CLOEXEC 0 +#endif + if (cfg && cfg->urandom_fd_is_set && cfg->urandom_fd >= 0) { + fd = cfg->urandom_fd; + } else { + if (cfg && cfg->urandom_fname) + urandom_fname = cfg->urandom_fname; + else + urandom_fname = "/dev/urandom"; + + fd = open(urandom_fname, O_RDONLY|O_CLOEXEC); + own_fd = 1; + if (fd < 0) + return OTTERY_ERR_INIT_STRONG_RNG; + } + if (fstat(fd, &st) < 0) { + result = OTTERY_ERR_INIT_STRONG_RNG; + goto end; + } + if (check_device) { + if (0 == (st.st_mode & S_IFCHR)) { + result = OTTERY_ERR_INIT_STRONG_RNG; + goto end; + } + + if (state) { + if (0 == state->urandom_fd_inode) { + state->urandom_fd_inode = (uint64_t) st.st_ino; + } else if ((uint64_t)st.st_ino != state->urandom_fd_inode) { + close(fd); + return OTTERY_ERR_ACCESS_STRONG_RNG; + } + } + } + + n = ottery_read_n_bytes_from_file_(fd, out, outlen); + if (n < 0 || (size_t)n != outlen) + result = OTTERY_ERR_ACCESS_STRONG_RNG; + + end: + if (own_fd) + close(fd); + return result; +} + +#define ENTROPY_SOURCE_URANDOM \ + { ottery_get_entropy_urandom, SRC(RANDOMDEV)|DOM(OS)|FL(STRONG) } + +#endif diff --git a/contrib/libottery/ottery_global.c b/contrib/libottery/ottery_global.c new file mode 100644 index 0000000..dd1efc5 --- /dev/null +++ b/contrib/libottery/ottery_global.c @@ -0,0 +1,116 @@ +/* Libottery by Nick Mathewson. + + This software has been dedicated to the public domain under the CC0 + public domain dedication. + + To the extent possible under law, the person who associated CC0 with + libottery has waived all copyright and related or neighboring rights + to libottery. + + You should have received a copy of the CC0 legalcode along with this + work in doc/cc0.txt. If not, see + <http://creativecommons.org/publicdomain/zero/1.0/>. + */ +#define OTTERY_INTERNAL +#include <stdlib.h> +#include "ottery-internal.h" +#include "ottery.h" +#include "ottery_st.h" + + +/** Flag: true iff ottery_global_state_ is initialized. */ +static int ottery_global_state_initialized_ = 0; +int ottery_valgrind_ = 0; +/** A global state to use for the ottery_* functions that don't take a + * state. */ +static struct ottery_state ottery_global_state_; + +/** Initialize ottery_global_state_ if it has not been initialize. */ +#define CHECK_INIT(rv) do { \ + if (UNLIKELY(!ottery_global_state_initialized_)) { \ + int err; \ + if ((err = ottery_init(NULL))) { \ + ottery_fatal_error_(OTTERY_ERR_FLAG_GLOBAL_PRNG_INIT|err); \ + return rv; \ + } \ + } \ +} while (0) + +int +ottery_init(const struct ottery_config *cfg) +{ + if (getenv("VALGRIND")) { + ottery_valgrind_ = 1; + } + int n = ottery_st_init(&ottery_global_state_, cfg); + if (n == 0) + ottery_global_state_initialized_ = 1; + return n; +} + +int +ottery_add_seed(const uint8_t *seed, size_t n) +{ + CHECK_INIT(0); + return ottery_st_add_seed(&ottery_global_state_, seed, n); +} + +void +ottery_wipe(void) +{ + if (ottery_global_state_initialized_) { + ottery_global_state_initialized_ = 0; + ottery_st_wipe(&ottery_global_state_); + } +} + +void +ottery_prevent_backtracking(void) +{ + CHECK_INIT(); + ottery_st_prevent_backtracking(&ottery_global_state_); +} + +void +ottery_rand_bytes(void *out, size_t n) +{ + CHECK_INIT(); + ottery_st_rand_bytes(&ottery_global_state_, out, n); +} + +unsigned +ottery_rand_unsigned(void) +{ + CHECK_INIT(0); + return ottery_st_rand_unsigned(&ottery_global_state_); +} +uint32_t +ottery_rand_uint32(void) +{ + CHECK_INIT(0); + return ottery_st_rand_uint32(&ottery_global_state_); +} +uint64_t +ottery_rand_uint64(void) +{ + CHECK_INIT(0); + return ottery_st_rand_uint64(&ottery_global_state_); +} +unsigned +ottery_rand_range(unsigned top) +{ + CHECK_INIT(0); + return ottery_st_rand_range(&ottery_global_state_, top); +} +uint64_t +ottery_rand_range64(uint64_t top) +{ + CHECK_INIT(0); + return ottery_st_rand_range64(&ottery_global_state_, top); +} + +const char *ottery_get_impl_name(void) +{ + CHECK_INIT(0); + return ottery_global_state_.prf.name; +}
\ No newline at end of file diff --git a/contrib/libottery/ottery_nolock.h b/contrib/libottery/ottery_nolock.h new file mode 100644 index 0000000..b504e11 --- /dev/null +++ b/contrib/libottery/ottery_nolock.h @@ -0,0 +1,190 @@ +/* Libottery by Nick Mathewson. + + This software has been dedicated to the public domain under the CC0 + public domain dedication. + + To the extent possible under law, the person who associated CC0 with + libottery has waived all copyright and related or neighboring rights + to libottery. + + You should have received a copy of the CC0 legalcode along with this + work in doc/cc0.txt. If not, see + <http://creativecommons.org/publicdomain/zero/1.0/>. + */ +#ifndef OTTERY_NOLOCK_H_HEADER_INCLUDED_ +#define OTTERY_NOLOCK_H_HEADER_INCLUDED_ +#include <stdint.h> +#include <sys/types.h> + +#ifdef __cplusplus +extern "C" { +#endif + +#include "ottery_common.h" + +/** @file */ + +struct ottery_config; +struct ottery_state_nolock; + +/** Size reserved for struct ottery_state_nolock */ +#define OTTERY_STATE_NOLOCK_DUMMY_SIZE_ 1536 + +#ifndef OTTERY_INTERNAL +/** + * The state for a non-thread-safe libottery PRNG + * + * Like struct ottery_state, but this structure (and its associated functions) + * are not thread safe. If you try to use this structure in more than one + * thread at a time, your program's behavior will be undefined. It might + * crash. It might insecurely give the same random sequence to multiple + * threads. It might fail in strange ways that you'd never predict. + * + * An ottery_state_nolock structure is constucted with ottery_st_init(). It + * MUST be aligned on a 16-byte boundary. + * + * You may not use an ottery_state_nolock structure with any other function + * before you have first initialized it with ottery_st_init_nolock(). + * + * The contents of this structure are opaque; The definition here is + * defined to be large enough so that programs that allocate it will get + * more than enough room. + */ +struct __attribute__((aligned(16))) ottery_state_nolock { + /** Nothing to see here */ + uint8_t dummy_[OTTERY_STATE_NOLOCK_DUMMY_SIZE_]; +}; +#endif + +/** + * Get the minimal size for allocating an ottery_state_nolock. + * + * sizeof(ottery_state_nolock) will give an overestimate to allow binary + * compatibility with future versions of libottery. Use this function instead + * to get the minimal number of bytes to allocate. + * + * @return The minimal number of bytes to use when allocating an + * ottery_state_nolock structure. + */ +size_t ottery_get_sizeof_state_nolock(void); + +/** + * Initialize an ottery_state_nolock structure. + * + * You must call this function on any ottery_state_nolock structure before + * calling any other functions on it. + * + * @param st The ottery_state_nolock to initialize. + * @param cfg Either NULL, or an ottery_config structure that has been + * initialized with ottery_config_init(). + * @return Zero on success, or one of the OTTERY_ERR_* error codes on failure. + */ +int ottery_st_init_nolock(struct ottery_state_nolock *st, const struct ottery_config *cfg); + +/** + * Add more entropy to an ottery_state_nolock structure. + * + * Calling this function should be needless, if you trust your operating + * system's random number generator and entropy extraction features. You + * would want to use this function if you think the operating system's random + * number generator might be inadequate, and you want to add more entropy from + * EGD or something. + * + * You might also want to call this function if your belief system says that + * it's useful to periodically add more raw entropy to a well-seeded + * cryptographically strong PRNG. + * + * @param st The state which will receive more entropy. + * @param seed Bytes to add to the state. + * @param n The number of bytes to add. + * @return Zero on success, or one of the OTTERY_ERR_* error codes on failure. + */ +int ottery_st_add_seed_nolock(struct ottery_state_nolock *st, const uint8_t *seed, size_t n); + +/** + * Destroy an ottery_state_nolock structure and release any resources that it + * might hold. + * + * Ordinarily, you would want to call this at exit, or before freeing an + * ottery_state_nolock + * + * @param st The state to wipe. + */ +void ottery_st_wipe_nolock(struct ottery_state_nolock *st); + +/** + * Explicitly prevent backtracking attacks. (Usually needless). + * + * Once this function has been called, an attacker who compromises the state + * later on will not be able to recover bytes that have previously been + * returned by any of the ottery_st_rand_*_nolock functions. + * + * You should not usually need to call this function: Libottery provides + * backtracking resistance by default, so unless you have manually recompiled + * with the OTTERY_NO_CLEAR_AFTER_YIELD option, this function isn't + * necessary and has no effect. Even *with* OTTERY_NO_CLEAR_AFTER_YIELD, + * this function isn't necessary in ordinary operation: the libottery state is + * implicitly "stirred" every 1k or so. + * + * @param st The state to stir. + */ +void ottery_st_prevent_backtracking_nolock(struct ottery_state_nolock *st); + +/** + * Use an ottery_state_nolock structure to fill a buffer with random bytes. + * + * @param st The state structure to use. + * @param buf The buffer to fill. + * @param n The number of bytes to write. + */ +void ottery_st_rand_bytes_nolock(struct ottery_state_nolock *st, void *buf, size_t n); +/** + * Use an ottery_state_nolock structure to generate a random number of type unsigned. + * + * @param st The state structure to use. + * @return A random number between 0 and UINT_MAX included, + * chosen uniformly. + */ +unsigned ottery_st_rand_unsigned_nolock(struct ottery_state_nolock *st); +/** + * Use an ottery_state_nolock structure to generate a random number of type uint32_t. + * + * @param st The state structure to use. + * @return A random number between 0 and UINT32_MAX included, + * chosen uniformly. + */ +uint32_t ottery_st_rand_uint32_nolock(struct ottery_state_nolock *st); +/** + * Use an ottery_state_nolock structure to generate a random number of type uint64_t. + * + * @param st The state structure to use. + * @return A random number between 0 and UINT64_MAX included, + * chosen uniformly. + */ +uint64_t ottery_st_rand_uint64_nolock(struct ottery_state_nolock *st); +/** + * Use an ottery_state_nolock structure to generate a random number of type unsigned + * in a given range. + * + * @param st The state structure to use. + * @param top The upper bound of the range (inclusive). + * @return A random number no larger than top, and no less than 0, + * chosen uniformly. + */ +unsigned ottery_st_rand_range_nolock(struct ottery_state_nolock *st, unsigned top); +/** + * Use an ottery_state_nolock structure to generate a random number of type uint64_t + * in a given range. + * + * @param st The state structure to use. + * @param top The upper bound of the range (inclusive). + * @return A random number no larger than top, and no less than 0, + * chosen uniformly. + */ +uint64_t ottery_st_rand_range64_nolock(struct ottery_state_nolock *st, uint64_t top); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/contrib/libottery/ottery_st.h b/contrib/libottery/ottery_st.h new file mode 100644 index 0000000..38955cb --- /dev/null +++ b/contrib/libottery/ottery_st.h @@ -0,0 +1,184 @@ +/* Libottery by Nick Mathewson. + + This software has been dedicated to the public domain under the CC0 + public domain dedication. + + To the extent possible under law, the person who associated CC0 with + libottery has waived all copyright and related or neighboring rights + to libottery. + + You should have received a copy of the CC0 legalcode along with this + work in doc/cc0.txt. If not, see + <http://creativecommons.org/publicdomain/zero/1.0/>. + */ +#ifndef OTTERY_ST_H_HEADER_INCLUDED_ +#define OTTERY_ST_H_HEADER_INCLUDED_ +#include <stdint.h> +#include <sys/types.h> + +#ifdef __cplusplus +extern "C" { +#endif + +#include "ottery_common.h" + +/** @file */ + +struct ottery_config; +struct ottery_state; + +/** Size reserved for struct ottery_state */ +#define OTTERY_STATE_DUMMY_SIZE_ 1536 + +#ifndef OTTERY_INTERNAL +/** + * The state for a libottery PRNG. + * + * An ottery_state structure is constucted with ottery_st_init(). It MUST be + * aligned on a 16-byte boundary. + * + * You may not use an ottery_state structure with any other function before + * you have first initialized it with ottery_st_init(). + * + * The contents of this structure are opaque; The definition here is + * defined to be large enough so that programs that allocate it will get + * more than enough room. + */ +struct __attribute__((aligned(16))) ottery_state { + /** Nothing to see here */ + uint8_t dummy_[OTTERY_STATE_DUMMY_SIZE_]; +}; +#endif + +/** + * Get the minimal size for allocating an ottery_state. + * + * sizeof(ottery_state) will give an overestimate to allow binary + * compatibility with future versions of libottery. Use this function instead + * to get the minimal number of bytes to allocate. + * + * @return The minimal number of bytes to use when allocating an + * ottery_state structure. + */ +size_t ottery_get_sizeof_state(void); + +/** + * Initialize an ottery_state structure. + * + * You must call this function on any ottery_state structure before + * calling any other functions on it. + * + * @param st The ottery_state to initialize. + * @param cfg Either NULL, or an ottery_config structure that has been + * initialized with ottery_config_init(). + * @return Zero on success, or one of the OTTERY_ERR_* error codes on failure. + */ +int ottery_st_init(struct ottery_state *st, const struct ottery_config *cfg); + +/** + * Add more entropy to an ottery_state structure. + * + * Calling this function should be needless, if you trust your operating + * system's random number generator and entropy extraction features. You + * would want to use this function if you think the operating system's random + * number generator might be inadequate, and you want to add more entropy from + * EGD or something. + * + * You might also want to call this function if your belief system says that + * it's useful to periodically add more raw entropy to a well-seeded + * cryptographically strong PRNG. + * + * @param st The state which will receive more entropy. + * @param seed Bytes to add to the state. + * @param n The number of bytes to add. + * @return Zero on success, or one of the OTTERY_ERR_* error codes on failure. + */ +int ottery_st_add_seed(struct ottery_state *st, const uint8_t *seed, size_t n); + +/** + * Destroy an ottery_state structure and release any resources that it might + * hold. + * + * Ordinarily, you would want to call this at exit, or before freeing an + * ottery_state + * + * @param st The state to wipe. + */ +void ottery_st_wipe(struct ottery_state *st); + +/** + * Explicitly prevent backtracking attacks. (Usually needless). + * + * Once this function has been called, an attacker who compromises the state + * later on will not be able to recover bytes that have previously been + * returned by any of the ottery_st_rand_* functions. + * + * You should not usually need to call this function: Libottery provides + * backtracking resistance by default, so unless you have manually recompiled + * with the OTTERY_NO_CLEAR_AFTER_YIELD option, this function isn't + * necessary and has no effect. Even *with* OTTERY_NO_CLEAR_AFTER_YIELD, + * this function isn't necessary in ordinary operation: the libottery state is + * implicitly "stirred" every 1k or so. + * + * @param st The state to stir. + */ +void ottery_st_prevent_backtracking(struct ottery_state *st); + +/** + * Use an ottery_state structure to fill a buffer with random bytes. + * + * @param st The state structure to use. + * @param buf The buffer to fill. + * @param n The number of bytes to write. + */ +void ottery_st_rand_bytes(struct ottery_state *st, void *buf, size_t n); +/** + * Use an ottery_state structure to generate a random number of type unsigned. + * + * @param st The state structure to use. + * @return A random number between 0 and UINT_MAX included, + * chosen uniformly. + */ +unsigned ottery_st_rand_unsigned(struct ottery_state *st); +/** + * Use an ottery_state structure to generate a random number of type uint32_t. + * + * @param st The state structure to use. + * @return A random number between 0 and UINT32_MAX included, + * chosen uniformly. + */ +uint32_t ottery_st_rand_uint32(struct ottery_state *st); +/** + * Use an ottery_state structure to generate a random number of type uint64_t. + * + * @param st The state structure to use. + * @return A random number between 0 and UINT64_MAX included, + * chosen uniformly. + */ +uint64_t ottery_st_rand_uint64(struct ottery_state *st); +/** + * Use an ottery_state structure to generate a random number of type unsigned + * in a given range. + * + * @param st The state structure to use. + * @param top The upper bound of the range (inclusive). + * @return A random number no larger than top, and no less than 0, + * chosen uniformly. + */ +unsigned ottery_st_rand_range(struct ottery_state *st, unsigned top); +/** + * Use an ottery_state structure to generate a random number of type uint64_t + * in a given range. + * + * @param st The state structure to use. + * @param top The upper bound of the range (inclusive). + * @return A random number no larger than top, and no less than 0, + * chosen uniformly. + */ +uint64_t ottery_st_rand_range64(struct ottery_state *st, uint64_t top); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/contrib/libottery/ottery_version.h.in b/contrib/libottery/ottery_version.h.in new file mode 100644 index 0000000..1b6a244 --- /dev/null +++ b/contrib/libottery/ottery_version.h.in @@ -0,0 +1,28 @@ +/* Libottery by Nick Mathewson. + + This software has been dedicated to the public domain under the CC0 + public domain dedication. + + To the extent possible under law, the person who associated CC0 with + libottery has waived all copyright and related or neighboring rights + to libottery. + + You should have received a copy of the CC0 legalcode along with this + work in doc/cc0.txt. If not, see + <http://creativecommons.org/publicdomain/zero/1.0/>. + */ +#ifndef OTTERY_VERSION_H_HEADER_INCLUDED_ +#define OTTERY_VERSION_H_HEADER_INCLUDED_ + +/** + * Version number for Libottery. The first three bytes are the major number, + * minor number, and patch-level respectively. The final byte is 0 for a + * released version, and nonzero otherwise. + */ +#undef OTTERY_VERSION +/** + * Human-readable string representing the Libottery version. + */ +#undef OTTERY_VERSION_STRING + +#endif |