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