我有一个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...
答案 0 :(得分:1)
您正在调用正确的OpenSSL方法。但是,您没有详细说明如何将Result
保存到文件。根据其名称,TString
可能表现为以0结尾的字符串。如果是这样,则签名将不会正确写入文件,但是只要签名包含0字节,它就会被过早地截断。请注意,ECDSA签名步骤包括一个随机组件,因此每次您运行代码时签名都不同。
以下推理支持这种猜测,并大致解释了为什么您的代码失败并成功的次数与以前一样多。如果阅读this explanation about the format of the ECDSA signature,您会发现0字节在此类签名中非常常见。对于r
和s
分量的第一个字节,该概率约为3/4。然后还有一个额外的概率1-(255/256)^ 64,大约为1/4,剩余的64个字节将包含一个0。因此,失败的概率约为3/4 + 1/4 * 1/4 ,大约80%。
您的样本空间很小,但是考虑到字符串错误,很可能在21次尝试中有5次成功。