unix-crypt 1.1.1 → 1.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 1d23e0cd7fb0edc71372a52d4bd357dbbbbd0a8b
4
- data.tar.gz: 0b135e10570ae2b629f52f441997cd304663b728
3
+ metadata.gz: a4f112426245004b2afc9ce190162d81729fcabd
4
+ data.tar.gz: a47fe1d84ca16f4597b63a3622f96b57405e25f6
5
5
  SHA512:
6
- metadata.gz: 769ec3053c3e3af385aa5feb6bee79607763a6691cf33362f08a1198296c57cb1c98d8b78472f4eb354ac0e22cba35fc10d680e7bfecb30820d7ef71eb0a1b6b
7
- data.tar.gz: a175438b7eedfe60a156aaaf003b3956cf70f7f0b054c181b29c9ca5879dbe421253b80d997331a2f095db1dcece3f5ed130df167c8dbaf82d037706cf31d317
6
+ metadata.gz: e355b3654486a6102dae8273c00cb58925e9731e268f4486fae24944bf5c63c51e18e79015cae9cc4a22b6c97182d730f5799eef155baac1c5ab879e8cf17f38
7
+ data.tar.gz: 9051d55228a699b3104ec8ea71637af6b05973a984ffd7f36d654d851673ce66259f0d72f6289c56c2dc78aadc226933dc1c2f1eac7a9592bb961d2f17651b87
@@ -12,7 +12,11 @@ It handles:
12
12
  * SHA256 passwords (starting with $5$)
13
13
  * SHA512 passwords (starting with $6$)
14
14
 
15
- This library is compatible with Ruby 1.8.7 and above. Tested on Ruby 2.0.0p0.
15
+ This library is compatible with Ruby 1.8.7 and above. Tested on Ruby 2.0.0p353.
16
+
17
+ == Installation
18
+
19
+ gem install unix-crypt
16
20
 
17
21
  == Using the command line tool
18
22
 
@@ -20,9 +24,9 @@ An executable named +mkunixcrypt+ allows you to generate passwords from the comm
20
24
 
21
25
  Usage: mkunixcrypt [options]
22
26
  Encrypts password using the unix-crypt gem
23
-
27
+
24
28
  Options:
25
- -h, --hash [HASH] Set hash algorithm [SHA512 (default), SHA256, MD5]
29
+ -h, --hash [HASH] Set hash algorithm [SHA512 (default), SHA256, MD5, DES]
26
30
  -p, --password [PASSWORD] Provide password on command line (insecure!)
27
31
  -s, --salt [SALT] Provide hash salt
28
32
  -r, --rounds [ROUNDS] Set number of hashing rounds (SHA256/SHA512 only)
@@ -31,8 +35,10 @@ An executable named +mkunixcrypt+ allows you to generate passwords from the comm
31
35
 
32
36
  == Using the library
33
37
 
34
- You can either validate a password matches its hash:
38
+ You can either validate a password of any type matches its hash:
35
39
 
40
+ >> require 'unix_crypt'
41
+ => true
36
42
  >> UnixCrypt.valid?("Hello world!", "$5$saltstring$5B8vYYiY.CVt1RlTTf8KbXBH3hsxY/GNooZaBBGWEc5")
37
43
  => true
38
44
 
@@ -46,6 +52,13 @@ If a salt is not specified, one will be generated using random data:
46
52
  >> UnixCrypt::SHA256.build("Hello world!")
47
53
  => "$5$v.fjb6lucDCZKjcf$90gzpr9HYo0eAeaN8rubElJdUUOcVYjTnGePBRvCgt1"
48
54
 
55
+ There are four classes you can use, depending on which hashing algorithm you'd like:
56
+
57
+ UnixCrypt::DES
58
+ UnixCrypt::MD5
59
+ UnixCrypt::SHA256
60
+ UnixCrypt::SHA512
61
+
49
62
  == License
50
63
 
51
64
  Licensed under the BSD license. See LICENSE file for details.
@@ -2,178 +2,30 @@ require 'digest'
2
2
  require 'securerandom'
3
3
 
4
4
  module UnixCrypt
5
- VERSION = "1.1.1"
5
+ VERSION = "1.3.0"
6
+
7
+ Error = Class.new(StandardError)
8
+ SaltTooLongError = Class.new(Error)
6
9
 
7
10
  def self.valid?(password, string)
8
11
  # Handle the original DES-based crypt(3)
9
12
  return password.crypt(string) == string if string.length == 13
10
13
 
14
+ # All other types of password follow a standard format
11
15
  return false unless m = string.match(/\A\$([156])\$(?:rounds=(\d+)\$)?(.+)\$(.+)/)
12
16
 
13
17
  hash = IDENTIFIER_MAPPINGS[m[1]].hash(password, m[3], m[2] && m[2].to_i)
14
18
  hash == m[4]
15
19
  end
20
+ end
16
21
 
17
- class Base
18
- def self.build(password, salt = nil, rounds = nil)
19
- salt ||= generate_salt
20
-
21
- "$#{identifier}$#{rounds_marker rounds}#{salt}$#{hash(password, salt, rounds)}"
22
- end
23
-
24
- def self.hash(password, salt, rounds = nil)
25
- bit_specified_base64encode internal_hash(prepare_password(password), salt, rounds)
26
- end
27
-
28
- def self.generate_salt
29
- # Generates a random salt using the same character set as the base64 encoding
30
- # used by the hash encoder.
31
- SecureRandom.base64(default_salt_length).gsub("=", "").tr("+", ".")
32
- end
33
-
34
- protected
35
- def self.bit_specified_base64encode(input)
36
- b64 = "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
37
- input = input.bytes.to_a
38
- output = ""
39
- byte_indexes.each do |i3, i2, i1|
40
- b1, b2, b3 = i1 && input[i1] || 0, i2 && input[i2] || 0, i3 && input[i3] || 0
41
- output <<
42
- b64[ b1 & 0b00111111] <<
43
- b64[((b1 & 0b11000000) >> 6) |
44
- ((b2 & 0b00001111) << 2)] <<
45
- b64[((b2 & 0b11110000) >> 4) |
46
- ((b3 & 0b00000011) << 4)] <<
47
- b64[ (b3 & 0b11111100) >> 2]
48
- end
49
-
50
- remainder = 3 - (length % 3)
51
- remainder = 0 if remainder == 3
52
- output[0..-1-remainder]
53
- end
54
-
55
- def self.prepare_password(password)
56
- # For Ruby 1.9+, convert the password to UTF-8, then treat that new string
57
- # as binary for the digest methods.
58
- if password.respond_to?(:encode)
59
- password = password.encode("UTF-8")
60
- password.force_encoding("ASCII-8BIT")
61
- end
62
-
63
- password
64
- end
65
-
66
- def self.rounds_marker(rounds)
67
- nil
68
- end
69
- end
70
-
71
- class MD5 < Base
72
- def self.digest; Digest::MD5; end
73
- def self.length; 16; end
74
- def self.default_salt_length; 6; end
75
- def self.identifier; 1; end
76
-
77
- def self.byte_indexes
78
- [[0, 6, 12], [1, 7, 13], [2, 8, 14], [3, 9, 15], [4, 10, 5], [nil, nil, 11]]
79
- end
80
-
81
- def self.internal_hash(password, salt, ignored = nil)
82
- salt = salt[0..7]
83
-
84
- b = digest.digest("#{password}#{salt}#{password}")
85
- a_string = "#{password}$1$#{salt}#{b * (password.length/length)}#{b[0...password.length % length]}"
86
-
87
- password_length = password.length
88
- while password_length > 0
89
- a_string += (password_length & 1 != 0) ? "\x0" : password[0].chr
90
- password_length >>= 1
91
- end
92
-
93
- input = digest.digest(a_string)
94
-
95
- 1000.times do |index|
96
- c_string = ((index & 1 != 0) ? password : input)
97
- c_string += salt unless index % 3 == 0
98
- c_string += password unless index % 7 == 0
99
- c_string += ((index & 1 != 0) ? input : password)
100
- input = digest.digest(c_string)
101
- end
102
-
103
- input
104
- end
105
- end
106
-
107
- class SHABase < Base
108
- protected
109
- def self.default_salt_length; 12; end
110
- def self.default_rounds; 5000; end
111
-
112
- def self.internal_hash(password, salt, rounds = nil)
113
- rounds = apply_rounds_bounds(rounds || default_rounds)
114
- salt = salt[0..15]
115
-
116
- b = digest.digest("#{password}#{salt}#{password}")
117
-
118
- a_string = password + salt + b * (password.length/length) + b[0...password.length % length]
119
-
120
- password_length = password.length
121
- while password_length > 0
122
- a_string += (password_length & 1 != 0) ? b : password
123
- password_length >>= 1
124
- end
125
-
126
- input = digest.digest(a_string)
127
-
128
- dp = digest.digest(password * password.length)
129
- p = dp * (password.length/length) + dp[0...password.length % length]
130
-
131
- ds = digest.digest(salt * (16 + input.bytes.first))
132
- s = ds * (salt.length/length) + ds[0...salt.length % length]
133
-
134
- rounds.times do |index|
135
- c_string = ((index & 1 != 0) ? p : input)
136
- c_string += s unless index % 3 == 0
137
- c_string += p unless index % 7 == 0
138
- c_string += ((index & 1 != 0) ? input : p)
139
- input = digest.digest(c_string)
140
- end
141
-
142
- input
143
- end
144
-
145
- def self.apply_rounds_bounds(rounds)
146
- rounds = 1000 if rounds < 1000
147
- rounds = 999_999_999 if rounds > 999_999_999
148
- rounds
149
- end
150
-
151
- def self.rounds_marker(rounds)
152
- if rounds && rounds != default_rounds
153
- "rounds=#{apply_rounds_bounds(rounds)}$"
154
- end
155
- end
156
- end
157
-
158
- class SHA256 < SHABase
159
- def self.digest; Digest::SHA256; end
160
- def self.length; 32; end
161
- def self.identifier; 5; end
162
-
163
- def self.byte_indexes
164
- [[0, 10, 20], [21, 1, 11], [12, 22, 2], [3, 13, 23], [24, 4, 14], [15, 25, 5], [6, 16, 26], [27, 7, 17], [18, 28, 8], [9, 19, 29], [nil, 31, 30]]
165
- end
166
- end
167
-
168
- class SHA512 < SHABase
169
- def self.digest; Digest::SHA512; end
170
- def self.length; 64; end
171
- def self.identifier; 6; end
172
- def self.byte_indexes
173
- [[0, 21, 42], [22, 43, 1], [44, 2, 23], [3, 24, 45], [25, 46, 4], [47, 5, 26], [6, 27, 48], [28, 49, 7], [50, 8, 29], [9, 30, 51], [31, 52, 10],
174
- [53, 11, 32], [12, 33, 54], [34, 55, 13], [56, 14, 35], [15, 36, 57], [37, 58, 16], [59, 17, 38], [18, 39, 60], [40, 61, 19], [62, 20, 41], [nil, nil, 63]]
175
- end
176
- end
22
+ require 'unix_crypt/base'
23
+ require 'unix_crypt/des'
24
+ require 'unix_crypt/md5'
25
+ require 'unix_crypt/sha'
177
26
 
178
- IDENTIFIER_MAPPINGS = {'1' => MD5, '5' => SHA256, '6' => SHA512}
179
- end
27
+ UnixCrypt::IDENTIFIER_MAPPINGS = {
28
+ '1' => UnixCrypt::MD5,
29
+ '5' => UnixCrypt::SHA256,
30
+ '6' => UnixCrypt::SHA512
31
+ }
@@ -0,0 +1,61 @@
1
+ class UnixCrypt::Base
2
+ def self.build(password, salt = nil, rounds = nil)
3
+ salt ||= generate_salt
4
+ if salt.length > max_salt_length
5
+ raise UnixCrypt::SaltTooLongError, "Salts longer than #{max_salt_length} characters are not permitted"
6
+ end
7
+
8
+ construct_password(password, salt, rounds)
9
+ end
10
+
11
+ def self.hash(password, salt, rounds = nil)
12
+ bit_specified_base64encode internal_hash(prepare_password(password), salt, rounds)
13
+ end
14
+
15
+ def self.generate_salt
16
+ # Generates a random salt using the same character set as the base64 encoding
17
+ # used by the hash encoder.
18
+ SecureRandom.base64((default_salt_length * 6 / 8.0).ceil).tr("+", ".")[0...default_salt_length]
19
+ end
20
+
21
+ protected
22
+ def self.construct_password(password, salt, rounds)
23
+ "$#{identifier}$#{rounds_marker rounds}#{salt}$#{hash(password, salt, rounds)}"
24
+ end
25
+
26
+ def self.bit_specified_base64encode(input)
27
+ b64 = "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
28
+ input = input.bytes.to_a
29
+ output = ""
30
+ byte_indexes.each do |i3, i2, i1|
31
+ b1, b2, b3 = i1 && input[i1] || 0, i2 && input[i2] || 0, i3 && input[i3] || 0
32
+ output <<
33
+ b64[ b1 & 0b00111111] <<
34
+ b64[((b1 & 0b11000000) >> 6) |
35
+ ((b2 & 0b00001111) << 2)] <<
36
+ b64[((b2 & 0b11110000) >> 4) |
37
+ ((b3 & 0b00000011) << 4)] <<
38
+ b64[ (b3 & 0b11111100) >> 2]
39
+ end
40
+
41
+ remainder = 3 - (length % 3)
42
+ remainder = 0 if remainder == 3
43
+ output[0..-1-remainder]
44
+ end
45
+
46
+ def self.prepare_password(password)
47
+ # For Ruby 1.9+, convert the password to UTF-8, then treat that new string
48
+ # as binary for the digest methods.
49
+ if password.respond_to?(:encode)
50
+ password = password.encode("UTF-8")
51
+ password.force_encoding("ASCII-8BIT")
52
+ end
53
+
54
+ password
55
+ end
56
+
57
+ def self.rounds_marker(rounds)
58
+ nil
59
+ end
60
+ end
61
+
@@ -22,7 +22,12 @@ class UnixCrypt::CommandLine
22
22
  password_warning
23
23
  end
24
24
 
25
- puts @options.hasher.build(@options.password, @options.salt, @options.rounds)
25
+ begin
26
+ puts @options.hasher.build(@options.password, @options.salt, @options.rounds)
27
+ rescue UnixCrypt::Error => e
28
+ $stderr.puts "password generation failed: #{e.message}"
29
+ end
30
+
26
31
  clear_string(@options.password)
27
32
  end
28
33
 
@@ -31,7 +36,8 @@ class UnixCrypt::CommandLine
31
36
  HASHERS = {
32
37
  :SHA512 => UnixCrypt::SHA512,
33
38
  :SHA256 => UnixCrypt::SHA256,
34
- :MD5 => UnixCrypt::MD5
39
+ :MD5 => UnixCrypt::MD5,
40
+ :DES => UnixCrypt::DES
35
41
  }
36
42
 
37
43
  def self.parse(args)
@@ -47,7 +53,7 @@ class UnixCrypt::CommandLine
47
53
  opts.separator ""
48
54
  opts.separator "Options:"
49
55
 
50
- opts.on("-h", "--hash [HASH]", String, "Set hash algorithm [SHA512 (default), SHA256, MD5]") do |hasher|
56
+ opts.on("-h", "--hash [HASH]", String, "Set hash algorithm [SHA512 (default), SHA256, MD5, DES]") do |hasher|
51
57
  options.hashmethod = hasher.to_s.upcase.to_sym
52
58
  options.hasher = HASHERS[options.hashmethod]
53
59
  raise Abort, "Invalid hash algorithm for -h/--hash" if options.hasher.nil?
@@ -0,0 +1,13 @@
1
+ class UnixCrypt::DES < UnixCrypt::Base
2
+ def self.hash(*args)
3
+ raise "Unimplemented for DES"
4
+ end
5
+
6
+ protected
7
+ def self.construct_password(password, salt, rounds)
8
+ password.crypt(salt)
9
+ end
10
+
11
+ def self.default_salt_length; 2; end
12
+ def self.max_salt_length; 2; end
13
+ end
@@ -0,0 +1,37 @@
1
+ class UnixCrypt::MD5 < UnixCrypt::Base
2
+ protected
3
+ def self.digest; Digest::MD5; end
4
+ def self.length; 16; end
5
+ def self.default_salt_length; 8; end
6
+ def self.max_salt_length; 8; end
7
+ def self.identifier; 1; end
8
+
9
+ def self.byte_indexes
10
+ [[0, 6, 12], [1, 7, 13], [2, 8, 14], [3, 9, 15], [4, 10, 5], [nil, nil, 11]]
11
+ end
12
+
13
+ def self.internal_hash(password, salt, ignored = nil)
14
+ salt = salt[0..7]
15
+
16
+ b = digest.digest("#{password}#{salt}#{password}")
17
+ a_string = "#{password}$1$#{salt}#{b * (password.length/length)}#{b[0...password.length % length]}"
18
+
19
+ password_length = password.length
20
+ while password_length > 0
21
+ a_string += (password_length & 1 != 0) ? "\x0" : password[0].chr
22
+ password_length >>= 1
23
+ end
24
+
25
+ input = digest.digest(a_string)
26
+
27
+ 1000.times do |index|
28
+ c_string = ((index & 1 != 0) ? password : input)
29
+ c_string += salt unless index % 3 == 0
30
+ c_string += password unless index % 7 == 0
31
+ c_string += ((index & 1 != 0) ? input : password)
32
+ input = digest.digest(c_string)
33
+ end
34
+
35
+ input
36
+ end
37
+ end
@@ -0,0 +1,75 @@
1
+ module UnixCrypt
2
+ class SHABase < Base
3
+ protected
4
+ def self.default_salt_length; 16; end
5
+ def self.max_salt_length; 16; end
6
+ def self.default_rounds; 5000; end
7
+
8
+ def self.internal_hash(password, salt, rounds = nil)
9
+ rounds = apply_rounds_bounds(rounds || default_rounds)
10
+ salt = salt[0..15]
11
+
12
+ b = digest.digest("#{password}#{salt}#{password}")
13
+
14
+ a_string = password + salt + b * (password.length/length) + b[0...password.length % length]
15
+
16
+ password_length = password.length
17
+ while password_length > 0
18
+ a_string += (password_length & 1 != 0) ? b : password
19
+ password_length >>= 1
20
+ end
21
+
22
+ input = digest.digest(a_string)
23
+
24
+ dp = digest.digest(password * password.length)
25
+ p = dp * (password.length/length) + dp[0...password.length % length]
26
+
27
+ ds = digest.digest(salt * (16 + input.bytes.first))
28
+ s = ds * (salt.length/length) + ds[0...salt.length % length]
29
+
30
+ rounds.times do |index|
31
+ c_string = ((index & 1 != 0) ? p : input)
32
+ c_string += s unless index % 3 == 0
33
+ c_string += p unless index % 7 == 0
34
+ c_string += ((index & 1 != 0) ? input : p)
35
+ input = digest.digest(c_string)
36
+ end
37
+
38
+ input
39
+ end
40
+
41
+ def self.apply_rounds_bounds(rounds)
42
+ rounds = 1000 if rounds < 1000
43
+ rounds = 999_999_999 if rounds > 999_999_999
44
+ rounds
45
+ end
46
+
47
+ def self.rounds_marker(rounds)
48
+ if rounds && rounds != default_rounds
49
+ "rounds=#{apply_rounds_bounds(rounds)}$"
50
+ end
51
+ end
52
+ end
53
+
54
+ class SHA256 < SHABase
55
+ protected
56
+ def self.digest; Digest::SHA256; end
57
+ def self.length; 32; end
58
+ def self.identifier; 5; end
59
+
60
+ def self.byte_indexes
61
+ [[0, 10, 20], [21, 1, 11], [12, 22, 2], [3, 13, 23], [24, 4, 14], [15, 25, 5], [6, 16, 26], [27, 7, 17], [18, 28, 8], [9, 19, 29], [nil, 31, 30]]
62
+ end
63
+ end
64
+
65
+ class SHA512 < SHABase
66
+ protected
67
+ def self.digest; Digest::SHA512; end
68
+ def self.length; 64; end
69
+ def self.identifier; 6; end
70
+ def self.byte_indexes
71
+ [[0, 21, 42], [22, 43, 1], [44, 2, 23], [3, 24, 45], [25, 46, 4], [47, 5, 26], [6, 27, 48], [28, 49, 7], [50, 8, 29], [9, 30, 51], [31, 52, 10],
72
+ [53, 11, 32], [12, 33, 54], [34, 55, 13], [56, 14, 35], [15, 36, 57], [37, 58, 16], [59, 17, 38], [18, 39, 60], [40, 61, 19], [62, 20, 41], [nil, nil, 63]]
73
+ end
74
+ end
75
+ end
@@ -50,25 +50,50 @@ class UnixCryptTest < Test::Unit::TestCase
50
50
  end
51
51
  end
52
52
 
53
- def test_md5_password_generation
53
+ def test_validity_of_des_password_generation
54
+ hash = UnixCrypt::DES.build("test")
55
+ assert UnixCrypt.valid?("test", hash)
56
+
57
+ hash = UnixCrypt::DES.build("test", 'xx')
58
+ assert UnixCrypt.valid?("test", hash)
59
+ end
60
+
61
+ def test_validity_of_md5_password_generation
54
62
  hash = UnixCrypt::MD5.build("test")
55
63
  assert UnixCrypt.valid?("test", hash)
64
+
65
+ hash = UnixCrypt::MD5.build("test", "abcdefgh")
66
+ assert UnixCrypt.valid?("test", hash)
56
67
  end
57
68
 
58
- def test_sha256_password_generation
69
+ def test_validity_of_sha256_password_generation
59
70
  hash = UnixCrypt::SHA256.build("test")
60
71
  assert UnixCrypt.valid?("test", hash)
72
+
73
+ hash = UnixCrypt::SHA256.build("test", "1234567890123456")
74
+ assert UnixCrypt.valid?("test", hash)
61
75
  end
62
76
 
63
- def test_sha512_password_generation
77
+ def test_validity_of_sha512_password_generation
64
78
  hash = UnixCrypt::SHA512.build("test")
65
79
  assert UnixCrypt.valid?("test", hash)
80
+
81
+ hash = UnixCrypt::SHA512.build("test", "1234567890123456")
82
+ assert UnixCrypt.valid?("test", hash)
66
83
  end
67
84
 
68
- def test_salt_generation
85
+ def test_structure_of_generated_passwords_and_salts
86
+ assert_match %r{\A[a-zA-Z0-9./]{13}\z}, UnixCrypt::DES.build("test password")
87
+ assert_match %r{\Azz[a-zA-Z0-9./]{11}\z}, UnixCrypt::DES.build("test password", 'zz')
88
+
69
89
  assert_match %r{\A\$1\$[a-zA-Z0-9./]{8}\$[a-zA-Z0-9./]{22}\z}, UnixCrypt::MD5.build("test password")
90
+ assert_match %r{\A\$1\$abcdefgh\$[a-zA-Z0-9./]{22}\z}, UnixCrypt::MD5.build("test password", "abcdefgh")
91
+
70
92
  assert_match %r{\A\$5\$[a-zA-Z0-9./]{16}\$[a-zA-Z0-9./]{43}\z}, UnixCrypt::SHA256.build("test password")
93
+ assert_match %r{\A\$5\$0123456789abcdef\$[a-zA-Z0-9./]{43}\z}, UnixCrypt::SHA256.build("test password", "0123456789abcdef")
94
+
71
95
  assert_match %r{\A\$6\$[a-zA-Z0-9./]{16}\$[a-zA-Z0-9./]{86}\z}, UnixCrypt::SHA512.build("test password")
96
+ assert_match %r{\A\$6\$0123456789abcdef\$[a-zA-Z0-9./]{86}\z}, UnixCrypt::SHA512.build("test password", "0123456789abcdef")
72
97
  end
73
98
 
74
99
  def test_password_generation_with_rounds
@@ -88,4 +113,10 @@ class UnixCryptTest < Test::Unit::TestCase
88
113
  assert_match %r{\A\$6\$rounds=1000\$[a-zA-Z0-9./]{16}\$[a-zA-Z0-9./]{86}\z}, hash
89
114
  assert UnixCrypt.valid?("test password", hash)
90
115
  end
116
+
117
+ def test_salt_is_not_longer_than_max_length
118
+ assert_raise(UnixCrypt::SaltTooLongError) { UnixCrypt::DES.build("test", "123") }
119
+ assert_raise(UnixCrypt::SaltTooLongError) { UnixCrypt::MD5.build("test", "123456789") }
120
+ assert_raise(UnixCrypt::SaltTooLongError) { UnixCrypt::SHA256.build("test", "12345678901234567") }
121
+ end
91
122
  end
@@ -1,4 +1,7 @@
1
- require './lib/unix_crypt'
1
+ lib = File.expand_path('../lib/', __FILE__)
2
+ $:.unshift lib unless $:.include?(lib)
3
+
4
+ require 'unix_crypt'
2
5
 
3
6
  spec = Gem::Specification.new do |s|
4
7
  s.name = 'unix-crypt'
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: unix-crypt
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.1.1
4
+ version: 1.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Roger Nesbitt
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2013-09-23 00:00:00.000000000 Z
11
+ date: 2013-12-11 00:00:00.000000000 Z
12
12
  dependencies: []
13
13
  description: Performs the UNIX crypt(3) algorithm using DES (standard 13 character
14
14
  passwords), MD5 (starting with $1$), SHA256 (starting with $5$) and SHA512 (starting
@@ -25,7 +25,11 @@ files:
25
25
  - Rakefile
26
26
  - bin/mkunixcrypt
27
27
  - lib/unix_crypt.rb
28
+ - lib/unix_crypt/base.rb
28
29
  - lib/unix_crypt/command_line.rb
30
+ - lib/unix_crypt/des.rb
31
+ - lib/unix_crypt/md5.rb
32
+ - lib/unix_crypt/sha.rb
29
33
  - test/test_unix_crypt.rb
30
34
  - test/unix_crypt/test_command_line.rb
31
35
  - unix-crypt.gemspec
@@ -49,7 +53,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
49
53
  version: '0'
50
54
  requirements: []
51
55
  rubyforge_project:
52
- rubygems_version: 2.0.2
56
+ rubygems_version: 2.1.11
53
57
  signing_key:
54
58
  specification_version: 4
55
59
  summary: Performs the UNIX crypt(3) algorithm using DES, MD5, SHA256 or SHA512