matrix_sdk_crypto/olm/group_sessions/
mod.rs1use ruma::{DeviceKeyAlgorithm, OwnedRoomId};
16use serde::{Deserialize, Serialize};
17
18mod forwarder_data;
19mod inbound;
20mod outbound;
21mod sender_data;
22pub(crate) mod sender_data_finder;
23
24pub use forwarder_data::ForwarderData;
25pub use inbound::{InboundGroupSession, PickledInboundGroupSession};
26pub(crate) use outbound::ShareState;
27pub use outbound::{
28 EncryptionSettings, OutboundGroupSession, OutboundGroupSessionEncryptionResult,
29 PickledOutboundGroupSession, ShareInfo,
30};
31pub use sender_data::{KnownSenderData, SenderData, SenderDataType};
32use thiserror::Error;
33pub use vodozemac::megolm::{ExportedSessionKey, SessionKey};
34use vodozemac::{Curve25519PublicKey, megolm::SessionKeyDecodeError};
35
36#[cfg(feature = "experimental-algorithms")]
37use crate::types::events::forwarded_room_key::ForwardedMegolmV2AesSha2Content;
38use crate::types::{
39 EventEncryptionAlgorithm, RoomKeyExport, SigningKey, SigningKeys, deserialize_curve_key,
40 deserialize_curve_key_vec,
41 events::forwarded_room_key::{ForwardedMegolmV1AesSha2Content, ForwardedRoomKeyContent},
42 serialize_curve_key, serialize_curve_key_vec,
43};
44
45#[derive(Debug, Error)]
47pub enum SessionCreationError {
48 #[error("The provided algorithm is not supported: {0}")]
50 Algorithm(EventEncryptionAlgorithm),
51 #[error(transparent)]
53 Decode(#[from] SessionKeyDecodeError),
54}
55
56#[derive(Debug, Error)]
61pub enum SessionExportError {
62 #[error("The provided algorithm is not supported: {0}")]
64 Algorithm(EventEncryptionAlgorithm),
65 #[error("The provided room key export is missing a claimed Ed25519 sender key")]
67 MissingEd25519Key,
68}
69
70#[derive(Deserialize, Serialize)]
76#[allow(missing_debug_implementations)]
77pub struct ExportedRoomKey {
78 pub algorithm: EventEncryptionAlgorithm,
80
81 pub room_id: OwnedRoomId,
83
84 #[serde(deserialize_with = "deserialize_curve_key", serialize_with = "serialize_curve_key")]
86 pub sender_key: Curve25519PublicKey,
87
88 pub session_id: String,
90
91 pub session_key: ExportedSessionKey,
93
94 #[serde(default)]
96 pub sender_claimed_keys: SigningKeys<DeviceKeyAlgorithm>,
97
98 #[serde(
101 default,
102 deserialize_with = "deserialize_curve_key_vec",
103 serialize_with = "serialize_curve_key_vec"
104 )]
105 pub forwarding_curve25519_key_chain: Vec<Curve25519PublicKey>,
106
107 #[serde(default, rename = "m.shared_history", alias = "org.matrix.msc3061.shared_history")]
113 pub shared_history: bool,
114}
115
116impl ExportedRoomKey {
117 pub fn from_backed_up_room_key(
121 room_id: OwnedRoomId,
122 session_id: String,
123 room_key: BackedUpRoomKey,
124 ) -> Self {
125 let BackedUpRoomKey {
126 algorithm,
127 sender_key,
128 session_key,
129 sender_claimed_keys,
130 forwarding_curve25519_key_chain,
131 shared_history,
132 } = room_key;
133
134 Self {
135 algorithm,
136 room_id,
137 sender_key,
138 session_id,
139 session_key,
140 sender_claimed_keys,
141 forwarding_curve25519_key_chain,
142 shared_history,
143 }
144 }
145}
146
147impl RoomKeyExport for &ExportedRoomKey {
148 fn room_id(&self) -> &ruma::RoomId {
149 &self.room_id
150 }
151
152 fn session_id(&self) -> &str {
153 &self.session_id
154 }
155
156 fn sender_key(&self) -> Curve25519PublicKey {
157 self.sender_key
158 }
159}
160
161#[derive(Deserialize, Serialize)]
173#[allow(missing_debug_implementations)]
174pub struct BackedUpRoomKey {
175 pub algorithm: EventEncryptionAlgorithm,
177
178 #[serde(deserialize_with = "deserialize_curve_key", serialize_with = "serialize_curve_key")]
180 pub sender_key: Curve25519PublicKey,
181
182 pub session_key: ExportedSessionKey,
184
185 pub sender_claimed_keys: SigningKeys<DeviceKeyAlgorithm>,
187
188 #[serde(
191 default,
192 deserialize_with = "deserialize_curve_key_vec",
193 serialize_with = "serialize_curve_key_vec"
194 )]
195 pub forwarding_curve25519_key_chain: Vec<Curve25519PublicKey>,
196
197 #[serde(default, rename = "m.shared_history", alias = "org.matrix.msc3061.shared_history")]
203 pub shared_history: bool,
204}
205
206impl TryFrom<ExportedRoomKey> for ForwardedRoomKeyContent {
207 type Error = SessionExportError;
208
209 fn try_from(room_key: ExportedRoomKey) -> Result<ForwardedRoomKeyContent, Self::Error> {
215 match room_key.algorithm {
216 EventEncryptionAlgorithm::MegolmV1AesSha2 => {
217 if let Some(SigningKey::Ed25519(claimed_ed25519_key)) =
225 room_key.sender_claimed_keys.get(&DeviceKeyAlgorithm::Ed25519)
226 {
227 Ok(ForwardedRoomKeyContent::MegolmV1AesSha2(
228 ForwardedMegolmV1AesSha2Content {
229 room_id: room_key.room_id,
230 session_id: room_key.session_id,
231 session_key: room_key.session_key,
232 claimed_sender_key: room_key.sender_key,
233 claimed_ed25519_key: *claimed_ed25519_key,
234 forwarding_curve25519_key_chain: room_key
235 .forwarding_curve25519_key_chain
236 .clone(),
237 other: Default::default(),
238 }
239 .into(),
240 ))
241 } else {
242 Err(SessionExportError::MissingEd25519Key)
243 }
244 }
245 #[cfg(feature = "experimental-algorithms")]
246 EventEncryptionAlgorithm::MegolmV2AesSha2 => {
247 Ok(ForwardedRoomKeyContent::MegolmV2AesSha2(
248 ForwardedMegolmV2AesSha2Content {
249 room_id: room_key.room_id,
250 session_id: room_key.session_id,
251 session_key: room_key.session_key,
252 claimed_sender_key: room_key.sender_key,
253 claimed_signing_keys: room_key.sender_claimed_keys,
254 other: Default::default(),
255 }
256 .into(),
257 ))
258 }
259 _ => Err(SessionExportError::Algorithm(room_key.algorithm)),
260 }
261 }
262}
263
264impl From<ExportedRoomKey> for BackedUpRoomKey {
265 fn from(value: ExportedRoomKey) -> Self {
266 let ExportedRoomKey {
267 algorithm,
268 room_id: _,
269 sender_key,
270 session_id: _,
271 session_key,
272 sender_claimed_keys,
273 forwarding_curve25519_key_chain,
274 shared_history,
275 } = value;
276
277 Self {
278 algorithm,
279 sender_key,
280 session_key,
281 sender_claimed_keys,
282 forwarding_curve25519_key_chain,
283 shared_history,
284 }
285 }
286}
287
288impl TryFrom<ForwardedRoomKeyContent> for ExportedRoomKey {
289 type Error = SessionExportError;
290
291 fn try_from(forwarded_key: ForwardedRoomKeyContent) -> Result<Self, Self::Error> {
293 let algorithm = forwarded_key.algorithm();
294
295 match forwarded_key {
296 ForwardedRoomKeyContent::MegolmV1AesSha2(content) => {
297 let mut sender_claimed_keys = SigningKeys::new();
298 sender_claimed_keys
299 .insert(DeviceKeyAlgorithm::Ed25519, content.claimed_ed25519_key.into());
300
301 Ok(Self {
302 algorithm,
303 room_id: content.room_id,
304 session_id: content.session_id,
305 forwarding_curve25519_key_chain: content.forwarding_curve25519_key_chain,
306 sender_claimed_keys,
307 sender_key: content.claimed_sender_key,
308 session_key: content.session_key,
309 shared_history: false,
310 })
311 }
312 #[cfg(feature = "experimental-algorithms")]
313 ForwardedRoomKeyContent::MegolmV2AesSha2(content) => Ok(Self {
314 algorithm,
315 room_id: content.room_id,
316 session_id: content.session_id,
317 forwarding_curve25519_key_chain: Default::default(),
318 sender_claimed_keys: content.claimed_signing_keys,
319 sender_key: content.claimed_sender_key,
320 session_key: content.session_key,
321 shared_history: false,
322 }),
323 ForwardedRoomKeyContent::Unknown(c) => Err(SessionExportError::Algorithm(c.algorithm)),
324 }
325 }
326}
327
328#[cfg(test)]
329mod tests {
330 use serde_json::json;
331
332 use super::BackedUpRoomKey;
333
334 #[test]
335 fn test_deserialize_backed_up_key() {
336 let data = json!({
337 "algorithm": "m.megolm.v1.aes-sha2",
338 "room_id": "!room:id",
339 "sender_key": "FOvlmz18LLI3k/llCpqRoKT90+gFF8YhuL+v1YBXHlw",
340 "session_id": "/2K+V777vipCxPZ0gpY9qcpz1DYaXwuMRIu0UEP0Wa0",
341 "session_key": "AQAAAAAclzWVMeWBKH+B/WMowa3rb4ma3jEl6n5W4GCs9ue65CruzD3ihX+85pZ9hsV9Bf6fvhjp76WNRajoJYX0UIt7aosjmu0i+H+07hEQ0zqTKpVoSH0ykJ6stAMhdr6Q4uW5crBmdTTBIsqmoWsNJZKKoE2+ldYrZ1lrFeaJbjBIY/9ivle++74qQsT2dIKWPanKc9Q2Gl8LjESLtFBD9Fmt",
342 "sender_claimed_keys": {
343 "ed25519": "F4P7f1Z0RjbiZMgHk1xBCG3KC4/Ng9PmxLJ4hQ13sHA"
344 },
345 "forwarding_curve25519_key_chain": ["DBPC2zr6c9qimo9YRFK3RVr0Two/I6ODb9mbsToZN3Q", "bBc/qzZFOOKshMMT+i4gjS/gWPDoKfGmETs9yfw9430"]
346 });
347
348 let backed_up_room_key: BackedUpRoomKey = serde_json::from_value(data)
349 .expect("We should be able to deserialize the backed up room key.");
350 assert_eq!(
351 backed_up_room_key.forwarding_curve25519_key_chain.len(),
352 2,
353 "The number of forwarding Curve25519 chains should be two."
354 );
355 }
356}