4

文字列の SHA-256 ハッシュを計算するコードがあり、同じ文字列に対して Android と Oracle Java 7 から異なるハッシュを取得していることに気付きました。私のハッシュコードは次のように変換Stringbyte[]ます:

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]

さまざまなプラットフォームでさまざまな結果を引き起こしている何らかの種類のエンディアンの問題が発生していますか? プラットフォームに依存しない方法でハッシュされる文字列を実際にどのように準備すればよいですか?

編集: おっと、UTF-16についてもう少し読んだら、答えはかなり明白です。UTF-16 には 2 つのバージョン (ビッグ エンディアンとリトル エンディアン) があります。getBytes() が使用するバージョンを指定するだけでよく、ハッシュは同じです。次のいずれかを選択します。

  • UTF-16LE
  • UTF-16BE
4

2 に答える 2

1

Orcale Javaのドキュメントによると:

デコード時に、UTF-16文字セットはバイトオーダーマークを解釈してストリームのバイトオーダーを示しますが、バイトオーダーマークがない場合はデフォルトでビッグエンディアンになります。エンコード時には、ビッグエンディアンのバイトオーダーを使用し、ビッグエンディアンのバイトオーダーマークを書き込みます。

つまり、プレーンUTF-16は常にOracleJavaでビッグエンディアンとしてエンコードする必要があります。

次に、Android Javaのドキュメントから:

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

したがって、いずれか、またはドキュメントにバグがあります。どちらもビッグエンディアンであり、BOMを記述している必要があるため、違いはありません。

一般的には、よりも優先する必要がありますUTF-16BE/LEUTF-16、この場合はバグのようです。

于 2012-12-18T10:21:01.263 に答える
0

ハッシュコードを表示しますが、おそらく何か間違ったことをしています. ハッシュの結果は であるbyte[]ため、そもそも文字列から変換する必要はありませんbyte[]。バイナリ ハッシュ値をStringBase64 または 16 進エンコーディングに変換する場合。

于 2012-12-18T05:37:37.477 に答える