Created
September 30, 2013 18:16
-
-
Save antifuchs/6767842 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env ruby | |
require 'optparse' | |
def exp_notation(n) | |
Math.log10(n).floor | |
end | |
def main | |
options = {} | |
optparse = OptionParser.new do |opts| | |
opts.banner = <<-EOB | |
Usage: #{0} [options] [number of words] | |
Generate a random passphrase from words in a dictionary. | |
EOB | |
opts.on('-v', "--verbose", "Output the number of combinations from which this password was picked") { | |
options[:verbose] = true | |
} | |
opts.on('-l', '--min-length=LENGTH', 'Set the minimum length for a constituent word (default: 3)') { |length| | |
options[:min] = length.to_i | |
} | |
opts.on('-u', '--max-length=LENGTH', 'Set the maximum length for a constituent word (default: 9)') { |length| | |
options[:max] = length.to_i | |
} | |
opts.on('-f', '--dictionary=DICT', 'Dictionary file to use (default: /usr/share/dict/words)') { |dict| | |
options[:dict] = dict | |
} | |
opts.on('-x', '--exclude-easy-typos', 'Exclude repeated chars at word boundaries') { | |
options[:exclude_duplicates_at_boundaries] = true | |
} | |
opts.on('-X', '--exclude-dupes-inside', 'Exclude repeated chars inside words') { | |
options[:exclude_duplicates] = true | |
} | |
opts.on('-h', '--help', 'This help') { | |
puts opts | |
exit(1) | |
} | |
end | |
optparse.parse! | |
n=(ARGV[0] || 4).to_i | |
min = options[:min] || 3 | |
max = options[:max] || 9 | |
dict = options[:dict] || '/usr/share/dict/words' | |
lines = File.open(dict).readlines.map {|line| line.chomp.downcase }.uniq.select {|word| | |
word.length >= min && word.length <= max && (!options[:exclude_duplicates] || !word.match(/([a-z])\1/)) | |
} | |
words = [] | |
last_word = '' | |
n.times do | |
word = lines[rand(lines.length)] | |
if options[:exclude_duplicates_at_boundaries] && last_word[-1] == word.first | |
continue | |
end | |
words << word | |
last_word = word | |
end | |
passphrase = words.join(' ').downcase | |
print passphrase | |
if options[:verbose] | |
puts " (10e#{exp_notation(27 ** passphrase.length)}c 10e#{exp_notation(lines.length ** words.length)}w)" | |
else | |
puts | |
end | |
end | |
main if $0 == __FILE__ |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment