use crate::ncch::NCCH;
use ctr::Ctr128BE;
use ctr::cipher::KeyIvInit;
const fn keyscrambler(key_x: u128, key_y: u128) -> u128 {
const CONSTANT: u128 = 0x1FF9_E9AA_C5FE_0408_0245_91DC_5D52_768A_u128;
((key_x.rotate_left(2) ^ key_y).wrapping_add(CONSTANT)).rotate_left(87)
}
pub type AESCtr = Ctr128BE<aes::Aes128>;
const INFO_KEYX: u128 = 0xB98E_95CE_CA3E_4D17_1F76_A94D_E934_C053_u128;
fn compute_exefs_iv(partition_id: u64, offset: u32) -> u128 {
((u128::from(partition_id) << 64) | (2u128 << 56)) + u128::from(offset)
}
impl NCCH {
#[must_use]
#[allow(clippy::missing_panics_doc)]
pub fn exefs_ctr(&self) -> AESCtr {
let key_y = u128::from_be_bytes(self.signature[0..0x10].try_into().unwrap());
let key = keyscrambler(INFO_KEYX, key_y);
let iv = compute_exefs_iv(self.partition_title_id, 0);
AESCtr::new((&key.to_be_bytes()).into(), (&iv.to_be_bytes()).into())
}
}
#[cfg(test)]
mod tests {
use crate::crypto::keyscrambler;
#[test]
fn test() {
assert_eq!(
0xEE2EA93B480FFCF4D562FF02040122C8u128,
keyscrambler(
0x00000000000000000000000000000001u128,
0x00000000000000000000000000000002u128
)
);
}
}