What do you use for hashing passwords?

453 views
Skip to first unread message

Iuri Machado

unread,
Nov 10, 2014, 5:08:19 PM11/10/14
to python-...@googlegroups.com
Hello people, what libraries are you using for hashing passwords? I've seen some posts about threading + bcrypt here and around the internet but I can't find my way out. Is there a way to use it together with the decorator @tornado.gen.coroutine?

Thanks in advance,

I.

aliane abdelouahab

unread,
Nov 10, 2014, 5:23:35 PM11/10/14
to python-...@googlegroups.com
Hi,
the asynchronous nature of tornado is with the sockets I/O, and not with the cpu (hashing  or image processing) so if you are spending the time to hash, then you have to use another process.

Ben Darnell

unread,
Nov 10, 2014, 11:13:17 PM11/10/14
to Tornado Mailing List
You can use any password-hashing library[1] with a concurrent.futures.ThreadPoolExecutor to avoid blocking.

Here's an example with py-bcrypt:

  from concurrent.futures import ThreadPoolExecutor
  from tornado import gen
  from tornado.process import cpu_count
  import bcrypt

  # global threadpool
  pool = ThreadPoolExecutor(cpu_count())

  @gen.coroutine
  def create_user(name, password):
    hashed_pw = yield pool.submit(bcrypt.hashpw, password, bcrypt.gensalt()
    yield save_user(name, hashed_pw)

  @gen.coroutine
  def login(name, password):
    user = yield load_user(name)
    match = yield pool.submit(bcrypt.checkpw, password, user.hashed_pw)
    if not match:
      raise IncorrectPasswordError()
  
[1] As long as it releases the GIL while working, which I believe is true of most password-hashing libraries.

-Ben


--
You received this message because you are subscribed to the Google Groups "Tornado Web Server" group.
To unsubscribe from this group and stop receiving emails from it, send an email to python-tornad...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Lists Kamikaze

unread,
Nov 10, 2014, 11:42:04 PM11/10/14
to python-...@googlegroups.com
Hi,
Here I share an example using the `werkzeug` framework, more precisely the methods `werkzeug.security.check_password_hash` and `werkzeug.security.generate_password_hash`.
I hope you enjoy it. 
A!~



from concurrent.futures import ThreadPoolExecutor
from functools import wraps
from werkzeug.security import check_password_hash, generate_password_hash

__all__ = (
    'SHA1Password',
    'SHA256Password',
    'SHA512Password',
    'MD5Password',
    'PlainPassword',
    'PasswordThreadPoolExecutor'
)

MAXIMUM_PASSWORD_LENGTH = 64
MINIMUM_PASSWORD_LENGTH = 8


def validate_password(length):
    def decorator(func):
        @wraps(func)
        def wrapper(self, password, *args, **kwargs):
            password_len = len(password)
            if password_len < length or password_len > MAXIMUM_PASSWORD_LENGTH:
                raise ValueError(
                    'The "password" must be greater than or equal to %s '
                    'or less than or equal to %s'
                    % (length, MAXIMUM_PASSWORD_LENGTH)
                )
            return func(self, password, *args, **kwargs)
        return wrapper
    return decorator


class _PasswordHasher(object):
    _algorithm = None

    @validate_password(MINIMUM_PASSWORD_LENGTH)
    def make(self, password, salt_length=8):
        return generate_password_hash(password, self._algorithm, salt_length)

    @validate_password(MINIMUM_PASSWORD_LENGTH)
    def verify(self, password, password_hash):
        return check_password_hash(password_hash, password)


class SHA1Password(_PasswordHasher):
    _algorithm = 'pbkdf2:sha1'


class SHA256Password(_PasswordHasher):
    _algorithm = 'pbkdf2:sha256'


class SHA512Password(_PasswordHasher):
    _algorithm = 'pbkdf2:sha512'


class MD5Password(_PasswordHasher):
    _algorithm = 'pbkdf2:md5'


class PlainPassword(_PasswordHasher):
    _algorithm = 'plain'


class PasswordThreadPoolExecutor(ThreadPoolExecutor):
    def _get_client(self, algorithm='sha256'):
        client = {
            'sha1': SHA1Password,
            'sha256': SHA256Password,
            'sha512': SHA512Password,
            'md5': MD5Password,
            'plain': PlainPassword
        }[algorithm.lower()]
        return client()

    def make(self, password, salt_length=8, algorithm='sha256'):
        client = self._get_client(algorithm)
        return self.submit(client.make, password, salt_length)

    def verify(self, password, password_hash, algorithm='sha256'):
        client = self._get_client(algorithm)
        return self.submit(client.verify, password, password_hash)


Jordan Bettis

unread,
Nov 10, 2014, 11:57:59 PM11/10/14
to python-...@googlegroups.com

If you're using python 2.7.8 or later you don't need any external libraries anymore, the standard lib now supports password hashing:

import os, hashlib, base64

def hash_password(password):
    salt = os.urandom(16)
    alg, rounds = "sha256", 100000  
    pw_hash = hashlib.pbkdf2_hmac(alg, password, salt, rounds)
    return "{}:{}:{}:{}".format(alg, repr(rounds), base64.b16encode(salt), base64.b16encode(pw_hash))

def check_password(password, pw_hash):
    alg, rounds, salt, ohash = pw_hash.split(":")
    rounds = int(rounds)
    salt, ohash = base64.b16decode(salt), base64.b16decode(ohash)
    check_hash = hashlib.pbkdf2_hmac(alg, password, salt, rounds)
    return check_hash == ohash

shh = hash_password("toomanysecrets")

print check_password("myvoiceismypassport", shh)
print check_password("toomanysecrets", shh)

aliane abdelouahab

unread,
Nov 11, 2014, 9:39:39 AM11/11/14
to python-...@googlegroups.com, b...@bendarnell.com
Ben gave you an excellent example!
and i just want to add that the best library i tested, is Passlib.

Iuri Machado

unread,
Nov 11, 2014, 7:59:31 PM11/11/14
to python-...@googlegroups.com
Thanks people, I'm really enjoying using Tornado with this new project I'm working in. You have been sooo helpful! :-) 
Reply all
Reply to author
Forward
0 new messages