diff --git a/armsrc/appmain.c b/armsrc/appmain.c index e7d6fae8d..57c2f36c7 100644 --- a/armsrc/appmain.c +++ b/armsrc/appmain.c @@ -1178,6 +1178,10 @@ static void PacketReceived(PacketCommandNG *packet) { em4x70_unlock((em4x70_data_t *)packet->data.asBytes); break; } + case CMD_LF_EM4X70_AUTH: { + em4x70_auth((em4x70_data_t *)packet->data.asBytes); + break; + } #endif #ifdef WITH_ISO15693 diff --git a/armsrc/em4x70.c b/armsrc/em4x70.c index a1f04ed6d..0bb18e7d2 100644 --- a/armsrc/em4x70.c +++ b/armsrc/em4x70.c @@ -360,6 +360,46 @@ static bool check_ack(void) { return false; } +static int authenticate(const uint8_t *rnd, const uint8_t *frnd, uint8_t *response) { + + if (find_listen_window(true)) { + + em4x70_send_nibble(EM4X70_COMMAND_AUTH, true); + + // Send 56-bit Random number + for (int i = 0; i < 7; i++) { + em4x70_send_byte(rnd[i]); + } + + // Send 7 x 0's (Diversity bits) + for (int i = 0; i < 7; i++) { + em4x70_send_bit(0); + } + + // Send 28-bit f(RN) + + // Send first 24 bits + for (int i = 0; i < 3; i++) { + em4x70_send_byte(frnd[i]); + } + + // Send last 4 bits (no parity) + em4x70_send_nibble((frnd[3] >> 4) & 0xf, false); + + // Receive header, 20-bit g(RN), LIW + uint8_t grnd[EM4X70_MAX_RECEIVE_LENGTH] = {0}; + int num = em4x70_receive(grnd); + if (num < 10) { + Dbprintf("Auth failed"); + return PM3_ESOFT; + } + bits2bytes(grnd, 24, response); + return PM3_SUCCESS; + } + + return PM3_ESOFT; +} + static int send_pin(const uint32_t pin) { // sends pin code for unlocking @@ -387,7 +427,7 @@ static int send_pin(const uint32_t pin) { // Writes Lock Bits WaitTicks(TICKS_PER_FC * EM4X70_T_TAG_WEE); // <-- Receive header + ID - uint8_t tag_id[64]; + uint8_t tag_id[EM4X70_MAX_RECEIVE_LENGTH]; int num = em4x70_receive(tag_id); if (num < 32) { Dbprintf("Invalid ID Received"); @@ -730,4 +770,25 @@ void em4x70_unlock(em4x70_data_t *etd) { reply_ng(CMD_LF_EM4X70_UNLOCK, status, tag.data, sizeof(tag.data)); } +void em4x70_auth(em4x70_data_t *etd) { + + uint8_t status = 0; + uint8_t response[3] = {0}; + + command_parity = etd->parity; + + init_tag(); + EM4170_setup_read(); + + // Find the Tag + if (get_signalproperties() && find_EM4X70_Tag()) { + + // Authenticate and get tag response + status = authenticate(etd->rnd, etd->frnd, response) == PM3_SUCCESS; + } + + StopTicks(); + lf_finalize(); + reply_ng(CMD_LF_EM4X70_AUTH, status, response, sizeof(response)); +} diff --git a/armsrc/em4x70.h b/armsrc/em4x70.h index 2d9f077f8..17ac243ae 100644 --- a/armsrc/em4x70.h +++ b/armsrc/em4x70.h @@ -20,5 +20,6 @@ typedef struct { void em4x70_info(em4x70_data_t *etd); void em4x70_write(em4x70_data_t *etd); void em4x70_unlock(em4x70_data_t *etd); +void em4x70_auth(em4x70_data_t *etd); #endif /* EM4x70_H */ diff --git a/client/src/cmdlfem4x70.c b/client/src/cmdlfem4x70.c index 4db2aa650..a13d29073 100644 --- a/client/src/cmdlfem4x70.c +++ b/client/src/cmdlfem4x70.c @@ -240,11 +240,76 @@ int CmdEM4x70Unlock(const char *Cmd) { return PM3_ESOFT; } +int CmdEM4x70Auth(const char *Cmd) { + + // Authenticate transponder + // Send 56-bit random number + pre-computed f(rnd, k) to transponder. + // Transponder will respond with a response + em4x70_data_t etd = {0}; + + CLIParserContext *ctx; + + CLIParserInit(&ctx, "lf em 4x70 auth", + "Authenticate against an EM4x70 by sending random number (RN) and F(RN)\n" + " If F(RN) is incorrect based on the tag crypt key, the tag will not respond", + "lf em 4x70 auth --rnd 11223344556677 --frn 11223344\n" + ); + + void *argtable[] = { + arg_param_begin, + arg_lit0(NULL, "par", "Add parity bit when sending commands"), + arg_str1(NULL, "rnd", "", "Random 56-bit"), + arg_str1(NULL, "frn", "", "F(RN) 28-bit as 4 hex bytes"), + arg_param_end + }; + + CLIExecWithReturn(ctx, Cmd, argtable, true); + + etd.parity = arg_get_lit(ctx, 1); + + int rnd_len = 7; + CLIGetHexWithReturn(ctx, 2, etd.rnd, &rnd_len); + + int frnd_len = 4; + CLIGetHexWithReturn(ctx, 3, etd.frnd, &frnd_len); + + CLIParserFree(ctx); + + if (rnd_len != 7) { + PrintAndLogEx(FAILED, "Random number length must be 7 bytes instead of %d", rnd_len); + return PM3_EINVARG; + } + + if (frnd_len != 4) { + PrintAndLogEx(FAILED, "F(RN) length must be 4 bytes instead of %d", frnd_len); + return PM3_EINVARG; + } + + clearCommandBuffer(); + SendCommandNG(CMD_LF_EM4X70_AUTH, (uint8_t *)&etd, sizeof(etd)); + + PacketResponseNG resp; + if (!WaitForResponseTimeout(CMD_LF_EM4X70_AUTH, &resp, TIMEOUT)) { + PrintAndLogEx(WARNING, "Timeout while waiting for reply."); + return PM3_ETIMEOUT; + } + + if (resp.status) { + // Response is 20-bit from tag + PrintAndLogEx(INFO, "Tag Auth Response: %02X %02X %02X", resp.data.asBytes[2], resp.data.asBytes[1], resp.data.asBytes[0]); + return PM3_SUCCESS; + } + + PrintAndLogEx(FAILED, "TAG Authentication " _RED_("Failed")); + return PM3_ESOFT; +} + static command_t CommandTable[] = { {"help", CmdHelp, AlwaysAvailable, "This help"}, {"info", CmdEM4x70Info, IfPm3EM4x70, "Tag information EM4x70"}, {"write", CmdEM4x70Write, IfPm3EM4x70, "Write EM4x70"}, {"unlock", CmdEM4x70Unlock, IfPm3EM4x70, "Unlock EM4x70 for writing"}, + {"auth", CmdEM4x70Auth, IfPm3EM4x70, "Authenticate EM4x70"}, {NULL, NULL, NULL, NULL} }; diff --git a/client/src/cmdlfem4x70.h b/client/src/cmdlfem4x70.h index 3f7930673..755ff74d2 100644 --- a/client/src/cmdlfem4x70.h +++ b/client/src/cmdlfem4x70.h @@ -20,6 +20,7 @@ int CmdLFEM4X70(const char *Cmd); int CmdEM4x70Info(const char *Cmd); int CmdEM4x70Write(const char *Cmd); int CmdEM4x70Unlock(const char *Cmd); +int CmdEM4x70Auth(const char *Cmd); int em4x70_info(void); bool detect_4x70_block(void); diff --git a/include/em4x70.h b/include/em4x70.h index a9d94403d..0703c3900 100644 --- a/include/em4x70.h +++ b/include/em4x70.h @@ -23,6 +23,10 @@ typedef struct { // PIN to unlock uint32_t pin; + // Used for authentication + uint8_t rnd[7]; + uint8_t frnd[4]; + } em4x70_data_t; #endif /* EM4X70_H__ */ diff --git a/include/pm3_cmd.h b/include/pm3_cmd.h index f5585f192..95ef41ebb 100644 --- a/include/pm3_cmd.h +++ b/include/pm3_cmd.h @@ -519,6 +519,7 @@ typedef struct { #define CMD_LF_EM4X70_INFO 0x0260 #define CMD_LF_EM4X70_WRITE 0x0261 #define CMD_LF_EM4X70_UNLOCK 0x0262 +#define CMD_LF_EM4X70_AUTH 0x0263 // Sampling configuration for LF reader/sniffer #define CMD_LF_SAMPLING_SET_CONFIG 0x021D #define CMD_LF_FSK_SIMULATE 0x021E