diff --git a/.gitignore b/.gitignore index 23628bf..f6f976d 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ build/ .cache/ cmake-build-* +.vscode/ diff --git a/CMakeLists.txt b/CMakeLists.txt index 97af605..d368322 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -2,19 +2,26 @@ cmake_minimum_required(VERSION 3.14) project(kgg-dec VERSION 0.6.0 LANGUAGES CXX) -option(USE_WIN_SQLITE3 "Use Windows SQLite3 (MSVC Only)" ${MSVC}) -option(USE_WIN_CRYPTO "Use Windows Crypto API" ${WIN32}) -option(USE_SYSTEM_SQLITE3 "Use system SQLite3 (if not using WinSQLite3)" ON) +option(USE_SYSTEM_SQLITE3 "Use system SQLite3 (if not using WinSQLite3 and available)" ON) +option(USE_OPENSSL "Use OpenSSL API (if not using WinCrypto API and available)" ON) +if(WIN32) + option(USE_WIN_SQLITE3 "Use Windows SQLite3 (MSVC Only)" ${MSVC}) + option(USE_WIN_CRYPTO "Use Windows Crypto API" ${WIN32}) +else() + set(USE_WIN_SQLITE3 OFF) + set(USE_WIN_CRYPTO OFF) +endif() + +# Setup CryptoAPI +if (NOT USE_WIN_CRYPTO AND USE_OPENSSL) + find_package(OpenSSL REQUIRED) +endif() + +include(cmake/SetupSQLite3.cmake) add_subdirectory(third-party/aes) add_subdirectory(third-party/md5) -include(cmake/FindWinSQLite3.cmake) -if (NOT WinSQLite3_Found AND NOT USE_WIN_SQLITE3) - message("including sqlite3 to the build") - add_subdirectory(third-party/sqlite3) -endif () - set(CMAKE_CXX_STANDARD 20) set(CMAKE_CXX_STANDARD_REQUIRED ON) @@ -40,6 +47,8 @@ target_include_directories(kgg-dec target_link_libraries(kgg-dec PRIVATE libaes libmd5) if (USE_WIN_CRYPTO) target_compile_definitions(kgg-dec PRIVATE USE_WIN_CRYPTO=1) +elseif(USE_OPENSSL) + target_compile_definitions(kgg-dec PRIVATE USE_OPENSSL=1) endif () # Win32 specific diff --git a/cmake/FindWinSQLite3.cmake b/cmake/SetupSQLite3.cmake similarity index 79% rename from cmake/FindWinSQLite3.cmake rename to cmake/SetupSQLite3.cmake index 9ee2d9e..a38dec6 100644 --- a/cmake/FindWinSQLite3.cmake +++ b/cmake/SetupSQLite3.cmake @@ -13,9 +13,12 @@ if (MSVC AND USE_WIN_SQLITE3) endif () endif () -if (NOT WinSQLite3_Found AND USE_SYSTEM_SQLITE3) - find_package(SQLite3) - if (SQLite3_FOUND) +if (NOT WinSQLite3_Found) + if (USE_SYSTEM_SQLITE3) message("Using existing SQLite3.") + find_package(SQLite3 REQUIRED) + else() + message("including sqlite3 to the build") + add_subdirectory(third-party/sqlite3) endif() endif() diff --git a/third-party/aes/CMakeLists.txt b/third-party/aes/CMakeLists.txt index f619c2f..8b32cfc 100644 --- a/third-party/aes/CMakeLists.txt +++ b/third-party/aes/CMakeLists.txt @@ -7,10 +7,16 @@ set(CMAKE_CXX_STANDARD_REQUIRED ON) set(SOURCES) if (USE_WIN_CRYPTO) + message("Using Windows Crypto API for AES-CBC-128") list(APPEND SOURCES aes_win32.cpp) +elseif (USE_OPENSSL) + message("Using OpenSSL API for AES-CBC-128") + find_package(OpenSSL REQUIRED) + list(APPEND SOURCES aes_openssl.cpp) else () # Tiny AES in C (https://github.com/kokke/tiny-AES-c/) # is licensed under the Unlicense license. + message("Using included AES-CBC-128 implementation") list(APPEND SOURCES aes.cpp) endif () @@ -23,4 +29,7 @@ target_include_directories(libaes if (USE_WIN_CRYPTO) target_link_libraries(libaes PRIVATE bcrypt) target_compile_definitions(libaes PRIVATE USE_WIN_CRYPTO=1) +elseif (USE_OPENSSL) + target_link_libraries(libaes PRIVATE OpenSSL::Crypto) + target_compile_definitions(libaes PRIVATE USE_OPENSSL=1) endif () diff --git a/third-party/aes/aes.h b/third-party/aes/aes.h index 4649012..9abce7c 100644 --- a/third-party/aes/aes.h +++ b/third-party/aes/aes.h @@ -7,6 +7,8 @@ #include #include +#elif USE_OPENSSL +#include #endif namespace AES { @@ -20,6 +22,8 @@ struct AES_ctx { BCRYPT_ALG_HANDLE hAlg; BCRYPT_KEY_HANDLE hKey; uint8_t iv[0x10]; +#elif USE_OPENSSL + EVP_CIPHER_CTX* cipher_ctx; #else uint8_t RoundKey[kKeyExpansionSize]; uint8_t Iv[16]; @@ -35,7 +39,7 @@ bool AES_init_ctx_iv(AES_ctx* ctx, const uint8_t* key, const uint8_t* iv); size_t AES_CBC_encrypt_buffer(AES_ctx* ctx, uint8_t* buf, size_t length); size_t AES_CBC_decrypt_buffer(AES_ctx* ctx, uint8_t* buf, size_t length); -#if USE_WIN_CRYPTO +#if USE_WIN_CRYPTO || USE_OPENSSL bool AES_cleanup(AES_ctx* ctx); #else inline bool AES_cleanup(AES_ctx* ctx) { diff --git a/third-party/aes/aes_openssl.cpp b/third-party/aes/aes_openssl.cpp new file mode 100644 index 0000000..866e3e5 --- /dev/null +++ b/third-party/aes/aes_openssl.cpp @@ -0,0 +1,43 @@ +#include +#include + +#include "aes.h" + +namespace AES { + +bool AES_init_ctx_iv(AES_ctx* ctx, const uint8_t* key, const uint8_t* iv) { + ctx->cipher_ctx = EVP_CIPHER_CTX_new(); + if (!ctx->cipher_ctx) { + return false; + } + + if (EVP_DecryptInit_ex(ctx->cipher_ctx, EVP_aes_128_cbc(), nullptr, key, iv) != 1) { + AES_cleanup(ctx); + return false; + } + + EVP_CIPHER_CTX_set_padding(ctx->cipher_ctx, 0); + return true; +} + +size_t AES_CBC_encrypt_buffer(struct AES_ctx* ctx, uint8_t* buf, size_t length) { + // not implemented + return 0; +} + +size_t AES_CBC_decrypt_buffer(struct AES_ctx* ctx, uint8_t* buf, size_t length) { + auto buf_len = static_cast(length); + EVP_DecryptUpdate(ctx->cipher_ctx, buf, &buf_len, buf, buf_len); + assert(buf_len == length && "AES_CBC_decrypt_buffer: buffer length mismatch"); + return buf_len; +} + +bool AES_cleanup(AES_ctx* ctx) { + if (ctx->cipher_ctx) { + EVP_CIPHER_CTX_free(ctx->cipher_ctx); + ctx->cipher_ctx = nullptr; + } + return true; +} + +} // namespace AES diff --git a/third-party/md5/CMakeLists.txt b/third-party/md5/CMakeLists.txt index e61698d..66966fa 100644 --- a/third-party/md5/CMakeLists.txt +++ b/third-party/md5/CMakeLists.txt @@ -7,10 +7,16 @@ set(CMAKE_CXX_STANDARD_REQUIRED ON) set(SOURCES) if (USE_WIN_CRYPTO) + message("Using Windows Crypto API for MD5") list(APPEND SOURCES md5_win32.cpp) +elseif (USE_OPENSSL) + message("Using OpenSSL API for MD5") + find_package(OpenSSL REQUIRED) + list(APPEND SOURCES md5_openssl.cpp) else () # Derived from the "RSA Data Security, Inc. MD5 Message-Digest Algorithm": # https://github.com/freebsd/freebsd-src/blob/release/14.2.0/sys/kern/md5c.c + message("Using included MD5 implementation") list(APPEND SOURCES md5.cpp) endif () @@ -24,4 +30,7 @@ target_include_directories(libmd5 if (USE_WIN_CRYPTO) target_link_libraries(libmd5 PRIVATE crypt32) target_compile_definitions(libmd5 PRIVATE USE_WIN_CRYPTO=1) +elseif (USE_OPENSSL) + target_link_libraries(libmd5 PRIVATE OpenSSL::Crypto) + target_compile_definitions(libmd5 PRIVATE USE_OPENSSL=1) endif () diff --git a/third-party/md5/md5.h b/third-party/md5/md5.h index 872e6e4..0f091d1 100644 --- a/third-party/md5/md5.h +++ b/third-party/md5/md5.h @@ -1,21 +1,23 @@ #pragma once +#include + #if USE_WIN_CRYPTO #include #include +#elif USE_OPENSSL +#include #endif -#include - -#define MD5_BLOCK_LENGTH 64 #define MD5_DIGEST_LENGTH 16 -#define MD5_DIGEST_STRING_LENGTH (MD5_DIGEST_LENGTH * 2 + 1) struct MD5_CTX { #if USE_WIN_CRYPTO HCRYPTPROV hProv; HCRYPTHASH hHash; +#elif USE_OPENSSL + EVP_MD_CTX* md_ctx; #else uint64_t count; /* number of bits, modulo 2^64 (lsb first) */ uint32_t state[4]; /* state (ABCD) */ @@ -23,8 +25,8 @@ struct MD5_CTX { #endif }; -#if USE_WIN_CRYPTO -bool md5_init(MD5_CTX* context); +#if USE_WIN_CRYPTO || USE_OPENSSL +bool md5_init(MD5_CTX* ctx); bool md5_cleanup(MD5_CTX* ctx); #else /* MD5 initialization. Begins an MD5 operation, writing a new context. */ diff --git a/third-party/md5/md5_openssl.cpp b/third-party/md5/md5_openssl.cpp new file mode 100644 index 0000000..fd0f1e5 --- /dev/null +++ b/third-party/md5/md5_openssl.cpp @@ -0,0 +1,32 @@ +#include +#include +#include "md5.h" + +bool md5_init(MD5_CTX* ctx) { + memset(ctx, 0, sizeof(*ctx)); + + ctx->md_ctx = EVP_MD_CTX_new(); + if (!ctx->md_ctx) { + return false; + } + + return EVP_DigestInit_ex(ctx->md_ctx, EVP_md5(), nullptr) == 1; +} + +bool md5_cleanup(MD5_CTX* ctx) { + if (ctx->md_ctx != nullptr) { + EVP_MD_CTX_free(ctx->md_ctx); + } + memset(ctx, 0xcc, sizeof(*ctx)); + return true; +} + +void md5_update(MD5_CTX* ctx, const uint8_t* in, size_t len) { + EVP_DigestUpdate(ctx->md_ctx, in, len); +} + +void md5_final(MD5_CTX* ctx, uint8_t* digest) { + unsigned int len{MD5_DIGEST_LENGTH}; + EVP_DigestFinal_ex(ctx->md_ctx, digest, &len); + EVP_MD_CTX_reset(ctx->md_ctx); +}