"""passlib.bcrypt -- implementation of OpenBSD's BCrypt algorithm. TODO: * support 2x and altered-2a hashes? http://www.openwall.com/lists/oss-security/2011/06/27/9 * deal with lack of PY3-compatibile c-ext implementation """ #========================================================= #imports #========================================================= from __future__ import with_statement, absolute_import #core import os import re import logging; log = logging.getLogger(__name__) from warnings import warn #site try: from bcrypt import hashpw as pybcrypt_hashpw except ImportError: #pragma: no cover pybcrypt_hashpw = None try: from bcryptor.engine import Engine as bcryptor_engine except ImportError: #pragma: no cover bcryptor_engine = None #libs from passlib.exc import PasslibHashWarning, PasslibSecurityWarning from passlib.utils import bcrypt64, safe_crypt, repeat_string, \ classproperty, rng, getrandstr, test_crypt from passlib.utils.compat import bytes, b, u, uascii_to_str, unicode, str_to_uascii import passlib.utils.handlers as uh #pkg #local __all__ = [ "bcrypt", ] #========================================================= # support funcs & constants #========================================================= _builtin_bcrypt = None def _load_builtin(): global _builtin_bcrypt if _builtin_bcrypt is None: from passlib.utils._blowfish import raw_bcrypt as _builtin_bcrypt IDENT_2 = u("$2$") IDENT_2A = u("$2a$") IDENT_2X = u("$2x$") IDENT_2Y = u("$2y$") _BNULL = b('\x00') #========================================================= # handler #========================================================= class bcrypt(uh.HasManyIdents, uh.HasRounds, uh.HasSalt, uh.HasManyBackends, uh.GenericHandler): """This class implements the BCrypt password hash, and follows the :ref:`password-hash-api`. It supports a fixed-length salt, and a variable number of rounds. The :meth:`~passlib.ifc.PasswordHash.encrypt` and :meth:`~passlib.ifc.PasswordHash.genconfig` methods accept the following optional keywords: :type salt: str :param salt: Optional salt string. If not specified, one will be autogenerated (this is recommended). If specified, it must be 22 characters, drawn from the regexp range ``[./0-9A-Za-z]``. :type rounds: int :param rounds: Optional number of rounds to use. Defaults to 12, must be between 4 and 31, inclusive. This value is logarithmic, the actual number of iterations used will be :samp:`2**{rounds}`. :type ident: str :param ident: selects specific version of BCrypt hash that will be used. Typically you want to leave this alone, and let it default to ``2a``, but it can be set to ``2`` to use the older (and less secure) version of the BCrypt algorithm. .. versionchanged:: 1.6 This class now supports ``2y`` hashes, and recognizes (but does not support) the broken ``2x`` hashes. (see the :ref:`crypt_blowfish bug ` for details). """ #========================================================= #class attrs #========================================================= #--GenericHandler-- name = "bcrypt" setting_kwds = ("salt", "rounds", "ident") checksum_size = 31 checksum_chars = bcrypt64.charmap #--HasManyIdents-- default_ident = u("$2a$") ident_values = (u("$2$"), IDENT_2A, IDENT_2X, IDENT_2Y) ident_aliases = {u("2"): u("$2$"), u("2a"): IDENT_2A, u("2y"): IDENT_2Y} #--HasSalt-- min_salt_size = max_salt_size = 22 salt_chars = bcrypt64.charmap #NOTE: 22nd salt char must be in bcrypt64._padinfo2[1], not full charmap #--HasRounds-- default_rounds = 12 # current passlib default min_rounds = 4 # bcrypt spec specified minimum max_rounds = 31 # 32-bit integer limit (since real_rounds=1<