我正在尝试使用OpenSSL的CMS_encrypt方法,但遇到了崩溃
EXC_BAD_ACCESS (code=1,address=0xaa0003f4aa0203fe)
根据OpenSSL docs的说法
#include <openssl/cms.h>
CMS_ContentInfo *CMS_encrypt(STACK_OF(X509) *certs, BIO *in,
const EVP_CIPHER *cipher, unsigned int flags);
CMS CMS_encrypt()创建并返回
EnvelopedData结构。证书是收件人证书的列表。in是要加密的内容。cipher是要使用的对称密码。标志是一组可选的标志。
我已经仔细检查了我放在dataToEncrpytBIO
中的数据是否真的被正确地写入了BIO。
我尝试过使用各种密码和标志,但似乎没有一种组合有效,所以我暂时将其保留为CMS_Text
。(传入0也会失败)
有趣的是,它正在崩溃。这告诉我,我的一个输入必须是invlalid。根据文档,如果加密失败,它应该返回NULL
。如果成功,它应该返回一个CMS_ContentInfo
CMS_encrypt()返回CMS_ContentInfo结构,如果出现错误,则返回NULL。误差可以从ERR_get_error(3)获得。
我猜我的证书堆栈有问题。尽管它成功地创建了,但当我查看堆栈时,它显示我有1个证书,我认为在收件人信息周围可能需要额外的代码,或者堆栈可能是错误的?我没有把握。我很乐意得到任何反馈。谢谢。
func cmsEncryptionTest(){
//Set Algorithms
addAlgorithms()
//Prepare data to encrypt
let testEncryptionString = "String to Encrypt"
let testEncryptionData = testEncryptionString.data(using: .utf8)!
let dataToEncryptBIO = BIO_new(BIO_s_mem())
BIO_write(dataToEncryptBIO, (testEncryptionData as NSData).bytes, Int32(testEncryptionData.count))
//Prepare Certificate Stack
let deviceCert = "MIIDXXXXXXXXXXXXXXXXXX="
guard let base64Data = Data(base64Encoded: deviceCert, options: Data.Base64DecodingOptions.ignoreUnknownCharacters) else {
throw TestError.failedToDecodeBase64
}
let certBIO = BIO_new(BIO_s_mem())
BIO_write(certBIO, (base64Data as NSData).bytes, Int32(base64Data.count))
guard let x509Cert: UnsafeMutablePointer<X509> = d2i_X509_bio(certBIO, nil) else{
throw TestError.failedToLoadCertificate
}
let certStack = generateX509Stack(x509Cert.pointee)
//Perform Encryption
var flags:UInt32 = UInt32(CMS_TEXT)
//Crashes
let cms = CMS_encrypt(certs, dataToEncrypt, EVP_aes_256_gcm(), flags)
....
}
//Objective-C Helper Method to put a cert on an x509Stack
struct stack_st_X509 * generateX509Stack(X509 cert){
struct stack_st_X509 sk = *sk_X509_new_null();
sk_X509_push(&sk, &cert);
return &sk;
}
//Objective-C Helper Method to add algorithms
void addAlgorithms(){
OpenSSL_add_all_algorithms();
}
发布于 2019-05-22 04:30:38
CMS封装数据不支持GCM。改为使用类似EVP_aes_256_cbc()的内容。
更新:
我是从一个openssl维护者那里得到这句话的。我找不到支持的密码的“清晰”列表。
如果您查看CMS帮助page,您会看到:
有关您的OpenSSL版本支持的密码列表,请参阅enc(1)。
如果您查看链接的enc页面,您会看到:
enc程序不支持CCM和GCM等认证加密模式,将来也不会支持此类模式。
我相信这适用于CMS,以及它在CMS中使用相同的加密例程。
您还可以在enc页面上看到“受支持”列表。
在尝试用C语言直接针对openssl库再现上面的示例时,一旦我切换了密码,它就对我起作用了。所以我只能假设你的问题出在别的地方。
我的代码可以正常工作的重现示例(例如,它可以很好地加密和解密):
bool CMS_encrypt_data()
{
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);
/*
auto const in = make_handle(BIO_new_file(R"(C:\work\testcert\secret.txt)", "rb"), BIO_free);
if(!in) return false;
*/
auto const in = make_handle(BIO_new(BIO_s_mem()), BIO_free);
if(!in) return false;
auto const data = "this is a secret"s;
if(BIO_write(in.get(), data.c_str(), data.size()) <= 0) return false;
auto const flags = 0;
auto const content_info = make_handle(CMS_encrypt(encrypt_certificate_stack.get(), in.get(), EVP_aes_256_cbc(), flags), CMS_ContentInfo_free);
if(!content_info) return false;
auto const outfile = make_handle(BIO_new_file("secret.out", "w"), BIO_free);
if(!outfile) return false;
if(PEM_write_bio_CMS_stream(outfile.get(), content_info.get(), in.get(), flags) == 0) return false;
return true;
}
发布于 2019-05-22 06:29:49
Shane的答案是正确的,因为密码不受支持,但这不会导致崩溃。崩溃是由证书堆栈中指针的错误引起的。下面的代码用于生成我的堆栈
+ (nullable struct stack_st_X509 *) generateX509Stack: (nonnull X509 *) cert{
struct stack_st_X509 *sk = sk_X509_new_null();
int result = sk_X509_push(sk, cert);
return sk;
}
我返回证书&sk
堆栈的内存引用,并在堆栈上创建它,而不是作为指向另一块内存的指针。在退出该方法之后,它将在将来被其他东西践踏。这就是为什么加密对我来说失败了。
我还将密码更改为EVP_aes_256_cbc()
。我尝试使用健身房,它加密失败,但遵循OpenSSL文档,并只返回一个空对象。
https://stackoverflow.com/questions/56244418
复制相似问题