我最近开始研究MD5哈希(用Java),虽然我找到了帮助我实现这一目标的算法和方法,但我还是想知道它是如何工作的。
首先,我从this 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中使用位移的任何需要,所以我对此有点生疏。有人足以说明(简单来说)上述代码究竟是如何进行转换的? “&GT;&GT;&gt;” 中?
我还在StackOverflow上找到了其他解决方案,例如使用BigInteger的here和here:
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();
}
为什么这样做也有效,哪种方式更有效?
感谢您的时间。
答案 0 :(得分:10)
private static String convertToHex(byte[] data) {
StringBuffer buf = new StringBuffer();
for (int i = 0; i < data.length; i++) {
到目前为止......只是基本设置并开始循环以遍历数组中的所有字节
int halfbyte = (data[i] >>> 4) & 0x0F;
转换为十六进制时的字节是两个十六进制数字或8个二进制数字,具体取决于您查看它的基数。上述语句将高4位向下移位(&gt;&gt;&gt;是无符号右移)和逻辑AND使用0000 1111,结果是一个等于字节高4位的整数(第一个十六进制数字)。
说23是输入,这是二进制的0001 0111。移位使得逻辑AND将其转换为0000 0001。
int two_halfs = 0;
do {
这只是将do / while循环设置为运行两次
if ((0 <= halfbyte) && (halfbyte <= 9))
buf.append((char) ('0' + halfbyte));
else
buf.append((char) ('a' + (halfbyte - 10)));
这里我们显示的是实际的十六进制数字,基本上只是使用零或一个字符作为起点并向上移动到正确的字符。第一个if语句覆盖所有数字0-9,第二个覆盖所有数字10-15(a-f,十六进制)
再一次,使用我们的十进制0000 0001示例等于1.我们陷入上面的if块并将'1'加1以获得字符'1',将其附加到字符串并继续
halfbyte = data[i] & 0x0F;
现在我们将整数设置为恰好等于字节中的低位并重复。
同样,如果我们的输入是23 ... 0001 0111,则逻辑AND变为0000 0111,即十进制7。重复上述相同的逻辑,显示字符“7”。
} while(two_halfs++ < 1);
现在我们继续前进到数组中的下一个字节并重复。
}
return buf.toString();
}
为了回答您的下一个问题,Java API已经在BigInteger中内置了一个基本转换实用程序。请参阅toString(int radix)文档。
我不知道Java API使用的实现,我不能肯定地说,但我愿意打赌,Java实现比你发布的第一个简单算法更有效。
答案 1 :(得分:2)
回答这个问题:
为什么这样做呢
没有。至少,与循环版本不同。 new BigInteger(...)。toString(16)将不会显示前一版本的前导零。通常用于写出一个字节数组(特别是一个表示类似哈希的数组),你会想要一个固定长度的输出,所以如果你想使用那个版本,你必须适当地填充它。
答案 2 :(得分:1)
有关位移的详细说明请查看以下SO问题中的答案 What are bitwise shift (bit-shift) operators and how do they work?
他似乎试图将一个字节转换为一个小于16的数字,这样他就可以很容易地确定该字节用代码表示的那个字符
if ((0 <= halfbyte) && (halfbyte <= 9))
buf.append((char) ('0' + halfbyte));
else
buf.append((char) ('a' + (halfbyte - 10)));
这是一个简单的答案,但我不是那么明亮= D
答案 3 :(得分:0)
这些东西你不必自己写,因为它已经用apache-commons-codec编写了:
import org.apache.commons.codec.binary.Hex;
...
Hex.encodeHexString(byte[] array)
Hex
类中有许多更有用的方法。