Page MenuHomePhorge

No OneTemporary

Size
20 KB
Referenced Files
None
Subscribers
None
diff --git a/cpp/Makefile b/cpp/Makefile
index 827caad..9987f50 100644
--- a/cpp/Makefile
+++ b/cpp/Makefile
@@ -1,63 +1,64 @@
rust-lib:
cargo build
account-test: rust-lib tests/account.cpp
g++ \
-Wall -g \
-pthread -std=c++17 \
tests/account.cpp \
-lgtest_main -lgtest \
-lolm -lboost_json \
-lpthread \
-I ../target/cxxbridge \
-L ../target/debug/ \
-l vodozemac \
-ldl \
-o account-test
session-test: rust-lib tests/session.cpp
g++ \
-Wall -g \
-pthread -std=c++17 \
tests/session.cpp \
-lgtest_main -lgtest \
-lolm -lboost_json \
-lpthread \
-I ../target/cxxbridge \
-L ../target/debug/ \
-l vodozemac \
-ldl \
-o session-test
sas-test: rust-lib tests/sas.cpp
g++ \
-Wall -g \
-pthread -std=c++17 \
tests/sas.cpp \
-lgtest_main -lgtest \
-lpthread \
-I ../target/cxxbridge \
-L ../target/debug/ \
-l vodozemac \
-ldl \
-o sas-test
group-session-test: rust-lib tests/group_session.cpp
g++ \
-Wall -g \
-pthread -std=c++17 \
tests/group_session.cpp \
-lgtest_main -lgtest \
+ -lolm -lboost_json \
-lpthread \
-I ../target/cxxbridge \
-L ../target/debug/ \
-l vodozemac \
-ldl \
-o group-session-test
test: account-test session-test sas-test group-session-test
./account-test --gtest_color=yes
./session-test --gtest_color=yes
./sas-test --gtest_color=yes
./group-session-test --gtest_color=yes
diff --git a/cpp/src/group_sessions.rs b/cpp/src/group_sessions.rs
index 70ca747..89655c5 100644
--- a/cpp/src/group_sessions.rs
+++ b/cpp/src/group_sessions.rs
@@ -1,135 +1,148 @@
use super::ffi::DecryptedMessage;
use anyhow::{anyhow, Result};
pub struct GroupSession(vodozemac::megolm::GroupSession);
pub fn new_group_session() -> Box<GroupSession> {
GroupSession::new().into()
}
pub struct MegolmMessage(vodozemac::megolm::MegolmMessage);
pub fn megolm_message_from_base64(message: &str) -> Result<Box<MegolmMessage>> {
Ok(MegolmMessage(vodozemac::megolm::MegolmMessage::from_base64(message)?).into())
}
impl MegolmMessage {
pub fn to_base64(&self) -> String {
self.0.to_base64()
}
}
pub struct SessionKey(vodozemac::megolm::SessionKey);
pub fn session_key_from_base64(message: &str) -> Result<Box<SessionKey>> {
Ok(SessionKey(vodozemac::megolm::SessionKey::from_base64(message)?).into())
}
impl SessionKey {
pub fn to_base64(&self) -> String {
self.0.to_base64()
}
}
pub struct ExportedSessionKey(vodozemac::megolm::ExportedSessionKey);
pub fn exported_session_key_from_base64(message: &str) -> Result<Box<ExportedSessionKey>> {
Ok(ExportedSessionKey(vodozemac::megolm::ExportedSessionKey::from_base64(message)?).into())
}
impl ExportedSessionKey {
pub fn to_base64(&self) -> String {
self.0.to_base64()
}
}
impl GroupSession {
fn new() -> Self {
Self(vodozemac::megolm::GroupSession::new(vodozemac::megolm::SessionConfig::version_1()))
}
pub fn session_id(&self) -> String {
self.0.session_id()
}
pub fn message_index(&self) -> u32 {
self.0.message_index()
}
pub fn session_key(&self) -> Box<SessionKey> {
SessionKey(self.0.session_key()).into()
}
pub fn encrypt(&mut self, plaintext: &str) -> Box<MegolmMessage> {
MegolmMessage(self.0.encrypt(plaintext)).into()
}
pub fn pickle(&self, pickle_key: &[u8; 32]) -> String {
self.0.pickle().encrypt(pickle_key)
}
}
pub fn group_session_from_pickle(pickle: &str, pickle_key: &[u8; 32]) -> Result<Box<GroupSession>> {
let pickle = vodozemac::megolm::GroupSessionPickle::from_encrypted(pickle, pickle_key)?;
Ok(GroupSession(vodozemac::megolm::GroupSession::from_pickle(pickle)).into())
}
+pub fn group_session_from_libolm_pickle(pickle: &str, pickle_key: &[u8]) -> Result<Box<GroupSession>> {
+ let res = vodozemac::megolm::GroupSession::from_libolm_pickle(pickle, pickle_key)?;
+ Ok(GroupSession(res).into())
+}
+
pub struct InboundGroupSession(vodozemac::megolm::InboundGroupSession);
pub fn new_inbound_group_session(session_key: &SessionKey) -> Box<InboundGroupSession> {
InboundGroupSession::new(session_key).into()
}
pub fn import_inbound_group_session(session_key: &ExportedSessionKey) -> Box<InboundGroupSession> {
InboundGroupSession::import(session_key).into()
}
pub fn inbound_group_session_from_pickle(
pickle: &str,
pickle_key: &[u8; 32],
) -> Result<Box<InboundGroupSession>> {
let pickle = vodozemac::megolm::InboundGroupSessionPickle::from_encrypted(pickle, pickle_key)?;
Ok(InboundGroupSession(vodozemac::megolm::InboundGroupSession::from_pickle(pickle)).into())
}
+pub fn inbound_group_session_from_libolm_pickle(
+ pickle: &str,
+ pickle_key: &[u8],
+) -> Result<Box<InboundGroupSession>> {
+ let res = vodozemac::megolm::InboundGroupSession::from_libolm_pickle(pickle, pickle_key)?;
+ Ok(InboundGroupSession(res).into())
+}
+
impl InboundGroupSession {
fn new(session_key: &SessionKey) -> Self {
Self(vodozemac::megolm::InboundGroupSession::new(&session_key.0, vodozemac::megolm::SessionConfig::version_1()))
}
fn import(session_key: &ExportedSessionKey) -> Self {
Self(vodozemac::megolm::InboundGroupSession::import(
&session_key.0,
vodozemac::megolm::SessionConfig::version_1(),
))
}
pub fn session_id(&self) -> String {
self.0.session_id()
}
pub fn first_known_index(&self) -> u32 {
self.0.first_known_index()
}
pub fn export_at(&mut self, index: u32) -> Result<Box<ExportedSessionKey>> {
self.0
.export_at(index)
.map(ExportedSessionKey)
.map(Box::new)
.ok_or_else(|| anyhow!("Unknown message index"))
}
pub fn decrypt(&mut self, message: &MegolmMessage) -> Result<DecryptedMessage> {
let ret = self.0.decrypt(&message.0)?;
Ok(DecryptedMessage {
plaintext: ret.plaintext,
message_index: ret.message_index,
})
}
pub fn pickle(&self, pickle_key: &[u8; 32]) -> String {
self.0.pickle().encrypt(pickle_key)
}
}
diff --git a/cpp/src/lib.rs b/cpp/src/lib.rs
index 03f2d12..2087876 100644
--- a/cpp/src/lib.rs
+++ b/cpp/src/lib.rs
@@ -1,178 +1,186 @@
mod account;
mod group_sessions;
mod sas;
mod session;
mod types;
use account::{account_from_pickle, account_from_libolm_pickle, new_account, olm_message_from_parts, Account, OlmMessage};
use group_sessions::{
- exported_session_key_from_base64, group_session_from_pickle, import_inbound_group_session,
- inbound_group_session_from_pickle, megolm_message_from_base64, new_group_session,
+ exported_session_key_from_base64, group_session_from_pickle, group_session_from_libolm_pickle, import_inbound_group_session,
+ inbound_group_session_from_pickle, inbound_group_session_from_libolm_pickle, megolm_message_from_base64, new_group_session,
new_inbound_group_session, session_key_from_base64, ExportedSessionKey, GroupSession,
InboundGroupSession, MegolmMessage, SessionKey,
};
use sas::{mac_from_base64, new_sas, EstablishedSas, Mac, Sas, SasBytes};
use session::{session_from_pickle, session_from_libolm_pickle, Session};
use types::{
curve_key_from_base64, ed25519_key_from_base64, Curve25519PublicKey, Ed25519PublicKey,
Ed25519Signature,
};
#[cxx::bridge]
mod ffi {
#[namespace = "olm"]
struct OlmMessageParts {
message_type: usize,
ciphertext: String,
}
#[namespace = "olm"]
pub struct InboundCreationResult {
pub session: Box<Session>,
pub plaintext: Vec<u8>,
}
#[namespace = "olm"]
struct OneTimeKey {
key_id: String,
key: Box<Curve25519PublicKey>,
}
#[namespace = "olm"]
#[derive(PartialEq, Eq)]
struct SessionKeys {
identity_key: Box<Curve25519PublicKey>,
base_key: Box<Curve25519PublicKey>,
one_time_key: Box<Curve25519PublicKey>,
}
#[namespace = "types"]
extern "Rust" {
type Curve25519PublicKey;
fn curve_key_from_base64(key: &str) -> Result<Box<Curve25519PublicKey>>;
fn to_base64(self: &Curve25519PublicKey) -> String;
type Ed25519PublicKey;
fn ed25519_key_from_base64(key: &str) -> Result<Box<Ed25519PublicKey>>;
fn to_base64(self: &Ed25519PublicKey) -> String;
type Ed25519Signature;
}
#[namespace = "olm"]
extern "Rust" {
type Account;
fn new_account() -> Box<Account>;
fn ed25519_key(self: &Account) -> Box<Ed25519PublicKey>;
fn curve25519_key(self: &Account) -> Box<Curve25519PublicKey>;
fn sign(self: &Account, message: &str) -> Box<Ed25519Signature>;
fn generate_one_time_keys(self: &mut Account, count: usize);
fn one_time_keys(self: &Account) -> Vec<OneTimeKey>;
fn generate_fallback_key(self: &mut Account);
fn fallback_key(self: &Account) -> Vec<OneTimeKey>;
fn mark_keys_as_published(self: &mut Account);
fn max_number_of_one_time_keys(self: &Account) -> usize;
fn account_from_pickle(pickle: &str, pickle_key: &[u8; 32]) -> Result<Box<Account>>;
fn account_from_libolm_pickle(pickle: &str, pickle_key: &[u8]) -> Result<Box<Account>>;
fn pickle(self: &Account, pickle_key: &[u8; 32]) -> String;
fn create_outbound_session(
self: &Account,
identity_key: &Curve25519PublicKey,
one_time_key: &Curve25519PublicKey,
) -> Result<Box<Session>>;
fn create_inbound_session(
self: &mut Account,
identity_key: &Curve25519PublicKey,
message: &OlmMessage,
) -> Result<InboundCreationResult>;
type Session;
fn session_id(self: &Session) -> String;
fn session_keys(self: &Session) -> SessionKeys;
fn session_matches(self: &Session, message: &OlmMessage) -> bool;
fn encrypt(self: &mut Session, plaintext: &str) -> Box<OlmMessage>;
fn decrypt(self: &mut Session, message: &OlmMessage) -> Result<Vec<u8>>;
fn session_from_pickle(pickle: &str, pickle_key: &[u8; 32]) -> Result<Box<Session>>;
fn session_from_libolm_pickle(pickle: &str, pickle_key: &[u8]) -> Result<Box<Session>>;
fn pickle(self: &Session, pickle_key: &[u8; 32]) -> String;
type OlmMessage;
fn to_parts(self: &OlmMessage) -> OlmMessageParts;
fn olm_message_from_parts(parts: &OlmMessageParts) -> Result<Box<OlmMessage>>;
}
#[namespace = "megolm"]
struct DecryptedMessage {
plaintext: Vec<u8>,
message_index: u32,
}
#[namespace = "megolm"]
extern "Rust" {
type MegolmMessage;
fn megolm_message_from_base64(message: &str) -> Result<Box<MegolmMessage>>;
fn to_base64(self: &MegolmMessage) -> String;
type SessionKey;
fn session_key_from_base64(key: &str) -> Result<Box<SessionKey>>;
fn to_base64(self: &SessionKey) -> String;
type ExportedSessionKey;
fn exported_session_key_from_base64(key: &str) -> Result<Box<ExportedSessionKey>>;
fn to_base64(self: &ExportedSessionKey) -> String;
type GroupSession;
fn new_group_session() -> Box<GroupSession>;
fn encrypt(self: &mut GroupSession, plaintext: &str) -> Box<MegolmMessage>;
fn session_id(self: &GroupSession) -> String;
fn session_key(self: &GroupSession) -> Box<SessionKey>;
fn message_index(self: &GroupSession) -> u32;
fn pickle(self: &GroupSession, pickle_key: &[u8; 32]) -> String;
fn group_session_from_pickle(
pickle: &str,
pickle_key: &[u8; 32],
) -> Result<Box<GroupSession>>;
+ fn group_session_from_libolm_pickle(
+ pickle: &str,
+ pickle_key: &[u8],
+ ) -> Result<Box<GroupSession>>;
type InboundGroupSession;
fn new_inbound_group_session(session_key: &SessionKey) -> Box<InboundGroupSession>;
fn import_inbound_group_session(
session_key: &ExportedSessionKey,
) -> Box<InboundGroupSession>;
fn decrypt(
self: &mut InboundGroupSession,
message: &MegolmMessage,
) -> Result<DecryptedMessage>;
fn session_id(self: &InboundGroupSession) -> String;
fn first_known_index(self: &InboundGroupSession) -> u32;
fn export_at(
self: &mut InboundGroupSession,
message_index: u32,
) -> Result<Box<ExportedSessionKey>>;
fn pickle(self: &InboundGroupSession, pickle_key: &[u8; 32]) -> String;
fn inbound_group_session_from_pickle(
pickle: &str,
pickle_key: &[u8; 32],
) -> Result<Box<InboundGroupSession>>;
+ fn inbound_group_session_from_libolm_pickle(
+ pickle: &str,
+ pickle_key: &[u8],
+ ) -> Result<Box<InboundGroupSession>>;
}
#[namespace = "sas"]
extern "Rust" {
type Mac;
fn mac_from_base64(mac: &str) -> Result<Box<Mac>>;
fn to_base64(self: &Mac) -> String;
type Sas;
fn new_sas() -> Box<Sas>;
fn public_key(self: &Sas) -> Box<Curve25519PublicKey>;
fn diffie_hellman(
self: &mut Sas,
other_public_key: &Curve25519PublicKey,
) -> Result<Box<EstablishedSas>>;
type EstablishedSas;
fn bytes(self: &EstablishedSas, info: &str) -> Box<SasBytes>;
fn calculate_mac(self: &EstablishedSas, input: &str, info: &str) -> Box<Mac>;
fn verify_mac(self: &EstablishedSas, input: &str, info: &str, mac: &Mac) -> Result<()>;
type SasBytes;
fn emoji_indices(self: &SasBytes) -> [u8; 7];
fn decimals(self: &SasBytes) -> [u16; 3];
}
}
diff --git a/cpp/tests/group_session.cpp b/cpp/tests/group_session.cpp
index 6ee51d6..f06c198 100644
--- a/cpp/tests/group_session.cpp
+++ b/cpp/tests/group_session.cpp
@@ -1,120 +1,184 @@
#include "../../target/cxxbridge/vodozemac/src/lib.rs.h"
+#include <olm/outbound_group_session.h>
+#include <olm/inbound_group_session.h>
#include "gtest/gtest.h"
#include "util.hpp"
using namespace rust;
struct SessionCreationResult {
Box<megolm::GroupSession> outbound;
Box<megolm::InboundGroupSession> inbound;
};
SessionCreationResult create_session() {
auto outbound = megolm::new_group_session();
auto session_key = outbound->session_key();
auto inbound = megolm::new_inbound_group_session(*session_key);
auto ret = SessionCreationResult{
std::move(outbound),
std::move(inbound),
};
return ret;
}
+struct LibolmSessionCreationResult {
+ std::vector<uint8_t> outbound_data;
+ OlmOutboundGroupSession *outbound;
+ std::vector<uint8_t> inbound_data;
+ OlmInboundGroupSession *inbound;
+};
+
+LibolmSessionCreationResult create_libolm_session() {
+ LibolmSessionCreationResult res{
+ std::vector<uint8_t>(olm_outbound_group_session_size()),
+ 0,
+ std::vector<uint8_t>(olm_inbound_group_session_size()),
+ 0,
+ };
+
+ res.outbound = olm_outbound_group_session(res.outbound_data.data());
+ auto random = gen_random(olm_init_outbound_group_session_random_length(res.outbound));
+ check_olm_error(olm_init_outbound_group_session(res.outbound, random.data(), random.size()));
+ auto session_key = std::vector<uint8_t>(olm_outbound_group_session_key_length(res.outbound));
+ check_olm_error(olm_outbound_group_session_key(res.outbound, session_key.data(), session_key.size()));
+
+ res.inbound = olm_inbound_group_session(res.inbound_data.data());
+ olm_init_inbound_group_session(res.inbound, session_key.data(), session_key.size());
+ return res;
+}
+
TEST(GroupSessionTest, Creation) {
auto [outbound, inbound] = create_session();
auto outbound_id = outbound->session_id();
auto inbound_id = inbound->session_id();
EXPECT_NE(outbound_id.length(), 0);
EXPECT_STREQ(outbound_id.c_str(), inbound_id.c_str());
}
TEST(GroupSessionTest, MessageIndex) {
auto [outbound, inbound] = create_session();
EXPECT_EQ(outbound->message_index(), 0);
EXPECT_EQ(inbound->first_known_index(), 0);
outbound->encrypt("Hello");
auto inbound2 = megolm::new_inbound_group_session(*outbound->session_key());
EXPECT_EQ(outbound->message_index(), 1);
EXPECT_EQ(inbound2->first_known_index(), 1);
}
TEST(GroupSessionTest, Pickle) {
auto session = megolm::new_group_session();
auto pickle = session->pickle(PICKLE_KEY);
auto unpickled = megolm::group_session_from_pickle(pickle, PICKLE_KEY);
ASSERT_STREQ(session->session_id().c_str(), unpickled->session_id().c_str());
EXPECT_EQ(session->message_index(), unpickled->message_index());
}
+TEST(GroupSessionTest, PickleLibolm) {
+ auto [_1, outbound, _2, inbound] = create_libolm_session();
+
+ auto pickle = std::string(olm_pickle_outbound_group_session_length(outbound), '\0');
+ check_olm_error(olm_pickle_outbound_group_session(outbound, OLM_PICKLE_KEY.data(), OLM_PICKLE_KEY.size(), pickle.data(), pickle.size()));
+ auto unpickled = megolm::group_session_from_libolm_pickle(String(pickle), Slice<const unsigned char>(OLM_PICKLE_KEY.data(), OLM_PICKLE_KEY.size()));
+
+ auto session_id = std::vector<uint8_t>(olm_outbound_group_session_id_length(outbound));
+ check_olm_error(olm_outbound_group_session_id(outbound, session_id.data(), session_id.size()));
+
+ ASSERT_EQ(as_std_string(session_id), static_cast<std::string>(unpickled->session_id()));
+
+ auto message_index = olm_outbound_group_session_message_index(outbound);
+
+ EXPECT_EQ(message_index, unpickled->message_index());
+}
+
TEST(GroupSessionTest, PickleInbound) {
auto [outbound, inbound] = create_session();
auto pickle = inbound->pickle(PICKLE_KEY);
auto unpickled =
megolm::inbound_group_session_from_pickle(pickle, PICKLE_KEY);
ASSERT_STREQ(inbound->session_id().c_str(), unpickled->session_id().c_str());
EXPECT_EQ(inbound->first_known_index(), unpickled->first_known_index());
}
+TEST(GroupSessionTest, PickleInboundLibolm) {
+ auto [_1, outbound, _2, inbound] = create_libolm_session();
+
+ auto pickle = std::string(olm_pickle_inbound_group_session_length(inbound), '\0');
+ check_olm_error(olm_pickle_inbound_group_session(inbound, OLM_PICKLE_KEY.data(), OLM_PICKLE_KEY.size(), pickle.data(), pickle.size()));
+
+ auto unpickled =
+ megolm::inbound_group_session_from_libolm_pickle(pickle, Slice<const unsigned char>(OLM_PICKLE_KEY.data(), OLM_PICKLE_KEY.size()));
+
+ auto session_id = std::vector<uint8_t>(olm_inbound_group_session_id_length(inbound));
+ check_olm_error(olm_inbound_group_session_id(inbound, session_id.data(), session_id.size()));
+
+ ASSERT_EQ(as_std_string(session_id), static_cast<std::string>(unpickled->session_id()));
+
+ auto first_known_index = olm_inbound_group_session_first_known_index(inbound);
+
+ EXPECT_EQ(first_known_index, unpickled->first_known_index());
+}
+
TEST(GroupSessionTest, UnpicklingFail) {
EXPECT_ANY_THROW(megolm::group_session_from_pickle("", PICKLE_KEY));
EXPECT_ANY_THROW(megolm::inbound_group_session_from_pickle("", PICKLE_KEY));
}
TEST(GroupSessionTest, DecryptionFail) {
auto [outbound, inbound] = create_session();
auto outbound2 = megolm::new_group_session();
auto message = outbound2->encrypt("Hello");
EXPECT_ANY_THROW(inbound->decrypt(*message));
}
TEST(GroupSessionTest, Encryption) {
auto [outbound, inbound] = create_session();
auto plaintext = "It's a secret to everybody";
auto message = outbound->encrypt(plaintext);
auto decrypted = inbound->decrypt(*message);
EXPECT_EQ(as_std_string(decrypted.plaintext), std::string(plaintext));
EXPECT_EQ(decrypted.message_index, 0);
plaintext = "Another secret";
message = outbound->encrypt(plaintext);
decrypted = inbound->decrypt(*message);
EXPECT_EQ(as_std_string(decrypted.plaintext), std::string(plaintext));
EXPECT_EQ(decrypted.message_index, 1);
}
TEST(GroupSessionTest, SessionExport) {
auto [outbound, inbound] = create_session();
auto imported = megolm::import_inbound_group_session(*inbound->export_at(0));
EXPECT_STREQ(outbound->session_id().c_str(), imported->session_id().c_str());
auto plaintext = "It's a secret to everybody";
auto message = outbound->encrypt(plaintext);
auto decrypted = imported->decrypt(*message);
EXPECT_EQ(as_std_string(decrypted.plaintext), std::string(plaintext));
EXPECT_EQ(decrypted.message_index, 0);
plaintext = "Another secret";
message = outbound->encrypt(plaintext);
decrypted = imported->decrypt(*message);
EXPECT_EQ(as_std_string(decrypted.plaintext), std::string(plaintext));
EXPECT_EQ(decrypted.message_index, 1);
}

File Metadata

Mime Type
text/x-diff
Expires
Sat, Oct 10, 6:41 PM (1 d, 5 h)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
1785394
Default Alt Text
(20 KB)

Event Timeline