diff --git a/Borepin/Borepin.iOS/CNFC/Reader.cs b/Borepin/Borepin.iOS/CNFC/Reader.cs index 2623290..992eb5e 100644 --- a/Borepin/Borepin.iOS/CNFC/Reader.cs +++ b/Borepin/Borepin.iOS/CNFC/Reader.cs @@ -62,6 +62,5 @@ namespace Borepin.iOS.CNFC // TODO: decide what to do Console.WriteLine("reader session invalidated"); } - } } diff --git a/NFC/Crypto/CRC16.cs b/NFC/Crypto/CRC/CRC16.cs similarity index 59% rename from NFC/Crypto/CRC16.cs rename to NFC/Crypto/CRC/CRC16.cs index 25f2a22..1530396 100644 --- a/NFC/Crypto/CRC16.cs +++ b/NFC/Crypto/CRC/CRC16.cs @@ -2,26 +2,14 @@ namespace NFC.Crypto { + /// + /// CRC16 for DESFire Card + /// public class CRC16 { - public byte[] Calculate(byte[] data) - { - UInt16 crc16 = 0x6363; + public UInt16 Polynomial { get; } = 0x8408; - crc16 = Calculate(data, crc16); - - return BitConverter.GetBytes(crc16); - } - - public byte[] Calculate(byte[] cmd, byte[] data) - { - UInt16 crc16 = 0x6363; - - crc16 = Calculate(cmd, crc16); - crc16 = Calculate(data, crc16); - - return BitConverter.GetBytes(crc16); - } + public UInt16 InitValue { get; } = 0x6363; public UInt16 Calculate(byte[] data, UInt16 crc16) { @@ -34,11 +22,23 @@ namespace NFC.Crypto crc16 >>= 1; if (b_Bit) { - crc16 ^= 0x8408; + crc16 ^= Polynomial; } } } return crc16; } + + public byte[] Calculate(params byte[][] data) + { + UInt16 crc16 = InitValue; + + foreach(byte[] d in data) + { + crc16 = Calculate(d, crc16); + } + + return BitConverter.GetBytes(crc16); + } } } diff --git a/NFC/Crypto/CRC32.cs b/NFC/Crypto/CRC/CRC32.cs similarity index 57% rename from NFC/Crypto/CRC32.cs rename to NFC/Crypto/CRC/CRC32.cs index e3e6f1d..1d1c45a 100644 --- a/NFC/Crypto/CRC32.cs +++ b/NFC/Crypto/CRC/CRC32.cs @@ -1,28 +1,15 @@ using System; -using System.Linq; namespace NFC.Crypto { + /// + /// CRC32 for DESFire Card + /// public class CRC32 { - public byte[] Calculate(byte[] data) - { - UInt32 crc32 = 0xFFFFFFFF; + public UInt32 Polynomial { get; } = 0xEDB88320; - crc32 = Calculate(data, crc32); - - return BitConverter.GetBytes(crc32); - } - - public byte[] Calculate(byte[] cmd, byte[] data) - { - UInt32 crc32 = 0xFFFFFFFF; - - crc32 = Calculate(cmd, crc32); - crc32 = Calculate(data, crc32); - - return BitConverter.GetBytes(crc32); - } + public UInt32 InitValue { get; } = 0xFFFFFFFF; public UInt32 Calculate(byte[] data, UInt32 crc32) { @@ -35,11 +22,23 @@ namespace NFC.Crypto crc32 >>= 1; if (b_Bit) { - crc32 ^= 0xEDB88320; + crc32 ^= Polynomial; } } } return crc32; } + + public byte[] Calculate(params byte[][] data) + { + UInt32 crc32 = InitValue; + + foreach(byte[] d in data) + { + crc32 = Calculate(d, crc32); + } + + return BitConverter.GetBytes(crc32); + } } } diff --git a/NFC/Crypto/AES.cs b/NFC/Crypto/Cipher/AES.cs similarity index 93% rename from NFC/Crypto/AES.cs rename to NFC/Crypto/Cipher/AES.cs index 4c5be9a..83a7676 100644 --- a/NFC/Crypto/AES.cs +++ b/NFC/Crypto/Cipher/AES.cs @@ -1,13 +1,16 @@ using Org.BouncyCastle.Crypto; using Org.BouncyCastle.Crypto.Engines; using Org.BouncyCastle.Crypto.Modes; -using Org.BouncyCastle.Crypto.Paddings; using Org.BouncyCastle.Crypto.Parameters; namespace NFC.Crypto { - public class AES + public class AES : ICipher { + public uint BlockSize { get; } = 16; + + public uint KeySize { get; } = 16; + public byte[] Encrypt(byte[] data, byte[] key, byte[] iv) { AesEngine engine = new AesEngine(); diff --git a/NFC/Crypto/Cipher/TDES.cs b/NFC/Crypto/Cipher/TDES.cs new file mode 100644 index 0000000..59e591e --- /dev/null +++ b/NFC/Crypto/Cipher/TDES.cs @@ -0,0 +1,49 @@ +using Org.BouncyCastle.Crypto; +using Org.BouncyCastle.Crypto.Engines; +using Org.BouncyCastle.Crypto.Modes; +using Org.BouncyCastle.Crypto.Parameters; + +namespace NFC.Crypto +{ + public class TDES : ICipher + { + public uint BlockSize { get; } = 8; + + // Two times the DES Key + public uint KeySize { get; } = 16; + + public byte[] Encrypt(byte[] data, byte[] key, byte[] iv) + { + DesEngine engine = new DesEdeEngine(); + CbcBlockCipher blockCipher = new CbcBlockCipher(engine); + BufferedBlockCipher cipher = new BufferedBlockCipher(blockCipher); + KeyParameter keyParam = new KeyParameter(key); + ParametersWithIV keyParamWithIV = new ParametersWithIV(keyParam, iv); + + // Encrypt + cipher.Init(true, keyParamWithIV); + byte[] outputBytes = new byte[cipher.GetOutputSize(data.Length)]; + int length = cipher.ProcessBytes(data, outputBytes, 0); + cipher.DoFinal(outputBytes, length); + + return outputBytes; + } + + public byte[] Decrypt(byte[] data, byte[] key, byte[] iv) + { + DesEngine engine = new DesEdeEngine(); + CbcBlockCipher blockCipher = new CbcBlockCipher(engine); + BufferedBlockCipher cipher = new BufferedBlockCipher(blockCipher); + KeyParameter keyParam = new KeyParameter(key); + ParametersWithIV keyParamWithIV = new ParametersWithIV(keyParam, iv); + + // Decrypt + cipher.Init(false, keyParamWithIV); + byte[] outputBytes = new byte[cipher.GetOutputSize(data.Length)]; + int length = cipher.ProcessBytes(data, outputBytes, 0); + cipher.DoFinal(outputBytes, length); + + return outputBytes; + } + } +} diff --git a/NFC/Crypto/TripleDES.cs b/NFC/Crypto/Cipher/TDES_2K.cs similarity index 92% rename from NFC/Crypto/TripleDES.cs rename to NFC/Crypto/Cipher/TDES_2K.cs index bf4c4fe..142f6cc 100644 --- a/NFC/Crypto/TripleDES.cs +++ b/NFC/Crypto/Cipher/TDES_2K.cs @@ -1,13 +1,16 @@ using Org.BouncyCastle.Crypto; using Org.BouncyCastle.Crypto.Engines; using Org.BouncyCastle.Crypto.Modes; -using Org.BouncyCastle.Crypto.Paddings; using Org.BouncyCastle.Crypto.Parameters; namespace NFC.Crypto { - public class TripleDES + public class TDES_2K : ICipher { + public uint BlockSize { get; } = 8; + + public uint KeySize { get; } = 16; + public byte[] Encrypt(byte[] data, byte[] key, byte[] iv) { DesEngine engine = new DesEdeEngine(); diff --git a/NFC/Crypto/DES.cs b/NFC/Crypto/Cipher/TDES_3K.cs similarity index 87% rename from NFC/Crypto/DES.cs rename to NFC/Crypto/Cipher/TDES_3K.cs index db9356a..87a3bf5 100644 --- a/NFC/Crypto/DES.cs +++ b/NFC/Crypto/Cipher/TDES_3K.cs @@ -1,16 +1,19 @@ using Org.BouncyCastle.Crypto; using Org.BouncyCastle.Crypto.Engines; using Org.BouncyCastle.Crypto.Modes; -using Org.BouncyCastle.Crypto.Paddings; using Org.BouncyCastle.Crypto.Parameters; namespace NFC.Crypto { - public class DES + public class TDES_3K : ICipher { + public uint BlockSize { get; } = 8; + + public uint KeySize { get; } = 24; + public byte[] Encrypt(byte[] data, byte[] key, byte[] iv) { - DesEngine engine = new DesEngine(); + DesEngine engine = new DesEdeEngine(); CbcBlockCipher blockCipher = new CbcBlockCipher(engine); BufferedBlockCipher cipher = new BufferedBlockCipher(blockCipher); KeyParameter keyParam = new KeyParameter(key); @@ -27,7 +30,7 @@ namespace NFC.Crypto public byte[] Decrypt(byte[] data, byte[] key, byte[] iv) { - DesEngine engine = new DesEngine(); + DesEngine engine = new DesEdeEngine(); CbcBlockCipher blockCipher = new CbcBlockCipher(engine); BufferedBlockCipher cipher = new BufferedBlockCipher(blockCipher); KeyParameter keyParam = new KeyParameter(key); diff --git a/NFC/Crypto/CipherKey.cs b/NFC/Crypto/CipherKey.cs new file mode 100644 index 0000000..519ab2a --- /dev/null +++ b/NFC/Crypto/CipherKey.cs @@ -0,0 +1,171 @@ +using System; + +namespace NFC.Crypto +{ + /// + /// Key for DESFire Card + /// + public class CipherKey + { + #region Constructors + /// + /// Creates Key from Array + /// + /// Key + /// Cipher for Key + /// Version of Key + public CipherKey(byte[] key, CipherType cipher, byte keyVersion) + { + _Cipher = cipher; + + if (cipher == CipherType.AES && keyVersion < 0x10) + { + throw new ArgumentOutOfRangeException("KeyVersion is to low for AES Key (Minimum = 0x10)"); + } + _KeyVersion = keyVersion; + + if (!CheckKey(key, cipher)) + { + throw new ArgumentException("Key is not vaild for CipherType"); + } + + if (cipher == CipherType.TDES || cipher == CipherType.TDES_2K || cipher == CipherType.TDES_3K) + { + _Key = SetKeyVersion(key, keyVersion); + } + else + { + _Key = key; + } + } + + /// + /// Generates Empty Key + /// + /// Cipher for Key + /// + public CipherKey(CipherType cipher) + { + _Cipher = cipher; + _Key = GenerateEmptyKey(cipher); + + if (cipher == CipherType.AES) + { + _KeyVersion = 0x10; + } + else + { + _KeyVersion = 0x00; + } + } + #endregion + + #region Properties + /// + /// Key as Array + /// + public byte[] _Key { get; private set; } + + /// + /// CipherType of Key + /// + public CipherType _Cipher { get; private set; } + + /// + /// KeyVersion of Key + /// For AES 0x10 is minimum + /// + public byte _KeyVersion { get; private set; } + #endregion + + #region Methods + /// + /// Generate Empty Key for CipherType + /// + /// Type of Cipher + public byte[] GenerateEmptyKey(CipherType cipher) + { + uint size = GetKeySize(cipher); + + byte[] key = new byte[size]; + for (int i = 0; i < size; i++) + { + key[i] = 0; + } + + return key; + } + + /// + /// Check Key Array + /// + /// Key + /// Cipher Type of Key + public bool CheckKey(byte[] key, CipherType cipher) + { + if (key.Length != GetKeySize(cipher)) + { + return false; + } + else + { + return true; + } + } + + /// + /// Get KeySize for CipherType + /// + /// Type of Cipher + public uint GetKeySize(CipherType cipher) + { + switch (cipher) + { + case CipherType.TDES: + return 8; + case CipherType.TDES_2K: + return 16; + case CipherType.TDES_3K: + return 24; + case CipherType.AES: + return 16; + default: + throw new ArgumentOutOfRangeException("Unknown CipherType."); + } + } + + /// + /// Set Key Version for DES/TDES Keys + /// KeyVersion is stored in the LSBits of the first 8 Bytes + /// Parity Bits are not used from DESFire Cars + /// + /// + /// + /// + public byte[] SetKeyVersion(byte[] key, byte version) + { + byte[] pow2 = new byte[] + { + 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80 + }; + + byte[] new_key = new byte[key.Length]; + key.CopyTo(new_key, 0); + + for (int i = 0; i < 8; i++) + { + if ((version & pow2[i]) > 0) + { + new_key[i] = (byte)(new_key[5] | 0x01); + } + else + { + new_key[i] = (byte)(new_key[5] & 0x7F); + } + } + + return new_key; + } + #endregion + } +} \ No newline at end of file diff --git a/NFC/Crypto/CipherType.cs b/NFC/Crypto/CipherType.cs new file mode 100644 index 0000000..c0b7dfa --- /dev/null +++ b/NFC/Crypto/CipherType.cs @@ -0,0 +1,25 @@ +namespace NFC.Crypto +{ + public enum CipherType + { + /// + /// DES / Triple DES + /// + TDES, + + /// + /// Triple DES with 2 DES Keys + /// + TDES_2K, + + /// + /// Triple DES with 3 DES Keys + /// + TDES_3K, + + /// + /// AES + /// + AES + } +} diff --git a/NFC/Crypto/ICipher.cs b/NFC/Crypto/ICipher.cs new file mode 100644 index 0000000..84583a4 --- /dev/null +++ b/NFC/Crypto/ICipher.cs @@ -0,0 +1,32 @@ +namespace NFC.Crypto +{ + public interface ICipher + { + /// + /// Size of Cipher Block in Byte + /// + public uint BlockSize { get; } + + /// + /// Size of Key in Byte + /// + public uint KeySize { get; } + + /// + /// Encrypt Data + /// + /// Data in BlockSize + /// Key + /// Initialisation Vector + /// + public byte[] Encrypt(byte[] data, byte[] key, byte[] IV); + + /// + /// Decrypt Data + /// + /// Data in BlockSize + /// Key + /// Initialisation Vector + public byte[] Decrypt(byte[] data, byte[] key, byte[] IV); + } +} diff --git a/NFC/HexConverter.cs b/NFC/HexConverter.cs new file mode 100644 index 0000000..b6e07a7 --- /dev/null +++ b/NFC/HexConverter.cs @@ -0,0 +1,51 @@ +using System; + +namespace NFC +{ + /// + /// Converts to and from Byte Array from and to String + /// + public static class HexConverter + { + /// + /// Converts byte[] to string with HEX Code + /// No 0x is created + /// + /// Data + public static string ConvertToHexString(byte[] data) + { + return BitConverter.ToString(data).Replace("-", "").ToLower(); + } + + /// + /// Converts string with HEX Code to byte[] + /// No 0x is requiered + /// + /// Data + public static byte[] ConvertFromHexString(string data) + { + if (data.Length % 2 == 1) + throw new Exception("Data Length is uneven."); + + byte[] arr = new byte[data.Length >> 1]; + + for (int i = 0; i < data.Length >> 1; ++i) + { + arr[i] = (byte)((GetHexVal(data[i << 1]) << 4) + (GetHexVal(data[(i << 1) + 1]))); + } + + return arr; + } + + private static int GetHexVal(char hex) + { + int val = (int)hex; + //For uppercase A-F letters: + //return val - (val < 58 ? 48 : 55); + //For lowercase a-f letters: + //return val - (val < 58 ? 48 : 87); + //Or the two combined, but a bit slower: + return val - (val < 58 ? 48 : (val < 97 ? 55 : 87)); + } + } +} diff --git a/NFC/ISO7816-4/APDUCommand.cs b/NFC/ISO7816-4/APDUCommand.cs index bf60034..ef6a5e3 100644 --- a/NFC/ISO7816-4/APDUCommand.cs +++ b/NFC/ISO7816-4/APDUCommand.cs @@ -1,7 +1,7 @@ using PCSC; using PCSC.Iso7816; using System; -using System.Collections.Generic; +using System.Linq; namespace NFC.ISO7816_4 { @@ -13,7 +13,7 @@ namespace NFC.ISO7816_4 } public override bool Equals(object obj) - { + { return obj is APDUCommand command && Case == command.Case && Protocol == command.Protocol && @@ -21,7 +21,8 @@ namespace NFC.ISO7816_4 INS == command.INS && P1 == command.P1 && P2 == command.P2 && - EqualityComparer.Default.Equals(Data, command.Data); + Data.SequenceEqual(command.Data) && + Le == command.Le; } public override int GetHashCode() @@ -43,5 +44,40 @@ namespace NFC.ISO7816_4 hash.Add(IsValid); return hash.ToHashCode(); } + + public static bool operator ==(APDUCommand obj1, APDUCommand obj2) + { + return obj1.Equals(obj2); + } + + public static bool operator !=(APDUCommand obj1, APDUCommand obj2) + { + return !(obj1.Equals(obj2)); + } + + public override string ToString() + { + string pattern_case1 = "(CASE: 1) CLA: 0x{0:x} | INS: 0x{1:x} | P1: 0x{2:x} | P2: 0x{3:x}"; + string pattern_case2 = "(CASE: 2) CLA: 0x{0:x} | INS: 0x{1:x} | P1: 0x{2:x} | P2: 0x{3:x} | LE: 0x{4:x} |"; + string pattern_case3 = "(CASE: 3) CLA: 0x{0:x} | INS: 0x{1:x} | P1: 0x{2:x} | P2: 0x{3:x} | LC: 0x{4:x} | Data: {5:x}"; + string pattern_case4 = "(CASE: 4) CLA: 0x{0:x} | INS: 0x{1:x} | P1: 0x{2:x} | P2: 0x{3:x} | LC: 0x{4:x} | Data: {5:x} | LE: 0x{6:x} |"; + + switch (Case) + { + case IsoCase.Case1: + return string.Format(pattern_case1, CLA, INS, P1, P2); + case IsoCase.Case2Short: + case IsoCase.Case2Extended: + 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("-", " ")); + case IsoCase.Case4Short: + case IsoCase.Case4Extended: + return string.Format(pattern_case4, CLA, INS, P1, P2, Lc, BitConverter.ToString(Data).Replace("-", " "), Le); + default: + throw new Exception("Unknown IsoCase"); + } + } } } diff --git a/NFC/NXP MIFARE DESFire/APDUInstructions.cs b/NFC/NXP MIFARE DESFire/APDUInstructions.cs index dd3025c..934c08d 100644 --- a/NFC/NXP MIFARE DESFire/APDUInstructions.cs +++ b/NFC/NXP MIFARE DESFire/APDUInstructions.cs @@ -28,7 +28,7 @@ CREATE_CYCLIC_RECORD_FILE = 0xC0, DELETE_FILE = 0xDF, GET_ISO_FILE_IDS = 0x61, - READ_DATA = 0x8D, + READ_DATA = 0xBD, WRITE_DATA = 0x3D, GET_VALUE = 0x6C, CREDIT = 0x0C, diff --git a/NFC/NXP MIFARE DESFire/CMAC.cs b/NFC/NXP MIFARE DESFire/CMAC.cs new file mode 100644 index 0000000..532aa23 --- /dev/null +++ b/NFC/NXP MIFARE DESFire/CMAC.cs @@ -0,0 +1,106 @@ +using NFC.Crypto; +using System; + +namespace NFC.NXP_MIFARE_DESFire +{ + public class CMAC + { + #region Contructors + public CMAC(CipherType cipher) + { + switch(cipher) + { + case(CipherType.TDES): + _Cipher = new TDES(); + break; + case(CipherType.TDES_2K): + _Cipher = new TDES_2K(); + break; + case(CipherType.TDES_3K): + _Cipher = new TDES_3K(); + break; + case (CipherType.AES): + _Cipher = new AES(); + break; + default: + throw new ArgumentException("Unkown Cipher Type."); + } + } + + public CMAC(ICipher cipher) + { + _Cipher = cipher ?? throw new ArgumentNullException(); + } + #endregion + + #region Properties + private ICipher _Cipher; + #endregion + + #region Methods + /// + /// Generate Key with all Zeros, in KeySize + /// + public byte[] GenerateEmpytKey() + { + byte[] key = new byte[_Cipher.KeySize]; + for (int i = 0; i < _Cipher.KeySize; i++) + { + key[i] = 0; + } + + return key; + } + + /// + /// Generate IV with all Zeros, in KeySize + /// + public byte[] GenerateEmpytIV() + { + byte[] key = new byte[_Cipher.BlockSize]; + for (int i = 0; i < _Cipher.BlockSize; i++) + { + key[i] = 0; + } + + return key; + } + + /// + /// Encrypt Data + /// + public byte[] Encrypt(byte[] data) + { + throw new NotImplementedException(); + } + + /// + /// Decrypt Data + /// + public byte[] Decrypt(byte[] data) + { + throw new NotImplementedException(); + } + + /// + /// + /// + /// Two Keys + public byte[][] GenerateSubKey() + { + throw new NotImplementedException(); + } + + /// + /// + /// + /// + /// + public byte[] Digest(byte[] data) + { + throw new NotImplementedException(); + } + + #endregion + } +} diff --git a/NFC/NXP MIFARE DESFire/Enums/AccessRights.cs b/NFC/NXP MIFARE DESFire/Enums/FileAccessRights.cs similarity index 70% rename from NFC/NXP MIFARE DESFire/Enums/AccessRights.cs rename to NFC/NXP MIFARE DESFire/Enums/FileAccessRights.cs index 0c91aa1..fd91f3a 100644 --- a/NFC/NXP MIFARE DESFire/Enums/AccessRights.cs +++ b/NFC/NXP MIFARE DESFire/Enums/FileAccessRights.cs @@ -1,6 +1,6 @@ namespace NFC.Mifare_DESFire.Enums { - public enum AccessRights : byte + public enum FileAccessRights : byte { FREE = 0x0E, NEVER = 0x0F diff --git a/NFC/NXP MIFARE DESFire/FileTypes.cs b/NFC/NXP MIFARE DESFire/Enums/FileTypes.cs similarity index 93% rename from NFC/NXP MIFARE DESFire/FileTypes.cs rename to NFC/NXP MIFARE DESFire/Enums/FileTypes.cs index 9c1fb13..0a18ea3 100644 --- a/NFC/NXP MIFARE DESFire/FileTypes.cs +++ b/NFC/NXP MIFARE DESFire/Enums/FileTypes.cs @@ -1,4 +1,4 @@ -namespace NFC.Mifare_DESFire +namespace NFC.Mifare_DESFire.Enums { enum FileTypes : byte { diff --git a/NFC/NXP MIFARE DESFire/Exceptions/AuthenticationMissingException.cs b/NFC/NXP MIFARE DESFire/Exceptions/AuthenticationMissingException.cs new file mode 100644 index 0000000..04c19cd --- /dev/null +++ b/NFC/NXP MIFARE DESFire/Exceptions/AuthenticationMissingException.cs @@ -0,0 +1,26 @@ +using System; + +namespace NFC.NXP_MIFARE_DESFire.Exceptions +{ + /// + /// Current authentication status does not allow there- quested command. + /// 0x91AE + /// + public class AuthenticationMissingException : Exception + { + public AuthenticationMissingException() + { + + } + + public AuthenticationMissingException(string message) : base(message) + { + + } + + public AuthenticationMissingException(string message, Exception inner) : base(message, inner) + { + + } + } +} diff --git a/NFC/NXP MIFARE DESFire/MIFARE_DESFire.cs b/NFC/NXP MIFARE DESFire/MIFARE_DESFire.cs index 2c3840e..149d04e 100644 --- a/NFC/NXP MIFARE DESFire/MIFARE_DESFire.cs +++ b/NFC/NXP MIFARE DESFire/MIFARE_DESFire.cs @@ -1,6 +1,8 @@ -using NFC.Crypto; +using log4net.Repository.Hierarchy; +using NFC.Crypto; using NFC.ISO7816_4; using NFC.Mifare_DESFire.Enums; +using NFC.NXP_MIFARE_DESFire.Exceptions; using PCSC.Iso7816; using System; using System.Collections.Generic; @@ -12,6 +14,10 @@ namespace NFC.Mifare_DESFire { // Docs https://hackmd.io/qATu8uYdRnOC40aFrB9afg + #region Log + private static readonly log4net.ILog _Log = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType); + #endregion + #region Contructors /// /// Construct MIFRARE_DESFire Object with ICard Interface @@ -29,16 +35,25 @@ namespace NFC.Mifare_DESFire /// private ICard _Card; + /// + /// SessionKey, is set after Successfull Authentication + /// public byte[] _SessionKey; + + /// + /// Initialation Vector for CBC Encryption + /// Is 0 bytes after Successfull Authentication + /// public byte[] _IV; #endregion #region Methods + #region Helper Methods /// /// Generate Byte Array filled with 0 /// /// Size of Array - public byte[] GenerateDefaultKey(uint size) + public byte[] GenerateEmptyKey(uint size) { byte[] key = new byte[size]; for (int i = 0; i < size; i++) @@ -56,93 +71,121 @@ namespace NFC.Mifare_DESFire /// Data public string ConvertToHexString(byte[] data) { - return BitConverter.ToString(data).Replace("-", " "); + return BitConverter.ToString(data).Replace("-", "").ToLower(); } + /// + /// Converts string with HEX Code to byte[] + /// No 0x is requiered + /// + /// Data + public byte[] ConvertFromHexString(string data) + { + if (data.Length % 2 == 1) + throw new Exception("Data Length is uneven."); + byte[] arr = new byte[data.Length >> 1]; + + for (int i = 0; i < data.Length >> 1; ++i) + { + arr[i] = (byte)((GetHexVal(data[i << 1]) << 4) + (GetHexVal(data[(i << 1) + 1]))); + } + + return arr; + } + + private int GetHexVal(char hex) + { + int val = (int)hex; + //For uppercase A-F letters: + //return val - (val < 58 ? 48 : 55); + //For lowercase a-f letters: + //return val - (val < 58 ? 48 : 87); + //Or the two combined, but a bit slower: + return val - (val < 58 ? 48 : (val < 97 ? 55 : 87)); + } + + /// + /// Check APDU Response for DESFire Error Codes + /// https://www.nxp.com/docs/en/data-sheet/MF2DLHX0.pdf + /// Section: 11.3 + /// public void CheckAPDUResponse(APDUResponse response) { - - } - - public bool CheckKey(byte[] key) - { - try + if (response == null) { - GetKeyTypeDES(key); - return true; + throw new ArgumentNullException("Response cannot be null."); } - catch + + if (response.SW1 == 0x91) { - return false; + switch (response.SW2) + { + case 0x00: // OPERATION_OK + return; + case 0x0C: // NO_CHANGES + return; + case 0x1C: // ILLEGAL_COMMAND_CODE + throw new IllegalCommandCodeException(); + case 0x1E: // INTEGRITY_ERROR + throw new IntegrityErrorException(); + case 0x40: // NO_SUCH_KEY + throw new NoSuchKeyException(); + case 0x7E: // LENGTH_ERROR + throw new LengthErrorException(); + case 0x9D: // PERMISSION_DENIED + throw new PermissionDeniedException(); + case 0x9E: // PARAMETER_ERROR + throw new ParameterErrorException(); + case 0xAD: // AUTHENTICATION_DELAY + throw new AuthenticationDelayException(); + case 0xAE: // AUTHENTICATION_ERROR + throw new AuthenticationErrorException(); + case 0xAF: // ADDITIONAL_FRAME + return; + case 0xBE: // BOUNDARY_ERROR + throw new BoundaryErrorException(); + case 0xCA: // COMMAND_ABORTED + throw new CommandAbortedException(); + case 0xDE: // DUPLICATE_ERROR + throw new DuplicateErrorException(); + case 0xF0: // FILE_NOT_FOUND + throw new FileNotFoundException(); + default: + break; + } } + + throw new Exception(string.Format("Unknown Response Code: 0x{0}.", BitConverter.ToString(new byte[] { response.SW1, response.SW2 }).Replace("-", string.Empty))); } + #endregion - /// - /// Key Types used for DESFire Cards - /// - public enum KeyType - { - /// - /// DES Key - 8 Byte - 64 Bit - /// - DES, - - /// - /// Triple DES Key with two DES Keys - 16 Byte - 128 Bit - /// - TDES_2K, - - /// - /// Triple DES Key with three DES Keys - 24 Byte - 192 Bit - /// - TDES_3K, - - /// - /// AES Key - 16 Byte - 128 Bit - /// - AES - } - - /// - /// Check the Key Length to get Type of DES/3DES Key - /// - public KeyType GetKeyTypeDES(byte[] key) - { - switch(key.Length) - { - case 8: - return KeyType.DES; - case 16: - return KeyType.TDES_2K; - case 24: - return KeyType.TDES_3K; - default: - throw new ArgumentException(string.Format("No valid DES/3DES Key Size({0})", key.Length)); - } - } - - #region Methods for Crypto Operation + #region Crypto Operation /// /// Return a copy of the last Block of data /// /// Data compatible to blocksize - /// Size of Block, default is 8 - public byte[] GetLastBlock(byte[] data, uint blocksize = 8) + /// in byte + public byte[] ExtractLastBlock(byte[] data, uint blocksize) { - if(data.Length % blocksize != 0) + if (data == null) { - throw new ArgumentException(string.Format("Data is not compatible with blocksize(data(length):{0}, blocksize:{1}", data.Length, blocksize)); + throw new ArgumentNullException("Data cannot be null."); } - byte[] block = new byte[blocksize]; + if (data.Length % blocksize != 0) + { + throw new ArgumentException(string.Format("Data is not compatible with blocksize(data(length):{0}, blocksize:{1}.", data.Length, blocksize)); + } + + byte[] lastblock = new byte[blocksize]; for (int i = 0; i < blocksize; i++) { - block[i] = data[data.Length - blocksize + i]; + lastblock[i] = data[data.Length - blocksize + i]; } - return block; + return lastblock; } /// @@ -150,8 +193,13 @@ namespace NFC.Mifare_DESFire /// /// Data /// Copy of data - public byte[] rotateLeft(byte[] data) + public byte[] RotateLeft(byte[] data) { + if (data == null) + { + throw new ArgumentNullException("Data cannot be null."); + } + byte[] rotate = new byte[data.Length]; data.CopyTo(rotate, 0); @@ -170,8 +218,13 @@ namespace NFC.Mifare_DESFire /// /// Data /// Copy of data - public byte[] rotateRight(byte[] data) + public byte[] RotateRight(byte[] data) { + if (data == null) + { + throw new ArgumentNullException("Data cannot be null."); + } + byte[] rotate = new byte[data.Length]; data.CopyTo(rotate, 0); @@ -186,25 +239,47 @@ namespace NFC.Mifare_DESFire } /// - /// Concatenates two Arrays, Array A start at index 0 + /// Concatenates Arrays + /// + /// List of Byte Array + public byte[] Concatenate(params byte[][] data) + { + if (data == null) + { + throw new ArgumentNullException("Data cannot be null."); + } + + List cat = new List(); + + foreach(byte[] d in data) + { + cat.AddRange(d); + } + + return cat.ToArray(); + } + + /// + /// Boolean Operation XOR on all Bytes /// /// Array A /// Array B /// Copy of Data - public byte[] concatenate(byte[] a, byte[] b) + public byte[] XOR(byte[] a, byte[] b) { - byte[] c = new byte[a.Length + b.Length]; - a.CopyTo(c, 0); - b.CopyTo(c, a.Length); - - return c; - } - - public byte[] xor(byte[] a, byte[] b) - { - if(a.Length != b.Length) + if (a == null) { - throw new ArgumentException("Array are not same Length"); + throw new ArgumentNullException("Array A cannot be null."); + } + + if (b == null) + { + throw new ArgumentNullException("Array B cannot be null."); + } + + if (a.Length != b.Length) + { + throw new ArgumentException(string.Format("Arrays are not same Length(Length A:{0}, Lenght B:{1})", a.Length, b.Length)); } byte[] c = new byte[a.Length]; @@ -216,246 +291,18 @@ namespace NFC.Mifare_DESFire return c; } - #endregion - - #endregion - - #region DESFire Commands - /// - /// Get Application IDs from Card - /// - /// AIDs as Array - public UInt32[] GetApplicationIDs() - { - APDUCommand cmd = new APDUCommand(IsoCase.Case2Short) - { - CLA = 0x90, - INS = (byte)APDUInstructions.GET_APPLICATION_IDS - }; - - APDUResponse response = _Card.Transmit(cmd); - - CheckAPDUResponse(response); - - if (response.Body.Length % 3 != 0) - { - throw new Exception(string.Format("Invalid body length (was: {0}).", response.Body.Length)); - } - - if(response.Body.Length == 0) - { - throw new Exception("Missing PICC Entry 0x000000."); - } - - List applicationIDs = new List(); - - for (int i = 0; i < response.Body.Length; i += 3) - { - UInt32 new_applicationID = 0; - new_applicationID = (UInt32)((response.Body[i] << 16) + (response.Body[i + 1] << 8) + response.Body[i + 2]); - applicationIDs.Add(new_applicationID); - } - - return applicationIDs.ToArray(); - } /// - /// Select Application by AID + /// Generates SessionKey for DES Authentification /// - /// 3 Byte AID - public void SelectApplication(UInt32 aid) - { - byte[] id_byte = BitConverter.GetBytes(aid); - - APDUCommand cmd = new APDUCommand(IsoCase.Case4Short) - { - CLA = 0x90, - INS = (byte)APDUInstructions.SELECT_APPLICATION, - Data = new byte[] - { - id_byte[0], - id_byte[1], - id_byte[2] - } - }; - - APDUResponse response = _Card.Transmit(cmd); - - CheckAPDUResponse(response); - } - #endregion - - /// - /// Expand Array to Block Size - /// - /// - /// - public byte[] expandToBlockSize(byte[] data, int bocksize) - { - int diff = data.Length % bocksize; - if (diff == 0) - { - return data; - } - - byte[] expand = new byte[data.Length + bocksize - diff]; - - data.CopyTo(expand, 0); - - for(int i = expand.Length - 1; i > data.Length - 1; i--) - { - expand[i] = 0x00; - } - - return expand; - } - - public void ChangeKeyDES(byte key_no, byte[] key_new, byte[] key_current) - { - Console.WriteLine("key_new: {0}", ConvertToHexString(key_new)); - key_new = concatenate(key_new, key_new); - Console.WriteLine("key_new_double: {0}", ConvertToHexString(key_new)); - - byte[] header = new byte[] - { - 0xC4, key_no - }; - Console.WriteLine("header: {0}", ConvertToHexString(header)); - - byte[] cmd_ = concatenate(header, key_new); - Console.WriteLine("cmd_: {0}", ConvertToHexString(cmd_)); - - CRC32 crc = new CRC32(); - byte[] cmd_crc = crc.Calculate(cmd_); - Console.WriteLine("cmd_crc: {0}", ConvertToHexString(cmd_crc)); - byte[] cryptogram = concatenate(key_new, cmd_crc); - Console.WriteLine("cryptogram: {0}", ConvertToHexString(cryptogram)); - - byte[] cryptogram_block = expandToBlockSize(cryptogram, 8); - Console.WriteLine("cryptogram_block: {0}", ConvertToHexString(cryptogram_block)); - - DES des = new DES(); - - byte[] cryptogram_block_enc = des.Encrypt(cryptogram_block, _SessionKey, _IV); - Console.WriteLine("cryptogram_block_enc: {0}", ConvertToHexString(cryptogram_block_enc)); - - byte[] data = concatenate(new byte[] { key_no }, cryptogram_block_enc); - Console.WriteLine("data: {0}", ConvertToHexString(data)); - - APDUCommand cmd = new APDUCommand(IsoCase.Case4Short) - { - CLA = 0x90, - INS = 0xC4, - Data = data - }; - Console.WriteLine("cmd: {0}", ConvertToHexString(cmd.ToArray())); - - APDUResponse response = _Card.Transmit(cmd); - - CheckAPDUResponse(response); - } - - - - - - - - /// - /// Create new Application with AID - /// - /// Appilication ID - public APDUCommand CreateApplication(UInt64 aid) - { - throw new NotImplementedException(); - } - - public void Format() - { - throw new NotImplementedException(); - } - - /// - /// Authenticate to Card - /// - /// 0x01 - 0x0D - /// - - // TODO - public void AuthenticateDES(byte key_id, byte[] key) - { - APDUCommand cmd_challange_request = new APDUCommand(IsoCase.Case4Short) - { - CLA = 0x90, - INS = (byte)0x1A, - Data = new byte[] - { - key_id - } - }; - APDUResponse response = _Card.Transmit(cmd_challange_request); - - byte[] rndB_enc = response.Body; - Console.WriteLine("rndB_enc: {0}", ConvertToHexString(rndB_enc)); - - DES des = new DES(); - byte[] rndB = des.Decrypt(rndB_enc, key, GenerateDefaultKey(8)); - Console.WriteLine("rndB: {0}", ConvertToHexString(rndB)); - - byte[] iv = new byte[8]; - rndB.CopyTo(iv, 0); - - byte[] rndB_rl = rotateLeft(rndB); - Console.WriteLine("rndB_enc: {0}", ConvertToHexString(rndB_rl)); - - byte[] rndA = new byte[] - { - 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08 - }; - Console.WriteLine("rndA: {0}", ConvertToHexString(rndA)); - - byte[] rndAB = concatenate(rndA, rndB_rl); - Console.WriteLine("rndAB: {0}", ConvertToHexString(rndAB)); - - byte[] rndAB_enc = des.Encrypt(rndAB, key, rndB_enc); - Console.WriteLine("rndA_rndB_enc: {0}", ConvertToHexString(rndAB_enc)); - iv = GetLastBlock(rndAB_enc); - - APDUCommand cmd_challange_response = new APDUCommand(IsoCase.Case4Short) - { - CLA = 0x90, - INS = (byte)0xAF, - Data = rndAB_enc - }; - Console.WriteLine("cmd_challange_response: {0}", ConvertToHexString(cmd_challange_response.ToArray())); - - response = _Card.Transmit(cmd_challange_response); - - byte[] encryptedRndAFromCard = response.Body; - Console.WriteLine("encryptedRndAFromCard: {0}", ConvertToHexString(encryptedRndAFromCard)); - - byte[] rotatedRndAFromCard = des.Decrypt(encryptedRndAFromCard, key, iv); - Console.WriteLine("rotatedRndAFromCard: {0}", ConvertToHexString(rotatedRndAFromCard)); - - byte[] rndAFromCard = rotateRight(rotatedRndAFromCard); - Console.WriteLine("rndAFromCard: {0}", ConvertToHexString(rndAFromCard)); - - if (!rndA.SequenceEqual(rndAFromCard)) - { - throw new Exception("PICC Challenge is not correct answered."); - } - - _SessionKey = GenerateDESSesionKey(rndA, rndB); - _IV = GenerateDefaultKey(8); - } - - private byte[] GenerateDESSesionKey(byte[] rndA, byte[] rndB) + /// 16Byte SessionKey + public byte[] GenerateSesionKey_DES(byte[] rndA, byte[] rndB) { byte[] sesssionkey = new byte[8]; - for(int i = 0; i < sesssionkey.Length; i++) + for (int i = 0; i < sesssionkey.Length; i++) { - if(i < 4) + if (i < 4) { sesssionkey[i] = rndA[i]; } @@ -465,13 +312,45 @@ namespace NFC.Mifare_DESFire } } - // Set Key Verion of Key to 0x55 to LSB - // TODO - byte[] key_version = SetKeyVersion(sesssionkey, 0x55); - - return concatenate(key_version, key_version); + // DES SessionKey is a double DES Key + return Concatenate(sesssionkey, sesssionkey); } + /// + /// Generates SessionKey for AES Authentification + /// + /// 16Byte SessionKey + public byte[] GenerateSesionKey_AES(byte[] rndA, byte[] rndB) + { + byte[] sesssionkey = new byte[16]; + + for (int i = 0; i < sesssionkey.Length; i++) + { + if (i < 4) + { + sesssionkey[i] = rndA[i]; + } + else if(i >= 4 && i < 8) + { + sesssionkey[i] = rndB[i - 4]; + } + else if (i >= 8 && i < 12) + { + sesssionkey[i] = rndA[i + 4]; + } + else + { + sesssionkey[i] = rndB[i]; + } + } + + return sesssionkey; + } + + /// + /// Set KeyVersion in DES Key + /// KeyVersion is stored in LSB of the first 8 Bytes of the DES Key + /// public byte[] SetKeyVersion(byte[] key, byte keyversion) { byte[] pow2 = new byte[] @@ -482,10 +361,9 @@ namespace NFC.Mifare_DESFire byte[] new_key = new byte[key.Length]; key.CopyTo(new_key, 0); - - for(int i = 0; i < 8; i++) + for (int i = 0; i < 8; i++) { - if((keyversion & pow2[i]) > 0) + if ((keyversion & pow2[i]) > 0) { new_key[i] = (byte)(new_key[5] | 0x01); } @@ -498,53 +376,162 @@ namespace NFC.Mifare_DESFire return new_key; } - public void ChangeApplicationMasterKey(byte[] aPP_MasterKey) - { - throw new NotImplementedException(); - } - /// - /// Delete Application by ID + /// Expand Array to Block Size, fill with 0x00 /// - /// 3 Byte ID - public void DeleteApplication(UInt32 id) + /// + public byte[] ExpandToBlockSize(byte[] data, uint bocksize) { - byte[] id_byte = BitConverter.GetBytes(id); + int diff = data.Length % (int)bocksize; + if (diff == 0) + { + return data; + } - APDUCommand cmd = new APDUCommand(IsoCase.Case4Short) + byte[] expand = new byte[data.Length + bocksize - diff]; + + data.CopyTo(expand, 0); + + for (int i = expand.Length - 1; i > data.Length - 1; i--) + { + expand[i] = 0x00; + } + + return expand; + } + #endregion + + #region DESFire Commands + /// + /// Authenticate to PICC, with ISO Authenticate + /// + /// 0x01 - 0x0D + /// + /// !!! 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"); + + // Sepearte InitialisationVector for Authentication + byte[] iv = new byte[8]; + + APDUCommand cmd_challange_request = new APDUCommand(IsoCase.Case4Short) { CLA = 0x90, - INS = (byte)APDUInstructions.DELETE_APPLICATION, + INS = 0x1A, Data = new byte[] { - id_byte[0], - id_byte[1], - id_byte[2] - }, - Le = 0x00 + key_id + } }; + _Log.DebugFormat("APDU_CMD(cmd_challange_request): {0}", ConvertToHexString(cmd_challange_request.ToArray())); + + APDUResponse response = _Card.Transmit(cmd_challange_request); + _Log.DebugFormat("APDU_RES(cmd_challange_request): {0}", ConvertToHexString(response.ToArray())); - APDUResponse response = _Card.Transmit(cmd); CheckAPDUResponse(response); - } - public void ChangeApplicationKey(int v, byte[] aPP_Key_1) - { - throw new NotImplementedException(); + byte[] rndB_enc = response.Body; + _Log.DebugFormat("rndB_enc: {0}", ConvertToHexString(rndB_enc)); + + TDES des = new TDES(); + byte[] rndB = des.Decrypt(rndB_enc, key, GenerateEmptyKey(8)); + _Log.DebugFormat("rndB: {0}", ConvertToHexString(rndB)); + + rndB.CopyTo(iv, 0); + + byte[] rndB_rl = RotateLeft(rndB); + _Log.DebugFormat("rndB_enc: {0}", ConvertToHexString(rndB_rl)); + + if(rndA == null) + { + Random rnd = new Random(); + rndA = new byte[8]; + rnd.NextBytes(rndA); + } + _Log.DebugFormat("rndA: {0}", ConvertToHexString(rndA)); + + byte[] rndAB = Concatenate(rndA, rndB_rl); + _Log.DebugFormat("rndAB: {0}", ConvertToHexString(rndAB)); + + byte[] rndAB_enc = des.Encrypt(rndAB, key, rndB_enc); + _Log.DebugFormat("rndA_rndB_enc: {0}", ConvertToHexString(rndAB_enc)); + iv = ExtractLastBlock(rndAB_enc, 8); + + APDUCommand cmd_challange_response = new APDUCommand(IsoCase.Case4Short) + { + CLA = 0x90, + INS = 0xAF, + Data = rndAB_enc + }; + _Log.DebugFormat("APDU_CMD(cmd_challange_response): {0}", ConvertToHexString(cmd_challange_response.ToArray())); + + response = _Card.Transmit(cmd_challange_response); + _Log.DebugFormat("APDU_RES(cmd_challange_response): {0}", ConvertToHexString(cmd_challange_response.ToArray())); + + CheckAPDUResponse(response); + + byte[] encryptedRndAFromCard = response.Body; + _Log.DebugFormat("encryptedRndAFromCard: {0}", ConvertToHexString(encryptedRndAFromCard)); + + byte[] rotatedRndAFromCard = des.Decrypt(encryptedRndAFromCard, key, iv); + _Log.DebugFormat("rotatedRndAFromCard: {0}", ConvertToHexString(rotatedRndAFromCard)); + + byte[] rndAFromCard = RotateRight(rotatedRndAFromCard); + _Log.DebugFormat("rndAFromCard: {0}", ConvertToHexString(rndAFromCard)); + + if (!rndA.SequenceEqual(rndAFromCard)) + { + throw new Exception("Authentication failed, PICC Challenge is not corret"); + } + + _SessionKey = GenerateSesionKey_DES(rndA, rndB); + _Log.DebugFormat("_SessionKey: {0}", ConvertToHexString(_SessionKey)); + + _IV = GenerateEmptyKey(8); + _Log.DebugFormat("_IV: {0}", ConvertToHexString(_IV)); + + _Log.Debug("End AuthenticateISO_DES"); } /// - /// Select Application by ID + /// Format PICC /// - /// 3 Byte ID - public APDUCommand CreateApplication(UInt32 id, byte keysetting1, byte keysetting2) + public void Format() { - byte[] id_byte = BitConverter.GetBytes(id); + _Log.Debug("Start Format"); - APDUCommand cmd = new APDUCommand(IsoCase.Case4Short) + APDUCommand cmd_format = new APDUCommand(IsoCase.Case2Short) { CLA = 0x90, - INS = (byte)APDUInstructions.CREATE_APPLICATION, + INS = 0xFC, + }; + _Log.DebugFormat("APDU_CMD(cmd_format): {0}", ConvertToHexString(cmd_format.ToArray())); + + APDUResponse response = _Card.Transmit(cmd_format); + _Log.DebugFormat("APDU_RES(cmd_format): {0}", ConvertToHexString(response.ToArray())); + + CheckAPDUResponse(response); + + _Log.Debug("End Format"); + } + + /// + /// Create Application for ID + /// + /// 3 Byte ID + public void CreateApplication(UInt32 aid, byte keysetting1, byte keysetting2) + { + _Log.Debug("Start CreateApplication"); + + byte[] id_byte = BitConverter.GetBytes(aid); + _Log.DebugFormat("AID: {0}", ConvertToHexString(id_byte.ToArray())); + + APDUCommand cmd_CreateApplication = new APDUCommand(IsoCase.Case4Short) + { + CLA = 0x90, + INS = 0xCA, Data = new byte[] { id_byte[0], @@ -552,38 +539,476 @@ namespace NFC.Mifare_DESFire id_byte[2], keysetting1, keysetting2 - }, - Le = 0x00 + } + }; + _Log.DebugFormat("APDU_CMD(cmd_CreateApplication): {0}", ConvertToHexString(cmd_CreateApplication.ToArray())); + + APDUResponse response = _Card.Transmit(cmd_CreateApplication); + _Log.DebugFormat("APDU_RES(cmd_CreateApplication): {0}", ConvertToHexString(response.ToArray())); + + 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}", 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}", ConvertToHexString(cmd_SelectApplication.ToArray())); + + APDUResponse response = _Card.Transmit(cmd_SelectApplication); + _Log.DebugFormat("APDU_RES(cmd_SelectApplication): {0}", ConvertToHexString(response.ToArray())); + + CheckAPDUResponse(response); + + _Log.Debug("End SelectApplication"); + } + + /// + /// Authenticate to PICC, with ISO Authenticate + /// + /// 0x01 - 0x0D + /// + /// !!! 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"); + + // Sepearte InitialisationVector for Authentication + byte[] iv = new byte[16]; + + APDUCommand cmd_challange_request = new APDUCommand(IsoCase.Case4Short) + { + CLA = 0x90, + INS = 0xAA, + Data = new byte[] + { + key_id + } + }; + _Log.DebugFormat("APDU_CMD(cmd_challange_request): {0}", ConvertToHexString(cmd_challange_request.ToArray())); + + APDUResponse response = _Card.Transmit(cmd_challange_request); + _Log.DebugFormat("APDU_RES(cmd_challange_request): {0}", ConvertToHexString(response.ToArray())); + + CheckAPDUResponse(response); + + byte[] rndB_enc = response.Body; + _Log.DebugFormat("rndB_enc: {0}", ConvertToHexString(rndB_enc)); + + AES aes = new AES(); + byte[] rndB = aes.Decrypt(rndB_enc, key, GenerateEmptyKey(16)); + _Log.DebugFormat("rndB: {0}", ConvertToHexString(rndB)); + + rndB.CopyTo(iv, 0); + + byte[] rndB_rl = RotateLeft(rndB); + _Log.DebugFormat("rndB_enc: {0}", ConvertToHexString(rndB_rl)); + + if (rndA == null) + { + Random rnd = new Random(); + rndA = new byte[16]; + rnd.NextBytes(rndA); + } + _Log.DebugFormat("rndA: {0}", ConvertToHexString(rndA)); + + byte[] rndAB = Concatenate(rndA, rndB_rl); + _Log.DebugFormat("rndAB: {0}", ConvertToHexString(rndAB)); + + byte[] rndAB_enc = aes.Encrypt(rndAB, key, rndB_enc); + _Log.DebugFormat("rndA_rndB_enc: {0}", ConvertToHexString(rndAB_enc)); + iv = ExtractLastBlock(rndAB_enc, 16); + + APDUCommand cmd_challange_response = new APDUCommand(IsoCase.Case4Short) + { + CLA = 0x90, + INS = 0xAF, + Data = rndAB_enc + }; + _Log.DebugFormat("APDU_CMD(cmd_challange_response): {0}", ConvertToHexString(cmd_challange_response.ToArray())); + + response = _Card.Transmit(cmd_challange_response); + _Log.DebugFormat("APDU_RES(cmd_challange_response): {0}", ConvertToHexString(cmd_challange_response.ToArray())); + + CheckAPDUResponse(response); + + byte[] encryptedRndAFromCard = response.Body; + _Log.DebugFormat("encryptedRndAFromCard: {0}", ConvertToHexString(encryptedRndAFromCard)); + + byte[] rotatedRndAFromCard = aes.Decrypt(encryptedRndAFromCard, key, iv); + _Log.DebugFormat("rotatedRndAFromCard: {0}", ConvertToHexString(rotatedRndAFromCard)); + + byte[] rndAFromCard = RotateRight(rotatedRndAFromCard); + _Log.DebugFormat("rndAFromCard: {0}", ConvertToHexString(rndAFromCard)); + + if (!rndA.SequenceEqual(rndAFromCard)) + { + throw new Exception("Authentication failed, PICC Challenge is not corret"); + } + + _SessionKey = GenerateSesionKey_AES(rndA, rndB); + _Log.DebugFormat("_SessionKey: {0}", ConvertToHexString(_SessionKey)); + + _IV = GenerateEmptyKey(16); + _Log.DebugFormat("_IV: {0}", ConvertToHexString(_IV)); + + _Log.Debug("End AuthenticateISO_DES"); + } + + /// + /// Change Same AES key as Authenticated + /// + /// + /// + /// + public void ChangeKey_AES(byte key_id, byte[] new_key, byte key_version) + { + _Log.Debug("Start ChangeKey_AES"); + + byte[] header = new byte[] + { + 0xC4, key_id + }; + _Log.DebugFormat("header: {0}", ConvertToHexString(header)); + + // AES Key Version is Append to Key + byte[] key_and_version = Concatenate(new_key, new byte[] { key_version }); + byte[] command = Concatenate(header, key_and_version); + _Log.DebugFormat("command: {0}", ConvertToHexString(command)); + + CRC32 crc32 = new CRC32(); + byte[] crc = crc32.Calculate(command); + _Log.DebugFormat("crc: {0}", ConvertToHexString(crc)); + + byte[] cryptogram = Concatenate(key_and_version, crc); + _Log.DebugFormat("cryptogram: {0}", ConvertToHexString(cryptogram)); + + byte[] cryptogram_block = ExpandToBlockSize(cryptogram, 16); + _Log.DebugFormat("cryptogram_block: {0}", ConvertToHexString(cryptogram_block)); + + AES aes = new AES(); + byte[] cryptogram_enc = aes.Encrypt(cryptogram_block, _SessionKey, _IV); + _Log.DebugFormat("cryptogram_enc: {0}", ConvertToHexString(cryptogram_enc)); + + _IV = ExtractLastBlock(cryptogram_enc, 16); + _Log.DebugFormat("_IV: {0}", ConvertToHexString(_IV)); + + byte[] data = Concatenate(new byte[] { key_id }, cryptogram_enc); + _Log.DebugFormat("data: {0}", ConvertToHexString(data)); + + APDUCommand cmd_ChangeKey = new APDUCommand(IsoCase.Case4Short) + { + CLA = 0x90, + INS = 0xC4, + Data = data + }; + _Log.DebugFormat("APDU_CMD(cmd_ChangeKey): {0}", ConvertToHexString(cmd_ChangeKey.ToArray())); + + APDUResponse response = _Card.Transmit(cmd_ChangeKey); + _Log.DebugFormat("APDU_RES(cmd_ChangeKey): {0}", ConvertToHexString(response.ToArray())); + + CheckAPDUResponse(response); + + _Log.Debug("End ChangeKey_AES"); + } + + /// + /// Change other AES key as Authenticated + /// + /// + /// + /// + public void ChangeOtherKey_AES(byte key_id, byte[] new_key, byte[] old_key, byte key_version) + { + _Log.Debug("Start ChangeOtherKey_AES"); + + byte[] header = new byte[] + { + 0xC4, key_id + }; + _Log.DebugFormat("header: {0}", ConvertToHexString(header)); + + byte[] key_xor = XOR(new_key, old_key); + + // AES Key Version is Append to Key + byte[] key_and_version = Concatenate(key_xor, new byte[] { key_version }); + byte[] command = Concatenate(header, key_and_version); + _Log.DebugFormat("command: {0}", ConvertToHexString(command)); + + CRC32 crc32 = new CRC32(); + byte[] crc_cmd = crc32.Calculate(command); + _Log.DebugFormat("crc_cmd: {0}", ConvertToHexString(crc_cmd)); + byte[] crc_key = crc32.Calculate(new_key); + _Log.DebugFormat("crc_key: {0}", ConvertToHexString(crc_key)); + + byte[] cryptogram = Concatenate(key_and_version, crc_cmd); + cryptogram = Concatenate(cryptogram, crc_key); + _Log.DebugFormat("cryptogram: {0}", ConvertToHexString(cryptogram)); + + byte[] cryptogram_block = ExpandToBlockSize(cryptogram, 16); + _Log.DebugFormat("cryptogram_block: {0}", ConvertToHexString(cryptogram_block)); + + AES aes = new AES(); + byte[] cryptogram_enc = aes.Encrypt(cryptogram_block, _SessionKey, _IV); + _Log.DebugFormat("cryptogram_enc: {0}", ConvertToHexString(cryptogram_enc)); + + _IV = ExtractLastBlock(cryptogram_enc, 16); + _Log.DebugFormat("_IV: {0}", ConvertToHexString(_IV)); + + byte[] data = Concatenate(new byte[] { key_id }, cryptogram_enc); + _Log.DebugFormat("data: {0}", ConvertToHexString(data)); + + APDUCommand cmd_ChangeKey = new APDUCommand(IsoCase.Case4Short) + { + CLA = 0x90, + INS = 0xC4, + Data = data + }; + _Log.DebugFormat("APDU_CMD(cmd_ChangeKey): {0}", ConvertToHexString(cmd_ChangeKey.ToArray())); + + APDUResponse response = _Card.Transmit(cmd_ChangeKey); + _Log.DebugFormat("APDU_RES(cmd_ChangeKey): {0}", ConvertToHexString(response.ToArray())); + + CheckAPDUResponse(response); + + _Log.Debug("End ChangeOtherKey_AES"); + } + + /// + /// Create Standard Data File + /// + /// ID of File (0x01 - 0x10) + /// 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); + + byte[] accessRights_byte = BitConverter.GetBytes(accessRights); + byte[] size_byte_tolong = BitConverter.GetBytes(size); + // Use only 3 Bytes + byte[] size_byte = new byte[] + { + size_byte_tolong[0], + size_byte_tolong[1], + size_byte_tolong[2], }; - return cmd; + byte[] data = new byte[] + { + file_id, + (byte)communication + }; + + APDUCommand cmd_CreateFile_Standard = new APDUCommand(IsoCase.Case4Short) + { + CLA = 0x90, + INS = (byte)APDUInstructions.CREATE_STDDATAFILE, + Data = Concatenate(data, accessRights_byte, size_byte) + }; + _Log.DebugFormat("APDU_CMD(cmd_CreateFile_Standard): {0}", ConvertToHexString(cmd_CreateFile_Standard.ToArray())); + + APDUResponse response = _Card.Transmit(cmd_CreateFile_Standard); + _Log.DebugFormat("APDU_RES(cmd_CreateFile_Standard): {0}", ConvertToHexString(response.ToArray())); + + CheckAPDUResponse(response); + + _Log.Debug("End CreateFile_Standard"); } - public void CreateFile(byte fabAccessIdentFileID, FileCommunication pLAIN, ushort fileAccessRight, UInt32 v) + /// + /// 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) { - throw new NotImplementedException(); + _Log.Debug("Start ReadData"); + + byte[] data = new byte[] + { + file_id + }; + + byte[] offset_byte_tolong = BitConverter.GetBytes(offset); + // Use only 3 Bytes + byte[] offset_byte = new byte[] + { + offset_byte_tolong[0], + offset_byte_tolong[1], + offset_byte_tolong[2], + }; + + byte[] length_byte_tolong = BitConverter.GetBytes(length); + // 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}", ConvertToHexString(cmd_ReadData.ToArray())); + + APDUResponse response = _Card.Transmit(cmd_ReadData); + _Log.DebugFormat("APDU_RES(cmd_ReadData): {0}", ConvertToHexString(response.ToArray())); + + CheckAPDUResponse(response); + + _Log.Debug("End ReadData"); + + return response.Body; } - public ushort GenerateFileAccessRight(AccessRights fREE, int v1, int v2, int v3) + /// + /// Write Data to File + /// + /// ID of File (0x01 - 0x10) + /// Offset for File + /// Data to write + public void WriteData(byte file_id, UInt32 offset, byte[] data) { - throw new NotImplementedException(); + _Log.Debug("Start WriteData"); + + byte[] file_id_array = new byte[] + { + file_id + }; + + byte[] offset_byte_tolong = BitConverter.GetBytes(offset); + // Use only 3 Bytes + byte[] offset_byte = new byte[] + { + offset_byte_tolong[0], + offset_byte_tolong[1], + offset_byte_tolong[2], + }; + + byte[] lenght_byte_tolong = BitConverter.GetBytes(data.Length); + // Use only 3 Bytes + byte[] lenght_byte = new byte[] + { + lenght_byte_tolong[0], + lenght_byte_tolong[1], + lenght_byte_tolong[2], + }; + + APDUCommand cmd_WriteData = new APDUCommand(IsoCase.Case4Short) + { + CLA = 0x90, + INS = (byte)APDUInstructions.WRITE_DATA, + Data = Concatenate(file_id_array, offset_byte, lenght_byte, data) + }; + _Log.DebugFormat("APDU_CMD(cmd_WriteData): {0}", ConvertToHexString(cmd_WriteData.ToArray())); + + APDUResponse response = _Card.Transmit(cmd_WriteData); + _Log.DebugFormat("APDU_RES(cmd_WriteData): {0}", ConvertToHexString(response.ToArray())); + + CheckAPDUResponse(response); + + _Log.Debug("End WriteData"); } - public void WirteData(byte fabAccessIdentFileID, int v1, int v2, byte[] vs) - { - throw new NotImplementedException(); - } + /// + /// Get all ApplicationIDS from PICC + /// + /// AIDs (3 Byte) as Array + //public UInt32[] GetApplicationIDs() + //{ + // _Log.Debug("Start GetApplicationIDs"); - public void CreateFile(byte fabAccessIdentFileID, object plain, AccessRights fREE, int v1, int v2, int v3) - { - throw new NotImplementedException(); - } + // APDUCommand cmd = new APDUCommand(IsoCase.Case2Short) + // { + // CLA = 0x90, + // INS = (byte)APDUInstructions.GET_APPLICATION_IDS + // }; - public byte[] ReadData(byte identFileID, int v1, int v2) - { - throw new NotImplementedException(); - } + // APDUResponse response = _Card.Transmit(cmd); + // CheckAPDUResponse(response); + + // if (response.Body.Length % 3 != 0) + // { + // throw new Exception(string.Format("Invalid body length (was: {0}).", response.Body.Length)); + // } + + // if (response.Body.Length == 0) + // { + // throw new Exception("Missing PICC Entry 0x000000."); + // } + + // List applicationIDs = new List(); + + // for (int i = 0; i < response.Body.Length; i += 3) + // { + // UInt32 new_applicationID = 0; + // new_applicationID = (UInt32)((response.Body[i] << 16) + (response.Body[i + 1] << 8) + response.Body[i + 2]); + // applicationIDs.Add(new_applicationID); + // } + + // _Log.Debug("End GetApplicationIDs"); + + // return applicationIDs.ToArray(); + //} + + /// + /// Delete Application by ID + /// + /// 3 Byte ID + //public void DeleteApplication(UInt32 id) + //{ + // byte[] id_byte = BitConverter.GetBytes(id); + + // APDUCommand cmd = new APDUCommand(IsoCase.Case4Short) + // { + // CLA = 0x90, + // INS = (byte)APDUInstructions.DELETE_APPLICATION, + // Data = new byte[] + // { + // id_byte[0], + // id_byte[1], + // id_byte[2] + // }, + // Le = 0x00 + // }; + + // APDUResponse response = _Card.Transmit(cmd); + // CheckAPDUResponse(response); + //} + #endregion + + #region Configuration Generator /// /// Genearte KeySetting1 for Application Settings or PICC Setting /// @@ -592,6 +1017,53 @@ namespace NFC.Mifare_DESFire return (byte)(((byte)changeKey << 4) | (byte)changeMasterKeySettings | (byte)createDeleteFile | (byte)fileDirectoryAccess | (byte)changeMasterKey); } - + /// + /// Genearte KeySetting1 for Application Settings or PICC Setting + /// + /// ID of Key for changing Application Keys + /// + public byte GenerateKeySetting1(byte changeKey, ChangeMasterKeySettings changeMasterKeySettings, CreateDeleteFile createDeleteFile, FileDirectoryAccess fileDirectoryAccess, ChangeMasterKey changeMasterKey) + { + if (changeKey < 0x01 || changeKey >= 0x0E) + { + throw new ArgumentOutOfRangeException(); + } + return GenerateKeySetting1(changeKey, changeMasterKeySettings, createDeleteFile, fileDirectoryAccess, changeMasterKey); + } + + /// + /// Genearte KeySetting2 for Application Creation + /// + /// Number of keys that can be stored within the application (0x01-0x0D) + /// + public byte GenerateKeySetting2(CryptoOperationsType cryptoOperations, FileIdentifies fileIdentifies, byte numberOfKeys) + { + if (numberOfKeys < 0x01 || numberOfKeys >= 0x0D) + { + throw new ArgumentOutOfRangeException(); + } + + return (byte)((byte)cryptoOperations | (byte)fileIdentifies | numberOfKeys); + } + + /// + /// Generate FileAccess Rights for File Settings + /// Use enum AccesRights for Free or Never Option + /// + /// KeyID for Read Access + /// KeyID for Write Access + /// KeyID for Read and Write Access + /// KeyID for Configuration Access + public UInt16 GenerateFileAccessRights(byte read, byte write, byte read_write, byte configure) + { + if(read > 0x0F || write > 0x0F || read_write > 0x0F || configure > 0x0F) + { + throw new ArgumentOutOfRangeException("One KeyID is not valid"); + } + + return (UInt16)((read << 12) | (write << 8) | (read_write << 4) | configure); + } + #endregion + #endregion } } diff --git a/NFC/NXP MIFARE DESFire/MIFARE_DESFire_V2.cs b/NFC/NXP MIFARE DESFire/MIFARE_DESFire_V2.cs deleted file mode 100644 index b0bda50..0000000 --- a/NFC/NXP MIFARE DESFire/MIFARE_DESFire_V2.cs +++ /dev/null @@ -1,844 +0,0 @@ -using log4net.Repository.Hierarchy; -using NFC.Crypto; -using NFC.ISO7816_4; -using NFC.Mifare_DESFire.Enums; -using NFC.NXP_MIFARE_DESFire.Exceptions; -using PCSC.Iso7816; -using System; -using System.Linq; - -namespace NFC.Mifare_DESFire -{ - public class MIFARE_DESFire_V2 - { - // Docs https://hackmd.io/qATu8uYdRnOC40aFrB9afg - - #region Log - private static readonly log4net.ILog _Log = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType); - #endregion - - #region Contructors - /// - /// Construct MIFRARE_DESFire Object with ICard Interface - /// - /// Implementation of ICard, only transmit is used - public MIFARE_DESFire_V2(ICard card) - { - _Card = card; - } - #endregion - - #region Properties - /// - /// ICard Implementation used to transmit APDUCommands and recive APDUResponses - /// - private ICard _Card; - - /// - /// SessionKey, is set after Successfull Authentication - /// - public byte[] _SessionKey; - - /// - /// Initialation Vector for CBC Encryption - /// Is 0 bytes after Successfull Authentication - /// - public byte[] _IV; - #endregion - - #region Methods - #region Helper Methods - /// - /// Generate Byte Array filled with 0 - /// - /// Size of Array - public byte[] GenerateEmptyKey(uint size) - { - byte[] key = new byte[size]; - for (int i = 0; i < size; i++) - { - key[i] = 0; - } - - return key; - } - - /// - /// Converts byte[] to string with HEX Code - /// No 0x is created - /// - /// Data - public string ConvertToHexString(byte[] data) - { - return BitConverter.ToString(data).Replace("-", "").ToLower(); - } - - /// - /// Converts string with HEX Code to byte[] - /// No 0x is requiered - /// - /// Data - public byte[] ConvertFromHexString(string data) - { - if (data.Length % 2 == 1) - throw new Exception("Data Length is uneven."); - - byte[] arr = new byte[data.Length >> 1]; - - for (int i = 0; i < data.Length >> 1; ++i) - { - arr[i] = (byte)((GetHexVal(data[i << 1]) << 4) + (GetHexVal(data[(i << 1) + 1]))); - } - - return arr; - } - - private int GetHexVal(char hex) - { - int val = (int)hex; - //For uppercase A-F letters: - //return val - (val < 58 ? 48 : 55); - //For lowercase a-f letters: - //return val - (val < 58 ? 48 : 87); - //Or the two combined, but a bit slower: - return val - (val < 58 ? 48 : (val < 97 ? 55 : 87)); - } - - /// - /// Check APDU Response for DESFire Error Codes - /// https://www.nxp.com/docs/en/data-sheet/MF2DLHX0.pdf - /// Section: 11.3 - /// - public void CheckAPDUResponse(APDUResponse response) - { - if (response == null) - { - throw new ArgumentNullException("Response cannot be null."); - } - - if (response.SW1 == 0x91) - { - switch (response.SW2) - { - case 0x00: // OPERATION_OK - return; - case 0x0C: // NO_CHANGES - return; - case 0x1C: // ILLEGAL_COMMAND_CODE - throw new IllegalCommandCodeException(); - case 0x1E: // INTEGRITY_ERROR - throw new IntegrityErrorException(); - case 0x40: // NO_SUCH_KEY - throw new NoSuchKeyException(); - case 0x7E: // LENGTH_ERROR - throw new LengthErrorException(); - case 0x9D: // PERMISSION_DENIED - throw new PermissionDeniedException(); - case 0x9E: // PARAMETER_ERROR - throw new ParameterErrorException(); - case 0xAD: // AUTHENTICATION_DELAY - throw new AuthenticationDelayException(); - case 0xAE: // AUTHENTICATION_ERROR - throw new AuthenticationErrorException(); - case 0xAF: // ADDITIONAL_FRAME - return; - case 0xBE: // BOUNDARY_ERROR - throw new BoundaryErrorException(); - case 0xCA: // COMMAND_ABORTED - throw new CommandAbortedException(); - case 0xDE: // DUPLICATE_ERROR - throw new DuplicateErrorException(); - case 0xF0: // FILE_NOT_FOUND - throw new FileNotFoundException(); - default: - break; - } - } - - throw new Exception(string.Format("Unknown Response Code: 0x{0}.", BitConverter.ToString(new byte[] { response.SW1, response.SW2 }).Replace("-", string.Empty))); - } - #endregion - - #region Crypto Operation - /// - /// Return a copy of the last Block of data - /// - /// Data compatible to blocksize - /// in byte - public byte[] ExtractLastBlock(byte[] data, uint blocksize) - { - if (data == null) - { - throw new ArgumentNullException("Data cannot be null."); - } - - if (data.Length % blocksize != 0) - { - throw new ArgumentException(string.Format("Data is not compatible with blocksize(data(length):{0}, blocksize:{1}.", data.Length, blocksize)); - } - - byte[] lastblock = new byte[blocksize]; - - for (int i = 0; i < blocksize; i++) - { - lastblock[i] = data[data.Length - blocksize + i]; - } - - return lastblock; - } - - /// - /// Rotates Array to the left - /// - /// Data - /// Copy of data - public byte[] RotateLeft(byte[] data) - { - if (data == null) - { - throw new ArgumentNullException("Data cannot be null."); - } - - byte[] rotate = new byte[data.Length]; - data.CopyTo(rotate, 0); - - byte tmp = rotate[0]; - for (var i = 0; i < rotate.Length - 1; i++) - { - rotate[i] = rotate[i + 1]; - } - rotate[rotate.Length - 1] = tmp; - - return rotate; - } - - /// - /// Rotates Array to the right - /// - /// Data - /// Copy of data - public byte[] RotateRight(byte[] data) - { - if (data == null) - { - throw new ArgumentNullException("Data cannot be null."); - } - - byte[] rotate = new byte[data.Length]; - data.CopyTo(rotate, 0); - - byte tmp = rotate[rotate.Length - 1]; - for (var i = rotate.Length - 1; i > 0; i--) - { - rotate[i] = rotate[i - 1]; - } - rotate[0] = tmp; - - return rotate; - } - - /// - /// Concatenates two Arrays, Array A start at index 0 - /// - /// Array A - /// Array B - /// Copy of Data (a.Size + b.Size) - public byte[] Concatenate(byte[] a, byte[] b) - { - if (a == null) - { - throw new ArgumentNullException("Array A cannot be null."); - } - - if (b == null) - { - throw new ArgumentNullException("Array B cannot be null."); - } - - byte[] c = new byte[a.Length + b.Length]; - a.CopyTo(c, 0); - b.CopyTo(c, a.Length); - - return c; - } - - /// - /// Boolean Operation XOR on all Bytes - /// - /// Array A - /// Array B - /// Copy of Data - public byte[] XOR(byte[] a, byte[] b) - { - if (a == null) - { - throw new ArgumentNullException("Array A cannot be null."); - } - - if (b == null) - { - throw new ArgumentNullException("Array B cannot be null."); - } - - if (a.Length != b.Length) - { - throw new ArgumentException(string.Format("Arrays are not same Length(Length A:{0}, Lenght B:{1})", a.Length, b.Length)); - } - - byte[] c = new byte[a.Length]; - - for(int i = 0; i < a.Length; i++) - { - c[i] = (byte)(a[i] ^ b[i]); - } - - return c; - } - - /// - /// Generates SessionKey for DES Authentification - /// - /// 16Byte SessionKey - public byte[] GenerateSesionKey_DES(byte[] rndA, byte[] rndB) - { - byte[] sesssionkey = new byte[8]; - - for (int i = 0; i < sesssionkey.Length; i++) - { - if (i < 4) - { - sesssionkey[i] = rndA[i]; - } - else - { - sesssionkey[i] = rndB[i - 4]; - } - } - - // DES SessionKey is a double DES Key - return Concatenate(sesssionkey, sesssionkey); - } - - /// - /// Generates SessionKey for AES Authentification - /// - /// 16Byte SessionKey - public byte[] GenerateSesionKey_AES(byte[] rndA, byte[] rndB) - { - byte[] sesssionkey = new byte[16]; - - for (int i = 0; i < sesssionkey.Length; i++) - { - if (i < 4) - { - sesssionkey[i] = rndA[i]; - } - else if(i >= 4 && i < 8) - { - sesssionkey[i] = rndB[i - 4]; - } - else if (i >= 8 && i < 12) - { - sesssionkey[i] = rndA[i + 4]; - } - else - { - sesssionkey[i] = rndB[i]; - } - } - - return sesssionkey; - } - - /// - /// Set KeyVersion in DES Key - /// KeyVersion is stored in LSB of the first 8 Bytes of the DES Key - /// - public byte[] SetKeyVersion(byte[] key, byte keyversion) - { - byte[] pow2 = new byte[] - { - 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80 - }; - - byte[] new_key = new byte[key.Length]; - key.CopyTo(new_key, 0); - - for (int i = 0; i < 8; i++) - { - if ((keyversion & pow2[i]) > 0) - { - new_key[i] = (byte)(new_key[5] | 0x01); - } - else - { - new_key[i] = (byte)(new_key[5] & 0x7F); - } - } - - return new_key; - } - - /// - /// Expand Array to Block Size, fill with 0x00 - /// - /// - public byte[] ExpandToBlockSize(byte[] data, uint bocksize) - { - int diff = data.Length % (int)bocksize; - if (diff == 0) - { - return data; - } - - byte[] expand = new byte[data.Length + bocksize - diff]; - - data.CopyTo(expand, 0); - - for (int i = expand.Length - 1; i > data.Length - 1; i--) - { - expand[i] = 0x00; - } - - return expand; - } - #endregion - - #region DESFire Commands - /// - /// Authenticate to PICC, with ISO Authenticate - /// - /// 0x01 - 0x0D - /// - /// !!! 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"); - - // Sepearte InitialisationVector for Authentication - byte[] iv = new byte[8]; - - APDUCommand cmd_challange_request = new APDUCommand(IsoCase.Case4Short) - { - CLA = 0x90, - INS = 0x1A, - Data = new byte[] - { - key_id - } - }; - _Log.DebugFormat("APDU_CMD(cmd_challange_request): {0}", ConvertToHexString(cmd_challange_request.ToArray())); - - APDUResponse response = _Card.Transmit(cmd_challange_request); - _Log.DebugFormat("APDU_RES(cmd_challange_request): {0}", ConvertToHexString(response.ToArray())); - - CheckAPDUResponse(response); - - byte[] rndB_enc = response.Body; - _Log.DebugFormat("rndB_enc: {0}", ConvertToHexString(rndB_enc)); - - DES des = new DES(); - byte[] rndB = des.Decrypt(rndB_enc, key, GenerateEmptyKey(8)); - _Log.DebugFormat("rndB: {0}", ConvertToHexString(rndB)); - - rndB.CopyTo(iv, 0); - - byte[] rndB_rl = RotateLeft(rndB); - _Log.DebugFormat("rndB_enc: {0}", ConvertToHexString(rndB_rl)); - - if(rndA == null) - { - Random rnd = new Random(); - rndA = new byte[8]; - rnd.NextBytes(rndA); - } - _Log.DebugFormat("rndA: {0}", ConvertToHexString(rndA)); - - byte[] rndAB = Concatenate(rndA, rndB_rl); - _Log.DebugFormat("rndAB: {0}", ConvertToHexString(rndAB)); - - byte[] rndAB_enc = des.Encrypt(rndAB, key, rndB_enc); - _Log.DebugFormat("rndA_rndB_enc: {0}", ConvertToHexString(rndAB_enc)); - iv = ExtractLastBlock(rndAB_enc, 8); - - APDUCommand cmd_challange_response = new APDUCommand(IsoCase.Case4Short) - { - CLA = 0x90, - INS = 0xAF, - Data = rndAB_enc - }; - _Log.DebugFormat("APDU_CMD(cmd_challange_response): {0}", ConvertToHexString(cmd_challange_response.ToArray())); - - response = _Card.Transmit(cmd_challange_response); - _Log.DebugFormat("APDU_RES(cmd_challange_response): {0}", ConvertToHexString(cmd_challange_response.ToArray())); - - CheckAPDUResponse(response); - - byte[] encryptedRndAFromCard = response.Body; - _Log.DebugFormat("encryptedRndAFromCard: {0}", ConvertToHexString(encryptedRndAFromCard)); - - byte[] rotatedRndAFromCard = des.Decrypt(encryptedRndAFromCard, key, iv); - _Log.DebugFormat("rotatedRndAFromCard: {0}", ConvertToHexString(rotatedRndAFromCard)); - - byte[] rndAFromCard = RotateRight(rotatedRndAFromCard); - _Log.DebugFormat("rndAFromCard: {0}", ConvertToHexString(rndAFromCard)); - - if (!rndA.SequenceEqual(rndAFromCard)) - { - throw new Exception("Authentication failed, PICC Challenge is not corret"); - } - - _SessionKey = GenerateSesionKey_DES(rndA, rndB); - _Log.DebugFormat("_SessionKey: {0}", ConvertToHexString(_SessionKey)); - - _IV = GenerateEmptyKey(8); - _Log.DebugFormat("_IV: {0}", ConvertToHexString(_IV)); - - _Log.Debug("End AuthenticateISO_DES"); - } - - /// - /// Format PICC - /// - public void Format() - { - _Log.Debug("Start Format"); - - APDUCommand cmd_format = new APDUCommand(IsoCase.Case2Short) - { - CLA = 0x90, - INS = 0xFC, - }; - _Log.DebugFormat("APDU_CMD(cmd_format): {0}", ConvertToHexString(cmd_format.ToArray())); - - APDUResponse response = _Card.Transmit(cmd_format); - _Log.DebugFormat("APDU_RES(cmd_format): {0}", ConvertToHexString(response.ToArray())); - - CheckAPDUResponse(response); - - _Log.Debug("End Format"); - } - - /// - /// Create Application for ID - /// - /// 3 Byte ID - public void CreateApplication(UInt32 aid, byte keysetting1, byte keysetting2) - { - _Log.Debug("Start CreateApplication"); - - byte[] id_byte = BitConverter.GetBytes(aid); - _Log.DebugFormat("AID: {0}", ConvertToHexString(id_byte.ToArray())); - - APDUCommand cmd_CreateApplication = new APDUCommand(IsoCase.Case4Short) - { - CLA = 0x90, - INS = 0xCA, - Data = new byte[] - { - id_byte[0], - id_byte[1], - id_byte[2], - keysetting1, - keysetting2 - } - }; - _Log.DebugFormat("APDU_CMD(cmd_CreateApplication): {0}", ConvertToHexString(cmd_CreateApplication.ToArray())); - - APDUResponse response = _Card.Transmit(cmd_CreateApplication); - _Log.DebugFormat("APDU_RES(cmd_CreateApplication): {0}", ConvertToHexString(response.ToArray())); - - 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}", 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}", ConvertToHexString(cmd_SelectApplication.ToArray())); - - APDUResponse response = _Card.Transmit(cmd_SelectApplication); - _Log.DebugFormat("APDU_RES(cmd_SelectApplication): {0}", ConvertToHexString(response.ToArray())); - - CheckAPDUResponse(response); - - _Log.Debug("End SelectApplication"); - } - - /// - /// Authenticate to PICC, with ISO Authenticate - /// - /// 0x01 - 0x0D - /// - /// !!! 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"); - - // Sepearte InitialisationVector for Authentication - byte[] iv = new byte[16]; - - APDUCommand cmd_challange_request = new APDUCommand(IsoCase.Case4Short) - { - CLA = 0x90, - INS = 0xAA, - Data = new byte[] - { - key_id - } - }; - _Log.DebugFormat("APDU_CMD(cmd_challange_request): {0}", ConvertToHexString(cmd_challange_request.ToArray())); - - APDUResponse response = _Card.Transmit(cmd_challange_request); - _Log.DebugFormat("APDU_RES(cmd_challange_request): {0}", ConvertToHexString(response.ToArray())); - - CheckAPDUResponse(response); - - byte[] rndB_enc = response.Body; - _Log.DebugFormat("rndB_enc: {0}", ConvertToHexString(rndB_enc)); - - AES aes = new AES(); - byte[] rndB = aes.Decrypt(rndB_enc, key, GenerateEmptyKey(16)); - _Log.DebugFormat("rndB: {0}", ConvertToHexString(rndB)); - - rndB.CopyTo(iv, 0); - - byte[] rndB_rl = RotateLeft(rndB); - _Log.DebugFormat("rndB_enc: {0}", ConvertToHexString(rndB_rl)); - - if (rndA == null) - { - Random rnd = new Random(); - rndA = new byte[16]; - rnd.NextBytes(rndA); - } - _Log.DebugFormat("rndA: {0}", ConvertToHexString(rndA)); - - byte[] rndAB = Concatenate(rndA, rndB_rl); - _Log.DebugFormat("rndAB: {0}", ConvertToHexString(rndAB)); - - byte[] rndAB_enc = aes.Encrypt(rndAB, key, rndB_enc); - _Log.DebugFormat("rndA_rndB_enc: {0}", ConvertToHexString(rndAB_enc)); - iv = ExtractLastBlock(rndAB_enc, 16); - - APDUCommand cmd_challange_response = new APDUCommand(IsoCase.Case4Short) - { - CLA = 0x90, - INS = 0xAF, - Data = rndAB_enc - }; - _Log.DebugFormat("APDU_CMD(cmd_challange_response): {0}", ConvertToHexString(cmd_challange_response.ToArray())); - - response = _Card.Transmit(cmd_challange_response); - _Log.DebugFormat("APDU_RES(cmd_challange_response): {0}", ConvertToHexString(cmd_challange_response.ToArray())); - - CheckAPDUResponse(response); - - byte[] encryptedRndAFromCard = response.Body; - _Log.DebugFormat("encryptedRndAFromCard: {0}", ConvertToHexString(encryptedRndAFromCard)); - - byte[] rotatedRndAFromCard = aes.Decrypt(encryptedRndAFromCard, key, iv); - _Log.DebugFormat("rotatedRndAFromCard: {0}", ConvertToHexString(rotatedRndAFromCard)); - - byte[] rndAFromCard = RotateRight(rotatedRndAFromCard); - _Log.DebugFormat("rndAFromCard: {0}", ConvertToHexString(rndAFromCard)); - - if (!rndA.SequenceEqual(rndAFromCard)) - { - throw new Exception("Authentication failed, PICC Challenge is not corret"); - } - - _SessionKey = GenerateSesionKey_AES(rndA, rndB); - _Log.DebugFormat("_SessionKey: {0}", ConvertToHexString(_SessionKey)); - - _IV = GenerateEmptyKey(16); - _Log.DebugFormat("_IV: {0}", ConvertToHexString(_IV)); - - _Log.Debug("End AuthenticateISO_DES"); - } - - /// - /// Change Same AES key as Authenticated - /// - /// - /// - /// - public void ChangeKey_AES(byte key_id, byte[] new_key, byte key_version) - { - _Log.Debug("Start ChangeKey_AES"); - - byte[] header = new byte[] - { - 0xC4, key_id - }; - _Log.DebugFormat("header: {0}", ConvertToHexString(header)); - - // AES Key Version is Append to Key - byte[] key_and_version = Concatenate(new_key, new byte[] { key_version }); - byte[] command = Concatenate(header, key_and_version); - _Log.DebugFormat("command: {0}", ConvertToHexString(command)); - - CRC32 crc32 = new CRC32(); - byte[] crc = crc32.Calculate(command); - _Log.DebugFormat("crc: {0}", ConvertToHexString(crc)); - - byte[] cryptogram = Concatenate(key_and_version, crc); - _Log.DebugFormat("cryptogram: {0}", ConvertToHexString(cryptogram)); - - byte[] cryptogram_block = ExpandToBlockSize(cryptogram, 16); - _Log.DebugFormat("cryptogram_block: {0}", ConvertToHexString(cryptogram_block)); - - AES aes = new AES(); - byte[] cryptogram_enc = aes.Encrypt(cryptogram_block, _SessionKey, _IV); - _Log.DebugFormat("cryptogram_enc: {0}", ConvertToHexString(cryptogram_enc)); - - _IV = ExtractLastBlock(cryptogram_enc, 16); - _Log.DebugFormat("_IV: {0}", ConvertToHexString(_IV)); - - byte[] data = Concatenate(new byte[] { key_id }, cryptogram_enc); - _Log.DebugFormat("data: {0}", ConvertToHexString(data)); - - APDUCommand cmd_ChangeKey = new APDUCommand(IsoCase.Case4Short) - { - CLA = 0x90, - INS = 0xC4, - Data = data - }; - _Log.DebugFormat("APDU_CMD(cmd_ChangeKey): {0}", ConvertToHexString(cmd_ChangeKey.ToArray())); - - APDUResponse response = _Card.Transmit(cmd_ChangeKey); - _Log.DebugFormat("APDU_RES(cmd_ChangeKey): {0}", ConvertToHexString(response.ToArray())); - - CheckAPDUResponse(response); - - _Log.Debug("End ChangeKey_AES"); - } - - /// - /// Change other AES key as Authenticated - /// - /// - /// - /// - public void ChangeOtherKey_AES(byte key_id, byte[] new_key, byte[] old_key, byte key_version) - { - _Log.Debug("Start ChangeOtherKey_AES"); - - byte[] header = new byte[] - { - 0xC4, key_id - }; - _Log.DebugFormat("header: {0}", ConvertToHexString(header)); - - byte[] key_xor = XOR(new_key, old_key); - - // AES Key Version is Append to Key - byte[] key_and_version = Concatenate(key_xor, new byte[] { key_version }); - byte[] command = Concatenate(header, key_and_version); - _Log.DebugFormat("command: {0}", ConvertToHexString(command)); - - CRC32 crc32 = new CRC32(); - byte[] crc_cmd = crc32.Calculate(command); - _Log.DebugFormat("crc_cmd: {0}", ConvertToHexString(crc_cmd)); - byte[] crc_key = crc32.Calculate(new_key); - _Log.DebugFormat("crc_key: {0}", ConvertToHexString(crc_key)); - - byte[] cryptogram = Concatenate(key_and_version, crc_cmd); - cryptogram = Concatenate(cryptogram, crc_key); - _Log.DebugFormat("cryptogram: {0}", ConvertToHexString(cryptogram)); - - byte[] cryptogram_block = ExpandToBlockSize(cryptogram, 16); - _Log.DebugFormat("cryptogram_block: {0}", ConvertToHexString(cryptogram_block)); - - AES aes = new AES(); - byte[] cryptogram_enc = aes.Encrypt(cryptogram_block, _SessionKey, _IV); - _Log.DebugFormat("cryptogram_enc: {0}", ConvertToHexString(cryptogram_enc)); - - _IV = ExtractLastBlock(cryptogram_enc, 16); - _Log.DebugFormat("_IV: {0}", ConvertToHexString(_IV)); - - byte[] data = Concatenate(new byte[] { key_id }, cryptogram_enc); - _Log.DebugFormat("data: {0}", ConvertToHexString(data)); - - APDUCommand cmd_ChangeKey = new APDUCommand(IsoCase.Case4Short) - { - CLA = 0x90, - INS = 0xC4, - Data = data - }; - _Log.DebugFormat("APDU_CMD(cmd_ChangeKey): {0}", ConvertToHexString(cmd_ChangeKey.ToArray())); - - APDUResponse response = _Card.Transmit(cmd_ChangeKey); - _Log.DebugFormat("APDU_RES(cmd_ChangeKey): {0}", ConvertToHexString(response.ToArray())); - - CheckAPDUResponse(response); - - _Log.Debug("End ChangeOtherKey_AES"); - } - - public void CreateFile_STD() - #endregion - - #region Configuration Generator - /// - /// Genearte KeySetting1 for Application Settings or PICC Setting - /// - public byte GenerateKeySetting1(ChangeApplicationKey changeKey, ChangeMasterKeySettings changeMasterKeySettings, CreateDeleteFile createDeleteFile, FileDirectoryAccess fileDirectoryAccess, ChangeMasterKey changeMasterKey) - { - return (byte)(((byte)changeKey << 4) | (byte)changeMasterKeySettings | (byte)createDeleteFile | (byte)fileDirectoryAccess | (byte)changeMasterKey); - } - - /// - /// Genearte KeySetting1 for Application Settings or PICC Setting - /// - /// ID of Key for changing Application Keys - /// - public byte GenerateKeySetting1(byte changeKey, ChangeMasterKeySettings changeMasterKeySettings, CreateDeleteFile createDeleteFile, FileDirectoryAccess fileDirectoryAccess, ChangeMasterKey changeMasterKey) - { - if (changeKey < 0x01 || changeKey >= 0x0E) - { - throw new ArgumentOutOfRangeException(); - } - return GenerateKeySetting1(changeKey, changeMasterKeySettings, createDeleteFile, fileDirectoryAccess, changeMasterKey); - } - - /// - /// Genearte KeySetting2 for Application Creation - /// - /// Number of keys that can be stored within the application (0x01-0x0D) - /// - public byte GenerateKeySetting2(CryptoOperationsType cryptoOperations, FileIdentifies fileIdentifies, byte numberOfKeys) - { - if (numberOfKeys < 0x01 || numberOfKeys >= 0x0D) - { - throw new ArgumentOutOfRangeException(); - } - - return (byte)((byte)cryptoOperations | (byte)fileIdentifies | numberOfKeys); - } - #endregion - #endregion - } -} diff --git a/NFC_Test/AuthCrypto_Test.cs b/NFC_Test/AuthCrypto_Test.cs deleted file mode 100644 index 58e6b6f..0000000 --- a/NFC_Test/AuthCrypto_Test.cs +++ /dev/null @@ -1,211 +0,0 @@ -using NFC; -using NFC.Crypto; -using NFC.ISO7816_4; -using NFC.Mifare_DESFire; -using NSubstitute; -using NUnit.Framework; -using PCSC.Iso7816; -using System; -using System.Collections.Generic; -using System.Text; - -namespace NFC_Test -{ - public class AuthCrypto_Test - { - public byte[] GenerateDefaultKey(int size) - { - List key = new List(); - for (int i = 0; i < size; i++) - { - key.Add(0); - } - - return key.ToArray(); - } - - [Test] - // https://www.linkedin.com/pulse/mifare-desfire-introduction-david-coelho - public void AuthExample() - { - DES des = new DES(); - - byte[] challenge = new byte[] - { - 0x93 ,0x9d ,0x2c ,0x2e ,0xa1 ,0x65 ,0x75 ,0xd5 - }; - - byte[] key = GenerateDefaultKey(8); - byte[] iv = GenerateDefaultKey(8); - - byte[] rndA = new byte[] - { - 0x00 ,0x01 ,0x02 ,0x03 ,0x04 ,0x05 ,0x06 ,0x07 - }; - - byte[] rndB = des.Decrypt(challenge, key, iv); - - byte[] rndB_expected = new byte[] - { - 0xea ,0x48 ,0x50 ,0x13 ,0xd8 ,0x0a ,0x05 ,0x67 - }; - - Assert.AreEqual(rndB_expected, rndB); - } - - [Test] - public void concatenate() - { - MIFARE_DESFire mifareDESFire = new MIFARE_DESFire(null); - - byte[] rndA = new byte[] - { - 0x00 ,0x01 ,0x02 ,0x03 ,0x04 ,0x05 ,0x06 ,0x07 - }; - - byte[] rndB = new byte[] - { - 0x48 ,0x50 ,0x13 ,0xd8 ,0x0a ,0x05 ,0x67 ,0xea - }; - - byte[] rndA_rndB_expected = new byte[] - { - 0x00 ,0x01 ,0x02 ,0x03 ,0x04 ,0x05 ,0x06 ,0x07, 0x48 ,0x50 ,0x13 ,0xd8 ,0x0a ,0x05 ,0x67 ,0xea - }; - - byte[] rndA_rndB = mifareDESFire.concatenate(rndA, rndB); - - Assert.AreEqual(rndA_rndB_expected, rndA_rndB); - } - - [Test] - public void Auth() - { - APDUCommand cmd_getchallange = new APDUCommand(IsoCase.Case4Short) - { - CLA = 0x90, - INS = (byte)0x1A, - Data = new byte[] - { - 0x00 - } - }; - - APDUCommand cmd_answerchallange = new APDUCommand(IsoCase.Case4Short) - { - CLA = 0x90, - INS = (byte)0xAF, - Data = new byte[] - { - 0x69, 0x17, 0x8b, 0x93, 0x8c, 0x03, 0xed, 0xf1, 0x86, 0xd3, 0x05, 0x6b, 0xed, 0xc8, 0xd6, 0xcf - } - }; - - APDUResponse response = new APDUResponse() - { - Body = new byte[] - { - 0xB8, 0x90, 0x04, 0x7F, 0x2D, 0xC8, 0xD6, 0x8B - } - }; - - APDUResponse response2 = new APDUResponse() - { - Body = new byte[] - { - 0x04, 0x79, 0xed, 0x6c, 0x4f, 0x74, 0xda, 0x4a - } - }; - - ICard card = Substitute.For(); - - card.Transmit(cmd_getchallange).ReturnsForAnyArgs(response); - card.Transmit(cmd_answerchallange).Returns(response2); - - MIFARE_DESFire mifareDESFire = new MIFARE_DESFire(card); - - mifareDESFire.AuthenticateDES(0x00, mifareDESFire.GenerateDefaultKey(16)); - } - - [Test] - public void ChangeKey() - { - ICard card = Substitute.For(); - MIFARE_DESFire mifareDESFire = new MIFARE_DESFire(card); - - mifareDESFire._SessionKey = new byte[] - { - 0xDC, 0xB0, 0x96, 0xC2, 0xA4, 0x0E, 0x78, 0xE0, 0xA0, 0xE4, 0x7A, 0x96, 0xF4, 0x2E, 0x62, 0xAE - }; - mifareDESFire._IV = new byte[] - { - 0x33, 0x45 , 0xAA , 0x95 , 0xF2 , 0xD9 , 0x56 , 0xCF - }; - - mifareDESFire.ChangeKeyDES(0x00, GenerateDefaultKey(16), GenerateDefaultKey(16)); - } - - [Test] - public void CRC() - { - byte[] data = StringToByteArrayFastest("c40045eeb8338ae8f49a032e85bb1114353010"); - - CRC32 crc32 = new CRC32(); - - byte[] crc = crc32.Calculate(data); - - MIFARE_DESFire dESFire = new MIFARE_DESFire(null); - - Console.WriteLine("data: {0}", dESFire.ConvertToHexString(data)); - Console.WriteLine("crc: {0}", dESFire.ConvertToHexString(crc)); - - byte[] data_crc = dESFire.concatenate(data, crc); - Console.WriteLine("data_crc: {0}", dESFire.ConvertToHexString(data_crc)); - } - - public static byte[] StringToByteArrayFastest(string hex) - { - if (hex.Length % 2 == 1) - throw new Exception("The binary key cannot have an odd number of digits"); - - byte[] arr = new byte[hex.Length >> 1]; - - for (int i = 0; i < hex.Length >> 1; ++i) - { - arr[i] = (byte)((GetHexVal(hex[i << 1]) << 4) + (GetHexVal(hex[(i << 1) + 1]))); - } - - return arr; - } - - public static int GetHexVal(char hex) - { - int val = (int)hex; - //For uppercase A-F letters: - //return val - (val < 58 ? 48 : 55); - //For lowercase a-f letters: - //return val - (val < 58 ? 48 : 87); - //Or the two combined, but a bit slower: - return val - (val < 58 ? 48 : (val < 97 ? 55 : 87)); - } - - [Test] - public void AES() - { - byte[] data = StringToByteArrayFastest("45eeb8338ae8f49a032e85bb111435301095c3894b0000000000000000000000"); - byte[] key = StringToByteArrayFastest("d99aca2b5b4de3a949fa2cf12b0eb673"); - byte[] iv = StringToByteArrayFastest("00000000000000000000000000000000"); - - MIFARE_DESFire dESFire = new MIFARE_DESFire(null); - - Console.WriteLine("data: {0}", dESFire.ConvertToHexString(data)); - Console.WriteLine("key: {0}", dESFire.ConvertToHexString(key)); - Console.WriteLine("iv: {0}", dESFire.ConvertToHexString(iv)); - - AES aes = new AES(); - - byte[] data_enc = aes.Encrypt(data, key, iv); - Console.WriteLine("data_enc: {0}", dESFire.ConvertToHexString(data_enc)); - } - } -} diff --git a/NFC_Test/AES_Test.cs b/NFC_Test/Crypto/AES_Test.cs similarity index 89% rename from NFC_Test/AES_Test.cs rename to NFC_Test/Crypto/AES_Test.cs index b35fee2..a4a2cf0 100644 --- a/NFC_Test/AES_Test.cs +++ b/NFC_Test/Crypto/AES_Test.cs @@ -2,7 +2,7 @@ using NFC.Mifare_DESFire; using NUnit.Framework; -namespace NFC_Test +namespace NFC_Test.Crypto { [TestFixture] public class AES_Test @@ -10,7 +10,7 @@ namespace NFC_Test [Test] public void Encrypt() { - MIFARE_DESFire_V2 desfire = new MIFARE_DESFire_V2(null); + MIFARE_DESFire desfire = new MIFARE_DESFire(null); byte[] data = desfire.ConvertFromHexString("8db1f942f2d7cc82f6fa1486a30f8c12104a3b07e8eb77a7ac00000000000000"); byte[] key = desfire.ConvertFromHexString("e7aff3361c3e85347993c3219a87d24b"); diff --git a/NFC_Test/Crypto/CRC16_Test.cs b/NFC_Test/Crypto/CRC16_Test.cs new file mode 100644 index 0000000..d174e05 --- /dev/null +++ b/NFC_Test/Crypto/CRC16_Test.cs @@ -0,0 +1,23 @@ +using NFC; +using NFC.Crypto; +using NUnit.Framework; + +namespace NFC_Test.Crypto +{ + [TestFixture] + public class CRC16_Test + { + [Test] + [Ignore("Unknown Expected Data")] + public void Caluclate() + { + byte[] data = HexConverter.ConvertFromHexString(""); + byte[] crc_expected = HexConverter.ConvertFromHexString(""); + + CRC16 crc16 = new CRC16(); + byte[] crc = crc16.Calculate(data); + + Assert.AreEqual(crc_expected, crc); + } + } +} diff --git a/NFC_Test/Crypto/CRC32_Test.cs b/NFC_Test/Crypto/CRC32_Test.cs new file mode 100644 index 0000000..aa14248 --- /dev/null +++ b/NFC_Test/Crypto/CRC32_Test.cs @@ -0,0 +1,22 @@ +using NFC; +using NFC.Crypto; +using NUnit.Framework; + +namespace NFC_Test.Crypto +{ + [TestFixture] + public class CRC32_Test + { + [Test] + public void Caluclate() + { + byte[] data = HexConverter.ConvertFromHexString("c40045eeb8338ae8f49a032e85bb1114353010"); + byte[] crc_expected = HexConverter.ConvertFromHexString("95c3894b"); + + CRC32 crc32 = new CRC32(); + byte[] crc = crc32.Calculate(data); + + Assert.AreEqual(crc_expected, crc); + } + } +} diff --git a/NFC_Test/Crypto/TDES_Test.cs b/NFC_Test/Crypto/TDES_Test.cs new file mode 100644 index 0000000..3789040 --- /dev/null +++ b/NFC_Test/Crypto/TDES_Test.cs @@ -0,0 +1,61 @@ +using NFC.Crypto; +using NFC.Mifare_DESFire; +using NUnit.Framework; + +namespace NFC_Test.Crypto +{ + [TestFixture] + public class TDES_Test + { + [Test] + [Ignore("Unknown Expected Data")] + public void Encrypt_TDES() + { + MIFARE_DESFire desfire = new MIFARE_DESFire(null); + + byte[] data = desfire.ConvertFromHexString(""); + byte[] key = desfire.ConvertFromHexString(""); + byte[] iv = desfire.ConvertFromHexString("0000000000000000"); + + TDES des = new TDES(); + byte[] data_enc = des.Encrypt(data, key, iv); + + byte[] data_enc_expected = desfire.ConvertFromHexString(""); + Assert.AreEqual(data_enc_expected, data_enc); + } + + [Test] + [Ignore("Unknown Expected Data")] + public void Encrypt_TDES_2K() + { + MIFARE_DESFire desfire = new MIFARE_DESFire(null); + + byte[] data = desfire.ConvertFromHexString(""); + byte[] key = desfire.ConvertFromHexString(""); + byte[] iv = desfire.ConvertFromHexString("0000000000000000"); + + TDES_2K des = new TDES_2K(); + byte[] data_enc = des.Encrypt(data, key, iv); + + byte[] data_enc_expected = desfire.ConvertFromHexString(""); + Assert.AreEqual(data_enc_expected, data_enc); + } + + [Test] + [Ignore("Unknown Expected Data")] + public void Encrypt_TDES_3K() + { + MIFARE_DESFire desfire = new MIFARE_DESFire(null); + + byte[] data = desfire.ConvertFromHexString(""); + byte[] key = desfire.ConvertFromHexString(""); + byte[] iv = desfire.ConvertFromHexString("0000000000000000"); + + TDES_3K des = new TDES_3K(); + byte[] data_enc = des.Encrypt(data, key, iv); + + byte[] data_enc_expected = desfire.ConvertFromHexString(""); + Assert.AreEqual(data_enc_expected, data_enc); + } + } +} \ No newline at end of file diff --git a/NFC_Test/ISO7816-4/APDUCommand_Test.cs b/NFC_Test/ISO7816-4/APDUCommand_Test.cs new file mode 100644 index 0000000..28c68e1 --- /dev/null +++ b/NFC_Test/ISO7816-4/APDUCommand_Test.cs @@ -0,0 +1,119 @@ +using System; +using NFC.ISO7816_4; +using NUnit.Framework; +using PCSC.Iso7816; + +namespace NFC_Test.ISO7816_4 +{ + [TestFixture] + public class APDUCommand_Test + { + [Test] + public void Compare() + { + APDUCommand command1 = new APDUCommand(IsoCase.Case4Short) + { + CLA = 0x90, + INS = 0xAA, + Data = new byte[] + { + 0x01, 0x02, 0x03 + } + }; + + APDUCommand command2 = new APDUCommand(IsoCase.Case4Short) + { + CLA = 0x90, + INS = 0xAA, + Data = new byte[] + { + 0x01, 0x02, 0x03 + } + }; + + Assert.IsTrue(command1 == command2); + } + + [Test] + public void Compare_Diff() + { + APDUCommand command1 = new APDUCommand(IsoCase.Case4Short) + { + CLA = 0x90, + INS = 0xAA, + Data = new byte[] + { + 0x01, 0x02, 0x03 + } + }; + + APDUCommand command2 = new APDUCommand(IsoCase.Case4Short) + { + CLA = 0x90, + INS = 0x1A, + Data = new byte[] + { + 0x01, 0x02, 0x03 + } + }; + + Assert.IsFalse(command1 == command2); + } + + [Test] + public void ToString_Case1() + { + APDUCommand command = new APDUCommand(IsoCase.Case1) + { + CLA = 0x90, + INS = 0x1A + }; + + Console.WriteLine(command.ToString()); + } + + [Test] + public void ToString_Case2() + { + APDUCommand command = new APDUCommand(IsoCase.Case2Short) + { + CLA = 0x90, + INS = 0x1A + }; + + Console.WriteLine(command.ToString()); + } + + [Test] + public void ToString_Case3() + { + APDUCommand command = new APDUCommand(IsoCase.Case3Short) + { + CLA = 0x90, + INS = 0x1A, + Data = new byte[] + { + 0x01, 0x02, 0x03 + } + }; + + Console.WriteLine(command.ToString()); + } + + [Test] + public void ToString_Case4() + { + APDUCommand command = new APDUCommand(IsoCase.Case4Short) + { + CLA = 0x90, + INS = 0x1A, + Data = new byte[] + { + 0x01, 0x02, 0x03 + } + }; + + Console.WriteLine(command.ToString()); + } + } +} diff --git a/NFC_Test/MifareDESFire_Commands.cs b/NFC_Test/MifareDESFire_Commands.cs deleted file mode 100644 index 504b25a..0000000 --- a/NFC_Test/MifareDESFire_Commands.cs +++ /dev/null @@ -1,34 +0,0 @@ -using NFC; -using NFC.Mifare_DESFire; -using NFC.Mifare_DESFire.Enums; -using NUnit.Framework; -using System; -using System.Collections.Generic; -using System.Text; - -namespace NFC_Test -{ - [TestFixture] - public class MifareDESFire_Commands - { - private MIFARE_DESFire _MifareDESFire; - - [SetUp] - public void SetUp() - { - //_MifareDESFire = new MifareDESFire(); - } - - [Test] - public void GetApplicationIDs() - { - - } - - [Test] - public void GenerateKeySetting1() - { - Assert.AreEqual(0xEF, _MifareDESFire.GenerateKeySetting1(ChangeApplicationKey.SAMEKEY, ChangeMasterKeySettings.WITHMASTERKEY, CreateDeleteFile.NOKEY, FileDirectoryAccess.NOKEY, ChangeMasterKey.CHANGEABLE)); - } - } -} diff --git a/NFC_Test/NFC_Test.csproj b/NFC_Test/NFC_Test.csproj index d420e5c..28d0baf 100644 --- a/NFC_Test/NFC_Test.csproj +++ b/NFC_Test/NFC_Test.csproj @@ -1,4 +1,4 @@ - + netcoreapp3.1 diff --git a/NFC_Test/MIFARE_DESFire_V2_Test.cs b/NFC_Test/NXP MIFARE DESFire/MIFARE_DESFire_Test.cs similarity index 73% rename from NFC_Test/MIFARE_DESFire_V2_Test.cs rename to NFC_Test/NXP MIFARE DESFire/MIFARE_DESFire_Test.cs index a3a8a2b..0a1b6d5 100644 --- a/NFC_Test/MIFARE_DESFire_V2_Test.cs +++ b/NFC_Test/NXP MIFARE DESFire/MIFARE_DESFire_Test.cs @@ -3,17 +3,13 @@ using NFC.ISO7816_4; using NFC.Mifare_DESFire; using NFC.NXP_MIFARE_DESFire.Exceptions; using NSubstitute; -using NSubstitute.Core; using NUnit.Framework; -using PCSC.Iso7816; using System; -using System.Collections.Generic; -using System.Net; -namespace NFC_Test +namespace NFC_Test.NXP_MIFARE_DESFire { [TestFixture] - public class MIFARE_DESFire_V2_Test + public class MIFARE_DESFire_Test { #region Helper Methods [Test] @@ -21,7 +17,7 @@ namespace NFC_Test { uint i = 16; - MIFARE_DESFire_V2 desfire = new MIFARE_DESFire_V2(null); + MIFARE_DESFire desfire = new MIFARE_DESFire(null); byte[] data = desfire.GenerateEmptyKey(i); @@ -37,7 +33,7 @@ namespace NFC_Test [Test] public void CheckAPDUResponse__NULL() { - MIFARE_DESFire_V2 desfire = new MIFARE_DESFire_V2(null); + MIFARE_DESFire desfire = new MIFARE_DESFire(null); Assert.Throws( delegate { @@ -54,7 +50,7 @@ namespace NFC_Test SW2 = 0x00 }; - MIFARE_DESFire_V2 desfire = new MIFARE_DESFire_V2(null); + MIFARE_DESFire desfire = new MIFARE_DESFire(null); Assert.Throws( delegate { @@ -71,7 +67,7 @@ namespace NFC_Test SW2 = 0x00 }; - MIFARE_DESFire_V2 desfire = new MIFARE_DESFire_V2(null); + MIFARE_DESFire desfire = new MIFARE_DESFire(null); desfire.CheckAPDUResponse(response); } @@ -85,7 +81,7 @@ namespace NFC_Test SW2 = 0x0C }; - MIFARE_DESFire_V2 desfire = new MIFARE_DESFire_V2(null); + MIFARE_DESFire desfire = new MIFARE_DESFire(null); desfire.CheckAPDUResponse(response); } @@ -98,7 +94,7 @@ namespace NFC_Test SW2 = 0x1C }; - MIFARE_DESFire_V2 desfire = new MIFARE_DESFire_V2(null); + MIFARE_DESFire desfire = new MIFARE_DESFire(null); Assert.Throws( delegate @@ -116,7 +112,7 @@ namespace NFC_Test SW2 = 0x1E }; - MIFARE_DESFire_V2 desfire = new MIFARE_DESFire_V2(null); + MIFARE_DESFire desfire = new MIFARE_DESFire(null); Assert.Throws( delegate @@ -134,7 +130,7 @@ namespace NFC_Test SW2 = 0x40 }; - MIFARE_DESFire_V2 desfire = new MIFARE_DESFire_V2(null); + MIFARE_DESFire desfire = new MIFARE_DESFire(null); Assert.Throws( delegate @@ -152,7 +148,7 @@ namespace NFC_Test SW2 = 0x7E }; - MIFARE_DESFire_V2 desfire = new MIFARE_DESFire_V2(null); + MIFARE_DESFire desfire = new MIFARE_DESFire(null); Assert.Throws( delegate @@ -170,7 +166,7 @@ namespace NFC_Test SW2 = 0x9D }; - MIFARE_DESFire_V2 desfire = new MIFARE_DESFire_V2(null); + MIFARE_DESFire desfire = new MIFARE_DESFire(null); Assert.Throws( delegate @@ -189,7 +185,7 @@ namespace NFC_Test SW2 = 0x9E }; - MIFARE_DESFire_V2 desfire = new MIFARE_DESFire_V2(null); + MIFARE_DESFire desfire = new MIFARE_DESFire(null); Assert.Throws( delegate @@ -208,7 +204,7 @@ namespace NFC_Test SW2 = 0xAD }; - MIFARE_DESFire_V2 desfire = new MIFARE_DESFire_V2(null); + MIFARE_DESFire desfire = new MIFARE_DESFire(null); Assert.Throws( delegate @@ -226,7 +222,7 @@ namespace NFC_Test SW2 = 0xAE }; - MIFARE_DESFire_V2 desfire = new MIFARE_DESFire_V2(null); + MIFARE_DESFire desfire = new MIFARE_DESFire(null); Assert.Throws( delegate @@ -244,7 +240,7 @@ namespace NFC_Test SW2 = 0xAF }; - MIFARE_DESFire_V2 desfire = new MIFARE_DESFire_V2(null); + MIFARE_DESFire desfire = new MIFARE_DESFire(null); desfire.CheckAPDUResponse(response); } @@ -258,7 +254,7 @@ namespace NFC_Test SW2 = 0xBE }; - MIFARE_DESFire_V2 desfire = new MIFARE_DESFire_V2(null); + MIFARE_DESFire desfire = new MIFARE_DESFire(null); Assert.Throws( delegate @@ -276,7 +272,7 @@ namespace NFC_Test SW2 = 0xCA }; - MIFARE_DESFire_V2 desfire = new MIFARE_DESFire_V2(null); + MIFARE_DESFire desfire = new MIFARE_DESFire(null); Assert.Throws( delegate @@ -294,7 +290,7 @@ namespace NFC_Test SW2 = 0xDE }; - MIFARE_DESFire_V2 desfire = new MIFARE_DESFire_V2(null); + MIFARE_DESFire desfire = new MIFARE_DESFire(null); Assert.Throws( delegate @@ -312,7 +308,7 @@ namespace NFC_Test SW2 = 0xF0 }; - MIFARE_DESFire_V2 desfire = new MIFARE_DESFire_V2(null); + MIFARE_DESFire desfire = new MIFARE_DESFire(null); Assert.Throws( delegate @@ -336,7 +332,7 @@ namespace NFC_Test 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 }; - MIFARE_DESFire_V2 desfire = new MIFARE_DESFire_V2(null); + MIFARE_DESFire desfire = new MIFARE_DESFire(null); byte[] lastblock = desfire.ExtractLastBlock(data, 8); @@ -351,7 +347,7 @@ namespace NFC_Test 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 }; - MIFARE_DESFire_V2 desfire = new MIFARE_DESFire_V2(null); + MIFARE_DESFire desfire = new MIFARE_DESFire(null); Assert.Throws( delegate @@ -365,7 +361,7 @@ namespace NFC_Test { byte[] data = null; - MIFARE_DESFire_V2 desfire = new MIFARE_DESFire_V2(null); + MIFARE_DESFire desfire = new MIFARE_DESFire(null); Assert.Throws( delegate @@ -387,7 +383,7 @@ namespace NFC_Test 0x02, 0x03, 0x04, 0x01 }; - MIFARE_DESFire_V2 desfire = new MIFARE_DESFire_V2(null); + MIFARE_DESFire desfire = new MIFARE_DESFire(null); byte[] data_left = desfire.RotateLeft(data); @@ -397,7 +393,7 @@ namespace NFC_Test [Test] public void RotateLeft_Null() { - MIFARE_DESFire_V2 desfire = new MIFARE_DESFire_V2(null); + MIFARE_DESFire desfire = new MIFARE_DESFire(null); Assert.Throws( delegate @@ -419,7 +415,7 @@ namespace NFC_Test 0x04, 0x01, 0x02, 0x03 }; - MIFARE_DESFire_V2 desfire = new MIFARE_DESFire_V2(null); + MIFARE_DESFire desfire = new MIFARE_DESFire(null); byte[] data_left = desfire.RotateRight(data); @@ -429,7 +425,7 @@ namespace NFC_Test [Test] public void RotateRight_Null() { - MIFARE_DESFire_V2 desfire = new MIFARE_DESFire_V2(null); + MIFARE_DESFire desfire = new MIFARE_DESFire(null); Assert.Throws( delegate @@ -456,17 +452,47 @@ namespace NFC_Test 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08 }; - MIFARE_DESFire_V2 desfire = new MIFARE_DESFire_V2(null); + MIFARE_DESFire desfire = new MIFARE_DESFire(null); byte[] data_c = desfire.Concatenate(data_a, data_b); Assert.AreEqual(expected_data_c, data_c); } + [Test] + public void Concatenate_ABC() + { + byte[] data_a = new byte[] + { + 0x01, 0x02, 0x03, 0x04 + }; + + byte[] data_b = new byte[] + { + 0x05, 0x06, 0x07, 0x08 + }; + + byte[] data_c = new byte[] + { + 0x09, 0xA0, 0xB0, 0xC0 + }; + + byte[] expected_data_d = new byte[] + { + 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0xA0, 0xB0, 0xC0 + }; + + MIFARE_DESFire desfire = new MIFARE_DESFire(null); + + byte[] data_d = desfire.Concatenate(data_a, data_b, data_c); + + Assert.AreEqual(expected_data_d, data_d); + } + [Test] public void Concatenate_Null() { - MIFARE_DESFire_V2 desfire = new MIFARE_DESFire_V2(null); + MIFARE_DESFire desfire = new MIFARE_DESFire(null); Assert.Throws( delegate @@ -493,7 +519,7 @@ namespace NFC_Test 0x0F, 0xF0, 0x0F, 0xF0 }; - MIFARE_DESFire_V2 desfire = new MIFARE_DESFire_V2(null); + MIFARE_DESFire desfire = new MIFARE_DESFire(null); byte[] data_c = desfire.XOR(data_a, data_b); @@ -503,7 +529,7 @@ namespace NFC_Test [Test] public void XOR_null() { - MIFARE_DESFire_V2 desfire = new MIFARE_DESFire_V2(null); + MIFARE_DESFire desfire = new MIFARE_DESFire(null); Assert.Throws( delegate @@ -515,7 +541,7 @@ namespace NFC_Test [Test] public void GenerateSessionKey_AES() { - MIFARE_DESFire_V2 desfire = new MIFARE_DESFire_V2(null); + MIFARE_DESFire desfire = new MIFARE_DESFire(null); byte[] rndA = desfire.ConvertFromHexString("bc14dfde20074617e45a8822f06fdd91"); Console.WriteLine(desfire.ConvertToHexString(rndA)); @@ -537,31 +563,31 @@ namespace NFC_Test { ICard card = Substitute.For(); - MIFARE_DESFire_V2 desfire = new MIFARE_DESFire_V2(card); + MIFARE_DESFire desfire = new MIFARE_DESFire(card); APDUResponse response_challenge_request = new APDUResponse() { SW1 = 0x91, SW2 = 0xAF, - Body = desfire.ConvertFromHexString("5D994CE085F24089") + Body = HexConverter.ConvertFromHexString("5D994CE085F24089") }; APDUResponse response_challenge_response = new APDUResponse() { SW1 = 0x91, SW2 = 0x00, - Body = desfire.ConvertFromHexString("913C6DED84221C41") + Body = HexConverter.ConvertFromHexString("913C6DED84221C41") }; - byte[] rndA = desfire.ConvertFromHexString("849B36C5F8BF4A09"); - byte[] key = desfire.ConvertFromHexString("00000000000000000000000000000000"); + byte[] rndA = HexConverter.ConvertFromHexString("849B36C5F8BF4A09"); + 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); desfire.AuthenticateISO_DES(0x00, key, rndA); - byte[] expected_sessionkey = desfire.ConvertFromHexString("849B36C54FD1B759849B36C54FD1B759"); + byte[] expected_sessionkey = HexConverter.ConvertFromHexString("849B36C54FD1B759849B36C54FD1B759"); byte[] expected_iv = desfire.GenerateEmptyKey(8); Assert.AreEqual(expected_sessionkey, desfire._SessionKey); @@ -573,31 +599,31 @@ namespace NFC_Test { ICard card = Substitute.For(); - MIFARE_DESFire_V2 desfire = new MIFARE_DESFire_V2(card); + MIFARE_DESFire desfire = new MIFARE_DESFire(card); APDUResponse response_challenge_request = new APDUResponse() { SW1 = 0x91, SW2 = 0xAF, - Body = desfire.ConvertFromHexString("43a28e28c653df83cd85039714bccb51") + Body = HexConverter.ConvertFromHexString("43a28e28c653df83cd85039714bccb51") }; APDUResponse response_challenge_response = new APDUResponse() { SW1 = 0x91, SW2 = 0x00, - Body = desfire.ConvertFromHexString("d8f70a0f9a43f522f775a56f5688592f") + Body = HexConverter.ConvertFromHexString("d8f70a0f9a43f522f775a56f5688592f") }; - byte[] rndA = desfire.ConvertFromHexString("8a8b3c15e576ae3a21c2b18e6aead1f1"); - byte[] key = desfire.ConvertFromHexString("00000000000000000000000000000000"); + byte[] rndA = HexConverter.ConvertFromHexString("8a8b3c15e576ae3a21c2b18e6aead1f1"); + 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); desfire.AuthenticateISO_AES(0x00, key, rndA); - byte[] expected_sessionkey = desfire.ConvertFromHexString("8a8b3c15c71d0cf46aead1f148f27703"); + byte[] expected_sessionkey = HexConverter.ConvertFromHexString("8a8b3c15c71d0cf46aead1f148f27703"); byte[] expected_iv = desfire.GenerateEmptyKey(16); Assert.AreEqual(expected_sessionkey, desfire._SessionKey); @@ -609,7 +635,7 @@ namespace NFC_Test { ICard card = Substitute.For(); - MIFARE_DESFire_V2 desfire = new MIFARE_DESFire_V2(card); + MIFARE_DESFire desfire = new MIFARE_DESFire(card); APDUResponse response = new APDUResponse() { @@ -617,10 +643,10 @@ namespace NFC_Test SW2 = 0x00 }; - byte[] new_key = desfire.ConvertFromHexString("45eeb8338ae8f49a032e85bb11143530"); + byte[] new_key = HexConverter.ConvertFromHexString("45eeb8338ae8f49a032e85bb11143530"); - byte[] sessionkey = desfire.ConvertFromHexString("2f96515262e1beb0129de2df3e97feb3"); - byte[] iv = desfire.ConvertFromHexString("00000000000000000000000000000000"); + byte[] sessionkey = HexConverter.ConvertFromHexString("2f96515262e1beb0129de2df3e97feb3"); + byte[] iv = HexConverter.ConvertFromHexString("00000000000000000000000000000000"); desfire._SessionKey = sessionkey; desfire._IV = iv; @@ -635,7 +661,7 @@ namespace NFC_Test { ICard card = Substitute.For(); - MIFARE_DESFire_V2 desfire = new MIFARE_DESFire_V2(card); + MIFARE_DESFire desfire = new MIFARE_DESFire(card); APDUResponse response = new APDUResponse() { @@ -643,11 +669,11 @@ namespace NFC_Test SW2 = 0x00 }; - byte[] new_key = desfire.ConvertFromHexString("8db1f942f2d7cc82f6fa1486a30f8c12"); - byte[] old_key = desfire.ConvertFromHexString("00000000000000000000000000000000"); + byte[] new_key = HexConverter.ConvertFromHexString("8db1f942f2d7cc82f6fa1486a30f8c12"); + byte[] old_key = HexConverter.ConvertFromHexString("00000000000000000000000000000000"); - byte[] sessionkey = desfire.ConvertFromHexString("e7aff3361c3e85347993c3219a87d24b"); - byte[] iv = desfire.ConvertFromHexString("00000000000000000000000000000000"); + byte[] sessionkey = HexConverter.ConvertFromHexString("e7aff3361c3e85347993c3219a87d24b"); + byte[] iv = HexConverter.ConvertFromHexString("00000000000000000000000000000000"); desfire._SessionKey = sessionkey; desfire._IV = iv; @@ -657,5 +683,27 @@ namespace NFC_Test desfire.ChangeOtherKey_AES(0x01, new_key, old_key, 0x10); } #endregion + + #region Configuration Generator + [Test] + public void GenerateFileAccessRights() + { + MIFARE_DESFire desfire = new MIFARE_DESFire(null); + + Assert.AreEqual(0x1234, desfire.GenerateFileAccessRights(0x01, 0x02, 0x03, 0x04)); + } + + [Test] + public void GenerateFileAccessRights_OutOfRange() + { + MIFARE_DESFire desfire = new MIFARE_DESFire(null); + + Assert.Throws( + delegate + { + desfire.GenerateFileAccessRights(0x10, 0x00, 0x00, 0x00); + }); + } + #endregion } } diff --git a/NFC_Test/NamespaceSetUp.cs b/NFC_Test/NamespaceSetUp.cs index 4cb85ab..eb86856 100644 --- a/NFC_Test/NamespaceSetUp.cs +++ b/NFC_Test/NamespaceSetUp.cs @@ -1,14 +1,11 @@ -using log4net; -using log4net.Config; +using log4net.Config; using NUnit.Framework; -using System; namespace NFC_Test { [SetUpFixture] public class NamespaceSetUp - { - private static readonly ILog log = LogManager.GetLogger(typeof(NamespaceSetUp)); + { [OneTimeSetUp] public void OneTimeSetUp() { diff --git a/NFC_Test/OTA.cs b/NFC_Test/OTA.cs index 217efa4..9e1cd36 100644 --- a/NFC_Test/OTA.cs +++ b/NFC_Test/OTA.cs @@ -3,6 +3,8 @@ using NFC; using NFC.Readers.PCSC; using NFC.Mifare_DESFire; using NFC.Mifare_DESFire.Enums; +using System; +using System.Text; namespace NFC_Test { @@ -23,7 +25,7 @@ namespace NFC_Test { card.Connect(); - MIFARE_DESFire_V2 desfire = new MIFARE_DESFire_V2(card); + MIFARE_DESFire desfire = new MIFARE_DESFire(card); desfire.SelectApplication(0x000000); desfire.AuthenticateISO_DES(0x00, desfire.GenerateEmptyKey(16)); @@ -49,6 +51,15 @@ namespace NFC_Test desfire.AuthenticateISO_AES(0x00, key_master); desfire.ChangeOtherKey_AES(0x02, key_2, desfire.GenerateEmptyKey(16), 0x10); + UInt16 accesRights = desfire.GenerateFileAccessRights((byte)FileAccessRights.FREE, 0x00, 0x00, 0x00); + desfire.CreateFile_Standard(0x01, FileCommunication.PLAIN, accesRights, 0x100); + + desfire.WriteData(0x01, 0, Encoding.ASCII.GetBytes("user@domain.org")); + + byte[] data = desfire.ReadData(0x01, 0, 32); + + Console.WriteLine(Encoding.ASCII.GetString(data)); + transmit_successfully = true; card.Disconnect(); diff --git a/NFC_Test/REAL_Windows.cs b/NFC_Test/REAL_Windows.cs index 0e35f12..0951e4b 100644 --- a/NFC_Test/REAL_Windows.cs +++ b/NFC_Test/REAL_Windows.cs @@ -58,275 +58,5 @@ namespace NFC_Test reader.Stop(); reader.CardDiscovered -= handler; } - - [TestCase("ACS ACR122U PICC Interface 0")] - public void GetApplicationIDs(string readerID) - { - IHardware hardware = new Hardware(); - IReader reader = hardware.OpenReader(readerID); - - bool transmit_successfully = false; - - ReaderEventHandler handler = (sender, card) => - { - card.Connect(); - - MIFARE_DESFire desfire = new MIFARE_DESFire(card); - - //APDUCommand cmd = desfire.GetApplicationIDs(); - - //APDUResponse response = card.Transmit(cmd); - - //if (response.StatusWord == NFC.Mifare_DESFire.APDUStatusWords.OK) - //{ - // UInt32[] ApplicationIDs = desfire.ConvertApplicationIDs(response); - - // foreach(UInt32 id in ApplicationIDs) - // { - // Console.WriteLine("0x{0:X3}", id); - // } - - // transmit_successfully = true; - //} - - card.Disconnect(); - }; - - reader.CardDiscovered += handler; - reader.Start(); - - Assert.AreEqual(true, transmit_successfully); - - reader.Stop(); - reader.CardDiscovered -= handler; - } - - [TestCase("ACS ACR122U PICC Interface 0", (UInt32)0xC0FFEE)] - public void SelectApplication(string readerID, UInt32 applicationID) - { - IHardware hardware = new Hardware(); - IReader reader = hardware.OpenReader(readerID); - - bool transmit_successfully = false; - - ReaderEventHandler handler = (sender, card) => - { - card.Connect(); - - //MIFARE_DESFire desfire = new MIFARE_DESFire(card); - - //APDUCommand cmd = desfire.SelectApplication(applicationID); - - //cmd.ToArray(); - - //APDUResponse response = card.Transmit(cmd); - - //if (response.StatusWord == NFC.Mifare_DESFire.APDUStatusWords.OK) - //{ - // transmit_successfully = true; - //} - - card.Disconnect(); - }; - - reader.CardDiscovered += handler; - reader.Start(); - - Assert.AreEqual(true, transmit_successfully); - - reader.Stop(); - reader.CardDiscovered -= handler; - } - - [TestCase("ACS ACR122U PICC Interface 0", (UInt32)0xAAFFEE)] - public void CreateApplication(string readerID, UInt32 applicationID) - { - //IHardware hardware = new Hardware(); - //IReader reader = hardware.OpenReader(readerID); - - //bool transmit_successfully = false; - - //ReaderEventHandler handler = (sender, card) => - //{ - // card.Connect(); - - // MIFARE_DESFire desfire = new MIFARE_DESFire(card); - - // byte keysetting1 = desfire.GenerateKeySetting1(ChangeApplicationKey.MASTERKEY, ChangeMasterKeySettings.WITHMASTERKEY, CreateDeleteFile.NOKEY, FileDirectoryAccess.NOKEY, ChangeMasterKey.CHANGEABLE); - // byte keysetting2 = desfire.GenerateKeySetting2(CryptoOperationsType.TDES, FileIdentifies.NOTUSED, 0x03); - - // APDUCommand cmd = desfire.CreateApplication(applicationID, keysetting1, keysetting2); - - // Console.WriteLine(cmd.ToArray()); - - // APDUResponse response = card.Transmit(cmd); - - // if (response.StatusWord == NFC.Mifare_DESFire.APDUStatusWords.OK) - // { - // transmit_successfully = true; - // } - - // card.Disconnect(); - //}; - - //reader.CardDiscovered += handler; - //reader.Start(); - - //Assert.AreEqual(true, transmit_successfully); - - //reader.Stop(); - //reader.CardDiscovered -= handler; - } - - [TestCase("ACS ACR122U PICC Interface 0", (UInt32)0xAAFFEE)] - public void DeleteApplication(string readerID, UInt32 applicationID) - { - IHardware hardware = new Hardware(); - IReader reader = hardware.OpenReader(readerID); - - bool transmit_successfully = false; - - ReaderEventHandler handler = (sender, card) => - { - card.Connect(); - - MIFARE_DESFire desfire = new MIFARE_DESFire(card); - - desfire.SelectApplication(0x000000); - desfire.AuthenticateDES(0x00, GenerateDefaultKey(8)); - desfire.DeleteApplication(applicationID); - - transmit_successfully = true; - - card.Disconnect(); - }; - - reader.CardDiscovered += handler; - reader.Start(); - - Assert.AreEqual(true, transmit_successfully); - - reader.Stop(); - reader.CardDiscovered -= handler; - } - - public byte[] GenerateDefaultKey(int size) - { - List key = new List(); - for(int i = 0; i < size; i++) - { - key.Add(0); - } - - return key.ToArray(); - } - - /// - /// Used Default PICC Key with PICC authenticate - /// - /// - [TestCase("ACS ACR122U PICC Interface 0")] - public void Authenticate(string readerID) - { - IHardware hardware = new Hardware(); - IReader reader = hardware.OpenReader(readerID); - - bool transmit_successfully = false; - - ReaderEventHandler handler = (sender, card) => - { - card.Connect(); - - MIFARE_DESFire desfire = new MIFARE_DESFire(card); - - desfire.SelectApplication(0x000000); - desfire.AuthenticateDES(0x00, GenerateDefaultKey(8)); - - transmit_successfully = true; - - card.Disconnect(); - }; - - reader.CardDiscovered += handler; - reader.Start(); - - Assert.AreEqual(true, transmit_successfully); - - reader.Stop(); - reader.CardDiscovered -= handler; - } - - [TestCase("ACS ACR122U PICC Interface 0")] - public void ChangeKey(string readerID) - { - IHardware hardware = new Hardware(); - IReader reader = hardware.OpenReader(readerID); - - bool transmit_successfully = false; - - ReaderEventHandler handler = (sender, card) => - { - card.Connect(); - - MIFARE_DESFire desfire = new MIFARE_DESFire(card); - - desfire.SelectApplication(0xAAFFEE); - desfire.AuthenticateDES(0x00, GenerateDefaultKey(8)); - desfire.ChangeKeyDES(0x00, GenerateDefaultKey(8), new byte[] { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF }); - - transmit_successfully = true; - - card.Disconnect(); - }; - - reader.CardDiscovered += handler; - reader.Start(); - - Assert.AreEqual(true, transmit_successfully); - - reader.Stop(); - reader.CardDiscovered -= handler; - } - - [TestCase("ACS ACR122U PICC Interface 0")] - public void ChangeKey_Test(string readerID) - { - IHardware hardware = new Hardware(); - IReader reader = hardware.OpenReader(readerID); - - bool transmit_successfully = false; - - ReaderEventHandler handler = (sender, card) => - { - card.Connect(); - - MIFARE_DESFire desfire = new MIFARE_DESFire(card); - - desfire.SelectApplication(0xAAFFEE); - desfire.AuthenticateDES(0x00, GenerateDefaultKey(8)); - - APDUCommand cmd = new APDUCommand(IsoCase.Case4Short) - { - CLA = 0x90, - INS = 0xC4, - Data = GenerateDefaultKey(1 + 16 + 4 + 4) - // KEY_NO, KEY, CRC32, PADDING - }; - - card.Transmit(cmd); - - transmit_successfully = true; - - card.Disconnect(); - }; - - reader.CardDiscovered += handler; - reader.Start(); - - Assert.AreEqual(true, transmit_successfully); - - reader.Stop(); - reader.CardDiscovered -= handler; - } } } diff --git a/NFC_Test/REAL_Windows_CardSetUp.cs b/NFC_Test/REAL_Windows_CardSetUp.cs index 652913b..931a17a 100644 --- a/NFC_Test/REAL_Windows_CardSetUp.cs +++ b/NFC_Test/REAL_Windows_CardSetUp.cs @@ -9,183 +9,183 @@ using System.Text; namespace NFC_Test { - [TestFixture] - public class REAL_Windows_CardSetUp - { - public static UInt32 FabAccessAID = 0x001100; - public static string CardReaderID = "ACS ACR122U PICC Interface 0"; - public static byte[] PICC_MasterKey = new byte[] - { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 - }; + //[TestFixture] + //public class REAL_Windows_CardSetUp + //{ + // public static UInt32 FabAccessAID = 0x001100; + // public static string CardReaderID = "ACS ACR122U PICC Interface 0"; + // public static byte[] PICC_MasterKey = new byte[] + // { + // 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + // }; - public static byte[] APP_MasterKey = new byte[] - { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 - }; + // public static byte[] APP_MasterKey = new byte[] + // { + // 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + // }; - public static byte[] APP_Key_1 = new byte[] - { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 - }; + // public static byte[] APP_Key_1 = new byte[] + // { + // 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + // }; - public static byte[] APP_Key_2 = new byte[] - { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 - }; + // public static byte[] APP_Key_2 = new byte[] + // { + // 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + // }; - public static byte[] Empty_Key = new byte[] - { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 - }; + // public static byte[] Empty_Key = new byte[] + // { + // 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + // }; - public static byte FabAccessIdentFileID = 0x01; - public static string UserDomain = "user1@fabaccess.org"; + // public static byte FabAccessIdentFileID = 0x01; + // public static string UserDomain = "user1@fabaccess.org"; - [Test] - public void ResetCard() - { - IHardware hardware = new Hardware(); - IReader reader = hardware.OpenReader(CardReaderID); + // [Test] + // public void ResetCard() + // { + // IHardware hardware = new Hardware(); + // IReader reader = hardware.OpenReader(CardReaderID); - bool connected_successfully = false; + // bool connected_successfully = false; - ReaderEventHandler handler = (sender, card) => - { - card.Connect(); + // ReaderEventHandler handler = (sender, card) => + // { + // card.Connect(); - MIFARE_DESFire mifareDESFire = new MIFARE_DESFire(card); + // MIFARE_DESFire mifareDESFire = new MIFARE_DESFire(card); - mifareDESFire.AuthenticateDES(0x01, PICC_MasterKey); + // mifareDESFire.AuthenticateISO_DES(0x01, PICC_MasterKey); - mifareDESFire.Format(); + // mifareDESFire.Format(); - connected_successfully = true; + // connected_successfully = true; - card.Disconnect(); - }; + // card.Disconnect(); + // }; - reader.CardDiscovered += handler; - reader.Start(); + // reader.CardDiscovered += handler; + // reader.Start(); - Assert.AreEqual(true, connected_successfully); + // Assert.AreEqual(true, connected_successfully); - reader.Stop(); - reader.CardDiscovered -= handler; - } + // reader.Stop(); + // reader.CardDiscovered -= handler; + // } - [Test] - public void ProvisionCard() - { - IHardware hardware = new Hardware(); - IReader reader = hardware.OpenReader(CardReaderID); + // [Test] + // public void ProvisionCard() + // { + // IHardware hardware = new Hardware(); + // IReader reader = hardware.OpenReader(CardReaderID); - bool connected_successfully = false; + // bool connected_successfully = false; - ReaderEventHandler handler = (sender, card) => - { - card.Connect(); + // ReaderEventHandler handler = (sender, card) => + // { + // card.Connect(); - MIFARE_DESFire mifareDESFire = new MIFARE_DESFire(card); + // MIFARE_DESFire mifareDESFire = new MIFARE_DESFire(card); - mifareDESFire.AuthenticateDES(0x01, APP_MasterKey); - mifareDESFire.CreateApplication(FabAccessAID); - mifareDESFire.SelectApplication(FabAccessAID); + // mifareDESFire.AuthenticateISO_DES(0x01, APP_MasterKey); + // mifareDESFire.CreateApplication(FabAccessAID); + // mifareDESFire.SelectApplication(FabAccessAID); - mifareDESFire.AuthenticateDES(0x00, Empty_Key); - mifareDESFire.ChangeApplicationMasterKey(APP_MasterKey); + // mifareDESFire.AuthenticateDES(0x00, Empty_Key); + // mifareDESFire.ChangeApplicationMasterKey(APP_MasterKey); - mifareDESFire.AuthenticateDES(0x00, APP_MasterKey); - mifareDESFire.ChangeApplicationKey(0x01, APP_Key_1); + // mifareDESFire.AuthenticateDES(0x00, APP_MasterKey); + // mifareDESFire.ChangeApplicationKey(0x01, APP_Key_1); - connected_successfully = true; + // connected_successfully = true; - card.Disconnect(); - }; + // card.Disconnect(); + // }; - reader.CardDiscovered += handler; - reader.Start(); + // reader.CardDiscovered += handler; + // reader.Start(); - Assert.AreEqual(true, connected_successfully); + // Assert.AreEqual(true, connected_successfully); - reader.Stop(); - reader.CardDiscovered -= handler; - } + // reader.Stop(); + // reader.CardDiscovered -= handler; + // } - [Test] - public void SetUpUserCard() - { - IHardware hardware = new Hardware(); - IReader reader = hardware.OpenReader(CardReaderID); + // [Test] + // public void SetUpUserCard() + // { + // IHardware hardware = new Hardware(); + // IReader reader = hardware.OpenReader(CardReaderID); - bool connected_successfully = false; + // bool connected_successfully = false; - ReaderEventHandler handler = (sender, card) => - { - card.Connect(); + // ReaderEventHandler handler = (sender, card) => + // { + // card.Connect(); - MIFARE_DESFire mifareDESFire = new MIFARE_DESFire(card); + // MIFARE_DESFire mifareDESFire = new MIFARE_DESFire(card); - mifareDESFire.SelectApplication(FabAccessAID); - mifareDESFire.AuthenticateDES(0x00, Empty_Key); - UInt16 fileAccessRight = mifareDESFire.GenerateFileAccessRight(AccessRights.FREE, 0x00, 0x00, 0x00); - mifareDESFire.CreateFile(FabAccessIdentFileID, FileCommunication.PLAIN, fileAccessRight, (UInt32)0x90); + // mifareDESFire.SelectApplication(FabAccessAID); + // mifareDESFire.AuthenticateDES(0x00, Empty_Key); + // UInt16 fileAccessRight = mifareDESFire.GenerateFileAccessRight(AccessRights.FREE, 0x00, 0x00, 0x00); + // mifareDESFire.CreateFile(FabAccessIdentFileID, FileCommunication.PLAIN, fileAccessRight, (UInt32)0x90); - System.Text.ASCIIEncoding enc = new System.Text.ASCIIEncoding(); + // System.Text.ASCIIEncoding enc = new System.Text.ASCIIEncoding(); - mifareDESFire.WirteData(FabAccessIdentFileID, 0x00000000, 0x00000000, enc.GetBytes(UserDomain)); + // mifareDESFire.WirteData(FabAccessIdentFileID, 0x00000000, 0x00000000, enc.GetBytes(UserDomain)); - connected_successfully = true; + // connected_successfully = true; - card.Disconnect(); - }; + // card.Disconnect(); + // }; - reader.CardDiscovered += handler; - reader.Start(); + // reader.CardDiscovered += handler; + // reader.Start(); - Assert.AreEqual(true, connected_successfully); + // Assert.AreEqual(true, connected_successfully); - reader.Stop(); - reader.CardDiscovered -= handler; - } + // reader.Stop(); + // reader.CardDiscovered -= handler; + // } - [Test] - public void AuthenticateCard() - { - IHardware hardware = new Hardware(); - IReader reader = hardware.OpenReader(CardReaderID); + // [Test] + // public void AuthenticateCard() + // { + // IHardware hardware = new Hardware(); + // IReader reader = hardware.OpenReader(CardReaderID); - bool connected_successfully = false; + // bool connected_successfully = false; - ReaderEventHandler handler = (sender, card) => - { - card.Connect(); + // ReaderEventHandler handler = (sender, card) => + // { + // card.Connect(); - MIFARE_DESFire mifareDESFire = new MIFARE_DESFire(card); + // MIFARE_DESFire mifareDESFire = new MIFARE_DESFire(card); - mifareDESFire.SelectApplication(FabAccessAID); - byte[] filedata = mifareDESFire.ReadData(FabAccessIdentFileID, 0x00000000, 0x00000000); + // mifareDESFire.SelectApplication(FabAccessAID); + // byte[] filedata = mifareDESFire.ReadData(FabAccessIdentFileID, 0x00000000, 0x00000000); - System.Text.ASCIIEncoding enc = new System.Text.ASCIIEncoding(); - string userdomain = enc.GetString(filedata); + // System.Text.ASCIIEncoding enc = new System.Text.ASCIIEncoding(); + // string userdomain = enc.GetString(filedata); - Console.WriteLine(userdomain); + // Console.WriteLine(userdomain); - mifareDESFire.AuthenticateDES(0x01, APP_Key_1); + // mifareDESFire.AuthenticateDES(0x01, APP_Key_1); - connected_successfully = true; + // connected_successfully = true; - card.Disconnect(); - }; + // card.Disconnect(); + // }; - reader.CardDiscovered += handler; - reader.Start(); + // reader.CardDiscovered += handler; + // reader.Start(); - Assert.AreEqual(true, connected_successfully); + // Assert.AreEqual(true, connected_successfully); - reader.Stop(); - reader.CardDiscovered -= handler; - } - } + // reader.Stop(); + // reader.CardDiscovered -= handler; + // } + //} }