Skip to content

A high-performance C++ library implementing the AES-128 standard for encrypting and decrypting 128-bit data blocks.

License

Notifications You must be signed in to change notification settings

togunchan/BlockCrypt

Repository files navigation

BlockCrypt

Modern C++17 implementation of AES-128 with CBC mode, PKCS#7 padding, and a practical command-line interface. The project keeps the cryptographic core, padding logic, CBC chaining, and tooling separated so that each piece is easy to study, test, and reuse.


Highlights

  • AES-128 block cipher with full round-key expansion
  • ECB single-block helpers and NIST SP 800-38A test vectors
  • CBC mode with PKCS#7 padding for arbitrary-length payloads
  • CLI utility (blockcrypt) for file/stream encrypt–decrypt workflows
  • Catch2-based unit tests: edge cases, fuzzing, standards compliance
  • Optional benchmarking targets to measure ECB/CBC latency & throughput

Directory Layout

BlockCrypt/
├── CMakeLists.txt          # Root CMake project (enables AddressSanitizer by default)
├── include/               # Public headers shared by the library & CLI
│   ├── CBC.hpp
│   ├── blockcrypt.hpp
│   └── padding.hpp
├── src/                   # AES core, CBC mode, padding implementations
│   ├── CBC.cpp
│   ├── blockcrypt.cpp
│   └── padding.cpp
├── constants/             # S-Boxes, inverse S-Boxes, Rcon values
│   ├── BlockCryptConstants.cpp
│   └── BlockCryptConstants.hpp
├── tests/                 # Catch2 tests & benchmarks (registered with CTest)
│   ├── CMakeLists.txt
│   ├── benchmark_performance.cpp
│   └── test_blockcrypt.cpp
├── third_party/           # Vendored Catch2 headers (used when FetchContent is skipped)
├── main.cpp               # Command-line entry point
├── README.md              # You are here
├── LICENSE
└── build/                 # (generated) CMake build tree

Getting Started

Prerequisites

  • C++17 compliant compiler (GCC ≥ 9, Clang ≥ 10, MSVC ≥ 2019)
  • CMake ≥ 3.15

ℹ️ The root CMakeLists.txt enables AddressSanitizer (-fsanitize=address) and debug symbols by default. To change this, pass your own compiler flags or configure a Release build (-DCMAKE_BUILD_TYPE=Release).

Configure & Build

cmake -S . -B build
cmake --build build

Run the Test Suite

cd build
# Full suite (includes long-running benchmarks ~12 minutes total)
ctest --output-on-failure --timeout 1200

# Skip benchmarks to keep CI fast
ctest -LE benchmark --output-on-failure

Run Benchmarks Only

cd build
ctest -L benchmark --output-on-failure --timeout 600

Command-Line Usage

The blockcrypt executable reads/writes binary data either from files or via standard streams. Keys and IVs must be provided as hexadecimal strings (32 hex characters → 16 bytes). Defaults:

  • Key: 16 zero bytes (if -k/--key omitted)
  • IV: 000102030405060708090A0B0C0D0E0F (if -i/--iv omitted)
# Quick help
./build/blockcrypt --help

# Encrypt file → ciphertext.bin
./build/blockcrypt encrypt \
  -k 2b7e151628aed2a6abf7158809cf4f3c \
  -i 000102030405060708090a0b0c0d0e0f \
  -I plaintext.bin \
  -O ciphertext.bin

# Decrypt file → decrypted.bin
./build/blockcrypt decrypt \
  -k 2b7e151628aed2a6abf7158809cf4f3c \
  -i 000102030405060708090a0b0c0d0e0f \
  -I ciphertext.bin \
  -O decrypted.bin

# Stream-based usage (stdin/stdout when -I / -O omitted)
cat message.txt | ./build/blockcrypt encrypt -k ... -i ... > encrypted.bin

Errors such as malformed hex strings, missing files, or padding inconsistencies are reported to stderr with non-zero exit codes.


Library Integration Example

#include "blockcrypt.hpp"
#include "CBC.hpp"
#include "padding.hpp"

int main()
{
    BlockCrypt::Key key{
        0x2B, 0x7E, 0x15, 0x16,
        0x28, 0xAE, 0xD2, 0xA6,
        0xAB, 0xF7, 0x15, 0x88,
        0x09, 0xCF, 0x4F, 0x3C};

    BlockCrypt::Block iv{
        0x00, 0x01, 0x02, 0x03,
        0x04, 0x05, 0x06, 0x07,
        0x08, 0x09, 0x0A, 0x0B,
        0x0C, 0x0D, 0x0E, 0x0F};

    std::vector<uint8_t> data{'H', 'e', 'l', 'l', 'o'};

    BC::encryptCBC(data, key, iv); // ciphertext w/ PKCS#7 padding
    BC::decryptCBC(data, key, iv); // returns to original plaintext

    std::cout << std::string(data.begin(), data.end()) << '\n';
}

Testing & Quality Gates

tests/test_blockcrypt.cpp exercises the cryptographic primitives and padding helpers:

  • Round-trip encrypt/decrypt for canonical and extreme (all-zero, all-0xFF) data
  • Random fuzzing (100 × 100 key/block combinations)
  • NIST AES-128 ECB & CBC vector compliance
  • PKCS#7 padding/unpadding symmetry checks

tests/benchmark_performance.cpp registers Catch2 benchmarks used to profile ECB/CBC latency and throughput. Benchmarks are labeled with benchmark to keep them opt-in for quick test runs.


Implementation Notes

  • AES Core – Implements the SubBytes, ShiftRows, MixColumns, and AddRoundKey stages exactly as described in FIPS 197. Round keys are pre-computed once per BlockCrypt instance.
  • Key Expansion – Generates 11 round keys via RotWord, SubWord (S-Box), and Rcon XOR, throwing if Rcon indices overflow.
  • CBC Mode – XORs each plaintext block with the previous ciphertext (or IV) before AES encryption; decryption reverses via buffering the previous ciphertext block.
  • PaddingBCPad::addPKCS7 / removePKCS7 implement strict PKCS#7 checks and throw on malformed padding, preventing truncated or tampered ciphertext from silently passing.

References


License

This project is licensed under the MIT License. See LICENSE for details.


Contact

Questions, feedback, ideas?

LinkedIn GitHub

About

A high-performance C++ library implementing the AES-128 standard for encrypting and decrypting 128-bit data blocks.

Topics

Resources

License

Stars

Watchers

Forks

Packages

No packages published