Secure Token Generator — C source
Generate cryptographically-secure random tokens in your browser. Pick the entropy size and format - hex, base32, base64, base62, or alphanumeric - and see the real strength in bits. Runs entirely client-side.
This is the C implementation — the same logic the interactive tool runs, in a shareable, citable form.
/* token-generator — cryptographically-secure random tokens in hex/base32/base64/base62/... alphabets, with unbiased symbol selection and entropy/strength estimates. Language: C (C11, stdlib only — draws from the kernel CSPRNG via /dev/urandom). Port of src/lib/token-generator.ts — same logic as this dir's javascript.js; the full 8-entry alphabet table, custom alphabets and injectable RNG omitted for the 80-line budget (see javascript.js / python.py). */
#include <math.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
/* The fixed alphabets (subset), as name -> symbol-string pairs. */
static const struct { const char *name, *symbols; } ALPHABETS[] = {
{"hex", "0123456789abcdef"},
{"base32", "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567"}, /* RFC 4648 */
{"base64url", "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_"},
{"base62", "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"},
};
/* Resolve an alphabet name to its symbol string; unknown -> hex (the default). */
static const char *resolve_alphabet(const char *name) {
for (unsigned i = 0; i < sizeof ALPHABETS / sizeof *ALPHABETS; i++)
if (strcmp(name, ALPHABETS[i].name) == 0) return ALPHABETS[i].symbols;
return ALPHABETS[0].symbols;
}
/* One cryptographically-secure 32-bit draw from the kernel RNG. */
static uint32_t draw32(void) {
unsigned char b[4];
FILE *urandom = fopen("/dev/urandom", "r");
if (!urandom || fread(b, 1, 4, urandom) != 4) { fputs("CSPRNG unavailable\n", stderr); exit(1); }
fclose(urandom);
return (uint32_t)b[0] << 24 | (uint32_t)b[1] << 16 | (uint32_t)b[2] << 8 | b[3];
}
/* Pick alphabet[n] WITHOUT modulo bias: naive draw % size favors trailing
symbols whenever size does not divide the draw range (base62 etc.), so any
draw at or above the largest multiple of size fitting in 32 bits is
rejected and redrawn (64-redraw cap, same guard as the TS/Python ref). */
static void select_unbiased(const char *alphabet, unsigned n, char out[]) {
uint32_t size = (uint32_t)strlen(alphabet);
uint32_t limit = 0xFFFFFFFFu / size * size;
for (unsigned i = 0; i < n; i++) {
uint32_t x = draw32();
for (unsigned guard = 0; x >= limit && guard < 64; guard++)
x = draw32();
out[i] = alphabet[x % size];
}
out[n] = '\0';
}
/* Characters needed to carry `bytes` bytes of entropy through `size` symbols. */
static unsigned output_length(double bytes, uint32_t size) {
if (bytes < 1 || size < 2) return 0;
return (unsigned)ceil(bytes * 8.0 / log2((double)size));
}
/* Bucket an entropy estimate (bits) into the tool's strength tiers:
weak <64 · fair 64-127 · strong 128-255 · very strong >=256. */
static const char *strength_label(double bits) {
if (bits < 64) return "weak";
if (bits < 128) return "fair";
if (bits < 256) return "strong";
return "very strong";
}
/* Demo: the island's three showcase rows — 16-byte hex, 20-byte base62,
32-byte base32 — each labeled with its real strength in bits. */
int main(void) {
const struct { const char *name; double bytes; } demos[] = {
{"hex", 16}, {"base62", 20}, {"base32", 32},
};
char token[128];
for (unsigned i = 0; i < sizeof demos / sizeof *demos; i++) {
const char *alphabet = resolve_alphabet(demos[i].name);
uint32_t size = (uint32_t)strlen(alphabet);
unsigned n = output_length(demos[i].bytes, size);
select_unbiased(alphabet, n, token);
double bits = n * log2((double)size);
printf("%-8s %2.0f bytes -> %-52s %3.0f bits, %s\n",
demos[i].name, demos[i].bytes, token, bits, strength_label(bits));
}
return 0;
}
Also available in 13 other languages
Every CosmoDev tool ships its pure logic in TypeScript (web) and Go (CLI), with authored implementations in a dozen-plus languages — the same contract, ported. Compare all languages side by side →