I'm trying to compute a CMAC using OpenSSL 3 EVP_MAC APIs in Swift, and I am stuck at the EVP_MAC_init call, which always fails. I've tried many different combinations, without success.
If anyone managed to do this, please let me know, it's making me crazy as also the ERR_get_error() call gives me nothing, also returns 0 after the failure.
Here is the function:
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])
}
Found the solution, handling of the OSSL_PARAM was not OK memory wise, resulting in an invalid OSSL_PARAM. That does not explain why the init call never generated an error, it should probably have when called with an invalid parameter list.
The following code works:
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")
}
}