Swift中使用OpenSSL 3计算CMAC时EVP_MAC_init初始化失败求助
Swift中OpenSSL 3 EVP_MAC初始化失败的修复方案
你的代码在调用EVP_MAC_init时失败,核心问题集中在算法参数、内存指针传递和错误信息收集这几个环节,以下是具体修复方案:
问题分析
- 错误的密码算法字符串:CMAC仅需指定块密码算法本身,无需附加模式(如
cbc),错误的模式后缀会导致算法匹配失败。 - 密钥与算法不匹配:未校验密钥长度与AES算法的对应关系(16字节对应aes-128、24字节对应aes-192、32字节对应aes-256),参数不匹配会直接导致初始化失败。
- 不安全的指针传递:直接用
&keyValue传递Swift数组地址不符合内存安全规范,可能导致指针失效。 - 错误信息缺失:未循环读取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
相关产品推荐
相关产品推荐

