用Android和oraclejava进行字符串编码
我有计算字符串的SHA-256散列的代码,并且注意到对于同一个字符串,我从Android和Oracle Java 7获得了不同的散列。我的哈希代码将用Android和oraclejava进行字符串编码,java,android,unicode,character-encoding,Java,Android,Unicode,Character Encoding,我有计算字符串的SHA-256散列的代码,并且注意到对于同一个字符串,我从Android和Oracle Java 7获得了不同的散列。我的哈希代码将字符串转换为字节[],使用: byte[] data = stringData.getBytes("UTF-16"); 通过UTF-16编码,我从Oracle Java和Android Java中得到了不同的结果。这是我正在散列的字符串: // Test Code: String toHash = "testdata"; System.out.pr
字符串
转换为字节[]
,使用:
byte[] data = stringData.getBytes("UTF-16");
通过UTF-16编码,我从Oracle 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
- 显示您的哈希代码,但它可能做错了什么。散列的结果是一个
字节[]
,因此首先不需要将字符串转换为字节[]
。要将二进制哈希值转换为字符串
,请使用Base64或十六进制编码 根据:
解码时,UTF-16字符集将字节顺序标记解释为
指示流的字节顺序,但如果
没有字节顺序标记编码时,它使用大端字节
排序并写入大端字节顺序标记。
这意味着在Oracle Java中,普通的UTF-16
应该始终编码为Big-Endian
然后从:
因此,其中一个或文档中都存在缺陷。两者都必须是Big-Endian,并且写BOM,所以应该没有任何区别
一般来说,您应该更喜欢
UTF-16BE/LE
而不是UTF-16
,但在这种情况下,这似乎是一个bug。Ahh,很有趣。它看起来确实像Android(至少2.2)正在进行小的endian转换: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,116,0,100,0,97,0,116,97,0]
@TajMorton-1,-2,116,0..
是小尾端,带有LE BOM。这是安卓的吗?无论如何,它显然与Android文档相矛盾。对不起,我的格式被破坏了,在我准备好之前我不小心发布了。Oracle Java 7给出了带有“UTF-16”的[-2,-1,0,116]
,而Android 2.2给出了[-2,-1,116,0]
。所以是的,它看起来像是在用一个LE BOM生产LE。
Charset Encoder writes
UTF-16BE BE, no BOM
UTF-16LE LE, no BOM
UTF-16 BE, with BE BOM