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# (.NET 6+; System.Security.Cryptography CSPRNG). Port of src/lib/password.ts.

using System;
using System.Security.Cryptography;
using System.Text;

var o = new PasswordOptions(Length: 20, Upper: true, Lower: true,
    Numbers: true, Symbols: true, ExcludeAmbiguous: true);
var cs = Password.BuildCharset(o);
var bits = Password.EntropyBits(o.Length, cs.Length);
Console.WriteLine($"{Password.Generate(o)} — {bits:F1} bits, {Password.StrengthTier(bits)}");

record PasswordOptions(int Length, bool Upper = false, bool Lower = false,
    bool Numbers = false, bool Symbols = false, bool ExcludeAmbiguous = false);

static class Password
{
    const string Lower = "abcdefghijklmnopqrstuvwxyz";
    const string Upper = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
    const string Numbers = "0123456789";
    const string Symbols = "!@#$%^&*()-_=+[]{};:,.<>?/";
    const string Ambiguous = "O0Il1|"; // O/0, I/l/1, pipe — dropped on request

    // Concat the selected pools, then drop ambiguous glyphs (mirrors buildCharset).
    public static string BuildCharset(PasswordOptions o)
    {
        var cs = new StringBuilder();
        if (o.Lower) cs.Append(Lower);
        if (o.Upper) cs.Append(Upper);
        if (o.Numbers) cs.Append(Numbers);
        if (o.Symbols) cs.Append(Symbols);
        if (o.ExcludeAmbiguous)
            for (int i = cs.Length - 1; i >= 0; i--)
                if (Ambiguous.IndexOf(cs[i]) >= 0) cs.Remove(i, 1);
        return cs.ToString();
    }

    // Uniform index in [0, n): reject uint32 CSPRNG draws >= the largest
    // multiple of n fitting in 2^32, so `% n` carries no modulo bias.
    static uint UnbiasedIndex(uint n)
    {
        const ulong Max = 1UL << 32;
        ulong limit = Max - Max % n, r;
        Span<byte> b = stackalloc byte[4];
        do
        {
            RandomNumberGenerator.Fill(b);
            r = BitConverter.ToUInt32(b);
        } while (r >= limit);
        return (uint)(r % n);
    }

    // Returns "" for an empty pool or length < 1 — same contract as the TS lib.
    public static string Generate(PasswordOptions o)
    {
        var cs = BuildCharset(o);
        if (cs.Length == 0 || o.Length < 1) return "";
        var pw = new char[o.Length];
        for (int i = 0; i < o.Length; i++) pw[i] = cs[(int)UnbiasedIndex((uint)cs.Length)];
        return new string(pw);
    }

    // Theoretical entropy in bits: length * log2(|alphabet|).
    public static double EntropyBits(int length, int charsetSize) =>
        length <= 0 || charsetSize <= 1 ? 0.0 : length * Math.Log2(charsetSize);

    // Strength meter tiers, 1:1 with the TS thresholds.
    public static string StrengthTier(double bits) =>
        bits >= 100 ? "very strong"
        : bits >= 70 ? "strong"
        : bits >= 45 ? "fair"
        : bits >= 28 ? "weak"
        : "very weak";
}

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 →