【问题标题】:How do I read the PAN from an EMV SmartCard from Java如何从 Java 的 EMV 智能卡中读取 PAN
【发布时间】:2010-09-21 22:43:08
【问题描述】:

我需要使用智能卡读卡器从 Maestro/Mastercard 读取帐号。我正在使用 Java 1.6 及其 javax.smartcardio 包。我需要发送 APDU 命令,该命令将询问存储在卡芯片上的 EMV 应用程序的 PAN 号。问题是,我找不到常规字节数组来构造 APDU 命令,它将在任何地方返回所需的数据......

【问题讨论】:

    标签: java smartcard apdu emv


    【解决方案1】:

    您需要构造一个 CommandAPDU 对象并将其传递给传输()命令。

    您应该能够在智能卡的文档中找到准确的命令,但这里有一个示例:

    byte[] readFile(CardChannel channel) throws CardException {
      CommandAPDU command = new CommandAPDU(0xB0, 0x60, 0x10, 0x00);
      ResponseAPDU response = channel.transmit(command);
      return response.getData();
    }
    

    【讨论】:

      【解决方案2】:

      您是否尝试在文档中查找 0x6D00 的含义?看起来这可能意味着不支持 ENVELOPE 命令。您是否尝试过使用 T=0 协议而不是 T=1?

      我不希望我的示例适用于您的卡片。我不知道 Maestro/MasterCard 支持哪些 APDU,所以我不能给你一个可行的例子。

      尝试给命令一个明确的预期长度,如下所示:

      byte[] readPan(CardChannel channel) throws CardException {
        CommandAPDU command = new CommandAPDU(0x00, 0xB2, 0x5a, 0x14, 250);
        ResponseAPDU response = channel.transmit(command);
        return response.getData();
      }
      

      【讨论】:

        【解决方案3】:

        您不需要进一步包装 APDU。 API 层应该负责这一点。

        看起来 0x6D00 响应只是意味着应用程序不支持 INS。

        现在才进行故障排除,但您确实是从选择 MasterCard 应用程序开始的,对吧?

        即像这样:

        void selectApplication(CardChannel channel) throws CardException {
          byte[] masterCardRid = new byte[]{0xA0, 0x00, 0x00, 0x00, 0x04};
          CommandAPDU command = new CommandAPDU(0x00, 0xA4, 0x04, 0x00, masterCardRid);
          ResponseAPDU response = channel.transmit(command);
          return response.getData();
        }
        

        【讨论】:

        • 我不太明白你的回答。我的回复总是打到 0x6D00。像你说的我的卡不支持INS怎么办?
        【解决方案4】:

        这里有一些工作示例:

        CardChannel channel = card.getBasicChannel(); 
        
         byte[] selectMaestro={(byte)0x00, (byte)0xA4,(byte)0x04,(byte)0x00 ,(byte)0x07 ,(byte)0xA0 ,(byte)0x00 ,(byte)0x00 ,(byte)0x00 ,(byte)0x04 ,(byte)0x30 ,(byte)0x60 ,(byte)0x00};
          byte[] getProcessingOptions={(byte)0x80,(byte)0xA8,(byte)0x00,(byte)0x00,(byte)0x02,(byte)0x83,(byte)0x00,(byte)0x00};
          byte[] readRecord={(byte)0x00,(byte)0xB2,(byte)0x02,(byte)0x0C,(byte)0x00};
        
          ResponseAPDU r=null;
        
           try {
             ATR atr = card.getATR(); //reset kartice
        
              CommandAPDU capdu=new CommandAPDU( selectMaestro   );
        
               r=card.getBasicChannel().transmit( capdu );
        
              capdu=new CommandAPDU(getProcessingOptions);
              r=card.getBasicChannel().transmit( capdu );
        
        
              capdu=new CommandAPDU(readRecord);
              r=card.getBasicChannel().transmit( capdu );
        

        这适用于 Maestro 卡,我可以读取 PAN 号码,但现在我需要读取 MasterCard 的 PAN 号码。我不知道我应该更改读取记录 APDU 还是选择应用程序 APDU。有人熟悉 APDU 吗?

        【讨论】:

        • 是需要更改的选择应用命令。该命令的最后一部分是您要选择的应用程序的 AID。将其更改为 MasterCard AID 应该可以。或者您可能只想缩短 AID。如果您提供 A400000004,...
        • ...它应该匹配所有以 A400000004 开头的 AID。
        【解决方案5】:
        atr = open();
        prints(atr);
        
        prints("[Step 1] Select 1PAY.SYS.DDF01 to get the PSE directory");
        cmd = new ISOSelect(ISOSelect.SELECT_AID, EMV4_1.AID_1PAY_SYS_DDF01);
        card_response = execute(cmd);
        prints(card_response);
        SFI = NumUtil.hex2String((byte)((1 < < 3) | 4));
        
        // try SFI 1 record 1
        prints("[Step 2] Send READ RECORD with 0 to find out where the record is");
        read = new EMVReadRecord(SFI, "01", "00");
        card_response = execute(read);
        prints(card_response);
        byte_size = NumUtil.hex2String(card_response.getStatusWord().getSw2());
        
        prints("[Step 3] Send READ RECORD with 1C to get the PSE data");
        read = new EMVReadRecord(SFI, "01", byte_size);
        card_response = execute(read);
        prints(card_response);
        // the AID is A0000000031010
        prints("[Step 4] Now that we know the AID, select the application");
        
        cmd = new ISOSelect(ISOSelect.SELECT_AID, "A0000000031010");
        card_response = execute(cmd);
        prints(card_response);
        prints("[Step 5] Send GET PROCESSING OPTIONS command");
        
        cmd = new EMVGetProcessingOptions();
        card_response = execute(cmd);
        prints(card_response);
        
        // SFI for the first group of AFL is 0C
        
        prints("[Step 6] Send READ RECORD with 0 to find out where the record is");
        read = new EMVReadRecord("0C", "01", "00");
        card_response = execute(read);
        prints(card_response);
        byte_size = NumUtil.hex2String(card_response.getStatusWord().getSw2());
        
        prints("[Step 7] Use READ RECORD with the given number of bytes to retrieve the data");
        read = new EMVReadRecord("0C", "01", byte_size);
        card_response = execute(read);
        prints(card_response);
        
        data = new TLV(card_response.getData());
        
        close();
        

        【讨论】:

        • 嗨,Grandie,你能在这里添加 TLV 类吗
        【解决方案6】:

        如何使用扫描仪,获取卡片图片,使用好的 java ocr 库(例如 http://ocr4j.sourceforge.net/)扫描图片内容并搜索(通常)16 位序列 XXXX-XXXX- XXXX-XXXX ,然后您将使用 java 从任何 EMV 卡获取 PAN。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2011-09-24
          • 1970-01-01
          • 2016-08-10
          • 2014-04-22
          • 2019-10-22
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多