libnfc 1.4.2
|
00001 /*- 00002 * Public platform independent Near Field Communication (NFC) library examples 00003 * 00004 * Copyright (C) 2009, Roel Verdult 00005 * Copyright (C) 2010, Romuald Conty, Romain Tartière 00006 * 00007 * Redistribution and use in source and binary forms, with or without 00008 * modification, are permitted provided that the following conditions are met: 00009 * 1) Redistributions of source code must retain the above copyright notice, 00010 * this list of conditions and the following disclaimer. 00011 * 2 )Redistributions in binary form must reproduce the above copyright 00012 * notice, this list of conditions and the following disclaimer in the 00013 * documentation and/or other materials provided with the distribution. 00014 * 00015 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 00016 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 00017 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 00018 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 00019 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 00020 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 00021 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 00022 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 00023 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 00024 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 00025 * POSSIBILITY OF SUCH DAMAGE. 00026 * 00027 * Note that this license only applies on the examples, NFC library itself is under LGPL 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 // Test if we are in the small or big sectors 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 // Test if we are in the small or big sectors 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 // Test if we are in the small or big sectors 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 // Key file authentication. 00130 if (bUseKeyFile) { 00131 // Set the authentication information (uid) 00132 memcpy (mp.mpa.abtUid, nt.nti.nai.abtUid, 4); 00133 00134 // Locate the trailer (with the keys) used for this sector 00135 uiTrailerBlock = get_trailer_block (uiBlock); 00136 00137 // Determin if we should use the a or the b key 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 // Try to authenticate for the current sector 00147 if (nfc_initiator_mifare_cmd (pnd, mc, uiBlock, &mp)) 00148 return true; 00149 } 00150 // Auto authentication. 00151 else { 00152 // Determin if we should use the a or the b key 00153 mc = (bUseKeyA) ? MC_AUTH_A : MC_AUTH_B; 00154 00155 // Set the authentication information (uid) 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 // Read the card from end to begin 00186 for (iBlock = uiBlocks; iBlock >= 0; iBlock--) { 00187 // Authenticate everytime we reach a trailer block 00188 if (is_trailer_block (iBlock)) { 00189 // Skip this the first time, bFailure it means nothing (yet) 00190 if (iBlock != uiBlocks) 00191 print_success_or_failure (bFailure, &uiReadBlocks); 00192 00193 // Show if the readout went well 00194 if (bFailure) { 00195 // When a failure occured we need to redo the anti-collision 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 // Try to authenticate for the current sector 00206 if (!authenticate (iBlock)) { 00207 printf ("!\nError: authentication failed for block 0x%02x\n", iBlock); 00208 return false; 00209 } 00210 // Try to read out the trailer 00211 if (nfc_initiator_mifare_cmd (pnd, MC_READ, iBlock, &mp)) { 00212 // Copy the keys over from our key dump and store the retrieved access bits 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 // Make sure a earlier readout did not fail 00221 if (!bFailure) { 00222 // Try to read out the data block 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 // Write the card from begin to end; 00251 for (uiBlock = 0; uiBlock <= uiBlocks; uiBlock++) { 00252 // Authenticate everytime we reach the first sector of a new block 00253 if (is_first_block (uiBlock)) { 00254 // Skip this the first time, bFailure it means nothing (yet) 00255 if (uiBlock != 0) 00256 print_success_or_failure (bFailure, &uiWriteBlocks); 00257 00258 // Show if the readout went well 00259 if (bFailure) { 00260 // When a failure occured we need to redo the anti-collision 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 // Try to authenticate for the current sector 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 // Copy the keys over from our key dump and store the retrieved access bits 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 // Try to write the trailer 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 // The first block 0x00 is read only, skip this 00290 if (uiBlock == 0) 00291 continue; 00292 00293 // Make sure a earlier write did not fail 00294 if (!bFailure) { 00295 // Try to write the data block 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 // for(uint8_t uiByteIndex=0; uiByteIndex<16; uiByteIndex++) printf("%02x ", abDump[szPayloadIndex+uiByteIndex]); 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 // printf("Successfully opened required files\n"); 00422 00423 // Try to open the NFC reader 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 // Drop the field for a while 00433 if (!nfc_configure (pnd, NDO_ACTIVATE_FIELD, false)) { 00434 nfc_perror (pnd, "nfc_configure"); 00435 exit (EXIT_FAILURE); 00436 } 00437 // Let the reader only try once to find a tag 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 // Enable field so more power consuming cards can power themselves up 00451 if (!nfc_configure (pnd, NDO_ACTIVATE_FIELD, true)) { 00452 nfc_perror (pnd, "nfc_configure"); 00453 exit (EXIT_FAILURE); 00454 } 00455 // Disable ISO14443-4 switching in order to read devices that emulate Mifare Classic with ISO14443-4 compliance. 00456 nfc_configure (pnd, NDO_AUTO_ISO14443_4, false); 00457 00458 printf ("Connected to NFC reader: %s\n", pnd->acName); 00459 00460 // Try to find a MIFARE Classic tag 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 // Test if we are dealing with a MIFARE compatible tag 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 // Get the info from the key dump 00475 b4K = (mtKeys.amb[0].mbm.abtATQA[1] == 0x02); 00476 pbtUID = mtKeys.amb[0].mbm.abtUID; 00477 00478 // Compare if key dump UID is the same as the current tag UID 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 // Get the info from the current tag 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 }