From 70419a33b54e2404fcaee6ea38e7e065f846cadc Mon Sep 17 00:00:00 2001 From: Philipp Schafft Date: Wed, 21 Oct 2020 21:09:52 +0000 Subject: [PATCH] Feature: Added PRNG --- src/Makefile.am | 2 + src/cfgfile.c | 2 + src/main.c | 8 ++ src/prng.c | 233 ++++++++++++++++++++++++++++++++++++++++++++++++ src/prng.h | 24 +++++ 5 files changed, 269 insertions(+) create mode 100644 src/prng.c create mode 100644 src/prng.h diff --git a/src/Makefile.am b/src/Makefile.am index 78da816c..f8168ac0 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -29,6 +29,7 @@ noinst_HEADERS = \ yp.h \ md5.h \ digest.h \ + prng.h \ matchfile.h \ tls.h \ refobject.h \ @@ -79,6 +80,7 @@ icecast_SOURCES = \ resourcematch.c \ md5.c \ digest.c \ + prng.c \ matchfile.c \ tls.c \ refobject.c \ diff --git a/src/cfgfile.c b/src/cfgfile.c index 89d3ec58..41359bd6 100644 --- a/src/cfgfile.c +++ b/src/cfgfile.c @@ -45,6 +45,7 @@ #include "main.h" #include "slave.h" #include "xslt.h" +#include "prng.h" #define CATMODULE "CONFIG" #define CONFIG_DEFAULT_LOCATION "Earth" @@ -765,6 +766,7 @@ void config_reread_config(void) config_set_config(&new_config); config = config_get_config_unlocked(); restart_logging(config); + prng_configure(config); main_config_reload(config); connection_reread_config(config); yp_recheck_config(config); diff --git a/src/main.c b/src/main.c index ed3e0387..f121da54 100644 --- a/src/main.c +++ b/src/main.c @@ -79,6 +79,7 @@ #include "event.h" #include "listensocket.h" #include "fastevent.h" +#include "prng.h" #include @@ -144,6 +145,7 @@ static void initialize_subsystems(void) { log_initialize(); thread_initialize(); + prng_initialize(); global_initialize(); #ifndef FASTEVENT_ENABLED fastevent_initialize(); @@ -181,6 +183,7 @@ static void shutdown_subsystems(void) refobject_unref(fastevent_reg); fastevent_shutdown(); #endif + prng_shutdown(); global_shutdown(); thread_shutdown(); @@ -576,6 +579,7 @@ int main(int argc, char **argv) char filename[512] = ""; #endif char pbuf[1024]; + ice_config_t *config; /* parse the '-c icecast.xml' option ** only, so that we can read a configfile @@ -644,6 +648,10 @@ int main(int argc, char **argv) return 1; } + config = config_get_config(); + prng_configure(config); + config_release_config(); + stats_initialize(); /* We have to do this later on because of threading */ fserve_initialize(); /* This too */ diff --git a/src/prng.c b/src/prng.c new file mode 100644 index 00000000..0b7b0532 --- /dev/null +++ b/src/prng.c @@ -0,0 +1,233 @@ +/* Icecast + * + * This program is distributed under the GNU General Public License, version 2. + * A copy of this license is included with this source. + * + * Copyright 2020, Philipp "ph3-der-loewe" Schafft + * + * The SHA3 implementation is based on rhash: + * 2013 by Aleksey Kravchenko + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include + +#ifdef HAVE_UNAME +#include +#endif + +#include "common/thread/thread.h" + +#include "prng.h" +#include "digest.h" + +#include "logging.h" +#define CATMODULE "prng" + +#define BLOCK_LENGTH (512/8) + +static int initialized = 0; +static mutex_t digest_a_lock; +static mutex_t digest_b_lock; +static digest_t * digest_a; +static digest_t * digest_b; + +static void prng_initial_seed(void) +{ + struct { + int debian; + time_t t; +#ifdef HAVE_UNAME + struct utsname utsname; +#endif +#ifdef HAVE_SETUID + uid_t uid; + pid_t pid; + pid_t ppid; +#endif + } seed; + + seed.debian = 4; + seed.t = time(NULL); +#ifdef HAVE_UNAME + uname(&seed.utsname); +#endif +#ifdef HAVE_SETUID + seed.uid = getuid(); + seed.pid = getpid(); + seed.ppid = getppid(); +#endif + + prng_write(&seed, sizeof(seed)); +} + +void prng_initialize(void) +{ + if (initialized) + return; + + thread_mutex_create(&digest_a_lock); + thread_mutex_create(&digest_b_lock); + digest_a = digest_new(DIGEST_ALGO_SHA3_512); + digest_b = digest_new(DIGEST_ALGO_SHA3_512); + initialized = 1; + prng_initial_seed(); +} + +void prng_shutdown(void) +{ + if (!initialized) + return; + + refobject_unref(digest_b); + refobject_unref(digest_a); + thread_mutex_destroy(&digest_b_lock); + thread_mutex_destroy(&digest_a_lock); + + initialized = 0; +} + +void prng_configure(ice_config_t *config) +{ + if (!initialized) + return; + + // no-op at the moment. +} + +void prng_write(const void *buffer, size_t len) +{ + if (!initialized) + return; + + thread_mutex_lock(&digest_a_lock); + digest_write(digest_a, buffer, len); + thread_mutex_unlock(&digest_a_lock); +} + +static ssize_t prng_read_block(void *froma, void *buffer, size_t len) +{ + char fromb[BLOCK_LENGTH]; + + digest_write(digest_b, froma, BLOCK_LENGTH); + + if (digest_read(digest_b, fromb, sizeof(fromb)) != sizeof(fromb)) + return -1; + + refobject_unref(digest_b); + digest_b = digest_new(DIGEST_ALGO_SHA3_512); + digest_write(digest_b, fromb, sizeof(fromb)); + digest_write(digest_b, &len, sizeof(len)); + + if (len > sizeof(fromb)) + len = sizeof(fromb); + + memcpy(buffer, fromb, len); + + return len; +} + +ssize_t prng_read(void *buffer, size_t len) +{ + digest_t *copy; + char froma[BLOCK_LENGTH]; + size_t ret = 0; + ssize_t res; + + if (!initialized) + return -1; + + thread_mutex_lock(&digest_a_lock); + digest_write(digest_a, &len, sizeof(len)); + copy = digest_copy(digest_a); + thread_mutex_unlock(&digest_a_lock); + + if (!copy) + return -1; + + if (digest_read(copy, froma, sizeof(froma)) != sizeof(froma)) + return -1; + + refobject_unref(copy); + + thread_mutex_lock(&digest_b_lock); + while (ret < len) { + res = prng_read_block(froma, buffer + ret, len - ret); + if (res < 0) { + thread_mutex_unlock(&digest_a_lock); + return -1; + } + ret += res; + } + thread_mutex_unlock(&digest_a_lock); + + return ret; +} + +int prng_write_file(const char *filename, ssize_t len) +{ + char buffer[BLOCK_LENGTH*16]; + size_t done = 0; + FILE *file; + + if (len < 0) + len = 1024; + + file = fopen(filename, "wb"); + if (!file) + return -1; + + while (done < (size_t)len) { + size_t todo = (size_t)len < sizeof(buffer) ? (size_t)len : sizeof(buffer); + ssize_t res = prng_read(buffer, todo); + if (res < 1) { + fclose(file); + return -1; + } + + if (fwrite(buffer, 1, res, file) != (size_t)res) { + fclose(file); + return -1; + } + + done += res; + } + + fclose(file); + return 0; +} + +int prng_read_file(const char *filename, ssize_t len) +{ + char buffer[BLOCK_LENGTH*16]; + size_t done = 0; + FILE *file; + + if (len < 0 || len > 1048576) + len = 1048576; + + file = fopen(filename, "rb"); + if (!file) + return -1; + + while (done < (size_t)len) { + size_t todo = (size_t)len < sizeof(buffer) ? (size_t)len : sizeof(buffer); + size_t res = fread(buffer, 1, todo, file); + + if (res < 1) { + fclose(file); + return 0; + } + + prng_write(buffer, res); + + done += res; + } + + fclose(file); + return 0; +} diff --git a/src/prng.h b/src/prng.h new file mode 100644 index 00000000..d79057c4 --- /dev/null +++ b/src/prng.h @@ -0,0 +1,24 @@ +/* Icecast + * + * This program is distributed under the GNU General Public License, version 2. + * A copy of this license is included with this source. + * + * Copyright 2020, Philipp "ph3-der-loewe" Schafft + */ + +#ifndef __PRNG_H__ +#define __PRNG_H__ + +#include "icecasttypes.h" + +void prng_initialize(void); +void prng_shutdown(void); +void prng_configure(ice_config_t *config); + +void prng_write(const void *buffer, size_t len); +ssize_t prng_read(void *buffer, size_t len); + +int prng_write_file(const char *filename, ssize_t len); +int prng_read_file(const char *filename, ssize_t len); + +#endif