diff --git a/rust/protocol/src/crypto.rs b/rust/protocol/src/crypto.rs index fd79f0bccf..b19ad62a8c 100644 --- a/rust/protocol/src/crypto.rs +++ b/rust/protocol/src/crypto.rs @@ -1,156 +1,244 @@ // -// Copyright 2020 Signal Messenger, LLC. +// Copyright 2020-2022 Signal Messenger, LLC. // SPDX-License-Identifier: AGPL-3.0-only // -use std::convert::TryInto; -use std::result::Result; +//! Internal convenience wrappers for symmetric cryptographic primitives. use aes::cipher::{NewCipher, StreamCipher}; use aes::{Aes256, Aes256Ctr}; +use arrayref::array_ref; use block_modes::block_padding::Pkcs7; use block_modes::{BlockMode, Cbc}; +use displaydoc::Display; use hmac::{Hmac, Mac, NewMac}; use sha2::Sha256; use subtle::ConstantTimeEq; +use thiserror::Error; -#[derive(Debug)] -pub(crate) enum EncryptionError { - /// The key or IV is the wrong length. - BadKeyOrIv, -} +/// bad ciphertext: {0} +/// +/// Either the input is malformed, or the MAC doesn't match on decryption. +/// +/// These cases should not be distinguished; message corruption can cause either problem. +#[derive(Debug, Display, Error)] +#[ignore_extra_doc_attributes] +pub struct DecryptionError(pub &'static str); -#[derive(Debug)] -pub(crate) enum DecryptionError { - /// The key or IV is the wrong length. - BadKeyOrIv, - /// Either the input is malformed, or the MAC doesn't match on decryption. - /// - /// These cases should not be distinguished; message corruption can cause either problem. - BadCiphertext(&'static str), -} +// TODO: Could be nice to have a type-safe library for manipulating units of bytes safely. +const BITS_PER_BYTE: usize = std::mem::size_of::() * 8; -fn aes_256_ctr_encrypt(ptext: &[u8], key: &[u8]) -> Result, EncryptionError> { - let key: [u8; 32] = key.try_into().map_err(|_| EncryptionError::BadKeyOrIv)?; +/// The length of the key we use for AES encryption in this crate. +pub const AES_256_KEY_SIZE: usize = 256 / BITS_PER_BYTE; - let zero_nonce = [0u8; 16]; - let mut cipher = Aes256Ctr::new(key[..].into(), zero_nonce[..].into()); +/// The size of the generated nonce we use for AES encryption in this crate. +pub const AES_NONCE_SIZE: usize = 128 / BITS_PER_BYTE; - let mut ctext = ptext.to_vec(); - cipher.apply_keystream(&mut ctext); - Ok(ctext) -} +/// Use AES-256 in CTR mode. +pub mod ctr { + use super::*; -fn aes_256_ctr_decrypt(ctext: &[u8], key: &[u8]) -> Result, DecryptionError> { - aes_256_ctr_encrypt(ctext, key).map_err(|e| match e { - EncryptionError::BadKeyOrIv => DecryptionError::BadKeyOrIv, - }) -} + pub fn aes_256_ctr_encrypt(ptext: &[u8], key: &[u8; AES_256_KEY_SIZE]) -> Vec { + let zero_nonce = [0u8; AES_NONCE_SIZE]; + let mut cipher = Aes256Ctr::new(key[..].into(), zero_nonce[..].into()); -pub(crate) fn aes_256_cbc_encrypt( - ptext: &[u8], - key: &[u8], - iv: &[u8], -) -> Result, EncryptionError> { - match Cbc::::new_from_slices(key, iv) { - Ok(mode) => Ok(mode.encrypt_vec(ptext)), - Err(block_modes::InvalidKeyIvLength) => Err(EncryptionError::BadKeyOrIv), + let mut ctext = ptext.to_vec(); + cipher.apply_keystream(&mut ctext); + ctext } -} -pub(crate) fn aes_256_cbc_decrypt( - ctext: &[u8], - key: &[u8], - iv: &[u8], -) -> Result, DecryptionError> { - if ctext.is_empty() || ctext.len() % 16 != 0 { - return Err(DecryptionError::BadCiphertext( - "ciphertext length must be a non-zero multiple of 16", - )); + pub fn aes_256_ctr_decrypt(ctext: &[u8], key: &[u8; AES_256_KEY_SIZE]) -> Vec { + aes_256_ctr_encrypt(ctext, key) } - let mode = - Cbc::::new_from_slices(key, iv).map_err(|_| DecryptionError::BadKeyOrIv)?; - mode.decrypt_vec(ctext) - .map_err(|_| DecryptionError::BadCiphertext("failed to decrypt")) -} + /// Length in bytes of the [`Hmac`] key used for [`aes_256_ctr_hmac_encrypt`] and + /// [`aes_256_ctr_hmac_decrypt`]. + pub const MAC_KEY_LENGTH: usize = 80 / BITS_PER_BYTE; -pub(crate) fn hmac_sha256(key: &[u8], input: &[u8]) -> [u8; 32] { - let mut hmac = - Hmac::::new_from_slice(key).expect("HMAC-SHA256 should accept any size key"); - hmac.update(input); - hmac.finalize().into_bytes().into() -} - -pub(crate) fn aes256_ctr_hmacsha256_encrypt( - msg: &[u8], - cipher_key: &[u8], - mac_key: &[u8], -) -> Result, EncryptionError> { - let mut ctext = aes_256_ctr_encrypt(msg, cipher_key)?; - let mac = hmac_sha256(mac_key, &ctext); - ctext.extend_from_slice(&mac[..10]); - Ok(ctext) -} + /// Encrypt plaintext `msg` with AES-256 and embed a computed HMAC into the returned bytes. + /// + /// *Implementation note: within the body of this method, only the first [`MAC_KEY_LENGTH`] + /// bytes of the computed MAC are used.* + pub fn aes_256_ctr_hmac_encrypt( + msg: &[u8], + cipher_key: &[u8; AES_256_KEY_SIZE], + mac_key: &[u8; MAC_KEY_LENGTH], + ) -> Vec { + let mut ctext = aes_256_ctr_encrypt(msg, cipher_key); + let mac = hmac_sha256(mac_key, &ctext); + ctext.extend_from_slice(&mac[..MAC_KEY_LENGTH]); + ctext + } -pub(crate) fn aes256_ctr_hmacsha256_decrypt( - ctext: &[u8], - cipher_key: &[u8], - mac_key: &[u8], -) -> Result, DecryptionError> { - if ctext.len() < 10 { - return Err(DecryptionError::BadCiphertext("truncated ciphertext")); + /// Validate the HMAC `mac_key` against the ciphertext `ctext`, then decrypt `ctext` using + /// AES-256 with `cipher_key` and [`aes_256_ctr_decrypt`]. + /// + /// *Implementation note: the last [`MAC_KEY_LENGTH`] bytes of the `ctext` slice represent the + /// truncated HMAC of the rest of the message, as generated by [`aes_256_ctr_hmac_encrypt`].* + pub fn aes_256_ctr_hmac_decrypt( + ctext: &[u8], + cipher_key: &[u8; AES_256_KEY_SIZE], + mac_key: &[u8; MAC_KEY_LENGTH], + ) -> Result, DecryptionError> { + if ctext.len() < MAC_KEY_LENGTH { + return Err(DecryptionError("truncated ciphertext")); + } + let (ctext, ctext_mac) = ctext.split_at(ctext.len() - MAC_KEY_LENGTH); + let ctext_mac = array_ref![ctext_mac, 0, MAC_KEY_LENGTH]; + let our_mac = hmac_sha256(mac_key, ctext); + let our_mac = array_ref![&our_mac, 0, MAC_KEY_LENGTH]; + let same: bool = our_mac.ct_eq(ctext_mac).into(); + if !same { + return Err(DecryptionError("MAC verification failed")); + } + Ok(aes_256_ctr_decrypt(ctext, cipher_key)) } - let ptext_len = ctext.len() - 10; - let our_mac = hmac_sha256(mac_key, &ctext[..ptext_len]); - let same: bool = our_mac[..10].ct_eq(&ctext[ptext_len..]).into(); - if !same { - return Err(DecryptionError::BadCiphertext("MAC verification failed")); + + #[cfg(test)] + mod test { + use super::*; + + use std::convert::TryInto; + + use rand::rngs::OsRng; + use rand::Rng; + + #[test] + fn static_test() { + let key: [u8; AES_256_KEY_SIZE] = + hex::decode("603DEB1015CA71BE2B73AEF0857D77811F352C073B6108D72D9810A30914DFF4") + .expect("valid hex") + .try_into() + .expect("correct array size"); + let ptext = [0u8; 35]; + + let ctext = aes_256_ctr_encrypt(&ptext, &key); + assert_eq!( + hex::encode(ctext), + "e568f68194cf76d6174d4cc04310a85491151e5d0b7a1f1bc0d7acd0ae3e51e4170e23" + ); + } + + #[test] + fn no_hmac_test() { + let key: [u8; AES_256_KEY_SIZE] = (&mut OsRng).gen(); + let ptext: [u8; 30] = (&mut OsRng).gen(); + + let ctext = aes_256_ctr_encrypt(&ptext, &key); + let decrypted = aes_256_ctr_decrypt(&ctext, &key); + assert_eq!(ptext.as_ref(), &decrypted); + } + + #[test] + fn hmac_test() { + let key: [u8; AES_256_KEY_SIZE] = (&mut OsRng).gen(); + let mac_key: [u8; MAC_KEY_LENGTH] = (&mut OsRng).gen(); + let ptext: [u8; 30] = (&mut OsRng).gen(); + + let ctext = aes_256_ctr_hmac_encrypt(&ptext, &key, &mac_key); + let decrypted = + aes_256_ctr_hmac_decrypt(&ctext, &key, &mac_key).expect("valid decryption"); + assert_eq!(ptext.as_ref(), &decrypted); + } } - aes_256_ctr_decrypt(&ctext[..ptext_len], cipher_key) } -#[cfg(test)] -mod test { +/// Use AES-256 in CBC mode. +pub mod cbc { use super::*; - #[test] - fn aes_cbc_test() { - let key = hex::decode("4e22eb16d964779994222e82192ce9f747da72dc4abe49dfdeeb71d0ffe3796e") - .expect("valid hex"); - let iv = hex::decode("6f8a557ddc0a140c878063a6d5f31d3d").expect("valid hex"); - - let ptext = hex::decode("30736294a124482a4159").expect("valid hex"); - - let ctext = aes_256_cbc_encrypt(&ptext, &key, &iv).expect("valid key and IV"); - assert_eq!( - hex::encode(ctext.clone()), - "dd3f573ab4508b9ed0e45e0baf5608f3" - ); - - let recovered = aes_256_cbc_decrypt(&ctext, &key, &iv).expect("valid"); - assert_eq!(hex::encode(ptext), hex::encode(recovered.clone())); - - // padding is invalid: - assert!(aes_256_cbc_decrypt(&recovered, &key, &iv).is_err()); - assert!(aes_256_cbc_decrypt(&ctext, &key, &ctext).is_err()); + pub fn aes_256_cbc_encrypt( + ptext: &[u8], + key: &[u8; AES_256_KEY_SIZE], + iv: &[u8; AES_NONCE_SIZE], + ) -> Vec { + let mode = + Cbc::::new_from_slices(key, iv).expect("key and iv were fixed length"); + mode.encrypt_vec(ptext) + } - // bitflip the IV to cause a change in the recovered text - let bad_iv = hex::decode("ef8a557ddc0a140c878063a6d5f31d3d").expect("valid hex"); - let recovered = aes_256_cbc_decrypt(&ctext, &key, &bad_iv).expect("still valid"); - assert_eq!(hex::encode(recovered), "b0736294a124482a4159"); + pub fn aes_256_cbc_decrypt( + ctext: &[u8], + key: &[u8; AES_256_KEY_SIZE], + iv: &[u8; AES_NONCE_SIZE], + ) -> Result, DecryptionError> { + if ctext.is_empty() || ctext.len() % 16 != 0 { + return Err(DecryptionError( + "ciphertext length must be a non-zero multiple of 16", + )); + } + + let mode = Cbc::::new_from_slices(key.as_ref(), iv.as_ref()) + .expect("key and iv were fixed length"); + mode.decrypt_vec(ctext) + .map_err(|_| DecryptionError("failed to decrypt")) } - #[test] - fn aes_ctr_test() { - let key = hex::decode("603DEB1015CA71BE2B73AEF0857D77811F352C073B6108D72D9810A30914DFF4") - .expect("valid hex"); - let ptext = [0u8; 35]; - - let ctext = aes_256_ctr_encrypt(&ptext, &key).expect("valid key"); - assert_eq!( - hex::encode(ctext), - "e568f68194cf76d6174d4cc04310a85491151e5d0b7a1f1bc0d7acd0ae3e51e4170e23" - ); + #[cfg(test)] + mod test { + use super::*; + + use std::convert::TryInto; + + use rand::rngs::OsRng; + use rand::Rng; + + #[test] + fn static_test() { + let key: [u8; AES_256_KEY_SIZE] = + hex::decode("4e22eb16d964779994222e82192ce9f747da72dc4abe49dfdeeb71d0ffe3796e") + .expect("valid hex") + .try_into() + .expect("correct array size"); + let iv: [u8; AES_NONCE_SIZE] = hex::decode("6f8a557ddc0a140c878063a6d5f31d3d") + .expect("valid hex") + .try_into() + .expect("correct array size"); + + let ptext = hex::decode("30736294a124482a4159").expect("valid hex"); + + let ctext = cbc::aes_256_cbc_encrypt(&ptext, &key, &iv); + assert_eq!( + hex::encode(ctext.clone()), + "dd3f573ab4508b9ed0e45e0baf5608f3" + ); + + let recovered = cbc::aes_256_cbc_decrypt(&ctext, &key, &iv).expect("valid"); + assert_eq!(hex::encode(ptext), hex::encode(recovered.clone())); + + // padding is invalid: + assert!(cbc::aes_256_cbc_decrypt(&recovered, &key, &iv).is_err()); + assert!( + cbc::aes_256_cbc_decrypt(&ctext, &key, array_ref![&ctext, 0, AES_NONCE_SIZE]) + .is_err() + ); + + // bitflip the IV to cause a change in the recovered text + let bad_iv: [u8; AES_NONCE_SIZE] = hex::decode("ef8a557ddc0a140c878063a6d5f31d3d") + .expect("valid hex") + .try_into() + .expect("correct array size"); + let recovered = cbc::aes_256_cbc_decrypt(&ctext, &key, &bad_iv).expect("still valid"); + assert_eq!(hex::encode(recovered), "b0736294a124482a4159"); + } + + #[test] + fn random_test() { + let key: [u8; AES_256_KEY_SIZE] = (&mut OsRng).gen(); + let iv: [u8; AES_NONCE_SIZE] = (&mut OsRng).gen(); + let ptext: [u8; 30] = (&mut OsRng).gen(); + + let ctext = aes_256_cbc_encrypt(&ptext, &key, &iv); + let decrypted = aes_256_cbc_decrypt(&ctext, &key, &iv).expect("valid decryption"); + assert_eq!(ptext.as_ref(), &decrypted); + } } } + +/// Calculate the [`Hmac`]-[`Sha256`] code over `input` using `key`. +pub fn hmac_sha256(key: &[u8], input: &[u8]) -> [u8; 256 / BITS_PER_BYTE] { + let mut hmac = + Hmac::::new_from_slice(key).expect("HMAC-SHA256 should accept any size key"); + hmac.update(input); + hmac.finalize().into_bytes().into() +} diff --git a/rust/protocol/src/group_cipher.rs b/rust/protocol/src/group_cipher.rs index baa3a20776..56e98b34fa 100644 --- a/rust/protocol/src/group_cipher.rs +++ b/rust/protocol/src/group_cipher.rs @@ -1,5 +1,5 @@ // -// Copyright 2020-2021 Signal Messenger, LLC. +// Copyright 2020-2022 Signal Messenger, LLC. // SPDX-License-Identifier: AGPL-3.0-only // @@ -14,7 +14,7 @@ use crate::protocol::SENDERKEY_MESSAGE_CURRENT_VERSION; use crate::sender_keys::{SenderKeyState, SenderMessageKey}; use rand::{CryptoRng, Rng}; -use std::convert::TryFrom; +use std::convert::{TryFrom, TryInto}; use uuid::Uuid; pub async fn group_encrypt( @@ -40,15 +40,22 @@ pub async fn group_encrypt( let message_keys = sender_chain_key.sender_message_key(); - let ciphertext = - crypto::aes_256_cbc_encrypt(plaintext, message_keys.cipher_key(), message_keys.iv()) - .map_err(|_| { - log::error!( - "outgoing sender key state corrupt for distribution ID {}", - distribution_id, - ); - SignalProtocolError::InvalidSenderKeySession { distribution_id } - })?; + let cipher_key: [u8; crypto::AES_256_KEY_SIZE] = + message_keys.cipher_key().try_into().map_err(|_| { + log::error!( + "outgoing sender key state corrupt for distribution ID {}", + distribution_id, + ); + SignalProtocolError::InvalidSenderKeySession { distribution_id } + })?; + let iv: [u8; crypto::AES_NONCE_SIZE] = message_keys.iv().try_into().map_err(|_| { + log::error!( + "outgoing sender key state corrupt for distribution ID {}", + distribution_id, + ); + SignalProtocolError::InvalidSenderKeySession { distribution_id } + })?; + let ciphertext = crypto::cbc::aes_256_cbc_encrypt(plaintext, &cipher_key, &iv); let signing_key = sender_key_state .signing_key_private() @@ -169,22 +176,25 @@ pub async fn group_decrypt( let sender_key = get_sender_key(sender_key_state, skm.iteration(), distribution_id)?; - let plaintext = match crypto::aes_256_cbc_decrypt( - skm.ciphertext(), - sender_key.cipher_key(), - sender_key.iv(), - ) { - Ok(plaintext) => plaintext, - Err(crypto::DecryptionError::BadKeyOrIv) => { + let cipher_key: [u8; crypto::AES_256_KEY_SIZE] = + sender_key.cipher_key().try_into().map_err(|_| { log::error!( - "incoming sender key state corrupt for {}, distribution ID {}, chain ID {}", - sender, + "outgoing sender key state corrupt for distribution ID {}", distribution_id, - chain_id, ); - return Err(SignalProtocolError::InvalidSenderKeySession { distribution_id }); - } - Err(crypto::DecryptionError::BadCiphertext(msg)) => { + SignalProtocolError::InvalidSenderKeySession { distribution_id } + })?; + let iv: [u8; crypto::AES_NONCE_SIZE] = sender_key.iv().try_into().map_err(|_| { + log::error!( + "outgoing sender key state corrupt for distribution ID {}", + distribution_id, + ); + SignalProtocolError::InvalidSenderKeySession { distribution_id } + })?; + + let plaintext = match crypto::cbc::aes_256_cbc_decrypt(skm.ciphertext(), &cipher_key, &iv) { + Ok(plaintext) => plaintext, + Err(crypto::DecryptionError(msg)) => { log::error!("sender key decryption failed: {}", msg); return Err(SignalProtocolError::InvalidMessage( CiphertextMessageType::SenderKey, diff --git a/rust/protocol/src/lib.rs b/rust/protocol/src/lib.rs index 0d587d7237..b1b2acde1e 100644 --- a/rust/protocol/src/lib.rs +++ b/rust/protocol/src/lib.rs @@ -1,5 +1,5 @@ // -// Copyright 2020-2021 Signal Messenger, LLC. +// Copyright 2020-2022 Signal Messenger, LLC. // SPDX-License-Identifier: AGPL-3.0-only // @@ -24,7 +24,7 @@ mod address; mod consts; -mod crypto; +pub(crate) mod crypto; mod curve; pub mod error; mod fingerprint; diff --git a/rust/protocol/src/ratchet/keys.rs b/rust/protocol/src/ratchet/keys.rs index 6c019936c6..8a2023295e 100644 --- a/rust/protocol/src/ratchet/keys.rs +++ b/rust/protocol/src/ratchet/keys.rs @@ -40,17 +40,17 @@ impl MessageKeys { } #[inline] - pub(crate) fn cipher_key(&self) -> &[u8; 32] { + pub(crate) fn cipher_key(&self) -> &[u8; crypto::AES_256_KEY_SIZE] { &self.cipher_key } #[inline] - pub(crate) fn mac_key(&self) -> &[u8; 32] { + pub(crate) fn mac_key(&self) -> &[u8; crypto::AES_256_KEY_SIZE] { &self.mac_key } #[inline] - pub(crate) fn iv(&self) -> &[u8; 16] { + pub(crate) fn iv(&self) -> &[u8; crypto::AES_NONCE_SIZE] { &self.iv } diff --git a/rust/protocol/src/sealed_sender.rs b/rust/protocol/src/sealed_sender.rs index e93b145e5b..c7c98c2ccc 100644 --- a/rust/protocol/src/sealed_sender.rs +++ b/rust/protocol/src/sealed_sender.rs @@ -707,12 +707,11 @@ mod sealed_sender_v1 { )?; // Encrypt the sender's public key with AES-256 CTR and a MAC. - let sender_static_key_ctext = crypto::aes256_ctr_hmacsha256_encrypt( + let sender_static_key_ctext = crypto::ctr::aes_256_ctr_hmac_encrypt( &sender_identity.public_key().serialize(), &sender_eph_keys.cipher_key, - &sender_eph_keys.mac_key, - ) - .expect("just generated these keys, they should be correct"); + array_ref![&sender_eph_keys.mac_key, 0, crypto::ctr::MAC_KEY_LENGTH], + ); // Generate another cipher and MAC key. let sender_static_keys = StaticKeys::calculate( @@ -723,12 +722,11 @@ mod sealed_sender_v1 { )?; let sender_message_contents = b"this is a binary message"; - let sender_message_data = crypto::aes256_ctr_hmacsha256_encrypt( + let sender_message_data = crypto::ctr::aes_256_ctr_hmac_encrypt( sender_message_contents, &sender_static_keys.cipher_key, - &sender_static_keys.mac_key, - ) - .expect("just generated these keys, they should be correct"); + array_ref![&sender_static_keys.mac_key, 0, crypto::ctr::MAC_KEY_LENGTH], + ); // The message recipient calculates the ephemeral key and the sender's public key. let recipient_eph_keys = EphemeralKeys::calculate( @@ -738,10 +736,10 @@ mod sealed_sender_v1 { )?; assert_eq!(sender_eph_keys, recipient_eph_keys); - let recipient_message_key_bytes = crypto::aes256_ctr_hmacsha256_decrypt( + let recipient_message_key_bytes = crypto::ctr::aes_256_ctr_hmac_decrypt( &sender_static_key_ctext, &recipient_eph_keys.cipher_key, - &recipient_eph_keys.mac_key, + array_ref![&recipient_eph_keys.mac_key, 0, crypto::ctr::MAC_KEY_LENGTH], ) .expect("should decrypt successfully"); let sender_public_key: PublicKey = PublicKey::try_from(&recipient_message_key_bytes[..])?; @@ -754,10 +752,14 @@ mod sealed_sender_v1 { &sender_static_key_ctext, )?; - let recipient_message_contents = crypto::aes256_ctr_hmacsha256_decrypt( + let recipient_message_contents = crypto::ctr::aes_256_ctr_hmac_decrypt( &sender_message_data, &recipient_static_keys.cipher_key, - &recipient_static_keys.mac_key, + array_ref![ + &recipient_static_keys.mac_key, + 0, + crypto::ctr::MAC_KEY_LENGTH + ], ) .expect("should decrypt successfully"); assert_eq!(recipient_message_contents, sender_message_contents); @@ -863,12 +865,11 @@ pub async fn sealed_sender_encrypt_from_usmc( Direction::Sending, )?; - let static_key_ctext = crypto::aes256_ctr_hmacsha256_encrypt( + let static_key_ctext = crypto::ctr::aes_256_ctr_hmac_encrypt( &our_identity.public_key().serialize(), &eph_keys.cipher_key, - &eph_keys.mac_key, - ) - .expect("just generated these keys, they should be correct"); + array_ref![&eph_keys.mac_key, 0, crypto::ctr::MAC_KEY_LENGTH], + ); let static_keys = sealed_sender_v1::StaticKeys::calculate( &our_identity, @@ -877,12 +878,11 @@ pub async fn sealed_sender_encrypt_from_usmc( &static_key_ctext, )?; - let message_data = crypto::aes256_ctr_hmacsha256_encrypt( + let message_data = crypto::ctr::aes_256_ctr_hmac_encrypt( usmc.serialized()?, &static_keys.cipher_key, - &static_keys.mac_key, - ) - .expect("just generated these keys, they should be correct"); + array_ref![&static_keys.mac_key, 0, crypto::ctr::MAC_KEY_LENGTH], + ); let version = SEALED_SENDER_V1_VERSION; let mut serialized = vec![version | (version << 4)]; @@ -1436,16 +1436,13 @@ pub async fn sealed_sender_decrypt_to_usmc( Direction::Receiving, )?; - let message_key_bytes = match crypto::aes256_ctr_hmacsha256_decrypt( + let message_key_bytes = match crypto::ctr::aes_256_ctr_hmac_decrypt( &encrypted_static, &eph_keys.cipher_key, - &eph_keys.mac_key, + array_ref![&eph_keys.mac_key, 0, crypto::ctr::MAC_KEY_LENGTH], ) { Ok(plaintext) => plaintext, - Err(crypto::DecryptionError::BadKeyOrIv) => { - unreachable!("just derived these keys; they should be valid"); - } - Err(crypto::DecryptionError::BadCiphertext(msg)) => { + Err(crypto::DecryptionError(msg)) => { log::error!("failed to decrypt sealed sender v1 message key: {}", msg); return Err(SignalProtocolError::InvalidSealedSenderMessage( "failed to decrypt sealed sender v1 message key".to_owned(), @@ -1462,16 +1459,13 @@ pub async fn sealed_sender_decrypt_to_usmc( &encrypted_static, )?; - let message_bytes = match crypto::aes256_ctr_hmacsha256_decrypt( + let message_bytes = match crypto::ctr::aes_256_ctr_hmac_decrypt( &encrypted_message, &static_keys.cipher_key, - &static_keys.mac_key, + array_ref![&static_keys.mac_key, 0, crypto::ctr::MAC_KEY_LENGTH], ) { Ok(plaintext) => plaintext, - Err(crypto::DecryptionError::BadKeyOrIv) => { - unreachable!("just derived these keys; they should be valid"); - } - Err(crypto::DecryptionError::BadCiphertext(msg)) => { + Err(crypto::DecryptionError(msg)) => { log::error!( "failed to decrypt sealed sender v1 message contents: {}", msg diff --git a/rust/protocol/src/session_cipher.rs b/rust/protocol/src/session_cipher.rs index 210f114a55..3ee3f7740e 100644 --- a/rust/protocol/src/session_cipher.rs +++ b/rust/protocol/src/session_cipher.rs @@ -47,11 +47,8 @@ pub async fn message_encrypt( ) })?; - let ctext = crypto::aes_256_cbc_encrypt(ptext, message_keys.cipher_key(), message_keys.iv()) - .map_err(|_| { - log::error!("session state corrupt for {}", remote_address); - SignalProtocolError::InvalidSessionStructure("invalid sender chain message keys") - })?; + let ctext = + crypto::cbc::aes_256_cbc_encrypt(ptext, message_keys.cipher_key(), message_keys.iv()); let message = if let Some(items) = session_state.unacknowledged_pre_key_message_items()? { let local_registration_id = session_state.local_registration_id(); @@ -425,7 +422,6 @@ fn decrypt_message_with_record( if let Some(current_state) = record.session_state() { let mut current_state = current_state.clone(); let result = decrypt_message_with_state( - CurrentOrPrevious::Current, &mut current_state, ciphertext, original_message_type, @@ -463,7 +459,6 @@ fn decrypt_message_with_record( let mut previous = previous?; let result = decrypt_message_with_state( - CurrentOrPrevious::Previous, &mut previous, ciphertext, original_message_type, @@ -526,23 +521,7 @@ fn decrypt_message_with_record( } } -#[derive(Clone, Copy)] -enum CurrentOrPrevious { - Current, - Previous, -} - -impl std::fmt::Display for CurrentOrPrevious { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - match self { - Self::Current => write!(f, "current"), - Self::Previous => write!(f, "previous"), - } - } -} - fn decrypt_message_with_state( - current_or_previous: CurrentOrPrevious, state: &mut SessionState, ciphertext: &SignalMessage, original_message_type: CiphertextMessageType, @@ -595,23 +574,13 @@ fn decrypt_message_with_state( )); } - let ptext = match crypto::aes_256_cbc_decrypt( + let ptext = match crypto::cbc::aes_256_cbc_decrypt( ciphertext.body(), message_keys.cipher_key(), message_keys.iv(), ) { Ok(ptext) => ptext, - Err(crypto::DecryptionError::BadKeyOrIv) => { - log::warn!( - "{} session state corrupt for {}", - current_or_previous, - remote_address, - ); - return Err(SignalProtocolError::InvalidSessionStructure( - "invalid receiver chain message keys", - )); - } - Err(crypto::DecryptionError::BadCiphertext(msg)) => { + Err(crypto::DecryptionError(msg)) => { log::warn!("failed to decrypt 1:1 message: {}", msg); return Err(SignalProtocolError::InvalidMessage( original_message_type,