aboutsummaryrefslogtreecommitdiff
path: root/utilities/gen_apikey.c
diff options
context:
space:
mode:
authorTom Smeding <tom@tomsmeding.com>2021-02-10 12:07:45 +0100
committerTom Smeding <tom@tomsmeding.com>2021-02-10 12:07:45 +0100
commite7a188d9f8cd105485c5362f525cdd614c03dd3c (patch)
treecbbcf64aeef1de1ca56f1023464316e1dc4cce83 /utilities/gen_apikey.c
parent6a69d512e4615e01b5f35e7b68af307969fc6c17 (diff)
utilities: Add gen_apikey
Diffstat (limited to 'utilities/gen_apikey.c')
-rw-r--r--utilities/gen_apikey.c99
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);
+}