spogulis no
https://github.com/henrydcase/pqc.git
synced 2024-11-26 01:11:25 +00:00
234 rindas
6.0 KiB
C
234 rindas
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 */
|