【问题标题】:How can I create an SHA512 digest string in Java using bouncy castle?如何使用 bouncy castle 在 Java 中创建 SHA512 摘要字符串?
【发布时间】:2014-02-06 23:48:26
【问题描述】:

此单元测试失败:

    public void testDigest() throws NoSuchAlgorithmException {
    String hashExpected = "150a14ed5bea6cc731cf86c41566ac427a8db48ef1b9fd626664b3bfbb99071fa4c922f33dde38719b8c8354e2b7ab9d77e0e67fc12843920a712e73d558e197";
    MessageDigest md = new MessageDigest();
    String hashActual = new String(md.digest("hi"));
    Assert.assertEquals(hashExpected, hashActual);
}

下面是我的 MessageDigest 类的实现:


import java.io.IOException;
import java.io.InputStream;
import java.security.NoSuchAlgorithmException;
import java.security.Security;

import org.bouncycastle.crypto.Digest; import org.bouncycastle.crypto.digests.SHA512Digest; import org.bouncycastle.crypto.io.DigestInputStream; import org.bouncycastle.jce.provider.BouncyCastleProvider;

public class MessageDigest { private Digest messageDigest;

public MessageDigest() throws NoSuchAlgorithmException {
    Security.addProvider(new BouncyCastleProvider());
    messageDigest = new SHA512Digest();
}

public byte[] digest(String message) {
    byte[] retValue = new byte[messageDigest.getDigestSize()];
    messageDigest.update(message.getBytes(), 0, message.length());
    messageDigest.doFinal(retValue, 0);
    return retValue;
}

}

测试失败,原因如下:


junit.framework.ComparisonFailure: expected:<150a14ed5bea6cc731cf86c41566ac427a8db48ef1b9fd626664b3bfbb99071fa4c922f33dde38719b8c8354e2b7ab9d77e0e67fc12843920a712e73d558e197> but was:<
í[êlÇ1φÄf¬Bz�´Žñ¹ýbfd³¿»™¤É"ó=Þ8q›ŒƒTâ·«�wàæÁ(C’
q.sÕXá

当我将 byte[] 摘要转换为字符串时,我感觉我没有使用正确的编码方案。任何帮助将不胜感激。

【问题讨论】:

    标签: java hash bouncycastle sha512


    【解决方案1】:

    您期望的值是十六进制编码值。您正在根据原始字节创建一个字符串,这是行不通的。

    您应该尽可能使用标准的 Java Crypto API,而不是 BouncyCastle 特定的 API。

    尝试以下方法(Hex 库来自commons-codec):

    Security.addProvider(new BouncyCastleProvider());
    
    String data = "hello world";
    
    MessageDigest mda = MessageDigest.getInstance("SHA-512", "BC");
    byte [] digesta = mda.digest(data.getBytes());
    
    MessageDigest mdb = MessageDigest.getInstance("SHA-512", "BC");
    byte [] digestb = mdb.digest(data.getBytes());
    
    System.out.println(MessageDigest.isEqual(digesta, digestb));
    
    System.out.println(Hex.encodeHex(digesta));
    

    【讨论】:

    • +1 我喜欢你更全面的回答。问题:何时/为什么要使用 MessageDigest.isEqual 而不是 Arrays.equals?
    • 它们在功能上是等效的。 MessageDigest#isEqual() 提供了更多的语义含义,但这是值得商榷的。
    • 它们并不完全等价。 Arrays.equals 方法认为两个空引用相等,而 MessageDigest.isEqual 方法会抛出 NullPointerException。
    • Commons Codec 对于十六进制转换不是必需的。试试System.out.println(new BigInteger(1,m.digest(new byte[]{0x00})).toString(16));
    • 关于MessageDigest#isEqual():它是时​​间常数,即计算需要相同的时间,并且一旦看到差异就不会返回false。这样一来,您就无法对函数调用计时以检查您是否有一个哈希值,该哈希值具有一些带有所需哈希值的公共前缀。
    【解决方案2】:

    只是对 Kevin 回答的补充:从 Java 5 开始,您可以使用 String.format("%0128x", new BigInteger(1, digesta)) 而不是 commons-codec 将字节数组格式化为带前导零的 128 位十六进制编码数字。

    【讨论】:

    • 谢谢你,但有一个问题。除了不需要引入另一个库之外,使用这种方法比 commons-codec 答案中指定的方法有什么好处吗?
    • @jtbradle:可能不会。
    【解决方案3】:

    是的,您需要将字节数组转换为十六进制字符串。 :-) 查看Apache Commons Codec,尤其是Hex 类。

    【讨论】:

      【解决方案4】:

      自 BouncyCastle 1.49 以来,Hex 类中有少数 toHexString 方法。例如:

      Hex.toHexString(digest);
      

      会将哈希摘要作为 Java String 以十六进制格式返回给您。

      有关参考,请参阅 BouncyCastle javadocgrepcode

      【讨论】:

        猜你喜欢
        • 2015-06-13
        • 2013-02-27
        • 2015-10-15
        • 1970-01-01
        • 1970-01-01
        • 2015-06-24
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多