use aes::cipher::block_padding::Pkcs7;
use aes::cipher::{BlockDecryptMut, KeyInit, KeyIvInit};
use aes::cipher::generic_array::GenericArray;
use cbc::Decryptor as CbcDecryptor;
use ecb::Decryptor as EcbDecryptor;
use crate::error::SteamError;
const BLOCK_SIZE: usize = 16;
const KEY_SIZE: usize = 32;
pub fn symmetric_decrypt(input: &[u8], key: &[u8]) -> Result<Vec<u8>, SteamError> {
CryptoHelper::symmetric_decrypt(input, key)
}
#[derive(Debug)]
pub struct CryptoHelper;
impl CryptoHelper {
pub fn symmetric_decrypt(input: &[u8], key: &[u8]) -> Result<Vec<u8>, SteamError> {
if key.len() != KEY_SIZE {
crate::util::debug_log::DebugLog::assert(
false,
"CryptoHelper",
"SymmetricDecrypt used with non 32 byte key!",
);
return Err(SteamError::InvalidArgument(format!(
"SymmetricDecrypt used with non {KEY_SIZE} byte key (was {} bytes)!",
key.len()
)));
}
if input.len() < BLOCK_SIZE {
return Err(SteamError::Crypto(format!(
"SymmetricDecrypt input is too short to contain the IV (was {} bytes).",
input.len()
)));
}
let mut iv = [0u8; BLOCK_SIZE];
{
let mut decryptor = EcbDecryptor::<aes::Aes256>::new_from_slice(key)
.map_err(|_| SteamError::Crypto("Invalid AES-256 key.".to_string()))?;
let mut block = GenericArray::clone_from_slice(&input[..BLOCK_SIZE]);
decryptor.decrypt_block_mut(&mut block);
iv.copy_from_slice(block.as_slice());
}
let ciphertext = &input[BLOCK_SIZE..];
if ciphertext.is_empty() || ciphertext.len() % BLOCK_SIZE != 0 {
return Err(SteamError::Crypto(format!(
"SymmetricDecrypt input has an invalid length (was {} bytes).",
input.len()
)));
}
let mut buffer = vec![0u8; ciphertext.len()];
buffer.copy_from_slice(ciphertext);
let decryptor = CbcDecryptor::<aes::Aes256>::new_from_slices(key, &iv)
.map_err(|_| SteamError::Crypto("Invalid AES-256 key or IV.".to_string()))?;
let plaintext = decryptor
.decrypt_padded_mut::<Pkcs7>(&mut buffer)
.map_err(|_| SteamError::Crypto("Failed to decrypt the payload.".to_string()))?;
Ok(plaintext.to_vec())
}
}