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

2024-06-28 21:03:04 发布

您现在位置:Python中文网/ 问答频道 /正文

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

对于我的示例,原始的2048位整数在Python和Java中分别存储为big_int和{},两个变量都包含相同的数字。在

我要复制的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个指纹只是为了看看引擎盖下面发生了什么):

^{pr2}$

下面是到目前为止我的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以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似乎特别相关),但没有找到任何可以帮助我的东西。提前感谢你,如果没有别的,只是为了阅读这个冗长的问题!:)


Tags: 代码示例raw字节javaoutsystembuff
1条回答
网友
1楼 · 发布于 2024-06-28 21:03:04

在Java中,数据在缓冲区中,但是光标位置都是错误的。将数据写入ByteBuffer后,如下所示,x表示数据,0是缓冲区中未写入的字节:

xxxxxxxxxxxxxxxxxxxx00000000000000000000000000000000000000000
                    ^ position                               ^ limit

光标位于所写数据的后面。此时的read将从position读取到{},这是您尚未写入的字节。在

相反,您希望:

^{pr2}$

其中,位置为0,限制为已写入的字节数。要到达那里,请致电^{}。翻转缓冲区从概念上将其从写入模式切换到读取模式。我之所以说“概念上的”,是因为bytebuffer没有明确的读写模式,但是你应该把它们当作是有读写模式的。在

(相反的操作是^{},它返回到读取模式。)

相关问题 更多 >