mirror of
https://github.com/decompals/wibo.git
synced 2025-10-17 07:35:11 +00:00
Rewrite BCryptGenRandom and add tests
This commit is contained in:
parent
bc33bae659
commit
8cac50e50e
@ -80,6 +80,18 @@ if(BUILD_TESTING)
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/test/test_external_dll.c
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/test/test_assert.h)
|
||||
|
||||
add_custom_command(
|
||||
OUTPUT ${WIBO_TEST_BIN_DIR}/test_bcrypt.exe
|
||||
COMMAND ${WIBO_MINGW_CC} -Wall -Wextra -O2
|
||||
-I${CMAKE_CURRENT_SOURCE_DIR}/test
|
||||
-o test_bcrypt.exe
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/test/test_bcrypt.c
|
||||
-lbcrypt
|
||||
WORKING_DIRECTORY ${WIBO_TEST_BIN_DIR}
|
||||
DEPENDS
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/test/test_bcrypt.c
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/test/test_assert.h)
|
||||
|
||||
add_custom_command(
|
||||
OUTPUT ${WIBO_TEST_BIN_DIR}/test_resources_res.o
|
||||
COMMAND ${WIBO_MINGW_WINDRES}
|
||||
@ -105,6 +117,7 @@ if(BUILD_TESTING)
|
||||
DEPENDS
|
||||
${WIBO_TEST_BIN_DIR}/external_exports.dll
|
||||
${WIBO_TEST_BIN_DIR}/test_external_dll.exe
|
||||
${WIBO_TEST_BIN_DIR}/test_bcrypt.exe
|
||||
${WIBO_TEST_BIN_DIR}/test_resources.exe)
|
||||
|
||||
if(CMAKE_CONFIGURATION_TYPES)
|
||||
@ -123,6 +136,12 @@ if(BUILD_TESTING)
|
||||
WORKING_DIRECTORY ${WIBO_TEST_BIN_DIR}
|
||||
DEPENDS wibo.build_fixtures)
|
||||
|
||||
add_test(NAME wibo.test_bcrypt
|
||||
COMMAND $<TARGET_FILE:wibo> ${WIBO_TEST_BIN_DIR}/test_bcrypt.exe)
|
||||
set_tests_properties(wibo.test_bcrypt PROPERTIES
|
||||
WORKING_DIRECTORY ${WIBO_TEST_BIN_DIR}
|
||||
DEPENDS wibo.build_fixtures)
|
||||
|
||||
add_test(NAME wibo.test_resources
|
||||
COMMAND $<TARGET_FILE:wibo> ${WIBO_TEST_BIN_DIR}/test_resources.exe)
|
||||
set_tests_properties(wibo.test_resources PROPERTIES
|
||||
|
2
common.h
2
common.h
@ -81,6 +81,8 @@ typedef unsigned char BYTE;
|
||||
typedef int NTSTATUS;
|
||||
#define STATUS_SUCCESS ((NTSTATUS)0x00000000)
|
||||
#define STATUS_INVALID_HANDLE ((NTSTATUS)0xC0000008)
|
||||
#define STATUS_INVALID_PARAMETER ((NTSTATUS)0xC000000D)
|
||||
#define STATUS_NOT_IMPLEMENTED ((NTSTATUS)0xC0000002)
|
||||
#define STATUS_END_OF_FILE ((NTSTATUS)0xC0000011)
|
||||
#define STATUS_NOT_SUPPORTED ((NTSTATUS)0xC00000BB)
|
||||
#define STATUS_UNEXPECTED_IO_ERROR ((NTSTATUS)0xC00000E9)
|
||||
|
@ -1,21 +1,64 @@
|
||||
#include "common.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <climits>
|
||||
#include <random>
|
||||
#include <sys/random.h>
|
||||
#include <vector>
|
||||
|
||||
namespace {
|
||||
|
||||
typedef PVOID BCRYPT_ALG_HANDLE;
|
||||
|
||||
namespace bcrypt {
|
||||
constexpr ULONG BCRYPT_RNG_USE_ENTROPY_IN_BUFFER = 0x00000001;
|
||||
constexpr ULONG BCRYPT_USE_SYSTEM_PREFERRED_RNG = 0x00000002;
|
||||
|
||||
using random_bytes_engine = std::independent_bits_engine<std::default_random_engine, CHAR_BIT, unsigned char>;
|
||||
bool fillWithSystemRandom(PUCHAR buffer, size_t length) {
|
||||
while (length > 0) {
|
||||
ssize_t written = getrandom(buffer, length, 0);
|
||||
if (written < 0) {
|
||||
if (errno == EINTR)
|
||||
continue;
|
||||
return false;
|
||||
}
|
||||
if (written == 0)
|
||||
continue;
|
||||
buffer += written;
|
||||
length -= static_cast<size_t>(written);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
namespace bcrypt {
|
||||
|
||||
NTSTATUS WIN_FUNC BCryptGenRandom(BCRYPT_ALG_HANDLE hAlgorithm, PUCHAR pbBuffer, ULONG cbBuffer, ULONG dwFlags) {
|
||||
DEBUG_LOG("BCryptGenRandom(%p, %p, %lu, %lu)\n", hAlgorithm, pbBuffer, cbBuffer, dwFlags);
|
||||
assert(hAlgorithm == nullptr);
|
||||
assert(dwFlags == 0 || dwFlags == 2 /* BCRYPT_USE_SYSTEM_PREFERRED_RNG */);
|
||||
random_bytes_engine rbe;
|
||||
std::generate(pbBuffer, pbBuffer + cbBuffer, std::ref(rbe));
|
||||
if (pbBuffer == nullptr && cbBuffer != 0)
|
||||
return STATUS_INVALID_HANDLE;
|
||||
|
||||
if (hAlgorithm != nullptr)
|
||||
return STATUS_NOT_IMPLEMENTED;
|
||||
|
||||
if ((dwFlags & BCRYPT_USE_SYSTEM_PREFERRED_RNG) == 0)
|
||||
return STATUS_INVALID_HANDLE;
|
||||
|
||||
ULONG allowedFlags = BCRYPT_RNG_USE_ENTROPY_IN_BUFFER | BCRYPT_USE_SYSTEM_PREFERRED_RNG;
|
||||
if ((dwFlags & ~allowedFlags) != 0)
|
||||
return STATUS_INVALID_PARAMETER;
|
||||
|
||||
if (cbBuffer == 0)
|
||||
return STATUS_SUCCESS;
|
||||
|
||||
std::vector<unsigned char> entropy;
|
||||
if ((dwFlags & BCRYPT_RNG_USE_ENTROPY_IN_BUFFER) && pbBuffer != nullptr)
|
||||
entropy.assign(pbBuffer, pbBuffer + cbBuffer);
|
||||
|
||||
if (!fillWithSystemRandom(pbBuffer, cbBuffer))
|
||||
return STATUS_UNEXPECTED_IO_ERROR;
|
||||
|
||||
if (!entropy.empty()) {
|
||||
for (size_t i = 0; i < entropy.size(); ++i)
|
||||
pbBuffer[i] ^= entropy[i];
|
||||
}
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
|
12
dll/crt.cpp
12
dll/crt.cpp
@ -132,6 +132,12 @@ void WIN_ENTRY free(void *ptr) { ::free(ptr); }
|
||||
|
||||
void *WIN_ENTRY memcpy(void *dest, const void *src, size_t count) { return std::memcpy(dest, src, count); }
|
||||
|
||||
void *WIN_ENTRY memmove(void *dest, const void *src, size_t count) { return std::memmove(dest, src, count); }
|
||||
|
||||
void *WIN_ENTRY memset(void *dest, int ch, size_t count) { return std::memset(dest, ch, count); }
|
||||
|
||||
int WIN_ENTRY memcmp(const void *lhs, const void *rhs, size_t count) { return std::memcmp(lhs, rhs, count); }
|
||||
|
||||
int WIN_ENTRY __setusermatherr(void *handler) {
|
||||
DEBUG_LOG("STUB: __setusermatherr(%p)\n", handler);
|
||||
return 0;
|
||||
@ -266,6 +272,12 @@ static void *resolveByName(const char *name) {
|
||||
return (void *)crt::free;
|
||||
if (strcmp(name, "memcpy") == 0)
|
||||
return (void *)crt::memcpy;
|
||||
if (strcmp(name, "memmove") == 0)
|
||||
return (void *)crt::memmove;
|
||||
if (strcmp(name, "memset") == 0)
|
||||
return (void *)crt::memset;
|
||||
if (strcmp(name, "memcmp") == 0)
|
||||
return (void *)crt::memcmp;
|
||||
if (strcmp(name, "exit") == 0)
|
||||
return (void *)crt::exit;
|
||||
if (strcmp(name, "_cexit") == 0)
|
||||
|
@ -570,6 +570,10 @@ char* WIN_ENTRY setlocale(int category, const char *locale){
|
||||
return std::memmove(dest, src, count);
|
||||
}
|
||||
|
||||
int WIN_ENTRY memcmp(const void *lhs, const void *rhs, size_t count) {
|
||||
return std::memcmp(lhs, rhs, count);
|
||||
}
|
||||
|
||||
int WIN_ENTRY fflush(FILE *stream) {
|
||||
return std::fflush(stream);
|
||||
}
|
||||
@ -1485,6 +1489,7 @@ static void *resolveByName(const char *name) {
|
||||
if (strcmp(name, "memset") == 0) return (void*)msvcrt::memset;
|
||||
if (strcmp(name, "memcpy") == 0) return (void*)msvcrt::memcpy;
|
||||
if (strcmp(name, "memmove") == 0) return (void*)msvcrt::memmove;
|
||||
if (strcmp(name, "memcmp") == 0) return (void*)msvcrt::memcmp;
|
||||
if (strcmp(name, "fflush") == 0) return (void*)msvcrt::fflush;
|
||||
if (strcmp(name, "fopen") == 0) return (void*)msvcrt::fopen;
|
||||
if (strcmp(name, "fseek") == 0) return (void*)msvcrt::fseek;
|
||||
|
67
test/test_bcrypt.c
Normal file
67
test/test_bcrypt.c
Normal file
@ -0,0 +1,67 @@
|
||||
#define WIN32_NO_STATUS
|
||||
#include <windows.h>
|
||||
#undef WIN32_NO_STATUS
|
||||
#include <bcrypt.h>
|
||||
#include <ntstatus.h>
|
||||
|
||||
#include "test_assert.h"
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#ifndef NT_SUCCESS
|
||||
#define NT_SUCCESS(Status) (((NTSTATUS)(Status)) >= 0)
|
||||
#endif
|
||||
|
||||
static void expect_success(NTSTATUS status) {
|
||||
TEST_CHECK_MSG(NT_SUCCESS(status), "Expected success NTSTATUS, got 0x%08lx", (unsigned long)status);
|
||||
}
|
||||
|
||||
int main(void) {
|
||||
UCHAR temp[32] = {0};
|
||||
const UCHAR zero_block[32] = {0};
|
||||
NTSTATUS status = BCryptGenRandom(NULL, temp, sizeof(temp), 0);
|
||||
TEST_CHECK_EQ(STATUS_INVALID_HANDLE, status);
|
||||
|
||||
UCHAR first[32] = {0};
|
||||
status = BCryptGenRandom(NULL, first, sizeof(first), BCRYPT_USE_SYSTEM_PREFERRED_RNG);
|
||||
expect_success(status);
|
||||
TEST_CHECK_MSG(memcmp(first, zero_block, sizeof(first)) != 0,
|
||||
"BCryptGenRandom with system RNG flag left buffer zeroed");
|
||||
|
||||
UCHAR second[32] = {0};
|
||||
status = BCryptGenRandom(NULL, second, sizeof(second), BCRYPT_USE_SYSTEM_PREFERRED_RNG);
|
||||
expect_success(status);
|
||||
TEST_CHECK_MSG(memcmp(second, zero_block, sizeof(second)) != 0,
|
||||
"BCryptGenRandom produced zeroed buffer on repeat call");
|
||||
TEST_CHECK_MSG(memcmp(first, second, sizeof(first)) != 0,
|
||||
"BCryptGenRandom produced identical buffers across calls");
|
||||
|
||||
UCHAR entropy_buffer[32];
|
||||
UCHAR entropy_original[32];
|
||||
memset(entropy_buffer, 0x5a, sizeof(entropy_buffer));
|
||||
memcpy(entropy_original, entropy_buffer, sizeof(entropy_buffer));
|
||||
status = BCryptGenRandom(NULL, entropy_buffer, sizeof(entropy_buffer),
|
||||
BCRYPT_RNG_USE_ENTROPY_IN_BUFFER | BCRYPT_USE_SYSTEM_PREFERRED_RNG);
|
||||
expect_success(status);
|
||||
TEST_CHECK_MSG(memcmp(entropy_buffer, entropy_original, sizeof(entropy_buffer)) != 0,
|
||||
"Entropy flag did not modify buffer");
|
||||
|
||||
status = BCryptGenRandom((BCRYPT_ALG_HANDLE)0x1, first, sizeof(first), 0);
|
||||
TEST_CHECK_EQ(STATUS_NOT_IMPLEMENTED, status);
|
||||
|
||||
status = BCryptGenRandom(NULL, first, sizeof(first), 0x4);
|
||||
TEST_CHECK_EQ(STATUS_INVALID_HANDLE, status);
|
||||
|
||||
status = BCryptGenRandom((BCRYPT_ALG_HANDLE)0x1, first, sizeof(first), BCRYPT_USE_SYSTEM_PREFERRED_RNG);
|
||||
TEST_CHECK_EQ(STATUS_NOT_IMPLEMENTED, status);
|
||||
|
||||
status = BCryptGenRandom(NULL, NULL, sizeof(first), 0);
|
||||
TEST_CHECK_EQ(STATUS_INVALID_HANDLE, status);
|
||||
|
||||
status = BCryptGenRandom(NULL, NULL, 0, 0);
|
||||
TEST_CHECK_EQ(STATUS_INVALID_HANDLE, status);
|
||||
|
||||
printf("bcrypt_gen_random: passed\n");
|
||||
return EXIT_SUCCESS;
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user