【问题标题】:Which SHA-256 is correct? The Java SHA-256 digest or the Linux commandline tool哪个 SHA-256 是正确的? Java SHA-256 摘要或 Linux 命令行工具
【发布时间】:2011-03-02 14:34:15
【问题描述】:

当我在 Java 中使用以下方法计算字符串的 SHA-256 时

public static void main(String[] args) throws NoSuchAlgorithmException {

    MessageDigest md = MessageDigest.getInstance("SHA-256");

    byte[] hash = md.digest("password".getBytes());

    StringBuffer sb = new StringBuffer();
    for(byte b : hash) {
        sb.append(Integer.toHexString(b & 0xff));
    }

    System.out.println(sb.toString());
}

我明白了:

5e884898da2847151d0e56f8dc6292773603dd6aabbdd62a11ef721d1542d8

在命令行上我执行以下操作(我需要 -n 不添加换行符):

echo -n "password" | sha256sum

得到

5e884898da28047151d0e56f8dc6292773603d0d6aabbdd62a11ef721d1542d8

如果我们更仔细地比较这些,我会发现 2 个细微差别

5e884898da2847151d0e56f8dc6292773603dd6aabbdd62a11ef721d1542d8
5e884898da28047151d0e56f8dc6292773603d0d6aabbdd62a11ef721d1542d8

或:

5e884898da28   47151d0e56f8dc6292773603d   d6aabbdd62a11ef721d1542d8
5e884898da28 0 47151d0e56f8dc6292773603d 0 d6aabbdd62a11ef721d1542d8

这两个哪个是正确的?

结果:都是,但我错了……

通过使用修复它:

    StringBuffer sb = new StringBuffer();
    for(byte b : hash) {
        sb.append(String.format("%02x", b));
    }

谢谢!

【问题讨论】:

    标签: java security hash


    【解决方案1】:

    我会做一个合理的猜测:两者都输出相同的摘要,但是在将 byte[] 结果输出为十六进制字符串的 Java 代码中,您输出的小字节值(小于 16)没有前导 0。所以一个值为“0x0d”的字节被写为“d”而不是“0d”。

    【讨论】:

    • 是的,刚刚看到你的代码更新——这就是问题所在。 Integer.toHexString() 不会写前导 0。可能最简单的方法是仅使用小于 16 的特殊情况值并在前面写一个“0”。
    • 傻我!感谢您的快速回复!我刚刚对我的 MD5 实现感到幸运。伟大的保存...
    【解决方案2】:

    罪魁祸首是toHexString。它似乎为值 6 输出 6,而 sha256sum 则输出 06Integer.toHexString() 状态的 Java 文档:

    此值被转换为十六进制(基数为 16)的 ASCII 数字字符串,没有额外的前导 0。

    字符串中的其他零不受影响,因为它们是字节的后半部分(例如,30)。

    解决它的一种方法是更改​​:

    for(byte b : hash) {
        sb.append(Integer.toHexString(b & 0xff));
    }
    

    到:

    for(byte b : hash) {
        if (b < 16) sb.append("0");
        sb.append(Integer.toHexString(b & 0xff));
    }
    

    【讨论】:

      【解决方案3】:

      他们都是对的 - 是你的 Java 代码有问题,因为它没有打印出小于 0x10 的十六进制值的前导 0。

      【讨论】:

        【解决方案4】:

        你仍然需要“echo -n”来防止尾随\n

        【讨论】:

          【解决方案5】:

          sha256sum 生成的那个似乎是正确的。您的实现似乎去掉了这两个零。

          【讨论】:

            【解决方案6】:

            使用@paxdiablo 的想法有问题,因为它显示为负数,所以

            代替:

            for(byte b : hash) {
                sb.append(Integer.toHexString(b & 0xff));
            }
            

            你可以这样做:

            for(byte b : hash) {
                if (b > 0 && b < 16) {
                    sb.append("0");
                }
                sb.append(Integer.toHexString(b & 0xff));
            }
            

            并阅读@Sean Owen 的答案。

            【讨论】:

              【解决方案7】:

              您也可以使用以下方法获得正确的结果:

              MessageDigest md = MessageDigest.getInstance("SHA-256");
              
              byte[] hash = md.digest("password".getBytes());
              
              BigInteger bI = new BigInteger(1, hash);
              
              System.out.println(bI.toString(16));
              

              【讨论】:

              • 不,这段代码还是错的。 BigInteger.toString(16) 将不包含前导零。
              猜你喜欢
              • 2011-10-15
              • 1970-01-01
              • 2011-04-15
              • 2011-03-22
              • 2015-06-18
              • 1970-01-01
              • 1970-01-01
              • 2012-12-31
              • 2014-08-19
              相关资源
              最近更新 更多