Skip to content

crypt

Functions for cryptography.

create_fernet_key

create_fernet_key(password: str, salt: bytes) -> bytes

Create a Fernet key.

Source code in src/envers/crypt.py
21
22
23
24
25
26
27
28
29
30
31
def create_fernet_key(password: str, salt: bytes) -> bytes:
    """Create a Fernet key."""
    # Use PBKDF2HMAC to derive a Fernet-compatible key from the user password
    kdf = PBKDF2HMAC(
        algorithm=hashes.SHA256(),
        length=32,
        salt=salt,
        iterations=100000,
        backend=default_backend(),
    )
    return base64.urlsafe_b64encode(kdf.derive(password.encode("utf-8")))

decrypt_data

decrypt_data(data: str, password: Optional[str] = None) -> str

Decrypt the given data.

Source code in src/envers/crypt.py
65
66
67
68
69
70
71
72
73
74
75
76
77
78
def decrypt_data(data: str, password: Optional[str] = None) -> str:
    """Decrypt the given data."""
    if password is None:
        password = get_password()

    HEX_SALT_LENGTH = SALT_LENGTH * 2

    salt_hex, data_clean = data[:HEX_SALT_LENGTH], data[HEX_SALT_LENGTH:]
    salt = bytes.fromhex(salt_hex)

    key = create_fernet_key(password, salt)
    cipher_suite = Fernet(key)

    return cipher_suite.decrypt(data_clean.encode("utf-8")).decode("utf-8")

encrypt_data

encrypt_data(data: str, password: Optional[str] = None) -> str

Encrypt the given data.

Source code in src/envers/crypt.py
51
52
53
54
55
56
57
58
59
60
61
62
def encrypt_data(data: str, password: Optional[str] = None) -> str:
    """Encrypt the given data."""
    if password is None:
        password = get_password()

    salt = generate_salt()
    salt_hex = salt.hex()
    key = create_fernet_key(password, salt)
    cipher_suite = Fernet(key)

    encrypted = cipher_suite.encrypt(data.encode("utf-8")).decode("utf-8")
    return salt_hex + encrypted

generate_salt

generate_salt() -> bytes

Generate a salt in byte format.

Source code in src/envers/crypt.py
46
47
48
def generate_salt() -> bytes:
    """Generate a salt in byte format."""
    return os.urandom(SALT_LENGTH)

get_password

get_password(message: str = '') -> str

Prompt a password.

Source code in src/envers/crypt.py
34
35
36
37
38
39
40
41
42
43
def get_password(message: str = "") -> str:
    """Prompt a password."""
    if sys.stdin.isatty():
        # Interactive mode: Use Typer's prompt
        message = "Enter your password" if not message else message
        password = cast(str, typer.prompt(message, hide_input=True))
    else:
        # Non-interactive mode: Read from stdin
        password = sys.stdin.readline().rstrip()
    return password