Files
tinyaes/CMakeLists.txt
Brandon Lehmann b4df5d078a Fix ARM CE byte ordering, expand C/C++ API, and harden build
ARM backends: fix round key byte-swap on little-endian (vrev32q_u8),
rewrite decrypt to pre-process middle keys with InvMixColumns, fix
GHASH PMULL reflect and reduction ordering.

API: add nonce/IV-generating convenience overloads for CTR, CBC, and
GCM (library generates and prepends nonce, appends tag). Add C API
for IV/nonce generation. Rename error codes (TINYAES_OK, Result::Ok,
Result::AuthenticationFailed, etc.).

Build: add MinGW GCC AVX-512 debug alignment fix, harden bench/fuzz
CMake targets (warnings-as-errors, linker hardening), align with
tinysha CMake conventions. Add README.

Tests: expand coverage for nonce-generating API overloads, add NIST
GCM test vectors, improve fuzz target differential testing.
2026-02-24 21:59:23 -05:00

228 lines
8.5 KiB
CMake

cmake_minimum_required(VERSION 3.10)
project(tinyaes VERSION 0.1.0 LANGUAGES CXX)
include(CheckCXXCompilerFlag)
if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES)
set(CMAKE_BUILD_TYPE Release CACHE STRING "Build type" FORCE)
endif()
option(BUILD_SHARED_LIBS "Build shared library" OFF)
option(BUILD_TESTS "Build unit tests" OFF)
option(BUILD_BENCHMARKS "Build benchmarks" OFF)
option(FORCE_PORTABLE "Disable SIMD backends; use only portable code" OFF)
# --- Library sources ---
set(TINYAES_SOURCES
src/secure_zero.cpp
src/cpuid.cpp
src/iv_generate.cpp
src/keyschedule.cpp
src/ecb.cpp
src/cbc.cpp
src/ctr.cpp
src/gcm.cpp
src/backend/aes_portable.cpp
src/backend/ghash_portable.cpp
)
# Conditionally add SIMD backend sources on x86_64
if(CMAKE_SYSTEM_PROCESSOR MATCHES "x86_64|AMD64" AND NOT FORCE_PORTABLE)
list(APPEND TINYAES_SOURCES
src/backend/aes_aesni.cpp
src/backend/aes_vaes.cpp
src/backend/ghash_pclmulqdq.cpp
src/backend/ghash_vpclmulqdq.cpp
)
endif()
# Conditionally add ARM64 crypto extension backend sources
if(CMAKE_SYSTEM_PROCESSOR MATCHES "aarch64|arm64|ARM64" AND NOT FORCE_PORTABLE)
list(APPEND TINYAES_SOURCES
src/backend/aes_arm_ce.cpp
src/backend/ghash_arm_ce.cpp
)
endif()
add_library(tinyaes ${TINYAES_SOURCES})
# --- Shared library symbol visibility ---
if(BUILD_SHARED_LIBS)
set_target_properties(tinyaes PROPERTIES
CXX_VISIBILITY_PRESET hidden
VISIBILITY_INLINES_HIDDEN ON
)
target_compile_definitions(tinyaes PUBLIC TINYAES_SHARED=1)
target_compile_definitions(tinyaes PRIVATE TINYAES_BUILDING=1)
endif()
if(FORCE_PORTABLE)
target_compile_definitions(tinyaes PUBLIC TINYAES_FORCE_PORTABLE=1)
endif()
target_include_directories(tinyaes PUBLIC
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
)
# Internal headers (src/) for the library itself
target_include_directories(tinyaes PRIVATE
${CMAKE_CURRENT_SOURCE_DIR}/src
)
set_target_properties(tinyaes PROPERTIES
CXX_STANDARD 17
CXX_STANDARD_REQUIRED ON
CXX_EXTENSIONS OFF
)
# --- Link bcrypt on Windows for BCryptGenRandom ---
if(WIN32)
target_link_libraries(tinyaes PRIVATE bcrypt)
endif()
# --- Detect MinGW environment ---
# Only use CMake's built-in MINGW (set for GCC with MinGW). Clang on Windows can
# target either MinGW or MSVC ABI, and the linker varies (GNU ld vs lld-link) —
# applying the wrong linker flags breaks the build. We let Clang on Windows rely
# on the OS defaults for DEP/ASLR (enabled by default on modern Windows) rather
# than guessing the linker style.
# --- Hardening flags ---
if(CMAKE_CXX_COMPILER_ID MATCHES "GNU|Clang")
target_compile_options(tinyaes PRIVATE
-Wall -Wextra -Wpedantic -Werror
-Wconversion -Wsign-conversion -Wshadow
-Wcast-align -Wundef
-Wformat=2 -Wformat-security
-fno-strict-overflow
)
# Stack protector: requires libssp or compiler-rt at link time.
# Probe with try_compile to catch Clang+MinGW toolchains that lack libssp.
include(CheckCXXSourceCompiles)
set(CMAKE_REQUIRED_FLAGS "-fstack-protector-strong")
check_cxx_source_compiles("int main() { char buf[64]; buf[0] = 0; return buf[0]; }" HAS_STACK_PROTECTOR_STRONG)
unset(CMAKE_REQUIRED_FLAGS)
if(HAS_STACK_PROTECTOR_STRONG)
target_compile_options(tinyaes PRIVATE -fstack-protector-strong)
endif()
# -fPIC is implied on Windows PE; only needed on ELF/Mach-O
if(NOT WIN32)
target_compile_options(tinyaes PRIVATE -fPIC)
# Stack clash protection (Linux only — not supported on macOS/Apple Clang)
if(CMAKE_SYSTEM_NAME STREQUAL "Linux")
target_compile_options(tinyaes PRIVATE -fstack-clash-protection)
endif()
endif()
# Intel CET control flow integrity (x86_64 only)
if(CMAKE_SYSTEM_PROCESSOR MATCHES "x86_64|AMD64")
check_cxx_compiler_flag("-fcf-protection=full" HAS_CF_PROTECTION)
if(HAS_CF_PROTECTION)
target_compile_options(tinyaes PRIVATE -fcf-protection=full)
endif()
endif()
# -Wstrict-aliasing=2 only for GCC (Clang doesn't support the =2 level)
if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
target_compile_options(tinyaes PRIVATE -Wstrict-aliasing=2)
# libstdc++ container assertions in Debug (bounds checks on operator[], etc.)
target_compile_options(tinyaes PRIVATE
$<$<CONFIG:Debug>:-D_GLIBCXX_ASSERTIONS>
)
endif()
# _FORTIFY_SOURCE requires optimization; not reliably supported on MinGW
if(NOT WIN32)
target_compile_options(tinyaes PRIVATE
$<$<NOT:$<CONFIG:Debug>>:-D_FORTIFY_SOURCE=2>
)
endif()
# Linker hardening (use LINK_FLAGS for CMake 3.10 compat)
if(CMAKE_SYSTEM_NAME STREQUAL "Linux")
set_property(TARGET tinyaes APPEND_STRING PROPERTY LINK_FLAGS
" -Wl,-z,relro,-z,now -Wl,-z,noexecstack")
# Reject undefined symbols in shared libs (catches missing TINYAES_EXPORT)
if(BUILD_SHARED_LIBS)
set_property(TARGET tinyaes APPEND_STRING PROPERTY LINK_FLAGS " -Wl,-z,defs")
endif()
endif()
# macOS: -bind_at_load is deprecated on modern macOS (eager binding is the default)
# MinGW linker hardening (DEP + ASLR) — only for GCC+MinGW (known GNU ld)
if(MINGW)
set_property(TARGET tinyaes APPEND_STRING PROPERTY LINK_FLAGS
" -Wl,--nxcompat -Wl,--dynamicbase -Wl,--high-entropy-va")
endif()
elseif(MSVC)
target_compile_options(tinyaes PRIVATE
/W4 /WX
/sdl
/GS
/guard:cf
)
check_cxx_compiler_flag("/Qspectre" HAS_QSPECTRE)
if(HAS_QSPECTRE)
target_compile_options(tinyaes PRIVATE /Qspectre)
endif()
set_property(TARGET tinyaes APPEND_STRING PROPERTY LINK_FLAGS
" /DYNAMICBASE /NXCOMPAT /HIGHENTROPYVA")
# CET shadow stack compatibility
check_cxx_compiler_flag("/guard:ehcont" HAS_GUARD_EHCONT)
if(HAS_GUARD_EHCONT)
target_compile_options(tinyaes PRIVATE /guard:ehcont)
set_property(TARGET tinyaes APPEND_STRING PROPERTY LINK_FLAGS " /guard:ehcont /CETCOMPAT")
endif()
endif()
# --- Per-backend SIMD compile flags ---
# MinGW GCC + Debug: Windows x64 ABI only guarantees 16-byte stack alignment,
# but YMM/ZMM registers need 32/64-byte alignment. At -O0, GCC spills AVX
# registers to the stack with aligned moves (vmovdqa), which SIGSEGV on the
# misaligned stack. Force -O1 for SIMD backends in Debug mode so GCC keeps
# values in registers. -mpreferred-stack-boundary=5 is blocked by the ABI.
set(_MINGW_SIMD_FIX "")
if(MINGW AND CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
set(_MINGW_SIMD_FIX " $<$<CONFIG:Debug>:-O1>")
endif()
if(CMAKE_SYSTEM_PROCESSOR MATCHES "x86_64|AMD64" AND NOT FORCE_PORTABLE)
if(CMAKE_CXX_COMPILER_ID MATCHES "GNU|Clang")
set_source_files_properties(src/backend/aes_aesni.cpp PROPERTIES
COMPILE_FLAGS "-maes -msse4.1")
set_source_files_properties(src/backend/aes_vaes.cpp PROPERTIES
COMPILE_FLAGS "-mavx512f -mvaes -maes -msse4.1${_MINGW_SIMD_FIX}")
set_source_files_properties(src/backend/ghash_pclmulqdq.cpp PROPERTIES
COMPILE_FLAGS "-mpclmul -msse4.1")
set_source_files_properties(src/backend/ghash_vpclmulqdq.cpp PROPERTIES
COMPILE_FLAGS "-mavx512f -mvpclmulqdq -mpclmul -msse4.1${_MINGW_SIMD_FIX}")
elseif(MSVC)
# MSVC: AES-NI and PCLMULQDQ available without extra flags on x64
set_source_files_properties(src/backend/aes_vaes.cpp PROPERTIES
COMPILE_FLAGS "/arch:AVX512")
set_source_files_properties(src/backend/ghash_vpclmulqdq.cpp PROPERTIES
COMPILE_FLAGS "/arch:AVX512")
endif()
endif()
# --- Per-backend ARM64 crypto extension compile flags ---
if(CMAKE_SYSTEM_PROCESSOR MATCHES "aarch64|arm64|ARM64" AND NOT FORCE_PORTABLE)
if(CMAKE_CXX_COMPILER_ID MATCHES "GNU|Clang")
set_source_files_properties(src/backend/aes_arm_ce.cpp PROPERTIES
COMPILE_FLAGS "-march=armv8-a+crypto")
set_source_files_properties(src/backend/ghash_arm_ce.cpp PROPERTIES
COMPILE_FLAGS "-march=armv8-a+crypto")
endif()
# MSVC on ARM64: crypto extensions are enabled by default
endif()
# --- Tests ---
if(BUILD_TESTS)
enable_testing()
add_subdirectory(tests)
endif()
# --- Benchmarks ---
if(BUILD_BENCHMARKS)
add_subdirectory(bench)
endif()
# --- Fuzzing (Clang only, Linux only) ---
if(CMAKE_CXX_COMPILER_ID MATCHES "Clang" AND CMAKE_SYSTEM_NAME STREQUAL "Linux")
add_subdirectory(fuzz)
endif()