diff --git a/native/cpp/CommonCpp/CryptoTools/CryptoModule.h b/native/cpp/CommonCpp/CryptoTools/CryptoModule.h --- a/native/cpp/CommonCpp/CryptoTools/CryptoModule.h +++ b/native/cpp/CommonCpp/CryptoTools/CryptoModule.h @@ -40,6 +40,14 @@ std::string getIdentityKeys(); std::string getOneTimeKeys(size_t oneTimeKeysAmount = 50); + // Prekey rotation methods for X3DH + std::uint8_t getNumPrekeys(); + std::string getPrekey(); + std::string getUnpublishedPrekey(); + std::string generateAndGetPrekey(); + void markPrekeyAsPublished(); + void forgetOldPrekey(); + void initializeInboundForReceivingSession( const std::string &targetUserId, const OlmBuffer &encryptedMessage, diff --git a/native/cpp/CommonCpp/CryptoTools/CryptoModule.cpp b/native/cpp/CommonCpp/CryptoTools/CryptoModule.cpp --- a/native/cpp/CommonCpp/CryptoTools/CryptoModule.cpp +++ b/native/cpp/CommonCpp/CryptoTools/CryptoModule.cpp @@ -1,5 +1,6 @@ #include "CryptoModule.h" #include "PlatformSpecificTools.h" +#include "olm/account.hh" #include "olm/session.hh" #include @@ -115,6 +116,89 @@ this->keys.oneTimeKeys.begin(), this->keys.oneTimeKeys.end()}; } +std::uint8_t CryptoModule::getNumPrekeys() { + return reinterpret_cast(this->account)->num_prekeys; +} + +std::string CryptoModule::getPrekey() { + if (this->getNumPrekeys() == 0) { + throw std::runtime_error{ + "error getPrekey => No prekey has been generated yet."}; + } + + OlmBuffer prekey; + prekey.resize(::olm_account_prekey_length(this->account)); + + if (-1 == ::olm_account_prekey(this->account, prekey.data(), prekey.size())) { + throw std::runtime_error{ + "error getPrekey => " + + std::string{::olm_account_last_error(this->account)}}; + } + + return std::string{prekey.begin(), prekey.end()}; +} + +std::string CryptoModule::getUnpublishedPrekey() { + if (this->getNumPrekeys() == 0) { + throw std::runtime_error{ + "error getPrekey => No prekey has been generated yet."}; + } + + OlmBuffer prekey; + prekey.resize(::olm_account_prekey_length(this->account)); + + std::size_t retval = ::olm_account_unpublished_prekey( + this->account, prekey.data(), prekey.size()); + + if (-1 == retval && + ::olm_account_last_error_code(this->account) != + OlmErrorCode::OLM_SUCCESS) { + throw std::runtime_error{ + "error getUnpublishedPrekey => " + + std::string{::olm_account_last_error(this->account)}}; + } else if (-1 == retval) { + throw std::runtime_error{ + "error getUnpublishedPrekey => All prekeys have been published."}; + } + + return std::string{prekey.begin(), prekey.end()}; +} + +std::string CryptoModule::generateAndGetPrekey() { + size_t prekeySize = + ::olm_account_generate_prekey_random_length(this->account); + + OlmBuffer random; + PlatformSpecificTools::generateSecureRandomBytes(random, prekeySize); + + if (-1 == + ::olm_account_generate_prekey( + this->account, random.data(), random.size())) { + throw std::runtime_error{ + "error generateAndGetPrekey => " + + std::string{::olm_account_last_error(this->account)}}; + } + + OlmBuffer prekey; + prekey.resize(::olm_account_prekey_length(this->account)); + + if (-1 == ::olm_account_prekey(this->account, prekey.data(), prekey.size())) { + throw std::runtime_error{ + "error generateAndGetPrekey => " + + std::string{::olm_account_last_error(this->account)}}; + } + + return std::string{prekey.begin(), prekey.end()}; +} + +void CryptoModule::markPrekeyAsPublished() { + ::olm_account_mark_prekey_as_published(this->account); +} + +void CryptoModule::forgetOldPrekey() { + ::olm_account_forget_old_prekey(this->account); +} + void CryptoModule::initializeInboundForReceivingSession( const std::string &targetUserId, const OlmBuffer &encryptedMessage,