Пример #1
4
        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];
            }
        }
Пример #2
1
        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;
        }
Пример #4
0
        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);
            }
        }
Пример #5
0
        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);
        }
Пример #6
0
        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];
            }
        }
Пример #7
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;
            }
        }
Пример #8
0
        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);
            }
        }
Пример #9
0
        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);
            }
        }
Пример #10
0
        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;
            }
        }
Пример #11
0
        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;
        }
Пример #12
0
        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();
                }
            }
        }
Пример #13
0
        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;
        }
Пример #14
0
        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);
        }
Пример #15
0
        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;
            }
        }
Пример #16
0
        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);
            }
        }
Пример #17
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(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);
        }
Пример #18
0
        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;

        }
Пример #19
0
        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();
        }
Пример #20
0
        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];
            }
        }
Пример #21
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);
        }
Пример #22
0
        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];
        }
Пример #23
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";
        }