Module: JunglePath::Authentication::PasswordHash

Defined in:
lib/jungle_path/authentication/password_hash.rb

Overview

Salted password hashing with PBKDF2-SHA1. Authors: @RedragonX (dicesoft.net), havoc AT defuse.ca www: crackstation.net/hashing-security.htm

Constant Summary collapse

PBKDF2_ITERATIONS =

The following constants can be changed without breaking existing hashes.

1000
SALT_BYTE_SIZE =
24
HASH_BYTE_SIZE =
24
HASH_SECTIONS =
4
SECTION_DELIMITER =
':'
ITERATIONS_INDEX =
1
SALT_INDEX =
2
HASH_INDEX =
3

Class Method Summary collapse

Class Method Details

.assert(truth, msg) ⇒ Object



112
113
114
115
116
117
118
119
# File 'lib/jungle_path/authentication/password_hash.rb', line 112

def self.assert( truth, msg )
  if truth
    puts "PASS [#{msg}]"
  else
    puts "FAIL [#{msg}]"
    @@allPass = false
  end
end

.create_hash(password) ⇒ Object

Returns a salted PBKDF2 hash of the password.



54
55
56
57
58
59
60
61
62
63
# File 'lib/jungle_path/authentication/password_hash.rb', line 54

def self.create_hash( password )
  salt = SecureRandom.base64( SALT_BYTE_SIZE )
  pbkdf2 = OpenSSL::PKCS5::pbkdf2_hmac_sha1(
    password,
    salt,
    PBKDF2_ITERATIONS,
    HASH_BYTE_SIZE
  )
  return ["sha1", PBKDF2_ITERATIONS, salt, Base64.encode64( pbkdf2 )].join( SECTION_DELIMITER )
end

.runSelfTestsObject

Run tests to ensure the module is functioning properly. Returns true if all tests succeed, false if not.



84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
# File 'lib/jungle_path/authentication/password_hash.rb', line 84

def self.runSelfTests
  puts "Sample hashes:"
  3.times { puts create_hash("password") }

  puts "\nRunning self tests..."
  @@allPass = true

  correctPassword = 'aaaaaaaaaa'
  wrongPassword = 'aaaaaaaaab'
  hash = create_hash(correctPassword)

  assert( validate_password( correctPassword, hash ) == true, "correct password" )
  assert( validate_password( wrongPassword, hash ) == false, "wrong password" )

  h1 = hash.split( SECTION_DELIMITER )
  h2 = create_hash( correctPassword ).split( SECTION_DELIMITER )
  assert( h1[HASH_INDEX] != h2[HASH_INDEX], "different hashes" )
  assert( h1[SALT_INDEX] != h2[SALT_INDEX], "different salt" )

  if @@allPass
    puts "*** ALL TESTS PASS ***"
  else
    puts "*** FAILURES ***"
  end

  return @@allPass
end

.validate_password(password, correctHash) ⇒ Object

Checks if a password is correct given a hash of the correct one. correctHash must be a hash string generated with create_hash.



67
68
69
70
71
72
73
74
75
76
77
78
79
80
# File 'lib/jungle_path/authentication/password_hash.rb', line 67

def self.validate_password( password, correctHash )
  params = correctHash.split( SECTION_DELIMITER )
  return false if params.length != HASH_SECTIONS

  pbkdf2 = Base64.decode64( params[HASH_INDEX] )
  testHash = OpenSSL::PKCS5::pbkdf2_hmac_sha1(
    password,
    params[SALT_INDEX],
    params[ITERATIONS_INDEX].to_i,
    pbkdf2.length
  )

  return pbkdf2 == testHash
end