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