summaryrefslogtreecommitdiff
path: root/passlib/handlers/django.py
diff options
context:
space:
mode:
Diffstat (limited to 'passlib/handlers/django.py')
-rw-r--r--passlib/handlers/django.py72
1 files changed, 70 insertions, 2 deletions
diff --git a/passlib/handlers/django.py b/passlib/handlers/django.py
index b643a66..83e8860 100644
--- a/passlib/handlers/django.py
+++ b/passlib/handlers/django.py
@@ -4,12 +4,14 @@
#=============================================================================
# core
from base64 import b64encode
-from hashlib import md5, sha1
+from binascii import hexlify
+from hashlib import md5, sha1, sha256
import re
import logging; log = logging.getLogger(__name__)
from warnings import warn
# site
# pkg
+from passlib.hash import bcrypt
from passlib.utils import to_unicode, classproperty
from passlib.utils.compat import b, bytes, str_to_uascii, uascii_to_str, unicode, u
from passlib.utils.pbkdf2 import pbkdf2
@@ -28,6 +30,8 @@ __all__ = [
#=============================================================================
# lazy imports & constants
#=============================================================================
+
+# imported by django_des_crypt._calc_checksum()
des_crypt = None
def _import_des_crypt():
@@ -162,7 +166,7 @@ class django_salted_md5(DjangoSaltedHash):
secret = secret.encode("utf-8")
return str_to_uascii(md5(self.salt.encode("ascii") + secret).hexdigest())
-django_bcrypt = uh.PrefixWrapper("django_bcrypt", "bcrypt",
+django_bcrypt = uh.PrefixWrapper("django_bcrypt", bcrypt,
prefix=u('bcrypt$'), ident=u("bcrypt$"),
# NOTE: this docstring is duplicated in the docs, since sphinx
# seems to be having trouble reading it via autodata::
@@ -181,6 +185,70 @@ django_bcrypt = uh.PrefixWrapper("django_bcrypt", "bcrypt",
""")
django_bcrypt.django_name = "bcrypt"
+class django_bcrypt_sha256(bcrypt):
+ """This class implements Django 1.6's Bcrypt+SHA256 hash, and follows the :ref:`password-hash-api`.
+
+ It supports a variable-length salt, and a variable number of rounds.
+
+ While the algorithm and format is somewhat different,
+ the api and options for this hash are identical to :class:`!bcrypt` itself,
+ see :doc:`/lib/passlib.hash.bcrypt` for more details.
+
+ .. versionadded:: 1.6.2
+ """
+ name = "django_bcrypt_sha256"
+ django_name = "bcrypt_sha256"
+ _digest = sha256
+
+ # NOTE: django bcrypt ident locked at "$2a$", so omitting 'ident' support.
+ setting_kwds = ("salt", "rounds")
+
+ # sample hash:
+ # bcrypt_sha256$$2a$06$/3OeRpbOf8/l6nPPRdZPp.nRiyYqPobEZGdNRBWihQhiFDh1ws1tu
+
+ # XXX: we can't use .ident attr due to bcrypt code using it.
+ # working around that via django_prefix
+ django_prefix = u('bcrypt_sha256$')
+
+ @classmethod
+ def identify(cls, hash):
+ hash = uh.to_unicode_for_identify(hash)
+ if not hash:
+ return False
+ return hash.startswith(cls.django_prefix)
+
+ @classmethod
+ def from_string(cls, hash):
+ hash = to_unicode(hash, "ascii", "hash")
+ if not hash.startswith(cls.django_prefix):
+ raise uh.exc.InvalidHashError(cls)
+ bhash = hash[len(cls.django_prefix):]
+ if not bhash.startswith("$2"):
+ raise uh.exc.MalformedHashError(cls)
+ return super(django_bcrypt_sha256, cls).from_string(bhash)
+
+ def __init__(self, **kwds):
+ if 'ident' in kwds and kwds.get("use_defaults"):
+ raise TypeError("%s does not support the ident keyword" %
+ self.__class__.__name__)
+ return super(django_bcrypt_sha256, self).__init__(**kwds)
+
+ def to_string(self):
+ bhash = super(django_bcrypt_sha256, self).to_string()
+ return uascii_to_str(self.django_prefix) + bhash
+
+ def _calc_checksum(self, secret):
+ if isinstance(secret, unicode):
+ secret = secret.encode("utf-8")
+ secret = hexlify(self._digest(secret).digest())
+ return super(django_bcrypt_sha256, self)._calc_checksum(secret)
+
+ # patch set_backend so it modifies bcrypt class, not this one...
+ # else it would clobber our _calc_checksum() wrapper above.
+ @classmethod
+ def set_backend(cls, *args, **kwds):
+ return bcrypt.set_backend(*args, **kwds)
+
class django_pbkdf2_sha256(DjangoVariableHash):
"""This class implements Django's PBKDF2-HMAC-SHA256 hash, and follows the :ref:`password-hash-api`.