Skip to content

Conversation

@xsanm
Copy link
Collaborator

@xsanm xsanm commented Dec 2, 2025

Summary:
ENG-11531.

Making Vodozemac available on native.

Depends on D15549

Test Plan: Test encrypt/decrypt and create a session with Olm and Vodozemac.

Reviewers: ashoat

Subscribers: tomek

Differential Revision: https://phab.comm.dev/D15550

@xsanm xsanm requested a review from Ashoat December 2, 2025 16:03
@CLAassistant
Copy link

CLA assistant check
Thank you for your submission! We really appreciate it. Like many open source projects, we ask that you sign our Contributor License Agreement before we can accept your contribution.
You have signed the CLA already but the status is still pending? Let us recheck it.

@xsanm xsanm force-pushed the vodozemac-work-part-4 branch 2 times, most recently from 6018853 to 865c668 Compare December 3, 2025 16:15
@xsanm xsanm force-pushed the vodozemac-work-part-5 branch from a811562 to 58cb6e6 Compare December 3, 2025 16:17
@xsanm xsanm force-pushed the vodozemac-work-part-4 branch 2 times, most recently from de66670 to de276f7 Compare December 3, 2025 16:58
Copy link
Member

@Ashoat Ashoat left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Only got through CryptoModule

} else {
CryptoModule::CryptoModule(std::string secretKey, Persist persist)
: vodozemacAccount(::account_new()) {
this->secretKey = secretKey;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why do we need this? I can't find where it's used

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Removing

for (const auto &key : oneTimeKeysVec) {
this->keys.oneTimeKeys.push_back(std::string(key));
}
return ::olm_account_mark_keys_as_published(this->getOlmAccount());
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is a slight difference here it seems... previously we returned the result of olm_account_mark_keys_as_published, but now we return oneTimeKeysVec.size. Are these always the same?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is because mark_keys_as_published in vodozemac is returning void, but the values should be the same

Comment on lines 102 to 103
folly::dynamic identityKeysObj = folly::parseJson(this->getIdentityKeys());
std::string signingPublicKey = identityKeysObj["ed25519"].asString();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why'd we get rid of getSigningPublicKey? We seem to be doing the same thing here, but I guess with less robust error handling. I guess we didn't need the error handling here?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That was strange. I am reintroducing getSigningPublicKey

Comment on lines 103 to 106
std::string signingPublicKey = identityKeysObj["ed25519"].asString();

std::string prekey = this->getPrekey();
std::string prekeySignature = this->getPrekeySignature();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why'd you remove the const keyword from these declarations?

std::string rawMessage{e.what()};
if (rawMessage.find("BAD_MESSAGE_MAC") != std::string::npos) {
if (rawMessage.find("BAD_MESSAGE_MAC") != std::string::npos ||
rawMessage.find("Signature") != std::string::npos) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The same issue with checking Signature as in a prior PR

random.data(),
random.size())) {
throw std::runtime_error{
"error generateOneTimeKeys => " +
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are we no longer handling this error generateOneTimeKeys?

try {
std::string unpublished =
std::string(this->vodozemacAccount->unpublished_prekey());
if (unpublished.empty()) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add a comment explaining why we use the empty string

idKeys);

auto [newSession, plaintext] = Session::createSessionAsResponder(
this->vodozemacAccount, encryptedData, idKeys);
Copy link
Member

@Ashoat Ashoat Dec 3, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why don't we need to pass this->keys.identityKeys.data() anymore?

EDIT – looking at Session.cpp, it apparently wasn't even used before. Feel free to ignore this comment

this->vodozemacAccount, encryptedData, idKeys);
newSession->setVersion(sessionVersion);
this->sessions.insert(make_pair(targetDeviceId, std::move(newSession)));
return plaintext;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why do we return plaintext now?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Previously (C++ Olm), create_inbound_session was creating the session only, and we had to decrypt the initial message separately; it was done in CommCoreModule. In Vodoezmac, decryption is part of create_inbound_session, so we have to return 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());
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why do we still need to use OlmBuffer? Is this type from inside of the old Olm library? Will it prevent us from removing that library?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OlmBuffer is just an alias for std::vector<std::uint8_t>:

typedef std::vector<std::uint8_t> OlmBuffer;

account->create_outbound_session(
curve25519Key,
ed25519Key,
oneTimeKey.value_or(""),
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would be good to add a comment here explaining why we use the empty string

static_cast<uint32_t>(encryptedData.messageType)));
} catch (const std::exception &e) {
throw std::runtime_error(
"error decrypt => " + olmErrorFlag + " " + std::string(e.what()));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We used to print the message hash here in this error, but we don't anymore. Did we add the message hash previously because it helped with debugging? Is it difficult to reintroduce?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Did we add the message hash previously because it helped with debugging?

I don't know, but I think so, perhaps when having some issues with notifications in the past.

Reintroduced

int version;

public:
::rust::Box<::VodozemacSession> vodozemacSession;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why does this need to be public?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It was because we used it in:

isSenderChainEmpty = maybeSessionWithPicklingKey.value()
.first->vodozemacSession->is_sender_chain_empty();
hasReceivedMessage = maybeSessionWithPicklingKey.value()
.first->vodozemacSession->has_received_message();

I implemented methods for isSenderChainEmpty and hasReceivedMessage and updated vodozemacSession to be private

@@ -1,6 +1,5 @@
// @flow

import { getOneTimeKeyValues } from 'lib/shared/crypto-utils.js';
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is getOneTimeKeyValues used anywhere anymore?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is used as part of getOneTimeKeyValuesFromBlob, which is used to parse the result from getOlmSessionInitializationDataResponder endpoint (this endpoint has to still support old format for older clients, as we discussed yesterday)

import type { ClientDBReportStoreOperation } from 'lib/ops/report-store-ops.js';
import type { ClientDBThreadStoreOperation } from 'lib/ops/thread-store-ops.js';
import type {
OneTimeKeysResult,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is the OneTimeKeysResult type used anywhere anymore? Can it be removed?

@Ashoat
Copy link
Member

Ashoat commented Dec 4, 2025

I reviewed only the final commit, as this branch needs to be rebased on #323's branch

@xsanm xsanm changed the base branch from vodozemac-work-part-4 to vodozemac-work-part-1 December 4, 2025 10:03
@xsanm xsanm force-pushed the vodozemac-work-part-5 branch 2 times, most recently from 3b4513a to e4858cf Compare December 4, 2025 11:08
const OlmBuffer prekeyBytes = Base64::decode(prekey);
try {
this->verifySignature(signingPublicKey, prekeyBytes, preKeySignature);
std::string signingPublicKey = getSigningPublicKey(this->getIdentityKeys());
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

const was still removed here

Summary:
[ENG-11531](https://linear.app/comm/issue/ENG-11531/migrate-the-full-crypto-api-to-vodozemac).

Making vodozemac available on native.

Depends on D15549

Test Plan: Test encrypt/decrypt and creating session with Olm and Vodozemac.

Reviewers: ashoat

Subscribers: tomek

Differential Revision: https://phab.comm.dev/D15550
@xsanm xsanm force-pushed the vodozemac-work-part-5 branch from e4858cf to b943500 Compare December 4, 2025 11:24
@xsanm
Copy link
Collaborator Author

xsanm commented Dec 4, 2025

I triggered CI in ac50bc4 to make sure it passes before merging to master

@Ashoat Ashoat merged commit c234a98 into vodozemac-work-part-1 Dec 4, 2025
@Ashoat Ashoat deleted the vodozemac-work-part-5 branch December 4, 2025 11:43
xsanm added a commit that referenced this pull request Dec 4, 2025
Summary:
[ENG-11531](https://linear.app/comm/issue/ENG-11531/migrate-the-full-crypto-api-to-vodozemac).

Making vodozemac available on native.

Depends on D15549

Test Plan: Test encrypt/decrypt and creating session with Olm and Vodozemac.

Reviewers: ashoat

Subscribers: tomek

Differential Revision: https://phab.comm.dev/D15550
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants