2016-07-25 84 views
1

我試圖在Java中複製了Python 2.7函數的行爲,但在運行(看似)相同的字節序列時,我得到了不同的結果SHA-256哈希。這些字節是通過以特定的方式(我的Python代碼示例的第二行)處理一個非常大的整數(準確地說2048位長)生成的。在Python和Java中散列原始字節會產生不同的結果

對於我的示例,原始的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包含含有在上面的Python的例子相同的數量big_int一個BigInteger對象)

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")。我做了這兩個出於同樣的原因 - 在我的測試中,撥打toByteArray()BigInteger返回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似乎相關),但沒有找到任何東西來幫助我。在此先感謝,如果沒有其他的閱讀這個冗長的問題! :)

+0

誰downvoted這個問題?老實說,如果這個問題沒有解決,我不知道你會遇到什麼樣的問題。我的想法很難理解。 –

回答

2

在Java中,您已經獲得了緩衝區中的數據,但光標位置都是錯誤的。你已經寫入字節緩衝區數據後它看起來像這樣,在X的代表你的數據和的是在緩衝區中寫入的字節:

xxxxxxxxxxxxxxxxxxxx00000000000000000000000000000000000000000 
        ^position        ^limit 

光標定位在你寫的數據之後。此時的讀取將從position讀取到limit,這是您未寫入的字節。

相反,你要這樣:

xxxxxxxxxxxxxxxxxxxx00000000000000000000000000000000000000000 
^ position  ^limit 

在位置爲0,上限是你寫的字節數。要到達那裏,請致電flip()。從概念上翻轉緩衝區將其從寫入模式切換到讀取模式。我說「概念上」,因爲ByteBuffers沒有明確的讀寫模式,但你應該像看待它們一樣來考慮它們。

(相反的操作是compact(),可以追溯到讀模式。)

+1

你還需要提到'buff.array()'是整個緩衝區支持數組,而不僅僅是寫了哪些可能是不同的東西。 –

+0

在這種情況下,我給ByteBuffer分配了與其放入的數據大小相同的大小,所以後備數組的大小相同 - 在我不太理解緩衝區處理其後備數組的方式之前,但它現在更有意義。謝謝! – jming

相關問題