代码之家  ›  专栏  ›  技术社区  ›  Peter Tillemans

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

  •  24
  • Peter Tillemans  · 技术社区  · 14 年前

    当我用Java计算一个字符串的SHA256时,用下面的方法

    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
    

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

    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 回复  |  直到 11 年前
        1
  •  28
  •   Sean Owen    14 年前

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

        2
  •  10
  •   paxdiablo    14 年前

    罪魁祸首是 toHexString . 它似乎在输出 6 对于值6,而 sha256sum 一个正在输出 06 . Java文档 Integer.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));
    }
    
        3
  •  7
  •   David M    14 年前

    它们都是正确的——这是你的Java代码出错了,因为它没有打印出小于0x10的十六进制值的前导0。

        4
  •  4
  •   yegong    13 年前

    您仍然需要“echo-n”来防止跟踪\n

        5
  •  2
  •   user308323    14 年前

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

        6
  •  1
  •   Community CDub    7 年前

    使用@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
  •  0
  •   gswierczynski    11 年前

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

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