首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >在iOS上使用Open SSL的CMS_Encrypt问题

在iOS上使用Open SSL的CMS_Encrypt问题
EN

Stack Overflow用户
提问于 2019-05-22 02:31:07
回答 2查看 230关注 0票数 2

我正在尝试使用OpenSSL的CMS_encrypt方法,但遇到了崩溃

EXC_BAD_ACCESS (code=1,address=0xaa0003f4aa0203fe)

根据OpenSSL docs的说法

代码语言:javascript
复制
 #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个证书,我认为在收件人信息周围可能需要额外的代码,或者堆栈可能是错误的?我没有把握。我很乐意得到任何反馈。谢谢。

代码语言:javascript
复制
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();
}
EN

回答 2

Stack Overflow用户

回答已采纳

发布于 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库再现上面的示例时,一旦我切换了密码,它就对我起作用了。所以我只能假设你的问题出在别的地方。

我的代码可以正常工作的重现示例(例如,它可以很好地加密和解密):

代码语言:javascript
复制
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;
}
票数 2
EN

Stack Overflow用户

发布于 2019-05-22 06:29:49

Shane的答案是正确的,因为密码不受支持,但这不会导致崩溃。崩溃是由证书堆栈中指针的错误引起的。下面的代码用于生成我的堆栈

代码语言:javascript
复制
+ (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文档,并只返回一个空对象。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/56244418

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档