libnfc  1.4.2
nfc-mfclassic.c
Go to the documentation of this file.
1 /*-
2  * Public platform independent Near Field Communication (NFC) library examples
3  *
4  * Copyright (C) 2009, Roel Verdult
5  * Copyright (C) 2010, Romuald Conty, Romain Tartière
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions are met:
9  * 1) Redistributions of source code must retain the above copyright notice,
10  * this list of conditions and the following disclaimer.
11  * 2 )Redistributions in binary form must reproduce the above copyright
12  * notice, this list of conditions and the following disclaimer in the
13  * documentation and/or other materials provided with the distribution.
14  *
15  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
16  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
19  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
20  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
21  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
22  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
23  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
24  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
25  * POSSIBILITY OF SUCH DAMAGE.
26  *
27  * Note that this license only applies on the examples, NFC library itself is under LGPL
28  *
29  */
30 
36 #ifdef HAVE_CONFIG_H
37 # include "config.h"
38 #endif // HAVE_CONFIG_H
39 
40 #include <stdio.h>
41 #include <stdlib.h>
42 #include <stdint.h>
43 #include <stddef.h>
44 #include <stdbool.h>
45 
46 #include <string.h>
47 #include <ctype.h>
48 
49 #include <nfc/nfc.h>
50 
51 #include "mifare.h"
52 #include "nfc-utils.h"
53 
54 static nfc_device_t *pnd;
55 static nfc_target_t nt;
56 static mifare_param mp;
57 static mifare_classic_tag mtKeys;
58 static mifare_classic_tag mtDump;
59 static bool bUseKeyA;
60 static bool bUseKeyFile;
61 static uint8_t uiBlocks;
62 static byte_t keys[] = {
63  0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
64  0xd3, 0xf7, 0xd3, 0xf7, 0xd3, 0xf7,
65  0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5,
66  0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5,
67  0x4d, 0x3a, 0x99, 0xc3, 0x51, 0xdd,
68  0x1a, 0x98, 0x2c, 0x7e, 0x45, 0x9a,
69  0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff,
70  0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
71  0xab, 0xcd, 0xef, 0x12, 0x34, 0x56
72 };
73 
74 static const nfc_modulation_t nmMifare = {
75  .nmt = NMT_ISO14443A,
76  .nbr = NBR_106,
77 };
78 
79 static size_t num_keys = sizeof (keys) / 6;
80 
81 static void
82 print_success_or_failure (bool bFailure, uint32_t * uiBlockCounter)
83 {
84  printf ("%c", (bFailure) ? 'x' : '.');
85  if (uiBlockCounter && !bFailure)
86  *uiBlockCounter += (*uiBlockCounter < 128) ? 4 : 16;
87 }
88 
89 static bool
90 is_first_block (uint32_t uiBlock)
91 {
92  // Test if we are in the small or big sectors
93  if (uiBlock < 128)
94  return ((uiBlock) % 4 == 0);
95  else
96  return ((uiBlock) % 16 == 0);
97 }
98 
99 static bool
100 is_trailer_block (uint32_t uiBlock)
101 {
102  // Test if we are in the small or big sectors
103  if (uiBlock < 128)
104  return ((uiBlock + 1) % 4 == 0);
105  else
106  return ((uiBlock + 1) % 16 == 0);
107 }
108 
109 static uint32_t
110 get_trailer_block (uint32_t uiFirstBlock)
111 {
112  // Test if we are in the small or big sectors
113  uint32_t trailer_block = 0;
114  if (uiFirstBlock < 128) {
115  trailer_block = uiFirstBlock + (3 - (uiFirstBlock % 4));
116  } else {
117  trailer_block = uiFirstBlock + (15 - (uiFirstBlock % 16));
118  }
119  return trailer_block;
120 }
121 
122 static bool
123 authenticate (uint32_t uiBlock)
124 {
125  mifare_cmd mc;
126  uint32_t uiTrailerBlock;
127  size_t key_index;
128 
129  // Key file authentication.
130  if (bUseKeyFile) {
131  // Set the authentication information (uid)
132  memcpy (mp.mpa.abtUid, nt.nti.nai.abtUid, 4);
133 
134  // Locate the trailer (with the keys) used for this sector
135  uiTrailerBlock = get_trailer_block (uiBlock);
136 
137  // Determin if we should use the a or the b key
138  if (bUseKeyA) {
139  mc = MC_AUTH_A;
140  memcpy (mp.mpa.abtKey, mtKeys.amb[uiTrailerBlock].mbt.abtKeyA, 6);
141  } else {
142  mc = MC_AUTH_B;
143  memcpy (mp.mpa.abtKey, mtKeys.amb[uiTrailerBlock].mbt.abtKeyB, 6);
144  }
145 
146  // Try to authenticate for the current sector
147  if (nfc_initiator_mifare_cmd (pnd, mc, uiBlock, &mp))
148  return true;
149  }
150  // Auto authentication.
151  else {
152  // Determin if we should use the a or the b key
153  mc = (bUseKeyA) ? MC_AUTH_A : MC_AUTH_B;
154 
155  // Set the authentication information (uid)
156  memcpy (mp.mpa.abtUid, nt.nti.nai.abtUid, 4);
157 
158  for (key_index = 0; key_index < num_keys; key_index++) {
159  memcpy (mp.mpa.abtKey, keys + (key_index * 6), 6);
160  if (nfc_initiator_mifare_cmd (pnd, mc, uiBlock, &mp)) {
161  if (bUseKeyA)
162  memcpy (mtKeys.amb[uiBlock].mbt.abtKeyA, &mp.mpa.abtKey, 6);
163  else
164  memcpy (mtKeys.amb[uiBlock].mbt.abtKeyB, &mp.mpa.abtKey, 6);
165 
166  return true;
167  }
168 
169  nfc_initiator_select_passive_target (pnd, nmMifare, mp.mpa.abtUid, 4, NULL);
170  }
171  }
172 
173  return false;
174 }
175 
176 static bool
177 read_card (void)
178 {
179  int32_t iBlock;
180  bool bFailure = false;
181  uint32_t uiReadBlocks = 0;
182 
183  printf ("Reading out %d blocks |", uiBlocks + 1);
184 
185  // Read the card from end to begin
186  for (iBlock = uiBlocks; iBlock >= 0; iBlock--) {
187  // Authenticate everytime we reach a trailer block
188  if (is_trailer_block (iBlock)) {
189  // Skip this the first time, bFailure it means nothing (yet)
190  if (iBlock != uiBlocks)
191  print_success_or_failure (bFailure, &uiReadBlocks);
192 
193  // Show if the readout went well
194  if (bFailure) {
195  // When a failure occured we need to redo the anti-collision
196  if (!nfc_initiator_select_passive_target (pnd, nmMifare, NULL, 0, &nt)) {
197  printf ("!\nError: tag was removed\n");
198  return false;
199  }
200  bFailure = false;
201  }
202 
203  fflush (stdout);
204 
205  // Try to authenticate for the current sector
206  if (!authenticate (iBlock)) {
207  printf ("!\nError: authentication failed for block 0x%02x\n", iBlock);
208  return false;
209  }
210  // Try to read out the trailer
211  if (nfc_initiator_mifare_cmd (pnd, MC_READ, iBlock, &mp)) {
212  // Copy the keys over from our key dump and store the retrieved access bits
213  memcpy (mtDump.amb[iBlock].mbt.abtKeyA, mtKeys.amb[iBlock].mbt.abtKeyA, 6);
214  memcpy (mtDump.amb[iBlock].mbt.abtAccessBits, mp.mpd.abtData + 6, 4);
215  memcpy (mtDump.amb[iBlock].mbt.abtKeyB, mtKeys.amb[iBlock].mbt.abtKeyB, 6);
216  } else {
217  printf ("!\nError: unable to read trailer block 0x%02x\n", iBlock);
218  }
219  } else {
220  // Make sure a earlier readout did not fail
221  if (!bFailure) {
222  // Try to read out the data block
223  if (nfc_initiator_mifare_cmd (pnd, MC_READ, iBlock, &mp)) {
224  memcpy (mtDump.amb[iBlock].mbd.abtData, mp.mpd.abtData, 16);
225  } else {
226  bFailure = true;
227  printf ("!\nError: unable to read block 0x%02x\n", iBlock);
228  return false;
229  }
230  }
231  }
232  }
233  print_success_or_failure (bFailure, &uiReadBlocks);
234  printf ("|\n");
235  printf ("Done, %d of %d blocks read.\n", uiReadBlocks, uiBlocks + 1);
236  fflush (stdout);
237 
238  return true;
239 }
240 
241 static bool
242 write_card (void)
243 {
244  uint32_t uiBlock;
245  bool bFailure = false;
246  uint32_t uiWriteBlocks = 0;
247 
248  printf ("Writing %d blocks |", uiBlocks + 1);
249 
250  // Write the card from begin to end;
251  for (uiBlock = 0; uiBlock <= uiBlocks; uiBlock++) {
252  // Authenticate everytime we reach the first sector of a new block
253  if (is_first_block (uiBlock)) {
254  // Skip this the first time, bFailure it means nothing (yet)
255  if (uiBlock != 0)
256  print_success_or_failure (bFailure, &uiWriteBlocks);
257 
258  // Show if the readout went well
259  if (bFailure) {
260  // When a failure occured we need to redo the anti-collision
261  if (!nfc_initiator_select_passive_target (pnd, nmMifare, NULL, 0, &nt)) {
262  printf ("!\nError: tag was removed\n");
263  return false;
264  }
265  bFailure = false;
266  }
267 
268  fflush (stdout);
269 
270  // Try to authenticate for the current sector
271  if (!authenticate (uiBlock)) {
272  printf ("!\nError: authentication failed for block %02x\n", uiBlock);
273  return false;
274  }
275  }
276 
277  if (is_trailer_block (uiBlock)) {
278  // Copy the keys over from our key dump and store the retrieved access bits
279  memcpy (mp.mpd.abtData, mtDump.amb[uiBlock].mbt.abtKeyA, 6);
280  memcpy (mp.mpd.abtData + 6, mtDump.amb[uiBlock].mbt.abtAccessBits, 4);
281  memcpy (mp.mpd.abtData + 10, mtDump.amb[uiBlock].mbt.abtKeyB, 6);
282 
283  // Try to write the trailer
284  if (nfc_initiator_mifare_cmd (pnd, MC_WRITE, uiBlock, &mp) == false) {
285  printf ("failed to write trailer block %d \n", uiBlock);
286  bFailure = true;
287  }
288  } else {
289  // The first block 0x00 is read only, skip this
290  if (uiBlock == 0)
291  continue;
292 
293  // Make sure a earlier write did not fail
294  if (!bFailure) {
295  // Try to write the data block
296  memcpy (mp.mpd.abtData, mtDump.amb[uiBlock].mbd.abtData, 16);
297  if (!nfc_initiator_mifare_cmd (pnd, MC_WRITE, uiBlock, &mp))
298  bFailure = true;
299  }
300  }
301  }
302  print_success_or_failure (bFailure, &uiWriteBlocks);
303  printf ("|\n");
304  printf ("Done, %d of %d blocks written.\n", uiWriteBlocks, uiBlocks + 1);
305  fflush (stdout);
306 
307  return true;
308 }
309 
310 static void
311 mifare_classic_extract_payload (const char *abDump, char *pbPayload)
312 {
313  uint8_t uiSectorIndex;
314  uint8_t uiBlockIndex;
315  size_t szDumpOffset;
316  size_t szPayloadIndex = 0;
317 
318  for (uiSectorIndex = 1; uiSectorIndex < 16; uiSectorIndex++) {
319  for (uiBlockIndex = 0; uiBlockIndex < 3; uiBlockIndex++) {
320  szDumpOffset = uiSectorIndex * 16 * 4 + uiBlockIndex * 16;
321 // for(uint8_t uiByteIndex=0; uiByteIndex<16; uiByteIndex++) printf("%02x ", abDump[szPayloadIndex+uiByteIndex]);
322  memcpy (pbPayload + szPayloadIndex, abDump + szDumpOffset, 16);
323  szPayloadIndex += 16;
324  }
325  }
326 }
327 
328 typedef enum {
329  ACTION_READ,
330  ACTION_WRITE,
331  ACTION_EXTRACT,
332  ACTION_USAGE
333 } action_t;
334 
335 static void
336 print_usage (const char *pcProgramName)
337 {
338  printf ("Usage: ");
339  printf ("%s r|w a|b <dump.mfd> [<keys.mfd>]\n", pcProgramName);
340  printf (" r|w - Perform read from (r) or write to (w) card\n");
341  printf (" a|b - Use A or B keys for action\n");
342  printf (" <dump.mfd> - MiFare Dump (MFD) used to write (card to MFD) or (MFD to card)\n");
343  printf (" <keys.mfd> - MiFare Dump (MFD) that contain the keys (optional)\n");
344  printf ("Or: ");
345  printf ("%s x <dump.mfd> <payload.bin>\n", pcProgramName);
346  printf (" x - Extract payload (data blocks) from MFD\n");
347  printf (" <dump.mfd> - MiFare Dump (MFD) that contains wanted payload\n");
348  printf (" <payload.bin> - Binary file where payload will be extracted\n");
349 }
350 
351 int
352 main (int argc, const char *argv[])
353 {
354  bool b4K;
355  action_t atAction = ACTION_USAGE;
356  byte_t *pbtUID;
357  FILE *pfKeys = NULL;
358  FILE *pfDump = NULL;
359  const char *command = argv[1];
360 
361  if (argc < 3) {
362  print_usage (argv[0]);
363  exit (EXIT_FAILURE);
364  }
365 
366  if (strcmp (command, "r") == 0) {
367  atAction = ACTION_READ;
368  bUseKeyA = tolower ((int) ((unsigned char) *(argv[2]))) == 'a';
369  bUseKeyFile = (argc > 4);
370  } else if (strcmp (command, "w") == 0) {
371  atAction = ACTION_WRITE;
372  bUseKeyA = tolower ((int) ((unsigned char) *(argv[2]))) == 'a';
373  bUseKeyFile = (argc > 4);
374  } else if (strcmp (command, "x") == 0) {
375  atAction = ACTION_EXTRACT;
376  }
377 
378  switch (atAction) {
379  case ACTION_USAGE:
380  print_usage (argv[0]);
381  exit (EXIT_FAILURE);
382  break;
383  case ACTION_READ:
384  case ACTION_WRITE:
385  if (argc < 4) {
386  print_usage (argv[0]);
387  exit (EXIT_FAILURE);
388  }
389 
390  if (bUseKeyFile) {
391  pfKeys = fopen (argv[4], "rb");
392  if (pfKeys == NULL) {
393  printf ("Could not open keys file: %s\n", argv[4]);
394  exit (EXIT_FAILURE);
395  }
396  if (fread (&mtKeys, 1, sizeof (mtKeys), pfKeys) != sizeof (mtKeys)) {
397  printf ("Could not read keys file: %s\n", argv[4]);
398  fclose (pfKeys);
399  exit (EXIT_FAILURE);
400  }
401  fclose (pfKeys);
402  }
403 
404  if (atAction == ACTION_READ) {
405  memset (&mtDump, 0x00, sizeof (mtDump));
406  } else {
407  pfDump = fopen (argv[3], "rb");
408 
409  if (pfDump == NULL) {
410  printf ("Could not open dump file: %s\n", argv[3]);
411  exit (EXIT_FAILURE);
412  }
413 
414  if (fread (&mtDump, 1, sizeof (mtDump), pfDump) != sizeof (mtDump)) {
415  printf ("Could not read dump file: %s\n", argv[3]);
416  fclose (pfDump);
417  exit (EXIT_FAILURE);
418  }
419  fclose (pfDump);
420  }
421  // printf("Successfully opened required files\n");
422 
423  // Try to open the NFC reader
424  pnd = nfc_connect (NULL);
425  if (pnd == NULL) {
426  printf ("Error connecting NFC reader\n");
427  exit (EXIT_FAILURE);
428  }
429 
430  nfc_initiator_init (pnd);
431 
432  // Drop the field for a while
433  if (!nfc_configure (pnd, NDO_ACTIVATE_FIELD, false)) {
434  nfc_perror (pnd, "nfc_configure");
435  exit (EXIT_FAILURE);
436  }
437  // Let the reader only try once to find a tag
438  if (!nfc_configure (pnd, NDO_INFINITE_SELECT, false)) {
439  nfc_perror (pnd, "nfc_configure");
440  exit (EXIT_FAILURE);
441  }
442  if (!nfc_configure (pnd, NDO_HANDLE_CRC, true)) {
443  nfc_perror (pnd, "nfc_configure");
444  exit (EXIT_FAILURE);
445  }
446  if (!nfc_configure (pnd, NDO_HANDLE_PARITY, true)) {
447  nfc_perror (pnd, "nfc_configure");
448  exit (EXIT_FAILURE);
449  }
450  // Enable field so more power consuming cards can power themselves up
451  if (!nfc_configure (pnd, NDO_ACTIVATE_FIELD, true)) {
452  nfc_perror (pnd, "nfc_configure");
453  exit (EXIT_FAILURE);
454  }
455  // Disable ISO14443-4 switching in order to read devices that emulate Mifare Classic with ISO14443-4 compliance.
456  nfc_configure (pnd, NDO_AUTO_ISO14443_4, false);
457 
458  printf ("Connected to NFC reader: %s\n", pnd->acName);
459 
460  // Try to find a MIFARE Classic tag
461  if (!nfc_initiator_select_passive_target (pnd, nmMifare, NULL, 0, &nt)) {
462  printf ("Error: no tag was found\n");
463  nfc_disconnect (pnd);
464  exit (EXIT_FAILURE);
465  }
466  // Test if we are dealing with a MIFARE compatible tag
467  if ((nt.nti.nai.btSak & 0x08) == 0) {
468  printf ("Error: tag is not a MIFARE Classic card\n");
469  nfc_disconnect (pnd);
470  exit (EXIT_FAILURE);
471  }
472 
473  if (bUseKeyFile) {
474  // Get the info from the key dump
475  b4K = (mtKeys.amb[0].mbm.abtATQA[1] == 0x02);
476  pbtUID = mtKeys.amb[0].mbm.abtUID;
477 
478  // Compare if key dump UID is the same as the current tag UID
479  if (memcmp (nt.nti.nai.abtUid, pbtUID, 4) != 0) {
480  printf ("Expected MIFARE Classic %ck card with UID: %02x%02x%02x%02x\n", b4K ? '4' : '1', pbtUID[3], pbtUID[2],
481  pbtUID[1], pbtUID[0]);
482  }
483  }
484  // Get the info from the current tag
485  pbtUID = nt.nti.nai.abtUid;
486  b4K = (nt.nti.nai.abtAtqa[1] == 0x02);
487  printf ("Found MIFARE Classic %ck card with UID: %02x%02x%02x%02x\n", b4K ? '4' : '1', pbtUID[3], pbtUID[2],
488  pbtUID[1], pbtUID[0]);
489 
490  uiBlocks = (b4K) ? 0xff : 0x3f;
491 
492  if (atAction == ACTION_READ) {
493  if (read_card ()) {
494  printf ("Writing data to file: %s ...", argv[3]);
495  fflush (stdout);
496  pfDump = fopen (argv[3], "wb");
497  if (pfDump == NULL) {
498  printf ("Could not open dump file: %s\n", argv[3]);
499  exit (EXIT_FAILURE);
500  }
501  if (fwrite (&mtDump, 1, sizeof (mtDump), pfDump) != sizeof (mtDump)) {
502  printf ("\nCould not write to file: %s\n", argv[3]);
503  exit (EXIT_FAILURE);
504  }
505  printf ("Done.\n");
506  fclose (pfDump);
507  }
508  } else {
509  write_card ();
510  }
511 
512  nfc_disconnect (pnd);
513  break;
514 
515  case ACTION_EXTRACT:{
516  const char *pcDump = argv[2];
517  const char *pcPayload = argv[3];
518 
519  FILE *pfDump = NULL;
520  FILE *pfPayload = NULL;
521 
522  char abDump[4096];
523  char abPayload[4096];
524 
525  pfDump = fopen (pcDump, "rb");
526 
527  if (pfDump == NULL) {
528  printf ("Could not open dump file: %s\n", pcDump);
529  exit (EXIT_FAILURE);
530  }
531 
532  if (fread (abDump, 1, sizeof (abDump), pfDump) != sizeof (abDump)) {
533  printf ("Could not read dump file: %s\n", pcDump);
534  fclose (pfDump);
535  exit (EXIT_FAILURE);
536  }
537  fclose (pfDump);
538 
539  mifare_classic_extract_payload (abDump, abPayload);
540 
541  printf ("Writing data to file: %s\n", pcPayload);
542  pfPayload = fopen (pcPayload, "wb");
543  if (pfPayload == NULL) {
544  printf ("Could not open file %s for writting.\n", pcPayload);
545  exit (EXIT_FAILURE);
546  }
547  if (fwrite (abPayload, 1, sizeof (abPayload), pfPayload) != sizeof (abPayload)) {
548  printf ("Could not write to file: %s\n", pcPayload);
549  exit (EXIT_FAILURE);
550  }
551  fclose (pfPayload);
552  printf ("Done, all bytes have been extracted!\n");
553  }
554  };
555 
556  exit (EXIT_SUCCESS);
557 }