mirror of
https://gitlab.com/fabinfra/fabaccess/nfc_rs.git
synced 2025-03-12 06:41:46 +01:00
reformated files with rustfmt
This commit is contained in:
parent
dce2bc30a8
commit
099c78d979
@ -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 crate::error::{Error, Result};
|
||||
use aes::Aes128;
|
||||
use block_modes::block_padding::NoPadding;
|
||||
use block_modes::{BlockMode, Cbc};
|
||||
|
||||
type Aes128Cbc = Cbc<Aes128, NoPadding>;
|
||||
|
||||
@ -23,16 +23,16 @@ impl Cipher for AES {
|
||||
|
||||
let result = cipher.decrypt_vec(data);
|
||||
return match result {
|
||||
Ok(data) => { Ok(data) }
|
||||
Err(err) => { Err(Error::BlockModeError(err)) }
|
||||
}
|
||||
Ok(data) => Ok(data),
|
||||
Err(err) => Err(Error::BlockModeError(err)),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use hex_literal::hex;
|
||||
use crate::crypto::cipher::Cipher;
|
||||
use hex_literal::hex;
|
||||
|
||||
#[test]
|
||||
fn encrypt() {
|
||||
|
@ -10,6 +10,6 @@ pub trait Cipher {
|
||||
const BLOCK_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>>;
|
||||
}
|
@ -1,9 +1,9 @@
|
||||
//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::error::{Error, Result};
|
||||
use block_modes::block_padding::NoPadding;
|
||||
use block_modes::{BlockMode, Cbc};
|
||||
use des::TdesEde2;
|
||||
|
||||
type TDesEde2Cbc = Cbc<TdesEde2, NoPadding>;
|
||||
|
||||
@ -22,19 +22,18 @@ impl Cipher for Tdes {
|
||||
fn decrypt(data: &[u8], key: &[u8], iv: &[u8]) -> Result<Vec<u8>> {
|
||||
let cipher = TDesEde2Cbc::new_var(&key, &iv)?;
|
||||
|
||||
|
||||
let result = cipher.decrypt_vec(data);
|
||||
return match result {
|
||||
Ok(data) => { Ok(data) }
|
||||
Err(err) => { Err(Error::BlockModeError(err)) }
|
||||
}
|
||||
Ok(data) => Ok(data),
|
||||
Err(err) => Err(Error::BlockModeError(err)),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use hex_literal::hex;
|
||||
use crate::crypto::cipher::Cipher;
|
||||
use hex_literal::hex;
|
||||
|
||||
#[test]
|
||||
#[ignore]
|
||||
|
@ -1,9 +1,9 @@
|
||||
//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::error::{Error, Result};
|
||||
use block_modes::block_padding::NoPadding;
|
||||
use block_modes::{BlockMode, Cbc};
|
||||
use des::TdesEde2;
|
||||
|
||||
type TDesEde2Cbc = Cbc<TdesEde2, NoPadding>;
|
||||
|
||||
@ -22,19 +22,18 @@ impl Cipher for Tdes2k {
|
||||
fn decrypt(data: &[u8], key: &[u8], iv: &[u8]) -> Result<Vec<u8>> {
|
||||
let cipher = TDesEde2Cbc::new_var(&key, &iv)?;
|
||||
|
||||
|
||||
let result = cipher.decrypt_vec(data);
|
||||
return match result {
|
||||
Ok(data) => { Ok(data) }
|
||||
Err(err) => { Err(Error::BlockModeError(err)) }
|
||||
}
|
||||
Ok(data) => Ok(data),
|
||||
Err(err) => Err(Error::BlockModeError(err)),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use hex_literal::hex;
|
||||
use crate::crypto::cipher::Cipher;
|
||||
use hex_literal::hex;
|
||||
|
||||
#[test]
|
||||
#[ignore]
|
||||
|
@ -1,9 +1,9 @@
|
||||
//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::error::{Error, Result};
|
||||
use block_modes::block_padding::NoPadding;
|
||||
use block_modes::{BlockMode, Cbc};
|
||||
use des::TdesEde3;
|
||||
|
||||
type TDesEde3Cbc = Cbc<TdesEde3, NoPadding>;
|
||||
|
||||
@ -22,19 +22,18 @@ impl Cipher for Tdes3k {
|
||||
fn decrypt(data: &[u8], key: &[u8], iv: &[u8]) -> Result<Vec<u8>> {
|
||||
let cipher = TDesEde3Cbc::new_var(&key, &iv)?;
|
||||
|
||||
|
||||
let result = cipher.decrypt_vec(data);
|
||||
return match result {
|
||||
Ok(data) => { Ok(data) }
|
||||
Err(err) => { Err(Error::BlockModeError(err)) }
|
||||
}
|
||||
Ok(data) => Ok(data),
|
||||
Err(err) => Err(Error::BlockModeError(err)),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use hex_literal::hex;
|
||||
use crate::crypto::cipher::Cipher;
|
||||
use hex_literal::hex;
|
||||
|
||||
#[test]
|
||||
#[ignore]
|
||||
|
@ -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::{aes, tdes, tdes_2k, tdes_3k, Cipher};
|
||||
use crate::error::Error;
|
||||
use crate::error::Result;
|
||||
|
||||
@ -15,17 +15,21 @@ pub struct CipherKey {
|
||||
cipher: CipherType,
|
||||
|
||||
/// KeyVersion of Key
|
||||
key_version: u8
|
||||
key_version: u8,
|
||||
}
|
||||
|
||||
impl CipherKey {
|
||||
pub fn new(key: &[u8], cipher: CipherType, key_version: u8) -> Result<CipherKey> {
|
||||
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()) {
|
||||
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);
|
||||
@ -36,7 +40,7 @@ impl CipherKey {
|
||||
Ok(CipherKey {
|
||||
cipher,
|
||||
key_version,
|
||||
key
|
||||
key,
|
||||
})
|
||||
}
|
||||
|
||||
@ -45,10 +49,10 @@ impl CipherKey {
|
||||
}
|
||||
|
||||
pub fn new_empty(cipher: CipherType) -> Result<CipherKey> {
|
||||
Ok(CipherKey{
|
||||
Ok(CipherKey {
|
||||
key: generate_empty_key(cipher.clone()),
|
||||
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
|
||||
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
|
||||
@ -80,7 +88,9 @@ pub fn check_key(key: &[u8], cipher: CipherType) -> bool {
|
||||
/// Parity Bits are not used from DESFire Cars
|
||||
|
||||
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();
|
||||
|
||||
|
@ -10,5 +10,5 @@ pub enum CipherType {
|
||||
TDES3K,
|
||||
|
||||
/// AES
|
||||
AES
|
||||
AES,
|
||||
}
|
@ -1,5 +1,5 @@
|
||||
pub mod cipher;
|
||||
pub mod crc;
|
||||
pub mod cipher_type;
|
||||
pub mod cipher_key;
|
||||
pub mod cipher_type;
|
||||
pub mod crc;
|
||||
pub mod util;
|
@ -1,10 +1,15 @@
|
||||
use crate::error::{Result, Error};
|
||||
use crate::error::{Error, Result};
|
||||
use simple_error::simple_error;
|
||||
|
||||
/// Extracts the the last `n` bytes of a slice. n being the blocksize.
|
||||
pub fn extract_last_block(data: &[u8], blocksize: usize) -> Result<&[u8]> {
|
||||
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)..])
|
||||
|
@ -1,6 +1,5 @@
|
||||
use num_derive::FromPrimitive;
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// hold the Access Rights for changing application keys (Change Key command)
|
||||
/// </summary>
|
||||
@ -28,13 +27,13 @@ pub enum ChangeApplicationKey {
|
||||
#[derive(Clone, Copy)]
|
||||
pub enum ChangeMasterKey {
|
||||
/// <summary>
|
||||
/// Application master key is not changeable anymore (frozen)
|
||||
/// </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>
|
||||
/// Application master key is changeable (authentication with the current application master key necessary, default)
|
||||
/// </summary>
|
||||
CHANGEABLE = 0x01,
|
||||
}
|
||||
|
||||
@ -44,16 +43,15 @@ pub enum ChangeMasterKey {
|
||||
#[repr(u8)]
|
||||
#[derive(Clone, Copy)]
|
||||
pub enum ChangeMasterKeySettings {
|
||||
/// <summary>
|
||||
/// configuration not changeable anymore (frozen)
|
||||
/// </summary>
|
||||
FROZEN = 0x00,
|
||||
|
||||
/// <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>
|
||||
/// this configuration is changeable if authenticated with the application master key (default)
|
||||
/// </summary>
|
||||
WITHMASTERKEY = 0x08,
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -62,15 +60,15 @@ WITHMASTERKEY = 0x08
|
||||
#[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 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>
|
||||
/// “Create File”/ “Delete File”is permitted also without application master key authentication (default)
|
||||
/// </summary>
|
||||
NOKEY = 0x04,
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -88,7 +86,7 @@ pub enum CryptoOperationsType {
|
||||
#[derive(Clone, Copy)]
|
||||
pub enum FileAccessRights {
|
||||
FREE = 0x0E,
|
||||
NEVER = 0x0F
|
||||
NEVER = 0x0F,
|
||||
}
|
||||
|
||||
#[repr(u8)]
|
||||
@ -107,7 +105,7 @@ pub enum FileCommunication {
|
||||
/// <summary>
|
||||
/// Fully DES/3DES enciphered communication
|
||||
/// </summary>
|
||||
ENCRYPT = 0x03
|
||||
ENCRYPT = 0x03,
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -134,7 +132,7 @@ pub enum FileDirectoryAccess {
|
||||
#[derive(Clone, Copy)]
|
||||
pub enum FileIdentifiers {
|
||||
NOTUSED = 0x00,
|
||||
USED = 0x20
|
||||
USED = 0x20,
|
||||
}
|
||||
|
||||
#[repr(u8)]
|
||||
@ -163,7 +161,7 @@ pub enum FileTypes {
|
||||
/// <summary>
|
||||
/// Cyclic Record Files with Backup
|
||||
/// </summary>
|
||||
CYCLICRECORD = 0x04
|
||||
CYCLICRECORD = 0x04,
|
||||
}
|
||||
|
||||
mod apduinstructions;
|
||||
|
29
src/error.rs
29
src/error.rs
@ -1,5 +1,5 @@
|
||||
use std::io;
|
||||
use std::fmt;
|
||||
use std::io;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum Error {
|
||||
@ -66,7 +66,10 @@ impl fmt::Display for Error {
|
||||
write!(f, "SW2: Command code not supported.")
|
||||
}
|
||||
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 => {
|
||||
write!(f, "SW2: Invalid key number specified.")
|
||||
@ -75,7 +78,10 @@ impl fmt::Display for Error {
|
||||
write!(f, "SW2: Length of command string invalid.")
|
||||
}
|
||||
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 => {
|
||||
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.")
|
||||
}
|
||||
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 => {
|
||||
write!(f, "SW2: Attempt to read/write data from/to beyond the file’s/record’s 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 {
|
||||
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 {
|
||||
@ -155,11 +166,15 @@ impl From<block_modes::InvalidKeyIvLength> 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 {
|
||||
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>;
|
||||
|
@ -1,7 +1,7 @@
|
||||
use crate::error::{Error, Result};
|
||||
use std::convert::TryFrom;
|
||||
use std::fmt;
|
||||
use std::fmt::Formatter;
|
||||
use std::convert::TryFrom;
|
||||
use crate::error::{Result, Error};
|
||||
|
||||
#[repr(u8)]
|
||||
#[derive(Eq, PartialEq, Hash, Debug, Clone)]
|
||||
@ -78,7 +78,9 @@ pub enum IsoCase {
|
||||
}
|
||||
|
||||
impl Default for IsoCase {
|
||||
fn default() -> Self { IsoCase::Case1 }
|
||||
fn default() -> Self {
|
||||
IsoCase::Case1
|
||||
}
|
||||
}
|
||||
|
||||
#[repr(u8)]
|
||||
@ -106,7 +108,9 @@ pub enum SCardProtocol {
|
||||
}
|
||||
|
||||
impl Default for SCardProtocol {
|
||||
fn default() -> Self { SCardProtocol::Any }
|
||||
fn default() -> Self {
|
||||
SCardProtocol::Any
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Eq, PartialEq, Hash, Debug, Default, Clone)]
|
||||
@ -155,10 +159,7 @@ impl TryFrom<APDUCommand> for Vec<u8> {
|
||||
v.push(cmd.le as u8);
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
|
||||
return Err(Error::InvalidIsoCase)
|
||||
}
|
||||
_ => return Err(Error::InvalidIsoCase),
|
||||
}
|
||||
Ok(v)
|
||||
}
|
||||
@ -180,10 +181,18 @@ impl fmt::Display for APDUCommand {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
|
||||
match self.case {
|
||||
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 => {
|
||||
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 => {
|
||||
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)]
|
||||
mod tests {
|
||||
use crate::iso7816_4::apducommand::{APDUCommand, SCardProtocol, IsoCase};
|
||||
use crate::iso7816_4::apducommand::{APDUCommand, IsoCase, SCardProtocol};
|
||||
|
||||
#[test]
|
||||
fn compare() {
|
||||
let command1 = APDUCommand{
|
||||
let command1 = APDUCommand {
|
||||
case: IsoCase::Case4Short,
|
||||
protocol: SCardProtocol::Unset,
|
||||
cla: 0x90,
|
||||
@ -218,7 +227,7 @@ mod tests {
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
let command2 = APDUCommand{
|
||||
let command2 = APDUCommand {
|
||||
case: IsoCase::Case4Short,
|
||||
protocol: SCardProtocol::Unset,
|
||||
cla: 0x90,
|
||||
@ -232,7 +241,7 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn compare_diff() {
|
||||
let command1 = APDUCommand{
|
||||
let command1 = APDUCommand {
|
||||
case: IsoCase::Case4Short,
|
||||
protocol: SCardProtocol::Unset,
|
||||
cla: 0x90,
|
||||
@ -241,7 +250,7 @@ mod tests {
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
let command2 = APDUCommand{
|
||||
let command2 = APDUCommand {
|
||||
case: IsoCase::Case4Short,
|
||||
protocol: SCardProtocol::Unset,
|
||||
cla: 0x90,
|
||||
@ -255,7 +264,7 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn to_string_case1() {
|
||||
let command1 = APDUCommand{
|
||||
let command1 = APDUCommand {
|
||||
case: IsoCase::Case1,
|
||||
cla: 0x90,
|
||||
ins: 0x1A,
|
||||
@ -263,12 +272,15 @@ mod tests {
|
||||
};
|
||||
|
||||
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]
|
||||
fn to_string_case2() {
|
||||
let command1 = APDUCommand{
|
||||
let command1 = APDUCommand {
|
||||
case: IsoCase::Case2Short,
|
||||
cla: 0x90,
|
||||
ins: 0x1A,
|
||||
@ -276,12 +288,15 @@ mod tests {
|
||||
};
|
||||
|
||||
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]
|
||||
fn to_string_case3() {
|
||||
let command1 = APDUCommand{
|
||||
let command1 = APDUCommand {
|
||||
case: IsoCase::Case3Short,
|
||||
cla: 0x90,
|
||||
ins: 0x1A,
|
||||
@ -290,12 +305,15 @@ mod tests {
|
||||
};
|
||||
|
||||
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]
|
||||
fn to_string_case4() {
|
||||
let command1 = APDUCommand{
|
||||
let command1 = APDUCommand {
|
||||
case: IsoCase::Case4Short,
|
||||
cla: 0x90,
|
||||
ins: 0x1A,
|
||||
|
@ -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::error::{Result};
|
||||
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;
|
||||
|
||||
#[derive(Eq, PartialEq, Hash, Debug, Default)]
|
||||
@ -22,7 +26,9 @@ impl From<APDUResponse> for Vec<u8> {
|
||||
let mut v: Vec<u8> = vec![];
|
||||
match resp.body {
|
||||
None => {}
|
||||
Some(body) => {v.extend(body);}
|
||||
Some(body) => {
|
||||
v.extend(body);
|
||||
}
|
||||
}
|
||||
v.push(resp.sw1);
|
||||
v.push(resp.sw2);
|
||||
@ -35,9 +41,13 @@ impl fmt::Display for APDUResponse {
|
||||
match &self.body {
|
||||
None => {
|
||||
write!(f, "SW1: {:#X} | SW2: 0x{:#X}", self.sw1, self.sw2)
|
||||
},
|
||||
}
|
||||
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),
|
||||
0x62 => Ok(APDUStatusWord::StorageNotChanged),
|
||||
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),
|
||||
0x65 => Ok(APDUStatusWord::ExecutionErrorWithChange),
|
||||
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<()> {
|
||||
if self.sw1 == 0x91 {
|
||||
return match FromPrimitive::from_u8(self.sw2) {
|
||||
Some(APDUStatusWord2::OperationOk) => { Ok(()) }
|
||||
Some(APDUStatusWord2::NoChanges) => { Ok(()) }
|
||||
Some(APDUStatusWord2::IllegalCommandCode) => {Err(IllegalCommandCode)}
|
||||
Some(APDUStatusWord2::IntegrityError) => {Err(IntegrityError)}
|
||||
Some(APDUStatusWord2::NoSuchKey) => {Err(NoSuchKey)}
|
||||
Some(APDUStatusWord2::LengthError) => {Err(LengthError)}
|
||||
Some(APDUStatusWord2::PermissionDenied) => {Err(PermissionDenied)}
|
||||
Some(APDUStatusWord2::ParameterError) => {Err(ParameterError)}
|
||||
Some(APDUStatusWord2::AuthenticationDelay) => {Err(AuthenticationDelay)}
|
||||
Some(APDUStatusWord2::AuthenticationError) => {Err(AuthenticationError)}
|
||||
Some(APDUStatusWord2::AdditionalFrame) => {Ok(())}
|
||||
Some(APDUStatusWord2::BoundaryError) => {Err(BoundaryError)}
|
||||
Some(APDUStatusWord2::CommandAborted) => {Err(CommandAborted)}
|
||||
Some(APDUStatusWord2::DuplicateError) => {Err(DuplicateError)}
|
||||
Some(APDUStatusWord2::FileNotFound) => {Err(FileNotFound)}
|
||||
Some(APDUStatusWord2::ApplicationNotFound) => {Err(ApplicationNotFound)}
|
||||
None => { Err(InvalidStatusWord)}
|
||||
Some(APDUStatusWord2::OperationOk) => Ok(()),
|
||||
Some(APDUStatusWord2::NoChanges) => Ok(()),
|
||||
Some(APDUStatusWord2::IllegalCommandCode) => Err(IllegalCommandCode),
|
||||
Some(APDUStatusWord2::IntegrityError) => Err(IntegrityError),
|
||||
Some(APDUStatusWord2::NoSuchKey) => Err(NoSuchKey),
|
||||
Some(APDUStatusWord2::LengthError) => Err(LengthError),
|
||||
Some(APDUStatusWord2::PermissionDenied) => Err(PermissionDenied),
|
||||
Some(APDUStatusWord2::ParameterError) => Err(ParameterError),
|
||||
Some(APDUStatusWord2::AuthenticationDelay) => Err(AuthenticationDelay),
|
||||
Some(APDUStatusWord2::AuthenticationError) => Err(AuthenticationError),
|
||||
Some(APDUStatusWord2::AdditionalFrame) => Ok(()),
|
||||
Some(APDUStatusWord2::BoundaryError) => Err(BoundaryError),
|
||||
Some(APDUStatusWord2::CommandAborted) => Err(CommandAborted),
|
||||
Some(APDUStatusWord2::DuplicateError) => Err(DuplicateError),
|
||||
Some(APDUStatusWord2::FileNotFound) => Err(FileNotFound),
|
||||
Some(APDUStatusWord2::ApplicationNotFound) => Err(ApplicationNotFound),
|
||||
None => Err(InvalidStatusWord),
|
||||
};
|
||||
} else {
|
||||
Err(InvalidStatusWord)
|
||||
}
|
||||
} else { Err(InvalidStatusWord) }
|
||||
}
|
||||
}
|
@ -108,19 +108,15 @@ pub enum APDUStatusWord {
|
||||
/// Parameter P1/P2 falsch
|
||||
WrongParameters2 = 0x6B00,
|
||||
|
||||
|
||||
/// Falsche Lnge Le; xx gibt die korrekte Lnge an Statuswort zur Steuerung des T=0-Protokolls
|
||||
InvalidLe = 0x6C00,
|
||||
|
||||
|
||||
/// Das Kommando (INS) wird nicht untersttzt
|
||||
InstructionNotSupported = 0x6D00,
|
||||
|
||||
|
||||
/// Die Kommandoklasse (CLA) wird nicht untersttzt
|
||||
ClassNotSupported = 0x6E00,
|
||||
|
||||
|
||||
/// Kommando wurde mit unbekanntem Fehler abgebrochen
|
||||
UnknownError = 0x6F00,
|
||||
|
||||
@ -129,7 +125,6 @@ pub enum APDUStatusWord {
|
||||
|
||||
/// OK
|
||||
OK = 0x9100,
|
||||
|
||||
}
|
||||
|
||||
#[derive(FromPrimitive)]
|
||||
|
32
src/lib.rs
32
src/lib.rs
@ -1,27 +1,27 @@
|
||||
use crate::iso7816_4::apduresponse::APDUResponse;
|
||||
use crate::iso7816_4::apducommand::APDUCommand;
|
||||
use crate::iso7816_4::apduresponse::APDUResponse;
|
||||
use error::Result;
|
||||
|
||||
pub mod crypto;
|
||||
pub mod iso7816_4;
|
||||
pub mod desfire;
|
||||
pub mod error;
|
||||
pub mod iso7816_4;
|
||||
|
||||
pub trait Card {
|
||||
/// <summary>
|
||||
/// Connect to Smartcard
|
||||
/// </summary>
|
||||
fn connect(&mut self) -> Result<()>;
|
||||
/// <summary>
|
||||
/// Connect to Smartcard
|
||||
/// </summary>
|
||||
fn connect(&mut self) -> Result<()>;
|
||||
|
||||
/// <summary>
|
||||
/// Disconnect from Smartcard
|
||||
/// </summary>
|
||||
fn disconnect(&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>
|
||||
fn transmit(&self, apdu_cmd: APDUCommand) -> Result<APDUResponse>;
|
||||
/// <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>
|
||||
fn transmit(&self, apdu_cmd: APDUCommand) -> Result<APDUResponse>;
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user