From 60f36b468de51834bf8bda79fabb1ab1be17939c Mon Sep 17 00:00:00 2001 From: Christian Molson Date: Tue, 15 Dec 2020 12:32:30 -0500 Subject: [PATCH] em4x70: Add write key convenience function. Use real values in writekey/auth help text so people with blank tags can program a test key and test authentication. --- armsrc/appmain.c | 4 +++ armsrc/em4x70.c | 38 +++++++++++++++++++++++++++ armsrc/em4x70.h | 1 + client/src/cmdlfem4x70.c | 55 ++++++++++++++++++++++++++++++++++++++-- client/src/cmdlfem4x70.h | 1 + include/em4x70.h | 3 +++ include/pm3_cmd.h | 1 + 7 files changed, 101 insertions(+), 2 deletions(-) diff --git a/armsrc/appmain.c b/armsrc/appmain.c index af6e6c956..fe8566363 100644 --- a/armsrc/appmain.c +++ b/armsrc/appmain.c @@ -1186,6 +1186,10 @@ static void PacketReceived(PacketCommandNG *packet) { em4x70_write_pin((em4x70_data_t *)packet->data.asBytes); break; } + case CMD_LF_EM4X70_WRITEKEY: { + em4x70_write_key((em4x70_data_t *)packet->data.asBytes); + break; + } #endif #ifdef WITH_ISO15693 diff --git a/armsrc/em4x70.c b/armsrc/em4x70.c index 758b6e08e..1a6f37d56 100644 --- a/armsrc/em4x70.c +++ b/armsrc/em4x70.c @@ -768,3 +768,41 @@ void em4x70_write_pin(em4x70_data_t *etd) { lf_finalize(); reply_ng(CMD_LF_EM4X70_WRITEPIN, status, tag.data, sizeof(tag.data)); } + +void em4x70_write_key(em4x70_data_t *etd) { + + uint8_t status = 0; + + command_parity = etd->parity; + + init_tag(); + em4x70_setup_read(); + + // Find the Tag + if (get_signalproperties() && find_em4x70_tag()) { + + // Read ID to ensure we can write to card + if (em4x70_read_id()) { + status = 1; + + // Write each crypto block + for(int i = 0; i < 6; i++) { + + uint16_t key_word = (etd->crypt_key[(i*2)+1] << 8) + etd->crypt_key[i*2]; + // Write each word, abort if any failure occurs + if (write(key_word, 9-i) != PM3_SUCCESS) { + status = 0; + break; + } + } + // TODO: Ideally here we would perform a test authentication + // to ensure the new key was written correctly. This is + // what the datasheet suggests. We can't do that until + // we have the crypto algorithm implemented. + } + } + + StopTicks(); + lf_finalize(); + reply_ng(CMD_LF_EM4X70_WRITEKEY, status, tag.data, sizeof(tag.data)); +} diff --git a/armsrc/em4x70.h b/armsrc/em4x70.h index 41bfe824d..abebe0e8b 100644 --- a/armsrc/em4x70.h +++ b/armsrc/em4x70.h @@ -27,5 +27,6 @@ void em4x70_write(em4x70_data_t *etd); void em4x70_unlock(em4x70_data_t *etd); void em4x70_auth(em4x70_data_t *etd); void em4x70_write_pin(em4x70_data_t *etd); +void em4x70_write_key(em4x70_data_t *etd); #endif /* EM4x70_H */ diff --git a/client/src/cmdlfem4x70.c b/client/src/cmdlfem4x70.c index b2ccb3a0e..032daf4b2 100644 --- a/client/src/cmdlfem4x70.c +++ b/client/src/cmdlfem4x70.c @@ -286,7 +286,7 @@ int CmdEM4x70Auth(const char *Cmd) { 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" + "lf em 4x70 auth --rnd 45F54ADA252AAC --frn 4866BB70 --> Test authentication, tag will respond if successful\n" ); void *argtable[] = { @@ -340,7 +340,6 @@ int CmdEM4x70Auth(const char *Cmd) { int CmdEM4x70WritePIN(const char *Cmd) { - // send pin code to device, unlocking it for writing em4x70_data_t etd = {0}; CLIParserContext *ctx; @@ -395,6 +394,57 @@ int CmdEM4x70WritePIN(const char *Cmd) { return PM3_ESOFT; } +int CmdEM4x70WriteKey(const char *Cmd) { + + // Write new crypt key to tag + em4x70_data_t etd = {0}; + + CLIParserContext *ctx; + + CLIParserInit(&ctx, "lf em 4x70 writekey", + "Write new 96-bit key to tag\n", + "lf em 4x70 writekey -k F32AA98CF5BE4ADFA6D3480B\n" + ); + + void *argtable[] = { + arg_param_begin, + arg_lit0(NULL, "par", "Add parity bit when sending commands"), + arg_str1("k", "key", "", "Crypt Key as 12 hex bytes"), + arg_param_end + }; + + CLIExecWithReturn(ctx, Cmd, argtable, true); + + etd.parity = arg_get_lit(ctx, 1); + + int key_len = 12; + CLIGetHexWithReturn(ctx, 2, etd.crypt_key, &key_len); + + CLIParserFree(ctx); + + if (key_len != 12) { + PrintAndLogEx(FAILED, "Crypt key length must be 12 bytes instead of %d", key_len); + return PM3_EINVARG; + } + + clearCommandBuffer(); + SendCommandNG(CMD_LF_EM4X70_WRITEKEY, (uint8_t *)&etd, sizeof(etd)); + + PacketResponseNG resp; + if (!WaitForResponseTimeout(CMD_LF_EM4X70_WRITEKEY, &resp, TIMEOUT)) { + PrintAndLogEx(WARNING, "Timeout while waiting for reply."); + return PM3_ETIMEOUT; + } + + if (resp.status) { + PrintAndLogEx(INFO, "Writing new crypt key: " _GREEN_("SUCCESS")); + return PM3_SUCCESS; + } + + PrintAndLogEx(FAILED, "Writing new crypt key: " _RED_("FAILED")); + return PM3_ESOFT; +} + static command_t CommandTable[] = { {"help", CmdHelp, AlwaysAvailable, "This help"}, {"info", CmdEM4x70Info, IfPm3EM4x70, "Tag information EM4x70"}, @@ -402,6 +452,7 @@ static command_t CommandTable[] = { {"unlock", CmdEM4x70Unlock, IfPm3EM4x70, "Unlock EM4x70 for writing"}, {"auth", CmdEM4x70Auth, IfPm3EM4x70, "Authenticate EM4x70"}, {"writepin", CmdEM4x70WritePIN, IfPm3EM4x70, "Write PIN"}, + {"writekey", CmdEM4x70WriteKey, IfPm3EM4x70, "Write Crypt Key"}, {NULL, NULL, NULL, NULL} }; diff --git a/client/src/cmdlfem4x70.h b/client/src/cmdlfem4x70.h index 09a9b9361..f0f221b06 100644 --- a/client/src/cmdlfem4x70.h +++ b/client/src/cmdlfem4x70.h @@ -22,6 +22,7 @@ int CmdEM4x70Write(const char *Cmd); int CmdEM4x70Unlock(const char *Cmd); int CmdEM4x70Auth(const char *Cmd); int CmdEM4x70WritePIN(const char *Cmd); +int CmdEM4x70WriteKey(const char *Cmd); int em4x70_info(void); bool detect_4x70_block(void); diff --git a/include/em4x70.h b/include/em4x70.h index 4d08d622b..183e7398d 100644 --- a/include/em4x70.h +++ b/include/em4x70.h @@ -31,6 +31,9 @@ typedef struct { uint8_t rnd[7]; uint8_t frnd[4]; + // Used to write new key + uint8_t crypt_key[12]; + } em4x70_data_t; #endif /* EM4X70_H__ */ diff --git a/include/pm3_cmd.h b/include/pm3_cmd.h index 0249d15a7..e3dc29aee 100644 --- a/include/pm3_cmd.h +++ b/include/pm3_cmd.h @@ -521,6 +521,7 @@ typedef struct { #define CMD_LF_EM4X70_UNLOCK 0x0262 #define CMD_LF_EM4X70_AUTH 0x0263 #define CMD_LF_EM4X70_WRITEPIN 0x0264 +#define CMD_LF_EM4X70_WRITEKEY 0x0265 // Sampling configuration for LF reader/sniffer #define CMD_LF_SAMPLING_SET_CONFIG 0x021D #define CMD_LF_FSK_SIMULATE 0x021E