From 664ff91e63ed80d89c9ac2985295d485b60a3a87 Mon Sep 17 00:00:00 2001 From: Timerix Date: Thu, 24 Jul 2025 05:47:18 +0300 Subject: [PATCH] added random header to AES and removed malloc calls --- .vscode/c_cpp_properties.json | 2 +- dependencies/bearssl.project.config | 27 +++--- project.config | 2 +- src/cryptography/AES.c | 140 +++++++++++----------------- src/cryptography/cryptography.h | 40 +++++--- src/cryptography/hash.c | 17 ++-- src/main.c | 36 +++---- 7 files changed, 124 insertions(+), 140 deletions(-) diff --git a/.vscode/c_cpp_properties.json b/.vscode/c_cpp_properties.json index 7cdd1a2..99d6d0c 100755 --- a/.vscode/c_cpp_properties.json +++ b/.vscode/c_cpp_properties.json @@ -5,7 +5,7 @@ "defines": [], "includePath": [ "src", - "dependencies", + "dependencies/BearSSL/inc", "dependencies/tlibc/include", "${default}" ], diff --git a/dependencies/bearssl.project.config b/dependencies/bearssl.project.config index c536c01..cd3ff78 100644 --- a/dependencies/bearssl.project.config +++ b/dependencies/bearssl.project.config @@ -9,10 +9,7 @@ STD_CPP="c++11" WARN_C="-Wno-unknown-pragmas" # WARN_CPP="-Wall -Wextra" -SRC_C="" -for d in codec int hash rand rsa symcipher; do - SRC_C+=" $(find src/$d -name '*.c')" -done +SRC_C="$(find src -name '*.c')" #SRC_CPP="$(find src -name '*.cpp')" # Directory with dependency configs. @@ -38,11 +35,13 @@ case "$OS" in EXEC_FILE="$PROJECT.exe" SHARED_LIB_FILE="$PROJECT.dll" LINKER_LIBS="" + DEFINE="" ;; LINUX) EXEC_FILE="$PROJECT" SHARED_LIB_FILE="$PROJECT.so" LINKER_LIBS="" + DEFINE="-DBR_USE_GETENTROPY=0" ;; *) error "operating system $OS has no configuration variants" @@ -59,7 +58,7 @@ case "$TASK" in # -fprofile-use enables compiler to use profiling info files to optimize executable # -fprofile-prefix-path sets path where profiling info about objects are be saved # -fdata-sections -ffunction-sections -Wl,--gc-sections removes unused code - C_ARGS="-O2 -flto=auto -fuse-linker-plugin -fprofile-use -fprofile-prefix-path=$(realpath $OBJDIR)/objects -fdata-sections -ffunction-sections -Wl,--gc-sections" + C_ARGS="$DEFINE -O2 -flto=auto -fuse-linker-plugin -fprofile-use -fprofile-prefix-path=$(realpath $OBJDIR)/objects -fdata-sections -ffunction-sections -Wl,--gc-sections" CPP_ARGS="$C_ARGS" LINKER_ARGS="$CPP_ARGS $LINKER_LIBS" PRE_TASK_SCRIPT= @@ -68,7 +67,7 @@ case "$TASK" in ;; # creates executable with debug info and no optimizations build_exec_dbg) - C_ARGS="-O0 -g3" + C_ARGS="$DEFINE -O0 -g3" CPP_ARGS="$C_ARGS" LINKER_ARGS="$CPP_ARGS $LINKER_LIBS" PRE_TASK_SCRIPT= @@ -77,7 +76,7 @@ case "$TASK" in ;; # creates shared library build_shared_lib) - C_ARGS="-O2 -fpic -flto -shared" + C_ARGS="$DEFINE -O2 -fpic -flto -shared" CPP_ARGS="$C_ARGS" LINKER_ARGS="$CPP_ARGS $LINKER_LIBS -Wl,-soname,$SHARED_LIB_FILE" PRE_TASK_SCRIPT= @@ -86,7 +85,7 @@ case "$TASK" in ;; # creates shared library with debug symbols and no optimizations build_shared_lib_dbg) - C_ARGS="-O0 -g3 -fpic -shared" + C_ARGS="$DEFINE -O0 -g3 -fpic -shared" CPP_ARGS="$C_ARGS" LINKER_ARGS="$CPP_ARGS $LINKER_LIBS -Wl,-soname,$SHARED_LIB_FILE" PRE_TASK_SCRIPT= @@ -95,7 +94,7 @@ case "$TASK" in ;; # creates static library build_static_lib) - C_ARGS="-O2 -fpic -fdata-sections -ffunction-sections" + C_ARGS="$DEFINE -O2 -fpic -fdata-sections -ffunction-sections" CPP_ARGS="$C_ARGS" PRE_TASK_SCRIPT= TASK_SCRIPT=cbuild/default_tasks/build_static_lib.sh @@ -103,7 +102,7 @@ case "$TASK" in ;; # creates static library with debug symbols and no optimizations build_static_lib_dbg) - C_ARGS="-O0 -g3" + C_ARGS="$DEFINE -O0 -g3" CPP_ARGS="$C_ARGS" PRE_TASK_SCRIPT= TASK_SCRIPT=cbuild/default_tasks/build_static_lib.sh @@ -127,7 +126,7 @@ case "$TASK" in # -pg adds code to executable, that generates file containing function call info (gmon.out) # -fprofile-generate generates executable with profiling code # -fprofile-prefix-path sets path where profiling info about objects will be saved - C_ARGS="-O2 -flto=auto -fuse-linker-plugin -fprofile-generate -fprofile-prefix-path=$(realpath $OBJDIR)/objects" + C_ARGS="$DEFINE -O2 -flto=auto -fuse-linker-plugin -fprofile-generate -fprofile-prefix-path=$(realpath $OBJDIR)/objects" CPP_ARGS="$C_ARGS" LINKER_ARGS="$CPP_ARGS $LINKER_LIBS" PRE_TASK_SCRIPT=cbuild/default_tasks/build_exec.sh @@ -140,7 +139,7 @@ case "$TASK" in gprof) OUTDIR="$OUTDIR/gprof" # -pg adds code to executable, that generates file containing function call info (gmon.out) - C_ARGS="-O2 -flto=auto -fuse-linker-plugin -pg" + C_ARGS="$DEFINE -O2 -flto=auto -fuse-linker-plugin -pg" CPP_ARGS="$C_ARGS" LINKER_ARGS="$CPP_ARGS $LINKER_LIBS" PRE_TASK_SCRIPT=cbuild/default_tasks/build_exec.sh @@ -154,7 +153,7 @@ case "$TASK" in callgrind) OUTDIR="$OUTDIR/callgrind" # -pg adds code to executable, that generates file containing function call info (gmon.out) - C_ARGS="-O2 -flto=auto -fuse-linker-plugin" + C_ARGS="$DEFINE -O2 -flto=auto -fuse-linker-plugin" CPP_ARGS="$C_ARGS" LINKER_ARGS="$CPP_ARGS $LINKER_LIBS" PRE_TASK_SCRIPT=cbuild/default_tasks/build_exec.sh @@ -164,7 +163,7 @@ case "$TASK" in # compiles executable with sanitizers and executes it to find errors and warnings sanitize) OUTDIR="$OUTDIR/sanitize" - C_ARGS="-O0 -g3 -fsanitize=undefined,address" + C_ARGS="$DEFINE -O0 -g3 -fsanitize=undefined,address" CPP_ARGS="$C_ARGS" LINKER_ARGS="$CPP_ARGS $LINKER_LIBS" PRE_TASK_SCRIPT=cbuild/default_tasks/build_exec.sh diff --git a/project.config b/project.config index 5c66362..d8bcf2f 100644 --- a/project.config +++ b/project.config @@ -26,7 +26,7 @@ OBJDIR="obj" OUTDIR="bin" STATIC_LIB_FILE="lib$PROJECT.a" -INCLUDE="-I./src -I./dependencies -I./dependencies/tlibc/include" +INCLUDE="-I./src -I./dependencies/BearSSL/inc -I./dependencies/tlibc/include" # OS-specific options case "$OS" in diff --git a/src/cryptography/AES.c b/src/cryptography/AES.c index fb7c881..9580f99 100755 --- a/src/cryptography/AES.c +++ b/src/cryptography/AES.c @@ -1,125 +1,95 @@ #include "cryptography.h" -#include "BearSSL/inc/bearssl_block.h" #include +#include "tlibc/time.h" -// size must be multiple of 16 -#define __AES_BUFFER_SIZE 256 - -typedef struct EncryptorAES { - br_aes_ct64_cbcenc_keys enc_ctx; - Array buf; - Array iv; -} EncryptorAES; - -typedef struct DecryptorAES { - br_aes_ct64_cbcdec_keys dec_ctx; - Array buf; - Array iv; -} DecryptorAES; - -EncryptorAES* EncryptorAES_create(Array key){ +void EncryptorAES_create(EncryptorAES* ptr, Array key){ assert(key.size == 16 || key.size == 24 || key.size == 32); - EncryptorAES* ptr = (EncryptorAES*)malloc(sizeof(EncryptorAES)); br_aes_ct64_cbcenc_init(&ptr->enc_ctx, key.data, key.size); - // size must be multiple of 16 - ptr->buf = Array_alloc(u8, __AES_BUFFER_SIZE); - Array_memset(&ptr->buf, 0); + // uses CLOCK_REALTIME to seed rng + nsec_t time_now = getTimeNsec(); + br_hmac_drbg_init(&ptr->rng_ctx, &br_sha256_vtable, &time_now, sizeof(time_now)); - // size of one SHA block (16 bytes) - ptr->iv = Array_alloc(u8, 16); - Array_memset(&ptr->iv, 0); - - return ptr; -} - -void EncryptorAES_destroy(EncryptorAES* ptr){ - free(ptr->buf.data); - free(ptr->iv.data); + memset(ptr->buf, 0, __AES_BUFFER_SIZE); + memset(ptr->iv, 0, sizeof(ptr->iv)); } void EncryptorAES_encrypt(EncryptorAES* ptr, Array src, Array dst){ assert(dst.size >= EncryptorAES_calcDstSize(src.size)); + // write random bytes to the beginning of the buffer + br_hmac_drbg_generate(&ptr->rng_ctx, ptr->buf, __AES_RANDOM_BYTES_N); const EncryptedBlockInfo block_info = { .padding_size = 16 - src.size % 16 }; - memcpy(ptr->buf.data, &block_info, sizeof(EncryptedBlockInfo)); - // encrypt this struct - br_aes_ct64_cbcenc_run(&ptr->enc_ctx, ptr->iv.data, ptr->buf.data, sizeof(EncryptedBlockInfo)); - // emit EncryptedBlockInfo to beginning of result - memcpy(dst.data, ptr->buf.data, sizeof(EncryptedBlockInfo)); - dst.data += sizeof(EncryptedBlockInfo); - dst.size -= sizeof(EncryptedBlockInfo); - + // write struct after random_bytes + memcpy((u8*)ptr->buf + __AES_RANDOM_BYTES_N, &block_info, sizeof(EncryptedBlockInfo)); + // encrypt buffer + const u32 header_size = __AES_RANDOM_BYTES_N + sizeof(EncryptedBlockInfo); + br_aes_ct64_cbcenc_run(&ptr->enc_ctx, ptr->iv, ptr->buf, header_size); + // write encrypted header to dst + memcpy(dst.data, ptr->buf, header_size); + dst.data += header_size; + dst.size -= header_size; + // write full blocks - while(src.size > ptr->buf.size){ - memcpy(ptr->buf.data, src.data, ptr->buf.size); - src.data += ptr->buf.size; - src.size -= ptr->buf.size; - br_aes_ct64_cbcenc_run(&ptr->enc_ctx, ptr->iv.data, ptr->buf.data, ptr->buf.size); - memcpy(dst.data, ptr->buf.data, ptr->buf.size); - dst.data += ptr->buf.size; - dst.size -= ptr->buf.size; + while(src.size > __AES_BUFFER_SIZE){ + memcpy(ptr->buf, src.data, __AES_BUFFER_SIZE); + src.data += __AES_BUFFER_SIZE; + src.size -= __AES_BUFFER_SIZE; + br_aes_ct64_cbcenc_run(&ptr->enc_ctx, ptr->iv, ptr->buf, __AES_BUFFER_SIZE); + memcpy(dst.data, ptr->buf, __AES_BUFFER_SIZE); + dst.data += __AES_BUFFER_SIZE; + dst.size -= __AES_BUFFER_SIZE; } // write incomplete block - Array_memset(&ptr->buf, 0); - memcpy(ptr->buf.data, src.data, src.size); + memset(ptr->buf, 0, __AES_BUFFER_SIZE); + memcpy(ptr->buf, src.data, src.size); u32 src_size_padded = src.size + block_info.padding_size; - br_aes_ct64_cbcenc_run(&ptr->enc_ctx, ptr->iv.data, ptr->buf.data, src_size_padded); - memcpy(dst.data, ptr->buf.data, src_size_padded); + br_aes_ct64_cbcenc_run(&ptr->enc_ctx, ptr->iv, ptr->buf, src_size_padded); + memcpy(dst.data, ptr->buf, src_size_padded); } -DecryptorAES* DecryptorAES_create(Array key){ +void DecryptorAES_create(DecryptorAES* ptr, Array key){ assert(key.size == 16 || key.size == 24 || key.size == 32); - DecryptorAES* ptr = (DecryptorAES*)malloc(sizeof(DecryptorAES)); br_aes_ct64_cbcdec_init(&ptr->dec_ctx, key.data, key.size); - // size must be multiple of 16 - ptr->buf = Array_alloc(u8, __AES_BUFFER_SIZE); - Array_memset(&ptr->buf, 0); - - // size of one SHA block (16 bytes) - ptr->iv = Array_alloc(u8, 16); - Array_memset(&ptr->iv, 0); - - return ptr; -} - -void DecryptorAES_destroy(DecryptorAES* ptr){ - free(ptr->buf.data); - free(ptr->iv.data); + memset(ptr->buf, 0, __AES_BUFFER_SIZE); + memset(ptr->iv, 0, sizeof(ptr->iv)); } void DecryptorAES_decrypt(DecryptorAES* ptr, Array src, Array dst, u32* decrypted_size){ assert(dst.size >= src.size); - // read EncryptedBlockInfo from beginning of data + // copy encrypted header from src to buffer + const u32 header_size = __AES_RANDOM_BYTES_N + sizeof(EncryptedBlockInfo); + memcpy(ptr->buf, src.data, header_size); + src.data += header_size; + src.size -= header_size; + // decrypt buffer + br_aes_ct64_cbcdec_run(&ptr->dec_ctx, ptr->iv, &ptr->buf, header_size); + // read EncryptedBlockInfo from buffer EncryptedBlockInfo block_info; - memcpy(&block_info, src.data, sizeof(EncryptedBlockInfo)); - src.data += sizeof(EncryptedBlockInfo); - src.size -= sizeof(EncryptedBlockInfo); - // decrypt this struct - br_aes_ct64_cbcdec_run(&ptr->dec_ctx, ptr->iv.data, &block_info, sizeof(EncryptedBlockInfo)); + memcpy(&block_info, (u8*)ptr->buf + __AES_RANDOM_BYTES_N, sizeof(EncryptedBlockInfo)); *decrypted_size = src.size - block_info.padding_size; // write full blocks - while(src.size > ptr->buf.size){ - memcpy(ptr->buf.data, src.data, ptr->buf.size); - src.data += ptr->buf.size; - src.size -= ptr->buf.size; - br_aes_ct64_cbcdec_run(&ptr->dec_ctx, ptr->iv.data, ptr->buf.data, ptr->buf.size); - memcpy(dst.data, ptr->buf.data, ptr->buf.size); - dst.data += ptr->buf.size; - dst.size -= ptr->buf.size; + while(src.size > __AES_BUFFER_SIZE){ + memcpy(ptr->buf, src.data, __AES_BUFFER_SIZE); + src.data += __AES_BUFFER_SIZE; + src.size -= __AES_BUFFER_SIZE; + br_aes_ct64_cbcdec_run(&ptr->dec_ctx, ptr->iv, ptr->buf, __AES_BUFFER_SIZE); + memcpy(dst.data, ptr->buf, __AES_BUFFER_SIZE); + dst.data += __AES_BUFFER_SIZE; + dst.size -= __AES_BUFFER_SIZE; } // write incomplete block - Array_memset(&ptr->buf, 0); - memcpy(ptr->buf.data, src.data, src.size); + memset(ptr->buf, 0, __AES_BUFFER_SIZE); + memcpy(ptr->buf, src.data, src.size); u32 src_size_padded = src.size + block_info.padding_size; - br_aes_ct64_cbcdec_run(&ptr->dec_ctx, ptr->iv.data, ptr->buf.data, src_size_padded); - memcpy(dst.data, ptr->buf.data, src_size_padded); + br_aes_ct64_cbcdec_run(&ptr->dec_ctx, ptr->iv, ptr->buf, src_size_padded); + memcpy(dst.data, ptr->buf, src_size_padded); } diff --git a/src/cryptography/cryptography.h b/src/cryptography/cryptography.h index eed2be5..7e2ea1c 100755 --- a/src/cryptography/cryptography.h +++ b/src/cryptography/cryptography.h @@ -2,40 +2,54 @@ #include "tlibc/std.h" #include "tlibc/collections/Array.h" #include "tlibc/string/str.h" +#include "bearssl_block.h" +#include "bearssl_rand.h" /// @brief hashes password multiple times using its own hash as salt /// @param password some byte array +/// @param out_buffer u8[hash_password_out_size] /// @param iterations number of iterations -/// @return Array -Array hash_password(str password, i32 iterations); +void hash_password(str password, u8* out_buffer, i32 iterations); +#define hash_password_out_size 32 typedef struct EncryptedBlockInfo { - u32 padding_size; + u8 padding_size; u32 _reserved; u64 __reserved; -} EncryptedBlockInfo; +} __attribute__((aligned(16))) EncryptedBlockInfo; -typedef struct EncryptorAES EncryptorAES; +// must be multiple of 16 +#define __AES_BUFFER_SIZE 512 +// must be multiple of 16 +#define __AES_RANDOM_BYTES_N 16 + +typedef struct EncryptorAES { + br_aes_ct64_cbcenc_keys enc_ctx; + br_hmac_drbg_context rng_ctx; + u8 buf[__AES_BUFFER_SIZE]; + u8 iv[16]; +} EncryptorAES; /// @param key Array -EncryptorAES* EncryptorAES_create(Array key); - -void EncryptorAES_destroy(EncryptorAES* ptr); +void EncryptorAES_create(EncryptorAES* ptr, Array key); /// @brief Encrypts `src` and writes output to `dst`. /// @param src array of any size /// @param dst array of size >= EncryptorAES_calcDstSize(src.size) void EncryptorAES_encrypt(EncryptorAES* ptr, Array src, Array dst); -#define EncryptorAES_calcDstSize(SRC_SIZE) (ALIGN_TO(SRC_SIZE, 16) + sizeof(EncryptedBlockInfo)) +#define EncryptorAES_calcDstSize(SRC_SIZE) (ALIGN_TO(SRC_SIZE, 16) + __AES_RANDOM_BYTES_N + sizeof(EncryptedBlockInfo)) -typedef struct DecryptorAES DecryptorAES; + +typedef struct DecryptorAES { + br_aes_ct64_cbcdec_keys dec_ctx; + u8 buf[__AES_BUFFER_SIZE]; + u8 iv[16]; +} DecryptorAES; /// @param key Array -DecryptorAES* DecryptorAES_create(Array key); - -void DecryptorAES_destroy(DecryptorAES* ptr); +void DecryptorAES_create(DecryptorAES* ptr, Array key); /// @brief Decrypts `src` and writes output to `dst`. /// @param src array of any size diff --git a/src/cryptography/hash.c b/src/cryptography/hash.c index af881b7..4327d00 100755 --- a/src/cryptography/hash.c +++ b/src/cryptography/hash.c @@ -1,18 +1,17 @@ #include "cryptography.h" -#include "BearSSL/inc/bearssl_hash.h" +#include "bearssl_hash.h" +#include "assert.h" -Array hash_password(str password, i32 iterations){ - Array hash_buffer = Array_alloc(u8, br_sha256_SIZE); - Array_memset(&hash_buffer, 0); +void hash_password(str password, u8* out_buffer, i32 iterations){ + assert(hash_password_out_size == br_sha256_SIZE);; + memset(out_buffer, 0, br_sha256_SIZE); br_sha256_context sha256_ctx; br_sha256_init(&sha256_ctx); for(i32 i = 0; i < iterations; i++){ br_sha256_update(&sha256_ctx, password.data, password.size); - br_sha256_out(&sha256_ctx, hash_buffer.data); - br_sha256_update(&sha256_ctx, hash_buffer.data, hash_buffer.size); + br_sha256_out(&sha256_ctx, out_buffer); + br_sha256_update(&sha256_ctx, out_buffer, hash_password_out_size); } - br_sha256_out(&sha256_ctx, hash_buffer.data); - - return hash_buffer; + br_sha256_out(&sha256_ctx, out_buffer); } diff --git a/src/main.c b/src/main.c index 918e4ae..46eea28 100755 --- a/src/main.c +++ b/src/main.c @@ -1,42 +1,44 @@ #include "cryptography/cryptography.h" #include "network/network.h" #include "network/socket.h" -#include #include "tlibc/time.h" -#include "errno.h" -#include +#include +#include +#include Result(void) test_aes(){ const str password = STR("abobus"); const Array data = str_castTo_Array(STR("0123456789_hii_")); - const Array key_hash = hash_password(password, 1e5); - str hash_str = hex_to_str(key_hash, true); - printf("password hash [%i] %s\n", key_hash.size, hash_str.data); - free(hash_str.data); - + u8 hash_buffer[hash_password_out_size]; // SHA256 accepts keys with size 16, 24 or 32 const u32 key_size = 32; - const Array key = Array_construct_size(key_hash.data, key_size); + assert(key_size <= hash_password_out_size); + const Array key = Array_construct_size(hash_buffer, key_size); + hash_password(password, hash_buffer, 1e5); + str hash_str = hex_to_str(key, true); + printf("key [%i] %s\n", key.size, hash_str.data); + free(hash_str.data); - EncryptorAES* encr = EncryptorAES_create(key); + EncryptorAES encr; + EncryptorAES_create(&encr, key); Array buffer = Array_alloc_size(EncryptorAES_calcDstSize(data.size)); - EncryptorAES_encrypt(encr, data, buffer); - EncryptorAES_destroy(encr); + EncryptorAES_encrypt(&encr, data, buffer); str encrypted_str = hex_to_str(buffer, true); printf("data encrypted (hex): %s\n", encrypted_str.data); free(encrypted_str.data); - DecryptorAES* decr = DecryptorAES_create(key); + DecryptorAES decr; + DecryptorAES_create(&decr, key); u32 decrypted_size = 0; - DecryptorAES_decrypt(decr, buffer, buffer, &decrypted_size); - DecryptorAES_destroy(decr); + DecryptorAES_decrypt(&decr, buffer, buffer, &decrypted_size); str decrypted_str = str_copy(str_construct(buffer.data, decrypted_size, false)); printf("data decrypted (utf8): %s\n", decrypted_str.data); free(decrypted_str.data); + free(buffer.data); return RESULT_VOID; } @@ -155,8 +157,8 @@ Result(void) test_network(){ int main(){ try_fatal(_10, network_init(), ); - // try_fatal(_20, test_aes(), ); - try_fatal(_30, test_network(), ); + try_fatal(_20, test_aes(), ); + // try_fatal(_30, test_network(), ); try_fatal(_100, network_deinit(), ); return 0; }