首页 > 解决方案 > 阅读 Mifare Classic 会返回奇怪的字符

问题描述

在使用 Android 读取 MIFARE 卡并将数据转换为 UTF-8 时,我会得到奇怪的字符,例如 �。我正在尝试构建一个可以读取我们正在使用的某种身份证的应用程序。现在的问题是我在单词之间得到了奇怪的字符,并且一些单词在块之间被分割了,所以我怎样才能安全地得到我正在寻找的单词?例如,我的读数是这样的:

43224���19032019�� 在区块 2 sektor 2 bindex :8

并拆分以 19 开头的其余数字在一个新块中:

�我的名字����M����19

在第 1 区块 sektor 1 bindex :4

930402……NO934951

在第 2 区块 sektor 1 bindex :4

c5 42 4e 49 44 00 07 4f 4f 4f 4f 4f 4f 00 4b 42 "Åbnid" "OOOOOO" "KB"
44 44 44 20 44 44 44 44 44 00 82 4d 00 c9 31 39 "DDD DDDDD" "M" "19"
39 34 34 33 34 32 00 d0 4e 4f 39 36 36 36 35 31 "944342" "NO966651"
00 00 00 00 00 00 70 f7 88 00 00 00 00 00 00 00
30 32 32 20 20 41 53 00 d3 54 4f 54 41 4c 20 4b “022” “AS” “总 k”
4f 4e 54 52 4f 4c 4c 20 41 53 20 00 c9 30 32 38 "ONTROLL AS" "028"
37 30 34 33 33 00 c9 32 30 32 31 30 32 31 31 00 "70433" "20210211"
00 00 00 00 00 00 70 f7 88 00 00 00 00 00 00 00

这就是我从卡中读取的方式:

Tag tagFromIntent = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG);
MifareClassic mfc = MifareClassic.get(tagFromIntent);

这是我用于在 for 循环中读取的代码:

 data = mfc.readBlock(bIndex + block); 

然后将数据转换为 UTF8 进行打印,我使用:

   public String convertByteArrayToUTF8(byte[] bytes){
    String encoded = null;
    try {
        encoded = new String(bytes, StandardCharsets.UTF_8);
    }
    catch (Exception e){
        encoded = new String(bytes, Charset.defaultCharset());
    }
    return encoded;
}

我尝试过使用 ASCII、UTF-16 等,但没有成功。

标签: androidformatnfcmifarecontactless-smartcard

解决方案


首先是问题标题的大声笑。当我还是新手时,我也处于同样的境地。没有在线教程为您提供从 Mifare 经典卡读取数据的确切代码。

首先了解 Mifare 卡的内存结构。

Mifare Classic 的内存分为扇区,扇区也分为 16 字节的块。

MIFARE Classic 1K 卡有 16 个扇区,每个扇区分为四个块。如果我们进行数学计算,我们可以计算出内存结构是怎样的:16 字节(1 块)* 4 块 * 16 扇区 = 1024 字节。

在此处输入图像描述

MIFARE Classic 4K卡有40个扇区,其中32个分为4个区块,其余8个分为16个区块。16 字节(1 块)* 4 块 * 32 扇区 + 16 字节(1 块)* 16 块 * 8 扇区 = 4096 字节。内存结构如下:

在此处输入图像描述

块上的数字表示它的索引。每个扇区都受到扇区最后一个块中写入的站点密钥的保护。例如,块 3 包含扇区 1 的站点密钥,块 7 包含扇区 2。每个扇区的最后一个块还包含访问条件信息,例如“写入”、“读取”和“读写”。下图演示了最后一个块的组成:

在此处输入图像描述

而且,卡中写入的数据是二进制的,即;0 & 1。

现在,您需要按照以下步骤读取数据:

step1:检查设备是否支持NFC。

step2:检查设备是否有NXP芯片(尤其是读取Mifare经典卡)。

第三步:实例化 NFC 管理器和 NFC 适配器并定义您要读取的卡的技术列表。

step4:请求访问设备NFC的权限。

step5:创建一个检测卡的意图并指定您要读取的MIME类型(在大多数情况下它是所有MIME类型)。

step6:在 onResume() 和 onPause() 中启用和禁用适配器的前台调度,以便您的应用程序在您的活动处于前台时获得读取卡的优先级。

step7:当卡与设备接触时,您可以从以下位置获取标签信息intent.getParcelableExtra(NfcAdapter.EXTRA_TAG);

step8:读取卡信息ie;卡类型,技术列表等。

step9:要读取卡中的数据,您需要通过上面检索到的标签信息连接到卡。

step10:遍历所有扇区。使用默认密钥验证每个扇区 // https://developer.android.com/reference/android/nfc/tech/MifareClassic.html#authenticateSectorWithKeyA(int,%20byte[])

step11:认证成功后读取每个扇区块中的二进制数据。

step12:将二进制数据转换为字符串数据,以便我们读取。

step13:就是这样,对数据做任何你想做的事情。

惊喜!在我的 github 存储库中获取完整的工作代码: https ://github.com/codes29/RFIDReader

注意:我很同情您作为新手的感受,并在没有合适教程的情况下完成了这项任务。因此,我更新了经过几天努力编写的代码。

这是成功验证并读取数据后您将获得的示例。我扫描的卡现在是空的。但是如果这里有数据,那么它肯定会在这里而不是 0。

/tmp/mozilla_mobulous0/Screenshot_20190221-124444.png

干杯! 快乐的编码兄弟!


推荐阅读