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