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

时间:2017-11-08 07:40:30

标签: openssl cryptography bouncycastle ecdsa

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

这是与密钥生成相关的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()));

验证签名的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打印出的密钥如下:

使用充气城堡的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充气城堡的专家。任何建议都非常感谢!谢谢,抱歉这篇长篇文章。

1 个答案:

答案 0 :(得分:0)

我弄清楚出了什么问题,用于签名的摘要又多了一步,我错过了,因此用于验证的摘要与用于签名的摘要不同,所以它失败了。

相关问题