ECDSA与充气城堡签署并与openssl核实

时间:2022-03-18 18:22:30

I have a self-signed certificate(not popular X.509 one). The certificate and ECDSA public/private key pair are generated by java program using bouncy castle. I need to verify this certificate with C program using openssl. However, the ECDSA signature can be verified by java program correctly, but failed with openssl verification. If I use the same private key to re-sign the message with openssl, the signature verification with openssl would passed though.

我有一个自签名证书(不受欢迎的X.509证书)。证书和ECDSA公钥/私钥对由java程序使用充气城堡生成。我需要使用openssl使用C程序验证此证书。但是,ECDSA签名可以通过java程序正确验证,但是使用openssl验证失败了。如果我使用相同的私钥来使用openssl重新签名消息,那么使用openssl的签名验证将会通过。

Here is the java code snippet related to key generation.(After key pair generated, I actually save them in file, so it will always use the the same key, not shown in following snipet).

这是与密钥生成相关的java代码片段。(生成密钥对后,我实际上将它们保存在文件中,因此它将始终使用相同的密钥,未在下面的snipet中显示)。

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()));

The C code of verify the signature showed in bellow:

验证签名的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;
}

The keys printed out by java and C are in bellow :

由java和C打印出来的键如下:

Java using bouncy castle:

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 

And the sha256 hash being signed is

并且签名的sha256哈希是

F40D983058408C0519D7E238BEBFA5EDCAA7F3B86AD4C83847F5DD66EA1C051B

C Using 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

I am pretty stuck here, java program can sign and verify that given digest, and C program can sign and verify the same digest using same key pair. But the C program can NOT verify the signature generated by java program. I also dumped out the generated signature r/s portion from java and compared with what i am trying to verify in C program , they are the same.

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

I can go deeper into OpenSSL to add debug, but too bad I am not expert in java bouncy castle. Any suggestion is greatly appreciated! Thanks and sorry for the long post.

我可以深入OpenSSL来添加调试,但是太糟糕了我不是java充气城堡的专家。任何建议都非常感谢!谢谢和抱歉长篇文章。

1 个解决方案

#1


0  

I figured out what's wrong, the digest used for signing takes one more step which i missed, as a result the digest used for verification is different with what's used for signing, so it failed.

我想出了什么是错的,用于签名的摘要又花了一个步骤而我错过了,因此用于验证的摘要与用于签名的摘要不同,所以它失败了。

#1


0  

I figured out what's wrong, the digest used for signing takes one more step which i missed, as a result the digest used for verification is different with what's used for signing, so it failed.

我想出了什么是错的,用于签名的摘要又花了一个步骤而我错过了,因此用于验证的摘要与用于签名的摘要不同,所以它失败了。