我尝试在 Swift 中使用 OpenSSL 3 EVP_MAC API 计算 CMAC,但我陷入了 EVP_MAC_init 调用,该调用总是失败。我尝试了很多不同的组合,但没有成功。
如果有人设法做到这一点,请告诉我,这让我发疯,因为 ERR_get_error() 调用也没有给我任何结果,失败后也返回 0。
这是函数:
static func generateAESCMAC(key: [UInt8], message: [UInt8] ) throws -> [UInt8] {
guard let lib = OSSL_LIB_CTX_new()
else {
throw OpenSSLError.cmac("Cannot setup lib ctx")
}
defer { OSSL_LIB_CTX_free(lib) }
guard let macAlgo = EVP_MAC_fetch(lib, "CMAC", nil)
else {
throw OpenSSLError.cmac("Cannot fetch CMAC algo")
}
defer { EVP_MAC_free(macAlgo) }
guard let ctx = EVP_MAC_CTX_new(macAlgo)
else {
throw OpenSSLError.cmac("Cannot create CMAC ctx")
}
defer { EVP_MAC_CTX_free(ctx) }
var params: [OSSL_PARAM] = []
var cipherString = "aes-128-cbc".cString(using: .utf8)!
let cipherParam = OSSL_PARAM_construct_utf8_string(
OSSL_MAC_PARAM_CIPHER,
&cipherString,
0
)
params.append(cipherParam)
params.append(OSSL_PARAM_construct_end())
var keyValue = key
guard EVP_MAC_init(ctx, &keyValue, key.count, params) == 1
else {
throw OpenSSLError.cmac("Cannot init CMAC")
}
guard EVP_MAC_update(ctx, message, message.count) == 1
else {
throw OpenSSLError.cmac("Cannot update CMAC")
}
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("Cannot final CMAC")
}
return Array(cmacResult[0..<cmacLength])
}
找到解决方案,OSSL_PARAM 的处理在内存方面不正常,导致 OSSL_PARAM 无效。这并不能解释为什么 init 调用从未生成错误,当使用无效参数列表调用时,它可能应该会生成错误。
以下代码有效:
static func generateAESCMAC(key: [UInt8], message: [UInt8]) throws -> [UInt8] {
guard let lib = OSSL_LIB_CTX_new()
else {
throw OpenSSLError.cmac("Cannot setup lib ctx")
}
defer { OSSL_LIB_CTX_free(lib) }
guard let macAlgo = EVP_MAC_fetch(lib, "CMAC", nil)
else {
throw OpenSSLError.cmac("Cannot fetch CMAC algo")
}
defer { EVP_MAC_free(macAlgo) }
guard let ctx = EVP_MAC_CTX_new(macAlgo)
else {
throw OpenSSLError.cmac("Cannot create CMAC ctx")
}
defer { EVP_MAC_CTX_free(ctx) }
var cipherString = "AES-128-CBC".cString(using: .utf8)!
try OSSL_MAC_PARAM_CIPHER.withCString { cipherKey in
try cipherString.withUnsafeMutableBytes { cipherBytes in
let cipherParam = OSSL_PARAM_construct_utf8_string(
cipherKey,
cipherBytes.baseAddress,
0
)
let params = [cipherParam, OSSL_PARAM_construct_end()]
guard EVP_MAC_init(ctx, key, key.count, params) == 1
else {
throw OpenSSLError.cmac("Cannot init CMAC")
}
}
}
guard EVP_MAC_update(ctx, message, message.count) == 1
else {
throw OpenSSLError.cmac("Cannot update CMAC")
}
var cmacResult = [UInt8](repeating: 0, count: Int(EVP_MAX_MD_SIZE))
var cmacLength: size_t = 0
if EVP_MAC_final(ctx, &cmacResult, &cmacLength, cmacResult.count) == 1 {
return Array(cmacResult[0..<cmacLength])
} else {
throw OpenSSLError.cmac("Cannot final CMAC")
}
}