Search code examples
c#cryptographymifaredes

Computing a MAC for a DESFire file read


I am being driven mildly mad by this. I am trying to validate a MAC code produced by a read of data from a DESFire card. After authentication I have:

RNDA: 174067B263D4A2FB
RNDB: 28556156579E6F8D

Which makes a session key of 174067B228556156. I do a read of a file that contains the ASCII 'Hello'. The resultant data is:

48656C6C6F9E34BA18 which makes the MAC 9E34BA18. I cannot reproduce it. My C# code is below. It produces a MAC of 826C10B4DD1F3632 neither top nor bottom 32-bits are the desired MAC.

        byte[] data = new byte[] { 0x48, 0x65, 0x6C, 0x6C, 0x6F}; // Hello
        var key16 = Slicer.FromHexToBytes(SessionKey + SessionKey);
        for (int i = 0; i < 16; i++)
        {
            key16[i] = (byte)(key16[i] & 0xfe); // bottom bit contains version so set it to 0
        }
        KeyParameter key = new DesParameters(key16);
        var mac = Org.BouncyCastle.Security.MacUtilities.GetMac("DESEDEISO9797ALG1MACWITHISO7816-4PADDING");
        mac = new CbcBlockCipherMac(new DesEdeEngine(), 64, new ZeroBytePadding());
        mac.Init(key);

        mac.BlockUpdate(data, 0, data.Length);

        byte[] outBytes = new byte[mac.GetMacSize()];
        mac.DoFinal(outBytes, 0);
        Debug.Print(outBytes);

Just doubling up the session key seems like a guess but I have seen it mentioned in several places. I hope I am on the right track, can anyone suggest what I am doing wrong?


Solution

  • Looks like DESFire protocol is not public. You will need to reverse engineer it. There are others who have gone down this path before. Take a look at this example project in Python: https://github.com/miohtama/desfire

    I apologize that the only code I could find was in a different language. I am glad you were able to extract the logic you needed from it.

    The solution you cited is:

    It turns out the session key is dependant on the authentication key. The doubling I mention is correct if the authentication key is symmetric which it is for the default 0000....000 key - and which it wasn't in my example.