我有两个公共密钥,我使用下面的命令通过这两个公共密钥加密数据
openssl smime -encrypt -binary -aes256 -in secret.txt -out secret_multi.enc -outform PEM alice.pub bob.pub
因此基本上可以使用alice.pub和bob.pub来使用其私钥解密数据secret_multi.enc。
请帮助我如何使用openssl API函数实现此目标。
即使用多个密钥加密数据。
相当于我上面提到的命令。
答案 0 :(得分:1)
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);