Команда openssl smime -encrypt использует API PKCS7_encrypt для шифрования данных с помощью стека сертификатов.
Вот пример его использования, который воспроизводит указанную выше команду с использованием 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;
}
UPDATE:
API-интерфейс PKCS7_decrypt :
Хотя сертификат получателя не требуется для расшифровки данных
необходимо найти подходящее (возможно несколько)
получатели в структуре 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:
Существует память BIO , которую можно использовать только для памяти BIO, если вы хотите использовать ее в буферах памяти только с API openssl.
std::vector<char> data;
auto memory_bio = make_handle(BIO_new_mem_buf(data.data(), data.size()), BIO_free);