From e4cc1348b8337aaac4b385fcd4617ef203b03140 Mon Sep 17 00:00:00 2001 From: TheJoKlLa Date: Sat, 7 Nov 2020 21:28:55 +0100 Subject: [PATCH] Finished: NFC Lib v0.9, TODO: CMAC check, Change PICC Key --- NFC/ISO7816-4/APDUCommand.cs | 4 +- NFC/ISO7816-4/APDUResponse.cs | 11 +- NFC/NXP MIFARE DESFire/MIFARE_DESFire.cs | 442 ++++++++---------- .../NXP MIFARE DESFire/MIFARE_DESFire_Test.cs | 349 +++++++++++++- NFC_Test/REAL_DESFireCommands.cs | 2 +- NFC_Test/REAL_FabAccess_OTA.cs | 4 +- 6 files changed, 547 insertions(+), 265 deletions(-) diff --git a/NFC/ISO7816-4/APDUCommand.cs b/NFC/ISO7816-4/APDUCommand.cs index ef6a5e3..a0ffaa4 100644 --- a/NFC/ISO7816-4/APDUCommand.cs +++ b/NFC/ISO7816-4/APDUCommand.cs @@ -71,10 +71,10 @@ namespace NFC.ISO7816_4 return string.Format(pattern_case2, CLA, INS, P1, P2, Le); case IsoCase.Case3Short: case IsoCase.Case3Extended: - return string.Format(pattern_case3, CLA, INS, P1, P2, Lc, BitConverter.ToString(Data).Replace("-", " ")); + return string.Format(pattern_case3, CLA, INS, P1, P2, Lc, BitConverter.ToString(Data).Replace("-", "").ToLower()); case IsoCase.Case4Short: case IsoCase.Case4Extended: - return string.Format(pattern_case4, CLA, INS, P1, P2, Lc, BitConverter.ToString(Data).Replace("-", " "), Le); + return string.Format(pattern_case4, CLA, INS, P1, P2, Lc, BitConverter.ToString(Data).Replace("-", "").ToLower(), Le); default: throw new Exception("Unknown IsoCase"); } diff --git a/NFC/ISO7816-4/APDUResponse.cs b/NFC/ISO7816-4/APDUResponse.cs index 61e8501..d5ef0e3 100644 --- a/NFC/ISO7816-4/APDUResponse.cs +++ b/NFC/ISO7816-4/APDUResponse.cs @@ -146,8 +146,15 @@ namespace NFC.ISO7816_4 public override string ToString() { - string pattern = "SW1: 0x{0:x} | SW2: 0x{1:x} | Body: 0x{2:x}"; - return string.Format(pattern, SW1, SW2, Body); + if(Body == null) + { + return string.Format("SW1: 0x{0:x} | SW2: 0x{1:x}", SW1, SW2); + } + else + { + return string.Format("SW1: 0x{0:x} | SW2: 0x{1:x} | Body: {2:x}", SW1, SW2, BitConverter.ToString(Body).Replace("-", "").ToLower()); + } + } #endregion } diff --git a/NFC/NXP MIFARE DESFire/MIFARE_DESFire.cs b/NFC/NXP MIFARE DESFire/MIFARE_DESFire.cs index 185d78c..9dd39d7 100644 --- a/NFC/NXP MIFARE DESFire/MIFARE_DESFire.cs +++ b/NFC/NXP MIFARE DESFire/MIFARE_DESFire.cs @@ -412,40 +412,54 @@ namespace NFC.Mifare_DESFire #region DESFire Commands /// - /// Format PICC - /// Works after PICC Authentication + /// Select Application by ApplicationID (AID) /// - public void Format() + /// 3 Byte AID + public void SelectApplication(UInt32 aid) { - _Log.Debug("Start Format"); + if(aid > 0xFFFFFF) + { + throw new ArgumentOutOfRangeException("AID is too large"); + } - APDUCommand cmd_format = new APDUCommand(IsoCase.Case2Short) + byte[] id_byte = BitConverter.GetBytes(aid); + _Log.InfoFormat("Select Application: {0}", HexConverter.ConvertToHexString(id_byte.ToArray())); + + APDUCommand cmd_SelectApplication = new APDUCommand(IsoCase.Case4Short) { CLA = 0x90, - INS = 0xFC, + INS = (byte)APDUInstructions.SELECT_APPLICATION, + Data = new byte[] + { + id_byte[0], + id_byte[1], + id_byte[2] + } }; - _Log.DebugFormat("APDU_CMD(cmd_format): {0}", HexConverter.ConvertToHexString(cmd_format.ToArray())); - - APDUResponse response = _Card.Transmit(cmd_format); - _Log.DebugFormat("APDU_RES(cmd_format): {0}", HexConverter.ConvertToHexString(response.ToArray())); + _Log.Debug(cmd_SelectApplication.ToString()); + HexConverter.ConvertToHexString(cmd_SelectApplication.ToArray()); + APDUResponse response = _Card.Transmit(cmd_SelectApplication); + _Log.DebugFormat(response.ToString()); CheckAPDUResponse(response); - - _Log.Debug("End Format"); } /// - /// Authenticate to PICC, with ISO Authenticate + /// Authenticate to PICC, with ISO Authenticate for DES Key /// /// 0x01 - 0x0D - /// + /// Array of 8/16 Bytes /// !!! WARNING For Testing only !!! - /// Retry after short Time public void AuthenticateISO_DES(byte key_id, byte[] key, byte[] rndA = null) { - _Log.Debug("Start AuthenticateISO_DES"); + if(key_id >= 0x0E) + { + throw new ArgumentOutOfRangeException("KeyID is invalid"); + } - // Sepearte InitialisationVector for Authentication + _Log.InfoFormat("Authenticate with DES Key No: 0x{0:x}", key_id); + + // Sepearte Initialisation Vector for Authentication Process byte[] iv = new byte[8]; APDUCommand cmd_challange_request = new APDUCommand(IsoCase.Case4Short) @@ -457,10 +471,10 @@ namespace NFC.Mifare_DESFire key_id } }; - _Log.DebugFormat("APDU_CMD(cmd_challange_request): {0}", HexConverter.ConvertToHexString(cmd_challange_request.ToArray())); + _Log.Debug(cmd_challange_request.ToString()); APDUResponse response = _Card.Transmit(cmd_challange_request); - _Log.DebugFormat("APDU_RES(cmd_challange_request): {0}", HexConverter.ConvertToHexString(response.ToArray())); + _Log.Debug(response.ToString()); CheckAPDUResponse(response); @@ -476,7 +490,7 @@ namespace NFC.Mifare_DESFire byte[] rndB_rl = RotateLeft(rndB); _Log.DebugFormat("rndB_enc: {0}", HexConverter.ConvertToHexString(rndB_rl)); - if(rndA == null) + if (rndA == null) { Random rnd = new Random(); rndA = new byte[8]; @@ -488,7 +502,7 @@ namespace NFC.Mifare_DESFire _Log.DebugFormat("rndAB: {0}", HexConverter.ConvertToHexString(rndAB)); byte[] rndAB_enc = des.Encrypt(rndAB, key, rndB_enc); - _Log.DebugFormat("rndA_rndB_enc: {0}", HexConverter.ConvertToHexString(rndAB_enc)); + _Log.DebugFormat("rndAB_enc: {0}", HexConverter.ConvertToHexString(rndAB_enc)); iv = ExtractLastBlock(rndAB_enc, 8); APDUCommand cmd_challange_response = new APDUCommand(IsoCase.Case4Short) @@ -497,10 +511,10 @@ namespace NFC.Mifare_DESFire INS = 0xAF, Data = rndAB_enc }; - _Log.DebugFormat("APDU_CMD(cmd_challange_response): {0}", HexConverter.ConvertToHexString(cmd_challange_response.ToArray())); + _Log.Debug(cmd_challange_response.ToString()); response = _Card.Transmit(cmd_challange_response); - _Log.DebugFormat("APDU_RES(cmd_challange_response): {0}", HexConverter.ConvertToHexString(cmd_challange_response.ToArray())); + _Log.Debug(response.ToString()); CheckAPDUResponse(response); @@ -515,28 +529,52 @@ namespace NFC.Mifare_DESFire if (!rndA.SequenceEqual(rndAFromCard)) { - throw new Exception("Authentication failed, PICC Challenge is not corret"); + throw new Exception("Authentication failed, PICC Challenge is invalid."); } + _Log.Info("Authenticated"); + _SessionKey = GenerateSesionKey_DES(rndA, rndB); - _Log.DebugFormat("_SessionKey: {0}", HexConverter.ConvertToHexString(_SessionKey)); + _Log.DebugFormat("SessionKey: {0}", HexConverter.ConvertToHexString(_SessionKey)); _IV = GenerateEmptyArray(8); - _Log.DebugFormat("_IV: {0}", HexConverter.ConvertToHexString(_IV)); - - _Log.Debug("End AuthenticateISO_DES"); + _Log.DebugFormat("IV: {0}", HexConverter.ConvertToHexString(_IV)); } /// - /// Create Application for ID + /// Format PICC + /// Need Authentication for PICC / Application 0x000000 + /// + public void Format() + { + _Log.Info("Format PICC"); + + APDUCommand cmd_format = new APDUCommand(IsoCase.Case2Short) + { + CLA = 0x90, + INS = 0xFC, + }; + _Log.Debug(cmd_format.ToString()); + + APDUResponse response = _Card.Transmit(cmd_format); + _Log.Debug(response.ToString()); + + CheckAPDUResponse(response); + } + + /// + /// Create Application for ApplicationID /// /// 3 Byte ID public void CreateApplication(UInt32 aid, byte keysetting1, byte keysetting2) { - _Log.Debug("Start CreateApplication"); + if (aid > 0xFFFFFF) + { + throw new ArgumentOutOfRangeException("AID is too large"); + } byte[] id_byte = BitConverter.GetBytes(aid); - _Log.DebugFormat("AID: {0}", HexConverter.ConvertToHexString(id_byte.ToArray())); + _Log.InfoFormat("Create Application: {0}", HexConverter.ConvertToHexString(id_byte.ToArray())); APDUCommand cmd_CreateApplication = new APDUCommand(IsoCase.Case4Short) { @@ -551,58 +589,28 @@ namespace NFC.Mifare_DESFire keysetting2 } }; - _Log.DebugFormat("APDU_CMD(cmd_CreateApplication): {0}", HexConverter.ConvertToHexString(cmd_CreateApplication.ToArray())); + _Log.Debug(cmd_CreateApplication.ToString()); APDUResponse response = _Card.Transmit(cmd_CreateApplication); - _Log.DebugFormat("APDU_RES(cmd_CreateApplication): {0}", HexConverter.ConvertToHexString(response.ToArray())); + _Log.Debug(response.ToString()); CheckAPDUResponse(response); - - _Log.Debug("End CreateApplication"); - } - - /// - /// Select Application by AID - /// - /// 3 Byte AID - public void SelectApplication(UInt32 aid) - { - _Log.Debug("Start SelectApplication"); - - byte[] id_byte = BitConverter.GetBytes(aid); - _Log.DebugFormat("AID: {0}", HexConverter.ConvertToHexString(id_byte.ToArray())); - - APDUCommand cmd_SelectApplication = new APDUCommand(IsoCase.Case4Short) - { - CLA = 0x90, - INS = (byte)APDUInstructions.SELECT_APPLICATION, - Data = new byte[] - { - id_byte[0], - id_byte[1], - id_byte[2] - } - }; - _Log.DebugFormat("APDU_CMD(cmd_SelectApplication): {0}", HexConverter.ConvertToHexString(cmd_SelectApplication.ToArray())); - - APDUResponse response = _Card.Transmit(cmd_SelectApplication); - _Log.DebugFormat("APDU_RES(cmd_SelectApplication): {0}", HexConverter.ConvertToHexString(response.ToArray())); - - CheckAPDUResponse(response); - - _Log.Debug("End SelectApplication"); } /// /// Authenticate to PICC, with ISO Authenticate /// /// 0x01 - 0x0D - /// + /// Array of 16 Bytes /// !!! WARNING For Testing only !!! - /// Retry after short Time public void AuthenticateISO_AES(byte key_id, byte[] key, byte[] rndA = null) { - _Log.Debug("Start AuthenticateISO_AES"); + if (key_id >= 0x0E) + { + throw new ArgumentOutOfRangeException("KeyID is invalid"); + } + + _Log.InfoFormat("Authenticate with AES Key No: 0x{0:x}", key_id); // Sepearte InitialisationVector for Authentication byte[] iv = new byte[16]; @@ -616,10 +624,10 @@ namespace NFC.Mifare_DESFire key_id } }; - _Log.DebugFormat("APDU_CMD(cmd_challange_request): {0}", HexConverter.ConvertToHexString(cmd_challange_request.ToArray())); + _Log.Debug(cmd_challange_request.ToString()); APDUResponse response = _Card.Transmit(cmd_challange_request); - _Log.DebugFormat("APDU_RES(cmd_challange_request): {0}", HexConverter.ConvertToHexString(response.ToArray())); + _Log.Debug(response.ToString()); CheckAPDUResponse(response); @@ -647,7 +655,7 @@ namespace NFC.Mifare_DESFire _Log.DebugFormat("rndAB: {0}", HexConverter.ConvertToHexString(rndAB)); byte[] rndAB_enc = aes.Encrypt(rndAB, key, rndB_enc); - _Log.DebugFormat("rndA_rndB_enc: {0}", HexConverter.ConvertToHexString(rndAB_enc)); + _Log.DebugFormat("rndAB_enc: {0}", HexConverter.ConvertToHexString(rndAB_enc)); iv = ExtractLastBlock(rndAB_enc, 16); APDUCommand cmd_challange_response = new APDUCommand(IsoCase.Case4Short) @@ -656,10 +664,10 @@ namespace NFC.Mifare_DESFire INS = 0xAF, Data = rndAB_enc }; - _Log.DebugFormat("APDU_CMD(cmd_challange_response): {0}", HexConverter.ConvertToHexString(cmd_challange_response.ToArray())); + _Log.Debug(cmd_challange_response.ToString()); response = _Card.Transmit(cmd_challange_response); - _Log.DebugFormat("APDU_RES(cmd_challange_response): {0}", HexConverter.ConvertToHexString(cmd_challange_response.ToArray())); + _Log.Debug(response.ToString()); CheckAPDUResponse(response); @@ -674,83 +682,30 @@ namespace NFC.Mifare_DESFire if (!rndA.SequenceEqual(rndAFromCard)) { - throw new Exception("Authentication failed, PICC Challenge is not corret"); + throw new Exception("Authentication failed, PICC Challenge is invalid."); } _SessionKey = GenerateSesionKey_AES(rndA, rndB); - _Log.DebugFormat("_SessionKey: {0}", HexConverter.ConvertToHexString(_SessionKey)); + _Log.DebugFormat("SessionKey: {0}", HexConverter.ConvertToHexString(_SessionKey)); _IV = GenerateEmptyArray(16); - _Log.DebugFormat("_IV: {0}", HexConverter.ConvertToHexString(_IV)); - - _Log.Debug("End AuthenticateISO_DES"); + _Log.DebugFormat("IV: {0}", HexConverter.ConvertToHexString(_IV)); } /// - /// Change Same DES key as Authenticated + /// Change AES key, the same as Authenticated /// - /// - /// - /// - public void ChangeKey_DES(byte key_id, byte[] new_key, byte key_version) - { - _Log.Debug("Start ChangeKey_DES"); - - byte[] header = new byte[] - { - 0xC4, key_id - }; - _Log.DebugFormat("header: {0}", HexConverter.ConvertToHexString(header)); - - byte[] key_and_version = new_key; - byte[] command = Concatenate(header, key_and_version); - _Log.DebugFormat("command: {0}", HexConverter.ConvertToHexString(command)); - - CRC32 crc32 = new CRC32(); - byte[] crc = crc32.Calculate(command); - _Log.DebugFormat("crc: {0}", HexConverter.ConvertToHexString(crc)); - - byte[] cryptogram = Concatenate(key_and_version, crc); - _Log.DebugFormat("cryptogram: {0}", HexConverter.ConvertToHexString(cryptogram)); - - byte[] cryptogram_block = ExpandToBlockSize(cryptogram, 16); - _Log.DebugFormat("cryptogram_block: {0}", HexConverter.ConvertToHexString(cryptogram_block)); - - TDES des = new TDES(); - byte[] cryptogram_enc = des.Encrypt(cryptogram_block, _SessionKey, _IV); - _Log.DebugFormat("cryptogram_enc: {0}", HexConverter.ConvertToHexString(cryptogram_enc)); - - _IV = ExtractLastBlock(cryptogram_enc, 8); - _Log.DebugFormat("_IV: {0}", HexConverter.ConvertToHexString(_IV)); - - byte[] data = Concatenate(new byte[] { key_id }, cryptogram_enc); - _Log.DebugFormat("data: {0}", HexConverter.ConvertToHexString(data)); - - APDUCommand cmd_ChangeKey = new APDUCommand(IsoCase.Case4Short) - { - CLA = 0x90, - INS = 0xC4, - Data = data - }; - _Log.DebugFormat("APDU_CMD(cmd_ChangeKey): {0}", HexConverter.ConvertToHexString(cmd_ChangeKey.ToArray())); - - APDUResponse response = _Card.Transmit(cmd_ChangeKey); - _Log.DebugFormat("APDU_RES(cmd_ChangeKey): {0}", HexConverter.ConvertToHexString(response.ToArray())); - - CheckAPDUResponse(response); - - _Log.Debug("End ChangeKey_AES"); - } - - /// - /// Change Same AES key as Authenticated - /// - /// - /// - /// + /// 0x01 - 0x0D + /// Array of 16 Bytes + /// Version of Key(min. 0x10) public void ChangeKey_AES(byte key_id, byte[] new_key, byte key_version) { - _Log.Debug("Start ChangeKey_AES"); + if (key_id >= 0x0E) + { + throw new ArgumentOutOfRangeException("KeyID is invalid"); + } + + _Log.InfoFormat("Change AES Key No: 0x{0:x}", key_id); byte[] header = new byte[] { @@ -789,25 +744,28 @@ namespace NFC.Mifare_DESFire INS = 0xC4, Data = data }; - _Log.DebugFormat("APDU_CMD(cmd_ChangeKey): {0}", HexConverter.ConvertToHexString(cmd_ChangeKey.ToArray())); + _Log.Debug(cmd_ChangeKey.ToString()); APDUResponse response = _Card.Transmit(cmd_ChangeKey); - _Log.DebugFormat("APDU_RES(cmd_ChangeKey): {0}", HexConverter.ConvertToHexString(response.ToArray())); + _Log.Debug(response.ToString()); CheckAPDUResponse(response); - - _Log.Debug("End ChangeKey_AES"); } /// - /// Change other AES key as Authenticated + /// Change AES key, other than Authenticated /// - /// - /// - /// + /// 0x01 - 0x0D + /// Array of 16 Bytes + /// Version of Key(min. 0x10) public void ChangeOtherKey_AES(byte key_id, byte[] new_key, byte[] old_key, byte key_version) { - _Log.Debug("Start ChangeOtherKey_AES"); + if (key_id >= 0x0E) + { + throw new ArgumentOutOfRangeException("KeyID is invalid"); + } + + _Log.InfoFormat("Change AES Key No: 0x{0:x}", key_id); byte[] header = new byte[] { @@ -851,28 +809,28 @@ namespace NFC.Mifare_DESFire INS = 0xC4, Data = data }; - _Log.DebugFormat("APDU_CMD(cmd_ChangeKey): {0}", HexConverter.ConvertToHexString(cmd_ChangeKey.ToArray())); + _Log.Debug(cmd_ChangeKey.ToString()); APDUResponse response = _Card.Transmit(cmd_ChangeKey); - _Log.DebugFormat("APDU_RES(cmd_ChangeKey): {0}", HexConverter.ConvertToHexString(response.ToArray())); + _Log.Debug(response.ToString()); CheckAPDUResponse(response); - - _Log.Debug("End ChangeOtherKey_AES"); } /// /// Create Standard Data File /// - /// ID of File (0x01 - 0x10) + /// ID of File (0x00 - 0x20) /// Type of File Communicaton /// Access Rights for File /// Size of File in Bytes public void CreateFile_Standard(byte file_id, FileCommunication communication, UInt16 accessRights, UInt32 size) { - _Log.Debug("Start CreateFile_Standard"); - - _Log.DebugFormat("FID: {0}", file_id); + if (file_id >= 0x20) + { + throw new ArgumentOutOfRangeException("FileID is to large"); + } + _Log.DebugFormat("Create STD File: {0}", file_id); byte[] accessRights_byte = BitConverter.GetBytes(accessRights); byte[] size_byte_tolong = BitConverter.GetBytes(size); @@ -896,97 +854,27 @@ namespace NFC.Mifare_DESFire INS = (byte)APDUInstructions.CREATE_STDDATAFILE, Data = Concatenate(data, accessRights_byte, size_byte) }; - _Log.DebugFormat("APDU_CMD(cmd_CreateFile_Standard): {0}", HexConverter.ConvertToHexString(cmd_CreateFile_Standard.ToArray())); + _Log.Debug(cmd_CreateFile_Standard.ToString()); APDUResponse response = _Card.Transmit(cmd_CreateFile_Standard); - _Log.DebugFormat("APDU_RES(cmd_CreateFile_Standard): {0}", HexConverter.ConvertToHexString(response.ToArray())); + _Log.DebugFormat(response.ToString()); CheckAPDUResponse(response); - - _Log.Debug("End CreateFile_Standard"); - } - - /// - /// Read Data from File - /// - /// ID of File (0x01 - 0x10) - /// Offset for File - /// Lenght of Data - public byte[] ReadData(byte file_id, UInt32 offset, UInt32 length) - { - _Log.Debug("Start ReadData"); - - int max_read_bytes_pre_transaction = 47; - long bytes_readed = 0; - - List read_data = new List(); - - while (bytes_readed != length) - { - byte[] data = new byte[] - { - file_id - }; - - byte[] offset_byte_tolong = BitConverter.GetBytes(offset + bytes_readed); - // Use only 3 Bytes - byte[] offset_byte = new byte[] - { - offset_byte_tolong[0], - offset_byte_tolong[1], - offset_byte_tolong[2], - }; - - long bytes_toread = 0; - - if (length - bytes_readed < max_read_bytes_pre_transaction) - { - bytes_toread = length - bytes_readed; - } - else - { - bytes_toread = max_read_bytes_pre_transaction; - } - - byte[] length_byte_tolong = BitConverter.GetBytes(bytes_toread); - bytes_readed += bytes_toread; - - // Use only 3 Bytes - byte[] length_byte = new byte[] - { - length_byte_tolong[0], - length_byte_tolong[1], - length_byte_tolong[2], - }; - - APDUCommand cmd_ReadData = new APDUCommand(IsoCase.Case4Short) - { - CLA = 0x90, - INS = (byte)APDUInstructions.READ_DATA, - Data = Concatenate(data, offset_byte, length_byte) - }; - _Log.DebugFormat("APDU_CMD(cmd_ReadData): {0}", HexConverter.ConvertToHexString(cmd_ReadData.ToArray())); - - APDUResponse response = _Card.Transmit(cmd_ReadData); - _Log.DebugFormat("APDU_RES(cmd_ReadData): {0}", HexConverter.ConvertToHexString(response.ToArray())); - - CheckAPDUResponse(response); - read_data.AddRange(response.Body); - } - _Log.Debug("End ReadData"); - - return read_data.ToArray(); } /// /// Write Data to File /// - /// ID of File (0x01 - 0x10) + /// ID of File (0x00 - 0x20) /// Offset for File /// Data to write public void WriteData(byte file_id, UInt32 offset, byte[] data) { - _Log.Debug("Start WriteData"); + if (file_id >= 0x20) + { + throw new ArgumentOutOfRangeException("FileID is to large"); + } + _Log.DebugFormat("Write Data to File: {0}", file_id); int max_write_bytes_pre_transaction = 47; byte[] write_buffer; @@ -1040,15 +928,91 @@ namespace NFC.Mifare_DESFire INS = (byte)APDUInstructions.WRITE_DATA, Data = Concatenate(file_id_array, offset_byte, length_byte, write_buffer) }; - _Log.DebugFormat("APDU_CMD(cmd_WriteData): {0}", HexConverter.ConvertToHexString(cmd_WriteData.ToArray())); + _Log.Debug(cmd_WriteData.ToString()); APDUResponse response = _Card.Transmit(cmd_WriteData); - _Log.DebugFormat("APDU_RES(cmd_WriteData): {0}", HexConverter.ConvertToHexString(response.ToArray())); + _Log.Debug(response.ToString()); CheckAPDUResponse(response); } + } - _Log.Debug("End WriteData"); + /// + /// Read Data from File + /// + /// ID of File (0x00 - 0x20) + /// Offset for File + /// Lenght of Data + public byte[] ReadData(byte file_id, UInt32 offset, UInt32 length) + { + if (file_id >= 0x20) + { + throw new ArgumentOutOfRangeException("FileID is to large"); + } + _Log.DebugFormat("Read Data from File: {0}", file_id); + + int max_read_bytes_pre_transaction = 47; + long bytes_readed = 0; + byte[] readbuffer = new byte[47]; + + List read_data = new List(); + + while (bytes_readed != length) + { + byte[] data = new byte[] + { + file_id + }; + + byte[] offset_byte_tolong = BitConverter.GetBytes(offset + bytes_readed); + // Use only 3 Bytes + byte[] offset_byte = new byte[] + { + offset_byte_tolong[0], + offset_byte_tolong[1], + offset_byte_tolong[2], + }; + + long bytes_toread = 0; + + if (length - bytes_readed < max_read_bytes_pre_transaction) + { + bytes_toread = length - bytes_readed; + } + else + { + bytes_toread = max_read_bytes_pre_transaction; + } + + byte[] length_byte_tolong = BitConverter.GetBytes(bytes_toread); + bytes_readed += bytes_toread; + + // Use only 3 Bytes + byte[] length_byte = new byte[] + { + length_byte_tolong[0], + length_byte_tolong[1], + length_byte_tolong[2], + }; + + APDUCommand cmd_ReadData = new APDUCommand(IsoCase.Case4Short) + { + CLA = 0x90, + INS = (byte)APDUInstructions.READ_DATA, + Data = Concatenate(data, offset_byte, length_byte) + }; + _Log.Debug(cmd_ReadData.ToString()); + + APDUResponse response = _Card.Transmit(cmd_ReadData); + _Log.Debug(response.ToString()); + + CheckAPDUResponse(response); + + // Remove CMAC from Body + read_data.AddRange(GetSubArray(response.Body, 0, bytes_toread)); + } + + return read_data.ToArray(); } /// diff --git a/NFC_Test/NXP MIFARE DESFire/MIFARE_DESFire_Test.cs b/NFC_Test/NXP MIFARE DESFire/MIFARE_DESFire_Test.cs index 22de52a..f39d986 100644 --- a/NFC_Test/NXP MIFARE DESFire/MIFARE_DESFire_Test.cs +++ b/NFC_Test/NXP MIFARE DESFire/MIFARE_DESFire_Test.cs @@ -6,6 +6,7 @@ using NFC.NXP_MIFARE_DESFire.Exceptions; using NSubstitute; using NUnit.Framework; using System; +using System.Text; namespace NFC_Unit_Test.NXP_MIFARE_DESFire { @@ -697,6 +698,38 @@ namespace NFC_Unit_Test.NXP_MIFARE_DESFire #endregion #region DESFire Commands + [Test] + public void SelectApplication() + { + ICard card = Substitute.For(); + + MIFARE_DESFire desfire = new MIFARE_DESFire(card); + + APDUResponse response = new APDUResponse() + { + SW1 = 0x91, + SW2 = 0x00 + }; + + card.Transmit(Arg.Is(x => HexConverter.ConvertToHexString(x.ToArray()) == "905a00000333221100")).Returns(response); + + desfire.SelectApplication(0x112233); + } + + [Test] + public void SelectApplication_InvalidAID() + { + ICard card = Substitute.For(); + + MIFARE_DESFire desfire = new MIFARE_DESFire(null); + + Assert.Throws( + delegate + { + desfire.SelectApplication(0xFF000000); + }); + } + [Test] public void AuthenticateISO_DES() { @@ -708,31 +741,93 @@ namespace NFC_Unit_Test.NXP_MIFARE_DESFire { SW1 = 0x91, SW2 = 0xAF, - Body = HexConverter.ConvertFromHexString("5D994CE085F24089") + Body = HexConverter.ConvertFromHexString("2bf9a938ecca02e2") }; APDUResponse response_challenge_response = new APDUResponse() { SW1 = 0x91, SW2 = 0x00, - Body = HexConverter.ConvertFromHexString("913C6DED84221C41") + Body = HexConverter.ConvertFromHexString("07d825607a552e2e") }; - byte[] rndA = HexConverter.ConvertFromHexString("849B36C5F8BF4A09"); + byte[] rndA = HexConverter.ConvertFromHexString("5f7d1dd12d979173"); byte[] key = HexConverter.ConvertFromHexString("00000000000000000000000000000000"); - card.Transmit(Arg.Is(x => x.INS == 0x1A)).Returns(response_challenge_request); - card.Transmit(Arg.Is(x => x.INS == 0xAF)).Returns(response_challenge_response); + card.Transmit(Arg.Is(x => HexConverter.ConvertToHexString(x.ToArray()) == "901a0000010000")).Returns(response_challenge_request); + card.Transmit(Arg.Is(x => HexConverter.ConvertToHexString(x.ToArray()) == "90af000010f8cdb2eaa42a3167dfcb53852ce267fd00")).Returns(response_challenge_response); desfire.AuthenticateISO_DES(0x00, key, rndA); - byte[] expected_sessionkey = HexConverter.ConvertFromHexString("849B36C54FD1B759849B36C54FD1B759"); + byte[] expected_sessionkey = HexConverter.ConvertFromHexString("5f7d1dd1f449db5c5f7d1dd1f449db5c"); byte[] expected_iv = HexConverter.ConvertFromHexString("0000000000000000"); Assert.AreEqual(expected_sessionkey, desfire._SessionKey); Assert.AreEqual(expected_iv, desfire._IV); } + [Test] + public void AuthenticateISO_DES_InvalidKeyNo() + { + MIFARE_DESFire desfire = new MIFARE_DESFire(null); + + Assert.Throws( + delegate + { + desfire.AuthenticateISO_DES(0x0F, null); + }); + } + + [Test] + public void Format() + { + ICard card = Substitute.For(); + + MIFARE_DESFire desfire = new MIFARE_DESFire(card); + + APDUResponse response = new APDUResponse() + { + SW1 = 0x91, + SW2 = 0x00 + }; + + card.Transmit(Arg.Is(x => HexConverter.ConvertToHexString(x.ToArray()) == "90fc000000")).Returns(response); + + desfire.Format(); + } + + [Test] + public void CreateApplication() + { + ICard card = Substitute.For(); + + MIFARE_DESFire desfire = new MIFARE_DESFire(card); + + APDUResponse response = new APDUResponse() + { + SW1 = 0x91, + SW2 = 0x00 + }; + + card.Transmit(Arg.Is(x => HexConverter.ConvertToHexString(x.ToArray()) == "90ca000005eeffaa0b8200")).Returns(response); + + desfire.CreateApplication(0xAAFFEE, 0x0b, 0x82); + } + + [Test] + public void CreateApplication_InvalidAID() + { + ICard card = Substitute.For(); + + MIFARE_DESFire desfire = new MIFARE_DESFire(null); + + Assert.Throws( + delegate + { + desfire.CreateApplication(0xFF000000, 0x00, 0x00); + }); + } + [Test] public void AuthenticateISO_AES() { @@ -744,31 +839,43 @@ namespace NFC_Unit_Test.NXP_MIFARE_DESFire { SW1 = 0x91, SW2 = 0xAF, - Body = HexConverter.ConvertFromHexString("43a28e28c653df83cd85039714bccb51") + Body = HexConverter.ConvertFromHexString("a33856932308775cf464610c2b17a558") }; APDUResponse response_challenge_response = new APDUResponse() { SW1 = 0x91, SW2 = 0x00, - Body = HexConverter.ConvertFromHexString("d8f70a0f9a43f522f775a56f5688592f") + Body = HexConverter.ConvertFromHexString("8fdc476f6bac44fe9150e285abd68d48") }; - byte[] rndA = HexConverter.ConvertFromHexString("8a8b3c15e576ae3a21c2b18e6aead1f1"); + byte[] rndA = HexConverter.ConvertFromHexString("2176770e7a6eb4bef00d5e4b201d1e57"); byte[] key = HexConverter.ConvertFromHexString("00000000000000000000000000000000"); - card.Transmit(Arg.Is(x => x.INS == 0xAA)).Returns(response_challenge_request); - card.Transmit(Arg.Is(x => x.INS == 0xAF)).Returns(response_challenge_response); + card.Transmit(Arg.Is(x => HexConverter.ConvertToHexString(x.ToArray()) == "90aa0000010000")).Returns(response_challenge_request); + card.Transmit(Arg.Is(x => HexConverter.ConvertToHexString(x.ToArray()) == "90af000020cbe9726faf54bc76b2055d0b9700e7dc97ecad5627f1d1702a16e8408d2a0ada00")).Returns(response_challenge_response); desfire.AuthenticateISO_AES(0x00, key, rndA); - byte[] expected_sessionkey = HexConverter.ConvertFromHexString("8a8b3c15c71d0cf46aead1f148f27703"); + byte[] expected_sessionkey = HexConverter.ConvertFromHexString("2176770e11c512ca201d1e57fde6e15a"); byte[] expected_iv = HexConverter.ConvertFromHexString("00000000000000000000000000000000"); Assert.AreEqual(expected_sessionkey, desfire._SessionKey); Assert.AreEqual(expected_iv, desfire._IV); } + [Test] + public void AuthenticateISO_AES_InvalidKeyNo() + { + MIFARE_DESFire desfire = new MIFARE_DESFire(null); + + Assert.Throws( + delegate + { + desfire.AuthenticateISO_AES(0x0F, null); + }); + } + [Test] public void ChangeKey_AES() { @@ -782,19 +889,31 @@ namespace NFC_Unit_Test.NXP_MIFARE_DESFire SW2 = 0x00 }; - byte[] new_key = HexConverter.ConvertFromHexString("45eeb8338ae8f49a032e85bb11143530"); + card.Transmit(Arg.Is(x => HexConverter.ConvertToHexString(x.ToArray()) == "90c400002100c2b54a718d0251845653199909bb32e8e38bd6719e8dc21799c29c922a0984fc00")).Returns(response); - byte[] sessionkey = HexConverter.ConvertFromHexString("2f96515262e1beb0129de2df3e97feb3"); + byte[] new_key = HexConverter.ConvertFromHexString("25432a462d4a614e645267556b587032"); + + byte[] sessionkey = HexConverter.ConvertFromHexString("a8514dd0350f3dfbc86e80744bcc9b57"); byte[] iv = HexConverter.ConvertFromHexString("00000000000000000000000000000000"); desfire._SessionKey = sessionkey; desfire._IV = iv; - card.Transmit(null).ReturnsForAnyArgs(response); - desfire.ChangeKey_AES(0x00, new_key, 0x10); } + [Test] + public void ChangeKey_AES_InvalidKeyNo() + { + MIFARE_DESFire desfire = new MIFARE_DESFire(null); + + Assert.Throws( + delegate + { + desfire.ChangeKey_AES(0x0F, null, 0x10); + }); + } + [Test] public void ChangeOtherKey_AES() { @@ -808,19 +927,209 @@ namespace NFC_Unit_Test.NXP_MIFARE_DESFire SW2 = 0x00 }; - byte[] new_key = HexConverter.ConvertFromHexString("8db1f942f2d7cc82f6fa1486a30f8c12"); + card.Transmit(Arg.Is(x => HexConverter.ConvertToHexString(x.ToArray()) == "90c400002101a8c5a61a06f56f38dc91266fed2e87dc00a5ad72a634ff0e62c8d6d80707dd6000")).Returns(response); + + byte[] new_key = HexConverter.ConvertFromHexString("25432a462d4a614e645267556b587032"); byte[] old_key = HexConverter.ConvertFromHexString("00000000000000000000000000000000"); - byte[] sessionkey = HexConverter.ConvertFromHexString("e7aff3361c3e85347993c3219a87d24b"); + byte[] sessionkey = HexConverter.ConvertFromHexString("1677623e1e158a62dc3d128db55f947d"); byte[] iv = HexConverter.ConvertFromHexString("00000000000000000000000000000000"); desfire._SessionKey = sessionkey; desfire._IV = iv; - card.Transmit(null).ReturnsForAnyArgs(response); - desfire.ChangeOtherKey_AES(0x01, new_key, old_key, 0x10); } + + [Test] + public void ChangeOtherKey_AES_InvalidKeyNo() + { + MIFARE_DESFire desfire = new MIFARE_DESFire(null); + + Assert.Throws( + delegate + { + desfire.ChangeKey_AES(0x0F, null, 0x10); + }); + } + + [Test] + public void CreateFile_Standard() + { + ICard card = Substitute.For(); + + MIFARE_DESFire desfire = new MIFARE_DESFire(card); + + APDUResponse response = new APDUResponse() + { + SW1 = 0x91, + SW2 = 0x00 + }; + + card.Transmit(Arg.Is(x => HexConverter.ConvertToHexString(x.ToArray()) == "90cd000007010000e0f0000000")).Returns(response); + + UInt16 accesRights = desfire.GenerateFileAccessRights((byte)FileAccessRights.FREE, 0x00, 0x00, 0x00); + desfire.CreateFile_Standard(0x01, FileCommunication.PLAIN, accesRights, 0xF0); + } + + [Test] + public void CreateFile_Standard_InvalidFID() + { + ICard card = Substitute.For(); + + MIFARE_DESFire desfire = new MIFARE_DESFire(card); + + Assert.Throws( + delegate + { + desfire.CreateFile_Standard(0x21, FileCommunication.PLAIN, 0x0000, 0xF0); + }); + } + + [Test] + public void WriteData() + { + ICard card = Substitute.For(); + + MIFARE_DESFire desfire = new MIFARE_DESFire(card); + + APDUResponse response = new APDUResponse() + { + SW1 = 0x91, + SW2 = 0x00 + }; + + card.Transmit(Arg.Is(x => HexConverter.ConvertToHexString(x.ToArray()) == "903d00000f01000000080000546573743132333400")).Returns(response); + + desfire.WriteData(0x01, 0, Encoding.ASCII.GetBytes("Test1234")); + } + + [Test] + public void WriteData_Long() + { + ICard card = Substitute.For(); + + MIFARE_DESFire desfire = new MIFARE_DESFire(card); + + APDUResponse response = new APDUResponse() + { + SW1 = 0x91, + SW2 = 0x00 + }; + + card.Transmit(Arg.Is(x => HexConverter.ConvertToHexString(x.ToArray()) == "903d000036010000002f0000546573743132333454657374313233345465737431323334546573743132333454657374313233345465737431323300")).Returns(response); + card.Transmit(Arg.Is(x => HexConverter.ConvertToHexString(x.ToArray()) == "903d000036012f00002f0000345465737431323334546573743132333454657374313233345465737431323334546573743132333454657374313200")).Returns(response); + card.Transmit(Arg.Is(x => HexConverter.ConvertToHexString(x.ToArray()) == "903d000019015e000012000033345465737431323334546573743132333400")).Returns(response); + + desfire.WriteData(0x01, 0, Encoding.ASCII.GetBytes("Test1234Test1234Test1234Test1234Test1234Test1234Test1234Test1234Test1234Test1234Test1234Test1234Test1234Test1234")); + } + + [Test] + public void WriteData_InvalidFileID() + { + ICard card = Substitute.For(); + + MIFARE_DESFire desfire = new MIFARE_DESFire(card); + + Assert.Throws( + delegate + { + desfire.WriteData(0x21, 0x00, Encoding.ASCII.GetBytes("Test1234")); + }); + } + + [Test] + public void ReadData() + { + ICard card = Substitute.For(); + + MIFARE_DESFire desfire = new MIFARE_DESFire(card); + + APDUResponse response = new APDUResponse() + { + SW1 = 0x91, + SW2 = 0x00, + Body = HexConverter.ConvertFromHexString("54657374313233340000000000000000000000000000000000000000000000009100") + }; + + card.Transmit(Arg.Is(x => HexConverter.ConvertToHexString(x.ToArray()) == "90bd0000070100000020000000")).Returns(response); + + byte[] data = desfire.ReadData(0x01, 0x00, 0x20); + + Assert.AreEqual("Test1234", Encoding.ASCII.GetString(data).Replace("\u0000", "")); + } + + [Test] + public void ReadData_CMAC() + { + ICard card = Substitute.For(); + + MIFARE_DESFire desfire = new MIFARE_DESFire(card); + + APDUResponse response = new APDUResponse() + { + SW1 = 0x91, + SW2 = 0x00, + Body = HexConverter.ConvertFromHexString("5465737431323334000000000000000000000000000000000000000000000000809a9bedbc559a5b9100") + }; + + card.Transmit(Arg.Is(x => HexConverter.ConvertToHexString(x.ToArray()) == "90bd0000070100000020000000")).Returns(response); + + byte[] data = desfire.ReadData(0x01, 0x00, 0x20); + + Assert.AreEqual("Test1234", Encoding.ASCII.GetString(data).Replace("\u0000", "")); + } + + [Test] + public void ReadData_Long() + { + ICard card = Substitute.For(); + + MIFARE_DESFire desfire = new MIFARE_DESFire(card); + + APDUResponse response_1 = new APDUResponse() + { + SW1 = 0x91, + SW2 = 0x00, + Body = HexConverter.ConvertFromHexString("54657374313233340000000000000000000000000000000000000000000000000000000000000000000000000000009100") + }; + + APDUResponse response_2 = new APDUResponse() + { + SW1 = 0x91, + SW2 = 0x00, + Body = HexConverter.ConvertFromHexString("00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000009100") + }; + + APDUResponse response_3 = new APDUResponse() + { + SW1 = 0x91, + SW2 = 0x00, + Body = HexConverter.ConvertFromHexString("00009100") + }; + + card.Transmit(Arg.Is(x => HexConverter.ConvertToHexString(x.ToArray()) == "90bd000007010000002f000000")).Returns(response_1); + card.Transmit(Arg.Is(x => HexConverter.ConvertToHexString(x.ToArray()) == "90bd000007012f00002f000000")).Returns(response_2); + card.Transmit(Arg.Is(x => HexConverter.ConvertToHexString(x.ToArray()) == "90bd000007015e000002000000")).Returns(response_3); + + byte[] data = desfire.ReadData(0x01, 0x00, 0x60); + + Assert.AreEqual("Test1234", Encoding.ASCII.GetString(data).Replace("\u0000", "")); + } + + [Test] + public void ReadData_InvalidFileID() + { + ICard card = Substitute.For(); + + MIFARE_DESFire desfire = new MIFARE_DESFire(card); + + Assert.Throws( + delegate + { + desfire.ReadData(0x21, 0x00, 0x20); + }); + } #endregion } } diff --git a/NFC_Test/REAL_DESFireCommands.cs b/NFC_Test/REAL_DESFireCommands.cs index 36bd22f..5808d54 100644 --- a/NFC_Test/REAL_DESFireCommands.cs +++ b/NFC_Test/REAL_DESFireCommands.cs @@ -251,7 +251,7 @@ namespace NFC_Real_Test desfire.AuthenticateISO_AES(0x00, key_aes._Key); CipherKey key_aes_new = new CipherKey(ApplicationMasterKey, CipherType.AES, 0x10); - desfire.ChangeKey_AES(0x00, key._Key, key._KeyVersion); + desfire.ChangeKey_AES(0x00, key_aes_new._Key, key_aes_new._KeyVersion); test_successfully = true; diff --git a/NFC_Test/REAL_FabAccess_OTA.cs b/NFC_Test/REAL_FabAccess_OTA.cs index 7edc1ab..a17c0dc 100644 --- a/NFC_Test/REAL_FabAccess_OTA.cs +++ b/NFC_Test/REAL_FabAccess_OTA.cs @@ -17,7 +17,9 @@ namespace NFC_Real_Test private byte _FabAccess_FID = 0x01; private UInt32 _FabAccess_FSize = 0xF0; - private CipherKey _FabAccess_Card_MasterKey = new CipherKey("294A404E635266556A576E5A72347537", CipherType.AES, 0x10); + // Change of PICC Key is not implementet yet + // private CipherKey _FabAccess_Card_MasterKey = new CipherKey("294A404E635266556A576E5A72347537", CipherType.AES, 0x10); + private CipherKey _FabAccess_Application_MasterKey = new CipherKey("50645367566B59703273357638792F42", CipherType.AES, 0x10); private CipherKey _FabAccess_Application_AuthKey = new CipherKey("6D5A7134743677397A24432646294A40", CipherType.AES, 0x10);