diff options
Diffstat (limited to 'utilities/gen_apikey.c')
-rw-r--r-- | utilities/gen_apikey.c | 99 |
1 files changed, 99 insertions, 0 deletions
diff --git a/utilities/gen_apikey.c b/utilities/gen_apikey.c new file mode 100644 index 0000000..6f8d3f7 --- /dev/null +++ b/utilities/gen_apikey.c @@ -0,0 +1,99 @@ +#ifdef NDEBUG +#error Asserts must work here +#endif + +#include <stdio.h> +#include <stdlib.h> +#include <stdbool.h> +#include <string.h> +#include <stdint.h> +#include <assert.h> + + +// This gives log2(64)*24 = 6*24 = 144 bits of entropy. +#define ALPHABET_SIZE 64 +#define KEY_LENGTH 24 + + +__attribute__((noreturn)) +static void die(const char *msg) { + fprintf(stderr, "%s\n", msg); + exit(1); +} + + +//////////////////// RANDOM GENERATOR //////////////////// + +struct randgen { + FILE *urandom; + uint8_t buffer[256]; + size_t cursor; +}; + +static void randgen_refresh(struct randgen *gen) { + size_t nr = fread(gen->buffer, 1, sizeof gen->buffer, gen->urandom); + if (nr < sizeof gen->buffer) die("Cannot read from /dev/urandom"); + gen->cursor = 0; +} + +static struct randgen randgen_init(void) { + FILE *f = fopen("/dev/urandom", "r"); + if (!f) die("Cannot open /dev/urandom"); + + struct randgen gen; + gen.urandom = f; + randgen_refresh(&gen); + + return gen; +} + +static uint8_t randgen_gen_byte(struct randgen *gen) { + if (gen->cursor == sizeof gen->buffer) randgen_refresh(gen); + return gen->buffer[gen->cursor++]; +} + +static uint64_t randgen_gen(struct randgen *gen, uint64_t below) { + if (below == 0) return 0; + + int nbytes = 0; + while (nbytes < 8 && (1ULL << (8 * nbytes)) < below) nbytes++; + + // This check allows us to do fearless modulo in the main loop + if (nbytes == 8) assert(false && "'below' too large"); + + const uint64_t gen_limit = 1ULL << (8 * nbytes); + + while (true) { + uint64_t sample = 0; + for (int i = 0; i < nbytes; i++) { + sample |= (uint64_t)randgen_gen_byte(gen) << (8 * i); + } + + if (sample < gen_limit - gen_limit % below) { + return sample % below; + } + } +} + + +//////////////////// MAIN FUNCTIONALITY //////////////////// + +static char gen_key_char(struct randgen *gen) { + // 64 characters, so 6 bits + static const char alphabet[] = + "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_"; + assert(strlen(alphabet) == ALPHABET_SIZE); + return alphabet[randgen_gen(gen, strlen(alphabet))]; +} + +int main() { + struct randgen gen = randgen_init(); + + char key[KEY_LENGTH + 1]; + for (size_t i = 0; i < KEY_LENGTH; i++) { + key[i] = gen_key_char(&gen); + } + key[KEY_LENGTH] = '\0'; + + printf("%s\n", key); +} |