reformated files with rustfmt

This commit is contained in:
Kai Jan Kriegel 2021-12-26 02:33:05 +01:00
parent dce2bc30a8
commit 099c78d979
21 changed files with 271 additions and 216 deletions

View File

@ -1,8 +1,8 @@
use aes::Aes128;
use block_modes::{BlockMode, Cbc};
use block_modes::block_padding::NoPadding;
use crate::error::{Result, Error};
use super::Cipher; use super::Cipher;
use crate::error::{Error, Result};
use aes::Aes128;
use block_modes::block_padding::NoPadding;
use block_modes::{BlockMode, Cbc};
type Aes128Cbc = Cbc<Aes128, NoPadding>; type Aes128Cbc = Cbc<Aes128, NoPadding>;
@ -23,16 +23,16 @@ impl Cipher for AES {
let result = cipher.decrypt_vec(data); let result = cipher.decrypt_vec(data);
return match result { return match result {
Ok(data) => { Ok(data) } Ok(data) => Ok(data),
Err(err) => { Err(Error::BlockModeError(err)) } Err(err) => Err(Error::BlockModeError(err)),
} };
} }
} }
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use hex_literal::hex;
use crate::crypto::cipher::Cipher; use crate::crypto::cipher::Cipher;
use hex_literal::hex;
#[test] #[test]
fn encrypt() { fn encrypt() {

View File

@ -10,6 +10,6 @@ pub trait Cipher {
const BLOCK_SIZE: usize; const BLOCK_SIZE: usize;
const KEY_SIZE: usize; const KEY_SIZE: usize;
fn encrypt (data: &[u8], key: &[u8], iv: &[u8]) -> Result<Vec<u8>>; fn encrypt(data: &[u8], key: &[u8], iv: &[u8]) -> Result<Vec<u8>>;
fn decrypt(data: &[u8], key: &[u8], iv: &[u8]) -> Result<Vec<u8>>; fn decrypt(data: &[u8], key: &[u8], iv: &[u8]) -> Result<Vec<u8>>;
} }

View File

@ -1,9 +1,9 @@
//FIXME: Which TDES Mode should be used by this? //FIXME: Which TDES Mode should be used by this?
use des::TdesEde2;
use block_modes::{BlockMode, Cbc};
use block_modes::block_padding::NoPadding;
use crate::error::{Result, Error};
use crate::crypto::cipher::Cipher; use crate::crypto::cipher::Cipher;
use crate::error::{Error, Result};
use block_modes::block_padding::NoPadding;
use block_modes::{BlockMode, Cbc};
use des::TdesEde2;
type TDesEde2Cbc = Cbc<TdesEde2, NoPadding>; type TDesEde2Cbc = Cbc<TdesEde2, NoPadding>;
@ -22,19 +22,18 @@ impl Cipher for Tdes {
fn decrypt(data: &[u8], key: &[u8], iv: &[u8]) -> Result<Vec<u8>> { fn decrypt(data: &[u8], key: &[u8], iv: &[u8]) -> Result<Vec<u8>> {
let cipher = TDesEde2Cbc::new_var(&key, &iv)?; let cipher = TDesEde2Cbc::new_var(&key, &iv)?;
let result = cipher.decrypt_vec(data); let result = cipher.decrypt_vec(data);
return match result { return match result {
Ok(data) => { Ok(data) } Ok(data) => Ok(data),
Err(err) => { Err(Error::BlockModeError(err)) } Err(err) => Err(Error::BlockModeError(err)),
} };
} }
} }
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use hex_literal::hex;
use crate::crypto::cipher::Cipher; use crate::crypto::cipher::Cipher;
use hex_literal::hex;
#[test] #[test]
#[ignore] #[ignore]

View File

@ -1,9 +1,9 @@
//FIXME: Which TDES Mode should be used by this? //FIXME: Which TDES Mode should be used by this?
use des::TdesEde2;
use block_modes::{BlockMode, Cbc};
use block_modes::block_padding::NoPadding;
use crate::error::{Result, Error};
use crate::crypto::cipher::Cipher; use crate::crypto::cipher::Cipher;
use crate::error::{Error, Result};
use block_modes::block_padding::NoPadding;
use block_modes::{BlockMode, Cbc};
use des::TdesEde2;
type TDesEde2Cbc = Cbc<TdesEde2, NoPadding>; type TDesEde2Cbc = Cbc<TdesEde2, NoPadding>;
@ -22,19 +22,18 @@ impl Cipher for Tdes2k {
fn decrypt(data: &[u8], key: &[u8], iv: &[u8]) -> Result<Vec<u8>> { fn decrypt(data: &[u8], key: &[u8], iv: &[u8]) -> Result<Vec<u8>> {
let cipher = TDesEde2Cbc::new_var(&key, &iv)?; let cipher = TDesEde2Cbc::new_var(&key, &iv)?;
let result = cipher.decrypt_vec(data); let result = cipher.decrypt_vec(data);
return match result { return match result {
Ok(data) => { Ok(data) } Ok(data) => Ok(data),
Err(err) => { Err(Error::BlockModeError(err)) } Err(err) => Err(Error::BlockModeError(err)),
} };
} }
} }
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use hex_literal::hex;
use crate::crypto::cipher::Cipher; use crate::crypto::cipher::Cipher;
use hex_literal::hex;
#[test] #[test]
#[ignore] #[ignore]

View File

@ -1,9 +1,9 @@
//FIXME: Which TDES Mode should be used by this? //FIXME: Which TDES Mode should be used by this?
use des::TdesEde3;
use block_modes::{BlockMode, Cbc};
use block_modes::block_padding::NoPadding;
use crate::error::{Result, Error};
use crate::crypto::cipher::Cipher; use crate::crypto::cipher::Cipher;
use crate::error::{Error, Result};
use block_modes::block_padding::NoPadding;
use block_modes::{BlockMode, Cbc};
use des::TdesEde3;
type TDesEde3Cbc = Cbc<TdesEde3, NoPadding>; type TDesEde3Cbc = Cbc<TdesEde3, NoPadding>;
@ -22,19 +22,18 @@ impl Cipher for Tdes3k {
fn decrypt(data: &[u8], key: &[u8], iv: &[u8]) -> Result<Vec<u8>> { fn decrypt(data: &[u8], key: &[u8], iv: &[u8]) -> Result<Vec<u8>> {
let cipher = TDesEde3Cbc::new_var(&key, &iv)?; let cipher = TDesEde3Cbc::new_var(&key, &iv)?;
let result = cipher.decrypt_vec(data); let result = cipher.decrypt_vec(data);
return match result { return match result {
Ok(data) => { Ok(data) } Ok(data) => Ok(data),
Err(err) => { Err(Error::BlockModeError(err)) } Err(err) => Err(Error::BlockModeError(err)),
} };
} }
} }
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use hex_literal::hex;
use crate::crypto::cipher::Cipher; use crate::crypto::cipher::Cipher;
use hex_literal::hex;
#[test] #[test]
#[ignore] #[ignore]

View File

@ -1,6 +1,6 @@
use crate::crypto::cipher::{aes, tdes, tdes_2k, tdes_3k, Cipher};
use crate::crypto::cipher_type::CipherType; use crate::crypto::cipher_type::CipherType;
use crate::crypto::cipher_type::CipherType::*; use crate::crypto::cipher_type::CipherType::*;
use crate::crypto::cipher::{aes, tdes, tdes_2k, tdes_3k, Cipher};
use crate::error::Error; use crate::error::Error;
use crate::error::Result; use crate::error::Result;
@ -15,17 +15,21 @@ pub struct CipherKey {
cipher: CipherType, cipher: CipherType,
/// KeyVersion of Key /// KeyVersion of Key
key_version: u8 key_version: u8,
} }
impl CipherKey { impl CipherKey {
pub fn new(key: &[u8], cipher: CipherType, key_version: u8) -> Result<CipherKey> { pub fn new(key: &[u8], cipher: CipherType, key_version: u8) -> Result<CipherKey> {
if cipher == AES && key_version < 0x10 { if cipher == AES && key_version < 0x10 {
return Err(Error::Boxed(Box::new(simple_error!("KeyVersion is to low for AES Key (Minimum = 0x10)")))) return Err(Error::Boxed(Box::new(simple_error!(
"KeyVersion is to low for AES Key (Minimum = 0x10)"
))));
} }
if !check_key(key, cipher.clone()) { if !check_key(key, cipher.clone()) {
return Err(Error::Boxed(Box::new(simple_error!("Key is not valid for CipherType")))) return Err(Error::Boxed(Box::new(simple_error!(
"Key is not valid for CipherType"
))));
} }
let mut key: Box<[u8]> = Box::from(key); let mut key: Box<[u8]> = Box::from(key);
@ -36,7 +40,7 @@ impl CipherKey {
Ok(CipherKey { Ok(CipherKey {
cipher, cipher,
key_version, key_version,
key key,
}) })
} }
@ -45,10 +49,10 @@ impl CipherKey {
} }
pub fn new_empty(cipher: CipherType) -> Result<CipherKey> { pub fn new_empty(cipher: CipherType) -> Result<CipherKey> {
Ok(CipherKey{ Ok(CipherKey {
key: generate_empty_key(cipher.clone()), key: generate_empty_key(cipher.clone()),
key_version: if cipher == AES { 0x10u8 } else { 0x00u8 }, key_version: if cipher == AES { 0x10u8 } else { 0x00u8 },
cipher cipher,
}) })
} }
} }
@ -72,7 +76,11 @@ pub fn get_key_size(cipher: CipherType) -> usize {
/// Check Key Slice /// Check Key Slice
pub fn check_key(key: &[u8], cipher: CipherType) -> bool { pub fn check_key(key: &[u8], cipher: CipherType) -> bool {
if key.len() != get_key_size(cipher) { false } else { true } if key.len() != get_key_size(cipher) {
false
} else {
true
}
} }
/// Set Key Version for DES/TDES Keys /// Set Key Version for DES/TDES Keys
@ -80,7 +88,9 @@ pub fn check_key(key: &[u8], cipher: CipherType) -> bool {
/// Parity Bits are not used from DESFire Cars /// Parity Bits are not used from DESFire Cars
pub fn set_key_version(key: &[u8], version: u8) -> Box<[u8]> { pub fn set_key_version(key: &[u8], version: u8) -> Box<[u8]> {
let pow2 = [0x01u8, 0x02u8, 0x04u8, 0x08u8, 0x10u8, 0x20u8, 0x40u8, 0x80u8]; let pow2 = [
0x01u8, 0x02u8, 0x04u8, 0x08u8, 0x10u8, 0x20u8, 0x40u8, 0x80u8,
];
let mut new_key = key.to_vec(); let mut new_key = key.to_vec();

View File

@ -10,5 +10,5 @@ pub enum CipherType {
TDES3K, TDES3K,
/// AES /// AES
AES AES,
} }

View File

@ -1,5 +1,5 @@
pub mod cipher; pub mod cipher;
pub mod crc;
pub mod cipher_type;
pub mod cipher_key; pub mod cipher_key;
pub mod cipher_type;
pub mod crc;
pub mod util; pub mod util;

View File

@ -1,10 +1,15 @@
use crate::error::{Result, Error}; use crate::error::{Error, Result};
use simple_error::simple_error; use simple_error::simple_error;
/// Extracts the the last `n` bytes of a slice. n being the blocksize. /// Extracts the the last `n` bytes of a slice. n being the blocksize.
pub fn extract_last_block(data: &[u8], blocksize: usize) -> Result<&[u8]> { pub fn extract_last_block(data: &[u8], blocksize: usize) -> Result<&[u8]> {
if data.len() % blocksize != 0 { if data.len() % blocksize != 0 {
return Err(simple_error!("Data is not compatible with blocksize: data(length): {}, blocksize: {}.", data.len(), blocksize).into()) return Err(simple_error!(
"Data is not compatible with blocksize: data(length): {}, blocksize: {}.",
data.len(),
blocksize
)
.into());
} }
Ok(&data[(data.len() - blocksize)..]) Ok(&data[(data.len() - blocksize)..])

View File

@ -1,6 +1,5 @@
use num_derive::FromPrimitive; use num_derive::FromPrimitive;
/// <summary> /// <summary>
/// hold the Access Rights for changing application keys (Change Key command) /// hold the Access Rights for changing application keys (Change Key command)
/// </summary> /// </summary>
@ -28,13 +27,13 @@ pub enum ChangeApplicationKey {
#[derive(Clone, Copy)] #[derive(Clone, Copy)]
pub enum ChangeMasterKey { pub enum ChangeMasterKey {
/// <summary> /// <summary>
/// Application master key is not changeable anymore (frozen) /// Application master key is not changeable anymore (frozen)
/// </summary> /// </summary>
FROZEN = 0x00, FROZEN = 0x00,
/// <summary> /// <summary>
/// Application master key is changeable (authentication with the current application master key necessary, default) /// Application master key is changeable (authentication with the current application master key necessary, default)
/// </summary> /// </summary>
CHANGEABLE = 0x01, CHANGEABLE = 0x01,
} }
@ -44,16 +43,15 @@ pub enum ChangeMasterKey {
#[repr(u8)] #[repr(u8)]
#[derive(Clone, Copy)] #[derive(Clone, Copy)]
pub enum ChangeMasterKeySettings { pub enum ChangeMasterKeySettings {
/// <summary>
/// configuration not changeable anymore (frozen)
/// </summary>
FROZEN = 0x00,
/// <summary> /// <summary>
/// configuration not changeable anymore (frozen) /// this configuration is changeable if authenticated with the application master key (default)
/// </summary> /// </summary>
FROZEN = 0x00, WITHMASTERKEY = 0x08,
/// <summary>
/// this configuration is changeable if authenticated with the application master key (default)
/// </summary>
WITHMASTERKEY = 0x08
} }
/// <summary> /// <summary>
@ -62,15 +60,15 @@ WITHMASTERKEY = 0x08
#[repr(u8)] #[repr(u8)]
#[derive(Clone, Copy)] #[derive(Clone, Copy)]
pub enum CreateDeleteFile { pub enum CreateDeleteFile {
/// <summary> /// <summary>
/// “Create File”/ “Delete File”is permitted only with application master key authentication /// “Create File”/ “Delete File”is permitted only with application master key authentication
/// </summary> /// </summary>
ONLYMASTERKEY = 0x00, ONLYMASTERKEY = 0x00,
/// <summary> /// <summary>
/// “Create File”/ “Delete File”is permitted also without application master key authentication (default) /// “Create File”/ “Delete File”is permitted also without application master key authentication (default)
/// </summary> /// </summary>
NOKEY = 0x04, NOKEY = 0x04,
} }
/// <summary> /// <summary>
@ -88,7 +86,7 @@ pub enum CryptoOperationsType {
#[derive(Clone, Copy)] #[derive(Clone, Copy)]
pub enum FileAccessRights { pub enum FileAccessRights {
FREE = 0x0E, FREE = 0x0E,
NEVER = 0x0F NEVER = 0x0F,
} }
#[repr(u8)] #[repr(u8)]
@ -107,7 +105,7 @@ pub enum FileCommunication {
/// <summary> /// <summary>
/// Fully DES/3DES enciphered communication /// Fully DES/3DES enciphered communication
/// </summary> /// </summary>
ENCRYPT = 0x03 ENCRYPT = 0x03,
} }
/// <summary> /// <summary>
@ -134,7 +132,7 @@ pub enum FileDirectoryAccess {
#[derive(Clone, Copy)] #[derive(Clone, Copy)]
pub enum FileIdentifiers { pub enum FileIdentifiers {
NOTUSED = 0x00, NOTUSED = 0x00,
USED = 0x20 USED = 0x20,
} }
#[repr(u8)] #[repr(u8)]
@ -163,7 +161,7 @@ pub enum FileTypes {
/// <summary> /// <summary>
/// Cyclic Record Files with Backup /// Cyclic Record Files with Backup
/// </summary> /// </summary>
CYCLICRECORD = 0x04 CYCLICRECORD = 0x04,
} }
mod apduinstructions; mod apduinstructions;

View File

@ -1,5 +1,5 @@
use std::io;
use std::fmt; use std::fmt;
use std::io;
#[derive(Debug)] #[derive(Debug)]
pub enum Error { pub enum Error {
@ -66,7 +66,10 @@ impl fmt::Display for Error {
write!(f, "SW2: Command code not supported.") write!(f, "SW2: Command code not supported.")
} }
Error::IntegrityError => { Error::IntegrityError => {
write!(f, "SW2: CRC or MAC does not match data. Paddingbytes not valid.") write!(
f,
"SW2: CRC or MAC does not match data. Paddingbytes not valid."
)
} }
Error::NoSuchKey => { Error::NoSuchKey => {
write!(f, "SW2: Invalid key number specified.") write!(f, "SW2: Invalid key number specified.")
@ -75,7 +78,10 @@ impl fmt::Display for Error {
write!(f, "SW2: Length of command string invalid.") write!(f, "SW2: Length of command string invalid.")
} }
Error::PermissionDenied => { Error::PermissionDenied => {
write!(f, "SW2: Current configuration / status does not allow the requested command.") write!(
f,
"SW2: Current configuration / status does not allow the requested command."
)
} }
Error::ParameterError => { Error::ParameterError => {
write!(f, "SW2: Value of the parameter(s) invalid.") write!(f, "SW2: Value of the parameter(s) invalid.")
@ -84,7 +90,10 @@ impl fmt::Display for Error {
write!(f, "SW2: Currently not allowed to authenticate. Keeptrying until full delay is spent.") write!(f, "SW2: Currently not allowed to authenticate. Keeptrying until full delay is spent.")
} }
Error::AuthenticationError => { Error::AuthenticationError => {
write!(f, "SW2: Current authentication status does not allow the requested command.") write!(
f,
"SW2: Current authentication status does not allow the requested command."
)
} }
Error::BoundaryError => { Error::BoundaryError => {
write!(f, "SW2: Attempt to read/write data from/to beyond the files/records limits. Attempt to exceed the limits of a value file.") write!(f, "SW2: Attempt to read/write data from/to beyond the files/records limits. Attempt to exceed the limits of a value file.")
@ -139,7 +148,9 @@ impl From<io::Error> for Error {
} }
impl From<simple_error::SimpleError> for Error { impl From<simple_error::SimpleError> for Error {
fn from(e: simple_error::SimpleError) -> Error { Error::Simple(e) } fn from(e: simple_error::SimpleError) -> Error {
Error::Simple(e)
}
} }
impl From<block_modes::BlockModeError> for Error { impl From<block_modes::BlockModeError> for Error {
@ -155,11 +166,15 @@ impl From<block_modes::InvalidKeyIvLength> for Error {
} }
impl From<hex::FromHexError> for Error { impl From<hex::FromHexError> for Error {
fn from(e: hex::FromHexError) -> Error { Error::FromHexError(e) } fn from(e: hex::FromHexError) -> Error {
Error::FromHexError(e)
}
} }
impl From<block_modes::block_padding::PadError> for Error { impl From<block_modes::block_padding::PadError> for Error {
fn from(e: block_modes::block_padding::PadError) -> Error { Error::PadError(e) } fn from(e: block_modes::block_padding::PadError) -> Error {
Error::PadError(e)
}
} }
pub(crate) type Result<T> = std::result::Result<T, Error>; pub(crate) type Result<T> = std::result::Result<T, Error>;

View File

@ -1,7 +1,7 @@
use crate::error::{Error, Result};
use std::convert::TryFrom;
use std::fmt; use std::fmt;
use std::fmt::Formatter; use std::fmt::Formatter;
use std::convert::TryFrom;
use crate::error::{Result, Error};
#[repr(u8)] #[repr(u8)]
#[derive(Eq, PartialEq, Hash, Debug, Clone)] #[derive(Eq, PartialEq, Hash, Debug, Clone)]
@ -78,7 +78,9 @@ pub enum IsoCase {
} }
impl Default for IsoCase { impl Default for IsoCase {
fn default() -> Self { IsoCase::Case1 } fn default() -> Self {
IsoCase::Case1
}
} }
#[repr(u8)] #[repr(u8)]
@ -106,7 +108,9 @@ pub enum SCardProtocol {
} }
impl Default for SCardProtocol { impl Default for SCardProtocol {
fn default() -> Self { SCardProtocol::Any } fn default() -> Self {
SCardProtocol::Any
}
} }
#[derive(Eq, PartialEq, Hash, Debug, Default, Clone)] #[derive(Eq, PartialEq, Hash, Debug, Default, Clone)]
@ -155,10 +159,7 @@ impl TryFrom<APDUCommand> for Vec<u8> {
v.push(cmd.le as u8); v.push(cmd.le as u8);
} }
} }
_ => { _ => return Err(Error::InvalidIsoCase),
return Err(Error::InvalidIsoCase)
}
} }
Ok(v) Ok(v)
} }
@ -180,10 +181,18 @@ impl fmt::Display for APDUCommand {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
match self.case { match self.case {
IsoCase::Case1 => { IsoCase::Case1 => {
write!(f, "(CASE: 1) cla: {:#X} | ins: {:#X} | p1: {:#X} | p2: {:#X}", self.cla, self.ins, self.p1, self.p2) write!(
f,
"(CASE: 1) cla: {:#X} | ins: {:#X} | p1: {:#X} | p2: {:#X}",
self.cla, self.ins, self.p1, self.p2
)
} }
IsoCase::Case2Short | IsoCase::Case2Extended => { IsoCase::Case2Short | IsoCase::Case2Extended => {
write!(f, "(CASE: 2) cla: {:#X} | ins: {:#X} | p1: {:#X} | p2: {:#X} | LE: {:#X}", self.cla, self.ins, self.p1, self.p2, self.le) write!(
f,
"(CASE: 2) cla: {:#X} | ins: {:#X} | p1: {:#X} | p2: {:#X} | LE: {:#X}",
self.cla, self.ins, self.p1, self.p2, self.le
)
} }
IsoCase::Case3Short | IsoCase::Case3Extended => { IsoCase::Case3Short | IsoCase::Case3Extended => {
write!(f, "(CASE: 3) cla: {:#X} | ins: {:#X} | p1: {:#X} | p2: {:#X} | LC: {:#X} | data: [ ", self.cla, self.ins, self.p1, self.p2, self.lc())?; write!(f, "(CASE: 3) cla: {:#X} | ins: {:#X} | p1: {:#X} | p2: {:#X} | LC: {:#X} | data: [ ", self.cla, self.ins, self.p1, self.p2, self.lc())?;
@ -205,11 +214,11 @@ impl fmt::Display for APDUCommand {
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use crate::iso7816_4::apducommand::{APDUCommand, SCardProtocol, IsoCase}; use crate::iso7816_4::apducommand::{APDUCommand, IsoCase, SCardProtocol};
#[test] #[test]
fn compare() { fn compare() {
let command1 = APDUCommand{ let command1 = APDUCommand {
case: IsoCase::Case4Short, case: IsoCase::Case4Short,
protocol: SCardProtocol::Unset, protocol: SCardProtocol::Unset,
cla: 0x90, cla: 0x90,
@ -218,7 +227,7 @@ mod tests {
..Default::default() ..Default::default()
}; };
let command2 = APDUCommand{ let command2 = APDUCommand {
case: IsoCase::Case4Short, case: IsoCase::Case4Short,
protocol: SCardProtocol::Unset, protocol: SCardProtocol::Unset,
cla: 0x90, cla: 0x90,
@ -232,7 +241,7 @@ mod tests {
#[test] #[test]
fn compare_diff() { fn compare_diff() {
let command1 = APDUCommand{ let command1 = APDUCommand {
case: IsoCase::Case4Short, case: IsoCase::Case4Short,
protocol: SCardProtocol::Unset, protocol: SCardProtocol::Unset,
cla: 0x90, cla: 0x90,
@ -241,7 +250,7 @@ mod tests {
..Default::default() ..Default::default()
}; };
let command2 = APDUCommand{ let command2 = APDUCommand {
case: IsoCase::Case4Short, case: IsoCase::Case4Short,
protocol: SCardProtocol::Unset, protocol: SCardProtocol::Unset,
cla: 0x90, cla: 0x90,
@ -255,7 +264,7 @@ mod tests {
#[test] #[test]
fn to_string_case1() { fn to_string_case1() {
let command1 = APDUCommand{ let command1 = APDUCommand {
case: IsoCase::Case1, case: IsoCase::Case1,
cla: 0x90, cla: 0x90,
ins: 0x1A, ins: 0x1A,
@ -263,12 +272,15 @@ mod tests {
}; };
println!("{}", command1.to_string()); println!("{}", command1.to_string());
assert_eq!("(CASE: 1) cla: 0x90 | ins: 0x1A | p1: 0x0 | p2: 0x0", command1.to_string()); assert_eq!(
"(CASE: 1) cla: 0x90 | ins: 0x1A | p1: 0x0 | p2: 0x0",
command1.to_string()
);
} }
#[test] #[test]
fn to_string_case2() { fn to_string_case2() {
let command1 = APDUCommand{ let command1 = APDUCommand {
case: IsoCase::Case2Short, case: IsoCase::Case2Short,
cla: 0x90, cla: 0x90,
ins: 0x1A, ins: 0x1A,
@ -276,12 +288,15 @@ mod tests {
}; };
println!("{}", command1.to_string()); println!("{}", command1.to_string());
assert_eq!("(CASE: 2) cla: 0x90 | ins: 0x1A | p1: 0x0 | p2: 0x0 | LE: 0x0", command1.to_string()); assert_eq!(
"(CASE: 2) cla: 0x90 | ins: 0x1A | p1: 0x0 | p2: 0x0 | LE: 0x0",
command1.to_string()
);
} }
#[test] #[test]
fn to_string_case3() { fn to_string_case3() {
let command1 = APDUCommand{ let command1 = APDUCommand {
case: IsoCase::Case3Short, case: IsoCase::Case3Short,
cla: 0x90, cla: 0x90,
ins: 0x1A, ins: 0x1A,
@ -290,12 +305,15 @@ mod tests {
}; };
println!("{}", command1.to_string()); println!("{}", command1.to_string());
assert_eq!("(CASE: 3) cla: 0x90 | ins: 0x1A | p1: 0x0 | p2: 0x0 | LC: 0x3 | data: [ 0x1 0x2 0x3 ]", command1.to_string()); assert_eq!(
"(CASE: 3) cla: 0x90 | ins: 0x1A | p1: 0x0 | p2: 0x0 | LC: 0x3 | data: [ 0x1 0x2 0x3 ]",
command1.to_string()
);
} }
#[test] #[test]
fn to_string_case4() { fn to_string_case4() {
let command1 = APDUCommand{ let command1 = APDUCommand {
case: IsoCase::Case4Short, case: IsoCase::Case4Short,
cla: 0x90, cla: 0x90,
ins: 0x1A, ins: 0x1A,

View File

@ -1,7 +1,11 @@
use crate::error::Error::{
ApplicationNotFound, AuthenticationDelay, AuthenticationError, BoundaryError, CommandAborted,
DuplicateError, FileNotFound, IllegalCommandCode, IntegrityError, InvalidStatusWord,
LengthError, NoSuchKey, ParameterError, PermissionDenied,
};
use crate::error::Result;
use crate::iso7816_4::apdustatuswords::{APDUStatusWord, APDUStatusWord2}; use crate::iso7816_4::apdustatuswords::{APDUStatusWord, APDUStatusWord2};
use crate::error::{Result};
use num_traits::FromPrimitive; use num_traits::FromPrimitive;
use crate::error::Error::{InvalidStatusWord, IllegalCommandCode, IntegrityError, NoSuchKey, LengthError, PermissionDenied, ParameterError, AuthenticationDelay, AuthenticationError, BoundaryError, CommandAborted, DuplicateError, FileNotFound, ApplicationNotFound};
use std::fmt; use std::fmt;
#[derive(Eq, PartialEq, Hash, Debug, Default)] #[derive(Eq, PartialEq, Hash, Debug, Default)]
@ -22,7 +26,9 @@ impl From<APDUResponse> for Vec<u8> {
let mut v: Vec<u8> = vec![]; let mut v: Vec<u8> = vec![];
match resp.body { match resp.body {
None => {} None => {}
Some(body) => {v.extend(body);} Some(body) => {
v.extend(body);
}
} }
v.push(resp.sw1); v.push(resp.sw1);
v.push(resp.sw2); v.push(resp.sw2);
@ -35,9 +41,13 @@ impl fmt::Display for APDUResponse {
match &self.body { match &self.body {
None => { None => {
write!(f, "SW1: {:#X} | SW2: 0x{:#X}", self.sw1, self.sw2) write!(f, "SW1: {:#X} | SW2: 0x{:#X}", self.sw1, self.sw2)
}, }
Some(body) => { Some(body) => {
write!(f, "SW1: {:#X} | SW2: {:#X} | Body: {:#X?}", self.sw1, self.sw2, body) write!(
f,
"SW1: {:#X} | SW2: {:#X} | Body: {:#X?}",
self.sw1, self.sw2, body
)
} }
} }
} }
@ -66,12 +76,17 @@ impl APDUResponse {
0x61 => Ok(APDUStatusWord::DataReady), 0x61 => Ok(APDUStatusWord::DataReady),
0x62 => Ok(APDUStatusWord::StorageNotChanged), 0x62 => Ok(APDUStatusWord::StorageNotChanged),
0x63 => { 0x63 => {
if (self.sw2 & 0xF0) == 0xC0 { Ok(APDUStatusWord::CounterReached) } else { Ok(APDUStatusWord::StorageChanged) } if (self.sw2 & 0xF0) == 0xC0 {
}, Ok(APDUStatusWord::CounterReached)
} else {
Ok(APDUStatusWord::StorageChanged)
}
}
0x64 => Ok(APDUStatusWord::ExecutionErrorWithoutChange), 0x64 => Ok(APDUStatusWord::ExecutionErrorWithoutChange),
0x65 => Ok(APDUStatusWord::ExecutionErrorWithChange), 0x65 => Ok(APDUStatusWord::ExecutionErrorWithChange),
0x6C => Ok(APDUStatusWord::InvalidLe), 0x6C => Ok(APDUStatusWord::InvalidLe),
_ => FromPrimitive::from_u16(((self.sw1 as u16) << 8) | self.sw2 as u16).ok_or(InvalidStatusWord) _ => FromPrimitive::from_u16(((self.sw1 as u16) << 8) | self.sw2 as u16)
.ok_or(InvalidStatusWord),
} }
} }
@ -90,24 +105,26 @@ impl APDUResponse {
pub fn check(&self) -> Result<()> { pub fn check(&self) -> Result<()> {
if self.sw1 == 0x91 { if self.sw1 == 0x91 {
return match FromPrimitive::from_u8(self.sw2) { return match FromPrimitive::from_u8(self.sw2) {
Some(APDUStatusWord2::OperationOk) => { Ok(()) } Some(APDUStatusWord2::OperationOk) => Ok(()),
Some(APDUStatusWord2::NoChanges) => { Ok(()) } Some(APDUStatusWord2::NoChanges) => Ok(()),
Some(APDUStatusWord2::IllegalCommandCode) => {Err(IllegalCommandCode)} Some(APDUStatusWord2::IllegalCommandCode) => Err(IllegalCommandCode),
Some(APDUStatusWord2::IntegrityError) => {Err(IntegrityError)} Some(APDUStatusWord2::IntegrityError) => Err(IntegrityError),
Some(APDUStatusWord2::NoSuchKey) => {Err(NoSuchKey)} Some(APDUStatusWord2::NoSuchKey) => Err(NoSuchKey),
Some(APDUStatusWord2::LengthError) => {Err(LengthError)} Some(APDUStatusWord2::LengthError) => Err(LengthError),
Some(APDUStatusWord2::PermissionDenied) => {Err(PermissionDenied)} Some(APDUStatusWord2::PermissionDenied) => Err(PermissionDenied),
Some(APDUStatusWord2::ParameterError) => {Err(ParameterError)} Some(APDUStatusWord2::ParameterError) => Err(ParameterError),
Some(APDUStatusWord2::AuthenticationDelay) => {Err(AuthenticationDelay)} Some(APDUStatusWord2::AuthenticationDelay) => Err(AuthenticationDelay),
Some(APDUStatusWord2::AuthenticationError) => {Err(AuthenticationError)} Some(APDUStatusWord2::AuthenticationError) => Err(AuthenticationError),
Some(APDUStatusWord2::AdditionalFrame) => {Ok(())} Some(APDUStatusWord2::AdditionalFrame) => Ok(()),
Some(APDUStatusWord2::BoundaryError) => {Err(BoundaryError)} Some(APDUStatusWord2::BoundaryError) => Err(BoundaryError),
Some(APDUStatusWord2::CommandAborted) => {Err(CommandAborted)} Some(APDUStatusWord2::CommandAborted) => Err(CommandAborted),
Some(APDUStatusWord2::DuplicateError) => {Err(DuplicateError)} Some(APDUStatusWord2::DuplicateError) => Err(DuplicateError),
Some(APDUStatusWord2::FileNotFound) => {Err(FileNotFound)} Some(APDUStatusWord2::FileNotFound) => Err(FileNotFound),
Some(APDUStatusWord2::ApplicationNotFound) => {Err(ApplicationNotFound)} Some(APDUStatusWord2::ApplicationNotFound) => Err(ApplicationNotFound),
None => { Err(InvalidStatusWord)} None => Err(InvalidStatusWord),
};
} else {
Err(InvalidStatusWord)
} }
} else { Err(InvalidStatusWord) }
} }
} }

View File

@ -108,19 +108,15 @@ pub enum APDUStatusWord {
/// Parameter P1/P2 falsch /// Parameter P1/P2 falsch
WrongParameters2 = 0x6B00, WrongParameters2 = 0x6B00,
/// Falsche Lnge Le; xx gibt die korrekte Lnge an Statuswort zur Steuerung des T=0-Protokolls /// Falsche Lnge Le; xx gibt die korrekte Lnge an Statuswort zur Steuerung des T=0-Protokolls
InvalidLe = 0x6C00, InvalidLe = 0x6C00,
/// Das Kommando (INS) wird nicht untersttzt /// Das Kommando (INS) wird nicht untersttzt
InstructionNotSupported = 0x6D00, InstructionNotSupported = 0x6D00,
/// Die Kommandoklasse (CLA) wird nicht untersttzt /// Die Kommandoklasse (CLA) wird nicht untersttzt
ClassNotSupported = 0x6E00, ClassNotSupported = 0x6E00,
/// Kommando wurde mit unbekanntem Fehler abgebrochen /// Kommando wurde mit unbekanntem Fehler abgebrochen
UnknownError = 0x6F00, UnknownError = 0x6F00,
@ -129,7 +125,6 @@ pub enum APDUStatusWord {
/// OK /// OK
OK = 0x9100, OK = 0x9100,
} }
#[derive(FromPrimitive)] #[derive(FromPrimitive)]

View File

@ -1,27 +1,27 @@
use crate::iso7816_4::apduresponse::APDUResponse;
use crate::iso7816_4::apducommand::APDUCommand; use crate::iso7816_4::apducommand::APDUCommand;
use crate::iso7816_4::apduresponse::APDUResponse;
use error::Result; use error::Result;
pub mod crypto; pub mod crypto;
pub mod iso7816_4;
pub mod desfire; pub mod desfire;
pub mod error; pub mod error;
pub mod iso7816_4;
pub trait Card { pub trait Card {
/// <summary> /// <summary>
/// Connect to Smartcard /// Connect to Smartcard
/// </summary> /// </summary>
fn connect(&mut self) -> Result<()>; fn connect(&mut self) -> Result<()>;
/// <summary> /// <summary>
/// Disconnect from Smartcard /// Disconnect from Smartcard
/// </summary> /// </summary>
fn disconnect(&mut self) -> Result<()>; fn disconnect(&mut self) -> Result<()>;
/// <summary> /// <summary>
/// Transmit APDU Command to Smartcard /// Transmit APDU Command to Smartcard
/// </summary> /// </summary>
/// <param name="apdu_cmd">Application Protocol Data Unit Command - ISO 7816</param> /// <param name="apdu_cmd">Application Protocol Data Unit Command - ISO 7816</param>
/// <returns>Application Protocol Data Unit Response - ISO 7816</returns> /// <returns>Application Protocol Data Unit Response - ISO 7816</returns>
fn transmit(&self, apdu_cmd: APDUCommand) -> Result<APDUResponse>; fn transmit(&self, apdu_cmd: APDUCommand) -> Result<APDUResponse>;
} }