RSA 加密。 EVP_PKEY_CTX_new 失败

RSA encryption. EVP_PKEY_CTX_new failed

我正在使用 OAEP SHA256 实施 RSA 加密。 按照 Whosebug 和 openssl 文档上的示例, 我在下面实施 code.But 我没有找到 EVP_PKEY_size 和 EVP_PKEY_CTX_new() 失败的原因。

谁能指出错误?或者谁能​​提供可以进行 SHA256 rsa public 密钥加密的代码?

   keybio = BIO_new(BIO_s_mem());
    if (keybio == NULL)
    {
        printf("Failed to create key BIO");
        return 0;
    }
    int len = BIO_write(keybio, Key, strlen(Key));
    EVP_PKEY*  evppubKey = PEM_read_bio_PUBKEY(keybio, NULL, NULL, NULL);
//  EVP_PKEY* evp_key = PEM_read_bio_RSAPublicKey(keybio, NULL, NULL, NULL);
    int a = EVP_PKEY_size(evp_key);
    EVP_PKEY_CTX* ctx = EVP_PKEY_CTX_new(evp_key, eng);
    
    EVP_PKEY_free(evp_key);

    if (ctx)
    {
        if (EVP_PKEY_encrypt_init(ctx) > 0)
        {
            EVP_PKEY_CTX_ctrl_str(ctx, "rsa_padding_mode", "oaep");
            EVP_PKEY_CTX_ctrl_str(ctx, "rsa_oaep_md", "sha256");
            EVP_PKEY_CTX_ctrl_str(ctx, "rsa_mgf1_md", "sha256");


            if (EVP_PKEY_encrypt(ctx, NULL, &outlen, data, data_len) <= 0)
            {
                return -1;
            }

            outdata = OPENSSL_malloc(outlen);

            if (!outdata) {
                return -1;
            }
            if (EVP_PKEY_encrypt(ctx, outdata, &outlen, data, data_len) <= 0) {
                return -1;
            }

        }
        EVP_PKEY_CTX_free(ctx);
    }

更新: 我对代码进行了更改。 PEM_read_bio_PUBKEY() 返回 NULL。 我的 public 开头是 -----BEGIN RSA PUBLIC KEY----- 我不确定 PEM_read_bio_PUBKEY() 是否是正确的阅读方法。

就是这个类型

PEM_read_bio_RSA_PUBKEY 通过引用获取(如果非空)AND returns RSA * 不是 EVP_PKEY *;请参阅系统的手册页或 on the web。使用错误的 pointed-to 类型违反了 C 中的约束,并且如果您在符合模式下使用一个体面的编译器(这几乎总是一个好主意)它应该给您诊断,您应该注意这一点。

类似地,RSA_size 需要 RSA *,而您实际上没有 EVP_PKEY *,因为您错误地声明并因此有效,但是 EVP_PKEY_CTX_new 需要 EVP_PKEY *,您没有,因此不起作用。如果你幸运的话,它至少会崩溃,或者给你鼻恶魔或重新格式化你的磁盘。

最简单的解决方案是使用 PEM_read_bio_PUBKEY(注意 NO RSA),也在同一个手册页上,它需要 &returns EVP_PKEY * -- 而且不要不要在上面调用 RSA_size。如果您确实需要输出大小或密钥大小,但您似乎没有这样做,请根据需要使用 EVP_PKEY_sizeEVP_PKEY_bits

或者,您可以使用 RSA * 作为 PEM_read_bio_RSA_PUBKEY 的结果,然后将其设置为单独分配的 EVP_PKEY * 以用于加密。这会工作,但更繁琐。

已添加:您还需要对 EVP_PKEY_encrypt

使用 EVP_PKEY_encrypt_init 而不是 _decrypt_init

I have access only to pub key, not to .pem file

文件的扩展名本身并不重要,只是因为它通常用于指示文件的内容。 PEM 格式(在文件中)可用于多种数据,包括 public 键,实际上 PEM_read_[bio]_[type]_PUBKEY 完全读取:一个 PEM 文件(或其他数据源)包含 public 键。如果那不是你所拥有的,那么你的代码比我上面诊断的要错误得多,但是由于你没有说出你所拥有的,所以不可能提供任何有用的建议。如果您的意思是您在 PEM 文件中有 私钥 ,并且想要 public 密钥,请使用 openssl rsa -in private -pubout -out publicopenssl pkey -in private -pubout -out public。 OpenSSL 实际上可以用私钥加密,因为私钥值完全决定了 public 密钥,但任何以这种方式使用密钥的系统都设计得很糟糕,可能不安全。


更新: 您现在披露您的文件包含 -----BEGIN/END RSA PUBLIC KEY-----。这是一种很少使用的格式,它不是 OpenSSL 调用的格式 'PUBKEY',它是来自 X.509/PKIX 的 SubjectPublicKeyInfo 结构并且被标记为 -----BEGIN/END PUBLIC KEY-----(没有 'RSA',尽管它包含 一个 RSA public 密钥)。要阅读您的文件,您必须使用(正如您在评论中所做的那样)PEM_read_[bio]_RSAPublicKey——这需要 &returns RSA * 而不是 EVP_PKEY *。无法将这种类型的文件读取为 EVP_PKEY *,但是由于您需要 EVP_PKEY * 用于您想要的加密例程,因此您必须使用我之前提到的 'alternative':首先读取文件进入 RSA *,然后从 RSA *:

构建一个 EVP_PKEY *
...
RSA * rsa = PEM_read_bio_RSAPublicKey (bio, NULL, NULL, NULL);
if( rsa == NULL ) error;
EVP_PKEY * evp_key = EVP_PKEY_new();
if( evp_key == NULL ) error; // very unlikely
if( ! EVP_PKEY_set1_RSA (evp_key, rsa) ) error;
RSA_free (rsa);
// and then continue as you already have:
EVP_PKEY_CTX* ctx = EVP_PKEY_CTX_new(evp_key, eng/*normally NULL*/);
if nonnull and EVP_PKEY_encrypt_init(ctx) > 0:
  EVP_PKEY_CTX_ctrl ... and EVP_PKEY_encrypt