Password Generator — Ruby 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 Ruby implementation — the same logic the interactive tool runs, in a shareable, citable form.
# password-generator — CSPRNG password generation + entropy scoring. Language: Ruby (3.1+; SecureRandom). Port of src/lib/password.ts.
require 'securerandom'
module PasswordGenerator
LOWER = 'abcdefghijklmnopqrstuvwxyz'
UPPER = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
NUMBERS = '0123456789'
SYMBOLS = '!@#$%^&*()-_=+[]{};:,.<>?/'
AMBIGUOUS = 'O0Il1|' # O/0, I/l/1, pipe — dropped on request
Options = Struct.new(:length, :upper, :lower, :numbers, :symbols,
:exclude_ambiguous, keyword_init: true)
module_function
# Concat the selected pools, then drop ambiguous glyphs (mirrors buildCharset).
def build_charset(o)
cs = +''
cs << LOWER if o.lower
cs << UPPER if o.upper
cs << NUMBERS if o.numbers
cs << SYMBOLS if o.symbols
cs.delete!(AMBIGUOUS) if o.exclude_ambiguous
cs
end
# Uniform index in [0, n): reject uint32 CSPRNG draws >= the largest multiple
# of n fitting in 2^32, so `% n` carries no modulo bias.
def unbiased_index(n)
limit = (1 << 32) - ((1 << 32) % n)
loop do
r = SecureRandom.random_bytes(4).unpack1('L>')
return r % n if r < limit
end
end
# Returns '' for an empty pool or length < 1 — same contract as the TS lib.
def generate(o)
cs = build_charset(o)
return '' if cs.empty? || o.length < 1
Array.new(o.length) { cs[unbiased_index(cs.length)] }.join
end
# Theoretical entropy in bits: length * log2(|alphabet|).
def entropy_bits(length, charset_size)
return 0.0 if length <= 0 || charset_size <= 1
length * Math.log2(charset_size)
end
# Strength meter tiers, 1:1 with the TS thresholds.
def strength_tier(bits)
return 'very strong' if bits >= 100
return 'strong' if bits >= 70
return 'fair' if bits >= 45
return 'weak' if bits >= 28
'very weak'
end
# Average crack time (s) = 2^(bits-1) / guesses-per-second.
def crack_time_seconds(bits, guesses_per_second) = 2**(bits - 1) / guesses_per_second
end
o = PasswordGenerator::Options.new(length: 20, upper: true, lower: true,
numbers: true, symbols: true, exclude_ambiguous: true)
cs = PasswordGenerator.build_charset(o)
bits = PasswordGenerator.entropy_bits(o.length, cs.length)
puts "#{PasswordGenerator.generate(o)} — #{bits.round(1)} bits, #{PasswordGenerator.strength_tier(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 →