libnfc 1.3.9
|
00001 /*- 00002 * Public platform independent Near Field Communication (NFC) library 00003 * 00004 * Copyright (C) 2009, Roel Verdult, 2010, Romuald Conty 00005 * 00006 * This program is free software: you can redistribute it and/or modify it 00007 * under the terms of the GNU Lesser General Public License as published by the 00008 * Free Software Foundation, either version 3 of the License, or (at your 00009 * option) any later version. 00010 * 00011 * This program is distributed in the hope that it will be useful, but WITHOUT 00012 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 00013 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 00014 * more details. 00015 * 00016 * You should have received a copy of the GNU Lesser General Public License 00017 * along with this program. If not, see <http://www.gnu.org/licenses/> 00018 */ 00019 00025 #ifdef HAVE_CONFIG_H 00026 # include "config.h" 00027 #endif // HAVE_CONFIG_H 00028 00029 #include <stdio.h> 00030 #include <stdlib.h> 00031 #include <stdint.h> 00032 #include <stddef.h> 00033 #include <stdbool.h> 00034 00035 #include <string.h> 00036 #include <ctype.h> 00037 00038 #include <nfc/nfc.h> 00039 #include <nfc/nfc-messages.h> 00040 00041 #include "mifare.h" 00042 #include "nfc-utils.h" 00043 00044 static nfc_device_t *pnd; 00045 static nfc_target_info_t nti; 00046 static mifare_param mp; 00047 static mifareul_tag mtDump; 00048 static uint32_t uiBlocks = 0xF; 00049 00050 static void 00051 print_success_or_failure (bool bFailure, uint32_t * uiCounter) 00052 { 00053 printf ("%c", (bFailure) ? 'x' : '.'); 00054 if (uiCounter) 00055 *uiCounter += (bFailure) ? 0 : 1; 00056 } 00057 00058 static bool 00059 read_card (void) 00060 { 00061 uint32_t page; 00062 bool bFailure = false; 00063 uint32_t uiReadedPages = 0; 00064 00065 printf ("Reading %d pages |", uiBlocks + 1); 00066 00067 for (page = 0; page <= uiBlocks; page += 4) { 00068 // Try to read out the data block 00069 if (nfc_initiator_mifare_cmd (pnd, MC_READ, page, &mp)) { 00070 memcpy (mtDump.amb[page / 4].mbd.abtData, mp.mpd.abtData, 16); 00071 } else { 00072 bFailure = true; 00073 break; 00074 } 00075 00076 print_success_or_failure (bFailure, &uiReadedPages); 00077 print_success_or_failure (bFailure, &uiReadedPages); 00078 print_success_or_failure (bFailure, &uiReadedPages); 00079 print_success_or_failure (bFailure, &uiReadedPages); 00080 } 00081 printf ("|\n"); 00082 printf ("Done, %d of %d pages readed.\n", uiReadedPages, uiBlocks + 1); 00083 fflush (stdout); 00084 00085 return (!bFailure); 00086 } 00087 00088 static bool 00089 write_card (void) 00090 { 00091 uint32_t uiBlock = 0; 00092 int page = 0x4; 00093 bool bFailure = false; 00094 uint32_t uiWritenPages = 0; 00095 00096 char buffer[BUFSIZ]; 00097 bool write_otp; 00098 00099 printf ("Write OTP bytes ? [yN] "); 00100 fgets (buffer, BUFSIZ, stdin); 00101 write_otp = ((buffer[0] == 'y') || (buffer[0] == 'Y')); 00102 00103 /* We need to skip 3 first pages. */ 00104 printf ("Writing %d pages |", uiBlocks + 1); 00105 printf ("sss"); 00106 00107 if (write_otp) { 00108 page = 0x3; 00109 } else { 00110 /* If user don't want to write OTP, we skip 1 page more. */ 00111 printf ("s"); 00112 page = 0x4; 00113 } 00114 00115 for (; page <= 0xF; page++) { 00116 // Show if the readout went well 00117 if (bFailure) { 00118 // When a failure occured we need to redo the anti-collision 00119 if (!nfc_initiator_select_passive_target (pnd, NM_ISO14443A_106, NULL, 0, &nti)) { 00120 ERR ("tag was removed"); 00121 return false; 00122 } 00123 bFailure = false; 00124 } 00125 // For the Mifare Ultralight, this write command can be used 00126 // in compatibility mode, which only actually writes the first 00127 // page (4 bytes). The Ultralight-specific Write command only 00128 // writes one page at a time. 00129 uiBlock = page / 4; 00130 memcpy (mp.mpd.abtData, mtDump.amb[uiBlock].mbd.abtData + ((page % 4) * 4), 16); 00131 if (!nfc_initiator_mifare_cmd (pnd, MC_WRITE, page, &mp)) 00132 bFailure = true; 00133 00134 print_success_or_failure (bFailure, &uiWritenPages); 00135 } 00136 printf ("|\n"); 00137 printf ("Done, %d of %d pages written (%d first pages are skipped).\n", uiWritenPages, uiBlocks + 1, 00138 write_otp ? 3 : 4); 00139 00140 return true; 00141 } 00142 00143 int 00144 main (int argc, const char *argv[]) 00145 { 00146 bool bReadAction; 00147 byte_t *pbtUID; 00148 FILE *pfDump; 00149 00150 if (argc < 3) { 00151 printf ("\n"); 00152 printf ("%s r|w <dump.mfd>\n", argv[0]); 00153 printf ("\n"); 00154 printf ("r|w - Perform read from or write to card\n"); 00155 printf ("<dump.mfd> - MiFare Dump (MFD) used to write (card to MFD) or (MFD to card)\n"); 00156 printf ("\n"); 00157 return 1; 00158 } 00159 00160 DBG ("\nChecking arguments and settings\n"); 00161 00162 bReadAction = tolower ((int) ((unsigned char) *(argv[1])) == 'r'); 00163 00164 if (bReadAction) { 00165 memset (&mtDump, 0x00, sizeof (mtDump)); 00166 } else { 00167 pfDump = fopen (argv[2], "rb"); 00168 00169 if (pfDump == NULL) { 00170 ERR ("Could not open dump file: %s\n", argv[2]); 00171 return 1; 00172 } 00173 00174 if (fread (&mtDump, 1, sizeof (mtDump), pfDump) != sizeof (mtDump)) { 00175 ERR ("Could not read from dump file: %s\n", argv[2]); 00176 fclose (pfDump); 00177 return 1; 00178 } 00179 fclose (pfDump); 00180 } 00181 DBG ("Successfully opened the dump file\n"); 00182 00183 // Try to open the NFC reader 00184 pnd = nfc_connect (NULL); 00185 if (pnd == NULL) { 00186 ERR ("Error connecting NFC reader\n"); 00187 return 1; 00188 } 00189 00190 nfc_initiator_init (pnd); 00191 00192 // Drop the field for a while 00193 if (!nfc_configure (pnd, NDO_ACTIVATE_FIELD, false)) { 00194 nfc_perror (pnd, "nfc_configure"); 00195 exit (EXIT_FAILURE); 00196 } 00197 // Let the reader only try once to find a tag 00198 if (!nfc_configure (pnd, NDO_INFINITE_SELECT, false)) { 00199 nfc_perror (pnd, "nfc_configure"); 00200 exit (EXIT_FAILURE); 00201 } 00202 if (!nfc_configure (pnd, NDO_HANDLE_CRC, true)) { 00203 nfc_perror (pnd, "nfc_configure"); 00204 exit (EXIT_FAILURE); 00205 } 00206 if (!nfc_configure (pnd, NDO_HANDLE_PARITY, true)) { 00207 nfc_perror (pnd, "nfc_configure"); 00208 exit (EXIT_FAILURE); 00209 } 00210 // Enable field so more power consuming cards can power themselves up 00211 if (!nfc_configure (pnd, NDO_ACTIVATE_FIELD, true)) { 00212 nfc_perror (pnd, "nfc_configure"); 00213 exit (EXIT_FAILURE); 00214 } 00215 00216 printf ("Connected to NFC reader: %s\n", pnd->acName); 00217 00218 // Try to find a MIFARE Ultralight tag 00219 if (!nfc_initiator_select_passive_target (pnd, NM_ISO14443A_106, NULL, 0, &nti)) { 00220 ERR ("no tag was found\n"); 00221 nfc_disconnect (pnd); 00222 return 1; 00223 } 00224 // Test if we are dealing with a MIFARE compatible tag 00225 00226 if (nti.nai.abtAtqa[1] != 0x44) { 00227 ERR ("tag is not a MIFARE Ultralight card\n"); 00228 nfc_disconnect (pnd); 00229 return EXIT_FAILURE; 00230 } 00231 // Get the info from the current tag (UID is stored little-endian) 00232 pbtUID = nti.nai.abtUid; 00233 printf ("Found MIFARE Ultralight card with UID: %02x%02x%02x%02x\n", pbtUID[3], pbtUID[2], pbtUID[1], pbtUID[0]); 00234 00235 if (bReadAction) { 00236 if (read_card ()) { 00237 printf ("Writing data to file: %s ... ", argv[2]); 00238 fflush (stdout); 00239 pfDump = fopen (argv[2], "wb"); 00240 if (pfDump == NULL) { 00241 printf ("Could not open file: %s\n", argv[2]); 00242 return EXIT_FAILURE; 00243 } 00244 if (fwrite (&mtDump, 1, sizeof (mtDump), pfDump) != sizeof (mtDump)) { 00245 printf ("Could not write to file: %s\n", argv[2]); 00246 return EXIT_FAILURE; 00247 } 00248 fclose (pfDump); 00249 printf ("Done.\n"); 00250 } 00251 } else { 00252 write_card (); 00253 } 00254 00255 nfc_disconnect (pnd); 00256 00257 return EXIT_SUCCESS; 00258 }