- Disclaimer
- How AES works
- Prerequisites
- Code Components
- Usage
- Limitations
- Resources
- Contributions
- License
This implementation of the AES (Advanced Encryption Standard) algorithm is provided for educational and demonstration purposes only.
It is not intended to be secure, efficient, or suitable for production environments.
👉 Recommendation: Use well-established and thoroughly tested cryptographic libraries for robust encryption needs.
The goal of this AES implementation is to provide an understanding of how AES works, its internal mathematical operations, and concepts that make AES efficient.
This implementation is written in modern C++ (C++17), using template-free and object-oriented approaches for clarity and educational value.
AES (Rijndael) is a symmetric block cipher algorithm adopted by NIST in 2001.
It operates on fixed block sizes of 128 bits (16 bytes) and supports key sizes of 128, 192, and 256 bits.
Key Size | Rounds |
---|---|
128 | 10 |
192 | 12 |
256 | 14 |
Constant | Size (bytes) |
---|---|
Sbox | 256 |
InvSbox | 256 |
MixCols | 16 |
InvMixCols | 16 |
Rcon | 256 |
Nb: Number of columns in the state (always 4 for AES)
Nk: Number of 32-bit words in the key (4, 6, or 8)
Nr: Number of rounds (10, 12, 14)
- KeyExpansion
- SubBytes
- ShiftRows
- MixColumns
- AddRoundKey
- KeyExpansion
- InvShiftRows
- InvSubBytes
- AddRoundKey
- InvMixColumns
AES operates on 16-byte blocks. If the data is not a multiple of the block size, it must be padded.
This implementation uses PKCS#7 padding via AES::Utils::PKCS7Pad
and unpadding via AES::Utils::PKCS7Unpad
.
AES supports several modes:
Mode | Parallelizable (Enc) | Parallelizable (Dec) | Random-Read | IV/Nonce | Counter | Style |
---|---|---|---|---|---|---|
ECB | YES | YES | YES | NO | NO | Block |
CBC | NO | YES | YES | YES | NO | Block |
OFB | NO | NO | NO | YES | NO | Stream-like |
CFB | NO | YES | YES | YES | NO | Stream-like |
CTR | YES | YES | YES | YES | YES | Stream-like |
Note: GCM is not implemented in this header.
- C++17-compliant compiler.
- Linux/Unix recommended for best entropy (key/IV generation).
The header aes.hpp
defines:
AES::byte
— Byte alias (uint8_t
)AES::SecureByteBlock
— Secure byte container for keys/IVs.AES::SecureByteGenerator
— Static methods to generate random key/IV blocks using CSPRNG or PRNG.AES::Utils
— Utility namespace (PKCS#7 padding, key size validation, etc).AES::Engine
— AES core engine for block operations.AES::Result
— Result wrapper with various output conversions.AES::ECB
,AES::CBC
,AES::CFB
,AES::OFB
,AES::CTR
— Structs, each providing staticEncrypt
andDecrypt
for that mode.
Struct/Class | Purpose |
---|---|
AES::Engine |
Performs AES block encryption/decryption |
AES::ECB , ... |
Provides mode-specific high-level API |
AES::SecureByteGenerator |
Generate keys and IVs securely |
AES::Result |
Output wrapper: .toVector() , .toString() , etc. |
Absolutely! Here’s a comprehensive and detailed Usage section for your aes.hpp
showing all important functionalities, including both simple and advanced usage for every mode (ECB, CBC, CFB, OFB, CTR), with all variants (Encrypt
, Decrypt
, ParallelEncryption
, SerialEncryption
, etc.), and demonstrating how to use AES::Result
for output. This will form a robust reference for users of your header.
Certainly! Here is a segmented, well-structured Usage section for your README. Each section introduces and explains the concept before showing concise, correct code samples, specifically tailored to your aes.hpp header. This is ideal for onboarding users who want both conceptual clarity and practical code at a glance.
Description:
AES keys must be random and of the correct length for the chosen security level (128, 192, or 256 bits).
This library provides a simple, secure way to generate keys.
// Generate a 128-bit AES key (16 bytes)
std::string key128 = AES::SecureByteGenerator::GenKeyBlock(AES::AES128KS).toString(); // or .toVector() for std::vector<byte> ...
// Generate a 192-bit AES key (24 bytes)
std::string key192 = AES::SecureByteGenerator::GenKeyBlock(AES::AES192KS).toString();
// Generate a 256-bit AES key (32 bytes)
std::string key256 = AES::SecureByteGenerator::GenKeyBlock(AES::AES256KS).toString();
Use the correct key size for your security requirements and make sure to keep the key secret.
Description:
Some AES modes (CBC, CFB, OFB, CTR) require a random Initialization Vector (IV) of 16 bytes (128 bits).
An IV should be unique and unpredictable for every encryption session.
std::string iv = AES::SecureByteGenerator::GenIvBlock(16).toString(); // or .toVector() for vector type...
Always generate a new IV for each message when using modes that require it. The IV does not need to be kept secret, but must be unique.
Description:
- Serial mode processes one block at a time, suitable for environments with limited resources or when deterministic order is required.
- Parallel mode leverages multi-core CPUs to process multiple blocks at once, offering better performance for large data if
AES_ENABLE_PARALLEL_MODE
is defined.
std::string plaintext("some message to encrypt!");
// Serial Encryption (CBC mode)
AES::Result encrypted = AES::CBC::SerialEncryption(plaintext, key, iv);
// Serial Decryption
AES::Result decrypted = AES::CBC::SerialDecryption(encrypted.toString(), key, iv);
Description:
Parallel encryption and decryption will process blocks concurrently.
Use this when encrypting/decrypting large data for better speed (if your system supports it).
// Parallel Encryption (CBC mode)
AES::Result encrypted = AES::CBC::ParallelEncryption(plaintext, key, iv);
// Parallel Decryption
AES::Result decrypted = AES::CBC::ParallelDecryption(encrypted.toString(), key, iv);
Choose parallel for speed, serial for simple or deterministic use.
Description:
After encryption or decryption, you can extract the result in different formats.
AES::Result result = AES::ECB::SerialEncryption("test", key);
std::vector<AES::byte> raw = result.toVector(); // Raw bytes
std::string hex = result.toHex(); // Hex string
std::string b64 = result.toBase64(); // Base64
std::string ascii = result.toAscii(); // ASCII
std::string plain = AES::ECB::SerialDecryption(raw, key).toString(); // Decrypted as string
About:
ECB (Electronic Codebook) is the simplest AES mode. Each block is encrypted independently.
Warning: Do not use ECB for sensitive data—it leaks patterns!
AES::Result enc = AES::ECB::SerialEncryption(plaintext, key);
AES::Result dec = AES::ECB::SerialDecryption(enc.toString(), key);
About:
CBC (Cipher Block Chaining) xors each plaintext block with the previous ciphertext block, using an IV for the first block.
This is a secure default for most applications (with random IV per message).
AES::Result enc = AES::CBC::SerialEncryption(plaintext, key, iv);
AES::Result dec = AES::CBC::SerialDecryption(enc.toString(), key, iv);
About:
CFB (Cipher Feedback) turns AES into a self-synchronizing stream cipher. Good for encrypting data of arbitrary length.
AES::Result enc = AES::CFB::SerialEncryption(plaintext, key, iv);
AES::Result dec = AES::CFB::SerialDecryption(enc.toString(), key, iv);
About:
OFB (Output Feedback) is similar to CFB, but more resistant to transmission errors. Produces a key stream that is xored with plaintext.
AES::Result enc = AES::OFB::SerialEncryption(plaintext, key, iv);
AES::Result dec = AES::OFB::SerialDecryption(enc.toString(), key, iv);
About:
CTR (Counter) mode turns AES into a stream cipher using a nonce and counter. Allows random access to encrypted data and parallel processing.
AES::Result enc = AES::CTR::SerialEncryption(plaintext, key, iv);
AES::Result dec = AES::CTR::SerialDecryption(enc.toString(), key, iv);
#include "aes.hpp"
#include <iostream>
int main() {
// 1. Generate a 128-bit AES key and a 16-byte IV
std::string key = AES::SecureByteGenerator::GenKeyBlock(AES::AES256KS).toString();
std::string iv = AES::SecureByteGenerator::GenIvBlock(16).toString();
// 2. Define plaintext
std::string plaintext = "Parallel encryption and decryption example!";
// 3. Parallel Encryption (CBC mode)
AES::Result encrypted = AES::CBC::ParallelEncryption(plaintext, key, iv);
// 4. Parallel Decryption (CBC mode)
AES::Result decrypted = AES::CBC::ParallelDecryption(encrypted.toString(), key, iv);
// 5. Print results
std::cout << "Original: " << plaintext << std::endl;
std::cout << "Encrypted(Hex): " << encrypted.toHex() << std::endl;
std::cout << "Decrypted: " << decrypted.toString() << std::endl;
return 0;
}
#include "aes.hpp"
#include <iostream>
int main() {
// 1. Generate a 128-bit AES key and a 16-byte IV
std::string key = AES::SecureByteGenerator::GenKeyBlock(AES::AES256KS).toString();
std::string iv = AES::SecureByteGenerator::GenIvBlock(16).toString();
// 2. Define plaintext
std::string plaintext = "Serial encryption and decryption example!";
// 3. Serial Encryption (CBC mode)
AES::Result encrypted = AES::CBC::SerialEncryption(plaintext, key, iv);
// 4. Serial Decryption (CBC mode)
AES::Result decrypted = AES::CBC::SerialDecryption(encrypted.toString(), key, iv);
// 5. Print results
std::cout << "Original: " << plaintext << std::endl;
std::cout << "Encrypted(Hex): " << encrypted.toHex() << std::endl;
std::cout << "Decrypted: " << decrypted.toString() << std::endl;
return 0;
}
ECB and CBC modes require padding. This implementation applies PKCS#7 automatically for those modes.
OFB, CFB, and CTR do not require padding and are safe for arbitrary-length plaintext.
AES::Result
provides:
.toVector()
— Get asstd::vector<AES::byte>
.toString()
— As plaintext (if decrypting).toHex()
— Hex representation.toBase64()
— Base64.toAscii()
— ASCII-safe
- 16 bytes → 128 bits
- 24 bytes → 192 bits
- 32 bytes → 256 bits
Use the appropriate key size for your desired AES strength.
- Security:
- Not hardened against side-channel or cache attacks.
- Not production ready.
- Cryptography (Wikipedia)
- Cryptographic Primitives Overview
- Symmetric-key Cryptography
- Public-key Cryptography
- AES (Wikipedia)
- NIST AES Specification (FIPS 197)
- AES Explained (Khan Academy)
- AES Key Sizes and Security
- Applied Cryptography by Bruce Schneier
- Introduction to Modern Cryptography
- Cryptography I (Stanford Online)
Contributions are welcome! If you encounter issues or have suggestions, feel free to open an issue or submit a pull request.
This project is licensed under the MIT License. See the LICENSE
file for details.