Use cases
- Password based encryption of a file
- Previously shared common secret (password)
Installation
Install cryptography
with pip
: pip install cryptorgraphy
Supported Python versions
- Python 2.7
- Python 3.6
- Python 3.7
Example Code for Python based symmetric file encryption using AES-GCM and PBKDF2
import logging
import os
from random import SystemRandom
from cryptography.exceptions import AlreadyFinalized
from cryptography.exceptions import InvalidTag
from cryptography.exceptions import UnsupportedAlgorithm
from cryptography.hazmat.backends import default_backend
from cryptography.hazmat.primitives import hashes
from cryptography.hazmat.primitives.ciphers.aead import AESGCM
from cryptography.hazmat.primitives.kdf.pbkdf2 import PBKDF2HMAC
# set up logger
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)
def demonstrate_file_encryption_password_based(plain_text_file_name, password=""):
"""
Example for encryption and decryption of a file in one method.
- Random password generation using strong secure random number generator
- Random salt generation using OS random mode
- Key derivation using PBKDF2 HMAC SHA-512
- AES-256 authenticated encryption using GCM
- UTF-8 encoding of Strings
- Exception handling
"""
with open(plain_text_file_name, 'r') as plain_text_file:
plain_text = plain_text_file.read()
try:
# GENERATE password (not needed if you have a password already)
if not password:
alphabet = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
password = "".join(SystemRandom().choice(alphabet) for _ in range(40))
password_bytes = password.encode('utf-8')
# GENERATE random salt (needed for PBKDF2HMAC)
salt = os.urandom(64)
# DERIVE key (from password and salt)
kdf = PBKDF2HMAC(
algorithm=hashes.SHA512(),
length=32,
salt=salt,
iterations=10000,
backend=default_backend()
)
key = kdf.derive(password_bytes)
# GENERATE random nonce (number used once)
nonce = os.urandom(12)
# ENCRYPTION
aesgcm = AESGCM(key)
cipher_text_bytes = aesgcm.encrypt(
nonce=nonce,
data=plain_text.encode('utf-8'),
associated_data=None
)
# WRITE to file
with open("res/encrypted_file.enc", 'wb') as encrypted_file:
encrypted_file.write(cipher_text_bytes)
# READ from file
with open("res/encrypted_file.enc", 'rb') as encrypted_file:
cipher_file_content = encrypted_file.read()
# DECRYPTION
decrypted_cipher_text_bytes = aesgcm.decrypt(
nonce=nonce,
data=cipher_file_content,
associated_data=None
)
decrypted_cipher_text = decrypted_cipher_text_bytes.decode('utf-8')
logger.info("Decrypted and original plain text are the same: %s",
decrypted_cipher_text == plain_text)
except (UnsupportedAlgorithm, AlreadyFinalized, InvalidTag):
logger.exception("Symmetric file encryption failed")
if __name__ == '__main__':
# demonstrate method
demonstrate_file_encryption_password_based("res/plain_text_file.txt", "")
References
- Cryptography AEAD Documentation - AESGCM
- Cryptography Password Based Key Derivation Function 2 Documentation