Python AES Encrypt With Fernet

2024-02-01

筆記如何使用 Python Fernet 對稱式進行資料加解密,以及搭配 PBKDF2HMAC 的方式,使用密碼加密 Fernet 的金鑰。

logo

說明

前置作業需要先使用 pip 安裝 library:

pip install pycryptodome

generateKey.py

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
import os
import base64

def generate_save_key(password, file_path="encrypted_key.bin"):
    fernet_key = Fernet.generate_key()
    
    salt = os.urandom(16)
    
    kdf = PBKDF2HMAC(
        algorithm=hashes.SHA512(),
        length=32,
        salt=salt,
        iterations=100000,
        backend=default_backend()
    )
    key = base64.urlsafe_b64encode(kdf.derive(password.encode()))
    
    cipher = Fernet(key)
    encrypted_fernet_key = cipher.encrypt(fernet_key)
    
    with open(file_path, "wb") as file:
        file.write(salt + encrypted_fernet_key)

接著就可以建立 key file:

password = "12345678"
file_path = "encrypted_key.bin"
generate_save_key(password, file_path)

loadKey.py

def load_key(password, file_path="encrypted_key.bin"):
    with open(file_path, "rb") as file:
        salt = file.read(16)
        encrypted_fernet_key = file.read()
    
    kdf = PBKDF2HMAC(
        algorithm=hashes.SHA512(),
        length=32,
        salt=salt,
        iterations=100000,
        backend=default_backend()
    )
    key = base64.urlsafe_b64encode(kdf.derive(password.encode()))
    
    cipher = Fernet(key)
    fernet_key = cipher.decrypt(encrypted_fernet_key)
    return fernet_key

可以透過以下的方式,讓使用者輸入密碼取回真正的 Fernet key:

password = input('please input password:')
fernet_key = load_key(password, 'encrypted_key.bin')

EncryptDecrypt.py

藉由取回的 Fernet key,可以搭配 Fernet 物件來進行加解密的操作,加密的資料必須是 Binary 所以加密前必須進行 Encode,解密的資料則必須透過 Decode 的方式還原為原本的內容。

def encrypt(data, fernet_key):
    cipher = Fernet(fernet_key)
    return cipher.encrypt(data.encode())

def decrypt(encrypted_data, fernet_key):
    cipher = Fernet(fernet_key)
    return cipher.decrypt(encrypted_data).decode()

main.py

with open('business.txt', 'r', encoding='utf8') as f:
    data_to_encrypt = '\n'.join(f.readlines())
    
encrypted_data = encrypt(data_to_encrypt, fernet_key)

with open('encrypted_text.bin', 'wb') as f:
    f.write(encrypted_data)
    print(f"Encrypted: {encrypted_data}")

以上示範如何將文字檔的內容讀取,並且藉由 Fernet 加密後另存為 encrypted_text.bin

with open('encrypted_text.bin', 'rb') as f:
    encrypted_data = f.read()
    
decrypted_data = decrypt(encrypted_data, fernet_key)
print(f"Decrypted: {decrypted_data}")

以上示範如何讀取 encrypted_text.bin 並且解密回原本的內容。