Secure Password Scheme for Turbogears2 Application with repoze.who and bcrypt

I am working on a little Turbogears2 application, and wanted to use the repoze.who and repoze.what packages that integrate nicely with Turbogears2 and have gathered fair amount of positive feedback. It seems usage is simple, but I was quite disappointed in how password hashes are done by default, especially after I had read Thomas Ptacek’s educational rant about secure password schemes.

It turns out by default the authentication code that gets generated for you if you tell paster quickstart you want authentication is the weak kind of way Thomas warns about. Luckily the correct way he advices is easy to put in by using the py-bcrypt module. If you want pointers, see repoze.who Issue 85, or the py-bcrypt homepage.

Unfortunately py-crypt is kind of annoying to put in dependencies. The pypi entry is named bcrypt, but the download page links to py-bcrypt, so setuptools machinery can not find the right package. This can be worked around relatively easily by adding the py-bcrypt download link to setup.cfg:

[easy_install]
find_links = http://www.pylonshq.com/download/
             http://www.mindrot.org/projects/py-bcrypt/
# ...

and then in setup.py you do something like this:

#...
 
install_requires=[
    "TurboGears2 >= 2.0.3",
    "Catwalk >= 2.0.2",
    "Babel >=0.9.4",
    #can be removed iif use_toscawidgets = False
    "toscawidgets >= 0.9.7.1",
    "zope.sqlalchemy >= 0.4 ",
    "repoze.tm2 >= 1.0a4",
    "repoze.what-quickstart >= 1.0",
]
 
try:
    import bcrypt
except ImportError:
    install_requires.append("py-bcrypt >= 0.1")
 
setup(
    install_requires = install_requires,
 
# ...

Now when you go deploy your TG2 app with easy_install or similar tools, it will download the py-bcrypt package the first time, and won’t bother you if it already exists.

Similar Posts:

    None Found

4 Comments

  1. John Secal:

    bcryptor [1] is a wrapper for bcrypt that provides a high level object oriented wrapper around bcrypt as well as low level bindings to the C library, so it’s very fast.

    And there is not problem to install from PyPi.

    $ sudo easy_install bcryptor

    [1] http://pypi.python.org/pypi/bcryptor/

  2. Daniel Holth:

    I wrote Cryptacular (http://pypi.python.org/pypi/cryptacular) after reading that rant. It uses ctypes to talk to a public-domain bcrypt implementation instead of the BSD-licensed implementation.

    It’s designed for people who may need to deal with many different hashing schemes with optional hash migration when a user authenticates against a legacy hash. You can start using good hashes in your application without having to delete all your old password hashes; they will simply be replaced as users log in.

  3. Heikki Toivonen:

    Thanks John and Daniel. I’ll definitely be checking out bcryptor and cryptacular.

  4. Aigars Mahinovs:

    Heh, I implemented a random-salted SHA256 password extension to the TG2.0 default scheme in like 4 lines added to the default code and with 2 more lines allowed usage of legacy MD5 random-salted passwords that most of our users still have in the database.

    I think the new default code in TG2.1 should accept any of the old hash types that TG ever supported (and some other legacy types, like AD-hash or Linux crypt()) and have an option (turned-off by default, but prominent) that would replace the hash with the most secure type on next login of a user.