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