DimanNe
DimanNe

Reputation: 1941

OpenSSL occasionally generates wrong signature

I have a C++ programme, ECDSA key pair and some string to sign. The programme generates signature and saves it into a file (signature.bin). Then I check the validity of the signature via the following command:

openssl dgst -verify ec_public.pem -signature signature.bin ToSign.txt

the problem is that the programme sometimes generates wrong signature. 16 times out of 21 the above command outputs:

Error Verifying Data

while in the remaining 5 occurrences it outputs:

Verified OK

How can it be possible?

Here is the programme:

SSL_library_init();
OPENSSL_config(nullptr);
SSL_load_error_strings();
OpenSSL_add_all_algorithms();
ERR_load_BIO_strings();
CRYPTO_set_id_callback(ThreadIdFunction);
CRYPTO_set_locking_callback(LockingFunction);

const TString pk = "-----BEGIN EC PRIVATE KEY-----\n"
                       "MHcCAQEEIG90zmo1o3NWNFa8wp2z4rdQXGSN8xAP/OATLpwlgi+1oAoGCCqGSM49\n"
                       "AwEHoUQDQgAE5TwpzBhjUWZoOf629GfwGG5WlRJD7TSuz+ZTHUaiK5mj2qgxBOPk\n"
                       "eqOrTYXsiPwnaWe23zHjIM8NOhAm1BiGgA==\n"
                       "-----END EC PRIVATE KEY-----\n";

const TString ToSign = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhdWQiOiJhc2RmIn0";

EVP_MD_CTX *Ctx    = EVP_MD_CTX_create();
BIO *       Bio    = BIO_new_mem_buf(pk.data(), pk.size());
EVP_PKEY *  EVPKey = PEM_read_bio_PrivateKey(Bio, nullptr, nullptr, nullptr);

EVP_DigestSignInit(Ctx, nullptr, EVP_sha256(), nullptr, EVPKey);
EVP_DigestSignUpdate(Ctx, ToSign.data(), ToSign.size());
size_t SignatureLength;
EVP_DigestSignFinal(Ctx, nullptr, &SignatureLength);

TString Result;
Result.resize(SignatureLength);
EVP_DigestSignFinal(Ctx, reinterpret_cast<unsigned char *>(const_cast<char *>(Result.data())), &SignatureLength);

// Saving to file...

Upvotes: 2

Views: 751

Answers (1)

Reinier Torenbeek
Reinier Torenbeek

Reputation: 17383

You are invoking the right OpenSSL methods. However, you did not explain in detail how you save the Result to file. Based on its name, TString probably behaves as a 0-terminated string. If so, then the signature will not be written to the file correctly but truncated too early whenever the it contains a 0-byte. Note that the ECDSA signing steps include a random component so the signature is different every time you run your code.

The following reasoning supports this guess and roughly explains why your code fails and succeeds as often as it does. If you read this explanation about the format of the ECDSA signature, you will see that the 0-byte is very common in such signatures. The probability is about 3/4 for the first bytes of the r and s components combined. Then there is an additional probability of 1-(255/256)^64, about 1/4, that the remaining 64 bytes will contain a 0. So the probability of failure is roughly 3/4 + 1/4*1/4, about 80%.

Your sample space is small, but with that string-mistake taken into account, 5 successes out of 21 attempts is a likely result.

Upvotes: 1

Related Questions