Core Idea of AES
AES (Advanced Encryption Standard) is a symmetric block cipher — meaning the same key is used for both encryption and decryption. It is the most widely used encryption algorithm today and is the official U.S. government standard (FIPS 197) for protecting sensitive but unclassified data.
Key points:
- It operates on fixed-size 128-bit blocks of data (16 bytes).
- It supports three key sizes: 128, 192, or 256 bits.
- AES-128 uses a 128-bit key, AES-256 uses a 256-bit key.
- The algorithm is the same for all key sizes; the only differences are the key length and the number of rounds (iterations) it performs.
Why the different key sizes?
- Larger keys provide higher security against brute-force attacks.
- AES-128 is considered secure for most applications today (no practical attacks exist).
- AES-256 is used when regulations or policies require “higher assurance” (e.g., some government or financial systems, or when protecting data for decades into the future).
How AES Works (High-Level)
AES encrypts a 128-bit block through a series of rounds. Each round applies four transformations:
- SubBytes – Non-linear substitution: each byte is replaced using a fixed lookup table (S-box). This provides confusion.
- ShiftRows – Bytes in each row of the 4×4 state matrix are cyclically shifted left. This spreads data across the block (diffusion).
- MixColumns – Each column is multiplied by a fixed matrix over GF(2⁸). Further diffusion.
- AddRoundKey – The round key (derived from the main key) is XORed with the state.
The process:
- An initial AddRoundKey with the original key.
- Then Nr-1 full rounds (all four steps).
- A final round with no MixColumns.
Number of rounds (Nr):
- AES-128 → 10 rounds
- AES-192 → 12 rounds
- AES-256 → 14 rounds
Key expansion: The original key is expanded into a set of round keys (one per round) using a key schedule algorithm.
Modes of operation (important in practice):
AES by itself only encrypts one 128-bit block. To encrypt larger messages securely, we use modes like:
- CBC (legacy, needs padding and IV)
- CTR (turns AES into a stream cipher)
- GCM (Galois/Counter Mode) – most common today: provides both confidentiality and authenticated encryption (integrity + authenticity).
Security Summary
- No practical break of AES exists (as of 2026).
- Best known attacks are theoretical and reduce the effective security only marginally.
- AES-128 offers ~128 bits of security.
- AES-256 offers ~256 bits (overkill for most threats except quantum computers in the distant future).
In your domain (identity/credentials/certificates):
- AES is frequently used to encrypt private keys in keystores, protect credential databases, or encrypt data at rest.
- In protocols like TLS, AES-GCM is the dominant cipher suite.
- Many credential formats (e.g., encrypted JWTs, password vaults, secure enclaves) rely on AES.
Practical Part
Here’s a short, real-world Python example using the widely available cryptography library (the de-facto standard in Python for secure crypto). It shows AES-128-GCM and AES-256-GCM encryption/decryption of a simple message.
from os import urandom
from cryptography.hazmat.primitives.ciphers.aead import AESGCM
def encrypt_aes(key_bit_size: int, plaintext: bytes) -> bytes:
# Generate a random 128-bit (16-byte) nonce (IV) - required for GCM
nonce = urandom(12)
# Key size determines AES-128 or AES-256
key = urandom(key_bit_size // 8) # 16 bytes for 128-bit, 32 bytes for 256-bit
aesgcm = AESGCM(key)
ciphertext = aesgcm.encrypt(nonce, plaintext, associated_data=None)
# Return nonce + ciphertext (common format)
return nonce + ciphertext
def decrypt_aes(key_bit_size: int, key: bytes, data: bytes):
nonce = data[:12]
ciphertext = data[12:]
aesgcm = AESGCM(key)
plaintext = aesgcm.decrypt(nonce, ciphertext, associated_data=None)
return plaintext
# Example usage
message = b"Secret credential data"
# AES-128-GCM
ct_128 = encrypt_aes(128, message)
print("AES-128 ciphertext length:", len(ct_128))
# AES-256-GCM
ct_256 = encrypt_aes(256, message)
print("AES-256 ciphertext length:", len(ct_256))
# To decrypt, you need the exact same key used for encryption
# (In real code you would securely store/load the key)
Key observations:
- Ciphertext length = nonce (12 bytes) + plaintext length + 16-byte authentication tag.
- Changing just one bit in the key or nonce produces completely different ciphertext.
- Never reuse nonce with the same key (GCM requirement).
Try running this snippet locally (install with pip install cryptography). It’s only ~30 lines and gives you immediate hands-on feel for the difference between AES-128 and AES-256 in practice.
pics wikipedia:

c github:
