【问题标题】:How to programmatically create encrypted PKCS#7 using ECC certificate and OpenSSL in C?如何在 C 中使用 ECC 证书和 OpenSSL 以编程方式创建加密的 PKCS#7?
【发布时间】:2021-04-07 13:19:25
【问题描述】:

执行此操作的 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_encrypt 函数(这适用于 RSA)

STACK_OF(X509)* stackOfX509 = sk_X509_new_null();
X509* x509Cert = d2i_X509(NULL, &(cert->buff), cert->buffLen);
sk_X509_push(stackOfX509, x509Cert);
CMS_ContentInfo* pkcs7EnvelopedData = CMS_ContentInfo_new();
BIO* dataBIOToEncrypt = BIO_new_mem_buf(data2Encrypt->buff, data2Encrypt->buffLen);

pkcs7EnvelopedData = CMS_encrypt(stackOfX509, dataBIOToEncrypt, cipher, CMS_BINARY);

这当然行不通。我不知道如何通过keyopt。我现在正在寻找这个。找到即EVP_PKEY_CTX_ctrl_str(ctx, "ecdh_kdf_md", "sha256");,但这需要我拥有EVP_PKEY_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);

【问题讨论】:

    标签: c openssl elliptic-curve pkcs#7


    【解决方案1】:

    如果你分解 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;
    }
    

    您必须原谅我使用 C++,因为您要求使用 C,但上面的示例为我编译并根据您的示例 openssl 命令生成正确的输出。

    与您的代码唯一真正的区别是它调用i2d_CMS_bio_stream 来编写输出,而不是您尝试使用 CMS_final,文档说该参数仅用于分离数据,而您在这里没有这样做。

    您的代码还使用了 CMS_BINARY 选项,这会将 -binary 选项添加到您的 openssl 命令中。

    【讨论】:

    • 是的,我也确实使用了cms.c 作为参考点。你也执行了CMS_final,所以代码看起来是一样的,除了我不需要文件处理程序。 EVP_EncryptInit_ex 似乎也没有必要。我正在 iOS 上构建它,它在 CMS_dataInit: crypto/evp/evp_enc.cCMS_final somwhere 处崩溃,但我不擅长阅读 ASM。我猜算法的输入参数可能不好。所以,我想我会用命令行来调试应用程序以确定输入。无论如何谢谢你的回答!这让我走上了正轨:)
    • 另一方面,您的代码按您所说的那样编译/运行,所以它们应该是好的。这一定是别的东西。
    • 您是否正在检查您的返回码以查看您之前的最后一次通话是否失败?一个可能的问题可能是您添加的证书类型,因为 ecdh 要求导致 EVP_PKEY_CTX_ctrl_str 调用失败。
    • 是的。我在其他地方成功使用了相同的证书加载器。这里没有错误。我还检查了每个命令结果,(char*)ERR_error_string((int)ERR_get_error(), NULL); 没有出现错误。 EVP_PKEY_CTX_ctrl_str 返回 1。
    • 明白了!问题在于我对 C 的了解不足,我将 EVP_CIPHER 指针传递给 CMS_encrypt 但方法错误。在我把原始的CMS_encrypt(NULL, dataBIOToEncrypt, EVP_aes_256_cbc(), flags); 放在那里之后,它起作用了......再次感谢您的时间!非常感谢
    猜你喜欢
    • 2010-09-20
    • 2011-06-08
    • 1970-01-01
    • 1970-01-01
    • 2011-09-16
    • 1970-01-01
    • 2011-05-02
    • 2013-04-23
    • 2011-03-16
    相关资源
    最近更新 更多