diff --git a/CHANGELOG.md b/CHANGELOG.md index 50ee0d9c9..69807b05c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,7 @@ All notable changes to this project will be documented in this file. This project uses the changelog in accordance with [keepchangelog](http://keepachangelog.com/). Please use this to write notable changes, which is not the same as git commit log... ## [unreleased][unreleased] + - Added `lf hitag view` - now supports viewing of dump files (@iceman1001) - Changed `lf hitag dump --ns` - now support nosave flag (@iceman1001) - Added `hf xerox rdbl` - read block of a Fuji/Xerox tag (@iceman1001) - Added a xerox trace file, thanks @jeroenSteen, (@iceman1001) @@ -20,8 +21,8 @@ This project uses the changelog in accordance with [keepchangelog](http://keepac - Changed `hw readmem` to allow larger reads, write to file and better hex viewer (@martian01010) - Added `CMD_READ_MEM_DOWNLOAD` and `CMD_READ_MEM_DOWNLOADED` to osimage and bootloader (@martian01010) - Changed `hf mfu info` - now correctly identifies NTAG I2C tags (@icemann1001) - - Changed `hf 14b dump/view` - now supports `z` flag for dense output (@iceman1001) - - Changed `hf xerox dump/view` - now supports `z` flag for dense output (@iceman1001) + - Changed `hf 14b dump/view` - now supports `-z` flag for dense output (@iceman1001) + - Changed `hf xerox dump/view` - now supports `-z` flag for dense output (@iceman1001) - Changed `hf mfu dump/view/eview` - now supports `-z` flag for dense output (@iceman1001) - Added `data crypto` to encrypt and decrypt data in the proxmark client using built-in methods (@team-orangeBlue) - Changed `hf tune` and `lf tune` - Added an option to show statistical data after tuning (@wh201906) @@ -44,9 +45,9 @@ This project uses the changelog in accordance with [keepchangelog](http://keepac - Changed `hf 15 findafi` - improved the params (@iceman1001) - Changed `hf 15 rdbl/rdmulti/dump` - should handle 4 vs 8 bytes block sizes in cards (@iceman1001) - Changed `hf 15 *` - all 15 commands now uses NG packets (@iceman1001) - - Changed `hf 15 raw` - now supports "-k" keep field on and "-s" select (@iceman1001) + - Changed `hf 15 raw` - now supports `-k` keep field on and `-s` select (@iceman1001) - Changed `prefs set client.debug` - now also toggles the client side APDU logging (@iceman1001) - - Changed `hf 14b sriwrbl` - now supports --force to override block checks. Thanks @gentilkiwi for the idea! (@iceman1001) + - Changed `hf 14b sriwrbl` - now supports `--force` to override block checks. Thanks @gentilkiwi for the idea! (@iceman1001) - Changed `hf 14b sriwrbl` - now tries to verify the write (@iceman1001) - Changed `hf 14b apdu` - now supports tearoff (@iceman1001) - Fixed `hf 14b raw` - fixed a potential write out of bounds. (@iceman1001) diff --git a/client/src/cmdlfhitag.c b/client/src/cmdlfhitag.c index 45206750f..c93886014 100644 --- a/client/src/cmdlfhitag.c +++ b/client/src/cmdlfhitag.c @@ -332,8 +332,7 @@ static int CmdLFHitagSim(const char *Cmd) { return PM3_SUCCESS; } - -static void printHitag2PaxtonDowngrade(const uint8_t *data) { +static void print_hitag2_paxton(const uint8_t *data) { uint64_t bytes = 0; uint64_t num = 0; @@ -359,116 +358,150 @@ static void printHitag2PaxtonDowngrade(const uint8_t *data) { } } - PrintAndLogEx(INFO, "-------- " _CYAN_("Possible de-scramble patterns") " ---------"); - PrintAndLogEx(SUCCESS, "Paxton id: %lu | 0x%lx", paxton_id, paxton_id); + PrintAndLogEx(INFO, ""); + PrintAndLogEx(INFO, "--- " _CYAN_("Possible de-scramble patterns") " -------------"); + PrintAndLogEx(SUCCESS, "Paxton id... %" PRIu64 " | 0x%" PRIx64, paxton_id, paxton_id); } -static void printHitag2Configuration(uint8_t config) { +static void print_hitag2_configuration(uint32_t uid, uint8_t config) { + + PrintAndLogEx(NORMAL, ""); + PrintAndLogEx(INFO, "--- " _CYAN_("Tag Information") " ---------------------------"); + PrintAndLogEx(SUCCESS, "UID.... " _GREEN_("%08X"), uid); + PrintAndLogEx(SUCCESS, "TYPE... " _GREEN_("%s"), getHitagTypeStr(uid)); char msg[100]; memset(msg, 0, sizeof(msg)); - char bits[9]; - char *bs = bits; - for (uint8_t i = 0 ; i < 8 ; i++) { - snprintf(bs, sizeof(bits) - i, "%1d", (config >> (7 - i)) & 1); - bs++; - } - - PrintAndLogEx(INFO, "\n\nHitag2 tag information "); - PrintAndLogEx(INFO, "------------------------------------"); - + uint8_t bits[8 + 1] = {0}; + num_to_bytebits(config, 8, bits); + const char *bs = sprint_bytebits_bin(bits, 8); + //configuration byte - PrintAndLogEx(SUCCESS, "Config byte : 0x%02X [ %s ]", config, bits); + PrintAndLogEx(SUCCESS, ""); + PrintAndLogEx(SUCCESS, "Config byte... 0x%02X", config); + PrintAndLogEx(SUCCESS, " %s", bs); - // encoding - strcat(msg, "Encoding : "); - if (config & 0x1) { - strcat(msg + strlen(msg), _YELLOW_("Biphase")); - } else { - strcat(msg + strlen(msg), _YELLOW_("Manchester")); + + PrintAndLogEx(SUCCESS, " %s", sprint_breakdown_bin(C_NONE, bs, 8, 0, 4, "RFU")); + + if (config & 0x8) { + PrintAndLogEx(SUCCESS, " %s", sprint_breakdown_bin(C_YELLOW, bs, 8, 4, 1, "Crypto mode")); + } else { + PrintAndLogEx(SUCCESS, " %s", sprint_breakdown_bin(C_NONE, bs, 8, 4, 1, "Password mode")); } - PrintAndLogEx(SUCCESS, "%s", msg); - memset(msg, 0, sizeof(msg)); // version - strcat(msg, "Coding in HITAG 2 operation: %s"); - uint8_t foo = (config & 0x6) >> 1; + uint8_t foo = ((config & 0x6) >> 1); switch (foo) { case 0: - PrintAndLogEx(SUCCESS, "Version : public mode B, Coding: biphase"); - PrintAndLogEx(SUCCESS, msg, (config & 0x1) ? "biphase" : "manchester"); + PrintAndLogEx(SUCCESS, " %s", sprint_breakdown_bin(C_NONE, bs, 8, 5, 2, "Public mode B, Coding: biphase")); break; case 1: - PrintAndLogEx(SUCCESS, "Version : public mode A, Coding: manchester"); - PrintAndLogEx(SUCCESS, msg, (config & 0x1) ? "biphase" : "manchester"); + PrintAndLogEx(SUCCESS, " %s", sprint_breakdown_bin(C_NONE, bs, 8, 5, 2, "Public mode A, Coding: manchester")); break; case 2: - PrintAndLogEx(SUCCESS, "Version : public mode C, Coding: biphase"); - PrintAndLogEx(SUCCESS, msg, (config & 0x1) ? "biphase" : "manchester"); + PrintAndLogEx(SUCCESS, " %s", sprint_breakdown_bin(C_NONE, bs, 8, 5, 2, "Public mode C, Coding: biphase")); break; case 3: - PrintAndLogEx(SUCCESS, "Version : Hitag2"); - PrintAndLogEx(SUCCESS, msg, (config & 0x1) ? "biphase" : "manchester"); + PrintAndLogEx(SUCCESS, " %s", sprint_breakdown_bin(C_NONE, bs, 8, 5, 2, "Hitag2")); break; } - memset(msg, 0, sizeof(msg)); - // mode - strcat(msg, "Tag is in : "); - if (config & 0x8) { - strcat(msg + strlen(msg), _YELLOW_("Crypto mode")); - } else { - strcat(msg + strlen(msg), _YELLOW_("Password mode")); + // encoding + if (config & 0x01) { + PrintAndLogEx(SUCCESS, " %s", sprint_breakdown_bin(C_NONE, bs, 8, 7, 1, "Biphase")); + } else { + PrintAndLogEx(SUCCESS, " %s", sprint_breakdown_bin(C_NONE, bs, 8, 7, 1, "Manchester")); } - PrintAndLogEx(SUCCESS, "%s", msg); - memset(msg, 0, sizeof(msg)); - // page access - strcat(msg, "Page 6,7 : "); - if (config & 0x10) { - strcat(msg + strlen(msg), "read only"); - } else { - strcat(msg + strlen(msg), _GREEN_("RW")); - } - PrintAndLogEx(SUCCESS, "%s", msg); - memset(msg, 0, sizeof(msg)); +} - // page access - strcat(msg, "Page 4,5 : "); - if (config & 0x20) { - strcat(msg + strlen(msg), "read only"); - } else { - strcat(msg + strlen(msg), _GREEN_("RW")); - } - PrintAndLogEx(SUCCESS, "%s", msg); - memset(msg, 0, sizeof(msg)); +const char* annotation[] = { + "UID", "Pwd", "Key/Pwd", "Config", + "User", "User", "User", "User", + "User", "User", "User", "User" +}; - // OTP - strcat(msg, "Page 3 : "); - if (config & 0x40) { - strcat(msg + strlen(msg), "read only. Configuration byte and password tag " _RED_("FIXED / IRREVERSIBLE")); - } else { - strcat(msg + strlen(msg), _GREEN_("RW")); - } - PrintAndLogEx(SUCCESS, "%s", msg); - memset(msg, 0, sizeof(msg)); +static void print_hitag2_blocks(uint8_t *d, uint16_t n) { - // OTP - if (config & 0x80) { - strcat(msg, "Page 1 : " _RED_("locked") "\n"); + PrintAndLogEx(INFO, ""); + PrintAndLogEx(INFO, "-----------------------------------------------"); + PrintAndLogEx(INFO, "block# | data | ascii | lck | Info"); + PrintAndLogEx(INFO, "---------+-------------+-------+-----+---------"); - strcat(msg + strlen(msg), "Page 2 : "); - if (config & 0x8) { - strcat(msg + strlen(msg), _RED_("locked")); - } else { - strcat(msg + strlen(msg), "read only"); + uint8_t config = d[HITAG2_CONFIG_OFFSET]; + uint8_t blocks = (n / HITAG_BLOCK_SIZE); + + for (uint8_t i = 0; i < blocks; ++i) { + + char lckstr[20] = {0}; + sprintf(lckstr, " "); + + switch (i) { + case 0: + sprintf(lckstr, "%s", _RED_("L ")); + break; + case 1: + if (config & 0x80) { + sprintf(lckstr, "%s", _RED_("L ")); + } else { + sprintf(lckstr, "%s", _GREEN_("RW")); + } + break; + case 2: + if (config & 0x80) { + if (config & 0x8) { + sprintf(lckstr, "%s", _RED_("L ")); + } else { + sprintf(lckstr, "%s", _RED_("R ")); + } + } else { + sprintf(lckstr, "%s", _GREEN_("RW")); + } + break; + case 3: + // OTP Page 3. + if (config & 0x40) { + sprintf(lckstr, "%s", _RED_("R ")); + //. Configuration byte and password tag " _RED_("FIXED / IRREVERSIBLE")); + } else { + sprintf(lckstr, "%s", _GREEN_("RW")); + } + break; + case 4: + case 5: + if (config & 0x20) { + sprintf(lckstr, "%s", _RED_("R ")); + } else { + sprintf(lckstr, "%s", _GREEN_("RW")); + } + break; + case 6: + case 7: + if (config & 0x10) { + sprintf(lckstr, "%s", _RED_("R ")); + } else { + sprintf(lckstr, "%s", _GREEN_("RW")); + } + break; + default: + break; } - } else { - strcat(msg, "Page 1,2 : " _GREEN_("RW")); + + PrintAndLogEx(INFO, "%3d/0x%02X | %s| %s | %s | %s" + , i + , i + , sprint_hex(d + (i * HITAG_BLOCK_SIZE), HITAG_BLOCK_SIZE) + , sprint_ascii(d + (i * HITAG_BLOCK_SIZE), HITAG_BLOCK_SIZE) + , lckstr + , annotation[i] + ); } - PrintAndLogEx(SUCCESS, "%s", msg); - PrintAndLogEx(INFO, "------------------------------------"); + PrintAndLogEx(INFO, "---------+-------------+-------+-----+---------"); + PrintAndLogEx(INFO, " L = Locked, "_GREEN_("RW") " = Read Write, R = Read Only"); + PrintAndLogEx(INFO, " FI = Fixed / Irreversible"); + PrintAndLogEx(INFO, "-----------------------------------------------"); } static bool getHitag2Uid(uint32_t *uid) { @@ -477,7 +510,7 @@ static bool getHitag2Uid(uint32_t *uid) { clearCommandBuffer(); SendCommandMIX(CMD_LF_HITAG_READER, RHT2F_UID_ONLY, 0, 0, &htd, sizeof(htd)); PacketResponseNG resp; - if (!WaitForResponseTimeout(CMD_ACK, &resp, 2500)) { + if (WaitForResponseTimeout(CMD_ACK, &resp, 2500) == false) { PrintAndLogEx(WARNING, "timeout while waiting for reply."); return false; } @@ -487,8 +520,9 @@ static bool getHitag2Uid(uint32_t *uid) { return false; } - if (uid) - *uid = bytes_to_num(resp.data.asBytes, 4); + if (uid) { + *uid = bytes_to_num(resp.data.asBytes, HITAG_UID_SIZE); + } return true; } @@ -509,24 +543,18 @@ static int CmdLFHitagInfo(const char *Cmd) { // read UID uint32_t uid = 0; - if (getHitag2Uid(&uid) == false) + if (getHitag2Uid(&uid) == false) { return PM3_ESOFT; - - PrintAndLogEx(NORMAL, ""); - PrintAndLogEx(INFO, "--- " _CYAN_("Tag Information") " ---------------------------"); - PrintAndLogEx(SUCCESS, " UID: " _GREEN_("%08X"), uid); - PrintAndLogEx(SUCCESS, " TYPE: " _GREEN_("%s"), getHitagTypeStr(uid)); - + } // how to determine Hitag types? // read block3, get configuration byte. // common configurations. - // printHitag2Configuration(0x06); - //printHitag2Configuration( 0x0E ); - //printHitag2Configuration( 0x02 ); - //printHitag2Configuration( 0x00 ); - //printHitag2Configuration( 0x04 ); - PrintAndLogEx(INFO, "-------------------------------------------------------------"); + print_hitag2_configuration( uid, 0x06 ); + // print_hitag2_configuration( uid, 0x0E ); + // print_hitag2_configuration( uid, 0x02 ); + // print_hitag2_configuration( uid, 0x00 ); + // print_hitag2_configuration( uid, 0x04 ); return PM3_SUCCESS; } @@ -700,12 +728,11 @@ static int CmdLFHitagReader(const char *Cmd) { return PM3_ESOFT; } - uint32_t id = bytes_to_num(resp.data.asBytes, 4); uint8_t *data = resp.data.asBytes; - PrintAndLogEx(SUCCESS, " UID: " _YELLOW_("%08x"), id); - printHitag2Configuration(data[4 * 3]); - print_hex_break(data, 48, 4); - printHitag2PaxtonDowngrade(data); + uint32_t uid = bytes_to_num(data, HITAG_UID_SIZE); + print_hitag2_configuration(uid, data[HITAG_BLOCK_SIZE * 3]); + print_hex_break(data, HITAG2_MAX_BYTE_SIZE, HITAG_BLOCK_SIZE); + print_hitag2_paxton(data); return PM3_SUCCESS; } @@ -773,7 +800,6 @@ static int CmdLFHitag2CheckChallenges(const char *Cmd) { return PM3_SUCCESS; } - static int CmdLFHitagWriter(const char *Cmd) { CLIParserContext *ctx; CLIParserInit(&ctx, "lf hitag wrbl", @@ -985,6 +1011,7 @@ static int CmdLFHitag2Dump(const char *Cmd) { arg_lit0(NULL, "crypto", "crypto mode"), arg_str0("k", "key", "", "key, 4 or 6 hex bytes"), arg_str0("f", "file", "", "specify file name"), + arg_lit0(NULL, "ns", "no save to file"), arg_param_end }; CLIExecWithReturn(ctx, Cmd, argtable, false); @@ -1006,7 +1033,7 @@ static int CmdLFHitag2Dump(const char *Cmd) { bool use_nrar = nalen > 0; bool use_crypto = arg_get_lit(ctx, 3); - uint8_t key[6]; + uint8_t key[HITAG_CRYPTOKEY_SIZE]; int keylen = 0; res = CLIParamHexToBuf(arg_get_str(ctx, 4), key, sizeof(key), &keylen); if (res != 0) { @@ -1018,6 +1045,7 @@ static int CmdLFHitag2Dump(const char *Cmd) { char filename[FILE_PATH_SIZE] = {0}; CLIParamStrToBuf(arg_get_str(ctx, 5), (uint8_t *)filename, FILE_PATH_SIZE, &fnlen); + bool nosave = arg_get_lit(ctx, 6); CLIParserFree(ctx); // sanity checks @@ -1036,19 +1064,21 @@ static int CmdLFHitag2Dump(const char *Cmd) { } // complete options - if (keylen == 4) { + if (keylen == HITAG_PASSWORD_SIZE) { use_pwd = true; } - if (keylen == 6) { + if (keylen == HITAG_CRYPTOKEY_SIZE) { use_crypto = true; } + + // Set default key / pwd if ((keylen == 0) && use_pwd) { - memcpy(key, "MIKR", 4); - keylen = 4; + memcpy(key, "MIKR", HITAG_PASSWORD_SIZE); + keylen = HITAG_PASSWORD_SIZE; } if ((keylen == 0) && use_crypto) { - memcpy(key, "ONMIKR", 6); - keylen = 6; + memcpy(key, "ONMIKR", HITAG_CRYPTOKEY_SIZE); + keylen = HITAG_CRYPTOKEY_SIZE; } // check coherence @@ -1081,11 +1111,11 @@ static int CmdLFHitag2Dump(const char *Cmd) { if (use_ht2 && use_pwd) { htf = RHT2F_PASSWORD; memcpy(htd.pwd.password, key, sizeof(htd.pwd.password)); - PrintAndLogEx(INFO, "Authenticating to Hitag 2 in Password mode"); + PrintAndLogEx(INFO, "Authenticating to Hitag2 in Password mode"); } else if (use_ht2 && use_crypto) { htf = RHT2F_CRYPTO; memcpy(htd.crypto.key, key, sizeof(htd.crypto.key)); - PrintAndLogEx(INFO, "Authenticating to Hitag 2 in Crypto mode"); + PrintAndLogEx(INFO, "Authenticating to Hitag2 in Crypto mode"); } else { PrintAndLogEx(WARNING, "Sorry, not yet implemented"); return PM3_ENOTIMPL; @@ -1103,34 +1133,77 @@ static int CmdLFHitag2Dump(const char *Cmd) { PrintAndLogEx(DEBUG, "DEBUG: Error - hitag failed"); return PM3_ESOFT; } + uint8_t *data = resp.data.asBytes; - if (data == NULL) - return PM3_ESOFT; + // block3, 1 byte + uint32_t uid = bytes_to_num(data, HITAG_UID_SIZE); + print_hitag2_configuration(uid, data[HITAG_BLOCK_SIZE * 3]); + print_hitag2_blocks(data, HITAG2_MAX_BYTE_SIZE); + print_hitag2_paxton(data); - uint32_t id = bytes_to_num(resp.data.asBytes, 4); - PrintAndLogEx(SUCCESS, " UID: " _YELLOW_("%08x"), id); + if (nosave) { + PrintAndLogEx(NORMAL, ""); + PrintAndLogEx(INFO, "Called with no save option"); + PrintAndLogEx(NORMAL, ""); + return PM3_SUCCESS; + } if (fnlen < 1) { char *fptr = filename; fptr += snprintf(filename, sizeof(filename), "lf-hitag-"); - FillFileNameByUID(fptr, data, "-dump", 4); + FillFileNameByUID(fptr, data, "-dump", HITAG_UID_SIZE); } - // block3, 1 byte - printHitag2Configuration(data[4 * 3]); - - // print data - print_hex_break(data, 48, 4); - - printHitag2PaxtonDowngrade(data); - - PrintAndLogEx(SUCCESS, "Dumping tag memory..."); - - pm3_save_dump(filename, data, 48, jsfHitag); + pm3_save_dump(filename, data, HITAG2_MAX_BYTE_SIZE, jsfHitag); return PM3_SUCCESS; } +static int CmdLFHitagView(const char *Cmd) { + + CLIParserContext *ctx; + CLIParserInit(&ctx, "lf hitag view", + "Print a HITAG dump file (bin/eml/json)", + "lf hitag view -f lf-hitag-01020304-dump.bin" + ); + void *argtable[] = { + arg_param_begin, + arg_str1("f", "file", "", "Specify a filename for dump file"), + arg_lit0("v", "verbose", "Verbose output"), + arg_param_end + }; + CLIExecWithReturn(ctx, Cmd, argtable, false); + int fnlen = 0; + char filename[FILE_PATH_SIZE]; + CLIParamStrToBuf(arg_get_str(ctx, 1), (uint8_t *)filename, FILE_PATH_SIZE, &fnlen); + bool verbose = arg_get_lit(ctx, 2); + CLIParserFree(ctx); + + // read dump file + uint8_t *dump = NULL; + size_t bytes_read = 0; + int res = pm3_load_dump(filename, (void **)&dump, &bytes_read, HITAG2_MAX_BYTE_SIZE); + if (res != PM3_SUCCESS) { + return res; + } + + if (bytes_read < HITAG2_MAX_BYTE_SIZE) { + PrintAndLogEx(ERR, "Error, dump file is too small"); + free(dump); + return PM3_ESOFT; + } + + if (verbose) { + // block3, 1 byte + uint8_t config = dump[HITAG_BLOCK_SIZE * 3]; + uint32_t uid = bytes_to_num(dump, HITAG_UID_SIZE); + print_hitag2_configuration(uid, config); + print_hitag2_paxton(dump); + } + print_hitag2_blocks(dump, HITAG2_MAX_BYTE_SIZE); + free(dump); + return PM3_SUCCESS; +} // Annotate HITAG protocol void annotateHitag1(char *exp, size_t size, const uint8_t *cmd, uint8_t cmdsize, bool is_response) { @@ -1197,6 +1270,7 @@ static command_t CommandTable[] = { {"info", CmdLFHitagInfo, IfPm3Hitag, "Hitag 2 tag information"}, {"dump", CmdLFHitag2Dump, IfPm3Hitag, "Dump Hitag 2 tag"}, {"read", CmdLFHitagReader, IfPm3Hitag, "Read Hitag memory"}, + {"view", CmdLFHitagView, AlwaysAvailable, "Display content from tag dump file"}, {"wrbl", CmdLFHitagWriter, IfPm3Hitag, "Write a block (page) in Hitag memory"}, {"sniff", CmdLFHitagSniff, IfPm3Hitag, "Eavesdrop Hitag communication"}, {"cc", CmdLFHitagSCheckChallenges, IfPm3Hitag, "Hitag S: test all provided challenges"}, @@ -1223,6 +1297,8 @@ int readHitagUid(void) { } uint8_t hitag1_CRC_check(uint8_t *d, uint32_t nbit) { - if (nbit < 9) return 2; + if (nbit < 9) { + return 2; + } return (CRC8Hitag1Bits(d, nbit) == 0); } diff --git a/client/src/cmdlfhitag.h b/client/src/cmdlfhitag.h index cb5b1ce0b..3605bce40 100644 --- a/client/src/cmdlfhitag.h +++ b/client/src/cmdlfhitag.h @@ -21,6 +21,20 @@ #include "common.h" + +#define HITAG_CRYPTOKEY_SIZE 6 +#define HITAG_PASSWORD_SIZE 4 +#define HITAG_UID_SIZE 4 +#define HITAG_BLOCK_SIZE 4 +#define HITAG2_MAX_BYTE_SIZE 48 +// need to see which limits these cards has +#define HITAG1_MAX_BYTE_SIZE 64 +#define HITAGS_MAX_BYTE_SIZE 64 +#define HITAGU_MAX_BYTE_SIZE 64 + +#define HITAG2_CONFIG_BLOCK 3 +#define HITAG2_CONFIG_OFFSET (HITAG_BLOCK_SIZE * HITAG2_CONFIG_BLOCK) + int CmdLFHitag(const char *Cmd); int readHitagUid(void);