libnfc  1.7.1
nfc-jewel.c
Go to the documentation of this file.
1 /*-
2  * Free/Libre Near Field Communication (NFC) library
3  *
4  * Libnfc historical contributors:
5  * Copyright (C) 2009 Roel Verdult
6  * Copyright (C) 2009-2013 Romuald Conty
7  * Copyright (C) 2010-2012 Romain Tartière
8  * Copyright (C) 2010-2013 Philippe Teuwen
9  * Copyright (C) 2012-2013 Ludovic Rousseau
10  * See AUTHORS file for a more comprehensive list of contributors.
11  * Additional contributors of this file:
12  * Copyright (C) 2014 Pim 't Hart
13  *
14  * Redistribution and use in source and binary forms, with or without
15  * modification, are permitted provided that the following conditions are met:
16  * 1) Redistributions of source code must retain the above copyright notice,
17  * this list of conditions and the following disclaimer.
18  * 2 )Redistributions in binary form must reproduce the above copyright
19  * notice, this list of conditions and the following disclaimer in the
20  * documentation and/or other materials provided with the distribution.
21  *
22  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
23  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
26  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
27  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
28  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
29  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
30  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
31  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
32  * POSSIBILITY OF SUCH DAMAGE.
33  *
34  * Note that this license only applies on the examples, NFC library itself is under LGPL
35  *
36  */
37 
43 #ifdef HAVE_CONFIG_H
44 # include "config.h"
45 #endif // HAVE_CONFIG_H
46 
47 #include <stdio.h>
48 #include <stdlib.h>
49 #include <stdint.h>
50 #include <stddef.h>
51 #include <stdbool.h>
52 
53 #include <string.h>
54 #include <ctype.h>
55 
56 #include <nfc/nfc.h>
57 
58 #include "nfc-utils.h"
59 #include "jewel.h"
60 
61 static nfc_device *pnd;
62 static nfc_target nt;
63 static jewel_req req;
64 static jewel_res res;
65 static jewel_tag ttDump;
66 static uint32_t uiBlocks = 0x0E;
67 static uint32_t uiBytesPerBlock = 0x08;
68 
69 static const nfc_modulation nmJewel = {
70  .nmt = NMT_JEWEL,
71  .nbr = NBR_106,
72 };
73 
74 static void
75 print_success_or_failure(bool bFailure, uint32_t *uiCounter)
76 {
77  printf("%c", (bFailure) ? 'x' : '.');
78  if (uiCounter)
79  *uiCounter += (bFailure) ? 0 : 1;
80 }
81 
82 static bool
83 read_card(void)
84 {
85  uint32_t block;
86  uint32_t byte;
87  bool bFailure = false;
88  uint32_t uiReadBlocks = 0;
89 
90  printf("Reading %d blocks |", uiBlocks + 1);
91 
92  for (block = 0; block <= uiBlocks; block++) {
93  for (byte = 0; byte < uiBytesPerBlock; byte++) {
94 
95  // Try to read the byte
96  req.read.btCmd = TC_READ;
97  req.read.btAdd = (block << 3) + byte;
98  if (nfc_initiator_jewel_cmd(pnd, req, &res)) {
99  ttDump.ttd.abtData[(block << 3) + byte] = res.read.btDat;
100  } else {
101  bFailure = true;
102  break;
103  }
104  }
105 
106  print_success_or_failure(bFailure, &uiReadBlocks);
107  fflush(stdout);
108  }
109  printf("|\n");
110  printf("Done, %d of %d blocks read.\n", uiReadBlocks, uiBlocks + 1);
111 
112  return (!bFailure);
113 }
114 
115 static bool
116 write_card(void)
117 {
118  uint32_t block;
119  uint32_t byte;
120  bool bFailure = false;
121  uint32_t uiWrittenBlocks = 0;
122  uint32_t uiSkippedBlocks = 0;
123  uint32_t uiPartialBlocks = 0;
124 
125  char buffer[BUFSIZ];
126  bool write_otp;
127  bool write_lock;
128 
129  printf("Write Lock bytes ? [yN] ");
130  if (!fgets(buffer, BUFSIZ, stdin)) {
131  ERR("Unable to read standard input.");
132  }
133  write_lock = ((buffer[0] == 'y') || (buffer[0] == 'Y'));
134 
135  printf("Write OTP bytes ? [yN] ");
136  if (!fgets(buffer, BUFSIZ, stdin)) {
137  ERR("Unable to read standard input.");
138  }
139  write_otp = ((buffer[0] == 'y') || (buffer[0] == 'Y'));
140 
141  printf("Writing %d pages |", uiBlocks + 1);
142 
143  // Skip block 0 - as far as I know there are no Jewel tags with block 0 writeable
144  printf("s");
145  uiSkippedBlocks++;
146 
147  for (block = uiSkippedBlocks; block <= uiBlocks; block++) {
148  // Skip block 0x0D - it is reserved for internal use and can't be written
149  if (block == 0x0D) {
150  printf("s");
151  uiSkippedBlocks++;
152  continue;
153  }
154  // Skip block 0X0E if lock-bits and OTP shouldn't be written
155  if ((block == 0x0E) && (!write_lock) && (!write_otp)) {
156  printf("s");
157  uiSkippedBlocks++;
158  continue;
159  }
160  // Write block 0x0E partially if lock-bits or OTP shouldn't be written
161  if ((block == 0x0E) && (!write_lock || !write_otp)) {
162  printf("p");
163  uiPartialBlocks++;
164  }
165 
166  for (byte = 0; byte < uiBytesPerBlock; byte++) {
167  if ((block == 0x0E) && (byte == 0 || byte == 1) && (!write_lock)) {
168  continue;
169  }
170  if ((block == 0x0E) && (byte > 1) && (!write_otp)) {
171  continue;
172  }
173 
174  // Show if the readout went well
175  if (bFailure) {
176  // When a failure occured we need to redo the anti-collision
177  if (nfc_initiator_select_passive_target(pnd, nmJewel, NULL, 0, &nt) <= 0) {
178  ERR("tag was removed");
179  return false;
180  }
181  bFailure = false;
182  }
183 
184  req.writee.btCmd = TC_WRITEE;
185  req.writee.btAdd = (block << 3) + byte;
186  req.writee.btDat = ttDump.ttd.abtData[(block << 3) + byte];
187  if (!nfc_initiator_jewel_cmd(pnd, req, &res)) {
188  bFailure = true;
189  }
190  }
191  print_success_or_failure(bFailure, &uiWrittenBlocks);
192  fflush(stdout);
193  }
194  printf("|\n");
195  printf("Done, %d of %d blocks written (%d blocks partial, %d blocks skipped).\n", uiWrittenBlocks, uiBlocks + 1, uiPartialBlocks, uiSkippedBlocks);
196 
197  return true;
198 }
199 
200 int
201 main(int argc, const char *argv[])
202 {
203  bool bReadAction;
204  FILE *pfDump;
205 
206  if (argc < 3) {
207  printf("\n");
208  printf("%s r|w <dump.jwd>\n", argv[0]);
209  printf("\n");
210  printf("r|w - Perform read from or write to card\n");
211  printf("<dump.jwd> - JeWel Dump (JWD) used to write (card to JWD) or (JWD to card)\n");
212  printf("\n");
213  exit(EXIT_FAILURE);
214  }
215 
216  DBG("\nChecking arguments and settings\n");
217 
218  bReadAction = tolower((int)((unsigned char) * (argv[1])) == 'r');
219 
220  if (bReadAction) {
221  memset(&ttDump, 0x00, sizeof(ttDump));
222  } else {
223  pfDump = fopen(argv[2], "rb");
224 
225  if (pfDump == NULL) {
226  ERR("Could not open dump file: %s\n", argv[2]);
227  exit(EXIT_FAILURE);
228  }
229 
230  if (fread(&ttDump, 1, sizeof(ttDump), pfDump) != sizeof(ttDump)) {
231  ERR("Could not read from dump file: %s\n", argv[2]);
232  fclose(pfDump);
233  exit(EXIT_FAILURE);
234  }
235  fclose(pfDump);
236  }
237  DBG("Successfully opened the dump file\n");
238 
239  nfc_context *context;
240  nfc_init(&context);
241  if (context == NULL) {
242  ERR("Unable to init libnfc (malloc)");
243  exit(EXIT_FAILURE);
244  }
245 
246  // Try to open the NFC device
247  pnd = nfc_open(context, NULL);
248  if (pnd == NULL) {
249  ERR("Error opening NFC device");
250  nfc_exit(context);
251  exit(EXIT_FAILURE);
252  }
253 
254  if (nfc_initiator_init(pnd) < 0) {
255  nfc_perror(pnd, "nfc_initiator_init");
256  nfc_close(pnd);
257  nfc_exit(context);
258  exit(EXIT_FAILURE);
259  }
260 
261  // Let the device only try once to find a tag
262  if (nfc_device_set_property_bool(pnd, NP_INFINITE_SELECT, false) < 0) {
263  nfc_perror(pnd, "nfc_device_set_property_bool");
264  nfc_close(pnd);
265  nfc_exit(context);
266  exit(EXIT_FAILURE);
267  }
268 
269  printf("NFC device: %s opened\n", nfc_device_get_name(pnd));
270 
271  // Try to find a Jewel tag
272  if (nfc_initiator_select_passive_target(pnd, nmJewel, NULL, 0, &nt) <= 0) {
273  ERR("no tag was found\n");
274  nfc_close(pnd);
275  nfc_exit(context);
276  exit(EXIT_FAILURE);
277  }
278 
279  // Get the info from the current tag
280  printf("Found Jewel card with UID: ");
281  size_t szPos;
282  for (szPos = 0; szPos < 4; szPos++) {
283  printf("%02x", nt.nti.nji.btId[szPos]);
284  }
285  printf("\n");
286 
287  if (bReadAction) {
288  if (read_card()) {
289  printf("Writing data to file: %s ... ", argv[2]);
290  fflush(stdout);
291  pfDump = fopen(argv[2], "wb");
292  if (pfDump == NULL) {
293  printf("Could not open file: %s\n", argv[2]);
294  nfc_close(pnd);
295  nfc_exit(context);
296  exit(EXIT_FAILURE);
297  }
298  if (fwrite(&ttDump, 1, sizeof(ttDump), pfDump) != sizeof(ttDump)) {
299  printf("Could not write to file: %s\n", argv[2]);
300  fclose(pfDump);
301  nfc_close(pnd);
302  nfc_exit(context);
303  exit(EXIT_FAILURE);
304  }
305  fclose(pfDump);
306  printf("Done.\n");
307  }
308  } else {
309  write_card();
310  }
311 
312  nfc_close(pnd);
313  nfc_exit(context);
314  exit(EXIT_SUCCESS);
315 }
nfc_initiator_init
int nfc_initiator_init(nfc_device *pnd)
Initialize NFC device as initiator (reader)
Definition: nfc.c:452
nfc_init
void nfc_init(nfc_context **context)
Initialize libnfc. This function must be called before calling any other libnfc function.
Definition: nfc.c:192
nfc_context
NFC library context Struct which contains internal options, references, pointers, etc....
Definition: nfc-internal.h:175
nfc_device
NFC device information.
Definition: nfc-internal.h:190
NP_INFINITE_SELECT
@ NP_INFINITE_SELECT
Definition: nfc-types.h:114
nfc_exit
void nfc_exit(nfc_context *context)
Deinitialize libnfc. Should be called after closing all open devices and before your application term...
Definition: nfc.c:209
nfc_target
NFC target structure.
Definition: nfc-types.h:328
nfc_modulation
NFC modulation structure.
Definition: nfc-types.h:319
nfc_device_get_name
const char * nfc_device_get_name(nfc_device *pnd)
Returns the device name.
Definition: nfc.c:1164
nfc_open
nfc_device * nfc_open(nfc_context *context, const nfc_connstring connstring)
Open a NFC device.
Definition: nfc.c:238
nfc_initiator_select_passive_target
int nfc_initiator_select_passive_target(nfc_device *pnd, const nfc_modulation nm, const uint8_t *pbtInitData, const size_t szInitData, nfc_target *pnt)
Select a passive or emulated tag.
Definition: nfc.c:521
nfc_perror
void nfc_perror(const nfc_device *pnd, const char *pcString)
Display the last error occured on a nfc_device.
Definition: nfc.c:1138
ERR
#define ERR(...)
Print a error message.
Definition: nfc-utils.h:85
nfc_close
void nfc_close(nfc_device *pnd)
Close from a NFC device.
Definition: nfc.c:300
nfc-utils.h
Provide some examples shared functions like print, parity calculation, options parsing.
nfc_initiator_jewel_cmd
bool nfc_initiator_jewel_cmd(nfc_device *pnd, const jewel_req req, jewel_res *pres)
Execute a Jewel Topaz Command.
Definition: jewel.c:56
nfc_device_set_property_bool
int nfc_device_set_property_bool(nfc_device *pnd, const nfc_property property, const bool bEnable)
Set a device's boolean-property value.
Definition: nfc.c:426
jewel.h
provide samples structs and functions to manipulate Jewel Topaz tags using libnfc
DBG
#define DBG(...)
Print a message of standard output only in DEBUG mode.
Definition: nfc-utils.h:59
nfc.h
libnfc interface