|
6 | 6 |
|
7 | 7 | class Net::LDAP::Password
|
8 | 8 | class << self
|
| 9 | + KNOWN = %i(md5 sha sha1 sha256 sha384 sha512) |
9 | 10 | # Generate a password-hash suitable for inclusion in an LDAP attribute.
|
10 | 11 | # Pass a hash type as a symbol (:md5, :sha, :ssha) and a plaintext
|
11 | 12 | # password. This function will return a hashed representation.
|
12 | 13 | #
|
13 | 14 | #--
|
14 | 15 | # STUB: This is here to fulfill the requirements of an RFC, which
|
15 | 16 | # one?
|
16 |
| - # |
17 |
| - # TODO: |
18 |
| - # * maybe salted-md5 |
19 |
| - # * Should we provide sha1 as a synonym for sha1? I vote no because then |
20 |
| - # should you also provide ssha1 for symmetry? |
21 |
| - # |
22 |
| - attribute_value = "" |
23 | 17 | def generate(type, str)
|
24 |
| - case type |
25 |
| - when :md5 |
26 |
| - attribute_value = '{MD5}' + Base64.encode64(Digest::MD5.digest(str)).chomp! |
27 |
| - when :sha |
28 |
| - attribute_value = '{SHA}' + Base64.encode64(Digest::SHA1.digest(str)).chomp! |
29 |
| - when :ssha |
30 |
| - salt = SecureRandom.random_bytes(16) |
31 |
| - attribute_value = '{SSHA}' + Base64.encode64(Digest::SHA1.digest(str + salt) + salt).chomp! |
| 18 | + if KNOWN.include?(type) |
| 19 | + digest = type.to_s |
| 20 | + salt = '' |
| 21 | + elsif type[0] == 's' && KNOWN.include?(type[1..-1].to_sym) |
| 22 | + digest = type[1..-1] |
| 23 | + salt = SecureRandom.random_bytes(16) |
32 | 24 | else
|
33 |
| - raise Net::LDAP::HashTypeUnsupportedError, "Unsupported password-hash type (#{type})" |
| 25 | + fail Net::LDAP::HashTypeUnsupportedError, |
| 26 | + "Unsupported password-hash type (#{type})" |
34 | 27 | end
|
35 |
| - return attribute_value |
| 28 | + digest = 'sha1' if digest == 'sha' |
| 29 | + type = (type == :sha1 ? :sha : :ssha) if type[-4, 4] == 'sha1' |
| 30 | + algo = Digest.module_eval(digest.upcase) |
| 31 | + "{#{type.upcase}}#{Base64.encode64(algo.digest(str + salt) + salt).chomp}" |
36 | 32 | end
|
37 | 33 | end
|
38 | 34 | end
|
0 commit comments