initial commit
This commit is contained in:
commit
366cc3b759
6 changed files with 422 additions and 0 deletions
112
src/crypto/encsign.rs
Normal file
112
src/crypto/encsign.rs
Normal 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
1
src/crypto/mod.rs
Normal file
|
|
@ -0,0 +1 @@
|
|||
pub mod encsign;
|
||||
2
src/lib.rs
Normal file
2
src/lib.rs
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
#[cfg(feature = "crypto")]
|
||||
pub mod crypto;
|
||||
Loading…
Reference in a new issue