diff --git a/src/desfire/desfire.rs b/src/desfire/desfire.rs index 3abca30..53cdc4b 100644 --- a/src/desfire/desfire.rs +++ b/src/desfire/desfire.rs @@ -11,7 +11,6 @@ use crate::crypto::util::expand_to_blocksize; use crate::desfire::{FileCommunication, ChangeMasterKeySettings, CreateDeleteFile, FileDirectoryAccess, ChangeMasterKey, ChangeApplicationKey, CryptoOperationsType, FileIdentifiers}; use crate::iso7816_4::apduresponse::APDUResponse; use num_traits::FromPrimitive; -use std::fs::read_to_string; pub struct Desfire { card: Box, @@ -81,6 +80,8 @@ impl Desfire { rnd_b_rl.rotate_left(1); println!("RND_B_RL: {:x?}", rnd_b_rl); + //FIXME: This is ugly, we should find a better way to make the function testable + //TODO: Check if we need a CSPRNG here let rnd_a = match rnd_a { None => { rand::random() } Some(i) => { i } @@ -169,6 +170,8 @@ impl Desfire { rnd_b_rl.rotate_left(1); println!("RND_B_RL: {:x?}", rnd_b_rl); + //FIXME: This is ugly, we should find a better way to make the function testable + //TODO: Check if we need a CSPRNG here let rnd_a = match rnd_a { None => { rand::random() } Some(i) => { i } @@ -425,6 +428,8 @@ impl Desfire { return Err(InvalidFileID); } + println!("Writing data to file {}", file_id); + const MAX_BYTES_PER_TRANSACTION: usize = 47; let mut bytes_writen: usize = 0; let length: usize = data.len(); @@ -438,11 +443,14 @@ impl Desfire { }; let mut write_buffer = vec![file_id]; - write_buffer.append(&mut offset.to_le_bytes()[..3].to_vec()); + write_buffer.append(&mut (offset as usize + bytes_writen).to_le_bytes()[..3].to_vec()); write_buffer.append(&mut bytes_towrite.to_le_bytes()[..3].to_vec()); write_buffer.append(&mut data[bytes_writen..bytes_writen + bytes_towrite].to_vec()); bytes_writen += bytes_towrite; + println!("WRITE_BUFFER: {:x?}", write_buffer); + println!("BYTES_WRITEN: {}", bytes_writen); + let cmd_write_data = APDUCommand { case: IsoCase::Case4Short, cla: 0x90, @@ -450,8 +458,10 @@ impl Desfire { data: Option::from(write_buffer), ..Default::default() }; + println!("CMD_WRITE_DATA: {}", cmd_write_data); let response = self.card.transmit(cmd_write_data).unwrap(); + println!("RESPONSE: {}", response); ret = response.check(); }; @@ -482,7 +492,7 @@ impl Desfire { }; let mut send_buffer = vec![file_id]; - send_buffer.append(&mut offset.to_le_bytes()[..3].to_vec()); + send_buffer.append(&mut (offset as usize + bytes_read).to_le_bytes()[..3].to_vec()); send_buffer.append(&mut bytes_toread.to_le_bytes()[..3].to_vec()); bytes_read += bytes_toread; @@ -493,8 +503,10 @@ impl Desfire { data: Option::from(send_buffer), ..Default::default() }; + println!("CMD_READ_DATA: {}", cmd_read_data); let response = self.card.transmit(cmd_read_data).unwrap(); + println!("RESPONSE: {}", response); response.check().or_else(|e| return Err(e)); @@ -785,7 +797,7 @@ mod tests { return; } }; - + let mut card = PCSCCard { ctx, reader: CString::from(reader), @@ -1114,4 +1126,151 @@ mod tests { let access_rights = generate_file_access_rights(FileAccessRights::FREE as u8, 0x00, 0x00, 0x00).unwrap(); desfire.create_file_standard(0xFF, FileCommunication::PLAIN, access_rights, 0xF0).unwrap(); } + + #[test] + fn write_data() { + let mut mock = MockVirtualCard::new(); + mock.expect_transmit().withf(|x: &APDUCommand| (Vec::::try_from(x.clone()).unwrap()) == hex!("903d00000f01000000080000546573743132333400")).return_once(move |_| Ok(APDUResponse { + sw1: 0x91, + sw2: 0x00, + body: None + })); + + let mut desfire = Desfire { + card: Box::new(mock), + cbc_iv: None, + session_key: None + }; + + let data = "Test1234".as_bytes(); + assert!(desfire.write_data(0x01, 0x00, data.as_ref()).is_ok()); + } + + #[test] + fn write_data_long() { + let mut mock = MockVirtualCard::new(); + mock.expect_transmit().withf(|x: &APDUCommand| (Vec::::try_from(x.clone()).unwrap()) == hex!("903d000036010000002f0000546573743132333454657374313233345465737431323334546573743132333454657374313233345465737431323300")).return_once(move |_| Ok(APDUResponse { + sw1: 0x91, + sw2: 0x00, + body: None + })); + + mock.expect_transmit().withf(|x: &APDUCommand| (Vec::::try_from(x.clone()).unwrap()) == hex!("903d000036012f00002f0000345465737431323334546573743132333454657374313233345465737431323334546573743132333454657374313200")).return_once(move |_| Ok(APDUResponse { + sw1: 0x91, + sw2: 0x00, + body: None + })); + + mock.expect_transmit().withf(|x: &APDUCommand| (Vec::::try_from(x.clone()).unwrap()) == hex!("903d000019015e000012000033345465737431323334546573743132333400")).return_once(move |_| Ok(APDUResponse { + sw1: 0x91, + sw2: 0x00, + body: None + })); + + let mut desfire = Desfire { + card: Box::new(mock), + cbc_iv: None, + session_key: None + }; + + let data = "Test1234Test1234Test1234Test1234Test1234Test1234Test1234Test1234Test1234Test1234Test1234Test1234Test1234Test1234".as_bytes(); + assert!(desfire.write_data(0x01, 0x00, data.as_ref()).is_ok()); + } + + #[test] + #[should_panic(expected = "InvalidFileID")] + fn write_data_invalid_file_id() { + let mut mock = MockVirtualCard::new(); + + let mut desfire = Desfire { + card: Box::new(mock), + cbc_iv: None, + session_key: None + }; + + desfire.write_data(0xFF, 0x00, &[0 as u8; 1]).unwrap(); + } + + #[test] + fn read_data() { + let mut mock = MockVirtualCard::new(); + mock.expect_transmit().withf(|x: &APDUCommand| (Vec::::try_from(x.clone()).unwrap()) == hex!("90bd0000070100000020000000")).return_once(move |_| Ok(APDUResponse { + sw1: 0x91, + sw2: 0x00, + body: Some(hex!("54657374313233340000000000000000000000000000000000000000000000009100").to_vec()) + })); + + let mut desfire = Desfire { + card: Box::new(mock), + cbc_iv: None, + session_key: None + }; + + let data = desfire.read_data(0x01, 0x00, 0x20).unwrap(); + assert_eq!("Test1234", String::from_utf8(data).unwrap().replace("\0", "")); + } + + #[test] + fn read_data_cmac() { + let mut mock = MockVirtualCard::new(); + mock.expect_transmit().withf(|x: &APDUCommand| (Vec::::try_from(x.clone()).unwrap()) == hex!("90bd0000070100000020000000")).return_once(move |_| Ok(APDUResponse { + sw1: 0x91, + sw2: 0x00, + body: Some(hex!("5465737431323334000000000000000000000000000000000000000000000000809a9bedbc559a5b9100").to_vec()) + })); + + let mut desfire = Desfire { + card: Box::new(mock), + cbc_iv: None, + session_key: None + }; + + let data = desfire.read_data(0x01, 0x00, 0x20).unwrap(); + assert_eq!("Test1234", String::from_utf8(data).unwrap().replace("\0", "")); + } + + #[test] + fn read_data_long() { + let mut mock = MockVirtualCard::new(); + mock.expect_transmit().withf(|x: &APDUCommand| (Vec::::try_from(x.clone()).unwrap()) == hex!("90bd000007010000002f000000")).return_once(move |_| Ok(APDUResponse { + sw1: 0x91, + sw2: 0x00, + body: Some(hex!("54657374313233340000000000000000000000000000000000000000000000000000000000000000000000000000009100").to_vec()) + })); + + mock.expect_transmit().withf(|x: &APDUCommand| (Vec::::try_from(x.clone()).unwrap()) == hex!("90bd000007012f00002f000000")).return_once(move |_| Ok(APDUResponse { + sw1: 0x91, + sw2: 0x00, + body: Some(hex!("00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000009100").to_vec()) + })); + + mock.expect_transmit().withf(|x: &APDUCommand| (Vec::::try_from(x.clone()).unwrap()) == hex!("90bd000007015e000002000000")).return_once(move |_| Ok(APDUResponse { + sw1: 0x91, + sw2: 0x00, + body: Some(hex!("00009100").to_vec()) + })); + + let mut desfire = Desfire { + card: Box::new(mock), + cbc_iv: None, + session_key: None + }; + + let data = desfire.read_data(0x01, 0x00, 0x60).unwrap(); + assert_eq!("Test1234", String::from_utf8(data).unwrap().replace("\0", "")); + } + + #[test] + #[should_panic(expected = "InvalidFileID")] + fn read_data_invalid_file_id() { + let mut mock = MockVirtualCard::new(); + + let mut desfire = Desfire { + card: Box::new(mock), + cbc_iv: None, + session_key: None + }; + + desfire.read_data(0xFF, 0x00, 0x20).unwrap(); + } } \ No newline at end of file