Skip to content

Password Generator — Kotlin 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 Kotlin implementation — the same logic the interactive tool runs, in a shareable, citable form.

// password-generator — CSPRNG password generation + entropy scoring. Language: Kotlin (JVM 1.9+; java.security.SecureRandom). Port of src/lib/password.ts.

import java.security.SecureRandom
import kotlin.math.log2
import kotlin.math.pow

data class PasswordOptions(
    val length: Int,
    val upper: Boolean = false,
    val lower: Boolean = false,
    val numbers: Boolean = false,
    val symbols: Boolean = false,
    val excludeAmbiguous: Boolean = false,
)

object PasswordGenerator {
    private const val LOWER = "abcdefghijklmnopqrstuvwxyz"
    private const val UPPER = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
    private const val NUMBERS = "0123456789"
    private const val SYMBOLS = "!@#$%^&*()-_=+[]{};:,.<>?/"
    private const val AMBIGUOUS = "O0Il1|" // O/0, I/l/1, pipe — dropped on request
    private val rng = SecureRandom()

    // Concat the selected pools, then drop ambiguous glyphs (mirrors buildCharset).
    fun buildCharset(o: PasswordOptions): String {
        var cs = (if (o.lower) LOWER else "") + (if (o.upper) UPPER else "") +
            (if (o.numbers) NUMBERS else "") + (if (o.symbols) SYMBOLS else "")
        if (o.excludeAmbiguous) cs = cs.filter { it !in AMBIGUOUS }
        return cs
    }

    // Uniform index in [0, n): reject uint32 SecureRandom draws >= the largest
    // multiple of n fitting in 2^32, so `% n` carries no modulo bias.
    private fun unbiasedIndex(n: Int): Int {
        val max = 1L shl 32
        val limit = max - max % n
        var r: Long
        do { r = rng.nextInt().toLong() and 0xFFFFFFFFL } while (r >= limit)
        return (r % n).toInt()
    }

    // Returns "" for an empty pool or length < 1 — same contract as the TS lib.
    fun generate(o: PasswordOptions): String {
        val cs = buildCharset(o)
        if (cs.isEmpty() || o.length < 1) return ""
        return buildString { repeat(o.length) { append(cs[unbiasedIndex(cs.length)]) } }
    }

    // Theoretical entropy in bits: length * log2(|alphabet|).
    fun entropyBits(length: Int, charsetSize: Int): Double =
        if (length <= 0 || charsetSize <= 1) 0.0 else length * log2(charsetSize.toDouble())

    // Strength meter tiers, 1:1 with the TS thresholds.
    fun strengthTier(bits: Double): String = when {
        bits >= 100 -> "very strong"
        bits >= 70 -> "strong"
        bits >= 45 -> "fair"
        bits >= 28 -> "weak"
        else -> "very weak"
    }

    // Average crack time (s) = 2^(bits-1) / guesses-per-second.
    fun crackTimeSeconds(bits: Double, guessesPerSecond: Double): Double =
        2.0.pow(bits - 1) / guessesPerSecond
}

fun main() {
    val o = PasswordOptions(20, upper = true, lower = true,
        numbers = true, symbols = true, excludeAmbiguous = true)
    val cs = PasswordGenerator.buildCharset(o)
    val bits = PasswordGenerator.entropyBits(o.length, cs.length)
    println("${PasswordGenerator.generate(o)} — $bits bits, ${PasswordGenerator.strengthTier(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 →