Project

General

Profile

password_crypt.rb

Si Man, 04/17/2019 08:56 AM

 
1
require 'base64'
2

    
3
class PasswordCrypt
4
  ALGORITHMS = {'SHA256' => '$5$', 'SHA512' => '$6$', 'Base64' => '', 'Base64-Windows' => ''}
5

    
6
  if Foreman::Fips.md5_available?
7
    ALGORITHMS['MD5'] = '$1$'
8
  end
9

    
10
  def self.generate_linux_salt
11
    # Linux crypt accepts maximum 16 [a-zA-Z0-9./] characters, on Ruby 2.5+ use alphanumeric
12
    # method, on older rubies let's use safe base64 downgraded to base63
13
    SecureRandom.respond_to?(:alphanumeric) ? SecureRandom.alphanumeric(16) : SecureRandom.base64(12).tr('+=', '..')
14
  end
15

    
16
  def self.passw_crypt(passwd, hash_alg = 'SHA256')
17
    raise Foreman::Exception.new(N_("Unsupported password hash function '%s'"), hash_alg) unless ALGORITHMS.has_key?(hash_alg)
18

    
19
    case hash_alg
20
    when 'Base64'
21
      result = Base64.strict_encode64(passwd)
22
    when 'Base64-Windows'
23
      passwd << "AdministratorPassword"
24
      result = Base64.strict_encode64(passwd.encode('utf-16le'))
25
    else
26
      result = passwd.crypt("#{ALGORITHMS[hash_alg]}#{self.generate_linux_salt}")
27
    end
28

    
29
    result.force_encoding(Encoding::UTF_8) if result.encoding != Encoding::UTF_8
30
    result
31
  end
32

    
33
  def self.grub2_passw_crypt(passw)
34
    self.passw_crypt(passw, 'SHA512')
35
  end
36

    
37
  def self.crypt_gnu_compatible?
38
    @crypt_gnu_compatible ||= passw_crypt("test_this").match('^\$\d+\$.+\$.+')
39
  end
40
end