PythonNTAG 424 NFC芯片的CRC计算
Python CRC calculation for the NTAG 424 NFC chip
我目前正在使用具有 AES-128 加密功能的 NXP NTAG 424 chips。
每当设置新密钥时,该芯片都需要计算 crc32 校验值(参见 datasheet 11.6.1/Page 67). According to the data sheet, the crc is "computed according to IEEE Std802.3-2008". The application note(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 标准中引用的算法之间的任何区别。
示例的 CRC 是 IEEE Std802.3(或等效的 CCITT V.42)的 32 位 CRC 的 COMPLEMENT具体说明,我详述there参考。这是在此标签中使用标准 CRC 变体的另一种情况:与所有 ISO/IEC 14443 A 类标签一样,其错误检测(最多 848 kbit/s)使用 16 位 CRC 的变体IEEE Std802.3(或等效的 CCITT V.42)指定的,具有不同的初始值并且缺少最终补码。
这是与问题的测试向量相匹配的独立代码:
# 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())
What am I doing wrong?
- 相信制造商忠实地执行了自己的规范。
- 期望
binascii.crc32
的输出是大端;它是小字节序的,并且在电信中必须如此以保留 CRC32 的突发错误检测 属性。在 binascii.crc32
的规范中将 int
作为输出是一个疏忽,当使用 bytearray
作为其输入时,几乎不可能出现字节顺序错误。
我们可以而且可能应该使用 binascii.crc32
,它是本机的并使用预先计算的 table,因此速度更快(但可能更容易受到与缓存相关的侧信道攻击).
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())
我目前正在使用具有 AES-128 加密功能的 NXP NTAG 424 chips。
每当设置新密钥时,该芯片都需要计算 crc32 校验值(参见 datasheet 11.6.1/Page 67). According to the data sheet, the crc is "computed according to IEEE Std802.3-2008". The application note(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 标准中引用的算法之间的任何区别。
示例的 CRC 是 IEEE Std802.3(或等效的 CCITT V.42)的 32 位 CRC 的 COMPLEMENT具体说明,我详述there参考。这是在此标签中使用标准 CRC 变体的另一种情况:与所有 ISO/IEC 14443 A 类标签一样,其错误检测(最多 848 kbit/s)使用 16 位 CRC 的变体IEEE Std802.3(或等效的 CCITT V.42)指定的,具有不同的初始值并且缺少最终补码。
这是与问题的测试向量相匹配的独立代码:
# 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())
What am I doing wrong?
- 相信制造商忠实地执行了自己的规范。
- 期望
binascii.crc32
的输出是大端;它是小字节序的,并且在电信中必须如此以保留 CRC32 的突发错误检测 属性。在binascii.crc32
的规范中将int
作为输出是一个疏忽,当使用bytearray
作为其输入时,几乎不可能出现字节顺序错误。
我们可以而且可能应该使用 binascii.crc32
,它是本机的并使用预先计算的 table,因此速度更快(但可能更容易受到与缓存相关的侧信道攻击).
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())