00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00025 #ifdef HAVE_CONFIG_H
00026 # include "config.h"
00027 #endif // HAVE_CONFIG_H
00028
00029 #include <stdio.h>
00030 #include <stdlib.h>
00031 #include <stdint.h>
00032 #include <stddef.h>
00033 #include <stdbool.h>
00034
00035 #include <string.h>
00036 #include <ctype.h>
00037
00038 #include <nfc/nfc.h>
00039
00040 #include "mifare.h"
00041 #include "nfc-utils.h"
00042
00043 static nfc_device_t *pnd;
00044 static nfc_target_info_t nti;
00045 static mifare_param mp;
00046 static mifare_classic_tag mtKeys;
00047 static mifare_classic_tag mtDump;
00048 static bool bUseKeyA;
00049 static bool bUseKeyFile;
00050 static uint8_t uiBlocks;
00051 static byte_t keys[] = {
00052 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
00053 0xd3, 0xf7, 0xd3, 0xf7, 0xd3, 0xf7,
00054 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5,
00055 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5,
00056 0x4d, 0x3a, 0x99, 0xc3, 0x51, 0xdd,
00057 0x1a, 0x98, 0x2c, 0x7e, 0x45, 0x9a,
00058 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff,
00059 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
00060 };
00061
00062 static size_t num_keys = sizeof (keys) / 6;
00063
00064 static void
00065 print_success_or_failure (bool bFailure, uint32_t * uiBlockCounter)
00066 {
00067 printf ("%c", (bFailure) ? 'x' : '.');
00068 if (uiBlockCounter && !bFailure)
00069 *uiBlockCounter += (*uiBlockCounter < 128) ? 4 : 16;
00070 }
00071
00072 static bool
00073 is_first_block (uint32_t uiBlock)
00074 {
00075
00076 if (uiBlock < 128)
00077 return ((uiBlock) % 4 == 0);
00078 else
00079 return ((uiBlock) % 16 == 0);
00080 }
00081
00082 static bool
00083 is_trailer_block (uint32_t uiBlock)
00084 {
00085
00086 if (uiBlock < 128)
00087 return ((uiBlock + 1) % 4 == 0);
00088 else
00089 return ((uiBlock + 1) % 16 == 0);
00090 }
00091
00092 static uint32_t
00093 get_trailer_block (uint32_t uiFirstBlock)
00094 {
00095
00096 uint32_t trailer_block = 0;
00097 if (uiFirstBlock < 128) {
00098 trailer_block = uiFirstBlock + (3 - (uiFirstBlock % 4));
00099 } else {
00100 trailer_block = uiFirstBlock + (15 - (uiFirstBlock % 16));
00101 }
00102 return trailer_block;
00103 }
00104
00105 static bool
00106 authenticate (uint32_t uiBlock)
00107 {
00108 mifare_cmd mc;
00109 uint32_t uiTrailerBlock;
00110 size_t key_index;
00111
00112
00113 if (bUseKeyFile) {
00114
00115 memcpy (mp.mpa.abtUid, nti.nai.abtUid, 4);
00116
00117
00118 uiTrailerBlock = get_trailer_block (uiBlock);
00119
00120
00121 if (bUseKeyA) {
00122 mc = MC_AUTH_A;
00123 memcpy (mp.mpa.abtKey, mtKeys.amb[uiTrailerBlock].mbt.abtKeyA, 6);
00124 } else {
00125 mc = MC_AUTH_B;
00126 memcpy (mp.mpa.abtKey, mtKeys.amb[uiTrailerBlock].mbt.abtKeyB, 6);
00127 }
00128
00129
00130 if (nfc_initiator_mifare_cmd (pnd, mc, uiBlock, &mp))
00131 return true;
00132 }
00133
00134 else {
00135
00136 mc = (bUseKeyA) ? MC_AUTH_A : MC_AUTH_B;
00137
00138
00139 memcpy (mp.mpa.abtUid, nti.nai.abtUid, 4);
00140
00141 for (key_index = 0; key_index < num_keys; key_index++) {
00142 memcpy (mp.mpa.abtKey, keys + (key_index * 6), 6);
00143 if (nfc_initiator_mifare_cmd (pnd, mc, uiBlock, &mp)) {
00144 if (bUseKeyA)
00145 memcpy (mtKeys.amb[uiBlock].mbt.abtKeyA, &mp.mpa.abtKey, 6);
00146 else
00147 memcpy (mtKeys.amb[uiBlock].mbt.abtKeyB, &mp.mpa.abtKey, 6);
00148
00149 return true;
00150 }
00151
00152 nfc_initiator_select_passive_target (pnd, NM_ISO14443A_106, mp.mpa.abtUid, 4, NULL);
00153 }
00154 }
00155
00156 return false;
00157 }
00158
00159 static bool
00160 read_card (void)
00161 {
00162 int32_t iBlock;
00163 bool bFailure = false;
00164 uint32_t uiReadBlocks = 0;
00165
00166 printf ("Reading out %d blocks |", uiBlocks + 1);
00167
00168
00169 for (iBlock = uiBlocks; iBlock >= 0; iBlock--) {
00170
00171 if (is_trailer_block (iBlock)) {
00172
00173 if (iBlock != uiBlocks)
00174 print_success_or_failure (bFailure, &uiReadBlocks);
00175
00176
00177 if (bFailure) {
00178
00179 if (!nfc_initiator_select_passive_target (pnd, NM_ISO14443A_106, NULL, 0, &nti)) {
00180 printf ("!\nError: tag was removed\n");
00181 return false;
00182 }
00183 bFailure = false;
00184 }
00185
00186 fflush (stdout);
00187
00188
00189 if (!authenticate (iBlock)) {
00190 printf ("!\nError: authentication failed for block 0x%02x\n", iBlock);
00191 return false;
00192 }
00193
00194 if (nfc_initiator_mifare_cmd (pnd, MC_READ, iBlock, &mp)) {
00195
00196 memcpy (mtDump.amb[iBlock].mbt.abtKeyA, mtKeys.amb[iBlock].mbt.abtKeyA, 6);
00197 memcpy (mtDump.amb[iBlock].mbt.abtAccessBits, mp.mpd.abtData + 6, 4);
00198 memcpy (mtDump.amb[iBlock].mbt.abtKeyB, mtKeys.amb[iBlock].mbt.abtKeyB, 6);
00199 } else {
00200 printf ("!\nError: unable to read trailer block 0x%02x\n", iBlock);
00201 }
00202 } else {
00203
00204 if (!bFailure) {
00205
00206 if (nfc_initiator_mifare_cmd (pnd, MC_READ, iBlock, &mp)) {
00207 memcpy (mtDump.amb[iBlock].mbd.abtData, mp.mpd.abtData, 16);
00208 } else {
00209 bFailure = true;
00210 printf ("!\nError: unable to read block 0x%02x\n", iBlock);
00211 return false;
00212 }
00213 }
00214 }
00215 }
00216 print_success_or_failure (bFailure, &uiReadBlocks);
00217 printf ("|\n");
00218 printf ("Done, %d of %d blocks read.\n", uiReadBlocks, uiBlocks + 1);
00219 fflush (stdout);
00220
00221 return true;
00222 }
00223
00224 static bool
00225 write_card (void)
00226 {
00227 uint32_t uiBlock;
00228 bool bFailure = false;
00229 uint32_t uiWriteBlocks = 0;
00230
00231 printf ("Writing %d blocks |", uiBlocks + 1);
00232
00233
00234 for (uiBlock = 0; uiBlock <= uiBlocks; uiBlock++) {
00235
00236 if (is_first_block (uiBlock)) {
00237
00238 if (uiBlock != 0)
00239 print_success_or_failure (bFailure, &uiWriteBlocks);
00240
00241
00242 if (bFailure) {
00243
00244 if (!nfc_initiator_select_passive_target (pnd, NM_ISO14443A_106, NULL, 0, &nti)) {
00245 printf ("!\nError: tag was removed\n");
00246 return false;
00247 }
00248 bFailure = false;
00249 }
00250
00251 fflush (stdout);
00252
00253
00254 if (!authenticate (uiBlock)) {
00255 printf ("!\nError: authentication failed for block %02x\n", uiBlock);
00256 return false;
00257 }
00258 }
00259
00260 if (is_trailer_block (uiBlock)) {
00261
00262 memcpy (mp.mpd.abtData, mtDump.amb[uiBlock].mbt.abtKeyA, 6);
00263 memcpy (mp.mpd.abtData + 6, mtDump.amb[uiBlock].mbt.abtAccessBits, 4);
00264 memcpy (mp.mpd.abtData + 10, mtDump.amb[uiBlock].mbt.abtKeyB, 6);
00265
00266
00267 if (nfc_initiator_mifare_cmd (pnd, MC_WRITE, uiBlock, &mp) == false) {
00268 printf ("failed to write trailer block %d \n", uiBlock);
00269 bFailure = true;
00270 }
00271 } else {
00272
00273 if (uiBlock == 0)
00274 continue;
00275
00276
00277 if (!bFailure) {
00278
00279 memcpy (mp.mpd.abtData, mtDump.amb[uiBlock].mbd.abtData, 16);
00280 if (!nfc_initiator_mifare_cmd (pnd, MC_WRITE, uiBlock, &mp))
00281 bFailure = true;
00282 }
00283 }
00284 }
00285 print_success_or_failure (bFailure, &uiWriteBlocks);
00286 printf ("|\n");
00287 printf ("Done, %d of %d blocks written.\n", uiWriteBlocks, uiBlocks + 1);
00288 fflush (stdout);
00289
00290 return true;
00291 }
00292
00293 static void
00294 mifare_classic_extract_payload (const char *abDump, char *pbPayload)
00295 {
00296 uint8_t uiSectorIndex;
00297 uint8_t uiBlockIndex;
00298 size_t szDumpOffset;
00299 size_t szPayloadIndex = 0;
00300
00301 for (uiSectorIndex = 1; uiSectorIndex < 16; uiSectorIndex++) {
00302 for (uiBlockIndex = 0; uiBlockIndex < 3; uiBlockIndex++) {
00303 szDumpOffset = uiSectorIndex * 16 * 4 + uiBlockIndex * 16;
00304
00305 memcpy (pbPayload + szPayloadIndex, abDump + szDumpOffset, 16);
00306 szPayloadIndex += 16;
00307 }
00308 }
00309 }
00310
00311 typedef enum {
00312 ACTION_READ,
00313 ACTION_WRITE,
00314 ACTION_EXTRACT,
00315 ACTION_USAGE
00316 } action_t;
00317
00318 static void
00319 print_usage (const char *pcProgramName)
00320 {
00321 printf ("Usage: ");
00322 printf ("%s r|w a|b <dump.mfd> [<keys.mfd>]\n", pcProgramName);
00323 printf (" r|w - Perform read from (r) or write to (w) card\n");
00324 printf (" a|b - Use A or B keys for action\n");
00325 printf (" <dump.mfd> - MiFare Dump (MFD) used to write (card to MFD) or (MFD to card)\n");
00326 printf (" <keys.mfd> - MiFare Dump (MFD) that contain the keys (optional)\n");
00327 printf ("Or: ");
00328 printf ("%s x <dump.mfd> <payload.bin>\n", pcProgramName);
00329 printf (" x - Extract payload (data blocks) from MFD\n");
00330 printf (" <dump.mfd> - MiFare Dump (MFD) that contains wanted payload\n");
00331 printf (" <payload.bin> - Binary file where payload will be extracted\n");
00332 }
00333
00334 int
00335 main (int argc, const char *argv[])
00336 {
00337 bool b4K;
00338 action_t atAction = ACTION_USAGE;
00339 byte_t *pbtUID;
00340 FILE *pfKeys = NULL;
00341 FILE *pfDump = NULL;
00342 const char *command = argv[1];
00343
00344 if (argc < 2) {
00345 print_usage (argv[0]);
00346 exit (EXIT_FAILURE);
00347 }
00348
00349 if (strcmp (command, "r") == 0) {
00350 atAction = ACTION_READ;
00351 bUseKeyA = tolower ((int) ((unsigned char) *(argv[2]))) == 'a';
00352 bUseKeyFile = (argc > 4);
00353 } else if (strcmp (command, "w") == 0) {
00354 atAction = ACTION_WRITE;
00355 bUseKeyA = tolower ((int) ((unsigned char) *(argv[2]))) == 'a';
00356 bUseKeyFile = (argc > 4);
00357 } else if (strcmp (command, "x") == 0) {
00358 atAction = ACTION_EXTRACT;
00359 }
00360
00361 switch (atAction) {
00362 case ACTION_USAGE:
00363 print_usage (argv[0]);
00364 exit (EXIT_FAILURE);
00365 break;
00366 case ACTION_READ:
00367 case ACTION_WRITE:
00368 if (argc < 4) {
00369 print_usage (argv[0]);
00370 exit (EXIT_FAILURE);
00371 }
00372
00373 if (bUseKeyFile) {
00374 pfKeys = fopen (argv[4], "rb");
00375 if (pfKeys == NULL) {
00376 printf ("Could not open keys file: %s\n", argv[4]);
00377 exit (EXIT_FAILURE);
00378 }
00379 if (fread (&mtKeys, 1, sizeof (mtKeys), pfKeys) != sizeof (mtKeys)) {
00380 printf ("Could not read keys file: %s\n", argv[4]);
00381 fclose (pfKeys);
00382 exit (EXIT_FAILURE);
00383 }
00384 fclose (pfKeys);
00385 }
00386
00387 if (atAction == ACTION_READ) {
00388 memset (&mtDump, 0x00, sizeof (mtDump));
00389 } else {
00390 pfDump = fopen (argv[3], "rb");
00391
00392 if (pfDump == NULL) {
00393 printf ("Could not open dump file: %s\n", argv[3]);
00394 exit (EXIT_FAILURE);
00395 }
00396
00397 if (fread (&mtDump, 1, sizeof (mtDump), pfDump) != sizeof (mtDump)) {
00398 printf ("Could not read dump file: %s\n", argv[3]);
00399 fclose (pfDump);
00400 exit (EXIT_FAILURE);
00401 }
00402 fclose (pfDump);
00403 }
00404
00405
00406
00407 pnd = nfc_connect (NULL);
00408 if (pnd == NULL) {
00409 printf ("Error connecting NFC reader\n");
00410 exit (EXIT_FAILURE);
00411 }
00412
00413 nfc_initiator_init (pnd);
00414
00415
00416 if (!nfc_configure (pnd, NDO_ACTIVATE_FIELD, false)) {
00417 nfc_perror (pnd, "nfc_configure");
00418 exit (EXIT_FAILURE);
00419 }
00420
00421 if (!nfc_configure (pnd, NDO_INFINITE_SELECT, false)) {
00422 nfc_perror (pnd, "nfc_configure");
00423 exit (EXIT_FAILURE);
00424 }
00425 if (!nfc_configure (pnd, NDO_HANDLE_CRC, true)) {
00426 nfc_perror (pnd, "nfc_configure");
00427 exit (EXIT_FAILURE);
00428 }
00429 if (!nfc_configure (pnd, NDO_HANDLE_PARITY, true)) {
00430 nfc_perror (pnd, "nfc_configure");
00431 exit (EXIT_FAILURE);
00432 }
00433
00434 if (!nfc_configure (pnd, NDO_ACTIVATE_FIELD, true)) {
00435 nfc_perror (pnd, "nfc_configure");
00436 exit (EXIT_FAILURE);
00437 }
00438
00439 nfc_configure (pnd, NDO_AUTO_ISO14443_4, false);
00440
00441 printf ("Connected to NFC reader: %s\n", pnd->acName);
00442
00443
00444 if (!nfc_initiator_select_passive_target (pnd, NM_ISO14443A_106, NULL, 0, &nti)) {
00445 printf ("Error: no tag was found\n");
00446 nfc_disconnect (pnd);
00447 exit (EXIT_FAILURE);
00448 }
00449
00450 if ((nti.nai.btSak & 0x08) == 0) {
00451 printf ("Error: tag is not a MIFARE Classic card\n");
00452 nfc_disconnect (pnd);
00453 exit (EXIT_FAILURE);
00454 }
00455
00456 if (bUseKeyFile) {
00457
00458 b4K = (mtKeys.amb[0].mbm.abtATQA[1] == 0x02);
00459 pbtUID = mtKeys.amb[0].mbm.abtUID;
00460
00461
00462 if (memcmp (nti.nai.abtUid, pbtUID, 4) != 0) {
00463 printf ("Expected MIFARE Classic %ck card with UID: %02x%02x%02x%02x\n", b4K ? '4' : '1', pbtUID[3], pbtUID[2],
00464 pbtUID[1], pbtUID[0]);
00465 }
00466 }
00467
00468 pbtUID = nti.nai.abtUid;
00469 b4K = (nti.nai.abtAtqa[1] == 0x02);
00470 printf ("Found MIFARE Classic %ck card with UID: %02x%02x%02x%02x\n", b4K ? '4' : '1', pbtUID[3], pbtUID[2],
00471 pbtUID[1], pbtUID[0]);
00472
00473 uiBlocks = (b4K) ? 0xff : 0x3f;
00474
00475 if (atAction == ACTION_READ) {
00476 if (read_card ()) {
00477 printf ("Writing data to file: %s ...", argv[3]);
00478 fflush (stdout);
00479 pfDump = fopen (argv[3], "wb");
00480 if (fwrite (&mtDump, 1, sizeof (mtDump), pfDump) != sizeof (mtDump)) {
00481 printf ("\nCould not write to file: %s\n", argv[3]);
00482 exit (EXIT_FAILURE);
00483 }
00484 printf ("Done.\n");
00485 fclose (pfDump);
00486 }
00487 } else {
00488 write_card ();
00489 }
00490
00491 nfc_disconnect (pnd);
00492 break;
00493
00494 case ACTION_EXTRACT:{
00495 const char *pcDump = argv[2];
00496 const char *pcPayload = argv[3];
00497
00498 FILE *pfDump = NULL;
00499 FILE *pfPayload = NULL;
00500
00501 char abDump[4096];
00502 char abPayload[4096];
00503
00504 pfDump = fopen (pcDump, "rb");
00505
00506 if (pfDump == NULL) {
00507 printf ("Could not open dump file: %s\n", pcDump);
00508 exit (EXIT_FAILURE);
00509 }
00510
00511 if (fread (abDump, 1, sizeof (abDump), pfDump) != sizeof (abDump)) {
00512 printf ("Could not read dump file: %s\n", pcDump);
00513 fclose (pfDump);
00514 exit (EXIT_FAILURE);
00515 }
00516 fclose (pfDump);
00517
00518 mifare_classic_extract_payload (abDump, abPayload);
00519
00520 printf ("Writing data to file: %s\n", pcPayload);
00521 pfPayload = fopen (pcPayload, "wb");
00522 if (fwrite (abPayload, 1, sizeof (abPayload), pfPayload) != sizeof (abPayload)) {
00523 printf ("Could not write to file: %s\n", pcPayload);
00524 exit (EXIT_FAILURE);
00525 }
00526 fclose (pfPayload);
00527 printf ("Done, all bytes have been extracted!\n");
00528 }
00529 };
00530
00531 exit (EXIT_SUCCESS);
00532 }