RFID Door Unlocker

Reading and Writing to MiFare (1K/Classic?) PICC

by Cory on April 13, 2019 10:33 PM (Edited April 13, 2019 10:48 PM)

So that code I have up until now is very basic and just checks if a provided PICC (rfid card) is able to be read. This is easily handled by the mfrc522 library with two calls to "PICC_IsNewCardPresent()" and "PIC_ReadCardSerial()" or "PICC_DumpToSerial()".

"IsNewCardPresent" or "WakeupA" or "PresentA" need to be called before reading/writing the PICC because those methods do some internal things to prep the card.

Behind the scenes, the read methods above also do some complicated things with checking compatibility of card version, dealing with collisions (when multiple cards are presented), authenticating with the "KeyA" stored in the card data, and then calculating byte offsets and stuff (which depends on what version the card is) and then reading the data.

When I do an internet search to figure out what the protocol to write data is, there are a lot of websites out there with the same vague instructions. I could also read the datasheets, but I don't have the patience to do it if I don't have to... It's weird, you know? Like I'm not even sure which datasheet I need to read and even then, the protocol descriptions are filled with weird ambiguous technical terms that I feel like mean something specific but I couldn't find where they were defined. Maybe I'm just stupid.

EDIT: uhhh, so both Miguel Balboa's git repo and the link below have numerous references to the MiFare datasheet and specific subsections for different topics like memory layout and authentication protocols. Guess I'm stupid then.

But then I found a good explanation of what it takes to read/write to a card. It seems short and simple now that I know how it works, but I just needed a plain English description of what to do:

https://www.mifare.net/support/forum/topic/keya-and-keyb-and-how-to-protect-the-contacless-card-from-cloning/

All these things I'm reading talk about the mifare protocol and using "KeyA" and "KeyB". You can configure the access bits of each sector to require keyA or keyB when doing reads or writes. The access bits are stored with the card data.

If you use sector 1 (blocks 4 … 7) then 3 blocks (4, 5 and 6) can be used for store you data. The last block is the so called sector trailerand contains the keys and the access condition bits. The access condition bits can be set e.g. to “read = free”, “write = Key A” or “read = Key B” and “write = Key A” etc. The level of protection depends on your use case.

Jackpot. Ok, so the card data is laid out like this:

Card UID: D6 00 56 D3
Card SAK: 08
PICC type: MIFARE 1KB
Sector Block 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 AccessBits
15 63 00 00 00 00 00 00 FF 07 80 69 FF FF FF FF FF FF [ 0 0 1 ]
62 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 [ 0 0 0 ]
61 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 [ 0 0 0 ]
60 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 [ 0 0 0 ]
14 59 00 00 00 00 00 00 FF 07 80 69 FF FF FF FF FF FF [ 0 0 1 ]
58 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 [ 0 0 0 ]
57 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 [ 0 0 0 ]
56 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 [ 0 0 0 ]
...

2 11 00 00 00 00 00 00 FF 07 80 69 FF FF FF FF FF FF [ 0 0 1 ]
10 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 [ 0 0 0 ]
9 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 [ 0 0 0 ]
8 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 [ 0 0 0 ]
1 7 00 00 00 00 00 00 FF 07 80 69 FF FF FF FF FF FF [ 0 0 1 ]
6 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 [ 0 0 0 ]
5 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 [ 0 0 0 ]
4 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 [ 0 0 0 ]
0 3 00 00 00 00 00 00 FF 07 80 69 FF FF FF FF FF FF [ 0 0 1 ]
2 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 [ 0 0 0 ]
1 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 [ 0 0 0 ]
0 D6 00 56 D3 53 08 04 00 62 63 64 65 66 67 68 69 [ 0 0 0 ]

There are 16 sectors (identfied by the left most number) and each sector is 4 blocks. For instance, sector 0 is special and can't/shouldn't be written after it comes from the factory. Sector 0 covers blocks 0 to 3. Sector 1 is the first recommended user data storage area and covers blocks 4 to 7. From the quote above, you can use blocks 4 to 6 for whatever you want.

 1  7 00 00 00 00 00 00 FF 07 80 69 FF FF FF FF FF FF [ 0 0 1 ] 
6 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 [ 0 0 0 ]
5 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 [ 0 0 0 ]
4 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 [ 0 0 0 ]

Here's sector 1 pasted here by itself. Note that this is a dump of my own card. Blocks 4 and 6 are for user data and since the card is brand new, it's just all zeros. As you can see block 7 actually has data in it. These bits contain the keys and other configuration bits. Apparently, the usual default KeyA value is 0xFF_FFFF, which you can see in the LSB position in block 7. Also you can see the access bits for block 7, which are 0x1.

It looks like this "KeyA" and "KeyB" business is the ancient proprietary mifare security protocols they put in place. From what I can glean, this is "not hacker proof", and this is what you hear about when people talk about cloning RFID cards because they can just sniff a card, dump the data and then read the right blocks.

What you're apparently supposed to do is store a RSA public key or something in your user data and then use that to authenticate in an extra step before you do anything important. I thought I had an article that would tell me how to do this RSA key stuff around here somewhere but I lost it I guess. Time to go looking...

 



This Thought is part of RFID Door Unlocker

You know how nice cars like Mercedes or Tesla automatically unlock when you get close to them with the key fob? Let's do that but for my apartment front door.

back to the

top