如何在C中使用ECC证书和OpenSSL以编程方式创建加密的PKCS#7?

如何在C中使用ECC证书和OpenSSL以编程方式创建加密的PKCS#7?,c,openssl,elliptic-curve,pkcs#7,C,Openssl,Elliptic Curve,Pkcs#7,执行此操作的OpenSSL控制台命令是: openssl cms -encrypt -aes-256-cbc -in plain-original.txt -outform der -out encrypted.p7 -recip certificate.pem -keyopt ecdh_kdf_md:sha256 假设certificate.pem为EC类型。 我正在尝试使用CMS\u encrypt函数(这适用于RSA) 这当然不行。我不知道如何通过keyopt。我在找这个有一段时间了。发

执行此操作的OpenSSL控制台命令是:

openssl cms -encrypt -aes-256-cbc -in plain-original.txt -outform der -out encrypted.p7 -recip certificate.pem -keyopt ecdh_kdf_md:sha256
假设
certificate.pem
为EC类型。 我正在尝试使用
CMS\u encrypt
函数(这适用于RSA)

这当然不行。我不知道如何通过
keyopt
。我在找这个有一段时间了。发现,即:EVP_PKEY_CTX_ctrl_str(CTX,“ecdh_kdf_md”,“sha256”)但这需要我有
EVP\u PKEY\u CTX

在我开始挖掘OpenSSL源代码以确定他们是如何做到这一点之前,也许有人能给我一些提示

---更新---

好吧,我知道我的第一次尝试过于简单了。越来越近我希望:

pkcs7EnvelopedData = CMS_encrypt(NULL, dataBIOToEncrypt, cipher, CMS_BINARY | CMS_PARTIAL);
CMS_RecipientInfo *ri = CMS_add1_recipient_cert(pkcs7EnvelopedData, x509Cert, CMS_BINARY | CMS_PARTIAL | CMS_KEY_PARAM);
EVP_PKEY_CTX *pctx = CMS_RecipientInfo_get0_pkey_ctx(ri);
EVP_PKEY_CTX_ctrl_str(pctx, "ecdh_kdf_md", "sha256");
EVP_CIPHER_CTX *wctx = CMS_RecipientInfo_kari_get0_ctx(ri);
EVP_EncryptInit_ex(wctx, EVP_aes_256_wrap(), NULL, NULL, NULL);
CMS_final(pkcs7EnvelopedData, dataBIOToEncrypt, NULL, CMS_BINARY | CMS_PARTIAL);

如果您分解openssl应用程序cms.c源文件以生成命令,您将得到:

bool CMS_encrypt_example(char const* in_file_name, char const* out_file_name, char const* recip_cert_path )
{
    // openssl cms -encrypt -aes-256-cbc -in plain-original.txt -outform der -out encrypted.p7 -recip certificate.pem -keyopt ecdh_kdf_md:sha256

    auto in = make_handle(BIO_new_file(in_file_name, "rb"), BIO_free);
    if(!in) return false;

    auto file = make_handle(BIO_new_file(recip_cert_path, "r"), BIO_free);
    auto cert = PEM_read_bio_X509(file.get(), nullptr, nullptr, nullptr);
    if(!cert) return false;

    auto flags = CMS_PARTIAL;
    auto const content_info = make_handle(CMS_encrypt(nullptr, in.get(), EVP_aes_256_cbc(), flags), CMS_ContentInfo_free);
    if(!content_info) return false;

    auto* ri = CMS_add1_recipient_cert(content_info.get(), cert, flags | CMS_KEY_PARAM);
    if(ri == nullptr) return false;

    auto* pctx = CMS_RecipientInfo_get0_pkey_ctx(ri);
    if (EVP_PKEY_CTX_ctrl_str(pctx, "ecdh_kdf_md", "sha256") <= 0) return false;

    if(!CMS_final(content_info.get(), in.get(), nullptr, flags)) return false;

    auto const outfile = make_handle(BIO_new_file(out_file_name, "wb"), BIO_free);
    if(!outfile) return false;
    if(i2d_CMS_bio_stream(outfile.get(), content_info.get(), in.get(), flags) == 0) return false;

    return true;
}
boolcms\u encrypt\u示例(char const*in\u file\u name、char const*out\u file\u name、char const*recip\u cert\u path)
{
//openssl cms-encrypt-aes-256-cbc-in plain-original.txt-outform der-out encrypted.p7-recip certificate.pem-keyopt ecdh_kdf_md:sha256
auto-in=make_handle(BIO_-new_文件(在文件名中为“rb”),BIO_-free);
如果(!in)返回false;
自动文件=生成句柄(BIO新文件(往复证书路径,“r”)、BIO自由);
自动证书=PEM_read_bio_X509(file.get(),nullptr,nullptr,nullptr);
如果(!cert)返回false;
自动标志=CMS_部分;
auto const content_info=make_handle(CMS_encrypt(nullptr,in.get(),EVP_aes_256_cbc(),flags),CMS_ContentInfo_free);
如果(!content_info)返回false;
auto*ri=CMS_add1_recipient_cert(content_info.get(),cert,flags | CMS_KEY_PARAM);
if(ri==nullptr)返回false;
auto*pctx=CMS\u RecipientInfo\u get0\u pkey\u ctx(ri);

如果(执行副总裁、首席技术官、首席技术官、首席技术官、首席技术官、首席技术官、首席技术官、首席技术官)是的,我也使用了
cms.c
作为参考点。你也执行了
cms\u final
,所以代码看起来是一样的,只是我不需要文件处理程序。另外
EVP\u EncryptInit\u ex
似乎没有必要。我在iOS上构建这个,它在
cms\u final
中的某些地方崩溃了
cms\u dataInit:crypto/EVP/EVP\u encc
,但我不擅长阅读ASM。我猜算法的输入参数可能不好。所以,我想我会用命令行调试应用程序以确定输入。无论如何,感谢您的回答!这让我走上了正确的轨道:)另一方面,你的代码按照你说的编译/运行,所以它们应该是好的。这一定是其他原因。你是否检查你的返回代码,看你上次的最终调用没有失败?一个可能的问题可能是你添加的证书类型,因为ecdh要求使EVP_PKEY_CTX_ctrl_str调用失败。是的。我使用相同的ce证书加载程序ELSHERE成功。此处没有错误。我还使用
(char*)ERR\u error\u字符串((int)ERR\u get\u error(),NULL)检查了每个命令结果
没有错误。
EVP\u PKEY\u CTX\u ctrl\u str
返回1.明白了!问题是我对C的了解不够,我传递了
EVP\u CIPHER
指向
CMS\u encrypt
的指针,但方向错误。在我把原始
CMS\u encrypt(NULL,dataBIOToEncrypt,EVP\u aes\u 256\u cbc(),flags)放在那里之后
成功了…再次感谢您抽出时间!非常感谢
bool CMS_encrypt_example(char const* in_file_name, char const* out_file_name, char const* recip_cert_path )
{
    // openssl cms -encrypt -aes-256-cbc -in plain-original.txt -outform der -out encrypted.p7 -recip certificate.pem -keyopt ecdh_kdf_md:sha256

    auto in = make_handle(BIO_new_file(in_file_name, "rb"), BIO_free);
    if(!in) return false;

    auto file = make_handle(BIO_new_file(recip_cert_path, "r"), BIO_free);
    auto cert = PEM_read_bio_X509(file.get(), nullptr, nullptr, nullptr);
    if(!cert) return false;

    auto flags = CMS_PARTIAL;
    auto const content_info = make_handle(CMS_encrypt(nullptr, in.get(), EVP_aes_256_cbc(), flags), CMS_ContentInfo_free);
    if(!content_info) return false;

    auto* ri = CMS_add1_recipient_cert(content_info.get(), cert, flags | CMS_KEY_PARAM);
    if(ri == nullptr) return false;

    auto* pctx = CMS_RecipientInfo_get0_pkey_ctx(ri);
    if (EVP_PKEY_CTX_ctrl_str(pctx, "ecdh_kdf_md", "sha256") <= 0) return false;

    if(!CMS_final(content_info.get(), in.get(), nullptr, flags)) return false;

    auto const outfile = make_handle(BIO_new_file(out_file_name, "wb"), BIO_free);
    if(!outfile) return false;
    if(i2d_CMS_bio_stream(outfile.get(), content_info.get(), in.get(), flags) == 0) return false;

    return true;
}