New in 2026: Master Python for AI, Data Science

ProgrammingPython

A Developer’s Guide to End-to-End Encryption in Python (Part 2 of 5)

Developer implementing AES symmetric encryption in Python with code snippets and security concepts illustrated

In Part 1, we explored what end-to-end encryption is and why it matters. We also covered the basics of symmetric and asymmetric encryption. Now, we’ll focus on symmetric encryption — specifically using the AES algorithm — and implement it safely and effectively in Python.

Symmetric encryption uses the same secret key to both encrypt and decrypt data. It is fast and efficient, making it perfect for encrypting large messages or files. However, secure key management and correct usage of cryptographic primitives are critical.

Why AES?

AES (Advanced Encryption Standard) is the industry standard symmetric cipher. It is secure, widely supported, and implemented in hardware to optimize speed. AES can work in different modes; for secure encryption you should prefer authenticated modes like GCM (Galois/Counter Mode).

Getting Started: Installing the Cryptography Library

pip install cryptography

This library provides a high-level interface to AES and many other cryptographic functions.

Encrypting and Decrypting with AES-GCM

Here’s a simple example demonstrating how to encrypt and decrypt a message using AES in GCM mode.

from cryptography.hazmat.primitives.ciphers.aead import AESGCM
import os

def encrypt_message(key: bytes, plaintext: bytes, associated_data: bytes = None):
# Generate a random 12-byte nonce (number used once)
nonce = os.urandom(12)

aesgcm = AESGCM(key)
# Encrypt the data, applying optional authenticated data
ciphertext = aesgcm.encrypt(nonce, plaintext, associated_data)
return nonce, ciphertext

def decrypt_message(key: bytes, nonce: bytes, ciphertext: bytes, associated_data: bytes = None):
aesgcm = AESGCM(key)
plaintext = aesgcm.decrypt(nonce, ciphertext, associated_data)
return plaintext

# Generate a secure 256-bit (32 bytes) key — share this key securely!
key = AESGCM.generate_key(bit_length=256)

message = b"Hello, this is a secret message!"
aad = b"metadata-or-associated-data" # Optional but recommended for data integrity

nonce, encrypted = encrypt_message(key, message, aad)
print(f"Nonce: {nonce.hex()}")
print(f"Encrypted: {encrypted.hex()}")

decrypted = decrypt_message(key, nonce, encrypted, aad)
print(f"Decrypted: {decrypted.decode()}")

Explanation:

  • Key: Should be a securely generated 32-byte random value.
  • Nonce: A unique random number per encryption operation; never reuse the same nonce with the same key.
  • Associated Data (AAD): Optional data you want to authenticate (e.g., headers). It is not encrypted but will trigger authentication failure if altered.
  • AESGCM.encrypt(): Returns ciphertext concatenated with the authentication tag.
  • AESGCM.decrypt(): Verifies the tag and decrypts.

Important Security Notes

  • Never reuse nonces with the same key. This compromises security drastically.
  • Store or transmit the nonce with the ciphertext (it’s not secret).
  • Use a secure key exchange mechanism (asymmetric encryption) to share the AES key safely.
  • Use authenticated encryption modes (e.g., GCM, ChaCha20-Poly1305) to ensure integrity and authenticity.
  • Avoid ECB mode — it’s insecure and leaks patterns.

Encrypting Files Safely

Many use cases involve encrypting files rather than strings. Here is a simple way to encrypt and decrypt files with AES-GCM:

def encrypt_file(key: bytes, in_filename: str, out_filename: str):
nonce = os.urandom(12)
aesgcm = AESGCM(key)

with open(in_filename, 'rb') as f:
data = f.read()

encrypted_data = aesgcm.encrypt(nonce, data, None)

with open(out_filename, 'wb') as f:
# Write nonce + ciphertext
f.write(nonce + encrypted_data)

def decrypt_file(key: bytes, in_filename: str, out_filename: str):
aesgcm = AESGCM(key)

with open(in_filename, 'rb') as f:
nonce = f.read(12)
ciphertext = f.read()

decrypted_data = aesgcm.decrypt(nonce, ciphertext, None)

with open(out_filename, 'wb') as f:
f.write(decrypted_data)

# Usage example
key = AESGCM.generate_key(bit_length=256)
encrypt_file(key, 'secret.pdf', 'secret_encrypted.bin')
decrypt_file(key, 'secret_encrypted.bin', 'secret_decrypted.pdf')

Key Management: What You Need to Know

  • Never hardcode keys in your source code.
  • Store keys in secure vaults or environment variables.
  • Use proper key exchange protocols (covered in Part 3).
  • Rotate keys periodically for long-lived data.

Summary

  • Symmetric encryption is the backbone of E2EE for fast, bulk data encryption.
  • AES-GCM ensures both confidentiality and integrity.
  • Secure key and nonce management is critical.
  • Python’s cryptography library offers a clean, effective AES API.

What’s Next?

In Part 3, we will implement asymmetric encryption with RSA and elliptic curve cryptography. You’ll learn how to generate key pairs and encrypt messages securely for key exchange and digital signatures.

Try It Yourself

pip install cryptography

Copy the code snippets above, experiment with encrypting and decrypting messages or files, and observe what happens if you reuse a nonce or tamper with ciphertext.

Feel free to ask questions or share your experience in the comments!

Useful Links

ResourceURLDescription
Cryptography Library Docshttps://cryptography.io/en/latest/Official documentation for the Python cryptography library.
AES-GCM Specificationhttps://nvlpubs.nist.gov/nistpubs/Legacy/SP/nistspecialpublication800-38d.pdfNIST documentation on AES-GCM mode (standard reference).
PyNaCl Libraryhttps://pynacl.readthedocs.io/en/latest/Python binding for the NaCl cryptography library.
PyCryptodome Libraryhttps://pycryptodome.readthedocs.io/en/latest/Alternative Python crypto library with AES support.
OWASP Cryptographic Storagehttps://cheatsheetseries.owasp.org/cheatsheets/Cryptographic_Storage_Cheat_Sheet.htmlBest practices for cryptographic storage from OWASP.
Python Official Documentationhttps://docs.python.org/3/library/os.htmlFor generating cryptographically strong random numbers.

More Links

Related posts
Python

Pydantic Agent Basics: A Complete 2026 Tutorial

ProgrammingPython

Production-Ready MCP Servers — Security, Testing & Deployment

ProgrammingPython

Build Your First MCP Server with Python SDK — Fundamentals

ProgrammingPython

Connect FastAPI to MCP — Two Integration Patterns

Leave a Reply