1 The Problem
We want a tool that creates a strong password: a random mix of letters, numbers, and symbols, of a length the user chooses. It teaches building a string from random choices — and an important lesson about which randomness is safe for security.
2 How to Think About It
Think about how a strong password is built, before any code:
3 The Build — explained part by part
Here is the complete generator. Read each part’s note below — you should understand the whole thing from the notes alone.
import java.security.SecureRandom
private val LOWER = "abcdefghijklmnopqrstuvwxyz"
private val UPPER = LOWER.uppercase()
private val DIGITS = "0123456789"
private val SYMBOLS = "!@#$%^&*"
val POOL = LOWER + UPPER + DIGITS + SYMBOLS
private val secureRandom = SecureRandom()
/** Picks [length] random characters from [POOL], securely. */
fun generate(length: Int): String {
val sb = StringBuilder(length)
repeat(length) {
sb.append(POOL[secureRandom.nextInt(POOL.length)])
}
return sb.toString()
}
fun main() {
print("Password length: ")
val length = readLine()?.trim()?.toIntOrNull()
if (length == null || length <= 0) {
println("Please type a positive whole number.")
return
}
println("Your password: ${generate(length)}")
}kotlinc on your own machine instead; the “Run It” section explains exactly how.string.ascii_letters) makes it obvious exactly which characters a password can contain.import java.security.SecureRandom — Kotlin runs on the JVM, so it reaches straight for Java’s own cryptographically-secure generator;
kotlin.random.Random (used in the guessing game) is not designed to be unpredictable to an attacker and must never be used for anything resembling a password or a secret.POOL[secureRandom.nextInt(POOL.length)] — pick one random index into the pool string, repeated
length times via repeat(length) { ... }, a Kotlin standard-library function that just runs its block length times — a clearer name than a bare for loop when the index itself is unused.fun generate(length: Int): String — pulling the loop into its own typed function (rather than writing it inline in
main) is what makes it directly testable, with no prompt or typed input in the way.
kotlin.random.Random (or java.util.Random) to pick password characters.java.security.SecureRandom for anything security-sensitive.SecureRandom() fresh inside the loop, once per character.SecureRandom instance and reuse it — creating a new one repeatedly is wasteful and, on some platforms, can even slow down entropy collection.length > 0 before generating — see “Try this next” below.4 Test & Prove Each Part
How do we know this works? We pull the real logic into small, plain functions and check each one against cases we already know the answer to.
import kotlin.test.Test
import kotlin.test.assertEquals
import kotlin.test.assertNotEquals
import kotlin.test.assertTrue
class PasswordTest {
@Test
fun correctLength() {
assertEquals(12, generate(12).length)
}
@Test
fun charsFromPool() {
for (ch in generate(50)) {
assertTrue(POOL.contains(ch))
}
}
@Test
fun passwordsDiffer() {
assertNotEquals(generate(16), generate(16))
}
}Compile with kotlinc password.kt password_test.kt -include-runtime -d password.jar and run with JUnit's own runner. Testing randomness directly is impossible, so instead we test its guarantees: the right length, only pool characters, and (practically) no repeats.
5 The Interface
What it expects
Password length: 16What it returns
Your password: Rxp7QarCT*DvpdFA6 Run It & Automate It
Save the code as password.kt and compile it with kotlinc password.kt -include-runtime -d password.jar.
kotlinc password.kt -include-runtime -d password.jar && java -jar password.jarType a length and get back a secure random password of that length.
A CI tool like Jenkins compiles and tests automatically whenever the code changes — every line below has a plain explanation.
Password length: 16
Your password: OYDikcnPFCP%YnNs0, a negative number, or any non-numeric text all print this same message rather than silently producing an empty or nonsensical password.POOL really does combine letters, digits, and symbols — a typo that drops one of the four building blocks silently shrinks the pool.// Jenkinsfile — compiles and tests automatically every time the code changes.
pipeline {
agent any // run on any available machine
stages {
stage('Get the code') {
steps { checkout scm } // download the latest code
}
stage('Set up Kotlin') {
steps {
sh 'kotlinc -version' // confirm the compiler is installed
}
}
stage('Compile and test') {
steps {
sh 'kotlinc password.kt password_test.kt -include-runtime -d build.jar' // one real JVM jar, no build tool required
sh 'java -cp build.jar:kotlin-test-junit.jar:junit.jar org.junit.runner.JUnitCore PasswordTest'
}
}
}
post {
success { echo 'All tests passed.' }
failure { echo 'A test failed — look above.' }
}
}
You have a working password generator. Extend it:
- Reject a non-positive length. Print a clearer, more specific error. (Teaches: input validation.)
- Let the user opt out of symbols. Some sites do not accept them. (Teaches: building the pool conditionally.)
- Guarantee variety. Force at least one digit and one symbol to appear. (Teaches: combining a guarantee with randomness.)
- Estimate strength. Print how many possible passwords exist for that pool and length, using
BigIntegersince the count outgrows a normalLong. (Teaches: arbitrary-precision arithmetic.)
java.security.SecureRandom (not kotlin.random.Random) is the right tool whenever randomness has to be unpredictable, plus Kotlin’s repeat helper and how smoothly it calls straight into the Java standard library. Related reference: Kotlin & Java Interop, Standard Library Deep Dive.