diff --git a/executables/benchmark.cpp b/executables/benchmark.cpp index 73898150..d679afb1 100644 --- a/executables/benchmark.cpp +++ b/executables/benchmark.cpp @@ -98,9 +98,9 @@ void benchmark_fec_encode(const Options &options, bool printBlockTime = false) { void benchmark_crypt(const Options &options,const bool packet_validation_only) { assert(options.benchmarkType == BENCHMARK_ENCRYPT || options.benchmarkType == BENCHMARK_DECRYPT); const bool encrypt=options.benchmarkType==BENCHMARK_ENCRYPT; - Encryptor encryptor{std::nullopt}; + wb::Encryptor encryptor{wb::generate_keypair_deterministic(true)}; encryptor.set_encryption_enabled(!packet_validation_only); - Decryptor decryptor{std::nullopt}; + wb::Decryptor decryptor{wb::generate_keypair_deterministic(true)}; decryptor.set_encryption_enabled(!packet_validation_only); std::array sessionKeyNonce{}; std::array sessionKeyData{}; diff --git a/executables/unit_test.cpp b/executables/unit_test.cpp index a8fb024c..e88579fa 100644 --- a/executables/unit_test.cpp +++ b/executables/unit_test.cpp @@ -114,17 +114,27 @@ static void test_encrypt_decrypt_validate(const bool useGeneratedFiles,bool mess //const std::string filename_drone="drone.key"; const std::string filename_gs="../example_keys/gs.key"; const std::string filename_drone="../example_keys/drone.key"; - std::optional encKey = useGeneratedFiles ? std::optional(filename_gs) : std::nullopt; - std::optional decKey = useGeneratedFiles ? std::optional(filename_drone) : std::nullopt; + wb::Keypair encKey{}; + wb::Keypair decKey{}; + if(useGeneratedFiles){ + encKey=wb::read_keypair_from_file(filename_gs); + decKey=wb::read_keypair_from_file(filename_drone); + }else{ + /*encKey=wb::generate_keypair_deterministic(false); + decKey=wb::generate_keypair_deterministic(false);*/ + auto tmp=wb::generate_keypair_from_bind_phrase("openhd"); + encKey=tmp.drone; + decKey=tmp.drone; + } if(message_signing_only){ std::cout<<"Testing message signing\n"; }else{ std::cout<<"Testing encryption & signing\n"; } - Encryptor encryptor{encKey}; + wb::Encryptor encryptor{encKey}; encryptor.set_encryption_enabled(!message_signing_only); - Decryptor decryptor{decKey}; + wb::Decryptor decryptor{decKey}; decryptor.set_encryption_enabled(!message_signing_only); struct SessionStuff{ std::array sessionKeyNonce{}; // random data @@ -135,7 +145,7 @@ static void test_encrypt_decrypt_validate(const bool useGeneratedFiles,bool mess encryptor.makeNewSessionKey(sessionKeyPacket.sessionKeyNonce, sessionKeyPacket.sessionKeyData); // and "receive" session key (rx) assert(decryptor.onNewPacketSessionKeyData(sessionKeyPacket.sessionKeyNonce, sessionKeyPacket.sessionKeyData) - == Decryptor::SESSION_VALID_NEW); + == wb::Decryptor::SESSION_VALID_NEW); // now encrypt a couple of packets and decrypt them again afterwards for (uint64_t nonce = 0; nonce < 200; nonce++) { const auto data = GenericHelper::createRandomDataBuffer(FEC_PACKET_MAX_PAYLOAD_SIZE); diff --git a/src/Encryption.hpp b/src/Encryption.hpp index d829cf73..144b69d1 100644 --- a/src/Encryption.hpp +++ b/src/Encryption.hpp @@ -27,6 +27,97 @@ static_assert(crypto_onetimeauth_BYTES==crypto_aead_chacha20poly1305_ABYTES); // Encryption (or packet validation) adds this many bytes to the end of the message static constexpr auto ENCRYPTION_ADDITIONAL_VALIDATION_DATA=crypto_aead_chacha20poly1305_ABYTES; +namespace wb{ + +struct Keypair{ + std::array public_key; + std::array secret_key; +}; + +struct KeypairData{ + // NOTE: The key itself for drone exists of drone.secret and ground.public + Keypair drone; + Keypair ground; +}; + +// Generates a new keypair. Non-deterministic, 100% secure. +static KeypairData generate_keypair(){ + KeypairData ret{}; + crypto_box_keypair(ret.drone.public_key.data(), ret.drone.secret_key.data()); + crypto_box_keypair(ret.ground.public_key.data(), ret.ground.secret_key.data()); + return ret; +} +static Keypair generate_keypair_deterministic(bool is_air){ + Keypair ret{}; + std::array seed1{0}; + std::array seed2{1}; + crypto_box_seed_keypair(ret.public_key.data(), ret.secret_key.data(),is_air ? seed1.data(): seed2.data()); + return ret; +} + +/** + * Generates a deterministic keypair from the openhd bind_phrase. Deterministic, + * same bind phrase will always generate the same key-pairs (but reversing is hard) + */ +static KeypairData generate_keypair_from_bind_phrase(const std::string& bind_phrase=""){ + // Simple default seed, different for air and ground + std::array seed_ground{0}; + std::array seed_drone{UINT8_MAX}; + assert(bind_phrase.length()<=seed_ground.size()); + // We just use the bind-phrase as seed + memcpy(seed_ground.data(),bind_phrase.c_str(),bind_phrase.length()); + memcpy(seed_drone.data(),bind_phrase.c_str(),bind_phrase.length()); + KeypairData ret{}; + crypto_box_seed_keypair(ret.drone.public_key.data(), ret.drone.secret_key.data(),seed_drone.data()); + crypto_box_seed_keypair(ret.ground.public_key.data(), ret.ground.secret_key.data(),seed_ground.data()); + return ret; +} + +static int write_keypair_to_file(const Keypair& keypair,const std::string& filename){ + FILE *fp; + if ((fp = fopen(filename.c_str(), "w")) == nullptr) { + std::cerr<<"Unable to save "< create_onetimeauth_subkey(const uint64_t nonce,const std::array session_key){ @@ -46,26 +137,9 @@ class Encryptor { * @param keypair encryption key, otherwise enable a default deterministic encryption key by using std::nullopt * @param DISABLE_ENCRYPTION_FOR_PERFORMANCE only validate, do not encrypt (less CPU usage) */ - explicit Encryptor(std::optional keypair){ - if (keypair == std::nullopt) { - // use default encryption keys - crypto_box_seed_keypair(rx_publickey.data(), tx_secretkey.data(), DEFAULT_ENCRYPTION_SEED.data()); - wifibroadcast::log::get_default()->debug("Using default keys"); - } else { - FILE *fp; - if ((fp = fopen(keypair->c_str(), "r")) == nullptr) { - throw std::runtime_error(fmt::format("Unable to open {}: {}", keypair->c_str(), strerror(errno))); - } - if (fread(tx_secretkey.data(), crypto_box_SECRETKEYBYTES, 1, fp) != 1) { - fclose(fp); - throw std::runtime_error(fmt::format("Unable to read tx secret key: {}", strerror(errno))); - } - if (fread(rx_publickey.data(), crypto_box_PUBLICKEYBYTES, 1, fp) != 1) { - fclose(fp); - throw std::runtime_error(fmt::format("Unable to read rx public key: {}", strerror(errno))); - } - fclose(fp); - } + explicit Encryptor(wb::Keypair keypair) + : tx_secretkey(keypair.secret_key), + rx_publickey(keypair.public_key){ } /** * Creates a new session key, simply put, the data we can send publicly @@ -95,7 +169,7 @@ class Encryptor { if(!m_encrypt_data){ memcpy(dest,src, src_len); uint8_t* sign=dest+src_len; - const auto sub_key=create_onetimeauth_subkey(nonce,session_key); + const auto sub_key=wb::create_onetimeauth_subkey(nonce,session_key); crypto_onetimeauth(sign,src,src_len,sub_key.data()); return src_len+crypto_onetimeauth_BYTES; } @@ -123,8 +197,8 @@ class Encryptor { } private: // tx->rx keypair - std::array tx_secretkey{}; - std::array rx_publickey{}; + const std::array tx_secretkey{}; + const std::array rx_publickey{}; std::array session_key{}; // use this one if you are worried about CPU usage when using encryption bool m_encrypt_data= true; @@ -134,34 +208,15 @@ class Decryptor { public: // enable a default deterministic encryption key by using std::nullopt // else, pass path to file with encryption keys - explicit Decryptor(std::optional keypair){ - if (keypair == std::nullopt) { - crypto_box_seed_keypair(tx_publickey.data(), rx_secretkey.data(), DEFAULT_ENCRYPTION_SEED.data()); - wifibroadcast::log::get_default()->debug("Using default keys"); - } else { - FILE *fp; - if ((fp = fopen(keypair->c_str(), "r")) == nullptr) { - throw std::runtime_error(fmt::format("Unable to open {}: {}", keypair->c_str(), strerror(errno))); - } - if (fread(rx_secretkey.data(), crypto_box_SECRETKEYBYTES, 1, fp) != 1) { - fclose(fp); - throw std::runtime_error(fmt::format("Unable to read rx secret key: {}", strerror(errno))); - } - if (fread(tx_publickey.data(), crypto_box_PUBLICKEYBYTES, 1, fp) != 1) { - fclose(fp); - throw std::runtime_error(fmt::format("Unable to read tx public key: {}", strerror(errno))); - } - fclose(fp); - } + explicit Decryptor(wb::Keypair keypair) + :rx_secretkey(keypair.secret_key),tx_publickey(keypair.public_key){ memset(session_key.data(), 0, sizeof(session_key)); } private: // use this one if you are worried about CPU usage when using encryption bool m_encrypt_data= true; - public: - std::array rx_secretkey{}; - public: - std::array tx_publickey{}; + const std::array rx_secretkey{}; + const std::array tx_publickey{}; std::array session_key{}; public: static constexpr auto SESSION_VALID_NEW=0; @@ -174,7 +229,7 @@ class Decryptor { * */ int onNewPacketSessionKeyData(const std::array &sessionKeyNonce, - const std::array &sessionKeyData) { + const std::array &sessionKeyData) { std::array new_session_key{}; if (crypto_box_open_easy(new_session_key.data(), sessionKeyData.data(), sessionKeyData.size(), @@ -204,7 +259,7 @@ class Decryptor { assert(payload_size>0); const uint8_t* sign=encrypted+payload_size; //const int res=crypto_auth_hmacsha256_verify(sign,msg,payload_size,session_key.data()); - const auto sub_key=create_onetimeauth_subkey(nonce,session_key); + const auto sub_key=wb::create_onetimeauth_subkey(nonce,session_key); const int res=crypto_onetimeauth_verify(sign,encrypted,payload_size,sub_key.data()); if(res!=-1){ memcpy(dest,encrypted,payload_size); @@ -244,46 +299,7 @@ class Decryptor { } }; -namespace wbencryption{ - -struct KeypairData{ - unsigned char drone_publickey[crypto_box_PUBLICKEYBYTES]; - unsigned char drone_secretkey[crypto_box_SECRETKEYBYTES]; - unsigned char gs_publickey[crypto_box_PUBLICKEYBYTES]; - unsigned char gs_secretkey[crypto_box_SECRETKEYBYTES]; -}; - -static KeypairData generate_keypair(){ - KeypairData ret{}; - crypto_box_keypair(ret.drone_publickey, ret.drone_secretkey); - crypto_box_keypair(ret.gs_publickey, ret.gs_secretkey); - return ret; -} - -static int write_to_file(const KeypairData& data){ - FILE *fp; - if ((fp = fopen("drone.key", "w")) == NULL) { - perror("Unable to save drone.key"); - return 1; - } - fwrite(data.drone_secretkey, crypto_box_SECRETKEYBYTES, 1, fp); - fwrite(data.gs_publickey, crypto_box_PUBLICKEYBYTES, 1, fp); - fclose(fp); - - fprintf(stderr, "Drone keypair (drone sec + gs pub) saved to drone.key\n"); - - if ((fp = fopen("gs.key", "w")) == NULL) { - perror("Unable to save gs.key"); - return 1; - } - - fwrite(data.gs_secretkey, crypto_box_SECRETKEYBYTES, 1, fp); - fwrite(data.drone_publickey, crypto_box_PUBLICKEYBYTES, 1, fp); - fclose(fp); - fprintf(stderr, "GS keypair (gs sec + drone pub) saved to gs.key\n"); - return 0; -} +} // namespace wb end -} #endif //ENCRYPTION_HPP \ No newline at end of file diff --git a/src/WBTxRx.cpp b/src/WBTxRx.cpp index f9f713d0..9645729f 100644 --- a/src/WBTxRx.cpp +++ b/src/WBTxRx.cpp @@ -54,8 +54,14 @@ WBTxRx::WBTxRx(std::vector wifi_cards1,Options options1) m_receive_pollfds[i].fd = fd; m_receive_pollfds[i].events = POLLIN; } - m_encryptor=std::make_unique(m_options.encryption_key); - m_decryptor=std::make_unique(m_options.encryption_key); + wb::Keypair keypair{}; + if(m_options.encryption_key.has_value()){ + keypair= wb::read_keypair_from_file(m_options.encryption_key.value()); + }else{ + keypair=wb::generate_keypair_deterministic(true); + } + //m_encryptor=std::make_unique(m_options.encryption_key); + //m_decryptor=std::make_unique(m_options.encryption_key); m_encryptor->makeNewSessionKey(m_tx_sess_key_packet.sessionKeyNonce,m_tx_sess_key_packet.sessionKeyData); // next session key in delta ms if packets are being fed m_session_key_next_announce_ts = std::chrono::steady_clock::now(); @@ -376,11 +382,11 @@ void WBTxRx::on_new_packet(const uint8_t wlan_idx, const pcap_pkthdr &hdr, }*/ SessionKeyPacket &sessionKeyPacket = *((SessionKeyPacket*) parsedPacket->payload); const auto decrypt_res=m_decryptor->onNewPacketSessionKeyData(sessionKeyPacket.sessionKeyNonce, sessionKeyPacket.sessionKeyData); - if(wlan_idx==0 && (decrypt_res==Decryptor::SESSION_VALID_NEW || decrypt_res==Decryptor::SESSION_VALID_NOT_NEW)){ + if(wlan_idx==0 && (decrypt_res==wb::Decryptor::SESSION_VALID_NEW || decrypt_res==wb::Decryptor::SESSION_VALID_NOT_NEW)){ m_pollution_openhd_rx_packets++; recalculate_pollution_perc(); } - if (decrypt_res==Decryptor::SESSION_VALID_NEW) { + if (decrypt_res==wb::Decryptor::SESSION_VALID_NEW) { m_console->debug("Initializing new session."); m_rx_stats.n_received_valid_session_key_packets++; for(auto& handler:m_rx_handlers){ diff --git a/src/WBTxRx.h b/src/WBTxRx.h index 60843f57..499e4faa 100644 --- a/src/WBTxRx.h +++ b/src/WBTxRx.h @@ -283,8 +283,8 @@ class WBTxRx { // For multiple RX cards the card with the highest rx rssi is used to inject packets on std::atomic m_curr_tx_card=0; SessionKeyPacket m_tx_sess_key_packet; - std::unique_ptr m_encryptor; - std::unique_ptr m_decryptor; + std::unique_ptr m_encryptor; + std::unique_ptr m_decryptor; struct PcapTxRx{ pcap_t *tx= nullptr; pcap_t *rx= nullptr;