Sunday, 25 September 2011

How to protect passwords with Python and Scrypt


First, install py-scrypt, you need mercurial client for this method:

$ hg clone http://bitbucket.org/mhallin/py-scrypt
$ cd py-scrypt
$ python setup.py build
$ sudo python setup.py install    ### root user

Alternative method, download the tarball from py-scrypt project page downloads. Then extract and run the build and install steps above. An example showing how to use the module:

import random, scrypt

def randstr(length):
    return ''.join(chr(random.randint(0,255)) for i in range(length))

def hash_password(password, maxtime=0.5, datalength=64):
    return scrypt.encrypt(randstr(datalength), password, maxtime=maxtime)

def verify_password(hashed_password, guessed_password, maxtime=0.5):
    try:
        scrypt.decrypt(hashed_password, guessed_password, maxtime)
        return True
    except scrypt.error:
        return False

if __name__ == '__main__':
    user_pw = 'theansweris42'
    user_salt = randstr(2)             # 2+ bytes unique, save it too
    pw_salt = user_pw + user_salt
    hashed_pw = hash_password(pw_salt) # To be stored len()==192
    print verify_password(hashed_pw, pw_salt)              # True
    print verify_password(hashed_pw, 'guessing'+ pw_salt)  # False

The default settings will use about 0.5s to generate each password. Migrating a large password database could take hours. The same random string could be used for all passwords but the speed improvement would be negligible.

The length of the random string could be shorter, making the password entry only 130 bytes long. But perhaps this could affect the security of the model.

More information:

The Scrypt Derivation function
Enough With The Rainbow Tables: What You Need To Know About Secure Password Schemes.

Edit: made the code a bit more clear and added last paragraph.

0 comments:

 
Creative Commons License
This work is licensed under a Creative Commons Attribution-Noncommercial-Share Alike 3.0 United States License.