Remove randombytes from 3rdparty

pull/647/head
Jonathan G Rennison 4 months ago
parent f966153ae2
commit e8c17f634b

@ -7,7 +7,6 @@ add_subdirectory(squirrel)
add_subdirectory(nlohmann)
add_subdirectory(opengl)
add_subdirectory(cpp-btree)
add_subdirectory(randombytes)
add_subdirectory(robin_hood)
if (MINGW AND OPTION_MINGW_STDTHREADS)

@ -1,4 +0,0 @@
add_files(
randombytes.h
randombytes.c
)

@ -1,21 +0,0 @@
The MIT License
Copyright (c) 2017 Daan Sprenkels <hello@dsprenkels.com>
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

@ -1,88 +0,0 @@
# Pluggable randombytes function
[![Travis-CI](https://travis-ci.org/dsprenkels/sss.svg?branch=master)](https://travis-ci.org/dsprenkels/randombytes)
[![Appveyor](https://ci.appveyor.com/api/projects/status/github/dsprenkels/randombytes?branch=master&svg=true)](https://ci.appveyor.com/project/dsprenkels/randombytes)
`randombytes` is a library that exposes a single function for retrieving
_crypto-secure_ random bytes. It is loosely based on [Libsodium's random bytes
API][libsodium_randombytes]. If you can, you should use that one. Otherwise, you
can use this library.
## Usage
`randombytes` takes two arguments:
1. A pointer to the buffer
2. The length of the buffer in bytes
The function will always return an `int` which will be `0` on success. The
caller _must_ check this. If some kind of error occured, `errno` MAY contain a
hint to what the error was, and a subsequent call to the `randombytes` function
MAY succeed. An example of when the function may fail is when `/dev/urandom`
could not be opened, because there were no file descriptors left to use for the
process.
On sensible systems (like the ones with `arc4random`) the latency is very low.
However, this is totally not guaranteed. Do not expect this function to be very
fast. Benchmark for your specific setup, and use a fast CSPRNG if you need.
Example code:
```c
#include "randombytes.h"
#include <inttypes.h>
#include <stdio.h>
int main()
{
// Generate some random bytes and print them in hex
int ret;
uint8_t buf[20];
size_t i;
ret = randombytes(&buf[0], sizeof(buf));
if (ret != 0) {
printf("Error in `randombytes`");
return 1;
}
for (i = 0; i < sizeof(buf); ++i) {
printf("%02hhx", buf[i]);
}
printf("\n");
return 0;
}
```
## How secure is it really?
While building this I keep one rule of thumb which is: **Trust the OS**.
Most OS'es implement a secure random generator, which is seeded by a good
entropy source. We will always use this random source. This essentially means
that the implementation is highly platform-dependent. For example we use
`getrandom` on Linux and `arc4random` on BSD systems.
### What if the OS's random generator is bad?
If you are dealing with an OS that has a compromised random generator you are
out of luck. The reason why you cannot generate high quality random data from
userspace is that userspace is made so that everything is too deterministic.
A secure random generator needs a good source of entropy, such as 2.4 GHz noise
or the user's mouse movements. Collecting these kinds of events only works well
when working on the lowest level.
## Questions
### It does not compile on my platform!
[Please open an issue.](https://github.com/dsprenkels/randombytes/issues/new)
If possible I will try to make a `randombytes` implementation for your platform.
### Do you have bindings for language _x_?
No, your language probably already has a random source. Use that one.
### Other
Feel free to send me an email on my Github associated e-mail address.
[libsodium_randombytes]: https://github.com/jedisct1/libsodium/blob/master/src/libsodium/randombytes/sysrandom/randombytes_sysrandom.c

@ -1,339 +0,0 @@
// In the case that are compiling on linux, we need to define _GNU_SOURCE
// *before* randombytes.h is included. Otherwise SYS_getrandom will not be
// declared.
#if defined(__linux__)
# define _GNU_SOURCE
#endif /* defined(__linux__) */
#include "randombytes.h"
#if defined(_WIN32)
/* Windows */
# include <windows.h>
# include <wincrypt.h> /* CryptAcquireContext, CryptGenRandom */
#endif /* defined(_WIN32) */
/* wasi */
#if defined(__wasi__)
#include <stdlib.h>
#endif
#if defined(__linux__)
/* Linux */
// We would need to include <linux/random.h>, but not every target has access
// to the linux headers. We only need RNDGETENTCNT, so we instead inline it.
// RNDGETENTCNT is originally defined in `include/uapi/linux/random.h` in the
// linux repo.
# define RNDGETENTCNT 0x80045200
# include <assert.h>
# include <errno.h>
# include <fcntl.h>
# include <poll.h>
# include <stdint.h>
# include <stdio.h>
# include <sys/ioctl.h>
# if defined(__linux__) && defined(__GLIBC__) && ((__GLIBC__ > 2) || (__GLIBC_MINOR__ > 24))
# define USE_GLIBC
# include <sys/random.h>
# endif /* defined(__linux__) && defined(__GLIBC__) && ((__GLIBC__ > 2) || (__GLIBC_MINOR__ > 24)) */
# include <sys/stat.h>
# include <sys/syscall.h>
# include <sys/types.h>
# include <unistd.h>
// We need SSIZE_MAX as the maximum read len from /dev/urandom
# if !defined(SSIZE_MAX)
# define SSIZE_MAX (SIZE_MAX / 2 - 1)
# endif /* defined(SSIZE_MAX) */
#endif /* defined(__linux__) */
#if defined(__unix__) || (defined(__APPLE__) && defined(__MACH__))
/* Dragonfly, FreeBSD, NetBSD, OpenBSD (has arc4random) */
# include <sys/param.h>
# if defined(BSD)
# include <stdlib.h>
# endif
#endif
#if defined(__EMSCRIPTEN__)
# include <assert.h>
# include <emscripten.h>
# include <errno.h>
# include <stdbool.h>
#endif /* defined(__EMSCRIPTEN__) */
#if defined(_WIN32)
static int randombytes_win32_randombytes(void* buf, const size_t n)
{
HCRYPTPROV ctx;
BOOL tmp;
tmp = CryptAcquireContext(&ctx, NULL, NULL, PROV_RSA_FULL,
CRYPT_VERIFYCONTEXT);
if (tmp == FALSE) return -1;
tmp = CryptGenRandom(ctx, (DWORD)n, (BYTE*) buf);
if (tmp == FALSE) return -1;
tmp = CryptReleaseContext(ctx, 0);
if (tmp == FALSE) return -1;
return 0;
}
#endif /* defined(_WIN32) */
#if defined(__wasi__)
static int randombytes_wasi_randombytes(void *buf, size_t n) {
arc4random_buf(buf, n);
return 0;
}
#endif /* defined(__wasi__) */
#if defined(__linux__) && (defined(USE_GLIBC) || defined(SYS_getrandom))
# if defined(USE_GLIBC)
// getrandom is declared in glibc.
# elif defined(SYS_getrandom)
static ssize_t getrandom(void *buf, size_t buflen, unsigned int flags) {
return syscall(SYS_getrandom, buf, buflen, flags);
}
# endif
static int randombytes_linux_randombytes_getrandom(void *buf, size_t n)
{
/* I have thought about using a separate PRF, seeded by getrandom, but
* it turns out that the performance of getrandom is good enough
* (250 MB/s on my laptop).
*/
size_t offset = 0, chunk;
int ret;
while (n > 0) {
/* getrandom does not allow chunks larger than 33554431 */
chunk = n <= 33554431 ? n : 33554431;
do {
ret = getrandom((char *)buf + offset, chunk, 0);
} while (ret == -1 && errno == EINTR);
if (ret < 0) return ret;
offset += ret;
n -= ret;
}
assert(n == 0);
return 0;
}
#endif // defined(__linux__) && (defined(USE_GLIBC) || defined(SYS_getrandom))
#if defined(__linux__) && !defined(SYS_getrandom)
static int randombytes_linux_read_entropy_ioctl(int device, int *entropy)
{
return ioctl(device, RNDGETENTCNT, entropy);
}
static int randombytes_linux_read_entropy_proc(FILE *stream, int *entropy)
{
int retcode;
do {
rewind(stream);
retcode = fscanf(stream, "%d", entropy);
} while (retcode != 1 && errno == EINTR);
if (retcode != 1) {
return -1;
}
return 0;
}
static int randombytes_linux_wait_for_entropy(int device)
{
/* We will block on /dev/random, because any increase in the OS' entropy
* level will unblock the request. I use poll here (as does libsodium),
* because we don't *actually* want to read from the device. */
enum { IOCTL, PROC } strategy = IOCTL;
const int bits = 128;
struct pollfd pfd;
int fd;
FILE *proc_file;
int retcode, retcode_error = 0; // Used as return codes throughout this function
int entropy = 0;
/* If the device has enough entropy already, we will want to return early */
retcode = randombytes_linux_read_entropy_ioctl(device, &entropy);
// printf("errno: %d (%s)\n", errno, strerror(errno));
if (retcode != 0 && (errno == ENOTTY || errno == ENOSYS)) {
// The ioctl call on /dev/urandom has failed due to a
// - ENOTTY (unsupported action), or
// - ENOSYS (invalid ioctl; this happens on MIPS, see #22).
//
// We will fall back to reading from
// `/proc/sys/kernel/random/entropy_avail`. This less ideal,
// because it allocates a file descriptor, and it may not work
// in a chroot. But at this point it seems we have no better
// options left.
strategy = PROC;
// Open the entropy count file
proc_file = fopen("/proc/sys/kernel/random/entropy_avail", "r");
} else if (retcode != 0) {
// Unrecoverable ioctl error
return -1;
}
if (entropy >= bits) {
return 0;
}
do {
fd = open("/dev/random", O_RDONLY);
} while (fd == -1 && errno == EINTR); /* EAGAIN will not occur */
if (fd == -1) {
/* Unrecoverable IO error */
return -1;
}
pfd.fd = fd;
pfd.events = POLLIN;
for (;;) {
retcode = poll(&pfd, 1, -1);
if (retcode == -1 && (errno == EINTR || errno == EAGAIN)) {
continue;
} else if (retcode == 1) {
if (strategy == IOCTL) {
retcode = randombytes_linux_read_entropy_ioctl(device, &entropy);
} else if (strategy == PROC) {
retcode = randombytes_linux_read_entropy_proc(proc_file, &entropy);
} else {
return -1; // Unreachable
}
if (retcode != 0) {
// Unrecoverable I/O error
retcode_error = retcode;
break;
}
if (entropy >= bits) {
break;
}
} else {
// Unreachable: poll() should only return -1 or 1
retcode_error = -1;
break;
}
}
do {
retcode = close(fd);
} while (retcode == -1 && errno == EINTR);
if (strategy == PROC) {
do {
retcode = fclose(proc_file);
} while (retcode == -1 && errno == EINTR);
}
if (retcode_error != 0) {
return retcode_error;
}
return retcode;
}
static int randombytes_linux_randombytes_urandom(void *buf, size_t n)
{
int fd;
size_t offset = 0, count;
ssize_t tmp;
do {
fd = open("/dev/urandom", O_RDONLY);
} while (fd == -1 && errno == EINTR);
if (fd == -1) return -1;
if (randombytes_linux_wait_for_entropy(fd) == -1) return -1;
while (n > 0) {
count = n <= SSIZE_MAX ? n : SSIZE_MAX;
tmp = read(fd, (char *)buf + offset, count);
if (tmp == -1 && (errno == EAGAIN || errno == EINTR)) {
continue;
}
if (tmp == -1) return -1; /* Unrecoverable IO error */
offset += tmp;
n -= tmp;
}
close(fd);
assert(n == 0);
return 0;
}
#endif /* defined(__linux__) && !defined(SYS_getrandom) */
#if defined(BSD)
static int randombytes_bsd_randombytes(void *buf, size_t n)
{
arc4random_buf(buf, n);
return 0;
}
#endif /* defined(BSD) */
#if defined(__EMSCRIPTEN__)
static int randombytes_js_randombytes_nodejs(void *buf, size_t n) {
const int ret = EM_ASM_INT({
var crypto;
try {
crypto = require('crypto');
} catch (error) {
return -2;
}
try {
writeArrayToMemory(crypto.randomBytes($1), $0);
return 0;
} catch (error) {
return -1;
}
}, buf, n);
switch (ret) {
case 0:
return 0;
case -1:
errno = EINVAL;
return -1;
case -2:
default:
errno = ENOSYS;
return -1;
}
}
#endif /* defined(__EMSCRIPTEN__) */
int randombytes(void *buf, size_t n)
{
#if defined(__EMSCRIPTEN__)
// # pragma message("Using crypto api from NodeJS")
return randombytes_js_randombytes_nodejs(buf, n);
#elif defined(__linux__)
# if defined(USE_GLIBC)
// # pragma message("Using getrandom function call")
/* Use getrandom system call */
return randombytes_linux_randombytes_getrandom(buf, n);
# elif defined(SYS_getrandom)
// # pragma message("Using getrandom system call")
/* Use getrandom system call */
return randombytes_linux_randombytes_getrandom(buf, n);
# else
// # pragma message("Using /dev/urandom device")
/* When we have enough entropy, we can read from /dev/urandom */
return randombytes_linux_randombytes_urandom(buf, n);
# endif
#elif defined(BSD)
// # pragma message("Using arc4random system call")
/* Use arc4random system call */
return randombytes_bsd_randombytes(buf, n);
#elif defined(_WIN32)
// # pragma message("Using Windows cryptographic API")
/* Use windows API */
return randombytes_win32_randombytes(buf, n);
#elif defined(__wasi__)
// # pragma message("Using WASI arc4random_buf system call")
/* Use WASI */
return randombytes_wasi_randombytes(buf, n);
#else
# error "randombytes(...) is not supported on this platform"
#endif
}

@ -1,25 +0,0 @@
#ifndef sss_RANDOMBYTES_H
#define sss_RANDOMBYTES_H
#ifdef __cplusplus
extern "C" {
#endif
#ifdef _WIN32
/* Load size_t on windows */
#include <crtdefs.h>
#else
#include <unistd.h>
#endif /* _WIN32 */
/*
* Write `n` bytes of high quality random bytes to `buf`
*/
int randombytes(void *buf, size_t n);
#ifdef __cplusplus
}
#endif
#endif /* sss_RANDOMBYTES_H */
Loading…
Cancel
Save