【问题标题】:ECDSA sign with bouncy castle and verify with opensslECDSA 用充气城堡签名并用 openssl 验证
【发布时间】:2018-04-20 19:24:37
【问题描述】:

我有一个自签名证书(不是流行的 X.509 证书)。证书和 ECDSA 公钥/私钥对由 java 程序使用 bouncy castle 生成。 我需要使用 openssl 用 C 程序验证这个证书。但是,ECDSA 签名可以通过 java 程序正确验证,但通过 openssl 验证失败。如果我使用相同的私钥使用 openssl 重新签署消息,则使用 openssl 的签名验证将通过。

这里是与密钥生成相关的java代码sn-p。(密钥对生成后,我实际上将它们保存在文件中,所以它总是使用相同的密钥,下面的片段中没有显示)。

KeyPair rootCASigningKeys = cryptoManager.generateKeyPair(SignatureChoices.ecdsaNistP256Signature);

BCECPublicKey bcPub = cryptoManager.toBCECPublicKey(PublicKeyAlgorithm.ecies_nistp256, (java.security.interfaces.ECPublicKey) rootCASigningKeys.getPublic());
ECPublicKey pk = (java.security.interfaces.ECPublicKey) rootCASigningKeys.getPublic();
ECPrivateKey priv = (ECPrivateKey) rootCASigningKeys.getPrivate();

System.out.println("pubkeyX="+getHexString(pk.getW().getAffineX().toByteArray()));
System.out.println("pubkeyY="+getHexString(pk.getW().getAffineY().toByteArray()));
System.out.println("privatekey="+getHexString(priv.getS().toByteArray()));

验证签名的C代码如下:

bool v2x_ecdsa_verify(
        const uint8_t *digest,
        size_t dgstlen,
        const void *sig,
        const void *pkey)
{
 ECDSA_SIG *ecdsa_sig;
    EC_KEY *ec_key;
    EC_GROUP *grp
    int ret;

    /* debug */
    EC_POINT *ecpt;
    /* debug end */

    grp = EC_GROUP_new_by_curve_name(NID_X9_62_prime256v1); /*TODO: */
    ecpt = EC_KEY_get0_public_key((const EC_KEY *)pkey);
    struct ec_point_st *cpt = (struct ec_point_st *)ecpt;
    printf("Pubkey_x:%d=\n", BN_num_bytes(&cpt->X));
    BN_print_fp(stdout, &cpt->X);
    printf("Pubkey_y:%d=\n", BN_num_bytes(&cpt->Y));
    BN_print_fp(stdout, &cpt->Y);
    printf("\n");


    printf("digest dump\n");
    v2x_dump_hex(V2X_LOG_ERR, digest, 32);
    printf("\n");
    {
        /* DEBUG code, Use the private key outputed by Java code to re-sign the digest */
        uint8_t priv_buf[] = {
            0x00, 0xB2, 0x6C, 0x1D, 0x0C, 0x62, 0x84, 0x45, 0x31, 0x3C, 0xF3, 0x83, 0x1D, 0x4E, 0xA7, 0x4B,
            0x2C, 0x07, 0x19, 0xCF, 0x19, 0xCC, 0x3E, 0xA7, 0xE5, 0x4F, 0xA4, 0xF0, 0x91, 0xBF, 0x5B, 0x96, 0xE8};
        BIGNUM *priv_bn = BN_bin2bn(priv_buf, sizeof(priv_buf), NULL);
        printf("priv_bn=\n");
        BN_print_fp(stdout, priv_bn);
        printf("\n");
        if (!priv_bn) {
            V2X_ERR("Failed to conver privkey \n");
            return false;
        }
        EC_KEY *priv_key = EC_KEY_new();
        if (priv_key) {
            if (!EC_KEY_set_group(priv_key, grp)) {
                V2X_ERR("Failed to set group\n");
                return false;
            }
            EC_KEY_set_private_key(priv_key, priv_bn);
        }
        ecdsa_sig = v2x_ecdsa_sign(digest, dgstlen, NULL, 0, (void *)priv_key);
    /* END of DEBUG code */
    }
    //ret = ECDSA_do_verify(digest, dgstlen, (ECDSA_SIG *)sig, (EC_KEY *)pkey); /* It fail to verify original signature */
    ret =  ECDSA_do_verify(digest, dgstlen, ecdsa_sig, (EC_KEY *)pkey); /* it pass to verify the re-signed signature */

    if (ret < 0)
        V2X_ERR("ret=%d\n", ret);

    return (bool)ret;
}

java和C打印出来的key如下:

Java 使用充气城堡:

provider=BC
pubkeyX=00 E4 B6 E1 50 C2 7A 85 DD BD 92 F8 14 C9 0E B0 5E 1E 28 A6 3C A3 B6 B1 69 32 39 BF 1B 1B F0 B0 03 
pubkeyY=00 ED DC 75 F0 E9 36 05 25 5F 54 08 74 E7 9D 6E BC 1B DF 97 5A E4 D2 A7 04 A7 E0 5F 21 06 54 26 1E 
privatekey=00 B2 6C 1D 0C 62 84 45 31 3C F3 83 1D 4E A7 4B 2C 07 19 CF 19 CC 3E A7 E5 4F A4 F0 91 BF 5B 96 E8 

而被签名的 sha256 哈希是

F40D983058408C0519D7E238BEBFA5EDCAA7F3B86AD4C83847F5DD66EA1C051B

C 使用 OpenSSL

Pubkey_x:32=
E4B6E150C27A85DDBD92F814C90EB05E1E28A63CA3B6B1693239BF1B1BF0B003
Pubkey_y:32=
EDDC75F0E93605255F540874E79D6EBC1BDF975AE4D2A704A7E05F210654261E
digest dump
        f4 0d 98 30  58 40 8c 05  19 d7 e2 38  be bf a5 ed
        ca a7 f3 b8  6a d4 c8 38  47 f5 dd 66  ea 1c 05 1b


priv_bn=
B26C1D0C628445313CF3831D4EA74B2C0719CF19CC3EA7E54FA4F091BF5B96E8

我被困在这里,java 程序可以签署和验证给定的摘要,而 C 程序可以使用相同的密钥对签署和验证相同的摘要。但是 C 程序无法验证 java 程序生成的签名。我还从 java 中导出了生成的签名 r/s 部分,并与我在 C 程序中尝试验证的内容进行比较,它们是相同的。

我可以更深入地了解 OpenSSL 以添加调试,但可惜我不是 java 充气城堡方面的专家。非常感谢任何建议!感谢和抱歉发了这么长的帖子。

【问题讨论】:

标签: openssl cryptography bouncycastle ecdsa


【解决方案1】:

我发现出了什么问题,用于签名的摘要多走了一步,我错过了,结果用于验证的摘要与用于签名的摘要不同,所以它失败了。

【讨论】:

    猜你喜欢
    • 2014-08-18
    • 2015-05-04
    • 1970-01-01
    • 2020-06-11
    • 2016-12-02
    • 2017-03-04
    • 1970-01-01
    • 2015-12-23
    • 1970-01-01
    相关资源
    最近更新 更多