initial commit

This commit is contained in:
Maple Nebel 2026-07-03 22:15:58 +02:00
commit 366cc3b759
6 changed files with 422 additions and 0 deletions

112
src/crypto/encsign.rs Normal file
View file

@ -0,0 +1,112 @@
use aes::{
Aes128,
cipher::{Block, BlockCipherDecrypt, BlockCipherEncrypt, BlockSizeUser, block},
};
use bytemuck::{Pod, PodCastError, Zeroable};
use hmac::{Hmac, KeyInit, Mac};
use hybrid_array::Array;
use md5::Md5;
use rand::random;
use thiserror::Error;
use crate::crypto::encsign::Error::{BlockCastError, InvalidSignature, MessageTooSmall};
// first is aes second is hmac
pub struct EncSignKeypair(pub [u8; 0x10], pub [u8; 0x40]);
type HmacMd5 = Hmac<Md5>;
impl EncSignKeypair {
fn new_random() -> Self {
Self(random(), random())
}
}
pub fn blob_calc_signature(data: &[u8], key: &[u8; 0x40]) -> [u8; 0x10] {
let mut hmac = HmacMd5::new(Array::cast_from_core(key));
hmac.update(data);
hmac.finalize().into_bytes().0
}
pub fn encrypt_and_gen_signature_blocks(
data: &mut [Block<Aes128>],
pair: &EncSignKeypair,
) -> [u8; 0x10] {
let signature = blob_calc_signature(bytemuck::cast_slice(&data), &pair.1);
Aes128::new(Array::cast_from_core(&pair.0)).encrypt_blocks(data);
signature
}
pub fn decrypt_and_gen_signature_blocks<'a, 'b>(
data: &'a mut [Block<Aes128>],
pair: &'b EncSignKeypair,
) -> [u8; 0x10] {
Aes128::new(Array::cast_from_core(&pair.0)).decrypt_blocks(data);
blob_calc_signature(bytemuck::cast_slice(&data), &pair.1)
}
#[derive(Error, Debug, PartialEq)]
pub enum Error {
#[error("an error occurred whilest casting data to blocks: {0}")]
BlockCastError(PodCastError),
#[error("invalid signature")]
InvalidSignature,
#[error("message too small, it must be at least 0x10 in size")]
MessageTooSmall,
}
pub type Result<T, E = Error> = std::result::Result<T, E>;
pub fn encrypt_and_sign(mut data: Vec<u8>, keypair: &EncSignKeypair) -> Result<Vec<u8>> {
let block_data = bytemuck::try_cast_slice_mut(&mut data).map_err(BlockCastError)?;
let signature = encrypt_and_gen_signature_blocks(block_data, keypair);
data.extend_from_slice(&signature[..]);
Ok(data)
}
pub fn decrypt_and_check<'a, 'b>(
data: &'a mut [u8],
keypair: &'b EncSignKeypair,
) -> Result<&'a [u8]> {
let signature_delim_point = data.len().checked_sub(0x10).ok_or(MessageTooSmall)?;
let (crypt_data, signature_data) = data
.split_at_mut_checked(signature_delim_point)
.ok_or(MessageTooSmall)?;
let block_data = bytemuck::try_cast_slice_mut(crypt_data).map_err(BlockCastError)?;
let signature = decrypt_and_gen_signature_blocks(block_data, keypair);
if signature_data != &signature[..] {
return Err(InvalidSignature);
}
Ok(crypt_data)
}
#[cfg(test)]
mod test {
use super::{EncSignKeypair, Error, decrypt_and_check, encrypt_and_sign};
const FUZZ_ROUNDS: usize = 10000;
#[test]
fn fuzz_test_succeed() {
for _ in 0..FUZZ_ROUNDS {
let keypair = EncSignKeypair::new_random();
let random_data: [u8; 0x20] = rand::random();
let random_data_vec: Vec<u8> = random_data.into();
let mut message = encrypt_and_sign(random_data_vec, &keypair).unwrap();
let result = decrypt_and_check(&mut message, &keypair).unwrap();
assert_eq!(&random_data[..], result);
}
}
#[test]
fn fuzz_test_fail() {
for _ in 0..FUZZ_ROUNDS {
let keypair = EncSignKeypair::new_random();
let random_data: [u8; 0x20] = rand::random();
let random_data_vec: Vec<u8> = random_data.into();
let mut message = encrypt_and_sign(random_data_vec, &keypair).unwrap();
message.extend_from_slice(&[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]);
assert_eq!(
decrypt_and_check(&mut message, &keypair),
Err(Error::InvalidSignature)
);
}
}
}

1
src/crypto/mod.rs Normal file
View file

@ -0,0 +1 @@
pub mod encsign;

2
src/lib.rs Normal file
View file

@ -0,0 +1,2 @@
#[cfg(feature = "crypto")]
pub mod crypto;