libnfc 1.3.9
|
00001 /*- 00002 * Public platform independent Near Field Communication (NFC) library 00003 * 00004 * Copyright (C) 2009, Roel Verdult 00005 * 00006 * This program is free software: you can redistribute it and/or modify it 00007 * under the terms of the GNU Lesser General Public License as published by the 00008 * Free Software Foundation, either version 3 of the License, or (at your 00009 * option) any later version. 00010 * 00011 * This program is distributed in the hope that it will be useful, but WITHOUT 00012 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 00013 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 00014 * more details. 00015 * 00016 * You should have received a copy of the GNU Lesser General Public License 00017 * along with this program. If not, see <http://www.gnu.org/licenses/> 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 // Test if we are in the small or big sectors 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 // Test if we are in the small or big sectors 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 // Test if we are in the small or big sectors 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 // Key file authentication. 00113 if (bUseKeyFile) { 00114 // Set the authentication information (uid) 00115 memcpy (mp.mpa.abtUid, nti.nai.abtUid, 4); 00116 00117 // Locate the trailer (with the keys) used for this sector 00118 uiTrailerBlock = get_trailer_block (uiBlock); 00119 00120 // Determin if we should use the a or the b key 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 // Try to authenticate for the current sector 00130 if (nfc_initiator_mifare_cmd (pnd, mc, uiBlock, &mp)) 00131 return true; 00132 } 00133 // Auto authentication. 00134 else { 00135 // Determin if we should use the a or the b key 00136 mc = (bUseKeyA) ? MC_AUTH_A : MC_AUTH_B; 00137 00138 // Set the authentication information (uid) 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 // Read the card from end to begin 00169 for (iBlock = uiBlocks; iBlock >= 0; iBlock--) { 00170 // Authenticate everytime we reach a trailer block 00171 if (is_trailer_block (iBlock)) { 00172 // Skip this the first time, bFailure it means nothing (yet) 00173 if (iBlock != uiBlocks) 00174 print_success_or_failure (bFailure, &uiReadBlocks); 00175 00176 // Show if the readout went well 00177 if (bFailure) { 00178 // When a failure occured we need to redo the anti-collision 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 // Try to authenticate for the current sector 00189 if (!authenticate (iBlock)) { 00190 printf ("!\nError: authentication failed for block 0x%02x\n", iBlock); 00191 return false; 00192 } 00193 // Try to read out the trailer 00194 if (nfc_initiator_mifare_cmd (pnd, MC_READ, iBlock, &mp)) { 00195 // Copy the keys over from our key dump and store the retrieved access bits 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 // Make sure a earlier readout did not fail 00204 if (!bFailure) { 00205 // Try to read out the data block 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 // Write the card from begin to end; 00234 for (uiBlock = 0; uiBlock <= uiBlocks; uiBlock++) { 00235 // Authenticate everytime we reach the first sector of a new block 00236 if (is_first_block (uiBlock)) { 00237 // Skip this the first time, bFailure it means nothing (yet) 00238 if (uiBlock != 0) 00239 print_success_or_failure (bFailure, &uiWriteBlocks); 00240 00241 // Show if the readout went well 00242 if (bFailure) { 00243 // When a failure occured we need to redo the anti-collision 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 // Try to authenticate for the current sector 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 // Copy the keys over from our key dump and store the retrieved access bits 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 // Try to write the trailer 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 // The first block 0x00 is read only, skip this 00273 if (uiBlock == 0) 00274 continue; 00275 00276 // Make sure a earlier write did not fail 00277 if (!bFailure) { 00278 // Try to write the data block 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 // for(uint8_t uiByteIndex=0; uiByteIndex<16; uiByteIndex++) printf("%02x ", abDump[szPayloadIndex+uiByteIndex]); 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 // printf("Successfully opened required files\n"); 00405 00406 // Try to open the NFC reader 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 // Drop the field for a while 00416 if (!nfc_configure (pnd, NDO_ACTIVATE_FIELD, false)) { 00417 nfc_perror (pnd, "nfc_configure"); 00418 exit (EXIT_FAILURE); 00419 } 00420 // Let the reader only try once to find a tag 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 // Enable field so more power consuming cards can power themselves up 00434 if (!nfc_configure (pnd, NDO_ACTIVATE_FIELD, true)) { 00435 nfc_perror (pnd, "nfc_configure"); 00436 exit (EXIT_FAILURE); 00437 } 00438 // Disable ISO14443-4 switching in order to read devices that emulate Mifare Classic with ISO14443-4 compliance. 00439 nfc_configure (pnd, NDO_AUTO_ISO14443_4, false); 00440 00441 printf ("Connected to NFC reader: %s\n", pnd->acName); 00442 00443 // Try to find a MIFARE Classic tag 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 // Test if we are dealing with a MIFARE compatible tag 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 // Get the info from the key dump 00458 b4K = (mtKeys.amb[0].mbm.abtATQA[1] == 0x02); 00459 pbtUID = mtKeys.amb[0].mbm.abtUID; 00460 00461 // Compare if key dump UID is the same as the current tag UID 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 // Get the info from the current tag 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 }