Authenticated encryption is about making sure your data is both secret and real.
Let’s see AES-GCM in action. Imagine we have a message, "Meet me at 3 PM", and a secret key.
from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes
from cryptography.hazmat.backends import default_backend
import os
key = os.urandom(32) # 256-bit key
nonce = os.urandom(12) # 96-bit nonce for GCM
# Message to encrypt
plaintext = b"Meet me at 3 PM"
# Additional authenticated data (AAD) - data that needs integrity but not confidentiality
aad = b"header_info"
# AES-GCM Cipher
cipher = Cipher(algorithms.AES(key), modes.GCM(nonce, aad), backend=default_backend())
encryptor = cipher.encryptor()
# Encrypt
ciphertext = encryptor.update(plaintext) + encryptor.finalize()
# Get the authentication tag
tag = encryptor.tag
print(f"Plaintext: {plaintext}")
print(f"Ciphertext: {ciphertext}")
print(f"Authentication Tag: {tag.hex()}")
# --- Decryption ---
decryptor = cipher.decryptor() # Re-initialize with the same key, nonce, and AAD
decryptor.authenticate_additional_data(aad) # Authenticate AAD first
decryptor.update(ciphertext) # Feed the ciphertext
plaintext_decrypted = decryptor.finalize_with_tag(tag) # Finalize and verify the tag
print(f"Decrypted Plaintext: {plaintext_decrypted}")
This code shows a symmetric encryption process using AES in Galois/Counter Mode (GCM). The key is the secret shared between parties. The nonce (number used once) is crucial for GCM; it must be unique for each encryption with the same key. plaintext is the data we want to protect. aad is interesting – it’s data that we want to ensure hasn’t been tampered with, but we don’t necessarily need to hide. Think of packet headers.
When we encrypt, AES-GCM produces ciphertext (the hidden data) and an authentication tag. This tag is the magic sauce for integrity. During decryption, the recipient uses the same key, nonce, and AAD, along with the ciphertext, to recompute the tag. If the recomputed tag matches the received tag, the data is considered authentic and confidential. If they don’t match, it means either the ciphertext or the AAD has been altered, and the decryption will fail.
The core problem AES-GCM solves is the separation of confidentiality (keeping data secret) and integrity (ensuring data hasn’t been tampered with). Before authenticated encryption, you’d often encrypt data (confidentiality) and then sign it separately (integrity). This was prone to errors, like encrypting then signing, which could allow an attacker to tamper with the ciphertext in ways that might be missed by the signature verification after decryption. Authenticated encryption modes like GCM combine these operations efficiently and securely. The GCM mode specifically uses a universal hash function (GHASH) over a finite field, combined with a counter mode (CTR) for encryption, to generate the authentication tag.
The nonce is the most critical parameter for GCM’s security. Reusing a nonce with the same key in GCM is catastrophic. It doesn’t just break confidentiality; it completely breaks the authentication mechanism, allowing an attacker to forge messages and recover the authentication key. This is why os.urandom(12) is used here to generate a fresh, random nonce for every encryption. The size of the nonce is also important; 96 bits is the recommended size for GCM, balancing security and efficiency.
The aad (Additional Authenticated Data) is a powerful feature. It allows you to protect the integrity of data that doesn’t need to be encrypted. For example, in TLS, the handshake messages or packet headers might be AAD. This data isn’t hidden, but any modification to it will cause the authentication tag verification to fail, preventing man-in-the-middle attacks that try to alter routing information or connection parameters.
The final authentication tag is derived from the ciphertext and the AAD using the GHASH function, which is based on polynomial multiplication in the finite field GF(2^128). This mathematical operation, when combined with the counter mode encryption, provides strong assurance against tampering.
A common misconception is that the tag is just a checksum. It’s far more robust. It’s a cryptographic commitment that ensures that any modification to the ciphertext or AAD will result in a tag mismatch with extremely high probability, making brute-force forgery infeasible.
The next step after understanding authenticated encryption is exploring different modes of authenticated encryption, like ChaCha20-Poly1305, and understanding how they compare in performance and security guarantees.