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, SigningKey,
39 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
144#[derive(Deserialize, Serialize)]
153#[allow(missing_debug_implementations)]
154pub struct BackedUpRoomKey {
155 pub algorithm: EventEncryptionAlgorithm,
157
158 #[serde(deserialize_with = "deserialize_curve_key", serialize_with = "serialize_curve_key")]
160 pub sender_key: Curve25519PublicKey,
161
162 pub session_key: ExportedSessionKey,
164
165 pub sender_claimed_keys: SigningKeys<DeviceKeyAlgorithm>,
167
168 #[serde(
171 default,
172 deserialize_with = "deserialize_curve_key_vec",
173 serialize_with = "serialize_curve_key_vec"
174 )]
175 pub forwarding_curve25519_key_chain: Vec<Curve25519PublicKey>,
176
177 #[serde(default, rename = "org.matrix.msc3061.shared_history")]
183 pub shared_history: bool,
184}
185
186impl TryFrom<ExportedRoomKey> for ForwardedRoomKeyContent {
187 type Error = SessionExportError;
188
189 fn try_from(room_key: ExportedRoomKey) -> Result<ForwardedRoomKeyContent, Self::Error> {
195 match room_key.algorithm {
196 EventEncryptionAlgorithm::MegolmV1AesSha2 => {
197 if let Some(SigningKey::Ed25519(claimed_ed25519_key)) =
204 room_key.sender_claimed_keys.get(&DeviceKeyAlgorithm::Ed25519)
205 {
206 Ok(ForwardedRoomKeyContent::MegolmV1AesSha2(
207 ForwardedMegolmV1AesSha2Content {
208 room_id: room_key.room_id,
209 session_id: room_key.session_id,
210 session_key: room_key.session_key,
211 claimed_sender_key: room_key.sender_key,
212 claimed_ed25519_key: *claimed_ed25519_key,
213 forwarding_curve25519_key_chain: room_key
214 .forwarding_curve25519_key_chain
215 .clone(),
216 other: Default::default(),
217 }
218 .into(),
219 ))
220 } else {
221 Err(SessionExportError::MissingEd25519Key)
222 }
223 }
224 #[cfg(feature = "experimental-algorithms")]
225 EventEncryptionAlgorithm::MegolmV2AesSha2 => {
226 Ok(ForwardedRoomKeyContent::MegolmV2AesSha2(
227 ForwardedMegolmV2AesSha2Content {
228 room_id: room_key.room_id,
229 session_id: room_key.session_id,
230 session_key: room_key.session_key,
231 claimed_sender_key: room_key.sender_key,
232 claimed_signing_keys: room_key.sender_claimed_keys,
233 other: Default::default(),
234 }
235 .into(),
236 ))
237 }
238 _ => Err(SessionExportError::Algorithm(room_key.algorithm)),
239 }
240 }
241}
242
243impl From<ExportedRoomKey> for BackedUpRoomKey {
244 fn from(value: ExportedRoomKey) -> Self {
245 let ExportedRoomKey {
246 algorithm,
247 room_id: _,
248 sender_key,
249 session_id: _,
250 session_key,
251 sender_claimed_keys,
252 forwarding_curve25519_key_chain,
253 shared_history,
254 } = value;
255
256 Self {
257 algorithm,
258 sender_key,
259 session_key,
260 sender_claimed_keys,
261 forwarding_curve25519_key_chain,
262 shared_history,
263 }
264 }
265}
266
267impl TryFrom<ForwardedRoomKeyContent> for ExportedRoomKey {
268 type Error = SessionExportError;
269
270 fn try_from(forwarded_key: ForwardedRoomKeyContent) -> Result<Self, Self::Error> {
272 let algorithm = forwarded_key.algorithm();
273
274 match forwarded_key {
275 ForwardedRoomKeyContent::MegolmV1AesSha2(content) => {
276 let mut sender_claimed_keys = SigningKeys::new();
277 sender_claimed_keys
278 .insert(DeviceKeyAlgorithm::Ed25519, content.claimed_ed25519_key.into());
279
280 Ok(Self {
281 algorithm,
282 room_id: content.room_id,
283 session_id: content.session_id,
284 forwarding_curve25519_key_chain: content.forwarding_curve25519_key_chain,
285 sender_claimed_keys,
286 sender_key: content.claimed_sender_key,
287 session_key: content.session_key,
288 shared_history: false,
289 })
290 }
291 #[cfg(feature = "experimental-algorithms")]
292 ForwardedRoomKeyContent::MegolmV2AesSha2(content) => Ok(Self {
293 algorithm,
294 room_id: content.room_id,
295 session_id: content.session_id,
296 forwarding_curve25519_key_chain: Default::default(),
297 sender_claimed_keys: content.claimed_signing_keys,
298 sender_key: content.claimed_sender_key,
299 session_key: content.session_key,
300 shared_history: false,
301 }),
302 ForwardedRoomKeyContent::Unknown(c) => Err(SessionExportError::Algorithm(c.algorithm)),
303 }
304 }
305}
306
307#[cfg(test)]
308mod tests {
309 use serde_json::json;
310
311 use super::BackedUpRoomKey;
312
313 #[test]
314 fn test_deserialize_backed_up_key() {
315 let data = json!({
316 "algorithm": "m.megolm.v1.aes-sha2",
317 "room_id": "!room:id",
318 "sender_key": "FOvlmz18LLI3k/llCpqRoKT90+gFF8YhuL+v1YBXHlw",
319 "session_id": "/2K+V777vipCxPZ0gpY9qcpz1DYaXwuMRIu0UEP0Wa0",
320 "session_key": "AQAAAAAclzWVMeWBKH+B/WMowa3rb4ma3jEl6n5W4GCs9ue65CruzD3ihX+85pZ9hsV9Bf6fvhjp76WNRajoJYX0UIt7aosjmu0i+H+07hEQ0zqTKpVoSH0ykJ6stAMhdr6Q4uW5crBmdTTBIsqmoWsNJZKKoE2+ldYrZ1lrFeaJbjBIY/9ivle++74qQsT2dIKWPanKc9Q2Gl8LjESLtFBD9Fmt",
321 "sender_claimed_keys": {
322 "ed25519": "F4P7f1Z0RjbiZMgHk1xBCG3KC4/Ng9PmxLJ4hQ13sHA"
323 },
324 "forwarding_curve25519_key_chain": ["DBPC2zr6c9qimo9YRFK3RVr0Two/I6ODb9mbsToZN3Q", "bBc/qzZFOOKshMMT+i4gjS/gWPDoKfGmETs9yfw9430"]
325 });
326
327 let backed_up_room_key: BackedUpRoomKey = serde_json::from_value(data)
328 .expect("We should be able to deserialize the backed up room key.");
329 assert_eq!(
330 backed_up_room_key.forwarding_curve25519_key_chain.len(),
331 2,
332 "The number of forwarding Curve25519 chains should be two."
333 );
334 }
335}