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)]
71#[allow(missing_debug_implementations)]
72pub struct ExportedRoomKey {
73 pub algorithm: EventEncryptionAlgorithm,
75
76 pub room_id: OwnedRoomId,
78
79 #[serde(deserialize_with = "deserialize_curve_key", serialize_with = "serialize_curve_key")]
81 pub sender_key: Curve25519PublicKey,
82
83 pub session_id: String,
85
86 pub session_key: ExportedSessionKey,
88
89 #[serde(default)]
91 pub sender_claimed_keys: SigningKeys<DeviceKeyAlgorithm>,
92
93 #[serde(
96 default,
97 deserialize_with = "deserialize_curve_key_vec",
98 serialize_with = "serialize_curve_key_vec"
99 )]
100 pub forwarding_curve25519_key_chain: Vec<Curve25519PublicKey>,
101
102 #[serde(default, rename = "org.matrix.msc3061.shared_history")]
108 pub shared_history: bool,
109}
110
111impl ExportedRoomKey {
112 pub fn from_backed_up_room_key(
116 room_id: OwnedRoomId,
117 session_id: String,
118 room_key: BackedUpRoomKey,
119 ) -> Self {
120 let BackedUpRoomKey {
121 algorithm,
122 sender_key,
123 session_key,
124 sender_claimed_keys,
125 forwarding_curve25519_key_chain,
126 shared_history,
127 } = room_key;
128
129 Self {
130 algorithm,
131 room_id,
132 sender_key,
133 session_id,
134 session_key,
135 sender_claimed_keys,
136 forwarding_curve25519_key_chain,
137 shared_history,
138 }
139 }
140}
141
142#[derive(Deserialize, Serialize)]
149#[allow(missing_debug_implementations)]
150pub struct BackedUpRoomKey {
151 pub algorithm: EventEncryptionAlgorithm,
153
154 #[serde(deserialize_with = "deserialize_curve_key", serialize_with = "serialize_curve_key")]
156 pub sender_key: Curve25519PublicKey,
157
158 pub session_key: ExportedSessionKey,
160
161 pub sender_claimed_keys: SigningKeys<DeviceKeyAlgorithm>,
163
164 #[serde(
167 default,
168 deserialize_with = "deserialize_curve_key_vec",
169 serialize_with = "serialize_curve_key_vec"
170 )]
171 pub forwarding_curve25519_key_chain: Vec<Curve25519PublicKey>,
172
173 #[serde(default, rename = "org.matrix.msc3061.shared_history")]
179 pub shared_history: bool,
180}
181
182impl TryFrom<ExportedRoomKey> for ForwardedRoomKeyContent {
183 type Error = SessionExportError;
184
185 fn try_from(room_key: ExportedRoomKey) -> Result<ForwardedRoomKeyContent, Self::Error> {
191 match room_key.algorithm {
192 EventEncryptionAlgorithm::MegolmV1AesSha2 => {
193 if let Some(SigningKey::Ed25519(claimed_ed25519_key)) =
200 room_key.sender_claimed_keys.get(&DeviceKeyAlgorithm::Ed25519)
201 {
202 Ok(ForwardedRoomKeyContent::MegolmV1AesSha2(
203 ForwardedMegolmV1AesSha2Content {
204 room_id: room_key.room_id,
205 session_id: room_key.session_id,
206 session_key: room_key.session_key,
207 claimed_sender_key: room_key.sender_key,
208 claimed_ed25519_key: *claimed_ed25519_key,
209 forwarding_curve25519_key_chain: room_key
210 .forwarding_curve25519_key_chain
211 .clone(),
212 other: Default::default(),
213 }
214 .into(),
215 ))
216 } else {
217 Err(SessionExportError::MissingEd25519Key)
218 }
219 }
220 #[cfg(feature = "experimental-algorithms")]
221 EventEncryptionAlgorithm::MegolmV2AesSha2 => {
222 Ok(ForwardedRoomKeyContent::MegolmV2AesSha2(
223 ForwardedMegolmV2AesSha2Content {
224 room_id: room_key.room_id,
225 session_id: room_key.session_id,
226 session_key: room_key.session_key,
227 claimed_sender_key: room_key.sender_key,
228 claimed_signing_keys: room_key.sender_claimed_keys,
229 other: Default::default(),
230 }
231 .into(),
232 ))
233 }
234 _ => Err(SessionExportError::Algorithm(room_key.algorithm)),
235 }
236 }
237}
238
239impl From<ExportedRoomKey> for BackedUpRoomKey {
240 fn from(value: ExportedRoomKey) -> Self {
241 let ExportedRoomKey {
242 algorithm,
243 room_id: _,
244 sender_key,
245 session_id: _,
246 session_key,
247 sender_claimed_keys,
248 forwarding_curve25519_key_chain,
249 shared_history,
250 } = value;
251
252 Self {
253 algorithm,
254 sender_key,
255 session_key,
256 sender_claimed_keys,
257 forwarding_curve25519_key_chain,
258 shared_history,
259 }
260 }
261}
262
263impl TryFrom<ForwardedRoomKeyContent> for ExportedRoomKey {
264 type Error = SessionExportError;
265
266 fn try_from(forwarded_key: ForwardedRoomKeyContent) -> Result<Self, Self::Error> {
268 let algorithm = forwarded_key.algorithm();
269
270 match forwarded_key {
271 ForwardedRoomKeyContent::MegolmV1AesSha2(content) => {
272 let mut sender_claimed_keys = SigningKeys::new();
273 sender_claimed_keys
274 .insert(DeviceKeyAlgorithm::Ed25519, content.claimed_ed25519_key.into());
275
276 Ok(Self {
277 algorithm,
278 room_id: content.room_id,
279 session_id: content.session_id,
280 forwarding_curve25519_key_chain: content.forwarding_curve25519_key_chain,
281 sender_claimed_keys,
282 sender_key: content.claimed_sender_key,
283 session_key: content.session_key,
284 shared_history: false,
285 })
286 }
287 #[cfg(feature = "experimental-algorithms")]
288 ForwardedRoomKeyContent::MegolmV2AesSha2(content) => Ok(Self {
289 algorithm,
290 room_id: content.room_id,
291 session_id: content.session_id,
292 forwarding_curve25519_key_chain: Default::default(),
293 sender_claimed_keys: content.claimed_signing_keys,
294 sender_key: content.claimed_sender_key,
295 session_key: content.session_key,
296 shared_history: false,
297 }),
298 ForwardedRoomKeyContent::Unknown(c) => Err(SessionExportError::Algorithm(c.algorithm)),
299 }
300 }
301}
302
303#[cfg(test)]
304mod tests {
305 use serde_json::json;
306
307 use super::BackedUpRoomKey;
308
309 #[test]
310 fn test_deserialize_backed_up_key() {
311 let data = json!({
312 "algorithm": "m.megolm.v1.aes-sha2",
313 "room_id": "!room:id",
314 "sender_key": "FOvlmz18LLI3k/llCpqRoKT90+gFF8YhuL+v1YBXHlw",
315 "session_id": "/2K+V777vipCxPZ0gpY9qcpz1DYaXwuMRIu0UEP0Wa0",
316 "session_key": "AQAAAAAclzWVMeWBKH+B/WMowa3rb4ma3jEl6n5W4GCs9ue65CruzD3ihX+85pZ9hsV9Bf6fvhjp76WNRajoJYX0UIt7aosjmu0i+H+07hEQ0zqTKpVoSH0ykJ6stAMhdr6Q4uW5crBmdTTBIsqmoWsNJZKKoE2+ldYrZ1lrFeaJbjBIY/9ivle++74qQsT2dIKWPanKc9Q2Gl8LjESLtFBD9Fmt",
317 "sender_claimed_keys": {
318 "ed25519": "F4P7f1Z0RjbiZMgHk1xBCG3KC4/Ng9PmxLJ4hQ13sHA"
319 },
320 "forwarding_curve25519_key_chain": ["DBPC2zr6c9qimo9YRFK3RVr0Two/I6ODb9mbsToZN3Q", "bBc/qzZFOOKshMMT+i4gjS/gWPDoKfGmETs9yfw9430"]
321 });
322
323 let backed_up_room_key: BackedUpRoomKey = serde_json::from_value(data)
324 .expect("We should be able to deserialize the backed up room key.");
325 assert_eq!(
326 backed_up_room_key.forwarding_curve25519_key_chain.len(),
327 2,
328 "The number of forwarding Curve25519 chains should be two."
329 );
330 }
331}