gpt4 book ai didi

java - 在 Python 和 Java 中散列原始字节会产生不同的结果

转载 作者:行者123 更新时间:2023-11-30 08:34:56 27 4
gpt4 key购买 nike

我正在尝试在 Java 中复制 Python 2.7 函数的行为,但是当通过 SHA-256 哈希运行(看似)相同的字节序列时,我得到了不同的结果。字节是通过以特定方式(我的 Python 代码示例的第二行)操作一个非常大的整数(正好 2048 位长)生成的。

在我的示例中,原始的 2048 位整数在 Python 和 Java 中分别存储为 big_intbigInt,并且两个变量包含相同的数字。

我正在尝试复制的 Python2 代码:

raw_big_int = ("%x" % big_int).decode("hex")

buff = struct.pack(">i", len(raw_big_int) + 1) + "\x00" + raw_big_int

pprint("Buffer contains: " + buff)
pprint("Encoded: " + buff.encode("hex").upper())

digest = hashlib.sha256(buff).digest()

pprint("Digest contains: " + digest)
pprint("Encoded: " + digest.encode("hex").upper())

运行此代码打印以下内容(请注意,我真正感兴趣的唯一结果是最后一个 - 十六进制编码的摘要。其他 3 个打印只是为了看看发生了什么引擎盖下):

'Buffer contains: \x00\x00\x01\x01\x00\xe3\xbb\xd3\x84\x94P\xff\x9c\'\xd0P\xf2\xf0s,a^\xf0i\xac~\xeb\xb9_\xb0m\xa2&f\x8d~W\xa0\xb3\xcd\xf9\xf0\xa8\xa2\x8f\x85\x02\xd4&\x7f\xfc\xe8\xd0\xf2\xe2y"\xd0\x84ck\xc2\x18\xad\xf6\x81\xb1\xb0q\x19\xabd\x1b>\xc8$g\xd7\xd2g\xe01\xd4r\xa3\x86"+N\\\x8c\n\xb7q\x1c \x0c\xa8\xbcW\x9bt\xb0\xae\xff\xc3\x8aG\x80\xb6\x9a}\xd9*\x9f\x10\x14\x14\xcc\xc0\xb6\xa9\x18*\x01/eC\x0eQ\x1b]\n\xc2\x1f\x9e\xb6\x8d\xbfb\xc7\xce\x0c\xa1\xa3\x82\x98H\x85\xa1\\\xb2\xf1\'\xafmX|\x82\xe7%\x8f\x0eT\xaa\xe4\x04*\x91\xd9\xf4e\xf7\x8c\xd6\xe5\x84\xa8\x01*\x86\x1cx\x8c\xf0d\x9cOs\xebh\xbc1\xd6\'\xb1\xb0\xcfy\xd7(\x8b\xeaIf6\xb4\xb7p\xcdgc\xca\xbb\x94\x01\xb5&\xd7M\xf9\x9co\xf3\x10\x87U\xc3jB3?vv\xc4JY\xc9>\xa3cec\x01\x86\xe9c\x81F-\x1d\x0f\xdd\xbf\xe8\xe9k\xbd\xe7c5'
'Encoded: 0000010100E3BBD3849450FF9C27D050F2F0732C615EF069AC7EEBB95FB06DA226668D7E57A0B3CDF9F0A8A28F8502D4267FFCE8D0F2E27922D084636BC218ADF681B1B07119AB641B3EC82467D7D267E031D472A386222B4E5C8C0AB7711C200CA8BC579B74B0AEFFC38A4780B69A7DD92A9F101414CCC0B6A9182A012F65430E511B5D0AC21F9EB68DBF62C7CE0CA1A382984885A15CB2F127AF6D587C82E7258F0E54AAE4042A91D9F465F78CD6E584A8012A861C788CF0649C4F73EB68BC31D627B1B0CF79D7288BEA496636B4B770CD6763CABB9401B526D74DF99C6FF3108755C36A42333F7676C44A59C93EA36365630186E96381462D1D0FDDBFE8E96BBDE76335'
'Digest contains: Q\xf9\xb9\xaf\xe1\xbey\xdc\xfa\xc4.\xa9 \xfckz\xfeB\xa0>\xb3\xd6\xd0*S\xff\xe1\xe5*\xf0\xa3i'
'Encoded: 51F9B9AFE1BE79DCFAC42EA920FC6B7AFE42A03EB3D6D02A53FFE1E52AF0A369'

现在,下面是我到目前为止的 Java 代码。当我测试它时,我得到了相同的输入缓冲区值,但得到了不同的摘要值。 (bigInt 包含一个 BigInteger 对象,其中包含与上面 Python 示例中的 big_int 相同的数字)

byte[] rawBigInt = bigInt.toByteArray();

ByteBuffer buff = ByteBuffer.allocate(rawBigInt.length + 4);
buff.order(ByteOrder.BIG_ENDIAN);
buff.putInt(rawBigInt.length).put(rawBigInt);

System.out.print("Buffer contains: ");
System.out.println( DatatypeConverter.printHexBinary(buff.array()) );


MessageDigest hash = MessageDigest.getInstance("SHA-256");
hash.update(buff);
byte[] digest = hash.digest();

System.out.print("Digest contains: ");
System.out.println( DatatypeConverter.printHexBinary(digest) );

请注意,在我的 Python 示例中,我以打包的 len(raw_big_int) + 1 开始缓冲区,而在 Java 中,我以 rawBigInt.length 开始。在用 Java 编写时,我还省略了额外的 0 字节 ("\x00")。我出于同样的原因做了这两个 - 在我的测试中,在 BigInteger 上调用 toByteArray() 返回了一个 byte 数组 以 0 字节开始,比 Python 的字节序列长 1 个字节。所以,至少在我的测试中,len(raw_big_int) + 1 等于 rawBigInt.length,因为 rawBigInt 以 0 字节和 raw_big_int 没有。

好吧,除此之外,这是 Java 代码的输出:

Buffer contains: 0000010100E3BBD3849450FF9C27D050F2F0732C615EF069AC7EEBB95FB06DA226668D7E57A0B3CDF9F0A8A28F8502D4267FFCE8D0F2E27922D084636BC218ADF681B1B07119AB641B3EC82467D7D267E031D472A386222B4E5C8C0AB7711C200CA8BC579B74B0AEFFC38A4780B69A7DD92A9F101414CCC0B6A9182A012F65430E511B5D0AC21F9EB68DBF62C7CE0CA1A382984885A15CB2F127AF6D587C82E7258F0E54AAE4042A91D9F465F78CD6E584A8012A861C788CF0649C4F73EB68BC31D627B1B0CF79D7288BEA496636B4B770CD6763CABB9401B526D74DF99C6FF3108755C36A42333F7676C44A59C93EA36365630186E96381462D1D0FDDBFE8E96BBDE76335
Digest contains: E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855

如您所见,缓冲区内容在 Python 和 Java 中看起来相同,但摘要明显不同。有人可以指出我哪里出错了吗?

我怀疑它与 Python 似乎存储字节的奇怪方式有关 - 变量 raw_big_intbuff 显示为 str 类型在解释器中,当它们自己打印出来时,带有'\x'的奇怪格式在某些地方几乎与字节本身相同,但在其他地方完全是乱码。我没有足够的 Python 经验来准确理解这里发生了什么,而且我的搜索没有结果。

此外,由于我正在尝试将 Python 代码移植到 Java 中,我不能只更改 Python - 我的目标是编写接受相同输入并产生相同输出的 Java 代码。我四处搜索(特别是 this question 似乎相关)但没有找到任何可以帮助我的东西。在此先感谢,如果只是为了阅读这个冗长的问题! :)

最佳答案

在 Java 中,您已经在缓冲区中获取了数据,但是光标位置全都错了。将数据写入 ByteBuffer 后,它看起来像这样,其中 x 代表您的数据,0 是缓冲区中未写入的字节:

xxxxxxxxxxxxxxxxxxxx00000000000000000000000000000000000000000
^ position ^ limit

光标位于您写入的数据之后。此时的读取将从 position 读取到 limit,这是您尚未写入的字节。

相反,你想要这样:

xxxxxxxxxxxxxxxxxxxx00000000000000000000000000000000000000000
^ position ^ limit

位置为 0,限制是您写入的字节数。要到达那里,请调用 flip() .翻转缓冲区在概念上将其从写入模式切换到读取模式。我说“概念上”是因为 ByteBuffers 没有明确的读写模式,但您应该将它们视为有。

(相反的操作是 compact() ,返回读取模式。)

关于java - 在 Python 和 Java 中散列原始字节会产生不同的结果,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38558820/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com