libnfc  1.4.2
nfc-mfultralight.c
00001 /*-
00002  * Public platform independent Near Field Communication (NFC) library examples
00003  * 
00004  * Copyright (C) 2009, Roel Verdult
00005  * Copyright (C) 2010, Romuald Conty
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 #include <nfc/nfc-messages.h>
00051 
00052 #include "mifare.h"
00053 
00054 static nfc_device_t *pnd;
00055 static nfc_target_t nt;
00056 static mifare_param mp;
00057 static mifareul_tag mtDump;
00058 static uint32_t uiBlocks = 0xF;
00059 
00060 static const nfc_modulation_t nmMifare = {
00061   .nmt = NMT_ISO14443A,
00062   .nbr = NBR_106,
00063 };
00064 
00065 static void
00066 print_success_or_failure (bool bFailure, uint32_t * uiCounter)
00067 {
00068   printf ("%c", (bFailure) ? 'x' : '.');
00069   if (uiCounter)
00070     *uiCounter += (bFailure) ? 0 : 1;
00071 }
00072 
00073 static  bool
00074 read_card (void)
00075 {
00076   uint32_t page;
00077   bool    bFailure = false;
00078   uint32_t uiReadedPages = 0;
00079 
00080   printf ("Reading %d pages |", uiBlocks + 1);
00081 
00082   for (page = 0; page <= uiBlocks; page += 4) {
00083     // Try to read out the data block
00084     if (nfc_initiator_mifare_cmd (pnd, MC_READ, page, &mp)) {
00085       memcpy (mtDump.amb[page / 4].mbd.abtData, mp.mpd.abtData, 16);
00086     } else {
00087       bFailure = true;
00088       break;
00089     }
00090 
00091     print_success_or_failure (bFailure, &uiReadedPages);
00092     print_success_or_failure (bFailure, &uiReadedPages);
00093     print_success_or_failure (bFailure, &uiReadedPages);
00094     print_success_or_failure (bFailure, &uiReadedPages);
00095   }
00096   printf ("|\n");
00097   printf ("Done, %d of %d pages readed.\n", uiReadedPages, uiBlocks + 1);
00098   fflush (stdout);
00099 
00100   return (!bFailure);
00101 }
00102 
00103 static  bool
00104 write_card (void)
00105 {
00106   uint32_t uiBlock = 0;
00107   bool    bFailure = false;
00108   uint32_t uiWritenPages = 0;
00109   uint32_t uiSkippedPages;
00110 
00111   char    buffer[BUFSIZ];
00112   bool    write_otp;
00113   bool    write_lock;
00114 
00115   printf ("Write OTP bytes ? [yN] ");
00116   if (!fgets (buffer, BUFSIZ, stdin)) {
00117     ERR ("Unable to read standard input.");
00118   }
00119   write_otp = ((buffer[0] == 'y') || (buffer[0] == 'Y'));
00120   printf ("Write Lock bytes ? [yN] ");
00121   if (!fgets (buffer, BUFSIZ, stdin)) {
00122     ERR ("Unable to read standard input.");
00123   }
00124   write_lock = ((buffer[0] == 'y') || (buffer[0] == 'Y'));
00125 
00126   printf ("Writing %d pages |", uiBlocks + 1);
00127   /* We need to skip 2 first pages. */
00128   printf ("ss");
00129   uiSkippedPages = 2;
00130 
00131   for (int page = 0x2; page <= 0xF; page++) {
00132     if ((page==0x2) && (!write_lock)) {
00133       printf ("s");
00134       uiSkippedPages++;
00135       continue;
00136     }
00137     if ((page==0x3) && (!write_otp)) {
00138       printf ("s");
00139       uiSkippedPages++;
00140       continue;
00141     }
00142     // Show if the readout went well
00143     if (bFailure) {
00144       // When a failure occured we need to redo the anti-collision
00145       if (!nfc_initiator_select_passive_target (pnd, nmMifare, NULL, 0, &nt)) {
00146         ERR ("tag was removed");
00147         return false;
00148       }
00149       bFailure = false;
00150     }
00151     // For the Mifare Ultralight, this write command can be used
00152     // in compatibility mode, which only actually writes the first 
00153     // page (4 bytes). The Ultralight-specific Write command only
00154     // writes one page at a time.
00155     uiBlock = page / 4;
00156     memcpy (mp.mpd.abtData, mtDump.amb[uiBlock].mbd.abtData + ((page % 4) * 4), 16);
00157     if (!nfc_initiator_mifare_cmd (pnd, MC_WRITE, page, &mp))
00158       bFailure = true;
00159 
00160     print_success_or_failure (bFailure, &uiWritenPages);
00161   }
00162   printf ("|\n");
00163   printf ("Done, %d of %d pages written (%d pages skipped).\n", uiWritenPages, uiBlocks + 1, uiSkippedPages);
00164 
00165   return true;
00166 }
00167 
00168 int
00169 main (int argc, const char *argv[])
00170 {
00171   bool    bReadAction;
00172   FILE   *pfDump;
00173 
00174   if (argc < 3) {
00175     printf ("\n");
00176     printf ("%s r|w <dump.mfd>\n", argv[0]);
00177     printf ("\n");
00178     printf ("r|w         - Perform read from or write to card\n");
00179     printf ("<dump.mfd>  - MiFare Dump (MFD) used to write (card to MFD) or (MFD to card)\n");
00180     printf ("\n");
00181     return 1;
00182   }
00183 
00184   DBG ("\nChecking arguments and settings\n");
00185 
00186   bReadAction = tolower ((int) ((unsigned char) *(argv[1])) == 'r');
00187 
00188   if (bReadAction) {
00189     memset (&mtDump, 0x00, sizeof (mtDump));
00190   } else {
00191     pfDump = fopen (argv[2], "rb");
00192 
00193     if (pfDump == NULL) {
00194       ERR ("Could not open dump file: %s\n", argv[2]);
00195       return 1;
00196     }
00197 
00198     if (fread (&mtDump, 1, sizeof (mtDump), pfDump) != sizeof (mtDump)) {
00199       ERR ("Could not read from dump file: %s\n", argv[2]);
00200       fclose (pfDump);
00201       return 1;
00202     }
00203     fclose (pfDump);
00204   }
00205   DBG ("Successfully opened the dump file\n");
00206 
00207   // Try to open the NFC device
00208   pnd = nfc_connect (NULL);
00209   if (pnd == NULL) {
00210     ERR ("Error connecting NFC device\n");
00211     return 1;
00212   }
00213 
00214   nfc_initiator_init (pnd);
00215 
00216   // Drop the field for a while
00217   if (!nfc_configure (pnd, NDO_ACTIVATE_FIELD, false)) {
00218     nfc_perror (pnd, "nfc_configure");
00219     exit (EXIT_FAILURE);
00220   }
00221   // Let the device only try once to find a tag
00222   if (!nfc_configure (pnd, NDO_INFINITE_SELECT, false)) {
00223     nfc_perror (pnd, "nfc_configure");
00224     exit (EXIT_FAILURE);
00225   }
00226   if (!nfc_configure (pnd, NDO_HANDLE_CRC, true)) {
00227     nfc_perror (pnd, "nfc_configure");
00228     exit (EXIT_FAILURE);
00229   }
00230   if (!nfc_configure (pnd, NDO_HANDLE_PARITY, true)) {
00231     nfc_perror (pnd, "nfc_configure");
00232     exit (EXIT_FAILURE);
00233   }
00234   // Enable field so more power consuming cards can power themselves up
00235   if (!nfc_configure (pnd, NDO_ACTIVATE_FIELD, true)) {
00236     nfc_perror (pnd, "nfc_configure");
00237     exit (EXIT_FAILURE);
00238   }
00239 
00240   printf ("Connected to NFC device: %s\n", pnd->acName);
00241 
00242   // Try to find a MIFARE Ultralight tag
00243   if (!nfc_initiator_select_passive_target (pnd, nmMifare, NULL, 0, &nt)) {
00244     ERR ("no tag was found\n");
00245     nfc_disconnect (pnd);
00246     return 1;
00247   }
00248   // Test if we are dealing with a MIFARE compatible tag
00249 
00250   if (nt.nti.nai.abtAtqa[1] != 0x44) {
00251     ERR ("tag is not a MIFARE Ultralight card\n");
00252     nfc_disconnect (pnd);
00253     return EXIT_FAILURE;
00254   }
00255   // Get the info from the current tag
00256   printf ("Found MIFARE Ultralight card with UID: ");
00257   size_t  szPos;
00258   for (szPos = 0; szPos < nt.nti.nai.szUidLen; szPos++) {
00259     printf ("%02x", nt.nti.nai.abtUid[szPos]);
00260   }
00261   printf("\n");
00262 
00263   if (bReadAction) {
00264     if (read_card ()) {
00265       printf ("Writing data to file: %s ... ", argv[2]);
00266       fflush (stdout);
00267       pfDump = fopen (argv[2], "wb");
00268       if (pfDump == NULL) {
00269         printf ("Could not open file: %s\n", argv[2]);
00270         return EXIT_FAILURE;
00271       }
00272       if (fwrite (&mtDump, 1, sizeof (mtDump), pfDump) != sizeof (mtDump)) {
00273         printf ("Could not write to file: %s\n", argv[2]);
00274         return EXIT_FAILURE;
00275       }
00276       fclose (pfDump);
00277       printf ("Done.\n");
00278     }
00279   } else {
00280     write_card ();
00281   }
00282 
00283   nfc_disconnect (pnd);
00284 
00285   return EXIT_SUCCESS;
00286 }