diff --git a/CMakeLists.txt b/CMakeLists.txt index ddb48c24536152bf65f911cdd25beef42f65fbc6..be75e5ac0de71be972e58dd3aef88594ebe94429 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,10 +1,14 @@ -cmake_minimum_required(VERSION 3.10) +cmake_minimum_required(VERSION 3.11) # 3.11 required for FetchContent project(sm_engine VERSION 1.0.0 LANGUAGES C) # Set C standard set(CMAKE_C_STANDARD 99) set(CMAKE_C_STANDARD_REQUIRED ON) +# Include required modules +include(ExternalProject) +include(ProcessorCount) + # Options option(BUILD_SHARED_LIBS "Build shared libraries" ON) option(BUILD_TESTS "Build test programs" ON) @@ -12,6 +16,7 @@ option(BUILD_EXAMPLES "Build example programs" ON) option(ENABLE_DEBUG "Enable debug build" OFF) option(ENABLE_ASAN "Enable AddressSanitizer" OFF) option(ENABLE_VALGRIND "Enable Valgrind memory checks" OFF) +option(AUTO_BUILD_OPENSSL "Automatically build OpenSSL if not found" ON) # Set default build type if not specified if(NOT CMAKE_BUILD_TYPE) @@ -67,9 +72,43 @@ set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin) set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib) set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib) +# Determine number of cores for parallel build +ProcessorCount(NPROC) +if(NPROC EQUAL 0) + set(NPROC 4) +endif() + +# Git submodule auto-initialization +find_package(Git QUIET) +if(GIT_FOUND) + message(STATUS "Checking git submodules...") + execute_process( + COMMAND ${GIT_EXECUTABLE} submodule status 3rd/openssl + WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} + OUTPUT_VARIABLE GIT_SUBMODULE_STATUS + RESULT_VARIABLE GIT_SUBMOD_RESULT + OUTPUT_STRIP_TRAILING_WHITESPACE + ) + + # Check if submodule needs initialization (status starts with -) + if(GIT_SUBMOD_RESULT OR "${GIT_SUBMODULE_STATUS}" MATCHES "^-") + message(STATUS "Initializing git submodule 3rd/openssl...") + execute_process( + COMMAND ${GIT_EXECUTABLE} submodule update --init 3rd/openssl + WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} + RESULT_VARIABLE GIT_SUBMOD_RESULT + ) + if(GIT_SUBMOD_RESULT) + message(WARNING "Failed to initialize git submodule. Will attempt to continue anyway.") + endif() + endif() +endif() + # OpenSSL configuration - use the one from 3rd/openssl # IMPORTANT: We explicitly use the OpenSSL from 3rd/openssl, NOT the system OpenSSL set(OPENSSL_ROOT_DIR "${CMAKE_SOURCE_DIR}/3rd/openssl" CACHE PATH "Path to OpenSSL root directory") +set(OPENSSL_BUILD_DIR "${CMAKE_BINARY_DIR}/openssl-build" CACHE PATH "OpenSSL build directory") +set(OPENSSL_INSTALL_DIR "${CMAKE_BINARY_DIR}/openssl-install" CACHE PATH "OpenSSL install directory") # Prevent CMake from finding system OpenSSL set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY NEVER) @@ -78,29 +117,97 @@ unset(OPENSSL_INCLUDE_DIR CACHE) unset(OPENSSL_SSL_LIBRARY CACHE) unset(OPENSSL_CRYPTO_LIBRARY CACHE) -# Check if OpenSSL is built -if(EXISTS "${OPENSSL_ROOT_DIR}/build/lib/libcrypto.a") - set(OPENSSL_CRYPTO_LIBRARY "${OPENSSL_ROOT_DIR}/build/lib/libcrypto.a" CACHE FILEPATH "Path to OpenSSL crypto library" FORCE) - set(OPENSSL_INCLUDE_DIR "${OPENSSL_ROOT_DIR}/build/include" CACHE PATH "Path to OpenSSL include directory" FORCE) -elseif(EXISTS "${OPENSSL_ROOT_DIR}/libcrypto.a") - set(OPENSSL_CRYPTO_LIBRARY "${OPENSSL_ROOT_DIR}/libcrypto.a" CACHE FILEPATH "Path to OpenSSL crypto library" FORCE) - set(OPENSSL_INCLUDE_DIR "${OPENSSL_ROOT_DIR}/include" CACHE PATH "Path to OpenSSL include directory" FORCE) -else() - message(FATAL_ERROR "OpenSSL libcrypto.a not found. Please build OpenSSL first:\n" +# Function to check if OpenSSL is built +function(check_openssl_built) + if(EXISTS "${OPENSSL_INSTALL_DIR}/lib/libcrypto.a") + set(OPENSSL_FOUND TRUE PARENT_SCOPE) + set(OPENSSL_CRYPTO_LIBRARY "${OPENSSL_INSTALL_DIR}/lib/libcrypto.a" CACHE FILEPATH "Path to OpenSSL crypto library" FORCE) + set(OPENSSL_INCLUDE_DIR "${OPENSSL_INSTALL_DIR}/include" CACHE PATH "Path to OpenSSL include directory" FORCE) + elseif(EXISTS "${OPENSSL_ROOT_DIR}/build/lib/libcrypto.a") + set(OPENSSL_FOUND TRUE PARENT_SCOPE) + set(OPENSSL_CRYPTO_LIBRARY "${OPENSSL_ROOT_DIR}/build/lib/libcrypto.a" CACHE FILEPATH "Path to OpenSSL crypto library" FORCE) + set(OPENSSL_INCLUDE_DIR "${OPENSSL_ROOT_DIR}/build/include" CACHE PATH "Path to OpenSSL include directory" FORCE) + elseif(EXISTS "${OPENSSL_ROOT_DIR}/libcrypto.a") + set(OPENSSL_FOUND TRUE PARENT_SCOPE) + set(OPENSSL_CRYPTO_LIBRARY "${OPENSSL_ROOT_DIR}/libcrypto.a" CACHE FILEPATH "Path to OpenSSL crypto library" FORCE) + set(OPENSSL_INCLUDE_DIR "${OPENSSL_ROOT_DIR}/include" CACHE PATH "Path to OpenSSL include directory" FORCE) + else() + set(OPENSSL_FOUND FALSE PARENT_SCOPE) + endif() +endfunction() + +# Check if OpenSSL is already built +check_openssl_built() + +if(NOT OPENSSL_FOUND AND AUTO_BUILD_OPENSSL) + message(STATUS "OpenSSL not found. Building OpenSSL as external project...") + + # Check if OpenSSL source exists + if(NOT EXISTS "${OPENSSL_ROOT_DIR}/Configure") + message(FATAL_ERROR "OpenSSL source not found at ${OPENSSL_ROOT_DIR}. " + "Please ensure git submodule is initialized:\n" + " git submodule update --init 3rd/openssl") + endif() + + # Configure OpenSSL build command based on platform + if(APPLE) + # Detect architecture on macOS + execute_process( + COMMAND uname -m + OUTPUT_VARIABLE APPLE_ARCH + OUTPUT_STRIP_TRAILING_WHITESPACE + ) + if(APPLE_ARCH STREQUAL "arm64") + set(OPENSSL_CONFIGURE_COMMAND ./Configure darwin64-arm64-cc) + else() + set(OPENSSL_CONFIGURE_COMMAND ./Configure darwin64-x86_64-cc) + endif() + message(STATUS "Detected macOS architecture: ${APPLE_ARCH}") + else() + set(OPENSSL_CONFIGURE_COMMAND ./config) + endif() + + # Add OpenSSL as external project (OpenSSL requires in-source build) + ExternalProject_Add( + openssl_external + SOURCE_DIR ${OPENSSL_ROOT_DIR} + INSTALL_DIR ${OPENSSL_INSTALL_DIR} + CONFIGURE_COMMAND ${CMAKE_COMMAND} -E chdir ${OPENSSL_ROOT_DIR} + ${OPENSSL_CONFIGURE_COMMAND} + --prefix=${OPENSSL_INSTALL_DIR} + no-shared + no-tests + BUILD_COMMAND ${CMAKE_COMMAND} -E chdir ${OPENSSL_ROOT_DIR} + make -j${NPROC} + BUILD_IN_SOURCE 1 + INSTALL_COMMAND ${CMAKE_COMMAND} -E chdir ${OPENSSL_ROOT_DIR} + make install_sw + BUILD_BYPRODUCTS + ${OPENSSL_INSTALL_DIR}/lib/libcrypto.a + ${OPENSSL_INSTALL_DIR}/include/openssl/engine.h + ) + + # Set OpenSSL paths after build + set(OPENSSL_CRYPTO_LIBRARY "${OPENSSL_INSTALL_DIR}/lib/libcrypto.a" CACHE FILEPATH "Path to OpenSSL crypto library" FORCE) + set(OPENSSL_INCLUDE_DIR "${OPENSSL_INSTALL_DIR}/include" CACHE PATH "Path to OpenSSL include directory" FORCE) + set(OPENSSL_BUILD_REQUIRED TRUE) + + message(STATUS "OpenSSL will be built to: ${OPENSSL_INSTALL_DIR}") + message(STATUS "Using ${NPROC} parallel jobs for OpenSSL build") +elseif(NOT OPENSSL_FOUND) + message(FATAL_ERROR "OpenSSL libcrypto.a not found and AUTO_BUILD_OPENSSL is disabled.\n" + "Either enable AUTO_BUILD_OPENSSL or build OpenSSL manually:\n" " cd ${OPENSSL_ROOT_DIR}\n" " ./config --prefix=\${PWD}/build\n" " make -j4\n" " make install_sw") +else() + message(STATUS "Found existing OpenSSL:") + message(STATUS " Include: ${OPENSSL_INCLUDE_DIR}") + message(STATUS " Library: ${OPENSSL_CRYPTO_LIBRARY}") + set(OPENSSL_BUILD_REQUIRED FALSE) endif() -# Check for OpenSSL headers -if(NOT EXISTS "${OPENSSL_INCLUDE_DIR}/openssl/engine.h") - message(FATAL_ERROR "OpenSSL headers not found at ${OPENSSL_INCLUDE_DIR}") -endif() - -message(STATUS "OpenSSL include: ${OPENSSL_INCLUDE_DIR}") -message(STATUS "OpenSSL crypto library: ${OPENSSL_CRYPTO_LIBRARY}") - # Platform-specific symbol export settings if(APPLE) set(SYMBOL_EXPORT_FILE "${CMAKE_SOURCE_DIR}/exported.symbols") @@ -173,4 +280,4 @@ message(STATUS " make run_asan_tests") message(STATUS "") message(STATUS " Install:") message(STATUS " sudo make install") -message(STATUS "=====================================") \ No newline at end of file +message(STATUS "=====================================") diff --git a/README.md b/README.md index bc372d624b23fccc3eda49c2dc49745e17e11120..3e21d457ecf3a571427e5e09a51c09b88aec44ca 100644 --- a/README.md +++ b/README.md @@ -22,16 +22,78 @@ ## 编译与使用 -### 一键构建(推荐) +### 方式一:CMake 构建(推荐) -使用 `build.sh` 脚本统一构建引擎与示例。支持为“引擎编译/链接”和“示例编译/链接”分别指定 OpenSSL 的头文件与库路径。 +使用 CMake 可以自动管理依赖和构建流程,支持自动构建 OpenSSL(如果本地没有)。 + +#### 基本构建步骤: + +```bash +# 1. 初始化并拉取 OpenSSL 子模块(如果尚未拉取) +git submodule update --init 3rd/openssl + +# 2. 创建构建目录 +mkdir build && cd build + +# 3. 配置项目(自动检测并构建 OpenSSL) +cmake .. + +# 4. 编译 +make -j + +#### CMake 配置选项: + +```bash +# 指定构建类型(Debug/Release) +cmake .. -DCMAKE_BUILD_TYPE=Release + +# 启用/禁用测试 +cmake .. -DBUILD_TESTING=ON + +# 启用 AddressSanitizer(内存检测) +cmake .. -DENABLE_ASAN=ON +make run_asan_tests + +# 启用 Valgrind 支持(内存泄漏检测) +cmake .. -DENABLE_VALGRIND=ON +make run_valgrind_tests + +# 指定安装路径 +cmake .. -DCMAKE_INSTALL_PREFIX=/usr/local + +# 安装引擎 +sudo make install +``` + +#### 性能测试: + +```bash +# 使用 OpenSSL speed 命令进行性能测试 +./openssl_speed_test.sh + +# 快速测试(仅运行1秒) +./build/openssl-install/bin/openssl speed -engine sm_ce_engine -evp sm3 -seconds 1 +./build/openssl-install/bin/openssl speed -engine sm_ce_engine -evp sm4-ecb -seconds 1 +./build/openssl-install/bin/openssl speed -engine sm_ce_engine -evp sm4-cbc -seconds 1 +``` + +#### CMake 输出产物: +- 引擎共享库:`build/lib/libsm_engine.so` (Linux) 或 `build/lib/libsm_engine.dylib` (macOS) +- 测试程序:`build/bin/example`, `build/bin/quick_test` +- OpenSSL(如自动构建):`build/openssl-install/` + +### 方式二:Shell 脚本构建 + +使用 `build.sh` 脚本统一构建引擎与示例。支持为"引擎编译/链接"和"示例编译/链接"分别指定 OpenSSL 的头文件与库路径。 常用参数: - `-oi, --openssl-include DIR` 引擎编译头文件目录(可重复) - `-ol, --openssl-lib-path FILE` 引擎链接使用的 OpenSSL 库路径(如 `libcrypto.a`) - `-ai, --app-include DIR` 示例/测试编译头文件目录(可重复) -- `-al, --app-lib-path FILE` 示例/测试链接使用的 OpenSSL 库路径 -- `--cc CC` 指定编译器;`--cflags '...'` 指定编译参数 +- `-sd, --so-dir DIR` 包含 libcrypto.so 的目录,用于示例/测试链接 +- `--cc CC` 指定编译器 +- `--cflags '...'` 指定编译参数 +- `-d, --debug` 启用调试模式(添加 -g -O0 标志) 构建引擎与示例: ```bash @@ -39,7 +101,7 @@ -oi ../../openssl-OpenSSL_1_1_1wc/include \ -ol ../../openssl-OpenSSL_1_1_1wc/libcrypto.a \ -ai ../../openssl-OpenSSL_1_1_1wc/include \ - -al ../../openssl-OpenSSL_1_1_1wc/libcrypto.a + -sd ../../openssl-OpenSSL_1_1_1wc ``` 运行示例: @@ -47,6 +109,22 @@ ./build.sh test ``` +调试模式构建: +```bash +./build.sh build -d \ + -oi ../../openssl-OpenSSL_1_1_1wc/include \ + -ol ../../openssl-OpenSSL_1_1_1wc/libcrypto.a +``` + +自定义编译器和编译参数: +```bash +./build.sh build \ + --cc clang \ + --cflags "-Wall -Wextra -O3 -fPIC" \ + -oi ../../openssl-OpenSSL_1_1_1wc/include \ + -ol ../../openssl-OpenSSL_1_1_1wc/libcrypto.a +``` + 安装引擎(默认安装到 `/usr/local/lib/engines`): ```bash sudo ./build.sh install @@ -114,13 +192,38 @@ default_algorithms = DIGESTS,CIPHERS - OpenSSL 1.1.1 或更高版本(示例使用 1.1.1 分支) - GCC/Clang 编译器 -- Make 工具(可选) +- CMake 3.10+ (使用 CMake 构建时需要) +- Make 工具 + +## 测试与验证 + +### 功能测试 +```bash +# 运行基础功能测试 +cd build +./bin/example # SM3/SM4 基础功能测试 +./bin/quick_test # 快速验证测试 +``` + +### 性能测试 +```bash +# 完整性能测试 +./openssl_speed_test.sh + +``` + +### 单独的引擎加载测试 +```bash +# 测试引擎是否正确加载 +./test_engine.sh +``` ## 故障排除 - 链接报 `unknown option --version-script`:macOS 上请使用 `exported.symbols` 方案(脚本已自动处理)。 - 运行找不到引擎:检查 `openssl.cnf` 的 `dynamic_path` 是否正确、引擎是否安装到系统默认目录。 - `NID_sm4_gcm` 未定义:当前示例未启用 GCM,启用前需确保外部 OpenSSL 提供该算法及符号。 +- CMake 找不到 OpenSSL:CMake 会自动从 git submodule 构建 OpenSSL 1.1.1,确保执行了 `git submodule update --init 3rd/openssl`。 ## 许可证 diff --git a/openssl_speed_test.sh b/openssl_speed_test.sh new file mode 100755 index 0000000000000000000000000000000000000000..593f075f2829a50123f34933b2f822ad1050d46a --- /dev/null +++ b/openssl_speed_test.sh @@ -0,0 +1,141 @@ +#!/bin/bash +# OpenSSL speed test script for SM engine +# Usage: ./openssl_speed_test.sh + +set -e + +# Get script directory +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" + +# Detect OS for library extension +if [[ "$OSTYPE" == "darwin"* ]]; then + LIB_EXT="dylib" +else + LIB_EXT="so" +fi + +# Find OpenSSL binary - prefer locally built one +OPENSSL_BIN="" +if [ -f "$SCRIPT_DIR/build/openssl-install/bin/openssl" ]; then + OPENSSL_BIN="$SCRIPT_DIR/build/openssl-install/bin/openssl" + echo "Using locally built OpenSSL" +else + OPENSSL_BIN="openssl" + echo "Using system OpenSSL" +fi + +# Check library exists +if [ ! -f "$SCRIPT_DIR/build/lib/libsm_engine.$LIB_EXT" ]; then + echo "Error: SM engine library not found at $SCRIPT_DIR/build/lib/libsm_engine.$LIB_EXT" + echo "Please build the engine first: mkdir build && cd build && cmake .. && make" + exit 1 +fi + +# Display configuration +echo "==========================================" +echo " SM Engine OpenSSL Speed Test" +echo "==========================================" +echo "OpenSSL binary: $OPENSSL_BIN" +echo "Engine library: $SCRIPT_DIR/build/lib/libsm_engine.$LIB_EXT" +echo "==========================================" +echo "" + +# Set up configuration and environment +if [ -d "$SCRIPT_DIR/build/openssl-install" ]; then + # We have locally built OpenSSL - use it with relative paths + + # Create config directory if needed + mkdir -p "$SCRIPT_DIR/build/openssl-install/ssl" + + # Generate configuration file with relative paths + cat > "$SCRIPT_DIR/build/openssl-install/ssl/openssl.cnf" < "$TEMP_CONF" < #include +#include #ifdef __cplusplus extern "C" { @@ -27,6 +28,13 @@ int SmSm4EcbCleanup(EVP_CIPHER_CTX *ctx); int SmSm4CbcImplCtxSize(void); int SmSm4EcbImplCtxSize(void); +/* SM4 ASN.1 and ctrl wrappers */ +int SmSm4CbcSetAsn1Params(EVP_CIPHER_CTX *ctx, ASN1_TYPE *asn1Type); +int SmSm4CbcGetAsn1Params(EVP_CIPHER_CTX *ctx, ASN1_TYPE *asn1Type); +int SmSm4EcbSetAsn1Params(EVP_CIPHER_CTX *ctx, ASN1_TYPE *asn1Type); +int SmSm4EcbGetAsn1Params(EVP_CIPHER_CTX *ctx, ASN1_TYPE *asn1Type); +int SmSm4CbcCtrl(EVP_CIPHER_CTX *ctx, int type, int arg, void *ptr); +int SmSm4EcbCtrl(EVP_CIPHER_CTX *ctx, int type, int arg, void *ptr); /* SM4 property helpers (read from external method) */ int SmSm4BlockSizeCbc(void); int SmSm4BlockSizeEcb(void); diff --git a/src/sm_engine.c b/src/sm_engine.c index 307fc9f008363312103bf954114d9803faa744d5..483a506ac350b534a16d519fcf3664b5aadaa540 100644 --- a/src/sm_engine.c +++ b/src/sm_engine.c @@ -85,6 +85,12 @@ static int InitSm3Digest(void) { if (!EVP_MD_meth_set_result_size(gSm3Md, SmSm3ResultSize())) { return 0; } + if (!EVP_MD_meth_set_flags(gSm3Md, SmSm3Flags())) { + return 0; + } + if (!EVP_MD_meth_set_input_blocksize(gSm3Md, SmSm3BlockSize())) { + return 0; + } if (!EVP_MD_meth_set_app_datasize(gSm3Md, SmSm3AppDatasize())) { return 0; } @@ -103,6 +109,9 @@ static int InitSm3Digest(void) { if (!EVP_MD_meth_set_cleanup(gSm3Md, SmSm3Cleanup)) { return 0; } + if (!EVP_MD_meth_set_ctrl(gSm3Md, SmSm3MdCtrl)) { + return 0; + } return 1; } @@ -128,6 +137,15 @@ static int InitSm4Cbc(void) { if (!EVP_CIPHER_meth_set_cleanup(gSm4Cbc, SmSm4CbcCleanup)) { return 0; } + if (!EVP_CIPHER_meth_set_ctrl(gSm4Cbc, SmSm4CbcCtrl)) { + return 0; + } + if (!EVP_CIPHER_meth_set_set_asn1_params(gSm4Cbc, SmSm4CbcSetAsn1Params)) { + return 0; + } + if (!EVP_CIPHER_meth_set_get_asn1_params(gSm4Cbc, SmSm4CbcGetAsn1Params)) { + return 0; + } if (!EVP_CIPHER_meth_set_impl_ctx_size(gSm4Cbc, SmSm4CbcImplCtxSize())) { return 0; } @@ -156,6 +174,15 @@ static int InitSm4Ecb(void) { if (!EVP_CIPHER_meth_set_cleanup(gSm4Ecb, SmSm4EcbCleanup)) { return 0; } + if (!EVP_CIPHER_meth_set_ctrl(gSm4Ecb, SmSm4EcbCtrl)) { + return 0; + } + if (!EVP_CIPHER_meth_set_set_asn1_params(gSm4Ecb, SmSm4EcbSetAsn1Params)) { + return 0; + } + if (!EVP_CIPHER_meth_set_get_asn1_params(gSm4Ecb, SmSm4EcbGetAsn1Params)) { + return 0; + } if (!EVP_CIPHER_meth_set_impl_ctx_size(gSm4Ecb, SmSm4EcbImplCtxSize())) { return 0; } @@ -186,6 +213,12 @@ static int SmInit(ENGINE *e) { /* Engine cleanup */ static int SmFinish(ENGINE *e) { + (void)e; + return 1; +} + +/* Engine destroy */ +static int SmDestroy(ENGINE *e) { (void)e; if (gSm3Md) { EVP_MD_meth_free(gSm3Md); @@ -202,12 +235,6 @@ static int SmFinish(ENGINE *e) { return 1; } -/* Engine destroy */ -static int SmDestroy(ENGINE *e) { - (void)e; - return 1; -} - /* Engine control */ static int SmCtrl(ENGINE *e, int cmd, long i, void *p, void (*f)(void)) { (void)e; @@ -244,5 +271,13 @@ static int SmBind(ENGINE *e, const char *id) { } /* Register the engine */ +/* Export v_check symbol for version compatibility */ +#ifdef __GNUC__ +__attribute__((visibility("default"))) +#endif IMPLEMENT_DYNAMIC_CHECK_FN() +/* Export bind_engine symbol for dynamic loading */ +#ifdef __GNUC__ +__attribute__((visibility("default"))) +#endif IMPLEMENT_DYNAMIC_BIND_FN(SmBind) diff --git a/test.sh b/test.sh deleted file mode 100755 index f440f7cdc5b7c44c4396420ed366ed1f1498678f..0000000000000000000000000000000000000000 --- a/test.sh +++ /dev/null @@ -1,40 +0,0 @@ -#!/bin/bash - -# SM Engine 测试脚本 - -echo "========================================" -echo " SM Engine 测试脚本" -echo "========================================" -echo "" - -# 设置路径 -SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" -BUILD_DIR="${SCRIPT_DIR}/build" -TEST_DIR="${SCRIPT_DIR}/test" - -# 检查编译 -if [ ! -f "${BUILD_DIR}/lib/libsm_engine.dylib" ]; then - echo "错误: 引擎未编译,请先运行:" - echo " mkdir build && cd build && cmake .. && make" - exit 1 -fi - -echo "1. 运行功能测试..." -echo "----------------------------------------" -cd "${BUILD_DIR}" -OPENSSL_CONF="${TEST_DIR}/openssl.cnf" ./bin/example -echo "" - -echo "2. 运行性能测试(快速版)..." -echo "----------------------------------------" -cd "${BUILD_DIR}" -OPENSSL_CONF="${TEST_DIR}/openssl.cnf" ./bin/quick_test -echo "" - -echo "注:完整性能测试可以通过以下命令运行:" -echo " cd build && OPENSSL_CONF=../test/openssl.cnf ./bin/performance -c" -echo "" - -echo "========================================" -echo " 测试完成" -echo "========================================" \ No newline at end of file diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index ccf01174999d4f170f0a8e7d71edce55a4614ea4..ca0f3f3a2291a911d74692260ff14d0d91463f07 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -10,6 +10,11 @@ include_directories( if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/example.c) add_executable(example example.c) + # If OpenSSL needs to be built first, add dependency + if(OPENSSL_BUILD_REQUIRED) + add_dependencies(example openssl_external) + endif() + # Link with the engine and OpenSSL target_link_libraries(example sm_engine @@ -39,38 +44,18 @@ if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/example.c) ) endif() -# Performance test program -if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/performance.c) - add_executable(performance performance.c) - - target_link_libraries(performance - sm_engine - ${OPENSSL_CRYPTO_LIBRARY} - ) - - if(UNIX AND NOT APPLE) - target_link_libraries(performance dl pthread) - endif() - - set_target_properties(performance PROPERTIES - INSTALL_RPATH_USE_LINK_PATH TRUE - BUILD_RPATH "${CMAKE_BINARY_DIR}/lib" - ) - - add_test(NAME performance_test - COMMAND performance - WORKING_DIRECTORY ${CMAKE_BINARY_DIR} - ) - - set_tests_properties(performance_test PROPERTIES - ENVIRONMENT "LD_LIBRARY_PATH=${CMAKE_BINARY_DIR}/lib:$ENV{LD_LIBRARY_PATH}" - ) -endif() +# Performance testing removed - use OpenSSL speed command instead +# Example: openssl speed -engine sm_ce_engine sm3 sm4-ecb sm4-cbc # Quick test program if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/quick_test.c) add_executable(quick_test quick_test.c) + # If OpenSSL needs to be built first, add dependency + if(OPENSSL_BUILD_REQUIRED) + add_dependencies(quick_test openssl_external) + endif() + target_link_libraries(quick_test sm_engine ${OPENSSL_CRYPTO_LIBRARY} @@ -90,6 +75,11 @@ endif() if(ENABLE_ASAN AND EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/test_asan.c) add_executable(test_asan test_asan.c) + # If OpenSSL needs to be built first, add dependency + if(OPENSSL_BUILD_REQUIRED) + add_dependencies(test_asan openssl_external) + endif() + # Include directories target_include_directories(test_asan PRIVATE ${CMAKE_SOURCE_DIR}/src diff --git a/test/openssl_build.cnf b/test/openssl_build.cnf new file mode 100644 index 0000000000000000000000000000000000000000..f5d8370552ce357e2bfca3539d6645cba41e28c4 --- /dev/null +++ b/test/openssl_build.cnf @@ -0,0 +1,21 @@ +# OpenSSL Engine Configuration for Build Directory Testing +# This config works from build/openssl-install/ssl directory +# Uses relative paths to work on different machines + +# Load the SM engine +openssl_conf = openssl_init + +[openssl_init] +engines = engine_section + +[engine_section] +sm_ce_engine = sm_section + +[sm_section] +engine_id = sm_ce_engine +# Relative path from build/openssl-install/ssl to build/lib +# OpenSSL will add the appropriate extension (.so on Linux, .dylib on macOS) +dynamic_path = ../../lib/libsm_engine.dylib +init = 1 +# 让引擎接管摘要和对称加密算法 +default_algorithms = DIGESTS,CIPHERS \ No newline at end of file diff --git a/test/openssl_linux.cnf b/test/openssl_linux.cnf new file mode 100644 index 0000000000000000000000000000000000000000..f2f4075a43e8c849df419a93f3a9e4015891c690 --- /dev/null +++ b/test/openssl_linux.cnf @@ -0,0 +1,19 @@ +# OpenSSL Engine Configuration for Linux Local Build Testing +# This config is for testing the locally built engine on Linux + +# Load the SM engine +openssl_conf = openssl_init + +[openssl_init] +engines = engine_section + +[engine_section] +sm_ce_engine = sm_section + +[sm_section] +engine_id = sm_ce_engine +# Path relative to build directory on Linux +dynamic_path = ./lib/libsm_engine.so +init = 1 +# 让引擎接管摘要和对称加密算法 +default_algorithms = DIGESTS,CIPHERS \ No newline at end of file diff --git a/test/openssl_macos.cnf b/test/openssl_macos.cnf new file mode 100644 index 0000000000000000000000000000000000000000..af065e1104792228dd383d9ef7bbcc7b4043b0dd --- /dev/null +++ b/test/openssl_macos.cnf @@ -0,0 +1,19 @@ +# OpenSSL Engine Configuration for macOS Local Build Testing +# This config is for testing the locally built engine on macOS + +# Load the SM engine +openssl_conf = openssl_init + +[openssl_init] +engines = engine_section + +[engine_section] +sm_ce_engine = sm_section + +[sm_section] +engine_id = sm_ce_engine +# Path relative to build directory on macOS +dynamic_path = ./lib/libsm_engine.dylib +init = 1 +# 让引擎接管摘要和对称加密算法 +default_algorithms = DIGESTS,CIPHERS \ No newline at end of file diff --git a/test/performance.c b/test/performance.c deleted file mode 100644 index 5f1ca300630faec355c35df41a7ff33b36b1b438..0000000000000000000000000000000000000000 --- a/test/performance.c +++ /dev/null @@ -1,526 +0,0 @@ -/* - * SM3/SM4 性能测试程序 - * 测试引擎的哈希和加密性能 - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define TEST_SECONDS 3 /* 每项测试运行秒数 */ -#define WARMUP_ITERATIONS 1000 /* 预热迭代次数 */ - -/* 全局退出标志 */ -static volatile int g_interrupted = 0; - -/* 测试数据大小 */ -static const int block_sizes[] = {16, 64, 256, 1024, 8192, 16384}; -static const int num_sizes = 6; - -/* 信号处理函数 */ -static void signal_handler(int sig) -{ - if (sig == SIGINT) { - printf("\n\n>>> 收到中断信号,正在退出...\n"); - g_interrupted = 1; - } -} - -/* 获取当前时间(微秒精度) */ -static double get_time(void) -{ - struct timeval tv; - gettimeofday(&tv, NULL); - return tv.tv_sec + tv.tv_usec / 1000000.0; -} - -/* 格式化输出大小 */ -static const char *format_size(long bytes) -{ - static char buf[32]; - if (bytes < 1024) { - snprintf(buf, sizeof(buf), "%ld B", bytes); - } else if (bytes < 1024 * 1024) { - snprintf(buf, sizeof(buf), "%.2f KB", bytes / 1024.0); - } else if (bytes < 1024 * 1024 * 1024) { - snprintf(buf, sizeof(buf), "%.2f MB", bytes / 1024.0 / 1024.0); - } else { - snprintf(buf, sizeof(buf), "%.2f GB", bytes / 1024.0 / 1024.0 / 1024.0); - } - return buf; -} - -/* 格式化输出速度 */ -static const char *format_speed(double bytes_per_sec) -{ - static char buf[32]; - if (bytes_per_sec < 1024) { - snprintf(buf, sizeof(buf), "%.2f B/s", bytes_per_sec); - } else if (bytes_per_sec < 1024 * 1024) { - snprintf(buf, sizeof(buf), "%.2f KB/s", bytes_per_sec / 1024.0); - } else if (bytes_per_sec < 1024 * 1024 * 1024) { - snprintf(buf, sizeof(buf), "%.2f MB/s", bytes_per_sec / 1024.0 / 1024.0); - } else { - snprintf(buf, sizeof(buf), "%.2f GB/s", bytes_per_sec / 1024.0 / 1024.0 / 1024.0); - } - return buf; -} - -/* 测试SM3性能 */ -static void benchmark_sm3(void) -{ - EVP_MD_CTX *ctx; - const EVP_MD *md; - unsigned char *buffer; - unsigned char hash[EVP_MAX_MD_SIZE]; - unsigned int hash_len; - int i, j; - double start, elapsed; - long iterations; - double total_bytes; - - printf("\n┌────────────────────────────────────────────────────┐\n"); - printf("│ SM3 哈希性能测试 │\n"); - printf("└────────────────────────────────────────────────────┘\n\n"); - - /* 获取SM3算法 */ - md = EVP_get_digestbyname("sm3"); - if (!md) { - printf("错误: SM3算法不可用\n"); - return; - } - - /* 创建上下文 */ - ctx = EVP_MD_CTX_new(); - if (!ctx) { - printf("错误: 无法创建MD上下文\n"); - return; - } - - printf("块大小 操作次数 总数据量 速度\n"); - printf("──────────────────────────────────────────────────────\n"); - - /* 测试不同大小的数据块 */ - for (i = 0; i < num_sizes; i++) { - if (g_interrupted) break; - int size = block_sizes[i]; - - /* 分配缓冲区 */ - buffer = malloc(size); - if (!buffer) { - printf("错误: 内存分配失败\n"); - continue; - } - RAND_bytes(buffer, size); - - /* 预热 */ - for (j = 0; j < WARMUP_ITERATIONS; j++) { - EVP_DigestInit_ex(ctx, md, NULL); - EVP_DigestUpdate(ctx, buffer, size); - EVP_DigestFinal_ex(ctx, hash, &hash_len); - } - - /* 正式测试 */ - iterations = 0; - start = get_time(); - do { - if (g_interrupted) break; - EVP_DigestInit_ex(ctx, md, NULL); - EVP_DigestUpdate(ctx, buffer, size); - EVP_DigestFinal_ex(ctx, hash, &hash_len); - iterations++; - elapsed = get_time() - start; - } while (elapsed < TEST_SECONDS && !g_interrupted); - - total_bytes = (double)iterations * size; - printf("%-12d %-10ld %-12s %s\n", - size, iterations, - format_size((long)total_bytes), - format_speed(total_bytes / elapsed)); - - free(buffer); - } - - EVP_MD_CTX_free(ctx); -} - -/* 测试SM4性能 */ -static void benchmark_sm4(const char *cipher_name, const char *display_name) -{ - EVP_CIPHER_CTX *ctx; - const EVP_CIPHER *cipher; - unsigned char key[16]; - unsigned char iv[16]; - unsigned char *plaintext; - unsigned char *ciphertext; - int outlen, tmplen; - int i, j; - double start, elapsed; - long iterations; - double total_bytes; - - printf("\n┌────────────────────────────────────────────────────┐\n"); - printf("│ %s 加密性能测试 │\n", display_name); - printf("└────────────────────────────────────────────────────┘\n\n"); - - /* 获取算法 */ - cipher = EVP_get_cipherbyname(cipher_name); - if (!cipher) { - printf("错误: %s算法不可用\n", cipher_name); - return; - } - - /* 初始化密钥和IV */ - RAND_bytes(key, sizeof(key)); - RAND_bytes(iv, sizeof(iv)); - - /* 创建上下文 */ - ctx = EVP_CIPHER_CTX_new(); - if (!ctx) { - printf("错误: 无法创建CIPHER上下文\n"); - return; - } - - printf("块大小 操作次数 总数据量 速度\n"); - printf("──────────────────────────────────────────────────────\n"); - - /* 测试不同大小的数据块 */ - for (i = 0; i < num_sizes; i++) { - if (g_interrupted) break; - int size = block_sizes[i]; - - /* 分配缓冲区 */ - plaintext = malloc(size); - ciphertext = malloc(size + EVP_CIPHER_block_size(cipher)); - if (!plaintext || !ciphertext) { - printf("错误: 内存分配失败\n"); - if (plaintext) free(plaintext); - if (ciphertext) free(ciphertext); - continue; - } - RAND_bytes(plaintext, size); - - /* 预热 */ - for (j = 0; j < WARMUP_ITERATIONS; j++) { - EVP_EncryptInit_ex(ctx, cipher, NULL, key, iv); - EVP_EncryptUpdate(ctx, ciphertext, &outlen, plaintext, size); - EVP_EncryptFinal_ex(ctx, ciphertext + outlen, &tmplen); - } - - /* 正式测试 */ - iterations = 0; - start = get_time(); - do { - if (g_interrupted) break; - EVP_EncryptInit_ex(ctx, cipher, NULL, key, iv); - EVP_EncryptUpdate(ctx, ciphertext, &outlen, plaintext, size); - EVP_EncryptFinal_ex(ctx, ciphertext + outlen, &tmplen); - iterations++; - elapsed = get_time() - start; - } while (elapsed < TEST_SECONDS && !g_interrupted); - - total_bytes = (double)iterations * size; - printf("%-12d %-10ld %-12s %s\n", - size, iterations, - format_size((long)total_bytes), - format_speed(total_bytes / elapsed)); - - free(plaintext); - free(ciphertext); - } - - EVP_CIPHER_CTX_free(ctx); -} - - - -/* 加载SM引擎 */ -static ENGINE *load_sm_engine(const char *engine_path) -{ - ENGINE *e = NULL; - char error_buf[256]; - - /* 如果提供了引擎路径,尝试动态加载 */ - if (engine_path) { - printf("尝试从路径加载引擎: %s\n", engine_path); - - /* 检查文件是否存在 */ - FILE *fp = fopen(engine_path, "r"); - if (!fp) { - printf(" ✗ 错误: 引擎文件不存在: %s\n", engine_path); - return NULL; - } - fclose(fp); - - ENGINE_load_dynamic(); - e = ENGINE_by_id("dynamic"); - if (e) { - if (!ENGINE_ctrl_cmd_string(e, "SO_PATH", engine_path, 0)) { - ERR_error_string_n(ERR_get_error(), error_buf, sizeof(error_buf)); - printf(" ✗ 错误: 无法设置引擎路径: %s\n", error_buf); - ENGINE_free(e); - e = NULL; - } else if (!ENGINE_ctrl_cmd_string(e, "ID", "sm_ce_engine", 0)) { - ERR_error_string_n(ERR_get_error(), error_buf, sizeof(error_buf)); - printf(" ✗ 错误: 无法设置引擎ID: %s\n", error_buf); - ENGINE_free(e); - e = NULL; - } else if (!ENGINE_ctrl_cmd_string(e, "LOAD", NULL, 0)) { - ERR_error_string_n(ERR_get_error(), error_buf, sizeof(error_buf)); - printf(" ✗ 错误: 无法加载引擎: %s\n", error_buf); - ENGINE_free(e); - e = NULL; - } else { - printf(" ✓ 成功动态加载引擎\n"); - } - } else { - printf(" ✗ 错误: 无法获取动态引擎\n"); - } - } - - /* 如果动态加载失败,尝试使用配置文件中的引擎 */ - if (!e) { - printf("尝试通过配置文件加载引擎...\n"); - - /* 先尝试使用环境变量设置配置文件 */ - const char *config_file = getenv("OPENSSL_CONF"); - if (config_file) { - printf(" 使用配置文件: %s\n", config_file); - } else { - /* 如果没有设置环境变量,尝试设置本地配置文件 */ - setenv("OPENSSL_CONF", "test/openssl.cnf", 1); - printf(" 设置配置文件: test/openssl.cnf\n"); - - /* 重新初始化OpenSSL以加载新配置 */ - CONF_modules_unload(1); - OPENSSL_init_crypto(OPENSSL_INIT_LOAD_CONFIG, NULL); - } - - /* 通过配置文件加载引擎 */ - e = ENGINE_by_id("sm_ce_engine"); - if (!e) { - printf(" ✗ SM引擎未找到(使用OpenSSL内置)\n"); - return NULL; - } - printf(" ✓ 成功通过配置文件获取引擎\n"); - } - - /* 初始化引擎 */ - if (!ENGINE_init(e)) { - ERR_error_string_n(ERR_get_error(), error_buf, sizeof(error_buf)); - printf(" ✗ 错误: 引擎初始化失败: %s\n", error_buf); - ENGINE_free(e); - return NULL; - } - printf(" ✓ 引擎初始化成功\n"); - - /* 设置为默认引擎 */ - if (!ENGINE_set_default_digests(e)) { - printf(" ⚠ 警告: 无法设置为默认摘要引擎\n"); - } else { - printf(" ✓ 已设置为默认摘要引擎\n"); - } - - if (!ENGINE_set_default_ciphers(e)) { - printf(" ⚠ 警告: 无法设置为默认加密引擎\n"); - } else { - printf(" ✓ 已设置为默认加密引擎\n"); - } - - /* 列出引擎支持的算法 */ - printf("\n引擎信息:\n"); - const char *engine_name = ENGINE_get_name(e); - const char *engine_id = ENGINE_get_id(e); - printf(" • 名称: %s\n", engine_name ? engine_name : "未知"); - printf(" • ID: %s\n", engine_id ? engine_id : "未知"); - - return e; -} - -/* 打印使用说明 */ -static void print_usage(const char *program) -{ - printf("用法: %s [选项]\n", program); - printf("选项:\n"); - printf(" -h, --help 显示帮助信息\n"); - printf(" -e, --engine PATH 指定引擎路径\n"); - printf(" -t <秒> 设置每项测试时长(默认: %d秒)\n", TEST_SECONDS); - printf("\n"); - printf("示例:\n"); - printf(" %s # 使用配置文件中的引擎\n", program); - printf(" %s -e build/lib/libsm_engine.dylib # 指定引擎路径\n", program); - printf("\n"); - printf("提示: 按 Ctrl+C 可以随时中断测试\n"); -} - -int main(int argc, char *argv[]) -{ - const char *engine_path = NULL; - ENGINE *engine = NULL; - int i; - - /* 设置信号处理 */ - signal(SIGINT, signal_handler); - - /* 解析参数 */ - for (i = 1; i < argc; i++) { - if (strcmp(argv[i], "-h") == 0 || strcmp(argv[i], "--help") == 0) { - print_usage(argv[0]); - return 0; - } else if ((strcmp(argv[i], "-e") == 0 || strcmp(argv[i], "--engine") == 0) && i + 1 < argc) { - engine_path = argv[++i]; - } - } - - printf("╔════════════════════════════════════════════════════╗\n"); - printf("║ SM Engine 性能测试程序 v1.0 ║\n"); - printf("╚════════════════════════════════════════════════════╝\n"); - printf("\n"); - printf("测试配置:\n"); - printf(" • OpenSSL版本: %s\n", SSLeay_version(SSLEAY_VERSION)); - printf(" • 测试时长: %d秒/项\n", TEST_SECONDS); - printf(" • 预热次数: %d次\n", WARMUP_ITERATIONS); - printf(" • 测试块大小: "); - for (i = 0; i < num_sizes; i++) { - printf("%d ", block_sizes[i]); - } - printf("bytes\n"); - - /* 设置环境变量以使用本地配置文件 */ - if (!getenv("OPENSSL_CONF")) { - setenv("OPENSSL_CONF", "test/openssl.cnf", 1); - printf(" • 配置文件: test/openssl.cnf (自动设置)\n"); - } else { - printf(" • 配置文件: %s\n", getenv("OPENSSL_CONF")); - } - - /* 初始化OpenSSL */ - OPENSSL_init_crypto(OPENSSL_INIT_LOAD_CONFIG, NULL); - - /* 加载所有算法 */ - OpenSSL_add_all_algorithms(); - - /* 加载引擎 */ - ENGINE_load_builtin_engines(); - ENGINE_register_all_complete(); - - /* 尝试加载SM引擎 */ - printf("\n正在加载SM引擎...\n"); - engine = load_sm_engine(engine_path); - if (engine) { - printf(" • 引擎状态: 已加载\n"); - } else { - printf(" • 引擎状态: 未加载(使用OpenSSL内置实现)\n"); - } - printf("\n"); - - /* 检查算法可用性 */ - const EVP_MD *sm3_md = EVP_get_digestbyname("sm3"); - const EVP_CIPHER *sm4_ecb = EVP_get_cipherbyname("sm4-ecb"); - const EVP_CIPHER *sm4_cbc = EVP_get_cipherbyname("sm4-cbc"); - - printf("算法支持状态:\n"); - printf(" • SM3: %s", sm3_md ? "可用" : "不可用"); - if (sm3_md && engine) { - /* 检查算法提供者 */ - int from_engine = 0; - ENGINE_DIGESTS_PTR fn = ENGINE_get_digests(engine); - if (fn) { - const int *nids; - int n = fn(engine, NULL, &nids, 0); - for (int j = 0; j < n; j++) { - if (nids[j] == EVP_MD_type(sm3_md)) { - from_engine = 1; - break; - } - } - } - printf(" [来源: %s]", from_engine ? "SM引擎" : "OpenSSL内置"); - } - printf("\n"); - - printf(" • SM4-ECB: %s", sm4_ecb ? "可用" : "不可用"); - if (sm4_ecb && engine) { - int from_engine = 0; - ENGINE_CIPHERS_PTR fn = ENGINE_get_ciphers(engine); - if (fn) { - const int *nids; - int n = fn(engine, NULL, &nids, 0); - for (int j = 0; j < n; j++) { - if (nids[j] == EVP_CIPHER_nid(sm4_ecb)) { - from_engine = 1; - break; - } - } - } - printf(" [来源: %s]", from_engine ? "SM引擎" : "OpenSSL内置"); - } - printf("\n"); - - printf(" • SM4-CBC: %s", sm4_cbc ? "可用" : "不可用"); - if (sm4_cbc && engine) { - int from_engine = 0; - ENGINE_CIPHERS_PTR fn = ENGINE_get_ciphers(engine); - if (fn) { - const int *nids; - int n = fn(engine, NULL, &nids, 0); - for (int j = 0; j < n; j++) { - if (nids[j] == EVP_CIPHER_nid(sm4_cbc)) { - from_engine = 1; - break; - } - } - } - printf(" [来源: %s]", from_engine ? "SM引擎" : "OpenSSL内置"); - } - printf("\n\n"); - - /* 运行性能测试 */ - if (sm3_md) { - benchmark_sm3(); - } else { - printf("跳过 SM3 测试(算法不可用)\n"); - } - - if (sm4_ecb) { - benchmark_sm4("sm4-ecb", "SM4-ECB"); - } else { - printf("跳过 SM4-ECB 测试(算法不可用)\n"); - } - - if (sm4_cbc) { - benchmark_sm4("sm4-cbc", "SM4-CBC"); - } else { - printf("跳过 SM4-CBC 测试(算法不可用)\n"); - } - - /* 检查是否被中断 */ - if (g_interrupted) { - printf("\n\n>>> 测试被用户中断\n"); - } - - printf("\n╔════════════════════════════════════════════════════╗\n"); - printf("║ 测试完成 ║\n"); - printf("╚════════════════════════════════════════════════════╝\n"); - - /* 清理引擎 */ - if (engine) { - ENGINE_finish(engine); - ENGINE_free(engine); - } - - /* 清理 */ - EVP_cleanup(); - ENGINE_cleanup(); - - return 0; -} \ No newline at end of file diff --git a/test/quick_test.c b/test/quick_test.c index 4946a1f20e9d86ae70fd338058b2ebacde07c4b4..17b2b87eedd704028e8eb098d8195ab3cb57c96a 100644 --- a/test/quick_test.c +++ b/test/quick_test.c @@ -112,9 +112,11 @@ static void test_sm4(const char *cipher_name) unsigned char ciphertext[TEST_SIZE + 32]; unsigned char decrypted[TEST_SIZE + 32]; int outlen, tmplen; - double start, elapsed; int i; + /* Move timing variables to avoid stack corruption */ + static double start_time, elapsed_time; + printf("\n%s 测试:\n", cipher_name); printf("----------\n"); @@ -158,13 +160,15 @@ static void test_sm4(const char *cipher_name) } /* 性能测试 */ - start = get_time(); + int actual_iterations = TEST_ITERATIONS; + start_time = get_time(); for (i = 0; i < TEST_ITERATIONS && !g_interrupted; i++) { + int out_len, tmp_len; /* Use fresh variables for each iteration */ EVP_EncryptInit_ex(ctx, cipher, NULL, key, iv); - EVP_EncryptUpdate(ctx, ciphertext, &outlen, plaintext, sizeof(plaintext)); - EVP_EncryptFinal_ex(ctx, ciphertext + outlen, &tmplen); + EVP_EncryptUpdate(ctx, ciphertext, &out_len, plaintext, sizeof(plaintext)); + EVP_EncryptFinal_ex(ctx, ciphertext + out_len, &tmp_len); } - elapsed = get_time() - start; + elapsed_time = get_time() - start_time; if (g_interrupted) { printf(" 测试被中断\n"); @@ -172,8 +176,28 @@ static void test_sm4(const char *cipher_name) return; } - printf(" 性能: %d 次/秒 (1KB数据)\n", (int)(TEST_ITERATIONS / elapsed)); - printf(" 速度: %.2f MB/s\n", (TEST_ITERATIONS * TEST_SIZE / elapsed) / (1024.0 * 1024.0)); + /* Handle very fast operations - if elapsed < 1ms, run more iterations */ + if (elapsed_time < 0.001 && !g_interrupted) { + actual_iterations = TEST_ITERATIONS * 100; /* 1 million iterations */ + start_time = get_time(); + for (i = 0; i < actual_iterations && !g_interrupted; i++) { + int out_len, tmp_len; /* Use fresh variables for each iteration */ + EVP_EncryptInit_ex(ctx, cipher, NULL, key, iv); + EVP_EncryptUpdate(ctx, ciphertext, &out_len, plaintext, sizeof(plaintext)); + EVP_EncryptFinal_ex(ctx, ciphertext + out_len, &tmp_len); + } + elapsed_time = get_time() - start_time; + } + + if (elapsed_time > 0.0) { + double ops_per_sec = actual_iterations / elapsed_time; + double mb_per_sec = (actual_iterations * TEST_SIZE / elapsed_time) / (1024.0 * 1024.0); + printf(" 性能: %.0f 次/秒 (1KB数据)\n", ops_per_sec); + printf(" 速度: %.2f MB/s\n", mb_per_sec); + } else { + printf(" 性能: 无法测量 (操作过快)\n"); + printf(" 速度: 无法测量 MB/s\n"); + } EVP_CIPHER_CTX_free(ctx); } diff --git a/test/run_asan.sh b/test/run_asan.sh deleted file mode 100755 index 0718672ef3dda571a1d566f50a3c4d6002c39132..0000000000000000000000000000000000000000 --- a/test/run_asan.sh +++ /dev/null @@ -1,239 +0,0 @@ -#!/bin/bash - -# Run AddressSanitizer tests for SM Engine -# This script compiles and runs tests with ASAN enabled - -set -e - -# Colors for output -RED='\033[0;31m' -GREEN='\033[0;32m' -YELLOW='\033[1;33m' -NC='\033[0m' # No Color - -echo -e "${GREEN}SM Engine AddressSanitizer Test Runner${NC}" -echo "========================================" -echo "" - -# Check if we're in the right directory -if [ ! -f "src/sm_engine.c" ]; then - echo -e "${RED}Error: Must run from sm-engine root directory${NC}" - exit 1 -fi - -# Parse command line arguments -OPENSSL_INCLUDE="" -OPENSSL_LIB="" -DEBUG=0 -VERBOSE=0 - -while [[ $# -gt 0 ]]; do - case $1 in - -oi|--openssl-include) - OPENSSL_INCLUDE="$2" - shift 2 - ;; - -ol|--openssl-lib) - OPENSSL_LIB="$2" - shift 2 - ;; - -d|--debug) - DEBUG=1 - shift - ;; - -v|--verbose) - VERBOSE=1 - shift - ;; - -h|--help) - echo "Usage: $0 [options]" - echo "Options:" - echo " -oi, --openssl-include DIR OpenSSL include directory" - echo " -ol, --openssl-lib PATH OpenSSL library path (libcrypto.a)" - echo " -d, --debug Enable debug output" - echo " -v, --verbose Enable verbose ASAN output" - echo " -h, --help Show this help message" - exit 0 - ;; - *) - echo -e "${RED}Unknown option: $1${NC}" - exit 1 - ;; - esac -done - -# Set default paths if not provided -if [ -z "$OPENSSL_INCLUDE" ]; then - if [ -d "3rd/openssl/include" ]; then - OPENSSL_INCLUDE="3rd/openssl/include" - else - OPENSSL_INCLUDE="/usr/local/include" - fi -fi - -if [ -z "$OPENSSL_LIB" ]; then - if [ -f "3rd/openssl/libcrypto.a" ]; then - OPENSSL_LIB="3rd/openssl/libcrypto.a" - else - OPENSSL_LIB="-lcrypto" - fi -fi - -echo "Configuration:" -echo " OpenSSL Include: $OPENSSL_INCLUDE" -echo " OpenSSL Library: $OPENSSL_LIB" -echo "" - -# Determine platform -PLATFORM=$(uname -s) -echo "Platform: $PLATFORM" -echo "" - -# Check for compiler with ASAN support -CC=${CC:-gcc} -if ! command -v $CC &> /dev/null; then - CC=clang -fi - -if ! command -v $CC &> /dev/null; then - echo -e "${RED}Error: No suitable compiler found (tried gcc and clang)${NC}" - exit 1 -fi - -echo "Compiler: $CC" - -# Check if compiler supports ASAN -echo -n "Checking ASAN support... " -if echo "int main(){return 0;}" | $CC -fsanitize=address -x c - -o /dev/null 2>/dev/null; then - echo -e "${GREEN}OK${NC}" -else - echo -e "${RED}FAILED${NC}" - echo -e "${RED}Error: Compiler does not support AddressSanitizer${NC}" - echo "Try installing clang or a newer version of gcc" - exit 1 -fi -echo "" - -# Build the engine with ASAN if not already built -ENGINE_LIB="build/libsm_engine.so" -if [ ! -f "$ENGINE_LIB" ]; then - echo -e "${YELLOW}Engine not found, building with ASAN...${NC}" - - # Create build directory - mkdir -p build - - # Compile flags for ASAN - CFLAGS="-fPIC -Wall -Wextra -g -O0 -fsanitize=address -fno-omit-frame-pointer" - if [ $DEBUG -eq 1 ]; then - CFLAGS="$CFLAGS -DSM_ENGINE_DEBUG" - fi - - # Platform-specific linking - if [ "$PLATFORM" = "Darwin" ]; then - LDFLAGS="-dynamiclib -Wl,-exported_symbols_list,exported.symbols" - ENGINE_EXT="dylib" - else - LDFLAGS="-shared -Wl,--version-script=sm_engine.syms" - ENGINE_EXT="so" - fi - - LDFLAGS="$LDFLAGS -fsanitize=address" - - # Build command - BUILD_CMD="$CC $CFLAGS -I$OPENSSL_INCLUDE \ - src/sm_engine.c src/sm3.c src/sm4.c \ - -o build/libsm_engine.$ENGINE_EXT \ - $LDFLAGS $OPENSSL_LIB -ldl" - - echo "Build command:" - echo "$BUILD_CMD" - echo "" - - if $BUILD_CMD; then - echo -e "${GREEN}Engine built successfully with ASAN${NC}" - else - echo -e "${RED}Failed to build engine${NC}" - exit 1 - fi - - ENGINE_LIB="build/libsm_engine.$ENGINE_EXT" -else - echo -e "${GREEN}Using existing engine: $ENGINE_LIB${NC}" -fi -echo "" - -# Compile the ASAN test program -echo "Building ASAN test program..." -TEST_CFLAGS="-g -O0 -fsanitize=address -fno-omit-frame-pointer" -if [ $DEBUG -eq 1 ]; then - TEST_CFLAGS="$TEST_CFLAGS -DDEBUG" -fi - -TEST_BUILD_CMD="$CC $TEST_CFLAGS -I$OPENSSL_INCLUDE \ - test/test_asan.c \ - -o build/test_asan \ - -fsanitize=address $OPENSSL_LIB -ldl" - -echo "Test build command:" -echo "$TEST_BUILD_CMD" -echo "" - -if $TEST_BUILD_CMD; then - echo -e "${GREEN}Test program built successfully${NC}" -else - echo -e "${RED}Failed to build test program${NC}" - exit 1 -fi -echo "" - -# Set up environment for running tests -export OPENSSL_ENGINES=$(pwd)/build -export ASAN_OPTIONS="detect_leaks=1:check_initialization_order=1:strict_string_checks=1:print_stats=1" - -if [ $VERBOSE -eq 1 ]; then - export ASAN_OPTIONS="$ASAN_OPTIONS:verbosity=1" -fi - -# Additional ASAN options for better debugging -export ASAN_SYMBOLIZER_PATH=$(which llvm-symbolizer 2>/dev/null || which addr2line 2>/dev/null) - -echo "Environment:" -echo " OPENSSL_ENGINES=$OPENSSL_ENGINES" -echo " ASAN_OPTIONS=$ASAN_OPTIONS" -if [ -n "$ASAN_SYMBOLIZER_PATH" ]; then - echo " ASAN_SYMBOLIZER_PATH=$ASAN_SYMBOLIZER_PATH" -fi -echo "" - -# Run the tests -echo -e "${YELLOW}Running ASAN tests...${NC}" -echo "========================================" -echo "" - -if ./build/test_asan; then - EXIT_CODE=$? - echo "" - echo -e "${GREEN}========================================" - echo -e "ASAN tests completed successfully" - echo -e "========================================${NC}" -else - EXIT_CODE=$? - echo "" - echo -e "${RED}========================================" - echo -e "ASAN tests failed with exit code: $EXIT_CODE" - echo -e "========================================${NC}" -fi - -# Check for ASAN output -if [ $EXIT_CODE -ne 0 ]; then - echo "" - echo -e "${YELLOW}Note: Check above for AddressSanitizer reports${NC}" - echo "Common issues detected by ASAN:" - echo " - Heap buffer overflow" - echo " - Stack buffer overflow" - echo " - Use after free" - echo " - Memory leaks" - echo " - Double free" -fi - -exit $EXIT_CODE \ No newline at end of file diff --git a/test/run_valgrind.sh b/test/run_valgrind.sh deleted file mode 100755 index 5d625efef3b82b7e79fc2cc109e00366b3e9fcfa..0000000000000000000000000000000000000000 --- a/test/run_valgrind.sh +++ /dev/null @@ -1,220 +0,0 @@ -#!/bin/bash - -# Run Valgrind memory checks for SM Engine -# This script runs the test program under Valgrind to detect memory issues - -set -e - -# Colors for output -RED='\033[0;31m' -GREEN='\033[0;32m' -YELLOW='\033[1;33m' -NC='\033[0m' # No Color - -echo -e "${GREEN}SM Engine Valgrind Memory Check${NC}" -echo "================================" -echo "" - -# Check if we're in the right directory -if [ ! -f "src/sm_engine.c" ]; then - echo -e "${RED}Error: Must run from sm-engine root directory${NC}" - exit 1 -fi - -# Check if Valgrind is installed -if ! command -v valgrind &> /dev/null; then - echo -e "${RED}Error: Valgrind is not installed${NC}" - echo "Install with:" - echo " Ubuntu/Debian: sudo apt-get install valgrind" - echo " RHEL/CentOS: sudo yum install valgrind" - echo " macOS: brew install valgrind (Note: may not work on Apple Silicon)" - exit 1 -fi - -echo "Valgrind version:" -valgrind --version -echo "" - -# Parse command line arguments -OPENSSL_INCLUDE="" -OPENSSL_LIB="" -TEST_PROGRAM="example" -FULL_CHECK=0 -SUPPRESSIONS="" - -while [[ $# -gt 0 ]]; do - case $1 in - -oi|--openssl-include) - OPENSSL_INCLUDE="$2" - shift 2 - ;; - -ol|--openssl-lib) - OPENSSL_LIB="$2" - shift 2 - ;; - -t|--test) - TEST_PROGRAM="$2" - shift 2 - ;; - -f|--full) - FULL_CHECK=1 - shift - ;; - -s|--suppressions) - SUPPRESSIONS="$2" - shift 2 - ;; - -h|--help) - echo "Usage: $0 [options]" - echo "Options:" - echo " -oi, --openssl-include DIR OpenSSL include directory" - echo " -ol, --openssl-lib PATH OpenSSL library path" - echo " -t, --test PROGRAM Test program to run (default: example)" - echo " -f, --full Run full leak check (slower)" - echo " -s, --suppressions FILE Valgrind suppressions file" - echo " -h, --help Show this help message" - exit 0 - ;; - *) - echo -e "${RED}Unknown option: $1${NC}" - exit 1 - ;; - esac -done - -# Set default paths if not provided -if [ -z "$OPENSSL_INCLUDE" ]; then - if [ -d "3rd/openssl/include" ]; then - OPENSSL_INCLUDE="3rd/openssl/include" - else - OPENSSL_INCLUDE="/usr/local/include" - fi -fi - -if [ -z "$OPENSSL_LIB" ]; then - if [ -f "3rd/openssl/libcrypto.a" ]; then - OPENSSL_LIB="3rd/openssl/libcrypto.a" - else - OPENSSL_LIB="-lcrypto" - fi -fi - -echo "Configuration:" -echo " OpenSSL Include: $OPENSSL_INCLUDE" -echo " OpenSSL Library: $OPENSSL_LIB" -echo " Test Program: $TEST_PROGRAM" -echo "" - -# Determine platform -PLATFORM=$(uname -s) - -# Build the engine without ASAN (Valgrind and ASAN don't mix well) -if [ ! -f "build/libsm_engine.so" ] && [ ! -f "build/libsm_engine.dylib" ]; then - echo -e "${YELLOW}Building engine for Valgrind testing...${NC}" - ./build.sh build \ - -oi "$OPENSSL_INCLUDE" \ - -ol "$OPENSSL_LIB" \ - -ai "$OPENSSL_INCLUDE" \ - -al "$OPENSSL_LIB" \ - -d # Debug build for better Valgrind output -fi - -# Build test program if needed -TEST_BINARY="build/$TEST_PROGRAM" -if [ ! -f "$TEST_BINARY" ]; then - if [ "$TEST_PROGRAM" = "example" ] && [ -f "test/example.c" ]; then - echo -e "${YELLOW}Building example program...${NC}" - ./build.sh test - elif [ "$TEST_PROGRAM" = "test_asan" ] && [ -f "test/test_asan.c" ]; then - echo -e "${YELLOW}Building test_asan program (without ASAN for Valgrind)...${NC}" - gcc -g -O0 -I"$OPENSSL_INCLUDE" \ - test/test_asan.c \ - -o build/test_asan \ - $OPENSSL_LIB -ldl - else - echo -e "${RED}Error: Test program '$TEST_BINARY' not found${NC}" - exit 1 - fi -fi - -# Set up environment -export OPENSSL_ENGINES=$(pwd)/build - -# Prepare Valgrind options -VALGRIND_OPTS="--leak-check=full" -VALGRIND_OPTS="$VALGRIND_OPTS --show-leak-kinds=all" -VALGRIND_OPTS="$VALGRIND_OPTS --track-origins=yes" -VALGRIND_OPTS="$VALGRIND_OPTS --verbose" -VALGRIND_OPTS="$VALGRIND_OPTS --log-file=valgrind.log" - -if [ $FULL_CHECK -eq 1 ]; then - VALGRIND_OPTS="$VALGRIND_OPTS --leak-check=full" - VALGRIND_OPTS="$VALGRIND_OPTS --show-reachable=yes" - VALGRIND_OPTS="$VALGRIND_OPTS --track-fds=yes" -fi - -if [ -n "$SUPPRESSIONS" ] && [ -f "$SUPPRESSIONS" ]; then - VALGRIND_OPTS="$VALGRIND_OPTS --suppressions=$SUPPRESSIONS" -fi - -echo "Valgrind options:" -echo " $VALGRIND_OPTS" -echo "" - -# Run Valgrind -echo -e "${YELLOW}Running Valgrind memory check...${NC}" -echo "================================" -echo "" - -valgrind $VALGRIND_OPTS "$TEST_BINARY" - -EXIT_CODE=$? - -# Analyze the results -echo "" -echo -e "${YELLOW}Analyzing Valgrind results...${NC}" -echo "================================" - -if [ -f "valgrind.log" ]; then - # Check for definitely lost memory - DEFINITELY_LOST=$(grep "definitely lost:" valgrind.log | tail -1 | awk '{print $4}') - INDIRECTLY_LOST=$(grep "indirectly lost:" valgrind.log | tail -1 | awk '{print $4}') - POSSIBLY_LOST=$(grep "possibly lost:" valgrind.log | tail -1 | awk '{print $4}') - REACHABLE=$(grep "still reachable:" valgrind.log | tail -1 | awk '{print $4}') - - echo "Memory leak summary:" - echo " Definitely lost: ${DEFINITELY_LOST:-0} bytes" - echo " Indirectly lost: ${INDIRECTLY_LOST:-0} bytes" - echo " Possibly lost: ${POSSIBLY_LOST:-0} bytes" - echo " Still reachable: ${REACHABLE:-0} bytes" - echo "" - - # Check for errors - ERROR_COUNT=$(grep "ERROR SUMMARY:" valgrind.log | tail -1 | awk '{print $4}') - echo "Error count: ${ERROR_COUNT:-0}" - echo "" - - # Display any error details - if [ "${ERROR_COUNT:-0}" -gt 0 ]; then - echo -e "${RED}Errors detected! Check valgrind.log for details${NC}" - echo "" - echo "First few errors:" - grep -A 5 "Invalid" valgrind.log | head -20 || true - else - echo -e "${GREEN}No errors detected${NC}" - fi - - # Check for leaks - if [ "${DEFINITELY_LOST:-0}" = "0" ] && [ "${INDIRECTLY_LOST:-0}" = "0" ]; then - echo -e "${GREEN}No definite memory leaks detected${NC}" - else - echo -e "${RED}Memory leaks detected! Check valgrind.log for details${NC}" - fi - - echo "" - echo "Full log saved to: valgrind.log" -else - echo -e "${RED}Valgrind log file not found${NC}" -fi - -exit $EXIT_CODE \ No newline at end of file diff --git a/test_engine.sh b/test_engine.sh index 84a1aee4cc03c2fd0d0de4e57983aefbb0547171..e71fa8ad137a87f4aa7d405e512aa90e4ac5d766 100755 --- a/test_engine.sh +++ b/test_engine.sh @@ -1,22 +1,55 @@ #!/bin/bash +# Test script for SM Engine with automatic path configuration -echo "=========================================" -echo " SM引擎测试脚本" -echo "=========================================" -echo "" +# Detect OS and set library extension +if [[ "$OSTYPE" == "darwin"* ]]; then + LIB_EXT="dylib" +else + LIB_EXT="so" +fi -cd "$(dirname "$0")/build" +# Check if we're in build directory or source directory +if [ -f "./lib/libsm_engine.$LIB_EXT" ]; then + # We're in build directory + ENGINE_PATH="$(pwd)/lib/libsm_engine.$LIB_EXT" +elif [ -f "./build/lib/libsm_engine.$LIB_EXT" ]; then + # We're in source directory + ENGINE_PATH="$(pwd)/build/lib/libsm_engine.$LIB_EXT" +else + echo "Error: Cannot find libsm_engine.$LIB_EXT" + echo "Please run from build directory or source root" + exit 1 +fi -echo "1. 功能测试(使用配置文件)" -echo "-----------------------------------------" -OPENSSL_CONF=../test/openssl.cnf timeout 5 ./bin/example || echo "功能测试完成或超时" -echo "" +# Set up OpenSSL config for engine loading +if [ -f "./build/lib/libsm_engine.$LIB_EXT" ]; then + # We're in source directory - set up config in build directory + mkdir -p build/openssl-install/ssl + + # Copy platform-specific config + if [[ "$OSTYPE" == "darwin"* ]]; then + cp test/openssl_macos.cnf build/openssl-install/ssl/openssl.cnf + else + cp test/openssl_linux.cnf build/openssl-install/ssl/openssl.cnf + fi + + # Update config with absolute path + sed -i.bak "s|dynamic_path = ./lib/libsm_engine.$LIB_EXT|dynamic_path = $ENGINE_PATH|" build/openssl-install/ssl/openssl.cnf + rm -f build/openssl-install/ssl/openssl.cnf.bak + + echo "✅ Engine config updated: build/openssl-install/ssl/openssl.cnf" +fi -echo "2. 快速性能测试" -echo "-----------------------------------------" -OPENSSL_CONF=../test/openssl.cnf timeout 5 ./bin/quick_test || echo "快速测试完成或超时" +echo "Using engine: $ENGINE_PATH" echo "" -echo "=========================================" -echo " 测试完成" -echo "=========================================" \ No newline at end of file +# Find and run test binary +if [ -f "./bin/quick_test" ]; then + ./bin/quick_test +elif [ -f "./build/bin/quick_test" ]; then + ./build/bin/quick_test +else + echo "Error: Cannot find quick_test binary" + echo "Please build the project first: mkdir build && cd build && cmake .. && make" + exit 1 +fi