use std::{borrow::Cow, ptr::NonNull};
use shared::{FromStatic, OwnedPtr};
use vtable_rs::VPtr;
use crate::{DLVector, dlkr::DLAllocator, rva};
#[vtable_rs::vtable]
pub trait DLCipherKeyVmt {
fn destructor(&mut self, flags: u32);
fn get_key(&self) -> *const u8;
fn get_key_length(&self) -> usize;
}
#[repr(C)]
pub struct DLCipherKey {
vftable: VPtr<dyn DLCipherKeyVmt, Self>,
}
impl DLCipherKey {
pub fn key(&self) -> &[u8] {
unsafe {
let ptr = (self.vftable.get_key)(self);
let len = (self.vftable.get_key_length)(self);
std::slice::from_raw_parts(ptr, len)
}
}
pub fn key_as_str(&self) -> Option<&str> {
let bytes = self.key();
std::str::from_utf8(bytes.strip_suffix(&[0]).unwrap_or(bytes)).ok()
}
}
#[repr(C)]
pub struct DLSerialCipherKey {
pub base: DLCipherKey,
key: OwnedPtr<u8>,
key_length: usize,
}
#[repr(C)]
pub struct AESEncrypter {
vftable: usize,
algorithm: OwnedPtr<DLRijndaelAlgorithm>,
unk10: u64,
}
#[repr(C)]
pub struct AESDecrypter {
base: DLDecrypter,
algorithm: OwnedPtr<DLRijndaelAlgorithm>,
}
#[repr(C)]
pub struct DLRijndaelAlgorithm {
vftable: usize,
}
#[repr(u16)]
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub enum CryptoKeyType {
Null = 0,
Cerial = 1 << 8,
}
#[repr(C)]
#[derive(Debug, Clone, Copy)]
pub struct CryptoKeyParams {
pub magic: [u8; 4],
pub version: u32,
pub key_type: CryptoKeyType,
}
impl CryptoKeyParams {
pub const MAGIC: &'static [u8; 4] = b"CKP\0";
pub fn is_valid(&self) -> bool {
&self.magic == Self::MAGIC
}
}
#[repr(u16)]
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub enum CipherMode {
Null = 0,
Cbc = 1 << 8,
Ecb = 2 << 8,
Cfb = 3 << 8,
Ofb = 4 << 8,
CtrNw = 5 << 8,
}
#[repr(u16)]
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub enum CipherType {
Null = 0,
Aes = 1 << 8,
OpenSslAES = 2 << 8,
OpenSslRsa = 3 << 8,
}
#[repr(u16)]
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub enum CipherPaddingMode {
None = 0,
Pkcs5 = 1 << 8,
}
#[repr(u16)]
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub enum KeyUsageType {
Null = 0,
Default = 1 << 8,
}
#[repr(u16)]
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub enum KeyType {
Common = 0,
Public = 1 << 8,
Private = 2 << 8,
}
#[repr(C)]
#[derive(Debug, Clone, Copy)]
pub struct CipherInitParams {
pub magic: [u8; 4],
pub version: u32,
pub mode: u32,
pub cipher_type: CipherType,
pub cipher_mode: CipherMode,
pub padding_mode: CipherPaddingMode,
pub key_usage: KeyUsageType,
pub key_type: KeyType,
pub reserved: u16,
pub reserved2: u64,
}
impl CipherInitParams {
pub const MAGIC: &'static [u8; 4] = b"CIP\0";
pub fn is_valid(&self) -> bool {
&self.magic == Self::MAGIC
}
}
#[vtable_rs::vtable]
pub trait DLDecrypterVmt {
fn destructor(&mut self, flags: u32);
fn decrypt(
&self,
input: *mut u8,
input_size: usize,
output: *mut u8,
output_size: usize,
) -> i32;
}
#[repr(C)]
pub struct DLDecrypter {
vftable: VPtr<dyn DLDecrypterVmt, Self>,
}
#[repr(C)]
pub struct OpenSslAesCipher {
pub cipher_key: NonNull<DLCipherKey>,
pub cipher_mode: u32,
pub padding_mode: u32,
pub key_usage: u32,
pub allocator: &'static DLAllocator,
evp_cipher: usize,
evp_cipher_ctx: usize,
pub requires_iv: bool,
pub padding_enabled: bool,
}
#[repr(C)]
pub struct OpenSslAesDecrypter {
pub base: DLDecrypter,
pub cipher_data: OwnedPtr<OpenSslAesCipher>,
}
#[repr(C)]
pub struct OpenSslRsaCipher {
pub cipher_key: NonNull<DLCipherKey>,
pub padding_mode: u32,
pub block_size: u32,
pub allocator: &'static DLAllocator,
pub use_public_key: bool,
bio: usize,
evp_pkey_ctx: usize,
pub rsa_size: u32,
pub block_input_buffer: OwnedPtr<u8>,
pub block_output_buffer: OwnedPtr<u8>,
}
#[repr(C)]
pub struct OpenSslRsaDecrypter {
pub base: DLDecrypter,
pub cipher_data: OwnedPtr<OpenSslRsaCipher>,
}
#[vtable_rs::vtable]
pub trait DLCipherSPIVmt {
fn destructor(&mut self, flags: u32);
fn get_decrypter(
&self,
params: &CipherInitParams,
key: &DLCipherKey,
allocator: &DLAllocator,
) -> Option<NonNull<DLDecrypter>>;
fn get_encrypter(
&self,
params: &CipherInitParams,
key: &DLCipherKey,
allocator: &DLAllocator,
) -> usize;
}
#[repr(C)]
pub struct DLCipherSPI {
vftable: VPtr<dyn DLCipherSPIVmt, Self>,
}
#[vtable_rs::vtable]
pub trait DLKeyGeneratorSPIVmt {
fn destructor(&mut self, flags: u32);
fn get_cipher_key(
&self,
params: &CryptoKeyParams,
key: &str,
key_len: u32,
allocator: &DLAllocator,
) -> Option<NonNull<DLCipherKey>>;
}
#[repr(C)]
pub struct DLKeyGeneratorSPI {
vftable: VPtr<dyn DLKeyGeneratorSPIVmt, Self>,
}
#[repr(C)]
pub struct CryptoSPIRegistry {
pub key_generators: DLVector<NonNull<DLKeyGeneratorSPI>>,
pub cipher_spis: DLVector<NonNull<DLCipherSPI>>,
}
impl CryptoSPIRegistry {
pub fn get_decrypter(
&self,
params: &CipherInitParams,
key: &DLCipherKey,
allocator: &DLAllocator,
) -> Option<NonNull<DLDecrypter>> {
if !params.is_valid() {
return None;
}
for spi_ptr in self.cipher_spis.iter() {
let cipher_spi = unsafe { spi_ptr.as_ref() };
if let Some(decrypter) =
(cipher_spi.vftable.get_decrypter)(cipher_spi, params, key, allocator)
{
return Some(decrypter);
}
}
None
}
pub fn get_cipher_key(
&self,
params: &CryptoKeyParams,
rsa_key: &str,
allocator: &DLAllocator,
) -> Option<NonNull<DLCipherKey>> {
if !params.is_valid() {
return None;
}
let rsa_key_len: u32 = rsa_key.len() as u32;
for spi_ptr in self.key_generators.iter() {
let keygen_spi = unsafe { spi_ptr.as_ref() };
if let Some(cipher_key) = (keygen_spi.vftable.get_cipher_key)(
keygen_spi,
params,
rsa_key,
rsa_key_len,
allocator,
) {
return Some(cipher_key);
}
}
None
}
}
impl FromStatic for CryptoSPIRegistry {
fn name() -> Cow<'static, str> {
Cow::Borrowed("CryptoSPIRegistry")
}
fn instance_ptr() -> fromsoftware_shared::InstanceResult<*mut Self> {
unsafe { shared::load_static_indirect(rva::get().crypto_spi_registry) }
}
}