【问题标题】:getting a segmentation fault with RSA_public_encryptRSA_public_encrypt 出现分段错误
【发布时间】:2021-01-26 16:27:03
【问题描述】:

这是我的代码:

#include <openssl/evp.h>
#include <openssl/pem.h>
#include <string.h>

int main (void)
{
        char publicKey[] = "-----BEGIN RSA PUBLIC KEY-----\n"\
"MIIBCgKCAQEAqBa0jeqfHO8CFZuHyN5WgdTd3uThkU/I9lR+bb2R9khVU1tYhiyL\n"\
"Gfnm051K0039gCBAz9S7HHO2lqR/B1kiEGwBzg83N3tL2UzQXXbpxJz0b7vV8rXZ\n"\
"fB9j+FCAtD5znittXRjWrNqlEyJyxK+PuxNF3uPGWSjkYtRKv2f5HCXsfRJah40w\n"\
"5zU+OKZsZMrSSxweYN9Jwc++oMaSPCsGKog6NPbkbcTK8Akveof8v5rpG50I/zcQ\n"\
"9dCD69qJcmhm4ai4fAZFJlsFH2HmxV6DERFs3TNyzGlSQ1gd/XLER7U9nlrOUT87\n"\
"mXreUIXSkAFdCrlHXHOzj0eodfN8IfHjnQIDAQAB\n"\
"-----END RSA PUBLIC KEY-----\n";
    char plaintext[] = "enp6";

    // base64 decode plaintext
    EVP_DecodeBlock(plaintext, plaintext, strlen(plaintext));

    BIO* bo = BIO_new(BIO_s_mem());
    BIO_write(bo, publicKey, strlen(publicKey));
    EVP_PKEY* pkey = 0;
    PEM_read_bio_PUBKEY(bo, NULL, NULL, NULL);
    BIO_free(bo);
    RSA* rsa = EVP_PKEY_get1_RSA(pkey);
    char ciphertext[RSA_size(rsa)];

    RSA_public_encrypt(strlen(plaintext), plaintext, ciphertext, rsa, RSA_NO_PADDING);
    printf("%d\n", (int) strlen(ciphertext));
}

我正在尝试通过 gcc -x c test2.c -lcrypto &amp;&amp; ./a.out 运行它。关于我做错了什么有什么想法吗?

【问题讨论】:

  • 真的允许EVP_DecodeBlock的源和目标使用相同的缓冲区(plaintext[])吗?另外,strlen(plaintext); 在那之后仍然有效吗? EVP_DecodeBlock返回解码后数据的长度,所以你不应该用它作为解码后的明文长度吗?
  • 另外,strlen(ciphertext); 似乎不正确,因为 ciphertext 不是以 null 结尾的字符串。
  • 行尾的反斜杠是多余的,因为相邻的字符串文字无论如何都会连接起来。如果你没有在每一行都使用引号,你会使用它
  • @IanAbbott 不幸的是,文档没有说明 EVP_DecodeBlock 是否需要单独的源和目标。因此,要么深入研究源代码,要么防御性地使用不同的缓冲区

标签: c openssl rsa


【解决方案1】:

您的代码包含几个错误。 segfault 的直接原因是变量pkey 在用0 初始化后从未被赋予任何值。 EVP_PKEY_get1_RSA(pkey) segfaults 结果。你可能打算这样做

EVP_PKEY *pkey = PEM_read_bio_PUBKEY(bo, NULL, NULL, NULL);

但是,对于您发布的 PEM,这将不起作用。 PEM 的标头表明这是一个以“传统”格式存储的 RSA 密钥。 PEM_read_bio_RSAPublicKey 能够读取这样的密钥:

RSA *rsa = PEM_read_bio_RSAPublicKey(bo, NULL, NULL, NULL);

那么你在调用RSA_public_encrypt 时选择的RSA_NO_PADDING 是不对的。为了使用它,明文的长度必须与密钥大小完全相同。您可以尝试改用RSA_PKCS1_PADDING

最后,就像评论部分提到的那样,在密文上使用strlen是不正确的,因为它不是以0结尾的字符串。

通常,您应该检查所有调用的 OpenSSL 函数的所有返回值,以查看何时/是否出现问题。

【讨论】:

  • 加上这个,密文的大小是sizeof ciphertext。 OP 似乎没有意识到 RSA 加密发生在与密钥长度相同大小的块中
  • 是的,尽管由于声明数组的方式,我不确定sizeof 在这种情况下是否有效。但另外,正如the man page 所说:“RSA_public_encrypt() 返回加密数据的大小(即 RSA_size(rsa))。”。 :-)
  • @M.M 我试过了,sizeof 确实适用于 VLA——我从来不知道。
  • 我尝试了您的建议,但仍然遇到分段错误:pastebin.com/8r0T59QA。这是我检查返回值并在出现错误时使用ERR_error_string(我没有收到任何错误):pastebin.com/iwdA3aDB
  • 您不再需要EVP_PKEY,您可以删除该行。然后你在调用bo 之后在bo 上调用PEM_read_bio_RSAPublicKey,这将失败。首先阅读,然后释放生物。不过,错误检查对我来说看起来不错。运行您当前的代码时,在尝试读取 EVP_PKEY 后,我确实看到了一条错误消息 error:0909006C:PEM routines:get_name:no start line(这很神秘,但意味着它无法识别标头。那是因为它不需要 RSA 标头)。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-11-15
  • 2013-06-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多