Note
Go to the end to download the full example code.
File encryption and decryption utilitiesΒΆ
Simple functions to encrypt and decrypt files.
It uses Fernet symmetric encryption scheme from the cryptography library.
A password is transformed into a Fernet-compatible key using SHA-256. Note: this is a simplified key-derivation method and is not as secure as PBKDF2HMAC or scrypt for real-world applications.
import base64
import hashlib
import os
import pathlib
import tempfile
from cryptography.fernet import Fernet
# -------------------------------------------------------------------------
# Key generation
# -------------------------------------------------------------------------
def generate_key(password: str) -> bytes:
"""
Generate a Fernet-compatible key from a password using SHA-256.
This function hashes the password twice with SHA-256 and encodes the
result in URL-safe Base64, as required by Fernet.
Parameters
----------
password : str
The password used to derive the encryption key.
Returns
-------
bytes
A 32-byte Base64-encoded key suitable for Fernet.
Notes
-----
This is a simplified key derivation function. For stronger security,
consider using PBKDF2HMAC with a salt and many iterations.
"""
digest = hashlib.sha256(password.encode()).digest()
return base64.urlsafe_b64encode(hashlib.sha256(digest).digest())
# -------------------------------------------------------------------------
# File encryption
# -------------------------------------------------------------------------
def encrypt_file(file_path: str, key: bytes):
"""
Encrypt a file in place using the Fernet algorithm.
The file is read entirely into memory, encrypted, and then overwritten
with the encrypted content.
Parameters
----------
file_path : str
Path to the file to encrypt.
key : bytes
A Fernet key generated by `generate_key()`.
Returns
-------
Fernet
The Fernet instance used for encryption.
Notes
-----
- The original file content is overwritten and cannot be recovered
without the correct key.
- If you need to preserve the original file, copy it before encrypting.
"""
fernet = Fernet(key)
original = pathlib.Path(file_path).read_bytes()
encrypted = fernet.encrypt(original)
pathlib.Path(file_path).write_bytes(encrypted)
return fernet
# -------------------------------------------------------------------------
# File decryption
# -------------------------------------------------------------------------
def decrypt_file(file_path: str, key: bytes):
"""
Decrypt a file in place using the Fernet algorithm.
The file is read entirely into memory, decrypted, and then overwritten
with the decrypted content.
Parameters
----------
file_path : str
Path to the file to decrypt.
key : bytes
A Fernet key generated by `generate_key()`.
Returns
-------
None
Notes
-----
- If the key is invalid, the function prints an error and leaves the
encrypted file unchanged.
- The decrypted content overwrites the encrypted file.
"""
encrypted = pathlib.Path(file_path).read_bytes()
fernet = Fernet(key)
try:
decrypted = fernet.decrypt(encrypted)
except Exception:
print("Error: invalid key. File was not decrypted.")
return
pathlib.Path(file_path).write_bytes(decrypted)
Example usage of the encryption functions
# 1. Create a temporary file with known content
original_content = b"Hello, this is a test message."
with tempfile.NamedTemporaryFile(delete=False) as tmp:
file_path = tmp.name
tmp.write(original_content)
print(f"Temporary file created at: {file_path}")
# 2. Generate a key from a password
password = "my_password"
key = generate_key(password)
# 3. Encrypt the file
encrypt_file(file_path, key)
print("File encrypted.")
# 4. Decrypt the file
decrypt_file(file_path, key)
print("File decrypted.")
# 5. Read back the content and verify equality
final_content = pathlib.Path(file_path).read_bytes()
if final_content == original_content:
print("Success: decrypted content matches the original.")
else:
print("Error: decrypted content does NOT match the original.")
# 6. Clean up
os.remove(file_path)
Temporary file created at: /tmp/tmp5289r_25
File encrypted.
File decrypted.
Success: decrypted content matches the original.
Total running time of the script: (0 minutes 0.246 seconds)
Estimated memory usage: 118 MB