2012-12-18 56 views
4

我有计算字符串SHA-256哈希的代码,并且注意到我从Android和Oracle Java 7获得了不同的哈希以获得相同的字符串。我的散列码转换成Stringbyte[]使用Android和Oracle进行字符串字符编码Java

byte[] data = stringData.getBytes("UTF-16"); 

使用UTF-16编码,我从甲骨文的Java和Android的Java不同的结果。这是我散列字符串:

// Test Code: 
String toHash = "testdata"; 
System.out.println("Hash: " +DataHash.getHashString(toHash)); 

并获得论文哈希使用UTF-16:

Hash: a1112a0363a59097a701e38398e1fdfef3049358aee81b77ecaad2924a426bc5 [Oracle Java 7] 
Hash: 811b723aee07c7a52456fc57a5683e73649075a373d341f7257bf73575111ba3 [Android 2.2] 

然而,UTF-8,我得到了相同的散列两者的JRE:

Hash: 810ff2fb242a5dee4220f2cb0e6a519891fb67f2f828a6cab4ef8894633b1f50 [Oracle Java 7] 
Hash: 810ff2fb242a5dee4220f2cb0e6a519891fb67f2f828a6cab4ef8894633b1f50 [Android 2.2] 

是否存在某种类型的endian-ness问题,这会导致不同平台上的不同结果?我应该如何真正准备一个字符串以独立于平台的方式进行散列?

编辑: 哎呀,答案是相当明显的,一旦你读了关于UTF-16多一点。有两种版本的UTF-16(大端和小端)。你只需要指定getBytes()应该使用哪个版本,并且散列值是相同的。挑一个:

  • UTF-16LE
  • UTF-16BE

回答

1

按照documentation of Orcale Java

解码时,UTF-16字符集解释一个字节顺序标记到 指示流但默认为大端的字节顺序如果 没有字节顺序标记编码时,它使用大端字节 命令并写入一个大端字节顺序标记。

这意味着普通UTF-16应该始终以Oracle Java中的Big Endian编码。

然后从Android Java documentation

Charset   Encoder writes 
UTF-16BE   BE, no BOM 
UTF-16LE   LE, no BOM 
UTF-16    BE, with BE BOM 

所以在任何一个错误,或者文档。两者都必须是Big Endian,并写入BOM,所以应该没有任何区别。

一般而言,您应该更喜欢UTF-16BE/LE而不是UTF-16,但在这种情况下,它似乎是一个错误。

+0

啊,有趣。它看起来像Android(2。2至少)正在进行小端转换: Oracle Java 7: “UTF-16:[-2,-1,0,116,0,101,0,115,0,116,0,100 ,0,97,0,116,0,97]' Android Java 2.2: 'UTF-16:[-1,-2,116,0,101,0,115,0,116,0,100 ,0,97,0,116,0,97,0]' –

+0

@TajMorton'-1,-2,116,0..'是Little Endian,带有LE BOM。这是从Android?无论如何,它显然与Android文档相矛盾。 – Esailija

+0

对不起,我的格式化已被破坏,并在我准备好之前意外发布。 Oracle Java 7为'[-2,-1,0,116]'提供了“UTF-16”,而Android 2.2提供了'[-2,-1,116,0]'。所以是的,它看起来像是用LE BOM生产LE。 –

0

显示你的哈希代码,但它可能是做错了什么。哈希结果是byte[],所以不需要首先将字符串转换为byte[]。要将二进制散列值转换为String,请使用Base64或十六进制编码。