1
votes

I am trying to authenticate w/ an NXP MiFare Ultralight C. My NFC tag reader is an Android phone (Samsung Galaxy Express) but I'm doing all of the crypto on a Windows 7 machine using C# and the functions in the System.Security.Cryptography namespace.

I DO have full datasheets (under NDA) on the Ultralight-C. Understanding them isn't my issue (I don't think) - I'm just not getting what I expect from my crypto functions. I will need to be a little circumspect on details about the tag, but I don't think the tag is my issue.

Basically what's happening is I initiate an authentication and I get the expected data from the tag. I do [the stuff] on my side and send a response to the tag using Nfca.Transceive() on the Android. That function immediately throws a "transceive failed" exception, which I take to mean the tag is telling me to take a flying leap. Other attempts to use Transceive() are successful (writes, initiating authentication, etc).

That the tag is kicking it back is no surprise because my code isn't producing what I expect when using the only test vectors I could find by Googling.

Because of the NDA probably best to just stick with 3DES side of things since that's no secret... These are from the test data I found online:

Given ek(Data) is 63FC19906A77D13F and k is 49454D4B41455242214E4143554F5946 dk(Data) should be c00c24ed61ea0f3e

This isn't what I'm getting from my code, which looks basically like this:

byte[] key = new byte[16] 
                {                 
                    0x49, 0x45, 0x4D, 0x4B, 
                    0x41, 0x45, 0x52, 0x42, 
                    0x21, 0x4E, 0x41, 0x43, 
                    0x55, 0x4F, 0x59, 0x46
                };

byte[] initVector = new byte[8];

byte[] encrypted =  new byte[8] 
                {
                    0x63, 0xFC, 0x19, 0x90,
                    0x6A, 0x77, 0xD1, 0x3F
                }

byte[] result = DecryptSingleBlock(encrypted, key, ref initVector);

At this point I expect result to contain the result from the test data: c00c24ed61ea0f3e but it doesn't. Its value is: 5bdd317111226152

My decryption function:

public byte[] DecryptSingleBlock(byte[] input, byte[] key, ref byte[] initVector)
{


    using (var des = new TripleDESCryptoServiceProvider  
                         {
                             IV = initVector,   // all zeros this time
                             BlockSize = 64,
                             KeySize = 128,
                             Mode = CipherMode.CBC,
                             Padding = PaddingMode.None,
                             Key = key,
                         })
        {
            byte[] output = des.CreateDecryptor().TransformFinalBlock(input, 0, 8);

            return output;
        }
    }

I have:

  • Reversed the order of the bytes in the encrypted data;
  • Swapped the first 8 bytes of the key with the second 8 bytes;
  • Toyed with the FeedbackSize (though I am very unclear on what NXP expects or if this is even applicable to CBC mode (which itself shouldn't apply to this single block decryption);
  • Used CreateEncryptor instead of CreateDecryptor.
  • Tried to make sense of the LibFreeFare code, though it covers a lot more - I'm just trying to get past this step.

I'm at a loss. Does anyone have any idea what I need to do to the function above to make it return 'c00c24ed61ea0f3e' for the given input and key? I don't know if I've overlooked something NXP is doing or if I'm falling victim to some special MS-tastic way 3DES is implemented in .NET. My gut tells me there is some endian-ness issue somewhere but I don't know where or what to do about it other than what I've tried.

Honestly, I'd be happy to get some known-good test vectors (A, B, K, ek(xx+xx)) so I can get my code working before I even bring a tag into the mix. I have asked NXP for this but they are 8 hours ahead so no response yet and anyway, I have no idea how long their normal response is and whether they'll be able to help at all - I guess that depends on whether it gets routed to the right people.

In the alternative, if someone knows of a step-by-step authentication application note I can ask for through the DocStore, that would be helpful too. Once again, I'm under the NDA for both Ultralight-C and DESFire so I'm sure they'll provide it if I know what to ask for.

Thanks!

1

1 Answers

3
votes

Okay, I figured this out with the help of some reading about issues someone had while trying to re-create openSSL.NET functionality with pure managed code.

When creating the TripleDESCryptoServiceProvider do NOT include the key or IV in the class initializer as I did above. Setting the key or IV before the mode, block size, key size, etc. have been initialized will cause the key, the IV or both to get mangled or truncated or something, resulting in the wonky behavior I was seeing. I have not experimented further to see what got mangled and how.

Glad it's fixed but it cost me about 8 hours...

Here is the way to do it. I have omitted the other code for clarity.

var des = new TripleDESCryptoServiceProvider  
{
    BlockSize = 64,
    KeySize = 128,
    Mode = CipherMode.CBC,
    Padding = PaddingMode.None,
};

// the important bit is that these properties are 
// being set last
des.IV = initVector;
des.Key = key;