예제 #1
0
        public bool SelectApplication()
        {
            System.Threading.Thread.Sleep(100);
            //dunno what the heck is this command
            APDUCommand  apduCmd = new APDUCommand(0, 0xa4, 1, 0, new byte[] { 1, 0x18 }, 0);
            APDUResponse apdu1   = iCard.Transmit(apduCmd);

            if (apdu1.SW1 != 0x90)
            {
                System.Threading.Thread.Sleep(100);
                apdu1 = iCard.Transmit(apduCmd);
                if (apdu1.SW1 != 0x90)
                {
                    return(false);
                }
            }

            System.Threading.Thread.Sleep(100);
            //dunno what the heck is this command, probably selecting something
            apduCmd = new APDUCommand(0, 0xa4, 2, 0, new byte[] { 0, 1 }, 0);
            apdu1   = iCard.Transmit(apduCmd);
            if (apdu1.SW1 != 0x90)
            {
                System.Threading.Thread.Sleep(100);
                apdu1 = iCard.Transmit(apduCmd);
                if (apdu1.SW1 != 0x90)
                {
                    return(false);
                }
            }
            System.Threading.Thread.Sleep(100);

            return(true);
        }
예제 #2
0
        public void ReadCard()
        {
            //get processing options
            ReadGPO();

            //read all possible data and extract needed  info
            foreach (SFIRecords sfir in sfiRecords)
            {
                byte p2 = (byte)((sfir.sfi << 3) | 4);
                foreach (byte p1 in sfir.records)
                {
                    //read each record
                    APDUCommand  apduReadRecord = new APDUCommand(0x00, 0xB2, p1, p2, null, 0);
                    APDUResponse apduR          = this.cardUpdater.Transmit(apduReadRecord);
                    if (apduR.SW1 == 0x90)
                    {
                        if (apduR.Data[0] == 0x70 || apduR.Data[0] == 0x77)
                        {
                            ExtractData(ReadTagData(apduR.Data, 0));
                            //if (!String.IsNullOrEmpty(NumberString) && !String.IsNullOrEmpty(Name) &&
                            //    !String.IsNullOrEmpty(ExpiryString) && !String.IsNullOrEmpty(CardType) &&
                            //    !String.IsNullOrEmpty(Label))
                            //    return;  //we have all info we need
                        }
                        else
                        {
                            throw new Exception("Unrecognized data template");
                        }
                    }
                }
            }
        }
예제 #3
0
        public bool SelectApplication()
        {
            APDUCommand  apduSelectPxyApl = new APDUCommand(0x00, 0xA4, 4, 0, m_JPNAID, 0);
            APDUResponse apdu1            = this.cardUpdater.Transmit(apduSelectPxyApl);

            byte[] apduRespByte = apdu1.Packet;
            return(checkExchangeApduResult(apduRespByte));
        }
예제 #4
0
        private void ReadGPO()
        {
            //get processing options
            APDUCommand  apduGPO = new APDUCommand(0x80, 0xa8, 0, 0, new byte[] { 0x83, 0 }, 0);
            APDUResponse apdu1   = this.cardUpdater.Transmit(apduGPO);

            if (apdu1.SW1 != 0x90)
            {
                throw new Exception("Read GPO Data fail");
            }
            //two possible forms, 0x80 and 0x77
            if (apdu1.Data[0] == 0x80)
            {
                for (int i = 4; i < apdu1.Data.Length; i += 4)
                {
                    byte   sfi      = (byte)((apdu1.Data[i] >> 3) & 0xf);
                    byte   lowRange = apdu1.Data[i + 1];
                    byte   hiRange  = apdu1.Data[i + 2];
                    byte[] records  = new byte[hiRange - lowRange + 1];
                    for (int j = lowRange; j <= hiRange; j++)
                    {
                        records[j - lowRange] = (byte)j;
                    }
                    sfiRecords.Add(new SFIRecords(sfi, records));
                }
            }
            else if (apdu1.Data[0] == 0x77)
            {
                //look for the application file locator AFL
                int a, tag;
                for (a = 2; (tag = ReadTag(apdu1.Data, a)) != 0x94; a = SkipTag(apdu1.Data, a))
                {
                    ;
                }
                if (tag == 0x94)
                {
                    //found it
                    a++;
                    int len = apdu1.Data[a++];
                    for (int i = a; i < a + len; i += 4)
                    {
                        byte   sfi      = (byte)((apdu1.Data[i] >> 3) & 0xf);
                        byte   lowRange = apdu1.Data[i + 1];
                        byte   hiRange  = apdu1.Data[i + 2];
                        byte[] records  = new byte[hiRange - lowRange + 1];
                        for (int j = lowRange; j <= hiRange; j++)
                        {
                            records[j - lowRange] = (byte)j;
                        }
                        sfiRecords.Add(new SFIRecords(sfi, records));
                    }
                }
            }
            else
            {
                throw new Exception("Unknown GPO template");
            }
        }
예제 #5
0
        public bool SelectApplication()
        {
            //select the PSE application
            APDUCommand  apduSelectPSEApl = new APDUCommand(0x00, 0xA4, 4, 0, m_PSEAID, 0);
            APDUResponse apduPSE          = this.cardUpdater.Transmit(apduSelectPSEApl);

            if (apduPSE.SW1 == 0x90)    //PSE supported
            {
                //send the Read Record command, record 1, SFI 1
                //P2 format:  MSB                  LSB
                //            7   6   5   4   3   2   1   0
                //            SFI SFI SFI SFI SFI 1   0   0
                //1 0 0 in the LSB bits means that P1 is a record number
                APDUCommand  apduReadRecord = new APDUCommand(0x00, 0xB2, 1, 0xc, null, 0);
                APDUResponse apdu1          = this.cardUpdater.Transmit(apduReadRecord);
                if (apdu1.SW1 == 0x90)
                {
                    m_EMVAID = new byte[apdu1.Data[5]];
                    Array.Copy(apdu1.Data, 6, m_EMVAID, 0, m_EMVAID.Length);

                    APDUCommand  apduSelectEMVApl = new APDUCommand(0x00, 0xA4, 4, 0, m_EMVAID, 0);
                    APDUResponse apdu2            = this.cardUpdater.Transmit(apduSelectEMVApl);
                    if (apdu2.SW1 == 0x90)
                    {
                        //Label = ASCIIEncoding.ASCII.GetString(apdu2.Data, 15, apdu2.Data[14]);
                        if (apdu2.Data[0] == 0x6f)  //fci template
                        {
                            ExtractData(ReadTagData(apdu2.Data, 0));
                        }
                        return(true);
                    }
                }
            }

            //PSE unsupported, need to try AID list
            foreach (byte[] aid in aidList)
            {
                APDUCommand  apduSelectEMVApl = new APDUCommand(0x00, 0xA4, 4, 0, aid, 0);
                APDUResponse apdu2            = this.cardUpdater.Transmit(apduSelectEMVApl);
                if (apdu2.SW1 == 0x90)
                {
                    //Label = ASCIIEncoding.ASCII.GetString(apdu2.Data, 15, apdu2.Data[14]);
                    //found it!
                    m_EMVAID = aid;
                    if (apdu2.Data[0] == 0x6f)  //fci template
                    {
                        ExtractData(ReadTagData(apdu2.Data, 0));
                    }
                    return(true);
                }
            }

            return(false);
        }
예제 #6
0
        private void SetLength(short len)
        {
            byte[] paramBytes = new byte[] { 8, 0, 0, 0, 0 };
            byte[] lenBytes   = BitConverter.GetBytes(len);
            Array.Copy(lenBytes, 0, paramBytes, 3, 2);
            APDUCommand  setLengthAPdu = new APDUCommand(0xc8, 0x32, 0, 0, paramBytes, 0);
            APDUResponse apdu1         = this.cardUpdater.Transmit(setLengthAPdu);

            if (apdu1.SW1 != 0x91 || apdu1.SW2 != 8)
            {
                throw new Exception("Failed to read");
            }
            ;
        }
예제 #7
0
        private byte[] ReadInfo(short len)
        {
            MemoryStream ms = new MemoryStream();

            while (len > 0)
            {
                byte         readLen      = (byte)(len < 255 ? len : 255);
                APDUCommand  readInfoApdu = new APDUCommand(0xcc, 6, 0, 0, null, readLen);
                APDUResponse apdu1        = this.cardUpdater.Transmit(readInfoApdu);
                if (apdu1.SW1 != 0x94 && apdu1.SW1 != 0x90)
                {
                    throw new Exception("Failed to read");
                }
                ;
                len -= readLen;
                ms.Write(apdu1.Data, 0, apdu1.Data.Length);
            }
            return(ms.ToArray());
        }
예제 #8
0
        private void SelectInfo(short filen1, short filen2, short offset, short len)
        {
            byte[] paramBytes  = new byte[8];
            byte[] n1Bytes     = BitConverter.GetBytes(filen1);
            byte[] n2Bytes     = BitConverter.GetBytes(filen2);
            byte[] offsetBytes = BitConverter.GetBytes(offset);
            byte[] lenBytes    = BitConverter.GetBytes(len);
            Array.Copy(n2Bytes, 0, paramBytes, 0, 2);
            Array.Copy(n1Bytes, 0, paramBytes, 2, 2);
            Array.Copy(offsetBytes, 0, paramBytes, 4, 2);
            Array.Copy(lenBytes, 0, paramBytes, 6, 2);
            APDUCommand  setLengthAPdu = new APDUCommand(0xcc, 0, 0, 0, paramBytes, 0);
            APDUResponse apdu1         = this.cardUpdater.Transmit(setLengthAPdu);

            if (apdu1.SW1 != 0x94)
            {
                throw new Exception("Failed to read");
            }
            ;
        }
예제 #9
0
        public void ReadCard()
        {
            //get processing options
            ReadGPO();

            //read all possible data and extract needed  info
            foreach (SFIRecords sfir in sfiRecords)
            {
                byte p2 = (byte)((sfir.sfi << 3) | 4);
                foreach (byte p1 in sfir.records)
                {
                    //read each record
                    APDUCommand apduReadRecord = new APDUCommand(0x00, 0xB2, p1, p2, null, 0);
                    APDUResponse apduR = this.cardUpdater.Transmit(apduReadRecord);
                    if (apduR.SW1 == 0x90)
                    {
                        if (apduR.Data[0] == 0x70 || apduR.Data[0] == 0x77)
                        {
                            ExtractData(ReadTagData(apduR.Data, 0));
                            //if (!String.IsNullOrEmpty(NumberString) && !String.IsNullOrEmpty(Name) &&
                            //    !String.IsNullOrEmpty(ExpiryString) && !String.IsNullOrEmpty(CardType) &&
                            //    !String.IsNullOrEmpty(Label))
                            //    return;  //we have all info we need
                        }
                        else
                            throw new Exception("Unrecognized data template");
                    }
                }
            }
        }
예제 #10
0
        /// <summary>
        /// Wraps the PCSC function
        /// LONG SCardTransmit(
        ///		SCARDHANDLE hCard,
        ///		LPCSCARD_I0_REQUEST pioSendPci,
        ///		LPCBYTE pbSendBuffer,
        ///		DWORD cbSendLength,
        ///		LPSCARD_IO_REQUEST pioRecvPci,
        ///		LPBYTE pbRecvBuffer,
        ///		LPDWORD pcbRecvLength
        ///	);
        /// </summary>
        /// <param name="ApduCmd">APDUCommand object with the APDU to send to the card</param>
        /// <returns>An APDUResponse object with the response from the card</returns>
        public override APDUResponse Transmit(APDUCommand ApduCmd)
        {
            uint	RecvLength = (uint) (ApduCmd.Le + APDUResponse.SW_LENGTH);
            byte[]	ApduBuffer = null;
            byte[] ApduResponse = new byte[RecvLength];
            SCard_IO_Request	ioRequest = new SCard_IO_Request();
            ioRequest.m_dwProtocol = m_nProtocol;
            ioRequest.m_cbPciLength = 8;
            SCard_IO_Request ioResponse = new SCard_IO_Request();
            ioResponse.m_dwProtocol = m_nProtocol;
            ioResponse.m_cbPciLength = 8;

            // Build the command APDU
            if (ApduCmd.Data == null)
            {
                ApduBuffer = new byte[APDUCommand.APDU_MIN_LENGTH + ((ApduCmd.Le != 0) ? 1 : 0)];

                if (ApduCmd.Le != 0)
                    ApduBuffer[4] = (byte) ApduCmd.Le;
            }
            else
            {
                ApduBuffer = new byte[APDUCommand.APDU_MIN_LENGTH + 1 + ApduCmd.Data.Length + ((ApduCmd.Le != 0) ? 1 : 0)];

                for (int nI = 0; nI < ApduCmd.Data.Length; nI++)
                    ApduBuffer[APDUCommand.APDU_MIN_LENGTH + 1 + nI] = ApduCmd.Data[nI];

                ApduBuffer[APDUCommand.APDU_MIN_LENGTH] = (byte) ApduCmd.Data.Length;

                if (ApduCmd.Le != 0)
                    ApduBuffer[ApduBuffer.Length - 1] = (byte)ApduCmd.Le;
            }

            ApduBuffer[0] = ApduCmd.Class;
            ApduBuffer[1] = ApduCmd.Ins;
            ApduBuffer[2] = ApduCmd.P1;
            ApduBuffer[3] = ApduCmd.P2;

            m_nLastError = SCardTransmit(m_hCard, ref ioRequest, ApduBuffer, (uint) ApduBuffer.Length, ref ioResponse, ApduResponse, ref RecvLength);
            if (m_nLastError != 0)
            {
                string msg = "SCardTransmit error: " + m_nLastError;
                throw new Exception(msg);
            }
            int sw1 = ApduResponse[ApduResponse.Length - 2] & 0xff;
            int sw2 = ApduResponse[ApduResponse.Length - 1] & 0xff;

            if (sw1 == 0x6c) //wrong length, read again with correct len
            {
                ApduBuffer = new byte[] { ApduCmd.Class, ApduCmd.Ins, ApduCmd.P1, ApduCmd.P2, (byte)sw2 };
                ApduResponse = new byte[sw2 + APDUResponse.SW_LENGTH];
                RecvLength = (uint)ApduResponse.Length;
                m_nLastError = SCardTransmit(m_hCard, ref ioRequest, ApduBuffer, (uint)ApduBuffer.Length, ref ioResponse, ApduResponse, ref RecvLength);
                if (m_nLastError != 0)
                {
                    string msg = "SCardTransmit error: " + m_nLastError;
                    throw new Exception(msg);
                }
                sw1 = ApduResponse[ApduResponse.Length - 2] & 0xff;
                sw2 = ApduResponse[ApduResponse.Length - 1] & 0xff;
            }

            MemoryStream ms = new MemoryStream();
            ms.Write(ApduResponse, 0, ApduResponse.Length - APDUResponse.SW_LENGTH);

            //while has remaining bytes to be read
            while (sw1 == 0x61)
            {
                ApduBuffer = new byte[] { 0, 0xc0, 0, 0, (byte)sw2 }; //read sw2 number of bytes
                ApduResponse = new byte[sw2 + APDUResponse.SW_LENGTH];
                RecvLength = (uint)ApduResponse.Length;
                m_nLastError = SCardTransmit(m_hCard, ref ioRequest, ApduBuffer, (uint)ApduBuffer.Length, ref ioResponse, ApduResponse, ref RecvLength);
                if (m_nLastError != 0)
                {
                    string msg = "SCardTransmit error: " + m_nLastError;
                    throw new Exception(msg);
                }
                sw1 = ApduResponse[ApduResponse.Length - 2] & 0xff;
                sw2 = ApduResponse[ApduResponse.Length - 1] & 0xff;
                if (ApduResponse.Length > APDUResponse.SW_LENGTH)
                {
                    ms.Write(ApduResponse, 0, ApduResponse.Length - APDUResponse.SW_LENGTH);
                }
            }
            ms.WriteByte((byte)sw1);
            ms.WriteByte((byte)sw2);

            return new APDUResponse(ms.ToArray());
        }
예제 #11
0
        public bool SelectApplication()
        {
            //select the PSE application
            APDUCommand apduSelectPSEApl = new APDUCommand(0x00, 0xA4, 4, 0, m_PSEAID, 0);
            APDUResponse apduPSE = this.cardUpdater.Transmit(apduSelectPSEApl);
            if (apduPSE.SW1 == 0x90)    //PSE supported
            {
                //send the Read Record command, record 1, SFI 1
                //P2 format:  MSB                  LSB
                //            7   6   5   4   3   2   1   0
                //            SFI SFI SFI SFI SFI 1   0   0
                //1 0 0 in the LSB bits means that P1 is a record number
                APDUCommand apduReadRecord = new APDUCommand(0x00, 0xB2, 1, 0xc, null, 0);
                APDUResponse apdu1 = this.cardUpdater.Transmit(apduReadRecord);
                if (apdu1.SW1 == 0x90)
                {
                    m_EMVAID = new byte[apdu1.Data[5]];
                    Array.Copy(apdu1.Data, 6, m_EMVAID, 0, m_EMVAID.Length);

                    APDUCommand apduSelectEMVApl = new APDUCommand(0x00, 0xA4, 4, 0, m_EMVAID, 0);
                    APDUResponse apdu2 = this.cardUpdater.Transmit(apduSelectEMVApl);
                    if (apdu2.SW1 == 0x90)
                    {
                        //Label = ASCIIEncoding.ASCII.GetString(apdu2.Data, 15, apdu2.Data[14]);
                        if (apdu2.Data[0] == 0x6f)  //fci template
                        {
                            ExtractData(ReadTagData(apdu2.Data, 0));
                        }
                        return true;
                    }
                }
            }

            //PSE unsupported, need to try AID list
            foreach (byte[] aid in aidList)
            {
                APDUCommand apduSelectEMVApl = new APDUCommand(0x00, 0xA4, 4, 0, aid, 0);
                APDUResponse apdu2 = this.cardUpdater.Transmit(apduSelectEMVApl);
                if (apdu2.SW1 == 0x90)
                {
                    //Label = ASCIIEncoding.ASCII.GetString(apdu2.Data, 15, apdu2.Data[14]);
                    //found it!
                    m_EMVAID = aid;
                    if (apdu2.Data[0] == 0x6f)  //fci template
                    {
                        ExtractData(ReadTagData(apdu2.Data, 0));
                    }
                    return true;
                }
            }

            return false;
        }
예제 #12
0
 private void ReadGPO()
 {
     //get processing options
     APDUCommand apduGPO = new APDUCommand(0x80, 0xa8, 0, 0, new byte[] { 0x83, 0 }, 0);
     APDUResponse apdu1 = this.cardUpdater.Transmit(apduGPO);
     if (apdu1.SW1 != 0x90) throw new Exception("Read GPO Data fail");
     //two possible forms, 0x80 and 0x77
     if (apdu1.Data[0] == 0x80)
     {
         for (int i = 4; i < apdu1.Data.Length; i += 4)
         {
             byte sfi = (byte)((apdu1.Data[i] >> 3) & 0xf);
             byte lowRange = apdu1.Data[i + 1];
             byte hiRange = apdu1.Data[i + 2];
             byte[] records = new byte[hiRange - lowRange + 1];
             for (int j = lowRange; j <= hiRange; j++)
                 records[j - lowRange] = (byte)j;
             sfiRecords.Add(new SFIRecords(sfi, records));
         }
     }
     else if (apdu1.Data[0] == 0x77)
     {
         //look for the application file locator AFL
         int a, tag;
         for (a = 2; (tag = ReadTag(apdu1.Data, a)) != 0x94; a = SkipTag(apdu1.Data, a)) ;
         if (tag == 0x94)
         {
             //found it
             a++;
             int len = apdu1.Data[a++];
             for (int i = a; i < a + len; i += 4)
             {
                 byte sfi = (byte)((apdu1.Data[i] >> 3) & 0xf);
                 byte lowRange = apdu1.Data[i + 1];
                 byte hiRange = apdu1.Data[i + 2];
                 byte[] records = new byte[hiRange - lowRange + 1];
                 for (int j = lowRange; j <= hiRange; j++)
                     records[j - lowRange] = (byte)j;
                 sfiRecords.Add(new SFIRecords(sfi, records));
             }
         }
     }
     else
         throw new Exception("Unknown GPO template");
 }
예제 #13
0
        public bool SelectApplication()
        {
            System.Threading.Thread.Sleep(100);
            //dunno what the heck is this command
            APDUCommand apduCmd = new APDUCommand(0, 0xa4, 1, 0, new byte[]{1,0x18}, 0);
            APDUResponse apdu1 = iCard.Transmit(apduCmd);
            if (apdu1.SW1 != 0x90)
            {
                System.Threading.Thread.Sleep(100);
                apdu1 = iCard.Transmit(apduCmd);
                if (apdu1.SW1 != 0x90)
                    return false;
            }

            System.Threading.Thread.Sleep(100);
            //dunno what the heck is this command, probably selecting something
            apduCmd = new APDUCommand(0, 0xa4, 2, 0, new byte[] { 0, 1 }, 0);
            apdu1 = iCard.Transmit(apduCmd);
            if (apdu1.SW1 != 0x90)
            {
                System.Threading.Thread.Sleep(100);
                apdu1 = iCard.Transmit(apduCmd);
                if (apdu1.SW1 != 0x90)
                    return false;
            }
            System.Threading.Thread.Sleep(100);

            return true;
        }
예제 #14
0
        public void ReadCard()
        {
            //read balance   80 32 00 03 04 00 00 00 00
            //received:                                     Deposit(BCD)
            //                                              vvvvv
            // 05 11 11 25 02 03 12 15 37 20 00 25 09 08 60 00 00 0A 00 18 00 00 00 00 90 00
            //    ^^^^^^^^^^^^^^^^^^^^^^^          ^^^^^ ^^
            //            CAN                issue date  months of validity
            //                               2009/08     60 mths

            APDUCommand apduCmd = new APDUCommand(0x80, 0x32, 0, 3, new byte[4], 0);
            APDUResponse apdu1 = iCard.Transmit(apduCmd);
            byte[] balanceBytes = new byte[4];
            balanceBytes[0] = apdu1.Data[3];
            balanceBytes[1] = apdu1.Data[2];
            balanceBytes[2] = apdu1.Data[1];
            balanceBytes[3] = apdu1.Data[0];
            //balance is in cents. divide by 100 to get dollars
            Balance = BitConverter.ToInt32(balanceBytes, 0) / 100.0f;

            //dunno what the heck is this command, probably selecting something
            apduCmd = new APDUCommand(0, 0xa4, 2, 0, new byte[] { 0, 1 }, 0);
            apdu1 = iCard.Transmit(apduCmd);

            //read CAN, expiry date, deposit 00 B0 00 00 18
            apduCmd = new APDUCommand(0x00, 0xb0, 0, 0, null, 0x18);
            apdu1 = iCard.Transmit(apduCmd);
            //card number (CAN)
            Number = ConvertBCDCardNumber(apdu1.Data, 1, 8);
            //get the string form XXXX-XXXX-XXXX-XXXX
            StringBuilder sb = new StringBuilder();
            sb.Append(ConvertBCDCardNumber(apdu1.Data, 1, 2).ToString("D4"));
            sb.Append("-");
            sb.Append(ConvertBCDCardNumber(apdu1.Data, 3, 2).ToString("D4"));
            sb.Append("-");
            sb.Append(ConvertBCDCardNumber(apdu1.Data, 5, 2).ToString("D4"));
            sb.Append("-");
            sb.Append(ConvertBCDCardNumber(apdu1.Data, 7, 2).ToString("D4"));
            NumberString = sb.ToString();
            //read expiry date
            int year = apdu1.Data[12]; //year, from 1900 or 2000
            if (year > 90 && year < 100)
                year += 1900;
            else year += 2000;
            byte month = apdu1.Data[13];
            byte validity = (byte)ConvertBCDCardNumber(apdu1.Data, 14, 1); //validity in months
            DateTime issueDate = new DateTime(year, month, 1);
            Expiry = issueDate.AddMonths(validity);
            ExpiryString = Expiry.ToString("dd MMM yyyy");
            Deposit = ConvertBCDCardNumber(apdu1.Data, 15, 2) / 100.0f;

            //get transaction log
            //read number of total entries in log
            apduCmd = new APDUCommand(0, 0xb0, 0, 2, null, 4);
            apdu1 = iCard.Transmit(apduCmd);
            if (apdu1.SW1 != 0x90) throw new Exception("Read NETS log size fail");
            short logSize = (short)ConvertBCDCardNumber(new byte[]{apdu1.Data[2], apdu1.Data[3]}, 0, 2);

            apduCmd = new APDUCommand(0, 0xa4, 2, 0, new byte[] { 0, 5 }, 0);
            apdu1 = iCard.Transmit(apduCmd);
            if (apdu1.SW1 != 0x90) throw new Exception("Read NETS transaction fail");

            //read the current log entry number
            short endOffs = (short)(logSize * 4);
            byte endP1 = (byte)((endOffs >> 8) & 0xff);
            byte endP2 = (byte)(endOffs & 0xff);
            apduCmd = new APDUCommand(0, 0xb0, endP1, endP2, null, 2);
            apdu1 = iCard.Transmit(apduCmd);
            if (apdu1.SW1 != 0x90) throw new Exception("Read NETS current log number fail");
            short currentLogNum = (short)ConvertBCDCardNumber(new byte[] { apdu1.Data[0], apdu1.Data[1] }, 0, 2);
            currentLogNum -= 2;

            //read each log entry from the ring buffer, starting from current
            for (byte n = 0; n < logSize; n++)
            {
                int i = currentLogNum - n;
                if (i < 0) i += logSize;
                short logOffs = (short)(i * 4);
                byte logP1 = (byte)((logOffs >> 8) & 0xff);
                byte logP2 = (byte)(logOffs & 0xff);
                //read binary 0xb0, offset logOffs, size 16
                apduCmd = new APDUCommand(0, 0xb0, logP1, logP2, null, 16);
                apdu1 = iCard.Transmit(apduCmd);
                if (apdu1.SW1 != 0x90) throw new Exception("Read NETS log entry fail");
                NETSTransaction logEntry = new NETSTransaction(apdu1.Data);
                if (logEntry.Type != 0)
                    TransactionLog.Add(logEntry);
            }
        }
예제 #15
0
        public void ReadCard()
        {
            //read balance   80 32 00 03 04 00 00 00 00
            //received:                                     Deposit(BCD)
            //                                              vvvvv
            // 05 11 11 25 02 03 12 15 37 20 00 25 09 08 60 00 00 0A 00 18 00 00 00 00 90 00
            //    ^^^^^^^^^^^^^^^^^^^^^^^          ^^^^^ ^^
            //            CAN                issue date  months of validity
            //                               2009/08     60 mths

            APDUCommand  apduCmd = new APDUCommand(0x80, 0x32, 0, 3, new byte[4], 0);
            APDUResponse apdu1   = iCard.Transmit(apduCmd);

            byte[] balanceBytes = new byte[4];
            balanceBytes[0] = apdu1.Data[3];
            balanceBytes[1] = apdu1.Data[2];
            balanceBytes[2] = apdu1.Data[1];
            balanceBytes[3] = apdu1.Data[0];
            //balance is in cents. divide by 100 to get dollars
            Balance = BitConverter.ToInt32(balanceBytes, 0) / 100.0f;

            //dunno what the heck is this command, probably selecting something
            apduCmd = new APDUCommand(0, 0xa4, 2, 0, new byte[] { 0, 1 }, 0);
            apdu1   = iCard.Transmit(apduCmd);

            //read CAN, expiry date, deposit 00 B0 00 00 18
            apduCmd = new APDUCommand(0x00, 0xb0, 0, 0, null, 0x18);
            apdu1   = iCard.Transmit(apduCmd);
            //card number (CAN)
            Number = ConvertBCDCardNumber(apdu1.Data, 1, 8);
            //get the string form XXXX-XXXX-XXXX-XXXX
            StringBuilder sb = new StringBuilder();

            sb.Append(ConvertBCDCardNumber(apdu1.Data, 1, 2).ToString("D4"));
            sb.Append("-");
            sb.Append(ConvertBCDCardNumber(apdu1.Data, 3, 2).ToString("D4"));
            sb.Append("-");
            sb.Append(ConvertBCDCardNumber(apdu1.Data, 5, 2).ToString("D4"));
            sb.Append("-");
            sb.Append(ConvertBCDCardNumber(apdu1.Data, 7, 2).ToString("D4"));
            NumberString = sb.ToString();
            //read expiry date
            int year = apdu1.Data[12]; //year, from 1900 or 2000

            if (year > 90 && year < 100)
            {
                year += 1900;
            }
            else
            {
                year += 2000;
            }
            byte     month     = apdu1.Data[13];
            byte     validity  = (byte)ConvertBCDCardNumber(apdu1.Data, 14, 1); //validity in months
            DateTime issueDate = new DateTime(year, month, 1);

            Expiry       = issueDate.AddMonths(validity);
            ExpiryString = Expiry.ToString("dd MMM yyyy");
            Deposit      = ConvertBCDCardNumber(apdu1.Data, 15, 2) / 100.0f;

            //get transaction log
            //read number of total entries in log
            apduCmd = new APDUCommand(0, 0xb0, 0, 2, null, 4);
            apdu1   = iCard.Transmit(apduCmd);
            if (apdu1.SW1 != 0x90)
            {
                throw new Exception("Read NETS log size fail");
            }
            short logSize = (short)ConvertBCDCardNumber(new byte[] { apdu1.Data[2], apdu1.Data[3] }, 0, 2);

            apduCmd = new APDUCommand(0, 0xa4, 2, 0, new byte[] { 0, 5 }, 0);
            apdu1   = iCard.Transmit(apduCmd);
            if (apdu1.SW1 != 0x90)
            {
                throw new Exception("Read NETS transaction fail");
            }

            //read the current log entry number
            short endOffs = (short)(logSize * 4);
            byte  endP1   = (byte)((endOffs >> 8) & 0xff);
            byte  endP2   = (byte)(endOffs & 0xff);

            apduCmd = new APDUCommand(0, 0xb0, endP1, endP2, null, 2);
            apdu1   = iCard.Transmit(apduCmd);
            if (apdu1.SW1 != 0x90)
            {
                throw new Exception("Read NETS current log number fail");
            }
            short currentLogNum = (short)ConvertBCDCardNumber(new byte[] { apdu1.Data[0], apdu1.Data[1] }, 0, 2);

            currentLogNum -= 2;

            //read each log entry from the ring buffer, starting from current
            for (byte n = 0; n < logSize; n++)
            {
                int i = currentLogNum - n;
                if (i < 0)
                {
                    i += logSize;
                }
                short logOffs = (short)(i * 4);
                byte  logP1   = (byte)((logOffs >> 8) & 0xff);
                byte  logP2   = (byte)(logOffs & 0xff);
                //read binary 0xb0, offset logOffs, size 16
                apduCmd = new APDUCommand(0, 0xb0, logP1, logP2, null, 16);
                apdu1   = iCard.Transmit(apduCmd);
                if (apdu1.SW1 != 0x90)
                {
                    throw new Exception("Read NETS log entry fail");
                }
                NETSTransaction logEntry = new NETSTransaction(apdu1.Data);
                if (logEntry.Type != 0)
                {
                    TransactionLog.Add(logEntry);
                }
            }
        }
예제 #16
0
        /// <summary>
        /// Wraps the PCSC function
        /// LONG SCardTransmit(
        ///		SCARDHANDLE hCard,
        ///		LPCSCARD_I0_REQUEST pioSendPci,
        ///		LPCBYTE pbSendBuffer,
        ///		DWORD cbSendLength,
        ///		LPSCARD_IO_REQUEST pioRecvPci,
        ///		LPBYTE pbRecvBuffer,
        ///		LPDWORD pcbRecvLength
        ///	);
        /// </summary>
        /// <param name="ApduCmd">APDUCommand object with the APDU to send to the card</param>
        /// <returns>An APDUResponse object with the response from the card</returns>
        public override APDUResponse Transmit(APDUCommand ApduCmd)
        {
            uint RecvLength = (uint)(ApduCmd.Le + APDUResponse.SW_LENGTH);

            byte[]           ApduBuffer   = null;
            byte[]           ApduResponse = new byte[RecvLength];
            SCard_IO_Request ioRequest    = new SCard_IO_Request();

            ioRequest.m_dwProtocol  = m_nProtocol;
            ioRequest.m_cbPciLength = 8;
            SCard_IO_Request ioResponse = new SCard_IO_Request();

            ioResponse.m_dwProtocol  = m_nProtocol;
            ioResponse.m_cbPciLength = 8;

            // Build the command APDU
            if (ApduCmd.Data == null)
            {
                ApduBuffer = new byte[APDUCommand.APDU_MIN_LENGTH + ((ApduCmd.Le != 0) ? 1 : 0)];

                if (ApduCmd.Le != 0)
                {
                    ApduBuffer[4] = (byte)ApduCmd.Le;
                }
            }
            else
            {
                ApduBuffer = new byte[APDUCommand.APDU_MIN_LENGTH + 1 + ApduCmd.Data.Length + ((ApduCmd.Le != 0) ? 1 : 0)];

                for (int nI = 0; nI < ApduCmd.Data.Length; nI++)
                {
                    ApduBuffer[APDUCommand.APDU_MIN_LENGTH + 1 + nI] = ApduCmd.Data[nI];
                }

                ApduBuffer[APDUCommand.APDU_MIN_LENGTH] = (byte)ApduCmd.Data.Length;

                if (ApduCmd.Le != 0)
                {
                    ApduBuffer[ApduBuffer.Length - 1] = (byte)ApduCmd.Le;
                }
            }

            ApduBuffer[0] = ApduCmd.Class;
            ApduBuffer[1] = ApduCmd.Ins;
            ApduBuffer[2] = ApduCmd.P1;
            ApduBuffer[3] = ApduCmd.P2;

            m_nLastError = SCardTransmit(m_hCard, ref ioRequest, ApduBuffer, (uint)ApduBuffer.Length, ref ioResponse, ApduResponse, ref RecvLength);
            if (m_nLastError != 0)
            {
                string msg = "SCardTransmit error: " + m_nLastError;
                throw new Exception(msg);
            }
            int sw1 = ApduResponse[ApduResponse.Length - 2] & 0xff;
            int sw2 = ApduResponse[ApduResponse.Length - 1] & 0xff;

            if (sw1 == 0x6c) //wrong length, read again with correct len
            {
                ApduBuffer   = new byte[] { ApduCmd.Class, ApduCmd.Ins, ApduCmd.P1, ApduCmd.P2, (byte)sw2 };
                ApduResponse = new byte[sw2 + APDUResponse.SW_LENGTH];
                RecvLength   = (uint)ApduResponse.Length;
                m_nLastError = SCardTransmit(m_hCard, ref ioRequest, ApduBuffer, (uint)ApduBuffer.Length, ref ioResponse, ApduResponse, ref RecvLength);
                if (m_nLastError != 0)
                {
                    string msg = "SCardTransmit error: " + m_nLastError;
                    throw new Exception(msg);
                }
                sw1 = ApduResponse[ApduResponse.Length - 2] & 0xff;
                sw2 = ApduResponse[ApduResponse.Length - 1] & 0xff;
            }

            MemoryStream ms = new MemoryStream();

            ms.Write(ApduResponse, 0, ApduResponse.Length - APDUResponse.SW_LENGTH);

            //while has remaining bytes to be read
            while (sw1 == 0x61)
            {
                ApduBuffer   = new byte[] { 0, 0xc0, 0, 0, (byte)sw2 }; //read sw2 number of bytes
                ApduResponse = new byte[sw2 + APDUResponse.SW_LENGTH];
                RecvLength   = (uint)ApduResponse.Length;
                m_nLastError = SCardTransmit(m_hCard, ref ioRequest, ApduBuffer, (uint)ApduBuffer.Length, ref ioResponse, ApduResponse, ref RecvLength);
                if (m_nLastError != 0)
                {
                    string msg = "SCardTransmit error: " + m_nLastError;
                    throw new Exception(msg);
                }
                sw1 = ApduResponse[ApduResponse.Length - 2] & 0xff;
                sw2 = ApduResponse[ApduResponse.Length - 1] & 0xff;
                if (ApduResponse.Length > APDUResponse.SW_LENGTH)
                {
                    ms.Write(ApduResponse, 0, ApduResponse.Length - APDUResponse.SW_LENGTH);
                }
            }
            ms.WriteByte((byte)sw1);
            ms.WriteByte((byte)sw2);

            return(new APDUResponse(ms.ToArray()));
        }
예제 #17
0
 abstract public APDUResponse Transmit(APDUCommand ApduCmd);
예제 #18
0
 private byte[] ReadInfo(short len)
 {
     MemoryStream ms = new MemoryStream();
     while (len > 0)
     {
         byte readLen = (byte)(len < 255 ? len : 255);
         APDUCommand readInfoApdu = new APDUCommand(0xcc, 6, 0, 0, null, readLen);
         APDUResponse apdu1 = this.cardUpdater.Transmit(readInfoApdu);
         if (apdu1.SW1 != 0x94 && apdu1.SW1 != 0x90) throw new Exception("Failed to read"); ;
         len -= readLen;
         ms.Write(apdu1.Data, 0, apdu1.Data.Length);
     }
     return ms.ToArray();
 }
예제 #19
0
 private void SelectInfo(short filen1, short filen2, short offset, short len)
 {
     byte[] paramBytes = new byte[8];
     byte[] n1Bytes = BitConverter.GetBytes(filen1);
     byte[] n2Bytes = BitConverter.GetBytes(filen2);
     byte[] offsetBytes = BitConverter.GetBytes(offset);
     byte[] lenBytes = BitConverter.GetBytes(len);
     Array.Copy(n2Bytes, 0, paramBytes, 0, 2);
     Array.Copy(n1Bytes, 0, paramBytes, 2, 2);
     Array.Copy(offsetBytes, 0, paramBytes, 4, 2);
     Array.Copy(lenBytes, 0, paramBytes, 6, 2);
     APDUCommand setLengthAPdu = new APDUCommand(0xcc, 0, 0, 0, paramBytes, 0);
     APDUResponse apdu1 = this.cardUpdater.Transmit(setLengthAPdu);
     if (apdu1.SW1 != 0x94) throw new Exception("Failed to read"); ;
 }
예제 #20
0
 private void SetLength(short len)
 {
     byte[] paramBytes = new byte[] { 8, 0, 0, 0, 0 };
     byte[] lenBytes = BitConverter.GetBytes(len);
     Array.Copy(lenBytes, 0, paramBytes, 3, 2);
     APDUCommand setLengthAPdu = new APDUCommand(0xc8, 0x32, 0, 0, paramBytes, 0);
     APDUResponse apdu1 = this.cardUpdater.Transmit(setLengthAPdu);
     if (apdu1.SW1 != 0x91 || apdu1.SW2 != 8) throw new Exception("Failed to read"); ;
 }
예제 #21
0
 public bool SelectApplication()
 {
     APDUCommand apduSelectPxyApl = new APDUCommand(0x00, 0xA4, 4, 0, m_proxyAppletAID, 0);
     APDUResponse apdu1 = this.cardUpdater.Transmit(apduSelectPxyApl);
     byte[] apduRespByte = apdu1.Packet;
     return checkExchangeApduResult(apduRespByte);
 }