Search code examples
encryptioncryptographyaesmifaredesfire

Decrypt DESFire ReadData Session


We´re struggeling with the decryption of DESFire Data. We´ve authenticated successfully and could decrypt RndA´ which was the same as the RndA we´ve created.

Now we try to read an encyphered File from position 0 for 16 bytes.

From some java library we could figure out, that we have to use the encyphered Command as IV for the decryption. Is that right?

Here the examples:

SessionKey: 0ba1caf83a26a72170149b7504895f34
ReadCommand: bd00000000100000
Crc32C for Cmd: D9CEE76B
Secret: 6a0d0f0d5c8f054b1e5914a42e49728622774c6272e5c34a69ed302251576aaf

So now we concat the ReadCommand with Crc32C:

bd00000000100000D9CEE76B

Then we padd Zeros up to 16 Bytes

bd00000000100000D9CEE76B00000000

Then we generate e(cmd + crc + padding) with session key and IV 0 to gain the next iv for decrypting the resposne:

77E24803B5401C61F657607923E5A318

Now we decrypt the secret with session Key and IV:=e(cmd + crc32) and are getting:

D1E9A4726C2A5C3FD5938E714C07524EF1F74BD9000000000000000000000000

There are many Zeros which let me think we are not far away from the answer. So please someone tell us, what is wrong?

We are using this library for Crc32C And here the full code we are using within a test:

        [Theory]
    [InlineData("6a0d0f0d5c8f054b1e5914a42e49728622774c6272e5c34a69ed302251576aaf", "0ba1caf83a26a72170149b7504895f34", "bd00000000100000")]
    public void DecryptData_Test(string secretS, string sessionKeyS, string cmdS) 
    {
        var cryptoAlgoFactory = new Func<SymmetricAlgorithm>(() => Aes.Create());
        var keyLength = 16;

        var secret = EncriptionHelper.StringToByte(secretS);
        var sessionKey = EncriptionHelper.StringToByte(sessionKeyS);
        var cmd = EncriptionHelper.StringToByte(cmdS);

        var crytoAlgo = cryptoAlgoFactory();
        crytoAlgo.Mode = CipherMode.CBC;
        crytoAlgo.Padding = PaddingMode.None;

        var encryptor = crytoAlgo.CreateEncryptor(sessionKey, new byte[keyLength]);

        var crc32 = BitConverter.GetBytes(Crc32C.Crc32CAlgorithm.Compute(cmd));

        var padding = 0;
        if ((cmd.Length + crc32.Length) % keyLength != 0)
            padding = keyLength - ((cmd.Length + crc32.Length) % keyLength);

        var result = new byte[cmd.Length + crc32.Length + padding];

        Array.Copy(cmd, result, cmd.Length);
        Array.Copy(crc32, 0, result, cmd.Length, crc32.Length);

        var iv = encryptor.TransformFinalBlock(result, 0, result.Length);

        crytoAlgo = cryptoAlgoFactory();
        crytoAlgo.Mode = CipherMode.CBC;
        crytoAlgo.Padding = PaddingMode.None;

        var decryptor = crytoAlgo.CreateDecryptor(sessionKey, iv);

        var plain = decryptor.TransformFinalBlock(secret, 0, secret.Length);

        Assert.NotNull(plain);
    }

Solution

  • We´ve found out, that we have to encrypt the command with CMACing and without CRC32C.

    Therefore the following solution:

    SessionKey: 0ba1caf83a26a72170149b7504895f34
    ReadCommand: bd00000000100000
    Secret: 6a0d0f0d5c8f054b1e5914a42e49728622774c6272e5c34a69ed302251576aaf
    

    First Encrypt the cmd with CMACing to get the following IV for further decrypting (Note to use the SessionKey):

    A70BEC41E95A706F11F7DA3D59F2F256
    

    Then decrypt the secret in CBC Mode with IV cmac(cmd) to get the result:

    01000030303030313233343536100300F1F74BD9000000000000000000000000
    

    Within the CMACing there is still something wrong so we used an NuGet Packege which worked fine.