从智能卡读取数据 (CNS/CNR)

Posted

技术标签:

【中文标题】从智能卡读取数据 (CNS/CNR)【英文标题】:Read data from smart card (CNS/CNR) 【发布时间】:2018-10-17 20:49:37 【问题描述】:

我使用 java 卡编写了一个程序,允许我从智能卡中读取一些数据。卡片文件系统结构如下:

Smart Card File System

智能卡是意大利公共管理部门的卡。

我可以正确连接卡,通过运行此代码将数据读取命令发送到路径MF/DF1/EF_Dati_Personali路径

当我尝试输入 DF2/Dati_personali_aggiuntvi 时,尽管它们存在,但我找不到任何数据。

根据参考指南,访问DF1和DF2区域,扇区如下:

Data sectors

下面是我写的代码。代码在行注释以获取数据以识别问题。

谁能告诉我哪里错了?每一个建议都值得赞赏。非常感谢

package smartcard;

import java.io.IOException;
import static java.lang.System.out;
import java.util.List;
import javax.smartcardio.ATR;
import javax.smartcardio.Card;
import javax.smartcardio.CardChannel;
import javax.smartcardio.CardException;
import javax.smartcardio.CardTerminal;
import javax.smartcardio.CommandAPDU;
import javax.smartcardio.ResponseAPDU;
import javax.smartcardio.TerminalFactory;
import javax.swing.JOptionPane;

public class SmartCard 

    /**
     * @param args the command line arguments
     */
    public static void main(String[] args) throws CardException, IOException 
        try 
             TerminalFactory factory = TerminalFactory.getDefault();
            List<CardTerminal> terminals = factory.terminals().list();
            System.out.println("Terminals: " + terminals);

            // Use the first terminal
            CardTerminal terminal = terminals.get(0);

            // Connect wit hthe card
            Card card = terminal.connect("*");
            System.out.println("card: " + card);
            CardChannel channel = card.getBasicChannel();

            //GET ATR
            ATR atr = card.getATR();

            byte[] ATR = atr.getBytes();
            System.out.println("Card ATR: " + bytesToHex(ATR));
           //   // originale

            //GET SELECT_FILE_APDU
            byte[] READ_BINARY_APDU = (byte) 0x00, (byte) 0xB0, (byte) 0x00, (byte) 0x00, (byte) 0xff; 

            byte[] dati_personali = (byte) 0x00, (byte) 0xA4, (byte) 0x08, (byte) 0x00, (byte) 0x04, (byte) 0x11, (byte) 0x00, (byte) 0x11, (byte) 0x02, (byte) 0x00;
            // Whit this String I can correctly read DF1 Data of CNS (Carta Nazionale servizi)

            // This should be the string for get DF2 data but I cannot find anything.
            byte[] dati_personali_aggiuntivi = (byte) 0x00, (byte) 0xA4, (byte) 0x08, (byte) 0x00, (byte) 0x04, (byte) 0x12, (byte) 0x00, (byte) 0x12, (byte) 0x01, (byte) 0x00;

            String dati_personali_string = richiedi(channel, READ_BINARY_APDU, dati_personali, "<b>Dati personali:</b><br>");
            String dati_personali_aggiuntivi_string = richiedi(channel, READ_BINARY_APDU, dati_personali_aggiuntivi, "<b>Dati personali aggiuntivi:</b><br>");
            JOptionPane.showMessageDialog(null,"dati personali: "+ dati_personali_string, "Dati personali",JOptionPane.INFORMATION_MESSAGE);
            JOptionPane.showMessageDialog(null,"dati personali agiguntivi: "+ dati_personali_aggiuntivi_string, "Dati personali aggiuntivi",JOptionPane.INFORMATION_MESSAGE);


            // Disconnect the card
            card.disconnect(false);
            System.out.println("DISCONEESSO ");

         catch (Exception e) 
            System.out.println("Ouch: " + e.toString());
        

    

    public static String richiedi(CardChannel channel, byte[] read, byte[] select, String titolo) throws CardException 
        out.println(titolo);
        // Send Select Applet command
        ResponseAPDU answer = channel.transmit(new CommandAPDU(select));
        // Send test command
        answer = channel.transmit(new CommandAPDU(read));
        byte r[] = answer.getData();
        String test = "";
        for (int i = 0; i < r.length; i++) 
            test += (char) r[i];
        
        System.out.print(test);
        out.println(test);
        out.println("<br><br>");
        return test;
    

    public static String bytesToHex(byte[] bytes) 
        StringBuilder sb = new StringBuilder(bytes.length * 2);
        for (int i = 0; i < bytes.length; i++) 
            sb.append(String.format("%02x", bytes[i]));
        
        return sb.toString();
    


更新 APDU 跟踪

REQUEST: Dati personali:
read command: >>> 00b00000ff
select command: >>> 00a40800041100110200

RESPONSE: Dati personali:
<<< answer from CNS: 303030303733303436303330303830373039323031303038303730393230313630384954414c49414e4f3130414e544f4e494f20435249535449414e3038323230343139383230314d30303130544c4e4e4e43383244323246323035493030303446323035303030303034463230353030303000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000009000

_____________________
REQUEST: Dati personali aggiuntivi:
read command: >>> 00b00000ff
select command: >>> 00a40800041200120100

RESPONSE: Dati personali aggiuntivi:
<<< answer from CNS: 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000009000

【问题讨论】:

.. 我找不到任何数据... 有点模糊。你得到了哪些错误代码? 请在 richiedi() 方法中围绕每个传输添加 APDU 跟踪,例如System.out.println("&gt;&gt;&gt; " + bytesToHex(select));...transmit(select)...System.out.println("&lt;&lt;&lt; " + bytesToHex(answer.getBytes()));...System.out.println("&gt;&gt;&gt; " + bytesToHex(read));...transmit(read)...System.out.println("&lt;&lt;&lt; " + bytesToHex(answer.getBytes())); 并使用此跟踪更新您的问题。 您好,感谢您的回答。我在 richiedi() 方法中添加了围绕每个传输的 APDU 跟踪。第一个调用与 DF1 (dati personali) 有关,第二个调用与 DF2 (dati_personali_aggiuntivi) 有关。我已经用这些数据更新了问题。谢谢。 @GammoneGammone 您的跟踪显示读取成功(卡响应状态字“9000”)并且文件包含 100 个零字节... 【参考方案1】:

根据给定的跟踪,您的代码可以正常工作,并且卡中的数据已成功读取——基本文件“DF2/Dati_personali_aggiuntivi”被零填充。

这符合the documentation(第 4.3 节):

EF.Dati_personali_aggiuntvi – l'intero contenuto è posto a ‘00’hex

使用谷歌翻译翻译:

EF.Additional_personal_dates - 整个内容设置为 '00'hex

一些补充说明:

“EF.Dati_personali”文件包含 400 个字节——您可能需要使用多个“READ BINARY”命令来获取所有内容

始终检查 APDU 响应状态 ('90 00') -- ResponseAPDU.getSW() 对此很有用

祝你的项目好运!

编辑>OpenSC支持CNS卡(见here和here)你可能想试一试

【讨论】:

首先,感谢您的回答。你是对的,“整个内容设置为'00'hex”是我的疑问。我试图读取“EF.Dati_personali”中的其他字节,但我得到一个零字符串,好像没有比我读取的数据更多的数据。我尝试改变问题:使用另一个软件(我认为用 delphi 编写,但我认为这不是问题)我在屏幕上获得了我需要的信息(即 Additional_personal_data)。根据您的经验和上面的文件系统,这些数据可能在哪里?欢迎任何指示或直觉!谢谢 @GammoneGammone 我简要地查看了文档并没有找到任何线索(但我不会说意大利语,以前从未使用过 CNS 卡)。您可以使用APDUPlay 或WinSCard APDU View Utility 等工具查看其他应用程序对卡片的操作(请检查您的操作的合法性)。也许其他应用程序与某个服务器通信以获取更多信息……祝你好运!

以上是关于从智能卡读取数据 (CNS/CNR)的主要内容,如果未能解决你的问题,请参考以下文章

如何在 C# 中从智能卡中读取名称和地址等基本数据?

如何从自定义 BLE 服务读取数据(例如智能手表)

从浏览器读取智能卡

从欧洲DTCO公司卡读取数据

智能卡读卡器插件(插入卡)事件

在Android上的蓝牙中从InputStream读取数据时出错