diff --git a/native/cpp/CommonCpp/CryptoTools/CryptoModule.cpp b/native/cpp/CommonCpp/CryptoTools/CryptoModule.cpp index 2ed7bfa80d..7c9ba9b164 100644 --- a/native/cpp/CommonCpp/CryptoTools/CryptoModule.cpp +++ b/native/cpp/CommonCpp/CryptoTools/CryptoModule.cpp @@ -121,6 +121,24 @@ bool CryptoModule::prekeyExistsAndOlderThan(uint64_t threshold) { return currentTime - lastPrekeyPublishTime >= threshold; } +bool CryptoModule::prekeyDoesntExist() { + // Prekey generation when creating an Olm Account was added to clients + // after the initial launch of Olm. Because of that, there is a high + // chance there are users who have the account without a generated prekey. + + // When prekey or signature is empty it contains bytes with only 0 values. + // Because of Base64 encoding, 0 is encoded as char `A` and empty + // prekey/signature is a string built from only `A`'s. + const std::string emptyPrekey(KEYSIZE, 'A'); + const std::string emptySignature(SIGNATURESIZE, 'A'); + + std::string prekey = this->getPrekey(); + std::string signature = this->getPrekeySignature(); + + return prekey.find(emptyPrekey) != std::string::npos || + signature == emptySignature; +} + Keys CryptoModule::keysFromStrings( const std::string &identityKeys, const std::string &oneTimeKeys) { @@ -455,6 +473,11 @@ std::optional CryptoModule::validatePrekey() { static const uint64_t maxOldPrekeyAge = 2 * 60; std::optional maybeNewPrekey; + bool prekeyDoesntExist = this->prekeyDoesntExist(); + if (prekeyDoesntExist) { + return this->generateAndGetPrekey(); + } + bool shouldRotatePrekey = this->prekeyExistsAndOlderThan(maxPrekeyPublishTime); if (shouldRotatePrekey) { diff --git a/native/cpp/CommonCpp/CryptoTools/CryptoModule.h b/native/cpp/CommonCpp/CryptoTools/CryptoModule.h index b6066afd4c..2b61f448c4 100644 --- a/native/cpp/CommonCpp/CryptoTools/CryptoModule.h +++ b/native/cpp/CommonCpp/CryptoTools/CryptoModule.h @@ -29,6 +29,7 @@ class CryptoModule { // returns number of published keys size_t publishOneTimeKeys(); bool prekeyExistsAndOlderThan(uint64_t threshold); + bool prekeyDoesntExist(); OlmBuffer pickleAccount(const std::string &secretKey); public: