安卓NFC IsoDep读取文件内容

8
我正在尝试读取来自 ISO/IEC 14443 Type A 类型的卡片上的一些信息。
通过分析该卡片使用安卓应用程序NFC TagInfo ,我发现该应用程序(AID:15845F)拥有我需要的特定文件(文件ID:01)。
我已经成功连接到卡片并选择了应用程序。
String action = getIntent().getAction();
if (NfcAdapter.ACTION_TECH_DISCOVERED.equals(action))
{
    Tag tagFromIntent = getIntent().getParcelableExtra(NfcAdapter.EXTRA_TAG);  
    Log.i(TAG, Arrays.toString(tagFromIntent.getTechList()));

    IsoDep isoDep = IsoDep.get(tagFromIntent);
    try
    {
        isoDep.connect();

        byte[] SELECT = { 
            (byte) 0x00, // CLA = 00 (first interindustry command set)
            (byte) 0xA4, // INS = A4 (SELECT)
            (byte) 0x04, // P1  = 04 (select file by DF name)
            (byte) 0x0C, // P2  = 0C (first or only file; no FCI)
            (byte) 0x06, // Lc  = 6  (data/AID has 6 bytes)
            (byte) 0x31, (byte) 0x35,(byte) 0x38,(byte) 0x34,(byte) 0x35,(byte) 0x46 // AID = 15845F
        };

        byte[] result = isoDep.transceive(SELECT);
        Log.i(TAG, "SELECT: " + bin2hex(result));

        if (!(result[0] == (byte) 0x90 && result[1] == (byte) 0x00))
            throw new IOException("could not select application");

        byte[] GET_STRING = { 
            (byte) 0x00, // CLA Class
            (byte) 0xB0, // INS Instruction
            (byte) 0x00, // P1  Parameter 1
            (byte) 0x00, // P2  Parameter 2
            (byte) 0x04  // LE  maximal number of bytes expected in result
        };

        result = isoDep.transceive(GET_STRING);
        Log.i(TAG, "GET_STRING: " + bin2hex(result));
    }
}

但是我的第二个查询失败了,出现了错误代码:6A86(P1-P2参数不正确)。我已经谷歌搜索了很多,并找到了不同的文档(例如:http://bit.ly/180b6tB),但我就是不能理解如何为P1P2实现正确的值。

编辑

使用NFC TagInfo标记卡的标签类型:ISO/IEC 14443-4智能卡,Mifare DESFire EV1(MF3ICD81)

源代码中使用的SELECT命令实际上没有失败,而是返回了9000响应。所以这就是为什么我认为一切正常的原因。

您提到NFC TagInfo没有提供DF名称等的正确值。值0x313538343546是否正确,您是如何发现这一点的?

您能否给我提供一个简短的描述,我该如何获得想要的数据?是否有其他可以用来读取正确的DF名称、AID等的Android应用程序?我基本上需要从一个应用程序中获取一个文件。如果需要,我还可以提供一些使用NFC TagInfo收集的信息截图。


编辑2

我已重新编写命令,但(如您所提议的)将它们保留在APDU包装器中。因此,我最终有了两个不同的命令,一个用于选择应用程序,另一个用于选择文件

private final byte[] NATIVE_SELECT_APP_COMMAND = new byte[]
{
    (byte) 0x90, (byte) 0x5A, (byte) 0x00, (byte) 0x00, 3,  // SELECT
    (byte) 0x5F, (byte) 0x84, (byte) 0x15, (byte) 0x00      // APPLICATION ID
};
private final byte[] NATIVE_SELECT_FILE_COMMAND = new byte[]
{
    (byte) 0x90, (byte) 0xBD, (byte) 0x00, (byte) 0x00, 7,  // READ
    (byte) 0x01,                                            // FILE ID
    (byte) 0x00, (byte) 0x00, (byte) 0x00,                  // OFFSET
    (byte) 0x00, (byte) 0x00, (byte) 0x00,                  // LENGTH
    (byte) 0x00
};

寻找原生Mifare-Desfire命令教程的尝试没有成功,所以我遵循以下教程:http://noobstah.blogspot.de/2013/04/mifare-desfire-ev1-and-android.html
此教程提供了一种卡认证方法,但我已将其禁用,并且使用了transceive方法来执行原生命令。根据我的理解,这不是一个适当的执行原生命令的方式?有哪些方法(甚至是代码片段)可以用于执行原生命令? 我应该使用哪个Android类?
我重写了该教程中提供的类,并将其上传到 pastebin。执行该类后,我得到了以下结果。
Select APPLICATION: 9100
Read DATA: 91AE

目前我陷入困境,不知道接下来该采取什么步骤。这到底是一个错误,还是查询中需要做出哪些更改才能获得我想要的数据?

1个回答

9
从您从NFC TagInfo中提取的信息和您正在尝试使用的命令来看,我认为这张卡是MIFARE DESFire EV1。正确吗?
关于您的选择命令:NFC TagInfo目前不读取DESFire EV1 ISO命令集中使用的DF名称值。因此,我假设为此应用程序设置的DF名称实际上是0x313538343546,否则SELECT命令将失败。但是请注意,这个值绝不是从NFC TagInfo中显示的DESFire AID中推导出来的!实际上,DF名称是在应用程序创建期间定义的单独值。(这与先前的DESFire版本不同。)
关于您的读取二进制命令:您使用的命令表明您之前已选择了一个文件。然而,您只选择了应用程序。因此,您需要为数据文件发出SELECT命令或在READ BINARY命令中使用短文件ID:
byte[] READ_BINARY = { 
        (byte) 0x00, // CLA Class
        (byte) 0xB0, // INS Instruction
        (byte) 0x80, // P1  (indicate use of SFI)
        (byte) 0x01, // P2  (SFI = 0x01)
        (byte) 0x04  // LE  maximal number of bytes expected in result
};

然而,当涉及到DESFire(EV1)时,我建议您使用原生的命令集(直接或包装)而不是使用ISO 7816-4 APDU。

使用原生的命令集可以获得MIFARE DESFire的全部功能。命令包装是通过将本地DESFire命令嵌入到ISO 7816-4 APDU结构中实现的。封装命令如下:

0x90 CMD 0x00 0x00 LEN CMD-PARAM 0x00

CMD是原生DESFire命令,CMD-PARAM是命令参数。响应为:

[DATA] 0x91 STATUS

其中状态码是原生DESFire状态码。如果状态码为0xAF,您可以通过发送以下命令获取剩余的响应数据:

0x90 0xAF 0x00 0x00 0x00

在您的情况下,您需要为应用程序0x15845F(注意不同的字节顺序!)发出选择应用程序命令:

0x90 0x5A 0x00 0x00 3 0x5F 0x84 0x15 0x00
   |SELECT|          |APPLICATION ID|

接下来,您需要读取数据文件0x01(整个文件,从偏移量0开始):

0x90 0xBD 0x00 0x00 7 0x01 0x00 0x00 0x00 0x00 0x00 0x00 0x00
    |READ|           |FILE|    OFFSET    |    LENGTH    |

关于如何获取您的应用程序的ISO DF名称和ISO FID,您可以尝试以下命令:

选择主应用程序:

905A00000300000000

获取应用程序及其DF名称:
906D000000

请选择您的应用程序:

905A0000035F841500

获取 DESFire FIDs:

906F000000

获取ISO FID:
9061000000

您可以始终使用IsoDep对象的transceive()方法。无论是原生DESFire命令、封装的原生命令还是ISO 7816-4命令,都使用了IsoDep(即ISO/IEC 14443-4)。

您从卡片收到的错误代码(0xAE)表示身份验证错误(请参见此数据表以获取更多信息:DESFire)。因此,该文件仅允许经过身份验证的只读访问(请参见NFC TagInfo中显示的访问条件)。

因此,为了读取此文件,您需要实现身份验证过程。


感谢您的快速回复!我刚刚编辑了我的帖子,在底部添加了额外的信息。 - Vilius
谢谢您的帮助,但我仍然卡住了,我刚刚编辑了我的帖子并提供了更多信息。 - Vilius
我已经更新了答案。不幸的是,我无法帮助您实现身份验证过程。 - Michael Roland
感谢您的回答,也感谢您提供错误和成功代码的链接!这将有望帮助我找到解决方案。此外,我之前并不知道我实际上需要进行身份验证 - 我会阅读规范的! - Vilius

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接