libnfc 1.8.0
nfc-mfclassic.c
Go to the documentation of this file.
1/*-
2 * Free/Libre Near Field Communication (NFC) library
3 *
4 * Libnfc historical contributors:
5 * Copyright (C) 2009 Roel Verdult
6 * Copyright (C) 2009-2013 Romuald Conty
7 * Copyright (C) 2010-2012 Romain Tartière
8 * Copyright (C) 2010-2013 Philippe Teuwen
9 * Copyright (C) 2012-2013 Ludovic Rousseau
10 * See AUTHORS file for a more comprehensive list of contributors.
11 * Additional contributors of this file:
12 * Copyright (C) 2011-2013 Adam Laurie
13 * Copyright (C) 2018-2019 Danielle Bruneo
14 *
15 * Redistribution and use in source and binary forms, with or without
16 * modification, are permitted provided that the following conditions are met:
17 * 1) Redistributions of source code must retain the above copyright notice,
18 * this list of conditions and the following disclaimer.
19 * 2 )Redistributions in binary form must reproduce the above copyright
20 * notice, this list of conditions and the following disclaimer in the
21 * documentation and/or other materials provided with the distribution.
22 *
23 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
24 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
27 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
28 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
29 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
30 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
31 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
32 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
33 * POSSIBILITY OF SUCH DAMAGE.
34 *
35 * Note that this license only applies on the examples, NFC library itself is under LGPL
36 *
37 */
38
43
44#ifdef HAVE_CONFIG_H
45# include "config.h"
46#endif // HAVE_CONFIG_H
47
48#include <stdio.h>
49#include <stdlib.h>
50#include <stdint.h>
51#include <stddef.h>
52#include <stdbool.h>
53
54#include <string.h>
55#include <ctype.h>
56
57#ifndef _WIN32
58#include <fcntl.h>
59#include <sys/stat.h>
60#include <unistd.h>
61#endif
62
63#include <nfc/nfc.h>
64
65#include "mifare.h"
66#include "nfc-utils.h"
67
68static nfc_context *context;
69static nfc_device *pnd;
70static nfc_target nt;
71static mifare_param mp;
72static mifare_classic_tag mtKeys;
73static mifare_classic_tag mtDump;
74static bool bUseKeyA;
75static bool bUseKeyFile;
76static bool bForceKeyFile;
77static bool bTolerateFailures;
78static bool bFormatCard;
79static bool dWrite = false;
80static bool unlocked = false;
81static uint8_t uiBlocks;
82static uint8_t keys[] = {
83 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
84 0xd3, 0xf7, 0xd3, 0xf7, 0xd3, 0xf7,
85 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5,
86 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5,
87 0x4d, 0x3a, 0x99, 0xc3, 0x51, 0xdd,
88 0x1a, 0x98, 0x2c, 0x7e, 0x45, 0x9a,
89 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff,
90 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
91 0xab, 0xcd, 0xef, 0x12, 0x34, 0x56
92};
93static uint8_t default_key[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
94static uint8_t default_acl[] = {0xff, 0x07, 0x80, 0x69};
95
96static const nfc_modulation nmMifare = {
97 .nmt = NMT_ISO14443A,
98 .nbr = NBR_106,
99};
100
101static size_t num_keys = sizeof(keys) / 6;
102
103#define MAX_FRAME_LEN 264
104
105static uint8_t abtRx[MAX_FRAME_LEN];
106static int szRxBits;
107
108uint8_t abtHalt[4] = { 0x50, 0x00, 0x00, 0x00 };
109
110// special unlock command
111uint8_t abtUnlock1[1] = { 0x40 };
112uint8_t abtUnlock2[1] = { 0x43 };
113
114static bool
115transmit_bits(const uint8_t *pbtTx, const size_t szTxBits)
116{
117 // Show transmitted command
118 printf("Sent bits: ");
119 print_hex_bits(pbtTx, szTxBits);
120 // Transmit the bit frame command, we don't use the arbitrary parity feature
121 if ((szRxBits = nfc_initiator_transceive_bits(pnd, pbtTx, szTxBits, NULL, abtRx, sizeof(abtRx), NULL)) < 0)
122 return false;
123
124 // Show received answer
125 printf("Received bits: ");
126 print_hex_bits(abtRx, szRxBits);
127 // Succesful transfer
128 return true;
129}
130
131
132static bool
133transmit_bytes(const uint8_t *pbtTx, const size_t szTx)
134{
135 // Show transmitted command
136 printf("Sent bits: ");
137 print_hex(pbtTx, szTx);
138 // Transmit the command bytes
139 int res;
140 if ((res = nfc_initiator_transceive_bytes(pnd, pbtTx, szTx, abtRx, sizeof(abtRx), 0)) < 0)
141 return false;
142
143 // Show received answer
144 printf("Received bits: ");
145 print_hex(abtRx, res);
146 // Succesful transfer
147 return true;
148}
149
150static void
151print_success_or_failure(bool bFailure, uint32_t *uiBlockCounter)
152{
153 printf("%c", (bFailure) ? 'x' : '.');
154 if (uiBlockCounter && !bFailure)
155 *uiBlockCounter += 1;
156}
157
158static bool
159is_first_block(uint32_t uiBlock)
160{
161 // Test if we are in the small or big sectors
162 if (uiBlock < 128)
163 return ((uiBlock) % 4 == 0);
164 else
165 return ((uiBlock) % 16 == 0);
166}
167
168static bool
169is_trailer_block(uint32_t uiBlock)
170{
171 // Test if we are in the small or big sectors
172 if (uiBlock < 128)
173 return ((uiBlock + 1) % 4 == 0);
174 else
175 return ((uiBlock + 1) % 16 == 0);
176}
177
178static uint32_t
179get_trailer_block(uint32_t uiFirstBlock)
180{
181 // Test if we are in the small or big sectors
182 uint32_t trailer_block = 0;
183 if (uiFirstBlock < 128) {
184 trailer_block = uiFirstBlock + (3 - (uiFirstBlock % 4));
185 } else {
186 trailer_block = uiFirstBlock + (15 - (uiFirstBlock % 16));
187 }
188 return trailer_block;
189}
190
191static bool
192authenticate(uint32_t uiBlock)
193{
194 mifare_cmd mc;
195
196 // Set the authentication information (uid)
197 memcpy(mp.mpa.abtAuthUid, nt.nti.nai.abtUid + nt.nti.nai.szUidLen - 4, 4);
198
199 // Should we use key A or B?
200 mc = (bUseKeyA) ? MC_AUTH_A : MC_AUTH_B;
201
202 // Key file authentication.
203 if (bUseKeyFile) {
204
205 // Locate the trailer (with the keys) used for this sector
206 uint32_t uiTrailerBlock;
207 uiTrailerBlock = get_trailer_block(uiBlock);
208
209 // Extract the right key from dump file
210 if (bUseKeyA)
211 memcpy(mp.mpa.abtKey, mtKeys.amb[uiTrailerBlock].mbt.abtKeyA, sizeof(mp.mpa.abtKey));
212 else
213 memcpy(mp.mpa.abtKey, mtKeys.amb[uiTrailerBlock].mbt.abtKeyB, sizeof(mp.mpa.abtKey));
214
215 // Try to authenticate for the current sector
216 if (nfc_initiator_mifare_cmd(pnd, mc, uiBlock, &mp))
217 return true;
218
219 // If formatting or not using key file, try to guess the right key
220 } else if (bFormatCard || !bUseKeyFile) {
221 for (size_t key_index = 0; key_index < num_keys; key_index++) {
222 memcpy(mp.mpa.abtKey, keys + (key_index * 6), 6);
223 if (nfc_initiator_mifare_cmd(pnd, mc, uiBlock, &mp)) {
224 if (bUseKeyA)
225 memcpy(mtKeys.amb[uiBlock].mbt.abtKeyA, &mp.mpa.abtKey, sizeof(mtKeys.amb[uiBlock].mbt.abtKeyA));
226 else
227 memcpy(mtKeys.amb[uiBlock].mbt.abtKeyB, &mp.mpa.abtKey, sizeof(mtKeys.amb[uiBlock].mbt.abtKeyB));
228 return true;
229 }
230 if (nfc_initiator_select_passive_target(pnd, nmMifare, nt.nti.nai.abtUid, nt.nti.nai.szUidLen, NULL) <= 0) {
231 ERR("tag was removed");
232 return false;
233 }
234 }
235 }
236
237 return false;
238}
239
240static bool
241unlock_card(bool write)
242{
243 // Configure the CRC
244 if (nfc_device_set_property_bool(pnd, NP_HANDLE_CRC, false) < 0) {
245 nfc_perror(pnd, "nfc_configure");
246 return false;
247 }
248 // Use raw send/receive methods
249 if (nfc_device_set_property_bool(pnd, NP_EASY_FRAMING, false) < 0) {
250 nfc_perror(pnd, "nfc_configure");
251 return false;
252 }
253
254 iso14443a_crc_append(abtHalt, 2);
255 transmit_bytes(abtHalt, 4);
256 // now send unlock
257 if (!transmit_bits(abtUnlock1, 7)) {
258 printf("Warning: Unlock command [1/2]: failed / not acknowledged.\n");
259 dWrite = true;
260 if (write) {
261 printf("Trying to rewrite block 0 on a direct write tag.\n");
262 }
263 } else {
264 if (transmit_bytes(abtUnlock2, 1)) {
265 printf("Card unlocked\n");
266 unlocked = true;
267 } else {
268 printf("Warning: Unlock command [2/2]: failed / not acknowledged.\n");
269 }
270 }
271
272 // reset reader
273 if (!unlocked) {
274 if (nfc_initiator_select_passive_target(pnd, nmMifare, nt.nti.nai.abtUid, nt.nti.nai.szUidLen, NULL) <= 0) {
275 printf("Error: tag was removed\n");
276 nfc_close(pnd);
277 nfc_exit(context);
278 exit(EXIT_FAILURE);
279 }
280 return true;
281 }
282 // Configure the CRC
283 if (nfc_device_set_property_bool(pnd, NP_HANDLE_CRC, true) < 0) {
284 nfc_perror(pnd, "nfc_device_set_property_bool");
285 return false;
286 }
287 // Switch off raw send/receive methods
288 if (nfc_device_set_property_bool(pnd, NP_EASY_FRAMING, true) < 0) {
289 nfc_perror(pnd, "nfc_device_set_property_bool");
290 return false;
291 }
292 return true;
293}
294
295static int
296get_rats(void)
297{
298 int res;
299 uint8_t abtRats[2] = { 0xe0, 0x50};
300 // Use raw send/receive methods
301 if (nfc_device_set_property_bool(pnd, NP_EASY_FRAMING, false) < 0) {
302 nfc_perror(pnd, "nfc_configure");
303 return -1;
304 }
305 res = nfc_initiator_transceive_bytes(pnd, abtRats, sizeof(abtRats), abtRx, sizeof(abtRx), 0);
306 if (res > 0) {
307 // ISO14443-4 card, turn RF field off/on to access ISO14443-3 again
308 if (nfc_device_set_property_bool(pnd, NP_ACTIVATE_FIELD, false) < 0) {
309 nfc_perror(pnd, "nfc_configure");
310 return -1;
311 }
313 nfc_perror(pnd, "nfc_configure");
314 return -1;
315 }
316 }
317 // Reselect tag
318 if (nfc_initiator_select_passive_target(pnd, nmMifare, NULL, 0, &nt) <= 0) {
319 printf("Error: tag disappeared\n");
320 nfc_close(pnd);
321 nfc_exit(context);
322 exit(EXIT_FAILURE);
323 }
324 return res;
325}
326
327static bool
328read_card(bool read_unlocked)
329{
330 int32_t iBlock;
331 bool bFailure = false;
332 uint32_t uiReadBlocks = 0;
333
334 if (read_unlocked) {
335 unlock_card(false);
336 //If the user is attempting an unlocked read, but has a direct-write type magic card, they don't
337 //need to use the R mode. We'll trigger a warning and let them proceed.
338 if (dWrite) {
339 printf("Note: This card can't do an unlocked read (R) \n");
340 read_unlocked = 0;
341 }
342 }
343
344 printf("Reading out %d blocks |", uiBlocks + 1);
345 // Read the card from end to begin
346 for (iBlock = uiBlocks; iBlock >= 0; iBlock--) {
347 // Authenticate everytime we reach a trailer block
348 if (is_trailer_block(iBlock)) {
349 if (bFailure) {
350 // When a failure occured we need to redo the anti-collision
351 if (nfc_initiator_select_passive_target(pnd, nmMifare, NULL, 0, &nt) <= 0) {
352 printf("!\nError: tag was removed\n");
353 return false;
354 }
355 bFailure = false;
356 }
357
358 fflush(stdout);
359
360 // Try to authenticate for the current sector
361 if (!read_unlocked && !authenticate(iBlock)) {
362 printf("!\nError: authentication failed for block 0x%02x\n", iBlock);
363 return false;
364 }
365 // Try to read out the trailer
366 if (nfc_initiator_mifare_cmd(pnd, MC_READ, iBlock, &mp)) {
367 if (read_unlocked) {
368 memcpy(mtDump.amb[iBlock].mbd.abtData, mp.mpd.abtData, sizeof(mtDump.amb[iBlock].mbd.abtData));
369 } else {
370 // Copy the keys over from our key dump and store the retrieved access bits
371 memcpy(mtDump.amb[iBlock].mbt.abtKeyA, mtKeys.amb[iBlock].mbt.abtKeyA, sizeof(mtDump.amb[iBlock].mbt.abtKeyA));
372 memcpy(mtDump.amb[iBlock].mbt.abtAccessBits, mp.mpt.abtAccessBits, sizeof(mtDump.amb[iBlock].mbt.abtAccessBits));
373 memcpy(mtDump.amb[iBlock].mbt.abtKeyB, mtKeys.amb[iBlock].mbt.abtKeyB, sizeof(mtDump.amb[iBlock].mbt.abtKeyB));
374 }
375 } else {
376 printf("!\nfailed to read trailer block 0x%02x\n", iBlock);
377 bFailure = true;
378 }
379 } else {
380 // Make sure a earlier readout did not fail
381 if (!bFailure) {
382 // Try to read out the data block
383 if (nfc_initiator_mifare_cmd(pnd, MC_READ, iBlock, &mp)) {
384 memcpy(mtDump.amb[iBlock].mbd.abtData, mp.mpd.abtData, sizeof(mtDump.amb[iBlock].mbd.abtData));
385 } else {
386 printf("!\nError: unable to read block 0x%02x\n", iBlock);
387 bFailure = true;
388 }
389 }
390 }
391 // Show if the readout went well for each block
392 print_success_or_failure(bFailure, &uiReadBlocks);
393 if ((!bTolerateFailures) && bFailure)
394 return false;
395 }
396 printf("|\n");
397 printf("Done, %d of %d blocks read.\n", uiReadBlocks, uiBlocks + 1);
398 fflush(stdout);
399
400 return true;
401}
402
403static bool
404write_card(bool write_block_zero)
405{
406 uint32_t uiBlock;
407 bool bFailure = false;
408 uint32_t uiWriteBlocks = 0;
409
410 //Determine if we have to unlock the card
411 if (write_block_zero) {
412 unlock_card(true);
413 }
414
415 printf("Writing %d blocks |", uiBlocks + write_block_zero);
416 // Completely write the card, but skipping block 0 if we don't need to write on it
417 for (uiBlock = 0; uiBlock <= uiBlocks; uiBlock++) {
418 //Determine if we have to write block 0
419 if (!write_block_zero && uiBlock == 0) {
420 continue;
421 }
422 // Authenticate everytime we reach the first sector of a new block
423 if (uiBlock == 1 || is_first_block(uiBlock)) {
424 if (bFailure) {
425 // When a failure occured we need to redo the anti-collision
426 if (nfc_initiator_select_passive_target(pnd, nmMifare, NULL, 0, &nt) <= 0) {
427 printf("!\nError: tag was removed\n");
428 return false;
429 }
430 bFailure = false;
431 }
432
433 fflush(stdout);
434
435 // Try to authenticate for the current sector
436 // If we are are writing to a chinese magic card, we've already unlocked
437 // If we're writing to a direct write card, we need to authenticate
438 // If we're writing something else, we'll need to authenticate
439 if ((write_block_zero && dWrite) || !write_block_zero) {
440 if (!authenticate(uiBlock) && !bTolerateFailures) {
441 printf("!\nError: authentication failed for block %02x\n", uiBlock);
442 return false;
443 }
444 }
445 }
446
447 if (is_trailer_block(uiBlock)) {
448 if (bFormatCard) {
449 // Copy the default key and reset the access bits
450 memcpy(mp.mpt.abtKeyA, default_key, sizeof(mp.mpt.abtKeyA));
451 memcpy(mp.mpt.abtAccessBits, default_acl, sizeof(mp.mpt.abtAccessBits));
452 memcpy(mp.mpt.abtKeyB, default_key, sizeof(mp.mpt.abtKeyB));
453 } else {
454 // Copy the keys over from our key dump and store the retrieved access bits
455 memcpy(mp.mpt.abtKeyA, mtDump.amb[uiBlock].mbt.abtKeyA, sizeof(mp.mpt.abtKeyA));
456 memcpy(mp.mpt.abtAccessBits, mtDump.amb[uiBlock].mbt.abtAccessBits, sizeof(mp.mpt.abtAccessBits));
457 memcpy(mp.mpt.abtKeyB, mtDump.amb[uiBlock].mbt.abtKeyB, sizeof(mp.mpt.abtKeyB));
458 }
459
460 // Try to write the trailer
461 if (nfc_initiator_mifare_cmd(pnd, MC_WRITE, uiBlock, &mp) == false) {
462 printf("failed to write trailer block %d \n", uiBlock);
463 bFailure = true;
464 }
465 } else {
466 // Make sure a earlier write did not fail
467 if (!bFailure) {
468 // Try to write the data block
469 if (bFormatCard && uiBlock)
470
471 memset(mp.mpd.abtData, 0x00, sizeof(mp.mpd.abtData));
472 else
473 memcpy(mp.mpd.abtData, mtDump.amb[uiBlock].mbd.abtData, sizeof(mp.mpd.abtData));
474 // do not write a block 0 with incorrect BCC - card will be made invalid!
475 if (uiBlock == 0) {
476 if ((mp.mpd.abtData[0] ^ mp.mpd.abtData[1] ^ mp.mpd.abtData[2] ^ mp.mpd.abtData[3] ^ mp.mpd.abtData[4]) != 0x00) {
477 printf("!\nError: incorrect BCC in MFD file!\n");
478 printf("Expecting BCC=%02X\n", mp.mpd.abtData[0] ^ mp.mpd.abtData[1] ^ mp.mpd.abtData[2] ^ mp.mpd.abtData[3]);
479 return false;
480 }
481 }
482 if (!nfc_initiator_mifare_cmd(pnd, MC_WRITE, uiBlock, &mp)) {
483 bFailure = true;
484 printf("Failure to write to data block %i\n", uiBlock);
485 }
486 if (uiBlock == 0 && dWrite) {
487 if (nfc_initiator_init(pnd) < 0) {
488 nfc_perror(pnd, "nfc_initiator_init");
489 nfc_close(pnd);
490 nfc_exit(context);
491 exit(EXIT_FAILURE);
492 };
493 if (nfc_initiator_select_passive_target(pnd, nmMifare, NULL, 0, &nt) <= 0) {
494 printf("!\nError: tag was removed\n");
495 return false;
496 }
497 }
498 } else {
499 printf("Failure during write process.\n");
500 }
501 }
502 //}
503 // Show if the write went well for each block
504 print_success_or_failure(bFailure, &uiWriteBlocks);
505 if ((! bTolerateFailures) && bFailure)
506 return false;
507 }
508
509 printf("|\n");
510 printf("Done, %d of %d blocks written.\n", uiWriteBlocks, uiBlocks + 1);
511 fflush(stdout);
512
513 return true;
514}
515
516typedef enum {
517 ACTION_READ,
518 ACTION_WRITE,
519 ACTION_USAGE
520} action_t;
521
522static void
523print_usage(const char *pcProgramName)
524{
525 printf("Usage: ");
526 #ifndef _WIN32
527 printf("%s f|r|R|w|W a|b u|U<01ab23cd> <dump.mfd> [<keys.mfd> [f] [v]]\n", pcProgramName);
528 #else
529 printf("%s f|r|R|w|W a|b u|U<01ab23cd> <dump.mfd> [<keys.mfd> [f]]\n", pcProgramName);
530 #endif
531 printf(" f|r|R|w|W - Perform format (f) or read from (r) or unlocked read from (R) or write to (w) or block 0 write to (W) card\n");
532 printf(" *** format will reset all keys to FFFFFFFFFFFF and all data to 00 and all ACLs to default\n");
533 printf(" *** unlocked read does not require authentication and will reveal A and B keys\n");
534 printf(" *** note that block 0 write will attempt to overwrite block 0 including UID\n");
535 printf(" *** block 0 write only works with special Mifare cards (Chinese clones)\n");
536 printf(" a|A|b|B - Use A or B keys for action; Halt on errors (a|b) or tolerate errors (A|B)\n");
537 printf(" u|U - Use any (u) uid or supply a uid specifically as U01ab23cd.\n");
538 printf(" <dump.mfd> - MiFare Dump (MFD) used to write (card to MFD) or (MFD to card)\n");
539 printf(" <keys.mfd> - MiFare Dump (MFD) that contain the keys (optional)\n");
540 printf(" f - Force using the keyfile even if UID does not match (optional)\n");
541 #ifndef _WIN32
542 printf(" v - Sends libnfc log output to console (optional)\n");
543 #endif
544 printf("Examples: \n\n");
545 printf(" Read card to file, using key A:\n\n");
546 printf(" %s r a u mycard.mfd\n\n", pcProgramName);
547 printf(" Write file to blank card, using key A:\n\n");
548 printf(" %s w a u mycard.mfd\n\n", pcProgramName);
549 printf(" Write new data and/or keys to previously written card, using key A:\n\n");
550 printf(" %s w a u newdata.mfd mycard.mfd\n\n", pcProgramName);
551 printf(" Format/wipe card (note two passes required to ensure writes for all ACL cases):\n\n");
552 printf(" %s f A u dummy.mfd keyfile.mfd f\n", pcProgramName);
553 printf(" %s f B u dummy.mfd keyfile.mfd f\n\n", pcProgramName);
554 printf(" Read card to file, using key A and uid 0x01 0xab 0x23 0xcd:\n\n");
555 printf(" %s r a U01ab23cd mycard.mfd\n\n", pcProgramName);
556}
557
558
559int
560main(int argc, const char *argv[])
561{
562 action_t atAction = ACTION_USAGE;
563 uint8_t *pbtUID;
564 uint8_t _tag_uid[4];
565 uint8_t *tag_uid = _tag_uid;
566
567 bool unlock = false;
568
569 if (argc < 2) {
570 print_usage(argv[0]);
571 exit(EXIT_FAILURE);
572 }
573 const char *command = argv[1];
574
575 if (argc < 5) {
576 print_usage(argv[0]);
577 exit(EXIT_FAILURE);
578 }
579 if (strcmp(command, "r") == 0 || strcmp(command, "R") == 0) {
580 atAction = ACTION_READ;
581 if (strcmp(command, "R") == 0)
582 unlock = true;
583 bUseKeyA = tolower((int)((unsigned char) * (argv[2]))) == 'a';
584 bTolerateFailures = tolower((int)((unsigned char) * (argv[2]))) != (int)((unsigned char) * (argv[2]));
585 bUseKeyFile = (argc > 5) && strcmp(argv[5], "v");
586 bForceKeyFile = ((argc > 6) && (strcmp((char *)argv[6], "f") == 0));
587 } else if (strcmp(command, "w") == 0 || strcmp(command, "W") == 0 || strcmp(command, "f") == 0) {
588 atAction = ACTION_WRITE;
589 if (strcmp(command, "W") == 0)
590 unlock = true;
591 bFormatCard = (strcmp(command, "f") == 0);
592 bUseKeyA = tolower((int)((unsigned char) * (argv[2]))) == 'a';
593 bTolerateFailures = tolower((int)((unsigned char) * (argv[2]))) != (int)((unsigned char) * (argv[2]));
594 bUseKeyFile = (argc > 5) && strcmp(argv[5], "v");
595 bForceKeyFile = ((argc > 6) && (strcmp((char *)argv[6], "f") == 0));
596 }
597 if (argv[3][0] == 'U') {
598 unsigned long int _uid;
599
600 if (strlen(argv[3]) != 9) {
601 printf("Error, illegal tag specification, use U01ab23cd for example.\n");
602 print_usage(argv[0]);
603 exit(EXIT_FAILURE);
604 }
605 _uid = strtoul(argv[3] + 1, NULL, 16);
606 tag_uid[0] = (_uid & 0xff000000UL) >> 24;
607 tag_uid[1] = (_uid & 0x00ff0000UL) >> 16;
608 tag_uid[2] = (_uid & 0x0000ff00UL) >> 8;
609 tag_uid[3] = (_uid & 0x000000ffUL);
610 printf("Attempting to use specific UID: 0x%2x 0x%2x 0x%2x 0x%2x\n",
611 tag_uid[0], tag_uid[1], tag_uid[2], tag_uid[3]);
612 } else {
613 tag_uid = NULL;
614 }
615
616 #ifndef _WIN32
617 // Send noise from lib to /dev/null
618 bool verbose = false;
619 if (argv[7]) {
620 if (strcmp(argv[7], "v") == 0) verbose = true;
621 } else {
622 if ((strcmp(argv[6], "v")) || (strcmp(argv[5], "v")) == 0) verbose = true;
623 }
624 if (!verbose) {
625 int fd = open("/dev/null", O_WRONLY);
626 dup2(fd, 2);
627 close(fd);
628 }
629 #endif
630
631 if (atAction == ACTION_USAGE) {
632 print_usage(argv[0]);
633 exit(EXIT_FAILURE);
634 }
635 // We don't know yet the card size so let's read only the UID from the keyfile for the moment
636 if (bUseKeyFile) {
637 FILE *pfKeys = fopen(argv[5], "rb");
638 if (pfKeys == NULL) {
639 printf("Could not open keys file: %s\n", argv[5]);
640 exit(EXIT_FAILURE);
641 }
642 if (fread(&mtKeys, 1, 4, pfKeys) != 4) {
643 printf("Could not read UID from key file: %s\n", argv[5]);
644 fclose(pfKeys);
645 exit(EXIT_FAILURE);
646 }
647 fclose(pfKeys);
648 }
649 nfc_init(&context);
650 if (context == NULL) {
651 ERR("Unable to init libnfc (malloc)");
652 exit(EXIT_FAILURE);
653 }
654
655// Try to open the NFC reader
656 pnd = nfc_open(context, NULL);
657 if (pnd == NULL) {
658 ERR("Error opening NFC reader");
659 nfc_exit(context);
660 exit(EXIT_FAILURE);
661 }
662
663 if (nfc_initiator_init(pnd) < 0) {
664 nfc_perror(pnd, "nfc_initiator_init");
665 nfc_close(pnd);
666 nfc_exit(context);
667 exit(EXIT_FAILURE);
668 };
669
670 // Drop the field for a while, so can be reset
672 nfc_perror(pnd, "nfc_device_set_property_bool activate field");
673 nfc_close(pnd);
674 nfc_exit(context);
675 exit(EXIT_FAILURE);
676 }
677
678// Let the reader only try once to find a tag
680 nfc_perror(pnd, "nfc_device_set_property_bool");
681 nfc_close(pnd);
682 nfc_exit(context);
683 exit(EXIT_FAILURE);
684 }
685// Disable ISO14443-4 switching in order to read devices that emulate Mifare Classic with ISO14443-4 compliance.
687 nfc_perror(pnd, "nfc_device_set_property_bool");
688 nfc_close(pnd);
689 nfc_exit(context);
690 exit(EXIT_FAILURE);
691 }
692
693 // Configure the CRC and Parity settings
694 if (nfc_device_set_property_bool(pnd, NP_HANDLE_CRC, true) < 0) {
695 nfc_perror(pnd, "nfc_device_set_property_bool crc");
696 nfc_close(pnd);
697 nfc_exit(context);
698 exit(EXIT_FAILURE);
699 }
701 nfc_perror(pnd, "nfc_device_set_property_bool parity");
702 nfc_close(pnd);
703 nfc_exit(context);
704 exit(EXIT_FAILURE);
705 }
706
707 printf("NFC reader: %s opened\n", nfc_device_get_name(pnd));
708
709// Try to find a MIFARE Classic tag
710 int tags;
711 tags = nfc_initiator_select_passive_target(pnd, nmMifare, tag_uid, tag_uid == NULL ? 0 : 4, &nt);
712 if (tags <= 0) {
713 printf("Error: no tag was found\n");
714 nfc_close(pnd);
715 nfc_exit(context);
716 exit(EXIT_FAILURE);
717 }
718// Test if we are dealing with a MIFARE compatible tag
719 if (((nt.nti.nai.btSak & 0x08) == 0) && (nt.nti.nai.btSak != 0x01)) {
720// if ((nt.nti.nai.btSak & 0x08) == 0) {
721 printf("Warning: tag is probably not a MFC!\n");
722 }
723
724// Get the info from the current tag
725 pbtUID = nt.nti.nai.abtUid;
726
727 if (bUseKeyFile) {
728 uint8_t fileUid[4];
729 memcpy(fileUid, mtKeys.amb[0].mbm.abtUID, 4);
730// Compare if key dump UID is the same as the current tag UID, at least for the first 4 bytes
731 if (memcmp(pbtUID, fileUid, 4) != 0) {
732 printf("Expected MIFARE Classic card with UID starting as: %02x%02x%02x%02x\n",
733 fileUid[0], fileUid[1], fileUid[2], fileUid[3]);
734 printf("Got card with UID starting as: %02x%02x%02x%02x\n",
735 pbtUID[0], pbtUID[1], pbtUID[2], pbtUID[3]);
736 if (!bForceKeyFile) {
737 printf("Aborting!\n");
738 nfc_close(pnd);
739 nfc_exit(context);
740 exit(EXIT_FAILURE);
741 }
742 }
743 }
744 printf("Found MIFARE Classic card:\n");
745 print_nfc_target(&nt, false);
746
747// Guessing size
748 if ((nt.nti.nai.abtAtqa[1] & 0x02) == 0x02 || nt.nti.nai.btSak == 0x18)
749// 4K
750 uiBlocks = 0xff;
751 else if (nt.nti.nai.btSak == 0x09)
752// 320b
753 uiBlocks = 0x13;
754 else
755// 1K/2K, checked through RATS
756 uiBlocks = 0x3f;
757// Testing RATS
758 int res;
759 if ((res = get_rats()) > 0) {
760 printf("RATS support: yes\n");
761 if ((res >= 10) && (abtRx[5] == 0xc1) && (abtRx[6] == 0x05)
762 && (abtRx[7] == 0x2f) && (abtRx[8] == 0x2f)
763 && ((nt.nti.nai.abtAtqa[1] & 0x02) == 0x00)) {
764 // MIFARE Plus 2K
765 uiBlocks = 0x7f;
766 }
767 } else
768 printf("RATS support: no\n");
769 printf("Guessing size: seems to be a %lu-byte card\n", (unsigned long)((uiBlocks + 1) * sizeof(mifare_classic_block)));
770
771 if (bUseKeyFile) {
772 FILE *pfKeys = fopen(argv[5], "rb");
773 if (pfKeys == NULL) {
774 printf("Could not open keys file: %s\n", argv[5]);
775 exit(EXIT_FAILURE);
776 }
777 if (fread(&mtKeys, 1, (uiBlocks + 1) * sizeof(mifare_classic_block), pfKeys) != (uiBlocks + 1) * sizeof(mifare_classic_block)) {
778 printf("Could not read keys file: %s\n", argv[5]);
779 fclose(pfKeys);
780 exit(EXIT_FAILURE);
781 }
782 fclose(pfKeys);
783 }
784
785 if (atAction == ACTION_READ) {
786 memset(&mtDump, 0x00, sizeof(mtDump));
787 } else {
788 FILE *pfDump = fopen(argv[4], "rb");
789
790 if (pfDump == NULL) {
791 printf("Could not open dump file: %s\n", argv[4]);
792 exit(EXIT_FAILURE);
793
794 }
795
796 if (fread(&mtDump, 1, (uiBlocks + 1) * sizeof(mifare_classic_block), pfDump) != (uiBlocks + 1) * sizeof(mifare_classic_block)) {
797 printf("Could not read dump file: %s\n", argv[4]);
798 fclose(pfDump);
799 exit(EXIT_FAILURE);
800 }
801 fclose(pfDump);
802 }
803// printf("Successfully opened required files\n");
804
805 if (atAction == ACTION_READ) {
806 if (read_card(unlock)) {
807 printf("Writing data to file: %s ...", argv[4]);
808 fflush(stdout);
809 FILE *pfDump = fopen(argv[4], "wb");
810 if (pfDump == NULL) {
811 printf("Could not open dump file: %s\n", argv[4]);
812 nfc_close(pnd);
813 nfc_exit(context);
814 exit(EXIT_FAILURE);
815 }
816 if (fwrite(&mtDump, 1, (uiBlocks + 1) * sizeof(mifare_classic_block), pfDump) != ((uiBlocks + 1) * sizeof(mifare_classic_block))) {
817 printf("\nCould not write to file: %s\n", argv[4]);
818 fclose(pfDump);
819 nfc_close(pnd);
820 nfc_exit(context);
821 exit(EXIT_FAILURE);
822 }
823 printf("Done.\n");
824 fclose(pfDump);
825 } else {
826 nfc_close(pnd);
827 nfc_exit(context);
828 exit(EXIT_FAILURE);
829 }
830 } else if (atAction == ACTION_WRITE) {
831 if (!write_card(unlock)) {
832 nfc_close(pnd);
833 nfc_exit(context);
834 exit(EXIT_FAILURE);
835 }
836 }
837
838 nfc_close(pnd);
839 nfc_exit(context);
840 exit(EXIT_SUCCESS);
841}
const char * nfc_device_get_name(nfc_device *pnd)
Returns the device name.
Definition nfc.c:1213
void nfc_close(nfc_device *pnd)
Close from a NFC device.
Definition nfc.c:339
nfc_device * nfc_open(nfc_context *context, const nfc_connstring connstring)
Open a NFC device.
Definition nfc.c:277
void nfc_perror(const nfc_device *pnd, const char *pcString)
Display the last error occured on a nfc_device.
Definition nfc.c:1187
int nfc_initiator_transceive_bytes(nfc_device *pnd, const uint8_t *pbtTx, const size_t szTx, uint8_t *pbtRx, const size_t szRx, int timeout)
Send data to target then retrieve data from target.
Definition nfc.c:813
int nfc_initiator_transceive_bits(nfc_device *pnd, const uint8_t *pbtTx, const size_t szTxBits, const uint8_t *pbtTxPar, uint8_t *pbtRx, const size_t szRx, uint8_t *pbtRxPar)
Transceive raw bit-frames to a target.
Definition nfc.c:856
int nfc_initiator_init(nfc_device *pnd)
Initialize NFC device as initiator (reader)
Definition nfc.c:493
int nfc_initiator_select_passive_target(nfc_device *pnd, const nfc_modulation nm, const uint8_t *pbtInitData, const size_t szInitData, nfc_target *pnt)
Select a passive or emulated tag.
Definition nfc.c:562
void nfc_exit(nfc_context *context)
Deinitialize libnfc. Should be called after closing all open devices and before your application term...
Definition nfc.c:248
void nfc_init(nfc_context **context)
Initialize libnfc. This function must be called before calling any other libnfc function.
Definition nfc.c:231
int nfc_device_set_property_bool(nfc_device *pnd, const nfc_property property, const bool bEnable)
Set a device's boolean-property value.
Definition nfc.c:466
bool nfc_initiator_mifare_cmd(nfc_device *pnd, const mifare_cmd mc, const uint8_t ui8Block, mifare_param *pmp)
Execute a MIFARE Classic Command.
Definition mifare.c:60
provide samples structs and functions to manipulate MIFARE Classic and Ultralight tags using libnfc
@ NP_INFINITE_SELECT
Definition nfc-types.h:115
@ NP_HANDLE_CRC
Definition nfc-types.h:94
@ NP_ACTIVATE_FIELD
Definition nfc-types.h:105
@ NP_AUTO_ISO14443_4
Definition nfc-types.h:134
@ NP_EASY_FRAMING
Definition nfc-types.h:136
@ NP_HANDLE_PARITY
Definition nfc-types.h:102
Provide some examples shared functions like print, parity calculation, options parsing.
#define ERR(...)
Print a error message.
Definition nfc-utils.h:85
libnfc interface
NFC library context Struct which contains internal options, references, pointers, etc....
NFC device information.
NFC modulation structure.
Definition nfc-types.h:342
NFC target structure.
Definition nfc-types.h:351