-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* keccak: KECCAK: README.md: extend description Makefile: add keccak/ KECCAK: Makefile: build and run Keccak tests KECCAK: main.cc: add benchmark and test cases for Keccak and auto_seed() KECCAK: testvectors.c: add all n*8 bit test vectors from ShortMsgKAT_0.txt KECCAK: keccak.cc: add KeccakRng::auto_seed() entropy gathering implementation KECCAK: keccak.hh: add 1600 bit Keccak sponge PRNG KECCAK: README.md: add readme with brief description Signed-off-by: Tim Janik <[email protected]>
- Loading branch information
Showing
7 changed files
with
1,199 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
# Dedicated to the Public Domain under the Unlicense: https://unlicense.org/UNLICENSE | ||
|
||
all: # Default Rule | ||
|
||
MAYBE_CLANG != clang++ --version 2>/dev/null | grep -q 'clang.* [1-9][0-9]\+\.' && echo clang++ | ||
CXX := $(if $(MAYBE_CLANG), $(MAYBE_CLANG), $(CXX)) | ||
OPTIMIZE := -O3 -march=native | ||
|
||
# == keccak == | ||
keccak: main.cc Makefile | ||
$(CXX) -std=gnu++17 -Wall $(OPTIMIZE) $< -o keccak | ||
keccak: keccak.hh keccak.cc | ||
clean: ; rm -f ./keccak | ||
all: keccak | ||
|
||
# == check == | ||
check: keccak | ||
./keccak --check | ||
|
||
# == dieharder == | ||
dieharder: keccak | ||
./keccak | dieharder -a -g 200 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
|
||
# Keccak PRNG Implementation | ||
|
||
The header file `keccak.hh` contains a Keccak sponge construction implementation for generic CPUs (ALU) | ||
in the `class scl::Keccak::class KeccakRng`. The implementation is are based on the original | ||
[Specification of Keccak](https://keccak.team/files/Keccak-reference-3.0.pdf) from 2011. | ||
The header file can be used on its own for cryptographic hashing via Keccak. | ||
|
||
However, the method `KeccakRng::auto_seed()` is implemented in the source file `keccak.cc`, it allows | ||
the use of a `KeccakRng` sponge as an entropy pool for cryptographically secure random seeds for other PRNGs. | ||
|
||
The code for `KeccakRng::auto_seed()` gathers entropy from various system sources such as | ||
`/dev/urandom`, `getrandom(2)`, `getentropy(3)`, `arc4random(3bsd)`, `RDTSC`, `RDRAND` and high precision clocks. | ||
The code performs detailed timing measurements to improve the quality of the gathered entropy, according to this | ||
paper from 2013 that deals with entropy gathering in embedded systems at boot time: | ||
[Welcome to the Entropics: Boot-Time Entropy in Embedded Devices](https://cseweb.ucsd.edu/~swanso/). | ||
The entropy pool uses `class KeccakRng` with 1600 bits of state, of which 576 are hidden bits, | ||
to guarantee cryptographically secure mixing. | ||
|
||
The source file `main.cc` contains random number generation examples, benchmarks and unit test code based | ||
on the Keccak test vectors. | ||
|
||
The source code is dedicated to the Public Domain under the [Unlicense](https://unlicense.org/UNLICENSE). | ||
|
||
|
||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,166 @@ | ||
// Dedicated to the Public Domain under the Unlicense: https://unlicense.org/UNLICENSE | ||
|
||
// #include "keccak.hh" | ||
#include <unistd.h> // getentropy | ||
#include <sys/random.h> // getrandom | ||
#include <stdlib.h> // arc4random | ||
#include <sys/time.h> // gettimeofday | ||
#include <time.h> // clock_gettime | ||
#include <random> // std::random_device | ||
#include <chrono> // std::chrono | ||
#include <sys/resource.h> // getrusage | ||
#if defined (__i386__) || defined (__x86_64__) | ||
# include <x86gprintrin.h> // __rdtsc | ||
#endif | ||
|
||
namespace scl::Keccak { | ||
|
||
static void | ||
seed_addtime (KeccakRng &pool) | ||
{ | ||
// Gather entropy from execution time fluctuations, see: | ||
// "Welcome to the Entropics: Boot-Time Entropy in Embedded Devices", | ||
// https://cseweb.ucsd.edu/~swanson/papers/Oakland2013EarlyEntropy.pdf | ||
std::array<uint64_t, 25> xw{}; | ||
#if defined (__i386__) || defined (__x86_64__) | ||
xw[0] = __rdtsc(); | ||
#endif | ||
xw[1] = std::chrono::steady_clock::now().time_since_epoch().count(); | ||
xw[2] = std::chrono::system_clock::now().time_since_epoch().count(); | ||
xw[3] = clock(); | ||
struct timeval timeval{}; | ||
gettimeofday (&timeval, nullptr); | ||
xw[4] = timeval.tv_sec; | ||
xw[5] = timeval.tv_usec; | ||
struct timespec ts{}; | ||
clock_gettime (CLOCK_REALTIME, &ts); | ||
xw[6] = ts.tv_sec; | ||
xw[7] = ts.tv_nsec; | ||
clock_gettime (CLOCK_MONOTONIC, &ts); | ||
xw[8] = ts.tv_sec; | ||
xw[9] = ts.tv_nsec; | ||
clock_gettime (CLOCK_PROCESS_CPUTIME_ID, &ts); | ||
xw[10] = ts.tv_sec; | ||
xw[11] = ts.tv_nsec; | ||
#if defined (__i386__) || defined (__x86_64__) | ||
xw[12] = __rdtsc(); | ||
#endif | ||
pool.update64 (xw.data(), xw.size(), false); | ||
} | ||
|
||
static bool | ||
seed_addfile (KeccakRng &pool, const char *filename, const size_t maxbytes = 200) | ||
{ | ||
FILE *file = fopen (filename, "r"); | ||
if (file) | ||
{ | ||
std::array<uint8_t, 200> xs{}; | ||
const size_t l = fread (xs.data(), 1, maxbytes < xs.size() ? maxbytes : xs.size(), file); | ||
fclose (file); | ||
pool.update (xs.data(), xs.size(), false); | ||
seed_addtime (pool); // execution timing | ||
return l > 0; | ||
} | ||
return false; | ||
} | ||
|
||
static void | ||
random_entropy (KeccakRng &pool) | ||
{ | ||
seed_addtime (pool); // execution timing | ||
|
||
std::array<uint64_t, 25> xw{}; // engouh state to feed Keccak1600 | ||
|
||
// Peek at C++ random_device | ||
if (true) { | ||
// std::random_device easily throws for non-default sources | ||
// also some impls reopen devices for every 32bit operator() call. | ||
std::random_device cpprd; | ||
static_assert (sizeof (cpprd()) == 4); | ||
xw[0] = cpprd() + (uint64_t (cpprd()) << 32); | ||
pool.update64 (xw.data(), xw.size(), false); | ||
seed_addtime (pool); // execution timing | ||
} | ||
|
||
// HW counter if any | ||
#if defined(__RDRND__) | ||
xw = std::array<uint64_t, 25>{}; | ||
for (size_t i = 0; i < xw.size(); i++) { | ||
unsigned long long ull = 0; | ||
__builtin_ia32_rdrand64_step (&ull); | ||
xw[i] = ull; | ||
} | ||
pool.update64 (xw.data(), xw.size(), false); | ||
seed_addtime (pool); // execution timing | ||
#endif | ||
|
||
xw = std::array<uint64_t, 25>{}; | ||
xw[0] = time (nullptr); | ||
xw[1] = getpid(); | ||
xw[2] = gettid(); | ||
xw[10] = std::ptrdiff_t (&xw[23]); // stack/thread location | ||
xw[11] = std::ptrdiff_t (&pool); // instance location | ||
xw[12] = std::ptrdiff_t (random_entropy); // code segment | ||
xw[13] = std::ptrdiff_t (&malloc); // libc segment | ||
pool.update64 (xw.data(), xw.size(), false); | ||
seed_addtime (pool); // execution timing | ||
|
||
// read from frequently changing files | ||
seed_addfile (pool, "/dev/urandom"); | ||
seed_addfile (pool, "/proc/stat"); | ||
seed_addfile (pool, "/proc/uptime"); | ||
seed_addfile (pool, "/proc/loadavg"); | ||
seed_addfile (pool, "/proc/softirqs"); | ||
seed_addfile (pool, "/proc/schedstat"); | ||
seed_addfile (pool, "/proc/diskstats"); | ||
seed_addfile (pool, "/proc/interrupts"); | ||
seed_addfile (pool, "/proc/sys/kernel/random/uuid"); | ||
// seed_addfile (pool, "/proc/vmstat"); | ||
// seed_addfile (pool, "/proc/meminfo"); | ||
// seed_addfile (pool, "/proc/zoneinfo"); | ||
|
||
std::array<uint8_t, 200> xs{}; // engouh state to feed Keccak1600 | ||
#if defined(__linux__) || defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__DragonFly__) | ||
auto const dummy1 [[maybe_unused]] = getrandom (xs.data(), xs.size(), GRND_NONBLOCK); | ||
pool.update (xs.data(), xs.size(), false); | ||
#endif | ||
|
||
#if defined(__linux__) || defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__DragonFly__) | ||
auto const dummy2 [[maybe_unused]] = getentropy (xs.data(), xs.size()); | ||
pool.update (xs.data(), xs.size(), false); | ||
#endif | ||
|
||
#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__DragonFly__) | ||
arc4random_buf (xs.data(), xs.size()); | ||
pool.update (xs.data(), xs.size(), false); | ||
#endif | ||
|
||
// process statistics | ||
union { | ||
uint8_t data[25 * 8]; | ||
struct { | ||
struct rusage rusage; // 144 bytes | ||
} stats; | ||
static_assert (sizeof (stats) <= sizeof (data)); | ||
} u = { { 0 }, }; | ||
getrusage (RUSAGE_SELF, &u.stats.rusage); | ||
pool.update (u.data, sizeof (u.data), false); | ||
|
||
seed_addtime (pool); // execution timing | ||
} | ||
|
||
/** Tap into various OS and runtime sources of entropy. | ||
* Gathering entropy from system and runtime sources may take a few microseconds | ||
* or milliseconds so it is recommended to call this once and use the KeccakRng | ||
* to reseed other PRNGs. | ||
*/ | ||
void | ||
KeccakRng::auto_seed() | ||
{ | ||
reset(); | ||
random_entropy (*this); | ||
update (nullptr, 0, false); // finalize | ||
keccak1600_permute (state_.A, 37); | ||
} | ||
|
||
} // scl::Keccak |
Oops, something went wrong.