/*- * Public platform independent Near Field Communication (NFC) library * * Copyright (C) 2010, Romuald Conty * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published by the * Free Software Foundation, either version 3 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see */ /** * @file nfc-emulate-tag.c * @brief Emulate a simple tag */ // Note that depending on the device (initiator) you'll use against, this // emulator it might work or not. Some readers are very strict on responses // timings, e.g. a Nokia NFC and will drop communication too soon for us. #ifdef HAVE_CONFIG_H # include "config.h" #endif // HAVE_CONFIG_H #include #include #include #include #include #include #include #include #include "nfc-utils.h" #define MAX_FRAME_LEN 264 static byte_t abtRx[MAX_FRAME_LEN]; static size_t szRx; static nfc_device_t *pnd; static bool quiet_output = false; static bool init_mfc_auth = false; void intr_hdlr (void) { printf ("\nQuitting...\n"); if (pnd != NULL) { nfc_disconnect(pnd); } exit (EXIT_FAILURE); } bool target_io( const nfc_target_t nt, const byte_t * pbtInput, const size_t szInput, byte_t * pbtOutput, size_t *pszOutput ) { bool loop = true; *pszOutput = 0; // Show transmitted command if (!quiet_output) { printf (" In: "); print_hex (pbtInput, szInput); } if(szInput) { switch(pbtInput[0]) { case 0x60: // Mifare authA case 0x61: // Mifare authB // Let's give back a very random nonce... *pszOutput = 2; pbtOutput[0] = 0x12; pbtOutput[1] = 0x34; // Next commands will be without CRC init_mfc_auth = true; break; case 0xe0: // RATS // Send ATS *pszOutput = nt.nti.nai.szAtsLen + 1; pbtOutput[0] = nt.nti.nai.szAtsLen + 1; // ISO14443-4 says that ATS contains ATS_Lenght as first byte if(nt.nti.nai.szAtsLen) { memcpy(pbtOutput+1, nt.nti.nai.abtAts, nt.nti.nai.szAtsLen); } break; case 0xc2: // S-block DESELECT if (!quiet_output) { printf("Target released me. Bye!\n"); } loop = false; break; default: // Unknown if (!quiet_output) { printf("Unknown frame, emulated target abort.\n"); } loop = false; } } // Show transmitted command if ((!quiet_output) && *pszOutput) { printf (" Out: "); print_hex (pbtOutput, *pszOutput); } return loop; } bool nfc_target_emulate_tag(nfc_device_t* pnd, const nfc_target_t nt) { size_t szTx; byte_t abtTx[MAX_FRAME_LEN]; bool loop = true; if (!nfc_target_init (pnd, NTM_PASSIVE_ONLY, nt, abtRx, &szRx)) { nfc_perror (pnd, "nfc_target_init"); return false; } while ( loop ) { loop = target_io( nt, abtRx, szRx, abtTx, &szTx ); if (szTx) { if (!nfc_target_send_bytes(pnd, abtTx, szTx)) { nfc_perror (pnd, "nfc_target_send_bytes"); return false; } } if ( loop ) { if ( init_mfc_auth ) { nfc_configure (pnd, NDO_HANDLE_CRC, false); init_mfc_auth = false; } if (!nfc_target_receive_bytes(pnd, abtRx, &szRx)) { nfc_perror (pnd, "nfc_target_receive_bytes"); return false; } } } return true; } int main (int argc, char *argv[]) { const char *acLibnfcVersion; #ifdef WIN32 signal (SIGINT, (void (__cdecl *) (int)) intr_hdlr); #else signal (SIGINT, (void (*)()) intr_hdlr); #endif // Try to open the NFC reader pnd = nfc_connect (NULL); // Display libnfc version acLibnfcVersion = nfc_version (); printf ("%s use libnfc %s\n", argv[0], acLibnfcVersion); if (pnd == NULL) { ERR("Unable to connect to NFC device"); return EXIT_FAILURE; } printf ("Connected to NFC device: %s\n", pnd->acName); // Example of a Mifare Classic Mini // Note that crypto1 is not implemented in this example nfc_target_t nt = { .ptt = PTT_MIFARE, .nti.nai.abtAtqa = { 0x00, 0x04 }, .nti.nai.abtUid = { 0x08, 0xab, 0xcd, 0xef }, .nti.nai.btSak = 0x09, .nti.nai.szUidLen = 4, .nti.nai.szAtsLen = 0, }; /* // Example of a FeliCa nfc_target_t nt = { .ptt = PTT_FELICA_212, .nti.nfi.abtId = { 0x01, 0xFE, 0x56, 0x78, 0x9A, 0xBC, 0xDE, 0xFF }, .nti.nfi.abtPad = { 0x12, 0x34, 0x56, 0x78, 0x9A, 0xBC, 0xDE, 0xFF }, .nti.nfi.abtSysCode = { 0xFF, 0xFF }, }; */ /* // Example of a ISO14443-4 (DESfire) nfc_target_t nt = { .ptt = PTT_MIFARE, .nti.nai.abtAtqa = { 0x03, 0x44 }, .nti.nai.abtUid = { 0x08, 0xab, 0xcd, 0xef }, .nti.nai.btSak = 0x20, .nti.nai.szUidLen = 4, .nti.nai.abtAts = { 0x75, 0x77, 0x81, 0x02, 0x80 }, .nti.nai.szAtsLen = 5, }; */ printf ("%s will emulate this ISO14443-A tag:\n", argv[0]); print_nfc_iso14443a_info( nt.nti.nai ); printf ("NFC device (configured as target) is now emulating the tag, please touch it with a second NFC device (initiator)\n"); if (!nfc_target_emulate_tag (pnd, nt)) { nfc_perror (pnd, "nfc_target_emulate_tag"); return EXIT_FAILURE; } nfc_disconnect(pnd); exit (EXIT_SUCCESS); }