Compare commits

..

5 Commits

5 changed files with 837 additions and 2282 deletions

2232
bigint.h

File diff suppressed because it is too large Load Diff

View File

@@ -20,7 +20,7 @@
* - SLOWCRYPT_CHACHA20_IMPL * - SLOWCRYPT_CHACHA20_IMPL
* - SLOWCRYPT_CHACHA20_FUNC * - SLOWCRYPT_CHACHA20_FUNC
* will be used in front of every function definition / declaration * will be used in front of every function definition / declaration
* - SLOWCRYPT_CHACHA20_UINT32 * - uint32_t
* if this is not set, will include <stdint.h>, and use `uint32_t` * if this is not set, will include <stdint.h>, and use `uint32_t`
* *
* *
@@ -90,10 +90,7 @@
extern "C" { extern "C" {
#endif #endif
#ifndef SLOWCRYPT_CHACHA20_UINT32
#include <stdint.h> #include <stdint.h>
#define SLOWCRYPT_CHACHA20_UINT32 uint32_t
#endif
#ifndef SLOWCRYPT_CHACHA20_FUNC #ifndef SLOWCRYPT_CHACHA20_FUNC
#define SLOWCRYPT_CHACHA20_FUNC /**/ #define SLOWCRYPT_CHACHA20_FUNC /**/
@@ -101,7 +98,7 @@ extern "C" {
typedef struct typedef struct
{ {
SLOWCRYPT_CHACHA20_UINT32 state[16]; uint32_t state[16];
} slowcrypt_chacha20; } slowcrypt_chacha20;
/* /*
@@ -111,46 +108,36 @@ typedef struct
*/ */
SLOWCRYPT_CHACHA20_FUNC void slowcrypt_chacha20_block( SLOWCRYPT_CHACHA20_FUNC void slowcrypt_chacha20_block(
slowcrypt_chacha20 state[2], slowcrypt_chacha20 state[2],
char const key[32], uint8_t const key[32],
SLOWCRYPT_CHACHA20_UINT32 block_ctr, uint32_t block_ctr,
char const nonce[12], uint8_t const nonce[12],
char data[64]); uint8_t data[64]);
/* call this to zero out memory */ /* call this to zero out memory */
SLOWCRYPT_CHACHA20_FUNC void slowcrypt_chacha20_deinit( SLOWCRYPT_CHACHA20_FUNC void slowcrypt_chacha20_deinit(
slowcrypt_chacha20* state); slowcrypt_chacha20* state);
SLOWCRYPT_CHACHA20_FUNC void slowcrypt_chacha20_init( SLOWCRYPT_CHACHA20_FUNC void slowcrypt_chacha20_init(slowcrypt_chacha20* state,
slowcrypt_chacha20* state, uint8_t const key[32],
char const key[32], uint32_t block_ctr,
SLOWCRYPT_CHACHA20_UINT32 block_ctr, uint8_t const nonce[12]);
char const nonce[12]);
SLOWCRYPT_CHACHA20_FUNC void slowcrypt_chacha20_serialize( SLOWCRYPT_CHACHA20_FUNC void slowcrypt_chacha20_serialize(
char buf[64], uint8_t buf[64],
slowcrypt_chacha20 const* state); slowcrypt_chacha20 const* state);
SLOWCRYPT_CHACHA20_FUNC void slowcrypt_chacha20_serialize_xor( SLOWCRYPT_CHACHA20_FUNC void slowcrypt_chacha20_serialize_xor(
char buf[64], uint8_t buf[64],
slowcrypt_chacha20 const* state); slowcrypt_chacha20 const* state);
SLOWCRYPT_CHACHA20_FUNC void slowcrypt_chacha20_run(slowcrypt_chacha20* state, SLOWCRYPT_CHACHA20_FUNC void slowcrypt_chacha20_run(slowcrypt_chacha20* state,
slowcrypt_chacha20* swap, slowcrypt_chacha20* swap,
int num_rounds); int num_rounds);
SLOWCRYPT_CHACHA20_FUNC SLOWCRYPT_CHACHA20_UINT32 #define SLOWCRYPT_CHACHA20_LAST32(n, bits) (((uint32_t)(n)) >> (32 - (bits)))
slowcrypt_chacha20_read_ul32(char const* buf);
SLOWCRYPT_CHACHA20_FUNC void slowcrypt_chacha20_write_ul32( #define SLOWCRYPT_CHACHA20_ROL32(n, by) \
char* buf, ((((uint32_t)(n)) << (by)) | SLOWCRYPT_CHACHA20_LAST32((n), (by)))
SLOWCRYPT_CHACHA20_UINT32 val);
#define SLOWCRYPT_CHACHA20_LAST32(n, bits) \
(((SLOWCRYPT_CHACHA20_UINT32)(n)) >> (32 - (bits)))
#define SLOWCRYPT_CHACHA20_ROL32(n, by) \
((((SLOWCRYPT_CHACHA20_UINT32)(n)) << (by)) | \
SLOWCRYPT_CHACHA20_LAST32((n), (by)))
#define SLOWCRYPT_CHACHA20_QROUND(state, a, b, c, d) \ #define SLOWCRYPT_CHACHA20_QROUND(state, a, b, c, d) \
do { \ do { \
@@ -181,20 +168,16 @@ SLOWCRYPT_CHACHA20_FUNC void slowcrypt_chacha20_deinit(
*(volatile int*)&state->state[i] = 0; *(volatile int*)&state->state[i] = 0;
} }
SLOWCRYPT_CHACHA20_FUNC SLOWCRYPT_CHACHA20_UINT32 static uint32_t slowcrypt_chacha20_read_ul32(uint8_t const* buf)
slowcrypt_chacha20_read_ul32(char const* buf)
{ {
SLOWCRYPT_CHACHA20_UINT32 o = uint32_t o = (uint32_t)((uint8_t const*)buf)[0];
(SLOWCRYPT_CHACHA20_UINT32)((uint8_t const*)buf)[0]; o |= (uint32_t)((uint8_t const*)buf)[1] << 8;
o |= (SLOWCRYPT_CHACHA20_UINT32)((uint8_t const*)buf)[1] << 8; o |= (uint32_t)((uint8_t const*)buf)[2] << 16;
o |= (SLOWCRYPT_CHACHA20_UINT32)((uint8_t const*)buf)[2] << 16; o |= (uint32_t)((uint8_t const*)buf)[3] << 24;
o |= (SLOWCRYPT_CHACHA20_UINT32)((uint8_t const*)buf)[3] << 24;
return o; return o;
} }
SLOWCRYPT_CHACHA20_FUNC void slowcrypt_chacha20_write_ul32( static void slowcrypt_chacha20_write_ul32(uint8_t* buf, uint32_t val)
char* buf,
SLOWCRYPT_CHACHA20_UINT32 val)
{ {
((uint8_t*)buf)[0] = (uint8_t)(val & 0xFF); ((uint8_t*)buf)[0] = (uint8_t)(val & 0xFF);
((uint8_t*)buf)[1] = (uint8_t)((val >> 8) & 0xFF); ((uint8_t*)buf)[1] = (uint8_t)((val >> 8) & 0xFF);
@@ -202,11 +185,10 @@ SLOWCRYPT_CHACHA20_FUNC void slowcrypt_chacha20_write_ul32(
((uint8_t*)buf)[3] = (uint8_t)((val >> 24) & 0xFF); ((uint8_t*)buf)[3] = (uint8_t)((val >> 24) & 0xFF);
} }
SLOWCRYPT_CHACHA20_FUNC void slowcrypt_chacha20_init( SLOWCRYPT_CHACHA20_FUNC void slowcrypt_chacha20_init(slowcrypt_chacha20* state,
slowcrypt_chacha20* state, uint8_t const key[32],
char const key[32], uint32_t block_ctr,
SLOWCRYPT_CHACHA20_UINT32 block_ctr, uint8_t const nonce[12])
char const nonce[12])
{ {
int i; int i;
@@ -225,7 +207,7 @@ SLOWCRYPT_CHACHA20_FUNC void slowcrypt_chacha20_init(
} }
SLOWCRYPT_CHACHA20_FUNC void slowcrypt_chacha20_serialize( SLOWCRYPT_CHACHA20_FUNC void slowcrypt_chacha20_serialize(
char buf[64], uint8_t buf[64],
slowcrypt_chacha20 const* state) slowcrypt_chacha20 const* state)
{ {
int i; int i;
@@ -234,10 +216,10 @@ SLOWCRYPT_CHACHA20_FUNC void slowcrypt_chacha20_serialize(
} }
SLOWCRYPT_CHACHA20_FUNC void slowcrypt_chacha20_serialize_xor( SLOWCRYPT_CHACHA20_FUNC void slowcrypt_chacha20_serialize_xor(
char buf[64], uint8_t buf[64],
slowcrypt_chacha20 const* state) slowcrypt_chacha20 const* state)
{ {
char swp[4]; uint8_t swp[4];
int i, j; int i, j;
for (i = 0; i < 16; i++) { for (i = 0; i < 16; i++) {
@@ -245,6 +227,9 @@ SLOWCRYPT_CHACHA20_FUNC void slowcrypt_chacha20_serialize_xor(
for (j = 0; j < 4; j++) for (j = 0; j < 4; j++)
buf[i * 4 + j] ^= swp[j]; buf[i * 4 + j] ^= swp[j];
} }
for (i = 0; i < 4; i++)
swp[i] = 0;
} }
SLOWCRYPT_CHACHA20_FUNC void slowcrypt_chacha20_run(slowcrypt_chacha20* state, SLOWCRYPT_CHACHA20_FUNC void slowcrypt_chacha20_run(slowcrypt_chacha20* state,
@@ -278,10 +263,10 @@ SLOWCRYPT_CHACHA20_FUNC void slowcrypt_chacha20_run(slowcrypt_chacha20* state,
SLOWCRYPT_CHACHA20_FUNC void slowcrypt_chacha20_block( SLOWCRYPT_CHACHA20_FUNC void slowcrypt_chacha20_block(
slowcrypt_chacha20 state[2], slowcrypt_chacha20 state[2],
char const key[32], uint8_t const key[32],
SLOWCRYPT_CHACHA20_UINT32 block_ctr, uint32_t block_ctr,
char const nonce[12], uint8_t const nonce[12],
char data[64]) uint8_t data[64])
{ {
slowcrypt_chacha20_init(state, key, block_ctr, nonce); slowcrypt_chacha20_init(state, key, block_ctr, nonce);
slowcrypt_chacha20_run(state, &state[1], 20); slowcrypt_chacha20_run(state, &state[1], 20);

179
poly1305.h Normal file
View File

@@ -0,0 +1,179 @@
#ifndef SLOWCRYPT_POLY1305_H
#define SLOWCRYPT_POLY1305_H
#ifndef SLOWCRYPT_POLY1305_FUNC
#define SLOWCRYPT_POLY1305_FUNC /**/
#endif
#ifndef SLOWCRYPT_POLY1305_DONT_USE_BITINT
#include <limits.h>
#ifdef BITINT_MAXWIDTH
#if BITINT_MAXWIDTH >= 264
#define SLOWCRYPT_POLY1305_USE_BITINT
#endif
#elif defined(__BITINT_MAXWIDTH__)
#if __BITINT_MAXWIDTH__ >= 264
#define SLOWCRYPT_POLY1305_USE_BITINT
#endif
#endif
#endif
#ifdef SLOWCRYPT_POLY1305_USE_BITINT
#else
ERROR NOT YET IMPLEMENTED;
#ifdef SLOWCRYPT_POLY1305_IMPL
#define BIGINT_IMPLEMENTATION
#endif
#define BIGINT_FUNC SLOWCRYPT_POLY1305_FUNC
#define BIGINT_NAMESPACE(x) slowcrypt_poly1305_bigint_##x
#define BIGINT_UNDEF
#define BIGINT_NO_MALLOC
#define BIGINT_DEFAULT_LIMIT 33
#define BIGINT_WORD_WIDTH 1
#endif
#include <stdint.h>
typedef struct
{
#ifdef SLOWCRYPT_POLY1305_USE_BITINT
unsigned _BitInt(128) r, s;
unsigned _BitInt(136) acc;
unsigned _BitInt(264) prod;
#else
slowcrypt_poly1305_bigint_bigint r, s, acc, p, temp1, temp2;
#endif
} slowcrypt_poly1305;
/* the key buffer will be destroyed: used as scratch buffer */
SLOWCRYPT_POLY1305_FUNC void slowcrypt_poly1305_init(slowcrypt_poly1305* p,
uint8_t key[32]);
/* only the last block is allowed to be shorter than 16 bytes!
*
* length has to be maximum 16
*/
SLOWCRYPT_POLY1305_FUNC void slowcrypt_poly1305_next_block(
slowcrypt_poly1305* p,
uint8_t const* data,
unsigned int length);
/* also zeroizes memory */
SLOWCRYPT_POLY1305_FUNC void slowcrypt_poly1305_finish(slowcrypt_poly1305* p,
uint8_t out[16]);
#ifdef SLOWCRYPT_POLY1305_IMPL
#ifdef SLOWCRYPT_POLY1305_USE_BITINT
static unsigned _BitInt(136) slowcrypt_poly1305_from_le(uint8_t const* buf,
unsigned int buf_len,
uint8_t top)
{
unsigned int i;
unsigned _BitInt(136) out = (unsigned _BitInt(136))top << (buf_len * 8);
for (i = 0; i < buf_len; i++)
out |= (unsigned _BitInt(136))buf[i] << (i * 8);
return out;
}
SLOWCRYPT_POLY1305_FUNC void slowcrypt_poly1305_init(slowcrypt_poly1305* p,
uint8_t key[32])
{
key[3] &= 15;
key[7] &= 15;
key[11] &= 15;
key[15] &= 15;
key[4] &= 252;
key[8] &= 252;
key[12] &= 252;
p->r = (unsigned _BitInt(128))slowcrypt_poly1305_from_le(key, 16, 0);
p->s = (unsigned _BitInt(128))slowcrypt_poly1305_from_le(&key[16], 16, 0);
p->acc = 0;
}
SLOWCRYPT_POLY1305_FUNC void slowcrypt_poly1305_next_block(
slowcrypt_poly1305* p,
uint8_t const* data,
unsigned int length)
{
if (length == 0)
return;
p->prod = p->acc + slowcrypt_poly1305_from_le(data, length, 0x01);
p->prod *= p->r;
p->prod %= ((unsigned _BitInt(136))1 << 130) - (unsigned _BitInt(136))5;
p->acc = p->prod;
}
SLOWCRYPT_POLY1305_FUNC void slowcrypt_poly1305_finish(slowcrypt_poly1305* p,
uint8_t out[16])
{
unsigned int i;
p->acc += p->s;
for (i = 0; i < 16; i++)
out[i] = (uint8_t)((p->acc >> (i * 8)));
for (i = 0; i < sizeof(slowcrypt_poly1305); i++)
((char*)p)[i] = 0;
}
#else
static void slowcrypt_poly1305_from_le(slowcrypt_poly1305_bigint_bigint* out,
slowcrypt_poly1305_bigint_bigint* temp,
uint8_t const* buf,
unsigned int buf_len,
uint8_t top)
{
slowcrypt_poly1305_bigint_from_u8(temp, top);
for (; buf_len-- > 0; buf++) {
slowcrypt_poly1305_bigint_from_u8(temp, *buf);
slowcrypt_poly1305_bigint_lshift_overwrite(out, 8);
slowcrypt_poly1305_bigint_inc(out, temp);
}
}
SLOWCRYPT_POLY1305_FUNC void slowcrypt_poly1305_init(slowcrypt_poly1305* p,
uint8_t key[32])
{
(void)slowcrypt_poly1305_bigint_from_cstring(
&p->p, "3fffffffffffffffffffffffffffffffb", 16);
key[3] &= 15;
key[7] &= 15;
key[11] &= 15;
key[15] &= 15;
key[4] &= 252;
key[8] &= 252;
key[12] &= 252;
slowcrypt_poly1305_from_le(&p->r, &p->temp1, key, 16, 0);
slowcrypt_poly1305_from_le(&p->s, &p->temp1, &key[16], 16, 0);
}
/* only the last block is allowed to be shorter than 16 bytes! */
SLOWCRYPT_POLY1305_FUNC void slowcrypt_poly1305_next_block(
slowcrypt_poly1305* p,
uint8_t const* data,
unsigned int length)
{
if (length == 0)
return;
slowcrypt_poly1305_from_le(&p->temp1, &p->temp2, data, length, 0x01);
slowcrypt_poly1305_bigint_inc(&p->acc, &p->temp1);
slowcrypt_poly1305_bigint_mul(&p->acc, &p->acc, &p->r);
slowcrypt_poly1305_bigint_div_mod(&p->temp1, &p->acc, &p->acc, &p->p);
}
SLOWCRYPT_POLY1305_FUNC void slowcrypt_poly1305_finish(slowcrypt_poly1305* p,
uint8_t out[16])
{
unsigned int i;
slowcrypt_poly1305_bigint_inc(&p->acc, &p->s);
for (i = 0; i < 16; i++)
out[i] = p->acc.words[i];
for (i = 0; i < sizeof(slowcrypt_poly1305); i++)
((char*)p)[i] = 0;
}
#endif
#endif
#endif

448
slowcrypt/slowcrypt.c Normal file
View File

@@ -0,0 +1,448 @@
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define SLOWCRYPT_CHACHA20_IMPL
#include "../chacha20.h"
#define SLOWCRYPT_POLY1305_IMPL
#include "../poly1305.h"
#define SLOWCRYPT_SYSTEMRAND_IMPL
#include "../systemrand.h"
struct algo
{
char const* name;
void (*run)(char**);
};
static FILE* file_open(char const* path)
{
FILE* fp;
if (!strcmp(path, "-"))
return stdin;
fp = fopen(path, "rb");
if (!fp) {
fprintf(stderr, "Could not open %s\n", path);
exit(1);
}
return fp;
}
static void file_close(FILE* p)
{
if (!p)
return;
if (p == stdout || p == stdin || p == stderr)
return;
fclose(p);
}
static int anyeq__impl(char const* str, char const** opts)
{
for (; *opts; opts++)
if (!strcmp(str, *opts))
return 1;
return 0;
}
#define anyeq(str, ...) anyeq__impl(str, (char const*[]){__VA_ARGS__, 0})
static char const* parse_hex_prefix(char const* msg)
{
if (*msg == 'h')
msg++;
else if (msg[0] == '0' && msg[1] == 'x')
msg++;
return msg;
}
static uint8_t parse_hex_nibble(char c)
{
if (c >= '0' && c <= '9')
return c - '0';
if (c >= 'a' && c <= 'f')
return c - 'a' + 0xA;
if (c >= 'A' && c <= 'F')
return c - 'A' + 0xA;
fprintf(stderr, "Not a hexadecimal number!\n");
exit(1);
}
static uint8_t parse_hex(char const** msg)
{
uint8_t res = parse_hex_nibble(*(*msg)++);
if (**msg) {
res <<= 4;
res |= parse_hex_nibble(*(*msg)++);
}
return res;
}
static void parse_hex2buf(uint8_t* buf,
unsigned int buflen,
char const* label,
char const* hex)
{
unsigned int num = 0;
hex = parse_hex_prefix(hex);
for (; num < buflen && *hex; num++)
buf[num] = parse_hex(&hex);
if (num != buflen || *hex) {
fprintf(stderr, "Expected %s to be %u (hexadecimal) bytes!\n", label,
buflen);
exit(1);
}
}
static unsigned long file_read_chunk(FILE* file,
uint8_t* buf,
unsigned long buflen)
{
unsigned long n;
if (feof(file))
return 0;
n = fread(buf, 1, buflen, file);
if (ferror(file)) {
fprintf(stderr, "File read error!");
exit(1);
}
return n;
}
static void run_chacha20_core(char** args)
{
static char const help[] =
"chacha20-core <key> <counter> <nonce>\n"
"\n"
"Run the ChaCha20 block function\n";
char const *key, *nonce;
unsigned int npos = 0;
unsigned int nb;
unsigned long lu;
uint32_t counter;
slowcrypt_chacha20 state[2];
uint8_t buf[64];
uint8_t keyb[32];
uint8_t nonceb[12];
if (!*args) {
printf("%s", help);
exit(0);
}
for (; *args; args++) {
if (anyeq(*args, "-h", "-help", "--help")) {
printf("%s", help);
exit(0);
} else if (npos == 2 && ++npos) {
nonce = *args;
} else if (npos == 1 && ++npos) {
sscanf(*args, "%lu", &lu);
counter = lu;
} else if (npos == 0 && ++npos) {
key = *args;
} else {
fprintf(stderr, "Unexpected argument: %s\n", *args);
exit(1);
}
}
if (npos != 3) {
fprintf(stderr, "Missing arguments!\n");
exit(1);
}
parse_hex2buf(keyb, 32, "key", key);
parse_hex2buf(nonceb, 12, "nonce", nonce);
slowcrypt_chacha20_init(state, keyb, counter, nonceb);
slowcrypt_chacha20_run(state, &state[1], 20);
slowcrypt_chacha20_serialize(buf, state);
for (nb = 0; nb < 64; nb++)
printf("%02x", buf[nb]);
printf("\n");
}
static void run_chacha20_crypt(char** args)
{
static char const help[] =
"chacha20 [--pad <padding>] [--init-counter <n>] [--full-chunks] <key> "
"<nonce> <file>\n"
"\n"
"Run the ChaCha20 en-/de- cryption algorithm on the given file, or "
"stdin, and output the result to stdout\n"
"\n"
"Defaults to padding with zeros, but can be overwritten with --pad <n>\n"
""
"Outputs only the number of input bytes from the last block. This "
"behaviour can be changed by passing --full-chunks\n";
char const *key, *nonce, *fpath = "-";
unsigned int npos = 0;
unsigned int nb, i;
unsigned long ul;
uint8_t pad = 0;
int full_chunks = 0;
uint32_t counter = 1;
slowcrypt_chacha20 state[2];
uint8_t buf[64];
uint8_t keyb[32];
uint8_t nonceb[12];
FILE* fp;
if (!*args) {
printf("%s", help);
exit(0);
}
for (; *args; args++) {
if (anyeq(*args, "-full-chunk", "--full-chunk", "-full-chunks",
"--full-chunks")) {
full_chunks = 1;
} else if (anyeq(*args, "-pad", "--pad", "--padding") && args[1]) {
args++;
pad = (uint8_t)atoi(*args);
} else if (anyeq(*args, "-init-counter", "-initial-counter",
"--initial-counter", "--init-counter") &&
args[1]) {
args++;
sscanf(*args, "%lu", &ul);
counter = ul;
} else if (anyeq(*args, "-h", "-help", "--help")) {
printf("%s", help);
exit(0);
} else if (npos == 2 && ++npos) {
fpath = *args;
} else if (npos == 1 && ++npos) {
nonce = *args;
} else if (npos == 0 && ++npos) {
key = *args;
} else {
fprintf(stderr, "Unexpected argument: %s\n", *args);
exit(1);
}
}
if (npos < 2) {
fprintf(stderr, "Missing arguments!\n");
exit(1);
}
parse_hex2buf(keyb, 32, "key", key);
parse_hex2buf(nonceb, 12, "nonce", nonce);
fp = file_open(fpath);
for (; (nb = file_read_chunk(fp, buf, 64)); counter++) {
for (i = nb; i < 64; i++)
buf[i] = pad;
slowcrypt_chacha20_block(state, keyb, counter, nonceb, buf);
if (full_chunks)
nb = 64;
fwrite(buf, 1, nb, stdout);
}
file_close(fp);
}
static void run_chacha20_csprng(char** args)
{
static char const help[] =
"chacha20-csprng [--limit <num bytes>] [--init-counter <n>] [--key "
"<key>] "
"[--nonce <nonce>] \n"
"\n"
"Run the ChaCha20 function repeatedly, with incrementing counter, "
"(starting at the given initial counter, defaulting to 1),"
"writing the output to stdout.\n"
"\n"
"If no limit (in number of bytes) is given, will repeat forever.\n"
"\n"
"Both key and nonce will be generated randomly (using the highest "
"entropy random source available), unless overwritten\n";
char const* key = 0;
char const* nonce = 0;
unsigned long ul;
unsigned long limit = 0;
unsigned long nb, nwrb;
uint32_t counter = 1;
slowcrypt_chacha20 state[2];
uint8_t buf[64];
uint8_t keyb[32];
uint8_t nonceb[12];
for (; *args; args++) {
if (anyeq(*args, "-limit", "--limit") && args[1]) {
args++;
sscanf(*args, "%lu", &ul);
limit = ul;
} else if (anyeq(*args, "-init-counter", "-initial-counter",
"--initial-counter", "--init-counter") &&
args[1]) {
args++;
sscanf(*args, "%lu", &ul);
counter = ul;
} else if (anyeq(*args, "-h", "-help", "--help")) {
printf("%s", help);
exit(0);
} else if (anyeq(*args, "-key", "--key")) {
args++;
key = *args;
} else if (anyeq(*args, "-nonce", "--nonce")) {
args++;
nonce = *args;
} else {
fprintf(stderr, "Unexpected argument: %s\n", *args);
exit(1);
}
}
if (key) {
parse_hex2buf(keyb, 32, "key", key);
} else {
slowcrypt_systemrand(keyb, 32, 0);
}
if (nonce) {
parse_hex2buf(nonceb, 12, "nonce", nonce);
} else {
slowcrypt_systemrand(keyb, 12, 0);
}
if (!limit) {
for (;; counter++) {
slowcrypt_chacha20_init(state, keyb, counter, nonceb);
slowcrypt_chacha20_run(state, &state[1], 20);
slowcrypt_chacha20_serialize(buf, state);
fwrite(buf, 1, 64, stdout);
}
} else {
for (nb = 0; nb < limit; (nb += 64, counter++)) {
nwrb = limit - nb;
if (nwrb > 64)
nwrb = 64;
slowcrypt_chacha20_init(state, keyb, counter, nonceb);
slowcrypt_chacha20_run(state, &state[1], 20);
slowcrypt_chacha20_serialize(buf, state);
fwrite(buf, 1, nwrb, stdout);
}
}
}
static void run_poly1305(char** args)
{
static char const help[] =
"poly1305 [--key] <hex-key> [file]\n"
"\n"
"Run the Poly1305 one-time authenticator on the data from the given file "
"or stdin\n";
char const* key = 0;
char const* fpath = "-";
FILE* fp;
unsigned int npos = 0;
uint8_t keybuf[32];
uint8_t chunk[16];
slowcrypt_poly1305 poly1305;
unsigned int nb;
if (!*args) {
printf("%s", help);
exit(0);
}
for (; *args; args++) {
if (!key && anyeq(*args, "-k", "-key", "--key") && args[1]) {
args++;
key = *args;
} else if (anyeq(*args, "-h", "-help", "--help")) {
printf("%s", help);
exit(0);
} else if (npos == 1 && ++npos) {
fpath = *args;
} else if (npos == 0 && ++npos && !key) {
key = *args;
} else {
fprintf(stderr, "Unexpected argument: %s\n", *args);
exit(1);
}
}
if (!key) {
fprintf(stderr, "Missing argument: [--key] <hex-key>");
exit(1);
}
fp = file_open(fpath);
parse_hex2buf(keybuf, 32, "key", key);
slowcrypt_poly1305_init(&poly1305, keybuf);
while ((nb = file_read_chunk(fp, chunk, 16))) {
slowcrypt_poly1305_next_block(&poly1305, chunk, nb);
}
slowcrypt_poly1305_finish(&poly1305, chunk);
for (nb = 0; nb < 16; nb++)
printf("%02x", chunk[nb]);
printf("\n");
file_close(fp);
}
static struct algo bytes2scalar[] = {{"poly1305", run_poly1305},
{"chacha20-core", run_chacha20_core},
{0, 0}};
static struct algo bytes2bytes[] = {{"chacha20", run_chacha20_crypt}, {0, 0}};
static struct algo scalar2bytes[] = {{"chacha20-csprng", run_chacha20_csprng},
{0, 0}};
int main(int argc, char** argv)
{
struct algo* a;
(void)argc;
argv++;
if (!*argv || anyeq(*argv, "-h", "-help", "--help")) {
printf("bytes -> scalar\n");
for (a = bytes2scalar; a->name; a++)
printf(" %s\n", a->name);
printf("\nbytes -> bytes\n");
for (a = bytes2bytes; a->name; a++)
printf(" %s\n", a->name);
printf("\nscalar -> bytes\n");
for (a = scalar2bytes; a->name; a++)
printf(" %s\n", a->name);
return 0;
}
for (a = bytes2scalar; a->name; a++) {
if (!strcmp(a->name, *argv)) {
a->run(argv + 1);
return 0;
}
}
for (a = bytes2bytes; a->name; a++) {
if (!strcmp(a->name, *argv)) {
a->run(argv + 1);
return 0;
}
}
for (a = scalar2bytes; a->name; a++) {
if (!strcmp(a->name, *argv)) {
a->run(argv + 1);
return 0;
}
}
fprintf(stderr, "Unknown algorithm %s\n", *argv);
return 1;
}

175
systemrand.h Normal file
View File

@@ -0,0 +1,175 @@
/*
* Copyright (c) 2025 Alexander Nutz
* MIT licensed, see below documentation
*
* Latest version can be found at:
* https://gitea.vxcc.dev/alexander.nutz/slow-libs
*
* ======== High-entropy system RNG =========
*
* Configuration options:
* - SLOWCRYPT_SYSTEMRAND_IMPL
* - SLOWCRYPT_SYSTEMRAND_FUNC
* will be used in front of every function definition / declaration
*
* Tries these sources (depending on platform support), in order:
* - getentropy()
* - getrandom()
* - unless _WIN32 is defined, read from /dev/random or /dev/urandom
* - on _WIN32, try BCryptGenRandom
* - on _WIN32, CryptGenRandom
* - on _WIN32, RtlGenRandom
* - random(), unless bail on insecure
* - rand(), unless bail on insecure
*
* As with all slow-libs, a wide range of supported platforms is a priority,
* so please report any incompatibility issues.
*/
/*
* Copyright (c) 2025 Alexander Nutz
* 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.
*/
#ifndef SLOWCRYPT_SYSTEMRAND_H
#define SLOWCRYPT_SYSTEMRAND_H
#ifndef SLOWCRYPT_SYSTEMRAND_FUNC
#define SLOWCRYPT_SYSTEMRAND_FUNC /**/
#endif
typedef enum
{
SLOWCRYPT_SYSTEMRAND__BAIL_IF_INSECURE = 1 << 0,
SLOWCRYPT_SYSTEMRAND__INSECURE_NON_BLOCKING = 1 << 1
} slowcrypt_systemrand_flags;
/*
* Return codes:
* - 0: success
* - 1: unexpected error
* - 2: random number is not secure enough. Only returned with BAIL_IF_INSECURE
*/
SLOWCRYPT_SYSTEMRAND_FUNC int slowcrypt_systemrand(
void* buffer,
unsigned long length,
slowcrypt_systemrand_flags flags);
#ifdef SLOWCRYPT_SYSTEMRAND_IMPL
#ifndef _GNU_SOURCE
#define SLOWCRYPT_SYSTEMRAND_UNDEF_GNU_SOURCE
#define _GNU_SOURCE
#endif
#include <stdio.h>
#include <stdlib.h>
#ifdef unix
#include <errno.h>
#include <unistd.h>
#endif
#ifdef SLOWCRYPT_SYSTEMRAND_UNDEF_GNU_SOURCE
#undef SLOWCRYPT_SYSTEMRAND_UNDEF_GNU_SOURCE
#undef _GNU_SOURCE
#endif
static int slowcrypt_systemrand__chunk256(void* buffer,
unsigned long length,
slowcrypt_systemrand_flags flags)
{
unsigned long i, j;
unsigned char u8;
char const* fpath;
FILE* fp;
#if defined(unix) && defined(__GLIBC__) && \
(__GLIBC__ > 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 25))
if (getentropy(buffer, length)) {
if (errno != ENOSYS) {
return 1;
}
} else {
return 0;
}
#endif
/* TODO: getrandom (on glibc, freebsd, and probably others) */
#ifndef _WIN32
fpath = (flags & SLOWCRYPT_SYSTEMRAND__INSECURE_NON_BLOCKING) ? "/dev/urandom"
: "/dev/random";
fp = fopen(fpath, "rb");
if (fp) {
i = fread(buffer, 1, length, fp);
fclose(fp);
if (i == length)
return 0;
}
#endif
/* TODO: windows stuff */
if (flags & SLOWCRYPT_SYSTEMRAND__BAIL_IF_INSECURE)
return 2;
/* TODO: random() */
if (RAND_MAX >= 255) {
for (i = 0; i < length; i++) {
((unsigned char*)buffer)[i] =
(unsigned char)((unsigned int)rand() / (unsigned int)(RAND_MAX));
}
} else {
/* why would this ever happen... */
for (i = 0; i < length; i++) {
u8 = 0;
for (j = 0; j < 8; j++) {
u8 <<= 1;
u8 ^= (unsigned char)rand();
}
((unsigned char*)buffer)[i] = u8;
}
}
return 0;
}
SLOWCRYPT_SYSTEMRAND_FUNC int slowcrypt_systemrand(
void* buffer,
unsigned long length,
slowcrypt_systemrand_flags flags)
{
unsigned int i, j;
int rc;
/* many random sources have a limit of 256 bytes */
for (i = 0; i < length; i += 256) {
j = length - i;
if (j > 256)
j = 256;
if ((rc = slowcrypt_systemrand__chunk256(buffer, length, flags))) {
return rc;
}
}
return 0;
}
#endif
#endif