Skip to content

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. C# (.NET 7+) 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).
using System.Security.Cryptography;

static class TokenGenerator
{
    // The fixed alphabets (subset).
    static readonly Dictionary<string, string> Alphabets = new()
    {
        ["hex"] = "0123456789abcdef",
        ["base32"] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567",                    // RFC 4648
        ["base64url"] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_",
        ["base62"] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz",
    };

    // Resolve an alphabet name to its symbol string; unknown -> hex (the default).
    static string ResolveAlphabet(string name) =>
        Alphabets.TryGetValue(name, out var symbols) ? symbols : Alphabets["hex"];

    // Characters needed to carry `bytes` bytes of entropy through `size` symbols.
    static int OutputLength(double bytes, int size) =>
        bytes < 1 || size < 2 ? 0 : (int)Math.Ceiling(bytes * 8 / Math.Log2(size));

    // 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. The 64-redraw cap stops a broken RNG from looping
    // forever — same guard as the TS/Python reference.
    static string SelectUnbiased(string alphabet, int n)
    {
        uint size = (uint)alphabet.Length;
        uint limit = uint.MaxValue / size * size;
        Span<byte> raw = stackalloc byte[4];
        var chars = new char[n];
        for (var i = 0; i < n; i++)
        {
            uint x;
            var guard = 0;
            do
            {
                RandomNumberGenerator.Fill(raw); // one secure 32-bit draw
                x = BitConverter.ToUInt32(raw);
            }
            while (x >= limit && ++guard < 64);
            chars[i] = alphabet[(int)(x % size)];
        }
        return new string(chars);
    }

    // Bucket an entropy estimate (bits) into the tool's strength tiers:
    // weak <64 · fair 64-127 · strong 128-255 · very strong >=256.
    static string StrengthLabel(double bits) =>
        bits < 64 ? "weak" : bits < 128 ? "fair" : bits < 256 ? "strong" : "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.
    static void Main()
    {
        foreach (var (name, bytes) in new[] { ("hex", 16.0), ("base62", 20.0), ("base32", 32.0) })
        {
            string alphabet = ResolveAlphabet(name);
            string token = SelectUnbiased(alphabet, OutputLength(bytes, alphabet.Length));
            double bits = token.Length * Math.Log2(alphabet.Length);
            Console.WriteLine($"{name,-8} {(int)bytes} bytes -> {token}  ({bits:F0} bits, {StrengthLabel(bits)})");
        }
    }
}

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 →