ios - 在 iOS 上使用 Openssl 的 CMS 加密问题

标签 ios swift encryption openssl x509

我正在尝试使用 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也失败)

有趣的是它正在崩溃。这告诉我我的输入之一必须无效。根据文档,如果它未能加密它应该返回 NULL。如果成功,它应该返回一个 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 维护者那里得到了“报价”。我找不到受支持密码的“明确”列表。

如果您查看 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 页面上看到“支持”列表。

在尝试直接针对 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;
}

关于ios - 在 iOS 上使用 Openssl 的 CMS 加密问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56244418/

相关文章:

ios - 如何通过AVPlayer iOS以音频2.0播放视频

ios - 无法从 iMessage 应用程序访问相机

sql - 如何在 SQL Server 中备份对称 key ?

cocoa - 在相同加密的情况下更改密文(IV) Cocoa?

ios - 带有 UITapGestureRecognizer 的 UIView 上的 UITableView(单元格选择不起作用)

ios - 使用新行更新 TableView ,首先保留先前的行

ios - 为什么 Flickr 没有 UIActivity?

swift - 在 Swift(iOS 应用程序)中,什么时候需要使用其他整数类型?

ios - 转换为 swift 3.0 时,UIButton 上 'dismiss()' 的使用不明确

java - 使用 PBEWithMD5AndDES 加密字符串以与 Java 存储的哈希进行比较