Page MenuHomePhorge

D15550.1765004424.diff
No OneTemporary

Size
65 KB
Referenced Files
None
Subscribers
None

D15550.1765004424.diff

diff --git a/lib/shared/crypto-utils.js b/lib/shared/crypto-utils.js
--- a/lib/shared/crypto-utils.js
+++ b/lib/shared/crypto-utils.js
@@ -110,7 +110,6 @@
}
export {
- getOneTimeKeyValues,
getOneTimeKeyValuesFromBlob,
getPrekeyValueFromBlob,
initialEncryptedMessageContent,
diff --git a/lib/types/crypto-types.js b/lib/types/crypto-types.js
--- a/lib/types/crypto-types.js
+++ b/lib/types/crypto-types.js
@@ -42,11 +42,6 @@
+curve25519: { +[string]: string },
};
-export type OneTimeKeysResult = {
- +contentOneTimeKeys: OLMOneTimeKeys,
- +notificationsOneTimeKeys: OLMOneTimeKeys,
-};
-
export type OneTimeKeysResultValues = {
+contentOneTimeKeys: $ReadOnlyArray<string>,
+notificationsOneTimeKeys: $ReadOnlyArray<string>,
diff --git a/native/android/app/CMakeLists.txt b/native/android/app/CMakeLists.txt
--- a/native/android/app/CMakeLists.txt
+++ b/native/android/app/CMakeLists.txt
@@ -171,6 +171,10 @@
${RUST_NATIVE_CODE}
)
+# Ensure Rust cxxbridge headers are generated before compiling C++ code
+# Make package depend on both the Rust static library and cxxbridge target
+add_dependencies(${PACKAGE_NAME} native_rust_library-static native_rust_library_cxxbridge)
+
set(BUILD_DIR ${CMAKE_SOURCE_DIR}/build)
target_include_directories(
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
@@ -4,8 +4,6 @@
#include <string>
#include <unordered_map>
-#include "olm/olm.h"
-
#include "Persist.h"
#include "Session.h"
#include "Tools.h"
@@ -21,14 +19,12 @@
class CryptoModule {
- OlmBuffer accountBuffer;
+ ::rust::Box<::VodozemacAccount> vodozemacAccount;
std::unordered_map<std::string, std::shared_ptr<Session>> sessions = {};
Keys keys;
- OlmAccount *getOlmAccount();
- void createAccount();
void exposePublicIdentityKeys();
void generateOneTimeKeys(size_t oneTimeKeysAmount);
std::string generateAndGetPrekey();
@@ -37,43 +33,38 @@
bool prekeyExistsAndOlderThan(uint64_t threshold);
bool prekeyDoesntExist();
bool isPrekeySignatureValid();
- OlmBuffer pickleAccount(const std::string &secretKey);
+ std::string pickleAccount(const std::string &secretKey);
public:
- CryptoModule();
CryptoModule(std::string secretKey, Persist persist);
// CryptoModule's accountBuffer cannot be safely copied
// See explanation in https://phab.comm.dev/D9562
CryptoModule(const CryptoModule &) = delete;
- static Keys keysFromStrings(
- const std::string &identityKeys,
- const std::string &oneTimeKeys);
-
std::string getIdentityKeys();
- std::string getOneTimeKeysForPublishing(size_t oneTimeKeysAmount = 10);
+ std::vector<std::string>
+ getOneTimeKeysForPublishing(size_t oneTimeKeysAmount = 10);
// Prekey rotation methods for X3DH
- std::uint8_t getNumPrekeys();
std::string getPrekey();
std::string getPrekeySignature();
std::optional<std::string> getUnpublishedPrekey();
void markPrekeyAsPublished();
void forgetOldPrekey();
- void initializeInboundForReceivingSession(
+ std::string initializeInboundForReceivingSession(
const std::string &targetDeviceId,
- const OlmBuffer &encryptedMessage,
- const OlmBuffer &idKeys,
+ const crypto::EncryptedData &encryptedData,
+ const std::string &idKeys,
int sessionVersion,
const bool overwrite);
int initializeOutboundForSendingSession(
const std::string &targetDeviceId,
- const OlmBuffer &idKeys,
- const OlmBuffer &preKeys,
- const OlmBuffer &preKeySignature,
- const std::optional<OlmBuffer> &oneTimeKey);
+ const std::string &idKeys,
+ const std::string &preKeys,
+ const std::string &preKeySignature,
+ const std::optional<std::string> &oneTimeKey);
bool hasSessionFor(const std::string &targetDeviceId);
std::shared_ptr<Session> getSessionByDeviceId(const std::string &deviceId);
void removeSessionByDeviceId(const std::string &deviceId);
@@ -90,7 +81,7 @@
std::string signMessage(const std::string &message);
static void verifySignature(
const std::string &publicKey,
- const OlmBuffer &message,
+ const std::string &message,
const std::string &signature);
std::optional<std::string> validatePrekey();
};
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,10 +1,6 @@
#include "CryptoModule.h"
-#include "Base64.h"
+#include "../Tools/OlmUtils.h"
#include "Logger.h"
-#include "OlmUtils.h"
-#include "PlatformSpecificTools.h"
-#include "olm/account.hh"
-#include "olm/session.hh"
#include <folly/dynamic.h>
#include <folly/json.h>
@@ -26,96 +22,59 @@
const std::string SESSION_DOES_NOT_EXIST_ERROR{"SESSION_DOES_NOT_EXIST"};
const std::string INVALID_SESSION_VERSION_ERROR{"INVALID_SESSION_VERSION"};
-CryptoModule::CryptoModule() {
- this->createAccount();
-}
-
-CryptoModule::CryptoModule(std::string secretKey, Persist persist) {
- if (persist.isEmpty()) {
- this->createAccount();
- } else {
+CryptoModule::CryptoModule(std::string secretKey, Persist persist)
+ : vodozemacAccount(::account_new()) {
+ if (!persist.isEmpty()) {
this->restoreFromB64(secretKey, persist);
}
}
-OlmAccount *CryptoModule::getOlmAccount() {
- return reinterpret_cast<OlmAccount *>(this->accountBuffer.data());
-}
-
-void CryptoModule::createAccount() {
- this->accountBuffer.resize(::olm_account_size());
- ::olm_account(this->accountBuffer.data());
-
- size_t randomSize = ::olm_create_account_random_length(this->getOlmAccount());
- OlmBuffer randomBuffer;
- PlatformSpecificTools::generateSecureRandomBytes(randomBuffer, randomSize);
-
- if (-1 ==
- ::olm_create_account(
- this->getOlmAccount(), randomBuffer.data(), randomSize)) {
- throw std::runtime_error{
- "error createAccount => " +
- std::string{::olm_account_last_error(this->getOlmAccount())}};
- };
-}
-
void CryptoModule::exposePublicIdentityKeys() {
- size_t identityKeysSize =
- ::olm_account_identity_keys_length(this->getOlmAccount());
- if (this->keys.identityKeys.size() == identityKeysSize) {
+ if (!this->keys.identityKeys.empty()) {
return;
}
- this->keys.identityKeys.resize(
- ::olm_account_identity_keys_length(this->getOlmAccount()));
- if (-1 ==
- ::olm_account_identity_keys(
- this->getOlmAccount(),
- this->keys.identityKeys.data(),
- this->keys.identityKeys.size())) {
- throw std::runtime_error{
- "error generateIdentityKeys => " +
- std::string{::olm_account_last_error(this->getOlmAccount())}};
- }
+
+ std::string ed25519 = std::string(this->vodozemacAccount->ed25519_key());
+ std::string curve25519 =
+ std::string(this->vodozemacAccount->curve25519_key());
+
+ // Format as JSON: {"ed25519":"...","curve25519":"..."}
+ folly::dynamic identityKeys =
+ folly::dynamic::object("ed25519", ed25519)("curve25519", curve25519);
+
+ this->keys.identityKeys = folly::toJson(identityKeys);
}
void CryptoModule::generateOneTimeKeys(size_t oneTimeKeysAmount) {
- size_t numRandomBytesRequired =
- ::olm_account_generate_one_time_keys_random_length(
- this->getOlmAccount(), oneTimeKeysAmount);
- OlmBuffer random;
- PlatformSpecificTools::generateSecureRandomBytes(
- random, numRandomBytesRequired);
-
- if (-1 ==
- ::olm_account_generate_one_time_keys(
- this->getOlmAccount(),
- oneTimeKeysAmount,
- random.data(),
- random.size())) {
- throw std::runtime_error{
- "error generateOneTimeKeys => " +
- std::string{::olm_account_last_error(this->getOlmAccount())}};
+ try {
+ this->vodozemacAccount->generate_one_time_keys(oneTimeKeysAmount);
+ } catch (const std::exception &e) {
+ throw std::runtime_error(
+ "error generateOneTimeKeys => " + std::string(e.what()));
}
}
// returns number of published keys
size_t CryptoModule::publishOneTimeKeys() {
- this->keys.oneTimeKeys.resize(
- ::olm_account_one_time_keys_length(this->getOlmAccount()));
- if (-1 ==
- ::olm_account_one_time_keys(
- this->getOlmAccount(),
- this->keys.oneTimeKeys.data(),
- this->keys.oneTimeKeys.size())) {
- throw std::runtime_error{
- "error publishOneTimeKeys => " +
- std::string{::olm_account_last_error(this->getOlmAccount())}};
+ try {
+ auto oneTimeKeysVec = this->vodozemacAccount->one_time_keys();
+
+ this->keys.oneTimeKeys.clear();
+ for (const auto &key : oneTimeKeysVec) {
+ this->keys.oneTimeKeys.push_back(std::string(key));
+ }
+
+ this->vodozemacAccount->mark_keys_as_published();
+
+ return oneTimeKeysVec.size();
+ } catch (const std::exception &e) {
+ throw std::runtime_error(
+ "error publishOneTimeKeys => " + std::string(e.what()));
}
- return ::olm_account_mark_keys_as_published(this->getOlmAccount());
}
bool CryptoModule::prekeyExistsAndOlderThan(uint64_t threshold) {
- // Our fork of Olm only remembers two prekeys at a time.
+ // Our fork of Vodozemac only remembers two prekeys at a time.
// If the new one hasn't been published, then the old one is still active.
// In that scenario, we need to avoid rotating the prekey because it will
// result in the old active prekey being discarded.
@@ -125,14 +84,14 @@
uint64_t currentTime = std::time(nullptr);
uint64_t lastPrekeyPublishTime =
- ::olm_account_get_last_prekey_publish_time(this->getOlmAccount());
+ this->vodozemacAccount->last_prekey_publish_time();
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
+ // Prekey generation when creating an Vodozemac Account was added to clients
+ // after the initial launch of Vodozemac. 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.
@@ -149,18 +108,19 @@
}
bool CryptoModule::isPrekeySignatureValid() {
- const std::string signingPublicKey =
- getSigningPublicKey(this->getIdentityKeys());
- const std::string prekey = parseOLMPrekey(this->getPrekey());
- const std::string preKeySignature = this->getPrekeySignature();
-
- const OlmBuffer prekeyBytes = Base64::decode(prekey);
try {
- this->verifySignature(signingPublicKey, prekeyBytes, preKeySignature);
+ const std::string signingPublicKey =
+ getSigningPublicKey(this->getIdentityKeys());
+
+ const std::string prekey = this->getPrekey();
+ const std::string prekeySignature = this->getPrekeySignature();
+
+ // Use the dedicated prekey verification function that decodes base64
+ ::verify_prekey_signature(signingPublicKey, prekey, prekeySignature);
return true;
} catch (const std::exception &e) {
std::string rawMessage{e.what()};
- if (rawMessage.find("BAD_MESSAGE_MAC") != std::string::npos) {
+ if (rawMessage.find("The signature was invalid") != std::string::npos) {
return false;
}
@@ -171,147 +131,87 @@
}
}
-Keys CryptoModule::keysFromStrings(
- const std::string &identityKeys,
- const std::string &oneTimeKeys) {
- return {
- OlmBuffer(identityKeys.begin(), identityKeys.end()),
- OlmBuffer(oneTimeKeys.begin(), oneTimeKeys.end())};
-}
-
std::string CryptoModule::getIdentityKeys() {
this->exposePublicIdentityKeys();
- return std::string{
- this->keys.identityKeys.begin(), this->keys.identityKeys.end()};
+ return this->keys.identityKeys;
}
-std::string
+std::vector<std::string>
CryptoModule::getOneTimeKeysForPublishing(size_t oneTimeKeysAmount) {
- OlmBuffer unpublishedOneTimeKeys;
- unpublishedOneTimeKeys.resize(
- ::olm_account_one_time_keys_length(this->getOlmAccount()));
- if (-1 ==
- ::olm_account_one_time_keys(
- this->getOlmAccount(),
- unpublishedOneTimeKeys.data(),
- unpublishedOneTimeKeys.size())) {
- throw std::runtime_error{
- "error getOneTimeKeysForPublishing => " +
- std::string{::olm_account_last_error(this->getOlmAccount())}};
- }
- std::string unpublishedKeysString =
- std::string{unpublishedOneTimeKeys.begin(), unpublishedOneTimeKeys.end()};
+ try {
+ // Get current unpublished keys
+ auto oneTimeKeysVec = this->vodozemacAccount->one_time_keys();
+ size_t numUnpublishedKeys = oneTimeKeysVec.size();
- folly::dynamic parsedUnpublishedKeys =
- folly::parseJson(unpublishedKeysString);
+ // Generate more if needed
+ if (numUnpublishedKeys < oneTimeKeysAmount) {
+ this->generateOneTimeKeys(oneTimeKeysAmount - numUnpublishedKeys);
+ }
- size_t numUnpublishedKeys = parsedUnpublishedKeys["curve25519"].size();
+ this->publishOneTimeKeys();
- if (numUnpublishedKeys < oneTimeKeysAmount) {
- this->generateOneTimeKeys(oneTimeKeysAmount - numUnpublishedKeys);
+ return this->keys.oneTimeKeys;
+ } catch (const std::exception &e) {
+ throw std::runtime_error(
+ "error getOneTimeKeysForPublishing => " + std::string(e.what()));
}
-
- this->publishOneTimeKeys();
-
- return std::string{
- this->keys.oneTimeKeys.begin(), this->keys.oneTimeKeys.end()};
-}
-
-std::uint8_t CryptoModule::getNumPrekeys() {
- return reinterpret_cast<olm::Account *>(this->getOlmAccount())->num_prekeys;
}
std::string CryptoModule::getPrekey() {
- OlmBuffer prekey;
- prekey.resize(::olm_account_prekey_length(this->getOlmAccount()));
-
- if (-1 ==
- ::olm_account_prekey(
- this->getOlmAccount(), prekey.data(), prekey.size())) {
- throw std::runtime_error{
- "error getPrekey => " +
- std::string{::olm_account_last_error(this->getOlmAccount())}};
+ try {
+ return std::string(this->vodozemacAccount->prekey());
+ } catch (const std::exception &e) {
+ throw std::runtime_error("error getPrekey => " + std::string(e.what()));
}
-
- return std::string{std::string{prekey.begin(), prekey.end()}};
}
std::string CryptoModule::getPrekeySignature() {
- size_t signatureSize = ::olm_account_signature_length(this->getOlmAccount());
-
- OlmBuffer signatureBuffer;
- signatureBuffer.resize(signatureSize);
-
- if (-1 ==
- ::olm_account_prekey_signature(
- this->getOlmAccount(), signatureBuffer.data())) {
- throw std::runtime_error{
- "error getPrekeySignature => " +
- std::string{::olm_account_last_error(this->getOlmAccount())}};
+ try {
+ return std::string(this->vodozemacAccount->prekey_signature());
+ } catch (const std::exception &e) {
+ throw std::runtime_error(
+ "error getPrekeySignature => " + std::string(e.what()));
}
-
- return std::string{signatureBuffer.begin(), signatureBuffer.end()};
}
std::optional<std::string> CryptoModule::getUnpublishedPrekey() {
- OlmBuffer prekey;
- prekey.resize(::olm_account_prekey_length(this->getOlmAccount()));
-
- std::size_t retval = ::olm_account_unpublished_prekey(
- this->getOlmAccount(), prekey.data(), prekey.size());
-
- if (0 == retval) {
- return std::nullopt;
- } else if (-1 == retval) {
- throw std::runtime_error{
- "error getUnpublishedPrekey => " +
- std::string{::olm_account_last_error(this->getOlmAccount())}};
+ try {
+ std::string unpublished =
+ std::string(this->vodozemacAccount->unpublished_prekey());
+ // NOTE: We use an empty string to represent None because cxx doesn't
+ // support Option<&str> in FFI function signatures.
+ if (unpublished.empty()) {
+ return std::nullopt;
+ }
+ return unpublished;
+ } catch (const std::exception &e) {
+ throw std::runtime_error(
+ "error getUnpublishedPrekey => " + std::string(e.what()));
}
-
- return std::string{prekey.begin(), prekey.end()};
}
std::string CryptoModule::generateAndGetPrekey() {
- size_t prekeySize =
- ::olm_account_generate_prekey_random_length(this->getOlmAccount());
-
- OlmBuffer random;
- PlatformSpecificTools::generateSecureRandomBytes(random, prekeySize);
-
- if (-1 ==
- ::olm_account_generate_prekey(
- this->getOlmAccount(), random.data(), random.size())) {
- throw std::runtime_error{
- "error generateAndGetPrekey => " +
- std::string{::olm_account_last_error(this->getOlmAccount())}};
- }
-
- OlmBuffer prekey;
- prekey.resize(::olm_account_prekey_length(this->getOlmAccount()));
-
- if (-1 ==
- ::olm_account_prekey(
- this->getOlmAccount(), prekey.data(), prekey.size())) {
- throw std::runtime_error{
- "error generateAndGetPrekey => " +
- std::string{::olm_account_last_error(this->getOlmAccount())}};
+ try {
+ this->vodozemacAccount->generate_prekey();
+ return std::string(this->vodozemacAccount->prekey());
+ } catch (const std::exception &e) {
+ throw std::runtime_error(
+ "error generateAndGetPrekey => " + std::string(e.what()));
}
-
- return std::string{prekey.begin(), prekey.end()};
}
void CryptoModule::markPrekeyAsPublished() {
- ::olm_account_mark_prekey_as_published(this->getOlmAccount());
+ this->vodozemacAccount->mark_prekey_as_published();
}
void CryptoModule::forgetOldPrekey() {
- ::olm_account_forget_old_prekey(this->getOlmAccount());
+ this->vodozemacAccount->forget_old_prekey();
}
-void CryptoModule::initializeInboundForReceivingSession(
+std::string CryptoModule::initializeInboundForReceivingSession(
const std::string &targetDeviceId,
- const OlmBuffer &encryptedMessage,
- const OlmBuffer &idKeys,
+ const crypto::EncryptedData &encryptedData,
+ const std::string &idKeys,
int sessionVersion,
const bool overwrite) {
if (this->hasSessionFor(targetDeviceId)) {
@@ -325,37 +225,39 @@
this->sessions.erase(this->sessions.find(targetDeviceId));
}
- std::unique_ptr<Session> newSession = Session::createSessionAsResponder(
- this->getOlmAccount(),
- this->keys.identityKeys.data(),
- encryptedMessage,
- idKeys);
+
+ auto [newSession, plaintext] = Session::createSessionAsResponder(
+ this->vodozemacAccount, encryptedData, idKeys);
newSession->setVersion(sessionVersion);
this->sessions.insert(make_pair(targetDeviceId, std::move(newSession)));
+ return plaintext;
}
int CryptoModule::initializeOutboundForSendingSession(
const std::string &targetDeviceId,
- const OlmBuffer &idKeys,
- const OlmBuffer &preKeys,
- const OlmBuffer &preKeySignature,
- const std::optional<OlmBuffer> &oneTimeKey) {
+ const std::string &idKeys,
+ const std::string &preKeys,
+ const std::string &preKeySignature,
+ const std::optional<std::string> &oneTimeKey) {
int newSessionVersion = 1;
if (this->hasSessionFor(targetDeviceId)) {
std::shared_ptr<Session> existingSession =
getSessionByDeviceId(targetDeviceId);
newSessionVersion = existingSession->getVersion() + 1;
Logger::log(
- "olm session overwritten for the device with id: " + targetDeviceId);
+ "session overwritten for the device with id: " + targetDeviceId);
this->sessions.erase(this->sessions.find(targetDeviceId));
}
+
+ // Use Olm compatibility mode = true for backward compatibility
std::unique_ptr<Session> newSession = Session::createSessionAsInitializer(
- this->getOlmAccount(),
- this->keys.identityKeys.data(),
+ this->vodozemacAccount,
idKeys,
preKeys,
preKeySignature,
- oneTimeKey);
+ oneTimeKey,
+ true); // olmCompatibilityMode = true
+
newSession->setVersion(newSessionVersion);
this->sessions.insert(make_pair(targetDeviceId, std::move(newSession)));
return newSessionVersion;
@@ -374,33 +276,28 @@
this->sessions.erase(deviceId);
}
-OlmBuffer CryptoModule::pickleAccount(const std::string &secretKey) {
- OlmAccount *olmAccount = this->getOlmAccount();
- size_t accountPickleLength = ::olm_pickle_account_length(olmAccount);
- OlmBuffer accountPickleBuffer(accountPickleLength);
-
- size_t result = ::olm_pickle_account(
- olmAccount,
- secretKey.data(),
- secretKey.size(),
- accountPickleBuffer.data(),
- accountPickleLength);
+std::string CryptoModule::pickleAccount(const std::string &secretKey) {
+ try {
+ // Convert secretKey to 32-byte array
+ std::array<uint8_t, 32> key;
+ std::copy_n(
+ secretKey.begin(), std::min(secretKey.size(), size_t(32)), key.begin());
- if (accountPickleLength != result) {
- throw std::runtime_error(
- "Error in pickleAccount => " +
- std::string(::olm_account_last_error(olmAccount)));
+ return std::string(this->vodozemacAccount->pickle(key));
+ } catch (const std::exception &e) {
+ throw std::runtime_error("error pickleAccount => " + std::string(e.what()));
}
- return accountPickleBuffer;
}
Persist CryptoModule::storeAsB64(const std::string &secretKey) {
Persist persist;
- persist.account = this->pickleAccount(secretKey);
+ std::string accountPickle = this->pickleAccount(secretKey);
+ persist.account = OlmBuffer(accountPickle.begin(), accountPickle.end());
std::unordered_map<std::string, std::shared_ptr<Session>>::iterator it;
for (it = this->sessions.begin(); it != this->sessions.end(); ++it) {
- OlmBuffer buffer = it->second->storeAsB64(secretKey);
+ std::string sessionPickle = it->second->storeAsB64(secretKey);
+ OlmBuffer buffer(sessionPickle.begin(), sessionPickle.end());
SessionPersist sessionPersist{buffer, it->second->getVersion()};
persist.sessions.insert(make_pair(it->first, sessionPersist));
}
@@ -409,33 +306,28 @@
}
std::string CryptoModule::pickleAccountToString(const std::string &secretKey) {
- OlmBuffer pickledAccount = this->pickleAccount(secretKey);
- return std::string(pickledAccount.begin(), pickledAccount.end());
+ return this->pickleAccount(secretKey);
}
void CryptoModule::restoreFromB64(
const std::string &secretKey,
Persist persist) {
- this->accountBuffer.resize(::olm_account_size());
- ::olm_account(this->accountBuffer.data());
- if (-1 ==
- ::olm_unpickle_account(
- this->getOlmAccount(),
- secretKey.data(),
- secretKey.size(),
- persist.account.data(),
- persist.account.size())) {
- throw std::runtime_error{
- "error restoreFromB64 => " +
- std::string{::olm_account_last_error(this->getOlmAccount())}};
- }
-
- std::unordered_map<std::string, SessionPersist>::iterator it;
- for (it = persist.sessions.begin(); it != persist.sessions.end(); ++it) {
- std::unique_ptr<Session> session =
- session->restoreFromB64(secretKey, it->second.buffer);
- session->setVersion(it->second.version);
- this->sessions.insert(make_pair(it->first, move(session)));
+ try {
+ std::string accountPickle(persist.account.begin(), persist.account.end());
+ this->vodozemacAccount = ::account_from_pickle(accountPickle, secretKey);
+
+ std::unordered_map<std::string, SessionPersist>::iterator it;
+ for (it = persist.sessions.begin(); it != persist.sessions.end(); ++it) {
+ std::string sessionPickle(
+ it->second.buffer.begin(), it->second.buffer.end());
+ std::unique_ptr<Session> session =
+ Session::restoreFromB64(secretKey, sessionPickle);
+ session->setVersion(it->second.version);
+ this->sessions.insert(make_pair(it->first, move(session)));
+ }
+ } catch (const std::exception &e) {
+ throw std::runtime_error(
+ "error restoreFromB64 => " + std::string(e.what()));
}
}
@@ -463,40 +355,22 @@
}
std::string CryptoModule::signMessage(const std::string &message) {
- OlmBuffer signature;
- signature.resize(::olm_account_signature_length(this->getOlmAccount()));
- size_t signatureLength = ::olm_account_sign(
- this->getOlmAccount(),
- (uint8_t *)message.data(),
- message.length(),
- signature.data(),
- signature.size());
- if (signatureLength == -1) {
- throw std::runtime_error{
- "olm error: " +
- std::string{::olm_account_last_error(this->getOlmAccount())}};
+ try {
+ return std::string(this->vodozemacAccount->sign(message));
+ } catch (const std::exception &e) {
+ throw std::runtime_error("error signMessage => " + std::string(e.what()));
}
- return std::string{(char *)signature.data(), signatureLength};
}
void CryptoModule::verifySignature(
const std::string &publicKey,
- const OlmBuffer &message,
+ const std::string &message,
const std::string &signature) {
- OlmBuffer utilityBuffer;
- utilityBuffer.resize(::olm_utility_size());
- OlmUtility *olmUtility = ::olm_utility(utilityBuffer.data());
- ssize_t verificationResult = ::olm_ed25519_verify(
- olmUtility,
- (uint8_t *)publicKey.data(),
- publicKey.length(),
- message.data(),
- message.size(),
- (uint8_t *)signature.data(),
- signature.length());
- if (verificationResult == -1) {
- throw std::runtime_error{
- "olm error: " + std::string{::olm_utility_last_error(olmUtility)}};
+ try {
+ ::verify_ed25519_signature(publicKey, message, signature);
+ } catch (const std::exception &e) {
+ throw std::runtime_error(
+ "error verifySignature => " + std::string(e.what()));
}
}
diff --git a/native/cpp/CommonCpp/CryptoTools/Session.h b/native/cpp/CommonCpp/CryptoTools/Session.h
--- a/native/cpp/CommonCpp/CryptoTools/Session.h
+++ b/native/cpp/CommonCpp/CryptoTools/Session.h
@@ -6,8 +6,6 @@
#include "Tools.h"
-#include "olm/olm.h"
-
#ifndef ANDROID
#include "vodozemac_bindings.rs.h"
#else
@@ -18,30 +16,36 @@
namespace crypto {
class Session {
- OlmBuffer olmSessionBuffer;
int version;
+ ::rust::Box<::VodozemacSession> vodozemacSession;
public:
+ // Constructor that takes a vodozemac session
+ Session(::rust::Box<::VodozemacSession> session)
+ : vodozemacSession(std::move(session)), version(0) {
+ }
+
static std::unique_ptr<Session> createSessionAsInitializer(
- OlmAccount *account,
- std::uint8_t *ownerIdentityKeys,
- const OlmBuffer &idKeys,
- const OlmBuffer &preKeys,
- const OlmBuffer &preKeySignature,
- const std::optional<OlmBuffer> &oneTimeKey);
- static std::unique_ptr<Session> createSessionAsResponder(
- OlmAccount *account,
- std::uint8_t *ownerIdentityKeys,
- const OlmBuffer &encryptedMessage,
- const OlmBuffer &idKeys);
- OlmBuffer storeAsB64(const std::string &secretKey);
+ ::rust::Box<::VodozemacAccount> &account,
+ const std::string &idKeys,
+ const std::string &preKeys,
+ const std::string &preKeySignature,
+ const std::optional<std::string> &oneTimeKey,
+ bool olmCompatibilityMode);
+ static std::pair<std::unique_ptr<Session>, std::string>
+ createSessionAsResponder(
+ ::rust::Box<::VodozemacAccount> &account,
+ const crypto::EncryptedData &encryptedData,
+ const std::string &idKeys);
+ std::string storeAsB64(const std::string &secretKey);
static std::unique_ptr<Session>
- restoreFromB64(const std::string &secretKey, OlmBuffer &b64);
- OlmSession *getOlmSession();
+ restoreFromB64(const std::string &secretKey, const std::string &b64);
std::string decrypt(EncryptedData &encryptedData);
EncryptedData encrypt(const std::string &content);
int getVersion();
void setVersion(int newVersion);
+ bool isSenderChainEmpty() const;
+ bool hasReceivedMessage() const;
};
} // namespace crypto
diff --git a/native/cpp/CommonCpp/CryptoTools/Session.cpp b/native/cpp/CommonCpp/CryptoTools/Session.cpp
--- a/native/cpp/CommonCpp/CryptoTools/Session.cpp
+++ b/native/cpp/CommonCpp/CryptoTools/Session.cpp
@@ -1,7 +1,7 @@
#include "Session.h"
-#include "PlatformSpecificTools.h"
-#include <optional>
+#include <folly/dynamic.h>
+#include <folly/json.h>
#include <stdexcept>
#ifndef ANDROID
@@ -17,201 +17,122 @@
// lib/utils/olm-utils.js
static const std::string olmErrorFlag = "OLM_ERROR";
-OlmSession *Session::getOlmSession() {
- return reinterpret_cast<OlmSession *>(this->olmSessionBuffer.data());
-}
-
std::unique_ptr<Session> Session::createSessionAsInitializer(
- OlmAccount *account,
- std::uint8_t *ownerIdentityKeys,
- const OlmBuffer &idKeys,
- const OlmBuffer &preKeys,
- const OlmBuffer &preKeySignature,
- const std::optional<OlmBuffer> &oneTimeKey) {
- std::unique_ptr<Session> session(new Session());
-
- session->olmSessionBuffer.resize(::olm_session_size());
- ::olm_session(session->olmSessionBuffer.data());
-
- OlmBuffer randomBuffer;
- PlatformSpecificTools::generateSecureRandomBytes(
- randomBuffer,
- ::olm_create_outbound_session_random_length(session->getOlmSession()));
-
- if (oneTimeKey) {
- if (-1 ==
- ::olm_create_outbound_session(
- session->getOlmSession(),
- account,
- idKeys.data() + ID_KEYS_PREFIX_OFFSET,
- KEYSIZE,
- idKeys.data() + SIGNING_KEYS_PREFIX_OFFSET,
- KEYSIZE,
- preKeys.data(),
- KEYSIZE,
- preKeySignature.data(),
- SIGNATURESIZE,
- oneTimeKey->data(),
- KEYSIZE,
- randomBuffer.data(),
- randomBuffer.size())) {
- throw std::runtime_error(
- "error createOutbound => " +
- std::string{::olm_session_last_error(session->getOlmSession())});
- }
- return session;
- }
- if (-1 ==
- ::olm_create_outbound_session_without_otk(
- session->getOlmSession(),
- account,
- idKeys.data() + ID_KEYS_PREFIX_OFFSET,
- KEYSIZE,
- idKeys.data() + SIGNING_KEYS_PREFIX_OFFSET,
- KEYSIZE,
- preKeys.data(),
- KEYSIZE,
- preKeySignature.data(),
- SIGNATURESIZE,
- randomBuffer.data(),
- randomBuffer.size())) {
+ ::rust::Box<::VodozemacAccount> &account,
+ const std::string &idKeys,
+ const std::string &preKeys,
+ const std::string &preKeySignature,
+ const std::optional<std::string> &oneTimeKey,
+ bool olmCompatibilityMode) {
+
+ try {
+ // Parse identity keys JSON
+ folly::dynamic idKeysObj = folly::parseJson(idKeys);
+ std::string curve25519Key = idKeysObj["curve25519"].asString();
+ std::string ed25519Key = idKeysObj["ed25519"].asString();
+
+ // Create outbound session
+ ::rust::Box<::VodozemacSession> vodozemacSession =
+ account->create_outbound_session(
+ curve25519Key,
+ ed25519Key,
+ // NOTE: We use an empty string to represent None because cxx
+ // doesn't support Option<&str> in FFI function signatures.
+ oneTimeKey.value_or(""),
+ preKeys,
+ preKeySignature,
+ olmCompatibilityMode);
+
+ return std::unique_ptr<Session>(new Session(std::move(vodozemacSession)));
+ } catch (const std::exception &e) {
throw std::runtime_error(
- "error createOutbound => " +
- std::string{::olm_session_last_error(session->getOlmSession())});
+ "error createOutbound => " + std::string(e.what()));
}
- return session;
}
-std::unique_ptr<Session> Session::createSessionAsResponder(
- OlmAccount *account,
- std::uint8_t *ownerIdentityKeys,
- const OlmBuffer &encryptedMessage,
- const OlmBuffer &idKeys) {
- std::unique_ptr<Session> session(new Session());
-
- OlmBuffer tmpEncryptedMessage(encryptedMessage);
- session->olmSessionBuffer.resize(::olm_session_size());
- ::olm_session(session->olmSessionBuffer.data());
- if (-1 ==
- ::olm_create_inbound_session_from(
- session->getOlmSession(),
- account,
- idKeys.data() + ID_KEYS_PREFIX_OFFSET,
- KEYSIZE,
- tmpEncryptedMessage.data(),
- encryptedMessage.size())) {
- throw std::runtime_error(
- "error createInbound => " +
- std::string{::olm_session_last_error(session->getOlmSession())});
- }
+std::pair<std::unique_ptr<Session>, std::string>
+Session::createSessionAsResponder(
+ ::rust::Box<::VodozemacAccount> &account,
+ const crypto::EncryptedData &encryptedData,
+ const std::string &idKeys) {
- if (-1 == ::olm_remove_one_time_keys(account, session->getOlmSession())) {
- throw std::runtime_error(
- "error createInbound (remove oneTimeKey) => " +
- std::string{::olm_session_last_error(session->getOlmSession())});
+ try {
+ // Parse identity keys JSON
+ folly::dynamic idKeysObj = folly::parseJson(idKeys);
+ std::string curve25519Key = idKeysObj["curve25519"].asString();
+
+ auto encryptResult =
+ ::encrypt_result_new(encryptedData.message, encryptedData.messageType);
+ auto result =
+ account->create_inbound_session(curve25519Key, *encryptResult);
+
+ std::string plaintext = std::string(result->plaintext());
+
+ ::rust::Box<::VodozemacSession> vodozemacSession = result->take_session();
+
+ return std::make_pair(
+ std::unique_ptr<Session>(new Session(std::move(vodozemacSession))),
+ plaintext);
+ } catch (const std::exception &e) {
+ throw std::runtime_error("error createInbound => " + std::string(e.what()));
}
- return session;
}
-OlmBuffer Session::storeAsB64(const std::string &secretKey) {
- size_t pickleLength = ::olm_pickle_session_length(this->getOlmSession());
- OlmBuffer pickle(pickleLength);
- size_t res = ::olm_pickle_session(
- this->getOlmSession(),
- secretKey.data(),
- secretKey.size(),
- pickle.data(),
- pickleLength);
- if (pickleLength != res) {
- throw std::runtime_error("error pickleSession => ::olm_pickle_session");
+std::string Session::storeAsB64(const std::string &secretKey) {
+ try {
+ // Convert secretKey to 32-byte array
+ std::array<uint8_t, 32> key;
+ std::copy_n(
+ secretKey.begin(), std::min(secretKey.size(), size_t(32)), key.begin());
+
+ return std::string(this->vodozemacSession->pickle(key));
+ } catch (const std::exception &e) {
+ throw std::runtime_error("error pickleSession => " + std::string(e.what()));
}
- return pickle;
}
std::unique_ptr<Session>
-Session::restoreFromB64(const std::string &secretKey, OlmBuffer &b64) {
- std::unique_ptr<Session> session(new Session());
-
- session->olmSessionBuffer.resize(::olm_session_size());
- ::olm_session(session->olmSessionBuffer.data());
- if (-1 ==
- ::olm_unpickle_session(
- session->getOlmSession(),
- secretKey.data(),
- secretKey.size(),
- b64.data(),
- b64.size())) {
- throw std::runtime_error("error pickleSession => ::olm_unpickle_session");
+Session::restoreFromB64(const std::string &secretKey, const std::string &b64) {
+ try {
+ ::rust::Box<::VodozemacSession> vodozemacSession =
+ ::session_from_pickle(b64, secretKey);
+
+ return std::unique_ptr<Session>(new Session(std::move(vodozemacSession)));
+ } catch (const std::exception &e) {
+ throw std::runtime_error(
+ "error restoreFromB64 => " + std::string(e.what()));
}
- return session;
}
std::string Session::decrypt(EncryptedData &encryptedData) {
- OlmSession *session = this->getOlmSession();
-
- OlmBuffer utilityBuffer(::olm_utility_size());
- OlmUtility *olmUtility = ::olm_utility(utilityBuffer.data());
-
- OlmBuffer messageHashBuffer(::olm_sha256_length(olmUtility));
- ::olm_sha256(
- olmUtility,
- encryptedData.message.data(),
- encryptedData.message.size(),
- messageHashBuffer.data(),
- messageHashBuffer.size());
-
- OlmBuffer tmpEncryptedMessage(encryptedData.message);
- size_t maxSize = ::olm_decrypt_max_plaintext_length(
- session,
- encryptedData.messageType,
- tmpEncryptedMessage.data(),
- tmpEncryptedMessage.size());
-
- if (maxSize == -1) {
- throw std::runtime_error{
- "error decrypt_max_plaintext_length => " +
- std::string{::olm_session_last_error(session)} + ". Hash: " +
- std::string{messageHashBuffer.begin(), messageHashBuffer.end()}};
- }
+ try {
+ return std::string(this->vodozemacSession->decrypt(
+ encryptedData.message,
+ static_cast<uint32_t>(encryptedData.messageType)));
+ } catch (const std::exception &e) {
+ // Compute message hash for debugging
+ rust::Slice<const uint8_t> messageSlice{
+ reinterpret_cast<const uint8_t *>(encryptedData.message.data()),
+ encryptedData.message.size()};
+ std::string messageHash = std::string(::sha256(messageSlice));
- OlmBuffer decryptedMessage(maxSize);
- size_t decryptedSize = ::olm_decrypt(
- session,
- encryptedData.messageType,
- encryptedData.message.data(),
- encryptedData.message.size(),
- decryptedMessage.data(),
- decryptedMessage.size());
- if (decryptedSize == -1) {
- throw std::runtime_error{
- "error decrypt => " + olmErrorFlag + " " +
- std::string{::olm_session_last_error(session)} + ". Hash: " +
- std::string{messageHashBuffer.begin(), messageHashBuffer.end()}};
+ throw std::runtime_error(
+ "error decrypt => " + olmErrorFlag + " " + std::string(e.what()) +
+ ", message hash: " + messageHash);
}
- return std::string{(char *)decryptedMessage.data(), decryptedSize};
}
EncryptedData Session::encrypt(const std::string &content) {
- OlmSession *session = this->getOlmSession();
- OlmBuffer encryptedMessage(
- ::olm_encrypt_message_length(session, content.size()));
- OlmBuffer messageRandom;
- PlatformSpecificTools::generateSecureRandomBytes(
- messageRandom, ::olm_encrypt_random_length(session));
- size_t messageType = ::olm_encrypt_message_type(session);
- if (-1 ==
- ::olm_encrypt(
- session,
- (uint8_t *)content.data(),
- content.size(),
- messageRandom.data(),
- messageRandom.size(),
- encryptedMessage.data(),
- encryptedMessage.size())) {
- throw std::runtime_error{
- "error encrypt => " + std::string{::olm_session_last_error(session)}};
+ try {
+ auto result = this->vodozemacSession->encrypt(content);
+
+ return EncryptedData{
+ std::string(result->encrypted_message()),
+ result->message_type(),
+ this->getVersion()};
+ } catch (const std::exception &e) {
+ throw std::runtime_error("error encrypt => " + std::string(e.what()));
}
- return {encryptedMessage, messageType, this->getVersion()};
}
int Session::getVersion() {
@@ -222,5 +143,13 @@
this->version = newVersion;
}
+bool Session::isSenderChainEmpty() const {
+ return this->vodozemacSession->is_sender_chain_empty();
+}
+
+bool Session::hasReceivedMessage() const {
+ return this->vodozemacSession->has_received_message();
+}
+
} // namespace crypto
} // namespace comm
diff --git a/native/cpp/CommonCpp/CryptoTools/Tools.h b/native/cpp/CommonCpp/CryptoTools/Tools.h
--- a/native/cpp/CommonCpp/CryptoTools/Tools.h
+++ b/native/cpp/CommonCpp/CryptoTools/Tools.h
@@ -18,12 +18,35 @@
typedef std::vector<std::uint8_t> OlmBuffer;
struct Keys {
- OlmBuffer identityKeys; // size = 116
- OlmBuffer oneTimeKeys; // size = 43 each
+ std::string identityKeys;
+ std::vector<std::string> oneTimeKeys;
+
+ // Securely wipe keys from memory
+ void wipe() {
+ // Volatile pointer prevents compiler from optimizing away the zeroing
+ volatile char *p1 = const_cast<char *>(identityKeys.data());
+ for (size_t i = 0; i < identityKeys.size(); ++i) {
+ p1[i] = 0;
+ }
+ identityKeys.clear();
+
+ for (auto &key : oneTimeKeys) {
+ volatile char *p2 = const_cast<char *>(key.data());
+ for (size_t i = 0; i < key.size(); ++i) {
+ p2[i] = 0;
+ }
+ key.clear();
+ }
+ oneTimeKeys.clear();
+ }
+
+ ~Keys() {
+ wipe();
+ }
};
struct EncryptedData {
- OlmBuffer message;
+ std::string message;
size_t messageType;
std::optional<int> sessionVersion;
};
diff --git a/native/cpp/CommonCpp/NativeModules/CommCoreModule.cpp b/native/cpp/CommonCpp/NativeModules/CommCoreModule.cpp
--- a/native/cpp/CommonCpp/NativeModules/CommCoreModule.cpp
+++ b/native/cpp/CommonCpp/NativeModules/CommCoreModule.cpp
@@ -7,7 +7,6 @@
#include "InternalModules/RustPromiseManager.h"
#include "Logger.h"
#include "NativeModuleUtils.h"
-#include "OlmUtils.h"
#include "TerminateApp.h"
#include <ReactCommon/TurboModuleUtils.h>
@@ -814,15 +813,27 @@
jsi::Object parseOneTimeKeysResult(
jsi::Runtime &rt,
- std::string contentOneTimeKeysBlob,
- std::string notifOneTimeKeysBlob) {
- auto contentOneTimeKeys = parseOLMOneTimeKeys(rt, contentOneTimeKeysBlob);
- auto notifOneTimeKeys = parseOLMOneTimeKeys(rt, notifOneTimeKeysBlob);
+ std::vector<std::string> contentOneTimeKeys,
+ std::vector<std::string> notifOneTimeKeys) {
+ auto jsiContentOneTimeKeys = jsi::Array(rt, contentOneTimeKeys.size());
+ size_t contentIdx = 0;
+ for (const auto &key : contentOneTimeKeys) {
+ jsiContentOneTimeKeys.setValueAtIndex(
+ rt, contentIdx++, jsi::String::createFromUtf8(rt, key));
+ }
+
+ auto jsiNotifOneTimeKeys = jsi::Array(rt, notifOneTimeKeys.size());
+ size_t notifIdx = 0;
+ for (const auto &key : notifOneTimeKeys) {
+ jsiNotifOneTimeKeys.setValueAtIndex(
+ rt, notifIdx++, jsi::String::createFromUtf8(rt, key));
+ }
+
auto jsiOneTimeKeysResult = jsi::Object(rt);
jsiOneTimeKeysResult.setProperty(
- rt, "contentOneTimeKeys", contentOneTimeKeys);
+ rt, "contentOneTimeKeys", jsiContentOneTimeKeys);
jsiOneTimeKeysResult.setProperty(
- rt, "notificationsOneTimeKeys", notifOneTimeKeys);
+ rt, "notificationsOneTimeKeys", jsiNotifOneTimeKeys);
return jsiOneTimeKeysResult;
}
@@ -869,8 +880,8 @@
rt, [=](jsi::Runtime &innerRt, std::shared_ptr<Promise> promise) {
taskType job = [=, &innerRt]() {
std::string error;
- std::string contentResult;
- std::string notifResult;
+ std::vector<std::string> contentResult;
+ std::vector<std::string> notifResult;
if (this->contentCryptoModule == nullptr ||
!NotificationsCryptoModule::isNotificationsAccountInitialized()) {
this->jsInvoker_->invokeAsync([=, &innerRt]() {
@@ -1000,10 +1011,10 @@
auto currentID = RustPromiseManager::instance.addPromise(
std::move(promiseInfo));
auto contentPrekeyToUploadRust =
- rust::String(parseOLMPrekey(contentPrekeyToUpload));
+ rust::String(contentPrekeyToUpload);
auto prekeySignatureRust = rust::string(contentPrekeySignature);
auto notifsPrekeyToUploadRust =
- rust::String(parseOLMPrekey(notifsPrekeyToUpload));
+ rust::String(notifsPrekeyToUpload);
auto notificationsPrekeySignatureRust =
rust::string(notifsPrekeySignature);
::identityRefreshUserPrekeys(
@@ -1097,8 +1108,8 @@
notifPrekeySignature = notifsCryptoModuleWithPicklingKey.value()
.first->getPrekeySignature();
- contentPrekey = parseOLMPrekey(contentPrekeyBlob.value());
- notifPrekey = parseOLMPrekey(notifPrekeyBlob.value());
+ contentPrekey = contentPrekeyBlob.value();
+ notifPrekey = notifPrekeyBlob.value();
} catch (const std::exception &e) {
error = e.what();
}
@@ -1163,21 +1174,14 @@
try {
notifsCryptoModuleWithPicklingKey =
NotificationsCryptoModule::fetchNotificationsAccount();
- std::optional<crypto::OlmBuffer> oneTimeKeyBuffer;
- if (oneTimeKeyCpp) {
- oneTimeKeyBuffer = crypto::OlmBuffer(
- oneTimeKeyCpp->begin(), oneTimeKeyCpp->end());
- }
notifsCryptoModuleWithPicklingKey.value()
.first->initializeOutboundForSendingSession(
keyserverIDCpp,
- std::vector<uint8_t>(
- identityKeysCpp.begin(), identityKeysCpp.end()),
- std::vector<uint8_t>(prekeyCpp.begin(), prekeyCpp.end()),
- std::vector<uint8_t>(
- prekeySignatureCpp.begin(), prekeySignatureCpp.end()),
- oneTimeKeyBuffer);
+ identityKeysCpp,
+ prekeyCpp,
+ prekeySignatureCpp,
+ oneTimeKeyCpp);
result = notifsCryptoModuleWithPicklingKey.value().first->encrypt(
keyserverIDCpp,
@@ -1540,20 +1544,13 @@
crypto::EncryptedData initialEncryptedData;
int sessionVersion;
try {
- std::optional<crypto::OlmBuffer> oneTimeKeyBuffer;
- if (oneTimeKeyCpp) {
- oneTimeKeyBuffer = crypto::OlmBuffer(
- oneTimeKeyCpp->begin(), oneTimeKeyCpp->end());
- }
sessionVersion =
this->contentCryptoModule->initializeOutboundForSendingSession(
deviceIDCpp,
- std::vector<uint8_t>(
- identityKeysCpp.begin(), identityKeysCpp.end()),
- std::vector<uint8_t>(prekeyCpp.begin(), prekeyCpp.end()),
- std::vector<uint8_t>(
- prekeySignatureCpp.begin(), prekeySignatureCpp.end()),
- oneTimeKeyBuffer);
+ identityKeysCpp,
+ prekeyCpp,
+ prekeySignatureCpp,
+ oneTimeKeyCpp);
const std::string initMessage = "{\"type\": \"init\"}";
initialEncryptedData =
@@ -1602,20 +1599,15 @@
std::string error;
std::string decryptedMessage;
try {
- this->contentCryptoModule->initializeInboundForReceivingSession(
- deviceIDCpp,
- std::vector<uint8_t>(
- encryptedMessageCpp.begin(), encryptedMessageCpp.end()),
- std::vector<uint8_t>(
- identityKeysCpp.begin(), identityKeysCpp.end()),
- static_cast<int>(sessionVersion),
- overwrite);
crypto::EncryptedData encryptedData{
- std::vector<uint8_t>(
- encryptedMessageCpp.begin(), encryptedMessageCpp.end()),
- messageType};
+ encryptedMessageCpp, messageType};
decryptedMessage =
- this->contentCryptoModule->decrypt(deviceIDCpp, encryptedData);
+ this->contentCryptoModule->initializeInboundForReceivingSession(
+ deviceIDCpp,
+ encryptedData,
+ identityKeysCpp,
+ static_cast<int>(sessionVersion),
+ overwrite);
this->persistCryptoModules(true, std::nullopt);
} catch (const std::exception &e) {
error = e.what();
@@ -1697,20 +1689,13 @@
try {
notifsCryptoModuleWithPicklingKey =
NotificationsCryptoModule::fetchNotificationsAccount();
- std::optional<crypto::OlmBuffer> oneTimeKeyBuffer;
- if (oneTimeKeyCpp) {
- oneTimeKeyBuffer = crypto::OlmBuffer(
- oneTimeKeyCpp->begin(), oneTimeKeyCpp->end());
- }
notifsCryptoModuleWithPicklingKey.value()
.first->initializeOutboundForSendingSession(
deviceIDCpp,
- std::vector<uint8_t>(
- identityKeysCpp.begin(), identityKeysCpp.end()),
- std::vector<uint8_t>(prekeyCpp.begin(), prekeyCpp.end()),
- std::vector<uint8_t>(
- prekeySignatureCpp.begin(), prekeySignatureCpp.end()),
- oneTimeKeyBuffer);
+ identityKeysCpp,
+ prekeyCpp,
+ prekeySignatureCpp,
+ oneTimeKeyCpp);
result = notifsCryptoModuleWithPicklingKey.value().first->encrypt(
deviceIDCpp,
@@ -1904,9 +1889,7 @@
std::string decryptedMessage;
try {
crypto::EncryptedData encryptedData{
- std::vector<uint8_t>(message.begin(), message.end()),
- messageType,
- sessionVersion};
+ message, messageType, sessionVersion};
decryptedMessage =
this->contentCryptoModule->decrypt(deviceIDCpp, encryptedData);
this->persistCryptoModules(true, std::nullopt);
@@ -1953,9 +1936,7 @@
std::string decryptedMessage;
try {
crypto::EncryptedData encryptedData{
- std::vector<uint8_t>(message.begin(), message.end()),
- messageType,
- sessionVersion};
+ message, messageType, sessionVersion};
decryptedMessage =
this->contentCryptoModule->decrypt(deviceIDCpp, encryptedData);
@@ -2086,10 +2067,8 @@
taskType job = [=, &innerRt]() {
std::string error;
try {
- crypto::OlmBuffer messageBuffer(
- messageStr.begin(), messageStr.end());
crypto::CryptoModule::verifySignature(
- keyStr, messageBuffer, signatureStr);
+ keyStr, messageStr, signatureStr);
} catch (const std::exception &e) {
error = "verifying signature failed with: " + std::string(e.what());
}
diff --git a/native/cpp/CommonCpp/NativeModules/CommUtilsModule.h b/native/cpp/CommonCpp/NativeModules/CommUtilsModule.h
--- a/native/cpp/CommonCpp/NativeModules/CommUtilsModule.h
+++ b/native/cpp/CommonCpp/NativeModules/CommUtilsModule.h
@@ -1,9 +1,7 @@
#pragma once
-#include "../CryptoTools/Tools.h"
#include "../Tools/WorkerThread.h"
#include "../_generated/utilsJSI.h"
-#include "olm/olm.h"
#include <ReactCommon/TurboModuleUtils.h>
#include <jsi/jsi.h>
#include <memory>
@@ -12,15 +10,11 @@
namespace comm {
namespace jsi = facebook::jsi;
-using ::comm::crypto::OlmBuffer;
class CommUtilsModule
: public facebook::react::CommUtilsModuleSchemaCxxSpecJSI {
std::unique_ptr<WorkerThread> utilsThread;
- OlmBuffer olmUtilityBuffer;
- ::OlmUtility *olmUtility;
-
virtual jsi::Value writeBufferToFile(
jsi::Runtime &rt,
jsi::String path,
diff --git a/native/cpp/CommonCpp/NativeModules/CommUtilsModule.cpp b/native/cpp/CommonCpp/NativeModules/CommUtilsModule.cpp
--- a/native/cpp/CommonCpp/NativeModules/CommUtilsModule.cpp
+++ b/native/cpp/CommonCpp/NativeModules/CommUtilsModule.cpp
@@ -1,6 +1,11 @@
#include "CommUtilsModule.h"
#include "../Tools/Base64.h"
-#include "olm/olm.h"
+
+#ifndef ANDROID
+#include "vodozemac_bindings.rs.h"
+#else
+#include "lib.rs.h"
+#endif
#include <ReactCommon/TurboModuleUtils.h>
#include <fstream>
@@ -12,9 +17,7 @@
CommUtilsModule::CommUtilsModule(std::shared_ptr<CallInvoker> jsInvoker)
: CommUtilsModuleSchemaCxxSpecJSI(jsInvoker),
- utilsThread(std::make_unique<WorkerThread>("utils")),
- olmUtilityBuffer(::olm_utility_size()) {
- this->olmUtility = ::olm_utility(olmUtilityBuffer.data());
+ utilsThread(std::make_unique<WorkerThread>("utils")) {
}
jsi::Value CommUtilsModule::writeBufferToFile(
@@ -135,19 +138,10 @@
auto inputPtr = arrayBuffer.data(rt);
auto inputSize = arrayBuffer.size(rt);
- auto sha256Size = ::olm_sha256_length(this->olmUtility);
- OlmBuffer sha256Bytes(sha256Size);
- auto outputLength = ::olm_sha256(
- this->olmUtility, inputPtr, inputSize, sha256Bytes.data(), sha256Size);
- if (outputLength == std::size_t(-1)) {
- throw jsi::JSError(
- rt,
- "olm error: " +
- std::string{::olm_utility_last_error(this->olmUtility)});
- }
+ rust::Slice<const uint8_t> input{inputPtr, inputSize};
+ auto sha256Result = ::sha256(input);
- std::string sha256String{sha256Bytes.begin(), sha256Bytes.end()};
- return jsi::String::createFromUtf8(rt, sha256String);
+ return jsi::String::createFromUtf8(rt, std::string(sha256Result));
}
jsi::String CommUtilsModule::decodeUTF8ArrayBufferToString(
diff --git a/native/cpp/CommonCpp/Notifications/BackgroundDataStorage/NotificationsCryptoModule.cpp b/native/cpp/CommonCpp/Notifications/BackgroundDataStorage/NotificationsCryptoModule.cpp
--- a/native/cpp/CommonCpp/Notifications/BackgroundDataStorage/NotificationsCryptoModule.cpp
+++ b/native/cpp/CommonCpp/Notifications/BackgroundDataStorage/NotificationsCryptoModule.cpp
@@ -5,7 +5,6 @@
#include "../../Tools/CommSecureStore.h"
#include "../../Tools/PlatformSpecificTools.h"
#include "NotificationsInboundKeysProvider.h"
-#include "olm/session.hh"
#include "Logger.h"
#include <fcntl.h>
@@ -19,6 +18,10 @@
#include <unordered_set>
namespace comm {
+// Message type constants (replacing Olm constants)
+constexpr uint32_t MESSAGE_TYPE_PREKEY = 0;
+constexpr uint32_t MESSAGE_TYPE_MESSAGE = 1;
+
const std::string
NotificationsCryptoModule::secureStoreNotificationsAccountDataKey =
"notificationsCryptoAccountDataKey";
@@ -166,9 +169,7 @@
std::string NotificationsCryptoModule::serializeNotificationsSession(
std::shared_ptr<crypto::Session> session,
std::string picklingKey) {
- crypto::OlmBuffer pickledSessionBytes = session->storeAsB64(picklingKey);
- std::string pickledSession =
- std::string{pickledSessionBytes.begin(), pickledSessionBytes.end()};
+ std::string pickledSession = session->storeAsB64(picklingKey);
folly::dynamic serializedSessionJson = folly::dynamic::object(
"session", pickledSession)("picklingKey", picklingKey);
return folly::toJson(serializedSessionJson);
@@ -187,11 +188,9 @@
}
std::string pickledSession = serializedSessionJson["session"].asString();
- crypto::OlmBuffer pickledSessionBytes =
- crypto::OlmBuffer{pickledSession.begin(), pickledSession.end()};
std::string picklingKey = serializedSessionJson["picklingKey"].asString();
std::unique_ptr<crypto::Session> session =
- crypto::Session::restoreFromB64(picklingKey, pickledSessionBytes);
+ crypto::Session::restoreFromB64(picklingKey, pickledSession);
return {std::move(session), picklingKey};
}
@@ -548,8 +547,7 @@
std::string legacyNotificationsAccountPath =
comm::PlatformSpecificTools::getNotificationsCryptoAccountPath();
- crypto::EncryptedData encryptedData{
- std::vector<uint8_t>(data.begin(), data.end()), messageType};
+ crypto::EncryptedData encryptedData{data, messageType};
auto cryptoModule = NotificationsCryptoModule::deserializeCryptoModule(
legacyNotificationsAccountPath, picklingKey.value());
@@ -585,8 +583,7 @@
std::unique_ptr<crypto::Session> session =
std::move(sessionWithPicklingKey.value().first);
std::string picklingKey = sessionWithPicklingKey.value().second;
- crypto::EncryptedData encryptedData{
- std::vector<uint8_t>(data.begin(), data.end()), messageType};
+ crypto::EncryptedData encryptedData{data, messageType};
std::string decryptedData = session->decrypt(encryptedData);
NotificationsCryptoModule::persistNotificationsSessionInternal(
@@ -629,8 +626,7 @@
std::unique_ptr<crypto::Session> session =
std::move(sessionWithPicklingKey.value().first);
std::string picklingKey = sessionWithPicklingKey.value().second;
- crypto::EncryptedData encryptedData{
- std::vector<uint8_t>(data.begin(), data.end()), messageType};
+ crypto::EncryptedData encryptedData{data, messageType};
std::string decryptedData = session->decrypt(encryptedData);
StatefulDecryptResult statefulDecryptResult(
std::move(session), keyserverID, picklingKey, decryptedData);
@@ -651,8 +647,8 @@
std::optional<std::pair<std::shared_ptr<crypto::CryptoModule>, std::string>>
maybeAccountWithPicklingKey;
- if (messageType != OLM_MESSAGE_TYPE_MESSAGE &&
- messageType != OLM_MESSAGE_TYPE_PRE_KEY) {
+ if (messageType != MESSAGE_TYPE_MESSAGE &&
+ messageType != MESSAGE_TYPE_PREKEY) {
throw std::runtime_error(
"Received message of invalid type from device: " + deviceID);
} else {
@@ -665,32 +661,30 @@
}
if (!maybeSessionWithPicklingKey.has_value() &&
- messageType == OLM_MESSAGE_TYPE_MESSAGE) {
+ messageType == MESSAGE_TYPE_MESSAGE) {
throw std::runtime_error(
"Received MESSAGE_TYPE_MESSAGE message from device: " + deviceID +
" but session not initialized.");
}
- crypto::EncryptedData encryptedData{
- std::vector<uint8_t>(data.begin(), data.end()), messageType};
+ crypto::EncryptedData encryptedData{data, messageType};
bool isSenderChainEmpty = true;
bool hasReceivedMessage = false;
bool sessionExists = maybeSessionWithPicklingKey.has_value();
if (sessionExists) {
- ::olm::Session *olmSessionAsCppClass = reinterpret_cast<::olm::Session *>(
- maybeSessionWithPicklingKey.value().first->getOlmSession());
- isSenderChainEmpty = olmSessionAsCppClass->ratchet.sender_chain.empty();
- hasReceivedMessage = olmSessionAsCppClass->received_message;
+ isSenderChainEmpty =
+ maybeSessionWithPicklingKey.value().first->isSenderChainEmpty();
+ hasReceivedMessage =
+ maybeSessionWithPicklingKey.value().first->hasReceivedMessage();
}
// regular message
- bool isRegularMessage =
- sessionExists && messageType == OLM_MESSAGE_TYPE_MESSAGE;
+ bool isRegularMessage = sessionExists && messageType == MESSAGE_TYPE_MESSAGE;
bool isRegularPrekeyMessage = sessionExists &&
- messageType == OLM_MESSAGE_TYPE_PRE_KEY && isSenderChainEmpty &&
+ messageType == MESSAGE_TYPE_PREKEY && isSenderChainEmpty &&
hasReceivedMessage;
if (isRegularMessage || isRegularPrekeyMessage) {
@@ -728,17 +722,17 @@
}
auto accountWithPicklingKey = maybeAccountWithPicklingKey.value();
- accountWithPicklingKey.first->initializeInboundForReceivingSession(
- deviceID,
- {data.begin(), data.end()},
- {notifInboundKeys.begin(), notifInboundKeys.end()},
- // The argument below is relevant for content only
- 0,
- true);
+ std::string decryptedData =
+ accountWithPicklingKey.first->initializeInboundForReceivingSession(
+ deviceID,
+ encryptedData,
+ {notifInboundKeys.begin(), notifInboundKeys.end()},
+ // The argument below is relevant for content only
+ 0,
+ true);
std::shared_ptr<crypto::Session> newInboundSession =
accountWithPicklingKey.first->getSessionByDeviceId(deviceID);
accountWithPicklingKey.first->removeSessionByDeviceId(deviceID);
- std::string decryptedData = newInboundSession->decrypt(encryptedData);
// session reset attempt or session initialization - handled the same
bool sessionResetAttempt =
diff --git a/native/cpp/CommonCpp/Tools/OlmUtils.h b/native/cpp/CommonCpp/Tools/OlmUtils.h
--- a/native/cpp/CommonCpp/Tools/OlmUtils.h
+++ b/native/cpp/CommonCpp/Tools/OlmUtils.h
@@ -4,14 +4,6 @@
namespace comm {
-/**
- * Parses a OLM prekey string from JSON format
- * @param prekeyBlob JSON string with prekey
- * @return The prekey string extracted from the JSON
- * @throws std::runtime_error if parsing fails
- */
-std::string parseOLMPrekey(std::string prekeyBlob);
-
/**
* Extracts the ed25519 signing public key from an identity keys JSON blob
* @param identityKeysBlob JSON string with identity keys
diff --git a/native/cpp/CommonCpp/Tools/OlmUtils.cpp b/native/cpp/CommonCpp/Tools/OlmUtils.cpp
--- a/native/cpp/CommonCpp/Tools/OlmUtils.cpp
+++ b/native/cpp/CommonCpp/Tools/OlmUtils.cpp
@@ -6,33 +6,6 @@
namespace comm {
-std::string parseOLMPrekey(std::string prekeyBlob) {
- folly::dynamic parsedPrekey;
- try {
- parsedPrekey = folly::parseJson(prekeyBlob);
- } catch (const folly::json::parse_error &e) {
- std::string errorMessage{
- "parsing prekey failed with: " + std::string(e.what())};
- Logger::log(errorMessage);
- throw std::runtime_error(errorMessage);
- }
-
- folly::dynamic innerObject = parsedPrekey["curve25519"];
- if (!innerObject.isObject()) {
- std::string errorMessage{"parsing prekey failed: inner object malformed"};
- Logger::log(errorMessage);
- throw std::runtime_error(errorMessage);
- }
-
- if (innerObject.values().begin() == innerObject.values().end()) {
- std::string errorMessage{"parsing prekey failed: prekey missing"};
- Logger::log(errorMessage);
- throw std::runtime_error(errorMessage);
- }
-
- return parsedPrekey["curve25519"].values().begin()->asString();
-}
-
std::string getSigningPublicKey(const std::string &identityKeysBlob) {
folly::dynamic parsedKeys;
try {
diff --git a/native/crypto/olm-api.js b/native/crypto/olm-api.js
--- a/native/crypto/olm-api.js
+++ b/native/crypto/olm-api.js
@@ -1,6 +1,5 @@
// @flow
-import { getOneTimeKeyValues } from 'lib/shared/crypto-utils.js';
import { type AuthMetadata } from 'lib/shared/identity-client-context.js';
import {
type OneTimeKeysResultValues,
@@ -117,8 +116,8 @@
const { contentOneTimeKeys, notificationsOneTimeKeys } =
await commCoreModule.getOneTimeKeys(numberOfKeys);
return {
- contentOneTimeKeys: getOneTimeKeyValues(contentOneTimeKeys),
- notificationsOneTimeKeys: getOneTimeKeyValues(notificationsOneTimeKeys),
+ contentOneTimeKeys: contentOneTimeKeys,
+ notificationsOneTimeKeys: notificationsOneTimeKeys,
};
},
async validateAndUploadPrekeys(authMetadata: AuthMetadata): Promise<void> {
diff --git a/native/identity-service/identity-service-context-provider.react.js b/native/identity-service/identity-service-context-provider.react.js
--- a/native/identity-service/identity-service-context-provider.react.js
+++ b/native/identity-service/identity-service-context-provider.react.js
@@ -3,7 +3,6 @@
import * as React from 'react';
import { useInvalidCSATLogOut } from 'lib/actions/user-actions.js';
-import { getOneTimeKeyValues } from 'lib/shared/crypto-utils.js';
import { createAndSignSingletonDeviceList } from 'lib/shared/device-list-utils.js';
import { IdentityClientContext } from 'lib/shared/identity-client-context.js';
import type {
@@ -456,8 +455,8 @@
prekeys.contentPrekeySignature,
prekeys.notifPrekey,
prekeys.notifPrekeySignature,
- getOneTimeKeyValues(contentOneTimeKeys),
- getOneTimeKeyValues(notificationsOneTimeKeys),
+ contentOneTimeKeys,
+ notificationsOneTimeKeys,
fid ?? '',
JSON.stringify(initialDeviceList),
farcasterDCsToken ?? '',
@@ -498,8 +497,8 @@
prekeys.contentPrekeySignature,
prekeys.notifPrekey,
prekeys.notifPrekeySignature,
- getOneTimeKeyValues(contentOneTimeKeys),
- getOneTimeKeyValues(notificationsOneTimeKeys),
+ contentOneTimeKeys,
+ notificationsOneTimeKeys,
keyserverMessage,
keyserverSignature,
JSON.stringify(initialDeviceList),
@@ -531,8 +530,8 @@
prekeys.contentPrekeySignature,
prekeys.notifPrekey,
prekeys.notifPrekeySignature,
- getOneTimeKeyValues(contentOneTimeKeys),
- getOneTimeKeyValues(notificationsOneTimeKeys),
+ contentOneTimeKeys,
+ notificationsOneTimeKeys,
);
return await processAuthResult(
@@ -570,8 +569,8 @@
prekeys.contentPrekeySignature,
prekeys.notifPrekey,
prekeys.notifPrekeySignature,
- getOneTimeKeyValues(contentOneTimeKeys),
- getOneTimeKeyValues(notificationsOneTimeKeys),
+ contentOneTimeKeys,
+ notificationsOneTimeKeys,
fid ?? '',
JSON.stringify(initialDeviceList),
farcasterDCsToken ?? '',
@@ -607,8 +606,8 @@
prekeys.contentPrekeySignature,
prekeys.notifPrekey,
prekeys.notifPrekeySignature,
- getOneTimeKeyValues(contentOneTimeKeys),
- getOneTimeKeyValues(notificationsOneTimeKeys),
+ contentOneTimeKeys,
+ notificationsOneTimeKeys,
);
return await processAuthResult(
@@ -643,8 +642,8 @@
prekeys.contentPrekeySignature,
prekeys.notifPrekey,
prekeys.notifPrekeySignature,
- getOneTimeKeyValues(contentOneTimeKeys),
- getOneTimeKeyValues(notificationsOneTimeKeys),
+ contentOneTimeKeys,
+ notificationsOneTimeKeys,
JSON.stringify(deviceList),
backupSecret,
);
@@ -686,8 +685,8 @@
prekeys.contentPrekeySignature,
prekeys.notifPrekey,
prekeys.notifPrekeySignature,
- getOneTimeKeyValues(contentOneTimeKeys),
- getOneTimeKeyValues(notificationsOneTimeKeys),
+ contentOneTimeKeys,
+ notificationsOneTimeKeys,
);
return await processAuthResult(
diff --git a/native/schema/CommCoreModuleSchema.js b/native/schema/CommCoreModuleSchema.js
--- a/native/schema/CommCoreModuleSchema.js
+++ b/native/schema/CommCoreModuleSchema.js
@@ -11,7 +11,7 @@
import type { ClientDBReportStoreOperation } from 'lib/ops/report-store-ops.js';
import type { ClientDBThreadStoreOperation } from 'lib/ops/thread-store-ops.js';
import type {
- OneTimeKeysResult,
+ OneTimeKeysResultValues,
SignedPrekeys,
ClientPublicKeys,
EncryptedData,
@@ -58,7 +58,9 @@
) => Promise<void>;
+initializeCryptoAccount: () => Promise<string>;
+getUserPublicKey: () => Promise<ClientPublicKeys>;
- +getOneTimeKeys: (oneTimeKeysAmount: number) => Promise<OneTimeKeysResult>;
+ +getOneTimeKeys: (
+ oneTimeKeysAmount: number,
+ ) => Promise<OneTimeKeysResultValues>;
+validateAndGetPrekeys: () => Promise<SignedPrekeys>;
+validateAndUploadPrekeys: (
authUserID: string,

File Metadata

Mime Type
text/plain
Expires
Sat, Dec 6, 7:00 AM (21 h, 12 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
5829083
Default Alt Text
D15550.1765004424.diff (65 KB)

Event Timeline