#ifdef NDEBUG #error Asserts must work here #endif #include #include #include #include #include #include // 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); }