From 7c35d4ce6d3ac722c86b0e806004c61a08f99196 Mon Sep 17 00:00:00 2001 From: Kai Jan Kriegel Date: Sat, 25 Dec 2021 06:24:45 +0100 Subject: [PATCH] fixed aes auth, change_key_aes, change_key_other_aes --- src/desfire/desfire.rs | 66 ++++++++++++++++++++++++++++++++++-------- src/error.rs | 4 +++ 2 files changed, 58 insertions(+), 12 deletions(-) diff --git a/src/desfire/desfire.rs b/src/desfire/desfire.rs index b7fa2d8..6a01389 100644 --- a/src/desfire/desfire.rs +++ b/src/desfire/desfire.rs @@ -6,7 +6,7 @@ use crate::crypto::cipher::aes::AES; use crate::crypto::cipher::Cipher; use crate::crypto::util; use crate::error::{Result, Error}; -use crate::error::Error::{InvalidApplicationID, InvalidKeyID, InvalidFileID, NumKeys}; +use crate::error::Error::{InvalidApplicationID, InvalidKeyID, InvalidFileID, NumKeys, InvalidKeyVersion}; use crate::crypto::util::expand_to_blocksize; use crate::desfire::{FileCommunication, ChangeMasterKeySettings, CreateDeleteFile, FileDirectoryAccess, ChangeMasterKey, ChangeApplicationKey, CryptoOperationsType, FileIdentifiers}; use crate::iso7816_4::apduresponse::APDUResponse; @@ -140,8 +140,6 @@ impl Desfire { return Err(InvalidKeyID); } - // let auth_iv: Vec; - let cmd_challenge_request = APDUCommand { case: IsoCase::Case4Short, cla: 0x90, @@ -149,6 +147,7 @@ impl Desfire { data: Option::from(vec!(key_id)), ..Default::default() }; + println!("CMD_CHALLENGE_REQUEST: {}", cmd_challenge_request); let response = self.card.transmit(cmd_challenge_request).unwrap(); @@ -156,6 +155,7 @@ impl Desfire { Ok(_) => {} Err(e) => { return Err(e); } } + println!("RESPONSE: {}", response); let rnd_b_response_body = response.body.unwrap(); let rnd_b_enc = rnd_b_response_body.as_slice(); @@ -165,8 +165,8 @@ impl Desfire { println!("RND_B: {:x?}", rnd_b); // auth_iv = rnd_b.clone(); - let rnd_b_rl = rnd_b.clone(); - rnd_b.rotate_left(1); + let mut rnd_b_rl = rnd_b.clone(); + rnd_b_rl.rotate_left(1); println!("RND_B_RL: {:x?}", rnd_b_rl); let rnd_a = match rnd_a { @@ -175,10 +175,10 @@ impl Desfire { }; println!("RND_A: {:x?}", rnd_a); - let rnd_ab = [&rnd_a, rnd_b_rl].concat(); + let rnd_ab = [&rnd_a, rnd_b_rl.as_slice()].concat(); println!("RND_AB: {:x?}", rnd_ab); - let rnd_ab_enc = AES::encrypt(rnd_ab.as_slice(), key, auth_iv.as_slice()).unwrap(); + let rnd_ab_enc = AES::encrypt(rnd_ab.as_slice(), key, rnd_b_enc).unwrap(); println!("RND_AB_ENC: {:x?}", rnd_ab_enc); let cmd_challenge_response = APDUCommand { @@ -188,6 +188,7 @@ impl Desfire { data: Some(rnd_ab_enc.clone()), ..Default::default() }; + println!("CMD_CHALLENGE_RESPONSE: {}", cmd_challenge_response); let response = self.card.transmit(cmd_challenge_response).unwrap(); @@ -195,18 +196,27 @@ impl Desfire { Ok(_) => {} Err(e) => { return Err(e); } } + println!("RESPONSE: {}", response); - let mut rnd_a_rot_from_card = AES::decrypt(response.body.unwrap().as_slice(), key, auth_iv.as_slice()).unwrap(); + let iv: &[u8] = util::extract_last_block(rnd_ab_enc.as_slice(), 16).unwrap(); + let rnd_a_enc_from_card = response.body.unwrap(); + println!("RND_A_ENC_FROM_CARD: {:x?}", rnd_a_enc_from_card.as_slice()); + let mut rnd_a_rot_from_card = AES::decrypt(rnd_a_enc_from_card.as_slice(), key, iv).unwrap(); rnd_a_rot_from_card.rotate_right(1); + println!("RND_A_ROT_FROM_CARD: {:x?}", rnd_a_rot_from_card); let rnd_a_from_card = rnd_a_rot_from_card.as_slice(); + println!("RND_A_FROM_CARD: {:x?}", rnd_a_from_card); if rnd_a != rnd_a_from_card { return Err(Error::InvalidPICCChallenge); } self.session_key = Some(generate_session_key_aes(&rnd_a, rnd_b.as_slice()).unwrap()); + println!("SESSION_KEY: {:x?}", self.session_key.as_ref().unwrap()); self.cbc_iv = Some(vec![0 as u8; 16]); + println!("CBC_IV: {:x?}", self.cbc_iv.as_ref().unwrap()); + Ok(()) } @@ -262,6 +272,9 @@ impl Desfire { if key_id >= 0x0E { return Err(InvalidKeyID); } + if key_version < 0x10 { + return Err(InvalidKeyVersion); + } let header = vec![0xC4, key_id]; let key_and_version: Vec = [new_key, &[key_version]].concat(); @@ -269,21 +282,29 @@ impl Desfire { command.extend(&header); command.extend(&key_and_version); + println!("HEADER: {:x?}", header); + println!("COMMAND: {:x?}", command); let crc = crate::crypto::crc::crc32::calculate(command.as_slice()); + println!("CRC: {:x?}", crc); let mut plaintext: Vec = vec![]; plaintext.extend(key_and_version); plaintext.extend(crc); + println!("PLAINTEXT: {:x?}", plaintext); let plaintext_pad = expand_to_blocksize(plaintext.as_mut_slice(), 16)?; + println!("PLAINTEXT_PAD: {:x?}", plaintext_pad); - let cryptogram = AES::encrypt(plaintext_pad, self.session_key.as_ref().unwrap(), self.cbc_iv.as_ref().unwrap())?; + let cryptogram = AES::encrypt(plaintext_pad.as_slice(), self.session_key.as_ref().unwrap(), self.cbc_iv.as_ref().unwrap())?; + println!("CRYPTOGRAM: {:x?}", cryptogram); self.cbc_iv = Some(util::extract_last_block(cryptogram.as_slice(), 16)?.to_vec()); + println!("CBC_IV: {:x?}", self.cbc_iv.as_ref().unwrap()); let mut data: Vec = vec![key_id]; data.extend(cryptogram); + println!("DATA: {:x?}", data); let cmd_change_key = APDUCommand { case: IsoCase::Case4Short, @@ -292,8 +313,10 @@ impl Desfire { data: Option::from(data), //FIXME: Which byteorder? ..Default::default() }; + println!("CMD_CHANGE_KEY: {}", cmd_change_key); let response = self.card.transmit(cmd_change_key).unwrap(); + println!("RESPONSE: {}", response); response.check() } @@ -309,31 +332,48 @@ impl Desfire { if key_id >= 0x0E { return Err(InvalidKeyID); } + if key_version < 0x10 { + return Err(InvalidKeyVersion); + } let header = vec![0xC4, key_id]; + println!("HEADER: {:x?}", header); let key_xor: Vec = new_key.iter().zip(old_key.iter()).map(|(&x1, &x2)| x1 ^ x2).collect(); + println!("KEY_XOR: {:x?}", key_xor); let key_and_version: Vec = [key_xor, vec![key_version]].concat(); + println!("KEY_AND_VERSION: {:x?}", key_and_version); let mut command = vec![]; command.extend(&header); command.extend(&key_and_version); + println!("COMMAND: {:x?}", command); - let crc = crate::crypto::crc::crc32::calculate(command.as_slice()); + let crc_cmd = crate::crypto::crc::crc32::calculate(command.as_slice()); + println!("CRC_CMD: {:x?}", crc_cmd); + + let crc_key = crate::crypto::crc::crc32::calculate(new_key); + println!("CRC_KEY: {:x?}", crc_key); let mut plaintext: Vec = vec![]; plaintext.extend(key_and_version); - plaintext.extend(crc); + plaintext.extend(crc_cmd); + plaintext.extend(crc_key); + println!("PLAINTEXT: {:x?}", plaintext); let plaintext_pad = expand_to_blocksize(plaintext.as_mut_slice(), 16)?; + println!("PLAINTEXT_PAD: {:x?}", plaintext_pad); - let cryptogram = AES::encrypt(plaintext_pad, self.session_key.as_ref().unwrap(), self.cbc_iv.as_ref().unwrap())?; + let cryptogram = AES::encrypt(plaintext_pad.as_slice(), self.session_key.as_ref().unwrap(), self.cbc_iv.as_ref().unwrap())?; + println!("CRYPTOGRAM: {:x?}", cryptogram); self.cbc_iv = Some(util::extract_last_block(cryptogram.as_slice(), 16)?.to_vec()); + println!("CBC_IV: {:x?}", self.cbc_iv.as_ref().unwrap()); let mut data: Vec = vec![key_id]; data.extend(cryptogram); + println!("DATA: {:x?}", data); let cmd_change_key = APDUCommand { case: IsoCase::Case4Short, @@ -342,8 +382,10 @@ impl Desfire { data: Option::from(data), //FIXME: Which byteorder? ..Default::default() }; + println!("CMD_CHANGE_KEY: {}", cmd_change_key); let response = self.card.transmit(cmd_change_key).unwrap(); + println!("RESPONSE: {}", response); response.check() } diff --git a/src/error.rs b/src/error.rs index 9bf9424..7938aa9 100644 --- a/src/error.rs +++ b/src/error.rs @@ -30,6 +30,7 @@ pub enum Error { InvalidKeyID, InvalidPICCChallenge, InvalidFileID, + InvalidKeyVersion, NumKeys, CardError, } @@ -109,6 +110,9 @@ impl fmt::Display for Error { Error::InvalidKeyID => { write!(f, "Invalid KeyID: Was larger then 0x0E") } + Error::InvalidKeyVersion => { + write!(f, "Invalid KeyVersion: Should be atleast 0x10") + } Error::InvalidPICCChallenge => { write!(f, "Authentication failed, PICC Challenge is invalid.") }