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   fgets (buffer, BUFSIZ, stdin);
00117   write_otp = ((buffer[0] == 'y') || (buffer[0] == 'Y'));
00118   printf ("Write Lock bytes ? [yN] ");
00119   fgets (buffer, BUFSIZ, stdin);
00120   write_lock = ((buffer[0] == 'y') || (buffer[0] == 'Y'));
00121 
00122   printf ("Writing %d pages |", uiBlocks + 1);
00123   /* We need to skip 2 first pages. */
00124   printf ("ss");
00125   uiSkippedPages = 2;
00126 
00127   for (int page = 0x2; page <= 0xF; page++) {
00128     if ((page==0x2) && (!write_lock)) {
00129       printf ("s");
00130       uiSkippedPages++;
00131       continue;
00132     }
00133     if ((page==0x3) && (!write_otp)) {
00134       printf ("s");
00135       uiSkippedPages++;
00136       continue;
00137     }
00138     // Show if the readout went well
00139     if (bFailure) {
00140       // When a failure occured we need to redo the anti-collision
00141       if (!nfc_initiator_select_passive_target (pnd, nmMifare, NULL, 0, &nt)) {
00142         ERR ("tag was removed");
00143         return false;
00144       }
00145       bFailure = false;
00146     }
00147     // For the Mifare Ultralight, this write command can be used
00148     // in compatibility mode, which only actually writes the first 
00149     // page (4 bytes). The Ultralight-specific Write command only
00150     // writes one page at a time.
00151     uiBlock = page / 4;
00152     memcpy (mp.mpd.abtData, mtDump.amb[uiBlock].mbd.abtData + ((page % 4) * 4), 16);
00153     if (!nfc_initiator_mifare_cmd (pnd, MC_WRITE, page, &mp))
00154       bFailure = true;
00155 
00156     print_success_or_failure (bFailure, &uiWritenPages);
00157   }
00158   printf ("|\n");
00159   printf ("Done, %d of %d pages written (%d pages skipped).\n", uiWritenPages, uiBlocks + 1, uiSkippedPages);
00160 
00161   return true;
00162 }
00163 
00164 int
00165 main (int argc, const char *argv[])
00166 {
00167   bool    bReadAction;
00168   FILE   *pfDump;
00169 
00170   if (argc < 3) {
00171     printf ("\n");
00172     printf ("%s r|w <dump.mfd>\n", argv[0]);
00173     printf ("\n");
00174     printf ("r|w         - Perform read from or write to card\n");
00175     printf ("<dump.mfd>  - MiFare Dump (MFD) used to write (card to MFD) or (MFD to card)\n");
00176     printf ("\n");
00177     return 1;
00178   }
00179 
00180   DBG ("\nChecking arguments and settings\n");
00181 
00182   bReadAction = tolower ((int) ((unsigned char) *(argv[1])) == 'r');
00183 
00184   if (bReadAction) {
00185     memset (&mtDump, 0x00, sizeof (mtDump));
00186   } else {
00187     pfDump = fopen (argv[2], "rb");
00188 
00189     if (pfDump == NULL) {
00190       ERR ("Could not open dump file: %s\n", argv[2]);
00191       return 1;
00192     }
00193 
00194     if (fread (&mtDump, 1, sizeof (mtDump), pfDump) != sizeof (mtDump)) {
00195       ERR ("Could not read from dump file: %s\n", argv[2]);
00196       fclose (pfDump);
00197       return 1;
00198     }
00199     fclose (pfDump);
00200   }
00201   DBG ("Successfully opened the dump file\n");
00202 
00203   // Try to open the NFC device
00204   pnd = nfc_connect (NULL);
00205   if (pnd == NULL) {
00206     ERR ("Error connecting NFC device\n");
00207     return 1;
00208   }
00209 
00210   nfc_initiator_init (pnd);
00211 
00212   // Drop the field for a while
00213   if (!nfc_configure (pnd, NDO_ACTIVATE_FIELD, false)) {
00214     nfc_perror (pnd, "nfc_configure");
00215     exit (EXIT_FAILURE);
00216   }
00217   // Let the device only try once to find a tag
00218   if (!nfc_configure (pnd, NDO_INFINITE_SELECT, false)) {
00219     nfc_perror (pnd, "nfc_configure");
00220     exit (EXIT_FAILURE);
00221   }
00222   if (!nfc_configure (pnd, NDO_HANDLE_CRC, true)) {
00223     nfc_perror (pnd, "nfc_configure");
00224     exit (EXIT_FAILURE);
00225   }
00226   if (!nfc_configure (pnd, NDO_HANDLE_PARITY, true)) {
00227     nfc_perror (pnd, "nfc_configure");
00228     exit (EXIT_FAILURE);
00229   }
00230   // Enable field so more power consuming cards can power themselves up
00231   if (!nfc_configure (pnd, NDO_ACTIVATE_FIELD, true)) {
00232     nfc_perror (pnd, "nfc_configure");
00233     exit (EXIT_FAILURE);
00234   }
00235 
00236   printf ("Connected to NFC device: %s\n", pnd->acName);
00237 
00238   // Try to find a MIFARE Ultralight tag
00239   if (!nfc_initiator_select_passive_target (pnd, nmMifare, NULL, 0, &nt)) {
00240     ERR ("no tag was found\n");
00241     nfc_disconnect (pnd);
00242     return 1;
00243   }
00244   // Test if we are dealing with a MIFARE compatible tag
00245 
00246   if (nt.nti.nai.abtAtqa[1] != 0x44) {
00247     ERR ("tag is not a MIFARE Ultralight card\n");
00248     nfc_disconnect (pnd);
00249     return EXIT_FAILURE;
00250   }
00251   // Get the info from the current tag
00252   printf ("Found MIFARE Ultralight card with UID: ");
00253   size_t  szPos;
00254   for (szPos = 0; szPos < nt.nti.nai.szUidLen; szPos++) {
00255     printf ("%02x", nt.nti.nai.abtUid[szPos]);
00256   }
00257   printf("\n");
00258 
00259   if (bReadAction) {
00260     if (read_card ()) {
00261       printf ("Writing data to file: %s ... ", argv[2]);
00262       fflush (stdout);
00263       pfDump = fopen (argv[2], "wb");
00264       if (pfDump == NULL) {
00265         printf ("Could not open file: %s\n", argv[2]);
00266         return EXIT_FAILURE;
00267       }
00268       if (fwrite (&mtDump, 1, sizeof (mtDump), pfDump) != sizeof (mtDump)) {
00269         printf ("Could not write to file: %s\n", argv[2]);
00270         return EXIT_FAILURE;
00271       }
00272       fclose (pfDump);
00273       printf ("Done.\n");
00274     }
00275   } else {
00276     write_card ();
00277   }
00278 
00279   nfc_disconnect (pnd);
00280 
00281   return EXIT_SUCCESS;
00282 }