From 23040a1bf7185a528de2ef1c0487e082c52d1d50 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Damir=20Jeli=C4=87?= Date: Mon, 28 Mar 2022 13:09:35 +0200 Subject: [PATCH] refactor(crypto): Use vodozemac types for the cross signing and device keys --- crates/matrix-qrcode/Cargo.toml | 4 + crates/matrix-qrcode/src/error.rs | 6 +- crates/matrix-qrcode/src/lib.rs | 16 ++- crates/matrix-qrcode/src/types.rs | 100 ++++++++-------- crates/matrix-qrcode/src/utils.rs | 25 ++-- .../src/gossiping/machine.rs | 10 +- .../src/identities/device.rs | 57 ++++++--- .../src/identities/manager.rs | 2 +- .../matrix-sdk-crypto/src/identities/user.rs | 75 +++++++----- crates/matrix-sdk-crypto/src/machine.rs | 5 +- crates/matrix-sdk-crypto/src/olm/account.rs | 41 ++----- .../src/olm/group_sessions/outbound.rs | 32 ++--- crates/matrix-sdk-crypto/src/olm/session.rs | 28 +++-- .../matrix-sdk-crypto/src/olm/signing/mod.rs | 3 +- .../src/olm/signing/pk_signing.rs | 7 +- crates/matrix-sdk-crypto/src/requests.rs | 2 +- .../src/session_manager/sessions.rs | 6 +- crates/matrix-sdk-crypto/src/store/caches.rs | 8 +- .../src/store/integration_tests.rs | 4 +- .../src/store/memorystore.rs | 2 +- crates/matrix-sdk-crypto/src/store/mod.rs | 15 ++- .../src/types/cross_signing_key.rs | 90 +++++++++++++- .../src/types/device_keys.rs | 112 +++++++++++++++++- crates/matrix-sdk-crypto/src/types/mod.rs | 21 +++- .../src/types/one_time_keys.rs | 10 -- .../src/verification/qrcode.rs | 67 +++++------ .../src/verification/requests.rs | 6 +- .../src/verification/sas/helpers.rs | 18 +-- .../matrix-sdk-indexeddb/src/cryptostore.rs | 4 +- crates/matrix-sdk-sled/src/cryptostore.rs | 5 +- .../src/encryption/identities/users.rs | 2 +- 31 files changed, 500 insertions(+), 283 deletions(-) diff --git a/crates/matrix-qrcode/Cargo.toml b/crates/matrix-qrcode/Cargo.toml index f897ebeaa..94ff40c8a 100644 --- a/crates/matrix-qrcode/Cargo.toml +++ b/crates/matrix-qrcode/Cargo.toml @@ -28,3 +28,7 @@ ruma-identifiers = "0.22.0" ruma-serde = "0.6.0" rqrr = { version = "0.4.0", optional = true } thiserror = "1.0.25" + +[dependencies.vodozemac] +git = "https://github.com/matrix-org/vodozemac" +rev = "16fb254aa3325c61ef949314c81c35f91d0664e1" diff --git a/crates/matrix-qrcode/src/error.rs b/crates/matrix-qrcode/src/error.rs index e487addd9..307038af1 100644 --- a/crates/matrix-qrcode/src/error.rs +++ b/crates/matrix-qrcode/src/error.rs @@ -42,6 +42,9 @@ pub enum DecodingError { /// The QR code data uses an invalid or unsupported version. #[error("the QR code contains an invalid or unsupported version: {0}")] Version(u8), + /// The QR code data doesn't contain valid ed25519 keys. + #[error("the QR code contains invalid ed25519 keys: {0}")] + Keys(#[from] vodozemac::KeyError), } /// Error type describing errors that happen while QR data is being encoded. @@ -51,9 +54,6 @@ pub enum EncodingError { /// doesn't fit into a QR code. #[error(transparent)] Qr(#[from] qrcode::types::QrError), - /// Error decoding the identity keys as base64. - #[error(transparent)] - Base64(#[from] base64::DecodeError), /// Error encoding the given flow id, the flow id is too large. #[error("The verification flow id length can't be converted into a u16: {0}")] FlowId(#[from] std::num::TryFromIntError), diff --git a/crates/matrix-qrcode/src/lib.rs b/crates/matrix-qrcode/src/lib.rs index e7323db63..af7a0f457 100644 --- a/crates/matrix-qrcode/src/lib.rs +++ b/crates/matrix-qrcode/src/lib.rs @@ -187,11 +187,23 @@ mod test { let data = b"MATRIX\ \x02\x00\x00\x0f\ test:localhost\ - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\ - BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB\ + kS /\x92i\x1e6\xcd'g\xf9#\x11\xd8\x8a\xa2\xf61\x05\x1b6\xef\xfc\xa4%\x80\x1a\x0c\xd2\xe8\x04\ + \xbdR|\xf8n\x07\xa4\x1f\xb4\xcc3\x0eBT\xe7[~\xfd\x87\xd06B\xdfoVv%\x9b\x86\xae\xbcM\ SECRETISLONGENOUGH"; let result = QrVerificationData::from_bytes(data); assert!(matches!(result, Err(DecodingError::Identifier(_)))) } + + #[test] + fn decode_invalid_keys() { + let data = b"MATRIX\ + \x02\x00\x00\x0f\ + !test:localhost\ + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\ + BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB\ + SECRETISLONGENOUGH"; + let result = QrVerificationData::from_bytes(data); + assert!(matches!(result, Err(DecodingError::Keys(_)))) + } } diff --git a/crates/matrix-qrcode/src/types.rs b/crates/matrix-qrcode/src/types.rs index 723205899..0f0609978 100644 --- a/crates/matrix-qrcode/src/types.rs +++ b/crates/matrix-qrcode/src/types.rs @@ -23,12 +23,13 @@ use image::{DynamicImage, GenericImage, GenericImageView, ImageBuffer, Luma}; use qrcode::QrCode; use ruma_identifiers::EventId; use ruma_serde::Base64; +use vodozemac::Ed25519PublicKey; #[cfg(feature = "decode_image")] use crate::utils::decode_qr; use crate::{ error::{DecodingError, EncodingError}, - utils::{base_64_encode, to_bytes, to_qr_code, HEADER, MAX_MODE, MIN_SECRET_LEN, VERSION}, + utils::{to_bytes, to_qr_code, HEADER, MAX_MODE, MIN_SECRET_LEN, VERSION}, }; /// An enum representing the different modes a QR verification can be in. @@ -150,8 +151,8 @@ impl QrVerificationData { /// let data = b"MATRIX\ /// \x02\x02\x00\x07\ /// FLOW_ID\ - /// AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\ - /// BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB\ + /// kS /\x92i\x1e6\xcd'g\xf9#\x11\xd8\x8a\xa2\xf61\x05\x1b6\xef\xfc\xa4%\x80\x1a\x0c\xd2\xe8\x04\ + /// \xbdR|\xf8n\x07\xa4\x1f\xb4\xcc3\x0eBT\xe7[~\xfd\x87\xd06B\xdfoVv%\x9b\x86\xae\xbcM\ /// SHARED_SECRET"; /// /// let result = QrVerificationData::from_bytes(data)?; @@ -178,8 +179,8 @@ impl QrVerificationData { /// let data = b"MATRIX\ /// \x02\x02\x00\x07\ /// FLOW_ID\ - /// AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\ - /// BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB\ + /// kS /\x92i\x1e6\xcd'g\xf9#\x11\xd8\x8a\xa2\xf61\x05\x1b6\xef\xfc\xa4%\x80\x1a\x0c\xd2\xe8\x04\ + /// \xbdR|\xf8n\x07\xa4\x1f\xb4\xcc3\x0eBT\xe7[~\xfd\x87\xd06B\xdfoVv%\x9b\x86\xae\xbcM\ /// SHARED_SECRET"; /// /// let result = QrVerificationData::from_bytes(data)?; @@ -208,8 +209,8 @@ impl QrVerificationData { /// let data = b"MATRIX\ /// \x02\x02\x00\x07\ /// FLOW_ID\ - /// AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\ - /// BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB\ + /// kS /\x92i\x1e6\xcd'g\xf9#\x11\xd8\x8a\xa2\xf61\x05\x1b6\xef\xfc\xa4%\x80\x1a\x0c\xd2\xe8\x04\ + /// \xbdR|\xf8n\x07\xa4\x1f\xb4\xcc3\x0eBT\xe7[~\xfd\x87\xd06B\xdfoVv%\x9b\x86\xae\xbcM\ /// SHARED_SECRET"; /// /// let result = QrVerificationData::from_bytes(data)?; @@ -289,6 +290,9 @@ impl QrVerificationData { return Err(DecodingError::SharedSecret(shared_secret.len())); } + let first_key = Ed25519PublicKey::from_slice(&first_key)?; + let second_key = Ed25519PublicKey::from_slice(&second_key)?; + QrVerificationData::new(mode, flow_id, first_key, second_key, shared_secret) } @@ -306,12 +310,10 @@ impl QrVerificationData { fn new( mode: u8, flow_id: Vec, - first_key: [u8; 32], - second_key: [u8; 32], + first_key: Ed25519PublicKey, + second_key: Ed25519PublicKey, shared_secret: Vec, ) -> Result { - let first_key = base_64_encode(&first_key); - let second_key = base_64_encode(&second_key); let flow_id = String::from_utf8(flow_id)?; let shared_secret = Base64::new(shared_secret); @@ -343,20 +345,20 @@ impl QrVerificationData { } /// Get the first key of this `QrVerificationData`. - pub fn first_key(&self) -> &str { + pub fn first_key(&self) -> Ed25519PublicKey { match self { - QrVerificationData::Verification(v) => &v.first_master_key, - QrVerificationData::SelfVerification(v) => &v.master_key, - QrVerificationData::SelfVerificationNoMasterKey(v) => &v.device_key, + QrVerificationData::Verification(v) => v.first_master_key, + QrVerificationData::SelfVerification(v) => v.master_key, + QrVerificationData::SelfVerificationNoMasterKey(v) => v.device_key, } } /// Get the second key of this `QrVerificationData`. - pub fn second_key(&self) -> &str { + pub fn second_key(&self) -> Ed25519PublicKey { match self { - QrVerificationData::Verification(v) => &v.second_master_key, - QrVerificationData::SelfVerification(v) => &v.device_key, - QrVerificationData::SelfVerificationNoMasterKey(v) => &v.master_key, + QrVerificationData::Verification(v) => v.second_master_key, + QrVerificationData::SelfVerification(v) => v.device_key, + QrVerificationData::SelfVerificationNoMasterKey(v) => v.master_key, } } @@ -377,8 +379,8 @@ impl QrVerificationData { #[derive(Clone, Debug, PartialEq)] pub struct VerificationData { event_id: Box, - first_master_key: String, - second_master_key: String, + first_master_key: Ed25519PublicKey, + second_master_key: Ed25519PublicKey, shared_secret: Base64, } @@ -400,8 +402,8 @@ impl VerificationData { /// needs to be at least 8 bytes long. pub fn new( event_id: Box, - first_key: String, - second_key: String, + first_key: Ed25519PublicKey, + second_key: Ed25519PublicKey, shared_secret: Base64, ) -> Self { Self { event_id, first_master_key: first_key, second_master_key: second_key, shared_secret } @@ -420,8 +422,8 @@ impl VerificationData { /// let data = b"MATRIX\ /// \x02\x00\x00\x0f\ /// $test:localhost\ - /// AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\ - /// BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB\ + /// kS /\x92i\x1e6\xcd'g\xf9#\x11\xd8\x8a\xa2\xf61\x05\x1b6\xef\xfc\xa4%\x80\x1a\x0c\xd2\xe8\x04\ + /// \xbdR|\xf8n\x07\xa4\x1f\xb4\xcc3\x0eBT\xe7[~\xfd\x87\xd06B\xdfoVv%\x9b\x86\xae\xbcM\ /// SHARED_SECRET"; /// /// let result = QrVerificationData::from_bytes(data)?; @@ -438,8 +440,8 @@ impl VerificationData { to_bytes( Self::QR_MODE, self.event_id.as_str(), - &self.first_master_key, - &self.second_master_key, + self.first_master_key, + self.second_master_key, &self.shared_secret, ) } @@ -455,8 +457,8 @@ impl VerificationData { to_qr_code( Self::QR_MODE, self.event_id.as_str(), - &self.first_master_key, - &self.second_master_key, + self.first_master_key, + self.second_master_key, &self.shared_secret, ) } @@ -476,8 +478,8 @@ impl From for QrVerificationData { #[derive(Clone, Debug, PartialEq)] pub struct SelfVerificationData { transaction_id: String, - master_key: String, - device_key: String, + master_key: Ed25519PublicKey, + device_key: Ed25519PublicKey, shared_secret: Base64, } @@ -503,8 +505,8 @@ impl SelfVerificationData { /// needs to be at least 8 bytes long. pub fn new( transaction_id: String, - master_key: String, - device_key: String, + master_key: Ed25519PublicKey, + device_key: Ed25519PublicKey, shared_secret: Base64, ) -> Self { Self { transaction_id, master_key, device_key, shared_secret } @@ -523,8 +525,8 @@ impl SelfVerificationData { /// let data = b"MATRIX\ /// \x02\x01\x00\x06\ /// FLOWID\ - /// AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\ - /// BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB\ + /// kS /\x92i\x1e6\xcd'g\xf9#\x11\xd8\x8a\xa2\xf61\x05\x1b6\xef\xfc\xa4%\x80\x1a\x0c\xd2\xe8\x04\ + /// \xbdR|\xf8n\x07\xa4\x1f\xb4\xcc3\x0eBT\xe7[~\xfd\x87\xd06B\xdfoVv%\x9b\x86\xae\xbcM\ /// SHARED_SECRET"; /// /// let result = QrVerificationData::from_bytes(data)?; @@ -541,8 +543,8 @@ impl SelfVerificationData { to_bytes( Self::QR_MODE, &self.transaction_id, - &self.master_key, - &self.device_key, + self.master_key, + self.device_key, &self.shared_secret, ) } @@ -558,8 +560,8 @@ impl SelfVerificationData { to_qr_code( Self::QR_MODE, &self.transaction_id, - &self.master_key, - &self.device_key, + self.master_key, + self.device_key, &self.shared_secret, ) } @@ -579,8 +581,8 @@ impl From for QrVerificationData { #[derive(Clone, Debug, PartialEq)] pub struct SelfVerificationNoMasterKey { transaction_id: String, - device_key: String, - master_key: String, + device_key: Ed25519PublicKey, + master_key: Ed25519PublicKey, shared_secret: Base64, } @@ -606,8 +608,8 @@ impl SelfVerificationNoMasterKey { /// needs to be at least 8 bytes long. pub fn new( transaction_id: String, - device_key: String, - master_key: String, + device_key: Ed25519PublicKey, + master_key: Ed25519PublicKey, shared_secret: Base64, ) -> Self { Self { transaction_id, device_key, master_key, shared_secret } @@ -626,8 +628,8 @@ impl SelfVerificationNoMasterKey { /// let data = b"MATRIX\ /// \x02\x02\x00\x06\ /// FLOWID\ - /// AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\ - /// BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB\ + /// kS /\x92i\x1e6\xcd'g\xf9#\x11\xd8\x8a\xa2\xf61\x05\x1b6\xef\xfc\xa4%\x80\x1a\x0c\xd2\xe8\x04\ + /// \xbdR|\xf8n\x07\xa4\x1f\xb4\xcc3\x0eBT\xe7[~\xfd\x87\xd06B\xdfoVv%\x9b\x86\xae\xbcM\ /// SHARED_SECRET"; /// /// let result = QrVerificationData::from_bytes(data)?; @@ -644,8 +646,8 @@ impl SelfVerificationNoMasterKey { to_bytes( Self::QR_MODE, &self.transaction_id, - &self.device_key, - &self.master_key, + self.device_key, + self.master_key, &self.shared_secret, ) } @@ -661,8 +663,8 @@ impl SelfVerificationNoMasterKey { to_qr_code( Self::QR_MODE, &self.transaction_id, - &self.device_key, - &self.master_key, + self.device_key, + self.master_key, &self.shared_secret, ) } diff --git a/crates/matrix-qrcode/src/utils.rs b/crates/matrix-qrcode/src/utils.rs index c0daf56ac..b2468cbc6 100644 --- a/crates/matrix-qrcode/src/utils.rs +++ b/crates/matrix-qrcode/src/utils.rs @@ -14,11 +14,11 @@ use std::convert::TryInto; -use base64::{decode_config, encode_config, STANDARD_NO_PAD}; #[cfg(feature = "decode_image")] use image::{GenericImage, GenericImageView, Luma}; use qrcode::{bits::Bits, EcLevel, QrCode, Version}; use ruma_serde::Base64; +use vodozemac::Ed25519PublicKey; #[cfg(feature = "decode_image")] use crate::error::DecodingError; @@ -29,35 +29,24 @@ pub(crate) const VERSION: u8 = 0x2; pub(crate) const MAX_MODE: u8 = 0x2; pub(crate) const MIN_SECRET_LEN: usize = 8; -pub(crate) fn base_64_encode(data: &[u8]) -> String { - encode_config(data, STANDARD_NO_PAD) -} - -pub(crate) fn base64_decode(data: &str) -> Result, base64::DecodeError> { - decode_config(data, STANDARD_NO_PAD) -} - pub(crate) fn to_bytes( mode: u8, flow_id: &str, - first_key: &str, - second_key: &str, + first_key: Ed25519PublicKey, + second_key: Ed25519PublicKey, shared_secret: &Base64, ) -> Result, EncodingError> { let flow_id_len: u16 = flow_id.len().try_into()?; let flow_id_len = flow_id_len.to_be_bytes(); - let first_key = base64_decode(first_key)?; - let second_key = base64_decode(second_key)?; - let data = [ HEADER, &[VERSION], &[mode], flow_id_len.as_ref(), flow_id.as_bytes(), - &first_key, - &second_key, + first_key.as_bytes(), + second_key.as_bytes(), shared_secret.as_bytes(), ] .concat(); @@ -68,8 +57,8 @@ pub(crate) fn to_bytes( pub(crate) fn to_qr_code( mode: u8, flow_id: &str, - first_key: &str, - second_key: &str, + first_key: Ed25519PublicKey, + second_key: Ed25519PublicKey, shared_secret: &Base64, ) -> Result { let data = to_bytes(mode, flow_id, first_key, second_key, shared_secret)?; diff --git a/crates/matrix-sdk-crypto/src/gossiping/machine.rs b/crates/matrix-sdk-crypto/src/gossiping/machine.rs index 27bd2994f..be1cf49f4 100644 --- a/crates/matrix-sdk-crypto/src/gossiping/machine.rs +++ b/crates/matrix-sdk-crypto/src/gossiping/machine.rs @@ -951,7 +951,7 @@ mod test { }, room_id, to_device::DeviceIdOrAllDevices, - user_id, DeviceId, DeviceKeyAlgorithm, RoomId, UserId, + user_id, DeviceId, RoomId, UserId, }; use super::{GossipMachine, KeyForwardDecision}; @@ -1277,7 +1277,7 @@ mod test { .mark_shared_with( bob_device.user_id(), bob_device.device_id(), - bob_device.get_key(DeviceKeyAlgorithm::Curve25519).unwrap(), + bob_device.curve25519_key().unwrap(), ) .await; assert!(machine.should_share_key(&bob_device, &inbound).await.is_ok()); @@ -1315,7 +1315,7 @@ mod test { .mark_shared_with( own_device.user_id(), own_device.device_id(), - own_device.get_key(DeviceKeyAlgorithm::Curve25519).unwrap(), + own_device.curve25519_key().unwrap(), ) .await; @@ -1378,7 +1378,7 @@ mod test { .mark_shared_with( alice_device.user_id(), alice_device.device_id(), - alice_device.get_key(DeviceKeyAlgorithm::Curve25519).unwrap(), + alice_device.curve25519_key().unwrap(), ) .await; @@ -1582,7 +1582,7 @@ mod test { .mark_shared_with( alice_device.user_id(), alice_device.device_id(), - alice_device.get_key(DeviceKeyAlgorithm::Curve25519).unwrap(), + alice_device.curve25519_key().unwrap(), ) .await; diff --git a/crates/matrix-sdk-crypto/src/identities/device.rs b/crates/matrix-sdk-crypto/src/identities/device.rs index 45f4cbc3c..5c26b567e 100644 --- a/crates/matrix-sdk-crypto/src/identities/device.rs +++ b/crates/matrix-sdk-crypto/src/identities/device.rs @@ -36,7 +36,7 @@ use ruma::{ use serde::{Deserialize, Deserializer, Serialize, Serializer}; use serde_json::{json, Value}; use tracing::warn; -use vodozemac::Ed25519PublicKey; +use vodozemac::{Curve25519PublicKey, Ed25519PublicKey}; use super::{atomic_bool_deserializer, atomic_bool_serializer}; use crate::{ @@ -44,7 +44,7 @@ use crate::{ identities::{ReadOnlyOwnUserIdentity, ReadOnlyUserIdentities}, olm::{InboundGroupSession, Session, VerifyJson}, store::{Changes, CryptoStore, DeviceChanges, Result as StoreResult}, - types::{device_keys::DeviceKeys, one_time_keys::SignedKey}, + types::{DeviceKey, DeviceKeys, SignedKey}, verification::VerificationMachine, OutgoingVerificationRequest, Sas, ToDeviceRequest, VerificationRequest, }; @@ -177,8 +177,8 @@ impl Device { /// Get the Olm sessions that belong to this device. pub(crate) async fn get_sessions(&self) -> StoreResult>>>> { - if let Some(k) = self.get_key(DeviceKeyAlgorithm::Curve25519) { - self.verification_machine.store.get_sessions(k).await + if let Some(k) = self.curve25519_key() { + self.verification_machine.store.get_sessions(&k.to_base64()).await } else { Ok(None) } @@ -399,12 +399,34 @@ impl ReadOnlyDevice { } /// Get the key of the given key algorithm belonging to this device. - pub fn get_key(&self, algorithm: DeviceKeyAlgorithm) -> Option<&String> { + pub fn get_key(&self, algorithm: DeviceKeyAlgorithm) -> Option<&DeviceKey> { self.inner.keys.get(&DeviceKeyId::from_parts(algorithm, self.device_id())) } + /// Get the Curve25519 key of the given device. + pub fn curve25519_key(&self) -> Option { + self.get_key(DeviceKeyAlgorithm::Curve25519).and_then(|k| { + if let DeviceKey::Curve25519(k) = k { + Some(*k) + } else { + None + } + }) + } + + /// Get the Ed25519 key of the given device. + pub fn ed25519_key(&self) -> Option { + self.get_key(DeviceKeyAlgorithm::Ed25519).and_then(|k| { + if let DeviceKey::Ed25519(k) = k { + Some(*k) + } else { + None + } + }) + } + /// Get a map containing all the device keys. - pub fn keys(&self) -> &BTreeMap, String> { + pub fn keys(&self) -> &BTreeMap, DeviceKey> { &self.inner.keys } @@ -490,7 +512,7 @@ impl ReadOnlyDevice { store: &dyn CryptoStore, content: AnyToDeviceEventContent, ) -> OlmResult<(Session, ToDeviceRoomEncryptedEventContent)> { - let sender_key = if let Some(k) = self.get_key(DeviceKeyAlgorithm::Curve25519) { + let sender_key = if let Some(k) = self.curve25519_key() { k } else { warn!( @@ -502,7 +524,7 @@ impl ReadOnlyDevice { return Err(EventError::MissingSenderKey.into()); }; - let session = if let Some(s) = store.get_sessions(sender_key).await? { + let session = if let Some(s) = store.get_sessions(&sender_key.to_base64()).await? { let sessions = s.lock().await; sessions.get(0).cloned() } else { @@ -535,10 +557,7 @@ impl ReadOnlyDevice { } pub(crate) fn is_signed_by_device(&self, json: &mut Value) -> Result<(), SignatureError> { - let key = - self.get_key(DeviceKeyAlgorithm::Ed25519).ok_or(SignatureError::MissingSigningKey)?; - - let key = Ed25519PublicKey::from_base64(key)?; + let key = self.ed25519_key().ok_or(SignatureError::MissingSigningKey)?; key.verify_json( self.user_id(), @@ -618,7 +637,7 @@ pub(crate) mod testing { #![allow(dead_code)] use serde_json::json; - use crate::{identities::ReadOnlyDevice, types::device_keys::DeviceKeys}; + use crate::{identities::ReadOnlyDevice, types::DeviceKeys}; /// Generate default DeviceKeys for tests pub fn device_keys() -> DeviceKeys { @@ -655,7 +674,8 @@ pub(crate) mod testing { #[cfg(test)] pub(crate) mod test { - use ruma::{user_id, DeviceKeyAlgorithm}; + use ruma::user_id; + use vodozemac::{Curve25519PublicKey, Ed25519PublicKey}; use super::testing::{device_keys, get_device}; use crate::identities::LocalTrust; @@ -673,12 +693,13 @@ pub(crate) mod test { assert_eq!(LocalTrust::Unset, device.local_trust_state()); assert_eq!("Alice's mobile phone", device.display_name().unwrap()); assert_eq!( - device.get_key(DeviceKeyAlgorithm::Curve25519).unwrap(), - "xfgbLIC5WAl1OIkpOzoxpCe8FsRDT6nch7NQsOb15nc" + device.curve25519_key().unwrap(), + Curve25519PublicKey::from_base64("xfgbLIC5WAl1OIkpOzoxpCe8FsRDT6nch7NQsOb15nc") + .unwrap(), ); assert_eq!( - device.get_key(DeviceKeyAlgorithm::Ed25519).unwrap(), - "2/5LWJMow5zhJqakV88SIc7q/1pa8fmkfgAzx72w9G4" + device.ed25519_key().unwrap(), + Ed25519PublicKey::from_base64("2/5LWJMow5zhJqakV88SIc7q/1pa8fmkfgAzx72w9G4").unwrap(), ); } diff --git a/crates/matrix-sdk-crypto/src/identities/manager.rs b/crates/matrix-sdk-crypto/src/identities/manager.rs index 5e345bb18..c23abaf05 100644 --- a/crates/matrix-sdk-crypto/src/identities/manager.rs +++ b/crates/matrix-sdk-crypto/src/identities/manager.rs @@ -35,7 +35,7 @@ use crate::{ olm::PrivateCrossSigningIdentity, requests::KeysQueryRequest, store::{Changes, DeviceChanges, IdentityChanges, Result as StoreResult, Store}, - types::{cross_signing_key::CrossSigningKey, device_keys::DeviceKeys}, + types::{CrossSigningKey, DeviceKeys}, LocalTrust, }; diff --git a/crates/matrix-sdk-crypto/src/identities/user.rs b/crates/matrix-sdk-crypto/src/identities/user.rs index d0bfab16e..8c1171d6a 100644 --- a/crates/matrix-sdk-crypto/src/identities/user.rs +++ b/crates/matrix-sdk-crypto/src/identities/user.rs @@ -40,7 +40,7 @@ use crate::{ error::SignatureError, olm::VerifyJson, store::{Changes, IdentityChanges}, - types::{cross_signing_key::CrossSigningKey, device_keys::DeviceKeys}, + types::{CrossSigningKey, DeviceKeys, SigningKey}, verification::VerificationMachine, CryptoStoreError, OutgoingVerificationRequest, ReadOnlyDevice, VerificationRequest, }; @@ -393,7 +393,7 @@ impl MasterPubkey { } /// Get the keys map of containing the master keys. - pub fn keys(&self) -> &BTreeMap, String> { + pub fn keys(&self) -> &BTreeMap, SigningKey> { &self.0.keys } @@ -412,16 +412,20 @@ impl MasterPubkey { /// # Arguments /// /// * `key_id` - The id of the key that should be fetched. - pub fn get_key(&self, key_id: &DeviceKeyId) -> Option<&str> { - self.0.keys.get(key_id).map(|k| k.as_str()) + pub fn get_key(&self, key_id: &DeviceKeyId) -> Option<&SigningKey> { + self.0.keys.get(key_id) } /// Get the first available master key. /// /// There's usually only a single master key so this will usually fetch the /// only key. - pub fn get_first_key(&self) -> Option<&str> { - self.0.keys.values().map(|k| k.as_str()).next() + pub fn get_first_key(&self) -> Option { + if let Some(SigningKey::Ed25519(k)) = self.0.keys.values().next() { + Some(*k) + } else { + None + } } /// Check if the given cross signing sub-key is signed by the master key. @@ -450,19 +454,22 @@ impl MasterPubkey { return Err(SignatureError::UserIdMismatch); } - let key = Ed25519PublicKey::from_base64(key)?; - - key.verify_json( - &self.0.user_id, - key_id, - &mut to_value(subkey.cross_signing_key()).map_err(|_| SignatureError::NotAnObject)?, - ) + if let SigningKey::Ed25519(key) = key { + key.verify_json( + &self.0.user_id, + key_id, + &mut to_value(subkey.cross_signing_key()) + .map_err(|_| SignatureError::NotAnObject)?, + ) + } else { + Err(SignatureError::UnsupportedAlgorithm) + } } } impl<'a> IntoIterator for &'a MasterPubkey { - type Item = (&'a Box, &'a String); - type IntoIter = Iter<'a, Box, String>; + type Item = (&'a Box, &'a SigningKey); + type IntoIter = Iter<'a, Box, SigningKey>; fn into_iter(self) -> Self::IntoIter { self.keys().iter() @@ -476,7 +483,7 @@ impl UserSigningPubkey { } /// Get the keys map of containing the user signing keys. - pub fn keys(&self) -> &BTreeMap, String> { + pub fn keys(&self) -> &BTreeMap, SigningKey> { &self.0.keys } @@ -497,18 +504,21 @@ impl UserSigningPubkey { // TODO check that the usage is OK. - let key = Ed25519PublicKey::from_base64(key)?; - key.verify_json( - &self.0.user_id, - key_id.as_str().try_into()?, - &mut to_value(&master_key.0).map_err(|_| SignatureError::NotAnObject)?, - ) + if let SigningKey::Ed25519(key) = key { + key.verify_json( + &self.0.user_id, + key_id.as_str().try_into()?, + &mut to_value(&master_key.0).map_err(|_| SignatureError::NotAnObject)?, + ) + } else { + Err(SignatureError::UnsupportedAlgorithm) + } } } impl<'a> IntoIterator for &'a UserSigningPubkey { - type Item = (&'a Box, &'a String); - type IntoIter = Iter<'a, Box, String>; + type Item = (&'a Box, &'a SigningKey); + type IntoIter = Iter<'a, Box, SigningKey>; fn into_iter(self) -> Self::IntoIter { self.keys().iter() @@ -522,7 +532,7 @@ impl SelfSigningPubkey { } /// Get the keys map of containing the self signing keys. - pub fn keys(&self) -> &BTreeMap, String> { + pub fn keys(&self) -> &BTreeMap, SigningKey> { &self.0.keys } @@ -532,8 +542,11 @@ impl SelfSigningPubkey { let mut device = to_value(device_keys)?; - let key = Ed25519PublicKey::from_base64(key)?; - key.verify_json(&self.0.user_id, key_id.as_str().try_into()?, &mut device) + if let SigningKey::Ed25519(key) = key { + key.verify_json(&self.0.user_id, key_id.as_str().try_into()?, &mut device) + } else { + Err(SignatureError::UnsupportedAlgorithm) + } } /// Check if the given device is signed by this self signing key. @@ -550,8 +563,8 @@ impl SelfSigningPubkey { } impl<'a> IntoIterator for &'a SelfSigningPubkey { - type Item = (&'a Box, &'a String); - type IntoIter = Iter<'a, Box, String>; + type Item = (&'a Box, &'a SigningKey); + type IntoIter = Iter<'a, Box, SigningKey>; fn into_iter(self) -> Self::IntoIter { self.keys().iter() @@ -908,7 +921,7 @@ pub(crate) mod testing { manager::testing::{other_key_query, own_key_query}, ReadOnlyDevice, }, - types::cross_signing_key::CrossSigningKey, + types::CrossSigningKey, }; /// Generate test devices from KeyQueryResponse @@ -971,7 +984,7 @@ pub(crate) mod test { identities::{manager::testing::own_key_query, Device}, olm::{PrivateCrossSigningIdentity, ReadOnlyAccount}, store::MemoryStore, - types::cross_signing_key::CrossSigningKey, + types::CrossSigningKey, verification::VerificationMachine, }; diff --git a/crates/matrix-sdk-crypto/src/machine.rs b/crates/matrix-sdk-crypto/src/machine.rs index 90f280f10..ef73b127b 100644 --- a/crates/matrix-sdk-crypto/src/machine.rs +++ b/crates/matrix-sdk-crypto/src/machine.rs @@ -1031,9 +1031,7 @@ impl OlmMachine { ) -> StoreResult { let verification_state = if let Some(device) = self.get_device(sender, device_id).await?.filter(|d| { - d.get_key(DeviceKeyAlgorithm::Curve25519) - .map(|k| k == session.sender_key()) - .unwrap_or(false) + d.curve25519_key().map(|k| k.to_base64() == session.sender_key()).unwrap_or(false) }) { if (self.user_id() == device.user_id() && self.device_id() == device.device_id()) || device.verified() @@ -1488,6 +1486,7 @@ impl OlmMachine { .await .and_then(|m| m.get_first_key().map(|k| k.to_owned())) .ok_or(crate::SignatureError::MissingSigningKey)? + .to_base64() .into(); let device_key_id = DeviceKeyId::from_parts(DeviceKeyAlgorithm::Ed25519, &master_key); diff --git a/crates/matrix-sdk-crypto/src/olm/account.rs b/crates/matrix-sdk-crypto/src/olm/account.rs index 90324ed77..ebe9eae51 100644 --- a/crates/matrix-sdk-crypto/src/olm/account.rs +++ b/crates/matrix-sdk-crypto/src/olm/account.rs @@ -39,7 +39,7 @@ use ruma::{ DeviceId, DeviceKeyAlgorithm, DeviceKeyId, EventEncryptionAlgorithm, RoomId, UInt, UserId, }; use serde::{Deserialize, Serialize}; -use serde_json::{json, value::RawValue as RawJsonValue, Value}; +use serde_json::{value::RawValue as RawJsonValue, Value}; use sha2::{Digest, Sha256}; use tracing::{debug, info, trace, warn}; use vodozemac::{ @@ -56,11 +56,7 @@ use crate::{ identities::{MasterPubkey, ReadOnlyDevice}, requests::UploadSigningKeysRequest, store::{Changes, Store}, - types::{ - cross_signing_key::CrossSigningKey, - device_keys::DeviceKeys, - one_time_keys::{OneTimeKey, SignedKey}, - }, + types::{CrossSigningKey, DeviceKeys, OneTimeKey, SignedKey}, utilities::encode, CryptoStoreError, OlmError, SignatureError, }; @@ -724,11 +720,11 @@ impl ReadOnlyAccount { let keys = BTreeMap::from([ ( DeviceKeyId::from_parts(DeviceKeyAlgorithm::Curve25519, &self.device_id), - identity_keys.curve25519.to_base64(), + identity_keys.curve25519.into(), ), ( DeviceKeyId::from_parts(DeviceKeyAlgorithm::Ed25519, &self.device_id), - identity_keys.ed25519.to_base64(), + identity_keys.ed25519.into(), ), ]); @@ -748,12 +744,8 @@ impl ReadOnlyAccount { // Create a copy of the device keys containing only fields that will // get signed. - let json_device_keys = json!({ - "user_id": device_keys.user_id, - "device_id": device_keys.device_id, - "algorithms": device_keys.algorithms, - "keys": device_keys.keys, - }); + let json_device_keys = + serde_json::to_value(&device_keys).expect("Can't serialize device keys"); device_keys .signatures @@ -799,7 +791,8 @@ impl ReadOnlyAccount { master_key: MasterPubkey, ) -> Result { let public_key = - master_key.get_first_key().ok_or(SignatureError::MissingSigningKey)?.into(); + master_key.get_first_key().ok_or(SignatureError::MissingSigningKey)?.to_base64().into(); + let mut cross_signing_key: CrossSigningKey = master_key.as_ref().clone(); cross_signing_key.signatures.clear(); self.sign_cross_signing_key(&mut cross_signing_key).await?; @@ -937,7 +930,7 @@ impl ReadOnlyAccount { our_identity_keys: self.identity_keys.clone(), inner: Arc::new(Mutex::new(session)), session_id: session_id.into(), - sender_key: identity_key.to_base64().into(), + sender_key: identity_key, created_using_fallback_key: fallback_used, creation_time: Arc::new(now), last_use_time: Arc::new(now), @@ -992,14 +985,13 @@ impl ReadOnlyAccount { ) })?; - let identity_key = device.get_key(DeviceKeyAlgorithm::Curve25519).ok_or_else(|| { + let identity_key = device.curve25519_key().ok_or_else(|| { SessionCreationError::DeviceMissingCurveKey( device.user_id().to_owned(), device.device_id().into(), ) })?; - let identity_key = Curve25519PublicKey::from_base64(identity_key)?; let is_fallback = one_time_key.fallback(); let one_time_key = one_time_key.key(); @@ -1034,7 +1026,7 @@ impl ReadOnlyAccount { our_identity_keys: self.identity_keys.clone(), inner: Arc::new(Mutex::new(result.session)), session_id: session_id.into(), - sender_key: their_identity_key.to_base64().into(), + sender_key: their_identity_key, created_using_fallback_key: false, creation_time: Arc::new(now), last_use_time: Arc::new(now), @@ -1144,16 +1136,7 @@ impl ReadOnlyAccount { let our_device = ReadOnlyDevice::from_account(self).await; let other_session = other - .create_inbound_session( - our_device - .keys() - .get(&DeviceKeyId::from_parts( - DeviceKeyAlgorithm::Curve25519, - our_device.device_id(), - )) - .unwrap(), - &prekey, - ) + .create_inbound_session(&our_device.curve25519_key().unwrap().to_base64(), &prekey) .await .unwrap(); diff --git a/crates/matrix-sdk-crypto/src/olm/group_sessions/outbound.rs b/crates/matrix-sdk-crypto/src/olm/group_sessions/outbound.rs index b8c2a49a3..d16bf48e4 100644 --- a/crates/matrix-sdk-crypto/src/olm/group_sessions/outbound.rs +++ b/crates/matrix-sdk-crypto/src/olm/group_sessions/outbound.rs @@ -37,11 +37,12 @@ use ruma::{ room_key::ToDeviceRoomKeyEventContent, AnyToDeviceEventContent, }, - DeviceId, DeviceKeyAlgorithm, EventEncryptionAlgorithm, RoomId, TransactionId, UserId, + DeviceId, EventEncryptionAlgorithm, RoomId, TransactionId, UserId, }; use serde::{Deserialize, Serialize}; use serde_json::{json, Value}; use tracing::{debug, error, info}; +use vodozemac::Curve25519PublicKey; pub use vodozemac::{ megolm::{GroupSession, GroupSessionPickle, MegolmMessage, SessionKey}, olm::IdentityKeys, @@ -138,7 +139,7 @@ pub type ShareInfoSet = BTreeMap, BTreeMap, ShareInfo> #[derive(Clone, Debug, Serialize, Deserialize)] pub struct ShareInfo { /// The sender key of the device that was used to encrypt the room key. - pub sender_key: String, + pub sender_key: Curve25519PublicKey, /// The message index that the device received. pub message_index: u32, } @@ -380,7 +381,7 @@ impl OutboundGroupSession { // Check if we shared the session. let shared_state = self.shared_with_set.get(device.user_id()).and_then(|d| { d.get(device.device_id()).map(|s| { - if Some(&s.sender_key) == device.get_key(DeviceKeyAlgorithm::Curve25519) { + if Some(s.sender_key) == device.curve25519_key() { ShareState::Shared(s.message_index) } else { ShareState::SharedButChangedSenderKey @@ -401,8 +402,7 @@ impl OutboundGroupSession { share_info.get(device.user_id()).and_then(|d| { d.get(device.device_id()).map(|info| { - if Some(&info.sender_key) == device.get_key(DeviceKeyAlgorithm::Curve25519) - { + if Some(info.sender_key) == device.curve25519_key() { ShareState::Shared(info.message_index) } else { ShareState::SharedButChangedSenderKey @@ -422,25 +422,27 @@ impl OutboundGroupSession { &self, user_id: &UserId, device_id: &DeviceId, - sender_key: &str, + sender_key: Curve25519PublicKey, index: u32, ) { - self.shared_with_set.entry(user_id.to_owned()).or_insert_with(DashMap::new).insert( - device_id.to_owned(), - ShareInfo { sender_key: sender_key.to_owned(), message_index: index }, - ); + self.shared_with_set + .entry(user_id.to_owned()) + .or_insert_with(DashMap::new) + .insert(device_id.to_owned(), ShareInfo { sender_key, message_index: index }); } /// Mark the session as shared with the given user/device pair, starting /// from the current index. #[cfg(test)] - pub async fn mark_shared_with(&self, user_id: &UserId, device_id: &DeviceId, sender_key: &str) { + pub async fn mark_shared_with( + &self, + user_id: &UserId, + device_id: &DeviceId, + sender_key: Curve25519PublicKey, + ) { self.shared_with_set.entry(user_id.to_owned()).or_insert_with(DashMap::new).insert( device_id.to_owned(), - ShareInfo { - sender_key: sender_key.to_owned(), - message_index: self.message_index().await, - }, + ShareInfo { sender_key, message_index: self.message_index().await }, ); } diff --git a/crates/matrix-sdk-crypto/src/olm/session.rs b/crates/matrix-sdk-crypto/src/olm/session.rs index 6f4c7f758..b728972d9 100644 --- a/crates/matrix-sdk-crypto/src/olm/session.rs +++ b/crates/matrix-sdk-crypto/src/olm/session.rs @@ -23,11 +23,14 @@ use ruma::{ }, AnyToDeviceEventContent, EventContent, }, - DeviceId, DeviceKeyAlgorithm, UserId, + DeviceId, UserId, }; use serde::{Deserialize, Serialize}; use serde_json::json; -use vodozemac::olm::{DecryptionError, OlmMessage, Session as InnerSession, SessionPickle}; +use vodozemac::{ + olm::{DecryptionError, OlmMessage, Session as InnerSession, SessionPickle}, + Curve25519PublicKey, +}; use super::{deserialize_instant, serialize_instant, IdentityKeys}; use crate::{ @@ -50,7 +53,7 @@ pub struct Session { /// Our sessionId pub session_id: Arc, /// The Key of the sender - pub sender_key: Arc, + pub sender_key: Curve25519PublicKey, /// Has this been created using the fallback key pub created_using_fallback_key: bool, /// When the session was created @@ -85,8 +88,8 @@ impl Session { } /// Get the sender key that was used to establish this Session. - pub fn sender_key(&self) -> &str { - &self.sender_key + pub fn sender_key(&self) -> Curve25519PublicKey { + self.sender_key } /// Encrypt the given plaintext as a OlmMessage. @@ -117,9 +120,8 @@ impl Session { recipient_device: &ReadOnlyDevice, content: AnyToDeviceEventContent, ) -> OlmResult { - let recipient_signing_key = recipient_device - .get_key(DeviceKeyAlgorithm::Ed25519) - .ok_or(EventError::MissingSigningKey)?; + let recipient_signing_key = + recipient_device.ed25519_key().ok_or(EventError::MissingSigningKey)?; let event_type = content.event_type(); @@ -131,7 +133,7 @@ impl Session { }, "recipient": recipient_device.user_id(), "recipient_keys": { - "ed25519": recipient_signing_key, + "ed25519": recipient_signing_key.to_base64(), }, "type": event_type, "content": content, @@ -144,7 +146,7 @@ impl Session { let ciphertext = CiphertextInfo::new(ciphertext.1, (message_type as u32).into()); let mut content = BTreeMap::new(); - content.insert((*self.sender_key).to_owned(), ciphertext); + content.insert(self.sender_key.to_base64(), ciphertext); Ok(EncryptedEventScheme::OlmV1Curve25519AesSha2(OlmV1Curve25519AesSha2Content::new( content, @@ -169,7 +171,7 @@ impl Session { PickledSession { pickle, - sender_key: self.sender_key.to_string(), + sender_key: self.sender_key, created_using_fallback_key: self.created_using_fallback_key, creation_time: *self.creation_time, last_use_time: *self.last_use_time, @@ -209,7 +211,7 @@ impl Session { inner: Arc::new(Mutex::new(session)), session_id: session_id.into(), created_using_fallback_key: pickle.created_using_fallback_key, - sender_key: pickle.sender_key.into(), + sender_key: pickle.sender_key, creation_time: Arc::new(pickle.creation_time), last_use_time: Arc::new(pickle.last_use_time), } @@ -232,7 +234,7 @@ pub struct PickledSession { /// The pickle string holding the Olm Session. pub pickle: SessionPickle, /// The curve25519 key of the other user that we share this session with. - pub sender_key: String, + pub sender_key: Curve25519PublicKey, /// Was the session created using a fallback key. #[serde(default)] pub created_using_fallback_key: bool, diff --git a/crates/matrix-sdk-crypto/src/olm/signing/mod.rs b/crates/matrix-sdk-crypto/src/olm/signing/mod.rs index 1bcc1b848..066e78fa9 100644 --- a/crates/matrix-sdk-crypto/src/olm/signing/mod.rs +++ b/crates/matrix-sdk-crypto/src/olm/signing/mod.rs @@ -36,7 +36,7 @@ use crate::{ identities::{MasterPubkey, SelfSigningPubkey, UserSigningPubkey}, requests::UploadSigningKeysRequest, store::SecretImportError, - types::device_keys::DeviceKeys, + types::DeviceKeys, OwnUserIdentity, ReadOnlyAccount, ReadOnlyDevice, ReadOnlyOwnUserIdentity, ReadOnlyUserIdentity, }; @@ -404,6 +404,7 @@ impl PrivateCrossSigningIdentity { .master_key() .get_first_key() .ok_or(SignatureError::MissingSigningKey)? + .to_base64() .into(), master_key.to_raw(), ); diff --git a/crates/matrix-sdk-crypto/src/olm/signing/pk_signing.rs b/crates/matrix-sdk-crypto/src/olm/signing/pk_signing.rs index 795f8449b..3f63a2c43 100644 --- a/crates/matrix-sdk-crypto/src/olm/signing/pk_signing.rs +++ b/crates/matrix-sdk-crypto/src/olm/signing/pk_signing.rs @@ -26,10 +26,7 @@ use vodozemac::{Ed25519PublicKey, Ed25519SecretKey, Ed25519Signature, KeyError}; use crate::{ error::SignatureError, identities::{MasterPubkey, SelfSigningPubkey, UserSigningPubkey}, - types::{ - cross_signing_key::{CrossSigningKey, CrossSigningKeySignatures}, - device_keys::DeviceKeys, - }, + types::{CrossSigningKey, CrossSigningKeySignatures, DeviceKeys}, utilities::{encode, DecodeError}, ReadOnlyUserIdentity, }; @@ -324,7 +321,7 @@ impl Signing { DeviceKeyAlgorithm::Ed25519, &Box::::from(self.public_key().to_base64()), ), - self.inner.public_key().to_base64(), + self.inner.public_key().into(), )]); CrossSigningKey::new(user_id, vec![usage], keys, BTreeMap::new()) diff --git a/crates/matrix-sdk-crypto/src/requests.rs b/crates/matrix-sdk-crypto/src/requests.rs index b42ddbf54..aac6fff36 100644 --- a/crates/matrix-sdk-crypto/src/requests.rs +++ b/crates/matrix-sdk-crypto/src/requests.rs @@ -36,7 +36,7 @@ use ruma::{ }; use serde::{Deserialize, Serialize}; -use crate::types::cross_signing_key::CrossSigningKey; +use crate::types::CrossSigningKey; /// Customized version of /// `ruma_client_api::to_device::send_event_to_device::v3::Request` diff --git a/crates/matrix-sdk-crypto/src/session_manager/sessions.rs b/crates/matrix-sdk-crypto/src/session_manager/sessions.rs index b6883e68d..e1bb023f9 100644 --- a/crates/matrix-sdk-crypto/src/session_manager/sessions.rs +++ b/crates/matrix-sdk-crypto/src/session_manager/sessions.rs @@ -194,8 +194,8 @@ impl SessionManager { "Device doesn't support any of our 1-to-1 E2EE \ algorithms, can't establish an Olm session" ); - } else if let Some(sender_key) = device.get_key(DeviceKeyAlgorithm::Curve25519) { - let sessions = self.store.get_sessions(sender_key).await?; + } else if let Some(sender_key) = device.curve25519_key() { + let sessions = self.store.get_sessions(&sender_key.to_base64()).await?; let is_missing = if let Some(sessions) = sessions { sessions.lock().await.is_empty() @@ -452,7 +452,7 @@ mod test { assert!(!manager.users_for_key_claim.contains_key(bob.user_id())); assert!(!manager.is_device_wedged(&bob_device)); - manager.mark_device_as_wedged(bob_device.user_id(), curve_key).await.unwrap(); + manager.mark_device_as_wedged(bob_device.user_id(), &curve_key.to_base64()).await.unwrap(); assert!(manager.is_device_wedged(&bob_device)); assert!(manager.users_for_key_claim.contains_key(bob.user_id())); diff --git a/crates/matrix-sdk-crypto/src/store/caches.rs b/crates/matrix-sdk-crypto/src/store/caches.rs index 344017921..d8d38640b 100644 --- a/crates/matrix-sdk-crypto/src/store/caches.rs +++ b/crates/matrix-sdk-crypto/src/store/caches.rs @@ -47,7 +47,7 @@ impl SessionStore { pub async fn add(&self, session: Session) -> bool { let sessions_lock = self .entries - .entry(session.sender_key.to_string()) + .entry(session.sender_key.to_base64()) .or_insert_with(|| Arc::new(Mutex::new(Vec::new()))); let mut sessions = sessions_lock.lock().await; @@ -205,7 +205,7 @@ mod test { assert!(store.add(session.clone()).await); assert!(!store.add(session.clone()).await); - let sessions = store.get(&session.sender_key).unwrap(); + let sessions = store.get(&session.sender_key.to_base64()).unwrap(); let sessions = sessions.lock().await; let loaded_session = &sessions[0]; @@ -218,9 +218,9 @@ mod test { let (_, session) = get_account_and_session().await; let store = SessionStore::new(); - store.set_for_sender(&session.sender_key, vec![session.clone()]); + store.set_for_sender(&session.sender_key.to_base64(), vec![session.clone()]); - let sessions = store.get(&session.sender_key).unwrap(); + let sessions = store.get(&session.sender_key.to_base64()).unwrap(); let sessions = sessions.lock().await; let loaded_session = &sessions[0]; diff --git a/crates/matrix-sdk-crypto/src/store/integration_tests.rs b/crates/matrix-sdk-crypto/src/store/integration_tests.rs index 938293b18..665c92f9d 100644 --- a/crates/matrix-sdk-crypto/src/store/integration_tests.rs +++ b/crates/matrix-sdk-crypto/src/store/integration_tests.rs @@ -130,7 +130,7 @@ macro_rules! cryptostore_integration_tests { store.save_changes(changes).await.unwrap(); let sessions = - store.get_sessions(&session.sender_key).await.expect("Can't load sessions").unwrap(); + store.get_sessions(&session.sender_key.to_base64()).await.expect("Can't load sessions").unwrap(); let loaded_session = sessions.lock().await.get(0).cloned().unwrap(); assert_eq!(&session, &loaded_session); @@ -141,7 +141,7 @@ macro_rules! cryptostore_integration_tests { let store_name = "add_and_save_session".to_owned(); let store = get_store(store_name.clone(), None).await; let (account, session) = get_account_and_session().await; - let sender_key = session.sender_key.to_owned(); + let sender_key = session.sender_key.to_base64(); let session_id = session.session_id().to_owned(); store.save_account(account.clone()).await.expect("Can't save account"); diff --git a/crates/matrix-sdk-crypto/src/store/memorystore.rs b/crates/matrix-sdk-crypto/src/store/memorystore.rs index 10d3731c3..b78cb4109 100644 --- a/crates/matrix-sdk-crypto/src/store/memorystore.rs +++ b/crates/matrix-sdk-crypto/src/store/memorystore.rs @@ -327,7 +327,7 @@ mod test { store.save_sessions(vec![session.clone()]).await; - let sessions = store.get_sessions(&session.sender_key).await.unwrap().unwrap(); + let sessions = store.get_sessions(&session.sender_key.to_base64()).await.unwrap().unwrap(); let sessions = sessions.lock().await; let loaded_session = &sessions[0]; diff --git a/crates/matrix-sdk-crypto/src/store/mod.rs b/crates/matrix-sdk-crypto/src/store/mod.rs index 7f99dedee..1b5943e21 100644 --- a/crates/matrix-sdk-crypto/src/store/mod.rs +++ b/crates/matrix-sdk-crypto/src/store/mod.rs @@ -59,12 +59,13 @@ pub use memorystore::MemoryStore; pub use pickle_key::{EncryptedPickleKey, PickleKey}; use ruma::{ events::secret::request::SecretName, identifiers::Error as IdentifierValidationError, DeviceId, - DeviceKeyAlgorithm, RoomId, TransactionId, UserId, + RoomId, TransactionId, UserId, }; use serde::{Deserialize, Serialize}; use serde_json::Error as SerdeError; use thiserror::Error; use tracing::{info, warn}; +use vodozemac::Curve25519PublicKey; use zeroize::Zeroize; use crate::{ @@ -376,11 +377,13 @@ impl Store { user_id: &UserId, curve_key: &str, ) -> Result> { - self.get_user_devices(user_id).await.map(|d| { - d.devices().find(|d| { - d.get_key(DeviceKeyAlgorithm::Curve25519).map_or(false, |k| k == curve_key) - }) - }) + if let Ok(curve_key) = Curve25519PublicKey::from_base64(curve_key) { + self.get_user_devices(user_id) + .await + .map(|d| d.devices().find(|d| d.curve25519_key().map_or(false, |k| k == curve_key))) + } else { + Ok(None) + } } /// Get all devices associated with the given `user_id` diff --git a/crates/matrix-sdk-crypto/src/types/cross_signing_key.rs b/crates/matrix-sdk-crypto/src/types/cross_signing_key.rs index bf392a9c4..fa65d2e96 100644 --- a/crates/matrix-sdk-crypto/src/types/cross_signing_key.rs +++ b/crates/matrix-sdk-crypto/src/types/cross_signing_key.rs @@ -21,15 +21,17 @@ use std::collections::BTreeMap; -use ruma::{encryption::KeyUsage, serde::Raw, DeviceKeyId, UserId}; +use ruma::{encryption::KeyUsage, serde::Raw, DeviceKeyAlgorithm, DeviceKeyId, UserId}; use serde::{Deserialize, Serialize}; use serde_json::{value::to_raw_value, Value}; +use vodozemac::Ed25519PublicKey; /// Signatures for a `CrossSigningKey` object. pub type CrossSigningKeySignatures = BTreeMap, BTreeMap, String>>; /// A cross signing key. #[derive(Clone, Debug, Deserialize, Serialize)] +#[serde(try_from = "CrossSigningKeyHelper", into = "CrossSigningKeyHelper")] pub struct CrossSigningKey { /// The ID of the user the key belongs to. pub user_id: Box, @@ -40,7 +42,7 @@ pub struct CrossSigningKey { /// The public key. /// /// The object must have exactly one property. - pub keys: BTreeMap, String>, + pub keys: BTreeMap, SigningKey>, /// Signatures of the key. /// @@ -58,7 +60,7 @@ impl CrossSigningKey { pub fn new( user_id: Box, usage: Vec, - keys: BTreeMap, String>, + keys: BTreeMap, SigningKey>, signatures: CrossSigningKeySignatures, ) -> Self { Self { user_id, usage, keys, signatures, other: BTreeMap::new() } @@ -70,6 +72,88 @@ impl CrossSigningKey { } } +/// An enum over the different key types a cross-signing key can have. +/// +/// Currently cross signing keys support an ed25519 keypair. The keys transport +/// format is a base64 encoded string, any unknown key type will be left as such +/// a string. +#[derive(Clone, Debug, PartialEq)] +pub enum SigningKey { + Ed25519(Ed25519PublicKey), + Other(String), +} + +impl SigningKey { + /// Convert the `SigningKey` into a base64 encoded string. + pub fn to_base64(&self) -> String { + match self { + SigningKey::Ed25519(k) => k.to_base64(), + SigningKey::Other(k) => k.to_owned(), + } + } +} + +impl From for SigningKey { + fn from(val: Ed25519PublicKey) -> Self { + SigningKey::Ed25519(val) + } +} + +#[derive(Clone, Debug, Deserialize, Serialize)] +struct CrossSigningKeyHelper { + pub user_id: Box, + pub usage: Vec, + pub keys: BTreeMap, String>, + #[serde(default, skip_serializing_if = "BTreeMap::is_empty")] + pub signatures: CrossSigningKeySignatures, + #[serde(flatten)] + other: BTreeMap, +} + +impl TryFrom for CrossSigningKey { + type Error = vodozemac::KeyError; + + fn try_from(value: CrossSigningKeyHelper) -> Result { + let keys: Result, SigningKey>, vodozemac::KeyError> = value + .keys + .into_iter() + .map(|(k, v)| { + let key = match k.algorithm() { + DeviceKeyAlgorithm::Ed25519 => { + SigningKey::Ed25519(Ed25519PublicKey::from_base64(&v)?) + } + _ => SigningKey::Other(v), + }; + + Ok((k, key)) + }) + .collect(); + + Ok(Self { + user_id: value.user_id, + usage: value.usage, + keys: keys?, + signatures: value.signatures, + other: value.other, + }) + } +} + +impl From for CrossSigningKeyHelper { + fn from(value: CrossSigningKey) -> Self { + let keys: BTreeMap, String> = + value.keys.into_iter().map(|(k, v)| (k, v.to_base64())).collect(); + + Self { + user_id: value.user_id, + usage: value.usage, + keys, + signatures: value.signatures, + other: value.other, + } + } +} + #[cfg(test)] mod test { use ruma::user_id; diff --git a/crates/matrix-sdk-crypto/src/types/device_keys.rs b/crates/matrix-sdk-crypto/src/types/device_keys.rs index 01b93c0f7..b01582ee5 100644 --- a/crates/matrix-sdk-crypto/src/types/device_keys.rs +++ b/crates/matrix-sdk-crypto/src/types/device_keys.rs @@ -20,12 +20,16 @@ use std::collections::BTreeMap; -use ruma::{serde::Raw, DeviceId, DeviceKeyId, EventEncryptionAlgorithm, UserId}; +use ruma::{ + serde::Raw, DeviceId, DeviceKeyAlgorithm, DeviceKeyId, EventEncryptionAlgorithm, UserId, +}; use serde::{Deserialize, Serialize}; use serde_json::{value::to_raw_value, Value}; +use vodozemac::{Curve25519PublicKey, Ed25519PublicKey}; /// Identity keys for a device. #[derive(Clone, Debug, Deserialize, Serialize)] +#[serde(try_from = "DeviceKeyHelper", into = "DeviceKeyHelper")] pub struct DeviceKeys { /// The ID of the user the device belongs to. /// @@ -41,7 +45,7 @@ pub struct DeviceKeys { pub algorithms: Vec, /// Public identity keys. - pub keys: BTreeMap, String>, + pub keys: BTreeMap, DeviceKey>, /// Signatures for the device key object. pub signatures: BTreeMap, BTreeMap, String>>, @@ -62,7 +66,7 @@ impl DeviceKeys { user_id: Box, device_id: Box, algorithms: Vec, - keys: BTreeMap, String>, + keys: BTreeMap, DeviceKey>, signatures: BTreeMap, BTreeMap, String>>, ) -> Self { Self { @@ -105,6 +109,108 @@ impl UnsignedDeviceInfo { } } +/// An enum over the different key types a device can have. +/// +/// Currently devices have a curve25519 and ed25519 keypair. The keys transport +/// format is a base64 encoded string, any unknown key type will be left as such +/// a string. +#[derive(Clone, Debug, PartialEq)] +pub enum DeviceKey { + /// The curve25519 device key. + Curve25519(Curve25519PublicKey), + /// The ed25519 device key. + Ed25519(Ed25519PublicKey), + /// An unknown device key. + Other(String), +} + +impl DeviceKey { + /// Convert the `DeviceKey` into a base64 encoded string. + pub fn to_base64(&self) -> String { + match self { + DeviceKey::Curve25519(k) => k.to_base64(), + DeviceKey::Ed25519(k) => k.to_base64(), + DeviceKey::Other(k) => k.to_owned(), + } + } +} + +impl From for DeviceKey { + fn from(val: Curve25519PublicKey) -> Self { + DeviceKey::Curve25519(val) + } +} + +impl From for DeviceKey { + fn from(val: Ed25519PublicKey) -> Self { + DeviceKey::Ed25519(val) + } +} + +#[derive(Clone, Debug, Deserialize, Serialize)] +struct DeviceKeyHelper { + pub user_id: Box, + pub device_id: Box, + pub algorithms: Vec, + pub keys: BTreeMap, String>, + pub signatures: BTreeMap, BTreeMap, String>>, + #[serde(default, skip_serializing_if = "UnsignedDeviceInfo::is_empty")] + pub unsigned: UnsignedDeviceInfo, + #[serde(flatten)] + other: BTreeMap, +} + +impl TryFrom for DeviceKeys { + type Error = vodozemac::KeyError; + + fn try_from(value: DeviceKeyHelper) -> Result { + let keys: Result, DeviceKey>, vodozemac::KeyError> = value + .keys + .into_iter() + .map(|(k, v)| { + let key = match k.algorithm() { + DeviceKeyAlgorithm::Ed25519 => { + DeviceKey::Ed25519(Ed25519PublicKey::from_base64(&v)?) + } + DeviceKeyAlgorithm::Curve25519 => { + DeviceKey::Curve25519(Curve25519PublicKey::from_base64(&v)?) + } + _ => DeviceKey::Other(v), + }; + + Ok((k, key)) + }) + .collect(); + + Ok(Self { + user_id: value.user_id, + device_id: value.device_id, + algorithms: value.algorithms, + keys: keys?, + signatures: value.signatures, + unsigned: value.unsigned, + other: value.other, + }) + } +} + +impl From for DeviceKeyHelper { + fn from(value: DeviceKeys) -> Self { + let keys: BTreeMap, String> = + value.keys.into_iter().map(|(k, v)| (k, v.to_base64())).collect(); + + Self { + user_id: value.user_id, + device_id: value.device_id, + algorithms: value.algorithms, + keys, + signatures: value.signatures, + unsigned: value.unsigned, + other: value.other, + } + } +} + #[cfg(test)] mod test { use ruma::{device_id, user_id}; diff --git a/crates/matrix-sdk-crypto/src/types/mod.rs b/crates/matrix-sdk-crypto/src/types/mod.rs index 7b557f5cd..c74ed9666 100644 --- a/crates/matrix-sdk-crypto/src/types/mod.rs +++ b/crates/matrix-sdk-crypto/src/types/mod.rs @@ -12,6 +12,21 @@ // See the License for the specific language governing permissions and // limitations under the License. -pub mod cross_signing_key; -pub mod device_keys; -pub mod one_time_keys; +//! Module containing customized types modeling Matrix keys. +//! +//! These types were mostly taken from the Ruma project. The types differ in two +//! important ways to the Ruma types of the same name: +//! +//! 1. They are using vodozemac types so we directly deserialize into a +//! vodozemac curve25519 or ed25519 key. +//! 2. They support lossless serialization cycles in a canonical JSON supported +//! way, meaning the white-space and field order won't be preserved but the +//! data will. + +mod cross_signing_key; +mod device_keys; +mod one_time_keys; + +pub use cross_signing_key::*; +pub use device_keys::*; +pub use one_time_keys::*; diff --git a/crates/matrix-sdk-crypto/src/types/one_time_keys.rs b/crates/matrix-sdk-crypto/src/types/one_time_keys.rs index e61a29fd8..64668c484 100644 --- a/crates/matrix-sdk-crypto/src/types/one_time_keys.rs +++ b/crates/matrix-sdk-crypto/src/types/one_time_keys.rs @@ -18,16 +18,6 @@ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. -//! Module containing customized types modeling Matrix one-time keys. -//! -//! These types were mostly taken from the Ruma project. The types differ in two -//! important ways to the Ruma types of the same name: -//! -//! 1. They are using vodozemac types so we directly deserialize into a -//! vodozemac curve25519 key. -//! 2. They support lossless serialization cycles in a canonical JSON supported -//! way, meaning the white-space and field order won't be preserved. - use std::collections::BTreeMap; use ruma::{serde::Raw, DeviceKeyId, UserId}; diff --git a/crates/matrix-sdk-crypto/src/verification/qrcode.rs b/crates/matrix-sdk-crypto/src/verification/qrcode.rs index 85bc27dc3..fc7dfa0fd 100644 --- a/crates/matrix-sdk-crypto/src/verification/qrcode.rs +++ b/crates/matrix-sdk-crypto/src/verification/qrcode.rs @@ -34,10 +34,11 @@ use ruma::{ AnyMessageEventContent, AnyToDeviceEventContent, }, serde::Base64, - DeviceId, DeviceKeyAlgorithm, RoomId, TransactionId, UserId, + DeviceId, RoomId, TransactionId, UserId, }; use thiserror::Error; use tracing::trace; +use vodozemac::Ed25519PublicKey; use super::{ event_enums::{CancelContent, DoneContent, OutgoingContent, OwnedStartContent, StartContent}, @@ -441,8 +442,8 @@ impl QrVerification { pub(crate) fn new_self( flow_id: FlowId, - own_master_key: String, - other_device_key: String, + own_master_key: Ed25519PublicKey, + other_device_key: Ed25519PublicKey, identities: IdentitiesBeingVerified, we_started: bool, request_handle: Option, @@ -463,7 +464,7 @@ impl QrVerification { pub(crate) fn new_self_no_master( store: VerificationStore, flow_id: FlowId, - own_master_key: String, + own_master_key: Ed25519PublicKey, identities: IdentitiesBeingVerified, we_started: bool, request_handle: Option, @@ -472,7 +473,7 @@ impl QrVerification { let inner: QrVerificationData = SelfVerificationNoMasterKey::new( flow_id.as_str().to_owned(), - store.account.identity_keys().ed25519.to_base64(), + store.account.identity_keys().ed25519, own_master_key, secret, ) @@ -483,8 +484,8 @@ impl QrVerification { pub(crate) fn new_cross( flow_id: FlowId, - own_master_key: String, - other_master_key: String, + own_master_key: Ed25519PublicKey, + other_master_key: Ed25519PublicKey, identities: IdentitiesBeingVerified, we_started: bool, request_handle: Option, @@ -541,8 +542,8 @@ impl QrVerification { if key != master_key { Err(ScanError::KeyMismatch { - expected: master_key.to_owned(), - found: qr_code.first_key().to_owned(), + expected: master_key.to_base64(), + found: qr_code.first_key().to_base64(), }) } else { Ok(()) @@ -558,24 +559,24 @@ impl QrVerification { } QrVerificationData::SelfVerification(_) => { check_master_key(qr_code.first_key(), &other_identity)?; - if qr_code.second_key() != store.account.identity_keys().ed25519.to_base64() { + if qr_code.second_key() != store.account.identity_keys().ed25519 { return Err(ScanError::KeyMismatch { expected: store.account.identity_keys().ed25519.to_base64(), - found: qr_code.second_key().to_owned(), + found: qr_code.second_key().to_base64(), }); } (other_device, Some(other_identity)) } QrVerificationData::SelfVerificationNoMasterKey(_) => { - let device_key = - other_device.get_key(DeviceKeyAlgorithm::Ed25519).ok_or_else(|| { - ScanError::MissingDeviceKeys(other_user_id.clone(), other_device_id.clone()) - })?; + let device_key = other_device.ed25519_key().ok_or_else(|| { + ScanError::MissingDeviceKeys(other_user_id.clone(), other_device_id.clone()) + })?; + if qr_code.first_key() != device_key { return Err(ScanError::KeyMismatch { - expected: device_key.to_owned(), - found: qr_code.first_key().to_owned(), + expected: device_key.to_base64(), + found: qr_code.first_key().to_base64(), }); } check_master_key(qr_code.second_key(), &other_identity)?; @@ -834,7 +835,7 @@ mod test { let private_identity = PrivateCrossSigningIdentity::new(user_id().to_owned()).await; let flow_id = FlowId::ToDevice("test_transaction".into()); - let device_key = account.identity_keys.ed25519.to_base64(); + let device_key = account.identity_keys.ed25519; let master_key = private_identity.master_public_key().await.unwrap(); let master_key = master_key.get_first_key().unwrap().to_owned(); @@ -850,26 +851,26 @@ mod test { let verification = QrVerification::new_self_no_master( store.clone(), flow_id.clone(), - master_key.clone(), + master_key, identities.clone(), false, None, ); - assert_eq!(verification.inner.first_key(), &device_key); - assert_eq!(verification.inner.second_key(), &master_key); + assert_eq!(verification.inner.first_key(), device_key); + assert_eq!(verification.inner.second_key(), master_key); let verification = QrVerification::new_self( flow_id, - master_key.clone(), - device_key.clone(), + master_key, + device_key, identities.clone(), false, None, ); - assert_eq!(verification.inner.first_key(), &master_key); - assert_eq!(verification.inner.second_key(), &device_key); + assert_eq!(verification.inner.first_key(), master_key); + assert_eq!(verification.inner.second_key(), device_key); let bob_identity = PrivateCrossSigningIdentity::new(user_id!("@bob:example").to_owned()).await; @@ -879,17 +880,11 @@ mod test { let flow_id = FlowId::InRoom(room_id!("!test:example").to_owned(), event_id!("$EVENTID").to_owned()); - let verification = QrVerification::new_cross( - flow_id, - master_key.clone(), - bob_master_key.clone(), - identities, - false, - None, - ); + let verification = + QrVerification::new_cross(flow_id, master_key, bob_master_key, identities, false, None); - assert_eq!(verification.inner.first_key(), &master_key); - assert_eq!(verification.inner.second_key(), &bob_master_key); + assert_eq!(verification.inner.first_key(), master_key); + assert_eq!(verification.inner.second_key(), bob_master_key); } #[async_test] @@ -929,7 +924,7 @@ mod test { let alice_verification = QrVerification::new_self_no_master( store, flow_id.clone(), - master_key.clone(), + master_key, identities, false, None, diff --git a/crates/matrix-sdk-crypto/src/verification/requests.rs b/crates/matrix-sdk-crypto/src/verification/requests.rs index c5ca0fb67..c22dd5a16 100644 --- a/crates/matrix-sdk-crypto/src/verification/requests.rs +++ b/crates/matrix-sdk-crypto/src/verification/requests.rs @@ -20,8 +20,6 @@ use std::{ #[cfg(feature = "qrcode")] use matrix_qrcode::QrVerificationData; use matrix_sdk_common::{instant::Instant, util::milli_seconds_since_unix_epoch}; -#[cfg(feature = "qrcode")] -use ruma::DeviceKeyAlgorithm; use ruma::{ events::{ key::verification::{ @@ -1004,9 +1002,7 @@ impl RequestState { ReadOnlyUserIdentities::Own(i) => { if let Some(master_key) = i.master_key().get_first_key() { if identites.can_sign_devices().await { - if let Some(device_key) = - identites.other_device().get_key(DeviceKeyAlgorithm::Ed25519) - { + if let Some(device_key) = identites.other_device().ed25519_key() { Some(QrVerification::new_self( self.flow_id.as_ref().to_owned(), master_key.to_owned(), diff --git a/crates/matrix-sdk-crypto/src/verification/sas/helpers.rs b/crates/matrix-sdk-crypto/src/verification/sas/helpers.rs index 5a92929f7..646cee93c 100644 --- a/crates/matrix-sdk-crypto/src/verification/sas/helpers.rs +++ b/crates/matrix-sdk-crypto/src/verification/sas/helpers.rs @@ -229,7 +229,7 @@ pub fn receive_mac_event( if let Some(key) = ids.other_device.keys().get(&key_id) { let calculated_mac = Base64::parse( - sas.calculate_mac_invalid_base64(key, &format!("{}{}", info, key_id)), + sas.calculate_mac_invalid_base64(&key.to_base64(), &format!("{}{}", info, key_id)), ) .expect("Can't base64-decode SAS MAC"); @@ -243,9 +243,10 @@ pub fn receive_mac_event( if let Some(key) = identity.master_key().get_key(&key_id) { // TODO we should check that the master key signs the device, // this way we know the master key also trusts the device - let calculated_mac = Base64::parse( - sas.calculate_mac_invalid_base64(key, &format!("{}{}", info, key_id)), - ) + let calculated_mac = Base64::parse(sas.calculate_mac_invalid_base64( + &key.to_base64(), + &format!("{}{}", info, key_id), + )) .expect("Can't base64-decode SAS MAC"); if *key_mac == calculated_mac { @@ -318,11 +319,12 @@ pub fn get_mac_content(sas: &EstablishedSas, ids: &SasIds, flow_id: &FlowId) -> if let Some(own_identity) = &ids.own_identity { if own_identity.is_verified() { if let Some(key) = own_identity.master_key().get_first_key() { - let key_id = format!("{}:{}", DeviceKeyAlgorithm::Ed25519, &key); + let key_id = format!("{}:{}", DeviceKeyAlgorithm::Ed25519, key.to_base64()); - let calculated_mac = Base64::parse( - sas.calculate_mac_invalid_base64(key, &format!("{}{}", info, &key_id)), - ) + let calculated_mac = Base64::parse(sas.calculate_mac_invalid_base64( + &key.to_base64(), + &format!("{}{}", info, &key_id), + )) .expect("Can't base64-decode SAS Master key MAC"); mac.insert(key_id, calculated_mac); diff --git a/crates/matrix-sdk-indexeddb/src/cryptostore.rs b/crates/matrix-sdk-indexeddb/src/cryptostore.rs index 6c9146562..370c23df8 100644 --- a/crates/matrix-sdk-indexeddb/src/cryptostore.rs +++ b/crates/matrix-sdk-indexeddb/src/cryptostore.rs @@ -324,11 +324,11 @@ impl IndexeddbStore { let sessions = tx.object_store(KEYS::SESSION)?; for session in &changes.sessions { - let sender_key = session.sender_key(); + let sender_key = session.sender_key().to_base64(); let session_id = session.session_id(); let pickle = session.pickle().await; - let key = (sender_key, session_id).encode(); + let key = (&sender_key, session_id).encode(); sessions.put_key_val(&key, &self.serialize_value(&pickle)?)?; } diff --git a/crates/matrix-sdk-sled/src/cryptostore.rs b/crates/matrix-sdk-sled/src/cryptostore.rs index c5fb34698..c37be9cac 100644 --- a/crates/matrix-sdk-sled/src/cryptostore.rs +++ b/crates/matrix-sdk-sled/src/cryptostore.rs @@ -193,7 +193,7 @@ impl EncodeSecureKey for ReadOnlyDevice { impl EncodeKey for Session { fn encode(&self) -> Vec { - let sender_key = self.sender_key(); + let sender_key = self.sender_key().to_base64(); let session_id = self.session_id(); [sender_key.as_bytes(), &[Self::SEPARATOR], session_id.as_bytes(), &[Self::SEPARATOR]] @@ -249,7 +249,8 @@ impl EncodeSecureKey for (&RoomId, &str, &str) { impl EncodeSecureKey for Session { fn encode_secure(&self, table_name: &str, store_cipher: &StoreCipher) -> Vec { - let sender_key = store_cipher.hash_key(table_name, self.sender_key().as_bytes()); + let sender_key = + store_cipher.hash_key(table_name, self.sender_key().to_base64().as_bytes()); let session_id = store_cipher.hash_key(table_name, self.session_id().as_bytes()); [sender_key.as_slice(), &[Self::SEPARATOR], session_id.as_slice(), &[Self::SEPARATOR]] diff --git a/crates/matrix-sdk/src/encryption/identities/users.rs b/crates/matrix-sdk/src/encryption/identities/users.rs index c1d8bd42b..cf06ad262 100644 --- a/crates/matrix-sdk/src/encryption/identities/users.rs +++ b/crates/matrix-sdk/src/encryption/identities/users.rs @@ -379,7 +379,7 @@ impl UserIdentity { /// // matches what we expect, for this we fetch the first public key we /// // can find, there's currently only a single key allowed so this is /// // fine. - /// if user.master_key().get_first_key() == Some("MyMasterKey") { + /// if user.master_key().get_first_key().map(|k| k.to_base64()) == Some("MyMasterKey".to_string()) { /// println!( /// "Master keys match for user {}, marking the user as verified", /// user.user_id().as_str(),