Equivalent of CBCBlockCipherMac from bouncycastle for swift

1k Views Asked by At

I need to re-implement for iOS (swift) a cryptographic operation done for an Android app (kotlin) thanks to bouncycastle's lbrary. The kotlin code is :

val mac = "9D3391051A4E774B".hexStringToByteArray()
val macKey = "89D7B23D500D492FA01DC53B44864AB8".hexStringToByteArray()
val cipheredData = "E77A914D5C94A04B6D8E10BA7A56A015AC2C40167F867A97B6349F29F3100D6D".hexStringToByteArray()

var macBlock = CBCBlockCipherMac(AESEngine(), ISO7816d4Padding())
macBlock.init(KeyParameter(macKey))
macBlock.update(cipheredData, 0, cipheredData.size)
var output = ByteArray(8)
macBlock.doFinal(output, 0)

if(output.toHex() == mac.toHex()) {
    print("equals !!")
} else {
    print("not equals : ${output.toHex()}")
}

This code works, the found mac from the output is the same as the original 'mac' property.

I tried using swift Library CryptoSwift with this code :

let mac = Data(hex: "9D3391051A4E774B")
let macKey = Data(hex: "89D7B23D500D492FA01DC53B44864AB8")
let cipheredData = Data(hex: "E77A914D5C94A04B6D8E10BA7A56A015AC2C40167F867A97B6349F29F3100D6D")

do {
    var output = try CBCMAC(key: macKey.bytes).authenticate(cipheredData.bytes)
    checkOutput(mac: mac, output: output)
} catch {
    debugPrint("Exception \(error)")
}

But this doesn't work. The algorithm behind the CryptoSwift's CBCMAC class is not doing the same think as bouncycastle's CBCBlockCipherMac.

I also tried using apple's CommonCrypto library but there is no CBCMAC authentification, only HMAC. I didn't find any way of doing CBC-MAC authentification easily for iOS plateform.

1

There are 1 best solutions below

3
On BEST ANSWER

I found a solution, developing the real CBC-MAC encryption in CryptoSwift class :

public func authenticate(_ cipheredBytes: Array<UInt8>, padding: Padding, blockSize: Int) throws -> Array<UInt8> {
    var inBytes = cipheredBytes
    bitPadding(to: &inBytes, blockSize: blockSize)
    let blocks = inBytes.chunked(into: blockSize)

    var lastBlockEncryptionResult : [UInt8] = CBCMAC.Zero
    try blocks.forEach { (block) in
        let aes = try AES(key: Array(key), blockMode: CBC(iv: lastBlockEncryptionResult), padding: padding)
        lastBlockEncryptionResult = try aes.encrypt(block)
    }

    return lastBlockEncryptionResult
}

Calling this with my initial parameters gives the answer :

9d3391051a4e774b7572fb9bca51dc51

So the first 8 bits are the good ones.