refactor: use winapi for aes/md5 procedure
This commit is contained in:
parent
f458c053c8
commit
d19ed2d57f
@ -3,9 +3,11 @@ cmake_minimum_required(VERSION 3.10)
|
||||
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})
|
||||
|
||||
add_subdirectory(third-party/aes)
|
||||
add_subdirectory(third-party/md5)
|
||||
|
||||
include(cmake/FindWinSQLite3.cmake)
|
||||
if (NOT WinSQLite3_Found)
|
||||
message("including sqlite3 to the build")
|
||||
@ -42,3 +44,7 @@ else ()
|
||||
endif ()
|
||||
target_compile_definitions(kgg-dec PRIVATE NOMINMAX)
|
||||
target_compile_definitions(kgg-dec PRIVATE KGGDEC_PROJECT_VERSION="${PROJECT_VERSION}")
|
||||
|
||||
if (USE_WIN_CRYPTO)
|
||||
target_compile_definitions(kgg-dec PRIVATE USE_WIN_CRYPTO=1)
|
||||
endif ()
|
@ -95,10 +95,12 @@ int load_db(std::vector<uint8_t>& db_data, const std::filesystem::path& db_path)
|
||||
if (std::equal(kSQLiteDatabaseHeader.cbegin(), kSQLiteDatabaseHeader.cend(), p_page)) {
|
||||
ifs_db.read(reinterpret_cast<char*>(p_page + kPageSize),
|
||||
static_cast<std::streamsize>(db_size - kPageSize));
|
||||
AES_cleanup(&ctx_aes);
|
||||
return SQLITE_OK; // no encryption
|
||||
}
|
||||
|
||||
if (!is_valid_page_1_header(p_page)) {
|
||||
AES_cleanup(&ctx_aes);
|
||||
db_data.clear();
|
||||
return SQLITE_CORRUPT; // header validation failed
|
||||
}
|
||||
@ -114,6 +116,7 @@ int load_db(std::vector<uint8_t>& db_data, const std::filesystem::path& db_path)
|
||||
} else {
|
||||
AES_CBC_decrypt_buffer(&ctx_aes, p_page, kPageSize);
|
||||
}
|
||||
AES_cleanup(&ctx_aes);
|
||||
}
|
||||
|
||||
return SQLITE_OK;
|
||||
|
16
third-party/aes/CMakeLists.txt
vendored
16
third-party/aes/CMakeLists.txt
vendored
@ -5,10 +5,22 @@ project(libaes VERSION 0.0.1 LANGUAGES CXX)
|
||||
set(CMAKE_CXX_STANDARD 20)
|
||||
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||
|
||||
# Tiny AES in C (https://github.com/kokke/tiny-AES-c/) is licensed under the Unlicense license.
|
||||
add_library(libaes STATIC aes.cpp)
|
||||
set(SOURCES)
|
||||
if (USE_WIN_CRYPTO)
|
||||
list(APPEND SOURCES aes_win32.cpp)
|
||||
else ()
|
||||
# Tiny AES in C (https://github.com/kokke/tiny-AES-c/)
|
||||
# is licensed under the Unlicense license.
|
||||
list(APPEND SOURCES aes.cpp)
|
||||
endif ()
|
||||
|
||||
add_library(libaes STATIC ${SOURCES})
|
||||
target_include_directories(libaes
|
||||
PUBLIC
|
||||
"$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>"
|
||||
"$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>"
|
||||
)
|
||||
if (USE_WIN_CRYPTO)
|
||||
target_link_libraries(libaes PRIVATE bcrypt)
|
||||
target_compile_definitions(libaes PRIVATE USE_WIN_CRYPTO=1)
|
||||
endif ()
|
||||
|
9
third-party/aes/aes.cpp
vendored
9
third-party/aes/aes.cpp
vendored
@ -129,9 +129,10 @@ void KeyExpansion(uint8_t* RoundKey, const uint8_t* Key) {
|
||||
}
|
||||
}
|
||||
|
||||
void AES_init_ctx_iv(AES_ctx* ctx, const uint8_t* key, const uint8_t* iv) {
|
||||
bool AES_init_ctx_iv(AES_ctx* ctx, const uint8_t* key, const uint8_t* iv) {
|
||||
KeyExpansion(ctx->RoundKey, key);
|
||||
memcpy(ctx->Iv, iv, kBlockLen);
|
||||
return true;
|
||||
}
|
||||
|
||||
// This function adds the round key to state.
|
||||
@ -331,7 +332,7 @@ inline void XorWithIv(uint8_t* buf, const uint8_t* Iv) {
|
||||
}
|
||||
}
|
||||
|
||||
void AES_CBC_encrypt_buffer(struct AES_ctx* ctx, uint8_t* buf, size_t length) {
|
||||
size_t AES_CBC_encrypt_buffer(AES_ctx* ctx, uint8_t* buf, size_t length) {
|
||||
uint8_t* Iv = ctx->Iv;
|
||||
for (size_t i = 0; i < length; i += kBlockLen) {
|
||||
XorWithIv(buf, Iv);
|
||||
@ -341,9 +342,10 @@ void AES_CBC_encrypt_buffer(struct AES_ctx* ctx, uint8_t* buf, size_t length) {
|
||||
}
|
||||
/* store Iv in ctx for next call */
|
||||
memcpy(ctx->Iv, Iv, kBlockLen);
|
||||
return length;
|
||||
}
|
||||
|
||||
void AES_CBC_decrypt_buffer(struct AES_ctx* ctx, uint8_t* buf, size_t length) {
|
||||
size_t AES_CBC_decrypt_buffer(AES_ctx* ctx, uint8_t* buf, size_t length) {
|
||||
for (size_t i = 0; i < length; i += kBlockLen) {
|
||||
uint8_t storeNextIv[kBlockLen];
|
||||
memcpy(storeNextIv, buf, kBlockLen);
|
||||
@ -352,6 +354,7 @@ void AES_CBC_decrypt_buffer(struct AES_ctx* ctx, uint8_t* buf, size_t length) {
|
||||
memcpy(ctx->Iv, storeNextIv, kBlockLen);
|
||||
buf += kBlockLen;
|
||||
}
|
||||
return length;
|
||||
}
|
||||
|
||||
} // namespace AES
|
||||
|
24
third-party/aes/aes.h
vendored
24
third-party/aes/aes.h
vendored
@ -2,6 +2,12 @@
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
#if USE_WIN_CRYPTO
|
||||
#include <windows.h>
|
||||
|
||||
#include <bcrypt.h>
|
||||
#endif
|
||||
|
||||
namespace AES {
|
||||
|
||||
constexpr size_t kKeyLen = 16; // Key length in bytes
|
||||
@ -9,17 +15,29 @@ constexpr size_t kKeyExpansionSize = 176;
|
||||
constexpr size_t kBlockLen = 16; // Block length in bytes - AES is 128b block only
|
||||
|
||||
struct AES_ctx {
|
||||
#if USE_WIN_CRYPTO
|
||||
BCRYPT_ALG_HANDLE hAlg;
|
||||
BCRYPT_KEY_HANDLE hKey;
|
||||
uint8_t iv[0x10];
|
||||
#else
|
||||
uint8_t RoundKey[kKeyExpansionSize];
|
||||
uint8_t Iv[16];
|
||||
#endif
|
||||
};
|
||||
|
||||
void AES_init_ctx_iv(AES_ctx* ctx, const uint8_t* key, const uint8_t* iv);
|
||||
bool AES_init_ctx_iv(AES_ctx* ctx, const uint8_t* key, const uint8_t* iv);
|
||||
|
||||
// buffer size MUST be mutile of AES_BLOCKLEN;
|
||||
// Suggest https://en.wikipedia.org/wiki/Padding_(cryptography)#PKCS7 for padding scheme
|
||||
// NOTES: you need to set IV in ctx via AES_init_ctx_iv() or AES_ctx_set_iv()
|
||||
// no IV should ever be reused with the same key
|
||||
void AES_CBC_encrypt_buffer(struct AES_ctx* ctx, uint8_t* buf, size_t length);
|
||||
void AES_CBC_decrypt_buffer(struct AES_ctx* ctx, uint8_t* buf, size_t length);
|
||||
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
|
||||
bool AES_cleanup(AES_ctx* ctx);
|
||||
#else
|
||||
inline bool AES_cleanup(AES_ctx* ctx) {return true;}
|
||||
#endif
|
||||
|
||||
} // namespace AES
|
||||
|
59
third-party/aes/aes_win32.cpp
vendored
Normal file
59
third-party/aes/aes_win32.cpp
vendored
Normal file
@ -0,0 +1,59 @@
|
||||
#include <algorithm>
|
||||
#include <cassert>
|
||||
#include <cstring>
|
||||
|
||||
#include "aes.h"
|
||||
|
||||
namespace AES {
|
||||
// ReSharper disable CppCStyleCast
|
||||
|
||||
bool AES_init_ctx_iv(AES_ctx* ctx, const uint8_t* key, const uint8_t* iv) {
|
||||
memset(ctx, 0, sizeof(AES_ctx));
|
||||
|
||||
if (BCryptOpenAlgorithmProvider(&ctx->hAlg, BCRYPT_AES_ALGORITHM, nullptr, 0) != 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (BCryptSetProperty(ctx->hAlg, BCRYPT_CHAINING_MODE, (PUCHAR)BCRYPT_CHAIN_MODE_CBC, sizeof(BCRYPT_CHAIN_MODE_CBC),
|
||||
0) != 0) {
|
||||
BCryptCloseAlgorithmProvider(ctx->hAlg, 0);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (BCryptGenerateSymmetricKey(ctx->hAlg, &ctx->hKey, nullptr, 0, (PUCHAR)key, 0x10, 0) != 0) {
|
||||
BCryptCloseAlgorithmProvider(ctx->hAlg, 0);
|
||||
return false;
|
||||
}
|
||||
|
||||
std::copy_n(iv, 0x10, ctx->iv);
|
||||
return true;
|
||||
}
|
||||
|
||||
// buffer size MUST be mutile of AES_BLOCKLEN;
|
||||
// Suggest https://en.wikipedia.org/wiki/Padding_(cryptography)#PKCS7 for padding scheme
|
||||
// NOTES: you need to set IV in ctx via AES_init_ctx_iv() or AES_ctx_set_iv()
|
||||
// no IV should ever be reused with the same key
|
||||
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) {
|
||||
ULONG cbData{0};
|
||||
const auto len = static_cast<ULONG>(length);
|
||||
if (BCryptDecrypt(ctx->hKey, buf, len, nullptr, ctx->iv, sizeof(ctx->iv), buf, len, &cbData, 0) != 0) {
|
||||
assert(false && "BCryptDecrypt failed");
|
||||
return 0;
|
||||
}
|
||||
|
||||
assert(cbData == len && "AES_CBC_decrypt_buffer: cbData != length");
|
||||
return cbData;
|
||||
}
|
||||
|
||||
bool AES_cleanup(AES_ctx* ctx) {
|
||||
BCryptDestroyKey(ctx->hKey);
|
||||
BCryptCloseAlgorithmProvider(ctx->hAlg, 0);
|
||||
memset(ctx, 0, sizeof(AES_ctx));
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace AES
|
14
third-party/md5/CMakeLists.txt
vendored
14
third-party/md5/CMakeLists.txt
vendored
@ -5,11 +5,23 @@ project(md5 VERSION 0.0.1 LANGUAGES CXX)
|
||||
set(CMAKE_CXX_STANDARD 20)
|
||||
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||
|
||||
set(SOURCES)
|
||||
if (USE_WIN_CRYPTO)
|
||||
list(APPEND SOURCES md5_win32.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
|
||||
add_library(libmd5 STATIC md5.cpp)
|
||||
list(APPEND SOURCES md5.cpp)
|
||||
endif ()
|
||||
|
||||
add_library(libmd5 STATIC ${SOURCES})
|
||||
target_include_directories(libmd5
|
||||
PUBLIC
|
||||
"$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>"
|
||||
"$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>"
|
||||
)
|
||||
|
||||
if (USE_WIN_CRYPTO)
|
||||
target_link_libraries(libmd5 PRIVATE crypt32)
|
||||
target_compile_definitions(libmd5 PRIVATE USE_WIN_CRYPTO=1)
|
||||
endif ()
|
||||
|
32
third-party/md5/md5.h
vendored
32
third-party/md5/md5.h
vendored
@ -1,7 +1,10 @@
|
||||
#pragma once
|
||||
|
||||
// Derived from the "RSA Data Security, Inc. MD5 Message-Digest Algorithm":
|
||||
// src: https://github.com/freebsd/freebsd-src/blob/release/14.2.0/sys/kern/md5c.c
|
||||
#if USE_WIN_CRYPTO
|
||||
#include <windows.h>
|
||||
|
||||
#include <wincrypt.h>
|
||||
#endif
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
@ -9,15 +12,23 @@
|
||||
#define MD5_DIGEST_LENGTH 16
|
||||
#define MD5_DIGEST_STRING_LENGTH (MD5_DIGEST_LENGTH * 2 + 1)
|
||||
|
||||
/* MD5 context. */
|
||||
struct MD5_CTX {
|
||||
#if USE_WIN_CRYPTO
|
||||
HCRYPTPROV hProv;
|
||||
HCRYPTHASH hHash;
|
||||
#else
|
||||
uint64_t count; /* number of bits, modulo 2^64 (lsb first) */
|
||||
uint32_t state[4]; /* state (ABCD) */
|
||||
unsigned char buffer[64]; /* input buffer */
|
||||
#endif
|
||||
};
|
||||
|
||||
#if USE_WIN_CRYPTO
|
||||
bool md5_init(MD5_CTX* context);
|
||||
bool md5_cleanup(MD5_CTX* ctx);
|
||||
#else
|
||||
/* MD5 initialization. Begins an MD5 operation, writing a new context. */
|
||||
inline void md5_init(MD5_CTX* context) {
|
||||
inline bool md5_init(MD5_CTX* context) {
|
||||
context->count = 0;
|
||||
|
||||
/* Load magic initialization constants. */
|
||||
@ -25,22 +36,31 @@ inline void md5_init(MD5_CTX* context) {
|
||||
context->state[1] = 0xefcdab89;
|
||||
context->state[2] = 0x98badcfe;
|
||||
context->state[3] = 0x10325476;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
inline bool md5_cleanup(MD5_CTX* ctx) {
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
void md5_update(MD5_CTX* ctx, const uint8_t* in, size_t len);
|
||||
void md5_final(MD5_CTX* ctx, uint8_t* digest);
|
||||
|
||||
inline void md5(uint8_t* digest, const uint8_t* in, const size_t len) {
|
||||
MD5_CTX ctx;
|
||||
MD5_CTX ctx{};
|
||||
md5_init(&ctx);
|
||||
md5_update(&ctx, in, len);
|
||||
md5_final(&ctx, digest);
|
||||
md5_cleanup(&ctx);
|
||||
}
|
||||
|
||||
inline void md5(uint8_t* digest, const uint8_t* in, const size_t len, const uint8_t* in2, size_t len2) {
|
||||
MD5_CTX ctx;
|
||||
MD5_CTX ctx{};
|
||||
md5_init(&ctx);
|
||||
md5_update(&ctx, in, len);
|
||||
md5_update(&ctx, in2, len2);
|
||||
md5_final(&ctx, digest);
|
||||
md5_cleanup(&ctx);
|
||||
}
|
||||
|
35
third-party/md5/md5_win32.cpp
vendored
Normal file
35
third-party/md5/md5_win32.cpp
vendored
Normal file
@ -0,0 +1,35 @@
|
||||
#include "md5.h"
|
||||
|
||||
bool md5_init(MD5_CTX* ctx) {
|
||||
if (!CryptAcquireContext(&ctx->hProv, nullptr, nullptr, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Create the hash object
|
||||
if (!CryptCreateHash(ctx->hProv, CALG_MD5, 0, 0, &ctx->hHash)) {
|
||||
CryptReleaseContext(ctx->hProv, 0);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void md5_update(MD5_CTX* ctx, const uint8_t* in, size_t len) {
|
||||
CryptHashData(ctx->hHash, in, static_cast<DWORD>(len), 0);
|
||||
}
|
||||
|
||||
void md5_final(MD5_CTX* ctx, uint8_t* digest) {
|
||||
DWORD dataLen = MD5_DIGEST_LENGTH;
|
||||
CryptGetHashParam(ctx->hHash, HP_HASHVAL, digest, &dataLen, 0);
|
||||
CryptDestroyHash(ctx->hHash);
|
||||
ctx->hHash = 0;
|
||||
}
|
||||
|
||||
bool md5_cleanup(MD5_CTX* ctx) {
|
||||
if (ctx->hHash) {
|
||||
CryptDestroyHash(ctx->hHash);
|
||||
}
|
||||
CryptReleaseContext(ctx->hProv, 0);
|
||||
memset(ctx, 0, sizeof(MD5_CTX));
|
||||
return true;
|
||||
}
|
Loading…
Reference in New Issue
Block a user