Class: PassForge::Passphrase
- Inherits:
-
Object
- Object
- PassForge::Passphrase
- Defined in:
- lib/passforge/passphrase.rb
Overview
Passphrase generator for creating memorable, XKCD-style passwords Uses EFF’s long wordlist for maximum security and memorability
Class Method Summary collapse
-
.crack_time(words:) ⇒ String
Estimate crack time for a passphrase.
-
.entropy(words:) ⇒ Float
Calculate entropy of a passphrase.
-
.format_time(seconds) ⇒ Object
Format seconds into human-readable time.
-
.generate(words: 4, separator: "-", capitalize: true, numbers: false) ⇒ String
Generate a passphrase.
Class Method Details
.crack_time(words:) ⇒ String
Estimate crack time for a passphrase
61 62 63 64 65 66 67 68 69 |
# File 'lib/passforge/passphrase.rb', line 61 def self.crack_time(words:) ent = entropy(words: words) guesses_per_second = 1_000_000_000 # 1 billion guesses/sec total_guesses = 2**ent seconds = total_guesses / guesses_per_second format_time(seconds) end |
.entropy(words:) ⇒ Float
Calculate entropy of a passphrase
50 51 52 53 54 55 56 |
# File 'lib/passforge/passphrase.rb', line 50 def self.entropy(words:) # EFF wordlist has 7,776 words (2^12.9) # Entropy = log2(possibilities^words) # For our wordlist: log2(1000^words) ≈ 9.97 * words wordlist_size = Wordlist::WORDS.length Math.log2(wordlist_size) * words end |
.format_time(seconds) ⇒ Object
Format seconds into human-readable time
73 74 75 76 77 78 79 80 81 82 |
# File 'lib/passforge/passphrase.rb', line 73 def self.format_time(seconds) return "instant" if seconds < 1 return "#{seconds.to_i} seconds" if seconds < 60 return "#{(seconds / 60).to_i} minutes" if seconds < 3600 return "#{(seconds / 3600).to_i} hours" if seconds < 86_400 return "#{(seconds / 86_400).to_i} days" if seconds < 31_536_000 return "#{(seconds / 31_536_000).to_i} years" if seconds < 31_536_000_000 "#{(seconds / 31_536_000_000).to_i} millennia" end |
.generate(words: 4, separator: "-", capitalize: true, numbers: false) ⇒ String
Generate a passphrase
29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 |
# File 'lib/passforge/passphrase.rb', line 29 def self.generate(words: 4, separator: "-", capitalize: true, numbers: false) raise ArgumentError, "Words must be at least 2" if words < 2 raise ArgumentError, "Words must be at most 10" if words > 10 selected_words = Wordlist.random_words(words) # Capitalize if requested selected_words = selected_words.map(&:capitalize) if capitalize # Join with separator passphrase = selected_words.join(separator) # Add random number if requested passphrase += "#{separator}#{SecureRandom.random_number(100)}" if numbers passphrase end |