4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
|
# File 'lib/puppet/functions/htpasswd/ht_md5.rb', line 4
Puppet::Functions.create_function(:'htpasswd::ht_md5') do
dispatch :ht_md5 do
param 'String', :password
param 'String', :salt
return_type 'String'
end
SALT_CHARS = (%w[ . / ] + ("0".."9").to_a + ('A'..'Z').to_a + ('a'..'z').to_a).freeze unless defined? SALT_CHARS
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
DIGEST_LENGTH = 16 unless defined? DIGEST_LENGTH
def ht_md5(password, salt)
prefix = '$apr1$'
primary = ::Digest::MD5.new
primary << password
primary << prefix
primary << salt
md5_t = ::Digest::MD5.digest("#{password}#{salt}#{password}")
l = password.length
while l > 0 do
slice_size = ( l > DIGEST_LENGTH ) ? DIGEST_LENGTH : l
primary << md5_t[0, slice_size]
l -= DIGEST_LENGTH
end
l = password.length
while l != 0
case (l & 1)
when 1
primary << 0.chr
when 0
primary << password[0,1]
end
l >>= 1
end
pd = primary.digest
encoded_password = "#{prefix}#{salt}$"
1000.times do |x|
ctx = ::Digest::MD5.new
ctx << (( ( x & 1 ) == 1 ) ? password : pd[0,DIGEST_LENGTH])
(ctx << salt) unless ( x % 3 ) == 0
(ctx << password) unless ( x % 7 ) == 0
ctx << (( ( x & 1 ) == 0 ) ? password : pd[0,DIGEST_LENGTH])
pd = ctx.digest
end
l = (pd[ 0].ord<<16) | (pd[ 6].ord<<8) | pd[12].ord
encoded_password << to_64(l, 4)
l = (pd[ 1].ord<<16) | (pd[ 7].ord<<8) | pd[13].ord
encoded_password << to_64(l, 4)
l = (pd[ 2].ord<<16) | (pd[ 8].ord<<8) | pd[14].ord
encoded_password << to_64(l, 4)
l = (pd[ 3].ord<<16) | (pd[ 9].ord<<8) | pd[15].ord
encoded_password << to_64(l, 4)
l = (pd[ 4].ord<<16) | (pd[10].ord<<8) | pd[ 5].ord
encoded_password << to_64(l, 4)
encoded_password << to_64(pd[11].ord,2)
return encoded_password
end
end
|