哪个SHA-256是正确的? Java SHA-256摘要或Linux命令行工具

时间:2010-06-11 10:20:56

标签: java security hash

当我使用以下方法在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));
    }

谢谢!

7 个答案:

答案 0 :(得分:28)

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

答案 1 :(得分:10)

罪魁祸首是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));
}

答案 2 :(得分:7)

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

答案 3 :(得分:4)

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

答案 4 :(得分:2)

sha256sum生成的那个似乎是正确的。你的实现似乎放弃了这两个零。

答案 5 :(得分:1)

使用@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回答。

答案 6 :(得分:0)

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

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

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

BigInteger bI = new BigInteger(1, hash);

System.out.println(bI.toString(16));