如何用 Python 计算 CRC32 以匹配在线结果?
Posted
技术标签:
【中文标题】如何用 Python 计算 CRC32 以匹配在线结果?【英文标题】:How to calculate CRC32 with Python to match online results? 【发布时间】:2015-07-17 12:06:00 【问题描述】:我正在尝试使用 Python 计算/生成一些随机字符串的 CRC32 哈希,但它们与我从在线资源生成的值不匹配。这是我在我的电脑上做的事情,
>>> import binascii
>>> binascii.crc32('hello-world')
-1311505829
另一种方法,
>>> import zlib
>>> zlib.crc32('hello-world')
-1311505829
上述结果相同的事实告诉我,我正确地调用了该函数。但是,如果我去以下在线资源,
http://www.lammertbies.nl/comm/info/crc-calculation.html http://crc32-checksum.waraxe.us/ http://www.md5calc.com/(从下拉列表中选择 CRC32B)对于字符串“hello-world”,它们都给出相同的值 = b1d4025b
有人知道我需要做什么才能获得匹配的结果吗?
当我输入这个问题时,我突然想到我可能需要将我的 Python 结果转换为十六进制,
>>> hex(zlib.crc32('hello-world'))
'-0x4e2bfda5'
不幸的是,这也没有帮助。 :(
【问题讨论】:
@Yeo:hello-world
的正确 CRC32 是 0xb1d4025b
作为无符号整数,-0x4e2bfda5
作为有符号整数。他显然不知道这两个值是如何相关的,因此提出了这个问题。
【参考方案1】:
Python 2(与 py3 不同)正在执行带符号的 32 位 CRC。
那些网站正在执行无符号 32 位 CRC。
其他的值是一样的,从这里可以看出:
>>> 0x100000000 - 0xb1d4025b == 0x4e2bfda5
True
从 32 位有符号转换为 32 位无符号的一种快速方法是:*
>>> -1311505829 % (1<<32)
2983461467
或者,十六进制:
>>> hex(-1311505829 % (1<<32))
'0xb1d4025b'
& 0xFFFFFFFF
或 % 0x100000000
或 & (2**32-1)
或 % (2**32)
等都是执行相同位旋转的等效方式;它只是归结为您认为最易读的一个。
* 这仅适用于执行整数除法的语言,例如 Python (-3 // 2 == -2
);在执行截断整数除法的语言中,如 Java (-3 / 2 == -1
),你仍然会得到一个负数。在甚至不需要除法和 mod 正确组合的语言中,比如 C,所有的赌注都没有了——但在 C 中,你只需将字节转换为你想要的类型......
【讨论】:
Python is doing a signed 32-bit CRC
请注意:在 Python3 中,这已更改为运行无符号 CRC。请参阅docs。
这不取决于如何进行除法,而是%
的定义。在大多数语言中,它被定义为以下之一:x % y == x - floor(x / y) * y
(“与除数相同的符号”,Python 所做的。如此积极,因为2**32
是正数)、x % y == x - truncate(x / y) * y
(“与除数相同的符号”)或@ 987654337@(“正模”)。通常这与 / 相同,但并非总是如此。要在其他语言中始终使用正整数除法,您可以执行以下操作:def positive_mod(a, b): return ((a % b) + b) % b
。见en.wikipedia.org/wiki/Modulo_operation【参考方案2】:
zlib.crc32 documentation 建议使用以下方法“在所有 Python 版本和平台上生成相同的数值”。
import zlib
hex(zlib.crc32(b'hello-world') & 0xffffffff)
结果如预期的那样是0xb1d4025b
。
【讨论】:
我很好奇为什么跨平台会有所不同。 Python 的行为不是一刀切吗? (忽略 2.x 和 3.x 的差异) @chronodekar:我相信在源代码中找到它不会太难;如果您自己找不到,您可以创建一个新问题。但是从快速测试来看,它在 Mac 2.7 和 Linux 2.7 上是负面的,在 Windows 2.7 和 Mac 3.5 上是正面的,所以我很确定这是一个平台问题,而不是 2-vs.-3 问题。或者也许是两者的结合。 (无论如何,它对 OP 没有帮助,它的 Python 显然确实签署了 crc32,就像我的 Mac 2.7 一样......) @chronodekar 我在 Python 文档中没有找到任何明确的答案,所以我编辑了我的答案以在所有 Python 版本和平台上具有相同的行为。 请注意,Python 3 保证 binascii.crc32 返回无符号值,而 2.6 和 2.7 应保证有符号值,因此平台差异不应影响这一点。【参考方案3】:python 似乎返回一个有符号整数(因此是负数),而其他的返回一个无符号整数。
我尝试使用 2^32 的模数,它给出的值与这些网站相同。
>>> hex(zlib.crc32(b'hello-world')% 2**32)
'0xb1d4025b'
【讨论】:
以上是关于如何用 Python 计算 CRC32 以匹配在线结果?的主要内容,如果未能解决你的问题,请参考以下文章