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 →