CMS_Encrypt 在 iOS 上使用 Open SSL 的问题
Issues with CMS_Encrypt using Open SSL on iOS
我正在尝试使用 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_encrypt() creates and returns a CMS EnvelopedData structure. certs is a list of recipient certificates. in is the content to be encrypted. cipher is the symmetric cipher to use. flags is an optional set of flags.
我仔细检查了我放置在 dataToEncrpytBIO
中的数据实际上是否正确写入了 BIO。
我试过使用各种密码和标志,但似乎没有任何组合起作用,所以我暂时将其保留为 CMS_Text
。 (传入0也失败)
有趣的是它正在崩溃。这告诉我我的输入之一必须无效。根据文档,如果它未能加密其应该 return NULL
。如果成功,它应该 return a CMS_ContentInfo
CMS_encrypt() returns either a CMS_ContentInfo structure or NULL if an error occurred. The error can be obtained from 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();
}
CMS 封装数据不支持 GCM。改用 EVP_aes_256_cbc() 之类的东西。
更新:
我从 openssl 维护者那里得到了 "quote"。我找不到 "clear" 支持的密码列表。
如果您查看 CMS 帮助 page,您会看到:
See enc(1) for a list of ciphers supported by your version of OpenSSL.
如果您查看链接的 enc 页面,您会看到:
The enc program does not support authenticated encryption modes like
CCM and GCM, and will not support such modes in the future.
我相信这适用于 CMS 以及它在 CMS 中使用相同的加密例程。
您也可以在 enc 页面上看到 "supported" 列表。
在尝试直接针对 openssl 库在 C 中重现上面的示例时,一旦我切换了密码,它就对我有用。所以我只能假设你的问题出在其他地方。
我的代码重现示例有效(即加密和解密都很好):
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;
}
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 文档,并返回了一个空对象。
我正在尝试使用 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_encrypt() creates and returns a CMS EnvelopedData structure. certs is a list of recipient certificates. in is the content to be encrypted. cipher is the symmetric cipher to use. flags is an optional set of flags.
我仔细检查了我放置在 dataToEncrpytBIO
中的数据实际上是否正确写入了 BIO。
我试过使用各种密码和标志,但似乎没有任何组合起作用,所以我暂时将其保留为 CMS_Text
。 (传入0也失败)
有趣的是它正在崩溃。这告诉我我的输入之一必须无效。根据文档,如果它未能加密其应该 return NULL
。如果成功,它应该 return a CMS_ContentInfo
CMS_encrypt() returns either a CMS_ContentInfo structure or NULL if an error occurred. The error can be obtained from 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();
}
CMS 封装数据不支持 GCM。改用 EVP_aes_256_cbc() 之类的东西。
更新:
我从 openssl 维护者那里得到了 "quote"。我找不到 "clear" 支持的密码列表。
如果您查看 CMS 帮助 page,您会看到:
See enc(1) for a list of ciphers supported by your version of OpenSSL.
如果您查看链接的 enc 页面,您会看到:
The enc program does not support authenticated encryption modes like CCM and GCM, and will not support such modes in the future.
我相信这适用于 CMS 以及它在 CMS 中使用相同的加密例程。
您也可以在 enc 页面上看到 "supported" 列表。
在尝试直接针对 openssl 库在 C 中重现上面的示例时,一旦我切换了密码,它就对我有用。所以我只能假设你的问题出在其他地方。
我的代码重现示例有效(即加密和解密都很好):
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;
}
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 文档,并返回了一个空对象。