AES (Advanced Encryption Standard)
Description
The Advanced Encryption Standard (AES) is a symmetric block cipher chosen by the U.S. National Institute of Standards and Technology (NIST) in 2001. It is widely used worldwide and has become the de facto standard for secure data encryption.
- Processes data in 128-bit blocks
- Supports key lengths of 128, 192, and 256 bits
- Uses substitution-permutation network
- Performs multiple rounds of transformation
History

AES, originally named Rijndael, was developed by two Belgian cryptographers, Joan Daemen and Vincent Rijmen. It was submitted to the AES selection process initiated by NIST in 1997 when they realized that DES (Data Encryption Standard) was becoming vulnerable.
After a five-year standardization process with fifteen competing designs, Rijndael was selected as the winner and became the Advanced Encryption Standard in 2001. The algorithm's combination of security, performance, efficiency, and flexibility made it the standout choice.
Today, AES is used by various organizations worldwide, including the U.S. National Security Agency (NSA) for protecting top secret information.
How It Works
- Key Expansion
- Original key is expanded into a key schedule
- Generates unique round keys for each transformation round
- Initial Round
- AddRoundKey - XOR the state with the round key
- Main Rounds (9, 11, or 13 rounds depending on key size)
- SubBytes - Non-linear substitution of bytes
- ShiftRows - Cyclic shifting of rows
- MixColumns - Linear mixing operation
- AddRoundKey - XOR with round key
- Final Round
- SubBytes
- ShiftRows
- AddRoundKey
Visualization
State Matrix
Click Start to begin AES encryption
Implementation
from Crypto.Cipher import AES
from Crypto.Random import get_random_bytes
def encrypt_aes(plaintext: bytes, key: bytes) -> tuple[bytes, bytes]:
"""
Encrypt data using AES in CBC mode with a random IV
"""
cipher = AES.new(key, AES.MODE_CBC)
ciphertext = cipher.encrypt(pad(plaintext))
return cipher.iv, ciphertext
def decrypt_aes(iv: bytes, ciphertext: bytes, key: bytes) -> bytes:
"""
Decrypt AES-encrypted data
"""
cipher = AES.new(key, AES.MODE_CBC, iv)
plaintext = unpad(cipher.decrypt(ciphertext))
return plaintext
def pad(data: bytes) -> bytes:
"""
Pad data to be multiple of 16 bytes (AES block size)
"""
padding_length = 16 - (len(data) % 16)
padding = bytes([padding_length] * padding_length)
return data + padding
def unpad(data: bytes) -> bytes:
"""
Remove PKCS7 padding
"""
padding_length = data[-1]
return data[:-padding_length]
# Example usage
key = get_random_bytes(32) # 256-bit key
message = b"Hello, AES!"
# Encrypt
iv, encrypted = encrypt_aes(message, key)
# Decrypt
decrypted = decrypt_aes(iv, encrypted, key)
print(decrypted.decode()) # Hello, AES!
#include <openssl/evp.h>
#include <openssl/aes.h>
#include <vector>
#include <string>
class AES256 {
private:
unsigned char key[32];
unsigned char iv[16];
public:
AES256(const unsigned char* key_data) {
memcpy(key, key_data, 32);
}
std::vector<unsigned char> encrypt(const std::string& plaintext) {
EVP_CIPHER_CTX *ctx = EVP_CIPHER_CTX_new();
EVP_EncryptInit_ex(ctx, EVP_aes_256_cbc(), NULL, key, iv);
std::vector<unsigned char> ciphertext(plaintext.size() + EVP_MAX_BLOCK_LENGTH);
int len;
EVP_EncryptUpdate(ctx, ciphertext.data(), &len,
(unsigned char*)plaintext.data(), plaintext.size());
int ciphertext_len = len;
EVP_EncryptFinal_ex(ctx, ciphertext.data() + len, &len);
ciphertext_len += len;
EVP_CIPHER_CTX_free(ctx);
ciphertext.resize(ciphertext_len);
return ciphertext;
}
std::string decrypt(const std::vector<unsigned char>& ciphertext) {
EVP_CIPHER_CTX *ctx = EVP_CIPHER_CTX_new();
EVP_DecryptInit_ex(ctx, EVP_aes_256_cbc(), NULL, key, iv);
std::vector<unsigned char> plaintext(ciphertext.size());
int len;
EVP_DecryptUpdate(ctx, plaintext.data(), &len,
ciphertext.data(), ciphertext.size());
int plaintext_len = len;
EVP_DecryptFinal_ex(ctx, plaintext.data() + len, &len);
plaintext_len += len;
EVP_CIPHER_CTX_free(ctx);
return std::string(plaintext.begin(), plaintext.begin() + plaintext_len);
}
};
using System;
using System.Security.Cryptography;
using System.IO;
public class AESEncryption
{
private readonly Aes aes;
public AESEncryption()
{
aes = Aes.Create();
aes.KeySize = 256;
}
public (byte[] iv, byte[] ciphertext) Encrypt(byte[] plaintext)
{
aes.GenerateIV();
using var encryptor = aes.CreateEncryptor();
using var msEncrypt = new MemoryStream();
using var csEncrypt = new CryptoStream(msEncrypt, encryptor, CryptoStreamMode.Write);
csEncrypt.Write(plaintext, 0, plaintext.Length);
csEncrypt.FlushFinalBlock();
return (aes.IV, msEncrypt.ToArray());
}
public byte[] Decrypt(byte[] iv, byte[] ciphertext)
{
aes.IV = iv;
using var decryptor = aes.CreateDecryptor();
using var msDecrypt = new MemoryStream();
using var csDecrypt = new CryptoStream(msDecrypt, decryptor, CryptoStreamMode.Write);
csDecrypt.Write(ciphertext, 0, ciphertext.Length);
csDecrypt.FlushFinalBlock();
return msDecrypt.ToArray();
}
// Example usage
public static void Main()
{
var aesEncryption = new AESEncryption();
var plaintext = System.Text.Encoding.UTF8.GetBytes("Hello, AES!");
// Encrypt
var (iv, ciphertext) = aesEncryption.Encrypt(plaintext);
// Decrypt
var decrypted = aesEncryption.Decrypt(iv, ciphertext);
Console.WriteLine(System.Text.Encoding.UTF8.GetString(decrypted));
}
}
Complexity Analysis
Operation | Time Complexity | Space Complexity |
---|---|---|
Encryption/Decryption | O(1) per block | O(1) |
Key Expansion | O(1) | O(1) |
The complexity is constant because AES operates on fixed-size blocks regardless of input size. For large inputs, the time is linear in the number of blocks.
Advantages and Disadvantages
Advantages
- Strong security (no practical attacks known)
- Fast in both software and hardware
- Widely supported and standardized
- Free for any use
- Relatively simple to implement
Disadvantages
- Key management can be complex
- Requires secure key exchange
- Vulnerable to side-channel attacks
- Fixed block size may require padding