Python计算NTAG 424 NFC芯片的CRC值

4

我目前正在使用NXP NTAG 424芯片,它具有AES-128加密功能。

每当设置新的密钥时,该芯片需要计算crc32校验值(详见数据表11.6.1/第67页)。 根据数据表,crc是“按照IEEE Std802.3-2008计算的”。应用笔记甚至为此提供了一个例子(第6.16.1页/第39页)。

new_key: F3847D627727ED3BC9C4CC050489B966
CRC32(new_key): 789DFADC

然而,当我尝试使用Python和binascii crc32库复制结果时,结果是不同的:

>>> from binascii import unhexlify, crc32
>>> new_key = unhexlify('F3847D627727ED3BC9C4CC050489B966')
>>> print(hex(crc32(new_key)))
0x23056287     # Not the CRC I was looking for

这份文档经常颠倒字节顺序,但是命令不会受到影响。

>>> print(hex(crc32(new_key[::-1])))
0x9453faa7

所以问题是:我做错了什么?我尝试查阅引用的标准,但由于我的表面知识,我无法发现标准crc32和IEEE标准中引用的算法之间的任何区别。同时,

也毫无乐趣可言。

2个回答

4
该示例的CRC是IEEE Std802.3(或等效的CCITT V.42)指定的32位CRC的补码,我在此处详细说明。这是在此标签中使用标准CRC的变体的另一种情况:像所有ISO / IEC 14443类型A标签一样,其误差检测(高达848 kbit / s)使用IEEE Std802.3(或等效的CCITT V.42)指定的16位CRC的变体,具有不同的初始值和缺少最终的补码。
以下是符合问题测试向量的自包含代码:
# compute the CRC32 for NTAG424
# Ethernet / CCITT V42 CRC32, less final complement
def NTAG424CRC(m):
    c = 0xFFFFFFFF
    for b in m:
         c ^= b;
         for n in range(8):
             c = (c>>1)^(0xEDB88320&-(c&1))
#   c ^= 0xFFFFFFFF  # required by Ethernet / CCITT V42
    return c.to_bytes(4,'little')

# demo, expected value 789dfadc
print(NTAG424CRC(bytearray.fromhex('F3847D627727ED3BC9C4CC050489B966')).hex())

在线测试!

我做错了什么?

  • 相信制造商会忠实地实现自己的规范。
  • 期望 binascii.crc32 的输出是大端字节序;实际上它是小端字节序,并且在电信领域中必须保持这种方式以维护 CRC32 的突发错误检测属性。在规范中使用 int 作为输出是一个疏忽,如果使用像输入一样的 bytearray 就几乎不会出现字节序错误。

我们可以并且可能应该使用本地的 binascii.crc32,它使用预先计算的表格,因此更快(但可能更容易受到缓存相关的侧信道攻击)。

import binascii

# compute the CRC32 for NTAG424 using binascii.crc32
# Ethernet / CCITT V42 CRC32, less final complement
def NTAG424CRC(m):
    return (binascii.crc32(m)&0xFFFFFFFF^0xFFFFFFFF).to_bytes(4,'little')
# &0xFFFFFFFF deals with negative output; it can be removed under Python 3
# ^0xFFFFFFFF undoes the complement rightly done by binascii.crc32

# demo, expected value 789dfadc
print(NTAG424CRC(bytearray.fromhex('F3847D627727ED3BC9C4CC050489B966')).hex())

在此在线尝试!

该链接可供您在线体验!

1
我刚刚尝试了NTAG 424,它按预期工作,但只有在您尝试更改密钥之前直接进行身份验证时才有效(至少对我而言,这可能与我的命令计数器增量有关(尽管它对我的所有其他命令都有效),或者是NTAG 424的另一个未记录的“功能”)。 但感谢解决方案,包括binascii.crc32调用,它非常好用! - U_flow
我做错了什么?相信制造商忠实地实现了自己的规格说明。- 我笑得很开心=)非常正确。另外,非常好的答案,谢谢! - oberstet

0
function NTAG424CRC(m) {
  let c = 4294967295; // 0xffffffff
  for (let i = 0; i < m.length; i++) {
    c = c ^ m[i];
    for (let j = 0; j < 8; j++) {
      c = (c >>> 1) ^ (3988292384 & -(c & 1));   // 3988292384 === 0xEDB88320
    }
  }

  let buffer = new ArrayBuffer (4);     // 4 === length of crc32 in decimal
  let view = new DataView(buffer);
  view.setUint32(0, c, true);
  let bytes = new Uint8Array(buffer);
  return bytes;
}

let crc32Value = NTAG424CRC(
  new Uint8Array([
    0xf3, 0x84, 0x7d, 0x62, 0x77, 0x27, 0xed, 0x3b, 0xc9, 0xc4, 0xcc, 0x05,
    0x04, 0x89, 0xb9, 0x66,
  ])
);

console.log(Buffer.from(crc32Value).toString("hex").toUpperCase()); //789DFADC
//javascript CRC32 calculation for ntag 424 DNA

根据目前的写法,你的回答不够清晰。请编辑以添加更多细节,以帮助其他人理解这如何回答所提出的问题。你可以在帮助中心找到关于如何撰写好回答的更多信息。 - undefined

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