Java 的 BouncyCastle 并不总是验证 OpenSSL ECDSA 签名

2023-12-27

我使用 OpenSSL(在 C++ 中)对文本进行签名,但是我的 Java 程序并不总是验证签名消息(只有大约五分之一得到验证)。有趣的是https://kjur.github.io/jsrsasign/sample/sample-ecdsa.html https://kjur.github.io/jsrsasign/sample/sample-ecdsa.html不验证其中任何一个:

曲线名称:secp256k1签名算法:SHA256 和 ECDSA

私钥

431313701ec60d303fa7d027d5f1579eaa57f0e870b23e3a25876e61bed2caa3

公钥

035bcefc4a6ca257e394e82c20027db2af368474afb8917273713644f11a7cecb3

Failed:

text to sign=
    pcax2727gRo8M6vf9Vjhr1JDrQ3rdPYu6xx81000pcax273z8kaV5Ugsiqz3tvWGo8Gg6sch6V4912341535867163229

signature=
    3044022061dff8e39f9324b0794ec2c58abda971898f694ca980baf3c2a4045a9048b441022054a2fb8ef3d383fd7eeb31425dba440e2fd2053778d4ab3725046385c7845cff0000

成功的:

text to sign=
    pcax2727gRo8M6vf9Vjhr1JDrQ3rdPYu6xx81000pcax273z8kaV5Ugsiqz3tvWGo8Gg6sch6V4912341535867122614

signature=
    3046022100f200d0fb9e86a16bd46ee2dd11f1840a436d0a5c6823001a516e975a44906fcf022100d062a60611fc0f21d81fa3140741c8b6e650fff33d2c48aef69a3a40d7c7b3ca

Java

private static final String SHA256WITH_ECDSA = "SHA256withECDSA";

public static boolean isValidSignature(PublicKey pub, byte[] dataToVerify, byte[] signature) {

    try {

        Signature sign = Signature.getInstance(SHA256WITH_ECDSA, BouncyCastleProvider.PROVIDER_NAME);

        sign.initVerify(pub);

        sign.update(dataToVerify);

        return sign.verify(signature);

    } catch (Exception e) {
        log.error("Error: " + e.getMessage());
    }

    return false;

}

C++

std::vector<unsigned char> utils::crypto::sign(std::string& private_key_58, std::string& message) {

    auto priv_bytes = utils::base58::decode_base(private_key_58);

    auto digest = utils::crypto::sha256(message);

    auto key = utils::crypto::ec_new_keypair(priv_bytes);

    auto signature = ECDSA_do_sign(digest.data(), digest.size(), key);

    auto der_len = ECDSA_size(key);
    auto der = (uint8_t*) calloc(der_len, sizeof(uint8_t));
    auto der_copy = der;
    i2d_ECDSA_SIG(signature, &der_copy);

    std::vector<unsigned char> s (der, der+der_len);

    return s;

}

std::vector<unsigned char> utils::crypto::sha256(std::string& str) {

    unsigned char hash[SHA256_DIGEST_LENGTH];
    SHA256_CTX sha256;
    SHA256_Init(&sha256);
    SHA256_Update(&sha256, str.c_str(), str.size());
    SHA256_Final(hash, &sha256);

    std::vector<unsigned char> data(hash, hash + SHA256_DIGEST_LENGTH);

    return data;

}

EC_KEY *utils::crypto::ec_new_keypair(std::vector<unsigned char>& priv_bytes) {

    EC_KEY *key = nullptr;
    BIGNUM *priv = nullptr;
    BN_CTX *ctx = nullptr;
    const EC_GROUP *group = nullptr;
    EC_POINT *pub = nullptr;

    key = EC_KEY_new_by_curve_name(NID_secp256k1);

    if (!key) {
        std::cerr << "Can't generate curve secp256k1\n";
        std::abort();
    }

    priv = BN_new();
    BN_bin2bn(priv_bytes.data(), 32, priv);
    EC_KEY_set_private_key(key, priv);

    ctx = BN_CTX_new();
    BN_CTX_start(ctx);

    group = EC_KEY_get0_group(key);
    pub = EC_POINT_new(group);
    EC_POINT_mul(group, pub, priv, NULL, NULL, ctx);
    EC_KEY_set_public_key(key, pub);

    EC_POINT_free(pub);
    BN_CTX_end(ctx);
    BN_CTX_free(ctx);
    BN_clear_free(priv);

    return key;
}

近乎欺骗ECDSA 签名长度 https://stackoverflow.com/questions/17269238/ecdsa and 如何为 java.security.Signature 签名方法指定签名长度 https://stackoverflow.com/questions/48177791/how-to-specify-signature-length-for-java-security-signature-sign-method(还有更多链接)

ASN.1 DER 编码是可变大小的适用于除某些非常有限的数据之外的所有数据,特别是 ECDSA(或 DSA)签名。ECDSA_size返回maximum给定密钥的可能长度,但每个实际签名可能是该长度或更短,具体取决于签名中值 r 和 s 的二进制表示形式,出于您的目的,可以将其本质上视为随机数。

如果实际签名短于ECDSA_size您仍然对整个缓冲区进行编码并将其传递给 Java;注意两个字节的零(0000以十六进制表示)在“失败”示例的末尾? DER 解码器can忽略尾随垃圾,当我在较旧的 BouncyCastle 和 SunEC 提供商上测试这种情况时,它实际上工作正常,但从 BouncyCastle 1.54 开始对我来说失败了——有一个相当明显的例外,java.security.SignatureException: error decoding signature bytes.-- SunEC 从 8u121 开始,原因或异常类似于java.security.SignatureException: Invalid encoding for signature.

在对“宽松”编码(包括比特币中的 secp256k1 签名)进行一些成功攻击之后,许多实现最近使 DER 解码变得更加严格 - 请参阅https://bitcoin.stackexchange.com/questions/51706/what-c​​an-be-changed-in-signed-bitcoin-transaction https://bitcoin.stackexchange.com/questions/51706/what-can-be-changed-in-signed-bitcoin-transaction and https://en.bitcoin.it/wiki/Transaction_malleability https://en.bitcoin.it/wiki/Transaction_malleability。这在Oracle Java 8u121 发行说明 http://www.oracle.com/technetwork/java/javase/8u121-relnotes-3315208.html项目“在 DER 编码解析代码中添加了更多检查”,尽管我没有看到 Bouncy 的任何类似内容。

由于 secp256k1 是 Certicom/X9 'prime' (Fp) 曲线组,其余因子为 1,其阶数非常接近基础字段大小,而基础字段大小又非常接近 256 位(8 的倍数),因此签名该组将在几乎 1/4 (25%) 的时间内将 DER 编码到最大长度(并且有效);其余时间他们都会失败。

官方最好的解决方案是使用指针中更新的值,这里der_copy,由(任意)输出i2d*例程,以确定编码的长度,并使用该长度。如果由于某种原因无法处理可变长度,您可以传输整个缓冲区,但在传递给 BouncyCastle(或 SunEC)之前将其截断,方法是使用2+signature[1]作为有效长度——但如果您更改为大于约 480 位的曲线,则不会;上面它是不同的并且更复杂。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Java 的 BouncyCastle 并不总是验证 OpenSSL ECDSA 签名 的相关文章

  • 如何使用 Java 将 HTML 内容转换为 PDF 而不丢失格式?

    我有一些 HTML 内容 包括格式化标签 例如strong 图像等 在我的 Java 代码中 我想将此 HTML 内容转换为 PDF 文档 而不丢失 HTML 格式 有没有办法用 Java 来实现 使用 iText 或任何其他库 I use
  • Java Sqlite Gradle

    我对 gradle 和 java 还很陌生 我有一个使用 sqlite 的项目 它通过 intellij idea 运行良好 但我无法从终端运行它 它会抛出异常 java lang ClassNotFoundException org sq
  • 以点作为分隔符分割字符串

    我想知道我是否要在一个字符串上分割字符串 正确的方式 我的代码是 String fn filename split return fn 0 我只需要字符串的第一部分 这就是我返回第一项的原因 我问这个是因为我在 API 中注意到 意味着任何
  • 如何在Mac上使用eclipse安装jetty

    我是一个新手 jetty 和 RESTful API 我想使用 Jetty 创建 REST 服务 并希望将嵌入式 jetty 与 eclipse 一起使用 任何人都可以建议我在 Mac OS 中使用 Eclipse 安装 Jetty Jet
  • 空 EntityManager/EJB 注入 MDB

    我有一个消息驱动 bean MDB 部署到 WebLogic 12 1 3 我尝试使用 PersistenceContext 注释将实体管理器注入 MDB 但实体管理器为空 我还尝试注入一个简单的无状态会话 bean 它也是空的 但是 Me
  • 通过 JNI 从 Applet 调用 DLL

    我有一个 概念验证 的作品 它跨越了一些不熟悉的领域 我的任务是将 EFTPOS 机器连接到在内联网浏览器中作为小程序运行的应用程序 我暂时忽略了 EFTPOS dll 并用我选择的语言 Delphi 创建了一个简单的 JNI 修饰的 DL
  • 如何在Gradle中支持多种语言(Java和Scala)的多个项目?

    我正在尝试将过时的 Ant 构建转换为 Gradle 该项目包含约50个Java子项目和10个Scala子项目 Java 项目仅包含 Java Scala 项目仅包含 Scala 每个项目都是由 Java 和 Scala 构建的 这大大减慢
  • 如何使用 Spring MVC 和 Thymeleaf 添加静态文件

    我的问题是如何添加 CSS 和图像文件等静态文件 以便我可以使用它们 我正在使用 Spring MVC 和 Thymeleaf 我查看了有关此主题的各种帖子 但它们对我没有帮助 所以我才来问 根据这些帖子 我将 CSS 和图像文件放在res
  • Scala(或 Java)中泛型函数的特化

    是否可以在 Scala 中专门化泛型函数 或类 例如 我想编写一个将数据写入 ByteBuffer 的通用函数 def writeData T buffer ByteBuffer data T buffer put data 但由于 put
  • 如何在命令提示符中检查 JAVA_OPTS 值?

    我们的应用程序部署 JBoss 服务器然后抛出错误 PermGen space 然后在 jboss bat 和配置文件中设置 permgen 变量中的 java OPTS JAVA OPTs 中是否有值 assige 如何检查 如何在命令提
  • 如何将txt文件添加到你的android项目中? [复制]

    这个问题在这里已经有答案了 我的Android studio版本是1 5 1 显然这个 never 版本没有 txt 文件的 asset 文件夹 您打算如何将这些文件包含到您的项目中 以及如何进一步使用您内部的应用程序 谢谢你的建议 Pro
  • XSLT:我们可以使用abs值吗?

    我想知道在 XSLT 中我们是否可以使用 math abs 我在某处看到过这个 但它不起作用 我有类似的东西
  • 删除 ArrayList 对象问题

    我在处理作业时遇到从 ArrayList 中删除对象的问题 如果我使用 正常 for 循环 它的工作原理如下 public void returnBook String isbn for int i 0 i lt booksBorrowed
  • 膨胀类片段 InflateException 二进制 XML 文件时出错

    我正在使用 Material Design 和 NavigationDrawer 布局等设计我的第一个应用程序 但我遇到了一个问题 该应用程序非常简单 它只显示文本 并且基于 Android Studio 中提供的模板 尝试启动我的应用程序
  • 在方法内声明类 - Final 关键字 [重复]

    这个问题在这里已经有答案了 给定方法中的以下内部类 IsSomething public class InnerMethod private int x public class Something private int y public
  • 使用 Cucumber Scenario Outline 处理 Excel 电子表格

    如果可能的话 我试图找到一种更优雅的方法来处理从与 Excel 电子表格行 第 n 个 相关的 Cucumber Scenario Outline 中调用第 n 个数字 目前 我正在使用迭代编号来定义要从中提取数据的 Excel 电子表格的
  • 设计抽象类时是否应该考虑序列化问题?

    一般来说这个问题来自Eclipse建议在抽象类上添加串行版本UID 由于该类是抽象类 因此该类的实例永远不会存在 因此它们永远不会被序列化 只有派生类才会被序列化 所以我的问题是放置一个安全 SuppressWarnings serial
  • 当我在 Java 中输入 IP 时无法连接到我的服务器

    好的 我正在尝试学习 Java 客户端 服务器的内容 并且正在浏览教程代码 如下所示 当我将 localhost 更改为我的 IP 时 它会停止工作 请帮忙 编辑 127 0 0 1 似乎也可以工作 但不是我的真实IP Copyright
  • 条件查询:按计数排序

    我正在尝试执行一个标准查询 该查询返回 stackoverflow 中回答最多的问题 例如常见问题解答 一个问题包含多个答案 我正在尝试使用标准查询返回按每个问题的答案数排序的回答最多的问题 任何人都知道我应该在 hibernate cri
  • java中的回调是什么[重复]

    这个问题在这里已经有答案了 可能的重复 什么是回调函数 https stackoverflow com questions 824234 what is a callback function 我已经阅读了回调的维基百科定义 但我仍然没有明

随机推荐