diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index fb3dcf18..14e49d8e 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -65,6 +65,13 @@ jobs: path: entity/c ref: ${{ github.ref }} if: ${{ github.ref}} + + - name: Init and update submodules for sst-c-api (pico-sdk, mbedtls) + working-directory: entity/c + run: | + git submodule sync --recursive + git submodule update --init --recursive + - name: Install openssl run: sudo apt-get update && sudo apt-get install -y openssl - name: Set up JDK 17 @@ -87,7 +94,7 @@ jobs: nohup java -jar target/auth-server-jar-with-dependencies.jar -p ../properties/exampleAuth101.properties --password=asdf & echo $! > auth.pid # Save the PID - - name: Run the file_block_encrypt_example examples. + - name: Run the file_block_encrypt_example examples using openssl. working-directory: entity/c/examples/file_block_encrypt_example run: | mkdir build && cd build && cmake ../ && make @@ -95,7 +102,7 @@ jobs: ./block_reader ../block_reader.config ./block_reader_load_s_key_list - - name: Run the server_client_example examples. + - name: Run the server_client_example examples using openssl. working-directory: entity/c/examples/server_client_example run: | mkdir build && cd build && cmake ../ && make @@ -104,7 +111,7 @@ jobs: ./threaded_get_target_id_client ../c_client.config ./threaded_get_target_id_server ../c_server.config - - name: Run the tests examples. + - name: Run the tests examples using openssl. working-directory: entity/c/tests run: | mkdir build && cd build && cmake ../ && make @@ -112,6 +119,31 @@ jobs: # ./encrypt_buf_with_session_key_without_malloc_execution_time_test ../test_configs/client.config ./multi_thread_get_session_key_test ../test_configs/client.config + # - name: Run the file_block_encrypt_example examples using mbedtls. + # working-directory: entity/c/examples/file_block_encrypt_example + # run: | + # rm -rf build && mkdir build && cd build && cmake -DUSE_MBEDTLS=ON ../ && make + # ./block_writer ../block_writer.config + # ./block_reader ../block_reader.config + # ./block_reader_load_s_key_list + + # - name: Run the server_client_example examples using mbedtls. + # working-directory: entity/c/examples/server_client_example + # run: | + # rm -rf build && mkdir build && cd build && cmake -DUSE_MBEDTLS=ON ../ && make + # ./entity_server ../c_server.config & + # ./entity_client ../c_client.config + # ./threaded_get_target_id_client ../c_client.config + # ./threaded_get_target_id_server ../c_server.config + + # - name: Run the tests examples using mbedtls. + # working-directory: entity/c/tests + # run: | + # rm -rf build && mkdir build && cd build && cmake -DUSE_MBEDTLS=ON ../ && make + # ./save_load_session_key_list_with_password_test ../test_configs/client.config + # # ./encrypt_buf_with_session_key_without_malloc_execution_time_test ../test_configs/client.config + # ./multi_thread_get_session_key_test ../test_configs/client.config + - name: Stop auth server working-directory: auth/auth-server run: | diff --git a/.gitmodules b/.gitmodules index 6ad90cd2..03b5bd4c 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,3 +1,6 @@ -[submodule "embedded/lib/mbedtls"] - path = embedded/lib/mbedtls - url = https://github.com/Mbed-TLS/mbedtls.git +[submodule "embedded/lib/pico-sdk"] + path = embedded/lib/pico-sdk + url = https://github.com/raspberrypi/pico-sdk.git +[submodule "embedded/lib/FreeRTOS-Kernel"] + path = embedded/lib/FreeRTOS-Kernel + url = https://github.com/FreeRTOS/FreeRTOS-Kernel.git diff --git a/CMakeLists.txt b/CMakeLists.txt index 1fc1c0ea..92619fee 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -2,23 +2,53 @@ # $ cmake -DCMAKE_BUILD_TYPE=Debug ../ cmake_minimum_required(VERSION 3.19) -project(sst-lib VERSION 1.0.0 LANGUAGES C) -find_package(OpenSSL REQUIRED) -find_package(Threads REQUIRED) +project(sst-lib VERSION 1.0.0 LANGUAGES C CXX ASM) -add_library(sst-c-api STATIC +# Crypto backend selection +option(USE_OPENSSL "Use OpenSSL (default)" ON) + +# Pico build off as default +option(SST_PLATFORM_PICO "Build SST library for Raspberry Pi Pico targets" OFF) + +set(SST_CORE_SOURCES ${CMAKE_CURRENT_LIST_DIR}/c_api.c ${CMAKE_CURRENT_LIST_DIR}/c_common.c ${CMAKE_CURRENT_LIST_DIR}/c_crypto.c ${CMAKE_CURRENT_LIST_DIR}/c_secure_comm.c ${CMAKE_CURRENT_LIST_DIR}/load_config.c - ${CMAKE_CURRENT_LIST_DIR}/ipfs.c) - -set_target_properties(sst-c-api PROPERTIES POSITION_INDEPENDENT_CODE ON) +) -# Statically link OpenSSL into sst-c-api -target_link_libraries(sst-c-api PUBLIC OpenSSL::Crypto OpenSSL::SSL Threads::Threads) +add_library(sst-c-api STATIC ${SST_CORE_SOURCES}) + +# Add crypto backend source files +if(USE_OPENSSL) + target_sources(sst-c-api PRIVATE + ${CMAKE_CURRENT_LIST_DIR}/crypto_openssl.c + ${CMAKE_CURRENT_LIST_DIR}/ipfs.c) + target_compile_definitions(sst-c-api PUBLIC USE_OPENSSL) + find_package(OpenSSL REQUIRED) + target_link_libraries(sst-c-api PUBLIC OpenSSL::Crypto OpenSSL::SSL) + # list(APPEND SST_CORE_SOURCES ${CMAKE_CURRENT_LIST_DIR}/ipfs.c) +elseif(SST_PLATFORM_PICO) + set(FREERTOS_KERNEL_PATH "${CMAKE_CURRENT_LIST_DIR}/embedded/lib/FreeRTOS-Kernel" CACHE PATH "Path to FreeRTOS Kernel" FORCE) + include(${FREERTOS_KERNEL_PATH}/portable/ThirdParty/GCC/RP2040/FreeRTOS_Kernel_import.cmake) + pico_sdk_init() + target_link_libraries(sst-c-api PRIVATE + pico_cyw43_arch_lwip_sys_freertos + pico_stdlib + pico_mbedtls + FreeRTOS-Kernel-Heap4 + ) + target_sources(sst-c-api PRIVATE ${CMAKE_CURRENT_LIST_DIR}/crypto_mbedtls.c) + target_compile_definitions(sst-c-api PUBLIC USE_MBEDTLS) + target_compile_definitions(sst-c-api PUBLIC SST_PLATFORM_PICO) + # Include lwipopts.h & mbedtls_sst_config.h & FreeRTOSConfig.h + target_include_directories(sst-c-api PRIVATE + # ${CMAKE_CURRENT_LIST_DIR} + ${CMAKE_CURRENT_LIST_DIR}/embedded/include + ) +endif() target_include_directories(sst-c-api PUBLIC $ @@ -28,8 +58,11 @@ target_include_directories(sst-c-api PUBLIC # Compiler flags if(MSVC) target_compile_options(sst-c-api PRIVATE /W4 /WX) +elseif(SST_PLATFORM_PICO) + target_compile_options(sst-c-api PRIVATE -Wall -Wextra) elseif(CMAKE_SYSTEM_NAME STREQUAL "Darwin") # Exclude errors, because some can use GNU-specific variadic arguments. This is done for only compiling the SST library. + target_compile_options(sst-c-api PRIVATE -Wall -Wextra) else() target_compile_options(sst-c-api PRIVATE -Wall -Wextra -Wpedantic -Werror) endif() @@ -40,49 +73,43 @@ if(CMAKE_BUILD_TYPE STREQUAL "Debug" OR CMAKE_BUILD_TYPE STREQUAL "DEBUG") target_compile_definitions(sst-c-api PRIVATE DEBUG=1) endif() -# Install the library -# Installs in /usr/local/lib/cmake/sst-lib/sst-libTargets.cmake & sst-libTargets-noconfig.cmake -# Contains target definitions for sst-c-api -# Helps CMake know how to link against sst-c-api - -# sst-libTargets-noconfig.cmake Acts as the entry point for find_package(sst-lib) -# Defines where to look for sst-libTargets.cmake -install(TARGETS sst-c-api - EXPORT sst-libTargets - LIBRARY DESTINATION lib - ARCHIVE DESTINATION lib - RUNTIME DESTINATION bin -) - -# Export targets for find_package() -include(CMakePackageConfigHelpers) - -install( - EXPORT sst-libTargets - FILE sst-libTargets.cmake - NAMESPACE sst-lib:: - DESTINATION lib/cmake/sst-lib -) - -# Creates in /usr/local/lib/cmake/sst-lib/sst-libConfig.cmake -# Acts as the entry point for find_package(sst-lib) -# Defines where to look for sst-libTargets.cmake -configure_package_config_file( - ${CMAKE_CURRENT_SOURCE_DIR}/cmake/sst-libConfig.cmake.in - ${CMAKE_CURRENT_BINARY_DIR}/sst-libConfig.cmake - INSTALL_DESTINATION lib/cmake/sst-lib -) -install( - FILES ${CMAKE_CURRENT_BINARY_DIR}/sst-libConfig.cmake - DESTINATION lib/cmake/sst-lib -) +# Install/export only when not vendoring mbedTLS +if(USE_OPENSSL) + # Install the library and export target + install(TARGETS sst-c-api + EXPORT sst-libTargets + LIBRARY DESTINATION lib + ARCHIVE DESTINATION lib + RUNTIME DESTINATION bin + ) + + include(CMakePackageConfigHelpers) + + install( + EXPORT sst-libTargets + FILE sst-libTargets.cmake + NAMESPACE sst-lib:: + DESTINATION lib/cmake/sst-lib + ) + + configure_package_config_file( + ${CMAKE_CURRENT_SOURCE_DIR}/cmake/sst-libConfig.cmake.in + ${CMAKE_CURRENT_BINARY_DIR}/sst-libConfig.cmake + INSTALL_DESTINATION lib/cmake/sst-lib + ) + install( + FILES ${CMAKE_CURRENT_BINARY_DIR}/sst-libConfig.cmake + DESTINATION lib/cmake/sst-lib + ) +endif() # Install headers install(FILES c_api.h DESTINATION include/sst-c-api) -# Build unit tests -enable_testing() - -add_executable(crypto_test ${CMAKE_CURRENT_SOURCE_DIR}/tests/c_crypto_test.c) -target_link_libraries(crypto_test PRIVATE sst-c-api) -add_test(NAME crypto_test COMMAND crypto_test) +# Build unit tests only for host builds (not Pico SDK) +if(USE_OPENSSL) + enable_testing() + add_executable(crypto_test ${CMAKE_CURRENT_SOURCE_DIR}/tests/c_crypto_test.c) + target_link_libraries(crypto_test PRIVATE sst-c-api) + add_test(NAME crypto_test COMMAND crypto_test) +endif() diff --git a/README.md b/README.md index c7f6d47a..726d04d2 100644 --- a/README.md +++ b/README.md @@ -136,23 +136,7 @@ $sudo make install # Example -- Turn on two different terminals at `$SST_ROOT/entity/c/examples/server_client_example/build`, and turn on Auth on the third terminal. - -Execute - -`$./entity_client ../c_client.config` - -`$./entity_server ../c_server.config` - -on each terminal - -To test AES_128_CTR mode, with noHMAC when exchanging messages, execute - -`$./entity_client ../c_computenode_CTR_noHMAC.config` - -`$./entity_server ../c_compactionnode_CTR_noHMAC.config` - -This will get all keys encrypted in AES_128_CTR mode, and send all messages in CTR mode, with no HMAC. +To run examples, please checkout the [`examples/`](./examples/README.md) directory. # For Developers @@ -168,4 +152,4 @@ This will get all keys encrypted in AES_128_CTR mode, and send all messages in C - Implement an additional API function for extracting session key from cached session keys. -*Last updated on February 2, 2024* +*Last updated on December 5, 2025* diff --git a/c_api.c b/c_api.c index c601c861..85f5c772 100644 --- a/c_api.c +++ b/c_api.c @@ -1,16 +1,18 @@ #include "c_api.h" -#include - #include "c_common.h" #include "c_crypto.h" #include "c_secure_comm.h" #include "load_config.h" SST_ctx_t* init_SST(const char* config_path) { +#ifdef USE_OPENSSL OPENSSL_init_crypto(OPENSSL_INIT_NO_ATEXIT, NULL); +#endif // By default OpenSSL will attempt to clean itself up when the process exits // via an "atexit" handler. Using this option suppresses that behaviour. + // mbed TLS initialization is typically done automatically + // This means that the application will have to clean up OpenSSL explicitly // using OPENSSL_cleanup(). // This is needed because, Lingua Franca uses the "atexit" handler, and @@ -20,15 +22,45 @@ SST_ctx_t* init_SST(const char* config_path) { SST_print_error("Failed to load_config()"); return NULL; } - int numkey = ctx->config.numkey; + SST_print_debug("load_config() success."); + SST_print_debug("=== Config after load_config() ==="); + SST_print_debug(" name: %s", ctx->config.name); + SST_print_debug(" purpose_index: %u", ctx->config.purpose_index); + SST_print_debug(" purpose[0]: %s", ctx->config.purpose[0]); + SST_print_debug(" purpose[1]: %s", ctx->config.purpose[1]); + SST_print_debug(" numkey: %d", ctx->config.numkey); + SST_print_debug(" encryption_mode: %d", ctx->config.encryption_mode); + SST_print_debug(" hmac_mode: %d", ctx->config.hmac_mode); + SST_print_debug(" auth_id: %d", ctx->config.auth_id); + SST_print_debug(" auth_pubkey_path: %s", ctx->config.auth_pubkey_path); + SST_print_debug(" entity_privkey_path: %s", + ctx->config.entity_privkey_path); + SST_print_debug(" auth_ip_addr: %s", ctx->config.auth_ip_addr); + SST_print_debug(" auth_port_num: %d", ctx->config.auth_port_num); + SST_print_debug(" entity_server_ip_addr: %s", + ctx->config.entity_server_ip_addr); + SST_print_debug(" entity_server_port_num: %d", + ctx->config.entity_server_port_num); + SST_print_debug(" file_system_manager_ip_addr: %s", + ctx->config.file_system_manager_ip_addr); + SST_print_debug(" file_system_manager_port_num: %d", + ctx->config.file_system_manager_port_num); + SST_print_debug(" network_protocol: %s", ctx->config.network_protocol); + SST_print_debug("=== End of config dump ==="); + int numkey = ctx->config.numkey; +#ifdef SST_PLATFORM_PICO + ctx->pub_key = (void*)load_auth_public_key(config_path); + ctx->priv_key = (void*)load_entity_private_key(config_path); +#else ctx->pub_key = (void*)load_auth_public_key(ctx->config.auth_pubkey_path); + ctx->priv_key = + (void*)load_entity_private_key(ctx->config.entity_privkey_path); +#endif if (ctx->pub_key == NULL) { SST_print_error("Failed load_auth_public_key()."); return NULL; } - ctx->priv_key = - (void*)load_entity_private_key(ctx->config.entity_privkey_path); if (ctx->priv_key == NULL) { SST_print_error("Failed load_entity_private_key()."); return NULL; @@ -39,10 +71,8 @@ SST_ctx_t* init_SST(const char* config_path) { "session keys are %d", MAX_SESSION_KEY); } - bzero(&ctx->dist_key, sizeof(distribution_key_t)); return ctx; } - session_key_list_t* init_empty_session_key_list(void) { session_key_list_t* session_key_list = malloc(sizeof(session_key_list_t)); session_key_list->num_key = 0; @@ -440,6 +470,7 @@ int decrypt_buf_with_session_key_without_malloc( s_key, encrypted, encrypted_length, decrypted, decrypted_length, 0); } +#ifdef USE_OPENSSL int save_session_key_list(session_key_list_t* session_key_list, const char* file_path) { FILE* saved_file_fp = fopen(file_path, "wb"); @@ -495,8 +526,8 @@ int save_session_key_list_with_password(session_key_list_t* session_key_list, const char* salt, unsigned int salt_len) { // Generate IV. - unsigned char iv[AES_BLOCK_SIZE]; - if (generate_nonce(AES_BLOCK_SIZE, iv) < 0) { + unsigned char iv[AES_128_IV_SIZE]; + if (generate_nonce(AES_128_IV_SIZE, iv) < 0) { SST_print_error("Failed generate_nonce()."); return -1; } @@ -544,7 +575,7 @@ int load_session_key_list_with_password(session_key_list_t* session_key_list, unsigned int password_len, const char* salt, unsigned int salt_len) { - unsigned char iv[AES_BLOCK_SIZE]; + unsigned char iv[AES_128_IV_SIZE]; unsigned char ciphertext[sizeof(session_key_list_t) + sizeof(session_key_t) * MAX_SESSION_KEY]; unsigned char buffer[sizeof(session_key_list_t) + @@ -604,6 +635,8 @@ int load_session_key_list_with_password(session_key_list_t* session_key_list, return 0; } +#endif + unsigned int convert_skid_buf_to_int(unsigned char* buf, int byte_length) { return read_unsigned_int_BE(buf, byte_length); } @@ -624,8 +657,18 @@ void free_session_key_list_t(session_key_list_t* session_key_list) { void free_session_ctx(SST_session_ctx_t* session_ctx) { free(session_ctx); } void free_SST_ctx_t(SST_ctx_t* ctx) { - EVP_PKEY_free((EVP_PKEY*)ctx->priv_key); - EVP_PKEY_free((EVP_PKEY*)ctx->pub_key); + const crypto_backend_t* backend = get_crypto_backend(); + if (backend && backend->free_pkey) { + if (ctx->priv_key) { + backend->free_pkey((crypto_pkey_t*)ctx->priv_key); + ctx->priv_key = NULL; + } + if (ctx->pub_key) { + backend->free_pkey((crypto_pkey_t*)ctx->pub_key); + ctx->pub_key = NULL; + } + } + free(ctx); } @@ -634,7 +677,7 @@ int secure_rand(int min, int max) { unsigned int rand_num; unsigned char buffer[4]; - if (RAND_bytes(buffer, sizeof(buffer)) != 1) { + if (generate_nonce(sizeof(buffer), buffer) != 0) { fprintf(stderr, "RAND_bytes failed"); return -1; // handle error } diff --git a/c_api.h b/c_api.h index d902672a..b3acb367 100644 --- a/c_api.h +++ b/c_api.h @@ -1,8 +1,8 @@ #ifndef C_API_H #define C_API_H -#include -#include +#include +#include #define DIST_KEY_EXPIRATION_TIME_SIZE 6 #define KEY_EXPIRATION_TIME_SIZE 6 @@ -14,6 +14,7 @@ #define MAX_PURPOSE_LENGTH 64 #define NETWORK_PROTOCOL_NAME_LENGTH 4 #define MAX_PATH_LEN 512 +#define IPV4_ADDRSTRLEN 16 #define AES_IV_SIZE 16 #define SEQ_NUM_SIZE 8 @@ -67,12 +68,12 @@ typedef struct { int auth_id; char auth_pubkey_path[MAX_PATH_LEN]; char entity_privkey_path[MAX_PATH_LEN]; - char auth_ip_addr[INET_ADDRSTRLEN]; + char auth_ip_addr[IPV4_ADDRSTRLEN]; int auth_port_num; - char entity_server_ip_addr[INET_ADDRSTRLEN]; + char entity_server_ip_addr[IPV4_ADDRSTRLEN]; int entity_server_port_num; char network_protocol[NETWORK_PROTOCOL_NAME_LENGTH]; - char file_system_manager_ip_addr[INET_ADDRSTRLEN]; + char file_system_manager_ip_addr[IPV4_ADDRSTRLEN]; int file_system_manager_port_num; } config_t; @@ -101,7 +102,6 @@ typedef struct { config_t config; void* pub_key; void* priv_key; - pthread_mutex_t mutex; } SST_ctx_t; // Load config file from path and save the information in ctx struct. diff --git a/c_common.c b/c_common.c index d1a83f49..03614b47 100644 --- a/c_common.c +++ b/c_common.c @@ -1,20 +1,13 @@ #include "c_common.h" -#include #include -#include -#include -#include -#include #include -#include #include #include #include -#include -#include -#include -#include + +#include "crypto_backend.h" +#include "platform_compat.h" void SST_print_debug(const char* fmt, ...) { if (SST_DEBUG_ENABLED) { @@ -80,9 +73,16 @@ void print_buf_log(const unsigned char* buf, size_t size) { SST_print_log("Hex:%s", hex); } +// TODO: Maybe need to move this to crypto. int generate_nonce(int length, unsigned char* buf) { - int x = RAND_bytes(buf, length); - if (x == -1) { + const crypto_backend_t* backend = get_crypto_backend(); + if (!backend) { + SST_print_error("Crypto backend not available"); + return -1; + } + + int result = backend->generate_random(buf, length); + if (result != 0) { SST_print_error("Failed to create Random Nonce"); return -1; } @@ -202,16 +202,24 @@ int read_header_return_data_buf_pointer(int socket, unsigned char* message_type, SST_print_error("Larger buffer size required."); return -1; } - int bytes_read = sst_read_from_socket(socket, buf, ret_length); - if (bytes_read <= 0) { - SST_print_error("Failed to read from socket reading the payload."); - return bytes_read; + unsigned int total_read = 0; + while (total_read < ret_length) { + int bytes_read = sst_read_from_socket(socket, buf + total_read, + ret_length - total_read); + if (bytes_read <= 0) { + SST_print_error( + "Failed to read from socket while reading the payload."); + return bytes_read; + } + total_read += bytes_read; } - if ((unsigned int)bytes_read != ret_length) { - SST_print_error("Wrong read... Exiting.."); + + if (total_read != ret_length) { + SST_print_error("Incomplete read... Exiting.."); return -1; } - return bytes_read; + + return total_read; } // ----------------Header Parsing functions---------------- @@ -275,7 +283,7 @@ int connect_as_client(const char* ip_addr, int port_num, int* sock) { } memset(&serv_addr, 0, sizeof(serv_addr)); serv_addr.sin_family = AF_INET; // IPv4 - if (inet_pton(AF_INET, ip_addr, &serv_addr.sin_addr) != 1) { + if (sst_inet_pton(AF_INET, ip_addr, &serv_addr.sin_addr) != 1) { SST_print_error("invalid IPv4 address: %s", ip_addr); close(*sock); *sock = -1; @@ -299,17 +307,17 @@ int connect_as_client(const char* ip_addr, int port_num, int* sock) { continue; } - SST_print_error("Connection attempt %d failed: %s. Retrying...", + SST_print_error("Connection attempt %d failed. Retrying...", count_retries); close(*sock); *sock = socket(AF_INET, SOCK_STREAM, 0); if (*sock == -1) { - SST_print_error("socket() error during retry: %s"); + SST_print_error("socket() error during retry."); ret = -1; break; } - usleep(50000); + sst_platform_sleep_us(50000); } if (ret < 0) { SST_print_error("Failed to connect to %s:%d after %d attempts.", diff --git a/c_crypto.c b/c_crypto.c index 95e9d092..3c3cf4a6 100644 --- a/c_crypto.c +++ b/c_crypto.c @@ -1,15 +1,19 @@ #include "c_crypto.h" +#include +#include + #include "c_common.h" -// Print OpenSSL crypto error message to stderr with message. +// Print crypto error message to stderr with message. // @param msg Message to print with. static void print_crypto_error(const char* msg) { - char err[MAX_ERROR_MESSAGE_LENGTH]; - - ERR_load_crypto_strings(); - ERR_error_string(ERR_get_error(), err); - printf("%s ERROR: %s\n", msg, err); + const crypto_backend_t* backend = get_crypto_backend(); + if (backend && backend->print_error) { + backend->print_error(msg); + return; + } + SST_print_error("%s", msg); } // Print OpenSSL crypto error message, and return NULL. @@ -19,267 +23,138 @@ static void* print_crypto_error_return_NULL(const char* msg) { return NULL; } -EVP_PKEY* load_auth_public_key(const char* path) { - FILE* pemFile = fopen(path, "rb"); - if (pemFile == NULL) { - printf("Error %d \n", errno); +crypto_pkey_t* load_auth_public_key(const char* path) { + const crypto_backend_t* backend = get_crypto_backend(); + if (!backend) { + return print_crypto_error_return_NULL("Crypto backend not available"); + } + + crypto_pkey_t* pkey = backend->load_public_key(path); + if (!pkey) { return print_crypto_error_return_NULL( "Loading auth_pub_key_path failed"); } - X509* cert = PEM_read_X509(pemFile, NULL, NULL, NULL); - EVP_PKEY* pub_key = X509_get_pubkey(cert); - if (pub_key == NULL) { - return print_crypto_error_return_NULL("public key getting fail"); - } - int id = EVP_PKEY_id(pub_key); - if (id != EVP_PKEY_RSA) { - return print_crypto_error_return_NULL("is not RSA Encryption file"); - } - fclose(pemFile); - X509_free(cert); - return pub_key; + + return (crypto_pkey_t*)pkey; } -EVP_PKEY* load_entity_private_key(const char* path) { - FILE* keyfile = fopen(path, "rb"); - if (keyfile == NULL) { - printf("Error %d \n", errno); +crypto_pkey_t* load_entity_private_key(const char* path) { + const crypto_backend_t* backend = get_crypto_backend(); + if (!backend) { + return print_crypto_error_return_NULL("Crypto backend not available"); + } + + crypto_pkey_t* pkey = backend->load_private_key(path); + if (!pkey) { return print_crypto_error_return_NULL( "Loading entity_priv_key_path failed"); } - EVP_PKEY* priv_key = PEM_read_PrivateKey(keyfile, NULL, NULL, NULL); - fclose(keyfile); - return priv_key; + + return (crypto_pkey_t*)pkey; } unsigned char* public_encrypt(const unsigned char* data, size_t data_len, - int padding, EVP_PKEY* pub_key, size_t* ret_len) { - EVP_PKEY_CTX* ctx; - unsigned char* out = NULL; - - ctx = EVP_PKEY_CTX_new(pub_key, NULL); - if (!ctx) { - return print_crypto_error_return_NULL("EVP_PKEY_CTX_new failed"); - } - if (EVP_PKEY_encrypt_init(ctx) <= 0) { - return print_crypto_error_return_NULL("EVP_PKEY_encrypt_init failed"); - } - if (EVP_PKEY_CTX_set_rsa_padding(ctx, padding) <= 0) { - return print_crypto_error_return_NULL( - "EVP_PKEY_CTX_set_rsa_padding failed"); - } - if (EVP_PKEY_encrypt(ctx, NULL, ret_len, data, data_len) <= 0) { - return print_crypto_error_return_NULL("EVP_PKEY_encrypt failed"); - } - out = (unsigned char*)OPENSSL_malloc(*ret_len); - if (!out) { - return print_crypto_error_return_NULL("OPENSSL_malloc failed"); + crypto_pkey_t* pub_key, size_t* ret_len) { + const crypto_backend_t* backend = get_crypto_backend(); + if (!backend) { + return print_crypto_error_return_NULL("Crypto backend not available"); } - if (EVP_PKEY_encrypt(ctx, out, ret_len, data, data_len) <= 0) { - return print_crypto_error_return_NULL("EVP_PKEY_encrypt failed"); + unsigned char* result = backend->public_encrypt( + data, data_len, (crypto_pkey_t*)pub_key, ret_len); + if (!result) { + return print_crypto_error_return_NULL("Public encryption failed"); } - EVP_PKEY_CTX_free(ctx); - return out; + + return result; } unsigned char* private_decrypt(const unsigned char* enc_data, - size_t enc_data_len, int padding, - EVP_PKEY* priv_key, size_t* ret_len) { - EVP_PKEY_CTX* ctx; - unsigned char* out = NULL; - ctx = EVP_PKEY_CTX_new(priv_key, NULL); - if (!ctx) { - return print_crypto_error_return_NULL("EVP_PKEY_CTX_new failed"); - } - if (EVP_PKEY_decrypt_init(ctx) <= 0) { - return print_crypto_error_return_NULL("EVP_PKEY_decrypt_init failed"); - } - if (EVP_PKEY_CTX_set_rsa_padding(ctx, padding) <= 0) { - return print_crypto_error_return_NULL( - "EVP_PKEY_CTX_set_rsa_padding failed"); - } - if (EVP_PKEY_decrypt(ctx, NULL, ret_len, enc_data, enc_data_len) <= 0) { - return print_crypto_error_return_NULL("EVP_PKEY_decrypt failed"); - } - out = (unsigned char*)OPENSSL_malloc(*ret_len); - if (!out) { - return print_crypto_error_return_NULL("OPENSSL_malloc failed"); + size_t enc_data_len, crypto_pkey_t* priv_key, + size_t* ret_len) { + const crypto_backend_t* backend = get_crypto_backend(); + if (!backend) { + return print_crypto_error_return_NULL("Crypto backend not available"); } - if (EVP_PKEY_decrypt(ctx, out, ret_len, enc_data, enc_data_len) <= 0) { - return print_crypto_error_return_NULL("EVP_PKEY_decrypt failed"); + + unsigned char* result = backend->private_decrypt( + enc_data, enc_data_len, (crypto_pkey_t*)priv_key, ret_len); + if (!result) { + return print_crypto_error_return_NULL("Private decryption failed"); } - EVP_PKEY_CTX_free(ctx); - return out; + + return result; } unsigned char* SHA256_sign(const unsigned char* encrypted, - unsigned int encrypted_length, EVP_PKEY* priv_key, - size_t* sig_length) { - unsigned char md[SHA256_DIGEST_LENGTH]; - unsigned int md_length; - if (digest_message_SHA_256(encrypted, encrypted_length, md, &md_length) < - 0) { - return print_crypto_error_return_NULL( - "Failed digest_message_SHA_256()."); - } - EVP_PKEY_CTX* ctx; - unsigned char* sig = NULL; - ctx = EVP_PKEY_CTX_new(priv_key, NULL); - if (!ctx) { - return print_crypto_error_return_NULL("EVP_PKEY_CTX_new failed"); - } - if (EVP_PKEY_sign_init(ctx) <= 0) { - return print_crypto_error_return_NULL("EVP_PKEY_sign_init failed"); - } - if (EVP_PKEY_CTX_set_rsa_padding(ctx, RSA_PKCS1_PADDING) <= 0) { - return print_crypto_error_return_NULL( - "EVP_PKEY_CTX_set_rsa_padding failed"); - } - if (EVP_PKEY_CTX_set_signature_md(ctx, EVP_sha256()) <= 0) { - return print_crypto_error_return_NULL( - "EVP_PKEY_CTX_set_signature_md failed"); + unsigned int encrypted_length, + crypto_pkey_t* priv_key, size_t* sig_length) { + const crypto_backend_t* backend = get_crypto_backend(); + if (!backend) { + return print_crypto_error_return_NULL("Crypto backend not available"); } - if (EVP_PKEY_sign(ctx, NULL, sig_length, md, md_length) <= 0) { - return print_crypto_error_return_NULL("EVP_PKEY_sign failed"); - } - sig = (unsigned char*)OPENSSL_malloc(*sig_length); - if (!sig) { - return print_crypto_error_return_NULL("OPENSSL_malloc failed"); - } - if (EVP_PKEY_sign(ctx, sig, sig_length, md, md_length) <= 0) { - return print_crypto_error_return_NULL("EVP_PKEY_sign failed"); + unsigned char* result = backend->sign_sha256( + encrypted, encrypted_length, (crypto_pkey_t*)priv_key, sig_length); + if (!result) { + return print_crypto_error_return_NULL("SHA256 signing failed"); } - EVP_PKEY_CTX_free(ctx); - return sig; + return result; } int SHA256_verify(const unsigned char* data, unsigned int data_length, - unsigned char* sig, size_t sig_length, EVP_PKEY* pub_key) { - EVP_PKEY_CTX* ctx; - unsigned char md[SHA256_DIGEST_LENGTH]; - unsigned int md_len; - if (digest_message_SHA_256(data, data_length, md, &md_len) < 0) { - print_crypto_error("Failed digest_message_SHA_256()."); + unsigned char* sig, size_t sig_length, + crypto_pkey_t* pub_key) { + const crypto_backend_t* backend = get_crypto_backend(); + if (!backend) { + print_crypto_error("Crypto backend not available"); return -1; } - ctx = EVP_PKEY_CTX_new(pub_key, NULL); - if (!ctx) { - print_crypto_error("EVP_PKEY_CTX_new failed"); - return -1; - } - if (EVP_PKEY_verify_init(ctx) <= 0) { - print_crypto_error("EVP_PKEY_verify_init failed"); + int result = backend->verify_sha256(data, data_length, sig, sig_length, + (crypto_pkey_t*)pub_key); + if (result != 0) { + print_crypto_error("SHA256 verification failed"); return -1; } - if (EVP_PKEY_CTX_set_rsa_padding(ctx, RSA_PKCS1_PADDING) <= 0) { - print_crypto_error("EVP_PKEY_CTX_set_rsa_padding failed"); - return -1; - } - if (EVP_PKEY_CTX_set_signature_md(ctx, EVP_sha256()) <= 0) { - print_crypto_error("EVP_PKEY_CTX_set_signature_md failed"); - return -1; - } - if (EVP_PKEY_verify(ctx, sig, sig_length, md, md_len) != 1) { - print_crypto_error("EVP_PKEY_verify failed"); - return -1; - } - EVP_PKEY_CTX_free(ctx); + return 0; } int digest_message_SHA_256(const unsigned char* data, size_t data_len, unsigned char* md5_hash, unsigned int* md_len) { - EVP_MD_CTX* mdctx; - - if ((mdctx = EVP_MD_CTX_create()) == NULL) { - print_crypto_error("EVP_MD_CTX_create() failed"); + const crypto_backend_t* backend = get_crypto_backend(); + if (!backend) { + print_crypto_error("Crypto backend not available"); return -1; } - if (EVP_DigestInit_ex(mdctx, EVP_sha256(), NULL) != 1) { - print_crypto_error("EVP_DigestInit_ex failed"); - return -1; - } - if (EVP_DigestUpdate(mdctx, data, data_len) != 1) { - print_crypto_error("EVP_DigestUpdate failed"); - return -1; - } - if (EVP_DigestFinal_ex(mdctx, md5_hash, md_len) != 1) { - print_crypto_error("failed"); + + int result = backend->digest_sha256(data, data_len, md5_hash, md_len); + if (result != 0) { + print_crypto_error("SHA256 digest failed"); return -1; } - EVP_MD_CTX_destroy(mdctx); - return 0; -} -// Get OpenSSL EVP_CIPHER structure corresponding to the given encryption mode. -// @param enc_mode AES encryption mode enum (e.g., AES_128_CBC) -// @return OpenSSL EVP_CIPHER*, or NULL if unsupported -static const EVP_CIPHER* get_EVP_CIPHER(AES_encryption_mode_t enc_mode) { - if (enc_mode == AES_128_CBC) { - return EVP_aes_128_cbc(); - } else if (enc_mode == AES_128_CTR) { - return EVP_aes_128_ctr(); - } else if (enc_mode == AES_128_GCM) { - return EVP_aes_128_gcm(); - } else { - SST_print_error("Encryption type not supported."); - } - return NULL; + return 0; } int encrypt_AES(const unsigned char* plaintext, unsigned int plaintext_length, const unsigned char* key, const unsigned char* iv, AES_encryption_mode_t enc_mode, unsigned char* ret, unsigned int* ret_length) { - EVP_CIPHER_CTX* ctx = EVP_CIPHER_CTX_new(); - if (!EVP_EncryptInit_ex(ctx, get_EVP_CIPHER(enc_mode), NULL, key, iv)) { - // Error - EVP_CIPHER_CTX_free(ctx); - print_crypto_error("EVP_EncryptInit_ex failed"); + const crypto_backend_t* backend = get_crypto_backend(); + if (!backend) { + print_crypto_error("Crypto backend not available"); return -1; } - if (enc_mode == AES_128_GCM) { - if (!EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_SET_IVLEN, - AES_128_GCM_IV_SIZE, - NULL)) { // Set IV length to 12 bytes - EVP_CIPHER_CTX_free(ctx); - print_crypto_error("EVP_CIPHER_CTX_ctrl (SET_IVLEN) failed"); - return -1; - } - } - - if (!EVP_EncryptUpdate(ctx, ret, (int*)ret_length, plaintext, - plaintext_length)) { - EVP_CIPHER_CTX_free(ctx); - print_crypto_error("EVP_EncryptUpdate failed"); + int result = backend->encrypt_aes(plaintext, plaintext_length, key, iv, + enc_mode, ret, ret_length); + if (result != 0) { + print_crypto_error("AES encryption failed"); return -1; } - - unsigned int temp_len; - if (!EVP_EncryptFinal_ex(ctx, ret + *ret_length, (int*)&temp_len)) { - EVP_CIPHER_CTX_free(ctx); - print_crypto_error("EVP_EncryptFinal_ex failed"); - return -1; - } - *ret_length += temp_len; - - if (enc_mode == AES_128_GCM) { - // Append the GCM authentication tag to the end of the ciphertext - if (!EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_GET_TAG, AES_GCM_TAG_SIZE, - ret + *ret_length)) { // 16 bytes tag - EVP_CIPHER_CTX_free(ctx); - print_crypto_error("EVP_CIPHER_CTX_ctrl (GET_TAG) failed"); - return -1; - } - *ret_length += AES_GCM_TAG_SIZE; // Increase the length by the tag size - } - - EVP_CIPHER_CTX_free(ctx); return 0; } @@ -287,54 +162,19 @@ int decrypt_AES(const unsigned char* encrypted, unsigned int encrypted_length, const unsigned char* key, const unsigned char* iv, AES_encryption_mode_t enc_mode, unsigned char* ret, unsigned int* ret_length) { - EVP_CIPHER_CTX* ctx = EVP_CIPHER_CTX_new(); - if (!EVP_DecryptInit_ex(ctx, get_EVP_CIPHER(enc_mode), NULL, key, iv)) { - EVP_CIPHER_CTX_free(ctx); - print_crypto_error("EVP_DecryptInit_ex failed"); + const crypto_backend_t* backend = get_crypto_backend(); + if (!backend) { + print_crypto_error("Crypto backend not available"); return -1; } - if (enc_mode == AES_128_GCM) { - if (!EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_SET_IVLEN, - AES_128_GCM_IV_SIZE, - NULL)) { // Set IV length to 12 bytes - EVP_CIPHER_CTX_free(ctx); - print_crypto_error("EVP_CIPHER_CTX_ctrl (SET_IVLEN) failed"); - return -1; - } - - // Set the expected tag value by extracting it from the end of the - // ciphertext - unsigned char* tag = - (unsigned char*)encrypted + encrypted_length - - AES_GCM_TAG_SIZE; // Get the last 16 bytes as the tag - if (!EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_SET_TAG, AES_GCM_TAG_SIZE, - tag)) { - EVP_CIPHER_CTX_free(ctx); - print_crypto_error("EVP_CIPHER_CTX_ctrl (SET_TAG) failed"); - return -1; - } - - encrypted_length -= - AES_GCM_TAG_SIZE; // Adjust the encrypted length to exclude the tag - } - - if (!EVP_DecryptUpdate(ctx, ret, (int*)ret_length, encrypted, - encrypted_length)) { - EVP_CIPHER_CTX_free(ctx); - print_crypto_error("EVP_DecryptUpdate failed"); + int result = backend->decrypt_aes(encrypted, encrypted_length, key, iv, + enc_mode, ret, ret_length); + if (result != 0) { + print_crypto_error("AES decryption failed"); return -1; } - unsigned int temp_len; - if (!EVP_DecryptFinal_ex(ctx, ret + *ret_length, (int*)&temp_len)) { - EVP_CIPHER_CTX_free(ctx); - print_crypto_error("EVP_DecryptFinal_ex failed"); - return -1; - } - *ret_length += temp_len; - - EVP_CIPHER_CTX_free(ctx); return 0; } @@ -397,9 +237,19 @@ static int get_symmetric_encrypt_authenticate_buffer( if (hmac_mode == USE_HMAC) { // Attach HMAC tag if (mac_key_size == MAC_KEY_SHA256_SIZE) { - HMAC(EVP_sha256(), mac_key, mac_key_size, ret, total_length, - ret + total_length, &mac_key_size); - total_length += mac_key_size; + const crypto_backend_t* backend = get_crypto_backend(); + if (!backend) { + SST_print_error("Crypto backend not available."); + return -1; + } + + unsigned int hmac_len = 0; + if (backend->hmac_sha256(mac_key, mac_key_size, ret, total_length, + ret + total_length, &hmac_len) != 0) { + SST_print_error("HMAC generation failed."); + return -1; + } + total_length += hmac_len; } // Add other MAC key sizes in future. else { @@ -450,8 +300,19 @@ static int get_symmetric_decrypt_authenticate_buffer( unsigned char reproduced_tag[mac_key_size]; encrypted_length -= mac_key_size; if (mac_key_size == MAC_KEY_SHA256_SIZE) { - HMAC(EVP_sha256(), mac_key, mac_key_size, buf, - iv_size + encrypted_length, reproduced_tag, &mac_key_size); + const crypto_backend_t* backend = get_crypto_backend(); + if (!backend) { + SST_print_error("Crypto backend not available."); + return -1; + } + + unsigned int hmac_len = 0; + if (backend->hmac_sha256(mac_key, mac_key_size, buf, + iv_size + encrypted_length, reproduced_tag, + &hmac_len) != 0) { + SST_print_error("HMAC verification failed."); + return -1; + } } else { SST_print_error("HMAC_key_size is not supported."); return -1; diff --git a/c_crypto.h b/c_crypto.h index 21742f12..60f3d84c 100644 --- a/c_crypto.h +++ b/c_crypto.h @@ -1,21 +1,8 @@ #ifndef C_CRYPTO_H #define C_CRYPTO_H -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - #include "c_api.h" +#include "crypto_backend.h" #define AES_128_KEY_SIZE_IN_BYTES 16 #define AES_128_IV_SIZE 16 @@ -32,11 +19,6 @@ #define RSA_ENCRYPT_SIGN_SIZE RSA_KEY_SIZE * 2 #define SHA256_DIGEST_LENGTH 32 -// Encryption Mode // -// #define AES_128_CBC 101 -// #define AES_128_CTR 102 -// #define AES_128_GCM 103 - // Struct for digital signature typedef struct { unsigned char data[RSA_KEY_SIZE]; @@ -45,57 +27,52 @@ typedef struct { // Loads auth's public key from path // @param path path of auth's public key -EVP_PKEY* load_auth_public_key(const char* path); +crypto_pkey_t* load_auth_public_key(const char* path); // Loads entity's private key from path // @param path path of entity's private key -EVP_PKEY* load_entity_private_key(const char* path); +crypto_pkey_t* load_entity_private_key(const char* path); -// Encrypt the message with public key using public key encryption from OpenSSL. +// Encrypt the message with public key using public key encryption. // @param data message for public key encryption // @param data_len length of message -// @param padding set of padding , 1 if padding is used, 0 if not used. -// padding prevents an attacker from knowing the exact length of the plaintext -// message. -// @param path protected key path +// @param pub_key public key // @param ret_len length of encrypted message // @return encrypted message from public key encryption unsigned char* public_encrypt(const unsigned char* data, size_t data_len, - int padding, EVP_PKEY* pub_key, size_t* ret_len); + crypto_pkey_t* pub_key, size_t* ret_len); -// Decrypt message with private key using private key decryption from OpenSSL. +// Decrypt message with private key using private key decryption. // @param enc_data encrypted message for private key decryption // @param enc_data_len length of encrypted message -// @param padding set of padding , 1 if padding is used, 0 if not used. -// padding prevents an attacker from knowing the exact length of the plaintext -// message. -// @param path private key path +// @param priv_key private key // @param ret_len length of decrypted message // @return decrypted message from private key decryption unsigned char* private_decrypt(const unsigned char* enc_data, - size_t enc_data_len, int padding, - EVP_PKEY* priv_key, size_t* ret_len); + size_t enc_data_len, crypto_pkey_t* priv_key, + size_t* ret_len); // After digest the encrypted message, sign digested message -// with private key using private key signature from OpenSSL. +// with private key using private key signature. // @param encrypted encrypted message to sign // @param encrypted_length length of encrypted message -// @param path private key path for private key signature +// @param priv_key private key for private key signature // @param sig_length length of signed buffer // @return sign sign of the encrypted message unsigned char* SHA256_sign(const unsigned char* encrypted, - unsigned int encrypted_length, EVP_PKEY* priv_key, - size_t* sig_length); + unsigned int encrypted_length, + crypto_pkey_t* priv_key, size_t* sig_length); // Verification of encrypted data and signature -// using the RSA verification from OpenSSL. +// using the RSA verification. // @param data encrypted data // @param data_length length of encrypted data -// @param sign signature buffer -// @param sign_length length of signiture -// @param path public key path +// @param sig signature buffer +// @param sig_length length of signature +// @param pub_key public key int SHA256_verify(const unsigned char* data, unsigned int data_length, - unsigned char* sig, size_t sig_length, EVP_PKEY* pub_key); + unsigned char* sig, size_t sig_length, + crypto_pkey_t* pub_key); // Digest the message using the SHA256 digest function. // @param data Data to digest diff --git a/c_secure_comm.c b/c_secure_comm.c index b535ac85..8c9689cb 100644 --- a/c_secure_comm.c +++ b/c_secure_comm.c @@ -1,9 +1,11 @@ #include "c_secure_comm.h" -#include +#include +#include #include "c_common.h" #include "c_crypto.h" +#include "platform_compat.h" typedef enum { INIT, @@ -87,15 +89,14 @@ static unsigned char* encrypt_and_sign(unsigned char* buf, unsigned int buf_len, unsigned int* message_length) { size_t encrypted_length; unsigned char* encrypted = - public_encrypt(buf, buf_len, RSA_PKCS1_OAEP_PADDING, - (EVP_PKEY*)ctx->pub_key, &encrypted_length); + public_encrypt(buf, buf_len, (void*)ctx->pub_key, &encrypted_length); if (encrypted == NULL) { SST_print_error("Failed public_encrypt()."); return NULL; } size_t sigret_length; - unsigned char* sigret = SHA256_sign( - encrypted, encrypted_length, (EVP_PKEY*)ctx->priv_key, &sigret_length); + unsigned char* sigret = SHA256_sign(encrypted, encrypted_length, + (void*)ctx->priv_key, &sigret_length); if (sigret == NULL) { SST_print_error("Failed SHA256_sign()."); return NULL; @@ -104,8 +105,8 @@ static unsigned char* encrypt_and_sign(unsigned char* buf, unsigned int buf_len, unsigned char* message = (unsigned char*)malloc(*message_length); memcpy(message, encrypted, encrypted_length); memcpy(message + encrypted_length, sigret, sigret_length); - OPENSSL_free(encrypted); - OPENSSL_free(sigret); + free(encrypted); + free(sigret); return message; } @@ -144,7 +145,7 @@ static unsigned char* serialize_session_key_req_with_distribution_key( memcpy(ret + offset, name, name_length); offset += name_length; memcpy(ret + offset, temp, temp_length); - OPENSSL_free(temp); + free(temp); *ret_length = 1 + strlen(name) + temp_length; return ret; } @@ -153,7 +154,7 @@ static unsigned char* serialize_session_key_req_with_distribution_key( // @param abs_validity_ms Expiration time in ms (uint64_t). // @return -1 when expired, 0 when still valid. static int check_validity(uint64_t abs_validity_ms) { - uint64_t current_ms = (uint64_t)time(NULL) * 1000ULL; // seconds → ms + uint64_t current_ms = sst_platform_now_ms(); return (current_ms >= abs_validity_ms) ? -1 : 0; } @@ -300,7 +301,9 @@ static int check_session_key_validity(session_key_t* session_key) { // @return -1 when expired, 0 when valid static int check_distribution_key_validity(distribution_key_t* dist_key) { int ret = check_validity(dist_key->abs_validity); - SST_print_debug("Distribution key expired!"); + if (ret < 0) { + SST_print_debug("Distribution key expired!"); + } return ret; } @@ -342,7 +345,7 @@ static int send_auth_request_message(unsigned char* serialized, SST_print_error("Failed sst_write_to_socket()."); return -1; } - OPENSSL_free(enc); + free(enc); } else { unsigned int enc_length; unsigned char* enc = serialize_session_key_req_with_distribution_key( @@ -369,7 +372,7 @@ static int send_auth_request_message(unsigned char* serialized, return -1; } - OPENSSL_free(enc); + free(enc); } return 0; } @@ -384,7 +387,7 @@ int handle_AUTH_HELLO(unsigned char* data_buf, SST_ctx_t* ctx, return -1; } memcpy(auth_nonce, data_buf + AUTH_ID_LEN, NONCE_SIZE); - RAND_bytes(entity_nonce, NONCE_SIZE); + generate_nonce(NONCE_SIZE, entity_nonce); unsigned int serialized_length; unsigned char* serialized = serialize_message_for_auth( entity_nonce, auth_nonce, num_key, ctx->config.name, purpose, @@ -407,7 +410,7 @@ int save_distribution_key(unsigned char* data_buf, SST_ctx_t* ctx, // verify if (SHA256_verify(signed_data.data, key_size, signed_data.sign, key_size, - (EVP_PKEY*)ctx->pub_key) < 0) { + (void*)ctx->pub_key) < 0) { SST_print_error("Failed SHA256_verify()."); return -1; } @@ -415,9 +418,9 @@ int save_distribution_key(unsigned char* data_buf, SST_ctx_t* ctx, // decrypt encrypted_distribution_key size_t decrypted_dist_key_buf_length; - unsigned char* decrypted_dist_key_buf = private_decrypt( - signed_data.data, key_size, RSA_PKCS1_OAEP_PADDING, - (EVP_PKEY*)ctx->priv_key, &decrypted_dist_key_buf_length); + unsigned char* decrypted_dist_key_buf = + private_decrypt(signed_data.data, key_size, (void*)ctx->priv_key, + &decrypted_dist_key_buf_length); if (decrypted_dist_key_buf == NULL) { SST_print_error("Failed private_decrypt()."); return -1; @@ -433,7 +436,7 @@ int save_distribution_key(unsigned char* data_buf, SST_ctx_t* ctx, unsigned char* parse_handshake_1(session_key_t* s_key, unsigned char* entity_nonce, unsigned int* ret_length) { - RAND_bytes(entity_nonce, HS_NONCE_SIZE); + generate_nonce(HS_NONCE_SIZE, entity_nonce); unsigned char indicator_entity_nonce[1 + HS_NONCE_SIZE]; memcpy(indicator_entity_nonce + 1, entity_nonce, HS_NONCE_SIZE); indicator_entity_nonce[0] = 1; @@ -804,7 +807,7 @@ unsigned char* check_handshake1_send_handshake2( SST_print_debug("Client's nonce: "); print_buf_debug(hs.nonce, HS_NONCE_SIZE); - RAND_bytes(server_nonce, HS_NONCE_SIZE); + generate_nonce(HS_NONCE_SIZE, server_nonce); SST_print_debug("Server's nonce: "); print_buf_debug(server_nonce, HS_NONCE_SIZE); @@ -892,7 +895,7 @@ void append_session_key_list(session_key_list_t* dest, void update_validity(session_key_t* session_key) { session_key->abs_validity = - ((uint64_t)time(NULL) * 1000) + session_key->rel_validity; + sst_platform_now_ms() + session_key->rel_validity; } int check_session_key_list_addable(int requested_num_key, diff --git a/crypto_backend.h b/crypto_backend.h new file mode 100644 index 00000000..10d7a748 --- /dev/null +++ b/crypto_backend.h @@ -0,0 +1,89 @@ +#ifndef CRYPTO_BACKEND_H +#define CRYPTO_BACKEND_H + +#include +#include + +#include "c_api.h" + +// Forward declarations for crypto backend types +#ifdef USE_OPENSSL +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +typedef EVP_PKEY crypto_pkey_t; + +#elif defined(USE_MBEDTLS) +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +typedef mbedtls_pk_context crypto_pkey_t; + +#endif + +// Common crypto backend interface +typedef struct { + crypto_pkey_t* (*load_public_key)(const char* path); + crypto_pkey_t* (*load_private_key)(const char* path); + void (*free_pkey)(crypto_pkey_t* pkey); + // Backend-specific error printer + void (*print_error)(const char* msg); + + unsigned char* (*public_encrypt)(const unsigned char* data, size_t data_len, + crypto_pkey_t* pub_key, size_t* ret_len); + unsigned char* (*private_decrypt)(const unsigned char* enc_data, + size_t enc_data_len, + crypto_pkey_t* priv_key, size_t* ret_len); + + unsigned char* (*sign_sha256)(const unsigned char* data, + unsigned int data_length, + crypto_pkey_t* priv_key, size_t* sig_length); + int (*verify_sha256)(const unsigned char* data, unsigned int data_length, + unsigned char* sig, size_t sig_length, + crypto_pkey_t* pub_key); + + int (*digest_sha256)(const unsigned char* data, size_t data_len, + unsigned char* hash, unsigned int* hash_len); + + int (*encrypt_aes)(const unsigned char* plaintext, + unsigned int plaintext_length, const unsigned char* key, + const unsigned char* iv, AES_encryption_mode_t enc_mode, + unsigned char* ret, unsigned int* ret_length); + int (*decrypt_aes)(const unsigned char* encrypted, + unsigned int encrypted_length, const unsigned char* key, + const unsigned char* iv, AES_encryption_mode_t enc_mode, + unsigned char* ret, unsigned int* ret_length); + + int (*generate_random)(unsigned char* buf, int length); + + // HMAC functions + int (*hmac_sha256)(const unsigned char* key, size_t key_len, + const unsigned char* data, size_t data_len, + unsigned char* output, unsigned int* output_len); +} crypto_backend_t; + +// Get the appropriate crypto backend +const crypto_backend_t* get_crypto_backend(void); + +#endif // CRYPTO_BACKEND_H diff --git a/crypto_mbedtls.c b/crypto_mbedtls.c new file mode 100644 index 00000000..82bb0562 --- /dev/null +++ b/crypto_mbedtls.c @@ -0,0 +1,1004 @@ +#include +#include + +#ifdef USE_MBEDTLS + +#include +#include +#include + +#include "c_api.h" +#include "c_common.h" +#include "c_crypto.h" +#include "crypto_backend.h" + +static mbedtls_entropy_context g_entropy; +static mbedtls_ctr_drbg_context g_ctr_drbg; +static int g_rng_ready = 0; + +// mbed TLS implementation of crypto backend + +static void mbedtls_print_error(const char* msg) { + SST_print_error("%s ERROR: mbed TLS crypto error", msg); +} + +static void mbedtls_print_error_with_code(const char* msg, int error_code) { + char error_buf[256]; + mbedtls_strerror(error_code, error_buf, sizeof(error_buf)); + SST_print_error("%s ERROR: %s (code: 0x%x)", msg, error_buf, error_code); +} + +// Extract a PEM block between given BEGIN/END markers from an in-memory text +// blob. On success, returns 0 and sets *pem_start/*pem_len to point inside +// `text`. +static int find_pem_block(const char* text, const char* begin_marker, + const char* end_marker, + const unsigned char** pem_start, size_t* pem_len) { + if (!text || !begin_marker || !end_marker || !pem_start || !pem_len) + return -1; + const char* begin = strstr(text, begin_marker); + if (!begin) return -1; + const char* end = strstr(begin, end_marker); + if (!end) return -1; + end += strlen(end_marker); // include END line + *pem_start = (const unsigned char*)begin; + *pem_len = (size_t)(end - begin); + + SST_print_debug("[find_pem_block] begin offset: %ld", (long)(begin - text)); + SST_print_debug("[find_pem_block] end offset: %ld", (long)(end - text)); + SST_print_debug("[find_pem_block] pem_len: %zu", *pem_len); + + + SST_print_debug("[find_pem_block] PEM full:\n%.*s", (int)*pem_len, + (const char*)*pem_start); + + return 0; +} + +static crypto_pkey_t* mbedtls_load_public_key(const char* config_blob) { + // Treat the input string as an in-memory configuration blob that contains a + // PEM certificate + const unsigned char* pem = NULL; + size_t pem_len = 0; + if (find_pem_block(config_blob, "-----BEGIN CERTIFICATE-----", + "-----END CERTIFICATE-----", &pem, &pem_len) != 0) { + SST_print_error("Public cert PEM not found in provided config text"); + return NULL; + } + + unsigned char* pem_buf = malloc(pem_len + 1); + if (!pem_buf) { + SST_print_error("malloc(pem_buf) failed"); + return NULL; + } + memcpy(pem_buf, pem, pem_len); + pem_buf[pem_len] = '\0'; + + mbedtls_x509_crt crt; + mbedtls_x509_crt_init(&crt); + + int ret = mbedtls_x509_crt_parse(&crt, pem_buf, pem_len + 1); + free(pem_buf); + + if (ret != 0) { + mbedtls_print_error_with_code("Failed to parse in-memory certificate", + ret); + mbedtls_x509_crt_free(&crt); + return NULL; + } + + mbedtls_pk_context* pk = malloc(sizeof(mbedtls_pk_context)); + if (!pk) { + mbedtls_x509_crt_free(&crt); + SST_print_error("malloc(mbedtls_pk_context) failed"); + return NULL; + } + mbedtls_pk_init(pk); + + // Move (copy) the public key from the certificate into our own context + *pk = crt.pk; // struct copy + memset(&crt.pk, 0, sizeof(crt.pk)); // avoid double-free + mbedtls_x509_crt_free(&crt); + + return pk; +} + +static crypto_pkey_t* mbedtls_load_private_key(const char* config_blob) { + // Treat the input string as an in-memory configuration blob that contains a + // PEM private key + const unsigned char* pem = NULL; + size_t pem_len = 0; + if (find_pem_block(config_blob, "-----BEGIN PRIVATE KEY-----", + "-----END PRIVATE KEY-----", &pem, &pem_len) != 0) { + SST_print_error("Private key PEM not found in provided config text"); + return NULL; + } + + unsigned char* pem_buf = malloc(pem_len + 1); + if (!pem_buf) { + SST_print_error("malloc(pem_buf) failed"); + return NULL; + } + memcpy(pem_buf, pem, pem_len); + pem_buf[pem_len] = '\0'; + + mbedtls_pk_context* pk = malloc(sizeof(mbedtls_pk_context)); + if (!pk) { + SST_print_error("malloc(mbedtls_pk_context) failed"); + return NULL; + } + mbedtls_pk_init(pk); + + // If your key is password-protected, pass the password bytes and length + // below instead of NULLs. + int ret = + mbedtls_pk_parse_key(pk, pem_buf, pem_len + 1, NULL, 0, // no password + mbedtls_ctr_drbg_random, &g_ctr_drbg); + free(pem_buf); + if (ret != 0) { + mbedtls_print_error_with_code("Failed to parse in-memory private key", + ret); + mbedtls_pk_free(pk); + free(pk); + return NULL; + } + + return pk; +} + +static void mbedtls_free_pkey(crypto_pkey_t* pkey) { + if (pkey) { + mbedtls_pk_free(pkey); + free(pkey); + } +} + +static int crypto_mbedtls_rng_init_once(void) { + if (g_rng_ready) return 0; + + mbedtls_entropy_init(&g_entropy); + mbedtls_ctr_drbg_init(&g_ctr_drbg); + + const char* pers = "crypto_mbedtls_rng"; + int ret = + mbedtls_ctr_drbg_seed(&g_ctr_drbg, mbedtls_entropy_func, &g_entropy, + (const unsigned char*)pers, strlen(pers)); + if (ret != 0) { + mbedtls_print_error_with_code("Failed to seed global CTR-DRBG", ret); + mbedtls_ctr_drbg_free(&g_ctr_drbg); + mbedtls_entropy_free(&g_entropy); + return ret; + } + + g_rng_ready = 1; + return 0; +} + +static unsigned char* mbedtls_public_encrypt(const unsigned char* data, + size_t data_len, + crypto_pkey_t* pub_key, + size_t* ret_len) { + if (!data || data_len == 0 || !pub_key || !ret_len) { + errno = EINVAL; + SST_print_error("mbedtls_public_encrypt invalid arguments"); + return NULL; + } + if (!mbedtls_pk_can_do(pub_key, MBEDTLS_PK_RSA)) { + SST_print_error("mbedtls_public_encrypt expects an RSA public key"); + return NULL; + } + + // 1) Initialize global RNG once (no per-call seeding) + int ret = crypto_mbedtls_rng_init_once(); + if (ret != 0) { + SST_print_error("Global RNG not ready"); + return NULL; + } + + // 2) Force OAEP padding (OpenSSL compatibility) + mbedtls_rsa_context* rsa = mbedtls_pk_rsa(*pub_key); + // Set OAEP (PKCS#1 v2.1) with SHA-1 to mirror OpenSSL's + // RSA_PKCS1_OAEP_PADDING default + ret = mbedtls_rsa_set_padding(rsa, MBEDTLS_RSA_PKCS_V21, MBEDTLS_MD_SHA1); + if (ret != 0) { + mbedtls_print_error_with_code("Failed to set RSA OAEP padding", ret); + return NULL; + } + + // 3) Allocate ciphertext buffer of modulus size + const size_t key_size = (mbedtls_pk_get_bitlen(pub_key) + 7) / 8; + unsigned char* out = (unsigned char*)malloc(key_size); + if (!out) { + SST_print_error("malloc(ciphertext) failed"); + return NULL; + } + + // 4) Encrypt (OAEP uses RNG internally) + size_t out_len = 0; + ret = mbedtls_pk_encrypt(pub_key, data, data_len, out, &out_len, key_size, + mbedtls_ctr_drbg_random, &g_ctr_drbg); + if (ret != 0) { + mbedtls_print_error_with_code("Failed to encrypt with public key", ret); + free(out); + return NULL; + } + + *ret_len = out_len; // equals key_size for RSA + return out; +} + +static unsigned char* mbedtls_private_decrypt(const unsigned char* enc_data, + size_t enc_data_len, + crypto_pkey_t* priv_key, + size_t* ret_len) { + // Validate arguments + if (!enc_data || enc_data_len == 0 || !priv_key || !ret_len) { + errno = EINVAL; + SST_print_error("mbedtls_private_decrypt invalid arguments"); + return NULL; + } + + // Ensure RSA private key + if (!mbedtls_pk_can_do(priv_key, MBEDTLS_PK_RSA)) { + SST_print_error("mbedtls_private_decrypt expects an RSA private key"); + return NULL; + } + + // Initialize global RNG once (used for RSA blinding in private ops) + int ret = crypto_mbedtls_rng_init_once(); + if (ret != 0) { + SST_print_error("Global RNG not ready"); + return NULL; + } + + // Force OAEP padding (to mirror OpenSSL's RSA_PKCS1_OAEP_PADDING) + mbedtls_rsa_context* rsa = mbedtls_pk_rsa(*priv_key); + // Set OAEP (PKCS#1 v2.1) with SHA-1 to mirror OpenSSL's + // RSA_PKCS1_OAEP_PADDING default + ret = mbedtls_rsa_set_padding(rsa, MBEDTLS_RSA_PKCS_V21, MBEDTLS_MD_SHA1); + if (ret != 0) { + mbedtls_print_error_with_code("Failed to set RSA OAEP padding", ret); + return NULL; + } + + // Allocate output buffer: maximum possible plaintext size is key_size + const size_t key_size = (mbedtls_pk_get_bitlen(priv_key) + 7) / 8; + unsigned char* out = (unsigned char*)malloc(key_size); + if (!out) { + SST_print_error("malloc(plaintext) failed"); + return NULL; + } + + // Decrypt (RSA private op may use RNG for blinding → pass DRBG) + size_t out_len = 0; + ret = mbedtls_pk_decrypt(priv_key, enc_data, enc_data_len, out, &out_len, + key_size, mbedtls_ctr_drbg_random, &g_ctr_drbg); + if (ret != 0) { + mbedtls_print_error_with_code("Failed to decrypt with private key", + ret); + free(out); + return NULL; + } + + // Optionally shrink to fit: + // unsigned char* shrunk = realloc(out, out_len); + // if (shrunk) out = shrunk; + + *ret_len = out_len; + return out; +} + +static unsigned char* mbedtls_sign_sha256(const unsigned char* data, + unsigned int data_length, + crypto_pkey_t* priv_key, + size_t* sig_length) { + // Validate inputs + if (!data || data_length == 0 || !priv_key || !sig_length) { + errno = EINVAL; + SST_print_error("mbedtls_sign_sha256 invalid arguments"); + return NULL; + } + + // Ensure RSA private key + if (!mbedtls_pk_can_do(priv_key, MBEDTLS_PK_RSA)) { + SST_print_error("mbedtls_sign_sha256 expects an RSA private key"); + return NULL; + } + + // Ensure global RNG is ready (used for RSA blinding) + if (crypto_mbedtls_rng_init_once() != 0) { + SST_print_error("Global RNG not ready"); + return NULL; + } + + // Compute SHA-256 digest of the message + unsigned char hash[SHA256_DIGEST_LENGTH]; + int ret = mbedtls_sha256(data, data_length, hash, 0); + if (ret != 0) { + mbedtls_print_error_with_code("Failed to calculate SHA256 hash", ret); + return NULL; + } + + // Force PKCS#1 v1.5 signing (RSA-SHA256), to mirror OpenSSL's + // RSA_PKCS1_PADDING + EVP_sha256() + mbedtls_rsa_context* rsa = mbedtls_pk_rsa(*priv_key); + ret = mbedtls_rsa_set_padding(rsa, MBEDTLS_RSA_PKCS_V15, MBEDTLS_MD_NONE); + if (ret != 0) { + mbedtls_print_error_with_code("Failed to set RSA PKCS#1 v1.5 padding", + ret); + return NULL; + } + + // Allocate signature buffer of modulus size + size_t key_size = (mbedtls_pk_get_bitlen(priv_key) + 7) / 8; + unsigned char* sig = (unsigned char*)malloc(key_size); + if (!sig) { + SST_print_error("malloc(signature) failed"); + return NULL; + } + + // Sign precomputed hash with RSA PKCS#1 v1.5 + SHA-256 + size_t out_len = 0; + ret = mbedtls_pk_sign(priv_key, MBEDTLS_MD_SHA256, hash, + 0, // hash length ignored for fixed-size hash + sig, key_size, &out_len, mbedtls_ctr_drbg_random, + &g_ctr_drbg); + if (ret != 0) { + mbedtls_print_error_with_code("Failed to sign with private key", ret); + free(sig); + return NULL; + } + + *sig_length = out_len; + return sig; +} + +static int mbedtls_verify_sha256(const unsigned char* data, + unsigned int data_length, unsigned char* sig, + size_t sig_length, crypto_pkey_t* pub_key) { + // Validate inputs + if (!data || data_length == 0 || !sig || sig_length == 0 || !pub_key) { + errno = EINVAL; + SST_print_error("mbedtls_verify_sha256 invalid arguments"); + return -1; + } + + // Ensure RSA public key + if (!mbedtls_pk_can_do(pub_key, MBEDTLS_PK_RSA)) { + SST_print_error("mbedtls_verify_sha256 expects an RSA public key"); + return -1; + } + + // Compute SHA-256 digest of the message + unsigned char hash[SHA256_DIGEST_LENGTH]; + int ret = mbedtls_sha256(data, data_length, hash, 0); + if (ret != 0) { + mbedtls_print_error_with_code( + "Failed to calculate SHA256 hash for verification", ret); + return -1; + } + + // Force PKCS#1 v1.5 verify to mirror OpenSSL's RSA_PKCS1_PADDING + + // EVP_sha256() + mbedtls_rsa_context* rsa = mbedtls_pk_rsa(*pub_key); + ret = mbedtls_rsa_set_padding(rsa, MBEDTLS_RSA_PKCS_V15, MBEDTLS_MD_NONE); + if (ret != 0) { + mbedtls_print_error_with_code( + "Failed to set RSA PKCS#1 v1.5 padding for verify", ret); + return -1; + } + + // Verify signature over SHA-256 hash + // Note: when md_alg != MBEDTLS_MD_NONE, mbedTLS expects hash_len == 0 + ret = + mbedtls_pk_verify(pub_key, MBEDTLS_MD_SHA256, hash, 0, sig, sig_length); + if (ret != 0) { + mbedtls_print_error_with_code("Failed to verify signature", ret); + return -1; + } + + return 0; +} + +static int mbedtls_digest_sha256(const unsigned char* data, size_t data_len, + unsigned char* hash, unsigned int* hash_len) { + // Validate required output arguments + if (!hash || !hash_len) { + errno = EINVAL; + SST_print_error("mbedtls_digest_sha256 invalid arguments"); + return -1; + } + + // Compute SHA-256 digest over the input buffer (data may be NULL when + // data_len==0) + int ret = mbedtls_sha256(data, data_len, hash, 0); + if (ret != 0) { + mbedtls_print_error_with_code("Failed to compute SHA-256 digest", ret); + return -1; + } + + // Set output length to 32 bytes to match OpenSSL's SHA256_DIGEST_LENGTH + *hash_len = SHA256_DIGEST_LENGTH; + return 0; +} + +static int mbedtls_encrypt_aes(const unsigned char* plaintext, + unsigned int plaintext_length, + const unsigned char* key, + const unsigned char* iv, + AES_encryption_mode_t enc_mode, + unsigned char* output, + unsigned int* ret_length) { + // Validate basic arguments + if (!key || !iv || !output || !ret_length) { + errno = EINVAL; + SST_print_error("mbedtls_encrypt_aes invalid arguments"); + return -1; + } + + int ret = 0; + + switch (enc_mode) { + case AES_128_CBC: { + mbedtls_cipher_context_t c; + mbedtls_cipher_init(&c); + + const mbedtls_cipher_info_t* info = + mbedtls_cipher_info_from_type(MBEDTLS_CIPHER_AES_128_CBC); + if (!info) { + mbedtls_cipher_free(&c); + SST_print_error("Failed to get cipher info (AES-128-CBC)"); + return -1; + } + + if ((ret = mbedtls_cipher_setup(&c, info)) != 0) { + mbedtls_cipher_free(&c); + mbedtls_print_error_with_code("mbedtls_cipher_setup failed", + ret); + return -1; + } + + if ((ret = mbedtls_cipher_setkey(&c, key, 128, MBEDTLS_ENCRYPT)) != + 0) { + mbedtls_cipher_free(&c); + mbedtls_print_error_with_code("Failed to set AES-128 key (CBC)", + ret); + return -1; + } + + // Match OpenSSL default: PKCS#7 padding + if ((ret = mbedtls_cipher_set_padding_mode( + &c, MBEDTLS_PADDING_PKCS7)) != 0) { + mbedtls_cipher_free(&c); + mbedtls_print_error_with_code("Failed to set PKCS#7 padding", + ret); + return -1; + } + + if ((ret = mbedtls_cipher_set_iv(&c, iv, AES_128_CBC_IV_SIZE)) != + 0) { + mbedtls_cipher_free(&c); + mbedtls_print_error_with_code("Failed to set IV (CBC)", ret); + return -1; + } + + if ((ret = mbedtls_cipher_reset(&c)) != 0) { + mbedtls_cipher_free(&c); + mbedtls_print_error_with_code("mbedtls_cipher_reset failed", + ret); + return -1; + } + + size_t out_len = 0, finish_len = 0; + if ((ret = mbedtls_cipher_update(&c, plaintext, plaintext_length, + output, &out_len)) != 0) { + mbedtls_cipher_free(&c); + mbedtls_print_error_with_code( + "mbedtls_cipher_update failed (CBC)", ret); + return -1; + } + + if ((ret = mbedtls_cipher_finish(&c, output + out_len, + &finish_len)) != 0) { + mbedtls_cipher_free(&c); + mbedtls_print_error_with_code( + "mbedtls_cipher_finish failed (CBC)", ret); + return -1; + } + + *ret_length = (unsigned int)(out_len + finish_len); + mbedtls_cipher_free(&c); + return 0; + } + + case AES_128_CTR: { + mbedtls_cipher_context_t c; + mbedtls_cipher_init(&c); + + const mbedtls_cipher_info_t* info = + mbedtls_cipher_info_from_type(MBEDTLS_CIPHER_AES_128_CTR); + if (!info) { + mbedtls_cipher_free(&c); + SST_print_error("Failed to get cipher info (AES-128-CTR)"); + return -1; + } + + if ((ret = mbedtls_cipher_setup(&c, info)) != 0) { + mbedtls_cipher_free(&c); + mbedtls_print_error_with_code("mbedtls_cipher_setup failed", + ret); + return -1; + } + + if ((ret = mbedtls_cipher_setkey(&c, key, 128, MBEDTLS_ENCRYPT)) != + 0) { + mbedtls_cipher_free(&c); + mbedtls_print_error_with_code("Failed to set AES-128 key (CTR)", + ret); + return -1; + } + + if ((ret = mbedtls_cipher_set_iv(&c, iv, AES_128_CTR_IV_SIZE)) != + 0) { + mbedtls_cipher_free(&c); + mbedtls_print_error_with_code("Failed to set IV (CTR)", ret); + return -1; + } + + if ((ret = mbedtls_cipher_reset(&c)) != 0) { + mbedtls_cipher_free(&c); + mbedtls_print_error_with_code("mbedtls_cipher_reset failed", + ret); + return -1; + } + + size_t out_len = 0, finish_len = 0; + if ((ret = mbedtls_cipher_update(&c, plaintext, plaintext_length, + output, &out_len)) != 0) { + mbedtls_cipher_free(&c); + mbedtls_print_error_with_code( + "mbedtls_cipher_update failed (CTR)", ret); + return -1; + } + + if ((ret = mbedtls_cipher_finish(&c, output + out_len, + &finish_len)) != 0) { + mbedtls_cipher_free(&c); + mbedtls_print_error_with_code( + "mbedtls_cipher_finish failed (CTR)", ret); + return -1; + } + + *ret_length = + (unsigned int)(out_len + + finish_len); // finish_len is expected 0 for CTR + mbedtls_cipher_free(&c); + return 0; + } + + case AES_128_GCM: { + mbedtls_cipher_context_t c; + mbedtls_cipher_init(&c); + + const mbedtls_cipher_info_t* info = + mbedtls_cipher_info_from_type(MBEDTLS_CIPHER_AES_128_GCM); + if (!info) { + mbedtls_cipher_free(&c); + SST_print_error("Failed to get cipher info (AES-128-GCM)"); + return -1; + } + + if ((ret = mbedtls_cipher_setup(&c, info)) != 0) { + mbedtls_cipher_free(&c); + mbedtls_print_error_with_code("mbedtls_cipher_setup failed", + ret); + return -1; + } + + if ((ret = mbedtls_cipher_setkey(&c, key, 128, MBEDTLS_ENCRYPT)) != + 0) { + mbedtls_cipher_free(&c); + mbedtls_print_error_with_code("Failed to set AES-128 key (GCM)", + ret); + return -1; + } + + if ((ret = mbedtls_cipher_set_iv(&c, iv, AES_128_GCM_IV_SIZE)) != + 0) { + mbedtls_cipher_free(&c); + mbedtls_print_error_with_code("Failed to set IV (GCM)", ret); + return -1; + } + + if ((ret = mbedtls_cipher_reset(&c)) != 0) { + mbedtls_cipher_free(&c); + mbedtls_print_error_with_code("mbedtls_cipher_reset failed", + ret); + return -1; + } + + size_t out_len = 0, finish_len = 0; + if ((ret = mbedtls_cipher_update(&c, plaintext, plaintext_length, + output, &out_len)) != 0) { + mbedtls_cipher_free(&c); + mbedtls_print_error_with_code( + "mbedtls_cipher_update failed (GCM)", ret); + return -1; + } + + if ((ret = mbedtls_cipher_finish(&c, output + out_len, + &finish_len)) != 0) { + mbedtls_cipher_free(&c); + mbedtls_print_error_with_code( + "mbedtls_cipher_finish failed (GCM)", ret); + return -1; + } + + unsigned char tag[AES_GCM_TAG_SIZE]; + if ((ret = mbedtls_cipher_write_tag(&c, tag, AES_GCM_TAG_SIZE)) != + 0) { + mbedtls_cipher_free(&c); + mbedtls_print_error_with_code( + "mbedtls_cipher_write_tag failed (GCM)", ret); + return -1; + } + + memcpy(output + out_len + finish_len, tag, AES_GCM_TAG_SIZE); + *ret_length = + (unsigned int)(out_len + finish_len + AES_GCM_TAG_SIZE); + + mbedtls_cipher_free(&c); + return 0; + } + + default: + SST_print_error("Invalid encryption mode: %d", enc_mode); + return -1; + } +} + +static int mbedtls_decrypt_aes(const unsigned char* encrypted, + unsigned int encrypted_length, + const unsigned char* key, + const unsigned char* iv, + AES_encryption_mode_t enc_mode, + unsigned char* output, + unsigned int* ret_length) { + // Validate basic arguments + if (!key || !iv || !output || !ret_length) { + errno = EINVAL; + SST_print_error("mbedtls_decrypt_aes invalid arguments"); + return -1; + } + + int ret = 0; + + switch (enc_mode) { + case AES_128_CBC: { + if (encrypted_length == 0 || + (encrypted_length % AES_128_CBC_IV_SIZE) != 0) { + SST_print_error( + "AES-CBC ciphertext length is not a multiple of 16"); + return -1; + } + + mbedtls_cipher_context_t c; + mbedtls_cipher_init(&c); + + const mbedtls_cipher_info_t* info = + mbedtls_cipher_info_from_type(MBEDTLS_CIPHER_AES_128_CBC); + if (!info) { + mbedtls_cipher_free(&c); + SST_print_error("Failed to get cipher info (AES-128-CBC)"); + return -1; + } + + if ((ret = mbedtls_cipher_setup(&c, info)) != 0) { + mbedtls_cipher_free(&c); + mbedtls_print_error_with_code("mbedtls_cipher_setup failed", + ret); + return -1; + } + + if ((ret = mbedtls_cipher_setkey(&c, key, 128, MBEDTLS_DECRYPT)) != + 0) { + mbedtls_cipher_free(&c); + mbedtls_print_error_with_code("Failed to set AES-128 key (CBC)", + ret); + return -1; + } + + if ((ret = mbedtls_cipher_set_padding_mode( + &c, MBEDTLS_PADDING_PKCS7)) != 0) { + mbedtls_cipher_free(&c); + mbedtls_print_error_with_code("Failed to set PKCS#7 padding", + ret); + return -1; + } + + if ((ret = mbedtls_cipher_set_iv(&c, iv, AES_128_CBC_IV_SIZE)) != + 0) { + mbedtls_cipher_free(&c); + mbedtls_print_error_with_code("Failed to set IV (CBC)", ret); + return -1; + } + + if ((ret = mbedtls_cipher_reset(&c)) != 0) { + mbedtls_cipher_free(&c); + mbedtls_print_error_with_code("mbedtls_cipher_reset failed", + ret); + return -1; + } + + size_t out_len = 0, finish_len = 0; + if ((ret = mbedtls_cipher_update(&c, encrypted, encrypted_length, + output, &out_len)) != 0) { + mbedtls_cipher_free(&c); + mbedtls_print_error_with_code( + "mbedtls_cipher_update failed (CBC)", ret); + return -1; + } + + if ((ret = mbedtls_cipher_finish(&c, output + out_len, + &finish_len)) != 0) { + mbedtls_cipher_free(&c); + mbedtls_print_error_with_code( + "mbedtls_cipher_finish failed (CBC)", ret); + return -1; + } + + *ret_length = (unsigned int)(out_len + finish_len); + mbedtls_cipher_free(&c); + return 0; + } + + case AES_128_CTR: { + mbedtls_cipher_context_t c; + mbedtls_cipher_init(&c); + + const mbedtls_cipher_info_t* info = + mbedtls_cipher_info_from_type(MBEDTLS_CIPHER_AES_128_CTR); + if (!info) { + mbedtls_cipher_free(&c); + SST_print_error("Failed to get cipher info (AES-128-CTR)"); + return -1; + } + + if ((ret = mbedtls_cipher_setup(&c, info)) != 0) { + mbedtls_cipher_free(&c); + mbedtls_print_error_with_code("mbedtls_cipher_setup failed", + ret); + return -1; + } + + if ((ret = mbedtls_cipher_setkey(&c, key, 128, MBEDTLS_DECRYPT)) != + 0) { + mbedtls_cipher_free(&c); + mbedtls_print_error_with_code("Failed to set AES-128 key (CTR)", + ret); + return -1; + } + + if ((ret = mbedtls_cipher_set_iv(&c, iv, AES_128_CTR_IV_SIZE)) != + 0) { + mbedtls_cipher_free(&c); + mbedtls_print_error_with_code("Failed to set IV (CTR)", ret); + return -1; + } + + if ((ret = mbedtls_cipher_reset(&c)) != 0) { + mbedtls_cipher_free(&c); + mbedtls_print_error_with_code("mbedtls_cipher_reset failed", + ret); + return -1; + } + + size_t out_len = 0, finish_len = 0; + if ((ret = mbedtls_cipher_update(&c, encrypted, encrypted_length, + output, &out_len)) != 0) { + mbedtls_cipher_free(&c); + mbedtls_print_error_with_code( + "mbedtls_cipher_update failed (CTR)", ret); + return -1; + } + + if ((ret = mbedtls_cipher_finish(&c, output + out_len, + &finish_len)) != 0) { + mbedtls_cipher_free(&c); + mbedtls_print_error_with_code( + "mbedtls_cipher_finish failed (CTR)", ret); + return -1; + } + + *ret_length = + (unsigned int)(out_len + finish_len); // finish_len expected 0 + mbedtls_cipher_free(&c); + return 0; + } + + case AES_128_GCM: { + if (encrypted_length < AES_GCM_TAG_SIZE) { + SST_print_error("AES-GCM ciphertext too short"); + return -1; + } + + mbedtls_cipher_context_t c; + mbedtls_cipher_init(&c); + + const mbedtls_cipher_info_t* info = + mbedtls_cipher_info_from_type(MBEDTLS_CIPHER_AES_128_GCM); + if (!info) { + mbedtls_cipher_free(&c); + SST_print_error("Failed to get cipher info (AES-128-GCM)"); + return -1; + } + + if ((ret = mbedtls_cipher_setup(&c, info)) != 0) { + mbedtls_cipher_free(&c); + mbedtls_print_error_with_code("mbedtls_cipher_setup failed", + ret); + return -1; + } + + if ((ret = mbedtls_cipher_setkey(&c, key, 128, MBEDTLS_DECRYPT)) != + 0) { + mbedtls_cipher_free(&c); + mbedtls_print_error_with_code("Failed to set AES-128 key (GCM)", + ret); + return -1; + } + + const unsigned char* tag = + encrypted + encrypted_length - AES_GCM_TAG_SIZE; + const unsigned char* ciphertext = encrypted; + size_t ciphertext_len = encrypted_length - AES_GCM_TAG_SIZE; + + if ((ret = mbedtls_cipher_set_iv(&c, iv, AES_128_GCM_IV_SIZE)) != + 0) { + mbedtls_cipher_free(&c); + mbedtls_print_error_with_code("Failed to set IV (GCM)", ret); + return -1; + } + + if ((ret = mbedtls_cipher_reset(&c)) != 0) { + mbedtls_cipher_free(&c); + mbedtls_print_error_with_code("mbedtls_cipher_reset failed", + ret); + return -1; + } + + size_t out_len = 0, finish_len = 0; + if ((ret = mbedtls_cipher_update(&c, ciphertext, ciphertext_len, + output, &out_len)) != 0) { + mbedtls_cipher_free(&c); + mbedtls_print_error_with_code( + "mbedtls_cipher_update failed (GCM)", ret); + return -1; + } + + if ((ret = mbedtls_cipher_finish(&c, output + out_len, + &finish_len)) != 0) { + mbedtls_cipher_free(&c); + mbedtls_print_error_with_code( + "mbedtls_cipher_finish failed (GCM)", ret); + return -1; + } + + if ((ret = mbedtls_cipher_check_tag(&c, tag, AES_GCM_TAG_SIZE)) != + 0) { + mbedtls_cipher_free(&c); + mbedtls_print_error_with_code( + "mbedtls_cipher_check_tag failed (GCM)", ret); + return -1; + } + + *ret_length = (unsigned int)(out_len + finish_len); + mbedtls_cipher_free(&c); + return 0; + } + + default: + SST_print_error("Invalid encryption mode: %d", enc_mode); + return -1; + } +} + +static int mbedtls_generate_random(unsigned char* buf, int length) { + // Validate arguments + if (!buf || length <= 0) { + errno = EINVAL; + SST_print_error("mbedtls_generate_random invalid arguments"); + return -1; + } + + // Ensure global DRBG is initialized once (reuse across calls) + if (crypto_mbedtls_rng_init_once() != 0) { + SST_print_error("Global RNG not ready"); + return -1; + } + + // Generate cryptographically secure random bytes + int ret = mbedtls_ctr_drbg_random(&g_ctr_drbg, buf, (size_t)length); + if (ret != 0) { + mbedtls_print_error_with_code("Failed to generate random bytes", ret); + return -1; + } + + return 0; +} + +static int mbedtls_hmac_sha256(const unsigned char* key, size_t key_len, + const unsigned char* data, size_t data_len, + unsigned char* output, + unsigned int* output_len) { + // Validate arguments + if (!key || key_len == 0 || (!data && data_len != 0) || !output || + !output_len) { + errno = EINVAL; + SST_print_error("mbedtls_hmac_sha256 invalid arguments"); + return -1; + } + + mbedtls_md_context_t ctx; + mbedtls_md_init(&ctx); + + const mbedtls_md_info_t* md_info = + mbedtls_md_info_from_type(MBEDTLS_MD_SHA256); + if (md_info == NULL) { + mbedtls_md_free(&ctx); + SST_print_error("mbedtls_hmac_sha256 failed to get md info"); + return -1; + } + + int ret = mbedtls_md_setup(&ctx, md_info, 1 /* HMAC enable */); + if (ret != 0) { + mbedtls_md_free(&ctx); + mbedtls_print_error_with_code("mbedtls_md_setup failed", ret); + return -1; + } + + ret = mbedtls_md_hmac_starts(&ctx, key, key_len); + if (ret != 0) { + mbedtls_md_free(&ctx); + mbedtls_print_error_with_code("mbedtls_md_hmac_starts failed", ret); + return -1; + } + + ret = mbedtls_md_hmac_update(&ctx, data, data_len); + if (ret != 0) { + mbedtls_md_free(&ctx); + mbedtls_print_error_with_code("mbedtls_md_hmac_update failed", ret); + return -1; + } + + ret = mbedtls_md_hmac_finish(&ctx, output); + if (ret != 0) { + mbedtls_md_free(&ctx); + mbedtls_print_error_with_code("mbedtls_md_hmac_finish failed", ret); + return -1; + } + + *output_len = SHA256_DIGEST_LENGTH; // SHA-256 HMAC length in bytes + mbedtls_md_free(&ctx); + return 0; +} + +// mbed TLS crypto backend implementation +static const crypto_backend_t mbedtls_backend = { + .load_public_key = mbedtls_load_public_key, + .load_private_key = mbedtls_load_private_key, + .free_pkey = mbedtls_free_pkey, + .print_error = mbedtls_print_error, + .public_encrypt = mbedtls_public_encrypt, + .private_decrypt = mbedtls_private_decrypt, + .sign_sha256 = mbedtls_sign_sha256, + .verify_sha256 = mbedtls_verify_sha256, + .digest_sha256 = mbedtls_digest_sha256, + .encrypt_aes = mbedtls_encrypt_aes, + .decrypt_aes = mbedtls_decrypt_aes, + .generate_random = mbedtls_generate_random, + .hmac_sha256 = mbedtls_hmac_sha256}; + +const crypto_backend_t* get_crypto_backend(void) { return &mbedtls_backend; } + +#endif // USE_MBEDTLS diff --git a/crypto_openssl.c b/crypto_openssl.c new file mode 100644 index 00000000..dc6cac44 --- /dev/null +++ b/crypto_openssl.c @@ -0,0 +1,384 @@ +#ifdef USE_OPENSSL + +#include "c_api.h" +#include "c_common.h" +#include "c_crypto.h" +#include "crypto_backend.h" + +// OpenSSL implementation of crypto backend + +static void openssl_print_error(const char* msg) { + unsigned long error_code = ERR_get_error(); + if (error_code != 0) { + char err[MAX_ERROR_MESSAGE_LENGTH]; + ERR_load_crypto_strings(); + ERR_error_string(error_code, err); + SST_print_error("%s ERROR: %s (code: 0x%lx)", msg, err, error_code); + } else { + SST_print_error("%s ERROR: Unknown OpenSSL error", msg); + } +} + +static crypto_pkey_t* openssl_load_public_key(const char* path) { + FILE* pemFile = fopen(path, "rb"); + if (pemFile == NULL) { + SST_print_error("Failed to open public key file: %s (errno: %d)", path, + errno); + return NULL; + } + X509* cert = PEM_read_X509(pemFile, NULL, NULL, NULL); + EVP_PKEY* pub_key = X509_get_pubkey(cert); + if (pub_key == NULL) { + fclose(pemFile); + X509_free(cert); + return NULL; + } + int id = EVP_PKEY_id(pub_key); + if (id != EVP_PKEY_RSA) { + EVP_PKEY_free(pub_key); + fclose(pemFile); + X509_free(cert); + return NULL; + } + fclose(pemFile); + X509_free(cert); + return pub_key; +} + +static crypto_pkey_t* openssl_load_private_key(const char* path) { + FILE* keyfile = fopen(path, "rb"); + if (keyfile == NULL) { + SST_print_error("Failed to open private key file: %s (errno: %d)", path, + errno); + return NULL; + } + EVP_PKEY* priv_key = PEM_read_PrivateKey(keyfile, NULL, NULL, NULL); + fclose(keyfile); + return priv_key; +} + +static void openssl_free_pkey(crypto_pkey_t* pkey) { + if (pkey) { + EVP_PKEY_free(pkey); + } +} + +static unsigned char* openssl_public_encrypt(const unsigned char* data, + size_t data_len, + crypto_pkey_t* pub_key, + size_t* ret_len) { + EVP_PKEY_CTX* ctx; + unsigned char* out = NULL; + + ctx = EVP_PKEY_CTX_new(pub_key, NULL); + if (!ctx) { + return NULL; + } + if (EVP_PKEY_encrypt_init(ctx) <= 0) { + EVP_PKEY_CTX_free(ctx); + return NULL; + } + if (EVP_PKEY_CTX_set_rsa_padding(ctx, RSA_PKCS1_OAEP_PADDING) <= 0) { + EVP_PKEY_CTX_free(ctx); + return NULL; + } + if (EVP_PKEY_encrypt(ctx, NULL, ret_len, data, data_len) <= 0) { + EVP_PKEY_CTX_free(ctx); + return NULL; + } + out = (unsigned char*)malloc(*ret_len); + if (!out) { + EVP_PKEY_CTX_free(ctx); + return NULL; + } + + if (EVP_PKEY_encrypt(ctx, out, ret_len, data, data_len) <= 0) { + free(out); + EVP_PKEY_CTX_free(ctx); + return NULL; + } + EVP_PKEY_CTX_free(ctx); + return out; +} + +static unsigned char* openssl_private_decrypt(const unsigned char* enc_data, + size_t enc_data_len, + crypto_pkey_t* priv_key, + size_t* ret_len) { + EVP_PKEY_CTX* ctx; + unsigned char* out = NULL; + ctx = EVP_PKEY_CTX_new(priv_key, NULL); + if (!ctx) { + return NULL; + } + if (EVP_PKEY_decrypt_init(ctx) <= 0) { + EVP_PKEY_CTX_free(ctx); + return NULL; + } + if (EVP_PKEY_CTX_set_rsa_padding(ctx, RSA_PKCS1_OAEP_PADDING) <= 0) { + EVP_PKEY_CTX_free(ctx); + return NULL; + } + if (EVP_PKEY_decrypt(ctx, NULL, ret_len, enc_data, enc_data_len) <= 0) { + EVP_PKEY_CTX_free(ctx); + return NULL; + } + out = (unsigned char*)malloc(*ret_len); + if (!out) { + EVP_PKEY_CTX_free(ctx); + return NULL; + } + if (EVP_PKEY_decrypt(ctx, out, ret_len, enc_data, enc_data_len) <= 0) { + free(out); + EVP_PKEY_CTX_free(ctx); + return NULL; + } + EVP_PKEY_CTX_free(ctx); + return out; +} + +static unsigned char* openssl_sign_sha256(const unsigned char* data, + unsigned int data_length, + crypto_pkey_t* priv_key, + size_t* sig_length) { + unsigned char md[SHA256_DIGEST_LENGTH]; + unsigned int md_length; + if (digest_message_SHA_256(data, data_length, md, &md_length) < 0) { + return NULL; + } + EVP_PKEY_CTX* ctx; + unsigned char* sig = NULL; + ctx = EVP_PKEY_CTX_new(priv_key, NULL); + if (!ctx) { + return NULL; + } + if (EVP_PKEY_sign_init(ctx) <= 0) { + EVP_PKEY_CTX_free(ctx); + return NULL; + } + if (EVP_PKEY_CTX_set_rsa_padding(ctx, RSA_PKCS1_PADDING) <= 0) { + EVP_PKEY_CTX_free(ctx); + return NULL; + } + if (EVP_PKEY_CTX_set_signature_md(ctx, EVP_sha256()) <= 0) { + EVP_PKEY_CTX_free(ctx); + return NULL; + } + if (EVP_PKEY_sign(ctx, NULL, sig_length, md, md_length) <= 0) { + EVP_PKEY_CTX_free(ctx); + return NULL; + } + sig = (unsigned char*)malloc(*sig_length); + + if (!sig) { + EVP_PKEY_CTX_free(ctx); + return NULL; + } + if (EVP_PKEY_sign(ctx, sig, sig_length, md, md_length) <= 0) { + free(sig); + EVP_PKEY_CTX_free(ctx); + return NULL; + } + EVP_PKEY_CTX_free(ctx); + return sig; +} + +static int openssl_verify_sha256(const unsigned char* data, + unsigned int data_length, unsigned char* sig, + size_t sig_length, crypto_pkey_t* pub_key) { + EVP_PKEY_CTX* ctx; + unsigned char md[SHA256_DIGEST_LENGTH]; + unsigned int md_len; + if (digest_message_SHA_256(data, data_length, md, &md_len) < 0) { + return -1; + } + + ctx = EVP_PKEY_CTX_new(pub_key, NULL); + if (!ctx) { + return -1; + } + if (EVP_PKEY_verify_init(ctx) <= 0) { + EVP_PKEY_CTX_free(ctx); + return -1; + } + if (EVP_PKEY_CTX_set_rsa_padding(ctx, RSA_PKCS1_PADDING) <= 0) { + EVP_PKEY_CTX_free(ctx); + return -1; + } + if (EVP_PKEY_CTX_set_signature_md(ctx, EVP_sha256()) <= 0) { + EVP_PKEY_CTX_free(ctx); + return -1; + } + if (EVP_PKEY_verify(ctx, sig, sig_length, md, md_len) != 1) { + EVP_PKEY_CTX_free(ctx); + return -1; + } + EVP_PKEY_CTX_free(ctx); + return 0; +} + +static int openssl_digest_sha256(const unsigned char* data, size_t data_len, + unsigned char* hash, unsigned int* hash_len) { + EVP_MD_CTX* mdctx; + + if ((mdctx = EVP_MD_CTX_create()) == NULL) { + return -1; + } + if (EVP_DigestInit_ex(mdctx, EVP_sha256(), NULL) != 1) { + EVP_MD_CTX_destroy(mdctx); + return -1; + } + if (EVP_DigestUpdate(mdctx, data, data_len) != 1) { + EVP_MD_CTX_destroy(mdctx); + return -1; + } + if (EVP_DigestFinal_ex(mdctx, hash, hash_len) != 1) { + EVP_MD_CTX_destroy(mdctx); + return -1; + } + EVP_MD_CTX_destroy(mdctx); + return 0; +} + +static const EVP_CIPHER* get_EVP_CIPHER(AES_encryption_mode_t enc_mode) { + if (enc_mode == AES_128_CBC) { + return EVP_aes_128_cbc(); + } else if (enc_mode == AES_128_CTR) { + return EVP_aes_128_ctr(); + } else if (enc_mode == AES_128_GCM) { + return EVP_aes_128_gcm(); + } else { + return NULL; + } +} + +static int openssl_encrypt_aes(const unsigned char* plaintext, + unsigned int plaintext_length, + const unsigned char* key, + const unsigned char* iv, + AES_encryption_mode_t enc_mode, + unsigned char* ret, unsigned int* ret_length) { + EVP_CIPHER_CTX* ctx = EVP_CIPHER_CTX_new(); + if (!EVP_EncryptInit_ex(ctx, get_EVP_CIPHER(enc_mode), NULL, key, iv)) { + EVP_CIPHER_CTX_free(ctx); + return -1; + } + + if (enc_mode == AES_128_GCM) { + if (!EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_SET_IVLEN, + AES_128_GCM_IV_SIZE, NULL)) { + EVP_CIPHER_CTX_free(ctx); + return -1; + } + } + + if (!EVP_EncryptUpdate(ctx, ret, (int*)ret_length, plaintext, + plaintext_length)) { + EVP_CIPHER_CTX_free(ctx); + return -1; + } + + unsigned int temp_len; + if (!EVP_EncryptFinal_ex(ctx, ret + *ret_length, (int*)&temp_len)) { + EVP_CIPHER_CTX_free(ctx); + return -1; + } + *ret_length += temp_len; + + if (enc_mode == AES_128_GCM) { + if (!EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_GET_TAG, AES_GCM_TAG_SIZE, + ret + *ret_length)) { + EVP_CIPHER_CTX_free(ctx); + return -1; + } + *ret_length += AES_GCM_TAG_SIZE; + } + + EVP_CIPHER_CTX_free(ctx); + return 0; +} + +static int openssl_decrypt_aes(const unsigned char* encrypted, + unsigned int encrypted_length, + const unsigned char* key, + const unsigned char* iv, + AES_encryption_mode_t enc_mode, + unsigned char* ret, unsigned int* ret_length) { + EVP_CIPHER_CTX* ctx = EVP_CIPHER_CTX_new(); + if (!EVP_DecryptInit_ex(ctx, get_EVP_CIPHER(enc_mode), NULL, key, iv)) { + EVP_CIPHER_CTX_free(ctx); + return -1; + } + + if (enc_mode == AES_128_GCM) { + if (!EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_SET_IVLEN, + AES_128_GCM_IV_SIZE, NULL)) { + EVP_CIPHER_CTX_free(ctx); + return -1; + } + + unsigned char* tag = + (unsigned char*)encrypted + encrypted_length - AES_GCM_TAG_SIZE; + if (!EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_SET_TAG, AES_GCM_TAG_SIZE, + tag)) { + EVP_CIPHER_CTX_free(ctx); + return -1; + } + + encrypted_length -= AES_GCM_TAG_SIZE; + } + + if (!EVP_DecryptUpdate(ctx, ret, (int*)ret_length, encrypted, + encrypted_length)) { + EVP_CIPHER_CTX_free(ctx); + return -1; + } + + unsigned int temp_len; + if (!EVP_DecryptFinal_ex(ctx, ret + *ret_length, (int*)&temp_len)) { + EVP_CIPHER_CTX_free(ctx); + return -1; + } + *ret_length += temp_len; + + EVP_CIPHER_CTX_free(ctx); + return 0; +} + +static int openssl_generate_random(unsigned char* buf, int length) { + return RAND_bytes(buf, length) == 1 ? 0 : -1; +} + +static int openssl_hmac_sha256(const unsigned char* key, size_t key_len, + const unsigned char* data, size_t data_len, + unsigned char* output, + unsigned int* output_len) { + unsigned int len = 0; + unsigned char* result = + HMAC(EVP_sha256(), key, key_len, data, data_len, output, &len); + if (!result) { + return -1; + } + *output_len = len; + return 0; +} + +// OpenSSL crypto backend implementation +static const crypto_backend_t openssl_backend = { + .load_public_key = openssl_load_public_key, + .load_private_key = openssl_load_private_key, + .free_pkey = openssl_free_pkey, + .print_error = openssl_print_error, + .public_encrypt = openssl_public_encrypt, + .private_decrypt = openssl_private_decrypt, + .sign_sha256 = openssl_sign_sha256, + .verify_sha256 = openssl_verify_sha256, + .digest_sha256 = openssl_digest_sha256, + .encrypt_aes = openssl_encrypt_aes, + .decrypt_aes = openssl_decrypt_aes, + .generate_random = openssl_generate_random, + .hmac_sha256 = openssl_hmac_sha256}; + +const crypto_backend_t* get_crypto_backend(void) { return &openssl_backend; } + +#endif // USE_OPENSSL diff --git a/embedded/examples/CMakeLists.txt b/embedded/examples/CMakeLists.txt new file mode 100644 index 00000000..55b66480 --- /dev/null +++ b/embedded/examples/CMakeLists.txt @@ -0,0 +1,56 @@ +cmake_minimum_required(VERSION 3.19) + +# This part must come before project() +if(SST_PLATFORM_PICO) + set(USE_MBEDTLS ON) + set(USE_OPENSSL OFF) + message(STATUS "Using mbedTLS crypto backend") + if(NOT DEFINED PICO_SDK_PATH OR PICO_SDK_PATH STREQUAL "") + set(PICO_SDK_PATH "${CMAKE_CURRENT_LIST_DIR}/../lib/pico-sdk" CACHE PATH "Path to pico-sdk") + endif() + set(PICO_BOARD pico2_w CACHE STRING "Target board" FORCE) + include(${PICO_SDK_PATH}/pico_sdk_init.cmake) +endif() + +project(sst-examples VERSION 1.0.0 LANGUAGES C CXX ASM) + +# --- Always use mbedTLS backend for embedded builds --- +set(USE_MBEDTLS ON CACHE BOOL "Force use of mbedTLS backend" FORCE) +set(USE_OPENSSL OFF CACHE BOOL "Disable OpenSSL backend" FORCE) +set(SST_PLATFORM_PICO ON CACHE BOOL "Build SST library for Raspberry Pi Pico targets" FORCE) + +# Include the main SST library (assuming the root directory is two levels up) +add_subdirectory(../../ ${CMAKE_BINARY_DIR}/sst-lib-build) + +add_executable(embedded_client embedded_client.c) + +# Include headers with #include "c_api.h" +target_include_directories(embedded_client PRIVATE + ${CMAKE_CURRENT_LIST_DIR} + ${CMAKE_CURRENT_LIST_DIR}/../..) + +set(FREERTOS_KERNEL_PATH "${CMAKE_CURRENT_LIST_DIR}/../lib/FreeRTOS-Kernel" CACHE PATH "Path to FreeRTOS Kernel" FORCE) +include(${FREERTOS_KERNEL_PATH}/portable/ThirdParty/GCC/RP2040/FreeRTOS_Kernel_import.cmake) +pico_sdk_init() +# Link against the freshly built SST library and Pico Wi-Fi (lwIP+cyw43) +target_link_libraries(embedded_client + sst-c-api + pico_cyw43_arch_lwip_sys_freertos + pico_stdlib + pico_mbedtls + FreeRTOS-Kernel-Heap4 +) + + # Include lwipopts.h & mbedtls_sst_config.h & FreeRTOSConfig.h + target_include_directories(embedded_client PRIVATE + ${CMAKE_CURRENT_LIST_DIR}/../include + ) + +# Enable USB serial output (printf over USB) +pico_enable_stdio_usb(embedded_client 1) +# Disable UART serial output (no logs via TX/RX pins) +pico_enable_stdio_uart(embedded_client 0) + + +# Produce UF2, bin, map, etc. +pico_add_extra_outputs(embedded_client) diff --git a/embedded/examples/README.md b/embedded/examples/README.md new file mode 100644 index 00000000..f5067fdd --- /dev/null +++ b/embedded/examples/README.md @@ -0,0 +1,4 @@ +### Prerequisites + +- (optional) Install picotool, or it will fetch picotool everytime, but this is also fine. +- Install arm-none-eabi-gcc diff --git a/embedded/examples/embedded_client.c b/embedded/examples/embedded_client.c new file mode 100644 index 00000000..5d321c83 --- /dev/null +++ b/embedded/examples/embedded_client.c @@ -0,0 +1,213 @@ +#include +#include +#include +#include + +#include "c_api.h" +#include "lwip/netdb.h" +#include "lwip/sockets.h" // BSD socket API +#include "pico/cyw43_arch.h" // Wi-Fi driver + lwIP init +#include "pico/stdlib.h" + +#include "FreeRTOS.h" +#include "task.h" + +#define WIFI_SSID "204_office" +#define WIFI_PASSWORD "hkim2010" + +#define TEST_TASK_PRIORITY ( tskIDLE_PRIORITY + 2UL ) +#define TEST_TASK_STACK_SIZE 1024 + +// #define SERVER_IP "192.168.0.10" +// #define SERVER_PORT 5000 + +static const char default_config_text[] = + "entityInfo.name=net1.client\n" + "entityInfo.purpose={\"group\":\"Servers\"}\n" + "entityInfo.number_key=3\n" + "authInfo.id=101\n" + "auth.ip.address=10.218.100.95\n" + "auth.port.number=21800\n" + "entity.server.ip.address=10.218.100.95\n" + "entity.server.port.number=21200\n" + "network.protocol=TCP\n" + "authInfo.pubkey.path=\n" + "-----BEGIN CERTIFICATE-----\n" + "MIIDWjCCAkICFAzOlPI6THQ5t/L40v6XU4VaN3uFMA0GCSqGSIb3DQEBCwUAMHEx\n" + "CzAJBgNVBAYTAlVTMQswCQYDVQQIDAJDQTERMA8GA1UEBwwIQmVya2VsZXkxDTAL\n" + "BgNVBAoMBEVFQ1MxHTAbBgNVBAsMFENlcnRpZmljYXRlQXV0aG9yaXR5MRQwEgYD\n" + "VQQDDAtpb3RhdXRoLm9yZzAeFw0yNTEyMTgyMDAxNDRaFw0yNzEyMTgyMDAxNDRa\n" + "MGIxCzAJBgNVBAYTAlVTMQswCQYDVQQIDAJDQTERMA8GA1UEBwwIQmVya2VsZXkx\n" + "DTALBgNVBAoMBEVFQ1MxEDAOBgNVBAsMB0F1dGgxMDExEjAQBgNVBAMMCWxvY2Fs\n" + "aG9zdDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAPdQbrZfbaKo7oDs\n" + "SI8fsmBKfBaLL/ny8xyPt+tXsNOqbizG6n1F7+NcYatHLekyLtWq52I4/IW+4hfh\n" + "ttFLt6ysrrt70cPC/Kw20mORRHDdXL3nYl4RkYINShE89fWjFcADRak2q81ylef+\n" + "Cubg45b54Crax07kajIXctJIX9Fehdo7KJajylhev/Lk3erUWX0aTCqK4EWXsdKD\n" + "urjJZPOutAZ1htSTaxBycelquPwx6Dc2Kdi0L7fki7uKtKbds7HangIoRpmSB3oY\n" + "PzLbun4MK4bgGIr+uJbKO8HZGb6b1iBo3fzuK8rExeWLzKBElzMx+F8RKy9sqkKy\n" + "MS5jZ3kCAwEAATANBgkqhkiG9w0BAQsFAAOCAQEAVyJb+ixbur6PSrR8QbnEzEeY\n" + "01uBZaksGBnXCphQJ4zrRqVA3f/FVmh2Vgc2DuCylVUd3fjm+akTtBEUxm0orRyy\n" + "wopN5q9iX0nXN1XS9lktyCFVNTqRj4bK5M901I6FMS5XCHPDk0bzccpAIx5flQ1o\n" + "aQg9prABIoedHLcFLZSaMprpB18QCFSDO9kBDkJdiNiPlsW01M/S1vus35wosoDv\n" + "HzcovdskC5CK00e9uLv8mRL/3wjmnRhEphj2PnPLbFFlfYl1/UI5uDDqCuDo+a6r\n" + "g9cqiNwuzYRDNlZDYyfYMndedo10XOck1FeI7PsGRODBWxiE9pppanU665BJJg==\n" + "-----END CERTIFICATE-----\n" + "entityInfo.privkey.path=\n" + "-----BEGIN PRIVATE KEY-----\n" + "MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQCrqA01Apl9r6LT\n" + "puDRQLt3kc+V/FdZeD/TZglqtHTDXp61wmyNRev5CK2stajisU+/07d4ufuA9Ddu\n" + "uH1ABtniOR8AWAzYQERZzy8K98+b1fUDdERCY+sGbyarvW8o/tJh5067Ms1EvpJw\n" + "g9AOyGyqkkZrAQyqd9SudZ1GhA6o86mF7ozVVl+zKmm1r9XGp+j99VXi+lV9QQow\n" + "FJEJQJZgfH0mP6vLACpi4RaO1yckiVm3KsY4zReiTeSD+ZWqC3/h2xpJRKDBrwPL\n" + "9WNAd3rZpvMwvRXE/g9gn0d1mWN++mdbCagAz3YrIYiunqcTWqtQDc1ZbmhzTAVf\n" + "RHh6H31LAgMBAAECggEAF5a6aeR3j0wJhihSkK7ilCXXbvcEUekybCyDcsRln0tr\n" + "Z/LV0/wd11UX+LnmAXD4UpYXimGUbD4jN/XmUFwgqPPMjNGMwlLikazk/A7d2r5m\n" + "MxlRIAZ3D6VKnSMlGW8bHhUZPqRWjPHbUdbrSnzEYhRD1QSJ5wsckPTcrgoLsa/A\n" + "SW6PzAF/vwkzjoVXoCwOlN7A2/rgPpuO1c6f5wp+Q7k6JeQIWOeyf6cnLYcZ98PT\n" + "b6byXASrWF3gTJCuGrfQBlwXCNxf0GErBSr8JxY3Ckqm4AzjWPQNlSTeda1k+AfC\n" + "mFyT2DVFD/12aQdlmM9o53Y2Sa0FykOZck9sAr4xwQKBgQC7HilZPKOJIbhgd6iG\n" + "BotiwwmILgNwZs/iU/Owf9uaXpOPRObxLfTu4ZO8RVQFD0H5cr3Sr75yMIHiQySi\n" + "LXpU8IYkbpa/q13SkWFXAkPbWlFp3iOyVmsnMeSDGkm0ws7aZH4qXIhm1avZVHDB\n" + "UhHeHvctXhUnmNlouu0JeMS72wKBgQDq2NKj6vtjFq1fJuvnuhggGXRslaWl/2xI\n" + "SHHl4+PWtQFD3TD7vO+eq/NG8D+NOPyyUW7/Y8pi5j/3RLoKpF14FagJcNboDvSZ\n" + "XsrQjCJHpfHX7XfOfKISKVDdaZXC7vlj6cbk6ulj5GzOCa8LjhcCGGIhUi4BQeCD\n" + "WIjT98w3UQKBgBECzvOD5cIjxKVQe4ujsKxL2uP8euePETscMr1LAmXoTzXpJ62p\n" + "ZekJrOqiyt6i4naRDdzHiWLMMiKlxADSbZqnOyq4uw+1vpPUD6tfU1fvwBMF1Ozz\n" + "mk435PReQXEjfLayCB5Fx0jCCBt757xLf8BXxFTlhrrQ1IMG62G/DvOdAoGAcrLC\n" + "7dvuO07wDfDsdpik/8hu3DmaVaCSOhtnxWev90UgAQ0ex1RXk59XieX8o/SZNl4f\n" + "YAxU5EigJRwj4N6159hr4XCDBYOIYv+w/nnypBugKl2IjgjA/y2+mOTgh/w/QVUE\n" + "FvnEU01U9qw0GeijxBo0kyGX5nVOOdgbu6riyoECgYB2olYihWN//wynrz4wwu62\n" + "O8qW7pSz90m8FyZ70Q6bDsMvOM/WQ5iS7BQipDQeg9wmkbU8DVbGB5Y8ZjZ7PNP2\n" + "N7gTEYZyDJparOA5ZJfGKfObndN27fLEMiL6voVr4ceW3mYpAmlfo7pg+3eGfiVo\n" + "UWo74pQah3huBU0XkYZ9dA==\n" + "-----END PRIVATE KEY-----\n"; + + +void main_task(__unused void* params) { + // Initialize CYW43 Wi-Fi + lwIP stack + printf("0.54!\n"); + if (cyw43_arch_init()) { + printf("failed to initialise\n"); + return; + } + // printf("0.56!\n"); + // cyw43_arch_gpio_put(CYW43_WL_GPIO_LED_PIN, 1); + // sleep_ms(250); + // cyw43_arch_gpio_put(CYW43_WL_GPIO_LED_PIN, 0); + // sleep_ms(250); + // cyw43_arch_gpio_put(CYW43_WL_GPIO_LED_PIN, 1); + // sleep_ms(250); + // cyw43_arch_gpio_put(CYW43_WL_GPIO_LED_PIN, 0); + // sleep_ms(250); + // cyw43_arch_gpio_put(CYW43_WL_GPIO_LED_PIN, 1); + // sleep_ms(250); + // cyw43_arch_gpio_put(CYW43_WL_GPIO_LED_PIN, 0); + // sleep_ms(250); + + // printf("1!\n"); + // printf("1!\n"); + // printf("1!\n"); + // printf("1!\n"); + // printf("1!\n"); + // printf("1!\n"); + // printf("1!\n"); + // printf("1!\n"); + + // printf("2!\n"); + cyw43_arch_enable_sta_mode(); + printf("3!\n"); + printf("Connecting to Wi-Fi: %s ...\n", WIFI_SSID); + int rc = cyw43_arch_wifi_connect_timeout_ms(WIFI_SSID, WIFI_PASSWORD, + CYW43_AUTH_WPA2_AES_PSK, 30000); + printf("4!\n"); + if (rc != 0) { + printf("Wi-Fi connect failed: %d\n", rc); + cyw43_arch_deinit(); + return; + } + printf("Wi-Fi connected!\n"); + + // cyw43_arch_gpio_put(CYW43_WL_GPIO_LED_PIN, 1); + // sleep_ms(250); + // cyw43_arch_gpio_put(CYW43_WL_GPIO_LED_PIN, 0); + // sleep_ms(250); + // cyw43_arch_gpio_put(CYW43_WL_GPIO_LED_PIN, 1); + // sleep_ms(250); + // cyw43_arch_gpio_put(CYW43_WL_GPIO_LED_PIN, 0); + // sleep_ms(250); + // cyw43_arch_gpio_put(CYW43_WL_GPIO_LED_PIN, 1); + // sleep_ms(250); + // cyw43_arch_gpio_put(CYW43_WL_GPIO_LED_PIN, 0); + // sleep_ms(250); + // printf("5!\n"); + + + SST_ctx_t* ctx = init_SST(default_config_text); + if (ctx == NULL) { + SST_print_error_exit("init_SST() failed."); + } + printf("init_SST done."); + + session_key_list_t* s_key_list = get_session_key(ctx, NULL); + if (s_key_list == NULL) { + SST_print_error_exit("Failed get_session_key()."); + } + printf("get_session_key done."); + // SST_session_ctx_t* session_ctx = + // secure_connect_to_server(&s_key_list->s_key[0], ctx); + // if (session_ctx == NULL) { + // SST_print_error_exit("Failed secure_connect_to_server()."); + // } + // print("secure_connect_to_server done."); + // free_session_ctx(session_ctx); + + free_session_key_list_t(s_key_list); + free_SST_ctx_t(ctx); + + cyw43_arch_deinit(); + panic("Test passed"); +} + +void vLaunch(void) { + TaskHandle_t task; + xTaskCreate(main_task, "TestMainThread", TEST_TASK_STACK_SIZE, NULL, + TEST_TASK_PRIORITY, &task); + +#if NO_SYS && configUSE_CORE_AFFINITY && configNUM_CORES > 1 + // we must bind the main task to one core (well at least while the init is + // called) (note we only do this in NO_SYS mode, because cyw43_arch_freertos + // takes care of it otherwise) + vTaskCoreAffinitySet(task, 1); +#endif + + /* Start the tasks and timer running. */ + vTaskStartScheduler(); +} + +int main(int argc, char* argv[]) { + stdio_init_all(); + // sleep_ms(3000); + // printf("0!\n"); + /* Configure the hardware ready to run the demo. */ + const char* rtos_name; +#if (portSUPPORT_SMP == 1) + rtos_name = "FreeRTOS SMP"; +#else + rtos_name = "FreeRTOS"; +#endif + +#if (portSUPPORT_SMP == 1) && (configNUM_CORES == 2) + printf("Starting %s on both cores:\n", rtos_name); + vLaunch(); +#elif (RUN_FREERTOS_ON_CORE == 1) + printf("Starting %s on core 1:\n", rtos_name); + multicore_launch_core1(vLaunch); + while (true); +#else + printf("Starting %s on core 0:\n", rtos_name); + vLaunch(); +#endif + return 0; + + +} diff --git a/embedded/include/FreeRTOSConfig.h b/embedded/include/FreeRTOSConfig.h new file mode 100644 index 00000000..7e751bfb --- /dev/null +++ b/embedded/include/FreeRTOSConfig.h @@ -0,0 +1,158 @@ +/* + * FreeRTOS V202111.00 + * Copyright (C) 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * http://www.FreeRTOS.org + * http://aws.amazon.com/freertos + * + * 1 tab == 4 spaces! + */ + +#ifndef FREERTOS_CONFIG_EXAMPLES_COMMON_H +#define FREERTOS_CONFIG_EXAMPLES_COMMON_H + +/*----------------------------------------------------------- + * Application specific definitions. + * + * These definitions should be adjusted for your particular hardware and + * application requirements. + * + * THESE PARAMETERS ARE DESCRIBED WITHIN THE 'CONFIGURATION' SECTION OF THE + * FreeRTOS API DOCUMENTATION AVAILABLE ON THE FreeRTOS.org WEB SITE. + * + * See http://www.freertos.org/a00110.html + *----------------------------------------------------------*/ + +/* Scheduler Related */ +#define configUSE_PREEMPTION 1 +#define configUSE_TICKLESS_IDLE 0 +#define configUSE_IDLE_HOOK 0 +#define configUSE_TICK_HOOK 0 +#define configTICK_RATE_HZ ((TickType_t)1000) +#define configMAX_PRIORITIES 32 +#define configMINIMAL_STACK_SIZE (configSTACK_DEPTH_TYPE)512 +#define configUSE_16_BIT_TICKS 0 + +#define configIDLE_SHOULD_YIELD 1 + +/* Synchronization Related */ +#define configUSE_MUTEXES 1 +#define configUSE_RECURSIVE_MUTEXES 1 +#define configUSE_APPLICATION_TASK_TAG 0 +#define configUSE_COUNTING_SEMAPHORES 1 +#define configQUEUE_REGISTRY_SIZE 8 +#define configUSE_QUEUE_SETS 1 +#define configUSE_TIME_SLICING 1 +#define configUSE_NEWLIB_REENTRANT 0 +// todo need this for lwip FreeRTOS sys_arch to compile +#define configENABLE_BACKWARD_COMPATIBILITY 1 +#define configNUM_THREAD_LOCAL_STORAGE_POINTERS 5 + +/* System */ +#define configSTACK_DEPTH_TYPE uint32_t +#define configMESSAGE_BUFFER_LENGTH_TYPE size_t + +/* Memory allocation related definitions. */ +#define configSUPPORT_STATIC_ALLOCATION 0 +#define configSUPPORT_DYNAMIC_ALLOCATION 1 +#define configTOTAL_HEAP_SIZE (128 * 1024) +#define configAPPLICATION_ALLOCATED_HEAP 0 + +/* Hook function related definitions. */ +#define configCHECK_FOR_STACK_OVERFLOW 0 +#define configUSE_MALLOC_FAILED_HOOK 0 +#define configUSE_DAEMON_TASK_STARTUP_HOOK 0 + +/* Run time and task stats gathering related definitions. */ +#define configGENERATE_RUN_TIME_STATS 0 +#define configUSE_TRACE_FACILITY 1 +#define configUSE_STATS_FORMATTING_FUNCTIONS 0 + +/* Co-routine related definitions. */ +#define configUSE_CO_ROUTINES 0 +#define configMAX_CO_ROUTINE_PRIORITIES 1 + +/* Software timer related definitions. */ +#define configUSE_TIMERS 1 +#define configTIMER_TASK_PRIORITY (configMAX_PRIORITIES - 1) +#define configTIMER_QUEUE_LENGTH 10 +#define configTIMER_TASK_STACK_DEPTH 1024 + +/* Interrupt nesting behaviour configuration. */ +/* +#define configKERNEL_INTERRUPT_PRIORITY [dependent of processor] +#define configMAX_SYSCALL_INTERRUPT_PRIORITY [dependent on processor and +application] #define configMAX_API_CALL_INTERRUPT_PRIORITY [dependent on +processor and application] +*/ + +#define configNUMBER_OF_CORES 2 +/* SMP (configNUMBER_OF_CORES > 1) only */ +#define configTICK_CORE 0 +#define configRUN_MULTIPLE_PRIORITIES 1 +#if configNUMBER_OF_CORES > 1 +#define configUSE_CORE_AFFINITY 1 +#endif +#define configUSE_PASSIVE_IDLE_HOOK 0 + +/* Armv8-M */ + +/* Not currently supported */ +#define configENABLE_MPU 0 +// #define configSYSTEM_CALL_STACK_SIZE ( configSTACK_DEPTH_TYPE ) +// 512 +#define configENABLE_FPU 1 +/* Not currently supported */ +#define configENABLE_TRUSTZONE 0 +#define configRUN_FREERTOS_SECURE_ONLY 1 +// see https://www.freertos.org/RTOS-Cortex-M3-M4.html +#define configMAX_SYSCALL_INTERRUPT_PRIORITY 16 + +/* RP2xxx specific */ +#define configSUPPORT_PICO_SYNC_INTEROP 1 +#define configSUPPORT_PICO_TIME_INTEROP 1 + +#include +/* Define to trap errors during development. */ +#define configASSERT(x) assert(x) + +/* Set the following definitions to 1 to include the API function, or zero +to exclude the API function. */ +#define INCLUDE_vTaskPrioritySet 1 +#define INCLUDE_uxTaskPriorityGet 1 +#define INCLUDE_vTaskDelete 1 +#define INCLUDE_vTaskSuspend 1 +#define INCLUDE_vTaskDelayUntil 1 +#define INCLUDE_vTaskDelay 1 +#define INCLUDE_xTaskGetSchedulerState 1 +#define INCLUDE_xTaskGetCurrentTaskHandle 1 +#define INCLUDE_uxTaskGetStackHighWaterMark 1 +#define INCLUDE_xTaskGetIdleTaskHandle 1 +#define INCLUDE_eTaskGetState 1 +#define INCLUDE_xTimerPendFunctionCall 1 +#define INCLUDE_xTaskAbortDelay 1 +#define INCLUDE_xTaskGetHandle 1 +#define INCLUDE_xTaskResumeFromISR 1 +#define INCLUDE_xQueueGetMutexHolder 1 + +/* A header file that defines trace macro can be included here. */ + +#endif /* FREERTOS_CONFIG_H */ diff --git a/embedded/include/lwipopts.h b/embedded/include/lwipopts.h new file mode 100644 index 00000000..e2fbc276 --- /dev/null +++ b/embedded/include/lwipopts.h @@ -0,0 +1,104 @@ +#ifndef _LWIPOPTS_H +#define _LWIPOPTS_H + + +// Common settings used in most of the pico_w examples +// (see https://www.nongnu.org/lwip/2_1_x/group__lwip__opts.html for details) + +// allow override in some examples +#ifndef NO_SYS +#define NO_SYS 0 +#endif +// allow override in some examples +#ifndef LWIP_SOCKET +#define LWIP_SOCKET 1 +#endif +#if PICO_CYW43_ARCH_POLL +#define MEM_LIBC_MALLOC 1 +#else +// MEM_LIBC_MALLOC is incompatible with non polling versions +#define MEM_LIBC_MALLOC 0 +#endif +#define MEM_ALIGNMENT 4 +#ifndef MEM_SIZE +#define MEM_SIZE 4000 +#endif +#define MEMP_NUM_TCP_SEG 32 +#define MEMP_NUM_ARP_QUEUE 10 +#define PBUF_POOL_SIZE 24 +#define LWIP_ARP 1 +#define LWIP_ETHERNET 1 +#define LWIP_ICMP 1 +#define LWIP_RAW 1 +#define TCP_WND (8 * TCP_MSS) +#define TCP_MSS 1460 +#define TCP_SND_BUF (8 * TCP_MSS) +#define TCP_SND_QUEUELEN ((4 * (TCP_SND_BUF) + (TCP_MSS - 1)) / (TCP_MSS)) +#define LWIP_NETIF_STATUS_CALLBACK 1 +#define LWIP_NETIF_LINK_CALLBACK 1 +#define LWIP_NETIF_HOSTNAME 1 +#define LWIP_NETCONN 0 +#define MEM_STATS 0 +#define SYS_STATS 0 +#define MEMP_STATS 0 +#define LINK_STATS 0 +// #define ETH_PAD_SIZE 2 +#define LWIP_CHKSUM_ALGORITHM 3 +#define LWIP_DHCP 1 +#define LWIP_IPV4 1 +#define LWIP_TCP 1 +#define LWIP_UDP 1 +#define LWIP_DNS 1 +#define LWIP_TCP_KEEPALIVE 1 +#define LWIP_NETIF_TX_SINGLE_PBUF 1 +#define DHCP_DOES_ARP_CHECK 0 +#define LWIP_DHCP_DOES_ACD_CHECK 0 + +#ifndef NDEBUG +#define LWIP_DEBUG 1 +#define LWIP_STATS 1 +#define LWIP_STATS_DISPLAY 1 +#endif + +#define ETHARP_DEBUG LWIP_DBG_OFF +#define NETIF_DEBUG LWIP_DBG_OFF +#define PBUF_DEBUG LWIP_DBG_OFF +#define API_LIB_DEBUG LWIP_DBG_OFF +#define API_MSG_DEBUG LWIP_DBG_OFF +#define SOCKETS_DEBUG LWIP_DBG_OFF +#define ICMP_DEBUG LWIP_DBG_OFF +#define INET_DEBUG LWIP_DBG_OFF +#define IP_DEBUG LWIP_DBG_OFF +#define IP_REASS_DEBUG LWIP_DBG_OFF +#define RAW_DEBUG LWIP_DBG_OFF +#define MEM_DEBUG LWIP_DBG_OFF +#define MEMP_DEBUG LWIP_DBG_OFF +#define SYS_DEBUG LWIP_DBG_OFF +#define TCP_DEBUG LWIP_DBG_OFF +#define TCP_INPUT_DEBUG LWIP_DBG_OFF +#define TCP_OUTPUT_DEBUG LWIP_DBG_OFF +#define TCP_RTO_DEBUG LWIP_DBG_OFF +#define TCP_CWND_DEBUG LWIP_DBG_OFF +#define TCP_WND_DEBUG LWIP_DBG_OFF +#define TCP_FR_DEBUG LWIP_DBG_OFF +#define TCP_QLEN_DEBUG LWIP_DBG_OFF +#define TCP_RST_DEBUG LWIP_DBG_OFF +#define UDP_DEBUG LWIP_DBG_OFF +#define TCPIP_DEBUG LWIP_DBG_OFF +#define PPP_DEBUG LWIP_DBG_OFF +#define SLIP_DEBUG LWIP_DBG_OFF +#define DHCP_DEBUG LWIP_DBG_OFF + +#if !NO_SYS +#define TCPIP_THREAD_STACKSIZE 1024 +#define DEFAULT_THREAD_STACKSIZE 1024 +#define DEFAULT_RAW_RECVMBOX_SIZE 8 +#define TCPIP_MBOX_SIZE 8 +#define LWIP_TIMEVAL_PRIVATE 0 +#endif + +#define LWIP_TIMEVAL_PRIVATE 0 +#define LWIP_SOCKET_POLL 0 + + +#endif /* __LWIPOPTS_H__ */ diff --git a/embedded/include/mbedtls_config.h b/embedded/include/mbedtls_config.h new file mode 100644 index 00000000..3f5940b9 --- /dev/null +++ b/embedded/include/mbedtls_config.h @@ -0,0 +1,71 @@ +#ifndef SST_MBEDTLS_CONFIG_H +#define SST_MBEDTLS_CONFIG_H + +#define MBEDTLS_AES_C +#define MBEDTLS_ASN1_PARSE_C +#define MBEDTLS_ASN1_WRITE_C +#define MBEDTLS_BASE64_C +#define MBEDTLS_BIGNUM_C +#define MBEDTLS_CIPHER_C +#define MBEDTLS_CIPHER_MODE_CBC +#define MBEDTLS_CIPHER_MODE_CTR +#define MBEDTLS_CIPHER_MODE_GCM +#define MBEDTLS_CIPHER_PADDING_PKCS7 +#define MBEDTLS_CTR_DRBG_C +#define MBEDTLS_ENTROPY_C +#define MBEDTLS_ERROR_C +#undef MBEDTLS_FS_IO +#define MBEDTLS_GCM_C +#define MBEDTLS_MD_C +#define MBEDTLS_OID_C +#define MBEDTLS_PEM_PARSE_C +#define MBEDTLS_PEM_WRITE_C +#define MBEDTLS_PK_C +#define MBEDTLS_PK_PARSE_C +#define MBEDTLS_PK_WRITE_C +#define MBEDTLS_PKCS1_V15 +#define MBEDTLS_PKCS1_V21 +#define MBEDTLS_RSA_C +#define MBEDTLS_SHA1_C +#define MBEDTLS_SHA256_C +#define MBEDTLS_X509_USE_C +#define MBEDTLS_X509_CRT_PARSE_C + +#undef MBEDTLS_AESNI_C +#undef MBEDTLS_AESCE_C +#undef MBEDTLS_ARIA_C +#undef MBEDTLS_CAMELLIA_C +#undef MBEDTLS_CHACHA20_C +#undef MBEDTLS_CHACHAPOLY_C +#undef MBEDTLS_DES_C +#undef MBEDTLS_DHM_C +#undef MBEDTLS_ECP_C +#undef MBEDTLS_ECDH_C +#undef MBEDTLS_ECDSA_C +#undef MBEDTLS_ECJPAKE_C +#undef MBEDTLS_HMAC_DRBG_C +#undef MBEDTLS_LMS_C +#undef MBEDTLS_MD5_C +#undef MBEDTLS_NIST_KW_C +#undef MBEDTLS_PSA_CRYPTO_C +#undef MBEDTLS_PSA_CRYPTO_SE_C +#undef MBEDTLS_PSA_CRYPTO_STORAGE_C +#undef MBEDTLS_RIPEMD160_C +#undef MBEDTLS_SHA384_C +#undef MBEDTLS_SHA512_C +#undef MBEDTLS_SHA3_C +#undef MBEDTLS_THREADING_C +#undef MBEDTLS_TIMING_C +#undef MBEDTLS_USE_PSA_CRYPTO + +#undef MBEDTLS_HAVE_TIME +#undef MBEDTLS_HAVE_TIME_DATE + +// #if defined(SST_PLATFORM_PICO) +#define MBEDTLS_NO_PLATFORM_ENTROPY +#define MBEDTLS_ENTROPY_HARDWARE_ALT +// #endif + +// #include "mbedtls/check_config.h" + +#endif /* SST_MBEDTLS_CONFIG_H */ diff --git a/embedded/include/sst_mbedtls.h b/embedded/include/sst_mbedtls.h deleted file mode 100644 index 480e8f73..00000000 --- a/embedded/include/sst_mbedtls.h +++ /dev/null @@ -1,35 +0,0 @@ -#ifndef SST_CRYPTO_EMBEDDED_H -#define SST_CRYPTO_EMBEDDED_H - -#include -#include - -#define SST_KEY_SIZE 16 -#define SST_NONCE_SIZE 12 -#define SST_TAG_SIZE 16 - -// Encrypt using AES-GCM with provided key & nonce. -// @param key AES-128 key (16 bytes) -// @param nonce Nonce (12 bytes, must be unique per message) -// @param input Plaintext input buffer -// @param input_len Length of plaintext -// @param ciphertext Output buffer for encrypted data -// @param tag Output buffer for authentication tag (16 bytes) -// @return 0 on success, non-zero on failure -int sst_encrypt_gcm(const uint8_t* key, const uint8_t* nonce, - const uint8_t* input, size_t input_len, uint8_t* ciphertext, - uint8_t* tag); - -// Decrypt using AES-GCM with provided key, nonce, and tag. -// @param key AES-128 key (16 bytes) -// @param nonce Nonce used during encryption -// @param ciphertext Input buffer with encrypted data -// @param ciphertext_len Length of ciphertext -// @param tag Authentication tag (16 bytes) -// @param output Output buffer for decrypted plaintext -// @return 0 on success, non-zero if authentication fails -int sst_decrypt_gcm(const uint8_t* key, const uint8_t* nonce, - const uint8_t* ciphertext, size_t ciphertext_len, - const uint8_t* tag, uint8_t* output); - -#endif // SST_CRYPTO_EMBEDDED_H diff --git a/embedded/lib/FreeRTOS-Kernel b/embedded/lib/FreeRTOS-Kernel new file mode 160000 index 00000000..fed39c5e --- /dev/null +++ b/embedded/lib/FreeRTOS-Kernel @@ -0,0 +1 @@ +Subproject commit fed39c5ea7483dde7bf7c92950d49e6b75539f5a diff --git a/embedded/lib/mbedtls b/embedded/lib/mbedtls deleted file mode 160000 index edb8fec9..00000000 --- a/embedded/lib/mbedtls +++ /dev/null @@ -1 +0,0 @@ -Subproject commit edb8fec9882084344a314368ac7fd957a187519c diff --git a/embedded/lib/pico-sdk b/embedded/lib/pico-sdk new file mode 160000 index 00000000..a1438dff --- /dev/null +++ b/embedded/lib/pico-sdk @@ -0,0 +1 @@ +Subproject commit a1438dff1d38bd9c65dbd693f0e5db4b9ae91779 diff --git a/embedded/src/sst_mbedtls.c b/embedded/src/sst_mbedtls.c deleted file mode 100644 index da413597..00000000 --- a/embedded/src/sst_mbedtls.c +++ /dev/null @@ -1,43 +0,0 @@ -// sst_crypto_embedded.c -#include "../include/sst_crypto_embedded.h" -#include "mbedtls/gcm.h" - -int sst_encrypt_gcm(const uint8_t* key, const uint8_t* nonce, - const uint8_t* input, size_t input_len, uint8_t* ciphertext, - uint8_t* tag) { - mbedtls_gcm_context gcm; - mbedtls_gcm_init(&gcm); - - int ret = mbedtls_gcm_setkey(&gcm, MBEDTLS_CIPHER_ID_AES, key, 128); - if (ret != 0) { - mbedtls_gcm_free(&gcm); - return ret; - } - - ret = mbedtls_gcm_crypt_and_tag(&gcm, MBEDTLS_GCM_ENCRYPT, input_len, nonce, - SST_NONCE_SIZE, NULL, 0, input, ciphertext, - SST_TAG_SIZE, tag); - - mbedtls_gcm_free(&gcm); - return ret; -} - -int sst_decrypt_gcm(const uint8_t* key, const uint8_t* nonce, - const uint8_t* ciphertext, size_t ciphertext_len, - const uint8_t* tag, uint8_t* output) { - mbedtls_gcm_context gcm; - mbedtls_gcm_init(&gcm); - - int ret = mbedtls_gcm_setkey(&gcm, MBEDTLS_CIPHER_ID_AES, key, 128); - if (ret != 0) { - mbedtls_gcm_free(&gcm); - return ret; - } - - ret = mbedtls_gcm_auth_decrypt(&gcm, ciphertext_len, nonce, SST_NONCE_SIZE, - NULL, 0, tag, SST_TAG_SIZE, ciphertext, - output); - - mbedtls_gcm_free(&gcm); - return ret; -} diff --git a/examples/README.md b/examples/README.md new file mode 100644 index 00000000..ffec1389 --- /dev/null +++ b/examples/README.md @@ -0,0 +1,82 @@ +# SST C API Examples + +This directory contains several example programs that demonstrate how to use the `sst-c-api` with the main [SST (Secure Swarm Toolkit) repo](https://github.com/iotauth/iotauth). + +For the rest of this document, we use `$SST_ROOT` for the root directory of SST’s main repository (`iotauth`), and this repository (`sst-c-api`) is assumed to be checked out as a submodule under `$SST_ROOT/entity/c`. + +Each subdirectory here has its own `README.md` with detailed build and run instructions. This file gives a high-level overview and links into those examples. + +--- + +## 1. Server–Client Example + +A minimal example showing how to build a secure client–server application using SST: + +- Uses Auth to distribute session keys between a client and a server. +- Demonstrates basic secure messaging over TCP channels. +- Shows how to configure entities via `.config` files and connect them through Auth. + +For compilation and step-by-step run instructions, see: + +- [`server_client_example/README.md`](./server_client_example/README.md) + +--- + +## 2. IPFS Examples + +Examples that integrate SST with [IPFS](https://ipfs.tech/) to realize a secure file-sharing workflow: + +- `entity_uploader` encrypts a file with an SST session key and uploads it to IPFS. +- `entity_downloader` obtains the file hash and session key information from a file system manager, retrieves the encrypted file from IPFS, and decrypts it using SST. +- Includes both C and C++ entity implementations. + +For compilation and step-by-step run instructions, see: + +- Higher-level description in the main SST repo: + [`$SST_ROOT/examples/file_sharing/README.md`](https://github.com/iotauth/iotauth/tree/master/examples/file_sharing) +- C example: [`ipfs_examples/c/README.md`](./ipfs_examples/c/README.md) +- C++ example: [`ipfs_examples/cpp/README.md`](./ipfs_examples/cpp/README.md) + +--- + +## 3. File Block Encrypt Example + +An example focused on **block-based file encryption**, inspired by RocksDB-style block layouts: + +- Random key–value pairs are packed into fixed-size (32 KB) blocks. +- Remaining space in a block is zero-padded. +- Each block is encrypted with a session key obtained via SST. +- Multiple encrypted blocks are written into files, along with metadata describing the session keys used. +- A separate reader: + - Loads metadata. + - Requests corresponding session keys. + - Decrypts the blocks and verifies them against plaintext copies. + +For compilation and step-by-step run instructions, see: + +- [`file_block_encrypt_example/README.md`](./file_block_encrypt_example/README.md) + +--- + +## 4. SST Testbed + +A testbed to experiment attacks on SST. + +- Uses Auth, example entities, and CSV-driven traffic patterns. +- Includes: + 1. **Basic messaging** between client and server. + 2. **Replay attack** scenarios (sequence number manipulation). + 3. **Denial of Service (DoS) attacks**: + - To Auth via excessive session key requests (DoSK). + - To server via repeated message sending (DoSM). + - To server (and indirectly Auth) via repeated connection requests (DoSC). + 4. **Distributed DoS (DDoS)-style scenarios** with multiple clients. + +For compilation steps, and detailed instructions for each scenario, see: + +- [`SST_Testbed/README.md`](./SST_Testbed/README.md) + +--- + +Each of these examples is designed to be run together with the Java Auth server in `$SST_ROOT/auth/auth-server/`. +For deeper background on the architecture and example setups, refer to the corresponding `README.md` files in the main SST (`iotauth`) repository as well. \ No newline at end of file diff --git a/examples/scenario_example/CMakeLists.txt b/examples/SST_Testbed/CMakeLists.txt similarity index 92% rename from examples/scenario_example/CMakeLists.txt rename to examples/SST_Testbed/CMakeLists.txt index 1751d1d2..06e4463b 100644 --- a/examples/scenario_example/CMakeLists.txt +++ b/examples/SST_Testbed/CMakeLists.txt @@ -1,6 +1,6 @@ cmake_minimum_required(VERSION 3.10) -project(scenario_example) +project(SST_Testbed) # Add the main SST library add_subdirectory(../../ ${CMAKE_BINARY_DIR}/sst-lib-build) diff --git a/examples/scenario_example/README.md b/examples/SST_Testbed/README.md similarity index 94% rename from examples/scenario_example/README.md rename to examples/SST_Testbed/README.md index 956df01d..0b013cd3 100644 --- a/examples/scenario_example/README.md +++ b/examples/SST_Testbed/README.md @@ -52,9 +52,9 @@ $ git submodule update --init 1. Go to directory `iotauth/examples` -### Compile the scenario code +### Compile the SST_Testbed code -1. Go to `iotauth/entity/c/examples/scenario_example/` +1. Go to `iotauth/entity/c/examples/SST_Testbed/` 2. Run `mkdir build && cd build` @@ -89,7 +89,7 @@ However, for convenience, DoS attacks with multiple clients have it's own script ## 1. Basic Messaging -1. Go to `$ROOT/entity/c/examples/scenario_example/` +1. Go to `$ROOT/entity/c/examples/SST_Testbed/` 2. *[Optional]* Customize `csv_files/basic_messages.csv` to have the client send custom messages to the server. - The format of the input CSV file for this example should be: @@ -112,7 +112,7 @@ However, for convenience, DoS attacks with multiple clients have it's own script ## 2. Attack Scenarios ## 2.1 Replay Attack -1. Go to `$ROOT/entity/c/examples/scenario_example/` +1. Go to `$ROOT/entity/c/examples/SST_Testbed/` 2. *[Optional]* Customize `csv_files/replay_attack.csv` to have the client send custom messages and replay attacks to the server, - The format of the input CSV file for this attack example should be: @@ -136,7 +136,7 @@ However, for convenience, DoS attacks with multiple clients have it's own script ## 2.2 Denial of Service (DoS) attack ## 2.2.1 DoS attack to Auth via session key requests (DoSK) -1. Go to `$ROOT/entity/c/examples/scenario_example/` +1. Go to `$ROOT/entity/c/examples/SST_Testbed/` 2. *[Optional]* Customize `csv_files/dos_attack_key.csv` to have the client send custom messages and DoS attacks to the server. - The format of the input CSV file for this attack example should be: @@ -158,7 +158,7 @@ However, for convenience, DoS attacks with multiple clients have it's own script ## 2.2.2 DoS attack to Server via session key requests (DoSM) -1. Go to `$ROOT/entity/c/examples/scenario_example/` +1. Go to `$ROOT/entity/c/examples/SST_Testbed/` 2. *[Optional]* Customize `csv_files/dos_attack_message.csv` to have the client send custom messages and DoS attacks to the server. - The format of the input CSV file for this attack example should be: @@ -180,7 +180,7 @@ However, for convenience, DoS attacks with multiple clients have it's own script ## 2.2.3 DoS attack to Server and Auth via connection requests (DoSC) -1. Go to `$ROOT/entity/c/examples/scenario_example/` +1. Go to `$ROOT/entity/c/examples/SST_Testbed/` 2. *[Optional]* Customize `csv_files/dos_attack_message.csv` to have the client send custom messages and DoS attacks to the server. - The format of the input CSV file for this attack example should be: @@ -206,7 +206,7 @@ So, also make sure that the ***Auth*** executed before is terminated. ### Create New Graph for Auth Databases and Configuration Files for the Clients -1. Go to `$ROOT/entity/c/examples/scenario_example/clients_dos_attack` +1. Go to `$ROOT/entity/c/examples/SST_Testbed/clients_dos_attack` 2. *[Optional]* `chmod +x clients_dos_setup.sh` diff --git a/examples/scenario_example/client.cpp b/examples/SST_Testbed/client.cpp similarity index 100% rename from examples/scenario_example/client.cpp rename to examples/SST_Testbed/client.cpp diff --git a/examples/scenario_example/clients_dos_attack/clients_dos_setup.sh b/examples/SST_Testbed/clients_dos_attack/clients_dos_setup.sh similarity index 100% rename from examples/scenario_example/clients_dos_attack/clients_dos_setup.sh rename to examples/SST_Testbed/clients_dos_attack/clients_dos_setup.sh diff --git a/examples/scenario_example/clients_dos_attack/config_generator.js b/examples/SST_Testbed/clients_dos_attack/config_generator.js similarity index 95% rename from examples/scenario_example/clients_dos_attack/config_generator.js rename to examples/SST_Testbed/clients_dos_attack/config_generator.js index 68b65f56..7b3fbb18 100644 --- a/examples/scenario_example/clients_dos_attack/config_generator.js +++ b/examples/SST_Testbed/clients_dos_attack/config_generator.js @@ -4,7 +4,7 @@ // Examples: ./configGenerator.js 100 -import fs from 'fs'; +import fs from 'fs'; import path from 'path'; // Parses the command line arguments @@ -71,4 +71,4 @@ for (let i = 0; i < count; i++) { fs.writeFileSync(out_path, out_lines.join('\n'), 'utf8'); } -console.log(`Generated ${count} configs in scenario_example/config/`); +console.log(`Generated ${count} configs in SST_Testbed/config/`); diff --git a/examples/scenario_example/clients_dos_attack/graph_generator.js b/examples/SST_Testbed/clients_dos_attack/graph_generator.js similarity index 100% rename from examples/scenario_example/clients_dos_attack/graph_generator.js rename to examples/SST_Testbed/clients_dos_attack/graph_generator.js diff --git a/examples/scenario_example/clients_dos_attack/run_clients.sh b/examples/SST_Testbed/clients_dos_attack/run_clients.sh similarity index 100% rename from examples/scenario_example/clients_dos_attack/run_clients.sh rename to examples/SST_Testbed/clients_dos_attack/run_clients.sh diff --git a/examples/scenario_example/csv_files/basic_messages.csv b/examples/SST_Testbed/csv_files/basic_messages.csv similarity index 100% rename from examples/scenario_example/csv_files/basic_messages.csv rename to examples/SST_Testbed/csv_files/basic_messages.csv diff --git a/examples/scenario_example/csv_files/dos_attack_connect.csv b/examples/SST_Testbed/csv_files/dos_attack_connect.csv similarity index 100% rename from examples/scenario_example/csv_files/dos_attack_connect.csv rename to examples/SST_Testbed/csv_files/dos_attack_connect.csv diff --git a/examples/scenario_example/csv_files/dos_attack_key.csv b/examples/SST_Testbed/csv_files/dos_attack_key.csv similarity index 100% rename from examples/scenario_example/csv_files/dos_attack_key.csv rename to examples/SST_Testbed/csv_files/dos_attack_key.csv diff --git a/examples/scenario_example/csv_files/dos_attack_message.csv b/examples/SST_Testbed/csv_files/dos_attack_message.csv similarity index 100% rename from examples/scenario_example/csv_files/dos_attack_message.csv rename to examples/SST_Testbed/csv_files/dos_attack_message.csv diff --git a/examples/scenario_example/csv_files/replay_attack.csv b/examples/SST_Testbed/csv_files/replay_attack.csv similarity index 100% rename from examples/scenario_example/csv_files/replay_attack.csv rename to examples/SST_Testbed/csv_files/replay_attack.csv diff --git a/examples/scenario_example/server.cpp b/examples/SST_Testbed/server.cpp similarity index 100% rename from examples/scenario_example/server.cpp rename to examples/SST_Testbed/server.cpp diff --git a/examples/file_block_encrypt_example/block_writer.c b/examples/file_block_encrypt_example/block_writer.c index 67375bb2..9bb6ecf1 100644 --- a/examples/file_block_encrypt_example/block_writer.c +++ b/examples/file_block_encrypt_example/block_writer.c @@ -1,5 +1,7 @@ #include "block_common.h" +#include "time.h" + int main(int argc, char* argv[]) { if (argc != 2) { SST_print_error_exit("Usage: %s ", argv[0]); diff --git a/examples/scenario_example/Instructions.txt b/examples/scenario_example/Instructions.txt deleted file mode 100644 index b71c661d..00000000 --- a/examples/scenario_example/Instructions.txt +++ /dev/null @@ -1,238 +0,0 @@ -SST TESTBED -=========== - -PREREQUISITES -------------- - -Auth ----- -1. OpenSSL command line tools for creating certificates and keystores of Auths and example entities -2. Java 11 or above -3. Maven CLI (http://maven.apache.org/ref/3.1.0/maven-embedder/cli.html) for building Auth from the command line -4. Node.js for running example server and client entities - -sst-c-api ---------- -1. OpenSSL 3.0 or above -2. CMake 3.19 or above - - -INSTALLATION ------------- - -Debian/Ubuntu -------------- -sudo apt-get update && sudo apt-get install -y \ - openjdk-11-jdk \ - maven \ - nodejs \ - npm \ - openssl \ - cmake \ - build-essential \ - pkg-config \ - libssl-dev - - -MacOS ------ -brew install openjdk@11 maven node openssl cmake pkg-config - - -VERIFY VERSIONS ---------------- -java -version -mvn -version -node -v -openssl version -cmake --version - - -CLONE REPOSITORY & UPDATE SUBMODULE ------------------------------------ -git clone https://github.com/iotauth/iotauth.git -cd iotauth -git submodule update --init - - - -COMPILATION ------------ - -Compilation of Auth -------------------- -1. Go to directory iotauth/examples - -Compile the scenario code -------------------------- -1. Go to iotauth/entity/c/examples/scenario_example/ -2. Run: mkdir build && cd build -3. Run: cmake .. - - Run: cmake -DCMAKE_BUILD_TYPE=Debug .. (for debugging mode) -4. Run: make - - -RUNNING EXAMPLES ----------------- -We have multiple examples to run. -1. Basic messaging examples with no attacks. -2. Attack scenarios - 2.1 Replay attack - 2.2 Denial of Service (DoS) attacks - 2.2.1 to Auth via session key requests (DoSK) - 2.2.2 to server via sending messages (DoSM) - 2.2.3 to server, and indirectly to Auth via connection requests (DoSC) - 2.3 Denial of Service (DoS) attacks with multiple clients - 2.3.1 DDoSK - 2.3.2 DDoSM - 2.3.3 DDoSC - -We clarify that all examples need the Auth to distribute keys, so launching the Auth once in one terminal will cover from Basic messaging examples to DoS attacks. -However, for convenience, DoS attacks with multiple clients have its own script to launch the Auth and clients. - - -Running the Auth ----------------- -1. Go to $ROOT/auth/auth-server/ -2. Build the executable jar file by running: mvn clean install -3. Run the jar file with the properties file for Auth101: - java -jar target/auth-server-jar-with-dependencies.jar -p ../properties/exampleAuth101.properties - - -1. Basic Messaging ------------------- -1. Go to $ROOT/entity/c/examples/scenario_example/ -2. [Optional] Customize csv_files/basic_messages.csv to have the client send custom messages to the server. - - The format of the input CSV file for this example should be: - - Each entry should be on its own line. - - First is amount of time spent sleeping (in milliseconds). - - Second is the message. - - The sleep time and message are always separated by only a single comma. - Example: - , - , - ... - -3. Run: cd build -4. Run the server: - ./server ../../server_client_example/c_server.config -5. Run the client in another terminal: - ./client ../../server_client_example/c_client.config ../csv_files/basic_messages.csv - -2. ATTACK SCENARIOS -=================== - -2.1 Replay Attack ------------------ -1. Go to $ROOT/entity/c/examples/scenario_example/ -2. [Optional] Customize csv_files/replay_attack.csv to have the client send custom messages and replay attacks to the server. - - The format of the input CSV file for this attack example should be: - - First and second are same as in Basic Messaging. - - Third is the attack type word: "Replay" (case insensitive). - - Fourth is the sequence number change because this attack revolves around modifying the sequence number. - - The formatting for changing the sequence number is "seq++", "seq--", or "seq=#" where # can be any integer. - - Example: - ,,Replay,seq-- - ,,REPLAY,seq++ - ,,replay,seq=12 - ... - -3. Run: cd build -4. Run the server: - ./server ../../server_client_example/c_server.config -5. Run the client in another terminal: - ./client ../../server_client_example/c_client.config ../csv_files/replay_attack.csv - - -2.2 Denial of Service (DoS) Attack ----------------------------------- - -2.2.1 DoS attack to Auth via session key requests (DoSK) --------------------------------------------------------- -1. Go to $ROOT/entity/c/examples/scenario_example/ -2. [Optional] Customize csv_files/dos_attack_key.csv to have the client send custom messages and DoS attacks to the server. - - The format of the input CSV file for this attack example should be: - - First and second are same as in Basic Messaging. - - Third is "DoSK". - - Fourth is the number of session key requests the client will make to Auth. - - Example: - ,,DoSK,10000 - ,,DOSK,55555 - ,,dosk,123456 - ... - -3. Run: cd build -4. Run the server: - ./server ../../server_client_example/c_server.config -5. Run the client in another terminal: - ./client ../../server_client_example/c_client.config ../csv_files/dos_attack_key.csv - -2.2.2 DoS attack to Server via session key requests (DoSM) ----------------------------------------------------------- -1. Go to $ROOT/entity/c/examples/scenario_example/ -2. [Optional] Customize csv_files/dos_attack_message.csv to have the client send custom messages and DoS attacks to the server. - - The format of the input CSV file for this attack example should be: - - First and second are same as in Basic Messaging. - - Third is "DoSM". - - Fourth is the number of times the message will be sent to the server. - - Example: - ,,DoSM,10000 - ,,DOSM,55555 - ,,dosm,123456 - ... - -3. Run: cd build -4. Run the server: - ./server ../../server_client_example/c_server.config -5. Run the client in another terminal: - ./client ../../server_client_example/c_client.config ../csv_files/dos_attack_message.csv - - -2.2.3 DoS attack to Server and Auth via connection requests (DoSC) ------------------------------------------------------------------- -1. Go to $ROOT/entity/c/examples/scenario_example/ -2. [Optional] Customize csv_files/dos_attack_message.csv to have the client send custom messages and DoS attacks to the server. - - The format of the input CSV file for this attack example should be: - - First and second are same as in Basic Messaging. - - Third is "DoSC". - - Fourth is the number of times the client should connect to the server using Auth. - - Example: - ,,DoSC,10000 - ,,DOSC,55555 - ,,dosc,123456 - ... - -3. Run: cd build -4. Run the server: - ./server ../../server_client_example/c_server.config -5. Run the client in another terminal: - ./client ../../server_client_example/c_client.config ../csv_files/dos_attack_connect.csv - - -2.3 DoS attack with Multiple Clients (DDoS) -------------------------------------------- -This attack involves using many clients to connect to the server to create the denial of service. -To do that, the Auth databases and configurations need to be modified to support this. -Make sure that the Auth executed before is terminated. - -Create New Graph for Auth Databases and Configuration Files for the Clients ---------------------------------------------------------------------------- -1. Go to $ROOT/entity/c/examples/scenario_example/clients_dos_attack -2. [Optional] chmod +x clients_dos_setup.sh -3. Run: ./client_dos_setup.sh -p - - is the maximum number of clients that Auth should be able to recognize and is defined by the parameter. - - [Optional] is the password of the generated Auth. - - Example: ./client_dos_setup.sh 3 -p asdf -4. Insert a password when prompted. -5. Run: ./run_clients.sh - - is the number of clients that should be created during this execution. - - is the input CSV file that the program should read for this execution. - - The format of the file should match the corresponding format for each attack type given above, - because the attacks are the same, only that multiple clients are performing the attack simultaneously. - - Example: ./run_clients.sh 3 ../csv_files/dos_attack_connect.csv - -Each client will be launched in a unique terminal window and will simultaneously perform the attack specified in the input CSV file. \ No newline at end of file diff --git a/examples/server_client_example/entity_client.c b/examples/server_client_example/entity_client.c index fd4c2f74..c246f306 100644 --- a/examples/server_client_example/entity_client.c +++ b/examples/server_client_example/entity_client.c @@ -2,6 +2,7 @@ #include #include #include +#include #include "../../c_api.h" diff --git a/examples/server_client_example/entity_server.c b/examples/server_client_example/entity_server.c index 6f4fabd1..0af56ff4 100644 --- a/examples/server_client_example/entity_server.c +++ b/examples/server_client_example/entity_server.c @@ -4,6 +4,7 @@ #include #include #include +#include #include "../../c_api.h" diff --git a/examples/server_client_example/threaded_get_target_id_server.c b/examples/server_client_example/threaded_get_target_id_server.c index b5f9fdbb..bd78fe91 100644 --- a/examples/server_client_example/threaded_get_target_id_server.c +++ b/examples/server_client_example/threaded_get_target_id_server.c @@ -37,13 +37,11 @@ void* call_get_session_key_by_ID(void* args) { printf("Session Key ID from file %s: %u\n", file_path, convert_skid_buf_to_int(target_session_key_id, SESSION_KEY_ID_SIZE)); - pthread_mutex_lock(&ctx->mutex); session_key_t* session_key = get_session_key_by_ID(target_session_key_id, ctx, s_key_list); if (session_key == NULL) { SST_print_error_exit("Failed get_session_key_by_ID()."); } - pthread_mutex_unlock(&ctx->mutex); if (session_key) { printf( @@ -67,7 +65,8 @@ int main(int argc, char* argv[]) { if (ctx == NULL) { SST_print_error_exit("init_SST() failed."); } - pthread_mutex_init(&ctx->mutex, NULL); + // Make sure to update distribution key. + session_key_list_t* s_key_list = get_session_key(ctx, NULL); pthread_t threads[3]; thread_args_t args[3] = { @@ -81,7 +80,5 @@ int main(int argc, char* argv[]) { for (int i = 0; i < 3; i++) { pthread_join(threads[i], NULL); } - - pthread_mutex_destroy(&ctx->mutex); return 0; } diff --git a/ipfs.c b/ipfs.c index 049b00f2..776509b0 100644 --- a/ipfs.c +++ b/ipfs.c @@ -1,5 +1,7 @@ #include "ipfs.h" +#include +#include #include #include diff --git a/load_config.c b/load_config.c index 9466a7dc..40c1e526 100644 --- a/load_config.c +++ b/load_config.c @@ -65,7 +65,7 @@ int safe_config_value_copy(char* dest, const char* src, size_t dest_size) { return -1; } else { dest[dest_size - 1] = 0; - strncpy(dest, src, dest_size); + snprintf(dest, dest_size, "%s", src); if (dest[dest_size - 1] != 0) { SST_print_error( "Problem found while copying config value, dest string is not " @@ -76,7 +76,7 @@ int safe_config_value_copy(char* dest, const char* src, size_t dest_size) { return 1; } } - +#ifdef USE_OPENSSL int load_config(config_t* c, const char* path) { FILE* fp = fopen(path, "r"); if (fp == NULL) { @@ -281,3 +281,233 @@ int load_config(config_t* c, const char* path) { fclose(fp); return 0; } +#elif defined(SST_PLATFORM_PICO) +int load_config(config_t* c, const char* path) { + // In PICO builds, `path` actually holds the entire config text. + // Parse line-by-line and populate `c`, skipping multi-line PEM blocks. + if (!c || !path) { + SST_print_error("load_config(): NULL input."); + return -1; + } + // Defaults (match desktop loader) + unsigned short purpose_count = 0; // Option for ipfs. + c->purpose_index = 0; // Option for ipfs. + c->hmac_mode = USE_HMAC; // Default with HMAC. + c->encryption_mode = AES_128_CBC; // Default encryption mode. + + enum ParserState { + NORMAL = 0, + SKIP_CERT, // inside -----BEGIN CERTIFICATE----- ... -----END + // CERTIFICATE----- + SKIP_PRIVKEY // inside -----BEGIN PRIVATE KEY----- ... -----END PRIVATE + // KEY----- + } state = NORMAL; + + const char* p = path; + char linebuf[MAX_CONFIG_BUF_SIZE]; + + while (*p) { + // Extract one line + size_t len = 0; + const char* start = p; + while (p[len] && p[len] != '\n' && len + 1 < sizeof(linebuf)) { + len++; + } + // Copy to buffer (truncate safely if too long) + size_t copy_len = + (len < sizeof(linebuf) - 1) ? len : (sizeof(linebuf) - 1); + memcpy(linebuf, start, copy_len); + linebuf[copy_len] = '\0'; + + // Advance p past this line (and the newline if present) + p += len; + if (*p == '\n') p++; + + // Skip empty lines + if (linebuf[0] == '\0') continue; + + // Handle skipping PEM blocks + if (state == SKIP_CERT) { + if (strstr(linebuf, "-----END CERTIFICATE-----") != NULL) { + state = NORMAL; + } + continue; + } else if (state == SKIP_PRIVKEY) { + if (strstr(linebuf, "-----END PRIVATE KEY-----") != NULL) { + state = NORMAL; + } + continue; + } + + // If the line doesn't contain '=', it could be part of PEM + // (unexpected), ignore. + char* eq = strchr(linebuf, '='); + if (!eq) { + continue; + } + + *eq = '\0'; + char* key = linebuf; + char* val = eq + 1; + + // Trim simple whitespace on both sides of value + while (*val == ' ' || *val == '\t') val++; + // rtrim key + for (int i = (int)strlen(key) - 1; + i >= 0 && (key[i] == ' ' || key[i] == '\t'); --i) { + key[i] = '\0'; + } + + // Determine config key + config_type_t cfg = get_key_value(key); + + // If this is a PEM-carrying key, enter skip state and ignore multi-line + // payload. + if (cfg == AUTH_INFO_PUBKEY_PATH) { + // In embedded builds we ignore on-disk paths and embedded PEM + // payloads. + state = SKIP_CERT; // subsequent lines until END CERTIFICATE + continue; + } else if (cfg == ENTITY_INFO_PRIVKEY_PATH) { + state = SKIP_PRIVKEY; // subsequent lines until END PRIVATE KEY + continue; + } + + // Populate fields for the remaining keys (single-line values) + switch (cfg) { + case ENTITY_INFO_NAME: + if (safe_config_value_copy(c->name, val, sizeof(c->name)) < 0) { + SST_print_error( + "Failed safe_config_value_copy() ENTITY_INFO_NAME"); + return -1; + } + break; + + case ENTITY_INFO_PURPOSE: + if (purpose_count <= 1) { + if (safe_config_value_copy( + c->purpose[purpose_count], val, + sizeof(c->purpose[purpose_count])) < 0) { + SST_print_error( + "Failed safe_config_value_copy() " + "ENTITY_INFO_PURPOSE"); + return -1; + } + purpose_count += 1; + } else { + SST_print_debug("Error for wrong number of purpose."); + } + c->purpose_index = purpose_count - 1; + break; + + case ENTITY_INFO_NUMKEY: + c->numkey = atoi(val); + break; + + case ENCRYPTION_MODE: + if (strcmp(val, "AES_128_CBC") == 0) { + c->encryption_mode = AES_128_CBC; + } else if (strcmp(val, "AES_128_CTR") == 0) { + c->encryption_mode = AES_128_CTR; + } else if (strcmp(val, "AES_128_GCM") == 0) { + c->encryption_mode = AES_128_GCM; + } + break; + + case HMAC_MODE: + if (strcmp(val, "off") == 0 || strcmp(val, "0") == 0) { + c->hmac_mode = NO_HMAC; + } else if (strcmp(val, "on") == 0 || strcmp(val, "1") == 0) { + c->hmac_mode = USE_HMAC; + } else { + SST_print_error("Wrong input for hmac_mode."); + return -1; + } + break; + + case AUTH_ID: + c->auth_id = atoi(val); + break; + + case AUTH_INFO_IP_ADDRESS: + if (safe_config_value_copy(c->auth_ip_addr, val, + sizeof(c->auth_ip_addr)) < 0) { + SST_print_error( + "Failed safe_config_value_copy() AUTH_INFO_IP_ADDRESS"); + return -1; + } + break; + + case AUTH_INFO_PORT: { + int port = atoi(val); + if (port < 0 || port > 65535) { + SST_print_error("Error: Invalid Auth port number."); + return -1; + } + c->auth_port_num = port; + break; + } + + case ENTITY_SERVER_INFO_IP_ADDRESS: + if (safe_config_value_copy(c->entity_server_ip_addr, val, + sizeof(c->entity_server_ip_addr)) < + 0) { + SST_print_error( + "Failed safe_config_value_copy() " + "ENTITY_SERVER_INFO_IP_ADDRESS"); + return -1; + } + break; + + case ENTITY_SERVER_INFO_PORT_NUMBER: { + int port = atoi(val); + if (port < 0 || port > 65535) { + SST_print_error("Error: Invalid server port number."); + return -1; + } + c->entity_server_port_num = port; + break; + } + + case NETWORK_PROTOCOL: + if (safe_config_value_copy(c->network_protocol, val, + sizeof(c->network_protocol)) < 0) { + SST_print_error( + "Failed safe_config_value_copy() NETWORK_PROTOCOL"); + return -1; + } + break; + + case FILE_SYSTEM_MANAGER_INFO_IP_ADDRESS: + if (safe_config_value_copy( + c->file_system_manager_ip_addr, val, + sizeof(c->file_system_manager_ip_addr)) < 0) { + SST_print_error( + "Failed safe_config_value_copy() " + "FILE_SYSTEM_MANAGER_INFO_IP_ADDRESS"); + return -1; + } + break; + + case FILE_SYSTEM_MANAGER_INFO_PORT_NUMBER: { + int port = atoi(val); + if (port < 0 || port > 65535) { + SST_print_error( + "Error: Invalid file system manager port number."); + return -1; + } + c->file_system_manager_port_num = port; + break; + } + + case UNKNOWN_CONFIG: + default: + // Ignore unknown lines in embedded mode. + break; + } + } + + return 0; +} + +#endif diff --git a/platform_compat.h b/platform_compat.h new file mode 100644 index 00000000..ea65bbe3 --- /dev/null +++ b/platform_compat.h @@ -0,0 +1,62 @@ +#ifndef SST_PLATFORM_COMPAT_H +#define SST_PLATFORM_COMPAT_H + +#include +#include +#include +#include + +#ifdef SST_PLATFORM_PICO +#include "lwip/api.h" +#include "lwip/inet.h" +#include "lwip/ip4_addr.h" +#include "lwip/ip_addr.h" +#include "lwip/netdb.h" +#include "lwip/netif.h" +#include "lwip/sockets.h" +#include "pico/cyw43_arch.h" +#include "pico/time.h" + +static inline void sst_platform_sleep_us(uint32_t micros) { sleep_us(micros); } + +static inline int sst_inet_pton(int af, const char* src, void* dst) { + if (af == AF_INET) { + ip_addr_t addr; + if (!ipaddr_aton(src, &addr)) { + return 0; + } + *(uint32_t*)dst = ip4_addr_get_u32(ip_2_ip4(&addr)); + return 1; + } + return 0; +} + +static inline uint64_t sst_platform_now_ms(void) { + return to_ms_since_boot(get_absolute_time()); +} + +#else /* !SST_PLATFORM_PICO */ + +#include +#include +#include +#include +#include + +static inline void sst_platform_sleep_us(uint32_t micros) { + usleep((useconds_t)micros); +} + +static inline int sst_inet_pton(int af, const char* src, void* dst) { + return inet_pton(af, src, dst); +} + +static inline uint64_t sst_platform_now_ms(void) { + struct timespec ts; + clock_gettime(CLOCK_REALTIME, &ts); + return (uint64_t)ts.tv_sec * 1000ULL + (uint64_t)ts.tv_nsec / 1000000ULL; +} + +#endif /* SST_PLATFORM_PICO */ + +#endif /* SST_PLATFORM_COMPAT_H */ diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 8d9bb965..cf15f4cf 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -4,9 +4,6 @@ project(SST_TEST LANGUAGES C) # Add the root directory, which contains the sst-c-api library add_subdirectory(.. sst-build) -find_package(OpenSSL REQUIRED) -find_package(Threads REQUIRED) - # Create test executables add_executable(c_crypto_test c_crypto_test.c) add_executable(multi_thread_get_session_key_test multi_thread_get_session_key_test.c) diff --git a/tests/c_crypto_test.c b/tests/c_crypto_test.c index d9618eeb..40aa4c29 100644 --- a/tests/c_crypto_test.c +++ b/tests/c_crypto_test.c @@ -13,6 +13,8 @@ #include "../c_crypto.h" #include +#include +#include #include "../c_api.h" #include "../c_common.h" @@ -29,8 +31,8 @@ void AES_test_common(AES_encryption_mode_t mode) { // Generate buffer const char plaintext[] = "Hello World!"; - printf("Plaintext Length: %ld, Plaintext: %s\n", strlen(plaintext), - plaintext); + SST_print_log("Plaintext Length: %ld, Plaintext: %s", strlen(plaintext), + plaintext); // Encrypt Cipher unsigned char cipher[100]; @@ -42,7 +44,7 @@ void AES_test_common(AES_encryption_mode_t mode) { } // Returns IV(16) + cipher + (HMAC(32)) - printf("Cipher Length: %d, Cipher Text: ", length); + SST_print_log("Cipher Length: %d, Cipher Text: ", length); print_buf_log(cipher, length); unsigned char decrypted[100]; @@ -52,26 +54,25 @@ void AES_test_common(AES_encryption_mode_t mode) { &decrypted_length) < 0) { SST_print_error_exit("Failed decrypt_AES()."); } - printf("Decrypted Length: %d, Decrypted: %s\n", decrypted_length, - decrypted); + SST_print_log("Decrypted Length: %d, Decrypted: %s\n", decrypted_length, + decrypted); assert(decrypted_length == strlen(plaintext)); assert(strncmp((const char*)decrypted, (const char*)plaintext, decrypted_length) == 0); - printf("\n"); } void AES_CBC_test(void) { - printf("**** STARTING AES_CBC_TEST.\n"); + SST_print_log("**** STARTING AES_CBC_TEST."); AES_test_common(AES_128_CBC); } void AES_CTR_test(void) { - printf("**** STARTING AES_CTR_TEST.\n"); + SST_print_log("**** STARTING AES_CTR_TEST."); AES_test_common(AES_128_CTR); } void AES_GCM_test(void) { - printf("**** STARTING AES_GCM_TEST.\n"); + SST_print_log("**** STARTING AES_GCM_TEST."); AES_test_common(AES_128_GCM); } @@ -94,8 +95,8 @@ void symmetric_encrypt_decrypt_authenticate_common(char enc_mode, // Generate buffer const char plaintext[] = "Hello World!"; - printf("Plaintext Length: %ld, Plaintext: %s\n", strlen(plaintext), - plaintext); + SST_print_log("Plaintext Length: %ld, Plaintext: %s", strlen(plaintext), + plaintext); int s; _unused(s); unsigned int encrypted_length; @@ -108,20 +109,19 @@ void symmetric_encrypt_decrypt_authenticate_common(char enc_mode, MAC_KEY_SHA256_SIZE, cipher_key, AES_128_KEY_SIZE_IN_BYTES, AES_128_IV_SIZE, enc_mode, hmac_mode, &encrypted, &encrypted_length); - printf("Cipher Length: %d, Cipher Text: ", encrypted_length); + SST_print_log("Cipher Length: %d, Cipher Text: ", encrypted_length); print_buf_log(encrypted, encrypted_length); assert(s == 0); s = symmetric_decrypt_authenticate( encrypted, encrypted_length, mac_key, MAC_KEY_SHA256_SIZE, cipher_key, AES_128_KEY_SIZE_IN_BYTES, AES_128_CBC_IV_SIZE, enc_mode, hmac_mode, &decrypted, &decrypted_length); - printf("Decrypted Length: %d, Decrypted: %s\n", decrypted_length, - decrypted); + SST_print_log("Decrypted Length: %d, Decrypted: %s\n", decrypted_length, + decrypted); assert(s == 0); assert(decrypted_length == strlen(plaintext)); assert(strncmp((const char*)decrypted, (const char*)plaintext, decrypted_length) == 0); - printf("\n"); free(encrypted); free(decrypted); } else { @@ -136,7 +136,7 @@ void symmetric_encrypt_decrypt_authenticate_common(char enc_mode, AES_128_IV_SIZE, enc_mode, hmac_mode, &encrypted_stack[0], &encrypted_length); encrypted = &encrypted_stack[0]; - printf("Cipher Length: %d, Cipher Text: ", encrypted_length); + SST_print_log("Cipher Length: %d, Cipher Text: ", encrypted_length); print_buf_log(encrypted, encrypted_length); assert(s == 0); unsigned int estimate_decrypted_length = @@ -149,13 +149,12 @@ void symmetric_encrypt_decrypt_authenticate_common(char enc_mode, cipher_key, AES_128_KEY_SIZE_IN_BYTES, AES_128_IV_SIZE, enc_mode, hmac_mode, &decrypted_stack[0], &decrypted_length); decrypted = &decrypted_stack[0]; - printf("Decrypted Length: %d, Decrypted: %s\n", decrypted_length, - decrypted); + SST_print_log("Decrypted Length: %d, Decrypted: %s\n", decrypted_length, + decrypted); assert(s == 0); assert(decrypted_length == strlen(plaintext)); assert(strncmp((const char*)decrypted, (const char*)plaintext, decrypted_length) == 0); - printf("\n"); } } @@ -164,38 +163,41 @@ void symmetric_encrypt_decrypt_authenticate_common(char enc_mode, // allocation (malloc). void symmetric_encrypt_decrypt_authenticate_AES_128_CBC_test(void) { - printf("**** STARTING symmetric_encrypt_authenticate_AES_128_CBC_test.\n"); + SST_print_log( + "**** STARTING symmetric_encrypt_authenticate_AES_128_CBC_test."); symmetric_encrypt_decrypt_authenticate_common(AES_128_CBC, 0, 0); } void symmetric_encrypt_decrypt_authenticate_AES_128_CTR_test(void) { - printf("**** STARTING symmetric_encrypt_authenticate_AES_128_CTR_test.\n"); + SST_print_log( + "**** STARTING symmetric_encrypt_authenticate_AES_128_CTR_test."); symmetric_encrypt_decrypt_authenticate_common(AES_128_CTR, 0, 0); } void symmetric_encrypt_decrypt_authenticate_AES_128_GCM_test(void) { - printf("**** STARTING symmetric_encrypt_authenticate_AES_128_GCM_test.\n"); + SST_print_log( + "**** STARTING symmetric_encrypt_authenticate_AES_128_GCM_test."); symmetric_encrypt_decrypt_authenticate_common(AES_128_GCM, 0, 0); } void symmetric_encrypt_decrypt_authenticate_AES_128_CBC_noHMAC_test(void) { - printf( + SST_print_log( "**** STARTING " - "symmetric_encrypt_authenticate_AES_128_CBC_noHMAC_test.\n"); + "symmetric_encrypt_authenticate_AES_128_CBC_noHMAC_test."); symmetric_encrypt_decrypt_authenticate_common(AES_128_CBC, 1, 0); } void symmetric_encrypt_decrypt_authenticate_AES_128_CTR_noHMAC_test(void) { - printf( + SST_print_log( "**** STARTING " - "symmetric_encrypt_authenticate_AES_128_CTR_noHMAC_test.\n"); + "symmetric_encrypt_authenticate_AES_128_CTR_noHMAC_test."); symmetric_encrypt_decrypt_authenticate_common(AES_128_CTR, 1, 0); } void symmetric_encrypt_decrypt_authenticate_AES_128_GCM_noHMAC_test(void) { - printf( + SST_print_log( "**** STARTING " - "symmetric_encrypt_authenticate_AES_128_GCM_noHMAC_test.\n"); + "symmetric_encrypt_authenticate_AES_128_GCM_noHMAC_test."); symmetric_encrypt_decrypt_authenticate_common(AES_128_GCM, 1, 0); } @@ -205,52 +207,52 @@ void symmetric_encrypt_decrypt_authenticate_AES_128_GCM_noHMAC_test(void) { void symmetric_encrypt_decrypt_authenticate_AES_128_CBC_without_malloc_test( void) { - printf( + SST_print_log( "**** STARTING " - "symmetric_encrypt_authenticate_AES_128_CBC_without_malloc_test.\n"); + "symmetric_encrypt_authenticate_AES_128_CBC_without_malloc_test."); symmetric_encrypt_decrypt_authenticate_common(AES_128_CBC, 0, 1); } void symmetric_encrypt_decrypt_authenticate_AES_128_CTR_without_malloc_test( void) { - printf( + SST_print_log( "**** STARTING " - "symmetric_encrypt_authenticate_AES_128_CTR_without_malloc_test.\n"); + "symmetric_encrypt_authenticate_AES_128_CTR_without_malloc_test."); symmetric_encrypt_decrypt_authenticate_common(AES_128_CTR, 0, 1); } void symmetric_encrypt_decrypt_authenticate_AES_128_GCM_without_malloc_test( void) { - printf( + SST_print_log( "**** STARTING " - "symmetric_encrypt_authenticate_AES_128_GCM_without_malloc_test.\n"); + "symmetric_encrypt_authenticate_AES_128_GCM_without_malloc_test."); symmetric_encrypt_decrypt_authenticate_common(AES_128_GCM, 0, 1); } void symmetric_encrypt_decrypt_authenticate_AES_128_CBC_noHMAC_without_malloc_test( void) { - printf( + SST_print_log( "**** STARTING " "symmetric_encrypt_authenticate_AES_128_CBC_noHMAC_without_malloc_test." - "\n"); + ""); symmetric_encrypt_decrypt_authenticate_common(AES_128_CBC, 1, 1); } void symmetric_encrypt_decrypt_authenticate_AES_128_CTR_noHMAC_without_malloc_test( void) { - printf( + SST_print_log( "**** STARTING " "symmetric_encrypt_authenticate_AES_128_CTR_noHMAC_without_malloc_test." - "\n"); + ""); symmetric_encrypt_decrypt_authenticate_common(AES_128_CTR, 1, 1); } void symmetric_encrypt_decrypt_authenticate_AES_128_GCM_noHMAC_without_malloc_test( void) { - printf( + SST_print_log( "**** STARTING " "symmetric_encrypt_authenticate_AES_128_GCM_noHMAC_without_malloc_test." - "\n"); + ""); symmetric_encrypt_decrypt_authenticate_common(AES_128_GCM, 1, 1); } @@ -259,9 +261,9 @@ void symmetric_encrypt_decrypt_authenticate_AES_128_GCM_noHMAC_without_malloc_te // encryption modes: AES-CBC AES-CTR AES-GCM void symmetric_encrypt_decrypt_authenticate_AES_128_with_malloc_test(void) { - printf( + SST_print_log( "**** STARTING " - "symmetric_encrypt_authenticate_AES_128_with_malloc_tests.\n"); + "symmetric_encrypt_authenticate_AES_128_with_malloc_tests."); symmetric_encrypt_decrypt_authenticate_AES_128_CBC_test(); symmetric_encrypt_decrypt_authenticate_AES_128_CTR_test(); symmetric_encrypt_decrypt_authenticate_AES_128_GCM_test(); @@ -271,9 +273,9 @@ void symmetric_encrypt_decrypt_authenticate_AES_128_with_malloc_test(void) { } void symmetric_encrypt_decrypt_authenticate_AES_128_without_malloc_test(void) { - printf( + SST_print_log( "**** STARTING " - "symmetric_encrypt_authenticate_AES_128_without_malloc_tests.\n"); + "symmetric_encrypt_authenticate_AES_128_without_malloc_tests."); symmetric_encrypt_decrypt_authenticate_AES_128_CBC_without_malloc_test(); symmetric_encrypt_decrypt_authenticate_AES_128_CTR_without_malloc_test(); symmetric_encrypt_decrypt_authenticate_AES_128_GCM_without_malloc_test(); diff --git a/tests/encrypt_buf_with_session_key_without_malloc_execution_time_test.c b/tests/encrypt_buf_with_session_key_without_malloc_execution_time_test.c index d3825cdc..9f4a6dca 100644 --- a/tests/encrypt_buf_with_session_key_without_malloc_execution_time_test.c +++ b/tests/encrypt_buf_with_session_key_without_malloc_execution_time_test.c @@ -16,12 +16,12 @@ * encryption and decryption times per block and per file for performance * evaluation. */ -#include #include #include #include #include "../c_api.h" +#include "../c_common.h" #define FILE_ITERATION 100 #define BLOCK_ITERATION 16384 #define BLOCK_SIZE 4096 @@ -48,7 +48,7 @@ int main(int argc, char* argv[]) { unsigned char plaintext_buf[BLOCK_SIZE]; // Insert random bytes inside buffer. - RAND_bytes(plaintext_buf, BLOCK_SIZE); + generate_nonce(BLOCK_SIZE, plaintext_buf); unsigned char encrypted_data[BLOCK_SIZE + 16]; unsigned char decrypted_data[BLOCK_SIZE]; diff --git a/tests/multi_thread_get_session_key_test.c b/tests/multi_thread_get_session_key_test.c index 93109eb9..297197c3 100644 --- a/tests/multi_thread_get_session_key_test.c +++ b/tests/multi_thread_get_session_key_test.c @@ -7,6 +7,7 @@ * @copyright Copyright (c) 2025 * */ +#include #include #include #include