ECDSA подписывается с помощью надувного замка и проверяется с помощью openssl

У меня есть самоподписанный сертификат (не популярный X.509). Сертификат и пара открытый / закрытый ключ ECDSA генерируются java-программой с использованием надувного замка. Мне нужно проверить этот сертификат с помощью программы C, используя openssl. Однако подпись ECDSA может быть правильно проверена программой java, но не удалась при проверке openssl. Если я использую тот же закрытый ключ для повторной подписи сообщения с помощью openssl, проверка подписи с помощью openssl пройдет.

Вот фрагмент кода Java, связанный с генерацией ключей (после создания пары ключей я фактически сохраняю их в файле, поэтому он всегда будет использовать один и тот же ключ, не показанный в следующем фрагменте).

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-программой. Я также выгрузил сгенерированную часть r / s подписи из java и по сравнению с тем, что я пытаюсь проверить в программе C, они такие же.

Я могу углубиться в OpenSSL, чтобы добавить отладку, но, к сожалению, я не эксперт в java bouncy castle. Любое предложение приветствуется! Спасибо и извините за длинный пост.


person chris.sun    schedule 08.11.2017    source источник
comment
Подпись Bouncy Castle всегда 64 байта, а подпись OpenSSL обычно около 70? stackoverflow.com/a/39575576/6535399   -  person bartonjs    schedule 08.11.2017


Ответы (1)


Я понял, что не так, дайджест, используемый для подписи, требует еще одного шага, который я пропустил, в результате дайджест, используемый для проверки, отличается от того, который используется для подписи, поэтому он не удался.

person chris.sun    schedule 09.11.2017