Day 1 of 5
⏱ ~60 minutes
Cryptography in 5 Days — Day 1

Symmetric Encryption

Symmetric encryption uses the same key to encrypt and decrypt. It is the fastest form of encryption and protects data at rest and in bulk data transfer. Today you master AES, understand modes of operation, and learn why key management is often harder than the crypto itself.

AES: The Global Standard

The Advanced Encryption Standard (AES) was selected by NIST in 2001 after an open international competition. It is a block cipher operating on 128-bit blocks with key sizes of 128, 192, or 256 bits. AES-256 has never been broken. It is used in TLS, disk encryption (BitLocker, FileVault, LUKS), and virtually every secure protocol. The NSA approves AES-256 for TOP SECRET data.

Modes of Operation

A mode of operation defines how AES handles data longer than 128 bits. ECB (Electronic Codebook) encrypts each block independently — identical plaintext blocks produce identical ciphertext, leaking patterns. CBC (Cipher Block Chaining) XORs each block with the previous ciphertext, hiding patterns. GCM (Galois/Counter Mode) provides authenticated encryption — it detects tampering. Always use AES-GCM or AES-CBC with HMAC.

Key Management

Strong crypto fails with weak key management. Keys must be generated with a cryptographically secure random number generator (CSPRNG), never hardcoded in source code, stored in a key management system (AWS KMS, HashiCorp Vault), rotated regularly, and destroyed securely when retired. The most common crypto failure in real systems is poor key management, not weak algorithms.

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

def encrypt(key: bytes, plaintext: bytes, aad: bytes = b'') -> tuple:
    # GCM provides authenticated encryption
    # Returns: (nonce, ciphertext+tag)
    aesgcm = AESGCM(key)
    nonce = os.urandom(12)  # 96-bit nonce for GCM
    ct = aesgcm.encrypt(nonce, plaintext, aad)
    return nonce, ct

def decrypt(key: bytes, nonce: bytes, ct: bytes, aad: bytes = b'') -> bytes:
    aesgcm = AESGCM(key)
    # Raises InvalidTag if ciphertext was tampered with
    return aesgcm.decrypt(nonce, ct, aad)

# Example usage
key = AESGCM.generate_key(bit_length=256)
message = b'Secret message for Precision AI Academy'

nonce, ciphertext = encrypt(key, message)
print(f'Ciphertext: {ciphertext.hex()[:32]}...')

recovered = decrypt(key, nonce, ciphertext)
print(f'Decrypted: {recovered.decode()}')
💡
Never reuse a nonce with the same key in AES-GCM. Nonce reuse with the same key breaks GCM's authentication and leaks the keystream. Generate a new random nonce for every encryption operation.
📝 Day 1 Exercise
Build a File Encryption Tool
  1. Install the cryptography library: pip install cryptography
  2. Write a CLI tool that encrypts a file with AES-256-GCM using a random key
  3. Save the key, nonce, and ciphertext to separate files
  4. Write the decryption function and verify you can recover the original file
  5. Add HMAC authentication to detect file tampering before decryption

Day 1 Summary

  • AES-256 is the global standard for symmetric encryption — never broken
  • ECB mode leaks patterns; always use GCM or CBC+HMAC
  • GCM provides authenticated encryption: it detects tampering automatically
  • Key management is often the weakest link, not the algorithm
  • Generate a fresh random nonce for every AES-GCM encryption operation
Challenge

Demonstrate the ECB mode weakness by encrypting a bitmap image with AES-ECB and AES-CBC. The ECB version will reveal the image structure in the ciphertext. Post the two encrypted images side-by-side.

Finished this lesson?