2023-09-26 12:37:59 +00:00
|
|
|
use std::sync::atomic::{AtomicU16, Ordering::SeqCst};
|
|
|
|
|
2023-09-22 10:34:35 +00:00
|
|
|
use aes::{
|
2023-09-24 11:16:57 +00:00
|
|
|
cipher::{
|
2023-09-25 09:30:54 +00:00
|
|
|
block_padding::NoPadding, generic_array::GenericArray, BlockDecrypt, BlockDecryptMut,
|
2023-10-03 07:19:19 +00:00
|
|
|
BlockEncrypt, BlockEncryptMut, BlockSizeUser, KeyInit, KeyIvInit,
|
2023-09-24 11:16:57 +00:00
|
|
|
},
|
2023-09-22 10:34:35 +00:00
|
|
|
Aes128,
|
|
|
|
};
|
2023-09-24 11:16:57 +00:00
|
|
|
use anyhow::{bail, Result};
|
2023-09-22 10:34:35 +00:00
|
|
|
use rand::{self, RngCore};
|
2023-09-24 11:16:57 +00:00
|
|
|
use sha2::{Digest, Sha256};
|
2023-09-22 10:34:35 +00:00
|
|
|
|
|
|
|
use crate::hex;
|
|
|
|
|
|
|
|
#[allow(non_camel_case_types)]
|
|
|
|
#[repr(u8)]
|
2023-09-24 11:16:57 +00:00
|
|
|
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone, Copy)]
|
2023-09-22 10:34:35 +00:00
|
|
|
pub enum MsgType {
|
|
|
|
HANDSHAKE_REQUEST = 0x0,
|
|
|
|
ENCRYPTED_RESPONSE = 0x3,
|
|
|
|
ENCRYPTED_REQUEST = 0x6,
|
|
|
|
}
|
|
|
|
|
2023-09-22 12:14:46 +00:00
|
|
|
#[derive(Debug, Default)]
|
|
|
|
pub struct Security {
|
2023-09-26 12:37:59 +00:00
|
|
|
request_count: AtomicU16,
|
|
|
|
response_count: AtomicU16,
|
2023-09-24 11:16:57 +00:00
|
|
|
|
|
|
|
tcp_key: Option<[u8; 32]>,
|
2023-09-22 12:14:46 +00:00
|
|
|
}
|
2023-09-22 10:34:35 +00:00
|
|
|
|
|
|
|
impl Security {
|
2023-09-22 12:14:46 +00:00
|
|
|
const N: u128 = 141661095494369103254425781617665632877;
|
|
|
|
const KEY: [u8; 16] = Self::N.to_be_bytes();
|
2023-09-24 11:16:57 +00:00
|
|
|
const IV: [u8; 16] = [b'\0'; 16];
|
2023-09-29 13:10:47 +00:00
|
|
|
const SALT: &[u8] = b"xhdiwjnchekd4d512chdjx5d8e4c394D2D7S";
|
|
|
|
|
|
|
|
pub fn encode32_data(data: &[u8]) -> Vec<u8> {
|
|
|
|
md5::compute([data, Self::SALT].concat()).to_vec()
|
|
|
|
}
|
|
|
|
|
2023-10-03 07:19:19 +00:00
|
|
|
pub fn aes_encrypt(data: &[u8]) -> Vec<u8> {
|
2023-09-29 13:10:47 +00:00
|
|
|
let array = GenericArray::from(Self::KEY);
|
|
|
|
let cipher = Aes128::new(&array);
|
|
|
|
|
|
|
|
let mut result = vec![0; data.len()];
|
|
|
|
let padding = 16 - (result.len() % 16);
|
|
|
|
result.extend(&vec![0; padding]);
|
|
|
|
|
|
|
|
for (inchunk, outchunk) in data.chunks(16).zip(result.chunks_mut(16)) {
|
|
|
|
let in_data = if inchunk.len() != 16 {
|
|
|
|
[inchunk, &vec![0; padding]].concat()
|
|
|
|
} else {
|
|
|
|
inchunk.to_vec()
|
|
|
|
};
|
|
|
|
|
|
|
|
let inblock = GenericArray::from_slice(&in_data);
|
|
|
|
let mut out_block = GenericArray::from_mut_slice(outchunk);
|
|
|
|
|
|
|
|
cipher.encrypt_block_b2b(&inblock, &mut out_block);
|
|
|
|
}
|
|
|
|
|
|
|
|
result
|
|
|
|
}
|
2023-09-22 10:34:35 +00:00
|
|
|
|
2023-09-26 12:37:59 +00:00
|
|
|
pub fn aes_decrypt(data: &mut [u8]) {
|
2023-09-22 12:14:46 +00:00
|
|
|
let array = GenericArray::from(Self::KEY);
|
2023-09-22 10:34:35 +00:00
|
|
|
let cipher = Aes128::new(&array);
|
|
|
|
|
|
|
|
for chunk in data.chunks_mut(16) {
|
|
|
|
let mut block = GenericArray::from_mut_slice(chunk);
|
|
|
|
cipher.decrypt_block(&mut block);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-10-03 07:19:19 +00:00
|
|
|
pub fn aes_cbc_encrypt(raw: &[u8], key: &[u8; 32]) -> Vec<u8> {
|
2023-09-24 11:16:57 +00:00
|
|
|
type Aes256CbcEnc = cbc::Encryptor<aes::Aes256>;
|
|
|
|
|
2023-10-03 07:19:19 +00:00
|
|
|
debug_assert_eq!(raw.len() % Aes256CbcEnc::block_size(), 0);
|
2023-10-02 07:30:58 +00:00
|
|
|
|
2023-10-03 07:19:19 +00:00
|
|
|
Aes256CbcEnc::new(key.into(), &Self::IV.into()).encrypt_padded_vec_mut::<NoPadding>(raw)
|
2023-09-24 11:16:57 +00:00
|
|
|
}
|
|
|
|
|
2023-10-03 07:19:19 +00:00
|
|
|
pub fn aes_cbc_decrypt(raw: &[u8], key: &[u8; 32]) -> Vec<u8> {
|
2023-09-24 11:16:57 +00:00
|
|
|
type Aes256CbcDec = cbc::Decryptor<aes::Aes256>;
|
|
|
|
|
2023-10-03 07:19:19 +00:00
|
|
|
debug_assert_eq!(raw.len() % Aes256CbcDec::block_size(), 0);
|
|
|
|
|
2023-09-24 11:16:57 +00:00
|
|
|
Aes256CbcDec::new(key.into(), &Self::IV.into())
|
2023-10-03 07:19:19 +00:00
|
|
|
.decrypt_padded_vec_mut::<NoPadding>(raw)
|
2023-09-25 09:30:54 +00:00
|
|
|
.unwrap()
|
2023-09-24 11:16:57 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
pub fn tcp_key(&mut self, response: &[u8], key: &[u8; 32]) -> Result<()> {
|
|
|
|
if response == b"ERROR" {
|
2023-09-25 09:30:54 +00:00
|
|
|
bail!("authentication failed! (code ERROR)");
|
2023-09-24 11:16:57 +00:00
|
|
|
}
|
|
|
|
|
2023-10-03 07:19:19 +00:00
|
|
|
let payload = &response[0..32];
|
2023-09-25 09:30:54 +00:00
|
|
|
let sign = &response[32..];
|
2023-10-03 07:19:19 +00:00
|
|
|
let result = Self::aes_cbc_decrypt(payload, &key);
|
2023-09-24 11:16:57 +00:00
|
|
|
|
2023-09-25 09:30:54 +00:00
|
|
|
if Sha256::digest(&result).into_iter().collect::<Vec<u8>>() != sign {
|
2023-09-24 11:16:57 +00:00
|
|
|
bail!("sign does not match");
|
|
|
|
}
|
|
|
|
|
2023-09-25 09:30:54 +00:00
|
|
|
self.tcp_key = Some(Self::xorstr(&result, key).try_into().unwrap());
|
2023-09-26 12:37:59 +00:00
|
|
|
self.request_count.store(0, SeqCst);
|
|
|
|
self.response_count.store(0, SeqCst);
|
2023-09-24 11:16:57 +00:00
|
|
|
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
|
|
|
fn xorstr(lhs: &[u8], rhs: &[u8]) -> Vec<u8> {
|
2023-09-25 09:30:54 +00:00
|
|
|
debug_assert_eq!(lhs.len(), rhs.len());
|
2023-09-22 10:34:35 +00:00
|
|
|
|
2023-09-24 11:16:57 +00:00
|
|
|
lhs.iter().zip(rhs.iter()).map(|(&l, &r)| l ^ r).collect()
|
|
|
|
}
|
|
|
|
|
2023-09-26 12:37:59 +00:00
|
|
|
pub fn encode_8370(&self, msg: &[u8], msg_type: MsgType) -> Result<Vec<u8>> {
|
2023-09-24 11:16:57 +00:00
|
|
|
let mut header = hex("8370")?;
|
|
|
|
let mut data: Vec<u8> = msg.to_vec();
|
|
|
|
|
|
|
|
let mut size = data.len() as u16;
|
2023-09-22 10:34:35 +00:00
|
|
|
let mut padding = 0;
|
|
|
|
|
|
|
|
if msg_type == MsgType::ENCRYPTED_RESPONSE || msg_type == MsgType::ENCRYPTED_REQUEST {
|
|
|
|
if (size + 2) % 16 != 0 {
|
|
|
|
padding = 16 - ((size + 2) & 0xf);
|
|
|
|
size += padding + 32;
|
|
|
|
data.extend({
|
2023-09-24 11:16:57 +00:00
|
|
|
let mut d = vec![0; padding as usize];
|
2023-09-22 10:34:35 +00:00
|
|
|
rand::thread_rng().fill_bytes(&mut d);
|
|
|
|
|
|
|
|
d
|
|
|
|
});
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-09-24 11:16:57 +00:00
|
|
|
header.extend(size.to_be_bytes());
|
|
|
|
header.extend([0x20, (padding << 4) as u8 | msg_type as u8]);
|
|
|
|
|
|
|
|
data = {
|
2023-09-26 12:37:59 +00:00
|
|
|
let mut b = self
|
|
|
|
.request_count
|
|
|
|
.fetch_add(1, SeqCst)
|
|
|
|
.to_be_bytes()
|
|
|
|
.to_vec();
|
2023-09-24 11:16:57 +00:00
|
|
|
b.extend(data);
|
|
|
|
b
|
|
|
|
};
|
|
|
|
|
|
|
|
if msg_type == MsgType::ENCRYPTED_RESPONSE || msg_type == MsgType::ENCRYPTED_REQUEST {
|
|
|
|
let sign: Vec<u8> = Sha256::digest(Self::add_bytes(header.clone(), data.clone()))
|
|
|
|
.into_iter()
|
|
|
|
.collect();
|
|
|
|
|
2023-10-03 07:19:19 +00:00
|
|
|
data = Self::aes_cbc_encrypt(&data, self.tcp_key.as_ref().unwrap());
|
2023-09-24 11:16:57 +00:00
|
|
|
data.extend(sign);
|
|
|
|
}
|
|
|
|
|
|
|
|
header.extend(data);
|
|
|
|
Ok(header)
|
|
|
|
}
|
|
|
|
|
|
|
|
fn add_bytes(mut lhs: Vec<u8>, rhs: Vec<u8>) -> Vec<u8> {
|
|
|
|
lhs.extend(rhs);
|
|
|
|
lhs
|
2023-09-22 10:34:35 +00:00
|
|
|
}
|
2023-09-26 12:37:59 +00:00
|
|
|
|
2023-10-02 07:30:58 +00:00
|
|
|
pub fn decode_8370(&self, mut data: Vec<u8>) -> Result<(Vec<Vec<u8>>, Vec<u8>)> {
|
|
|
|
if data.len() < 6 {
|
|
|
|
return Ok((Vec::new(), data));
|
|
|
|
}
|
|
|
|
|
|
|
|
let header = data[..6].to_vec();
|
|
|
|
|
|
|
|
if header[0] != 0x83 || header[1] != 0x70 {
|
|
|
|
bail!("no an 8370 message");
|
|
|
|
} else if header[4] != 0x20 {
|
|
|
|
bail!("missing byte 4");
|
|
|
|
}
|
|
|
|
|
|
|
|
let size = u16::from_be_bytes(header[2..4].try_into().unwrap()) as usize + 8;
|
|
|
|
|
|
|
|
let mut leftover = Vec::new();
|
|
|
|
|
|
|
|
if data.len() < size {
|
|
|
|
return Ok((Vec::new(), data.to_vec()));
|
|
|
|
} else if data.len() > size {
|
|
|
|
leftover = data[size..].to_vec();
|
|
|
|
data = data[..size].to_vec();
|
|
|
|
}
|
|
|
|
|
|
|
|
let padding = header[5] >> 4;
|
|
|
|
let msgtype = header[5] & 0xf;
|
|
|
|
data = data[6..].to_vec();
|
|
|
|
|
2023-10-03 07:19:19 +00:00
|
|
|
let header_ref = b"\x83p\x00\x8e c";
|
|
|
|
|
|
|
|
assert_eq!(header_ref, header.as_slice());
|
|
|
|
|
2023-10-02 07:30:58 +00:00
|
|
|
if msgtype == MsgType::ENCRYPTED_RESPONSE as u8
|
|
|
|
|| msgtype == MsgType::ENCRYPTED_REQUEST as u8
|
|
|
|
{
|
|
|
|
let sign = data[(data.len() - 32)..].to_vec();
|
|
|
|
data = data[..(data.len() - 32)].to_vec();
|
2023-10-03 07:19:19 +00:00
|
|
|
data = Self::aes_cbc_decrypt(&data, &self.tcp_key.unwrap()).to_vec();
|
2023-10-02 07:30:58 +00:00
|
|
|
|
|
|
|
let compare_sign: Vec<u8> = Sha256::digest(&[header.to_vec(), data.clone()].concat())
|
|
|
|
.into_iter()
|
|
|
|
.collect();
|
|
|
|
|
|
|
|
if sign != compare_sign {
|
|
|
|
bail!("sign does not match");
|
|
|
|
}
|
|
|
|
|
|
|
|
if padding != 0 {
|
|
|
|
data = data[..(data.len() - padding as usize)].to_vec();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
self.response_count
|
|
|
|
.store(u16::from_be_bytes(data[..2].try_into().unwrap()), SeqCst);
|
|
|
|
|
|
|
|
data = data[2..].to_vec();
|
|
|
|
|
|
|
|
if leftover.len() > 0 {
|
|
|
|
let (mut packets, incomplete) = self.decode_8370(leftover)?;
|
|
|
|
|
|
|
|
packets.insert(0, data);
|
|
|
|
|
|
|
|
Ok((packets, incomplete))
|
|
|
|
} else {
|
|
|
|
Ok((vec![data], Vec::new()))
|
|
|
|
}
|
2023-09-26 12:37:59 +00:00
|
|
|
}
|
2023-09-22 10:34:35 +00:00
|
|
|
}
|
2023-09-25 09:30:54 +00:00
|
|
|
|
|
|
|
#[cfg(test)]
|
|
|
|
mod test {
|
|
|
|
use super::*;
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn aes_cbc_decrypt() {
|
2023-10-03 07:19:19 +00:00
|
|
|
let payload =
|
|
|
|
b",\xcbq_T\x81L\x96\xfa\xe7\xe4\xa7\xc5\xabU \r\xf5x\xd6\x08\x94_\\\xce\x8br\x1b\xa5\xbe\xc6\x1a";
|
2023-09-25 09:30:54 +00:00
|
|
|
let key = b"*[R\x00\xc2\xc0ML\x81\x1d\x05P\xe1\xdc[1CT6\xb9[wM*\x88\xd7\xe4ma\xfd\x96i";
|
|
|
|
let plain = b"\x9b\xaa\xdf\xff\x07\x1a\xd2\xe4\xb7TY\xe2\xf9\x8c\xdf\xe7!+\xda\xe4\x86GY\xe6j\x94\xdb\xe7\xb9b\xda\xe6";
|
|
|
|
|
2023-10-03 07:19:19 +00:00
|
|
|
let result = Security::aes_cbc_decrypt(payload, key);
|
2023-09-25 09:30:54 +00:00
|
|
|
|
|
|
|
assert_eq!(&result, plain);
|
|
|
|
}
|
2023-10-03 07:19:19 +00:00
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn xor() {
|
|
|
|
let lhs = b"\xf8\x9c\xd9\xb4{>X\x95Y\xff\xd9\x95\x98nY\x95\x89\x8eY\x95\xe9\x86Y\x95\xe1\xb6Y\x95\xd1\xb2Y\x95";
|
|
|
|
let rhs = b"P\xe7yG\xdccBm\xb3\x88<v\x16a4\x10\x04K\x02V\x7fR@\xa5\xba\xf7\x899\x1b.Zy";
|
|
|
|
|
|
|
|
let res = Security::xorstr(lhs, rhs);
|
|
|
|
|
|
|
|
assert_eq!(res, b"\xa8{\xa0\xf3\xa7]\x1a\xf8\xeaw\xe5\xe3\x8e\x0fm\x85\x8d\xc5[\xc3\x96\xd4\x190[A\xd0\xac\xca\x9c\x03\xec");
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn aes_cbc_decrypt_padding() {
|
|
|
|
let data = b"~\xb3\xb2\xa3x\t\x95\\\xe5U\x08\xba\t\xafe\xd0M\x0f\xf2\xdb\xda!\xb9\xab\x08#\xcf\xb3\x1f\xb3K\xa5\x85\x97\x06\xb4s\xaa\x11\xde\xb7\xf4%<J~\x9d\xdd\x9c8\xa1+\xdd\xa2\xdb\xf0\xc5)\xb3Oa\xb0\xbd\xbf\xf8\xd0Ea~f*\xc7}\xa9\x89\xb8\x9b\x89\xd8\xaci\x11S}\xd4Z\x981z\xed\xbe\xcf\xc8V\xe8\xe9\x19.\x8d\xc9\xf6`\xb7\xc3\xf7\x98O$\x19\x0bUz";
|
|
|
|
let key = b"V\x103\xba\xa0W\x85\xaa\x0c\x01q\xb7\x94\t\x7f\xd4\xe7=L\x91\x02\x14\x8d`\xf7~\xc6\xfd\x99?\x14\xbc";
|
|
|
|
|
|
|
|
let res_ref = b"\x00\x00ZZ\x01\x11h\x00@\x00\xfe\x11\x00\x00\xe9C1\x13\x02\n\x17\x14\x02\x86\x02\x00\x00\x8b\x00\x00\x00\x00\x00\x00\x00\x00\x01\x80\x00\x00\x00\x00\xb9qa\xcbB\xe7\x16\x97 b\xc8\xcd\x03N\x10\xd0\x94\xd9S\x10\xf9\x88\xbdZOX,\n\xe7L'\x1d\xf2p\xa5\x15\xf6\x9d\x1d>\x84z\xfe\xda\xd6Gx\x1d\n\xf6F\xac\xe9\xcd\xc5\xb9\xb8\x98\xae\x1b\n\xab\xc9\xee\x9a\xb6\xd2\xc5=:";
|
|
|
|
let res = Security::aes_cbc_decrypt(data, key);
|
|
|
|
|
|
|
|
assert_eq!(res.len(), res_ref.len());
|
|
|
|
assert_eq!(res, res_ref);
|
|
|
|
}
|
2023-09-25 09:30:54 +00:00
|
|
|
}
|