mirror of
https://codeberg.org/icewind/mitemp-rs.git
synced 2026-06-03 17:24:08 +02:00
wip dumpo
This commit is contained in:
parent
c51f1988d9
commit
9496c0a605
4 changed files with 208 additions and 33 deletions
|
|
@ -5,7 +5,8 @@ authors = ["Robin Appelman <robin@icewind.nl>"]
|
||||||
edition = "2018"
|
edition = "2018"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
btleplug = "0.3.1"
|
btleplug = { version = "0.4.0", path = "../btleplug" }
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
main_error = "0.1.0"
|
main_error = "0.1.0"
|
||||||
|
env_logger = "0.7.1"
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
fn main() -> Result<(), btleplug::Error> {
|
fn main() -> Result<(), btleplug::Error> {
|
||||||
|
env_logger::init();
|
||||||
mitemp::test()?;
|
mitemp::test()?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
|
||||||
62
src/cipher.rs
Normal file
62
src/cipher.rs
Normal file
|
|
@ -0,0 +1,62 @@
|
||||||
|
use std::ops::Rem;
|
||||||
|
|
||||||
|
pub fn mix_a(mac: [u8; 6], product_id: u16) -> [u8; 8] {
|
||||||
|
[
|
||||||
|
mac[0],
|
||||||
|
mac[2],
|
||||||
|
mac[5],
|
||||||
|
(product_id & 0xFF) as u8,
|
||||||
|
(product_id & 0xFF) as u8,
|
||||||
|
mac[4],
|
||||||
|
mac[5],
|
||||||
|
mac[1],
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn mix_b(mac: [u8; 6], product_id: u16) -> [u8; 8] {
|
||||||
|
[
|
||||||
|
mac[0],
|
||||||
|
mac[2],
|
||||||
|
mac[5],
|
||||||
|
(product_id >> 8 & 255) as u8,
|
||||||
|
mac[4],
|
||||||
|
mac[0],
|
||||||
|
mac[5],
|
||||||
|
(product_id & 255) as u8,
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
const KEY_SIZE: usize = 256;
|
||||||
|
|
||||||
|
fn cipher_init(key: &[u8]) -> [u8; KEY_SIZE] {
|
||||||
|
let mut perm = [0u8; KEY_SIZE];
|
||||||
|
for i in 0..KEY_SIZE {
|
||||||
|
perm[i] = i as u8;
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut j: u8 = 0;
|
||||||
|
for ia in 0..KEY_SIZE {
|
||||||
|
j = j.wrapping_add(perm[ia]).wrapping_add(key[ia % key.len()]);
|
||||||
|
perm.swap(ia, j as usize);
|
||||||
|
}
|
||||||
|
perm
|
||||||
|
}
|
||||||
|
|
||||||
|
fn cipher_crypt(input: &[u8], mut perm: [u8; KEY_SIZE]) -> Vec<u8> {
|
||||||
|
let mut output = Vec::with_capacity(input.len());
|
||||||
|
let mut index1: u8 = 0;
|
||||||
|
let mut index2: u8 = 0;
|
||||||
|
|
||||||
|
for i in 0..input.len() {
|
||||||
|
index1 = index1.wrapping_add(1);
|
||||||
|
index2 = index2.wrapping_add(perm[index1 as usize]);
|
||||||
|
perm.swap(index1 as usize, index2 as usize);
|
||||||
|
let index = perm[index1 as usize].wrapping_add(perm[index2 as usize]);
|
||||||
|
output.push(input[i] ^ perm[index as usize]);
|
||||||
|
}
|
||||||
|
output
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn cipher(key: &[u8], input: &[u8]) -> Vec<u8> {
|
||||||
|
cipher_crypt(input, cipher_init(key))
|
||||||
|
}
|
||||||
173
src/lib.rs
173
src/lib.rs
|
|
@ -1,47 +1,69 @@
|
||||||
|
#![allow(dead_code)]
|
||||||
|
#![allow(unused_variables)]
|
||||||
|
#![allow(unused_mut)]
|
||||||
|
|
||||||
|
mod cipher;
|
||||||
|
|
||||||
|
use btleplug::api::{
|
||||||
|
BDAddr, Central, CentralEvent, CharPropFlags, Characteristic, Peripheral, UUID,
|
||||||
|
};
|
||||||
|
use btleplug::bluez::adapter::ConnectedAdapter;
|
||||||
|
use btleplug::bluez::manager::Manager;
|
||||||
|
use std::str::FromStr;
|
||||||
|
use std::sync::atomic::{AtomicBool, Ordering};
|
||||||
|
use std::sync::mpsc::channel;
|
||||||
|
use std::sync::Arc;
|
||||||
use std::thread;
|
use std::thread;
|
||||||
use std::time::{Duration, Instant};
|
use std::time::{Duration, Instant};
|
||||||
use btleplug::bluez::manager::Manager;
|
|
||||||
use btleplug::api::{UUID, Central, Peripheral, BDAddr, CentralEvent, Characteristic};
|
|
||||||
use std::sync::atomic::{AtomicBool, Ordering};
|
|
||||||
use std::sync::Arc;
|
|
||||||
use btleplug::bluez::adapter::ConnectedAdapter;
|
|
||||||
|
|
||||||
pub fn test() -> Result<(), btleplug::Error> {
|
pub fn test() -> Result<(), btleplug::Error> {
|
||||||
let addr = BDAddr {
|
// let addr = BDAddr::from_str("1C:4D:70:56:DA:AA").unwrap();
|
||||||
address: [0xAA, 0xDA, 0x56, 0x70, 0x4D, 0x1C]
|
let addr = BDAddr::from_str("00:1A:7D:DA:71:08").unwrap();
|
||||||
};
|
// let addr = BDAddr::from_str("40:4E:36:BF:E1:45").unwrap();
|
||||||
let adapter = adapter_by_mac(addr)?;
|
let adapter = adapter_by_mac(addr)?;
|
||||||
|
|
||||||
// reset the adapter -- clears out any errant state
|
dbg!("discovering");
|
||||||
|
|
||||||
let addr = BDAddr {
|
let addr = BDAddr::from_str("58:2d:34:35:f3:d4").unwrap();
|
||||||
address: [0xD4, 0xF3, 0x35, 0x34, 0x2D, 0x58]
|
|
||||||
};
|
|
||||||
|
|
||||||
let mut device = Device::discover(&adapter, addr).unwrap();
|
let mut device = Device::discover(&adapter, addr).unwrap();
|
||||||
|
|
||||||
println!("connecting");
|
println!("connecting");
|
||||||
device.connect()?;
|
device.connect()?;
|
||||||
|
|
||||||
|
device.auth([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12])?;
|
||||||
let _ = dbg!(device.get_firmware());
|
let _ = dbg!(device.get_firmware());
|
||||||
let _ = dbg!(device.get_battery());
|
let _ = dbg!(device.get_battery());
|
||||||
Ok(())
|
device.listen(|| {})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn adapter_by_mac(addr: BDAddr) -> Result<ConnectedAdapter, btleplug::Error> {
|
pub fn adapter_by_mac(addr: BDAddr) -> Result<ConnectedAdapter, btleplug::Error> {
|
||||||
let manager = Manager::new()?;
|
let manager = Manager::new()?;
|
||||||
let adapters = manager.adapters()?;
|
let adapters = manager.adapters()?;
|
||||||
|
|
||||||
let mut adapter = adapters.into_iter().find(|adapter| adapter.addr == addr).ok_or(btleplug::Error::DeviceNotFound)?;
|
let mut adapter = adapters
|
||||||
|
.into_iter()
|
||||||
adapter = manager.down(&adapter).unwrap();
|
.find(|adapter| adapter.addr == addr)
|
||||||
adapter = manager.up(&adapter).unwrap();
|
.ok_or(btleplug::Error::DeviceNotFound)?;
|
||||||
|
//
|
||||||
|
// adapter = manager.down(&adapter).unwrap();
|
||||||
|
// adapter = manager.up(&adapter).unwrap();
|
||||||
|
|
||||||
adapter.connect()
|
adapter.connect()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const UUID_DEVICE_NAME: UUID = UUID::B16(0x2A00);
|
||||||
|
const UUID_APPEARANCE: UUID = UUID::B16(0x2A01);
|
||||||
const UUID_BATTERY: UUID = UUID::B16(0x2A19);
|
const UUID_BATTERY: UUID = UUID::B16(0x2A19);
|
||||||
|
const UUID_MODEL: UUID = UUID::B16(0x2A24);
|
||||||
|
const UUID_SERIAL: UUID = UUID::B16(0x2A25);
|
||||||
const UUID_FIRMWARE: UUID = UUID::B16(0x2A26);
|
const UUID_FIRMWARE: UUID = UUID::B16(0x2A26);
|
||||||
|
const UUID_REVISION: UUID = UUID::B16(0x2A27);
|
||||||
|
const UUID_MANUFACTURER: UUID = UUID::B16(0x2A29);
|
||||||
const UUID_WRITE_SENSOR: UUID = UUID::B16(0x2A05);
|
const UUID_WRITE_SENSOR: UUID = UUID::B16(0x2A05);
|
||||||
|
const UUID_AUTH_INIT: UUID = UUID::B16(0x0010);
|
||||||
|
const UUID_AUTH: UUID = UUID::B16(0x0001);
|
||||||
|
const UUID_AUTH_VER: UUID = UUID::B16(0x0004);
|
||||||
|
|
||||||
struct Device<P: Peripheral> {
|
struct Device<P: Peripheral> {
|
||||||
peripheral: P,
|
peripheral: P,
|
||||||
|
|
@ -57,13 +79,14 @@ impl<P: Peripheral> Device<P> {
|
||||||
adapter.on_event(Box::new(move |ev| {
|
adapter.on_event(Box::new(move |ev| {
|
||||||
match ev {
|
match ev {
|
||||||
CentralEvent::DeviceDiscovered(discovered_mac) if mac == discovered_mac => {
|
CentralEvent::DeviceDiscovered(discovered_mac) if mac == discovered_mac => {
|
||||||
device_count_clone.store(true, Ordering::Relaxed);
|
// println!("discovered {}", discovered_mac);
|
||||||
|
// device_count_clone.store(true, Ordering::Relaxed);
|
||||||
}
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
};
|
};
|
||||||
}));
|
}));
|
||||||
|
|
||||||
for _ in 0..1500 {
|
for _ in 0..150 {
|
||||||
thread::sleep(Duration::from_millis(100));
|
thread::sleep(Duration::from_millis(100));
|
||||||
if found.load(Ordering::Relaxed) {
|
if found.load(Ordering::Relaxed) {
|
||||||
break;
|
break;
|
||||||
|
|
@ -74,10 +97,10 @@ impl<P: Peripheral> Device<P> {
|
||||||
|
|
||||||
match adapter.peripheral(mac) {
|
match adapter.peripheral(mac) {
|
||||||
Some(peripheral) => Ok(Device {
|
Some(peripheral) => Ok(Device {
|
||||||
peripheral,
|
peripheral: dbg!(peripheral),
|
||||||
connected: false,
|
connected: false,
|
||||||
}),
|
}),
|
||||||
None => Err(btleplug::Error::DeviceNotFound)
|
None => Err(btleplug::Error::DeviceNotFound),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -93,9 +116,10 @@ impl<P: Peripheral> Device<P> {
|
||||||
self.connected = true;
|
self.connected = true;
|
||||||
|
|
||||||
self.peripheral.discover_characteristics()?;
|
self.peripheral.discover_characteristics()?;
|
||||||
|
// dbg!(self.peripheral.characteristics());
|
||||||
return Ok(());
|
return Ok(());
|
||||||
},
|
}
|
||||||
Err(e) => eprintln!("{}", e)
|
Err(e) => eprintln!("{}", e),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -105,20 +129,107 @@ impl<P: Peripheral> Device<P> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_characteristic(&self, uuid: UUID) -> Option<Characteristic> {
|
fn get_characteristic(&self, uuid: UUID) -> Option<Characteristic> {
|
||||||
self.peripheral.characteristics().into_iter().find(|c| c.uuid == uuid)
|
self.peripheral
|
||||||
|
.characteristics()
|
||||||
|
.into_iter()
|
||||||
|
.find(|c| c.uuid == uuid)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_battery(&self) -> Result<u8, btleplug::Error> {
|
fn get_u8(&self, uuid: UUID) -> Result<u8, btleplug::Error> {
|
||||||
let bat = self.get_characteristic(UUID_BATTERY).unwrap();
|
let c = self.get_characteristic(uuid).unwrap();
|
||||||
let data = self.peripheral.read(&bat)?;
|
let data = self.peripheral.read(&c)?;
|
||||||
|
|
||||||
Ok(data[1])
|
Ok(data[1])
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_firmware(&self) -> Result<String, btleplug::Error> {
|
fn get_u16(&self, uuid: UUID) -> Result<u16, btleplug::Error> {
|
||||||
let bat = self.get_characteristic(UUID_FIRMWARE).unwrap();
|
let c = self.get_characteristic(uuid).unwrap();
|
||||||
let data = self.peripheral.read(&bat)?;
|
let data = self.peripheral.read(&c)?;
|
||||||
|
dbg!(&data);
|
||||||
|
|
||||||
|
Ok(u16::from_le_bytes([data[1], data[2]]))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_battery(&self) -> Result<u8, btleplug::Error> {
|
||||||
|
self.get_u8(UUID_BATTERY)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_string(&self, uuid: UUID) -> Result<String, btleplug::Error> {
|
||||||
|
let c = self.get_characteristic(uuid).unwrap();
|
||||||
|
let data = self.peripheral.read(&c)?;
|
||||||
let data = data[1..].to_vec();
|
let data = data[1..].to_vec();
|
||||||
Ok(String::from_utf8(data).unwrap())
|
Ok(String::from_utf8(data).unwrap())
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
pub fn get_firmware(&self) -> Result<String, btleplug::Error> {
|
||||||
|
self.get_string(UUID_FIRMWARE)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_name(&self) -> Result<String, btleplug::Error> {
|
||||||
|
self.get_string(UUID_DEVICE_NAME)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn auth(&self, token: [u8; 12]) -> Result<(), btleplug::Error> {
|
||||||
|
dbg!("auth");
|
||||||
|
dbg!(self.peripheral.request(
|
||||||
|
&self.get_characteristic(UUID_AUTH_INIT).unwrap(),
|
||||||
|
// &[0x90, 0xCA, 0x85, 0xDE],
|
||||||
|
&[0x90, 0xCA, 0x85, 0xDE],
|
||||||
|
));
|
||||||
|
|
||||||
|
let (auth_in, auth_out) = channel();
|
||||||
|
self.peripheral
|
||||||
|
.subscribe(&self.get_characteristic(UUID_AUTH).unwrap())?;
|
||||||
|
self.peripheral
|
||||||
|
.on_notification(Box::new(move |notification| {
|
||||||
|
dbg!(notification.uuid);
|
||||||
|
if notification.uuid == UUID_AUTH {
|
||||||
|
auth_in.send(notification.value).unwrap();
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
|
||||||
|
let mac = self.peripheral.address().address;
|
||||||
|
let device_id = 426;
|
||||||
|
// let device_id = 131;
|
||||||
|
let data = cipher::cipher(&cipher::mix_a(mac, device_id), &token);
|
||||||
|
self.peripheral
|
||||||
|
.request(&self.get_characteristic(UUID_AUTH).unwrap(), &data);
|
||||||
|
|
||||||
|
let auth_response = auth_out.recv().unwrap();
|
||||||
|
let verify = cipher::cipher(
|
||||||
|
&cipher::mix_b(mac, device_id),
|
||||||
|
&cipher::cipher(&cipher::mix_a(mac, device_id), &auth_response),
|
||||||
|
);
|
||||||
|
assert_eq!(&token, verify.as_slice());
|
||||||
|
// dbg!(self.peripheral.command(
|
||||||
|
// &self.get_characteristic(UUID_AUTH).unwrap(),
|
||||||
|
// &[0x92, 0xAB, 0x54, 0xFA],
|
||||||
|
// ));
|
||||||
|
dbg!(self.peripheral.request(
|
||||||
|
&self.get_characteristic(UUID_AUTH).unwrap(),
|
||||||
|
&[0x92, 0xAB, 0x54, 0xFA],
|
||||||
|
));
|
||||||
|
|
||||||
|
dbg!(&self
|
||||||
|
.peripheral
|
||||||
|
.read(&self.get_characteristic(UUID_AUTH_VER).unwrap())?);
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn listen(&self, callback: impl Fn() -> ()) -> Result<(), btleplug::Error> {
|
||||||
|
let uuid = UUID::from_str("22:6C:AA:55:64:76:45:66:75:62:66:73:44:70:66:6D").unwrap();
|
||||||
|
let sensor = self.get_characteristic(uuid).unwrap();
|
||||||
|
eprintln!("sub");
|
||||||
|
self.peripheral.subscribe(&sensor)?;
|
||||||
|
eprintln!("notify");
|
||||||
|
self.peripheral.on_notification(Box::new(|notification| {
|
||||||
|
dbg!(String::from_utf8(notification.value).unwrap());
|
||||||
|
}));
|
||||||
|
loop {
|
||||||
|
eprintln!("sleep");
|
||||||
|
thread::sleep(Duration::from_millis(5000));
|
||||||
|
dbg!(self.get_battery());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue