unsafe int TryEmvPseCardRead(string df_name, string szTitlePse) { EMV_STATUS emv_status; tCNR1.Clear(); tCNR2.Clear(); tCNR3.Clear(); tCNR4.Clear(); uFCoder reader = new uFCoder(); bool head_attached = false; emv_tree_node_t head = new emv_tree_node_t(); emv_tree_node_t tail = new emv_tree_node_t(); emv_tree_node_t temp = new emv_tree_node_t(); afl_list_item_t afl_list = new afl_list_item_t(); afl_list_item_t afl_list_item = new afl_list_item_t(); byte afl_list_count; byte[] r_apdu = new byte[258]; int Ne; byte[] aid = new byte[16]; char[] chr_aid = new char[16]; byte[] sw = new byte[2]; byte sfi, record = 0, cnt = 1, aid_len = 0; byte[] gpo_data_field = new byte[4]; ushort gpo_data_field_size = 0; bool card_found = false; byte[] card_nr = new byte[8]; int card_nr_len = 0; do { status = uFCoder.SetISO14443_4_Mode(); if (status > 0) { ReadPSERtb.AppendText("Error while switching into ISO 14443 - 4 mode, uFR status is: " + uFCoder.status2str(status)); break; } ReadPSERtb.AppendText(cnt++.ToString() + ". Issuing \"Select PSE\" command: \n"); ReadPSERtb.AppendText(" [C] 00 A4 04 00 " + BitConverter.ToString(Encoding.ASCII.GetBytes(df_name)).Replace("-", " ") + " 00"); Ne = 256; status = uFCoder.APDUTransceive(0x00, 0xA4, 0x04, 0x00, df_name.ToCharArray(), df_name.Length, r_apdu, &Ne, 1, sw); if (status > 0) { ReadPSERtb.AppendText("Error while executing APDU command, uFR status: " + uFCoder.status2str(status)); break; } else { if (sw[0] != 0x90) { ReadPSERtb.AppendText("\n[SW]: " + sw[0].ToString("X2") + sw[1].ToString("X2") + "\n"); ReadPSERtb.AppendText("Could not continue execution due to an APDU error. \n"); break; } if (Ne > 0) { ReadPSERtb.AppendText("\n APDU command executed, response data length: " + Ne.ToString() + "\n"); ReadPSERtb.AppendText("[R] "); for (int resp = 0; resp < Ne; resp++) { ReadPSERtb.AppendText(r_apdu[resp].ToString("X2") + ":"); } } ReadPSERtb.AppendText("\n[SW]: " + sw[0].ToString("X2") + sw[1].ToString("X2") + "\n"); } emv_status = reader.newEmvTag(ref head, r_apdu, Ne, false); if (emv_status > 0) { ReadPSERtb.AppendText("EMV parsing error code: " + emv_status.ToString()); break; } emv_status = reader.getSfi(ref head, &sfi); if (emv_status == 0) { record = 1; do { ReadPSERtb.AppendText("\n" + cnt.ToString() + ". Issuing \"Read Record\" command (record = " + record.ToString() + ", sfi = " + sfi.ToString() + ")\n"); ReadPSERtb.AppendText("[C] 00 B2 " + record.ToString("X2") + " " + ((sfi << 3) | 4).ToString("X2") + " 00\n"); emv_status = reader.emvReadRecord(r_apdu, &Ne, sfi, record, sw); if (emv_status == 0) { emv_status = reader.newEmvTag(ref temp, r_apdu, Ne, false); if (!head_attached) { head.next = temp; head_attached = true; } else { tail.next = temp; tail = tail.next; } if (Ne > 0) { ReadPSERtb.AppendText(" APDU command executed: response data length = " + Ne.ToString() + "\n"); ReadPSERtb.AppendText("[R] "); for (int resp = 0; resp < Ne; resp++) { ReadPSERtb.AppendText(r_apdu[resp].ToString("X2") + ":"); } } ReadPSERtb.AppendText("\n[SW] " + sw[0].ToString("X2") + sw[1].ToString("X2") + "\n"); } else { if (sw[0] != 0x90) { ReadPSERtb.AppendText("\n[SW] " + sw[0].ToString("X2") + sw[1].ToString("X2") + "\n"); ReadPSERtb.AppendText("There is no records.\n"); } } record++; cnt++; } while (emv_status == 0); } emv_status = reader.getAid(ref head, ref aid, ref aid_len); if (emv_status == 0) { Array.Copy(aid, chr_aid, aid.Length); } { ReadPSERtb.AppendText("\n " + cnt++.ToString() + ". Issuing \"Select the appplication command\": \n"); ReadPSERtb.AppendText(" [C] 00 A4 00 00 " + aid_len.ToString("X2") + " "); for (int print = 0; print < aid_len; print++) { ReadPSERtb.AppendText(aid[print].ToString("X2") + " "); } ReadPSERtb.AppendText(" 00"); Ne = 256; status = uFCoder.APDUTransceive(0x00, 0xA4, 0x04, 0x00, chr_aid, aid_len, r_apdu, &Ne, 1, sw); if (status != 0) { ReadPSERtb.AppendText(" Error while executing APDU command, uFR status is: " + uFCoder.status2str(status) + "\n"); } else { if (sw[0] != 0x90) { ReadPSERtb.AppendText("\n[SW] " + sw[0].ToString("X2") + sw[1].ToString("X2") + "\n"); ReadPSERtb.AppendText("Could not continue execution due to an APDU error.\n"); break; } if (Ne > 0) { ReadPSERtb.AppendText("\n APDU command executed: response data length = " + Ne.ToString() + " bytes \n"); ReadPSERtb.AppendText("[R] "); for (int resp = 0; resp < Ne; resp++) { ReadPSERtb.AppendText(r_apdu[resp].ToString("X2") + ":"); } } ReadPSERtb.AppendText("\n[SW] " + sw[0].ToString("X2") + sw[1].ToString("X2") + "\n"); } emv_status = reader.newEmvTag(ref temp, r_apdu, Ne, false); if (emv_status > 0) { ReadPSERtb.AppendText(" EMV parsing error code: " + emv_status.ToString()); break; } if (!head_attached) { head.next = tail = temp; head_attached = true; } else { tail.next = temp; tail = tail.next; } ReadPSERtb.AppendText("\n " + cnt++.ToString() + ". Formatting \"Get Processing Options\" instruction (checking PDOL).\n"); emv_status = reader.formatGetProcessingOptionsDataField(temp, ref gpo_data_field, &gpo_data_field_size); if (emv_status > 0) { ReadPSERtb.AppendText("EMV parsing error code: " + emv_status.ToString()); break; } ReadPSERtb.AppendText("\n " + cnt++.ToString() + ". Issuing \"Get Processing options\" command:\n"); ReadPSERtb.AppendText(" [C] 80 A8 00 00 " + gpo_data_field_size.ToString("X2") + " "); for (int comm = 0; comm < gpo_data_field_size; comm++) { ReadPSERtb.AppendText(gpo_data_field[comm].ToString("X2") + " "); } ReadPSERtb.AppendText("00\n"); Ne = 256; char[] chr_gpo_array = new char[gpo_data_field_size]; Array.Copy(gpo_data_field, chr_gpo_array, gpo_data_field.Length); status = uFCoder.APDUTransceive_Bytes(0x80, 0xA8, 0x00, 0x00, gpo_data_field, gpo_data_field_size, r_apdu, &Ne, 1, sw); if (status != 0) { ReadPSERtb.AppendText(" Error while executing APDU command, uFR status: " + uFCoder.status2str(status) + "\n"); break; } else { if (sw[0] != 0x90) { ReadPSERtb.AppendText("\n[SW] " + sw[0].ToString("X2") + sw[1].ToString("X2")); ReadPSERtb.AppendText("Could not continue execution due to an APDU error."); break; } if (Ne > 0) { ReadPSERtb.AppendText("APDU command executed: response data length = " + Ne.ToString() + "\n"); ReadPSERtb.AppendText("[R] "); for (int resp = 0; resp < Ne; resp++) { ReadPSERtb.AppendText(r_apdu[resp].ToString("X2") + ":"); } } ReadPSERtb.AppendText("\n[SW] " + sw[0].ToString("X2") + sw[1].ToString("X2")); } emv_status = reader.newEmvTag(ref temp, r_apdu, Ne, false); if (emv_status > 0) { ReadPSERtb.AppendText(" EMV parsing error code: " + emv_status.ToString()); break; } tail.next = temp; tail = tail.next; emv_status = reader.getAfl(temp, afl_list, &afl_list_count); if (emv_status == EMV_STATUS.EMV_ERR_TAG_NOT_FOUND) { emv_status = reader.getAflFromResponseMessageTemplateFormat1(temp, afl_list, &afl_list_count); } if (emv_status > 0) { ReadPSERtb.AppendText(" EMV parsing error code: " + emv_status.ToString()); break; } afl_list_item = afl_list.next; while (afl_list_item != null) { for (int r = afl_list_item.record_first; r <= afl_list_item.record_last; r++) { ReadPSERtb.AppendText("\n" + cnt.ToString() + ". Issuing \"Read Record\" command (record = " + r.ToString() + ", sfi = " + afl_list_item.sfi.ToString() + "):\n"); ReadPSERtb.AppendText(" [C] 00 B2 " + r.ToString("X2") + " " + ((afl_list_item.sfi << 3) | 4).ToString("X2") + " 00\n"); emv_status = reader.emvReadRecord(r_apdu, &Ne, afl_list_item.sfi, (byte)r, sw); if (card_found == false) { card_found = reader.GetCardNumber(r_apdu, (int)Ne, ref card_nr, &card_nr_len); } if (emv_status == 0) { byte[] emv_apdu = new byte[r_apdu.Length]; Array.Copy(r_apdu, emv_apdu, r_apdu.Length); emv_status = reader.newEmvTag(ref temp, emv_apdu, Ne, false); if (emv_status == 0) { tail.next = temp; tail = tail.next; } if (Ne > 0) { ReadPSERtb.AppendText("APDU command executed: response data length = " + Ne.ToString() + "\n"); ReadPSERtb.AppendText("[R] "); for (int resp = 0; resp < Ne; resp++) { ReadPSERtb.AppendText(r_apdu[resp].ToString("X2") + ":"); } } ReadPSERtb.AppendText("\n[SW] " + sw[0].ToString("X2") + sw[1].ToString("X2")); } else { if (sw[0] != 0x90) { ReadPSERtb.AppendText("\n[SW] " + sw[0].ToString("X2") + sw[1].ToString("X2")); } } cnt++; } afl_list_item = afl_list_item.next; } } } while (false); tCNR1.AppendText(card_nr[0].ToString("X2") + " " + card_nr[1].ToString("X2")); tCNR2.AppendText(card_nr[2].ToString("X2") + " " + card_nr[3].ToString("X2")); tCNR3.AppendText(card_nr[4].ToString("X2") + " " + card_nr[5].ToString("X2")); tCNR4.AppendText(card_nr[6].ToString("X2") + " " + card_nr[7].ToString("X2")); uFCoder.s_block_deselect(100); return(0); }
private void btnReadEMV_Click(object sender, RoutedEventArgs e) { String df_name = ""; String PseTitle = ""; if (rbPSE1.IsChecked == true) { df_name = "1PAY.SYS.DDF01"; PseTitle = "PSE1"; } else if (rbPSE2.IsChecked == true) { df_name = "2PAY.SYS.DDF01"; PseTitle = "PSE2"; } else { MessageBox.Show("Select Payment System Environment first."); return; } txtReadEMV.Clear(); byte[] r_apdu = new byte[258]; int[] Ne = new int[1]; Ne[0] = 256; byte[] sw = new byte[2]; byte[] sfi = new byte[1]; byte record = 0; byte cnt = 0; uint ufr_status = 0x54; int[] emv_status = new int[1]; bool head_attached = false; byte[] aid = new byte[16]; char[] chr_aid = new char[16]; byte[] aid_len = new byte[1]; short[] gpo_data_field_size = new short[1]; byte[] gpo_data_field = new byte[1024]; byte[] afl_list_count = new byte[1]; byte[] ascii_name = Encoding.ASCII.GetBytes(df_name); emv_tree_node_t head = new emv_tree_node_t(); emv_tree_node_t temp = new emv_tree_node_t(); emv_tree_node_t tail = new emv_tree_node_t(); afl_list_item_t[] afl_list_item = new afl_list_item_t[1]; do { ufr_status = uFCoder.SetISO14443_4_Mode(); if (ufr_status != 0) { txtReadEMV.AppendText(" Error while switching into ISO 14443-4 mode, check uFR status."); txtStatus.Text = uFCoder.status2str(ufr_status); break; } txtReadEMV.AppendText(++cnt + ". Issuing \"Select PSE\" command (" + PseTitle + ")\n" + " [C] 00 A4 04 00 "); for (int i = 0; i < df_name.Length; i++) { txtReadEMV.AppendText(ascii_name[i].ToString("X2") + " "); } ufr_status = uFCoder.APDUTransceive((byte)0x00, (byte)0xA4, (byte)0x04, (byte)0x00, df_name.ToCharArray(), df_name.Length, r_apdu, Ne, (byte)1, sw); if (ufr_status != 0) { txtStatus.Text = uFCoder.status2str(ufr_status); break; } else { if (sw[0] != (byte)0x90) { txtReadEMV.AppendText("\n [SW] " + sw[0].ToString("X2") + " " + sw[1].ToString("X2") + " "); txtReadEMV.AppendText("\nCould not continue execution due to an APDU error.\n"); ufr_status = (uint)UFR_STATUS.UFR_APDU_TRANSCEIVE_ERROR; txtStatus.Text = uFCoder.status2str(ufr_status); break; } if (Ne[0] > 0) { txtReadEMV.AppendText("\n APDU command executed: response data length = " + Ne[0] + " bytes\n"); txtReadEMV.AppendText(" [R] "); for (int i = 0; i < Ne[0]; i++) { txtReadEMV.AppendText(r_apdu[i].ToString("X2") + " "); } } txtReadEMV.AppendText("\n [SW] " + sw[0].ToString("X2") + " " + sw[1].ToString("X2") + " "); } int[] Ne_ptr = new int[1]; Ne_ptr[0] = Ne[0]; head = uFCoder.newEmvTag(head, r_apdu, Ne_ptr, false, emv_status); if (emv_status[0] != 0) { txtReadEMV.AppendText(" EMV parsing error occurred."); ufr_status = (uint)emv_status[0]; txtStatus.Text = uFCoder.status2str(ufr_status); break; } ufr_status = (uint)uFCoder.getSfi(head, sfi); if (ufr_status == 0) { record = 1; do { ++cnt; txtReadEMV.AppendText("\n " + cnt.ToString() + ". Issuing \"Read Record\" command (record = " + record.ToString() + ", sfi = " + sfi.ToString() + "):\n [C] 00 B2" + record.ToString("X2") + ((sfi[0] << 3) | 4).ToString("X2") + "\n"); ufr_status = (uint)uFCoder.emvReadRecord(r_apdu, Ne_ptr, sfi[0], record, sw); if (ufr_status == 0) { temp = uFCoder.newEmvTag(temp, r_apdu, Ne_ptr, false, emv_status); if (record == 1) { head.next = tail = temp; } else { tail.next = temp; tail = tail.next; } if (Ne_ptr[0] > 0) { txtReadEMV.AppendText(" APDU command executed: response data length = " + Ne[0] + " bytes\n"); txtReadEMV.AppendText(" [R] "); for (int i = 0; i < Ne[0]; i++) { txtReadEMV.AppendText(r_apdu[i].ToString("X2") + " "); } } txtReadEMV.AppendText("\n [SW] " + sw[0].ToString("X2") + " " + sw[1].ToString("X2") + " "); } else { if (sw[0] != 0x90) { txtReadEMV.AppendText("\n [SW] " + sw[0].ToString("X2") + " " + sw[1].ToString("X2") + " "); txtReadEMV.AppendText(" There is no records"); } } record++; cnt++; } while (ufr_status == 0); } ufr_status = (uint)uFCoder.getAid(head, aid, aid_len); if (ufr_status == 0) { ++cnt; txtReadEMV.AppendText("\n" + cnt.ToString() + ". Issuing \"Select the application\" command \n [C] 00 A4 04 00 " + aid_len[0].ToString("X2") + "\n"); Ne[0] = 256; Array.Copy(aid, chr_aid, aid.Length); ufr_status = uFCoder.APDUTransceive((byte)0x00, (byte)0xA4, (byte)0x04, (byte)0x00, chr_aid, aid_len[0], r_apdu, Ne, (byte)1, sw); if (ufr_status != 0) { txtStatus.Text = uFCoder.status2str(ufr_status); break; } else { if (sw[0] != (byte)0x90) { txtReadEMV.AppendText("\n [SW] " + sw[0].ToString("X2") + " " + sw[1].ToString("X2") + " "); txtReadEMV.AppendText("\nCould not continue execution due to an APDU error.\n"); } if (Ne[0] > 0) { txtReadEMV.AppendText(" APDU command executed: response data length = " + Ne[0] + " bytes\n"); txtReadEMV.AppendText(" [R] "); for (int i = 0; i < Ne[0]; i++) { txtReadEMV.AppendText(r_apdu[i].ToString("X2") + " "); } } txtReadEMV.AppendText("\n [SW] " + sw[0].ToString("X2") + " " + sw[1].ToString("X2") + " "); } Ne_ptr[0] = Ne[0]; temp = uFCoder.newEmvTag(temp, r_apdu, Ne_ptr, false, emv_status); if (emv_status[0] != 0) { break; } if (head_attached == false) { head.next = tail = temp; head_attached = true; } else { tail.next = temp; tail = tail.next; } ++cnt; txtReadEMV.AppendText("\n" + cnt.ToString() + ". Formating \"Get Processing Options\" instruction (checking PDOL)\n"); emv_status[0] = uFCoder.formatGetProcessingOptionsDataField(temp, gpo_data_field, gpo_data_field_size); if (emv_status[0] != 0) { ufr_status = (uint)emv_status[0]; txtReadEMV.AppendText(" EMV parsing error occurred."); ufr_status = (uint)emv_status[0]; txtStatus.Text = uFCoder.status2str(ufr_status); break; } ++cnt; txtReadEMV.AppendText("\n" + cnt.ToString() + ". Issuing \"Get Processing Options\" command:\n [C] 80 A8 00 00 " + gpo_data_field_size[0].ToString("X2") + "\n"); for (int i = 0; i < gpo_data_field_size[0]; i++) { txtReadEMV.AppendText(String.Format("%02X", gpo_data_field[i]) + " "); } Ne[0] = 256; ufr_status = uFCoder.APDUTransceive_Bytes(0x80, 0xA8, 0x00, 0x00, gpo_data_field, gpo_data_field_size[0], r_apdu, Ne, 1, sw); if (ufr_status != 0) { txtReadEMV.AppendText(" Error while executing APDU command, uFR status is: " + uFCoder.status2str(ufr_status)); txtStatus.Text = uFCoder.status2str(ufr_status); break; } else { if (sw[0] != (byte)0x90) { txtReadEMV.AppendText("\n [SW] " + sw[0].ToString("X2") + " " + sw[1].ToString("X2") + " "); txtReadEMV.AppendText("\nCould not continue execution due to an APDU error.\n"); break; } if (Ne[0] > 0) { txtReadEMV.AppendText("\n APDU command executed: response data length = " + Ne[0] + " bytes\n"); txtReadEMV.AppendText(" [R] "); for (int i = 0; i < Ne[0]; i++) { txtReadEMV.AppendText(r_apdu[i].ToString("X2") + " "); } } txtReadEMV.AppendText("\n [SW] " + sw[0].ToString("X2") + " " + sw[1].ToString("X2") + " "); } Ne_ptr[0] = Ne[0]; temp = uFCoder.newEmvTag(temp, r_apdu, Ne_ptr, false, emv_status); if (emv_status[0] != 0) { ufr_status = (uint)emv_status[0]; txtReadEMV.AppendText("EMV parsing error: " + uFCoder.status2str(ufr_status)); txtStatus.Text = uFCoder.status2str(ufr_status); break; } tail.next = temp; tail = tail.next; ufr_status = (uint)uFCoder.getAfl(temp, afl_list_item, afl_list_count); if (ufr_status == (uint)UFR_STATUS.EMV_ERR_TAG_NOT_FOUND) { ufr_status = (uint)uFCoder.getAflFromResponseMessageTemplateFormat1(temp, afl_list_item, afl_list_count); } if (ufr_status != 0) { txtReadEMV.AppendText("EMV parsing error: " + uFCoder.status2str(ufr_status)); txtStatus.Text = uFCoder.status2str(ufr_status); break; } while (afl_list_item[0] != null) { for (int r = afl_list_item[0].record_first[0]; r <= afl_list_item[0].record_last[0]; r++) { ++cnt; txtReadEMV.AppendText("\n " + cnt.ToString() + ". Issuing \"Read Record\" command (record = " + r.ToString() + ", sfi = " + afl_list_item[0].sfi[0].ToString() + "):\n [C] 00 B2 " + r.ToString("X2") + " " + ((afl_list_item[0].sfi[0] << 3) | 4).ToString("X2") + "\n"); ufr_status = (uint)uFCoder.emvReadRecord(r_apdu, Ne_ptr, afl_list_item[0].sfi[0], (byte)r, sw); if (ufr_status == 0) { int[] temp_Ne = new int[Ne_ptr.Length]; Array.Copy(Ne_ptr, 0, temp_Ne, 0, Ne_ptr.Length); byte[] temp_resp = new byte[r_apdu.Length]; Array.Copy(r_apdu, 0, temp_resp, 0, r_apdu.Length); temp = uFCoder.newEmvTag(temp, temp_resp, temp_Ne, false, emv_status); if (emv_status[0] == 0) { tail.next = temp; tail = tail.next; } if (Ne_ptr[0] > 0) { txtReadEMV.AppendText(" APDU command executed: response data length = " + Ne_ptr[0] + " bytes\n"); txtReadEMV.AppendText(" [R] "); for (int i = 0; i < Ne_ptr[0]; i++) { txtReadEMV.AppendText(r_apdu[i].ToString("X2") + " "); } } txtReadEMV.AppendText("\n [SW] " + sw[0].ToString("X2") + " " + sw[1].ToString("X2") + " "); } } afl_list_item[0] = afl_list_item[0].next; } } ufr_status = 0; txtStatus.Text = uFCoder.status2str(ufr_status); } while (false); uFCoder.s_block_deselect((byte)100); }