# Path: webtools/utils/encoding.py
# def smart_bytes(value, encoding='utf-8', errors='strict'):
#     if isinstance(value, bytes):
#         if encoding == 'utf-8':
#             return value
# 
#         return value.decode('utf-8', errors).encode(encoding, errors)
# 
#     if not isinstance(value, str):
#         value = str(value)
# 
#     return value.encode(encoding, errors)
# 
# Path: webtools/utils/crypto.py
# def pbkdf2(password, salt, iterations, dklen=0, digest=None):
#     """
#     Implements PBKDF2 as defined in RFC 2898, section 5.2
# 
#     HMAC+SHA256 is used as the default pseudo random function.
# 
#     Right now 10,000 iterations is the recommended default which takes
#     100ms on a 2.2Ghz Core 2 Duo.  This is probably the bare minimum
#     for security given 1000 iterations was recommended in 2001. This
#     code is very well optimized for CPython and is only four times
#     slower than openssl's implementation.
#     """
#     assert iterations > 0
#     if not digest:
#         digest = hashlib.sha256
#     password = smart_bytes(password)
#     salt = smart_bytes(salt)
#     hlen = digest().digest_size
#     if not dklen:
#         dklen = hlen
#     if dklen > (2 ** 32 - 1) * hlen:
#         raise OverflowError('dklen too big')
#     l = -(-dklen // hlen)
#     r = dklen - (l - 1) * hlen
# 
#     hex_format_string = "%%0%ix" % (hlen * 2)
# 
#     def F(i):
#         def U():
#             u = salt + struct.pack(b'>I', i)
#             for j in range(int(iterations)):
#                 u = _fast_hmac(password, u, digest).digest()
#                 yield _bin_to_long(u)
#         return _long_to_bin(reduce(operator.xor, U()), hex_format_string)
# 
#     T = [F(x) for x in range(1, l + 1)]
#     return b''.join(T[:-1]) + T[-1][:r]
# 
# def constant_time_compare(val1, val2):
#     """
#     Returns True if the two strings are equal, False otherwise.
# 
#     The time taken is independent of the number of characters that match.
#     """
#     if len(val1) != len(val2):
#         return False
#     result = 0
#     for x, y in zip(val1, val2):
#         result |= ord(x) ^ ord(y)
#     return result == 0
# 
# def get_random_string(length=12,
#                       allowed_chars='abcdefghijklmnopqrstuvwxyz'
#                                     'ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789'):
#     """
#     Returns a securely generated random string.
# 
#     The default length of 12 with the a-z, A-Z, 0-9 character set returns
#     a 71-bit value. log_2((26+26+10)^12) =~ 71 bits
#     """
#     if not using_sysrandom:
#         # This is ugly, and a hack, but it makes things better than
#         # the alternative of predictability. This re-seeds the PRNG
#         # using a value that is hard for an attacker to predict, every
#         # time a random string is required. This may change the
#         # properties of the chosen random sequence slightly, but this
#         # is better than absolute predictability.
#         random.seed(
#             hashlib.sha256(
#                 "%s%s%s" % (
#                     random.getstate(),
#                     time.time(),
#                     settings.SECRET_KEY)
#                 ).digest())
#     return ''.join([random.choice(allowed_chars) for i in range(length)])


from webtools.utils.encoding import smart_bytes
from webtools.utils.crypto import pbkdf2, constant_time_compare, get_random_string
    from webtools.application import get_app
import base64
import hashlib
import importlib
    algorithm = "pbkdf2_sha1"
    digest = hashlib.sha1


class BCryptPasswordHasher(BasePasswordHasher):
    """
    Secure password hashing using the bcrypt algorithm (recommended)

    This is considered by many to be the most secure algorithm but you
    must first install the py-bcrypt library.  Please be warned that
    this library depends on native C code and might cause portability
    issues.
    """
    algorithm = "bcrypt"
    library = ("py-bcrypt", "bcrypt")
    rounds = 12

    def salt(self):
        bcrypt = self._load_library()
        return bcrypt.gensalt(self.rounds)

    def encode(self, password, salt):
        bcrypt = self._load_library()
        data = bcrypt.hashpw(password, salt)
        return "%s$%s" % (self.algorithm, data)

    def verify(self, password, encoded):
        algorithm, data = encoded.split('$', 1)
        assert algorithm == self.algorithm
        bcrypt = self._load_library()

# Path: webtools/utils/encoding.py
# def smart_bytes(value, encoding='utf-8', errors='strict'):
#     if isinstance(value, bytes):
#         if encoding == 'utf-8':
#             return value
# 
#         return value.decode('utf-8', errors).encode(encoding, errors)
# 
#     if not isinstance(value, str):
#         value = str(value)
# 
#     return value.encode(encoding, errors)
# 
# Path: webtools/utils/crypto.py
# def pbkdf2(password, salt, iterations, dklen=0, digest=None):
#     """
#     Implements PBKDF2 as defined in RFC 2898, section 5.2
# 
#     HMAC+SHA256 is used as the default pseudo random function.
# 
#     Right now 10,000 iterations is the recommended default which takes
#     100ms on a 2.2Ghz Core 2 Duo.  This is probably the bare minimum
#     for security given 1000 iterations was recommended in 2001. This
#     code is very well optimized for CPython and is only four times
#     slower than openssl's implementation.
#     """
#     assert iterations > 0
#     if not digest:
#         digest = hashlib.sha256
#     password = smart_bytes(password)
#     salt = smart_bytes(salt)
#     hlen = digest().digest_size
#     if not dklen:
#         dklen = hlen
#     if dklen > (2 ** 32 - 1) * hlen:
#         raise OverflowError('dklen too big')
#     l = -(-dklen // hlen)
#     r = dklen - (l - 1) * hlen
# 
#     hex_format_string = "%%0%ix" % (hlen * 2)
# 
#     def F(i):
#         def U():
#             u = salt + struct.pack(b'>I', i)
#             for j in range(int(iterations)):
#                 u = _fast_hmac(password, u, digest).digest()
#                 yield _bin_to_long(u)
#         return _long_to_bin(reduce(operator.xor, U()), hex_format_string)
# 
#     T = [F(x) for x in range(1, l + 1)]
#     return b''.join(T[:-1]) + T[-1][:r]
# 
# def constant_time_compare(val1, val2):
#     """
#     Returns True if the two strings are equal, False otherwise.
# 
#     The time taken is independent of the number of characters that match.
#     """
#     if len(val1) != len(val2):
#         return False
#     result = 0
#     for x, y in zip(val1, val2):
#         result |= ord(x) ^ ord(y)
#     return result == 0
# 
# def get_random_string(length=12,
#                       allowed_chars='abcdefghijklmnopqrstuvwxyz'
#                                     'ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789'):
#     """
#     Returns a securely generated random string.
# 
#     The default length of 12 with the a-z, A-Z, 0-9 character set returns
#     a 71-bit value. log_2((26+26+10)^12) =~ 71 bits
#     """
#     if not using_sysrandom:
#         # This is ugly, and a hack, but it makes things better than
#         # the alternative of predictability. This re-seeds the PRNG
#         # using a value that is hard for an attacker to predict, every
#         # time a random string is required. This may change the
#         # properties of the chosen random sequence slightly, but this
#         # is better than absolute predictability.
#         random.seed(
#             hashlib.sha256(
#                 "%s%s%s" % (
#                     random.getstate(),
#                     time.time(),
#                     settings.SECRET_KEY)
#                 ).digest())
#     return ''.join([random.choice(allowed_chars) for i in range(length)])


# Path: webtools/auth/hashers.py
from webtools.utils.encoding import smart_bytes
from webtools.utils.crypto import pbkdf2, constant_time_compare, get_random_string
    from webtools.application import get_app
import base64
import hashlib
import importlib

    algorithm = "pbkdf2_sha1"
    digest = hashlib.sha1


class BCryptPasswordHasher(BasePasswordHasher):
    """
    Secure password hashing using the bcrypt algorithm (recommended)

    This is considered by many to be the most secure algorithm but you
    must first install the py-bcrypt library.  Please be warned that
    this library depends on native C code and might cause portability
    issues.
    """
    algorithm = "bcrypt"
    library = ("py-bcrypt", "bcrypt")
    rounds = 12

    def salt(self):
        bcrypt = self._load_library()
        return bcrypt.gensalt(self.rounds)

    def encode(self, password, salt):
        bcrypt = self._load_library()
        data = bcrypt.hashpw(password, salt)
        return "%s$%s" % (self.algorithm, data)

    def verify(self, password, encoded):
        algorithm, data = encoded.split('$', 1)
        assert algorithm == self.algorithm
        bcrypt = self._load_library()

        return constant_time_compare(data, bcrypt.hashpw(password, data))