将二进制SHA-1摘要转换为十六进制字符串的奇怪算法

时间:2013-04-27 16:08:57

标签: java integer hex sha1

在Internet上我发现这段代码生成SHA1哈希:

        public static String hash(String str) {
            try {
                    MessageDigest mg = MessageDigest.getInstance("SHA-1");
                    byte[] result = mg.digest(str.getBytes());
                    StringBuffer sb = new StringBuffer();
                    for (int i = 0; i < result.length; i++) {
                            sb.append(Integer.toString((result[i] & 0xff) + 0x100, 16).substring(1));
                    }
                    return sb.toString();
            } catch (NoSuchAlgorithmException e) {
                    System.err.println("SHA-1 not found.");
                    return "";
            }
    }

但为什么会有(result[i] & 0xff) + 0x100

2 个答案:

答案 0 :(得分:6)

字节已签名:它们可能是否定的。当Integer.toString()处理负字节时,会生成以“FFFFFF”开头的字符串,但这不会发生正字节,因此结果字符串的长度不固定。 & 0xff将字节转换为无符号整数。然后添加0x100以确保十六进制字符串为3个字符长;这是必需的,因为我们想要一个每个字节有2个十六进制数字的字符串,但是0到15之间的字节只产生1个字符。最后,使用substring(1)丢弃第三个数字。

我建议用StringBuilder替换StringBuffer,因为它稍微高效一点,并且还指定了初始缓冲区长度:

StringBuilder sb = new StringBuilder(result.length * 2);

答案 1 :(得分:1)

&amp; 0xff是为了防止字节被提升为大于8位的符号并进行符号扩展。

签名扩展在这里是一个非常现实的问题,因此至少需要0xff。