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".freeze
- BCRYPT =
Public: flag for the bcrypt algorithm
"bcrypt".freeze
- MD5 =
Public: flag for the md5 algorithm
"md5".freeze
- SHA1 =
Public: flag for the sha1 algorithm
"sha1".freeze
- PLAINTEXT =
Public: flag for the plaintext algorithm
"plaintext".freeze
- CRYPT =
Public: flag for the crypt algorithm
"crypt".freeze
- DEFAULT =
Public: flag for the default algorithm
MD5
- EXISTING =
Public: flag to indicate using the existing algorithm of the entry
"existing".freeze
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(a, b) ⇒ 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.
-
#to_64(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? return 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 } if !found then names = children.map { |c| c.algorithm_name } raise InvalidAlgorithmError, "`#{a_name}' is an unknown encryption algorithm, use one of #{names.join(', ')}" end return found.new(params) end |
.algorithm_name ⇒ Object
37 38 39 |
# File 'lib/htauth/algorithm.rb', line 37 def algorithm_name self.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, "#{self.name} must implement #{self.name}.handles?(password_entry)" end |
.secure_compare(a, b) ⇒ 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 |
# File 'lib/htauth/algorithm.rb', line 77 def secure_compare(a, b) return false unless a.bytesize == b.bytesize l = a.unpack("C*") r, i = 0, -1 b.each_byte { |v| r |= v ^ l[i+=1] } r == 0 end |
Instance Method Details
#encode(password) ⇒ Object
Internal
89 90 91 |
# File 'lib/htauth/algorithm.rb', line 89 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
102 103 104 |
# File 'lib/htauth/algorithm.rb', line 102 def gen_salt(length = SALT_LENGTH) Array.new(length) { SALT_CHARS.sample }.join('') end |
#to_64(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
109 110 111 112 113 114 115 116 |
# File 'lib/htauth/algorithm.rb', line 109 def to_64(number, rounds) r = StringIO.new rounds.times do |x| r.print(SALT_CHARS[number % 64]) number >>= 6 end return 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
96 97 98 99 |
# File 'lib/htauth/algorithm.rb', line 96 def verify_password?(password, digest) encoded = encode(password) self.class.secure_compare(encoded, digest) end |