From 187dfc4f4a8c2d3bba8ecb413789e984201d1f94 Mon Sep 17 00:00:00 2001 From: TheJoKlLa Date: Tue, 15 Sep 2020 15:27:01 +0200 Subject: [PATCH] Added: PCSC Implementation --- Borepin.sln | 28 +++- NFC/APDUCommand.cs | 61 +++++++ NFC/APDUResponse.cs | 108 ++++++++++++ NFC/APDUStatusWords.cs | 209 ++++++++++++++++++++++++ NFC/IReader.cs | 14 +- NFC/Mifare DESFire/APDUInstructions.cs | 44 +++++ NFC/Mifare DESFire/APDUStatusCodes.cs | 32 ++++ NFC/Mifare DESFire/CryptoOperations.cs | 13 ++ NFC/Mifare DESFire/FileCommunication.cs | 20 +++ NFC/Mifare DESFire/FileTypes.cs | 30 ++++ NFC/NFC.csproj | 5 + NFC/Readers/PCSC/Card.cs | 63 +++++++ NFC/Readers/PCSC/Hardware.cs | 33 ++++ NFC/Readers/PCSC/Reader.cs | 51 ++++++ NFC_Test/NFC_Test.csproj | 17 ++ NFC_Test/REAL_Windows.cs | 37 +++++ 16 files changed, 757 insertions(+), 8 deletions(-) create mode 100644 NFC/APDUCommand.cs create mode 100644 NFC/APDUResponse.cs create mode 100644 NFC/APDUStatusWords.cs create mode 100644 NFC/Mifare DESFire/APDUInstructions.cs create mode 100644 NFC/Mifare DESFire/APDUStatusCodes.cs create mode 100644 NFC/Mifare DESFire/CryptoOperations.cs create mode 100644 NFC/Mifare DESFire/FileCommunication.cs create mode 100644 NFC/Mifare DESFire/FileTypes.cs create mode 100644 NFC/Readers/PCSC/Card.cs create mode 100644 NFC/Readers/PCSC/Hardware.cs create mode 100644 NFC/Readers/PCSC/Reader.cs create mode 100644 NFC_Test/NFC_Test.csproj create mode 100644 NFC_Test/REAL_Windows.cs diff --git a/Borepin.sln b/Borepin.sln index dda3f6a..da929dd 100644 --- a/Borepin.sln +++ b/Borepin.sln @@ -15,7 +15,9 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Borepin.GTK", "Borepin\Bore EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Borepin.macOS", "Borepin\Borepin.macOS\Borepin.macOS.csproj", "{3EC23FE7-395E-4BBC-B56B-9455354BDA34}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NFC", "NFC\NFC.csproj", "{72DAC306-D4B2-4DBF-9C32-317203FD5D61}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "NFC", "NFC\NFC.csproj", "{72DAC306-D4B2-4DBF-9C32-317203FD5D61}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NFC_Test", "NFC_Test\NFC_Test.csproj", "{0DC42C5F-FB5D-48E1-81C2-25AF23F3916A}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -249,6 +251,30 @@ Global {72DAC306-D4B2-4DBF-9C32-317203FD5D61}.Release|x64.Build.0 = Release|Any CPU {72DAC306-D4B2-4DBF-9C32-317203FD5D61}.Release|x86.ActiveCfg = Release|Any CPU {72DAC306-D4B2-4DBF-9C32-317203FD5D61}.Release|x86.Build.0 = Release|Any CPU + {0DC42C5F-FB5D-48E1-81C2-25AF23F3916A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {0DC42C5F-FB5D-48E1-81C2-25AF23F3916A}.Debug|Any CPU.Build.0 = Debug|Any CPU + {0DC42C5F-FB5D-48E1-81C2-25AF23F3916A}.Debug|ARM.ActiveCfg = Debug|Any CPU + {0DC42C5F-FB5D-48E1-81C2-25AF23F3916A}.Debug|ARM.Build.0 = Debug|Any CPU + {0DC42C5F-FB5D-48E1-81C2-25AF23F3916A}.Debug|iPhone.ActiveCfg = Debug|Any CPU + {0DC42C5F-FB5D-48E1-81C2-25AF23F3916A}.Debug|iPhone.Build.0 = Debug|Any CPU + {0DC42C5F-FB5D-48E1-81C2-25AF23F3916A}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU + {0DC42C5F-FB5D-48E1-81C2-25AF23F3916A}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU + {0DC42C5F-FB5D-48E1-81C2-25AF23F3916A}.Debug|x64.ActiveCfg = Debug|Any CPU + {0DC42C5F-FB5D-48E1-81C2-25AF23F3916A}.Debug|x64.Build.0 = Debug|Any CPU + {0DC42C5F-FB5D-48E1-81C2-25AF23F3916A}.Debug|x86.ActiveCfg = Debug|Any CPU + {0DC42C5F-FB5D-48E1-81C2-25AF23F3916A}.Debug|x86.Build.0 = Debug|Any CPU + {0DC42C5F-FB5D-48E1-81C2-25AF23F3916A}.Release|Any CPU.ActiveCfg = Release|Any CPU + {0DC42C5F-FB5D-48E1-81C2-25AF23F3916A}.Release|Any CPU.Build.0 = Release|Any CPU + {0DC42C5F-FB5D-48E1-81C2-25AF23F3916A}.Release|ARM.ActiveCfg = Release|Any CPU + {0DC42C5F-FB5D-48E1-81C2-25AF23F3916A}.Release|ARM.Build.0 = Release|Any CPU + {0DC42C5F-FB5D-48E1-81C2-25AF23F3916A}.Release|iPhone.ActiveCfg = Release|Any CPU + {0DC42C5F-FB5D-48E1-81C2-25AF23F3916A}.Release|iPhone.Build.0 = Release|Any CPU + {0DC42C5F-FB5D-48E1-81C2-25AF23F3916A}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU + {0DC42C5F-FB5D-48E1-81C2-25AF23F3916A}.Release|iPhoneSimulator.Build.0 = Release|Any CPU + {0DC42C5F-FB5D-48E1-81C2-25AF23F3916A}.Release|x64.ActiveCfg = Release|Any CPU + {0DC42C5F-FB5D-48E1-81C2-25AF23F3916A}.Release|x64.Build.0 = Release|Any CPU + {0DC42C5F-FB5D-48E1-81C2-25AF23F3916A}.Release|x86.ActiveCfg = Release|Any CPU + {0DC42C5F-FB5D-48E1-81C2-25AF23F3916A}.Release|x86.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/NFC/APDUCommand.cs b/NFC/APDUCommand.cs new file mode 100644 index 0000000..c568298 --- /dev/null +++ b/NFC/APDUCommand.cs @@ -0,0 +1,61 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace NFC +{ + public class APDUCommand + { + /// + /// ISO 7816 - CLA - Class + /// + public byte Class { get; set; } + + /// + /// ISO 7816 - INS - Instruction + /// + public byte Instruction { get; set; } + + /// + /// ISO 7816 - P1 - Parameter 1 + /// + public byte Parameter1 { get; set; } + + /// + /// ISO 7816 - P2 - Parameter 2 + /// + public byte Parameter2 { get; set; } + + /// + /// ISO 7816 - Lc - Length Command + /// + public byte LengthCommand + { + get + { + throw new NotImplementedException(); + } + } + + /// + /// ISO 7816 - Data - Data + /// + public byte[] Data { get; set; } + + /// + /// ISO 7816 - Le - Length expected + /// + public byte LengthExpected + { + get + { + throw new NotImplementedException(); + } + } + + public byte[] APDUCommandMessage() + { + throw new NotImplementedException(); + } + } +} diff --git a/NFC/APDUResponse.cs b/NFC/APDUResponse.cs new file mode 100644 index 0000000..bc4f810 --- /dev/null +++ b/NFC/APDUResponse.cs @@ -0,0 +1,108 @@ +using System; +using System.Collections.Generic; +using System.Text; +using System.Linq; +using NFC.Mifare_DESFire; + +namespace NFC +{ + public class APDUResponse + { + /// + /// ISO 7816 - Body - Body + /// + public byte[] Body { get; set; } + + /// + /// ISO 7816 - SW1 - Status Word 1 + /// + public byte SW1 { get; set; } + + /// + /// ISO 7816 - SW2 - Status Word 2 + /// + public byte SW2 { get; set; } + + /// + /// Creates a new APDUResponse from the raw received data. + /// + public APDUResponse(byte[] raw) { + Body = raw.Take(raw.Length-1).ToArray(); + SW1 = raw[raw.Length - 2]; + SW2 = raw[raw.Length - 3]; + } + + public APDUResponse() + { + + } + + public APDUStatusWords StatusWord + { + get + { + // Some status words only require a specific first byte + // and in some cases SW2 contains additional information. + // This will filter out those errors. When there is more information separate methods for getting those are available. + switch(SW1) { + case 0x61: + // Kommando erfolgreich ausgeführt. xx Datenbytes können mit dem ‚GET RESPONSE‘-Kommando abgeholt werden. Statuswort zur Steuerung des T=0-Protokolls + return APDUStatusWords.DATA_READY; + case 0x62: + // Warnung; Zustand des nichtflüchtigen Speichers nicht verändert + return APDUStatusWords.STORAGE_NOT_CHANGED; + case 0x63: + if((SW2 & 0xF0) == 0xC0) { + // Zähler hat den Wert x erreicht (die genaue Bedeutung ist vom Kommando abhängig) + return APDUStatusWords.COUNTER_REACHED; + } + // Warnung; Zustand des nichtflüchtigen Speichers verändert + return APDUStatusWords.STORAGE_CHANGED; + case 0x64: + // Ausführungsfehler; Zustand des nichtflüchtigen Speichers nicht verändert + return APDUStatusWords.EXECUTION_ERROR_WITHOUT_CHANGE; + case 0x65: + // Ausführungsfehler; Zustand des nichtflüchtigen Speichers verändert + return APDUStatusWords.EXECUTION_ERROR_WITH_CHANGE; + case 0x6C: + // Falsche Länge Le; xx gibt die korrekte Länge an Statuswort zur Steuerung des T=0-Protokolls + return APDUStatusWords.INVALID_LE; + } + return (APDUStatusWords) (((UInt16) SW1) << 8 | ((UInt16) SW2)); + } + } + + /// + /// If the reponse status is DATA_READY this method can be used to get the amount of data that can be read from the card. + /// + public byte DataLength + { + get + { + return SW2; + } + } + + /// + /// If the reponse status is COUNTER_REACHED this method can be used to get the value that the counter reached. + /// + public byte Counter + { + get + { + return (byte)(SW2 & 0x0F); + } + } + + /// + /// If the reponse status is INVALID_LE this method can be used to get the correct LE. + /// + public byte CorrectLE + { + get + { + return SW2; + } + } + } +} diff --git a/NFC/APDUStatusWords.cs b/NFC/APDUStatusWords.cs new file mode 100644 index 0000000..b0680cd --- /dev/null +++ b/NFC/APDUStatusWords.cs @@ -0,0 +1,209 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace NFC.Mifare_DESFire +{ + public enum APDUStatusWords : UInt16 + { + /// + /// Kommando erfolgreich ausgeführt. xx Datenbytes können mit dem ‚GET RESPONSE‘-Kommando abgeholt werden. Statuswort zur Steuerung des T=0-Protokolls + /// + DATA_READY = 0x6100, + + /// + /// Die zurückgegebenen Daten können fehlerhaft sein. + /// + FAULTY_DATA = 0x6281, + + /// + /// Da das Dateiende vorher erreicht wurde, konnten nur weniger als Le Bytes gelesen werden. + /// + UNEXPECTED_END_OF_FILE = 0x6282, + + /// + /// Die ausgewählte Datei ist gesperrt (englisch invalidated, wörtlich „ungültig“). + /// + INVALIDATED_FILE = 0x6283, + + /// + /// Die File Control Information (FCI) ist inkonform zu ISO 7816-4. + /// + FCI_NOT_CONFORM = 0x6284, + + /// + /// Warnung; Zustand des nichtflüchtigen Speichers nicht verändert + /// + STORAGE_NOT_CHANGED = 0x6200, + + /// + /// Zähler hat den Wert x erreicht (die genaue Bedeutung ist vom Kommando abhängig) + /// + COUNTER_REACHED = 0x63C0, + + /// + /// Warnung; Zustand des nichtflüchtigen Speichers verändert + /// + STORAGE_CHANGED = 0x6300, + + /// + /// Ausführungsfehler; Zustand des nichtflüchtigen Speichers nicht verändert + /// + EXECUTION_ERROR_WITHOUT_CHANGE = 0x6400, + + /// + /// Speicherfehler + /// + MEMORY_ERROR = 0x6581, + + /// + /// Ausführungsfehler; Zustand des nichtflüchtigen Speichers verändert + /// + EXECUTION_ERROR_WITH_CHANGE = 0x6500, + + /// + /// Befehlslänge (Lc) oder erwartete Antwortlänge (Le) falsch + /// + INVALID_LC_LE = 0x6700, + + /// + /// Funktionen im Class-Byte werden nicht unterstützt + /// + CLASS_FEATURE_NOT_SUPPORTED = 0x6800, + + /// + /// Logische Kanäle werden nicht unterstützt + /// + LOGIC_CHANNEL_NOT_SUPPORTED = 0x6881, + + /// + /// Secure Messaging wird nicht unterstützt + /// + SECURE_MESSAGING_NOT_SUPPORTED = 0x6882, + + /// + /// Kommando nicht erlaubt + /// + COMMAND_NOT_ALLOWED = 0x6900, + + /// + /// Kommando inkompatibel zur Dateistruktur + /// + COMMAND_INCOMPATIBLE = 0x6981, + + /// + /// Sicherheitszustand nicht erfüllt + /// + SAFETY_STATUS_NOT_FULFILLED = 0x6982, + + /// + /// Authentisierungsmethode ist gesperrt + /// + AUTHENTICATION_METHOD_LOCKED = 0x6983, + + /// + /// Referenzierte Daten sind gesperrt + /// + REFERENCED_FILE_LOCKED = 0x6984, + + /// + /// Nutzungsbedingungen sind nicht erfüllt + /// + TERMS_OF_SERVICE_NOT_FULFILLED = 0x6985, + + /// + /// Kommando nicht erlaubt (kein EF selektiert) + /// + COMMAND_NOT_ALLOWED_NO_EF_SELECTED = 0x6986, + + /// + /// Erwartete Secure-Messaging-Objekte nicht gefunden + /// + EXPECTED_SECURE_MESSAGING_OBJECTS_NOT_FOUND = 0x6987, + + /// + /// Secure-Messaging-Datenobjekte sind inkorrekt + /// + INVALID_SECURE_MESSAGING_OBJECTS = 0x6988, + + /// + /// Falsche Parameter P1/P2 + /// + WRONG_PARAMETERS = 0x6A00, + + /// + /// Falsche Daten + /// + WRONG_DATA = 0x6A80, + + /// + /// Funktion wird nicht unterstützt + /// + FEATURE_NOT_SUPPORTED = 0x6A81, + + /// + /// Datei wurde nicht gefunden + /// + FILE_NOT_FOUND = 0x6A82, + + /// + /// Datensatz (engl. record) der Datei nicht gefunden + /// + RECORD_NOT_FOUND = 0x6A83, + + /// + /// Nicht genügend Speicherplatz in der Datei + /// + INSUFFICIENT_SPACE = 0x6A84, + + /// + /// Lc nicht konsistent mit der TLV-Struktur + /// + LC_TLV_INCONSISTENT = 0x6A85, + + /// + /// Inkorrekte Parameter P1/P2 + /// + INCORRECT_PARAMETERs = 0x6A86, + + /// + /// Lc inkonsistent mit P1/P2 + /// + LC_PARAMETERS_INCONSISTENT = 0x6A87, + + /// + /// Referenzierte Daten nicht gefunden + /// + REFERENCED_FILE_NOT_FOUND = 0x6A88, + + /// + /// Parameter P1/P2 falsch + /// + WRONG_PARAMETERS_2 = 0x6B00, + + /// + /// Falsche Länge Le; xx gibt die korrekte Länge an Statuswort zur Steuerung des T=0-Protokolls + /// + INVALID_LE = 0x6C00, + + /// + /// Das Kommando (INS) wird nicht unterstützt + /// + INSTRUCTION_NOT_SUPPORTED = 0x6D00, + + /// + /// Die Kommandoklasse (CLA) wird nicht unterstützt + /// + CLASS_NOT_SUPPORTED = 0x6E00, + + /// + /// Kommando wurde mit unbekanntem Fehler abgebrochen + /// + UNKNOWN_ERROR = 0x6F00, + + /// + /// Kommando erfolgreich ausgeführt + /// + SUCCESS = 0x9000, + } +} diff --git a/NFC/IReader.cs b/NFC/IReader.cs index a0b05b1..d068f9e 100644 --- a/NFC/IReader.cs +++ b/NFC/IReader.cs @@ -1,6 +1,4 @@ using System; -using System.Collections.Generic; -using System.Text; namespace NFC { @@ -16,16 +14,18 @@ namespace NFC bool IsAvailable(); /// Returns all available readers. - String[] GetReader(); + string[] GetReaders(); /// /// Create a new reader instance from the specified id. /// /// Returns the spatform specific reader that corresponds to the id. /// Invalid reader id. - IReader OpenReader(String readerID); + IReader OpenReader(string readerID); } + public delegate void ReaderEventHandler(object sender, ICard card); + /// /// Abstraction of a platform-specifc reader that can communicate with NFC cards. /// @@ -34,12 +34,12 @@ namespace NFC /// /// Event that will be called when a new tag was discovered. /// - event EventHandler CardDiscovered; + event ReaderEventHandler CardDiscovered; /// /// Event that will be called when a tag that is in use gets disconnected. /// - event EventHandler CardLost; + event ReaderEventHandler CardLost; void start(); @@ -63,7 +63,7 @@ namespace NFC /// /// Application Protocol Data Unit Command - ISO 7816 /// Application Protocol Data Unit Response - ISO 7816 - byte[] Transmit(byte[] apdu_cmd); + APDUResponse Transmit(APDUCommand apdu_cmd); } public class ReaderUnavailableException : Exception { } diff --git a/NFC/Mifare DESFire/APDUInstructions.cs b/NFC/Mifare DESFire/APDUInstructions.cs new file mode 100644 index 0000000..dd3025c --- /dev/null +++ b/NFC/Mifare DESFire/APDUInstructions.cs @@ -0,0 +1,44 @@ +namespace NFC.Mifare_DESFire +{ + enum APDUInstructions : byte + { + AUTHENTICATE_ISO = 0x1A, + AUTHENTICATE_AES = 0xAA, + CHANGE_KEY_SETTINGS = 0x54, + SET_CONFIGURATION = 0x5C, + CHANGE_KEY = 0xC4, + GET_KEY_VERSION = 0x64, + CREATE_APPLICATION = 0xCA, + DELETE_APPLICATION = 0xDA, + GET_APPLICATION_IDS = 0x6A, + FREE_MEMORY = 0x6E, + GET_DF_NAMES = 0x6D, + GET_KEY_SETTINGS = 0x45, + SELECT_APPLICATION = 0x5A, + FORMAT_PICC = 0xFC, + GET_VERSION = 0x60, + GET_CARD_UID = 0x51, + GET_FILE_IDS = 0x6F, + GET_FILE_SETTINGS = 0xF5, + CHANGE_FILE_SETTINGS = 0x5F, + CREATE_STDDATAFILE = 0xCD, + CREATE_BACKUPDATAFILE = 0xCB, + CREATE_VALUE_FILE = 0xCC, + CREATE_LINEAR_RECORD_FILE = 0xC1, + CREATE_CYCLIC_RECORD_FILE = 0xC0, + DELETE_FILE = 0xDF, + GET_ISO_FILE_IDS = 0x61, + READ_DATA = 0x8D, + WRITE_DATA = 0x3D, + GET_VALUE = 0x6C, + CREDIT = 0x0C, + DEBIT = 0xDC, + LIMITED_CREDIT = 0x1C, + WRITE_RECORD = 0x3B, + READ_RECORDS = 0xBB, + CLEAR_RECORD_FILE = 0xEB, + COMMIT_TRANSACTION = 0xC7, + ABORT_TRANSACTION = 0xA7, + CONTINUE = 0xAF, + } +} diff --git a/NFC/Mifare DESFire/APDUStatusCodes.cs b/NFC/Mifare DESFire/APDUStatusCodes.cs new file mode 100644 index 0000000..a06327b --- /dev/null +++ b/NFC/Mifare DESFire/APDUStatusCodes.cs @@ -0,0 +1,32 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace NFC.Mifare_DESFire +{ + public enum APDUStatusCodes : UInt16 + { + OPERATION_OK = 0x9000, // = Successful operation + NO_CHANGES = 0x900C, // = No changes done to backup files, CommitTransaction / AbortTransaction not necessary + OUT_OF_EEPROM_ERROR = 0x900E, // = Insufficient NV-Memory to complete command + ILLEGAL_COMMAND_CODE = 0x901C, // = Command code not supported + INTEGRITY_ERROR = 0x901E, // = CRC or MAC does not match data Padding bytes not valid + NO_SUCH_KEY = 0x9040, // = Invalid key number specified + LENGTH_ERROR = 0x907E, // = Length of command string invalid + PERMISSION_DENIED = 0x909D, // = Current configuration / status does not allow the requested command + PARAMETER_ERROR = 0x909E, // = Value of the parameter(s) invalid + APPLICATION_NOT_FOUND = 0x90A0, // = Requested AID not present on PICC + APPL_INTEGRITY_ERROR = 0x90A1, // = Unrecoverable error within application, application will be disabled + AUTHENTICATION_ERROR = 0x90AE, // = Current authentication status does not allow the requested command + ADDITIONAL_FRAME = 0x90AF, // = Additional data frame is expected to be sent + BOUNDARY_ERROR = 0x90BE, // = Attempt to read/write data from/to beyond the file\'s/record\'s limits. Attempt to exceed the limits of a value file. + PICC_INTEGRITY_ERROR = 0x90C1, // = Unrecoverable error within PICC, PICC will be disabled + COMMAND_ABORTED = 0x90CA, // = Previous Command was not fully completed Not all Frames were requested or provided by the PCD + PICC_DISABLED_ERROR = 0x90CD, // = PICC was disabled by an unrecoverable error + COUNT_ERROR = 0x90CE, // = Number of Applications limited to 28, no additional CreateApplication possible + DUPLICATE_ERROR = 0x90DE, // = Creation of file/application failed because file/application with same number already exists + EEPROM_ERROR = 0x90EE, // = Could not complete NV-write operation due to loss of power, internal backup/rollback mechanism activated + FILE_NOT_FOUND = 0x90F0, // = Specified file number does not exist + FILE_INTEGRITY_ERROR = 0x90F1, // = Unrecoverable error within file, file will be disabled + } +} \ No newline at end of file diff --git a/NFC/Mifare DESFire/CryptoOperations.cs b/NFC/Mifare DESFire/CryptoOperations.cs new file mode 100644 index 0000000..0ae77af --- /dev/null +++ b/NFC/Mifare DESFire/CryptoOperations.cs @@ -0,0 +1,13 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace NFC.Mifare_DESFire +{ + enum CryptoOperations : byte + { + TDES = 0x00, + TKTDES = 0x40, + AES = 0x80, + } +} diff --git a/NFC/Mifare DESFire/FileCommunication.cs b/NFC/Mifare DESFire/FileCommunication.cs new file mode 100644 index 0000000..efce035 --- /dev/null +++ b/NFC/Mifare DESFire/FileCommunication.cs @@ -0,0 +1,20 @@ +namespace NFC.Mifare_DESFire +{ + enum FileCommunication : byte + { + /// + /// "Plain communication" + /// + PLAIN = 0x00, + + /// + /// Plain communication secured by DES/3DES MACing + /// + MAC = 0x01, + + /// + /// Fully DES/3DES enciphered communication + /// + ENCRYPT = 0x03 + } +} diff --git a/NFC/Mifare DESFire/FileTypes.cs b/NFC/Mifare DESFire/FileTypes.cs new file mode 100644 index 0000000..9c1fb13 --- /dev/null +++ b/NFC/Mifare DESFire/FileTypes.cs @@ -0,0 +1,30 @@ +namespace NFC.Mifare_DESFire +{ + enum FileTypes : byte + { + /// + /// Standard Data File + /// + STANDARD = 0x00, + + /// + /// Backup Data Files + /// + BACKUP = 0x01, + + /// + /// Value Files with Backup + /// + VALUE = 0x02, + + /// + /// Linear Record Files with Backup + /// + LINEARRECORD = 0x03, + + /// + /// Cyclic Record Files with Backup + /// + CYCLICRECORD = 0x04 + } +} diff --git a/NFC/NFC.csproj b/NFC/NFC.csproj index cb63190..3c87e5e 100644 --- a/NFC/NFC.csproj +++ b/NFC/NFC.csproj @@ -4,4 +4,9 @@ netcoreapp3.1 + + + + + diff --git a/NFC/Readers/PCSC/Card.cs b/NFC/Readers/PCSC/Card.cs new file mode 100644 index 0000000..cd70e1b --- /dev/null +++ b/NFC/Readers/PCSC/Card.cs @@ -0,0 +1,63 @@ +using PCSC; +using PCSC.Iso7816; + +namespace NFC.Readers.PCSC +{ + public class Card : ICard + { + private IsoReader _ISOReader; + private string _ReaderID; + + public Card(IsoReader isoreader, string readerID) + { + _ISOReader = isoreader; + _ReaderID = readerID; + } + public void Connect() + { + _ISOReader.Connect(_ReaderID, SCardShareMode.Shared, SCardProtocol.Any); + } + + public void Disconnect() + { + _ISOReader.Disconnect(SCardReaderDisposition.Eject); + } + + public APDUResponse Transmit(APDUCommand apdu_cmd) + { + Response response = _ISOReader.Transmit(Convert(apdu_cmd)); + return Convert(response); + } + + public CommandApdu Convert(APDUCommand apdu_cmd) + { + CommandApdu apdu = new CommandApdu(IsoCase.Case2Short, _ISOReader.ActiveProtocol) + { + CLA = apdu_cmd.Class, + INS = apdu_cmd.Instruction, + P1 = apdu_cmd.Parameter1, + P2 = apdu_cmd.Parameter2, + + Data = apdu_cmd.Data, + + Le = apdu_cmd.LengthExpected + }; + + return apdu; + } + + public APDUResponse Convert(Response response) + { + ResponseApdu responseApdu = response.Get(0); + + APDUResponse apduResponse = new APDUResponse() + { + SW1 = responseApdu.SW1, + SW2 = responseApdu.SW2, + Body = responseApdu.GetData() + }; + + return apduResponse; + } + } +} diff --git a/NFC/Readers/PCSC/Hardware.cs b/NFC/Readers/PCSC/Hardware.cs new file mode 100644 index 0000000..efc2373 --- /dev/null +++ b/NFC/Readers/PCSC/Hardware.cs @@ -0,0 +1,33 @@ +using PCSC; + +namespace NFC.Readers.PCSC +{ + public class Hardware : IHardware + { + public string[] GetReaders() + { + var contextFactory = ContextFactory.Instance; + using (var context = contextFactory.Establish(SCardScope.System)) + { + return context.GetReaders(); + } + } + + public bool IsAvailable() + { + if(GetReaders().Length == 0) + { + return false; + } + else + { + return true; + } + } + + public IReader OpenReader(string readerID) + { + return new Reader(readerID); + } + } +} diff --git a/NFC/Readers/PCSC/Reader.cs b/NFC/Readers/PCSC/Reader.cs new file mode 100644 index 0000000..d3e9686 --- /dev/null +++ b/NFC/Readers/PCSC/Reader.cs @@ -0,0 +1,51 @@ +using PCSC; +using PCSC.Iso7816; +using System; +using System.Collections.Generic; +using System.Text; + +namespace NFC.Readers.PCSC +{ + + public class Reader : IReader, IDisposable + { + private string _ReaderID; + private IContextFactory _ContextFactory; + private ISCardContext _SCardContext; + private IsoReader _ISOReader; + private ICard _Card; + + public Reader(string readerID) + { + _ReaderID = readerID; + } + + public event ReaderEventHandler CardDiscovered; + public event ReaderEventHandler CardLost; + + public void Dispose() + { + stop(); + } + + public void start() + { + _ContextFactory = ContextFactory.Instance; + _SCardContext = _ContextFactory.Establish(SCardScope.System); + + _ISOReader = new IsoReader(_SCardContext); + + _Card = new Card(_ISOReader, _ReaderID); + + CardDiscovered?.Invoke(this, _Card); + } + + public void stop() + { + CardLost?.Invoke(this, _Card); + + _ISOReader.Dispose(); + _SCardContext.Dispose(); + } + } +} diff --git a/NFC_Test/NFC_Test.csproj b/NFC_Test/NFC_Test.csproj new file mode 100644 index 0000000..df2e516 --- /dev/null +++ b/NFC_Test/NFC_Test.csproj @@ -0,0 +1,17 @@ + + + + netcoreapp3.1 + + + + + + + + + + + + + diff --git a/NFC_Test/REAL_Windows.cs b/NFC_Test/REAL_Windows.cs new file mode 100644 index 0000000..f144ee8 --- /dev/null +++ b/NFC_Test/REAL_Windows.cs @@ -0,0 +1,37 @@ +using NUnit.Framework; +using System; +using System.Collections.Generic; +using System.Text; +using NFC; +using NFC.Readers.PCSC; + +namespace NFC_Test +{ + [TestFixture, Explicit] + public class REAL_Windows + { + [Test] + public void GetReaders() + { + Hardware hardware = new Hardware(); + string[] readers = hardware.GetReaders(); + + Console.WriteLine("Readers detected: {0}", readers.Length); + + if(readers.Length > 0) + { + Console.WriteLine("List of ReaderIDs:"); + foreach (string readerID in readers) + { + Console.WriteLine("{0}", readerID); + } + } + } + + [TestCase("")] + public void Connect(string readerID) + { + + } + } +}