using NFC.Interfaces; using PCSClib = PCSC; using PCSCIso7816 = PCSC.Iso7816; using System; using System.Collections.Generic; using PCSC.Exceptions; using NFC.Exceptions; using PCSC.Iso7816; namespace NFC.PCSC { public class NFCService : INFCService { #region Private Members private PCSCIso7816.IsoReader _IsoReader; private PCSClib.IContextFactory _ContextFactory; private PCSClib.ISCardContext _SCardContext; #endregion #region Constructors public NFCService() { _ContextFactory = PCSClib.ContextFactory.Instance; _SCardContext = _ContextFactory.Establish(PCSClib.SCardScope.System); } #endregion #region Members /// /// Indicates if NFC Hardware is available /// public bool IsAvailable { get { return true; } } /// /// Indicates if NFC Hardware is enabled /// public bool IsEnabled { get { return true; } } /// /// Indicates if NFC Card is connected /// public bool IsConnected { get { return _IsoReader != null; } } #endregion #region Methods /// /// Get a list of availible NFC ReaderIDs /// public IList GetReaderIDs() { return new List(_SCardContext.GetReaders()); } /// /// Connect with ReaderID to NFC Card /// /// ReaderID from GetReaderIDs /// /// /// /// public void Connect(string readerID) { if(string.IsNullOrEmpty(readerID)) { throw new ArgumentNullException(); } try { _IsoReader = new PCSCIso7816.IsoReader(_SCardContext); _IsoReader.Connect(readerID, PCSClib.SCardShareMode.Shared, PCSClib.SCardProtocol.Any); } catch (Exception exception) { switch(exception) { case InvalidContextException _: case InvalidProtocolException _: case InvalidValueException _: case UnsupportedFeatureException _: case CommunicationErrorException _: case InternalErrorException _: case WinErrorInsufficientBufferException _: case InsufficientBufferException _: throw new ConnectionException("Connect failed", exception); case NoServiceException _: case NoReadersAvailableException _: case NotReadyException _: case PCSClib.Exceptions.ReaderUnavailableException _: case SharingViolationException _: case UnknownReaderException _: throw new NFC.Exceptions.ReaderException("Reader connecting failed", exception); case NoSmartcardException _: case UnpoweredCardException _: case UnresponsiveCardException _: case RemovedCardException _: throw new CardException("Reader connecting failed", exception); case PCSCException _: default: throw new ConnectionException("Connect failed", exception); } } } /// /// Disconnects Reader from NFC Card /// /// /// public void Disconnect() { if(_IsoReader == null) { throw new InvalidOperationException(); } try { _IsoReader.Disconnect(PCSClib.SCardReaderDisposition.Eject); } catch(Exception exception) { throw new ConnectionException("Disconnect failed", exception); } finally { _IsoReader.Dispose(); _IsoReader = null; } } /// /// Transmit APDUCommand to Card if connected /// /// /// /// /// /// public APDUResponse Transmit(APDUCommand command) { if(_IsoReader == null) { throw new InvalidOperationException(); } if(command == null) { throw new ArgumentNullException(); } try { PCSCIso7816.Response response = _IsoReader.Transmit(ConvertAPDUCommand(command)); return Convert(response); } catch(Exception exception) { switch (exception) { case InvalidContextException _: case InvalidProtocolException _: case InvalidValueException _: case UnsupportedFeatureException _: case InternalErrorException _: case WinErrorInsufficientBufferException _: throw new ConnectionException("Connect failed", exception); case InvalidApduException _: case InsufficientBufferException _: case CommunicationErrorException _: throw new ConnectionException("Transmit failed", exception); case NoServiceException _: case NoReadersAvailableException _: case NotReadyException _: case ReaderUnavailableException _: case SharingViolationException _: case UnknownReaderException _: throw new ReaderException("Reader connecting failed", exception); case NoSmartcardException _: case UnpoweredCardException _: case UnresponsiveCardException _: case RemovedCardException _: throw new CardException("Reader connecting failed", exception); case PCSCException _: default: throw new ConnectionException("Connect failed", exception); } } } #endregion #region Convert Methods public PCSCIso7816.CommandApdu ConvertAPDUCommand(APDUCommand apdu_cmd) { switch (apdu_cmd.Case) { case NFC.IsoCase.Case1: return new PCSCIso7816.CommandApdu(ConvertISOCase(apdu_cmd.Case), ConvertSCardProtocol(apdu_cmd.Protocol)) { CLA = apdu_cmd.CLA, INS = apdu_cmd.INS, P1 = apdu_cmd.P1, P2 = apdu_cmd.P2 }; case NFC.IsoCase.Case2Short: return new PCSCIso7816.CommandApdu(ConvertISOCase(apdu_cmd.Case), ConvertSCardProtocol(apdu_cmd.Protocol)) { CLA = apdu_cmd.CLA, INS = apdu_cmd.INS, P1 = apdu_cmd.P1, P2 = apdu_cmd.P2, Le = apdu_cmd.LE }; case NFC.IsoCase.Case3Short: return new PCSCIso7816.CommandApdu(ConvertISOCase(apdu_cmd.Case), ConvertSCardProtocol(apdu_cmd.Protocol)) { CLA = apdu_cmd.CLA, INS = apdu_cmd.INS, P1 = apdu_cmd.P1, P2 = apdu_cmd.P2, Data = apdu_cmd.Data }; case NFC.IsoCase.Case4Short: return new PCSCIso7816.CommandApdu(ConvertISOCase(apdu_cmd.Case), ConvertSCardProtocol(apdu_cmd.Protocol)) { CLA = apdu_cmd.CLA, INS = apdu_cmd.INS, P1 = apdu_cmd.P1, P2 = apdu_cmd.P2, Data = apdu_cmd.Data, Le = apdu_cmd.LE }; default: throw new Exception("Unknown IsoCase"); } } public PCSCIso7816.IsoCase ConvertISOCase(NFC.IsoCase isoCase) { switch (isoCase) { case NFC.IsoCase.Case1: return PCSCIso7816.IsoCase.Case1; case NFC.IsoCase.Case2Short: return PCSCIso7816.IsoCase.Case2Short; case NFC.IsoCase.Case3Short: return PCSCIso7816.IsoCase.Case3Short; case NFC.IsoCase.Case4Short: return PCSCIso7816.IsoCase.Case4Short; default: throw new Exception("Unknown IsoCase"); } } public PCSClib.SCardProtocol ConvertSCardProtocol(NFC.SCardProtocol sCardProtocol) { switch (sCardProtocol) { case NFC.SCardProtocol.UNSET: return PCSClib.SCardProtocol.Unset; case NFC.SCardProtocol.T0: return PCSClib.SCardProtocol.T0; case NFC.SCardProtocol.T1: return PCSClib.SCardProtocol.T1; case NFC.SCardProtocol.RAW: return PCSClib.SCardProtocol.Raw; case NFC.SCardProtocol.T15: return PCSClib.SCardProtocol.T15; case NFC.SCardProtocol.ANY: return PCSClib.SCardProtocol.Any; default: throw new NotSupportedException("Unknown SCardProtocol"); } } public APDUResponse Convert(PCSCIso7816.Response response) { PCSCIso7816.ResponseApdu responseApdu = response.Get(0); APDUResponse apduResponse = new APDUResponse() { SW1 = responseApdu.SW1, SW2 = responseApdu.SW2, Body = responseApdu.GetData() }; return apduResponse; } #endregion } }