I am rewriting a Django app in Ruby on Rails and want to preserve the old passwords for users.
Django uses PBKDF2SHA1 as the encryption mechanism. So one encrypted password I have is this
pbkdf2_sha256$10000$YsnGfP4rZ1IZ$Tpf4922MoNEjuJQA9EG2Elptyt3dMAyzBPUgmunFOW4=
the original password is 2bulls
In Ruby, I use PBKDF256 gem and base64 for the checking.
Base64.encode64 PBKDF256.dk("2bulls", "YsnGfP4rZ1IZ", 10000, 32)
I am expecting
Tpf4922MoNEjuJQA9EG2Elptyt3dMAyzBPUgmunFOW4=
However, I got
YEfK6oUGFHdaKZMDXC0Dz8TpwsJlKfqC5vjCxjo+ldU=
Any ideas?
UPDATE
Found code in django source if it makes more sense to you.
class PBKDF2PasswordHasher(BasePasswordHasher):
"""
Secure password hashing using the PBKDF2 algorithm (recommended)
Configured to use PBKDF2 + HMAC + SHA256 with 10000 iterations.
The result is a 64 byte binary string. Iterations may be changed
safely but you must rename the algorithm if you change SHA256.
"""
algorithm = "pbkdf2_sha256"
iterations = 10000
digest = hashlib.sha256
def encode(self, password, salt, iterations=None):
assert password
assert salt and '$' not in salt
if not iterations:
iterations = self.iterations
hash = pbkdf2(password, salt, iterations, digest=self.digest)
hash = base64.b64encode(hash).decode('ascii').strip()
return "%s$%d$%s$%s" % (self.algorithm, iterations, salt, hash)
def verify(self, password, encoded):
algorithm, iterations, salt, hash = encoded.split('$', 3)
assert algorithm == self.algorithm
encoded_2 = self.encode(password, salt, int(iterations))
return constant_time_compare(encoded, encoded_2)
def safe_summary(self, encoded):
algorithm, iterations, salt, hash = encoded.split('$', 3)
assert algorithm == self.algorithm
return SortedDict([
(_('algorithm'), algorithm),
(_('iterations'), iterations),
(_('salt'), mask_hash(salt)),
(_('hash'), mask_hash(hash)),
])
CONCLUSION:
It turns out that only the account with 2bulls being the password has this problem. The other accounts are fine. When I know the exact reason for inconsistent password for 2bulls, I will post here.
If you hash that password 2bulls
using the following script (same logic that Django uses to hash passwords) this is what you get (ran this on Django's shell):
>>> import base64, hashlib
>>> hash = pbkdf2("2bulls","YsnGfP4rZ1IZ", 10000, 32, hashlib.sha256)
>>> hash.encode('base64').strip()
'YEfK6oUGFHdaKZMDXC0Dz8TpwsJlKfqC5vjCxjo+ldU='
Notice how I'm using the same parameters that you are using in Ruby:
password = "2bulls"
salt = "YsnGfP4rZ1IZ"
iterations = 10000
dklen = 32
digest = hashlib.sha256
Are you sure your expected hash corresponds to password 2bulls
?
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With