MIKAI
Library to modify content of a Mykey
reader.c
Go to the documentation of this file.
1 /*
2  * @author Lilz <https://telegram.me/Lilz73>
3  * @copyright 2020-2021 Lilz <https://telegram.me/Lilz73>
4  * @license MIKAI LICENSE
5  *
6  * This file is part of MIKAI.
7  *
8  * MIKAI is free software: you can redistribute it and/or modify
9  * it under the terms of the MIKAI License, as published by
10  * Lilz along with this program and available on "MIKAI Download" Telegram channel
11  * <https://telegram.me/mikaidownload>.
12  *
13  * MIKAI is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY.
15  *
16  * You should have received a copy of the MIKAI License along
17  * with MIKAI.
18  * If not, see <https://telegram.me/mikaidownload>.
19  */
20 
21 #include <stdlib.h>
22 #include <string.h>
23 #include <nfc/nfc.h>
24 #include <mikai/mikai.h>
25 #include "reader.h"
26 
27 static const nfc_modulation nfc_ISO14443B = {
28  .nmt = NMT_ISO14443B,
29  .nbr = NBR_106,
30 };
31 
32 static const nfc_modulation nfc_ISO14443B2SR = {
33  .nmt = NMT_ISO14443B2SR,
34  .nbr = NBR_106,
35 };
36 
37 static nfc_context *libnfc_context = (void *) 0;
38 
39 static void exitNfcContext() {
40  nfc_exit(libnfc_context);
41 }
42 
46 static void nfcContextInit() {
47  if (!libnfc_context) {
48  nfc_init(&libnfc_context);
49  atexit(exitNfcContext);
50  }
51 }
52 
59 static MikaiError nfcReaderInit(NfcReader *reader, int target) {
60  /* Open target reader */
61  reader->libnfc_reader = nfc_open(libnfc_context, reader->libnfc_readers[target]);
62  if (!reader->libnfc_reader) {
63  return MIKAI_ERROR(MIKAI_NFC_ERROR, "unable to open requested nfc reader");
64  }
65 
66  /* NFC device is an initiator (a reader) */
67  if (nfc_initiator_init(reader->libnfc_reader)) {
68  nfc_close(reader->libnfc_reader);
69  return MIKAI_ERROR(MIKAI_NFC_ERROR, nfc_strerror(reader->libnfc_reader));
70  }
71 
72  nfc_device_set_property_bool(reader->libnfc_reader, NP_INFINITE_SELECT, true);
73 
74  return MIKAI_NO_ERROR;
75 }
76 
82 static MikaiError nfcSrix4kInit(NfcReader *reader) {
83  /*
84  * (libnfc) To read ISO14443B2SR you have to initiate first ISO14443B to configure PN532 internal registers.
85  * https://github.com/nfc-tools/libnfc/issues/436#issuecomment-326686914
86  */
87  nfc_target tmpTarget [MAX_TARGET_COUNT];
88  nfc_initiator_list_passive_targets(reader->libnfc_reader, nfc_ISO14443B, tmpTarget, MAX_TARGET_COUNT);
89 
90  /* NFC tag polling */
91  if (nfc_initiator_select_passive_target(reader->libnfc_reader, nfc_ISO14443B2SR, (void *) 0, 0, tmpTarget) < 0) {
92  nfc_close(reader->libnfc_reader);
93  return MIKAI_ERROR(MIKAI_NFC_ERROR, nfc_strerror(reader->libnfc_reader));
94  } else {
95  return MIKAI_NO_ERROR;
96  }
97 }
98 
108 static inline size_t nfcExchange(nfc_device *target, const uint8_t *restrict tx_data, const size_t tx_size,
109  uint8_t *restrict rx_data, const size_t rx_size) {
110  return nfc_initiator_transceive_bytes(target, tx_data, tx_size, rx_data, rx_size, 0);
111 }
112 
114  /* Allocate struct */
115  NfcReader *created = malloc(sizeof(NfcReader));
116  if (!created) {
117  return (void *) 0;
118  }
119 
120  /* Initialize context and set nfc reader to null (avoid conflicts) */
121  nfcContextInit();
122  created->libnfc_reader = (void *) 0;
123 
124  /* Return struct pointer */
125  return created;
126 }
127 
128 void NfcCloseReader(NfcReader reader[static 1]) {
129  nfc_close(reader->libnfc_reader);
130 }
131 
132 size_t NfcUpdateReaders(NfcReader reader[static 1]) {
133  /* Search for readers */
134  return nfc_list_devices(libnfc_context, reader->libnfc_readers, MAX_DEVICE_COUNT);
135 }
136 
137 char *NfcGetReaderDescription(NfcReader reader[static 1], int selection) {
138  return reader->libnfc_readers[selection];
139 }
140 
141 MikaiError NfcInitReader(NfcReader reader[static 1], int selection) {
142  /* Init Reader */
143  MikaiError error = nfcReaderInit(reader, selection);
144  if (MIKAI_IS_ERROR(error)) {
145  return error;
146  }
147 
148  /* Init SRIX */
149  error = nfcSrix4kInit(reader);
150  if (MIKAI_IS_ERROR(error)) {
151  return error;
152  }
153 
154  return MIKAI_NO_ERROR;
155 }
156 
157 /* NFC commands */
158 #define SRIX_GET_UID 0x0B
159 #define SRIX_READ_BLOCK 0x08
160 #define SRIX_WRITE_BLOCK 0x09
161 
162 MikaiError NfcGetUid(NfcReader reader[static 1], uint8_t uid[const static SRIX_UID_LENGTH]) {
163  /* Send command (length = 1) and check length */
164  if (nfcExchange(reader->libnfc_reader, (const uint8_t[]) {SRIX_GET_UID}, 1, uid, SRIX_UID_LENGTH) !=
165  SRIX_UID_LENGTH) {
166  return MIKAI_ERROR(MIKAI_NFC_ERROR, "invalid UID length");
167  }
168 
169  return MIKAI_NO_ERROR;
170 }
171 
172 
173 MikaiError NfcReadBlock(NfcReader reader[static 1], SrixBlock block[static 1], const uint8_t blockNum) {
174  /* Read while read block length is different than expected */
175  do {
176  if (nfc_initiator_target_is_present(reader->libnfc_reader, (void *) 0) < 0) {
177  MikaiError error = nfcSrix4kInit(reader);
178  if (MIKAI_IS_ERROR(error)) {
179  return error;
180  }
181  }
182  } while (nfcExchange(reader->libnfc_reader, (const uint8_t[]) {SRIX_READ_BLOCK, blockNum}, 2,
183  (uint8_t *) block, SRIX_BLOCK_LENGTH) != SRIX_BLOCK_LENGTH);
184 
185  return MIKAI_NO_ERROR;
186 }
187 
188 MikaiError NfcWriteBlock(NfcReader reader[static 1], SrixBlock block[static 1], const uint8_t blockNum) {
189  /* SRIX write command */
190  const uint8_t writeCommand[] = {
192  blockNum,
193  block->block[0],
194  block->block[1],
195  block->block[2],
196  block->block[3]
197  };
198 
199  /* Array where save read block */
200  SrixBlock check;
201 
202  do {
203  /* Check tag presence */
204  if (nfc_initiator_target_is_present(reader->libnfc_reader, (void *) 0) < 0) {
205  MikaiError error = nfcSrix4kInit(reader);
206  if (MIKAI_IS_ERROR(error)) {
207  return error;
208  }
209  }
210 
211  /* Write data */
212  nfcExchange(reader->libnfc_reader, writeCommand, 6, (void *) 0, 0);
213 
214  /* Check written data */
215  NfcReadBlock(reader, &check, blockNum);
216  } while (memcmp(block, &check, SRIX_BLOCK_LENGTH) != 0);
217 
218  return MIKAI_NO_ERROR;
219 }
220 
221 #undef SRIX_GET_UID
222 #undef SRIX_READ_BLOCK
223 #undef SRIX_WRITE_BLOCK
mikai.h
NfcInitReader
MikaiError NfcInitReader(NfcReader reader[static 1], int selection)
Definition: reader.c:141
NfcReaderNew
NfcReader * NfcReaderNew()
Allocate a nfc reader and set its default values.
Definition: reader.c:113
SrixBlock
Single SRIX block.
Definition: reader.h:34
NfcCloseReader
void NfcCloseReader(NfcReader reader[static 1])
Definition: reader.c:128
MyKey::error
MikaiError error
Definition: mikai-internal.h:34
MIKAI_NFC_ERROR
@ MIKAI_NFC_ERROR
Definition: mikai-error.h:32
NfcReadBlock
MikaiError NfcReadBlock(NfcReader reader[static 1], SrixBlock block[static 1], const uint8_t blockNum)
Definition: reader.c:173
MIKAI_NO_ERROR
#define MIKAI_NO_ERROR
Definition: mikai-error.h:45
MikaiError
Error structure that contains a description message.
Definition: mikai-error.h:40
MIKAI_IS_ERROR
#define MIKAI_IS_ERROR(isError)
Definition: mikai-error.h:47
NfcReader
Struct that represents a NFC Reader.
Definition: reader.h:41
NfcUpdateReaders
size_t NfcUpdateReaders(NfcReader reader[static 1])
Definition: reader.c:132
NfcWriteBlock
MikaiError NfcWriteBlock(NfcReader reader[static 1], SrixBlock block[static 1], const uint8_t blockNum)
Definition: reader.c:188
NfcGetReaderDescription
char * NfcGetReaderDescription(NfcReader reader[static 1], int selection)
Definition: reader.c:137
SRIX_UID_LENGTH
#define SRIX_UID_LENGTH
Definition: mikai.h:29
reader.h
NfcReader::libnfc_reader
nfc_device * libnfc_reader
Definition: reader.h:43
MAX_TARGET_COUNT
#define MAX_TARGET_COUNT
Definition: reader.h:29
SRIX_BLOCK_LENGTH
#define SRIX_BLOCK_LENGTH
Definition: mikai.h:28
MAX_DEVICE_COUNT
#define MAX_DEVICE_COUNT
Definition: reader.h:28
SrixBlock::block
uint8_t block[SRIX_BLOCK_LENGTH]
Definition: reader.h:35
MIKAI_ERROR
#define MIKAI_ERROR(type, errorMessage)
Definition: mikai-error.h:46
NfcReader::libnfc_readers
nfc_connstring libnfc_readers[8]
Definition: reader.h:42
SRIX_WRITE_BLOCK
#define SRIX_WRITE_BLOCK
Definition: reader.c:160
NfcGetUid
MikaiError NfcGetUid(NfcReader reader[static 1], uint8_t uid[const static SRIX_UID_LENGTH])
Definition: reader.c:162