diff --git a/.idea/dictionaries/project.xml b/.idea/dictionaries/project.xml index 6baf2b5..9bd757b 100644 --- a/.idea/dictionaries/project.xml +++ b/.idea/dictionaries/project.xml @@ -5,6 +5,7 @@ felica gpst trng + wcnt \ No newline at end of file diff --git a/pn532/src/commands.rs b/pn532/src/commands.rs deleted file mode 100644 index 8a0670e..0000000 --- a/pn532/src/commands.rs +++ /dev/null @@ -1,147 +0,0 @@ -//! Command and protocol constants for the PN532. - -// PN532 commands. -pub const PN532_COMMAND_DIAGNOSE: u8 = 0x00; -pub const PN532_COMMAND_GETFIRMWAREVERSION: u8 = 0x02; -pub const PN532_COMMAND_GETGENERALSTATUS: u8 = 0x04; -pub const PN532_COMMAND_READREGISTER: u8 = 0x06; -pub const PN532_COMMAND_WRITEREGISTER: u8 = 0x08; -pub const PN532_COMMAND_READGPIO: u8 = 0x0C; -pub const PN532_COMMAND_WRITEGPIO: u8 = 0x0E; -pub const PN532_COMMAND_SETSERIALBAUDRATE: u8 = 0x10; -pub const PN532_COMMAND_SETPARAMETERS: u8 = 0x12; -pub const PN532_COMMAND_SAMCONFIGURATION: u8 = 0x14; -pub const PN532_COMMAND_POWERDOWN: u8 = 0x16; -pub const PN532_COMMAND_RFCONFIGURATION: u8 = 0x32; -pub const PN532_COMMAND_RFREGULATIONTEST: u8 = 0x58; -pub const PN532_COMMAND_INJUMPFORDEP: u8 = 0x56; -pub const PN532_COMMAND_INJUMPFORPSL: u8 = 0x46; -pub const PN532_COMMAND_INLISTPASSIVETARGET: u8 = 0x4A; -pub const PN532_COMMAND_INATR: u8 = 0x50; -pub const PN532_COMMAND_INPSL: u8 = 0x4E; -pub const PN532_COMMAND_INDATAEXCHANGE: u8 = 0x40; -pub const PN532_COMMAND_INCOMMUNICATETHRU: u8 = 0x42; -pub const PN532_COMMAND_INDESELECT: u8 = 0x44; -pub const PN532_COMMAND_INRELEASE: u8 = 0x52; -pub const PN532_COMMAND_INSELECT: u8 = 0x54; -pub const PN532_COMMAND_INAUTOPOLL: u8 = 0x60; -pub const PN532_COMMAND_TGINITASTARGET: u8 = 0x8C; -pub const PN532_COMMAND_TGSETGENERALBYTES: u8 = 0x92; -pub const PN532_COMMAND_TGGETDATA: u8 = 0x86; -pub const PN532_COMMAND_TGSETDATA: u8 = 0x8E; -pub const PN532_COMMAND_TGSETMETADATA: u8 = 0x94; -pub const PN532_COMMAND_TGGETINITIATORCOMMAND: u8 = 0x88; -pub const PN532_COMMAND_TGRESPONSETOINITIATOR: u8 = 0x90; -pub const PN532_COMMAND_TGGETTARGETSTATUS: u8 = 0x8A; - -pub const PN532_RESPONSE_INDATAEXCHANGE: u8 = 0x41; -pub const PN532_RESPONSE_INLISTPASSIVETARGET: u8 = 0x4B; - -pub const PN532_MIFARE_ISO14443A: u8 = 0x00; - -// Mifare commands. -pub const MIFARE_CMD_AUTH_A: u8 = 0x60; -pub const MIFARE_CMD_AUTH_B: u8 = 0x61; -pub const MIFARE_CMD_READ: u8 = 0x30; -pub const MIFARE_CMD_WRITE: u8 = 0xA0; -pub const MIFARE_CMD_WRITE_ULTRALIGHT: u8 = 0xA2; -pub const MIFARE_CMD_TRANSFER: u8 = 0xB0; -pub const MIFARE_CMD_DECREMENT: u8 = 0xC0; -pub const MIFARE_CMD_INCREMENT: u8 = 0xC1; -pub const MIFARE_CMD_STORE: u8 = 0xC2; - -// FeliCa commands. -pub const FELICA_CMD_POLLING: u8 = 0x00; -pub const FELICA_CMD_REQUEST_SERVICE: u8 = 0x02; -pub const FELICA_CMD_REQUEST_RESPONSE: u8 = 0x04; -pub const FELICA_CMD_READ_WITHOUT_ENCRYPTION: u8 = 0x06; -pub const FELICA_CMD_WRITE_WITHOUT_ENCRYPTION: u8 = 0x08; -pub const FELICA_CMD_REQUEST_SYSTEM_CODE: u8 = 0x0C; - -/// NDEF URI record identifier codes (see NFC Forum "URI Record Type Definition"). -pub mod ndef { - pub const NONE: u8 = 0x00; - pub const HTTP_WWWDOT: u8 = 0x01; - pub const HTTPS_WWWDOT: u8 = 0x02; - pub const HTTP: u8 = 0x03; - pub const HTTPS: u8 = 0x04; - pub const TEL: u8 = 0x05; - pub const MAILTO: u8 = 0x06; - pub const FTP_ANONAT: u8 = 0x07; - pub const FTP_FTPDOT: u8 = 0x08; - pub const FTPS: u8 = 0x09; - pub const SFTP: u8 = 0x0A; - pub const SMB: u8 = 0x0B; - pub const NFS: u8 = 0x0C; - pub const FTP: u8 = 0x0D; - pub const DAV: u8 = 0x0E; - pub const NEWS: u8 = 0x0F; - pub const TELNET: u8 = 0x10; - pub const IMAP: u8 = 0x11; - pub const RTSP: u8 = 0x12; - pub const URN: u8 = 0x13; - pub const POP: u8 = 0x14; - pub const SIP: u8 = 0x15; - pub const SIPS: u8 = 0x16; - pub const TFTP: u8 = 0x17; - pub const BTSPP: u8 = 0x18; - pub const BTL2CAP: u8 = 0x19; - pub const BTGOEP: u8 = 0x1A; - pub const TCPOBEX: u8 = 0x1B; - pub const IRDAOBEX: u8 = 0x1C; - pub const FILE: u8 = 0x1D; - pub const URN_EPC_ID: u8 = 0x1E; - pub const URN_EPC_TAG: u8 = 0x1F; - pub const URN_EPC_PAT: u8 = 0x20; - pub const URN_EPC_RAW: u8 = 0x21; - pub const URN_EPC: u8 = 0x22; - pub const URN_NFC: u8 = 0x23; -} - -// GPIO. -pub const PN532_GPIO_VALIDATIONBIT: u8 = 0x80; -pub const PN532_GPIO_P30: u8 = 0; -pub const PN532_GPIO_P31: u8 = 1; -pub const PN532_GPIO_P32: u8 = 2; -pub const PN532_GPIO_P33: u8 = 3; -pub const PN532_GPIO_P34: u8 = 4; -pub const PN532_GPIO_P35: u8 = 5; - -pub const FELICA_READ_MAX_SERVICE_NUM: usize = 3; -pub const FELICA_READ_MAX_BLOCK_NUM: usize = 3; - -pub const FELICA_WRITE_MAX_SERVICE_NUM: usize = 3; -pub const FELICA_WRITE_MAX_BLOCK_NUM: usize = 3; - -pub const FELICA_REQ_SERVICE_MAX_NODE_NUM: usize = 32; - -// Frame protocol constants. -pub const PN532_PREAMBLE: u8 = 0x00; -pub const PN532_STARTCODE1: u8 = 0x00; -pub const PN532_STARTCODE2: u8 = 0xFF; -pub const PN532_POSTAMBLE: u8 = 0x00; - -pub const PN532_HOST_TO_PN532: u8 = 0xD4; -pub const PN532_PN532_TO_HOST: u8 = 0xD5; - -pub const PN532_ACK_WAIT_TIME_MS: u16 = 10; - -/// The fixed 7-bit I2C address of the PN532 (0x48 >> 1). -pub const PN532_I2C_ADDRESS: u8 = 0x48 >> 1; - -/// Passive target baud rates supported by [`crate::Pn532::read_passive_target_id`]. -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -#[repr(u8)] -pub enum BaudRate { - ISO14443A106kbps = 0x00, - Felica212kbps = 0x01, - Felica424kbps = 0x02, - ISO14443B106kbps = 0x03, - InnovisionJewel106kbps = 0x04, -} - -impl From for u8 { - fn from(value: BaudRate) -> Self { - value as u8 - } -} diff --git a/pn532/src/commands/mifare.rs b/pn532/src/commands/mifare.rs new file mode 100644 index 0000000..06600b4 --- /dev/null +++ b/pn532/src/commands/mifare.rs @@ -0,0 +1,10 @@ +// Mifare commands. +pub const MIFARE_CMD_AUTH_A: u8 = 0x60; +pub const MIFARE_CMD_AUTH_B: u8 = 0x61; +pub const MIFARE_CMD_READ: u8 = 0x30; +pub const MIFARE_CMD_WRITE: u8 = 0xA0; +pub const MIFARE_CMD_WRITE_ULTRALIGHT: u8 = 0xA2; +pub const MIFARE_CMD_TRANSFER: u8 = 0xB0; +pub const MIFARE_CMD_DECREMENT: u8 = 0xC0; +pub const MIFARE_CMD_INCREMENT: u8 = 0xC1; +pub const MIFARE_CMD_STORE: u8 = 0xC2; \ No newline at end of file diff --git a/pn532/src/commands/mod.rs b/pn532/src/commands/mod.rs new file mode 100644 index 0000000..cabc43a --- /dev/null +++ b/pn532/src/commands/mod.rs @@ -0,0 +1,51 @@ +//! Command and protocol constants for the PN532. + +pub mod ndef; +#[cfg(feature = "mifare-classic")] +pub mod mifare; +pub mod pn532; + +// PN532 commands. + +pub const PN532_RESPONSE_INDATAEXCHANGE: u8 = 0x41; +pub const PN532_RESPONSE_INLISTPASSIVETARGET: u8 = 0x4B; +pub const PN532_MIFARE_ISO14443A: u8 = 0x00; + +// FeliCa commands. +pub const FELICA_CMD_POLLING: u8 = 0x00; +pub const FELICA_CMD_REQUEST_SERVICE: u8 = 0x02; +pub const FELICA_CMD_REQUEST_RESPONSE: u8 = 0x04; +pub const FELICA_CMD_READ_WITHOUT_ENCRYPTION: u8 = 0x06; +pub const FELICA_CMD_WRITE_WITHOUT_ENCRYPTION: u8 = 0x08; +pub const FELICA_CMD_REQUEST_SYSTEM_CODE: u8 = 0x0C; + +// GPIO. +pub const PN532_GPIO_VALIDATIONBIT: u8 = 0x80; +pub const PN532_GPIO_P30: u8 = 0; +pub const PN532_GPIO_P31: u8 = 1; +pub const PN532_GPIO_P32: u8 = 2; +pub const PN532_GPIO_P33: u8 = 3; +pub const PN532_GPIO_P34: u8 = 4; +pub const PN532_GPIO_P35: u8 = 5; + +pub const FELICA_READ_MAX_SERVICE_NUM: usize = 3; +pub const FELICA_READ_MAX_BLOCK_NUM: usize = 3; + +pub const FELICA_WRITE_MAX_SERVICE_NUM: usize = 3; +pub const FELICA_WRITE_MAX_BLOCK_NUM: usize = 3; + +pub const FELICA_REQ_SERVICE_MAX_NODE_NUM: usize = 32; + +// Frame protocol constants. +pub const PN532_PREAMBLE: u8 = 0x00; +pub const PN532_STARTCODE1: u8 = 0x00; +pub const PN532_STARTCODE2: u8 = 0xFF; +pub const PN532_POSTAMBLE: u8 = 0x00; + +pub const PN532_HOST_TO_PN532: u8 = 0xD4; +pub const PN532_PN532_TO_HOST: u8 = 0xD5; + +pub const PN532_ACK_WAIT_TIME_MS: u16 = 10; + +/// The fixed 7-bit I2C address of the PN532 (0x48 >> 1). +pub const PN532_I2C_ADDRESS: u8 = 0x48 >> 1; diff --git a/pn532/src/commands/ndef.rs b/pn532/src/commands/ndef.rs new file mode 100644 index 0000000..727c471 --- /dev/null +++ b/pn532/src/commands/ndef.rs @@ -0,0 +1,38 @@ +///! NDEF URI record identifier codes (see NFC Forum "URI Record Type Definition"). + +pub const NONE: u8 = 0x00; +pub const HTTP_WWWDOT: u8 = 0x01; +pub const HTTPS_WWWDOT: u8 = 0x02; +pub const HTTP: u8 = 0x03; +pub const HTTPS: u8 = 0x04; +pub const TEL: u8 = 0x05; +pub const MAILTO: u8 = 0x06; +pub const FTP_ANONAT: u8 = 0x07; +pub const FTP_FTPDOT: u8 = 0x08; +pub const FTPS: u8 = 0x09; +pub const SFTP: u8 = 0x0A; +pub const SMB: u8 = 0x0B; +pub const NFS: u8 = 0x0C; +pub const FTP: u8 = 0x0D; +pub const DAV: u8 = 0x0E; +pub const NEWS: u8 = 0x0F; +pub const TELNET: u8 = 0x10; +pub const IMAP: u8 = 0x11; +pub const RTSP: u8 = 0x12; +pub const URN: u8 = 0x13; +pub const POP: u8 = 0x14; +pub const SIP: u8 = 0x15; +pub const SIPS: u8 = 0x16; +pub const TFTP: u8 = 0x17; +pub const BTSPP: u8 = 0x18; +pub const BTL2CAP: u8 = 0x19; +pub const BTGOEP: u8 = 0x1A; +pub const TCPOBEX: u8 = 0x1B; +pub const IRDAOBEX: u8 = 0x1C; +pub const FILE: u8 = 0x1D; +pub const URN_EPC_ID: u8 = 0x1E; +pub const URN_EPC_TAG: u8 = 0x1F; +pub const URN_EPC_PAT: u8 = 0x20; +pub const URN_EPC_RAW: u8 = 0x21; +pub const URN_EPC: u8 = 0x22; +pub const URN_NFC: u8 = 0x23; \ No newline at end of file diff --git a/pn532/src/commands/pn532.rs b/pn532/src/commands/pn532.rs new file mode 100644 index 0000000..5c5ea94 --- /dev/null +++ b/pn532/src/commands/pn532.rs @@ -0,0 +1,32 @@ +pub const DIAGNOSE: u8 = 0x00; +pub const GETFIRMWAREVERSION: u8 = 0x02; +pub const GETGENERALSTATUS: u8 = 0x04; +pub const READREGISTER: u8 = 0x06; +pub const WRITEREGISTER: u8 = 0x08; +pub const READGPIO: u8 = 0x0C; +pub const WRITEGPIO: u8 = 0x0E; +pub const SETSERIALBAUDRATE: u8 = 0x10; +pub const SETPARAMETERS: u8 = 0x12; +pub const SAMCONFIGURATION: u8 = 0x14; +pub const POWERDOWN: u8 = 0x16; +pub const RFCONFIGURATION: u8 = 0x32; +pub const RFREGULATIONTEST: u8 = 0x58; +pub const INJUMPFORDEP: u8 = 0x56; +pub const INJUMPFORPSL: u8 = 0x46; +pub const INLISTPASSIVETARGET: u8 = 0x4A; +pub const INATR: u8 = 0x50; +pub const INPSL: u8 = 0x4E; +pub const INDATAEXCHANGE: u8 = 0x40; +pub const INCOMMUNICATETHRU: u8 = 0x42; +pub const INDESELECT: u8 = 0x44; +pub const INRELEASE: u8 = 0x52; +pub const INSELECT: u8 = 0x54; +pub const INAUTOPOLL: u8 = 0x60; +pub const TGINITASTARGET: u8 = 0x8C; +pub const TGSETGENERALBYTES: u8 = 0x92; +pub const TGGETDATA: u8 = 0x86; +pub const TGSETDATA: u8 = 0x8E; +pub const TGSETMETADATA: u8 = 0x94; +pub const TGGETINITIATORCOMMAND: u8 = 0x88; +pub const TGRESPONSETOINITIATOR: u8 = 0x90; +pub const TGGETTARGETSTATUS: u8 = 0x8A; diff --git a/pn532/src/driver.rs b/pn532/src/driver.rs index ff48a07..dd99bd7 100644 --- a/pn532/src/driver.rs +++ b/pn532/src/driver.rs @@ -88,7 +88,7 @@ impl Pn532 { /// Read the PN532 firmware version and ID. pub fn get_firmware_version(&mut self) -> Result> { - self.buffer[0] = PN532_COMMAND_GETFIRMWAREVERSION; + self.buffer[0] = pn532::GETFIRMWAREVERSION; self.send(1)?; let len = self.read()?; if len < 4 { @@ -104,7 +104,7 @@ impl Pn532 { /// Read a 16-bit PN532 register. pub fn read_register(&mut self, reg: u16) -> Result> { - self.buffer[0] = PN532_COMMAND_READREGISTER; + self.buffer[0] = pn532::READREGISTER; self.buffer[1] = (reg >> 8) as u8; self.buffer[2] = reg as u8; self.send(3)?; @@ -117,7 +117,7 @@ impl Pn532 { /// Write to a 16-bit PN532 register. pub fn write_register(&mut self, reg: u16, val: u8) -> Result<(), Error> { - self.buffer[0] = PN532_COMMAND_WRITEREGISTER; + self.buffer[0] = pn532::WRITEREGISTER; self.buffer[1] = (reg >> 8) as u8; self.buffer[2] = reg as u8; self.buffer[3] = val; @@ -129,7 +129,7 @@ impl Pn532 { /// Set the PN532's GPIO pins (see the PN532 user manual for valid pins). pub fn write_gpio(&mut self, pinstate: u8) -> Result<(), Error> { let pinstate = pinstate | (1 << PN532_GPIO_P32) | (1 << PN532_GPIO_P34); - self.buffer[0] = PN532_COMMAND_WRITEGPIO; + self.buffer[0] = pn532::WRITEGPIO; self.buffer[1] = PN532_GPIO_VALIDATIONBIT | pinstate; self.buffer[2] = 0x00; self.send(3)?; @@ -142,7 +142,7 @@ impl Pn532 { /// Read the state of the PN532's GPIO pins. pub fn read_gpio(&mut self) -> Result> { - self.buffer[0] = PN532_COMMAND_READGPIO; + self.buffer[0] = pn532::READGPIO; self.send(1)?; self.read()?; Ok(self.buffer[0]) @@ -150,7 +150,7 @@ impl Pn532 { /// Configure the SAM (Secure Access Module) in normal mode. pub fn sam_config(&mut self) -> Result<(), Error> { - self.buffer[0] = PN532_COMMAND_SAMCONFIGURATION; + self.buffer[0] = pn532::SAMCONFIGURATION; self.buffer[1] = 0x01; // normal mode self.buffer[2] = 0x14; // timeout 50 ms * 20 = 1 second self.buffer[3] = 0x01; // use IRQ pin @@ -164,7 +164,7 @@ impl Pn532 { &mut self, max_retries: u8, ) -> Result<(), Error> { - self.buffer[0] = PN532_COMMAND_RFCONFIGURATION; + self.buffer[0] = pn532::RFCONFIGURATION; self.buffer[1] = 5; self.buffer[2] = 0xFF; self.buffer[3] = 0x01; @@ -180,7 +180,7 @@ impl Pn532 { auto_rfca: u8, rf_on_off: u8, ) -> Result<(), Error> { - self.buffer[0] = PN532_COMMAND_RFCONFIGURATION; + self.buffer[0] = pn532::RFCONFIGURATION; self.buffer[1] = 1; self.buffer[2] = 0x00 | auto_rfca | rf_on_off; self.send(3)?; @@ -201,7 +201,7 @@ impl Pn532 { /// Release the card. pub fn release(&mut self) -> Result<(), Error> { - self.buffer[0] = PN532_COMMAND_INRELEASE; + self.buffer[0] = pn532::INRELEASE; self.buffer[1] = 0x00; self.send(2)?; diff --git a/pn532/src/error.rs b/pn532/src/error.rs index 50f35e9..b497cf6 100644 --- a/pn532/src/error.rs +++ b/pn532/src/error.rs @@ -1,6 +1,6 @@ use core::fmt::Debug; use bitfields::bitflag; -use crate::felica; +use crate::protocol::felica; /// Driver-level error type, generic over the transport (I2C) error. #[derive(Debug, Clone, Copy, PartialEq, Eq, thiserror::Error)] diff --git a/pn532/src/lib.rs b/pn532/src/lib.rs index 390fbbb..4e304ac 100644 --- a/pn532/src/lib.rs +++ b/pn532/src/lib.rs @@ -47,15 +47,11 @@ extern crate alloc; pub mod commands; pub mod error; -#[cfg(feature = "felica")] -pub mod felica; pub mod interface; pub(crate) mod driver; pub mod tg; -#[cfg(feature = "mifare-classic")] -pub mod mifare; -#[cfg(feature = "iso14443a")] -pub mod iso14443a; +pub mod types; +pub mod protocol; pub use commands::*; pub use driver::*; @@ -64,7 +60,7 @@ pub use interface::*; #[cfg(feature = "defmt")] #[allow(unused_imports)] -use defmt::{error, warn, info, debug, trace}; +use defmt::{debug, error, info, trace, warn}; #[cfg(not(feature = "defmt"))] #[macro_export] diff --git a/pn532/src/felica/error.rs b/pn532/src/protocol/felica/error.rs similarity index 100% rename from pn532/src/felica/error.rs rename to pn532/src/protocol/felica/error.rs diff --git a/pn532/src/felica/felica_lite_s/mod.rs b/pn532/src/protocol/felica/felica_lite_s/auth.rs similarity index 69% rename from pn532/src/felica/felica_lite_s/mod.rs rename to pn532/src/protocol/felica/felica_lite_s/auth.rs index 2881444..edd3f83 100644 --- a/pn532/src/felica/felica_lite_s/mod.rs +++ b/pn532/src/protocol/felica/felica_lite_s/auth.rs @@ -1,53 +1,13 @@ -pub mod issuance; - use des::cipher::{Block, BlockCipherEncrypt, Key, KeyInit}; use des::TdesEde2; use rand_core::Rng; use crate::{Interface, Pn532}; -use crate::felica::error::Error; -use crate::felica::types::{AsBlock, CardSession, FelicaLiteSBlock, FelicaLiteSServiceCode}; -use crate::felica::types::felica_lite_s::auth::{AuthSession, CardKey, MacInput, RandomChallenge, SessionKeys}; +use crate::types::felica::{CardSession, FelicaLiteSBlock, FelicaLiteSServiceCode}; +use crate::types::felica::felica_lite_s::auth::{AuthSession, CardKey, MacInput, RandomChallenge, SessionKeys}; impl Pn532 { - pub fn try_authenticate(&mut self, rng: &mut impl Rng, card: &CardSession, key: &CardKey) - -> Result, crate::Error> - { - let rc = self.set_random_challenge(card, rng)?; - let sk = self.get_session_keys(&rc, key)?; - let session = AuthSession::new(sk, rc); - let is_valid_auth = self.check_auth(card, &session)?; - if is_valid_auth { - Ok(Some(session)) - } else { - Ok(None) - } - } - - pub fn read_with_mac( - &mut self, - card: &CardSession, - session: &AuthSession, - block: impl AsBlock - ) -> Result<[u8; 16], crate::Error> { - let mut block_data = [[0u8; 16]; 2]; - let block_list = [block.as_block(), FelicaLiteSBlock::MACA as u16]; - self.felica_read_without_encryption( - card, - &[FelicaLiteSServiceCode::Read], - &block_list, - &mut block_data - )?; - let input = MacInput::new(&block_data, &block_list); - let mac = self.compute_mac(session, &input); - if mac != input.maca() { - return Err(crate::Error::FelicaError(Error::MACMismatch)); - } - - Ok(block_data[0]) - } - - fn set_random_challenge(&mut self, card: &CardSession, rng: &mut impl Rng) - -> Result> + pub(crate) fn set_random_challenge(&mut self, card: &CardSession, rng: &mut impl Rng) + -> Result> { let mut data = [[0u8; 16]]; rng.fill_bytes(&mut data[0]); @@ -61,7 +21,7 @@ impl Pn532 { Ok(rc) } - fn get_session_keys( + pub(crate) fn get_session_keys( &mut self, rc: &RandomChallenge, card_key: &CardKey, @@ -82,7 +42,7 @@ impl Pn532 { // crate::trace!("SK2: {:02X}", sk2); } - fn compute_mac( + pub(crate) fn compute_mac( &mut self, session: &AuthSession, input: &MacInput @@ -149,7 +109,7 @@ impl Pn532 { mac } - fn check_auth( + pub(crate) fn check_auth( &mut self, card: &CardSession, session: &AuthSession, diff --git a/pn532/src/felica/felica_lite_s/issuance.rs b/pn532/src/protocol/felica/felica_lite_s/issuance.rs similarity index 100% rename from pn532/src/felica/felica_lite_s/issuance.rs rename to pn532/src/protocol/felica/felica_lite_s/issuance.rs diff --git a/pn532/src/protocol/felica/felica_lite_s/mod.rs b/pn532/src/protocol/felica/felica_lite_s/mod.rs new file mode 100644 index 0000000..d09ec3c --- /dev/null +++ b/pn532/src/protocol/felica/felica_lite_s/mod.rs @@ -0,0 +1,70 @@ +pub mod issuance; +pub mod auth; + +use rand_core::Rng; +use crate::{Interface, Pn532}; +use crate::protocol::felica::error::Error; +use crate::types::felica::{AsBlock, CardSession, FelicaLiteSBlock, FelicaLiteSServiceCode}; +use crate::types::felica::felica_lite_s::auth::{AuthSession, CardKey, MacInput}; + +impl Pn532 { + pub fn try_authenticate(&mut self, rng: &mut impl Rng, card: &CardSession, key: &CardKey) + -> Result, crate::Error> + { + let rc = self.set_random_challenge(card, rng)?; + let sk = self.get_session_keys(&rc, key)?; + let session = AuthSession::new(sk, rc); + let is_valid_auth = self.check_auth(card, &session)?; + if is_valid_auth { + Ok(Some(session)) + } else { + Ok(None) + } + } + + pub fn read_with_mac( + &mut self, + card: &CardSession, + session: &AuthSession, + block: impl AsBlock + ) -> Result<[u8; 16], crate::Error> { + let mut block_data = [[0u8; 16]; 2]; + let block_list = [block.as_block(), FelicaLiteSBlock::MACA as u16]; + self.read_block(card, &block_list, &mut block_data)?; + let input = MacInput::new(&block_data, &block_list); + let mac = self.compute_mac(session, &input); + if mac != input.maca() { + return Err(crate::Error::FelicaError(Error::MACMismatch)); + } + + Ok(block_data[0]) + } + + pub fn read_block( + &mut self, + card: &CardSession, + list: &[impl AsBlock; U], + data: &mut [[u8; 16]; U] + ) -> Result<(), crate::Error> { + self.felica_read_without_encryption( + card, + &[FelicaLiteSServiceCode::Read], + list, + data + ) + } + + pub fn write_block( + &mut self, + card: &CardSession, + list: &[impl AsBlock; U], + data: &[[u8; 16]; U] + ) -> Result<(), crate::Error> { + self.felica_write_without_encryption( + card, + &[FelicaLiteSServiceCode::Write], + list, + data + ) + } +} \ No newline at end of file diff --git a/pn532/src/felica/mod.rs b/pn532/src/protocol/felica/mod.rs similarity index 89% rename from pn532/src/felica/mod.rs rename to pn532/src/protocol/felica/mod.rs index 039de1d..1b78f3a 100644 --- a/pn532/src/felica/mod.rs +++ b/pn532/src/protocol/felica/mod.rs @@ -1,4 +1,3 @@ -pub mod types; #[cfg(feature="felica-lite-s")] mod felica_lite_s; pub mod error; @@ -8,9 +7,9 @@ use crate::commands::*; use crate::driver::Pn532; use crate::error::Error; use crate::interface::Interface; -use crate::BaudRate; use core::time::Duration; -use types::*; +use crate::types::felica::*; +use crate::types::BaudRate; impl Pn532 { /// Poll for a FeliCa card. @@ -25,7 +24,7 @@ impl Pn532 { return Err(Error::InvalidBaudRate); } let system_code = system_code.unwrap_or(0xFFFF); - self.buffer[0] = PN532_COMMAND_INLISTPASSIVETARGET; + self.buffer[0] = pn532::INLISTPASSIVETARGET; self.buffer[1] = 1; self.buffer[2] = baud_rate.into(); self.buffer[3] = FELICA_CMD_POLLING; @@ -79,7 +78,7 @@ impl Pn532 { /// Send a raw FeliCa command to the currently in-listed card. /// /// Returns the number of bytes written to `response`. - pub fn felica_send_command( + pub(crate) fn felica_send_command( &mut self, command: &[u8], response: &mut [u8], @@ -88,7 +87,7 @@ impl Pn532 { if command.len() > 0xFE { return Err(Error::InvalidParam); } - self.buffer[0] = PN532_COMMAND_INDATAEXCHANGE; + self.buffer[0] = pn532::INDATAEXCHANGE; self.buffer[1] = self.in_listed_tag; self.buffer[2] = (command.len() + 1) as u8; self.send_with_body(3, command)?; @@ -124,12 +123,12 @@ impl Pn532 { /// Send a FeliCa "Read Without Encryption" command. /// /// Note: the number of blocks is limited by the 64-byte response buffer. - pub fn felica_read_without_encryption( + pub(crate) fn felica_read_without_encryption( &mut self, card: &CardSession, service_code_list: &[impl AsServiceCode], - block_list: &[impl AsBlock], - block_data: &mut [[u8; 16]], + block_list: &[impl AsBlock; U], + block_data: &mut [[u8; 16]; U], ) -> Result<(), Error> { const COMMAND_SIZE: usize = 1 // command code (0x06) @@ -148,10 +147,7 @@ impl Pn532 { // validate let num_service = service_code_list.len(); - let num_block = block_list.len(); - if num_service > FELICA_READ_MAX_SERVICE_NUM - || num_block > FELICA_READ_MAX_BLOCK_NUM - || num_block > block_data.len() + if num_service > FELICA_READ_MAX_SERVICE_NUM || U > FELICA_READ_MAX_BLOCK_NUM { return Err(Error::InvalidParam); } @@ -165,7 +161,7 @@ impl Pn532 { let sc: [u8; 2] = sc.as_service_code().to_le_bytes(); cmd.extend_from_slice(&sc).unwrap(); } - cmd.push(num_block as u8).unwrap(); + cmd.push(U as u8).unwrap(); for bl in block_list { let bl: [u8; 2] = bl.as_block().to_be_bytes(); cmd.extend_from_slice(&bl).unwrap(); @@ -179,10 +175,10 @@ impl Pn532 { let response_len = self.felica_send_command( &cmd, &mut response, - card.pmm.get_read_timeout(num_block, Some(Duration::from_millis(50))) + card.pmm.get_read_timeout(U, Some(Duration::from_millis(50))) )?; crate::trace!("Read Response: {:02X}", response); - if response_len != 12 + 16 * num_block { + if response_len != 12 + 16 * U { return Err(Error::InvalidFrame); } if response[9] != 0 || response[10] != 0 { @@ -190,7 +186,7 @@ impl Pn532 { } let mut k = 12; - for block in block_data.iter_mut().take(num_block) { + for block in block_data.iter_mut().take(U) { block.copy_from_slice(&response[k..k + 16]); k += 16; } @@ -198,12 +194,12 @@ impl Pn532 { } /// Send a FeliCa "Write Without Encryption" command. - pub fn felica_write_without_encryption( + pub(crate) fn felica_write_without_encryption( &mut self, card: &CardSession, service_code_list: &[impl AsServiceCode], - block_list: &[impl AsBlock], - block_data: &[[u8; 16]], + block_list: &[impl AsBlock; U], + block_data: &[[u8; 16]; U], ) -> Result<(), Error> { const COMMAND_SIZE: usize = 1 // command code @@ -221,10 +217,7 @@ impl Pn532 { // validate let num_service = service_code_list.len(); - let num_block = block_list.len(); - if num_service > FELICA_WRITE_MAX_SERVICE_NUM - || num_block > FELICA_WRITE_MAX_BLOCK_NUM - || num_block > block_data.len() + if num_service > FELICA_WRITE_MAX_SERVICE_NUM || U > FELICA_WRITE_MAX_BLOCK_NUM { return Err(Error::InvalidParam); } @@ -238,12 +231,12 @@ impl Pn532 { let sc = sc.as_service_code().to_le_bytes(); cmd.extend_from_slice(&sc).unwrap(); } - cmd.push(num_block as u8).unwrap(); + cmd.push(U as u8).unwrap(); for block in block_list { let block = block.as_block().to_be_bytes(); cmd.extend_from_slice(&block).unwrap(); } - for block in block_data.iter().take(num_block) { + for block in block_data.iter().take(U) { cmd.extend_from_slice(block).unwrap(); } @@ -252,7 +245,7 @@ impl Pn532 { let response_len = self.felica_send_command( &cmd, &mut response, - card.pmm.get_write_timeout(num_block, Some(Duration::from_millis(50))) + card.pmm.get_write_timeout(U, Some(Duration::from_millis(50))) )?; if response_len != RESPONSE_SIZE { return Err(Error::InvalidFrame); diff --git a/pn532/src/iso14443a/mod.rs b/pn532/src/protocol/iso14443a/mod.rs similarity index 100% rename from pn532/src/iso14443a/mod.rs rename to pn532/src/protocol/iso14443a/mod.rs diff --git a/pn532/src/mifare/mod.rs b/pn532/src/protocol/mifare/mod.rs similarity index 100% rename from pn532/src/mifare/mod.rs rename to pn532/src/protocol/mifare/mod.rs diff --git a/pn532/src/protocol/mod.rs b/pn532/src/protocol/mod.rs new file mode 100644 index 0000000..9a7f876 --- /dev/null +++ b/pn532/src/protocol/mod.rs @@ -0,0 +1,6 @@ +#[cfg(feature = "felica")] +pub mod felica; +#[cfg(feature = "mifare-classic")] +pub mod mifare; +#[cfg(feature = "iso14443a")] +pub mod iso14443a; \ No newline at end of file diff --git a/pn532/src/tg/mod.rs b/pn532/src/tg.rs similarity index 87% rename from pn532/src/tg/mod.rs rename to pn532/src/tg.rs index acf1e89..3b77b23 100644 --- a/pn532/src/tg/mod.rs +++ b/pn532/src/tg.rs @@ -1,4 +1,4 @@ -use crate::commands::{PN532_COMMAND_TGGETDATA, PN532_COMMAND_TGINITASTARGET, PN532_COMMAND_TGSETDATA}; +use crate::commands::*; use crate::error::StatusCode; use crate::{Error, Interface, Pn532, TargetInitStatus}; use core::time::Duration; @@ -24,7 +24,7 @@ impl Pn532 { timeout_ms: u16, ) -> Result> { const COMMAND: [u8; 44] = [ - PN532_COMMAND_TGINITASTARGET, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x01, 0xFE, + pn532::TGINITASTARGET, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x01, 0xFE, 0x0F, 0xBB, 0xBA, 0xA6, 0xC9, 0x89, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x01, 0xFE, 0x0F, 0xBB, 0xBA, 0xA6, 0xC9, 0x89, 0x00, 0x00, 0x06, 0x46, 0x66, 0x6D, 0x01, 0x01, 0x10, 0x00, @@ -34,7 +34,7 @@ impl Pn532 { /// Retrieve data received from the initiator. pub fn tg_get_data(&mut self, buf: &mut [u8]) -> Result> { - self.buffer[0] = PN532_COMMAND_TGGETDATA; + self.buffer[0] = pn532::TGGETDATA; self.send(1)?; let len = self.read_timeout(Duration::from_millis(3000))?; @@ -57,10 +57,10 @@ impl Pn532 { body: &[u8], ) -> Result<(), Error> { if header.len() > N - 1 { - self.buffer[0] = PN532_COMMAND_TGSETDATA; + self.buffer[0] = pn532::TGSETDATA; self.interface.write_command(&self.buffer[..1], header)?; } else { - self.buffer[0] = PN532_COMMAND_TGSETDATA; + self.buffer[0] = pn532::TGSETDATA; self.buffer[1..1 + header.len()].copy_from_slice(header); self.interface .write_command(&self.buffer[..1 + header.len()], body)?; diff --git a/pn532/src/felica/types/felica_lite_s/auth/card_key.rs b/pn532/src/types/felica/felica_lite_s/auth/card_key.rs similarity index 100% rename from pn532/src/felica/types/felica_lite_s/auth/card_key.rs rename to pn532/src/types/felica/felica_lite_s/auth/card_key.rs diff --git a/pn532/src/felica/types/felica_lite_s/auth/mac_input.rs b/pn532/src/types/felica/felica_lite_s/auth/mac_input.rs similarity index 84% rename from pn532/src/felica/types/felica_lite_s/auth/mac_input.rs rename to pn532/src/types/felica/felica_lite_s/auth/mac_input.rs index 20add88..e83193b 100644 --- a/pn532/src/felica/types/felica_lite_s/auth/mac_input.rs +++ b/pn532/src/types/felica/felica_lite_s/auth/mac_input.rs @@ -1,4 +1,4 @@ -use crate::felica::types::AsBlock; +use crate::types::felica::AsBlock; use crate::FELICA_READ_MAX_BLOCK_NUM; #[derive(Copy, Clone, Eq, PartialEq, Debug)] @@ -26,13 +26,6 @@ impl MacInput { } } - pub fn as_vec(&self) -> heapless::Vec { - let mut data = heapless::Vec::new(); - data.extend(self.block_list()); - data.extend_from_slice(&self.block_data()).unwrap(); - data - } - pub fn block_data(&self) -> heapless::Vec { let mut data = heapless::Vec::::new(); for block in self.block_data.iter().take(N - 1) { diff --git a/pn532/src/felica/types/felica_lite_s/auth/mod.rs b/pn532/src/types/felica/felica_lite_s/auth/mod.rs similarity index 100% rename from pn532/src/felica/types/felica_lite_s/auth/mod.rs rename to pn532/src/types/felica/felica_lite_s/auth/mod.rs diff --git a/pn532/src/felica/types/felica_lite_s/auth/rc.rs b/pn532/src/types/felica/felica_lite_s/auth/rc.rs similarity index 100% rename from pn532/src/felica/types/felica_lite_s/auth/rc.rs rename to pn532/src/types/felica/felica_lite_s/auth/rc.rs diff --git a/pn532/src/felica/types/felica_lite_s/auth/sk.rs b/pn532/src/types/felica/felica_lite_s/auth/sk.rs similarity index 96% rename from pn532/src/felica/types/felica_lite_s/auth/sk.rs rename to pn532/src/types/felica/felica_lite_s/auth/sk.rs index 0ea81df..0a3e1cc 100644 --- a/pn532/src/felica/types/felica_lite_s/auth/sk.rs +++ b/pn532/src/types/felica/felica_lite_s/auth/sk.rs @@ -1,6 +1,6 @@ use cbc::cipher::{Block, BlockCipherEncrypt}; use des::TdesEde2; -use crate::felica::types::felica_lite_s::auth::RandomChallenge; +use crate::types::felica::felica_lite_s::auth::RandomChallenge; #[derive(Copy, Clone, Eq, PartialEq, Debug)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] diff --git a/pn532/src/felica/types/felica_lite_s/mod.rs b/pn532/src/types/felica/felica_lite_s/mod.rs similarity index 91% rename from pn532/src/felica/types/felica_lite_s/mod.rs rename to pn532/src/types/felica/felica_lite_s/mod.rs index c455958..62a0ead 100644 --- a/pn532/src/felica/types/felica_lite_s/mod.rs +++ b/pn532/src/types/felica/felica_lite_s/mod.rs @@ -1,10 +1,12 @@ pub mod auth; +use core::fmt::{Display, Formatter}; ///! Types for Felica Lite-S (RC-S966) ///! User Manual: https://www.sony.net/Products/felica/business/tech-support/data/fls_usmnl_1.4e.pdf use bitfields::bitflag; -use super::AsBlock; +use crate::types::felica::polling::PollingResponse; +use super::{AsBlock, IDm, PMm}; use super::AsServiceCode; /// Service Code @@ -62,11 +64,11 @@ pub enum Block { /// Card key version block. CKV = 0x8086, /// Card key block. - CK= 0x8087, + CK = 0x8087, /// Memory configuration block. MemoryConfig = 0x8088, /// Write counter block. - WriteCounter = 0x8090, + WCNT = 0x8090, /// MAC_A block. MACA = 0x8091 } diff --git a/pn532/src/felica/types/ic_type.rs b/pn532/src/types/felica/ic_type.rs similarity index 100% rename from pn532/src/felica/types/ic_type.rs rename to pn532/src/types/felica/ic_type.rs diff --git a/pn532/src/felica/types/idm.rs b/pn532/src/types/felica/idm.rs similarity index 100% rename from pn532/src/felica/types/idm.rs rename to pn532/src/types/felica/idm.rs diff --git a/pn532/src/felica/types/mod.rs b/pn532/src/types/felica/mod.rs similarity index 52% rename from pn532/src/felica/types/mod.rs rename to pn532/src/types/felica/mod.rs index 0e489cb..fa5b018 100644 --- a/pn532/src/felica/types/mod.rs +++ b/pn532/src/types/felica/mod.rs @@ -5,14 +5,13 @@ mod idm; pub mod felica_lite_s; pub mod ic_type; -use core::fmt::{Display, Formatter}; pub use idm::*; pub use pmm::*; pub use polling::PollingRequestCode as FelicaPollingRequestCode; pub use polling::PollingResponse as FelicaPollingResponse; +pub use polling::CardSession; #[cfg(feature = "felica-lite-s")] pub use felica_lite_s::{Block as FelicaLiteSBlock, ServiceCode as FelicaLiteSServiceCode}; -use crate::felica::types::polling::PollingResponse; pub trait AsServiceCode { fn as_service_code(&self) -> u16; @@ -37,33 +36,4 @@ impl AsServiceCode for u16 { fn from_service_code(val: u16) -> Self { val } -} - -#[derive(Copy, Clone, Eq, PartialEq, Debug)] -#[cfg_attr(feature = "defmt", derive(defmt::Format))] -#[readonly::make] -pub struct CardSession { - pub idm: IDm, - pub pmm: PMm -} - -impl CardSession { - pub fn new(idm: IDm, pmm: PMm) -> Self { - Self { idm, pmm } - } -} - -impl From for CardSession { - fn from(value: PollingResponse) -> Self { - Self { - idm: value.idm, - pmm: value.pmm - } - } -} - -impl Display for CardSession { - fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result { - write!(f, "IDm: {}, PMm: {}", self.idm, self.pmm) - } } \ No newline at end of file diff --git a/pn532/src/felica/types/pmm.rs b/pn532/src/types/felica/pmm.rs similarity index 100% rename from pn532/src/felica/types/pmm.rs rename to pn532/src/types/felica/pmm.rs diff --git a/pn532/src/felica/types/polling.rs b/pn532/src/types/felica/polling.rs similarity index 66% rename from pn532/src/felica/types/polling.rs rename to pn532/src/types/felica/polling.rs index 50d556a..877751c 100644 --- a/pn532/src/felica/types/polling.rs +++ b/pn532/src/types/felica/polling.rs @@ -1,5 +1,5 @@ use alloc::string::ToString; -use core::fmt::Display; +use core::fmt::{Display, Formatter}; use bitfields::bitflag; use super::{IDm, PMm}; @@ -46,4 +46,33 @@ impl Display for PollingResponse { }; write!(f, "IDm: {}, PMm, {}, System Code: {}", self.idm, self.pmm, system_code) } +} + +#[derive(Copy, Clone, Eq, PartialEq, Debug)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +#[readonly::make] +pub struct CardSession { + pub idm: IDm, + pub pmm: PMm +} + +impl CardSession { + pub fn new(idm: IDm, pmm: PMm) -> Self { + Self { idm, pmm } + } +} + +impl From for CardSession { + fn from(value: PollingResponse) -> Self { + Self { + idm: value.idm, + pmm: value.pmm + } + } +} + +impl Display for CardSession { + fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result { + write!(f, "IDm: {}, PMm: {}", self.idm, self.pmm) + } } \ No newline at end of file diff --git a/pn532/src/types/mod.rs b/pn532/src/types/mod.rs new file mode 100644 index 0000000..9c69647 --- /dev/null +++ b/pn532/src/types/mod.rs @@ -0,0 +1,19 @@ +#[cfg(feature = "felica")] +pub mod felica; + +/// Passive target baud rates supported by [`crate::Pn532::read_passive_target_id`]. +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +#[repr(u8)] +pub enum BaudRate { + ISO14443A106kbps = 0x00, + Felica212kbps = 0x01, + Felica424kbps = 0x02, + ISO14443B106kbps = 0x03, + InnovisionJewel106kbps = 0x04, +} + +impl From for u8 { + fn from(value: BaudRate) -> Self { + value as u8 + } +} \ No newline at end of file diff --git a/src/components/card_reader.rs b/src/components/card_reader.rs index 64fe78c..1248fe6 100644 --- a/src/components/card_reader.rs +++ b/src/components/card_reader.rs @@ -4,9 +4,10 @@ use embassy_sync::once_lock::OnceLock; use embassy_time::{Delay, Timer}; use esp_hal::gpio; use esp_hal::rng::Trng; -use pn532::felica::types::{CardSession, FelicaLiteSBlock, FelicaPollingRequestCode}; -use pn532::{BaudRate, Pn532}; -use pn532::felica::types::felica_lite_s::auth::CardKey; +use pn532::types::felica::{CardSession, FelicaLiteSBlock, FelicaPollingRequestCode}; +use pn532::{Pn532}; +use pn532::types::felica::felica_lite_s::auth::CardKey; +use pn532::types::BaudRate; static CARD_KEY: OnceLock = OnceLock::new(); const CARD_KEY_STR: &str = env!("CARD_KEY");