From 972ead3cae637939007b4bda7d2b1b4d876ed7d4 Mon Sep 17 00:00:00 2001 From: Carles Fernandez Date: Wed, 7 Jun 2023 17:21:42 +0200 Subject: [PATCH] Introducing the crypto bro --- src/core/libs/CMakeLists.txt | 39 --- src/core/libs/osnma_msg_receiver.cc | 309 +---------------- src/core/libs/osnma_msg_receiver.h | 15 +- src/core/receiver/gnss_flowgraph.cc | 4 +- src/core/system_parameters/CMakeLists.txt | 38 ++ src/core/system_parameters/gnss_crypto.cc | 400 ++++++++++++++++++++++ src/core/system_parameters/gnss_crypto.h | 49 +++ 7 files changed, 507 insertions(+), 347 deletions(-) create mode 100644 src/core/system_parameters/gnss_crypto.cc create mode 100644 src/core/system_parameters/gnss_crypto.h diff --git a/src/core/libs/CMakeLists.txt b/src/core/libs/CMakeLists.txt index c5425d027..1c0c6e811 100644 --- a/src/core/libs/CMakeLists.txt +++ b/src/core/libs/CMakeLists.txt @@ -102,45 +102,6 @@ target_link_libraries(core_libs Pugixml::pugixml ) -if(OPENSSL_FOUND) - if(TARGET OpenSSL::SSL) - target_link_libraries(core_libs - PRIVATE - OpenSSL::SSL - ) - else() - target_link_libraries(core_libs - PRIVATE - ${OPENSSL_LIBRARIES} - ) - target_include_directories(core_libs - PRIVATE - ${OPENSSL_INCLUDE_DIR} - ) - endif() - if(OPENSSL_VERSION) - if(OPENSSL_VERSION VERSION_GREATER "3.0.0") - target_compile_definitions(core_libs PRIVATE -DUSE_OPENSSL_3=1) - endif() - endif() -else() - target_link_libraries(core_libs - PRIVATE - ${GNUTLS_LIBRARIES} - ${GNUTLS_OPENSSL_LIBRARY} - ) - target_include_directories(core_libs - PRIVATE - ${GNUTLS_INCLUDE_DIR} - ) -endif() - - - -if(OPENSSL_FOUND) - target_compile_definitions(core_libs PRIVATE -DUSE_OPENSSL_FALLBACK=1) -endif() - if(USE_GENERIC_LAMBDAS AND NOT GNURADIO_USES_STD_POINTERS) target_link_libraries(core_libs PUBLIC Boost::headers) else() diff --git a/src/core/libs/osnma_msg_receiver.cc b/src/core/libs/osnma_msg_receiver.cc index 8572ec03d..c8cd9e372 100644 --- a/src/core/libs/osnma_msg_receiver.cc +++ b/src/core/libs/osnma_msg_receiver.cc @@ -19,18 +19,15 @@ #include "osnma_msg_receiver.h" #include "Galileo_OSNMA.h" +#include "gnss_crypto.h" #include "osnma_dsm_reader.h" // for OSNMA_DSM_Reader #include // for DLOG #include // for gr::io_signature::make -#include #include #include #include -#include #include -#include #include -#include #include // for typeid #if HAS_GENERIC_LAMBDA @@ -46,33 +43,21 @@ namespace wht = boost; namespace wht = std; #endif -#if USE_OPENSSL_FALLBACK -#include -#include -#if USE_OPENSSL_3 -#include -#define OPENSSL_ENGINE NULL -#else -#include -#endif -#else -#include -#include -#include -#endif -osnma_msg_receiver_sptr osnma_msg_receiver_make() +osnma_msg_receiver_sptr osnma_msg_receiver_make(const std::string& pemFilePath) { - return osnma_msg_receiver_sptr(new osnma_msg_receiver()); + return osnma_msg_receiver_sptr(new osnma_msg_receiver(pemFilePath)); } -osnma_msg_receiver::osnma_msg_receiver() : gr::block("osnma_msg_receiver", - gr::io_signature::make(0, 0, 0), - gr::io_signature::make(0, 0, 0)) +osnma_msg_receiver::osnma_msg_receiver( + const std::string& pemFilePath) : gr::block("osnma_msg_receiver", + gr::io_signature::make(0, 0, 0), + gr::io_signature::make(0, 0, 0)) { d_dsm_reader = std::make_unique(); - // register OSNMA input message port from telemetry blocks + d_crypto = std::make_unique(pemFilePath); + // register OSNMA input message port from telemetry blocks this->message_port_register_in(pmt::mp("OSNMA_from_TLM")); // register OSNMA output message port to PVT block this->message_port_register_out(pmt::mp("OSNMA_to_PVT")); @@ -291,11 +276,11 @@ void osnma_msg_receiver::process_dsm_message(const std::vector& dsm_msg std::vector hash; if (d_osnma_data.d_dsm_kroot_message.hf == 0) // Table 8. { - hash = computeSHA256(MSG); + hash = d_crypto->computeSHA256(MSG); } else if (d_osnma_data.d_dsm_kroot_message.hf == 2) { - hash = computeSHA3_256(MSG); + hash = d_crypto->computeSHA3_256(MSG); } else { @@ -585,275 +570,3 @@ void osnma_msg_receiver::read_mack_key() void osnma_msg_receiver::read_mack_padding() { } - - -std::vector osnma_msg_receiver::computeSHA256(const std::vector& input) -{ - std::vector output(32); // SHA256 hash size -#if USE_OPENSSL_FALLBACK -#if USE_OPENSSL_3 - // unsigned char mdVal[EVP_MAX_MD_SIZE]; - // unsigned char* md; - unsigned int mdLen; - EVP_MD_CTX* mdCtx = EVP_MD_CTX_new(); - if (!EVP_DigestInit_ex(mdCtx, EVP_sha256(), OPENSSL_ENGINE)) - { - LOG(WARNING) << "OSNMA SHA-256: Message digest initialization failed."; - EVP_MD_CTX_free(mdCtx); - return output; - } - if (!EVP_DigestUpdate(mdCtx, input.data(), input.size())) - { - LOG(WARNING) << "OSNMA SHA-256: Message digest update failed."; - EVP_MD_CTX_free(mdCtx); - return output; - } - if (!EVP_DigestFinal_ex(mdCtx, output.data(), &mdLen)) - { - LOG(WARNING) << "OSNMA SHA-256: Message digest finalization failed."; - EVP_MD_CTX_free(mdCtx); - return output; - } - EVP_MD_CTX_free(mdCtx); - // md = mdVal; -#else - SHA256_CTX sha256Context; - SHA256_Init(&sha256Context); - SHA256_Update(&sha256Context, input.data(), input.size()); - SHA256_Final(output.data(), &sha256Context); -#endif -#else - std::vector output_aux(32); - gnutls_hash_hd_t hashHandle; - gnutls_hash_init(&hashHandle, GNUTLS_DIG_SHA256); - gnutls_hash(hashHandle, input.data(), input.size()); - gnutls_hash_output(hashHandle, output_aux.data()); - output = output_aux; - gnutls_hash_deinit(hashHandle, output_aux.data()); -#endif - return output; -} - - -std::vector osnma_msg_receiver::computeSHA3_256(const std::vector& input) -{ - std::vector output(32); // SHA256 hash size -#if USE_OPENSSL_FALLBACK -#if USE_OPENSSL_3 - EVP_MD_CTX* mdctx = EVP_MD_CTX_new(); - const EVP_MD* md = EVP_sha3_256(); - - EVP_DigestInit_ex(mdctx, md, nullptr); - EVP_DigestUpdate(mdctx, input.data(), input.size()); - EVP_DigestFinal_ex(mdctx, output.data(), nullptr); - EVP_MD_CTX_free(mdctx); -#else - // SHA3-256 not implemented in OpenSSL < 3.0 -#endif -#else - std::vector output_aux(32); - gnutls_hash_hd_t hashHandle; - gnutls_hash_init(&hashHandle, GNUTLS_DIG_SHA3_256); - gnutls_hash(hashHandle, input.data(), input.size()); - gnutls_hash_output(hashHandle, output_aux.data()); - output = output_aux; - gnutls_hash_deinit(hashHandle, output_aux.data()); -#endif - return output; -} - - -std::vector osnma_msg_receiver::computeHMAC_SHA_256(const std::vector& key, const std::vector& input) -{ - std::vector output(32); -#if USE_OPENSSL_FALLBACK -#if USE_OPENSSL_3 - std::vector hmac(EVP_MAX_MD_SIZE); - - // Create HMAC-SHA256 context - EVP_MD_CTX* ctx = EVP_MD_CTX_new(); - EVP_PKEY* pkey = EVP_PKEY_new_mac_key(EVP_PKEY_HMAC, nullptr, key.data(), key.size()); - - // Initialize HMAC-SHA256 context - EVP_DigestSignInit(ctx, nullptr, EVP_sha256(), nullptr, pkey); - - // Compute HMAC-SHA256 - EVP_DigestSignUpdate(ctx, input.data(), input.size()); - size_t macLength; - EVP_DigestSignFinal(ctx, hmac.data(), &macLength); - - EVP_PKEY_free(pkey); - EVP_MD_CTX_free(ctx); - - hmac.resize(macLength); - output = hmac; -#else - std::vector hmac(32); - // Create HMAC context - HMAC_CTX* ctx = HMAC_CTX_new(); - HMAC_Init_ex(ctx, key.data(), key.size(), EVP_sha256(), nullptr); - - // Update HMAC context with the message - HMAC_Update(ctx, input.data(), input.size()); - - // Finalize HMAC computation - unsigned int hmacLen; - HMAC_Final(ctx, hmac.data(), &hmacLen); - - // Clean up HMAC context - HMAC_CTX_free(ctx); - - // Resize the HMAC vector to the actual length - hmac.resize(hmacLen); - - output = hmac; -#endif -#else - std::vector output_aux(32); - gnutls_hmac_hd_t hmac; - gnutls_hmac_init(&hmac, GNUTLS_MAC_SHA256, key.data(), key.size()); - gnutls_hmac(hmac, input.data(), input.size()); - gnutls_hmac_output(hmac, output_aux.data()); - output = output_aux; - gnutls_hmac_deinit(hmac, output_aux.data()); - -#endif - return output; -} - - -std::vector osnma_msg_receiver::computeCMAC_AES(const std::vector& key, const std::vector& input) -{ - std::vector output(16); -#if USE_OPENSSL_FALLBACK -#if USE_OPENSSL_3 - std::vector mac(EVP_MAX_MD_SIZE); // CMAC-AES output size - - EVP_CIPHER_CTX* ctx = EVP_CIPHER_CTX_new(); - - // Initialize CMAC-AES context - EVP_CIPHER_CTX* cmacCtx = EVP_CIPHER_CTX_new(); - EVP_CMAC_CTX* cmac = EVP_CMAC_CTX_new(); - - EVP_CIPHER_CTX_reset(ctx); - EVP_CMAC_CTX_reset(cmac); - - // Set AES-128 CMAC cipher and key - EVP_CMAC_init(cmac, key.data(), key.size(), EVP_aes_128_cbc(), nullptr); - - // Compute CMAC-AES - EVP_CMAC_update(cmac, input.data(), input.size()); - size_t macLength; - EVP_CMAC_final(cmac, mac.data(), &macLength); - - EVP_CIPHER_CTX_free(ctx); - EVP_CMAC_CTX_free(cmac); - - mac.resize(macLength); - output = mac; -#else - std::vector mac(CMAC_DIGEST_LENGTH); // CMAC-AES output size - - // Create CMAC context - CMAC_CTX* cmacCtx = CMAC_CTX_new(); - CMAC_Init(cmacCtx, key.data(), key.size(), EVP_aes_128_cbc(), nullptr); - - // Compute CMAC-AES - CMAC_Update(cmacCtx, input.data(), input.size()); - CMAC_Final(cmacCtx, mac.data(), nullptr); - - // Clean up CMAC context - CMAC_CTX_free(cmacCtx); - - output = mac; -#endif -#else - gnutls_cipher_hd_t cipher; - std::vector mac(16); - std::vector message = input; - gnutls_datum_t key_data = {const_cast(key.data()), static_cast(key.size())}; - gnutls_cipher_init(&cipher, GNUTLS_CIPHER_AES_128_CBC, &key_data, nullptr); - gnutls_cipher_set_iv(cipher, nullptr, 16); // Set IV to zero - gnutls_cipher_encrypt(cipher, message.data(), message.size()); // Encrypt the message with AES-128 - gnutls_cipher_tag(cipher, mac.data(), mac.size()); // Get the CMAC-AES tag - output = mac; - gnutls_cipher_deinit(cipher); -#endif - return output; -} - -// bool signature(const std::vector& publicKey, const std::vector& digest, std::vector& signature) -// { -// bool success = false; -// #if USE_OPENSSL_FALLBACK -// #else -// gnutls_global_init(); -// int result = gnutls_pubkey_verify_data(publicKey.data(), GNUTLS_SIGN_ECDSA_SHA256, digest.data, digest.size(), signature.data(), signature.size()); -// success = (result == GNUTLS_E_SUCCESS); -// gnutls_global_deinit(); -// #endif -// return success; -// } -// bool verifyDigitalSignature(const unsigned char* signature, size_t signatureSize, const unsigned char* message, size_t messageSize, gnutls_pubkey_t publicKey) -// { -// int verificationStatus = gnutls_pubkey_verify_data(publicKey, GNUTLS_DIG_SHA256, 0, message, messageSize, signature, signatureSize); -// return verificationStatus == 0; - -std::vector osnma_msg_receiver::readPublicKeyFromPEM(const std::string& filePath) -{ - std::vector publicKey; -#if USE_OPENSSL_FALLBACK -#if USE_OPENSSL_3 -#else -#endif -#else - // Open the .pem file - std::ifstream file(filePath); - if (!file) - { - std::cerr << "Failed to open the file: " << filePath << std::endl; - return publicKey; - } - - // Read the contents of the .pem file into a string - std::string pemContents((std::istreambuf_iterator(file)), std::istreambuf_iterator()); - - gnutls_x509_crt_t cert; - gnutls_x509_crt_init(&cert); - - // Import the certificate from the PEM file - gnutls_datum_t pemData; - pemData.data = reinterpret_cast(const_cast(pemContents.data())); - pemData.size = pemContents.size(); - int ret = gnutls_x509_crt_import(cert, &pemData, GNUTLS_X509_FMT_PEM); - if (ret < 0) - { - std::cerr << "Failed to import certificate from PEM file" << std::endl; - gnutls_x509_crt_deinit(cert); - return publicKey; - } - - // Export the public key data - size_t pubkey_data_size = 0; - ret = gnutls_x509_crt_export(cert, GNUTLS_X509_FMT_DER, nullptr, &pubkey_data_size); - if (ret < 0) - { - std::cerr << "Failed to export public key data" << std::endl; - gnutls_x509_crt_deinit(cert); - return publicKey; - } - - publicKey.resize(pubkey_data_size); - ret = gnutls_x509_crt_export(cert, GNUTLS_X509_FMT_DER, publicKey.data(), &pubkey_data_size); - if (ret < 0) - { - std::cerr << "Failed to export public key data" << std::endl; - gnutls_x509_crt_deinit(cert); - return publicKey; - } - - gnutls_x509_crt_deinit(cert); - -#endif - return publicKey; -} \ No newline at end of file diff --git a/src/core/libs/osnma_msg_receiver.h b/src/core/libs/osnma_msg_receiver.h index 149d20b43..831ca29ab 100644 --- a/src/core/libs/osnma_msg_receiver.h +++ b/src/core/libs/osnma_msg_receiver.h @@ -27,6 +27,7 @@ #include // for pmt::pmt_t #include // for std::array #include // for std::shared_ptr +#include #include /** \addtogroup Core @@ -35,11 +36,12 @@ * \{ */ class OSNMA_DSM_Reader; +class Gnss_Crypto; class osnma_msg_receiver; using osnma_msg_receiver_sptr = gnss_shared_ptr; -osnma_msg_receiver_sptr osnma_msg_receiver_make(); +osnma_msg_receiver_sptr osnma_msg_receiver_make(const std::string& pemFilePath); /*! * \brief GNU Radio block that receives asynchronous OSNMA messages @@ -53,8 +55,8 @@ public: ~osnma_msg_receiver() = default; //!< Default destructor private: - friend osnma_msg_receiver_sptr osnma_msg_receiver_make(); - osnma_msg_receiver(); + friend osnma_msg_receiver_sptr osnma_msg_receiver_make(const std::string& pemFilePath); + osnma_msg_receiver(const std::string& pemFilePath); void msg_handler_osnma(const pmt::pmt_t& msg); void process_osnma_message(const std::shared_ptr& osnma_msg); @@ -69,13 +71,8 @@ private: void read_mack_key(); void read_mack_padding(); - std::vector computeSHA256(const std::vector& input); - std::vector computeSHA3_256(const std::vector& input); - std::vector computeHMAC_SHA_256(const std::vector& key, const std::vector& input); - std::vector computeCMAC_AES(const std::vector& key, const std::vector& input); - std::vector readPublicKeyFromPEM(const std::string& filePath); - std::unique_ptr d_dsm_reader; + std::unique_ptr d_crypto; std::array, 16> d_dsm_message{}; std::array, 16> d_dsm_id_received{}; diff --git a/src/core/receiver/gnss_flowgraph.cc b/src/core/receiver/gnss_flowgraph.cc index 4fde5eea3..7d17fa1b0 100644 --- a/src/core/receiver/gnss_flowgraph.cc +++ b/src/core/receiver/gnss_flowgraph.cc @@ -118,7 +118,9 @@ void GNSSFlowgraph::init() if (configuration_->property("Channels_1B.count", 0) > 0) { enable_osnma_rx_ = true; - osnma_rx_ = osnma_msg_receiver_make(); + const std::string pemfile_default("./OSNMA_PublicKey_20210920133026.pem"); + auto pemFilePath = configuration_->property("GNSS-SDR.OSNMA_pem", pemfile_default); + osnma_rx_ = osnma_msg_receiver_make(pemFilePath); } else { diff --git a/src/core/system_parameters/CMakeLists.txt b/src/core/system_parameters/CMakeLists.txt index 3f2e2a167..a39e45c6c 100644 --- a/src/core/system_parameters/CMakeLists.txt +++ b/src/core/system_parameters/CMakeLists.txt @@ -7,6 +7,7 @@ set(SYSTEM_PARAMETERS_SOURCES gnss_almanac.cc + gnss_crypto.cc gnss_ephemeris.cc gnss_satellite.cc gnss_signal.cc @@ -34,6 +35,7 @@ set(SYSTEM_PARAMETERS_SOURCES set(SYSTEM_PARAMETERS_HEADERS gnss_almanac.h + gnss_crypto.h gnss_ephemeris.h gnss_satellite.h gnss_signal.h @@ -130,6 +132,42 @@ target_include_directories(core_system_parameters ${GNSSSDR_SOURCE_DIR}/src/algorithms/libs ) +if(OPENSSL_FOUND) + if(TARGET OpenSSL::SSL) + target_link_libraries(core_system_parameters + PRIVATE + OpenSSL::SSL + ) + else() + target_link_libraries(core_system_parameters + PRIVATE + ${OPENSSL_LIBRARIES} + ) + target_include_directories(core_system_parameters + PRIVATE + ${OPENSSL_INCLUDE_DIR} + ) + endif() + if(OPENSSL_VERSION) + if(OPENSSL_VERSION VERSION_GREATER "3.0.0") + target_compile_definitions(core_system_parameters PRIVATE -DUSE_OPENSSL_3=1) + endif() + endif() +else() + target_link_libraries(core_system_parameters + PRIVATE + ${GNUTLS_LIBRARIES} + ${GNUTLS_OPENSSL_LIBRARY} + ) + target_include_directories(core_system_parameters + PRIVATE + ${GNUTLS_INCLUDE_DIR} + ) +endif() +if(OPENSSL_FOUND) + target_compile_definitions(core_system_parameters PRIVATE -DUSE_OPENSSL_FALLBACK=1) +endif() + if(ENABLE_CLANG_TIDY) if(CLANG_TIDY_EXE) set_target_properties(core_system_parameters diff --git a/src/core/system_parameters/gnss_crypto.cc b/src/core/system_parameters/gnss_crypto.cc new file mode 100644 index 000000000..7f65f081b --- /dev/null +++ b/src/core/system_parameters/gnss_crypto.cc @@ -0,0 +1,400 @@ +/*! + * \file gnss_crypto.cc + * \brief Class for computing cryptografic functions + * \author Carles Fernandez, 2023. cfernandez(at)cttc.es + * + * + * ----------------------------------------------------------------------------- + * + * GNSS-SDR is a Global Navigation Satellite System software-defined receiver. + * This file is part of GNSS-SDR. + * + * Copyright (C) 2010-2023 (see AUTHORS file for a list of contributors) + * SPDX-License-Identifier: GPL-3.0-or-later + * + * ----------------------------------------------------------------------------- + */ + +#include "gnss_crypto.h" +#include +#include +#include +#include + +#if USE_OPENSSL_FALLBACK +#include +#include +#include +#if USE_OPENSSL_3 +#include +#define OPENSSL_ENGINE NULL +#else +#include +#include +#endif +#else +#include +#include +#include +#endif + +Gnss_Crypto::Gnss_Crypto(const std::string& filePath) +{ + d_PublicKey = readPublicKeyFromPEM(filePath); +} + + +std::vector Gnss_Crypto::computeSHA256(const std::vector& input) +{ + std::vector output(32); // SHA256 hash size +#if USE_OPENSSL_FALLBACK +#if USE_OPENSSL_3 + unsigned int mdLen; + EVP_MD_CTX* mdCtx = EVP_MD_CTX_new(); + if (!EVP_DigestInit_ex(mdCtx, EVP_sha256(), OPENSSL_ENGINE)) + { + // LOG(WARNING) << "OSNMA SHA-256: Message digest initialization failed."; + EVP_MD_CTX_free(mdCtx); + return output; + } + if (!EVP_DigestUpdate(mdCtx, input.data(), input.size())) + { + // LOG(WARNING) << "OSNMA SHA-256: Message digest update failed."; + EVP_MD_CTX_free(mdCtx); + return output; + } + if (!EVP_DigestFinal_ex(mdCtx, output.data(), &mdLen)) + { + // LOG(WARNING) << "OSNMA SHA-256: Message digest finalization failed."; + EVP_MD_CTX_free(mdCtx); + return output; + } + EVP_MD_CTX_free(mdCtx); +#else + SHA256_CTX sha256Context; + SHA256_Init(&sha256Context); + SHA256_Update(&sha256Context, input.data(), input.size()); + SHA256_Final(output.data(), &sha256Context); +#endif +#else + std::vector output_aux(32); + gnutls_hash_hd_t hashHandle; + gnutls_hash_init(&hashHandle, GNUTLS_DIG_SHA256); + gnutls_hash(hashHandle, input.data(), input.size()); + gnutls_hash_output(hashHandle, output_aux.data()); + output = output_aux; + gnutls_hash_deinit(hashHandle, output_aux.data()); +#endif + return output; +} + + +std::vector Gnss_Crypto::computeSHA3_256(const std::vector& input) +{ + std::vector output(32); // SHA256 hash size +#if USE_OPENSSL_FALLBACK +#if USE_OPENSSL_3 + EVP_MD_CTX* mdctx = EVP_MD_CTX_new(); + const EVP_MD* md = EVP_sha3_256(); + + EVP_DigestInit_ex(mdctx, md, nullptr); + EVP_DigestUpdate(mdctx, input.data(), input.size()); + EVP_DigestFinal_ex(mdctx, output.data(), nullptr); + EVP_MD_CTX_free(mdctx); +#else + // SHA3-256 not implemented in OpenSSL < 3.0 +#endif +#else + std::vector output_aux(32); + gnutls_hash_hd_t hashHandle; + gnutls_hash_init(&hashHandle, GNUTLS_DIG_SHA3_256); + gnutls_hash(hashHandle, input.data(), input.size()); + gnutls_hash_output(hashHandle, output_aux.data()); + output = output_aux; + gnutls_hash_deinit(hashHandle, output_aux.data()); +#endif + return output; +} + + +std::vector Gnss_Crypto::computeHMAC_SHA_256(const std::vector& key, const std::vector& input) +{ + std::vector output(32); +#if USE_OPENSSL_FALLBACK +#if USE_OPENSSL_3 + std::vector hmac(EVP_MAX_MD_SIZE); + + // Create HMAC-SHA256 context + EVP_MD_CTX* ctx = EVP_MD_CTX_new(); + EVP_PKEY* pkey = EVP_PKEY_new_mac_key(EVP_PKEY_HMAC, nullptr, key.data(), key.size()); + + // Initialize HMAC-SHA256 context + EVP_DigestSignInit(ctx, nullptr, EVP_sha256(), nullptr, pkey); + + // Compute HMAC-SHA256 + EVP_DigestSignUpdate(ctx, input.data(), input.size()); + size_t macLength; + EVP_DigestSignFinal(ctx, hmac.data(), &macLength); + + EVP_PKEY_free(pkey); + EVP_MD_CTX_free(ctx); + + hmac.resize(macLength); + output = hmac; +#else + std::vector hmac(32); + // Create HMAC context + HMAC_CTX* ctx = HMAC_CTX_new(); + HMAC_Init_ex(ctx, key.data(), key.size(), EVP_sha256(), nullptr); + + // Update HMAC context with the message + HMAC_Update(ctx, input.data(), input.size()); + + // Finalize HMAC computation + unsigned int hmacLen; + HMAC_Final(ctx, hmac.data(), &hmacLen); + + // Clean up HMAC context + HMAC_CTX_free(ctx); + + // Resize the HMAC vector to the actual length + hmac.resize(hmacLen); + + output = hmac; +#endif +#else + std::vector output_aux(32); + gnutls_hmac_hd_t hmac; + gnutls_hmac_init(&hmac, GNUTLS_MAC_SHA256, key.data(), key.size()); + gnutls_hmac(hmac, input.data(), input.size()); + gnutls_hmac_output(hmac, output_aux.data()); + output = output_aux; + gnutls_hmac_deinit(hmac, output_aux.data()); + +#endif + return output; +} + + +std::vector Gnss_Crypto::computeCMAC_AES(const std::vector& key, const std::vector& input) +{ + std::vector output(16); +#if USE_OPENSSL_FALLBACK +#if USE_OPENSSL_3 + std::vector mac(EVP_MAX_MD_SIZE); // CMAC-AES output size + + EVP_CIPHER_CTX* ctx = EVP_CIPHER_CTX_new(); + EVP_MAC* cmac = EVP_MAC_fetch(NULL, "CMAC-AES", NULL); + + EVP_MAC_CTX* cmacCtx = EVP_MAC_CTX_new(cmac); + + OSSL_PARAM params[4]; + params[0] = OSSL_PARAM_construct_utf8_string("key", (char*)key.data(), key.size()); + params[1] = OSSL_PARAM_construct_octet_string("iv", NULL, 0); // Set IV to NULL + params[2] = OSSL_PARAM_construct_octet_string("aad", NULL, 0); // Set AAD to NULL + params[3] = OSSL_PARAM_construct_end(); + + // Set AES-128 CMAC cipher and key + EVP_MAC_init(cmacCtx, nullptr, 0, params); + + // Compute CMAC-AES + EVP_MAC_update(cmacCtx, input.data(), input.size()); + size_t macLength = mac.size(); + size_t outputLength = 16; + + EVP_MAC_final(cmacCtx, mac.data(), &macLength, outputLength); + + EVP_MAC_free(cmac); + EVP_MAC_CTX_free(cmacCtx); + EVP_CIPHER_CTX_free(ctx); + + mac.resize(macLength); + output = mac; +#else + std::vector mac(16); // CMAC-AES output size + + // Create CMAC context + CMAC_CTX* cmacCtx = CMAC_CTX_new(); + CMAC_Init(cmacCtx, key.data(), key.size(), EVP_aes_128_cbc(), nullptr); + + // Compute CMAC-AES + CMAC_Update(cmacCtx, input.data(), input.size()); + CMAC_Final(cmacCtx, mac.data(), nullptr); + + // Clean up CMAC context + CMAC_CTX_free(cmacCtx); + + output = mac; +#endif +#else + gnutls_cipher_hd_t cipher; + std::vector mac(16); + std::vector message = input; + gnutls_datum_t key_data = {const_cast(key.data()), static_cast(key.size())}; + gnutls_cipher_init(&cipher, GNUTLS_CIPHER_AES_128_CBC, &key_data, nullptr); + gnutls_cipher_set_iv(cipher, nullptr, 16); // Set IV to zero + gnutls_cipher_encrypt(cipher, message.data(), message.size()); // Encrypt the message with AES-128 + gnutls_cipher_tag(cipher, mac.data(), mac.size()); // Get the CMAC-AES tag + output = mac; + gnutls_cipher_deinit(cipher); +#endif + return output; +} + + +std::vector Gnss_Crypto::readPublicKeyFromPEM(const std::string& filePath) +{ + std::vector publicKey; + // Open the .pem file + std::ifstream pemFile(filePath); + if (!pemFile) + { + std::cerr << "Failed to open the file: " << filePath << std::endl; + return publicKey; + } +#if USE_OPENSSL_FALLBACK +#if USE_OPENSSL_3 + // Read the contents of the file into a string + std::string pemContent((std::istreambuf_iterator(pemFile)), std::istreambuf_iterator()); + + // Create a BIO object from the string data + BIO* bio = BIO_new_mem_buf(pemContent.c_str(), pemContent.length()); + if (!bio) + { + // Handle BIO creation error + pemFile.close(); + // ... + } + + // Read the PEM data from the BIO + EVP_PKEY* evpKey = PEM_read_bio_PUBKEY(bio, nullptr, nullptr, nullptr); + if (!evpKey) + { + // Handle PEM reading error + BIO_free(bio); + pemFile.close(); + // ... + } + + // Create a memory BIO to write the public key data + BIO* memBio = BIO_new(BIO_s_mem()); + if (!memBio) + { + // Handle memory BIO creation error + EVP_PKEY_free(evpKey); + BIO_free(bio); + pemFile.close(); + // ... + } + + // Write the public key to the memory BIO + int result = PEM_write_bio_PUBKEY(memBio, evpKey); + if (result != 1) + { + // Handle public key writing error + BIO_free(memBio); + EVP_PKEY_free(evpKey); + BIO_free(bio); + pemFile.close(); + // ... + } + + // Get the pointer to the memory BIO data and its length + char* bioData; + long bioDataLength = BIO_get_mem_data(memBio, &bioData); + + // Copy the public key data to the vector + publicKey.assign(bioData, bioData + bioDataLength); + + // Free resources + BIO_free(memBio); + EVP_PKEY_free(evpKey); + BIO_free(bio); + pemFile.close(); +#else + // Read the PEM file contents into a string + std::string pemContents((std::istreambuf_iterator(pemFile)), std::istreambuf_iterator()); + + // Create a BIO object to hold the PEM data + BIO* bio = BIO_new_mem_buf(pemContents.c_str(), -1); + + // Load the public key from the BIO + RSA* rsa = PEM_read_bio_RSA_PUBKEY(bio, nullptr, nullptr, nullptr); + BIO_free(bio); + + if (rsa == nullptr) + { + // Handle error reading public key + return {}; + } + + // Get the RSA modulus and convert it to a vector of uint8_t + const BIGNUM* rsaModulus = nullptr; + RSA_get0_key(rsa, &rsaModulus, nullptr, nullptr); + + BN_bn2bin(rsaModulus, publicKey.data()); + + // Clean up the RSA object + RSA_free(rsa); +#endif +#else + // Read the contents of the .pem file into a string + std::string pemContents((std::istreambuf_iterator(pemFile)), std::istreambuf_iterator()); + + gnutls_x509_crt_t cert; + gnutls_x509_crt_init(&cert); + + // Import the certificate from the PEM file + gnutls_datum_t pemData; + pemData.data = reinterpret_cast(const_cast(pemContents.data())); + pemData.size = pemContents.size(); + int ret = gnutls_x509_crt_import(cert, &pemData, GNUTLS_X509_FMT_PEM); + if (ret < 0) + { + std::cerr << "Failed to import certificate from PEM file" << std::endl; + gnutls_x509_crt_deinit(cert); + return publicKey; + } + + // Export the public key data + size_t pubkey_data_size = 0; + ret = gnutls_x509_crt_export(cert, GNUTLS_X509_FMT_DER, nullptr, &pubkey_data_size); + if (ret < 0) + { + std::cerr << "Failed to export public key data" << std::endl; + gnutls_x509_crt_deinit(cert); + return publicKey; + } + + publicKey.resize(pubkey_data_size); + ret = gnutls_x509_crt_export(cert, GNUTLS_X509_FMT_DER, publicKey.data(), &pubkey_data_size); + if (ret < 0) + { + std::cerr << "Failed to export public key data" << std::endl; + gnutls_x509_crt_deinit(cert); + return publicKey; + } + + gnutls_x509_crt_deinit(cert); +#endif + return publicKey; +} + + + +// // bool signature(const std::vector& publicKey, const std::vector& digest, std::vector& signature) +// // { +// // bool success = false; +// // #if USE_OPENSSL_FALLBACK +// // #else +// // gnutls_global_init(); +// // int result = gnutls_pubkey_verify_data(publicKey.data(), GNUTLS_SIGN_ECDSA_SHA256, digest.data, digest.size(), signature.data(), signature.size()); +// // success = (result == GNUTLS_E_SUCCESS); +// // gnutls_global_deinit(); +// // #endif +// // return success; +// // } +// // bool verifyDigitalSignature(const unsigned char* signature, size_t signatureSize, const unsigned char* message, size_t messageSize, gnutls_pubkey_t publicKey) +// // { +// // int verificationStatus = gnutls_pubkey_verify_data(publicKey, GNUTLS_DIG_SHA256, 0, message, messageSize, signature, signatureSize); +// // return verificationStatus == 0; diff --git a/src/core/system_parameters/gnss_crypto.h b/src/core/system_parameters/gnss_crypto.h new file mode 100644 index 000000000..5dc20f4c3 --- /dev/null +++ b/src/core/system_parameters/gnss_crypto.h @@ -0,0 +1,49 @@ +/*! + * \file gnss_crypto.h + * \brief Class for computing cryptografic functions + * \author Carles Fernandez, 2023. cfernandez(at)cttc.es + * + * + * ----------------------------------------------------------------------------- + * + * GNSS-SDR is a Global Navigation Satellite System software-defined receiver. + * This file is part of GNSS-SDR. + * + * Copyright (C) 2010-2023 (see AUTHORS file for a list of contributors) + * SPDX-License-Identifier: GPL-3.0-or-later + * + * ----------------------------------------------------------------------------- + */ + +#ifndef GNSS_SDR_GNSS_CRYPTO_H +#define GNSS_SDR_GNSS_CRYPTO_H + +#include +#include +#include + + +/** \addtogroup Core + * \{ */ +/** \addtogroup System_Parameters + * \{ */ + + +class Gnss_Crypto +{ +public: + Gnss_Crypto() = default; + Gnss_Crypto(const std::string& filePath); + std::vector computeSHA256(const std::vector& input); + std::vector computeSHA3_256(const std::vector& input); + std::vector computeHMAC_SHA_256(const std::vector& key, const std::vector& input); + std::vector computeCMAC_AES(const std::vector& key, const std::vector& input); + std::vector readPublicKeyFromPEM(const std::string& filePath); + +private: + std::vector d_PublicKey; +}; + +/** \} */ +/** \} */ +#endif // GNSS_SDR_GNSS_CRYPTO_H \ No newline at end of file