diff --git a/minidisc-rs/Cargo.toml b/minidisc-rs/Cargo.toml index ec10556..3301d11 100644 --- a/minidisc-rs/Cargo.toml +++ b/minidisc-rs/Cargo.toml @@ -25,7 +25,9 @@ regex = "1.10.2" lazy_static = "1.4.0" nusb = "0.1.4" futures-lite = "2.2.0" - +num-derive = "0.3.3" +num-traits = "0.2.14" +rand = "0.8.5" [lib] crate-type = ["cdylib", "rlib"] diff --git a/minidisc-rs/src/netmd/commands.rs b/minidisc-rs/src/netmd/commands.rs new file mode 100644 index 0000000..1913e8f --- /dev/null +++ b/minidisc-rs/src/netmd/commands.rs @@ -0,0 +1,77 @@ +use std::{error::Error, thread::sleep, time::Duration}; +use num_derive::FromPrimitive; +use num_traits::FromPrimitive; + +use super::interface::{NetMDInterface, MDTrack}; + +#[derive(FromPrimitive)] +#[derive(PartialEq)] +pub enum OperatingStatus{ + Ready = 50687, + Playing = 50037, + Paused = 50045, + FastForward = 49983, + Rewind = 49999, + ReadingTOC = 65315, + NoDisc = 65296, + DiscBlank = 65535, + ReadyForTransfer = 65319, +} + +pub struct Time { + minute: u16, + second: u16, + frame: u16, +} + +pub struct DeviceStatus { + disc_present: bool, + state: Option, + track: u8, + time: Time, +} + +pub fn device_status(interface: &mut NetMDInterface) -> Result> { + let status = interface.status()?; + let playback_status = interface.playback_status2()?; + let b1: u16 = playback_status[4] as u16; + let b2: u16 = playback_status[5] as u16; + let position = interface.position()?; + let operating_status = b1 << 8 | b2; + + let track = position[0] as u8; + let disc_present = status[4] != 0x80; + let mut state: Option = FromPrimitive::from_u16(operating_status); + + if state == Some(OperatingStatus::Playing) && !disc_present { + state = Some(OperatingStatus::Ready); + } + + let time = Time{ + minute: position[2], + second: position[3], + frame: position[4], + }; + + Ok(DeviceStatus { disc_present, state, track, time }) +} + +pub fn prepare_download(interface: &mut NetMDInterface) -> Result<(), Box>{ + while ![OperatingStatus::DiscBlank, OperatingStatus::Ready].contains(&device_status(interface)?.state.or(Some(OperatingStatus::NoDisc)).unwrap()) { + sleep(Duration::from_millis(200)); + } + + let _ = interface.session_key_forget(); + let _ = interface.leave_secure_session(); + + interface.acquire()?; + let _ = interface.disable_new_track_protection(1); + + Ok(()) +} + +pub fn download(interface: &mut NetMDInterface, track: MDTrack) -> Result<(), Box>{ + prepare_download(interface)?; + + Ok(()) +} \ No newline at end of file diff --git a/minidisc-rs/src/netmd/interface.rs b/minidisc-rs/src/netmd/interface.rs index a168f0d..80e8e28 100644 --- a/minidisc-rs/src/netmd/interface.rs +++ b/minidisc-rs/src/netmd/interface.rs @@ -7,6 +7,7 @@ use crate::netmd::utils::{ use encoding_rs::*; use hex; use magic_crypt::{new_magic_crypt, MagicCrypt, MagicCryptTrait, SecureBit}; +use rand::RngCore; use std::collections::HashMap; use std::error::Error; @@ -442,7 +443,7 @@ impl NetMDInterface { Ok(()) } - fn acquire(&mut self) -> Result<(), Box> { + pub fn acquire(&mut self) -> Result<(), Box> { let mut query = format_query("ff 010c ffff ffff ffff ffff ffff ffff".to_string(), vec![])?; let reply = self.send_query(&mut query, false, false)?; @@ -451,7 +452,7 @@ impl NetMDInterface { Ok(()) } - fn release(&mut self) -> Result<(), Box> { + pub fn release(&mut self) -> Result<(), Box> { let mut query = format_query("ff 0100 ffff ffff ffff ffff ffff ffff".to_string(), vec![])?; let reply = self.send_query(&mut query, false, false)?; @@ -1341,9 +1342,9 @@ impl NetMDInterface { pub fn send_key_data( &mut self, ekbid: i32, - keychain: Vec<[u8; 16]>, + keychain: [[u8; 16]; 2], depth: i32, - ekbsignature: Vec, + ekbsignature: [u8; 24], ) -> Result, Box> { let chainlen = keychain.len(); let databytes = 16 + 16 * chainlen + 24; @@ -1366,7 +1367,7 @@ impl NetMDInterface { QueryValue::Number(depth as i64), QueryValue::Number(ekbid as i64), QueryValue::Array(keychains), - QueryValue::Array(ekbsignature), + QueryValue::Array(ekbsignature.to_vec()), ], )?; @@ -1581,39 +1582,43 @@ lazy_static! { ]); } -struct EKBOpenSource {} +pub struct EKBData { + chains: [[u8; 16]; 2], + depth: i32, + signature: [u8; 24], +} + +pub struct EKBOpenSource {} impl EKBOpenSource { - fn root_key(&mut self) -> [u8; 16] { + pub fn root_key(&self) -> [u8; 16] { [ 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x0f, 0xed, 0xcb, 0xa9, 0x87, 0x65, 0x43, 0x21, ] } - fn ekb_id(&mut self) -> i32 { + pub fn ekb_id(&self) -> i32 { 0x26422642 } - /* What's this for? - ekb_data_for_leaf_id(): [Uint8Array[], number, Uint8Array] { - return [ - [ - new Uint8Array([0x25, 0x45, 0x06, 0x4d, 0xea, 0xca, 0x14, 0xf9, 0x96, 0xbd, 0xc8, 0xa4, 0x06, 0xc2, 0x2b, 0x81]), - new Uint8Array([0xfb, 0x60, 0xbd, 0xdd, 0x0d, 0xbc, 0xab, 0x84, 0x8a, 0x00, 0x5e, 0x03, 0x19, 0x4d, 0x3e, 0xda]), + pub fn ekb_data_for_leaf_id(&self) -> EKBData { + EKBData { + chains: [ + [0x25, 0x45, 0x06, 0x4d, 0xea, 0xca, 0x14, 0xf9, 0x96, 0xbd, 0xc8, 0xa4, 0x06, 0xc2, 0x2b, 0x81], + [0xfb, 0x60, 0xbd, 0xdd, 0x0d, 0xbc, 0xab, 0x84, 0x8a, 0x00, 0x5e, 0x03, 0x19, 0x4d, 0x3e, 0xda], ], - 9, - new Uint8Array([ + depth: 9, + signature: [ 0x8f, 0x2b, 0xc3, 0x52, 0xe8, 0x6c, 0x5e, 0xd3, 0x06, 0xdc, 0xae, 0x18, - 0xd2, 0xf3, 0x8c, 0x7f, 0x89, 0xb5, 0xe1, 0x85, 0x55, 0xa1, 0x05, 0xea - ]) - ]; + 0xd2, 0xf3, 0x8c, 0x7f, 0x89, 0xb5, 0xe1, 0x85, 0x55, 0xa1, 0x05, 0xea, + ], + } } - */ } #[derive(Clone)] -struct MDTrack { +pub struct MDTrack { title: String, format: WireFormat, data: Vec, @@ -1623,7 +1628,7 @@ struct MDTrack { } #[derive(Clone)] -struct EncryptPacketsIterator { +pub struct EncryptPacketsIterator { kek: Vec, frame_size: i32, data: Vec, @@ -1675,3 +1680,24 @@ impl MDTrack { [0x14, 0xe3, 0x83, 0x4e, 0xe2, 0xd3, 0xcc, 0xa5] } } + +pub struct MDSession { + md: NetMDInterface, + ekb_object: EKBOpenSource, + hex_session_key: String, +} + +impl MDSession { + pub fn init(&mut self) -> Result<(), Box>{ + self.md.enter_secure_session()?; + self.md.leaf_id()?; + + let ekb = self.ekb_object.ekb_data_for_leaf_id(); + self.md.send_key_data(self.ekb_object.ekb_id(), ekb.chains, ekb.depth, ekb.signature)?; + let mut nonce = vec![0u8, 8]; + rand::thread_rng().fill_bytes(&mut nonce); + + // TODO + Ok(()) + } +} \ No newline at end of file diff --git a/minidisc-rs/src/netmd/mod.rs b/minidisc-rs/src/netmd/mod.rs index af8d317..a8450ea 100644 --- a/minidisc-rs/src/netmd/mod.rs +++ b/minidisc-rs/src/netmd/mod.rs @@ -9,3 +9,4 @@ pub mod interface; mod query_utils; mod utils; mod mappings; +mod commands;