Parcourir la source

Use cryptobox chacha for libottery.

tags/1.0.6
Vsevolod Stakhov il y a 8 ans
Parent
révision
572f8723c8

+ 1
- 1
contrib/blake2/CMakeLists.txt Voir le fichier

set(BLAKE_SRC blake2b-ref.c) set(BLAKE_SRC blake2b-ref.c)
add_library(blake2 STATIC "${BLAKE_SRC}") add_library(blake2 STATIC "${BLAKE_SRC}")
if ("${CMAKE_C_COMPILER_ID}" STREQUAL "Clang" OR "${CMAKE_C_COMPILER_ID}" STREQUAL "GNU") if ("${CMAKE_C_COMPILER_ID}" STREQUAL "Clang" OR "${CMAKE_C_COMPILER_ID}" STREQUAL "GNU")
set_target_properties(blake2 PROPERTIES COMPILER_FLAGS "-O3")
set_target_properties(blake2 PROPERTIES COMPILE_FLAGS "-O3")
endif () endif ()

+ 3
- 2
contrib/http-parser/CMakeLists.txt Voir le fichier

SET(HTTPSRC http_parser.c) SET(HTTPSRC http_parser.c)


SET(HTTP_COMPILE_FLAGS "-DRSPAMD_LIB")
if ("${CMAKE_C_COMPILER_ID}" STREQUAL "Clang" OR "${CMAKE_C_COMPILER_ID}" STREQUAL "GNU") if ("${CMAKE_C_COMPILER_ID}" STREQUAL "Clang" OR "${CMAKE_C_COMPILER_ID}" STREQUAL "GNU")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -O3")
set(HTTP_COMPILE_FLAGS "${HTTP_COMPILE_FLAGS} -O3")
endif () endif ()


ADD_LIBRARY(rspamd-http-parser STATIC ${HTTPSRC}) ADD_LIBRARY(rspamd-http-parser STATIC ${HTTPSRC})
SET_TARGET_PROPERTIES(rspamd-http-parser PROPERTIES VERSION ${RSPAMD_VERSION}) SET_TARGET_PROPERTIES(rspamd-http-parser PROPERTIES VERSION ${RSPAMD_VERSION})
SET_TARGET_PROPERTIES(rspamd-http-parser PROPERTIES COMPILE_FLAGS "-DRSPAMD_LIB")
SET_TARGET_PROPERTIES(rspamd-http-parser PROPERTIES COMPILE_FLAGS "${HTTP_COMPILE_FLAGS}")

+ 6
- 3
contrib/libottery/CMakeLists.txt Voir le fichier

ottery.c ottery.c
ottery_cpuinfo.c ottery_cpuinfo.c
ottery_entropy.c ottery_entropy.c
ottery_global.c)
ottery_global.c chacha_cryptobox.c)
ADD_LIBRARY(ottery STATIC ${OTTERYSRC}) ADD_LIBRARY(ottery STATIC ${OTTERYSRC})

SET(OTTERY_CFLAGS "-DBUILD_RSPAMD")
if ("${CMAKE_C_COMPILER_ID}" STREQUAL "Clang" OR "${CMAKE_C_COMPILER_ID}" STREQUAL "GNU") if ("${CMAKE_C_COMPILER_ID}" STREQUAL "Clang" OR "${CMAKE_C_COMPILER_ID}" STREQUAL "GNU")
set_target_properties(ottery PROPERTIES COMPILER_FLAGS "-O3")
endif ()
SET(OTTERY_CFLAGS "${OTTERY_CFLAGS} -O3")
endif ()
set_target_properties(ottery PROPERTIES COMPILE_FLAGS "${OTTERY_CFLAGS}")

+ 64
- 0
contrib/libottery/chacha_cryptobox.c Voir le fichier

/*
* Copyright (c) 2015, Vsevolod Stakhov
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY AUTHOR ''AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL AUTHOR BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

#include "config.h"
#include "ottery-internal.h"
#include "libcryptobox/chacha20/chacha.h"

#define STATE_LEN (sizeof(chacha_state))
#define STATE_BYTES 40

#define IDX_STEP 16
#define OUTPUT_LEN (IDX_STEP * 64)

static void
chacha_cryptobox_state_setup (void *state_, const uint8_t *bytes)
{
chacha_state *x = state_;
chacha_init (x, (chacha_key *)bytes, (chacha_iv *)(bytes + 32), 20);
}

static void
chacha20_cryptobox_generate (void *state_, uint8_t *output, uint32_t idx)
{
chacha_state *x = state_;

memset (output, 0, OUTPUT_LEN);
memcpy (output, &idx, sizeof (idx));
chacha_update (x, output, output, OUTPUT_LEN);
}

#define PRF_CHACHA(r) { \
"CHACHA" #r, \
"CHACHA" #r "-NOSIMD", \
"CHACHA" #r "-NOSIMD-DEFAULT", \
STATE_LEN, \
STATE_BYTES, \
OUTPUT_LEN, \
0, \
chacha_cryptobox_state_setup, \
chacha ## r ## _cryptobox_generate \
}

const struct ottery_prf ottery_prf_chacha20_cryptobox_ = PRF_CHACHA(20);

+ 8
- 0
contrib/libottery/ottery-internal.h Voir le fichier

#define OTTERY_INTERNAL_H_HEADER_INCLUDED_ #define OTTERY_INTERNAL_H_HEADER_INCLUDED_
#include <stdint.h> #include <stdint.h>
#include <sys/types.h> #include <sys/types.h>

#ifdef BUILD_RSPAMD
#include "config.h" #include "config.h"
#endif

#include "ottery-threading.h" #include "ottery-threading.h"




extern const struct ottery_prf ottery_prf_chacha8_merged_; 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_chacha12_merged_;
extern const struct ottery_prf ottery_prf_chacha20_merged_; extern const struct ottery_prf ottery_prf_chacha20_merged_;

#ifdef BUILD_RSPAMD
extern const struct ottery_prf ottery_prf_chacha20_cryptobox_;
#endif
/**@}*/ /**@}*/


/** /**

+ 5
- 0
contrib/libottery/ottery-threading.h Voir le fichier

#ifndef OTTERY_LOCKING_H_HEADER_INCLUDED_ #ifndef OTTERY_LOCKING_H_HEADER_INCLUDED_
#define OTTERY_LOCKING_H_HEADER_INCLUDED_ #define OTTERY_LOCKING_H_HEADER_INCLUDED_


/* We don't need locks when building rspamd */
#ifdef BUILD_RSPAMD
#define OTTERY_NO_LOCKS
#endif

/* Locks */ /* Locks */
#ifdef OTTERY_NO_LOCKS #ifdef OTTERY_NO_LOCKS
/* Nothing here. */ /* Nothing here. */

+ 162
- 159
contrib/libottery/ottery.c Voir le fichier

&ottery_prf_chacha12_krovetz_1_, &ottery_prf_chacha12_krovetz_1_,
&ottery_prf_chacha8_krovetz_1_, &ottery_prf_chacha8_krovetz_1_,
#endif #endif
&ottery_prf_chacha20_merged_,
&ottery_prf_chacha12_merged_,
&ottery_prf_chacha8_merged_,
#ifdef BUILD_RSPAMD
&ottery_prf_chacha20_cryptobox_,
#endif
&ottery_prf_chacha20_merged_,
&ottery_prf_chacha12_merged_,
&ottery_prf_chacha8_merged_,


NULL,
NULL,
}; };
const uint32_t cap = ottery_get_cpu_capabilities_(); const uint32_t cap = ottery_get_cpu_capabilities_();


for (i = 0; ALL_PRFS[i]; ++i) { 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;
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; return NULL;
} }


int int
ottery_config_force_implementation(struct ottery_config *cfg, ottery_config_force_implementation(struct ottery_config *cfg,
const char *impl)
const char *impl)
{ {
const struct ottery_prf *prf = ottery_get_impl(impl); const struct ottery_prf *prf = ottery_get_impl(impl);
if (prf) { if (prf) {
cfg->impl = prf;
return 0;
cfg->impl = prf;
return 0;
} }
return OTTERY_ERR_INVALID_ARGUMENT; return OTTERY_ERR_INVALID_ARGUMENT;
} }


void void
ottery_config_set_manual_prf_(struct ottery_config *cfg, ottery_config_set_manual_prf_(struct ottery_config *cfg,
const struct ottery_prf *prf)
const struct ottery_prf *prf)
{ {
cfg->impl = prf; cfg->impl = prf;
} }


void void
ottery_config_set_urandom_device(struct ottery_config *cfg, ottery_config_set_urandom_device(struct ottery_config *cfg,
const char *fname)
const char *fname)
{ {
cfg->entropy_config.urandom_fname = fname; cfg->entropy_config.urandom_fname = fname;
} }


void void
ottery_config_set_urandom_fd(struct ottery_config *cfg, ottery_config_set_urandom_fd(struct ottery_config *cfg,
int fd)
int fd)
{ {
cfg->entropy_config.urandom_fd = fd; cfg->entropy_config.urandom_fd = fd;
cfg->entropy_config.urandom_fd_is_set = (fd >= 0); cfg->entropy_config.urandom_fd_is_set = (fd >= 0);


void void
ottery_config_set_egd_socket(struct ottery_config *cfg, ottery_config_set_egd_socket(struct ottery_config *cfg,
const struct sockaddr *addr,
int len)
const struct sockaddr *addr,
int len)
{ {
cfg->entropy_config.egd_sockaddr = addr; cfg->entropy_config.egd_sockaddr = addr;
cfg->entropy_config.egd_socklen = len; cfg->entropy_config.egd_socklen = len;


void void
ottery_config_disable_entropy_sources(struct ottery_config *cfg, ottery_config_disable_entropy_sources(struct ottery_config *cfg,
uint32_t disabled_sources)
uint32_t disabled_sources)
{ {
cfg->entropy_config.disabled_sources = cfg->entropy_config.disabled_sources =
(disabled_sources & OTTERY_ENTROPY_ALL_SOURCES);
(disabled_sources & OTTERY_ENTROPY_ALL_SOURCES);
} }


void void
ottery_config_mark_entropy_sources_weak(struct ottery_config *cfg, ottery_config_mark_entropy_sources_weak(struct ottery_config *cfg,
uint32_t disabled_sources)
uint32_t disabled_sources)
{ {
cfg->entropy_config.weak_sources = cfg->entropy_config.weak_sources =
(disabled_sources & OTTERY_ENTROPY_ALL_SOURCES);
(disabled_sources & OTTERY_ENTROPY_ALL_SOURCES);
} }


/** /**
*/ */
static int static int
ottery_st_initialize(struct ottery_state *st, ottery_st_initialize(struct ottery_state *st,
const struct ottery_config *config,
int locked)
const struct ottery_config *config,
int locked)
{ {
const struct ottery_prf *prf = NULL; const struct ottery_prf *prf = NULL;
struct ottery_config cfg_tmp; struct ottery_config cfg_tmp;
* error now, and not a crash when the SIMD instructions start to fail. * error now, and not a crash when the SIMD instructions start to fail.
*/ */
if (((uintptr_t)st) & 0xf) if (((uintptr_t)st) & 0xf)
return OTTERY_ERR_STATE_ALIGNMENT;
return OTTERY_ERR_STATE_ALIGNMENT;


if (!config) { if (!config) {
ottery_config_init(&cfg_tmp);
config = &cfg_tmp;
ottery_config_init(&cfg_tmp);
config = &cfg_tmp;
} }


prf = config->impl; prf = config->impl;


if (!prf) if (!prf)
prf = ottery_get_impl(NULL);
prf = ottery_get_impl(NULL);


memset(st, 0, sizeof(*st)); memset(st, 0, sizeof(*st));


if (locked) { if (locked) {
/* Now set up the spinlock or mutex or hybrid thing. */
if (INIT_LOCK(&st->mutex))
return OTTERY_ERR_LOCK_INIT;
/* 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. */ /* Check invariants for PRF, in case we wrote some bad code. */
if ((prf->state_len > MAX_STATE_LEN) || 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;
(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. */ /* Check whether some of our structure size assumptions are right. */
if ((sizeof(struct ottery_state) > OTTERY_STATE_DUMMY_SIZE_) || if ((sizeof(struct ottery_state) > OTTERY_STATE_DUMMY_SIZE_) ||
(sizeof(struct ottery_config) > OTTERY_CONFIG_DUMMY_SIZE_))
return OTTERY_ERR_INTERNAL;
(sizeof(struct ottery_config) > OTTERY_CONFIG_DUMMY_SIZE_))
return OTTERY_ERR_INTERNAL;


memcpy(&st->entropy_config, &config->entropy_config, memcpy(&st->entropy_config, &config->entropy_config,
sizeof(struct ottery_entropy_config));
sizeof(struct ottery_entropy_config));


/* Copy the PRF into place. */ /* Copy the PRF into place. */
memcpy(&st->prf, prf, sizeof(*prf)); memcpy(&st->prf, prf, sizeof(*prf));


if ((err = ottery_st_reseed(st))) if ((err = ottery_st_reseed(st)))
return err;
return err;


/* Set the magic number last, or else we might look like we succeeded /* Set the magic number last, or else we might look like we succeeded
* when we didn't */ * when we didn't */
size_t buflen = ottery_get_entropy_bufsize_(st->prf.state_bytes); size_t buflen = ottery_get_entropy_bufsize_(st->prf.state_bytes);
uint8_t *buf = alloca(buflen); uint8_t *buf = alloca(buflen);
if (!buf) if (!buf)
return OTTERY_ERR_INIT_STRONG_RNG;
return OTTERY_ERR_INIT_STRONG_RNG;


if ((err = ottery_get_entropy_(&st->entropy_config, &st->entropy_state, 0, if ((err = ottery_get_entropy_(&st->entropy_config, &st->entropy_state, 0,
buf, st->prf.state_bytes,
&buflen,
&flags)))
return err;
buf, st->prf.state_bytes,
&buflen,
&flags)))
return err;
if (buflen < st->prf.state_bytes) if (buflen < st->prf.state_bytes)
return OTTERY_ERR_ACCESS_STRONG_RNG;
return OTTERY_ERR_ACCESS_STRONG_RNG;
/* The first state_bytes bytes become the initial key. */ /* The first state_bytes bytes become the initial key. */
st->prf.setup(st->state, buf); st->prf.setup(st->state, buf);
/* If there are more bytes, we mix them into the key with add_seed */ /* If there are more bytes, we mix them into the key with add_seed */
if (buflen > st->prf.state_bytes) 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_st_add_seed_impl(st,
buf + st->prf.state_bytes,
buflen - st->prf.state_bytes,
0,
0);
ottery_memclear_(buf, buflen); ottery_memclear_(buf, buflen);
st->last_entropy_flags = flags; st->last_entropy_flags = flags;
st->entropy_src_flags = flags; st->entropy_src_flags = flags;


int int
ottery_st_init_nolock(struct ottery_state_nolock *st, ottery_st_init_nolock(struct ottery_state_nolock *st,
const struct ottery_config *cfg)
const struct ottery_config *cfg)
{ {
return ottery_st_initialize(st, cfg, 0); return ottery_st_initialize(st, cfg, 0);
} }
{ {
#ifndef OTTERY_NO_INIT_CHECK #ifndef OTTERY_NO_INIT_CHECK
if (check_magic && UNLIKELY(st->magic != MAGIC(st))) { if (check_magic && UNLIKELY(st->magic != MAGIC(st))) {
ottery_fatal_error_(OTTERY_ERR_STATE_INIT);
return OTTERY_ERR_STATE_INIT;
ottery_fatal_error_(OTTERY_ERR_STATE_INIT);
return OTTERY_ERR_STATE_INIT;
} }
#endif #endif


uint32_t flags = 0; uint32_t flags = 0;


if (!seed || !n) { 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;
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) if (locking)
LOCK(st);
LOCK(st);
/* The algorithm here is really easy. We grab a block of output from the /* 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 * 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_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. * state. We do this over and over until we have no more seed data to add.
*/ */
while (n) { 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;
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. */ /* Now make sure that st->buffer is set up with the new state. */
st->last_entropy_flags = flags; st->last_entropy_flags = flags;


if (locking) if (locking)
UNLOCK(st);
UNLOCK(st);


/* If we used stack-allocated seed material, wipe it. */ /* If we used stack-allocated seed material, wipe it. */
if (tmp_seed) if (tmp_seed)
ottery_memclear_(tmp_seed, tmp_seed_len);
ottery_memclear_(tmp_seed, tmp_seed_len);


return 0; return 0;
} }
ottery_fatal_error_(int error) ottery_fatal_error_(int error)
{ {
if (ottery_fatal_handler) if (ottery_fatal_handler)
ottery_fatal_handler(error);
ottery_fatal_handler(error);
else else
abort();
abort();
} }


void void
{ {
#ifndef OTTERY_NO_INIT_CHECK #ifndef OTTERY_NO_INIT_CHECK
if (UNLIKELY(st->magic != MAGIC(st))) { if (UNLIKELY(st->magic != MAGIC(st))) {
ottery_fatal_error_(OTTERY_ERR_STATE_INIT);
return -1;
ottery_fatal_error_(OTTERY_ERR_STATE_INIT);
return -1;
} }
#else #else
(void)st; (void)st;
{ {
#ifndef OTTERY_NO_PID_CHECK #ifndef OTTERY_NO_PID_CHECK
if (UNLIKELY(st->pid != getpid())) { 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();
int err;
if ((err = ottery_st_reseed(st))) {
ottery_fatal_error_(OTTERY_ERR_FLAG_POSTFORK_RESEED|err);
return -1;
}
st->pid = getpid();
} }
#else #else
(void) st; (void) st;
ottery_st_rand_lock_and_check(struct ottery_state *st) ottery_st_rand_lock_and_check(struct ottery_state *st)
{ {
if (ottery_st_rand_check_init(st)) if (ottery_st_rand_check_init(st))
return -1;
return -1;
LOCK(st); LOCK(st);
if (ottery_st_rand_check_pid(st)) { if (ottery_st_rand_check_pid(st)) {
UNLOCK(st);
return -1;
UNLOCK(st);
return -1;
} }
return 0; return 0;
} }
ottery_st_rand_check_nolock(struct ottery_state_nolock *st) ottery_st_rand_check_nolock(struct ottery_state_nolock *st)
{ {
if (ottery_st_rand_check_init(st)) if (ottery_st_rand_check_init(st))
return -1;
return -1;
if (ottery_st_rand_check_pid(st)) if (ottery_st_rand_check_pid(st))
return -1;
return -1;
return 0; return 0;
} }


*/ */
static inline void static inline void
ottery_st_rand_bytes_from_buf(struct ottery_state *st, uint8_t *out, ottery_st_rand_bytes_from_buf(struct ottery_state *st, uint8_t *out,
size_t n)
size_t n)
{ {
if (n + st->pos < st->prf.output_len) { if (n + st->pos < st->prf.output_len) {
memcpy(out, st->buffer+st->pos, n);
CLEARBUF(st->buffer+st->pos, n);
st->pos += n;
memcpy(out, st->buffer+st->pos, n);
CLEARBUF(st->buffer+st->pos, n);
st->pos += n;
} else { } 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);
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 static void
ottery_st_rand_bytes_impl(struct ottery_state *st, void *out_, ottery_st_rand_bytes_impl(struct ottery_state *st, void *out_,
size_t n)
size_t n)
{ {
uint8_t *out = out_; uint8_t *out = out_;
size_t cpy; size_t cpy;


if (n + st->pos < st->prf.output_len * 2 - st->prf.state_bytes - 1) { 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;
/* 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... */ /* Okay. That's not going to happen. Well, take what we can... */


/* Then take whole blocks so long as we need them, without stirring... */ /* Then take whole blocks so long as we need them, without stirring... */
while (n >= st->prf.output_len) { 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;
/* (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. */ /* Then stir for the last part. */
ottery_st_rand_bytes(struct ottery_state *st, void *out_, size_t n) ottery_st_rand_bytes(struct ottery_state *st, void *out_, size_t n)
{ {
if (ottery_st_rand_lock_and_check(st)) if (ottery_st_rand_lock_and_check(st))
return;
return;
ottery_st_rand_bytes_impl(st, out_, n); ottery_st_rand_bytes_impl(st, out_, n);
UNLOCK(st); UNLOCK(st);
} }
ottery_st_rand_bytes_nolock(struct ottery_state_nolock *st, void *out_, size_t n) ottery_st_rand_bytes_nolock(struct ottery_state_nolock *st, void *out_, size_t n)
{ {
if (ottery_st_rand_check_nolock(st)) if (ottery_st_rand_check_nolock(st))
return;
return;
ottery_st_rand_bytes_impl(st, out_, n); ottery_st_rand_bytes_impl(st, out_, n);
} }


* @param p a pointer to the bytes to read from. * @param p a pointer to the bytes to read from.
**/ **/
#define INT_ASSIGN_PTR(type, r, p) do { \ #define INT_ASSIGN_PTR(type, r, p) do { \
memcpy(&r, p, sizeof(type)); \
memcpy(&r, p, sizeof(type)); \
} while (0) } while (0)


/** /**
* @param inttype The type of integer to generate. * @param inttype The type of integer to generate.
**/ **/
#define OTTERY_RETURN_RAND_INTTYPE_IMPL(st, inttype, unlock) do { \ #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; \
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) } while (0)


#define OTTERY_RETURN_RAND_INTTYPE(st, inttype) do { \ #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)); \
if (ottery_st_rand_lock_and_check(st)) \
return (inttype)0; \
OTTERY_RETURN_RAND_INTTYPE_IMPL(st, inttype, UNLOCK(st)); \
} while (0) } while (0)


#define OTTERY_RETURN_RAND_INTTYPE_NOLOCK(st, inttype) do { \ #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, ); \
if (ottery_st_rand_check_nolock(st)) \
return (inttype)0; \
OTTERY_RETURN_RAND_INTTYPE_IMPL(st, inttype, ); \
} while (0) } while (0)


unsigned unsigned
unsigned divisor = lim ? (UINT_MAX / lim) : 1; unsigned divisor = lim ? (UINT_MAX / lim) : 1;
unsigned n; unsigned n;
do { do {
n = (ottery_st_rand_unsigned_nolock(st) / divisor);
n = (ottery_st_rand_unsigned_nolock(st) / divisor);
} while (n > upper); } while (n > upper);


return n; return n;
uint64_t divisor = lim ? (UINT64_MAX / lim) : 1; uint64_t divisor = lim ? (UINT64_MAX / lim) : 1;
uint64_t n; uint64_t n;
do { do {
n = (ottery_st_rand_uint64_nolock(st) / divisor);
n = (ottery_st_rand_uint64_nolock(st) / divisor);
} while (n > upper); } while (n > upper);


return n; return n;
{ {
unsigned n; unsigned n;
if (ottery_st_rand_check_init(state)) if (ottery_st_rand_check_init(state))
return 0;
return 0;
LOCK(state); LOCK(state);
n = ottery_st_rand_range_nolock(state, upper); n = ottery_st_rand_range_nolock(state, upper);
UNLOCK(state); UNLOCK(state);
{ {
uint64_t n; uint64_t n;
if (ottery_st_rand_check_init(state)) if (ottery_st_rand_check_init(state))
return 0;
return 0;
LOCK(state); LOCK(state);
n = ottery_st_rand_range64_nolock(state, upper); n = ottery_st_rand_range64_nolock(state, upper);
UNLOCK(state); UNLOCK(state);

+ 1
- 1
src/libutil/util.c Voir le fichier

{ {
struct rlimit rlim; struct rlimit rlim;


rspamd_cryptobox_init ();
ottery_init (NULL); ottery_init (NULL);


rspamd_cryptobox_init ();
#ifdef HAVE_LOCALE_H #ifdef HAVE_LOCALE_H
if (getenv ("LANG") == NULL) { if (getenv ("LANG") == NULL) {
setlocale (LC_ALL, "C"); setlocale (LC_ALL, "C");

Chargement…
Annuler
Enregistrer