module Capsium::Reactor::Htpasswd::Md5Crypt
md5-crypt as deployed by Apache htpasswd, OpenSSL and glibc ($1$ and $apr1$ magics; identical except for the magic string). NOTE: Poul-Henning Kamp’s original FreeBSD implementation mixed the magic in at the % 7 step where all deployed implementations mix in the password (see apr_md5.c, glibc crypt-md5.c).
Constants
- DIGEST_GROUPS
- ITOA64
Public Class Methods
(String password, String salt, String magic) → String
Source
# File lib/capsium/reactor/htpasswd.rb, line 35 def self.digest(password, salt, magic) final = initial_digest(password, salt, magic) 1000.times do |i| final = stretch_digest(i, password, salt, final) end "#{magic}#{salt}$#{to64(final)}" end
(String password, String salt, String magic) → String
Source
# File lib/capsium/reactor/htpasswd.rb, line 43 def self.initial_digest(password, salt, magic) inner = Digest::MD5.digest(password + salt + password) context = Digest::MD5.new context << password << magic << salt length = password.length while length.positive? context << inner[0, [16, length].min] length -= 16 end length = password.length while length.positive? context << (length.odd? ? "\0" : password[0]) length >>= 1 end context.digest end
(Integer iteration, String password, String salt, String final) → String
Source
# File lib/capsium/reactor/htpasswd.rb, line 60 def self.stretch_digest(iteration, password, salt, final) context = Digest::MD5.new context << (iteration.odd? ? password : final) context << salt unless (iteration % 3).zero? context << password unless (iteration % 7).zero? context << (iteration.odd? ? final : password) context.digest end
(String final) → String
Source
# File lib/capsium/reactor/htpasswd.rb, line 71 def self.to64(final) encoded = +"" DIGEST_GROUPS.each do |a, b, c| value = final[c].ord | (final[b].ord << 8) | (final[a].ord << 16) 4.times do encoded << ITOA64[value & 0x3f] value >>= 6 end end value = final[11].ord 2.times do encoded << ITOA64[value & 0x3f] value >>= 6 end encoded end
The custom base-64 of md5-crypt: digest triples permuted, first index to the high bits, 22 characters total.
(String hash, String password) → bool
Source
# File lib/capsium/reactor/htpasswd.rb, line 28 def self.verify(hash, password) _prefix, magic, salt, = hash.split("$", 4) return false if salt.nil? || salt.empty? Reactor.secure_compare(digest(password, salt, "$#{magic}$"), hash) end