Skip to content

ECDSA producing unverifiable or incorrect signatures for some curves #2841

@guidovranken

Description

@guidovranken
#include <botan/ecdsa.h>
#include <botan/pubkey.h>
#include <botan/system_rng.h>
#include <botan/hash.h>
#include <botan/ber_dec.h>

static void sign_verify(const std::string& curve) {
    ::Botan::System_RNG rng;
    const std::vector<uint8_t> msg{0xFF};
    std::unique_ptr<::Botan::PK_Signer> signer;
    ::Botan::EC_Group group(curve);
    const ::Botan::BigInt priv_bn("1");
    const auto priv = std::make_unique<::Botan::ECDSA_PrivateKey>(::Botan::ECDSA_PrivateKey(rng, group, priv_bn));
    signer.reset(new ::Botan::PK_Signer(*priv, rng, "EMSA1(SHA-256)", ::Botan::DER_SEQUENCE));
    const auto signature = signer->sign_message(msg, rng);
    ::Botan::BER_Decoder decoder(signature);
    ::Botan::BER_Decoder ber_sig = decoder.start_sequence();

    size_t count = 0;

    ::Botan::BigInt R;
    ::Botan::BigInt S;
    while(ber_sig.more_items())
    {
        switch ( count ) {
            case    0:
                ber_sig.decode(R);
                break;
            case    1:
                ber_sig.decode(S);
                break;
            default:
                printf("Error: Too many parts in signature BER\n");
                abort();
        }

        ++count;
    }

    const auto pub_x = priv->public_point().get_affine_x();
    const auto pub_y = priv->public_point().get_affine_y();

    const ::Botan::PointGFp public_point = group.point(pub_x, pub_y);
    const auto pub = std::make_unique<::Botan::ECDSA_PublicKey>(::Botan::ECDSA_PublicKey(group, public_point));
    const auto sig = ::Botan::BigInt::encode_fixed_length_int_pair(R, S, group.get_order_bytes());
    auto hash = ::Botan::HashFunction::create("SHA-256");
    hash->update(msg);
    const auto _msg = hash->final();
    printf("%s; verified: %d\n", curve.c_str(), ::Botan::PK_Verifier(*pub, "Raw").verify_message(_msg, sig));

    return;
}
int main(void)
{
    const std::vector<std::string> curves{
        "brainpool160r1",
            "brainpool192r1",
            "brainpool224r1",
            "brainpool256r1",
            "brainpool320r1",
            "brainpool384r1",
            "brainpool512r1",
            "frp256v1",
            "gost_256A",
            "gost_512A",
            "secp160k1",
            "secp160r1",
            "secp160r2",
            "secp192k1",
            "secp192r1",
            "secp224k1",
            "secp224r1",
            "secp256k1",
            "secp256r1",
            "secp384r1",
            "secp521r1",
            "sm2p256v1",
            "x962_p192v2",
            "x962_p192v3",
            "x962_p239v1",
            "x962_p239v2",
            "x962_p239v3",
    };

    for (const auto& c : curves) {
        sign_verify(c);
    }
}

prints:

brainpool160r1; verified: 1
brainpool192r1; verified: 1
brainpool224r1; verified: 1
brainpool256r1; verified: 1
brainpool320r1; verified: 1
brainpool384r1; verified: 1
brainpool512r1; verified: 1
frp256v1; verified: 1
gost_256A; verified: 1
gost_512A; verified: 1
secp160k1; verified: 0
secp160r1; verified: 0
secp160r2; verified: 0
secp192k1; verified: 1
secp192r1; verified: 1
secp224k1; verified: 0
secp224r1; verified: 1
secp256k1; verified: 1
secp256r1; verified: 1
secp384r1; verified: 1
secp521r1; verified: 1
sm2p256v1; verified: 1
x962_p192v2; verified: 1
x962_p192v3; verified: 1
x962_p239v1; verified: 0
x962_p239v2; verified: 0
x962_p239v3; verified: 0

Metadata

Metadata

Assignees

No one assigned

    Labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions