Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Verifying Django Password in Ruby on Rails gives non-matching password

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.

like image 634
benzhang Avatar asked Mar 28 '13 17:03

benzhang


1 Answers

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?

like image 194
Dan Aronne Avatar answered Oct 20 '22 08:10

Dan Aronne