Class: HTAuth::Algorithm

Inherits:
Object
  • Object
show all
Defined in:
lib/htauth/algorithm.rb

Overview

Internal: Base class all the password algorithms derive from

Direct Known Subclasses

Crypt, Md5, Plaintext, Sha1

Constant Summary collapse

SALT_CHARS =
(%w[ . / ] + ("0".."9").to_a + ('A'..'Z').to_a + ('a'..'z').to_a).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

Instance Method Summary collapse

Class Method Details

.algorithm_from_name(a_name, params = {}) ⇒ Object



29
30
31
32
# File 'lib/htauth/algorithm.rb', line 29

def algorithm_from_name(a_name, params = {})
  raise InvalidAlgorithmError, "`#{a_name}' is an invalid encryption algorithm, use one of #{sub_klasses.keys.join(', ')}" unless sub_klasses[a_name.downcase]
  sub_klasses[a_name.downcase].new(params)
end

.algorithms_from_field(password_field) ⇒ Object



34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
# File 'lib/htauth/algorithm.rb', line 34

def algorithms_from_field(password_field)
  matches = []

  if password_field.index(sub_klasses[SHA1].new.prefix) then
    matches << sub_klasses[SHA1].new
  elsif password_field.index(sub_klasses[MD5].new.prefix) then
    p = password_field.split("$")
    matches << sub_klasses[MD5].new( :salt => p[2] )
  else
    matches << sub_klasses[PLAINTEXT].new
    matches << sub_klasses[CRYPT].new( :salt => password_field[0,2] )
  end

  return matches
end

.inherited(sub_klass) ⇒ Object



50
51
52
53
# File 'lib/htauth/algorithm.rb', line 50

def inherited(sub_klass)
  k = sub_klass.name.split("::").last.downcase
  sub_klasses[k] = sub_klass
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.



67
68
69
70
71
72
73
74
75
# File 'lib/htauth/algorithm.rb', line 67

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

.sub_klassesObject



55
56
57
# File 'lib/htauth/algorithm.rb', line 55

def sub_klasses
  @sub_klasses ||= {}
end

Instance Method Details

#encode(password) ⇒ Object

Internal



82
# File 'lib/htauth/algorithm.rb', line 82

def encode(password) ; end

#gen_saltObject

Internal: 8 bytes of random items from SALT_CHARS



85
86
87
88
89
# File 'lib/htauth/algorithm.rb', line 85

def gen_salt
  chars = []
  8.times { chars << SALT_CHARS[SecureRandom.random_number(SALT_CHARS.size)] }
  chars.join('')
end

#prefixObject

Internal



79
# File 'lib/htauth/algorithm.rb', line 79

def prefix ; end

#to_64(number, rounds) ⇒ Object

Internal: this is not the Base64 encoding, this is the to64() method from the apache protable runtime library



93
94
95
96
97
98
99
100
# File 'lib/htauth/algorithm.rb', line 93

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