mirror of
https://github.com/RfidResearchGroup/proxmark3.git
synced 2025-08-19 13:00:42 -07:00
EM4x70 Authentication support
This commit is contained in:
parent
7b7698843f
commit
a6024a8622
7 changed files with 138 additions and 1 deletions
|
@ -1178,6 +1178,10 @@ static void PacketReceived(PacketCommandNG *packet) {
|
||||||
em4x70_unlock((em4x70_data_t *)packet->data.asBytes);
|
em4x70_unlock((em4x70_data_t *)packet->data.asBytes);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case CMD_LF_EM4X70_AUTH: {
|
||||||
|
em4x70_auth((em4x70_data_t *)packet->data.asBytes);
|
||||||
|
break;
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef WITH_ISO15693
|
#ifdef WITH_ISO15693
|
||||||
|
|
|
@ -360,6 +360,46 @@ static bool check_ack(void) {
|
||||||
return false;
|
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) {
|
static int send_pin(const uint32_t pin) {
|
||||||
|
|
||||||
// sends pin code for unlocking
|
// sends pin code for unlocking
|
||||||
|
@ -387,7 +427,7 @@ static int send_pin(const uint32_t pin) {
|
||||||
// <w> Writes Lock Bits
|
// <w> Writes Lock Bits
|
||||||
WaitTicks(TICKS_PER_FC * EM4X70_T_TAG_WEE);
|
WaitTicks(TICKS_PER_FC * EM4X70_T_TAG_WEE);
|
||||||
// <-- Receive header + ID
|
// <-- Receive header + ID
|
||||||
uint8_t tag_id[64];
|
uint8_t tag_id[EM4X70_MAX_RECEIVE_LENGTH];
|
||||||
int num = em4x70_receive(tag_id);
|
int num = em4x70_receive(tag_id);
|
||||||
if(num < 32) {
|
if(num < 32) {
|
||||||
Dbprintf("Invalid ID Received");
|
Dbprintf("Invalid ID Received");
|
||||||
|
@ -731,4 +771,25 @@ void em4x70_unlock(em4x70_data_t *etd) {
|
||||||
reply_ng(CMD_LF_EM4X70_UNLOCK, status, tag.data, sizeof(tag.data));
|
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));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -20,5 +20,6 @@ typedef struct {
|
||||||
void em4x70_info(em4x70_data_t *etd);
|
void em4x70_info(em4x70_data_t *etd);
|
||||||
void em4x70_write(em4x70_data_t *etd);
|
void em4x70_write(em4x70_data_t *etd);
|
||||||
void em4x70_unlock(em4x70_data_t *etd);
|
void em4x70_unlock(em4x70_data_t *etd);
|
||||||
|
void em4x70_auth(em4x70_data_t *etd);
|
||||||
|
|
||||||
#endif /* EM4x70_H */
|
#endif /* EM4x70_H */
|
||||||
|
|
|
@ -240,11 +240,76 @@ int CmdEM4x70Unlock(const char *Cmd) {
|
||||||
return PM3_ESOFT;
|
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 -r 11223344556677 -f 11223344\n"
|
||||||
|
);
|
||||||
|
|
||||||
|
void *argtable[] = {
|
||||||
|
arg_param_begin,
|
||||||
|
arg_lit0("x", "par", "Add parity bit when sending commands"),
|
||||||
|
arg_str1("r", "rnd", "<hex>", "Random 56-bit"),
|
||||||
|
arg_str1("f", "frn", "<hex>", "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[] = {
|
static command_t CommandTable[] = {
|
||||||
{"help", CmdHelp, AlwaysAvailable, "This help"},
|
{"help", CmdHelp, AlwaysAvailable, "This help"},
|
||||||
{"info", CmdEM4x70Info, IfPm3EM4x70, "Tag information EM4x70"},
|
{"info", CmdEM4x70Info, IfPm3EM4x70, "Tag information EM4x70"},
|
||||||
{"write", CmdEM4x70Write, IfPm3EM4x70, "Write EM4x70"},
|
{"write", CmdEM4x70Write, IfPm3EM4x70, "Write EM4x70"},
|
||||||
{"unlock", CmdEM4x70Unlock, IfPm3EM4x70, "Unlock EM4x70 for writing"},
|
{"unlock", CmdEM4x70Unlock, IfPm3EM4x70, "Unlock EM4x70 for writing"},
|
||||||
|
{"auth", CmdEM4x70Auth, IfPm3EM4x70, "Authenticate EM4x70"},
|
||||||
{NULL, NULL, NULL, NULL}
|
{NULL, NULL, NULL, NULL}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -20,6 +20,7 @@ int CmdLFEM4X70(const char *Cmd);
|
||||||
int CmdEM4x70Info(const char *Cmd);
|
int CmdEM4x70Info(const char *Cmd);
|
||||||
int CmdEM4x70Write(const char *Cmd);
|
int CmdEM4x70Write(const char *Cmd);
|
||||||
int CmdEM4x70Unlock(const char *Cmd);
|
int CmdEM4x70Unlock(const char *Cmd);
|
||||||
|
int CmdEM4x70Auth(const char *Cmd);
|
||||||
|
|
||||||
int em4x70_info(void);
|
int em4x70_info(void);
|
||||||
bool detect_4x70_block(void);
|
bool detect_4x70_block(void);
|
||||||
|
|
|
@ -23,6 +23,10 @@ typedef struct {
|
||||||
// PIN to unlock
|
// PIN to unlock
|
||||||
uint32_t pin;
|
uint32_t pin;
|
||||||
|
|
||||||
|
// Used for authentication
|
||||||
|
uint8_t rnd[7];
|
||||||
|
uint8_t frnd[4];
|
||||||
|
|
||||||
} em4x70_data_t;
|
} em4x70_data_t;
|
||||||
|
|
||||||
#endif /* EM4X70_H__ */
|
#endif /* EM4X70_H__ */
|
||||||
|
|
|
@ -519,6 +519,7 @@ typedef struct {
|
||||||
#define CMD_LF_EM4X70_INFO 0x0260
|
#define CMD_LF_EM4X70_INFO 0x0260
|
||||||
#define CMD_LF_EM4X70_WRITE 0x0261
|
#define CMD_LF_EM4X70_WRITE 0x0261
|
||||||
#define CMD_LF_EM4X70_UNLOCK 0x0262
|
#define CMD_LF_EM4X70_UNLOCK 0x0262
|
||||||
|
#define CMD_LF_EM4X70_AUTH 0x0263
|
||||||
// Sampling configuration for LF reader/sniffer
|
// Sampling configuration for LF reader/sniffer
|
||||||
#define CMD_LF_SAMPLING_SET_CONFIG 0x021D
|
#define CMD_LF_SAMPLING_SET_CONFIG 0x021D
|
||||||
#define CMD_LF_FSK_SIMULATE 0x021E
|
#define CMD_LF_FSK_SIMULATE 0x021E
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue