【问题标题】:Issues with CMS_Encrypt using Open SSL on iOS在 iOS 上使用 Open SSL 的 CMS_Encrypt 问题
【发布时间】:2019-10-08 05:02:20
【问题描述】:

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

EXC_BAD_ACCESS(代码=1,地址=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() 创建并返回一个 CMS EnvelopedData 结构。 certs 是收件人证书的列表。 in 是要加密的内容。 cipher 是要使用的对称密码。 flags 是一组可选的标志。

我已经仔细检查了我放入 dataToEncrpytBIO 的数据实际上是否正确写入 BIO。

我尝试过使用各种密码和标志,但似乎没有任何组合有效,所以我暂时将其保留为CMS_Text。 (传入0也失败)

有趣的是它正在崩溃。这告诉我我的输入之一必须是无效的。根据文档,如果它未能加密它应该返回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();
}

【问题讨论】:

    标签: ios swift encryption openssl x509


    【解决方案1】:

    CMS 封装数据不支持 GCM。改用 EVP_aes_256_cbc() 之类的东西。

    更新:

    我从一个 openssl 维护者那里得到了“报价”。我找不到支持密码的“明确”列表。

    如果您查看 CMS 帮助 page 您会看到:

    有关您的 OpenSSL 版本支持的密码列表,请参阅 enc(1)。

    如果您查看链接的 enc 页面,您会看到:

    enc 程序不支持经过身份验证的加密模式,例如 CCM 和 GCM,未来将不支持此类模式。

    我认为这适用于 CMS,并且它在 CMS 中使用相同的加密例程。

    您还可以在 enc 页面上查看“支持”列表。

    在尝试直接在 C 中针对 openssl lirary 复制上面的示例时,一旦我切换密码,它就对我有用。所以我只能假设你的问题在其他地方。

    我的代码复制示例(即它可以很好地加密和解密):

    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;
    }
    

    【讨论】:

    • 无论密码如何,我仍然会遇到相同的错误。在单独的说明中。我现在如何知道 CMS 支持哪些密码?
    【解决方案2】:

    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;
    }
    

    我正在返回证书堆栈的内存引用&amp;sk,并在堆栈上创建它,而不是作为指向另一块内存的指针。退出该方法后,它会在未来被其他东西踩到。这就是为什么加密对我来说失败的原因。

    我还将密码更改为EVP_aes_256_cbc()。我尝试使用健身房,但它未能加密,但遵循 OpenSSL 文档,只是返回了一个空对象。

    【讨论】:

      猜你喜欢
      • 2012-02-22
      • 1970-01-01
      • 2012-03-27
      • 1970-01-01
      • 1970-01-01
      • 2010-12-31
      • 2021-04-16
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多