Buttplug sex toy control library
at dev 5.1 kB view raw
1// Buttplug Rust Source Code File - See https://buttplug.io for more info. 2// 3// Copyright 2016-2024 Nonpolynomial Labs LLC. All rights reserved. 4// 5// Licensed under the BSD 3-Clause license. See LICENSE file in the project root 6// for full license information. 7 8use crate::device::{ 9 hardware::{Hardware, HardwareCommand, HardwareEvent, HardwareSubscribeCmd, HardwareWriteCmd}, 10 protocol::{ 11 ProtocolHandler, 12 ProtocolIdentifier, 13 ProtocolInitializer, 14 generic_protocol_initializer_setup, 15 }, 16}; 17use aes::Aes128; 18use async_trait::async_trait; 19use buttplug_core::errors::ButtplugDeviceError; 20use buttplug_server_device_config::Endpoint; 21use buttplug_server_device_config::{ 22 ProtocolCommunicationSpecifier, 23 ServerDeviceDefinition, 24 UserDeviceIdentifier, 25}; 26use ecb::cipher::block_padding::Pkcs7; 27use ecb::cipher::{BlockDecryptMut, BlockEncryptMut, KeyInit}; 28use std::sync::{ 29 Arc, 30 atomic::{AtomicU8, Ordering}, 31}; 32use uuid::{Uuid, uuid}; 33 34use rand::distributions::Alphanumeric; 35use rand::{Rng, thread_rng}; 36use regex::Regex; 37use sha2::{Digest, Sha256}; 38 39type Aes128EcbEnc = ecb::Encryptor<Aes128>; 40type Aes128EcbDec = ecb::Decryptor<Aes128>; 41 42const VIBCRAFTER_PROTOCOL_UUID: Uuid = uuid!("d3721a71-a81d-461a-b404-8599ce50c00b"); 43const VIBCRAFTER_KEY: [u8; 16] = *b"jdk#Cra%f5Vib28r"; 44 45generic_protocol_initializer_setup!(VibCrafter, "vibcrafter"); 46 47#[derive(Default)] 48pub struct VibCrafterInitializer {} 49 50fn encrypt(command: String) -> Vec<u8> { 51 let enc = Aes128EcbEnc::new(&VIBCRAFTER_KEY.into()); 52 let res = enc.encrypt_padded_vec_mut::<Pkcs7>(command.as_bytes()); 53 54 info!("Encoded {} to {:?}", command, res); 55 res 56} 57 58fn decrypt(data: Vec<u8>) -> String { 59 let dec = Aes128EcbDec::new(&VIBCRAFTER_KEY.into()); 60 let res = String::from_utf8(dec.decrypt_padded_vec_mut::<Pkcs7>(&data).unwrap()).unwrap(); 61 62 info!("Decoded {} from {:?}", res, data); 63 res 64} 65 66#[async_trait] 67impl ProtocolInitializer for VibCrafterInitializer { 68 async fn initialize( 69 &mut self, 70 hardware: Arc<Hardware>, 71 _: &ServerDeviceDefinition, 72 ) -> Result<Arc<dyn ProtocolHandler>, ButtplugDeviceError> { 73 let mut event_receiver = hardware.event_stream(); 74 hardware 75 .subscribe(&HardwareSubscribeCmd::new( 76 VIBCRAFTER_PROTOCOL_UUID, 77 Endpoint::Rx, 78 )) 79 .await?; 80 81 let auth_str = thread_rng() 82 .sample_iter(&Alphanumeric) 83 .take(6) 84 .map(char::from) 85 .collect::<String>(); 86 let auth_msg = format!("Auth:{};", auth_str); 87 hardware 88 .write_value(&HardwareWriteCmd::new( 89 &[VIBCRAFTER_PROTOCOL_UUID], 90 Endpoint::Tx, 91 encrypt(auth_msg), 92 false, 93 )) 94 .await?; 95 96 loop { 97 let event = event_receiver.recv().await; 98 if let Ok(HardwareEvent::Notification(_, _, n)) = event { 99 let decoded = decrypt(n); 100 if decoded.eq("OK;") { 101 debug!("VibCrafter authenticated!"); 102 return Ok(Arc::new(VibCrafter::default())); 103 } 104 let challenge = Regex::new(r"^[a-zA-Z0-9]{4}:([a-zA-Z0-9]+);$") 105 .expect("This is static and should always compile"); 106 if let Some(parts) = challenge.captures(decoded.as_str()) { 107 debug!("VibCrafter challenge {:?}", parts); 108 if let Some(to_hash) = parts.get(1) { 109 debug!("VibCrafter to hash {:?}", to_hash); 110 let mut sha256 = Sha256::new(); 111 sha256.update(to_hash.as_str().as_bytes()); 112 let result = &sha256.finalize(); 113 114 let auth_msg = format!("Auth:{:02x}{:02x};", result[0], result[1]); 115 hardware 116 .write_value(&HardwareWriteCmd::new( 117 &[VIBCRAFTER_PROTOCOL_UUID], 118 Endpoint::Tx, 119 encrypt(auth_msg), 120 false, 121 )) 122 .await?; 123 } else { 124 return Err(ButtplugDeviceError::ProtocolSpecificError( 125 "VibCrafter".to_owned(), 126 "VibCrafter didn't provide a valid security handshake".to_owned(), 127 )); 128 } 129 } else { 130 return Err(ButtplugDeviceError::ProtocolSpecificError( 131 "VibCrafter".to_owned(), 132 "VibCrafter didn't provide a valid security handshake".to_owned(), 133 )); 134 } 135 } else { 136 return Err(ButtplugDeviceError::ProtocolSpecificError( 137 "VibCrafter".to_owned(), 138 "VibCrafter didn't provide a valid security handshake".to_owned(), 139 )); 140 } 141 } 142 } 143} 144 145#[derive(Default)] 146pub struct VibCrafter { 147 speeds: [AtomicU8; 2], 148} 149 150impl ProtocolHandler for VibCrafter { 151 fn handle_output_vibrate_cmd( 152 &self, 153 feature_index: u32, 154 feature_id: uuid::Uuid, 155 speed: u32, 156 ) -> Result<Vec<HardwareCommand>, ButtplugDeviceError> { 157 self.speeds[feature_index as usize].store(speed as u8, Ordering::Relaxed); 158 159 Ok(vec![ 160 HardwareWriteCmd::new( 161 &[feature_id], 162 Endpoint::Tx, 163 encrypt(format!( 164 "MtInt:{:02}{:02};", 165 self.speeds[0].load(Ordering::Relaxed), 166 self.speeds[1].load(Ordering::Relaxed) 167 )), 168 false, 169 ) 170 .into(), 171 ]) 172 } 173}