def test_invalid_verify(self, backend): prk = binascii.unhexlify(b"077709362c2e32df0ddc3f0dc47bba6390b6c73bb50f9c3122ec844ad7c2b3e5") info = binascii.unhexlify(b"f0f1f2f3f4f5f6f7f8f9") hkdf = HKDFExpand(hashes.SHA256(), 42, info, backend) with pytest.raises(InvalidKey): hkdf.verify(prk, b"wrong key")
def test_invalid_verify(self, backend): prk = binascii.unhexlify( b"077709362c2e32df0ddc3f0dc47bba6390b6c73bb50f9c3122ec844ad7c2b3e5" ) info = binascii.unhexlify(b"f0f1f2f3f4f5f6f7f8f9") hkdf = HKDFExpand(hashes.SHA256(), 42, info, backend) with pytest.raises(InvalidKey): hkdf.verify(prk, b"wrong key")
def test_random_source_verify_default_backend(self, backend): key_material = urandom(16) identifier = b'region123' derived_key = derive_key(key_material, identifier, strong=True) kdf = HKDFExpand(algorithm=hashes.SHA256(), length=32, info=identifier, backend=backend) kdf.verify(key_material, derived_key)
def test_verify(self, backend): prk = binascii.unhexlify( b"077709362c2e32df0ddc3f0dc47bba6390b6c73bb50f9c3122ec844ad7c2b3e5" ) okm = (b"3cb25f25faacd57a90434f64d0362f2a2d2d0a90cf1a5a4c5db02d56ecc4c" b"5bf34007208d5b887185865") info = binascii.unhexlify(b"f0f1f2f3f4f5f6f7f8f9") hkdf = HKDFExpand(hashes.SHA256(), 42, info, backend) hkdf.verify(prk, binascii.unhexlify(okm))
def test_verify(self, backend): prk = binascii.unhexlify(b"077709362c2e32df0ddc3f0dc47bba6390b6c73bb50f9c3122ec844ad7c2b3e5") okm = b"3cb25f25faacd57a90434f64d0362f2a2d2d0a90cf1a5a4c5db02d56ecc4c" b"5bf34007208d5b887185865" info = binascii.unhexlify(b"f0f1f2f3f4f5f6f7f8f9") hkdf = HKDFExpand(hashes.SHA256(), 42, info, backend) assert hkdf.verify(prk, binascii.unhexlify(okm)) is None
async def login_post(): if 'authenticated' in session: return await flash('error', "You're already logged in!", 'home') if glob.config.debug: login_time = time.time_ns() form = await request.form username = form.get('username', type=str) passwd_txt = form.get('password', type=str) if username is None or passwd_txt is None: return await flash('error', 'Invalid parameters.', 'home') # check if account exists user_info = await glob.db.fetchrow( 'SELECT id, name, email, priv, ' 'pw, silence_end ' 'FROM users ' 'WHERE safe_name = %s', [utils.get_safe_name(username)] ) # user doesn't exist; deny post # NOTE: Bot isn't a user. if not user_info or user_info['id'] == 1: if glob.config.debug: log(f"{username}'s login failed - account doesn't exist.", Ansi.LYELLOW) return await flash('error', 'Account does not exist.', 'login') # cache and other related password information pw_cache = glob.cache['pw'] pw_hash = user_info['pw'].encode('ISO-8859-1').decode('unicode-escape').encode('ISO-8859-1') pw_md5 = hashlib.md5(passwd_txt.encode()).hexdigest().encode() # check credentials (password) against db # intentionally slow, will cache to speed up if pw_hash in pw_cache: if pw_md5 != pw_cache[pw_hash]: # ~0.1ms if glob.config.debug: log(f"{username}'s login failed - pw incorrect.", Ansi.LYELLOW) return await flash('error', 'Password is incorrect.', 'login') else: # ~200ms k = HKDFExpand(algorithm=hashes.SHA256(), length=32, info=b'', backend=backend()) try: k.verify(pw_md5, pw_hash) except: if glob.config.debug: log(f"{username}'s login failed - pw incorrect.", Ansi.LYELLOW) return await flash('error', 'Password is incorrect.', 'login') # login successful; cache password for next login pw_cache[pw_hash] = pw_md5 # user not verified; render verify if not user_info['priv'] & Privileges.Verified: if glob.config.debug: log(f"{username}'s login failed - not verified.", Ansi.LYELLOW) return await render_template('verify.html') # user banned; deny post if user_info['priv'] & Privileges.Disallowed: if glob.config.debug: log(f"{username}'s login failed - banned.", Ansi.RED) return await flash('error', 'Your account is restricted. You are not allowed to log in.', 'login') # login successful; store session data if glob.config.debug: log(f"{username}'s login succeeded.", Ansi.LGREEN) session['authenticated'] = True session['user_data'] = { 'id': user_info['id'], 'name': user_info['name'], 'email': user_info['email'], 'priv': user_info['priv'], 'silence_end': user_info['silence_end'], 'is_staff': user_info['priv'] & Privileges.Staff, 'is_donator': user_info['priv'] & Privileges.Supporter } if glob.config.debug: login_time = (time.time_ns() - login_time) / 1e6 log(f'Login took {login_time:.2f}ms!', Ansi.LYELLOW) return await flash('success', f'Hey, welcome back {username}!', 'home')
async def settings_password_post(): form = await request.form old_password = form.get('old_password') new_password = form.get('new_password') repeat_password = form.get('repeat_password') # new password and repeat password don't match; deny post if new_password != repeat_password: return await flash('error', "Your new password doesn't match your repeated password!", 'settings/password') # new password and old password match; deny post if old_password == new_password: return await flash('error', 'Your new password cannot be the same as your old password!', 'settings/password') # Passwords must: # - be within 8-32 characters in length # - have more than 3 unique characters # - not be in the config's `disallowed_passwords` list if not 8 < len(new_password) <= 32: return await flash('error', 'Your new password must be 8-32 characters in length.', 'settings/password') if len(set(new_password)) <= 3: return await flash('error', 'Your new password must have more than 3 unique characters.', 'settings/password') if new_password.lower() in glob.config.disallowed_passwords: return await flash('error', 'Your new password was deemed too simple.', 'settings/password') # cache and other password related information pw_cache = glob.cache['pw'] pw_hash = (await glob.db.fetchval( 'SELECT pw ' 'FROM users ' 'WHERE id = %s', [session['user_data']['id']]) ).encode('ISO-8859-1').decode('unicode-escape').encode('ISO-8859-1') pw_md5 = hashlib.md5(old_password.encode()).hexdigest().encode() # check old password against db # intentionally slow, will cache to speed up if pw_hash in pw_cache: if pw_md5 != pw_cache[pw_hash]: # ~0.1ms if glob.config.debug: log(f"{session['user_data']['name']}'s change pw failed - pw incorrect.", Ansi.LYELLOW) return await flash('error', 'Your old password is incorrect.', 'settings/password') else: # ~200ms k = HKDFExpand(algorithm=hashes.SHA256(), length=32, info=b'', backend=backend()) try: k.verify(pw_hash, pw_md5) except: if glob.config.debug: log(f"{session['user_data']['name']}'s change pw failed - pw incorrect.", Ansi.LYELLOW) return await flash('error', 'Your old password is incorrect.', 'settings/password') # remove old password from cache if pw_hash in pw_cache: del pw_cache[pw_hash] # calculate new md5 & bcrypt pw pw_md5 = hashlib.md5(new_password.encode()).hexdigest().encode() k = HKDFExpand(algorithm=hashes.SHA256(), length=32, info=b'', backend=backend()) pw_hash_new = k.derive(pw_md5).decode('unicode-escape') # update password in cache and db pw_cache[pw_hash_new] = pw_md5 await glob.db.execute( 'UPDATE users ' 'SET pw = %s ' 'WHERE safe_name = %s', [pw_hash_new, utils.get_safe_name(session['user_data']['name'])] ) # logout session.pop('authenticated', None) session.pop('user_data', None) return await flash('success', 'Your password has been changed! Please log in again.', 'login')
else: # password is already converted or db already has correct formats bcache = glob.cache['pw'] # get our cached pws to potentially enhance speed user_pw = user['pw'].encode('ISO-8859-1').decode('unicode-escape').encode('ISO-8859-1') # this is cursed SHUT UP if user_pw in bcache: if pw != bcache[user_pw]: # compare provided md5 with the stored (cached) pw to ensure they have provided the correct password if glob.config.debug: log(f"{username}'s login attempt failed: provided an incorrect password", Ansi.LRED) request.resp_headers['cho-token'] = 'no' # client knows there is something up if we set token to 'no' return writer.userID(-1) else: k = HKDFExpand(algorithm=hashes.SHA256(), length=32, info=b'', backend=backend()) try: k.verify(pw, user_pw) except Exception: if glob.config.debug: log(f"{username}'s login attempt failed: provided an incorrect password", Ansi.LRED) request.resp_headers['cho-token'] = 'no' # client knows there is something up if we set token to 'no' return writer.userID(-1) bcache[user_pw] = pw # cache pw for future if user['priv'] & Privileges.Banned: request.resp_headers['cho-token'] = 'no' return writer.userID(-3) if (p := await glob.players.get(id=user['id'])) and (start - p.last_ping) > 10: # game crashes n shit p.logout()