diff --git a/requirements.txt b/requirements.txt index a2a6e09..b703d12 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,4 +1,3 @@ -bcrypt cryptography pymysql python-dotenv diff --git a/src/bot/handlers.py b/src/bot/handlers.py index 83ab037..71cda91 100644 --- a/src/bot/handlers.py +++ b/src/bot/handlers.py @@ -219,7 +219,7 @@ def _add_account5( return send_tmp_message(bot, mes.chat.id, "Успешная отмена") salt, hash_ = database.get.get_master_pass(engine, mes.from_user.id) - if cryptography.master_pass.encrypt_master_pass(text, salt) != hash_: + if not cryptography.master_pass.check_master_pass(text, hash_, salt): return send_tmp_message(bot, mes.chat.id, "Не подходит главный пароль") name, login, passwd = data["name"], data["login"], data["passwd"] @@ -281,7 +281,7 @@ def _get_account3( master_salt, hash_pass = database.get.get_master_pass(engine, mes.from_user.id) - if cryptography.master_pass.encrypt_master_pass(text, master_salt) != hash_pass: + if not cryptography.master_pass.check_master_pass(text, hash_pass, master_salt): return send_tmp_message(bot, mes.chat.id, "Не подходит мастер пароль") salt, enc_login, enc_pass = database.get.get_account_info( @@ -378,7 +378,7 @@ def _export2( return send_tmp_message(bot, mes.chat.id, "Успешная отмена") master_salt, hash_pass = database.get.get_master_pass(engine, mes.from_user.id) - if cryptography.master_pass.encrypt_master_pass(text, master_salt) != hash_pass: + if not cryptography.master_pass.check_master_pass(text, hash_pass, master_salt): return send_tmp_message(bot, mes.chat.id, "Не подходит мастер пароль") accounts = get_all_accounts(engine, mes.from_user.id, text) @@ -445,7 +445,7 @@ def _import3( return send_tmp_message(bot, mes.chat.id, "Успешная отмена") master_salt, hash_pass = database.get.get_master_pass(engine, mes.from_user.id) - if cryptography.master_pass.encrypt_master_pass(text, master_salt) != hash_pass: + if not cryptography.master_pass.check_master_pass(text, hash_pass, master_salt): return send_tmp_message(bot, mes.chat.id, "Не подходит мастер пароль") # List of names of accounts, which failed to be added to the database or failed tests diff --git a/src/cryptography/master_pass.py b/src/cryptography/master_pass.py index da98987..11c793d 100644 --- a/src/cryptography/master_pass.py +++ b/src/cryptography/master_pass.py @@ -1,26 +1,35 @@ -from typing import overload +import os -import bcrypt +from cryptography.exceptions import InvalidKey +from cryptography.hazmat.primitives.kdf.scrypt import Scrypt + +_memory_use = 2**14 -@overload -def encrypt_master_pass(passwd: str, salt: bytes) -> bytes: - ... +def _get_kdf(salt: bytes) -> Scrypt: + kdf = Scrypt( + salt=salt, + length=128, + n=_memory_use, + r=8, + p=1, + ) + return kdf -@overload def encrypt_master_pass(passwd: str) -> tuple[bytes, bytes]: - ... - - -def encrypt_master_pass( - passwd: str, salt: bytes | None = None -) -> tuple[bytes, bytes] | bytes: """Hashes master password and return tuple of hashed password and salt""" - if salt is None: - salt = bcrypt.gensalt() - gened_salt = True + salt = os.urandom(64) + kdf = _get_kdf(salt) + return kdf.derive(passwd.encode("utf-8")), salt + + +def check_master_pass(passwd: str, enc_pass: bytes, salt: bytes) -> bool: + """Checks if the master password is correct""" + kdf = _get_kdf(salt) + try: + kdf.verify(passwd.encode("utf-8"), enc_pass) + except InvalidKey: + return False else: - gened_salt = False - hashed = bcrypt.hashpw(passwd.encode("utf-8"), salt) - return (hashed, salt) if gened_salt else hashed + return True diff --git a/src/cryptography/other_accounts.py b/src/cryptography/other_accounts.py index ed9368c..aa6b607 100644 --- a/src/cryptography/other_accounts.py +++ b/src/cryptography/other_accounts.py @@ -1,6 +1,5 @@ import base64 - -import bcrypt +import os from cryptography.fernet import Fernet from cryptography.hazmat.backends import default_backend @@ -25,7 +24,7 @@ def encrypt_account_info( ) -> tuple[bytes, bytes, bytes]: """Encrypts login and password of a user using their master password as a key. Returns a tuple of encrypted login, password and salt""" - salt = bcrypt.gensalt() + salt = os.urandom(64) key = _generate_key(salt, master_pass) f = Fernet(key) enc_login = f.encrypt(login.encode("utf-8")) diff --git a/src/database/models.py b/src/database/models.py index a483fbd..a6972fb 100644 --- a/src/database/models.py +++ b/src/database/models.py @@ -8,10 +8,10 @@ class MasterPass(sqlmodel.SQLModel, table=True): id: Optional[int] = sqlmodel.Field(primary_key=True) user_id: int = sqlmodel.Field(nullable=False, index=True, unique=True) salt: bytes = sqlmodel.Field( - sa_column=sqlmodel.Column(sqlmodel.VARBINARY(255), nullable=False) + sa_column=sqlmodel.Column(sqlmodel.BINARY(64), nullable=False) ) passwd: bytes = sqlmodel.Field( - sa_column=sqlmodel.Column(sqlmodel.VARBINARY(255), nullable=False) + sa_column=sqlmodel.Column(sqlmodel.BINARY(128), nullable=False) ) @@ -22,11 +22,11 @@ class Account(sqlmodel.SQLModel, table=True): user_id: int = sqlmodel.Field(nullable=False, index=True) name: str = sqlmodel.Field(nullable=False, index=True, max_length=255) salt: bytes = sqlmodel.Field( - sa_column=sqlmodel.Column(sqlmodel.VARBINARY(255), nullable=False) + sa_column=sqlmodel.Column(sqlmodel.BINARY(64), nullable=False) ) enc_login: bytes = sqlmodel.Field( - sa_column=sqlmodel.Column(sqlmodel.VARBINARY(255), nullable=False) + sa_column=sqlmodel.Column(sqlmodel.VARBINARY(500), nullable=False) ) enc_pass: bytes = sqlmodel.Field( - sa_column=sqlmodel.Column(sqlmodel.VARBINARY(255), nullable=False) + sa_column=sqlmodel.Column(sqlmodel.VARBINARY(500), nullable=False) )