public byte[] GetUid(SCardReader reader) { SCardError sc = reader.BeginTransaction(); var apdu = new CommandApdu(IsoCase.Case2Short, reader.ActiveProtocol) { CLA = 0xFF, Instruction = InstructionCode.GetData, P1 = 0x00, P2 = 0x00, Le = 0x00 }; var responseApdu = SendAPDU(apdu, reader); reader.EndTransaction(SCardReaderDisposition.Leave); if (responseApdu != null && responseApdu.HasData) { return responseApdu.GetData(); } else { return new byte[0]; } }
private static void Main() { // Establish Smartcard context using (var context = new SCardContext()) { context.Establish(SCardScope.System); var readerNames = context.GetReaders(); if (readerNames == null || readerNames.Length < 1) { Console.WriteLine("You need at least one reader in order to run this example."); Console.ReadKey(); return; } var readerName = ChooseReader(readerNames); if (readerName == null) { return; } using (var isoReader = new IsoReader(context, readerName, SCardShareMode.Shared, SCardProtocol.Any, false)) { // Build a GET CHALLENGE command var apdu = new CommandApdu(IsoCase.Case2Short, isoReader.ActiveProtocol) { CLA = 0x00, // Class Instruction = InstructionCode.GetChallenge, P1 = 0x00, // Parameter 1 P2 = 0x00, // Parameter 2 Le = 0x08 // Expected length of the returned data }; Console.WriteLine("Send APDU with \"GET CHALLENGE\" command: {0}", BitConverter.ToString(apdu.ToArray())); var response = isoReader.Transmit(apdu); Console.WriteLine("SW1 SW2 = {0:X2} {1:X2}", response.SW1, response.SW2); if (!response.HasData) { Console.WriteLine("No data. (Card does not understand \"GET CHALLENGE\")"); } else { var data = response.GetData(); Console.WriteLine("Challenge: {0}", BitConverter.ToString(data)); } } } Console.ReadKey(); }
private byte[] SendCommand(CommandApdu command) { var response = reader.Transmit(command); if (!response.HasData) return new byte[] { response.SW1, response.SW2 }; var data = response.GetData(); var result = new byte[data.Length + 2]; Buffer.BlockCopy(data, 0, result, 0, data.Length); result[result.Length - 2] = response.SW1; result[result.Length - 1] = response.SW2; return result; }
public bool LoadKey(KeyStructure keyStructure, int keyNumber, byte[] key) { unchecked { var loadKeyCmd = new CommandApdu(IsoCase.Case3Short, SCardProtocol.Any) { CLA = 0xFF, Instruction = InstructionCode.ExternalAuthenticate, P1 = (byte) keyStructure, P2 = (byte) keyNumber, Data = key }; Debug.WriteLine(string.Format("Load Authentication Keys: {0}", BitConverter.ToString(loadKeyCmd.ToArray()))); var response = _isoReader.Transmit(loadKeyCmd); Debug.WriteLine(string.Format("SW1 SW2 = {0:X2} {1:X2}", response.SW1, response.SW2)); return Success(response); } }
protected ResponseApdu SendAPDU(CommandApdu apdu, SCardReader reader) { var receivePci = new SCardPCI(); // IO returned protocol control information. var sendPci = SCardPCI.GetPci(reader.ActiveProtocol); var receiveBuffer = new byte[256]; var command = apdu.ToArray(); SCardError sc = reader.Transmit( sendPci, // Protocol Control Information (T0, T1 or Raw) command, // command APDU receivePci, // returning Protocol Control Information ref receiveBuffer); // data buffer if (sc != SCardError.Success) { // todo return null; } return new ResponseApdu(receiveBuffer, IsoCase.Case2Short, reader.ActiveProtocol); }
private byte[] getPage(byte page, SCardReader reader) { var apdu = new CommandApdu(IsoCase.Case2Short, reader.ActiveProtocol) { CLA = 0xFF, Instruction = InstructionCode.ReadBinary, P1 = 0x00, P2 = page, // block number Le = 0x04 // bytes to read }; var responseApdu = SendAPDU(apdu, reader); if (responseApdu != null && responseApdu.HasData) { return responseApdu.GetData(); } else { return new byte[0]; } }
public byte[] ReadBinary(int msb, int lsb, int size) { unchecked { var readBinaryCmd = new CommandApdu(IsoCase.Case2Short, SCardProtocol.Any) { CLA = 0xFF, Instruction = InstructionCode.ReadBinary, P1 = (byte) msb, P2 = (byte) lsb, Le = size }; Debug.WriteLine(string.Format("Read Binary (before update): {0}", BitConverter.ToString(readBinaryCmd.ToArray()))); var response = _isoReader.Transmit(readBinaryCmd); Debug.WriteLine(string.Format("SW1 SW2 = {0:X2} {1:X2} Data: {2}", response.SW1, response.SW2, BitConverter.ToString(response.GetData()))); return Success(response) ? response.GetData() ?? new byte[0] : null; } }
public bool Authenticate(int msb, int lsb, KeyType keyType, int keyNumber) { unchecked { var authBlock = new GeneralAuthenticate { MSB = (byte)msb, LSB = (byte)lsb, KeyNumber = (byte)keyNumber, KeyType = keyType }; var authKeyCmd = new CommandApdu(IsoCase.Case3Short, SCardProtocol.Any) { CLA = 0xFF, Instruction = InstructionCode.InternalAuthenticate, P1 = 0x00, P2 = 0x00, Data = authBlock.ToArray() }; Debug.WriteLine(string.Format("General Authenticate: {0}", BitConverter.ToString(authKeyCmd.ToArray()))); var response = _isoReader.Transmit(authKeyCmd); Debug.WriteLine(string.Format("SW1 SW2 = {0:X2} {1:X2}", response.SW1, response.SW2)); return (response.SW1 == 0x90) && (response.SW2 == 0x00); } }
private void WriteAllCardBytes(IsoReader isoReader, byte[] bytes, int packetSize) { var bytesToWrite = new List<byte>(bytes); //while (bytesToWrite.Count < 38 * 4) // bytesToWrite.Add(0x00); while (bytesToWrite.Count % packetSize != 0) bytesToWrite.Add(0x00); for (int i = 0; i < bytesToWrite.Count / packetSize; i++) { var updateBinaryCmd = new CommandApdu(IsoCase.Case3Short, SCardProtocol.Any) { CLA = 0xFF, Instruction = InstructionCode.UpdateBinary, P1 = 0x00, P2 = (byte)((16 / packetSize) + i), Data = bytesToWrite.Skip(i * packetSize).Take(packetSize).ToArray() }; var response = isoReader.Transmit(updateBinaryCmd); Console.WriteLine("UpdateBinary: {0},{1}", response.SW1, response.SW2); } }
private bool AuthenticateBlock(byte blockNumber, SCardReader reader) { var apdu = new CommandApdu(IsoCase.Case3Short, reader.ActiveProtocol) { CLA = 0xFF, Instruction = InstructionCode.InternalAuthenticate, P1 = 0x00, P2 = 0x00, Data = new byte[]{ (byte)0x01, // version number (byte)0x00, blockNumber, (byte)authentificationKeyType, keyNumber} }; var responseApdu = SendAPDU(apdu, reader); if (responseApdu != null && responseApdu.SW1 == 0x90) { return true; } else { return false; } }
public virtual Response Transmit(CommandApdu cmdApdu) { if (cmdApdu == null) throw new ArgumentNullException("cmdApdu"); // prepare send buffer (Check Command APDU and convert it to an byte array) byte[] sendbuf; try { sendbuf = cmdApdu.ToArray(); } catch (InvalidOperationException ex) { throw new InvalidApduException("Invalid APDU.", cmdApdu, ex); } catch (Exception ex) { throw ex; } // create Response object Response resp = new Response(); // prepare receive buffer (Response APDU) byte[] recvbuf = null; int recvbuflen = cmdApdu.ExpectedResponseLength; // expected size that shall be returned recvbuf = new byte[recvbuflen]; ResponseApdu respApdu = null; SCardPCI recvPci = new SCardPCI(); respApdu = _SimpleTransmit( sendbuf, sendbuf.Length, cmdApdu.Case, // ISO case used by the Command APDU cmdApdu.Protocol, // Protocol used by the Command APDU recvPci, ref recvbuf, ref recvbuflen); /* Check status word SW1SW2: * * 1. 0x6cxx -> Set response buffer size Le <- SW2 * 2. AND/OR 0x61xx -> More data can be read with GET RESPONSE */ // Case 1: SW1=0x6c, Previous Le/P3 not accepted -> Set le = SW2 if (respApdu.SW1 == (byte)SW1Code.ErrorP3Incorrect) { CommandApdu resendCmdApdu = (CommandApdu)cmdApdu.Clone(); if (respApdu.SW2 == 0) { resendCmdApdu.Le = 0; // 256 recvbuflen = 256 + 2; // 2 bytes for status word } else { resendCmdApdu.Le = respApdu.SW2; recvbuflen = respApdu.SW2 + 2; // 2 bytes for status word } recvbuf = new byte[recvbuflen]; recvPci = new SCardPCI(); try { sendbuf = resendCmdApdu.ToArray(); // Shall we wait until we re-send we APDU/TPDU? if (_retransmitWaitTime > 0) Thread.Sleep(_retransmitWaitTime); // send Command APDU again with new Le value respApdu = _SimpleTransmit( sendbuf, sendbuf.Length, resendCmdApdu.Case, resendCmdApdu.Protocol, recvPci, ref recvbuf, ref recvbuflen); } catch (InvalidOperationException ex) { throw new InvalidApduException("Got SW1=0x6c. Retransmission failed because of an invalid APDU.", resendCmdApdu, ex); } } // Case 2: SW1=0x61, More data available -> GET RESPONSE if (respApdu.SW1 == (byte)SW1Code.NormalDataResponse) { /* The transmission system shall issue a GET RESPONSE command APDU (or TPDU) * to the card by assigning the minimum of SW2 and Le to parameter Le (or P3)). * Le = min(Le,SW2) */ int _le = (cmdApdu.Le < respApdu.SW2) ? cmdApdu.Le : respApdu.SW2; do { // add the last ResponseAPDU to the Response object resp.AddResponseApdu(respApdu); resp.AddRecvPci(recvPci); CommandApdu getResponseApdu = _constructGetResponseApdu(ref _le); if (_le == 0) recvbuflen = 256 + 2; // 2 bytes for status word else recvbuflen = _le + 2; // 2 bytes for status word recvbuf = new byte[recvbuflen]; try { sendbuf = getResponseApdu.ToArray(); // Shall we wait until we re-send we APDU/TPDU? if (_retransmitWaitTime > 0) Thread.Sleep(_retransmitWaitTime); // send Command APDU again with new Le value respApdu = _SimpleTransmit( sendbuf, sendbuf.Length, getResponseApdu.Case, getResponseApdu.Protocol, recvPci, ref recvbuf, ref recvbuflen); } catch (InvalidOperationException ex) { throw new InvalidApduException("Got SW1=0x61. Retransmission failed because of an invalid GET RESPONSE APDU.", getResponseApdu, ex); } // In case there is more data available. _le = respApdu.SW2; } while ( // More data available. respApdu.SW1 == (byte)SW1Code.NormalDataResponse || // Warning condition: data may be corrupted. Iso7816-4 7.1.5 (respApdu.SW1 == (byte)SW1Code.WarningNVDataNotChanged && respApdu.SW2 == (byte)0x81) ); } resp.AddResponseApdu(respApdu); resp.AddRecvPci(recvPci); return resp; }
public static void Main() { using (var context = new SCardContext()) { context.Establish(SCardScope.System); var readerNames = context.GetReaders(); if (readerNames == null || readerNames.Length < 1) { Console.WriteLine("You need at least one reader in order to run this example."); Console.ReadKey(); return; } var readerName = ChooseRfidReader(readerNames); if (readerName == null) { return; } using (var rfidReader = new SCardReader(context)) { var sc = rfidReader.Connect(readerName, SCardShareMode.Shared, SCardProtocol.Any); if (sc != SCardError.Success) { Console.WriteLine("Could not connect to reader {0}:\n{1}", readerName, SCardHelper.StringifyError(sc)); Console.ReadKey(); return; } var apdu = new CommandApdu(IsoCase.Case2Short, rfidReader.ActiveProtocol) { CLA = 0xFF, Instruction = InstructionCode.GetData, P1 = 0x00, P2 = 0x00, Le = 0 // We don't know the ID tag size }; sc = rfidReader.BeginTransaction(); if (sc != SCardError.Success) { Console.WriteLine("Could not begin transaction."); Console.ReadKey(); return; } Console.WriteLine("Retrieving the UID .... "); var receivePci = new SCardPCI(); // IO returned protocol control information. var sendPci = SCardPCI.GetPci(rfidReader.ActiveProtocol); var receiveBuffer = new byte[256]; var command = apdu.ToArray(); sc = rfidReader.Transmit( sendPci, // Protocol Control Information (T0, T1 or Raw) command, // command APDU receivePci, // returning Protocol Control Information ref receiveBuffer); // data buffer if (sc != SCardError.Success) { Console.WriteLine("Error: " + SCardHelper.StringifyError(sc)); } var responseApdu = new ResponseApdu(receiveBuffer, IsoCase.Case2Short, rfidReader.ActiveProtocol); Console.Write("SW1: {0:X2}, SW2: {1:X2}\nUid: {2}", responseApdu.SW1, responseApdu.SW2, responseApdu.HasData ? BitConverter.ToString(responseApdu.GetData()) : "No uid received"); rfidReader.EndTransaction(SCardReaderDisposition.Leave); rfidReader.Disconnect(SCardReaderDisposition.Reset); Console.ReadKey(); } } }
public object Clone() { CommandApdu cmdAPDU = new CommandApdu(isocase, proto); cmdAPDU.cla = cla; cmdAPDU.ins = ins; cmdAPDU.p1 = p1; cmdAPDU.p2 = p2; cmdAPDU.lc = lc; cmdAPDU.le = le; cmdAPDU.data = data; return cmdAPDU; }
private ResponseApdu IssueGetResponseCommand(CommandApdu commandApdu, ResponseApdu lastResponseApdu, Response response, SCardPCI receivePci) { /* The transmission system shall issue a GET RESPONSE command APDU (or TPDU) * to the card by assigning the minimum of SW2 and Le to parameter Le (or P3)). * Le = Le > 0 ? min(Le,SW2) : SW2 * http://www.cardwerk.com/smartcards/smartcard_standard_ISO7816-4_annex-a.aspx#AnnexA_4 */ var le = (commandApdu.Le > 0) && (commandApdu.Le < lastResponseApdu.SW2) ? commandApdu.Le : lastResponseApdu.SW2; var responseApdu = lastResponseApdu; do { // add the last ResponseAPDU to the Response object response.Add(responseApdu); response.Add(receivePci); var getResponseApdu = ConstructGetResponseApdu(ref le); // +2 bytes for status word var receiveBufferLength = le == 0 ? 256 + 2 : le + 2; var receiveBuffer = new byte[receiveBufferLength]; try { var sendBuffer = getResponseApdu.ToArray(); // Shall we wait until we re-send we APDU/TPDU? if (RetransmitWaitTime > 0) { Thread.Sleep(RetransmitWaitTime); } // send Command APDU again with new Le value responseApdu = SimpleTransmit( sendBuffer, sendBuffer.Length, getResponseApdu.Case, getResponseApdu.Protocol, receivePci, receiveBuffer, receiveBufferLength); } catch (WinErrorInsufficientBufferException ex) { throw new InvalidApduException($"GET RESPONSE command failed because of unsufficient buffer (Le={getResponseApdu.Le})", getResponseApdu, ex); } catch (InvalidOperationException ex) { throw new InvalidApduException( "Got SW1=0x61. Retransmission failed because of an invalid GET RESPONSE APDU.", getResponseApdu, ex); } // In case there is more data available. le = responseApdu.SW2; } while ( // More data available. responseApdu.SW1 == (byte)SW1Code.NormalDataResponse || // Warning condition: data may be corrupted. Iso7816-4 7.1.5 (responseApdu.SW1 == (byte)SW1Code.WarningNVDataNotChanged && responseApdu.SW2 == 0x81)); return(responseApdu); }
private bool LoadAuthenticationKey(SCardReader reader) { var apdu = new CommandApdu(IsoCase.Case3Short, reader.ActiveProtocol) { CLA = 0xFF, Instruction = InstructionCode.ExternalAuthenticate, P1 = 0x00, // key structure P2 = keyNumber, // key number Data = authentificationKey }; var responseApdu = SendAPDU(apdu, reader); if (responseApdu != null && responseApdu.SW1 == 0x90) { return true; } else { return false; } }
public bool UpdateBinary(int msb, int lsb, byte[] data) { unchecked { var updateBinaryCmd = new CommandApdu(IsoCase.Case3Short, SCardProtocol.Any) { CLA = 0xFF, Instruction = InstructionCode.UpdateBinary, P1 = (byte)msb, P2 = (byte)lsb, Data = data }; Debug.WriteLine(string.Format("Update Binary: {0}", BitConverter.ToString(updateBinaryCmd.ToArray()))); var response = _isoReader.Transmit(updateBinaryCmd); Debug.WriteLine(string.Format("SW1 SW2 = {0:X2} {1:X2}", response.SW1, response.SW2)); return Success(response); } }
/// <summary>Transmits the specified command APDU.</summary> /// <param name="commandApdu">The command APDU.</param> /// <returns>A response containing one ore more <see cref="ResponseApdu" />.</returns> public virtual Response Transmit(CommandApdu commandApdu) { if (commandApdu == null) { throw new ArgumentNullException(nameof(commandApdu)); } // prepare send buffer (Check Command APDU and convert it to an byte array) byte[] sendBuffer; try { sendBuffer = commandApdu.ToArray(); } catch (InvalidOperationException exception) { throw new InvalidApduException("Invalid APDU.", commandApdu, exception); } // prepare receive buffer (Response APDU) var receiveBufferLength = commandApdu.ExpectedResponseLength; // expected size that shall be returned var receiveBuffer = new byte[receiveBufferLength]; var receivePci = new SCardPCI(); ResponseApdu responseApdu; try { responseApdu = SimpleTransmit( sendBuffer, sendBuffer.Length, commandApdu.Case, // ISO case used by the Command APDU commandApdu.Protocol, // Protocol used by the Command APDU receivePci, receiveBuffer, receiveBufferLength); } catch (WinErrorInsufficientBufferException ex) { throw new InvalidApduException($"Unsufficient buffer: check Le size (Le={commandApdu.Le})", ex); } /* Check status word SW1SW2: * * 1. 0x6cxx -> Set response buffer size Le <- SW2 * 2. AND/OR 0x61xx -> More data can be read with GET RESPONSE */ if (responseApdu.SW1 == (byte)SW1Code.ErrorP3Incorrect) { // Case 1: SW1=0x6c, Previous Le/P3 not accepted -> Set le = SW2 responseApdu = RetransmitOnInsufficientBuffer(commandApdu, responseApdu, out receivePci); } // create Response object var response = new Response(); if (responseApdu.SW1 == (byte)SW1Code.NormalDataResponse) { // Case 2: SW1=0x61, More data available -> GET RESPONSE responseApdu = IssueGetResponseCommand(commandApdu, responseApdu, response, receivePci); } response.Add(responseApdu); response.Add(receivePci); return(response); }
static void Main(string[] args) { // Establish Smartcard context SCardContext ctx = new SCardContext(); ctx.Establish(SCardScope.System); string[] readernames = ctx.GetReaders(); if (readernames == null || readernames.Length < 1) throw new Exception("You need at least one reader in order to run this example."); // we will use the first reader for the transmit test. string readername = readernames[0]; SCardReader reader = new SCardReader(ctx); SCardError rc = reader.Connect( readername, SCardShareMode.Shared, SCardProtocol.Any); if (rc != SCardError.Success) { Console.WriteLine("Could not connect to card in reader " + readername + "\n" + "Error: " + SCardHelper.StringifyError(rc)); return; } // Build a GET CHALLENGE command CommandApdu apdu = new CommandApdu( IsoCase.Case2Short, reader.ActiveProtocol); apdu.CLA = 0x00; // Class apdu.INS = 0x84; // Instruction: GET CHALLENGE apdu.P1 = 0x00; // Parameter 1 apdu.P2 = 0x00; // Parameter 2 apdu.Le = 0x08; // Expected length of the returned data // convert the APDU object into an array of bytes byte[] cmd = apdu.ToArray(); // prepare a buffer for response APDU -> LE + 2 bytes (SW1 SW2) byte[] outbuf = new byte[apdu.ExpectedResponseLength]; rc = reader.Transmit( cmd, ref outbuf); if (rc == SCardError.Success) { Console.WriteLine("Ok."); if (outbuf != null) { ResponseApdu response = new ResponseApdu(outbuf, apdu.Case, apdu.Protocol); if (response.IsValid) { Console.WriteLine("SW1 SW2 = {0:X2} {1:X2}", response.SW1, response.SW2); if (response.HasData) { Console.Write("Data: "); for (int i = 0; i < (response.DataSize); i++) Console.Write("{0:X2} ", response.FullApdu[i]); Console.WriteLine(""); } } } } else { // Error Console.WriteLine(SCardHelper.StringifyError(rc)); } return; }
public byte[] GetCardId(IsoReader reader) { var command = new CommandApdu(IsoCase.Case2Short, SCardProtocol.Any) { CLA = 0xFF, Instruction = InstructionCode.GetData, P1 = 0x00, P2 = 0x00, Le = 0x00 }; var response = reader.Transmit(command); return response.GetData(); }
private byte[] ReadBinaryBlock(byte blockNumber, SCardReader reader) { if (!AuthenticateBlock(blockNumber, reader)) return new byte[0]; // TODO throw exception byte blockSize = 0x10; // all classic variants have 16 byte blocks var apdu = new CommandApdu(IsoCase.Case2Short, reader.ActiveProtocol) { CLA = 0xFF, Instruction = InstructionCode.ReadBinary, P1 = 0x00, P2 = blockNumber, // block number Le = blockSize // bytes to read }; var responseApdu = SendAPDU(apdu, reader); if (responseApdu != null && responseApdu.SW1 == 0x90) { return responseApdu.GetData().Take(16).ToArray(); // todo check size in debugging } else { return new byte[0]; } }
/// <summary>Transmits the specified command APDU.</summary> /// <param name="commandApdu">The command APDU.</param> /// <returns>A response containing one ore more <see cref="ResponseApdu" />.</returns> public virtual Response Transmit(CommandApdu commandApdu) { if (commandApdu == null) { throw new ArgumentNullException("commandApdu"); } // prepare send buffer (Check Command APDU and convert it to an byte array) byte[] sendBuffer; try { sendBuffer = commandApdu.ToArray(); } catch (InvalidOperationException exception) { throw new InvalidApduException("Invalid APDU.", commandApdu, exception); } // create Response object var response = new Response(); // prepare receive buffer (Response APDU) var receiveBufferLength = commandApdu.ExpectedResponseLength; // expected size that shall be returned var receiveBuffer = new byte[receiveBufferLength]; var receivePci = new SCardPCI(); var responseApdu = SimpleTransmit( sendBuffer, sendBuffer.Length, commandApdu.Case, // ISO case used by the Command APDU commandApdu.Protocol, // Protocol used by the Command APDU receivePci, ref receiveBuffer, ref receiveBufferLength); /* Check status word SW1SW2: * * 1. 0x6cxx -> Set response buffer size Le <- SW2 * 2. AND/OR 0x61xx -> More data can be read with GET RESPONSE */ if (responseApdu.SW1 == (byte)SW1Code.ErrorP3Incorrect) { // Case 1: SW1=0x6c, Previous Le/P3 not accepted -> Set le = SW2 var resendCmdApdu = (CommandApdu)commandApdu.Clone(); if (responseApdu.SW2 == 0) { resendCmdApdu.Le = 0; // 256 receiveBufferLength = 256 + 2; // 2 bytes for status word } else { resendCmdApdu.Le = responseApdu.SW2; receiveBufferLength = responseApdu.SW2 + 2; // 2 bytes for status word } receiveBuffer = new byte[receiveBufferLength]; receivePci = new SCardPCI(); try { sendBuffer = resendCmdApdu.ToArray(); // Shall we wait until we re-send we APDU/TPDU? if (RetransmitWaitTime > 0) { Thread.Sleep(RetransmitWaitTime); } // send Command APDU again with new Le value responseApdu = SimpleTransmit( sendBuffer, sendBuffer.Length, resendCmdApdu.Case, resendCmdApdu.Protocol, receivePci, ref receiveBuffer, ref receiveBufferLength); } catch (InvalidOperationException ex) { throw new InvalidApduException("Got SW1=0x6c. Retransmission failed because of an invalid APDU.", resendCmdApdu, ex); } } if (responseApdu.SW1 == (byte)SW1Code.NormalDataResponse) { // Case 2: SW1=0x61, More data available -> GET RESPONSE /* The transmission system shall issue a GET RESPONSE command APDU (or TPDU) * to the card by assigning the minimum of SW2 and Le to parameter Le (or P3)). * Le = min(Le,SW2) */ var le = (commandApdu.Le < responseApdu.SW2) ? commandApdu.Le : responseApdu.SW2; do { // add the last ResponseAPDU to the Response object response.Add(responseApdu); response.Add(receivePci); var getResponseApdu = ConstructGetResponseApdu(ref le); if (le == 0) { receiveBufferLength = 256 + 2; // 2 bytes for status word } else { receiveBufferLength = le + 2; // 2 bytes for status word } receiveBuffer = new byte[receiveBufferLength]; try { sendBuffer = getResponseApdu.ToArray(); // Shall we wait until we re-send we APDU/TPDU? if (RetransmitWaitTime > 0) { Thread.Sleep(RetransmitWaitTime); } // send Command APDU again with new Le value responseApdu = SimpleTransmit( sendBuffer, sendBuffer.Length, getResponseApdu.Case, getResponseApdu.Protocol, receivePci, ref receiveBuffer, ref receiveBufferLength); } catch (InvalidOperationException ex) { throw new InvalidApduException( "Got SW1=0x61. Retransmission failed because of an invalid GET RESPONSE APDU.", getResponseApdu, ex); } // In case there is more data available. le = responseApdu.SW2; } while ( // More data available. responseApdu.SW1 == (byte)SW1Code.NormalDataResponse || // Warning condition: data may be corrupted. Iso7816-4 7.1.5 (responseApdu.SW1 == (byte)SW1Code.WarningNVDataNotChanged && responseApdu.SW2 == 0x81)); } response.Add(responseApdu); response.Add(receivePci); return(response); }
private byte[] GetAllCardBytes(IsoReader reader, int packetSize) { try { var firstDataBlock = 16 / packetSize; var readSize = 16; var bytesToRead = 0; var buffer = new List<byte>(); while (true) { var blockToRead = (byte)(firstDataBlock + (buffer.Count / packetSize)); var readBinaryCmd = new CommandApdu(IsoCase.Case2Short, SCardProtocol.Any) { CLA = 0xFF, Instruction = InstructionCode.ReadBinary, P1 = 0x00, P2 = blockToRead, Le = readSize }; var response = reader.Transmit(readBinaryCmd); var data = response.GetData(); if (buffer.Count == 0) bytesToRead = data[1] + 1 + 1; buffer.AddRange(data.Take(bytesToRead - buffer.Count < readSize ? bytesToRead - buffer.Count : readSize).ToArray()); if (buffer.Count >= bytesToRead) break; } Log.Debug(String.Format("ReadBinary: {0}", BitConverter.ToString(buffer.ToArray()))); Log.Debug(String.Format("Buffersize: Reported: {0}, Actual: {1}", bytesToRead, buffer.Count)); return buffer.ToArray(); } catch (Exception ex) { Log.Error(ex); } return new byte[0]; }
/// <summary> /// Will try to connect to _connectedReader and read the card. /// </summary> /// <returns>Either the data from the card or the error message. Or if 'uidOnly' is true, just the UID prefixed with 'UID^' and ending with '^'</returns> public string ReadCard(bool uidOnly = false) { SCardContext context = new SCardContext(); context.Establish(SCardScope.System); SCardReader reader = new SCardReader(context); SCardError result = reader.Connect(_connectedReader, SCardShareMode.Shared, SCardProtocol.Any); if (result != SCardError.Success) { context.Dispose(); reader.Dispose(); return string.Format("No card is detected (or reader reserved by another application){0}{1}", Environment.NewLine, SCardHelper.StringifyError(result)); } string[] readerNames; SCardProtocol protocol; SCardState state; byte[] atr; result = reader.Status(out readerNames, out state, out protocol, out atr); if (result != SCardError.Success) { context.Dispose(); reader.Dispose(); return string.Format("Unable to read from card.{0}{1}", Environment.NewLine, SCardHelper.StringifyError(result)); } string message = string.Format("Card detected:{0}Protocol: {1}{0}State: {2}{0}ATR: {3}{0}", Environment.NewLine, protocol, state, BitConverter.ToString(atr ?? new byte[0])); CommandApdu apdu = new CommandApdu(IsoCase.Case2Short, reader.ActiveProtocol) { CLA = 0xFF, Instruction = InstructionCode.GetData, P1 = 0x00, P2 = 0x00, Le = 0 }; result = reader.BeginTransaction(); if (result != SCardError.Success) { context.Dispose(); reader.Dispose(); return string.Format("Cannot start transaction.{0} {1}", Environment.NewLine, SCardHelper.StringifyError(result)); } SCardPCI recievePci = new SCardPCI(); IntPtr sendPci = SCardPCI.GetPci(reader.ActiveProtocol); byte[] recieveBuffer = new byte[256]; result = reader.Transmit(sendPci, apdu.ToArray(), recievePci, ref recieveBuffer); if (result != SCardError.Success) { context.Dispose(); reader.Dispose(); return string.Format("Cannot transmit data.{0} {1}", Environment.NewLine, SCardHelper.StringifyError(result)); } var responseApdu = new ResponseApdu(recieveBuffer, IsoCase.Case2Short, reader.ActiveProtocol); message += string.Format("SW1: {1}{0}SW2: {2}{0}", Environment.NewLine, responseApdu.SW1, responseApdu.SW2); string data = responseApdu.HasData ? BitConverter.ToString(responseApdu.GetData()) : "--"; if (uidOnly) { context.Dispose(); reader.Dispose(); return string.Format("UID^{0}^", data); } message += string.Format("UID: {0}",data); reader.EndTransaction(SCardReaderDisposition.Leave); reader.Disconnect(SCardReaderDisposition.Reset); context.Dispose(); reader.Dispose(); return message; }
public string ReadSmartCard() { using (var context = new SCardContext()) { context.Establish(SCardScope.System); string readerName = null; try { string[] readerNames = context.GetReaders(); readerName = readerNames[0]; } catch(Exception ex) { return "error"; } if (readerName == null) { return "error"; } using (var rfidReader = new SCardReader(context)) { var sc = rfidReader.Connect(readerName, SCardShareMode.Shared, SCardProtocol.Any); if (sc != SCardError.Success) { return "error";//"Could not connect to reader {0}:\n{1}"; } var apdu = new CommandApdu(IsoCase.Case2Short, rfidReader.ActiveProtocol) { CLA = 0xFF, Instruction = InstructionCode.GetData, P1 = 0x00, P2 = 0x00, Le = 0 // We don't know the ID tag size }; sc = rfidReader.BeginTransaction(); if (sc != SCardError.Success) { return "none";// "Could not begin transaction."; } var receivePci = new SCardPCI(); // IO returned protocol control information. var sendPci = SCardPCI.GetPci(rfidReader.ActiveProtocol); var receiveBuffer = new byte[256]; var command = apdu.ToArray(); sc = rfidReader.Transmit( sendPci, // Protocol Control Information (T0, T1 or Raw) command, // command APDU receivePci, // returning Protocol Control Information ref receiveBuffer); // data buffer if (sc != SCardError.Success) { return "none";//SCardHelper.StringifyError(sc); } var responseApdu = new ResponseApdu(receiveBuffer, IsoCase.Case2Short, rfidReader.ActiveProtocol); rfidReader.EndTransaction(SCardReaderDisposition.Leave); rfidReader.Disconnect(SCardReaderDisposition.Reset); int id = responseApdu.HasData ? BitConverter.ToInt32(responseApdu.GetData(),0) : -1; //int id = responseApdu.HasData ? System.Text.Encoding.UTF8.GetString(responseApdu.GetData()) : "none"; if (id < 0) id = id * (-1); return id.ToString(); } } return "none"; }