unix-crypt 1.1.1 → 1.3.0

Sign up to get free protection for your applications and to get access to all the features.
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