65 #define MAX_FRAME_LEN 264
66 #define MAX_DEVICE_COUNT 2
68 static uint8_t abtCapdu[MAX_FRAME_LEN];
69 static size_t szCapduLen;
70 static uint8_t abtRapdu[MAX_FRAME_LEN];
71 static size_t szRapduLen;
74 static bool quitting =
false;
75 static bool quiet_output =
false;
76 static bool initiator_only_mode =
false;
77 static bool target_only_mode =
false;
78 static bool swap_devices =
false;
79 static unsigned int waiting_time = 0;
87 printf(
"\nQuitting...\n");
88 printf(
"Please send a last command to the emulator to quit properly.\n");
94 print_usage(
char *argv[])
96 printf(
"Usage: %s [OPTIONS]\n", argv[0]);
98 printf(
"\t-h\tHelp. Print this message.\n");
99 printf(
"\t-q\tQuiet mode. Suppress printing of relayed data (improves timing).\n");
100 printf(
"\t-t\tTarget mode only (the one on reader side). Data expected from FD3 to FD4.\n");
101 printf(
"\t-i\tInitiator mode only (the one on tag side). Data expected from FD3 to FD4.\n");
102 printf(
"\t-s\tSwap roles of found devices.\n");
103 printf(
"\t-n N\tAdds a waiting time of N seconds (integer) in the relay to mimic long distance.\n");
106 static int print_hex_fd4(
const uint8_t *pbtData,
const size_t szBytes,
const char *pchPrefix)
109 if (szBytes > MAX_FRAME_LEN) {
112 if (fprintf(fd4,
"#%s %04" PRIxPTR
": ", pchPrefix, szBytes) < 0) {
116 for (szPos = 0; szPos < szBytes; szPos++) {
117 if (fprintf(fd4,
"%02x ", pbtData[szPos]) < 0) {
121 if (fprintf(fd4,
"\n") < 0) {
128 static int scan_hex_fd3(uint8_t *pbtData,
size_t *pszBytes,
const char *pchPrefix)
131 unsigned int uiBytes;
136 while ((c = fgetc(fd3)) !=
'#') {
141 strncpy(pchScan, pchPrefix, 250);
142 pchScan[
sizeof(pchScan) - 1] =
'\0';
143 strcat(pchScan,
" %04x:");
144 if (fscanf(fd3, pchScan, &uiBytes) < 1) {
148 if (*pszBytes > MAX_FRAME_LEN) {
151 for (szPos = 0; szPos < *pszBytes; szPos++) {
152 if (fscanf(fd3,
"%02x", &uiData) < 1) {
155 pbtData[szPos] = uiData;
161 main(
int argc,
char *argv[])
168 for (arg = 1; arg < argc; arg++) {
169 if (0 == strcmp(argv[arg],
"-h")) {
172 }
else if (0 == strcmp(argv[arg],
"-q")) {
174 }
else if (0 == strcmp(argv[arg],
"-t")) {
175 printf(
"INFO: %s\n",
"Target mode only.");
176 initiator_only_mode =
false;
177 target_only_mode =
true;
178 }
else if (0 == strcmp(argv[arg],
"-i")) {
179 printf(
"INFO: %s\n",
"Initiator mode only.");
180 initiator_only_mode =
true;
181 target_only_mode =
false;
182 }
else if (0 == strcmp(argv[arg],
"-s")) {
183 printf(
"INFO: %s\n",
"Swapping devices.");
185 }
else if (0 == strcmp(argv[arg],
"-n")) {
186 if (++arg == argc || (sscanf(argv[arg],
"%10u", &waiting_time) < 1)) {
187 ERR(
"Missing or wrong waiting time value: %s.", argv[arg]);
191 printf(
"Waiting time: %u secs.\n", waiting_time);
193 ERR(
"%s is not supported option.", argv[arg]);
200 printf(
"%s uses libnfc %s\n", argv[0], acLibnfcVersion);
203 signal(SIGINT, (
void (__cdecl *)(
int)) intr_hdlr);
205 signal(SIGINT, intr_hdlr);
210 if (context == NULL) {
211 ERR(
"Unable to init libnfc (malloc)");
219 if (initiator_only_mode || target_only_mode) {
221 ERR(
"No device found");
225 if ((fd3 = fdopen(3,
"r")) == NULL) {
226 ERR(
"Could not open file descriptor 3");
230 if ((fd4 = fdopen(4,
"w")) == NULL) {
231 ERR(
"Could not open file descriptor 4");
237 ERR(
"%" PRIdPTR
" device found but two opened devices are needed to relay NFC.", szFound);
243 if (!target_only_mode) {
249 if ((szFound == 1) || swap_devices) {
250 pndInitiator =
nfc_open(context, connstrings[0]);
252 pndInitiator =
nfc_open(context, connstrings[1]);
255 if (pndInitiator == NULL) {
256 printf(
"Error opening NFC reader\n");
264 printf(
"Error: fail initializing initiator\n");
272 .nmt = NMT_ISO14443A,
276 printf(
"Error: no tag was found\n");
282 printf(
"Found tag:\n");
283 print_nfc_target(&ntRealTarget,
false);
284 if (initiator_only_mode) {
285 if (print_hex_fd4(ntRealTarget.nti.nai.abtUid, ntRealTarget.nti.nai.szUidLen,
"UID") < 0) {
286 fprintf(stderr,
"Error while printing UID to FD4\n");
291 if (print_hex_fd4(ntRealTarget.nti.nai.abtAtqa, 2,
"ATQA") < 0) {
292 fprintf(stderr,
"Error while printing ATQA to FD4\n");
297 if (print_hex_fd4(&(ntRealTarget.nti.nai.btSak), 1,
"SAK") < 0) {
298 fprintf(stderr,
"Error while printing SAK to FD4\n");
303 if (print_hex_fd4(ntRealTarget.nti.nai.abtAts, ntRealTarget.nti.nai.szAtsLen,
"ATS") < 0) {
304 fprintf(stderr,
"Error while printing ATS to FD4\n");
311 if (initiator_only_mode) {
312 printf(
"Hint: tag <---> *INITIATOR* (relay) <-FD3/FD4-> target (relay) <---> original reader\n\n");
313 }
else if (target_only_mode) {
314 printf(
"Hint: tag <---> initiator (relay) <-FD3/FD4-> *TARGET* (relay) <---> original reader\n\n");
316 printf(
"Hint: tag <---> initiator (relay) <---> target (relay) <---> original reader\n\n");
318 if (!initiator_only_mode) {
321 .nmt = NMT_ISO14443A,
325 if (target_only_mode) {
327 if (scan_hex_fd3(ntEmulatedTarget.nti.nai.abtUid, &(ntEmulatedTarget.nti.nai.szUidLen),
"UID") < 0) {
328 fprintf(stderr,
"Error while scanning UID from FD3\n");
333 if (scan_hex_fd3(ntEmulatedTarget.nti.nai.abtAtqa, &foo,
"ATQA") < 0) {
334 fprintf(stderr,
"Error while scanning ATQA from FD3\n");
339 if (scan_hex_fd3(&(ntEmulatedTarget.nti.nai.btSak), &foo,
"SAK") < 0) {
340 fprintf(stderr,
"Error while scanning SAK from FD3\n");
345 if (scan_hex_fd3(ntEmulatedTarget.nti.nai.abtAts, &(ntEmulatedTarget.nti.nai.szAtsLen),
"ATS") < 0) {
346 fprintf(stderr,
"Error while scanning ATS from FD3\n");
352 ntEmulatedTarget.nti = ntRealTarget.nti;
355 ntEmulatedTarget.nti.nai.szUidLen = 4;
356 ntEmulatedTarget.nti.nai.abtAtqa[1] &= (0xFF - 0x40);
358 ntEmulatedTarget.nti.nai.abtUid[0] = 0x08;
372 pbtTk = iso14443a_locate_historical_bytes(ntEmulatedTarget.nti.nai.abtAts, ntEmulatedTarget.nti.nai.szAtsLen, &szTk);
373 szTk = (szTk > 48) ? 48 : szTk;
375 memcpy(pbtTkt, pbtTk, szTk);
376 ntEmulatedTarget.nti.nai.abtAts[0] = 0x75;
377 ntEmulatedTarget.nti.nai.abtAts[1] = 0x33;
378 ntEmulatedTarget.nti.nai.abtAts[2] = 0x92;
379 ntEmulatedTarget.nti.nai.abtAts[3] = 0x03;
380 ntEmulatedTarget.nti.nai.szAtsLen = 4 + szTk;
381 memcpy(&(ntEmulatedTarget.nti.nai.abtAts[4]), pbtTkt, szTk);
383 printf(
"We will emulate:\n");
384 print_nfc_target(&ntEmulatedTarget,
false);
388 pndTarget =
nfc_open(context, connstrings[1]);
390 pndTarget =
nfc_open(context, connstrings[0]);
392 if (pndTarget == NULL) {
393 printf(
"Error opening NFC emulator device\n");
394 if (!target_only_mode) {
402 if (
nfc_target_init(pndTarget, &ntEmulatedTarget, abtCapdu,
sizeof(abtCapdu), 0) < 0) {
403 ERR(
"%s",
"Initialization of NFC emulator failed");
404 if (!target_only_mode) {
411 printf(
"%s\n",
"Done, relaying frames now!");
417 if (!initiator_only_mode) {
420 nfc_perror(pndTarget,
"nfc_target_receive_bytes");
421 if (!target_only_mode) {
428 szCapduLen = (size_t) res;
429 if (target_only_mode) {
430 if (print_hex_fd4(abtCapdu, szCapduLen,
"C-APDU") < 0) {
431 fprintf(stderr,
"Error while printing C-APDU to FD4\n");
438 if (scan_hex_fd3(abtCapdu, &szCapduLen,
"C-APDU") < 0) {
439 fprintf(stderr,
"Error while scanning C-APDU from FD3\n");
447 printf(
"Forwarding C-APDU: ");
448 print_hex(abtCapdu, szCapduLen);
451 if (!target_only_mode) {
456 szRapduLen = (size_t) res;
460 if (scan_hex_fd3(abtRapdu, &szRapduLen,
"R-APDU") < 0) {
461 fprintf(stderr,
"Error while scanning R-APDU from FD3\n");
470 if (waiting_time != 0) {
472 printf(
"Waiting %us to simulate longer relay...\n", waiting_time);
478 printf(
"Forwarding R-APDU: ");
479 print_hex(abtRapdu, szRapduLen);
481 if (!initiator_only_mode) {
484 nfc_perror(pndTarget,
"nfc_target_send_bytes");
485 if (!target_only_mode) {
488 if (!initiator_only_mode) {
495 if (print_hex_fd4(abtRapdu, szRapduLen,
"R-APDU") < 0) {
496 fprintf(stderr,
"Error while printing R-APDU to FD4\n");
505 if (!target_only_mode) {
508 if (!initiator_only_mode) {
const char * nfc_device_get_name(nfc_device *pnd)
Returns the device name.
void nfc_close(nfc_device *pnd)
Close from a NFC device.
nfc_device * nfc_open(nfc_context *context, const nfc_connstring connstring)
Open a NFC device.
size_t nfc_list_devices(nfc_context *context, nfc_connstring connstrings[], const size_t connstrings_len)
Scan for discoverable supported devices (ie. only available for some drivers)
void nfc_perror(const nfc_device *pnd, const char *pcString)
Display the last error occured on a nfc_device.
int nfc_initiator_transceive_bytes(nfc_device *pnd, const uint8_t *pbtTx, const size_t szTx, uint8_t *pbtRx, const size_t szRx, int timeout)
Send data to target then retrieve data from target.
int nfc_initiator_init(nfc_device *pnd)
Initialize NFC device as initiator (reader)
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.
void nfc_exit(nfc_context *context)
Deinitialize libnfc. Should be called after closing all open devices and before your application term...
void nfc_init(nfc_context **context)
Initialize libnfc. This function must be called before calling any other libnfc function.
const char * nfc_version(void)
Returns the library version.
int nfc_target_send_bytes(nfc_device *pnd, const uint8_t *pbtTx, const size_t szTx, int timeout)
Send bytes and APDU frames.
int nfc_target_init(nfc_device *pnd, nfc_target *pnt, uint8_t *pbtRx, const size_t szRx, int timeout)
Initialize NFC device as an emulated tag.
int nfc_target_receive_bytes(nfc_device *pnd, uint8_t *pbtRx, const size_t szRx, int timeout)
Receive bytes and APDU frames.
char nfc_connstring[NFC_BUFSIZE_CONNSTRING]
Provide some examples shared functions like print, parity calculation, options parsing.
#define ERR(...)
Print a error message.
NFC library context Struct which contains internal options, references, pointers, etc....
NFC modulation structure.