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