use crate::modules::pxconstants::*;
use crate::px_debug;
use aes::cipher::{block_padding::Pkcs7, BlockModeDecrypt, KeyIvInit};
use hmac::{digest::KeyInit, Hmac, Mac};
use pbkdf2::pbkdf2_hmac_array;
use sha2::{Digest, Sha256};
type HmacSha256 = Hmac<Sha256>;
type Aes128CbcDec = cbc::Decryptor<aes::Aes256>;
pub fn is_hmac_valid(timestamp: &str, hmac: &str, cookie_secret: &str) -> bool {
let encoded = create_hmac(timestamp, cookie_secret);
match encoded {
Some(e) => e.to_lowercase() == hmac.to_lowercase(),
None => false,
}
}
pub fn sha256_hex(input: &str) -> Option<String> {
let mut hasher = Sha256::new();
hasher.update(input.as_bytes());
Some(hex::encode(hasher.finalize()))
}
pub fn create_hmac(input: &str, cookie_secret: &str) -> Option<String> {
let content = input.as_bytes();
let key = cookie_secret.as_bytes();
let mut mac = HmacSha256::new_from_slice(key).ok()?;
mac.update(content);
let result = mac.finalize();
let s = result.into_bytes();
Some(hex::encode(s))
}
pub fn get_cookie_hmac(
cookie_json: &serde_json::Value,
action_type: &str,
cookie_secret: &str,
) -> Option<String> {
let data = format!(
"{}{}{}{}",
cookie_json["t"],
cookie_json["u"].as_str().unwrap_or_default(),
cookie_json["v"].as_str().unwrap_or_default(),
action_type
);
create_hmac(&data, cookie_secret)
}
pub fn decrypt_cookie_v3<'a>(
cookie_secret: &String,
salt: Vec<u8>,
iterations: usize,
payload: &'a mut [u8],
) -> Option<&'a [u8]> {
let cookie_key = cookie_secret.as_bytes();
const LEN: usize = KEY_LEN + IV_LEN;
let decoded_key = pbkdf2_hmac_array::<Sha256, LEN>(cookie_key, &salt, iterations as u32);
let key: &[u8; KEY_LEN] = decoded_key[0..KEY_LEN].try_into().ok()?;
let iv: &[u8; IV_LEN] = decoded_key[KEY_LEN..].try_into().ok()?;
match Aes128CbcDec::new(key.into(), iv.into()).decrypt_padded::<Pkcs7>(payload) {
Ok(d) => Some(d),
Err(e) => {
px_debug!("Cookie decryption failed: {}", e);
None
}
}
}