Ejemplo n.º 1
1
def reset():
    status = Status()
    form = Form(request.forms)
    token = request.query.token
    s = URLSafeTimedSerializer(secret_key, max_age=3600, salt=salt)
    try:
        username = s.loads(token)
    except:
        return abort(500, 'bad signature')
    else:
        if request.method == 'POST' and form.validate():
            new_pbkdf2 = to_bytes(pbkdf2_sha256.encrypt(form.password.data))
            try:
                conn = db.engine.connect()
                conn.execute(users.update().values(
                    pbkdf2=new_pbkdf2).where(users.c.id == username))
                conn.close()
            except exc.SQLAlchemyError as message:
                status.danger = message
            else:
                status.success = 'Password Changed. Please log in.'
                return render_template('/status.html',
                                       status=status)
    return render_template('/action/reset.html',
                           status=status,
                           form=form,
                           username=username,
                           token=token)
Ejemplo n.º 2
0
 def genhash(cls, secret, config):
     # TODO: add in 'encoding' support once that's finalized in 1.8 / 1.9.
     uh.validate_secret(secret)
     secret = to_bytes(secret, "utf-8")
     self = cls.from_string(config)
     if self.type_d:
         type = _argon2_cffi.low_level.Type.D
     else:
         type = _argon2_cffi.low_level.Type.I
     # XXX: doesn't seem to be a way to make this honor max_threads
     try:
         result = bascii_to_str(_argon2_cffi.low_level.hash_secret(
             type=type,
             memory_cost=self.memory_cost,
             time_cost=self.rounds,
             parallelism=self.parallelism,
             salt=to_bytes(self.salt),
             hash_len=self.checksum_size,
             secret=secret,
             version=self.version,
         ))
     except _argon2_cffi.exceptions.HashingError as err:
         raise cls._adapt_backend_error(err, hash=config)
     if self.version == 0x10:
         # workaround: argon2 0x13 always returns "v=" segment, even for 0x10 hashes
         result = result.replace("$v=16$", "$")
     return result
Ejemplo n.º 3
0
 def genhash(cls, secret, config):
     # TODO: add in 'encoding' support once that's finalized in 1.8 / 1.9.
     uh.validate_secret(secret)
     secret = to_bytes(secret, "utf-8")
     self = cls.from_string(config)
     if self.type_d:
         type = _argon2_cffi.low_level.Type.D
     else:
         type = _argon2_cffi.low_level.Type.I
     # XXX: doesn't seem to be a way to make this honor max_threads
     try:
         result = bascii_to_str(
             _argon2_cffi.low_level.hash_secret(
                 type=type,
                 memory_cost=self.memory_cost,
                 time_cost=self.rounds,
                 parallelism=self.parallelism,
                 salt=to_bytes(self.salt),
                 hash_len=self.checksum_size,
                 secret=secret,
                 version=self.version,
             ))
     except _argon2_cffi.exceptions.HashingError as err:
         raise cls._adapt_backend_error(err, hash=config)
     if self.version == 0x10:
         # workaround: argon2 0x13 always returns "v=" segment, even for 0x10 hashes
         result = result.replace("$v=16$", "$")
     return result
Ejemplo n.º 4
0
def pbkdf1(digest, secret, salt, rounds, keylen=None):
    """pkcs#5 password-based key derivation v1.5

    :arg digest:
        digest name or constructor.
        
    :arg secret:
        secret to use when generating the key.
        may be :class:`!bytes` or :class:`unicode` (encoded using UTF-8).
        
    :arg salt:
        salt string to use when generating key.
        may be :class:`!bytes` or :class:`unicode` (encoded using UTF-8).

    :param rounds:
        number of rounds to use to generate key.

    :arg keylen:
        number of bytes to generate (if omitted / ``None``, uses digest's native size)

    :returns:
        raw :class:`bytes` of generated key

    .. note::

        This algorithm has been deprecated, new code should use PBKDF2.
        Among other limitations, ``keylen`` cannot be larger
        than the digest size of the specified hash.
    """
    # resolve digest
    const, digest_size, block_size = lookup_hash(digest)

    # validate secret & salt
    secret = to_bytes(secret, param="secret")
    salt = to_bytes(salt, param="salt")

    # validate rounds
    if not isinstance(rounds, int_types):
        raise exc.ExpectedTypeError(rounds, "int", "rounds")
    if rounds < 1:
        raise ValueError("rounds must be at least 1")

    # validate keylen
    if keylen is None:
        keylen = digest_size
    elif not isinstance(keylen, int_types):
        raise exc.ExpectedTypeError(keylen, "int or None", "keylen")
    elif keylen < 0:
        raise ValueError("keylen must be at least 0")
    elif keylen > digest_size:
        raise ValueError("keylength too large for digest: %r > %r" %
                         (keylen, digest_size))

    # main pbkdf1 loop
    block = secret + salt
    for _ in irange(rounds):
        block = const(block).digest()
    return block[:keylen]
Ejemplo n.º 5
0
def pbkdf1(digest, secret, salt, rounds, keylen=None):
    """pkcs#5 password-based key derivation v1.5

    :arg digest:
        digest name or constructor.
        
    :arg secret:
        secret to use when generating the key.
        may be :class:`!bytes` or :class:`unicode` (encoded using UTF-8).
        
    :arg salt:
        salt string to use when generating key.
        may be :class:`!bytes` or :class:`unicode` (encoded using UTF-8).

    :param rounds:
        number of rounds to use to generate key.

    :arg keylen:
        number of bytes to generate (if omitted / ``None``, uses digest's native size)

    :returns:
        raw :class:`bytes` of generated key

    .. note::

        This algorithm has been deprecated, new code should use PBKDF2.
        Among other limitations, ``keylen`` cannot be larger
        than the digest size of the specified hash.
    """
    # resolve digest
    const, digest_size, block_size = lookup_hash(digest)
    
    # validate secret & salt
    secret = to_bytes(secret, param="secret")
    salt = to_bytes(salt, param="salt")

    # validate rounds
    if not isinstance(rounds, int_types):
        raise exc.ExpectedTypeError(rounds, "int", "rounds")
    if rounds < 1:
        raise ValueError("rounds must be at least 1")

    # validate keylen
    if keylen is None:
        keylen = digest_size
    elif not isinstance(keylen, int_types):
        raise exc.ExpectedTypeError(keylen, "int or None", "keylen")
    elif keylen < 0:
        raise ValueError("keylen must be at least 0")
    elif keylen > digest_size:
        raise ValueError("keylength too large for digest: %r > %r" %
                         (keylen, digest_size))

    # main pbkdf1 loop
    block = secret + salt
    for _ in irange(rounds):
        block = const(block).digest()
    return block[:keylen]
Ejemplo n.º 6
0
    def test_to_bytes(self):
        "test to_bytes()"

        #check unicode inputs
        self.assertEqual(to_bytes(u'abc'), b('abc'))
        self.assertEqual(to_bytes(u'\x00\xff'), b('\x00\xc3\xbf'))

        #check unicode w/ encodings
        self.assertEqual(to_bytes(u'\x00\xff', 'latin-1'), b('\x00\xff'))
        self.assertRaises(ValueError, to_bytes, u'\x00\xff', 'ascii')
        self.assertRaises(TypeError, to_bytes, u'abc', None)

        #check bytes inputs
        self.assertEqual(to_bytes(b('abc')), b('abc'))
        self.assertEqual(to_bytes(b('\x00\xff')), b('\x00\xff'))
        self.assertEqual(to_bytes(b('\x00\xc3\xbf')), b('\x00\xc3\xbf'))

        #check byte inputs ignores enocding
        self.assertEqual(to_bytes(b('\x00\xc3\xbf'), "latin-1"),
                         b('\x00\xc3\xbf'))
        self.assertEqual(to_bytes(b('\x00\xc3\xbf'), None, "utf-8"),
                         b('\x00\xc3\xbf'))

        #check bytes transcoding
        self.assertEqual(to_bytes(b('\x00\xc3\xbf'), "latin-1", "utf-8"),
                         b('\x00\xff'))

        #check other
        self.assertRaises(TypeError, to_bytes, None)
Ejemplo n.º 7
0
    def test_to_bytes(self):
        "test to_bytes()"

        #check unicode inputs
        self.assertEqual(to_bytes(u'abc'),                  b('abc'))
        self.assertEqual(to_bytes(u'\x00\xff'),             b('\x00\xc3\xbf'))

        #check unicode w/ encodings
        self.assertEqual(to_bytes(u'\x00\xff', 'latin-1'),  b('\x00\xff'))
        self.assertRaises(ValueError, to_bytes, u'\x00\xff', 'ascii')
        self.assertRaises(TypeError, to_bytes, u'abc',      None)

        #check bytes inputs
        self.assertEqual(to_bytes(b('abc')),                b('abc'))
        self.assertEqual(to_bytes(b('\x00\xff')),           b('\x00\xff'))
        self.assertEqual(to_bytes(b('\x00\xc3\xbf')),       b('\x00\xc3\xbf'))

        #check byte inputs ignores enocding
        self.assertEqual(to_bytes(b('\x00\xc3\xbf'), "latin-1"),
                                                            b('\x00\xc3\xbf'))
        self.assertEqual(to_bytes(b('\x00\xc3\xbf'), None, "utf-8"),
                                                            b('\x00\xc3\xbf'))

        #check bytes transcoding
        self.assertEqual(to_bytes(b('\x00\xc3\xbf'), "latin-1", "utf-8"),
                                                            b('\x00\xff'))

        #check other
        self.assertRaises(TypeError, to_bytes, None)
Ejemplo n.º 8
0
 def encrypt(cls, secret, user, realm, encoding=None):
     # NOTE: this was deliberately written so that raw bytes are passed through
     # unchanged, the encoding kwd is only used to handle unicode values.
     if not encoding:
         encoding = cls.default_encoding
     uh.validate_secret(secret)
     if isinstance(secret, unicode):
         secret = secret.encode(encoding)
     user = to_bytes(user, encoding, "user")
     realm = to_bytes(realm, encoding, "realm")
     data = render_bytes("%s:%s:%s", user, realm, secret)
     return hashlib.md5(data).hexdigest()
Ejemplo n.º 9
0
 def hash(cls, secret, user, realm, encoding=None):
     # NOTE: this was deliberately written so that raw bytes are passed through
     # unchanged, the encoding kwd is only used to handle unicode values.
     if not encoding:
         encoding = cls.default_encoding
     uh.validate_secret(secret)
     if isinstance(secret, unicode):
         secret = secret.encode(encoding)
     user = to_bytes(user, encoding, "user")
     realm = to_bytes(realm, encoding, "realm")
     data = render_bytes("%s:%s:%s", user, realm, secret)
     return hashlib.md5(data).hexdigest()
Ejemplo n.º 10
0
 def get_fuzz_settings(self):
     secret, other, kwds = super(_bcrypt_test,self).get_fuzz_settings()
     from passlib.handlers.bcrypt import IDENT_2, IDENT_2X
     from passlib.utils import to_bytes
     ident = kwds.get('ident')
     if ident == IDENT_2X:
         # 2x is just recognized, not supported. don't test with it.
         del kwds['ident']
     elif ident == IDENT_2 and other and repeat_string(to_bytes(other), len(to_bytes(secret))) == to_bytes(secret):
         # avoid false failure due to flaw in 0-revision bcrypt:
         # repeated strings like 'abc' and 'abcabc' hash identically.
         other = self.get_fuzz_password()
     return secret, other, kwds
Ejemplo n.º 11
0
 def get_fuzz_settings(self):
     secret, other, kwds = super(_bcrypt_test, self).get_fuzz_settings()
     from passlib.handlers.bcrypt import IDENT_2, IDENT_2X
     from passlib.utils import to_bytes
     ident = kwds.get('ident')
     if ident == IDENT_2X:
         # 2x is just recognized, not supported. don't test with it.
         del kwds['ident']
     elif ident == IDENT_2 and other and repeat_string(
             to_bytes(other), len(to_bytes(secret))) == to_bytes(secret):
         # avoid false failure due to flaw in 0-revision bcrypt:
         # repeated strings like 'abc' and 'abcabc' hash identically.
         other = self.get_fuzz_password()
     return secret, other, kwds
Ejemplo n.º 12
0
    def test_to_bytes(self):
        "test to_bytes()"
        from passlib.utils import to_bytes

        # check unicode inputs
        self.assertEqual(to_bytes(u('abc')), b('abc'))
        self.assertEqual(to_bytes(u('\x00\xff')), b('\x00\xc3\xbf'))

        # check unicode w/ encodings
        self.assertEqual(to_bytes(u('\x00\xff'), 'latin-1'), b('\x00\xff'))
        self.assertRaises(ValueError, to_bytes, u('\x00\xff'), 'ascii')

        # check bytes inputs
        self.assertEqual(to_bytes(b('abc')), b('abc'))
        self.assertEqual(to_bytes(b('\x00\xff')), b('\x00\xff'))
        self.assertEqual(to_bytes(b('\x00\xc3\xbf')), b('\x00\xc3\xbf'))

        # check byte inputs ignores enocding
        self.assertEqual(to_bytes(b('\x00\xc3\xbf'), "latin-1"),
                         b('\x00\xc3\xbf'))

        # check bytes transcoding
        self.assertEqual(to_bytes(b('\x00\xc3\xbf'), "latin-1", "", "utf-8"),
                         b('\x00\xff'))

        # check other
        self.assertRaises(AssertionError, to_bytes, 'abc', None)
        self.assertRaises(TypeError, to_bytes, None)
Ejemplo n.º 13
0
    def test_to_bytes(self):
        "test to_bytes()"
        from passlib.utils import to_bytes

        # check unicode inputs
        self.assertEqual(to_bytes(u('abc')),                  b('abc'))
        self.assertEqual(to_bytes(u('\x00\xff')),             b('\x00\xc3\xbf'))

        # check unicode w/ encodings
        self.assertEqual(to_bytes(u('\x00\xff'), 'latin-1'),  b('\x00\xff'))
        self.assertRaises(ValueError, to_bytes, u('\x00\xff'), 'ascii')

        # check bytes inputs
        self.assertEqual(to_bytes(b('abc')),                b('abc'))
        self.assertEqual(to_bytes(b('\x00\xff')),           b('\x00\xff'))
        self.assertEqual(to_bytes(b('\x00\xc3\xbf')),       b('\x00\xc3\xbf'))

        # check byte inputs ignores enocding
        self.assertEqual(to_bytes(b('\x00\xc3\xbf'), "latin-1"),
                                                            b('\x00\xc3\xbf'))

        # check bytes transcoding
        self.assertEqual(to_bytes(b('\x00\xc3\xbf'), "latin-1", "", "utf-8"),
                                                            b('\x00\xff'))

        # check other
        self.assertRaises(AssertionError, to_bytes, 'abc', None)
        self.assertRaises(TypeError, to_bytes, None)
Ejemplo n.º 14
0
def scrypt(secret, salt, n, r, p=1, keylen=32):
    """run SCrypt key derivation function using specified parameters.

    :arg secret:
        passphrase string (unicode is encoded to bytes using utf-8).

    :arg salt:
        salt string (unicode is encoded to bytes using utf-8).

    :arg n:
        integer 'N' parameter

    :arg r:
        integer 'r' parameter

    :arg p:
        integer 'p' parameter

    :arg keylen:
        number of bytes of key to generate.
        defaults to 32 (the internal block size).

    :returns:
        a *keylen*-sized bytes instance

    SCrypt imposes a number of constraints on it's input parameters:

    * ``r * p < 2**30`` -- due to a limitation of PBKDF2-HMAC-SHA256.
    * ``keylen < (2**32 - 1) * 32`` -- due to a limitation of PBKDF2-HMAC-SHA256.
    * ``n`` must a be a power of 2, and > 1 -- internal limitation of scrypt() implementation

    :raises ValueError: if the provided parameters are invalid (see constraints above).

    .. warning::

        Unless the third-party ``scrypt <https://pypi.python.org/pypi/scrypt/>``_ package
        is installed, passlib will use a builtin pure-python implementation of scrypt,
        which is *considerably* slower (and thus requires a much lower / less secure
        ``n`` value in order to be usuable). Installing the :mod:`!scrypt` package
        is strongly recommended.
    """
    validate(n, r, p)
    secret = to_bytes(secret, param="secret")
    salt = to_bytes(salt, param="salt")
    if keylen < 1:
        raise ValueError("keylen must be at least 1")
    if keylen > MAX_KEYLEN:
        raise ValueError("keylen too large, must be <= %d" % MAX_KEYLEN)
    return _scrypt(secret, salt, n, r, p, keylen)
Ejemplo n.º 15
0
 def _calc_checksum(self, secret):
     # TODO: add in 'encoding' support once that's finalized in 1.8 / 1.9.
     uh.validate_secret(secret)
     secret = to_bytes(secret, "utf-8")
     kwds = dict(
         password=secret,
         salt=self.salt,
         time_cost=self.rounds,
         memory_cost=self.memory_cost,
         parallelism=self.parallelism,
         tag_length=self.checksum_size,
         type_code=self._get_backend_type(self.type),
         version=self.version,
     )
     if self.max_threads > 0:
         kwds['threads'] = self.max_threads
     if self.pure_use_threads:
         kwds['use_threads'] = True
     if self.data:
         kwds['associated_data'] = self.data
     # NOTE: should return raw bytes
     # NOTE: this may raise _argon2pure.Argon2ParameterError,
     #       but it if does that, there's a bug in our own parameter checking code.
     try:
         return _argon2pure.argon2(**kwds)
     except _argon2pure.Argon2Error as err:
         raise self._adapt_backend_error(err, self=self)
Ejemplo n.º 16
0
def password():
    status = Status()
    form = Form(request.forms)
    username = open_session()['u']
    if request.method == 'POST' and form.validate():
        conn = db.engine.connect()
        result = conn.execute(
            select([
                users.c.pbkdf2]).where(
                    users.c.id == username))
        conn.close()
        row = result.fetchone()
        verify = pbkdf2_sha256.verify(
            form.current_password.data, row['pbkdf2'])
        if verify:
            new_pbkdf2 = to_bytes(pbkdf2_sha256.encrypt(
                form.new_password.data))
            conn = db.engine.connect()
            conn.execute(
                users.update().values(
                    pbkdf2=new_pbkdf2).where(
                        users.c.id == username))
            conn.close()
            status.success = "Changed password"
        else:
            status.warning = "Wrong password for this account"
    return dict(status=status,
                form=form)
Ejemplo n.º 17
0
    def test_02_from_string(self):
        "test CryptPolicy.from_string() constructor"
        # test "\n" linesep
        policy = CryptPolicy.from_string(self.sample_config_1s)
        self.assertEqual(policy.to_dict(), self.sample_config_1pd)

        # test "\r\n" linesep
        policy = CryptPolicy.from_string(
            self.sample_config_1s.replace("\n", "\r\n"))
        self.assertEqual(policy.to_dict(), self.sample_config_1pd)

        # test with unicode
        data = to_unicode(self.sample_config_1s)
        policy = CryptPolicy.from_string(data)
        self.assertEqual(policy.to_dict(), self.sample_config_1pd)

        # test with non-ascii-compatible encoding
        uc2 = to_bytes(self.sample_config_1s,
                       "utf-16",
                       source_encoding="utf-8")
        policy = CryptPolicy.from_string(uc2, encoding="utf-16")
        self.assertEqual(policy.to_dict(), self.sample_config_1pd)

        # test category specific options
        policy = CryptPolicy.from_string(self.sample_config_4s)
        self.assertEqual(policy.to_dict(), self.sample_config_4pd)
Ejemplo n.º 18
0
 def _calc_checksum(self, secret):
     # TODO: add in 'encoding' support once that's finalized in 1.8 / 1.9.
     uh.validate_secret(secret)
     secret = to_bytes(secret, "utf-8")
     if self.type_d:
         type = _argon2pure.ARGON2D
     else:
         type = _argon2pure.ARGON2I
     kwds = dict(
         password=secret,
         salt=self.salt,
         time_cost=self.rounds,
         memory_cost=self.memory_cost,
         parallelism=self.parallelism,
         tag_length=self.checksum_size,
         type_code=type,
         version=self.version,
     )
     if self.max_threads > 0:
         kwds['threads'] = self.max_threads
     if self.pure_use_threads:
         kwds['use_threads'] = True
     if self.data:
         kwds['associated_data'] = self.data
     # NOTE: should return raw bytes
     # NOTE: this may raise _argon2pure.Argon2ParameterError,
     #       but it if does that, there's a bug in our own parameter checking code.
     try:
         return _argon2pure.argon2(**kwds)
     except _argon2pure.Argon2Error as err:
         raise self._adapt_backend_error(err, self=self)
Ejemplo n.º 19
0
    def test_13_whitespace(self):
        """whitespace & comment handling"""

        # per htpasswd source (https://github.com/apache/httpd/blob/trunk/support/htpasswd.c),
        # lines that match "^\s*(#.*)?$" should be ignored
        source = to_bytes('\n'
                          'user2:pass2\n'
                          'user4:pass4\n'
                          'user7:pass7\r\n'
                          ' \t \n'
                          'user1:pass1\n'
                          ' # legacy users\n'
                          '#user6:pass6\n'
                          'user5:pass5\n\n')

        # loading should see all users (except user6, who was commented out)
        ht = apache.HtpasswdFile.from_string(source)
        self.assertEqual(sorted(ht.users()),
                         ["user1", "user2", "user4", "user5", "user7"])

        # update existing user
        ht.set_hash("user4", "althash4")
        self.assertEqual(sorted(ht.users()),
                         ["user1", "user2", "user4", "user5", "user7"])

        # add a new user
        ht.set_hash("user6", "althash6")
        self.assertEqual(
            sorted(ht.users()),
            ["user1", "user2", "user4", "user5", "user6", "user7"])

        # delete existing user
        ht.delete("user7")
        self.assertEqual(sorted(ht.users()),
                         ["user1", "user2", "user4", "user5", "user6"])

        # re-serialization should preserve whitespace
        target = to_bytes('\n'
                          'user2:pass2\n'
                          'user4:althash4\n'
                          ' \t \n'
                          'user1:pass1\n'
                          ' # legacy users\n'
                          '#user6:pass6\n'
                          'user5:pass5\n'
                          'user6:althash6\n')
        self.assertEqual(ht.to_string(), target)
Ejemplo n.º 20
0
 def check_bcrypt(secret, hash):
     """bcrypt"""
     secret = to_bytes(secret, self.fuzz_password_encoding)
     # if hash.startswith(IDENT_2Y):
     #    hash = IDENT_2A + hash[4:]
     if hash.startswith(IDENT_2):
         # bcryptor doesn't support $2$ hashes; but we can fake it
         # using the $2a$ algorithm, by repeating the password until
         # it's 72 chars in length.
         hash = IDENT_2A + hash[3:]
         if secret:
             secret = repeat_string(secret, 72)
     hash = to_bytes(hash)
     try:
         return bcrypt.hashpw(secret, hash) == hash
     except ValueError:
         raise ValueError("bcrypt rejected hash: %r" % (hash,))
Ejemplo n.º 21
0
    def test_13_whitespace(self):
        """whitespace & comment handling"""

        # per htpasswd source (https://github.com/apache/httpd/blob/trunk/support/htpasswd.c),
        # lines that match "^\s*(#.*)?$" should be ignored
        source = to_bytes(
            '\n'
            'user2:pass2\n'
            'user4:pass4\n'
            'user7:pass7\r\n'
            ' \t \n'
            'user1:pass1\n'
            ' # legacy users\n'
            '#user6:pass6\n'
            'user5:pass5\n\n'
        )

        # loading should see all users (except user6, who was commented out)
        ht = apache.HtpasswdFile.from_string(source)
        self.assertEqual(sorted(ht.users()), ["user1", "user2", "user4", "user5", "user7"])

        # update existing user
        ht.set_hash("user4", "althash4")
        self.assertEqual(sorted(ht.users()), ["user1", "user2", "user4", "user5", "user7"])

        # add a new user
        ht.set_hash("user6", "althash6")
        self.assertEqual(sorted(ht.users()), ["user1", "user2", "user4", "user5", "user6", "user7"])

        # delete existing user
        ht.delete("user7")
        self.assertEqual(sorted(ht.users()), ["user1", "user2", "user4", "user5", "user6"])

        # re-serialization should preserve whitespace
        target = to_bytes(
            '\n'
            'user2:pass2\n'
            'user4:althash4\n'
            ' \t \n'
            'user1:pass1\n'
            ' # legacy users\n'
            '#user6:pass6\n'
            'user5:pass5\n'
            'user6:althash6\n'
        )
        self.assertEqual(ht.to_string(), target)
Ejemplo n.º 22
0
 def check_bcrypt(secret, hash):
     "bcrypt"
     secret = to_bytes(secret, self.fuzz_password_encoding)
     #if hash.startswith(IDENT_2Y):
     #    hash = IDENT_2A + hash[4:]
     if hash.startswith(IDENT_2):
         # bcryptor doesn't support $2$ hashes; but we can fake it
         # using the $2a$ algorithm, by repeating the password until
         # it's 72 chars in length.
         hash = IDENT_2A + hash[3:]
         if secret:
             secret = repeat_string(secret, 72)
     hash = to_bytes(hash)
     try:
         return bcrypt.hashpw(secret, hash) == hash
     except ValueError:
         raise ValueError("bcrypt rejected hash: %r" % (hash, ))
Ejemplo n.º 23
0
 def hash(cls, secret):
     # TODO: add in 'encoding' support once that's finalized in 1.8 / 1.9.
     uh.validate_secret(secret)
     secret = to_bytes(secret, "utf-8")
     # XXX: doesn't seem to be a way to make this honor max_threads
     try:
         return bascii_to_str(_argon2_cffi.low_level.hash_secret(
             type=_argon2_cffi.low_level.Type.I,
             memory_cost=cls.memory_cost,
             time_cost=cls.default_rounds,
             parallelism=cls.parallelism,
             salt=to_bytes(cls._generate_salt()),
             hash_len=cls.checksum_size,
             secret=secret,
         ))
     except _argon2_cffi.exceptions.HashingError as err:
         raise cls._adapt_backend_error(err)
Ejemplo n.º 24
0
 def _calc_checksum(self, secret):
     secret = to_bytes(secret, param="secret")
     return _scrypt.scrypt(secret,
                           self.salt,
                           n=(1 << self.rounds),
                           r=self.block_size,
                           p=self.parallelism,
                           keylen=self.checksum_size)
Ejemplo n.º 25
0
 def verify(cls, secret, hash):
     # TODO: add in 'encoding' support once that's finalized in 1.8 / 1.9.
     uh.validate_secret(secret)
     secret = to_bytes(secret, "utf-8")
     hash = to_bytes(hash, "ascii")
     if hash.startswith(b"$argon2d$"):
         type = _argon2_cffi.low_level.Type.D
     else:
         type = _argon2_cffi.low_level.Type.I
     # XXX: doesn't seem to be a way to make this honor max_threads
     try:
         result = _argon2_cffi.low_level.verify_secret(hash, secret, type)
         assert result is True
         return True
     except _argon2_cffi.exceptions.VerifyMismatchError:
         return False
     except _argon2_cffi.exceptions.VerificationError as err:
         raise cls._adapt_backend_error(err, hash=hash)
Ejemplo n.º 26
0
 def verify(cls, secret, hash):
     # TODO: add in 'encoding' support once that's finalized in 1.8 / 1.9.
     uh.validate_secret(secret)
     secret = to_bytes(secret, "utf-8")
     hash = to_bytes(hash, "ascii")
     if hash.startswith(b"$argon2d$"):
         type = _argon2_cffi.low_level.Type.D
     else:
         type = _argon2_cffi.low_level.Type.I
     # XXX: doesn't seem to be a way to make this honor max_threads
     try:
         result = _argon2_cffi.low_level.verify_secret(hash, secret, type)
         assert result is True
         return True
     except _argon2_cffi.exceptions.VerifyMismatchError:
         return False
     except _argon2_cffi.exceptions.VerificationError as err:
         raise cls._adapt_backend_error(err, hash=hash)
Ejemplo n.º 27
0
 def hash(cls, secret):
     # TODO: add in 'encoding' support once that's finalized in 1.8 / 1.9.
     uh.validate_secret(secret)
     secret = to_bytes(secret, "utf-8")
     # XXX: doesn't seem to be a way to make this honor max_threads
     try:
         return bascii_to_str(
             _argon2_cffi.low_level.hash_secret(
                 type=cls._get_backend_type(cls.type),
                 memory_cost=cls.memory_cost,
                 time_cost=cls.default_rounds,
                 parallelism=cls.parallelism,
                 salt=to_bytes(cls._generate_salt()),
                 hash_len=cls.checksum_size,
                 secret=secret,
             ))
     except _argon2_cffi.exceptions.HashingError as err:
         raise cls._adapt_backend_error(err)
Ejemplo n.º 28
0
        def generate(self):
            opts = super(_bcrypt_test.FuzzHashGenerator, self).generate()

            secret = opts['secret']
            other = opts['other']
            settings = opts['settings']
            ident = settings.get('ident')

            if ident == IDENT_2X:
                # 2x is just recognized, not supported. don't test with it.
                del settings['ident']

            elif ident == IDENT_2 and other and repeat_string(to_bytes(other), len(to_bytes(secret))) == to_bytes(secret):
                # avoid false failure due to flaw in 0-revision bcrypt:
                # repeated strings like 'abc' and 'abcabc' hash identically.
                opts['secret'], opts['other'] = self.random_password_pair()

            return opts
Ejemplo n.º 29
0
 def check_bcrypt(secret, hash):
     """bcrypt"""
     secret = to_bytes(secret, self.FuzzHashGenerator.password_encoding)
     if hash.startswith(IDENT_2B):
         # bcrypt <1.1 lacks 2B support
         hash = IDENT_2A + hash[4:]
     elif hash.startswith(IDENT_2):
         # bcrypt doesn't support $2$ hashes; but we can fake it
         # using the $2a$ algorithm, by repeating the password until
         # it's 72 chars in length.
         hash = IDENT_2A + hash[3:]
         if secret:
             secret = repeat_string(secret, 72)
     elif hash.startswith(IDENT_2Y) and bcrypt.__version__ == "3.0.0":
         hash = IDENT_2B + hash[4:]
     hash = to_bytes(hash)
     try:
         return bcrypt.hashpw(secret, hash) == hash
     except ValueError:
         raise ValueError("bcrypt rejected hash: %r (secret=%r)" % (hash, secret))
Ejemplo n.º 30
0
        def generate(self):
            opts = super(_bcrypt_test.FuzzHashGenerator, self).generate()

            secret = opts['secret']
            other = opts['other']
            settings = opts['settings']
            ident = settings.get('ident')

            if ident == IDENT_2X:
                # 2x is just recognized, not supported. don't test with it.
                del settings['ident']

            elif ident == IDENT_2 and other and repeat_string(
                    to_bytes(other), len(
                        to_bytes(secret))) == to_bytes(secret):
                # avoid false failure due to flaw in 0-revision bcrypt:
                # repeated strings like 'abc' and 'abcabc' hash identically.
                opts['secret'], opts['other'] = self.random_password_pair()

            return opts
Ejemplo n.º 31
0
    def verify(cls, secret, hash):
        # TODO: add in 'encoding' support once that's finalized in 1.8 / 1.9.
        uh.validate_secret(secret)
        secret = to_bytes(secret, "utf-8")
        hash = to_bytes(hash, "ascii")

        # read type from start of hash
        # NOTE: don't care about malformed strings, lowlevel will throw error for us
        type = cls._byte_ident_map.get(hash[:1 + hash.find(b"$", 1)], TYPE_I)
        type_code = cls._get_backend_type(type)

        # XXX: doesn't seem to be a way to make this honor max_threads
        try:
            result = _argon2_cffi.low_level.verify_secret(
                hash, secret, type_code)
            assert result is True
            return True
        except _argon2_cffi.exceptions.VerifyMismatchError:
            return False
        except _argon2_cffi.exceptions.VerificationError as err:
            raise cls._adapt_backend_error(err, hash=hash)
Ejemplo n.º 32
0
 def check_bcrypt(secret, hash):
     """bcrypt"""
     secret = to_bytes(secret, self.FuzzHashGenerator.password_encoding)
     if hash.startswith(IDENT_2B):
         # bcrypt <1.1 lacks 2B support
         hash = IDENT_2A + hash[4:]
     elif hash.startswith(IDENT_2):
         # bcrypt doesn't support $2$ hashes; but we can fake it
         # using the $2a$ algorithm, by repeating the password until
         # it's 72 chars in length.
         hash = IDENT_2A + hash[3:]
         if secret:
             secret = repeat_string(secret, 72)
     elif hash.startswith(IDENT_2Y) and bcrypt.__version__ == "3.0.0":
         hash = IDENT_2B + hash[4:]
     hash = to_bytes(hash)
     try:
         return bcrypt.hashpw(secret, hash) == hash
     except ValueError:
         raise ValueError("bcrypt rejected hash: %r (secret=%r)" %
                          (hash, secret))
Ejemplo n.º 33
0
    def test_90_decode(self):
        """test cisco_type7.decode()"""
        from passlib.utils import to_unicode, to_bytes

        handler = self.handler
        for secret, hash in self.known_correct_hashes:
            usecret = to_unicode(secret)
            bsecret = to_bytes(secret)
            self.assertEqual(handler.decode(hash), usecret)
            self.assertEqual(handler.decode(hash, None), bsecret)

        self.assertRaises(UnicodeDecodeError, handler.decode,
                          '0958EDC8A9F495F6F8A5FD', 'ascii')
Ejemplo n.º 34
0
    def test_90_decode(self):
        """test cisco_type7.decode()"""
        from passlib.utils import to_unicode, to_bytes

        handler = self.handler
        for secret, hash in self.known_correct_hashes:
            usecret = to_unicode(secret)
            bsecret = to_bytes(secret)
            self.assertEqual(handler.decode(hash), usecret)
            self.assertEqual(handler.decode(hash, None), bsecret)

        self.assertRaises(UnicodeDecodeError, handler.decode,
                          '0958EDC8A9F495F6F8A5FD', 'ascii')
Ejemplo n.º 35
0
    def test_01_from_path(self):
        """test CryptPolicy.from_path() constructor with encodings"""
        path = self.mktemp()

        # test "\n" linesep
        set_file(path, self.sample_config_1s)
        policy = CryptPolicy.from_path(path)
        self.assertEqual(policy.to_dict(), self.sample_config_1pd)

        # test "\r\n" linesep
        set_file(path, self.sample_config_1s.replace("\n","\r\n"))
        policy = CryptPolicy.from_path(path)
        self.assertEqual(policy.to_dict(), self.sample_config_1pd)

        # test with custom encoding
        uc2 = to_bytes(self.sample_config_1s, "utf-16", source_encoding="utf-8")
        set_file(path, uc2)
        policy = CryptPolicy.from_path(path, encoding="utf-16")
        self.assertEqual(policy.to_dict(), self.sample_config_1pd)
    def test_01_from_path(self):
        "test CryptPolicy.from_path() constructor with encodings"
        path = self.mktemp()

        #test "\n" linesep
        set_file(path, self.sample_config_1s)
        policy = CryptPolicy.from_path(path)
        self.assertEqual(policy.to_dict(), self.sample_config_1pd)

        #test "\r\n" linesep
        set_file(path, self.sample_config_1s.replace("\n","\r\n"))
        policy = CryptPolicy.from_path(path)
        self.assertEqual(policy.to_dict(), self.sample_config_1pd)

        #test with custom encoding
        uc2 = to_bytes(self.sample_config_1s, "utf-16", source_encoding="utf-8")
        set_file(path, uc2)
        policy = CryptPolicy.from_path(path, encoding="utf-16")
        self.assertEqual(policy.to_dict(), self.sample_config_1pd)
Ejemplo n.º 37
0
    def from_string(cls, source, section="passlib", encoding="utf-8"):
        """create new policy from specified section of an ini-formatted string.

        :arg source: bytes/unicode string containing ini-formatted content.
        :param section: option name of section to read from.
        :arg encoding: optional encoding if source is bytes (defaults to utf-8)

        :returns: new CryptPolicy instance.
        """
        #NOTE: we want config parser object to have native strings as keys.
        #      so we parse as bytes under py2, and unicode under py3.
        #      to handle encoding issues under py2, we use
        #      "to_bytes()" to transcode to utf-8 as needed.

        # Py2k #
        source = to_bytes(source, "utf-8", source_encoding=encoding, errname="source")
        # Py3k #
        #source = to_unicode(source, encoding, errname="source")
        # end Py3k #
        return cls._from_stream(StringIO(source), section, "<???>")
Ejemplo n.º 38
0
    def test_01_from_path(self):
        "test CryptPolicy.from_path() constructor with encodings"
        if gae_env:
            return self.skipTest("GAE doesn't offer read/write filesystem access")

        path = mktemp()

        #test "\n" linesep
        set_file(path, self.sample_config_1s)
        policy = CryptPolicy.from_path(path)
        self.assertEqual(policy.to_dict(), self.sample_config_1pd)

        #test "\r\n" linesep
        set_file(path, self.sample_config_1s.replace("\n","\r\n"))
        policy = CryptPolicy.from_path(path)
        self.assertEqual(policy.to_dict(), self.sample_config_1pd)

        #test with custom encoding
        uc2 = to_bytes(self.sample_config_1s, "utf-16", source_encoding="utf-8")
        set_file(path, uc2)
        policy = CryptPolicy.from_path(path, encoding="utf-16")
        self.assertEqual(policy.to_dict(), self.sample_config_1pd)
    def test_02_from_string(self):
        "test CryptPolicy.from_string() constructor"
        #test "\n" linesep
        policy = CryptPolicy.from_string(self.sample_config_1s)
        self.assertEqual(policy.to_dict(), self.sample_config_1pd)

        #test "\r\n" linesep
        policy = CryptPolicy.from_string(
            self.sample_config_1s.replace("\n","\r\n"))
        self.assertEqual(policy.to_dict(), self.sample_config_1pd)

        #test with unicode
        data = to_unicode(self.sample_config_1s)
        policy = CryptPolicy.from_string(data)
        self.assertEqual(policy.to_dict(), self.sample_config_1pd)

        #test with non-ascii-compatible encoding
        uc2 = to_bytes(self.sample_config_1s, "utf-16", source_encoding="utf-8")
        policy = CryptPolicy.from_string(uc2, encoding="utf-16")
        self.assertEqual(policy.to_dict(), self.sample_config_1pd)

        #test category specific options
        policy = CryptPolicy.from_string(self.sample_config_4s)
        self.assertEqual(policy.to_dict(), self.sample_config_4pd)
Ejemplo n.º 40
0
def pbkdf2_hmac(digest, secret, salt, rounds, keylen=None):
    """pkcs#5 password-based key derivation v2.0 using HMAC + arbitrary digest.

    :arg digest:
        digest name or constructor.

    :arg secret:
        passphrase to use to generate key.
        may be :class:`!bytes` or :class:`unicode` (encoded using UTF-8).

    :arg salt:
        salt string to use when generating key.
        may be :class:`!bytes` or :class:`unicode` (encoded using UTF-8).

    :param rounds:
        number of rounds to use to generate key.

    :arg keylen:
        number of bytes to generate.
        if omitted / ``None``, will use digest's native output size.

    :returns:
        raw bytes of generated key

    .. versionchanged:: 1.7

        This function will use the first available of the following backends:

        * `fastpbk2 <https://pypi.python.org/pypi/fastpbkdf2>`_
        * :func:`hashlib.pbkdf2_hmac` (only available in py2 >= 2.7.8, and py3 >= 3.4)
        * builtin pure-python backend

        See :data:`passlib.crypto.digest.PBKDF2_BACKENDS` to determine
        which backend(s) are in use.
    """
    # validate secret & salt
    secret = to_bytes(secret, param="secret")
    salt = to_bytes(salt, param="salt")

    # resolve digest
    digest_info = lookup_hash(digest)
    digest_size = digest_info.digest_size

    # validate rounds
    if not isinstance(rounds, int_types):
        raise exc.ExpectedTypeError(rounds, "int", "rounds")
    if rounds < 1:
        raise ValueError("rounds must be at least 1")

    # validate keylen
    if keylen is None:
        keylen = digest_size
    elif not isinstance(keylen, int_types):
        raise exc.ExpectedTypeError(keylen, "int or None", "keylen")
    elif keylen < 1:
        # XXX: could allow keylen=0, but want to be compat w/ stdlib
        raise ValueError("keylen must be at least 1")

    # find smallest block count s.t. keylen <= block_count * digest_size;
    # make sure block count won't overflow (per pbkdf2 spec)
    # this corresponds to throwing error if keylen > digest_size * MAX_UINT32
    # NOTE: stdlib will throw error at lower bound (keylen > MAX_SINT32)
    # NOTE: have do this before other backends checked, since fastpbkdf2 raises wrong error
    #       (InvocationError, not OverflowError)
    block_count = (keylen + digest_size - 1) // digest_size
    if block_count > MAX_UINT32:
        raise OverflowError("keylen too long for digest")

    #
    # check for various high-speed backends
    #

    # ~3x faster than pure-python backend
    # NOTE: have to do this after above guards since fastpbkdf2 lacks bounds checks.
    if digest_info.supported_by_fastpbkdf2:
        return _fast_pbkdf2_hmac(digest_info.name, secret, salt, rounds, keylen)

    # ~1.4x faster than pure-python backend
    # NOTE: have to do this after fastpbkdf2 since hashlib-ssl is slower,
    #       will support larger number of hashes.
    if digest_info.supported_by_hashlib_pbkdf2:
        return _stdlib_pbkdf2_hmac(digest_info.name, secret, salt, rounds, keylen)

    #
    # otherwise use our own implementation
    #

    # generated keyed hmac
    keyed_hmac = compile_hmac(digest, secret)

    # get helper to calculate pbkdf2 inner loop efficiently
    calc_block = _get_pbkdf2_looper(digest_size)

    # assemble & return result
    return join_bytes(
        calc_block(keyed_hmac, keyed_hmac(salt + _pack_uint32(i)), rounds)
        for i in irange(1, block_count + 1)
    )[:keylen]
Ejemplo n.º 41
0
def pbkdf2_hmac(digest, secret, salt, rounds, keylen=None):
    """pkcs#5 password-based key derivation v2.0 using HMAC + arbitrary digest.

    :arg digest:
        digest name or constructor.

    :arg secret:
        passphrase to use to generate key.
        may be :class:`!bytes` or :class:`unicode` (encoded using UTF-8).

    :arg salt:
        salt string to use when generating key.
        may be :class:`!bytes` or :class:`unicode` (encoded using UTF-8).

    :param rounds:
        number of rounds to use to generate key.

    :arg keylen:
        number of bytes to generate.
        if omitted / ``None``, will use digest's native output size.

    :returns:
        raw bytes of generated key

    .. versionchanged:: 1.7

        This function will use the first available of the following backends:

        * `fastpbk2 <https://pypi.python.org/pypi/fastpbkdf2>`_
        * :func:`hashlib.pbkdf2_hmac` (only available in py2 >= 2.7.8, and py3 >= 3.4)
        * builtin pure-python backend

        See :data:`passlib.crypto.digest.PBKDF2_BACKENDS` to determine
        which backend(s) are in use.
    """
    # validate secret & salt
    secret = to_bytes(secret, param="secret")
    salt = to_bytes(salt, param="salt")

    # resolve digest
    digest_info = lookup_hash(digest)
    digest_size = digest_info.digest_size

    # validate rounds
    if not isinstance(rounds, int_types):
        raise exc.ExpectedTypeError(rounds, "int", "rounds")
    if rounds < 1:
        raise ValueError("rounds must be at least 1")

    # validate keylen
    if keylen is None:
        keylen = digest_size
    elif not isinstance(keylen, int_types):
        raise exc.ExpectedTypeError(keylen, "int or None", "keylen")
    elif keylen < 1:
        # XXX: could allow keylen=0, but want to be compat w/ stdlib
        raise ValueError("keylen must be at least 1")

    # find smallest block count s.t. keylen <= block_count * digest_size;
    # make sure block count won't overflow (per pbkdf2 spec)
    # this corresponds to throwing error if keylen > digest_size * MAX_UINT32
    # NOTE: stdlib will throw error at lower bound (keylen > MAX_SINT32)
    # NOTE: have do this before other backends checked, since fastpbkdf2 raises wrong error
    #       (InvocationError, not OverflowError)
    block_count = (keylen + digest_size - 1) // digest_size
    if block_count > MAX_UINT32:
        raise OverflowError("keylen too long for digest")

    #
    # check for various high-speed backends
    #

    # ~3x faster than pure-python backend
    # NOTE: have to do this after above guards since fastpbkdf2 lacks bounds checks.
    if digest_info.supported_by_fastpbkdf2:
        return _fast_pbkdf2_hmac(digest_info.name, secret, salt, rounds,
                                 keylen)

    # ~1.4x faster than pure-python backend
    # NOTE: have to do this after fastpbkdf2 since hashlib-ssl is slower,
    #       will support larger number of hashes.
    if digest_info.supported_by_hashlib_pbkdf2:
        return _stdlib_pbkdf2_hmac(digest_info.name, secret, salt, rounds,
                                   keylen)

    #
    # otherwise use our own implementation
    #

    # generated keyed hmac
    keyed_hmac = compile_hmac(digest, secret)

    # get helper to calculate pbkdf2 inner loop efficiently
    calc_block = _get_pbkdf2_looper(digest_size)

    # assemble & return result
    return join_bytes(
        calc_block(keyed_hmac, keyed_hmac(salt + _pack_uint32(i)), rounds)
        for i in irange(1, block_count + 1))[:keylen]
Ejemplo n.º 42
0
 def load_string(self, data):
     """Load state from unicode or bytes string, replacing current state"""
     data = to_bytes(data, self.encoding, "data")
     self._mtime = 0
     self._load_lines(BytesIO(data))
Ejemplo n.º 43
0
def compile_hmac(digest, key, multipart=False):
    """
    This function returns an efficient HMAC function, hardcoded with a specific digest & key.
    It can be used via ``hmac = compile_hmac(digest, key)``.

    :arg digest:
        digest name or constructor.

    :arg key:
        secret key as :class:`!bytes` or :class:`!unicode` (unicode will be encoded using utf-8).

    :param multipart:
        request a multipart constructor instead (see return description).

    :returns:
        By default, the returned function has the signature ``hmac(msg) -> digest output``.

        However, if ``multipart=True``, the returned function has the signature
        ``hmac() -> update, finalize``, where ``update(msg)`` may be called multiple times,
        and ``finalize() -> digest_output`` may be repeatedly called at any point to
        calculate the HMAC digest so far.

        The returned object will also have a ``digest_info`` attribute, containing
        a :class:`lookup_hash` instance for the specified digest.

    This function exists, and has the weird signature it does, in order to squeeze as
    provide as much efficiency as possible, by omitting much of the setup cost
    and features of the stdlib :mod:`hmac` module.
    """
    # all the following was adapted from stdlib's hmac module

    # resolve digest (cached)
    digest_info = lookup_hash(digest)
    const, digest_size, block_size = digest_info
    assert block_size >= 16, "block size too small"

    # prepare key
    if not isinstance(key, bytes):
        key = to_bytes(key, param="key")
    klen = len(key)
    if klen > block_size:
        key = const(key).digest()
        klen = digest_size
    if klen < block_size:
        key += b'\x00' * (block_size - klen)

    # create pre-initialized hash constructors
    _inner_copy = const(key.translate(_TRANS_36)).copy
    _outer_copy = const(key.translate(_TRANS_5C)).copy

    if multipart:
        # create multi-part function
        # NOTE: this is slightly slower than the single-shot version,
        #       and should only be used if needed.
        def hmac():
            """generated by compile_hmac(multipart=True)"""
            inner = _inner_copy()

            def finalize():
                outer = _outer_copy()
                outer.update(inner.digest())
                return outer.digest()

            return inner.update, finalize
    else:

        # single-shot function
        def hmac(msg):
            """generated by compile_hmac()"""
            inner = _inner_copy()
            inner.update(msg)
            outer = _outer_copy()
            outer.update(inner.digest())
            return outer.digest()

    # add info attr
    hmac.digest_info = digest_info
    return hmac
Ejemplo n.º 44
0
def compile_hmac(digest, key, multipart=False):
    """
    This function returns an efficient HMAC function, hardcoded with a specific digest & key.
    It can be used via ``hmac = compile_hmac(digest, key)``.

    :arg digest:
        digest name or constructor.

    :arg key:
        secret key as :class:`!bytes` or :class:`!unicode` (unicode will be encoded using utf-8).

    :param multipart:
        request a multipart constructor instead (see return description).

    :returns:
        By default, the returned function has the signature ``hmac(msg) -> digest output``.

        However, if ``multipart=True``, the returned function has the signature
        ``hmac() -> update, finalize``, where ``update(msg)`` may be called multiple times,
        and ``finalize() -> digest_output`` may be repeatedly called at any point to
        calculate the HMAC digest so far.

        The returned object will also have a ``digest_info`` attribute, containing
        a :class:`lookup_hash` instance for the specified digest.

    This function exists, and has the weird signature it does, in order to squeeze as
    provide as much efficiency as possible, by omitting much of the setup cost
    and features of the stdlib :mod:`hmac` module.
    """
    # all the following was adapted from stdlib's hmac module

    # resolve digest (cached)
    digest_info = lookup_hash(digest)
    const, digest_size, block_size = digest_info
    assert block_size >= 16, "block size too small"

    # prepare key
    if not isinstance(key, bytes):
        key = to_bytes(key, param="key")
    klen = len(key)
    if klen > block_size:
        key = const(key).digest()
        klen = digest_size
    if klen < block_size:
        key += b'\x00' * (block_size - klen)

    # create pre-initialized hash constructors
    _inner_copy = const(key.translate(_TRANS_36)).copy
    _outer_copy = const(key.translate(_TRANS_5C)).copy

    if multipart:
        # create multi-part function
        # NOTE: this is slightly slower than the single-shot version,
        #       and should only be used if needed.
        def hmac():
            """generated by compile_hmac(multipart=True)"""
            inner = _inner_copy()
            def finalize():
                outer = _outer_copy()
                outer.update(inner.digest())
                return outer.digest()
            return inner.update, finalize
    else:

        # single-shot function
        def hmac(msg):
            """generated by compile_hmac()"""
            inner = _inner_copy()
            inner.update(msg)
            outer = _outer_copy()
            outer.update(inner.digest())
            return outer.digest()

    # add info attr
    hmac.digest_info = digest_info
    return hmac
Ejemplo n.º 45
0
 def _calc_checksum(self, secret):
     if isinstance(secret, unicode):
         secret = secret.encode("utf-8")
     user = to_bytes(self.user, "utf-8", param="user")
     return str_to_uascii(md5(secret + user).hexdigest())
Ejemplo n.º 46
0
def cmp_hash(a, b):
    return consteq(to_bytes(a), to_bytes(b))
Ejemplo n.º 47
0
 def load_string(self, data):
     "Load state from unicode or bytes string, replacing current state"
     data = to_bytes(data, self.encoding, "data")
     self._mtime = 0
     self._load_lines(BytesIO(data))
Ejemplo n.º 48
0
    def test_crypt(self):
        """test crypt.crypt() wrappers"""
        from passlib.utils import has_crypt, safe_crypt, test_crypt
        from passlib.registry import get_supported_os_crypt_schemes, get_crypt_handler

        # test everything is disabled
        supported = get_supported_os_crypt_schemes()
        if not has_crypt:
            self.assertEqual(supported, ())
            self.assertEqual(safe_crypt("test", "aa"), None)
            self.assertFalse(test_crypt("test", "aaqPiZY5xR5l."))  # des_crypt() hash of "test"
            raise self.skipTest("crypt.crypt() not available")

        # expect there to be something supported, if crypt() is present
        if not supported:
            # NOTE: failures here should be investigated.  usually means one of:
            # 1) at least one of passlib's os_crypt detection routines is giving false negative
            # 2) crypt() ONLY supports some hash alg which passlib doesn't know about
            # 3) crypt() is present but completely disabled (never encountered this yet)
            raise self.fail("crypt() present, but no supported schemes found!")

        # pick cheap alg if possible, with minimum rounds, to speed up this test.
        # NOTE: trusting hasher class works properly (should have been verified using it's own UTs)
        for scheme in ("md5_crypt", "sha256_crypt"):
            if scheme in supported:
                break
        else:
            scheme = supported[-1]
        hasher = get_crypt_handler(scheme)
        if getattr(hasher, "min_rounds", None):
            hasher = hasher.using(rounds=hasher.min_rounds)

        # helpers to generate hashes & config strings to work with
        def get_hash(secret):
            assert isinstance(secret, unicode)
            hash = hasher.hash(secret)
            if isinstance(hash, bytes):  # py2
                hash = hash.decode("utf-8")
            assert isinstance(hash, unicode)
            return hash

        # test ascii password & return type
        s1 = u("test")
        h1 = get_hash(s1)
        result = safe_crypt(s1, h1)
        self.assertIsInstance(result, unicode)
        self.assertEqual(result, h1)
        self.assertEqual(safe_crypt(to_bytes(s1), to_bytes(h1)), h1)

        # make sure crypt doesn't just blindly return h1 for whatever we pass in
        h1x = h1[:-2] + 'xx'
        self.assertEqual(safe_crypt(s1, h1x), h1)

        # test utf-8 / unicode password
        s2 = u('test\u1234')
        h2 = get_hash(s2)
        self.assertEqual(safe_crypt(s2, h2), h2)
        self.assertEqual(safe_crypt(to_bytes(s2), to_bytes(h2)), h2)

        # test rejects null chars in password
        self.assertRaises(ValueError, safe_crypt, '\x00', h1)

        # check test_crypt()
        self.assertTrue(test_crypt("test", h1))
        self.assertFalse(test_crypt("test", h1x))

        # check crypt returning variant error indicators
        # some platforms return None on errors, others empty string,
        # The BSDs in some cases return ":"
        import passlib.utils as mod
        orig = mod._crypt
        try:
            retval = None
            mod._crypt = lambda secret, hash: retval

            for retval in [None, "", ":", ":0", "*0"]:
                self.assertEqual(safe_crypt("test", h1), None)
                self.assertFalse(test_crypt("test", h1))

            retval = 'xxx'
            self.assertEqual(safe_crypt("test", h1), "xxx")
            self.assertFalse(test_crypt("test", h1))

        finally:
            mod._crypt = orig
Ejemplo n.º 49
0
 def _calc_checksum(self, secret):
     if isinstance(secret, unicode):
         secret = secret.encode("utf-8")
     user = to_bytes(self.user, "utf-8", param="user")
     return str_to_uascii(md5(secret + user).hexdigest())
def login():
    req_data = request.get_json()
    if request.method == 'POST':
        app.logger.info("post")
 
    try:
        _name = req_data['username']
        _password = req_data['password']  
        # app.logger.info(_name)
        # app.logger.info(_password)
        # app.logger.info("got this far ......")
        
        if _name and _password:
            #every MYSQL query must be constructed this way
            with connection.cursor() as cursor:
                # return jsonify(message="Before call")
                # sqlname = str("'" + _name + "'")
                # sqlcode = str("SELECT * FROM USER INNER JOIN MEMBER ON USER.USER_NUM = MEMBER.USER_NUM INNER JOIN MEMBERSHIP ON MEMBER.MEM_CODE = MEMBERSHIP.MEM_CODE WHERE USERNAME = "******"SELECT MEMBER.PASSWORD, MEMBER.USER_NUM FROM MEMBER INNER JOIN USER ON MEMBER.USER_NUM = USER.USER_NUM INNER JOIN MEMBERSHIP ON MEMBER.MEM_CODE = MEMBERSHIP.MEM_CODE WHERE USERNAME = %s", _name )
                # SELECT * FROM USER INNER JOIN MEMBER ON USER.USER_NUM = MEMBER.USER_NUM INNER JOIN MEMBERSHIP ON MEMBER.MEM_CODE = MEMBERSHIP.MEM_CODE WHERE MEMBER.USERNAME = jimmy
                # cursor.execute("SELECT * FROM USER INNER JOIN MEMBER ON USER.USER_NUM = MEMBER.USER_NUM INNER JOIN MEMBERSHIP ON MEMBER.MEM_CODE = MEMBERSHIP.MEM_CODE")
                # cursor.execute("SELECT MEMBER.PASSWORD, MEMBER.USER_NUM FROM USER INNER JOIN MEMBER ON USER.USER_NUM = MEMBER.MEMBER_NUM INNER JOIN MEMBERSHIP ON MEMBER.MEM_CODE = MEMBERSHIP.MEM_CODE WHERE USERNAME = %s", _name)
                # cursor.execute("SELECT MEMBER.PASSWORD, MEMBER.USER_NUM, MEMBER.MEM_CODE, FROM MEMBER INNER JOIN USER ON MEMBER.USER_NUM = USER.USER_NUM WHERE USERNAME = %s", _name)
                # cursor.execute("SELECT MEMBERSHIP.MEM_CODE, MEMBERSHIP.NAME, MEMBERSHIP.POINTS, MEMBERSHIP.PERIOD_MONTHS, MEMBERSHIP.RECURRING FROM MEMBERSHIP INNER JOIN USER ON MEMBERSHIP.")
                cursor.execute("SELECT MEMBER.PASSWORD, MEMBER.USER_NUM FROM MEMBER INNER JOIN USER ON MEMBER.USER_NUM = USER.USER_NUM WHERE USERNAME = %s", _name)
                # cursor.execute("SELECT MEMBER.PASSWORD, MEMBER.USER_NUM, MEMBERSHIP.MEM_CODE, MEMBERSHIP.NAME, MEMBERSHIP.POINTS, MEMBERSHIP.PERIOD_MONTHS, MEMBERSHIP.RECURRING, USER.FNAME, USER.LNAME, USER.PHONE, USER.EMAIL, USER.SITE FROM MEMBER, MEMBERSHIP, USER WHERE USER.USERNAME = %s AND USER.USER_NUM = MEMBER.USER_NUM AND MEMBER.MEM_CODE = MEMBERSHIP.MEM_CODE", _name)
                # return jsonify(message="After call")
                
                data = cursor.fetchone()
                app.logger.info(data)
                if cursor.rowcount == 0: # This is working fine
                    app.logger.info("user non existent")
                    response = {
                        "success": False,
                        "error": "Username not found"
                    }
                    return jsonify(response)#,401
                else:
                    connection.commit()
                    myPassword = str(data["PASSWORD"])
                    id = data["USER_NUM"]
                    
                    # membershipName = data["NAME"]
                    # membershipPoints = data["POINTS"]
                    # membershipPeriod = data["PERIOD_MONTHS"]
                    # membershipRecurring = data["RECURRING"]
                    
                    app.logger.info(myPassword)
                    app.logger.info(id)
                    myPassword = to_bytes(myPassword,'utf-8')
                    
                    if pbkdf2_sha256.verify(_password, myPassword):
                        app.logger.info("it worked")
                        # session['username'] = _name # NOW GETTING AN ERROR HERE
                        # session['id'] = id
                        response = {
                            "success": True,
                            "username": _name,
                            "password": myPassword
                        }
                        return  jsonify(response)
                            
                    else:
                        app.logger.info("it did not work")
                        response = {
                            "success": False,
                            "error": "Incorrect password"
                        }
                        return jsonify(response)#,401
    except Exception as e:
        e = sys.exc_info()[0]
        app.logger.info(str(e))
        response = {
            "success": False,
            "error": "There was an internal error"
        }
        return jsonify(message='another error'),401
Ejemplo n.º 51
0
def hash(password, salt):
    return pbkdf2(to_bytes(password), to_bytes(salt), 10000).encode('hex')