1
1
зеркало из https://github.com/henrydcase/pqc.git synced 2024-11-22 15:39:07 +00:00
pqcrypto/3rd/jitterentropy/jitterentropy-timer.c
2023-01-27 22:49:29 +00:00

234 строки
6.0 KiB
C

/* Jitter RNG: Internal timer implementation
*
* Copyright (C) 2021 - 2022, Stephan Mueller <smueller@chronox.de>
*
* License: see LICENSE file in root directory
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ALL OF
* WHICH ARE HEREBY DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
* USE OF THIS SOFTWARE, EVEN IF NOT ADVISED OF THE POSSIBILITY OF SUCH
* DAMAGE.
*/
#include "jitterentropy-base.h"
#include "jitterentropy-timer.h"
#ifdef JENT_CONF_ENABLE_INTERNAL_TIMER
/***************************************************************************
* Thread handler
***************************************************************************/
JENT_PRIVATE_STATIC
int jent_notime_init(void **ctx)
{
struct jent_notime_ctx *thread_ctx;
long ncpu = jent_ncpu();
if (ncpu < 0)
return (int)ncpu;
/* We need at least two CPUs to enable the timer thread */
if (ncpu < 2)
return -EOPNOTSUPP;
thread_ctx = calloc(1, sizeof(struct jent_notime_ctx));
if (!thread_ctx)
return -errno;
*ctx = thread_ctx;
return 0;
}
JENT_PRIVATE_STATIC
void jent_notime_fini(void *ctx)
{
struct jent_notime_ctx *thread_ctx = (struct jent_notime_ctx *)ctx;
if (thread_ctx)
free(thread_ctx);
}
static int jent_notime_start(void *ctx,
void *(*start_routine) (void *), void *arg)
{
struct jent_notime_ctx *thread_ctx = (struct jent_notime_ctx *)ctx;
int ret;
if (!thread_ctx)
return -EINVAL;
ret = -pthread_attr_init(&thread_ctx->notime_pthread_attr);
if (ret)
return ret;
return -pthread_create(&thread_ctx->notime_thread_id,
&thread_ctx->notime_pthread_attr,
start_routine, arg);
}
static void jent_notime_stop(void *ctx)
{
struct jent_notime_ctx *thread_ctx = (struct jent_notime_ctx *)ctx;
pthread_join(thread_ctx->notime_thread_id, NULL);
pthread_attr_destroy(&thread_ctx->notime_pthread_attr);
}
static struct jent_notime_thread jent_notime_thread_builtin = {
.jent_notime_init = jent_notime_init,
.jent_notime_fini = jent_notime_fini,
.jent_notime_start = jent_notime_start,
.jent_notime_stop = jent_notime_stop
};
/***************************************************************************
* Timer-less timer replacement
*
* If there is no high-resolution hardware timer available, we create one
* ourselves. This logic is only used when the initialization identifies
* that no suitable time source is available.
***************************************************************************/
static int jent_force_internal_timer = 0;
static int jent_notime_switch_blocked = 0;
void jent_notime_block_switch(void)
{
jent_notime_switch_blocked = 1;
}
static struct jent_notime_thread *notime_thread = &jent_notime_thread_builtin;
/**
* Timer-replacement loop
*
* @brief The measurement loop triggers the read of the value from the
* counter function. It conceptually acts as the low resolution
* samples timer from a ring oscillator.
*/
static void *jent_notime_sample_timer(void *arg)
{
struct rand_data *ec = (struct rand_data *)arg;
ec->notime_timer = 0;
while (1) {
if (ec->notime_interrupt)
return NULL;
ec->notime_timer++;
}
return NULL;
}
/*
* Enable the clock: spawn a new thread that holds a counter.
*
* Note, although creating a thread is expensive, we do that every time a
* caller wants entropy from us and terminate the thread afterwards. This
* is to ensure an attacker cannot easily identify the ticking thread.
*/
int jent_notime_settick(struct rand_data *ec)
{
if (!ec->enable_notime || !notime_thread)
return 0;
ec->notime_interrupt = 0;
ec->notime_prev_timer = 0;
ec->notime_timer = 0;
return notime_thread->jent_notime_start(ec->notime_thread_ctx,
jent_notime_sample_timer, ec);
}
void jent_notime_unsettick(struct rand_data *ec)
{
if (!ec->enable_notime || !notime_thread)
return;
ec->notime_interrupt = 1;
notime_thread->jent_notime_stop(ec->notime_thread_ctx);
}
void jent_get_nstime_internal(struct rand_data *ec, uint64_t *out)
{
if (ec->enable_notime) {
/*
* Allow the counting thread to be initialized and guarantee
* that it ticked since last time we looked.
*
* Note, we do not use an atomic operation here for reading
* jent_notime_timer since if this integer is garbled, it even
* adds to entropy. But on most architectures, read/write
* of an uint64_t should be atomic anyway.
*/
while (ec->notime_timer == ec->notime_prev_timer)
jent_yield();
ec->notime_prev_timer = ec->notime_timer;
*out = ec->notime_prev_timer;
} else {
jent_get_nstime(out);
}
}
static inline int jent_notime_enable_thread(struct rand_data *ec)
{
if (notime_thread)
return notime_thread->jent_notime_init(&ec->notime_thread_ctx);
return 0;
}
void jent_notime_disable(struct rand_data *ec)
{
if (notime_thread)
notime_thread->jent_notime_fini(ec->notime_thread_ctx);
}
int jent_notime_enable(struct rand_data *ec, unsigned int flags)
{
/* Use internal timer */
if (jent_force_internal_timer || (flags & JENT_FORCE_INTERNAL_TIMER)) {
/* Self test not run yet */
if (!jent_force_internal_timer &&
jent_time_entropy_init(ec->osr,
flags | JENT_FORCE_INTERNAL_TIMER))
return EHEALTH;
ec->enable_notime = 1;
return jent_notime_enable_thread(ec);
}
return 0;
}
int jent_notime_switch(struct jent_notime_thread *new_thread)
{
if (jent_notime_switch_blocked)
return -EAGAIN;
notime_thread = new_thread;
return 0;
}
void jent_notime_force(void)
{
jent_force_internal_timer = 1;
}
int jent_notime_forced(void)
{
return jent_force_internal_timer;
}
#endif /* JENT_CONF_ENABLE_INTERNAL_TIMER */