Advertisement
BaSs_HaXoR

Ruby (on Rails) Password Hashing Code

Sep 9th, 2014
535
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Ruby 3.93 KB | None | 0 0
  1. # Password Hashing With PBKDF2 (http://crackstation.net/hashing-security.htm).
  2. # Copyright (c) 2013, Taylor Hornby
  3. # All rights reserved.
  4. #
  5. # Redistribution and use in source and binary forms, with or without
  6. # modification, are permitted provided that the following conditions are met:
  7. #
  8. # 1. Redistributions of source code must retain the above copyright notice,
  9. # this list of conditions and the following disclaimer.
  10. #
  11. # 2. Redistributions in binary form must reproduce the above copyright notice,
  12. # this list of conditions and the following disclaimer in the documentation
  13. # and/or other materials provided with the distribution.
  14. #
  15. # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
  16. # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  17. # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  18. # ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
  19. # LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
  20. # CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
  21. # SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
  22. # INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
  23. # CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  24. # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  25. # POSSIBILITY OF SUCH DAMAGE.
  26.  
  27. require 'securerandom'
  28. require 'openssl'
  29. require 'base64'
  30.  
  31. # Salted password hashing with PBKDF2-SHA1.
  32. # Authors: @RedragonX (dicesoft.net), havoc AT defuse.ca
  33. # www: http://crackstation.net/hashing-security.htm
  34. module PasswordHash
  35.  
  36.   # The following constants can be changed without breaking existing hashes.
  37.   PBKDF2_ITERATIONS = 1000
  38.   SALT_BYTE_SIZE = 24
  39.   HASH_BYTE_SIZE = 24
  40.  
  41.   HASH_SECTIONS = 4
  42.   SECTION_DELIMITER = ':'
  43.   ITERATIONS_INDEX = 1
  44.   SALT_INDEX = 2
  45.   HASH_INDEX = 3
  46.  
  47.   # Returns a salted PBKDF2 hash of the password.
  48.   def self.createHash( password )
  49.     salt = SecureRandom.base64( SALT_BYTE_SIZE )
  50.     pbkdf2 = OpenSSL::PKCS5::pbkdf2_hmac_sha1(
  51.       password,
  52.       salt,
  53.       PBKDF2_ITERATIONS,
  54.       HASH_BYTE_SIZE
  55.     )
  56.     return ["sha1", PBKDF2_ITERATIONS, salt, Base64.encode64( pbkdf2 )].join( SECTION_DELIMITER )
  57.   end
  58.  
  59.   # Checks if a password is correct given a hash of the correct one.
  60.   # correctHash must be a hash string generated with createHash.
  61.   def self.validatePassword( password, correctHash )
  62.     params = correctHash.split( SECTION_DELIMITER )
  63.     return false if params.length != HASH_SECTIONS
  64.  
  65.     pbkdf2 = Base64.decode64( params[HASH_INDEX] )
  66.     testHash = OpenSSL::PKCS5::pbkdf2_hmac_sha1(
  67.       password,
  68.       params[SALT_INDEX],
  69.       params[ITERATIONS_INDEX].to_i,
  70.       pbkdf2.length
  71.     )
  72.  
  73.     return pbkdf2 == testHash
  74.   end
  75.  
  76.   # Run tests to ensure the module is functioning properly.
  77.   # Returns true if all tests succeed, false if not.
  78.   def self.runSelfTests
  79.     puts "Sample hashes:"
  80.     3.times { puts createHash("password") }
  81.  
  82.     puts "\nRunning self tests..."
  83.     @@allPass = true
  84.  
  85.     correctPassword = 'aaaaaaaaaa'
  86.     wrongPassword = 'aaaaaaaaab'
  87.     hash = createHash(correctPassword)
  88.  
  89.     assert( validatePassword( correctPassword, hash ) == true, "correct password" )
  90.     assert( validatePassword( wrongPassword, hash ) == false, "wrong password" )
  91.  
  92.     h1 = hash.split( SECTION_DELIMITER )
  93.     h2 = createHash( correctPassword ).split( SECTION_DELIMITER )
  94.     assert( h1[HASH_INDEX] != h2[HASH_INDEX], "different hashes" )
  95.     assert( h1[SALT_INDEX] != h2[SALT_INDEX], "different salt" )
  96.  
  97.     if @@allPass
  98.       puts "*** ALL TESTS PASS ***"
  99.     else
  100.       puts "*** FAILURES ***"
  101.     end
  102.  
  103.     return @@allPass
  104.   end
  105.  
  106.   def self.assert( truth, msg )
  107.     if truth
  108.       puts "PASS [#{msg}]"
  109.     else
  110.       puts "FAIL [#{msg}]"
  111.       @@allPass = false
  112.     end
  113.   end
  114.  
  115. end
  116.  
  117. PasswordHash.runSelfTests
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement