-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathtroubadour.rb
executable file
·95 lines (74 loc) · 2.51 KB
/
troubadour.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
#!/usr/bin/env ruby
require 'optparse'
WILDCHARS = (32..126).map { |n| n.chr }.reject { |c| c =~ /[a-zA-Z]/ }
criteria = {
minWordLength: 3,
maxWordLength: 8,
wordCount: 3,
wildCharCount: 1,
wordList: '/usr/share/dict/words',
excludeExp: /^$/
}
op = OptionParser.new do |opts|
opts.banner = "Usage: #{$PROGRAM_NAME} [options]"
opts.on('-m', '--min_length=n', 'Minimum length of word to select') do |a|
raise OptionParser::ParseError, "n must be greater than 1" if a.to_i < 2
criteria[:minWordLength] = a.to_i
end
opts.on('-M', '--max_length=n', 'Maximum length of a word to select') do |a|
raise OptionParser::ParseError, "n must be greater than 1" if a.to_i < 2
criteria[:maxWordLength] = a.to_i
end
opts.on('-n', '--words=n', 'Number of words to select') do |a|
criteria[:wordCount] = a.to_i
end
opts.on('-w', '--wild_chars=n', 'Number of wild chars to randomly insert') do |a|
criteria[:wildCharCount] = a.to_i
end
opts.on('-l', "--word_list=FILE", "Word list to select words from") do |a|
raise OptionParser::ParseError, "file does not exist" unless File.file?(a)
criteria[:wordList] = a
end
opts.on('-E', "--exclude=REGEXP", "Regular expression for excluding words") do |a|
criteria[:excludeExp] = Regexp.new(a)
end
opts.on('-h', '--help', "Prints this help") do
puts opts
exit
end
end
begin
op.parse!
rescue OptionParser::ParseError => e
puts e
puts op
exit 1
end
lines = File.readlines(criteria[:wordList]).select { |l|
l = l.chomp
l.length >= criteria[:minWordLength] &&
l.length <= criteria[:maxWordLength]
}.reject { |l| l.chomp =~ criteria[:excludeExp]}
words = []
1.upto(criteria[:wordCount]) do |i|
words << lines.sample.chomp
end
puts "Words: #{words.join(' ')}"
wildChars = []
1.upto(criteria[:wildCharCount]) do |i|
wc = WILDCHARS.sample
wildChars << wc
w = words.sample
i = words.find_index(w)
words[i] = w.insert(rand(1...w.length), wc)
end
puts "Wildchar(s): #{wildChars.join('')}"
password = words.join('')
puts "Password: #{password}"
puts "Length: #{password.length}"
wordCount = lines.length
wordCharCount = lines.map { |l| l.chomp.chars.to_a.uniq }.join('').chars.to_a.uniq.length + WILDCHARS.length
bruteForceEntropy = Math.log2(wordCharCount ** password.length).round(2)
entropy = (Math.log2(wordCount ** criteria[:wordCount]) +
(wildChars.length * Math.log2(WILDCHARS.length * (password.length - words.length)))).round(2)
puts "Entropy: #{bruteForceEntropy} (#{entropy})"