Skip to content

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

// password-generator — CSPRNG password generation + entropy scoring. Language: Swift 5 (SystemRandomNumberGenerator — backed by the OS CSPRNG). Port of src/lib/password.ts.

import Foundation

struct PasswordOptions {
    var length: Int
    var upper = false, lower = false, numbers = false, symbols = false
    var excludeAmbiguous = false
}

let lower = "abcdefghijklmnopqrstuvwxyz"
let upper = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
let numbers = "0123456789"
let symbols = "!@#$%^&*()-_=+[]{};:,.<>?/"
let ambiguous = Set("O0Il1|") // O/0, I/l/1, pipe — dropped on request

enum PasswordGenerator {
    private static var rng = SystemRandomNumberGenerator()

    // Concat the selected pools, then drop ambiguous glyphs (mirrors buildCharset).
    static func buildCharset(_ o: PasswordOptions) -> String {
        var cs = ""
        if o.lower { cs += lower }
        if o.upper { cs += upper }
        if o.numbers { cs += numbers }
        if o.symbols { cs += symbols }
        if o.excludeAmbiguous { cs.removeAll(where: { ambiguous.contains($0) }) }
        return cs
    }

    // Uniform index in [0, n): reject uint32 system-CSPRNG draws >= the largest
    // multiple of n fitting in 2^32, so `% n` carries no modulo bias.
    static func unbiasedIndex(_ n: Int) -> Int {
        let max = 1 << 32
        let limit = UInt64(max - max % n)
        while true {
            let r = UInt32(truncatingIfNeeded: rng.next())
            if UInt64(r) < limit { return Int(r) % n }
        }
    }

    // Returns "" for an empty pool or length < 1 — same contract as the TS lib.
    static func generate(_ o: PasswordOptions) -> String {
        let cs = buildCharset(o)
        guard !cs.isEmpty, o.length >= 1 else { return "" }
        return String((0..<o.length).map { _ in
            cs[cs.index(cs.startIndex, offsetBy: unbiasedIndex(cs.count))]
        })
    }

    // Theoretical entropy in bits: length * log2(|alphabet|).
    static func entropyBits(_ length: Int, _ charsetSize: Int) -> Double {
        guard length > 0, charsetSize > 1 else { return 0.0 }
        return Double(length) * log2(Double(charsetSize))
    }

    // Strength meter tiers, 1:1 with the TS thresholds.
    static func strengthTier(_ bits: Double) -> String {
        switch bits {
        case 100...: return "very strong"
        case 70...: return "strong"
        case 45...: return "fair"
        case 28...: return "weak"
        default: return "very weak"
        }
    }

    // Average crack time (s) = 2^(bits-1) / guesses-per-second.
    static func crackTimeSeconds(_ bits: Double, _ guessesPerSecond: Double) -> Double {
        pow(2, bits - 1) / guessesPerSecond
    }
}

let o = PasswordOptions(length: 20, upper: true, lower: true,
                        numbers: true, symbols: true, excludeAmbiguous: true)
let cs = PasswordGenerator.buildCharset(o)
let bits = PasswordGenerator.entropyBits(o.length, cs.count)
print("\(PasswordGenerator.generate(o)) — \(String(format: "%.1f", 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 →