Class: HTAuth::Algorithm
- Inherits:
-
Object
- Object
- HTAuth::Algorithm
- Extended by:
- DescendantTracker
- Defined in:
- lib/htauth/algorithm.rb
Overview
Internal: Base class all the password algorithms derive from
Constant Summary collapse
- SALT_CHARS =
(%w[. /] + ("0".."9").to_a + ("A".."Z").to_a + ("a".."z").to_a).freeze
- SALT_LENGTH =
8- ARGON2 =
Public: flag for the argon2 algorithm
"argon2"- BCRYPT =
Public: flag for the bcrypt algorithm
"bcrypt"- MD5 =
Public: flag for the md5 algorithm
"md5"- SHA1 =
Public: flag for the sha1 algorithm
"sha1"- PLAINTEXT =
Public: flag for the plaintext algorithm
"plaintext"- CRYPT =
Public: flag for the crypt algorithm
"crypt"- DEFAULT =
Public: flag for the default algorithm
MD5- EXISTING =
Public: flag to indicate using the existing algorithm of the entry
"existing"
Class Method Summary collapse
-
.algorithm_from_field(password_field) ⇒ Object
NOTE: if it is plaintext, and the length is 13 - it may matched crypt and be tested that way.
- .algorithm_from_name(a_name, params = {}) ⇒ Object
- .algorithm_name ⇒ Object
-
.handles?(password_entry) ⇒ Boolean
Internal: Does this class handle this type of password entry.
-
.secure_compare(lhs, rhs) ⇒ Object
Internal: Constant time string comparison.
Instance Method Summary collapse
-
#encode(password) ⇒ Object
Internal.
-
#gen_salt(length = SALT_LENGTH) ⇒ Object
Internal: 8 bytes of random items from SALT_CHARS.
-
#to64(number, rounds) ⇒ Object
Internal: this is not the Base64 encoding, this is the to64() method from the Apache Portable Runtime (APR) library github.com/apache/apr/blob/trunk/crypto/apr_md5.c#L493-L502.
-
#verify_password?(password, digest) ⇒ Boolean
Internal: Does the given password match the digest, the default just encodes and secure compares the result, different algorithms may overide this method.
Methods included from DescendantTracker
children, find_child, inherited
Class Method Details
.algorithm_from_field(password_field) ⇒ Object
NOTE: if it is plaintext, and the length is 13 - it may matched crypt
and be tested that way. If that is the case - this is explicitly
siding with crypt() as you shouldn't be using plaintext. Or
crypt for that matter.
54 55 56 57 58 59 60 61 |
# File 'lib/htauth/algorithm.rb', line 54 def algorithm_from_field(password_field) match = find_child(:handles?, password_field) match = ::HTAuth::Plaintext if match.nil? && ::HTAuth::Plaintext.entry_matches?(password_field) raise InvalidAlgorithmError, "unknown encryption algorithm used for `#{password_field}`" if match.nil? match.new(existing: password_field) end |
.algorithm_from_name(a_name, params = {}) ⇒ Object
41 42 43 44 45 46 47 48 |
# File 'lib/htauth/algorithm.rb', line 41 def algorithm_from_name(a_name, params = {}) found = children.find { |c| c.algorithm_name == a_name } unless found names = children.map(&:algorithm_name) raise InvalidAlgorithmError, "`#{a_name}' is an unknown encryption algorithm, use one of #{names.join(', ')}" end found.new(params) end |
.algorithm_name ⇒ Object
37 38 39 |
# File 'lib/htauth/algorithm.rb', line 37 def algorithm_name name.split("::").last.downcase end |
.handles?(password_entry) ⇒ Boolean
Internal: Does this class handle this type of password entry
65 66 67 |
# File 'lib/htauth/algorithm.rb', line 65 def handles?(password_entry) raise NotImplementedError, "#{name} must implement #{name}.handles?(password_entry)" end |
.secure_compare(lhs, rhs) ⇒ Object
Internal: Constant time string comparison.
From github.com/rack/rack/blob/master/lib/rack/utils.rb
NOTE: the values compared should be of fixed length, such as strings that have already been processed by HMAC. This should not be used on variable length plaintext strings because it could leak length info via timing attacks.
77 78 79 80 81 82 83 84 85 86 |
# File 'lib/htauth/algorithm.rb', line 77 def secure_compare(lhs, rhs) return false unless lhs.bytesize == rhs.bytesize l = lhs.unpack("C*") r = 0 i = -1 rhs.each_byte { |v| r |= v ^ l[i += 1] } r.zero? end |
Instance Method Details
#encode(password) ⇒ Object
Internal
90 91 92 |
# File 'lib/htauth/algorithm.rb', line 90 def encode(password) raise NotImplementedError, "#{self.class.name} must implement #{self.class.name}.encode(password)" end |
#gen_salt(length = SALT_LENGTH) ⇒ Object
Internal: 8 bytes of random items from SALT_CHARS
103 104 105 |
# File 'lib/htauth/algorithm.rb', line 103 def gen_salt(length = SALT_LENGTH) Array.new(length) { SALT_CHARS.sample }.join end |
#to64(number, rounds) ⇒ Object
Internal: this is not the Base64 encoding, this is the to64() method from the Apache Portable Runtime (APR) library github.com/apache/apr/blob/trunk/crypto/apr_md5.c#L493-L502
110 111 112 113 114 115 116 117 |
# File 'lib/htauth/algorithm.rb', line 110 def to64(number, rounds) r = StringIO.new rounds.times do |_x| r.print(SALT_CHARS[number % 64]) number >>= 6 end r.string end |
#verify_password?(password, digest) ⇒ Boolean
Internal: Does the given password match the digest, the default just encodes and secure compares the result, different algorithms may overide this method
97 98 99 100 |
# File 'lib/htauth/algorithm.rb', line 97 def verify_password?(password, digest) encoded = encode(password) self.class.secure_compare(encoded, digest) end |