Page Menu
Home
Phorge
Search
Configure Global Search
Log In
Files
F85804936
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Award Token
Flag For Later
Size
20 KB
Referenced Files
None
Subscribers
None
View Options
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
Details
Attached
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)
Attached To
Mode
rVB vodozemac-bindings
Attached
Detach File
Event Timeline
Log In to Comment