Skip to content

Secure Token Generator — Java 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 Java 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. Java (17+) 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).
import java.security.SecureRandom;
import java.util.LinkedHashMap;
import java.util.Map;

public class TokenGenerator {
    // The fixed alphabets (subset).
    static final Map<String, String> ALPHABETS = new LinkedHashMap<>(Map.of(
            "hex", "0123456789abcdef",
            "base32", "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567",                    // RFC 4648
            "base64url", "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_",
            "base62", "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"));

    static final SecureRandom RNG = new SecureRandom(); // the CSPRNG

    private static double log2(double x) {
        return Math.log(x) / Math.log(2);
    }

    // Resolve an alphabet name to its symbol string; unknown -> hex (the default).
    static String resolveAlphabet(String name) {
        return ALPHABETS.getOrDefault(name, ALPHABETS.get("hex"));
    }

    // Characters needed to carry `bytes` bytes of entropy through `size` symbols.
    static int outputLength(double bytes, int size) {
        if (bytes < 1 || size < 2) return 0;
        return (int) Math.ceil(bytes * 8 / 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. nextInt() is treated
    // as unsigned so the math matches the 32-bit reference exactly.
    static String selectUnbiased(String alphabet, int n) {
        int size = alphabet.length();
        int limit = Integer.divideUnsigned(-1, size) * size; // 0xFFFFFFFF / size * size
        StringBuilder out = new StringBuilder(n);
        for (int i = 0; i < n; i++) {
            int x = RNG.nextInt(); // one secure 32-bit draw
            for (int guard = 0; Integer.compareUnsigned(x, limit) >= 0 && guard < 64; guard++)
                x = RNG.nextInt();
            out.append(alphabet.charAt(Integer.remainderUnsigned(x, size)));
        }
        return out.toString();
    }

    // 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) {
        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.
    public static void main(String[] args) {
        String[][] demos = {{"hex", "16"}, {"base62", "20"}, {"base32", "32"}};
        for (String[] d : demos) {
            double bytes = Double.parseDouble(d[1]);
            String alphabet = resolveAlphabet(d[0]);
            int n = outputLength(bytes, alphabet.length());
            String token = selectUnbiased(alphabet, n);
            double bits = n * log2(alphabet.length());
            System.out.printf("%-8s %.0f bytes -> %s  (%.0f bits, %s)%n",
                    d[0], bytes, token, 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 →