From 7146f0c33c4f68883e60169066a4a863ae388fc5 Mon Sep 17 00:00:00 2001 From: =?utf8?q?Petr=20=C5=A0tetiar?= Date: Mon, 20 May 2019 11:24:49 +0200 Subject: [PATCH 1/1] Initial commit MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit Signed-off-by: Petr Štetiar --- .gitignore | 2 + .gitmodules | 3 + 3rdparty/jitterentropy-rngd | 1 + CMakeLists.txt | 33 ++++ Makefile | 36 +++++ README.md | 13 ++ cmake/openwrt-toolchain-ath79.cmake | 20 +++ cmake/openwrt-toolchain-imx6.cmake | 17 ++ log.h | 34 ++++ urngd.c | 243 ++++++++++++++++++++++++++++ 10 files changed, 402 insertions(+) create mode 100644 .gitignore create mode 100644 .gitmodules create mode 160000 3rdparty/jitterentropy-rngd create mode 100644 CMakeLists.txt create mode 100644 Makefile create mode 100644 README.md create mode 100644 cmake/openwrt-toolchain-ath79.cmake create mode 100644 cmake/openwrt-toolchain-imx6.cmake create mode 100644 log.h create mode 100644 urngd.c diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..df20789 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +local.mk +build* diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..c892b92 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "3rdparty/jitterentropy-rngd"] + path = 3rdparty/jitterentropy-rngd + url = https://github.com/smuellerDD/jitterentropy-rngd.git diff --git a/3rdparty/jitterentropy-rngd b/3rdparty/jitterentropy-rngd new file mode 160000 index 0000000..ad4d636 --- /dev/null +++ b/3rdparty/jitterentropy-rngd @@ -0,0 +1 @@ +Subproject commit ad4d6364279fa437a433bbc49d851e35b8dc467d diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..bc9a2f6 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,33 @@ +cmake_minimum_required(VERSION 2.6) + +PROJECT(urngd) +INCLUDE(GNUInstallDirs) +INCLUDE (FindPkgConfig) + +SET(URNGD_VERSION 1.0.0) +SET(JTEN_DIR 3rdparty/jitterentropy-rngd) + +FIND_PATH(ubox_include_dir NAMES libubox/usock.h) +FIND_LIBRARY(ubox NAMES ubox) +INCLUDE_DIRECTORIES(${ubox_include_dir} ${JTEN_DIR}) + +SET(CMAKE_C_FLAGS_DEBUG -DURNGD_DEBUG) + +ADD_DEFINITIONS(-Wall -Werror -Wextra --std=gnu99 -DURNGD_VERSION="${URNGD_VERSION}") +ADD_DEFINITIONS(-Wno-unused-parameter) + +ADD_EXECUTABLE(urngd + urngd.c + ${JTEN_DIR}/jitterentropy-base.c +) +TARGET_LINK_LIBRARIES(urngd ${ubox}) + +# jitter RNG must not be compiled with optimizations +SET_SOURCE_FILES_PROPERTIES(${JTEN_DIR}/jitterentropy-base.c PROPERTIES COMPILE_FLAGS -O0) + +INSTALL(TARGETS urngd RUNTIME DESTINATION ${CMAKE_INSTALL_SBINDIR}) + +SET(REMOTE_ADDR 192.168.1.20) +ADD_CUSTOM_TARGET(upload + COMMAND scp ${CMAKE_BINARY_DIR}/urngd root@${REMOTE_ADDR}:/usr/sbin +) diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..86ffae7 --- /dev/null +++ b/Makefile @@ -0,0 +1,36 @@ +CC ?= gcc +CXX ?= g++ +CMAKE ?= cmake +CMAKE_BUILD_TYPE ?= Release + +define build_cross + -rm -fr build-$(2) + mkdir build-$(2) + cd build-$(2) && \ + $(CMAKE) \ + -D CMAKE_BUILD_TYPE=$(CMAKE_BUILD_TYPE) \ + -D CMAKE_TOOLCHAIN_FILE=cmake/$(1)-$(2).cmake \ + .. + make -j$$((nproc+1)) VERBOSE=$(VERBOSE) -C build-$(2) +endef + +.PHONY: imx6 ath79 + +all: + -rm -fr build + mkdir build + cd build && CC=$(CC) CXX=$(CXX) $(CMAKE) \ + -D CMAKE_BUILD_TYPE=$(CMAKE_BUILD_TYPE) \ + .. + make -j$$((nproc+1)) VERBOSE=$(VERBOSE) -C build + +imx6: + $(call build_cross,openwrt-toolchain,$@) + +ath79: + $(call build_cross,openwrt-toolchain,$@) + +clean: + @-rm -fr build* + +-include local.mk diff --git a/README.md b/README.md new file mode 100644 index 0000000..c7cf2d1 --- /dev/null +++ b/README.md @@ -0,0 +1,13 @@ +μrngd +===== + +μrngd is OpenWrt's micro non-physical true random number generator based on +timing jitter. + +Using the Jitter RNG core, the rngd provides an entropy source that feeds into +the Linux /dev/random device if its entropy runs low. It updates the /dev/random +entropy estimator such that the newly provided entropy unblocks /dev/random. + +The seeding of /dev/random also ensures that /dev/urandom benefits from entropy. +Especially during boot time, when the entropy of Linux is low, the Jitter RNGd +provides a source of sufficient entropy. diff --git a/cmake/openwrt-toolchain-ath79.cmake b/cmake/openwrt-toolchain-ath79.cmake new file mode 100644 index 0000000..411ffd3 --- /dev/null +++ b/cmake/openwrt-toolchain-ath79.cmake @@ -0,0 +1,20 @@ +SET(CMAKE_SYSTEM_NAME Linux) + +SET(OWRT_STAGING_DIR /opt/devel/openwrt/openwrt.git/staging_dir) +SET(OWRT_TARGET target-mips_24kc_musl) +SET(OWRT_TOOLCHAIN toolchain-mips_24kc_gcc-7.4.0_musl) +SET(OWRT_CROSS ${OWRT_STAGING_DIR}/${OWRT_TOOLCHAIN}/bin/mips-openwrt-linux-) + +SET(CMAKE_C_COMPILER ${OWRT_CROSS}gcc) +SET(CMAKE_CXX_COMPILER ${OWRT_CROSS}g++) + +SET(CMAKE_FIND_ROOT_PATH ${OWRT_STAGING_DIR}/${OWRT_TARGET}) + +SET(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) +SET(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) +SET(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) + +ADD_DEFINITIONS( + -Os -pipe -mno-branch-likely -mips32r2 -mtune=24kc -fno-caller-saves -fno-plt + -fhonour-copts -msoft-float -mips16 -minterlink-mips16 +) diff --git a/cmake/openwrt-toolchain-imx6.cmake b/cmake/openwrt-toolchain-imx6.cmake new file mode 100644 index 0000000..32ce656 --- /dev/null +++ b/cmake/openwrt-toolchain-imx6.cmake @@ -0,0 +1,17 @@ +SET(CMAKE_SYSTEM_NAME Linux) + +SET(OWRT_STAGING_DIR /opt/devel/openwrt/openwrt.git/staging_dir) +SET(OWRT_TARGET target-arm_cortex-a9+neon_musl_eabi) +SET(OWRT_TOOLCHAIN toolchain-arm_cortex-a9+neon_gcc-7.4.0_musl_eabi) +SET(OWRT_CROSS ${OWRT_STAGING_DIR}/${OWRT_TOOLCHAIN}/bin/arm-openwrt-linux-) + +SET(CMAKE_C_COMPILER ${OWRT_CROSS}gcc) +SET(CMAKE_CXX_COMPILER ${OWRT_CROSS}g++) + +SET(CMAKE_FIND_ROOT_PATH ${OWRT_STAGING_DIR}/${OWRT_TARGET}) + +SET(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) +SET(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) +SET(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) + +ADD_DEFINITIONS(-mcpu=cortex-a9 -mfpu=neon -g3 -fno-caller-saves -fhonour-copts -mfloat-abi=hard) diff --git a/log.h b/log.h new file mode 100644 index 0000000..b434001 --- /dev/null +++ b/log.h @@ -0,0 +1,34 @@ +/* + * Copyright (C) 2013 Felix Fietkau + * Copyright (C) 2013 John Crispin + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 2.1 + * as published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef __LOG_H +#define __LOG_H + +#include + +#ifdef URNGD_DEBUG +#define DEBUG(level, fmt, ...) do { \ + if (debug >= level) { \ + ulog(LOG_DEBUG, fmt, ## __VA_ARGS__); \ + } } while (0) +#else +#define DEBUG(level, fmt, ...) +#endif + +#define LOG ULOG_INFO +#define ERROR ULOG_ERR + +extern unsigned int debug; + +#endif diff --git a/urngd.c b/urngd.c new file mode 100644 index 0000000..8b9a762 --- /dev/null +++ b/urngd.c @@ -0,0 +1,243 @@ +/* + * Non-physical true random number generator based on timing jitter. + * + * Copyright Stephan Mueller , 2014 + * Copyright Petr Štetiar , 2019 + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, and the entire permission notice in its entirety, + * including the disclaimer of warranties. + * 2. 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. + * 3. The name of the author may not be used to endorse or promote + * products derived from this software without specific prior + * written permission. + * + * ALTERNATIVELY, this product may be distributed under the terms of + * the GNU General Public License, in which case the provisions of the GPL are + * required INSTEAD OF the above restrictions. (This clause is + * necessary due to a potential bad interaction between the GPL and + * the restrictions contained in a BSD-style copyright.) + * + * 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 +#include +#include + +#include +#include + +#include + +#include "log.h" +#include "jitterentropy.h" + +#define ENTROPYBYTES 32 +#define ENTROPYTHRESH 1024 +#define OVERSAMPLINGFACTOR 2 +#define DEV_RANDOM "/dev/random" +#define ENTROPYAVAIL "/proc/sys/kernel/random/entropy_avail" +#define ENTROPYPOOLBYTES (sizeof(struct rand_pool_info) + \ + (ENTROPYBYTES * OVERSAMPLINGFACTOR * sizeof(char))) + +#ifdef URNGD_DEBUG +unsigned int debug; +#endif + +struct urngd { + struct uloop_fd rnd_fd; + struct rand_data *ec; + struct rand_pool_info *rpi; +}; + +static struct urngd urngd_service; + +static inline void memset_secure(void *s, int c, size_t n) +{ + memset(s, c, n); + __asm__ __volatile__("" : : "r" (s) : "memory"); +} + +static size_t write_entropy(struct urngd *u, char *buf, size_t len, + size_t entropy_bytes) +{ + int ret; + size_t written = 0; + + /* value is in bits */ + u->rpi->entropy_count = (entropy_bytes * 8); + u->rpi->buf_size = len; + memcpy(u->rpi->buf, buf, len); + memset(buf, 0, len); + + ret = ioctl(u->rnd_fd.fd, RNDADDENTROPY, u->rpi); + if (0 > ret) { + ERROR("error injecting entropy: %s\n", strerror(errno)); + } else { + DEBUG(1, "injected %ub (%ub of entropy)\n", len, entropy_bytes); + written = len; + } + + u->rpi->entropy_count = 0; + u->rpi->buf_size = 0; + memset(u->rpi->buf, 0, len); + + return written; +} + +static size_t gather_entropy(struct urngd *u) +{ + size_t ret = 0; + char buf[(ENTROPYBYTES * OVERSAMPLINGFACTOR)]; + + if (jent_read_entropy(u->ec, buf, sizeof(buf)) < 0) { + ERROR("cannot read entropy\n"); + return 0; + } + + ret = write_entropy(u, buf, sizeof(buf), ENTROPYBYTES); + if (sizeof(buf) != ret) { + ERROR("injected %lub of entropy, less then %db expected\n", + ret, sizeof(buf)); + } else { + ret = sizeof(buf); + } + + memset_secure(buf, 0, sizeof(buf)); + DEBUG(2, DEV_RANDOM " fed with %lub of entropy\n", ret); + + return ret; +} + +static void low_entropy_cb(struct uloop_fd *ufd, unsigned int events) +{ + struct urngd *u = container_of(ufd, struct urngd, rnd_fd); + + DEBUG(2, DEV_RANDOM " signals low entropy\n"); + gather_entropy(u); +} + +static void urngd_done(struct urngd *u) +{ + if (u->ec) { + jent_entropy_collector_free(u->ec); + u->ec = NULL; + } + + if (u->rpi) { + memset(u->rpi, 0, ENTROPYPOOLBYTES); + free(u->rpi); + u->rpi = NULL; + } + + if (u->rnd_fd.fd) { + close(u->rnd_fd.fd); + u->rnd_fd.fd = 0; + } +} + +static bool urngd_init(struct urngd *u) +{ + int ret = jent_entropy_init(); + if (ret) { + ERROR("jent-rng init failed, err: %d\n", ret); + return false; + } + + u->ec = jent_entropy_collector_alloc(1, 0); + if (!u->ec) { + ERROR("jent-rng alloc failed\n"); + return false; + } + + u->rpi = malloc(ENTROPYPOOLBYTES); + if (!u->rpi) { + ERROR("rand pool alloc failed\n"); + return false; + } + + u->rnd_fd.cb = low_entropy_cb; + u->rnd_fd.fd = open(DEV_RANDOM, O_WRONLY); + if (u->rnd_fd.fd < 1) { + ERROR(DEV_RANDOM " open failed: %s", strerror(errno)); + return false; + } + + uloop_fd_add(&u->rnd_fd, ULOOP_READ); + + return true; +} + +static int usage(const char *prog) +{ + fprintf(stderr, "Usage: %s [options]\n" + "Options:\n" +#ifdef URNGD_DEBUG + " -d Enable debug messages\n" +#endif + " -S Print messages to stdout\n" + "\n", prog); + return 1; +} + +int main(int argc, char **argv) +{ + int ch; + int ulog_channels = ULOG_KMSG; +#ifdef URNGD_DEBUG + char *dbglvl = getenv("DBGLVL"); + + if (dbglvl) { + debug = atoi(dbglvl); + unsetenv("DBGLVL"); + } +#endif + + while ((ch = getopt(argc, argv, "d:S")) != -1) { + switch (ch) { +#ifdef URNGD_DEBUG + case 'd': + debug = atoi(optarg); + break; +#endif + case 'S': + ulog_channels = ULOG_STDIO; + break; + default: + return usage(argv[0]); + } + } + + if (!urngd_init(&urngd_service)) + return -1; + + ulog_open(ulog_channels, LOG_DAEMON, "urngd"); + LOG("v%s started.\n", URNGD_VERSION); + + gather_entropy(&urngd_service); + + uloop_init(); + uloop_run(); + uloop_done(); + + urngd_done(&urngd_service); + + return 0; +} -- 2.30.2