ruma_events/secret_storage/
secret.rs1use std::collections::BTreeMap;
4
5use ruma_common::serde::{Base64, JsonCastable, Raw};
6use serde::{Deserialize, Serialize};
7
8#[derive(Clone, Debug, Serialize, Deserialize)]
10#[cfg_attr(not(ruma_unstable_exhaustive_types), non_exhaustive)]
11pub struct SecretEventContent {
12 pub encrypted: BTreeMap<String, Raw<SecretEncryptedData>>,
16}
17
18impl SecretEventContent {
19 pub fn new(encrypted: BTreeMap<String, Raw<SecretEncryptedData>>) -> Self {
21 Self { encrypted }
22 }
23}
24
25#[non_exhaustive]
37pub struct SecretEncryptedData;
38
39impl SecretEncryptedData {
40 pub fn new<T: JsonCastable<Self>>(encrypted_data: Raw<T>) -> Raw<Self> {
42 encrypted_data.cast()
43 }
44
45 pub fn serialize<T: Serialize + JsonCastable<Self>>(
47 encrypted_data: &T,
48 ) -> Result<Raw<Self>, serde_json::Error> {
49 Raw::new(encrypted_data).map(Raw::cast)
50 }
51
52 pub fn deserialize_as_aes_hmac_sha2(
54 encrypted_data: &Raw<Self>,
55 ) -> Result<AesHmacSha2EncryptedData, serde_json::Error> {
56 encrypted_data.deserialize_as()
57 }
58}
59
60#[derive(Clone, Debug, Serialize, Deserialize)]
62#[cfg_attr(not(ruma_unstable_exhaustive_types), non_exhaustive)]
63pub struct AesHmacSha2EncryptedData {
64 pub iv: Base64,
66
67 pub ciphertext: Base64,
69
70 pub mac: Base64,
72}
73
74impl AesHmacSha2EncryptedData {
75 pub fn new(iv: Base64, ciphertext: Base64, mac: Base64) -> Self {
77 Self { iv, ciphertext, mac }
78 }
79}
80
81impl JsonCastable<SecretEncryptedData> for AesHmacSha2EncryptedData {}
82
83impl JsonCastable<AesHmacSha2EncryptedData> for SecretEncryptedData {}
84
85#[cfg(test)]
86mod tests {
87 use std::collections::BTreeMap;
88
89 use assert_matches2::assert_matches;
90 use ruma_common::{canonical_json::assert_to_canonical_json_eq, serde::Base64};
91 use serde_json::{from_value as from_json_value, json};
92
93 use super::{AesHmacSha2EncryptedData, SecretEncryptedData, SecretEventContent};
94
95 #[test]
96 fn test_secret_serialization() {
97 let key_one_data = AesHmacSha2EncryptedData {
98 iv: Base64::parse("YWJjZGVmZ2hpamtsbW5vcA").unwrap(),
99 ciphertext: Base64::parse("dGhpc2lzZGVmaW5pdGVseWNpcGhlcnRleHQ").unwrap(),
100 mac: Base64::parse("aWRvbnRrbm93d2hhdGFtYWNsb29rc2xpa2U").unwrap(),
101 };
102
103 let mut encrypted = BTreeMap::new();
104 encrypted
105 .insert("key_one".to_owned(), SecretEncryptedData::serialize(&key_one_data).unwrap());
106
107 let content = SecretEventContent::new(encrypted);
108
109 assert_to_canonical_json_eq!(
110 content,
111 json!({
112 "encrypted": {
113 "key_one" : {
114 "iv": "YWJjZGVmZ2hpamtsbW5vcA",
115 "ciphertext": "dGhpc2lzZGVmaW5pdGVseWNpcGhlcnRleHQ",
116 "mac": "aWRvbnRrbm93d2hhdGFtYWNsb29rc2xpa2U",
117 },
118 },
119 }),
120 );
121 }
122
123 #[test]
124 fn test_secret_deserialization() {
125 let json = json!({
126 "encrypted": {
127 "key_one" : {
128 "iv": "YWJjZGVmZ2hpamtsbW5vcA",
129 "ciphertext": "dGhpc2lzZGVmaW5pdGVseWNpcGhlcnRleHQ",
130 "mac": "aWRvbnRrbm93d2hhdGFtYWNsb29rc2xpa2U"
131 }
132 }
133 });
134
135 let deserialized: SecretEventContent = from_json_value(json).unwrap();
136 let secret_data = deserialized.encrypted.get("key_one").unwrap();
137
138 assert_matches!(
139 SecretEncryptedData::deserialize_as_aes_hmac_sha2(secret_data),
140 Ok(AesHmacSha2EncryptedData { iv, ciphertext, mac })
141 );
142 assert_eq!(iv.encode(), "YWJjZGVmZ2hpamtsbW5vcA");
143 assert_eq!(ciphertext.encode(), "dGhpc2lzZGVmaW5pdGVseWNpcGhlcnRleHQ");
144 assert_eq!(mac.encode(), "aWRvbnRrbm93d2hhdGFtYWNsb29rc2xpa2U");
145 }
146}