mirror of
https://github.com/gnss-sdr/gnss-sdr
synced 2025-01-18 21:23:02 +00:00
Introducing the crypto bro
This commit is contained in:
parent
d351049eb2
commit
972ead3cae
@ -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()
|
||||
|
@ -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 <glog/logging.h> // for DLOG
|
||||
#include <gnuradio/io_signature.h> // for gr::io_signature::make
|
||||
#include <bitset>
|
||||
#include <cmath>
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
#include <iterator>
|
||||
#include <numeric>
|
||||
#include <string>
|
||||
#include <typeinfo> // for typeid
|
||||
|
||||
#if HAS_GENERIC_LAMBDA
|
||||
@ -46,33 +43,21 @@ namespace wht = boost;
|
||||
namespace wht = std;
|
||||
#endif
|
||||
|
||||
#if USE_OPENSSL_FALLBACK
|
||||
#include <openssl/cmac.h>
|
||||
#include <openssl/hmac.h>
|
||||
#if USE_OPENSSL_3
|
||||
#include <openssl/evp.h>
|
||||
#define OPENSSL_ENGINE NULL
|
||||
#else
|
||||
#include <openssl/sha.h>
|
||||
#endif
|
||||
#else
|
||||
#include <gnutls/crypto.h>
|
||||
#include <gnutls/gnutls.h>
|
||||
#include <gnutls/x509.h>
|
||||
#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<OSNMA_DSM_Reader>();
|
||||
// register OSNMA input message port from telemetry blocks
|
||||
d_crypto = std::make_unique<Gnss_Crypto>(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<uint8_t>& dsm_msg
|
||||
std::vector<uint8_t> 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<uint8_t> osnma_msg_receiver::computeSHA256(const std::vector<uint8_t>& input)
|
||||
{
|
||||
std::vector<uint8_t> 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<uint8_t> 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<uint8_t> osnma_msg_receiver::computeSHA3_256(const std::vector<uint8_t>& input)
|
||||
{
|
||||
std::vector<uint8_t> 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<uint8_t> 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<uint8_t> osnma_msg_receiver::computeHMAC_SHA_256(const std::vector<uint8_t>& key, const std::vector<uint8_t>& input)
|
||||
{
|
||||
std::vector<uint8_t> output(32);
|
||||
#if USE_OPENSSL_FALLBACK
|
||||
#if USE_OPENSSL_3
|
||||
std::vector<uint8_t> 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<uint8_t> 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<uint8_t> 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<uint8_t> osnma_msg_receiver::computeCMAC_AES(const std::vector<uint8_t>& key, const std::vector<uint8_t>& input)
|
||||
{
|
||||
std::vector<uint8_t> output(16);
|
||||
#if USE_OPENSSL_FALLBACK
|
||||
#if USE_OPENSSL_3
|
||||
std::vector<uint8_t> 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<uint8_t> 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<uint8_t> mac(16);
|
||||
std::vector<uint8_t> message = input;
|
||||
gnutls_datum_t key_data = {const_cast<uint8_t*>(key.data()), static_cast<unsigned int>(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<uint8_t>& publicKey, const std::vector<uint8_t>& digest, std::vector<uint8_t>& 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<uint8_t> osnma_msg_receiver::readPublicKeyFromPEM(const std::string& filePath)
|
||||
{
|
||||
std::vector<uint8_t> 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<char>(file)), std::istreambuf_iterator<char>());
|
||||
|
||||
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<unsigned char*>(const_cast<char*>(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;
|
||||
}
|
@ -27,6 +27,7 @@
|
||||
#include <pmt/pmt.h> // for pmt::pmt_t
|
||||
#include <array> // for std::array
|
||||
#include <memory> // for std::shared_ptr
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
/** \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>;
|
||||
|
||||
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>& osnma_msg);
|
||||
@ -69,13 +71,8 @@ private:
|
||||
void read_mack_key();
|
||||
void read_mack_padding();
|
||||
|
||||
std::vector<uint8_t> computeSHA256(const std::vector<uint8_t>& input);
|
||||
std::vector<uint8_t> computeSHA3_256(const std::vector<uint8_t>& input);
|
||||
std::vector<uint8_t> computeHMAC_SHA_256(const std::vector<uint8_t>& key, const std::vector<uint8_t>& input);
|
||||
std::vector<uint8_t> computeCMAC_AES(const std::vector<uint8_t>& key, const std::vector<uint8_t>& input);
|
||||
std::vector<uint8_t> readPublicKeyFromPEM(const std::string& filePath);
|
||||
|
||||
std::unique_ptr<OSNMA_DSM_Reader> d_dsm_reader;
|
||||
std::unique_ptr<Gnss_Crypto> d_crypto;
|
||||
|
||||
std::array<std::array<uint8_t, 256>, 16> d_dsm_message{};
|
||||
std::array<std::array<uint8_t, 16>, 16> d_dsm_id_received{};
|
||||
|
@ -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
|
||||
{
|
||||
|
@ -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
|
||||
|
400
src/core/system_parameters/gnss_crypto.cc
Normal file
400
src/core/system_parameters/gnss_crypto.cc
Normal file
@ -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 <cstddef>
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
#include <iterator>
|
||||
|
||||
#if USE_OPENSSL_FALLBACK
|
||||
#include <openssl/cmac.h>
|
||||
#include <openssl/hmac.h>
|
||||
#include <openssl/pem.h>
|
||||
#if USE_OPENSSL_3
|
||||
#include <openssl/evp.h>
|
||||
#define OPENSSL_ENGINE NULL
|
||||
#else
|
||||
#include <openssl/rsa.h>
|
||||
#include <openssl/sha.h>
|
||||
#endif
|
||||
#else
|
||||
#include <gnutls/crypto.h>
|
||||
#include <gnutls/gnutls.h>
|
||||
#include <gnutls/x509.h>
|
||||
#endif
|
||||
|
||||
Gnss_Crypto::Gnss_Crypto(const std::string& filePath)
|
||||
{
|
||||
d_PublicKey = readPublicKeyFromPEM(filePath);
|
||||
}
|
||||
|
||||
|
||||
std::vector<uint8_t> Gnss_Crypto::computeSHA256(const std::vector<uint8_t>& input)
|
||||
{
|
||||
std::vector<uint8_t> 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<uint8_t> 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<uint8_t> Gnss_Crypto::computeSHA3_256(const std::vector<uint8_t>& input)
|
||||
{
|
||||
std::vector<uint8_t> 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<uint8_t> 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<uint8_t> Gnss_Crypto::computeHMAC_SHA_256(const std::vector<uint8_t>& key, const std::vector<uint8_t>& input)
|
||||
{
|
||||
std::vector<uint8_t> output(32);
|
||||
#if USE_OPENSSL_FALLBACK
|
||||
#if USE_OPENSSL_3
|
||||
std::vector<uint8_t> 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<uint8_t> 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<uint8_t> 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<uint8_t> Gnss_Crypto::computeCMAC_AES(const std::vector<uint8_t>& key, const std::vector<uint8_t>& input)
|
||||
{
|
||||
std::vector<uint8_t> output(16);
|
||||
#if USE_OPENSSL_FALLBACK
|
||||
#if USE_OPENSSL_3
|
||||
std::vector<uint8_t> 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<uint8_t> 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<uint8_t> mac(16);
|
||||
std::vector<uint8_t> message = input;
|
||||
gnutls_datum_t key_data = {const_cast<uint8_t*>(key.data()), static_cast<unsigned int>(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<uint8_t> Gnss_Crypto::readPublicKeyFromPEM(const std::string& filePath)
|
||||
{
|
||||
std::vector<uint8_t> 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<char>(pemFile)), std::istreambuf_iterator<char>());
|
||||
|
||||
// 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<char>(pemFile)), std::istreambuf_iterator<char>());
|
||||
|
||||
// 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<char>(pemFile)), std::istreambuf_iterator<char>());
|
||||
|
||||
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<unsigned char*>(const_cast<char*>(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<uint8_t>& publicKey, const std::vector<uint8_t>& digest, std::vector<uint8_t>& 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;
|
49
src/core/system_parameters/gnss_crypto.h
Normal file
49
src/core/system_parameters/gnss_crypto.h
Normal file
@ -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 <cstdint>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
|
||||
/** \addtogroup Core
|
||||
* \{ */
|
||||
/** \addtogroup System_Parameters
|
||||
* \{ */
|
||||
|
||||
|
||||
class Gnss_Crypto
|
||||
{
|
||||
public:
|
||||
Gnss_Crypto() = default;
|
||||
Gnss_Crypto(const std::string& filePath);
|
||||
std::vector<uint8_t> computeSHA256(const std::vector<uint8_t>& input);
|
||||
std::vector<uint8_t> computeSHA3_256(const std::vector<uint8_t>& input);
|
||||
std::vector<uint8_t> computeHMAC_SHA_256(const std::vector<uint8_t>& key, const std::vector<uint8_t>& input);
|
||||
std::vector<uint8_t> computeCMAC_AES(const std::vector<uint8_t>& key, const std::vector<uint8_t>& input);
|
||||
std::vector<uint8_t> readPublicKeyFromPEM(const std::string& filePath);
|
||||
|
||||
private:
|
||||
std::vector<uint8_t> d_PublicKey;
|
||||
};
|
||||
|
||||
/** \} */
|
||||
/** \} */
|
||||
#endif // GNSS_SDR_GNSS_CRYPTO_H
|
Loading…
Reference in New Issue
Block a user