Start implementing device communication

This commit is contained in:
hodasemi 2023-09-26 14:37:59 +02:00
parent 6f1106ee28
commit e0befff868
8 changed files with 201 additions and 21 deletions

21
src/command.rs Normal file
View file

@ -0,0 +1,21 @@
use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Command {
//
}
impl Command {
pub fn sub_type(device_type: u32) -> Self {
Self {}
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct CommandResponse {
//
}
impl CommandResponse {
//
}

View file

@ -1,27 +1,53 @@
use std::{ use std::{
io::{Read, Write}, io::{Read, Write},
net::TcpStream, net::TcpStream,
sync::Mutex,
thread, thread,
time::Duration, time::Duration,
}; };
use anyhow::{bail, Context, Error, Result}; use anyhow::{bail, Context, Error, Result};
use serde_json::to_string;
use crate::{ use crate::{
command::Command,
devices::{e1::E1, DeviceBackend}, devices::{e1::E1, DeviceBackend},
hex, hex,
packet_builder::PacketBuilder,
security::{MsgType, Security}, security::{MsgType, Security},
DeviceInfo, DeviceInfo,
}; };
#[repr(u8)]
enum MessageType {
Set = 0x02,
Query = 0x03,
Notify1 = 0x04,
Notify2 = 0x05,
Exception = 0x06,
QuerySN = 0x07,
Exception2 = 0x0A,
QuerySubtype = 0xA0,
}
enum ParseMessage {
Success,
Padding,
}
pub struct Device { pub struct Device {
info: DeviceInfo, info: DeviceInfo,
socket: TcpStream, socket: Mutex<TcpStream>,
security: Security, security: Security,
device_backend: Box<dyn DeviceBackend>, device_backend: Box<dyn DeviceBackend>,
buffer: Vec<u8>,
sub_type: Option<String>,
updates: Vec<Box<dyn Fn(&[u8]) -> Result<()>>>,
token: [u8; 64], token: [u8; 64],
key: [u8; 32], key: [u8; 32],
} }
@ -52,9 +78,14 @@ impl Device {
}), }),
info, info,
socket, socket: Mutex::new(socket),
security: Security::default(), security: Security::default(),
buffer: Vec::new(),
sub_type: None,
updates: Vec::new(),
token: hex(token)?.try_into().unwrap(), token: hex(token)?.try_into().unwrap(),
key: hex(key)?.try_into().unwrap(), key: hex(key)?.try_into().unwrap(),
}; };
@ -73,10 +104,12 @@ impl Device {
.security .security
.encode_8370(&self.token, MsgType::HANDSHAKE_REQUEST)?; .encode_8370(&self.token, MsgType::HANDSHAKE_REQUEST)?;
self.socket.write(&request)?; let mut socket = self.socket.lock().unwrap();
socket.write(&request)?;
let mut buffer = [0; 512]; let mut buffer = [0; 512];
let bytes_read = self.socket.read(&mut buffer)?; let bytes_read = socket.read(&mut buffer)?;
if bytes_read < 20 { if bytes_read < 20 {
bail!( bail!(
@ -90,9 +123,109 @@ impl Device {
Ok(()) Ok(())
} }
pub fn refresh_status(&self) -> Result<()> { pub fn refresh_status(&mut self) -> Result<()> {
let mut cmds = self.device_backend.build_query()?;
if self.sub_type.is_none() {
cmds.insert(0, Command::sub_type(self.info.device_type));
}
for cmd in cmds {
self.build_send(cmd)?;
loop {
let mut buf = [0; 512];
let bytes_read = self.socket.lock().unwrap().read(&mut buf)?;
if bytes_read == 0 {
bail!("socket error");
}
match self.parse_message(&buf[..bytes_read])? {
ParseMessage::Success => break,
ParseMessage::Padding => continue,
}
}
}
Ok(()) Ok(())
} }
pub fn register_update<F>(&mut self, f: F)
where
F: Fn(&[u8]) -> Result<()> + 'static,
{
self.updates.push(Box::new(f));
}
fn parse_message(&mut self, msg: &[u8]) -> Result<ParseMessage> {
let (messages, buffer) = self.security.decode_8370(&self.buffer, msg)?;
self.buffer = buffer;
if messages.is_empty() {
return Ok(ParseMessage::Padding);
}
for mut message in messages {
if message == b"ERROR" {
bail!("parse message error");
}
let payload_len = message[4] as u16 + ((message[5] as u16) << 8) - 56;
let payload_type = message[2] as u16 + ((message[3] as u16) << 8);
// heartbeat
if payload_type == 0x1001 || payload_type == 0x0001 {
continue;
}
if message.len() > 56 && payload_len % 16 == 0 {
let len = message.len();
let crypt = &mut message[40..len - 16];
Security::aes_decrypt(crypt);
if self.pre_process_message(crypt)? {
let status = self.device_backend.process_message(crypt)?;
if status.len() > 0 {
for update in self.updates.iter() {
update(&status)?;
}
}
}
}
}
Ok(ParseMessage::Success)
}
fn pre_process_message(&self, msg: &[u8]) -> Result<bool> {
if msg[9] == MessageType::QuerySubtype as u8 {
let message = todo!();
Ok(false)
} else {
Ok(true)
}
}
fn send_message(&self, msg: &[u8]) -> Result<()> {
let data = self.security.encode_8370(msg, MsgType::ENCRYPTED_REQUEST)?;
self.socket.lock().unwrap().write(&data)?;
Ok(())
}
fn send_heartbeat(&self) -> Result<()> {
let msg = PacketBuilder::builder(self.info.id, &[0x00]).finalize(0);
self.send_message(&msg)
}
fn build_send(&self, cmd: Command) -> Result<()> {
let data = PacketBuilder::builder(self.info.id, to_string(&cmd)?.as_bytes()).finalize(1);
self.send_message(&data)
}
} }
#[cfg(test)] #[cfg(test)]

View file

@ -2,6 +2,8 @@ use std::collections::HashMap;
use anyhow::Result; use anyhow::Result;
use crate::command::Command;
use super::DeviceBackend; use super::DeviceBackend;
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
@ -189,11 +191,11 @@ impl E1 {
} }
impl DeviceBackend for E1 { impl DeviceBackend for E1 {
fn build_query(&self) -> () { fn build_query(&self) -> Result<Vec<Command>> {
todo!() todo!()
} }
fn process_message(&self, msg: &str) -> () { fn process_message(&self, msg: &[u8]) -> Result<Vec<u8>> {
todo!() todo!()
} }

View file

@ -1,7 +1,9 @@
use crate::command::Command;
pub mod e1; pub mod e1;
pub trait DeviceBackend { pub trait DeviceBackend {
fn build_query(&self) -> (); fn build_query(&self) -> anyhow::Result<Vec<Command>>;
fn process_message(&self, msg: &str) -> (); fn process_message(&self, msg: &[u8]) -> anyhow::Result<Vec<u8>>;
fn set_attribute(&self, attribute: &str, value: &str) -> (); fn set_attribute(&self, attribute: &str, value: &str) -> ();
} }

View file

@ -72,7 +72,8 @@ impl Startup {
} }
let len = bytes.len(); let len = bytes.len();
let encrypt_data = Security::aes_decrypt(&mut bytes[40..(len - 16)]); let encrypt_data = &mut bytes[40..(len - 16)];
Security::aes_decrypt(encrypt_data);
let start = 41; let start = 41;
let upper = start + encrypt_data[40] as usize; let upper = start + encrypt_data[40] as usize;

View file

@ -2,9 +2,11 @@ use std::num::ParseIntError;
mod cloud; mod cloud;
mod cloud_security; mod cloud_security;
mod command;
mod device; mod device;
mod devices; mod devices;
mod discover; mod discover;
mod packet_builder;
mod security; mod security;
fn hex(s: &str) -> Result<Vec<u8>, ParseIntError> { fn hex(s: &str) -> Result<Vec<u8>, ParseIntError> {

13
src/packet_builder.rs Normal file
View file

@ -0,0 +1,13 @@
pub struct PacketBuilder {
//
}
impl PacketBuilder {
pub fn builder(device_id: u64, msg: &[u8]) -> Self {
Self {}
}
pub fn finalize(self, msg_type: u8) -> Vec<u8> {
todo!()
}
}

View file

@ -1,3 +1,5 @@
use std::sync::atomic::{AtomicU16, Ordering::SeqCst};
use aes::{ use aes::{
cipher::{ cipher::{
block_padding::NoPadding, generic_array::GenericArray, BlockDecrypt, BlockDecryptMut, block_padding::NoPadding, generic_array::GenericArray, BlockDecrypt, BlockDecryptMut,
@ -22,8 +24,8 @@ pub enum MsgType {
#[derive(Debug, Default)] #[derive(Debug, Default)]
pub struct Security { pub struct Security {
request_count: u16, request_count: AtomicU16,
response_count: u16, response_count: AtomicU16,
tcp_key: Option<[u8; 32]>, tcp_key: Option<[u8; 32]>,
} }
@ -33,7 +35,7 @@ impl Security {
const KEY: [u8; 16] = Self::N.to_be_bytes(); const KEY: [u8; 16] = Self::N.to_be_bytes();
const IV: [u8; 16] = [b'\0'; 16]; const IV: [u8; 16] = [b'\0'; 16];
pub fn aes_decrypt(data: &mut [u8]) -> &[u8] { pub fn aes_decrypt(data: &mut [u8]) {
let array = GenericArray::from(Self::KEY); let array = GenericArray::from(Self::KEY);
let cipher = Aes128::new(&array); let cipher = Aes128::new(&array);
@ -41,8 +43,6 @@ impl Security {
let mut block = GenericArray::from_mut_slice(chunk); let mut block = GenericArray::from_mut_slice(chunk);
cipher.decrypt_block(&mut block); cipher.decrypt_block(&mut block);
} }
data
} }
pub fn aes_cbc_encrypt(&self, raw: [u8; 32], key: &[u8; 32]) -> [u8; 32] { pub fn aes_cbc_encrypt(&self, raw: [u8; 32], key: &[u8; 32]) -> [u8; 32] {
@ -84,8 +84,8 @@ impl Security {
} }
self.tcp_key = Some(Self::xorstr(&result, key).try_into().unwrap()); self.tcp_key = Some(Self::xorstr(&result, key).try_into().unwrap());
self.request_count = 0; self.request_count.store(0, SeqCst);
self.response_count = 0; self.response_count.store(0, SeqCst);
Ok(()) Ok(())
} }
@ -96,7 +96,7 @@ impl Security {
lhs.iter().zip(rhs.iter()).map(|(&l, &r)| l ^ r).collect() lhs.iter().zip(rhs.iter()).map(|(&l, &r)| l ^ r).collect()
} }
pub fn encode_8370(&mut self, msg: &[u8], msg_type: MsgType) -> Result<Vec<u8>> { pub fn encode_8370(&self, msg: &[u8], msg_type: MsgType) -> Result<Vec<u8>> {
let mut header = hex("8370")?; let mut header = hex("8370")?;
let mut data: Vec<u8> = msg.to_vec(); let mut data: Vec<u8> = msg.to_vec();
@ -120,13 +120,15 @@ impl Security {
header.extend([0x20, (padding << 4) as u8 | msg_type as u8]); header.extend([0x20, (padding << 4) as u8 | msg_type as u8]);
data = { data = {
let mut b = self.request_count.to_be_bytes().to_vec(); let mut b = self
.request_count
.fetch_add(1, SeqCst)
.to_be_bytes()
.to_vec();
b.extend(data); b.extend(data);
b b
}; };
(self.request_count, _) = self.request_count.overflowing_add(1);
if msg_type == MsgType::ENCRYPTED_RESPONSE || msg_type == MsgType::ENCRYPTED_REQUEST { if msg_type == MsgType::ENCRYPTED_RESPONSE || msg_type == MsgType::ENCRYPTED_REQUEST {
let sign: Vec<u8> = Sha256::digest(Self::add_bytes(header.clone(), data.clone())) let sign: Vec<u8> = Sha256::digest(Self::add_bytes(header.clone(), data.clone()))
.into_iter() .into_iter()
@ -146,6 +148,10 @@ impl Security {
lhs.extend(rhs); lhs.extend(rhs);
lhs lhs
} }
pub fn decode_8370(&self, buffer: &[u8], msg: &[u8]) -> Result<(Vec<Vec<u8>>, Vec<u8>)> {
todo!()
}
} }
#[cfg(test)] #[cfg(test)]