Skip to content

Password Generator — C source

Generate cryptographically-random passwords with a CSPRNG using rejection sampling (no modulo bias). Shows live entropy in bits, a 5-tier strength meter, average offline-GPU crack time, and a Pro mode with the entropy formula, a crack-time-vs-length curve, and a 4-scenario attack table. Everything runs locally - nothing is sent anywhere.

This is the C implementation — the same logic the interactive tool runs, in a shareable, citable form.

/* password-generator — CSPRNG password generation + entropy scoring. Language: C (C11; getrandom(2) — C stdlib has no CSPRNG; arc4random_buf/SecRandomCopyBytes elsewhere). Port of src/lib/password.ts. */

#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/random.h>
static const char LOWER[] = "abcdefghijklmnopqrstuvwxyz", UPPER[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
static const char NUMBERS[] = "0123456789", SYMBOLS[] = "!@#$%^&*()-_=+[]{};:,.<>?/";
static const char AMBIGUOUS[] = "O0Il1|"; /* O/0, I/l/1, pipe — dropped on request */
typedef struct { int length, upper, lower, numbers, symbols, exclude_ambiguous; } PasswordOptions;

/* Concat the selected pools, then drop ambiguous glyphs (mirrors buildCharset). */
static size_t build_charset(const PasswordOptions *o, char *cs)
{
    const struct { const char *set; int on; } pools[4] = {
        { LOWER, o->lower }, { UPPER, o->upper },
        { NUMBERS, o->numbers }, { SYMBOLS, o->symbols },
    };
    size_t n = 0;
    for (int p = 0; p < 4; p++)
        if (pools[p].on) {
            size_t len = strlen(pools[p].set);
            memcpy(cs + n, pools[p].set, len);
            n += len;
        }
    if (o->exclude_ambiguous) {
        size_t w = 0;
        for (size_t i = 0; i < n; i++)
            if (!strchr(AMBIGUOUS, cs[i])) cs[w++] = cs[i];
        n = w;
    }
    cs[n] = '\0';
    return n;
}
/* Uniform index in [0, n): reject uint32 getrandom draws >= the largest multiple of n fitting in 2^32, so `r % n` carries no modulo bias. */
static unsigned unbiased_index(unsigned n)
{
    const unsigned long MAX = 1UL << 32;
    unsigned long limit = MAX - MAX % n, r;
    do {
        if (getrandom(&r, sizeof r, 0) != (long)sizeof r) exit(1);
    } while (r >= limit);
    return (unsigned)(r % n);
}
/* pw needs o->length + 1 bytes; returns 0 for an empty pool or length < 1 (the TS lib returns "" for both). */
static int generate_password(const PasswordOptions *o, char *pw)
{
    char cs[128];
    size_t n = build_charset(o, cs);
    if (n == 0 || o->length < 1) return 0;
    for (int i = 0; i < o->length; i++) pw[i] = cs[unbiased_index((unsigned)n)];
    pw[o->length] = '\0';
    return 1;
}
/* Theoretical entropy in bits: length * log2(|alphabet|). */
static double entropy_bits(int length, size_t charset_size)
{
    return (length <= 0 || charset_size <= 1) ? 0.0 : length * log2((double)charset_size);
}
/* Strength meter tiers, 1:1 with the TS thresholds. */
static const char *strength_tier(double bits)
{
    if (bits >= 100) return "very strong";
    if (bits >= 70) return "strong";
    if (bits >= 45) return "fair";
    if (bits >= 28) return "weak";
    return "very weak";
}
int main(void)
{
    PasswordOptions o = { 20, 1, 1, 1, 1, 1 }; /* 20 chars, all pools, drop ambiguous */
    char pw[128];
    if (!generate_password(&o, pw)) return 1;
    double bits = entropy_bits(20, 83); /* 26+26+10+26 minus O0Il1 (| not in symbols) */
    printf("%s — %.1f bits, %s\n", pw, bits, strength_tier(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 →