Last active
December 3, 2015 22:33
-
-
Save tsdorsey/d56fdb25d83246f18942 to your computer and use it in GitHub Desktop.
Revisions
-
tsdorsey revised this gist
Dec 3, 2015 . 1 changed file with 0 additions and 3 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -75,9 +75,6 @@ def _validateHashedPassword(hashedPassword) # Test cases to validate the verifyHashedPassword method. def testKnown() for password, hash in [ # Top 25 most used passwords in 2014. ['123456', 'AH9EGs/zg3gzLLdKuEe44+ShE07rl7K1uoQ1fXFM1GjdWdz8MamHpQhaeFgaUDzv0A=='], ['password', 'ACHYpKal/KMrWR+b2ucEFmYhCc5K/RfXJPUq0KAXxUjvN76EuxSnH7Cr0wNsnmPTmA=='], -
tsdorsey renamed this gist
Nov 25, 2015 . 1 changed file with 0 additions and 0 deletions.There are no files selected for viewing
File renamed without changes. -
tsdorsey created this gist
Nov 25, 2015 .There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,116 @@ require 'base64' require 'openssl' require 'securerandom' # Creates and interprets .NET RFC2898 version 0 encoded passwords. # Password format is Base64.strict_encode64(\0x0 + salt + subkey) def encode(str) Base64.strict_encode64(str) end def decode(str) Base64.strict_decode64(str) end ITERATIONS = 1000 SUBKEYLENGTH = 256 / 8 # 256 bit aka 32 bytes. SALTLENGTH = 128 / 8 # 128 bit aka 16 bytes. VERSION = decode('AA==') # 0b00000000. # From the .NET helper WebMatrix. def hashPassword(password) raise ArgumentError.new('password') if password.nil? saltBytes = SecureRandom.random_bytes(SALTLENGTH) return _encodePasswordV0(saltBytes, rfc2898DeriveBytes(password, saltBytes, ITERATIONS, SUBKEYLENGTH)) end def verifyHashedPassword(hashedPassword, password) _validateHashedPassword(hashedPassword) raise ArgumentError.new('password') if password.nil? saltBytes = extractSaltBytes(hashedPassword) subkeyBytes = extractSubkeyBytes(hashedPassword) generatedSubkeyBytes = rfc2898DeriveBytes(password, saltBytes, ITERATIONS, SUBKEYLENGTH) return generatedSubkeyBytes == subkeyBytes end # From .NET cryto. def extractSaltBytes(hashedPassword) _validateHashedPassword(hashedPassword) hashedPasswordBytes = decode(hashedPassword) # Pull the salt out. It's the second byte and runs until salt length. return hashedPasswordBytes[1..SALTLENGTH] end def extractSubkeyBytes(hashedPassword) _validateHashedPassword(hashedPassword) hashedPasswordBytes = decode(hashedPassword) # Pull out the subkey. It's at 1+SALTLENGTH until the end (we've already # checked total length). subkeyBytes = hashedPasswordBytes[(1+SALTLENGTH)..-1] end def rfc2898DeriveBytes(password, salt, iterations, subkeyLength) return OpenSSL::PKCS5.pbkdf2_hmac_sha1(password, salt, iterations, subkeyLength) end def _encodePasswordV0(salt, subkey) return encode(VERSION + salt + subkey) end def _validateHashedPassword(hashedPassword) raise ArgumentError.new('hashedPassword') if hashedPassword.nil? hashedPasswordBytes = decode(hashedPassword) raise ArgumentError.new('hash length') unless hashedPasswordBytes.length == (1 + SALTLENGTH + SUBKEYLENGTH) raise ArgumentError.new('hash version') unless hashedPasswordBytes[0] == VERSION end # Test cases to validate the verifyHashedPassword method. def testKnown() for password, hash in [ # From servicing. ['Test@User123', 'AHb24e6gSeTkwxQXBs5fUrUs82vNrIp9adkPwaT3IAWAnt3Il80JG20hU1z22PUzhg=='], ['Test@User123', 'ABvKjwCdZ5+ducW/piXi78Q6e0WsNTPNdbEcfZ52s22yW2XXH8ochASKpuHlc8ktyQ=='], # Top 25 most used passwords in 2014. ['123456', 'AH9EGs/zg3gzLLdKuEe44+ShE07rl7K1uoQ1fXFM1GjdWdz8MamHpQhaeFgaUDzv0A=='], ['password', 'ACHYpKal/KMrWR+b2ucEFmYhCc5K/RfXJPUq0KAXxUjvN76EuxSnH7Cr0wNsnmPTmA=='], ['12345', 'ADIYyvBkHa8lySq31mg0pAsT9sLe429VDDecKSP0dsVs2iR0ZJn5y2jAIaK0d6n5kg=='], ['12345678', 'AO1d73Vwc9T7ELETWKQmZXM9Hvuq1X54dPsIzG67JghRUPGYiWfKiAchJwhu6p8TJA=='], ['qwerty', 'AKOG2irQDjpBop3XaPQBqhCH86PoIGf9HJixEfp8WvepsYCALj1JnPhSICoi4smBiw=='], ['123456789', 'AIFzYbLfY8ucUJf3F4BltNx6YLAHysEM7gO5vuAd+QkV9OO1KjJwRgxCAIxS21oK0A=='], ['1234', 'AHjq0nf1wqG05TRTMTJiBWNYFECfqkndMpvKxyXbsbVXgADdkmN/jLB8yT7+hSV5Dw=='], ['baseball', 'AGvOuBwVMzUTjL0xupvqnv4eRbTioc3uIQcc5z8elsBWnb5crvWrXcZDBzPh5HC5Tw=='], ['dragon', 'AL7Ur4DS9FJLqNHaT5nWIrX5HBRC7IWIG6fYvnvESlcTAIjC1rCxzlZUpOmqOuAo6g=='], ['football', 'AJlA1pBtUFGzEHCqYA8Ns9Fh2zdZzzSwhNCK23S50FDK20YNDnbiDzQIW4xNlB5Jug=='], ['1234567', 'AM1alPNB4IPW2lIVst6bK28KDhWo+2Ezm7R/yC7+dhDhhq2RZ3JZ5oZrLE5974ASWw=='], ['monkey', 'AKn4uYPd63v47cBLll96E8PS1aEm90P3pwlLG+oQs1KFkeDYszdn6K2g0xIiDOOOuw=='], ['letmein', 'AL0Dy8TxuFGa/E4sda2YXv6hJIH+KCwE0WlwcNmiuMDuj7Fec0eEGDgRbFYGklUCYA=='], ['abc123', 'AGYl/6ZefhOGZTQuJ6itnjSOOokRpvfx1lCCXnRTXE/zHYDKwW2mFfhjdRvjnLI5Zg=='], ['111111', 'AGf75M6AboBq6yxzIbk7+26IZzQ3coDKUTVNBqLC3j6KKD2F1IzK8sPAaYSNdTtXDg=='], ['mustang', 'AAcX+qlW53M+USTu+Q5AN899NJTf4AJM/GQ8lQ5jaWVWZjceTJk/F6LUAuxHqWN7pQ=='], ['access', 'AKNT+A6rEp/D0/WFOgZAijZ1ifAs8k+GrWQGNQFUYAyUrt+HzA3ibo3UiVb445CU3g=='], ['shadow', 'AN/cBXaQ86Lksk2EDmr5Iu+MfOZjxwHuhKUPRFM67IuK/EpEuTBfMoBX9MwRVBH71w=='], ['master', 'AJuGySYECMScUY3lU4m2+BdeMNk/Qg1FUlZCyz5U8wYxtZrBgO2Vm0bMoPQGOc1mRA=='], ['michael', 'AEhCExzV1169K6PTGOYYm2z7X0kBs/+D+CqAp4prsgYePHJVfKcugmkMchb0/e9mKg=='], ['superman', 'ABdvz5mu9pqVPibF+Y/xHkyIasMblxk+t6XQQ4vRGiXTAZ4Aue+BINc5U36I2etMoQ=='], ['696969', 'ACq4T2oUestvtjOrMnUkoOSMRAd/d8ZD5BgsDgrldtJGvF/rSJkWrZJtwg08Xs5Q+w=='], ['123123', 'AKJfsCwXdHqfs5O+3FJwnkTP+tKafirFlRcOYWqVDvWQ2oWkUphUiXz5i3nSLhDF5g=='], ['batman', 'AKXTvBN0teL3OksQYtxp7//5bRlT97cgjivBmTYkYb80CUMPtADffdik6REO2935qQ=='], ['trustno1', 'AAzh2KHhb/qln6ZcxPweacXhITuaAWmOYV9+8/xAdGW3XMVWBWtp9iE2Rs4gQPy7mw=='] ] if verifyHashedPassword(hash, password) puts "#{hash} === #{password}" else puts "#{hash} =/= #{password}" end end return nil end