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

2022-09-01 18:29:22

当我在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

2个中的哪一个是正确的?

结果:两者都是,但我错了...

通过使用修复它:

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

谢谢!


答案 1

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


答案 2

罪魁祸首是 .它似乎正在输出值 6,而值 6 正在输出 。状态的 Java 文档:toHexString6sha256sum06Integer.toHexString()

此值将转换为十六进制(以 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));
}