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!