Merge branch 'fix/remove-cs-style-documenation' into 'main'

chore(doc): rework from C# XML style to markdown

See merge request fabinfra/fabaccess/nfc_rs!5
This commit is contained in:
dequbed 2022-05-25 17:38:03 +00:00
commit b2256e49ea
4 changed files with 154 additions and 203 deletions

View File

@ -16,8 +16,7 @@ use crate::iso7816_4::apducommand::{APDUCommand, IsoCase};
use crate::{error, Card};
use num_traits::FromPrimitive;
/// Maximum number of bytes in a single transaction while communicating with a nfc token
pub const MAX_BYTES_PER_TRANSACTION: usize = 47;
pub struct Desfire {
@ -43,10 +42,7 @@ impl Desfire {
})
}
/// <summary>
/// Select Application by ApplicationID (AID)
/// </summary>
/// <param name="aid">3 Byte AID</param>
/// Select Application by 3 Byte ApplicationID `aid`
pub fn select_application(&self, aid: u32) -> Result<()> {
let cmd_select_app = self.select_application_cmd(aid)?;
@ -55,12 +51,12 @@ impl Desfire {
response.check()
}
/// <summary>
/// Authenticate to PICC, with ISO Authenticate for DES Key
/// </summary>
/// <param name="key_id">0x01 - 0x0D</param>
/// <param name="key">Array of 8/16 Bytes</param>
/// <param name="rndA">!!! WARNING For Testing only !!!</param>
///
/// Arguments:
/// * `key_id`: 0x01 - 0x0D
/// * `key`: Array of 8/16 bytes
/// * `rnd_a`: !!! WARNING for testing only !!!
pub fn authenticate_iso_des(
&mut self,
key_id: u8,
@ -243,12 +239,12 @@ impl Desfire {
Ok(())
}
/// <summary>
/// Authenticate to PICC, with ISO Authenticate for AES Key
/// </summary>
/// <param name="key_id">0x01 - 0x0D</param>
/// <param name="key">Array of 8/16 Bytes</param>
/// <param name="rndA">!!! WARNING For Testing only !!!</param>
///
/// # Parameters
/// * `key_id`: 0x01 - 0x0D
/// * `key`: Array of 8/16 bytes
/// * `rnd_a`: !!! WARNING for testing only !!!
pub fn authenticate_iso_aes(
&mut self,
key_id: u8,
@ -311,10 +307,10 @@ impl Desfire {
)
}
/// <summary>
/// Format PICC
/// Need Authentication for PICC / Application 0x000000
/// </summary>
/// Format PICC, this is akin to a factory reset
///
/// # Note
/// This function will fail if you haven't authenticated against the PICC (Application ID: 0)
pub fn format_picc(&self) -> Result<()> {
let cmd_format = APDUCommand {
case: IsoCase::Case2Short,
@ -328,10 +324,12 @@ impl Desfire {
response.check()
}
/// <summary>
/// Create Application for ApplicationID
/// </summary>
/// <param name="aid">3 Byte ID</param>
/// Create a new application with `aid` as the application ID
///
/// # Arguments
/// * `aid`: 3 byte ID
/// * `keysetting1`: TODO
/// * `keysetting2`: TODO
pub fn create_application(&self, aid: u32, keysetting1: u8, keysetting2: u8) -> Result<()> {
if aid > 0xFFFFFF {
return Err(InvalidApplicationID);
@ -358,12 +356,18 @@ impl Desfire {
response.check()
}
/// <summary>
/// Change AES key, the same as Authenticated
/// </summary>
/// <param name="key_id">0x01 - 0x0D</param>
/// <param name="new_key">Array of 16 Bytes</param>
/// <param name="key_version">Version of Key(min. 0x10)</param>
/// Change AES key, that is currently authenticated
///
/// # Notes
///
/// This will fail if the key you are trying to change isn't authenticated
///
/// # Arguments
/// * `key_id` - 0x01 - 0x0D
/// * `new_key` - Array of 16 Bytes
/// * `key_version` - Version of Key(min. 0x10)
///
/// Also see: [`Desfire::change_other_key_aes`]
pub fn change_key_aes(&mut self, key_id: u8, new_key: &[u8], key_version: u8) -> Result<()> {
if key_id >= 0x0E {
return Err(InvalidKeyID);
@ -426,13 +430,15 @@ impl Desfire {
response.check()
}
/// <summary>
/// Change AES key, other than Authenticated
/// </summary>
/// <param name="key_id">0x01 - 0x0D</param>
/// <param name="new_key">Array of 16 Bytes</param>
/// <param name="old_key">Array of 16 Bytes</param>
/// <param name="key_version">Version of Key(min. 0x10)</param>
/// Change AES key, of a currently not authenticated key
///
/// # Arguments:
/// * `key_id` - 0x01 - 0x0D
/// * `new_key` - Array of 16 Bytes
/// * `old_key` - Array of 16 Bytes
/// * `key_version` - Version of Key(min. 0x10)
///
/// Also see: [`Desfire::change_key_aes`]
pub fn change_other_key_aes(
&mut self,
key_id: u8,
@ -514,6 +520,13 @@ impl Desfire {
response.check()
}
/// Create a new standard file
///
/// # Arguments
/// * `file_id` - ID of the new file (0x00 - 0x20)
/// * `communication` - TODO
/// * `access_rights` - TODO
/// * `size` - size of the file in bytes
pub fn create_file_standard(
&self,
file_id: u8,
@ -551,12 +564,12 @@ impl Desfire {
response.check()
}
/// <summary>
/// Write Data to File
/// </summary>
/// <param name="file_id">ID of File (0x00 - 0x20)</param>
/// <param name="offset">Offset for File</param>
/// <param name="data">Data to write</param>
///
/// # Parameters
/// * `file_id` - Id of the file (0x00 - 0x20)
/// * `offset` - offset of the file
/// * `data` - data to write
pub fn write_data(&self, file_id: u8, offset: u32, data: &[u8]) -> Result<()> {
if file_id >= 0x20 {
return Err(InvalidFileID);
@ -638,12 +651,15 @@ impl Desfire {
return Ok(cmd_read_data_chunk);
}
/// <summary>
/// Read Data from File
/// </summary>
/// <param name="file_id">ID of File (0x00 - 0x20)</param>
/// <param name="offset">Offset for File</param>
/// <param name="length">Lenght of Data</param>
/// Read data from a file
///
/// # Note
/// This operation will fail if you try to read more data then there is in the file
///
/// # Parameters
/// * `file_id` - ID of the file (0x00 - 0x20)
/// * `offset` - Offset of the file
/// * `length` - lenght of the data to read
pub fn read_data(&self, file_id: u8, offset: u32, length: usize) -> Result<Vec<u8>> {
if file_id >= 0x20 {
return Err(InvalidFileID);
@ -679,29 +695,30 @@ impl Desfire {
}
}
/// <summary>
/// Generates SessionKey for DES Authentification
/// </summary>
/// <returns>8Byte SessionKey</returns>
///
/// returns 8Byte SessionKey
fn generate_session_key_des(rnd_a: &[u8], rnd_b: &[u8]) -> Option<Vec<u8>> {
let sessionkey = [&rnd_a[..4], &rnd_b[..4]].concat();
Some([sessionkey.as_slice(), sessionkey.as_slice()].concat())
}
/// <summary>
/// Generates SessionKey for AES Authentification
/// </summary>
/// <returns>16Byte SessionKey</returns>
///
/// returns 16Byte SessionKey
fn generate_session_key_aes(rnd_a: &[u8], rnd_b: &[u8]) -> Option<Vec<u8>> {
//FIXME: Check math
Some([&rnd_a[..4], &rnd_b[..4], &rnd_a[12..], &rnd_b[12..]].concat())
}
/// <summary>
/// Generate KeySetting1 for Application Settings or PICC Setting
/// </summary>
/// <param name="changeKey">ID of Key for changing Application Keys</param>
/// <returns>generated keysettings</returns>
///
/// # Parameters
/// * `change_key` - ID of the key for changing application keys
/// * `change_master_key` - TODO
/// * `create_delete_file` - TODO
/// * `file_directory_access` - TODO
/// * `change_master_key` - TODO
pub fn generate_keysetting1(
change_key: u8,
change_masterkey_settings: ChangeMasterKeySettings,
@ -731,11 +748,12 @@ pub fn generate_keysetting1(
};
}
/// <summary>
/// Generate KeySetting2 for Application Creation
/// </summary>
/// <param name="numberOfKeys">Number of keys that can be stored within the application (0x01-0x0D)</param>
/// <returns>generated keysettings</returns>
///
/// # Parameters
/// * `crypto_operations` - TODO
/// * `file_identifier` - TODO
/// * `num_keys` - Number of keys that can be stored within the application (0x01 - 0x0D)
pub fn generate_keysetting2(
crypto_operations: CryptoOperationsType,
file_identifier: FileIdentifiers,
@ -748,14 +766,18 @@ pub fn generate_keysetting2(
};
}
/// <summary>
/// Generate FileAccess Rights for File Settings
/// Use enum AccesRights for Free or Never Option
/// </summary>
/// <param name="read">KeyID for Read Access</param>
/// <param name="write">KeyID for Write Access</param>
/// <param name="read_write">KeyID for Read and Write Access</param>
/// <param name="configure">KeyID for Configuration Access</param>
///
/// # Note
/// Use [`FileAccessRights`] for Free or Never Option
///
/// # Parameters
/// * `read` key_id for read access
/// * `write` key_id for write access
/// * `read_write` key_id for read and write access
/// * `configure` key_id for configuration access
///
/// [`FileAccessRights`]: crate::desfire::FileAccessRights
pub fn generate_file_access_rights(
read: u8,
write: u8,
@ -786,17 +808,15 @@ mod tests {
CryptoOperationsType, FileAccessRights, FileCommunication, FileDirectoryAccess,
FileIdentifiers,
};
use crate::error::Error::{CardError};
use crate::error::Error::CardError;
use crate::error::Result;
use crate::{APDUCommand, APDUResponse, Card as CardTrait};
use hex_literal::hex;
use mockall::{mock};
use mockall::mock;
use pcsc::{Card, Context, Protocols, Scope, ShareMode, MAX_BUFFER_SIZE};
use std::convert::TryFrom;
use std::ffi::{CString};
use std::ffi::CString;
mock! {
pub VirtualCard {}

View File

@ -1,79 +1,51 @@
use num_derive::FromPrimitive;
/// <summary>
/// hold the Access Rights for changing application keys (Change Key command)
/// </summary>
/// Access Rights for changing application keys (Change Key command)
#[repr(u8)]
#[derive(Clone, Copy, FromPrimitive)]
pub enum ChangeApplicationKey {
/// <summary>
/// Application master key authentication is necessary to change any key (default)
/// </summary>
MASTERKEY = 0x00,
/// <summary>
/// Authentication with the key to be changed (same Key#) is necessary to change a key
/// </summary>
SAMEKEY = 0x0E,
/// <summary>
/// All keys (except application master key, see Bit 0) within this application are frozen
/// </summary>
ALLKEYS = 0x0F,
}
/// <summary>
/// codes whether the application master key is changeable
/// </summary>
#[repr(u8)]
#[derive(Clone, Copy)]
pub enum ChangeMasterKey {
/// <summary>
/// Application master key is not changeable anymore (frozen)
/// </summary>
FROZEN = 0x00,
/// <summary>
/// Application master key is changeable (authentication with the current application master key necessary, default)
/// </summary>
CHANGEABLE = 0x01,
}
/// <summary>
/// codes whether a change of the application master key settings is allowed
/// </summary>
#[repr(u8)]
#[derive(Clone, Copy)]
pub enum ChangeMasterKeySettings {
/// <summary>
/// configuration not changeable anymore (frozen)
/// </summary>
FROZEN = 0x00,
/// <summary>
/// this configuration is changeable if authenticated with the application master key (default)
/// </summary>
WITHMASTERKEY = 0x08,
}
/// <summary>
/// codes whether application master key authentication is needed before “Create File” / “Delete File”
/// </summary>
#[repr(u8)]
#[derive(Clone, Copy)]
pub enum CreateDeleteFile {
/// <summary>
/// “Create File”/ “Delete File”is permitted only with application master key authentication
/// </summary>
ONLYMASTERKEY = 0x00,
/// <summary>
/// “Create File”/ “Delete File”is permitted also without application master key authentication (default)
/// </summary>
NOKEY = 0x04,
}
/// <summary>
/// Crypto method of the application
/// </summary>
#[repr(u8)]
#[derive(Clone, Copy)]
pub enum CryptoOperationsType {
@ -92,42 +64,30 @@ pub enum FileAccessRights {
#[repr(u8)]
#[derive(Clone, Copy)]
pub enum FileCommunication {
/// <summary>
/// "Plain communication"
/// </summary>
PLAIN = 0x00,
/// <summary>
/// Plain communication secured by DES/3DES MACing
/// </summary>
MAC = 0x01,
/// <summary>
/// Fully DES/3DES enciphered communication
/// </summary>
ENCRYPT = 0x03,
}
/// <summary>
/// codes whether application master key authentication is needed for file directory access
/// </summary>
#[repr(u8)]
#[derive(Clone, Copy)]
pub enum FileDirectoryAccess {
/// <summary>
/// Successful application master key authentication is required for executing the “Get FID List”, “Get File Settings”and “Get Key Settings”commands
/// </summary>
/// Successful application master key authentication is required for executing
/// the “Get FID List”, “Get File Settings”and “Get Key Settings”commands
ONLYMASTERKEY = 0x00,
/// <summary>
/// “Get FID List”, “Get File Settings” and “Get Key Settings” commands succeed independentlyof a preceding application master key authentication (default)
/// </summary>
/// “Get FID List”, “Get File Settings” and “Get Key Settings” commands succeed
/// independently of a preceding application master key authentication (default)
NOKEY = 0x02,
}
/// <summary>
/// Indicates use of 2 byte ISO/IEC 7816-4 File Identifies for files within the Application
/// </summary>
#[repr(u8)]
#[derive(Clone, Copy)]
pub enum FileIdentifiers {
@ -138,29 +98,19 @@ pub enum FileIdentifiers {
#[repr(u8)]
#[derive(Clone, Copy)]
pub enum FileTypes {
/// <summary>
/// Standard Data File
/// </summary>
STANDARD = 0x00,
/// <summary>
/// Backup Data Files
/// </summary>
BACKUP = 0x01,
/// <summary>
/// Value Files with Backup
/// </summary>
VALUE = 0x02,
/// <summary>
/// Linear Record Files with Backup
/// </summary>
LINEARRECORD = 0x03,
/// <summary>
/// Cyclic Record Files with Backup
/// </summary>
CYCLICRECORD = 0x04,
}

View File

@ -6,74 +6,60 @@ use std::fmt::Formatter;
#[repr(u8)]
#[derive(Eq, PartialEq, Hash, Debug, Clone)]
pub enum IsoCase {
/// <summary>No command data. No response data.</summary>
/// <remarks>
/// <list type="bullet">
/// <item><description>lc is valued to 0.</description></item>
/// <item><description>le is valued to 0.</description></item>
/// <item><description>No data byte is present.</description></item>
/// </list>
/// </remarks>
/// No command data. No response data.
///
/// # Notes
/// * lc is valued to 0.
/// * le is valued to 0.
/// * No data byte is present.
Case1 = 0,
/// <summary>No command data. Expected response data.</summary>
/// <remarks>
/// <list type="bullet">
/// <item><description>lc is valued to 0.</description></item>
/// <item><description>le is valued from 1 to 256.</description></item>
/// <item><description>No data byte is present.</description></item>
/// </list>
/// </remarks>
/// No command data. Expected response data.
///
/// # Notes
/// * lc is valued to 0.
/// * le is valued from 1 to 256.
/// * No data byte is present.
Case2Short = 1,
/// <summary>Command data. No response data.</summary>
/// <remarks>
/// <list type="bullet">
/// <item><description>lc is valued from 1 to 255.</description></item>
/// <item><description>le is valued to 0.</description></item>
/// <item><description>lc data bytes are present.</description></item>
/// </list>
/// </remarks>
/// Command data. No response data.
///
/// # Notes
/// * lc is valued from 1 to 255.
/// * le is valued to 0.
/// * lc data bytes are present.
Case3Short = 2,
/// <summary>Command data. Expected response data.</summary>
/// <remarks>
/// <list type="bullet">
/// <item><description>lc is valued from 1 to 255.</description></item>
/// <item><description>le is valued from 1 to 256.</description></item>
/// <item><description>lc data bytes are present.</description></item>
/// </list>
/// </remarks>
/// Command data. Expected response data.
///
/// # Notes
/// * lc is valued from 1 to 255.
/// * le is valued from 1 to 256.
/// * lc data bytes are present.
Case4Short = 3,
/// <summary>No command data. Expected response data.</summary>
/// <remarks>
/// <list type="bullet">
/// <item><description>lc is valued to 0.</description></item>
/// <item><description>le is valued from 1 to 65536.</description></item>
/// <item><description>No data byte is present.</description></item>
/// </list>
/// </remarks>
/// No command data. Expected response data.
///
/// # Notes
/// * lc is valued to 0.
/// * le is valued from 1 to 65536.
/// * No data byte is present.
Case2Extended = 4,
/// <summary>Command data. No response data.</summary>
/// <remarks>
/// <list type="bullet">
/// <item><description>lc is valued from 1 to 65536.</description></item>
/// <item><description>le is valued to 0.</description></item>
/// <item><description>lc data bytes are present.</description></item>
/// </list>
/// </remarks>
/// Command data. No response data.
///
/// # Notes
/// * lc is valued from 1 to 65536.
/// * le is valued to 0.
/// * lc data bytes are present.
Case3Extended = 5,
/// <summary>Command data. Expected response data.</summary>
/// <remarks>
/// <list type="bullet">
/// <item><description>lc is valued from 1 to 65535.</description></item>
/// <item><description>le is valued from 1 to 65536.</description></item>
/// <item><description>lc data bytes are present.</description></item>
/// </list>
/// </remarks>
/// Command data. Expected response data.
///
/// Notes
/// * lc is valued from 1 to 65535.
/// * le is valued from 1 to 65536.
/// * lc data bytes are present.
Case4Extended = 6,
}
@ -86,24 +72,22 @@ impl Default for IsoCase {
#[repr(u8)]
#[derive(Eq, PartialEq, Hash, Debug, Clone)]
pub enum SCardProtocol {
/// <summary>
/// protocol not defined.
/// </summary>
Unset = 0x0000,
/// <summary>T=0 active protocol.</summary>
/// T=0 active protocol.
T0 = 0x0001,
/// <summary>T=1 active protocol.</summary>
/// T=1 active protocol.
T1 = 0x0002,
/// <summary>Raw active protocol. Use with memory type cards.</summary>
/// Raw active protocol. Use with memory type cards.
Raw = 0x0004,
/// <summary>T=15 protocol.</summary>
/// T=15 protocol.
T15 = 0x0008,
/// <summary>(<see cref="SCardProtocol.T0" /> | <see cref="SCardProtocol.T1" />). IFD (Interface device) determines protocol.</summary>
/// (see [`SCardProtocol::T0`] and [`SCardProtocol::T1`]). IFD (Interface device) determines protocol.
Any = (0x0001 | 0x0002),
}

View File

@ -16,20 +16,17 @@ pub mod error;
pub mod iso7816_4;
pub trait Card {
/// <summary>
/// Connect to Smartcard
/// </summary>
fn connect(&mut self) -> Result<()>;
/// <summary>
/// Disconnect from Smartcard
/// </summary>
fn disconnect(&mut self) -> Result<()>;
/// <summary>
/// Transmit APDU Command to Smartcard
/// </summary>
/// <param name="apdu_cmd">Application Protocol Data Unit Command - ISO 7816</param>
/// <returns>Application Protocol Data Unit Response - ISO 7816</returns>
///
/// # Parameters
/// * `apdu_cmd` - Application Protocol Data Unit Command - ISO 7816
///
/// returns a Application Protocol Data Unit Response - ISO 7816
fn transmit(&self, apdu_cmd: APDUCommand) -> Result<APDUResponse>;
}