You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Swift中使用OpenSSL 3计算CMAC时EVP_MAC_init初始化失败求助

Swift中OpenSSL 3 EVP_MAC初始化失败的修复方案

你的代码在调用EVP_MAC_init时失败,核心问题集中在算法参数、内存指针传递和错误信息收集这几个环节,以下是具体修复方案:

问题分析

  1. 错误的密码算法字符串:CMAC仅需指定块密码算法本身,无需附加模式(如cbc),错误的模式后缀会导致算法匹配失败。
  2. 密钥与算法不匹配:未校验密钥长度与AES算法的对应关系(16字节对应aes-128、24字节对应aes-192、32字节对应aes-256),参数不匹配会直接导致初始化失败。
  3. 不安全的指针传递:直接用&keyValue传递Swift数组地址不符合内存安全规范,可能导致指针失效。
  4. 错误信息缺失:未循环读取OpenSSL错误栈,无法获取完整的失败原因。

修正后的代码

static func generateAESCMAC(key: [UInt8], message: [UInt8]) throws -> [UInt8] {
    // 根据密钥长度匹配对应AES算法
    let cipherName: String
    switch key.count {
    case 16:
        cipherName = "aes-128"
    case 24:
        cipherName = "aes-192"
    case 32:
        cipherName = "aes-256"
    default:
        throw OpenSSLError.cmac("无效AES密钥长度:\(key.count)字节,必须为16、24或32字节")
    }

    guard let lib = OSSL_LIB_CTX_new() else {
        throw OpenSSLError.cmac("无法初始化lib ctx:\(self.opensslErrorMessages())")
    }
    defer { OSSL_LIB_CTX_free(lib) }

    guard let macAlgo = EVP_MAC_fetch(lib, "CMAC", nil) else {
        throw OpenSSLError.cmac("无法获取CMAC算法:\(self.opensslErrorMessages())")
    }
    defer { EVP_MAC_free(macAlgo) }

    guard let ctx = EVP_MAC_CTX_new(macAlgo) else {
        throw OpenSSLError.cmac("无法创建CMAC上下文:\(self.opensslErrorMessages())")
    }
    defer { EVP_MAC_CTX_free(ctx) }

    // 构造CMAC参数:指定底层密码算法
    var cipherCStr = cipherName.cString(using: .utf8)!
    let params = [
        OSSL_PARAM_construct_utf8_string(OSSL_MAC_PARAM_CIPHER, &cipherCStr, 0),
        OSSL_PARAM_construct_end()
    ]

    // 安全传递密钥指针
    let initSuccess = key.withUnsafeBytes { keyBytes in
        EVP_MAC_init(ctx, keyBytes.baseAddress, key.count, params)
    }

    guard initSuccess == 1 else {
        throw OpenSSLError.cmac("无法初始化CMAC:\(self.opensslErrorMessages())")
    }

    guard EVP_MAC_update(ctx, message, message.count) == 1 else {
        throw OpenSSLError.cmac("无法更新CMAC:\(self.opensslErrorMessages())")
    }

    var cmacResult = [UInt8](repeating: 0, count: Int(EVP_MAX_MD_SIZE))
    var cmacLength: size_t = 0
    guard EVP_MAC_final(ctx, &cmacResult, &cmacLength, cmacResult.count) == 1 else {
        throw OpenSSLError.cmac("无法完成CMAC计算:\(self.opensslErrorMessages())")
    }

    return Array(cmacResult[0..<cmacLength])
}

// 辅助方法:收集完整OpenSSL错误信息
private static func opensslErrorMessages() -> String {
    var messages = [String]()
    var err: UInt32
    while let errPtr = ERR_get_error() {
        err = errPtr
        let buf = UnsafeMutablePointer<Int8>.allocate(capacity: 1024)
        ERR_error_string_n(err, buf, 1024)
        messages.append(String(cString: buf))
        buf.deallocate()
    }
    return messages.joined(separator: "; ")
}

关键修复点说明

  • 算法字符串修正:移除cbc模式后缀,CMAC会自动使用块密码的ECB模式完成标准计算。
  • 密钥长度校验:强制校验密钥长度与AES算法的对应关系,避免参数不匹配问题。
  • 安全指针传递:使用withUnsafeBytes获取密钥的原始字节指针,符合Swift内存安全规则。
  • 完整错误收集:循环读取OpenSSL错误栈,获取全部失败原因,便于调试定位问题。

内容的提问来源于stack exchange,提问作者Thomas Debouverie

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.20 11:55:02