Browse Source

Use libottery for secure random numbers.

Libottery itself is hosted here:
https://github.com/nmathewson/libottery

This import is a rough adoptation of libottery to use it for secure
random numbers in rspamd when needed (and in DNS resolver specifically).
This import makes the internal chacha20 code useless, hence it is
removed now.
tags/0.7.0
Vsevolod Stakhov 10 years ago
parent
commit
ff62d93b0e

+ 3
- 1
CMakeLists.txt View File

@@ -877,7 +877,8 @@ INCLUDE_DIRECTORIES("${CMAKE_SOURCE_DIR}/src"
"${CMAKE_BINARY_DIR}/src"
"${CMAKE_SOURCE_DIR}/src/ucl/include"
"${CMAKE_SOURCE_DIR}/contrib/uthash"
"${CMAKE_SOURCE_DIR}/contrib/http-parser")
"${CMAKE_SOURCE_DIR}/contrib/http-parser"
"${CMAKE_SOURCE_DIR}/contrib/libottery")

SET(RSPAMDSRC src/modules.c
src/controller.c
@@ -919,6 +920,7 @@ ADD_SUBDIRECTORY(src/json)
ADD_SUBDIRECTORY(src/cdb)
ADD_SUBDIRECTORY(src/ucl)
ADD_SUBDIRECTORY(contrib/http-parser)
ADD_SUBDIRECTORY(contrib/libottery)
ADD_SUBDIRECTORY(src)
ADD_SUBDIRECTORY(src/client)


+ 15
- 0
contrib/libottery/CMakeLists.txt View File

@@ -0,0 +1,15 @@
SET(OTTERYSRC chacha_merged.c
ottery.c
ottery_cpuinfo.c
ottery_entropy.c
ottery_global.c)

ADD_LIBRARY(rspamd-ottery ${LINK_TYPE} ${OTTERYSRC})
SET_TARGET_PROPERTIES(rspamd-ottery PROPERTIES VERSION ${RSPAMD_VERSION})
SET_TARGET_PROPERTIES(rspamd-ottery PROPERTIES COMPILE_FLAGS "-DRSPAMD_LIB")

IF(NO_SHARED MATCHES "OFF")
INSTALL(TARGETS rspamd-ottery
LIBRARY DESTINATION ${LIBDIR}
PUBLIC_HEADER DESTINATION ${INCLUDEDIR})
ENDIF(NO_SHARED MATCHES "OFF")

+ 314
- 0
contrib/libottery/Makefile View File

@@ -0,0 +1,314 @@
# CMAKE generated file: DO NOT EDIT!
# Generated by "Unix Makefiles" Generator, CMake Version 2.8

# Default target executed when no arguments are given to make.
default_target: all
.PHONY : default_target

#=============================================================================
# Special targets provided by cmake.

# Disable implicit rules so canonical targets will work.
.SUFFIXES:

# Remove some rules from gmake that .SUFFIXES does not remove.
SUFFIXES =

.SUFFIXES: .hpux_make_needs_suffix_list

# Suppress display of executed commands.
$(VERBOSE).SILENT:

# A target that is always out of date.
cmake_force:
.PHONY : cmake_force

#=============================================================================
# Set environment variables for the build.

# The shell in which to execute make rules.
SHELL = /bin/sh

# The CMake executable.
CMAKE_COMMAND = /usr/bin/cmake

# The command to remove a file.
RM = /usr/bin/cmake -E remove -f

# The top-level source directory on which CMake was run.
CMAKE_SOURCE_DIR = /home/vs374/rspamd

# The top-level build directory on which CMake was run.
CMAKE_BINARY_DIR = /home/vs374/rspamd

#=============================================================================
# Targets provided globally by CMake.

# Special rule for the target edit_cache
edit_cache:
@$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --cyan "Running interactive CMake command-line interface..."
/usr/bin/cmake -i .
.PHONY : edit_cache

# Special rule for the target edit_cache
edit_cache/fast: edit_cache
.PHONY : edit_cache/fast

# Special rule for the target install
install: preinstall
@$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --cyan "Install the project..."
/usr/bin/cmake -P cmake_install.cmake
.PHONY : install

# Special rule for the target install
install/fast: preinstall/fast
@$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --cyan "Install the project..."
/usr/bin/cmake -P cmake_install.cmake
.PHONY : install/fast

# Special rule for the target install/local
install/local: preinstall
@$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --cyan "Installing only the local directory..."
/usr/bin/cmake -DCMAKE_INSTALL_LOCAL_ONLY=1 -P cmake_install.cmake
.PHONY : install/local

# Special rule for the target install/local
install/local/fast: install/local
.PHONY : install/local/fast

# Special rule for the target install/strip
install/strip: preinstall
@$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --cyan "Installing the project stripped..."
/usr/bin/cmake -DCMAKE_INSTALL_DO_STRIP=1 -P cmake_install.cmake
.PHONY : install/strip

# Special rule for the target install/strip
install/strip/fast: install/strip
.PHONY : install/strip/fast

# Special rule for the target list_install_components
list_install_components:
@$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --cyan "Available install components are: \"Unspecified\""
.PHONY : list_install_components

# Special rule for the target list_install_components
list_install_components/fast: list_install_components
.PHONY : list_install_components/fast

# Special rule for the target rebuild_cache
rebuild_cache:
@$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --cyan "Running CMake to regenerate build system..."
/usr/bin/cmake -H$(CMAKE_SOURCE_DIR) -B$(CMAKE_BINARY_DIR)
.PHONY : rebuild_cache

# Special rule for the target rebuild_cache
rebuild_cache/fast: rebuild_cache
.PHONY : rebuild_cache/fast

# The main all target
all: cmake_check_build_system
cd /home/vs374/rspamd && $(CMAKE_COMMAND) -E cmake_progress_start /home/vs374/rspamd/CMakeFiles /home/vs374/rspamd/contrib/libottery/CMakeFiles/progress.marks
cd /home/vs374/rspamd && $(MAKE) -f CMakeFiles/Makefile2 contrib/libottery/all
$(CMAKE_COMMAND) -E cmake_progress_start /home/vs374/rspamd/CMakeFiles 0
.PHONY : all

# The main clean target
clean:
cd /home/vs374/rspamd && $(MAKE) -f CMakeFiles/Makefile2 contrib/libottery/clean
.PHONY : clean

# The main clean target
clean/fast: clean
.PHONY : clean/fast

# Prepare targets for installation.
preinstall: all
cd /home/vs374/rspamd && $(MAKE) -f CMakeFiles/Makefile2 contrib/libottery/preinstall
.PHONY : preinstall

# Prepare targets for installation.
preinstall/fast:
cd /home/vs374/rspamd && $(MAKE) -f CMakeFiles/Makefile2 contrib/libottery/preinstall
.PHONY : preinstall/fast

# clear depends
depend:
cd /home/vs374/rspamd && $(CMAKE_COMMAND) -H$(CMAKE_SOURCE_DIR) -B$(CMAKE_BINARY_DIR) --check-build-system CMakeFiles/Makefile.cmake 1
.PHONY : depend

# Convenience name for target.
contrib/libottery/CMakeFiles/rspamd-ottery.dir/rule:
cd /home/vs374/rspamd && $(MAKE) -f CMakeFiles/Makefile2 contrib/libottery/CMakeFiles/rspamd-ottery.dir/rule
.PHONY : contrib/libottery/CMakeFiles/rspamd-ottery.dir/rule

# Convenience name for target.
rspamd-ottery: contrib/libottery/CMakeFiles/rspamd-ottery.dir/rule
.PHONY : rspamd-ottery

# fast build rule for target.
rspamd-ottery/fast:
cd /home/vs374/rspamd && $(MAKE) -f contrib/libottery/CMakeFiles/rspamd-ottery.dir/build.make contrib/libottery/CMakeFiles/rspamd-ottery.dir/build
.PHONY : rspamd-ottery/fast

chacha_merged.o: chacha_merged.c.o
.PHONY : chacha_merged.o

# target to build an object file
chacha_merged.c.o:
cd /home/vs374/rspamd && $(MAKE) -f contrib/libottery/CMakeFiles/rspamd-ottery.dir/build.make contrib/libottery/CMakeFiles/rspamd-ottery.dir/chacha_merged.c.o
.PHONY : chacha_merged.c.o

chacha_merged.i: chacha_merged.c.i
.PHONY : chacha_merged.i

# target to preprocess a source file
chacha_merged.c.i:
cd /home/vs374/rspamd && $(MAKE) -f contrib/libottery/CMakeFiles/rspamd-ottery.dir/build.make contrib/libottery/CMakeFiles/rspamd-ottery.dir/chacha_merged.c.i
.PHONY : chacha_merged.c.i

chacha_merged.s: chacha_merged.c.s
.PHONY : chacha_merged.s

# target to generate assembly for a file
chacha_merged.c.s:
cd /home/vs374/rspamd && $(MAKE) -f contrib/libottery/CMakeFiles/rspamd-ottery.dir/build.make contrib/libottery/CMakeFiles/rspamd-ottery.dir/chacha_merged.c.s
.PHONY : chacha_merged.c.s

ottery.o: ottery.c.o
.PHONY : ottery.o

# target to build an object file
ottery.c.o:
cd /home/vs374/rspamd && $(MAKE) -f contrib/libottery/CMakeFiles/rspamd-ottery.dir/build.make contrib/libottery/CMakeFiles/rspamd-ottery.dir/ottery.c.o
.PHONY : ottery.c.o

ottery.i: ottery.c.i
.PHONY : ottery.i

# target to preprocess a source file
ottery.c.i:
cd /home/vs374/rspamd && $(MAKE) -f contrib/libottery/CMakeFiles/rspamd-ottery.dir/build.make contrib/libottery/CMakeFiles/rspamd-ottery.dir/ottery.c.i
.PHONY : ottery.c.i

ottery.s: ottery.c.s
.PHONY : ottery.s

# target to generate assembly for a file
ottery.c.s:
cd /home/vs374/rspamd && $(MAKE) -f contrib/libottery/CMakeFiles/rspamd-ottery.dir/build.make contrib/libottery/CMakeFiles/rspamd-ottery.dir/ottery.c.s
.PHONY : ottery.c.s

ottery_cpuinfo.o: ottery_cpuinfo.c.o
.PHONY : ottery_cpuinfo.o

# target to build an object file
ottery_cpuinfo.c.o:
cd /home/vs374/rspamd && $(MAKE) -f contrib/libottery/CMakeFiles/rspamd-ottery.dir/build.make contrib/libottery/CMakeFiles/rspamd-ottery.dir/ottery_cpuinfo.c.o
.PHONY : ottery_cpuinfo.c.o

ottery_cpuinfo.i: ottery_cpuinfo.c.i
.PHONY : ottery_cpuinfo.i

# target to preprocess a source file
ottery_cpuinfo.c.i:
cd /home/vs374/rspamd && $(MAKE) -f contrib/libottery/CMakeFiles/rspamd-ottery.dir/build.make contrib/libottery/CMakeFiles/rspamd-ottery.dir/ottery_cpuinfo.c.i
.PHONY : ottery_cpuinfo.c.i

ottery_cpuinfo.s: ottery_cpuinfo.c.s
.PHONY : ottery_cpuinfo.s

# target to generate assembly for a file
ottery_cpuinfo.c.s:
cd /home/vs374/rspamd && $(MAKE) -f contrib/libottery/CMakeFiles/rspamd-ottery.dir/build.make contrib/libottery/CMakeFiles/rspamd-ottery.dir/ottery_cpuinfo.c.s
.PHONY : ottery_cpuinfo.c.s

ottery_entropy.o: ottery_entropy.c.o
.PHONY : ottery_entropy.o

# target to build an object file
ottery_entropy.c.o:
cd /home/vs374/rspamd && $(MAKE) -f contrib/libottery/CMakeFiles/rspamd-ottery.dir/build.make contrib/libottery/CMakeFiles/rspamd-ottery.dir/ottery_entropy.c.o
.PHONY : ottery_entropy.c.o

ottery_entropy.i: ottery_entropy.c.i
.PHONY : ottery_entropy.i

# target to preprocess a source file
ottery_entropy.c.i:
cd /home/vs374/rspamd && $(MAKE) -f contrib/libottery/CMakeFiles/rspamd-ottery.dir/build.make contrib/libottery/CMakeFiles/rspamd-ottery.dir/ottery_entropy.c.i
.PHONY : ottery_entropy.c.i

ottery_entropy.s: ottery_entropy.c.s
.PHONY : ottery_entropy.s

# target to generate assembly for a file
ottery_entropy.c.s:
cd /home/vs374/rspamd && $(MAKE) -f contrib/libottery/CMakeFiles/rspamd-ottery.dir/build.make contrib/libottery/CMakeFiles/rspamd-ottery.dir/ottery_entropy.c.s
.PHONY : ottery_entropy.c.s

ottery_global.o: ottery_global.c.o
.PHONY : ottery_global.o

# target to build an object file
ottery_global.c.o:
cd /home/vs374/rspamd && $(MAKE) -f contrib/libottery/CMakeFiles/rspamd-ottery.dir/build.make contrib/libottery/CMakeFiles/rspamd-ottery.dir/ottery_global.c.o
.PHONY : ottery_global.c.o

ottery_global.i: ottery_global.c.i
.PHONY : ottery_global.i

# target to preprocess a source file
ottery_global.c.i:
cd /home/vs374/rspamd && $(MAKE) -f contrib/libottery/CMakeFiles/rspamd-ottery.dir/build.make contrib/libottery/CMakeFiles/rspamd-ottery.dir/ottery_global.c.i
.PHONY : ottery_global.c.i

ottery_global.s: ottery_global.c.s
.PHONY : ottery_global.s

# target to generate assembly for a file
ottery_global.c.s:
cd /home/vs374/rspamd && $(MAKE) -f contrib/libottery/CMakeFiles/rspamd-ottery.dir/build.make contrib/libottery/CMakeFiles/rspamd-ottery.dir/ottery_global.c.s
.PHONY : ottery_global.c.s

# Help Target
help:
@echo "The following are some of the valid targets for this Makefile:"
@echo "... all (the default if no target is provided)"
@echo "... clean"
@echo "... depend"
@echo "... edit_cache"
@echo "... install"
@echo "... install/local"
@echo "... install/strip"
@echo "... list_install_components"
@echo "... rebuild_cache"
@echo "... rspamd-ottery"
@echo "... chacha_merged.o"
@echo "... chacha_merged.i"
@echo "... chacha_merged.s"
@echo "... ottery.o"
@echo "... ottery.i"
@echo "... ottery.s"
@echo "... ottery_cpuinfo.o"
@echo "... ottery_cpuinfo.i"
@echo "... ottery_cpuinfo.s"
@echo "... ottery_entropy.o"
@echo "... ottery_entropy.i"
@echo "... ottery_entropy.s"
@echo "... ottery_global.o"
@echo "... ottery_global.i"
@echo "... ottery_global.s"
.PHONY : help



#=============================================================================
# Special targets to cleanup operation of make.

# Special rule to run CMake to check the build system integrity.
# No rule that depends on this can have commands that come from listfiles
# because they might be regenerated.
cmake_check_build_system:
cd /home/vs374/rspamd && $(CMAKE_COMMAND) -H$(CMAKE_SOURCE_DIR) -B$(CMAKE_BINARY_DIR) --check-build-system CMakeFiles/Makefile.cmake 0
.PHONY : cmake_check_build_system


+ 320
- 0
contrib/libottery/chacha_krovetz.c View File

@@ -0,0 +1,320 @@
/*
* This code is based on Ted Krovetz's 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 (partial) 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 implementation for 16-byte vectors by Ted Krovetz (ted@krovetz.net).
* Assumes 32-bit int, 64-bit long long. Public domain. Modified: 2012.07.26.
* Chacha is an improvement on the stream cipher Salsa, described at
* http://cr.yp.to/papers.html#chacha
*/
#include <string.h>
#include <assert.h>
#include "ottery-internal.h"

/* Architecture-neutral way to specify 16-byte vector of ints */
typedef unsigned vec __attribute__ ((vector_size (16)));

/* This implementation is designed for Neon, SSE and AltiVec machines. The
* following specify how to do certain vector operations efficiently on
* each architecture, using intrinsics.
* This implementation supports parallel processing of multiple blocks,
* including potentially using general-purpose registers.
*/
#if __ARM_NEON__
#include <arm_neon.h>
#define GPR_TOO 1
#define VBPI 2
#define ONE (vec)vsetq_lane_u32(1,vdupq_n_u32(0),0)
#define NONCE(ctr,p) (vec)vcombine_u32(vcreate_u32(ctr),vcreate_u32(*(uint64_t *)p))
#define ROTV1(x) (vec)vextq_u32((uint32x4_t)x,(uint32x4_t)x,1)
#define ROTV2(x) (vec)vextq_u32((uint32x4_t)x,(uint32x4_t)x,2)
#define ROTV3(x) (vec)vextq_u32((uint32x4_t)x,(uint32x4_t)x,3)
#define ROTW16(x) (vec)vrev32q_u16((uint16x8_t)x)
#if __clang__
#define ROTW7(x) (x << ((vec){ 7, 7, 7, 7})) ^ (x >> ((vec){25,25,25,25}))
#define ROTW8(x) (x << ((vec){ 8, 8, 8, 8})) ^ (x >> ((vec){24,24,24,24}))
#define ROTW12(x) (x << ((vec){12,12,12,12})) ^ (x >> ((vec){20,20,20,20}))
#else
#define ROTW7(x) (vec)vsriq_n_u32(vshlq_n_u32((uint32x4_t)x,7),(uint32x4_t)x,25)
#define ROTW8(x) (vec)vsriq_n_u32(vshlq_n_u32((uint32x4_t)x,8),(uint32x4_t)x,24)
#define ROTW12(x) (vec)vsriq_n_u32(vshlq_n_u32((uint32x4_t)x,12),(uint32x4_t)x,20)
#endif
#elif __ALTIVEC__
#include <altivec.h>
#define GPR_TOO 1
#define VBPI 3
#define ONE ((vec){1,0,0,0})
#define NONCE(ctr,p) vec_sro(*(vec *)p, (vector char)(vec){0,0,0,8*8})+((vec){((ctr)&0xffffffff), (ctr)>>32, 0, 0})
#error "Don't use this code till it can be tested on altivec"
#define REVW_BE(x) __builtin_bswap32(x)
#define REVV_BE(x) vec_perm(x,x,(vector char){3,2,1,0,7,6,5,4,11,10,9,8,15,14,13,12})
#define ROTV1(x) vec_perm(x,x,(vector char){4,5,6,7,8,9,10,11,12,13,14,15,0,1,2,3})
#define ROTV2(x) vec_perm(x,x,(vector char){8,9,10,11,12,13,14,15,0,1,2,3,4,5,6,7})
#define ROTV3(x) vec_perm(x,x,(vector char){12,13,14,15,0,1,2,3,4,5,6,7,8,9,10,11})
#define ROTW7(x) vec_rl(x,vec_splat_u32(7))
#define ROTW8(x) vec_rl(x,vec_splat_u32(8))
#define ROTW12(x) vec_rl(x,vec_splat_u32(12))
#define ROTW16(x) vec_rl(x,vec_splat_u32(-16)) /* trick to get 16 */
#elif __SSE2__
#include <emmintrin.h>
#define GPR_TOO 0
#if __clang__
#define VBPI 4
#else
#define VBPI 3
#endif
#define ONE (vec)_mm_set_epi32(0,0,0,1)
#define NONCE(ctr,p) (vec)(_mm_slli_si128(_mm_loadl_epi64((__m128i *)(p)),8)+_mm_set_epi64x(0,ctr))
#define ROTV1(x) (vec)_mm_shuffle_epi32((__m128i)x,_MM_SHUFFLE(0,3,2,1))
#define ROTV2(x) (vec)_mm_shuffle_epi32((__m128i)x,_MM_SHUFFLE(1,0,3,2))
#define ROTV3(x) (vec)_mm_shuffle_epi32((__m128i)x,_MM_SHUFFLE(2,1,0,3))
#define ROTW7(x) (vec)(_mm_slli_epi32((__m128i)x, 7) ^ _mm_srli_epi32((__m128i)x,25))
#define ROTW12(x) (vec)(_mm_slli_epi32((__m128i)x,12) ^ _mm_srli_epi32((__m128i)x,20))
#if __SSSE3__
#include <tmmintrin.h>
#define ROTW8(x) (vec)_mm_shuffle_epi8((__m128i)x,_mm_set_epi8(14,13,12,15,10,9,8,11,6,5,4,7,2,1,0,3))
#define ROTW16(x) (vec)_mm_shuffle_epi8((__m128i)x,_mm_set_epi8(13,12,15,14,9,8,11,10,5,4,7,6,1,0,3,2))
#else
#define ROTW8(x) (vec)(_mm_slli_epi32((__m128i)x, 8) ^ _mm_srli_epi32((__m128i)x,24))
#define ROTW16(x) (vec)(_mm_slli_epi32((__m128i)x,16) ^ _mm_srli_epi32((__m128i)x,16))
#endif
#else
#error -- Implementation supports only machines with neon, altivec or SSE2
#endif

#ifndef REVV_BE
#define REVV_BE(x) (x)
#endif

#ifndef REVW_BE
#define REVW_BE(x) (x)
#endif

#define BPI (VBPI + GPR_TOO) /* Blocks computed per loop iteration */

#define DQROUND_VECTORS(a,b,c,d) \
a += b; d ^= a; d = ROTW16(d); \
c += d; b ^= c; b = ROTW12(b); \
a += b; d ^= a; d = ROTW8(d); \
c += d; b ^= c; b = ROTW7(b); \
b = ROTV1(b); c = ROTV2(c); d = ROTV3(d); \
a += b; d ^= a; d = ROTW16(d); \
c += d; b ^= c; b = ROTW12(b); \
a += b; d ^= a; d = ROTW8(d); \
c += d; b ^= c; b = ROTW7(b); \
b = ROTV3(b); c = ROTV2(c); d = ROTV1(d);

#define QROUND_WORDS(a,b,c,d) \
a = a+b; d ^= a; d = d<<16 | d>>16; \
c = c+d; b ^= c; b = b<<12 | b>>20; \
a = a+b; d ^= a; d = d<< 8 | d>>24; \
c = c+d; b ^= c; b = b<< 7 | b>>25;

#define WRITE(op, d, v0, v1, v2, v3) \
*(vec *)(op + d + 0) = REVV_BE(v0); \
*(vec *)(op + d + 4) = REVV_BE(v1); \
*(vec *)(op + d + 8) = REVV_BE(v2); \
*(vec *)(op + d + 12) = REVV_BE(v3);

struct chacha_state_krovetz {
__attribute__ ((aligned (16))) uint8_t key[32];
__attribute__ ((aligned (16))) uint8_t nonce[8];
};

#define LOOP_ITERATIONS 4

static inline int
ottery_blocks_chacha_krovetz(
const int chacha_rounds,
uint8_t *out,
uint32_t block_idx,
struct chacha_state_krovetz *st)
__attribute__((always_inline));

/** Generates 64 * BPI * LOOP_ITERATIONS bytes of output using the key and
* nonce in st and the counter in block_idx, and store them in out.
*/
static inline int
ottery_blocks_chacha_krovetz(
const int chacha_rounds,
uint8_t *out,
uint32_t block_idx,
struct chacha_state_krovetz *st)
/* Assumes all pointers are aligned properly for vector reads */
{
const unsigned char *k = st->key;
const unsigned char *n = st->nonce;
unsigned i, j, *op=(unsigned *)out, *kp, *np;
__attribute__ ((aligned (16))) unsigned chacha_const[] =
{0x61707865,0x3320646E,0x79622D32,0x6B206574};
#if ( __ARM_NEON__ || __SSE2__)
kp = (unsigned *)k;
np = (unsigned *)n;
#else
__attribute__ ((aligned (16))) unsigned key[8], nonce[2];
((vec *)key)[0] = REVV_BE(((vec *)k)[0]);
((vec *)key)[1] = REVV_BE(((vec *)k)[1]);
nonce[0] = REVW_BE(((unsigned *)n)[0]);
nonce[1] = REVW_BE(((unsigned *)n)[1]);
kp = (unsigned *)key;
np = (unsigned *)nonce;
#endif
vec s0 = *(vec *)chacha_const;
vec s1 = ((vec *)kp)[0];
vec s2 = ((vec *)kp)[1];
vec s3 = NONCE(block_idx, np);
for (j = 0; j < LOOP_ITERATIONS; ++j) {
vec v0,v1,v2,v3,v4,v5,v6,v7;
v4 = v0 = s0; v5 = v1 = s1; v6 = v2 = s2; v3 = s3;
v7 = v3 + ONE;
#if VBPI > 2
vec v8,v9,v10,v11;
v8 = v4; v9 = v5; v10 = v6;
v11 = v7 + ONE;
#endif
#if VBPI > 3
vec v12,v13,v14,v15;
v12 = v8; v13 = v9; v14 = v10;
v15 = v11 + ONE;
#endif
#if GPR_TOO
register unsigned x0, x1, x2, x3, x4, x5, x6, x7, x8,
x9, x10, x11, x12, x13, x14, x15;
x0 = chacha_const[0]; x1 = chacha_const[1];
x2 = chacha_const[2]; x3 = chacha_const[3];
x4 = kp[0]; x5 = kp[1]; x6 = kp[2]; x7 = kp[3];
x8 = kp[4]; x9 = kp[5]; x10 = kp[6]; x11 = kp[7];
const uint64_t x_ctr = block_idx + BPI*iters+(BPI-1);
x12 = x_ctr & 0xffffffff; x13 = x_ctr>>32; x14 = np[0]; x15 = np[1];
#endif
for (i = chacha_rounds/2; i; i--) {
DQROUND_VECTORS(v0,v1,v2,v3)
DQROUND_VECTORS(v4,v5,v6,v7)
#if VBPI > 2
DQROUND_VECTORS(v8,v9,v10,v11)
#endif
#if VBPI > 3
DQROUND_VECTORS(v12,v13,v14,v15)
#endif
#if GPR_TOO
QROUND_WORDS( x0, x4, x8,x12)
QROUND_WORDS( x1, x5, x9,x13)
QROUND_WORDS( x2, x6,x10,x14)
QROUND_WORDS( x3, x7,x11,x15)
QROUND_WORDS( x0, x5,x10,x15)
QROUND_WORDS( x1, x6,x11,x12)
QROUND_WORDS( x2, x7, x8,x13)
QROUND_WORDS( x3, x4, x9,x14)
#endif
}
WRITE(op, 0, v0+s0, v1+s1, v2+s2, v3+s3)
s3 += ONE;
WRITE(op, 16, v4+s0, v5+s1, v6+s2, v7+s3)
s3 += ONE;
#if VBPI > 2
WRITE(op, 32, v8+s0, v9+s1, v10+s2, v11+s3)
s3 += ONE;
#endif
#if VBPI > 3
WRITE(op, 48, v12+s0, v13+s1, v14+s2, v15+s3)
s3 += ONE;
#endif
op += VBPI*16;
#if GPR_TOO
op[0] = REVW_BE((x0 + chacha_const[0]));
op[1] = REVW_BE((x1 + chacha_const[1]));
op[2] = REVW_BE((x2 + chacha_const[2]));
op[3] = REVW_BE((x3 + chacha_const[3]));
op[4] = REVW_BE((x4 + kp[0]));
op[5] = REVW_BE((x5 + kp[1]));
op[6] = REVW_BE((x6 + kp[2]));
op[7] = REVW_BE((x7 + kp[3]));
op[8] = REVW_BE((x8 + kp[4]));
op[9] = REVW_BE((x9 + kp[5]));
op[10] = REVW_BE((x10 + kp[6]));
op[11] = REVW_BE((x11 + kp[7]));
op[12] = REVW_BE((x12 + (x_ctr & 0xffffffff)));
op[13] = REVW_BE((x13 + (x_ctr >> 32)));
op[14] = REVW_BE((x14 + np[0]));
op[15] = REVW_BE((x15 + np[1]));
s3 += ONE;
op += 16;
#endif
}
return 0;
}

#define STATE_LEN (sizeof(struct chacha_state_krovetz))
#define STATE_BYTES 40
#define IDX_STEP (BPI * LOOP_ITERATIONS)
#define OUTPUT_LEN (IDX_STEP * 64)

static void
chacha_krovetz_state_setup(void *state, const uint8_t *bytes)
{
struct chacha_state_krovetz *st = state;
memcpy(st->key, bytes, 32);
memcpy(st->nonce, bytes+32, 8);
}

static void
chacha8_krovetz_generate(void *state, uint8_t *output, uint32_t idx)
{
struct chacha_state_krovetz *st = state;
ottery_blocks_chacha_krovetz(8, output, idx * IDX_STEP, st);
}

static void
chacha12_krovetz_generate(void *state, uint8_t *output, uint32_t idx)
{
struct chacha_state_krovetz *st = state;
ottery_blocks_chacha_krovetz(12, output, idx * IDX_STEP, st);
}

static void
chacha20_krovetz_generate(void *state, uint8_t *output, uint32_t idx)
{
struct chacha_state_krovetz *st = state;
ottery_blocks_chacha_krovetz(20, output, idx * IDX_STEP, st);
}

#ifdef __SSSE3__
#define NEED_CPUCAP OTTERY_CPUCAP_SSSE3|OTTERY_CPUCAP_SIMD
#define FLAV "-SSSE3"
#else
#define NEED_CPUCAP OTTERY_CPUCAP_SIMD
#define FLAV "-DEFAULT"
#endif

#define PRF_CHACHA(r) { \
"CHACHA" #r, \
"CHACHA" #r "-SIMD", \
"CHACHA" #r "-SIMD" FLAV, \
STATE_LEN, \
STATE_BYTES, \
OUTPUT_LEN, \
NEED_CPUCAP, \
chacha_krovetz_state_setup, \
chacha ## r ## _krovetz_generate \
}

#if defined OTTERY_BUILDING_SIMD1
const struct ottery_prf ottery_prf_chacha8_krovetz_1_ = PRF_CHACHA(8);
const struct ottery_prf ottery_prf_chacha12_krovetz_1_ = PRF_CHACHA(12);
const struct ottery_prf ottery_prf_chacha20_krovetz_1_ = PRF_CHACHA(20);
#elif defined OTTERY_BUILDING_SIMD2
const struct ottery_prf ottery_prf_chacha8_krovetz_2_ = PRF_CHACHA(8);
const struct ottery_prf ottery_prf_chacha12_krovetz_2_ = PRF_CHACHA(12);
const struct ottery_prf ottery_prf_chacha20_krovetz_2_ = PRF_CHACHA(20);
#else
#error "Which PRF symbols am I supposed to define?"
#endif

+ 218
- 0
contrib/libottery/chacha_merged.c View File

@@ -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);


+ 133
- 0
contrib/libottery/chacha_merged_ecrypt.h View File

@@ -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

+ 314
- 0
contrib/libottery/ottery-internal.h View File

@@ -0,0 +1,314 @@
/* 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>
#include "config.h"
#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 intialize 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);
};

#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 __attribute__((aligned(16))) ottery_state {
/**
* Holds up to prf.output_len bytes that have been generated by the
* pseudorandom function. */
__attribute__ ((aligned (16))) uint8_t buffer[MAX_OUTPUT_LEN];
/**
* Holds the state information (typically nonces and keys) used by the
* pseudorandom function. */

__attribute__ ((aligned (16))) uint8_t state[MAX_STATE_LEN];
/**
* 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_;
/**@}*/

/**
* @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

+ 91
- 0
contrib/libottery/ottery-threading.h View File

@@ -0,0 +1,91 @@
/* 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_

/* 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

+ 842
- 0
contrib/libottery/ottery.c View File

@@ -0,0 +1,842 @@
/* 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

/**
* Evaluate the condition 'x', while hinting to the compiler that it is
* likely to be false.
*/
#define UNLIKELY(x) __builtin_expect((x), 0)

/** 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
&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;
}

+ 143
- 0
contrib/libottery/ottery.h View File

@@ -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

+ 349
- 0
contrib/libottery/ottery_common.h View File

@@ -0,0 +1,349 @@
/* 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);

#endif

+ 88
- 0
contrib/libottery/ottery_cpuinfo.c View File

@@ -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;
}

+ 112
- 0
contrib/libottery/ottery_entropy.c View File

@@ -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;
}

+ 51
- 0
contrib/libottery/ottery_entropy_cryptgenrandom.c View File

@@ -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



+ 75
- 0
contrib/libottery/ottery_entropy_egd.c View File

@@ -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

+ 63
- 0
contrib/libottery/ottery_entropy_rdrand.c View File

@@ -0,0 +1,63 @@
/* 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)

/** Helper: invoke the RDRAND instruction to get 4 random bytes in the output
* value. Return 0 on success, and an error on failure. */
static int
rdrand(uint32_t *therand) {
unsigned char status;
__asm volatile(".byte 0x0F, 0xC7, 0xF0 ; setc %1"
: "=a" (*therand), "=qm" (status));
return (status)==1 ? 0 : OTTERY_ERR_INIT_STRONG_RNG;
}

/** 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)
{
int err;
uint32_t *up = (uint32_t *) out;
(void) cfg;
(void) state;
if (! (ottery_get_cpu_capabilities_() & OTTERY_CPUCAP_RAND))
return OTTERY_ERR_INIT_STRONG_RNG;
while (outlen >= 4) {
if ((err = rdrand(up)))
return err;
up += 1;
outlen -= 4;
}
if (outlen) {
uint32_t tmp;
if ((err = rdrand(&tmp)))
return err;
memcpy(up, &tmp, outlen);
}
return 0;
}

#define ENTROPY_SOURCE_RDRAND \
{ ottery_get_entropy_rdrand, SRC(RDRAND)|DOM(CPU)|FL(FAST)|FL(STRONG) }

#endif


+ 117
- 0
contrib/libottery/ottery_entropy_urandom.c View File

@@ -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

+ 111
- 0
contrib/libottery/ottery_global.c View File

@@ -0,0 +1,111 @@
/* 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"

/**
* Evaluate the condition 'x', while hinting to the compiler that it is
* likely to be false.
*/
#define UNLIKELY(x) __builtin_expect((x), 0)

/** Flag: true iff ottery_global_state_ is initialized. */
static int ottery_global_state_initialized_ = 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)
{
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);
}

+ 190
- 0
contrib/libottery/ottery_nolock.h View File

@@ -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

+ 184
- 0
contrib/libottery/ottery_st.h View File

@@ -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

+ 28
- 0
contrib/libottery/ottery_version.h.in View File

@@ -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

+ 1
- 0
src/CMakeLists.txt View File

@@ -67,6 +67,7 @@ ENDIF(CMAKE_COMPILER_IS_GNUCC)
TARGET_LINK_LIBRARIES(rspamd-util ${RSPAMD_REQUIRED_LIBRARIES})
TARGET_LINK_LIBRARIES(rspamd-util pcre)
TARGET_LINK_LIBRARIES(rspamd-util rspamd-ucl)
TARGET_LINK_LIBRARIES(rspamd-util rspamd-ottery)
TARGET_LINK_LIBRARIES(rspamd-util rspamd-http-parser)
TARGET_LINK_LIBRARIES(rspamd-util event)


+ 0
- 228
src/chacha_private.h View File

@@ -1,228 +0,0 @@
/*
chacha-merged.c version 20080118
D. J. Bernstein
Public domain.
*/

#ifndef CHACHA_PRIVATE_H_
#define CHACHA_PRIVATE_H_

#include <stddef.h>

typedef unsigned char u8;
typedef unsigned int u32;

typedef struct
{
u32 input[16]; /* could be compressed */
} chacha_ctx;

#define U8C(v) (v##U)
#define U32C(v) (v##U)

#define U8V(v) ((u8)(v) & U8C(0xFF))
#define U32V(v) ((u32)(v) & U32C(0xFFFFFFFF))

#define ROTL32(v, n) \
(U32V((v) << (n)) | ((v) >> (32 - (n))))

#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)

#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 const char tau[16] = "expand 16-byte k";

static void chacha_keysetup(chacha_ctx *x, const u8 *k, u32 kbits, u32 ivbits)
{
const char *constants;

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);
if (kbits == 256) { /* recommended */
k += 16;
constants = sigma;
}
else { /* kbits == 128 */
constants = tau;
}
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 chacha_ivsetup(chacha_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);
}

static void chacha_encrypt_bytes(chacha_ctx *x, const u8 *m, u8 *c, u32 bytes)
{
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;
u8 *ctarget = NULL;
u8 tmp[64];
unsigned int i;

if (!bytes)
return;

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 (;;) {
if (bytes < 64) {
for (i = 0; i < bytes; ++i)
tmp[i] = m[i];
m = tmp;
ctarget = c;
c = tmp;
}
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 = 20; 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);

#ifndef KEYSTREAM_ONLY
x0 = XOR(x0,U8TO32_LITTLE(m + 0));
x1 = XOR(x1,U8TO32_LITTLE(m + 4));
x2 = XOR(x2,U8TO32_LITTLE(m + 8));
x3 = XOR(x3,U8TO32_LITTLE(m + 12));
x4 = XOR(x4,U8TO32_LITTLE(m + 16));
x5 = XOR(x5,U8TO32_LITTLE(m + 20));
x6 = XOR(x6,U8TO32_LITTLE(m + 24));
x7 = XOR(x7,U8TO32_LITTLE(m + 28));
x8 = XOR(x8,U8TO32_LITTLE(m + 32));
x9 = XOR(x9,U8TO32_LITTLE(m + 36));
x10 = XOR(x10,U8TO32_LITTLE(m + 40));
x11 = XOR(x11,U8TO32_LITTLE(m + 44));
x12 = XOR(x12,U8TO32_LITTLE(m + 48));
x13 = XOR(x13,U8TO32_LITTLE(m + 52));
x14 = XOR(x14,U8TO32_LITTLE(m + 56));
x15 = XOR(x15,U8TO32_LITTLE(m + 60));
#endif

j12 = PLUSONE(j12);
if (!j12) {
j13 = PLUSONE(j13);
/* stopping at 2^70 bytes per nonce is user's responsibility */
}

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);

if (bytes <= 64) {
if (bytes < 64) {
for (i = 0; i < bytes; ++i)
ctarget[i] = c[i];
}
x->input[12] = j12;
x->input[13] = j13;
return;
}
bytes -= 64;
c += 64;
#ifndef KEYSTREAM_ONLY
m += 64;
#endif
}
}

#endif /* CHACHA_PRIVATE_H_ */

+ 5
- 43
src/dns.c View File

@@ -29,6 +29,7 @@
#include "main.h"
#include "utlist.h"
#include "uthash.h"
#include "ottery.h"

#ifdef HAVE_OPENSSL
#include <openssl/rand.h>
@@ -36,50 +37,12 @@

static void dns_retransmit_handler (gint fd, short what, void *arg);

/*
* DNS permutor utilities
*/

/**
* Init chacha20 context
* @param p
*/
static void
dns_permutor_init (struct dns_permutor *p)
{
/* Init random key and IV */
rspamd_random_bytes (p->perm_buf, PERMUTOR_KSIZE + PERMUTOR_IVSIZE);

/* Setup ctx */
chacha_keysetup (&p->ctx, p->perm_buf, PERMUTOR_KSIZE * 8, 0);
chacha_ivsetup (&p->ctx, p->perm_buf + PERMUTOR_KSIZE * 8);

chacha_encrypt_bytes (&p->ctx, p->perm_buf, p->perm_buf, sizeof (p->perm_buf));

p->pos = 0;
}

static struct dns_permutor *
dns_permutor_new (void)
{
struct dns_permutor *new;

new = g_slice_alloc0 (sizeof (struct dns_permutor));
dns_permutor_init (new);

return new;
}

static guint16
dns_permutor_generate_id (struct dns_permutor *p)
dns_permutor_generate_id (void)
{
guint16 id;
if (p->pos + sizeof (guint16) >= sizeof (p->perm_buf)) {
dns_permutor_init (p);
}

memcpy (&id, &p->perm_buf[p->pos], sizeof (guint16));
p->pos += sizeof (guint16);
id = ottery_rand_unsigned ();

return id;
}
@@ -280,7 +243,7 @@ make_dns_header (struct rspamd_dns_request *req)
/* Set DNS header values */
header = (struct dns_header *)req->packet;
memset (header, 0 , sizeof (struct dns_header));
header->qid = dns_permutor_generate_id (req->resolver->permutor);
header->qid = dns_permutor_generate_id ();
header->rd = 1;
header->qdcount = htons (1);
header->arcount = htons (1);
@@ -1284,7 +1247,7 @@ make_dns_request (struct rspamd_dns_resolver *resolver,
while (g_hash_table_lookup (req->io->requests, &req->id)) {
/* Check for unique id */
header = (struct dns_header *)req->packet;
header->qid = dns_permutor_generate_id (resolver->permutor);
header->qid = dns_permutor_generate_id ();
req->id = header->qid;
if (++r > max_id_cycles) {
msg_err ("cannot generate new id for server %s", serv->name);
@@ -1376,7 +1339,6 @@ dns_resolver_init (struct event_base *ev_base, struct config_file *cfg)
new = g_slice_alloc0 (sizeof (struct rspamd_dns_resolver));
new->ev_base = ev_base;
new->permutor = dns_permutor_new ();
new->io_channels = g_hash_table_new (g_direct_hash, g_direct_equal);
new->request_timeout = cfg->dns_timeout;
new->max_retransmits = cfg->dns_retransmits;

+ 0
- 13
src/dns_private.h View File

@@ -25,7 +25,6 @@
#define DNS_PRIVATE_H_

#include "config.h"
#include "chacha_private.h"

#define MAX_SERVERS 16
/* Upstream timeouts */
@@ -50,10 +49,6 @@ static const gint dns_port = 53;
#define DNS_D_MAXLABEL 63 /* + 1 '\0' */
#define DNS_D_MAXNAME 255 /* + 1 '\0' */

#define PERMUTOR_BUF_SIZE 32768
#define PERMUTOR_KSIZE 32
#define PERMUTOR_IVSIZE 8

#define RESOLV_CONF "/etc/resolv.conf"

/**
@@ -78,12 +73,10 @@ struct rspamd_dns_io_channel {
struct rspamd_dns_io_channel *prev, *next;
};

struct dns_permutor;

struct rspamd_dns_resolver {
struct rspamd_dns_server servers[MAX_SERVERS];
gint servers_num; /**< number of DNS servers registered */
struct dns_permutor *permutor; /**< permutor for randomizing request id */
guint request_timeout;
guint max_retransmits;
guint max_errors;
@@ -189,12 +182,6 @@ enum dns_type {
};
/* enum dns_type */

struct dns_permutor {
chacha_ctx ctx;
guchar perm_buf[PERMUTOR_BUF_SIZE];
guint pos;
};

static const gchar dns_rcodes[16][16] = {
[DNS_RC_NOERROR] = "NOERROR",
[DNS_RC_FORMERR] = "FORMERR",

+ 2
- 1
src/main.c View File

@@ -34,6 +34,7 @@
#include "cfg_xml.h"
#include "symbols_cache.h"
#include "lua/lua_common.h"
#include "ottery.h"
#ifdef HAVE_OPENSSL
#include <openssl/rand.h>
#include <openssl/err.h>
@@ -1055,7 +1056,7 @@ main (gint argc, gchar **argv, gchar **env)
OpenSSL_add_all_ciphers ();
#endif

rspamd_prng_seed ();
g_random_set_seed (ottery_rand_uint32 ());

/* First set logger to console logger */
rspamd_main->cfg->log_type = RSPAMD_LOG_CONSOLE;

+ 0
- 55
src/util.c View File

@@ -2110,61 +2110,6 @@ restart:
#endif
}

void
rspamd_random_bytes (gchar *buf, gsize buflen)
{
gint fd;
gsize i;
#ifdef HAVE_CLOCK_GETTIME
struct timespec ts;
#else
struct timeval tv;
#endif
#ifdef HAVE_OPENSSL

/* Init random generator */
if (RAND_bytes (buf, buflen) != 1) {
msg_err ("cannot seed random generator using openssl: %s, using time",
ERR_error_string (ERR_get_error (), NULL));
goto fallback;
}
#else
goto fallback;
#endif
return;

fallback:
/* Try to use /dev/random if no openssl is found */
fd = open ("/dev/random", O_RDONLY);
if (fd != -1) {
if (read (fd, buf, buflen) == (gssize)buflen) {
close (fd);
return;
}
close (fd);
}
/* No /dev/random */
#ifdef HAVE_CLOCK_GETTIME
(void)clock_gettime (CLOCK_REALTIME, &ts);
g_random_set_seed (ts.tv_nsec);
#else
(void)gettimeofday (&tv, NULL);
g_random_set_seed (tv.tv_usec);
#endif
for (i = 0; i < buflen; i ++) {
buf[i] = g_random_int () & 0xff;
}
}

void
rspamd_prng_seed (void)
{
guint32 rand_seed = 0;

rspamd_random_bytes ((gchar *)&rand_seed, sizeof (rand_seed));
g_random_set_seed (rand_seed);
}

gboolean
rspamd_ip_is_valid (void *ptr, int af)
{

+ 0
- 12
src/util.h View File

@@ -438,18 +438,6 @@ gboolean parse_ipmask_v4 (const char *line, struct in_addr *ina, int *mask);
*/
gint rspamd_read_passphrase (gchar *buf, gint size, gint rwflag, gpointer key);

/**
* Seed glib prng using openssl if possible
*/
void rspamd_prng_seed (void);

/**
* Generate random bytes using the most suitable generator
* @param buf
* @param buflen
*/
void rspamd_random_bytes (gchar *buf, gsize buflen);

/**
* Check whether specified ip is valid (not INADDR_ANY or INADDR_NONE) for ipv4 or ipv6
* @param ptr pointer to struct in_addr or struct in6_addr

Loading…
Cancel
Save