Secure Token Generator — Kotlin 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 Kotlin 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. Kotlin (1.9+) 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 kotlin.math.ceil
import kotlin.math.log2
// The fixed alphabets (subset).
val ALPHABETS = mapOf(
"hex" to "0123456789abcdef",
"base32" to "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567", // RFC 4648
"base64url" to "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_",
"base62" to "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz",
)
private val rng = SecureRandom() // the CSPRNG
// Resolve an alphabet name to its symbol string; unknown -> hex (the default).
fun resolveAlphabet(name: String): String = ALPHABETS[name] ?: ALPHABETS.getValue("hex")
// Characters needed to carry `bytes` bytes of entropy through `size` symbols.
fun outputLength(bytes: Double, size: Int): Int =
if (bytes < 1 || size < 2) 0 else ceil(bytes * 8 / log2(size.toDouble())).toInt()
// 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.
fun selectUnbiased(alphabet: String, n: Int): String {
val size = alphabet.length.toUInt()
val limit = UInt.MAX_VALUE / size * size
return buildString {
repeat(n) {
var x = rng.nextInt().toUInt() // one secure 32-bit draw
var redraws = 0
while (x >= limit && redraws++ < 64) x = rng.nextInt().toUInt()
append(alphabet[(x % size).toInt()])
}
}
}
// Generate a token carrying `bytes` bytes of entropy through `alphaName`.
fun generateToken(bytes: Double, alphaName: String): String {
val alphabet = resolveAlphabet(alphaName)
if (alphabet.length < 2) return ""
return selectUnbiased(alphabet, outputLength(bytes, alphabet.length))
}
// Bucket an entropy estimate (bits) into the tool's strength tiers:
// weak <64 · fair 64-127 · strong 128-255 · very strong >=256.
fun strengthLabel(bits: Double) = when {
bits < 64 -> "weak"
bits < 128 -> "fair"
bits < 256 -> "strong"
else -> "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.
fun main() {
for ((name, bytes) in listOf("hex" to 16.0, "base62" to 20.0, "base32" to 32.0)) {
val token = generateToken(bytes, name)
val size = resolveAlphabet(name).length
val bits = token.length * log2(size.toDouble())
println("%-8s %.0f bytes -> %s (%.0f bits, %s)".format(name, 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 →