Switched to the ChaCha20Poly1305 encryption algorithm for better security

This commit is contained in:
StNicolay 2023-01-10 20:00:58 +03:00
parent 3686195396
commit c051c14f1f

View File

@ -1,17 +1,22 @@
import base64
import os import os
from typing import Self
from cryptography.fernet import Fernet
from cryptography.hazmat.backends import default_backend from cryptography.hazmat.backends import default_backend
from cryptography.hazmat.primitives import hashes from cryptography.hazmat.primitives import hashes
from cryptography.hazmat.primitives.ciphers.aead import ChaCha20Poly1305
from cryptography.hazmat.primitives.kdf.pbkdf2 import PBKDF2HMAC from cryptography.hazmat.primitives.kdf.pbkdf2 import PBKDF2HMAC
from ..db.models import Account from ..db.models import Account
from ..decrypted_account import DecryptedAccount from ..decrypted_account import DecryptedAccount
def _generate_key(salt: bytes, master_pass: bytes) -> bytes: class Cipher:
"""Generates key for fernet encryption""" def __init__(self, key: bytes) -> None:
self._chacha = ChaCha20Poly1305(key)
@classmethod
def generate_cipher(cls, salt: bytes, password: bytes) -> Self:
"""Generates cipher which uses key derived from a given password"""
kdf = PBKDF2HMAC( kdf = PBKDF2HMAC(
algorithm=hashes.SHA256(), algorithm=hashes.SHA256(),
length=32, length=32,
@ -19,8 +24,22 @@ def _generate_key(salt: bytes, master_pass: bytes) -> bytes:
iterations=100000, iterations=100000,
backend=default_backend(), backend=default_backend(),
) )
key = base64.urlsafe_b64encode(kdf.derive(master_pass)) return cls(kdf.derive(password))
return key
def encrypt(self, data: bytes) -> bytes:
nonce = os.urandom(12)
return nonce + self._chacha.encrypt(
nonce,
data,
associated_data=None,
)
def decrypt(self, data: bytes) -> bytes:
return self._chacha.decrypt(
nonce=data[:12],
data=data[12:],
associated_data=None,
)
def encrypt( def encrypt(
@ -29,15 +48,10 @@ def encrypt(
) -> Account: ) -> Account:
"""Encrypts account using master password and returns Account object""" """Encrypts account using master password and returns Account object"""
salt = os.urandom(64) salt = os.urandom(64)
key = _generate_key(salt, master_pass.encode("utf-8")) cipher = Cipher.generate_cipher(salt, master_pass.encode("utf-8"))
f = Fernet(key)
enc_login = base64.urlsafe_b64decode( enc_login = cipher.encrypt(account.login.encode("utf-8"))
f.encrypt(account.login.encode("utf-8")), enc_password = cipher.encrypt(account.password.encode("utf-8"))
)
enc_password = base64.urlsafe_b64decode(
f.encrypt(account.password.encode("utf-8")),
)
return Account( return Account(
user_id=account.user_id, user_id=account.user_id,
@ -54,15 +68,10 @@ def decrypt(
) -> DecryptedAccount: ) -> DecryptedAccount:
"""Decrypts account using master password and returns """Decrypts account using master password and returns
DecryptedAccount object""" DecryptedAccount object"""
key = _generate_key(account.salt, master_pass.encode("utf-8")) cipher = Cipher.generate_cipher(account.salt, master_pass.encode("utf-8"))
f = Fernet(key)
login = f.decrypt( login = cipher.decrypt(account.enc_login).decode("utf-8")
base64.urlsafe_b64encode(account.enc_login), password = cipher.decrypt(account.enc_password).decode("utf-8")
).decode("utf-8")
password = f.decrypt(
base64.urlsafe_b64encode(account.enc_password),
).decode("utf-8")
return DecryptedAccount( return DecryptedAccount(
user_id=account.user_id, user_id=account.user_id,