matrix_sdk_crypto/backups/keys/
backup.rs1use std::sync::Arc;
16
17use matrix_sdk_common::locks::Mutex;
18use ruma::{
19 api::client::backup::{EncryptedSessionDataInit, KeyBackupData, KeyBackupDataInit},
20 serde::Base64,
21};
22use vodozemac::{pk_encryption::PkEncryption, Curve25519PublicKey};
23use zeroize::Zeroizing;
24
25use super::decryption::DecodeError;
26use crate::{olm::InboundGroupSession, types::Signatures};
27
28#[derive(Debug)]
29struct InnerBackupKey {
30 key: Curve25519PublicKey,
31 signatures: Signatures,
32 version: Mutex<Option<String>>,
33}
34
35#[derive(Clone)]
37pub struct MegolmV1BackupKey {
38 inner: Arc<InnerBackupKey>,
39}
40
41#[cfg(not(tarpaulin_include))]
42impl std::fmt::Debug for MegolmV1BackupKey {
43 fn fmt(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
44 formatter
45 .debug_struct("MegolmV1BackupKey")
46 .field("key", &self.to_base64())
47 .field("version", &self.backup_version())
48 .finish()
49 }
50}
51
52impl MegolmV1BackupKey {
53 pub(super) fn new(key: Curve25519PublicKey, version: Option<String>) -> Self {
54 Self {
55 inner: InnerBackupKey {
56 key,
57 signatures: Default::default(),
58 version: Mutex::new(version),
59 }
60 .into(),
61 }
62 }
63
64 pub fn backup_algorithm(&self) -> &str {
66 "m.megolm_backup.v1.curve25519-aes-sha2"
67 }
68
69 pub fn signatures(&self) -> Signatures {
71 self.inner.signatures.to_owned()
72 }
73
74 pub fn from_base64(public_key: &str) -> Result<Self, DecodeError> {
76 let key = Curve25519PublicKey::from_base64(public_key)?;
77
78 let inner =
79 InnerBackupKey { key, signatures: Default::default(), version: Mutex::new(None) };
80
81 Ok(MegolmV1BackupKey { inner: inner.into() })
82 }
83
84 pub fn to_base64(&self) -> String {
86 self.inner.key.to_base64()
87 }
88
89 pub fn backup_version(&self) -> Option<String> {
91 self.inner.version.lock().clone()
92 }
93
94 pub fn set_version(&self, version: String) {
99 *self.inner.version.lock() = Some(version);
100 }
101
102 pub async fn encrypt(&self, session: InboundGroupSession) -> KeyBackupData {
105 let pk = PkEncryption::from_key(self.inner.key);
106
107 let forwarded_count = (session.has_been_imported() as u8).into();
110 let first_message_index = session.first_known_index().into();
111
112 let key = session.to_backup().await;
114
115 let key =
118 Zeroizing::new(serde_json::to_vec(&key).expect("Can't serialize exported room key"));
119
120 let message = pk.encrypt(&key);
121
122 let session_data = EncryptedSessionDataInit {
123 ephemeral: Base64::new(message.ephemeral_key.to_vec()),
124 ciphertext: Base64::new(message.ciphertext),
125 mac: Base64::new(message.mac),
126 }
127 .into();
128
129 KeyBackupDataInit {
130 first_message_index,
131 forwarded_count,
132 is_verified: false,
137 session_data,
138 }
139 .into()
140 }
141}