Symmetric encryption protects confidentiality with one shared key. Use authenticated encryption (AES-GCM) so data is both secret and tamper-evident, and handle nonces and keys correctly — the parts that actually break.
Symmetric encryption uses the same key to encrypt and decrypt. It is fast and ideal for bulk data (files, database fields, disk). Its two hard problems are key distribution (how do both sides get the key without an eavesdropper seeing it?) and key management (storing and rotating keys safely). Asymmetric crypto, next lesson, exists largely to solve the distribution problem.
same key K
plaintext --[encrypt K]--> ciphertext --[decrypt K]--> plaintext
Great for: bulk data — disk/db encryption, files, sessions. Fast.
The two hard parts (not the math — the logistics):
distribution both parties need K without an eavesdropper getting it
-> solved with asymmetric key exchange (next lesson)
management where does K live? how is it rotated? -> a KMS
(see the Cloud Security course's envelope encryption)Plain encryption hides data but does not detect tampering — an attacker can flip ciphertext bits and you would decrypt garbage without knowing. Authenticated encryption (AEAD) like AES-GCM or ChaCha20-Poly1305 provides confidentiality and integrity together: decryption fails loudly if the ciphertext was modified. Always choose an AEAD mode; never plain CBC/ECB.
# pip install cryptography
import os
from cryptography.hazmat.primitives.ciphers.aead import AESGCM
key = AESGCM.generate_key(bit_length=256) # store this in a KMS, not code
aead = AESGCM(key)
nonce = os.urandom(12) # 96-bit, UNIQUE per encryption
ct = aead.encrypt(nonce, b"secret data", b"associated-context")
# decrypt: raises InvalidTag if the ciphertext OR the context was tampered with
pt = aead.decrypt(nonce, ct, b"associated-context")
# AES-GCM gives confidentiality + integrity in one step. Never use ECB
# (leaks patterns) or unauthenticated CBC (malleable).A nonce ("number used once") makes each encryption unique so identical plaintexts produce different ciphertexts. For AES-GCM this is critical: reusing a nonce with the same key catastrophically breaks the encryption, potentially revealing plaintext and the authentication key. Generate a fresh random nonce every time and store it next to the ciphertext (it is not secret).
Nonce = number used ONCE (per key). It's public, but must be UNIQUE.
reuse a (key, nonce) pair in AES-GCM -> catastrophic:
- XOR of two plaintexts leaks
- the GCM auth key can be recovered -> forgery
This is a real class of breaks (e.g. WEP, some misused libraries).
Do: os.urandom(12) fresh each time; store the nonce alongside ciphertext.
Don't: a counter you might reset, or a fixed nonce "for simplicity".Encryption only moves the secret from the data to the key — so protecting the key is the real task. A key hardcoded in source or sitting next to the ciphertext gives an attacker both halves. Keep keys in a dedicated key manager (KMS, Vault), use envelope encryption so the master key never leaves it, and rotate on a schedule. This connects directly to the Cloud Security and Vault courses.
Encryption relocates the secret: from "the data" to "the key".
So the key must be better protected than the data was.
BAD key hardcoded in code / committed / stored next to ciphertext
-> attacker gets both -> encryption bought you nothing
GOOD key in a KMS / Vault; app calls it to encrypt/decrypt;
envelope encryption so the master key never leaves the KMS;
scheduled rotation; access is an IAM decision + audited
"How do we manage keys?" is the real question -> Cloud Security (KMS)
and the Vault course.