【问题标题】:Java Signature.sign() with SHAwithECDSA produces different results on multiple runs带有 SHAwithECDSA 的 Java Signature.sign() 在多次运行时产生不同的结果
【发布时间】:2017-07-07 19:49:51
【问题描述】:

我正在尝试使用 SHAwithECDSA 对不会更改的私钥进行签名,该私钥也不会更改。无论您多久运行一次代码,这都应该产生相同的结果。 但是,我遇到了一些我无法解释的随机性,因为每次运行的结果输出都会发生变化。

这是我的工作(最小示例):

public byte[] sign() {
    Signature ecdsa = Signature.getInstance("SHA256withECDSA", "SunEC");

    // This is a hexadecimal byte sequence I need to sign
    String dataToBeSigned = "808112B43A3A381D1797BBBBBB973B99" + 
                         "9737B93397AA2917B1B0B737B734B1B0" + 
                         "B616B2BC3497A1AB43A3A381D1797BBB" +
                         "BBB973B999737B933979918181897981" +
                         "A17BC36B63239B4B396B6B7B93291B2B" +
                         "1B239B096B9B430991A9B22062349443" +
                         "1025687474703A2F2F7777772E77332E" +
                         "6F72672F54522F63616E6F6E6963616C" +
                         "2D6578692F4852D0E8E8E0745E5EEEEE" +
                         "EE5CEE665CDEE4CE5E646060625E6068" +
                         "5EF0DAD8CADCC646E6D0C2646A6C841A" +
                         "36BC07A00CB7DCAD662F3088A60A3D6A" +
                         "99431F81C122C2E9F1678EF531E95523" +
                         "70";

    String hexPrivKey = "B9134963F51C4414738435057F97BBF1" +
                        "010CABCB8DBDE9C5D48138396AA94B9D";
    byte[] privKey = DatatypeConverter.parseHexBinary(hexPrivKey);

    ecdsa.initSign(getPrivateKey(privKey));
    ecdsa.update(dataToBeSigned);
    byte[] signature = ecdsa.sign();

    System.out.println("Signature: " + DatatypeConverter.printHexBinary(signature));
}

public ECPrivateKey getPrivateKey(byte[] privateKeyBytes) {
    try {
        AlgorithmParameters parameters = AlgorithmParameters.getInstance("EC");
        parameters.init(new ECGenParameterSpec("secp256r1"));

        ECParameterSpec ecParameterSpec = parameters.getParameterSpec(ECParameterSpec.class);
        ECPrivateKeySpec ecPrivateKeySpec = new ECPrivateKeySpec(new BigInteger(privateKeyBytes), ecParameterSpec);

        ECPrivateKey privateKey = (ECPrivateKey) KeyFactory.getInstance("EC").generatePrivate(ecPrivateKeySpec);

        return privateKey;
    } catch (NoSuchAlgorithmException | InvalidKeySpecException | InvalidParameterSpecException e) {
        System.out.println(e.getClass().getSimpleName() + " occurred when trying to get private key from raw bytes", e);
        return null;
    }
}

您是否有任何提示,为什么每次运行此代码时都不会产生相同的签名输出? here 提出了类似的问题,但尚未找到真正的答案。

与此相关的另一个问题: 我看到 Signature 类提供了另一个 initSign 方法: initSign(PrivateKey privateKey, SecureRandom 随机) 为什么我要在创建签名时插入随机源/种子?如果随机种子未知,接收方应该如何验证该签名?

感谢您提供宝贵意见! 马克

【问题讨论】:

    标签: java ecdsa


    【解决方案1】:

    specification of the algorithm 解释它:

    DSA 和 ECDSA 的一个特点是它们需要为 每个签名生成,一个新的随机值(以下称为 问)。为了有效的安全性,k 必须随机选择并且 统一地从一组模整数,使用密码 安全的过程。在这个过程中,即使是轻微的偏见也可能会被扭转 对签名方案的攻击。

    所以你看到的是完全正常的。当然,算法的设计者使接收者可以验证签名,否则将毫无意义。这就是您的测试应该验证的内容。

    【讨论】:

    • 啊哈,好的。感谢您对 RFC 的提示。我只是无法想象 ECDSA 中的随机密钥如何让另一方进行验证,但我想我只需要依靠它并阅读 RFC 来了解如何。无论如何,现在我知道结果完全正常。
    • 不,能设置一个随机种子就好了,之后我们可以在未来使用相同的私钥设置该种子以获得相同的签名。
    • 实际上我这样做的目的是存储一个长种子,这样我就可以像钱包一样在未来可预测地重复生成无数密钥。
    猜你喜欢
    • 1970-01-01
    • 2012-05-02
    • 2011-10-31
    • 2017-08-16
    • 1970-01-01
    • 2018-05-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多