passgen 1.1.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,13 @@
1
+ v1.0.1 Corrected syntax error with ruby1.9.2
2
+
3
+ v1.0.0. Added password strength analyzer
4
+
5
+ v0.9.1. Had not added new files in 0.9.0 version
6
+
7
+ v0.9.0. Added pronounceable passwords
8
+
9
+ v0.1.3. Updated help
10
+
11
+ v0.1.2. Moved to rubygems.org
12
+
13
+ v0.1.1. First public release
@@ -0,0 +1,11 @@
1
+ CHANGELOG
2
+ Manifest
3
+ README.rdoc
4
+ Rakefile
5
+ rails/init.rb
6
+ lib/passgen.rb
7
+ lib/passgen/probabilities.rb
8
+ lib/passgen/strength_analyzer.rb
9
+ passgen.gemspec
10
+ spec/passgen/strength_analyzer_spec.rb
11
+ spec/passgen_spec.rb
@@ -0,0 +1,158 @@
1
+ = Passgen
2
+
3
+ Ruby gem for generating passwords quickly and easily. Although it is
4
+ suitable for use within Rails it has no Rails dependencies and can be used in
5
+ non-Rails applications as well.
6
+
7
+ It can generate passwords including lower case, upper case, digits and symbols and also
8
+ pronounceable passwords.
9
+
10
+ Since 1.0.0 you can also analyze the quality of a password, both as a numeric score
11
+ between 0 and 100 and as a complexity ranking.
12
+
13
+ The algorithm used exists in a number of variations for different languages, if if anyone
14
+ knows its origin and would like to include credit to the original author, please get in
15
+ touch via GitHub.
16
+
17
+ == Install
18
+
19
+ gem install passgen
20
+
21
+ == Usage
22
+
23
+ The usage could not be easier. Just require and call the generate method:
24
+
25
+ >> require 'rubygems'
26
+ >> require 'passgen'
27
+ >> Passgen::generate
28
+ => "zLWCeS3xC9"
29
+
30
+ You check the strength of a password by calling analyze:
31
+
32
+ >> info = Passgen::analyze("zLWCeS3xC9")
33
+ => #<Passgen::StrengthAnalyzer:0xb728654c @complexity="Strong", @score=78, @errors=[], @password="zLWCeS3xC9">
34
+ >> info.score
35
+ => 78
36
+ >> info.complexity
37
+ => "Strong"
38
+
39
+ == Examples
40
+
41
+ >> Passgen::generate
42
+ => "zLWCeS3xC9"
43
+
44
+ >> Passgen::generate(:length => 20)
45
+ => "6lCcHvkuEW6OuzAtkoAs"
46
+
47
+ >> Passgen::generate(:symbols => true)
48
+ => "gr)$6bIym1"
49
+
50
+ >> Passgen::generate(:lowercase => :only)
51
+ => "ysbwuxbcea"
52
+
53
+ >> Passgen::generate(:number => 3)
54
+ => ["REdOigTkdI", "PQu8DsV9WZ", "qptKLbw8YQ"]
55
+
56
+ >> Passgen::generate(:seed => 5)
57
+ => "JoV9M2qjiK"
58
+ >> Passgen::generate(:seed => 5) # Will generate same password again
59
+ => "JoV9M2qjiK"
60
+
61
+ >> Passgen::generate(:pronounceable => true) # Pronounceable, mixed case password
62
+ => "ActeodEuRT"
63
+ >> Passgen::generate(:pronounceable => true, :lowercase => :only) # Pronounceable lower case
64
+ => "terysolang"
65
+ >> Passgen::generate(:pronounceable => true, :uppercase => :only) # Pronounceable upper case
66
+ => "ACTOPECHEI"
67
+ >> Passgen::generate(:pronounceable => true, :digits_before => 3) # Pad with digits in front
68
+ => "886uRApLIN"
69
+ >> Passgen::generate(:pronounceable => true, :digits_before => 3) # Pad with digits at the end
70
+ => "uRAPLIN886"
71
+
72
+ == Options:
73
+
74
+ === :lowercase => true/false/:only
75
+ * true - Use lowercase letters in the generated password.
76
+ * false - Do not use lowercase letters in the generated password.
77
+ * :only - Only use lowercase letters in the generated password.
78
+
79
+ === :uppercase => true/false/:only
80
+ * true - Use uppercase letters in the generated password.
81
+ * false - Do not use uppercase letters in the generated password.
82
+ * :only - Only use uppercase letters in the generated password.
83
+
84
+ === :digits => true/false/:only
85
+ * true - Use digits in the generated password.
86
+ * false - Do not use digits in the generated password.
87
+ * :only - Only use digits in the generated password.
88
+
89
+ === :symbols => true/false/:only/:list
90
+ * true - Use symbols in the generated password.
91
+ * false - Do not use symbols in the generated password.
92
+ * :only - Only use symbols in the generated password.
93
+ * :list - A string with the symbols to use. Not implemented yet.
94
+
95
+ === :number => integer
96
+ Number of passwords to generate. If >1 the result is an Array.
97
+
98
+ === :length => integer/range
99
+ The number of characters in the generated passwords. A range results in passwords
100
+ lengths within the given range.
101
+
102
+ === :seed => integer/:default
103
+ Set the srand seed to the given integer prior to generating the passwords.
104
+
105
+ === :pronounceable => true/false
106
+ * true - Generate pronounceable passwords
107
+ * false - No effect
108
+
109
+ === :digits_after => true/number (Only in combination with :pronounceable)
110
+ * Pads the pronounceable password with number digits at the end. Defaults to 2 if true is passed.
111
+
112
+ === :digits_before => true/number (Only in combination with :pronounceable)
113
+ * Pads the pronounceable password with number digits in front. Defaults to 2 if true is passed.
114
+
115
+ === Default values:
116
+
117
+ :lowercase => true
118
+
119
+ :uppercase => true
120
+
121
+ :digits => true
122
+
123
+ :symbols => false
124
+
125
+ :pronounceable => Not implemented yet.
126
+
127
+ :number => 1
128
+
129
+ :length => 10
130
+
131
+ :seed => nil
132
+
133
+ :pronounceable => false
134
+
135
+ :digits_after => 2 (Only in combination with pronounceable)
136
+
137
+ :digits_before => 2 (Only in combination with pronounceable)
138
+
139
+ == Copyright and license
140
+
141
+ Permission is hereby granted, free of charge, to any person obtaining
142
+ a copy of this software and associated documentation files (the
143
+ "Software"), to deal in the Software without restriction, including
144
+ without limitation the rights to use, copy, modify, merge, publish,
145
+ distribute, sublicense, and/or sell copies of the Software, and to
146
+ permit persons to whom the Software is furnished to do so, subject to
147
+ the following conditions:
148
+
149
+ The above copyright notice and this permission notice shall be
150
+ included in all copies or substantial portions of the Software.
151
+
152
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
153
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
154
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
155
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
156
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
157
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
158
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,15 @@
1
+ # Rakefile
2
+ require 'rubygems'
3
+ require 'rake'
4
+ require 'echoe'
5
+
6
+ Echoe.new('passgen', '1.0.1') do |p|
7
+ p.description = "A password generation gem for Ruby and Rails applications."
8
+ p.url = "http://github.com/cryptice/passgen"
9
+ p.author = "Erik Lindblad"
10
+ p.email = "erik@l2c.se"
11
+ p.ignore_pattern = ["tmp/*", "script/*", "nbproject/*"]
12
+ p.development_dependencies = []
13
+ end
14
+
15
+ Dir["#{File.dirname(__FILE__)}/tasks/*.rake"].sort.each { |ext| load ext }
@@ -0,0 +1,328 @@
1
+ #= Passgen
2
+ #
3
+ #Ruby gem for generating passwords quickly and easily. Although it is
4
+ #suitable for use within Rails it has no Rails dependencies and can be used in
5
+ #non-Rails applications as well.
6
+ #
7
+ #== Install
8
+ #
9
+ # gem install cryptice-passgen --source http://gems.github.com
10
+ #
11
+ #== Usage
12
+ #
13
+ #The usage could not be easier. Just require and call the generate method:
14
+ #
15
+ # >> require 'rubygems'
16
+ # >> require 'passgen'
17
+ # >> Passgen::generate
18
+ # => "zLWCeS3xC9"
19
+ #
20
+ #== Examples
21
+ #
22
+ # >> Passgen::generate
23
+ # => "zLWCeS3xC9"
24
+ #
25
+ # >> Passgen::generate(:length => 20)
26
+ # => "6lCcHvkuEW6OuzAtkoAs"
27
+ #
28
+ # >> Passgen::generate(:symbols => true)
29
+ # => "gr)$6bIym1"
30
+ #
31
+ # >> Passgen::generate(:lowercase => :only)
32
+ # => "ysbwuxbcea"
33
+ #
34
+ # >> Passgen::generate(:number => 3)
35
+ # => ["REdOigTkdI", "PQu8DsV9WZ", "qptKLbw8YQ"]
36
+ #
37
+ # >> Passgen::generate(:seed => 5)
38
+ # => "JoV9M2qjiK"
39
+ # >> Passgen::generate(:seed => 5) # Will generate same password again
40
+ # => "JoV9M2qjiK"
41
+ #
42
+ # >> Passgen::generate(:seed => :default) # Will set random seed...
43
+ # => "SI8QDBdV98"
44
+ # >> Passgen::generate(:seed => :default) # and hence give different password
45
+ # => "tHHU5HLBAn"
46
+ #
47
+ #== Options:
48
+ #
49
+ #=== :lowercase => true/false/:only
50
+ #* true - Use lowercase letters in the generated password.
51
+ #* false - Do not use lowercase letters in the generated password.
52
+ #* :only - Only use lowercase letters in the generated password.
53
+ #
54
+ #=== :uppercase => true/false/:only
55
+ #* true - Use uppercase letters in the generated password.
56
+ #* false - Do not use uppercase letters in the generated password.
57
+ #* :only - Only use uppercase letters in the generated password.
58
+ #
59
+ #=== :digits => true/false/:only
60
+ #* true - Use digits in the generated password.
61
+ #* false - Do not use digits in the generated password.
62
+ #* :only - Only use digits in the generated password.
63
+ #
64
+ #=== :symbols => true/false/:only/:list
65
+ #* true - Use symbols in the generated password.
66
+ #* false - Do not use symbols in the generated password.
67
+ #* :only - Only use symbols in the generated password.
68
+ #* :list - A string with the symbols to use. Not implemented yet.
69
+ #
70
+ #=== :pronounceable => true/false
71
+ #Not implmented yet.
72
+ #
73
+ #=== :number => integer
74
+ #Number of passwords to generate. If >1 the result is an Array.
75
+ #
76
+ #=== :length => integer/range
77
+ #The number of characters in the generated passwords. A range results in passwords
78
+ #lengths within the given range.
79
+ #
80
+ #=== :seed => integer/:default
81
+ #Set the srand seed to the given integer prior to generating the passwords.
82
+ #
83
+ #=== Default values:
84
+ #
85
+ #:lowercase => true
86
+ #
87
+ #:uppercase => true
88
+ #
89
+ #:digits => true
90
+ #
91
+ #:symbols => false
92
+ #
93
+ #:pronounceable => Not implemented yet.
94
+ #
95
+ #:number => 1
96
+ #
97
+ #:length => 10
98
+ #
99
+ #:seed => nil
100
+ #
101
+ #== Copyright and license
102
+ #
103
+ #Copyright (c) 2009 Erik Lindblad
104
+ #
105
+ #Permission is hereby granted, free of charge, to any person obtaining
106
+ #a copy of this software and associated documentation files (the
107
+ #"Software"), to deal in the Software without restriction, including
108
+ #without limitation the rights to use, copy, modify, merge, publish,
109
+ #distribute, sublicense, and/or sell copies of the Software, and to
110
+ #permit persons to whom the Software is furnished to do so, subject to
111
+ #the following conditions:
112
+ #
113
+ #The above copyright notice and this permission notice shall be
114
+ #included in all copies or substantial portions of the Software.
115
+ #
116
+ #THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
117
+ #EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
118
+ #MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
119
+ #NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
120
+ #LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
121
+ #OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
122
+ #WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
123
+
124
+ require 'digest'
125
+ require 'passgen/probabilities'
126
+ require 'passgen/strength_analyzer'
127
+
128
+ module Passgen
129
+
130
+ VERSION = "1.0.0"
131
+
132
+ DEFAULT_PARAMS = {
133
+ :number => 1,
134
+ :length => 10,
135
+ :lowercase => true,
136
+ :uppercase => true,
137
+ :digits => true,
138
+ :symbols => false,
139
+ :pronounceable => false
140
+ }
141
+
142
+ def self.default_seed
143
+ Digest::MD5.hexdigest("#{rand}#{Time.now}#{Process.object_id}").to_i(16)
144
+ end
145
+
146
+ def self.generate(params={})
147
+ set_options(params)
148
+ tokens = valid_tokens
149
+ set_seed
150
+
151
+ if n == 1
152
+ generate_one(tokens)
153
+ else
154
+ Array.new(n) {|i| generate_one(tokens) }
155
+ end
156
+ end
157
+
158
+ def self.analyze(pw)
159
+ Passgen::StrengthAnalyzer.analyze(pw)
160
+ end
161
+
162
+ private
163
+ def self.alphabet(index)
164
+ if use_lowercase? && !use_uppercase?
165
+ LOWERCASE_TOKENS[index]
166
+ elsif use_uppercase? && !use_lowercase?
167
+ UPPERCASE_TOKENS[index]
168
+ else
169
+ tmp = LOWERCASE_TOKENS[index]
170
+ tmp.upcase! if rand > 0.5
171
+ tmp
172
+ end
173
+ end
174
+
175
+ def self.generate_one(tokens)
176
+ if @options[:pronounceable]
177
+ generate_pronounceable
178
+ else
179
+ Array.new(password_length) {tokens[rand(tokens.size)]}.join
180
+ end
181
+ end
182
+
183
+ def self.generate_pronounceable
184
+ password = ""
185
+
186
+ # Append digits in front
187
+ digits_prefix = if @options[:digits_before]
188
+ @options[:length] -= @options[:digits_before]
189
+ Array.new(@options[:digits_before]) {DIGIT_TOKENS[rand(DIGIT_TOKENS.size)]}.join
190
+ else
191
+ ""
192
+ end
193
+
194
+ # Append digits at the end
195
+ digits_suffix = if @options[:digits_after]
196
+ @options[:length] -= @options[:digits_after]
197
+ Array.new(@options[:digits_after]) {DIGIT_TOKENS[rand(DIGIT_TOKENS.size)]}.join
198
+ else
199
+ ""
200
+ end
201
+
202
+ # Find a random starting point.
203
+ found_start = false
204
+ ranno = rand * SIGMA # random number [0,1[ weighed by sum of frequencies
205
+ sum = 0;
206
+ N_LETTERS.times do |c1|
207
+ N_LETTERS.times do |c2|
208
+ N_LETTERS.times do |c3|
209
+ sum += P[c1][c2][c3]
210
+ if sum > ranno
211
+ password << alphabet(c1)
212
+ password << alphabet(c2)
213
+ password << alphabet(c3)
214
+ found_start = true
215
+ break
216
+ end
217
+ end
218
+ break if found_start
219
+ end
220
+ break if found_start
221
+ end
222
+
223
+ # Do a random walk.
224
+ (3...@options[:length]).each do |nchar|
225
+ c1 = LETTER_INDEXES[password[nchar-2..nchar-2]]
226
+ c2 = LETTER_INDEXES[password[nchar-1..nchar-1]]
227
+ sum = 0
228
+ N_LETTERS.times {|c3| sum += P[c1][c2][c3]}
229
+ break if sum == 0
230
+ ranno = rand * sum
231
+ sum = 0;
232
+ N_LETTERS.times do |c3|
233
+ sum += P[c1][c2][c3]
234
+ if sum > ranno
235
+ password << alphabet(c3)
236
+ break
237
+ end
238
+ end
239
+ end
240
+ digits_prefix + password + digits_suffix
241
+ end
242
+
243
+ def self.password_length
244
+ if @options[:length].is_a?(Range)
245
+ tmp = @options[:length].to_a
246
+ tmp[rand(tmp.size)]
247
+ else
248
+ @options[:length].to_i
249
+ end
250
+ end
251
+
252
+ def self.n
253
+ @options[:number]
254
+ end
255
+
256
+ def self.set_options(params)
257
+ if params[:lowercase] == :only
258
+ params[:uppercase] = false
259
+ params[:digits] = false
260
+ end
261
+
262
+ if params[:uppercase] == :only
263
+ params[:lowercase] = false
264
+ params[:digits] = false
265
+ end
266
+
267
+ if params[:digits] == :only
268
+ params[:lowercase] = false
269
+ params[:uppercase] = false
270
+ end
271
+
272
+ if params[:symbols] == :only
273
+ params[:lowercase] = false
274
+ params[:uppercase] = false
275
+ params[:digits] = false
276
+ params[:symbols] = true
277
+ end
278
+
279
+ if params[:digits_before] == true
280
+ params[:digits_before] = 2
281
+ end
282
+
283
+ if params[:digits_after] == true
284
+ params[:digits_after] = 2
285
+ end
286
+
287
+ @options = DEFAULT_PARAMS.merge(params)
288
+ end
289
+
290
+ def self.set_seed
291
+ if @options[:seed]
292
+ if @options[:seed] == :default
293
+ srand(default_seed)
294
+ else
295
+ srand(@options[:seed])
296
+ end
297
+ end
298
+ end
299
+
300
+ def self.symbol_tokens
301
+ %w{! @ # $ % & / ( ) + ? *}
302
+ end
303
+
304
+ def self.use_lowercase?
305
+ @options[:lowercase]
306
+ end
307
+
308
+ def self.use_uppercase?
309
+ @options[:uppercase]
310
+ end
311
+
312
+ def self.use_digits?
313
+ @options[:digits]
314
+ end
315
+
316
+ def self.use_symbols?
317
+ @options[:symbols]
318
+ end
319
+
320
+ def self.valid_tokens
321
+ tmp = []
322
+ tmp += LOWERCASE_TOKENS if use_lowercase?
323
+ tmp += UPPERCASE_TOKENS if use_uppercase?
324
+ tmp += DIGIT_TOKENS if use_digits?
325
+ tmp += symbol_tokens if use_symbols?
326
+ tmp
327
+ end
328
+ end