openssl smime -encrypt 命令使用PKCS7_encrypt API 使用证书堆栈加密数据。
这是一个使用它的示例,它使用 C API 的 C++ 使用重现上述命令。
template<typename T, typename D>
std::unique_ptr<T, D> make_handle(T* handle, D deleter)
{
return std::unique_ptr<T, D>{handle, deleter};
}
bool encrypt_data()
{
// load the stack of certificates
auto const encrypt_certificate_stack = make_handle(sk_X509_new_null(), [](auto handle){ sk_X509_pop_free(handle, X509_free); });
if(!encrypt_certificate_stack) return false;
auto file = make_handle(BIO_new_file("alice.pem", "r"), BIO_free);
auto cert = PEM_read_bio_X509(file.get(), nullptr, nullptr, nullptr);
if(!cert) return false;
sk_X509_push(encrypt_certificate_stack.get(), cert);
file = make_handle(BIO_new_file("bob.pem", "r"), BIO_free);
cert = PEM_read_bio_X509(file.get(), nullptr, nullptr, nullptr);
if(!cert) return false;
sk_X509_push(encrypt_certificate_stack.get(), cert);
// input file
auto const infile = make_handle(BIO_new_file("secret.txt", "rb"), BIO_free);
if(!infile) return false;
// encrypt
auto const flags = PKCS7_DETACHED | PKCS7_BINARY;
auto const p7 = make_handle(PKCS7_encrypt(encrypt_certificate_stack.get(), infile.get(), EVP_aes_256_cbc(), flags), PKCS7_free);
if(!p7) return false;
// write the output file as PEM format
auto const outfile = make_handle(BIO_new_file("secret.out.pem", "w"), BIO_free);
if(!outfile) return false;
if(PEM_write_bio_PKCS7_stream(outfile.get(), p7.get(), infile.get(), flags) == 0) return false;
return true;
}
更新:
PKCS7_decrypt API 声明:
虽然解密数据不需要收件人证书
需要找到合适的(可能的几个)
PKCS#7 结构中的接收者。
意味着证书是可选的,因此您可以将 nullptr 传递给该参数,它在您的简单示例中可以正常工作。
如果您确实传递了证书,它会将证书与私钥匹配,如果失败,解密将失败。
所以没有证书的解密代码如下所示:
bool decrypt_data()
{
// read in private key
auto file = make_handle(BIO_new_file("aliceprivatekey.pem", "r"), BIO_free);
auto const key = make_handle(PEM_read_bio_PrivateKey(file.get(), nullptr, nullptr, (void*)"password"), EVP_PKEY_free);
file.reset();
if(!key) return false;
// read in PKCS7 data
auto infile = make_handle(BIO_new_file("secret.out.pem", "rb"), BIO_free);
if(!infile) return false;
auto const p7 = make_handle(PEM_read_bio_PKCS7(infile.get(), nullptr, nullptr, nullptr), PKCS7_free);
if (!p7) return false;
infile.reset();
// decrypt and write to stdout
auto const out = BIO_new_fp(stdout, BIO_NOCLOSE);
auto const flags = PKCS7_DETACHED;
return PKCS7_decrypt(p7.get(), key.get(), nullptr, out, flags) != 0;
}
更新 2:
如果您只想通过 openssl API 在内存缓冲区中使用,则有一个 memory BIO 可用于仅内存 BIO。
std::vector<char> data;
auto memory_bio = make_handle(BIO_new_mem_buf(data.data(), data.size()), BIO_free);