OpenSSL偶尔会产生错误的签名

时间:2018-10-16 13:22:22

标签: openssl sign ecdsa

我有一个C ++程序,ECDSA密钥对和一些要签名的字符串。该程序将生成签名并将其保存到文件(signature.bin)中。然后我通过以下命令检查签名的有效性:

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

问题在于程序有时会生成错误的签名。以上命令输出21个中的16个:

Error Verifying Data

在其余5次出现时输出:

Verified OK

怎么可能?

这是程序:

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...

1 个答案:

答案 0 :(得分:1)

您正在调用正确的OpenSSL方法。但是,您没有详细说明如何将Result保存到文件。根据其名称,TString可能表现为以0结尾的字符串。如果是这样,则签名将不会正确写入文件,但是只要签名包含0字节,它就会被过早地截断。请注意,ECDSA签名步骤包括一个随机组件,因此每次您运行代码时签名都不同。

以下推理支持这种猜测,并大致解释了为什么您的代码失败并成功的次数与以前一样多。如果阅读this explanation about the format of the ECDSA signature,您会发现0字节在此类签名中非常常见。对于rs分量的第一个字节,该概率约为3/4。然后还有一个额外的概率1-(255/256)^ 64,大约为1/4,剩余的64个字节将包含一个0。因此,失败的概率约为3/4 + 1/4 * 1/4 ,大约80%。

您的样本空间很小,但是考虑到字符串错误,很可能在21次尝试中有5次成功。