libnfc  1.4.2
nfc-mfultralight.c
1 /*-
2  * Public platform independent Near Field Communication (NFC) library examples
3  *
4  * Copyright (C) 2009, Roel Verdult
5  * Copyright (C) 2010, Romuald Conty
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 #include <nfc/nfc-messages.h>
51 
52 #include "mifare.h"
53 
54 static nfc_device_t *pnd;
55 static nfc_target_t nt;
56 static mifare_param mp;
57 static mifareul_tag mtDump;
58 static uint32_t uiBlocks = 0xF;
59 
60 static const nfc_modulation_t nmMifare = {
61  .nmt = NMT_ISO14443A,
62  .nbr = NBR_106,
63 };
64 
65 static void
66 print_success_or_failure (bool bFailure, uint32_t * uiCounter)
67 {
68  printf ("%c", (bFailure) ? 'x' : '.');
69  if (uiCounter)
70  *uiCounter += (bFailure) ? 0 : 1;
71 }
72 
73 static bool
74 read_card (void)
75 {
76  uint32_t page;
77  bool bFailure = false;
78  uint32_t uiReadedPages = 0;
79 
80  printf ("Reading %d pages |", uiBlocks + 1);
81 
82  for (page = 0; page <= uiBlocks; page += 4) {
83  // Try to read out the data block
84  if (nfc_initiator_mifare_cmd (pnd, MC_READ, page, &mp)) {
85  memcpy (mtDump.amb[page / 4].mbd.abtData, mp.mpd.abtData, 16);
86  } else {
87  bFailure = true;
88  break;
89  }
90 
91  print_success_or_failure (bFailure, &uiReadedPages);
92  print_success_or_failure (bFailure, &uiReadedPages);
93  print_success_or_failure (bFailure, &uiReadedPages);
94  print_success_or_failure (bFailure, &uiReadedPages);
95  }
96  printf ("|\n");
97  printf ("Done, %d of %d pages readed.\n", uiReadedPages, uiBlocks + 1);
98  fflush (stdout);
99 
100  return (!bFailure);
101 }
102 
103 static bool
104 write_card (void)
105 {
106  uint32_t uiBlock = 0;
107  bool bFailure = false;
108  uint32_t uiWritenPages = 0;
109  uint32_t uiSkippedPages;
110 
111  char buffer[BUFSIZ];
112  bool write_otp;
113  bool write_lock;
114 
115  printf ("Write OTP bytes ? [yN] ");
116  if (!fgets (buffer, BUFSIZ, stdin)) {
117  ERR ("Unable to read standard input.");
118  }
119  write_otp = ((buffer[0] == 'y') || (buffer[0] == 'Y'));
120  printf ("Write Lock bytes ? [yN] ");
121  if (!fgets (buffer, BUFSIZ, stdin)) {
122  ERR ("Unable to read standard input.");
123  }
124  write_lock = ((buffer[0] == 'y') || (buffer[0] == 'Y'));
125 
126  printf ("Writing %d pages |", uiBlocks + 1);
127  /* We need to skip 2 first pages. */
128  printf ("ss");
129  uiSkippedPages = 2;
130 
131  for (int page = 0x2; page <= 0xF; page++) {
132  if ((page==0x2) && (!write_lock)) {
133  printf ("s");
134  uiSkippedPages++;
135  continue;
136  }
137  if ((page==0x3) && (!write_otp)) {
138  printf ("s");
139  uiSkippedPages++;
140  continue;
141  }
142  // Show if the readout went well
143  if (bFailure) {
144  // When a failure occured we need to redo the anti-collision
145  if (!nfc_initiator_select_passive_target (pnd, nmMifare, NULL, 0, &nt)) {
146  ERR ("tag was removed");
147  return false;
148  }
149  bFailure = false;
150  }
151  // For the Mifare Ultralight, this write command can be used
152  // in compatibility mode, which only actually writes the first
153  // page (4 bytes). The Ultralight-specific Write command only
154  // writes one page at a time.
155  uiBlock = page / 4;
156  memcpy (mp.mpd.abtData, mtDump.amb[uiBlock].mbd.abtData + ((page % 4) * 4), 16);
157  if (!nfc_initiator_mifare_cmd (pnd, MC_WRITE, page, &mp))
158  bFailure = true;
159 
160  print_success_or_failure (bFailure, &uiWritenPages);
161  }
162  printf ("|\n");
163  printf ("Done, %d of %d pages written (%d pages skipped).\n", uiWritenPages, uiBlocks + 1, uiSkippedPages);
164 
165  return true;
166 }
167 
168 int
169 main (int argc, const char *argv[])
170 {
171  bool bReadAction;
172  FILE *pfDump;
173 
174  if (argc < 3) {
175  printf ("\n");
176  printf ("%s r|w <dump.mfd>\n", argv[0]);
177  printf ("\n");
178  printf ("r|w - Perform read from or write to card\n");
179  printf ("<dump.mfd> - MiFare Dump (MFD) used to write (card to MFD) or (MFD to card)\n");
180  printf ("\n");
181  return 1;
182  }
183 
184  DBG ("\nChecking arguments and settings\n");
185 
186  bReadAction = tolower ((int) ((unsigned char) *(argv[1])) == 'r');
187 
188  if (bReadAction) {
189  memset (&mtDump, 0x00, sizeof (mtDump));
190  } else {
191  pfDump = fopen (argv[2], "rb");
192 
193  if (pfDump == NULL) {
194  ERR ("Could not open dump file: %s\n", argv[2]);
195  return 1;
196  }
197 
198  if (fread (&mtDump, 1, sizeof (mtDump), pfDump) != sizeof (mtDump)) {
199  ERR ("Could not read from dump file: %s\n", argv[2]);
200  fclose (pfDump);
201  return 1;
202  }
203  fclose (pfDump);
204  }
205  DBG ("Successfully opened the dump file\n");
206 
207  // Try to open the NFC device
208  pnd = nfc_connect (NULL);
209  if (pnd == NULL) {
210  ERR ("Error connecting NFC device\n");
211  return 1;
212  }
213 
214  nfc_initiator_init (pnd);
215 
216  // Drop the field for a while
217  if (!nfc_configure (pnd, NDO_ACTIVATE_FIELD, false)) {
218  nfc_perror (pnd, "nfc_configure");
219  exit (EXIT_FAILURE);
220  }
221  // Let the device only try once to find a tag
222  if (!nfc_configure (pnd, NDO_INFINITE_SELECT, false)) {
223  nfc_perror (pnd, "nfc_configure");
224  exit (EXIT_FAILURE);
225  }
226  if (!nfc_configure (pnd, NDO_HANDLE_CRC, true)) {
227  nfc_perror (pnd, "nfc_configure");
228  exit (EXIT_FAILURE);
229  }
230  if (!nfc_configure (pnd, NDO_HANDLE_PARITY, true)) {
231  nfc_perror (pnd, "nfc_configure");
232  exit (EXIT_FAILURE);
233  }
234  // Enable field so more power consuming cards can power themselves up
235  if (!nfc_configure (pnd, NDO_ACTIVATE_FIELD, true)) {
236  nfc_perror (pnd, "nfc_configure");
237  exit (EXIT_FAILURE);
238  }
239 
240  printf ("Connected to NFC device: %s\n", pnd->acName);
241 
242  // Try to find a MIFARE Ultralight tag
243  if (!nfc_initiator_select_passive_target (pnd, nmMifare, NULL, 0, &nt)) {
244  ERR ("no tag was found\n");
245  nfc_disconnect (pnd);
246  return 1;
247  }
248  // Test if we are dealing with a MIFARE compatible tag
249 
250  if (nt.nti.nai.abtAtqa[1] != 0x44) {
251  ERR ("tag is not a MIFARE Ultralight card\n");
252  nfc_disconnect (pnd);
253  return EXIT_FAILURE;
254  }
255  // Get the info from the current tag
256  printf ("Found MIFARE Ultralight card with UID: ");
257  size_t szPos;
258  for (szPos = 0; szPos < nt.nti.nai.szUidLen; szPos++) {
259  printf ("%02x", nt.nti.nai.abtUid[szPos]);
260  }
261  printf("\n");
262 
263  if (bReadAction) {
264  if (read_card ()) {
265  printf ("Writing data to file: %s ... ", argv[2]);
266  fflush (stdout);
267  pfDump = fopen (argv[2], "wb");
268  if (pfDump == NULL) {
269  printf ("Could not open file: %s\n", argv[2]);
270  return EXIT_FAILURE;
271  }
272  if (fwrite (&mtDump, 1, sizeof (mtDump), pfDump) != sizeof (mtDump)) {
273  printf ("Could not write to file: %s\n", argv[2]);
274  return EXIT_FAILURE;
275  }
276  fclose (pfDump);
277  printf ("Done.\n");
278  }
279  } else {
280  write_card ();
281  }
282 
283  nfc_disconnect (pnd);
284 
285  return EXIT_SUCCESS;
286 }