From dd47e442540b2e8014cab39a9db9e2a627b77760 Mon Sep 17 00:00:00 2001 From: Green Sky Date: Fri, 2 Aug 2024 11:50:01 +0200 Subject: [PATCH] implementation of the cryptographic primitives --- .gitignore | 26 ++++++++++++++++++ CMakeLists.txt | 39 +++++++++++++++++++++++++++ src/p2prng.c | 71 ++++++++++++++++++++++++++++++++++++++++++++++++++ src/p2prng.h | 50 +++++++++++++++++++++++++++++++++++ 4 files changed, 186 insertions(+) create mode 100644 .gitignore create mode 100644 CMakeLists.txt create mode 100644 src/p2prng.c create mode 100644 src/p2prng.h diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..56f48bf --- /dev/null +++ b/.gitignore @@ -0,0 +1,26 @@ +.vs/ +*.o +*.swp +~* +*~ +.idea/ +cmake-build-debug/ +cmake-build-debugandtest/ +cmake-build-release/ +*.stackdump +*.coredump +compile_commands.json +/build* +/result* +.clangd +.cache + +.DS_Store +.AppleDouble +.LSOverride + +CMakeLists.txt.user* +CMakeCache.txt + +*.tox +imgui.ini diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..9babac6 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,39 @@ +cmake_minimum_required(VERSION 3.9 FATAL_ERROR) + +project(p2prng) + +set(CMAKE_EXPORT_COMPILE_COMMANDS ON) + +set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/lib") +set(CMAKE_LIBRARY_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin") +set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin") + +add_library(p2prng + ./src/p2prng.h + ./src/p2prng.c +) + +find_package(unofficial-sodium CONFIG QUIET) +find_package(sodium QUIET) +find_package(PkgConfig QUIET) +if(unofficial-sodium_FOUND) # vcpkg + if(TARGET unofficial-sodium::sodium) + target_link_libraries(p2prng unofficial-sodium::sodium) + endif() + if(TARGET unofficial-sodium::sodium_config_public) + target_link_libraries(p2prng unofficial-sodium::sodium_config_public) + endif() +elseif(sodium_FOUND) + target_link_libraries(p2prng sodium) +else() + if(PkgConfig_FOUND) + pkg_check_modules(pkgconf_sodium IMPORTED_TARGET libsodium) + endif() + + if (TARGET PkgConfig::pkgconf_sodium) + target_link_libraries(p2prng PkgConfig::pkgconf_sodium) + else() + message(SEND_ERROR "missing libsodium") + endif() +endif() + diff --git a/src/p2prng.c b/src/p2prng.c new file mode 100644 index 0000000..aa2339e --- /dev/null +++ b/src/p2prng.c @@ -0,0 +1,71 @@ +#include "./p2prng.h" + +#include + +#include + +static_assert(P2PRNG_MAC_KEY_LEN == crypto_auth_KEYBYTES, "key sizes differ"); +static_assert(P2PRNG_MAC_LEN == crypto_auth_BYTES, "mac sizes differ"); + +static_assert(P2PRNG_MAC_KEY_LEN == P2PRNG_LEN, "key not 256"); +static_assert(P2PRNG_MAC_LEN == P2PRNG_LEN, "mac not 256"); + +static_assert(P2PRNG_COMBINE_LEN == P2PRNG_LEN, "combine not 256"); + +int p2prng_auth_create(uint8_t out_key[P2PRNG_MAC_KEY_LEN], uint8_t out_mac[P2PRNG_MAC_LEN], const uint8_t* msg, uint32_t msg_len) { + // could replace with randombytes_buf() to avoid key size check + crypto_auth_keygen(out_key); + + return crypto_auth(out_mac, msg, msg_len, out_key); +} + +int p2prng_auth_verify(const uint8_t key[P2PRNG_MAC_KEY_LEN], const uint8_t mac[P2PRNG_MAC_LEN], const uint8_t* msg, uint32_t msg_len) { + return crypto_auth_verify(mac, msg, msg_len, key); +} + + +int p2prng_combine_init(uint8_t out_hash[P2PRNG_COMBINE_LEN], const uint8_t* msg, uint32_t msg_len) { + return crypto_generichash(out_hash, P2PRNG_COMBINE_LEN, msg, msg_len, NULL, 0); +} + +int p2prng_combine_update(uint8_t out_hash[P2PRNG_COMBINE_LEN], const uint8_t prev_hash[P2PRNG_COMBINE_LEN], const uint8_t* msg, uint32_t msg_len) { + // either combine msg and hash, or use streaming interface + + /*alignas(64)*/ crypto_generichash_state state; + + // TODO: we could use the first part as key here, should be functionally identical + // or we hardcode a custom key here, mostly for vanity + int res = crypto_generichash_init(&state, NULL, 0, P2PRNG_COMBINE_LEN); + if (res != 0) { + return res; + } + + // H(msg || Hprev) + + // first msg + res = crypto_generichash_update(&state, msg, msg_len); + if (res != 0) { + return res; + } + + // then hash from prev round + res = crypto_generichash_update(&state, prev_hash, P2PRNG_COMBINE_LEN); + if (res != 0) { + return res; + } + + return crypto_generichash_final(&state, out_hash, P2PRNG_COMBINE_LEN); +} + +int p2prng_gen_and_auth(uint8_t out_rng[P2PRNG_LEN], uint8_t out_key[P2PRNG_MAC_KEY_LEN], uint8_t out_mac[P2PRNG_MAC_LEN], const uint8_t* is, uint32_t is_len) { + // generate a (hopefully) cryptogrpahiclly random number + randombytes_buf(out_rng, P2PRNG_LEN); + + // combine IS into rng + int res = p2prng_combine_update(out_rng, out_rng, is, is_len); + if (res != 0) { + return res; + } + + return p2prng_auth_create(out_key, out_mac, out_rng, P2PRNG_LEN); +} diff --git a/src/p2prng.h b/src/p2prng.h new file mode 100644 index 0000000..556be8b --- /dev/null +++ b/src/p2prng.h @@ -0,0 +1,50 @@ +#ifndef P2PRNG_H +#define P2PRNG_H + +#include + +// # generate random number and mac +// IS should include all peers participating, ideally with a unique id +// +// usage example: +// uint8_t self_rng[P2PRNG_LEN]; +// uint8_t self_key[P2PRNG_MAC_KEY_LEN]; +// p2prng_gen_and_auth(self_rng, self_key, self_mac, is, is_len); +// // wait for all other macs to arrive +// for (int i = 0; i < peer_count; i++) { +// if (p2prng_auth_verify(peer_mac_key[i], peer_mac[i], peer_msgs[i], peer_msg_len[i]) != 0) { +// // validation error, optionally rerequest +// exit(1); +// } +// } +// // proceed with rng combining + +// # combine the random numbers and IS +// call with IS last +// +// usage example: +// uint8_t final_hash[P2PRNG_COMBINE_LEN]; +// p2prng_combine_init(final_hash, peer_msgs[0], peer_msg_len[0]); +// for (int i = 1; i < peer_count; i++) { +// p2prng_combine_update(final_hash, final_hash, peer_msgs[i], peer_msg_len[i]); +// } +// p2prng_combine_update(final_hash, final_hash, is, is_len); + +#define P2PRNG_LEN 32u +#define P2PRNG_MAC_KEY_LEN 32u +#define P2PRNG_MAC_LEN 32u +#define P2PRNG_COMBINE_LEN 32u + +// TODO: merge key into msg +int p2prng_auth_create(uint8_t out_key[P2PRNG_MAC_KEY_LEN], uint8_t out_mac[P2PRNG_MAC_LEN], const uint8_t* msg, uint32_t msg_len); +int p2prng_auth_verify(const uint8_t key[P2PRNG_MAC_KEY_LEN], const uint8_t mac[P2PRNG_MAC_LEN], const uint8_t* msg, uint32_t msg_len); + +int p2prng_combine_init(uint8_t out_hash[P2PRNG_COMBINE_LEN], const uint8_t* msg, uint32_t msg_len); +int p2prng_combine_update(uint8_t out_hash[P2PRNG_COMBINE_LEN], const uint8_t prev_hash[P2PRNG_COMBINE_LEN], const uint8_t* msg, uint32_t msg_len); + +// helper that: +// - generates the random number (msg) +// - calls p2prng_auth_create() +int p2prng_gen_and_auth(uint8_t out_rng[P2PRNG_LEN], uint8_t out_key[P2PRNG_MAC_KEY_LEN], uint8_t out_mac[P2PRNG_MAC_LEN], const uint8_t* is, uint32_t is_len); + +#endif // P2PRNG_H