MFOC improved

When I started using MFOC, from a the description (in Dutch) at ov-chipkaart.org, I immediately ran into the problem described here. A bit strange seemed, that reading the card sector after sector with 10 different predefined keys did not crash the reader, while immediately after starting to try to calculate new keys, the reader would crash.

Ov-chipkaart.nl only mentioned that MFOC “is not very stable” and suggested decreasing the “distance” (-T option in MFOC).

I decided to dig further. Strangely, adding various “sleep” calls did seem to improve the stability of the reader – but only for a very short time. Also, the source code was full of reconfiguration calls, it would even turn the “field” (meaning the wireless signal meant to communicate with the card) off, reconfigure the reader, turn the field on again, then try to re-establish communication with the card again:

void mf_configure(nfc_device_t* pdi) {
 nfc_initiator_init(pdi);
 // Drop the field for a while, so can be reset
 nfc_configure(pdi,NDO_ACTIVATE_FIELD,false);
 // Let the reader only try once to find a tag
 nfc_configure(pdi,NDO_INFINITE_SELECT,false);
 // Configure the CRC and Parity settings
 nfc_configure(pdi,NDO_HANDLE_CRC,true);
 nfc_configure(pdi,NDO_HANDLE_PARITY,true);
 // Enable the field so more power consuming cards can power themselves up
 nfc_configure(pdi,NDO_ACTIVATE_FIELD,true);
}

followed by a call to

void mf_anticollision(mftag t, mfreader r) {
 const nfc_modulation_t nm = {
 .nmt = NMT_ISO14443A,
 .nbr = NBR_106,
 };
 if (!nfc_initiator_select_passive_target(r.pdi, nm, NULL, 0, &t.nt)) {
 fprintf(stderr, "\n\n!Error: tag has been removed\n");
 exit(1);
 }
}

This all seemed a bit unnecessary, so I started weeding out calls to mf_configure() and mf_anticollision(). That did not seem to harm MFOC reading the signal – although stability did, at first, not improve.

Then I noticed a call to mf_enhanced_auth that was followed by “fprint(); fflush(); mf_configure(); mf_anticollision()”, and afterwards, the reader would crash; but if I turned things around (mf_authenticate; mf_configure; mf_anticollision; fprint), it would be much more stable.

// Try to authenticate to exploit sector and determine distances (filling denonce.distances)
mf_enhanced_auth(e_sector, 0, t, r, &d, pk, 'd', dumpKeysA); // AUTH + Get Distances mode
printf("Sector: %d, type %c, probe %d, distance %d ", j, (dumpKeysA ? 'A' : 'B'), k, d.median);
// Configure device to the previous state
mf_configure(r.pdi);
mf_anticollision(t, r);

Aha. A timing issue.

Then I figured: if these calls to mf_configure are unnecessary (apart from the ones that enable key calculation), I might as well put them inside mf_enhanced_auth:

crypto1_destroy(pcs);
// Let reader handle parity & CRC again.
for (i=0;!nfc_configure(r.pdi, NDO_HANDLE_PARITY, true) && i < 10; i++)  {
  zsleep (100);
  printf("Parity");
}
if (i==10) { fprintf(stderr,"10 config errors, aborting now.\n"); exit (EXIT_FAILURE); }
for (i=0;!nfc_configure(r.pdi, NDO_HANDLE_CRC, true) && i < 10; i++) {
  zsleep (100);
  printf("CRC");
}
if (i==10) { fprintf(stderr,"10 config errors, aborting now.\n"); exit (EXIT_FAILURE); }
return 0;

This greatly improved stability: the reader wouldn’t crash anymore after the “d” part of mf_authenticate. However, it would after the “m” part. Now what?

Ironically, during a train ride, it struck me. The “m” part of mf_authenticate is heavily influenced by the “T” option: a higher value for “T” will increase the time until MFOC reconfigures the reader to it’s default settings (CRC and parity calculation done by the reader):

if (!nfc_initiator_transceive_bits(r.pdi, AuthEnc, 32, AuthEncPar,Rx, &RxLen, RxPar)) {
 fprintf(stdout, "Error requesting encrypted tag-nonce\n");
 exit(1);
 }
// followed by the calculation done by the computer:
for (m = d->median-d->tolerance; m <= d->median+d->tolerance; m +=2) {
// there is no more communication with the reader here!
}

The suggestion of having a low value for “tolerance” would help getting the reader being reconfigured in time, which would help the reader not crash. This also means that the faster your processor, the higher your “T” value can be. My MFOC tuning was done on a rather low-end machine with an Intel Atom processor, which is probably why even 1 or 2 for “T” would not finish calculations.

Anyway, here is the revised mfoc.c. It’s still a bit rough; you’ll need to tune mfoc.h a bit (remove mf_configure), but hey, your card reader will not crash anymore!

It’s not perfect. MFOC will, sometimes, still crash. Reconfiguring the parity/CRC at the end of mf_enhanced_auth will sometimes still stop the calculations. But so far, I haven’t seen my reader stop communicating anymore. Those of you who don’t have a crashing ACR122U are most welcome to test this source, too, to see if it doesn’t pose new problems. Please let me know your findings.

6 Replies to “MFOC improved”

  1. Hey Valentijn,

    I’m building a Mac OSX gui for mfoc. I run into the problem that the reader seems to crash after a little while. I implemented the changes you made, but it still seems to crash. Any insights as to what might be going wrong? If necessary I can supply you with my code.

    Whacko

  2. Hi valentijn,

    Thanks for your mfoc.c update. I noticed that you use a keys.h to define your challenge keys in i suppose. The line:

    #include “keys.h”

    due to this line the make will fail.

    After restoring the array with default Mifare Classic keys (uncommented what you commented and commented the keys.h include) as in the original mfoc.c make can continue.

  3. @O: Yes, I did. Generally though, the feeling is that the ACR122U reader has a firmware bug. The other thing is, that (parts of the) mf_configure() call are part of the protocol, especially when you try to read multiple cards. All in all, you should see my patch as a “quick hack” that, for unknown reasons, works around the bug in the ACR122U. And since no one knows what this bug is, adding half-baked code may not be the best thing to do. “It works for me” though 🙂

Leave a Reply

Your email address will not be published. Required fields are marked *