誰かがバイト配列から16進文字列への変換を説明できますか?
質問
最近(Javaで)MD5ハッシュを調べ始めました。それを実現するのに役立つアルゴリズムとメソッドを見つけましたが、実際にどのように機能するのか疑問に思っています。
1つには、このURL から次の情報が見つかりました。
private static String convertToHex(byte[] data) {
StringBuffer buf = new StringBuffer();
for (int i = 0; i < data.length; i++) {
int halfbyte = (data[i] >>> 4) & 0x0F;
int two_halfs = 0;
do {
if ((0 <= halfbyte) && (halfbyte <= 9))
buf.append((char) ('0' + halfbyte));
else
buf.append((char) ('a' + (halfbyte - 10)));
halfbyte = data[i] & 0x0F;
} while(two_halfs++ < 1);
}
return buf.toString();
}
Javaでビットシフトを使用する必要はありませんでしたので、少し錆びています。上記のコードがどのように正確に変換するかを(簡単に言えば)説明するのに十分な人? <!> quot; <!> gt; <!> gt; <!> gt; <!> quot;?
try {
String s = "TEST STRING";
MessageDigest md5 = MessageDigest.getInstance("MD5");
md5.update(s.getBytes(),0,s.length());
String signature = new BigInteger(1,md5.digest()).toString(16);
System.out.println("Signature: "+signature);
} catch (final NoSuchAlgorithmException e) {
e.printStackTrace();
}
なぜこれも機能するのか、どの方法がより効率的か
お時間をいただきありがとうございます。
解決
private static String convertToHex(byte[] data) {
StringBuffer buf = new StringBuffer();
for (int i = 0; i < data.length; i++) {
ここまでは、基本的なセットアップとループを開始して配列内のすべてのバイトを処理する
int halfbyte = (data[i] >>> 4) & 0x0F;
16進数に変換されたときのbyteは、2桁の16進数字または8桁の2進数字になります。上記のステートメントは、上位4ビットを下にシフトします(<!> gt; <!> gt; <!> gt ;は符号なしの右シフト)であり、結果がバイトの上位4ビット(最初の16進数)に等しい整数になるように0000 1111と論理ANDします。
Say 23は入力でした。これはバイナリで0001 0111です。シフトが行われ、論理ANDがこれを0000 0001に変換します。
int two_halfs = 0;
do {
これは、do / whileループを2回実行するように設定するだけです
if ((0 <= halfbyte) && (halfbyte <= 9))
buf.append((char) ('0' + halfbyte));
else
buf.append((char) ('a' + (halfbyte - 10)));
ここでは、実際の16進数を表示しています。基本的には、ゼロまたは文字を開始点として使用し、正しい文字にシフトします。最初のifステートメントは0〜9のすべての数字をカバーし、2番目のステートメントは10〜15のすべての数字をカバーします(16進数でa〜f)
再び、10進数で0000 0001の例を使用すると、1になります。ブロックの上部でキャッチされ、「0」文字に1を追加して文字「1」を取得し、文字列に追加して先に進みます。
halfbyte = data[i] & 0x0F;
バイトの下位ビットにちょうど等しくなるように整数を設定し、繰り返します。
ここでも、入力が23 ... 0001 0111の場合、論理ANDは0000 0111になり、10進数では7になります。上記と同じロジックを繰り返すと、文字「7」が表示されます。
} while(two_halfs++ < 1);
ここで、配列の次のバイトに移動して繰り返します。
}
return buf.toString();
}
次の質問に答えるために、Java APIにはすでにBigIntegerに組み込まれた基本変換ユーティリティがあります。 toString(int radix )ドキュメント。
Java APIで使用される実装を知らないので、確かなことは言えませんが、Java実装は、最初に投稿したやや単純なアルゴリズムよりも効率的であると確信しています。
他のヒント
このビットに答えるには
なぜこれも機能するのか
そうではありません。少なくとも、ループバージョンとは異なります。 new BigInteger(...)。toString(16)は、前のバージョンのように先行ゼロを表示しません。通常、バイト配列(特にハッシュのようなものを表すもの)を書き出すような場合、固定長の出力が必要になるため、そのバージョンを使用する場合は適切にパディングする必要があります。
ビットシフトの詳細な説明については、次のSOの質問の回答を参照してください。 ビットシフト(ビットシフト)演算子とは何ですか?
彼は、そのバイトがコードで表す文字を簡単に判断できるようにすることで、1バイトを16未満の数値に変換しようとしているようです
if ((0 <= halfbyte) && (halfbyte <= 9))
buf.append((char) ('0' + halfbyte));
else
buf.append((char) ('a' + (halfbyte - 10)));
これは単純な答えですが、とにかくそれほど明るくはありません= D
これらは、apache-commons-codecですでに記述されているため、自分で記述する必要はありません。
import org.apache.commons.codec.binary.Hex;
...
Hex.encodeHexString(byte[] array)
Hex
クラスにはさらに多くの便利なメソッドがあります。