diff --git a/cmake/src/main/sec/CMakeLists.txt b/cmake/src/main/sec/CMakeLists.txt index d487339..a9e4fc2 100644 --- a/cmake/src/main/sec/CMakeLists.txt +++ b/cmake/src/main/sec/CMakeLists.txt @@ -1,4 +1,5 @@ add_subdirectory(hasp) add_subdirectory(lockchip) add_subdirectory(microdog34) -add_subdirectory(microdog40) \ No newline at end of file +add_subdirectory(microdog40) +add_subdirectory(prinet) \ No newline at end of file diff --git a/cmake/src/main/sec/prinet/CMakeLists.txt b/cmake/src/main/sec/prinet/CMakeLists.txt new file mode 100644 index 0000000..7408640 --- /dev/null +++ b/cmake/src/main/sec/prinet/CMakeLists.txt @@ -0,0 +1,13 @@ +project(sec-prinet) +message(STATUS "Project " ${PROJECT_NAME}) + +set(SRC ${PT_ROOT_MAIN}/sec/prinet) + +set(SOURCE_FILES + ${SRC}/prinet.c) + +add_library(${PROJECT_NAME} STATIC ${SOURCE_FILES}) + +set_target_properties(${PROJECT_NAME} PROPERTIES COMPILE_FLAGS "-fPIC") + +target_link_libraries(${PROJECT_NAME} util -lsodium) diff --git a/cmake/src/test/CMakeLists.txt b/cmake/src/test/CMakeLists.txt index a462985..49ad470 100644 --- a/cmake/src/test/CMakeLists.txt +++ b/cmake/src/test/CMakeLists.txt @@ -5,5 +5,6 @@ include_directories(${PT_ROOT_TEST}) add_subdirectory(capnhook) add_subdirectory(hook) +add_subdirectory(sec) add_subdirectory(test-util) add_subdirectory(util) \ No newline at end of file diff --git a/cmake/src/test/sec/CMakeLists.txt b/cmake/src/test/sec/CMakeLists.txt new file mode 100644 index 0000000..2c3f50f --- /dev/null +++ b/cmake/src/test/sec/CMakeLists.txt @@ -0,0 +1 @@ +add_subdirectory(prinet) \ No newline at end of file diff --git a/cmake/src/test/sec/prinet/CMakeLists.txt b/cmake/src/test/sec/prinet/CMakeLists.txt new file mode 100644 index 0000000..2c3f50f --- /dev/null +++ b/cmake/src/test/sec/prinet/CMakeLists.txt @@ -0,0 +1 @@ +add_subdirectory(prinet) \ No newline at end of file diff --git a/cmake/src/test/sec/prinet/prinet/CMakeLists.txt b/cmake/src/test/sec/prinet/prinet/CMakeLists.txt new file mode 100644 index 0000000..020078a --- /dev/null +++ b/cmake/src/test/sec/prinet/prinet/CMakeLists.txt @@ -0,0 +1,14 @@ +project(test-sec-prinet-prinet) +message(STATUS "Project " ${PROJECT_NAME}) + +set(SRC ${PT_ROOT_TEST}/sec/prinet/prinet) + +add_resources(PRI_PRIVATE_KEY ${SRC} prime.private.key) +add_resources(PRI_PUBLIC_KEY ${SRC} prime.public.key) + +set(SOURCE_FILES + ${SRC}/main.c) + +add_executable(${PROJECT_NAME} ${SOURCE_FILES} ${PRI_PRIVATE_KEY} ${PRI_PUBLIC_KEY}) + +target_link_libraries(${PROJECT_NAME} cmocka sec-prinet test-util util) diff --git a/src/main/sec/prinet/prinet.c b/src/main/sec/prinet/prinet.c new file mode 100644 index 0000000..e28ae22 --- /dev/null +++ b/src/main/sec/prinet/prinet.c @@ -0,0 +1,118 @@ +#define LOG_MODULE "sec-prinet" + +#include +#include +#include +#include + +#include "sec/prinet/prinet.h" + +#include "util/log.h" +#include "util/mem.h" + +_Static_assert (crypto_box_NONCEBYTES == SEC_PRINET_NOUNCE_LEN, "Nounce length not as expected for prinet"); +_Static_assert (crypto_box_MACBYTES == SEC_PRINET_MACBYTES_LEN, "Nounce length not as expected for prinet"); + +static void* _key_pub; +static size_t _key_pub_len; +static void* _key_priv; +static size_t _key_priv_len; + +static void* _sec_prinet_safe_malloc(size_t size) +{ + size_t pagesize = getpagesize(); + size_t num_pages = size / pagesize; + size_t num_pages_round_up = num_pages; + + if (size % pagesize != 0) { + num_pages_round_up++; + } + + size_t size_aligned = num_pages_round_up * pagesize; + + void* ptr = sodium_malloc(size_aligned); + + if (ptr == NULL) { + log_error("Sodium malloc failed, %s", strerror(errno)); + return NULL; + } + + return ptr; +} + +void sec_prinet_init( + const uint8_t* key_pub, size_t key_pub_len, + const uint8_t* key_priv, size_t key_priv_len) +{ + _key_pub = util_xmalloc(key_pub_len); + memcpy(_key_pub, key_pub, key_pub_len); + _key_pub_len = key_pub_len; + + _key_priv = util_xmalloc(key_priv_len); + memcpy(_key_priv, key_priv, key_priv_len); + _key_priv_len = key_priv_len; + + // 0 on success, 1 if already initialized + if (sodium_init() == -1) { + log_error("Initializing sodium failed"); + } +} + +void sec_prinet_finit() +{ + util_xfree(&_key_pub); + util_xfree(&_key_priv); +} + +size_t sec_prinet_get_enc_data_buffer_size(size_t enc_data_len) +{ + return enc_data_len + crypto_box_MACBYTES; +} + +size_t sec_prinet_decrypt( + const uint8_t* nounce, size_t nounce_len, const uint8_t* enc_data, + size_t enc_data_len, uint8_t* dec_data) +{ + if (nounce_len != SEC_PRINET_NOUNCE_LEN) { + log_error("Nounce len %d does not match expected len %d", nounce_len, SEC_PRINET_NOUNCE_LEN); + return -1; + } + + if (crypto_box_open_easy(dec_data, enc_data, enc_data_len, nounce, _key_pub, _key_priv) != 0) { + log_error("Decrypting message, len %d, failed", enc_data_len); + return -1; + } + + return enc_data_len; +} + +size_t sec_prinet_encrypt( + const uint8_t* nounce, size_t nounce_len, const uint8_t* dec_data, + size_t dec_data_len, uint8_t* enc_data) +{ + if (nounce_len != SEC_PRINET_NOUNCE_LEN) { + log_error("Nounce len %d does not match expected len %d", nounce_len, SEC_PRINET_NOUNCE_LEN); + return -1; + } + + void* tmp_enc = _sec_prinet_safe_malloc(dec_data_len); + + if (tmp_enc == NULL) { + return -1; + } + + if (crypto_box_easy(tmp_enc, dec_data, dec_data_len, nounce, _key_pub, _key_priv) != 0) { + log_error("Encrypting message, len %d, failed", dec_data_len); + sodium_free(tmp_enc); + return -1; + } + + // Encrypted data/response expects additional data after game specific payload + size_t enc_data_len = sec_prinet_get_enc_data_buffer_size(dec_data_len); + + memcpy(enc_data, tmp_enc, enc_data_len); + + sodium_free(tmp_enc); + + return enc_data_len; +} \ No newline at end of file diff --git a/src/main/sec/prinet/prinet.h b/src/main/sec/prinet/prinet.h new file mode 100644 index 0000000..a9c7b56 --- /dev/null +++ b/src/main/sec/prinet/prinet.h @@ -0,0 +1,23 @@ +#pragma once + +#include +#include + +#define SEC_PRINET_NOUNCE_LEN 24 +#define SEC_PRINET_MACBYTES_LEN 16 + +void sec_prinet_init( + const uint8_t* key_pub, size_t key_pub_len, + const uint8_t* key_priv, size_t key_priv_len); + +void sec_prinet_finit(); + +size_t sec_prinet_get_enc_data_buffer_size(size_t enc_data_len); + +size_t sec_prinet_decrypt( + const uint8_t* nounce, size_t nounce_len, const uint8_t* enc_data, + size_t enc_data_len, uint8_t* dec_data); + +size_t sec_prinet_encrypt( + const uint8_t* nounce, size_t nounce_len, const uint8_t* dec_data, + size_t dec_data_len, uint8_t* enc_data); \ No newline at end of file diff --git a/src/test/sec/prinet/prinet/main.c b/src/test/sec/prinet/prinet/main.c new file mode 100644 index 0000000..9844fa9 --- /dev/null +++ b/src/test/sec/prinet/prinet/main.c @@ -0,0 +1,115 @@ +#include + +#include "sec/prinet/prinet.h" + +#include "test-util/mem.h" + +#include "util/mem.h" +#include "util/rand.h" + +/* Compiled binary data from data folder. Symbols are defined by compiler */ +extern const uint8_t _binary_prime_private_key_start[]; +extern const uint8_t _binary_prime_private_key_end[]; +extern const uint8_t _binary_prime_public_key_start[]; +extern const uint8_t _binary_prime_public_key_end[]; + +static void _test_encrypt_decrypt(uint32_t seed) +{ + util_rand_init(seed); + + uint8_t* data; + size_t data_len; + uint8_t* nounce; + uint8_t* enc_data; + size_t enc_data_len; + uint8_t* dec_data; + size_t dec_data_len; + size_t enc_data_len_res; + size_t dec_data_len_res; + + for (uint32_t i = 0; i < 20; i++) { + data_len = util_rand_gen_range_32(1024 * 1024); + data = util_xmalloc(data_len); + util_rand_gen_bytes(data, data_len); + + nounce = util_xmalloc(SEC_PRINET_NOUNCE_LEN); + util_rand_gen_bytes(nounce, SEC_PRINET_NOUNCE_LEN); + + enc_data_len = sec_prinet_get_enc_data_buffer_size(data_len); + enc_data = util_xmalloc(enc_data_len); + + enc_data_len_res = + sec_prinet_encrypt(nounce, SEC_PRINET_NOUNCE_LEN, data, data_len, enc_data); + + assert_int_equal(enc_data_len_res, enc_data_len); + + dec_data_len = enc_data_len_res; + dec_data = util_xmalloc(dec_data_len); + + dec_data_len_res = + sec_prinet_decrypt(nounce, SEC_PRINET_NOUNCE_LEN, enc_data, dec_data_len, dec_data); + + assert_int_equal(dec_data_len_res, sec_prinet_get_enc_data_buffer_size(data_len)); + + assert_memory_equal(data, dec_data, data_len); + + util_xfree((void**) &dec_data); + util_xfree((void**) &enc_data); + util_xfree((void**) &nounce); + util_xfree((void**) &data); + } +} + +static int setup(void** state) +{ + test_util_mem_install_mem_interface(); + + sec_prinet_init( + (const uint8_t*) _binary_prime_public_key_start, + ((uintptr_t) &_binary_prime_public_key_end - + (uintptr_t) &_binary_prime_public_key_start), + (const uint8_t*) _binary_prime_private_key_start, + ((uintptr_t) &_binary_prime_private_key_end - + (uintptr_t) &_binary_prime_private_key_start)); + + return 0; +} + +static int teardown(void** state) +{ + sec_prinet_finit(); + + return 0; +} + +static void test_encrypt_decrypt_1(void** state) +{ + _test_encrypt_decrypt(1); +} + +static void test_encrypt_decrypt_2(void** state) +{ + _test_encrypt_decrypt(2); +} + +static void test_encrypt_decrypt_3(void** state) +{ + _test_encrypt_decrypt(3); +} + +static void test_encrypt_decrypt_4(void** state) +{ + _test_encrypt_decrypt(4); +} + +int main(int argc, char* argv[]) +{ + const struct CMUnitTest tests[] ={ + cmocka_unit_test_setup_teardown(test_encrypt_decrypt_1, setup, teardown), + cmocka_unit_test_setup_teardown(test_encrypt_decrypt_2, setup, teardown), + cmocka_unit_test_setup_teardown(test_encrypt_decrypt_3, setup, teardown), + cmocka_unit_test_setup_teardown(test_encrypt_decrypt_4, setup, teardown) + }; + + return cmocka_run_group_tests(tests, NULL, NULL); +} \ No newline at end of file diff --git a/src/test/sec/prinet/prinet/prime.private.key b/src/test/sec/prinet/prinet/prime.private.key new file mode 100755 index 0000000..a624ea3 --- /dev/null +++ b/src/test/sec/prinet/prinet/prime.private.key @@ -0,0 +1 @@ +“²ø à•I߯þ6Væ­œšS›öcÓ|ð¤æ)<¿údV \ No newline at end of file diff --git a/src/test/sec/prinet/prinet/prime.public.key b/src/test/sec/prinet/prinet/prime.public.key new file mode 100755 index 0000000..acb180d --- /dev/null +++ b/src/test/sec/prinet/prinet/prime.public.key @@ -0,0 +1,2 @@ +°ë�GQ +. 2í/ÀùÔ눰Ê-½çÖNâЃL;¶û1U \ No newline at end of file