1use std::fmt;
21
22pub use hmac::digest::MacError;
23use hmac::Hmac;
24use pbkdf2::pbkdf2;
25use rand::{
26 distributions::{Alphanumeric, DistString},
27 thread_rng, RngCore,
28};
29use ruma::{
30 events::{
31 secret::request::SecretName,
32 secret_storage::{
33 key::{
34 PassPhrase, SecretStorageEncryptionAlgorithm, SecretStorageKeyEventContent,
35 SecretStorageV1AesHmacSha2Properties,
36 },
37 secret::SecretEncryptedData,
38 },
39 GlobalAccountDataEventContent, GlobalAccountDataEventType,
40 },
41 serde::Base64,
42 UInt,
43};
44use serde::de::Error;
45use sha2::Sha512;
46use subtle::ConstantTimeEq;
47use thiserror::Error;
48use zeroize::{Zeroize, ZeroizeOnDrop};
49
50use crate::ciphers::{AesHmacSha2Key, HmacSha256Mac, IV_SIZE, KEY_SIZE, MAC_SIZE};
51
52#[derive(Debug, Error)]
60pub enum DecodeError {
61 #[error("The decoded secret storage key has an invalid prefix: expected {0:?}, got {1:?}")]
63 Prefix([u8; 2], [u8; 2]),
64 #[error("The parity byte of the secret storage key doesn't match: expected {0:?}, got {1:?}")]
66 Parity(u8, u8),
67 #[error(transparent)]
69 Base58(#[from] bs58::decode::Error),
70 #[error(transparent)]
72 Base64(#[from] vodozemac::Base64DecodeError),
73 #[error("The Base58 decoded key has an invalid length, expected {0}, got {1}")]
75 KeyLength(usize, usize),
76 #[error("The MAC check for the secret storage key failed")]
78 Mac(#[from] MacError),
79 #[error(
82 "The MAC of for the secret storage MAC check has an incorrect length, \
83 expected: {0}, got: {1}"
84 )]
85 MacLength(usize, usize),
86 #[error(
89 "The IV of for the secret storage key MAC check has an incorrect length, \
90 expected: {0}, got: {1}"
91 )]
92 IvLength(usize, usize),
93 #[error("The secret storage key is using an unsupported secret encryption algorithm: {0}")]
99 UnsupportedAlgorithm(String),
100 #[error(
103 "The passphrase-based secret storage key has an excessively high KDF iteration count: {0}"
104 )]
105 KdfIterationCount(UInt),
106}
107
108#[derive(Zeroize, ZeroizeOnDrop)]
144pub struct SecretStorageKey {
145 #[zeroize(skip)]
149 storage_key_info: SecretStorageKeyEventContent,
150 secret_key: Box<[u8; 32]>,
152}
153
154#[cfg(not(tarpaulin_include))]
155impl fmt::Debug for SecretStorageKey {
156 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
157 f.debug_struct("SecretStorageKey")
158 .field("storage_key_info", &self.storage_key_info)
159 .finish_non_exhaustive()
160 }
161}
162
163#[derive(Clone, Debug)]
165pub struct AesHmacSha2EncryptedData {
166 pub iv: [u8; IV_SIZE],
168 pub ciphertext: Base64,
170 pub mac: [u8; MAC_SIZE],
173}
174
175impl TryFrom<SecretEncryptedData> for AesHmacSha2EncryptedData {
176 type Error = serde_json::Error;
177
178 fn try_from(value: SecretEncryptedData) -> Result<Self, Self::Error> {
179 match value {
180 SecretEncryptedData::AesHmacSha2EncryptedData { iv, ciphertext, mac } => {
181 let iv_length = iv.as_bytes().len();
182 let mac_length = mac.as_bytes().len();
183
184 if iv_length != IV_SIZE {
185 Err(serde_json::Error::custom(format!(
186 "Invalid initialization vector length, expected length {IV_SIZE}, got: {iv_length}",
187 )))
188 } else if mac_length != MAC_SIZE {
189 Err(serde_json::Error::custom(format!(
190 "Invalid message authentication tag length, expected length {MAC_SIZE}, got: {mac_length}",
191 )))
192 } else {
193 let mut mac_array = [0u8; MAC_SIZE];
194 let mut iv_array = [0u8; IV_SIZE];
195
196 mac_array.copy_from_slice(mac.as_bytes());
197 iv_array.copy_from_slice(iv.as_bytes());
198
199 Ok(Self { iv: iv_array, ciphertext, mac: mac_array })
200 }
201 }
202 _ => Err(serde_json::Error::custom("Unsupported secret storage algorithm")),
203 }
204 }
205}
206
207impl From<AesHmacSha2EncryptedData> for SecretEncryptedData {
208 fn from(value: AesHmacSha2EncryptedData) -> Self {
209 SecretEncryptedData::AesHmacSha2EncryptedData {
210 iv: Base64::new(value.iv.to_vec()),
211 ciphertext: value.ciphertext,
212 mac: Base64::new(value.mac.to_vec()),
213 }
214 }
215}
216
217impl SecretStorageKey {
218 const ZERO_MESSAGE: &'static [u8; 32] = &[0u8; 32];
219 const PREFIX: [u8; 2] = [0x8b, 0x01];
220 const PREFIX_PARITY: u8 = Self::PREFIX[0] ^ Self::PREFIX[1];
221 const DEFAULT_KEY_ID_LEN: usize = 32;
222 #[cfg(not(test))]
223 const DEFAULT_PBKDF_ITERATIONS: u32 = 500_000;
224 #[cfg(test)]
225 const DEFAULT_PBKDF_ITERATIONS: u32 = 10;
226
227 const DECODED_BASE58_KEY_LEN: usize = 2 + 32 + 1;
230
231 fn parity_byte(bytes: &[u8]) -> u8 {
236 bytes.iter().fold(Self::PREFIX_PARITY, |acc, x| acc ^ x)
237 }
238
239 fn check_zero_message(&self) -> Result<(), DecodeError> {
252 match &self.storage_key_info.algorithm {
253 SecretStorageEncryptionAlgorithm::V1AesHmacSha2(properties) => {
254 let (Some(iv), Some(mac)) = (&properties.iv, &properties.mac) else {
255 return Ok(());
261 };
262
263 let iv = iv.as_bytes();
264 let iv_length = iv.len();
265
266 if iv_length != IV_SIZE {
267 return Err(DecodeError::IvLength(IV_SIZE, iv_length));
268 }
269
270 let mut iv_array = [0u8; 16];
271 iv_array.copy_from_slice(iv);
272
273 let key = AesHmacSha2Key::from_secret_storage_key(&self.secret_key, "");
281 let ciphertext = key.apply_keystream(Self::ZERO_MESSAGE.to_vec(), &iv_array);
282 let expected_mac = HmacSha256Mac::from_slice(mac.as_bytes())
283 .ok_or_else(|| DecodeError::MacLength(MAC_SIZE, mac.as_bytes().len()))?;
284
285 key.verify_mac(&ciphertext, expected_mac.as_bytes())?;
286
287 Ok(())
288 }
289 custom => Err(DecodeError::UnsupportedAlgorithm(custom.algorithm().to_owned())),
290 }
291 }
292
293 fn create_event_content(key_id: String, key: &[u8; KEY_SIZE]) -> SecretStorageKeyEventContent {
294 let key = AesHmacSha2Key::from_secret_storage_key(key, "");
295
296 let (ciphertext, iv) = key.encrypt(Self::ZERO_MESSAGE.to_vec());
297 let iv = Base64::new(iv.to_vec());
298 let mac = Base64::new(key.create_mac_tag(&ciphertext).as_bytes().to_vec());
299
300 SecretStorageKeyEventContent::new(
301 key_id,
302 SecretStorageEncryptionAlgorithm::V1AesHmacSha2(
303 SecretStorageV1AesHmacSha2Properties::new(Some(iv), Some(mac)),
304 ),
305 )
306 }
307
308 pub fn new() -> Self {
310 let mut key = Box::new([0u8; KEY_SIZE]);
311 let mut rng = thread_rng();
312 rng.fill_bytes(key.as_mut_slice());
313
314 let key_id = Alphanumeric.sample_string(&mut rng, Self::DEFAULT_KEY_ID_LEN);
315
316 Self::from_bytes(key_id, key)
317 }
318
319 pub fn new_from_passphrase(passphrase: &str) -> Self {
326 let mut key = Box::new([0u8; 32]);
327 let mut rng = thread_rng();
328 let salt = Alphanumeric.sample_string(&mut rng, Self::DEFAULT_KEY_ID_LEN);
329
330 pbkdf2::<Hmac<Sha512>>(
331 passphrase.as_bytes(),
332 salt.as_bytes(),
333 Self::DEFAULT_PBKDF_ITERATIONS,
334 key.as_mut_slice(),
335 )
336 .expect(
337 "We should be able to expand a passphrase of any length due to \
338 HMAC being able to be initialized with any input size",
339 );
340
341 let key_id = Alphanumeric.sample_string(&mut rng, Self::DEFAULT_KEY_ID_LEN);
342 let mut key = Self::from_bytes(key_id, key);
343
344 key.storage_key_info.passphrase =
345 Some(PassPhrase::new(salt, Self::DEFAULT_PBKDF_ITERATIONS.into()));
346
347 key
348 }
349
350 pub(crate) fn from_bytes(key_id: String, key: Box<[u8; KEY_SIZE]>) -> Self {
351 let storage_key_info = Self::create_event_content(key_id, &key);
352
353 Self { storage_key_info, secret_key: key }
354 }
355
356 pub fn from_account_data(
366 input: &str,
367 content: SecretStorageKeyEventContent,
368 ) -> Result<Self, DecodeError> {
369 let key = if let Some(passphrase_info) = &content.passphrase {
370 match Self::from_passphrase(input, &content, passphrase_info) {
373 Ok(key) => key,
374 Err(e) => Self::from_base58(input, &content).map_err(|_| e)?,
377 }
378 } else {
379 Self::from_base58(input, &content)?
381 };
382
383 Ok(key)
384 }
385
386 fn from_passphrase(
387 passphrase: &str,
388 key_info: &SecretStorageKeyEventContent,
389 passphrase_info: &PassPhrase,
390 ) -> Result<Self, DecodeError> {
391 let mut key = Box::new([0u8; 32]);
392 pbkdf2::<Hmac<Sha512>>(
393 passphrase.as_bytes(),
394 passphrase_info.salt.as_bytes(),
395 passphrase_info
396 .iterations
397 .try_into()
398 .map_err(|_| DecodeError::KdfIterationCount(passphrase_info.iterations))?,
399 key.as_mut_slice(),
400 )
401 .expect(
402 "We should be able to expand a passphrase of any length due to \
403 HMAC being able to be initialized with any input size",
404 );
405
406 let key = Self { storage_key_info: key_info.to_owned(), secret_key: key };
407 key.check_zero_message()?;
408
409 Ok(key)
410 }
411
412 fn parse_base58_key(value: &str) -> Result<Box<[u8; 32]>, DecodeError> {
417 let value: String = value.chars().filter(|c| !c.is_whitespace()).collect();
423
424 let mut decoded = bs58::decode(value).with_alphabet(bs58::Alphabet::BITCOIN).into_vec()?;
425
426 let mut prefix = [0u8; 2];
427 let mut key = Box::new([0u8; 32]);
428
429 let decoded_len = decoded.len();
430
431 if decoded_len != Self::DECODED_BASE58_KEY_LEN {
432 Err(DecodeError::KeyLength(Self::DECODED_BASE58_KEY_LEN, decoded_len))
433 } else {
434 prefix.copy_from_slice(&decoded[0..2]);
435 key.copy_from_slice(&decoded[2..34]);
436 let expected_parity = decoded[34];
437
438 decoded.zeroize();
439
440 let parity = Self::parity_byte(key.as_ref());
441
442 let unexpected_choice = prefix.ct_ne(&Self::PREFIX);
443 let unexpected_parity = expected_parity.ct_ne(&parity);
444
445 if unexpected_choice.into() {
446 Err(DecodeError::Prefix(Self::PREFIX, prefix))
447 } else if unexpected_parity.into() {
448 Err(DecodeError::Parity(expected_parity, parity))
449 } else {
450 Ok(key)
451 }
452 }
453 }
454
455 fn from_base58(
457 value: &str,
458 key_info: &SecretStorageKeyEventContent,
459 ) -> Result<Self, DecodeError> {
460 let secret_key = Self::parse_base58_key(value)?;
461 let key = Self { storage_key_info: key_info.to_owned(), secret_key };
462 key.check_zero_message()?;
463
464 Ok(key)
465 }
466
467 pub fn to_base58(&self) -> String {
476 const DISPLAY_CHUNK_SIZE: usize = 4;
477
478 let mut bytes = Box::new([0u8; Self::DECODED_BASE58_KEY_LEN]);
479
480 bytes[0..2].copy_from_slice(Self::PREFIX.as_slice());
482 bytes[2..34].copy_from_slice(self.secret_key.as_slice());
483
484 bytes[34] = Self::parity_byte(self.secret_key.as_slice());
488
489 let base_58 =
492 bs58::encode(bytes.as_slice()).with_alphabet(bs58::Alphabet::BITCOIN).into_string();
493
494 bytes.zeroize();
495
496 let ret = base_58
498 .chars()
499 .collect::<Vec<char>>()
500 .chunks(DISPLAY_CHUNK_SIZE)
501 .map(|c| c.iter().collect::<String>())
502 .collect::<Vec<_>>()
503 .join(" ");
504
505 ret
506 }
507
508 pub fn encrypt(
529 &self,
530 plaintext: Vec<u8>,
531 secret_name: &SecretName,
532 ) -> AesHmacSha2EncryptedData {
533 let key = AesHmacSha2Key::from_secret_storage_key(&self.secret_key, secret_name.as_str());
534
535 let (ciphertext, iv) = key.encrypt(plaintext);
536 let mac = key.create_mac_tag(&ciphertext).into_bytes();
537 let ciphertext = Base64::new(ciphertext);
538
539 AesHmacSha2EncryptedData { iv, ciphertext, mac }
540 }
541
542 pub fn decrypt(
545 &self,
546 data: &AesHmacSha2EncryptedData,
547 secret_name: &SecretName,
548 ) -> Result<Vec<u8>, MacError> {
549 let key = AesHmacSha2Key::from_secret_storage_key(&self.secret_key, secret_name.as_str());
550 let ciphertext = data.ciphertext.to_owned().into_inner();
551
552 key.verify_mac(&ciphertext, &data.mac)?;
553
554 let plaintext = key.decrypt(ciphertext, &data.iv);
555
556 Ok(plaintext)
557 }
558
559 pub fn event_content(&self) -> &SecretStorageKeyEventContent {
567 &self.storage_key_info
568 }
569
570 pub fn key_id(&self) -> &str {
572 &self.storage_key_info.key_id
573 }
574
575 pub fn event_type(&self) -> GlobalAccountDataEventType {
584 self.event_content().event_type()
585 }
586}
587
588impl Default for SecretStorageKey {
589 fn default() -> Self {
590 Self::new()
591 }
592}
593
594#[cfg(test)]
595mod test {
596 use assert_matches::assert_matches;
597 use assert_matches2::assert_let;
598 use ruma::events::EventContentFromType;
599 use serde_json::{json, value::to_raw_value};
600
601 use super::*;
602
603 const SECRET_STORAGE_KEY: &[u8; 32] = &[0u8; 32];
604
605 #[test]
606 fn encrypting() {
607 let secret = "It's a secret to everybody";
608 let secret_name = SecretName::from("secret_message");
609
610 let key = SecretStorageKey::from_bytes(
611 "key_id".to_owned(),
612 Box::new(SECRET_STORAGE_KEY.to_owned()),
613 );
614
615 let encrypted = key.encrypt(secret.as_bytes().to_vec(), &secret_name);
616 let decrypted = key
617 .decrypt(&encrypted, &secret_name)
618 .expect("We should be able to decrypt the message we just encrypted");
619
620 assert_eq!(
621 secret.as_bytes(),
622 decrypted,
623 "Encryption roundtrip should result in the same plaintext"
624 );
625 }
626
627 #[test]
628 fn from_passphrase_roundtrip() {
629 let passphrase = "It's a secret to everybody";
630 let secret = "Foobar";
631 let secret_name = SecretName::from("secret_message");
632
633 let key = SecretStorageKey::new_from_passphrase("It's a secret to everybody");
634
635 let encrypted = key.encrypt(secret.as_bytes().to_vec(), &secret_name);
636 let content = to_raw_value(key.event_content())
637 .expect("We should be able to serialize the secret storage key event content");
638
639 let content =
640 SecretStorageKeyEventContent::from_parts(&key.event_type().to_string(), &content)
641 .expect(
642 "We should be able to parse our, just serialized, secret storage key event content",
643 );
644
645 let key = SecretStorageKey::from_account_data(passphrase, content)
646 .expect("We should be able to restore our secret storage key");
647
648 let decrypted = key.decrypt(&encrypted, &secret_name).expect(
649 "We should be able to decrypt the message using the restored secret storage key",
650 );
651
652 assert_eq!(
653 secret.as_bytes(),
654 decrypted,
655 "The encryption roundtrip should produce the same plaintext"
656 );
657 }
658
659 #[test]
660 fn from_base58_roundtrip() {
661 let secret = "Foobar";
662 let secret_name = SecretName::from("secret_message");
663
664 let key = SecretStorageKey::new();
665
666 let encrypted = key.encrypt(secret.as_bytes().to_vec(), &secret_name);
667 let content = to_raw_value(key.event_content())
668 .expect("We should be able to serialize the secret storage key event content");
669
670 let content =
671 SecretStorageKeyEventContent::from_parts(&key.event_type().to_string(), &content)
672 .expect(
673 "We should be able to parse our, just serialized, secret storage key event content",
674 );
675
676 let base58_key = key.to_base58();
677
678 let key = SecretStorageKey::from_account_data(&base58_key, content)
679 .expect("We should be able to restore our secret storage key");
680
681 let decrypted = key.decrypt(&encrypted, &secret_name).expect(
682 "We should be able to decrypt the message using the restored secret storage key",
683 );
684
685 assert_eq!(
686 secret.as_bytes(),
687 decrypted,
688 "The encryption roundtrip should produce the same plaintext"
689 );
690 }
691
692 #[test]
693 fn from_account_data_and_passphrase() {
694 let json = to_raw_value(&json!({
695 "algorithm":"m.secret_storage.v1.aes-hmac-sha2",
696 "iv":"gH2iNpiETFhApvW6/FFEJQ",
697 "mac":"9Lw12m5SKDipNghdQXKjgpfdj1/K7HFI2brO+UWAGoM",
698 "passphrase":{
699 "algorithm":"m.pbkdf2",
700 "salt":"IuLnH7S85YtZmkkBJKwNUKxWF42g9O1H",
701 "iterations":10
702 }
703 }))
704 .unwrap();
705
706 let content = SecretStorageKeyEventContent::from_parts(
707 "m.secret_storage.key.DZkbKc0RtKSq0z8V61w6KBmJCK6OCiIu",
708 &json,
709 )
710 .expect("We should be able to deserialize our static secret storage key");
711
712 SecretStorageKey::from_account_data("It's a secret to everybody", content)
713 .expect("We should be able to restore the secret storage key");
714 }
715
716 #[test]
717 fn from_account_data_and_base58() {
718 let base58_key = "EsTj 3yST y93F SLpB jJsz eAXc 2XzA ygD3 w69H fGaN TKBj jXEd";
719 let key_id = "bmur2d9ypPUH1msSwCxQOJkuKRmJI55e";
720
721 let json = to_raw_value(&json!({
722 "algorithm": "m.secret_storage.v1.aes-hmac-sha2",
723 "iv": "xv5b6/p3ExEw++wTyfSHEg==",
724 "mac": "ujBBbXahnTAMkmPUX2/0+VTfUh63pGyVRuBcDMgmJC8="
725 }))
726 .unwrap();
727
728 let content = SecretStorageKeyEventContent::from_parts(
729 &format!("m.secret_storage.key.{key_id}"),
730 &json,
731 )
732 .expect("We should be able to deserialize our static secret storage key");
733
734 let key = SecretStorageKey::from_account_data(base58_key, content)
735 .expect("We should be able to restore the secret storage key");
736
737 assert_eq!(key_id, key.key_id(), "The key should correctly remember the key ID");
738 }
739
740 #[test]
741 fn invalid_key() {
742 let key = SecretStorageKey::new_from_passphrase("It's a secret to everybody");
743
744 let content = to_raw_value(key.event_content())
745 .expect("We should be able to serialize the secret storage key event content");
746
747 let content =
748 SecretStorageKeyEventContent::from_parts(&key.event_type().to_string(), &content)
749 .expect(
750 "We should be able to parse our, just serialized, secret storage key event content",
751 );
752
753 assert_matches!(
754 SecretStorageKey::from_account_data("It's a secret to nobody", content.to_owned()),
755 Err(DecodeError::Mac(_)),
756 "Using the wrong passphrase should throw a MAC error"
757 );
758
759 let key = SecretStorageKey::new();
760 let base58_key = key.to_base58();
761
762 assert_matches!(
763 SecretStorageKey::from_account_data(&base58_key, content),
764 Err(DecodeError::Mac(_)),
765 "Using the wrong base58 key should throw a MAC error"
766 );
767 }
768
769 #[test]
773 fn accepts_any_passphrase_if_mac_and_iv_are_missing() {
774 let mut content = SecretStorageKeyEventContent::new(
775 "my_new_key_id".to_owned(),
776 SecretStorageEncryptionAlgorithm::V1AesHmacSha2(
777 SecretStorageV1AesHmacSha2Properties::new(None, None),
778 ),
779 );
780 content.passphrase =
781 Some(PassPhrase::new("salty goodness".to_owned(), UInt::new_saturating(100)));
782
783 SecretStorageKey::from_account_data("It's a secret to nobody", content)
784 .expect("Should accept any passphrase");
785 }
786
787 #[test]
788 fn base58_parsing() {
789 const DECODED_KEY: [u8; 32] = [
790 159, 189, 70, 187, 52, 81, 113, 198, 246, 2, 44, 154, 37, 213, 104, 27, 165, 78, 236,
791 106, 108, 73, 83, 243, 173, 192, 185, 110, 157, 145, 173, 163,
792 ];
793
794 let key = "EsT pRvZTnjck8 YrhRAtw XLS84Nr2r9S9LGAWDaExVAPBvLRK ";
795 let parsed_key = SecretStorageKey::parse_base58_key(key)
796 .expect("Whitespace in the Base58 encoded key should not matter");
797
798 assert_eq!(
799 parsed_key.as_slice(),
800 DECODED_KEY,
801 "Decoding the key should produce the correct bytes"
802 );
803
804 let key = "EsTpRvZTnjck8YrhRAtwXLS84Nr2r9S9LGAWDaExVAPBvLRk";
805 assert_matches!(
806 SecretStorageKey::parse_base58_key(key),
807 Err(DecodeError::Parity(..)),
808 "We should detect an invalid parity byte"
809 );
810
811 let key = "AATpRvZTnjck8YrhRAtwXLS84Nr2r9S9LGAWDaExVAPBvLRk";
812 assert_matches!(
813 SecretStorageKey::parse_base58_key(key),
814 Err(DecodeError::Prefix(..)),
815 "We should detect an invalid prefix"
816 );
817
818 let key = "AATpRvZTnjck8YrhRAtwXLS84Nr2r9S9";
819 assert_matches!(
820 SecretStorageKey::parse_base58_key(key),
821 Err(DecodeError::KeyLength(..)),
822 "We should detect if the key isn't of the correct length"
823 );
824
825 let key = "AATpRvZTnjck8YrhRAtwXLS84Nr0OIl";
826 assert_matches!(
827 SecretStorageKey::parse_base58_key(key),
828 Err(DecodeError::Base58(..)),
829 "We should detect if the key isn't Base58"
830 );
831 }
832
833 #[test]
834 fn encrypted_data_decoding() {
835 let json = json!({
836 "iv": "bdfCwu+ECYgZ/jWTkGrQ/A==",
837 "ciphertext": "lCRSSA1lChONEXj/8RyogsgAa8ouQwYDnLr4XBCheRikrZykLRzPCx3doCE=",
838 "mac": "NXeV1dZaOe2JLvQ6Hh6tFto7AgFFdaQnY0l9pruwdtE="
839 });
840
841 let content: SecretEncryptedData = serde_json::from_value(json)
842 .expect("We should be able to deserialize our static JSON content");
843
844 let encrypted_data: AesHmacSha2EncryptedData = content.try_into()
845 .expect("We should be able to convert a valid SecretEncryptedData to a AesHmacSha2EncryptedData struct");
846
847 assert_eq!(
848 encrypted_data.mac,
849 [
850 53, 119, 149, 213, 214, 90, 57, 237, 137, 46, 244, 58, 30, 30, 173, 22, 218, 59, 2,
851 1, 69, 117, 164, 39, 99, 73, 125, 166, 187, 176, 118, 209
852 ]
853 );
854 assert_eq!(
855 encrypted_data.iv,
856 [109, 215, 194, 194, 239, 132, 9, 136, 25, 254, 53, 147, 144, 106, 208, 252]
857 );
858
859 let secret_encrypted_data: SecretEncryptedData = encrypted_data.to_owned().into();
860
861 assert_let!(
862 SecretEncryptedData::AesHmacSha2EncryptedData { iv, ciphertext, mac } =
863 secret_encrypted_data
864 );
865 assert_eq!(mac.as_bytes(), encrypted_data.mac.as_slice());
866 assert_eq!(iv.as_bytes(), encrypted_data.iv.as_slice());
867 assert_eq!(ciphertext, encrypted_data.ciphertext);
868
869 let invalid_mac_json = json!({
870 "iv": "bdfCwu+ECYgZ/jWTkGrQ/A==",
871 "ciphertext": "lCRSSA1lChONEXj/8RyogsgAa8ouQwYDnLr4XBCheRikrZykLRzPCx3doCE=",
872 "mac": "NXeV1dZaOe2JLvQ6Hh6tFtgFFdaQnY0l9pruwdtE"
873 });
874
875 let content: SecretEncryptedData = serde_json::from_value(invalid_mac_json)
876 .expect("We should be able to deserialize our static JSON content");
877
878 let encrypted_data: Result<AesHmacSha2EncryptedData, _> = content.try_into();
879 encrypted_data.expect_err(
880 "We should be able to detect if a SecretEncryptedData content has an invalid MAC",
881 );
882
883 let invalid_iv_json = json!({
884 "iv": "bdfCwu+gZ/jWTkGrQ/A",
885 "ciphertext": "lCRSSA1lChONEXj/8RyogsgAa8ouQwYDnLr4XBCheRikrZykLRzPCx3doCE=",
886 "mac": "NXeV1dZaOe2JLvQ6Hh6tFto7AgFFdaQnY0l9pruwdtE="
887 });
888
889 let content: SecretEncryptedData = serde_json::from_value(invalid_iv_json)
890 .expect("We should be able to deserialize our static JSON content");
891
892 let encrypted_data: Result<AesHmacSha2EncryptedData, _> = content.try_into();
893 encrypted_data.expect_err(
894 "We should be able to detect if a SecretEncryptedData content has an invalid IV",
895 );
896 }
897
898 #[test]
899 fn invalid_key_info() {
900 let base58_key = "EsTj 3yST y93F SLpB jJsz eAXc 2XzA ygD3 w69H fGaN TKBj jXEd";
901
902 let content = SecretStorageKeyEventContent::new(
903 "bmur2d9ypPUH1msSwCxQOJkuKRmJI55e".to_owned(),
904 SecretStorageEncryptionAlgorithm::V1AesHmacSha2(
905 SecretStorageV1AesHmacSha2Properties::new(
906 Some(Base64::new(vec![0u8; 14])),
907 Some(Base64::new(vec![0u8; 32])),
908 ),
909 ),
910 );
911
912 assert_matches!(
913 SecretStorageKey::from_account_data(base58_key, content),
914 Err(DecodeError::IvLength(..)),
915 "We should correctly detect an invalid IV"
916 );
917
918 let content = SecretStorageKeyEventContent::new(
919 "bmur2d9ypPUH1msSwCxQOJkuKRmJI55e".to_owned(),
920 SecretStorageEncryptionAlgorithm::V1AesHmacSha2(
921 SecretStorageV1AesHmacSha2Properties::new(
922 Some(Base64::new(vec![0u8; 16])),
923 Some(Base64::new(vec![0u8; 10])),
924 ),
925 ),
926 );
927
928 assert_matches!(
929 SecretStorageKey::from_account_data(base58_key, content),
930 Err(DecodeError::MacLength(..)),
931 "We should correctly detect an invalid MAC"
932 );
933
934 let json = to_raw_value(&json!({
935 "algorithm": "m.secret_storage.custom",
936 "iv": "xv5b6/p3ExEw++wTyfSHEg==",
937 "mac": "ujBBbXahnTAMkmPUX2/0+VTfUh63pGyVRuBcDMgmJC8="
938 }))
939 .unwrap();
940
941 let content = SecretStorageKeyEventContent::from_parts(
942 "m.secret_storage.key.bmur2d9ypPUH1msSwCxQOJkuKRmJI55e",
943 &json,
944 )
945 .expect("We should be able to deserialize our static secret storage key");
946
947 assert_matches!(
948 SecretStorageKey::from_account_data(base58_key, content),
949 Err(DecodeError::UnsupportedAlgorithm(..)),
950 "We should correctly detect a unsupported algorithm"
951 );
952 }
953}