70 lines
2.2 KiB
Python
70 lines
2.2 KiB
Python
import base64
|
|
import os
|
|
from typing import Iterator
|
|
|
|
from cryptography.fernet import Fernet
|
|
from cryptography.hazmat.backends import default_backend
|
|
from cryptography.hazmat.primitives import hashes
|
|
from cryptography.hazmat.primitives.kdf.pbkdf2 import PBKDF2HMAC
|
|
|
|
|
|
def _generate_key(salt: bytes, master_pass: bytes) -> bytes:
|
|
kdf = PBKDF2HMAC(
|
|
algorithm=hashes.SHA256(),
|
|
length=32,
|
|
salt=salt,
|
|
iterations=100000,
|
|
backend=default_backend(),
|
|
)
|
|
key = base64.urlsafe_b64encode(kdf.derive(master_pass))
|
|
return key
|
|
|
|
|
|
def encrypt(
|
|
login: str,
|
|
passwd: str,
|
|
master_pass: str,
|
|
) -> 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 = os.urandom(64)
|
|
key = _generate_key(salt, master_pass.encode("utf-8"))
|
|
f = Fernet(key)
|
|
enc_login = base64.urlsafe_b64decode(f.encrypt(login.encode("utf-8")))
|
|
enc_password = base64.urlsafe_b64decode(f.encrypt(passwd.encode("utf-8")))
|
|
return (enc_login, enc_password, salt)
|
|
|
|
|
|
def decrypt(
|
|
enc_login: bytes,
|
|
enc_pass: bytes,
|
|
master_pass: str,
|
|
salt: bytes,
|
|
) -> tuple[str, str]:
|
|
"""Decrypts login and password using their
|
|
master password as a key.
|
|
Returns a tuple of decrypted login and password"""
|
|
key = _generate_key(salt, master_pass.encode("utf-8"))
|
|
f = Fernet(key)
|
|
login = f.decrypt(base64.urlsafe_b64encode(enc_login)).decode("utf-8")
|
|
password = f.decrypt(base64.urlsafe_b64encode(enc_pass)).decode("utf-8")
|
|
return (login, password)
|
|
|
|
|
|
def decrypt_multiple(
|
|
accounts: Iterator[tuple[str, bytes, bytes, bytes]], master_pass: str
|
|
) -> Iterator[tuple[str, str, str]]:
|
|
"""Gets an iterator of tuples, where values represent account's name, salt,
|
|
encrypted login and encrypted password.
|
|
Return an iterator of names, logins and passwords as a tuple"""
|
|
for account in accounts:
|
|
name, salt, enc_login, enc_passwd = account
|
|
login, passwd = decrypt(
|
|
enc_login,
|
|
enc_passwd,
|
|
master_pass,
|
|
salt,
|
|
)
|
|
yield (name, login, passwd)
|