From 4ca4119fc978acba442b0dc49334bb0041bf11ca Mon Sep 17 00:00:00 2001 From: iceman1001 Date: Fri, 11 Dec 2020 00:42:55 +0100 Subject: [PATCH 001/682] added --- client/src/cmdhficlass.c | 188 +++++++++++++++++++++++++++++++++------ 1 file changed, 162 insertions(+), 26 deletions(-) diff --git a/client/src/cmdhficlass.c b/client/src/cmdhficlass.c index d884e7184..01b903272 100644 --- a/client/src/cmdhficlass.c +++ b/client/src/cmdhficlass.c @@ -1149,7 +1149,7 @@ static int CmdHFiClassEncryptBlk(const char *Cmd) { if (key_len > 0) { if (key_len != 16) { - PrintAndLogEx(ERR, "Transport key must be 16 hex ytes (32 HEX characters)"); + PrintAndLogEx(ERR, "Transport key must be 16 hex bytes (32 HEX characters)"); CLIParserFree(clictx); return PM3_EINVARG; } @@ -1165,8 +1165,10 @@ static int CmdHFiClassEncryptBlk(const char *Cmd) { if (have_key == false && use_sc == false) { size_t keylen = 0; int res = loadFile_safe(ICLASS_DECRYPTION_BIN, "", (void **)&keyptr, &keylen); - if (res != PM3_SUCCESS) + if (res != PM3_SUCCESS) { + PrintAndLogEx(ERR, "Failed to find the transport key"); return PM3_EINVARG; + } memcpy(key, keyptr, sizeof(key)); free(keyptr); @@ -3314,6 +3316,139 @@ static int CmdHFiClassPermuteKey(const char *Cmd) { return PM3_SUCCESS; } +static int CmdHFiClassEncode(const char *Cmd) { + + CLIParserContext *ctx; + CLIParserInit(&ctx, "hf iclass encode", + "Encode binary wiegand to block 7", + "hf iclass encode --bin 10001111100000001010100011 --ki 0 -> FC 31 CN 337\n" + "hf iclass encode --bin 10001111100000001010100011 --ki 0 --elite -> FC 31 CN 337, writing w elite key" + ); + + void *argtable[] = { + arg_param_begin, + arg_str1(NULL, "bin", "", "Binary string i.e 0001001001"), + arg_int1(NULL, "ki", "", "Key index to select key from memory 'hf iclass managekeys'"), + arg_lit0(NULL, "credit", "key is assumed to be the credit key"), + arg_lit0(NULL, "elite", "elite computations applied to key"), + arg_lit0(NULL, "raw", "no computations applied to key"), + arg_str0(NULL, "enckey", "", "3DES transport key, 16 hex bytes"), + arg_param_end + }; + CLIExecWithReturn(ctx, Cmd, argtable, false); + + int bin_len = 63; + uint8_t bin[70] = {0}; + CLIGetStrWithReturn(ctx, 1, bin, &bin_len); + + int key_nr = arg_get_int_def(ctx, 2, -1); + bool auth = false; + + uint8_t key[8] = {0}; + if (key_nr >= 0) { + if (key_nr < ICLASS_KEYS_MAX) { + auth = true; + memcpy(key, iClass_Key_Table[key_nr], 8); + PrintAndLogEx(SUCCESS, "Using key[%d] " _GREEN_("%s"), key_nr, sprint_hex(iClass_Key_Table[key_nr], 8)); + } else { + PrintAndLogEx(ERR, "Key number is invalid"); + CLIParserFree(ctx); + return PM3_EINVARG; + } + } + + bool use_credit_key = arg_get_lit(ctx, 3); + bool elite = arg_get_lit(ctx, 4); + bool rawkey = arg_get_lit(ctx, 5); + + int enc_key_len = 0; + uint8_t enc_key[16] = {0}; + uint8_t *enckeyptr = NULL; + bool have_enc_key = false; + CLIGetHexWithReturn(ctx, 6, enc_key, &enc_key_len); + + CLIParserFree(ctx); + + if ((rawkey + elite) > 1) { + PrintAndLogEx(ERR, "Can not use a combo of 'elite', 'raw'"); + return PM3_EINVARG; + } + + if (enc_key_len > 0) { + if (enc_key_len != 16) { + PrintAndLogEx(ERR, "Transport key must be 16 hex bytes (32 HEX characters)"); + return PM3_EINVARG; + } + have_enc_key = true; + } + + if (bin_len > 127) { + PrintAndLogEx(ERR, "Binary wiegand string must be less than 128 bits"); + return PM3_EINVARG; + } + + bool use_sc = IsCryptoHelperPresent(false); + + if (have_enc_key == false && use_sc == false) { + size_t keylen = 0; + int res = loadFile_safe(ICLASS_DECRYPTION_BIN, "", (void **)&enckeyptr, &keylen); + if (res != PM3_SUCCESS) { + PrintAndLogEx(ERR, "Failed to find the transport key"); + return PM3_EINVARG; + } + if (keylen != 16) { + PrintAndLogEx(ERR, "Failed to load transport key from file"); + return PM3_EINVARG; + } + + memcpy(enc_key, enckeyptr, sizeof(enc_key)); + free(enckeyptr); + } + + uint8_t data[8]; + memset(data, 0, sizeof(data)); + + BitstreamOut bout = {data, 0, 0 }; + + for (int i = 0; i < 64 - bin_len - 1; i++) { + pushBit(&bout, 0); + } + // add binary sentinel bit. + pushBit(&bout, 1); + + // convert binary string to hex bytes + for (int i = 0; i < bin_len; i++) { + char c = bin[i]; + if (c == '1') + pushBit(&bout, 1); + else if (c == '0') + pushBit(&bout, 0); + else { + PrintAndLogEx(WARNING, "Ignoring '%c'", c); + } + } + + // encrypt with transport key + if (use_sc) { + Encrypt(data, data); + } else { + iclass_encrypt_block_data(data, enc_key); + } + PrintAndLogEx(SUCCESS, "encrypted block: " _YELLOW_("%s"), sprint_hex_inrow(data, sizeof(data))); + + // write block 7 + int isok = iclass_write_block(7, data, key, use_credit_key, elite, rawkey, false, false, auth); + switch (isok) { + case PM3_SUCCESS: + PrintAndLogEx(SUCCESS, "Write block 7/0x07 ( " _GREEN_("ok") " )"); + break; + default: + PrintAndLogEx(SUCCESS, "Write block 7/0x07 ( " _RED_("fail") " )"); + break; + } + return isok; +} + /* static int CmdHFiClassAutopwn(const char *Cmd) { @@ -3340,35 +3475,36 @@ static int CmdHFiClassAutopwn(const char *Cmd) { static command_t CommandTable[] = { {"-----------", CmdHelp, AlwaysAvailable, "--------------------- " _CYAN_("operations") " ---------------------"}, - {"help", CmdHelp, AlwaysAvailable, "This help"}, -// {"clone", CmdHFiClassClone, IfPm3Iclass, "[options..] Create a HID credential to Picopass / iCLASS tag"}, - {"dump", CmdHFiClassDump, IfPm3Iclass, "[options..] Dump Picopass / iCLASS tag to file"}, - {"info", CmdHFiClassInfo, AlwaysAvailable, " Tag information"}, - {"list", CmdHFiClassList, AlwaysAvailable, " List iclass history"}, - {"rdbl", CmdHFiClass_ReadBlock, IfPm3Iclass, "[options..] Read Picopass / iCLASS block"}, - {"reader", CmdHFiClassReader, IfPm3Iclass, " Act like an Picopass / iCLASS reader"}, - {"restore", CmdHFiClassRestore, IfPm3Iclass, "[options..] Restore a dump file onto a Picopass / iCLASS tag"}, - {"sniff", CmdHFiClassSniff, IfPm3Iclass, " Eavesdrop Picopass / iCLASS communication"}, - {"wrbl", CmdHFiClass_WriteBlock, IfPm3Iclass, "[options..] Write Picopass / iCLASS block"}, + {"help", CmdHelp, AlwaysAvailable, " This help"}, +// {"clone", CmdHFiClassClone, IfPm3Iclass, "[*] Create a HID credential to Picopass / iCLASS tag"}, + {"dump", CmdHFiClassDump, IfPm3Iclass, "[*] Dump Picopass / iCLASS tag to file"}, + {"info", CmdHFiClassInfo, AlwaysAvailable, " Tag information"}, + {"list", CmdHFiClassList, AlwaysAvailable, " List iclass history"}, + {"rdbl", CmdHFiClass_ReadBlock, IfPm3Iclass, "[*] Read Picopass / iCLASS block"}, + {"reader", CmdHFiClassReader, IfPm3Iclass, " Act like an Picopass / iCLASS reader"}, + {"restore", CmdHFiClassRestore, IfPm3Iclass, "[*] Restore a dump file onto a Picopass / iCLASS tag"}, + {"sniff", CmdHFiClassSniff, IfPm3Iclass, " Eavesdrop Picopass / iCLASS communication"}, + {"wrbl", CmdHFiClass_WriteBlock, IfPm3Iclass, "[*] Write Picopass / iCLASS block"}, {"-----------", CmdHelp, AlwaysAvailable, "--------------------- " _CYAN_("recovery") " ---------------------"}, -// {"autopwn", CmdHFiClassAutopwn, IfPm3Iclass, "[options..] Automatic key recovery tool for iCLASS"}, - {"chk", CmdHFiClassCheckKeys, IfPm3Iclass, "[options..] Check keys"}, - {"loclass", CmdHFiClass_loclass, AlwaysAvailable, "[options..] Use loclass to perform bruteforce reader attack"}, - {"lookup", CmdHFiClassLookUp, AlwaysAvailable, "[options..] Uses authentication trace to check for key in dictionary file"}, +// {"autopwn", CmdHFiClassAutopwn, IfPm3Iclass, "[*] Automatic key recovery tool for iCLASS"}, + {"chk", CmdHFiClassCheckKeys, IfPm3Iclass, "[*] Check keys"}, + {"loclass", CmdHFiClass_loclass, AlwaysAvailable, "[*] Use loclass to perform bruteforce reader attack"}, + {"lookup", CmdHFiClassLookUp, AlwaysAvailable, "[*] Uses authentication trace to check for key in dictionary file"}, {"-----------", CmdHelp, AlwaysAvailable, "--------------------- " _CYAN_("simulation") " ---------------------"}, - {"sim", CmdHFiClassSim, IfPm3Iclass, "[options..] Simulate iCLASS tag"}, - {"eload", CmdHFiClassELoad, IfPm3Iclass, "[f ] Load Picopass / iCLASS dump file into emulator memory"}, - {"esave", CmdHFiClassESave, IfPm3Iclass, "[f ] Save emulator memory to file"}, - {"eview", CmdHFiClassEView, IfPm3Iclass, "[options..] View emulator memory"}, + {"sim", CmdHFiClassSim, IfPm3Iclass, "[*] Simulate iCLASS tag"}, + {"eload", CmdHFiClassELoad, IfPm3Iclass, "[*] Load Picopass / iCLASS dump file into emulator memory"}, + {"esave", CmdHFiClassESave, IfPm3Iclass, "[*] Save emulator memory to file"}, + {"eview", CmdHFiClassEView, IfPm3Iclass, "[.] View emulator memory"}, {"-----------", CmdHelp, AlwaysAvailable, "--------------------- " _CYAN_("utils") " ---------------------"}, - {"calcnewkey", CmdHFiClassCalcNewKey, AlwaysAvailable, "[options..] Calc diversified keys (blocks 3 & 4) to write new keys"}, - {"encrypt", CmdHFiClassEncryptBlk, AlwaysAvailable, "[options..] Encrypt given block data"}, - {"decrypt", CmdHFiClassDecrypt, AlwaysAvailable, "[options..] Decrypt given block data or tag dump file" }, - {"managekeys", CmdHFiClassManageKeys, AlwaysAvailable, "[options..] Manage keys to use with iclass commands"}, - {"permutekey", CmdHFiClassPermuteKey, IfPm3Iclass, " Permute function from 'heart of darkness' paper"}, - {"view", CmdHFiClassView, AlwaysAvailable, "[options..] Display content from tag dump file"}, + {"calcnewkey", CmdHFiClassCalcNewKey, AlwaysAvailable, "[*] Calc diversified keys (blocks 3 & 4) to write new keys"}, + {"encode", CmdHFiClassEncode, AlwaysAvailable, "[*] Encode binary wiegand to block 7"}, + {"encrypt", CmdHFiClassEncryptBlk, AlwaysAvailable, "[*] Encrypt given block data"}, + {"decrypt", CmdHFiClassDecrypt, AlwaysAvailable, "[*] Decrypt given block data or tag dump file" }, + {"managekeys", CmdHFiClassManageKeys, AlwaysAvailable, "[*] Manage keys to use with iclass commands"}, + {"permutekey", CmdHFiClassPermuteKey, IfPm3Iclass, " Permute function from 'heart of darkness' paper"}, + {"view", CmdHFiClassView, AlwaysAvailable, "[*] Display content from tag dump file"}, {NULL, NULL, NULL, NULL} }; From 21eebd4b761e1a7d398977e2867b1da49b7a1dda Mon Sep 17 00:00:00 2001 From: iceman1001 Date: Fri, 11 Dec 2020 00:49:18 +0100 Subject: [PATCH 002/682] hf iclass encode - now writes a block6 --- client/src/cmdhficlass.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/client/src/cmdhficlass.c b/client/src/cmdhficlass.c index 01b903272..2d6992845 100644 --- a/client/src/cmdhficlass.c +++ b/client/src/cmdhficlass.c @@ -3446,6 +3446,16 @@ static int CmdHFiClassEncode(const char *Cmd) { PrintAndLogEx(SUCCESS, "Write block 7/0x07 ( " _RED_("fail") " )"); break; } + uint8_t block6[] = {0x03, 0x03, 0x03, 0x03, 0x00, 0x03, 0xE0, 0x17}; + isok = iclass_write_block(6, block6, key, use_credit_key, elite, rawkey, false, false, auth); + switch (isok) { + case PM3_SUCCESS: + PrintAndLogEx(SUCCESS, "Write block 6/0x06 ( " _GREEN_("ok") " )"); + break; + default: + PrintAndLogEx(SUCCESS, "Write block 6/0x06 ( " _RED_("fail") " )"); + break; + } return isok; } From 0c0cdab17d99cad2526fe7e51a40e67182a7dd0f Mon Sep 17 00:00:00 2001 From: iceman1001 Date: Fri, 11 Dec 2020 01:02:36 +0100 Subject: [PATCH 003/682] hf iclass encode - writes a credential 6,7,8,9 --- client/src/cmdhficlass.c | 80 +++++++++++++++++++++------------------- 1 file changed, 42 insertions(+), 38 deletions(-) diff --git a/client/src/cmdhficlass.c b/client/src/cmdhficlass.c index 2d6992845..075a5562e 100644 --- a/client/src/cmdhficlass.c +++ b/client/src/cmdhficlass.c @@ -3365,6 +3365,7 @@ static int CmdHFiClassEncode(const char *Cmd) { uint8_t enc_key[16] = {0}; uint8_t *enckeyptr = NULL; bool have_enc_key = false; + bool use_sc = false; CLIGetHexWithReturn(ctx, 6, enc_key, &enc_key_len); CLIParserFree(ctx); @@ -3387,27 +3388,33 @@ static int CmdHFiClassEncode(const char *Cmd) { return PM3_EINVARG; } - bool use_sc = IsCryptoHelperPresent(false); - - if (have_enc_key == false && use_sc == false) { - size_t keylen = 0; - int res = loadFile_safe(ICLASS_DECRYPTION_BIN, "", (void **)&enckeyptr, &keylen); - if (res != PM3_SUCCESS) { - PrintAndLogEx(ERR, "Failed to find the transport key"); - return PM3_EINVARG; + if (have_enc_key == false) { + use_sc = IsCryptoHelperPresent(false); + if (use_sc == false) { + size_t keylen = 0; + int res = loadFile_safe(ICLASS_DECRYPTION_BIN, "", (void **)&enckeyptr, &keylen); + if (res != PM3_SUCCESS) { + PrintAndLogEx(ERR, "Failed to find the transport key"); + return PM3_EINVARG; + } + if (keylen != 16) { + PrintAndLogEx(ERR, "Failed to load transport key from file"); + return PM3_EINVARG; + } + memcpy(enc_key, enckeyptr, sizeof(enc_key)); + free(enckeyptr); } - if (keylen != 16) { - PrintAndLogEx(ERR, "Failed to load transport key from file"); - return PM3_EINVARG; - } - - memcpy(enc_key, enckeyptr, sizeof(enc_key)); - free(enckeyptr); } + uint8_t credential[] = { + 0x03, 0x03, 0x03, 0x03, 0x00, 0x03, 0xE0, 0x17, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + }; + uint8_t data[8]; memset(data, 0, sizeof(data)); - BitstreamOut bout = {data, 0, 0 }; for (int i = 0; i < 64 - bin_len - 1; i++) { @@ -3427,34 +3434,31 @@ static int CmdHFiClassEncode(const char *Cmd) { PrintAndLogEx(WARNING, "Ignoring '%c'", c); } } + memcpy(credential + 8, data, sizeof(data)); // encrypt with transport key if (use_sc) { - Encrypt(data, data); + Encrypt(credential + 8, credential + 8); + Encrypt(credential + 16, credential + 16); + Encrypt(credential + 24, credential + 24); } else { - iclass_encrypt_block_data(data, enc_key); + iclass_encrypt_block_data(credential + 8, enc_key); + iclass_encrypt_block_data(credential + 16, enc_key); + iclass_encrypt_block_data(credential + 24, enc_key); } - PrintAndLogEx(SUCCESS, "encrypted block: " _YELLOW_("%s"), sprint_hex_inrow(data, sizeof(data))); - // write block 7 - int isok = iclass_write_block(7, data, key, use_credit_key, elite, rawkey, false, false, auth); - switch (isok) { - case PM3_SUCCESS: - PrintAndLogEx(SUCCESS, "Write block 7/0x07 ( " _GREEN_("ok") " )"); - break; - default: - PrintAndLogEx(SUCCESS, "Write block 7/0x07 ( " _RED_("fail") " )"); - break; - } - uint8_t block6[] = {0x03, 0x03, 0x03, 0x03, 0x00, 0x03, 0xE0, 0x17}; - isok = iclass_write_block(6, block6, key, use_credit_key, elite, rawkey, false, false, auth); - switch (isok) { - case PM3_SUCCESS: - PrintAndLogEx(SUCCESS, "Write block 6/0x06 ( " _GREEN_("ok") " )"); - break; - default: - PrintAndLogEx(SUCCESS, "Write block 6/0x06 ( " _RED_("fail") " )"); - break; + int isok = PM3_SUCCESS; + // write + for (uint8_t i=0; i<4; i++) { + isok = iclass_write_block(6 + i, credential + (i*8), key, use_credit_key, elite, rawkey, false, false, auth); + switch (isok) { + case PM3_SUCCESS: + PrintAndLogEx(SUCCESS, "Write block %d/0x0%x ( " _GREEN_("ok") " ) --> " _YELLOW_("%s"), 6 + i, 6 + i, sprint_hex_inrow(credential + (i*8), 8)); + break; + default: + PrintAndLogEx(SUCCESS, "Write block %d/0x0%x ( " _RED_("fail") " )", 6 + i, 6 + i); + break; + } } return isok; } From 7a3faa7de834d8b3b5b5aa80f0a62e6d310b53c1 Mon Sep 17 00:00:00 2001 From: cyberpunk-re Date: Fri, 11 Dec 2020 00:17:51 +0000 Subject: [PATCH 004/682] fix parsing for psk --- CHANGELOG.md | 1 + client/src/cmddata.c | 3 ++- common/lfdemod.c | 5 +++++ 3 files changed, 8 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6c6cba7e2..2f10e9c97 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] + - Fix `data rawdemod` parsing for psk2 and user defined clock (@cyberpunk-re) - Fix issue #844 - `lf t55xx config` => recompute block0 (@cyberpunk-re) - EM4x50: changed cli parameter from w (word) to d (data) (@tharexde) - EM4x50: new function 4x50 login: authenticate against tag (@tharexde) diff --git a/client/src/cmddata.c b/client/src/cmddata.c index daff73722..9a888f311 100644 --- a/client/src/cmddata.c +++ b/client/src/cmddata.c @@ -1367,6 +1367,7 @@ int CmdPSK1rawDemod(const char *Cmd) { if (strlen(Cmd) > 16 || cmdp == 'h') return usage_data_rawdemod_p1(); int clk = 0, invert = 0, max_err = 100; sscanf(Cmd, "%i %i %i", &clk, &invert, &max_err); + if (clk == 1) { invert = 1; clk = 0; @@ -1428,7 +1429,7 @@ static int CmdRawDemod(const char *Cmd) { else if (str_startswith(Cmd, "am")) ans = Cmdaskmandemod(Cmd + 2); else if (str_startswith(Cmd, "ar")) ans = Cmdaskrawdemod(Cmd + 2); else if (str_startswith(Cmd, "nr") || Cmd[0] == 'n') ans = CmdNRZrawDemod(Cmd + 2); - else if (str_startswith(Cmd, "p1") || Cmd[0] == 'p') ans = CmdPSK1rawDemod(Cmd + 2); + else if (str_startswith(Cmd, "p1")) ans = CmdPSK1rawDemod(Cmd + 2); else if (str_startswith(Cmd, "p2")) ans = CmdPSK2rawDemod(Cmd + 2); else PrintAndLogEx(WARNING, "Unknown modulation entered - see help ('h') for parameter structure"); diff --git a/common/lfdemod.c b/common/lfdemod.c index b6869ba43..24de41676 100644 --- a/common/lfdemod.c +++ b/common/lfdemod.c @@ -1081,6 +1081,11 @@ int DetectPSKClock(uint8_t *dest, size_t size, int clock, size_t *firstPhaseShif *firstPhaseShift = firstFullWave; if (g_debugMode == 2) prnt("DEBUG PSK: firstFullWave: %zu, waveLen: %d", firstFullWave, fullWaveLen); + // Avoid autodetect if user selected a clock + for(uint8_t validClk = 1; validClk < 8; validClk++) { + if(clock == clk[validClk]) return(clock); + } + //test each valid clock from greatest to smallest to see which lines up for (clkCnt = 7; clkCnt >= 1 ; clkCnt--) { uint8_t tol = *fc / 2; From 8d594db69edee3f2372df14d18bddfefce54b3fd Mon Sep 17 00:00:00 2001 From: cyberpunk-re Date: Fri, 11 Dec 2020 00:19:57 +0000 Subject: [PATCH 005/682] remove newline --- client/src/cmddata.c | 1 - 1 file changed, 1 deletion(-) diff --git a/client/src/cmddata.c b/client/src/cmddata.c index 9a888f311..7c6fd4785 100644 --- a/client/src/cmddata.c +++ b/client/src/cmddata.c @@ -1367,7 +1367,6 @@ int CmdPSK1rawDemod(const char *Cmd) { if (strlen(Cmd) > 16 || cmdp == 'h') return usage_data_rawdemod_p1(); int clk = 0, invert = 0, max_err = 100; sscanf(Cmd, "%i %i %i", &clk, &invert, &max_err); - if (clk == 1) { invert = 1; clk = 0; From bee075ad09d0abcf0e854a826bc4d8f21bd0f7d1 Mon Sep 17 00:00:00 2001 From: Ave Date: Sun, 6 Dec 2020 03:22:20 +0300 Subject: [PATCH 006/682] emrtd: Push initial code Can only read EF_CardAccess currently, but has abstractions for selecting AIDs and reading files, which was the Hard Part so far Based heavily on mrpkey by rfidiot --- client/CMakeLists.txt | 1 + client/Makefile | 1 + client/src/cmdhf.c | 38 ++++--- client/src/cmdhfemrtd.c | 247 ++++++++++++++++++++++++++++++++++++++++ client/src/cmdhfemrtd.h | 19 ++++ 5 files changed, 288 insertions(+), 18 deletions(-) create mode 100644 client/src/cmdhfemrtd.c create mode 100644 client/src/cmdhfemrtd.h diff --git a/client/CMakeLists.txt b/client/CMakeLists.txt index 4ea7acf36..c67104158 100644 --- a/client/CMakeLists.txt +++ b/client/CMakeLists.txt @@ -228,6 +228,7 @@ set (TARGET_SOURCES ${PM3_ROOT}/client/src/cmdhf15.c ${PM3_ROOT}/client/src/cmdhfcryptorf.c ${PM3_ROOT}/client/src/cmdhfepa.c + ${PM3_ROOT}/client/src/cmdhfemrtd.c ${PM3_ROOT}/client/src/cmdhffelica.c ${PM3_ROOT}/client/src/cmdhffido.c ${PM3_ROOT}/client/src/cmdhficlass.c diff --git a/client/Makefile b/client/Makefile index 9c624722c..9cfc4fc4b 100644 --- a/client/Makefile +++ b/client/Makefile @@ -469,6 +469,7 @@ SRCS = aiddesfire.c \ cmdhf15.c \ cmdhfcryptorf.c \ cmdhfepa.c \ + cmdhfemrtd.c \ cmdhffelica.c \ cmdhffido.c \ cmdhficlass.c \ diff --git a/client/src/cmdhf.c b/client/src/cmdhf.c index fa100e13d..94985579e 100644 --- a/client/src/cmdhf.c +++ b/client/src/cmdhf.c @@ -23,6 +23,7 @@ #include "cmdhf14b.h" // ISO14443-B #include "cmdhf15.h" // ISO15693 #include "cmdhfepa.h" +#include "cmdhfemrtd.h" // eMRTD #include "cmdhflegic.h" // LEGIC #include "cmdhficlass.h" // ICLASS #include "cmdhfmf.h" // CLASSIC @@ -357,24 +358,25 @@ int CmdHFPlot(const char *Cmd) { static command_t CommandTable[] = { {"--------", CmdHelp, AlwaysAvailable, "----------------------- " _CYAN_("High Frequency") " -----------------------"}, - {"14a", CmdHF14A, AlwaysAvailable, "{ ISO14443A RFIDs... }"}, - {"14b", CmdHF14B, AlwaysAvailable, "{ ISO14443B RFIDs... }"}, - {"15", CmdHF15, AlwaysAvailable, "{ ISO15693 RFIDs... }"}, -// {"cryptorf", CmdHFCryptoRF, AlwaysAvailable, "{ CryptoRF RFIDs... }"}, - {"epa", CmdHFEPA, AlwaysAvailable, "{ German Identification Card... }"}, - {"felica", CmdHFFelica, AlwaysAvailable, "{ ISO18092 / FeliCa RFIDs... }"}, - {"fido", CmdHFFido, AlwaysAvailable, "{ FIDO and FIDO2 authenticators... }"}, - {"iclass", CmdHFiClass, AlwaysAvailable, "{ ICLASS RFIDs... }"}, - {"legic", CmdHFLegic, AlwaysAvailable, "{ LEGIC RFIDs... }"}, - {"lto", CmdHFLTO, AlwaysAvailable, "{ LTO Cartridge Memory RFIDs... }"}, - {"mf", CmdHFMF, AlwaysAvailable, "{ MIFARE RFIDs... }"}, - {"mfp", CmdHFMFP, AlwaysAvailable, "{ MIFARE Plus RFIDs... }"}, - {"mfu", CmdHFMFUltra, AlwaysAvailable, "{ MIFARE Ultralight RFIDs... }"}, - {"mfdes", CmdHFMFDes, AlwaysAvailable, "{ MIFARE Desfire RFIDs... }"}, - {"st", CmdHF_ST, AlwaysAvailable, "{ ST Rothult RFIDs... }"}, - {"thinfilm", CmdHFThinfilm, AlwaysAvailable, "{ Thinfilm RFIDs... }"}, - {"topaz", CmdHFTopaz, AlwaysAvailable, "{ TOPAZ (NFC Type 1) RFIDs... }"}, - {"waveshare", CmdHFWaveshare, AlwaysAvailable, "{ Waveshare NFC ePaper... }"}, + {"14a", CmdHF14A, AlwaysAvailable, "{ ISO14443A RFIDs... }"}, + {"14b", CmdHF14B, AlwaysAvailable, "{ ISO14443B RFIDs... }"}, + {"15", CmdHF15, AlwaysAvailable, "{ ISO15693 RFIDs... }"}, +// {"cryptorf", CmdHFCryptoRF, AlwaysAvailable, "{ CryptoRF RFIDs... }"}, + {"epa", CmdHFEPA, AlwaysAvailable, "{ German Identification Card... }"}, + {"emrtd", CmdHFeMRTD, AlwaysAvailable, "{ Machine Readable Travel Document... }"}, + {"felica", CmdHFFelica, AlwaysAvailable, "{ ISO18092 / FeliCa RFIDs... }"}, + {"fido", CmdHFFido, AlwaysAvailable, "{ FIDO and FIDO2 authenticators... }"}, + {"iclass", CmdHFiClass, AlwaysAvailable, "{ ICLASS RFIDs... }"}, + {"legic", CmdHFLegic, AlwaysAvailable, "{ LEGIC RFIDs... }"}, + {"lto", CmdHFLTO, AlwaysAvailable, "{ LTO Cartridge Memory RFIDs... }"}, + {"mf", CmdHFMF, AlwaysAvailable, "{ MIFARE RFIDs... }"}, + {"mfp", CmdHFMFP, AlwaysAvailable, "{ MIFARE Plus RFIDs... }"}, + {"mfu", CmdHFMFUltra, AlwaysAvailable, "{ MIFARE Ultralight RFIDs... }"}, + {"mfdes", CmdHFMFDes, AlwaysAvailable, "{ MIFARE Desfire RFIDs... }"}, + {"st", CmdHF_ST, AlwaysAvailable, "{ ST Rothult RFIDs... }"}, + {"thinfilm", CmdHFThinfilm, AlwaysAvailable, "{ Thinfilm RFIDs... }"}, + {"topaz", CmdHFTopaz, AlwaysAvailable, "{ TOPAZ (NFC Type 1) RFIDs... }"}, + {"waveshare", CmdHFWaveshare, AlwaysAvailable, "{ Waveshare NFC ePaper... }"}, {"-----------", CmdHelp, AlwaysAvailable, "--------------------- " _CYAN_("General") " ---------------------"}, {"help", CmdHelp, AlwaysAvailable, "This help"}, {"list", CmdTraceList, AlwaysAvailable, "List protocol data in trace buffer"}, diff --git a/client/src/cmdhfemrtd.c b/client/src/cmdhfemrtd.c new file mode 100644 index 000000000..cc27a86f1 --- /dev/null +++ b/client/src/cmdhfemrtd.c @@ -0,0 +1,247 @@ +//----------------------------------------------------------------------------- +// Copyright (C) 2020 A. Ozkal +// +// This code is licensed to you under the terms of the GNU GPL, version 2 or, +// at your option, any later version. See the LICENSE.txt file for the text of +// the license. +//----------------------------------------------------------------------------- +// High frequency Electronic Machine Readable Travel Document commands +//----------------------------------------------------------------------------- + +#include "cmdhfemrtd.h" +#include +#include "fileutils.h" +#include "cmdparser.h" // command_t +#include "comms.h" // clearCommandBuffer +#include "cmdtrace.h" +#include "cliparser.h" +#include "crc16.h" +#include "cmdhf14a.h" +#include "protocols.h" // definitions of ISO14A/7816 protocol +#include "emv/apduinfo.h" // GetAPDUCodeDescription + +#define TIMEOUT 2000 + +static int CmdHelp(const char *Cmd); + +static uint16_t get_sw(uint8_t *d, uint8_t n) { + if (n < 2) + return 0; + + n -= 2; + return d[n] * 0x0100 + d[n + 1]; +} + +static int select_aid(const char *select_by, const char *file_id) { + bool activate_field = true; + bool keep_field_on = true; + uint8_t response[PM3_CMD_DATA_SIZE]; + int resplen = 0; + + size_t file_id_len = strlen(file_id) / 2; + + char cmd[50]; + sprintf(cmd, "00A4%s0C%02lu%s", select_by, file_id_len, file_id); + PrintAndLogEx(INFO, "Sending: %s", cmd); + + uint8_t aSELECT_AID[80]; + int aSELECT_AID_n = 0; + param_gethex_to_eol(cmd, 0, aSELECT_AID, sizeof(aSELECT_AID), &aSELECT_AID_n); + int res = ExchangeAPDU14a(aSELECT_AID, aSELECT_AID_n, activate_field, keep_field_on, response, sizeof(response), &resplen); + if (res) { + DropField(); + return false; + } + + if (resplen < 2) { + DropField(); + return false; + } + PrintAndLogEx(INFO, "Resp: %s", sprint_hex(response, resplen)); + + uint16_t sw = get_sw(response, resplen); + if (sw != 0x9000) { + PrintAndLogEx(ERR, "Selecting Card Access aid failed (%04x - %s).", sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff)); + DropField(); + return false; + } + return true; +} + +static int asn1datalength(uint8_t *datain, int datainlen) { + char* dataintext = sprint_hex_inrow(datain, datainlen); + + // lazy - https://stackoverflow.com/a/4214350/3286892 + char subbuff[8]; + memcpy(subbuff, &dataintext[2], 2); + subbuff[2] = '\0'; + + int thing = (int)strtol(subbuff, NULL, 16); + if (thing <= 0x7f) { + return thing; + } else if (thing == 0x81) { + memcpy(subbuff, &dataintext[2], 3); + subbuff[3] = '\0'; + return (int)strtol(subbuff, NULL, 16); + } else if (thing == 0x82) { + memcpy(subbuff, &dataintext[2], 5); + subbuff[5] = '\0'; + return (int)strtol(subbuff, NULL, 16); + } else if (thing == 0x83) { + memcpy(subbuff, &dataintext[2], 7); + subbuff[7] = '\0'; + return (int)strtol(subbuff, NULL, 16); + } + return false; +} + +static int asn1fieldlength(uint8_t *datain, int datainlen) { + char* dataintext = sprint_hex_inrow(datain, datainlen); + + // lazy - https://stackoverflow.com/a/4214350/3286892 + char subbuff[8]; + memcpy(subbuff, &dataintext[2], 2); + subbuff[2] = '\0'; + + int thing = (int)strtol(subbuff, NULL, 16); + if (thing <= 0x7f) { + return 2; + } else if (thing == 0x81) { + return 4; + } else if (thing == 0x82) { + return 6; + } else if (thing == 0x83) { + return 8; + } + return false; +} + +static int _read_binary(int offset, int bytes_to_read, uint8_t *dataout, int maxdataoutlen, int *dataoutlen) { + bool activate_field = false; + bool keep_field_on = true; + uint8_t response[PM3_CMD_DATA_SIZE]; + int resplen = 0; + + char cmd[50]; + sprintf(cmd, "00B0%04i%02i", offset, bytes_to_read); + PrintAndLogEx(INFO, "Sending: %s", cmd); + + uint8_t aREAD_BINARY[80]; + int aREAD_BINARY_n = 0; + param_gethex_to_eol(cmd, 0, aREAD_BINARY, sizeof(aREAD_BINARY), &aREAD_BINARY_n); + int res = ExchangeAPDU14a(aREAD_BINARY, aREAD_BINARY_n, activate_field, keep_field_on, response, sizeof(response), &resplen); + if (res) { + DropField(); + return false; + } + PrintAndLogEx(INFO, "Resp: %s", sprint_hex(response, resplen)); + + // drop sw + memcpy(dataout, &response, resplen - 2); + *dataoutlen = (resplen - 2); + + uint16_t sw = get_sw(response, resplen); + if (sw != 0x9000) { + PrintAndLogEx(ERR, "Reading binary failed (%04x - %s).", sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff)); + DropField(); + return false; + } + return true; +} + +static int read_file(uint8_t *dataout, int maxdataoutlen, int *dataoutlen) { + uint8_t response[PM3_CMD_DATA_SIZE]; + int resplen = 0; + uint8_t tempresponse[PM3_CMD_DATA_SIZE]; + int tempresplen = 0; + + if (!_read_binary(0, 4, response, sizeof(response), &resplen)) { + return false; + } + + int datalen = asn1datalength(response, resplen); + int readlen = datalen - (3 - asn1fieldlength(response, resplen) / 2); + int offset = 4; + int toread; + + while (readlen > 0) { + toread = readlen; + if (readlen > 118) { + toread = 118; + } + + if (!_read_binary(offset, toread, tempresponse, sizeof(tempresponse), &tempresplen)) { + return false; + } + + memcpy(&response[resplen], &tempresponse, tempresplen); + offset += toread; + readlen -= toread; + resplen += tempresplen; + } + + memcpy(dataout, &response, resplen); + *dataoutlen = resplen; + return true; +} + +int infoHF_EMRTD(void) { + // const uint8_t *data + if (select_aid("02", "011c")) { + uint8_t response[PM3_CMD_DATA_SIZE]; + int resplen = 0; + + read_file(response, sizeof(response), &resplen); + + PrintAndLogEx(INFO, "EF_CardAccess: %s", sprint_hex(response, resplen)); + } else { + PrintAndLogEx(INFO, "PACE unsupported. Will not read EF_CardAccess."); + } + + DropField(); + return PM3_SUCCESS; +} + +static int cmd_hf_emrtd_info(const char *Cmd) { + CLIParserContext *ctx; + CLIParserInit(&ctx, "hf emrtd info", + "Get info about an eMRTD", + "hf emrtd info" + ); + + void *argtable[] = { + arg_param_begin, + arg_param_end + }; + CLIExecWithReturn(ctx, Cmd, argtable, true); + CLIParserFree(ctx); + return infoHF_EMRTD(); +} + +static int cmd_hf_emrtd_list(const char *Cmd) { + char args[128] = {0}; + if (strlen(Cmd) == 0) { + snprintf(args, sizeof(args), "-t 7816"); + } else { + strncpy(args, Cmd, sizeof(args) - 1); + } + return CmdTraceList(args); +} + +static command_t CommandTable[] = { + {"help", CmdHelp, AlwaysAvailable, "This help"}, + {"info", cmd_hf_emrtd_info, IfPm3Iso14443a, "Tag information"}, + {"list", cmd_hf_emrtd_list, AlwaysAvailable, "List ISO 14443A/7816 history"}, + {NULL, NULL, NULL, NULL} +}; + +static int CmdHelp(const char *Cmd) { + (void)Cmd; // Cmd is not used so far + CmdsHelp(CommandTable); + return PM3_SUCCESS; +} + +int CmdHFeMRTD(const char *Cmd) { + clearCommandBuffer(); + return CmdsParse(CommandTable, Cmd); +} diff --git a/client/src/cmdhfemrtd.h b/client/src/cmdhfemrtd.h new file mode 100644 index 000000000..62b0a5bce --- /dev/null +++ b/client/src/cmdhfemrtd.h @@ -0,0 +1,19 @@ +//----------------------------------------------------------------------------- +// Copyright (C) 2020 A. Ozkal +// +// This code is licensed to you under the terms of the GNU GPL, version 2 or, +// at your option, any later version. See the LICENSE.txt file for the text of +// the license. +//----------------------------------------------------------------------------- +// High frequency Electronic Machine Readable Travel Document commands +//----------------------------------------------------------------------------- + +#ifndef CMDHFEMRTD_H__ +#define CMDHFEMRTD_H__ + +#include "common.h" + +int CmdHFeMRTD(const char *Cmd); + +int infoHF_EMRTD(void); +#endif From 2c5ab219482abb5af103d3155aac2572279a3410 Mon Sep 17 00:00:00 2001 From: Ave Date: Sun, 6 Dec 2020 03:39:16 +0300 Subject: [PATCH 007/682] emtrd: Switch magic numbers over to named defines --- client/src/cmdhfemrtd.c | 26 +++++++++++++++++++++----- 1 file changed, 21 insertions(+), 5 deletions(-) diff --git a/client/src/cmdhfemrtd.c b/client/src/cmdhfemrtd.c index cc27a86f1..e4a10562c 100644 --- a/client/src/cmdhfemrtd.c +++ b/client/src/cmdhfemrtd.c @@ -22,6 +22,22 @@ #define TIMEOUT 2000 +// ISO7816 commands +#define SELECT "A4" +#define GET_CHALLENGE "84" +#define READ_BINARY "B0" +#define P1_SELECT_BY_EF "02" +#define P1_SELECT_BY_NAME "04" +#define P2_PROPRIETARY "0C" + +// File IDs +#define EF_CARDACCESS "011C" +#define EF_COM "011E" +#define EF_DG1 "0101" + +// App IDs +#define AID_MRTD "A0000002471001" + static int CmdHelp(const char *Cmd); static uint16_t get_sw(uint8_t *d, uint8_t n) { @@ -41,7 +57,7 @@ static int select_aid(const char *select_by, const char *file_id) { size_t file_id_len = strlen(file_id) / 2; char cmd[50]; - sprintf(cmd, "00A4%s0C%02lu%s", select_by, file_id_len, file_id); + sprintf(cmd, "00%s%s0C%02lu%s", SELECT, select_by, file_id_len, file_id); PrintAndLogEx(INFO, "Sending: %s", cmd); uint8_t aSELECT_AID[80]; @@ -57,7 +73,7 @@ static int select_aid(const char *select_by, const char *file_id) { DropField(); return false; } - PrintAndLogEx(INFO, "Resp: %s", sprint_hex(response, resplen)); + PrintAndLogEx(INFO, "Response: %s", sprint_hex(response, resplen)); uint16_t sw = get_sw(response, resplen); if (sw != 0x9000) { @@ -123,7 +139,7 @@ static int _read_binary(int offset, int bytes_to_read, uint8_t *dataout, int max int resplen = 0; char cmd[50]; - sprintf(cmd, "00B0%04i%02i", offset, bytes_to_read); + sprintf(cmd, "00%s%04i%02i", READ_BINARY, offset, bytes_to_read); PrintAndLogEx(INFO, "Sending: %s", cmd); uint8_t aREAD_BINARY[80]; @@ -134,7 +150,7 @@ static int _read_binary(int offset, int bytes_to_read, uint8_t *dataout, int max DropField(); return false; } - PrintAndLogEx(INFO, "Resp: %s", sprint_hex(response, resplen)); + PrintAndLogEx(INFO, "Response: %s", sprint_hex(response, resplen)); // drop sw memcpy(dataout, &response, resplen - 2); @@ -187,7 +203,7 @@ static int read_file(uint8_t *dataout, int maxdataoutlen, int *dataoutlen) { int infoHF_EMRTD(void) { // const uint8_t *data - if (select_aid("02", "011c")) { + if (select_aid(P1_SELECT_BY_EF, EF_CARDACCESS)) { uint8_t response[PM3_CMD_DATA_SIZE]; int resplen = 0; From 885f4b52fd48be8a019f8171251b6615654ea8d8 Mon Sep 17 00:00:00 2001 From: Ave Date: Sun, 6 Dec 2020 03:42:41 +0300 Subject: [PATCH 008/682] emrtd: Rename select_aid to select_file --- client/src/cmdhfemrtd.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/client/src/cmdhfemrtd.c b/client/src/cmdhfemrtd.c index e4a10562c..c1dd246b1 100644 --- a/client/src/cmdhfemrtd.c +++ b/client/src/cmdhfemrtd.c @@ -48,7 +48,7 @@ static uint16_t get_sw(uint8_t *d, uint8_t n) { return d[n] * 0x0100 + d[n + 1]; } -static int select_aid(const char *select_by, const char *file_id) { +static int select_file(const char *select_by, const char *file_id) { bool activate_field = true; bool keep_field_on = true; uint8_t response[PM3_CMD_DATA_SIZE]; @@ -60,10 +60,10 @@ static int select_aid(const char *select_by, const char *file_id) { sprintf(cmd, "00%s%s0C%02lu%s", SELECT, select_by, file_id_len, file_id); PrintAndLogEx(INFO, "Sending: %s", cmd); - uint8_t aSELECT_AID[80]; - int aSELECT_AID_n = 0; - param_gethex_to_eol(cmd, 0, aSELECT_AID, sizeof(aSELECT_AID), &aSELECT_AID_n); - int res = ExchangeAPDU14a(aSELECT_AID, aSELECT_AID_n, activate_field, keep_field_on, response, sizeof(response), &resplen); + uint8_t aSELECT_FILE[80]; + int aSELECT_FILE_n = 0; + param_gethex_to_eol(cmd, 0, aSELECT_FILE, sizeof(aSELECT_FILE), &aSELECT_FILE_n); + int res = ExchangeAPDU14a(aSELECT_FILE, aSELECT_FILE_n, activate_field, keep_field_on, response, sizeof(response), &resplen); if (res) { DropField(); return false; @@ -77,7 +77,7 @@ static int select_aid(const char *select_by, const char *file_id) { uint16_t sw = get_sw(response, resplen); if (sw != 0x9000) { - PrintAndLogEx(ERR, "Selecting Card Access aid failed (%04x - %s).", sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff)); + PrintAndLogEx(ERR, "Selecting file failed (%04x - %s).", sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff)); DropField(); return false; } @@ -203,7 +203,7 @@ static int read_file(uint8_t *dataout, int maxdataoutlen, int *dataoutlen) { int infoHF_EMRTD(void) { // const uint8_t *data - if (select_aid(P1_SELECT_BY_EF, EF_CARDACCESS)) { + if (select_file(P1_SELECT_BY_EF, EF_CARDACCESS)) { uint8_t response[PM3_CMD_DATA_SIZE]; int resplen = 0; From 84a1059d9318a017f0ba8a0e2bfc620a98c65e1c Mon Sep 17 00:00:00 2001 From: Ave Date: Sun, 6 Dec 2020 04:48:38 +0300 Subject: [PATCH 009/682] emrtd: Add BAC check --- client/src/cmdhfemrtd.c | 41 ++++++++++++++++++++++++++++++----------- 1 file changed, 30 insertions(+), 11 deletions(-) diff --git a/client/src/cmdhfemrtd.c b/client/src/cmdhfemrtd.c index c1dd246b1..c43f614ce 100644 --- a/client/src/cmdhfemrtd.c +++ b/client/src/cmdhfemrtd.c @@ -48,9 +48,7 @@ static uint16_t get_sw(uint8_t *d, uint8_t n) { return d[n] * 0x0100 + d[n + 1]; } -static int select_file(const char *select_by, const char *file_id) { - bool activate_field = true; - bool keep_field_on = true; +static int select_file(const char *select_by, const char *file_id, bool activate_field, bool keep_field_on) { uint8_t response[PM3_CMD_DATA_SIZE]; int resplen = 0; @@ -70,7 +68,6 @@ static int select_file(const char *select_by, const char *file_id) { } if (resplen < 2) { - DropField(); return false; } PrintAndLogEx(INFO, "Response: %s", sprint_hex(response, resplen)); @@ -78,7 +75,6 @@ static int select_file(const char *select_by, const char *file_id) { uint16_t sw = get_sw(response, resplen); if (sw != 0x9000) { PrintAndLogEx(ERR, "Selecting file failed (%04x - %s).", sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff)); - DropField(); return false; } return true; @@ -159,7 +155,6 @@ static int _read_binary(int offset, int bytes_to_read, uint8_t *dataout, int max uint16_t sw = get_sw(response, resplen); if (sw != 0x9000) { PrintAndLogEx(ERR, "Reading binary failed (%04x - %s).", sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff)); - DropField(); return false; } return true; @@ -202,18 +197,42 @@ static int read_file(uint8_t *dataout, int maxdataoutlen, int *dataoutlen) { } int infoHF_EMRTD(void) { - // const uint8_t *data - if (select_file(P1_SELECT_BY_EF, EF_CARDACCESS)) { - uint8_t response[PM3_CMD_DATA_SIZE]; - int resplen = 0; + uint8_t response[PM3_CMD_DATA_SIZE]; + int resplen = 0; + // bool BAC = true; + // Select and read EF_CardAccess + if (select_file(P1_SELECT_BY_EF, EF_CARDACCESS, true, true)) { read_file(response, sizeof(response), &resplen); - PrintAndLogEx(INFO, "EF_CardAccess: %s", sprint_hex(response, resplen)); } else { PrintAndLogEx(INFO, "PACE unsupported. Will not read EF_CardAccess."); } + // Select MRTD applet + if (select_file(P1_SELECT_BY_NAME, AID_MRTD, false, true) == false) { + PrintAndLogEx(ERR, "Couldn't select the MRTD application."); + return PM3_ESOFT; + } + + // Select EF_COM + if (select_file(P1_SELECT_BY_EF, EF_COM, false, true) == false) { + // BAC = true; + PrintAndLogEx(INFO, "Basic Access Control is enforced. Will attempt auth."); + } else { + // BAC = false; + // Select EF_DG1 + select_file(P1_SELECT_BY_EF, EF_DG1, false, true); + + if (read_file(response, sizeof(response), &resplen) == false) { + // BAC = true; + PrintAndLogEx(INFO, "Basic Access Control is enforced. Will attempt auth."); + } else { + // BAC = false; + PrintAndLogEx(INFO, "EF_DG1: %s", sprint_hex(response, resplen)); + } + } + DropField(); return PM3_SUCCESS; } From 1149c56696d13e4dfd1473c003829e2daa47bb73 Mon Sep 17 00:00:00 2001 From: Ave Date: Sun, 6 Dec 2020 23:52:08 +0300 Subject: [PATCH 010/682] emrtd: Add kmrz calc --- client/src/cmdhfemrtd.c | 48 +++++++++++++++++++++++++++++++++++++++-- client/src/cmdhfemrtd.h | 2 +- 2 files changed, 47 insertions(+), 3 deletions(-) diff --git a/client/src/cmdhfemrtd.c b/client/src/cmdhfemrtd.c index c43f614ce..1be269c67 100644 --- a/client/src/cmdhfemrtd.c +++ b/client/src/cmdhfemrtd.c @@ -80,6 +80,28 @@ static int select_file(const char *select_by, const char *file_id, bool activate return true; } +static char calculate_check_digit(char *data) { + int mrz_weight[] = {7, 3, 1}; + int cd = 0; + int value = 0; + char d; + + for (int i = 0; i < strlen(data); i++) { + d = data[i]; + if ('A' <= d && d <= 'Z') { + value = d - 55; + } else if ('a' <= d && d <= 'z') { + value = d - 87; + } else if (d == '<') { + value = 0; + } else { // Numbers + value = d - 48; + } + cd += value * mrz_weight[i % 3]; + } + return cd % 10; +} + static int asn1datalength(uint8_t *datain, int datainlen) { char* dataintext = sprint_hex_inrow(datain, datainlen); @@ -196,7 +218,7 @@ static int read_file(uint8_t *dataout, int maxdataoutlen, int *dataoutlen) { return true; } -int infoHF_EMRTD(void) { +int infoHF_EMRTD(char *documentnumber, char *dob, char *expiry) { uint8_t response[PM3_CMD_DATA_SIZE]; int resplen = 0; // bool BAC = true; @@ -233,6 +255,14 @@ int infoHF_EMRTD(void) { } } + char documentnumbercd = calculate_check_digit(documentnumber); + char dobcd = calculate_check_digit(dob); + char expirycd = calculate_check_digit(expiry); + + char kmrz[25]; + sprintf(kmrz, "%s%i%s%i%s%i", documentnumber, documentnumbercd, dob, dobcd, expiry, expirycd); + PrintAndLogEx(INFO, "kmrz: %s", kmrz); + DropField(); return PM3_SUCCESS; } @@ -246,11 +276,25 @@ static int cmd_hf_emrtd_info(const char *Cmd) { void *argtable[] = { arg_param_begin, + arg_str1("n", "documentnumber", "", "9 character document number"), + arg_str1("d", "dateofbirth", "", "date of birth in YYMMDD format"), + arg_str1("e", "expiry", "", "expiry in YYMMDD format"), arg_param_end }; CLIExecWithReturn(ctx, Cmd, argtable, true); + + uint8_t docnum[9]; + uint8_t dob[6]; + uint8_t expiry[6]; + int docnumlen = sizeof(docnum); + int doblen = sizeof(dob); + int expirylen = sizeof(expiry); + CLIGetStrWithReturn(ctx, 1, docnum, &docnumlen); + CLIGetStrWithReturn(ctx, 2, dob, &doblen); + CLIGetStrWithReturn(ctx, 3, expiry, &expirylen); + CLIParserFree(ctx); - return infoHF_EMRTD(); + return infoHF_EMRTD((char *)docnum, (char *)dob, (char *)expiry); } static int cmd_hf_emrtd_list(const char *Cmd) { diff --git a/client/src/cmdhfemrtd.h b/client/src/cmdhfemrtd.h index 62b0a5bce..ba9e3f2b3 100644 --- a/client/src/cmdhfemrtd.h +++ b/client/src/cmdhfemrtd.h @@ -15,5 +15,5 @@ int CmdHFeMRTD(const char *Cmd); -int infoHF_EMRTD(void); +int infoHF_EMRTD(char *documentnumber, char *dob, char *expiry); #endif From 9f6309cc23cbf5cca11720f9435871ab2ed203c3 Mon Sep 17 00:00:00 2001 From: Ave Date: Mon, 7 Dec 2020 00:40:01 +0300 Subject: [PATCH 011/682] emrtd: Add kseed calc, fix kmrz calc --- client/src/cmdhfemrtd.c | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/client/src/cmdhfemrtd.c b/client/src/cmdhfemrtd.c index 1be269c67..91f97d001 100644 --- a/client/src/cmdhfemrtd.c +++ b/client/src/cmdhfemrtd.c @@ -19,6 +19,7 @@ #include "cmdhf14a.h" #include "protocols.h" // definitions of ISO14A/7816 protocol #include "emv/apduinfo.h" // GetAPDUCodeDescription +#include "sha1.h" // KSeed calculation #define TIMEOUT 2000 @@ -254,6 +255,9 @@ int infoHF_EMRTD(char *documentnumber, char *dob, char *expiry) { PrintAndLogEx(INFO, "EF_DG1: %s", sprint_hex(response, resplen)); } } + PrintAndLogEx(INFO, "doc: %s", documentnumber); + PrintAndLogEx(INFO, "dob: %s", dob); + PrintAndLogEx(INFO, "exp: %s", expiry); char documentnumbercd = calculate_check_digit(documentnumber); char dobcd = calculate_check_digit(dob); @@ -263,6 +267,10 @@ int infoHF_EMRTD(char *documentnumber, char *dob, char *expiry) { sprintf(kmrz, "%s%i%s%i%s%i", documentnumber, documentnumbercd, dob, dobcd, expiry, expirycd); PrintAndLogEx(INFO, "kmrz: %s", kmrz); + unsigned char kseed[20] = {0x00}; + mbedtls_sha1((unsigned char *)kmrz, strlen(kmrz), kseed); + PrintAndLogEx(INFO, "kseed: %s", sprint_hex_inrow(kseed, 16)); + DropField(); return PM3_SUCCESS; } @@ -283,9 +291,9 @@ static int cmd_hf_emrtd_info(const char *Cmd) { }; CLIExecWithReturn(ctx, Cmd, argtable, true); - uint8_t docnum[9]; - uint8_t dob[6]; - uint8_t expiry[6]; + uint8_t docnum[10]; + uint8_t dob[7]; + uint8_t expiry[7]; int docnumlen = sizeof(docnum); int doblen = sizeof(dob); int expirylen = sizeof(expiry); From 49e4321382611d01a303f1c9ad6b78eb2aa39fb6 Mon Sep 17 00:00:00 2001 From: Ave Date: Mon, 7 Dec 2020 01:17:03 +0300 Subject: [PATCH 012/682] emrtd: Get challenge also some code "cleanup" which makes this whole shit less mem safe but shh --- client/src/cmdhfemrtd.c | 60 ++++++++++++++++++++++++++++++++++------- 1 file changed, 51 insertions(+), 9 deletions(-) diff --git a/client/src/cmdhfemrtd.c b/client/src/cmdhfemrtd.c index 91f97d001..77ce7adc8 100644 --- a/client/src/cmdhfemrtd.c +++ b/client/src/cmdhfemrtd.c @@ -151,7 +151,39 @@ static int asn1fieldlength(uint8_t *datain, int datainlen) { return false; } -static int _read_binary(int offset, int bytes_to_read, uint8_t *dataout, int maxdataoutlen, int *dataoutlen) { +static int get_challenge(int length, uint8_t *dataout, int *dataoutlen) { + bool activate_field = false; + bool keep_field_on = true; + uint8_t response[PM3_CMD_DATA_SIZE]; + int resplen = 0; + + char cmd[50]; + sprintf(cmd, "00%s0000%02X", GET_CHALLENGE, length); + PrintAndLogEx(INFO, "Sending: %s", cmd); + + uint8_t aGET_CHALLENGE[80]; + int aGET_CHALLENGE_n = 0; + param_gethex_to_eol(cmd, 0, aGET_CHALLENGE, sizeof(aGET_CHALLENGE), &aGET_CHALLENGE_n); + int res = ExchangeAPDU14a(aGET_CHALLENGE, aGET_CHALLENGE_n, activate_field, keep_field_on, response, sizeof(response), &resplen); + if (res) { + DropField(); + return false; + } + PrintAndLogEx(INFO, "Response: %s", sprint_hex(response, resplen)); + + // drop sw + memcpy(dataout, &response, resplen - 2); + *dataoutlen = (resplen - 2); + + uint16_t sw = get_sw(response, resplen); + if (sw != 0x9000) { + PrintAndLogEx(ERR, "Getting challenge failed (%04x - %s).", sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff)); + return false; + } + return true; +} + +static int _read_binary(int offset, int bytes_to_read, uint8_t *dataout, int *dataoutlen) { bool activate_field = false; bool keep_field_on = true; uint8_t response[PM3_CMD_DATA_SIZE]; @@ -183,13 +215,13 @@ static int _read_binary(int offset, int bytes_to_read, uint8_t *dataout, int max return true; } -static int read_file(uint8_t *dataout, int maxdataoutlen, int *dataoutlen) { +static int read_file(uint8_t *dataout, int *dataoutlen) { uint8_t response[PM3_CMD_DATA_SIZE]; int resplen = 0; uint8_t tempresponse[PM3_CMD_DATA_SIZE]; int tempresplen = 0; - if (!_read_binary(0, 4, response, sizeof(response), &resplen)) { + if (!_read_binary(0, 4, response, &resplen)) { return false; } @@ -204,7 +236,7 @@ static int read_file(uint8_t *dataout, int maxdataoutlen, int *dataoutlen) { toread = 118; } - if (!_read_binary(offset, toread, tempresponse, sizeof(tempresponse), &tempresplen)) { + if (!_read_binary(offset, toread, tempresponse, &tempresplen)) { return false; } @@ -221,12 +253,13 @@ static int read_file(uint8_t *dataout, int maxdataoutlen, int *dataoutlen) { int infoHF_EMRTD(char *documentnumber, char *dob, char *expiry) { uint8_t response[PM3_CMD_DATA_SIZE]; + uint8_t challenge[8]; int resplen = 0; // bool BAC = true; // Select and read EF_CardAccess if (select_file(P1_SELECT_BY_EF, EF_CARDACCESS, true, true)) { - read_file(response, sizeof(response), &resplen); + read_file(response, &resplen); PrintAndLogEx(INFO, "EF_CardAccess: %s", sprint_hex(response, resplen)); } else { PrintAndLogEx(INFO, "PACE unsupported. Will not read EF_CardAccess."); @@ -235,6 +268,7 @@ int infoHF_EMRTD(char *documentnumber, char *dob, char *expiry) { // Select MRTD applet if (select_file(P1_SELECT_BY_NAME, AID_MRTD, false, true) == false) { PrintAndLogEx(ERR, "Couldn't select the MRTD application."); + DropField(); return PM3_ESOFT; } @@ -247,7 +281,7 @@ int infoHF_EMRTD(char *documentnumber, char *dob, char *expiry) { // Select EF_DG1 select_file(P1_SELECT_BY_EF, EF_DG1, false, true); - if (read_file(response, sizeof(response), &resplen) == false) { + if (read_file(response, &resplen) == false) { // BAC = true; PrintAndLogEx(INFO, "Basic Access Control is enforced. Will attempt auth."); } else { @@ -271,6 +305,14 @@ int infoHF_EMRTD(char *documentnumber, char *dob, char *expiry) { mbedtls_sha1((unsigned char *)kmrz, strlen(kmrz), kseed); PrintAndLogEx(INFO, "kseed: %s", sprint_hex_inrow(kseed, 16)); + // Get Challenge + if (get_challenge(8, challenge, &resplen) == false) { + PrintAndLogEx(ERR, "Couldn't get challenge."); + DropField(); + return PM3_ESOFT; + } + PrintAndLogEx(INFO, "challenge: %s", sprint_hex_inrow(challenge, 8)); + DropField(); return PM3_SUCCESS; } @@ -294,9 +336,9 @@ static int cmd_hf_emrtd_info(const char *Cmd) { uint8_t docnum[10]; uint8_t dob[7]; uint8_t expiry[7]; - int docnumlen = sizeof(docnum); - int doblen = sizeof(dob); - int expirylen = sizeof(expiry); + int docnumlen = 9; + int doblen = 6; + int expirylen = 6; CLIGetStrWithReturn(ctx, 1, docnum, &docnumlen); CLIGetStrWithReturn(ctx, 2, dob, &doblen); CLIGetStrWithReturn(ctx, 3, expiry, &expirylen); From b0fb5bfff64e95ce00225d0750a78f1ecb46df2f Mon Sep 17 00:00:00 2001 From: Ave Date: Mon, 7 Dec 2020 01:38:39 +0300 Subject: [PATCH 013/682] emrtd: Reduce code repetition --- client/src/cmdhfemrtd.c | 83 ++++++++++++----------------------------- 1 file changed, 23 insertions(+), 60 deletions(-) diff --git a/client/src/cmdhfemrtd.c b/client/src/cmdhfemrtd.c index 77ce7adc8..17d12e08e 100644 --- a/client/src/cmdhfemrtd.c +++ b/client/src/cmdhfemrtd.c @@ -49,20 +49,16 @@ static uint16_t get_sw(uint8_t *d, uint8_t n) { return d[n] * 0x0100 + d[n + 1]; } -static int select_file(const char *select_by, const char *file_id, bool activate_field, bool keep_field_on) { +static int exchange_commands(const char *cmd, uint8_t *dataout, int *dataoutlen, bool activate_field, bool keep_field_on) { uint8_t response[PM3_CMD_DATA_SIZE]; int resplen = 0; - size_t file_id_len = strlen(file_id) / 2; - - char cmd[50]; - sprintf(cmd, "00%s%s0C%02lu%s", SELECT, select_by, file_id_len, file_id); PrintAndLogEx(INFO, "Sending: %s", cmd); - uint8_t aSELECT_FILE[80]; - int aSELECT_FILE_n = 0; - param_gethex_to_eol(cmd, 0, aSELECT_FILE, sizeof(aSELECT_FILE), &aSELECT_FILE_n); - int res = ExchangeAPDU14a(aSELECT_FILE, aSELECT_FILE_n, activate_field, keep_field_on, response, sizeof(response), &resplen); + uint8_t aCMD[80]; + int aCMD_n = 0; + param_gethex_to_eol(cmd, 0, aCMD, sizeof(aCMD), &aCMD_n); + int res = ExchangeAPDU14a(aCMD, aCMD_n, activate_field, keep_field_on, response, sizeof(response), &resplen); if (res) { DropField(); return false; @@ -73,9 +69,13 @@ static int select_file(const char *select_by, const char *file_id, bool activate } PrintAndLogEx(INFO, "Response: %s", sprint_hex(response, resplen)); + // drop sw + memcpy(dataout, &response, resplen - 2); + *dataoutlen = (resplen - 2); + uint16_t sw = get_sw(response, resplen); if (sw != 0x9000) { - PrintAndLogEx(ERR, "Selecting file failed (%04x - %s).", sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff)); + PrintAndLogEx(ERR, "Command %s failed (%04x - %s).", cmd, sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff)); return false; } return true; @@ -151,68 +151,31 @@ static int asn1fieldlength(uint8_t *datain, int datainlen) { return false; } -static int get_challenge(int length, uint8_t *dataout, int *dataoutlen) { - bool activate_field = false; - bool keep_field_on = true; +static int select_file(const char *select_by, const char *file_id, bool activate_field, bool keep_field_on) { + size_t file_id_len = strlen(file_id) / 2; + + // Get data even tho we'll not use it uint8_t response[PM3_CMD_DATA_SIZE]; int resplen = 0; + char cmd[50]; + sprintf(cmd, "00%s%s0C%02lu%s", SELECT, select_by, file_id_len, file_id); + + return exchange_commands(cmd, response, &resplen, activate_field, keep_field_on); +} + +static int get_challenge(int length, uint8_t *dataout, int *dataoutlen) { char cmd[50]; sprintf(cmd, "00%s0000%02X", GET_CHALLENGE, length); - PrintAndLogEx(INFO, "Sending: %s", cmd); - uint8_t aGET_CHALLENGE[80]; - int aGET_CHALLENGE_n = 0; - param_gethex_to_eol(cmd, 0, aGET_CHALLENGE, sizeof(aGET_CHALLENGE), &aGET_CHALLENGE_n); - int res = ExchangeAPDU14a(aGET_CHALLENGE, aGET_CHALLENGE_n, activate_field, keep_field_on, response, sizeof(response), &resplen); - if (res) { - DropField(); - return false; - } - PrintAndLogEx(INFO, "Response: %s", sprint_hex(response, resplen)); - - // drop sw - memcpy(dataout, &response, resplen - 2); - *dataoutlen = (resplen - 2); - - uint16_t sw = get_sw(response, resplen); - if (sw != 0x9000) { - PrintAndLogEx(ERR, "Getting challenge failed (%04x - %s).", sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff)); - return false; - } - return true; + return exchange_commands(cmd, dataout, dataoutlen, false, true); } static int _read_binary(int offset, int bytes_to_read, uint8_t *dataout, int *dataoutlen) { - bool activate_field = false; - bool keep_field_on = true; - uint8_t response[PM3_CMD_DATA_SIZE]; - int resplen = 0; - char cmd[50]; sprintf(cmd, "00%s%04i%02i", READ_BINARY, offset, bytes_to_read); - PrintAndLogEx(INFO, "Sending: %s", cmd); - uint8_t aREAD_BINARY[80]; - int aREAD_BINARY_n = 0; - param_gethex_to_eol(cmd, 0, aREAD_BINARY, sizeof(aREAD_BINARY), &aREAD_BINARY_n); - int res = ExchangeAPDU14a(aREAD_BINARY, aREAD_BINARY_n, activate_field, keep_field_on, response, sizeof(response), &resplen); - if (res) { - DropField(); - return false; - } - PrintAndLogEx(INFO, "Response: %s", sprint_hex(response, resplen)); - - // drop sw - memcpy(dataout, &response, resplen - 2); - *dataoutlen = (resplen - 2); - - uint16_t sw = get_sw(response, resplen); - if (sw != 0x9000) { - PrintAndLogEx(ERR, "Reading binary failed (%04x - %s).", sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff)); - return false; - } - return true; + return exchange_commands(cmd, dataout, dataoutlen, false, true); } static int read_file(uint8_t *dataout, int *dataoutlen) { From a7478443b31c6a066528462de76c24a7ed8df901 Mon Sep 17 00:00:00 2001 From: Ave Date: Wed, 9 Dec 2020 01:15:09 +0300 Subject: [PATCH 014/682] emrtd: calc kenc and kmac --- client/src/cmdhfemrtd.c | 45 ++++++++++++++++++++++++++++++++++++----- 1 file changed, 40 insertions(+), 5 deletions(-) diff --git a/client/src/cmdhfemrtd.c b/client/src/cmdhfemrtd.c index 17d12e08e..75aafed3b 100644 --- a/client/src/cmdhfemrtd.c +++ b/client/src/cmdhfemrtd.c @@ -11,15 +11,17 @@ #include "cmdhfemrtd.h" #include #include "fileutils.h" -#include "cmdparser.h" // command_t -#include "comms.h" // clearCommandBuffer +#include "cmdparser.h" // command_t +#include "comms.h" // clearCommandBuffer #include "cmdtrace.h" #include "cliparser.h" #include "crc16.h" #include "cmdhf14a.h" -#include "protocols.h" // definitions of ISO14A/7816 protocol -#include "emv/apduinfo.h" // GetAPDUCodeDescription -#include "sha1.h" // KSeed calculation +#include "protocols.h" // definitions of ISO14A/7816 protocol +#include "emv/apduinfo.h" // GetAPDUCodeDescription +#include "sha1.h" // KSeed calculation etc +#include "mifare/desfire_crypto.h" // des_encrypt/des_decrypt +#include "des.h" // mbedtls_des_key_set_parity #define TIMEOUT 2000 @@ -151,6 +153,29 @@ static int asn1fieldlength(uint8_t *datain, int datainlen) { return false; } + +static void deskey(uint8_t *seed, uint8_t *type, int length, uint8_t *dataout) { + PrintAndLogEx(INFO, "seed: %s", sprint_hex_inrow(seed, 16)); + + // combine seed and type + uint8_t data[50]; + memcpy(data, seed, 16); + memcpy(data + 16, type, 4); + PrintAndLogEx(INFO, "data: %s", sprint_hex_inrow(data, 20)); + + // SHA1 the key + unsigned char key[20]; + mbedtls_sha1(data, 20, key); + PrintAndLogEx(INFO, "key: %s", sprint_hex_inrow(key, 20)); + + // Set parity bits + mbedtls_des_key_set_parity(key); + mbedtls_des_key_set_parity(key + 8); + PrintAndLogEx(INFO, "post-parity key: %s", sprint_hex_inrow(key, 20)); + + memcpy(dataout, &key, length); +} + static int select_file(const char *select_by, const char *file_id, bool activate_field, bool keep_field_on) { size_t file_id_len = strlen(file_id) / 2; @@ -217,6 +242,11 @@ static int read_file(uint8_t *dataout, int *dataoutlen) { int infoHF_EMRTD(char *documentnumber, char *dob, char *expiry) { uint8_t response[PM3_CMD_DATA_SIZE]; uint8_t challenge[8]; + // TODO: get these _types into a better spot + uint8_t KENC_type[4] = {0x00, 0x00, 0x00, 0x01}; + uint8_t KMAC_type[4] = {0x00, 0x00, 0x00, 0x02}; + uint8_t kenc[50]; + uint8_t kmac[50]; int resplen = 0; // bool BAC = true; @@ -268,6 +298,11 @@ int infoHF_EMRTD(char *documentnumber, char *dob, char *expiry) { mbedtls_sha1((unsigned char *)kmrz, strlen(kmrz), kseed); PrintAndLogEx(INFO, "kseed: %s", sprint_hex_inrow(kseed, 16)); + deskey(kseed, KENC_type, 16, kenc); + deskey(kseed, KMAC_type, 16, kmac); + PrintAndLogEx(INFO, "kenc: %s", sprint_hex_inrow(kenc, 16)); + PrintAndLogEx(INFO, "kmac: %s", sprint_hex_inrow(kmac, 16)); + // Get Challenge if (get_challenge(8, challenge, &resplen) == false) { PrintAndLogEx(ERR, "Couldn't get challenge."); From 69be5f8b253df22ac4bc40aa26202f710ee57c98 Mon Sep 17 00:00:00 2001 From: Ave Date: Wed, 9 Dec 2020 04:48:17 +0300 Subject: [PATCH 015/682] emrtd: calculate S and e_ifd --- client/src/cmdhfemrtd.c | 43 +++++++++++++++++++++++++++++++++++------ 1 file changed, 37 insertions(+), 6 deletions(-) diff --git a/client/src/cmdhfemrtd.c b/client/src/cmdhfemrtd.c index 75aafed3b..5840c875b 100644 --- a/client/src/cmdhfemrtd.c +++ b/client/src/cmdhfemrtd.c @@ -8,6 +8,8 @@ // High frequency Electronic Machine Readable Travel Document commands //----------------------------------------------------------------------------- +// This code is heavily based on mrpkey.py of RFIDIOt + #include "cmdhfemrtd.h" #include #include "fileutils.h" @@ -27,6 +29,7 @@ // ISO7816 commands #define SELECT "A4" +#define EXTERNAL_AUTHENTICATE "82" #define GET_CHALLENGE "84" #define READ_BINARY "B0" #define P1_SELECT_BY_EF "02" @@ -241,14 +244,18 @@ static int read_file(uint8_t *dataout, int *dataoutlen) { int infoHF_EMRTD(char *documentnumber, char *dob, char *expiry) { uint8_t response[PM3_CMD_DATA_SIZE]; - uint8_t challenge[8]; - // TODO: get these _types into a better spot - uint8_t KENC_type[4] = {0x00, 0x00, 0x00, 0x01}; - uint8_t KMAC_type[4] = {0x00, 0x00, 0x00, 0x02}; + uint8_t rnd_ic[8]; uint8_t kenc[50]; uint8_t kmac[50]; int resplen = 0; // bool BAC = true; + uint8_t S[32]; + // TODO: Code sponsored jointly by duracell and sony + uint8_t rnd_ifd[8] = {0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA}; + uint8_t k_ifd[16] = {0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA}; + // TODO: get these _types into a better spot + uint8_t KENC_type[4] = {0x00, 0x00, 0x00, 0x01}; + uint8_t KMAC_type[4] = {0x00, 0x00, 0x00, 0x02}; // Select and read EF_CardAccess if (select_file(P1_SELECT_BY_EF, EF_CARDACCESS, true, true)) { @@ -304,12 +311,36 @@ int infoHF_EMRTD(char *documentnumber, char *dob, char *expiry) { PrintAndLogEx(INFO, "kmac: %s", sprint_hex_inrow(kmac, 16)); // Get Challenge - if (get_challenge(8, challenge, &resplen) == false) { + if (get_challenge(8, rnd_ic, &resplen) == false) { PrintAndLogEx(ERR, "Couldn't get challenge."); DropField(); return PM3_ESOFT; } - PrintAndLogEx(INFO, "challenge: %s", sprint_hex_inrow(challenge, 8)); + PrintAndLogEx(INFO, "rnd_ic: %s", sprint_hex_inrow(rnd_ic, 8)); + + memcpy(S, rnd_ifd, 8); + memcpy(S + 8, rnd_ic, 8); + memcpy(S + 16, k_ifd, 16); + + mbedtls_des3_context ctx; + mbedtls_des3_set2key_enc(&ctx, kenc); + + uint8_t iv[8] = { 0x00 }; + uint8_t e_ifd[8] = { 0x00 }; + + mbedtls_des3_crypt_cbc(&ctx // des3_context + , MBEDTLS_DES_ENCRYPT // int mode + , sizeof(S) // length + , iv // iv[8] + , S // input + , e_ifd // output + ); + + // TODO: get m_ifd by ISO 9797-1 Algo 3(e_ifd, m_mac) + // TODO: get cmd_data by e_ifd + m_ifd + // TODO: iso_7816_external_authenticate(passport.ToHex(cmd_data),Kmac) + + PrintAndLogEx(INFO, "S: %s", sprint_hex_inrow(S, 32)); DropField(); return PM3_SUCCESS; From 6086ede2ed66dff1a4bf9d98fc421eaa3e0be8f3 Mon Sep 17 00:00:00 2001 From: Ave Date: Thu, 10 Dec 2020 22:53:01 +0300 Subject: [PATCH 016/682] emrtd: split 3des encryption to its own func --- client/src/cmdhfemrtd.c | 33 ++++++++++++++++++++++----------- 1 file changed, 22 insertions(+), 11 deletions(-) diff --git a/client/src/cmdhfemrtd.c b/client/src/cmdhfemrtd.c index 5840c875b..d941ed36c 100644 --- a/client/src/cmdhfemrtd.c +++ b/client/src/cmdhfemrtd.c @@ -156,6 +156,18 @@ static int asn1fieldlength(uint8_t *datain, int datainlen) { return false; } +static void des3_encrypt(uint8_t *iv, uint8_t *key, uint8_t *input, uint8_t *output) { + mbedtls_des3_context ctx; + mbedtls_des3_set2key_enc(&ctx, key); + + mbedtls_des3_crypt_cbc(&ctx // des3_context + , MBEDTLS_DES_ENCRYPT // int mode + , sizeof(input) // length + , iv // iv[8] + , input // input + , output // output + ); +} static void deskey(uint8_t *seed, uint8_t *type, int length, uint8_t *dataout) { PrintAndLogEx(INFO, "seed: %s", sprint_hex_inrow(seed, 16)); @@ -199,6 +211,13 @@ static int get_challenge(int length, uint8_t *dataout, int *dataoutlen) { return exchange_commands(cmd, dataout, dataoutlen, false, true); } +// static int external_authenticate(const char *response, int length, uint8_t *dataout, int *dataoutlen) { +// char cmd[50]; +// sprintf(cmd, "00%s00%02i%02X%02i", EXTERNAL_AUTHENTICATE, length, sprint_hex_inrow(response, length), length); + +// return exchange_commands(cmd, dataout, dataoutlen, false, true); +// } + static int _read_binary(int offset, int bytes_to_read, uint8_t *dataout, int *dataoutlen) { char cmd[50]; sprintf(cmd, "00%s%04i%02i", READ_BINARY, offset, bytes_to_read); @@ -322,26 +341,18 @@ int infoHF_EMRTD(char *documentnumber, char *dob, char *expiry) { memcpy(S + 8, rnd_ic, 8); memcpy(S + 16, k_ifd, 16); - mbedtls_des3_context ctx; - mbedtls_des3_set2key_enc(&ctx, kenc); + PrintAndLogEx(INFO, "S: %s", sprint_hex_inrow(S, 32)); uint8_t iv[8] = { 0x00 }; uint8_t e_ifd[8] = { 0x00 }; - mbedtls_des3_crypt_cbc(&ctx // des3_context - , MBEDTLS_DES_ENCRYPT // int mode - , sizeof(S) // length - , iv // iv[8] - , S // input - , e_ifd // output - ); + des3_encrypt(iv, kenc, S, e_ifd); + PrintAndLogEx(INFO, "e_ifd: %s", sprint_hex_inrow(e_ifd, 8)); // TODO: get m_ifd by ISO 9797-1 Algo 3(e_ifd, m_mac) // TODO: get cmd_data by e_ifd + m_ifd // TODO: iso_7816_external_authenticate(passport.ToHex(cmd_data),Kmac) - PrintAndLogEx(INFO, "S: %s", sprint_hex_inrow(S, 32)); - DropField(); return PM3_SUCCESS; } From ca04c44384f827605b1d7b0517be0f22cfda50c3 Mon Sep 17 00:00:00 2001 From: Ave Date: Fri, 11 Dec 2020 04:52:29 +0300 Subject: [PATCH 017/682] emrtd: Implement retail_mac and external authentication --- client/src/cmdhfemrtd.c | 98 +++++++++++++++++++++++++++++++++++------ 1 file changed, 84 insertions(+), 14 deletions(-) diff --git a/client/src/cmdhfemrtd.c b/client/src/cmdhfemrtd.c index d941ed36c..4aa9670de 100644 --- a/client/src/cmdhfemrtd.c +++ b/client/src/cmdhfemrtd.c @@ -60,7 +60,7 @@ static int exchange_commands(const char *cmd, uint8_t *dataout, int *dataoutlen, PrintAndLogEx(INFO, "Sending: %s", cmd); - uint8_t aCMD[80]; + uint8_t aCMD[100]; int aCMD_n = 0; param_gethex_to_eol(cmd, 0, aCMD, sizeof(aCMD), &aCMD_n); int res = ExchangeAPDU14a(aCMD, aCMD_n, activate_field, keep_field_on, response, sizeof(response), &resplen); @@ -156,19 +156,76 @@ static int asn1fieldlength(uint8_t *datain, int datainlen) { return false; } -static void des3_encrypt(uint8_t *iv, uint8_t *key, uint8_t *input, uint8_t *output) { +static void des_encrypt_ecb(uint8_t *key, uint8_t *input, uint8_t *output) { + mbedtls_des_context ctx_enc; + mbedtls_des_setkey_enc(&ctx_enc, key); + mbedtls_des_crypt_ecb(&ctx_enc, input, output); + mbedtls_des_free(&ctx_enc); +} + +static void des_decrypt_ecb(uint8_t *key, uint8_t *input, uint8_t *output) { + mbedtls_des_context ctx_dec; + mbedtls_des_setkey_dec(&ctx_dec, key); + mbedtls_des_crypt_ecb(&ctx_dec, input, output); + mbedtls_des_free(&ctx_dec); +} + +static void des3_encrypt_cbc(uint8_t *iv, uint8_t *key, uint8_t *input, int inputlen, uint8_t *output) { mbedtls_des3_context ctx; mbedtls_des3_set2key_enc(&ctx, key); mbedtls_des3_crypt_cbc(&ctx // des3_context , MBEDTLS_DES_ENCRYPT // int mode - , sizeof(input) // length + , inputlen // length , iv // iv[8] , input // input , output // output ); + mbedtls_des3_free(&ctx); } +static void retail_mac(uint8_t *key, uint8_t *input, uint8_t *output) { + // This code assumes blocklength (n) = 8, and input len of 32 chars + // This code takes inspirations from https://github.com/devinvenable/iso9797algorithm3 + uint8_t k0[8]; + uint8_t k1[8]; + uint8_t intermediate[8] = {0x00}; + uint8_t intermediate_des[32]; + uint8_t block[8]; + uint8_t message[40]; + uint8_t padding[8] = {0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; + + // Populate keys + memcpy(k0, key, 8); + memcpy(k1, key + 8, 8); + + // Prepare message + memcpy(message, input, 32); + // Normally this isn't how it works, but it's what mrpkey does... + memcpy(message + 32, padding, 8); + + // Do chaining and encryption + for (int i = 0; i < (sizeof(message) / 8); i++) { + memcpy(block, message + (i * 8), 8); + + // XOR + for (int x = 0; x < 8; x++) { + intermediate[x] = intermediate[x] ^ block[x]; + } + + des_encrypt_ecb(k0, intermediate, intermediate_des); + memcpy(intermediate, intermediate_des, 8); + } + + + des_decrypt_ecb(k1, intermediate, intermediate_des); + memcpy(intermediate, intermediate_des, 8); + + des_encrypt_ecb(k0, intermediate, intermediate_des); + memcpy(output, intermediate_des, 8); +} + + static void deskey(uint8_t *seed, uint8_t *type, int length, uint8_t *dataout) { PrintAndLogEx(INFO, "seed: %s", sprint_hex_inrow(seed, 16)); @@ -211,12 +268,13 @@ static int get_challenge(int length, uint8_t *dataout, int *dataoutlen) { return exchange_commands(cmd, dataout, dataoutlen, false, true); } -// static int external_authenticate(const char *response, int length, uint8_t *dataout, int *dataoutlen) { -// char cmd[50]; -// sprintf(cmd, "00%s00%02i%02X%02i", EXTERNAL_AUTHENTICATE, length, sprint_hex_inrow(response, length), length); +static int external_authenticate(uint8_t *data, int length, uint8_t *dataout, int *dataoutlen) { + char cmd[100]; -// return exchange_commands(cmd, dataout, dataoutlen, false, true); -// } + sprintf(cmd, "00%s0000%02X%s%02X", EXTERNAL_AUTHENTICATE, length, sprint_hex_inrow(data, length), length); + + return exchange_commands(cmd, dataout, dataoutlen, false, true); +} static int _read_binary(int offset, int bytes_to_read, uint8_t *dataout, int *dataoutlen) { char cmd[50]; @@ -344,14 +402,26 @@ int infoHF_EMRTD(char *documentnumber, char *dob, char *expiry) { PrintAndLogEx(INFO, "S: %s", sprint_hex_inrow(S, 32)); uint8_t iv[8] = { 0x00 }; - uint8_t e_ifd[8] = { 0x00 }; + uint8_t e_ifd[32] = { 0x00 }; - des3_encrypt(iv, kenc, S, e_ifd); - PrintAndLogEx(INFO, "e_ifd: %s", sprint_hex_inrow(e_ifd, 8)); + des3_encrypt_cbc(iv, kenc, S, sizeof(S), e_ifd); + PrintAndLogEx(INFO, "e_ifd: %s", sprint_hex_inrow(e_ifd, 32)); - // TODO: get m_ifd by ISO 9797-1 Algo 3(e_ifd, m_mac) - // TODO: get cmd_data by e_ifd + m_ifd - // TODO: iso_7816_external_authenticate(passport.ToHex(cmd_data),Kmac) + uint8_t m_ifd[8] = { 0x00 }; + + retail_mac(kmac, e_ifd, m_ifd); + PrintAndLogEx(INFO, "m_ifd: %s", sprint_hex_inrow(m_ifd, 8)); + + uint8_t cmd_data[40]; + memcpy(cmd_data, e_ifd, 32); + memcpy(cmd_data + 32, m_ifd, 8); + + // Do external authentication + if (external_authenticate(cmd_data, sizeof(cmd_data), response, &resplen) == false) { + PrintAndLogEx(ERR, "Couldn't do external authentication. Did you supply the correct MRZ info?"); + DropField(); + return PM3_ESOFT; + } DropField(); return PM3_SUCCESS; From 332b67655c6aca4ae29054957eb0461fe239f146 Mon Sep 17 00:00:00 2001 From: Ave Date: Fri, 11 Dec 2020 05:38:14 +0300 Subject: [PATCH 018/682] emrtd: Improve logging --- client/src/cmdhfemrtd.c | 41 +++++++++++++++++++++-------------------- 1 file changed, 21 insertions(+), 20 deletions(-) diff --git a/client/src/cmdhfemrtd.c b/client/src/cmdhfemrtd.c index 4aa9670de..3145dd6e6 100644 --- a/client/src/cmdhfemrtd.c +++ b/client/src/cmdhfemrtd.c @@ -58,7 +58,7 @@ static int exchange_commands(const char *cmd, uint8_t *dataout, int *dataoutlen, uint8_t response[PM3_CMD_DATA_SIZE]; int resplen = 0; - PrintAndLogEx(INFO, "Sending: %s", cmd); + PrintAndLogEx(DEBUG, "Sending: %s", cmd); uint8_t aCMD[100]; int aCMD_n = 0; @@ -72,7 +72,7 @@ static int exchange_commands(const char *cmd, uint8_t *dataout, int *dataoutlen, if (resplen < 2) { return false; } - PrintAndLogEx(INFO, "Response: %s", sprint_hex(response, resplen)); + PrintAndLogEx(DEBUG, "Response: %s", sprint_hex(response, resplen)); // drop sw memcpy(dataout, &response, resplen - 2); @@ -80,7 +80,7 @@ static int exchange_commands(const char *cmd, uint8_t *dataout, int *dataoutlen, uint16_t sw = get_sw(response, resplen); if (sw != 0x9000) { - PrintAndLogEx(ERR, "Command %s failed (%04x - %s).", cmd, sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff)); + PrintAndLogEx(DEBUG, "Command %s failed (%04x - %s).", cmd, sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff)); return false; } return true; @@ -227,23 +227,23 @@ static void retail_mac(uint8_t *key, uint8_t *input, uint8_t *output) { static void deskey(uint8_t *seed, uint8_t *type, int length, uint8_t *dataout) { - PrintAndLogEx(INFO, "seed: %s", sprint_hex_inrow(seed, 16)); + PrintAndLogEx(DEBUG, "seed: %s", sprint_hex_inrow(seed, 16)); // combine seed and type uint8_t data[50]; memcpy(data, seed, 16); memcpy(data + 16, type, 4); - PrintAndLogEx(INFO, "data: %s", sprint_hex_inrow(data, 20)); + PrintAndLogEx(DEBUG, "data: %s", sprint_hex_inrow(data, 20)); // SHA1 the key unsigned char key[20]; mbedtls_sha1(data, 20, key); - PrintAndLogEx(INFO, "key: %s", sprint_hex_inrow(key, 20)); + PrintAndLogEx(DEBUG, "key: %s", sprint_hex_inrow(key, 20)); // Set parity bits mbedtls_des_key_set_parity(key); mbedtls_des_key_set_parity(key + 8); - PrintAndLogEx(INFO, "post-parity key: %s", sprint_hex_inrow(key, 20)); + PrintAndLogEx(DEBUG, "post-parity key: %s", sprint_hex_inrow(key, 20)); memcpy(dataout, &key, length); } @@ -352,7 +352,7 @@ int infoHF_EMRTD(char *documentnumber, char *dob, char *expiry) { // Select EF_COM if (select_file(P1_SELECT_BY_EF, EF_COM, false, true) == false) { // BAC = true; - PrintAndLogEx(INFO, "Basic Access Control is enforced. Will attempt auth."); + PrintAndLogEx(INFO, "Basic Access Control is enforced. Will attempt external authentication."); } else { // BAC = false; // Select EF_DG1 @@ -360,15 +360,15 @@ int infoHF_EMRTD(char *documentnumber, char *dob, char *expiry) { if (read_file(response, &resplen) == false) { // BAC = true; - PrintAndLogEx(INFO, "Basic Access Control is enforced. Will attempt auth."); + PrintAndLogEx(INFO, "Basic Access Control is enforced. Will attempt external authentication."); } else { // BAC = false; PrintAndLogEx(INFO, "EF_DG1: %s", sprint_hex(response, resplen)); } } - PrintAndLogEx(INFO, "doc: %s", documentnumber); - PrintAndLogEx(INFO, "dob: %s", dob); - PrintAndLogEx(INFO, "exp: %s", expiry); + PrintAndLogEx(DEBUG, "doc: %s", documentnumber); + PrintAndLogEx(DEBUG, "dob: %s", dob); + PrintAndLogEx(DEBUG, "exp: %s", expiry); char documentnumbercd = calculate_check_digit(documentnumber); char dobcd = calculate_check_digit(dob); @@ -376,16 +376,16 @@ int infoHF_EMRTD(char *documentnumber, char *dob, char *expiry) { char kmrz[25]; sprintf(kmrz, "%s%i%s%i%s%i", documentnumber, documentnumbercd, dob, dobcd, expiry, expirycd); - PrintAndLogEx(INFO, "kmrz: %s", kmrz); + PrintAndLogEx(DEBUG, "kmrz: %s", kmrz); unsigned char kseed[20] = {0x00}; mbedtls_sha1((unsigned char *)kmrz, strlen(kmrz), kseed); - PrintAndLogEx(INFO, "kseed: %s", sprint_hex_inrow(kseed, 16)); + PrintAndLogEx(DEBUG, "kseed: %s", sprint_hex_inrow(kseed, 16)); deskey(kseed, KENC_type, 16, kenc); deskey(kseed, KMAC_type, 16, kmac); - PrintAndLogEx(INFO, "kenc: %s", sprint_hex_inrow(kenc, 16)); - PrintAndLogEx(INFO, "kmac: %s", sprint_hex_inrow(kmac, 16)); + PrintAndLogEx(DEBUG, "kenc: %s", sprint_hex_inrow(kenc, 16)); + PrintAndLogEx(DEBUG, "kmac: %s", sprint_hex_inrow(kmac, 16)); // Get Challenge if (get_challenge(8, rnd_ic, &resplen) == false) { @@ -393,24 +393,24 @@ int infoHF_EMRTD(char *documentnumber, char *dob, char *expiry) { DropField(); return PM3_ESOFT; } - PrintAndLogEx(INFO, "rnd_ic: %s", sprint_hex_inrow(rnd_ic, 8)); + PrintAndLogEx(DEBUG, "rnd_ic: %s", sprint_hex_inrow(rnd_ic, 8)); memcpy(S, rnd_ifd, 8); memcpy(S + 8, rnd_ic, 8); memcpy(S + 16, k_ifd, 16); - PrintAndLogEx(INFO, "S: %s", sprint_hex_inrow(S, 32)); + PrintAndLogEx(DEBUG, "S: %s", sprint_hex_inrow(S, 32)); uint8_t iv[8] = { 0x00 }; uint8_t e_ifd[32] = { 0x00 }; des3_encrypt_cbc(iv, kenc, S, sizeof(S), e_ifd); - PrintAndLogEx(INFO, "e_ifd: %s", sprint_hex_inrow(e_ifd, 32)); + PrintAndLogEx(DEBUG, "e_ifd: %s", sprint_hex_inrow(e_ifd, 32)); uint8_t m_ifd[8] = { 0x00 }; retail_mac(kmac, e_ifd, m_ifd); - PrintAndLogEx(INFO, "m_ifd: %s", sprint_hex_inrow(m_ifd, 8)); + PrintAndLogEx(DEBUG, "m_ifd: %s", sprint_hex_inrow(m_ifd, 8)); uint8_t cmd_data[40]; memcpy(cmd_data, e_ifd, 32); @@ -422,6 +422,7 @@ int infoHF_EMRTD(char *documentnumber, char *dob, char *expiry) { DropField(); return PM3_ESOFT; } + PrintAndLogEx(INFO, "External authentication successful."); DropField(); return PM3_SUCCESS; From 70ecfdf50295481f1516bd94919c373566b17312 Mon Sep 17 00:00:00 2001 From: Ave Date: Fri, 11 Dec 2020 06:27:47 +0300 Subject: [PATCH 019/682] emrtd: Verify rnd_ifd --- client/src/cmdhfemrtd.c | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/client/src/cmdhfemrtd.c b/client/src/cmdhfemrtd.c index 3145dd6e6..45f1125bd 100644 --- a/client/src/cmdhfemrtd.c +++ b/client/src/cmdhfemrtd.c @@ -184,6 +184,20 @@ static void des3_encrypt_cbc(uint8_t *iv, uint8_t *key, uint8_t *input, int inpu mbedtls_des3_free(&ctx); } +static void des3_decrypt_cbc(uint8_t *iv, uint8_t *key, uint8_t *input, int inputlen, uint8_t *output) { + mbedtls_des3_context ctx; + mbedtls_des3_set2key_dec(&ctx, key); + + mbedtls_des3_crypt_cbc(&ctx // des3_context + , MBEDTLS_DES_DECRYPT // int mode + , inputlen // length + , iv // iv[8] + , input // input + , output // output + ); + mbedtls_des3_free(&ctx); +} + static void retail_mac(uint8_t *key, uint8_t *input, uint8_t *output) { // This code assumes blocklength (n) = 8, and input len of 32 chars // This code takes inspirations from https://github.com/devinvenable/iso9797algorithm3 @@ -424,6 +438,15 @@ int infoHF_EMRTD(char *documentnumber, char *dob, char *expiry) { } PrintAndLogEx(INFO, "External authentication successful."); + uint8_t dec_output[32] = { 0x00 }; + des3_decrypt_cbc(iv, kenc, response, 32, dec_output); + + if (memcmp(rnd_ifd, dec_output + 8, 8) != 0) { + PrintAndLogEx(ERR, "Challenge failed, rnd_ifd does not match."); + DropField(); + return PM3_ESOFT; + } + DropField(); return PM3_SUCCESS; } From ca3471ffdf9707d4fc155527284df10b9c55441a Mon Sep 17 00:00:00 2001 From: Ave Date: Fri, 11 Dec 2020 06:52:26 +0300 Subject: [PATCH 020/682] emrtd: calculate session keys --- client/src/cmdhfemrtd.c | 30 +++++++++++++++++++++++++++++- 1 file changed, 29 insertions(+), 1 deletion(-) diff --git a/client/src/cmdhfemrtd.c b/client/src/cmdhfemrtd.c index 45f1125bd..49c7b9645 100644 --- a/client/src/cmdhfemrtd.c +++ b/client/src/cmdhfemrtd.c @@ -392,7 +392,7 @@ int infoHF_EMRTD(char *documentnumber, char *dob, char *expiry) { sprintf(kmrz, "%s%i%s%i%s%i", documentnumber, documentnumbercd, dob, dobcd, expiry, expirycd); PrintAndLogEx(DEBUG, "kmrz: %s", kmrz); - unsigned char kseed[20] = {0x00}; + uint8_t kseed[16] = {0x00}; mbedtls_sha1((unsigned char *)kmrz, strlen(kmrz), kseed); PrintAndLogEx(DEBUG, "kseed: %s", sprint_hex_inrow(kseed, 16)); @@ -440,6 +440,7 @@ int infoHF_EMRTD(char *documentnumber, char *dob, char *expiry) { uint8_t dec_output[32] = { 0x00 }; des3_decrypt_cbc(iv, kenc, response, 32, dec_output); + PrintAndLogEx(DEBUG, "dec_output: %s", sprint_hex_inrow(dec_output, 32)); if (memcmp(rnd_ifd, dec_output + 8, 8) != 0) { PrintAndLogEx(ERR, "Challenge failed, rnd_ifd does not match."); @@ -447,6 +448,33 @@ int infoHF_EMRTD(char *documentnumber, char *dob, char *expiry) { return PM3_ESOFT; } + uint8_t ssc[8] = { 0x00 }; + uint8_t ks_enc[16] = { 0x00 }; + uint8_t ks_mac[16] = { 0x00 }; + uint8_t k_icc[16] = { 0x00 }; + memcpy(k_icc, dec_output + 16, 16); + + // Calculate session keys + for (int x = 0; x < 16; x++) { + kseed[x] = k_ifd[x] ^ k_icc[x]; + } + + PrintAndLogEx(DEBUG, "kseed: %s", sprint_hex_inrow(kseed, 16)); + + deskey(kseed, KENC_type, 16, ks_enc); + deskey(kseed, KMAC_type, 16, ks_mac); + + PrintAndLogEx(DEBUG, "ks_enc: %s", sprint_hex_inrow(ks_enc, 16)); + PrintAndLogEx(DEBUG, "ks_mac: %s", sprint_hex_inrow(ks_mac, 16)); + + memcpy(ssc, rnd_ic + 4, 4); + memcpy(ssc + 4, rnd_ifd + 4, 4); + + PrintAndLogEx(DEBUG, "ssc: %s", sprint_hex_inrow(ssc, 8)); + + // TODO: Secure select + // TODO: Secure read + DropField(); return PM3_SUCCESS; } From c281895e8fe6d3fa62861bde90e8d94948465610 Mon Sep 17 00:00:00 2001 From: iceman1001 Date: Fri, 11 Dec 2020 07:59:33 +0100 Subject: [PATCH 021/682] textual --- CHANGELOG.md | 48 +++++++++++++++++++++++++++++------------------- 1 file changed, 29 insertions(+), 19 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2f10e9c97..e168a0db4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,29 +4,39 @@ This project uses the changelog in accordance with [keepchangelog](http://keepac ## [unreleased][unreleased] - Fix `data rawdemod` parsing for psk2 and user defined clock (@cyberpunk-re) + - Added `hf iclass encode` - encode a wiegand binary to a encrypted credential (@iceman1001) + - Changed `recoverpk.py` - now tests more ECDSA curves (@doegox) + - Added `hf 14a apdufuzz`- a naive apdu cla/ins/p1p2/len fuzzer (@iceman1001) + - Fix mixed up INC/DEC in MIFARE protocol defs (@vortixdev) + - Added `lf em 4x70 info` - new support for ID48 transponders (@cmolson) + - Fix multiple coverity scan issues (@iceman1001) + - Added a SIO item (@iceman1001) + - Fix `lf hid brute` - param (@iceman1001) + - Changed `lf em` layouts (@iceman1001) + - Change many commands to cliparser (@iceman1001, @tcprst, ...) - Fix issue #844 - `lf t55xx config` => recompute block0 (@cyberpunk-re) - - EM4x50: changed cli parameter from w (word) to d (data) (@tharexde) - - EM4x50: new function 4x50 login: authenticate against tag (@tharexde) - - EM4x50: new function 4x50 brute: guess password within a given password range (@tharexde) - - EM4x50: new function 4x50 chk: try passwords from dictionary (without option -> T55xx default dictionary or -f user dictionary) (@tharexde) - - EM4x50: new function 4x50 reader: read data from tag (configured data -> standard read mode), incl. option -@ (@tharexde) - - EM4x50: new function 4x50 sim: simulate dump from file or emulator/flash (@tharexde) - - EM4x50: new function 4x50 restore: restore dump file (bin, eml, json) onto tag (@tharexde) - - EM4x50: new function 4x50 esave: dump em4x50 content in emulator memory to file (bin + eml + json) (@tharexde) - - EM4x50: new function 4x50 eload: upload em4x50 file content (bin, eml, json) to emulator memory (@tharexde) - - EM4x50: added LED signals (@tharexde) - - EM4x50: added json format for 4x50 dump (@tharexde) - - EM4x50: relocated write requests in function 4x50 wipe from device to client (@tharexde) - - EM4x50: renamed 4x50_write_password to 4x50 writepwd (@tharexde) - - EM4x50: all hex input parameters now have to be given in lsb format (output is still msb + lsb) (@tharexde) - - EM4x50: changed cli parameter from a (address) to b (block) (@tharexde) - - EM4x50: switched to cliparser for all functions (@tharexde) - - EM4x50: stabilized and accelerated tag detection (@tharexde) - - EM4x50: removed global tag structure on device side (@tharexde) + - Change `lf em 4x50` - changed cli parameter from w (word) to d (data) (@tharexde) + - Added `lf em 4x50 login` - authenticate against tag (@tharexde) + - Added `lf em 4x50 brute` - guess password within a given password range (@tharexde) + - Added `lf em 4x50 chk` - try passwords from dictionary (without option -> T55xx default dictionary or -f user dictionary) (@tharexde) + - Added `lf em 4x50 reader` - read data from tag (configured data -> standard read mode), incl. option -@ (@tharexde) + - Added `lf em 4x50 sim` - simulate dump from file or emulator/flash (@tharexde) + - Added `lf em 4x50 restore` - restore dump file (bin, eml, json) onto tag (@tharexde) + - Added `lf em 4x50 esave` - dump em4x50 content in emulator memory to file (bin + eml + json) (@tharexde) + - Added `lf em 4x50 eload` - upload em4x50 file content (bin, eml, json) to emulator memory (@tharexde) + - Changed EM4x50 - added LED signals (@tharexde) + - Change `lf em 4x50 dump` - now support json format (@tharexde) + - Change `lf em 4x50 wipe` - relocated write requests from device to client (@tharexde) + - Renamed `lf em 4x50 write_passwordd` -> `writepwd` (@tharexde) + - Change `lf em 4x50` - all hex input parameters now have to be given in lsb format (output is still msb + lsb) (@tharexde) + - Change `lf em 4x50` - changed cli parameter from a (address) to b (block) (@tharexde) + - Change `lf em 4x50` - now supports cliparser (@tharexde) + - Change EM4x50 - stabilized and accelerated tag detection (@tharexde) + - Change EM4x50 - removed global tag structure on device side (@tharexde) - Fix `hf 15 sim` - Added basic response to GET_SYSTEM_INFO and READBLOCK requests in order to fix iso15693 tag sim (@cyberpunk-re) - Added `mf mfu sim t 7 n ` - MFU emulation now supports automatic exit after blocks read. (@cyberpunk-re) - Added T55xx Guide to assist in learning how to use the T55xx chip (@mwalker33) - - Fix 'hf iclass wrbl' - dealing with tags in unsecured vs secured pagemode now is correct (@iceman1001) + - Fix `hf iclass wrbl` - dealing with tags in unsecured vs secured pagemode now is correct (@iceman1001) - Change many commands to cliparser (@iceman1001, @tcprst, @mwalker33,...) - ... - Change `hf iclass chk/lookup/loclass` speedups (@iceman1001) From ac1081fdfb138e47bdbee30240cfa8cf70a3f8d6 Mon Sep 17 00:00:00 2001 From: Philippe Teuwen Date: Fri, 11 Dec 2020 14:34:10 +0100 Subject: [PATCH 022/682] recover_pk: some more --- tools/recover_pk.py | 25 +++++++++++++++++++++---- 1 file changed, 21 insertions(+), 4 deletions(-) diff --git a/tools/recover_pk.py b/tools/recover_pk.py index 45b0805be..9c393a2d2 100755 --- a/tools/recover_pk.py +++ b/tools/recover_pk.py @@ -199,6 +199,18 @@ CURVES = { 0xCF5AC8395BAFEB13C02DA292DDED7A83 ) ), + # ! h=4, how to handle that? + "secp128r2": ( + 707, + 0xFFFFFFFDFFFFFFFFFFFFFFFFFFFFFFFF, + 0x3FFFFFFF7FFFFFFFBE0024720613B5A3, + 0xD6031998D1B3BBFEBF59CC9BBFF9AEE1, + 0x5EEEFCA380D02919DC2C6558BB6D8A5D, + ( + 0x7B6AA5D85E572983E6FB32A7CDEBC140, + 0x27B6916A894D3AEE7106FE805FC34B44 + ) + ), "secp192k1": ( 711, 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFEE37, @@ -210,6 +222,7 @@ CURVES = { 0x9B2F2F6D9C5628A7844163D015BE86344082AA88D95E2F9D ) ), + # p192 "secp192r1": ( 409, 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFFFFFFFFFF, @@ -232,6 +245,7 @@ CURVES = { 0x7E089FED7FBA344282CAFBD6F7E319F7C0B0BD59E2CA4BDB556D61A5 ) ), + # p224 "secp224r1": ( 713, 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF000000000000000000000001, @@ -254,7 +268,7 @@ CURVES = { 0x483ADA7726A3C4655DA4FBFC0E1108A8FD17B448A68554199C47D08FFB10D4B8 ) ), - ## openssl uses the name: prime256v1. + # p256, openssl uses the name: prime256v1. "secp256r1": ( 415, 0xFFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFF, @@ -266,6 +280,7 @@ CURVES = { 0x4FE342E2FE1A7F9B8EE7EB4A7C0F9E162BCE33576B315ECECBB6406837BF51F5 ) ), + # p384 "secp384r1": ( 715, 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFF0000000000000000FFFFFFFF, @@ -367,6 +382,8 @@ class EllipticCurve: return data elif callable(hash): return hash(data) + elif hash == "md5": + return hashlib.md5(data).digest() elif hash == "sha1": return hashlib.sha1(data).digest() elif hash == "sha256": @@ -381,7 +398,7 @@ class EllipticCurve: def guess_curvename(signature): l = (len(signature) // 2) & 0xfe if l == 32 : - curves = [ "secp128r1" ] + curves = [ "secp128r1", "secp128r2" ] elif l == 48: curves = [ "secp192k1", "secp192r1" ] elif l == 56: @@ -501,7 +518,7 @@ def selftests(): curvenames = guess_curvename(t['samples'][1]) recovered = set() for c in curvenames: - for h in [None, "sha1", "sha256", "sha512"]: + for h in [None, "md5", "sha1", "sha256", "sha512"]: recovered |= recover_multiple(t['samples'][::2], t['samples'][1::2], c, alghash=h) if (len(recovered) == 1): pk = recovered.pop() @@ -536,7 +553,7 @@ if __name__ == "__main__": for c in curvenames: print("\nAssuming curve=%s" % c) print("========================") - for h in [None, "sha1", "sha256", "sha512"]: + for h in [None, "md5", "sha1", "sha256", "sha512"]: print("Assuming hash=%s" % h) recovered = recover_multiple(uids, sigs, c, alghash=h) if recovered: From 2f42b875e19ff56f9cdccb6f744bb3c7b771a972 Mon Sep 17 00:00:00 2001 From: Ave Date: Fri, 11 Dec 2020 21:07:52 +0300 Subject: [PATCH 023/682] emrtd: Impl secure file select --- client/src/cmdhfemrtd.c | 97 ++++++++++++++++++++++++++++++++++++----- 1 file changed, 87 insertions(+), 10 deletions(-) diff --git a/client/src/cmdhfemrtd.c b/client/src/cmdhfemrtd.c index 49c7b9645..ad3ff69f6 100644 --- a/client/src/cmdhfemrtd.c +++ b/client/src/cmdhfemrtd.c @@ -198,28 +198,39 @@ static void des3_decrypt_cbc(uint8_t *iv, uint8_t *key, uint8_t *input, int inpu mbedtls_des3_free(&ctx); } -static void retail_mac(uint8_t *key, uint8_t *input, uint8_t *output) { - // This code assumes blocklength (n) = 8, and input len of 32 chars +static int pad_block(uint8_t *input, int inputlen, uint8_t *output) { + uint8_t padding[8] = {0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; + + memcpy(output, input, inputlen); + + int to_pad = (8 - (inputlen % 8)); + + for (int i = 0; i < to_pad; i++) { + output[inputlen + i] = padding[i]; + } + + return inputlen + to_pad; +} + +static void retail_mac(uint8_t *key, uint8_t *input, int inputlen, uint8_t *output) { + // This code assumes blocklength (n) = 8, and input len of up to 56 chars // This code takes inspirations from https://github.com/devinvenable/iso9797algorithm3 uint8_t k0[8]; uint8_t k1[8]; uint8_t intermediate[8] = {0x00}; uint8_t intermediate_des[32]; uint8_t block[8]; - uint8_t message[40]; - uint8_t padding[8] = {0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; + uint8_t message[64]; // Populate keys memcpy(k0, key, 8); memcpy(k1, key + 8, 8); // Prepare message - memcpy(message, input, 32); - // Normally this isn't how it works, but it's what mrpkey does... - memcpy(message + 32, padding, 8); + int blocksize = pad_block(input, inputlen, message); // Do chaining and encryption - for (int i = 0; i < (sizeof(message) / 8); i++) { + for (int i = 0; i < (blocksize / 8); i++) { memcpy(block, message + (i * 8), 8); // XOR @@ -333,6 +344,69 @@ static int read_file(uint8_t *dataout, int *dataoutlen) { return true; } +static int secure_select_file(uint8_t *kenc, uint8_t *kmac, uint8_t *ssc, uint8_t *file) { + // Get data even tho we'll not use it + uint8_t response[PM3_CMD_DATA_SIZE]; + int resplen = 0; + + // TODO: fix sizes + uint8_t iv[8] = { 0x00 }; + char command[200]; + uint8_t cmd[200]; + uint8_t data[100]; + uint8_t temp[100] = {0x0c, 0xa4, 0x02, 0x0c}; + uint8_t temp_2[100]; + + PrintAndLogEx(DEBUG, "keyenc: %s", sprint_hex_inrow(kenc, 16)); + PrintAndLogEx(DEBUG, "keymac: %s", sprint_hex_inrow(kmac, 16)); + + int cmdlen = pad_block(temp, 4, cmd); + int datalen = pad_block(file, 2, data); + PrintAndLogEx(DEBUG, "cmd: %s", sprint_hex_inrow(cmd, cmdlen)); + PrintAndLogEx(DEBUG, "data: %s", sprint_hex_inrow(data, datalen)); + + des3_encrypt_cbc(iv, kenc, data, datalen, temp_2); + PrintAndLogEx(DEBUG, "temp_2: %s", sprint_hex_inrow(temp_2, datalen)); + uint8_t do87[103] = {0x87, 0x09, 0x01}; + memcpy(do87 + 3, temp_2, datalen); + PrintAndLogEx(DEBUG, "do87: %s", sprint_hex_inrow(do87, datalen + 3)); + + uint8_t m[153]; + memcpy(m, cmd, cmdlen); + memcpy(m + cmdlen, do87, (datalen + 3)); + PrintAndLogEx(DEBUG, "m: %s", sprint_hex_inrow(m, datalen + cmdlen + 3)); + + // this is hacky + PrintAndLogEx(DEBUG, "ssc-b: %s", sprint_hex_inrow(ssc, 8)); + (*(ssc + 7)) += 1; + PrintAndLogEx(DEBUG, "ssc-a: %s", sprint_hex_inrow(ssc, 8)); + + uint8_t n[161]; + memcpy(n, ssc, 8); + memcpy(n + 8, m, (cmdlen + datalen + 3)); + PrintAndLogEx(DEBUG, "n: %s", sprint_hex_inrow(n, (cmdlen + datalen + 11))); + + uint8_t cc[8]; + retail_mac(kmac, n, (cmdlen + datalen + 11), cc); + PrintAndLogEx(DEBUG, "cc: %s", sprint_hex_inrow(cc, 8)); + + uint8_t do8e[10] = {0x8E, 0x08}; + memcpy(do8e + 2, cc, 8); + PrintAndLogEx(DEBUG, "do8e: %s", sprint_hex_inrow(do8e, 10)); + + int lc = datalen + 3 + 10; + PrintAndLogEx(DEBUG, "lc: %i", lc); + + memcpy(data, do87, datalen + 3); + memcpy(data + (datalen + 3), do8e, 10); + PrintAndLogEx(DEBUG, "data: %s", sprint_hex_inrow(data, lc)); + + sprintf(command, "0C%s020C%02X%s00", SELECT, lc, sprint_hex_inrow(data, lc)); + PrintAndLogEx(DEBUG, "command: %s", command); + + return exchange_commands(command, response, &resplen, false, true); +} + int infoHF_EMRTD(char *documentnumber, char *dob, char *expiry) { uint8_t response[PM3_CMD_DATA_SIZE]; uint8_t rnd_ic[8]; @@ -423,7 +497,7 @@ int infoHF_EMRTD(char *documentnumber, char *dob, char *expiry) { uint8_t m_ifd[8] = { 0x00 }; - retail_mac(kmac, e_ifd, m_ifd); + retail_mac(kmac, e_ifd, 32, m_ifd); PrintAndLogEx(DEBUG, "m_ifd: %s", sprint_hex_inrow(m_ifd, 8)); uint8_t cmd_data[40]; @@ -472,7 +546,10 @@ int infoHF_EMRTD(char *documentnumber, char *dob, char *expiry) { PrintAndLogEx(DEBUG, "ssc: %s", sprint_hex_inrow(ssc, 8)); - // TODO: Secure select + // Select EF_COM + uint8_t file_id[2] = {0x01, 0x1E}; + secure_select_file(ks_enc, ks_mac, ssc, file_id); + // TODO: Secure read DropField(); From 831672be203bde22e23a9a1ff37fc4e65d6549de Mon Sep 17 00:00:00 2001 From: Ave Date: Fri, 11 Dec 2020 21:14:47 +0300 Subject: [PATCH 024/682] emrtd: Clean up secure select file --- client/src/cmdhfemrtd.c | 24 +++++++++++------------- 1 file changed, 11 insertions(+), 13 deletions(-) diff --git a/client/src/cmdhfemrtd.c b/client/src/cmdhfemrtd.c index ad3ff69f6..f1df87fbb 100644 --- a/client/src/cmdhfemrtd.c +++ b/client/src/cmdhfemrtd.c @@ -349,13 +349,11 @@ static int secure_select_file(uint8_t *kenc, uint8_t *kmac, uint8_t *ssc, uint8_ uint8_t response[PM3_CMD_DATA_SIZE]; int resplen = 0; - // TODO: fix sizes uint8_t iv[8] = { 0x00 }; - char command[200]; - uint8_t cmd[200]; - uint8_t data[100]; - uint8_t temp[100] = {0x0c, 0xa4, 0x02, 0x0c}; - uint8_t temp_2[100]; + char command[54]; + uint8_t cmd[8]; + uint8_t data[21]; + uint8_t temp[8] = {0x0c, 0xa4, 0x02, 0x0c}; PrintAndLogEx(DEBUG, "keyenc: %s", sprint_hex_inrow(kenc, 16)); PrintAndLogEx(DEBUG, "keymac: %s", sprint_hex_inrow(kmac, 16)); @@ -365,23 +363,23 @@ static int secure_select_file(uint8_t *kenc, uint8_t *kmac, uint8_t *ssc, uint8_ PrintAndLogEx(DEBUG, "cmd: %s", sprint_hex_inrow(cmd, cmdlen)); PrintAndLogEx(DEBUG, "data: %s", sprint_hex_inrow(data, datalen)); - des3_encrypt_cbc(iv, kenc, data, datalen, temp_2); - PrintAndLogEx(DEBUG, "temp_2: %s", sprint_hex_inrow(temp_2, datalen)); - uint8_t do87[103] = {0x87, 0x09, 0x01}; - memcpy(do87 + 3, temp_2, datalen); + des3_encrypt_cbc(iv, kenc, data, datalen, temp); + PrintAndLogEx(DEBUG, "temp: %s", sprint_hex_inrow(temp, datalen)); + uint8_t do87[11] = {0x87, 0x09, 0x01}; + memcpy(do87 + 3, temp, datalen); PrintAndLogEx(DEBUG, "do87: %s", sprint_hex_inrow(do87, datalen + 3)); - uint8_t m[153]; + uint8_t m[19]; memcpy(m, cmd, cmdlen); memcpy(m + cmdlen, do87, (datalen + 3)); PrintAndLogEx(DEBUG, "m: %s", sprint_hex_inrow(m, datalen + cmdlen + 3)); - // this is hacky + // TODO: this is hacky PrintAndLogEx(DEBUG, "ssc-b: %s", sprint_hex_inrow(ssc, 8)); (*(ssc + 7)) += 1; PrintAndLogEx(DEBUG, "ssc-a: %s", sprint_hex_inrow(ssc, 8)); - uint8_t n[161]; + uint8_t n[27]; memcpy(n, ssc, 8); memcpy(n + 8, m, (cmdlen + datalen + 3)); PrintAndLogEx(DEBUG, "n: %s", sprint_hex_inrow(n, (cmdlen + datalen + 11))); From e93a258f8802fb3b5a6ce5dfbc380436e924beb6 Mon Sep 17 00:00:00 2001 From: Ave Date: Fri, 11 Dec 2020 21:17:15 +0300 Subject: [PATCH 025/682] emrtd: make style pass --- client/src/cmdhfemrtd.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/client/src/cmdhfemrtd.c b/client/src/cmdhfemrtd.c index f1df87fbb..6ac998864 100644 --- a/client/src/cmdhfemrtd.c +++ b/client/src/cmdhfemrtd.c @@ -109,7 +109,7 @@ static char calculate_check_digit(char *data) { } static int asn1datalength(uint8_t *datain, int datainlen) { - char* dataintext = sprint_hex_inrow(datain, datainlen); + char *dataintext = sprint_hex_inrow(datain, datainlen); // lazy - https://stackoverflow.com/a/4214350/3286892 char subbuff[8]; @@ -136,7 +136,7 @@ static int asn1datalength(uint8_t *datain, int datainlen) { } static int asn1fieldlength(uint8_t *datain, int datainlen) { - char* dataintext = sprint_hex_inrow(datain, datainlen); + char *dataintext = sprint_hex_inrow(datain, datainlen); // lazy - https://stackoverflow.com/a/4214350/3286892 char subbuff[8]; From 80c033b93b65c01e3b323c3c4f2768991b4db315 Mon Sep 17 00:00:00 2001 From: tharexde Date: Fri, 11 Dec 2020 19:54:46 +0100 Subject: [PATCH 026/682] added function CmdEM4x50EView --- client/src/cmdlfem4x50.h | 1 + 1 file changed, 1 insertion(+) diff --git a/client/src/cmdlfem4x50.h b/client/src/cmdlfem4x50.h index dab84ba6c..0d5c04bc6 100644 --- a/client/src/cmdlfem4x50.h +++ b/client/src/cmdlfem4x50.h @@ -33,5 +33,6 @@ int CmdEM4x50Reader(const char *Cmd); int CmdEM4x50ELoad(const char *Cmd); int CmdEM4x50ESave(const char *Cmd); int CmdEM4x50Chk(const char *Cmd); +int CmdEM4x50EView(const char *Cmd); #endif From ffd1fe1dde21900e923a9da8fcb356475bcb8a90 Mon Sep 17 00:00:00 2001 From: tharexde Date: Fri, 11 Dec 2020 19:55:15 +0100 Subject: [PATCH 027/682] added function CmdEM4x50EView --- client/src/cmdlfem4x50.c | 47 ++++++++++++++++++++++++++++++++++++++-- 1 file changed, 45 insertions(+), 2 deletions(-) diff --git a/client/src/cmdlfem4x50.c b/client/src/cmdlfem4x50.c index ccdf30394..d57786cb6 100644 --- a/client/src/cmdlfem4x50.c +++ b/client/src/cmdlfem4x50.c @@ -259,6 +259,48 @@ int CmdEM4x50ESave(const char *Cmd) { return PM3_SUCCESS; } +int CmdEM4x50EView(const char *Cmd) { + + CLIParserContext *ctx; + CLIParserInit(&ctx, "lf em 4x50 eview", + "Displays em4x50 content of emulator memory.", + "lf em 4x50 eview\n" + ); + + void *argtable[] = { + arg_param_begin, + arg_param_end + }; + + CLIExecWithReturn(ctx, Cmd, argtable, true); + CLIParserFree(ctx); + + // download emulator memory + PrintAndLogEx(SUCCESS, "Reading emulator memory..."); + uint8_t data[DUMP_FILESIZE] = {0x0}; + if (GetFromDevice(BIG_BUF_EML, data, DUMP_FILESIZE, 0, NULL, 0, NULL, 2500, false) == false) { + PrintAndLogEx(WARNING, "Fail, transfer from device time-out"); + return PM3_ETIMEOUT; + } + + // valid em4x50 data? + uint32_t serial = bytes_to_num(data + 4 * EM4X50_DEVICE_SERIAL, 4); + uint32_t device_id = bytes_to_num(data + 4 * EM4X50_DEVICE_ID, 4); + if (serial == device_id) { + PrintAndLogEx(WARNING, "No valid em4x50 data in emulator memory."); + return PM3_ENODATA; + } + + em4x50_word_t words[EM4X50_NO_WORDS]; + for (int i = 0; i < EM4X50_NO_WORDS; i++) { + memcpy(words[i].byte, data + i * 4, 4); + } + print_result(words, 0, EM4X50_NO_WORDS - 1); + PrintAndLogEx(NORMAL, ""); + + return PM3_SUCCESS; +} + int CmdEM4x50Login(const char *Cmd) { CLIParserContext *ctx; CLIParserInit(&ctx, "lf em 4x50 login", @@ -1123,8 +1165,9 @@ static command_t CommandTable[] = { {"reader", CmdEM4x50Reader, IfPm3EM4x50, "show standard read mode data of EM4x50"}, {"restore",CmdEM4x50Restore, IfPm3EM4x50, "restore EM4x50 dump to tag"}, {"sim", CmdEM4x50Sim, IfPm3EM4x50, "simulate EM4x50 tag"}, - {"eload", CmdEM4x50ELoad, IfPm3EM4x50, "upload dump of EM4x50 to flash memory"}, - {"esave", CmdEM4x50ESave, IfPm3EM4x50, "save flash memory to file"}, + {"eload", CmdEM4x50ELoad, IfPm3EM4x50, "upload dump of EM4x50 to emulator memory"}, + {"esave", CmdEM4x50ESave, IfPm3EM4x50, "save emulator memory to file"}, + {"eview", CmdEM4x50EView, IfPm3EM4x50, "view EM4x50 content in emulator memory"}, {NULL, NULL, NULL, NULL} }; From 3e2e0299ffe415e67a5404a178b993068918fa0c Mon Sep 17 00:00:00 2001 From: Ave Date: Sat, 12 Dec 2020 01:50:54 +0300 Subject: [PATCH 028/682] emrtd: Impl secure read binary --- client/src/cmdhfemrtd.c | 85 +++++++++++++++++++++++++++++++++++------ 1 file changed, 73 insertions(+), 12 deletions(-) diff --git a/client/src/cmdhfemrtd.c b/client/src/cmdhfemrtd.c index 6ac998864..e9a129f0d 100644 --- a/client/src/cmdhfemrtd.c +++ b/client/src/cmdhfemrtd.c @@ -256,18 +256,19 @@ static void deskey(uint8_t *seed, uint8_t *type, int length, uint8_t *dataout) { // combine seed and type uint8_t data[50]; - memcpy(data, seed, 16); - memcpy(data + 16, type, 4); - PrintAndLogEx(DEBUG, "data: %s", sprint_hex_inrow(data, 20)); + memcpy(data, seed, length); + memcpy(data + length, type, 4); + PrintAndLogEx(DEBUG, "data: %s", sprint_hex_inrow(data, length + 4)); // SHA1 the key - unsigned char key[20]; - mbedtls_sha1(data, 20, key); - PrintAndLogEx(DEBUG, "key: %s", sprint_hex_inrow(key, 20)); + unsigned char key[64]; + mbedtls_sha1(data, length + 4, key); + PrintAndLogEx(DEBUG, "key: %s", sprint_hex_inrow(key, length + 4)); // Set parity bits - mbedtls_des_key_set_parity(key); - mbedtls_des_key_set_parity(key + 8); + for (int i = 0; i < ((length + 4) / 8); i++) { + mbedtls_des_key_set_parity(key + (i * 8)); + } PrintAndLogEx(DEBUG, "post-parity key: %s", sprint_hex_inrow(key, 20)); memcpy(dataout, &key, length); @@ -355,9 +356,6 @@ static int secure_select_file(uint8_t *kenc, uint8_t *kmac, uint8_t *ssc, uint8_ uint8_t data[21]; uint8_t temp[8] = {0x0c, 0xa4, 0x02, 0x0c}; - PrintAndLogEx(DEBUG, "keyenc: %s", sprint_hex_inrow(kenc, 16)); - PrintAndLogEx(DEBUG, "keymac: %s", sprint_hex_inrow(kmac, 16)); - int cmdlen = pad_block(temp, 4, cmd); int datalen = pad_block(file, 2, data); PrintAndLogEx(DEBUG, "cmd: %s", sprint_hex_inrow(cmd, cmdlen)); @@ -402,9 +400,71 @@ static int secure_select_file(uint8_t *kenc, uint8_t *kmac, uint8_t *ssc, uint8_ sprintf(command, "0C%s020C%02X%s00", SELECT, lc, sprint_hex_inrow(data, lc)); PrintAndLogEx(DEBUG, "command: %s", command); + // TODO: Impl CC check, which will handle incrementing itself + (*(ssc + 7)) += 1; + return exchange_commands(command, response, &resplen, false, true); } +static int secure_read_binary(uint8_t *kmac, uint8_t *ssc, int offset, int bytes_to_read, uint8_t *dataout, int *dataoutlen) { + char command[54]; + uint8_t cmd[8]; + uint8_t data[21]; + uint8_t temp[8] = {0x0c, 0xb0}; + + PrintAndLogEx(DEBUG, "kmac: %s", sprint_hex_inrow(kmac, 20)); + + // TODO: hacky + char offsethex[5]; + sprintf(offsethex, "%04X", offset); + char offsetbuffer[8]; + memcpy(offsetbuffer, offsethex, 2); + int p1 = (int)strtol(offsetbuffer, NULL, 16); + memcpy(offsetbuffer, offsethex + 2, 2); + int p2 = (int)strtol(offsetbuffer, NULL, 16); + temp[2] = p1; + temp[3] = p2; + + int cmdlen = pad_block(temp, 4, cmd); + PrintAndLogEx(DEBUG, "cmd: %s", sprint_hex_inrow(cmd, cmdlen)); + + uint8_t do97[3] = {0x97, 0x01, bytes_to_read}; + + uint8_t m[11]; + memcpy(m, cmd, 8); + memcpy(m + 8, do97, 3); + + // TODO: this is hacky + PrintAndLogEx(DEBUG, "ssc-b: %s", sprint_hex_inrow(ssc, 8)); + (*(ssc + 7)) += 1; + PrintAndLogEx(DEBUG, "ssc-a: %s", sprint_hex_inrow(ssc, 8)); + + uint8_t n[19]; + memcpy(n, ssc, 8); + memcpy(n + 8, m, 11); + PrintAndLogEx(DEBUG, "n: %s", sprint_hex_inrow(n, 19)); + + uint8_t cc[8]; + retail_mac(kmac, n, 19, cc); + PrintAndLogEx(DEBUG, "cc: %s", sprint_hex_inrow(cc, 8)); + + uint8_t do8e[10] = {0x8E, 0x08}; + memcpy(do8e + 2, cc, 8); + PrintAndLogEx(DEBUG, "do8e: %s", sprint_hex_inrow(do8e, 10)); + + int lc = 13; + PrintAndLogEx(DEBUG, "lc: %i", lc); + + memcpy(data, do97, 3); + memcpy(data + 3, do8e, 10); + PrintAndLogEx(DEBUG, "data: %s", sprint_hex_inrow(data, lc)); + + sprintf(command, "0C%s%02X%02X%02X%s00", READ_BINARY, p1, p2, lc, sprint_hex_inrow(data, lc)); + PrintAndLogEx(DEBUG, "command: %s", command); + + return exchange_commands(command, dataout, dataoutlen, false, true); +} + int infoHF_EMRTD(char *documentnumber, char *dob, char *expiry) { uint8_t response[PM3_CMD_DATA_SIZE]; uint8_t rnd_ic[8]; @@ -548,7 +608,8 @@ int infoHF_EMRTD(char *documentnumber, char *dob, char *expiry) { uint8_t file_id[2] = {0x01, 0x1E}; secure_select_file(ks_enc, ks_mac, ssc, file_id); - // TODO: Secure read + secure_read_binary(ks_mac, ssc, 0, 4, response, &resplen); + // TODO: impl secure read file DropField(); return PM3_SUCCESS; From cf3b0bcbe1d1c969ad7c3638d853911e84f0cff2 Mon Sep 17 00:00:00 2001 From: Ave Date: Sat, 12 Dec 2020 04:34:16 +0300 Subject: [PATCH 029/682] emrtd: Impl check_cc --- client/src/cmdhfemrtd.c | 59 +++++++++++++++++++++++++++++++++++------ 1 file changed, 51 insertions(+), 8 deletions(-) diff --git a/client/src/cmdhfemrtd.c b/client/src/cmdhfemrtd.c index e9a129f0d..ae25140e2 100644 --- a/client/src/cmdhfemrtd.c +++ b/client/src/cmdhfemrtd.c @@ -345,7 +345,41 @@ static int read_file(uint8_t *dataout, int *dataoutlen) { return true; } -static int secure_select_file(uint8_t *kenc, uint8_t *kmac, uint8_t *ssc, uint8_t *file) { +static bool check_cc(uint8_t *ssc, uint8_t *key, uint8_t *rapdu, int rapdulength) { + // https://elixi.re/i/clarkson.png + uint8_t k[100]; + uint8_t cc[100]; + + (*(ssc + 7)) += 1; + + memcpy(k, ssc, 8); + int length = 0; + int length2 = 0; + + if (*(rapdu) == 0x87) { + length += 2 + (*(rapdu + 1)); + memcpy(k + 8, rapdu, length); + PrintAndLogEx(DEBUG, "len1: %i", length); + } + + if ((*(rapdu + length)) == 0x99) { + length2 += 2 + (*(rapdu + (length + 1))); + memcpy(k + length + 8, rapdu + length, length2); + PrintAndLogEx(DEBUG, "len2: %i", length2); + } + + int klength = length + length2 + 8; + + retail_mac(key, k, klength, cc); + PrintAndLogEx(DEBUG, "cc: %s", sprint_hex_inrow(cc, 8)); + PrintAndLogEx(DEBUG, "rapdu: %s", sprint_hex_inrow(rapdu, rapdulength)); + PrintAndLogEx(DEBUG, "rapdu cut: %s", sprint_hex_inrow(rapdu + (rapdulength - 8), 8)); + PrintAndLogEx(DEBUG, "k: %s", sprint_hex_inrow(k, klength)); + + return memcmp(cc, rapdu + (rapdulength - 8), 8) == 0; +} + +static bool secure_select_file(uint8_t *kenc, uint8_t *kmac, uint8_t *ssc, uint8_t *file) { // Get data even tho we'll not use it uint8_t response[PM3_CMD_DATA_SIZE]; int resplen = 0; @@ -400,13 +434,12 @@ static int secure_select_file(uint8_t *kenc, uint8_t *kmac, uint8_t *ssc, uint8_ sprintf(command, "0C%s020C%02X%s00", SELECT, lc, sprint_hex_inrow(data, lc)); PrintAndLogEx(DEBUG, "command: %s", command); - // TODO: Impl CC check, which will handle incrementing itself - (*(ssc + 7)) += 1; + exchange_commands(command, response, &resplen, false, true); - return exchange_commands(command, response, &resplen, false, true); + return check_cc(ssc, kmac, response, resplen); } -static int secure_read_binary(uint8_t *kmac, uint8_t *ssc, int offset, int bytes_to_read, uint8_t *dataout, int *dataoutlen) { +static bool secure_read_binary(uint8_t *kmac, uint8_t *ssc, int offset, int bytes_to_read, uint8_t *dataout, int *dataoutlen) { char command[54]; uint8_t cmd[8]; uint8_t data[21]; @@ -462,7 +495,9 @@ static int secure_read_binary(uint8_t *kmac, uint8_t *ssc, int offset, int bytes sprintf(command, "0C%s%02X%02X%02X%s00", READ_BINARY, p1, p2, lc, sprint_hex_inrow(data, lc)); PrintAndLogEx(DEBUG, "command: %s", command); - return exchange_commands(command, dataout, dataoutlen, false, true); + exchange_commands(command, dataout, dataoutlen, false, true); + + return check_cc(ssc, kmac, dataout, *dataoutlen); } int infoHF_EMRTD(char *documentnumber, char *dob, char *expiry) { @@ -606,9 +641,17 @@ int infoHF_EMRTD(char *documentnumber, char *dob, char *expiry) { // Select EF_COM uint8_t file_id[2] = {0x01, 0x1E}; - secure_select_file(ks_enc, ks_mac, ssc, file_id); + if (secure_select_file(ks_enc, ks_mac, ssc, file_id) == false) { + PrintAndLogEx(ERR, "Failed to secure select EF_COM, crypto checksum check failed."); + DropField(); + return PM3_ESOFT; + } - secure_read_binary(ks_mac, ssc, 0, 4, response, &resplen); + if (secure_read_binary(ks_mac, ssc, 0, 4, response, &resplen) == false) { + PrintAndLogEx(ERR, "Failed to read EF_COM, crypto checksum check failed."); + DropField(); + return PM3_ESOFT; + } // TODO: impl secure read file DropField(); From 4c52fac9e1d6e3c7b5904d4dbb146e868611e12c Mon Sep 17 00:00:00 2001 From: Christian Molson Date: Fri, 11 Dec 2020 23:26:17 -0500 Subject: [PATCH 030/682] EM4x70 write support --- armsrc/appmain.c | 4 + armsrc/em4x70.c | 305 +++++++++++++++++++++++++-------------- armsrc/em4x70.h | 1 + client/src/cmdlfem4x70.c | 74 +++++++++- client/src/cmdlfem4x70.h | 1 + include/em4x70.h | 6 + include/pm3_cmd.h | 1 + 7 files changed, 282 insertions(+), 110 deletions(-) diff --git a/armsrc/appmain.c b/armsrc/appmain.c index c4cc6aaf2..0797eaa82 100644 --- a/armsrc/appmain.c +++ b/armsrc/appmain.c @@ -1170,6 +1170,10 @@ static void PacketReceived(PacketCommandNG *packet) { em4x70_info((em4x70_data_t *)packet->data.asBytes); break; } + case CMD_LF_EM4X70_WRITE: { + em4x70_write((em4x70_data_t *)packet->data.asBytes); + break; + } #endif #ifdef WITH_ISO15693 diff --git a/armsrc/em4x70.c b/armsrc/em4x70.c index 1feb448c7..843cb0978 100644 --- a/armsrc/em4x70.c +++ b/armsrc/em4x70.c @@ -29,20 +29,23 @@ static bool command_parity = true; #define EM4X70_T_TAG_DIV 224 // Divergency Time #define EM4X70_T_TAG_AUTH 4224 // Authentication Time #define EM4X70_T_TAG_WEE 3072 // EEPROM write Time -#define EM4X70_T_TAG_TWALB 128 // Write Access Time of Lock Bits +#define EM4X70_T_TAG_TWALB 672 // Write Access Time of Lock Bits #define EM4X70_T_WAITING_FOR_SNGLLIW 160 // Unsure #define TICKS_PER_FC 12 // 1 fc = 8us, 1.5us per tick = 12 ticks #define EM4X70_MIN_AMPLITUDE 10 // Minimum difference between a high and low signal -#define EM4X70_TAG_TOLERANCE 10 +#define EM4X70_TAG_TOLERANCE 8 #define EM4X70_TAG_WORD 48 +#define EM4X70_COMMAND_RETRIES 5 // Attempts to send/read command +#define EM4X70_MAX_RECEIVE_LENGTH 96 // Maximum bits to expect from any command + /** * These IDs are from the EM4170 datasheet - * Some versions of the chip require a fourth + * Some versions of the chip require a * (even) parity bit, others do not */ #define EM4X70_COMMAND_ID 0x01 @@ -58,10 +61,11 @@ static uint8_t gLow = 0; #define IS_HIGH(sample) (sample>gLow ? true : false) #define IS_LOW(sample) (sample timeout_ticks) +#define TICKS_ELAPSED(start_ticks) (GetTicks() - start_ticks) -static uint8_t bits2byte(uint8_t *bits, int length); -static void bits2bytes(uint8_t *bits, int length, uint8_t *out); +static uint8_t bits2byte(const uint8_t *bits, int length); +static void bits2bytes(const uint8_t *bits, int length, uint8_t *out); static int em4x70_receive(uint8_t *bits); static bool find_listen_window(bool command); @@ -135,7 +139,7 @@ static bool get_signalproperties(void) { uint32_t start_ticks = GetTicks(); //AT91C_BASE_TC0->TC_CCR = AT91C_TC_SWTRG; - while (GetTicks() - start_ticks < TICKS_PER_FC * 3 * EM4X70_T_TAG_FULL_PERIOD) { + while (TICKS_ELAPSED(start_ticks) < TICKS_PER_FC * 3 * EM4X70_T_TAG_FULL_PERIOD) { volatile uint8_t sample = (uint8_t)AT91C_BASE_SSC->SSC_RHR; @@ -197,7 +201,7 @@ static uint32_t get_pulse_length(void) { if (IS_TIMEOUT(timeout)) return 0; - return GetTicks() - start_ticks; + return TICKS_ELAPSED(start_ticks); } /** @@ -236,51 +240,50 @@ static uint32_t get_pulse_invert_length(void) { if (IS_TIMEOUT(timeout)) return 0; - return GetTicks() - start_ticks; + return TICKS_ELAPSED(start_ticks); } -static bool check_pulse_length(uint32_t pl, int length, int margin) { +static bool check_pulse_length(uint32_t pl, int length) { // check if pulse length corresponds to given length - //Dbprintf("%s: pulse length %d vs %d", __func__, pl, length * TICKS_PER_FC); - return ((pl >= TICKS_PER_FC * (length - margin)) & (pl <= TICKS_PER_FC * (length + margin))); + return ((pl >= TICKS_PER_FC * (length - EM4X70_TAG_TOLERANCE)) & (pl <= TICKS_PER_FC * (length + EM4X70_TAG_TOLERANCE))); } -static void em4x70_send_bit(int bit) { +static void em4x70_send_bit(bool bit) { // send single bit according to EM4170 application note and datasheet - uint32_t start_ticks = GetTicks(); if (bit == 0) { // disable modulation (drop the field) for 4 cycles of carrier LOW(GPIO_SSC_DOUT); - while (GetTicks() - start_ticks <= TICKS_PER_FC * 4); + while (TICKS_ELAPSED(start_ticks) <= TICKS_PER_FC * 4); // enable modulation (activates the field) for remaining first // half of bit period HIGH(GPIO_SSC_DOUT); - while (GetTicks() - start_ticks <= TICKS_PER_FC * EM4X70_T_TAG_HALF_PERIOD); + while (TICKS_ELAPSED(start_ticks) <= TICKS_PER_FC * EM4X70_T_TAG_HALF_PERIOD); // disable modulation for second half of bit period LOW(GPIO_SSC_DOUT); - while (GetTicks() - start_ticks <= TICKS_PER_FC * EM4X70_T_TAG_FULL_PERIOD); + while (TICKS_ELAPSED(start_ticks) <= TICKS_PER_FC * EM4X70_T_TAG_FULL_PERIOD); } else { // bit = "1" means disable modulation for full bit period LOW(GPIO_SSC_DOUT); - while (GetTicks() - start_ticks <= TICKS_PER_FC * EM4X70_T_TAG_FULL_PERIOD); + while (TICKS_ELAPSED(start_ticks) <= TICKS_PER_FC * EM4X70_T_TAG_FULL_PERIOD); } - } - /** - * em4x70_send_command + * em4x70_send_nibble + * + * sends 4 bits of data + 1 bit of parity (with_parity) + * */ -static void em4170_send_command(uint8_t command) { +static void em4x70_send_nibble(uint8_t nibble, bool with_parity) { int parity = 0; int msb_bit = 0; @@ -290,16 +293,100 @@ static void em4170_send_command(uint8_t command) { msb_bit = 1; for (int i = msb_bit; i < 4; i++) { - int bit = (command >> (3 - i)) & 1; + int bit = (nibble >> (3 - i)) & 1; em4x70_send_bit(bit); parity ^= bit; } - if(command_parity) + if(with_parity) em4x70_send_bit(parity); - } +static void em4x70_send_word(const uint16_t word) { + + // Split into nibbles + uint8_t nibbles[4]; + uint8_t j = 0; + for(int i = 0; i < 2; i++) { + uint8_t byte = (word >> (8*i)) & 0xff; + nibbles[j++] = (byte >> 4) & 0xf; + nibbles[j++] = byte & 0xf; + } + + // send 16 bit word with parity bits according to EM4x70 datasheet + // sent as 4 x nibbles (4 bits + parity) + for (int i = 0; i < 4; i++) { + em4x70_send_nibble(nibbles[i], true); + } + + // send column parities (4 bit) + em4x70_send_nibble(nibbles[0] ^ nibbles[1] ^ nibbles[2] ^ nibbles[3], false); + + // send final stop bit (always "0") + em4x70_send_bit(0); +} + +static bool check_ack(void) { + + // returns true if signal structue corresponds to ACK, anything else is + // counted as NAK (-> false) + uint32_t start_ticks = GetTicks(); + while (TICKS_ELAPSED(start_ticks) < TICKS_PER_FC * 4 * EM4X70_T_TAG_FULL_PERIOD) { + /* + ACK + 64 (48+16) + 64 (48+16) + NACK + 64 (48+16) + 48 (32+16) + */ + if (check_pulse_length(get_pulse_length(), 2 * EM4X70_T_TAG_FULL_PERIOD)) { + + // The received signal is either ACK or NAK. + if (check_pulse_length(get_pulse_length(), 2 * EM4X70_T_TAG_FULL_PERIOD)) { + return true; + } else { + // It's NAK -> stop searching + break; + } + } + } + return false; +} + +static int write(const uint16_t word, const uint8_t address) { + + // writes to specified
+ if (find_listen_window(true)) { + + // send write command + em4x70_send_nibble(EM4X70_COMMAND_WRITE, true); + + // send address data with parity bit + em4x70_send_nibble(address, true); + + // send data word + em4x70_send_word(word); + + // Wait TWA + WaitTicks(TICKS_PER_FC * EM4X70_T_TAG_TWA); + + // look for ACK sequence + if (check_ack()) { + + // now EM4x70 needs T0 * EM4X70_T_TAG_TWEE (EEPROM write time) + // for saving data and should return with ACK + WaitTicks(TICKS_PER_FC * EM4X70_T_TAG_WEE); + if (check_ack()) { + + return PM3_SUCCESS; + } + } + } + return PM3_ESOFT; +} + + static bool find_listen_window(bool command) { int cnt = 0; @@ -311,34 +398,33 @@ static bool find_listen_window(bool command) { 96 ( 64 + 32 ) 64 ( 32 + 16 +16 )*/ - if (check_pulse_length(get_pulse_invert_length(), 80, EM4X70_TAG_TOLERANCE)) { - if (check_pulse_length(get_pulse_invert_length(), 80, EM4X70_TAG_TOLERANCE)) { - if (check_pulse_length(get_pulse_length(), 96, EM4X70_TAG_TOLERANCE)) { - if (check_pulse_length(get_pulse_length(), 64, EM4X70_TAG_TOLERANCE)) { - if(command) { - /* Here we are after the 64 duration edge. - * em4170 says we need to wait about 48 RF clock cycles. - * depends on the delay between tag and us - * - * I've found between 4-5 quarter periods (32-40) works best - */ - WaitTicks(TICKS_PER_FC * 5 * EM4X70_T_TAG_QUARTER_PERIOD); - // Send RM Command - em4x70_send_bit(0); - em4x70_send_bit(0); - } - return true; - } + if ( check_pulse_length(get_pulse_invert_length(), 80) && + check_pulse_length(get_pulse_invert_length(), 80) && + check_pulse_length(get_pulse_length(), 96) && + check_pulse_length(get_pulse_length(), 64) ) + { + + if(command) { + /* Here we are after the 64 duration edge. + * em4170 says we need to wait about 48 RF clock cycles. + * depends on the delay between tag and us + * + * I've found between 4-5 quarter periods (32-40) works best + */ + WaitTicks(TICKS_PER_FC * 4 * EM4X70_T_TAG_QUARTER_PERIOD); + // Send RM Command + em4x70_send_bit(0); + em4x70_send_bit(0); } + return true; } - } cnt++; } return false; } -static void bits2bytes(uint8_t *bits, int length, uint8_t *out) { +static void bits2bytes(const uint8_t *bits, int length, uint8_t *out) { if(length%8 != 0) { Dbprintf("Should have a multiple of 8 bits, was sent %d", length); @@ -348,12 +434,11 @@ static void bits2bytes(uint8_t *bits, int length, uint8_t *out) { for(int i=1; i <= num_bytes; i++) { out[num_bytes-i] = bits2byte(bits, 8); - bits+=8; - //Dbprintf("Read: %02X", out[num_bytes-i]); + bits += 8; } } -static uint8_t bits2byte(uint8_t *bits, int length) { +static uint8_t bits2byte(const uint8_t *bits, int length) { // converts separate bits into a single "byte" uint8_t byte = 0; @@ -368,22 +453,27 @@ static uint8_t bits2byte(uint8_t *bits, int length) { return byte; } -/*static void print_array(uint8_t *bits, int len) { - - if(len%8 != 0) { - Dbprintf("Should have a multiple of 8 bits, was sent %d", len); - } +static bool send_command_and_read(uint8_t command, uint8_t resp_len_bits, uint8_t *out_bytes) { - int num_bytes = len / 8; // We should have a multiple of 8 here + int retries = EM4X70_COMMAND_RETRIES; + while(retries) { + retries--; - uint8_t bytes[8]; - - for(int i=0;i speed up "lf search" process return find_listen_window(false); @@ -460,8 +521,6 @@ static int em4x70_receive(uint8_t *bits) { uint32_t pl; int bit_pos = 0; uint8_t edge = 0; - - bool foundheader = false; // Read out the header @@ -476,7 +535,7 @@ static int em4x70_receive(uint8_t *bits) { while(pulse_count < 12){ pl = get_pulse_invert_length(); pulse_count++; - if(check_pulse_length(pl, 3 * EM4X70_T_TAG_HALF_PERIOD, EM4X70_TAG_TOLERANCE)) { + if(check_pulse_length(pl, 3 * EM4X70_T_TAG_HALF_PERIOD)) { foundheader = true; break; } @@ -494,19 +553,19 @@ static int em4x70_receive(uint8_t *bits) { // identify remaining bits based on pulse lengths // between two listen windows only pulse lengths of 1, 1.5 and 2 are possible - while (true) { + while (bit_pos < EM4X70_MAX_RECEIVE_LENGTH) { if(edge) pl = get_pulse_length(); else pl = get_pulse_invert_length(); - if (check_pulse_length(pl, EM4X70_T_TAG_FULL_PERIOD, EM4X70_T_TAG_QUARTER_PERIOD)) { + if (check_pulse_length(pl, EM4X70_T_TAG_FULL_PERIOD)) { // pulse length = 1 bits[bit_pos++] = edge; - } else if (check_pulse_length(pl, 3 * EM4X70_T_TAG_HALF_PERIOD, EM4X70_T_TAG_QUARTER_PERIOD)) { + } else if (check_pulse_length(pl, 3 * EM4X70_T_TAG_HALF_PERIOD)) { // pulse length = 1.5 -> flip edge detection if(edge) { @@ -519,7 +578,7 @@ static int em4x70_receive(uint8_t *bits) { edge = 1; } - } else if (check_pulse_length(pl, 2 * EM4X70_T_TAG_FULL_PERIOD, EM4X70_T_TAG_QUARTER_PERIOD)) { + } else if (check_pulse_length(pl, 2 * EM4X70_T_TAG_FULL_PERIOD)) { // pulse length of 2 if(edge) { @@ -530,15 +589,16 @@ static int em4x70_receive(uint8_t *bits) { bits[bit_pos++] = 0; } - } else if ( (edge && check_pulse_length(pl, 3 * EM4X70_T_TAG_FULL_PERIOD, EM4X70_T_TAG_QUARTER_PERIOD)) || - (!edge && check_pulse_length(pl, 80, EM4X70_T_TAG_QUARTER_PERIOD))) { + } else if ( (edge && check_pulse_length(pl, 3 * EM4X70_T_TAG_FULL_PERIOD)) || + (!edge && check_pulse_length(pl, 80))) { // LIW detected (either invert or normal) return --bit_pos; } } - return bit_pos; + // Should not get here + return --bit_pos; } void em4x70_info(em4x70_data_t *etd) { @@ -561,3 +621,34 @@ void em4x70_info(em4x70_data_t *etd) { lf_finalize(); reply_ng(CMD_LF_EM4X70_INFO, status, tag.data, sizeof(tag.data)); } + +void em4x70_write(em4x70_data_t *etd) { + + uint8_t status = 0; + + command_parity = etd->parity; + + init_tag(); + EM4170_setup_read(); + + // Find the Tag + if (get_signalproperties() && find_EM4X70_Tag()) { + + // Write + status = write(etd->word, etd->address) == PM3_SUCCESS; + + if(status) { + // Read Tag after writing + em4x70_read_id(); + em4x70_read_um1(); + em4x70_read_um2(); + } + + } + + StopTicks(); + lf_finalize(); + reply_ng(CMD_LF_EM4X70_WRITE, status, tag.data, sizeof(tag.data)); +} + + diff --git a/armsrc/em4x70.h b/armsrc/em4x70.h index 80fd977a9..63a06136d 100644 --- a/armsrc/em4x70.h +++ b/armsrc/em4x70.h @@ -18,5 +18,6 @@ typedef struct { } em4x70_tag_t; void em4x70_info(em4x70_data_t *etd); +void em4x70_write(em4x70_data_t *etd); #endif /* EM4x70_H */ diff --git a/client/src/cmdlfem4x70.c b/client/src/cmdlfem4x70.c index ae0b3ad22..b3bd192b1 100644 --- a/client/src/cmdlfem4x70.c +++ b/client/src/cmdlfem4x70.c @@ -16,6 +16,9 @@ #include "commonutil.h" #include "em4x70.h" +#define BYTES2UINT16(x) ((x[1] << 8) | (x[0])) +#define BYTES2UINT32(x) ((x[3] << 24) | (x[2] << 16) | (x[1] << 8) | (x[0])) + static int CmdHelp(const char *Cmd); @@ -33,7 +36,7 @@ static void print_info_result(uint8_t *data) { PrintAndLogEx(NORMAL, "%02X %02X", data[32-i], data[32-i-1]); } PrintAndLogEx(NORMAL, "Tag ID: %02X %02X %02X %02X", data[7], data[6], data[5], data[4]); - PrintAndLogEx(NORMAL, "Lockbit 0: %d", (data[3] & 0x40) ? 1:0); + PrintAndLogEx(NORMAL, "Lockbit 0: %d %s", (data[3] & 0x40) ? 1:0, (data[3] & 0x40) ? "LOCKED":"UNLOCKED"); PrintAndLogEx(NORMAL, "Lockbit 1: %d", (data[3] & 0x80) ? 1:0); PrintAndLogEx(NORMAL, ""); @@ -83,7 +86,7 @@ int CmdEM4x70Info(const char *Cmd) { " ID48 does not use command parity (default).\n" " V4070 and EM4170 do require parity bit.", "lf em 4x70 info\n" - "lf em 4x70 -p -> adds parity bit to commands\n" + "lf em 4x70 info -p -> adds parity bit to command\n" ); void *argtable[] = { @@ -114,9 +117,74 @@ int CmdEM4x70Info(const char *Cmd) { return PM3_ESOFT; } +int CmdEM4x70Write(const char *Cmd) { + + // write one block/word (16 bits) to the tag at given block address (0-15) + em4x70_data_t etd = {0}; + + CLIParserContext *ctx; + + CLIParserInit(&ctx, "lf em 4x10 write", + "Write EM4x70\n", + "lf em 4x70 write -b 15 d c0de -> write 'c0de' to block 15\n" + "lf em 4x70 write -p -b 15 -d c0de -> adds parity bit to commands\n" + ); + + void *argtable[] = { + arg_param_begin, + arg_lit0("p", "parity", "Add parity bit when sending commands"), + arg_int1("b", "block", "", "block/word address, dec"), + arg_str1("d", "data", "", "data, 2 bytes"), + arg_param_end + }; + + CLIExecWithReturn(ctx, Cmd, argtable, true); + + etd.parity = arg_get_lit(ctx, 1); + + int addr = arg_get_int(ctx, 2); + + int word_len = 0; + uint8_t word[2] = {0x0}; + CLIGetHexWithReturn(ctx, 3, word, &word_len); + + CLIParserFree(ctx); + + if (addr < 0 || addr >= EM4X70_NUM_BLOCKS) { + PrintAndLogEx(FAILED, "block has to be within range [0, 15]"); + return PM3_EINVARG; + } + + if (word_len != 2) { + PrintAndLogEx(FAILED, "word/data length must be 2 bytes instead of %d", word_len); + return PM3_EINVARG; + } + + etd.address = (uint8_t) addr; + etd.word = BYTES2UINT16(word);; + + clearCommandBuffer(); + SendCommandNG(CMD_LF_EM4X70_WRITE, (uint8_t *)&etd, sizeof(etd)); + + PacketResponseNG resp; + if (!WaitForResponseTimeout(CMD_LF_EM4X70_WRITE, &resp, TIMEOUT)) { + PrintAndLogEx(WARNING, "Timeout while waiting for reply."); + return PM3_ETIMEOUT; + } + + if (resp.status) { + print_info_result(resp.data.asBytes); + return PM3_SUCCESS; + } + + PrintAndLogEx(FAILED, "Writing " _RED_("Failed")); + return PM3_ESOFT; +} + static command_t CommandTable[] = { {"help", CmdHelp, AlwaysAvailable, "This help"}, - {"info", CmdEM4x70Info, IfPm3EM4x70, "tag information EM4x70"}, + {"info", CmdEM4x70Info, IfPm3EM4x70, "Tag information EM4x70"}, + {"write", CmdEM4x70Write, IfPm3EM4x70, "Write EM4x70"}, {NULL, NULL, NULL, NULL} }; diff --git a/client/src/cmdlfem4x70.h b/client/src/cmdlfem4x70.h index a529678e7..a6adb83d5 100644 --- a/client/src/cmdlfem4x70.h +++ b/client/src/cmdlfem4x70.h @@ -18,6 +18,7 @@ int CmdLFEM4X70(const char *Cmd); int CmdEM4x70Info(const char *Cmd); +int CmdEM4x70Write(const char *Cmd); int em4x70_info(void); bool detect_4x70_block(void); diff --git a/include/em4x70.h b/include/em4x70.h index 503b5f2e8..47e8acdce 100644 --- a/include/em4x70.h +++ b/include/em4x70.h @@ -11,8 +11,14 @@ #ifndef EM4X70_H__ #define EM4X70_H__ +#define EM4X70_NUM_BLOCKS 16 + typedef struct { bool parity; + + // Used for writing address + uint8_t address; + uint16_t word; } em4x70_data_t; #endif /* EM4X70_H__ */ diff --git a/include/pm3_cmd.h b/include/pm3_cmd.h index 217a468e2..9f2f7f0c1 100644 --- a/include/pm3_cmd.h +++ b/include/pm3_cmd.h @@ -517,6 +517,7 @@ typedef struct { #define CMD_LF_EM4X50_ESET 0x0252 #define CMD_LF_EM4X50_CHK 0x0253 #define CMD_LF_EM4X70_INFO 0x0260 +#define CMD_LF_EM4X70_WRITE 0x0261 // Sampling configuration for LF reader/sniffer #define CMD_LF_SAMPLING_SET_CONFIG 0x021D #define CMD_LF_FSK_SIMULATE 0x021E From ed8c63a4f4ee45cb92330736f4c6476fff6ad105 Mon Sep 17 00:00:00 2001 From: Christian Molson Date: Sat, 12 Dec 2020 01:20:26 -0500 Subject: [PATCH 031/682] EM4x70 Unlock support. Send pin code to unlock tag. --- armsrc/appmain.c | 4 ++ armsrc/em4x70.c | 80 ++++++++++++++++++++++++++++++++++++++++ armsrc/em4x70.h | 1 + client/src/cmdlfem4x70.c | 72 +++++++++++++++++++++++++++++++++--- client/src/cmdlfem4x70.h | 1 + include/em4x70.h | 4 ++ include/pm3_cmd.h | 1 + 7 files changed, 157 insertions(+), 6 deletions(-) diff --git a/armsrc/appmain.c b/armsrc/appmain.c index 0797eaa82..e7d6fae8d 100644 --- a/armsrc/appmain.c +++ b/armsrc/appmain.c @@ -1174,6 +1174,10 @@ static void PacketReceived(PacketCommandNG *packet) { em4x70_write((em4x70_data_t *)packet->data.asBytes); break; } + case CMD_LF_EM4X70_UNLOCK: { + em4x70_unlock((em4x70_data_t *)packet->data.asBytes); + break; + } #endif #ifdef WITH_ISO15693 diff --git a/armsrc/em4x70.c b/armsrc/em4x70.c index 843cb0978..0b6cf36e6 100644 --- a/armsrc/em4x70.c +++ b/armsrc/em4x70.c @@ -302,6 +302,12 @@ static void em4x70_send_nibble(uint8_t nibble, bool with_parity) { em4x70_send_bit(parity); } +static void em4x70_send_byte(uint8_t byte) { + // Send byte msb first + for (int i = 0; i < 8; i++) + em4x70_send_bit((byte >> (7 - i)) & 1); +} + static void em4x70_send_word(const uint16_t word) { // Split into nibbles @@ -354,6 +360,47 @@ static bool check_ack(void) { return false; } +static int send_pin(const uint32_t pin) { + + // sends pin code for unlocking + if (find_listen_window(true)) { + + // send PIN command + em4x70_send_nibble(EM4X70_COMMAND_PIN, true); + + // --> Send TAG ID (bytes 4-7) + for(int i=0; i < 4; i++) { + em4x70_send_byte(tag.data[7-i]); + } + + // --> Send PIN + for(int i=0; i < 4 ; i++) { + em4x70_send_byte((pin>>(i*8)) & 0xff); + } + + // Wait TWALB (write access lock bits) + WaitTicks(TICKS_PER_FC * EM4X70_T_TAG_TWALB); + + // <-- Receive ACK + if (check_ack()) { + + // Writes Lock Bits + WaitTicks(TICKS_PER_FC * EM4X70_T_TAG_WEE); + // <-- Receive header + ID + uint8_t tag_id[64]; + int num = em4x70_receive(tag_id); + if(num < 32) { + Dbprintf("Invalid ID Received"); + return PM3_ESOFT; + } + bits2bytes(tag_id, num, &tag.data[4]); + return PM3_SUCCESS; + } + } + + return PM3_ESOFT; +} + static int write(const uint16_t word, const uint8_t address) { // writes to specified
@@ -651,4 +698,37 @@ void em4x70_write(em4x70_data_t *etd) { reply_ng(CMD_LF_EM4X70_WRITE, status, tag.data, sizeof(tag.data)); } +void em4x70_unlock(em4x70_data_t *etd) { + + uint8_t status = 0; + + command_parity = etd->parity; + + init_tag(); + EM4170_setup_read(); + + // Find the Tag + if (get_signalproperties() && find_EM4X70_Tag()) { + + // Read ID (required for send_pin command) + if(em4x70_read_id()) { + + // Send PIN + status = send_pin(etd->pin) == PM3_SUCCESS; + + // If the write succeeded, read the rest of the tag + if(status) { + // Read Tag + // ID doesn't change + em4x70_read_um1(); + em4x70_read_um2(); + } + } + } + + StopTicks(); + lf_finalize(); + reply_ng(CMD_LF_EM4X70_UNLOCK, status, tag.data, sizeof(tag.data)); +} + diff --git a/armsrc/em4x70.h b/armsrc/em4x70.h index 63a06136d..2d9f077f8 100644 --- a/armsrc/em4x70.h +++ b/armsrc/em4x70.h @@ -19,5 +19,6 @@ typedef struct { void em4x70_info(em4x70_data_t *etd); void em4x70_write(em4x70_data_t *etd); +void em4x70_unlock(em4x70_data_t *etd); #endif /* EM4x70_H */ diff --git a/client/src/cmdlfem4x70.c b/client/src/cmdlfem4x70.c index b3bd192b1..0b9a18785 100644 --- a/client/src/cmdlfem4x70.c +++ b/client/src/cmdlfem4x70.c @@ -86,12 +86,12 @@ int CmdEM4x70Info(const char *Cmd) { " ID48 does not use command parity (default).\n" " V4070 and EM4170 do require parity bit.", "lf em 4x70 info\n" - "lf em 4x70 info -p -> adds parity bit to command\n" + "lf em 4x70 info -x -> adds parity bit to command\n" ); void *argtable[] = { arg_param_begin, - arg_lit0("p", "parity", "Add parity bit when sending commands"), + arg_lit0("x", "parity", "Add parity bit when sending commands"), arg_param_end }; @@ -104,7 +104,7 @@ int CmdEM4x70Info(const char *Cmd) { PacketResponseNG resp; if (!WaitForResponseTimeout(CMD_LF_EM4X70_INFO, &resp, TIMEOUT)) { - PrintAndLogEx(WARNING, "timeout while waiting for reply."); + PrintAndLogEx(WARNING, "Timeout while waiting for reply."); return PM3_ETIMEOUT; } @@ -113,7 +113,7 @@ int CmdEM4x70Info(const char *Cmd) { return PM3_SUCCESS; } - PrintAndLogEx(FAILED, "reading tag " _RED_("failed")); + PrintAndLogEx(FAILED, "Reading " _RED_("Failed")); return PM3_ESOFT; } @@ -127,12 +127,12 @@ int CmdEM4x70Write(const char *Cmd) { CLIParserInit(&ctx, "lf em 4x10 write", "Write EM4x70\n", "lf em 4x70 write -b 15 d c0de -> write 'c0de' to block 15\n" - "lf em 4x70 write -p -b 15 -d c0de -> adds parity bit to commands\n" + "lf em 4x70 write -x -b 15 -d c0de -> adds parity bit to commands\n" ); void *argtable[] = { arg_param_begin, - arg_lit0("p", "parity", "Add parity bit when sending commands"), + arg_lit0("x", "parity", "Add parity bit when sending commands"), arg_int1("b", "block", "", "block/word address, dec"), arg_str1("d", "data", "", "data, 2 bytes"), arg_param_end @@ -181,10 +181,70 @@ int CmdEM4x70Write(const char *Cmd) { return PM3_ESOFT; } +int CmdEM4x70Unlock(const char *Cmd) { + + // send pin code to device, unlocking it for writing + em4x70_data_t etd = {0}; + + CLIParserContext *ctx; + + CLIParserInit(&ctx, "lf em 4x10 unlock", + "Unlock EM4x70 by sending PIN\n" + "Default pin may be:\n" + " AAAAAAAA\n" + " 00000000\n", + "lf em 4x70 unlock -p 11223344 -> Unlock with PIN\n" + "lf em 4x70 unlock -x -p 11223344 -> Unlock with PIN using parity commands\n" + ); + + void *argtable[] = { + arg_param_begin, + arg_lit0("x", "parity", "Add parity bit when sending commands"), + arg_str1("p", "pin", "", "pin, 4 bytes"), + arg_param_end + }; + + CLIExecWithReturn(ctx, Cmd, argtable, true); + + etd.parity = arg_get_lit(ctx, 1); + + int pin_len = 0; + uint8_t pin[4] = {0x0}; + + CLIGetHexWithReturn(ctx, 2, pin, &pin_len); + + CLIParserFree(ctx); + + if (pin_len != 4) { + PrintAndLogEx(FAILED, "PIN length must be 4 bytes instead of %d", pin_len); + return PM3_EINVARG; + } + + etd.pin = BYTES2UINT32(pin); + + clearCommandBuffer(); + SendCommandNG(CMD_LF_EM4X70_UNLOCK, (uint8_t *)&etd, sizeof(etd)); + + PacketResponseNG resp; + if (!WaitForResponseTimeout(CMD_LF_EM4X70_UNLOCK, &resp, TIMEOUT)) { + PrintAndLogEx(WARNING, "Timeout while waiting for reply."); + return PM3_ETIMEOUT; + } + + if (resp.status) { + print_info_result(resp.data.asBytes); + return PM3_SUCCESS; + } + + PrintAndLogEx(FAILED, "Unlocking tag " _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"}, {NULL, NULL, NULL, NULL} }; diff --git a/client/src/cmdlfem4x70.h b/client/src/cmdlfem4x70.h index a6adb83d5..3f7930673 100644 --- a/client/src/cmdlfem4x70.h +++ b/client/src/cmdlfem4x70.h @@ -19,6 +19,7 @@ int CmdLFEM4X70(const char *Cmd); int CmdEM4x70Info(const char *Cmd); int CmdEM4x70Write(const char *Cmd); +int CmdEM4x70Unlock(const char *Cmd); int em4x70_info(void); bool detect_4x70_block(void); diff --git a/include/em4x70.h b/include/em4x70.h index 47e8acdce..a9d94403d 100644 --- a/include/em4x70.h +++ b/include/em4x70.h @@ -19,6 +19,10 @@ typedef struct { // Used for writing address uint8_t address; uint16_t word; + + // PIN to unlock + uint32_t pin; + } em4x70_data_t; #endif /* EM4X70_H__ */ diff --git a/include/pm3_cmd.h b/include/pm3_cmd.h index 9f2f7f0c1..f5585f192 100644 --- a/include/pm3_cmd.h +++ b/include/pm3_cmd.h @@ -518,6 +518,7 @@ typedef struct { #define CMD_LF_EM4X50_CHK 0x0253 #define CMD_LF_EM4X70_INFO 0x0260 #define CMD_LF_EM4X70_WRITE 0x0261 +#define CMD_LF_EM4X70_UNLOCK 0x0262 // Sampling configuration for LF reader/sniffer #define CMD_LF_SAMPLING_SET_CONFIG 0x021D #define CMD_LF_FSK_SIMULATE 0x021E From aaa4c7ac4fd5df216ff1ae39f0996833fab6de7c Mon Sep 17 00:00:00 2001 From: Philippe Teuwen Date: Sat, 12 Dec 2020 13:37:21 +0100 Subject: [PATCH 032/682] magic doc --- doc/magic_cards_notes.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/doc/magic_cards_notes.md b/doc/magic_cards_notes.md index 4f9cb2f68..9e4cdce12 100644 --- a/doc/magic_cards_notes.md +++ b/doc/magic_cards_notes.md @@ -426,6 +426,12 @@ Note: it seems some cards only accept the "change UID" command. It accepts direct read of block0 (and only block0) without prior auth. +Writing to block 0 has some side-effects: + +* It changes also the UID. Changing the UID *does not* change block 0. +* ATQA and SAK bytes are automatically replaced by fixed values. +* On 4-byte UID cards, BCC byte is automatically corrected. + ### Characteristics * UID: 4b and 7b versions @@ -452,6 +458,8 @@ Equivalent: ``` # change just UID: hf 14a raw -s -c -t 2000 90FBCCCC07 11223344556677 +# read block0: +hf 14a raw -s -c 3000 # write block0: hf 14a raw -s -c -t 2000 90F0CCCC10 041219c3219316984200e32000000000 # lock (uid/block0?) forever: From 7b7698843f28be549dd2fe47521e1e42c51d5ccc Mon Sep 17 00:00:00 2001 From: Christian Molson Date: Sat, 12 Dec 2020 08:29:33 -0500 Subject: [PATCH 033/682] EM4x70 fix info text, update parity options to use long options only --- client/src/cmdlfem4x70.c | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/client/src/cmdlfem4x70.c b/client/src/cmdlfem4x70.c index 0b9a18785..2c845b377 100644 --- a/client/src/cmdlfem4x70.c +++ b/client/src/cmdlfem4x70.c @@ -80,18 +80,18 @@ int CmdEM4x70Info(const char *Cmd) { CLIParserContext *ctx; - CLIParserInit(&ctx, "lf em 4x10 info", + CLIParserInit(&ctx, "lf em 4x70 info", "Tag Information EM4x70\n" " Tag variants include ID48 automotive transponder.\n" " ID48 does not use command parity (default).\n" " V4070 and EM4170 do require parity bit.", "lf em 4x70 info\n" - "lf em 4x70 info -x -> adds parity bit to command\n" + "lf em 4x70 info --par -> adds parity bit to command\n" ); void *argtable[] = { arg_param_begin, - arg_lit0("x", "parity", "Add parity bit when sending commands"), + arg_lit0(NULL, "par", "Add parity bit when sending commands"), arg_param_end }; @@ -124,17 +124,17 @@ int CmdEM4x70Write(const char *Cmd) { CLIParserContext *ctx; - CLIParserInit(&ctx, "lf em 4x10 write", + CLIParserInit(&ctx, "lf em 4x70 write", "Write EM4x70\n", - "lf em 4x70 write -b 15 d c0de -> write 'c0de' to block 15\n" - "lf em 4x70 write -x -b 15 -d c0de -> adds parity bit to commands\n" + "lf em 4x70 write -b 15 -d c0de -> write 'c0de' to block 15\n" + "lf em 4x70 write -b 15 -d c0de --par -> adds parity bit to commands\n" ); void *argtable[] = { arg_param_begin, - arg_lit0("x", "parity", "Add parity bit when sending commands"), - arg_int1("b", "block", "", "block/word address, dec"), - arg_str1("d", "data", "", "data, 2 bytes"), + arg_lit0(NULL, "par", "Add parity bit when sending commands"), + arg_int1("b", "block", "", "block/word address, dec"), + arg_str1("d", "data", "", "data, 2 bytes"), arg_param_end }; @@ -188,19 +188,19 @@ int CmdEM4x70Unlock(const char *Cmd) { CLIParserContext *ctx; - CLIParserInit(&ctx, "lf em 4x10 unlock", + CLIParserInit(&ctx, "lf em 4x70 unlock", "Unlock EM4x70 by sending PIN\n" "Default pin may be:\n" " AAAAAAAA\n" " 00000000\n", "lf em 4x70 unlock -p 11223344 -> Unlock with PIN\n" - "lf em 4x70 unlock -x -p 11223344 -> Unlock with PIN using parity commands\n" + "lf em 4x70 unlock -p 11223344 --par -> Unlock with PIN using parity commands\n" ); void *argtable[] = { arg_param_begin, - arg_lit0("x", "parity", "Add parity bit when sending commands"), - arg_str1("p", "pin", "", "pin, 4 bytes"), + arg_lit0(NULL, "par", "Add parity bit when sending commands"), + arg_str1("p", "pin", "", "pin, 4 bytes"), arg_param_end }; From 7cd80611d3d354d247c5251e52362826bd0f2402 Mon Sep 17 00:00:00 2001 From: Philippe Teuwen Date: Sat, 12 Dec 2020 14:46:40 +0100 Subject: [PATCH 034/682] #makestyleday --- armsrc/Standalone/lf_tharexde.c | 20 ++--- armsrc/em4x50.c | 82 ++++++++--------- armsrc/em4x70.c | 153 ++++++++++++++++---------------- armsrc/iso15693.c | 34 +++---- armsrc/lfsampling.c | 2 +- client/src/cmdhf14a.c | 36 ++++---- client/src/cmdhficlass.c | 16 ++-- client/src/cmdhfmfp.c | 2 +- client/src/cmdlfawid.c | 4 +- client/src/cmdlfdestron.c | 6 +- client/src/cmdlfem410x.c | 24 ++--- client/src/cmdlfem4x05.c | 30 +++---- client/src/cmdlfem4x50.c | 108 +++++++++++----------- client/src/cmdlfem4x70.c | 36 ++++---- client/src/cmdlffdxb.c | 12 +-- client/src/cmdlfgallagher.c | 2 +- client/src/cmdlfguard.c | 14 +-- client/src/cmdlfhid.c | 12 +-- client/src/cmdlfindala.c | 28 +++--- client/src/cmdlfio.c | 12 +-- client/src/cmdlfjablotron.c | 4 +- client/src/cmdlfmotorola.c | 2 +- client/src/cmdlfnedap.c | 34 +++---- client/src/cmdlfpcf7931.c | 4 +- client/src/cmdlft55xx.c | 2 +- client/src/cmdlft55xx.h | 2 +- client/src/cmdlfti.c | 4 +- common/commonutil.c | 2 +- common/lfdemod.c | 4 +- doc/commands.md | 71 +++++++-------- 30 files changed, 381 insertions(+), 381 deletions(-) diff --git a/armsrc/Standalone/lf_tharexde.c b/armsrc/Standalone/lf_tharexde.c index 887100855..f5195513c 100644 --- a/armsrc/Standalone/lf_tharexde.c +++ b/armsrc/Standalone/lf_tharexde.c @@ -88,7 +88,7 @@ static int get_input_data_from_file(uint32_t *words, char *inputfile) { uint32_t size = size_in_spiffs(inputfile); uint8_t *mem = BigBuf_malloc(size); - + Dbprintf(_YELLOW_("found input file %s"), inputfile); rdv40_spiffs_read_as_filetype(inputfile, mem, size, RDV40_SPIFFS_SAFETY_SAFE); @@ -153,7 +153,7 @@ void RunMod(void) { if (button_pressed == BUTTON_SINGLE_CLICK) { SpinUp(100); - + switch (state) { case STATE_SIM: @@ -168,7 +168,7 @@ void RunMod(void) { default: break; } - + state_change = true; } else if (button_pressed == BUTTON_HOLD) { @@ -261,9 +261,9 @@ void RunMod(void) { log_exists = exists_in_spiffs(LF_EM4X50BRUTE_LOGFILE); now = get_input_data_from_file(passwords, LF_EM4X50BRUTE_INPUTFILE); - + if (now == 2) { - + // print some information int no_iter = passwords[1] - passwords[0] + 1; int dur_s = no_iter / EM4X50_PWD_SPEED; @@ -277,7 +277,7 @@ void RunMod(void) { no_iter, passwords[0], passwords[1]); Dbprintf(_YELLOW_("estimated duration: %ih%im%is"), dur_h, dur_m, dur_s); - + } else { Dbprintf(_RED_("error in input data")); break; @@ -287,7 +287,7 @@ void RunMod(void) { } pwd_found = em4x50_standalone_brute(passwords[0], passwords[1], &pwd); - + if (pwd_found == PM3_ETIMEOUT) { // timeout -> no EM4x50 tag on reader? @@ -313,15 +313,15 @@ void RunMod(void) { strcat((char *)entry, "\n"); append(LF_EM4X50BRUTE_LOGFILE, entry, strlen((char *)entry)); - + } else { - + // stopped -> write to logfile sprintf((char *)entry, "stopped search - last password: 0x%08"PRIx32, pwd); Dbprintf(_YELLOW_("%s"), entry); strcat((char *)entry, "\n"); append(LF_EM4X50BRUTE_LOGFILE, entry, strlen((char *)entry)); - + // replace start password by last tested password in // inputfile (spiffs) so that brute forcing process will // be continued when envoking brute force mode again diff --git a/armsrc/em4x50.c b/armsrc/em4x50.c index 36923b6a5..8d977c91d 100644 --- a/armsrc/em4x50.c +++ b/armsrc/em4x50.c @@ -37,11 +37,11 @@ #define EM4X50_T_TAG_WAITING_FOR_SIGNAL 75 #define EM4X50_T_WAITING_FOR_DBLLIW 1550 #define EM4X50_T_WAITING_FOR_SNGLLIW 140 // this value seems to be - // critical; - // if it's too low - // (e.g. < 120) some cards - // are no longer readable - // although they're ok +// critical; +// if it's too low +// (e.g. < 120) some cards +// are no longer readable +// although they're ok #define EM4X50_TAG_TOLERANCE 8 #define EM4X50_TAG_WORD 45 @@ -65,18 +65,18 @@ static void wait_timer(uint32_t period) { // extract and check parities // return result of parity check and extracted plain data static bool extract_parities(uint64_t word, uint32_t *data) { - + uint8_t row_parities = 0x0, col_parities = 0x0; uint8_t row_parities_calculated = 0x0, col_parities_calculated = 0x0; - + *data = 0x0; - + // extract plain data (32 bits) from raw word (45 bits) for (int i = 0; i < 4; i++) { *data <<= 8; *data |= (word >> ((4 - i) * 9 + 1)) & 0xFF; } - + // extract row parities (4 bits + stop bit) from raw word (45 bits) for (int i = 0; i < 5; i++) { row_parities <<= 1; @@ -106,7 +106,7 @@ static bool extract_parities(uint64_t word, uint32_t *data) { col_parities_calculated ^= (*data >> ((3 - j) * 8 + (7 - i))) & 0x1; } } - + if ((row_parities == row_parities_calculated) && (col_parities == col_parities_calculated)) return true; @@ -191,7 +191,7 @@ static bool get_signalproperties(void) { // about 2 samples per bit period wait_timer(T0 * EM4X50_T_TAG_HALF_PERIOD); - + // ignore first samples if ((i > SIGNAL_IGNORE_FIRST_SAMPLES) && (AT91C_BASE_SSC->SSC_RHR > noise)) { signal_found = true; @@ -229,7 +229,7 @@ static bool get_signalproperties(void) { gLow = sample_ref - pct * (sample_max_mean - sample_ref) / 100; LED_A_OFF(); - + return true; } @@ -290,7 +290,7 @@ static uint32_t get_pulse_length(void) { // check if pulse length corresponds to given length static bool check_pulse_length(uint32_t pl, int length) { - return ((pl >= T0 * (length - EM4X50_TAG_TOLERANCE)) && (pl <= T0 * (length + EM4X50_TAG_TOLERANCE))); + return ((pl >= T0 * (length - EM4X50_TAG_TOLERANCE)) && (pl <= T0 * (length + EM4X50_TAG_TOLERANCE))); } // send single bit according to EM4x50 application note and datasheet @@ -346,12 +346,12 @@ static void em4x50_reader_send_byte_with_parity(uint8_t byte) { // word hast be sent in msb notation static void em4x50_reader_send_word(const uint32_t word) { uint8_t bytes[4] = {0x0, 0x0, 0x0, 0x0}; - + for (int i = 0; i < 4; i++) { bytes[i] = (word >> (24 - (8 * i))) & 0xFF; em4x50_reader_send_byte_with_parity(bytes[i]); } - + // send column parities em4x50_reader_send_byte(bytes[0] ^ bytes[1] ^ bytes[2] ^ bytes[3]); @@ -362,7 +362,7 @@ static void em4x50_reader_send_word(const uint32_t word) { // find single listen window static bool find_single_listen_window(void) { int cnt_pulses = 0; - + LED_B_ON(); while (cnt_pulses < EM4X50_T_WAITING_FOR_SNGLLIW) { @@ -392,7 +392,7 @@ static bool find_single_listen_window(void) { // -> 34 words + 34 single listen windows -> about 1600 pulses static int find_double_listen_window(bool bcommand) { int cnt_pulses = 0; - + LED_B_ON(); while (cnt_pulses < EM4X50_T_WAITING_FOR_DBLLIW) { @@ -452,7 +452,7 @@ static int find_double_listen_window(bool bcommand) { cnt_pulses++; } - LED_B_OFF(); + LED_B_OFF(); return PM3_EFAILED; } @@ -480,7 +480,7 @@ static bool check_ack(bool bliw) { if (BUTTON_PRESS()) return false; - + if (check_pulse_length(get_pulse_length(), 2 * EM4X50_T_TAG_FULL_PERIOD)) { // The received signal is either ACK or NAK. @@ -531,9 +531,9 @@ static int get_word_from_bitstream(uint32_t *data) { int cnt = 0; uint32_t pl = 0; uint64_t word = 0x0; - + LED_C_ON(); - + *data = 0x0; // initial bit value depends on last pulse length of listen window @@ -561,7 +561,7 @@ static int get_word_from_bitstream(uint32_t *data) { cnt++; word <<= 1; - + pl = get_pulse_length(); if (check_pulse_length(pl, EM4X50_T_TAG_FULL_PERIOD)) { @@ -612,9 +612,9 @@ static int get_word_from_bitstream(uint32_t *data) { return (extract_parities(word, data)) ? --cnt : 0; } } - + LED_C_OFF(); - + return PM3_EOPABORTED; } @@ -696,7 +696,7 @@ bool em4x50_sim_send_word(uint32_t word) { // word has tobe sent in msb, not lsb word = reflect32(word); - + // 4 bytes each with even row parity bit for (int i = 0; i < 4; i++) { if (em4x50_sim_send_byte_with_parity((word >> ((3 - i) * 8)) & 0xFF) == false) { @@ -776,7 +776,7 @@ static bool login(uint32_t password) { // send password em4x50_reader_send_word(password); - + wait_timer(T0 * EM4X50_T_TAG_TPP); // check if ACK is returned @@ -799,7 +799,7 @@ static bool brute(uint32_t start, uint32_t stop, uint32_t *pwd) { for (*pwd = start; *pwd <= stop; (*pwd)++) { if (login(*pwd) == PM3_SUCCESS) { - + pwd_found = true; // to be safe login 5 more times @@ -809,11 +809,11 @@ static bool brute(uint32_t start, uint32_t stop, uint32_t *pwd) { break; } } - + if (pwd_found) break; } - + // print password every 500 iterations if ((++cnt % 500) == 0) { @@ -827,10 +827,10 @@ static bool brute(uint32_t start, uint32_t stop, uint32_t *pwd) { // print data Dbprintf("|%8i | 0x%08x | 0x%08x |", cnt, reflect32(*pwd), *pwd); } - + if (BUTTON_PRESS()) break; - + } // print footer @@ -852,7 +852,7 @@ void em4x50_login(uint32_t *password) { reply_ng(CMD_LF_EM4X50_LOGIN, status, NULL, 0); } -// envoke password search +// envoke password search void em4x50_brute(em4x50_data_t *etd) { em4x50_setup_read(); @@ -903,7 +903,7 @@ void em4x50_chk(uint8_t *filename) { pwd = 0x0; for (int j = 0; j < 4; j++) pwd |= (*(pwds + 4 * i + j)) << ((3 - j) * 8); - + if ((status = login(pwd)) == PM3_SUCCESS) break; } @@ -1063,7 +1063,7 @@ void em4x50_reader(void) { // writes to specified static int write(uint32_t word, uint32_t addresses) { - + if (request_receive_mode() == PM3_SUCCESS) { // send write command @@ -1079,7 +1079,7 @@ static int write(uint32_t word, uint32_t addresses) { reply_ng(CMD_LF_EM4X50_WRITE, PM3_ETEAROFF, NULL, 0); return PM3_ETEAROFF; } else { - + // wait for T0 * EM4X50_T_TAG_TWA (write access time) wait_timer(T0 * EM4X50_T_TAG_TWA); @@ -1175,7 +1175,7 @@ void em4x50_write(em4x50_data_t *etd) { // if password is given renew login after reset if (etd->pwd_given) status = login(etd->password1); - + if (status == PM3_SUCCESS) { // call a selective read @@ -1225,11 +1225,11 @@ void em4x50_sim(uint8_t *filename) { int status = PM3_SUCCESS; uint8_t *em4x50_mem = BigBuf_get_EM_addr(); uint32_t words[EM4X50_NO_WORDS] = {0x0}; - + #ifdef WITH_FLASH if (strlen((char *)filename) != 0) { - + BigBuf_free(); int changed = rdv40_spiffs_lazy_mount(); @@ -1246,7 +1246,7 @@ void em4x50_sim(uint8_t *filename) { for (int i = 0; i < EM4X50_NO_WORDS; i++) words[i] = reflect32(bytes_to_num(em4x50_mem + (i * 4), 4)); - + // only if valid em4x50 data (e.g. uid == serial) if (words[EM4X50_DEVICE_SERIAL] != words[EM4X50_DEVICE_ID]) { @@ -1261,7 +1261,7 @@ void em4x50_sim(uint8_t *filename) { // iceman, will need a usb cmd check to break as well while (BUTTON_PRESS() == false) { - + WDT_HIT(); em4x50_sim_send_listen_window(); for (int i = fwr; i <= lwr; i++) { @@ -1277,7 +1277,7 @@ void em4x50_sim(uint8_t *filename) { } else { status = PM3_ENODATA; } - + BigBuf_free(); lf_finalize(); reply_ng(CMD_LF_EM4X50_SIM, status, NULL, 0); diff --git a/armsrc/em4x70.c b/armsrc/em4x70.c index 0b6cf36e6..a1f04ed6d 100644 --- a/armsrc/em4x70.c +++ b/armsrc/em4x70.c @@ -70,7 +70,7 @@ static int em4x70_receive(uint8_t *bits); static bool find_listen_window(bool command); static void init_tag(void) { - memset(tag.data, 0x00, sizeof(tag.data)/sizeof(tag.data[0])); + memset(tag.data, 0x00, sizeof(tag.data) / sizeof(tag.data[0])); } static void EM4170_setup_read(void) { @@ -114,7 +114,7 @@ static bool get_signalproperties(void) { uint8_t sample_max_mean = 0; uint8_t sample_max[no_periods]; uint32_t sample_max_sum = 0; - + memset(sample_max, 0x00, sizeof(sample_max)); // wait until signal/noise > 1 (max. 32 periods) @@ -158,7 +158,7 @@ static bool get_signalproperties(void) { gLow = sample_ref - pct * (sample_max_mean - sample_ref) / 100; // Basic sanity check - if(gHigh - gLow < EM4X70_MIN_AMPLITUDE) { + if (gHigh - gLow < EM4X70_MIN_AMPLITUDE) { return false; } @@ -168,9 +168,9 @@ static bool get_signalproperties(void) { /** * get_pulse_length - * + * * Times falling edge pulses - */ + */ static uint32_t get_pulse_length(void) { uint8_t sample; @@ -178,7 +178,7 @@ static uint32_t get_pulse_length(void) { do { sample = (uint8_t)AT91C_BASE_SSC->SSC_RHR; - }while (IS_HIGH(sample) && !IS_TIMEOUT(timeout)); + } while (IS_HIGH(sample) && !IS_TIMEOUT(timeout)); if (IS_TIMEOUT(timeout)) return 0; @@ -188,7 +188,7 @@ static uint32_t get_pulse_length(void) { do { sample = (uint8_t)AT91C_BASE_SSC->SSC_RHR; - }while (IS_LOW(sample) && !IS_TIMEOUT(timeout)); + } while (IS_LOW(sample) && !IS_TIMEOUT(timeout)); if (IS_TIMEOUT(timeout)) return 0; @@ -196,7 +196,7 @@ static uint32_t get_pulse_length(void) { timeout = (TICKS_PER_FC * 3 * EM4X70_T_TAG_FULL_PERIOD) + GetTicks(); do { sample = (uint8_t)AT91C_BASE_SSC->SSC_RHR; - }while (IS_HIGH(sample) && !IS_TIMEOUT(timeout)); + } while (IS_HIGH(sample) && !IS_TIMEOUT(timeout)); if (IS_TIMEOUT(timeout)) return 0; @@ -206,10 +206,10 @@ static uint32_t get_pulse_length(void) { /** * get_pulse_invert_length - * + * * Times rising edge pules * TODO: convert to single function with get_pulse_length() - */ + */ static uint32_t get_pulse_invert_length(void) { uint8_t sample; @@ -217,7 +217,7 @@ static uint32_t get_pulse_invert_length(void) { do { sample = (uint8_t)AT91C_BASE_SSC->SSC_RHR; - }while (IS_LOW(sample) && !IS_TIMEOUT(timeout)); + } while (IS_LOW(sample) && !IS_TIMEOUT(timeout)); if (IS_TIMEOUT(timeout)) return 0; @@ -227,7 +227,7 @@ static uint32_t get_pulse_invert_length(void) { do { sample = (uint8_t)AT91C_BASE_SSC->SSC_RHR; - }while (IS_HIGH(sample) && !IS_TIMEOUT(timeout)); + } while (IS_HIGH(sample) && !IS_TIMEOUT(timeout)); if (IS_TIMEOUT(timeout)) return 0; @@ -235,7 +235,7 @@ static uint32_t get_pulse_invert_length(void) { timeout = GetTicks() + (TICKS_PER_FC * 3 * EM4X70_T_TAG_FULL_PERIOD); do { sample = (uint8_t)AT91C_BASE_SSC->SSC_RHR; - }while (IS_LOW(sample) && !IS_TIMEOUT(timeout)); + } while (IS_LOW(sample) && !IS_TIMEOUT(timeout)); if (IS_TIMEOUT(timeout)) return 0; @@ -279,9 +279,9 @@ static void em4x70_send_bit(bool bit) { /** * em4x70_send_nibble - * + * * sends 4 bits of data + 1 bit of parity (with_parity) - * + * */ static void em4x70_send_nibble(uint8_t nibble, bool with_parity) { int parity = 0; @@ -289,16 +289,16 @@ static void em4x70_send_nibble(uint8_t nibble, bool with_parity) { // Non automotive EM4x70 based tags are 3 bits + 1 parity. // So drop the MSB and send a parity bit instead after the command - if(command_parity) + if (command_parity) msb_bit = 1; - + for (int i = msb_bit; i < 4; i++) { int bit = (nibble >> (3 - i)) & 1; em4x70_send_bit(bit); parity ^= bit; } - if(with_parity) + if (with_parity) em4x70_send_bit(parity); } @@ -313,8 +313,8 @@ static void em4x70_send_word(const uint16_t word) { // Split into nibbles uint8_t nibbles[4]; uint8_t j = 0; - for(int i = 0; i < 2; i++) { - uint8_t byte = (word >> (8*i)) & 0xff; + for (int i = 0; i < 2; i++) { + uint8_t byte = (word >> (8 * i)) & 0xff; nibbles[j++] = (byte >> 4) & 0xf; nibbles[j++] = byte & 0xf; } @@ -369,13 +369,13 @@ static int send_pin(const uint32_t pin) { em4x70_send_nibble(EM4X70_COMMAND_PIN, true); // --> Send TAG ID (bytes 4-7) - for(int i=0; i < 4; i++) { - em4x70_send_byte(tag.data[7-i]); + for (int i = 0; i < 4; i++) { + em4x70_send_byte(tag.data[7 - i]); } // --> Send PIN - for(int i=0; i < 4 ; i++) { - em4x70_send_byte((pin>>(i*8)) & 0xff); + for (int i = 0; i < 4 ; i++) { + em4x70_send_byte((pin >> (i * 8)) & 0xff); } // Wait TWALB (write access lock bits) @@ -389,7 +389,7 @@ static int send_pin(const uint32_t pin) { // <-- Receive header + ID uint8_t tag_id[64]; int num = em4x70_receive(tag_id); - if(num < 32) { + if (num < 32) { Dbprintf("Invalid ID Received"); return PM3_ESOFT; } @@ -415,7 +415,7 @@ static int write(const uint16_t word, const uint8_t address) { // send data word em4x70_send_word(word); - // Wait TWA + // Wait TWA WaitTicks(TICKS_PER_FC * EM4X70_T_TAG_TWA); // look for ACK sequence @@ -435,9 +435,9 @@ static int write(const uint16_t word, const uint8_t address) { static bool find_listen_window(bool command) { - + int cnt = 0; - while(cnt < EM4X70_T_WAITING_FOR_SNGLLIW) { + while (cnt < EM4X70_T_WAITING_FOR_SNGLLIW) { /* 80 ( 64 + 16 ) 80 ( 64 + 16 ) @@ -445,26 +445,25 @@ static bool find_listen_window(bool command) { 96 ( 64 + 32 ) 64 ( 32 + 16 +16 )*/ - if ( check_pulse_length(get_pulse_invert_length(), 80) && - check_pulse_length(get_pulse_invert_length(), 80) && - check_pulse_length(get_pulse_length(), 96) && - check_pulse_length(get_pulse_length(), 64) ) - { + if (check_pulse_length(get_pulse_invert_length(), 80) && + check_pulse_length(get_pulse_invert_length(), 80) && + check_pulse_length(get_pulse_length(), 96) && + check_pulse_length(get_pulse_length(), 64)) { - if(command) { - /* Here we are after the 64 duration edge. - * em4170 says we need to wait about 48 RF clock cycles. - * depends on the delay between tag and us - * - * I've found between 4-5 quarter periods (32-40) works best - */ - WaitTicks(TICKS_PER_FC * 4 * EM4X70_T_TAG_QUARTER_PERIOD); - // Send RM Command - em4x70_send_bit(0); - em4x70_send_bit(0); - } - return true; + if (command) { + /* Here we are after the 64 duration edge. + * em4170 says we need to wait about 48 RF clock cycles. + * depends on the delay between tag and us + * + * I've found between 4-5 quarter periods (32-40) works best + */ + WaitTicks(TICKS_PER_FC * 4 * EM4X70_T_TAG_QUARTER_PERIOD); + // Send RM Command + em4x70_send_bit(0); + em4x70_send_bit(0); } + return true; + } cnt++; } @@ -472,17 +471,17 @@ static bool find_listen_window(bool command) { } static void bits2bytes(const uint8_t *bits, int length, uint8_t *out) { - - if(length%8 != 0) { + + if (length % 8 != 0) { Dbprintf("Should have a multiple of 8 bits, was sent %d", length); } - + int num_bytes = length / 8; // We should have a multiple of 8 here - for(int i=1; i <= num_bytes; i++) { - out[num_bytes-i] = bits2byte(bits, 8); + for (int i = 1; i <= num_bytes; i++) { + out[num_bytes - i] = bits2byte(bits, 8); bits += 8; - } + } } static uint8_t bits2byte(const uint8_t *bits, int length) { @@ -501,16 +500,16 @@ static uint8_t bits2byte(const uint8_t *bits, int length) { } static bool send_command_and_read(uint8_t command, uint8_t resp_len_bits, uint8_t *out_bytes) { - + int retries = EM4X70_COMMAND_RETRIES; - while(retries) { + while (retries) { retries--; - if(find_listen_window(true)) { + if (find_listen_window(true)) { uint8_t bits[EM4X70_MAX_RECEIVE_LENGTH] = {0}; em4x70_send_nibble(command, command_parity); int len = em4x70_receive(bits); - if(len < resp_len_bits) { + if (len < resp_len_bits) { Dbprintf("Invalid data received length: %d", len); return false; } @@ -525,9 +524,9 @@ static bool send_command_and_read(uint8_t command, uint8_t resp_len_bits, uint8_ /** * em4x70_read_id - * + * * read pre-programmed ID (4 bytes) - */ + */ static bool em4x70_read_id(void) { return send_command_and_read(EM4X70_COMMAND_ID, 32, &tag.data[4]); @@ -536,7 +535,7 @@ static bool em4x70_read_id(void) { /** * em4x70_read_um1 - * + * * read user memory 1 (4 bytes including lock bits) */ static bool em4x70_read_um1(void) { @@ -548,7 +547,7 @@ static bool em4x70_read_um1(void) { /** * em4x70_read_um2 - * + * * read user memory 2 (8 bytes) */ static bool em4x70_read_um2(void) { @@ -573,28 +572,28 @@ static int em4x70_receive(uint8_t *bits) { // Read out the header // 12 Manchester 1's (may miss some during settle period) // 4 Manchester 0's - + // Skip a few leading 1's as it could be noisy WaitTicks(TICKS_PER_FC * 3 * EM4X70_T_TAG_FULL_PERIOD); // wait until we get the transition from 1's to 0's which is 1.5 full windows int pulse_count = 0; - while(pulse_count < 12){ + while (pulse_count < 12) { pl = get_pulse_invert_length(); pulse_count++; - if(check_pulse_length(pl, 3 * EM4X70_T_TAG_HALF_PERIOD)) { + if (check_pulse_length(pl, 3 * EM4X70_T_TAG_HALF_PERIOD)) { foundheader = true; break; } } - if(!foundheader) { + if (!foundheader) { Dbprintf("Failed to find read header"); return 0; } // Skip next 3 0's, header check consumes the first 0 - for(int i = 0; i < 3; i++) { + for (int i = 0; i < 3; i++) { get_pulse_invert_length(); } @@ -602,7 +601,7 @@ static int em4x70_receive(uint8_t *bits) { // between two listen windows only pulse lengths of 1, 1.5 and 2 are possible while (bit_pos < EM4X70_MAX_RECEIVE_LENGTH) { - if(edge) + if (edge) pl = get_pulse_length(); else pl = get_pulse_invert_length(); @@ -615,7 +614,7 @@ static int em4x70_receive(uint8_t *bits) { } else if (check_pulse_length(pl, 3 * EM4X70_T_TAG_HALF_PERIOD)) { // pulse length = 1.5 -> flip edge detection - if(edge) { + if (edge) { bits[bit_pos++] = 0; bits[bit_pos++] = 0; edge = 0; @@ -628,7 +627,7 @@ static int em4x70_receive(uint8_t *bits) { } else if (check_pulse_length(pl, 2 * EM4X70_T_TAG_FULL_PERIOD)) { // pulse length of 2 - if(edge) { + if (edge) { bits[bit_pos++] = 0; bits[bit_pos++] = 1; } else { @@ -636,8 +635,8 @@ static int em4x70_receive(uint8_t *bits) { bits[bit_pos++] = 0; } - } else if ( (edge && check_pulse_length(pl, 3 * EM4X70_T_TAG_FULL_PERIOD)) || - (!edge && check_pulse_length(pl, 80))) { + } else if ((edge && check_pulse_length(pl, 3 * EM4X70_T_TAG_FULL_PERIOD)) || + (!edge && check_pulse_length(pl, 80))) { // LIW detected (either invert or normal) return --bit_pos; @@ -651,7 +650,7 @@ static int em4x70_receive(uint8_t *bits) { void em4x70_info(em4x70_data_t *etd) { uint8_t status = 0; - + // Support tags with and without command parity bits command_parity = etd->parity; @@ -680,11 +679,11 @@ void em4x70_write(em4x70_data_t *etd) { // Find the Tag if (get_signalproperties() && find_EM4X70_Tag()) { - + // Write status = write(etd->word, etd->address) == PM3_SUCCESS; - if(status) { + if (status) { // Read Tag after writing em4x70_read_id(); em4x70_read_um1(); @@ -709,15 +708,15 @@ void em4x70_unlock(em4x70_data_t *etd) { // Find the Tag if (get_signalproperties() && find_EM4X70_Tag()) { - + // Read ID (required for send_pin command) - if(em4x70_read_id()) { - + if (em4x70_read_id()) { + // Send PIN status = send_pin(etd->pin) == PM3_SUCCESS; // If the write succeeded, read the rest of the tag - if(status) { + if (status) { // Read Tag // ID doesn't change em4x70_read_um1(); diff --git a/armsrc/iso15693.c b/armsrc/iso15693.c index b6d1b7ed8..ef4695e20 100644 --- a/armsrc/iso15693.c +++ b/armsrc/iso15693.c @@ -1727,7 +1727,7 @@ void SimTagIso15693(uint8_t *uid) { if ((cmd_len >= 5) && (cmd[0] & ISO15_REQ_INVENTORY) && (cmd[1] == ISO15_CMD_INVENTORY)) { bool slow = !(cmd[0] & ISO15_REQ_DATARATE_HIGH); uint32_t response_time = reader_eof_time + DELAY_ISO15693_VCD_TO_VICC_SIM; - + // Build INVENTORY command uint8_t resp_inv[CMD_INV_RESP] = {0}; @@ -1743,30 +1743,30 @@ void SimTagIso15693(uint8_t *uid) { resp_inv[7] = uid[2]; resp_inv[8] = uid[1]; resp_inv[9] = uid[0]; - + // CRC AddCrc15(resp_inv, 10); CodeIso15693AsTag(resp_inv, CMD_INV_RESP); - + tosend_t *ts = get_tosend(); - + TransmitTo15693Reader(ts->buf, ts->max, &response_time, 0, slow); LogTrace_ISO15693(resp_inv, CMD_INV_RESP, response_time * 32, (response_time * 32) + (ts->max * 32 * 64), NULL, false); chip_state = SELECTED; } - + // GET_SYSTEM_INFO if ((cmd[1] == ISO15_CMD_SYSINFO)) { bool slow = !(cmd[0] & ISO15_REQ_DATARATE_HIGH); uint32_t response_time = reader_eof_time + DELAY_ISO15693_VCD_TO_VICC_SIM; - + // Build GET_SYSTEM_INFO command uint8_t resp_sysinfo[CMD_SYSINFO_RESP] = {0}; - + resp_sysinfo[0] = 0; // Response flags. resp_sysinfo[1] = 0x0F; // Information flags (0x0F - DSFID, AFI, Mem size, IC) - + // 64-bit UID resp_sysinfo[2] = uid[7]; resp_sysinfo[3] = uid[6]; @@ -1776,42 +1776,42 @@ void SimTagIso15693(uint8_t *uid) { resp_sysinfo[7] = uid[2]; resp_sysinfo[8] = uid[1]; resp_sysinfo[9] = uid[0]; - + resp_sysinfo[10] = 0; // DSFID resp_sysinfo[11] = 0; // AFI resp_sysinfo[12] = 0x1B; // Memory size. resp_sysinfo[13] = 0x03; // Memory size. resp_sysinfo[14] = 0x01; // IC reference. - + // CRC AddCrc15(resp_sysinfo, 15); CodeIso15693AsTag(resp_sysinfo, CMD_SYSINFO_RESP); - + tosend_t *ts = get_tosend(); - + TransmitTo15693Reader(ts->buf, ts->max, &response_time, 0, slow); LogTrace_ISO15693(resp_sysinfo, CMD_SYSINFO_RESP, response_time * 32, (response_time * 32) + (ts->max * 32 * 64), NULL, false); } - + // READ_BLOCK if ((cmd[1] == ISO15_CMD_READ)) { bool slow = !(cmd[0] & ISO15_REQ_DATARATE_HIGH); uint32_t response_time = reader_eof_time + DELAY_ISO15693_VCD_TO_VICC_SIM; - + // Build GET_SYSTEM_INFO command uint8_t resp_readblock[CMD_READBLOCK_RESP] = {0}; - + resp_readblock[0] = 0; // Response flags. resp_readblock[1] = 0; // Block data. resp_readblock[2] = 0; // Block data. resp_readblock[3] = 0; // Block data. resp_readblock[4] = 0; // Block data. - + // CRC AddCrc15(resp_readblock, 5); CodeIso15693AsTag(resp_readblock, CMD_READBLOCK_RESP); - + tosend_t *ts = get_tosend(); TransmitTo15693Reader(ts->buf, ts->max, &response_time, 0, slow); diff --git a/armsrc/lfsampling.c b/armsrc/lfsampling.c index 7a42367dc..ef1d128cc 100644 --- a/armsrc/lfsampling.c +++ b/armsrc/lfsampling.c @@ -515,7 +515,7 @@ void doCotagAcquisition(void) { if (BUTTON_PRESS()) break; - + if (checker == 4000) { if (data_available()) break; diff --git a/client/src/cmdhf14a.c b/client/src/cmdhf14a.c index 576979aad..9957e8ed3 100644 --- a/client/src/cmdhf14a.c +++ b/client/src/cmdhf14a.c @@ -2135,7 +2135,7 @@ static int CmdHf14AFuzzapdu(const char *Cmd) { "Tag must be on antenna before running.", "hf 14a apdufuzz\n" "hf 14a apdufuzz --cla 80\n" - ); + ); void *argtable[] = { arg_param_begin, @@ -2143,7 +2143,7 @@ static int CmdHf14AFuzzapdu(const char *Cmd) { arg_str0(NULL, "ins", "", "start INSTRUCTION value (1 hex byte)"), arg_str0(NULL, "p1", "", "start P1 value (1 hex byte)"), arg_str0(NULL, "p2", "", "start P2 value (1 hex byte)"), - arg_str0(NULL, "le", "", "start LENGTH value (1 hex byte)"), + arg_str0(NULL, "le", "", "start LENGTH value (1 hex byte)"), arg_lit0("v", "verbose", "verbose output"), arg_param_end }; @@ -2152,7 +2152,7 @@ static int CmdHf14AFuzzapdu(const char *Cmd) { int cla_len = 0; uint8_t cla[1] = {0}; CLIGetHexWithReturn(ctx, 1, cla, &cla_len); - + int ins_len = 0; uint8_t ins[1] = {0}; CLIGetHexWithReturn(ctx, 2, ins, &ins_len); @@ -2176,12 +2176,12 @@ static int CmdHf14AFuzzapdu(const char *Cmd) { bool keep_field_on = true; uint8_t a = cla[0]; - uint8_t b = ins[0]; + uint8_t b = ins[0]; uint8_t c = p1[0]; uint8_t d = p2[0]; - uint8_t e = le[0]; + uint8_t e = le[0]; - PrintAndLogEx(SUCCESS, "Starting the apdu fuzzer [ CLA " _GREEN_("%02X") " INS " _GREEN_("%02X") " P1 " _GREEN_("%02X") " P2 " _GREEN_("%02X") " LE " _GREEN_("%02x")" ]", a,b,c,d,e); + PrintAndLogEx(SUCCESS, "Starting the apdu fuzzer [ CLA " _GREEN_("%02X") " INS " _GREEN_("%02X") " P1 " _GREEN_("%02X") " P2 " _GREEN_("%02X") " LE " _GREEN_("%02x")" ]", a, b, c, d, e); PrintAndLogEx(INFO, "Press " _GREEN_("") " to exit"); uint8_t response[PM3_CMD_DATA_SIZE]; @@ -2210,7 +2210,7 @@ static int CmdHf14AFuzzapdu(const char *Cmd) { } uint8_t foo[5] = {a, b, c, d, e}; - int foo_n = sizeof(foo); + int foo_n = sizeof(foo); if (verbose) { PrintAndLogEx(INFO, "%s", sprint_hex(foo, sizeof(foo))); @@ -2218,34 +2218,34 @@ static int CmdHf14AFuzzapdu(const char *Cmd) { res = ExchangeAPDU14a(foo, foo_n, activate_field, keep_field_on, response, sizeof(response), &resplen); if (res) { e++; - continue; + continue; } uint16_t sw = get_sw(response, resplen); if (sw != 0x6a86 && - sw != 0x6986 && - sw != 0x6d00 - ) { - PrintAndLogEx(INFO, "%02X %02X %02X %02X %02X (%04x - %s)", a,b,c,d,e, sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff)); + sw != 0x6986 && + sw != 0x6d00 + ) { + PrintAndLogEx(INFO, "%02X %02X %02X %02X %02X (%04x - %s)", a, b, c, d, e, sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff)); } e++; if (verbose) { - PrintAndLogEx(INFO, "Status: %02X %02X %02X %02X %02X", a,b,c,d,e); + PrintAndLogEx(INFO, "Status: %02X %02X %02X %02X %02X", a, b, c, d, e); } } while (e); d++; - PrintAndLogEx(INFO, "Status: %02X %02X %02X %02X %02X", a,b,c,d,e); + PrintAndLogEx(INFO, "Status: %02X %02X %02X %02X %02X", a, b, c, d, e); } while (d); c++; - PrintAndLogEx(INFO, "Status: %02X %02X %02X %02X %02X", a,b,c,d,e); + PrintAndLogEx(INFO, "Status: %02X %02X %02X %02X %02X", a, b, c, d, e); } while (c); b++; - PrintAndLogEx(INFO, "Status: %02X %02X %02X %02X %02X", a,b,c,d,e); + PrintAndLogEx(INFO, "Status: %02X %02X %02X %02X %02X", a, b, c, d, e); } while (b); a++; - PrintAndLogEx(INFO, "Status: %02X %02X %02X %02X %02X", a,b,c,d,e); - } while(a); + PrintAndLogEx(INFO, "Status: %02X %02X %02X %02X %02X", a, b, c, d, e); + } while (a); out: PrintAndLogEx(SUCCESS, "time: %" PRIu64 " seconds\n", (msclock() - t1) / 1000); diff --git a/client/src/cmdhficlass.c b/client/src/cmdhficlass.c index 075a5562e..0d182d9c3 100644 --- a/client/src/cmdhficlass.c +++ b/client/src/cmdhficlass.c @@ -624,7 +624,7 @@ static int CmdHFiClassReader(const char *Cmd) { CLIParserInit(&ctx, "hf iclass reader", "Act as a iCLASS reader. Look for iCLASS tags until Enter or the pm3 button is pressed", "hf iclass reader -@ -> continuous reader mode" - ); + ); void *argtable[] = { arg_param_begin, @@ -1700,7 +1700,7 @@ static int CmdHFiClassRestore(const char *Cmd) { "hf iclass restore -f hf-iclass-AA162D30F8FF12F1-dump.bin --first 6 --last 18 --ki 0\n" "hf iclass restore -f hf-iclass-AA162D30F8FF12F1-dump.bin --first 6 --last 18 --ki 0 --elite\n" "hf iclass restore -f hf-iclass-AA162D30F8FF12F1-dump.bin --first 6 --last 18 -k 1122334455667788 --elite\n" - ); + ); void *argtable[] = { arg_param_begin, @@ -3318,12 +3318,12 @@ static int CmdHFiClassPermuteKey(const char *Cmd) { static int CmdHFiClassEncode(const char *Cmd) { - CLIParserContext *ctx; + CLIParserContext *ctx; CLIParserInit(&ctx, "hf iclass encode", "Encode binary wiegand to block 7", "hf iclass encode --bin 10001111100000001010100011 --ki 0 -> FC 31 CN 337\n" "hf iclass encode --bin 10001111100000001010100011 --ki 0 --elite -> FC 31 CN 337, writing w elite key" - ); + ); void *argtable[] = { arg_param_begin, @@ -3422,7 +3422,7 @@ static int CmdHFiClassEncode(const char *Cmd) { } // add binary sentinel bit. pushBit(&bout, 1); - + // convert binary string to hex bytes for (int i = 0; i < bin_len; i++) { char c = bin[i]; @@ -3449,11 +3449,11 @@ static int CmdHFiClassEncode(const char *Cmd) { int isok = PM3_SUCCESS; // write - for (uint8_t i=0; i<4; i++) { - isok = iclass_write_block(6 + i, credential + (i*8), key, use_credit_key, elite, rawkey, false, false, auth); + for (uint8_t i = 0; i < 4; i++) { + isok = iclass_write_block(6 + i, credential + (i * 8), key, use_credit_key, elite, rawkey, false, false, auth); switch (isok) { case PM3_SUCCESS: - PrintAndLogEx(SUCCESS, "Write block %d/0x0%x ( " _GREEN_("ok") " ) --> " _YELLOW_("%s"), 6 + i, 6 + i, sprint_hex_inrow(credential + (i*8), 8)); + PrintAndLogEx(SUCCESS, "Write block %d/0x0%x ( " _GREEN_("ok") " ) --> " _YELLOW_("%s"), 6 + i, 6 + i, sprint_hex_inrow(credential + (i * 8), 8)); break; default: PrintAndLogEx(SUCCESS, "Write block %d/0x0%x ( " _RED_("fail") " )", 6 + i, 6 + i); diff --git a/client/src/cmdhfmfp.c b/client/src/cmdhfmfp.c index 46d7bf0cf..ab41bcf41 100644 --- a/client/src/cmdhfmfp.c +++ b/client/src/cmdhfmfp.c @@ -276,7 +276,7 @@ static int CmdHFMFPInfo(const char *Cmd) { arg_param_end }; CLIExecWithReturn(ctx, Cmd, argtable, true); - + PrintAndLogEx(NORMAL, ""); PrintAndLogEx(INFO, "--- " _CYAN_("Tag Information") " ---------------------------"); PrintAndLogEx(INFO, "-------------------------------------------------------------"); diff --git a/client/src/cmdlfawid.c b/client/src/cmdlfawid.c index 6591e1364..c54c3cd1d 100644 --- a/client/src/cmdlfawid.c +++ b/client/src/cmdlfawid.c @@ -510,7 +510,7 @@ static int CmdAWIDBrute(const char *Cmd) { break; } - + // truncate card number if ((cn & 0xFFFF) != cn) { cn &= 0xFFFF; @@ -550,7 +550,7 @@ static int CmdAWIDBrute(const char *Cmd) { if (cn > 1) { if (down > 1) { if (sendTry(fmtlen, fc, --down, delay, bits, size, verbose) != PM3_SUCCESS) { - return PM3_ESOFT; + return PM3_ESOFT; } } } diff --git a/client/src/cmdlfdestron.c b/client/src/cmdlfdestron.c index ec5e67a28..13f7a6398 100644 --- a/client/src/cmdlfdestron.c +++ b/client/src/cmdlfdestron.c @@ -190,9 +190,9 @@ static int CmdDestronClone(const char *Cmd) { blocks[1] = (blocks[1] & 0xFFFF) | 0xAAE20000; PrintAndLogEx(INFO, "Preparing to clone Destron tag to " _YELLOW_("%s") " with ID: " _YELLOW_("%s") - , cardtype - , sprint_hex_inrow(data, datalen) - ); + , cardtype + , sprint_hex_inrow(data, datalen) + ); print_blocks(blocks, ARRAYLEN(blocks)); diff --git a/client/src/cmdlfem410x.c b/client/src/cmdlfem410x.c index 790e3e070..c8b11a9db 100644 --- a/client/src/cmdlfem410x.c +++ b/client/src/cmdlfem410x.c @@ -118,7 +118,7 @@ void printEM410x(uint32_t hi, uint64_t id, bool verbose) { if (hi) { PrintAndLogEx(SUCCESS, "EM 410x ID "_GREEN_("%06X%016" PRIX64), hi, id); } else { - PrintAndLogEx(SUCCESS, "EM 410x ID "_GREEN_("%010" PRIX64), id); + PrintAndLogEx(SUCCESS, "EM 410x ID "_GREEN_("%010" PRIX64), id); } return; } @@ -395,7 +395,7 @@ static int CmdEM410xReader(const char *Cmd) { // emulate an EM410X tag static int CmdEM410xSim(const char *Cmd) { - + CLIParserContext *ctx; CLIParserInit(&ctx, "lf em 410x sim", "Enables simulation of EM 410x card.\n" @@ -433,7 +433,7 @@ static int CmdEM410xSim(const char *Cmd) { return PM3_SUCCESS; } -static int CmdEM410xBrute(const char *Cmd) { +static int CmdEM410xBrute(const char *Cmd) { CLIParserContext *ctx; CLIParserInit(&ctx, "lf em 410x brute", "bruteforcing by emulating EM 410x tag", @@ -452,10 +452,10 @@ static int CmdEM410xBrute(const char *Cmd) { }; CLIExecWithReturn(ctx, Cmd, argtable, false); - // clock default 64 in EM410x + // clock default 64 in EM410x uint32_t clk = arg_get_u32_def(ctx, 1, 64); - // default pause time: 1 second + // default pause time: 1 second uint32_t delay = arg_get_u32_def(ctx, 2, 1000); int fnlen = 0; @@ -467,7 +467,7 @@ static int CmdEM410xBrute(const char *Cmd) { PrintAndLogEx(ERR, "Error: Please specify a filename"); return PM3_EINVARG; } - + uint32_t uidcnt = 0; uint8_t stUidBlock = 20; uint8_t *p = NULL; @@ -543,10 +543,10 @@ static int CmdEM410xBrute(const char *Cmd) { memcpy(testuid, uidblock + 5 * c, 5); PrintAndLogEx(INFO, "Bruteforce %d / %d: simulating UID " _YELLOW_("%s") - , c + 1 - , uidcnt - , sprint_hex_inrow(testuid, sizeof(testuid)) - ); + , c + 1 + , uidcnt + , sprint_hex_inrow(testuid, sizeof(testuid)) + ); em410x_construct_emul_graph(testuid, clk); @@ -585,7 +585,7 @@ static int CmdEM410xClone(const char *Cmd) { CLIParserContext *ctx; CLIParserInit(&ctx, "lf em 410x clone", "Writes EM410x ID to a T55x7 or Q5/T5555 tag", - "lf em 410x clone --id 0F0368568B -> write id to T55x7 tag\n" + "lf em 410x clone --id 0F0368568B -> write id to T55x7 tag\n" "lf em 410x clone --id 0F0368568B --q5 -> write id to Q5/T5555 tag" ); @@ -598,7 +598,7 @@ static int CmdEM410xClone(const char *Cmd) { }; CLIExecWithReturn(ctx, Cmd, argtable, false); - // clock default 64 in EM410x + // clock default 64 in EM410x uint32_t clk = arg_get_u32_def(ctx, 1, 64); int uid_len = 0; uint8_t uid[5] = {0}; diff --git a/client/src/cmdlfem4x05.c b/client/src/cmdlfem4x05.c index 0f968d23d..c0dc8c2ee 100644 --- a/client/src/cmdlfem4x05.c +++ b/client/src/cmdlfem4x05.c @@ -773,7 +773,7 @@ int CmdEM4x05Write(const char *Cmd) { void *argtable[] = { arg_param_begin, arg_int0("a", "addr", "", "memory address to write to. (0-13)"), - arg_str1("d", "data", "", "data to write, 4 bytes hex"), + arg_str1("d", "data", "", "data to write, 4 bytes hex"), arg_str0("p", "pwd", "", "optional - password, 4 bytes hex"), arg_lit0(NULL, "po", "protect operation"), arg_param_end @@ -784,14 +784,14 @@ int CmdEM4x05Write(const char *Cmd) { uint64_t inputpwd = arg_get_u64_hexstr_def(ctx, 3, 0xFFFFFFFFFFFFFFFF); bool protect_operation = arg_get_lit(ctx, 4); CLIParserFree(ctx); - + if ((addr > 13) && (protect_operation == false)) { PrintAndLogEx(WARNING, "Address must be between 0 and 13"); return PM3_EINVARG; } - bool use_pwd = false; - uint32_t pwd = ( inputpwd != 0xFFFFFFFFFFFFFFFF) ? (inputpwd & 0xFFFFFFFF) : 0; + bool use_pwd = false; + uint32_t pwd = (inputpwd != 0xFFFFFFFFFFFFFFFF) ? (inputpwd & 0xFFFFFFFF) : 0; if (pwd == 0xFFFFFFFF) { if (protect_operation) PrintAndLogEx(INFO, "Writing protection words data %08X", data); @@ -807,14 +807,14 @@ int CmdEM4x05Write(const char *Cmd) { int res = PM3_SUCCESS; // set Protect Words - if (protect_operation) { + if (protect_operation) { res = em4x05_protect(pwd, use_pwd, data); - if ( res != PM3_SUCCESS) { + if (res != PM3_SUCCESS) { return res; } } else { res = em4x05_write_word_ext(addr, pwd, use_pwd, data); - if ( res != PM3_SUCCESS) { + if (res != PM3_SUCCESS) { return res; } } @@ -888,25 +888,25 @@ int CmdEM4x05Wipe(const char *Cmd) { bool use_pwd = false; uint32_t pwd = 0; - if ( inputpwd != 0xFFFFFFFFFFFFFFFF) { + if (inputpwd != 0xFFFFFFFFFFFFFFFF) { pwd = (inputpwd & 0xFFFFFFFF); use_pwd = true; } // block 0 : User Data or Chip Info int res = em4x05_write_word_ext(0, pwd, use_pwd, chip_info); - if ( res != PM3_SUCCESS) { + if (res != PM3_SUCCESS) { return res; } // block 1 : UID - this should be read only for EM4205 and EM4305 not sure about others res = em4x05_write_word_ext(1, pwd, use_pwd, chip_UID); - if ( res != PM3_SUCCESS) { + if (res != PM3_SUCCESS) { PrintAndLogEx(INFO, "UID block write failed"); } // block 2 : password res = em4x05_write_word_ext(2, pwd, use_pwd, block_data); - if ( res != PM3_SUCCESS) { + if (res != PM3_SUCCESS) { return res; } @@ -914,20 +914,20 @@ int CmdEM4x05Wipe(const char *Cmd) { pwd = block_data; // block 3 : user data res = em4x05_write_word_ext(3, pwd, use_pwd, block_data); - if ( res != PM3_SUCCESS) { + if (res != PM3_SUCCESS) { return res; } // block 4 : config res = em4x05_write_word_ext(4, pwd, use_pwd, config); - if ( res != PM3_SUCCESS) { + if (res != PM3_SUCCESS) { return res; } // Remainder of user/data blocks for (addr = 5; addr < 14; addr++) {// Clear user data blocks res = em4x05_write_word_ext(addr, pwd, use_pwd, block_data); - if ( res != PM3_SUCCESS) { + if (res != PM3_SUCCESS) { return res; } } @@ -2146,4 +2146,4 @@ static int CmdHelp(const char *Cmd) { int CmdLFEM4X05(const char *Cmd) { clearCommandBuffer(); return CmdsParse(CommandTable, Cmd); -} \ No newline at end of file +} diff --git a/client/src/cmdlfem4x50.c b/client/src/cmdlfem4x50.c index ccdf30394..09df8cfe6 100644 --- a/client/src/cmdlfem4x50.c +++ b/client/src/cmdlfem4x50.c @@ -28,7 +28,7 @@ static void prepare_result(const uint8_t *data, int fwr, int lwr, em4x50_word_t // restructure received result in "em4x50_word_t" structure for (int i = fwr; i <= lwr; i++) { for (int j = 0; j < 4; j++) { - words[i].byte[j] = data[i * 4 + (3 - j)]; + words[i].byte[j] = data[i * 4 + (3 - j)]; } } } @@ -131,7 +131,7 @@ static int em4x50_load_file(const char *filename, uint8_t *data, size_t data_len int res = 0; uint32_t serial = 0x0, device_id = 0x0; - + if (str_endswith(filename, ".eml")) res = loadFileEML(filename, data, bytes_read) != PM3_SUCCESS; else if (str_endswith(filename, ".json")) @@ -202,7 +202,7 @@ int CmdEM4x50ELoad(const char *Cmd) { // upload to emulator memory PrintAndLogEx(INFO, "Uploading dump " _YELLOW_("%s") " to emulator memory", filename); em4x50_seteml(data, 0, DUMP_FILESIZE); - + PrintAndLogEx(INFO, "Done"); return PM3_SUCCESS; } @@ -236,7 +236,7 @@ int CmdEM4x50ESave(const char *Cmd) { PrintAndLogEx(WARNING, "Fail, transfer from device time-out"); return PM3_ETIMEOUT; } - + // valid em4x50 data? uint32_t serial = bytes_to_num(data + 4 * EM4X50_DEVICE_SERIAL, 4); uint32_t device_id = bytes_to_num(data + 4 * EM4X50_DEVICE_ID, 4); @@ -244,7 +244,7 @@ int CmdEM4x50ESave(const char *Cmd) { PrintAndLogEx(WARNING, "No valid em4x50 data in flash memory."); return PM3_ENODATA; } - + // user supplied filename? if (fnlen == 0) { PrintAndLogEx(INFO, "Using UID as filename"); @@ -272,7 +272,7 @@ int CmdEM4x50Login(const char *Cmd) { arg_param_end }; - CLIExecWithReturn(ctx, Cmd, argtable, true); + CLIExecWithReturn(ctx, Cmd, argtable, true); int pwd_len = 0; uint8_t pwd[4] = {0x0}; CLIGetHexWithReturn(ctx, 1, pwd, &pwd_len); @@ -281,7 +281,7 @@ int CmdEM4x50Login(const char *Cmd) { if (pwd_len != 4) { PrintAndLogEx(FAILED, "password length must be 4 bytes"); return PM3_EINVARG; - } + } uint32_t password = BYTES2UINT32(pwd); @@ -315,30 +315,30 @@ int CmdEM4x50Brute(const char *Cmd) { arg_param_end }; - CLIExecWithReturn(ctx, Cmd, argtable, true); + CLIExecWithReturn(ctx, Cmd, argtable, true); int first_len = 0; - uint8_t first[4] = {0,0,0,0}; + uint8_t first[4] = {0, 0, 0, 0}; CLIGetHexWithReturn(ctx, 1, first, &first_len); int last_len = 0; - uint8_t last[4] = {0,0,0,0}; + uint8_t last[4] = {0, 0, 0, 0}; CLIGetHexWithReturn(ctx, 2, last, &last_len); CLIParserFree(ctx); if (first_len != 4) { PrintAndLogEx(FAILED, "password length must be 4 bytes"); return PM3_EINVARG; - } - if (last_len != 4) { - PrintAndLogEx(FAILED, "password length must be 4 bytes"); - return PM3_EINVARG; - } + } + if (last_len != 4) { + PrintAndLogEx(FAILED, "password length must be 4 bytes"); + return PM3_EINVARG; + } em4x50_data_t etd; etd.password1 = BYTES2UINT32(first); etd.password2 = BYTES2UINT32(last); // 27 passwords/second (empirical value) - const int speed = 27; + const int speed = 27; // print some information int no_iter = etd.password2 - etd.password1 + 1; @@ -348,10 +348,10 @@ int CmdEM4x50Brute(const char *Cmd) { dur_s -= dur_h * 3600 + dur_m * 60; PrintAndLogEx(INFO, "Trying %i passwords in range [0x%08x, 0x%08x]" - , no_iter - , etd.password1 - , etd.password2 - ); + , no_iter + , etd.password1 + , etd.password2 + ); PrintAndLogEx(INFO, "Estimated duration: %ih%im%is", dur_h, dur_m, dur_s); // start @@ -390,7 +390,7 @@ int CmdEM4x50Chk(const char *Cmd) { char filename[FILE_PATH_SIZE] = {0}; CLIParamStrToBuf(arg_get_str(ctx, 1), (uint8_t *)filename, FILE_PATH_SIZE, &fnlen); CLIParserFree(ctx); - + if (IfPm3Flash() == false) { PrintAndLogEx(WARNING, "no flash memory available"); return PM3_EFLASH; @@ -410,17 +410,17 @@ int CmdEM4x50Chk(const char *Cmd) { int res = loadFileDICTIONARY(filename, data, &datalen, 4, &key_count); if (res || !key_count) return PM3_EFILE; - + PrintAndLogEx(INFO, "You can cancel this operation by pressing the pm3 button"); int status = PM3_EFAILED; int keyblock = 2000; // block with 2000 bytes -> 500 keys uint8_t destfn[32] = "em4x50_chk.bin"; - PacketResponseNG resp; + PacketResponseNG resp; int bytes_remaining = datalen; while (bytes_remaining > 0) { - + PrintAndLogEx(INPLACE, "Remaining keys: %i ", bytes_remaining / 4); // upload to flash. @@ -434,7 +434,7 @@ int CmdEM4x50Chk(const char *Cmd) { clearCommandBuffer(); SendCommandNG(CMD_LF_EM4X50_CHK, destfn, sizeof(destfn)); WaitForResponseTimeoutW(CMD_LF_EM4X50_CHK, &resp, -1, false); - + status = resp.status; if ((status == PM3_SUCCESS) || (status == PM3_EOPABORTED)) break; @@ -444,7 +444,7 @@ int CmdEM4x50Chk(const char *Cmd) { } PrintAndLogEx(NORMAL, ""); - + // print response if (status == PM3_SUCCESS) { PrintAndLogEx(SUCCESS, "Key " _GREEN_("found: %02x %02x %02x %02x"), @@ -452,7 +452,7 @@ int CmdEM4x50Chk(const char *Cmd) { resp.data.asBytes[2], resp.data.asBytes[1], resp.data.asBytes[0] - ); + ); } else { PrintAndLogEx(FAILED, "No key found"); } @@ -536,7 +536,7 @@ int CmdEM4x50Read(const char *Cmd) { }; CLIExecWithReturn(ctx, Cmd, argtable, true); - + int addr = arg_get_int_def(ctx, 1, 0); int pwd_len = 0; uint8_t pwd[4] = {0x0}; @@ -545,7 +545,7 @@ int CmdEM4x50Read(const char *Cmd) { if (addr <= 0 || addr >= EM4X50_NO_WORDS) { return PM3_EINVARG; - } + } em4x50_data_t etd; @@ -587,11 +587,11 @@ int CmdEM4x50Info(const char *Cmd) { CLIExecWithReturn(ctx, Cmd, argtable, true); int pwd_len = 0; - uint8_t pwd[4] = {0x0}; + uint8_t pwd[4] = {0x0}; CLIGetHexWithReturn(ctx, 1, pwd, &pwd_len); CLIParserFree(ctx); - em4x50_data_t etd = {.pwd_given = false}; + em4x50_data_t etd = {.pwd_given = false}; if (pwd_len) { if (pwd_len != 4) { PrintAndLogEx(FAILED, "password length must be 4 bytes instead of %d", pwd_len); @@ -610,7 +610,7 @@ int CmdEM4x50Info(const char *Cmd) { return PM3_ETIMEOUT; } - if ( resp.status == PM3_SUCCESS) + if (resp.status == PM3_SUCCESS) print_info_result(resp.data.asBytes); else PrintAndLogEx(FAILED, "Reading tag " _RED_("failed")); @@ -666,7 +666,7 @@ int CmdEM4x50Reader(const char *Cmd) { PrintAndLogEx(INFO, _GREEN_(" %s") "| %s", sprint_hex(words[i].byte, 4), r); } - + PrintAndLogEx(INFO, "-------------+-------------"); } } while (cm && !kbd_enter_pressed()); @@ -771,11 +771,11 @@ int CmdEM4x50Write(const char *Cmd) { arg_str0("p", "pwd", "", "password, 4 bytes, lsb"), arg_param_end }; - + CLIExecWithReturn(ctx, Cmd, argtable, true); int addr = arg_get_int_def(ctx, 1, 0); - + int word_len = 0; uint8_t word[4] = {0x0}; CLIGetHexWithReturn(ctx, 2, word, &word_len); @@ -784,18 +784,18 @@ int CmdEM4x50Write(const char *Cmd) { uint8_t pwd[4] = {0x0}; CLIGetHexWithReturn(ctx, 3, pwd, &pwd_len); CLIParserFree(ctx); - + if (addr <= 0 || addr >= EM4X50_NO_WORDS) { PrintAndLogEx(FAILED, "address has to be within range [0, 31]"); return PM3_EINVARG; - } - + } + if (word_len != 4) { PrintAndLogEx(FAILED, "word/data length must be 4 bytes instead of %d", word_len); return PM3_EINVARG; } - em4x50_data_t etd = {.pwd_given = false}; + em4x50_data_t etd = {.pwd_given = false}; if (pwd_len) { if (pwd_len != 4) { PrintAndLogEx(FAILED, "password length must be 4 bytes instead of %d", pwd_len); @@ -853,7 +853,7 @@ int CmdEM4x50WritePwd(const char *Cmd) { arg_str1("n", "new", "", "new password, 4 hex bytes, lsb"), arg_param_end }; - + CLIExecWithReturn(ctx, Cmd, argtable, true); int pwd_len = 0; uint8_t pwd[4] = {0x0}; @@ -865,7 +865,7 @@ int CmdEM4x50WritePwd(const char *Cmd) { CLIParserFree(ctx); - em4x50_data_t etd; + em4x50_data_t etd; if (pwd_len != 4) { PrintAndLogEx(FAILED, "password length must be 4 bytes instead of %d", pwd_len); return PM3_EINVARG; @@ -898,9 +898,9 @@ int CmdEM4x50WritePwd(const char *Cmd) { } PrintAndLogEx(SUCCESS, "Writing new password %s (%s)" - , sprint_hex_inrow(npwd, sizeof(npwd)) - , _GREEN_("ok") - ); + , sprint_hex_inrow(npwd, sizeof(npwd)) + , _GREEN_("ok") + ); return PM3_SUCCESS; } @@ -919,7 +919,7 @@ int CmdEM4x50Wipe(const char *Cmd) { arg_param_end }; - CLIExecWithReturn(ctx, Cmd, argtable, true); + CLIExecWithReturn(ctx, Cmd, argtable, true); int pwd_len = 0; uint8_t pwd[4] = {0x0}; CLIGetHexWithReturn(ctx, 1, pwd, &pwd_len); @@ -935,7 +935,7 @@ int CmdEM4x50Wipe(const char *Cmd) { etd.password1 = BYTES2UINT32(pwd); etd.pwd_given = true; - + // clear password PacketResponseNG resp; clearCommandBuffer(); @@ -954,13 +954,13 @@ int CmdEM4x50Wipe(const char *Cmd) { // from now on new password 0x0 etd.password1 = 0x0; - + // clear data (words 1 to 31) for (int i = 1; i < EM4X50_DEVICE_SERIAL; i++) { // no login necessary for blocks 3 to 31 etd.pwd_given = (i <= EM4X50_CONTROL); - + PrintAndLogEx(INPLACE, "Wiping block %i", i); etd.addresses = i << 8 | i; @@ -971,7 +971,7 @@ int CmdEM4x50Wipe(const char *Cmd) { return PM3_ETIMEOUT; } - if ( resp.status != PM3_SUCCESS) { + if (resp.status != PM3_SUCCESS) { PrintAndLogEx(NORMAL, ""); PrintAndLogEx(FAILED, "Wiping data " _RED_("failed")); return PM3_ESOFT; @@ -1002,7 +1002,7 @@ int CmdEM4x50Restore(const char *Cmd) { arg_param_end }; - CLIExecWithReturn(ctx, Cmd, argtable, true); + CLIExecWithReturn(ctx, Cmd, argtable, true); int uidLen = 0; uint8_t uid[4] = {0x0}; @@ -1057,7 +1057,7 @@ int CmdEM4x50Restore(const char *Cmd) { etd.addresses = i << 8 | i; etd.word = reflect32(BYTES2UINT32((data + 4 * i))); - + PacketResponseNG resp; clearCommandBuffer(); SendCommandNG(CMD_LF_EM4X50_WRITE, (uint8_t *)&etd, sizeof(etd)); @@ -1074,7 +1074,7 @@ int CmdEM4x50Restore(const char *Cmd) { } } - PrintAndLogEx(NORMAL, ""); + PrintAndLogEx(NORMAL, ""); PrintAndLogEx(INFO, "Done"); return PM3_SUCCESS; } @@ -1118,10 +1118,10 @@ static command_t CommandTable[] = { {"login", CmdEM4x50Login, IfPm3EM4x50, "login into EM4x50"}, {"rdbl", CmdEM4x50Read, IfPm3EM4x50, "read word data from EM4x50"}, {"wrbl", CmdEM4x50Write, IfPm3EM4x50, "write word data to EM4x50"}, - {"writepwd",CmdEM4x50WritePwd, IfPm3EM4x50, "change password of EM4x50"}, + {"writepwd", CmdEM4x50WritePwd, IfPm3EM4x50, "change password of EM4x50"}, {"wipe", CmdEM4x50Wipe, IfPm3EM4x50, "wipe EM4x50 tag"}, {"reader", CmdEM4x50Reader, IfPm3EM4x50, "show standard read mode data of EM4x50"}, - {"restore",CmdEM4x50Restore, IfPm3EM4x50, "restore EM4x50 dump to tag"}, + {"restore", CmdEM4x50Restore, IfPm3EM4x50, "restore EM4x50 dump to tag"}, {"sim", CmdEM4x50Sim, IfPm3EM4x50, "simulate EM4x50 tag"}, {"eload", CmdEM4x50ELoad, IfPm3EM4x50, "upload dump of EM4x50 to flash memory"}, {"esave", CmdEM4x50ESave, IfPm3EM4x50, "save flash memory to file"}, diff --git a/client/src/cmdlfem4x70.c b/client/src/cmdlfem4x70.c index 2c845b377..4db2aa650 100644 --- a/client/src/cmdlfem4x70.c +++ b/client/src/cmdlfem4x70.c @@ -31,26 +31,26 @@ static void print_info_result(uint8_t *data) { // data section PrintAndLogEx(NORMAL, ""); PrintAndLogEx(INFO, _YELLOW_("EM4x70 data:")); - - for(int i=1; i <= 32; i+=2) { - PrintAndLogEx(NORMAL, "%02X %02X", data[32-i], data[32-i-1]); + + for (int i = 1; i <= 32; i += 2) { + PrintAndLogEx(NORMAL, "%02X %02X", data[32 - i], data[32 - i - 1]); } PrintAndLogEx(NORMAL, "Tag ID: %02X %02X %02X %02X", data[7], data[6], data[5], data[4]); - PrintAndLogEx(NORMAL, "Lockbit 0: %d %s", (data[3] & 0x40) ? 1:0, (data[3] & 0x40) ? "LOCKED":"UNLOCKED"); - PrintAndLogEx(NORMAL, "Lockbit 1: %d", (data[3] & 0x80) ? 1:0); + PrintAndLogEx(NORMAL, "Lockbit 0: %d %s", (data[3] & 0x40) ? 1 : 0, (data[3] & 0x40) ? "LOCKED" : "UNLOCKED"); + PrintAndLogEx(NORMAL, "Lockbit 1: %d", (data[3] & 0x80) ? 1 : 0); PrintAndLogEx(NORMAL, ""); } int em4x70_info(void) { - + em4x70_data_t edata = { .parity = false // TODO: try both? or default to true }; clearCommandBuffer(); SendCommandNG(CMD_LF_EM4X70_INFO, (uint8_t *)&edata, sizeof(edata)); - + PacketResponseNG resp; if (!WaitForResponseTimeout(CMD_LF_EM4X70_INFO, &resp, TIMEOUT)) { PrintAndLogEx(WARNING, "(em4x70) timeout while waiting for reply."); @@ -87,7 +87,7 @@ int CmdEM4x70Info(const char *Cmd) { " V4070 and EM4170 do require parity bit.", "lf em 4x70 info\n" "lf em 4x70 info --par -> adds parity bit to command\n" - ); + ); void *argtable[] = { arg_param_begin, @@ -128,7 +128,7 @@ int CmdEM4x70Write(const char *Cmd) { "Write EM4x70\n", "lf em 4x70 write -b 15 -d c0de -> write 'c0de' to block 15\n" "lf em 4x70 write -b 15 -d c0de --par -> adds parity bit to commands\n" - ); + ); void *argtable[] = { arg_param_begin, @@ -139,11 +139,11 @@ int CmdEM4x70Write(const char *Cmd) { }; CLIExecWithReturn(ctx, Cmd, argtable, true); - + etd.parity = arg_get_lit(ctx, 1); - + int addr = arg_get_int(ctx, 2); - + int word_len = 0; uint8_t word[2] = {0x0}; CLIGetHexWithReturn(ctx, 3, word, &word_len); @@ -153,8 +153,8 @@ int CmdEM4x70Write(const char *Cmd) { if (addr < 0 || addr >= EM4X70_NUM_BLOCKS) { PrintAndLogEx(FAILED, "block has to be within range [0, 15]"); return PM3_EINVARG; - } - + } + if (word_len != 2) { PrintAndLogEx(FAILED, "word/data length must be 2 bytes instead of %d", word_len); return PM3_EINVARG; @@ -195,7 +195,7 @@ int CmdEM4x70Unlock(const char *Cmd) { " 00000000\n", "lf em 4x70 unlock -p 11223344 -> Unlock with PIN\n" "lf em 4x70 unlock -p 11223344 --par -> Unlock with PIN using parity commands\n" - ); + ); void *argtable[] = { arg_param_begin, @@ -205,12 +205,12 @@ int CmdEM4x70Unlock(const char *Cmd) { }; CLIExecWithReturn(ctx, Cmd, argtable, true); - + etd.parity = arg_get_lit(ctx, 1); - + int pin_len = 0; uint8_t pin[4] = {0x0}; - + CLIGetHexWithReturn(ctx, 2, pin, &pin_len); CLIParserFree(ctx); diff --git a/client/src/cmdlffdxb.c b/client/src/cmdlffdxb.c index f44182483..529f63019 100644 --- a/client/src/cmdlffdxb.c +++ b/client/src/cmdlffdxb.c @@ -727,7 +727,7 @@ static int CmdFdxBClone(const char *Cmd) { } uint32_t extended = 0; - bool has_extended = false; + bool has_extended = false; if (extended_len) { extended = bytes_to_num(edata, extended_len); has_extended = true; @@ -773,10 +773,10 @@ static int CmdFdxBClone(const char *Cmd) { free(bs); PrintAndLogEx(INFO, "Preparing to clone FDX-B to " _YELLOW_("%s") " with animal ID: " _GREEN_("%04u-%"PRIu64) - , cardtype - , country_code - , national_code - ); + , cardtype + , country_code + , national_code + ); print_blocks(blocks, ARRAYLEN(blocks)); int res; @@ -820,7 +820,7 @@ static int CmdFdxBSim(const char *Cmd) { CLIParserFree(ctx); uint32_t extended = 0; - bool has_extended = false; + bool has_extended = false; if (extended_len) { extended = bytes_to_num(edata, extended_len); has_extended = true; diff --git a/client/src/cmdlfgallagher.c b/client/src/cmdlfgallagher.c index cf0488877..12b6b9b49 100644 --- a/client/src/cmdlfgallagher.c +++ b/client/src/cmdlfgallagher.c @@ -233,7 +233,7 @@ static int CmdGallagherClone(const char *Cmd) { static int CmdGallagherSim(const char *Cmd) { - CLIParserContext *ctx; + CLIParserContext *ctx; CLIParserInit(&ctx, "lf gallagher sim", "Enables simulation of GALLAGHER card with specified card number.\n" "Simulation runs until the button is pressed or another USB command is issued.\n", diff --git a/client/src/cmdlfguard.c b/client/src/cmdlfguard.c index ec49b46c5..929079158 100644 --- a/client/src/cmdlfguard.c +++ b/client/src/cmdlfguard.c @@ -226,10 +226,10 @@ static int CmdGuardClone(const char *Cmd) { free(bs); PrintAndLogEx(INFO, "Preparing to clone Guardall to " _YELLOW_("%s") " with Facility Code: " _GREEN_("%u") " Card Number: " _GREEN_("%u") - , cardtype - , facilitycode - , cardnumber - ); + , cardtype + , facilitycode + , cardnumber + ); print_blocks(blocks, ARRAYLEN(blocks)); int res; @@ -281,9 +281,9 @@ static int CmdGuardSim(const char *Cmd) { } PrintAndLogEx(SUCCESS, "Simulating Guardall Prox - Facility Code: " _YELLOW_("%u") " CardNumber: " _YELLOW_("%u") - , facilitycode - , cardnumber - ); + , facilitycode + , cardnumber + ); // Guard uses: clk: 64, invert: 0, encoding: 2 (ASK Biphase) lf_asksim_t *payload = calloc(1, sizeof(lf_asksim_t) + sizeof(bs)); diff --git a/client/src/cmdlfhid.c b/client/src/cmdlfhid.c index 3e10def56..108550539 100644 --- a/client/src/cmdlfhid.c +++ b/client/src/cmdlfhid.c @@ -60,16 +60,16 @@ static int sendTry(uint8_t format_idx, wiegand_card_t *card, uint32_t delay, boo if (HIDPack(format_idx, card, &packed) == false) { PrintAndLogEx(WARNING, "The card data could not be encoded in the selected format."); - return PM3_ESOFT; + return PM3_ESOFT; } if (verbose) { PrintAndLogEx(INFO, "Trying FC: " _YELLOW_("%u") " CN: " _YELLOW_("%"PRIu64) " Issue level: " _YELLOW_("%u") " OEM: " _YELLOW_("%u") - , card->FacilityCode - , card->CardNumber - , card->IssueLevel - , card->OEM - ); + , card->FacilityCode + , card->CardNumber + , card->IssueLevel + , card->OEM + ); } lf_hidsim_t payload; diff --git a/client/src/cmdlfindala.c b/client/src/cmdlfindala.c index df2bd4f46..da2662af1 100644 --- a/client/src/cmdlfindala.c +++ b/client/src/cmdlfindala.c @@ -250,7 +250,7 @@ static int CmdIndalaDemod(const char *Cmd) { "lf indala demod --clock 32 -> demod a Indala tag from GraphBuffer using a clock of RF/32\n" "lf indala demod --clock 32 -i -> demod a Indala tag from GraphBuffer using a clock of RF/32 and inverting data\n" "lf indala demod --clock 64 -i --maxerror 0 -> demod a Indala tag from GraphBuffer using a clock of RF/64, inverting data and allowing 0 demod errors" - ); + ); void *argtable[] = { arg_param_begin, @@ -281,7 +281,7 @@ static int CmdIndalaDemodAlt(const char *Cmd) { "It's now considered obsolete but remains because it has sometimes its advantages.", "lf indala altdemod\n" "lf indala altdemod --long -> demod a Indala tag from GraphBuffer as 224 bit long format" - ); + ); void *argtable[] = { arg_param_begin, @@ -583,9 +583,9 @@ static int CmdIndalaSim(const char *Cmd) { // lf simpsk 1 c 32 r 2 d 0102030405060708 PrintAndLogEx(SUCCESS, "Simulating " _YELLOW_("%s") " Indala raw " _YELLOW_("%s") - , (is_long_uid) ? "224b" : "64b" - , sprint_hex_inrow(raw, raw_len) - ); + , (is_long_uid) ? "224b" : "64b" + , sprint_hex_inrow(raw, raw_len) + ); PrintAndLogEx(SUCCESS, "Press pm3-button to abort simulation or run another command"); // indala PSK, clock 32, carrier 0 @@ -665,7 +665,7 @@ static int CmdIndalaClone(const char *Cmd) { uint8_t max = 0; uint32_t blocks[8] = {0}; char cardtype[16] = {"T55x7"}; - + if (is_long_uid) { blocks[0] = T55x7_BITRATE_RF_32 | T55x7_MODULATION_PSK2 | (7 << T55x7_MAXBLOCK_SHIFT); @@ -673,7 +673,7 @@ static int CmdIndalaClone(const char *Cmd) { blocks[0] = T5555_FIXED | T5555_SET_BITRATE(32) | T5555_MODULATION_PSK2 | (7 << T5555_MAXBLOCK_SHIFT); snprintf(cardtype, sizeof(cardtype), "Q5/T5555"); } - + if (em) { blocks[0] = EM4305_INDALA_224_CONFIG_BLOCK; snprintf(cardtype, sizeof(cardtype), "EM4305/4469"); @@ -691,9 +691,9 @@ static int CmdIndalaClone(const char *Cmd) { // 224 BIT UID // config for Indala (RF/32;PSK2 with RF/2;Maxblock=7) PrintAndLogEx(INFO, "Preparing to clone Indala 224bit to " _YELLOW_("%s") " raw " _GREEN_("%s") - , cardtype - , sprint_hex_inrow(raw, raw_len) - ); + , cardtype + , sprint_hex_inrow(raw, raw_len) + ); } else { @@ -737,7 +737,7 @@ static int CmdIndalaClone(const char *Cmd) { blocks[0] = T5555_FIXED | T5555_SET_BITRATE(32) | T5555_MODULATION_PSK1 | (2 << T5555_MAXBLOCK_SHIFT); snprintf(cardtype, sizeof(cardtype), "Q5/T5555"); } - + if (em) { blocks[0] = EM4305_INDALA_64_CONFIG_BLOCK; snprintf(cardtype, sizeof(cardtype), "EM4305/4469"); @@ -749,9 +749,9 @@ static int CmdIndalaClone(const char *Cmd) { // config for Indala 64 format (RF/32;PSK1 with RF/2;Maxblock=2) PrintAndLogEx(INFO, "Preparing to clone Indala 64bit to " _YELLOW_("%s") " raw " _GREEN_("%s") - , cardtype - , sprint_hex_inrow(raw, raw_len) - ); + , cardtype + , sprint_hex_inrow(raw, raw_len) + ); } print_blocks(blocks, max); diff --git a/client/src/cmdlfio.c b/client/src/cmdlfio.c index 3adc0ed90..fd9ce6d1d 100644 --- a/client/src/cmdlfio.c +++ b/client/src/cmdlfio.c @@ -318,12 +318,12 @@ static int CmdIOProxClone(const char *Cmd) { blocks[2] = bytebits_to_byte(bits + 32, 32); PrintAndLogEx(INFO, "Preparing to clone ioProx to " _YELLOW_("%s") " with Version: " _GREEN_("%u") " FC: " _GREEN_("%u (0x%02x)") " CN: " _GREEN_("%u") - , cardtype - , version - , fc - , fc - , cn - ); + , cardtype + , version + , fc + , fc + , cn + ); print_blocks(blocks, ARRAYLEN(blocks)); int res; diff --git a/client/src/cmdlfjablotron.c b/client/src/cmdlfjablotron.c index 7e1f81557..6e8a35d2c 100644 --- a/client/src/cmdlfjablotron.c +++ b/client/src/cmdlfjablotron.c @@ -219,11 +219,11 @@ static int CmdJablotronClone(const char *Cmd) { free(bits); - uint64_t id = getJablontronCardId(fullcode); + uint64_t id = getJablontronCardId(fullcode); PrintAndLogEx(INFO, "Preparing to clone Jablotron to " _YELLOW_("%s") " with FullCode: " _GREEN_("%"PRIx64)" id: " _GREEN_("%"PRIx64), cardtype, fullcode, id); print_blocks(blocks, ARRAYLEN(blocks)); - + int res; if (em) { res = em4x05_clone_tag(blocks, ARRAYLEN(blocks), 0, false); diff --git a/client/src/cmdlfmotorola.c b/client/src/cmdlfmotorola.c index 3f2ce059c..336bdf7b2 100644 --- a/client/src/cmdlfmotorola.c +++ b/client/src/cmdlfmotorola.c @@ -264,7 +264,7 @@ static int CmdMotorolaSim(const char *Cmd) { }; CLIExecWithReturn(ctx, Cmd, argtable, true); CLIParserFree(ctx); - + // PSK sim. PrintAndLogEx(INFO, " PSK1 at 66 kHz... Interesting."); PrintAndLogEx(INFO, " To be implemented, feel free to contribute!"); diff --git a/client/src/cmdlfnedap.c b/client/src/cmdlfnedap.c index 1e87c85bf..20cb5eec5 100644 --- a/client/src/cmdlfnedap.c +++ b/client/src/cmdlfnedap.c @@ -145,13 +145,13 @@ int demodNedap(bool verbose) { badgeId = r1 * 10000 + r2 * 1000 + r3 * 100 + r4 * 10 + r5; PrintAndLogEx(SUCCESS, "NEDAP (%s) - ID: " _YELLOW_("%05u") " subtype: " _YELLOW_("%1u")" customer code: " _YELLOW_("%u / 0x%03X") " Raw: " _YELLOW_("%s") - , (size == 128) ? "128b" : "64b" - , badgeId - , subtype - , customerCode - , customerCode - , sprint_hex_inrow(data, size / 8) - ); + , (size == 128) ? "128b" : "64b" + , badgeId + , subtype + , customerCode + , customerCode + , sprint_hex_inrow(data, size / 8) + ); PrintAndLogEx(DEBUG, "Checksum (%s) 0x%04X", _GREEN_("ok"), checksum); } else { @@ -373,7 +373,7 @@ static int CmdLFNedapClone(const char *Cmd) { arg_u64_0(NULL, "st", "", "optional - sub type (default 5)"), arg_u64_1(NULL, "cc", "", "customer code (0-4095)"), arg_u64_1(NULL, "id", "", "ID (0-99999)"), - arg_lit0("l", "long", "optional - long (128), default to short (64)"), + arg_lit0("l", "long", "optional - long (128), default to short (64)"), arg_lit0(NULL, "q5", "optional - specify writing to Q5/T5555 tag"), arg_lit0(NULL, "em", "optional - specify writing to EM4305/4469 tag"), arg_param_end @@ -395,17 +395,17 @@ static int CmdLFNedapClone(const char *Cmd) { } if (sub_type > 0xF) { PrintAndLogEx(FAILED, "out-of-range, valid subtype is between 0-15"); - return PM3_EINVARG; + return PM3_EINVARG; } if (customer_code > 0xFFF) { PrintAndLogEx(FAILED, "out-of-range, valid customer code is between 0-4095"); - return PM3_EINVARG; + return PM3_EINVARG; } if (id > 99999) { PrintAndLogEx(FAILED, "out-of-range, id max value is 99999"); - return PM3_EINVARG; + return PM3_EINVARG; } PrintAndLogEx(SUCCESS, "NEDAP (%s) - ID: " _GREEN_("%05u") " subtype: " _GREEN_("%1u") " customer code: " _GREEN_("%u / 0x%03X") @@ -454,7 +454,7 @@ static int CmdLFNedapClone(const char *Cmd) { NedapGen(sub_type, customer_code, id, is_long, data); for (uint8_t i = 1; i < max ; i++) { - blocks[i] = bytes_to_num (data + ((i - 1) * 4), 4); + blocks[i] = bytes_to_num(data + ((i - 1) * 4), 4); } PrintAndLogEx(SUCCESS, "Preparing to clone NEDAP to " _YELLOW_("%s") " tag", cardtype); @@ -492,7 +492,7 @@ static int CmdLFNedapSim(const char *Cmd) { arg_u64_0(NULL, "st", "", "optional - sub type (default 5)"), arg_u64_1(NULL, "cc", "", "customer code (0-4095)"), arg_u64_1(NULL, "id", "", "ID (0-99999)"), - arg_lit0("l", "long", "optional - long (128), default to short (64)"), + arg_lit0("l", "long", "optional - long (128), default to short (64)"), arg_param_end }; CLIExecWithReturn(ctx, Cmd, argtable, false); @@ -502,20 +502,20 @@ static int CmdLFNedapSim(const char *Cmd) { uint32_t id = arg_get_u32_def(ctx, 3, 0); bool is_long = arg_get_lit(ctx, 4); CLIParserFree(ctx); - + if (sub_type > 0xF) { PrintAndLogEx(FAILED, "out-of-range, valid subtype is between 0-15"); - return PM3_EINVARG; + return PM3_EINVARG; } if (customer_code > 0xFFF) { PrintAndLogEx(FAILED, "out-of-range, valid customer code is between 0-4095"); - return PM3_EINVARG; + return PM3_EINVARG; } if (id > 99999) { PrintAndLogEx(FAILED, "out-of-range, id max value is 99999"); - return PM3_EINVARG; + return PM3_EINVARG; } PrintAndLogEx(SUCCESS, "NEDAP (%s) - ID: " _GREEN_("%05u") " subtype: " _GREEN_("%1u") " customer code: " _GREEN_("%u / 0x%03X") diff --git a/client/src/cmdlfpcf7931.c b/client/src/cmdlfpcf7931.c index 48a029e2b..bd744f8ba 100644 --- a/client/src/cmdlfpcf7931.c +++ b/client/src/cmdlfpcf7931.c @@ -125,7 +125,7 @@ static int CmdLFPCF7931Config(const char *Cmd) { } if (pwd_len) { - memcpy(configPcf.Pwd, pwd, sizeof(configPcf.Pwd)); + memcpy(configPcf.Pwd, pwd, sizeof(configPcf.Pwd)); } if (delay != -1) { configPcf.InitDelay = (delay & 0xFFFF); @@ -134,7 +134,7 @@ static int CmdLFPCF7931Config(const char *Cmd) { configPcf.OffsetWidth = (ow & 0xFFFF); } if (op != 0xFFFF) { - configPcf.OffsetPosition =(op & 0xFFFF); + configPcf.OffsetPosition = (op & 0xFFFF); } pcf7931_printConfig(); diff --git a/client/src/cmdlft55xx.c b/client/src/cmdlft55xx.c index a3f5ca20b..d67770ba3 100644 --- a/client/src/cmdlft55xx.c +++ b/client/src/cmdlft55xx.c @@ -2806,7 +2806,7 @@ char *GetModelStrFromCID(uint32_t cid) { } char *GetConfigBlock0Source(uint8_t id) { - + static char buf[40]; char *retStr = buf; diff --git a/client/src/cmdlft55xx.h b/client/src/cmdlft55xx.h index 90fbaa85d..d87194b25 100644 --- a/client/src/cmdlft55xx.h +++ b/client/src/cmdlft55xx.h @@ -129,7 +129,7 @@ typedef struct { notSet = 0x00, autoDetect = 0x01, userSet = 0x02, - tagRead = 0x03, + tagRead = 0x03, } block0Status; enum { RF_8 = 0x00, diff --git a/client/src/cmdlfti.c b/client/src/cmdlfti.c index b02ad2e34..3e8138332 100644 --- a/client/src/cmdlfti.c +++ b/client/src/cmdlfti.c @@ -330,7 +330,7 @@ static int CmdTIWrite(const char *Cmd) { arg_param_begin, arg_str1("r", "raw", "", "raw hex data. 8 bytes max"), arg_str0(NULL, "crc", "", "optional - crc"), - arg_param_end + arg_param_end }; CLIExecWithReturn(ctx, Cmd, argtable, false); @@ -354,7 +354,7 @@ static int CmdTIWrite(const char *Cmd) { payload.crc = bytes_to_num(crc, crc_len); clearCommandBuffer(); - SendCommandNG(CMD_LF_TI_WRITE, (uint8_t*)&payload, sizeof(payload)); + SendCommandNG(CMD_LF_TI_WRITE, (uint8_t *)&payload, sizeof(payload)); PrintAndLogEx(SUCCESS, "Done"); PrintAndLogEx(HINT, "Hint: try " _YELLOW_("`lf ti reader`") " to verify"); return PM3_SUCCESS; diff --git a/common/commonutil.c b/common/commonutil.c index 70114bba1..802f362d8 100644 --- a/common/commonutil.c +++ b/common/commonutil.c @@ -109,7 +109,7 @@ uint32_t reflect32(uint32_t b) { // swap bytes v = ((v >> 8) & 0x00FF00FF) | ((v & 0x00FF00FF) << 8); // swap 2-byte long pairs - v = ( v >> 16 ) | ( v << 16); + v = (v >> 16) | (v << 16); return v; } diff --git a/common/lfdemod.c b/common/lfdemod.c index 24de41676..171417143 100644 --- a/common/lfdemod.c +++ b/common/lfdemod.c @@ -1082,8 +1082,8 @@ int DetectPSKClock(uint8_t *dest, size_t size, int clock, size_t *firstPhaseShif if (g_debugMode == 2) prnt("DEBUG PSK: firstFullWave: %zu, waveLen: %d", firstFullWave, fullWaveLen); // Avoid autodetect if user selected a clock - for(uint8_t validClk = 1; validClk < 8; validClk++) { - if(clock == clk[validClk]) return(clock); + for (uint8_t validClk = 1; validClk < 8; validClk++) { + if (clock == clk[validClk]) return (clock); } //test each valid clock from greatest to smallest to see which lines up diff --git a/doc/commands.md b/doc/commands.md index 44489d546..58578c26e 100644 --- a/doc/commands.md +++ b/doc/commands.md @@ -38,7 +38,6 @@ Check column "offline" for their availability. |`analyse nuid `|Y |`create NUID from 7byte UID` |`analyse demodbuff `|Y |`Load binary string to demodbuffer` |`analyse freq `|Y |`Calc wave lengths` -|`analyse foo `|Y |`muxer` ### data @@ -143,6 +142,7 @@ Check column "offline" for their availability. |`hf 14a raw `|N |`Send raw hex data to tag` |`hf 14a antifuzz `|N |`Fuzzing the anticollision phase. Warning! Readers may react strange` |`hf 14a config `|N |`Configure 14a settings (use with caution)` +|`hf 14a apdufuzz `|N |`Fuzz APDU - CLA/INS/P1P2` ### hf 14b @@ -248,28 +248,29 @@ Check column "offline" for their availability. |command |offline |description |------- |------- |----------- -|`hf iclass help `|Y |`This help` -|`hf iclass dump `|N |`[options..] Dump Picopass / iCLASS tag to file` -|`hf iclass info `|Y |` Tag information` -|`hf iclass list `|Y |` List iclass history` -|`hf iclass rdbl `|N |`[options..] Read Picopass / iCLASS block` -|`hf iclass reader `|N |` Act like an Picopass / iCLASS reader` -|`hf iclass restore `|N |`[options..] Restore a dump file onto a Picopass / iCLASS tag` -|`hf iclass sniff `|N |` Eavesdrop Picopass / iCLASS communication` -|`hf iclass wrbl `|N |`[options..] Write Picopass / iCLASS block` -|`hf iclass chk `|N |`[options..] Check keys` -|`hf iclass loclass `|Y |`[options..] Use loclass to perform bruteforce reader attack` -|`hf iclass lookup `|Y |`[options..] Uses authentication trace to check for key in dictionary file` -|`hf iclass sim `|N |`[options..] Simulate iCLASS tag` -|`hf iclass eload `|N |`[f ] Load Picopass / iCLASS dump file into emulator memory` -|`hf iclass esave `|N |`[f ] Save emulator memory to file` -|`hf iclass eview `|N |`[options..] View emulator memory` -|`hf iclass calcnewkey `|Y |`[options..] Calc diversified keys (blocks 3 & 4) to write new keys` -|`hf iclass encrypt `|Y |`[options..] Encrypt given block data` -|`hf iclass decrypt `|Y |`[options..] Decrypt given block data or tag dump file` -|`hf iclass managekeys `|Y |`[options..] Manage keys to use with iclass commands` -|`hf iclass permutekey `|N |` Permute function from 'heart of darkness' paper` -|`hf iclass view `|Y |`[options..] Display content from tag dump file` +|`hf iclass help `|Y |` This help` +|`hf iclass dump `|N |`[*] Dump Picopass / iCLASS tag to file` +|`hf iclass info `|Y |` Tag information` +|`hf iclass list `|Y |` List iclass history` +|`hf iclass rdbl `|N |`[*] Read Picopass / iCLASS block` +|`hf iclass reader `|N |` Act like an Picopass / iCLASS reader` +|`hf iclass restore `|N |`[*] Restore a dump file onto a Picopass / iCLASS tag` +|`hf iclass sniff `|N |` Eavesdrop Picopass / iCLASS communication` +|`hf iclass wrbl `|N |`[*] Write Picopass / iCLASS block` +|`hf iclass chk `|N |`[*] Check keys` +|`hf iclass loclass `|Y |`[*] Use loclass to perform bruteforce reader attack` +|`hf iclass lookup `|Y |`[*] Uses authentication trace to check for key in dictionary file` +|`hf iclass sim `|N |`[*] Simulate iCLASS tag` +|`hf iclass eload `|N |`[*] Load Picopass / iCLASS dump file into emulator memory` +|`hf iclass esave `|N |`[*] Save emulator memory to file` +|`hf iclass eview `|N |`[.] View emulator memory` +|`hf iclass calcnewkey `|Y |`[*] Calc diversified keys (blocks 3 & 4) to write new keys` +|`hf iclass encode `|Y |`[*] Encode binary wiegand to block 7` +|`hf iclass encrypt `|Y |`[*] Encrypt given block data` +|`hf iclass decrypt `|Y |`[*] Decrypt given block data or tag dump file` +|`hf iclass managekeys `|Y |`[*] Manage keys to use with iclass commands` +|`hf iclass permutekey `|N |` Permute function from 'heart of darkness' paper` +|`hf iclass view `|Y |`[*] Display content from tag dump file` ### hf legic @@ -577,10 +578,10 @@ Check column "offline" for their availability. |command |offline |description |------- |------- |----------- |`lf em help `|Y |`This help` -|`lf em 410x `|Y |`EM 410x commands...` -|`lf em 4x05 `|Y |`EM 4x05 commands...` -|`lf em 4x50 `|Y |`EM 4x50 commands...` -|`lf em 4x70 `|Y |`EM 4x70 commands...` +|`lf em 410x `|Y |`EM 4102 commands...` +|`lf em 4x05 `|Y |`EM 4205 / 4305 / 4369 / 4469 commands...` +|`lf em 4x50 `|Y |`EM 4350 / 4450 commands...` +|`lf em 4x70 `|Y |`EM 4070 / 4170 commands...` ### lf fdxb @@ -672,9 +673,9 @@ Check column "offline" for their availability. |command |offline |description |------- |------- |----------- |`lf indala help `|Y |`this help` -|`lf indala demod `|Y |`demodulate an indala tag (PSK1) from GraphBuffer` -|`lf indala altdemod `|Y |`alternative method to Demodulate samples for Indala 64 bit UID (option '224' for 224 bit)` -|`lf indala reader `|N |`read an Indala Prox tag from the antenna` +|`lf indala demod `|Y |`demodulate an Indala tag (PSK1) from GraphBuffer` +|`lf indala altdemod `|Y |`alternative method to demodulate samples for Indala 64 bit UID (option '224' for 224 bit)` +|`lf indala reader `|N |`read an Indala tag from the antenna` |`lf indala clone `|N |`clone Indala tag to T55x7 or Q5/T5555` |`lf indala sim `|N |`simulate Indala tag` @@ -686,10 +687,10 @@ Check column "offline" for their availability. |command |offline |description |------- |------- |----------- |`lf io help `|Y |`this help` -|`lf io demod `|Y |`demodulate an IOProx tag from the GraphBuffer` +|`lf io demod `|Y |`demodulate an ioProx tag from the GraphBuffer` |`lf io reader `|N |`attempt to read and extract tag data` -|`lf io clone `|N |`clone IOProx tag to T55x7 or Q5/T5555` -|`lf io sim `|N |`simulate IOProx tag` +|`lf io clone `|N |`clone ioProx tag to T55x7 or Q5/T5555` +|`lf io sim `|N |`simulate ioProx tag` |`lf io watch `|N |`continuously watch for cards. Reader mode` @@ -1001,7 +1002,7 @@ Check column "offline" for their availability. |------- |------- |----------- |`wiegand help `|Y |`This help` |`wiegand list `|Y |`List available wiegand formats` -|`wiegand encode `|Y |`Encode to wiegand raw hex` -|`wiegand decode `|Y |`Convert raw hex to decoded wiegand format` +|`wiegand encode `|Y |`Encode to wiegand raw hex (currently for HID Prox)` +|`wiegand decode `|Y |`Convert raw hex to decoded wiegand format (currently for HID Prox)` From a6024a8622f86727f2880ed6aea3a2421bf45cd0 Mon Sep 17 00:00:00 2001 From: Christian Molson Date: Sat, 12 Dec 2020 09:59:30 -0500 Subject: [PATCH 035/682] EM4x70 Authentication support --- armsrc/appmain.c | 4 +++ armsrc/em4x70.c | 63 +++++++++++++++++++++++++++++++++++++- armsrc/em4x70.h | 1 + client/src/cmdlfem4x70.c | 65 ++++++++++++++++++++++++++++++++++++++++ client/src/cmdlfem4x70.h | 1 + include/em4x70.h | 4 +++ include/pm3_cmd.h | 1 + 7 files changed, 138 insertions(+), 1 deletion(-) 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 0b6cf36e6..991d6df93 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"); @@ -731,4 +771,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 2c845b377..da4690db9 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 -r 11223344556677 -f 11223344\n" + ); + + void *argtable[] = { + arg_param_begin, + arg_lit0("x", "par", "Add parity bit when sending commands"), + arg_str1("r", "rnd", "", "Random 56-bit"), + arg_str1("f", "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 From 701914430f19222f798b03dfe148ca9d27ddcbbf Mon Sep 17 00:00:00 2001 From: Christian Molson Date: Sat, 12 Dec 2020 10:02:43 -0500 Subject: [PATCH 036/682] em4x70 makestyle --- armsrc/em4x70.c | 16 ++++++++-------- client/src/cmdlfem4x70.c | 6 +++--- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/armsrc/em4x70.c b/armsrc/em4x70.c index fd34716a2..0bb18e7d2 100644 --- a/armsrc/em4x70.c +++ b/armsrc/em4x70.c @@ -365,31 +365,31 @@ static int authenticate(const uint8_t *rnd, const uint8_t *frnd, uint8_t *respon if (find_listen_window(true)) { em4x70_send_nibble(EM4X70_COMMAND_AUTH, true); - + // Send 56-bit Random number - for(int i=0;i<7;i++) { + 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++) { + 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++) { + 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) { + if (num < 10) { Dbprintf("Auth failed"); return PM3_ESOFT; } diff --git a/client/src/cmdlfem4x70.c b/client/src/cmdlfem4x70.c index 877ee6d63..4172f0dc4 100644 --- a/client/src/cmdlfem4x70.c +++ b/client/src/cmdlfem4x70.c @@ -253,7 +253,7 @@ int CmdEM4x70Auth(const char *Cmd) { "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, @@ -264,9 +264,9 @@ int CmdEM4x70Auth(const char *Cmd) { }; CLIExecWithReturn(ctx, Cmd, argtable, true); - + etd.parity = arg_get_lit(ctx, 1); - + int rnd_len = 7; CLIGetHexWithReturn(ctx, 2, etd.rnd, &rnd_len); From 89099cf1a18a32232ed5cd7a4303bf8592f2bed7 Mon Sep 17 00:00:00 2001 From: Christian Molson Date: Sat, 12 Dec 2020 10:31:00 -0500 Subject: [PATCH 037/682] EM4x70 remove short command options from authentication. --- client/src/cmdlfem4x70.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/client/src/cmdlfem4x70.c b/client/src/cmdlfem4x70.c index 4172f0dc4..a13d29073 100644 --- a/client/src/cmdlfem4x70.c +++ b/client/src/cmdlfem4x70.c @@ -252,14 +252,14 @@ 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 -r 11223344556677 -f 11223344\n" + "lf em 4x70 auth --rnd 11223344556677 --frn 11223344\n" ); void *argtable[] = { arg_param_begin, - arg_lit0("x", "par", "Add parity bit when sending commands"), - arg_str1("r", "rnd", "", "Random 56-bit"), - arg_str1("f", "frn", "", "F(RN) 28-bit as 4 hex bytes"), + 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 }; From a895fbd3c689df3075c363bf395b712ccfaef768 Mon Sep 17 00:00:00 2001 From: Ave Date: Sat, 12 Dec 2020 20:26:54 +0300 Subject: [PATCH 038/682] emrtd: Implement secure_read_file --- client/src/cmdhfemrtd.c | 107 ++++++++++++++++++++++++++++++++-------- 1 file changed, 87 insertions(+), 20 deletions(-) diff --git a/client/src/cmdhfemrtd.c b/client/src/cmdhfemrtd.c index ae25140e2..aa0b6c9b8 100644 --- a/client/src/cmdhfemrtd.c +++ b/client/src/cmdhfemrtd.c @@ -60,7 +60,7 @@ static int exchange_commands(const char *cmd, uint8_t *dataout, int *dataoutlen, PrintAndLogEx(DEBUG, "Sending: %s", cmd); - uint8_t aCMD[100]; + uint8_t aCMD[500]; int aCMD_n = 0; param_gethex_to_eol(cmd, 0, aCMD, sizeof(aCMD), &aCMD_n); int res = ExchangeAPDU14a(aCMD, aCMD_n, activate_field, keep_field_on, response, sizeof(response), &resplen); @@ -113,10 +113,8 @@ static int asn1datalength(uint8_t *datain, int datainlen) { // lazy - https://stackoverflow.com/a/4214350/3286892 char subbuff[8]; - memcpy(subbuff, &dataintext[2], 2); - subbuff[2] = '\0'; - int thing = (int)strtol(subbuff, NULL, 16); + int thing = *(datain + 1); if (thing <= 0x7f) { return thing; } else if (thing == 0x81) { @@ -136,14 +134,7 @@ static int asn1datalength(uint8_t *datain, int datainlen) { } static int asn1fieldlength(uint8_t *datain, int datainlen) { - char *dataintext = sprint_hex_inrow(datain, datainlen); - - // lazy - https://stackoverflow.com/a/4214350/3286892 - char subbuff[8]; - memcpy(subbuff, &dataintext[2], 2); - subbuff[2] = '\0'; - - int thing = (int)strtol(subbuff, NULL, 16); + int thing = *(datain + 1); if (thing <= 0x7f) { return 2; } else if (thing == 0x81) { @@ -213,14 +204,14 @@ static int pad_block(uint8_t *input, int inputlen, uint8_t *output) { } static void retail_mac(uint8_t *key, uint8_t *input, int inputlen, uint8_t *output) { - // This code assumes blocklength (n) = 8, and input len of up to 56 chars + // This code assumes blocklength (n) = 8, and input len of up to 240 or so chars // This code takes inspirations from https://github.com/devinvenable/iso9797algorithm3 uint8_t k0[8]; uint8_t k1[8]; uint8_t intermediate[8] = {0x00}; - uint8_t intermediate_des[32]; + uint8_t intermediate_des[256]; uint8_t block[8]; - uint8_t message[64]; + uint8_t message[256]; // Populate keys memcpy(k0, key, 8); @@ -439,7 +430,7 @@ static bool secure_select_file(uint8_t *kenc, uint8_t *kmac, uint8_t *ssc, uint8 return check_cc(ssc, kmac, response, resplen); } -static bool secure_read_binary(uint8_t *kmac, uint8_t *ssc, int offset, int bytes_to_read, uint8_t *dataout, int *dataoutlen) { +static bool _secure_read_binary(uint8_t *kmac, uint8_t *ssc, int offset, int bytes_to_read, uint8_t *dataout, int *dataoutlen) { char command[54]; uint8_t cmd[8]; uint8_t data[21]; @@ -500,8 +491,69 @@ static bool secure_read_binary(uint8_t *kmac, uint8_t *ssc, int offset, int byte return check_cc(ssc, kmac, dataout, *dataoutlen); } +static bool _secure_read_binary_decrypt(uint8_t *kenc, uint8_t *kmac, uint8_t *ssc, int offset, int bytes_to_read, uint8_t *dataout, int *dataoutlen) { + uint8_t response[500]; + uint8_t temp[500]; + int resplen, cutat = 0; + uint8_t iv[8] = { 0x00 }; + + if (_secure_read_binary(kmac, ssc, offset, bytes_to_read, response, &resplen) == false) { + return false; + } + + PrintAndLogEx(DEBUG, "0offset %i on %i: ? (crypt: %s)", offset, bytes_to_read, sprint_hex_inrow(response, resplen)); + + cutat = ((int) response[1]) - 1; + + PrintAndLogEx(DEBUG, "1offset %i on %i: ? (crypt: %s)", offset, bytes_to_read, sprint_hex_inrow(response, resplen)); + des3_decrypt_cbc(iv, kenc, response + 3, cutat, temp); + PrintAndLogEx(DEBUG, "2eoffset %i on %i: ? (crypt: %s)", offset, bytes_to_read, sprint_hex_inrow(response, resplen)); + PrintAndLogEx(DEBUG, "2aoffset %i on %i: %s", offset, bytes_to_read, sprint_hex_inrow(temp, cutat)); + PrintAndLogEx(DEBUG, "2boffset %i on %i: c %s", offset, bytes_to_read, sprint_hex_inrow(response, resplen)); + memcpy(dataout, temp, bytes_to_read); + PrintAndLogEx(DEBUG, "3offset %i on %i: %s (crypt: %s)", offset, bytes_to_read, sprint_hex_inrow(temp, cutat), sprint_hex_inrow(response, resplen)); + *dataoutlen = bytes_to_read; + return true; +} + +static int secure_read_file(uint8_t *kenc, uint8_t *kmac, uint8_t *ssc, uint8_t *dataout, int *dataoutlen) { + uint8_t response[500]; + int resplen = 0; + uint8_t tempresponse[500]; + int tempresplen = 0; + + if (!_secure_read_binary_decrypt(kenc, kmac, ssc, 0, 4, response, &resplen)) { + return false; + } + + int datalen = asn1datalength(response, resplen); + int readlen = datalen - (3 - asn1fieldlength(response, resplen) / 2); + int offset = 4; + int toread; + + while (readlen > 0) { + toread = readlen; + if (readlen > 118) { + toread = 118; + } + + if (!_secure_read_binary_decrypt(kenc, kmac, ssc, offset, toread, tempresponse, &tempresplen)) { + return false; + } + + memcpy(response + resplen, tempresponse, tempresplen); + offset += toread; + readlen -= toread; + resplen += tempresplen; + } + + memcpy(dataout, &response, resplen); + *dataoutlen = resplen; + return true; +} + int infoHF_EMRTD(char *documentnumber, char *dob, char *expiry) { - uint8_t response[PM3_CMD_DATA_SIZE]; + uint8_t response[500]; uint8_t rnd_ic[8]; uint8_t kenc[50]; uint8_t kmac[50]; @@ -647,12 +699,27 @@ int infoHF_EMRTD(char *documentnumber, char *dob, char *expiry) { return PM3_ESOFT; } - if (secure_read_binary(ks_mac, ssc, 0, 4, response, &resplen) == false) { - PrintAndLogEx(ERR, "Failed to read EF_COM, crypto checksum check failed."); + if (secure_read_file(ks_enc, ks_mac, ssc, response, &resplen) == false) { + PrintAndLogEx(ERR, "Failed to read EF_COM."); DropField(); return PM3_ESOFT; } - // TODO: impl secure read file + PrintAndLogEx(INFO, "EF_COM: %s", sprint_hex_inrow(response, resplen)); + + // Select EF_DG1 + file_id[1] = 0x01; + if (secure_select_file(ks_enc, ks_mac, ssc, file_id) == false) { + PrintAndLogEx(ERR, "Failed to secure select EF_DG1, crypto checksum check failed."); + DropField(); + return PM3_ESOFT; + } + + if (secure_read_file(ks_enc, ks_mac, ssc, response, &resplen) == false) { + PrintAndLogEx(ERR, "Failed to read EF_DG1."); + DropField(); + return PM3_ESOFT; + } + PrintAndLogEx(INFO, "EF_DG1: %s", sprint_hex_inrow(response, resplen)); DropField(); return PM3_SUCCESS; From 42e6763ea1dc139a2ce331e4b2bd0f8fd5684164 Mon Sep 17 00:00:00 2001 From: Ave Date: Sat, 12 Dec 2020 20:55:16 +0300 Subject: [PATCH 039/682] emrtd: Improve and clean asn1datalength and asn1fieldlength --- client/src/cmdhfemrtd.c | 69 ++++++++++++++++++----------------------- 1 file changed, 30 insertions(+), 39 deletions(-) diff --git a/client/src/cmdhfemrtd.c b/client/src/cmdhfemrtd.c index aa0b6c9b8..8a6cf05a8 100644 --- a/client/src/cmdhfemrtd.c +++ b/client/src/cmdhfemrtd.c @@ -108,41 +108,34 @@ static char calculate_check_digit(char *data) { return cd % 10; } -static int asn1datalength(uint8_t *datain, int datainlen) { - char *dataintext = sprint_hex_inrow(datain, datainlen); - - // lazy - https://stackoverflow.com/a/4214350/3286892 - char subbuff[8]; - - int thing = *(datain + 1); - if (thing <= 0x7f) { - return thing; - } else if (thing == 0x81) { - memcpy(subbuff, &dataintext[2], 3); - subbuff[3] = '\0'; - return (int)strtol(subbuff, NULL, 16); - } else if (thing == 0x82) { - memcpy(subbuff, &dataintext[2], 5); - subbuff[5] = '\0'; - return (int)strtol(subbuff, NULL, 16); - } else if (thing == 0x83) { - memcpy(subbuff, &dataintext[2], 7); - subbuff[7] = '\0'; - return (int)strtol(subbuff, NULL, 16); +static int asn1datalength(uint8_t *datain, int datainlen, int offset) { + PrintAndLogEx(DEBUG, "asn1datalength, datain: %s", sprint_hex_inrow(datain, datainlen)); + int lenfield = (int) *(datain + offset); + PrintAndLogEx(DEBUG, "asn1datalength, lenfield: %i", lenfield); + if (lenfield <= 0x7f) { + return lenfield; + } else if (lenfield == 0x81) { + return ((int) *(datain + offset + 1)); + } else if (lenfield == 0x82) { + return ((int) *(datain + offset + 1) << 8) | ((int) *(datain + offset + 2)); + } else if (lenfield == 0x83) { + return (((int) *(datain + offset + 1) << 16) | ((int) *(datain + offset + 2)) << 8) | ((int) *(datain + offset + 3)); } return false; } -static int asn1fieldlength(uint8_t *datain, int datainlen) { - int thing = *(datain + 1); - if (thing <= 0x7f) { +static int asn1fieldlength(uint8_t *datain, int datainlen, int offset) { + PrintAndLogEx(DEBUG, "asn1fieldlength, datain: %s", sprint_hex_inrow(datain, datainlen)); + int lenfield = (int) *(datain + offset); + PrintAndLogEx(DEBUG, "asn1fieldlength, thing: %i", lenfield); + if (lenfield <= 0x7f) { + return 1; + } else if (lenfield == 0x81) { return 2; - } else if (thing == 0x81) { + } else if (lenfield == 0x82) { + return 3; + } else if (lenfield == 0x83) { return 4; - } else if (thing == 0x82) { - return 6; - } else if (thing == 0x83) { - return 8; } return false; } @@ -310,8 +303,8 @@ static int read_file(uint8_t *dataout, int *dataoutlen) { return false; } - int datalen = asn1datalength(response, resplen); - int readlen = datalen - (3 - asn1fieldlength(response, resplen) / 2); + int datalen = asn1datalength(response, resplen, 1); + int readlen = datalen - (3 - asn1fieldlength(response, resplen, 1)); int offset = 4; int toread; @@ -501,22 +494,20 @@ static bool _secure_read_binary_decrypt(uint8_t *kenc, uint8_t *kmac, uint8_t *s return false; } - PrintAndLogEx(DEBUG, "0offset %i on %i: ? (crypt: %s)", offset, bytes_to_read, sprint_hex_inrow(response, resplen)); + PrintAndLogEx(DEBUG, "secreadbindec, offset %i on read %i: encrypted: %s", offset, bytes_to_read, sprint_hex_inrow(response, resplen)); cutat = ((int) response[1]) - 1; - PrintAndLogEx(DEBUG, "1offset %i on %i: ? (crypt: %s)", offset, bytes_to_read, sprint_hex_inrow(response, resplen)); des3_decrypt_cbc(iv, kenc, response + 3, cutat, temp); - PrintAndLogEx(DEBUG, "2eoffset %i on %i: ? (crypt: %s)", offset, bytes_to_read, sprint_hex_inrow(response, resplen)); - PrintAndLogEx(DEBUG, "2aoffset %i on %i: %s", offset, bytes_to_read, sprint_hex_inrow(temp, cutat)); - PrintAndLogEx(DEBUG, "2boffset %i on %i: c %s", offset, bytes_to_read, sprint_hex_inrow(response, resplen)); memcpy(dataout, temp, bytes_to_read); - PrintAndLogEx(DEBUG, "3offset %i on %i: %s (crypt: %s)", offset, bytes_to_read, sprint_hex_inrow(temp, cutat), sprint_hex_inrow(response, resplen)); + PrintAndLogEx(DEBUG, "secreadbindec, offset %i on read %i: decrypted: %s", offset, bytes_to_read, sprint_hex_inrow(temp, cutat)); + PrintAndLogEx(DEBUG, "secreadbindec, offset %i on read %i: decrypted and cut: %s", offset, bytes_to_read, sprint_hex_inrow(dataout, bytes_to_read)); *dataoutlen = bytes_to_read; return true; } static int secure_read_file(uint8_t *kenc, uint8_t *kmac, uint8_t *ssc, uint8_t *dataout, int *dataoutlen) { + // TODO: join this with regular read file uint8_t response[500]; int resplen = 0; uint8_t tempresponse[500]; @@ -526,8 +517,8 @@ static int secure_read_file(uint8_t *kenc, uint8_t *kmac, uint8_t *ssc, uint8_t return false; } - int datalen = asn1datalength(response, resplen); - int readlen = datalen - (3 - asn1fieldlength(response, resplen) / 2); + int datalen = asn1datalength(response, resplen, 1); + int readlen = datalen - (3 - asn1fieldlength(response, resplen, 1)); int offset = 4; int toread; From 3dd4f580c8a95315e67f4ff5b16c68050542c2ca Mon Sep 17 00:00:00 2001 From: Ave Date: Sat, 12 Dec 2020 21:11:17 +0300 Subject: [PATCH 040/682] emrtd: Have secure_select_file accept string filenames --- client/src/cmdhfemrtd.c | 23 +++++++++++++++++------ 1 file changed, 17 insertions(+), 6 deletions(-) diff --git a/client/src/cmdhfemrtd.c b/client/src/cmdhfemrtd.c index 8a6cf05a8..9f3732874 100644 --- a/client/src/cmdhfemrtd.c +++ b/client/src/cmdhfemrtd.c @@ -363,11 +363,24 @@ static bool check_cc(uint8_t *ssc, uint8_t *key, uint8_t *rapdu, int rapdulength return memcmp(cc, rapdu + (rapdulength - 8), 8) == 0; } -static bool secure_select_file(uint8_t *kenc, uint8_t *kmac, uint8_t *ssc, uint8_t *file) { +static void _convert_filename(const char *file, uint8_t *dataout) { + char temp[3]; + memcpy(temp, file, 2); + dataout[0] = (int)strtol(temp, NULL, 16); + memcpy(temp, file + 2, 2); + dataout[1] = (int)strtol(temp, NULL, 16); +} + +static bool secure_select_file(uint8_t *kenc, uint8_t *kmac, uint8_t *ssc, const char *file) { // Get data even tho we'll not use it + // TODO: make a func to send without receive uint8_t response[PM3_CMD_DATA_SIZE]; int resplen = 0; + // convert filename of string to bytes + uint8_t file_id[2]; + _convert_filename(file, file_id); + uint8_t iv[8] = { 0x00 }; char command[54]; uint8_t cmd[8]; @@ -375,7 +388,7 @@ static bool secure_select_file(uint8_t *kenc, uint8_t *kmac, uint8_t *ssc, uint8 uint8_t temp[8] = {0x0c, 0xa4, 0x02, 0x0c}; int cmdlen = pad_block(temp, 4, cmd); - int datalen = pad_block(file, 2, data); + int datalen = pad_block(file_id, 2, data); PrintAndLogEx(DEBUG, "cmd: %s", sprint_hex_inrow(cmd, cmdlen)); PrintAndLogEx(DEBUG, "data: %s", sprint_hex_inrow(data, datalen)); @@ -683,8 +696,7 @@ int infoHF_EMRTD(char *documentnumber, char *dob, char *expiry) { PrintAndLogEx(DEBUG, "ssc: %s", sprint_hex_inrow(ssc, 8)); // Select EF_COM - uint8_t file_id[2] = {0x01, 0x1E}; - if (secure_select_file(ks_enc, ks_mac, ssc, file_id) == false) { + if (secure_select_file(ks_enc, ks_mac, ssc, EF_COM) == false) { PrintAndLogEx(ERR, "Failed to secure select EF_COM, crypto checksum check failed."); DropField(); return PM3_ESOFT; @@ -698,8 +710,7 @@ int infoHF_EMRTD(char *documentnumber, char *dob, char *expiry) { PrintAndLogEx(INFO, "EF_COM: %s", sprint_hex_inrow(response, resplen)); // Select EF_DG1 - file_id[1] = 0x01; - if (secure_select_file(ks_enc, ks_mac, ssc, file_id) == false) { + if (secure_select_file(ks_enc, ks_mac, ssc, EF_DG1) == false) { PrintAndLogEx(ERR, "Failed to secure select EF_DG1, crypto checksum check failed."); DropField(); return PM3_ESOFT; From c2531e7ed0dda3ab1aebc12e4eda67b0558a67e7 Mon Sep 17 00:00:00 2001 From: Ave Date: Sat, 12 Dec 2020 21:19:51 +0300 Subject: [PATCH 041/682] emrtd: Rename from hf emrtd info to dump, code cleanup --- client/src/cmdhfemrtd.c | 32 +++++++++++++++++--------------- client/src/cmdhfemrtd.h | 2 +- 2 files changed, 18 insertions(+), 16 deletions(-) diff --git a/client/src/cmdhfemrtd.c b/client/src/cmdhfemrtd.c index 9f3732874..c2611dc8f 100644 --- a/client/src/cmdhfemrtd.c +++ b/client/src/cmdhfemrtd.c @@ -54,7 +54,8 @@ static uint16_t get_sw(uint8_t *d, uint8_t n) { return d[n] * 0x0100 + d[n + 1]; } -static int exchange_commands(const char *cmd, uint8_t *dataout, int *dataoutlen, bool activate_field, bool keep_field_on) { +static bool exchange_commands(const char *cmd, uint8_t *dataout, int *dataoutlen, bool activate_field, bool keep_field_on) { + // TODO: Account for 14b too uint8_t response[PM3_CMD_DATA_SIZE]; int resplen = 0; @@ -86,6 +87,13 @@ static int exchange_commands(const char *cmd, uint8_t *dataout, int *dataoutlen, return true; } +static int exchange_commands_noout(const char *cmd, bool activate_field, bool keep_field_on) { + uint8_t response[PM3_CMD_DATA_SIZE]; + int resplen = 0; + + return exchange_commands(cmd, response, &resplen, activate_field, keep_field_on); +} + static char calculate_check_digit(char *data) { int mrz_weight[] = {7, 3, 1}; int cd = 0; @@ -261,14 +269,10 @@ static void deskey(uint8_t *seed, uint8_t *type, int length, uint8_t *dataout) { static int select_file(const char *select_by, const char *file_id, bool activate_field, bool keep_field_on) { size_t file_id_len = strlen(file_id) / 2; - // Get data even tho we'll not use it - uint8_t response[PM3_CMD_DATA_SIZE]; - int resplen = 0; - char cmd[50]; sprintf(cmd, "00%s%s0C%02lu%s", SELECT, select_by, file_id_len, file_id); - return exchange_commands(cmd, response, &resplen, activate_field, keep_field_on); + return exchange_commands_noout(cmd, activate_field, keep_field_on); } static int get_challenge(int length, uint8_t *dataout, int *dataoutlen) { @@ -372,8 +376,6 @@ static void _convert_filename(const char *file, uint8_t *dataout) { } static bool secure_select_file(uint8_t *kenc, uint8_t *kmac, uint8_t *ssc, const char *file) { - // Get data even tho we'll not use it - // TODO: make a func to send without receive uint8_t response[PM3_CMD_DATA_SIZE]; int resplen = 0; @@ -556,7 +558,7 @@ static int secure_read_file(uint8_t *kenc, uint8_t *kmac, uint8_t *ssc, uint8_t return true; } -int infoHF_EMRTD(char *documentnumber, char *dob, char *expiry) { +int dumpHF_EMRTD(char *documentnumber, char *dob, char *expiry) { uint8_t response[500]; uint8_t rnd_ic[8]; uint8_t kenc[50]; @@ -727,11 +729,11 @@ int infoHF_EMRTD(char *documentnumber, char *dob, char *expiry) { return PM3_SUCCESS; } -static int cmd_hf_emrtd_info(const char *Cmd) { +static int cmd_hf_emrtd_dump(const char *Cmd) { CLIParserContext *ctx; - CLIParserInit(&ctx, "hf emrtd info", - "Get info about an eMRTD", - "hf emrtd info" + CLIParserInit(&ctx, "hf emrtd dump", + "Dump all files on an eMRTD", + "hf emrtd dump" ); void *argtable[] = { @@ -754,7 +756,7 @@ static int cmd_hf_emrtd_info(const char *Cmd) { CLIGetStrWithReturn(ctx, 3, expiry, &expirylen); CLIParserFree(ctx); - return infoHF_EMRTD((char *)docnum, (char *)dob, (char *)expiry); + return dumpHF_EMRTD((char *)docnum, (char *)dob, (char *)expiry); } static int cmd_hf_emrtd_list(const char *Cmd) { @@ -769,7 +771,7 @@ static int cmd_hf_emrtd_list(const char *Cmd) { static command_t CommandTable[] = { {"help", CmdHelp, AlwaysAvailable, "This help"}, - {"info", cmd_hf_emrtd_info, IfPm3Iso14443a, "Tag information"}, + {"dump", cmd_hf_emrtd_dump, IfPm3Iso14443, "Dump eMRTD files to binary files"}, {"list", cmd_hf_emrtd_list, AlwaysAvailable, "List ISO 14443A/7816 history"}, {NULL, NULL, NULL, NULL} }; diff --git a/client/src/cmdhfemrtd.h b/client/src/cmdhfemrtd.h index ba9e3f2b3..5899ad27a 100644 --- a/client/src/cmdhfemrtd.h +++ b/client/src/cmdhfemrtd.h @@ -15,5 +15,5 @@ int CmdHFeMRTD(const char *Cmd); -int infoHF_EMRTD(char *documentnumber, char *dob, char *expiry); +int dumpHF_EMRTD(char *documentnumber, char *dob, char *expiry); #endif From d1d5d8ee740d2fe9992020c98e235dd2d8e62d03 Mon Sep 17 00:00:00 2001 From: Ave Date: Sat, 12 Dec 2020 21:54:23 +0300 Subject: [PATCH 042/682] emrtd: account for larger file reads, read ef_dg2 --- client/src/cmdhfemrtd.c | 64 ++++++++++++++++++++++++++++++++--------- 1 file changed, 51 insertions(+), 13 deletions(-) diff --git a/client/src/cmdhfemrtd.c b/client/src/cmdhfemrtd.c index c2611dc8f..c00919835 100644 --- a/client/src/cmdhfemrtd.c +++ b/client/src/cmdhfemrtd.c @@ -40,6 +40,22 @@ #define EF_CARDACCESS "011C" #define EF_COM "011E" #define EF_DG1 "0101" +#define EF_DG2 "0102" +#define EF_DG3 "0103" +#define EF_DG4 "0104" +#define EF_DG5 "0105" +#define EF_DG6 "0106" +#define EF_DG7 "0107" +#define EF_DG8 "0108" +#define EF_DG9 "0109" +#define EF_DG10 "010A" +#define EF_DG11 "010B" +#define EF_DG12 "010C" +#define EF_DG13 "010D" +#define EF_DG14 "010E" +#define EF_DG15 "010F" +#define EF_DG16 "0110" +#define EF_SOD "011D" // App IDs #define AID_MRTD "A0000002471001" @@ -333,12 +349,26 @@ static int read_file(uint8_t *dataout, int *dataoutlen) { return true; } +static void bump_ssc(uint8_t *ssc) { + PrintAndLogEx(DEBUG, "ssc-b: %s", sprint_hex_inrow(ssc, 8)); + for (int i = 7; i > 0; i--) { + if ((*(ssc + i)) == 0xFF) { + // Set anything already FF to 0, we'll do + 1 on num to left anyways + (*(ssc + i)) = 0; + continue; + } + (*(ssc + i)) += 1; + PrintAndLogEx(DEBUG, "ssc-a: %s", sprint_hex_inrow(ssc, 8)); + return; + } +} + static bool check_cc(uint8_t *ssc, uint8_t *key, uint8_t *rapdu, int rapdulength) { // https://elixi.re/i/clarkson.png - uint8_t k[100]; - uint8_t cc[100]; + uint8_t k[500]; + uint8_t cc[500]; - (*(ssc + 7)) += 1; + bump_ssc(ssc); memcpy(k, ssc, 8); int length = 0; @@ -405,10 +435,7 @@ static bool secure_select_file(uint8_t *kenc, uint8_t *kmac, uint8_t *ssc, const memcpy(m + cmdlen, do87, (datalen + 3)); PrintAndLogEx(DEBUG, "m: %s", sprint_hex_inrow(m, datalen + cmdlen + 3)); - // TODO: this is hacky - PrintAndLogEx(DEBUG, "ssc-b: %s", sprint_hex_inrow(ssc, 8)); - (*(ssc + 7)) += 1; - PrintAndLogEx(DEBUG, "ssc-a: %s", sprint_hex_inrow(ssc, 8)); + bump_ssc(ssc); uint8_t n[27]; memcpy(n, ssc, 8); @@ -466,10 +493,7 @@ static bool _secure_read_binary(uint8_t *kmac, uint8_t *ssc, int offset, int byt memcpy(m, cmd, 8); memcpy(m + 8, do97, 3); - // TODO: this is hacky - PrintAndLogEx(DEBUG, "ssc-b: %s", sprint_hex_inrow(ssc, 8)); - (*(ssc + 7)) += 1; - PrintAndLogEx(DEBUG, "ssc-a: %s", sprint_hex_inrow(ssc, 8)); + bump_ssc(ssc); uint8_t n[19]; memcpy(n, ssc, 8); @@ -523,7 +547,7 @@ static bool _secure_read_binary_decrypt(uint8_t *kenc, uint8_t *kmac, uint8_t *s static int secure_read_file(uint8_t *kenc, uint8_t *kmac, uint8_t *ssc, uint8_t *dataout, int *dataoutlen) { // TODO: join this with regular read file - uint8_t response[500]; + uint8_t response[25000]; int resplen = 0; uint8_t tempresponse[500]; int tempresplen = 0; @@ -559,7 +583,7 @@ static int secure_read_file(uint8_t *kenc, uint8_t *kmac, uint8_t *ssc, uint8_t } int dumpHF_EMRTD(char *documentnumber, char *dob, char *expiry) { - uint8_t response[500]; + uint8_t response[25000]; uint8_t rnd_ic[8]; uint8_t kenc[50]; uint8_t kmac[50]; @@ -725,6 +749,20 @@ int dumpHF_EMRTD(char *documentnumber, char *dob, char *expiry) { } PrintAndLogEx(INFO, "EF_DG1: %s", sprint_hex_inrow(response, resplen)); + // Select EF_DG2 + if (secure_select_file(ks_enc, ks_mac, ssc, EF_DG2) == false) { + PrintAndLogEx(ERR, "Failed to secure select EF_DG2, crypto checksum check failed."); + DropField(); + return PM3_ESOFT; + } + + if (secure_read_file(ks_enc, ks_mac, ssc, response, &resplen) == false) { + PrintAndLogEx(ERR, "Failed to read EF_DG2."); + DropField(); + return PM3_ESOFT; + } + PrintAndLogEx(INFO, "EF_DG2 (len: %i): %s", resplen, sprint_hex_inrow(response, resplen)); + DropField(); return PM3_SUCCESS; } From ac82a80afa7d4ba8e159beebe1e337fbd73953c1 Mon Sep 17 00:00:00 2001 From: Ave Date: Sat, 12 Dec 2020 22:10:40 +0300 Subject: [PATCH 043/682] emrtd: Read more files, save read files --- client/src/cmdhfemrtd.c | 82 ++++++++++++++++++++++++++++++++++++++--- 1 file changed, 77 insertions(+), 5 deletions(-) diff --git a/client/src/cmdhfemrtd.c b/client/src/cmdhfemrtd.c index c00919835..65dc1c200 100644 --- a/client/src/cmdhfemrtd.c +++ b/client/src/cmdhfemrtd.c @@ -12,7 +12,7 @@ #include "cmdhfemrtd.h" #include -#include "fileutils.h" +#include "fileutils.h" // saveFile #include "cmdparser.h" // command_t #include "comms.h" // clearCommandBuffer #include "cmdtrace.h" @@ -600,7 +600,8 @@ int dumpHF_EMRTD(char *documentnumber, char *dob, char *expiry) { // Select and read EF_CardAccess if (select_file(P1_SELECT_BY_EF, EF_CARDACCESS, true, true)) { read_file(response, &resplen); - PrintAndLogEx(INFO, "EF_CardAccess: %s", sprint_hex(response, resplen)); + PrintAndLogEx(INFO, "Read EF_CardAccess, len: %i.", resplen); + PrintAndLogEx(DEBUG, "Contents (may be incomplete over 2k chars): %s", sprint_hex_inrow(response, resplen)); } else { PrintAndLogEx(INFO, "PACE unsupported. Will not read EF_CardAccess."); } @@ -733,8 +734,11 @@ int dumpHF_EMRTD(char *documentnumber, char *dob, char *expiry) { DropField(); return PM3_ESOFT; } - PrintAndLogEx(INFO, "EF_COM: %s", sprint_hex_inrow(response, resplen)); + PrintAndLogEx(INFO, "Read EF_COM, len: %i.", resplen); + PrintAndLogEx(DEBUG, "Contents (may be incomplete over 2k chars): %s", sprint_hex_inrow(response, resplen)); + saveFile("EF_COM", ".BIN", response, resplen); + // TODO: Don't read a hardcoded list of files, reduce code repetition // Select EF_DG1 if (secure_select_file(ks_enc, ks_mac, ssc, EF_DG1) == false) { PrintAndLogEx(ERR, "Failed to secure select EF_DG1, crypto checksum check failed."); @@ -747,7 +751,9 @@ int dumpHF_EMRTD(char *documentnumber, char *dob, char *expiry) { DropField(); return PM3_ESOFT; } - PrintAndLogEx(INFO, "EF_DG1: %s", sprint_hex_inrow(response, resplen)); + PrintAndLogEx(INFO, "Read EF_DG1, len: %i.", resplen); + PrintAndLogEx(DEBUG, "Contents (may be incomplete over 2k chars): %s", sprint_hex_inrow(response, resplen)); + saveFile("EF_DG1", ".BIN", response, resplen); // Select EF_DG2 if (secure_select_file(ks_enc, ks_mac, ssc, EF_DG2) == false) { @@ -761,7 +767,73 @@ int dumpHF_EMRTD(char *documentnumber, char *dob, char *expiry) { DropField(); return PM3_ESOFT; } - PrintAndLogEx(INFO, "EF_DG2 (len: %i): %s", resplen, sprint_hex_inrow(response, resplen)); + PrintAndLogEx(INFO, "Read EF_DG2, len: %i.", resplen); + PrintAndLogEx(DEBUG, "Contents (may be incomplete over 2k chars): %s", sprint_hex_inrow(response, resplen)); + saveFile("EF_DG2", ".BIN", response, resplen); + + // Select EF_SOD + if (secure_select_file(ks_enc, ks_mac, ssc, EF_SOD) == false) { + PrintAndLogEx(ERR, "Failed to secure select EF_SOD, crypto checksum check failed."); + DropField(); + return PM3_ESOFT; + } + + if (secure_read_file(ks_enc, ks_mac, ssc, response, &resplen) == false) { + PrintAndLogEx(ERR, "Failed to read EF_SOD."); + DropField(); + return PM3_ESOFT; + } + PrintAndLogEx(INFO, "Read EF_SOD, len: %i.", resplen); + PrintAndLogEx(DEBUG, "Contents (may be incomplete over 2k chars): %s", sprint_hex_inrow(response, resplen)); + saveFile("EF_SOD", ".BIN", response, resplen); + + // Select EF_DG11 + if (secure_select_file(ks_enc, ks_mac, ssc, EF_DG11) == false) { + PrintAndLogEx(ERR, "Failed to secure select EF_DG11, crypto checksum check failed."); + DropField(); + return PM3_ESOFT; + } + + if (secure_read_file(ks_enc, ks_mac, ssc, response, &resplen) == false) { + PrintAndLogEx(ERR, "Failed to read EF_DG11."); + DropField(); + return PM3_ESOFT; + } + PrintAndLogEx(INFO, "Read EF_DG11, len: %i.", resplen); + PrintAndLogEx(DEBUG, "Contents (may be incomplete over 2k chars): %s", sprint_hex_inrow(response, resplen)); + saveFile("EF_DG11", ".BIN", response, resplen); + + // Select EF_DG12 + if (secure_select_file(ks_enc, ks_mac, ssc, EF_DG12) == false) { + PrintAndLogEx(ERR, "Failed to secure select EF_DG12, crypto checksum check failed."); + DropField(); + return PM3_ESOFT; + } + + if (secure_read_file(ks_enc, ks_mac, ssc, response, &resplen) == false) { + PrintAndLogEx(ERR, "Failed to read EF_DG12."); + DropField(); + return PM3_ESOFT; + } + PrintAndLogEx(INFO, "Read EF_DG12, len: %i.", resplen); + PrintAndLogEx(DEBUG, "Contents (may be incomplete over 2k chars): %s", sprint_hex_inrow(response, resplen)); + saveFile("EF_DG12", ".BIN", response, resplen); + + // Select EF_DG14 + if (secure_select_file(ks_enc, ks_mac, ssc, EF_DG14) == false) { + PrintAndLogEx(ERR, "Failed to secure select EF_DG14, crypto checksum check failed."); + DropField(); + return PM3_ESOFT; + } + + if (secure_read_file(ks_enc, ks_mac, ssc, response, &resplen) == false) { + PrintAndLogEx(ERR, "Failed to read EF_DG14."); + DropField(); + return PM3_ESOFT; + } + PrintAndLogEx(INFO, "Read EF_DG14, len: %i.", resplen); + PrintAndLogEx(DEBUG, "Contents (may be incomplete over 2k chars): %s", sprint_hex_inrow(response, resplen)); + saveFile("EF_DG14", ".BIN", response, resplen); DropField(); return PM3_SUCCESS; From 21fc1d634f9cb75a86cb4afa855ef8ff5c116b12 Mon Sep 17 00:00:00 2001 From: Ave Date: Sun, 13 Dec 2020 01:49:17 +0300 Subject: [PATCH 044/682] emrtd: Add 14b support and better presence detection --- client/src/cmdhf14b.c | 2 +- client/src/cmdhf14b.h | 2 + client/src/cmdhfemrtd.c | 129 +++++++++++++++++++++++++--------------- 3 files changed, 85 insertions(+), 48 deletions(-) diff --git a/client/src/cmdhf14b.c b/client/src/cmdhf14b.c index 3f4890581..eb1a4f67a 100644 --- a/client/src/cmdhf14b.c +++ b/client/src/cmdhf14b.c @@ -1488,7 +1488,7 @@ static int handle_14b_apdu(bool chainingin, uint8_t *datain, int datainlen, bool return PM3_SUCCESS; } -static int exchange_14b_apdu(uint8_t *datain, int datainlen, bool activate_field, bool leave_signal_on, uint8_t *dataout, int maxdataoutlen, int *dataoutlen) { +int exchange_14b_apdu(uint8_t *datain, int datainlen, bool activate_field, bool leave_signal_on, uint8_t *dataout, int maxdataoutlen, int *dataoutlen) { *dataoutlen = 0; bool chaining = false; int res; diff --git a/client/src/cmdhf14b.h b/client/src/cmdhf14b.h index 2058ea8ba..d236bb6cf 100644 --- a/client/src/cmdhf14b.h +++ b/client/src/cmdhf14b.h @@ -15,6 +15,8 @@ int CmdHF14B(const char *Cmd); +int exchange_14b_apdu(uint8_t *datain, int datainlen, bool activate_field, bool leave_signal_on, uint8_t *dataout, int maxdataoutlen, int *dataoutlen); + int infoHF14B(bool verbose); int readHF14B(bool verbose); #endif diff --git a/client/src/cmdhfemrtd.c b/client/src/cmdhfemrtd.c index 65dc1c200..f8f89f557 100644 --- a/client/src/cmdhfemrtd.c +++ b/client/src/cmdhfemrtd.c @@ -24,6 +24,8 @@ #include "sha1.h" // KSeed calculation etc #include "mifare/desfire_crypto.h" // des_encrypt/des_decrypt #include "des.h" // mbedtls_des_key_set_parity +#include "cmdhf14b.h" // exchange_14b_apdu +#include "iso14b.h" // ISO14B_CONNECT etc #define TIMEOUT 2000 @@ -70,8 +72,7 @@ static uint16_t get_sw(uint8_t *d, uint8_t n) { return d[n] * 0x0100 + d[n + 1]; } -static bool exchange_commands(const char *cmd, uint8_t *dataout, int *dataoutlen, bool activate_field, bool keep_field_on) { - // TODO: Account for 14b too +static bool exchange_commands(const char *cmd, uint8_t *dataout, int *dataoutlen, bool activate_field, bool keep_field_on, bool use_14b) { uint8_t response[PM3_CMD_DATA_SIZE]; int resplen = 0; @@ -80,7 +81,12 @@ static bool exchange_commands(const char *cmd, uint8_t *dataout, int *dataoutlen uint8_t aCMD[500]; int aCMD_n = 0; param_gethex_to_eol(cmd, 0, aCMD, sizeof(aCMD), &aCMD_n); - int res = ExchangeAPDU14a(aCMD, aCMD_n, activate_field, keep_field_on, response, sizeof(response), &resplen); + int res; + if (use_14b) { + res = exchange_14b_apdu(aCMD, aCMD_n, activate_field, keep_field_on, response, sizeof(response), &resplen); + } else { + res = ExchangeAPDU14a(aCMD, aCMD_n, activate_field, keep_field_on, response, sizeof(response), &resplen); + } if (res) { DropField(); return false; @@ -103,11 +109,11 @@ static bool exchange_commands(const char *cmd, uint8_t *dataout, int *dataoutlen return true; } -static int exchange_commands_noout(const char *cmd, bool activate_field, bool keep_field_on) { +static int exchange_commands_noout(const char *cmd, bool activate_field, bool keep_field_on, bool use_14b) { uint8_t response[PM3_CMD_DATA_SIZE]; int resplen = 0; - return exchange_commands(cmd, response, &resplen, activate_field, keep_field_on); + return exchange_commands(cmd, response, &resplen, activate_field, keep_field_on, use_14b); } static char calculate_check_digit(char *data) { @@ -282,44 +288,44 @@ static void deskey(uint8_t *seed, uint8_t *type, int length, uint8_t *dataout) { memcpy(dataout, &key, length); } -static int select_file(const char *select_by, const char *file_id, bool activate_field, bool keep_field_on) { +static int select_file(const char *select_by, const char *file_id, bool use_14b) { size_t file_id_len = strlen(file_id) / 2; char cmd[50]; sprintf(cmd, "00%s%s0C%02lu%s", SELECT, select_by, file_id_len, file_id); - return exchange_commands_noout(cmd, activate_field, keep_field_on); + return exchange_commands_noout(cmd, false, true, use_14b); } -static int get_challenge(int length, uint8_t *dataout, int *dataoutlen) { +static int get_challenge(int length, uint8_t *dataout, int *dataoutlen, bool use_14b) { char cmd[50]; sprintf(cmd, "00%s0000%02X", GET_CHALLENGE, length); - return exchange_commands(cmd, dataout, dataoutlen, false, true); + return exchange_commands(cmd, dataout, dataoutlen, false, true, use_14b); } -static int external_authenticate(uint8_t *data, int length, uint8_t *dataout, int *dataoutlen) { +static int external_authenticate(uint8_t *data, int length, uint8_t *dataout, int *dataoutlen, bool use_14b) { char cmd[100]; sprintf(cmd, "00%s0000%02X%s%02X", EXTERNAL_AUTHENTICATE, length, sprint_hex_inrow(data, length), length); - return exchange_commands(cmd, dataout, dataoutlen, false, true); + return exchange_commands(cmd, dataout, dataoutlen, false, true, use_14b); } -static int _read_binary(int offset, int bytes_to_read, uint8_t *dataout, int *dataoutlen) { +static int _read_binary(int offset, int bytes_to_read, uint8_t *dataout, int *dataoutlen, bool use_14b) { char cmd[50]; sprintf(cmd, "00%s%04i%02i", READ_BINARY, offset, bytes_to_read); - return exchange_commands(cmd, dataout, dataoutlen, false, true); + return exchange_commands(cmd, dataout, dataoutlen, false, true, use_14b); } -static int read_file(uint8_t *dataout, int *dataoutlen) { +static int read_file(uint8_t *dataout, int *dataoutlen, bool use_14b) { uint8_t response[PM3_CMD_DATA_SIZE]; int resplen = 0; uint8_t tempresponse[PM3_CMD_DATA_SIZE]; int tempresplen = 0; - if (!_read_binary(0, 4, response, &resplen)) { + if (!_read_binary(0, 4, response, &resplen, use_14b)) { return false; } @@ -334,7 +340,7 @@ static int read_file(uint8_t *dataout, int *dataoutlen) { toread = 118; } - if (!_read_binary(offset, toread, tempresponse, &tempresplen)) { + if (!_read_binary(offset, toread, tempresponse, &tempresplen, use_14b)) { return false; } @@ -405,7 +411,7 @@ static void _convert_filename(const char *file, uint8_t *dataout) { dataout[1] = (int)strtol(temp, NULL, 16); } -static bool secure_select_file(uint8_t *kenc, uint8_t *kmac, uint8_t *ssc, const char *file) { +static bool secure_select_file(uint8_t *kenc, uint8_t *kmac, uint8_t *ssc, const char *file, bool use_14b) { uint8_t response[PM3_CMD_DATA_SIZE]; int resplen = 0; @@ -460,12 +466,12 @@ static bool secure_select_file(uint8_t *kenc, uint8_t *kmac, uint8_t *ssc, const sprintf(command, "0C%s020C%02X%s00", SELECT, lc, sprint_hex_inrow(data, lc)); PrintAndLogEx(DEBUG, "command: %s", command); - exchange_commands(command, response, &resplen, false, true); + exchange_commands(command, response, &resplen, false, true, use_14b); return check_cc(ssc, kmac, response, resplen); } -static bool _secure_read_binary(uint8_t *kmac, uint8_t *ssc, int offset, int bytes_to_read, uint8_t *dataout, int *dataoutlen) { +static bool _secure_read_binary(uint8_t *kmac, uint8_t *ssc, int offset, int bytes_to_read, uint8_t *dataout, int *dataoutlen, bool use_14b) { char command[54]; uint8_t cmd[8]; uint8_t data[21]; @@ -518,18 +524,18 @@ static bool _secure_read_binary(uint8_t *kmac, uint8_t *ssc, int offset, int byt sprintf(command, "0C%s%02X%02X%02X%s00", READ_BINARY, p1, p2, lc, sprint_hex_inrow(data, lc)); PrintAndLogEx(DEBUG, "command: %s", command); - exchange_commands(command, dataout, dataoutlen, false, true); + exchange_commands(command, dataout, dataoutlen, false, true, use_14b); return check_cc(ssc, kmac, dataout, *dataoutlen); } -static bool _secure_read_binary_decrypt(uint8_t *kenc, uint8_t *kmac, uint8_t *ssc, int offset, int bytes_to_read, uint8_t *dataout, int *dataoutlen) { +static bool _secure_read_binary_decrypt(uint8_t *kenc, uint8_t *kmac, uint8_t *ssc, int offset, int bytes_to_read, uint8_t *dataout, int *dataoutlen, bool use_14b) { uint8_t response[500]; uint8_t temp[500]; int resplen, cutat = 0; uint8_t iv[8] = { 0x00 }; - if (_secure_read_binary(kmac, ssc, offset, bytes_to_read, response, &resplen) == false) { + if (_secure_read_binary(kmac, ssc, offset, bytes_to_read, response, &resplen, use_14b) == false) { return false; } @@ -545,14 +551,14 @@ static bool _secure_read_binary_decrypt(uint8_t *kenc, uint8_t *kmac, uint8_t *s return true; } -static int secure_read_file(uint8_t *kenc, uint8_t *kmac, uint8_t *ssc, uint8_t *dataout, int *dataoutlen) { +static int secure_read_file(uint8_t *kenc, uint8_t *kmac, uint8_t *ssc, uint8_t *dataout, int *dataoutlen, bool use_14b) { // TODO: join this with regular read file uint8_t response[25000]; int resplen = 0; uint8_t tempresponse[500]; int tempresplen = 0; - if (!_secure_read_binary_decrypt(kenc, kmac, ssc, 0, 4, response, &resplen)) { + if (!_secure_read_binary_decrypt(kenc, kmac, ssc, 0, 4, response, &resplen, use_14b)) { return false; } @@ -567,7 +573,7 @@ static int secure_read_file(uint8_t *kenc, uint8_t *kmac, uint8_t *ssc, uint8_t toread = 118; } - if (!_secure_read_binary_decrypt(kenc, kmac, ssc, offset, toread, tempresponse, &tempresplen)) { + if (!_secure_read_binary_decrypt(kenc, kmac, ssc, offset, toread, tempresponse, &tempresplen, use_14b)) { return false; } @@ -597,9 +603,38 @@ int dumpHF_EMRTD(char *documentnumber, char *dob, char *expiry) { uint8_t KENC_type[4] = {0x00, 0x00, 0x00, 0x01}; uint8_t KMAC_type[4] = {0x00, 0x00, 0x00, 0x02}; + bool use_14b = false; + + // Try to 14a + SendCommandMIX(CMD_HF_ISO14443A_READER, ISO14A_CONNECT | ISO14A_NO_DISCONNECT, 0, 0, NULL, 0); + PacketResponseNG resp; + bool failed_14a = false; + if (!WaitForResponseTimeout(CMD_ACK, &resp, 2500)) { + DropField(); + failed_14a = true; + } + + if (failed_14a || resp.oldarg[0] == 0) { + PrintAndLogEx(INFO, "No eMRTD spotted with 14a, trying 14b."); + // If not 14a, try to 14b + SendCommandMIX(CMD_HF_ISO14443B_COMMAND, ISO14B_CONNECT | ISO14B_SELECT_STD, 0, 0, NULL, 0); + if (!WaitForResponseTimeout(CMD_HF_ISO14443B_COMMAND, &resp, 2500)) { + DropField(); + PrintAndLogEx(INFO, "No eMRTD spotted with 14b, exiting."); + return PM3_ESOFT; + } + + if (resp.oldarg[0] != 0) { + DropField(); + PrintAndLogEx(INFO, "No eMRTD spotted with 14b, exiting."); + return PM3_ESOFT; + } + use_14b = true; + } + // Select and read EF_CardAccess - if (select_file(P1_SELECT_BY_EF, EF_CARDACCESS, true, true)) { - read_file(response, &resplen); + if (select_file(P1_SELECT_BY_EF, EF_CARDACCESS, use_14b)) { + read_file(response, &resplen, use_14b); PrintAndLogEx(INFO, "Read EF_CardAccess, len: %i.", resplen); PrintAndLogEx(DEBUG, "Contents (may be incomplete over 2k chars): %s", sprint_hex_inrow(response, resplen)); } else { @@ -607,22 +642,22 @@ int dumpHF_EMRTD(char *documentnumber, char *dob, char *expiry) { } // Select MRTD applet - if (select_file(P1_SELECT_BY_NAME, AID_MRTD, false, true) == false) { + if (select_file(P1_SELECT_BY_NAME, AID_MRTD, use_14b) == false) { PrintAndLogEx(ERR, "Couldn't select the MRTD application."); DropField(); return PM3_ESOFT; } // Select EF_COM - if (select_file(P1_SELECT_BY_EF, EF_COM, false, true) == false) { + if (select_file(P1_SELECT_BY_EF, EF_COM, use_14b) == false) { // BAC = true; PrintAndLogEx(INFO, "Basic Access Control is enforced. Will attempt external authentication."); } else { // BAC = false; // Select EF_DG1 - select_file(P1_SELECT_BY_EF, EF_DG1, false, true); + select_file(P1_SELECT_BY_EF, EF_DG1, use_14b); - if (read_file(response, &resplen) == false) { + if (read_file(response, &resplen, use_14b) == false) { // BAC = true; PrintAndLogEx(INFO, "Basic Access Control is enforced. Will attempt external authentication."); } else { @@ -652,7 +687,7 @@ int dumpHF_EMRTD(char *documentnumber, char *dob, char *expiry) { PrintAndLogEx(DEBUG, "kmac: %s", sprint_hex_inrow(kmac, 16)); // Get Challenge - if (get_challenge(8, rnd_ic, &resplen) == false) { + if (get_challenge(8, rnd_ic, &resplen, use_14b) == false) { PrintAndLogEx(ERR, "Couldn't get challenge."); DropField(); return PM3_ESOFT; @@ -681,7 +716,7 @@ int dumpHF_EMRTD(char *documentnumber, char *dob, char *expiry) { memcpy(cmd_data + 32, m_ifd, 8); // Do external authentication - if (external_authenticate(cmd_data, sizeof(cmd_data), response, &resplen) == false) { + if (external_authenticate(cmd_data, sizeof(cmd_data), response, &resplen, use_14b) == false) { PrintAndLogEx(ERR, "Couldn't do external authentication. Did you supply the correct MRZ info?"); DropField(); return PM3_ESOFT; @@ -723,13 +758,13 @@ int dumpHF_EMRTD(char *documentnumber, char *dob, char *expiry) { PrintAndLogEx(DEBUG, "ssc: %s", sprint_hex_inrow(ssc, 8)); // Select EF_COM - if (secure_select_file(ks_enc, ks_mac, ssc, EF_COM) == false) { + if (secure_select_file(ks_enc, ks_mac, ssc, EF_COM, use_14b) == false) { PrintAndLogEx(ERR, "Failed to secure select EF_COM, crypto checksum check failed."); DropField(); return PM3_ESOFT; } - if (secure_read_file(ks_enc, ks_mac, ssc, response, &resplen) == false) { + if (secure_read_file(ks_enc, ks_mac, ssc, response, &resplen, use_14b) == false) { PrintAndLogEx(ERR, "Failed to read EF_COM."); DropField(); return PM3_ESOFT; @@ -740,13 +775,13 @@ int dumpHF_EMRTD(char *documentnumber, char *dob, char *expiry) { // TODO: Don't read a hardcoded list of files, reduce code repetition // Select EF_DG1 - if (secure_select_file(ks_enc, ks_mac, ssc, EF_DG1) == false) { + if (secure_select_file(ks_enc, ks_mac, ssc, EF_DG1, use_14b) == false) { PrintAndLogEx(ERR, "Failed to secure select EF_DG1, crypto checksum check failed."); DropField(); return PM3_ESOFT; } - if (secure_read_file(ks_enc, ks_mac, ssc, response, &resplen) == false) { + if (secure_read_file(ks_enc, ks_mac, ssc, response, &resplen, use_14b) == false) { PrintAndLogEx(ERR, "Failed to read EF_DG1."); DropField(); return PM3_ESOFT; @@ -756,13 +791,13 @@ int dumpHF_EMRTD(char *documentnumber, char *dob, char *expiry) { saveFile("EF_DG1", ".BIN", response, resplen); // Select EF_DG2 - if (secure_select_file(ks_enc, ks_mac, ssc, EF_DG2) == false) { + if (secure_select_file(ks_enc, ks_mac, ssc, EF_DG2, use_14b) == false) { PrintAndLogEx(ERR, "Failed to secure select EF_DG2, crypto checksum check failed."); DropField(); return PM3_ESOFT; } - if (secure_read_file(ks_enc, ks_mac, ssc, response, &resplen) == false) { + if (secure_read_file(ks_enc, ks_mac, ssc, response, &resplen, use_14b) == false) { PrintAndLogEx(ERR, "Failed to read EF_DG2."); DropField(); return PM3_ESOFT; @@ -772,13 +807,13 @@ int dumpHF_EMRTD(char *documentnumber, char *dob, char *expiry) { saveFile("EF_DG2", ".BIN", response, resplen); // Select EF_SOD - if (secure_select_file(ks_enc, ks_mac, ssc, EF_SOD) == false) { + if (secure_select_file(ks_enc, ks_mac, ssc, EF_SOD, use_14b) == false) { PrintAndLogEx(ERR, "Failed to secure select EF_SOD, crypto checksum check failed."); DropField(); return PM3_ESOFT; } - if (secure_read_file(ks_enc, ks_mac, ssc, response, &resplen) == false) { + if (secure_read_file(ks_enc, ks_mac, ssc, response, &resplen, use_14b) == false) { PrintAndLogEx(ERR, "Failed to read EF_SOD."); DropField(); return PM3_ESOFT; @@ -788,13 +823,13 @@ int dumpHF_EMRTD(char *documentnumber, char *dob, char *expiry) { saveFile("EF_SOD", ".BIN", response, resplen); // Select EF_DG11 - if (secure_select_file(ks_enc, ks_mac, ssc, EF_DG11) == false) { + if (secure_select_file(ks_enc, ks_mac, ssc, EF_DG11, use_14b) == false) { PrintAndLogEx(ERR, "Failed to secure select EF_DG11, crypto checksum check failed."); DropField(); return PM3_ESOFT; } - if (secure_read_file(ks_enc, ks_mac, ssc, response, &resplen) == false) { + if (secure_read_file(ks_enc, ks_mac, ssc, response, &resplen, use_14b) == false) { PrintAndLogEx(ERR, "Failed to read EF_DG11."); DropField(); return PM3_ESOFT; @@ -804,13 +839,13 @@ int dumpHF_EMRTD(char *documentnumber, char *dob, char *expiry) { saveFile("EF_DG11", ".BIN", response, resplen); // Select EF_DG12 - if (secure_select_file(ks_enc, ks_mac, ssc, EF_DG12) == false) { + if (secure_select_file(ks_enc, ks_mac, ssc, EF_DG12, use_14b) == false) { PrintAndLogEx(ERR, "Failed to secure select EF_DG12, crypto checksum check failed."); DropField(); return PM3_ESOFT; } - if (secure_read_file(ks_enc, ks_mac, ssc, response, &resplen) == false) { + if (secure_read_file(ks_enc, ks_mac, ssc, response, &resplen, use_14b) == false) { PrintAndLogEx(ERR, "Failed to read EF_DG12."); DropField(); return PM3_ESOFT; @@ -820,13 +855,13 @@ int dumpHF_EMRTD(char *documentnumber, char *dob, char *expiry) { saveFile("EF_DG12", ".BIN", response, resplen); // Select EF_DG14 - if (secure_select_file(ks_enc, ks_mac, ssc, EF_DG14) == false) { + if (secure_select_file(ks_enc, ks_mac, ssc, EF_DG14, use_14b) == false) { PrintAndLogEx(ERR, "Failed to secure select EF_DG14, crypto checksum check failed."); DropField(); return PM3_ESOFT; } - if (secure_read_file(ks_enc, ks_mac, ssc, response, &resplen) == false) { + if (secure_read_file(ks_enc, ks_mac, ssc, response, &resplen, use_14b) == false) { PrintAndLogEx(ERR, "Failed to read EF_DG14."); DropField(); return PM3_ESOFT; From cd625ca7593c64f1420088e56c814a4bdd18d307 Mon Sep 17 00:00:00 2001 From: ikarus Date: Sat, 12 Dec 2020 23:59:09 +0100 Subject: [PATCH 045/682] Reworked hf 14a apdufuzz (now apdufind). * Renamed to apdufind. Fuzzing is something different than this simple enumeration. * Removed Le as parameter. This is just the maximum response bytes expected. Not much to find here with this simple tool. * Sweep through all values, even if a start value was given (don't stop at 0). * Changed sweep oder to INS->P1->P2->CLA. This way instructions are more quickly found. * Show response data, if there are any (hex & ascii). * Retry command with Le = 0x0100 (extended length APDU) if there was a length error return code. * Improved the output with general information. * Fixed bug: It's now possible to run the command without parameters. --- client/src/cmdhf14a.c | 172 +++++++++++++++++++++++------------------- 1 file changed, 96 insertions(+), 76 deletions(-) diff --git a/client/src/cmdhf14a.c b/client/src/cmdhf14a.c index 576979aad..075c0e4f5 100644 --- a/client/src/cmdhf14a.c +++ b/client/src/cmdhf14a.c @@ -2127,128 +2127,148 @@ static uint16_t get_sw(uint8_t *d, uint8_t n) { n -= 2; return d[n] * 0x0100 + d[n + 1]; } -static int CmdHf14AFuzzapdu(const char *Cmd) { + +static int CmdHf14AFindapdu(const char *Cmd) { CLIParserContext *ctx; - CLIParserInit(&ctx, "hf 14a apdufuzz", - "Fuzz APDU's of ISO7816 protocol to find valid CLS/INS/P1P2/LE commands.\n" + CLIParserInit(&ctx, "hf 14a apdufind", + "Enumerate APDU's of ISO7816 protocol to find valid CLS/INS/P1P2 commands.\n" "It loops all 256 possible values for each byte.\n" + "The loop oder is INS->P1->P2->CLA\n" "Tag must be on antenna before running.", - "hf 14a apdufuzz\n" - "hf 14a apdufuzz --cla 80\n" + "hf 14a apdufind\n" + "hf 14a apdufind --cla 80\n" ); void *argtable[] = { arg_param_begin, - arg_str0(NULL, "cla", "", "start CLASS value (1 hex byte)"), - arg_str0(NULL, "ins", "", "start INSTRUCTION value (1 hex byte)"), + arg_str0("c", "cla", "", "start CLASS value (1 hex byte)"), + arg_str0("i", "ins", "", "start INSTRUCTION value (1 hex byte)"), arg_str0(NULL, "p1", "", "start P1 value (1 hex byte)"), arg_str0(NULL, "p2", "", "start P2 value (1 hex byte)"), - arg_str0(NULL, "le", "", "start LENGTH value (1 hex byte)"), arg_lit0("v", "verbose", "verbose output"), arg_param_end }; - CLIExecWithReturn(ctx, Cmd, argtable, false); + CLIExecWithReturn(ctx, Cmd, argtable, true); int cla_len = 0; - uint8_t cla[1] = {0}; - CLIGetHexWithReturn(ctx, 1, cla, &cla_len); - + uint8_t cla_arg[1] = {0}; + CLIGetHexWithReturn(ctx, 1, cla_arg, &cla_len); + int ins_len = 0; - uint8_t ins[1] = {0}; - CLIGetHexWithReturn(ctx, 2, ins, &ins_len); + uint8_t ins_arg[1] = {0}; + CLIGetHexWithReturn(ctx, 2, ins_arg, &ins_len); int p1_len = 0; - uint8_t p1[1] = {0}; - CLIGetHexWithReturn(ctx, 3, p1, &p1_len); + uint8_t p1_arg[1] = {0}; + CLIGetHexWithReturn(ctx, 3, p1_arg, &p1_len); int p2_len = 0; - uint8_t p2[1] = {0}; - CLIGetHexWithReturn(ctx, 4, p2, &p2_len); + uint8_t p2_arg[1] = {0}; + CLIGetHexWithReturn(ctx, 4, p2_arg, &p2_len); - int le_len = 0; - uint8_t le[1] = {0}; - CLIGetHexWithReturn(ctx, 5, le, &le_len); - - bool verbose = arg_get_lit(ctx, 6); + bool verbose = arg_get_lit(ctx, 5); CLIParserFree(ctx); bool activate_field = true; bool keep_field_on = true; - - uint8_t a = cla[0]; - uint8_t b = ins[0]; - uint8_t c = p1[0]; - uint8_t d = p2[0]; - uint8_t e = le[0]; - - PrintAndLogEx(SUCCESS, "Starting the apdu fuzzer [ CLA " _GREEN_("%02X") " INS " _GREEN_("%02X") " P1 " _GREEN_("%02X") " P2 " _GREEN_("%02X") " LE " _GREEN_("%02x")" ]", a,b,c,d,e); - PrintAndLogEx(INFO, "Press " _GREEN_("") " to exit"); - + uint8_t cla = cla_arg[0]; + uint8_t ins = ins_arg[0]; + uint8_t p1 = p1_arg[0]; + uint8_t p2 = p2_arg[0]; uint8_t response[PM3_CMD_DATA_SIZE]; - int resplen = 0; - + int response_n = 0; uint8_t aSELECT_AID[80]; int aSELECT_AID_n = 0; + + // Check if the tag reponde to APDUs. + PrintAndLogEx(INFO, "Sending a test APDU (select file command) to check if the tag is responding to APDU"); param_gethex_to_eol("00a404000aa000000440000101000100", 0, aSELECT_AID, sizeof(aSELECT_AID), &aSELECT_AID_n); - int res = ExchangeAPDU14a(aSELECT_AID, aSELECT_AID_n, activate_field, keep_field_on, response, sizeof(response), &resplen); + int res = ExchangeAPDU14a(aSELECT_AID, aSELECT_AID_n, activate_field, keep_field_on, response, sizeof(response), &response_n); if (res) { DropField(); + PrintAndLogEx(FAILED, "Tag did not responde to a test APDU (select file command). Aborting"); return res; } + PrintAndLogEx(SUCCESS, "Got response. Starting the APDU finder [ CLA " _GREEN_("%02X") " INS " _GREEN_("%02X") " P1 " _GREEN_("%02X") " P2 " _GREEN_("%02X") " ]", cla,ins,p1,p2); + PrintAndLogEx(INFO, "Press " _GREEN_("") " to exit"); - if (activate_field) - activate_field = false; - + activate_field = false; uint64_t t1 = msclock(); + + // Enumerate APDUs. do { do { do { do { - do { - if (kbd_enter_pressed()) { - goto out; - } + // Exit (was the Enter key pressed)? + if (kbd_enter_pressed()) { + PrintAndLogEx(INFO, "User interrupted detected. Aborting"); + goto out; + } - uint8_t foo[5] = {a, b, c, d, e}; - int foo_n = sizeof(foo); + if (verbose) { + PrintAndLogEx(INFO, "Status: [ CLA " _GREEN_("%02X") " INS " _GREEN_("%02X") " P1 " _GREEN_("%02X") " P2 " _GREEN_("%02X") " ]", cla,ins,p1,p2); + } - if (verbose) { - PrintAndLogEx(INFO, "%s", sprint_hex(foo, sizeof(foo))); - } - res = ExchangeAPDU14a(foo, foo_n, activate_field, keep_field_on, response, sizeof(response), &resplen); + // Send APDU. + uint8_t command[4] = {cla, ins, p1, p2}; + int command_n = sizeof(command); + res = ExchangeAPDU14a(command, command_n, activate_field, keep_field_on, response, sizeof(response), &response_n); + if (res) { + continue; + } + + // Was there and length error? If so, try with Le length (case 2 instad of case 1, + // https://stackoverflow.com/a/30679558). Le = 0x00 will get interpreted as extended length APDU + // with Le being 0x0100. + uint16_t sw = get_sw(response, response_n); + bool command_with_le = false; + if (sw == 0x6700) { + PrintAndLogEx(INFO, "Got response for APDU: %02X%02X%02X%02X (%04x - %s)", cla,ins,p1,p2, + sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff)); + PrintAndLogEx(INFO, "Resending current command with Le = 0x0100 (extended length APDU)"); + uint8_t command2[7] = {cla, ins, p1, p2, 0x00}; + int command2_n = sizeof(command2); + res = ExchangeAPDU14a(command2, command2_n, activate_field, keep_field_on, response, sizeof(response), &response_n); if (res) { - e++; - continue; + continue; } + command_with_le = true; + } - uint16_t sw = get_sw(response, resplen); - if (sw != 0x6a86 && - sw != 0x6986 && - sw != 0x6d00 - ) { - PrintAndLogEx(INFO, "%02X %02X %02X %02X %02X (%04x - %s)", a,b,c,d,e, sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff)); + // Check response. + // TODO: What response values should be considerd "valid" or "instersting"? + sw = get_sw(response, response_n); + if (sw != 0x6a86 && + sw != 0x6986 && + sw != 0x6d00 + ) { + if (command_with_le) { + PrintAndLogEx(INFO, "Got response for APDU: %02X%02X%02X%02X00 (%04x - %s)", cla,ins,p1,p2, + sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff)); + } else { + PrintAndLogEx(INFO, "Got response for APDU: %02X%02X%02X%02X (%04x - %s)", cla,ins,p1,p2, + sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff)); } - e++; - if (verbose) { - PrintAndLogEx(INFO, "Status: %02X %02X %02X %02X %02X", a,b,c,d,e); + // Show response data. + if (response_n > 2) { + PrintAndLogEx(INFO, "Response data is: %s | %s", sprint_hex_inrow(response, response_n-2), + sprint_ascii(response, response_n-2)); } - - } while (e); - d++; - PrintAndLogEx(INFO, "Status: %02X %02X %02X %02X %02X", a,b,c,d,e); - } while (d); - c++; - PrintAndLogEx(INFO, "Status: %02X %02X %02X %02X %02X", a,b,c,d,e); - } while (c); - b++; - PrintAndLogEx(INFO, "Status: %02X %02X %02X %02X %02X", a,b,c,d,e); - } while (b); - a++; - PrintAndLogEx(INFO, "Status: %02X %02X %02X %02X %02X", a,b,c,d,e); - } while(a); + } + } while (++ins != ins_arg[0]); + p1++; + PrintAndLogEx(INFO, "Status: [ CLA " _GREEN_("%02X") " INS " _GREEN_("%02X") " P1 " _GREEN_("%02X") " P2 " _GREEN_("%02X") " ]", cla,ins,p1,p2); + } while (p1 != p1_arg[0]); + p2++; + PrintAndLogEx(INFO, "Status: [ CLA " _GREEN_("%02X") " INS " _GREEN_("%02X") " P1 " _GREEN_("%02X") " P2 " _GREEN_("%02X") " ]", cla,ins,p1,p2); + } while (p2 != p2_arg[0]); + cla++; + PrintAndLogEx(INFO, "Status: [ CLA " _GREEN_("%02X") " INS " _GREEN_("%02X") " P1 " _GREEN_("%02X") " P2 " _GREEN_("%02X") " ]", cla,ins,p1,p2); + } while (cla != cla_arg[0]); out: - PrintAndLogEx(SUCCESS, "time: %" PRIu64 " seconds\n", (msclock() - t1) / 1000); + PrintAndLogEx(SUCCESS, "Runtime: %" PRIu64 " seconds\n", (msclock() - t1) / 1000); DropField(); return PM3_SUCCESS; } @@ -2266,7 +2286,7 @@ static command_t CommandTable[] = { {"raw", CmdHF14ACmdRaw, IfPm3Iso14443a, "Send raw hex data to tag"}, {"antifuzz", CmdHF14AAntiFuzz, IfPm3Iso14443a, "Fuzzing the anticollision phase. Warning! Readers may react strange"}, {"config", CmdHf14AConfig, IfPm3Iso14443a, "Configure 14a settings (use with caution)"}, - {"apdufuzz", CmdHf14AFuzzapdu, IfPm3Iso14443a, "Fuzz APDU - CLA/INS/P1P2"}, + {"apdufind", CmdHf14AFindapdu, IfPm3Iso14443a, "Enuerate APDUs - CLA/INS/P1P2"}, {NULL, NULL, NULL, NULL} }; From baa86de247aa2f771ac6af16c038236725fd03a4 Mon Sep 17 00:00:00 2001 From: ikarus Date: Sun, 13 Dec 2020 00:16:56 +0100 Subject: [PATCH 046/682] Fixed merge conflict (make style). --- client/src/cmdhf14a.c | 34 +++++++++++++++++----------------- doc/commands.md | 2 +- 2 files changed, 18 insertions(+), 18 deletions(-) diff --git a/client/src/cmdhf14a.c b/client/src/cmdhf14a.c index 075c0e4f5..e984019b8 100644 --- a/client/src/cmdhf14a.c +++ b/client/src/cmdhf14a.c @@ -2137,7 +2137,7 @@ static int CmdHf14AFindapdu(const char *Cmd) { "Tag must be on antenna before running.", "hf 14a apdufind\n" "hf 14a apdufind --cla 80\n" - ); + ); void *argtable[] = { arg_param_begin, @@ -2189,7 +2189,7 @@ static int CmdHf14AFindapdu(const char *Cmd) { PrintAndLogEx(FAILED, "Tag did not responde to a test APDU (select file command). Aborting"); return res; } - PrintAndLogEx(SUCCESS, "Got response. Starting the APDU finder [ CLA " _GREEN_("%02X") " INS " _GREEN_("%02X") " P1 " _GREEN_("%02X") " P2 " _GREEN_("%02X") " ]", cla,ins,p1,p2); + PrintAndLogEx(SUCCESS, "Got response. Starting the APDU finder [ CLA " _GREEN_("%02X") " INS " _GREEN_("%02X") " P1 " _GREEN_("%02X") " P2 " _GREEN_("%02X") " ]", cla, ins, p1, p2); PrintAndLogEx(INFO, "Press " _GREEN_("") " to exit"); activate_field = false; @@ -2207,7 +2207,7 @@ static int CmdHf14AFindapdu(const char *Cmd) { } if (verbose) { - PrintAndLogEx(INFO, "Status: [ CLA " _GREEN_("%02X") " INS " _GREEN_("%02X") " P1 " _GREEN_("%02X") " P2 " _GREEN_("%02X") " ]", cla,ins,p1,p2); + PrintAndLogEx(INFO, "Status: [ CLA " _GREEN_("%02X") " INS " _GREEN_("%02X") " P1 " _GREEN_("%02X") " P2 " _GREEN_("%02X") " ]", cla, ins, p1, p2); } // Send APDU. @@ -2224,8 +2224,8 @@ static int CmdHf14AFindapdu(const char *Cmd) { uint16_t sw = get_sw(response, response_n); bool command_with_le = false; if (sw == 0x6700) { - PrintAndLogEx(INFO, "Got response for APDU: %02X%02X%02X%02X (%04x - %s)", cla,ins,p1,p2, - sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff)); + PrintAndLogEx(INFO, "Got response for APDU: %02X%02X%02X%02X (%04x - %s)", cla, ins, p1, p2, + sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff)); PrintAndLogEx(INFO, "Resending current command with Le = 0x0100 (extended length APDU)"); uint8_t command2[7] = {cla, ins, p1, p2, 0x00}; int command2_n = sizeof(command2); @@ -2240,31 +2240,31 @@ static int CmdHf14AFindapdu(const char *Cmd) { // TODO: What response values should be considerd "valid" or "instersting"? sw = get_sw(response, response_n); if (sw != 0x6a86 && - sw != 0x6986 && - sw != 0x6d00 - ) { + sw != 0x6986 && + sw != 0x6d00 + ) { if (command_with_le) { - PrintAndLogEx(INFO, "Got response for APDU: %02X%02X%02X%02X00 (%04x - %s)", cla,ins,p1,p2, - sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff)); + PrintAndLogEx(INFO, "Got response for APDU: %02X%02X%02X%02X00 (%04x - %s)", cla, ins, p1, p2, + sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff)); } else { - PrintAndLogEx(INFO, "Got response for APDU: %02X%02X%02X%02X (%04x - %s)", cla,ins,p1,p2, - sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff)); + PrintAndLogEx(INFO, "Got response for APDU: %02X%02X%02X%02X (%04x - %s)", cla, ins, p1, p2, + sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff)); } // Show response data. if (response_n > 2) { - PrintAndLogEx(INFO, "Response data is: %s | %s", sprint_hex_inrow(response, response_n-2), - sprint_ascii(response, response_n-2)); + PrintAndLogEx(INFO, "Response data is: %s | %s", sprint_hex_inrow(response, response_n - 2), + sprint_ascii(response, response_n - 2)); } } } while (++ins != ins_arg[0]); p1++; - PrintAndLogEx(INFO, "Status: [ CLA " _GREEN_("%02X") " INS " _GREEN_("%02X") " P1 " _GREEN_("%02X") " P2 " _GREEN_("%02X") " ]", cla,ins,p1,p2); + PrintAndLogEx(INFO, "Status: [ CLA " _GREEN_("%02X") " INS " _GREEN_("%02X") " P1 " _GREEN_("%02X") " P2 " _GREEN_("%02X") " ]", cla, ins, p1, p2); } while (p1 != p1_arg[0]); p2++; - PrintAndLogEx(INFO, "Status: [ CLA " _GREEN_("%02X") " INS " _GREEN_("%02X") " P1 " _GREEN_("%02X") " P2 " _GREEN_("%02X") " ]", cla,ins,p1,p2); + PrintAndLogEx(INFO, "Status: [ CLA " _GREEN_("%02X") " INS " _GREEN_("%02X") " P1 " _GREEN_("%02X") " P2 " _GREEN_("%02X") " ]", cla, ins, p1, p2); } while (p2 != p2_arg[0]); cla++; - PrintAndLogEx(INFO, "Status: [ CLA " _GREEN_("%02X") " INS " _GREEN_("%02X") " P1 " _GREEN_("%02X") " P2 " _GREEN_("%02X") " ]", cla,ins,p1,p2); + PrintAndLogEx(INFO, "Status: [ CLA " _GREEN_("%02X") " INS " _GREEN_("%02X") " P1 " _GREEN_("%02X") " P2 " _GREEN_("%02X") " ]", cla, ins, p1, p2); } while (cla != cla_arg[0]); out: diff --git a/doc/commands.md b/doc/commands.md index 58578c26e..7bc9342c5 100644 --- a/doc/commands.md +++ b/doc/commands.md @@ -142,7 +142,7 @@ Check column "offline" for their availability. |`hf 14a raw `|N |`Send raw hex data to tag` |`hf 14a antifuzz `|N |`Fuzzing the anticollision phase. Warning! Readers may react strange` |`hf 14a config `|N |`Configure 14a settings (use with caution)` -|`hf 14a apdufuzz `|N |`Fuzz APDU - CLA/INS/P1P2` +|`hf 14a apdufind `|N |`Enuerate APDUs - CLA/INS/P1P2` ### hf 14b From a9713bbe6162474f0ff87a433abc7c9b944cd0a6 Mon Sep 17 00:00:00 2001 From: iceman1001 Date: Sun, 13 Dec 2020 01:17:41 +0100 Subject: [PATCH 047/682] fix #1094 - add Le --- client/src/emv/emvcore.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/src/emv/emvcore.c b/client/src/emv/emvcore.c index 7982ff711..f9cbe4f82 100644 --- a/client/src/emv/emvcore.c +++ b/client/src/emv/emvcore.c @@ -617,7 +617,7 @@ int EMVSelectApplication(struct tlvdb *tlv, uint8_t *AID, size_t *AIDlen) { } int EMVGPO(EMVCommandChannel channel, bool LeaveFieldON, uint8_t *PDOL, size_t PDOLLen, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw, struct tlvdb *tlv) { - return EMVExchange(channel, LeaveFieldON, (sAPDU) {0x80, 0xa8, 0x00, 0x00, PDOLLen, PDOL}, Result, MaxResultLen, ResultLen, sw, tlv); + return EMVExchangeEx(channel, false, LeaveFieldON, (sAPDU) {0x80, 0xa8, 0x00, 0x00, PDOLLen, PDOL}, true, Result, MaxResultLen, ResultLen, sw, tlv); } int EMVReadRecord(EMVCommandChannel channel, bool LeaveFieldON, uint8_t SFI, uint8_t SFIrec, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw, struct tlvdb *tlv) { From 81981a73fee587d3af1ecfc6883efa442ff19838 Mon Sep 17 00:00:00 2001 From: ikarus Date: Sun, 13 Dec 2020 01:25:55 +0100 Subject: [PATCH 048/682] APDU finder: increment P1/P2 alternating & add Changelog entry. --- CHANGELOG.md | 1 + client/src/cmdhf14a.c | 111 ++++++++++++++++++++++-------------------- 2 files changed, 58 insertions(+), 54 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e168a0db4..f613c4c70 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -116,6 +116,7 @@ This project uses the changelog in accordance with [keepchangelog](http://keepac - Change, use system Whereami library if available (@doegox) - Change, use system Zlib library if available (@doegox) - Fix release version information (@doegox) + - Add `hf 14a apdufind` to find hidden APDUs (@iceman1001 & @ikarus23) ## [ice coffee.4.9237][2020-05-21] - Updated documentation (@doegox, @iceman1001) diff --git a/client/src/cmdhf14a.c b/client/src/cmdhf14a.c index e984019b8..0f020b54a 100644 --- a/client/src/cmdhf14a.c +++ b/client/src/cmdhf14a.c @@ -2133,7 +2133,7 @@ static int CmdHf14AFindapdu(const char *Cmd) { CLIParserInit(&ctx, "hf 14a apdufind", "Enumerate APDU's of ISO7816 protocol to find valid CLS/INS/P1P2 commands.\n" "It loops all 256 possible values for each byte.\n" - "The loop oder is INS->P1->P2->CLA\n" + "The loop oder is INS -> P1/P2 (alternating) -> CLA\n" "Tag must be on antenna before running.", "hf 14a apdufind\n" "hf 14a apdufind --cla 80\n" @@ -2193,76 +2193,79 @@ static int CmdHf14AFindapdu(const char *Cmd) { PrintAndLogEx(INFO, "Press " _GREEN_("") " to exit"); activate_field = false; + bool inc_p1 = true; uint64_t t1 = msclock(); // Enumerate APDUs. do { do { do { - do { - // Exit (was the Enter key pressed)? - if (kbd_enter_pressed()) { - PrintAndLogEx(INFO, "User interrupted detected. Aborting"); - goto out; - } + // Exit (was the Enter key pressed)? + if (kbd_enter_pressed()) { + PrintAndLogEx(INFO, "User interrupted detected. Aborting"); + goto out; + } - if (verbose) { - PrintAndLogEx(INFO, "Status: [ CLA " _GREEN_("%02X") " INS " _GREEN_("%02X") " P1 " _GREEN_("%02X") " P2 " _GREEN_("%02X") " ]", cla, ins, p1, p2); - } + if (verbose) { + PrintAndLogEx(INFO, "Status: [ CLA " _GREEN_("%02X") " INS " _GREEN_("%02X") " P1 " _GREEN_("%02X") " P2 " _GREEN_("%02X") " ]", cla, ins, p1, p2); + } - // Send APDU. - uint8_t command[4] = {cla, ins, p1, p2}; - int command_n = sizeof(command); - res = ExchangeAPDU14a(command, command_n, activate_field, keep_field_on, response, sizeof(response), &response_n); + // Send APDU. + uint8_t command[4] = {cla, ins, p1, p2}; + int command_n = sizeof(command); + res = ExchangeAPDU14a(command, command_n, activate_field, keep_field_on, response, sizeof(response), &response_n); + if (res) { + continue; + } + + // Was there and length error? If so, try with Le length (case 2 instad of case 1, + // https://stackoverflow.com/a/30679558). Le = 0x00 will get interpreted as extended length APDU + // with Le being 0x0100. + uint16_t sw = get_sw(response, response_n); + bool command_with_le = false; + if (sw == 0x6700) { + PrintAndLogEx(INFO, "Got response for APDU: %02X%02X%02X%02X (%04X - %s)", cla, ins, p1, p2, + sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff)); + PrintAndLogEx(INFO, "Resending current command with Le = 0x0100 (extended length APDU)"); + uint8_t command2[7] = {cla, ins, p1, p2, 0x00}; + int command2_n = sizeof(command2); + res = ExchangeAPDU14a(command2, command2_n, activate_field, keep_field_on, response, sizeof(response), &response_n); if (res) { continue; } + command_with_le = true; + } - // Was there and length error? If so, try with Le length (case 2 instad of case 1, - // https://stackoverflow.com/a/30679558). Le = 0x00 will get interpreted as extended length APDU - // with Le being 0x0100. - uint16_t sw = get_sw(response, response_n); - bool command_with_le = false; - if (sw == 0x6700) { - PrintAndLogEx(INFO, "Got response for APDU: %02X%02X%02X%02X (%04x - %s)", cla, ins, p1, p2, + // Check response. + // TODO: What response values should be considerd "valid" or "instersting"? + sw = get_sw(response, response_n); + if (sw != 0x6a86 && + sw != 0x6986 && + sw != 0x6d00 + ) { + if (command_with_le) { + PrintAndLogEx(INFO, "Got response for APDU: %02X%02X%02X%02X00 (%04X - %s)", cla, ins, p1, p2, + sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff)); + } else { + PrintAndLogEx(INFO, "Got response for APDU: %02X%02X%02X%02X (%04X - %s)", cla, ins, p1, p2, sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff)); - PrintAndLogEx(INFO, "Resending current command with Le = 0x0100 (extended length APDU)"); - uint8_t command2[7] = {cla, ins, p1, p2, 0x00}; - int command2_n = sizeof(command2); - res = ExchangeAPDU14a(command2, command2_n, activate_field, keep_field_on, response, sizeof(response), &response_n); - if (res) { - continue; - } - command_with_le = true; } - - // Check response. - // TODO: What response values should be considerd "valid" or "instersting"? - sw = get_sw(response, response_n); - if (sw != 0x6a86 && - sw != 0x6986 && - sw != 0x6d00 - ) { - if (command_with_le) { - PrintAndLogEx(INFO, "Got response for APDU: %02X%02X%02X%02X00 (%04x - %s)", cla, ins, p1, p2, - sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff)); - } else { - PrintAndLogEx(INFO, "Got response for APDU: %02X%02X%02X%02X (%04x - %s)", cla, ins, p1, p2, - sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff)); - } - // Show response data. - if (response_n > 2) { - PrintAndLogEx(INFO, "Response data is: %s | %s", sprint_hex_inrow(response, response_n - 2), - sprint_ascii(response, response_n - 2)); - } + // Show response data. + if (response_n > 2) { + PrintAndLogEx(SUCCESS, "Response data is: %s | %s", sprint_hex_inrow(response, response_n - 2), + sprint_ascii(response, response_n - 2)); } - } while (++ins != ins_arg[0]); + } + } while (++ins != ins_arg[0]); + // Increment P1/P2 in an alternating fashion. + if (inc_p1) { p1++; - PrintAndLogEx(INFO, "Status: [ CLA " _GREEN_("%02X") " INS " _GREEN_("%02X") " P1 " _GREEN_("%02X") " P2 " _GREEN_("%02X") " ]", cla, ins, p1, p2); - } while (p1 != p1_arg[0]); - p2++; + } else { + p2++; + } + inc_p1 = !inc_p1; PrintAndLogEx(INFO, "Status: [ CLA " _GREEN_("%02X") " INS " _GREEN_("%02X") " P1 " _GREEN_("%02X") " P2 " _GREEN_("%02X") " ]", cla, ins, p1, p2); - } while (p2 != p2_arg[0]); + } while (p1 != p1_arg[0] || p2 != p2_arg[0]); cla++; PrintAndLogEx(INFO, "Status: [ CLA " _GREEN_("%02X") " INS " _GREEN_("%02X") " P1 " _GREEN_("%02X") " P2 " _GREEN_("%02X") " ]", cla, ins, p1, p2); } while (cla != cla_arg[0]); From 9db2a04449a6cb89881ea540146a1726ea4102c7 Mon Sep 17 00:00:00 2001 From: iceman1001 Date: Sun, 13 Dec 2020 01:44:03 +0100 Subject: [PATCH 049/682] fix: rem - now handles cliparse and strings correct --- client/src/cmdmain.c | 24 ++++++++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-) diff --git a/client/src/cmdmain.c b/client/src/cmdmain.c index 9b26512f1..4d393756f 100644 --- a/client/src/cmdmain.c +++ b/client/src/cmdmain.c @@ -165,19 +165,35 @@ int CmdRem(const char *Cmd) { CLIParserContext *ctx; CLIParserInit(&ctx, "rem", "Add a text line in log file", - "rem" + "rem my message -> adds a timestamp with `my message`" ); void *argtable[] = { arg_param_begin, + arg_strx1(NULL, NULL, NULL, "message line you want inserted"), arg_param_end }; - CLIExecWithReturn(ctx, Cmd, argtable, true); - CLIParserFree(ctx); + CLIExecWithReturn(ctx, Cmd, argtable, false); + struct arg_str* foo = arg_get_str(ctx, 1); + size_t count = 0; + size_t len = 0; + do { + count += strlen(foo->sval[len]); + } while (len++ < (foo->count - 1)); + + char s[count + foo->count]; + memset(s, 0, sizeof(s)); + + len = 0; + do { + snprintf(s + strlen(s), sizeof(s) - strlen(s), "%s ", foo->sval[len]); + } while (len++ < (foo->count - 1)); + + CLIParserFree(ctx); char buf[22] = {0}; AppendDate(buf, sizeof(buf), NULL); - PrintAndLogEx(NORMAL, "%s remark: %s", buf, Cmd); + PrintAndLogEx(SUCCESS, "%s remark: %s", buf, s); return PM3_SUCCESS; } From d5d5cc1fe65b8c80cca5f7551120cb41ede30e5b Mon Sep 17 00:00:00 2001 From: Ave Date: Mon, 14 Dec 2020 00:21:10 +0300 Subject: [PATCH 050/682] emrtd: Add further checks to secure_select and secure_read --- client/src/cmdhfemrtd.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/client/src/cmdhfemrtd.c b/client/src/cmdhfemrtd.c index f8f89f557..3dec8accb 100644 --- a/client/src/cmdhfemrtd.c +++ b/client/src/cmdhfemrtd.c @@ -466,7 +466,9 @@ static bool secure_select_file(uint8_t *kenc, uint8_t *kmac, uint8_t *ssc, const sprintf(command, "0C%s020C%02X%s00", SELECT, lc, sprint_hex_inrow(data, lc)); PrintAndLogEx(DEBUG, "command: %s", command); - exchange_commands(command, response, &resplen, false, true, use_14b); + if (exchange_commands(command, response, &resplen, false, true, use_14b) == false) { + return false; + } return check_cc(ssc, kmac, response, resplen); } @@ -524,7 +526,9 @@ static bool _secure_read_binary(uint8_t *kmac, uint8_t *ssc, int offset, int byt sprintf(command, "0C%s%02X%02X%02X%s00", READ_BINARY, p1, p2, lc, sprint_hex_inrow(data, lc)); PrintAndLogEx(DEBUG, "command: %s", command); - exchange_commands(command, dataout, dataoutlen, false, true, use_14b); + if (exchange_commands(command, dataout, dataoutlen, false, true, use_14b) == false) { + return false; + } return check_cc(ssc, kmac, dataout, *dataoutlen); } From a85e8a40d4955471e3ac7a68ff86583ac2faaece Mon Sep 17 00:00:00 2001 From: Ave Date: Mon, 14 Dec 2020 01:30:11 +0300 Subject: [PATCH 051/682] emrtd: Get file list from ef_com (but not parse yet) --- client/src/cmdhfemrtd.c | 134 ++++++++++++---------------------------- 1 file changed, 38 insertions(+), 96 deletions(-) diff --git a/client/src/cmdhfemrtd.c b/client/src/cmdhfemrtd.c index 3dec8accb..7dac49477 100644 --- a/client/src/cmdhfemrtd.c +++ b/client/src/cmdhfemrtd.c @@ -78,7 +78,7 @@ static bool exchange_commands(const char *cmd, uint8_t *dataout, int *dataoutlen PrintAndLogEx(DEBUG, "Sending: %s", cmd); - uint8_t aCMD[500]; + uint8_t aCMD[PM3_CMD_DATA_SIZE]; int aCMD_n = 0; param_gethex_to_eol(cmd, 0, aCMD, sizeof(aCMD), &aCMD_n); int res; @@ -404,7 +404,7 @@ static bool check_cc(uint8_t *ssc, uint8_t *key, uint8_t *rapdu, int rapdulength } static void _convert_filename(const char *file, uint8_t *dataout) { - char temp[3]; + char temp[3] = {0x00}; memcpy(temp, file, 2); dataout[0] = (int)strtol(temp, NULL, 16); memcpy(temp, file + 2, 2); @@ -592,6 +592,34 @@ static int secure_read_file(uint8_t *kenc, uint8_t *kmac, uint8_t *ssc, uint8_t return true; } +static bool ef_com_get_file_list(uint8_t *datain, int *datainlen, uint8_t *dataout, int *dataoutlen) { + int offset = 2; + int elementidlen = 0; + int elementlen = 0; + while (offset < *datainlen) { + PrintAndLogEx(DEBUG, "ef_com_get_file_list, offset: %i, data: %X", offset, *(datain + offset)); + // Determine element ID length to set as offset on asn1datalength + if (*(datain + offset) == 0x5f) { + elementidlen = 2; + } else { + elementidlen = 1; + } + + // Get the length of the element + elementlen = asn1datalength(datain + offset, *datainlen - offset, elementidlen); + + // If the element is what we're looking for, get the data and return true + if (*(datain + offset) == 0x5c) { + *dataoutlen = elementlen; + memcpy(dataout, datain + offset + elementidlen + 1, elementlen); + return true; + } + offset += elementidlen + elementlen + 1; + } + // Return false if we can't find the relevant element + return false; +} + int dumpHF_EMRTD(char *documentnumber, char *dob, char *expiry) { uint8_t response[25000]; uint8_t rnd_ic[8]; @@ -763,7 +791,7 @@ int dumpHF_EMRTD(char *documentnumber, char *dob, char *expiry) { // Select EF_COM if (secure_select_file(ks_enc, ks_mac, ssc, EF_COM, use_14b) == false) { - PrintAndLogEx(ERR, "Failed to secure select EF_COM, crypto checksum check failed."); + PrintAndLogEx(ERR, "Failed to secure select EF_COM."); DropField(); return PM3_ESOFT; } @@ -775,104 +803,18 @@ int dumpHF_EMRTD(char *documentnumber, char *dob, char *expiry) { } PrintAndLogEx(INFO, "Read EF_COM, len: %i.", resplen); PrintAndLogEx(DEBUG, "Contents (may be incomplete over 2k chars): %s", sprint_hex_inrow(response, resplen)); - saveFile("EF_COM", ".BIN", response, resplen); + // saveFile("EF_COM", ".BIN", response, resplen); - // TODO: Don't read a hardcoded list of files, reduce code repetition - // Select EF_DG1 - if (secure_select_file(ks_enc, ks_mac, ssc, EF_DG1, use_14b) == false) { - PrintAndLogEx(ERR, "Failed to secure select EF_DG1, crypto checksum check failed."); + uint8_t filelist[50]; + int filelistlen = 0; + + if (ef_com_get_file_list(response, &resplen, filelist, &filelistlen) == false) { + PrintAndLogEx(ERR, "Failed to read file list from EF_COM."); DropField(); return PM3_ESOFT; } - if (secure_read_file(ks_enc, ks_mac, ssc, response, &resplen, use_14b) == false) { - PrintAndLogEx(ERR, "Failed to read EF_DG1."); - DropField(); - return PM3_ESOFT; - } - PrintAndLogEx(INFO, "Read EF_DG1, len: %i.", resplen); - PrintAndLogEx(DEBUG, "Contents (may be incomplete over 2k chars): %s", sprint_hex_inrow(response, resplen)); - saveFile("EF_DG1", ".BIN", response, resplen); - - // Select EF_DG2 - if (secure_select_file(ks_enc, ks_mac, ssc, EF_DG2, use_14b) == false) { - PrintAndLogEx(ERR, "Failed to secure select EF_DG2, crypto checksum check failed."); - DropField(); - return PM3_ESOFT; - } - - if (secure_read_file(ks_enc, ks_mac, ssc, response, &resplen, use_14b) == false) { - PrintAndLogEx(ERR, "Failed to read EF_DG2."); - DropField(); - return PM3_ESOFT; - } - PrintAndLogEx(INFO, "Read EF_DG2, len: %i.", resplen); - PrintAndLogEx(DEBUG, "Contents (may be incomplete over 2k chars): %s", sprint_hex_inrow(response, resplen)); - saveFile("EF_DG2", ".BIN", response, resplen); - - // Select EF_SOD - if (secure_select_file(ks_enc, ks_mac, ssc, EF_SOD, use_14b) == false) { - PrintAndLogEx(ERR, "Failed to secure select EF_SOD, crypto checksum check failed."); - DropField(); - return PM3_ESOFT; - } - - if (secure_read_file(ks_enc, ks_mac, ssc, response, &resplen, use_14b) == false) { - PrintAndLogEx(ERR, "Failed to read EF_SOD."); - DropField(); - return PM3_ESOFT; - } - PrintAndLogEx(INFO, "Read EF_SOD, len: %i.", resplen); - PrintAndLogEx(DEBUG, "Contents (may be incomplete over 2k chars): %s", sprint_hex_inrow(response, resplen)); - saveFile("EF_SOD", ".BIN", response, resplen); - - // Select EF_DG11 - if (secure_select_file(ks_enc, ks_mac, ssc, EF_DG11, use_14b) == false) { - PrintAndLogEx(ERR, "Failed to secure select EF_DG11, crypto checksum check failed."); - DropField(); - return PM3_ESOFT; - } - - if (secure_read_file(ks_enc, ks_mac, ssc, response, &resplen, use_14b) == false) { - PrintAndLogEx(ERR, "Failed to read EF_DG11."); - DropField(); - return PM3_ESOFT; - } - PrintAndLogEx(INFO, "Read EF_DG11, len: %i.", resplen); - PrintAndLogEx(DEBUG, "Contents (may be incomplete over 2k chars): %s", sprint_hex_inrow(response, resplen)); - saveFile("EF_DG11", ".BIN", response, resplen); - - // Select EF_DG12 - if (secure_select_file(ks_enc, ks_mac, ssc, EF_DG12, use_14b) == false) { - PrintAndLogEx(ERR, "Failed to secure select EF_DG12, crypto checksum check failed."); - DropField(); - return PM3_ESOFT; - } - - if (secure_read_file(ks_enc, ks_mac, ssc, response, &resplen, use_14b) == false) { - PrintAndLogEx(ERR, "Failed to read EF_DG12."); - DropField(); - return PM3_ESOFT; - } - PrintAndLogEx(INFO, "Read EF_DG12, len: %i.", resplen); - PrintAndLogEx(DEBUG, "Contents (may be incomplete over 2k chars): %s", sprint_hex_inrow(response, resplen)); - saveFile("EF_DG12", ".BIN", response, resplen); - - // Select EF_DG14 - if (secure_select_file(ks_enc, ks_mac, ssc, EF_DG14, use_14b) == false) { - PrintAndLogEx(ERR, "Failed to secure select EF_DG14, crypto checksum check failed."); - DropField(); - return PM3_ESOFT; - } - - if (secure_read_file(ks_enc, ks_mac, ssc, response, &resplen, use_14b) == false) { - PrintAndLogEx(ERR, "Failed to read EF_DG14."); - DropField(); - return PM3_ESOFT; - } - PrintAndLogEx(INFO, "Read EF_DG14, len: %i.", resplen); - PrintAndLogEx(DEBUG, "Contents (may be incomplete over 2k chars): %s", sprint_hex_inrow(response, resplen)); - saveFile("EF_DG14", ".BIN", response, resplen); + PrintAndLogEx(DEBUG, "File List: %s", sprint_hex_inrow(filelist, filelistlen)); DropField(); return PM3_SUCCESS; From 41a7bdef1c3dc8b209b70617272a31dc585367d3 Mon Sep 17 00:00:00 2001 From: Ave Date: Mon, 14 Dec 2020 02:11:39 +0300 Subject: [PATCH 052/682] emrtd: Detect file list on card and dump what is available --- client/src/cmdhfemrtd.c | 120 +++++++++++++++++++++++++++++++++++++++- 1 file changed, 119 insertions(+), 1 deletion(-) diff --git a/client/src/cmdhfemrtd.c b/client/src/cmdhfemrtd.c index 7dac49477..b0ee1a7b0 100644 --- a/client/src/cmdhfemrtd.c +++ b/client/src/cmdhfemrtd.c @@ -620,6 +620,113 @@ static bool ef_com_get_file_list(uint8_t *datain, int *datainlen, uint8_t *datao return false; } +static bool file_tag_to_file_id(uint8_t *datain, char *filenameout, char *dataout) { + // imagine bothering with a hashmap or writing good code + // couldn't be me + switch (*datain) { + case 0x60: + memcpy(dataout, EF_COM, 4); + memcpy(filenameout, "EF_COM", 6); + break; + case 0x61: + memcpy(dataout, EF_DG1, 4); + memcpy(filenameout, "EF_DG1", 6); + break; + case 0x75: + memcpy(dataout, EF_DG2, 4); + memcpy(filenameout, "EF_DG2", 6); + break; + // These cases are commented out as they require PACE + // Trying to read a PACE file without doing PACE auth kills the session + // case 0x63: + // memcpy(dataout, EF_DG3, 4); + // memcpy(filenameout, "EF_DG3", 6); + // break; + // case 0x76: + // memcpy(dataout, EF_DG4, 4); + // memcpy(filenameout, "EF_DG4", 6); + // break; + case 0x65: + memcpy(dataout, EF_DG5, 4); + memcpy(filenameout, "EF_DG5", 6); + break; + case 0x66: + memcpy(dataout, EF_DG6, 4); + memcpy(filenameout, "EF_DG6", 6); + break; + case 0x67: + memcpy(dataout, EF_DG7, 4); + memcpy(filenameout, "EF_DG7", 6); + break; + case 0x68: + memcpy(dataout, EF_DG8, 4); + memcpy(filenameout, "EF_DG8", 6); + break; + case 0x69: + memcpy(dataout, EF_DG9, 4); + memcpy(filenameout, "EF_DG9", 6); + break; + case 0x6a: + memcpy(dataout, EF_DG10, 4); + memcpy(filenameout, "EF_DG10", 7); + break; + case 0x6b: + memcpy(dataout, EF_DG11, 4); + memcpy(filenameout, "EF_DG11", 7); + break; + case 0x6c: + memcpy(dataout, EF_DG12, 4); + memcpy(filenameout, "EF_DG12", 7); + break; + case 0x6d: + memcpy(dataout, EF_DG13, 4); + memcpy(filenameout, "EF_DG13", 7); + break; + case 0x6e: + memcpy(dataout, EF_DG14, 4); + memcpy(filenameout, "EF_DG14", 7); + break; + case 0x6f: + memcpy(dataout, EF_DG15, 4); + memcpy(filenameout, "EF_DG15", 7); + break; + case 0x70: + memcpy(dataout, EF_DG16, 4); + memcpy(filenameout, "EF_DG16", 7); + break; + case 0x77: + memcpy(dataout, EF_SOD, 4); + memcpy(filenameout, "EF_SOD", 6); + break; + default: + return false; + } + return true; +} + +static bool dump_file(uint8_t *ks_enc, uint8_t *ks_mac, uint8_t *ssc, const char *file, const char *name, bool use_14b) { + uint8_t response[35000]; + int resplen = 0; + + if (secure_select_file(ks_enc, ks_mac, ssc, file, use_14b) == false) { + PrintAndLogEx(ERR, "Failed to secure select %s, crypto checksum check failed.", name); + DropField(); + return false; + } + + if (secure_read_file(ks_enc, ks_mac, ssc, response, &resplen, use_14b) == false) { + PrintAndLogEx(ERR, "Failed to read %s.", name); + DropField(); + return false; + } + + PrintAndLogEx(INFO, "Read %s, len: %i.", name, resplen); + PrintAndLogEx(DEBUG, "Contents (may be incomplete over 2k chars): %s", sprint_hex_inrow(response, resplen)); + saveFile(name, ".BIN", response, resplen); + + return true; +} + int dumpHF_EMRTD(char *documentnumber, char *dob, char *expiry) { uint8_t response[25000]; uint8_t rnd_ic[8]; @@ -803,7 +910,7 @@ int dumpHF_EMRTD(char *documentnumber, char *dob, char *expiry) { } PrintAndLogEx(INFO, "Read EF_COM, len: %i.", resplen); PrintAndLogEx(DEBUG, "Contents (may be incomplete over 2k chars): %s", sprint_hex_inrow(response, resplen)); - // saveFile("EF_COM", ".BIN", response, resplen); + saveFile("EF_COM", ".BIN", response, resplen); uint8_t filelist[50]; int filelistlen = 0; @@ -816,6 +923,17 @@ int dumpHF_EMRTD(char *documentnumber, char *dob, char *expiry) { PrintAndLogEx(DEBUG, "File List: %s", sprint_hex_inrow(filelist, filelistlen)); + for (int i = 0; i < filelistlen; i++) { + char file_id[5] = {0x00}; + char file_name[8] = {0x00}; + if (file_tag_to_file_id(&filelist[i], file_name, file_id) == false) { + PrintAndLogEx(INFO, "File tag not found, skipping: %02X", filelist[i]); + continue; + } + PrintAndLogEx(DEBUG, "Current file: %s", file_name); + dump_file(ks_enc, ks_mac, ssc, file_id, file_name, use_14b); + } + DropField(); return PM3_SUCCESS; } From a5aed0dffd558cd35993c2c42503c89327eb42e6 Mon Sep 17 00:00:00 2001 From: Ave Date: Mon, 14 Dec 2020 02:42:37 +0300 Subject: [PATCH 053/682] emrtd: Force dumping EF_SOD --- client/src/cmdhfemrtd.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/client/src/cmdhfemrtd.c b/client/src/cmdhfemrtd.c index b0ee1a7b0..a476352a3 100644 --- a/client/src/cmdhfemrtd.c +++ b/client/src/cmdhfemrtd.c @@ -804,6 +804,7 @@ int dumpHF_EMRTD(char *documentnumber, char *dob, char *expiry) { PrintAndLogEx(INFO, "EF_DG1: %s", sprint_hex(response, resplen)); } } + // TODO: account for the case of no BAC PrintAndLogEx(DEBUG, "doc: %s", documentnumber); PrintAndLogEx(DEBUG, "dob: %s", dob); PrintAndLogEx(DEBUG, "exp: %s", expiry); @@ -934,6 +935,8 @@ int dumpHF_EMRTD(char *documentnumber, char *dob, char *expiry) { dump_file(ks_enc, ks_mac, ssc, file_id, file_name, use_14b); } + dump_file(ks_enc, ks_mac, ssc, EF_SOD, "EF_SOD", use_14b); + DropField(); return PM3_SUCCESS; } From 1e16b2d2d9b949a74e5455ccbb7f2f1a0b8c8bba Mon Sep 17 00:00:00 2001 From: Ave Date: Mon, 14 Dec 2020 17:26:47 +0300 Subject: [PATCH 054/682] emrtd: Code cleanup, impl PRNG --- client/src/cmdhfemrtd.c | 37 ++++++++++++++++++++----------------- 1 file changed, 20 insertions(+), 17 deletions(-) diff --git a/client/src/cmdhfemrtd.c b/client/src/cmdhfemrtd.c index a476352a3..5fdf0e7ca 100644 --- a/client/src/cmdhfemrtd.c +++ b/client/src/cmdhfemrtd.c @@ -26,6 +26,9 @@ #include "des.h" // mbedtls_des_key_set_parity #include "cmdhf14b.h" // exchange_14b_apdu #include "iso14b.h" // ISO14B_CONNECT etc +#include "crapto1/crapto1.h" // prng_successor +#include "commonutil.h" // num_to_bytes +#include "util_posix.h" // msclock #define TIMEOUT 2000 @@ -62,6 +65,9 @@ // App IDs #define AID_MRTD "A0000002471001" +uint8_t KENC_type[4] = {0x00, 0x00, 0x00, 0x01}; +uint8_t KMAC_type[4] = {0x00, 0x00, 0x00, 0x02}; + static int CmdHelp(const char *Cmd); static uint16_t get_sw(uint8_t *d, uint8_t n) { @@ -481,16 +487,9 @@ static bool _secure_read_binary(uint8_t *kmac, uint8_t *ssc, int offset, int byt PrintAndLogEx(DEBUG, "kmac: %s", sprint_hex_inrow(kmac, 20)); - // TODO: hacky - char offsethex[5]; - sprintf(offsethex, "%04X", offset); - char offsetbuffer[8]; - memcpy(offsetbuffer, offsethex, 2); - int p1 = (int)strtol(offsetbuffer, NULL, 16); - memcpy(offsetbuffer, offsethex + 2, 2); - int p2 = (int)strtol(offsetbuffer, NULL, 16); - temp[2] = p1; - temp[3] = p2; + // Set p1 and p2 + temp[2] = (uint8_t)(offset >> 8); + temp[3] = (uint8_t)(offset >> 0); int cmdlen = pad_block(temp, 4, cmd); PrintAndLogEx(DEBUG, "cmd: %s", sprint_hex_inrow(cmd, cmdlen)); @@ -523,7 +522,7 @@ static bool _secure_read_binary(uint8_t *kmac, uint8_t *ssc, int offset, int byt memcpy(data + 3, do8e, 10); PrintAndLogEx(DEBUG, "data: %s", sprint_hex_inrow(data, lc)); - sprintf(command, "0C%s%02X%02X%02X%s00", READ_BINARY, p1, p2, lc, sprint_hex_inrow(data, lc)); + sprintf(command, "0C%s%04X%02X%s00", READ_BINARY, offset, lc, sprint_hex_inrow(data, lc)); PrintAndLogEx(DEBUG, "command: %s", command); if (exchange_commands(command, dataout, dataoutlen, false, true, use_14b) == false) { @@ -727,6 +726,13 @@ static bool dump_file(uint8_t *ks_enc, uint8_t *ks_mac, uint8_t *ssc, const char return true; } +static void rng(int length, uint8_t *dataout) { + // Do very very secure prng operations + for (int i = 0; i < (length / 4); i++) { + num_to_bytes(prng_successor(msclock() + i, 32), 4, &dataout[i * 4]); + } +} + int dumpHF_EMRTD(char *documentnumber, char *dob, char *expiry) { uint8_t response[25000]; uint8_t rnd_ic[8]; @@ -735,12 +741,9 @@ int dumpHF_EMRTD(char *documentnumber, char *dob, char *expiry) { int resplen = 0; // bool BAC = true; uint8_t S[32]; - // TODO: Code sponsored jointly by duracell and sony - uint8_t rnd_ifd[8] = {0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA}; - uint8_t k_ifd[16] = {0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA}; - // TODO: get these _types into a better spot - uint8_t KENC_type[4] = {0x00, 0x00, 0x00, 0x01}; - uint8_t KMAC_type[4] = {0x00, 0x00, 0x00, 0x02}; + uint8_t rnd_ifd[8], k_ifd[16]; + rng(8, rnd_ifd); + rng(16, k_ifd); bool use_14b = false; From 8ed358e3bed27df3d323f437ae5bc5b53258cbd5 Mon Sep 17 00:00:00 2001 From: Ave Date: Mon, 14 Dec 2020 17:28:54 +0300 Subject: [PATCH 055/682] emrtd: Mark DESKey as const --- client/src/cmdhfemrtd.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/client/src/cmdhfemrtd.c b/client/src/cmdhfemrtd.c index 5fdf0e7ca..4b658d95e 100644 --- a/client/src/cmdhfemrtd.c +++ b/client/src/cmdhfemrtd.c @@ -65,8 +65,9 @@ // App IDs #define AID_MRTD "A0000002471001" -uint8_t KENC_type[4] = {0x00, 0x00, 0x00, 0x01}; -uint8_t KMAC_type[4] = {0x00, 0x00, 0x00, 0x02}; +// DESKey Types +const uint8_t KENC_type[4] = {0x00, 0x00, 0x00, 0x01}; +const uint8_t KMAC_type[4] = {0x00, 0x00, 0x00, 0x02}; static int CmdHelp(const char *Cmd); @@ -271,7 +272,7 @@ static void retail_mac(uint8_t *key, uint8_t *input, int inputlen, uint8_t *outp } -static void deskey(uint8_t *seed, uint8_t *type, int length, uint8_t *dataout) { +static void deskey(uint8_t *seed, const uint8_t *type, int length, uint8_t *dataout) { PrintAndLogEx(DEBUG, "seed: %s", sprint_hex_inrow(seed, 16)); // combine seed and type From 19922e1d23db9e5e33704a9f182e261baf7d99b1 Mon Sep 17 00:00:00 2001 From: Ave Date: Mon, 14 Dec 2020 17:30:58 +0300 Subject: [PATCH 056/682] emrtd: Clean up includes, further document used files --- client/src/cmdhfemrtd.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/client/src/cmdhfemrtd.c b/client/src/cmdhfemrtd.c index 4b658d95e..0490c783a 100644 --- a/client/src/cmdhfemrtd.c +++ b/client/src/cmdhfemrtd.c @@ -14,11 +14,9 @@ #include #include "fileutils.h" // saveFile #include "cmdparser.h" // command_t -#include "comms.h" // clearCommandBuffer -#include "cmdtrace.h" -#include "cliparser.h" -#include "crc16.h" -#include "cmdhf14a.h" +#include "cmdtrace.h" // CmdTraceList +#include "cliparser.h" // CLIParserContext etc +#include "cmdhf14a.h" // ExchangeAPDU14a #include "protocols.h" // definitions of ISO14A/7816 protocol #include "emv/apduinfo.h" // GetAPDUCodeDescription #include "sha1.h" // KSeed calculation etc From eaea632eb31c542d8c5cd2538a98102195fe594e Mon Sep 17 00:00:00 2001 From: Ave Date: Mon, 14 Dec 2020 17:45:53 +0300 Subject: [PATCH 057/682] emrtd: Join secure and insecure reads --- client/src/cmdhfemrtd.c | 335 +++++++++++++++++++--------------------- 1 file changed, 157 insertions(+), 178 deletions(-) diff --git a/client/src/cmdhfemrtd.c b/client/src/cmdhfemrtd.c index 0490c783a..43f10ad19 100644 --- a/client/src/cmdhfemrtd.c +++ b/client/src/cmdhfemrtd.c @@ -269,7 +269,6 @@ static void retail_mac(uint8_t *key, uint8_t *input, int inputlen, uint8_t *outp memcpy(output, intermediate_des, 8); } - static void deskey(uint8_t *seed, const uint8_t *type, int length, uint8_t *dataout) { PrintAndLogEx(DEBUG, "seed: %s", sprint_hex_inrow(seed, 16)); @@ -324,42 +323,6 @@ static int _read_binary(int offset, int bytes_to_read, uint8_t *dataout, int *da return exchange_commands(cmd, dataout, dataoutlen, false, true, use_14b); } -static int read_file(uint8_t *dataout, int *dataoutlen, bool use_14b) { - uint8_t response[PM3_CMD_DATA_SIZE]; - int resplen = 0; - uint8_t tempresponse[PM3_CMD_DATA_SIZE]; - int tempresplen = 0; - - if (!_read_binary(0, 4, response, &resplen, use_14b)) { - return false; - } - - int datalen = asn1datalength(response, resplen, 1); - int readlen = datalen - (3 - asn1fieldlength(response, resplen, 1)); - int offset = 4; - int toread; - - while (readlen > 0) { - toread = readlen; - if (readlen > 118) { - toread = 118; - } - - if (!_read_binary(offset, toread, tempresponse, &tempresplen, use_14b)) { - return false; - } - - memcpy(&response[resplen], &tempresponse, tempresplen); - offset += toread; - readlen -= toread; - resplen += tempresplen; - } - - memcpy(dataout, &response, resplen); - *dataoutlen = resplen; - return true; -} - static void bump_ssc(uint8_t *ssc) { PrintAndLogEx(DEBUG, "ssc-b: %s", sprint_hex_inrow(ssc, 8)); for (int i = 7; i > 0; i--) { @@ -553,21 +516,28 @@ static bool _secure_read_binary_decrypt(uint8_t *kenc, uint8_t *kmac, uint8_t *s return true; } -static int secure_read_file(uint8_t *kenc, uint8_t *kmac, uint8_t *ssc, uint8_t *dataout, int *dataoutlen, bool use_14b) { - // TODO: join this with regular read file - uint8_t response[25000]; + +static int read_file(uint8_t *dataout, int *dataoutlen, uint8_t *kenc, uint8_t *kmac, uint8_t *ssc, bool use_14b) { + uint8_t response[35000]; int resplen = 0; uint8_t tempresponse[500]; int tempresplen = 0; + int toread = 4; + int offset = 0; - if (!_secure_read_binary_decrypt(kenc, kmac, ssc, 0, 4, response, &resplen, use_14b)) { - return false; + if (kenc == NULL) { + if (_read_binary(offset, toread, response, &resplen, use_14b) == false) { + return false; + } + } else { + if (_secure_read_binary_decrypt(kenc, kmac, ssc, offset, toread, response, &resplen, use_14b) == false) { + return false; + } } int datalen = asn1datalength(response, resplen, 1); int readlen = datalen - (3 - asn1fieldlength(response, resplen, 1)); - int offset = 4; - int toread; + offset = 4; while (readlen > 0) { toread = readlen; @@ -575,8 +545,14 @@ static int secure_read_file(uint8_t *kenc, uint8_t *kmac, uint8_t *ssc, uint8_t toread = 118; } - if (!_secure_read_binary_decrypt(kenc, kmac, ssc, offset, toread, tempresponse, &tempresplen, use_14b)) { - return false; + if (kenc == NULL) { + if (_read_binary(offset, toread, tempresponse, &tempresplen, use_14b) == false) { + return false; + } + } else { + if (_secure_read_binary_decrypt(kenc, kmac, ssc, offset, toread, tempresponse, &tempresplen, use_14b) == false) { + return false; + } } memcpy(response + resplen, tempresponse, tempresplen); @@ -712,7 +688,7 @@ static bool dump_file(uint8_t *ks_enc, uint8_t *ks_mac, uint8_t *ssc, const char return false; } - if (secure_read_file(ks_enc, ks_mac, ssc, response, &resplen, use_14b) == false) { + if (read_file(response, &resplen, ks_enc, ks_mac, ssc, use_14b) == false) { PrintAndLogEx(ERR, "Failed to read %s.", name); DropField(); return false; @@ -738,7 +714,7 @@ int dumpHF_EMRTD(char *documentnumber, char *dob, char *expiry) { uint8_t kenc[50]; uint8_t kmac[50]; int resplen = 0; - // bool BAC = true; + bool BAC = false; uint8_t S[32]; uint8_t rnd_ifd[8], k_ifd[16]; rng(8, rnd_ifd); @@ -775,7 +751,7 @@ int dumpHF_EMRTD(char *documentnumber, char *dob, char *expiry) { // Select and read EF_CardAccess if (select_file(P1_SELECT_BY_EF, EF_CARDACCESS, use_14b)) { - read_file(response, &resplen, use_14b); + read_file(response, &resplen, NULL, NULL, NULL, use_14b); PrintAndLogEx(INFO, "Read EF_CardAccess, len: %i.", resplen); PrintAndLogEx(DEBUG, "Contents (may be incomplete over 2k chars): %s", sprint_hex_inrow(response, resplen)); } else { @@ -791,153 +767,156 @@ int dumpHF_EMRTD(char *documentnumber, char *dob, char *expiry) { // Select EF_COM if (select_file(P1_SELECT_BY_EF, EF_COM, use_14b) == false) { - // BAC = true; + BAC = true; PrintAndLogEx(INFO, "Basic Access Control is enforced. Will attempt external authentication."); } else { - // BAC = false; + BAC = false; // Select EF_DG1 select_file(P1_SELECT_BY_EF, EF_DG1, use_14b); - if (read_file(response, &resplen, use_14b) == false) { - // BAC = true; + if (read_file(response, &resplen, NULL, NULL, NULL, use_14b) == false) { + BAC = true; PrintAndLogEx(INFO, "Basic Access Control is enforced. Will attempt external authentication."); } else { - // BAC = false; + BAC = false; PrintAndLogEx(INFO, "EF_DG1: %s", sprint_hex(response, resplen)); } } - // TODO: account for the case of no BAC - PrintAndLogEx(DEBUG, "doc: %s", documentnumber); - PrintAndLogEx(DEBUG, "dob: %s", dob); - PrintAndLogEx(DEBUG, "exp: %s", expiry); - char documentnumbercd = calculate_check_digit(documentnumber); - char dobcd = calculate_check_digit(dob); - char expirycd = calculate_check_digit(expiry); + if (BAC) { + // TODO: account for the case of no BAC + PrintAndLogEx(DEBUG, "doc: %s", documentnumber); + PrintAndLogEx(DEBUG, "dob: %s", dob); + PrintAndLogEx(DEBUG, "exp: %s", expiry); - char kmrz[25]; - sprintf(kmrz, "%s%i%s%i%s%i", documentnumber, documentnumbercd, dob, dobcd, expiry, expirycd); - PrintAndLogEx(DEBUG, "kmrz: %s", kmrz); + char documentnumbercd = calculate_check_digit(documentnumber); + char dobcd = calculate_check_digit(dob); + char expirycd = calculate_check_digit(expiry); - uint8_t kseed[16] = {0x00}; - mbedtls_sha1((unsigned char *)kmrz, strlen(kmrz), kseed); - PrintAndLogEx(DEBUG, "kseed: %s", sprint_hex_inrow(kseed, 16)); + char kmrz[25]; + sprintf(kmrz, "%s%i%s%i%s%i", documentnumber, documentnumbercd, dob, dobcd, expiry, expirycd); + PrintAndLogEx(DEBUG, "kmrz: %s", kmrz); - deskey(kseed, KENC_type, 16, kenc); - deskey(kseed, KMAC_type, 16, kmac); - PrintAndLogEx(DEBUG, "kenc: %s", sprint_hex_inrow(kenc, 16)); - PrintAndLogEx(DEBUG, "kmac: %s", sprint_hex_inrow(kmac, 16)); + uint8_t kseed[16] = { 0x00 }; + mbedtls_sha1((unsigned char *)kmrz, strlen(kmrz), kseed); + PrintAndLogEx(DEBUG, "kseed: %s", sprint_hex_inrow(kseed, 16)); - // Get Challenge - if (get_challenge(8, rnd_ic, &resplen, use_14b) == false) { - PrintAndLogEx(ERR, "Couldn't get challenge."); - DropField(); - return PM3_ESOFT; - } - PrintAndLogEx(DEBUG, "rnd_ic: %s", sprint_hex_inrow(rnd_ic, 8)); + deskey(kseed, KENC_type, 16, kenc); + deskey(kseed, KMAC_type, 16, kmac); + PrintAndLogEx(DEBUG, "kenc: %s", sprint_hex_inrow(kenc, 16)); + PrintAndLogEx(DEBUG, "kmac: %s", sprint_hex_inrow(kmac, 16)); - memcpy(S, rnd_ifd, 8); - memcpy(S + 8, rnd_ic, 8); - memcpy(S + 16, k_ifd, 16); - - PrintAndLogEx(DEBUG, "S: %s", sprint_hex_inrow(S, 32)); - - uint8_t iv[8] = { 0x00 }; - uint8_t e_ifd[32] = { 0x00 }; - - des3_encrypt_cbc(iv, kenc, S, sizeof(S), e_ifd); - PrintAndLogEx(DEBUG, "e_ifd: %s", sprint_hex_inrow(e_ifd, 32)); - - uint8_t m_ifd[8] = { 0x00 }; - - retail_mac(kmac, e_ifd, 32, m_ifd); - PrintAndLogEx(DEBUG, "m_ifd: %s", sprint_hex_inrow(m_ifd, 8)); - - uint8_t cmd_data[40]; - memcpy(cmd_data, e_ifd, 32); - memcpy(cmd_data + 32, m_ifd, 8); - - // Do external authentication - if (external_authenticate(cmd_data, sizeof(cmd_data), response, &resplen, use_14b) == false) { - PrintAndLogEx(ERR, "Couldn't do external authentication. Did you supply the correct MRZ info?"); - DropField(); - return PM3_ESOFT; - } - PrintAndLogEx(INFO, "External authentication successful."); - - uint8_t dec_output[32] = { 0x00 }; - des3_decrypt_cbc(iv, kenc, response, 32, dec_output); - PrintAndLogEx(DEBUG, "dec_output: %s", sprint_hex_inrow(dec_output, 32)); - - if (memcmp(rnd_ifd, dec_output + 8, 8) != 0) { - PrintAndLogEx(ERR, "Challenge failed, rnd_ifd does not match."); - DropField(); - return PM3_ESOFT; - } - - uint8_t ssc[8] = { 0x00 }; - uint8_t ks_enc[16] = { 0x00 }; - uint8_t ks_mac[16] = { 0x00 }; - uint8_t k_icc[16] = { 0x00 }; - memcpy(k_icc, dec_output + 16, 16); - - // Calculate session keys - for (int x = 0; x < 16; x++) { - kseed[x] = k_ifd[x] ^ k_icc[x]; - } - - PrintAndLogEx(DEBUG, "kseed: %s", sprint_hex_inrow(kseed, 16)); - - deskey(kseed, KENC_type, 16, ks_enc); - deskey(kseed, KMAC_type, 16, ks_mac); - - PrintAndLogEx(DEBUG, "ks_enc: %s", sprint_hex_inrow(ks_enc, 16)); - PrintAndLogEx(DEBUG, "ks_mac: %s", sprint_hex_inrow(ks_mac, 16)); - - memcpy(ssc, rnd_ic + 4, 4); - memcpy(ssc + 4, rnd_ifd + 4, 4); - - PrintAndLogEx(DEBUG, "ssc: %s", sprint_hex_inrow(ssc, 8)); - - // Select EF_COM - if (secure_select_file(ks_enc, ks_mac, ssc, EF_COM, use_14b) == false) { - PrintAndLogEx(ERR, "Failed to secure select EF_COM."); - DropField(); - return PM3_ESOFT; - } - - if (secure_read_file(ks_enc, ks_mac, ssc, response, &resplen, use_14b) == false) { - PrintAndLogEx(ERR, "Failed to read EF_COM."); - DropField(); - return PM3_ESOFT; - } - PrintAndLogEx(INFO, "Read EF_COM, len: %i.", resplen); - PrintAndLogEx(DEBUG, "Contents (may be incomplete over 2k chars): %s", sprint_hex_inrow(response, resplen)); - saveFile("EF_COM", ".BIN", response, resplen); - - uint8_t filelist[50]; - int filelistlen = 0; - - if (ef_com_get_file_list(response, &resplen, filelist, &filelistlen) == false) { - PrintAndLogEx(ERR, "Failed to read file list from EF_COM."); - DropField(); - return PM3_ESOFT; - } - - PrintAndLogEx(DEBUG, "File List: %s", sprint_hex_inrow(filelist, filelistlen)); - - for (int i = 0; i < filelistlen; i++) { - char file_id[5] = {0x00}; - char file_name[8] = {0x00}; - if (file_tag_to_file_id(&filelist[i], file_name, file_id) == false) { - PrintAndLogEx(INFO, "File tag not found, skipping: %02X", filelist[i]); - continue; + // Get Challenge + if (get_challenge(8, rnd_ic, &resplen, use_14b) == false) { + PrintAndLogEx(ERR, "Couldn't get challenge."); + DropField(); + return PM3_ESOFT; } - PrintAndLogEx(DEBUG, "Current file: %s", file_name); - dump_file(ks_enc, ks_mac, ssc, file_id, file_name, use_14b); - } + PrintAndLogEx(DEBUG, "rnd_ic: %s", sprint_hex_inrow(rnd_ic, 8)); - dump_file(ks_enc, ks_mac, ssc, EF_SOD, "EF_SOD", use_14b); + memcpy(S, rnd_ifd, 8); + memcpy(S + 8, rnd_ic, 8); + memcpy(S + 16, k_ifd, 16); + + PrintAndLogEx(DEBUG, "S: %s", sprint_hex_inrow(S, 32)); + + uint8_t iv[8] = { 0x00 }; + uint8_t e_ifd[32] = { 0x00 }; + + des3_encrypt_cbc(iv, kenc, S, sizeof(S), e_ifd); + PrintAndLogEx(DEBUG, "e_ifd: %s", sprint_hex_inrow(e_ifd, 32)); + + uint8_t m_ifd[8] = { 0x00 }; + + retail_mac(kmac, e_ifd, 32, m_ifd); + PrintAndLogEx(DEBUG, "m_ifd: %s", sprint_hex_inrow(m_ifd, 8)); + + uint8_t cmd_data[40]; + memcpy(cmd_data, e_ifd, 32); + memcpy(cmd_data + 32, m_ifd, 8); + + // Do external authentication + if (external_authenticate(cmd_data, sizeof(cmd_data), response, &resplen, use_14b) == false) { + PrintAndLogEx(ERR, "Couldn't do external authentication. Did you supply the correct MRZ info?"); + DropField(); + return PM3_ESOFT; + } + PrintAndLogEx(INFO, "External authentication successful."); + + uint8_t dec_output[32] = { 0x00 }; + des3_decrypt_cbc(iv, kenc, response, 32, dec_output); + PrintAndLogEx(DEBUG, "dec_output: %s", sprint_hex_inrow(dec_output, 32)); + + if (memcmp(rnd_ifd, dec_output + 8, 8) != 0) { + PrintAndLogEx(ERR, "Challenge failed, rnd_ifd does not match."); + DropField(); + return PM3_ESOFT; + } + + uint8_t ssc[8] = { 0x00 }; + uint8_t ks_enc[16] = { 0x00 }; + uint8_t ks_mac[16] = { 0x00 }; + uint8_t k_icc[16] = { 0x00 }; + memcpy(k_icc, dec_output + 16, 16); + + // Calculate session keys + for (int x = 0; x < 16; x++) { + kseed[x] = k_ifd[x] ^ k_icc[x]; + } + + PrintAndLogEx(DEBUG, "kseed: %s", sprint_hex_inrow(kseed, 16)); + + deskey(kseed, KENC_type, 16, ks_enc); + deskey(kseed, KMAC_type, 16, ks_mac); + + PrintAndLogEx(DEBUG, "ks_enc: %s", sprint_hex_inrow(ks_enc, 16)); + PrintAndLogEx(DEBUG, "ks_mac: %s", sprint_hex_inrow(ks_mac, 16)); + + memcpy(ssc, rnd_ic + 4, 4); + memcpy(ssc + 4, rnd_ifd + 4, 4); + + PrintAndLogEx(DEBUG, "ssc: %s", sprint_hex_inrow(ssc, 8)); + + // Select EF_COM + if (secure_select_file(ks_enc, ks_mac, ssc, EF_COM, use_14b) == false) { + PrintAndLogEx(ERR, "Failed to secure select EF_COM."); + DropField(); + return PM3_ESOFT; + } + + if (read_file(response, &resplen, ks_enc, ks_mac, ssc, use_14b) == false) { + PrintAndLogEx(ERR, "Failed to read EF_COM."); + DropField(); + return PM3_ESOFT; + } + PrintAndLogEx(INFO, "Read EF_COM, len: %i.", resplen); + PrintAndLogEx(DEBUG, "Contents (may be incomplete over 2k chars): %s", sprint_hex_inrow(response, resplen)); + saveFile("EF_COM", ".BIN", response, resplen); + + uint8_t filelist[50]; + int filelistlen = 0; + + if (ef_com_get_file_list(response, &resplen, filelist, &filelistlen) == false) { + PrintAndLogEx(ERR, "Failed to read file list from EF_COM."); + DropField(); + return PM3_ESOFT; + } + + PrintAndLogEx(DEBUG, "File List: %s", sprint_hex_inrow(filelist, filelistlen)); + + for (int i = 0; i < filelistlen; i++) { + char file_id[5] = {0x00}; + char file_name[8] = {0x00}; + if (file_tag_to_file_id(&filelist[i], file_name, file_id) == false) { + PrintAndLogEx(INFO, "File tag not found, skipping: %02X", filelist[i]); + continue; + } + PrintAndLogEx(DEBUG, "Current file: %s", file_name); + dump_file(ks_enc, ks_mac, ssc, file_id, file_name, use_14b); + } + + dump_file(ks_enc, ks_mac, ssc, EF_SOD, "EF_SOD", use_14b); + } DropField(); return PM3_SUCCESS; From 0bca61aa999a16a581a4e6c30e188d86c47a180e Mon Sep 17 00:00:00 2001 From: Ave Date: Mon, 14 Dec 2020 18:05:45 +0300 Subject: [PATCH 058/682] emrtd: Continue work on supporting non-BAC passports --- client/src/cmdhfemrtd.c | 154 +++++++++++++++++++++------------------- 1 file changed, 81 insertions(+), 73 deletions(-) diff --git a/client/src/cmdhfemrtd.c b/client/src/cmdhfemrtd.c index 43f10ad19..957620b86 100644 --- a/client/src/cmdhfemrtd.c +++ b/client/src/cmdhfemrtd.c @@ -379,7 +379,7 @@ static void _convert_filename(const char *file, uint8_t *dataout) { dataout[1] = (int)strtol(temp, NULL, 16); } -static bool secure_select_file(uint8_t *kenc, uint8_t *kmac, uint8_t *ssc, const char *file, bool use_14b) { +static bool secure_select_file(uint8_t *kenc, uint8_t *kmac, uint8_t *ssc, const char *select_by, const char *file, bool use_14b) { uint8_t response[PM3_CMD_DATA_SIZE]; int resplen = 0; @@ -391,7 +391,7 @@ static bool secure_select_file(uint8_t *kenc, uint8_t *kmac, uint8_t *ssc, const char command[54]; uint8_t cmd[8]; uint8_t data[21]; - uint8_t temp[8] = {0x0c, 0xa4, 0x02, 0x0c}; + uint8_t temp[8] = {0x0c, 0xa4, strtol(select_by, NULL, 16), 0x0c}; int cmdlen = pad_block(temp, 4, cmd); int datalen = pad_block(file_id, 2, data); @@ -431,7 +431,7 @@ static bool secure_select_file(uint8_t *kenc, uint8_t *kmac, uint8_t *ssc, const memcpy(data + (datalen + 3), do8e, 10); PrintAndLogEx(DEBUG, "data: %s", sprint_hex_inrow(data, lc)); - sprintf(command, "0C%s020C%02X%s00", SELECT, lc, sprint_hex_inrow(data, lc)); + sprintf(command, "0C%s%s0C%02X%s00", SELECT, select_by, lc, sprint_hex_inrow(data, lc)); PrintAndLogEx(DEBUG, "command: %s", command); if (exchange_commands(command, response, &resplen, false, true, use_14b) == false) { @@ -517,7 +517,7 @@ static bool _secure_read_binary_decrypt(uint8_t *kenc, uint8_t *kmac, uint8_t *s } -static int read_file(uint8_t *dataout, int *dataoutlen, uint8_t *kenc, uint8_t *kmac, uint8_t *ssc, bool use_14b) { +static int read_file(uint8_t *dataout, int *dataoutlen, uint8_t *kenc, uint8_t *kmac, uint8_t *ssc, bool use_secure, bool use_14b) { uint8_t response[35000]; int resplen = 0; uint8_t tempresponse[500]; @@ -525,12 +525,12 @@ static int read_file(uint8_t *dataout, int *dataoutlen, uint8_t *kenc, uint8_t * int toread = 4; int offset = 0; - if (kenc == NULL) { - if (_read_binary(offset, toread, response, &resplen, use_14b) == false) { + if (use_secure == true) { + if (_secure_read_binary_decrypt(kenc, kmac, ssc, offset, toread, response, &resplen, use_14b) == false) { return false; } } else { - if (_secure_read_binary_decrypt(kenc, kmac, ssc, offset, toread, response, &resplen, use_14b) == false) { + if (_read_binary(offset, toread, response, &resplen, use_14b) == false) { return false; } } @@ -678,19 +678,31 @@ static bool file_tag_to_file_id(uint8_t *datain, char *filenameout, char *dataou return true; } -static bool dump_file(uint8_t *ks_enc, uint8_t *ks_mac, uint8_t *ssc, const char *file, const char *name, bool use_14b) { +static bool select_and_read(uint8_t *dataout, int *dataoutlen, const char *file, uint8_t *ks_enc, uint8_t *ks_mac, uint8_t *ssc, bool use_secure, bool use_14b) { + if (use_secure == true) { + if (secure_select_file(ks_enc, ks_mac, ssc, P1_SELECT_BY_EF, file, use_14b) == false) { + PrintAndLogEx(ERR, "Failed to secure select %s.", file); + return false; + } + } else { + if (select_file(P1_SELECT_BY_EF, file, use_14b) == false) { + PrintAndLogEx(ERR, "Failed to select %s.", file); + return false; + } + } + + if (read_file(dataout, dataoutlen, ks_enc, ks_mac, ssc, use_secure, use_14b) == false) { + PrintAndLogEx(ERR, "Failed to read %s.", file); + return false; + } + return true; +} + +static bool dump_file(uint8_t *ks_enc, uint8_t *ks_mac, uint8_t *ssc, const char *file, const char *name, bool use_secure, bool use_14b) { uint8_t response[35000]; int resplen = 0; - if (secure_select_file(ks_enc, ks_mac, ssc, file, use_14b) == false) { - PrintAndLogEx(ERR, "Failed to secure select %s, crypto checksum check failed.", name); - DropField(); - return false; - } - - if (read_file(response, &resplen, ks_enc, ks_mac, ssc, use_14b) == false) { - PrintAndLogEx(ERR, "Failed to read %s.", name); - DropField(); + if (select_and_read(response, &resplen, file, ks_enc, ks_mac, ssc, use_secure, use_14b) == false) { return false; } @@ -709,17 +721,12 @@ static void rng(int length, uint8_t *dataout) { } int dumpHF_EMRTD(char *documentnumber, char *dob, char *expiry) { - uint8_t response[25000]; - uint8_t rnd_ic[8]; - uint8_t kenc[50]; - uint8_t kmac[50]; + uint8_t response[35000] = { 0x00 }; + uint8_t ssc[8] = { 0x00 }; + uint8_t ks_enc[16] = { 0x00 }; + uint8_t ks_mac[16] = { 0x00 }; int resplen = 0; bool BAC = false; - uint8_t S[32]; - uint8_t rnd_ifd[8], k_ifd[16]; - rng(8, rnd_ifd); - rng(16, k_ifd); - bool use_14b = false; // Try to 14a @@ -751,7 +758,7 @@ int dumpHF_EMRTD(char *documentnumber, char *dob, char *expiry) { // Select and read EF_CardAccess if (select_file(P1_SELECT_BY_EF, EF_CARDACCESS, use_14b)) { - read_file(response, &resplen, NULL, NULL, NULL, use_14b); + read_file(response, &resplen, NULL, NULL, NULL, false, use_14b); PrintAndLogEx(INFO, "Read EF_CardAccess, len: %i.", resplen); PrintAndLogEx(DEBUG, "Contents (may be incomplete over 2k chars): %s", sprint_hex_inrow(response, resplen)); } else { @@ -774,7 +781,7 @@ int dumpHF_EMRTD(char *documentnumber, char *dob, char *expiry) { // Select EF_DG1 select_file(P1_SELECT_BY_EF, EF_DG1, use_14b); - if (read_file(response, &resplen, NULL, NULL, NULL, use_14b) == false) { + if (read_file(response, &resplen, NULL, NULL, NULL, false, use_14b) == false) { BAC = true; PrintAndLogEx(INFO, "Basic Access Control is enforced. Will attempt external authentication."); } else { @@ -784,7 +791,16 @@ int dumpHF_EMRTD(char *documentnumber, char *dob, char *expiry) { } if (BAC) { - // TODO: account for the case of no BAC + uint8_t rnd_ic[8] = { 0x00 }; + uint8_t kenc[50] = { 0x00 }; + uint8_t kmac[50] = { 0x00 }; + uint8_t k_icc[16] = { 0x00 }; + uint8_t S[32] = { 0x00 }; + + uint8_t rnd_ifd[8], k_ifd[16]; + rng(8, rnd_ifd); + rng(16, k_ifd); + PrintAndLogEx(DEBUG, "doc: %s", documentnumber); PrintAndLogEx(DEBUG, "dob: %s", dob); PrintAndLogEx(DEBUG, "exp: %s", expiry); @@ -853,10 +869,6 @@ int dumpHF_EMRTD(char *documentnumber, char *dob, char *expiry) { return PM3_ESOFT; } - uint8_t ssc[8] = { 0x00 }; - uint8_t ks_enc[16] = { 0x00 }; - uint8_t ks_mac[16] = { 0x00 }; - uint8_t k_icc[16] = { 0x00 }; memcpy(k_icc, dec_output + 16, 16); // Calculate session keys @@ -876,48 +888,44 @@ int dumpHF_EMRTD(char *documentnumber, char *dob, char *expiry) { memcpy(ssc + 4, rnd_ifd + 4, 4); PrintAndLogEx(DEBUG, "ssc: %s", sprint_hex_inrow(ssc, 8)); - - // Select EF_COM - if (secure_select_file(ks_enc, ks_mac, ssc, EF_COM, use_14b) == false) { - PrintAndLogEx(ERR, "Failed to secure select EF_COM."); - DropField(); - return PM3_ESOFT; - } - - if (read_file(response, &resplen, ks_enc, ks_mac, ssc, use_14b) == false) { - PrintAndLogEx(ERR, "Failed to read EF_COM."); - DropField(); - return PM3_ESOFT; - } - PrintAndLogEx(INFO, "Read EF_COM, len: %i.", resplen); - PrintAndLogEx(DEBUG, "Contents (may be incomplete over 2k chars): %s", sprint_hex_inrow(response, resplen)); - saveFile("EF_COM", ".BIN", response, resplen); - - uint8_t filelist[50]; - int filelistlen = 0; - - if (ef_com_get_file_list(response, &resplen, filelist, &filelistlen) == false) { - PrintAndLogEx(ERR, "Failed to read file list from EF_COM."); - DropField(); - return PM3_ESOFT; - } - - PrintAndLogEx(DEBUG, "File List: %s", sprint_hex_inrow(filelist, filelistlen)); - - for (int i = 0; i < filelistlen; i++) { - char file_id[5] = {0x00}; - char file_name[8] = {0x00}; - if (file_tag_to_file_id(&filelist[i], file_name, file_id) == false) { - PrintAndLogEx(INFO, "File tag not found, skipping: %02X", filelist[i]); - continue; - } - PrintAndLogEx(DEBUG, "Current file: %s", file_name); - dump_file(ks_enc, ks_mac, ssc, file_id, file_name, use_14b); - } - - dump_file(ks_enc, ks_mac, ssc, EF_SOD, "EF_SOD", use_14b); } + // Select EF_COM + if (select_and_read(response, &resplen, EF_COM, ks_enc, ks_mac, ssc, BAC, use_14b) == false) { + PrintAndLogEx(ERR, "Failed to read EF_COM."); + DropField(); + return PM3_ESOFT; + } + PrintAndLogEx(INFO, "Read EF_COM, len: %i.", resplen); + PrintAndLogEx(DEBUG, "Contents (may be incomplete over 2k chars): %s", sprint_hex_inrow(response, resplen)); + saveFile("EF_COM", ".BIN", response, resplen); + + uint8_t filelist[50]; + int filelistlen = 0; + + if (ef_com_get_file_list(response, &resplen, filelist, &filelistlen) == false) { + PrintAndLogEx(ERR, "Failed to read file list from EF_COM."); + DropField(); + return PM3_ESOFT; + } + + PrintAndLogEx(DEBUG, "File List: %s", sprint_hex_inrow(filelist, filelistlen)); + + // Dump all files in the file list + for (int i = 0; i < filelistlen; i++) { + char file_id[5] = { 0x00 }; + char file_name[8] = { 0x00 }; + if (file_tag_to_file_id(&filelist[i], file_name, file_id) == false) { + PrintAndLogEx(INFO, "File tag not found, skipping: %02X", filelist[i]); + continue; + } + PrintAndLogEx(DEBUG, "Current file: %s", file_name); + dump_file(ks_enc, ks_mac, ssc, file_id, file_name, BAC, use_14b); + } + + // Dump EF_SOD + dump_file(ks_enc, ks_mac, ssc, EF_SOD, "EF_SOD", BAC, use_14b); + DropField(); return PM3_SUCCESS; } From d197d5df347478e71f59d6bfe0b3f48e7b64402d Mon Sep 17 00:00:00 2001 From: Ave Date: Mon, 14 Dec 2020 18:24:24 +0300 Subject: [PATCH 059/682] emrtd: Complete non-BAC support --- client/src/cmdhfemrtd.c | 39 +++++++++++++++++++++++++-------------- client/src/cmdhfemrtd.h | 2 +- 2 files changed, 26 insertions(+), 15 deletions(-) diff --git a/client/src/cmdhfemrtd.c b/client/src/cmdhfemrtd.c index 957620b86..a1e5406af 100644 --- a/client/src/cmdhfemrtd.c +++ b/client/src/cmdhfemrtd.c @@ -720,7 +720,7 @@ static void rng(int length, uint8_t *dataout) { } } -int dumpHF_EMRTD(char *documentnumber, char *dob, char *expiry) { +int dumpHF_EMRTD(char *documentnumber, char *dob, char *expiry, bool BAC_available) { uint8_t response[35000] = { 0x00 }; uint8_t ssc[8] = { 0x00 }; uint8_t ks_enc[16] = { 0x00 }; @@ -790,6 +790,13 @@ int dumpHF_EMRTD(char *documentnumber, char *dob, char *expiry) { } } + if (BAC == true && BAC_available == false) { + PrintAndLogEx(ERR, "This eMRTD enforces Basic Access Control, but you didn't supplied MRZ data. Cannot proceed."); + PrintAndLogEx(HINT, "Check out hf emrtd dump --help, supply data with -n -d and -e."); + DropField(); + return PM3_ESOFT; + } + if (BAC) { uint8_t rnd_ic[8] = { 0x00 }; uint8_t kenc[50] = { 0x00 }; @@ -939,25 +946,29 @@ static int cmd_hf_emrtd_dump(const char *Cmd) { void *argtable[] = { arg_param_begin, - arg_str1("n", "documentnumber", "", "9 character document number"), - arg_str1("d", "dateofbirth", "", "date of birth in YYMMDD format"), - arg_str1("e", "expiry", "", "expiry in YYMMDD format"), + arg_str0("n", "documentnumber", "", "9 character document number"), + arg_str0("d", "dateofbirth", "", "date of birth in YYMMDD format"), + arg_str0("e", "expiry", "", "expiry in YYMMDD format"), arg_param_end }; CLIExecWithReturn(ctx, Cmd, argtable, true); - uint8_t docnum[10]; - uint8_t dob[7]; - uint8_t expiry[7]; - int docnumlen = 9; - int doblen = 6; - int expirylen = 6; - CLIGetStrWithReturn(ctx, 1, docnum, &docnumlen); - CLIGetStrWithReturn(ctx, 2, dob, &doblen); - CLIGetStrWithReturn(ctx, 3, expiry, &expirylen); + uint8_t docnum[10] = { 0x00 }; + uint8_t dob[7] = { 0x00 }; + uint8_t expiry[7] = { 0x00 }; + bool BAC = true; + int slen = 0; // unused + // Go through all args, if even one isn't supplied, mark BAC as unavailable + if (CLIParamStrToBuf(arg_get_str(ctx, 1), docnum, 9, &slen) != 0 || slen == 0) { + BAC = false; + } else if (CLIParamStrToBuf(arg_get_str(ctx, 2), dob, 6, &slen) != 0 || slen == 0) { + BAC = false; + } else if (CLIParamStrToBuf(arg_get_str(ctx, 3), expiry, 6, &slen) != 0 || slen == 0) { + BAC = false; + } CLIParserFree(ctx); - return dumpHF_EMRTD((char *)docnum, (char *)dob, (char *)expiry); + return dumpHF_EMRTD((char *)docnum, (char *)dob, (char *)expiry, BAC); } static int cmd_hf_emrtd_list(const char *Cmd) { diff --git a/client/src/cmdhfemrtd.h b/client/src/cmdhfemrtd.h index 5899ad27a..84500fc8b 100644 --- a/client/src/cmdhfemrtd.h +++ b/client/src/cmdhfemrtd.h @@ -15,5 +15,5 @@ int CmdHFeMRTD(const char *Cmd); -int dumpHF_EMRTD(char *documentnumber, char *dob, char *expiry); +int dumpHF_EMRTD(char *documentnumber, char *dob, char *expiry, bool BAC_available); #endif From 457311ffd9a09d2ad8255353f36351fd6e6a3ef8 Mon Sep 17 00:00:00 2001 From: Ave Date: Mon, 14 Dec 2020 18:25:49 +0300 Subject: [PATCH 060/682] emrtd: make clean pass --- client/src/cmdhfemrtd.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/client/src/cmdhfemrtd.c b/client/src/cmdhfemrtd.c index a1e5406af..1ca3b9213 100644 --- a/client/src/cmdhfemrtd.c +++ b/client/src/cmdhfemrtd.c @@ -145,23 +145,23 @@ static char calculate_check_digit(char *data) { static int asn1datalength(uint8_t *datain, int datainlen, int offset) { PrintAndLogEx(DEBUG, "asn1datalength, datain: %s", sprint_hex_inrow(datain, datainlen)); - int lenfield = (int) *(datain + offset); + int lenfield = (int) * (datain + offset); PrintAndLogEx(DEBUG, "asn1datalength, lenfield: %i", lenfield); if (lenfield <= 0x7f) { return lenfield; } else if (lenfield == 0x81) { - return ((int) *(datain + offset + 1)); + return ((int) * (datain + offset + 1)); } else if (lenfield == 0x82) { - return ((int) *(datain + offset + 1) << 8) | ((int) *(datain + offset + 2)); + return ((int) * (datain + offset + 1) << 8) | ((int) * (datain + offset + 2)); } else if (lenfield == 0x83) { - return (((int) *(datain + offset + 1) << 16) | ((int) *(datain + offset + 2)) << 8) | ((int) *(datain + offset + 3)); + return (((int) * (datain + offset + 1) << 16) | ((int) * (datain + offset + 2)) << 8) | ((int) * (datain + offset + 3)); } return false; } static int asn1fieldlength(uint8_t *datain, int datainlen, int offset) { PrintAndLogEx(DEBUG, "asn1fieldlength, datain: %s", sprint_hex_inrow(datain, datainlen)); - int lenfield = (int) *(datain + offset); + int lenfield = (int) * (datain + offset); PrintAndLogEx(DEBUG, "asn1fieldlength, thing: %i", lenfield); if (lenfield <= 0x7f) { return 1; From bc00e92af012cd43896aa7dc64459cd1da6c0bf0 Mon Sep 17 00:00:00 2001 From: Ave Date: Mon, 14 Dec 2020 19:08:03 +0300 Subject: [PATCH 061/682] emrtd: Switch from size_t to int to make CI happy --- client/src/cmdhfemrtd.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/client/src/cmdhfemrtd.c b/client/src/cmdhfemrtd.c index 1ca3b9213..a3d98955e 100644 --- a/client/src/cmdhfemrtd.c +++ b/client/src/cmdhfemrtd.c @@ -293,10 +293,10 @@ static void deskey(uint8_t *seed, const uint8_t *type, int length, uint8_t *data } static int select_file(const char *select_by, const char *file_id, bool use_14b) { - size_t file_id_len = strlen(file_id) / 2; + int file_id_len = strlen(file_id) / 2; char cmd[50]; - sprintf(cmd, "00%s%s0C%02lu%s", SELECT, select_by, file_id_len, file_id); + sprintf(cmd, "00%s%s0C%02X%s", SELECT, select_by, file_id_len, file_id); return exchange_commands_noout(cmd, false, true, use_14b); } From 3339ba110f91cc24833a814a1248167a7b89da70 Mon Sep 17 00:00:00 2001 From: Ave Date: Mon, 14 Dec 2020 20:09:20 +0300 Subject: [PATCH 062/682] emrtd: Split BAC into its own function --- client/src/cmdhfemrtd.c | 223 +++++++++++++++++++++------------------- 1 file changed, 119 insertions(+), 104 deletions(-) diff --git a/client/src/cmdhfemrtd.c b/client/src/cmdhfemrtd.c index a3d98955e..d08a789f9 100644 --- a/client/src/cmdhfemrtd.c +++ b/client/src/cmdhfemrtd.c @@ -28,7 +28,11 @@ #include "commonutil.h" // num_to_bytes #include "util_posix.h" // msclock -#define TIMEOUT 2000 +// Max file size in bytes. Used in several places. +// Average EF_DG2 seems to be around 20-25kB or so, but ICAO doesn't set an upper limit +// Iris data seems to be suggested to be around 35kB per eye (Presumably bumping up the file size to around 70kB) +// but as we cannot read that until we implement PACE, 35k seems to be a safe point. +#define MAX_FILE_SIZE 35000 // ISO7816 commands #define SELECT "A4" @@ -518,7 +522,7 @@ static bool _secure_read_binary_decrypt(uint8_t *kenc, uint8_t *kmac, uint8_t *s static int read_file(uint8_t *dataout, int *dataoutlen, uint8_t *kenc, uint8_t *kmac, uint8_t *ssc, bool use_secure, bool use_14b) { - uint8_t response[35000]; + uint8_t response[MAX_FILE_SIZE]; int resplen = 0; uint8_t tempresponse[500]; int tempresplen = 0; @@ -699,7 +703,7 @@ static bool select_and_read(uint8_t *dataout, int *dataoutlen, const char *file, } static bool dump_file(uint8_t *ks_enc, uint8_t *ks_mac, uint8_t *ssc, const char *file, const char *name, bool use_secure, bool use_14b) { - uint8_t response[35000]; + uint8_t response[MAX_FILE_SIZE]; int resplen = 0; if (select_and_read(response, &resplen, file, ks_enc, ks_mac, ssc, use_secure, use_14b) == false) { @@ -720,12 +724,114 @@ static void rng(int length, uint8_t *dataout) { } } +static bool do_bac(char *documentnumber, char *dob, char *expiry, uint8_t *ssc, uint8_t *ks_enc, uint8_t *ks_mac, bool use_14b) { + uint8_t response[MAX_FILE_SIZE] = { 0x00 }; + int resplen = 0; + + uint8_t rnd_ic[8] = { 0x00 }; + uint8_t kenc[50] = { 0x00 }; + uint8_t kmac[50] = { 0x00 }; + uint8_t k_icc[16] = { 0x00 }; + uint8_t S[32] = { 0x00 }; + + uint8_t rnd_ifd[8], k_ifd[16]; + rng(8, rnd_ifd); + rng(16, k_ifd); + + PrintAndLogEx(DEBUG, "doc: %s", documentnumber); + PrintAndLogEx(DEBUG, "dob: %s", dob); + PrintAndLogEx(DEBUG, "exp: %s", expiry); + + char documentnumbercd = calculate_check_digit(documentnumber); + char dobcd = calculate_check_digit(dob); + char expirycd = calculate_check_digit(expiry); + + char kmrz[25]; + sprintf(kmrz, "%s%i%s%i%s%i", documentnumber, documentnumbercd, dob, dobcd, expiry, expirycd); + PrintAndLogEx(DEBUG, "kmrz: %s", kmrz); + + uint8_t kseed[16] = { 0x00 }; + mbedtls_sha1((unsigned char *)kmrz, strlen(kmrz), kseed); + PrintAndLogEx(DEBUG, "kseed: %s", sprint_hex_inrow(kseed, 16)); + + deskey(kseed, KENC_type, 16, kenc); + deskey(kseed, KMAC_type, 16, kmac); + PrintAndLogEx(DEBUG, "kenc: %s", sprint_hex_inrow(kenc, 16)); + PrintAndLogEx(DEBUG, "kmac: %s", sprint_hex_inrow(kmac, 16)); + + // Get Challenge + if (get_challenge(8, rnd_ic, &resplen, use_14b) == false) { + PrintAndLogEx(ERR, "Couldn't get challenge."); + return false; + } + PrintAndLogEx(DEBUG, "rnd_ic: %s", sprint_hex_inrow(rnd_ic, 8)); + + memcpy(S, rnd_ifd, 8); + memcpy(S + 8, rnd_ic, 8); + memcpy(S + 16, k_ifd, 16); + + PrintAndLogEx(DEBUG, "S: %s", sprint_hex_inrow(S, 32)); + + uint8_t iv[8] = { 0x00 }; + uint8_t e_ifd[32] = { 0x00 }; + + des3_encrypt_cbc(iv, kenc, S, sizeof(S), e_ifd); + PrintAndLogEx(DEBUG, "e_ifd: %s", sprint_hex_inrow(e_ifd, 32)); + + uint8_t m_ifd[8] = { 0x00 }; + + retail_mac(kmac, e_ifd, 32, m_ifd); + PrintAndLogEx(DEBUG, "m_ifd: %s", sprint_hex_inrow(m_ifd, 8)); + + uint8_t cmd_data[40]; + memcpy(cmd_data, e_ifd, 32); + memcpy(cmd_data + 32, m_ifd, 8); + + // Do external authentication + if (external_authenticate(cmd_data, sizeof(cmd_data), response, &resplen, use_14b) == false) { + PrintAndLogEx(ERR, "Couldn't do external authentication. Did you supply the correct MRZ info?"); + return false; + } + PrintAndLogEx(INFO, "External authentication successful."); + + uint8_t dec_output[32] = { 0x00 }; + des3_decrypt_cbc(iv, kenc, response, 32, dec_output); + PrintAndLogEx(DEBUG, "dec_output: %s", sprint_hex_inrow(dec_output, 32)); + + if (memcmp(rnd_ifd, dec_output + 8, 8) != 0) { + PrintAndLogEx(ERR, "Challenge failed, rnd_ifd does not match."); + return false; + } + + memcpy(k_icc, dec_output + 16, 16); + + // Calculate session keys + for (int x = 0; x < 16; x++) { + kseed[x] = k_ifd[x] ^ k_icc[x]; + } + + PrintAndLogEx(DEBUG, "kseed: %s", sprint_hex_inrow(kseed, 16)); + + deskey(kseed, KENC_type, 16, ks_enc); + deskey(kseed, KMAC_type, 16, ks_mac); + + PrintAndLogEx(DEBUG, "ks_enc: %s", sprint_hex_inrow(ks_enc, 16)); + PrintAndLogEx(DEBUG, "ks_mac: %s", sprint_hex_inrow(ks_mac, 16)); + + memcpy(ssc, rnd_ic + 4, 4); + memcpy(ssc + 4, rnd_ifd + 4, 4); + + PrintAndLogEx(DEBUG, "ssc: %s", sprint_hex_inrow(ssc, 8)); + + return true; +} + int dumpHF_EMRTD(char *documentnumber, char *dob, char *expiry, bool BAC_available) { - uint8_t response[35000] = { 0x00 }; + uint8_t response[MAX_FILE_SIZE] = { 0x00 }; + int resplen = 0; uint8_t ssc[8] = { 0x00 }; uint8_t ks_enc[16] = { 0x00 }; uint8_t ks_mac[16] = { 0x00 }; - int resplen = 0; bool BAC = false; bool use_14b = false; @@ -790,111 +896,20 @@ int dumpHF_EMRTD(char *documentnumber, char *dob, char *expiry, bool BAC_availab } } - if (BAC == true && BAC_available == false) { - PrintAndLogEx(ERR, "This eMRTD enforces Basic Access Control, but you didn't supplied MRZ data. Cannot proceed."); - PrintAndLogEx(HINT, "Check out hf emrtd dump --help, supply data with -n -d and -e."); - DropField(); - return PM3_ESOFT; - } - + // Do Basic Access Aontrol if (BAC) { - uint8_t rnd_ic[8] = { 0x00 }; - uint8_t kenc[50] = { 0x00 }; - uint8_t kmac[50] = { 0x00 }; - uint8_t k_icc[16] = { 0x00 }; - uint8_t S[32] = { 0x00 }; - - uint8_t rnd_ifd[8], k_ifd[16]; - rng(8, rnd_ifd); - rng(16, k_ifd); - - PrintAndLogEx(DEBUG, "doc: %s", documentnumber); - PrintAndLogEx(DEBUG, "dob: %s", dob); - PrintAndLogEx(DEBUG, "exp: %s", expiry); - - char documentnumbercd = calculate_check_digit(documentnumber); - char dobcd = calculate_check_digit(dob); - char expirycd = calculate_check_digit(expiry); - - char kmrz[25]; - sprintf(kmrz, "%s%i%s%i%s%i", documentnumber, documentnumbercd, dob, dobcd, expiry, expirycd); - PrintAndLogEx(DEBUG, "kmrz: %s", kmrz); - - uint8_t kseed[16] = { 0x00 }; - mbedtls_sha1((unsigned char *)kmrz, strlen(kmrz), kseed); - PrintAndLogEx(DEBUG, "kseed: %s", sprint_hex_inrow(kseed, 16)); - - deskey(kseed, KENC_type, 16, kenc); - deskey(kseed, KMAC_type, 16, kmac); - PrintAndLogEx(DEBUG, "kenc: %s", sprint_hex_inrow(kenc, 16)); - PrintAndLogEx(DEBUG, "kmac: %s", sprint_hex_inrow(kmac, 16)); - - // Get Challenge - if (get_challenge(8, rnd_ic, &resplen, use_14b) == false) { - PrintAndLogEx(ERR, "Couldn't get challenge."); - DropField(); - return PM3_ESOFT; - } - PrintAndLogEx(DEBUG, "rnd_ic: %s", sprint_hex_inrow(rnd_ic, 8)); - - memcpy(S, rnd_ifd, 8); - memcpy(S + 8, rnd_ic, 8); - memcpy(S + 16, k_ifd, 16); - - PrintAndLogEx(DEBUG, "S: %s", sprint_hex_inrow(S, 32)); - - uint8_t iv[8] = { 0x00 }; - uint8_t e_ifd[32] = { 0x00 }; - - des3_encrypt_cbc(iv, kenc, S, sizeof(S), e_ifd); - PrintAndLogEx(DEBUG, "e_ifd: %s", sprint_hex_inrow(e_ifd, 32)); - - uint8_t m_ifd[8] = { 0x00 }; - - retail_mac(kmac, e_ifd, 32, m_ifd); - PrintAndLogEx(DEBUG, "m_ifd: %s", sprint_hex_inrow(m_ifd, 8)); - - uint8_t cmd_data[40]; - memcpy(cmd_data, e_ifd, 32); - memcpy(cmd_data + 32, m_ifd, 8); - - // Do external authentication - if (external_authenticate(cmd_data, sizeof(cmd_data), response, &resplen, use_14b) == false) { - PrintAndLogEx(ERR, "Couldn't do external authentication. Did you supply the correct MRZ info?"); - DropField(); - return PM3_ESOFT; - } - PrintAndLogEx(INFO, "External authentication successful."); - - uint8_t dec_output[32] = { 0x00 }; - des3_decrypt_cbc(iv, kenc, response, 32, dec_output); - PrintAndLogEx(DEBUG, "dec_output: %s", sprint_hex_inrow(dec_output, 32)); - - if (memcmp(rnd_ifd, dec_output + 8, 8) != 0) { - PrintAndLogEx(ERR, "Challenge failed, rnd_ifd does not match."); + // If BAC isn't available, exit out and warn user. + if (!BAC_available) { + PrintAndLogEx(ERR, "This eMRTD enforces Basic Access Control, but you didn't supplied MRZ data. Cannot proceed."); + PrintAndLogEx(HINT, "Check out hf emrtd dump --help, supply data with -n -d and -e."); DropField(); return PM3_ESOFT; } - memcpy(k_icc, dec_output + 16, 16); - - // Calculate session keys - for (int x = 0; x < 16; x++) { - kseed[x] = k_ifd[x] ^ k_icc[x]; + if (do_bac(documentnumber, dob, expiry, ssc, ks_enc, ks_mac, use_14b) == false) { + DropField(); + return PM3_ESOFT; } - - PrintAndLogEx(DEBUG, "kseed: %s", sprint_hex_inrow(kseed, 16)); - - deskey(kseed, KENC_type, 16, ks_enc); - deskey(kseed, KMAC_type, 16, ks_mac); - - PrintAndLogEx(DEBUG, "ks_enc: %s", sprint_hex_inrow(ks_enc, 16)); - PrintAndLogEx(DEBUG, "ks_mac: %s", sprint_hex_inrow(ks_mac, 16)); - - memcpy(ssc, rnd_ic + 4, 4); - memcpy(ssc + 4, rnd_ifd + 4, 4); - - PrintAndLogEx(DEBUG, "ssc: %s", sprint_hex_inrow(ssc, 8)); } // Select EF_COM From 5f8612cf92c70219599990d2d57c4be49452d4fd Mon Sep 17 00:00:00 2001 From: Christian Molson Date: Mon, 14 Dec 2020 14:30:43 -0500 Subject: [PATCH 063/682] em4x70: Improve client print out of tag information --- client/src/cmdlfem4x70.c | 56 ++++++++++++++++++++++++++++++++-------- 1 file changed, 45 insertions(+), 11 deletions(-) diff --git a/client/src/cmdlfem4x70.c b/client/src/cmdlfem4x70.c index a13d29073..05d8d52b4 100644 --- a/client/src/cmdlfem4x70.c +++ b/client/src/cmdlfem4x70.c @@ -16,28 +16,62 @@ #include "commonutil.h" #include "em4x70.h" +#define LOCKBIT_0 BITMASK(6) +#define LOCKBIT_1 BITMASK(7) + #define BYTES2UINT16(x) ((x[1] << 8) | (x[0])) #define BYTES2UINT32(x) ((x[3] << 24) | (x[2] << 16) | (x[1] << 8) | (x[0])) +#define INDEX_TO_BLOCK(x) (((32-x)/2)-1) static int CmdHelp(const char *Cmd); -static void print_info_result(uint8_t *data) { +static void print_info_result(const uint8_t *data) { PrintAndLogEx(NORMAL, ""); PrintAndLogEx(INFO, "--- " _CYAN_("Tag Information") " ---------------------------"); - PrintAndLogEx(INFO, "-------------------------------------------------------------"); + PrintAndLogEx(INFO, "-----------------------------------------------"); - // data section - PrintAndLogEx(NORMAL, ""); - PrintAndLogEx(INFO, _YELLOW_("EM4x70 data:")); + PrintAndLogEx(INFO, "Block | data | info"); + PrintAndLogEx(INFO, "------+----------+-----------------------------"); - for (int i = 1; i <= 32; i += 2) { - PrintAndLogEx(NORMAL, "%02X %02X", data[32 - i], data[32 - i - 1]); + // Print out each section as memory map in datasheet + + // Start with UM2 + for (int i = 0; i < 8; i += 2) { + PrintAndLogEx(INFO, " %2d | %02X %02X | UM2", INDEX_TO_BLOCK(i), data[31 - i], data[31 - i - 1]); } - PrintAndLogEx(NORMAL, "Tag ID: %02X %02X %02X %02X", data[7], data[6], data[5], data[4]); - PrintAndLogEx(NORMAL, "Lockbit 0: %d %s", (data[3] & 0x40) ? 1 : 0, (data[3] & 0x40) ? "LOCKED" : "UNLOCKED"); - PrintAndLogEx(NORMAL, "Lockbit 1: %d", (data[3] & 0x80) ? 1 : 0); + PrintAndLogEx(INFO, "------+----------+-----------------------------"); + + // Print PIN (will never have data) + for (int i = 8; i < 12; i += 2) { + PrintAndLogEx(INFO, " %2d | -- -- | PIN write only", INDEX_TO_BLOCK(i)); + } + PrintAndLogEx(INFO, "------+----------+-----------------------------"); + + // Print Crypt Key (will never have data) + for (int i = 12; i < 24; i += 2) { + PrintAndLogEx(INFO, " %2d | -- -- | KEY write-only", INDEX_TO_BLOCK(i)); + } + PrintAndLogEx(INFO, "------+----------+-----------------------------"); + + // Print ID + for (int i = 24; i < 28; i += 2) { + PrintAndLogEx(INFO, " %2d | %02X %02X | ID", INDEX_TO_BLOCK(i), data[31 - i], data[31 - i - 1]); + } + PrintAndLogEx(INFO, "------+----------+-----------------------------"); + + // Print UM1 + for (int i = 28; i < 32; i += 2) { + PrintAndLogEx(INFO, " %2d | %02X %02X | UM1", INDEX_TO_BLOCK(i), data[31 - i], data[31 - i - 1]); + } + PrintAndLogEx(INFO, "------+----------+-----------------------------"); + + PrintAndLogEx(INFO, ""); + PrintAndLogEx(INFO, "Tag ID: %02X %02X %02X %02X", data[7], data[6], data[5], data[4]); + PrintAndLogEx(INFO, "Lockbit 0: %d", (data[3] & LOCKBIT_0) ? 1 : 0); + PrintAndLogEx(INFO, "Lockbit 1: %d", (data[3] & LOCKBIT_1) ? 1 : 0); + PrintAndLogEx(INFO, "Tag is %s.", (data[3] & LOCKBIT_0) ? _RED_("LOCKED") : _GREEN_("UNLOCKED")); PrintAndLogEx(NORMAL, ""); } @@ -53,7 +87,7 @@ int em4x70_info(void) { PacketResponseNG resp; if (!WaitForResponseTimeout(CMD_LF_EM4X70_INFO, &resp, TIMEOUT)) { - PrintAndLogEx(WARNING, "(em4x70) timeout while waiting for reply."); + PrintAndLogEx(WARNING, "(em4x70) Timeout while waiting for reply."); return PM3_ETIMEOUT; } From 006e5d2be036c3e2b81428c913a87d0ee649a574 Mon Sep 17 00:00:00 2001 From: ikarus Date: Mon, 14 Dec 2020 21:48:02 +0100 Subject: [PATCH 064/682] APDU finder: Reset the tag every x seconds (default is 5 minutes). --- client/src/cmdhf14a.c | 47 ++++++++++++++++++++++++++----------------- 1 file changed, 28 insertions(+), 19 deletions(-) diff --git a/client/src/cmdhf14a.c b/client/src/cmdhf14a.c index 0f020b54a..71ca030ef 100644 --- a/client/src/cmdhf14a.c +++ b/client/src/cmdhf14a.c @@ -2129,6 +2129,12 @@ static uint16_t get_sw(uint8_t *d, uint8_t n) { } static int CmdHf14AFindapdu(const char *Cmd) { + // TODO: What response values should be considerd "valid" or "instersting" (worth dispalying)? + // TODO: Option to select AID/File (and skip INS 0xA4). + // TODO: Validate the decoding of the APDU (not specific to this command, check + // https://cardwerk.com/smartcards/smartcard_standard_ISO7816-4_5_basic_organizations.aspx#chap5_3_2). + // TODO: Check all cases (APDUs) with no data bytes (no/short/extended length). + // TODO: Option to blacklist instructions (or whole APDUs). CLIParserContext *ctx; CLIParserInit(&ctx, "hf 14a apdufind", "Enumerate APDU's of ISO7816 protocol to find valid CLS/INS/P1P2 commands.\n" @@ -2141,11 +2147,12 @@ static int CmdHf14AFindapdu(const char *Cmd) { void *argtable[] = { arg_param_begin, - arg_str0("c", "cla", "", "start CLASS value (1 hex byte)"), - arg_str0("i", "ins", "", "start INSTRUCTION value (1 hex byte)"), - arg_str0(NULL, "p1", "", "start P1 value (1 hex byte)"), - arg_str0(NULL, "p2", "", "start P2 value (1 hex byte)"), - arg_lit0("v", "verbose", "verbose output"), + arg_str0("c", "cla", "", "Start value of CLASS (1 hex byte)"), + arg_str0("i", "ins", "", "Start value of INSTRUCTION (1 hex byte)"), + arg_str0(NULL, "p1", "", "Start value of P1 (1 hex byte)"), + arg_str0(NULL, "p2", "", "Start value of P2 (1 hex byte)"), + arg_u64_0("r", "reset", "", "Minimum secondes before resetting the tag (to prevent timeout issues). Default is 5 minutes"), + arg_lit0("v", "verbose", "Verbose output"), arg_param_end }; CLIExecWithReturn(ctx, Cmd, argtable, true); @@ -2153,20 +2160,18 @@ static int CmdHf14AFindapdu(const char *Cmd) { int cla_len = 0; uint8_t cla_arg[1] = {0}; CLIGetHexWithReturn(ctx, 1, cla_arg, &cla_len); - int ins_len = 0; uint8_t ins_arg[1] = {0}; CLIGetHexWithReturn(ctx, 2, ins_arg, &ins_len); - int p1_len = 0; uint8_t p1_arg[1] = {0}; CLIGetHexWithReturn(ctx, 3, p1_arg, &p1_len); - int p2_len = 0; uint8_t p2_arg[1] = {0}; CLIGetHexWithReturn(ctx, 4, p2_arg, &p2_len); + uint64_t reset_time = arg_get_u64_def(ctx, 5, 5 * 60); // Reset every 5 minutes. + bool verbose = arg_get_lit(ctx, 6); - bool verbose = arg_get_lit(ctx, 5); CLIParserFree(ctx); bool activate_field = true; @@ -2180,21 +2185,20 @@ static int CmdHf14AFindapdu(const char *Cmd) { uint8_t aSELECT_AID[80]; int aSELECT_AID_n = 0; - // Check if the tag reponde to APDUs. + // Check if the tag reponds to APDUs. PrintAndLogEx(INFO, "Sending a test APDU (select file command) to check if the tag is responding to APDU"); param_gethex_to_eol("00a404000aa000000440000101000100", 0, aSELECT_AID, sizeof(aSELECT_AID), &aSELECT_AID_n); - int res = ExchangeAPDU14a(aSELECT_AID, aSELECT_AID_n, activate_field, keep_field_on, response, sizeof(response), &response_n); + int res = ExchangeAPDU14a(aSELECT_AID, aSELECT_AID_n, true, false, response, sizeof(response), &response_n); if (res) { - DropField(); PrintAndLogEx(FAILED, "Tag did not responde to a test APDU (select file command). Aborting"); return res; } PrintAndLogEx(SUCCESS, "Got response. Starting the APDU finder [ CLA " _GREEN_("%02X") " INS " _GREEN_("%02X") " P1 " _GREEN_("%02X") " P2 " _GREEN_("%02X") " ]", cla, ins, p1, p2); PrintAndLogEx(INFO, "Press " _GREEN_("") " to exit"); - activate_field = false; bool inc_p1 = true; - uint64_t t1 = msclock(); + uint64_t t_start = msclock(); + uint64_t t_last_select = msclock(); // Enumerate APDUs. do { @@ -2224,7 +2228,7 @@ static int CmdHf14AFindapdu(const char *Cmd) { uint16_t sw = get_sw(response, response_n); bool command_with_le = false; if (sw == 0x6700) { - PrintAndLogEx(INFO, "Got response for APDU: %02X%02X%02X%02X (%04X - %s)", cla, ins, p1, p2, + PrintAndLogEx(INFO, "Got response for APDU \"%02X%02X%02X%02X\": %04X (%s)", cla, ins, p1, p2, sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff)); PrintAndLogEx(INFO, "Resending current command with Le = 0x0100 (extended length APDU)"); uint8_t command2[7] = {cla, ins, p1, p2, 0x00}; @@ -2237,17 +2241,16 @@ static int CmdHf14AFindapdu(const char *Cmd) { } // Check response. - // TODO: What response values should be considerd "valid" or "instersting"? sw = get_sw(response, response_n); if (sw != 0x6a86 && sw != 0x6986 && sw != 0x6d00 ) { if (command_with_le) { - PrintAndLogEx(INFO, "Got response for APDU: %02X%02X%02X%02X00 (%04X - %s)", cla, ins, p1, p2, + PrintAndLogEx(INFO, "Got response for APDU \"%02X%02X%02X%02X00\": %04X (%s)", cla, ins, p1, p2, sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff)); } else { - PrintAndLogEx(INFO, "Got response for APDU: %02X%02X%02X%02X (%04X - %s)", cla, ins, p1, p2, + PrintAndLogEx(INFO, "Got response for APDU \"%02X%02X%02X%02X\": %04X (%s)", cla, ins, p1, p2, sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff)); } // Show response data. @@ -2264,6 +2267,12 @@ static int CmdHf14AFindapdu(const char *Cmd) { p2++; } inc_p1 = !inc_p1; + // Check if re-selecting the card is needed. + if (((msclock() - t_last_select) / 1000) > reset_time) { + DropField(); + t_last_select = msclock(); + PrintAndLogEx(INFO, "Reseting the tag to prevent timeout issues"); + } PrintAndLogEx(INFO, "Status: [ CLA " _GREEN_("%02X") " INS " _GREEN_("%02X") " P1 " _GREEN_("%02X") " P2 " _GREEN_("%02X") " ]", cla, ins, p1, p2); } while (p1 != p1_arg[0] || p2 != p2_arg[0]); cla++; @@ -2271,7 +2280,7 @@ static int CmdHf14AFindapdu(const char *Cmd) { } while (cla != cla_arg[0]); out: - PrintAndLogEx(SUCCESS, "Runtime: %" PRIu64 " seconds\n", (msclock() - t1) / 1000); + PrintAndLogEx(SUCCESS, "Runtime: %" PRIu64 " seconds\n", (msclock() - t_start) / 1000); DropField(); return PM3_SUCCESS; } From 334000d44412f022854043002c485feaedf693d6 Mon Sep 17 00:00:00 2001 From: Christian Molson Date: Mon, 14 Dec 2020 16:17:29 -0500 Subject: [PATCH 065/682] em4x70: Used fixed threshold for high/low. Since we measure only pulse lengths (high+low) we just need to make sure the value is higher than noise threshold --- armsrc/em4x70.c | 71 +++++++++++-------------------------------------- 1 file changed, 15 insertions(+), 56 deletions(-) diff --git a/armsrc/em4x70.c b/armsrc/em4x70.c index 0bb18e7d2..697412f87 100644 --- a/armsrc/em4x70.c +++ b/armsrc/em4x70.c @@ -55,15 +55,18 @@ static bool command_parity = true; #define EM4X70_COMMAND_WRITE 0x05 #define EM4X70_COMMAND_UM2 0x07 -static uint8_t gHigh = 0; -static uint8_t gLow = 0; +// Constants used to determing high/low state of signal +#define EM4X70_NOISE_THRESHOLD 13 // May depend on noise in environment +#define HIGH_SIGNAL_THRESHOLD (127 + EM4X70_NOISE_THRESHOLD) +#define LOW_SIGNAL_THRESHOLD (127 - EM4X70_NOISE_THRESHOLD) -#define IS_HIGH(sample) (sample>gLow ? true : false) -#define IS_LOW(sample) (sample LOW_SIGNAL_THRESHOLD ? true : false) +#define IS_LOW(sample) (sample < HIGH_SIGNAL_THRESHOLD ? true : false) + +// Timing related macros #define IS_TIMEOUT(timeout_ticks) (GetTicks() > timeout_ticks) #define TICKS_ELAPSED(start_ticks) (GetTicks() - start_ticks) - static uint8_t bits2byte(const uint8_t *bits, int length); static void bits2bytes(const uint8_t *bits, int length, uint8_t *out); static int em4x70_receive(uint8_t *bits); @@ -106,64 +109,20 @@ static void EM4170_setup_read(void) { static bool get_signalproperties(void) { - // calculate signal properties (mean amplitudes) from measured data: - // 32 amplitudes (maximum values) -> mean amplitude value -> gHigh -> gLow - bool signal_found = false; - int no_periods = 32, pct = 50, noise = 140; // pct originally 75, found 50 was working better for me - uint8_t sample_ref = 127; - uint8_t sample_max_mean = 0; - uint8_t sample_max[no_periods]; - uint32_t sample_max_sum = 0; - - memset(sample_max, 0x00, sizeof(sample_max)); + // Simple check to ensure we see a signal above the noise threshold + uint32_t no_periods = 32; // wait until signal/noise > 1 (max. 32 periods) - for (int i = 0; i < TICKS_PER_FC * EM4X70_T_TAG_FULL_PERIOD * no_periods; i++) { + for (int i = 0; i < EM4X70_T_TAG_FULL_PERIOD * no_periods; i++) { // about 2 samples per bit period - WaitTicks(TICKS_PER_FC * EM4X70_T_TAG_HALF_PERIOD); + WaitTicks(EM4X70_T_TAG_HALF_PERIOD); - if (AT91C_BASE_SSC->SSC_RHR > noise) { - signal_found = true; - break; + if (AT91C_BASE_SSC->SSC_RHR > HIGH_SIGNAL_THRESHOLD) { + return true; } - } - - if (signal_found == false) - return false; - - // calculate mean maximum value of 32 periods, each period has a length of - // 3 single "full periods" to eliminate the influence of a listen window - for (int i = 0; i < no_periods; i++) { - - uint32_t start_ticks = GetTicks(); - //AT91C_BASE_TC0->TC_CCR = AT91C_TC_SWTRG; - while (TICKS_ELAPSED(start_ticks) < TICKS_PER_FC * 3 * EM4X70_T_TAG_FULL_PERIOD) { - - volatile uint8_t sample = (uint8_t)AT91C_BASE_SSC->SSC_RHR; - - if (sample > sample_max[i]) - sample_max[i] = sample; - - } - - sample_max_sum += sample_max[i]; - } - - sample_max_mean = sample_max_sum / no_periods; - - // set global envelope variables - gHigh = sample_ref + pct * (sample_max_mean - sample_ref) / 100; - gLow = sample_ref - pct * (sample_max_mean - sample_ref) / 100; - - // Basic sanity check - if (gHigh - gLow < EM4X70_MIN_AMPLITUDE) { - return false; - } - - Dbprintf("%s: gHigh %d gLow: %d", __func__, gHigh, gLow); - return true; + return false; } /** From b9b92c6bc3d0975bfd3c3d952a1e858096788dfe Mon Sep 17 00:00:00 2001 From: ikarus Date: Mon, 14 Dec 2020 23:27:47 +0100 Subject: [PATCH 066/682] APDU finder: Prevent reactivating the field (speedup). --- client/src/cmdhf14a.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/client/src/cmdhf14a.c b/client/src/cmdhf14a.c index 71ca030ef..d9ff4c3b7 100644 --- a/client/src/cmdhf14a.c +++ b/client/src/cmdhf14a.c @@ -2198,7 +2198,7 @@ static int CmdHf14AFindapdu(const char *Cmd) { bool inc_p1 = true; uint64_t t_start = msclock(); - uint64_t t_last_select = msclock(); + uint64_t t_last_reset = msclock(); // Enumerate APDUs. do { @@ -2259,6 +2259,7 @@ static int CmdHf14AFindapdu(const char *Cmd) { sprint_ascii(response, response_n - 2)); } } + activate_field = false; // Do not reativate the filed until the next reset. } while (++ins != ins_arg[0]); // Increment P1/P2 in an alternating fashion. if (inc_p1) { @@ -2268,10 +2269,12 @@ static int CmdHf14AFindapdu(const char *Cmd) { } inc_p1 = !inc_p1; // Check if re-selecting the card is needed. - if (((msclock() - t_last_select) / 1000) > reset_time) { + uint64_t t_since_last_reset = ((msclock() - t_last_reset) / 1000); + if (t_since_last_reset > reset_time) { DropField(); - t_last_select = msclock(); - PrintAndLogEx(INFO, "Reseting the tag to prevent timeout issues"); + activate_field = true; + t_last_reset = msclock(); + PrintAndLogEx(INFO, "Last reset was %" PRIu64 " seconds ago. Reseting the tag to prevent timeout issues", t_since_last_reset); } PrintAndLogEx(INFO, "Status: [ CLA " _GREEN_("%02X") " INS " _GREEN_("%02X") " P1 " _GREEN_("%02X") " P2 " _GREEN_("%02X") " ]", cla, ins, p1, p2); } while (p1 != p1_arg[0] || p2 != p2_arg[0]); From d76bdd250b5b782897cf29cf3e01c9db9087b770 Mon Sep 17 00:00:00 2001 From: ikarus Date: Mon, 14 Dec 2020 23:32:19 +0100 Subject: [PATCH 067/682] Fixed changelog. --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f613c4c70..a4898db8b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,7 @@ This project uses the changelog in accordance with [keepchangelog](http://keepac - Added `hf iclass encode` - encode a wiegand binary to a encrypted credential (@iceman1001) - Changed `recoverpk.py` - now tests more ECDSA curves (@doegox) - Added `hf 14a apdufuzz`- a naive apdu cla/ins/p1p2/len fuzzer (@iceman1001) + - Improved `hf 14a apdufuzz/apdufind` to find hidden APDUs (@ikarus23) - Fix mixed up INC/DEC in MIFARE protocol defs (@vortixdev) - Added `lf em 4x70 info` - new support for ID48 transponders (@cmolson) - Fix multiple coverity scan issues (@iceman1001) @@ -116,7 +117,6 @@ This project uses the changelog in accordance with [keepchangelog](http://keepac - Change, use system Whereami library if available (@doegox) - Change, use system Zlib library if available (@doegox) - Fix release version information (@doegox) - - Add `hf 14a apdufind` to find hidden APDUs (@iceman1001 & @ikarus23) ## [ice coffee.4.9237][2020-05-21] - Updated documentation (@doegox, @iceman1001) From 4969a0bca304142557b7acc059ffd962acd81d0e Mon Sep 17 00:00:00 2001 From: Ave Date: Tue, 15 Dec 2020 02:19:42 +0300 Subject: [PATCH 068/682] emrtd: Fix a crash --- client/src/cmdhfemrtd.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/src/cmdhfemrtd.c b/client/src/cmdhfemrtd.c index d08a789f9..bc0f13f3e 100644 --- a/client/src/cmdhfemrtd.c +++ b/client/src/cmdhfemrtd.c @@ -392,7 +392,7 @@ static bool secure_select_file(uint8_t *kenc, uint8_t *kmac, uint8_t *ssc, const _convert_filename(file, file_id); uint8_t iv[8] = { 0x00 }; - char command[54]; + char command[PM3_CMD_DATA_SIZE]; uint8_t cmd[8]; uint8_t data[21]; uint8_t temp[8] = {0x0c, 0xa4, strtol(select_by, NULL, 16), 0x0c}; From fbfe1d051c1998d0ac95af031775349467d2fff0 Mon Sep 17 00:00:00 2001 From: Ave Date: Tue, 15 Dec 2020 02:55:23 +0300 Subject: [PATCH 069/682] emrtd: loads of renames --- client/src/cmdhfemrtd.c | 249 ++++++++++++++++++++-------------------- 1 file changed, 124 insertions(+), 125 deletions(-) diff --git a/client/src/cmdhfemrtd.c b/client/src/cmdhfemrtd.c index bc0f13f3e..ea90fa433 100644 --- a/client/src/cmdhfemrtd.c +++ b/client/src/cmdhfemrtd.c @@ -32,40 +32,40 @@ // Average EF_DG2 seems to be around 20-25kB or so, but ICAO doesn't set an upper limit // Iris data seems to be suggested to be around 35kB per eye (Presumably bumping up the file size to around 70kB) // but as we cannot read that until we implement PACE, 35k seems to be a safe point. -#define MAX_FILE_SIZE 35000 +#define EMRTD_MAX_FILE_SIZE 35000 // ISO7816 commands -#define SELECT "A4" -#define EXTERNAL_AUTHENTICATE "82" -#define GET_CHALLENGE "84" -#define READ_BINARY "B0" -#define P1_SELECT_BY_EF "02" -#define P1_SELECT_BY_NAME "04" -#define P2_PROPRIETARY "0C" +#define EMRTD_SELECT "A4" +#define EMRTD_EXTERNAL_AUTHENTICATE "82" +#define EMRTD_GET_CHALLENGE "84" +#define EMRTD_READ_BINARY "B0" +#define EMRTD_P1_SELECT_BY_EF "02" +#define EMRTD_P1_SELECT_BY_NAME "04" +#define EMRTD_P2_PROPRIETARY "0C" // File IDs -#define EF_CARDACCESS "011C" -#define EF_COM "011E" -#define EF_DG1 "0101" -#define EF_DG2 "0102" -#define EF_DG3 "0103" -#define EF_DG4 "0104" -#define EF_DG5 "0105" -#define EF_DG6 "0106" -#define EF_DG7 "0107" -#define EF_DG8 "0108" -#define EF_DG9 "0109" -#define EF_DG10 "010A" -#define EF_DG11 "010B" -#define EF_DG12 "010C" -#define EF_DG13 "010D" -#define EF_DG14 "010E" -#define EF_DG15 "010F" -#define EF_DG16 "0110" -#define EF_SOD "011D" +#define EMRTD_EF_CARDACCESS "011C" +#define EMRTD_EF_COM "011E" +#define EMRTD_EF_DG1 "0101" +#define EMRTD_EF_DG2 "0102" +#define EMRTD_EF_DG3 "0103" +#define EMRTD_EF_DG4 "0104" +#define EMRTD_EF_DG5 "0105" +#define EMRTD_EF_DG6 "0106" +#define EMRTD_EF_DG7 "0107" +#define EMRTD_EF_DG8 "0108" +#define EMRTD_EF_DG9 "0109" +#define EMRTD_EF_DG10 "010A" +#define EMRTD_EF_DG11 "010B" +#define EMRTD_EF_DG12 "010C" +#define EMRTD_EF_DG13 "010D" +#define EMRTD_EF_DG14 "010E" +#define EMRTD_EF_DG15 "010F" +#define EMRTD_EF_DG16 "0110" +#define EMRTD_EF_SOD "011D" // App IDs -#define AID_MRTD "A0000002471001" +#define EMRTD_AID_MRTD "A0000002471001" // DESKey Types const uint8_t KENC_type[4] = {0x00, 0x00, 0x00, 0x01}; @@ -81,7 +81,7 @@ static uint16_t get_sw(uint8_t *d, uint8_t n) { return d[n] * 0x0100 + d[n + 1]; } -static bool exchange_commands(const char *cmd, uint8_t *dataout, int *dataoutlen, bool activate_field, bool keep_field_on, bool use_14b) { +static bool emrtd_exchange_commands(const char *cmd, uint8_t *dataout, int *dataoutlen, bool activate_field, bool keep_field_on, bool use_14b) { uint8_t response[PM3_CMD_DATA_SIZE]; int resplen = 0; @@ -118,14 +118,14 @@ static bool exchange_commands(const char *cmd, uint8_t *dataout, int *dataoutlen return true; } -static int exchange_commands_noout(const char *cmd, bool activate_field, bool keep_field_on, bool use_14b) { +static int emrtd_exchange_commands_noout(const char *cmd, bool activate_field, bool keep_field_on, bool use_14b) { uint8_t response[PM3_CMD_DATA_SIZE]; int resplen = 0; - return exchange_commands(cmd, response, &resplen, activate_field, keep_field_on, use_14b); + return emrtd_exchange_commands(cmd, response, &resplen, activate_field, keep_field_on, use_14b); } -static char calculate_check_digit(char *data) { +static char emrtd_calculate_check_digit(char *data) { int mrz_weight[] = {7, 3, 1}; int cd = 0; int value = 0; @@ -147,7 +147,7 @@ static char calculate_check_digit(char *data) { return cd % 10; } -static int asn1datalength(uint8_t *datain, int datainlen, int offset) { +static int emrtd_get_asn1_data_length(uint8_t *datain, int datainlen, int offset) { PrintAndLogEx(DEBUG, "asn1datalength, datain: %s", sprint_hex_inrow(datain, datainlen)); int lenfield = (int) * (datain + offset); PrintAndLogEx(DEBUG, "asn1datalength, lenfield: %i", lenfield); @@ -163,7 +163,7 @@ static int asn1datalength(uint8_t *datain, int datainlen, int offset) { return false; } -static int asn1fieldlength(uint8_t *datain, int datainlen, int offset) { +static int emrtd_get_asn1_field_length(uint8_t *datain, int datainlen, int offset) { PrintAndLogEx(DEBUG, "asn1fieldlength, datain: %s", sprint_hex_inrow(datain, datainlen)); int lenfield = (int) * (datain + offset); PrintAndLogEx(DEBUG, "asn1fieldlength, thing: %i", lenfield); @@ -273,7 +273,7 @@ static void retail_mac(uint8_t *key, uint8_t *input, int inputlen, uint8_t *outp memcpy(output, intermediate_des, 8); } -static void deskey(uint8_t *seed, const uint8_t *type, int length, uint8_t *dataout) { +static void emrtd_deskey(uint8_t *seed, const uint8_t *type, int length, uint8_t *dataout) { PrintAndLogEx(DEBUG, "seed: %s", sprint_hex_inrow(seed, 16)); // combine seed and type @@ -296,38 +296,38 @@ static void deskey(uint8_t *seed, const uint8_t *type, int length, uint8_t *data memcpy(dataout, &key, length); } -static int select_file(const char *select_by, const char *file_id, bool use_14b) { +static int emrtd_select_file(const char *select_by, const char *file_id, bool use_14b) { int file_id_len = strlen(file_id) / 2; char cmd[50]; - sprintf(cmd, "00%s%s0C%02X%s", SELECT, select_by, file_id_len, file_id); + sprintf(cmd, "00%s%s0C%02X%s", EMRTD_SELECT, select_by, file_id_len, file_id); - return exchange_commands_noout(cmd, false, true, use_14b); + return emrtd_exchange_commands_noout(cmd, false, true, use_14b); } -static int get_challenge(int length, uint8_t *dataout, int *dataoutlen, bool use_14b) { +static int emrtd_get_challenge(int length, uint8_t *dataout, int *dataoutlen, bool use_14b) { char cmd[50]; - sprintf(cmd, "00%s0000%02X", GET_CHALLENGE, length); + sprintf(cmd, "00%s0000%02X", EMRTD_GET_CHALLENGE, length); - return exchange_commands(cmd, dataout, dataoutlen, false, true, use_14b); + return emrtd_exchange_commands(cmd, dataout, dataoutlen, false, true, use_14b); } -static int external_authenticate(uint8_t *data, int length, uint8_t *dataout, int *dataoutlen, bool use_14b) { +static int emrtd_external_authenticate(uint8_t *data, int length, uint8_t *dataout, int *dataoutlen, bool use_14b) { char cmd[100]; - sprintf(cmd, "00%s0000%02X%s%02X", EXTERNAL_AUTHENTICATE, length, sprint_hex_inrow(data, length), length); + sprintf(cmd, "00%s0000%02X%s%02X", EMRTD_EXTERNAL_AUTHENTICATE, length, sprint_hex_inrow(data, length), length); - return exchange_commands(cmd, dataout, dataoutlen, false, true, use_14b); + return emrtd_exchange_commands(cmd, dataout, dataoutlen, false, true, use_14b); } -static int _read_binary(int offset, int bytes_to_read, uint8_t *dataout, int *dataoutlen, bool use_14b) { +static int _emrtd_read_binary(int offset, int bytes_to_read, uint8_t *dataout, int *dataoutlen, bool use_14b) { char cmd[50]; - sprintf(cmd, "00%s%04i%02i", READ_BINARY, offset, bytes_to_read); + sprintf(cmd, "00%s%04i%02i", EMRTD_READ_BINARY, offset, bytes_to_read); - return exchange_commands(cmd, dataout, dataoutlen, false, true, use_14b); + return emrtd_exchange_commands(cmd, dataout, dataoutlen, false, true, use_14b); } -static void bump_ssc(uint8_t *ssc) { +static void emrtd_bump_ssc(uint8_t *ssc) { PrintAndLogEx(DEBUG, "ssc-b: %s", sprint_hex_inrow(ssc, 8)); for (int i = 7; i > 0; i--) { if ((*(ssc + i)) == 0xFF) { @@ -341,12 +341,12 @@ static void bump_ssc(uint8_t *ssc) { } } -static bool check_cc(uint8_t *ssc, uint8_t *key, uint8_t *rapdu, int rapdulength) { +static bool emrtd_check_cc(uint8_t *ssc, uint8_t *key, uint8_t *rapdu, int rapdulength) { // https://elixi.re/i/clarkson.png uint8_t k[500]; uint8_t cc[500]; - bump_ssc(ssc); + emrtd_bump_ssc(ssc); memcpy(k, ssc, 8); int length = 0; @@ -375,7 +375,7 @@ static bool check_cc(uint8_t *ssc, uint8_t *key, uint8_t *rapdu, int rapdulength return memcmp(cc, rapdu + (rapdulength - 8), 8) == 0; } -static void _convert_filename(const char *file, uint8_t *dataout) { +static void _emrtd_convert_filename(const char *file, uint8_t *dataout) { char temp[3] = {0x00}; memcpy(temp, file, 2); dataout[0] = (int)strtol(temp, NULL, 16); @@ -383,13 +383,13 @@ static void _convert_filename(const char *file, uint8_t *dataout) { dataout[1] = (int)strtol(temp, NULL, 16); } -static bool secure_select_file(uint8_t *kenc, uint8_t *kmac, uint8_t *ssc, const char *select_by, const char *file, bool use_14b) { +static bool emrtd_secure_select_file(uint8_t *kenc, uint8_t *kmac, uint8_t *ssc, const char *select_by, const char *file, bool use_14b) { uint8_t response[PM3_CMD_DATA_SIZE]; int resplen = 0; // convert filename of string to bytes uint8_t file_id[2]; - _convert_filename(file, file_id); + _emrtd_convert_filename(file, file_id); uint8_t iv[8] = { 0x00 }; char command[PM3_CMD_DATA_SIZE]; @@ -413,7 +413,7 @@ static bool secure_select_file(uint8_t *kenc, uint8_t *kmac, uint8_t *ssc, const memcpy(m + cmdlen, do87, (datalen + 3)); PrintAndLogEx(DEBUG, "m: %s", sprint_hex_inrow(m, datalen + cmdlen + 3)); - bump_ssc(ssc); + emrtd_bump_ssc(ssc); uint8_t n[27]; memcpy(n, ssc, 8); @@ -435,17 +435,17 @@ static bool secure_select_file(uint8_t *kenc, uint8_t *kmac, uint8_t *ssc, const memcpy(data + (datalen + 3), do8e, 10); PrintAndLogEx(DEBUG, "data: %s", sprint_hex_inrow(data, lc)); - sprintf(command, "0C%s%s0C%02X%s00", SELECT, select_by, lc, sprint_hex_inrow(data, lc)); + sprintf(command, "0C%s%s0C%02X%s00", EMRTD_SELECT, select_by, lc, sprint_hex_inrow(data, lc)); PrintAndLogEx(DEBUG, "command: %s", command); - if (exchange_commands(command, response, &resplen, false, true, use_14b) == false) { + if (emrtd_exchange_commands(command, response, &resplen, false, true, use_14b) == false) { return false; } - return check_cc(ssc, kmac, response, resplen); + return emrtd_check_cc(ssc, kmac, response, resplen); } -static bool _secure_read_binary(uint8_t *kmac, uint8_t *ssc, int offset, int bytes_to_read, uint8_t *dataout, int *dataoutlen, bool use_14b) { +static bool _emrtd_secure_read_binary(uint8_t *kmac, uint8_t *ssc, int offset, int bytes_to_read, uint8_t *dataout, int *dataoutlen, bool use_14b) { char command[54]; uint8_t cmd[8]; uint8_t data[21]; @@ -466,7 +466,7 @@ static bool _secure_read_binary(uint8_t *kmac, uint8_t *ssc, int offset, int byt memcpy(m, cmd, 8); memcpy(m + 8, do97, 3); - bump_ssc(ssc); + emrtd_bump_ssc(ssc); uint8_t n[19]; memcpy(n, ssc, 8); @@ -488,23 +488,23 @@ static bool _secure_read_binary(uint8_t *kmac, uint8_t *ssc, int offset, int byt memcpy(data + 3, do8e, 10); PrintAndLogEx(DEBUG, "data: %s", sprint_hex_inrow(data, lc)); - sprintf(command, "0C%s%04X%02X%s00", READ_BINARY, offset, lc, sprint_hex_inrow(data, lc)); + sprintf(command, "0C%s%04X%02X%s00", EMRTD_READ_BINARY, offset, lc, sprint_hex_inrow(data, lc)); PrintAndLogEx(DEBUG, "command: %s", command); - if (exchange_commands(command, dataout, dataoutlen, false, true, use_14b) == false) { + if (emrtd_exchange_commands(command, dataout, dataoutlen, false, true, use_14b) == false) { return false; } - return check_cc(ssc, kmac, dataout, *dataoutlen); + return emrtd_check_cc(ssc, kmac, dataout, *dataoutlen); } -static bool _secure_read_binary_decrypt(uint8_t *kenc, uint8_t *kmac, uint8_t *ssc, int offset, int bytes_to_read, uint8_t *dataout, int *dataoutlen, bool use_14b) { +static bool _emrtd_secure_read_binary_decrypt(uint8_t *kenc, uint8_t *kmac, uint8_t *ssc, int offset, int bytes_to_read, uint8_t *dataout, int *dataoutlen, bool use_14b) { uint8_t response[500]; uint8_t temp[500]; int resplen, cutat = 0; uint8_t iv[8] = { 0x00 }; - if (_secure_read_binary(kmac, ssc, offset, bytes_to_read, response, &resplen, use_14b) == false) { + if (_emrtd_secure_read_binary(kmac, ssc, offset, bytes_to_read, response, &resplen, use_14b) == false) { return false; } @@ -521,8 +521,8 @@ static bool _secure_read_binary_decrypt(uint8_t *kenc, uint8_t *kmac, uint8_t *s } -static int read_file(uint8_t *dataout, int *dataoutlen, uint8_t *kenc, uint8_t *kmac, uint8_t *ssc, bool use_secure, bool use_14b) { - uint8_t response[MAX_FILE_SIZE]; +static int emrtd_read_file(uint8_t *dataout, int *dataoutlen, uint8_t *kenc, uint8_t *kmac, uint8_t *ssc, bool use_secure, bool use_14b) { + uint8_t response[EMRTD_MAX_FILE_SIZE]; int resplen = 0; uint8_t tempresponse[500]; int tempresplen = 0; @@ -530,17 +530,17 @@ static int read_file(uint8_t *dataout, int *dataoutlen, uint8_t *kenc, uint8_t * int offset = 0; if (use_secure == true) { - if (_secure_read_binary_decrypt(kenc, kmac, ssc, offset, toread, response, &resplen, use_14b) == false) { + if (_emrtd_secure_read_binary_decrypt(kenc, kmac, ssc, offset, toread, response, &resplen, use_14b) == false) { return false; } } else { - if (_read_binary(offset, toread, response, &resplen, use_14b) == false) { + if (_emrtd_read_binary(offset, toread, response, &resplen, use_14b) == false) { return false; } } - int datalen = asn1datalength(response, resplen, 1); - int readlen = datalen - (3 - asn1fieldlength(response, resplen, 1)); + int datalen = emrtd_get_asn1_data_length(response, resplen, 1); + int readlen = datalen - (3 - emrtd_get_asn1_field_length(response, resplen, 1)); offset = 4; while (readlen > 0) { @@ -550,11 +550,11 @@ static int read_file(uint8_t *dataout, int *dataoutlen, uint8_t *kenc, uint8_t * } if (kenc == NULL) { - if (_read_binary(offset, toread, tempresponse, &tempresplen, use_14b) == false) { + if (_emrtd_read_binary(offset, toread, tempresponse, &tempresplen, use_14b) == false) { return false; } } else { - if (_secure_read_binary_decrypt(kenc, kmac, ssc, offset, toread, tempresponse, &tempresplen, use_14b) == false) { + if (_emrtd_secure_read_binary_decrypt(kenc, kmac, ssc, offset, toread, tempresponse, &tempresplen, use_14b) == false) { return false; } } @@ -570,7 +570,7 @@ static int read_file(uint8_t *dataout, int *dataoutlen, uint8_t *kenc, uint8_t * return true; } -static bool ef_com_get_file_list(uint8_t *datain, int *datainlen, uint8_t *dataout, int *dataoutlen) { +static bool emrtd_ef_com_get_file_list(uint8_t *datain, int *datainlen, uint8_t *dataout, int *dataoutlen) { int offset = 2; int elementidlen = 0; int elementlen = 0; @@ -584,7 +584,7 @@ static bool ef_com_get_file_list(uint8_t *datain, int *datainlen, uint8_t *datao } // Get the length of the element - elementlen = asn1datalength(datain + offset, *datainlen - offset, elementidlen); + elementlen = emrtd_get_asn1_data_length(datain + offset, *datainlen - offset, elementidlen); // If the element is what we're looking for, get the data and return true if (*(datain + offset) == 0x5c) { @@ -598,82 +598,81 @@ static bool ef_com_get_file_list(uint8_t *datain, int *datainlen, uint8_t *datao return false; } -static bool file_tag_to_file_id(uint8_t *datain, char *filenameout, char *dataout) { +static bool emrtd_file_tag_to_file_id(uint8_t *datain, char *filenameout, char *dataout) { // imagine bothering with a hashmap or writing good code // couldn't be me switch (*datain) { case 0x60: - memcpy(dataout, EF_COM, 4); + memcpy(dataout, EMRTD_EF_COM, 4); memcpy(filenameout, "EF_COM", 6); break; case 0x61: - memcpy(dataout, EF_DG1, 4); + memcpy(dataout, EMRTD_EF_DG1, 4); memcpy(filenameout, "EF_DG1", 6); break; case 0x75: - memcpy(dataout, EF_DG2, 4); + memcpy(dataout, EMRTD_EF_DG2, 4); memcpy(filenameout, "EF_DG2", 6); break; // These cases are commented out as they require PACE - // Trying to read a PACE file without doing PACE auth kills the session // case 0x63: - // memcpy(dataout, EF_DG3, 4); + // memcpy(dataout, EMRTD_EF_DG3, 4); // memcpy(filenameout, "EF_DG3", 6); // break; // case 0x76: - // memcpy(dataout, EF_DG4, 4); + // memcpy(dataout, EMRTD_EF_DG4, 4); // memcpy(filenameout, "EF_DG4", 6); // break; case 0x65: - memcpy(dataout, EF_DG5, 4); + memcpy(dataout, EMRTD_EF_DG5, 4); memcpy(filenameout, "EF_DG5", 6); break; case 0x66: - memcpy(dataout, EF_DG6, 4); + memcpy(dataout, EMRTD_EF_DG6, 4); memcpy(filenameout, "EF_DG6", 6); break; case 0x67: - memcpy(dataout, EF_DG7, 4); + memcpy(dataout, EMRTD_EF_DG7, 4); memcpy(filenameout, "EF_DG7", 6); break; case 0x68: - memcpy(dataout, EF_DG8, 4); + memcpy(dataout, EMRTD_EF_DG8, 4); memcpy(filenameout, "EF_DG8", 6); break; case 0x69: - memcpy(dataout, EF_DG9, 4); + memcpy(dataout, EMRTD_EF_DG9, 4); memcpy(filenameout, "EF_DG9", 6); break; case 0x6a: - memcpy(dataout, EF_DG10, 4); + memcpy(dataout, EMRTD_EF_DG10, 4); memcpy(filenameout, "EF_DG10", 7); break; case 0x6b: - memcpy(dataout, EF_DG11, 4); + memcpy(dataout, EMRTD_EF_DG11, 4); memcpy(filenameout, "EF_DG11", 7); break; case 0x6c: - memcpy(dataout, EF_DG12, 4); + memcpy(dataout, EMRTD_EF_DG12, 4); memcpy(filenameout, "EF_DG12", 7); break; case 0x6d: - memcpy(dataout, EF_DG13, 4); + memcpy(dataout, EMRTD_EF_DG13, 4); memcpy(filenameout, "EF_DG13", 7); break; case 0x6e: - memcpy(dataout, EF_DG14, 4); + memcpy(dataout, EMRTD_EF_DG14, 4); memcpy(filenameout, "EF_DG14", 7); break; case 0x6f: - memcpy(dataout, EF_DG15, 4); + memcpy(dataout, EMRTD_EF_DG15, 4); memcpy(filenameout, "EF_DG15", 7); break; case 0x70: - memcpy(dataout, EF_DG16, 4); + memcpy(dataout, EMRTD_EF_DG16, 4); memcpy(filenameout, "EF_DG16", 7); break; case 0x77: - memcpy(dataout, EF_SOD, 4); + memcpy(dataout, EMRTD_EF_SOD, 4); memcpy(filenameout, "EF_SOD", 6); break; default: @@ -682,31 +681,31 @@ static bool file_tag_to_file_id(uint8_t *datain, char *filenameout, char *dataou return true; } -static bool select_and_read(uint8_t *dataout, int *dataoutlen, const char *file, uint8_t *ks_enc, uint8_t *ks_mac, uint8_t *ssc, bool use_secure, bool use_14b) { +static bool emrtd_select_and_read(uint8_t *dataout, int *dataoutlen, const char *file, uint8_t *ks_enc, uint8_t *ks_mac, uint8_t *ssc, bool use_secure, bool use_14b) { if (use_secure == true) { - if (secure_select_file(ks_enc, ks_mac, ssc, P1_SELECT_BY_EF, file, use_14b) == false) { + if (emrtd_secure_select_file(ks_enc, ks_mac, ssc, EMRTD_P1_SELECT_BY_EF, file, use_14b) == false) { PrintAndLogEx(ERR, "Failed to secure select %s.", file); return false; } } else { - if (select_file(P1_SELECT_BY_EF, file, use_14b) == false) { + if (emrtd_select_file(EMRTD_P1_SELECT_BY_EF, file, use_14b) == false) { PrintAndLogEx(ERR, "Failed to select %s.", file); return false; } } - if (read_file(dataout, dataoutlen, ks_enc, ks_mac, ssc, use_secure, use_14b) == false) { + if (emrtd_read_file(dataout, dataoutlen, ks_enc, ks_mac, ssc, use_secure, use_14b) == false) { PrintAndLogEx(ERR, "Failed to read %s.", file); return false; } return true; } -static bool dump_file(uint8_t *ks_enc, uint8_t *ks_mac, uint8_t *ssc, const char *file, const char *name, bool use_secure, bool use_14b) { - uint8_t response[MAX_FILE_SIZE]; +static bool emrtd_dump_file(uint8_t *ks_enc, uint8_t *ks_mac, uint8_t *ssc, const char *file, const char *name, bool use_secure, bool use_14b) { + uint8_t response[EMRTD_MAX_FILE_SIZE]; int resplen = 0; - if (select_and_read(response, &resplen, file, ks_enc, ks_mac, ssc, use_secure, use_14b) == false) { + if (emrtd_select_and_read(response, &resplen, file, ks_enc, ks_mac, ssc, use_secure, use_14b) == false) { return false; } @@ -724,8 +723,8 @@ static void rng(int length, uint8_t *dataout) { } } -static bool do_bac(char *documentnumber, char *dob, char *expiry, uint8_t *ssc, uint8_t *ks_enc, uint8_t *ks_mac, bool use_14b) { - uint8_t response[MAX_FILE_SIZE] = { 0x00 }; +static bool emrtd_do_bac(char *documentnumber, char *dob, char *expiry, uint8_t *ssc, uint8_t *ks_enc, uint8_t *ks_mac, bool use_14b) { + uint8_t response[EMRTD_MAX_FILE_SIZE] = { 0x00 }; int resplen = 0; uint8_t rnd_ic[8] = { 0x00 }; @@ -742,9 +741,9 @@ static bool do_bac(char *documentnumber, char *dob, char *expiry, uint8_t *ssc, PrintAndLogEx(DEBUG, "dob: %s", dob); PrintAndLogEx(DEBUG, "exp: %s", expiry); - char documentnumbercd = calculate_check_digit(documentnumber); - char dobcd = calculate_check_digit(dob); - char expirycd = calculate_check_digit(expiry); + char documentnumbercd = emrtd_calculate_check_digit(documentnumber); + char dobcd = emrtd_calculate_check_digit(dob); + char expirycd = emrtd_calculate_check_digit(expiry); char kmrz[25]; sprintf(kmrz, "%s%i%s%i%s%i", documentnumber, documentnumbercd, dob, dobcd, expiry, expirycd); @@ -754,13 +753,13 @@ static bool do_bac(char *documentnumber, char *dob, char *expiry, uint8_t *ssc, mbedtls_sha1((unsigned char *)kmrz, strlen(kmrz), kseed); PrintAndLogEx(DEBUG, "kseed: %s", sprint_hex_inrow(kseed, 16)); - deskey(kseed, KENC_type, 16, kenc); - deskey(kseed, KMAC_type, 16, kmac); + emrtd_deskey(kseed, KENC_type, 16, kenc); + emrtd_deskey(kseed, KMAC_type, 16, kmac); PrintAndLogEx(DEBUG, "kenc: %s", sprint_hex_inrow(kenc, 16)); PrintAndLogEx(DEBUG, "kmac: %s", sprint_hex_inrow(kmac, 16)); // Get Challenge - if (get_challenge(8, rnd_ic, &resplen, use_14b) == false) { + if (emrtd_get_challenge(8, rnd_ic, &resplen, use_14b) == false) { PrintAndLogEx(ERR, "Couldn't get challenge."); return false; } @@ -788,7 +787,7 @@ static bool do_bac(char *documentnumber, char *dob, char *expiry, uint8_t *ssc, memcpy(cmd_data + 32, m_ifd, 8); // Do external authentication - if (external_authenticate(cmd_data, sizeof(cmd_data), response, &resplen, use_14b) == false) { + if (emrtd_external_authenticate(cmd_data, sizeof(cmd_data), response, &resplen, use_14b) == false) { PrintAndLogEx(ERR, "Couldn't do external authentication. Did you supply the correct MRZ info?"); return false; } @@ -812,8 +811,8 @@ static bool do_bac(char *documentnumber, char *dob, char *expiry, uint8_t *ssc, PrintAndLogEx(DEBUG, "kseed: %s", sprint_hex_inrow(kseed, 16)); - deskey(kseed, KENC_type, 16, ks_enc); - deskey(kseed, KMAC_type, 16, ks_mac); + emrtd_deskey(kseed, KENC_type, 16, ks_enc); + emrtd_deskey(kseed, KMAC_type, 16, ks_mac); PrintAndLogEx(DEBUG, "ks_enc: %s", sprint_hex_inrow(ks_enc, 16)); PrintAndLogEx(DEBUG, "ks_mac: %s", sprint_hex_inrow(ks_mac, 16)); @@ -827,7 +826,7 @@ static bool do_bac(char *documentnumber, char *dob, char *expiry, uint8_t *ssc, } int dumpHF_EMRTD(char *documentnumber, char *dob, char *expiry, bool BAC_available) { - uint8_t response[MAX_FILE_SIZE] = { 0x00 }; + uint8_t response[EMRTD_MAX_FILE_SIZE] = { 0x00 }; int resplen = 0; uint8_t ssc[8] = { 0x00 }; uint8_t ks_enc[16] = { 0x00 }; @@ -863,8 +862,8 @@ int dumpHF_EMRTD(char *documentnumber, char *dob, char *expiry, bool BAC_availab } // Select and read EF_CardAccess - if (select_file(P1_SELECT_BY_EF, EF_CARDACCESS, use_14b)) { - read_file(response, &resplen, NULL, NULL, NULL, false, use_14b); + if (emrtd_select_file(EMRTD_P1_SELECT_BY_EF, EMRTD_EF_CARDACCESS, use_14b)) { + emrtd_read_file(response, &resplen, NULL, NULL, NULL, false, use_14b); PrintAndLogEx(INFO, "Read EF_CardAccess, len: %i.", resplen); PrintAndLogEx(DEBUG, "Contents (may be incomplete over 2k chars): %s", sprint_hex_inrow(response, resplen)); } else { @@ -872,22 +871,22 @@ int dumpHF_EMRTD(char *documentnumber, char *dob, char *expiry, bool BAC_availab } // Select MRTD applet - if (select_file(P1_SELECT_BY_NAME, AID_MRTD, use_14b) == false) { + if (emrtd_select_file(EMRTD_P1_SELECT_BY_NAME, EMRTD_AID_MRTD, use_14b) == false) { PrintAndLogEx(ERR, "Couldn't select the MRTD application."); DropField(); return PM3_ESOFT; } // Select EF_COM - if (select_file(P1_SELECT_BY_EF, EF_COM, use_14b) == false) { + if (emrtd_select_file(EMRTD_P1_SELECT_BY_EF, EMRTD_EF_COM, use_14b) == false) { BAC = true; PrintAndLogEx(INFO, "Basic Access Control is enforced. Will attempt external authentication."); } else { BAC = false; // Select EF_DG1 - select_file(P1_SELECT_BY_EF, EF_DG1, use_14b); + emrtd_select_file(EMRTD_P1_SELECT_BY_EF, EMRTD_EF_DG1, use_14b); - if (read_file(response, &resplen, NULL, NULL, NULL, false, use_14b) == false) { + if (emrtd_read_file(response, &resplen, NULL, NULL, NULL, false, use_14b) == false) { BAC = true; PrintAndLogEx(INFO, "Basic Access Control is enforced. Will attempt external authentication."); } else { @@ -906,14 +905,14 @@ int dumpHF_EMRTD(char *documentnumber, char *dob, char *expiry, bool BAC_availab return PM3_ESOFT; } - if (do_bac(documentnumber, dob, expiry, ssc, ks_enc, ks_mac, use_14b) == false) { + if (emrtd_do_bac(documentnumber, dob, expiry, ssc, ks_enc, ks_mac, use_14b) == false) { DropField(); return PM3_ESOFT; } } // Select EF_COM - if (select_and_read(response, &resplen, EF_COM, ks_enc, ks_mac, ssc, BAC, use_14b) == false) { + if (emrtd_select_and_read(response, &resplen, EMRTD_EF_COM, ks_enc, ks_mac, ssc, BAC, use_14b) == false) { PrintAndLogEx(ERR, "Failed to read EF_COM."); DropField(); return PM3_ESOFT; @@ -925,7 +924,7 @@ int dumpHF_EMRTD(char *documentnumber, char *dob, char *expiry, bool BAC_availab uint8_t filelist[50]; int filelistlen = 0; - if (ef_com_get_file_list(response, &resplen, filelist, &filelistlen) == false) { + if (emrtd_ef_com_get_file_list(response, &resplen, filelist, &filelistlen) == false) { PrintAndLogEx(ERR, "Failed to read file list from EF_COM."); DropField(); return PM3_ESOFT; @@ -937,16 +936,16 @@ int dumpHF_EMRTD(char *documentnumber, char *dob, char *expiry, bool BAC_availab for (int i = 0; i < filelistlen; i++) { char file_id[5] = { 0x00 }; char file_name[8] = { 0x00 }; - if (file_tag_to_file_id(&filelist[i], file_name, file_id) == false) { + if (emrtd_file_tag_to_file_id(&filelist[i], file_name, file_id) == false) { PrintAndLogEx(INFO, "File tag not found, skipping: %02X", filelist[i]); continue; } PrintAndLogEx(DEBUG, "Current file: %s", file_name); - dump_file(ks_enc, ks_mac, ssc, file_id, file_name, BAC, use_14b); + emrtd_dump_file(ks_enc, ks_mac, ssc, file_id, file_name, BAC, use_14b); } // Dump EF_SOD - dump_file(ks_enc, ks_mac, ssc, EF_SOD, "EF_SOD", BAC, use_14b); + emrtd_dump_file(ks_enc, ks_mac, ssc, EMRTD_EF_SOD, "EF_SOD", BAC, use_14b); DropField(); return PM3_SUCCESS; From 40654b8ac6af2a32eb6403ce3d8eabffdbd12b26 Mon Sep 17 00:00:00 2001 From: Christian Molson Date: Mon, 14 Dec 2020 19:44:07 -0500 Subject: [PATCH 070/682] em4x70: Clean up conversion of RF periods to ticks --- armsrc/em4x70.c | 90 ++++++++++++++++++++++++++----------------------- 1 file changed, 47 insertions(+), 43 deletions(-) diff --git a/armsrc/em4x70.c b/armsrc/em4x70.c index 697412f87..52bf21b11 100644 --- a/armsrc/em4x70.c +++ b/armsrc/em4x70.c @@ -21,28 +21,32 @@ static em4x70_tag_t tag = { 0 }; // EM4170 requires a parity bit on commands, other variants do not. static bool command_parity = true; -#define EM4X70_T_TAG_QUARTER_PERIOD 8 -#define EM4X70_T_TAG_HALF_PERIOD 16 -#define EM4X70_T_TAG_THREE_QUARTER_PERIOD 24 -#define EM4X70_T_TAG_FULL_PERIOD 32 -#define EM4X70_T_TAG_TWA 128 // Write Access Time -#define EM4X70_T_TAG_DIV 224 // Divergency Time -#define EM4X70_T_TAG_AUTH 4224 // Authentication Time -#define EM4X70_T_TAG_WEE 3072 // EEPROM write Time -#define EM4X70_T_TAG_TWALB 672 // Write Access Time of Lock Bits +// Conversion from Ticks to RF periods +// 1 us = 1.5 ticks +// 1RF Period = 8us = 12 Ticks +#define TICKS_PER_FC 12 -#define EM4X70_T_WAITING_FOR_SNGLLIW 160 // Unsure +// Chip timing from datasheet +// Converted into Ticks for timing functions +#define EM4X70_T_TAG_QUARTER_PERIOD (8 * TICKS_PER_FC) +#define EM4X70_T_TAG_HALF_PERIOD (16 * TICKS_PER_FC) +#define EM4X70_T_TAG_THREE_QUARTER_PERIOD (24 * TICKS_PER_FC) +#define EM4X70_T_TAG_FULL_PERIOD (32 * TICKS_PER_FC) // 1 Bit Period +#define EM4X70_T_TAG_TWA (128 * TICKS_PER_FC) // Write Access Time +#define EM4X70_T_TAG_DIV (224 * TICKS_PER_FC) // Divergency Time +#define EM4X70_T_TAG_AUTH (4224 * TICKS_PER_FC) // Authentication Time +#define EM4X70_T_TAG_WEE (3072 * TICKS_PER_FC) // EEPROM write Time +#define EM4X70_T_TAG_TWALB (672 * TICKS_PER_FC) // Write Access Time of Lock Bits +#define EM4X70_T_TAG_BITMOD (4 * TICKS_PER_FC) // Initial time to stop modulation when sending 0 +#define EM4X70_T_TAG_TOLERANCE (8 * TICKS_PER_FC) // Tolerance in RF periods for receive/LIW -#define TICKS_PER_FC 12 // 1 fc = 8us, 1.5us per tick = 12 ticks -#define EM4X70_MIN_AMPLITUDE 10 // Minimum difference between a high and low signal +#define EM4X70_T_TAG_TIMEOUT (4 * EM4X70_T_TAG_FULL_PERIOD) // Timeout if we ever get a pulse longer than this +#define EM4X70_T_WAITING_FOR_LIW 50 // Pulses to wait for listen window -#define EM4X70_TAG_TOLERANCE 8 -#define EM4X70_TAG_WORD 48 #define EM4X70_COMMAND_RETRIES 5 // Attempts to send/read command #define EM4X70_MAX_RECEIVE_LENGTH 96 // Maximum bits to expect from any command - /** * These IDs are from the EM4170 datasheet * Some versions of the chip require a @@ -133,7 +137,7 @@ static bool get_signalproperties(void) { static uint32_t get_pulse_length(void) { uint8_t sample; - uint32_t timeout = GetTicks() + (TICKS_PER_FC * 3 * EM4X70_T_TAG_FULL_PERIOD); + uint32_t timeout = GetTicks() + EM4X70_T_TAG_TIMEOUT; do { sample = (uint8_t)AT91C_BASE_SSC->SSC_RHR; @@ -143,7 +147,7 @@ static uint32_t get_pulse_length(void) { return 0; uint32_t start_ticks = GetTicks(); - timeout = start_ticks + (TICKS_PER_FC * 3 * EM4X70_T_TAG_FULL_PERIOD); + timeout = start_ticks + EM4X70_T_TAG_TIMEOUT; do { sample = (uint8_t)AT91C_BASE_SSC->SSC_RHR; @@ -152,7 +156,7 @@ static uint32_t get_pulse_length(void) { if (IS_TIMEOUT(timeout)) return 0; - timeout = (TICKS_PER_FC * 3 * EM4X70_T_TAG_FULL_PERIOD) + GetTicks(); + timeout = GetTicks() + EM4X70_T_TAG_TIMEOUT; do { sample = (uint8_t)AT91C_BASE_SSC->SSC_RHR; } while (IS_HIGH(sample) && !IS_TIMEOUT(timeout)); @@ -172,7 +176,7 @@ static uint32_t get_pulse_length(void) { static uint32_t get_pulse_invert_length(void) { uint8_t sample; - uint32_t timeout = GetTicks() + (TICKS_PER_FC * 3 * EM4X70_T_TAG_FULL_PERIOD); + uint32_t timeout = GetTicks() + EM4X70_T_TAG_TIMEOUT; do { sample = (uint8_t)AT91C_BASE_SSC->SSC_RHR; @@ -182,7 +186,7 @@ static uint32_t get_pulse_invert_length(void) { return 0; uint32_t start_ticks = GetTicks(); - timeout = start_ticks + (TICKS_PER_FC * 3 * EM4X70_T_TAG_FULL_PERIOD); + timeout = start_ticks + EM4X70_T_TAG_TIMEOUT; do { sample = (uint8_t)AT91C_BASE_SSC->SSC_RHR; @@ -191,7 +195,7 @@ static uint32_t get_pulse_invert_length(void) { if (IS_TIMEOUT(timeout)) return 0; - timeout = GetTicks() + (TICKS_PER_FC * 3 * EM4X70_T_TAG_FULL_PERIOD); + timeout = GetTicks() + EM4X70_T_TAG_TIMEOUT; do { sample = (uint8_t)AT91C_BASE_SSC->SSC_RHR; } while (IS_LOW(sample) && !IS_TIMEOUT(timeout)); @@ -203,9 +207,9 @@ static uint32_t get_pulse_invert_length(void) { } -static bool check_pulse_length(uint32_t pl, int length) { +static bool check_pulse_length(uint32_t pl, uint32_t length) { // check if pulse length corresponds to given length - return ((pl >= TICKS_PER_FC * (length - EM4X70_TAG_TOLERANCE)) & (pl <= TICKS_PER_FC * (length + EM4X70_TAG_TOLERANCE))); + return ((pl >= (length - EM4X70_T_TAG_TOLERANCE)) & (pl <= (length + EM4X70_T_TAG_TOLERANCE))); } static void em4x70_send_bit(bool bit) { @@ -215,24 +219,24 @@ static void em4x70_send_bit(bool bit) { if (bit == 0) { - // disable modulation (drop the field) for 4 cycles of carrier + // disable modulation (drop the field) n cycles of carrier LOW(GPIO_SSC_DOUT); - while (TICKS_ELAPSED(start_ticks) <= TICKS_PER_FC * 4); + while (TICKS_ELAPSED(start_ticks) <= EM4X70_T_TAG_BITMOD); // enable modulation (activates the field) for remaining first // half of bit period HIGH(GPIO_SSC_DOUT); - while (TICKS_ELAPSED(start_ticks) <= TICKS_PER_FC * EM4X70_T_TAG_HALF_PERIOD); + while (TICKS_ELAPSED(start_ticks) <= EM4X70_T_TAG_HALF_PERIOD); // disable modulation for second half of bit period LOW(GPIO_SSC_DOUT); - while (TICKS_ELAPSED(start_ticks) <= TICKS_PER_FC * EM4X70_T_TAG_FULL_PERIOD); + while (TICKS_ELAPSED(start_ticks) <= EM4X70_T_TAG_FULL_PERIOD); } else { // bit = "1" means disable modulation for full bit period LOW(GPIO_SSC_DOUT); - while (TICKS_ELAPSED(start_ticks) <= TICKS_PER_FC * EM4X70_T_TAG_FULL_PERIOD); + while (TICKS_ELAPSED(start_ticks) <= EM4X70_T_TAG_FULL_PERIOD); } } @@ -296,7 +300,7 @@ static bool check_ack(void) { // returns true if signal structue corresponds to ACK, anything else is // counted as NAK (-> false) uint32_t start_ticks = GetTicks(); - while (TICKS_ELAPSED(start_ticks) < TICKS_PER_FC * 4 * EM4X70_T_TAG_FULL_PERIOD) { + while (TICKS_ELAPSED(start_ticks) < (4 * EM4X70_T_TAG_FULL_PERIOD)) { /* ACK 64 (48+16) @@ -378,13 +382,13 @@ static int send_pin(const uint32_t pin) { } // Wait TWALB (write access lock bits) - WaitTicks(TICKS_PER_FC * EM4X70_T_TAG_TWALB); + WaitTicks(EM4X70_T_TAG_TWALB); // <-- Receive ACK if (check_ack()) { // Writes Lock Bits - WaitTicks(TICKS_PER_FC * EM4X70_T_TAG_WEE); + WaitTicks(EM4X70_T_TAG_WEE); // <-- Receive header + ID uint8_t tag_id[EM4X70_MAX_RECEIVE_LENGTH]; int num = em4x70_receive(tag_id); @@ -415,14 +419,14 @@ static int write(const uint16_t word, const uint8_t address) { em4x70_send_word(word); // Wait TWA - WaitTicks(TICKS_PER_FC * EM4X70_T_TAG_TWA); + WaitTicks(EM4X70_T_TAG_TWA); // look for ACK sequence if (check_ack()) { // now EM4x70 needs T0 * EM4X70_T_TAG_TWEE (EEPROM write time) // for saving data and should return with ACK - WaitTicks(TICKS_PER_FC * EM4X70_T_TAG_WEE); + WaitTicks(EM4X70_T_TAG_WEE); if (check_ack()) { return PM3_SUCCESS; @@ -436,7 +440,7 @@ static int write(const uint16_t word, const uint8_t address) { static bool find_listen_window(bool command) { int cnt = 0; - while (cnt < EM4X70_T_WAITING_FOR_SNGLLIW) { + while (cnt < EM4X70_T_WAITING_FOR_LIW) { /* 80 ( 64 + 16 ) 80 ( 64 + 16 ) @@ -444,10 +448,10 @@ static bool find_listen_window(bool command) { 96 ( 64 + 32 ) 64 ( 32 + 16 +16 )*/ - if (check_pulse_length(get_pulse_invert_length(), 80) && - check_pulse_length(get_pulse_invert_length(), 80) && - check_pulse_length(get_pulse_length(), 96) && - check_pulse_length(get_pulse_length(), 64)) { + if (check_pulse_length(get_pulse_invert_length(), (2*EM4X70_T_TAG_FULL_PERIOD) + EM4X70_T_TAG_HALF_PERIOD) && + check_pulse_length(get_pulse_invert_length(), (2*EM4X70_T_TAG_FULL_PERIOD) + EM4X70_T_TAG_HALF_PERIOD) && + check_pulse_length(get_pulse_length(), (2*EM4X70_T_TAG_FULL_PERIOD) + EM4X70_T_TAG_FULL_PERIOD) && + check_pulse_length(get_pulse_length(), EM4X70_T_TAG_FULL_PERIOD + (2*EM4X70_T_TAG_HALF_PERIOD))) { if (command) { /* Here we are after the 64 duration edge. @@ -456,7 +460,7 @@ static bool find_listen_window(bool command) { * * I've found between 4-5 quarter periods (32-40) works best */ - WaitTicks(TICKS_PER_FC * 4 * EM4X70_T_TAG_QUARTER_PERIOD); + WaitTicks( 4 * EM4X70_T_TAG_QUARTER_PERIOD ); // Send RM Command em4x70_send_bit(0); em4x70_send_bit(0); @@ -573,7 +577,7 @@ static int em4x70_receive(uint8_t *bits) { // 4 Manchester 0's // Skip a few leading 1's as it could be noisy - WaitTicks(TICKS_PER_FC * 3 * EM4X70_T_TAG_FULL_PERIOD); + WaitTicks(6 * EM4X70_T_TAG_FULL_PERIOD); // wait until we get the transition from 1's to 0's which is 1.5 full windows int pulse_count = 0; @@ -597,7 +601,7 @@ static int em4x70_receive(uint8_t *bits) { } // identify remaining bits based on pulse lengths - // between two listen windows only pulse lengths of 1, 1.5 and 2 are possible + // between listen windows only pulse lengths of 1, 1.5 and 2 are possible while (bit_pos < EM4X70_MAX_RECEIVE_LENGTH) { if (edge) @@ -634,8 +638,8 @@ static int em4x70_receive(uint8_t *bits) { bits[bit_pos++] = 0; } - } else if ((edge && check_pulse_length(pl, 3 * EM4X70_T_TAG_FULL_PERIOD)) || - (!edge && check_pulse_length(pl, 80))) { + } else if ((edge && check_pulse_length(pl, (2*EM4X70_T_TAG_FULL_PERIOD) + EM4X70_T_TAG_FULL_PERIOD)) || + (!edge && check_pulse_length(pl, (2*EM4X70_T_TAG_FULL_PERIOD) + EM4X70_T_TAG_HALF_PERIOD))) { // LIW detected (either invert or normal) return --bit_pos; From f87aa869c6e245048be3c183b42d9ff8c1991383 Mon Sep 17 00:00:00 2001 From: Christian Molson Date: Sun, 13 Dec 2020 16:23:25 -0500 Subject: [PATCH 071/682] em4x70: clean up edge detection code --- armsrc/em4x70.c | 90 +++++++++++++++++++++---------------------------- armsrc/em4x70.h | 5 +++ 2 files changed, 44 insertions(+), 51 deletions(-) diff --git a/armsrc/em4x70.c b/armsrc/em4x70.c index 52bf21b11..1c713905c 100644 --- a/armsrc/em4x70.c +++ b/armsrc/em4x70.c @@ -130,36 +130,27 @@ static bool get_signalproperties(void) { } /** - * get_pulse_length + * get_falling_pulse_length * - * Times falling edge pulses + * Returns time between falling edge pulse in ticks */ -static uint32_t get_pulse_length(void) { +static uint32_t get_falling_pulse_length(void) { - uint8_t sample; uint32_t timeout = GetTicks() + EM4X70_T_TAG_TIMEOUT; - do { - sample = (uint8_t)AT91C_BASE_SSC->SSC_RHR; - } while (IS_HIGH(sample) && !IS_TIMEOUT(timeout)); + while (IS_HIGH(AT91C_BASE_SSC->SSC_RHR) && !IS_TIMEOUT(timeout)); if (IS_TIMEOUT(timeout)) return 0; uint32_t start_ticks = GetTicks(); - timeout = start_ticks + EM4X70_T_TAG_TIMEOUT; - do { - sample = (uint8_t)AT91C_BASE_SSC->SSC_RHR; - } while (IS_LOW(sample) && !IS_TIMEOUT(timeout)); + while (IS_LOW(AT91C_BASE_SSC->SSC_RHR) && !IS_TIMEOUT(timeout)); if (IS_TIMEOUT(timeout)) return 0; - timeout = GetTicks() + EM4X70_T_TAG_TIMEOUT; - do { - sample = (uint8_t)AT91C_BASE_SSC->SSC_RHR; - } while (IS_HIGH(sample) && !IS_TIMEOUT(timeout)); + while (IS_HIGH(AT91C_BASE_SSC->SSC_RHR) && !IS_TIMEOUT(timeout)); if (IS_TIMEOUT(timeout)) return 0; @@ -168,37 +159,27 @@ static uint32_t get_pulse_length(void) { } /** - * get_pulse_invert_length + * get_rising_pulse_length * - * Times rising edge pules - * TODO: convert to single function with get_pulse_length() + * Returns time between rising edge pulse in ticks */ -static uint32_t get_pulse_invert_length(void) { +static uint32_t get_rising_pulse_length(void) { - uint8_t sample; uint32_t timeout = GetTicks() + EM4X70_T_TAG_TIMEOUT; - do { - sample = (uint8_t)AT91C_BASE_SSC->SSC_RHR; - } while (IS_LOW(sample) && !IS_TIMEOUT(timeout)); + while (IS_LOW(AT91C_BASE_SSC->SSC_RHR) && !IS_TIMEOUT(timeout)); if (IS_TIMEOUT(timeout)) return 0; uint32_t start_ticks = GetTicks(); - timeout = start_ticks + EM4X70_T_TAG_TIMEOUT; - do { - sample = (uint8_t)AT91C_BASE_SSC->SSC_RHR; - } while (IS_HIGH(sample) && !IS_TIMEOUT(timeout)); + while (IS_HIGH(AT91C_BASE_SSC->SSC_RHR) && !IS_TIMEOUT(timeout)); if (IS_TIMEOUT(timeout)) return 0; - timeout = GetTicks() + EM4X70_T_TAG_TIMEOUT; - do { - sample = (uint8_t)AT91C_BASE_SSC->SSC_RHR; - } while (IS_LOW(sample) && !IS_TIMEOUT(timeout)); + while (IS_LOW(AT91C_BASE_SSC->SSC_RHR) && !IS_TIMEOUT(timeout)); if (IS_TIMEOUT(timeout)) return 0; @@ -207,6 +188,16 @@ static uint32_t get_pulse_invert_length(void) { } +static uint32_t get_pulse_length(edge_detection_t edge) { + + if(edge == RISING_EDGE) + return get_rising_pulse_length(); + else if(edge == FALLING_EDGE) + return get_falling_pulse_length(); + + return 0; +} + static bool check_pulse_length(uint32_t pl, uint32_t length) { // check if pulse length corresponds to given length return ((pl >= (length - EM4X70_T_TAG_TOLERANCE)) & (pl <= (length + EM4X70_T_TAG_TOLERANCE))); @@ -309,10 +300,10 @@ static bool check_ack(void) { 64 (48+16) 48 (32+16) */ - if (check_pulse_length(get_pulse_length(), 2 * EM4X70_T_TAG_FULL_PERIOD)) { + if (check_pulse_length(get_pulse_length(FALLING_EDGE), 2 * EM4X70_T_TAG_FULL_PERIOD)) { // The received signal is either ACK or NAK. - if (check_pulse_length(get_pulse_length(), 2 * EM4X70_T_TAG_FULL_PERIOD)) { + if (check_pulse_length(get_pulse_length(FALLING_EDGE), 2 * EM4X70_T_TAG_FULL_PERIOD)) { return true; } else { // It's NAK -> stop searching @@ -448,10 +439,10 @@ static bool find_listen_window(bool command) { 96 ( 64 + 32 ) 64 ( 32 + 16 +16 )*/ - if (check_pulse_length(get_pulse_invert_length(), (2*EM4X70_T_TAG_FULL_PERIOD) + EM4X70_T_TAG_HALF_PERIOD) && - check_pulse_length(get_pulse_invert_length(), (2*EM4X70_T_TAG_FULL_PERIOD) + EM4X70_T_TAG_HALF_PERIOD) && - check_pulse_length(get_pulse_length(), (2*EM4X70_T_TAG_FULL_PERIOD) + EM4X70_T_TAG_FULL_PERIOD) && - check_pulse_length(get_pulse_length(), EM4X70_T_TAG_FULL_PERIOD + (2*EM4X70_T_TAG_HALF_PERIOD))) { + if (check_pulse_length(get_pulse_length(RISING_EDGE), (2*EM4X70_T_TAG_FULL_PERIOD) + EM4X70_T_TAG_HALF_PERIOD) && + check_pulse_length(get_pulse_length(RISING_EDGE), (2*EM4X70_T_TAG_FULL_PERIOD) + EM4X70_T_TAG_HALF_PERIOD) && + check_pulse_length(get_pulse_length(FALLING_EDGE), (2*EM4X70_T_TAG_FULL_PERIOD) + EM4X70_T_TAG_FULL_PERIOD) && + check_pulse_length(get_pulse_length(FALLING_EDGE), EM4X70_T_TAG_FULL_PERIOD + (2*EM4X70_T_TAG_HALF_PERIOD))) { if (command) { /* Here we are after the 64 duration edge. @@ -569,7 +560,7 @@ static int em4x70_receive(uint8_t *bits) { uint32_t pl; int bit_pos = 0; - uint8_t edge = 0; + edge_detection_t edge = RISING_EDGE; bool foundheader = false; // Read out the header @@ -582,7 +573,7 @@ static int em4x70_receive(uint8_t *bits) { // wait until we get the transition from 1's to 0's which is 1.5 full windows int pulse_count = 0; while (pulse_count < 12) { - pl = get_pulse_invert_length(); + pl = get_pulse_length(edge); pulse_count++; if (check_pulse_length(pl, 3 * EM4X70_T_TAG_HALF_PERIOD)) { foundheader = true; @@ -597,40 +588,37 @@ static int em4x70_receive(uint8_t *bits) { // Skip next 3 0's, header check consumes the first 0 for (int i = 0; i < 3; i++) { - get_pulse_invert_length(); + get_pulse_length(edge); } // identify remaining bits based on pulse lengths // between listen windows only pulse lengths of 1, 1.5 and 2 are possible while (bit_pos < EM4X70_MAX_RECEIVE_LENGTH) { - if (edge) - pl = get_pulse_length(); - else - pl = get_pulse_invert_length(); + pl = get_pulse_length(edge); if (check_pulse_length(pl, EM4X70_T_TAG_FULL_PERIOD)) { // pulse length = 1 - bits[bit_pos++] = edge; + bits[bit_pos++] = edge == FALLING_EDGE ? 1 : 0; } else if (check_pulse_length(pl, 3 * EM4X70_T_TAG_HALF_PERIOD)) { // pulse length = 1.5 -> flip edge detection - if (edge) { + if (edge == FALLING_EDGE) { bits[bit_pos++] = 0; bits[bit_pos++] = 0; - edge = 0; + edge = RISING_EDGE; } else { bits[bit_pos++] = 1; bits[bit_pos++] = 1; - edge = 1; + edge = FALLING_EDGE; } } else if (check_pulse_length(pl, 2 * EM4X70_T_TAG_FULL_PERIOD)) { // pulse length of 2 - if (edge) { + if (edge == FALLING_EDGE) { bits[bit_pos++] = 0; bits[bit_pos++] = 1; } else { @@ -638,8 +626,8 @@ static int em4x70_receive(uint8_t *bits) { bits[bit_pos++] = 0; } - } else if ((edge && check_pulse_length(pl, (2*EM4X70_T_TAG_FULL_PERIOD) + EM4X70_T_TAG_FULL_PERIOD)) || - (!edge && check_pulse_length(pl, (2*EM4X70_T_TAG_FULL_PERIOD) + EM4X70_T_TAG_HALF_PERIOD))) { + } else if (((edge == FALLING_EDGE) && check_pulse_length(pl, (2*EM4X70_T_TAG_FULL_PERIOD) + EM4X70_T_TAG_FULL_PERIOD)) || + ((edge == RISING_EDGE) && check_pulse_length(pl, (2*EM4X70_T_TAG_FULL_PERIOD) + EM4X70_T_TAG_HALF_PERIOD))) { // LIW detected (either invert or normal) return --bit_pos; diff --git a/armsrc/em4x70.h b/armsrc/em4x70.h index 17ac243ae..7331a2201 100644 --- a/armsrc/em4x70.h +++ b/armsrc/em4x70.h @@ -17,6 +17,11 @@ typedef struct { uint8_t data[32]; } em4x70_tag_t; +typedef enum { + RISING_EDGE, + FALLING_EDGE +}edge_detection_t; + void em4x70_info(em4x70_data_t *etd); void em4x70_write(em4x70_data_t *etd); void em4x70_unlock(em4x70_data_t *etd); From a2c21f1d07110ca9551444257389814cd668602b Mon Sep 17 00:00:00 2001 From: Christian Molson Date: Sun, 13 Dec 2020 16:40:27 -0500 Subject: [PATCH 072/682] em4x70: fix function names --- armsrc/em4x70.c | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/armsrc/em4x70.c b/armsrc/em4x70.c index 1c713905c..71f9cb6b7 100644 --- a/armsrc/em4x70.c +++ b/armsrc/em4x70.c @@ -80,7 +80,7 @@ static void init_tag(void) { memset(tag.data, 0x00, sizeof(tag.data) / sizeof(tag.data[0])); } -static void EM4170_setup_read(void) { +static void em4x70_setup_read(void) { FpgaDownloadAndGo(FPGA_BITSTREAM_LF); FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_ADC | FPGA_LF_ADC_READER_FIELD); @@ -550,7 +550,7 @@ static bool em4x70_read_um2(void) { } -static bool find_EM4X70_Tag(void) { +static bool find_em4x70_Tag(void) { // function is used to check wether a tag on the proxmark is an // EM4170 tag or not -> speed up "lf search" process return find_listen_window(false); @@ -646,10 +646,10 @@ void em4x70_info(em4x70_data_t *etd) { command_parity = etd->parity; init_tag(); - EM4170_setup_read(); + em4x70_setup_read(); // Find the Tag - if (get_signalproperties() && find_EM4X70_Tag()) { + if (get_signalproperties() && find_em4x70_Tag()) { // Read ID, UM1 and UM2 status = em4x70_read_id() && em4x70_read_um1() && em4x70_read_um2(); } @@ -666,10 +666,10 @@ void em4x70_write(em4x70_data_t *etd) { command_parity = etd->parity; init_tag(); - EM4170_setup_read(); + em4x70_setup_read(); // Find the Tag - if (get_signalproperties() && find_EM4X70_Tag()) { + if (get_signalproperties() && find_em4x70_Tag()) { // Write status = write(etd->word, etd->address) == PM3_SUCCESS; @@ -695,10 +695,10 @@ void em4x70_unlock(em4x70_data_t *etd) { command_parity = etd->parity; init_tag(); - EM4170_setup_read(); + em4x70_setup_read(); // Find the Tag - if (get_signalproperties() && find_EM4X70_Tag()) { + if (get_signalproperties() && find_em4x70_Tag()) { // Read ID (required for send_pin command) if (em4x70_read_id()) { @@ -729,10 +729,10 @@ void em4x70_auth(em4x70_data_t *etd) { command_parity = etd->parity; init_tag(); - EM4170_setup_read(); + em4x70_setup_read(); // Find the Tag - if (get_signalproperties() && find_EM4X70_Tag()) { + if (get_signalproperties() && find_em4x70_Tag()) { // Authenticate and get tag response status = authenticate(etd->rnd, etd->frnd, response) == PM3_SUCCESS; From afbef5ba73267baaf98a7028610955caf88a3fb2 Mon Sep 17 00:00:00 2001 From: Christian Molson Date: Mon, 14 Dec 2020 00:38:41 -0500 Subject: [PATCH 073/682] em4x70: clean up check_ack function --- armsrc/em4x70.c | 33 ++++++++++----------------------- 1 file changed, 10 insertions(+), 23 deletions(-) diff --git a/armsrc/em4x70.c b/armsrc/em4x70.c index 71f9cb6b7..ad11e8f19 100644 --- a/armsrc/em4x70.c +++ b/armsrc/em4x70.c @@ -287,30 +287,17 @@ static void em4x70_send_word(const uint16_t word) { } static bool check_ack(void) { - // returns true if signal structue corresponds to ACK, anything else is // counted as NAK (-> false) - uint32_t start_ticks = GetTicks(); - while (TICKS_ELAPSED(start_ticks) < (4 * EM4X70_T_TAG_FULL_PERIOD)) { - /* - ACK - 64 (48+16) - 64 (48+16) - NACK - 64 (48+16) - 48 (32+16) - */ - if (check_pulse_length(get_pulse_length(FALLING_EDGE), 2 * EM4X70_T_TAG_FULL_PERIOD)) { - - // The received signal is either ACK or NAK. - if (check_pulse_length(get_pulse_length(FALLING_EDGE), 2 * EM4X70_T_TAG_FULL_PERIOD)) { - return true; - } else { - // It's NAK -> stop searching - break; - } - } - } + // ACK 64 + 64 + // NACK 64 + 48 + if (check_pulse_length(get_pulse_length(FALLING_EDGE), 2 * EM4X70_T_TAG_FULL_PERIOD) && + check_pulse_length(get_pulse_length(FALLING_EDGE), 2 * EM4X70_T_TAG_FULL_PERIOD)) { + // ACK + return true; + } + + // Othewise it was a NACK or Listen Window return false; } @@ -415,7 +402,7 @@ static int write(const uint16_t word, const uint8_t address) { // look for ACK sequence if (check_ack()) { - // now EM4x70 needs T0 * EM4X70_T_TAG_TWEE (EEPROM write time) + // now EM4x70 needs EM4X70_T_TAG_TWEE (EEPROM write time) // for saving data and should return with ACK WaitTicks(EM4X70_T_TAG_WEE); if (check_ack()) { From ff762027d960e19bc44824d873f8c22d199d49d1 Mon Sep 17 00:00:00 2001 From: Christian Molson Date: Tue, 15 Dec 2020 08:57:11 -0500 Subject: [PATCH 074/682] em4x70: Update receive function with expected bits to receive. --- armsrc/em4x70.c | 57 ++++++++++++++++++++++++------------------------- 1 file changed, 28 insertions(+), 29 deletions(-) diff --git a/armsrc/em4x70.c b/armsrc/em4x70.c index ad11e8f19..61b7e76cb 100644 --- a/armsrc/em4x70.c +++ b/armsrc/em4x70.c @@ -42,7 +42,7 @@ static bool command_parity = true; #define EM4X70_T_TAG_TIMEOUT (4 * EM4X70_T_TAG_FULL_PERIOD) // Timeout if we ever get a pulse longer than this #define EM4X70_T_WAITING_FOR_LIW 50 // Pulses to wait for listen window - +#define EM4X70_T_READ_HEADER_LEN 16 // Read header length (16 bit periods) #define EM4X70_COMMAND_RETRIES 5 // Attempts to send/read command #define EM4X70_MAX_RECEIVE_LENGTH 96 // Maximum bits to expect from any command @@ -73,7 +73,7 @@ static bool command_parity = true; static uint8_t bits2byte(const uint8_t *bits, int length); static void bits2bytes(const uint8_t *bits, int length, uint8_t *out); -static int em4x70_receive(uint8_t *bits); +static int em4x70_receive(uint8_t *bits, size_t length); static bool find_listen_window(bool command); static void init_tag(void) { @@ -329,8 +329,8 @@ static int authenticate(const uint8_t *rnd, const uint8_t *frnd, uint8_t *respon // Receive header, 20-bit g(RN), LIW uint8_t grnd[EM4X70_MAX_RECEIVE_LENGTH] = {0}; - int num = em4x70_receive(grnd); - if (num < 10) { + int num = em4x70_receive(grnd, 20); + if (num < 20) { Dbprintf("Auth failed"); return PM3_ESOFT; } @@ -369,7 +369,7 @@ static int send_pin(const uint32_t pin) { WaitTicks(EM4X70_T_TAG_WEE); // <-- Receive header + ID uint8_t tag_id[EM4X70_MAX_RECEIVE_LENGTH]; - int num = em4x70_receive(tag_id); + int num = em4x70_receive(tag_id, 32); if (num < 32) { Dbprintf("Invalid ID Received"); return PM3_ESOFT; @@ -480,7 +480,7 @@ static uint8_t bits2byte(const uint8_t *bits, int length) { return byte; } -static bool send_command_and_read(uint8_t command, uint8_t resp_len_bits, uint8_t *out_bytes) { +static bool send_command_and_read(uint8_t command, uint8_t *bytes, size_t length) { int retries = EM4X70_COMMAND_RETRIES; while (retries) { @@ -488,13 +488,14 @@ static bool send_command_and_read(uint8_t command, uint8_t resp_len_bits, uint8_ if (find_listen_window(true)) { uint8_t bits[EM4X70_MAX_RECEIVE_LENGTH] = {0}; + size_t out_length_bits = length * 8; em4x70_send_nibble(command, command_parity); - int len = em4x70_receive(bits); - if (len < resp_len_bits) { - Dbprintf("Invalid data received length: %d", len); + int len = em4x70_receive(bits, out_length_bits); + if (len < out_length_bits) { + Dbprintf("Invalid data received length: %d, expected %d", len, out_length_bits); return false; } - bits2bytes(bits, len, out_bytes); + bits2bytes(bits, len, bytes); return true; } } @@ -510,7 +511,7 @@ static bool send_command_and_read(uint8_t command, uint8_t resp_len_bits, uint8_ */ static bool em4x70_read_id(void) { - return send_command_and_read(EM4X70_COMMAND_ID, 32, &tag.data[4]); + return send_command_and_read(EM4X70_COMMAND_ID, &tag.data[4], 4); } @@ -521,7 +522,7 @@ static bool em4x70_read_id(void) { */ static bool em4x70_read_um1(void) { - return send_command_and_read(EM4X70_COMMAND_UM1, 32, &tag.data[0]); + return send_command_and_read(EM4X70_COMMAND_UM1, &tag.data[0], 4); } @@ -533,7 +534,7 @@ static bool em4x70_read_um1(void) { */ static bool em4x70_read_um2(void) { - return send_command_and_read(EM4X70_COMMAND_UM2, 64, &tag.data[24]); + return send_command_and_read(EM4X70_COMMAND_UM2, &tag.data[24], 8); } @@ -543,7 +544,7 @@ static bool find_em4x70_Tag(void) { return find_listen_window(false); } -static int em4x70_receive(uint8_t *bits) { +static int em4x70_receive(uint8_t *bits, size_t length) { uint32_t pl; int bit_pos = 0; @@ -558,10 +559,8 @@ static int em4x70_receive(uint8_t *bits) { WaitTicks(6 * EM4X70_T_TAG_FULL_PERIOD); // wait until we get the transition from 1's to 0's which is 1.5 full windows - int pulse_count = 0; - while (pulse_count < 12) { + for(int i = 0; i < EM4X70_T_READ_HEADER_LEN; i++) { pl = get_pulse_length(edge); - pulse_count++; if (check_pulse_length(pl, 3 * EM4X70_T_TAG_HALF_PERIOD)) { foundheader = true; break; @@ -575,23 +574,26 @@ static int em4x70_receive(uint8_t *bits) { // Skip next 3 0's, header check consumes the first 0 for (int i = 0; i < 3; i++) { - get_pulse_length(edge); + // If pulse length is not 1 bit, then abort early + if(!check_pulse_length(get_pulse_length(edge), EM4X70_T_TAG_FULL_PERIOD)) { + return 0; + } } // identify remaining bits based on pulse lengths // between listen windows only pulse lengths of 1, 1.5 and 2 are possible - while (bit_pos < EM4X70_MAX_RECEIVE_LENGTH) { + while (bit_pos < length) { pl = get_pulse_length(edge); if (check_pulse_length(pl, EM4X70_T_TAG_FULL_PERIOD)) { - // pulse length = 1 + // pulse length 1 -> assign bit bits[bit_pos++] = edge == FALLING_EDGE ? 1 : 0; } else if (check_pulse_length(pl, 3 * EM4X70_T_TAG_HALF_PERIOD)) { - // pulse length = 1.5 -> flip edge detection + // pulse length 1.5 -> 2 bits + flip edge detection if (edge == FALLING_EDGE) { bits[bit_pos++] = 0; bits[bit_pos++] = 0; @@ -604,7 +606,7 @@ static int em4x70_receive(uint8_t *bits) { } else if (check_pulse_length(pl, 2 * EM4X70_T_TAG_FULL_PERIOD)) { - // pulse length of 2 + // pulse length of 2 -> two bits if (edge == FALLING_EDGE) { bits[bit_pos++] = 0; bits[bit_pos++] = 1; @@ -613,16 +615,13 @@ static int em4x70_receive(uint8_t *bits) { bits[bit_pos++] = 0; } - } else if (((edge == FALLING_EDGE) && check_pulse_length(pl, (2*EM4X70_T_TAG_FULL_PERIOD) + EM4X70_T_TAG_FULL_PERIOD)) || - ((edge == RISING_EDGE) && check_pulse_length(pl, (2*EM4X70_T_TAG_FULL_PERIOD) + EM4X70_T_TAG_HALF_PERIOD))) { - - // LIW detected (either invert or normal) - return --bit_pos; + } else { + // Listen Window, or invalid bit + break; } } - // Should not get here - return --bit_pos; + return bit_pos; } void em4x70_info(em4x70_data_t *etd) { From dc35f79bd2542d5e7712b7e26068423c0599a86e Mon Sep 17 00:00:00 2001 From: Christian Molson Date: Tue, 15 Dec 2020 11:22:43 -0500 Subject: [PATCH 075/682] em4x70: Add write pin convenience function to write and verify a new pin --- armsrc/appmain.c | 4 +++ armsrc/em4x70.c | 49 ++++++++++++++++++++++++++--- armsrc/em4x70.h | 1 + client/src/cmdlfem4x70.c | 68 +++++++++++++++++++++++++++++++++++++--- client/src/cmdlfem4x70.h | 1 + include/em4x70.h | 4 +++ include/pm3_cmd.h | 1 + 7 files changed, 118 insertions(+), 10 deletions(-) diff --git a/armsrc/appmain.c b/armsrc/appmain.c index 57c2f36c7..af6e6c956 100644 --- a/armsrc/appmain.c +++ b/armsrc/appmain.c @@ -1182,6 +1182,10 @@ static void PacketReceived(PacketCommandNG *packet) { em4x70_auth((em4x70_data_t *)packet->data.asBytes); break; } + case CMD_LF_EM4X70_WRITEPIN: { + em4x70_write_pin((em4x70_data_t *)packet->data.asBytes); + break; + } #endif #ifdef WITH_ISO15693 diff --git a/armsrc/em4x70.c b/armsrc/em4x70.c index 61b7e76cb..758b6e08e 100644 --- a/armsrc/em4x70.c +++ b/armsrc/em4x70.c @@ -538,7 +538,7 @@ static bool em4x70_read_um2(void) { } -static bool find_em4x70_Tag(void) { +static bool find_em4x70_tag(void) { // function is used to check wether a tag on the proxmark is an // EM4170 tag or not -> speed up "lf search" process return find_listen_window(false); @@ -635,7 +635,7 @@ void em4x70_info(em4x70_data_t *etd) { em4x70_setup_read(); // Find the Tag - if (get_signalproperties() && find_em4x70_Tag()) { + if (get_signalproperties() && find_em4x70_tag()) { // Read ID, UM1 and UM2 status = em4x70_read_id() && em4x70_read_um1() && em4x70_read_um2(); } @@ -655,7 +655,7 @@ void em4x70_write(em4x70_data_t *etd) { em4x70_setup_read(); // Find the Tag - if (get_signalproperties() && find_em4x70_Tag()) { + if (get_signalproperties() && find_em4x70_tag()) { // Write status = write(etd->word, etd->address) == PM3_SUCCESS; @@ -684,7 +684,7 @@ void em4x70_unlock(em4x70_data_t *etd) { em4x70_setup_read(); // Find the Tag - if (get_signalproperties() && find_em4x70_Tag()) { + if (get_signalproperties() && find_em4x70_tag()) { // Read ID (required for send_pin command) if (em4x70_read_id()) { @@ -718,7 +718,7 @@ void em4x70_auth(em4x70_data_t *etd) { em4x70_setup_read(); // Find the Tag - if (get_signalproperties() && find_em4x70_Tag()) { + if (get_signalproperties() && find_em4x70_tag()) { // Authenticate and get tag response status = authenticate(etd->rnd, etd->frnd, response) == PM3_SUCCESS; @@ -729,3 +729,42 @@ void em4x70_auth(em4x70_data_t *etd) { reply_ng(CMD_LF_EM4X70_AUTH, status, response, sizeof(response)); } +void em4x70_write_pin(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 (required for send_pin command) + if (em4x70_read_id()) { + + // Write new PIN + if( (write( etd->pin & 0xFFFF, EM4X70_PIN_WORD_UPPER) == PM3_SUCCESS) && + (write((etd->pin >> 16) & 0xFFFF, EM4X70_PIN_WORD_LOWER) == PM3_SUCCESS)) { + + // Now Try to authenticate using the new PIN + + // Send PIN + status = send_pin(etd->pin) == PM3_SUCCESS; + + // If the write succeeded, read the rest of the tag + if (status) { + // Read Tag + // ID doesn't change + em4x70_read_um1(); + em4x70_read_um2(); + } + } + } + } + + StopTicks(); + lf_finalize(); + reply_ng(CMD_LF_EM4X70_WRITEPIN, status, tag.data, sizeof(tag.data)); +} diff --git a/armsrc/em4x70.h b/armsrc/em4x70.h index 7331a2201..41bfe824d 100644 --- a/armsrc/em4x70.h +++ b/armsrc/em4x70.h @@ -26,5 +26,6 @@ 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); +void em4x70_write_pin(em4x70_data_t *etd); #endif /* EM4x70_H */ diff --git a/client/src/cmdlfem4x70.c b/client/src/cmdlfem4x70.c index 05d8d52b4..b2ccb3a0e 100644 --- a/client/src/cmdlfem4x70.c +++ b/client/src/cmdlfem4x70.c @@ -338,12 +338,70 @@ int CmdEM4x70Auth(const char *Cmd) { return PM3_ESOFT; } +int CmdEM4x70WritePIN(const char *Cmd) { + + // send pin code to device, unlocking it for writing + em4x70_data_t etd = {0}; + + CLIParserContext *ctx; + + CLIParserInit(&ctx, "lf em 4x70 writepin", + "Write PIN\n", + "lf em 4x70 writepin -p 11223344 -> Write PIN\n" + "lf em 4x70 writepin -p 11223344 --par -> Write PIN using parity commands\n" + ); + + void *argtable[] = { + arg_param_begin, + arg_lit0(NULL, "par", "Add parity bit when sending commands"), + arg_str1("p", "pin", "", "pin, 4 bytes"), + arg_param_end + }; + + CLIExecWithReturn(ctx, Cmd, argtable, true); + + etd.parity = arg_get_lit(ctx, 1); + + int pin_len = 0; + uint8_t pin[4] = {0x0}; + + CLIGetHexWithReturn(ctx, 2, pin, &pin_len); + + CLIParserFree(ctx); + + if (pin_len != 4) { + PrintAndLogEx(FAILED, "PIN length must be 4 bytes instead of %d", pin_len); + return PM3_EINVARG; + } + + etd.pin = BYTES2UINT32(pin); + + clearCommandBuffer(); + SendCommandNG(CMD_LF_EM4X70_WRITEPIN, (uint8_t *)&etd, sizeof(etd)); + + PacketResponseNG resp; + if (!WaitForResponseTimeout(CMD_LF_EM4X70_WRITEPIN, &resp, TIMEOUT)) { + PrintAndLogEx(WARNING, "Timeout while waiting for reply."); + return PM3_ETIMEOUT; + } + + if (resp.status) { + print_info_result(resp.data.asBytes); + PrintAndLogEx(INFO, "Writing new PIN: " _GREEN_("SUCCESS")); + return PM3_SUCCESS; + } + + PrintAndLogEx(FAILED, "Writing new PIN: " _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"}, + {"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"}, + {"writepin", CmdEM4x70WritePIN, IfPm3EM4x70, "Write PIN"}, {NULL, NULL, NULL, NULL} }; diff --git a/client/src/cmdlfem4x70.h b/client/src/cmdlfem4x70.h index 755ff74d2..09a9b9361 100644 --- a/client/src/cmdlfem4x70.h +++ b/client/src/cmdlfem4x70.h @@ -21,6 +21,7 @@ int CmdEM4x70Info(const char *Cmd); int CmdEM4x70Write(const char *Cmd); int CmdEM4x70Unlock(const char *Cmd); int CmdEM4x70Auth(const char *Cmd); +int CmdEM4x70WritePIN(const char *Cmd); int em4x70_info(void); bool detect_4x70_block(void); diff --git a/include/em4x70.h b/include/em4x70.h index 0703c3900..4d08d622b 100644 --- a/include/em4x70.h +++ b/include/em4x70.h @@ -13,6 +13,10 @@ #define EM4X70_NUM_BLOCKS 16 +// Common word/block addresses +#define EM4X70_PIN_WORD_LOWER 10 +#define EM4X70_PIN_WORD_UPPER 11 + typedef struct { bool parity; diff --git a/include/pm3_cmd.h b/include/pm3_cmd.h index 95ef41ebb..0249d15a7 100644 --- a/include/pm3_cmd.h +++ b/include/pm3_cmd.h @@ -520,6 +520,7 @@ typedef struct { #define CMD_LF_EM4X70_WRITE 0x0261 #define CMD_LF_EM4X70_UNLOCK 0x0262 #define CMD_LF_EM4X70_AUTH 0x0263 +#define CMD_LF_EM4X70_WRITEPIN 0x0264 // Sampling configuration for LF reader/sniffer #define CMD_LF_SAMPLING_SET_CONFIG 0x021D #define CMD_LF_FSK_SIMULATE 0x021E From 60f36b468de51834bf8bda79fabb1ab1be17939c Mon Sep 17 00:00:00 2001 From: Christian Molson Date: Tue, 15 Dec 2020 12:32:30 -0500 Subject: [PATCH 076/682] 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 From c7e56481648ce5f13f03536fa2d9e801ba76b1de Mon Sep 17 00:00:00 2001 From: iceman1001 Date: Tue, 15 Dec 2020 21:35:21 +0100 Subject: [PATCH 077/682] maur default key --- client/dictionaries/mfdes_default_keys.dic | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/client/dictionaries/mfdes_default_keys.dic b/client/dictionaries/mfdes_default_keys.dic index 4c863c3f5..a26d13d32 100644 --- a/client/dictionaries/mfdes_default_keys.dic +++ b/client/dictionaries/mfdes_default_keys.dic @@ -8,6 +8,7 @@ 43464F494D48504E4C4359454E528841 #NHIF 6AC292FAA1315B4D858AB3A3D7D5933A 404142434445464748494a4b4c4d4e4f +3112B738D8862CCD34302EB299AAB456 # Gallagher AES (https://pastebin.com/GkbGLz8r) 00112233445566778899aabbccddeeff 2b7e151628aed2a6abf7158809cf4f3c fbeed618357133667c85e08f7236a8de @@ -43,4 +44,4 @@ eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee 404142434445464748494a4b4c4d4e4f 303132333435363738393a3b3c3d3e3f 9CABF398358405AE2F0E2B3D31C99A8A # Default key -605F5E5D5C5B5A59605F5E5D5C5B5A59 # access control \ No newline at end of file +605F5E5D5C5B5A59605F5E5D5C5B5A59 # access control From 84873aa3cfa3d31951f7a8b8ccb042d02534c8a3 Mon Sep 17 00:00:00 2001 From: Ave Date: Tue, 15 Dec 2020 17:17:54 +0300 Subject: [PATCH 078/682] emrtd: pad document number --- client/src/cmdhfemrtd.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/client/src/cmdhfemrtd.c b/client/src/cmdhfemrtd.c index ea90fa433..7637541d7 100644 --- a/client/src/cmdhfemrtd.c +++ b/client/src/cmdhfemrtd.c @@ -221,6 +221,12 @@ static void des3_decrypt_cbc(uint8_t *iv, uint8_t *key, uint8_t *input, int inpu mbedtls_des3_free(&ctx); } +static void emrtd_pad_docnum(char *input) { + for (int i = strlen(input); i < 9; i++) { + input[i] = '<'; + } +} + static int pad_block(uint8_t *input, int inputlen, uint8_t *output) { uint8_t padding[8] = {0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; @@ -834,6 +840,8 @@ int dumpHF_EMRTD(char *documentnumber, char *dob, char *expiry, bool BAC_availab bool BAC = false; bool use_14b = false; + emrtd_pad_docnum(documentnumber); + // Try to 14a SendCommandMIX(CMD_HF_ISO14443A_READER, ISO14A_CONNECT | ISO14A_NO_DISCONNECT, 0, 0, NULL, 0); PacketResponseNG resp; @@ -960,7 +968,7 @@ static int cmd_hf_emrtd_dump(const char *Cmd) { void *argtable[] = { arg_param_begin, - arg_str0("n", "documentnumber", "", "9 character document number"), + arg_str0("n", "documentnumber", "", "document number, up to 9 chars"), arg_str0("d", "dateofbirth", "", "date of birth in YYMMDD format"), arg_str0("e", "expiry", "", "expiry in YYMMDD format"), arg_param_end From ac3392402fee65bdbdd17588d1b6c5f884031fc3 Mon Sep 17 00:00:00 2001 From: Ave Date: Wed, 16 Dec 2020 22:18:14 +0300 Subject: [PATCH 079/682] emrtd: Split auth into a separate function This is done to prepare for info command --- client/src/cmdhfemrtd.c | 68 +++++++++++++++++++++++------------------ 1 file changed, 38 insertions(+), 30 deletions(-) diff --git a/client/src/cmdhfemrtd.c b/client/src/cmdhfemrtd.c index 7637541d7..2251ddac8 100644 --- a/client/src/cmdhfemrtd.c +++ b/client/src/cmdhfemrtd.c @@ -797,7 +797,7 @@ static bool emrtd_do_bac(char *documentnumber, char *dob, char *expiry, uint8_t PrintAndLogEx(ERR, "Couldn't do external authentication. Did you supply the correct MRZ info?"); return false; } - PrintAndLogEx(INFO, "External authentication successful."); + PrintAndLogEx(INFO, "External authentication with BAC successful."); uint8_t dec_output[32] = { 0x00 }; des3_decrypt_cbc(iv, kenc, response, 32, dec_output); @@ -831,14 +831,9 @@ static bool emrtd_do_bac(char *documentnumber, char *dob, char *expiry, uint8_t return true; } -int dumpHF_EMRTD(char *documentnumber, char *dob, char *expiry, bool BAC_available) { +static bool emrtd_do_auth(char *documentnumber, char *dob, char *expiry, bool BAC_available, bool *BAC, uint8_t *ssc, uint8_t *ks_enc, uint8_t *ks_mac, bool *use_14b) { uint8_t response[EMRTD_MAX_FILE_SIZE] = { 0x00 }; int resplen = 0; - uint8_t ssc[8] = { 0x00 }; - uint8_t ks_enc[16] = { 0x00 }; - uint8_t ks_mac[16] = { 0x00 }; - bool BAC = false; - bool use_14b = false; emrtd_pad_docnum(documentnumber); @@ -856,22 +851,20 @@ int dumpHF_EMRTD(char *documentnumber, char *dob, char *expiry, bool BAC_availab // If not 14a, try to 14b SendCommandMIX(CMD_HF_ISO14443B_COMMAND, ISO14B_CONNECT | ISO14B_SELECT_STD, 0, 0, NULL, 0); if (!WaitForResponseTimeout(CMD_HF_ISO14443B_COMMAND, &resp, 2500)) { - DropField(); PrintAndLogEx(INFO, "No eMRTD spotted with 14b, exiting."); - return PM3_ESOFT; + return false; } if (resp.oldarg[0] != 0) { - DropField(); PrintAndLogEx(INFO, "No eMRTD spotted with 14b, exiting."); - return PM3_ESOFT; + return false; } - use_14b = true; + *use_14b = true; } // Select and read EF_CardAccess - if (emrtd_select_file(EMRTD_P1_SELECT_BY_EF, EMRTD_EF_CARDACCESS, use_14b)) { - emrtd_read_file(response, &resplen, NULL, NULL, NULL, false, use_14b); + if (emrtd_select_file(EMRTD_P1_SELECT_BY_EF, EMRTD_EF_CARDACCESS, *use_14b)) { + emrtd_read_file(response, &resplen, NULL, NULL, NULL, false, *use_14b); PrintAndLogEx(INFO, "Read EF_CardAccess, len: %i.", resplen); PrintAndLogEx(DEBUG, "Contents (may be incomplete over 2k chars): %s", sprint_hex_inrow(response, resplen)); } else { @@ -879,46 +872,61 @@ int dumpHF_EMRTD(char *documentnumber, char *dob, char *expiry, bool BAC_availab } // Select MRTD applet - if (emrtd_select_file(EMRTD_P1_SELECT_BY_NAME, EMRTD_AID_MRTD, use_14b) == false) { + if (emrtd_select_file(EMRTD_P1_SELECT_BY_NAME, EMRTD_AID_MRTD, *use_14b) == false) { PrintAndLogEx(ERR, "Couldn't select the MRTD application."); - DropField(); - return PM3_ESOFT; + return false; } // Select EF_COM - if (emrtd_select_file(EMRTD_P1_SELECT_BY_EF, EMRTD_EF_COM, use_14b) == false) { - BAC = true; + if (emrtd_select_file(EMRTD_P1_SELECT_BY_EF, EMRTD_EF_COM, *use_14b) == false) { + *BAC = true; PrintAndLogEx(INFO, "Basic Access Control is enforced. Will attempt external authentication."); } else { - BAC = false; + *BAC = false; // Select EF_DG1 - emrtd_select_file(EMRTD_P1_SELECT_BY_EF, EMRTD_EF_DG1, use_14b); + emrtd_select_file(EMRTD_P1_SELECT_BY_EF, EMRTD_EF_DG1, *use_14b); - if (emrtd_read_file(response, &resplen, NULL, NULL, NULL, false, use_14b) == false) { - BAC = true; + if (emrtd_read_file(response, &resplen, NULL, NULL, NULL, false, *use_14b) == false) { + *BAC = true; PrintAndLogEx(INFO, "Basic Access Control is enforced. Will attempt external authentication."); } else { - BAC = false; + *BAC = false; PrintAndLogEx(INFO, "EF_DG1: %s", sprint_hex(response, resplen)); } } // Do Basic Access Aontrol - if (BAC) { + if (*BAC) { // If BAC isn't available, exit out and warn user. if (!BAC_available) { PrintAndLogEx(ERR, "This eMRTD enforces Basic Access Control, but you didn't supplied MRZ data. Cannot proceed."); PrintAndLogEx(HINT, "Check out hf emrtd dump --help, supply data with -n -d and -e."); - DropField(); - return PM3_ESOFT; + return false; } - if (emrtd_do_bac(documentnumber, dob, expiry, ssc, ks_enc, ks_mac, use_14b) == false) { - DropField(); - return PM3_ESOFT; + if (emrtd_do_bac(documentnumber, dob, expiry, ssc, ks_enc, ks_mac, *use_14b) == false) { + return false; } } + return true; +} + +int dumpHF_EMRTD(char *documentnumber, char *dob, char *expiry, bool BAC_available) { + uint8_t response[EMRTD_MAX_FILE_SIZE] = { 0x00 }; + int resplen = 0; + uint8_t ssc[8] = { 0x00 }; + uint8_t ks_enc[16] = { 0x00 }; + uint8_t ks_mac[16] = { 0x00 }; + bool BAC = false; + bool use_14b = false; + + // Select and authenticate with the eMRTD + if (emrtd_do_auth(documentnumber, dob, expiry, BAC_available, &BAC, ssc, ks_enc, ks_mac, &use_14b) == false) { + DropField(); + return PM3_ESOFT; + } + // Select EF_COM if (emrtd_select_and_read(response, &resplen, EMRTD_EF_COM, ks_enc, ks_mac, ssc, BAC, use_14b) == false) { PrintAndLogEx(ERR, "Failed to read EF_COM."); From daaa3578ecb247a77385bf3d09e7bee713187d40 Mon Sep 17 00:00:00 2001 From: tharexde Date: Wed, 16 Dec 2020 20:44:04 +0100 Subject: [PATCH 080/682] replaced hardcoded values --- armsrc/em4x50.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/armsrc/em4x50.c b/armsrc/em4x50.c index 36923b6a5..a73d8c5dc 100644 --- a/armsrc/em4x50.c +++ b/armsrc/em4x50.c @@ -45,6 +45,7 @@ #define EM4X50_TAG_TOLERANCE 8 #define EM4X50_TAG_WORD 45 +#define EM4X50_TAG_MAX_NO_BYTES 136 #define EM4X50_COMMAND_LOGIN 0x01 #define EM4X50_COMMAND_RESET 0x80 @@ -1015,8 +1016,7 @@ void em4x50_read(em4x50_data_t *etd) { LOW(GPIO_SSC_DOUT); lf_finalize(); - // iceman: this hardcoded 136 value.... - reply_ng(CMD_LF_EM4X50_READ, status, (uint8_t *)words, 136); + reply_ng(CMD_LF_EM4X50_READ, status, (uint8_t *)words, EM4X50_TAG_MAX_NO_BYTES); } // collects as much information as possible via selective read mode @@ -1041,8 +1041,7 @@ void em4x50_info(em4x50_data_t *etd) { lf_finalize(); - // iceman: this hardcoded 136 value.... - reply_ng(CMD_LF_EM4X50_INFO, status, (uint8_t *)words, 136); + reply_ng(CMD_LF_EM4X50_INFO, status, (uint8_t *)words, EM4X50_TAG_MAX_NO_BYTES); } // reads data that tag transmits "voluntarily" -> standard read mode @@ -1193,7 +1192,7 @@ void em4x50_write(em4x50_data_t *etd) { } lf_finalize(); - reply_ng(CMD_LF_EM4X50_WRITE, status, (uint8_t *)words, 136); + reply_ng(CMD_LF_EM4X50_WRITE, status, (uint8_t *)words, EM4X50_TAG_MAX_NO_BYTES); } // simple change of password From 503e48d409e8dc353cc65a55f0acdf07d49fa4da Mon Sep 17 00:00:00 2001 From: Ave Date: Wed, 16 Dec 2020 23:53:40 +0300 Subject: [PATCH 081/682] emrtd: Start work on the hf emrtd info command --- client/src/cmdhfemrtd.c | 69 ++++++++++++++++++++++++++++++++++++++++- client/src/cmdhfemrtd.h | 1 + 2 files changed, 69 insertions(+), 1 deletion(-) diff --git a/client/src/cmdhfemrtd.c b/client/src/cmdhfemrtd.c index 2251ddac8..f0f238615 100644 --- a/client/src/cmdhfemrtd.c +++ b/client/src/cmdhfemrtd.c @@ -899,7 +899,7 @@ static bool emrtd_do_auth(char *documentnumber, char *dob, char *expiry, bool BA if (*BAC) { // If BAC isn't available, exit out and warn user. if (!BAC_available) { - PrintAndLogEx(ERR, "This eMRTD enforces Basic Access Control, but you didn't supplied MRZ data. Cannot proceed."); + PrintAndLogEx(ERR, "This eMRTD enforces Basic Access Control, but you didn't supply MRZ data. Cannot proceed."); PrintAndLogEx(HINT, "Check out hf emrtd dump --help, supply data with -n -d and -e."); return false; } @@ -967,6 +967,38 @@ int dumpHF_EMRTD(char *documentnumber, char *dob, char *expiry, bool BAC_availab return PM3_SUCCESS; } +int infoHF_EMRTD(char *documentnumber, char *dob, char *expiry, bool BAC_available) { + // TODO: support just loading a dump file + uint8_t response[EMRTD_MAX_FILE_SIZE] = { 0x00 }; + int resplen = 0; + uint8_t ssc[8] = { 0x00 }; + uint8_t ks_enc[16] = { 0x00 }; + uint8_t ks_mac[16] = { 0x00 }; + bool BAC = false; + bool use_14b = false; + + // Select and authenticate with the eMRTD + bool auth_result = emrtd_do_auth(documentnumber, dob, expiry, BAC_available, &BAC, ssc, ks_enc, ks_mac, &use_14b); + PrintAndLogEx(SUCCESS, "Communication standard: %s", use_14b ? _YELLOW_("ISO/IEC 14443(B)") : _YELLOW_("ISO/IEC 14443(A)")); + PrintAndLogEx(SUCCESS, "BAC: %s", BAC ? _GREEN_("Enforced") : _RED_("Not enforced")); + PrintAndLogEx(SUCCESS, "Authentication result: %s", auth_result ? _GREEN_("Successful") : _RED_("Failed")); + + if (!auth_result) { + DropField(); + return PM3_ESOFT; + } + + // Select EF_DG1 + if (emrtd_select_and_read(response, &resplen, EMRTD_EF_DG1, ks_enc, ks_mac, ssc, BAC, use_14b) == false) { + PrintAndLogEx(ERR, "Failed to read EF_DG1."); + DropField(); + return PM3_ESOFT; + } + + DropField(); + return PM3_SUCCESS; +} + static int cmd_hf_emrtd_dump(const char *Cmd) { CLIParserContext *ctx; CLIParserInit(&ctx, "hf emrtd dump", @@ -1001,6 +1033,40 @@ static int cmd_hf_emrtd_dump(const char *Cmd) { return dumpHF_EMRTD((char *)docnum, (char *)dob, (char *)expiry, BAC); } +static int cmd_hf_emrtd_info(const char *Cmd) { + CLIParserContext *ctx; + CLIParserInit(&ctx, "hf emrtd info", + "Display info about an eMRTD", + "hf emrtd info" + ); + + void *argtable[] = { + arg_param_begin, + arg_str0("n", "documentnumber", "", "document number, up to 9 chars"), + arg_str0("d", "dateofbirth", "", "date of birth in YYMMDD format"), + arg_str0("e", "expiry", "", "expiry in YYMMDD format"), + arg_param_end + }; + CLIExecWithReturn(ctx, Cmd, argtable, true); + + uint8_t docnum[10] = { 0x00 }; + uint8_t dob[7] = { 0x00 }; + uint8_t expiry[7] = { 0x00 }; + bool BAC = true; + int slen = 0; // unused + // Go through all args, if even one isn't supplied, mark BAC as unavailable + if (CLIParamStrToBuf(arg_get_str(ctx, 1), docnum, 9, &slen) != 0 || slen == 0) { + BAC = false; + } else if (CLIParamStrToBuf(arg_get_str(ctx, 2), dob, 6, &slen) != 0 || slen == 0) { + BAC = false; + } else if (CLIParamStrToBuf(arg_get_str(ctx, 3), expiry, 6, &slen) != 0 || slen == 0) { + BAC = false; + } + + CLIParserFree(ctx); + return infoHF_EMRTD((char *)docnum, (char *)dob, (char *)expiry, BAC); +} + static int cmd_hf_emrtd_list(const char *Cmd) { char args[128] = {0}; if (strlen(Cmd) == 0) { @@ -1014,6 +1080,7 @@ static int cmd_hf_emrtd_list(const char *Cmd) { static command_t CommandTable[] = { {"help", CmdHelp, AlwaysAvailable, "This help"}, {"dump", cmd_hf_emrtd_dump, IfPm3Iso14443, "Dump eMRTD files to binary files"}, + {"info", cmd_hf_emrtd_info, IfPm3Iso14443, "Display info about an eMRTD"}, {"list", cmd_hf_emrtd_list, AlwaysAvailable, "List ISO 14443A/7816 history"}, {NULL, NULL, NULL, NULL} }; diff --git a/client/src/cmdhfemrtd.h b/client/src/cmdhfemrtd.h index 84500fc8b..f19a71ac0 100644 --- a/client/src/cmdhfemrtd.h +++ b/client/src/cmdhfemrtd.h @@ -16,4 +16,5 @@ int CmdHFeMRTD(const char *Cmd); int dumpHF_EMRTD(char *documentnumber, char *dob, char *expiry, bool BAC_available); +int infoHF_EMRTD(char *documentnumber, char *dob, char *expiry, bool BAC_available); #endif From 4b9ffef63a30751d329277584a5e535ef5a2d2bc Mon Sep 17 00:00:00 2001 From: iceman1001 Date: Thu, 17 Dec 2020 00:00:26 +0100 Subject: [PATCH 082/682] change 14b apdu - longer timeout, emrt now autopad too short document numbers --- client/src/cmdhf14b.c | 3 +- client/src/cmdhfemrtd.c | 61 +++++++++++++++++++++++------------------ 2 files changed, 36 insertions(+), 28 deletions(-) diff --git a/client/src/cmdhf14b.c b/client/src/cmdhf14b.c index eb1a4f67a..e21509fe8 100644 --- a/client/src/cmdhf14b.c +++ b/client/src/cmdhf14b.c @@ -26,6 +26,7 @@ #include "mifare/ndef.h" // NDEFRecordsDecodeAndPrint #define TIMEOUT 2000 +#define APDU_TIMEOUT 4000 // iso14b apdu input frame length static uint16_t apdu_frame_length = 0; @@ -1438,7 +1439,7 @@ static int handle_14b_apdu(bool chainingin, uint8_t *datain, int datainlen, bool SendCommandMIX(CMD_HF_ISO14443B_COMMAND, ISO14B_APDU | flags, 0, 0, NULL, 0); PacketResponseNG resp; - if (WaitForResponseTimeout(CMD_HF_ISO14443B_COMMAND, &resp, TIMEOUT)) { + if (WaitForResponseTimeout(CMD_HF_ISO14443B_COMMAND, &resp, APDU_TIMEOUT)) { uint8_t *recv = resp.data.asBytes; int rlen = resp.oldarg[0]; uint8_t res = resp.oldarg[1]; diff --git a/client/src/cmdhfemrtd.c b/client/src/cmdhfemrtd.c index ea90fa433..926124225 100644 --- a/client/src/cmdhfemrtd.c +++ b/client/src/cmdhfemrtd.c @@ -274,24 +274,24 @@ static void retail_mac(uint8_t *key, uint8_t *input, int inputlen, uint8_t *outp } static void emrtd_deskey(uint8_t *seed, const uint8_t *type, int length, uint8_t *dataout) { - PrintAndLogEx(DEBUG, "seed: %s", sprint_hex_inrow(seed, 16)); + PrintAndLogEx(DEBUG, "seed.............. %s", sprint_hex_inrow(seed, 16)); // combine seed and type uint8_t data[50]; memcpy(data, seed, length); memcpy(data + length, type, 4); - PrintAndLogEx(DEBUG, "data: %s", sprint_hex_inrow(data, length + 4)); + PrintAndLogEx(DEBUG, "data.............. %s", sprint_hex_inrow(data, length + 4)); // SHA1 the key unsigned char key[64]; mbedtls_sha1(data, length + 4, key); - PrintAndLogEx(DEBUG, "key: %s", sprint_hex_inrow(key, length + 4)); + PrintAndLogEx(DEBUG, "key............... %s", sprint_hex_inrow(key, length + 4)); // Set parity bits for (int i = 0; i < ((length + 4) / 8); i++) { mbedtls_des_key_set_parity(key + (i * 8)); } - PrintAndLogEx(DEBUG, "post-parity key: %s", sprint_hex_inrow(key, 20)); + PrintAndLogEx(DEBUG, "post-parity key... %s", sprint_hex_inrow(key, 20)); memcpy(dataout, &key, length); } @@ -314,9 +314,7 @@ static int emrtd_get_challenge(int length, uint8_t *dataout, int *dataoutlen, bo static int emrtd_external_authenticate(uint8_t *data, int length, uint8_t *dataout, int *dataoutlen, bool use_14b) { char cmd[100]; - sprintf(cmd, "00%s0000%02X%s%02X", EMRTD_EXTERNAL_AUTHENTICATE, length, sprint_hex_inrow(data, length), length); - return emrtd_exchange_commands(cmd, dataout, dataoutlen, false, true, use_14b); } @@ -718,9 +716,10 @@ static bool emrtd_dump_file(uint8_t *ks_enc, uint8_t *ks_mac, uint8_t *ssc, cons static void rng(int length, uint8_t *dataout) { // Do very very secure prng operations - for (int i = 0; i < (length / 4); i++) { - num_to_bytes(prng_successor(msclock() + i, 32), 4, &dataout[i * 4]); - } + //for (int i = 0; i < (length / 4); i++) { + // num_to_bytes(prng_successor(msclock() + i, 32), 4, &dataout[i * 4]); + //} + memset(dataout, 0x00, length); } static bool emrtd_do_bac(char *documentnumber, char *dob, char *expiry, uint8_t *ssc, uint8_t *ks_enc, uint8_t *ks_mac, bool use_14b) { @@ -737,9 +736,9 @@ static bool emrtd_do_bac(char *documentnumber, char *dob, char *expiry, uint8_t rng(8, rnd_ifd); rng(16, k_ifd); - PrintAndLogEx(DEBUG, "doc: %s", documentnumber); - PrintAndLogEx(DEBUG, "dob: %s", dob); - PrintAndLogEx(DEBUG, "exp: %s", expiry); + PrintAndLogEx(DEBUG, "doc............... " _GREEN_("%s"), documentnumber); + PrintAndLogEx(DEBUG, "dob............... " _GREEN_("%s"), dob); + PrintAndLogEx(DEBUG, "exp............... " _GREEN_("%s"), expiry); char documentnumbercd = emrtd_calculate_check_digit(documentnumber); char dobcd = emrtd_calculate_check_digit(dob); @@ -747,40 +746,40 @@ static bool emrtd_do_bac(char *documentnumber, char *dob, char *expiry, uint8_t char kmrz[25]; sprintf(kmrz, "%s%i%s%i%s%i", documentnumber, documentnumbercd, dob, dobcd, expiry, expirycd); - PrintAndLogEx(DEBUG, "kmrz: %s", kmrz); + PrintAndLogEx(DEBUG, "kmrz.............. " _GREEN_("%s"), kmrz); uint8_t kseed[16] = { 0x00 }; mbedtls_sha1((unsigned char *)kmrz, strlen(kmrz), kseed); - PrintAndLogEx(DEBUG, "kseed: %s", sprint_hex_inrow(kseed, 16)); + PrintAndLogEx(DEBUG, "kseed (sha1)...... %s ", sprint_hex_inrow(kseed, 16)); emrtd_deskey(kseed, KENC_type, 16, kenc); emrtd_deskey(kseed, KMAC_type, 16, kmac); - PrintAndLogEx(DEBUG, "kenc: %s", sprint_hex_inrow(kenc, 16)); - PrintAndLogEx(DEBUG, "kmac: %s", sprint_hex_inrow(kmac, 16)); + PrintAndLogEx(DEBUG, "kenc.............. %s", sprint_hex_inrow(kenc, 16)); + PrintAndLogEx(DEBUG, "kmac.............. %s", sprint_hex_inrow(kmac, 16)); // Get Challenge if (emrtd_get_challenge(8, rnd_ic, &resplen, use_14b) == false) { PrintAndLogEx(ERR, "Couldn't get challenge."); return false; } - PrintAndLogEx(DEBUG, "rnd_ic: %s", sprint_hex_inrow(rnd_ic, 8)); + PrintAndLogEx(DEBUG, "rnd_ic............ %s", sprint_hex_inrow(rnd_ic, 8)); memcpy(S, rnd_ifd, 8); memcpy(S + 8, rnd_ic, 8); memcpy(S + 16, k_ifd, 16); - PrintAndLogEx(DEBUG, "S: %s", sprint_hex_inrow(S, 32)); + PrintAndLogEx(DEBUG, "S................. %s", sprint_hex_inrow(S, 32)); uint8_t iv[8] = { 0x00 }; uint8_t e_ifd[32] = { 0x00 }; des3_encrypt_cbc(iv, kenc, S, sizeof(S), e_ifd); - PrintAndLogEx(DEBUG, "e_ifd: %s", sprint_hex_inrow(e_ifd, 32)); + PrintAndLogEx(DEBUG, "e_ifd............. %s", sprint_hex_inrow(e_ifd, 32)); uint8_t m_ifd[8] = { 0x00 }; retail_mac(kmac, e_ifd, 32, m_ifd); - PrintAndLogEx(DEBUG, "m_ifd: %s", sprint_hex_inrow(m_ifd, 8)); + PrintAndLogEx(DEBUG, "m_ifd............. %s", sprint_hex_inrow(m_ifd, 8)); uint8_t cmd_data[40]; memcpy(cmd_data, e_ifd, 32); @@ -795,7 +794,7 @@ static bool emrtd_do_bac(char *documentnumber, char *dob, char *expiry, uint8_t uint8_t dec_output[32] = { 0x00 }; des3_decrypt_cbc(iv, kenc, response, 32, dec_output); - PrintAndLogEx(DEBUG, "dec_output: %s", sprint_hex_inrow(dec_output, 32)); + PrintAndLogEx(DEBUG, "dec_output........ %s", sprint_hex_inrow(dec_output, 32)); if (memcmp(rnd_ifd, dec_output + 8, 8) != 0) { PrintAndLogEx(ERR, "Challenge failed, rnd_ifd does not match."); @@ -809,18 +808,18 @@ static bool emrtd_do_bac(char *documentnumber, char *dob, char *expiry, uint8_t kseed[x] = k_ifd[x] ^ k_icc[x]; } - PrintAndLogEx(DEBUG, "kseed: %s", sprint_hex_inrow(kseed, 16)); + PrintAndLogEx(DEBUG, "kseed............ %s", sprint_hex_inrow(kseed, 16)); emrtd_deskey(kseed, KENC_type, 16, ks_enc); emrtd_deskey(kseed, KMAC_type, 16, ks_mac); - PrintAndLogEx(DEBUG, "ks_enc: %s", sprint_hex_inrow(ks_enc, 16)); - PrintAndLogEx(DEBUG, "ks_mac: %s", sprint_hex_inrow(ks_mac, 16)); + PrintAndLogEx(DEBUG, "ks_enc........ %s", sprint_hex_inrow(ks_enc, 16)); + PrintAndLogEx(DEBUG, "ks_mac........ %s", sprint_hex_inrow(ks_mac, 16)); memcpy(ssc, rnd_ic + 4, 4); memcpy(ssc + 4, rnd_ifd + 4, 4); - PrintAndLogEx(DEBUG, "ssc: %s", sprint_hex_inrow(ssc, 8)); + PrintAndLogEx(DEBUG, "ssc........... %s", sprint_hex_inrow(ssc, 8)); return true; } @@ -975,9 +974,17 @@ static int cmd_hf_emrtd_dump(const char *Cmd) { // Go through all args, if even one isn't supplied, mark BAC as unavailable if (CLIParamStrToBuf(arg_get_str(ctx, 1), docnum, 9, &slen) != 0 || slen == 0) { BAC = false; - } else if (CLIParamStrToBuf(arg_get_str(ctx, 2), dob, 6, &slen) != 0 || slen == 0) { + } else { + if ( slen != 9) { + memset(docnum + slen, 0x3c, 9 - slen); + } + } + + if (CLIParamStrToBuf(arg_get_str(ctx, 2), dob, 6, &slen) != 0 || slen == 0) { BAC = false; - } else if (CLIParamStrToBuf(arg_get_str(ctx, 3), expiry, 6, &slen) != 0 || slen == 0) { + } + + if (CLIParamStrToBuf(arg_get_str(ctx, 3), expiry, 6, &slen) != 0 || slen == 0) { BAC = false; } From 76da4ce427c08999640906a99575d3bec41c88f0 Mon Sep 17 00:00:00 2001 From: iceman1001 Date: Thu, 17 Dec 2020 00:00:26 +0100 Subject: [PATCH 083/682] change 14b apdu - longer timeout, emrt now autopad too short document numbers --- client/src/cmdhf14b.c | 3 +- client/src/cmdhfemrtd.c | 61 +++++++++++++++++++++++------------------ 2 files changed, 36 insertions(+), 28 deletions(-) diff --git a/client/src/cmdhf14b.c b/client/src/cmdhf14b.c index eb1a4f67a..e21509fe8 100644 --- a/client/src/cmdhf14b.c +++ b/client/src/cmdhf14b.c @@ -26,6 +26,7 @@ #include "mifare/ndef.h" // NDEFRecordsDecodeAndPrint #define TIMEOUT 2000 +#define APDU_TIMEOUT 4000 // iso14b apdu input frame length static uint16_t apdu_frame_length = 0; @@ -1438,7 +1439,7 @@ static int handle_14b_apdu(bool chainingin, uint8_t *datain, int datainlen, bool SendCommandMIX(CMD_HF_ISO14443B_COMMAND, ISO14B_APDU | flags, 0, 0, NULL, 0); PacketResponseNG resp; - if (WaitForResponseTimeout(CMD_HF_ISO14443B_COMMAND, &resp, TIMEOUT)) { + if (WaitForResponseTimeout(CMD_HF_ISO14443B_COMMAND, &resp, APDU_TIMEOUT)) { uint8_t *recv = resp.data.asBytes; int rlen = resp.oldarg[0]; uint8_t res = resp.oldarg[1]; diff --git a/client/src/cmdhfemrtd.c b/client/src/cmdhfemrtd.c index f0f238615..1781fbb41 100644 --- a/client/src/cmdhfemrtd.c +++ b/client/src/cmdhfemrtd.c @@ -280,24 +280,24 @@ static void retail_mac(uint8_t *key, uint8_t *input, int inputlen, uint8_t *outp } static void emrtd_deskey(uint8_t *seed, const uint8_t *type, int length, uint8_t *dataout) { - PrintAndLogEx(DEBUG, "seed: %s", sprint_hex_inrow(seed, 16)); + PrintAndLogEx(DEBUG, "seed.............. %s", sprint_hex_inrow(seed, 16)); // combine seed and type uint8_t data[50]; memcpy(data, seed, length); memcpy(data + length, type, 4); - PrintAndLogEx(DEBUG, "data: %s", sprint_hex_inrow(data, length + 4)); + PrintAndLogEx(DEBUG, "data.............. %s", sprint_hex_inrow(data, length + 4)); // SHA1 the key unsigned char key[64]; mbedtls_sha1(data, length + 4, key); - PrintAndLogEx(DEBUG, "key: %s", sprint_hex_inrow(key, length + 4)); + PrintAndLogEx(DEBUG, "key............... %s", sprint_hex_inrow(key, length + 4)); // Set parity bits for (int i = 0; i < ((length + 4) / 8); i++) { mbedtls_des_key_set_parity(key + (i * 8)); } - PrintAndLogEx(DEBUG, "post-parity key: %s", sprint_hex_inrow(key, 20)); + PrintAndLogEx(DEBUG, "post-parity key... %s", sprint_hex_inrow(key, 20)); memcpy(dataout, &key, length); } @@ -320,9 +320,7 @@ static int emrtd_get_challenge(int length, uint8_t *dataout, int *dataoutlen, bo static int emrtd_external_authenticate(uint8_t *data, int length, uint8_t *dataout, int *dataoutlen, bool use_14b) { char cmd[100]; - sprintf(cmd, "00%s0000%02X%s%02X", EMRTD_EXTERNAL_AUTHENTICATE, length, sprint_hex_inrow(data, length), length); - return emrtd_exchange_commands(cmd, dataout, dataoutlen, false, true, use_14b); } @@ -724,9 +722,10 @@ static bool emrtd_dump_file(uint8_t *ks_enc, uint8_t *ks_mac, uint8_t *ssc, cons static void rng(int length, uint8_t *dataout) { // Do very very secure prng operations - for (int i = 0; i < (length / 4); i++) { - num_to_bytes(prng_successor(msclock() + i, 32), 4, &dataout[i * 4]); - } + //for (int i = 0; i < (length / 4); i++) { + // num_to_bytes(prng_successor(msclock() + i, 32), 4, &dataout[i * 4]); + //} + memset(dataout, 0x00, length); } static bool emrtd_do_bac(char *documentnumber, char *dob, char *expiry, uint8_t *ssc, uint8_t *ks_enc, uint8_t *ks_mac, bool use_14b) { @@ -743,9 +742,9 @@ static bool emrtd_do_bac(char *documentnumber, char *dob, char *expiry, uint8_t rng(8, rnd_ifd); rng(16, k_ifd); - PrintAndLogEx(DEBUG, "doc: %s", documentnumber); - PrintAndLogEx(DEBUG, "dob: %s", dob); - PrintAndLogEx(DEBUG, "exp: %s", expiry); + PrintAndLogEx(DEBUG, "doc............... " _GREEN_("%s"), documentnumber); + PrintAndLogEx(DEBUG, "dob............... " _GREEN_("%s"), dob); + PrintAndLogEx(DEBUG, "exp............... " _GREEN_("%s"), expiry); char documentnumbercd = emrtd_calculate_check_digit(documentnumber); char dobcd = emrtd_calculate_check_digit(dob); @@ -753,40 +752,40 @@ static bool emrtd_do_bac(char *documentnumber, char *dob, char *expiry, uint8_t char kmrz[25]; sprintf(kmrz, "%s%i%s%i%s%i", documentnumber, documentnumbercd, dob, dobcd, expiry, expirycd); - PrintAndLogEx(DEBUG, "kmrz: %s", kmrz); + PrintAndLogEx(DEBUG, "kmrz.............. " _GREEN_("%s"), kmrz); uint8_t kseed[16] = { 0x00 }; mbedtls_sha1((unsigned char *)kmrz, strlen(kmrz), kseed); - PrintAndLogEx(DEBUG, "kseed: %s", sprint_hex_inrow(kseed, 16)); + PrintAndLogEx(DEBUG, "kseed (sha1)...... %s ", sprint_hex_inrow(kseed, 16)); emrtd_deskey(kseed, KENC_type, 16, kenc); emrtd_deskey(kseed, KMAC_type, 16, kmac); - PrintAndLogEx(DEBUG, "kenc: %s", sprint_hex_inrow(kenc, 16)); - PrintAndLogEx(DEBUG, "kmac: %s", sprint_hex_inrow(kmac, 16)); + PrintAndLogEx(DEBUG, "kenc.............. %s", sprint_hex_inrow(kenc, 16)); + PrintAndLogEx(DEBUG, "kmac.............. %s", sprint_hex_inrow(kmac, 16)); // Get Challenge if (emrtd_get_challenge(8, rnd_ic, &resplen, use_14b) == false) { PrintAndLogEx(ERR, "Couldn't get challenge."); return false; } - PrintAndLogEx(DEBUG, "rnd_ic: %s", sprint_hex_inrow(rnd_ic, 8)); + PrintAndLogEx(DEBUG, "rnd_ic............ %s", sprint_hex_inrow(rnd_ic, 8)); memcpy(S, rnd_ifd, 8); memcpy(S + 8, rnd_ic, 8); memcpy(S + 16, k_ifd, 16); - PrintAndLogEx(DEBUG, "S: %s", sprint_hex_inrow(S, 32)); + PrintAndLogEx(DEBUG, "S................. %s", sprint_hex_inrow(S, 32)); uint8_t iv[8] = { 0x00 }; uint8_t e_ifd[32] = { 0x00 }; des3_encrypt_cbc(iv, kenc, S, sizeof(S), e_ifd); - PrintAndLogEx(DEBUG, "e_ifd: %s", sprint_hex_inrow(e_ifd, 32)); + PrintAndLogEx(DEBUG, "e_ifd............. %s", sprint_hex_inrow(e_ifd, 32)); uint8_t m_ifd[8] = { 0x00 }; retail_mac(kmac, e_ifd, 32, m_ifd); - PrintAndLogEx(DEBUG, "m_ifd: %s", sprint_hex_inrow(m_ifd, 8)); + PrintAndLogEx(DEBUG, "m_ifd............. %s", sprint_hex_inrow(m_ifd, 8)); uint8_t cmd_data[40]; memcpy(cmd_data, e_ifd, 32); @@ -801,7 +800,7 @@ static bool emrtd_do_bac(char *documentnumber, char *dob, char *expiry, uint8_t uint8_t dec_output[32] = { 0x00 }; des3_decrypt_cbc(iv, kenc, response, 32, dec_output); - PrintAndLogEx(DEBUG, "dec_output: %s", sprint_hex_inrow(dec_output, 32)); + PrintAndLogEx(DEBUG, "dec_output........ %s", sprint_hex_inrow(dec_output, 32)); if (memcmp(rnd_ifd, dec_output + 8, 8) != 0) { PrintAndLogEx(ERR, "Challenge failed, rnd_ifd does not match."); @@ -815,18 +814,18 @@ static bool emrtd_do_bac(char *documentnumber, char *dob, char *expiry, uint8_t kseed[x] = k_ifd[x] ^ k_icc[x]; } - PrintAndLogEx(DEBUG, "kseed: %s", sprint_hex_inrow(kseed, 16)); + PrintAndLogEx(DEBUG, "kseed............ %s", sprint_hex_inrow(kseed, 16)); emrtd_deskey(kseed, KENC_type, 16, ks_enc); emrtd_deskey(kseed, KMAC_type, 16, ks_mac); - PrintAndLogEx(DEBUG, "ks_enc: %s", sprint_hex_inrow(ks_enc, 16)); - PrintAndLogEx(DEBUG, "ks_mac: %s", sprint_hex_inrow(ks_mac, 16)); + PrintAndLogEx(DEBUG, "ks_enc........ %s", sprint_hex_inrow(ks_enc, 16)); + PrintAndLogEx(DEBUG, "ks_mac........ %s", sprint_hex_inrow(ks_mac, 16)); memcpy(ssc, rnd_ic + 4, 4); memcpy(ssc + 4, rnd_ifd + 4, 4); - PrintAndLogEx(DEBUG, "ssc: %s", sprint_hex_inrow(ssc, 8)); + PrintAndLogEx(DEBUG, "ssc........... %s", sprint_hex_inrow(ssc, 8)); return true; } @@ -1023,9 +1022,17 @@ static int cmd_hf_emrtd_dump(const char *Cmd) { // Go through all args, if even one isn't supplied, mark BAC as unavailable if (CLIParamStrToBuf(arg_get_str(ctx, 1), docnum, 9, &slen) != 0 || slen == 0) { BAC = false; - } else if (CLIParamStrToBuf(arg_get_str(ctx, 2), dob, 6, &slen) != 0 || slen == 0) { + } else { + if ( slen != 9) { + memset(docnum + slen, 0x3c, 9 - slen); + } + } + + if (CLIParamStrToBuf(arg_get_str(ctx, 2), dob, 6, &slen) != 0 || slen == 0) { BAC = false; - } else if (CLIParamStrToBuf(arg_get_str(ctx, 3), expiry, 6, &slen) != 0 || slen == 0) { + } + + if (CLIParamStrToBuf(arg_get_str(ctx, 3), expiry, 6, &slen) != 0 || slen == 0) { BAC = false; } From 9066aa1d261c6e77d728693a3b465c3be78b0e3d Mon Sep 17 00:00:00 2001 From: Ave Date: Thu, 17 Dec 2020 03:44:39 +0300 Subject: [PATCH 084/682] emrtd: Support passports on hf emrtd info --- client/src/cmdhfemrtd.c | 216 +++++++++++++++++++++++++++++++++++++++- 1 file changed, 214 insertions(+), 2 deletions(-) diff --git a/client/src/cmdhfemrtd.c b/client/src/cmdhfemrtd.c index 1781fbb41..f77cc6676 100644 --- a/client/src/cmdhfemrtd.c +++ b/client/src/cmdhfemrtd.c @@ -602,6 +602,35 @@ static bool emrtd_ef_com_get_file_list(uint8_t *datain, int *datainlen, uint8_t return false; } +static bool emrtd_ef_dg1_get_mrz(uint8_t *datain, int *datainlen, uint8_t *dataout, int *dataoutlen) { + // TODO: combine with emrtd_ef_com_get_file_list + int offset = 2; + int elementidlen = 0; + int elementlen = 0; + while (offset < *datainlen) { + PrintAndLogEx(DEBUG, "emrtd_ef_dg1_get_mrz, offset: %i, data: %X", offset, *(datain + offset)); + // Determine element ID length to set as offset on asn1datalength + if (*(datain + offset) == 0x5f) { + elementidlen = 2; + } else { + elementidlen = 1; + } + + // Get the length of the element + elementlen = emrtd_get_asn1_data_length(datain + offset, *datainlen - offset, elementidlen); + + // If the element is what we're looking for, get the data and return true + if (*(datain + offset) == 0x5f && *(datain + offset + 1) == 0x1f) { + *dataoutlen = elementlen; + memcpy(dataout, datain + offset + elementidlen + 1, elementlen); + return true; + } + offset += elementidlen + elementlen + 1; + } + // Return false if we can't find the relevant element + return false; +} + static bool emrtd_file_tag_to_file_id(uint8_t *datain, char *filenameout, char *dataout) { // imagine bothering with a hashmap or writing good code // couldn't be me @@ -966,6 +995,135 @@ int dumpHF_EMRTD(char *documentnumber, char *dob, char *expiry, bool BAC_availab return PM3_SUCCESS; } +static bool emrtd_mrz_verify_check_digit(char *mrz, int offset, int datalen) { + char tempdata[90] = { 0x00 }; + char calculated_check_digit[3]; + + memcpy(tempdata, mrz + offset, datalen); + int check_digit = emrtd_calculate_check_digit(tempdata); + + sprintf(calculated_check_digit, "%i", check_digit); + + PrintAndLogEx(DEBUG, "emrtd_mrz_verify_check_digit, expected: %c", mrz[offset + datalen]); + PrintAndLogEx(DEBUG, "emrtd_mrz_verify_check_digit, calculated: %c", calculated_check_digit[0]); + + return calculated_check_digit[0] == mrz[offset + datalen]; +} + +static void emrtd_print_legal_sex(char *legal_sex) { + char sex[12] = { 0x00 }; + switch (*legal_sex) { + case 'M': + strncpy(sex, "Male", 5); + break; + case 'F': + strncpy(sex, "Female", 7); + break; + case '<': + strncpy(sex, "Unspecified", 12); + break; + } + PrintAndLogEx(SUCCESS, "Legal Sex Marker......: " _YELLOW_("%s"), sex); +} + +static int emrtd_mrz_determine_length(char *mrz, int offset, int max_length) { + int i; + for (i = max_length; i >= 0; i--) { + if (mrz[offset + i - 1] != '<') { + break; + } + } + return i; +} + +static int emrtd_mrz_determine_separator(char *mrz, int offset, int max_length) { + int i; + for (i = max_length; i >= 0; i--) { + if (mrz[offset + i - 1] == '<' && mrz[offset + i] == '<') { + break; + } + } + return i - 1; +} + +static void emrtd_print_optional_elements(char *mrz, int offset) { + int i = emrtd_mrz_determine_length(mrz, offset, 14); + + // Only print optional elements if they're available + if (i != 0) { + PrintAndLogEx(SUCCESS, "Optional elements.....: " _YELLOW_("%.*s"), i, mrz + offset); + } + + if (!emrtd_mrz_verify_check_digit(mrz, offset, 14)) { + PrintAndLogEx(SUCCESS, _RED_("Optional element check digit is invalid.")); + } +} + +static void emrtd_print_passport_number(char *mrz, int offset) { + int i = emrtd_mrz_determine_length(mrz, offset, 9); + + PrintAndLogEx(SUCCESS, "Passport Number.......: " _YELLOW_("%.*s"), i, mrz + offset); + + if (!emrtd_mrz_verify_check_digit(mrz, offset, 9)) { + PrintAndLogEx(SUCCESS, _RED_("Passport number check digit is invalid.")); + } +} + +static void emrtd_print_name(char *mrz, int offset, int max_length) { + char final_name[100] = { 0x00 }; + int i = emrtd_mrz_determine_length(mrz, offset, max_length); + int sep = emrtd_mrz_determine_separator(mrz, offset, i); + int namelen = (i - (sep + 2)); + + memcpy(final_name, mrz + offset + sep + 2, namelen); + final_name[namelen] = ' '; + memcpy(final_name + namelen + 1, mrz + offset, sep); + + PrintAndLogEx(SUCCESS, "Legal Name............: " _YELLOW_("%s"), final_name); +} + +static void emrtd_mrz_convert_date(char *mrz, int offset, char *final_date, bool is_expiry) { + char temp_year[3] = { 0x00 }; + + memcpy(temp_year, mrz + offset, 2); + // If it's > 20, assume 19xx. + if (strtol(temp_year, NULL, 10) < 20 || is_expiry) { + final_date[0] = '2'; + final_date[1] = '0'; + } else { + final_date[0] = '1'; + final_date[1] = '9'; + } + + memcpy(final_date + 2, mrz + offset, 2); + final_date[4] = '-'; + memcpy(final_date + 5, mrz + offset + 2, 2); + final_date[7] = '-'; + memcpy(final_date + 8, mrz + offset + 4, 2); +} + +static void emrtd_print_dob(char *mrz, int offset) { + char final_date[12] = { 0x00 }; + emrtd_mrz_convert_date(mrz, offset, final_date, false); + + PrintAndLogEx(SUCCESS, "Date of birth.........: " _YELLOW_("%s"), final_date); + + if (!emrtd_mrz_verify_check_digit(mrz, offset, 6)) { + PrintAndLogEx(SUCCESS, _RED_("Date of Birth check digit is invalid.")); + } +} + +static void emrtd_print_expiry(char *mrz, int offset) { + char final_date[12] = { 0x00 }; + emrtd_mrz_convert_date(mrz, offset, final_date, true); + + PrintAndLogEx(SUCCESS, "Date of expiry........: " _YELLOW_("%s"), final_date); + + if (!emrtd_mrz_verify_check_digit(mrz, offset, 6)) { + PrintAndLogEx(SUCCESS, _RED_("Date of expiry check digit is invalid.")); + } +} + int infoHF_EMRTD(char *documentnumber, char *dob, char *expiry, bool BAC_available) { // TODO: support just loading a dump file uint8_t response[EMRTD_MAX_FILE_SIZE] = { 0x00 }; @@ -976,11 +1134,13 @@ int infoHF_EMRTD(char *documentnumber, char *dob, char *expiry, bool BAC_availab bool BAC = false; bool use_14b = false; + int td_variant = 0; + // Select and authenticate with the eMRTD bool auth_result = emrtd_do_auth(documentnumber, dob, expiry, BAC_available, &BAC, ssc, ks_enc, ks_mac, &use_14b); PrintAndLogEx(SUCCESS, "Communication standard: %s", use_14b ? _YELLOW_("ISO/IEC 14443(B)") : _YELLOW_("ISO/IEC 14443(A)")); - PrintAndLogEx(SUCCESS, "BAC: %s", BAC ? _GREEN_("Enforced") : _RED_("Not enforced")); - PrintAndLogEx(SUCCESS, "Authentication result: %s", auth_result ? _GREEN_("Successful") : _RED_("Failed")); + PrintAndLogEx(SUCCESS, "BAC...................: %s", BAC ? _GREEN_("Enforced") : _RED_("Not enforced")); + PrintAndLogEx(SUCCESS, "Authentication result.: %s", auth_result ? _GREEN_("Successful") : _RED_("Failed")); if (!auth_result) { DropField(); @@ -994,6 +1154,58 @@ int infoHF_EMRTD(char *documentnumber, char *dob, char *expiry, bool BAC_availab return PM3_ESOFT; } + // MRZ on TD1 is 90 characters, 30 on each row. + // MRZ on TD3 is 88 characters, 44 on each row. + char mrz[90] = { 0x00 }; + int mrzlen = 0; + + if (emrtd_ef_dg1_get_mrz(response, &resplen, (uint8_t *) mrz, &mrzlen) == false) { + PrintAndLogEx(ERR, "Failed to read MRZ from EF_DG1."); + DropField(); + return PM3_ESOFT; + } + + // Determine and print the document type + if (mrz[0] == 'I' && mrz[1] == 'P') { + td_variant = 1; + PrintAndLogEx(SUCCESS, "Document Type.........: " _YELLOW_("Passport Card")); + } else if (mrz[0] == 'I') { + td_variant = 1; + PrintAndLogEx(SUCCESS, "Document Type.........: " _YELLOW_("ID Card")); + } else if (mrz[0] == 'P') { + td_variant = 3; + PrintAndLogEx(SUCCESS, "Document Type.........: " _YELLOW_("Passport")); + } else { + td_variant = 1; + PrintAndLogEx(SUCCESS, "Document Type.........: " _YELLOW_("Unknown")); + PrintAndLogEx(INFO, "Assuming ID-style MRZ."); + } + PrintAndLogEx(SUCCESS, "Document Form Factor..: " _YELLOW_("TD%i"), td_variant); + + // // Print the MRZ + // if (td_variant == 1) { + // PrintAndLogEx(SUCCESS, "MRZ Row 1: " _YELLOW_("%.30s"), mrz); + // PrintAndLogEx(SUCCESS, "MRZ Row 2: " _YELLOW_("%.30s"), mrz + 30); + // PrintAndLogEx(SUCCESS, "MRZ Row 3: " _YELLOW_("%.30s"), mrz + 60); + // } else if (td_variant == 3) { + // PrintAndLogEx(SUCCESS, "MRZ Row 1: " _YELLOW_("%.44s"), mrz); + // PrintAndLogEx(SUCCESS, "MRZ Row 2: " _YELLOW_("%.44s"), mrz + 44); + // } + + // Passport form factor + if (td_variant == 3) { + PrintAndLogEx(SUCCESS, "Issuing state.........: " _YELLOW_("%.3s"), mrz + 2); + emrtd_print_name(mrz, 5, 38); + emrtd_print_passport_number(mrz, 44); + PrintAndLogEx(SUCCESS, "Nationality...........: " _YELLOW_("%.3s"), mrz + 44 + 10); + emrtd_print_dob(mrz, 44 + 13); + emrtd_print_legal_sex(&mrz[44 + 20]); + emrtd_print_expiry(mrz, 44 + 21); + emrtd_print_optional_elements(mrz, 44 + 28); + + // TODO: verify composite check digit here + } + DropField(); return PM3_SUCCESS; } From 2e3e4835ed6e77d56eaaa0d42cd4b4d1e21561e0 Mon Sep 17 00:00:00 2001 From: Ave Date: Thu, 17 Dec 2020 04:03:09 +0300 Subject: [PATCH 085/682] emrtd: Support ID cards on hf emrtd info --- client/src/cmdhfemrtd.c | 50 +++++++++++++++++++++++++---------------- 1 file changed, 31 insertions(+), 19 deletions(-) diff --git a/client/src/cmdhfemrtd.c b/client/src/cmdhfemrtd.c index f77cc6676..2b33aa368 100644 --- a/client/src/cmdhfemrtd.c +++ b/client/src/cmdhfemrtd.c @@ -1046,26 +1046,26 @@ static int emrtd_mrz_determine_separator(char *mrz, int offset, int max_length) return i - 1; } -static void emrtd_print_optional_elements(char *mrz, int offset) { - int i = emrtd_mrz_determine_length(mrz, offset, 14); +static void emrtd_print_optional_elements(char *mrz, int offset, int length, bool verify_check_digit) { + int i = emrtd_mrz_determine_length(mrz, offset, length); // Only print optional elements if they're available if (i != 0) { PrintAndLogEx(SUCCESS, "Optional elements.....: " _YELLOW_("%.*s"), i, mrz + offset); } - if (!emrtd_mrz_verify_check_digit(mrz, offset, 14)) { + if (verify_check_digit && !emrtd_mrz_verify_check_digit(mrz, offset, length)) { PrintAndLogEx(SUCCESS, _RED_("Optional element check digit is invalid.")); } } -static void emrtd_print_passport_number(char *mrz, int offset) { +static void emrtd_print_document_number(char *mrz, int offset) { int i = emrtd_mrz_determine_length(mrz, offset, 9); - PrintAndLogEx(SUCCESS, "Passport Number.......: " _YELLOW_("%.*s"), i, mrz + offset); + PrintAndLogEx(SUCCESS, "Document Number.......: " _YELLOW_("%.*s"), i, mrz + offset); if (!emrtd_mrz_verify_check_digit(mrz, offset, 9)) { - PrintAndLogEx(SUCCESS, _RED_("Passport number check digit is invalid.")); + PrintAndLogEx(SUCCESS, _RED_("Document number check digit is invalid.")); } } @@ -1182,28 +1182,40 @@ int infoHF_EMRTD(char *documentnumber, char *dob, char *expiry, bool BAC_availab } PrintAndLogEx(SUCCESS, "Document Form Factor..: " _YELLOW_("TD%i"), td_variant); - // // Print the MRZ - // if (td_variant == 1) { - // PrintAndLogEx(SUCCESS, "MRZ Row 1: " _YELLOW_("%.30s"), mrz); - // PrintAndLogEx(SUCCESS, "MRZ Row 2: " _YELLOW_("%.30s"), mrz + 30); - // PrintAndLogEx(SUCCESS, "MRZ Row 3: " _YELLOW_("%.30s"), mrz + 60); - // } else if (td_variant == 3) { - // PrintAndLogEx(SUCCESS, "MRZ Row 1: " _YELLOW_("%.44s"), mrz); - // PrintAndLogEx(SUCCESS, "MRZ Row 2: " _YELLOW_("%.44s"), mrz + 44); - // } + // Print the MRZ + if (td_variant == 1) { + PrintAndLogEx(DEBUG, "MRZ Row 1: " _YELLOW_("%.30s"), mrz); + PrintAndLogEx(DEBUG, "MRZ Row 2: " _YELLOW_("%.30s"), mrz + 30); + PrintAndLogEx(DEBUG, "MRZ Row 3: " _YELLOW_("%.30s"), mrz + 60); + } else if (td_variant == 3) { + PrintAndLogEx(DEBUG, "MRZ Row 1: " _YELLOW_("%.44s"), mrz); + PrintAndLogEx(DEBUG, "MRZ Row 2: " _YELLOW_("%.44s"), mrz + 44); + } + + PrintAndLogEx(SUCCESS, "Issuing state.........: " _YELLOW_("%.3s"), mrz + 2); - // Passport form factor if (td_variant == 3) { - PrintAndLogEx(SUCCESS, "Issuing state.........: " _YELLOW_("%.3s"), mrz + 2); + // Passport form factor emrtd_print_name(mrz, 5, 38); - emrtd_print_passport_number(mrz, 44); + emrtd_print_document_number(mrz, 44); PrintAndLogEx(SUCCESS, "Nationality...........: " _YELLOW_("%.3s"), mrz + 44 + 10); emrtd_print_dob(mrz, 44 + 13); emrtd_print_legal_sex(&mrz[44 + 20]); emrtd_print_expiry(mrz, 44 + 21); - emrtd_print_optional_elements(mrz, 44 + 28); + emrtd_print_optional_elements(mrz, 44 + 28, 14, true); // TODO: verify composite check digit here + } else if (td_variant == 1) { + // ID form factor + emrtd_print_document_number(mrz, 5); + emrtd_print_optional_elements(mrz, 15, 15, false); + emrtd_print_dob(mrz, 30); + emrtd_print_legal_sex(&mrz[30 + 7]); + emrtd_print_expiry(mrz, 30 + 8); + PrintAndLogEx(SUCCESS, "Nationality...........: " _YELLOW_("%.3s"), mrz + 30 + 15); + emrtd_print_optional_elements(mrz, 30 + 18, 11, false); + // TODO: verify composite check digit here + emrtd_print_name(mrz, 60, 30); } DropField(); From 8e72830686930ba435bee127ede6bff89503ece3 Mon Sep 17 00:00:00 2001 From: Ave Date: Thu, 17 Dec 2020 04:15:00 +0300 Subject: [PATCH 086/682] emrtd: Merge two functions into emrtd_lds_get_data_by_tag --- client/src/cmdhfemrtd.c | 41 ++++++----------------------------------- 1 file changed, 6 insertions(+), 35 deletions(-) diff --git a/client/src/cmdhfemrtd.c b/client/src/cmdhfemrtd.c index 2b33aa368..2d4d8a8ee 100644 --- a/client/src/cmdhfemrtd.c +++ b/client/src/cmdhfemrtd.c @@ -574,14 +574,14 @@ static int emrtd_read_file(uint8_t *dataout, int *dataoutlen, uint8_t *kenc, uin return true; } -static bool emrtd_ef_com_get_file_list(uint8_t *datain, int *datainlen, uint8_t *dataout, int *dataoutlen) { +static bool emrtd_lds_get_data_by_tag(uint8_t *datain, int *datainlen, uint8_t *dataout, int *dataoutlen, int tag1, int tag2, bool twobytetag) { int offset = 2; int elementidlen = 0; int elementlen = 0; while (offset < *datainlen) { - PrintAndLogEx(DEBUG, "ef_com_get_file_list, offset: %i, data: %X", offset, *(datain + offset)); + PrintAndLogEx(DEBUG, "emrtd_lds_get_data_by_tag, offset: %i, data: %X", offset, *(datain + offset)); // Determine element ID length to set as offset on asn1datalength - if (*(datain + offset) == 0x5f) { + if ((*(datain + offset) == 0x5f) || (*(datain + offset) == 0x7f)) { elementidlen = 2; } else { elementidlen = 1; @@ -591,36 +591,7 @@ static bool emrtd_ef_com_get_file_list(uint8_t *datain, int *datainlen, uint8_t elementlen = emrtd_get_asn1_data_length(datain + offset, *datainlen - offset, elementidlen); // If the element is what we're looking for, get the data and return true - if (*(datain + offset) == 0x5c) { - *dataoutlen = elementlen; - memcpy(dataout, datain + offset + elementidlen + 1, elementlen); - return true; - } - offset += elementidlen + elementlen + 1; - } - // Return false if we can't find the relevant element - return false; -} - -static bool emrtd_ef_dg1_get_mrz(uint8_t *datain, int *datainlen, uint8_t *dataout, int *dataoutlen) { - // TODO: combine with emrtd_ef_com_get_file_list - int offset = 2; - int elementidlen = 0; - int elementlen = 0; - while (offset < *datainlen) { - PrintAndLogEx(DEBUG, "emrtd_ef_dg1_get_mrz, offset: %i, data: %X", offset, *(datain + offset)); - // Determine element ID length to set as offset on asn1datalength - if (*(datain + offset) == 0x5f) { - elementidlen = 2; - } else { - elementidlen = 1; - } - - // Get the length of the element - elementlen = emrtd_get_asn1_data_length(datain + offset, *datainlen - offset, elementidlen); - - // If the element is what we're looking for, get the data and return true - if (*(datain + offset) == 0x5f && *(datain + offset + 1) == 0x1f) { + if (*(datain + offset) == tag1 && (!twobytetag || *(datain + offset + 1) == tag2)) { *dataoutlen = elementlen; memcpy(dataout, datain + offset + elementidlen + 1, elementlen); return true; @@ -968,7 +939,7 @@ int dumpHF_EMRTD(char *documentnumber, char *dob, char *expiry, bool BAC_availab uint8_t filelist[50]; int filelistlen = 0; - if (emrtd_ef_com_get_file_list(response, &resplen, filelist, &filelistlen) == false) { + if (!emrtd_lds_get_data_by_tag(response, &resplen, filelist, &filelistlen, 0x5c, 0x00, false)) { PrintAndLogEx(ERR, "Failed to read file list from EF_COM."); DropField(); return PM3_ESOFT; @@ -1159,7 +1130,7 @@ int infoHF_EMRTD(char *documentnumber, char *dob, char *expiry, bool BAC_availab char mrz[90] = { 0x00 }; int mrzlen = 0; - if (emrtd_ef_dg1_get_mrz(response, &resplen, (uint8_t *) mrz, &mrzlen) == false) { + if (!emrtd_lds_get_data_by_tag(response, &resplen, (uint8_t *) mrz, &mrzlen, 0x5f, 0x1f, true)) { PrintAndLogEx(ERR, "Failed to read MRZ from EF_DG1."); DropField(); return PM3_ESOFT; From b362101b54b9655dc8db5fddbc6fe23ab4a2cecc Mon Sep 17 00:00:00 2001 From: Ave Date: Thu, 17 Dec 2020 04:19:54 +0300 Subject: [PATCH 087/682] emrtd: Split emrtd_mrz_verify_check_digit into two funcs --- client/src/cmdhfemrtd.c | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/client/src/cmdhfemrtd.c b/client/src/cmdhfemrtd.c index 2d4d8a8ee..747f9b042 100644 --- a/client/src/cmdhfemrtd.c +++ b/client/src/cmdhfemrtd.c @@ -966,19 +966,27 @@ int dumpHF_EMRTD(char *documentnumber, char *dob, char *expiry, bool BAC_availab return PM3_SUCCESS; } -static bool emrtd_mrz_verify_check_digit(char *mrz, int offset, int datalen) { +static bool emrtd_compare_check_digit(char *datain, int datalen, char expected_check_digit) { char tempdata[90] = { 0x00 }; char calculated_check_digit[3]; - memcpy(tempdata, mrz + offset, datalen); + memcpy(tempdata, datain, datalen); int check_digit = emrtd_calculate_check_digit(tempdata); sprintf(calculated_check_digit, "%i", check_digit); - PrintAndLogEx(DEBUG, "emrtd_mrz_verify_check_digit, expected: %c", mrz[offset + datalen]); - PrintAndLogEx(DEBUG, "emrtd_mrz_verify_check_digit, calculated: %c", calculated_check_digit[0]); + PrintAndLogEx(DEBUG, "emrtd_compare_check_digit, expected: %c", expected_check_digit); + PrintAndLogEx(DEBUG, "emrtd_compare_check_digit, calculated: %c", calculated_check_digit[0]); - return calculated_check_digit[0] == mrz[offset + datalen]; + return calculated_check_digit[0] == expected_check_digit; +} + +static bool emrtd_mrz_verify_check_digit(char *mrz, int offset, int datalen) { + char tempdata[90] = { 0x00 }; + + memcpy(tempdata, mrz + offset, datalen); + + return emrtd_compare_check_digit(tempdata, datalen, mrz[offset + datalen]); } static void emrtd_print_legal_sex(char *legal_sex) { @@ -1096,7 +1104,6 @@ static void emrtd_print_expiry(char *mrz, int offset) { } int infoHF_EMRTD(char *documentnumber, char *dob, char *expiry, bool BAC_available) { - // TODO: support just loading a dump file uint8_t response[EMRTD_MAX_FILE_SIZE] = { 0x00 }; int resplen = 0; uint8_t ssc[8] = { 0x00 }; From 8e6736edd1b7879b33bd6790960f79c68a9788ef Mon Sep 17 00:00:00 2001 From: Ave Date: Thu, 17 Dec 2020 04:28:26 +0300 Subject: [PATCH 088/682] emrtd: Verify composite check digits --- client/src/cmdhfemrtd.c | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/client/src/cmdhfemrtd.c b/client/src/cmdhfemrtd.c index 747f9b042..244234836 100644 --- a/client/src/cmdhfemrtd.c +++ b/client/src/cmdhfemrtd.c @@ -1182,7 +1182,15 @@ int infoHF_EMRTD(char *documentnumber, char *dob, char *expiry, bool BAC_availab emrtd_print_expiry(mrz, 44 + 21); emrtd_print_optional_elements(mrz, 44 + 28, 14, true); - // TODO: verify composite check digit here + // Calculate and verify composite check digit + char composite_check_data[50] = { 0x00 }; + memcpy(composite_check_data, mrz, 9); + memcpy(composite_check_data + 9, mrz + 13, 7); + memcpy(composite_check_data + 7, mrz + 21, 22); + + if (!emrtd_compare_check_digit(composite_check_data, 36, mrz[87])) { + PrintAndLogEx(SUCCESS, _RED_("Composite check digit is invalid.")); + } } else if (td_variant == 1) { // ID form factor emrtd_print_document_number(mrz, 5); @@ -1192,7 +1200,12 @@ int infoHF_EMRTD(char *documentnumber, char *dob, char *expiry, bool BAC_availab emrtd_print_expiry(mrz, 30 + 8); PrintAndLogEx(SUCCESS, "Nationality...........: " _YELLOW_("%.3s"), mrz + 30 + 15); emrtd_print_optional_elements(mrz, 30 + 18, 11, false); - // TODO: verify composite check digit here + + // Calculate and verify composite check digit + if (!emrtd_compare_check_digit(mrz, 59, mrz[59])) { + PrintAndLogEx(SUCCESS, _RED_("Composite check digit is invalid.")); + } + emrtd_print_name(mrz, 60, 30); } From b31a610566f62b816cc007f94436dee047459a0b Mon Sep 17 00:00:00 2001 From: Ave Date: Thu, 17 Dec 2020 05:08:56 +0300 Subject: [PATCH 089/682] emrtd: Fix passport composite + change print order --- client/src/cmdhfemrtd.c | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/client/src/cmdhfemrtd.c b/client/src/cmdhfemrtd.c index 244234836..5b1fe8981 100644 --- a/client/src/cmdhfemrtd.c +++ b/client/src/cmdhfemrtd.c @@ -1174,9 +1174,9 @@ int infoHF_EMRTD(char *documentnumber, char *dob, char *expiry, bool BAC_availab if (td_variant == 3) { // Passport form factor + PrintAndLogEx(SUCCESS, "Nationality...........: " _YELLOW_("%.3s"), mrz + 44 + 10); emrtd_print_name(mrz, 5, 38); emrtd_print_document_number(mrz, 44); - PrintAndLogEx(SUCCESS, "Nationality...........: " _YELLOW_("%.3s"), mrz + 44 + 10); emrtd_print_dob(mrz, 44 + 13); emrtd_print_legal_sex(&mrz[44 + 20]); emrtd_print_expiry(mrz, 44 + 21); @@ -1184,29 +1184,28 @@ int infoHF_EMRTD(char *documentnumber, char *dob, char *expiry, bool BAC_availab // Calculate and verify composite check digit char composite_check_data[50] = { 0x00 }; - memcpy(composite_check_data, mrz, 9); - memcpy(composite_check_data + 9, mrz + 13, 7); - memcpy(composite_check_data + 7, mrz + 21, 22); + memcpy(composite_check_data, mrz + 44, 10); + memcpy(composite_check_data + 10, mrz + 44 + 13, 7); + memcpy(composite_check_data + 17, mrz + 44 + 21, 23); - if (!emrtd_compare_check_digit(composite_check_data, 36, mrz[87])) { + if (!emrtd_compare_check_digit(composite_check_data, 39, mrz[87])) { PrintAndLogEx(SUCCESS, _RED_("Composite check digit is invalid.")); } } else if (td_variant == 1) { // ID form factor + PrintAndLogEx(SUCCESS, "Nationality...........: " _YELLOW_("%.3s"), mrz + 30 + 15); + emrtd_print_name(mrz, 60, 30); emrtd_print_document_number(mrz, 5); - emrtd_print_optional_elements(mrz, 15, 15, false); emrtd_print_dob(mrz, 30); emrtd_print_legal_sex(&mrz[30 + 7]); emrtd_print_expiry(mrz, 30 + 8); - PrintAndLogEx(SUCCESS, "Nationality...........: " _YELLOW_("%.3s"), mrz + 30 + 15); + emrtd_print_optional_elements(mrz, 15, 15, false); emrtd_print_optional_elements(mrz, 30 + 18, 11, false); // Calculate and verify composite check digit if (!emrtd_compare_check_digit(mrz, 59, mrz[59])) { PrintAndLogEx(SUCCESS, _RED_("Composite check digit is invalid.")); } - - emrtd_print_name(mrz, 60, 30); } DropField(); From 8cb25b742acb49a14b0d7035a732c51cef2575c2 Mon Sep 17 00:00:00 2001 From: Ave Date: Thu, 17 Dec 2020 05:12:54 +0300 Subject: [PATCH 090/682] emrtd: Remove redundant padding code --- client/src/cmdhfemrtd.c | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/client/src/cmdhfemrtd.c b/client/src/cmdhfemrtd.c index 5b1fe8981..50492e3ee 100644 --- a/client/src/cmdhfemrtd.c +++ b/client/src/cmdhfemrtd.c @@ -221,12 +221,6 @@ static void des3_decrypt_cbc(uint8_t *iv, uint8_t *key, uint8_t *input, int inpu mbedtls_des3_free(&ctx); } -static void emrtd_pad_docnum(char *input) { - for (int i = strlen(input); i < 9; i++) { - input[i] = '<'; - } -} - static int pad_block(uint8_t *input, int inputlen, uint8_t *output) { uint8_t padding[8] = {0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; @@ -834,8 +828,6 @@ static bool emrtd_do_auth(char *documentnumber, char *dob, char *expiry, bool BA uint8_t response[EMRTD_MAX_FILE_SIZE] = { 0x00 }; int resplen = 0; - emrtd_pad_docnum(documentnumber); - // Try to 14a SendCommandMIX(CMD_HF_ISO14443A_READER, ISO14A_CONNECT | ISO14A_NO_DISCONNECT, 0, 0, NULL, 0); PacketResponseNG resp; @@ -1237,7 +1229,8 @@ static int cmd_hf_emrtd_dump(const char *Cmd) { if (CLIParamStrToBuf(arg_get_str(ctx, 1), docnum, 9, &slen) != 0 || slen == 0) { BAC = false; } else { - if ( slen != 9) { + if (slen != 9) { + // Pad to 9 with < memset(docnum + slen, 0x3c, 9 - slen); } } From b3c7dd64c64c6e58e67547672a51b5296d244aec Mon Sep 17 00:00:00 2001 From: iceman1001 Date: Thu, 17 Dec 2020 14:46:57 +0100 Subject: [PATCH 091/682] fix auth logic, and compiler warning --- client/src/cmdhfemrtd.c | 20 ++++++++------------ 1 file changed, 8 insertions(+), 12 deletions(-) diff --git a/client/src/cmdhfemrtd.c b/client/src/cmdhfemrtd.c index b8de76a8b..c6688ff1e 100644 --- a/client/src/cmdhfemrtd.c +++ b/client/src/cmdhfemrtd.c @@ -960,24 +960,20 @@ int dumpHF_EMRTD(char *documentnumber, char *dob, char *expiry, bool BAC_availab static bool emrtd_compare_check_digit(char *datain, int datalen, char expected_check_digit) { char tempdata[90] = { 0x00 }; - char calculated_check_digit[3]; - memcpy(tempdata, datain, datalen); - int check_digit = emrtd_calculate_check_digit(tempdata); - sprintf(calculated_check_digit, "%i", check_digit); - - PrintAndLogEx(DEBUG, "emrtd_compare_check_digit, expected: %c", expected_check_digit); - PrintAndLogEx(DEBUG, "emrtd_compare_check_digit, calculated: %c", calculated_check_digit[0]); - - return calculated_check_digit[0] == expected_check_digit; + uint8_t check_digit = emrtd_calculate_check_digit(tempdata) + 0x30; + bool res =check_digit == expected_check_digit; + PrintAndLogEx(DEBUG, "emrtd_compare_check_digit, expected %c == %c calculated ( %s )" + , expected_check_digit + , check_digit + , (res) ? _GREEN_("ok") : _RED_("fail")); + return res; } static bool emrtd_mrz_verify_check_digit(char *mrz, int offset, int datalen) { char tempdata[90] = { 0x00 }; - memcpy(tempdata, mrz + offset, datalen); - return emrtd_compare_check_digit(tempdata, datalen, mrz[offset + datalen]); } @@ -1112,7 +1108,7 @@ int infoHF_EMRTD(char *documentnumber, char *dob, char *expiry, bool BAC_availab PrintAndLogEx(SUCCESS, "BAC...................: %s", BAC ? _GREEN_("Enforced") : _RED_("Not enforced")); PrintAndLogEx(SUCCESS, "Authentication result.: %s", auth_result ? _GREEN_("Successful") : _RED_("Failed")); - if (!auth_result) { + if (BAC && !auth_result) { DropField(); return PM3_ESOFT; } From 205885cb1534966672462cc7417df9651b740f03 Mon Sep 17 00:00:00 2001 From: Ave Date: Thu, 17 Dec 2020 18:18:25 +0300 Subject: [PATCH 092/682] emrtd: Improve card presence check logic --- client/src/cmdhfemrtd.c | 31 +++++++++++++++++++++++-------- 1 file changed, 23 insertions(+), 8 deletions(-) diff --git a/client/src/cmdhfemrtd.c b/client/src/cmdhfemrtd.c index c6688ff1e..daa51be19 100644 --- a/client/src/cmdhfemrtd.c +++ b/client/src/cmdhfemrtd.c @@ -824,10 +824,7 @@ static bool emrtd_do_bac(char *documentnumber, char *dob, char *expiry, uint8_t return true; } -static bool emrtd_do_auth(char *documentnumber, char *dob, char *expiry, bool BAC_available, bool *BAC, uint8_t *ssc, uint8_t *ks_enc, uint8_t *ks_mac, bool *use_14b) { - uint8_t response[EMRTD_MAX_FILE_SIZE] = { 0x00 }; - int resplen = 0; - +static bool emrtd_connect(bool *use_14b) { // Try to 14a SendCommandMIX(CMD_HF_ISO14443A_READER, ISO14A_CONNECT | ISO14A_NO_DISCONNECT, 0, 0, NULL, 0); PacketResponseNG resp; @@ -852,6 +849,12 @@ static bool emrtd_do_auth(char *documentnumber, char *dob, char *expiry, bool BA } *use_14b = true; } + return true; +} + +static bool emrtd_do_auth(char *documentnumber, char *dob, char *expiry, bool BAC_available, bool *BAC, uint8_t *ssc, uint8_t *ks_enc, uint8_t *ks_mac, bool *use_14b) { + uint8_t response[EMRTD_MAX_FILE_SIZE] = { 0x00 }; + int resplen = 0; // Select and read EF_CardAccess if (emrtd_select_file(EMRTD_P1_SELECT_BY_EF, EMRTD_EF_CARDACCESS, *use_14b)) { @@ -912,14 +915,20 @@ int dumpHF_EMRTD(char *documentnumber, char *dob, char *expiry, bool BAC_availab bool BAC = false; bool use_14b = false; - // Select and authenticate with the eMRTD - if (emrtd_do_auth(documentnumber, dob, expiry, BAC_available, &BAC, ssc, ks_enc, ks_mac, &use_14b) == false) { + // Select the eMRTD + if (!emrtd_connect(&use_14b)) { + DropField(); + return PM3_ESOFT; + } + + // Authenticate with the eMRTD + if (!emrtd_do_auth(documentnumber, dob, expiry, BAC_available, &BAC, ssc, ks_enc, ks_mac, &use_14b)) { DropField(); return PM3_ESOFT; } // Select EF_COM - if (emrtd_select_and_read(response, &resplen, EMRTD_EF_COM, ks_enc, ks_mac, ssc, BAC, use_14b) == false) { + if (!emrtd_select_and_read(response, &resplen, EMRTD_EF_COM, ks_enc, ks_mac, ssc, BAC, use_14b)) { PrintAndLogEx(ERR, "Failed to read EF_COM."); DropField(); return PM3_ESOFT; @@ -1102,13 +1111,19 @@ int infoHF_EMRTD(char *documentnumber, char *dob, char *expiry, bool BAC_availab int td_variant = 0; + // Select the eMRTD + if (!emrtd_connect(&use_14b)) { + DropField(); + return PM3_ESOFT; + } + // Select and authenticate with the eMRTD bool auth_result = emrtd_do_auth(documentnumber, dob, expiry, BAC_available, &BAC, ssc, ks_enc, ks_mac, &use_14b); PrintAndLogEx(SUCCESS, "Communication standard: %s", use_14b ? _YELLOW_("ISO/IEC 14443(B)") : _YELLOW_("ISO/IEC 14443(A)")); PrintAndLogEx(SUCCESS, "BAC...................: %s", BAC ? _GREEN_("Enforced") : _RED_("Not enforced")); PrintAndLogEx(SUCCESS, "Authentication result.: %s", auth_result ? _GREEN_("Successful") : _RED_("Failed")); - if (BAC && !auth_result) { + if (!auth_result) { DropField(); return PM3_ESOFT; } From 90bb07e63b7a6a5e685cd6135f9cb037bf7fe2bc Mon Sep 17 00:00:00 2001 From: iceman1001 Date: Thu, 17 Dec 2020 18:03:46 +0100 Subject: [PATCH 093/682] update discord lnk --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index bc7e88854..b8140e407 100644 --- a/README.md +++ b/README.md @@ -111,7 +111,7 @@ Next place to visit is the [Proxmark Forum](http://www.proxmark.org/forum/index. - [Proxmark3 IRC channel](http://webchat.freenode.net/?channels=#proxmark3) - [Proxmark3 sub reddit](https://www.reddit.com/r/proxmark3/) - [Twitter](https://twitter.com/proxmark3/) - - [Proxmark3 community discord server](https://discord.gg/zjxc8ZB) + - [Proxmark3 community discord server](https://discord.gg/QfPvGFRQxH) _no slack channel_ From 01ec2efc25f9675074ea2d5803804e2f72841692 Mon Sep 17 00:00:00 2001 From: Ave Date: Thu, 17 Dec 2020 22:07:16 +0300 Subject: [PATCH 094/682] Show hints by default --- client/src/preferences.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/src/preferences.c b/client/src/preferences.c index 5b5b9bee9..9f507b969 100644 --- a/client/src/preferences.c +++ b/client/src/preferences.c @@ -53,7 +53,7 @@ int preferences_load(void) { session.overlay.h = 200; session.overlay.w = session.plot.w; session.overlay_sliders = true; - session.show_hints = false; + session.show_hints = true; // setDefaultPath (spDefault, ""); // setDefaultPath (spDump, ""); From a9f28adabf4ee8a9c572b793b1a735d6741f5f32 Mon Sep 17 00:00:00 2001 From: Ave Date: Thu, 17 Dec 2020 22:22:26 +0300 Subject: [PATCH 095/682] emrtd: Improve emrtd_lds_get_data_by_tag to account for variable data sizes --- client/src/cmdhfemrtd.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/client/src/cmdhfemrtd.c b/client/src/cmdhfemrtd.c index daa51be19..9525e0ac0 100644 --- a/client/src/cmdhfemrtd.c +++ b/client/src/cmdhfemrtd.c @@ -569,9 +569,11 @@ static int emrtd_read_file(uint8_t *dataout, int *dataoutlen, uint8_t *kenc, uin } static bool emrtd_lds_get_data_by_tag(uint8_t *datain, int *datainlen, uint8_t *dataout, int *dataoutlen, int tag1, int tag2, bool twobytetag) { - int offset = 2; + int offset = 1; + offset += emrtd_get_asn1_field_length(datain, *datainlen, offset); int elementidlen = 0; int elementlen = 0; + int elementlenlen = 0; while (offset < *datainlen) { PrintAndLogEx(DEBUG, "emrtd_lds_get_data_by_tag, offset: %i, data: %X", offset, *(datain + offset)); // Determine element ID length to set as offset on asn1datalength @@ -584,13 +586,16 @@ static bool emrtd_lds_get_data_by_tag(uint8_t *datain, int *datainlen, uint8_t * // Get the length of the element elementlen = emrtd_get_asn1_data_length(datain + offset, *datainlen - offset, elementidlen); + // Get the length of the element's length + elementlenlen = emrtd_get_asn1_field_length(datain + offset, *datainlen - offset, elementidlen); + // If the element is what we're looking for, get the data and return true if (*(datain + offset) == tag1 && (!twobytetag || *(datain + offset + 1) == tag2)) { *dataoutlen = elementlen; - memcpy(dataout, datain + offset + elementidlen + 1, elementlen); + memcpy(dataout, datain + offset + elementidlen + elementlenlen, elementlen); return true; } - offset += elementidlen + elementlen + 1; + offset += elementidlen + elementlen + elementlenlen; } // Return false if we can't find the relevant element return false; @@ -894,7 +899,7 @@ static bool emrtd_do_auth(char *documentnumber, char *dob, char *expiry, bool BA // If BAC isn't available, exit out and warn user. if (!BAC_available) { PrintAndLogEx(ERR, "This eMRTD enforces Basic Access Control, but you didn't supply MRZ data. Cannot proceed."); - PrintAndLogEx(HINT, "Check out hf emrtd dump --help, supply data with -n -d and -e."); + PrintAndLogEx(HINT, "Check out hf emrtd info/dump --help, supply data with -n -d and -e."); return false; } From ae7090a47e29177a561ab1fe5e6e37499cc35425 Mon Sep 17 00:00:00 2001 From: Ave Date: Thu, 17 Dec 2020 22:22:41 +0300 Subject: [PATCH 096/682] emrtd: Dump image when dumping EF_DG5 --- client/src/cmdhfemrtd.c | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/client/src/cmdhfemrtd.c b/client/src/cmdhfemrtd.c index 9525e0ac0..cfb4361a4 100644 --- a/client/src/cmdhfemrtd.c +++ b/client/src/cmdhfemrtd.c @@ -704,6 +704,19 @@ static bool emrtd_select_and_read(uint8_t *dataout, int *dataoutlen, const char return true; } +static bool emrtd_dump_ef_dg5(uint8_t *file_contents, int file_length) { + uint8_t response[EMRTD_MAX_FILE_SIZE]; + int resplen = 0; + + // If we can't find image in EF_DG5, return false. + if (!emrtd_lds_get_data_by_tag(file_contents, &file_length, response, &resplen, 0x5f, 0x40, true)) { + return false; + } + + saveFile("EF_DG5", ".jpg", response, resplen); + return true; +} + static bool emrtd_dump_file(uint8_t *ks_enc, uint8_t *ks_mac, uint8_t *ssc, const char *file, const char *name, bool use_secure, bool use_14b) { uint8_t response[EMRTD_MAX_FILE_SIZE]; int resplen = 0; @@ -716,6 +729,10 @@ static bool emrtd_dump_file(uint8_t *ks_enc, uint8_t *ks_mac, uint8_t *ssc, cons PrintAndLogEx(DEBUG, "Contents (may be incomplete over 2k chars): %s", sprint_hex_inrow(response, resplen)); saveFile(name, ".BIN", response, resplen); + if (strcmp(file, EMRTD_EF_DG5) == 0) { + emrtd_dump_ef_dg5(response, resplen); + } + return true; } From f3d5c60c1085d9cbed0e617f709573143280515e Mon Sep 17 00:00:00 2001 From: Ave Date: Thu, 17 Dec 2020 22:45:41 +0300 Subject: [PATCH 097/682] emrtd: Dump cert when dumping EF_SOD --- client/src/cmdhfemrtd.c | 22 ++++++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/client/src/cmdhfemrtd.c b/client/src/cmdhfemrtd.c index cfb4361a4..299f3e7c7 100644 --- a/client/src/cmdhfemrtd.c +++ b/client/src/cmdhfemrtd.c @@ -705,15 +705,27 @@ static bool emrtd_select_and_read(uint8_t *dataout, int *dataoutlen, const char } static bool emrtd_dump_ef_dg5(uint8_t *file_contents, int file_length) { - uint8_t response[EMRTD_MAX_FILE_SIZE]; - int resplen = 0; + uint8_t data[EMRTD_MAX_FILE_SIZE]; + int datalen = 0; // If we can't find image in EF_DG5, return false. - if (!emrtd_lds_get_data_by_tag(file_contents, &file_length, response, &resplen, 0x5f, 0x40, true)) { + if (!emrtd_lds_get_data_by_tag(file_contents, &file_length, data, &datalen, 0x5f, 0x40, true)) { return false; } - saveFile("EF_DG5", ".jpg", response, resplen); + saveFile("EF_DG5", ".jpg", data, datalen); + return true; +} + +static bool emrtd_dump_ef_sod(uint8_t *file_contents, int file_length) { + uint8_t data[EMRTD_MAX_FILE_SIZE]; + + int datalenlen = emrtd_get_asn1_field_length(file_contents, file_length, 1); + int datalen = emrtd_get_asn1_data_length(file_contents, file_length, 1); + + memcpy(data, file_contents + datalenlen + 1, datalen); + + saveFile("EF_SOD", ".p7b", data, datalen); return true; } @@ -731,6 +743,8 @@ static bool emrtd_dump_file(uint8_t *ks_enc, uint8_t *ks_mac, uint8_t *ssc, cons if (strcmp(file, EMRTD_EF_DG5) == 0) { emrtd_dump_ef_dg5(response, resplen); + } else if (strcmp(file, EMRTD_EF_SOD) == 0) { + emrtd_dump_ef_sod(response, resplen); } return true; From 7d27dabbf1ba249c7e6f9436bc3514c1e342b424 Mon Sep 17 00:00:00 2001 From: iceman1001 Date: Thu, 17 Dec 2020 20:46:05 +0100 Subject: [PATCH 098/682] textual --- .github/ISSUE_TEMPLATE/checklist-for-release.md | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/.github/ISSUE_TEMPLATE/checklist-for-release.md b/.github/ISSUE_TEMPLATE/checklist-for-release.md index aae8ab053..01709e9ab 100644 --- a/.github/ISSUE_TEMPLATE/checklist-for-release.md +++ b/.github/ISSUE_TEMPLATE/checklist-for-release.md @@ -22,14 +22,14 @@ assignees: doegox, iceman1001 # OS compilation and tests ```bash -make clean && make -j PLATFORM=PM3OTHER && tools/pm3test.sh -make clean && make -j PLATFORM=PM3RDV4 && tools/pm3test.sh -make clean && make -j PLATFORM=PM3RDV4 PLATFORM_EXTRAS=BTADDON && tools/pm3test.sh -make install; pushd /tmp; proxmark3 -c 'data load em4x05.pm3;lf search 1'; popd; make uninstall +make clean && make -j PLATFORM=PM3OTHER && tools/pm3_tests.sh +make clean && make -j PLATFORM=PM3RDV4 && tools/pm3_tests.sh +make clean && make -j PLATFORM=PM3RDV4 PLATFORM_EXTRAS=BTADDON && tools/pm3_tests.sh +make install; pushd /tmp; proxmark3 -c 'data load -f em4x05.pm3;lf search 1'; popd; make uninstall -( cd client; rm -rf build; mkdir build;cd build;cmake .. && make -j PLATFORM=PM3OTHER && PM3BIN=./proxmark3 ../../tools/pm3test.sh client ) -( cd client; rm -rf build; mkdir build;cd build;cmake .. && make -j PLATFORM=PM3RDV4 && PM3BIN=./proxmark3 ../../tools/pm3test.sh client ) -( cd client; rm -rf build; mkdir build;cd build;cmake .. && make -j PLATFORM=PM3RDV4 PLATFORM_EXTRAS=BTADDON && PM3BIN=./proxmark3 ../../tools/pm3test.sh client ) +( cd client; rm -rf build; mkdir build;cd build;cmake .. && make -j PLATFORM=PM3OTHER && PM3BIN=./proxmark3 ../../tools/pm3_tests.sh client ) +( cd client; rm -rf build; mkdir build;cd build;cmake .. && make -j PLATFORM=PM3RDV4 && PM3BIN=./proxmark3 ../../tools/pm3_tests.sh client ) +( cd client; rm -rf build; mkdir build;cd build;cmake .. && make -j PLATFORM=PM3RDV4 PLATFORM_EXTRAS=BTADDON && PM3BIN=./proxmark3 ../../tools/pm3_tests.sh client ) ``` - [ ] RPI Zero From ced056be199f2091ec0714d2f9b3d2fe2be24c22 Mon Sep 17 00:00:00 2001 From: tharexde Date: Thu, 17 Dec 2020 20:54:06 +0100 Subject: [PATCH 099/682] deleted non existing functions in header --- armsrc/em4x50.h | 5 ----- 1 file changed, 5 deletions(-) diff --git a/armsrc/em4x50.h b/armsrc/em4x50.h index 12f0a64d8..9f9b38351 100644 --- a/armsrc/em4x50.h +++ b/armsrc/em4x50.h @@ -13,11 +13,6 @@ #include "../include/em4x50.h" -int em4x50_standalone_read(uint32_t *words); -int em4x50_standalone_brute(uint32_t start, uint32_t stop, uint32_t *pwd); -bool em4x50_sim_send_listen_window(void); -bool em4x50_sim_send_word(uint32_t word); - void em4x50_info(em4x50_data_t *etd); void em4x50_write(em4x50_data_t *etd); void em4x50_writepwd(em4x50_data_t *etd); From 50eb90bdc7f9ad08c88a1970027bffe63b403277 Mon Sep 17 00:00:00 2001 From: tharexde Date: Thu, 17 Dec 2020 20:55:01 +0100 Subject: [PATCH 100/682] added missing static statements --- armsrc/em4x50.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/armsrc/em4x50.c b/armsrc/em4x50.c index bf457c7cf..437afd956 100644 --- a/armsrc/em4x50.c +++ b/armsrc/em4x50.c @@ -691,7 +691,7 @@ static bool em4x50_sim_send_byte_with_parity(uint8_t byte) { return true; } -bool em4x50_sim_send_word(uint32_t word) { +static bool em4x50_sim_send_word(uint32_t word) { uint8_t cparity = 0x00; @@ -722,7 +722,7 @@ bool em4x50_sim_send_word(uint32_t word) { return true; } -bool em4x50_sim_send_listen_window(void) { +static bool em4x50_sim_send_listen_window(void) { uint16_t check = 0; From 0be10b617e039b90ee27c36badc9bba1d19338de Mon Sep 17 00:00:00 2001 From: tharexde <61853685+tharexde@users.noreply.github.com> Date: Thu, 17 Dec 2020 21:09:02 +0100 Subject: [PATCH 101/682] Delete lf_tharexde.c uploaded by mistake --- armsrc/Standalone/lf_tharexde.c | 359 -------------------------------- 1 file changed, 359 deletions(-) delete mode 100644 armsrc/Standalone/lf_tharexde.c diff --git a/armsrc/Standalone/lf_tharexde.c b/armsrc/Standalone/lf_tharexde.c deleted file mode 100644 index f5195513c..000000000 --- a/armsrc/Standalone/lf_tharexde.c +++ /dev/null @@ -1,359 +0,0 @@ -//----------------------------------------------------------------------------- -// Tharexde, 2020 -// -// This code is licensed to you under the terms of the GNU GPL, version 2 or, -// at your option, any later version. See the LICENSE.txt file for the text of -// the license. -//----------------------------------------------------------------------------- -// main code for EM4x50 simulator and collector aka THAREXDE -//----------------------------------------------------------------------------- -#include -#include "standalone.h" -#include "proxmark3_arm.h" -#include "appmain.h" -#include "BigBuf.h" -#include "fpgaloader.h" -#include "util.h" -#include "dbprint.h" -#include "spiffs.h" -#include "../em4x50.h" - -/* - * `lf_tharexde` simulates hardcoded words/blocks, reads words of standard read - * mode of EM4x50 tags and stores them in internal flash. - * It requires RDV4 hardware (for flash and battery). - * - * On entering stand-alone mode, this module will start reading/record EM4x50 data. - * Every found / collected data will be written/appended to the logfile in flash - * as a text string. - * - * LEDs: - * - LED A: simulating - * - LED B: reading / record - * - LED C: writing to flash - * - LED D: unmounting/sync'ing flash (normally < 100ms) - * - * To retrieve log file from flash: - * - * 1. mem spiffs dump o lf_em4x50collect.log f lf_em4x50collect.log - * Copies log file from flash to your client. - * - * 2. exit the Proxmark3 client - * - * 3. more lf_tharexdecollect.log - * - * This module emits debug strings during normal operation -- so try it out in - * the lab connected to PM3 client before taking it into the field. - * - * To delete the log file from flash: - * - * 1. mem spiffs remove lf_tharexdecollect.log - */ - -#define STATE_SIM 0 -#define STATE_READ 1 -#define STATE_BRUTE 2 -#define EM4X50_TAG_WORD 45 -#define EM4X50_PWD_SPEED 27 -#define LF_EM4X50SIMULATE_INPUTFILE "lf_em4x50simulate.eml" -#define LF_EM4X50COLLECT_LOGFILE "lf_em4x50collect.log" -#define LF_EM4X50BRUTE_INPUTFILE "lf_em4x50brute.eml" -#define LF_EM4X50BRUTE_LOGFILE "lf_em4x50brute.log" - -bool input_exists; -bool log_exists; - -static void LoadDataInstructions(const char *inputfile) { - Dbprintf(""); - Dbprintf("To load datafile into flash and display it:"); - Dbprintf(_YELLOW_("1.") " edit inputfile %s", inputfile); - Dbprintf(_YELLOW_("2.") " start proxmark3 client"); - Dbprintf(_YELLOW_("3.") " mem spiffs load f %s o %s", inputfile, inputfile); - Dbprintf(_YELLOW_("4.") " start standalone mode"); -} - -static void DownloadLogInstructions(const char *logfile) { - Dbprintf(""); - Dbprintf("To get the logfile from flash and display it:"); - Dbprintf(_YELLOW_("1.") " mem spiffs dump o %s f %s", logfile, logfile); - Dbprintf(_YELLOW_("2.") " exit proxmark3 client"); - Dbprintf(_YELLOW_("3.") " cat %s", logfile); -} - -static int get_input_data_from_file(uint32_t *words, char *inputfile) { - - size_t now = 0; - - if (exists_in_spiffs(inputfile)) { - - uint32_t size = size_in_spiffs(inputfile); - uint8_t *mem = BigBuf_malloc(size); - - Dbprintf(_YELLOW_("found input file %s"), inputfile); - - rdv40_spiffs_read_as_filetype(inputfile, mem, size, RDV40_SPIFFS_SAFETY_SAFE); - - now = size / 9; - for (int i = 0; i < now; i++) - for (int j = 0; j < 4; j++) - words[i] |= (hex2int(mem[2 * j + 9 * i]) << 4 | hex2int(mem[2 * j + 1 + 9 * i])) << ((3 - j) * 8); - - Dbprintf(_YELLOW_("read data from input file")); - } - - BigBuf_free(); - - return (now > 0) ? now : 0; -} - -static void append(const char *filename, uint8_t *entry, size_t entry_len) { - - LED_D_ON(); - if (log_exists == false) { - rdv40_spiffs_write(filename, entry, entry_len, RDV40_SPIFFS_SAFETY_SAFE); - log_exists = true; - } else { - rdv40_spiffs_append(filename, entry, entry_len, RDV40_SPIFFS_SAFETY_SAFE); - } - LED_D_OFF(); -} - -void ModInfo(void) { - DbpString(_YELLOW_(" LF EM4x50 sim/collector/bruteforce mode") " - a.k.a tharexde"); -} - -void RunMod(void) { - - bool state_change = true;//, password_found = false; - int pwd_found = false; - uint8_t state = STATE_SIM; - // declarations for simulating - uint32_t words[33] = {0x0}; - uint32_t pwd = 0x0; - uint32_t passwords[2] = {0x0}; - size_t now = 0; - // declarations for reading - int no_words = 0; - //uint32_t words[EM4X50_TAG_WORD]; - uint8_t entry[81]; - - rdv40_spiffs_lazy_mount(); - - StandAloneMode(); - Dbprintf(_YELLOW_("Standalone mode THAREXDE started")); - - for (;;) { - - WDT_HIT(); - if (data_available()) break; - - // press button - toggle between SIM, READ and BRUTE - // hold button - exit - int button_pressed = BUTTON_CLICKED(1000); - if (button_pressed == BUTTON_SINGLE_CLICK) { - - SpinUp(100); - - switch (state) { - - case STATE_SIM: - state = STATE_READ; - break; - case STATE_READ: - state = STATE_BRUTE; - break; - case STATE_BRUTE: - state = STATE_SIM; - break; - default: - break; - } - - state_change = true; - - } else if (button_pressed == BUTTON_HOLD) { - - SpinDown(100); - break; - } - - if (state == STATE_SIM) { - - if (state_change) { - - FpgaDownloadAndGo(FPGA_BITSTREAM_LF); - FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_EDGE_DETECT); - FpgaSendCommand(FPGA_CMD_SET_DIVISOR, LF_DIVISOR_125); - - AT91C_BASE_PIOA->PIO_PER = GPIO_SSC_DOUT | GPIO_SSC_CLK; - AT91C_BASE_PIOA->PIO_OER = GPIO_SSC_DOUT; - AT91C_BASE_PIOA->PIO_ODR = GPIO_SSC_CLK; - - LEDsoff(); - LED_A_ON(); - Dbprintf(""); - Dbprintf(_YELLOW_("switched to EM4x50 simulating mode")); - - now = get_input_data_from_file(words, LF_EM4X50SIMULATE_INPUTFILE); - if (now > 0) { - Dbprintf(_YELLOW_("simulating %i blocks"), now); - for (int i = 0; i < now; i++) - Dbprintf("%2i -> %lx", i + 1, words[i]); - - } else { - Dbprintf(_RED_("error in input data")); - } - - state_change = false; - } - - em4x50_sim_send_listen_window(); - for (int i = 0; i < now; i++) { - em4x50_sim_send_listen_window(); - em4x50_sim_send_word(words[i]); - } - - } else if (state == STATE_READ) { - - if (state_change) { - - LEDsoff(); - LED_B_ON(); - Dbprintf(""); - Dbprintf(_YELLOW_("switched to EM4x50 reading mode")); - - memset(entry, 0, sizeof(entry)); - memset(words, 0, sizeof(words)); - - log_exists = exists_in_spiffs(LF_EM4X50COLLECT_LOGFILE); - - state_change = false; - } - - no_words = em4x50_standalone_read(words); - - if (no_words > 0) { - - memset(entry, 0, sizeof(entry)); - - sprintf((char *)entry, "found new EM4x50 tag:"); - Dbprintf("%s", entry); - strcat((char *)entry, "\n"); - append(LF_EM4X50COLLECT_LOGFILE, entry, strlen((char *)entry)); - - for (int i = 0; i < no_words; i++) { - - sprintf((char *)entry, " %2i -> 0x%08"PRIx32"", i + 1, words[i]); - Dbprintf("%s", entry); - strcat((char *)entry, "\n"); - append(LF_EM4X50COLLECT_LOGFILE, entry, strlen((char *)entry)); - } - } - - } else if (state == STATE_BRUTE) { - - if (state_change) { - - LEDsoff(); - LED_C_ON(); - Dbprintf(""); - Dbprintf(_YELLOW_("switched to EM4x50 brute force mode")); - - log_exists = exists_in_spiffs(LF_EM4X50BRUTE_LOGFILE); - now = get_input_data_from_file(passwords, LF_EM4X50BRUTE_INPUTFILE); - - if (now == 2) { - - // print some information - int no_iter = passwords[1] - passwords[0] + 1; - int dur_s = no_iter / EM4X50_PWD_SPEED; - int dur_h = dur_s / 3600; - int dur_m = (dur_s - dur_h * 3600) / 60; - dur_s -= dur_h * 3600 + dur_m * 60; - - //iterprint = no_iter/10; - - Dbprintf(_YELLOW_("trying %i passwords in range [0x%08x, 0x%08x]"), - no_iter, passwords[0], passwords[1]); - Dbprintf(_YELLOW_("estimated duration: %ih%im%is"), - dur_h, dur_m, dur_s); - - } else { - Dbprintf(_RED_("error in input data")); - break; - } - - state_change = false; - } - - pwd_found = em4x50_standalone_brute(passwords[0], passwords[1], &pwd); - - if (pwd_found == PM3_ETIMEOUT) { - - // timeout -> no EM4x50 tag on reader? - Dbprintf(_YELLOW_("timeout - no EM4x50 tag detected")); - - } else if (pwd_found == true) { - - // password found -> write to logfile - sprintf((char *)entry, "password found: 0x%08"PRIx32, pwd); - Dbprintf(_YELLOW_("%s"), entry); - strcat((char *)entry, "\n"); - append(LF_EM4X50BRUTE_LOGFILE, entry, strlen((char *)entry)); - - break; - - } else { - - if (pwd == passwords[1] + 1) { - - // finished without success -> write to logfile - sprintf((char *)entry, "no password found"); - Dbprintf(_YELLOW_("%s"), entry); - strcat((char *)entry, "\n"); - append(LF_EM4X50BRUTE_LOGFILE, entry, strlen((char *)entry)); - - - } else { - - // stopped -> write to logfile - sprintf((char *)entry, "stopped search - last password: 0x%08"PRIx32, pwd); - Dbprintf(_YELLOW_("%s"), entry); - strcat((char *)entry, "\n"); - append(LF_EM4X50BRUTE_LOGFILE, entry, strlen((char *)entry)); - - // replace start password by last tested password in - // inputfile (spiffs) so that brute forcing process will - // be continued when envoking brute force mode again - sprintf((char *)entry, "%08"PRIx32"\n%08"PRIx32"\n", pwd, passwords[1]); - rdv40_spiffs_write(LF_EM4X50BRUTE_INPUTFILE, - entry, - strlen((char *)entry), - RDV40_SPIFFS_SAFETY_SAFE); - - } - - break; - } - } - } - - if (state == STATE_READ) { - DownloadLogInstructions(LF_EM4X50COLLECT_LOGFILE); - } else if (state == STATE_BRUTE) { - LoadDataInstructions(LF_EM4X50BRUTE_INPUTFILE); - DownloadLogInstructions(LF_EM4X50BRUTE_LOGFILE); - } else { - LoadDataInstructions(LF_EM4X50SIMULATE_INPUTFILE); - } - - LED_D_ON(); - rdv40_spiffs_lazy_unmount(); - LED_D_OFF(); - - FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); - LEDsoff(); - Dbprintf(""); - Dbprintf(_YELLOW_("[=] Standalone mode THAREXDE stopped")); - -} From a04d67e82866fe5775467071d6c236312b9fecc0 Mon Sep 17 00:00:00 2001 From: Ave Date: Thu, 17 Dec 2020 23:23:31 +0300 Subject: [PATCH 102/682] emrtd: Dump image when dumping EF_DG2 --- client/src/cmdhfemrtd.c | 31 ++++++++++++++++++++++++++++++- 1 file changed, 30 insertions(+), 1 deletion(-) diff --git a/client/src/cmdhfemrtd.c b/client/src/cmdhfemrtd.c index 299f3e7c7..390b95866 100644 --- a/client/src/cmdhfemrtd.c +++ b/client/src/cmdhfemrtd.c @@ -704,6 +704,33 @@ static bool emrtd_select_and_read(uint8_t *dataout, int *dataoutlen, const char return true; } +static bool emrtd_dump_ef_dg2(uint8_t *file_contents, int file_length) { + uint8_t data[EMRTD_MAX_FILE_SIZE]; + int datalen = 0; + + // This is a hacky impl that just looks for the image header. I'll improve it eventually. + // based on mrpkey.py + // FF D8 FF E0 -> JPEG + // 00 00 00 0C 6A 50 -> JPEG 2000 + for (int i = 0; i < file_length - 6; i++) { + if ((file_contents[i] == 0xFF && file_contents[i + 1] == 0xD8 && file_contents[i + 2] == 0xFF && file_contents[i + 3] == 0xE0) || + (file_contents[i] == 0x00 && file_contents[i + 1] == 0x00 && file_contents[i + 2] == 0x00 && file_contents[i + 3] == 0x0C && file_contents[i + 4] == 0x6A && file_contents[i + 5] == 0x50)) { + datalen = file_length - i; + memcpy(data, file_contents + i, datalen); + break; + } + } + + // If we didn't get any data, return false. + if (datalen == 0) { + return false; + } + + saveFile("EF_DG2", ".jpg", data, datalen); + return true; +} + + static bool emrtd_dump_ef_dg5(uint8_t *file_contents, int file_length) { uint8_t data[EMRTD_MAX_FILE_SIZE]; int datalen = 0; @@ -741,7 +768,9 @@ static bool emrtd_dump_file(uint8_t *ks_enc, uint8_t *ks_mac, uint8_t *ssc, cons PrintAndLogEx(DEBUG, "Contents (may be incomplete over 2k chars): %s", sprint_hex_inrow(response, resplen)); saveFile(name, ".BIN", response, resplen); - if (strcmp(file, EMRTD_EF_DG5) == 0) { + if (strcmp(file, EMRTD_EF_DG2) == 0) { + emrtd_dump_ef_dg2(response, resplen); + } else if (strcmp(file, EMRTD_EF_DG5) == 0) { emrtd_dump_ef_dg5(response, resplen); } else if (strcmp(file, EMRTD_EF_SOD) == 0) { emrtd_dump_ef_sod(response, resplen); From 2d00fcea98c31c65b9c16c6c1fb6bb08d6acdfa1 Mon Sep 17 00:00:00 2001 From: tharexde Date: Thu, 17 Dec 2020 21:28:19 +0100 Subject: [PATCH 103/682] added function eview for EM4x50 --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index a4898db8b..a1b430303 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 em 4x50 eview` - show uploaded EM4x50 data in emul memory (@tharexde) - Fix `data rawdemod` parsing for psk2 and user defined clock (@cyberpunk-re) - Added `hf iclass encode` - encode a wiegand binary to a encrypted credential (@iceman1001) - Changed `recoverpk.py` - now tests more ECDSA curves (@doegox) From f48f85469eca01c3ef070e0dd0aba622bc20fea2 Mon Sep 17 00:00:00 2001 From: iceman1001 Date: Thu, 17 Dec 2020 21:56:56 +0100 Subject: [PATCH 104/682] fix 308195 coverity --- client/src/cmdhfemrtd.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/src/cmdhfemrtd.c b/client/src/cmdhfemrtd.c index 390b95866..416234c7f 100644 --- a/client/src/cmdhfemrtd.c +++ b/client/src/cmdhfemrtd.c @@ -813,7 +813,7 @@ static bool emrtd_do_bac(char *documentnumber, char *dob, char *expiry, uint8_t sprintf(kmrz, "%s%i%s%i%s%i", documentnumber, documentnumbercd, dob, dobcd, expiry, expirycd); PrintAndLogEx(DEBUG, "kmrz.............. " _GREEN_("%s"), kmrz); - uint8_t kseed[16] = { 0x00 }; + uint8_t kseed[20] = { 0x00 }; mbedtls_sha1((unsigned char *)kmrz, strlen(kmrz), kseed); PrintAndLogEx(DEBUG, "kseed (sha1)...... %s ", sprint_hex_inrow(kseed, 16)); From 254235237edcab79af824727140d5afe1d3d3554 Mon Sep 17 00:00:00 2001 From: Philippe Teuwen Date: Thu, 17 Dec 2020 22:06:44 +0100 Subject: [PATCH 105/682] emrtd: fix emrtd_read_binary params --- client/src/cmdhfemrtd.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/src/cmdhfemrtd.c b/client/src/cmdhfemrtd.c index 390b95866..e73ed19f3 100644 --- a/client/src/cmdhfemrtd.c +++ b/client/src/cmdhfemrtd.c @@ -320,7 +320,7 @@ static int emrtd_external_authenticate(uint8_t *data, int length, uint8_t *datao static int _emrtd_read_binary(int offset, int bytes_to_read, uint8_t *dataout, int *dataoutlen, bool use_14b) { char cmd[50]; - sprintf(cmd, "00%s%04i%02i", EMRTD_READ_BINARY, offset, bytes_to_read); + sprintf(cmd, "00%s%04X%02X", EMRTD_READ_BINARY, offset, bytes_to_read); return emrtd_exchange_commands(cmd, dataout, dataoutlen, false, true, use_14b); } From 814e7c2536392c8680be3161abe15b72af27b402 Mon Sep 17 00:00:00 2001 From: iceman1001 Date: Thu, 17 Dec 2020 22:15:33 +0100 Subject: [PATCH 106/682] fix 308198 coverity --- client/src/cmdhfemrtd.c | 49 +++++++++++++++++++++++++---------------- 1 file changed, 30 insertions(+), 19 deletions(-) diff --git a/client/src/cmdhfemrtd.c b/client/src/cmdhfemrtd.c index 416234c7f..9e403350d 100644 --- a/client/src/cmdhfemrtd.c +++ b/client/src/cmdhfemrtd.c @@ -164,10 +164,10 @@ static int emrtd_get_asn1_data_length(uint8_t *datain, int datainlen, int offset } static int emrtd_get_asn1_field_length(uint8_t *datain, int datainlen, int offset) { - PrintAndLogEx(DEBUG, "asn1fieldlength, datain: %s", sprint_hex_inrow(datain, datainlen)); + PrintAndLogEx(DEBUG, "asn1 fieldlength, datain: %s", sprint_hex_inrow(datain, datainlen)); int lenfield = (int) * (datain + offset); - PrintAndLogEx(DEBUG, "asn1fieldlength, thing: %i", lenfield); - if (lenfield <= 0x7f) { + PrintAndLogEx(DEBUG, "asn1 fieldlength, thing: %i", lenfield); + if (lenfield <= 0x7F) { return 1; } else if (lenfield == 0x81) { return 2; @@ -571,31 +571,32 @@ static int emrtd_read_file(uint8_t *dataout, int *dataoutlen, uint8_t *kenc, uin static bool emrtd_lds_get_data_by_tag(uint8_t *datain, int *datainlen, uint8_t *dataout, int *dataoutlen, int tag1, int tag2, bool twobytetag) { int offset = 1; offset += emrtd_get_asn1_field_length(datain, *datainlen, offset); - int elementidlen = 0; - int elementlen = 0; - int elementlenlen = 0; + + int e_idlen = 0; + int e_datalen = 0; + int e_fieldlen = 0; while (offset < *datainlen) { PrintAndLogEx(DEBUG, "emrtd_lds_get_data_by_tag, offset: %i, data: %X", offset, *(datain + offset)); // Determine element ID length to set as offset on asn1datalength - if ((*(datain + offset) == 0x5f) || (*(datain + offset) == 0x7f)) { - elementidlen = 2; + if ((*(datain + offset) == 0x5F) || (*(datain + offset) == 0x7F)) { + e_idlen = 2; } else { - elementidlen = 1; + e_idlen = 1; } // Get the length of the element - elementlen = emrtd_get_asn1_data_length(datain + offset, *datainlen - offset, elementidlen); + e_datalen = emrtd_get_asn1_data_length(datain + offset, *datainlen - offset, e_idlen); // Get the length of the element's length - elementlenlen = emrtd_get_asn1_field_length(datain + offset, *datainlen - offset, elementidlen); + e_fieldlen = emrtd_get_asn1_field_length(datain + offset, *datainlen - offset, e_idlen); // If the element is what we're looking for, get the data and return true if (*(datain + offset) == tag1 && (!twobytetag || *(datain + offset + 1) == tag2)) { - *dataoutlen = elementlen; - memcpy(dataout, datain + offset + elementidlen + elementlenlen, elementlen); + *dataoutlen = e_datalen; + memcpy(dataout, datain + offset + e_idlen + e_fieldlen, e_datalen); return true; } - offset += elementidlen + elementlen + elementlenlen; + offset += e_idlen + e_datalen + e_fieldlen; } // Return false if we can't find the relevant element return false; @@ -736,21 +737,31 @@ static bool emrtd_dump_ef_dg5(uint8_t *file_contents, int file_length) { int datalen = 0; // If we can't find image in EF_DG5, return false. - if (!emrtd_lds_get_data_by_tag(file_contents, &file_length, data, &datalen, 0x5f, 0x40, true)) { + if (emrtd_lds_get_data_by_tag(file_contents, &file_length, data, &datalen, 0x5F, 0x40, true) == false) { return false; } - saveFile("EF_DG5", ".jpg", data, datalen); + if (datalen < EMRTD_MAX_FILE_SIZE) { + saveFile("EF_DG5", ".jpg", data, datalen); + } else { + PrintAndLogEx(ERR, "error (emrtd_dump_ef_dg5) datalen out-of-bounds"); + return false; + } return true; } static bool emrtd_dump_ef_sod(uint8_t *file_contents, int file_length) { uint8_t data[EMRTD_MAX_FILE_SIZE]; - int datalenlen = emrtd_get_asn1_field_length(file_contents, file_length, 1); + int fieldlen = emrtd_get_asn1_field_length(file_contents, file_length, 1); int datalen = emrtd_get_asn1_data_length(file_contents, file_length, 1); - - memcpy(data, file_contents + datalenlen + 1, datalen); + + if (fieldlen + 1 < EMRTD_MAX_FILE_SIZE) { + memcpy(data, file_contents + fieldlen + 1, datalen); + } else { + PrintAndLogEx(ERR, "error (emrtd_dump_ef_sod) fieldlen out-of-bounds"); + return false; + } saveFile("EF_SOD", ".p7b", data, datalen); return true; From f0d3cdec6728b8f6c5a372eb995e3f8e601afa99 Mon Sep 17 00:00:00 2001 From: iceman1001 Date: Thu, 17 Dec 2020 22:20:07 +0100 Subject: [PATCH 107/682] fix 308197 coverity --- client/src/cmdhfemrtd.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/client/src/cmdhfemrtd.c b/client/src/cmdhfemrtd.c index 9e403350d..7e099775e 100644 --- a/client/src/cmdhfemrtd.c +++ b/client/src/cmdhfemrtd.c @@ -518,7 +518,6 @@ static bool _emrtd_secure_read_binary_decrypt(uint8_t *kenc, uint8_t *kmac, uint return true; } - static int emrtd_read_file(uint8_t *dataout, int *dataoutlen, uint8_t *kenc, uint8_t *kmac, uint8_t *ssc, bool use_secure, bool use_14b) { uint8_t response[EMRTD_MAX_FILE_SIZE]; int resplen = 0; @@ -592,9 +591,15 @@ static bool emrtd_lds_get_data_by_tag(uint8_t *datain, int *datainlen, uint8_t * // If the element is what we're looking for, get the data and return true if (*(datain + offset) == tag1 && (!twobytetag || *(datain + offset + 1) == tag2)) { - *dataoutlen = e_datalen; - memcpy(dataout, datain + offset + e_idlen + e_fieldlen, e_datalen); - return true; + + if ( *datainlen > e_datalen) { + *dataoutlen = e_datalen; + memcpy(dataout, datain + offset + e_idlen + e_fieldlen, e_datalen); + return true; + } else { + PrintAndLogEx(ERR, "error (emrtd_lds_get_data_by_tag) e_datalen out-of-bounds"); + return false; + } } offset += e_idlen + e_datalen + e_fieldlen; } From ef7a6bb166cdeeecf12244113ffd9636b5732d14 Mon Sep 17 00:00:00 2001 From: iceman1001 Date: Thu, 17 Dec 2020 22:54:23 +0100 Subject: [PATCH 108/682] text --- client/luascripts/hf_mfu_magicwrite.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/luascripts/hf_mfu_magicwrite.lua b/client/luascripts/hf_mfu_magicwrite.lua index 2961bd54c..4b4d7178a 100644 --- a/client/luascripts/hf_mfu_magicwrite.lua +++ b/client/luascripts/hf_mfu_magicwrite.lua @@ -60,7 +60,7 @@ arguments = [[ -p password (8 hexsymbols), set password on tag. -a pack ( 4 hexsymbols), set pack on tag. -s signature data (64 hexsymbols), set signature data on tag. - -o OTP data (8 hexsymbols), set one-time-pad data on tag. + -o OTP data (8 hexsymbols), set `one time programmable` data on tag. -v version data (16 hexsymbols), set version data on tag. -w wipe tag. You can specify password if the tag has been locked down. Fills tag with zeros and put default values for NTAG213 (like -t 5) -k pwd to use with the wipe option From fbed338dcef7f98fb2d921fa274a621d70000a40 Mon Sep 17 00:00:00 2001 From: Ave Date: Fri, 18 Dec 2020 02:39:48 +0300 Subject: [PATCH 109/682] emrtd: don't check for EF_CardAccess, and dump it on hf emrtd dump --- client/src/cmdhfemrtd.c | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) diff --git a/client/src/cmdhfemrtd.c b/client/src/cmdhfemrtd.c index bdf19bfca..8d0aaecaa 100644 --- a/client/src/cmdhfemrtd.c +++ b/client/src/cmdhfemrtd.c @@ -937,15 +937,6 @@ static bool emrtd_do_auth(char *documentnumber, char *dob, char *expiry, bool BA uint8_t response[EMRTD_MAX_FILE_SIZE] = { 0x00 }; int resplen = 0; - // Select and read EF_CardAccess - if (emrtd_select_file(EMRTD_P1_SELECT_BY_EF, EMRTD_EF_CARDACCESS, *use_14b)) { - emrtd_read_file(response, &resplen, NULL, NULL, NULL, false, *use_14b); - PrintAndLogEx(INFO, "Read EF_CardAccess, len: %i.", resplen); - PrintAndLogEx(DEBUG, "Contents (may be incomplete over 2k chars): %s", sprint_hex_inrow(response, resplen)); - } else { - PrintAndLogEx(INFO, "PACE unsupported. Will not read EF_CardAccess."); - } - // Select MRTD applet if (emrtd_select_file(EMRTD_P1_SELECT_BY_NAME, EMRTD_AID_MRTD, *use_14b) == false) { PrintAndLogEx(ERR, "Couldn't select the MRTD application."); @@ -1041,8 +1032,12 @@ int dumpHF_EMRTD(char *documentnumber, char *dob, char *expiry, bool BAC_availab emrtd_dump_file(ks_enc, ks_mac, ssc, file_id, file_name, BAC, use_14b); } - // Dump EF_SOD + // Dump EF_SOD and EF_CardAccess (if available) emrtd_dump_file(ks_enc, ks_mac, ssc, EMRTD_EF_SOD, "EF_SOD", BAC, use_14b); + if (!emrtd_dump_file(ks_enc, ks_mac, ssc, EMRTD_EF_CARDACCESS, "EF_CardAccess", BAC, use_14b)) { + PrintAndLogEx(INFO, "Couldn't dump EF_CardAccess, card does not support PACE."); + PrintAndLogEx(HINT, "This is expected behavior for cards without PACE, and isn't something to be worried about."); + } DropField(); return PM3_SUCCESS; From ffb71118359a6d5a99eb3c5157fdd98aada7095c Mon Sep 17 00:00:00 2001 From: Ave Date: Fri, 18 Dec 2020 03:06:42 +0300 Subject: [PATCH 110/682] emrtd: Ensure that DOB and doc expiry lengths are correct --- client/src/cmdhfemrtd.c | 30 +++++++++++++++++++++++++++--- 1 file changed, 27 insertions(+), 3 deletions(-) diff --git a/client/src/cmdhfemrtd.c b/client/src/cmdhfemrtd.c index 8d0aaecaa..2f409d5e4 100644 --- a/client/src/cmdhfemrtd.c +++ b/client/src/cmdhfemrtd.c @@ -1324,10 +1324,22 @@ static int cmd_hf_emrtd_dump(const char *Cmd) { if (CLIParamStrToBuf(arg_get_str(ctx, 2), dob, 6, &slen) != 0 || slen == 0) { BAC = false; - } + } else { + if (slen != 6) { + PrintAndLogEx(ERR, "Date of Birth length is incorrect, cannot continue."); + PrintAndLogEx(HINT, "Use the format YYMMDD."); + return PM3_ESOFT; + } + } if (CLIParamStrToBuf(arg_get_str(ctx, 3), expiry, 6, &slen) != 0 || slen == 0) { BAC = false; + } else { + if (slen != 6) { + PrintAndLogEx(ERR, "Document expiry length is incorrect, cannot continue."); + PrintAndLogEx(HINT, "Use the format YYMMDD."); + return PM3_ESOFT; + } } CLIParserFree(ctx); @@ -1359,17 +1371,29 @@ static int cmd_hf_emrtd_info(const char *Cmd) { if (CLIParamStrToBuf(arg_get_str(ctx, 1), docnum, 9, &slen) != 0 || slen == 0) { BAC = false; } else { - if ( slen != 9) { + if (slen != 9) { memset(docnum + slen, 0x3c, 9 - slen); } } if (CLIParamStrToBuf(arg_get_str(ctx, 2), dob, 6, &slen) != 0 || slen == 0) { BAC = false; - } + } else { + if (slen != 6) { + PrintAndLogEx(ERR, "Date of Birth length is incorrect, cannot continue."); + PrintAndLogEx(HINT, "Use the format YYMMDD."); + return PM3_ESOFT; + } + } if (CLIParamStrToBuf(arg_get_str(ctx, 3), expiry, 6, &slen) != 0 || slen == 0) { BAC = false; + } else { + if (slen != 6) { + PrintAndLogEx(ERR, "Document expiry length is incorrect, cannot continue."); + PrintAndLogEx(HINT, "Use the format YYMMDD."); + return PM3_ESOFT; + } } CLIParserFree(ctx); From 45d55106c6c9689ac5e0dc741a7ce50423cb9be7 Mon Sep 17 00:00:00 2001 From: Ave Date: Fri, 18 Dec 2020 03:13:06 +0300 Subject: [PATCH 111/682] emrtd: Auto-convert document number to uppercase --- client/src/cmdhfemrtd.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/client/src/cmdhfemrtd.c b/client/src/cmdhfemrtd.c index 2f409d5e4..ae38ebc73 100644 --- a/client/src/cmdhfemrtd.c +++ b/client/src/cmdhfemrtd.c @@ -1291,6 +1291,15 @@ int infoHF_EMRTD(char *documentnumber, char *dob, char *expiry, bool BAC_availab return PM3_SUCCESS; } +static void text_to_upper(uint8_t *data, int datalen) { + // Loop over text to make lowercase text uppercase + for (int i = 0; i < datalen; i++) { + if ('a' <= data[i] && data[i] <= 'z') { + data[i] -= 32; + } + } +} + static int cmd_hf_emrtd_dump(const char *Cmd) { CLIParserContext *ctx; CLIParserInit(&ctx, "hf emrtd dump", @@ -1316,6 +1325,7 @@ static int cmd_hf_emrtd_dump(const char *Cmd) { if (CLIParamStrToBuf(arg_get_str(ctx, 1), docnum, 9, &slen) != 0 || slen == 0) { BAC = false; } else { + text_to_upper(docnum, slen); if (slen != 9) { // Pad to 9 with < memset(docnum + slen, 0x3c, 9 - slen); @@ -1371,6 +1381,8 @@ static int cmd_hf_emrtd_info(const char *Cmd) { if (CLIParamStrToBuf(arg_get_str(ctx, 1), docnum, 9, &slen) != 0 || slen == 0) { BAC = false; } else { + text_to_upper(docnum, slen); + PrintAndLogEx(HINT, "%.*s.", slen, (char *) docnum); if (slen != 9) { memset(docnum + slen, 0x3c, 9 - slen); } From 3312230e80d2d9f952ed234ef854909fcf3582d3 Mon Sep 17 00:00:00 2001 From: Ave Date: Fri, 18 Dec 2020 03:15:14 +0300 Subject: [PATCH 112/682] emrtd: Remove debug line --- client/src/cmdhfemrtd.c | 1 - 1 file changed, 1 deletion(-) diff --git a/client/src/cmdhfemrtd.c b/client/src/cmdhfemrtd.c index ae38ebc73..e77fc277b 100644 --- a/client/src/cmdhfemrtd.c +++ b/client/src/cmdhfemrtd.c @@ -1382,7 +1382,6 @@ static int cmd_hf_emrtd_info(const char *Cmd) { BAC = false; } else { text_to_upper(docnum, slen); - PrintAndLogEx(HINT, "%.*s.", slen, (char *) docnum); if (slen != 9) { memset(docnum + slen, 0x3c, 9 - slen); } From 027f4e5adc78edbed67694c992c88a63b8c76077 Mon Sep 17 00:00:00 2001 From: Ave Date: Fri, 18 Dec 2020 03:26:26 +0300 Subject: [PATCH 113/682] emrtd: Use toupper --- client/src/cmdhfemrtd.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/client/src/cmdhfemrtd.c b/client/src/cmdhfemrtd.c index e77fc277b..dc07744fe 100644 --- a/client/src/cmdhfemrtd.c +++ b/client/src/cmdhfemrtd.c @@ -1294,9 +1294,7 @@ int infoHF_EMRTD(char *documentnumber, char *dob, char *expiry, bool BAC_availab static void text_to_upper(uint8_t *data, int datalen) { // Loop over text to make lowercase text uppercase for (int i = 0; i < datalen; i++) { - if ('a' <= data[i] && data[i] <= 'z') { - data[i] -= 32; - } + data[i] = toupper(data[i]); } } From 79e9875b43bf893ba818a918ae850a569bb91ce2 Mon Sep 17 00:00:00 2001 From: Ave Date: Fri, 18 Dec 2020 03:29:21 +0300 Subject: [PATCH 114/682] emrtd: Validate date further --- client/src/cmdhfemrtd.c | 32 ++++++++++++++++++++++++-------- 1 file changed, 24 insertions(+), 8 deletions(-) diff --git a/client/src/cmdhfemrtd.c b/client/src/cmdhfemrtd.c index dc07744fe..5f6c12891 100644 --- a/client/src/cmdhfemrtd.c +++ b/client/src/cmdhfemrtd.c @@ -1298,6 +1298,22 @@ static void text_to_upper(uint8_t *data, int datalen) { } } +static bool validate_date(uint8_t *data, int datalen) { + // Date has to be 6 chars + if (datalen != 6) { + return false; + } + + // Check for valid date and month numbers + char temp[4] = { 0x00 }; + memcpy(temp, data + 2, 2); + int month = (int) strtol(temp, NULL, 10); + memcpy(temp, data + 4, 2); + int day = (int) strtol(temp, NULL, 10); + + return !(day <= 0 || day > 31 || month <= 0 || month > 12); +} + static int cmd_hf_emrtd_dump(const char *Cmd) { CLIParserContext *ctx; CLIParserInit(&ctx, "hf emrtd dump", @@ -1333,8 +1349,8 @@ static int cmd_hf_emrtd_dump(const char *Cmd) { if (CLIParamStrToBuf(arg_get_str(ctx, 2), dob, 6, &slen) != 0 || slen == 0) { BAC = false; } else { - if (slen != 6) { - PrintAndLogEx(ERR, "Date of Birth length is incorrect, cannot continue."); + if (!validate_date(dob, slen)) { + PrintAndLogEx(ERR, "Date of birth date format is incorrect, cannot continue."); PrintAndLogEx(HINT, "Use the format YYMMDD."); return PM3_ESOFT; } @@ -1343,8 +1359,8 @@ static int cmd_hf_emrtd_dump(const char *Cmd) { if (CLIParamStrToBuf(arg_get_str(ctx, 3), expiry, 6, &slen) != 0 || slen == 0) { BAC = false; } else { - if (slen != 6) { - PrintAndLogEx(ERR, "Document expiry length is incorrect, cannot continue."); + if (!validate_date(expiry, slen)) { + PrintAndLogEx(ERR, "Expiry date format is incorrect, cannot continue."); PrintAndLogEx(HINT, "Use the format YYMMDD."); return PM3_ESOFT; } @@ -1388,8 +1404,8 @@ static int cmd_hf_emrtd_info(const char *Cmd) { if (CLIParamStrToBuf(arg_get_str(ctx, 2), dob, 6, &slen) != 0 || slen == 0) { BAC = false; } else { - if (slen != 6) { - PrintAndLogEx(ERR, "Date of Birth length is incorrect, cannot continue."); + if (!validate_date(dob, slen)) { + PrintAndLogEx(ERR, "Date of birth date format is incorrect, cannot continue."); PrintAndLogEx(HINT, "Use the format YYMMDD."); return PM3_ESOFT; } @@ -1398,8 +1414,8 @@ static int cmd_hf_emrtd_info(const char *Cmd) { if (CLIParamStrToBuf(arg_get_str(ctx, 3), expiry, 6, &slen) != 0 || slen == 0) { BAC = false; } else { - if (slen != 6) { - PrintAndLogEx(ERR, "Document expiry length is incorrect, cannot continue."); + if (!validate_date(expiry, slen)) { + PrintAndLogEx(ERR, "Expiry date format is incorrect, cannot continue."); PrintAndLogEx(HINT, "Use the format YYMMDD."); return PM3_ESOFT; } From ffb1b662ac5452bd3f63c6715c66add19a8fe787 Mon Sep 17 00:00:00 2001 From: Philippe Teuwen Date: Fri, 18 Dec 2020 00:54:14 +0100 Subject: [PATCH 115/682] allowing user timeouts in 14b apdus --- armsrc/iso14443b.c | 4 +++- client/src/cmdhf14b.c | 37 +++++++++++++++++++++++++------------ client/src/cmdhf14b.h | 2 +- client/src/cmdhfemrtd.c | 3 ++- 4 files changed, 31 insertions(+), 15 deletions(-) diff --git a/armsrc/iso14443b.c b/armsrc/iso14443b.c index f170be153..a5b15a0c0 100644 --- a/armsrc/iso14443b.c +++ b/armsrc/iso14443b.c @@ -1400,7 +1400,9 @@ int iso14443b_apdu(uint8_t const *msg, size_t msg_len, bool send_chaining, void CodeAndTransmit14443bAsReader(real_cmd, msg_len + 3, &start_time, &eof_time); eof_time += DELAY_ISO14443B_VCD_TO_VICC_READER; - int len = Get14443bAnswerFromTag(rxdata, rxmaxlen, ISO14443B_READER_TIMEOUT, &eof_time); + +// int len = Get14443bAnswerFromTag(rxdata, rxmaxlen, ISO14443B_READER_TIMEOUT, &eof_time); + int len = Get14443bAnswerFromTag(rxdata, rxmaxlen, iso14b_timeout, &eof_time); FpgaDisableTracing(); uint8_t *data_bytes = (uint8_t *) rxdata; diff --git a/client/src/cmdhf14b.c b/client/src/cmdhf14b.c index e21509fe8..ffec87950 100644 --- a/client/src/cmdhf14b.c +++ b/client/src/cmdhf14b.c @@ -1415,7 +1415,7 @@ static int select_card_14443b_4(bool disconnect, iso14b_card_select_t *card) { return PM3_SUCCESS; } -static int handle_14b_apdu(bool chainingin, uint8_t *datain, int datainlen, bool activateField, uint8_t *dataout, int maxdataoutlen, int *dataoutlen, bool *chainingout) { +static int handle_14b_apdu(bool chainingin, uint8_t *datain, int datainlen, bool activateField, uint8_t *dataout, int maxdataoutlen, int *dataoutlen, bool *chainingout, int user_timeout) { *chainingout = false; if (activateField) { @@ -1430,13 +1430,24 @@ static int handle_14b_apdu(bool chainingin, uint8_t *datain, int datainlen, bool if (chainingin) flags = ISO14B_SEND_CHAINING; + uint32_t time_wait = 0; + if (user_timeout > 0) { +#define MAX_14B_TIMEOUT 40542464 // = (2^32-1) * (8*16) / 13560000Hz * 1000ms/s + flags |= ISO14B_SET_TIMEOUT; + if (user_timeout > MAX_14B_TIMEOUT) { + user_timeout = MAX_14B_TIMEOUT; + PrintAndLogEx(INFO, "set timeout to 40542 seconds (11.26 hours). The max we can wait for response"); + } + time_wait = 13560000 / 1000 / (8 * 16) * user_timeout; // timeout in ETUs (time to transfer 1 bit, approx. 9.4 us) + } + // "Command APDU" length should be 5+255+1, but javacard's APDU buffer might be smaller - 133 bytes // https://stackoverflow.com/questions/32994936/safe-max-java-card-apdu-data-command-and-respond-size // here length PM3_CMD_DATA_SIZE=512 if (datain) - SendCommandMIX(CMD_HF_ISO14443B_COMMAND, ISO14B_APDU | flags, (datainlen & 0xFFFF), 0, datain, datainlen & 0xFFFF); + SendCommandMIX(CMD_HF_ISO14443B_COMMAND, ISO14B_APDU | flags, (datainlen & 0xFFFF), time_wait, datain, datainlen & 0xFFFF); else - SendCommandMIX(CMD_HF_ISO14443B_COMMAND, ISO14B_APDU | flags, 0, 0, NULL, 0); + SendCommandMIX(CMD_HF_ISO14443B_COMMAND, ISO14B_APDU | flags, 0, time_wait, NULL, 0); PacketResponseNG resp; if (WaitForResponseTimeout(CMD_HF_ISO14443B_COMMAND, &resp, APDU_TIMEOUT)) { @@ -1489,7 +1500,7 @@ static int handle_14b_apdu(bool chainingin, uint8_t *datain, int datainlen, bool return PM3_SUCCESS; } -int exchange_14b_apdu(uint8_t *datain, int datainlen, bool activate_field, bool leave_signal_on, uint8_t *dataout, int maxdataoutlen, int *dataoutlen) { +int exchange_14b_apdu(uint8_t *datain, int datainlen, bool activate_field, bool leave_signal_on, uint8_t *dataout, int maxdataoutlen, int *dataoutlen, int user_timeout) { *dataoutlen = 0; bool chaining = false; int res; @@ -1506,7 +1517,7 @@ int exchange_14b_apdu(uint8_t *datain, int datainlen, bool activate_field, bool bool chainBlockNotLast = ((clen + vlen) < datainlen); *dataoutlen = 0; - res = handle_14b_apdu(chainBlockNotLast, &datain[clen], vlen, v_activate_field, dataout, maxdataoutlen, dataoutlen, &chaining); + res = handle_14b_apdu(chainBlockNotLast, &datain[clen], vlen, v_activate_field, dataout, maxdataoutlen, dataoutlen, &chaining, user_timeout); if (res) { if (leave_signal_on == false) switch_off_field_14b(); @@ -1535,7 +1546,7 @@ int exchange_14b_apdu(uint8_t *datain, int datainlen, bool activate_field, bool } else { - res = handle_14b_apdu(false, datain, datainlen, activate_field, dataout, maxdataoutlen, dataoutlen, &chaining); + res = handle_14b_apdu(false, datain, datainlen, activate_field, dataout, maxdataoutlen, dataoutlen, &chaining, user_timeout); if (res != PM3_SUCCESS) { if (leave_signal_on == false) { switch_off_field_14b(); @@ -1546,7 +1557,7 @@ int exchange_14b_apdu(uint8_t *datain, int datainlen, bool activate_field, bool while (chaining) { // I-block with chaining - res = handle_14b_apdu(false, NULL, 0, false, &dataout[*dataoutlen], maxdataoutlen, dataoutlen, &chaining); + res = handle_14b_apdu(false, NULL, 0, false, &dataout[*dataoutlen], maxdataoutlen, dataoutlen, &chaining, user_timeout); if (res != PM3_SUCCESS) { if (leave_signal_on == false) { switch_off_field_14b(); @@ -1594,6 +1605,7 @@ static int CmdHF14BAPDU(const char *Cmd) { arg_lit0("e", "extended", "make extended length apdu if `m` parameter included"), arg_int0("l", "le", "", "Le apdu parameter if `m` parameter included"), arg_strx1(NULL, "hex", "", " if `m` parameter included"), + arg_int0(NULL, "timeout", "", "timeout in ms"), arg_param_end }; CLIExecWithReturn(ctx, Cmd, argtable, false); @@ -1653,6 +1665,7 @@ static int CmdHF14BAPDU(const char *Cmd) { // len = data + PCB(1b) + CRC(2b) CLIGetHexBLessWithReturn(ctx, 8, data, &datalen, 1 + 2); } + int user_timeout = arg_get_int_def(ctx, 9, -1); CLIParserFree(ctx); PrintAndLogEx(NORMAL, ">>>>[%s%s%s] %s", @@ -1670,7 +1683,7 @@ static int CmdHF14BAPDU(const char *Cmd) { PrintAndLogEx(WARNING, "can't decode APDU."); } - int res = exchange_14b_apdu(data, datalen, activate_field, leave_signal_on, data, PM3_CMD_DATA_SIZE, &datalen); + int res = exchange_14b_apdu(data, datalen, activate_field, leave_signal_on, data, PM3_CMD_DATA_SIZE, &datalen, user_timeout); if (res != PM3_SUCCESS) { return res; } @@ -1709,7 +1722,7 @@ static int CmdHF14BNdef(const char *Cmd) { uint8_t aSELECT_AID[80]; int aSELECT_AID_n = 0; param_gethex_to_eol("00a4040007d276000085010100", 0, aSELECT_AID, sizeof(aSELECT_AID), &aSELECT_AID_n); - int res = exchange_14b_apdu(aSELECT_AID, aSELECT_AID_n, activate_field, keep_field_on, response, sizeof(response), &resplen); + int res = exchange_14b_apdu(aSELECT_AID, aSELECT_AID_n, activate_field, keep_field_on, response, sizeof(response), &resplen, -1); if (res) { goto out; } @@ -1735,7 +1748,7 @@ static int CmdHF14BNdef(const char *Cmd) { uint8_t aSELECT_FILE_NDEF[30]; int aSELECT_FILE_NDEF_n = 0; param_gethex_to_eol("00a4000c020001", 0, aSELECT_FILE_NDEF, sizeof(aSELECT_FILE_NDEF), &aSELECT_FILE_NDEF_n); - res = exchange_14b_apdu(aSELECT_FILE_NDEF, aSELECT_FILE_NDEF_n, activate_field, keep_field_on, response, sizeof(response), &resplen); + res = exchange_14b_apdu(aSELECT_FILE_NDEF, aSELECT_FILE_NDEF_n, activate_field, keep_field_on, response, sizeof(response), &resplen, -1); if (res) goto out; @@ -1750,7 +1763,7 @@ static int CmdHF14BNdef(const char *Cmd) { uint8_t aREAD_NDEF[30]; int aREAD_NDEF_n = 0; param_gethex_to_eol("00b0000002", 0, aREAD_NDEF, sizeof(aREAD_NDEF), &aREAD_NDEF_n); - res = exchange_14b_apdu(aREAD_NDEF, aREAD_NDEF_n, activate_field, keep_field_on, response, sizeof(response), &resplen); + res = exchange_14b_apdu(aREAD_NDEF, aREAD_NDEF_n, activate_field, keep_field_on, response, sizeof(response), &resplen, -1); if (res) { goto out; } @@ -1769,7 +1782,7 @@ static int CmdHF14BNdef(const char *Cmd) { aREAD_NDEF_n = 0; param_gethex_to_eol("00b00002", 0, aREAD_NDEF, sizeof(aREAD_NDEF), &aREAD_NDEF_n); aREAD_NDEF[4] = offset; - res = exchange_14b_apdu(aREAD_NDEF, aREAD_NDEF_n, activate_field, keep_field_on, response, sizeof(response), &resplen); + res = exchange_14b_apdu(aREAD_NDEF, aREAD_NDEF_n, activate_field, keep_field_on, response, sizeof(response), &resplen, -1); if (res) { goto out; } diff --git a/client/src/cmdhf14b.h b/client/src/cmdhf14b.h index d236bb6cf..9bbb17625 100644 --- a/client/src/cmdhf14b.h +++ b/client/src/cmdhf14b.h @@ -15,7 +15,7 @@ int CmdHF14B(const char *Cmd); -int exchange_14b_apdu(uint8_t *datain, int datainlen, bool activate_field, bool leave_signal_on, uint8_t *dataout, int maxdataoutlen, int *dataoutlen); +int exchange_14b_apdu(uint8_t *datain, int datainlen, bool activate_field, bool leave_signal_on, uint8_t *dataout, int maxdataoutlen, int *dataoutlen, int user_timeout); int infoHF14B(bool verbose); int readHF14B(bool verbose); diff --git a/client/src/cmdhfemrtd.c b/client/src/cmdhfemrtd.c index bdf19bfca..619b9cf58 100644 --- a/client/src/cmdhfemrtd.c +++ b/client/src/cmdhfemrtd.c @@ -92,7 +92,8 @@ static bool emrtd_exchange_commands(const char *cmd, uint8_t *dataout, int *data param_gethex_to_eol(cmd, 0, aCMD, sizeof(aCMD), &aCMD_n); int res; if (use_14b) { - res = exchange_14b_apdu(aCMD, aCMD_n, activate_field, keep_field_on, response, sizeof(response), &resplen); + // need to add a long timeout for passports with activated anti-bruteforce measure + res = exchange_14b_apdu(aCMD, aCMD_n, activate_field, keep_field_on, response, sizeof(response), &resplen, 15000); } else { res = ExchangeAPDU14a(aCMD, aCMD_n, activate_field, keep_field_on, response, sizeof(response), &resplen); } From 204ae46bf70351ff11de1ff2d3f942007fd1c4fd Mon Sep 17 00:00:00 2001 From: Philippe Teuwen Date: Fri, 18 Dec 2020 00:56:42 +0100 Subject: [PATCH 116/682] minor --- armsrc/iso14443b.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/armsrc/iso14443b.c b/armsrc/iso14443b.c index a5b15a0c0..11542a498 100644 --- a/armsrc/iso14443b.c +++ b/armsrc/iso14443b.c @@ -1400,8 +1400,6 @@ int iso14443b_apdu(uint8_t const *msg, size_t msg_len, bool send_chaining, void CodeAndTransmit14443bAsReader(real_cmd, msg_len + 3, &start_time, &eof_time); eof_time += DELAY_ISO14443B_VCD_TO_VICC_READER; - -// int len = Get14443bAnswerFromTag(rxdata, rxmaxlen, ISO14443B_READER_TIMEOUT, &eof_time); int len = Get14443bAnswerFromTag(rxdata, rxmaxlen, iso14b_timeout, &eof_time); FpgaDisableTracing(); From 975034854df159b12ae7ddfc1e6bd32150b24a2d Mon Sep 17 00:00:00 2001 From: Philippe Teuwen Date: Fri, 18 Dec 2020 02:14:50 +0100 Subject: [PATCH 117/682] rework 14b apdu timeout computations --- armsrc/iso14443b.c | 6 +++--- client/src/cmdhf14b.c | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/armsrc/iso14443b.c b/armsrc/iso14443b.c index 11542a498..c3c61e980 100644 --- a/armsrc/iso14443b.c +++ b/armsrc/iso14443b.c @@ -1201,7 +1201,7 @@ static int Get14443bAnswerFromTag(uint8_t *response, uint16_t max_len, int timeo if (Handle14443bSamplesFromTag(ci, cq)) { - *eof_time = dma_start_time + (samples) - DELAY_TAG_TO_ARM; // end of EOF + *eof_time = GetCountSspClkDelta(dma_start_time) - (DELAY_TAG_TO_ARM * 128); // end of EOF if (Demod.len > Demod.max_len) { ret = -2; // overflow @@ -1209,7 +1209,7 @@ static int Get14443bAnswerFromTag(uint8_t *response, uint16_t max_len, int timeo break; } - if (samples > timeout && Demod.state < DEMOD_PHASE_REF_TRAINING) { + if (((GetCountSspClkDelta(dma_start_time) >> 7) > timeout) && Demod.state < DEMOD_PHASE_REF_TRAINING) { ret = -1; break; } @@ -1225,7 +1225,7 @@ static int Get14443bAnswerFromTag(uint8_t *response, uint16_t max_len, int timeo - (Demod.len * (8 + 2)) // time for byte transfers - (12) // time for SOF transfer - (12); // time for EOF transfer - LogTrace(Demod.output, Demod.len, (sof_time * 4), (*eof_time * 4), NULL, false); + LogTrace(Demod.output, Demod.len, sof_time, *eof_time, NULL, false); } return Demod.len; } diff --git a/client/src/cmdhf14b.c b/client/src/cmdhf14b.c index ffec87950..17c31e0a7 100644 --- a/client/src/cmdhf14b.c +++ b/client/src/cmdhf14b.c @@ -26,7 +26,7 @@ #include "mifare/ndef.h" // NDEFRecordsDecodeAndPrint #define TIMEOUT 2000 -#define APDU_TIMEOUT 4000 +#define APDU_TIMEOUT 2000 // iso14b apdu input frame length static uint16_t apdu_frame_length = 0; @@ -1450,7 +1450,7 @@ static int handle_14b_apdu(bool chainingin, uint8_t *datain, int datainlen, bool SendCommandMIX(CMD_HF_ISO14443B_COMMAND, ISO14B_APDU | flags, 0, time_wait, NULL, 0); PacketResponseNG resp; - if (WaitForResponseTimeout(CMD_HF_ISO14443B_COMMAND, &resp, APDU_TIMEOUT)) { + if (WaitForResponseTimeout(CMD_HF_ISO14443B_COMMAND, &resp, MAX(APDU_TIMEOUT, user_timeout))) { uint8_t *recv = resp.data.asBytes; int rlen = resp.oldarg[0]; uint8_t res = resp.oldarg[1]; From 9b4e0c212f880275494197f4fb976f465b45e224 Mon Sep 17 00:00:00 2001 From: Ave Date: Fri, 18 Dec 2020 04:26:39 +0300 Subject: [PATCH 118/682] emrtd: Remove unnecessary memcpys from two dump functions --- client/src/cmdhfemrtd.c | 23 +++++++++-------------- 1 file changed, 9 insertions(+), 14 deletions(-) diff --git a/client/src/cmdhfemrtd.c b/client/src/cmdhfemrtd.c index 5f6c12891..15983b2f9 100644 --- a/client/src/cmdhfemrtd.c +++ b/client/src/cmdhfemrtd.c @@ -711,18 +711,17 @@ static bool emrtd_select_and_read(uint8_t *dataout, int *dataoutlen, const char } static bool emrtd_dump_ef_dg2(uint8_t *file_contents, int file_length) { - uint8_t data[EMRTD_MAX_FILE_SIZE]; - int datalen = 0; + int offset, datalen = 0; // This is a hacky impl that just looks for the image header. I'll improve it eventually. // based on mrpkey.py // FF D8 FF E0 -> JPEG // 00 00 00 0C 6A 50 -> JPEG 2000 - for (int i = 0; i < file_length - 6; i++) { - if ((file_contents[i] == 0xFF && file_contents[i + 1] == 0xD8 && file_contents[i + 2] == 0xFF && file_contents[i + 3] == 0xE0) || - (file_contents[i] == 0x00 && file_contents[i + 1] == 0x00 && file_contents[i + 2] == 0x00 && file_contents[i + 3] == 0x0C && file_contents[i + 4] == 0x6A && file_contents[i + 5] == 0x50)) { - datalen = file_length - i; - memcpy(data, file_contents + i, datalen); + // Note: Doing file_length - 6 to account for the longest data we're checking. + for (offset = 0; offset < file_length - 6; offset++) { + if ((file_contents[offset] == 0xFF && file_contents[offset + 1] == 0xD8 && file_contents[offset + 2] == 0xFF && file_contents[offset + 3] == 0xE0) || + (file_contents[offset] == 0x00 && file_contents[offset + 1] == 0x00 && file_contents[offset + 2] == 0x00 && file_contents[offset + 3] == 0x0C && file_contents[offset + 4] == 0x6A && file_contents[offset + 5] == 0x50)) { + datalen = file_length - offset; break; } } @@ -732,7 +731,7 @@ static bool emrtd_dump_ef_dg2(uint8_t *file_contents, int file_length) { return false; } - saveFile("EF_DG2", ".jpg", data, datalen); + saveFile("EF_DG2", ".jpg", file_contents + offset, datalen); return true; } @@ -756,19 +755,15 @@ static bool emrtd_dump_ef_dg5(uint8_t *file_contents, int file_length) { } static bool emrtd_dump_ef_sod(uint8_t *file_contents, int file_length) { - uint8_t data[EMRTD_MAX_FILE_SIZE]; - int fieldlen = emrtd_get_asn1_field_length(file_contents, file_length, 1); int datalen = emrtd_get_asn1_data_length(file_contents, file_length, 1); - if (fieldlen + 1 < EMRTD_MAX_FILE_SIZE) { - memcpy(data, file_contents + fieldlen + 1, datalen); - } else { + if (fieldlen + 1 > EMRTD_MAX_FILE_SIZE) { PrintAndLogEx(ERR, "error (emrtd_dump_ef_sod) fieldlen out-of-bounds"); return false; } - saveFile("EF_SOD", ".p7b", data, datalen); + saveFile("EF_SOD", ".p7b", file_contents + fieldlen + 1, datalen); return true; } From cd21765acc045175cda637227c201df8dc597726 Mon Sep 17 00:00:00 2001 From: Ave Date: Fri, 18 Dec 2020 04:28:14 +0300 Subject: [PATCH 119/682] emrtd: Move EF_CardAccess dump to before auth to ensure that it is dumped even without auth --- client/src/cmdhfemrtd.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/client/src/cmdhfemrtd.c b/client/src/cmdhfemrtd.c index 15983b2f9..3dc567d6c 100644 --- a/client/src/cmdhfemrtd.c +++ b/client/src/cmdhfemrtd.c @@ -988,6 +988,12 @@ int dumpHF_EMRTD(char *documentnumber, char *dob, char *expiry, bool BAC_availab return PM3_ESOFT; } + // Dump EF_CardAccess (if available) + if (!emrtd_dump_file(ks_enc, ks_mac, ssc, EMRTD_EF_CARDACCESS, "EF_CardAccess", BAC, use_14b)) { + PrintAndLogEx(INFO, "Couldn't dump EF_CardAccess, card does not support PACE."); + PrintAndLogEx(HINT, "This is expected behavior for cards without PACE, and isn't something to be worried about."); + } + // Authenticate with the eMRTD if (!emrtd_do_auth(documentnumber, dob, expiry, BAC_available, &BAC, ssc, ks_enc, ks_mac, &use_14b)) { DropField(); @@ -1027,12 +1033,8 @@ int dumpHF_EMRTD(char *documentnumber, char *dob, char *expiry, bool BAC_availab emrtd_dump_file(ks_enc, ks_mac, ssc, file_id, file_name, BAC, use_14b); } - // Dump EF_SOD and EF_CardAccess (if available) + // Dump EF_SOD emrtd_dump_file(ks_enc, ks_mac, ssc, EMRTD_EF_SOD, "EF_SOD", BAC, use_14b); - if (!emrtd_dump_file(ks_enc, ks_mac, ssc, EMRTD_EF_CARDACCESS, "EF_CardAccess", BAC, use_14b)) { - PrintAndLogEx(INFO, "Couldn't dump EF_CardAccess, card does not support PACE."); - PrintAndLogEx(HINT, "This is expected behavior for cards without PACE, and isn't something to be worried about."); - } DropField(); return PM3_SUCCESS; From 43dc10e7f0e5b251fd0b5224d9922def8d91f0d1 Mon Sep 17 00:00:00 2001 From: Philippe Teuwen Date: Fri, 18 Dec 2020 02:37:31 +0100 Subject: [PATCH 120/682] hf trace list: fix 14b CRC & accept 14a/14b crcs in 7816 --- client/src/cmdtrace.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/client/src/cmdtrace.c b/client/src/cmdtrace.c index ad5b38df7..f934caebe 100644 --- a/client/src/cmdtrace.c +++ b/client/src/cmdtrace.c @@ -184,6 +184,8 @@ static uint16_t printTraceLine(uint16_t tracepos, uint16_t traceLen, uint8_t *tr break; case ISO_14443B: case TOPAZ: + crcStatus = iso14443B_CRC_check(frame, data_len); + break; case FELICA: crcStatus = !felica_CRC_check(frame + 2, data_len - 4); break; @@ -193,9 +195,12 @@ static uint16_t printTraceLine(uint16_t tracepos, uint16_t traceLen, uint8_t *tr case ISO_14443A: case MFDES: case LTO: - case ISO_7816_4: crcStatus = iso14443A_CRC_check(hdr->isResponse, frame, data_len); break; + case ISO_7816_4: + crcStatus = iso14443A_CRC_check(hdr->isResponse, frame, data_len) == 1 ? 3 : 0; + crcStatus = iso14443B_CRC_check(frame, data_len) == 1 ? 4 : crcStatus; + break; case THINFILM: frame[data_len - 1] ^= frame[data_len - 2]; frame[data_len - 2] ^= frame[data_len - 1]; @@ -280,7 +285,8 @@ static uint16_t printTraceLine(uint16_t tracepos, uint16_t traceLen, uint8_t *tr } // Draw the CRC column - const char *crc = (crcStatus == 0 ? "!crc" : (crcStatus == 1 ? " ok " : " ")); + const char *crcstrings[] = { "!crc", " ok ", " ", "A ok", "B ok" }; + const char *crc = crcstrings[crcStatus]; // mark short bytes (less than 8 Bit + Parity) if (protocol == ISO_14443A || From e0e478c90d0b605da06faeabe6d88ccf99137503 Mon Sep 17 00:00:00 2001 From: iceman1001 Date: Fri, 18 Dec 2020 02:39:32 +0100 Subject: [PATCH 121/682] text --- client/luascripts/hf_mfu_magicwrite.lua | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/client/luascripts/hf_mfu_magicwrite.lua b/client/luascripts/hf_mfu_magicwrite.lua index 4b4d7178a..c01f043fe 100644 --- a/client/luascripts/hf_mfu_magicwrite.lua +++ b/client/luascripts/hf_mfu_magicwrite.lua @@ -44,8 +44,8 @@ arguments = [[ -c read magic configuration -u UID (14 hexsymbols), set UID on tag -t tag type to impersonate - 1 = UL_EV1 48k - 2 = UL_EV1 128k + 1 = UL EV1 48b + 2 = UL EV1 128b 3 = NTAG 210 4 = NTAG 212 5 = NTAG 213 (true) @@ -60,7 +60,7 @@ arguments = [[ -p password (8 hexsymbols), set password on tag. -a pack ( 4 hexsymbols), set pack on tag. -s signature data (64 hexsymbols), set signature data on tag. - -o OTP data (8 hexsymbols), set `one time programmable` data on tag. + -o OTP data (8 hexsymbols), set `One-Time Programmable` data on tag. -v version data (16 hexsymbols), set version data on tag. -w wipe tag. You can specify password if the tag has been locked down. Fills tag with zeros and put default values for NTAG213 (like -t 5) -k pwd to use with the wipe option From 69a124762a01a1414183c1dcf691589474978ef8 Mon Sep 17 00:00:00 2001 From: Ave Date: Fri, 18 Dec 2020 04:42:09 +0300 Subject: [PATCH 122/682] emrtd: Code cleanup on emrtd_bump_ssc --- client/src/cmdhfemrtd.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/client/src/cmdhfemrtd.c b/client/src/cmdhfemrtd.c index 3dc567d6c..6cf07b1ae 100644 --- a/client/src/cmdhfemrtd.c +++ b/client/src/cmdhfemrtd.c @@ -331,11 +331,11 @@ static void emrtd_bump_ssc(uint8_t *ssc) { if ((*(ssc + i)) == 0xFF) { // Set anything already FF to 0, we'll do + 1 on num to left anyways (*(ssc + i)) = 0; - continue; + } else { + (*(ssc + i)) += 1; + PrintAndLogEx(DEBUG, "ssc-a: %s", sprint_hex_inrow(ssc, 8)); + return; } - (*(ssc + i)) += 1; - PrintAndLogEx(DEBUG, "ssc-a: %s", sprint_hex_inrow(ssc, 8)); - return; } } From 4f3d3f8ac47892f409d8a20a00560f4e3b106346 Mon Sep 17 00:00:00 2001 From: Ave Date: Fri, 18 Dec 2020 05:03:06 +0300 Subject: [PATCH 123/682] emrtd: Fix insecure read on emrtd_read_file --- client/src/cmdhfemrtd.c | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/client/src/cmdhfemrtd.c b/client/src/cmdhfemrtd.c index 6cf07b1ae..bb89b91b9 100644 --- a/client/src/cmdhfemrtd.c +++ b/client/src/cmdhfemrtd.c @@ -526,7 +526,7 @@ static int emrtd_read_file(uint8_t *dataout, int *dataoutlen, uint8_t *kenc, uin int toread = 4; int offset = 0; - if (use_secure == true) { + if (use_secure) { if (_emrtd_secure_read_binary_decrypt(kenc, kmac, ssc, offset, toread, response, &resplen, use_14b) == false) { return false; } @@ -546,12 +546,12 @@ static int emrtd_read_file(uint8_t *dataout, int *dataoutlen, uint8_t *kenc, uin toread = 118; } - if (kenc == NULL) { - if (_emrtd_read_binary(offset, toread, tempresponse, &tempresplen, use_14b) == false) { + if (use_secure) { + if (_emrtd_secure_read_binary_decrypt(kenc, kmac, ssc, offset, toread, tempresponse, &tempresplen, use_14b) == false) { return false; } } else { - if (_emrtd_secure_read_binary_decrypt(kenc, kmac, ssc, offset, toread, tempresponse, &tempresplen, use_14b) == false) { + if (_emrtd_read_binary(offset, toread, tempresponse, &tempresplen, use_14b) == false) { return false; } } @@ -591,8 +591,7 @@ static bool emrtd_lds_get_data_by_tag(uint8_t *datain, int *datainlen, uint8_t * // If the element is what we're looking for, get the data and return true if (*(datain + offset) == tag1 && (!twobytetag || *(datain + offset + 1) == tag2)) { - - if ( *datainlen > e_datalen) { + if (*datainlen > e_datalen) { *dataoutlen = e_datalen; memcpy(dataout, datain + offset + e_idlen + e_fieldlen, e_datalen); return true; @@ -691,7 +690,7 @@ static bool emrtd_file_tag_to_file_id(uint8_t *datain, char *filenameout, char * } static bool emrtd_select_and_read(uint8_t *dataout, int *dataoutlen, const char *file, uint8_t *ks_enc, uint8_t *ks_mac, uint8_t *ssc, bool use_secure, bool use_14b) { - if (use_secure == true) { + if (use_secure) { if (emrtd_secure_select_file(ks_enc, ks_mac, ssc, EMRTD_P1_SELECT_BY_EF, file, use_14b) == false) { PrintAndLogEx(ERR, "Failed to secure select %s.", file); return false; From ba611ffb538d1fd67d0ac553e8c7a28ca99f7338 Mon Sep 17 00:00:00 2001 From: Drew Date: Fri, 18 Dec 2020 10:18:58 -0500 Subject: [PATCH 124/682] add dump_sim_mode to Standalone HF_ICECLASS --- armsrc/Standalone/hf_iceclass.c | 210 +++++++++++++++++++++++++++++++- 1 file changed, 207 insertions(+), 3 deletions(-) diff --git a/armsrc/Standalone/hf_iceclass.c b/armsrc/Standalone/hf_iceclass.c index 8490ea628..eab45edf4 100644 --- a/armsrc/Standalone/hf_iceclass.c +++ b/armsrc/Standalone/hf_iceclass.c @@ -37,15 +37,19 @@ #define ICE_STATE_ATTACK 2 #define ICE_STATE_READER 3 #define ICE_STATE_CONFIGCARD 4 +#define ICE_STATE_DUMP_SIM 5 + +#define HF_ICLASS_NUM_MODES 6 // ==================================================== // Select which standalone function to be active. -// 4 possiblities. Uncomment the one you wanna use. +// 5 possiblities. Uncomment the one you wanna use. -#define ICE_USE ICE_STATE_FULLSIM +//#define ICE_USE ICE_STATE_FULLSIM //#define ICE_USE ICE_STATE_ATTACK //#define ICE_USE ICE_STATE_READER //#define ICE_USE ICE_STATE_CONFIGCARD +#define ICE_USE ICE_STATE_DUMP_SIM // ==================================================== @@ -53,6 +57,8 @@ #define NUM_CSNS 9 #define MAC_RESPONSES_SIZE (16 * NUM_CSNS) #define HF_ICLASS_FULLSIM_ORIG_BIN "iceclass-orig.bin" +#define HF_ICALSSS_READSIM_TEMP_BIN "iceclass-temp.bin" +#define HF_ICALSSS_READSIM_TEMP_MOD_BIN "iceclass-temp-mod.bin" #define HF_ICLASS_FULLSIM_MOD "iceclass-modified" #define HF_ICLASS_FULLSIM_MOD_BIN HF_ICLASS_FULLSIM_MOD".bin" #define HF_ICLASS_FULLSIM_MOD_EML HF_ICLASS_FULLSIM_MOD".eml" @@ -141,6 +147,12 @@ static void download_instructions(uint8_t t) { DbpString("2. " _YELLOW_("mem spiffs dump h")); break; } + case ICE_STATE_DUMP_SIM: { + DbpString("The found tag will be dumped to " HF_ICALSSS_READSIM_TEMP_BIN); + DbpString("1. " _YELLOW_("mem spiffs tree")); + DbpString("2. " _YELLOW_("mem spiffs dump h")); + break; + } } } @@ -181,6 +193,22 @@ static void save_to_flash(uint8_t *data, uint16_t datalen) { rdv40_spiffs_lazy_unmount(); } +// Write over file if size of flash file is less than new datalen +static void save_to_temp_bin(uint8_t *data, uint16_t datalen) { + + rdv40_spiffs_lazy_mount(); + + const char * fn = HF_ICALSSS_READSIM_TEMP_BIN; + + int res; + res = rdv40_spiffs_write(fn, data, datalen, RDV40_SPIFFS_SAFETY_SAFE); + if (res == SPIFFS_OK) { + Dbprintf("saved to " _GREEN_("%s"), fn); + } + + rdv40_spiffs_lazy_unmount(); +} + static int fullsim_mode(void) { rdv40_spiffs_lazy_mount(); @@ -407,6 +435,172 @@ static int reader_dump_mode(void) { return PM3_SUCCESS; } +static int dump_sim_mode(void) { + + DbpString("this mode has no tracelog"); + if (have_aa2()) + DbpString("dumping of " _YELLOW_("AA2 enabled")); + + for (;;) { + + BigBuf_free(); + + uint8_t *card_data = BigBuf_malloc(ICLASS_16KS_SIZE); + memset(card_data, 0xFF, ICLASS_16KS_SIZE); + + if (BUTTON_PRESS()) { + DbpString("button pressed"); + break; + } + + // setup authenticate AA1 + iclass_auth_req_t auth = { + .use_raw = false, + .use_elite = false, + .use_credit_key = false, + .do_auth = true, + .send_reply = false, + }; + memcpy(auth.key, legacy_aa1_key, sizeof(auth.key)); + + Iso15693InitReader(); + set_tracing(false); + + + picopass_hdr *hdr = (picopass_hdr *)card_data; + + // select tag. + uint32_t eof_time = 0; + bool res = select_iclass_tag(hdr, auth.use_credit_key, &eof_time); + if (res == false) { + switch_off(); + continue; + } + + // sanity check of CSN. + if (hdr->csn[7] != 0xE0 && hdr->csn[6] != 0x12) { + switch_off(); + continue; + } + + uint32_t start_time = eof_time + DELAY_ICLASS_VICC_TO_VCD_READER; + + // get 3 config bits + uint8_t type = (hdr->conf.chip_config & 0x10) >> 2; + type |= (hdr->conf.mem_config & 0x80) >> 6; + type |= (hdr->conf.mem_config & 0x20) >> 5; + + Dbprintf(_GREEN_("%s") ", dumping...", card_types[type]); + + uint8_t pagemap = get_pagemap(hdr); + uint8_t app1_limit, app2_limit, start_block; + + // tags configured for NON SECURE PAGE, acts different + if (pagemap == PICOPASS_NON_SECURE_PAGEMODE) { + app1_limit = card_app2_limit[type]; + app2_limit = 0; + start_block = 3; + } else { + + app1_limit = hdr->conf.app_limit; + app2_limit = card_app2_limit[type]; + start_block = 5; + + res = authenticate_iclass_tag(&auth, hdr, &start_time, &eof_time, NULL); + if (res == false) { + switch_off(); + Dbprintf(_RED_("failed AA1 auth") ", skipping "); + continue; + } + + start_time = eof_time + DELAY_ICLASS_VICC_TO_VCD_READER; + } + + uint16_t dumped = 0; + + // main read loop + for (uint16_t i = start_block; i <= app1_limit; i++) { + if (iclass_read_block(i, card_data + (8 * i), &start_time, &eof_time)) { + dumped++; + } + } + + if (pagemap != PICOPASS_NON_SECURE_PAGEMODE && have_aa2()) { + + // authenticate AA2 + auth.use_raw = false; + auth.use_credit_key = true; + memcpy(auth.key, aa2_key, sizeof(auth.key)); + + res = select_iclass_tag(hdr, auth.use_credit_key, &eof_time); + if (res) { + + // sanity check of CSN. + if (hdr->csn[7] != 0xE0 && hdr->csn[6] != 0x12) { + switch_off(); + continue; + } + + res = authenticate_iclass_tag(&auth, hdr, &start_time, &eof_time, NULL); + if (res) { + start_time = eof_time + DELAY_ICLASS_VICC_TO_VCD_READER; + + for (uint16_t i = app1_limit + 1; i <= app2_limit; i++) { + if (iclass_read_block(i, card_data + (8 * i), &start_time, &eof_time)) { + dumped++; + } + } + } else { + DbpString(_RED_("failed AA2 auth")); + } + } else { + DbpString(_RED_("failed selecting AA2")); + + // sanity check of CSN. + if (hdr->csn[7] != 0xE0 && hdr->csn[6] != 0x12) { + switch_off(); + continue; + } + } + } + switch_off(); + save_to_temp_bin(card_data, (start_block + dumped) * 8); + Dbprintf("%u bytes saved", (start_block + dumped) * 8); + + if (((start_block + dumped) * 8) > 0) { + break; //switch to sim mode + } + } + + rdv40_spiffs_lazy_mount(); + + SpinOff(0); + uint8_t *emul = BigBuf_get_EM_addr(); + uint32_t fsize = size_in_spiffs(HF_ICALSSS_READSIM_TEMP_BIN); + int res = rdv40_spiffs_read_as_filetype(HF_ICALSSS_READSIM_TEMP_BIN, emul, fsize, RDV40_SPIFFS_SAFETY_SAFE); + rdv40_spiffs_lazy_unmount(); + if (res == SPIFFS_OK) { + Dbprintf("loaded " _GREEN_(HF_ICALSSS_READSIM_TEMP_BIN) " (%u bytes)", fsize); + } + + Dbprintf("simming " _GREEN_(HF_ICALSSS_READSIM_TEMP_BIN)); + iclass_simulate(ICLASS_SIM_MODE_FULL, 0, false, NULL, NULL, NULL); + + LED_B_ON(); + rdv40_spiffs_lazy_mount(); + res = rdv40_spiffs_write(HF_ICALSSS_READSIM_TEMP_BIN, emul, fsize, RDV40_SPIFFS_SAFETY_SAFE); + rdv40_spiffs_lazy_unmount(); + LED_B_OFF(); + if (res == SPIFFS_OK) { + Dbprintf("wrote emulator memory to " _GREEN_(HF_ICALSSS_READSIM_TEMP_MOD_BIN)); + } else { + Dbprintf(_RED_("error") " writing "HF_ICALSSS_READSIM_TEMP_MOD_BIN" to flash ( %d )", res); + } + + DbpString("-=[ exiting " _CYAN_("`dump & sim`") " mode ]=-"); + return PM3_SUCCESS; +} + static int config_sim_mode(void) { uint8_t *emul = BigBuf_get_EM_addr(); @@ -436,7 +630,7 @@ void RunMod(void) { uint8_t mode = ICE_USE; uint8_t *bb = BigBuf_get_EM_addr(); - if (bb[0] > 0 && bb[0] < 5) { + if (bb[0] > 0 && bb[0] < HF_ICLASS_NUM_MODES) { //increase number for new mode mode = bb[0]; } @@ -512,6 +706,16 @@ void RunMod(void) { if (mode == ICE_STATE_CONFIGCARD) config_sim_mode(); + mode = ICE_STATE_NONE; + break; + } + case ICE_STATE_DUMP_SIM: { + DbpString("-=[ enter " _CYAN_("`dump & sim`") " mode, read 1 card and sim it ]=-"); + res = dump_sim_mode(); + if (res == PM3_SUCCESS) { + download_instructions(mode); + } + mode = ICE_STATE_NONE; break; } From db729497203834b7b692b17f9a51c1efe308e84b Mon Sep 17 00:00:00 2001 From: Drew Date: Fri, 18 Dec 2020 12:01:03 -0500 Subject: [PATCH 125/682] change default mode; refactor save to take name --- armsrc/Standalone/hf_iceclass.c | 47 +++++++++++++++------------------ 1 file changed, 21 insertions(+), 26 deletions(-) diff --git a/armsrc/Standalone/hf_iceclass.c b/armsrc/Standalone/hf_iceclass.c index eab45edf4..472544310 100644 --- a/armsrc/Standalone/hf_iceclass.c +++ b/armsrc/Standalone/hf_iceclass.c @@ -45,11 +45,11 @@ // Select which standalone function to be active. // 5 possiblities. Uncomment the one you wanna use. -//#define ICE_USE ICE_STATE_FULLSIM +#define ICE_USE ICE_STATE_FULLSIM //#define ICE_USE ICE_STATE_ATTACK //#define ICE_USE ICE_STATE_READER //#define ICE_USE ICE_STATE_CONFIGCARD -#define ICE_USE ICE_STATE_DUMP_SIM +//#define ICE_USE ICE_STATE_DUMP_SIM // ==================================================== @@ -158,15 +158,25 @@ static void download_instructions(uint8_t t) { // Save to flash if file doesn't exist. // Write over file if size of flash file is less than new datalen -static void save_to_flash(uint8_t *data, uint16_t datalen) { +static void save_to_flash(uint8_t *data, uint16_t datalen, char * filename) { rdv40_spiffs_lazy_mount(); char fn[SPIFFS_OBJ_NAME_LEN]; - sprintf(fn, "iclass-%02X%02X%02X%02X%02X%02X%02X%02X.bin", - data[0], data[1], data[2], data[3], - data[4], data[5], data[6], data[7] - ); + + if (filename == NULL){ + sprintf(fn, "iclass-%02X%02X%02X%02X%02X%02X%02X%02X.bin", + data[0], data[1], data[2], data[3], + data[4], data[5], data[6], data[7] + ); + } else { + int name_len = SPIFFS_OBJ_NAME_LEN; + int filename_len = strlen(filename); + + // if the given name len longer than buffer allows, cut it down to size + name_len = (name_len >= SPIFFS_OBJ_NAME_LEN) ? SPIFFS_OBJ_NAME_LEN : filename_len; + memcpy(fn, filename, name_len); + } int res; if (exists_in_spiffs(fn) == false) { @@ -193,22 +203,6 @@ static void save_to_flash(uint8_t *data, uint16_t datalen) { rdv40_spiffs_lazy_unmount(); } -// Write over file if size of flash file is less than new datalen -static void save_to_temp_bin(uint8_t *data, uint16_t datalen) { - - rdv40_spiffs_lazy_mount(); - - const char * fn = HF_ICALSSS_READSIM_TEMP_BIN; - - int res; - res = rdv40_spiffs_write(fn, data, datalen, RDV40_SPIFFS_SAFETY_SAFE); - if (res == SPIFFS_OK) { - Dbprintf("saved to " _GREEN_("%s"), fn); - } - - rdv40_spiffs_lazy_unmount(); -} - static int fullsim_mode(void) { rdv40_spiffs_lazy_mount(); @@ -428,7 +422,7 @@ static int reader_dump_mode(void) { } } switch_off(); - save_to_flash(card_data, (start_block + dumped) * 8); + save_to_flash(card_data, (start_block + dumped) * 8, NULL); Dbprintf("%u bytes saved", (start_block + dumped) * 8); } DbpString("-=[ exiting " _CYAN_("`read & dump`") " mode ]=-"); @@ -564,7 +558,8 @@ static int dump_sim_mode(void) { } } switch_off(); - save_to_temp_bin(card_data, (start_block + dumped) * 8); + char * temp_file = HF_ICALSSS_READSIM_TEMP_BIN; + save_to_flash(card_data, (start_block + dumped) * 8, temp_file); Dbprintf("%u bytes saved", (start_block + dumped) * 8); if (((start_block + dumped) * 8) > 0) { @@ -630,7 +625,7 @@ void RunMod(void) { uint8_t mode = ICE_USE; uint8_t *bb = BigBuf_get_EM_addr(); - if (bb[0] > 0 && bb[0] < HF_ICLASS_NUM_MODES) { //increase number for new mode + if (bb[0] > 0 && bb[0] < HF_ICLASS_NUM_MODES) { mode = bb[0]; } From 9c37ef08da1f1e7beef5823348afa6a2bedd2088 Mon Sep 17 00:00:00 2001 From: Drew Date: Fri, 18 Dec 2020 12:27:02 -0500 Subject: [PATCH 126/682] update CHANGELOG --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index a1b430303..0f890c8d5 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 `ICE_STATE_DUMP_SIM` - standalone mode for dumping/simming one iClass tag (@iconicsec) - Added `lf em 4x50 eview` - show uploaded EM4x50 data in emul memory (@tharexde) - Fix `data rawdemod` parsing for psk2 and user defined clock (@cyberpunk-re) - Added `hf iclass encode` - encode a wiegand binary to a encrypted credential (@iceman1001) From 36cf0be239f43e63fb1aca12e12ef5713172d15b Mon Sep 17 00:00:00 2001 From: Ave Ozkal Date: Fri, 18 Dec 2020 21:12:57 +0300 Subject: [PATCH 127/682] emrtd: Basic EF_DG11 support on hf emrtd info --- client/src/cmdhfemrtd.c | 107 ++++++++++++++++++++++++++++++++-------- 1 file changed, 87 insertions(+), 20 deletions(-) diff --git a/client/src/cmdhfemrtd.c b/client/src/cmdhfemrtd.c index deff0d4df..c1e9bcbce 100644 --- a/client/src/cmdhfemrtd.c +++ b/client/src/cmdhfemrtd.c @@ -1118,7 +1118,7 @@ static void emrtd_print_document_number(char *mrz, int offset) { } } -static void emrtd_print_name(char *mrz, int offset, int max_length) { +static void emrtd_print_name(char *mrz, int offset, int max_length, bool localized) { char final_name[100] = { 0x00 }; int i = emrtd_mrz_determine_length(mrz, offset, max_length); int sep = emrtd_mrz_determine_separator(mrz, offset, i); @@ -1128,20 +1128,30 @@ static void emrtd_print_name(char *mrz, int offset, int max_length) { final_name[namelen] = ' '; memcpy(final_name + namelen + 1, mrz + offset, sep); - PrintAndLogEx(SUCCESS, "Legal Name............: " _YELLOW_("%s"), final_name); + if (localized) { + PrintAndLogEx(SUCCESS, "Legal Name (Localized): " _YELLOW_("%s"), final_name); + } else { + PrintAndLogEx(SUCCESS, "Legal Name............: " _YELLOW_("%s"), final_name); + } } -static void emrtd_mrz_convert_date(char *mrz, int offset, char *final_date, bool is_expiry) { - char temp_year[3] = { 0x00 }; - - memcpy(temp_year, mrz + offset, 2); - // If it's > 20, assume 19xx. - if (strtol(temp_year, NULL, 10) < 20 || is_expiry) { - final_date[0] = '2'; - final_date[1] = '0'; +static void emrtd_mrz_convert_date(char *mrz, int offset, char *final_date, bool is_expiry, bool is_full) { + if (is_full) { + // If we get the full date, use the first two characters from that for year + memcpy(final_date, mrz, 2); + // and do + 2 on offset so that rest of code uses the right data + offset += 2; } else { - final_date[0] = '1'; - final_date[1] = '9'; + char temp_year[3] = { 0x00 }; + memcpy(temp_year, mrz + offset, 2); + // If it's > 20, assume 19xx. + if (strtol(temp_year, NULL, 10) < 20 || is_expiry) { + final_date[0] = '2'; + final_date[1] = '0'; + } else { + final_date[0] = '1'; + final_date[1] = '9'; + } } memcpy(final_date + 2, mrz + offset, 2); @@ -1151,20 +1161,20 @@ static void emrtd_mrz_convert_date(char *mrz, int offset, char *final_date, bool memcpy(final_date + 8, mrz + offset + 4, 2); } -static void emrtd_print_dob(char *mrz, int offset) { +static void emrtd_print_dob(char *mrz, int offset, bool full) { char final_date[12] = { 0x00 }; - emrtd_mrz_convert_date(mrz, offset, final_date, false); + emrtd_mrz_convert_date(mrz, offset, final_date, false, full); PrintAndLogEx(SUCCESS, "Date of birth.........: " _YELLOW_("%s"), final_date); - if (!emrtd_mrz_verify_check_digit(mrz, offset, 6)) { + if (!full && !emrtd_mrz_verify_check_digit(mrz, offset, 6)) { PrintAndLogEx(SUCCESS, _RED_("Date of Birth check digit is invalid.")); } } static void emrtd_print_expiry(char *mrz, int offset) { char final_date[12] = { 0x00 }; - emrtd_mrz_convert_date(mrz, offset, final_date, true); + emrtd_mrz_convert_date(mrz, offset, final_date, true, false); PrintAndLogEx(SUCCESS, "Date of expiry........: " _YELLOW_("%s"), final_date); @@ -1173,6 +1183,57 @@ static void emrtd_print_expiry(char *mrz, int offset) { } } +static bool emrtd_print_ef_dg11_info(bool *BAC, uint8_t *ssc, uint8_t *ks_enc, uint8_t *ks_mac, bool *use_14b) { + uint8_t response[EMRTD_MAX_FILE_SIZE] = { 0x00 }; + int resplen = 0; + + uint8_t taglist[100] = { 0x00 }; + int taglistlen = 0; + uint8_t tagdata[1000] = { 0x00 }; + int tagdatalen = 0; + + PrintAndLogEx(INFO, "=====EF_DG11====="); + + if (!emrtd_select_and_read(response, &resplen, EMRTD_EF_DG11, ks_enc, ks_mac, ssc, *BAC, *use_14b)) { + PrintAndLogEx(ERR, "Failed to read EF_DG11."); + return false; + } + + if (!emrtd_lds_get_data_by_tag(response, &resplen, taglist, &taglistlen, 0x5c, 0x00, false)) { + PrintAndLogEx(ERR, "Failed to read file list from EF_DG11."); + return false; + } + + for (int i = 0; i < taglistlen; i++) { + emrtd_lds_get_data_by_tag(response, &resplen, tagdata, &tagdatalen, taglist[i], taglist[i + 1], taglist[i] == 0x5f); + // Special behavior for two char tags + if (taglist[i] == 0x5f) { + switch (taglist[i + 1]) { + case 0x0e: + emrtd_print_name((char *) tagdata, 0, tagdatalen, true); + break; + case 0x10: + PrintAndLogEx(SUCCESS, "Personal Number.......: " _YELLOW_("%.*s"), tagdatalen, tagdata); + break; + case 0x11: + PrintAndLogEx(SUCCESS, "Place of Birth........: " _YELLOW_("%.*s"), tagdatalen, tagdata); + break; + case 0x2b: + emrtd_print_dob((char *) tagdata, 0, true); + break; + default: + PrintAndLogEx(SUCCESS, "Unknown Field %02X%02X....: %s", taglist[i], taglist[i + 1], sprint_hex_inrow(tagdata, tagdatalen)); + break; + } + + i += 1; + } else { + PrintAndLogEx(INFO, "Reading %02X: %s", taglist[i], sprint_hex_inrow(tagdata, tagdatalen)); + } + } + return true; +} + int infoHF_EMRTD(char *documentnumber, char *dob, char *expiry, bool BAC_available) { uint8_t response[EMRTD_MAX_FILE_SIZE] = { 0x00 }; int resplen = 0; @@ -1208,6 +1269,8 @@ int infoHF_EMRTD(char *documentnumber, char *dob, char *expiry, bool BAC_availab return PM3_ESOFT; } + PrintAndLogEx(INFO, "=====EF_DG1====="); + // MRZ on TD1 is 90 characters, 30 on each row. // MRZ on TD3 is 88 characters, 44 on each row. char mrz[90] = { 0x00 }; @@ -1251,9 +1314,9 @@ int infoHF_EMRTD(char *documentnumber, char *dob, char *expiry, bool BAC_availab if (td_variant == 3) { // Passport form factor PrintAndLogEx(SUCCESS, "Nationality...........: " _YELLOW_("%.3s"), mrz + 44 + 10); - emrtd_print_name(mrz, 5, 38); + emrtd_print_name(mrz, 5, 38, false); emrtd_print_document_number(mrz, 44); - emrtd_print_dob(mrz, 44 + 13); + emrtd_print_dob(mrz, 44 + 13, false); emrtd_print_legal_sex(&mrz[44 + 20]); emrtd_print_expiry(mrz, 44 + 21); emrtd_print_optional_elements(mrz, 44 + 28, 14, true); @@ -1270,9 +1333,9 @@ int infoHF_EMRTD(char *documentnumber, char *dob, char *expiry, bool BAC_availab } else if (td_variant == 1) { // ID form factor PrintAndLogEx(SUCCESS, "Nationality...........: " _YELLOW_("%.3s"), mrz + 30 + 15); - emrtd_print_name(mrz, 60, 30); + emrtd_print_name(mrz, 60, 30, false); emrtd_print_document_number(mrz, 5); - emrtd_print_dob(mrz, 30); + emrtd_print_dob(mrz, 30, false); emrtd_print_legal_sex(&mrz[30 + 7]); emrtd_print_expiry(mrz, 30 + 8); emrtd_print_optional_elements(mrz, 15, 15, false); @@ -1284,6 +1347,10 @@ int infoHF_EMRTD(char *documentnumber, char *dob, char *expiry, bool BAC_availab } } + // Print EF_DG11 info + // TODO: verify existence from file list, also print file list in info. + emrtd_print_ef_dg11_info(&BAC, ssc, ks_enc, ks_mac, &use_14b); + DropField(); return PM3_SUCCESS; } From 27b7ecf1cdcdfe440850b06d680b99361cdb45e9 Mon Sep 17 00:00:00 2001 From: Ave Ozkal Date: Fri, 18 Dec 2020 21:25:46 +0300 Subject: [PATCH 128/682] emrtd: Complete EF_DG11 support on hf emrtd info --- client/src/cmdhfemrtd.c | 30 +++++++++++++++++++++++++++++- 1 file changed, 29 insertions(+), 1 deletion(-) diff --git a/client/src/cmdhfemrtd.c b/client/src/cmdhfemrtd.c index c1e9bcbce..62555d11b 100644 --- a/client/src/cmdhfemrtd.c +++ b/client/src/cmdhfemrtd.c @@ -1216,8 +1216,35 @@ static bool emrtd_print_ef_dg11_info(bool *BAC, uint8_t *ssc, uint8_t *ks_enc, u PrintAndLogEx(SUCCESS, "Personal Number.......: " _YELLOW_("%.*s"), tagdatalen, tagdata); break; case 0x11: + // TODO: acc for < separation PrintAndLogEx(SUCCESS, "Place of Birth........: " _YELLOW_("%.*s"), tagdatalen, tagdata); break; + case 0x42: + // TODO: acc for < separation + PrintAndLogEx(SUCCESS, "Permanent Address.....: " _YELLOW_("%.*s"), tagdatalen, tagdata); + break; + case 0x12: + PrintAndLogEx(SUCCESS, "Telephone.............: " _YELLOW_("%.*s"), tagdatalen, tagdata); + break; + case 0x13: + PrintAndLogEx(SUCCESS, "Profession............: " _YELLOW_("%.*s"), tagdatalen, tagdata); + break; + case 0x14: + PrintAndLogEx(SUCCESS, "Title.................: " _YELLOW_("%.*s"), tagdatalen, tagdata); + break; + case 0x15: + PrintAndLogEx(SUCCESS, "Personal Summary......: " _YELLOW_("%.*s"), tagdatalen, tagdata); + break; + case 0x16: + saveFile("ProofOfCitizenship", ".jpg", tagdata, tagdatalen); + break; + case 0x17: + // TODO: acc for < separation + PrintAndLogEx(SUCCESS, "Other valid TDs nums..: " _YELLOW_("%.*s"), tagdatalen, tagdata); + break; + case 0x18: + PrintAndLogEx(SUCCESS, "Custody Information...: " _YELLOW_("%.*s"), tagdatalen, tagdata); + break; case 0x2b: emrtd_print_dob((char *) tagdata, 0, true); break; @@ -1228,7 +1255,8 @@ static bool emrtd_print_ef_dg11_info(bool *BAC, uint8_t *ssc, uint8_t *ks_enc, u i += 1; } else { - PrintAndLogEx(INFO, "Reading %02X: %s", taglist[i], sprint_hex_inrow(tagdata, tagdatalen)); + // TODO: Account for A0 + PrintAndLogEx(SUCCESS, "Unknown Field %02X......: %s", taglist[i], sprint_hex_inrow(tagdata, tagdatalen)); } } return true; From 8e89eb12064f6e0fdfa19f6c81f891e62046c4a3 Mon Sep 17 00:00:00 2001 From: Ave Date: Fri, 18 Dec 2020 22:33:13 +0300 Subject: [PATCH 129/682] hf emrtd info: fancier output for files --- client/src/cmdhfemrtd.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/client/src/cmdhfemrtd.c b/client/src/cmdhfemrtd.c index 62555d11b..908b6e689 100644 --- a/client/src/cmdhfemrtd.c +++ b/client/src/cmdhfemrtd.c @@ -1192,7 +1192,8 @@ static bool emrtd_print_ef_dg11_info(bool *BAC, uint8_t *ssc, uint8_t *ks_enc, u uint8_t tagdata[1000] = { 0x00 }; int tagdatalen = 0; - PrintAndLogEx(INFO, "=====EF_DG11====="); + PrintAndLogEx(NORMAL, ""); + PrintAndLogEx(INFO, "-------------------- " _CYAN_("EF_DG11") " -------------------"); if (!emrtd_select_and_read(response, &resplen, EMRTD_EF_DG11, ks_enc, ks_mac, ssc, *BAC, *use_14b)) { PrintAndLogEx(ERR, "Failed to read EF_DG11."); @@ -1281,6 +1282,9 @@ int infoHF_EMRTD(char *documentnumber, char *dob, char *expiry, bool BAC_availab // Select and authenticate with the eMRTD bool auth_result = emrtd_do_auth(documentnumber, dob, expiry, BAC_available, &BAC, ssc, ks_enc, ks_mac, &use_14b); + + PrintAndLogEx(NORMAL, ""); + PrintAndLogEx(INFO, "------------------ " _CYAN_("Basic Info") " ------------------"); PrintAndLogEx(SUCCESS, "Communication standard: %s", use_14b ? _YELLOW_("ISO/IEC 14443(B)") : _YELLOW_("ISO/IEC 14443(A)")); PrintAndLogEx(SUCCESS, "BAC...................: %s", BAC ? _GREEN_("Enforced") : _RED_("Not enforced")); PrintAndLogEx(SUCCESS, "Authentication result.: %s", auth_result ? _GREEN_("Successful") : _RED_("Failed")); @@ -1297,7 +1301,8 @@ int infoHF_EMRTD(char *documentnumber, char *dob, char *expiry, bool BAC_availab return PM3_ESOFT; } - PrintAndLogEx(INFO, "=====EF_DG1====="); + PrintAndLogEx(NORMAL, ""); + PrintAndLogEx(INFO, "-------------------- " _CYAN_("EF_DG1") " --------------------"); // MRZ on TD1 is 90 characters, 30 on each row. // MRZ on TD3 is 88 characters, 44 on each row. From fa217875316a4837b428c1c5aafa0e304a799b92 Mon Sep 17 00:00:00 2001 From: Ave Date: Fri, 18 Dec 2020 23:52:42 +0300 Subject: [PATCH 130/682] hf emrtd info: Split EF_DG1 into its own func, read file list --- client/src/cmdhfemrtd.c | 189 ++++++++++++++++++++++------------------ 1 file changed, 102 insertions(+), 87 deletions(-) diff --git a/client/src/cmdhfemrtd.c b/client/src/cmdhfemrtd.c index 908b6e689..f2c3a60d3 100644 --- a/client/src/cmdhfemrtd.c +++ b/client/src/cmdhfemrtd.c @@ -1045,7 +1045,7 @@ static bool emrtd_compare_check_digit(char *datain, int datalen, char expected_c memcpy(tempdata, datain, datalen); uint8_t check_digit = emrtd_calculate_check_digit(tempdata) + 0x30; - bool res =check_digit == expected_check_digit; + bool res = check_digit == expected_check_digit; PrintAndLogEx(DEBUG, "emrtd_compare_check_digit, expected %c == %c calculated ( %s )" , expected_check_digit , check_digit @@ -1183,10 +1183,91 @@ static void emrtd_print_expiry(char *mrz, int offset) { } } -static bool emrtd_print_ef_dg11_info(bool *BAC, uint8_t *ssc, uint8_t *ks_enc, uint8_t *ks_mac, bool *use_14b) { - uint8_t response[EMRTD_MAX_FILE_SIZE] = { 0x00 }; - int resplen = 0; +static bool emrtd_print_ef_dg1_info(uint8_t *response, int resplen) { + int td_variant = 0; + PrintAndLogEx(NORMAL, ""); + PrintAndLogEx(INFO, "-------------------- " _CYAN_("EF_DG1") " --------------------"); + + // MRZ on TD1 is 90 characters, 30 on each row. + // MRZ on TD3 is 88 characters, 44 on each row. + char mrz[90] = { 0x00 }; + int mrzlen = 0; + + if (!emrtd_lds_get_data_by_tag(response, &resplen, (uint8_t *) mrz, &mrzlen, 0x5f, 0x1f, true)) { + PrintAndLogEx(ERR, "Failed to read MRZ from EF_DG1."); + return false; + } + + // Determine and print the document type + if (mrz[0] == 'I' && mrz[1] == 'P') { + td_variant = 1; + PrintAndLogEx(SUCCESS, "Document Type.........: " _YELLOW_("Passport Card")); + } else if (mrz[0] == 'I') { + td_variant = 1; + PrintAndLogEx(SUCCESS, "Document Type.........: " _YELLOW_("ID Card")); + } else if (mrz[0] == 'P') { + td_variant = 3; + PrintAndLogEx(SUCCESS, "Document Type.........: " _YELLOW_("Passport")); + } else { + td_variant = 1; + PrintAndLogEx(SUCCESS, "Document Type.........: " _YELLOW_("Unknown")); + PrintAndLogEx(INFO, "Assuming ID-style MRZ."); + } + PrintAndLogEx(SUCCESS, "Document Form Factor..: " _YELLOW_("TD%i"), td_variant); + + // Print the MRZ + if (td_variant == 1) { + PrintAndLogEx(DEBUG, "MRZ Row 1: " _YELLOW_("%.30s"), mrz); + PrintAndLogEx(DEBUG, "MRZ Row 2: " _YELLOW_("%.30s"), mrz + 30); + PrintAndLogEx(DEBUG, "MRZ Row 3: " _YELLOW_("%.30s"), mrz + 60); + } else if (td_variant == 3) { + PrintAndLogEx(DEBUG, "MRZ Row 1: " _YELLOW_("%.44s"), mrz); + PrintAndLogEx(DEBUG, "MRZ Row 2: " _YELLOW_("%.44s"), mrz + 44); + } + + PrintAndLogEx(SUCCESS, "Issuing state.........: " _YELLOW_("%.3s"), mrz + 2); + + if (td_variant == 3) { + // Passport form factor + PrintAndLogEx(SUCCESS, "Nationality...........: " _YELLOW_("%.3s"), mrz + 44 + 10); + emrtd_print_name(mrz, 5, 38, false); + emrtd_print_document_number(mrz, 44); + emrtd_print_dob(mrz, 44 + 13, false); + emrtd_print_legal_sex(&mrz[44 + 20]); + emrtd_print_expiry(mrz, 44 + 21); + emrtd_print_optional_elements(mrz, 44 + 28, 14, true); + + // Calculate and verify composite check digit + char composite_check_data[50] = { 0x00 }; + memcpy(composite_check_data, mrz + 44, 10); + memcpy(composite_check_data + 10, mrz + 44 + 13, 7); + memcpy(composite_check_data + 17, mrz + 44 + 21, 23); + + if (!emrtd_compare_check_digit(composite_check_data, 39, mrz[87])) { + PrintAndLogEx(SUCCESS, _RED_("Composite check digit is invalid.")); + } + } else if (td_variant == 1) { + // ID form factor + PrintAndLogEx(SUCCESS, "Nationality...........: " _YELLOW_("%.3s"), mrz + 30 + 15); + emrtd_print_name(mrz, 60, 30, false); + emrtd_print_document_number(mrz, 5); + emrtd_print_dob(mrz, 30, false); + emrtd_print_legal_sex(&mrz[30 + 7]); + emrtd_print_expiry(mrz, 30 + 8); + emrtd_print_optional_elements(mrz, 15, 15, false); + emrtd_print_optional_elements(mrz, 30 + 18, 11, false); + + // Calculate and verify composite check digit + if (!emrtd_compare_check_digit(mrz, 59, mrz[59])) { + PrintAndLogEx(SUCCESS, _RED_("Composite check digit is invalid.")); + } + } + + return true; +} + +static bool emrtd_print_ef_dg11_info(uint8_t *response, int resplen) { uint8_t taglist[100] = { 0x00 }; int taglistlen = 0; uint8_t tagdata[1000] = { 0x00 }; @@ -1195,11 +1276,6 @@ static bool emrtd_print_ef_dg11_info(bool *BAC, uint8_t *ssc, uint8_t *ks_enc, u PrintAndLogEx(NORMAL, ""); PrintAndLogEx(INFO, "-------------------- " _CYAN_("EF_DG11") " -------------------"); - if (!emrtd_select_and_read(response, &resplen, EMRTD_EF_DG11, ks_enc, ks_mac, ssc, *BAC, *use_14b)) { - PrintAndLogEx(ERR, "Failed to read EF_DG11."); - return false; - } - if (!emrtd_lds_get_data_by_tag(response, &resplen, taglist, &taglistlen, 0x5c, 0x00, false)) { PrintAndLogEx(ERR, "Failed to read file list from EF_DG11."); return false; @@ -1272,8 +1348,6 @@ int infoHF_EMRTD(char *documentnumber, char *dob, char *expiry, bool BAC_availab bool BAC = false; bool use_14b = false; - int td_variant = 0; - // Select the eMRTD if (!emrtd_connect(&use_14b)) { DropField(); @@ -1294,96 +1368,37 @@ int infoHF_EMRTD(char *documentnumber, char *dob, char *expiry, bool BAC_availab return PM3_ESOFT; } - // Select EF_DG1 - if (emrtd_select_and_read(response, &resplen, EMRTD_EF_DG1, ks_enc, ks_mac, ssc, BAC, use_14b) == false) { - PrintAndLogEx(ERR, "Failed to read EF_DG1."); + if (!emrtd_select_and_read(response, &resplen, EMRTD_EF_COM, ks_enc, ks_mac, ssc, BAC, use_14b)) { + PrintAndLogEx(ERR, "Failed to read EF_COM."); DropField(); return PM3_ESOFT; } - PrintAndLogEx(NORMAL, ""); - PrintAndLogEx(INFO, "-------------------- " _CYAN_("EF_DG1") " --------------------"); + uint8_t filelist[50]; + int filelistlen = 0; - // MRZ on TD1 is 90 characters, 30 on each row. - // MRZ on TD3 is 88 characters, 44 on each row. - char mrz[90] = { 0x00 }; - int mrzlen = 0; - - if (!emrtd_lds_get_data_by_tag(response, &resplen, (uint8_t *) mrz, &mrzlen, 0x5f, 0x1f, true)) { - PrintAndLogEx(ERR, "Failed to read MRZ from EF_DG1."); + if (!emrtd_lds_get_data_by_tag(response, &resplen, filelist, &filelistlen, 0x5c, 0x00, false)) { + PrintAndLogEx(ERR, "Failed to read file list from EF_COM."); DropField(); return PM3_ESOFT; } - // Determine and print the document type - if (mrz[0] == 'I' && mrz[1] == 'P') { - td_variant = 1; - PrintAndLogEx(SUCCESS, "Document Type.........: " _YELLOW_("Passport Card")); - } else if (mrz[0] == 'I') { - td_variant = 1; - PrintAndLogEx(SUCCESS, "Document Type.........: " _YELLOW_("ID Card")); - } else if (mrz[0] == 'P') { - td_variant = 3; - PrintAndLogEx(SUCCESS, "Document Type.........: " _YELLOW_("Passport")); - } else { - td_variant = 1; - PrintAndLogEx(SUCCESS, "Document Type.........: " _YELLOW_("Unknown")); - PrintAndLogEx(INFO, "Assuming ID-style MRZ."); - } - PrintAndLogEx(SUCCESS, "Document Form Factor..: " _YELLOW_("TD%i"), td_variant); - - // Print the MRZ - if (td_variant == 1) { - PrintAndLogEx(DEBUG, "MRZ Row 1: " _YELLOW_("%.30s"), mrz); - PrintAndLogEx(DEBUG, "MRZ Row 2: " _YELLOW_("%.30s"), mrz + 30); - PrintAndLogEx(DEBUG, "MRZ Row 3: " _YELLOW_("%.30s"), mrz + 60); - } else if (td_variant == 3) { - PrintAndLogEx(DEBUG, "MRZ Row 1: " _YELLOW_("%.44s"), mrz); - PrintAndLogEx(DEBUG, "MRZ Row 2: " _YELLOW_("%.44s"), mrz + 44); - } - - PrintAndLogEx(SUCCESS, "Issuing state.........: " _YELLOW_("%.3s"), mrz + 2); - - if (td_variant == 3) { - // Passport form factor - PrintAndLogEx(SUCCESS, "Nationality...........: " _YELLOW_("%.3s"), mrz + 44 + 10); - emrtd_print_name(mrz, 5, 38, false); - emrtd_print_document_number(mrz, 44); - emrtd_print_dob(mrz, 44 + 13, false); - emrtd_print_legal_sex(&mrz[44 + 20]); - emrtd_print_expiry(mrz, 44 + 21); - emrtd_print_optional_elements(mrz, 44 + 28, 14, true); - - // Calculate and verify composite check digit - char composite_check_data[50] = { 0x00 }; - memcpy(composite_check_data, mrz + 44, 10); - memcpy(composite_check_data + 10, mrz + 44 + 13, 7); - memcpy(composite_check_data + 17, mrz + 44 + 21, 23); - - if (!emrtd_compare_check_digit(composite_check_data, 39, mrz[87])) { - PrintAndLogEx(SUCCESS, _RED_("Composite check digit is invalid.")); + // Dump all files in the file list + for (int i = 0; i < filelistlen; i++) { + char file_id[5] = { 0x00 }; + char file_name[8] = { 0x00 }; + if (emrtd_file_tag_to_file_id(&filelist[i], file_name, file_id) == false) { + PrintAndLogEx(DEBUG, "File tag not found, skipping: %02X", filelist[i]); + continue; } - } else if (td_variant == 1) { - // ID form factor - PrintAndLogEx(SUCCESS, "Nationality...........: " _YELLOW_("%.3s"), mrz + 30 + 15); - emrtd_print_name(mrz, 60, 30, false); - emrtd_print_document_number(mrz, 5); - emrtd_print_dob(mrz, 30, false); - emrtd_print_legal_sex(&mrz[30 + 7]); - emrtd_print_expiry(mrz, 30 + 8); - emrtd_print_optional_elements(mrz, 15, 15, false); - emrtd_print_optional_elements(mrz, 30 + 18, 11, false); - // Calculate and verify composite check digit - if (!emrtd_compare_check_digit(mrz, 59, mrz[59])) { - PrintAndLogEx(SUCCESS, _RED_("Composite check digit is invalid.")); + if (strcmp(file_name, "EF_DG1") == 0 && emrtd_select_and_read(response, &resplen, EMRTD_EF_DG1, ks_enc, ks_mac, ssc, BAC, use_14b)) { + emrtd_print_ef_dg1_info(response, resplen); + } else if (strcmp(file_name, "EF_DG11") == 0 && emrtd_select_and_read(response, &resplen, EMRTD_EF_DG11, ks_enc, ks_mac, ssc, BAC, use_14b)) { + emrtd_print_ef_dg11_info(response, resplen); } } - // Print EF_DG11 info - // TODO: verify existence from file list, also print file list in info. - emrtd_print_ef_dg11_info(&BAC, ssc, ks_enc, ks_mac, &use_14b); - DropField(); return PM3_SUCCESS; } From 15e171b09dca3be141585847e719e8f977803221 Mon Sep 17 00:00:00 2001 From: iceman1001 Date: Fri, 18 Dec 2020 22:05:16 +0100 Subject: [PATCH 131/682] hf 14b info - now supports aidsearch --- client/src/aidsearch.c | 20 +++---- client/src/cmdhf14b.c | 130 ++++++++++++++++++++++++++++++++++++++--- client/src/cmdhf14b.h | 2 +- 3 files changed, 133 insertions(+), 19 deletions(-) diff --git a/client/src/aidsearch.c b/client/src/aidsearch.c index 47c64e77b..3a9d55ace 100644 --- a/client/src/aidsearch.c +++ b/client/src/aidsearch.c @@ -36,7 +36,7 @@ static int openAIDFile(json_t **root, bool verbose) { goto out; } - if (verbose) PrintAndLogEx(SUCCESS, "Loaded file (%s) OK. %zu records.", path, json_array_size(*root)); + PrintAndLogEx(DEBUG, "Loaded file " _YELLOW_("%s") " " _GREEN_("%zu") " records ( " _GREEN_("ok") " )", path, json_array_size(*root)); out: free(path); return retval; @@ -145,22 +145,22 @@ int PrintAIDDescription(json_t *xroot, char *aid, bool verbose) { const char *description = jsonStrGet(elm, "Description"); const char *type = jsonStrGet(elm, "Type"); - if (!verbose) { - PrintAndLogEx(SUCCESS, "AID %s | %s | %s", vaid, vendor, name); + if (verbose == false) { + PrintAndLogEx(SUCCESS, "AID : " _YELLOW_("%s") " | %s | %s", vaid, vendor, name); } else { - PrintAndLogEx(SUCCESS, "Input AID: %s", aid); + PrintAndLogEx(SUCCESS, "Input AID..... " _YELLOW_("%s"), aid); if (aid) - PrintAndLogEx(SUCCESS, "Found AID: %s", vaid); + PrintAndLogEx(SUCCESS, "Found AID..... " _YELLOW_("%s"), vaid); if (vendor) - PrintAndLogEx(SUCCESS, "Vendor: %s", vendor); + PrintAndLogEx(SUCCESS, "Vendor........ " _YELLOW_("%s"), vendor); if (type) - PrintAndLogEx(SUCCESS, "Type: %s", type); + PrintAndLogEx(SUCCESS, "Type.......... " _YELLOW_("%s"), type); if (name) - PrintAndLogEx(SUCCESS, "Name: %s", name); + PrintAndLogEx(SUCCESS, "Name.......... " _YELLOW_("%s"), name); if (country) - PrintAndLogEx(SUCCESS, "Country: %s", country); + PrintAndLogEx(SUCCESS, "Country....... %s", country); if (description) - PrintAndLogEx(SUCCESS, "Description: %s", description); + PrintAndLogEx(SUCCESS, "Description... %s", description); } out: diff --git a/client/src/cmdhf14b.c b/client/src/cmdhf14b.c index 17c31e0a7..80695b980 100644 --- a/client/src/cmdhf14b.c +++ b/client/src/cmdhf14b.c @@ -24,6 +24,8 @@ #include "protocols.h" // definitions of ISO14B/7816 protocol #include "emv/apduinfo.h" // GetAPDUCodeDescription #include "mifare/ndef.h" // NDEFRecordsDecodeAndPrint +#include "aidsearch.h" + #define TIMEOUT 2000 #define APDU_TIMEOUT 2000 @@ -64,6 +66,103 @@ static uint16_t get_sw(uint8_t *d, uint8_t n) { return d[n] * 0x0100 + d[n + 1]; } +static void hf14b_aid_search(bool verbose) { + + int elmindx = 0; + json_t *root = AIDSearchInit(verbose); + if (root == NULL) { + switch_off_field_14b(); + return; + } + + PrintAndLogEx(INFO, "-------------------- " _CYAN_("AID Search") " --------------------"); + + bool found = false; + bool leave_signal_on = true; + bool activate_field = true; + for (elmindx = 0; elmindx < json_array_size(root); elmindx++) { + + if (kbd_enter_pressed()) { + break; + } + + json_t *data = AIDSearchGetElm(root, elmindx); + uint8_t vaid[200] = {0}; + int vaidlen = 0; + if (!AIDGetFromElm(data, vaid, sizeof(vaid), &vaidlen) || !vaidlen) + continue; + + + // COMPUTE APDU + uint8_t apdu_data[PM3_CMD_DATA_SIZE] = {0}; + int apdu_len = 0; + sAPDU apdu = (sAPDU) {0x00, 0xa4, 0x04, 0x00, vaidlen, vaid}; + + if (APDUEncodeS(&apdu, false, 0x00, apdu_data, &apdu_len)) { + PrintAndLogEx(ERR, "APDU encoding error."); + return; + } + + PrintAndLogEx(DEBUG, ">>>> %s", sprint_hex(apdu_data, apdu_len)); + + int resultlen = 0; + uint8_t result[1024] = {0}; + int res = exchange_14b_apdu(apdu_data, apdu_len, activate_field, leave_signal_on, result, sizeof(result), &resultlen, -1); + activate_field = false; + if (res) + continue; + + uint16_t sw = get_sw(result, resultlen); + + uint8_t dfname[200] = {0}; + size_t dfnamelen = 0; + if (resultlen > 3) { + struct tlvdb *tlv = tlvdb_parse_multi(result, resultlen); + if (tlv) { + // 0x84 Dedicated File (DF) Name + const struct tlv *dfnametlv = tlvdb_get_tlv(tlvdb_find_full(tlv, 0x84)); + if (dfnametlv) { + dfnamelen = dfnametlv->len; + memcpy(dfname, dfnametlv->value, dfnamelen); + } + tlvdb_free(tlv); + } + } + + if (sw == 0x9000 || sw == 0x6283 || sw == 0x6285) { + if (sw == 0x9000) { + if (verbose) PrintAndLogEx(SUCCESS, "Application ( " _GREEN_("ok") " )"); + } else { + if (verbose) PrintAndLogEx(WARNING, "Application ( " _RED_("blocked") " )"); + } + + PrintAIDDescriptionBuf(root, vaid, vaidlen, verbose); + + if (dfnamelen) { + if (dfnamelen == vaidlen) { + if (memcmp(dfname, vaid, vaidlen) == 0) { + if (verbose) PrintAndLogEx(INFO, "(DF) Name found and equal to AID"); + } else { + PrintAndLogEx(INFO, "(DF) Name not equal to AID: %s :", sprint_hex(dfname, dfnamelen)); + PrintAIDDescriptionBuf(root, dfname, dfnamelen, verbose); + } + } else { + PrintAndLogEx(INFO, "(DF) Name not equal to AID: %s :", sprint_hex(dfname, dfnamelen)); + PrintAIDDescriptionBuf(root, dfname, dfnamelen, verbose); + } + } else { + if (verbose) PrintAndLogEx(INFO, "(DF) Name not found"); + } + + if (verbose) PrintAndLogEx(SUCCESS, "----------------------------------------------------"); + found = true; + } + } + switch_off_field_14b(); + if (verbose == false && found) + PrintAndLogEx(INFO, "----------------------------------------------------"); +} + static bool wait_cmd_14b(bool verbose, bool is_select) { PacketResponseNG resp; @@ -650,7 +749,7 @@ static void print_ct_general_info(void *vcard) { // 0200a4040010a000000018300301000000000000000000 (resp 02 6a 82 [4b 4c]) // 14b get and print Full Info (as much as we know) -static bool HF14B_Std_Info(bool verbose) { +static bool HF14B_Std_Info(bool verbose, bool do_aid_search) { bool is_success = false; @@ -671,14 +770,21 @@ static bool HF14B_Std_Info(bool verbose) { int status = resp.oldarg[0]; switch (status) { - case 0: + case 0: { PrintAndLogEx(NORMAL, ""); + PrintAndLogEx(INFO, "-------------------- " _CYAN_("Tag information") " --------------------"); PrintAndLogEx(SUCCESS, " UID : " _GREEN_("%s"), sprint_hex(card.uid, card.uidlen)); PrintAndLogEx(SUCCESS, " ATQB : %s", sprint_hex(card.atqb, sizeof(card.atqb))); PrintAndLogEx(SUCCESS, " CHIPID : %02X", card.chipid); print_atqb_resp(card.atqb, card.cid); + + if (do_aid_search) { + hf14b_aid_search(verbose); + } + is_success = true; break; + } case -1: if (verbose) PrintAndLogEx(FAILED, "ISO 14443-3 ATTRIB fail"); break; @@ -694,7 +800,7 @@ static bool HF14B_Std_Info(bool verbose) { } // SRx get and print full info (needs more info...) -static bool HF14B_ST_Info(bool verbose) { +static bool HF14B_ST_Info(bool verbose, bool do_aid_search) { clearCommandBuffer(); PacketResponseNG resp; SendCommandMIX(CMD_HF_ISO14443B_COMMAND, ISO14B_CONNECT | ISO14B_SELECT_SR | ISO14B_DISCONNECT, 0, 0, NULL, 0); @@ -712,6 +818,12 @@ static bool HF14B_ST_Info(bool verbose) { return false; print_st_general_info(card.uid, card.uidlen); + + if (do_aid_search) { + hf14b_aid_search(verbose); + } + + return true; } @@ -725,13 +837,15 @@ static int CmdHF14Binfo(const char *Cmd) { void *argtable[] = { arg_param_begin, + arg_lit0("s", "aidsearch", "checks if AIDs from aidlist.json is present on the card and prints information about found AIDs"), arg_lit0("v", "verbose", "verbose"), arg_param_end }; CLIExecWithReturn(ctx, Cmd, argtable, true); - bool verbose = arg_get_lit(ctx, 1); + bool do_aid_search = arg_get_lit(ctx, 1); + bool verbose = arg_get_lit(ctx, 2); CLIParserFree(ctx); - return infoHF14B(verbose); + return infoHF14B(verbose, do_aid_search); } static bool HF14B_st_reader(bool verbose) { @@ -1830,14 +1944,14 @@ int CmdHF14B(const char *Cmd) { } // get and print all info known about any known 14b tag -int infoHF14B(bool verbose) { +int infoHF14B(bool verbose, bool do_aid_search) { // try std 14b (atqb) - if (HF14B_Std_Info(verbose)) + if (HF14B_Std_Info(verbose, do_aid_search)) return 1; // try ST 14b - if (HF14B_ST_Info(verbose)) + if (HF14B_ST_Info(verbose, do_aid_search)) return 1; // try unknown 14b read commands (to be identified later) diff --git a/client/src/cmdhf14b.h b/client/src/cmdhf14b.h index 9bbb17625..bd97bbf5c 100644 --- a/client/src/cmdhf14b.h +++ b/client/src/cmdhf14b.h @@ -17,6 +17,6 @@ int CmdHF14B(const char *Cmd); int exchange_14b_apdu(uint8_t *datain, int datainlen, bool activate_field, bool leave_signal_on, uint8_t *dataout, int maxdataoutlen, int *dataoutlen, int user_timeout); -int infoHF14B(bool verbose); +int infoHF14B(bool verbose, bool do_aid_search); int readHF14B(bool verbose); #endif From 72f868e2a0a0a15e18f2b2ab8f365d141a77fcf2 Mon Sep 17 00:00:00 2001 From: iceman1001 Date: Fri, 18 Dec 2020 22:10:30 +0100 Subject: [PATCH 132/682] hf 14a info - now aidsearch is interuptable with press --- client/src/cmdhf14a.c | 22 ++++++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/client/src/cmdhf14a.c b/client/src/cmdhf14a.c index d9ff4c3b7..a1cf5b76e 100644 --- a/client/src/cmdhf14a.c +++ b/client/src/cmdhf14a.c @@ -26,9 +26,8 @@ #include "util_posix.h" // msclock #include "aidsearch.h" #include "cmdhf.h" // handle HF plot -#include "protocols.h" // MAGIC_GEN_1A #include "cliparser.h" -#include "protocols.h" // definitions of ISO14A/7816 protocol +#include "protocols.h" // definitions of ISO14A/7816 protocol, MAGIC_GEN_1A #include "emv/apduinfo.h" // GetAPDUCodeDescription bool APDUInFramingEnable = true; @@ -2001,11 +2000,21 @@ int infoHF14A(bool verbose, bool do_nack_test, bool do_aid_search) { } if (do_aid_search) { + + + PrintAndLogEx(INFO, "-------------------- " _CYAN_("AID Search") " --------------------"); + + bool found = false; int elmindx = 0; json_t *root = AIDSearchInit(verbose); if (root != NULL) { bool ActivateField = true; for (elmindx = 0; elmindx < json_array_size(root); elmindx++) { + + if (kbd_enter_pressed()) { + break; + } + json_t *data = AIDSearchGetElm(root, elmindx); uint8_t vaid[200] = {0}; int vaidlen = 0; @@ -2037,9 +2046,9 @@ int infoHF14A(bool verbose, bool do_nack_test, bool do_aid_search) { if (sw == 0x9000 || sw == 0x6283 || sw == 0x6285) { if (sw == 0x9000) { - if (verbose) PrintAndLogEx(SUCCESS, "------------- Application OK -----------"); + if (verbose) PrintAndLogEx(SUCCESS, "Application ( " _GREEN_("ok") " )"); } else { - if (verbose) PrintAndLogEx(WARNING, "----------- Application blocked --------"); + if (verbose) PrintAndLogEx(WARNING, "Application ( " _RED_("blocked") " )"); } PrintAIDDescriptionBuf(root, vaid, vaidlen, verbose); @@ -2059,10 +2068,15 @@ int infoHF14A(bool verbose, bool do_nack_test, bool do_aid_search) { } else { if (verbose) PrintAndLogEx(INFO, "(DF) Name not found"); } + + if (verbose) PrintAndLogEx(SUCCESS, "----------------------------------------------------"); + found = true; } } DropField(); + if (verbose == false && found) + PrintAndLogEx(INFO, "----------------------------------------------------"); } } } else { From 5a4e77d7afa35352c05c5867f179111288f69cac Mon Sep 17 00:00:00 2001 From: Ave Date: Sat, 19 Dec 2020 01:05:09 +0300 Subject: [PATCH 133/682] hf emrtd info: Parse and print info about EF_DG12 --- client/src/cmdhfemrtd.c | 77 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 77 insertions(+) diff --git a/client/src/cmdhfemrtd.c b/client/src/cmdhfemrtd.c index f2c3a60d3..82e9753c2 100644 --- a/client/src/cmdhfemrtd.c +++ b/client/src/cmdhfemrtd.c @@ -1183,6 +1183,22 @@ static void emrtd_print_expiry(char *mrz, int offset) { } } +static void emrtd_print_issuance(char *data) { + char final_date[12] = { 0x00 }; + emrtd_mrz_convert_date(data, 0, final_date, true, true); + + PrintAndLogEx(SUCCESS, "Date of issue.........: " _YELLOW_("%s"), final_date); +} + +static void emrtd_print_personalization_timestamp(uint8_t *data) { + char str_date[0x0F] = { 0x00 }; + strcpy(str_date, sprint_hex_inrow(data, 0x0E)); + char final_date[20] = { 0x00 }; + sprintf(final_date, "%.4s-%.2s-%.2s %.2s:%.2s:%.2s", str_date, str_date + 4, str_date + 6, str_date + 8, str_date + 10, str_date + 12); + + PrintAndLogEx(SUCCESS, "Personalization at....: " _YELLOW_("%s"), final_date); +} + static bool emrtd_print_ef_dg1_info(uint8_t *response, int resplen) { int td_variant = 0; @@ -1339,6 +1355,65 @@ static bool emrtd_print_ef_dg11_info(uint8_t *response, int resplen) { return true; } +static bool emrtd_print_ef_dg12_info(uint8_t *response, int resplen) { + uint8_t taglist[100] = { 0x00 }; + int taglistlen = 0; + uint8_t tagdata[1000] = { 0x00 }; + int tagdatalen = 0; + + PrintAndLogEx(NORMAL, ""); + PrintAndLogEx(INFO, "-------------------- " _CYAN_("EF_DG12") " -------------------"); + + if (!emrtd_lds_get_data_by_tag(response, &resplen, taglist, &taglistlen, 0x5c, 0x00, false)) { + PrintAndLogEx(ERR, "Failed to read file list from EF_DG12."); + return false; + } + + for (int i = 0; i < taglistlen; i++) { + emrtd_lds_get_data_by_tag(response, &resplen, tagdata, &tagdatalen, taglist[i], taglist[i + 1], taglist[i] == 0x5f); + // Special behavior for two char tags + if (taglist[i] == 0x5f) { + // Several things here are longer than the rest but I can't think of a way to shorten them + // ...and I doubt many states are using them. + switch (taglist[i + 1]) { + case 0x19: + PrintAndLogEx(SUCCESS, "Issuing Authority.....: " _YELLOW_("%.*s"), tagdatalen, tagdata); + break; + case 0x26: + emrtd_print_issuance((char *) tagdata); + break; + case 0x1b: + PrintAndLogEx(SUCCESS, "Endorsements & Observations: " _YELLOW_("%.*s"), tagdatalen, tagdata); + break; + case 0x1c: + PrintAndLogEx(SUCCESS, "Tax/Exit Requirements.: " _YELLOW_("%.*s"), tagdatalen, tagdata); + break; + case 0x1d: + saveFile("FrontOfDocument", ".jpg", tagdata, tagdatalen); + break; + case 0x1e: + saveFile("BackOfDocument", ".jpg", tagdata, tagdatalen); + break; + case 0x55: + emrtd_print_personalization_timestamp(tagdata); + break; + case 0x56: + PrintAndLogEx(SUCCESS, "Serial of Personalization System: " _YELLOW_("%.*s"), tagdatalen, tagdata); + break; + default: + PrintAndLogEx(SUCCESS, "Unknown Field %02X%02X....: %s", taglist[i], taglist[i + 1], sprint_hex_inrow(tagdata, tagdatalen)); + break; + } + + i += 1; + } else { + // TODO: Account for A0 + PrintAndLogEx(SUCCESS, "Unknown Field %02X......: %s", taglist[i], sprint_hex_inrow(tagdata, tagdatalen)); + } + } + return true; +} + int infoHF_EMRTD(char *documentnumber, char *dob, char *expiry, bool BAC_available) { uint8_t response[EMRTD_MAX_FILE_SIZE] = { 0x00 }; int resplen = 0; @@ -1396,6 +1471,8 @@ int infoHF_EMRTD(char *documentnumber, char *dob, char *expiry, bool BAC_availab emrtd_print_ef_dg1_info(response, resplen); } else if (strcmp(file_name, "EF_DG11") == 0 && emrtd_select_and_read(response, &resplen, EMRTD_EF_DG11, ks_enc, ks_mac, ssc, BAC, use_14b)) { emrtd_print_ef_dg11_info(response, resplen); + } else if (strcmp(file_name, "EF_DG12") == 0 && emrtd_select_and_read(response, &resplen, EMRTD_EF_DG12, ks_enc, ks_mac, ssc, BAC, use_14b)) { + emrtd_print_ef_dg12_info(response, resplen); } } From 24b0e042cbbfbac02091ddaa7c9d48954ba7f77e Mon Sep 17 00:00:00 2001 From: Ave Date: Sat, 19 Dec 2020 01:35:32 +0300 Subject: [PATCH 134/682] Resolve coverity 308206 and 308207 --- client/src/cmdhfemrtd.c | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/client/src/cmdhfemrtd.c b/client/src/cmdhfemrtd.c index 82e9753c2..796e765b0 100644 --- a/client/src/cmdhfemrtd.c +++ b/client/src/cmdhfemrtd.c @@ -1523,7 +1523,8 @@ static int cmd_hf_emrtd_dump(const char *Cmd) { uint8_t dob[7] = { 0x00 }; uint8_t expiry[7] = { 0x00 }; bool BAC = true; - int slen = 0; // unused + bool error = false; + int slen = 0; // Go through all args, if even one isn't supplied, mark BAC as unavailable if (CLIParamStrToBuf(arg_get_str(ctx, 1), docnum, 9, &slen) != 0 || slen == 0) { BAC = false; @@ -1541,7 +1542,7 @@ static int cmd_hf_emrtd_dump(const char *Cmd) { if (!validate_date(dob, slen)) { PrintAndLogEx(ERR, "Date of birth date format is incorrect, cannot continue."); PrintAndLogEx(HINT, "Use the format YYMMDD."); - return PM3_ESOFT; + error = true; } } @@ -1551,11 +1552,14 @@ static int cmd_hf_emrtd_dump(const char *Cmd) { if (!validate_date(expiry, slen)) { PrintAndLogEx(ERR, "Expiry date format is incorrect, cannot continue."); PrintAndLogEx(HINT, "Use the format YYMMDD."); - return PM3_ESOFT; + error = true; } } CLIParserFree(ctx); + if (error) { + return PM3_ESOFT; + } return dumpHF_EMRTD((char *)docnum, (char *)dob, (char *)expiry, BAC); } @@ -1579,7 +1583,8 @@ static int cmd_hf_emrtd_info(const char *Cmd) { uint8_t dob[7] = { 0x00 }; uint8_t expiry[7] = { 0x00 }; bool BAC = true; - int slen = 0; // unused + bool error = false; + int slen = 0; // Go through all args, if even one isn't supplied, mark BAC as unavailable if (CLIParamStrToBuf(arg_get_str(ctx, 1), docnum, 9, &slen) != 0 || slen == 0) { BAC = false; @@ -1596,7 +1601,7 @@ static int cmd_hf_emrtd_info(const char *Cmd) { if (!validate_date(dob, slen)) { PrintAndLogEx(ERR, "Date of birth date format is incorrect, cannot continue."); PrintAndLogEx(HINT, "Use the format YYMMDD."); - return PM3_ESOFT; + error = true; } } @@ -1606,11 +1611,14 @@ static int cmd_hf_emrtd_info(const char *Cmd) { if (!validate_date(expiry, slen)) { PrintAndLogEx(ERR, "Expiry date format is incorrect, cannot continue."); PrintAndLogEx(HINT, "Use the format YYMMDD."); - return PM3_ESOFT; + error = true; } } CLIParserFree(ctx); + if (error) { + return PM3_ESOFT; + } return infoHF_EMRTD((char *)docnum, (char *)dob, (char *)expiry, BAC); } From 7a9e129ad9513666852550ee417406aff25f7870 Mon Sep 17 00:00:00 2001 From: Philippe Teuwen Date: Sat, 19 Dec 2020 00:19:11 +0100 Subject: [PATCH 135/682] hf emrtd info: add option to load from files --- client/src/cmdhfemrtd.c | 76 +++++++++++++++++++++++++++++++++++++++-- client/src/cmdhfemrtd.h | 1 + 2 files changed, 74 insertions(+), 3 deletions(-) diff --git a/client/src/cmdhfemrtd.c b/client/src/cmdhfemrtd.c index 796e765b0..97b8264df 100644 --- a/client/src/cmdhfemrtd.c +++ b/client/src/cmdhfemrtd.c @@ -1480,6 +1480,70 @@ int infoHF_EMRTD(char *documentnumber, char *dob, char *expiry, bool BAC_availab return PM3_SUCCESS; } +int infoHF_EMRTD_offline(const char *path) { + uint8_t *data; + int datalen = 0; + char *filepath = calloc(strlen(path) + 100, sizeof(char)); + if (filepath == NULL) + return PM3_EMALLOC; + strcpy(filepath, path); + strncat(filepath, PATHSEP, 1); + strcat(filepath, "EF_COM"); + + if (loadFile_safeEx(filepath, ".BIN", (void **)&data, (size_t *)&datalen, true) != PM3_SUCCESS) { + PrintAndLogEx(ERR, "Failed to read EF_COM."); + free(filepath); + return PM3_ESOFT; + } + uint8_t filelist[50]; + int filelistlen = 0; + int res = emrtd_lds_get_data_by_tag(data, &datalen, filelist, &filelistlen, 0x5c, 0x00, false); + free(data); + if (!res) { + PrintAndLogEx(ERR, "Failed to read file list from EF_COM."); + free(filepath); + return PM3_ESOFT; + } + + // Read files in the file list + for (int i = 0; i < filelistlen; i++) { + char file_id[5] = { 0x00 }; + char file_name[8] = { 0x00 }; + if (emrtd_file_tag_to_file_id(&filelist[i], file_name, file_id) == false) { + PrintAndLogEx(DEBUG, "File tag not found, skipping: %02X", filelist[i]); + continue; + } + + if (strcmp(file_name, "EF_DG1") == 0) { + strcpy(filepath, path); + strncat(filepath, PATHSEP, 1); + strcat(filepath, "EF_DG1"); + if (loadFile_safeEx(filepath, ".BIN", (void **)&data, (size_t *)&datalen, true) == PM3_SUCCESS) { + emrtd_print_ef_dg1_info(data, datalen); + free(data); + } + } else if (strcmp(file_name, "EF_DG11") == 0) { + strcpy(filepath, path); + strncat(filepath, PATHSEP, 1); + strcat(filepath, "EF_DG11"); + if (loadFile_safeEx(filepath, ".BIN", (void **)&data, (size_t *)&datalen, true) == PM3_SUCCESS) { + emrtd_print_ef_dg11_info(data, datalen); + free(data); + } + } else if (strcmp(file_name, "EF_DG12") == 0) { + strcpy(filepath, path); + strncat(filepath, PATHSEP, 1); + strcat(filepath, "EF_DG12"); + if (loadFile_safeEx(filepath, ".BIN", (void **)&data, (size_t *)&datalen, true) == PM3_SUCCESS) { + emrtd_print_ef_dg12_info(data, datalen); + free(data); + } + } + } + free(filepath); + return PM3_SUCCESS; +} + static void text_to_upper(uint8_t *data, int datalen) { // Loop over text to make lowercase text uppercase for (int i = 0; i < datalen; i++) { @@ -1575,6 +1639,7 @@ static int cmd_hf_emrtd_info(const char *Cmd) { arg_str0("n", "documentnumber", "", "document number, up to 9 chars"), arg_str0("d", "dateofbirth", "", "date of birth in YYMMDD format"), arg_str0("e", "expiry", "", "expiry in YYMMDD format"), + arg_str0("p", "path", "", "display info from offline dump stored in dirpath"), arg_param_end }; CLIExecWithReturn(ctx, Cmd, argtable, true); @@ -1614,12 +1679,17 @@ static int cmd_hf_emrtd_info(const char *Cmd) { error = true; } } - + uint8_t path[FILENAME_MAX] = { 0x00 }; + bool offline = CLIParamStrToBuf(arg_get_str(ctx, 4), path, sizeof(path), &slen) == 0 && slen > 0; CLIParserFree(ctx); if (error) { return PM3_ESOFT; } - return infoHF_EMRTD((char *)docnum, (char *)dob, (char *)expiry, BAC); + if (offline) { + return infoHF_EMRTD_offline((const char *)path); + } else { + return infoHF_EMRTD((char *)docnum, (char *)dob, (char *)expiry, BAC); + } } static int cmd_hf_emrtd_list(const char *Cmd) { @@ -1635,7 +1705,7 @@ static int cmd_hf_emrtd_list(const char *Cmd) { static command_t CommandTable[] = { {"help", CmdHelp, AlwaysAvailable, "This help"}, {"dump", cmd_hf_emrtd_dump, IfPm3Iso14443, "Dump eMRTD files to binary files"}, - {"info", cmd_hf_emrtd_info, IfPm3Iso14443, "Display info about an eMRTD"}, + {"info", cmd_hf_emrtd_info, AlwaysAvailable, "Display info about an eMRTD"}, {"list", cmd_hf_emrtd_list, AlwaysAvailable, "List ISO 14443A/7816 history"}, {NULL, NULL, NULL, NULL} }; diff --git a/client/src/cmdhfemrtd.h b/client/src/cmdhfemrtd.h index f19a71ac0..3cfcd3cbd 100644 --- a/client/src/cmdhfemrtd.h +++ b/client/src/cmdhfemrtd.h @@ -17,4 +17,5 @@ int CmdHFeMRTD(const char *Cmd); int dumpHF_EMRTD(char *documentnumber, char *dob, char *expiry, bool BAC_available); int infoHF_EMRTD(char *documentnumber, char *dob, char *expiry, bool BAC_available); +int infoHF_EMRTD_offline(const char *path); #endif From bdcf84f90de080bc32332cbbe6fcb9205d9f7342 Mon Sep 17 00:00:00 2001 From: Philippe Teuwen Date: Sat, 19 Dec 2020 00:59:27 +0100 Subject: [PATCH 136/682] fix emrtd info offline bug --- client/src/cmdhfemrtd.c | 35 +++++++++++++++++------------------ 1 file changed, 17 insertions(+), 18 deletions(-) diff --git a/client/src/cmdhfemrtd.c b/client/src/cmdhfemrtd.c index 97b8264df..fda90889f 100644 --- a/client/src/cmdhfemrtd.c +++ b/client/src/cmdhfemrtd.c @@ -568,14 +568,14 @@ static int emrtd_read_file(uint8_t *dataout, int *dataoutlen, uint8_t *kenc, uin return true; } -static bool emrtd_lds_get_data_by_tag(uint8_t *datain, int *datainlen, uint8_t *dataout, int *dataoutlen, int tag1, int tag2, bool twobytetag) { +static bool emrtd_lds_get_data_by_tag(uint8_t *datain, int datainlen, uint8_t *dataout, int *dataoutlen, int tag1, int tag2, bool twobytetag) { int offset = 1; - offset += emrtd_get_asn1_field_length(datain, *datainlen, offset); + offset += emrtd_get_asn1_field_length(datain, datainlen, offset); int e_idlen = 0; int e_datalen = 0; int e_fieldlen = 0; - while (offset < *datainlen) { + while (offset < datainlen) { PrintAndLogEx(DEBUG, "emrtd_lds_get_data_by_tag, offset: %i, data: %X", offset, *(datain + offset)); // Determine element ID length to set as offset on asn1datalength if ((*(datain + offset) == 0x5F) || (*(datain + offset) == 0x7F)) { @@ -585,14 +585,14 @@ static bool emrtd_lds_get_data_by_tag(uint8_t *datain, int *datainlen, uint8_t * } // Get the length of the element - e_datalen = emrtd_get_asn1_data_length(datain + offset, *datainlen - offset, e_idlen); + e_datalen = emrtd_get_asn1_data_length(datain + offset, datainlen - offset, e_idlen); // Get the length of the element's length - e_fieldlen = emrtd_get_asn1_field_length(datain + offset, *datainlen - offset, e_idlen); + e_fieldlen = emrtd_get_asn1_field_length(datain + offset, datainlen - offset, e_idlen); // If the element is what we're looking for, get the data and return true if (*(datain + offset) == tag1 && (!twobytetag || *(datain + offset + 1) == tag2)) { - if (*datainlen > e_datalen) { + if (datainlen > e_datalen) { *dataoutlen = e_datalen; memcpy(dataout, datain + offset + e_idlen + e_fieldlen, e_datalen); return true; @@ -741,7 +741,7 @@ static bool emrtd_dump_ef_dg5(uint8_t *file_contents, int file_length) { int datalen = 0; // If we can't find image in EF_DG5, return false. - if (emrtd_lds_get_data_by_tag(file_contents, &file_length, data, &datalen, 0x5F, 0x40, true) == false) { + if (emrtd_lds_get_data_by_tag(file_contents, file_length, data, &datalen, 0x5F, 0x40, true) == false) { return false; } @@ -1013,7 +1013,7 @@ int dumpHF_EMRTD(char *documentnumber, char *dob, char *expiry, bool BAC_availab uint8_t filelist[50]; int filelistlen = 0; - if (!emrtd_lds_get_data_by_tag(response, &resplen, filelist, &filelistlen, 0x5c, 0x00, false)) { + if (!emrtd_lds_get_data_by_tag(response, resplen, filelist, &filelistlen, 0x5c, 0x00, false)) { PrintAndLogEx(ERR, "Failed to read file list from EF_COM."); DropField(); return PM3_ESOFT; @@ -1210,7 +1210,7 @@ static bool emrtd_print_ef_dg1_info(uint8_t *response, int resplen) { char mrz[90] = { 0x00 }; int mrzlen = 0; - if (!emrtd_lds_get_data_by_tag(response, &resplen, (uint8_t *) mrz, &mrzlen, 0x5f, 0x1f, true)) { + if (!emrtd_lds_get_data_by_tag(response, resplen, (uint8_t *) mrz, &mrzlen, 0x5f, 0x1f, true)) { PrintAndLogEx(ERR, "Failed to read MRZ from EF_DG1."); return false; } @@ -1292,13 +1292,13 @@ static bool emrtd_print_ef_dg11_info(uint8_t *response, int resplen) { PrintAndLogEx(NORMAL, ""); PrintAndLogEx(INFO, "-------------------- " _CYAN_("EF_DG11") " -------------------"); - if (!emrtd_lds_get_data_by_tag(response, &resplen, taglist, &taglistlen, 0x5c, 0x00, false)) { + if (!emrtd_lds_get_data_by_tag(response, resplen, taglist, &taglistlen, 0x5c, 0x00, false)) { PrintAndLogEx(ERR, "Failed to read file list from EF_DG11."); return false; } for (int i = 0; i < taglistlen; i++) { - emrtd_lds_get_data_by_tag(response, &resplen, tagdata, &tagdatalen, taglist[i], taglist[i + 1], taglist[i] == 0x5f); + emrtd_lds_get_data_by_tag(response, resplen, tagdata, &tagdatalen, taglist[i], taglist[i + 1], taglist[i] == 0x5f); // Special behavior for two char tags if (taglist[i] == 0x5f) { switch (taglist[i + 1]) { @@ -1364,13 +1364,13 @@ static bool emrtd_print_ef_dg12_info(uint8_t *response, int resplen) { PrintAndLogEx(NORMAL, ""); PrintAndLogEx(INFO, "-------------------- " _CYAN_("EF_DG12") " -------------------"); - if (!emrtd_lds_get_data_by_tag(response, &resplen, taglist, &taglistlen, 0x5c, 0x00, false)) { + if (!emrtd_lds_get_data_by_tag(response, resplen, taglist, &taglistlen, 0x5c, 0x00, false)) { PrintAndLogEx(ERR, "Failed to read file list from EF_DG12."); return false; } for (int i = 0; i < taglistlen; i++) { - emrtd_lds_get_data_by_tag(response, &resplen, tagdata, &tagdatalen, taglist[i], taglist[i + 1], taglist[i] == 0x5f); + emrtd_lds_get_data_by_tag(response, resplen, tagdata, &tagdatalen, taglist[i], taglist[i + 1], taglist[i] == 0x5f); // Special behavior for two char tags if (taglist[i] == 0x5f) { // Several things here are longer than the rest but I can't think of a way to shorten them @@ -1452,7 +1452,7 @@ int infoHF_EMRTD(char *documentnumber, char *dob, char *expiry, bool BAC_availab uint8_t filelist[50]; int filelistlen = 0; - if (!emrtd_lds_get_data_by_tag(response, &resplen, filelist, &filelistlen, 0x5c, 0x00, false)) { + if (!emrtd_lds_get_data_by_tag(response, resplen, filelist, &filelistlen, 0x5c, 0x00, false)) { PrintAndLogEx(ERR, "Failed to read file list from EF_COM."); DropField(); return PM3_ESOFT; @@ -1482,7 +1482,7 @@ int infoHF_EMRTD(char *documentnumber, char *dob, char *expiry, bool BAC_availab int infoHF_EMRTD_offline(const char *path) { uint8_t *data; - int datalen = 0; + size_t datalen = 0; char *filepath = calloc(strlen(path) + 100, sizeof(char)); if (filepath == NULL) return PM3_EMALLOC; @@ -1497,7 +1497,7 @@ int infoHF_EMRTD_offline(const char *path) { } uint8_t filelist[50]; int filelistlen = 0; - int res = emrtd_lds_get_data_by_tag(data, &datalen, filelist, &filelistlen, 0x5c, 0x00, false); + int res = emrtd_lds_get_data_by_tag(data, datalen, filelist, &filelistlen, 0x5c, 0x00, false); free(data); if (!res) { PrintAndLogEx(ERR, "Failed to read file list from EF_COM."); @@ -1513,7 +1513,6 @@ int infoHF_EMRTD_offline(const char *path) { PrintAndLogEx(DEBUG, "File tag not found, skipping: %02X", filelist[i]); continue; } - if (strcmp(file_name, "EF_DG1") == 0) { strcpy(filepath, path); strncat(filepath, PATHSEP, 1); @@ -1639,7 +1638,7 @@ static int cmd_hf_emrtd_info(const char *Cmd) { arg_str0("n", "documentnumber", "", "document number, up to 9 chars"), arg_str0("d", "dateofbirth", "", "date of birth in YYMMDD format"), arg_str0("e", "expiry", "", "expiry in YYMMDD format"), - arg_str0("p", "path", "", "display info from offline dump stored in dirpath"), + arg_str0(NULL, "path", "", "display info from offline dump stored in dirpath"), arg_param_end }; CLIExecWithReturn(ctx, Cmd, argtable, true); From 6ca472fc8ffa74a2c063a73dc6859aecfd863dea Mon Sep 17 00:00:00 2001 From: Ave Date: Sat, 19 Dec 2020 03:27:48 +0300 Subject: [PATCH 137/682] emrtd: Dump image from EF_DG7 too --- client/src/cmdhfemrtd.c | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/client/src/cmdhfemrtd.c b/client/src/cmdhfemrtd.c index fda90889f..a06beff9a 100644 --- a/client/src/cmdhfemrtd.c +++ b/client/src/cmdhfemrtd.c @@ -735,7 +735,6 @@ static bool emrtd_dump_ef_dg2(uint8_t *file_contents, int file_length) { return true; } - static bool emrtd_dump_ef_dg5(uint8_t *file_contents, int file_length) { uint8_t data[EMRTD_MAX_FILE_SIZE]; int datalen = 0; @@ -754,6 +753,24 @@ static bool emrtd_dump_ef_dg5(uint8_t *file_contents, int file_length) { return true; } +static bool emrtd_dump_ef_dg7(uint8_t *file_contents, int file_length) { + uint8_t data[EMRTD_MAX_FILE_SIZE]; + int datalen = 0; + + // If we can't find image in EF_DG7, return false. + if (emrtd_lds_get_data_by_tag(file_contents, file_length, data, &datalen, 0x5F, 0x42, true) == false) { + return false; + } + + if (datalen < EMRTD_MAX_FILE_SIZE) { + saveFile("EF_DG7", ".jpg", data, datalen); + } else { + PrintAndLogEx(ERR, "error (emrtd_dump_ef_dg7) datalen out-of-bounds"); + return false; + } + return true; +} + static bool emrtd_dump_ef_sod(uint8_t *file_contents, int file_length) { int fieldlen = emrtd_get_asn1_field_length(file_contents, file_length, 1); int datalen = emrtd_get_asn1_data_length(file_contents, file_length, 1); @@ -783,6 +800,8 @@ static bool emrtd_dump_file(uint8_t *ks_enc, uint8_t *ks_mac, uint8_t *ssc, cons emrtd_dump_ef_dg2(response, resplen); } else if (strcmp(file, EMRTD_EF_DG5) == 0) { emrtd_dump_ef_dg5(response, resplen); + } else if (strcmp(file, EMRTD_EF_DG7) == 0) { + emrtd_dump_ef_dg7(response, resplen); } else if (strcmp(file, EMRTD_EF_SOD) == 0) { emrtd_dump_ef_sod(response, resplen); } From 88f0de3176e21d30b2667839cea4e70b5e0f09ae Mon Sep 17 00:00:00 2001 From: Ave Date: Sat, 19 Dec 2020 05:28:21 +0300 Subject: [PATCH 138/682] emrtd: Use .jp2 ext when saving JPG 2000 files --- client/src/cmdhfemrtd.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/client/src/cmdhfemrtd.c b/client/src/cmdhfemrtd.c index a06beff9a..e6875fc63 100644 --- a/client/src/cmdhfemrtd.c +++ b/client/src/cmdhfemrtd.c @@ -731,7 +731,7 @@ static bool emrtd_dump_ef_dg2(uint8_t *file_contents, int file_length) { return false; } - saveFile("EF_DG2", ".jpg", file_contents + offset, datalen); + saveFile("EF_DG2", file_contents[offset] == 0xFF ? ".jpg" : ".jp2", file_contents + offset, datalen); return true; } @@ -745,7 +745,7 @@ static bool emrtd_dump_ef_dg5(uint8_t *file_contents, int file_length) { } if (datalen < EMRTD_MAX_FILE_SIZE) { - saveFile("EF_DG5", ".jpg", data, datalen); + saveFile("EF_DG5", data[0] == 0xFF ? ".jpg" : ".jp2", data, datalen); } else { PrintAndLogEx(ERR, "error (emrtd_dump_ef_dg5) datalen out-of-bounds"); return false; @@ -763,7 +763,7 @@ static bool emrtd_dump_ef_dg7(uint8_t *file_contents, int file_length) { } if (datalen < EMRTD_MAX_FILE_SIZE) { - saveFile("EF_DG7", ".jpg", data, datalen); + saveFile("EF_DG7", data[0] == 0xFF ? ".jpg" : ".jp2", data, datalen); } else { PrintAndLogEx(ERR, "error (emrtd_dump_ef_dg7) datalen out-of-bounds"); return false; @@ -1348,7 +1348,7 @@ static bool emrtd_print_ef_dg11_info(uint8_t *response, int resplen) { PrintAndLogEx(SUCCESS, "Personal Summary......: " _YELLOW_("%.*s"), tagdatalen, tagdata); break; case 0x16: - saveFile("ProofOfCitizenship", ".jpg", tagdata, tagdatalen); + saveFile("ProofOfCitizenship", tagdata[0] == 0xFF ? ".jpg" : ".jp2", tagdata, tagdatalen); break; case 0x17: // TODO: acc for < separation @@ -1408,10 +1408,10 @@ static bool emrtd_print_ef_dg12_info(uint8_t *response, int resplen) { PrintAndLogEx(SUCCESS, "Tax/Exit Requirements.: " _YELLOW_("%.*s"), tagdatalen, tagdata); break; case 0x1d: - saveFile("FrontOfDocument", ".jpg", tagdata, tagdatalen); + saveFile("FrontOfDocument", tagdata[0] == 0xFF ? ".jpg" : ".jp2", tagdata, tagdatalen); break; case 0x1e: - saveFile("BackOfDocument", ".jpg", tagdata, tagdatalen); + saveFile("BackOfDocument", tagdata[0] == 0xFF ? ".jpg" : ".jp2", tagdata, tagdatalen); break; case 0x55: emrtd_print_personalization_timestamp(tagdata); From 333afad302852c22ca03130a98eb65af84821953 Mon Sep 17 00:00:00 2001 From: Ave Date: Sat, 19 Dec 2020 06:49:21 +0300 Subject: [PATCH 139/682] hf emrtd info: Fixes for hungarian passports --- client/src/cmdhfemrtd.c | 46 +++++++++++++++++++++++++++-------------- 1 file changed, 31 insertions(+), 15 deletions(-) diff --git a/client/src/cmdhfemrtd.c b/client/src/cmdhfemrtd.c index e6875fc63..389d10f53 100644 --- a/client/src/cmdhfemrtd.c +++ b/client/src/cmdhfemrtd.c @@ -1154,15 +1154,28 @@ static void emrtd_print_name(char *mrz, int offset, int max_length, bool localiz } } -static void emrtd_mrz_convert_date(char *mrz, int offset, char *final_date, bool is_expiry, bool is_full) { +static void emrtd_mrz_convert_date(char *mrz, int offset, char *final_date, bool is_expiry, bool is_full, bool is_ascii) { + char work_date[9] = { 0x00 }; + int len = is_full ? 8 : 6; + + // Copy the data to a working array in the right format + if (!is_ascii) { + memcpy(work_date, sprint_hex_inrow((uint8_t *)mrz + offset, len / 2), len); + } else { + memcpy(work_date, mrz + offset, len); + } + + // Set offset to 0 as we've now copied data. + offset = 0; + if (is_full) { // If we get the full date, use the first two characters from that for year - memcpy(final_date, mrz, 2); + memcpy(final_date, work_date, 2); // and do + 2 on offset so that rest of code uses the right data offset += 2; } else { char temp_year[3] = { 0x00 }; - memcpy(temp_year, mrz + offset, 2); + memcpy(temp_year, work_date, 2); // If it's > 20, assume 19xx. if (strtol(temp_year, NULL, 10) < 20 || is_expiry) { final_date[0] = '2'; @@ -1173,16 +1186,16 @@ static void emrtd_mrz_convert_date(char *mrz, int offset, char *final_date, bool } } - memcpy(final_date + 2, mrz + offset, 2); + memcpy(final_date + 2, work_date + offset, 2); final_date[4] = '-'; - memcpy(final_date + 5, mrz + offset + 2, 2); + memcpy(final_date + 5, work_date + offset + 2, 2); final_date[7] = '-'; - memcpy(final_date + 8, mrz + offset + 4, 2); + memcpy(final_date + 8, work_date + offset + 4, 2); } -static void emrtd_print_dob(char *mrz, int offset, bool full) { +static void emrtd_print_dob(char *mrz, int offset, bool full, bool ascii) { char final_date[12] = { 0x00 }; - emrtd_mrz_convert_date(mrz, offset, final_date, false, full); + emrtd_mrz_convert_date(mrz, offset, final_date, false, full, ascii); PrintAndLogEx(SUCCESS, "Date of birth.........: " _YELLOW_("%s"), final_date); @@ -1193,7 +1206,7 @@ static void emrtd_print_dob(char *mrz, int offset, bool full) { static void emrtd_print_expiry(char *mrz, int offset) { char final_date[12] = { 0x00 }; - emrtd_mrz_convert_date(mrz, offset, final_date, true, false); + emrtd_mrz_convert_date(mrz, offset, final_date, true, false, true); PrintAndLogEx(SUCCESS, "Date of expiry........: " _YELLOW_("%s"), final_date); @@ -1202,9 +1215,9 @@ static void emrtd_print_expiry(char *mrz, int offset) { } } -static void emrtd_print_issuance(char *data) { +static void emrtd_print_issuance(char *data, bool ascii) { char final_date[12] = { 0x00 }; - emrtd_mrz_convert_date(data, 0, final_date, true, true); + emrtd_mrz_convert_date(data, 0, final_date, true, true, ascii); PrintAndLogEx(SUCCESS, "Date of issue.........: " _YELLOW_("%s"), final_date); } @@ -1268,7 +1281,7 @@ static bool emrtd_print_ef_dg1_info(uint8_t *response, int resplen) { PrintAndLogEx(SUCCESS, "Nationality...........: " _YELLOW_("%.3s"), mrz + 44 + 10); emrtd_print_name(mrz, 5, 38, false); emrtd_print_document_number(mrz, 44); - emrtd_print_dob(mrz, 44 + 13, false); + emrtd_print_dob(mrz, 44 + 13, false, true); emrtd_print_legal_sex(&mrz[44 + 20]); emrtd_print_expiry(mrz, 44 + 21); emrtd_print_optional_elements(mrz, 44 + 28, 14, true); @@ -1287,7 +1300,7 @@ static bool emrtd_print_ef_dg1_info(uint8_t *response, int resplen) { PrintAndLogEx(SUCCESS, "Nationality...........: " _YELLOW_("%.3s"), mrz + 30 + 15); emrtd_print_name(mrz, 60, 30, false); emrtd_print_document_number(mrz, 5); - emrtd_print_dob(mrz, 30, false); + emrtd_print_dob(mrz, 30, false, true); emrtd_print_legal_sex(&mrz[30 + 7]); emrtd_print_expiry(mrz, 30 + 8); emrtd_print_optional_elements(mrz, 15, 15, false); @@ -1324,6 +1337,9 @@ static bool emrtd_print_ef_dg11_info(uint8_t *response, int resplen) { case 0x0e: emrtd_print_name((char *) tagdata, 0, tagdatalen, true); break; + case 0x0f: + emrtd_print_name((char *) tagdata, 0, tagdatalen, false); + break; case 0x10: PrintAndLogEx(SUCCESS, "Personal Number.......: " _YELLOW_("%.*s"), tagdatalen, tagdata); break; @@ -1358,7 +1374,7 @@ static bool emrtd_print_ef_dg11_info(uint8_t *response, int resplen) { PrintAndLogEx(SUCCESS, "Custody Information...: " _YELLOW_("%.*s"), tagdatalen, tagdata); break; case 0x2b: - emrtd_print_dob((char *) tagdata, 0, true); + emrtd_print_dob((char *) tagdata, 0, true, tagdatalen != 4); break; default: PrintAndLogEx(SUCCESS, "Unknown Field %02X%02X....: %s", taglist[i], taglist[i + 1], sprint_hex_inrow(tagdata, tagdatalen)); @@ -1399,7 +1415,7 @@ static bool emrtd_print_ef_dg12_info(uint8_t *response, int resplen) { PrintAndLogEx(SUCCESS, "Issuing Authority.....: " _YELLOW_("%.*s"), tagdatalen, tagdata); break; case 0x26: - emrtd_print_issuance((char *) tagdata); + emrtd_print_issuance((char *) tagdata, tagdatalen != 4); break; case 0x1b: PrintAndLogEx(SUCCESS, "Endorsements & Observations: " _YELLOW_("%.*s"), tagdatalen, tagdata); From 013a8abcd885ffcb19a8311517618935b287a171 Mon Sep 17 00:00:00 2001 From: Ave Date: Sat, 19 Dec 2020 07:01:03 +0300 Subject: [PATCH 140/682] hf emrtd info: Fix segfaults on mononyms --- client/src/cmdhfemrtd.c | 23 +++++++++++++++-------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/client/src/cmdhfemrtd.c b/client/src/cmdhfemrtd.c index 389d10f53..f925c2809 100644 --- a/client/src/cmdhfemrtd.c +++ b/client/src/cmdhfemrtd.c @@ -1106,12 +1106,13 @@ static int emrtd_mrz_determine_length(char *mrz, int offset, int max_length) { static int emrtd_mrz_determine_separator(char *mrz, int offset, int max_length) { int i; - for (i = max_length; i >= 0; i--) { + for (i = max_length; i > 0; i--) { if (mrz[offset + i - 1] == '<' && mrz[offset + i] == '<') { break; } } - return i - 1; + // Return i - 1 unless we couldn't find anything (in that case return 0). + return i ? i - 1 : 0; } static void emrtd_print_optional_elements(char *mrz, int offset, int length, bool verify_check_digit) { @@ -1139,13 +1140,19 @@ static void emrtd_print_document_number(char *mrz, int offset) { static void emrtd_print_name(char *mrz, int offset, int max_length, bool localized) { char final_name[100] = { 0x00 }; - int i = emrtd_mrz_determine_length(mrz, offset, max_length); - int sep = emrtd_mrz_determine_separator(mrz, offset, i); - int namelen = (i - (sep + 2)); + int namelen = emrtd_mrz_determine_length(mrz, offset, max_length); + int sep = emrtd_mrz_determine_separator(mrz, offset, namelen); - memcpy(final_name, mrz + offset + sep + 2, namelen); - final_name[namelen] = ' '; - memcpy(final_name + namelen + 1, mrz + offset, sep); + // Account for mononyms + if (sep != 0) { + int firstnamelen = (namelen - (sep + 2)); + + memcpy(final_name, mrz + offset + sep + 2, firstnamelen); + final_name[firstnamelen] = ' '; + memcpy(final_name + firstnamelen + 1, mrz + offset, sep); + } else { + memcpy(final_name, mrz + offset, namelen); + } if (localized) { PrintAndLogEx(SUCCESS, "Legal Name (Localized): " _YELLOW_("%s"), final_name); From 9945107016ce0c05345c43ee4c6ad825f6b908eb Mon Sep 17 00:00:00 2001 From: Ave Date: Sat, 19 Dec 2020 07:08:39 +0300 Subject: [PATCH 141/682] hf emrtd info: Replace padding with spaces on names --- client/src/cmdhfemrtd.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/client/src/cmdhfemrtd.c b/client/src/cmdhfemrtd.c index f925c2809..32d42f523 100644 --- a/client/src/cmdhfemrtd.c +++ b/client/src/cmdhfemrtd.c @@ -1115,6 +1115,14 @@ static int emrtd_mrz_determine_separator(char *mrz, int offset, int max_length) return i ? i - 1 : 0; } +static void emrtd_mrz_replace_pad(char *data, int datalen, char newchar) { + for (int i = 0; i < datalen; i++) { + if (data[i] == '<') { + data[i] = newchar; + } + } +} + static void emrtd_print_optional_elements(char *mrz, int offset, int length, bool verify_check_digit) { int i = emrtd_mrz_determine_length(mrz, offset, length); @@ -1154,6 +1162,9 @@ static void emrtd_print_name(char *mrz, int offset, int max_length, bool localiz memcpy(final_name, mrz + offset, namelen); } + // Replace < characters with spaces + emrtd_mrz_replace_pad(final_name, namelen, ' '); + if (localized) { PrintAndLogEx(SUCCESS, "Legal Name (Localized): " _YELLOW_("%s"), final_name); } else { From d23ebec93c0e81819f649fab15b963157d63d946 Mon Sep 17 00:00:00 2001 From: Ave Date: Sat, 19 Dec 2020 07:25:28 +0300 Subject: [PATCH 142/682] emrtd: Make emrtd_mrz_determine_separator less hacky --- client/src/cmdhfemrtd.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/client/src/cmdhfemrtd.c b/client/src/cmdhfemrtd.c index 32d42f523..14abc8c90 100644 --- a/client/src/cmdhfemrtd.c +++ b/client/src/cmdhfemrtd.c @@ -1106,13 +1106,12 @@ static int emrtd_mrz_determine_length(char *mrz, int offset, int max_length) { static int emrtd_mrz_determine_separator(char *mrz, int offset, int max_length) { int i; - for (i = max_length; i > 0; i--) { - if (mrz[offset + i - 1] == '<' && mrz[offset + i] == '<') { + for (i = max_length - 1; i > 0; i--) { + if (mrz[offset + i] == '<' && mrz[offset + i + 1] == '<') { break; } } - // Return i - 1 unless we couldn't find anything (in that case return 0). - return i ? i - 1 : 0; + return i; } static void emrtd_mrz_replace_pad(char *data, int datalen, char newchar) { From 263eb5774900e1c5d12f078c011ef797cac69fee Mon Sep 17 00:00:00 2001 From: Ave Date: Sat, 19 Dec 2020 16:14:27 +0300 Subject: [PATCH 143/682] emrtd: fixes for some belgian passports --- client/src/cmdhfemrtd.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/client/src/cmdhfemrtd.c b/client/src/cmdhfemrtd.c index 14abc8c90..827faa4e0 100644 --- a/client/src/cmdhfemrtd.c +++ b/client/src/cmdhfemrtd.c @@ -1105,6 +1105,7 @@ static int emrtd_mrz_determine_length(char *mrz, int offset, int max_length) { } static int emrtd_mrz_determine_separator(char *mrz, int offset, int max_length) { + // Note: this function does not account for len=0 int i; for (i = max_length - 1; i > 0; i--) { if (mrz[offset + i] == '<' && mrz[offset + i + 1] == '<') { @@ -1146,6 +1147,9 @@ static void emrtd_print_document_number(char *mrz, int offset) { } static void emrtd_print_name(char *mrz, int offset, int max_length, bool localized) { + if (max_length == 0) { + return; + } char final_name[100] = { 0x00 }; int namelen = emrtd_mrz_determine_length(mrz, offset, max_length); int sep = emrtd_mrz_determine_separator(mrz, offset, namelen); From 3e4a03ec336783df1cca28cc46a6332979608fbd Mon Sep 17 00:00:00 2001 From: Ave Date: Sat, 19 Dec 2020 16:17:44 +0300 Subject: [PATCH 144/682] emrtd: Implement a better fix for parsing empty tags --- client/src/cmdhfemrtd.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/client/src/cmdhfemrtd.c b/client/src/cmdhfemrtd.c index 827faa4e0..0af2d406f 100644 --- a/client/src/cmdhfemrtd.c +++ b/client/src/cmdhfemrtd.c @@ -1147,9 +1147,6 @@ static void emrtd_print_document_number(char *mrz, int offset) { } static void emrtd_print_name(char *mrz, int offset, int max_length, bool localized) { - if (max_length == 0) { - return; - } char final_name[100] = { 0x00 }; int namelen = emrtd_mrz_determine_length(mrz, offset, max_length); int sep = emrtd_mrz_determine_separator(mrz, offset, namelen); @@ -1352,6 +1349,10 @@ static bool emrtd_print_ef_dg11_info(uint8_t *response, int resplen) { for (int i = 0; i < taglistlen; i++) { emrtd_lds_get_data_by_tag(response, resplen, tagdata, &tagdatalen, taglist[i], taglist[i + 1], taglist[i] == 0x5f); + // Don't bother with empty tags + if (tagdatalen == 0) { + continue; + } // Special behavior for two char tags if (taglist[i] == 0x5f) { switch (taglist[i + 1]) { @@ -1427,6 +1428,10 @@ static bool emrtd_print_ef_dg12_info(uint8_t *response, int resplen) { for (int i = 0; i < taglistlen; i++) { emrtd_lds_get_data_by_tag(response, resplen, tagdata, &tagdatalen, taglist[i], taglist[i + 1], taglist[i] == 0x5f); + // Don't bother with empty tags + if (tagdatalen == 0) { + continue; + } // Special behavior for two char tags if (taglist[i] == 0x5f) { // Several things here are longer than the rest but I can't think of a way to shorten them From 9bed791026ac1585fa119e92b758baf59f4de8c1 Mon Sep 17 00:00:00 2001 From: Ave Date: Sat, 19 Dec 2020 16:25:09 +0300 Subject: [PATCH 145/682] emrtd: Account for undocumented 5F85 tag --- client/src/cmdhfemrtd.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/client/src/cmdhfemrtd.c b/client/src/cmdhfemrtd.c index 0af2d406f..2fcc849b0 100644 --- a/client/src/cmdhfemrtd.c +++ b/client/src/cmdhfemrtd.c @@ -1249,6 +1249,14 @@ static void emrtd_print_personalization_timestamp(uint8_t *data) { PrintAndLogEx(SUCCESS, "Personalization at....: " _YELLOW_("%s"), final_date); } +static void emrtd_print_unknown_timestamp_5f85(uint8_t *data) { + char final_date[20] = { 0x00 }; + sprintf(final_date, "%.4s-%.2s-%.2s %.2s:%.2s:%.2s", data, data + 4, data + 6, data + 8, data + 10, data + 12); + + PrintAndLogEx(SUCCESS, "Unknown timestamp 5F85: " _YELLOW_("%s"), final_date); + PrintAndLogEx(HINT, "This is very likely the personalization timestamp, but it is using an undocumented tag."); +} + static bool emrtd_print_ef_dg1_info(uint8_t *response, int resplen) { int td_variant = 0; @@ -1461,6 +1469,9 @@ static bool emrtd_print_ef_dg12_info(uint8_t *response, int resplen) { case 0x56: PrintAndLogEx(SUCCESS, "Serial of Personalization System: " _YELLOW_("%.*s"), tagdatalen, tagdata); break; + case 0x85: + emrtd_print_unknown_timestamp_5f85(tagdata); + break; default: PrintAndLogEx(SUCCESS, "Unknown Field %02X%02X....: %s", taglist[i], taglist[i + 1], sprint_hex_inrow(tagdata, tagdatalen)); break; From e277eaaab2263b5641e9e6b693ca3a5cdb6b758e Mon Sep 17 00:00:00 2001 From: Philippe Teuwen Date: Sat, 19 Dec 2020 16:48:37 +0100 Subject: [PATCH 146/682] emrtd: add COM description, add big DG table --- client/src/cmdhfemrtd.c | 335 ++++++++++++++++++++-------------------- client/src/cmdhfemrtd.h | 11 ++ 2 files changed, 180 insertions(+), 166 deletions(-) diff --git a/client/src/cmdhfemrtd.c b/client/src/cmdhfemrtd.c index 2fcc849b0..241a4750b 100644 --- a/client/src/cmdhfemrtd.c +++ b/client/src/cmdhfemrtd.c @@ -44,25 +44,11 @@ #define EMRTD_P2_PROPRIETARY "0C" // File IDs +// TODO -> dg_table #define EMRTD_EF_CARDACCESS "011C" +#define EMRTD_EF_SOD "011D" #define EMRTD_EF_COM "011E" #define EMRTD_EF_DG1 "0101" -#define EMRTD_EF_DG2 "0102" -#define EMRTD_EF_DG3 "0103" -#define EMRTD_EF_DG4 "0104" -#define EMRTD_EF_DG5 "0105" -#define EMRTD_EF_DG6 "0106" -#define EMRTD_EF_DG7 "0107" -#define EMRTD_EF_DG8 "0108" -#define EMRTD_EF_DG9 "0109" -#define EMRTD_EF_DG10 "010A" -#define EMRTD_EF_DG11 "010B" -#define EMRTD_EF_DG12 "010C" -#define EMRTD_EF_DG13 "010D" -#define EMRTD_EF_DG14 "010E" -#define EMRTD_EF_DG15 "010F" -#define EMRTD_EF_DG16 "0110" -#define EMRTD_EF_SOD "011D" // App IDs #define EMRTD_AID_MRTD "A0000002471001" @@ -71,6 +57,40 @@ const uint8_t KENC_type[4] = {0x00, 0x00, 0x00, 0x01}; const uint8_t KMAC_type[4] = {0x00, 0x00, 0x00, 0x02}; +static int emrtd_dump_ef_dg2(uint8_t *file_contents, size_t file_length); +static int emrtd_dump_ef_dg5(uint8_t *file_contents, size_t file_length); +static int emrtd_dump_ef_dg7(uint8_t *file_contents, size_t file_length); +static int emrtd_dump_ef_sod(uint8_t *file_contents, size_t file_length); +static int emrtd_print_ef_com_info(uint8_t *data, size_t datalen); +static int emrtd_print_ef_dg1_info(uint8_t *data, size_t datalen); +static int emrtd_print_ef_dg11_info(uint8_t *data, size_t datalen); +static int emrtd_print_ef_dg12_info(uint8_t *data, size_t datalen); +static int emrtd_print_ef_sod_info(uint8_t *data, size_t datalen); +static emrtd_dg_t dg_table[] = { + {0x60, "011E", "EF_COM", "Header and Data Group Presence Information", true, emrtd_print_ef_com_info, NULL, true}, + {0xff, "011C", "EF_CardAccess", "PACE SecurityInfos", false, NULL, NULL, true}, + {0xff, "011D", "EF_CardSecurity", "PACE SecurityInfos for Chip Authentication Mapping", false, NULL, NULL, true}, + {0x61, "0101", "EF_DG1", "Details recorded in MRZ", true, emrtd_print_ef_dg1_info, NULL, true}, + {0x75, "0102", "EF_DG2", "Encoded Face", true, NULL, emrtd_dump_ef_dg2, false}, + // These cases are commented out as they require PACE + //{0x63, "0103", "EF_DG3", "Encoded Finger(s)", false, NULL, false}, + //{0x76, "0104", "EF_DG4", "Encoded Eye(s)", false, NULL, false}, + {0x65, "0105", "EF_DG5", "Displayed Portrait", false, NULL, emrtd_dump_ef_dg5, false}, + {0x66, "0106", "EF_DG6", "Reserved for Future Use", false, NULL, NULL, false}, + {0x67, "0107", "EF_DG7", "Displayed Signature or Usual Mark", false, NULL, emrtd_dump_ef_dg7, false}, + {0x68, "0108", "EF_DG8", "Data Feature(s)", false, NULL, NULL, true}, + {0x69, "0109", "EF_DG9", "Structure Feature(s)", false, NULL, NULL, true}, + {0x6a, "010A", "EF_DG10", "Substance Feature(s)", false, NULL, NULL, true}, + {0x6b, "010B", "EF_DG11", "Additional Personal Detail(s)", false, emrtd_print_ef_dg11_info, NULL, true}, + {0x6c, "010C", "EF_DG12", "Additional Document Detail(s)", false, emrtd_print_ef_dg12_info, NULL, true}, + {0x6d, "010D", "EF_DG13", "Optional Detail(s)", false, NULL, NULL, true}, + {0x6e, "010E", "EF_DG14", "Security Options", false, NULL, NULL, true}, + {0x6f, "010F", "EF_DG15", "Active Authentication Public Key Info", false, NULL, NULL, true}, + {0x70, "0110", "EF_DG16", "Person(s) to Notify", false, NULL, NULL, true}, + {0x77, "011D", "EF_SOD", "Document Security Object", false, emrtd_print_ef_sod_info, emrtd_dump_ef_sod, true}, + {0x00, NULL, NULL, NULL, false, NULL, NULL, false} +}; + static int CmdHelp(const char *Cmd); static uint16_t get_sw(uint8_t *d, uint8_t n) { @@ -608,86 +628,14 @@ static bool emrtd_lds_get_data_by_tag(uint8_t *datain, int datainlen, uint8_t *d } static bool emrtd_file_tag_to_file_id(uint8_t *datain, char *filenameout, char *dataout) { - // imagine bothering with a hashmap or writing good code - // couldn't be me - switch (*datain) { - case 0x60: - memcpy(dataout, EMRTD_EF_COM, 4); - memcpy(filenameout, "EF_COM", 6); - break; - case 0x61: - memcpy(dataout, EMRTD_EF_DG1, 4); - memcpy(filenameout, "EF_DG1", 6); - break; - case 0x75: - memcpy(dataout, EMRTD_EF_DG2, 4); - memcpy(filenameout, "EF_DG2", 6); - break; - // These cases are commented out as they require PACE - // case 0x63: - // memcpy(dataout, EMRTD_EF_DG3, 4); - // memcpy(filenameout, "EF_DG3", 6); - // break; - // case 0x76: - // memcpy(dataout, EMRTD_EF_DG4, 4); - // memcpy(filenameout, "EF_DG4", 6); - // break; - case 0x65: - memcpy(dataout, EMRTD_EF_DG5, 4); - memcpy(filenameout, "EF_DG5", 6); - break; - case 0x66: - memcpy(dataout, EMRTD_EF_DG6, 4); - memcpy(filenameout, "EF_DG6", 6); - break; - case 0x67: - memcpy(dataout, EMRTD_EF_DG7, 4); - memcpy(filenameout, "EF_DG7", 6); - break; - case 0x68: - memcpy(dataout, EMRTD_EF_DG8, 4); - memcpy(filenameout, "EF_DG8", 6); - break; - case 0x69: - memcpy(dataout, EMRTD_EF_DG9, 4); - memcpy(filenameout, "EF_DG9", 6); - break; - case 0x6a: - memcpy(dataout, EMRTD_EF_DG10, 4); - memcpy(filenameout, "EF_DG10", 7); - break; - case 0x6b: - memcpy(dataout, EMRTD_EF_DG11, 4); - memcpy(filenameout, "EF_DG11", 7); - break; - case 0x6c: - memcpy(dataout, EMRTD_EF_DG12, 4); - memcpy(filenameout, "EF_DG12", 7); - break; - case 0x6d: - memcpy(dataout, EMRTD_EF_DG13, 4); - memcpy(filenameout, "EF_DG13", 7); - break; - case 0x6e: - memcpy(dataout, EMRTD_EF_DG14, 4); - memcpy(filenameout, "EF_DG14", 7); - break; - case 0x6f: - memcpy(dataout, EMRTD_EF_DG15, 4); - memcpy(filenameout, "EF_DG15", 7); - break; - case 0x70: - memcpy(dataout, EMRTD_EF_DG16, 4); - memcpy(filenameout, "EF_DG16", 7); - break; - case 0x77: - memcpy(dataout, EMRTD_EF_SOD, 4); - memcpy(filenameout, "EF_SOD", 6); - break; - default: - return false; + for (int dgi=0; dg_table[dgi].filename != NULL; dgi++) { + if (dg_table[dgi].tag == *datain) { + strcpy(dataout, dg_table[dgi].fileid); + strcpy(filenameout, dg_table[dgi].filename); + return true; + } } - return true; + return false; } static bool emrtd_select_and_read(uint8_t *dataout, int *dataoutlen, const char *file, uint8_t *ks_enc, uint8_t *ks_mac, uint8_t *ssc, bool use_secure, bool use_14b) { @@ -710,7 +658,7 @@ static bool emrtd_select_and_read(uint8_t *dataout, int *dataoutlen, const char return true; } -static bool emrtd_dump_ef_dg2(uint8_t *file_contents, int file_length) { +static int emrtd_dump_ef_dg2(uint8_t *file_contents, size_t file_length) { int offset, datalen = 0; // This is a hacky impl that just looks for the image header. I'll improve it eventually. @@ -728,60 +676,60 @@ static bool emrtd_dump_ef_dg2(uint8_t *file_contents, int file_length) { // If we didn't get any data, return false. if (datalen == 0) { - return false; + return PM3_ESOFT; } saveFile("EF_DG2", file_contents[offset] == 0xFF ? ".jpg" : ".jp2", file_contents + offset, datalen); - return true; + return PM3_SUCCESS; } -static bool emrtd_dump_ef_dg5(uint8_t *file_contents, int file_length) { +static int emrtd_dump_ef_dg5(uint8_t *file_contents, size_t file_length) { uint8_t data[EMRTD_MAX_FILE_SIZE]; int datalen = 0; // If we can't find image in EF_DG5, return false. if (emrtd_lds_get_data_by_tag(file_contents, file_length, data, &datalen, 0x5F, 0x40, true) == false) { - return false; + return PM3_ESOFT; } if (datalen < EMRTD_MAX_FILE_SIZE) { saveFile("EF_DG5", data[0] == 0xFF ? ".jpg" : ".jp2", data, datalen); } else { PrintAndLogEx(ERR, "error (emrtd_dump_ef_dg5) datalen out-of-bounds"); - return false; + return PM3_ESOFT; } - return true; + return PM3_SUCCESS; } -static bool emrtd_dump_ef_dg7(uint8_t *file_contents, int file_length) { +static int emrtd_dump_ef_dg7(uint8_t *file_contents, size_t file_length) { uint8_t data[EMRTD_MAX_FILE_SIZE]; int datalen = 0; // If we can't find image in EF_DG7, return false. if (emrtd_lds_get_data_by_tag(file_contents, file_length, data, &datalen, 0x5F, 0x42, true) == false) { - return false; + return PM3_ESOFT; } if (datalen < EMRTD_MAX_FILE_SIZE) { saveFile("EF_DG7", data[0] == 0xFF ? ".jpg" : ".jp2", data, datalen); } else { PrintAndLogEx(ERR, "error (emrtd_dump_ef_dg7) datalen out-of-bounds"); - return false; + return PM3_ESOFT; } - return true; + return PM3_SUCCESS; } -static bool emrtd_dump_ef_sod(uint8_t *file_contents, int file_length) { +static int emrtd_dump_ef_sod(uint8_t *file_contents, size_t file_length) { int fieldlen = emrtd_get_asn1_field_length(file_contents, file_length, 1); int datalen = emrtd_get_asn1_data_length(file_contents, file_length, 1); if (fieldlen + 1 > EMRTD_MAX_FILE_SIZE) { PrintAndLogEx(ERR, "error (emrtd_dump_ef_sod) fieldlen out-of-bounds"); - return false; + return PM3_SUCCESS; } saveFile("EF_SOD", ".p7b", file_contents + fieldlen + 1, datalen); - return true; + return PM3_ESOFT; } static bool emrtd_dump_file(uint8_t *ks_enc, uint8_t *ks_mac, uint8_t *ssc, const char *file, const char *name, bool use_secure, bool use_14b) { @@ -796,16 +744,13 @@ static bool emrtd_dump_file(uint8_t *ks_enc, uint8_t *ks_mac, uint8_t *ssc, cons PrintAndLogEx(DEBUG, "Contents (may be incomplete over 2k chars): %s", sprint_hex_inrow(response, resplen)); saveFile(name, ".BIN", response, resplen); - if (strcmp(file, EMRTD_EF_DG2) == 0) { - emrtd_dump_ef_dg2(response, resplen); - } else if (strcmp(file, EMRTD_EF_DG5) == 0) { - emrtd_dump_ef_dg5(response, resplen); - } else if (strcmp(file, EMRTD_EF_DG7) == 0) { - emrtd_dump_ef_dg7(response, resplen); - } else if (strcmp(file, EMRTD_EF_SOD) == 0) { - emrtd_dump_ef_sod(response, resplen); + for (int dgi=0; dg_table[dgi].filename != NULL; dgi++) { + if (strcmp(dg_table[dgi].fileid, file) == 0) { + if (dg_table[dgi].dumper != NULL) + dg_table[dgi].dumper(response, resplen); + break; + } } - return true; } @@ -1257,7 +1202,36 @@ static void emrtd_print_unknown_timestamp_5f85(uint8_t *data) { PrintAndLogEx(HINT, "This is very likely the personalization timestamp, but it is using an undocumented tag."); } -static bool emrtd_print_ef_dg1_info(uint8_t *response, int resplen) { +static int emrtd_print_ef_com_info(uint8_t *data, size_t datalen) { + uint8_t filelist[50]; + int filelistlen = 0; + int res = emrtd_lds_get_data_by_tag(data, datalen, filelist, &filelistlen, 0x5c, 0x00, false); + if (!res) { + PrintAndLogEx(ERR, "Failed to read file list from EF_COM."); + return PM3_ESOFT; + } + + // List files in the file list + PrintAndLogEx(NORMAL, ""); + PrintAndLogEx(INFO, "-------------------- " _CYAN_("EF_COM") " --------------------"); + for (int i = 0; i < filelistlen; i++) { + char file_id[5] = { 0x00 }; + char file_name[8] = { 0x00 }; + if (emrtd_file_tag_to_file_id(&filelist[i], file_name, file_id) == false) { + PrintAndLogEx(DEBUG, "File tag not found, skipping: %02X", filelist[i]); + continue; + } + for (int dgi=0; dg_table[dgi].filename != NULL; dgi++) { + if (strcmp(dg_table[dgi].filename, file_name) == 0) { + PrintAndLogEx(SUCCESS, "%-7s...............: " _YELLOW_("%s"), file_name, dg_table[dgi].desc); + break; + } + } + } + return PM3_SUCCESS; +} + +static int emrtd_print_ef_dg1_info(uint8_t *data, size_t datalen) { int td_variant = 0; PrintAndLogEx(NORMAL, ""); @@ -1268,9 +1242,9 @@ static bool emrtd_print_ef_dg1_info(uint8_t *response, int resplen) { char mrz[90] = { 0x00 }; int mrzlen = 0; - if (!emrtd_lds_get_data_by_tag(response, resplen, (uint8_t *) mrz, &mrzlen, 0x5f, 0x1f, true)) { + if (!emrtd_lds_get_data_by_tag(data, datalen, (uint8_t *) mrz, &mrzlen, 0x5f, 0x1f, true)) { PrintAndLogEx(ERR, "Failed to read MRZ from EF_DG1."); - return false; + return PM3_ESOFT; } // Determine and print the document type @@ -1338,10 +1312,10 @@ static bool emrtd_print_ef_dg1_info(uint8_t *response, int resplen) { } } - return true; + return PM3_SUCCESS; } -static bool emrtd_print_ef_dg11_info(uint8_t *response, int resplen) { +static int emrtd_print_ef_dg11_info(uint8_t *data, size_t datalen) { uint8_t taglist[100] = { 0x00 }; int taglistlen = 0; uint8_t tagdata[1000] = { 0x00 }; @@ -1350,13 +1324,13 @@ static bool emrtd_print_ef_dg11_info(uint8_t *response, int resplen) { PrintAndLogEx(NORMAL, ""); PrintAndLogEx(INFO, "-------------------- " _CYAN_("EF_DG11") " -------------------"); - if (!emrtd_lds_get_data_by_tag(response, resplen, taglist, &taglistlen, 0x5c, 0x00, false)) { + if (!emrtd_lds_get_data_by_tag(data, datalen, taglist, &taglistlen, 0x5c, 0x00, false)) { PrintAndLogEx(ERR, "Failed to read file list from EF_DG11."); - return false; + return PM3_ESOFT; } for (int i = 0; i < taglistlen; i++) { - emrtd_lds_get_data_by_tag(response, resplen, tagdata, &tagdatalen, taglist[i], taglist[i + 1], taglist[i] == 0x5f); + emrtd_lds_get_data_by_tag(data, datalen, tagdata, &tagdatalen, taglist[i], taglist[i + 1], taglist[i] == 0x5f); // Don't bother with empty tags if (tagdatalen == 0) { continue; @@ -1417,10 +1391,10 @@ static bool emrtd_print_ef_dg11_info(uint8_t *response, int resplen) { PrintAndLogEx(SUCCESS, "Unknown Field %02X......: %s", taglist[i], sprint_hex_inrow(tagdata, tagdatalen)); } } - return true; + return PM3_SUCCESS; } -static bool emrtd_print_ef_dg12_info(uint8_t *response, int resplen) { +static int emrtd_print_ef_dg12_info(uint8_t *data, size_t datalen) { uint8_t taglist[100] = { 0x00 }; int taglistlen = 0; uint8_t tagdata[1000] = { 0x00 }; @@ -1429,13 +1403,13 @@ static bool emrtd_print_ef_dg12_info(uint8_t *response, int resplen) { PrintAndLogEx(NORMAL, ""); PrintAndLogEx(INFO, "-------------------- " _CYAN_("EF_DG12") " -------------------"); - if (!emrtd_lds_get_data_by_tag(response, resplen, taglist, &taglistlen, 0x5c, 0x00, false)) { + if (!emrtd_lds_get_data_by_tag(data, datalen, taglist, &taglistlen, 0x5c, 0x00, false)) { PrintAndLogEx(ERR, "Failed to read file list from EF_DG12."); - return false; + return PM3_ESOFT; } for (int i = 0; i < taglistlen; i++) { - emrtd_lds_get_data_by_tag(response, resplen, tagdata, &tagdatalen, taglist[i], taglist[i + 1], taglist[i] == 0x5f); + emrtd_lds_get_data_by_tag(data, datalen, tagdata, &tagdatalen, taglist[i], taglist[i + 1], taglist[i] == 0x5f); // Don't bother with empty tags if (tagdatalen == 0) { continue; @@ -1483,7 +1457,14 @@ static bool emrtd_print_ef_dg12_info(uint8_t *response, int resplen) { PrintAndLogEx(SUCCESS, "Unknown Field %02X......: %s", taglist[i], sprint_hex_inrow(tagdata, tagdatalen)); } } - return true; + return PM3_SUCCESS; +} + +static int emrtd_print_ef_sod_info(uint8_t *data, size_t datalen) { + PrintAndLogEx(NORMAL, ""); + PrintAndLogEx(INFO, "-------------------- " _CYAN_("EF_SOD") " --------------------"); + PrintAndLogEx(WARNING, "TODO"); + return PM3_SUCCESS; } int infoHF_EMRTD(char *documentnumber, char *dob, char *expiry, bool BAC_available) { @@ -1521,6 +1502,12 @@ int infoHF_EMRTD(char *documentnumber, char *dob, char *expiry, bool BAC_availab return PM3_ESOFT; } + int res = emrtd_print_ef_com_info(response, resplen); + if ( res != PM3_SUCCESS) { + DropField(); + return res; + } + uint8_t filelist[50]; int filelistlen = 0; @@ -1539,14 +1526,20 @@ int infoHF_EMRTD(char *documentnumber, char *dob, char *expiry, bool BAC_availab continue; } - if (strcmp(file_name, "EF_DG1") == 0 && emrtd_select_and_read(response, &resplen, EMRTD_EF_DG1, ks_enc, ks_mac, ssc, BAC, use_14b)) { - emrtd_print_ef_dg1_info(response, resplen); - } else if (strcmp(file_name, "EF_DG11") == 0 && emrtd_select_and_read(response, &resplen, EMRTD_EF_DG11, ks_enc, ks_mac, ssc, BAC, use_14b)) { - emrtd_print_ef_dg11_info(response, resplen); - } else if (strcmp(file_name, "EF_DG12") == 0 && emrtd_select_and_read(response, &resplen, EMRTD_EF_DG12, ks_enc, ks_mac, ssc, BAC, use_14b)) { - emrtd_print_ef_dg12_info(response, resplen); + for (int dgi=0; dg_table[dgi].filename != NULL; dgi++) { + if ((strcmp(dg_table[dgi].filename, file_name) == 0) && dg_table[dgi].fastdump) { + if (emrtd_select_and_read(response, &resplen, dg_table[dgi].fileid, ks_enc, ks_mac, ssc, BAC, use_14b)) { + if (dg_table[dgi].parser != NULL) + dg_table[dgi].parser(response, resplen); + } + break; + } } } +// TODO + if (emrtd_select_and_read(response, &resplen, EMRTD_EF_SOD, ks_enc, ks_mac, ssc, BAC, use_14b)) { + emrtd_print_ef_sod_info(response, resplen); + } DropField(); return PM3_SUCCESS; @@ -1562,55 +1555,65 @@ int infoHF_EMRTD_offline(const char *path) { strncat(filepath, PATHSEP, 1); strcat(filepath, "EF_COM"); - if (loadFile_safeEx(filepath, ".BIN", (void **)&data, (size_t *)&datalen, true) != PM3_SUCCESS) { + if (loadFile_safeEx(filepath, ".BIN", (void **)&data, (size_t *)&datalen, false) != PM3_SUCCESS) { PrintAndLogEx(ERR, "Failed to read EF_COM."); free(filepath); return PM3_ESOFT; } + + int res = emrtd_print_ef_com_info(data, datalen); + if ( res != PM3_SUCCESS) { + free(data); + free(filepath); + return res; + } + uint8_t filelist[50]; int filelistlen = 0; - int res = emrtd_lds_get_data_by_tag(data, datalen, filelist, &filelistlen, 0x5c, 0x00, false); - free(data); + res = emrtd_lds_get_data_by_tag(data, datalen, filelist, &filelistlen, 0x5c, 0x00, false); if (!res) { PrintAndLogEx(ERR, "Failed to read file list from EF_COM."); + free(data); free(filepath); return PM3_ESOFT; } - + free(data); // Read files in the file list for (int i = 0; i < filelistlen; i++) { char file_id[5] = { 0x00 }; char file_name[8] = { 0x00 }; if (emrtd_file_tag_to_file_id(&filelist[i], file_name, file_id) == false) { - PrintAndLogEx(DEBUG, "File tag not found, skipping: %02X", filelist[i]); + //PrintAndLogEx(DEBUG, "File tag not found, skipping: %02X", filelist[i]); continue; } - if (strcmp(file_name, "EF_DG1") == 0) { - strcpy(filepath, path); - strncat(filepath, PATHSEP, 1); - strcat(filepath, "EF_DG1"); - if (loadFile_safeEx(filepath, ".BIN", (void **)&data, (size_t *)&datalen, true) == PM3_SUCCESS) { - emrtd_print_ef_dg1_info(data, datalen); - free(data); - } - } else if (strcmp(file_name, "EF_DG11") == 0) { - strcpy(filepath, path); - strncat(filepath, PATHSEP, 1); - strcat(filepath, "EF_DG11"); - if (loadFile_safeEx(filepath, ".BIN", (void **)&data, (size_t *)&datalen, true) == PM3_SUCCESS) { - emrtd_print_ef_dg11_info(data, datalen); - free(data); - } - } else if (strcmp(file_name, "EF_DG12") == 0) { - strcpy(filepath, path); - strncat(filepath, PATHSEP, 1); - strcat(filepath, "EF_DG12"); - if (loadFile_safeEx(filepath, ".BIN", (void **)&data, (size_t *)&datalen, true) == PM3_SUCCESS) { - emrtd_print_ef_dg12_info(data, datalen); - free(data); + + for (int dgi=0; dg_table[dgi].filename != NULL; dgi++) { + if (strcmp(dg_table[dgi].filename, file_name) == 0) { + strcpy(filepath, path); + strncat(filepath, PATHSEP, 1); + strcat(filepath, dg_table[dgi].filename); + if (loadFile_safeEx(filepath, ".BIN", (void **)&data, (size_t *)&datalen, false) == PM3_SUCCESS) + { + // we won't halt on parsing errors + if (dg_table[dgi].parser != NULL) + dg_table[dgi].parser(data, datalen); + free(data); + } + break; } } } +// TODO + strcpy(filepath, path); + strncat(filepath, PATHSEP, 1); + strcat(filepath, "EF_SOD"); + if (loadFile_safeEx(filepath, ".BIN", (void **)&data, (size_t *)&datalen, false) == PM3_SUCCESS) + { + // we won't halt on parsing errors + emrtd_print_ef_sod_info(data, datalen); + free(data); + } + free(filepath); return PM3_SUCCESS; } diff --git a/client/src/cmdhfemrtd.h b/client/src/cmdhfemrtd.h index 3cfcd3cbd..aa1c4e1e1 100644 --- a/client/src/cmdhfemrtd.h +++ b/client/src/cmdhfemrtd.h @@ -13,6 +13,17 @@ #include "common.h" +typedef struct emrtd_dg_s { + uint8_t tag; + const char *fileid; + const char *filename; + const char *desc; + bool required; + int (*parser)(uint8_t *data, size_t datalen); + int (*dumper)(uint8_t *data, size_t datalen); + bool fastdump; +} emrtd_dg_t; + int CmdHFeMRTD(const char *Cmd); int dumpHF_EMRTD(char *documentnumber, char *dob, char *expiry, bool BAC_available); From 019f4a7e94698db45860601b75d54be40b7bf07a Mon Sep 17 00:00:00 2001 From: Philippe Teuwen Date: Sat, 19 Dec 2020 17:12:08 +0100 Subject: [PATCH 147/682] emrtd table: pace flag --- client/src/cmdhfemrtd.c | 57 ++++++++++++++++++++++------------------- client/src/cmdhfemrtd.h | 5 ++-- 2 files changed, 34 insertions(+), 28 deletions(-) diff --git a/client/src/cmdhfemrtd.c b/client/src/cmdhfemrtd.c index 241a4750b..33a6e0f8f 100644 --- a/client/src/cmdhfemrtd.c +++ b/client/src/cmdhfemrtd.c @@ -67,28 +67,28 @@ static int emrtd_print_ef_dg11_info(uint8_t *data, size_t datalen); static int emrtd_print_ef_dg12_info(uint8_t *data, size_t datalen); static int emrtd_print_ef_sod_info(uint8_t *data, size_t datalen); static emrtd_dg_t dg_table[] = { - {0x60, "011E", "EF_COM", "Header and Data Group Presence Information", true, emrtd_print_ef_com_info, NULL, true}, - {0xff, "011C", "EF_CardAccess", "PACE SecurityInfos", false, NULL, NULL, true}, - {0xff, "011D", "EF_CardSecurity", "PACE SecurityInfos for Chip Authentication Mapping", false, NULL, NULL, true}, - {0x61, "0101", "EF_DG1", "Details recorded in MRZ", true, emrtd_print_ef_dg1_info, NULL, true}, - {0x75, "0102", "EF_DG2", "Encoded Face", true, NULL, emrtd_dump_ef_dg2, false}, - // These cases are commented out as they require PACE - //{0x63, "0103", "EF_DG3", "Encoded Finger(s)", false, NULL, false}, - //{0x76, "0104", "EF_DG4", "Encoded Eye(s)", false, NULL, false}, - {0x65, "0105", "EF_DG5", "Displayed Portrait", false, NULL, emrtd_dump_ef_dg5, false}, - {0x66, "0106", "EF_DG6", "Reserved for Future Use", false, NULL, NULL, false}, - {0x67, "0107", "EF_DG7", "Displayed Signature or Usual Mark", false, NULL, emrtd_dump_ef_dg7, false}, - {0x68, "0108", "EF_DG8", "Data Feature(s)", false, NULL, NULL, true}, - {0x69, "0109", "EF_DG9", "Structure Feature(s)", false, NULL, NULL, true}, - {0x6a, "010A", "EF_DG10", "Substance Feature(s)", false, NULL, NULL, true}, - {0x6b, "010B", "EF_DG11", "Additional Personal Detail(s)", false, emrtd_print_ef_dg11_info, NULL, true}, - {0x6c, "010C", "EF_DG12", "Additional Document Detail(s)", false, emrtd_print_ef_dg12_info, NULL, true}, - {0x6d, "010D", "EF_DG13", "Optional Detail(s)", false, NULL, NULL, true}, - {0x6e, "010E", "EF_DG14", "Security Options", false, NULL, NULL, true}, - {0x6f, "010F", "EF_DG15", "Active Authentication Public Key Info", false, NULL, NULL, true}, - {0x70, "0110", "EF_DG16", "Person(s) to Notify", false, NULL, NULL, true}, - {0x77, "011D", "EF_SOD", "Document Security Object", false, emrtd_print_ef_sod_info, emrtd_dump_ef_sod, true}, - {0x00, NULL, NULL, NULL, false, NULL, NULL, false} +// tag fileid filename desc pace req fast parser dumper + {0x60, "011E", "EF_COM", "Header and Data Group Presence Information", false, true, true, emrtd_print_ef_com_info, NULL}, + {0xff, "011C", "EF_CardAccess", "PACE SecurityInfos", true, true, true, NULL, NULL}, + {0xff, "011D", "EF_CardSecurity", "PACE SecurityInfos for Chip Authentication Mapping", true, false, true, NULL, NULL}, + {0x61, "0101", "EF_DG1", "Details recorded in MRZ", false, true, true, emrtd_print_ef_dg1_info, NULL}, + {0x75, "0102", "EF_DG2", "Encoded Face", false, true, false, NULL, emrtd_dump_ef_dg2}, + {0x63, "0103", "EF_DG3", "Encoded Finger(s)", true, false, false, NULL, NULL}, + {0x76, "0104", "EF_DG4", "Encoded Eye(s)", true, false, false, NULL, NULL}, + {0x65, "0105", "EF_DG5", "Displayed Portrait", false, false, false, NULL, emrtd_dump_ef_dg5}, + {0x66, "0106", "EF_DG6", "Reserved for Future Use", false, false, false, NULL, NULL}, + {0x67, "0107", "EF_DG7", "Displayed Signature or Usual Mark", false, false, false, NULL, emrtd_dump_ef_dg7}, + {0x68, "0108", "EF_DG8", "Data Feature(s)", false, false, true, NULL, NULL}, + {0x69, "0109", "EF_DG9", "Structure Feature(s)", false, false, true, NULL, NULL}, + {0x6a, "010A", "EF_DG10", "Substance Feature(s)", false, false, true, NULL, NULL}, + {0x6b, "010B", "EF_DG11", "Additional Personal Detail(s)", false, false, true, emrtd_print_ef_dg11_info, NULL}, + {0x6c, "010C", "EF_DG12", "Additional Document Detail(s)", false, false, true, emrtd_print_ef_dg12_info, NULL}, + {0x6d, "010D", "EF_DG13", "Optional Detail(s)", false, false, true, NULL, NULL}, + {0x6e, "010E", "EF_DG14", "Security Options", false, false, true, NULL, NULL}, + {0x6f, "010F", "EF_DG15", "Active Authentication Public Key Info", false, false, true, NULL, NULL}, + {0x70, "0110", "EF_DG16", "Person(s) to Notify", false, false, true, NULL, NULL}, + {0x77, "011D", "EF_SOD", "Document Security Object", false, false, true, emrtd_print_ef_sod_info, emrtd_dump_ef_sod}, + {0x00, NULL, NULL, NULL, false, false, false, NULL, NULL} }; static int CmdHelp(const char *Cmd); @@ -994,7 +994,13 @@ int dumpHF_EMRTD(char *documentnumber, char *dob, char *expiry, bool BAC_availab continue; } PrintAndLogEx(DEBUG, "Current file: %s", file_name); - emrtd_dump_file(ks_enc, ks_mac, ssc, file_id, file_name, BAC, use_14b); + + for (int dgi=0; dg_table[dgi].filename != NULL; dgi++) { + if ((strcmp(dg_table[dgi].filename, file_name) == 0) && !dg_table[dgi].pace) { + emrtd_dump_file(ks_enc, ks_mac, ssc, file_id, file_name, BAC, use_14b); + break; + } + } } // Dump EF_SOD @@ -1525,9 +1531,8 @@ int infoHF_EMRTD(char *documentnumber, char *dob, char *expiry, bool BAC_availab PrintAndLogEx(DEBUG, "File tag not found, skipping: %02X", filelist[i]); continue; } - for (int dgi=0; dg_table[dgi].filename != NULL; dgi++) { - if ((strcmp(dg_table[dgi].filename, file_name) == 0) && dg_table[dgi].fastdump) { + if ((strcmp(dg_table[dgi].filename, file_name) == 0) && dg_table[dgi].fastdump && !dg_table[dgi].pace) { if (emrtd_select_and_read(response, &resplen, dg_table[dgi].fileid, ks_enc, ks_mac, ssc, BAC, use_14b)) { if (dg_table[dgi].parser != NULL) dg_table[dgi].parser(response, resplen); @@ -1588,7 +1593,7 @@ int infoHF_EMRTD_offline(const char *path) { } for (int dgi=0; dg_table[dgi].filename != NULL; dgi++) { - if (strcmp(dg_table[dgi].filename, file_name) == 0) { + if ((strcmp(dg_table[dgi].filename, file_name) == 0) && (!dg_table[dgi].pace)) { strcpy(filepath, path); strncat(filepath, PATHSEP, 1); strcat(filepath, dg_table[dgi].filename); diff --git a/client/src/cmdhfemrtd.h b/client/src/cmdhfemrtd.h index aa1c4e1e1..9df7846ad 100644 --- a/client/src/cmdhfemrtd.h +++ b/client/src/cmdhfemrtd.h @@ -18,10 +18,11 @@ typedef struct emrtd_dg_s { const char *fileid; const char *filename; const char *desc; - bool required; + bool pace; + bool required; // some are required only if PACE + bool fastdump; // fast to dump int (*parser)(uint8_t *data, size_t datalen); int (*dumper)(uint8_t *data, size_t datalen); - bool fastdump; } emrtd_dg_t; int CmdHFeMRTD(const char *Cmd); From 34cc523546207f08cae7c744083c6fddeb787d1d Mon Sep 17 00:00:00 2001 From: Philippe Teuwen Date: Sat, 19 Dec 2020 17:37:28 +0100 Subject: [PATCH 148/682] emrtd: add helper fcts to search the table --- client/src/cmdhfemrtd.c | 116 +++++++++++++++++----------------------- 1 file changed, 49 insertions(+), 67 deletions(-) diff --git a/client/src/cmdhfemrtd.c b/client/src/cmdhfemrtd.c index 33a6e0f8f..4475cfa3a 100644 --- a/client/src/cmdhfemrtd.c +++ b/client/src/cmdhfemrtd.c @@ -91,6 +91,23 @@ static emrtd_dg_t dg_table[] = { {0x00, NULL, NULL, NULL, false, false, false, NULL, NULL} }; +static emrtd_dg_t *emrtd_tag_to_dg(uint8_t tag) { + for (int dgi=0; dg_table[dgi].filename != NULL; dgi++) { + if (dg_table[dgi].tag == tag) { + return &dg_table[dgi]; + } + } + return NULL; +} +static emrtd_dg_t *emrtd_fileid_to_dg(const char *file_id) { + for (int dgi=0; dg_table[dgi].filename != NULL; dgi++) { + if (strcmp(dg_table[dgi].fileid, file_id) == 0) { + return &dg_table[dgi]; + } + } + return NULL; +} + static int CmdHelp(const char *Cmd); static uint16_t get_sw(uint8_t *d, uint8_t n) { @@ -627,17 +644,6 @@ static bool emrtd_lds_get_data_by_tag(uint8_t *datain, int datainlen, uint8_t *d return false; } -static bool emrtd_file_tag_to_file_id(uint8_t *datain, char *filenameout, char *dataout) { - for (int dgi=0; dg_table[dgi].filename != NULL; dgi++) { - if (dg_table[dgi].tag == *datain) { - strcpy(dataout, dg_table[dgi].fileid); - strcpy(filenameout, dg_table[dgi].filename); - return true; - } - } - return false; -} - static bool emrtd_select_and_read(uint8_t *dataout, int *dataoutlen, const char *file, uint8_t *ks_enc, uint8_t *ks_mac, uint8_t *ssc, bool use_secure, bool use_14b) { if (use_secure) { if (emrtd_secure_select_file(ks_enc, ks_mac, ssc, EMRTD_P1_SELECT_BY_EF, file, use_14b) == false) { @@ -743,13 +749,9 @@ static bool emrtd_dump_file(uint8_t *ks_enc, uint8_t *ks_mac, uint8_t *ssc, cons PrintAndLogEx(INFO, "Read %s, len: %i.", name, resplen); PrintAndLogEx(DEBUG, "Contents (may be incomplete over 2k chars): %s", sprint_hex_inrow(response, resplen)); saveFile(name, ".BIN", response, resplen); - - for (int dgi=0; dg_table[dgi].filename != NULL; dgi++) { - if (strcmp(dg_table[dgi].fileid, file) == 0) { - if (dg_table[dgi].dumper != NULL) - dg_table[dgi].dumper(response, resplen); - break; - } + emrtd_dg_t * dg = emrtd_fileid_to_dg(file); + if ((dg != NULL) && (dg->dumper != NULL)) { + dg->dumper(response, resplen); } return true; } @@ -987,19 +989,14 @@ int dumpHF_EMRTD(char *documentnumber, char *dob, char *expiry, bool BAC_availab // Dump all files in the file list for (int i = 0; i < filelistlen; i++) { - char file_id[5] = { 0x00 }; - char file_name[8] = { 0x00 }; - if (emrtd_file_tag_to_file_id(&filelist[i], file_name, file_id) == false) { + emrtd_dg_t * dg = emrtd_tag_to_dg(filelist[i]); + if (dg == NULL) { PrintAndLogEx(INFO, "File tag not found, skipping: %02X", filelist[i]); continue; } - PrintAndLogEx(DEBUG, "Current file: %s", file_name); - - for (int dgi=0; dg_table[dgi].filename != NULL; dgi++) { - if ((strcmp(dg_table[dgi].filename, file_name) == 0) && !dg_table[dgi].pace) { - emrtd_dump_file(ks_enc, ks_mac, ssc, file_id, file_name, BAC, use_14b); - break; - } + PrintAndLogEx(DEBUG, "Current file: %s", dg->filename); + if (!dg->pace) { + emrtd_dump_file(ks_enc, ks_mac, ssc, dg->fileid, dg->filename, BAC, use_14b); } } @@ -1221,18 +1218,12 @@ static int emrtd_print_ef_com_info(uint8_t *data, size_t datalen) { PrintAndLogEx(NORMAL, ""); PrintAndLogEx(INFO, "-------------------- " _CYAN_("EF_COM") " --------------------"); for (int i = 0; i < filelistlen; i++) { - char file_id[5] = { 0x00 }; - char file_name[8] = { 0x00 }; - if (emrtd_file_tag_to_file_id(&filelist[i], file_name, file_id) == false) { - PrintAndLogEx(DEBUG, "File tag not found, skipping: %02X", filelist[i]); + emrtd_dg_t * dg = emrtd_tag_to_dg(filelist[i]); + if (dg == NULL) { + PrintAndLogEx(INFO, "File tag not found, skipping: %02X", filelist[i]); continue; } - for (int dgi=0; dg_table[dgi].filename != NULL; dgi++) { - if (strcmp(dg_table[dgi].filename, file_name) == 0) { - PrintAndLogEx(SUCCESS, "%-7s...............: " _YELLOW_("%s"), file_name, dg_table[dgi].desc); - break; - } - } + PrintAndLogEx(SUCCESS, "%-7s...............: " _YELLOW_("%s"), dg->filename, dg->desc); } return PM3_SUCCESS; } @@ -1525,19 +1516,15 @@ int infoHF_EMRTD(char *documentnumber, char *dob, char *expiry, bool BAC_availab // Dump all files in the file list for (int i = 0; i < filelistlen; i++) { - char file_id[5] = { 0x00 }; - char file_name[8] = { 0x00 }; - if (emrtd_file_tag_to_file_id(&filelist[i], file_name, file_id) == false) { - PrintAndLogEx(DEBUG, "File tag not found, skipping: %02X", filelist[i]); + emrtd_dg_t * dg = emrtd_tag_to_dg(filelist[i]); + if (dg == NULL) { + PrintAndLogEx(INFO, "File tag not found, skipping: %02X", filelist[i]); continue; } - for (int dgi=0; dg_table[dgi].filename != NULL; dgi++) { - if ((strcmp(dg_table[dgi].filename, file_name) == 0) && dg_table[dgi].fastdump && !dg_table[dgi].pace) { - if (emrtd_select_and_read(response, &resplen, dg_table[dgi].fileid, ks_enc, ks_mac, ssc, BAC, use_14b)) { - if (dg_table[dgi].parser != NULL) - dg_table[dgi].parser(response, resplen); - } - break; + if (dg->fastdump && !dg->pace) { + if (emrtd_select_and_read(response, &resplen, dg->fileid, ks_enc, ks_mac, ssc, BAC, use_14b)) { + if (dg->parser != NULL) + dg->parser(response, resplen); } } } @@ -1585,26 +1572,21 @@ int infoHF_EMRTD_offline(const char *path) { free(data); // Read files in the file list for (int i = 0; i < filelistlen; i++) { - char file_id[5] = { 0x00 }; - char file_name[8] = { 0x00 }; - if (emrtd_file_tag_to_file_id(&filelist[i], file_name, file_id) == false) { - //PrintAndLogEx(DEBUG, "File tag not found, skipping: %02X", filelist[i]); + emrtd_dg_t * dg = emrtd_tag_to_dg(filelist[i]); + if (dg == NULL) { + PrintAndLogEx(INFO, "File tag not found, skipping: %02X", filelist[i]); continue; } - - for (int dgi=0; dg_table[dgi].filename != NULL; dgi++) { - if ((strcmp(dg_table[dgi].filename, file_name) == 0) && (!dg_table[dgi].pace)) { - strcpy(filepath, path); - strncat(filepath, PATHSEP, 1); - strcat(filepath, dg_table[dgi].filename); - if (loadFile_safeEx(filepath, ".BIN", (void **)&data, (size_t *)&datalen, false) == PM3_SUCCESS) - { - // we won't halt on parsing errors - if (dg_table[dgi].parser != NULL) - dg_table[dgi].parser(data, datalen); - free(data); - } - break; + if (!dg->pace) { + strcpy(filepath, path); + strncat(filepath, PATHSEP, 1); + strcat(filepath, dg->filename); + if (loadFile_safeEx(filepath, ".BIN", (void **)&data, (size_t *)&datalen, false) == PM3_SUCCESS) + { + // we won't halt on parsing errors + if (dg->parser != NULL) + dg->parser(data, datalen); + free(data); } } } From e16249252e5c64e864d9c2bbc307266b2deb434e Mon Sep 17 00:00:00 2001 From: Philippe Teuwen Date: Sat, 19 Dec 2020 17:58:22 +0100 Subject: [PATCH 149/682] emrtd: remove last defs and integrate SOD in com lists --- client/src/cmdhfemrtd.c | 77 +++++++++++++++++++++-------------------- 1 file changed, 39 insertions(+), 38 deletions(-) diff --git a/client/src/cmdhfemrtd.c b/client/src/cmdhfemrtd.c index 4475cfa3a..eb399f3cc 100644 --- a/client/src/cmdhfemrtd.c +++ b/client/src/cmdhfemrtd.c @@ -43,13 +43,6 @@ #define EMRTD_P1_SELECT_BY_NAME "04" #define EMRTD_P2_PROPRIETARY "0C" -// File IDs -// TODO -> dg_table -#define EMRTD_EF_CARDACCESS "011C" -#define EMRTD_EF_SOD "011D" -#define EMRTD_EF_COM "011E" -#define EMRTD_EF_DG1 "0101" - // App IDs #define EMRTD_AID_MRTD "A0000002471001" @@ -66,11 +59,33 @@ static int emrtd_print_ef_dg1_info(uint8_t *data, size_t datalen); static int emrtd_print_ef_dg11_info(uint8_t *data, size_t datalen); static int emrtd_print_ef_dg12_info(uint8_t *data, size_t datalen); static int emrtd_print_ef_sod_info(uint8_t *data, size_t datalen); + +typedef enum { // list must match dg_table + EF_COM=0, + EF_DG1, + EF_DG2, + EF_DG3, + EF_DG4, + EF_DG5, + EF_DG6, + EF_DG7, + EF_DG8, + EF_DG9, + EF_DG10, + EF_DG11, + EF_DG12, + EF_DG13, + EF_DG14, + EF_DG15, + EF_DG16, + EF_SOD, + EF_CardAccess, + EF_CardSecurity, +} emrtd_dg_enum; + static emrtd_dg_t dg_table[] = { // tag fileid filename desc pace req fast parser dumper {0x60, "011E", "EF_COM", "Header and Data Group Presence Information", false, true, true, emrtd_print_ef_com_info, NULL}, - {0xff, "011C", "EF_CardAccess", "PACE SecurityInfos", true, true, true, NULL, NULL}, - {0xff, "011D", "EF_CardSecurity", "PACE SecurityInfos for Chip Authentication Mapping", true, false, true, NULL, NULL}, {0x61, "0101", "EF_DG1", "Details recorded in MRZ", false, true, true, emrtd_print_ef_dg1_info, NULL}, {0x75, "0102", "EF_DG2", "Encoded Face", false, true, false, NULL, emrtd_dump_ef_dg2}, {0x63, "0103", "EF_DG3", "Encoded Finger(s)", true, false, false, NULL, NULL}, @@ -88,6 +103,8 @@ static emrtd_dg_t dg_table[] = { {0x6f, "010F", "EF_DG15", "Active Authentication Public Key Info", false, false, true, NULL, NULL}, {0x70, "0110", "EF_DG16", "Person(s) to Notify", false, false, true, NULL, NULL}, {0x77, "011D", "EF_SOD", "Document Security Object", false, false, true, emrtd_print_ef_sod_info, emrtd_dump_ef_sod}, + {0xff, "011C", "EF_CardAccess", "PACE SecurityInfos", true, true, true, NULL, NULL}, + {0xff, "011D", "EF_CardSecurity", "PACE SecurityInfos for Chip Authentication Mapping", true, false, true, NULL, NULL}, {0x00, NULL, NULL, NULL, false, false, false, NULL, NULL} }; @@ -905,13 +922,13 @@ static bool emrtd_do_auth(char *documentnumber, char *dob, char *expiry, bool BA } // Select EF_COM - if (emrtd_select_file(EMRTD_P1_SELECT_BY_EF, EMRTD_EF_COM, *use_14b) == false) { + if (emrtd_select_file(EMRTD_P1_SELECT_BY_EF, dg_table[EF_COM].fileid, *use_14b) == false) { *BAC = true; PrintAndLogEx(INFO, "Basic Access Control is enforced. Will attempt external authentication."); } else { *BAC = false; // Select EF_DG1 - emrtd_select_file(EMRTD_P1_SELECT_BY_EF, EMRTD_EF_DG1, *use_14b); + emrtd_select_file(EMRTD_P1_SELECT_BY_EF, dg_table[EF_DG1].fileid, *use_14b); if (emrtd_read_file(response, &resplen, NULL, NULL, NULL, false, *use_14b) == false) { *BAC = true; @@ -955,7 +972,7 @@ int dumpHF_EMRTD(char *documentnumber, char *dob, char *expiry, bool BAC_availab } // Dump EF_CardAccess (if available) - if (!emrtd_dump_file(ks_enc, ks_mac, ssc, EMRTD_EF_CARDACCESS, "EF_CardAccess", BAC, use_14b)) { + if (!emrtd_dump_file(ks_enc, ks_mac, ssc, dg_table[EF_CardAccess].fileid, dg_table[EF_CardAccess].filename, BAC, use_14b)) { PrintAndLogEx(INFO, "Couldn't dump EF_CardAccess, card does not support PACE."); PrintAndLogEx(HINT, "This is expected behavior for cards without PACE, and isn't something to be worried about."); } @@ -967,14 +984,14 @@ int dumpHF_EMRTD(char *documentnumber, char *dob, char *expiry, bool BAC_availab } // Select EF_COM - if (!emrtd_select_and_read(response, &resplen, EMRTD_EF_COM, ks_enc, ks_mac, ssc, BAC, use_14b)) { + if (!emrtd_select_and_read(response, &resplen, dg_table[EF_COM].fileid, ks_enc, ks_mac, ssc, BAC, use_14b)) { PrintAndLogEx(ERR, "Failed to read EF_COM."); DropField(); return PM3_ESOFT; } PrintAndLogEx(INFO, "Read EF_COM, len: %i.", resplen); PrintAndLogEx(DEBUG, "Contents (may be incomplete over 2k chars): %s", sprint_hex_inrow(response, resplen)); - saveFile("EF_COM", ".BIN", response, resplen); + saveFile(dg_table[EF_COM].filename, ".BIN", response, resplen); uint8_t filelist[50]; int filelistlen = 0; @@ -986,7 +1003,8 @@ int dumpHF_EMRTD(char *documentnumber, char *dob, char *expiry, bool BAC_availab } PrintAndLogEx(DEBUG, "File List: %s", sprint_hex_inrow(filelist, filelistlen)); - + // Add EF_SOD to the list + filelist[filelistlen++] = 0x77; // Dump all files in the file list for (int i = 0; i < filelistlen; i++) { emrtd_dg_t * dg = emrtd_tag_to_dg(filelist[i]); @@ -999,10 +1017,6 @@ int dumpHF_EMRTD(char *documentnumber, char *dob, char *expiry, bool BAC_availab emrtd_dump_file(ks_enc, ks_mac, ssc, dg->fileid, dg->filename, BAC, use_14b); } } - - // Dump EF_SOD - emrtd_dump_file(ks_enc, ks_mac, ssc, EMRTD_EF_SOD, "EF_SOD", BAC, use_14b); - DropField(); return PM3_SUCCESS; } @@ -1493,7 +1507,7 @@ int infoHF_EMRTD(char *documentnumber, char *dob, char *expiry, bool BAC_availab return PM3_ESOFT; } - if (!emrtd_select_and_read(response, &resplen, EMRTD_EF_COM, ks_enc, ks_mac, ssc, BAC, use_14b)) { + if (!emrtd_select_and_read(response, &resplen, dg_table[EF_COM].fileid, ks_enc, ks_mac, ssc, BAC, use_14b)) { PrintAndLogEx(ERR, "Failed to read EF_COM."); DropField(); return PM3_ESOFT; @@ -1513,7 +1527,8 @@ int infoHF_EMRTD(char *documentnumber, char *dob, char *expiry, bool BAC_availab DropField(); return PM3_ESOFT; } - + // Add EF_SOD to the list + filelist[filelistlen++] = 0x77; // Dump all files in the file list for (int i = 0; i < filelistlen; i++) { emrtd_dg_t * dg = emrtd_tag_to_dg(filelist[i]); @@ -1528,11 +1543,6 @@ int infoHF_EMRTD(char *documentnumber, char *dob, char *expiry, bool BAC_availab } } } -// TODO - if (emrtd_select_and_read(response, &resplen, EMRTD_EF_SOD, ks_enc, ks_mac, ssc, BAC, use_14b)) { - emrtd_print_ef_sod_info(response, resplen); - } - DropField(); return PM3_SUCCESS; } @@ -1545,7 +1555,7 @@ int infoHF_EMRTD_offline(const char *path) { return PM3_EMALLOC; strcpy(filepath, path); strncat(filepath, PATHSEP, 1); - strcat(filepath, "EF_COM"); + strcat(filepath, dg_table[EF_COM].filename); if (loadFile_safeEx(filepath, ".BIN", (void **)&data, (size_t *)&datalen, false) != PM3_SUCCESS) { PrintAndLogEx(ERR, "Failed to read EF_COM."); @@ -1570,6 +1580,8 @@ int infoHF_EMRTD_offline(const char *path) { return PM3_ESOFT; } free(data); + // Add EF_SOD to the list + filelist[filelistlen++] = 0x77; // Read files in the file list for (int i = 0; i < filelistlen; i++) { emrtd_dg_t * dg = emrtd_tag_to_dg(filelist[i]); @@ -1590,17 +1602,6 @@ int infoHF_EMRTD_offline(const char *path) { } } } -// TODO - strcpy(filepath, path); - strncat(filepath, PATHSEP, 1); - strcat(filepath, "EF_SOD"); - if (loadFile_safeEx(filepath, ".BIN", (void **)&data, (size_t *)&datalen, false) == PM3_SUCCESS) - { - // we won't halt on parsing errors - emrtd_print_ef_sod_info(data, datalen); - free(data); - } - free(filepath); return PM3_SUCCESS; } From 97eaab27a189afe4ee901ca4f78c9e7a886c213d Mon Sep 17 00:00:00 2001 From: Philippe Teuwen Date: Sat, 19 Dec 2020 18:01:19 +0100 Subject: [PATCH 150/682] emrtd: remove few hardcoded filenames --- client/src/cmdhfemrtd.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/client/src/cmdhfemrtd.c b/client/src/cmdhfemrtd.c index eb399f3cc..7a46c6850 100644 --- a/client/src/cmdhfemrtd.c +++ b/client/src/cmdhfemrtd.c @@ -702,7 +702,7 @@ static int emrtd_dump_ef_dg2(uint8_t *file_contents, size_t file_length) { return PM3_ESOFT; } - saveFile("EF_DG2", file_contents[offset] == 0xFF ? ".jpg" : ".jp2", file_contents + offset, datalen); + saveFile(dg_table[EF_DG2].filename, file_contents[offset] == 0xFF ? ".jpg" : ".jp2", file_contents + offset, datalen); return PM3_SUCCESS; } @@ -716,7 +716,7 @@ static int emrtd_dump_ef_dg5(uint8_t *file_contents, size_t file_length) { } if (datalen < EMRTD_MAX_FILE_SIZE) { - saveFile("EF_DG5", data[0] == 0xFF ? ".jpg" : ".jp2", data, datalen); + saveFile(dg_table[EF_DG5].filename, data[0] == 0xFF ? ".jpg" : ".jp2", data, datalen); } else { PrintAndLogEx(ERR, "error (emrtd_dump_ef_dg5) datalen out-of-bounds"); return PM3_ESOFT; @@ -734,7 +734,7 @@ static int emrtd_dump_ef_dg7(uint8_t *file_contents, size_t file_length) { } if (datalen < EMRTD_MAX_FILE_SIZE) { - saveFile("EF_DG7", data[0] == 0xFF ? ".jpg" : ".jp2", data, datalen); + saveFile(dg_table[EF_DG7].filename, data[0] == 0xFF ? ".jpg" : ".jp2", data, datalen); } else { PrintAndLogEx(ERR, "error (emrtd_dump_ef_dg7) datalen out-of-bounds"); return PM3_ESOFT; @@ -751,7 +751,7 @@ static int emrtd_dump_ef_sod(uint8_t *file_contents, size_t file_length) { return PM3_SUCCESS; } - saveFile("EF_SOD", ".p7b", file_contents + fieldlen + 1, datalen); + saveFile(dg_table[EF_SOD].filename, ".p7b", file_contents + fieldlen + 1, datalen); return PM3_ESOFT; } From 415dd84a8d6ddf752224bd12803f48ebf0544ced Mon Sep 17 00:00:00 2001 From: Philippe Teuwen Date: Sat, 19 Dec 2020 19:32:06 +0100 Subject: [PATCH 151/682] fix print_buffer out-of-boundaries bug --- client/src/util.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/client/src/util.c b/client/src/util.c index 4ba4af108..1dad2cd4b 100644 --- a/client/src/util.c +++ b/client/src/util.c @@ -208,7 +208,9 @@ void print_buffer(const uint8_t *data, const size_t len, int level) { char buf[UTIL_BUFFER_SIZE_SPRINT + 3]; int i; for (i = 0; i < len; i += 16) { - + if (len - i < 16) { // incomplete block, will be treated out of the loop + break; + } // (16 * 3) + (16) + + 1 memset(buf, 0, sizeof(buf)); sprintf(buf, "%*s%02x: ", (level * 4), " ", i); From 669eea1f7412d2f198695b3d1edba143fe7d9037 Mon Sep 17 00:00:00 2001 From: Philippe Teuwen Date: Sat, 19 Dec 2020 19:44:26 +0100 Subject: [PATCH 152/682] emrtd: hide SOD todo for now --- client/src/cmdhfemrtd.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/client/src/cmdhfemrtd.c b/client/src/cmdhfemrtd.c index 7a46c6850..9d8332ba7 100644 --- a/client/src/cmdhfemrtd.c +++ b/client/src/cmdhfemrtd.c @@ -1472,9 +1472,9 @@ static int emrtd_print_ef_dg12_info(uint8_t *data, size_t datalen) { } static int emrtd_print_ef_sod_info(uint8_t *data, size_t datalen) { - PrintAndLogEx(NORMAL, ""); - PrintAndLogEx(INFO, "-------------------- " _CYAN_("EF_SOD") " --------------------"); - PrintAndLogEx(WARNING, "TODO"); +// PrintAndLogEx(NORMAL, ""); +// PrintAndLogEx(INFO, "-------------------- " _CYAN_("EF_SOD") " --------------------"); +// PrintAndLogEx(WARNING, "TODO"); return PM3_SUCCESS; } From 3098f01dd9561d6f6ea95af623222920a5c0a2f9 Mon Sep 17 00:00:00 2001 From: Philippe Teuwen Date: Sat, 19 Dec 2020 20:53:16 +0100 Subject: [PATCH 153/682] emrtd: non-BAC: tested! remove debug print --- client/src/cmdhfemrtd.c | 1 - 1 file changed, 1 deletion(-) diff --git a/client/src/cmdhfemrtd.c b/client/src/cmdhfemrtd.c index 9d8332ba7..af586e59a 100644 --- a/client/src/cmdhfemrtd.c +++ b/client/src/cmdhfemrtd.c @@ -935,7 +935,6 @@ static bool emrtd_do_auth(char *documentnumber, char *dob, char *expiry, bool BA PrintAndLogEx(INFO, "Basic Access Control is enforced. Will attempt external authentication."); } else { *BAC = false; - PrintAndLogEx(INFO, "EF_DG1: %s", sprint_hex(response, resplen)); } } From 2d54ec652c4ab1d761f258e91f8ce0482c9ac50f Mon Sep 17 00:00:00 2001 From: tharexde Date: Sat, 19 Dec 2020 21:27:03 +0100 Subject: [PATCH 154/682] changed reading of "uid" to "serial" in function detect_4x50_block since output is always "serial" --- client/src/cmdlfem4x50.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/src/cmdlfem4x50.c b/client/src/cmdlfem4x50.c index 2f415c32b..0476043a5 100644 --- a/client/src/cmdlfem4x50.c +++ b/client/src/cmdlfem4x50.c @@ -508,7 +508,7 @@ bool detect_4x50_block(void) { em4x50_data_t etd = { .pwd_given = false, .addr_given = true, - .addresses = (EM4X50_DEVICE_ID << 8) | EM4X50_DEVICE_ID, + .addresses = (EM4X50_DEVICE_SERIAL << 8) | EM4X50_DEVICE_SERIAL, }; em4x50_word_t words[EM4X50_NO_WORDS]; return (em4x50_read(&etd, words) == PM3_SUCCESS); From ef8f47263ae35c40dab6e67f5be3b4237a0bff6f Mon Sep 17 00:00:00 2001 From: tharexde Date: Sat, 19 Dec 2020 22:00:48 +0100 Subject: [PATCH 155/682] lf em 4x50 info: complete data is displayed only via additional verbose option (-v) --- client/src/cmdlfem4x50.c | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/client/src/cmdlfem4x50.c b/client/src/cmdlfem4x50.c index 0476043a5..9c907caf7 100644 --- a/client/src/cmdlfem4x50.c +++ b/client/src/cmdlfem4x50.c @@ -81,7 +81,7 @@ static void print_result(const em4x50_word_t *words, int fwr, int lwr) { PrintAndLogEx(INFO, "----+-------------+-------------+--------------------"); } -static void print_info_result(uint8_t *data) { +static void print_info_result(uint8_t *data, bool verbose) { // display all information of info result in structured format em4x50_word_t words[EM4X50_NO_WORDS]; @@ -104,7 +104,11 @@ static void print_info_result(uint8_t *data) { // data section PrintAndLogEx(NORMAL, ""); PrintAndLogEx(INFO, _YELLOW_("EM4x50 data:")); - print_result(words, 0, EM4X50_NO_WORDS - 1); + if (verbose) { + print_result(words, 0, EM4X50_NO_WORDS - 1); + } else { + print_result(words, EM4X50_DEVICE_SERIAL, EM4X50_DEVICE_ID); + } // configuration section PrintAndLogEx(NORMAL, ""); @@ -618,12 +622,14 @@ int CmdEM4x50Info(const char *Cmd) { CLIParserInit(&ctx, "lf em 4x50 info", "Tag information EM4x50.", "lf em 4x50 info\n" + "lf em 4x50 info -v -> show data section\n" "lf em 4x50 info -p 12345678 -> uses pwd 0x12345678\n" ); void *argtable[] = { arg_param_begin, arg_str0("p", "pwd", "", "password, 4 hex bytes, lsb"), + arg_lit0("v", "verbose", "additional output of data section"), arg_param_end }; @@ -631,6 +637,7 @@ int CmdEM4x50Info(const char *Cmd) { int pwd_len = 0; uint8_t pwd[4] = {0x0}; CLIGetHexWithReturn(ctx, 1, pwd, &pwd_len); + bool verb = arg_get_lit(ctx, 2); CLIParserFree(ctx); em4x50_data_t etd = {.pwd_given = false}; @@ -653,7 +660,7 @@ int CmdEM4x50Info(const char *Cmd) { } if (resp.status == PM3_SUCCESS) - print_info_result(resp.data.asBytes); + print_info_result(resp.data.asBytes, verb); else PrintAndLogEx(FAILED, "Reading tag " _RED_("failed")); From c828caff3357a2210ac1309884b29557db582163 Mon Sep 17 00:00:00 2001 From: Philippe Teuwen Date: Sat, 19 Dec 2020 22:05:10 +0100 Subject: [PATCH 156/682] emrtd: add --mrz --- client/src/cmdhfemrtd.c | 58 ++++++++++++++++++++++++++++++++++++++--- 1 file changed, 55 insertions(+), 3 deletions(-) diff --git a/client/src/cmdhfemrtd.c b/client/src/cmdhfemrtd.c index af586e59a..6420d45e3 100644 --- a/client/src/cmdhfemrtd.c +++ b/client/src/cmdhfemrtd.c @@ -1640,10 +1640,12 @@ static int cmd_hf_emrtd_dump(const char *Cmd) { arg_str0("n", "documentnumber", "", "document number, up to 9 chars"), arg_str0("d", "dateofbirth", "", "date of birth in YYMMDD format"), arg_str0("e", "expiry", "", "expiry in YYMMDD format"), + arg_str0("m", "mrz", "<[0-9A-Z<]>", "2nd line of MRZ, 44 chars"), arg_param_end }; CLIExecWithReturn(ctx, Cmd, argtable, true); + uint8_t mrz[45] = { 0x00 }; uint8_t docnum[10] = { 0x00 }; uint8_t dob[7] = { 0x00 }; uint8_t expiry[7] = { 0x00 }; @@ -1657,7 +1659,7 @@ static int cmd_hf_emrtd_dump(const char *Cmd) { text_to_upper(docnum, slen); if (slen != 9) { // Pad to 9 with < - memset(docnum + slen, 0x3c, 9 - slen); + memset(docnum + slen, '<', 9 - slen); } } @@ -1681,6 +1683,30 @@ static int cmd_hf_emrtd_dump(const char *Cmd) { } } + if (CLIParamStrToBuf(arg_get_str(ctx, 4), mrz, 44, &slen) == 0 && slen != 0) { + if (slen != 44) { + PrintAndLogEx(ERR, "MRZ length is incorrect, it should be 44, not %i", slen); + error = true; + } else { + BAC = true; + text_to_upper(mrz, slen); + memcpy(docnum, &mrz[0], 9); + memcpy(dob, &mrz[13], 6); + memcpy(expiry, &mrz[21], 6); + // TODO check MRZ checksums? + if (!validate_date(dob, 6)) { + PrintAndLogEx(ERR, "Date of birth date format is incorrect, cannot continue."); + PrintAndLogEx(HINT, "Use the format YYMMDD."); + error = true; + } + if (!validate_date(expiry, 6)) { + PrintAndLogEx(ERR, "Expiry date format is incorrect, cannot continue."); + PrintAndLogEx(HINT, "Use the format YYMMDD."); + error = true; + } + } + } + CLIParserFree(ctx); if (error) { return PM3_ESOFT; @@ -1700,11 +1726,13 @@ static int cmd_hf_emrtd_info(const char *Cmd) { arg_str0("n", "documentnumber", "", "document number, up to 9 chars"), arg_str0("d", "dateofbirth", "", "date of birth in YYMMDD format"), arg_str0("e", "expiry", "", "expiry in YYMMDD format"), + arg_str0("m", "mrz", "<[0-9A-Z<]>", "2nd line of MRZ, 44 chars"), arg_str0(NULL, "path", "", "display info from offline dump stored in dirpath"), arg_param_end }; CLIExecWithReturn(ctx, Cmd, argtable, true); + uint8_t mrz[45] = { 0x00 }; uint8_t docnum[10] = { 0x00 }; uint8_t dob[7] = { 0x00 }; uint8_t expiry[7] = { 0x00 }; @@ -1717,7 +1745,7 @@ static int cmd_hf_emrtd_info(const char *Cmd) { } else { text_to_upper(docnum, slen); if (slen != 9) { - memset(docnum + slen, 0x3c, 9 - slen); + memset(docnum + slen, '<', 9 - slen); } } @@ -1740,8 +1768,32 @@ static int cmd_hf_emrtd_info(const char *Cmd) { error = true; } } + + if (CLIParamStrToBuf(arg_get_str(ctx, 4), mrz, 44, &slen) == 0 && slen != 0) { + if (slen != 44) { + PrintAndLogEx(ERR, "MRZ length is incorrect, it should be 44, not %i", slen); + error = true; + } else { + BAC = true; + text_to_upper(mrz, slen); + memcpy(docnum, &mrz[0], 9); + memcpy(dob, &mrz[13], 6); + memcpy(expiry, &mrz[21], 6); + // TODO check MRZ checksums? + if (!validate_date(dob, 6)) { + PrintAndLogEx(ERR, "Date of birth date format is incorrect, cannot continue."); + PrintAndLogEx(HINT, "Use the format YYMMDD."); + error = true; + } + if (!validate_date(expiry, 6)) { + PrintAndLogEx(ERR, "Expiry date format is incorrect, cannot continue."); + PrintAndLogEx(HINT, "Use the format YYMMDD."); + error = true; + } + } + } uint8_t path[FILENAME_MAX] = { 0x00 }; - bool offline = CLIParamStrToBuf(arg_get_str(ctx, 4), path, sizeof(path), &slen) == 0 && slen > 0; + bool offline = CLIParamStrToBuf(arg_get_str(ctx, 5), path, sizeof(path), &slen) == 0 && slen > 0; CLIParserFree(ctx); if (error) { return PM3_ESOFT; From 2385ea9bb723c27572087859d1ffb903e34e4491 Mon Sep 17 00:00:00 2001 From: Philippe Teuwen Date: Sun, 20 Dec 2020 01:13:20 +0100 Subject: [PATCH 157/682] fix issue #1127 --- client/src/cmdhfemrtd.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/client/src/cmdhfemrtd.c b/client/src/cmdhfemrtd.c index 6420d45e3..30eb4667f 100644 --- a/client/src/cmdhfemrtd.c +++ b/client/src/cmdhfemrtd.c @@ -1553,7 +1553,7 @@ int infoHF_EMRTD_offline(const char *path) { if (filepath == NULL) return PM3_EMALLOC; strcpy(filepath, path); - strncat(filepath, PATHSEP, 1); + strncat(filepath, PATHSEP, 2); strcat(filepath, dg_table[EF_COM].filename); if (loadFile_safeEx(filepath, ".BIN", (void **)&data, (size_t *)&datalen, false) != PM3_SUCCESS) { @@ -1590,7 +1590,7 @@ int infoHF_EMRTD_offline(const char *path) { } if (!dg->pace) { strcpy(filepath, path); - strncat(filepath, PATHSEP, 1); + strncat(filepath, PATHSEP, 2); strcat(filepath, dg->filename); if (loadFile_safeEx(filepath, ".BIN", (void **)&data, (size_t *)&datalen, false) == PM3_SUCCESS) { From 08efedaa8363786c8122d020cd9ff7f5a3d1fd53 Mon Sep 17 00:00:00 2001 From: tcprst Date: Sun, 20 Dec 2020 17:19:26 -0500 Subject: [PATCH 158/682] hf legic crc - now use cliparser --- client/luascripts/hf_legic_clone.lua | 2 +- client/src/cmdhflegic.c | 103 +++++++-------------------- doc/cliparser_todo.txt | 1 - 3 files changed, 26 insertions(+), 80 deletions(-) diff --git a/client/luascripts/hf_legic_clone.lua b/client/luascripts/hf_legic_clone.lua index 28a95bca7..ec0c78d25 100644 --- a/client/luascripts/hf_legic_clone.lua +++ b/client/luascripts/hf_legic_clone.lua @@ -536,7 +536,7 @@ local function main(args) res = res .."\n\na segmentCRC gets calculated over MCD,MSN0..3, Segment-Header0..3" res = res .."\ne.g. (based on Segment00 of the data from "..infile.."):" res = res .."\n" - res = res ..ansicolors.yellow.."hf legic crc d "..bytes[1]..bytes[2]..bytes[3]..bytes[4]..bytes[23]..bytes[24]..bytes[25]..bytes[26].." u "..newcrc.." c 8"..ansicolors.reset + res = res ..ansicolors.yellow.."hf legic crc -d "..bytes[1]..bytes[2]..bytes[3]..bytes[4]..bytes[23]..bytes[24]..bytes[25]..bytes[26].." --mcc "..newcrc.." -t 8"..ansicolors.reset -- this can not be calculated without knowing the new MCD, MSN0..2 print(res) end diff --git a/client/src/cmdhflegic.c b/client/src/cmdhflegic.c index 39a542cc9..b202ba170 100644 --- a/client/src/cmdhflegic.c +++ b/client/src/cmdhflegic.c @@ -16,6 +16,7 @@ #include #endif +#include "cliparser.h" #include "cmdparser.h" // command_t #include "comms.h" // clearCommandBuffer #include "cmdtrace.h" @@ -27,21 +28,6 @@ static int CmdHelp(const char *Cmd); #define MAX_LENGTH 1024 -static int usage_legic_calccrc(void) { - PrintAndLogEx(NORMAL, "Calculates the legic crc8/crc16 on the given data."); - PrintAndLogEx(NORMAL, "There must be an even number of hexsymbols as input.\n"); - PrintAndLogEx(NORMAL, "Usage: hf legic crc [h] d u c <8|16>\n"); - PrintAndLogEx(NORMAL, "Options:"); - PrintAndLogEx(NORMAL, " h : this help"); - PrintAndLogEx(NORMAL, " d : (hex symbols) bytes to calculate crc over"); - PrintAndLogEx(NORMAL, " u : MCC hexbyte"); - PrintAndLogEx(NORMAL, " c <8|16> : Crc type"); - PrintAndLogEx(NORMAL, ""); - PrintAndLogEx(NORMAL, "Examples:"); - PrintAndLogEx(NORMAL, _YELLOW_(" hf legic crc d deadbeef1122")); - PrintAndLogEx(NORMAL, _YELLOW_(" hf legic crc d deadbeef1122 u 9A c 16")); - return PM3_SUCCESS; -} static int usage_legic_rdbl(void) { PrintAndLogEx(NORMAL, "Read data from a LEGIC Prime tag\n"); PrintAndLogEx(NORMAL, "Usage: hf legic rdbl [h] [o ] [l ] [iv ]\n"); @@ -779,84 +765,45 @@ static int CmdLegicWrbl(const char *Cmd) { } static int CmdLegicCalcCrc(const char *Cmd) { + CLIParserContext *ctx; + CLIParserInit(&ctx, "hf legic crc", + "Calculates the legic crc8/crc16 on the given data", + "hf legic crc -d deadbeef1122\n" + "hf legic crc -d deadbeef1122 --mcc 9A -t 16 <- CRC Type 16"); - uint8_t *data = NULL; - uint8_t cmdp = 0, uidcrc = 0, type = 0; - bool errors = false; - int len = 0; - int bg, en; + void *argtable[] = { + arg_param_begin, + arg_str1("d", "data", "", "bytes to calculate crc over"), + arg_str0(NULL, "mcc", "", "MCC hex byte (UID CRC)"), + arg_int0("t", "type", "", "CRC Type (default: 8)"), + arg_param_end + }; + CLIExecWithReturn(ctx, Cmd, argtable, false); - while (param_getchar(Cmd, cmdp) != 0x00 && !errors) { - switch (tolower(param_getchar(Cmd, cmdp))) { - case 'd': - // peek at length of the input string so we can - // figure out how many elements to malloc in "data" - bg = en = 0; - if (param_getptr(Cmd, &bg, &en, cmdp + 1)) { - errors = true; - break; - } - len = (en - bg + 1); + int data_len = 0; + uint8_t data[4096] = {0}; - // check that user entered even number of characters - // for hex data string - if (len & 1) { - errors = true; - break; - } + CLIGetHexWithReturn(ctx, 1, data, &data_len); - // it's possible for user to accidentally enter "b" parameter - // more than once - we have to clean previous malloc - if (data) free(data); - data = calloc(len >> 1, sizeof(uint8_t)); - if (data == NULL) { - PrintAndLogEx(WARNING, "Can't allocate memory. exiting"); - errors = true; - break; - } + int mcc_len = 0; + uint8_t mcc[1] = {0}; // formerly uidcrc - if (param_gethex(Cmd, cmdp + 1, data, len)) { - errors = true; - break; - } + CLIGetHexWithReturn(ctx, 2, mcc, &mcc_len); - len >>= 1; - cmdp += 2; - break; - case 'u': - uidcrc = param_get8ex(Cmd, cmdp + 1, 0, 16); - cmdp += 2; - break; - case 'c': - type = param_get8ex(Cmd, cmdp + 1, 0, 10); - cmdp += 2; - break; - case 'h': - errors = true; - break; - default: - PrintAndLogEx(WARNING, "Unknown parameter '%c'", param_getchar(Cmd, cmdp)); - errors = true; - break; - } - } - //Validations - if (errors || cmdp == 0) { - if (data) free(data); - return usage_legic_calccrc(); - } + int type = arg_get_int_def(ctx, 3, 0); + + CLIParserFree(ctx); switch (type) { case 16: init_table(CRC_LEGIC); - PrintAndLogEx(SUCCESS, "Legic crc16: %X", crc16_legic(data, len, uidcrc)); + PrintAndLogEx(SUCCESS, "Legic crc16: %X", crc16_legic(data, data_len, mcc[0])); break; default: - PrintAndLogEx(SUCCESS, "Legic crc8: %X", CRC8Legic(data, len)); + PrintAndLogEx(SUCCESS, "Legic crc8: %X", CRC8Legic(data, data_len)); break; } - if (data) free(data); return PM3_SUCCESS; } diff --git a/doc/cliparser_todo.txt b/doc/cliparser_todo.txt index b2571f493..6e06c5278 100644 --- a/doc/cliparser_todo.txt +++ b/doc/cliparser_todo.txt @@ -85,7 +85,6 @@ hf legic restore hf legic rdbl hf legic sim hf legic wrbl -hf legic crc hf legic eload hf legic esave hf legic wipe From feeb32b13fdf0cd86520b6d773170d1b23c9e8a5 Mon Sep 17 00:00:00 2001 From: iceman1001 Date: Mon, 21 Dec 2020 01:45:03 +0100 Subject: [PATCH 159/682] lf tune - added possiblity to get bar / mix / value (defaul) output of measurements. Also set in preferences --- client/src/cmdlf.c | 121 ++++++++++++++++++++---------------- client/src/comms.h | 5 +- client/src/preferences.c | 128 ++++++++++++++++++++++++++++++++++++--- client/src/ui.c | 65 ++++++++++++++++++++ client/src/ui.h | 4 ++ client/src/util.h | 1 + 6 files changed, 261 insertions(+), 63 deletions(-) diff --git a/client/src/cmdlf.c b/client/src/cmdlf.c index 89483bf00..4cc303f19 100644 --- a/client/src/cmdlf.c +++ b/client/src/cmdlf.c @@ -230,59 +230,61 @@ static int usage_lf_find(void) { PrintAndLogEx(NORMAL, _YELLOW_(" lf search 1 u") " - use data from GraphBuffer & search for known and unknown tags"); return PM3_SUCCESS; } -static int usage_lf_tune(void) { - PrintAndLogEx(NORMAL, "Continuously measure LF antenna tuning."); - PrintAndLogEx(NORMAL, "Press button or Enter to interrupt."); - PrintAndLogEx(NORMAL, "Usage: lf tune [h] [n ] [q | f ]"); - PrintAndLogEx(NORMAL, ""); - PrintAndLogEx(NORMAL, "Options:"); - PrintAndLogEx(NORMAL, " h - This help"); - PrintAndLogEx(NORMAL, " n - number of iterations (default: 0=infinite)"); - PrintAndLogEx(NORMAL, " q - Frequency divisor. %d -> 134 kHz, %d -> 125 kHz", LF_DIVISOR_134, LF_DIVISOR_125); - PrintAndLogEx(NORMAL, " f - Frequency in kHz"); - return PM3_SUCCESS; -} static int CmdLFTune(const char *Cmd) { - int iter = 0; - uint8_t divisor = LF_DIVISOR_125;//Frequency divisor - bool errors = false; - uint8_t cmdp = 0; - while (param_getchar(Cmd, cmdp) != 0x00 && !errors) { - switch (param_getchar(Cmd, cmdp)) { - case 'h': - return usage_lf_tune(); - case 'q': - errors |= param_getdec(Cmd, cmdp + 1, &divisor); - cmdp += 2; - if (divisor < 19) { - PrintAndLogEx(ERR, "divisor must be between 19 and 255"); - return PM3_EINVARG; - } - break; - case 'f': { - float freq = param_getfloat(Cmd, cmdp + 1, 125); - if ((freq < 47) || (freq > 600)) { - PrintAndLogEx(ERR, "freq must be between 47 and 600"); - return PM3_EINVARG; - } - divisor = LF_FREQ2DIV(freq); - cmdp += 2; - break; - } - case 'n': - iter = param_get32ex(Cmd, cmdp + 1, 0, 10); - cmdp += 2; - break; - default: - PrintAndLogEx(WARNING, "Unknown parameter '%c'", param_getchar(Cmd, cmdp)); - errors = 1; - break; - } + + CLIParserContext *ctx; + CLIParserInit(&ctx, "lf tune", + "Continuously measure LF antenna tuning.\n" + "Press button or to interrupt.", + "lf tune" + ); + + char q_str[60]; + snprintf(q_str, sizeof(q_str), "Frequency divisor. %d -> 134 kHz, %d -> 125 kHz", LF_DIVISOR_134, LF_DIVISOR_125); + void *argtable[] = { + arg_param_begin, + arg_u64_0("n", "iteration", "", "number of iterations (default: 0=infinite)"), + arg_u64_0("q", "divisor", "", q_str), + arg_dbl0("f", "freq", "", "Frequency in kHz"), + arg_lit0(NULL, "bar", "bar style"), + arg_lit0(NULL, "mix", "mixed style"), + arg_lit0(NULL, "value", "values style"), + arg_param_end + }; + CLIExecWithReturn(ctx, Cmd, argtable, true); + uint32_t iter = arg_get_u32_def(ctx, 1, 0); + uint8_t divisor = arg_get_u32_def(ctx, 2, LF_DIVISOR_125); + double freq = arg_get_dbl_def(ctx, 3, 125); + + bool is_bar = arg_get_lit(ctx, 4); + bool is_mix = arg_get_lit(ctx, 5); + bool is_value = arg_get_lit(ctx, 6); + CLIParserFree(ctx); + + if (divisor < 19) { + PrintAndLogEx(ERR, "divisor must be between 19 and 255"); + return PM3_EINVARG; } - //Validations - if (errors) return usage_lf_tune(); + if ((freq < 47) || (freq > 600)) { + PrintAndLogEx(ERR, "freq must be between 47 and 600"); + return PM3_EINVARG; + } + divisor = LF_FREQ2DIV(freq); + + if ((is_bar + is_mix + is_value) > 1) { + PrintAndLogEx(ERR, "Select only one output style"); + return PM3_EINVARG; + } + + barMode_t style = session.bar_mode; + if (is_bar) + style = STYLE_BAR; + if (is_mix) + style = STYLE_MIXED; + if (is_value) + style = STYLE_VALUE; PrintAndLogEx(INFO, "Measuring LF antenna at " _YELLOW_("%.2f") " kHz, click " _GREEN_("pm3 button") " or press " _GREEN_("Enter") " to exit", LF_DIV2FREQ(divisor)); @@ -298,6 +300,13 @@ static int CmdLFTune(const char *Cmd) { } params[0] = 2; + + #define MAX_ADC_LF_VOLTAGE 140800 + uint32_t max = 71000; + bool first = true; + + print_progress(0, max, style); + // loop forever (till button pressed) if iter = 0 (default) for (uint8_t i = 0; iter == 0 || i < iter; i++) { if (kbd_enter_pressed()) { @@ -308,15 +317,23 @@ static int CmdLFTune(const char *Cmd) { if (!WaitForResponseTimeout(CMD_MEASURE_ANTENNA_TUNING_LF, &resp, 1000)) { PrintAndLogEx(NORMAL, ""); PrintAndLogEx(WARNING, "Timeout while waiting for Proxmark LF measure, aborting"); - return PM3_ETIMEOUT; + break; } if ((resp.status == PM3_EOPABORTED) || (resp.length != sizeof(uint32_t))) { + PrintAndLogEx(NORMAL, ""); break; } uint32_t volt = resp.data.asDwords[0]; - PrintAndLogEx(INPLACE, " %u mV / %3u V", volt, (uint32_t)(volt / 1000)); + if (first) { + max = (volt * 1.03); + first = false; + } + if ( volt > max) { + max = (volt * 1.03); + } + print_progress(volt, max, style); } params[0] = 3; @@ -325,7 +342,7 @@ static int CmdLFTune(const char *Cmd) { PrintAndLogEx(WARNING, "Timeout while waiting for Proxmark LF shutdown, aborting"); return PM3_ETIMEOUT; } - PrintAndLogEx(NORMAL, ""); + PrintAndLogEx(NORMAL, "\x1b%c[2K\r", 30); PrintAndLogEx(INFO, "Done."); return PM3_SUCCESS; } diff --git a/client/src/comms.h b/client/src/comms.h index 3ee691a30..80ce543da 100644 --- a/client/src/comms.h +++ b/client/src/comms.h @@ -21,9 +21,7 @@ extern "C" { #endif #ifndef DropField -#define DropField() { \ - clearCommandBuffer(); SendCommandNG(CMD_HF_DROPFIELD, NULL, 0); \ - } +#define DropField() { clearCommandBuffer(); SendCommandNG(CMD_HF_DROPFIELD, NULL, 0); } #endif #ifndef DropFieldEx @@ -48,7 +46,6 @@ typedef enum { FPGA_MEM, } DeviceMemType_t; - typedef struct { bool run; // If TRUE, continue running the uart_communication thread bool block_after_ACK; // if true, block after receiving an ACK package diff --git a/client/src/preferences.c b/client/src/preferences.c index 9f507b969..b6b1eddd3 100644 --- a/client/src/preferences.c +++ b/client/src/preferences.c @@ -55,6 +55,7 @@ int preferences_load(void) { session.overlay_sliders = true; session.show_hints = true; + session.bar_mode = STYLE_VALUE; // setDefaultPath (spDefault, ""); // setDefaultPath (spDump, ""); // setDefaultPath (spTrace, ""); @@ -210,6 +211,20 @@ void preferences_save_callback(json_t *root) { default: JsonSaveStr(root, "logging.level", "NORMAL"); } + + switch (session.bar_mode) { + case STYLE_BAR: + JsonSaveStr(root, "show.bar.mode", "bar"); + break; + case STYLE_MIXED: + JsonSaveStr(root, "show.bar.mode", "mixed"); + break; + case STYLE_VALUE: + JsonSaveStr(root, "show.bar.mode", "value"); + break; + default: + JsonSaveStr(root, "show.bar.mode", "value"); + } /* switch (session.device_debug_level) { case ddbOFF: @@ -298,6 +313,16 @@ void preferences_load_callback(json_t *root) { if (json_unpack_ex(root, &up_error, 0, "{s:b}", "os.supports.colors", &b1) == 0) session.supports_colors = (bool)b1; + + // bar mode + if (json_unpack_ex(root, &up_error, 0, "{s:s}", "show.bar.mode", &s1) == 0) { + strncpy(tempStr, s1, sizeof(tempStr) - 1); + str_lower(tempStr); + if (strncmp(tempStr, "bar", 5) == 0) session.bar_mode = STYLE_BAR; + if (strncmp(tempStr, "mixed", 5) == 0) session.bar_mode = STYLE_MIXED; + if (strncmp(tempStr, "value", 7) == 0) session.bar_mode = STYLE_VALUE; + } + /* // Logging Level if (json_unpack_ex(root, &up_error, 0, "{s:s}", "device.debug.level", &s1) == 0) { @@ -343,6 +368,17 @@ static int usage_set_debug(void) { PrintAndLogEx(NORMAL, " "_GREEN_("full")" - full debug messages"); return PM3_SUCCESS; } + +static int usage_set_bar_mode(void) { + PrintAndLogEx(NORMAL, "Usage: pref set barmode "); + PrintAndLogEx(NORMAL, "Options:"); + PrintAndLogEx(NORMAL, " "_GREEN_("help")" - This help"); + PrintAndLogEx(NORMAL, " "_GREEN_("bar")" - measured values as bar only"); + PrintAndLogEx(NORMAL, " "_GREEN_("mixed")" - measured values as numbers and bar"); + PrintAndLogEx(NORMAL, " "_GREEN_("value")" - measured values"); + return PM3_SUCCESS; +} + /* static int usage_set_devicedebug(void) { PrintAndLogEx(NORMAL, "Usage: pref set devicedebug "); @@ -521,6 +557,23 @@ static void showPlotSliderState(prefShowOpt_t opt) { PrintAndLogEx(INFO, " %s show plot sliders...... "_WHITE_("off"), prefShowMsg(opt)); } +static void showBarModeState(prefShowOpt_t opt) { + + switch (session.bar_mode) { + case STYLE_BAR: + PrintAndLogEx(INFO, " %s mode................... "_GREEN_("bar"), prefShowMsg(opt)); + break; + case STYLE_MIXED: + PrintAndLogEx(INFO, " %s mode................... "_GREEN_("mixed"), prefShowMsg(opt)); + break; + case STYLE_VALUE: + PrintAndLogEx(INFO, " %s mode................... "_GREEN_("value"), prefShowMsg(opt)); + break; + default: + PrintAndLogEx(INFO, " %s mode.................. "_RED_("unknown"), prefShowMsg(opt)); + } +} + static int setCmdEmoji(const char *Cmd) { uint8_t cmdp = 0; @@ -921,6 +974,57 @@ static int getCmdHelp(const char *Cmd) { } */ +static int setCmdBarMode(const char *Cmd) { + uint8_t cmdp = 0; + bool errors = false; + bool validValue = false; + char strOpt[50]; + barMode_t newValue = session.bar_mode; + + if (param_getchar(Cmd, cmdp) == 0x00) + return usage_set_bar_mode(); + + while ((param_getchar(Cmd, cmdp) != 0x00) && !errors) { + + if (param_getstr(Cmd, cmdp++, strOpt, sizeof(strOpt)) != 0) { + str_lower(strOpt); // convert to lowercase + + if (strncmp(strOpt, "help", 4) == 0) + return usage_set_bar_mode(); + + if (strncmp(strOpt, "bar", 3) == 0) { + validValue = true; + newValue = STYLE_BAR; + } + if (strncmp(strOpt, "mixed", 5) == 0) { + validValue = true; + newValue = STYLE_MIXED; + } + if (strncmp(strOpt, "value", 5) == 0) { + validValue = true; + newValue = STYLE_VALUE; + } + + if (validValue) { + if (session.bar_mode != newValue) {// changed + showBarModeState(prefShowOLD); + session.bar_mode = newValue; + showBarModeState(prefShowNEW); + preferences_save(); + } else { + PrintAndLogEx(INFO, "nothing changed"); + showBarModeState(prefShowNone); + } + } else { + PrintAndLogEx(ERR, "invalid option"); + return usage_set_bar_mode(); + } + } + } + + return PM3_SUCCESS; +} + static int getCmdEmoji(const char *Cmd) { showEmojiState(prefShowNone); return PM3_SUCCESS; @@ -946,27 +1050,35 @@ static int getCmdPlotSlider(const char *Cmd) { return PM3_SUCCESS; } +static int getCmdBarMode(const char *Cmd) { + showBarModeState(prefShowNone); + return PM3_SUCCESS; +} + + static command_t getCommandTable[] = { // {"help", getCmdHelp, AlwaysAvailable, "This help"}, - {"emoji", getCmdEmoji, AlwaysAvailable, "Get emoji display preference"}, - {"hints", getCmdHint, AlwaysAvailable, "Get hint display preference"}, + {"barmode", getCmdBarMode, AlwaysAvailable, "Get bar mode preference"}, + {"clientdebug", getCmdDebug, AlwaysAvailable, "Get client debug level preference"}, {"color", getCmdColor, AlwaysAvailable, "Get color support preference"}, // {"defaultsavepaths", getCmdSavePaths, AlwaysAvailable, "... to be adjusted next ... "}, - {"clientdebug", getCmdDebug, AlwaysAvailable, "Get client debug level preference"}, - {"plotsliders", getCmdPlotSlider, AlwaysAvailable, "Get plot slider display preference"}, // {"devicedebug", getCmdDeviceDebug, AlwaysAvailable, "Get device debug level"}, + {"emoji", getCmdEmoji, AlwaysAvailable, "Get emoji display preference"}, + {"hints", getCmdHint, AlwaysAvailable, "Get hint display preference"}, + {"plotsliders", getCmdPlotSlider, AlwaysAvailable, "Get plot slider display preference"}, {NULL, NULL, NULL, NULL} }; static command_t setCommandTable[] = { {"help", setCmdHelp, AlwaysAvailable, "This help"}, + {"barmode", setCmdBarMode, AlwaysAvailable, "Set bar mode"}, + {"clientdebug", setCmdDebug, AlwaysAvailable, "Set client debug level"}, + {"color", setCmdColor, AlwaysAvailable, "Set color support"}, {"emoji", setCmdEmoji, AlwaysAvailable, "Set emoji display"}, {"hints", setCmdHint, AlwaysAvailable, "Set hint display"}, - {"color", setCmdColor, AlwaysAvailable, "Set color support"}, // {"defaultsavepaths", setCmdSavePaths, AlwaysAvailable, "... to be adjusted next ... "}, - {"clientdebug", setCmdDebug, AlwaysAvailable, "Set client debug level"}, - {"plotsliders", setCmdPlotSliders, AlwaysAvailable, "Set plot slider display"}, // {"devicedebug", setCmdDeviceDebug, AlwaysAvailable, "Set device debug level"}, + {"plotsliders", setCmdPlotSliders, AlwaysAvailable, "Set plot slider display"}, {NULL, NULL, NULL, NULL} }; @@ -1009,6 +1121,8 @@ static int CmdPrefShow(const char *Cmd) { showClientDebugState(prefShowNone); showPlotSliderState(prefShowNone); // showDeviceDebugState(prefShowNone); + + showBarModeState(prefShowNone); PrintAndLogEx(NORMAL, ""); return PM3_SUCCESS; } diff --git a/client/src/ui.c b/client/src/ui.c index 6e8c73c27..03ff304b2 100644 --- a/client/src/ui.c +++ b/client/src/ui.c @@ -624,4 +624,69 @@ void iceSimple_Filter(int *data, const size_t len, uint8_t k) { } } +void print_progress(size_t count, uint64_t max, barMode_t style) { + #define PERCENTAGE(V, T) (100 - (((T - V) * 100) / T)) + +/* + typedef struct smooth_s { + const char *bar; + } smooth_t; + + static smooth_t smoothtable[] = { + {"\xe2\x96\x8F"}, + {"\xe2\x96\x8E"}, + {"\xe2\x96\x8D"}, + {"\xe2\x96\x8C"}, + {"\xe2\x96\x8B"}, + {"\xe2\x96\x8A"}, + {"\xe2\x96\x89"}, + {"\xe2\x96\x88"}, + }; +*/ + + // +1 for \0 + char *bar = calloc(100 + 1, sizeof(uint8_t)); + + uint8_t value = PERCENTAGE(count, max); + + // prefix is added already. + memset(bar + strlen(bar), 0x23, value); + + // add spaces + memset(bar + strlen(bar), 0x2E, 100 - value); + + // color buffer + uint8_t collen = 100 + 1 + 40; + char *cbar = calloc(collen, sizeof(uint8_t)); + + // Add colors + snprintf(cbar, collen, _GREEN_("%.*s"), 60, bar); + snprintf(cbar + strlen(cbar), collen - strlen(cbar), _CYAN_("%.*s"), 20, bar + 60); + snprintf(cbar + strlen(cbar), collen - strlen(cbar), _YELLOW_("%.*s"), 20, bar + 80); + + uint8_t len = collen + 1 + 1 + 30; + char *buffer = calloc(len, sizeof(uint8_t)); + + switch(style) { + case STYLE_BAR: { + sprintf(buffer, "%s", cbar); + printf("\b%c[2K\r[" _YELLOW_("=")"] %s", 27, buffer); + break; + } + case STYLE_MIXED: { + sprintf(buffer, "%s [ %zu mV / %3u V ]", cbar, count, (uint32_t)(count / 1000)); + printf("\b%c[2K\r[" _YELLOW_("=")"] %s ", 27, buffer); + break; + } + case STYLE_VALUE: { + printf("[" _YELLOW_("=")"] %zu mV / %3u V \r", count, (uint32_t)(count / 1000)); + break; + } + } + + fflush(stdout); + free(buffer); + free(bar); + free(cbar); +} diff --git a/client/src/ui.h b/client/src/ui.h index 1a8a14028..30d055b16 100644 --- a/client/src/ui.h +++ b/client/src/ui.h @@ -22,6 +22,7 @@ extern "C" { #define _USE_MATH_DEFINES +typedef enum {STYLE_BAR, STYLE_MIXED, STYLE_VALUE} barMode_t; typedef enum logLevel {NORMAL, SUCCESS, INFO, FAILED, WARNING, ERR, DEBUG, INPLACE, HINT} logLevel_t; typedef enum emojiMode {ALIAS, EMOJI, ALTTEXT, ERASE} emojiMode_t; typedef enum clientdebugLevel {cdbOFF, cdbSIMPLE, cdbFULL} clientdebugLevel_t; @@ -45,6 +46,7 @@ typedef struct { bool incognito; // char *defaultPaths[spItemCount]; // Array should allow loop searching for files clientdebugLevel_t client_debug_level; + barMode_t bar_mode; // uint8_t device_debug_level; char *history_path; pm3_device *current_device; @@ -69,6 +71,8 @@ int searchHomeFilePath(char **foundpath, const char *subdir, const char *filenam extern pthread_mutex_t print_lock; +void print_progress(size_t count, uint64_t max, barMode_t style); + void iceIIR_Butterworth(int *data, const size_t len); void iceSimple_Filter(int *data, const size_t len, uint8_t k); #ifdef __cplusplus diff --git a/client/src/util.h b/client/src/util.h index 66b72491f..573997d61 100644 --- a/client/src/util.h +++ b/client/src/util.h @@ -108,4 +108,5 @@ uint32_t bitcount32(uint32_t a); uint64_t bitcount64(uint64_t a); uint32_t leadingzeros32(uint32_t a); uint64_t leadingzeros64(uint64_t a); + #endif From 246ee8b2d7d1c0056ba26cd4df1553c3d5cc97e4 Mon Sep 17 00:00:00 2001 From: iceman1001 Date: Mon, 21 Dec 2020 02:06:43 +0100 Subject: [PATCH 160/682] hf tune - now uses the barmode --- client/src/cmdhf.c | 115 +++++++++++++++++++++++++-------------- client/src/cmdlf.c | 7 ++- client/src/preferences.c | 8 +-- 3 files changed, 81 insertions(+), 49 deletions(-) diff --git a/client/src/cmdhf.c b/client/src/cmdhf.c index 94985579e..41f3d0814 100644 --- a/client/src/cmdhf.c +++ b/client/src/cmdhf.c @@ -14,9 +14,8 @@ #include "cmdhf.h" #include // tolower - #include "cmdparser.h" // command_t -#include "cliparser.h" // parse +#include "cliparser.h" // parse #include "comms.h" // clearCommandBuffer #include "lfdemod.h" // computeSignalProperties #include "cmdhf14a.h" // ISO14443-A @@ -57,36 +56,6 @@ static int usage_hf_search(void) { return PM3_SUCCESS; } -static int usage_hf_sniff(void) { - PrintAndLogEx(NORMAL, "The high frequency sniffer will assign all available memory on device for sniffed data"); - PrintAndLogEx(NORMAL, "Use " _YELLOW_("'data samples'")" command to download from device, and " _YELLOW_("'data plot'")" to look at it"); - PrintAndLogEx(NORMAL, "Press button to quit the sniffing.\n"); - PrintAndLogEx(NORMAL, "Usage: hf sniff "); - PrintAndLogEx(NORMAL, "Options:"); - PrintAndLogEx(NORMAL, " h - This help"); - PrintAndLogEx(NORMAL, " - skip sample pairs"); - PrintAndLogEx(NORMAL, " - skip number of triggers"); - PrintAndLogEx(NORMAL, ""); - PrintAndLogEx(NORMAL, "Examples:"); - PrintAndLogEx(NORMAL, _YELLOW_(" hf sniff")); - PrintAndLogEx(NORMAL, _YELLOW_(" hf sniff 1000 0")); - PrintAndLogEx(NORMAL, ""); - return PM3_SUCCESS; -} - -static int usage_hf_tune(void) { - PrintAndLogEx(NORMAL, "Continuously measure HF antenna tuning."); - PrintAndLogEx(NORMAL, "Press button or `enter` to interrupt."); - PrintAndLogEx(NORMAL, "Usage: hf tune [h] []"); - PrintAndLogEx(NORMAL, "Options:"); - PrintAndLogEx(NORMAL, " h - This help"); - PrintAndLogEx(NORMAL, " - number of iterations (default: 0=infinite)"); - PrintAndLogEx(NORMAL, "Examples:"); - PrintAndLogEx(NORMAL, _YELLOW_(" hf tune 1")); - PrintAndLogEx(NORMAL, ""); - return PM3_SUCCESS; -} - int CmdHFSearch(const char *Cmd) { char cmdp = tolower(param_getchar(Cmd, 0)); @@ -199,9 +168,42 @@ int CmdHFSearch(const char *Cmd) { } int CmdHFTune(const char *Cmd) { - char cmdp = tolower(param_getchar(Cmd, 0)); - if (cmdp == 'h') return usage_hf_tune(); - int iter = param_get32ex(Cmd, 0, 0, 10); + + CLIParserContext *ctx; + CLIParserInit(&ctx, "hf tune", + "Continuously measure HF antenna tuning.\n" + "Press button or to interrupt.", + "hf tune\n" + "hf tune --mixed" + ); + + void *argtable[] = { + arg_param_begin, + arg_u64_0("n", "iter", "", "number of iterations (default: 0=infinite)"), + arg_lit0(NULL, "bar", "bar style"), + arg_lit0(NULL, "mix", "mixed style"), + arg_lit0(NULL, "value", "values style"), + arg_param_end + }; + CLIExecWithReturn(ctx, Cmd, argtable, true); + uint32_t iter = arg_get_u32_def(ctx, 1, 0); + bool is_bar = arg_get_lit(ctx, 2); + bool is_mix = arg_get_lit(ctx, 3); + bool is_value = arg_get_lit(ctx, 4); + CLIParserFree(ctx); + + if ((is_bar + is_mix + is_value) > 1) { + PrintAndLogEx(ERR, "Select only one output style"); + return PM3_EINVARG; + } + + barMode_t style = session.bar_mode; + if (is_bar) + style = STYLE_BAR; + if (is_mix) + style = STYLE_MIXED; + if (is_value) + style = STYLE_VALUE; PrintAndLogEx(INFO, "Measuring HF antenna, click " _GREEN_("pm3 button") " or press " _GREEN_("Enter") " to exit"); PacketResponseNG resp; @@ -215,6 +217,12 @@ int CmdHFTune(const char *Cmd) { } mode[0] = 2; + + uint32_t max = 0xFFFF; + bool first = true; + + print_progress(0, max, style); + // loop forever (till button pressed) if iter = 0 (default) for (uint8_t i = 0; iter == 0 || i < iter; i++) { if (kbd_enter_pressed()) { @@ -225,15 +233,23 @@ int CmdHFTune(const char *Cmd) { if (!WaitForResponseTimeout(CMD_MEASURE_ANTENNA_TUNING_HF, &resp, 1000)) { PrintAndLogEx(NORMAL, ""); PrintAndLogEx(WARNING, "Timeout while waiting for Proxmark HF measure, aborting"); - return PM3_ETIMEOUT; + break; } if ((resp.status == PM3_EOPABORTED) || (resp.length != sizeof(uint16_t))) { + PrintAndLogEx(NORMAL, ""); break; } uint16_t volt = resp.data.asDwords[0] & 0xFFFF; - PrintAndLogEx(INPLACE, " %u mV / %2u V", volt, (uint16_t)(volt / 1000)); + if (first) { + max = (volt * 1.03); + first = false; + } + if ( volt > max) { + max = (volt * 1.03); + } + print_progress(volt, max, style); } mode[0] = 3; @@ -242,7 +258,7 @@ int CmdHFTune(const char *Cmd) { PrintAndLogEx(WARNING, "Timeout while waiting for Proxmark HF shutdown, aborting"); return PM3_ETIMEOUT; } - PrintAndLogEx(NORMAL, ""); + PrintAndLogEx(NORMAL, "\x1b%c[2K\r", 30); PrintAndLogEx(INFO, "Done."); return PM3_SUCCESS; } @@ -252,16 +268,31 @@ int CmdHFTune(const char *Cmd) { // Takes all available bigbuff memory // data sample to download? Not sure what we can do with the data. int CmdHFSniff(const char *Cmd) { - char cmdp = tolower(param_getchar(Cmd, 0)); - if (cmdp == 'h') return usage_hf_sniff(); + + CLIParserContext *ctx; + CLIParserInit(&ctx, "hf sniff", + "The high frequency sniffer will assign all available memory on device for sniffed data.s\n" + "Use `data samples` to download from device and `data plot` to visualize it.\n" + "Press button to quit the sniffing.", + "hf sniff\n" + "hf sniff --sp 1000 --st 0 -> skip 1000 pairs, skip 0 triggers" + ); + void *argtable[] = { + arg_param_begin, + arg_u64_0(NULL, "sp", "", "skip sample pairs"), + arg_u64_0(NULL, "st", "", "skip number of triggers"), + arg_param_end + }; + CLIExecWithReturn(ctx, Cmd, argtable, true); struct { uint32_t samplesToSkip; uint32_t triggersToSkip; } PACKED params; - params.samplesToSkip = param_get32ex(Cmd, 0, 0, 10); - params.triggersToSkip = param_get32ex(Cmd, 1, 0, 10); + params.samplesToSkip = arg_get_u32_def(ctx, 1, 0); + params.triggersToSkip = arg_get_u32_def(ctx, 2, 0); + CLIParserFree(ctx); clearCommandBuffer(); SendCommandNG(CMD_HF_SNIFF, (uint8_t *)¶ms, sizeof(params)); diff --git a/client/src/cmdlf.c b/client/src/cmdlf.c index 4cc303f19..bd99f648e 100644 --- a/client/src/cmdlf.c +++ b/client/src/cmdlf.c @@ -237,14 +237,15 @@ static int CmdLFTune(const char *Cmd) { CLIParserInit(&ctx, "lf tune", "Continuously measure LF antenna tuning.\n" "Press button or to interrupt.", - "lf tune" + "lf tune\n" + "lf tune --mixed" ); char q_str[60]; snprintf(q_str, sizeof(q_str), "Frequency divisor. %d -> 134 kHz, %d -> 125 kHz", LF_DIVISOR_134, LF_DIVISOR_125); void *argtable[] = { arg_param_begin, - arg_u64_0("n", "iteration", "", "number of iterations (default: 0=infinite)"), + arg_u64_0("n", "iter", "", "number of iterations (default: 0=infinite)"), arg_u64_0("q", "divisor", "", q_str), arg_dbl0("f", "freq", "", "Frequency in kHz"), arg_lit0(NULL, "bar", "bar style"), @@ -301,7 +302,7 @@ static int CmdLFTune(const char *Cmd) { params[0] = 2; - #define MAX_ADC_LF_VOLTAGE 140800 +// #define MAX_ADC_LF_VOLTAGE 140800 uint32_t max = 71000; bool first = true; diff --git a/client/src/preferences.c b/client/src/preferences.c index b6b1eddd3..c80e24e3a 100644 --- a/client/src/preferences.c +++ b/client/src/preferences.c @@ -561,16 +561,16 @@ static void showBarModeState(prefShowOpt_t opt) { switch (session.bar_mode) { case STYLE_BAR: - PrintAndLogEx(INFO, " %s mode................... "_GREEN_("bar"), prefShowMsg(opt)); + PrintAndLogEx(INFO, " %s barmode................ "_GREEN_("bar"), prefShowMsg(opt)); break; case STYLE_MIXED: - PrintAndLogEx(INFO, " %s mode................... "_GREEN_("mixed"), prefShowMsg(opt)); + PrintAndLogEx(INFO, " %s barmode................ "_GREEN_("mixed"), prefShowMsg(opt)); break; case STYLE_VALUE: - PrintAndLogEx(INFO, " %s mode................... "_GREEN_("value"), prefShowMsg(opt)); + PrintAndLogEx(INFO, " %s barmode................ "_GREEN_("value"), prefShowMsg(opt)); break; default: - PrintAndLogEx(INFO, " %s mode.................. "_RED_("unknown"), prefShowMsg(opt)); + PrintAndLogEx(INFO, " %s barmode............... "_RED_("unknown"), prefShowMsg(opt)); } } From 8bb7e4ed8b23fd36199f88c6037c719eeb1d06f3 Mon Sep 17 00:00:00 2001 From: iceman1001 Date: Mon, 21 Dec 2020 02:40:04 +0100 Subject: [PATCH 161/682] hf xxx - uses cliparser and textual --- client/src/cmdhf.c | 26 ++++++++++++-------------- 1 file changed, 12 insertions(+), 14 deletions(-) diff --git a/client/src/cmdhf.c b/client/src/cmdhf.c index 41f3d0814..637d6637c 100644 --- a/client/src/cmdhf.c +++ b/client/src/cmdhf.c @@ -46,21 +46,19 @@ static int CmdHelp(const char *Cmd); -static int usage_hf_search(void) { - PrintAndLogEx(NORMAL, "Usage: hf search"); - PrintAndLogEx(NORMAL, "Will try to find a HF read out of the unknown tag."); - PrintAndLogEx(NORMAL, "Continues to search for all different HF protocols"); - PrintAndLogEx(NORMAL, "Options:"); - PrintAndLogEx(NORMAL, " h - This help"); - PrintAndLogEx(NORMAL, ""); - return PM3_SUCCESS; -} - int CmdHFSearch(const char *Cmd) { - char cmdp = tolower(param_getchar(Cmd, 0)); - if (cmdp == 'h') return usage_hf_search(); - + CLIParserContext *ctx; + CLIParserInit(&ctx, "hf search", + "Will try to find a HF read out of the unknown tag.\n" + "Continues to search for all different HF protocols.", + "hf sniff" + ); + void *argtable[] = { + arg_param_begin, + arg_param_end + }; + CLIExecWithReturn(ctx, Cmd, argtable, true); int res = PM3_ESOFT; PROMPT_CLEARLINE; @@ -271,7 +269,7 @@ int CmdHFSniff(const char *Cmd) { CLIParserContext *ctx; CLIParserInit(&ctx, "hf sniff", - "The high frequency sniffer will assign all available memory on device for sniffed data.s\n" + "The high frequency sniffer will assign all available memory on device for sniffed data.\n" "Use `data samples` to download from device and `data plot` to visualize it.\n" "Press button to quit the sniffing.", "hf sniff\n" From 0c41b4b260b2308dacb181b945aa43b9446d64f2 Mon Sep 17 00:00:00 2001 From: iceman1001 Date: Mon, 21 Dec 2020 02:41:29 +0100 Subject: [PATCH 162/682] text --- doc/cliparser_todo.txt | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/doc/cliparser_todo.txt b/doc/cliparser_todo.txt index b2571f493..6b4b7d01a 100644 --- a/doc/cliparser_todo.txt +++ b/doc/cliparser_todo.txt @@ -10,7 +10,6 @@ analyse a analyse nuid analyse demodbuff analyse freq -analyse foo data biphaserawdecode data detectclock data fsktonrz @@ -42,9 +41,6 @@ data print data samples data setdebugmode data tune -hf tune -hf search -hf sniff hf 14a reader hf 14a cuids hf 14a sim @@ -167,14 +163,12 @@ lf simfsk lf simpsk lf simbidir lf sniff -lf tune lf em 410x lf em 4x05 lf em 4x50 -lf hitag info +lf em 4x70 lf hitag reader lf hitag sim -lf hitag sniff lf hitag writer lf hitag dump lf hitag cc From b407d921a91911bce91103a8cdf2f99b1a1f94d5 Mon Sep 17 00:00:00 2001 From: tcprst Date: Sun, 20 Dec 2020 20:52:49 -0500 Subject: [PATCH 163/682] hf legic rdbl - now use cliparser --- client/src/cmdhflegic.c | 71 ++++++++++++++++------------------------- doc/cliparser_todo.txt | 1 - 2 files changed, 27 insertions(+), 45 deletions(-) diff --git a/client/src/cmdhflegic.c b/client/src/cmdhflegic.c index b202ba170..bd63057ce 100644 --- a/client/src/cmdhflegic.c +++ b/client/src/cmdhflegic.c @@ -28,21 +28,6 @@ static int CmdHelp(const char *Cmd); #define MAX_LENGTH 1024 -static int usage_legic_rdbl(void) { - PrintAndLogEx(NORMAL, "Read data from a LEGIC Prime tag\n"); - PrintAndLogEx(NORMAL, "Usage: hf legic rdbl [h] [o ] [l ] [iv ]\n"); - PrintAndLogEx(NORMAL, "Options:"); - PrintAndLogEx(NORMAL, " h : this help"); - PrintAndLogEx(NORMAL, " o : (hex) offset in data array to start download from"); - PrintAndLogEx(NORMAL, " l : (hex) number of bytes to read"); - PrintAndLogEx(NORMAL, " i : (hex) (optional) Initialization vector to use. Must be odd and 7bits max"); - PrintAndLogEx(NORMAL, ""); - PrintAndLogEx(NORMAL, "Examples:"); - PrintAndLogEx(NORMAL, _YELLOW_(" hf legic rdbl o 0 l 16 - reads from byte[0] 0x16 bytes(system header)")); - PrintAndLogEx(NORMAL, _YELLOW_(" hf legic rdbl o 0 l 4 iv 55 - reads from byte[0] 0x4 bytes with IV 0x55")); - PrintAndLogEx(NORMAL, _YELLOW_(" hf legic rdbl o 0 l 100 iv 55 - reads 0x100 bytes with IV 0x55")); - return PM3_SUCCESS; -} static int usage_legic_sim(void) { PrintAndLogEx(NORMAL, "Simulates a LEGIC Prime tag. MIM22, MIM256, MIM1024 types can be emulated"); PrintAndLogEx(NORMAL, "Use " _YELLOW_("`hf legic eload`") " to upload a dump into emulator memory\n"); @@ -512,34 +497,32 @@ out: // offset in data memory // number of bytes to read static int CmdLegicRdbl(const char *Cmd) { + CLIParserContext *ctx; + CLIParserInit(&ctx, "hf legic rdbl", + "Read data from a LEGIC Prime tag", + "hf legic rdbl -o 0 -l 16 <- reads from byte[0] 16 bytes(system header)\n" + "hf legic rdbl -o 0 -l 4 --iv 55 <- reads from byte[0] 4 bytes with IV 0x55\n" + "hf legic rdbl -o 0 -l 256 --iv 55 <- reads from byte[0] 256 bytes with IV 0x55"); - uint32_t offset = 0, len = 0, iv = 1; - bool errors = false; - uint8_t cmdp = 0; - while (param_getchar(Cmd, cmdp) != 0x00 && !errors) { - switch (tolower(param_getchar(Cmd, cmdp))) { - case 'h' : - return usage_legic_rdbl(); - case 'o' : - offset = param_get32ex(Cmd, cmdp + 1, 0, 16); - cmdp += 2; - break; - case 'l' : - len = param_get32ex(Cmd, cmdp + 1, 0, 16); - cmdp += 2; - break; - case 'i' : - iv = param_get32ex(Cmd, cmdp + 1, 1, 16); - cmdp += 2; - break; - default : - PrintAndLogEx(WARNING, "Unknown parameter '%c'", param_getchar(Cmd, cmdp)); - errors = true; - break; - } - } - //Validations - if (errors || strlen(Cmd) == 0) return usage_legic_rdbl(); + void *argtable[] = { + arg_param_begin, + arg_int1("o", "offset", "", "offset in data array to start download from"), + arg_int1("l", "length", "", "number of bytes to read"), + arg_str0(NULL, "iv", "", "Initialization vector to use. Must be odd and 7bits max"), + arg_param_end + }; + CLIExecWithReturn(ctx, Cmd, argtable, false); + + int offset = arg_get_int_def(ctx, 1, 0); + + int len = arg_get_int_def(ctx, 2, 0); + + int iv_len = 0; + uint8_t iv[1] = {0x01}; // formerly uidcrc + + CLIGetHexWithReturn(ctx, 3, iv, &iv_len); + + CLIParserFree(ctx); // sanity checks if (len + offset >= MAX_LENGTH) { @@ -557,9 +540,9 @@ static int CmdLegicRdbl(const char *Cmd) { } uint16_t datalen = 0; - int status = legic_read_mem(offset, len, iv, data, &datalen); + int status = legic_read_mem(offset, len, iv[0], data, &datalen); if (status == PM3_SUCCESS) { - PrintAndLogEx(NORMAL, "\n ## | 0 1 2 3 4 5 6 7 8 9 A B C D E F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F"); + PrintAndLogEx(NORMAL, " ## | 0 1 2 3 4 5 6 7 8 9 A B C D E F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F"); PrintAndLogEx(NORMAL, "-----+------------------------------------------------------------------------------------------------"); print_hex_break(data, datalen, 32); } diff --git a/doc/cliparser_todo.txt b/doc/cliparser_todo.txt index 6e06c5278..c8a21d606 100644 --- a/doc/cliparser_todo.txt +++ b/doc/cliparser_todo.txt @@ -82,7 +82,6 @@ hf legic reader hf legic info hf legic dump hf legic restore -hf legic rdbl hf legic sim hf legic wrbl hf legic eload From b676efd992e1aa8de5f8551d4b6b756460419523 Mon Sep 17 00:00:00 2001 From: tcprst Date: Sun, 20 Dec 2020 21:00:24 -0500 Subject: [PATCH 164/682] hf legic sim - now use cliparser --- client/src/cmdhflegic.c | 36 ++++++++++++++++++------------------ doc/cliparser_todo.txt | 1 - 2 files changed, 18 insertions(+), 19 deletions(-) diff --git a/client/src/cmdhflegic.c b/client/src/cmdhflegic.c index bd63057ce..b9f34d362 100644 --- a/client/src/cmdhflegic.c +++ b/client/src/cmdhflegic.c @@ -28,20 +28,6 @@ static int CmdHelp(const char *Cmd); #define MAX_LENGTH 1024 -static int usage_legic_sim(void) { - PrintAndLogEx(NORMAL, "Simulates a LEGIC Prime tag. MIM22, MIM256, MIM1024 types can be emulated"); - PrintAndLogEx(NORMAL, "Use " _YELLOW_("`hf legic eload`") " to upload a dump into emulator memory\n"); - PrintAndLogEx(NORMAL, "Usage: hf legic sim [h] \n"); - PrintAndLogEx(NORMAL, "Options:"); - PrintAndLogEx(NORMAL, " h : this help"); - PrintAndLogEx(NORMAL, " : 0 = MIM22"); - PrintAndLogEx(NORMAL, " : 1 = MIM256 (default)"); - PrintAndLogEx(NORMAL, " : 2 = MIM1024"); - PrintAndLogEx(NORMAL, ""); - PrintAndLogEx(NORMAL, "Examples:"); - PrintAndLogEx(NORMAL, _YELLOW_(" hf legic sim 2")); - return PM3_SUCCESS; -} static int usage_legic_wrbl(void) { PrintAndLogEx(NORMAL, "Write data to a LEGIC Prime tag. It autodetects tagsize to make sure size\n"); PrintAndLogEx(NORMAL, "Usage: hf legic wrbl [h] [o ] [d ] [y]\n"); @@ -551,9 +537,19 @@ static int CmdLegicRdbl(const char *Cmd) { } static int CmdLegicSim(const char *Cmd) { + CLIParserContext *ctx; + CLIParserInit(&ctx, "hf legic sim", + "Simulates a LEGIC Prime tag. MIM22, MIM256, MIM1024 types can be emulated", + "hf legic sim -t 0 <- Simulate Type MIM22\n" + "hf legic sim -t 1 <- Simulate Type MIM256 (default)\n" + "hf legic sim -t 2 <- Simulate Type MIM1024"); - char cmdp = tolower(param_getchar(Cmd, 0)); - if (strlen(Cmd) == 0 || cmdp == 'h') return usage_legic_sim(); + void *argtable[] = { + arg_param_begin, + arg_int0("t", "type", "", "Tag type to simulate."), + arg_param_end + }; + CLIExecWithReturn(ctx, Cmd, argtable, true); struct { uint8_t tagtype; @@ -561,9 +557,13 @@ static int CmdLegicSim(const char *Cmd) { } PACKED payload; payload.send_reply = true; - payload.tagtype = param_get8ex(Cmd, 0, 1, 10); + payload.tagtype = arg_get_int_def(ctx, 1, 1); + + CLIParserFree(ctx); + if (payload.tagtype > 2) { - return usage_legic_sim(); + PrintAndLogEx(ERR, "Invalid tag type selected."); + return PM3_EINVARG; } clearCommandBuffer(); diff --git a/doc/cliparser_todo.txt b/doc/cliparser_todo.txt index c8a21d606..274dfe81e 100644 --- a/doc/cliparser_todo.txt +++ b/doc/cliparser_todo.txt @@ -82,7 +82,6 @@ hf legic reader hf legic info hf legic dump hf legic restore -hf legic sim hf legic wrbl hf legic eload hf legic esave From 03edf439d2025dc4dc1978b37ef4358e265b482e Mon Sep 17 00:00:00 2001 From: tcprst Date: Sun, 20 Dec 2020 21:16:46 -0500 Subject: [PATCH 165/682] hf legic wrbl - now use cliparser --- client/luascripts/hf_legic.lua | 4 +- client/src/cmdhflegic.c | 117 +++++++-------------------------- doc/cliparser_todo.txt | 1 - 3 files changed, 25 insertions(+), 97 deletions(-) diff --git a/client/luascripts/hf_legic.lua b/client/luascripts/hf_legic.lua index 1715bf400..744372f83 100644 --- a/client/luascripts/hf_legic.lua +++ b/client/luascripts/hf_legic.lua @@ -582,14 +582,14 @@ function writeToTag(tag) -- write pm3-buffer to Tag for i=1, WriteBytes do if (i > 7) then - cmd = ("hf legic wrbl o %02x d %s "):format(i-1, padString(bytes[i])) + cmd = ("hf legic wrbl -o %d -d %s "):format(i-1, padString(bytes[i])) print(acgreen..cmd..acoff) core.console(cmd) core.clearCommandBuffer() elseif (i == 7) then if (writeDCF) then -- write DCF in reverse order (requires 'mosci-patch') - cmd = ('hf legic wrbl o 05 d %s%s'):format(padString(bytes[i-1]), padString(bytes[i])) + cmd = ('hf legic wrbl -o 5 -d %s%s'):format(padString(bytes[i-1]), padString(bytes[i])) print(acgreen..cmd..acoff) core.console(cmd) core.clearCommandBuffer() diff --git a/client/src/cmdhflegic.c b/client/src/cmdhflegic.c index b9f34d362..a09946d43 100644 --- a/client/src/cmdhflegic.c +++ b/client/src/cmdhflegic.c @@ -28,20 +28,6 @@ static int CmdHelp(const char *Cmd); #define MAX_LENGTH 1024 -static int usage_legic_wrbl(void) { - PrintAndLogEx(NORMAL, "Write data to a LEGIC Prime tag. It autodetects tagsize to make sure size\n"); - PrintAndLogEx(NORMAL, "Usage: hf legic wrbl [h] [o ] [d ] [y]\n"); - PrintAndLogEx(NORMAL, "Options:"); - PrintAndLogEx(NORMAL, " h : this help"); - PrintAndLogEx(NORMAL, " o : (hex) offset in data array to start writing"); - //PrintAndLogEx(NORMAL, " : (optional) Initialization vector to use (ODD and 7bits)"); - PrintAndLogEx(NORMAL, " d : (hex symbols) bytes to write "); - PrintAndLogEx(NORMAL, " y : Auto-confirm dangerous operations "); - PrintAndLogEx(NORMAL, ""); - PrintAndLogEx(NORMAL, "Examples:"); - PrintAndLogEx(NORMAL, _YELLOW_(" hf legic wrbl o 10 d 11223344 - Write 0x11223344 starting from offset 0x10")); - return PM3_SUCCESS; -} static int usage_legic_reader(void) { PrintAndLogEx(NORMAL, "Read UID and type information from a LEGIC Prime tag\n"); PrintAndLogEx(NORMAL, "Usage: hf legic reader [h]\n"); @@ -588,94 +574,37 @@ static int CmdLegicSim(const char *Cmd) { } static int CmdLegicWrbl(const char *Cmd) { + CLIParserContext *ctx; + CLIParserInit(&ctx, "hf legic wrbl", + "Write data to a LEGIC Prime tag. It autodetects tagsize to ensure proper write", + "hf legic wrbl -o 0 -d 11223344 <- Write 0x11223344 starting from offset 0)\n" + "hf legic wrbl -o 10 -d DEADBEEF <- Write 0xdeadbeef starting from offset 10"); - uint8_t *data = NULL; - uint8_t cmdp = 0; - bool errors = false; - bool autoconfirm = false; - int len = 0, bg, en; - uint32_t offset = 0, IV = 0x55; + void *argtable[] = { + arg_param_begin, + arg_int1("o", "offset", "", "offset in data array to start writing"), + arg_str1("d", "data", "", "data to write"), + arg_lit0(NULL, "danger", "Auto-confirm dangerous operations"), + arg_param_end + }; + CLIExecWithReturn(ctx, Cmd, argtable, false); - while (param_getchar(Cmd, cmdp) != 0x00 && !errors) { - switch (tolower(param_getchar(Cmd, cmdp))) { - case 'h': { - errors = true; - break; - } - case 'd': { - // peek at length of the input string so we can - // figure out how many elements to malloc in "data" - bg = en = 0; - if (param_getptr(Cmd, &bg, &en, cmdp + 1)) { - errors = true; - break; - } - len = (en - bg + 1); + int offset = arg_get_int_def(ctx, 1, 0); - // check that user entered even number of characters - // for hex data string - if (len & 1) { - errors = true; - break; - } + int data_len = 0; + uint8_t data[MAX_LENGTH] = {0}; - // limit number of bytes to write. This is not a 'restore' command. - if ((len >> 1) > 100) { - PrintAndLogEx(WARNING, "Max bound on 100bytes to write a one time."); - PrintAndLogEx(WARNING, "Use the 'hf legic restore' command if you want to write the whole tag at once"); - errors = true; - } + CLIGetHexWithReturn(ctx, 2, data, &data_len); - // it's possible for user to accidentally enter "b" parameter - // more than once - we have to clean previous malloc - if (data) - free(data); + bool autoconfirm = arg_get_lit(ctx, 3); - data = calloc(len >> 1, sizeof(uint8_t)); - if (data == NULL) { - PrintAndLogEx(WARNING, "Can't allocate memory. exiting"); - errors = true; - break; - } + CLIParserFree(ctx); - if (param_gethex(Cmd, cmdp + 1, data, len)) { - errors = true; - break; - } - - len >>= 1; - cmdp += 2; - break; - } - case 'o': { - offset = param_get32ex(Cmd, cmdp + 1, 4, 16); - cmdp += 2; - break; - } - case 'y': { - autoconfirm = true; - break; - } - default: { - PrintAndLogEx(WARNING, "Unknown parameter '%c'", param_getchar(Cmd, cmdp)); - errors = true; - break; - } - } - } - - //Validations - if (errors || cmdp == 0) { - if (data) - free(data); - return usage_legic_wrbl(); - } + uint32_t IV = 0x55; // OUT-OF-BOUNDS checks // UID 4+1 bytes can't be written to. if (offset < 5) { - if (data) - free(data); PrintAndLogEx(WARNING, "Out-of-bounds, bytes 0-1-2-3-4 can't be written to. Offset = %d", offset); return PM3_EOUTOFBOUND; } @@ -689,8 +618,8 @@ static int CmdLegicWrbl(const char *Cmd) { legic_print_type(card.cardsize, 0); - if (len + offset > card.cardsize) { - PrintAndLogEx(WARNING, "Out-of-bounds, Cardsize = %d, [offset+len = %d ]", card.cardsize, len + offset); + if (data_len + offset > card.cardsize) { + PrintAndLogEx(WARNING, "Out-of-bounds, Cardsize = %d, [offset+len = %d ]", card.cardsize, data_len + offset); return PM3_EOUTOFBOUND; } @@ -725,7 +654,7 @@ static int CmdLegicWrbl(const char *Cmd) { PacketResponseNG resp; clearCommandBuffer(); - SendCommandOLD(CMD_HF_LEGIC_WRITER, offset, len, IV, data, len); + SendCommandOLD(CMD_HF_LEGIC_WRITER, offset, data_len, IV, data, data_len); uint8_t timeout = 0; while (!WaitForResponseTimeout(CMD_ACK, &resp, 2000)) { diff --git a/doc/cliparser_todo.txt b/doc/cliparser_todo.txt index 274dfe81e..d181f93e6 100644 --- a/doc/cliparser_todo.txt +++ b/doc/cliparser_todo.txt @@ -82,7 +82,6 @@ hf legic reader hf legic info hf legic dump hf legic restore -hf legic wrbl hf legic eload hf legic esave hf legic wipe From a51c45168e8489a44ac558c74c4f6ebdc7f73ae2 Mon Sep 17 00:00:00 2001 From: tcprst Date: Sun, 20 Dec 2020 21:20:47 -0500 Subject: [PATCH 166/682] hf legic info - now use cliparser --- client/src/cmdhflegic.c | 21 +++++++++------------ doc/cliparser_todo.txt | 1 - 2 files changed, 9 insertions(+), 13 deletions(-) diff --git a/client/src/cmdhflegic.c b/client/src/cmdhflegic.c index a09946d43..d53c68e5e 100644 --- a/client/src/cmdhflegic.c +++ b/client/src/cmdhflegic.c @@ -38,16 +38,6 @@ static int usage_legic_reader(void) { PrintAndLogEx(NORMAL, _YELLOW_(" hf legic reader")); return PM3_SUCCESS; } -static int usage_legic_info(void) { - PrintAndLogEx(NORMAL, "Reads information from a LEGIC Prime tag like systemarea, user areas etc\n"); - PrintAndLogEx(NORMAL, "Usage: hf legic info [h]\n"); - PrintAndLogEx(NORMAL, "Options:"); - PrintAndLogEx(NORMAL, " h : this help"); - PrintAndLogEx(NORMAL, ""); - PrintAndLogEx(NORMAL, "Examples:"); - PrintAndLogEx(NORMAL, _YELLOW_(" hf legic info")); - return PM3_SUCCESS; -} static int usage_legic_dump(void) { PrintAndLogEx(NORMAL, "Read all memory from LEGIC Prime MIM22, MIM256, MIM1024"); PrintAndLogEx(NORMAL, "and saves bin/eml/json dump file"); @@ -146,9 +136,16 @@ static bool legic_xor(uint8_t *data, uint16_t cardsize) { * by Henryk Ploetz and Karsten Nohl at 26c3 */ static int CmdLegicInfo(const char *Cmd) { + CLIParserContext *ctx; + CLIParserInit(&ctx, "hf legic info", + "Gets information from a LEGIC Prime tag like systemarea, user areas, etc", + "hf legic info"); - char cmdp = tolower(param_getchar(Cmd, 0)); - if (cmdp == 'h') return usage_legic_info(); + void *argtable[] = { + arg_param_begin, + arg_param_end + }; + CLIExecWithReturn(ctx, Cmd, argtable, true); int i = 0, k = 0, segmentNum = 0, segment_len = 0, segment_flag = 0; int crc = 0, wrp = 0, wrc = 0; diff --git a/doc/cliparser_todo.txt b/doc/cliparser_todo.txt index d181f93e6..212029e2c 100644 --- a/doc/cliparser_todo.txt +++ b/doc/cliparser_todo.txt @@ -79,7 +79,6 @@ hf felica litesim hf felica litedump hf fido info hf legic reader -hf legic info hf legic dump hf legic restore hf legic eload From 7f740c4e3d5b50898aa468081375e84664e2275d Mon Sep 17 00:00:00 2001 From: tcprst Date: Sun, 20 Dec 2020 21:40:06 -0500 Subject: [PATCH 167/682] hf legic reader - continuous mode and cliparser --- client/src/cmdhf.c | 2 +- client/src/cmdhflegic.c | 83 +++++++++++++++++++++++++---------------- client/src/cmdhflegic.h | 2 +- doc/cliparser_todo.txt | 1 - 4 files changed, 53 insertions(+), 35 deletions(-) diff --git a/client/src/cmdhf.c b/client/src/cmdhf.c index 41f3d0814..4df232637 100644 --- a/client/src/cmdhf.c +++ b/client/src/cmdhf.c @@ -111,7 +111,7 @@ int CmdHFSearch(const char *Cmd) { PROMPT_CLEARLINE; PrintAndLogEx(INPLACE, " Searching for LEGIC tag..."); if (IfPm3Legicrf()) { - if (readLegicUid(false) == PM3_SUCCESS) { + if (readLegicUid(false, false) == PM3_SUCCESS) { PrintAndLogEx(SUCCESS, "\nValid " _GREEN_("LEGIC Prime tag") " found\n"); res = PM3_SUCCESS; } diff --git a/client/src/cmdhflegic.c b/client/src/cmdhflegic.c index d53c68e5e..00eff936d 100644 --- a/client/src/cmdhflegic.c +++ b/client/src/cmdhflegic.c @@ -28,16 +28,6 @@ static int CmdHelp(const char *Cmd); #define MAX_LENGTH 1024 -static int usage_legic_reader(void) { - PrintAndLogEx(NORMAL, "Read UID and type information from a LEGIC Prime tag\n"); - PrintAndLogEx(NORMAL, "Usage: hf legic reader [h]\n"); - PrintAndLogEx(NORMAL, "Options:"); - PrintAndLogEx(NORMAL, " h : this help"); - PrintAndLogEx(NORMAL, ""); - PrintAndLogEx(NORMAL, "Examples:"); - PrintAndLogEx(NORMAL, _YELLOW_(" hf legic reader")); - return PM3_SUCCESS; -} static int usage_legic_dump(void) { PrintAndLogEx(NORMAL, "Read all memory from LEGIC Prime MIM22, MIM256, MIM1024"); PrintAndLogEx(NORMAL, "and saves bin/eml/json dump file"); @@ -146,6 +136,7 @@ static int CmdLegicInfo(const char *Cmd) { arg_param_end }; CLIExecWithReturn(ctx, Cmd, argtable, true); + CLIParserFree(ctx); int i = 0, k = 0, segmentNum = 0, segment_len = 0, segment_flag = 0; int crc = 0, wrp = 0, wrc = 0; @@ -810,12 +801,26 @@ void legic_seteml(uint8_t *src, uint32_t offset, uint32_t numofbytes) { SendCommandOLD(CMD_HF_LEGIC_ESET, i, len, 0, src + i, len); } } - static int CmdLegicReader(const char *Cmd) { - char cmdp = tolower(param_getchar(Cmd, 0)); - if (cmdp == 'h') return usage_legic_reader(); + CLIParserContext *ctx; + CLIParserInit(&ctx, "hf legic reader", + "Read UID and type information from a LEGIC Prime tag", + "hf legic reader"); - return readLegicUid(true); + void *argtable[] = { + arg_param_begin, + arg_lit0("@", NULL, "optional - continuous reader mode"), + arg_param_end + }; + CLIExecWithReturn(ctx, Cmd, argtable, true); + bool cm = arg_get_lit(ctx, 1); + CLIParserFree(ctx); + + if (cm) { + PrintAndLogEx(INFO, "Press " _GREEN_("") " to exit"); + } + + return readLegicUid(cm, true); } static int CmdLegicDump(const char *Cmd) { @@ -1294,24 +1299,38 @@ int CmdHFLegic(const char *Cmd) { return CmdsParse(CommandTable, Cmd); } -int readLegicUid(bool verbose) { +int readLegicUid(bool loop, bool verbose) { + + do { + legic_card_select_t card; + + int resp = legic_get_type(&card); + + if (loop) { + if (resp != PM3_SUCCESS) { + continue; + } + } else { + switch (resp) { + case PM3_EINVARG: + return PM3_EINVARG; + case PM3_ETIMEOUT: + if (verbose) PrintAndLogEx(WARNING, "command execution time out"); + return PM3_ETIMEOUT; + case PM3_ESOFT: + if (verbose) PrintAndLogEx(WARNING, "legic card select failed"); + return PM3_ESOFT; + default: + break; + } + } + + PrintAndLogEx(NORMAL, ""); + PrintAndLogEx(SUCCESS, " MCD: " _GREEN_("%02X"), card.uid[0]); + PrintAndLogEx(SUCCESS, " MSN: " _GREEN_("%s"), sprint_hex(card.uid + 1, sizeof(card.uid) - 1)); + legic_print_type(card.cardsize, 0); + + } while (loop && kbd_enter_pressed() == false); - legic_card_select_t card; - switch (legic_get_type(&card)) { - case PM3_EINVARG: - return PM3_EINVARG; - case PM3_ETIMEOUT: - if (verbose) PrintAndLogEx(WARNING, "command execution time out"); - return PM3_ETIMEOUT; - case PM3_ESOFT: - if (verbose) PrintAndLogEx(WARNING, "legic card select failed"); - return PM3_ESOFT; - default: - break; - } - PrintAndLogEx(NORMAL, ""); - PrintAndLogEx(SUCCESS, " MCD: " _GREEN_("%02X"), card.uid[0]); - PrintAndLogEx(SUCCESS, " MSN: " _GREEN_("%s"), sprint_hex(card.uid + 1, sizeof(card.uid) - 1)); - legic_print_type(card.cardsize, 0); return PM3_SUCCESS; } diff --git a/client/src/cmdhflegic.h b/client/src/cmdhflegic.h index 9e9411a33..379ae13c7 100644 --- a/client/src/cmdhflegic.h +++ b/client/src/cmdhflegic.h @@ -17,7 +17,7 @@ int CmdHFLegic(const char *Cmd); -int readLegicUid(bool verbose); +int readLegicUid(bool loop, bool verbose); int legic_print_type(uint32_t tagtype, uint8_t spaces); int legic_get_type(legic_card_select_t *card); void legic_chk_iv(uint32_t *iv); diff --git a/doc/cliparser_todo.txt b/doc/cliparser_todo.txt index 212029e2c..26ee2f34b 100644 --- a/doc/cliparser_todo.txt +++ b/doc/cliparser_todo.txt @@ -78,7 +78,6 @@ hf felica resetmode hf felica litesim hf felica litedump hf fido info -hf legic reader hf legic dump hf legic restore hf legic eload From 0ce10e18dfb08bb1295103a37aa62b3edc04636e Mon Sep 17 00:00:00 2001 From: iceman1001 Date: Mon, 21 Dec 2020 12:55:36 +0100 Subject: [PATCH 168/682] textual --- client/src/cmdhf.c | 2 +- client/src/cmdlf.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/client/src/cmdhf.c b/client/src/cmdhf.c index 11d01e1a3..a5f3c1d8f 100644 --- a/client/src/cmdhf.c +++ b/client/src/cmdhf.c @@ -172,7 +172,7 @@ int CmdHFTune(const char *Cmd) { "Continuously measure HF antenna tuning.\n" "Press button or to interrupt.", "hf tune\n" - "hf tune --mixed" + "hf tune --mix" ); void *argtable[] = { diff --git a/client/src/cmdlf.c b/client/src/cmdlf.c index bd99f648e..4120959e8 100644 --- a/client/src/cmdlf.c +++ b/client/src/cmdlf.c @@ -238,7 +238,7 @@ static int CmdLFTune(const char *Cmd) { "Continuously measure LF antenna tuning.\n" "Press button or to interrupt.", "lf tune\n" - "lf tune --mixed" + "lf tune --mix" ); char q_str[60]; From 85b1a833fc00ecc8f3d18bfca11440c536ec6147 Mon Sep 17 00:00:00 2001 From: tcprst Date: Mon, 21 Dec 2020 12:17:05 -0500 Subject: [PATCH 169/682] hf legic wipe - now use cliparser --- client/src/cmdhflegic.c | 25 +++++++++++-------------- doc/cliparser_todo.txt | 1 - 2 files changed, 11 insertions(+), 15 deletions(-) diff --git a/client/src/cmdhflegic.c b/client/src/cmdhflegic.c index 00eff936d..dd4dde731 100644 --- a/client/src/cmdhflegic.c +++ b/client/src/cmdhflegic.c @@ -86,17 +86,6 @@ static int usage_legic_esave(void) { PrintAndLogEx(NORMAL, _YELLOW_(" hf legic esave 2 f myfile")); return PM3_SUCCESS; } -static int usage_legic_wipe(void) { - PrintAndLogEx(NORMAL, "Fills a LEGIC Prime tags memory with zeros. From byte7 and to the end"); - PrintAndLogEx(NORMAL, "It autodetects card type\n"); - PrintAndLogEx(NORMAL, "Usage: hf legic wipe [h]\n"); - PrintAndLogEx(NORMAL, "Options:"); - PrintAndLogEx(NORMAL, " h : this help"); - PrintAndLogEx(NORMAL, ""); - PrintAndLogEx(NORMAL, "Examples:"); - PrintAndLogEx(NORMAL, _YELLOW_(" hf legic wipe")); - return PM3_SUCCESS; -} static bool legic_xor(uint8_t *data, uint16_t cardsize) { @@ -1198,10 +1187,18 @@ static int CmdLegicESave(const char *Cmd) { } static int CmdLegicWipe(const char *Cmd) { + CLIParserContext *ctx; + CLIParserInit(&ctx, "hf legic wipe", + "Fills a LEGIC Prime tags memory with zeros. From byte7 and to the end\n" + "It autodetects card type", + "hf legic wipe"); - char cmdp = tolower(param_getchar(Cmd, 0)); - - if (cmdp == 'h') return usage_legic_wipe(); + void *argtable[] = { + arg_param_begin, + arg_param_end + }; + CLIExecWithReturn(ctx, Cmd, argtable, true); + CLIParserFree(ctx); // tagtype legic_card_select_t card; diff --git a/doc/cliparser_todo.txt b/doc/cliparser_todo.txt index 30e4578e2..3b636db91 100644 --- a/doc/cliparser_todo.txt +++ b/doc/cliparser_todo.txt @@ -78,7 +78,6 @@ hf legic dump hf legic restore hf legic eload hf legic esave -hf legic wipe hf mf darkside hf mf nested hf mf hardnested From 2f1408d65980291761c83402d1252c1af5632037 Mon Sep 17 00:00:00 2001 From: tcprst Date: Mon, 21 Dec 2020 12:41:14 -0500 Subject: [PATCH 170/682] hf legic dump - now use cliparser --- client/luascripts/hf_legic.lua | 2 +- client/src/cmdhflegic.c | 75 ++++++++++++---------------------- doc/cliparser_todo.txt | 1 - 3 files changed, 26 insertions(+), 52 deletions(-) diff --git a/client/luascripts/hf_legic.lua b/client/luascripts/hf_legic.lua index 744372f83..b8b9931cd 100644 --- a/client/luascripts/hf_legic.lua +++ b/client/luascripts/hf_legic.lua @@ -710,7 +710,7 @@ function readFromPM3() local tag, bytes, infile --infile="legic.temp" infile=os.tmpname() - core.console("hf legic dump f "..infile) + core.console("hf legic dump -f "..infile) tag=readFile(infile..".bin") os.remove(infile) os.remove(infile..".bin") diff --git a/client/src/cmdhflegic.c b/client/src/cmdhflegic.c index dd4dde731..09bbdf90b 100644 --- a/client/src/cmdhflegic.c +++ b/client/src/cmdhflegic.c @@ -28,22 +28,6 @@ static int CmdHelp(const char *Cmd); #define MAX_LENGTH 1024 -static int usage_legic_dump(void) { - PrintAndLogEx(NORMAL, "Read all memory from LEGIC Prime MIM22, MIM256, MIM1024"); - PrintAndLogEx(NORMAL, "and saves bin/eml/json dump file"); - PrintAndLogEx(NORMAL, "It autodetects card type.\n"); - PrintAndLogEx(NORMAL, "Usage: hf legic dump [h] [x] [f ]\n"); - PrintAndLogEx(NORMAL, "Options:"); - PrintAndLogEx(NORMAL, " h : this help"); - PrintAndLogEx(NORMAL, " f : filename w/o '.bin' to dump bytes"); - PrintAndLogEx(NORMAL, " x : deobfuscate dump data (xor with MCC)"); - PrintAndLogEx(NORMAL, ""); - PrintAndLogEx(NORMAL, "Examples:"); - PrintAndLogEx(NORMAL, _YELLOW_(" hf legic dump - uses UID as filename")); - PrintAndLogEx(NORMAL, _YELLOW_(" hf legic dump f myfile")); - PrintAndLogEx(NORMAL, _YELLOW_(" hf legic dump x")); - return PM3_SUCCESS; -} static int usage_legic_restore(void) { PrintAndLogEx(NORMAL, "Reads binary file and it autodetects card type and verifies that the file has the same size"); PrintAndLogEx(NORMAL, "Then write the data back to card. All bytes except the first 7bytes [UID(4) MCC(1) DCF(2)]\n"); @@ -813,38 +797,29 @@ static int CmdLegicReader(const char *Cmd) { } static int CmdLegicDump(const char *Cmd) { + CLIParserContext *ctx; + CLIParserInit(&ctx, "hf legic dump", + "Read all memory from LEGIC Prime MIM22, MIM256, MIM1024 and saves bin/eml/json dump file\n" + "It autodetects card type.", + "hf legic dump <-- use UID as filename\n" + "hf legic dump -f myfile <-- use user specified filename\n" + "hf legic dump --deobfuscate <-- use UID as filename and deobfuscate data"); - int fileNameLen = 0; - char filename[FILE_PATH_SIZE] = {0x00}; - char *fptr = filename; - bool errors = false, shall_deobsfuscate = false; - uint16_t dumplen; - uint8_t cmdp = 0; + void *argtable[] = { + arg_param_begin, + arg_str0("f", "file", "", "specify a filename for dump file"), + arg_lit0(NULL, "deobfuscate", "deobfuscate dump data (xor with MCC)"), + arg_param_end + }; + CLIExecWithReturn(ctx, Cmd, argtable, true); - while (param_getchar(Cmd, cmdp) != 0x00 && !errors) { - switch (tolower(param_getchar(Cmd, cmdp))) { - case 'h': - return usage_legic_dump(); - case 'f': - fileNameLen = param_getstr(Cmd, cmdp + 1, filename, FILE_PATH_SIZE); - if (!fileNameLen) - errors = true; - if (fileNameLen > FILE_PATH_SIZE - 5) - fileNameLen = FILE_PATH_SIZE - 5; - cmdp += 2; - break; - case 'x': - shall_deobsfuscate = true; - cmdp++; - break; - default: - PrintAndLogEx(WARNING, "Unknown parameter '%c'", param_getchar(Cmd, cmdp)); - errors = true; - break; - } - } - //Validations - if (errors) return usage_legic_dump(); + int fnlen = 0; + char filename[FILE_PATH_SIZE] = {0}; + CLIParamStrToBuf(arg_get_str(ctx, 1), (uint8_t *)filename, FILE_PATH_SIZE, &fnlen); + + bool shall_deobsfuscate = arg_get_lit(ctx, 2); + + CLIParserFree(ctx); // tagtype legic_card_select_t card; @@ -852,7 +827,7 @@ static int CmdLegicDump(const char *Cmd) { PrintAndLogEx(WARNING, "Failed to identify tagtype"); return PM3_ESOFT; } - dumplen = card.cardsize; + uint16_t dumplen = card.cardsize; legic_print_type(dumplen, 0); PrintAndLogEx(SUCCESS, "Reading tag memory %d b...", dumplen); @@ -896,10 +871,10 @@ static int CmdLegicDump(const char *Cmd) { } // user supplied filename? - if (fileNameLen < 1) { + if (fnlen < 1) { PrintAndLogEx(INFO, "Using UID as filename"); - fptr += snprintf(fptr, sizeof(filename), "hf-legic-"); - FillFileNameByUID(fptr, data, "-dump", 4); + strcat(filename, "hf-legic-"); + FillFileNameByUID(filename, data, "-dump", 4); } if (shall_deobsfuscate) { diff --git a/doc/cliparser_todo.txt b/doc/cliparser_todo.txt index 3b636db91..d78d347aa 100644 --- a/doc/cliparser_todo.txt +++ b/doc/cliparser_todo.txt @@ -74,7 +74,6 @@ hf felica resetmode hf felica litesim hf felica litedump hf fido info -hf legic dump hf legic restore hf legic eload hf legic esave From ef2dfc8b3b75c7ba1a58256fd344a15732df76b4 Mon Sep 17 00:00:00 2001 From: tcprst Date: Mon, 21 Dec 2020 12:50:12 -0500 Subject: [PATCH 171/682] hf legic restore - now use cliparser --- client/luascripts/hf_legic_clone.lua | 2 +- client/src/cmdhflegic.c | 68 ++++++++-------------------- doc/cliparser_todo.txt | 1 - 3 files changed, 21 insertions(+), 50 deletions(-) diff --git a/client/luascripts/hf_legic_clone.lua b/client/luascripts/hf_legic_clone.lua index ec0c78d25..ec651d35c 100644 --- a/client/luascripts/hf_legic_clone.lua +++ b/client/luascripts/hf_legic_clone.lua @@ -456,7 +456,7 @@ local function writeToTag(plainBytes) -- write data to file if (writeOutputBytes(bytes, "hf-legic-UID-dump.bin")) then -- write pm3-buffer to Tag - cmd = ('hf legic restore f hf-legic-UID-dump') + cmd = ('hf legic restore -f hf-legic-UID-dump') core.console(cmd) end end diff --git a/client/src/cmdhflegic.c b/client/src/cmdhflegic.c index 09bbdf90b..95b9567a1 100644 --- a/client/src/cmdhflegic.c +++ b/client/src/cmdhflegic.c @@ -28,19 +28,6 @@ static int CmdHelp(const char *Cmd); #define MAX_LENGTH 1024 -static int usage_legic_restore(void) { - PrintAndLogEx(NORMAL, "Reads binary file and it autodetects card type and verifies that the file has the same size"); - PrintAndLogEx(NORMAL, "Then write the data back to card. All bytes except the first 7bytes [UID(4) MCC(1) DCF(2)]\n"); - PrintAndLogEx(NORMAL, "Usage: hf legic restore [h] [x] [f ]\n"); - PrintAndLogEx(NORMAL, "Options:"); - PrintAndLogEx(NORMAL, " h : this help"); - PrintAndLogEx(NORMAL, " f : filename w/o '.bin' to restore bytes on to card from"); - PrintAndLogEx(NORMAL, " x : obfuscate dump data (xor with MCC)"); - PrintAndLogEx(NORMAL, ""); - PrintAndLogEx(NORMAL, "Examples:"); - PrintAndLogEx(NORMAL, _YELLOW_(" hf legic restore f myfile")); - return PM3_SUCCESS; -} static int usage_legic_eload(void) { PrintAndLogEx(NORMAL, "It loads a binary dump into emulator memory\n"); PrintAndLogEx(NORMAL, "Usage: hf legic eload [h] [card memory] [f ]\n"); @@ -891,44 +878,28 @@ static int CmdLegicDump(const char *Cmd) { } static int CmdLegicRestore(const char *Cmd) { + CLIParserContext *ctx; + CLIParserInit(&ctx, "hf legic restore", + "Reads binary file and it autodetects card type and verifies that the file has the same size\n" + "Then write the data back to card. All bytes except the first 7bytes [UID(4) MCC(1) DCF(2)]", + "hf legic restore -f myfile <-- use user specified filename\n" + "hf legic restore -f myfile --obfuscate <-- use UID as filename and deobfuscate data"); - char filename[FILE_PATH_SIZE] = {0x00}; - bool errors = false, shall_obsfuscate = false, have_filename = false; - size_t numofbytes; - uint8_t cmdp = 0; + void *argtable[] = { + arg_param_begin, + arg_str1("f", "file", "", "specify a filename to restore"), + arg_lit0(NULL, "obfuscate", "obfuscate dump data (xor with MCC)"), + arg_param_end + }; + CLIExecWithReturn(ctx, Cmd, argtable, false); - while (param_getchar(Cmd, cmdp) != 0x00 && !errors) { - switch (tolower(param_getchar(Cmd, cmdp))) { - case 'h': { - errors = true; - break; - } - case 'f': { - if (param_getstr(Cmd, cmdp + 1, filename, FILE_PATH_SIZE) >= FILE_PATH_SIZE) { - PrintAndLogEx(FAILED, "Filename too long"); - break; - } - have_filename = true; - cmdp += 2; - break; - } - case 'x': { - shall_obsfuscate = true; - cmdp++; - break; - } - default: { - PrintAndLogEx(WARNING, "Unknown parameter '%c'", param_getchar(Cmd, cmdp)); - errors = true; - break; - } - } - } - if (have_filename == false) - errors = true; + int fnlen = 0; + char filename[FILE_PATH_SIZE] = {0}; + CLIParamStrToBuf(arg_get_str(ctx, 1), (uint8_t *)filename, FILE_PATH_SIZE, &fnlen); - //Validations - if (errors || cmdp == 0) return usage_legic_restore(); + bool shall_obsfuscate = arg_get_lit(ctx, 2); + + CLIParserFree(ctx); // tagtype legic_card_select_t card; @@ -946,6 +917,7 @@ static int CmdLegicRestore(const char *Cmd) { return PM3_EMALLOC; } + size_t numofbytes; if (loadFile_safe(filename, ".bin", (void **)&data, &numofbytes) != PM3_SUCCESS) { free(data); PrintAndLogEx(WARNING, "Error, reading file"); diff --git a/doc/cliparser_todo.txt b/doc/cliparser_todo.txt index d78d347aa..debef93fb 100644 --- a/doc/cliparser_todo.txt +++ b/doc/cliparser_todo.txt @@ -74,7 +74,6 @@ hf felica resetmode hf felica litesim hf felica litedump hf fido info -hf legic restore hf legic eload hf legic esave hf mf darkside From d4c87945b8fa8b63570033a01275b0ecf7e09c91 Mon Sep 17 00:00:00 2001 From: iceman1001 Date: Mon, 21 Dec 2020 20:47:17 +0100 Subject: [PATCH 172/682] style & text --- client/src/cmdhf14b.c | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/client/src/cmdhf14b.c b/client/src/cmdhf14b.c index 80695b980..b27df1914 100644 --- a/client/src/cmdhf14b.c +++ b/client/src/cmdhf14b.c @@ -728,12 +728,12 @@ static void print_ct_general_info(void *vcard) { memcpy(&card, (iso14b_cts_card_select_t *)vcard, sizeof(iso14b_cts_card_select_t)); uint32_t uid32 = (card.uid[0] | card.uid[1] << 8 | card.uid[2] << 16 | card.uid[3] << 24); + PrintAndLogEx(NORMAL, ""); PrintAndLogEx(SUCCESS, "ASK C-Ticket"); PrintAndLogEx(SUCCESS, " UID: " _GREEN_("%s") " ( " _YELLOW_("%010u") " )", sprint_hex(card.uid, sizeof(card.uid)), uid32); PrintAndLogEx(SUCCESS, " Product Code: %02X", card.pc); PrintAndLogEx(SUCCESS, " Facility Code: %02X", card.fc); PrintAndLogEx(NORMAL, ""); - } // iceman, calypso? @@ -819,11 +819,9 @@ static bool HF14B_ST_Info(bool verbose, bool do_aid_search) { print_st_general_info(card.uid, card.uidlen); - if (do_aid_search) { - hf14b_aid_search(verbose); - } - - + if (do_aid_search) { + hf14b_aid_search(verbose); + } return true; } From cd972adce5e4682439c159fbe24cfd43e4b4119b Mon Sep 17 00:00:00 2001 From: tcprst Date: Mon, 21 Dec 2020 14:50:42 -0500 Subject: [PATCH 173/682] hf legic eload - now use cliparser --- client/luascripts/hf_legic_clone.lua | 2 +- client/src/cmdhflegic.c | 99 +++++++++++----------------- doc/cliparser_todo.txt | 1 - 3 files changed, 38 insertions(+), 64 deletions(-) diff --git a/client/luascripts/hf_legic_clone.lua b/client/luascripts/hf_legic_clone.lua index ec651d35c..757d65fa0 100644 --- a/client/luascripts/hf_legic_clone.lua +++ b/client/luascripts/hf_legic_clone.lua @@ -530,7 +530,7 @@ local function main(args) res = res .."\ncreated clone_dump from\n\t"..infile.." crc: "..oldcrc.."\ndump_file:" res = res .."\n\t"..outfile.." crc: "..string.sub(newcrc, -2) res = res .."\nyou may load the new file with:" - res = res ..ansicolors.yellow.."hf legic eload f "..outfile..ansicolors.reset + res = res ..ansicolors.yellow.."hf legic eload -f "..outfile..ansicolors.reset res = res .."\n\nif you don't write to tag immediately ('-w' switch) you will need to recalculate each segmentCRC" res = res .."\nafter writing this dump to a tag!" res = res .."\n\na segmentCRC gets calculated over MCD,MSN0..3, Segment-Header0..3" diff --git a/client/src/cmdhflegic.c b/client/src/cmdhflegic.c index 95b9567a1..3a95621e2 100644 --- a/client/src/cmdhflegic.c +++ b/client/src/cmdhflegic.c @@ -28,20 +28,6 @@ static int CmdHelp(const char *Cmd); #define MAX_LENGTH 1024 -static int usage_legic_eload(void) { - PrintAndLogEx(NORMAL, "It loads a binary dump into emulator memory\n"); - PrintAndLogEx(NORMAL, "Usage: hf legic eload [h] [card memory] [f ]\n"); - PrintAndLogEx(NORMAL, "Options:"); - PrintAndLogEx(NORMAL, " h : this help"); - PrintAndLogEx(NORMAL, " [card memory] : 0 = MIM22"); - PrintAndLogEx(NORMAL, " : 1 = MIM256 (default)"); - PrintAndLogEx(NORMAL, " : 2 = MIM1024"); - PrintAndLogEx(NORMAL, " f : filename w/o .bin to load"); - PrintAndLogEx(NORMAL, ""); - PrintAndLogEx(NORMAL, "Examples:"); - PrintAndLogEx(NORMAL, _YELLOW_(" hf legic eload 2 f myfile")); - return PM3_SUCCESS; -} static int usage_legic_esave(void) { PrintAndLogEx(NORMAL, "It saves bin/eml/json dump file of emulator memory\n"); PrintAndLogEx(NORMAL, "Usage: hf legic esave [h] [card memory] f \n"); @@ -978,58 +964,47 @@ static int CmdLegicRestore(const char *Cmd) { } static int CmdLegicELoad(const char *Cmd) { + CLIParserContext *ctx; + CLIParserInit(&ctx, "hf legic eload", + "Loads a LEGIC binary dump into emulator memory", + "hf legic eload -f myfile -t 0 <- Simulate Type MIM22\n" + "hf legic eload -f myfile -t 1 <- Simulate Type MIM256 (default)\n" + "hf legic eload -f myfile -t 2 <- Simulate Type MIM1024"); - size_t numofbytes = 256; - char filename[FILE_PATH_SIZE] = {0x00}; - bool errors = false, shall_obsfuscate = false, have_filename = false; - uint8_t cmdp = 0; + void *argtable[] = { + arg_param_begin, + arg_str1("f", "file", "", "Specify a filename to restore"), + arg_int0("t", "type", "", "Tag type to simulate."), + arg_lit0(NULL, "obfuscate", "Obfuscate dump data (xor with MCC)"), + arg_param_end + }; + CLIExecWithReturn(ctx, Cmd, argtable, false); - while (param_getchar(Cmd, cmdp) != 0x00 && !errors) { - switch (tolower(param_getchar(Cmd, cmdp))) { - case 'h' : { - return usage_legic_eload(); - } - case 'f' : { - if (param_getstr(Cmd, cmdp + 1, filename, FILE_PATH_SIZE) >= FILE_PATH_SIZE) { - PrintAndLogEx(FAILED, "Filename too long"); - break; - } - have_filename = true; - cmdp += 2; - break; - } - case 'x': { - shall_obsfuscate = true; - cmdp++; - break; - } - case '0' : { - numofbytes = 22; - cmdp++; - break; - } - case '1' : { - numofbytes = 256; - cmdp++; - break; - } - case '2' : { - numofbytes = 1024; - cmdp++; - break; - } - default : { - PrintAndLogEx(WARNING, "Unknown parameter '%c'", param_getchar(Cmd, cmdp)); - errors = true; - break; - } - } + int fnlen = 0; + char filename[FILE_PATH_SIZE] = {0}; + CLIParamStrToBuf(arg_get_str(ctx, 1), (uint8_t *)filename, FILE_PATH_SIZE, &fnlen); + + size_t numofbytes = 0; + + switch (arg_get_int_def(ctx, 2, 1)) { + case 0: + numofbytes = 22; + break; + case 1: + numofbytes = 256; + break; + case 2: + numofbytes = 1024; + break; + default: + PrintAndLogEx(ERR, "Unknown tag type"); + CLIParserFree(ctx); + return PM3_EINVARG; } - if (have_filename == false) - errors = true; - //Validations - if (errors || strlen(Cmd) == 0) return usage_legic_eload(); + bool shall_obsfuscate = arg_get_lit(ctx, 3); + + CLIParserFree(ctx); // set up buffer uint8_t *data = calloc(numofbytes, sizeof(uint8_t)); diff --git a/doc/cliparser_todo.txt b/doc/cliparser_todo.txt index debef93fb..00bb3781e 100644 --- a/doc/cliparser_todo.txt +++ b/doc/cliparser_todo.txt @@ -74,7 +74,6 @@ hf felica resetmode hf felica litesim hf felica litedump hf fido info -hf legic eload hf legic esave hf mf darkside hf mf nested From e25a99077e5819b625627447165b7d8f28ce81ea Mon Sep 17 00:00:00 2001 From: iceman1001 Date: Mon, 21 Dec 2020 20:50:47 +0100 Subject: [PATCH 174/682] hf search - always turn off field --- client/src/cmdhf.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/src/cmdhf.c b/client/src/cmdhf.c index a5f3c1d8f..0f6a351ec 100644 --- a/client/src/cmdhf.c +++ b/client/src/cmdhf.c @@ -157,11 +157,11 @@ int CmdHFSearch(const char *Cmd) { PROMPT_CLEARLINE; if (res != PM3_SUCCESS) { - PrintAndLogEx(WARNING, _RED_("No known/supported 13.56 MHz tags found")); res = PM3_ESOFT; } + DropField(); return res; } From f1c4be446cf9230c542850efeb7bbab36a7d71e9 Mon Sep 17 00:00:00 2001 From: tcprst Date: Mon, 21 Dec 2020 15:00:02 -0500 Subject: [PATCH 175/682] hf legic esave - now use cliparser --- client/src/cmdhflegic.c | 101 +++++++++++++++++----------------------- doc/cliparser_todo.txt | 1 - 2 files changed, 42 insertions(+), 60 deletions(-) diff --git a/client/src/cmdhflegic.c b/client/src/cmdhflegic.c index 3a95621e2..512f2dd53 100644 --- a/client/src/cmdhflegic.c +++ b/client/src/cmdhflegic.c @@ -28,22 +28,6 @@ static int CmdHelp(const char *Cmd); #define MAX_LENGTH 1024 -static int usage_legic_esave(void) { - PrintAndLogEx(NORMAL, "It saves bin/eml/json dump file of emulator memory\n"); - PrintAndLogEx(NORMAL, "Usage: hf legic esave [h] [card memory] f \n"); - PrintAndLogEx(NORMAL, "Options:"); - PrintAndLogEx(NORMAL, " h : this help"); - PrintAndLogEx(NORMAL, " [card memory] : 0 = MIM22"); - PrintAndLogEx(NORMAL, " : 1 = MIM256 (default)"); - PrintAndLogEx(NORMAL, " : 2 = MIM1024"); - PrintAndLogEx(NORMAL, " f : filename w/o .bin to load"); - PrintAndLogEx(NORMAL, ""); - PrintAndLogEx(NORMAL, "Examples:"); - PrintAndLogEx(NORMAL, _YELLOW_(" hf legic esave 2 - uses UID as filename")); - PrintAndLogEx(NORMAL, _YELLOW_(" hf legic esave 2 f myfile")); - return PM3_SUCCESS; -} - static bool legic_xor(uint8_t *data, uint16_t cardsize) { if (cardsize <= 22) { @@ -1032,49 +1016,48 @@ static int CmdLegicELoad(const char *Cmd) { } static int CmdLegicESave(const char *Cmd) { + CLIParserContext *ctx; + CLIParserInit(&ctx, "hf legic esave", + "Saves bin/eml/json dump file of emulator memory", + "hf legic esave <- uses UID as filename\n" + "hf legic esave -f myfile -t 0 <- Type MIM22\n" + "hf legic esave -f myfile -t 1 <- Type MIM256 (default)\n" + "hf legic esave -f myfile -t 2 <- Type MIM1024"); + void *argtable[] = { + arg_param_begin, + arg_str0("f", "file", "", "Specify a filename to save"), + arg_int0("t", "type", "", "Tag type"), + arg_lit0(NULL, "deobfuscate", "De-obfuscate dump data (xor with MCC)"), + arg_param_end + }; + CLIExecWithReturn(ctx, Cmd, argtable, true); + + int fnlen = 0; char filename[FILE_PATH_SIZE] = {0}; - char *fptr = filename; - int fileNameLen = 0; - size_t numofbytes = 256; - bool errors = false, shall_deobsfuscate = false; - uint8_t cmdp = 0; - while (param_getchar(Cmd, cmdp) != 0x00 && !errors) { - switch (tolower(param_getchar(Cmd, cmdp))) { - case 'h' : - return usage_legic_esave(); - case 'f' : - fileNameLen = param_getstr(Cmd, cmdp + 1, filename, FILE_PATH_SIZE); - if (!fileNameLen) - errors = true; - if (fileNameLen > FILE_PATH_SIZE - 5) - fileNameLen = FILE_PATH_SIZE - 5; - cmdp += 2; - break; - case 'x': - shall_deobsfuscate = true; - cmdp++; - break; - case '0' : - numofbytes = 22; - cmdp++; - break; - case '1' : - numofbytes = 256; - cmdp++; - break; - case '2' : - numofbytes = 1024; - cmdp++; - break; - default : - PrintAndLogEx(WARNING, "Unknown parameter '%c'", param_getchar(Cmd, cmdp)); - errors = true; - break; - } + CLIParamStrToBuf(arg_get_str(ctx, 1), (uint8_t *)filename, FILE_PATH_SIZE, &fnlen); + + size_t numofbytes = 0; + + switch (arg_get_int_def(ctx, 2, 1)) { + case 0: + numofbytes = 22; + break; + case 1: + numofbytes = 256; + break; + case 2: + numofbytes = 1024; + break; + default: + PrintAndLogEx(ERR, "Unknown tag type"); + CLIParserFree(ctx); + return PM3_EINVARG; } - //Validations - if (errors || strlen(Cmd) == 0) return usage_legic_esave(); + + bool shall_deobsfuscate = arg_get_lit(ctx, 3); + + CLIParserFree(ctx); // set up buffer uint8_t *data = calloc(numofbytes, sizeof(uint8_t)); @@ -1092,10 +1075,10 @@ static int CmdLegicESave(const char *Cmd) { } // user supplied filename? - if (fileNameLen < 1) { + if (fnlen < 1) { PrintAndLogEx(INFO, "Using UID as filename"); - fptr += snprintf(fptr, sizeof(filename), "hf-legic-"); - FillFileNameByUID(fptr, data, "-dump", 4); + strcat(filename, "hf-legic-"); + FillFileNameByUID(filename, data, "-dump", 4); } if (shall_deobsfuscate) { diff --git a/doc/cliparser_todo.txt b/doc/cliparser_todo.txt index 00bb3781e..daad348a5 100644 --- a/doc/cliparser_todo.txt +++ b/doc/cliparser_todo.txt @@ -74,7 +74,6 @@ hf felica resetmode hf felica litesim hf felica litedump hf fido info -hf legic esave hf mf darkside hf mf nested hf mf hardnested From fce36effb434489dba67dc12598939b89633fba4 Mon Sep 17 00:00:00 2001 From: tcprst Date: Mon, 21 Dec 2020 15:01:30 -0500 Subject: [PATCH 176/682] legic style --- client/src/cmdhflegic.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/client/src/cmdhflegic.c b/client/src/cmdhflegic.c index 512f2dd53..709cf9390 100644 --- a/client/src/cmdhflegic.c +++ b/client/src/cmdhflegic.c @@ -969,7 +969,7 @@ static int CmdLegicELoad(const char *Cmd) { CLIParamStrToBuf(arg_get_str(ctx, 1), (uint8_t *)filename, FILE_PATH_SIZE, &fnlen); size_t numofbytes = 0; - + switch (arg_get_int_def(ctx, 2, 1)) { case 0: numofbytes = 22; @@ -1038,7 +1038,7 @@ static int CmdLegicESave(const char *Cmd) { CLIParamStrToBuf(arg_get_str(ctx, 1), (uint8_t *)filename, FILE_PATH_SIZE, &fnlen); size_t numofbytes = 0; - + switch (arg_get_int_def(ctx, 2, 1)) { case 0: numofbytes = 22; From c3cc3b2a80a12aae82c2a82b57a0ebdcb888f0c9 Mon Sep 17 00:00:00 2001 From: Ave Date: Tue, 22 Dec 2020 02:22:28 +0300 Subject: [PATCH 177/682] emrtd: split lds tag det to a different func and improve emrtd_lds_get_data_by_tag --- client/src/cmdhfemrtd.c | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/client/src/cmdhfemrtd.c b/client/src/cmdhfemrtd.c index 30eb4667f..1aa6079ad 100644 --- a/client/src/cmdhfemrtd.c +++ b/client/src/cmdhfemrtd.c @@ -622,8 +622,15 @@ static int emrtd_read_file(uint8_t *dataout, int *dataoutlen, uint8_t *kenc, uin return true; } +static int emrtd_lds_determine_tag_length(uint8_t tag) { + if ((tag == 0x5F) || (tag == 0x7F)) { + return 2; + } + return 1; +} + static bool emrtd_lds_get_data_by_tag(uint8_t *datain, int datainlen, uint8_t *dataout, int *dataoutlen, int tag1, int tag2, bool twobytetag) { - int offset = 1; + int offset = emrtd_lds_determine_tag_length(*datain); offset += emrtd_get_asn1_field_length(datain, datainlen, offset); int e_idlen = 0; @@ -632,11 +639,7 @@ static bool emrtd_lds_get_data_by_tag(uint8_t *datain, int datainlen, uint8_t *d while (offset < datainlen) { PrintAndLogEx(DEBUG, "emrtd_lds_get_data_by_tag, offset: %i, data: %X", offset, *(datain + offset)); // Determine element ID length to set as offset on asn1datalength - if ((*(datain + offset) == 0x5F) || (*(datain + offset) == 0x7F)) { - e_idlen = 2; - } else { - e_idlen = 1; - } + e_idlen = emrtd_lds_determine_tag_length(*(datain + offset)); // Get the length of the element e_datalen = emrtd_get_asn1_data_length(datain + offset, datainlen - offset, e_idlen); From a05bdecaaf41ba201e571d3ee667123efe3c72d5 Mon Sep 17 00:00:00 2001 From: Ave Date: Tue, 22 Dec 2020 02:28:37 +0300 Subject: [PATCH 178/682] emrtd: make top tag skipping on emrtd_lds_get_data_by_tag optional --- client/src/cmdhfemrtd.c | 32 ++++++++++++++++++-------------- 1 file changed, 18 insertions(+), 14 deletions(-) diff --git a/client/src/cmdhfemrtd.c b/client/src/cmdhfemrtd.c index 1aa6079ad..e31c326fa 100644 --- a/client/src/cmdhfemrtd.c +++ b/client/src/cmdhfemrtd.c @@ -629,9 +629,13 @@ static int emrtd_lds_determine_tag_length(uint8_t tag) { return 1; } -static bool emrtd_lds_get_data_by_tag(uint8_t *datain, int datainlen, uint8_t *dataout, int *dataoutlen, int tag1, int tag2, bool twobytetag) { - int offset = emrtd_lds_determine_tag_length(*datain); - offset += emrtd_get_asn1_field_length(datain, datainlen, offset); +static bool emrtd_lds_get_data_by_tag(uint8_t *datain, int datainlen, uint8_t *dataout, int *dataoutlen, int tag1, int tag2, bool twobytetag, bool skiptoptag) { + int offset = 0; + + if (skiptoptag) { + offset += emrtd_lds_determine_tag_length(*datain); + offset += emrtd_get_asn1_field_length(datain, datainlen, offset); + } int e_idlen = 0; int e_datalen = 0; @@ -714,7 +718,7 @@ static int emrtd_dump_ef_dg5(uint8_t *file_contents, size_t file_length) { int datalen = 0; // If we can't find image in EF_DG5, return false. - if (emrtd_lds_get_data_by_tag(file_contents, file_length, data, &datalen, 0x5F, 0x40, true) == false) { + if (emrtd_lds_get_data_by_tag(file_contents, file_length, data, &datalen, 0x5F, 0x40, true, true) == false) { return PM3_ESOFT; } @@ -732,7 +736,7 @@ static int emrtd_dump_ef_dg7(uint8_t *file_contents, size_t file_length) { int datalen = 0; // If we can't find image in EF_DG7, return false. - if (emrtd_lds_get_data_by_tag(file_contents, file_length, data, &datalen, 0x5F, 0x42, true) == false) { + if (emrtd_lds_get_data_by_tag(file_contents, file_length, data, &datalen, 0x5F, 0x42, true, true) == false) { return PM3_ESOFT; } @@ -998,7 +1002,7 @@ int dumpHF_EMRTD(char *documentnumber, char *dob, char *expiry, bool BAC_availab uint8_t filelist[50]; int filelistlen = 0; - if (!emrtd_lds_get_data_by_tag(response, resplen, filelist, &filelistlen, 0x5c, 0x00, false)) { + if (!emrtd_lds_get_data_by_tag(response, resplen, filelist, &filelistlen, 0x5c, 0x00, false, true)) { PrintAndLogEx(ERR, "Failed to read file list from EF_COM."); DropField(); return PM3_ESOFT; @@ -1224,7 +1228,7 @@ static void emrtd_print_unknown_timestamp_5f85(uint8_t *data) { static int emrtd_print_ef_com_info(uint8_t *data, size_t datalen) { uint8_t filelist[50]; int filelistlen = 0; - int res = emrtd_lds_get_data_by_tag(data, datalen, filelist, &filelistlen, 0x5c, 0x00, false); + int res = emrtd_lds_get_data_by_tag(data, datalen, filelist, &filelistlen, 0x5c, 0x00, false, true); if (!res) { PrintAndLogEx(ERR, "Failed to read file list from EF_COM."); return PM3_ESOFT; @@ -1255,7 +1259,7 @@ static int emrtd_print_ef_dg1_info(uint8_t *data, size_t datalen) { char mrz[90] = { 0x00 }; int mrzlen = 0; - if (!emrtd_lds_get_data_by_tag(data, datalen, (uint8_t *) mrz, &mrzlen, 0x5f, 0x1f, true)) { + if (!emrtd_lds_get_data_by_tag(data, datalen, (uint8_t *) mrz, &mrzlen, 0x5f, 0x1f, true, true)) { PrintAndLogEx(ERR, "Failed to read MRZ from EF_DG1."); return PM3_ESOFT; } @@ -1337,13 +1341,13 @@ static int emrtd_print_ef_dg11_info(uint8_t *data, size_t datalen) { PrintAndLogEx(NORMAL, ""); PrintAndLogEx(INFO, "-------------------- " _CYAN_("EF_DG11") " -------------------"); - if (!emrtd_lds_get_data_by_tag(data, datalen, taglist, &taglistlen, 0x5c, 0x00, false)) { + if (!emrtd_lds_get_data_by_tag(data, datalen, taglist, &taglistlen, 0x5c, 0x00, false, true)) { PrintAndLogEx(ERR, "Failed to read file list from EF_DG11."); return PM3_ESOFT; } for (int i = 0; i < taglistlen; i++) { - emrtd_lds_get_data_by_tag(data, datalen, tagdata, &tagdatalen, taglist[i], taglist[i + 1], taglist[i] == 0x5f); + emrtd_lds_get_data_by_tag(data, datalen, tagdata, &tagdatalen, taglist[i], taglist[i + 1], taglist[i] == 0x5f, true); // Don't bother with empty tags if (tagdatalen == 0) { continue; @@ -1416,13 +1420,13 @@ static int emrtd_print_ef_dg12_info(uint8_t *data, size_t datalen) { PrintAndLogEx(NORMAL, ""); PrintAndLogEx(INFO, "-------------------- " _CYAN_("EF_DG12") " -------------------"); - if (!emrtd_lds_get_data_by_tag(data, datalen, taglist, &taglistlen, 0x5c, 0x00, false)) { + if (!emrtd_lds_get_data_by_tag(data, datalen, taglist, &taglistlen, 0x5c, 0x00, false, true)) { PrintAndLogEx(ERR, "Failed to read file list from EF_DG12."); return PM3_ESOFT; } for (int i = 0; i < taglistlen; i++) { - emrtd_lds_get_data_by_tag(data, datalen, tagdata, &tagdatalen, taglist[i], taglist[i + 1], taglist[i] == 0x5f); + emrtd_lds_get_data_by_tag(data, datalen, tagdata, &tagdatalen, taglist[i], taglist[i + 1], taglist[i] == 0x5f, true); // Don't bother with empty tags if (tagdatalen == 0) { continue; @@ -1524,7 +1528,7 @@ int infoHF_EMRTD(char *documentnumber, char *dob, char *expiry, bool BAC_availab uint8_t filelist[50]; int filelistlen = 0; - if (!emrtd_lds_get_data_by_tag(response, resplen, filelist, &filelistlen, 0x5c, 0x00, false)) { + if (!emrtd_lds_get_data_by_tag(response, resplen, filelist, &filelistlen, 0x5c, 0x00, false, true)) { PrintAndLogEx(ERR, "Failed to read file list from EF_COM."); DropField(); return PM3_ESOFT; @@ -1574,7 +1578,7 @@ int infoHF_EMRTD_offline(const char *path) { uint8_t filelist[50]; int filelistlen = 0; - res = emrtd_lds_get_data_by_tag(data, datalen, filelist, &filelistlen, 0x5c, 0x00, false); + res = emrtd_lds_get_data_by_tag(data, datalen, filelist, &filelistlen, 0x5c, 0x00, false, true); if (!res) { PrintAndLogEx(ERR, "Failed to read file list from EF_COM."); free(data); From 8c1e4168cfe2a81c54aa62f93f634751092d9665 Mon Sep 17 00:00:00 2001 From: Ave Date: Tue, 22 Dec 2020 02:30:26 +0300 Subject: [PATCH 179/682] emrtd: make style pass --- client/src/cmdhfemrtd.c | 43 ++++++++++++++++++++--------------------- 1 file changed, 21 insertions(+), 22 deletions(-) diff --git a/client/src/cmdhfemrtd.c b/client/src/cmdhfemrtd.c index e31c326fa..d0b3527af 100644 --- a/client/src/cmdhfemrtd.c +++ b/client/src/cmdhfemrtd.c @@ -61,7 +61,7 @@ static int emrtd_print_ef_dg12_info(uint8_t *data, size_t datalen); static int emrtd_print_ef_sod_info(uint8_t *data, size_t datalen); typedef enum { // list must match dg_table - EF_COM=0, + EF_COM = 0, EF_DG1, EF_DG2, EF_DG3, @@ -109,7 +109,7 @@ static emrtd_dg_t dg_table[] = { }; static emrtd_dg_t *emrtd_tag_to_dg(uint8_t tag) { - for (int dgi=0; dg_table[dgi].filename != NULL; dgi++) { + for (int dgi = 0; dg_table[dgi].filename != NULL; dgi++) { if (dg_table[dgi].tag == tag) { return &dg_table[dgi]; } @@ -117,7 +117,7 @@ static emrtd_dg_t *emrtd_tag_to_dg(uint8_t tag) { return NULL; } static emrtd_dg_t *emrtd_fileid_to_dg(const char *file_id) { - for (int dgi=0; dg_table[dgi].filename != NULL; dgi++) { + for (int dgi = 0; dg_table[dgi].filename != NULL; dgi++) { if (strcmp(dg_table[dgi].fileid, file_id) == 0) { return &dg_table[dgi]; } @@ -698,7 +698,7 @@ static int emrtd_dump_ef_dg2(uint8_t *file_contents, size_t file_length) { // Note: Doing file_length - 6 to account for the longest data we're checking. for (offset = 0; offset < file_length - 6; offset++) { if ((file_contents[offset] == 0xFF && file_contents[offset + 1] == 0xD8 && file_contents[offset + 2] == 0xFF && file_contents[offset + 3] == 0xE0) || - (file_contents[offset] == 0x00 && file_contents[offset + 1] == 0x00 && file_contents[offset + 2] == 0x00 && file_contents[offset + 3] == 0x0C && file_contents[offset + 4] == 0x6A && file_contents[offset + 5] == 0x50)) { + (file_contents[offset] == 0x00 && file_contents[offset + 1] == 0x00 && file_contents[offset + 2] == 0x00 && file_contents[offset + 3] == 0x0C && file_contents[offset + 4] == 0x6A && file_contents[offset + 5] == 0x50)) { datalen = file_length - offset; break; } @@ -752,7 +752,7 @@ static int emrtd_dump_ef_dg7(uint8_t *file_contents, size_t file_length) { static int emrtd_dump_ef_sod(uint8_t *file_contents, size_t file_length) { int fieldlen = emrtd_get_asn1_field_length(file_contents, file_length, 1); int datalen = emrtd_get_asn1_data_length(file_contents, file_length, 1); - + if (fieldlen + 1 > EMRTD_MAX_FILE_SIZE) { PrintAndLogEx(ERR, "error (emrtd_dump_ef_sod) fieldlen out-of-bounds"); return PM3_SUCCESS; @@ -773,7 +773,7 @@ static bool emrtd_dump_file(uint8_t *ks_enc, uint8_t *ks_mac, uint8_t *ssc, cons PrintAndLogEx(INFO, "Read %s, len: %i.", name, resplen); PrintAndLogEx(DEBUG, "Contents (may be incomplete over 2k chars): %s", sprint_hex_inrow(response, resplen)); saveFile(name, ".BIN", response, resplen); - emrtd_dg_t * dg = emrtd_fileid_to_dg(file); + emrtd_dg_t *dg = emrtd_fileid_to_dg(file); if ((dg != NULL) && (dg->dumper != NULL)) { dg->dumper(response, resplen); } @@ -785,7 +785,7 @@ static void rng(int length, uint8_t *dataout) { //for (int i = 0; i < (length / 4); i++) { // num_to_bytes(prng_successor(msclock() + i, 32), 4, &dataout[i * 4]); //} - memset(dataout, 0x00, length); + memset(dataout, 0x00, length); } static bool emrtd_do_bac(char *documentnumber, char *dob, char *expiry, uint8_t *ssc, uint8_t *ks_enc, uint8_t *ks_mac, bool use_14b) { @@ -1013,7 +1013,7 @@ int dumpHF_EMRTD(char *documentnumber, char *dob, char *expiry, bool BAC_availab filelist[filelistlen++] = 0x77; // Dump all files in the file list for (int i = 0; i < filelistlen; i++) { - emrtd_dg_t * dg = emrtd_tag_to_dg(filelist[i]); + emrtd_dg_t *dg = emrtd_tag_to_dg(filelist[i]); if (dg == NULL) { PrintAndLogEx(INFO, "File tag not found, skipping: %02X", filelist[i]); continue; @@ -1034,9 +1034,9 @@ static bool emrtd_compare_check_digit(char *datain, int datalen, char expected_c uint8_t check_digit = emrtd_calculate_check_digit(tempdata) + 0x30; bool res = check_digit == expected_check_digit; PrintAndLogEx(DEBUG, "emrtd_compare_check_digit, expected %c == %c calculated ( %s )" - , expected_check_digit - , check_digit - , (res) ? _GREEN_("ok") : _RED_("fail")); + , expected_check_digit + , check_digit + , (res) ? _GREEN_("ok") : _RED_("fail")); return res; } @@ -1238,7 +1238,7 @@ static int emrtd_print_ef_com_info(uint8_t *data, size_t datalen) { PrintAndLogEx(NORMAL, ""); PrintAndLogEx(INFO, "-------------------- " _CYAN_("EF_COM") " --------------------"); for (int i = 0; i < filelistlen; i++) { - emrtd_dg_t * dg = emrtd_tag_to_dg(filelist[i]); + emrtd_dg_t *dg = emrtd_tag_to_dg(filelist[i]); if (dg == NULL) { PrintAndLogEx(INFO, "File tag not found, skipping: %02X", filelist[i]); continue; @@ -1520,7 +1520,7 @@ int infoHF_EMRTD(char *documentnumber, char *dob, char *expiry, bool BAC_availab } int res = emrtd_print_ef_com_info(response, resplen); - if ( res != PM3_SUCCESS) { + if (res != PM3_SUCCESS) { DropField(); return res; } @@ -1537,7 +1537,7 @@ int infoHF_EMRTD(char *documentnumber, char *dob, char *expiry, bool BAC_availab filelist[filelistlen++] = 0x77; // Dump all files in the file list for (int i = 0; i < filelistlen; i++) { - emrtd_dg_t * dg = emrtd_tag_to_dg(filelist[i]); + emrtd_dg_t *dg = emrtd_tag_to_dg(filelist[i]); if (dg == NULL) { PrintAndLogEx(INFO, "File tag not found, skipping: %02X", filelist[i]); continue; @@ -1570,7 +1570,7 @@ int infoHF_EMRTD_offline(const char *path) { } int res = emrtd_print_ef_com_info(data, datalen); - if ( res != PM3_SUCCESS) { + if (res != PM3_SUCCESS) { free(data); free(filepath); return res; @@ -1590,7 +1590,7 @@ int infoHF_EMRTD_offline(const char *path) { filelist[filelistlen++] = 0x77; // Read files in the file list for (int i = 0; i < filelistlen; i++) { - emrtd_dg_t * dg = emrtd_tag_to_dg(filelist[i]); + emrtd_dg_t *dg = emrtd_tag_to_dg(filelist[i]); if (dg == NULL) { PrintAndLogEx(INFO, "File tag not found, skipping: %02X", filelist[i]); continue; @@ -1599,8 +1599,7 @@ int infoHF_EMRTD_offline(const char *path) { strcpy(filepath, path); strncat(filepath, PATHSEP, 2); strcat(filepath, dg->filename); - if (loadFile_safeEx(filepath, ".BIN", (void **)&data, (size_t *)&datalen, false) == PM3_SUCCESS) - { + if (loadFile_safeEx(filepath, ".BIN", (void **)&data, (size_t *)&datalen, false) == PM3_SUCCESS) { // we won't halt on parsing errors if (dg->parser != NULL) dg->parser(data, datalen); @@ -1669,7 +1668,7 @@ static int cmd_hf_emrtd_dump(const char *Cmd) { memset(docnum + slen, '<', 9 - slen); } } - + if (CLIParamStrToBuf(arg_get_str(ctx, 2), dob, 6, &slen) != 0 || slen == 0) { BAC = false; } else { @@ -1679,7 +1678,7 @@ static int cmd_hf_emrtd_dump(const char *Cmd) { error = true; } } - + if (CLIParamStrToBuf(arg_get_str(ctx, 3), expiry, 6, &slen) != 0 || slen == 0) { BAC = false; } else { @@ -1755,7 +1754,7 @@ static int cmd_hf_emrtd_info(const char *Cmd) { memset(docnum + slen, '<', 9 - slen); } } - + if (CLIParamStrToBuf(arg_get_str(ctx, 2), dob, 6, &slen) != 0 || slen == 0) { BAC = false; } else { @@ -1765,7 +1764,7 @@ static int cmd_hf_emrtd_info(const char *Cmd) { error = true; } } - + if (CLIParamStrToBuf(arg_get_str(ctx, 3), expiry, 6, &slen) != 0 || slen == 0) { BAC = false; } else { From 62f60dbfbf13375de988dacbb2b09fda597b546e Mon Sep 17 00:00:00 2001 From: Philippe Teuwen Date: Tue, 22 Dec 2020 00:29:45 +0100 Subject: [PATCH 180/682] utf8 barmode when emoji mode is set --- client/src/ui.c | 68 +++++++++++++++++++++++++++++-------------------- 1 file changed, 40 insertions(+), 28 deletions(-) diff --git a/client/src/ui.c b/client/src/ui.c index 03ff304b2..e4b873596 100644 --- a/client/src/ui.c +++ b/client/src/ui.c @@ -626,46 +626,58 @@ void iceSimple_Filter(int *data, const size_t len, uint8_t k) { void print_progress(size_t count, uint64_t max, barMode_t style) { - #define PERCENTAGE(V, T) (100 - (((T - V) * 100) / T)) + #define PERCENTAGE(V, T) ((V * 100) / T) + // x/8 fractional part of the percentage + #define PERCENTAGEFRAC(V, T) ((int)(((((float)V * 100) / T) - ((V * 100) / T)) * 8)) -/* - typedef struct smooth_s { - const char *bar; - } smooth_t; - - static smooth_t smoothtable[] = { - {"\xe2\x96\x8F"}, - {"\xe2\x96\x8E"}, - {"\xe2\x96\x8D"}, - {"\xe2\x96\x8C"}, - {"\xe2\x96\x8B"}, - {"\xe2\x96\x8A"}, - {"\xe2\x96\x89"}, - {"\xe2\x96\x88"}, + const char *smoothtable[] = { + "\xe2\x80\x80", + "\xe2\x96\x8F", + "\xe2\x96\x8E", + "\xe2\x96\x8D", + "\xe2\x96\x8C", + "\xe2\x96\x8B", + "\xe2\x96\x8A", + "\xe2\x96\x89", + "\xe2\x96\x88", }; -*/ + uint8_t mode = session.emoji_mode == EMOJI; + const char *block[] = {"#", "\xe2\x96\x88"}; + // use a 3-byte space in emoji mode to ease computations + const char *space[] = {" ", "\xe2\x80\x80"}; + uint8_t unit = strlen(block[mode]); // +1 for \0 - char *bar = calloc(100 + 1, sizeof(uint8_t)); + char *bar = calloc(unit*100 + 1, sizeof(uint8_t)); uint8_t value = PERCENTAGE(count, max); + int i = 0; // prefix is added already. - memset(bar + strlen(bar), 0x23, value); - + for (; i < unit*value; i+=unit) { + memcpy(bar + i, block[mode], unit); + } + // add last block + if (mode == 1) { + memcpy(bar + i, smoothtable[PERCENTAGEFRAC(count, max)], unit); + } else { + memcpy(bar + i, space[mode], unit); + } + i += unit; // add spaces - memset(bar + strlen(bar), 0x2E, 100 - value); - + for (; i < unit*100; i+=unit) { + memcpy(bar + i, space[mode], unit); + } // color buffer - uint8_t collen = 100 + 1 + 40; + size_t collen = strlen(bar) + 40; char *cbar = calloc(collen, sizeof(uint8_t)); // Add colors - snprintf(cbar, collen, _GREEN_("%.*s"), 60, bar); - snprintf(cbar + strlen(cbar), collen - strlen(cbar), _CYAN_("%.*s"), 20, bar + 60); - snprintf(cbar + strlen(cbar), collen - strlen(cbar), _YELLOW_("%.*s"), 20, bar + 80); + snprintf(cbar, collen, _GREEN_("%.*s"), unit*60, bar); + snprintf(cbar + strlen(cbar), collen - strlen(cbar), _CYAN_("%.*s"), unit*20, bar + unit*60); + snprintf(cbar + strlen(cbar), collen - strlen(cbar), _YELLOW_("%.*s"), unit*20, bar + unit*80); - uint8_t len = collen + 1 + 1 + 30; + size_t len = strlen(cbar) + 32; char *buffer = calloc(len, sizeof(uint8_t)); switch(style) { @@ -685,8 +697,8 @@ void print_progress(size_t count, uint64_t max, barMode_t style) { } } - fflush(stdout); - free(buffer); + fflush(stdout); + free(buffer); free(bar); free(cbar); } From b505c5f4d8e7823c3a2c474e63e375412ec57505 Mon Sep 17 00:00:00 2001 From: Ave Date: Tue, 22 Dec 2020 05:01:42 +0300 Subject: [PATCH 181/682] emrtd: Read file hash data from EF_SOD --- client/src/cmdhfemrtd.c | 76 ++++++++++++++++++++++++++++++++++++----- 1 file changed, 68 insertions(+), 8 deletions(-) diff --git a/client/src/cmdhfemrtd.c b/client/src/cmdhfemrtd.c index d0b3527af..4e3bfc575 100644 --- a/client/src/cmdhfemrtd.c +++ b/client/src/cmdhfemrtd.c @@ -203,9 +203,9 @@ static char emrtd_calculate_check_digit(char *data) { } static int emrtd_get_asn1_data_length(uint8_t *datain, int datainlen, int offset) { - PrintAndLogEx(DEBUG, "asn1datalength, datain: %s", sprint_hex_inrow(datain, datainlen)); + PrintAndLogEx(DEBUG, "asn1 datalength, datain: %s", sprint_hex_inrow(datain, datainlen)); int lenfield = (int) * (datain + offset); - PrintAndLogEx(DEBUG, "asn1datalength, lenfield: %i", lenfield); + PrintAndLogEx(DEBUG, "asn1 datalength, lenfield: %02X", lenfield); if (lenfield <= 0x7f) { return lenfield; } else if (lenfield == 0x81) { @@ -221,7 +221,7 @@ static int emrtd_get_asn1_data_length(uint8_t *datain, int datainlen, int offset static int emrtd_get_asn1_field_length(uint8_t *datain, int datainlen, int offset) { PrintAndLogEx(DEBUG, "asn1 fieldlength, datain: %s", sprint_hex_inrow(datain, datainlen)); int lenfield = (int) * (datain + offset); - PrintAndLogEx(DEBUG, "asn1 fieldlength, thing: %i", lenfield); + PrintAndLogEx(DEBUG, "asn1 fieldlength, lenfield: %02X", lenfield); if (lenfield <= 0x7F) { return 1; } else if (lenfield == 0x81) { @@ -629,10 +629,10 @@ static int emrtd_lds_determine_tag_length(uint8_t tag) { return 1; } -static bool emrtd_lds_get_data_by_tag(uint8_t *datain, int datainlen, uint8_t *dataout, int *dataoutlen, int tag1, int tag2, bool twobytetag, bool skiptoptag) { +static bool emrtd_lds_get_data_by_tag(uint8_t *datain, int datainlen, uint8_t *dataout, int *dataoutlen, int tag1, int tag2, bool twobytetag, bool entertoptag) { int offset = 0; - if (skiptoptag) { + if (entertoptag) { offset += emrtd_lds_determine_tag_length(*datain); offset += emrtd_get_asn1_field_length(datain, datainlen, offset); } @@ -651,6 +651,8 @@ static bool emrtd_lds_get_data_by_tag(uint8_t *datain, int datainlen, uint8_t *d // Get the length of the element's length e_fieldlen = emrtd_get_asn1_field_length(datain + offset, datainlen - offset, e_idlen); + PrintAndLogEx(DEBUG, "emrtd_lds_get_data_by_tag, e_idlen: %02X, e_datalen: %02X, e_fieldlen: %02X", e_idlen, e_datalen, e_fieldlen); + // If the element is what we're looking for, get the data and return true if (*(datain + offset) == tag1 && (!twobytetag || *(datain + offset + 1) == tag2)) { if (datainlen > e_datalen) { @@ -1477,10 +1479,68 @@ static int emrtd_print_ef_dg12_info(uint8_t *data, size_t datalen) { return PM3_SUCCESS; } +static int emrtd_ef_sod_extract_signatures(uint8_t *data, size_t datalen, uint8_t *dataout, size_t *dataoutlen) { + // very very very very cursed code. + uint8_t top[EMRTD_MAX_FILE_SIZE] = { 0x00 }; + uint8_t signeddata[EMRTD_MAX_FILE_SIZE] = { 0x00 }; + uint8_t emrtdsigcontainer[EMRTD_MAX_FILE_SIZE] = { 0x00 }; + uint8_t emrtdsig[EMRTD_MAX_FILE_SIZE] = { 0x00 }; + uint8_t emrtdsigtext[EMRTD_MAX_FILE_SIZE] = { 0x00 }; + size_t toplen, signeddatalen, emrtdsigcontainerlen, emrtdsiglen, emrtdsigtextlen = 0; + + if (!emrtd_lds_get_data_by_tag(data, (int) datalen, top, (int *) &toplen, 0x30, 0x00, false, true)) { + PrintAndLogEx(ERR, "Failed to read top from EF_SOD."); + return false; + } + + PrintAndLogEx(DEBUG, "top: %s.", sprint_hex_inrow(top, toplen)); + + if (!emrtd_lds_get_data_by_tag(top, (int) toplen, signeddata, (int *) &signeddatalen, 0xA0, 0x00, false, false)) { + PrintAndLogEx(ERR, "Failed to read signedData from EF_SOD."); + return false; + } + + PrintAndLogEx(DEBUG, "signeddata: %s.", sprint_hex_inrow(signeddata, signeddatalen)); + + // Do true on reading into the tag as it's a "sequence" + if (!emrtd_lds_get_data_by_tag(signeddata, (int) signeddatalen, emrtdsigcontainer, (int *) &emrtdsigcontainerlen, 0x30, 0x00, false, true)) { + PrintAndLogEx(ERR, "Failed to read eMRTDSignature container from EF_SOD."); + return false; + } + + PrintAndLogEx(DEBUG, "emrtdsigcontainer: %s.", sprint_hex_inrow(emrtdsigcontainer, emrtdsigcontainerlen)); + + if (!emrtd_lds_get_data_by_tag(emrtdsigcontainer, (int) emrtdsigcontainerlen, emrtdsig, (int *) &emrtdsiglen, 0xA0, 0x00, false, false)) { + PrintAndLogEx(ERR, "Failed to read eMRTDSignature from EF_SOD."); + return false; + } + + PrintAndLogEx(DEBUG, "emrtdsig: %s.", sprint_hex_inrow(emrtdsig, emrtdsiglen)); + + // TODO: Not doing memcpy here, it didn't work, fix it somehow + if (!emrtd_lds_get_data_by_tag(emrtdsig, (int) emrtdsiglen, emrtdsigtext, (int *) &emrtdsigtextlen, 0x04, 0x00, false, false)) { + PrintAndLogEx(ERR, "Failed to read eMRTDSignature (text) from EF_SOD."); + return false; + } + memcpy(dataout, emrtdsigtext, emrtdsigtextlen); + *dataoutlen = emrtdsigtextlen; + return PM3_SUCCESS; +} + static int emrtd_print_ef_sod_info(uint8_t *data, size_t datalen) { -// PrintAndLogEx(NORMAL, ""); -// PrintAndLogEx(INFO, "-------------------- " _CYAN_("EF_SOD") " --------------------"); -// PrintAndLogEx(WARNING, "TODO"); + uint8_t emrtdsig[EMRTD_MAX_FILE_SIZE] = { 0x00 }; + // size_t emrtdsiglen, e_datalen, e_fieldlen = 0; + size_t emrtdsiglen = 0; + + PrintAndLogEx(NORMAL, ""); + PrintAndLogEx(INFO, "-------------------- " _CYAN_("EF_SOD") " --------------------"); + + if (emrtd_ef_sod_extract_signatures(data, datalen, emrtdsig, &emrtdsiglen) != PM3_SUCCESS) { + return false; + } + // TODO: parse this + PrintAndLogEx(INFO, "hash data: %s", sprint_hex_inrow(emrtdsig, emrtdsiglen)); + return PM3_SUCCESS; } From f1a8345faccca4e18795c7c9e9fab1ca39a1aa70 Mon Sep 17 00:00:00 2001 From: Ave Date: Tue, 22 Dec 2020 05:29:37 +0300 Subject: [PATCH 182/682] emrtd: Add a skip feature to emrtd_lds_get_data_by_tag --- client/src/cmdhfemrtd.c | 39 +++++++++++++++++++++------------------ 1 file changed, 21 insertions(+), 18 deletions(-) diff --git a/client/src/cmdhfemrtd.c b/client/src/cmdhfemrtd.c index 4e3bfc575..d92dfb19a 100644 --- a/client/src/cmdhfemrtd.c +++ b/client/src/cmdhfemrtd.c @@ -629,8 +629,9 @@ static int emrtd_lds_determine_tag_length(uint8_t tag) { return 1; } -static bool emrtd_lds_get_data_by_tag(uint8_t *datain, int datainlen, uint8_t *dataout, int *dataoutlen, int tag1, int tag2, bool twobytetag, bool entertoptag) { +static bool emrtd_lds_get_data_by_tag(uint8_t *datain, int datainlen, uint8_t *dataout, int *dataoutlen, int tag1, int tag2, bool twobytetag, bool entertoptag, int skiptagcount) { int offset = 0; + int skipcounter = 0; if (entertoptag) { offset += emrtd_lds_determine_tag_length(*datain); @@ -655,7 +656,9 @@ static bool emrtd_lds_get_data_by_tag(uint8_t *datain, int datainlen, uint8_t *d // If the element is what we're looking for, get the data and return true if (*(datain + offset) == tag1 && (!twobytetag || *(datain + offset + 1) == tag2)) { - if (datainlen > e_datalen) { + if (skipcounter < skiptagcount) { + skipcounter += 1; + } else if (datainlen > e_datalen) { *dataoutlen = e_datalen; memcpy(dataout, datain + offset + e_idlen + e_fieldlen, e_datalen); return true; @@ -720,7 +723,7 @@ static int emrtd_dump_ef_dg5(uint8_t *file_contents, size_t file_length) { int datalen = 0; // If we can't find image in EF_DG5, return false. - if (emrtd_lds_get_data_by_tag(file_contents, file_length, data, &datalen, 0x5F, 0x40, true, true) == false) { + if (emrtd_lds_get_data_by_tag(file_contents, file_length, data, &datalen, 0x5F, 0x40, true, true, 0) == false) { return PM3_ESOFT; } @@ -738,7 +741,7 @@ static int emrtd_dump_ef_dg7(uint8_t *file_contents, size_t file_length) { int datalen = 0; // If we can't find image in EF_DG7, return false. - if (emrtd_lds_get_data_by_tag(file_contents, file_length, data, &datalen, 0x5F, 0x42, true, true) == false) { + if (emrtd_lds_get_data_by_tag(file_contents, file_length, data, &datalen, 0x5F, 0x42, true, true, 0) == false) { return PM3_ESOFT; } @@ -1004,7 +1007,7 @@ int dumpHF_EMRTD(char *documentnumber, char *dob, char *expiry, bool BAC_availab uint8_t filelist[50]; int filelistlen = 0; - if (!emrtd_lds_get_data_by_tag(response, resplen, filelist, &filelistlen, 0x5c, 0x00, false, true)) { + if (!emrtd_lds_get_data_by_tag(response, resplen, filelist, &filelistlen, 0x5c, 0x00, false, true, 0)) { PrintAndLogEx(ERR, "Failed to read file list from EF_COM."); DropField(); return PM3_ESOFT; @@ -1230,7 +1233,7 @@ static void emrtd_print_unknown_timestamp_5f85(uint8_t *data) { static int emrtd_print_ef_com_info(uint8_t *data, size_t datalen) { uint8_t filelist[50]; int filelistlen = 0; - int res = emrtd_lds_get_data_by_tag(data, datalen, filelist, &filelistlen, 0x5c, 0x00, false, true); + int res = emrtd_lds_get_data_by_tag(data, datalen, filelist, &filelistlen, 0x5c, 0x00, false, true, 0); if (!res) { PrintAndLogEx(ERR, "Failed to read file list from EF_COM."); return PM3_ESOFT; @@ -1261,7 +1264,7 @@ static int emrtd_print_ef_dg1_info(uint8_t *data, size_t datalen) { char mrz[90] = { 0x00 }; int mrzlen = 0; - if (!emrtd_lds_get_data_by_tag(data, datalen, (uint8_t *) mrz, &mrzlen, 0x5f, 0x1f, true, true)) { + if (!emrtd_lds_get_data_by_tag(data, datalen, (uint8_t *) mrz, &mrzlen, 0x5f, 0x1f, true, true, 0)) { PrintAndLogEx(ERR, "Failed to read MRZ from EF_DG1."); return PM3_ESOFT; } @@ -1343,13 +1346,13 @@ static int emrtd_print_ef_dg11_info(uint8_t *data, size_t datalen) { PrintAndLogEx(NORMAL, ""); PrintAndLogEx(INFO, "-------------------- " _CYAN_("EF_DG11") " -------------------"); - if (!emrtd_lds_get_data_by_tag(data, datalen, taglist, &taglistlen, 0x5c, 0x00, false, true)) { + if (!emrtd_lds_get_data_by_tag(data, datalen, taglist, &taglistlen, 0x5c, 0x00, false, true, 0)) { PrintAndLogEx(ERR, "Failed to read file list from EF_DG11."); return PM3_ESOFT; } for (int i = 0; i < taglistlen; i++) { - emrtd_lds_get_data_by_tag(data, datalen, tagdata, &tagdatalen, taglist[i], taglist[i + 1], taglist[i] == 0x5f, true); + emrtd_lds_get_data_by_tag(data, datalen, tagdata, &tagdatalen, taglist[i], taglist[i + 1], taglist[i] == 0x5f, true, 0); // Don't bother with empty tags if (tagdatalen == 0) { continue; @@ -1422,13 +1425,13 @@ static int emrtd_print_ef_dg12_info(uint8_t *data, size_t datalen) { PrintAndLogEx(NORMAL, ""); PrintAndLogEx(INFO, "-------------------- " _CYAN_("EF_DG12") " -------------------"); - if (!emrtd_lds_get_data_by_tag(data, datalen, taglist, &taglistlen, 0x5c, 0x00, false, true)) { + if (!emrtd_lds_get_data_by_tag(data, datalen, taglist, &taglistlen, 0x5c, 0x00, false, true, 0)) { PrintAndLogEx(ERR, "Failed to read file list from EF_DG12."); return PM3_ESOFT; } for (int i = 0; i < taglistlen; i++) { - emrtd_lds_get_data_by_tag(data, datalen, tagdata, &tagdatalen, taglist[i], taglist[i + 1], taglist[i] == 0x5f, true); + emrtd_lds_get_data_by_tag(data, datalen, tagdata, &tagdatalen, taglist[i], taglist[i + 1], taglist[i] == 0x5f, true, 0); // Don't bother with empty tags if (tagdatalen == 0) { continue; @@ -1488,14 +1491,14 @@ static int emrtd_ef_sod_extract_signatures(uint8_t *data, size_t datalen, uint8_ uint8_t emrtdsigtext[EMRTD_MAX_FILE_SIZE] = { 0x00 }; size_t toplen, signeddatalen, emrtdsigcontainerlen, emrtdsiglen, emrtdsigtextlen = 0; - if (!emrtd_lds_get_data_by_tag(data, (int) datalen, top, (int *) &toplen, 0x30, 0x00, false, true)) { + if (!emrtd_lds_get_data_by_tag(data, (int) datalen, top, (int *) &toplen, 0x30, 0x00, false, true, 0)) { PrintAndLogEx(ERR, "Failed to read top from EF_SOD."); return false; } PrintAndLogEx(DEBUG, "top: %s.", sprint_hex_inrow(top, toplen)); - if (!emrtd_lds_get_data_by_tag(top, (int) toplen, signeddata, (int *) &signeddatalen, 0xA0, 0x00, false, false)) { + if (!emrtd_lds_get_data_by_tag(top, (int) toplen, signeddata, (int *) &signeddatalen, 0xA0, 0x00, false, false, 0)) { PrintAndLogEx(ERR, "Failed to read signedData from EF_SOD."); return false; } @@ -1503,14 +1506,14 @@ static int emrtd_ef_sod_extract_signatures(uint8_t *data, size_t datalen, uint8_ PrintAndLogEx(DEBUG, "signeddata: %s.", sprint_hex_inrow(signeddata, signeddatalen)); // Do true on reading into the tag as it's a "sequence" - if (!emrtd_lds_get_data_by_tag(signeddata, (int) signeddatalen, emrtdsigcontainer, (int *) &emrtdsigcontainerlen, 0x30, 0x00, false, true)) { + if (!emrtd_lds_get_data_by_tag(signeddata, (int) signeddatalen, emrtdsigcontainer, (int *) &emrtdsigcontainerlen, 0x30, 0x00, false, true, 0)) { PrintAndLogEx(ERR, "Failed to read eMRTDSignature container from EF_SOD."); return false; } PrintAndLogEx(DEBUG, "emrtdsigcontainer: %s.", sprint_hex_inrow(emrtdsigcontainer, emrtdsigcontainerlen)); - if (!emrtd_lds_get_data_by_tag(emrtdsigcontainer, (int) emrtdsigcontainerlen, emrtdsig, (int *) &emrtdsiglen, 0xA0, 0x00, false, false)) { + if (!emrtd_lds_get_data_by_tag(emrtdsigcontainer, (int) emrtdsigcontainerlen, emrtdsig, (int *) &emrtdsiglen, 0xA0, 0x00, false, false, 0)) { PrintAndLogEx(ERR, "Failed to read eMRTDSignature from EF_SOD."); return false; } @@ -1518,7 +1521,7 @@ static int emrtd_ef_sod_extract_signatures(uint8_t *data, size_t datalen, uint8_ PrintAndLogEx(DEBUG, "emrtdsig: %s.", sprint_hex_inrow(emrtdsig, emrtdsiglen)); // TODO: Not doing memcpy here, it didn't work, fix it somehow - if (!emrtd_lds_get_data_by_tag(emrtdsig, (int) emrtdsiglen, emrtdsigtext, (int *) &emrtdsigtextlen, 0x04, 0x00, false, false)) { + if (!emrtd_lds_get_data_by_tag(emrtdsig, (int) emrtdsiglen, emrtdsigtext, (int *) &emrtdsigtextlen, 0x04, 0x00, false, false, 0)) { PrintAndLogEx(ERR, "Failed to read eMRTDSignature (text) from EF_SOD."); return false; } @@ -1588,7 +1591,7 @@ int infoHF_EMRTD(char *documentnumber, char *dob, char *expiry, bool BAC_availab uint8_t filelist[50]; int filelistlen = 0; - if (!emrtd_lds_get_data_by_tag(response, resplen, filelist, &filelistlen, 0x5c, 0x00, false, true)) { + if (!emrtd_lds_get_data_by_tag(response, resplen, filelist, &filelistlen, 0x5c, 0x00, false, true, 0)) { PrintAndLogEx(ERR, "Failed to read file list from EF_COM."); DropField(); return PM3_ESOFT; @@ -1638,7 +1641,7 @@ int infoHF_EMRTD_offline(const char *path) { uint8_t filelist[50]; int filelistlen = 0; - res = emrtd_lds_get_data_by_tag(data, datalen, filelist, &filelistlen, 0x5c, 0x00, false, true); + res = emrtd_lds_get_data_by_tag(data, datalen, filelist, &filelistlen, 0x5c, 0x00, false, true, 0); if (!res) { PrintAndLogEx(ERR, "Failed to read file list from EF_COM."); free(data); From c3ed99e3883c04a0e0aef09128605cb5adce9a02 Mon Sep 17 00:00:00 2001 From: Ave Date: Tue, 22 Dec 2020 05:52:48 +0300 Subject: [PATCH 183/682] emrtd: Parse hashes on EF_SOD --- client/src/cmdhfemrtd.c | 40 ++++++++++++++++++++++++++++++++++++++-- 1 file changed, 38 insertions(+), 2 deletions(-) diff --git a/client/src/cmdhfemrtd.c b/client/src/cmdhfemrtd.c index d92dfb19a..3203b4932 100644 --- a/client/src/cmdhfemrtd.c +++ b/client/src/cmdhfemrtd.c @@ -1532,8 +1532,19 @@ static int emrtd_ef_sod_extract_signatures(uint8_t *data, size_t datalen, uint8_ static int emrtd_print_ef_sod_info(uint8_t *data, size_t datalen) { uint8_t emrtdsig[EMRTD_MAX_FILE_SIZE] = { 0x00 }; + uint8_t hashlist[EMRTD_MAX_FILE_SIZE] = { 0x00 }; + uint8_t hash[65] = { 0x00 }; + size_t hashlen = 0; + + uint8_t hashidstr[4] = { 0x00 }; + size_t hashidstrlen = 0; + // size_t emrtdsiglen, e_datalen, e_fieldlen = 0; size_t emrtdsiglen = 0; + size_t hashlistlen = 0; + size_t e_datalen = 0; + size_t e_fieldlen = 0; + size_t offset = 0; PrintAndLogEx(NORMAL, ""); PrintAndLogEx(INFO, "-------------------- " _CYAN_("EF_SOD") " --------------------"); @@ -1541,8 +1552,33 @@ static int emrtd_print_ef_sod_info(uint8_t *data, size_t datalen) { if (emrtd_ef_sod_extract_signatures(data, datalen, emrtdsig, &emrtdsiglen) != PM3_SUCCESS) { return false; } - // TODO: parse this - PrintAndLogEx(INFO, "hash data: %s", sprint_hex_inrow(emrtdsig, emrtdsiglen)); + + PrintAndLogEx(DEBUG, "hash data: %s", sprint_hex_inrow(emrtdsig, emrtdsiglen)); + + if (!emrtd_lds_get_data_by_tag(emrtdsig, (int) emrtdsiglen, hashlist, (int *) &hashlistlen, 0x30, 0x00, false, true, 1)) { + PrintAndLogEx(ERR, "Failed to read hash list from EF_SOD."); + return false; + } + + PrintAndLogEx(DEBUG, "hash list: %s", sprint_hex_inrow(hashlist, hashlistlen)); + + while (offset < hashlistlen) { + // Get the length of the element + e_datalen = emrtd_get_asn1_data_length(hashlist + offset, hashlistlen - offset, 1); + + // Get the length of the element's length + e_fieldlen = emrtd_get_asn1_field_length(hashlist + offset, hashlistlen - offset, 1); + + switch (hashlist[offset]) { + case 0x30: + emrtd_lds_get_data_by_tag(hashlist + offset + e_fieldlen + 1, (int) e_datalen, hashidstr, (int *) &hashidstrlen, 0x02, 0x00, false, false, 0); + emrtd_lds_get_data_by_tag(hashlist + offset + e_fieldlen + 1, (int) e_datalen, hash, (int *) &hashlen, 0x04, 0x00, false, false, 0); + PrintAndLogEx(SUCCESS, "Hash for EF_DG%i: %s", hashidstr[0], sprint_hex_inrow(hash, hashlen)); + break; + } + // + 1 for length of ID + offset += 1 + e_datalen + e_fieldlen; + } return PM3_SUCCESS; } From 69e5f8daa5a613f99bddf3296aacc53457e2dc61 Mon Sep 17 00:00:00 2001 From: iceman1001 Date: Tue, 22 Dec 2020 22:56:57 +0100 Subject: [PATCH 184/682] update the readline to 8.1 and curses to 6.1. The later version 6.2 fails when cross compiling. Thanks @doegox for verifying cross compiling --- client/CMakeLists.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/client/CMakeLists.txt b/client/CMakeLists.txt index c67104158..ec1a28e60 100644 --- a/client/CMakeLists.txt +++ b/client/CMakeLists.txt @@ -82,7 +82,7 @@ if (NOT SKIPREADLINE EQUAL 1) endif (APPLE) if (EMBED_READLINE) ExternalProject_Add(ncurses - URL http://ftp.gnu.org/pub/gnu/ncurses/ncurses-6.0.tar.gz + URL http://ftp.gnu.org/pub/gnu/ncurses/ncurses-6.1.tar.gz PREFIX deps/ncurses DOWNLOAD_DIR ${CMAKE_CURRENT_SOURCE_DIR}/deps/ncurses CONFIGURE_COMMAND ./configure CC=${CMAKE_C_COMPILER} CXX=${CMAKE_CXX_COMPILER} LD=${CMAKE_C_COMPILER} AR=${CMAKE_AR} RANLIB=${CMAKE_RANLIB} ${CFLAGS_EXTERNAL_LIB} --host=arm --disable-database --with-fallbacks=ansi-generic,ansi-mini,color_xterm,dtterm,dumb,Eterm,Eterm-256color,Eterm-88color,eterm-color,gnome,gnome-256color,guru,hurd,iTerm.app,konsole,konsole-16color,konsole-256color,konsole-base,konsole-linux,konsole-solaris,konsole-vt100,kterm,kterm-color,linux,linux-16color,linux-basic,mac,mlterm,mlterm-256color,mrxvt,mrxvt-256color,mterm,mterm-ansi,mvterm,nsterm,nsterm-16color,nsterm-256color,pty,putty,putty-256color,putty-vt100,rxvt,rxvt-16color,rxvt-256color,rxvt-88color,rxvt-basic,rxvt-color,screen,screen-16color,screen-256color,simpleterm,st-16color,st-256color,st52,st52-color,stv52,tt,tt52,unknown,vt100,vt102,vte,vte-256color,xterm,xterm-16color,xterm-256color,xterm-88color,xterm-basic,xterm-bold,xterm-color,xterm-utf8,xterm-vt220,xterm-vt52,xterm1,xtermc,xtermm --enable-termcap --without-ada --without-debug --without-dlsym --without-gpm --without-develop --without-tests --without-cxx-binding --with-termlib @@ -94,7 +94,7 @@ if (NOT SKIPREADLINE EQUAL 1) ExternalProject_Add_StepTargets(ncurses configure build install) ExternalProject_Add(readline - URL ftp://ftp.gnu.org/gnu/readline/readline-7.0.tar.gz + URL ftp://ftp.gnu.org/gnu/readline/readline-8.1.tar.gz PREFIX deps/readline DOWNLOAD_DIR ${CMAKE_CURRENT_SOURCE_DIR}/deps/readline CONFIGURE_COMMAND ./configure CC=${CMAKE_C_COMPILER} CXX=${CMAKE_CXX_COMPILER} LD=${CMAKE_C_COMPILER} AR=${CMAKE_AR} RANLIB=${CMAKE_RANLIB} ${CFLAGS_EXTERNAL_LIB} --host=arm --enable-static From 59e3c31e0f8fa2750d51e0497d009c08b980ef59 Mon Sep 17 00:00:00 2001 From: tcprst Date: Tue, 22 Dec 2020 20:09:19 -0500 Subject: [PATCH 185/682] hf fido info - now use cliparser --- client/src/cmdhffido.c | 14 +++++++++++--- doc/cliparser_todo.txt | 1 - 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/client/src/cmdhffido.c b/client/src/cmdhffido.c index 7535a5ef4..d3ea8e1cb 100644 --- a/client/src/cmdhffido.c +++ b/client/src/cmdhffido.c @@ -48,10 +48,18 @@ static int cmd_hf_fido_list(const char *Cmd) { return CmdTraceList(args); } -static int cmd_hf_fido_info(const char *cmd) { +static int cmd_hf_fido_info(const char *Cmd) { + CLIParserContext *ctx; + CLIParserInit(&ctx, "hf fido info", + "Get info from Fido tags", + "hf fido info"); - if (cmd && strlen(cmd) > 0) - PrintAndLogEx(WARNING, "WARNING: command doesn't have any parameters.\n"); + void *argtable[] = { + arg_param_begin, + arg_param_end + }; + CLIExecWithReturn(ctx, Cmd, argtable, true); + CLIParserFree(ctx); // info about 14a part infoHF14A(false, false, false); diff --git a/doc/cliparser_todo.txt b/doc/cliparser_todo.txt index daad348a5..69a96a479 100644 --- a/doc/cliparser_todo.txt +++ b/doc/cliparser_todo.txt @@ -73,7 +73,6 @@ hf felica rqspecver hf felica resetmode hf felica litesim hf felica litedump -hf fido info hf mf darkside hf mf nested hf mf hardnested From dbf2ce6074941d5577901fb8c90b79194bb0eb9f Mon Sep 17 00:00:00 2001 From: tcprst Date: Tue, 22 Dec 2020 20:15:19 -0500 Subject: [PATCH 186/682] fix double import --- client/src/cmdhficlass.c | 1 - 1 file changed, 1 deletion(-) diff --git a/client/src/cmdhficlass.c b/client/src/cmdhficlass.c index 0d182d9c3..b4b2f4245 100644 --- a/client/src/cmdhficlass.c +++ b/client/src/cmdhficlass.c @@ -18,7 +18,6 @@ #include "cmdparser.h" // command_t #include "commonutil.h" // ARRAYLEN #include "cmdtrace.h" -#include "cliparser.h" #include "util_posix.h" #include "comms.h" #include "des.h" From 4c82cc4436ff3932455df0d4a703b6b9b6f5e41e Mon Sep 17 00:00:00 2001 From: tcprst Date: Tue, 22 Dec 2020 20:52:18 -0500 Subject: [PATCH 187/682] hf epa - now use cliparser --- client/src/cmdhfepa.c | 128 +++++++++++++++++++---------------------- doc/cliparser_todo.txt | 2 - doc/commands.md | 50 ++++++++++------ 3 files changed, 90 insertions(+), 90 deletions(-) diff --git a/client/src/cmdhfepa.c b/client/src/cmdhfepa.c index 83f347604..21b896032 100644 --- a/client/src/cmdhfepa.c +++ b/client/src/cmdhfepa.c @@ -15,7 +15,7 @@ #include #include #include // tolower - +#include "cliparser.h" #include "cmdparser.h" // command_t #include "commonutil.h" // ARRAYLEN #include "comms.h" // clearCommandBuffer @@ -24,35 +24,28 @@ static int CmdHelp(const char *Cmd); -static int usage_epa_collect(void) { - PrintAndLogEx(NORMAL, "Tries to collect nonces when doing part of PACE protocol.\n" - "\n" - "Usage: hf epa cnonces \n" - "Options:\n" - "\t nonce size\n" - "\t number of nonces to collect\n" - "\t delay between\n" - "\n" - "Example:\n" - _YELLOW_("\thf epa cnonces 4 4 1") - ); - return PM3_SUCCESS; -} - // Perform (part of) the PACE protocol static int CmdHFEPACollectPACENonces(const char *Cmd) { + CLIParserContext *ctx; + CLIParserInit(&ctx, "hf epa cnonces", + "Tries to collect nonces when doing part of PACE protocol.", + "hf epa cnonces --size 4 --num 4 --delay 1"); - char cmdp = tolower(param_getchar(Cmd, 0)); - if (cmdp == 'h') return usage_epa_collect(); + void *argtable[] = { + arg_param_begin, + arg_int1(NULL, "size", "", "nonce size"), + arg_int1(NULL, "num", "", "number of nonces to collect"), + arg_int1("d", "delay", "", "delay between attempts"), + arg_param_end + }; + CLIExecWithReturn(ctx, Cmd, argtable, false); - // requested nonce size - uint32_t m = 0; - // requested number of Nonces - uint32_t n = 0; - // delay between requests - uint32_t d = 0; - sscanf(Cmd, "%u %u %u", &m, &n, &d); + int m = arg_get_int_def(ctx, 1, 0); + int n = arg_get_int_def(ctx, 2, 0); + int d = arg_get_int_def(ctx, 3, 0); + + CLIParserFree(ctx); // values are expected to be > 0 m = m > 0 ? m : 1; @@ -99,54 +92,51 @@ static int CmdHFEPACollectPACENonces(const char *Cmd) { // perform the PACE protocol by replaying APDUs static int CmdHFEPAPACEReplay(const char *Cmd) { - // the 4 APDUs which are replayed + their lengths - uint8_t msesa_apdu[41] = {0}, gn_apdu[8] = {0}, map_apdu[75] = {0}; - uint8_t pka_apdu[75] = {0}, ma_apdu[18] = {0}, apdu_lengths[5] = {0}; + CLIParserContext *ctx; + CLIParserInit(&ctx, "hf epa preplay", + "Perform PACE protocol by replaying given APDUs", + "hf epa preplay --mse 0022C1A4 --get 1068000000 --map 1086000002 --pka 1234ABCDEF --ma 1A2B3C4D"); + + void *argtable[] = { + arg_param_begin, + arg_str1(NULL, "mse", "", "msesa APDU"), + arg_str1(NULL, "get", "", "gn APDU"), + arg_str1(NULL, "map", "", "map APDU"), + arg_str1(NULL, "pka", "", "pka APDU"), + arg_str1(NULL, "ma", "", "ma APDU"), + arg_param_end + }; + CLIExecWithReturn(ctx, Cmd, argtable, false); + + int msesa_len = 0; + uint8_t msesa_apdu[41] = {0}; + CLIGetHexWithReturn(ctx, 1, msesa_apdu, &msesa_len); + + int gn_len = 0; + uint8_t gn_apdu[8] = {0}; + CLIGetHexWithReturn(ctx, 2, gn_apdu, &gn_len); + + int map_len = 0; + uint8_t map_apdu[75] = {0}; + CLIGetHexWithReturn(ctx, 3, map_apdu, &map_len); + + int pka_len = 0; + uint8_t pka_apdu[75] = {0}; + CLIGetHexWithReturn(ctx, 4, pka_apdu, &pka_len); + + int ma_len = 0; + uint8_t ma_apdu[18] = {0}; + CLIGetHexWithReturn(ctx, 5, ma_apdu, &ma_len); + + CLIParserFree(ctx); + + uint8_t apdu_lengths[5] = {msesa_len, gn_len, map_len, pka_len, ma_len}; // pointers to the arrays to be able to iterate uint8_t *apdus[] = {msesa_apdu, gn_apdu, map_apdu, pka_apdu, ma_apdu}; - // usage message - static const char *usage_msg = - "Please specify 5 APDUs separated by spaces. " - "Example:\n preplay 0022C1A4 1068000000 1086000002 1234ABCDEF 1A2B3C4D"; - // Proxmark response PacketResponseNG resp; - int skip = 0, skip_add = 0, scan_return; - // for each APDU - for (int i = 0; i < ARRAYLEN(apdu_lengths); i++) { - // scan to next space or end of string - while (Cmd[skip] != ' ' && Cmd[skip] != '\0') { - // convert - scan_return = sscanf(Cmd + skip, - "%2" SCNx8 "%n", - apdus[i] + apdu_lengths[i], - &skip_add - ); - - if (scan_return < 1) { - PrintAndLogEx(INFO, (char *)usage_msg); - PrintAndLogEx(WARNING, "Not enough APDUs! Try again!"); - return PM3_SUCCESS; - } - skip += skip_add; - apdu_lengths[i]++; - } - - // break on EOF - if (Cmd[skip] == '\0') { - if (i < ARRAYLEN(apdu_lengths) - 1) { - - PrintAndLogEx(INFO, (char *)usage_msg); - return PM3_SUCCESS; - } - break; - } - // skip the space - skip++; - } - // transfer the APDUs to the Proxmark uint8_t data[PM3_CMD_DATA_SIZE]; // fast push mode @@ -205,8 +195,8 @@ static int CmdHFEPAPACEReplay(const char *Cmd) { static command_t CommandTable[] = { {"help", CmdHelp, AlwaysAvailable, "This help"}, - {"cnonces", CmdHFEPACollectPACENonces, IfPm3Iso14443, " Acquire n>0 encrypted PACE nonces of size m>0 with d sec pauses"}, - {"preplay", CmdHFEPAPACEReplay, IfPm3Iso14443, " Perform PACE protocol by replaying given APDUs"}, + {"cnonces", CmdHFEPACollectPACENonces, IfPm3Iso14443, "Acquire encrypted PACE nonces of specific size"}, + {"preplay", CmdHFEPAPACEReplay, IfPm3Iso14443, "Perform PACE protocol by replaying given APDUs"}, {NULL, NULL, NULL, NULL} }; diff --git a/doc/cliparser_todo.txt b/doc/cliparser_todo.txt index 69a96a479..7e333911b 100644 --- a/doc/cliparser_todo.txt +++ b/doc/cliparser_todo.txt @@ -56,8 +56,6 @@ hf 15 restore hf 15 wrbl hf 15 writeafi hf 15 writedsfid -hf epa cnonces -hf epa preplay hf felica reader hf felica sniff hf felica raw diff --git a/doc/commands.md b/doc/commands.md index 7bc9342c5..991f4a590 100644 --- a/doc/commands.md +++ b/doc/commands.md @@ -126,7 +126,7 @@ Check column "offline" for their availability. ### hf 14a - { ISO14443A RFIDs... } + { ISO14443A RFIDs... } |command |offline |description |------- |------- |----------- @@ -147,7 +147,7 @@ Check column "offline" for their availability. ### hf 14b - { ISO14443B RFIDs... } + { ISO14443B RFIDs... } |command |offline |description |------- |------- |----------- @@ -167,7 +167,7 @@ Check column "offline" for their availability. ### hf 15 - { ISO15693 RFIDs... } + { ISO15693 RFIDs... } |command |offline |description |------- |------- |----------- @@ -193,18 +193,30 @@ Check column "offline" for their availability. ### hf epa - { German Identification Card... } + { German Identification Card... } |command |offline |description |------- |------- |----------- |`hf epa help `|Y |`This help` -|`hf epa cnonces `|N |` Acquire n>0 encrypted PACE nonces of size m>0 with d sec pauses` -|`hf epa preplay `|N |` Perform PACE protocol by replaying given APDUs` +|`hf epa cnonces `|N |`Acquire encrypted PACE nonces of specific size` +|`hf epa preplay `|N |`Perform PACE protocol by replaying given APDUs` + + +### hf emrtd + + { Machine Readable Travel Document... } + +|command |offline |description +|------- |------- |----------- +|`hf emrtd help `|Y |`This help` +|`hf emrtd dump `|N |`Dump eMRTD files to binary files` +|`hf emrtd info `|Y |`Display info about an eMRTD` +|`hf emrtd list `|Y |`List ISO 14443A/7816 history` ### hf felica - { ISO18092 / FeliCa RFIDs... } + { ISO18092 / FeliCa RFIDs... } |command |offline |description |------- |------- |----------- @@ -229,7 +241,7 @@ Check column "offline" for their availability. ### hf fido - { FIDO and FIDO2 authenticators... } + { FIDO and FIDO2 authenticators... } |command |offline |description |------- |------- |----------- @@ -244,7 +256,7 @@ Check column "offline" for their availability. ### hf iclass - { ICLASS RFIDs... } + { ICLASS RFIDs... } |command |offline |description |------- |------- |----------- @@ -275,7 +287,7 @@ Check column "offline" for their availability. ### hf legic - { LEGIC RFIDs... } + { LEGIC RFIDs... } |command |offline |description |------- |------- |----------- @@ -296,7 +308,7 @@ Check column "offline" for their availability. ### hf lto - { LTO Cartridge Memory RFIDs... } + { LTO Cartridge Memory RFIDs... } |command |offline |description |------- |------- |----------- @@ -311,7 +323,7 @@ Check column "offline" for their availability. ### hf mf - { MIFARE RFIDs... } + { MIFARE RFIDs... } |command |offline |description |------- |------- |----------- @@ -363,7 +375,7 @@ Check column "offline" for their availability. ### hf mfp - { MIFARE Plus RFIDs... } + { MIFARE Plus RFIDs... } |command |offline |description |------- |------- |----------- @@ -383,7 +395,7 @@ Check column "offline" for their availability. ### hf mfu - { MIFARE Ultralight RFIDs... } + { MIFARE Ultralight RFIDs... } |command |offline |description |------- |------- |----------- @@ -406,7 +418,7 @@ Check column "offline" for their availability. ### hf mfdes - { MIFARE Desfire RFIDs... } + { MIFARE Desfire RFIDs... } |command |offline |description |------- |------- |----------- @@ -436,7 +448,7 @@ Check column "offline" for their availability. ### hf st - { ST Rothult RFIDs... } + { ST Rothult RFIDs... } |command |offline |description |------- |------- |----------- @@ -451,7 +463,7 @@ Check column "offline" for their availability. ### hf thinfilm - { Thinfilm RFIDs... } + { Thinfilm RFIDs... } |command |offline |description |------- |------- |----------- @@ -463,7 +475,7 @@ Check column "offline" for their availability. ### hf topaz - { TOPAZ (NFC Type 1) RFIDs... } + { TOPAZ (NFC Type 1) RFIDs... } |command |offline |description |------- |------- |----------- @@ -478,7 +490,7 @@ Check column "offline" for their availability. ### hf waveshare - { Waveshare NFC ePaper... } + { Waveshare NFC ePaper... } |command |offline |description |------- |------- |----------- From 7bc3067fa4ea05d176353314ee0d8f11b68fda33 Mon Sep 17 00:00:00 2001 From: Philippe Teuwen Date: Wed, 23 Dec 2020 01:12:35 +0100 Subject: [PATCH 188/682] Make print_progess scalable --- client/src/cmdhf.c | 2 +- client/src/cmdlf.c | 2 +- client/src/ui.c | 34 +++++++++++++++++++++++++--------- 3 files changed, 27 insertions(+), 11 deletions(-) diff --git a/client/src/cmdhf.c b/client/src/cmdhf.c index 0f6a351ec..d1bc184ff 100644 --- a/client/src/cmdhf.c +++ b/client/src/cmdhf.c @@ -219,7 +219,7 @@ int CmdHFTune(const char *Cmd) { uint32_t max = 0xFFFF; bool first = true; - print_progress(0, max, style); + print_progress(0, max, style); // loop forever (till button pressed) if iter = 0 (default) for (uint8_t i = 0; iter == 0 || i < iter; i++) { diff --git a/client/src/cmdlf.c b/client/src/cmdlf.c index 4120959e8..cd001bafb 100644 --- a/client/src/cmdlf.c +++ b/client/src/cmdlf.c @@ -306,7 +306,7 @@ static int CmdLFTune(const char *Cmd) { uint32_t max = 71000; bool first = true; - print_progress(0, max, style); + print_progress(0, max, style); // loop forever (till button pressed) if iter = 0 (default) for (uint8_t i = 0; iter == 0 || i < iter; i++) { diff --git a/client/src/ui.c b/client/src/ui.c index e4b873596..e128fb374 100644 --- a/client/src/ui.c +++ b/client/src/ui.c @@ -14,7 +14,9 @@ #if !defined(_WIN32) #define _POSIX_C_SOURCE 200112L #endif - +#ifdef HAVE_READLINE +#include +#endif #include "ui.h" #include "commonutil.h" // ARRAYLEN @@ -625,10 +627,22 @@ void iceSimple_Filter(int *data, const size_t len, uint8_t k) { } void print_progress(size_t count, uint64_t max, barMode_t style) { - - #define PERCENTAGE(V, T) ((V * 100) / T) + int cols = 100 + 35; +#ifdef HAVE_READLINE + static int prev_cols = 0; + int rows; + rl_reset_screen_size(); // refresh Readline idea of the actual screen width + rl_get_screen_size (&rows, &cols); + (void) rows; + if (prev_cols > cols) { + PrintAndLogEx(NORMAL, _CLEAR_ _TOP_ ""); + } + prev_cols = cols; +#endif + int width = cols - 35; + #define PERCENTAGE(V, T) ((V * width) / T) // x/8 fractional part of the percentage - #define PERCENTAGEFRAC(V, T) ((int)(((((float)V * 100) / T) - ((V * 100) / T)) * 8)) + #define PERCENTAGEFRAC(V, T) ((int)(((((float)V * width) / T) - ((V * width) / T)) * 8)) const char *smoothtable[] = { "\xe2\x80\x80", @@ -648,7 +662,7 @@ void print_progress(size_t count, uint64_t max, barMode_t style) { const char *space[] = {" ", "\xe2\x80\x80"}; uint8_t unit = strlen(block[mode]); // +1 for \0 - char *bar = calloc(unit*100 + 1, sizeof(uint8_t)); + char *bar = calloc(unit*width + 1, sizeof(uint8_t)); uint8_t value = PERCENTAGE(count, max); @@ -665,7 +679,7 @@ void print_progress(size_t count, uint64_t max, barMode_t style) { } i += unit; // add spaces - for (; i < unit*100; i+=unit) { + for (; i < unit*width; i+=unit) { memcpy(bar + i, space[mode], unit); } // color buffer @@ -673,9 +687,11 @@ void print_progress(size_t count, uint64_t max, barMode_t style) { char *cbar = calloc(collen, sizeof(uint8_t)); // Add colors - snprintf(cbar, collen, _GREEN_("%.*s"), unit*60, bar); - snprintf(cbar + strlen(cbar), collen - strlen(cbar), _CYAN_("%.*s"), unit*20, bar + unit*60); - snprintf(cbar + strlen(cbar), collen - strlen(cbar), _YELLOW_("%.*s"), unit*20, bar + unit*80); + int p60 = unit*(width*60/100); + int p20 = unit*(width*20/100); + snprintf(cbar, collen, _GREEN_("%.*s"), p60, bar); + snprintf(cbar + strlen(cbar), collen - strlen(cbar), _CYAN_("%.*s"), p20, bar + p60); + snprintf(cbar + strlen(cbar), collen - strlen(cbar), _YELLOW_("%.*s"), unit*width - p60 - p20, bar + p60 + p20); size_t len = strlen(cbar) + 32; char *buffer = calloc(len, sizeof(uint8_t)); From 8d4acbe3a622d642c65547243e7809d9d1315955 Mon Sep 17 00:00:00 2001 From: Philippe Teuwen Date: Wed, 23 Dec 2020 19:51:10 +0100 Subject: [PATCH 189/682] make style --- armsrc/Standalone/hf_iceclass.c | 20 +++++++-------- armsrc/em4x70.c | 38 ++++++++++++++--------------- armsrc/em4x70.h | 2 +- client/src/cmdhf.c | 6 ++--- client/src/cmdhf14a.c | 2 +- client/src/cmdhf14b.c | 6 ++--- client/src/cmdhfemrtd.c | 43 ++++++++++++++++----------------- client/src/cmdlf.c | 6 ++--- client/src/cmdlfem4x50.c | 2 +- client/src/cmdmain.c | 2 +- client/src/preferences.c | 2 +- client/src/ui.c | 24 +++++++++--------- doc/commands.md | 4 +-- 13 files changed, 78 insertions(+), 79 deletions(-) diff --git a/armsrc/Standalone/hf_iceclass.c b/armsrc/Standalone/hf_iceclass.c index 472544310..88ccfaa47 100644 --- a/armsrc/Standalone/hf_iceclass.c +++ b/armsrc/Standalone/hf_iceclass.c @@ -158,17 +158,17 @@ static void download_instructions(uint8_t t) { // Save to flash if file doesn't exist. // Write over file if size of flash file is less than new datalen -static void save_to_flash(uint8_t *data, uint16_t datalen, char * filename) { +static void save_to_flash(uint8_t *data, uint16_t datalen, char *filename) { rdv40_spiffs_lazy_mount(); char fn[SPIFFS_OBJ_NAME_LEN]; - if (filename == NULL){ - sprintf(fn, "iclass-%02X%02X%02X%02X%02X%02X%02X%02X.bin", - data[0], data[1], data[2], data[3], - data[4], data[5], data[6], data[7] - ); + if (filename == NULL) { + sprintf(fn, "iclass-%02X%02X%02X%02X%02X%02X%02X%02X.bin", + data[0], data[1], data[2], data[3], + data[4], data[5], data[6], data[7] + ); } else { int name_len = SPIFFS_OBJ_NAME_LEN; int filename_len = strlen(filename); @@ -176,7 +176,7 @@ static void save_to_flash(uint8_t *data, uint16_t datalen, char * filename) { // if the given name len longer than buffer allows, cut it down to size name_len = (name_len >= SPIFFS_OBJ_NAME_LEN) ? SPIFFS_OBJ_NAME_LEN : filename_len; memcpy(fn, filename, name_len); - } + } int res; if (exists_in_spiffs(fn) == false) { @@ -558,12 +558,12 @@ static int dump_sim_mode(void) { } } switch_off(); - char * temp_file = HF_ICALSSS_READSIM_TEMP_BIN; + char *temp_file = HF_ICALSSS_READSIM_TEMP_BIN; save_to_flash(card_data, (start_block + dumped) * 8, temp_file); Dbprintf("%u bytes saved", (start_block + dumped) * 8); if (((start_block + dumped) * 8) > 0) { - break; //switch to sim mode + break; //switch to sim mode } } @@ -577,7 +577,7 @@ static int dump_sim_mode(void) { if (res == SPIFFS_OK) { Dbprintf("loaded " _GREEN_(HF_ICALSSS_READSIM_TEMP_BIN) " (%u bytes)", fsize); } - + Dbprintf("simming " _GREEN_(HF_ICALSSS_READSIM_TEMP_BIN)); iclass_simulate(ICLASS_SIM_MODE_FULL, 0, false, NULL, NULL, NULL); diff --git a/armsrc/em4x70.c b/armsrc/em4x70.c index 1a6f37d56..77cfbb2dd 100644 --- a/armsrc/em4x70.c +++ b/armsrc/em4x70.c @@ -190,9 +190,9 @@ static uint32_t get_rising_pulse_length(void) { static uint32_t get_pulse_length(edge_detection_t edge) { - if(edge == RISING_EDGE) + if (edge == RISING_EDGE) return get_rising_pulse_length(); - else if(edge == FALLING_EDGE) + else if (edge == FALLING_EDGE) return get_falling_pulse_length(); return 0; @@ -292,11 +292,11 @@ static bool check_ack(void) { // ACK 64 + 64 // NACK 64 + 48 if (check_pulse_length(get_pulse_length(FALLING_EDGE), 2 * EM4X70_T_TAG_FULL_PERIOD) && - check_pulse_length(get_pulse_length(FALLING_EDGE), 2 * EM4X70_T_TAG_FULL_PERIOD)) { + check_pulse_length(get_pulse_length(FALLING_EDGE), 2 * EM4X70_T_TAG_FULL_PERIOD)) { // ACK return true; - } - + } + // Othewise it was a NACK or Listen Window return false; } @@ -426,10 +426,10 @@ static bool find_listen_window(bool command) { 96 ( 64 + 32 ) 64 ( 32 + 16 +16 )*/ - if (check_pulse_length(get_pulse_length(RISING_EDGE), (2*EM4X70_T_TAG_FULL_PERIOD) + EM4X70_T_TAG_HALF_PERIOD) && - check_pulse_length(get_pulse_length(RISING_EDGE), (2*EM4X70_T_TAG_FULL_PERIOD) + EM4X70_T_TAG_HALF_PERIOD) && - check_pulse_length(get_pulse_length(FALLING_EDGE), (2*EM4X70_T_TAG_FULL_PERIOD) + EM4X70_T_TAG_FULL_PERIOD) && - check_pulse_length(get_pulse_length(FALLING_EDGE), EM4X70_T_TAG_FULL_PERIOD + (2*EM4X70_T_TAG_HALF_PERIOD))) { + if (check_pulse_length(get_pulse_length(RISING_EDGE), (2 * EM4X70_T_TAG_FULL_PERIOD) + EM4X70_T_TAG_HALF_PERIOD) && + check_pulse_length(get_pulse_length(RISING_EDGE), (2 * EM4X70_T_TAG_FULL_PERIOD) + EM4X70_T_TAG_HALF_PERIOD) && + check_pulse_length(get_pulse_length(FALLING_EDGE), (2 * EM4X70_T_TAG_FULL_PERIOD) + EM4X70_T_TAG_FULL_PERIOD) && + check_pulse_length(get_pulse_length(FALLING_EDGE), EM4X70_T_TAG_FULL_PERIOD + (2 * EM4X70_T_TAG_HALF_PERIOD))) { if (command) { /* Here we are after the 64 duration edge. @@ -438,7 +438,7 @@ static bool find_listen_window(bool command) { * * I've found between 4-5 quarter periods (32-40) works best */ - WaitTicks( 4 * EM4X70_T_TAG_QUARTER_PERIOD ); + WaitTicks(4 * EM4X70_T_TAG_QUARTER_PERIOD); // Send RM Command em4x70_send_bit(0); em4x70_send_bit(0); @@ -559,7 +559,7 @@ static int em4x70_receive(uint8_t *bits, size_t length) { WaitTicks(6 * EM4X70_T_TAG_FULL_PERIOD); // wait until we get the transition from 1's to 0's which is 1.5 full windows - for(int i = 0; i < EM4X70_T_READ_HEADER_LEN; i++) { + for (int i = 0; i < EM4X70_T_READ_HEADER_LEN; i++) { pl = get_pulse_length(edge); if (check_pulse_length(pl, 3 * EM4X70_T_TAG_HALF_PERIOD)) { foundheader = true; @@ -575,7 +575,7 @@ static int em4x70_receive(uint8_t *bits, size_t length) { // Skip next 3 0's, header check consumes the first 0 for (int i = 0; i < 3; i++) { // If pulse length is not 1 bit, then abort early - if(!check_pulse_length(get_pulse_length(edge), EM4X70_T_TAG_FULL_PERIOD)) { + if (!check_pulse_length(get_pulse_length(edge), EM4X70_T_TAG_FULL_PERIOD)) { return 0; } } @@ -745,8 +745,8 @@ void em4x70_write_pin(em4x70_data_t *etd) { if (em4x70_read_id()) { // Write new PIN - if( (write( etd->pin & 0xFFFF, EM4X70_PIN_WORD_UPPER) == PM3_SUCCESS) && - (write((etd->pin >> 16) & 0xFFFF, EM4X70_PIN_WORD_LOWER) == PM3_SUCCESS)) { + if ((write(etd->pin & 0xFFFF, EM4X70_PIN_WORD_UPPER) == PM3_SUCCESS) && + (write((etd->pin >> 16) & 0xFFFF, EM4X70_PIN_WORD_LOWER) == PM3_SUCCESS)) { // Now Try to authenticate using the new PIN @@ -784,13 +784,13 @@ void em4x70_write_key(em4x70_data_t *etd) { // 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 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) { + if (write(key_word, 9 - i) != PM3_SUCCESS) { status = 0; break; } diff --git a/armsrc/em4x70.h b/armsrc/em4x70.h index abebe0e8b..5bb1a2a37 100644 --- a/armsrc/em4x70.h +++ b/armsrc/em4x70.h @@ -20,7 +20,7 @@ typedef struct { typedef enum { RISING_EDGE, FALLING_EDGE -}edge_detection_t; +} edge_detection_t; void em4x70_info(em4x70_data_t *etd); void em4x70_write(em4x70_data_t *etd); diff --git a/client/src/cmdhf.c b/client/src/cmdhf.c index d1bc184ff..ada69e905 100644 --- a/client/src/cmdhf.c +++ b/client/src/cmdhf.c @@ -53,7 +53,7 @@ int CmdHFSearch(const char *Cmd) { "Will try to find a HF read out of the unknown tag.\n" "Continues to search for all different HF protocols.", "hf sniff" - ); + ); void *argtable[] = { arg_param_begin, arg_param_end @@ -244,7 +244,7 @@ int CmdHFTune(const char *Cmd) { max = (volt * 1.03); first = false; } - if ( volt > max) { + if (volt > max) { max = (volt * 1.03); } print_progress(volt, max, style); @@ -274,7 +274,7 @@ int CmdHFSniff(const char *Cmd) { "Press button to quit the sniffing.", "hf sniff\n" "hf sniff --sp 1000 --st 0 -> skip 1000 pairs, skip 0 triggers" - ); + ); void *argtable[] = { arg_param_begin, arg_u64_0(NULL, "sp", "", "skip sample pairs"), diff --git a/client/src/cmdhf14a.c b/client/src/cmdhf14a.c index a1cf5b76e..d4418ee62 100644 --- a/client/src/cmdhf14a.c +++ b/client/src/cmdhf14a.c @@ -2001,7 +2001,7 @@ int infoHF14A(bool verbose, bool do_nack_test, bool do_aid_search) { if (do_aid_search) { - + PrintAndLogEx(INFO, "-------------------- " _CYAN_("AID Search") " --------------------"); bool found = false; diff --git a/client/src/cmdhf14b.c b/client/src/cmdhf14b.c index b27df1914..71c2f03ab 100644 --- a/client/src/cmdhf14b.c +++ b/client/src/cmdhf14b.c @@ -82,9 +82,9 @@ static void hf14b_aid_search(bool verbose) { bool activate_field = true; for (elmindx = 0; elmindx < json_array_size(root); elmindx++) { - if (kbd_enter_pressed()) { - break; - } + if (kbd_enter_pressed()) { + break; + } json_t *data = AIDSearchGetElm(root, elmindx); uint8_t vaid[200] = {0}; diff --git a/client/src/cmdhfemrtd.c b/client/src/cmdhfemrtd.c index 30eb4667f..3be321fcb 100644 --- a/client/src/cmdhfemrtd.c +++ b/client/src/cmdhfemrtd.c @@ -61,7 +61,7 @@ static int emrtd_print_ef_dg12_info(uint8_t *data, size_t datalen); static int emrtd_print_ef_sod_info(uint8_t *data, size_t datalen); typedef enum { // list must match dg_table - EF_COM=0, + EF_COM = 0, EF_DG1, EF_DG2, EF_DG3, @@ -109,7 +109,7 @@ static emrtd_dg_t dg_table[] = { }; static emrtd_dg_t *emrtd_tag_to_dg(uint8_t tag) { - for (int dgi=0; dg_table[dgi].filename != NULL; dgi++) { + for (int dgi = 0; dg_table[dgi].filename != NULL; dgi++) { if (dg_table[dgi].tag == tag) { return &dg_table[dgi]; } @@ -117,7 +117,7 @@ static emrtd_dg_t *emrtd_tag_to_dg(uint8_t tag) { return NULL; } static emrtd_dg_t *emrtd_fileid_to_dg(const char *file_id) { - for (int dgi=0; dg_table[dgi].filename != NULL; dgi++) { + for (int dgi = 0; dg_table[dgi].filename != NULL; dgi++) { if (strcmp(dg_table[dgi].fileid, file_id) == 0) { return &dg_table[dgi]; } @@ -691,7 +691,7 @@ static int emrtd_dump_ef_dg2(uint8_t *file_contents, size_t file_length) { // Note: Doing file_length - 6 to account for the longest data we're checking. for (offset = 0; offset < file_length - 6; offset++) { if ((file_contents[offset] == 0xFF && file_contents[offset + 1] == 0xD8 && file_contents[offset + 2] == 0xFF && file_contents[offset + 3] == 0xE0) || - (file_contents[offset] == 0x00 && file_contents[offset + 1] == 0x00 && file_contents[offset + 2] == 0x00 && file_contents[offset + 3] == 0x0C && file_contents[offset + 4] == 0x6A && file_contents[offset + 5] == 0x50)) { + (file_contents[offset] == 0x00 && file_contents[offset + 1] == 0x00 && file_contents[offset + 2] == 0x00 && file_contents[offset + 3] == 0x0C && file_contents[offset + 4] == 0x6A && file_contents[offset + 5] == 0x50)) { datalen = file_length - offset; break; } @@ -745,7 +745,7 @@ static int emrtd_dump_ef_dg7(uint8_t *file_contents, size_t file_length) { static int emrtd_dump_ef_sod(uint8_t *file_contents, size_t file_length) { int fieldlen = emrtd_get_asn1_field_length(file_contents, file_length, 1); int datalen = emrtd_get_asn1_data_length(file_contents, file_length, 1); - + if (fieldlen + 1 > EMRTD_MAX_FILE_SIZE) { PrintAndLogEx(ERR, "error (emrtd_dump_ef_sod) fieldlen out-of-bounds"); return PM3_SUCCESS; @@ -766,7 +766,7 @@ static bool emrtd_dump_file(uint8_t *ks_enc, uint8_t *ks_mac, uint8_t *ssc, cons PrintAndLogEx(INFO, "Read %s, len: %i.", name, resplen); PrintAndLogEx(DEBUG, "Contents (may be incomplete over 2k chars): %s", sprint_hex_inrow(response, resplen)); saveFile(name, ".BIN", response, resplen); - emrtd_dg_t * dg = emrtd_fileid_to_dg(file); + emrtd_dg_t *dg = emrtd_fileid_to_dg(file); if ((dg != NULL) && (dg->dumper != NULL)) { dg->dumper(response, resplen); } @@ -778,7 +778,7 @@ static void rng(int length, uint8_t *dataout) { //for (int i = 0; i < (length / 4); i++) { // num_to_bytes(prng_successor(msclock() + i, 32), 4, &dataout[i * 4]); //} - memset(dataout, 0x00, length); + memset(dataout, 0x00, length); } static bool emrtd_do_bac(char *documentnumber, char *dob, char *expiry, uint8_t *ssc, uint8_t *ks_enc, uint8_t *ks_mac, bool use_14b) { @@ -1006,7 +1006,7 @@ int dumpHF_EMRTD(char *documentnumber, char *dob, char *expiry, bool BAC_availab filelist[filelistlen++] = 0x77; // Dump all files in the file list for (int i = 0; i < filelistlen; i++) { - emrtd_dg_t * dg = emrtd_tag_to_dg(filelist[i]); + emrtd_dg_t *dg = emrtd_tag_to_dg(filelist[i]); if (dg == NULL) { PrintAndLogEx(INFO, "File tag not found, skipping: %02X", filelist[i]); continue; @@ -1027,9 +1027,9 @@ static bool emrtd_compare_check_digit(char *datain, int datalen, char expected_c uint8_t check_digit = emrtd_calculate_check_digit(tempdata) + 0x30; bool res = check_digit == expected_check_digit; PrintAndLogEx(DEBUG, "emrtd_compare_check_digit, expected %c == %c calculated ( %s )" - , expected_check_digit - , check_digit - , (res) ? _GREEN_("ok") : _RED_("fail")); + , expected_check_digit + , check_digit + , (res) ? _GREEN_("ok") : _RED_("fail")); return res; } @@ -1231,7 +1231,7 @@ static int emrtd_print_ef_com_info(uint8_t *data, size_t datalen) { PrintAndLogEx(NORMAL, ""); PrintAndLogEx(INFO, "-------------------- " _CYAN_("EF_COM") " --------------------"); for (int i = 0; i < filelistlen; i++) { - emrtd_dg_t * dg = emrtd_tag_to_dg(filelist[i]); + emrtd_dg_t *dg = emrtd_tag_to_dg(filelist[i]); if (dg == NULL) { PrintAndLogEx(INFO, "File tag not found, skipping: %02X", filelist[i]); continue; @@ -1513,7 +1513,7 @@ int infoHF_EMRTD(char *documentnumber, char *dob, char *expiry, bool BAC_availab } int res = emrtd_print_ef_com_info(response, resplen); - if ( res != PM3_SUCCESS) { + if (res != PM3_SUCCESS) { DropField(); return res; } @@ -1530,7 +1530,7 @@ int infoHF_EMRTD(char *documentnumber, char *dob, char *expiry, bool BAC_availab filelist[filelistlen++] = 0x77; // Dump all files in the file list for (int i = 0; i < filelistlen; i++) { - emrtd_dg_t * dg = emrtd_tag_to_dg(filelist[i]); + emrtd_dg_t *dg = emrtd_tag_to_dg(filelist[i]); if (dg == NULL) { PrintAndLogEx(INFO, "File tag not found, skipping: %02X", filelist[i]); continue; @@ -1563,7 +1563,7 @@ int infoHF_EMRTD_offline(const char *path) { } int res = emrtd_print_ef_com_info(data, datalen); - if ( res != PM3_SUCCESS) { + if (res != PM3_SUCCESS) { free(data); free(filepath); return res; @@ -1583,7 +1583,7 @@ int infoHF_EMRTD_offline(const char *path) { filelist[filelistlen++] = 0x77; // Read files in the file list for (int i = 0; i < filelistlen; i++) { - emrtd_dg_t * dg = emrtd_tag_to_dg(filelist[i]); + emrtd_dg_t *dg = emrtd_tag_to_dg(filelist[i]); if (dg == NULL) { PrintAndLogEx(INFO, "File tag not found, skipping: %02X", filelist[i]); continue; @@ -1592,8 +1592,7 @@ int infoHF_EMRTD_offline(const char *path) { strcpy(filepath, path); strncat(filepath, PATHSEP, 2); strcat(filepath, dg->filename); - if (loadFile_safeEx(filepath, ".BIN", (void **)&data, (size_t *)&datalen, false) == PM3_SUCCESS) - { + if (loadFile_safeEx(filepath, ".BIN", (void **)&data, (size_t *)&datalen, false) == PM3_SUCCESS) { // we won't halt on parsing errors if (dg->parser != NULL) dg->parser(data, datalen); @@ -1662,7 +1661,7 @@ static int cmd_hf_emrtd_dump(const char *Cmd) { memset(docnum + slen, '<', 9 - slen); } } - + if (CLIParamStrToBuf(arg_get_str(ctx, 2), dob, 6, &slen) != 0 || slen == 0) { BAC = false; } else { @@ -1672,7 +1671,7 @@ static int cmd_hf_emrtd_dump(const char *Cmd) { error = true; } } - + if (CLIParamStrToBuf(arg_get_str(ctx, 3), expiry, 6, &slen) != 0 || slen == 0) { BAC = false; } else { @@ -1748,7 +1747,7 @@ static int cmd_hf_emrtd_info(const char *Cmd) { memset(docnum + slen, '<', 9 - slen); } } - + if (CLIParamStrToBuf(arg_get_str(ctx, 2), dob, 6, &slen) != 0 || slen == 0) { BAC = false; } else { @@ -1758,7 +1757,7 @@ static int cmd_hf_emrtd_info(const char *Cmd) { error = true; } } - + if (CLIParamStrToBuf(arg_get_str(ctx, 3), expiry, 6, &slen) != 0 || slen == 0) { BAC = false; } else { diff --git a/client/src/cmdlf.c b/client/src/cmdlf.c index cd001bafb..2ee55eebf 100644 --- a/client/src/cmdlf.c +++ b/client/src/cmdlf.c @@ -328,11 +328,11 @@ static int CmdLFTune(const char *Cmd) { uint32_t volt = resp.data.asDwords[0]; if (first) { - max = (volt * 1.03); + max = (volt * 1.03); first = false; } - if ( volt > max) { - max = (volt * 1.03); + if (volt > max) { + max = (volt * 1.03); } print_progress(volt, max, style); } diff --git a/client/src/cmdlfem4x50.c b/client/src/cmdlfem4x50.c index 9c907caf7..79b019a03 100644 --- a/client/src/cmdlfem4x50.c +++ b/client/src/cmdlfem4x50.c @@ -286,7 +286,7 @@ int CmdEM4x50EView(const char *Cmd) { PrintAndLogEx(WARNING, "Fail, transfer from device time-out"); return PM3_ETIMEOUT; } - + // valid em4x50 data? uint32_t serial = bytes_to_num(data + 4 * EM4X50_DEVICE_SERIAL, 4); uint32_t device_id = bytes_to_num(data + 4 * EM4X50_DEVICE_ID, 4); diff --git a/client/src/cmdmain.c b/client/src/cmdmain.c index 4d393756f..fe4fa0b84 100644 --- a/client/src/cmdmain.c +++ b/client/src/cmdmain.c @@ -175,7 +175,7 @@ int CmdRem(const char *Cmd) { }; CLIExecWithReturn(ctx, Cmd, argtable, false); - struct arg_str* foo = arg_get_str(ctx, 1); + struct arg_str *foo = arg_get_str(ctx, 1); size_t count = 0; size_t len = 0; do { diff --git a/client/src/preferences.c b/client/src/preferences.c index c80e24e3a..1e943a84a 100644 --- a/client/src/preferences.c +++ b/client/src/preferences.c @@ -314,7 +314,7 @@ void preferences_load_callback(json_t *root) { if (json_unpack_ex(root, &up_error, 0, "{s:b}", "os.supports.colors", &b1) == 0) session.supports_colors = (bool)b1; - // bar mode + // bar mode if (json_unpack_ex(root, &up_error, 0, "{s:s}", "show.bar.mode", &s1) == 0) { strncpy(tempStr, s1, sizeof(tempStr) - 1); str_lower(tempStr); diff --git a/client/src/ui.c b/client/src/ui.c index e128fb374..f9595e5f3 100644 --- a/client/src/ui.c +++ b/client/src/ui.c @@ -632,7 +632,7 @@ void print_progress(size_t count, uint64_t max, barMode_t style) { static int prev_cols = 0; int rows; rl_reset_screen_size(); // refresh Readline idea of the actual screen width - rl_get_screen_size (&rows, &cols); + rl_get_screen_size(&rows, &cols); (void) rows; if (prev_cols > cols) { PrintAndLogEx(NORMAL, _CLEAR_ _TOP_ ""); @@ -640,9 +640,9 @@ void print_progress(size_t count, uint64_t max, barMode_t style) { prev_cols = cols; #endif int width = cols - 35; - #define PERCENTAGE(V, T) ((V * width) / T) +#define PERCENTAGE(V, T) ((V * width) / T) // x/8 fractional part of the percentage - #define PERCENTAGEFRAC(V, T) ((int)(((((float)V * width) / T) - ((V * width) / T)) * 8)) +#define PERCENTAGEFRAC(V, T) ((int)(((((float)V * width) / T) - ((V * width) / T)) * 8)) const char *smoothtable[] = { "\xe2\x80\x80", @@ -662,13 +662,13 @@ void print_progress(size_t count, uint64_t max, barMode_t style) { const char *space[] = {" ", "\xe2\x80\x80"}; uint8_t unit = strlen(block[mode]); // +1 for \0 - char *bar = calloc(unit*width + 1, sizeof(uint8_t)); + char *bar = calloc(unit * width + 1, sizeof(uint8_t)); uint8_t value = PERCENTAGE(count, max); int i = 0; // prefix is added already. - for (; i < unit*value; i+=unit) { + for (; i < unit * value; i += unit) { memcpy(bar + i, block[mode], unit); } // add last block @@ -679,7 +679,7 @@ void print_progress(size_t count, uint64_t max, barMode_t style) { } i += unit; // add spaces - for (; i < unit*width; i+=unit) { + for (; i < unit * width; i += unit) { memcpy(bar + i, space[mode], unit); } // color buffer @@ -687,24 +687,24 @@ void print_progress(size_t count, uint64_t max, barMode_t style) { char *cbar = calloc(collen, sizeof(uint8_t)); // Add colors - int p60 = unit*(width*60/100); - int p20 = unit*(width*20/100); + int p60 = unit * (width * 60 / 100); + int p20 = unit * (width * 20 / 100); snprintf(cbar, collen, _GREEN_("%.*s"), p60, bar); snprintf(cbar + strlen(cbar), collen - strlen(cbar), _CYAN_("%.*s"), p20, bar + p60); - snprintf(cbar + strlen(cbar), collen - strlen(cbar), _YELLOW_("%.*s"), unit*width - p60 - p20, bar + p60 + p20); + snprintf(cbar + strlen(cbar), collen - strlen(cbar), _YELLOW_("%.*s"), unit * width - p60 - p20, bar + p60 + p20); size_t len = strlen(cbar) + 32; char *buffer = calloc(len, sizeof(uint8_t)); - switch(style) { + switch (style) { case STYLE_BAR: { - sprintf(buffer, "%s", cbar); + sprintf(buffer, "%s", cbar); printf("\b%c[2K\r[" _YELLOW_("=")"] %s", 27, buffer); break; } case STYLE_MIXED: { sprintf(buffer, "%s [ %zu mV / %3u V ]", cbar, count, (uint32_t)(count / 1000)); - printf("\b%c[2K\r[" _YELLOW_("=")"] %s ", 27, buffer); + printf("\b%c[2K\r[" _YELLOW_("=")"] %s ", 27, buffer); break; } case STYLE_VALUE: { diff --git a/doc/commands.md b/doc/commands.md index 991f4a590..e1e445296 100644 --- a/doc/commands.md +++ b/doc/commands.md @@ -198,8 +198,8 @@ Check column "offline" for their availability. |command |offline |description |------- |------- |----------- |`hf epa help `|Y |`This help` -|`hf epa cnonces `|N |`Acquire encrypted PACE nonces of specific size` -|`hf epa preplay `|N |`Perform PACE protocol by replaying given APDUs` +|`hf epa cnonces `|N |` Acquire n>0 encrypted PACE nonces of size m>0 with d sec pauses` +|`hf epa preplay `|N |` Perform PACE protocol by replaying given APDUs` ### hf emrtd From 0272a3b63eaca1bde5f5093ebd2bb5c3572142c5 Mon Sep 17 00:00:00 2001 From: Ave Date: Wed, 23 Dec 2020 22:27:05 +0300 Subject: [PATCH 190/682] emrtd: Move a lot of size values from int to size_t --- client/src/cmdhfemrtd.c | 42 ++++++++++++++++++++--------------------- 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/client/src/cmdhfemrtd.c b/client/src/cmdhfemrtd.c index 3203b4932..0c9de0cac 100644 --- a/client/src/cmdhfemrtd.c +++ b/client/src/cmdhfemrtd.c @@ -629,7 +629,7 @@ static int emrtd_lds_determine_tag_length(uint8_t tag) { return 1; } -static bool emrtd_lds_get_data_by_tag(uint8_t *datain, int datainlen, uint8_t *dataout, int *dataoutlen, int tag1, int tag2, bool twobytetag, bool entertoptag, int skiptagcount) { +static bool emrtd_lds_get_data_by_tag(uint8_t *datain, size_t datainlen, uint8_t *dataout, size_t *dataoutlen, int tag1, int tag2, bool twobytetag, bool entertoptag, size_t skiptagcount) { int offset = 0; int skipcounter = 0; @@ -720,7 +720,7 @@ static int emrtd_dump_ef_dg2(uint8_t *file_contents, size_t file_length) { static int emrtd_dump_ef_dg5(uint8_t *file_contents, size_t file_length) { uint8_t data[EMRTD_MAX_FILE_SIZE]; - int datalen = 0; + size_t datalen = 0; // If we can't find image in EF_DG5, return false. if (emrtd_lds_get_data_by_tag(file_contents, file_length, data, &datalen, 0x5F, 0x40, true, true, 0) == false) { @@ -738,7 +738,7 @@ static int emrtd_dump_ef_dg5(uint8_t *file_contents, size_t file_length) { static int emrtd_dump_ef_dg7(uint8_t *file_contents, size_t file_length) { uint8_t data[EMRTD_MAX_FILE_SIZE]; - int datalen = 0; + size_t datalen = 0; // If we can't find image in EF_DG7, return false. if (emrtd_lds_get_data_by_tag(file_contents, file_length, data, &datalen, 0x5F, 0x42, true, true, 0) == false) { @@ -1005,7 +1005,7 @@ int dumpHF_EMRTD(char *documentnumber, char *dob, char *expiry, bool BAC_availab saveFile(dg_table[EF_COM].filename, ".BIN", response, resplen); uint8_t filelist[50]; - int filelistlen = 0; + size_t filelistlen = 0; if (!emrtd_lds_get_data_by_tag(response, resplen, filelist, &filelistlen, 0x5c, 0x00, false, true, 0)) { PrintAndLogEx(ERR, "Failed to read file list from EF_COM."); @@ -1017,7 +1017,7 @@ int dumpHF_EMRTD(char *documentnumber, char *dob, char *expiry, bool BAC_availab // Add EF_SOD to the list filelist[filelistlen++] = 0x77; // Dump all files in the file list - for (int i = 0; i < filelistlen; i++) { + for (size_t i = 0; i < filelistlen; i++) { emrtd_dg_t *dg = emrtd_tag_to_dg(filelist[i]); if (dg == NULL) { PrintAndLogEx(INFO, "File tag not found, skipping: %02X", filelist[i]); @@ -1232,7 +1232,7 @@ static void emrtd_print_unknown_timestamp_5f85(uint8_t *data) { static int emrtd_print_ef_com_info(uint8_t *data, size_t datalen) { uint8_t filelist[50]; - int filelistlen = 0; + size_t filelistlen = 0; int res = emrtd_lds_get_data_by_tag(data, datalen, filelist, &filelistlen, 0x5c, 0x00, false, true, 0); if (!res) { PrintAndLogEx(ERR, "Failed to read file list from EF_COM."); @@ -1262,7 +1262,7 @@ static int emrtd_print_ef_dg1_info(uint8_t *data, size_t datalen) { // MRZ on TD1 is 90 characters, 30 on each row. // MRZ on TD3 is 88 characters, 44 on each row. char mrz[90] = { 0x00 }; - int mrzlen = 0; + size_t mrzlen = 0; if (!emrtd_lds_get_data_by_tag(data, datalen, (uint8_t *) mrz, &mrzlen, 0x5f, 0x1f, true, true, 0)) { PrintAndLogEx(ERR, "Failed to read MRZ from EF_DG1."); @@ -1339,9 +1339,9 @@ static int emrtd_print_ef_dg1_info(uint8_t *data, size_t datalen) { static int emrtd_print_ef_dg11_info(uint8_t *data, size_t datalen) { uint8_t taglist[100] = { 0x00 }; - int taglistlen = 0; + size_t taglistlen = 0; uint8_t tagdata[1000] = { 0x00 }; - int tagdatalen = 0; + size_t tagdatalen = 0; PrintAndLogEx(NORMAL, ""); PrintAndLogEx(INFO, "-------------------- " _CYAN_("EF_DG11") " -------------------"); @@ -1418,9 +1418,9 @@ static int emrtd_print_ef_dg11_info(uint8_t *data, size_t datalen) { static int emrtd_print_ef_dg12_info(uint8_t *data, size_t datalen) { uint8_t taglist[100] = { 0x00 }; - int taglistlen = 0; + size_t taglistlen = 0; uint8_t tagdata[1000] = { 0x00 }; - int tagdatalen = 0; + size_t tagdatalen = 0; PrintAndLogEx(NORMAL, ""); PrintAndLogEx(INFO, "-------------------- " _CYAN_("EF_DG12") " -------------------"); @@ -1491,14 +1491,14 @@ static int emrtd_ef_sod_extract_signatures(uint8_t *data, size_t datalen, uint8_ uint8_t emrtdsigtext[EMRTD_MAX_FILE_SIZE] = { 0x00 }; size_t toplen, signeddatalen, emrtdsigcontainerlen, emrtdsiglen, emrtdsigtextlen = 0; - if (!emrtd_lds_get_data_by_tag(data, (int) datalen, top, (int *) &toplen, 0x30, 0x00, false, true, 0)) { + if (!emrtd_lds_get_data_by_tag(data, datalen, top, &toplen, 0x30, 0x00, false, true, 0)) { PrintAndLogEx(ERR, "Failed to read top from EF_SOD."); return false; } PrintAndLogEx(DEBUG, "top: %s.", sprint_hex_inrow(top, toplen)); - if (!emrtd_lds_get_data_by_tag(top, (int) toplen, signeddata, (int *) &signeddatalen, 0xA0, 0x00, false, false, 0)) { + if (!emrtd_lds_get_data_by_tag(top, toplen, signeddata, &signeddatalen, 0xA0, 0x00, false, false, 0)) { PrintAndLogEx(ERR, "Failed to read signedData from EF_SOD."); return false; } @@ -1506,14 +1506,14 @@ static int emrtd_ef_sod_extract_signatures(uint8_t *data, size_t datalen, uint8_ PrintAndLogEx(DEBUG, "signeddata: %s.", sprint_hex_inrow(signeddata, signeddatalen)); // Do true on reading into the tag as it's a "sequence" - if (!emrtd_lds_get_data_by_tag(signeddata, (int) signeddatalen, emrtdsigcontainer, (int *) &emrtdsigcontainerlen, 0x30, 0x00, false, true, 0)) { + if (!emrtd_lds_get_data_by_tag(signeddata, signeddatalen, emrtdsigcontainer, &emrtdsigcontainerlen, 0x30, 0x00, false, true, 0)) { PrintAndLogEx(ERR, "Failed to read eMRTDSignature container from EF_SOD."); return false; } PrintAndLogEx(DEBUG, "emrtdsigcontainer: %s.", sprint_hex_inrow(emrtdsigcontainer, emrtdsigcontainerlen)); - if (!emrtd_lds_get_data_by_tag(emrtdsigcontainer, (int) emrtdsigcontainerlen, emrtdsig, (int *) &emrtdsiglen, 0xA0, 0x00, false, false, 0)) { + if (!emrtd_lds_get_data_by_tag(emrtdsigcontainer, emrtdsigcontainerlen, emrtdsig, &emrtdsiglen, 0xA0, 0x00, false, false, 0)) { PrintAndLogEx(ERR, "Failed to read eMRTDSignature from EF_SOD."); return false; } @@ -1521,7 +1521,7 @@ static int emrtd_ef_sod_extract_signatures(uint8_t *data, size_t datalen, uint8_ PrintAndLogEx(DEBUG, "emrtdsig: %s.", sprint_hex_inrow(emrtdsig, emrtdsiglen)); // TODO: Not doing memcpy here, it didn't work, fix it somehow - if (!emrtd_lds_get_data_by_tag(emrtdsig, (int) emrtdsiglen, emrtdsigtext, (int *) &emrtdsigtextlen, 0x04, 0x00, false, false, 0)) { + if (!emrtd_lds_get_data_by_tag(emrtdsig, emrtdsiglen, emrtdsigtext, &emrtdsigtextlen, 0x04, 0x00, false, false, 0)) { PrintAndLogEx(ERR, "Failed to read eMRTDSignature (text) from EF_SOD."); return false; } @@ -1555,7 +1555,7 @@ static int emrtd_print_ef_sod_info(uint8_t *data, size_t datalen) { PrintAndLogEx(DEBUG, "hash data: %s", sprint_hex_inrow(emrtdsig, emrtdsiglen)); - if (!emrtd_lds_get_data_by_tag(emrtdsig, (int) emrtdsiglen, hashlist, (int *) &hashlistlen, 0x30, 0x00, false, true, 1)) { + if (!emrtd_lds_get_data_by_tag(emrtdsig, emrtdsiglen, hashlist, &hashlistlen, 0x30, 0x00, false, true, 1)) { PrintAndLogEx(ERR, "Failed to read hash list from EF_SOD."); return false; } @@ -1571,8 +1571,8 @@ static int emrtd_print_ef_sod_info(uint8_t *data, size_t datalen) { switch (hashlist[offset]) { case 0x30: - emrtd_lds_get_data_by_tag(hashlist + offset + e_fieldlen + 1, (int) e_datalen, hashidstr, (int *) &hashidstrlen, 0x02, 0x00, false, false, 0); - emrtd_lds_get_data_by_tag(hashlist + offset + e_fieldlen + 1, (int) e_datalen, hash, (int *) &hashlen, 0x04, 0x00, false, false, 0); + emrtd_lds_get_data_by_tag(hashlist + offset + e_fieldlen + 1, e_datalen, hashidstr, &hashidstrlen, 0x02, 0x00, false, false, 0); + emrtd_lds_get_data_by_tag(hashlist + offset + e_fieldlen + 1, e_datalen, hash, &hashlen, 0x04, 0x00, false, false, 0); PrintAndLogEx(SUCCESS, "Hash for EF_DG%i: %s", hashidstr[0], sprint_hex_inrow(hash, hashlen)); break; } @@ -1625,7 +1625,7 @@ int infoHF_EMRTD(char *documentnumber, char *dob, char *expiry, bool BAC_availab } uint8_t filelist[50]; - int filelistlen = 0; + size_t filelistlen = 0; if (!emrtd_lds_get_data_by_tag(response, resplen, filelist, &filelistlen, 0x5c, 0x00, false, true, 0)) { PrintAndLogEx(ERR, "Failed to read file list from EF_COM."); @@ -1676,7 +1676,7 @@ int infoHF_EMRTD_offline(const char *path) { } uint8_t filelist[50]; - int filelistlen = 0; + size_t filelistlen = 0; res = emrtd_lds_get_data_by_tag(data, datalen, filelist, &filelistlen, 0x5c, 0x00, false, true, 0); if (!res) { PrintAndLogEx(ERR, "Failed to read file list from EF_COM."); From 4962cb84ecc73bbc6e54a92fa0240fa582b7c7d1 Mon Sep 17 00:00:00 2001 From: Ave Date: Wed, 23 Dec 2020 22:37:51 +0300 Subject: [PATCH 191/682] emrtd: Note that MRZ option is for passports (TD3) only --- client/src/cmdhfemrtd.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/src/cmdhfemrtd.c b/client/src/cmdhfemrtd.c index d90c7e79e..499b06c1a 100644 --- a/client/src/cmdhfemrtd.c +++ b/client/src/cmdhfemrtd.c @@ -1831,7 +1831,7 @@ static int cmd_hf_emrtd_info(const char *Cmd) { arg_str0("n", "documentnumber", "", "document number, up to 9 chars"), arg_str0("d", "dateofbirth", "", "date of birth in YYMMDD format"), arg_str0("e", "expiry", "", "expiry in YYMMDD format"), - arg_str0("m", "mrz", "<[0-9A-Z<]>", "2nd line of MRZ, 44 chars"), + arg_str0("m", "mrz", "<[0-9A-Z<]>", "2nd line of MRZ, 44 chars (passports only)"), arg_str0(NULL, "path", "", "display info from offline dump stored in dirpath"), arg_param_end }; From 73dec1e072c13bd4fb039e3bcd6fc95e606975d6 Mon Sep 17 00:00:00 2001 From: Ave Date: Wed, 23 Dec 2020 19:57:50 +0000 Subject: [PATCH 192/682] ui: Load readline after stdio.h --- client/src/ui.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/client/src/ui.c b/client/src/ui.c index f9595e5f3..25d5edf7e 100644 --- a/client/src/ui.c +++ b/client/src/ui.c @@ -14,9 +14,6 @@ #if !defined(_WIN32) #define _POSIX_C_SOURCE 200112L #endif -#ifdef HAVE_READLINE -#include -#endif #include "ui.h" #include "commonutil.h" // ARRAYLEN @@ -24,6 +21,10 @@ #include #include +#ifdef HAVE_READLINE +#include +#endif + #include #include "util.h" #include "proxmark3.h" // PROXLOG From 9987ebf53493df280d9ef04e4e3efecc201f97b4 Mon Sep 17 00:00:00 2001 From: Ave Date: Wed, 23 Dec 2020 23:08:34 +0300 Subject: [PATCH 193/682] emrtd: Use memcmp for JPEG headers --- client/src/cmdhfemrtd.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/client/src/cmdhfemrtd.c b/client/src/cmdhfemrtd.c index 499b06c1a..1a51ea427 100644 --- a/client/src/cmdhfemrtd.c +++ b/client/src/cmdhfemrtd.c @@ -693,17 +693,19 @@ static bool emrtd_select_and_read(uint8_t *dataout, int *dataoutlen, const char return true; } +const uint8_t jpeg_header[4] = { 0xFF, 0xD8, 0xFF, 0xE0 }; +const uint8_t jpeg2k_header[6] = { 0x00, 0x00, 0x00, 0x0C, 0x6A, 0x50 }; + static int emrtd_dump_ef_dg2(uint8_t *file_contents, size_t file_length) { int offset, datalen = 0; // This is a hacky impl that just looks for the image header. I'll improve it eventually. // based on mrpkey.py - // FF D8 FF E0 -> JPEG - // 00 00 00 0C 6A 50 -> JPEG 2000 // Note: Doing file_length - 6 to account for the longest data we're checking. + // Checks first byte before the rest to reduce overhead for (offset = 0; offset < file_length - 6; offset++) { - if ((file_contents[offset] == 0xFF && file_contents[offset + 1] == 0xD8 && file_contents[offset + 2] == 0xFF && file_contents[offset + 3] == 0xE0) || - (file_contents[offset] == 0x00 && file_contents[offset + 1] == 0x00 && file_contents[offset + 2] == 0x00 && file_contents[offset + 3] == 0x0C && file_contents[offset + 4] == 0x6A && file_contents[offset + 5] == 0x50)) { + if ((file_contents[offset] == 0xFF && memcmp(jpeg_header, file_contents + offset, 4) != 0) || + (file_contents[offset] == 0x00 && memcmp(jpeg2k_header, file_contents + offset, 6) != 0)) { datalen = file_length - offset; break; } From f26e027e23259f247c87efc6ffc998ff80b07624 Mon Sep 17 00:00:00 2001 From: Ave Date: Wed, 23 Dec 2020 23:13:13 +0300 Subject: [PATCH 194/682] gitignore: Ignore emrtd dumps --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 081c0f8e8..94b4c221b 100644 --- a/.gitignore +++ b/.gitignore @@ -98,6 +98,7 @@ tools/andrew/* tools/jtag_openocd/openocd_configuration ppls patches/* *- Copy.* +/EF_* client/lualibs/mfc_default_keys.lua client/lualibs/pm3_cmd.lua From a1762fa4a30dde35e92d2f0c5164aa3c5d59c948 Mon Sep 17 00:00:00 2001 From: Ave Date: Wed, 23 Dec 2020 23:21:54 +0300 Subject: [PATCH 195/682] emrtd: Mark biometrics as EAC-only and introduce the concept --- client/src/cmdhfemrtd.c | 48 ++++++++++++++++++++--------------------- client/src/cmdhfemrtd.h | 1 + 2 files changed, 25 insertions(+), 24 deletions(-) diff --git a/client/src/cmdhfemrtd.c b/client/src/cmdhfemrtd.c index 1a51ea427..fa669f103 100644 --- a/client/src/cmdhfemrtd.c +++ b/client/src/cmdhfemrtd.c @@ -84,28 +84,28 @@ typedef enum { // list must match dg_table } emrtd_dg_enum; static emrtd_dg_t dg_table[] = { -// tag fileid filename desc pace req fast parser dumper - {0x60, "011E", "EF_COM", "Header and Data Group Presence Information", false, true, true, emrtd_print_ef_com_info, NULL}, - {0x61, "0101", "EF_DG1", "Details recorded in MRZ", false, true, true, emrtd_print_ef_dg1_info, NULL}, - {0x75, "0102", "EF_DG2", "Encoded Face", false, true, false, NULL, emrtd_dump_ef_dg2}, - {0x63, "0103", "EF_DG3", "Encoded Finger(s)", true, false, false, NULL, NULL}, - {0x76, "0104", "EF_DG4", "Encoded Eye(s)", true, false, false, NULL, NULL}, - {0x65, "0105", "EF_DG5", "Displayed Portrait", false, false, false, NULL, emrtd_dump_ef_dg5}, - {0x66, "0106", "EF_DG6", "Reserved for Future Use", false, false, false, NULL, NULL}, - {0x67, "0107", "EF_DG7", "Displayed Signature or Usual Mark", false, false, false, NULL, emrtd_dump_ef_dg7}, - {0x68, "0108", "EF_DG8", "Data Feature(s)", false, false, true, NULL, NULL}, - {0x69, "0109", "EF_DG9", "Structure Feature(s)", false, false, true, NULL, NULL}, - {0x6a, "010A", "EF_DG10", "Substance Feature(s)", false, false, true, NULL, NULL}, - {0x6b, "010B", "EF_DG11", "Additional Personal Detail(s)", false, false, true, emrtd_print_ef_dg11_info, NULL}, - {0x6c, "010C", "EF_DG12", "Additional Document Detail(s)", false, false, true, emrtd_print_ef_dg12_info, NULL}, - {0x6d, "010D", "EF_DG13", "Optional Detail(s)", false, false, true, NULL, NULL}, - {0x6e, "010E", "EF_DG14", "Security Options", false, false, true, NULL, NULL}, - {0x6f, "010F", "EF_DG15", "Active Authentication Public Key Info", false, false, true, NULL, NULL}, - {0x70, "0110", "EF_DG16", "Person(s) to Notify", false, false, true, NULL, NULL}, - {0x77, "011D", "EF_SOD", "Document Security Object", false, false, true, emrtd_print_ef_sod_info, emrtd_dump_ef_sod}, - {0xff, "011C", "EF_CardAccess", "PACE SecurityInfos", true, true, true, NULL, NULL}, - {0xff, "011D", "EF_CardSecurity", "PACE SecurityInfos for Chip Authentication Mapping", true, false, true, NULL, NULL}, - {0x00, NULL, NULL, NULL, false, false, false, NULL, NULL} +// tag fileid filename desc pace eac req fast parser dumper + {0x60, "011E", "EF_COM", "Header and Data Group Presence Information", false, false, true, true, emrtd_print_ef_com_info, NULL}, + {0x61, "0101", "EF_DG1", "Details recorded in MRZ", false, false, true, true, emrtd_print_ef_dg1_info, NULL}, + {0x75, "0102", "EF_DG2", "Encoded Face", false, false, true, false, NULL, emrtd_dump_ef_dg2}, + {0x63, "0103", "EF_DG3", "Encoded Finger(s)", false, true, false, false, NULL, NULL}, + {0x76, "0104", "EF_DG4", "Encoded Eye(s)", false, true, false, false, NULL, NULL}, + {0x65, "0105", "EF_DG5", "Displayed Portrait", false, false, false, false, NULL, emrtd_dump_ef_dg5}, + {0x66, "0106", "EF_DG6", "Reserved for Future Use", false, false, false, false, NULL, NULL}, + {0x67, "0107", "EF_DG7", "Displayed Signature or Usual Mark", false, false, false, false, NULL, emrtd_dump_ef_dg7}, + {0x68, "0108", "EF_DG8", "Data Feature(s)", false, false, false, true, NULL, NULL}, + {0x69, "0109", "EF_DG9", "Structure Feature(s)", false, false, false, true, NULL, NULL}, + {0x6a, "010A", "EF_DG10", "Substance Feature(s)", false, false, false, true, NULL, NULL}, + {0x6b, "010B", "EF_DG11", "Additional Personal Detail(s)", false, false, false, true, emrtd_print_ef_dg11_info, NULL}, + {0x6c, "010C", "EF_DG12", "Additional Document Detail(s)", false, false, false, true, emrtd_print_ef_dg12_info, NULL}, + {0x6d, "010D", "EF_DG13", "Optional Detail(s)", false, false, false, true, NULL, NULL}, + {0x6e, "010E", "EF_DG14", "Security Options", false, false, false, true, NULL, NULL}, + {0x6f, "010F", "EF_DG15", "Active Authentication Public Key Info", false, false, false, true, NULL, NULL}, + {0x70, "0110", "EF_DG16", "Person(s) to Notify", false, false, false, true, NULL, NULL}, + {0x77, "011D", "EF_SOD", "Document Security Object", false, false, false, true, emrtd_print_ef_sod_info, emrtd_dump_ef_sod}, + {0xff, "011C", "EF_CardAccess", "PACE SecurityInfos", true, false, true, true, NULL, NULL}, + {0xff, "011D", "EF_CardSecurity", "PACE SecurityInfos for Chip Authentication Mapping", true, false, false, true, NULL, NULL}, + {0x00, NULL, NULL, NULL, false, false, false, false, NULL, NULL} }; static emrtd_dg_t *emrtd_tag_to_dg(uint8_t tag) { @@ -1026,7 +1026,7 @@ int dumpHF_EMRTD(char *documentnumber, char *dob, char *expiry, bool BAC_availab continue; } PrintAndLogEx(DEBUG, "Current file: %s", dg->filename); - if (!dg->pace) { + if (!dg->pace && !dg->eac) { emrtd_dump_file(ks_enc, ks_mac, ssc, dg->fileid, dg->filename, BAC, use_14b); } } @@ -1643,7 +1643,7 @@ int infoHF_EMRTD(char *documentnumber, char *dob, char *expiry, bool BAC_availab PrintAndLogEx(INFO, "File tag not found, skipping: %02X", filelist[i]); continue; } - if (dg->fastdump && !dg->pace) { + if (dg->fastdump && !dg->pace && !dg->eac) { if (emrtd_select_and_read(response, &resplen, dg->fileid, ks_enc, ks_mac, ssc, BAC, use_14b)) { if (dg->parser != NULL) dg->parser(response, resplen); diff --git a/client/src/cmdhfemrtd.h b/client/src/cmdhfemrtd.h index 9df7846ad..bcae56538 100644 --- a/client/src/cmdhfemrtd.h +++ b/client/src/cmdhfemrtd.h @@ -19,6 +19,7 @@ typedef struct emrtd_dg_s { const char *filename; const char *desc; bool pace; + bool eac; // EAC only (we can't dump these) bool required; // some are required only if PACE bool fastdump; // fast to dump int (*parser)(uint8_t *data, size_t datalen); From 9e7d515c37d1303de07b635b0e0682ddb4a8303c Mon Sep 17 00:00:00 2001 From: Ave Date: Wed, 23 Dec 2020 23:52:31 +0300 Subject: [PATCH 196/682] emrtd info: Don't print EF_SOD info --- client/src/cmdhfemrtd.c | 163 ++++++++++++++++++++-------------------- 1 file changed, 81 insertions(+), 82 deletions(-) diff --git a/client/src/cmdhfemrtd.c b/client/src/cmdhfemrtd.c index fa669f103..88a79707a 100644 --- a/client/src/cmdhfemrtd.c +++ b/client/src/cmdhfemrtd.c @@ -58,7 +58,6 @@ static int emrtd_print_ef_com_info(uint8_t *data, size_t datalen); static int emrtd_print_ef_dg1_info(uint8_t *data, size_t datalen); static int emrtd_print_ef_dg11_info(uint8_t *data, size_t datalen); static int emrtd_print_ef_dg12_info(uint8_t *data, size_t datalen); -static int emrtd_print_ef_sod_info(uint8_t *data, size_t datalen); typedef enum { // list must match dg_table EF_COM = 0, @@ -102,7 +101,7 @@ static emrtd_dg_t dg_table[] = { {0x6e, "010E", "EF_DG14", "Security Options", false, false, false, true, NULL, NULL}, {0x6f, "010F", "EF_DG15", "Active Authentication Public Key Info", false, false, false, true, NULL, NULL}, {0x70, "0110", "EF_DG16", "Person(s) to Notify", false, false, false, true, NULL, NULL}, - {0x77, "011D", "EF_SOD", "Document Security Object", false, false, false, true, emrtd_print_ef_sod_info, emrtd_dump_ef_sod}, + {0x77, "011D", "EF_SOD", "Document Security Object", false, false, false, false, NULL, emrtd_dump_ef_sod}, {0xff, "011C", "EF_CardAccess", "PACE SecurityInfos", true, false, true, true, NULL, NULL}, {0xff, "011D", "EF_CardSecurity", "PACE SecurityInfos for Chip Authentication Mapping", true, false, false, true, NULL, NULL}, {0x00, NULL, NULL, NULL, false, false, false, false, NULL, NULL} @@ -1484,106 +1483,106 @@ static int emrtd_print_ef_dg12_info(uint8_t *data, size_t datalen) { return PM3_SUCCESS; } -static int emrtd_ef_sod_extract_signatures(uint8_t *data, size_t datalen, uint8_t *dataout, size_t *dataoutlen) { - // very very very very cursed code. - uint8_t top[EMRTD_MAX_FILE_SIZE] = { 0x00 }; - uint8_t signeddata[EMRTD_MAX_FILE_SIZE] = { 0x00 }; - uint8_t emrtdsigcontainer[EMRTD_MAX_FILE_SIZE] = { 0x00 }; - uint8_t emrtdsig[EMRTD_MAX_FILE_SIZE] = { 0x00 }; - uint8_t emrtdsigtext[EMRTD_MAX_FILE_SIZE] = { 0x00 }; - size_t toplen, signeddatalen, emrtdsigcontainerlen, emrtdsiglen, emrtdsigtextlen = 0; +// static int emrtd_ef_sod_extract_signatures(uint8_t *data, size_t datalen, uint8_t *dataout, size_t *dataoutlen) { +// // very very very very cursed code. +// uint8_t top[EMRTD_MAX_FILE_SIZE] = { 0x00 }; +// uint8_t signeddata[EMRTD_MAX_FILE_SIZE] = { 0x00 }; +// uint8_t emrtdsigcontainer[EMRTD_MAX_FILE_SIZE] = { 0x00 }; +// uint8_t emrtdsig[EMRTD_MAX_FILE_SIZE] = { 0x00 }; +// uint8_t emrtdsigtext[EMRTD_MAX_FILE_SIZE] = { 0x00 }; +// size_t toplen, signeddatalen, emrtdsigcontainerlen, emrtdsiglen, emrtdsigtextlen = 0; - if (!emrtd_lds_get_data_by_tag(data, datalen, top, &toplen, 0x30, 0x00, false, true, 0)) { - PrintAndLogEx(ERR, "Failed to read top from EF_SOD."); - return false; - } +// if (!emrtd_lds_get_data_by_tag(data, datalen, top, &toplen, 0x30, 0x00, false, true, 0)) { +// PrintAndLogEx(ERR, "Failed to read top from EF_SOD."); +// return false; +// } - PrintAndLogEx(DEBUG, "top: %s.", sprint_hex_inrow(top, toplen)); +// PrintAndLogEx(DEBUG, "top: %s.", sprint_hex_inrow(top, toplen)); - if (!emrtd_lds_get_data_by_tag(top, toplen, signeddata, &signeddatalen, 0xA0, 0x00, false, false, 0)) { - PrintAndLogEx(ERR, "Failed to read signedData from EF_SOD."); - return false; - } +// if (!emrtd_lds_get_data_by_tag(top, toplen, signeddata, &signeddatalen, 0xA0, 0x00, false, false, 0)) { +// PrintAndLogEx(ERR, "Failed to read signedData from EF_SOD."); +// return false; +// } - PrintAndLogEx(DEBUG, "signeddata: %s.", sprint_hex_inrow(signeddata, signeddatalen)); +// PrintAndLogEx(DEBUG, "signeddata: %s.", sprint_hex_inrow(signeddata, signeddatalen)); - // Do true on reading into the tag as it's a "sequence" - if (!emrtd_lds_get_data_by_tag(signeddata, signeddatalen, emrtdsigcontainer, &emrtdsigcontainerlen, 0x30, 0x00, false, true, 0)) { - PrintAndLogEx(ERR, "Failed to read eMRTDSignature container from EF_SOD."); - return false; - } +// // Do true on reading into the tag as it's a "sequence" +// if (!emrtd_lds_get_data_by_tag(signeddata, signeddatalen, emrtdsigcontainer, &emrtdsigcontainerlen, 0x30, 0x00, false, true, 0)) { +// PrintAndLogEx(ERR, "Failed to read eMRTDSignature container from EF_SOD."); +// return false; +// } - PrintAndLogEx(DEBUG, "emrtdsigcontainer: %s.", sprint_hex_inrow(emrtdsigcontainer, emrtdsigcontainerlen)); +// PrintAndLogEx(DEBUG, "emrtdsigcontainer: %s.", sprint_hex_inrow(emrtdsigcontainer, emrtdsigcontainerlen)); - if (!emrtd_lds_get_data_by_tag(emrtdsigcontainer, emrtdsigcontainerlen, emrtdsig, &emrtdsiglen, 0xA0, 0x00, false, false, 0)) { - PrintAndLogEx(ERR, "Failed to read eMRTDSignature from EF_SOD."); - return false; - } +// if (!emrtd_lds_get_data_by_tag(emrtdsigcontainer, emrtdsigcontainerlen, emrtdsig, &emrtdsiglen, 0xA0, 0x00, false, false, 0)) { +// PrintAndLogEx(ERR, "Failed to read eMRTDSignature from EF_SOD."); +// return false; +// } - PrintAndLogEx(DEBUG, "emrtdsig: %s.", sprint_hex_inrow(emrtdsig, emrtdsiglen)); +// PrintAndLogEx(DEBUG, "emrtdsig: %s.", sprint_hex_inrow(emrtdsig, emrtdsiglen)); - // TODO: Not doing memcpy here, it didn't work, fix it somehow - if (!emrtd_lds_get_data_by_tag(emrtdsig, emrtdsiglen, emrtdsigtext, &emrtdsigtextlen, 0x04, 0x00, false, false, 0)) { - PrintAndLogEx(ERR, "Failed to read eMRTDSignature (text) from EF_SOD."); - return false; - } - memcpy(dataout, emrtdsigtext, emrtdsigtextlen); - *dataoutlen = emrtdsigtextlen; - return PM3_SUCCESS; -} +// // TODO: Not doing memcpy here, it didn't work, fix it somehow +// if (!emrtd_lds_get_data_by_tag(emrtdsig, emrtdsiglen, emrtdsigtext, &emrtdsigtextlen, 0x04, 0x00, false, false, 0)) { +// PrintAndLogEx(ERR, "Failed to read eMRTDSignature (text) from EF_SOD."); +// return false; +// } +// memcpy(dataout, emrtdsigtext, emrtdsigtextlen); +// *dataoutlen = emrtdsigtextlen; +// return PM3_SUCCESS; +// } -static int emrtd_print_ef_sod_info(uint8_t *data, size_t datalen) { - uint8_t emrtdsig[EMRTD_MAX_FILE_SIZE] = { 0x00 }; - uint8_t hashlist[EMRTD_MAX_FILE_SIZE] = { 0x00 }; - uint8_t hash[65] = { 0x00 }; - size_t hashlen = 0; +// static int emrtd_print_ef_sod_info(uint8_t *data, size_t datalen) { +// uint8_t emrtdsig[EMRTD_MAX_FILE_SIZE] = { 0x00 }; +// uint8_t hashlist[EMRTD_MAX_FILE_SIZE] = { 0x00 }; +// uint8_t hash[65] = { 0x00 }; +// size_t hashlen = 0; - uint8_t hashidstr[4] = { 0x00 }; - size_t hashidstrlen = 0; +// uint8_t hashidstr[4] = { 0x00 }; +// size_t hashidstrlen = 0; - // size_t emrtdsiglen, e_datalen, e_fieldlen = 0; - size_t emrtdsiglen = 0; - size_t hashlistlen = 0; - size_t e_datalen = 0; - size_t e_fieldlen = 0; - size_t offset = 0; +// // size_t emrtdsiglen, e_datalen, e_fieldlen = 0; +// size_t emrtdsiglen = 0; +// size_t hashlistlen = 0; +// size_t e_datalen = 0; +// size_t e_fieldlen = 0; +// size_t offset = 0; - PrintAndLogEx(NORMAL, ""); - PrintAndLogEx(INFO, "-------------------- " _CYAN_("EF_SOD") " --------------------"); +// PrintAndLogEx(NORMAL, ""); +// PrintAndLogEx(INFO, "-------------------- " _CYAN_("EF_SOD") " --------------------"); - if (emrtd_ef_sod_extract_signatures(data, datalen, emrtdsig, &emrtdsiglen) != PM3_SUCCESS) { - return false; - } +// if (emrtd_ef_sod_extract_signatures(data, datalen, emrtdsig, &emrtdsiglen) != PM3_SUCCESS) { +// return false; +// } - PrintAndLogEx(DEBUG, "hash data: %s", sprint_hex_inrow(emrtdsig, emrtdsiglen)); +// PrintAndLogEx(DEBUG, "hash data: %s", sprint_hex_inrow(emrtdsig, emrtdsiglen)); - if (!emrtd_lds_get_data_by_tag(emrtdsig, emrtdsiglen, hashlist, &hashlistlen, 0x30, 0x00, false, true, 1)) { - PrintAndLogEx(ERR, "Failed to read hash list from EF_SOD."); - return false; - } +// if (!emrtd_lds_get_data_by_tag(emrtdsig, emrtdsiglen, hashlist, &hashlistlen, 0x30, 0x00, false, true, 1)) { +// PrintAndLogEx(ERR, "Failed to read hash list from EF_SOD."); +// return false; +// } - PrintAndLogEx(DEBUG, "hash list: %s", sprint_hex_inrow(hashlist, hashlistlen)); +// PrintAndLogEx(DEBUG, "hash list: %s", sprint_hex_inrow(hashlist, hashlistlen)); - while (offset < hashlistlen) { - // Get the length of the element - e_datalen = emrtd_get_asn1_data_length(hashlist + offset, hashlistlen - offset, 1); +// while (offset < hashlistlen) { +// // Get the length of the element +// e_datalen = emrtd_get_asn1_data_length(hashlist + offset, hashlistlen - offset, 1); - // Get the length of the element's length - e_fieldlen = emrtd_get_asn1_field_length(hashlist + offset, hashlistlen - offset, 1); +// // Get the length of the element's length +// e_fieldlen = emrtd_get_asn1_field_length(hashlist + offset, hashlistlen - offset, 1); - switch (hashlist[offset]) { - case 0x30: - emrtd_lds_get_data_by_tag(hashlist + offset + e_fieldlen + 1, e_datalen, hashidstr, &hashidstrlen, 0x02, 0x00, false, false, 0); - emrtd_lds_get_data_by_tag(hashlist + offset + e_fieldlen + 1, e_datalen, hash, &hashlen, 0x04, 0x00, false, false, 0); - PrintAndLogEx(SUCCESS, "Hash for EF_DG%i: %s", hashidstr[0], sprint_hex_inrow(hash, hashlen)); - break; - } - // + 1 for length of ID - offset += 1 + e_datalen + e_fieldlen; - } +// switch (hashlist[offset]) { +// case 0x30: +// emrtd_lds_get_data_by_tag(hashlist + offset + e_fieldlen + 1, e_datalen, hashidstr, &hashidstrlen, 0x02, 0x00, false, false, 0); +// emrtd_lds_get_data_by_tag(hashlist + offset + e_fieldlen + 1, e_datalen, hash, &hashlen, 0x04, 0x00, false, false, 0); +// PrintAndLogEx(SUCCESS, "Hash for EF_DG%i: %s", hashidstr[0], sprint_hex_inrow(hash, hashlen)); +// break; +// } +// // + 1 for length of ID +// offset += 1 + e_datalen + e_fieldlen; +// } - return PM3_SUCCESS; -} +// return PM3_SUCCESS; +// } int infoHF_EMRTD(char *documentnumber, char *dob, char *expiry, bool BAC_available) { uint8_t response[EMRTD_MAX_FILE_SIZE] = { 0x00 }; @@ -1696,7 +1695,7 @@ int infoHF_EMRTD_offline(const char *path) { PrintAndLogEx(INFO, "File tag not found, skipping: %02X", filelist[i]); continue; } - if (!dg->pace) { + if (!dg->pace && !dg->eac) { strcpy(filepath, path); strncat(filepath, PATHSEP, 2); strcat(filepath, dg->filename); From b91bc9bb856e9895dd2c3c10bd5fa92bf6a83030 Mon Sep 17 00:00:00 2001 From: tcprst Date: Wed, 23 Dec 2020 16:01:50 -0500 Subject: [PATCH 197/682] hf_legic Lua - change method for temp file naming --- client/luascripts/hf_legic.lua | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/client/luascripts/hf_legic.lua b/client/luascripts/hf_legic.lua index b8b9931cd..ca06ae8c5 100644 --- a/client/luascripts/hf_legic.lua +++ b/client/luascripts/hf_legic.lua @@ -704,12 +704,31 @@ function writeFile(bytes, filename) return true end +function getRandomTempName() + local upperCase = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" + local lowerCase = "abcdefghijklmnopqrstuvwxyz" + + local characterSet = upperCase .. lowerCase + + local keyLength = 8 + local output = "" + + for i = 1, keyLength do + local rand = math.random(#characterSet) + output = output .. string.sub(characterSet, rand, rand) + end + + output = "hf-legic-temp-" .. output + + return output +end + --- -- read from pm3 into virtual-tag function readFromPM3() local tag, bytes, infile --infile="legic.temp" - infile=os.tmpname() + infile=getRandomTempName() core.console("hf legic dump -f "..infile) tag=readFile(infile..".bin") os.remove(infile) From 902b6c98668e894901995f5e9de76969943f48c5 Mon Sep 17 00:00:00 2001 From: iceman1001 Date: Wed, 23 Dec 2020 22:54:56 +0100 Subject: [PATCH 198/682] hf/lf tune - show Volt max. And use corect session support identification --- client/src/ui.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/client/src/ui.c b/client/src/ui.c index 25d5edf7e..885910919 100644 --- a/client/src/ui.c +++ b/client/src/ui.c @@ -657,7 +657,8 @@ void print_progress(size_t count, uint64_t max, barMode_t style) { "\xe2\x96\x88", }; - uint8_t mode = session.emoji_mode == EMOJI; + uint8_t mode = session.supports_colors; + const char *block[] = {"#", "\xe2\x96\x88"}; // use a 3-byte space in emoji mode to ease computations const char *space[] = {" ", "\xe2\x80\x80"}; @@ -704,12 +705,12 @@ void print_progress(size_t count, uint64_t max, barMode_t style) { break; } case STYLE_MIXED: { - sprintf(buffer, "%s [ %zu mV / %3u V ]", cbar, count, (uint32_t)(count / 1000)); + sprintf(buffer, "%s [ %zu mV / %2u V / %2u Vmax ]", cbar, count, (uint32_t)(count / 1000), (uint32_t)(max / 1000)); printf("\b%c[2K\r[" _YELLOW_("=")"] %s ", 27, buffer); break; } case STYLE_VALUE: { - printf("[" _YELLOW_("=")"] %zu mV / %3u V \r", count, (uint32_t)(count / 1000)); + printf("[" _YELLOW_("=")"] %zu mV / %2u V / %2u Vmax\r", count, (uint32_t)(count / 1000), (uint32_t)(max / 1000)); break; } } From 3d76be2dbdcfa7bc293ba06614b7acd6a451cccb Mon Sep 17 00:00:00 2001 From: iceman1001 Date: Thu, 24 Dec 2020 10:55:36 +0100 Subject: [PATCH 199/682] coverity fix --- client/src/cmdhf.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/client/src/cmdhf.c b/client/src/cmdhf.c index ada69e905..85044f27b 100644 --- a/client/src/cmdhf.c +++ b/client/src/cmdhf.c @@ -52,13 +52,15 @@ int CmdHFSearch(const char *Cmd) { CLIParserInit(&ctx, "hf search", "Will try to find a HF read out of the unknown tag.\n" "Continues to search for all different HF protocols.", - "hf sniff" + "hf search" ); void *argtable[] = { arg_param_begin, arg_param_end }; CLIExecWithReturn(ctx, Cmd, argtable, true); + CLIParserFree(ctx); + int res = PM3_ESOFT; PROMPT_CLEARLINE; From d801d2be0f793787c60b98224eb1dc255c961916 Mon Sep 17 00:00:00 2001 From: iceman1001 Date: Sat, 26 Dec 2020 22:11:56 +0100 Subject: [PATCH 200/682] lf/hf tune - color vs emoji... --- client/src/ui.c | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/client/src/ui.c b/client/src/ui.c index 885910919..391279e52 100644 --- a/client/src/ui.c +++ b/client/src/ui.c @@ -657,7 +657,7 @@ void print_progress(size_t count, uint64_t max, barMode_t style) { "\xe2\x96\x88", }; - uint8_t mode = session.supports_colors; + uint8_t mode = (session.emoji_mode == EMOJI); const char *block[] = {"#", "\xe2\x96\x88"}; // use a 3-byte space in emoji mode to ease computations @@ -689,11 +689,15 @@ void print_progress(size_t count, uint64_t max, barMode_t style) { char *cbar = calloc(collen, sizeof(uint8_t)); // Add colors - int p60 = unit * (width * 60 / 100); - int p20 = unit * (width * 20 / 100); - snprintf(cbar, collen, _GREEN_("%.*s"), p60, bar); - snprintf(cbar + strlen(cbar), collen - strlen(cbar), _CYAN_("%.*s"), p20, bar + p60); - snprintf(cbar + strlen(cbar), collen - strlen(cbar), _YELLOW_("%.*s"), unit * width - p60 - p20, bar + p60 + p20); + if ( session.supports_colors ) { + int p60 = unit * (width * 60 / 100); + int p20 = unit * (width * 20 / 100); + snprintf(cbar, collen, _GREEN_("%.*s"), p60, bar); + snprintf(cbar + strlen(cbar), collen - strlen(cbar), _CYAN_("%.*s"), p20, bar + p60); + snprintf(cbar + strlen(cbar), collen - strlen(cbar), _YELLOW_("%.*s"), unit * width - p60 - p20, bar + p60 + p20); + } else { + snprintf(cbar, collen, "%s", bar); + } size_t len = strlen(cbar) + 32; char *buffer = calloc(len, sizeof(uint8_t)); From 20bc2b060b4867f441ee7b2bf44ca3f5fc420095 Mon Sep 17 00:00:00 2001 From: iceman1001 Date: Sat, 26 Dec 2020 22:12:22 +0100 Subject: [PATCH 201/682] textual --- README.md | 6 ------ 1 file changed, 6 deletions(-) diff --git a/README.md b/README.md index b8140e407..56af79cda 100644 --- a/README.md +++ b/README.md @@ -135,12 +135,6 @@ The separation from official Proxmark3 repo gives us a lot of freedom to create The official PM3-GUI from Gaucho will not work. The new [Proxmark3 Universal GUI](https://github.com/burma69/PM3UniversalGUI) will work more or less. Change is needed in order to show helptext when client isn't connected to a device. We don't know how active the maintainers. -## The end - -- July 2018 [@herrmann1001](https://mobile.twitter.com/herrmann1001) -- updated Feb 2019 [@5w0rdfish](https://mobile.twitter.com/5w0rdFish) -- updated 2019 [@doegox](https://mobile.twitter.com/doegox) - # Donations Nothing says thank you as much as a donation. So if you feel the love, do feel free to become a iceman patron. For some tiers it comes with rewards. From 9007629213890eb523eaa648b6c2a3a4cc7c6ebf Mon Sep 17 00:00:00 2001 From: ikarus Date: Sun, 27 Dec 2020 15:44:59 +0100 Subject: [PATCH 202/682] apdufind: filter reoccurring SWs & reset filed on tractive errors. --- client/src/cmdhf14a.c | 60 ++++++++++++++++++++++++++++--------------- client/src/ui.c | 2 +- 2 files changed, 41 insertions(+), 21 deletions(-) diff --git a/client/src/cmdhf14a.c b/client/src/cmdhf14a.c index d4418ee62..fd03d60a4 100644 --- a/client/src/cmdhf14a.c +++ b/client/src/cmdhf14a.c @@ -2135,15 +2135,26 @@ int infoHF14A(bool verbose, bool do_nack_test, bool do_aid_search) { } static uint16_t get_sw(uint8_t *d, uint8_t n) { - if (n < 2) + if (n < 2) { return 0; - + } n -= 2; return d[n] * 0x0100 + d[n + 1]; } +static uint64_t inc_sw_error_occurence(uint16_t sw, uint64_t all_sw[256][256]) { + uint8_t sw1 = (uint8_t)(sw >> 8); + uint8_t sw2 = (uint8_t)(0xff & sw); + if (sw1 == 0x90 && sw2 == 0x00) { + return 0; // Don't count successes. + } + if (sw1 == 0x6d && sw2 == 0x00) { + return 0xffffffffffffffffULL; // Always max "Instruction not supported". + } + return ++all_sw[sw1][sw2]; +} + static int CmdHf14AFindapdu(const char *Cmd) { - // TODO: What response values should be considerd "valid" or "instersting" (worth dispalying)? // TODO: Option to select AID/File (and skip INS 0xA4). // TODO: Validate the decoding of the APDU (not specific to this command, check // https://cardwerk.com/smartcards/smartcard_standard_ISO7816-4_5_basic_organizations.aspx#chap5_3_2). @@ -2161,12 +2172,13 @@ static int CmdHf14AFindapdu(const char *Cmd) { void *argtable[] = { arg_param_begin, - arg_str0("c", "cla", "", "Start value of CLASS (1 hex byte)"), - arg_str0("i", "ins", "", "Start value of INSTRUCTION (1 hex byte)"), - arg_str0(NULL, "p1", "", "Start value of P1 (1 hex byte)"), - arg_str0(NULL, "p2", "", "Start value of P2 (1 hex byte)"), - arg_u64_0("r", "reset", "", "Minimum secondes before resetting the tag (to prevent timeout issues). Default is 5 minutes"), - arg_lit0("v", "verbose", "Verbose output"), + arg_str0("c", "cla", "", "Start value of CLASS (1 hex byte)"), + arg_str0("i", "ins", "", "Start value of INSTRUCTION (1 hex byte)"), + arg_str0(NULL, "p1", "", "Start value of P1 (1 hex byte)"), + arg_str0(NULL, "p2", "", "Start value of P2 (1 hex byte)"), + arg_u64_0("r", "reset", "", "Minimum secondes before resetting the tag (to prevent timeout issues). Default is 5 minutes"), + arg_u64_0("e", "error-limit", "", "Maximum times an status word other than 0x9000 or 0x6D00 is shown. Default is 500."), + arg_lit0("v", "verbose", "Verbose output"), arg_param_end }; CLIExecWithReturn(ctx, Cmd, argtable, true); @@ -2184,7 +2196,8 @@ static int CmdHf14AFindapdu(const char *Cmd) { uint8_t p2_arg[1] = {0}; CLIGetHexWithReturn(ctx, 4, p2_arg, &p2_len); uint64_t reset_time = arg_get_u64_def(ctx, 5, 5 * 60); // Reset every 5 minutes. - bool verbose = arg_get_lit(ctx, 6); + uint64_t error_limit = arg_get_u64_def(ctx, 6, 500); + bool verbose = arg_get_lit(ctx, 7); CLIParserFree(ctx); @@ -2211,6 +2224,8 @@ static int CmdHf14AFindapdu(const char *Cmd) { PrintAndLogEx(INFO, "Press " _GREEN_("") " to exit"); bool inc_p1 = true; + uint64_t all_sw[256][256] = {0}; + uint64_t sw_occurences = 0; uint64_t t_start = msclock(); uint64_t t_last_reset = msclock(); @@ -2233,33 +2248,38 @@ static int CmdHf14AFindapdu(const char *Cmd) { int command_n = sizeof(command); res = ExchangeAPDU14a(command, command_n, activate_field, keep_field_on, response, sizeof(response), &response_n); if (res) { + DropField(); + activate_field = true; continue; } + uint16_t sw = get_sw(response, response_n); + sw_occurences = inc_sw_error_occurence(sw, all_sw); // Was there and length error? If so, try with Le length (case 2 instad of case 1, // https://stackoverflow.com/a/30679558). Le = 0x00 will get interpreted as extended length APDU // with Le being 0x0100. - uint16_t sw = get_sw(response, response_n); bool command_with_le = false; if (sw == 0x6700) { - PrintAndLogEx(INFO, "Got response for APDU \"%02X%02X%02X%02X\": %04X (%s)", cla, ins, p1, p2, - sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff)); - PrintAndLogEx(INFO, "Resending current command with Le = 0x0100 (extended length APDU)"); + if (sw_occurences < error_limit) { + PrintAndLogEx(INFO, "Got response for APDU \"%02X%02X%02X%02X\": %04X (%s)", cla, ins, p1, p2, + sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff)); + PrintAndLogEx(INFO, "Resending current command with Le = 0x0100 (extended length APDU)"); + } uint8_t command2[7] = {cla, ins, p1, p2, 0x00}; int command2_n = sizeof(command2); res = ExchangeAPDU14a(command2, command2_n, activate_field, keep_field_on, response, sizeof(response), &response_n); if (res) { + DropField(); + activate_field = true; continue; } + sw = get_sw(response, response_n); + sw_occurences = inc_sw_error_occurence(sw, all_sw); command_with_le = true; } - // Check response. - sw = get_sw(response, response_n); - if (sw != 0x6a86 && - sw != 0x6986 && - sw != 0x6d00 - ) { + // Show response. + if (sw_occurences < error_limit) { if (command_with_le) { PrintAndLogEx(INFO, "Got response for APDU \"%02X%02X%02X%02X00\": %04X (%s)", cla, ins, p1, p2, sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff)); diff --git a/client/src/ui.c b/client/src/ui.c index 391279e52..b7e63e7dd 100644 --- a/client/src/ui.c +++ b/client/src/ui.c @@ -689,7 +689,7 @@ void print_progress(size_t count, uint64_t max, barMode_t style) { char *cbar = calloc(collen, sizeof(uint8_t)); // Add colors - if ( session.supports_colors ) { + if (session.supports_colors) { int p60 = unit * (width * 60 / 100); int p20 = unit * (width * 20 / 100); snprintf(cbar, collen, _GREEN_("%.*s"), p60, bar); From 28df590fc845f24bbc9c32542a5ca9fcd31eaf4f Mon Sep 17 00:00:00 2001 From: ikarus Date: Sun, 27 Dec 2020 20:20:19 +0100 Subject: [PATCH 203/682] apdufind: added option to skip instrcutions. (This helps if a tag might be locked permanently with a certain instruction. You can just skip it.) --- client/src/cmdhf14a.c | 26 +++++++++++++++++++------- doc/commands.md | 4 ++-- 2 files changed, 21 insertions(+), 9 deletions(-) diff --git a/client/src/cmdhf14a.c b/client/src/cmdhf14a.c index fd03d60a4..f66b29e1c 100644 --- a/client/src/cmdhf14a.c +++ b/client/src/cmdhf14a.c @@ -2159,7 +2159,6 @@ static int CmdHf14AFindapdu(const char *Cmd) { // TODO: Validate the decoding of the APDU (not specific to this command, check // https://cardwerk.com/smartcards/smartcard_standard_ISO7816-4_5_basic_organizations.aspx#chap5_3_2). // TODO: Check all cases (APDUs) with no data bytes (no/short/extended length). - // TODO: Option to blacklist instructions (or whole APDUs). CLIParserContext *ctx; CLIParserInit(&ctx, "hf 14a apdufind", "Enumerate APDU's of ISO7816 protocol to find valid CLS/INS/P1P2 commands.\n" @@ -2168,6 +2167,7 @@ static int CmdHf14AFindapdu(const char *Cmd) { "Tag must be on antenna before running.", "hf 14a apdufind\n" "hf 14a apdufind --cla 80\n" + "hf 14a apdufind --cla 80 --error-limit 20 --skip-ins a4 --skip-ins b0\n" ); void *argtable[] = { @@ -2177,7 +2177,8 @@ static int CmdHf14AFindapdu(const char *Cmd) { arg_str0(NULL, "p1", "", "Start value of P1 (1 hex byte)"), arg_str0(NULL, "p2", "", "Start value of P2 (1 hex byte)"), arg_u64_0("r", "reset", "", "Minimum secondes before resetting the tag (to prevent timeout issues). Default is 5 minutes"), - arg_u64_0("e", "error-limit", "", "Maximum times an status word other than 0x9000 or 0x6D00 is shown. Default is 500."), + arg_u64_0("e", "error-limit", "", "Maximum times an status word other than 0x9000 or 0x6D00 is shown. Default is 256."), + arg_strx0("s", "skip-ins", "", "Do not test an instructions (can be specifed multiple times)"), arg_lit0("v", "verbose", "Verbose output"), arg_param_end }; @@ -2195,9 +2196,12 @@ static int CmdHf14AFindapdu(const char *Cmd) { int p2_len = 0; uint8_t p2_arg[1] = {0}; CLIGetHexWithReturn(ctx, 4, p2_arg, &p2_len); - uint64_t reset_time = arg_get_u64_def(ctx, 5, 5 * 60); // Reset every 5 minutes. - uint64_t error_limit = arg_get_u64_def(ctx, 6, 500); - bool verbose = arg_get_lit(ctx, 7); + uint64_t reset_time = arg_get_u64_def(ctx, 5, 5 * 60); + uint64_t error_limit = arg_get_u64_def(ctx, 6, 256); + int ignore_ins_len = 0; + uint8_t ignore_ins_arg[250] = {0}; + CLIGetHexWithReturn(ctx, 7, ignore_ins_arg, &ignore_ins_len); + bool verbose = arg_get_lit(ctx, 8); CLIParserFree(ctx); @@ -2239,6 +2243,13 @@ static int CmdHf14AFindapdu(const char *Cmd) { goto out; } + // Skip/Ignore this instrctuion? + for (int i = 0; i < ignore_ins_len; i++) { + if (ins == ignore_ins_arg[i]) { + goto next_ins; + } + } + if (verbose) { PrintAndLogEx(INFO, "Status: [ CLA " _GREEN_("%02X") " INS " _GREEN_("%02X") " P1 " _GREEN_("%02X") " P2 " _GREEN_("%02X") " ]", cla, ins, p1, p2); } @@ -2250,7 +2261,7 @@ static int CmdHf14AFindapdu(const char *Cmd) { if (res) { DropField(); activate_field = true; - continue; + goto next_ins; } uint16_t sw = get_sw(response, response_n); sw_occurences = inc_sw_error_occurence(sw, all_sw); @@ -2271,7 +2282,7 @@ static int CmdHf14AFindapdu(const char *Cmd) { if (res) { DropField(); activate_field = true; - continue; + goto next_ins; } sw = get_sw(response, response_n); sw_occurences = inc_sw_error_occurence(sw, all_sw); @@ -2293,6 +2304,7 @@ static int CmdHf14AFindapdu(const char *Cmd) { sprint_ascii(response, response_n - 2)); } } +next_ins: activate_field = false; // Do not reativate the filed until the next reset. } while (++ins != ins_arg[0]); // Increment P1/P2 in an alternating fashion. diff --git a/doc/commands.md b/doc/commands.md index e1e445296..991f4a590 100644 --- a/doc/commands.md +++ b/doc/commands.md @@ -198,8 +198,8 @@ Check column "offline" for their availability. |command |offline |description |------- |------- |----------- |`hf epa help `|Y |`This help` -|`hf epa cnonces `|N |` Acquire n>0 encrypted PACE nonces of size m>0 with d sec pauses` -|`hf epa preplay `|N |` Perform PACE protocol by replaying given APDUs` +|`hf epa cnonces `|N |`Acquire encrypted PACE nonces of specific size` +|`hf epa preplay `|N |`Perform PACE protocol by replaying given APDUs` ### hf emrtd From 4494c47e5fe53c6f249e6d0e00a8d3a48c93f354 Mon Sep 17 00:00:00 2001 From: ikarus Date: Sun, 27 Dec 2020 20:31:30 +0100 Subject: [PATCH 204/682] reverted the faulty edits by make style to doc/commands.md. --- doc/commands.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/commands.md b/doc/commands.md index 991f4a590..e1e445296 100644 --- a/doc/commands.md +++ b/doc/commands.md @@ -198,8 +198,8 @@ Check column "offline" for their availability. |command |offline |description |------- |------- |----------- |`hf epa help `|Y |`This help` -|`hf epa cnonces `|N |`Acquire encrypted PACE nonces of specific size` -|`hf epa preplay `|N |`Perform PACE protocol by replaying given APDUs` +|`hf epa cnonces `|N |` Acquire n>0 encrypted PACE nonces of size m>0 with d sec pauses` +|`hf epa preplay `|N |` Perform PACE protocol by replaying given APDUs` ### hf emrtd From 438cada2cf7729d5bed42f59a6a70d9b8d1d3efa Mon Sep 17 00:00:00 2001 From: tharexde Date: Sun, 27 Dec 2020 22:22:44 +0100 Subject: [PATCH 205/682] commits after xcode crash --- armsrc/appmain.c | 4 +++ armsrc/em4x50.c | 67 +++++++++++++++++++++++++++++++++++++++- armsrc/em4x50.h | 1 + client/src/cmdlfem4x50.c | 39 +++++++++++++++++++++++ client/src/cmdlfem4x50.h | 1 + include/em4x50.h | 4 +++ include/pm3_cmd.h | 1 + 7 files changed, 116 insertions(+), 1 deletion(-) diff --git a/armsrc/appmain.c b/armsrc/appmain.c index fe8566363..87b17afd9 100644 --- a/armsrc/appmain.c +++ b/armsrc/appmain.c @@ -1163,6 +1163,10 @@ static void PacketReceived(PacketCommandNG *packet) { em4x50_chk((uint8_t *)packet->data.asBytes); break; } + case CMD_LF_EM4X50_TEST: { + em4x50_test((em4x50_test_t *)packet->data.asBytes); + break; + } #endif #ifdef WITH_EM4x70 diff --git a/armsrc/em4x50.c b/armsrc/em4x50.c index 437afd956..a84a911c5 100644 --- a/armsrc/em4x50.c +++ b/armsrc/em4x50.c @@ -431,7 +431,6 @@ static int find_double_listen_window(bool bcommand) { // send RM for request mode em4x50_reader_send_bit(0); em4x50_reader_send_bit(0); - LED_B_OFF(); return PM3_SUCCESS; @@ -724,13 +723,27 @@ static bool em4x50_sim_send_word(uint32_t word) { static bool em4x50_sim_send_listen_window(void) { + bool cond = false; uint16_t check = 0; + uint32_t tval1[5 * EM4X50_T_TAG_FULL_PERIOD] = {0}; + uint32_t tval2[5 * EM4X50_T_TAG_FULL_PERIOD] = {0}; + + StartTicks(); for (int t = 0; t < 5 * EM4X50_T_TAG_FULL_PERIOD; t++) { + cond = ((t >= 3 * EM4X50_T_TAG_FULL_PERIOD) && (t < 4 * EM4X50_T_TAG_FULL_PERIOD)); + // wait until SSC_CLK goes HIGH + if (cond) { + AT91C_BASE_TC1->TC_CCR = AT91C_TC_SWTRG; + AT91C_BASE_TC0->TC_CCR = AT91C_TC_SWTRG; + while (AT91C_BASE_TC0->TC_CV > 0); + } + while (!(AT91C_BASE_PIOA->PIO_PDSR & GPIO_SSC_CLK)) { WDT_HIT(); + if (check == 1000) { if (BUTTON_PRESS()) return false; @@ -738,6 +751,8 @@ static bool em4x50_sim_send_listen_window(void) { } ++check; } + if (cond) + tval1[t] = GetTicks(); if (t >= 4 * EM4X50_T_TAG_FULL_PERIOD) SHORT_COIL(); @@ -753,6 +768,12 @@ static bool em4x50_sim_send_listen_window(void) { check = 0; // wait until SSC_CLK goes LOW + if (cond) { + AT91C_BASE_TC1->TC_CCR = AT91C_TC_SWTRG; + AT91C_BASE_TC0->TC_CCR = AT91C_TC_SWTRG; + while (AT91C_BASE_TC0->TC_CV > 0); + } + while (AT91C_BASE_PIOA->PIO_PDSR & GPIO_SSC_CLK) { WDT_HIT(); if (check == 1000) { @@ -762,8 +783,16 @@ static bool em4x50_sim_send_listen_window(void) { } ++check; } + if (cond) + tval2[t] = GetTicks(); } + for (int t = 0; t < 5 * EM4X50_T_TAG_FULL_PERIOD; t++) { + //if (tval[t] > 4) + Dbprintf("%3i probably RM intialization found: delta = %i %i", t, tval1[t], tval2[t]); + } + Dbprintf(""); + return true; } @@ -1281,3 +1310,39 @@ void em4x50_sim(uint8_t *filename) { lf_finalize(); reply_ng(CMD_LF_EM4X50_SIM, status, NULL, 0); } + +void em4x50_test(em4x50_test_t *ett) { + + int status = PM3_EFAILED; + + em4x50_setup_read(); + + if (ett->field) { + LOW(GPIO_SSC_DOUT); + LED_A_ON(); + + if (DBGLEVEL >= DBG_DEBUG) + Dbprintf("switched field on"); + + status = 1; + } else { + HIGH(GPIO_SSC_DOUT); + LED_A_OFF(); + + if (DBGLEVEL >= DBG_DEBUG) + Dbprintf("switched field off"); + + status = 0; + } + + while (BUTTON_PRESS() == false) { + + if (AT91C_BASE_PIOA->PIO_PDSR & GPIO_SSC_CLK) { + Dbprintf("field on"); + } else if (!(AT91C_BASE_PIOA->PIO_PDSR & GPIO_SSC_CLK)){ + Dbprintf("field on"); + } + } + + reply_ng(CMD_LF_EM4X50_TEST, status, NULL, 0); +} diff --git a/armsrc/em4x50.h b/armsrc/em4x50.h index 9f9b38351..87451e198 100644 --- a/armsrc/em4x50.h +++ b/armsrc/em4x50.h @@ -22,5 +22,6 @@ void em4x50_login(uint32_t *password); void em4x50_sim(uint8_t *filename); void em4x50_reader(void); void em4x50_chk(uint8_t *filename); +void em4x50_test(em4x50_test_t *ett); #endif /* EM4X50_H */ diff --git a/client/src/cmdlfem4x50.c b/client/src/cmdlfem4x50.c index 79b019a03..8182a822f 100644 --- a/client/src/cmdlfem4x50.c +++ b/client/src/cmdlfem4x50.c @@ -1158,6 +1158,43 @@ int CmdEM4x50Sim(const char *Cmd) { return resp.status; } +int CmdEM4x50Test(const char *Cmd) { + CLIParserContext *ctx; + CLIParserInit(&ctx, "lf em 4x50 test", + "perform EM4x50 tests.", + "lf em 4x50 test --field 1 -> reader field on \n" + ); + + void *argtable[] = { + arg_param_begin, + arg_lit0("", "field", "field off/on"), + arg_param_end + }; + + CLIExecWithReturn(ctx, Cmd, argtable, true); + + em4x50_test_t ett; + ett.field = arg_get_lit(ctx, 1); + CLIParserFree(ctx); + + // start + clearCommandBuffer(); + PacketResponseNG resp; + SendCommandNG(CMD_LF_EM4X50_TEST, (uint8_t *)&ett, sizeof(ett)); + WaitForResponse(CMD_LF_EM4X50_TEST, &resp); + + // print response + if (resp.status == 1) { + PrintAndLogEx(SUCCESS, "Field switched " _GREEN_("on")); + } else if (resp.status == 0) { + PrintAndLogEx(SUCCESS, "Field switched " _GREEN_("off")); + } else { + PrintAndLogEx(FAILED, "Test call " _RED_("failed")); + } + + return resp.status; +} + static command_t CommandTable[] = { {"help", CmdHelp, AlwaysAvailable, "This help"}, {"brute", CmdEM4x50Brute, IfPm3EM4x50, "guess password of EM4x50"}, @@ -1175,6 +1212,7 @@ static command_t CommandTable[] = { {"eload", CmdEM4x50ELoad, IfPm3EM4x50, "upload dump of EM4x50 to emulator memory"}, {"esave", CmdEM4x50ESave, IfPm3EM4x50, "save emulator memory to file"}, {"eview", CmdEM4x50EView, IfPm3EM4x50, "view EM4x50 content in emulator memory"}, + {"test", CmdEM4x50Test, IfPm3EM4x50, "perform EM4x50 tests"}, {NULL, NULL, NULL, NULL} }; @@ -1188,3 +1226,4 @@ int CmdLFEM4X50(const char *Cmd) { clearCommandBuffer(); return CmdsParse(CommandTable, Cmd); } + diff --git a/client/src/cmdlfem4x50.h b/client/src/cmdlfem4x50.h index 0d5c04bc6..df9c587de 100644 --- a/client/src/cmdlfem4x50.h +++ b/client/src/cmdlfem4x50.h @@ -34,5 +34,6 @@ int CmdEM4x50ELoad(const char *Cmd); int CmdEM4x50ESave(const char *Cmd); int CmdEM4x50Chk(const char *Cmd); int CmdEM4x50EView(const char *Cmd); +int CmdEM4x50Test(const char *Cmd); #endif diff --git a/include/em4x50.h b/include/em4x50.h index 573c58375..27d71e661 100644 --- a/include/em4x50.h +++ b/include/em4x50.h @@ -46,6 +46,10 @@ typedef struct { uint32_t addresses; } PACKED em4x50_data_t; +typedef struct { + bool field; +} PACKED em4x50_test_t; + typedef struct { uint8_t byte[4]; } PACKED em4x50_word_t; diff --git a/include/pm3_cmd.h b/include/pm3_cmd.h index e3dc29aee..022b602e3 100644 --- a/include/pm3_cmd.h +++ b/include/pm3_cmd.h @@ -516,6 +516,7 @@ typedef struct { #define CMD_LF_EM4X50_READER 0x0251 #define CMD_LF_EM4X50_ESET 0x0252 #define CMD_LF_EM4X50_CHK 0x0253 +#define CMD_LF_EM4X50_TEST 0x0254 #define CMD_LF_EM4X70_INFO 0x0260 #define CMD_LF_EM4X70_WRITE 0x0261 #define CMD_LF_EM4X70_UNLOCK 0x0262 From 8233b2c914b775e5976b841cd2699d18383b5d55 Mon Sep 17 00:00:00 2001 From: iceman1001 Date: Mon, 28 Dec 2020 13:36:37 +0100 Subject: [PATCH 206/682] script now supports Gen1a, Gen1b, Gen2 type of MIFARE Ultralight family uid changeable cards --- client/luascripts/hf_mfu_setuid.lua | 44 ++++++++++++++++++++--------- 1 file changed, 31 insertions(+), 13 deletions(-) diff --git a/client/luascripts/hf_mfu_setuid.lua b/client/luascripts/hf_mfu_setuid.lua index 86bef09c3..f64d5cfab 100644 --- a/client/luascripts/hf_mfu_setuid.lua +++ b/client/luascripts/hf_mfu_setuid.lua @@ -4,26 +4,32 @@ local ansicolors = require('ansicolors') copyright = '' author = "Iceman" -version = 'v1.0.2' +version = 'v1.0.3' desc = [[ This script tries to set UID on a mifare Ultralight magic card which either - answers to chinese backdoor commands - brickable magic tag (must write in one session) + + It defaults to GEN1A type of uid changeable card. ]] example = [[ - -- backdoor magic tag + -- backdoor magic tag (gen1a) script run hf_mfu_setuid -u 11223344556677 - -- brickable magic tag + -- backdoor magic tag (gen1b) script run hf_mfu_setuid -b -u 11223344556677 + + -- brickable magic tag (gen2) + script run hf_mfu_setuid -2 -u 11223344556677 ]] usage = [[ -script run hf_mfu_setuid [-h] [-b] [-u ] +script run hf_mfu_setuid [-h] [-b] [-2] [-u ] ]] arguments = [[ -h : this help -u : UID (14 hexsymbols) - -b : write to brickable magic tag + -b : write to magic tag GEN1B + -2 : write to brickable magic tag GEN2 ]] local DEBUG = true @@ -65,23 +71,33 @@ local function help() end -- --- Set UID on magic command enabled -function magicUID(b0, b1, b2) +function magicUID(b0, b1, b2, isgen1a) - print('Using backdoor Magic tag function') + if isgen1a then + print('Using backdoor Magic tag (gen1a) function') + else + print('Using backdoor Magic tag (gen1b) function') + end -- write block 0 core.console('hf 14a raw -k -a -b 7 40') - core.console('hf 14a raw -k -a 43') + if isgen1a then + core.console('hf 14a raw -k -a 43') + end core.console('hf 14a raw -c -a A200'..b0) -- write block 1 core.console('hf 14a raw -k -a -b 7 40') - core.console('hf 14a raw -k -a 43') + if isgen1a then + core.console('hf 14a raw -k -a 43') + end core.console('hf 14a raw -c -a A201'..b1) -- write block 2 core.console('hf 14a raw -k -a -b 7 40') - core.console('hf 14a raw -k -a 43') + if isgen1a then + core.console('hf 14a raw -k -a 43') + end core.console('hf 14a raw -c -a A202'..b2) end -- @@ -113,10 +129,11 @@ function main(args) local tagtype = 1 -- Read the parameters - for o, a in getopt.getopt(args, 'hu:b') do + for o, a in getopt.getopt(args, 'hu:b2') do if o == 'h' then return help() end if o == 'u' then uid = a end if o == 'b' then tagtype = 2 end + if o == '2' then tagtype = 3 end end -- uid string checks @@ -137,10 +154,11 @@ function main(args) core.clearCommandBuffer() - if tagtype == 2 then + if tagtype == 3 then brickableUID(block0, block1, block2) else - magicUID(block0, block1, block2) + local is_gen1a = (tagtype == 1) + magicUID(block0, block1, block2, is_gen1a) end --halt From 201e2506b2e8c3d9a5c23893305effb6155f815f Mon Sep 17 00:00:00 2001 From: ikarus Date: Mon, 28 Dec 2020 15:38:35 +0100 Subject: [PATCH 207/682] apdufind: fixed bug which prevented a retry, if there was an error. --- client/src/cmdhf14a.c | 22 ++++++++++++++++------ 1 file changed, 16 insertions(+), 6 deletions(-) diff --git a/client/src/cmdhf14a.c b/client/src/cmdhf14a.c index f66b29e1c..150b49fee 100644 --- a/client/src/cmdhf14a.c +++ b/client/src/cmdhf14a.c @@ -2228,6 +2228,7 @@ static int CmdHf14AFindapdu(const char *Cmd) { PrintAndLogEx(INFO, "Press " _GREEN_("") " to exit"); bool inc_p1 = true; + bool skip_ins = false; uint64_t all_sw[256][256] = {0}; uint64_t sw_occurences = 0; uint64_t t_start = msclock(); @@ -2237,6 +2238,7 @@ static int CmdHf14AFindapdu(const char *Cmd) { do { do { do { +retry_ins: // Exit (was the Enter key pressed)? if (kbd_enter_pressed()) { PrintAndLogEx(INFO, "User interrupted detected. Aborting"); @@ -2246,9 +2248,14 @@ static int CmdHf14AFindapdu(const char *Cmd) { // Skip/Ignore this instrctuion? for (int i = 0; i < ignore_ins_len; i++) { if (ins == ignore_ins_arg[i]) { - goto next_ins; + skip_ins = true; + break; } } + if (skip_ins) { + skip_ins = false; + continue; + } if (verbose) { PrintAndLogEx(INFO, "Status: [ CLA " _GREEN_("%02X") " INS " _GREEN_("%02X") " P1 " _GREEN_("%02X") " P2 " _GREEN_("%02X") " ]", cla, ins, p1, p2); @@ -2261,7 +2268,7 @@ static int CmdHf14AFindapdu(const char *Cmd) { if (res) { DropField(); activate_field = true; - goto next_ins; + goto retry_ins; } uint16_t sw = get_sw(response, response_n); sw_occurences = inc_sw_error_occurence(sw, all_sw); @@ -2282,7 +2289,7 @@ static int CmdHf14AFindapdu(const char *Cmd) { if (res) { DropField(); activate_field = true; - goto next_ins; + goto retry_ins; } sw = get_sw(response, response_n); sw_occurences = inc_sw_error_occurence(sw, all_sw); @@ -2291,11 +2298,15 @@ static int CmdHf14AFindapdu(const char *Cmd) { // Show response. if (sw_occurences < error_limit) { + logLevel_t log_level = INFO; + if (sw == 0x9000) { + log_level = SUCCESS; + } if (command_with_le) { - PrintAndLogEx(INFO, "Got response for APDU \"%02X%02X%02X%02X00\": %04X (%s)", cla, ins, p1, p2, + PrintAndLogEx(log_level, "Got response for APDU \"%02X%02X%02X%02X00\": %04X (%s)", cla, ins, p1, p2, sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff)); } else { - PrintAndLogEx(INFO, "Got response for APDU \"%02X%02X%02X%02X\": %04X (%s)", cla, ins, p1, p2, + PrintAndLogEx(log_level, "Got response for APDU \"%02X%02X%02X%02X\": %04X (%s)", cla, ins, p1, p2, sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff)); } // Show response data. @@ -2304,7 +2315,6 @@ static int CmdHf14AFindapdu(const char *Cmd) { sprint_ascii(response, response_n - 2)); } } -next_ins: activate_field = false; // Do not reativate the filed until the next reset. } while (++ins != ins_arg[0]); // Increment P1/P2 in an alternating fashion. From 59e6658753d40c40ea7d4b0a6d0f23e7f9ee9762 Mon Sep 17 00:00:00 2001 From: ikarus Date: Mon, 28 Dec 2020 19:14:29 +0100 Subject: [PATCH 208/682] apdufind: added option to find Le=0 commands (case 2S) --- client/src/cmdhf14a.c | 81 +++++++++++++++---------------------------- 1 file changed, 28 insertions(+), 53 deletions(-) diff --git a/client/src/cmdhf14a.c b/client/src/cmdhf14a.c index 150b49fee..29d3afa65 100644 --- a/client/src/cmdhf14a.c +++ b/client/src/cmdhf14a.c @@ -2156,18 +2156,17 @@ static uint64_t inc_sw_error_occurence(uint16_t sw, uint64_t all_sw[256][256]) { static int CmdHf14AFindapdu(const char *Cmd) { // TODO: Option to select AID/File (and skip INS 0xA4). - // TODO: Validate the decoding of the APDU (not specific to this command, check - // https://cardwerk.com/smartcards/smartcard_standard_ISO7816-4_5_basic_organizations.aspx#chap5_3_2). - // TODO: Check all cases (APDUs) with no data bytes (no/short/extended length). + // TODO: Check all instructions with extended APDUs if the card support it. + // TODO: Option to reset tag before every command. CLIParserContext *ctx; CLIParserInit(&ctx, "hf 14a apdufind", - "Enumerate APDU's of ISO7816 protocol to find valid CLS/INS/P1P2 commands.\n" + "Enumerate APDU's of ISO7816 protocol to find valid CLS/INS/P1/P2 commands.\n" "It loops all 256 possible values for each byte.\n" - "The loop oder is INS -> P1/P2 (alternating) -> CLA\n" + "The loop oder is INS -> P1/P2 (alternating) -> CLA.\n" "Tag must be on antenna before running.", "hf 14a apdufind\n" "hf 14a apdufind --cla 80\n" - "hf 14a apdufind --cla 80 --error-limit 20 --skip-ins a4 --skip-ins b0\n" + "hf 14a apdufind --cla 80 --error-limit 20 --skip-ins a4 --skip-ins b0 --with-le\n" ); void *argtable[] = { @@ -2177,8 +2176,9 @@ static int CmdHf14AFindapdu(const char *Cmd) { arg_str0(NULL, "p1", "", "Start value of P1 (1 hex byte)"), arg_str0(NULL, "p2", "", "Start value of P2 (1 hex byte)"), arg_u64_0("r", "reset", "", "Minimum secondes before resetting the tag (to prevent timeout issues). Default is 5 minutes"), - arg_u64_0("e", "error-limit", "", "Maximum times an status word other than 0x9000 or 0x6D00 is shown. Default is 256."), + arg_u64_0("e", "error-limit", "", "Maximum times an status word other than 0x9000 or 0x6D00 is shown. Default is 512."), arg_strx0("s", "skip-ins", "", "Do not test an instructions (can be specifed multiple times)"), + arg_lit0("l", "with-le", "Serach for APDUs with Le=0 (case 2S) as well"), arg_lit0("v", "verbose", "Verbose output"), arg_param_end }; @@ -2197,11 +2197,12 @@ static int CmdHf14AFindapdu(const char *Cmd) { uint8_t p2_arg[1] = {0}; CLIGetHexWithReturn(ctx, 4, p2_arg, &p2_len); uint64_t reset_time = arg_get_u64_def(ctx, 5, 5 * 60); - uint64_t error_limit = arg_get_u64_def(ctx, 6, 256); + uint64_t error_limit = arg_get_u64_def(ctx, 6, 512); int ignore_ins_len = 0; uint8_t ignore_ins_arg[250] = {0}; CLIGetHexWithReturn(ctx, 7, ignore_ins_arg, &ignore_ins_len); - bool verbose = arg_get_lit(ctx, 8); + bool with_le = arg_get_lit(ctx, 8); + bool verbose = arg_get_lit(ctx, 9); CLIParserFree(ctx); @@ -2261,58 +2262,32 @@ retry_ins: PrintAndLogEx(INFO, "Status: [ CLA " _GREEN_("%02X") " INS " _GREEN_("%02X") " P1 " _GREEN_("%02X") " P2 " _GREEN_("%02X") " ]", cla, ins, p1, p2); } - // Send APDU. - uint8_t command[4] = {cla, ins, p1, p2}; - int command_n = sizeof(command); - res = ExchangeAPDU14a(command, command_n, activate_field, keep_field_on, response, sizeof(response), &response_n); - if (res) { - DropField(); - activate_field = true; - goto retry_ins; - } - uint16_t sw = get_sw(response, response_n); - sw_occurences = inc_sw_error_occurence(sw, all_sw); - - // Was there and length error? If so, try with Le length (case 2 instad of case 1, - // https://stackoverflow.com/a/30679558). Le = 0x00 will get interpreted as extended length APDU - // with Le being 0x0100. - bool command_with_le = false; - if (sw == 0x6700) { - if (sw_occurences < error_limit) { - PrintAndLogEx(INFO, "Got response for APDU \"%02X%02X%02X%02X\": %04X (%s)", cla, ins, p1, p2, - sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff)); - PrintAndLogEx(INFO, "Resending current command with Le = 0x0100 (extended length APDU)"); - } - uint8_t command2[7] = {cla, ins, p1, p2, 0x00}; - int command2_n = sizeof(command2); - res = ExchangeAPDU14a(command2, command2_n, activate_field, keep_field_on, response, sizeof(response), &response_n); + // Send APDU without Le (case 1) and with Le = 0 (case 2S), if "with-le" was set. + uint8_t command[5] = {cla, ins, p1, p2, 0x00}; + int command_n = 4; + for (int i = 0; i < 1 + with_le; i++) { + // Send APDU. + res = ExchangeAPDU14a(command, command_n + i, activate_field, keep_field_on, response, sizeof(response), &response_n); if (res) { DropField(); activate_field = true; goto retry_ins; } - sw = get_sw(response, response_n); + uint16_t sw = get_sw(response, response_n); sw_occurences = inc_sw_error_occurence(sw, all_sw); - command_with_le = true; - } - // Show response. - if (sw_occurences < error_limit) { - logLevel_t log_level = INFO; - if (sw == 0x9000) { - log_level = SUCCESS; - } - if (command_with_le) { - PrintAndLogEx(log_level, "Got response for APDU \"%02X%02X%02X%02X00\": %04X (%s)", cla, ins, p1, p2, + // Show response. + if (sw_occurences < error_limit) { + logLevel_t log_level = INFO; + if (sw == 0x9000) { + log_level = SUCCESS; + } + PrintAndLogEx(log_level, "Got response for APDU \"%s\": %04X (%s)", sprint_hex_inrow(command, command_n + i), sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff)); - } else { - PrintAndLogEx(log_level, "Got response for APDU \"%02X%02X%02X%02X\": %04X (%s)", cla, ins, p1, p2, - sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff)); - } - // Show response data. - if (response_n > 2) { - PrintAndLogEx(SUCCESS, "Response data is: %s | %s", sprint_hex_inrow(response, response_n - 2), - sprint_ascii(response, response_n - 2)); + if (response_n > 2) { + PrintAndLogEx(SUCCESS, "Response data is: %s | %s", sprint_hex_inrow(response, response_n - 2), + sprint_ascii(response, response_n - 2)); + } } } activate_field = false; // Do not reativate the filed until the next reset. From 11567dc2e35cb556a32f40496124952b7a3fa824 Mon Sep 17 00:00:00 2001 From: gator96100 Date: Mon, 28 Dec 2020 22:48:41 +0100 Subject: [PATCH 209/682] Added option for running with uncompressed .data section. Thanks @doegox --- armsrc/Makefile | 4 ++++ armsrc/appmain.c | 11 ++++++++++- armsrc/start.c | 20 +++++++++++++++++--- common_arm/Makefile.hal | 3 +++ 4 files changed, 34 insertions(+), 4 deletions(-) diff --git a/armsrc/Makefile b/armsrc/Makefile index 46ba4f027..074380058 100644 --- a/armsrc/Makefile +++ b/armsrc/Makefile @@ -217,8 +217,12 @@ $(OBJDIR)/fullimage.data.o: $(OBJDIR)/fullimage.data.bin.z $(Q)$(OBJCOPY) -O elf32-littlearm -I binary -B arm --rename-section .data=compressed_data $^ $@ $(OBJDIR)/fullimage.elf: $(OBJDIR)/fullimage.nodata.o $(OBJDIR)/fullimage.data.o +ifneq ($(SKIP_COMPRESSION),1) $(info [=] LD $@) $(Q)$(CC) $(CROSS_LDFLAGS) -Wl,-T,ldscript,-e,_osimage_entry,-Map,$(patsubst %.elf,%.map,$@) -o $@ $^ +else + $(Q)$(CP) $(OBJDIR)/fullimage.stage1.elf $@ +endif tarbin: $(OBJS) $(info TAR $@) diff --git a/armsrc/appmain.c b/armsrc/appmain.c index fe8566363..b4c3d6a30 100644 --- a/armsrc/appmain.c +++ b/armsrc/appmain.c @@ -257,6 +257,9 @@ void ReadMem(int addr) { /* osimage version information is linked in, cf commonutil.h */ /* bootrom version information is pointed to from _bootphase1_version_pointer */ extern char *_bootphase1_version_pointer, _flash_start, _flash_end, __data_src_start__; +#ifdef WITH_NO_COMPRESSION +extern char *_bootrom_end, _bootrom_start, __os_size__; +#endif static void SendVersion(void) { char temp[PM3_CMD_DATA_SIZE - 12]; /* Limited data payload in USB packets */ char VersionString[PM3_CMD_DATA_SIZE - 12] = { '\0' }; @@ -295,9 +298,11 @@ static void SendVersion(void) { strncat(VersionString, "\n ", sizeof(VersionString) - strlen(VersionString) - 1); } } +#ifndef WITH_NO_COMPRESSION // Send Chip ID and used flash memory uint32_t text_and_rodata_section_size = (uint32_t)&__data_src_start__ - (uint32_t)&_flash_start; uint32_t compressed_data_section_size = common_area.arg1; +#endif struct p { uint32_t id; @@ -308,7 +313,11 @@ static void SendVersion(void) { struct p payload; payload.id = *(AT91C_DBGU_CIDR); - payload.section_size = text_and_rodata_section_size + compressed_data_section_size; +#ifdef WITH_NO_COMPRESSION + payload.section_size = (uint32_t)&_bootrom_end - (uint32_t)&_bootrom_start + (uint32_t)&__os_size__; +#else + payload.section_size = text_and_rodata_section_size + compressed_data_section_size; +#endif payload.versionstr_len = strlen(VersionString) + 1; memcpy(payload.versionstr, VersionString, payload.versionstr_len); diff --git a/armsrc/start.c b/armsrc/start.c index 70eee5063..542b9f3f4 100644 --- a/armsrc/start.c +++ b/armsrc/start.c @@ -14,14 +14,16 @@ #include "proxmark3_arm.h" #include "appmain.h" +#ifndef WITH_NO_COMPRESSION #include "lz4.h" +#endif #include "BigBuf.h" #include "string.h" extern struct common_area common_area; extern char __data_src_start__, __data_start__, __data_end__, __bss_start__, __bss_end__; - +#ifndef WITH_NO_COMPRESSION static void uncompress_data_section(void) { int avail_in; memcpy(&avail_in, &__data_src_start__, sizeof(int)); @@ -35,6 +37,7 @@ static void uncompress_data_section(void) { // save the size of the compressed data section common_area.arg1 = avail_in; } +#endif void __attribute__((section(".startos"))) Vector(void); void Vector(void) { @@ -47,12 +50,23 @@ void Vector(void) { common_area.version = 1; } common_area.flags.osimage_present = 1; - - uncompress_data_section(); + +#ifdef WITH_NO_COMPRESSION + /* Set up data segment: Copy from flash to ram */ + char *src = &__data_src_start__; + char *dst = &__data_start__; + char *end = &__data_end__; + while(dst < end) *dst++ = *src++; + dst = &__bss_start__; + end = &__bss_end__; +#else + uncompress_data_section(); /* Set up (that is: clear) BSS. */ char *dst = &__bss_start__; char *end = &__bss_end__; +#endif + while (dst < end) *dst++ = 0; AppMain(); diff --git a/common_arm/Makefile.hal b/common_arm/Makefile.hal index 24d31261e..bfbe56d34 100644 --- a/common_arm/Makefile.hal +++ b/common_arm/Makefile.hal @@ -137,6 +137,9 @@ endif ifneq ($(SKIP_HFPLOT),1) PLATFORM_DEFS += -DWITH_HFPLOT endif +ifeq ($(SKIP_COMPRESSION),1) + PLATFORM_DEFS += -DWITH_NO_COMPRESSION +endif # Standalone mode ifneq ($(strip $(filter $(PLATFORM_DEFS),$(STANDALONE_REQ_DEFS))),$(strip $(STANDALONE_REQ_DEFS))) From bdb384f7b7417a08368ab6cc2a3cfed918641481 Mon Sep 17 00:00:00 2001 From: gator96100 Date: Mon, 28 Dec 2020 22:57:58 +0100 Subject: [PATCH 210/682] Fix for the Makefile.platform file --- armsrc/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/armsrc/Makefile b/armsrc/Makefile index 074380058..019d10820 100644 --- a/armsrc/Makefile +++ b/armsrc/Makefile @@ -217,7 +217,7 @@ $(OBJDIR)/fullimage.data.o: $(OBJDIR)/fullimage.data.bin.z $(Q)$(OBJCOPY) -O elf32-littlearm -I binary -B arm --rename-section .data=compressed_data $^ $@ $(OBJDIR)/fullimage.elf: $(OBJDIR)/fullimage.nodata.o $(OBJDIR)/fullimage.data.o -ifneq ($(SKIP_COMPRESSION),1) +ifeq (,$(findstring WITH_NO_COMPRESSION,$(APP_CFLAGS))) $(info [=] LD $@) $(Q)$(CC) $(CROSS_LDFLAGS) -Wl,-T,ldscript,-e,_osimage_entry,-Map,$(patsubst %.elf,%.map,$@) -o $@ $^ else From 7e2b10d413fb38965359e1bd1a91352bbf251bdf Mon Sep 17 00:00:00 2001 From: Ave Date: Tue, 29 Dec 2020 01:55:18 +0300 Subject: [PATCH 211/682] emrtd info (offline): Add basic hash verification support --- client/src/cmdhfemrtd.c | 235 ++++++++++++++++++++++------------------ client/src/cmdhfemrtd.h | 1 + 2 files changed, 131 insertions(+), 105 deletions(-) diff --git a/client/src/cmdhfemrtd.c b/client/src/cmdhfemrtd.c index 88a79707a..a088bfc7f 100644 --- a/client/src/cmdhfemrtd.c +++ b/client/src/cmdhfemrtd.c @@ -20,6 +20,7 @@ #include "protocols.h" // definitions of ISO14A/7816 protocol #include "emv/apduinfo.h" // GetAPDUCodeDescription #include "sha1.h" // KSeed calculation etc +#include "crypto/libpcrypto.h" // Hash calculation (sha256), TODO: AES too #include "mifare/desfire_crypto.h" // des_encrypt/des_decrypt #include "des.h" // mbedtls_des_key_set_parity #include "cmdhf14b.h" // exchange_14b_apdu @@ -83,28 +84,28 @@ typedef enum { // list must match dg_table } emrtd_dg_enum; static emrtd_dg_t dg_table[] = { -// tag fileid filename desc pace eac req fast parser dumper - {0x60, "011E", "EF_COM", "Header and Data Group Presence Information", false, false, true, true, emrtd_print_ef_com_info, NULL}, - {0x61, "0101", "EF_DG1", "Details recorded in MRZ", false, false, true, true, emrtd_print_ef_dg1_info, NULL}, - {0x75, "0102", "EF_DG2", "Encoded Face", false, false, true, false, NULL, emrtd_dump_ef_dg2}, - {0x63, "0103", "EF_DG3", "Encoded Finger(s)", false, true, false, false, NULL, NULL}, - {0x76, "0104", "EF_DG4", "Encoded Eye(s)", false, true, false, false, NULL, NULL}, - {0x65, "0105", "EF_DG5", "Displayed Portrait", false, false, false, false, NULL, emrtd_dump_ef_dg5}, - {0x66, "0106", "EF_DG6", "Reserved for Future Use", false, false, false, false, NULL, NULL}, - {0x67, "0107", "EF_DG7", "Displayed Signature or Usual Mark", false, false, false, false, NULL, emrtd_dump_ef_dg7}, - {0x68, "0108", "EF_DG8", "Data Feature(s)", false, false, false, true, NULL, NULL}, - {0x69, "0109", "EF_DG9", "Structure Feature(s)", false, false, false, true, NULL, NULL}, - {0x6a, "010A", "EF_DG10", "Substance Feature(s)", false, false, false, true, NULL, NULL}, - {0x6b, "010B", "EF_DG11", "Additional Personal Detail(s)", false, false, false, true, emrtd_print_ef_dg11_info, NULL}, - {0x6c, "010C", "EF_DG12", "Additional Document Detail(s)", false, false, false, true, emrtd_print_ef_dg12_info, NULL}, - {0x6d, "010D", "EF_DG13", "Optional Detail(s)", false, false, false, true, NULL, NULL}, - {0x6e, "010E", "EF_DG14", "Security Options", false, false, false, true, NULL, NULL}, - {0x6f, "010F", "EF_DG15", "Active Authentication Public Key Info", false, false, false, true, NULL, NULL}, - {0x70, "0110", "EF_DG16", "Person(s) to Notify", false, false, false, true, NULL, NULL}, - {0x77, "011D", "EF_SOD", "Document Security Object", false, false, false, false, NULL, emrtd_dump_ef_sod}, - {0xff, "011C", "EF_CardAccess", "PACE SecurityInfos", true, false, true, true, NULL, NULL}, - {0xff, "011D", "EF_CardSecurity", "PACE SecurityInfos for Chip Authentication Mapping", true, false, false, true, NULL, NULL}, - {0x00, NULL, NULL, NULL, false, false, false, false, NULL, NULL} +// tag dg# fileid filename desc pace eac req fast parser dumper + {0x60, 0, "011E", "EF_COM", "Header and Data Group Presence Information", false, false, true, true, emrtd_print_ef_com_info, NULL}, + {0x61, 1, "0101", "EF_DG1", "Details recorded in MRZ", false, false, true, true, emrtd_print_ef_dg1_info, NULL}, + {0x75, 2, "0102", "EF_DG2", "Encoded Face", false, false, true, false, NULL, emrtd_dump_ef_dg2}, + {0x63, 3, "0103", "EF_DG3", "Encoded Finger(s)", false, true, false, false, NULL, NULL}, + {0x76, 4, "0104", "EF_DG4", "Encoded Eye(s)", false, true, false, false, NULL, NULL}, + {0x65, 5, "0105", "EF_DG5", "Displayed Portrait", false, false, false, false, NULL, emrtd_dump_ef_dg5}, + {0x66, 6, "0106", "EF_DG6", "Reserved for Future Use", false, false, false, false, NULL, NULL}, + {0x67, 7, "0107", "EF_DG7", "Displayed Signature or Usual Mark", false, false, false, false, NULL, emrtd_dump_ef_dg7}, + {0x68, 8, "0108", "EF_DG8", "Data Feature(s)", false, false, false, true, NULL, NULL}, + {0x69, 9, "0109", "EF_DG9", "Structure Feature(s)", false, false, false, true, NULL, NULL}, + {0x6a, 10, "010A", "EF_DG10", "Substance Feature(s)", false, false, false, true, NULL, NULL}, + {0x6b, 11, "010B", "EF_DG11", "Additional Personal Detail(s)", false, false, false, true, emrtd_print_ef_dg11_info, NULL}, + {0x6c, 12, "010C", "EF_DG12", "Additional Document Detail(s)", false, false, false, true, emrtd_print_ef_dg12_info, NULL}, + {0x6d, 13, "010D", "EF_DG13", "Optional Detail(s)", false, false, false, true, NULL, NULL}, + {0x6e, 14, "010E", "EF_DG14", "Security Options", false, false, false, true, NULL, NULL}, + {0x6f, 15, "010F", "EF_DG15", "Active Authentication Public Key Info", false, false, false, true, NULL, NULL}, + {0x70, 16, "0110", "EF_DG16", "Person(s) to Notify", false, false, false, true, NULL, NULL}, + {0x77, 0, "011D", "EF_SOD", "Document Security Object", false, false, false, false, NULL, emrtd_dump_ef_sod}, + {0xff, 0, "011C", "EF_CardAccess", "PACE SecurityInfos", true, false, true, true, NULL, NULL}, + {0xff, 0, "011D", "EF_CardSecurity", "PACE SecurityInfos for Chip Authentication Mapping", true, false, false, true, NULL, NULL}, + {0x00, 0, NULL, NULL, NULL, false, false, false, false, NULL, NULL} }; static emrtd_dg_t *emrtd_tag_to_dg(uint8_t tag) { @@ -1483,106 +1484,105 @@ static int emrtd_print_ef_dg12_info(uint8_t *data, size_t datalen) { return PM3_SUCCESS; } -// static int emrtd_ef_sod_extract_signatures(uint8_t *data, size_t datalen, uint8_t *dataout, size_t *dataoutlen) { -// // very very very very cursed code. -// uint8_t top[EMRTD_MAX_FILE_SIZE] = { 0x00 }; -// uint8_t signeddata[EMRTD_MAX_FILE_SIZE] = { 0x00 }; -// uint8_t emrtdsigcontainer[EMRTD_MAX_FILE_SIZE] = { 0x00 }; -// uint8_t emrtdsig[EMRTD_MAX_FILE_SIZE] = { 0x00 }; -// uint8_t emrtdsigtext[EMRTD_MAX_FILE_SIZE] = { 0x00 }; -// size_t toplen, signeddatalen, emrtdsigcontainerlen, emrtdsiglen, emrtdsigtextlen = 0; +static int emrtd_ef_sod_extract_signatures(uint8_t *data, size_t datalen, uint8_t *dataout, size_t *dataoutlen) { + // very very very very cursed code. + uint8_t top[EMRTD_MAX_FILE_SIZE] = { 0x00 }; + uint8_t signeddata[EMRTD_MAX_FILE_SIZE] = { 0x00 }; + uint8_t emrtdsigcontainer[EMRTD_MAX_FILE_SIZE] = { 0x00 }; + uint8_t emrtdsig[EMRTD_MAX_FILE_SIZE] = { 0x00 }; + uint8_t emrtdsigtext[EMRTD_MAX_FILE_SIZE] = { 0x00 }; + size_t toplen, signeddatalen, emrtdsigcontainerlen, emrtdsiglen, emrtdsigtextlen = 0; -// if (!emrtd_lds_get_data_by_tag(data, datalen, top, &toplen, 0x30, 0x00, false, true, 0)) { -// PrintAndLogEx(ERR, "Failed to read top from EF_SOD."); -// return false; -// } + if (!emrtd_lds_get_data_by_tag(data, datalen, top, &toplen, 0x30, 0x00, false, true, 0)) { + PrintAndLogEx(ERR, "Failed to read top from EF_SOD."); + return false; + } -// PrintAndLogEx(DEBUG, "top: %s.", sprint_hex_inrow(top, toplen)); + PrintAndLogEx(DEBUG, "top: %s.", sprint_hex_inrow(top, toplen)); -// if (!emrtd_lds_get_data_by_tag(top, toplen, signeddata, &signeddatalen, 0xA0, 0x00, false, false, 0)) { -// PrintAndLogEx(ERR, "Failed to read signedData from EF_SOD."); -// return false; -// } + if (!emrtd_lds_get_data_by_tag(top, toplen, signeddata, &signeddatalen, 0xA0, 0x00, false, false, 0)) { + PrintAndLogEx(ERR, "Failed to read signedData from EF_SOD."); + return false; + } -// PrintAndLogEx(DEBUG, "signeddata: %s.", sprint_hex_inrow(signeddata, signeddatalen)); + PrintAndLogEx(DEBUG, "signeddata: %s.", sprint_hex_inrow(signeddata, signeddatalen)); -// // Do true on reading into the tag as it's a "sequence" -// if (!emrtd_lds_get_data_by_tag(signeddata, signeddatalen, emrtdsigcontainer, &emrtdsigcontainerlen, 0x30, 0x00, false, true, 0)) { -// PrintAndLogEx(ERR, "Failed to read eMRTDSignature container from EF_SOD."); -// return false; -// } + // Do true on reading into the tag as it's a "sequence" + if (!emrtd_lds_get_data_by_tag(signeddata, signeddatalen, emrtdsigcontainer, &emrtdsigcontainerlen, 0x30, 0x00, false, true, 0)) { + PrintAndLogEx(ERR, "Failed to read eMRTDSignature container from EF_SOD."); + return false; + } -// PrintAndLogEx(DEBUG, "emrtdsigcontainer: %s.", sprint_hex_inrow(emrtdsigcontainer, emrtdsigcontainerlen)); + PrintAndLogEx(DEBUG, "emrtdsigcontainer: %s.", sprint_hex_inrow(emrtdsigcontainer, emrtdsigcontainerlen)); -// if (!emrtd_lds_get_data_by_tag(emrtdsigcontainer, emrtdsigcontainerlen, emrtdsig, &emrtdsiglen, 0xA0, 0x00, false, false, 0)) { -// PrintAndLogEx(ERR, "Failed to read eMRTDSignature from EF_SOD."); -// return false; -// } + if (!emrtd_lds_get_data_by_tag(emrtdsigcontainer, emrtdsigcontainerlen, emrtdsig, &emrtdsiglen, 0xA0, 0x00, false, false, 0)) { + PrintAndLogEx(ERR, "Failed to read eMRTDSignature from EF_SOD."); + return false; + } -// PrintAndLogEx(DEBUG, "emrtdsig: %s.", sprint_hex_inrow(emrtdsig, emrtdsiglen)); + PrintAndLogEx(DEBUG, "emrtdsig: %s.", sprint_hex_inrow(emrtdsig, emrtdsiglen)); -// // TODO: Not doing memcpy here, it didn't work, fix it somehow -// if (!emrtd_lds_get_data_by_tag(emrtdsig, emrtdsiglen, emrtdsigtext, &emrtdsigtextlen, 0x04, 0x00, false, false, 0)) { -// PrintAndLogEx(ERR, "Failed to read eMRTDSignature (text) from EF_SOD."); -// return false; -// } -// memcpy(dataout, emrtdsigtext, emrtdsigtextlen); -// *dataoutlen = emrtdsigtextlen; -// return PM3_SUCCESS; -// } + // TODO: Not doing memcpy here, it didn't work, fix it somehow + if (!emrtd_lds_get_data_by_tag(emrtdsig, emrtdsiglen, emrtdsigtext, &emrtdsigtextlen, 0x04, 0x00, false, false, 0)) { + PrintAndLogEx(ERR, "Failed to read eMRTDSignature (text) from EF_SOD."); + return false; + } + memcpy(dataout, emrtdsigtext, emrtdsigtextlen); + *dataoutlen = emrtdsigtextlen; + return PM3_SUCCESS; +} -// static int emrtd_print_ef_sod_info(uint8_t *data, size_t datalen) { -// uint8_t emrtdsig[EMRTD_MAX_FILE_SIZE] = { 0x00 }; -// uint8_t hashlist[EMRTD_MAX_FILE_SIZE] = { 0x00 }; -// uint8_t hash[65] = { 0x00 }; -// size_t hashlen = 0; +static int emrtd_parse_ef_sod_hashes(uint8_t *data, size_t datalen, uint8_t *hashes) { + uint8_t emrtdsig[EMRTD_MAX_FILE_SIZE] = { 0x00 }; + uint8_t hashlist[EMRTD_MAX_FILE_SIZE] = { 0x00 }; + uint8_t hash[65] = { 0x00 }; + size_t hashlen = 0; -// uint8_t hashidstr[4] = { 0x00 }; -// size_t hashidstrlen = 0; + uint8_t hashidstr[4] = { 0x00 }; + size_t hashidstrlen = 0; -// // size_t emrtdsiglen, e_datalen, e_fieldlen = 0; -// size_t emrtdsiglen = 0; -// size_t hashlistlen = 0; -// size_t e_datalen = 0; -// size_t e_fieldlen = 0; -// size_t offset = 0; + // size_t emrtdsiglen, e_datalen, e_fieldlen = 0; + size_t emrtdsiglen = 0; + size_t hashlistlen = 0; + size_t e_datalen = 0; + size_t e_fieldlen = 0; + size_t offset = 0; -// PrintAndLogEx(NORMAL, ""); -// PrintAndLogEx(INFO, "-------------------- " _CYAN_("EF_SOD") " --------------------"); + if (emrtd_ef_sod_extract_signatures(data, datalen, emrtdsig, &emrtdsiglen) != PM3_SUCCESS) { + return false; + } -// if (emrtd_ef_sod_extract_signatures(data, datalen, emrtdsig, &emrtdsiglen) != PM3_SUCCESS) { -// return false; -// } + PrintAndLogEx(DEBUG, "hash data: %s", sprint_hex_inrow(emrtdsig, emrtdsiglen)); -// PrintAndLogEx(DEBUG, "hash data: %s", sprint_hex_inrow(emrtdsig, emrtdsiglen)); + if (!emrtd_lds_get_data_by_tag(emrtdsig, emrtdsiglen, hashlist, &hashlistlen, 0x30, 0x00, false, true, 1)) { + PrintAndLogEx(ERR, "Failed to read hash list from EF_SOD."); + return false; + } -// if (!emrtd_lds_get_data_by_tag(emrtdsig, emrtdsiglen, hashlist, &hashlistlen, 0x30, 0x00, false, true, 1)) { -// PrintAndLogEx(ERR, "Failed to read hash list from EF_SOD."); -// return false; -// } + PrintAndLogEx(DEBUG, "hash list: %s", sprint_hex_inrow(hashlist, hashlistlen)); -// PrintAndLogEx(DEBUG, "hash list: %s", sprint_hex_inrow(hashlist, hashlistlen)); + while (offset < hashlistlen) { + // Get the length of the element + e_datalen = emrtd_get_asn1_data_length(hashlist + offset, hashlistlen - offset, 1); -// while (offset < hashlistlen) { -// // Get the length of the element -// e_datalen = emrtd_get_asn1_data_length(hashlist + offset, hashlistlen - offset, 1); + // Get the length of the element's length + e_fieldlen = emrtd_get_asn1_field_length(hashlist + offset, hashlistlen - offset, 1); -// // Get the length of the element's length -// e_fieldlen = emrtd_get_asn1_field_length(hashlist + offset, hashlistlen - offset, 1); + switch (hashlist[offset]) { + case 0x30: + emrtd_lds_get_data_by_tag(hashlist + offset + e_fieldlen + 1, e_datalen, hashidstr, &hashidstrlen, 0x02, 0x00, false, false, 0); + emrtd_lds_get_data_by_tag(hashlist + offset + e_fieldlen + 1, e_datalen, hash, &hashlen, 0x04, 0x00, false, false, 0); + if (hashlen <= 64) { // TODO: This is for coverity, account for it. + memcpy(hashes + (hashidstr[0] * 64), hash, hashlen); + } + break; + } + // + 1 for length of ID + offset += 1 + e_datalen + e_fieldlen; + } -// switch (hashlist[offset]) { -// case 0x30: -// emrtd_lds_get_data_by_tag(hashlist + offset + e_fieldlen + 1, e_datalen, hashidstr, &hashidstrlen, 0x02, 0x00, false, false, 0); -// emrtd_lds_get_data_by_tag(hashlist + offset + e_fieldlen + 1, e_datalen, hash, &hashlen, 0x04, 0x00, false, false, 0); -// PrintAndLogEx(SUCCESS, "Hash for EF_DG%i: %s", hashidstr[0], sprint_hex_inrow(hash, hashlen)); -// break; -// } -// // + 1 for length of ID -// offset += 1 + e_datalen + e_fieldlen; -// } - -// return PM3_SUCCESS; -// } + return PM3_SUCCESS; +} int infoHF_EMRTD(char *documentnumber, char *dob, char *expiry, bool BAC_available) { uint8_t response[EMRTD_MAX_FILE_SIZE] = { 0x00 }; @@ -1633,8 +1633,9 @@ int infoHF_EMRTD(char *documentnumber, char *dob, char *expiry, bool BAC_availab DropField(); return PM3_ESOFT; } + // TODO: DROP THIS TOO A LA OFFLINE // Add EF_SOD to the list - filelist[filelistlen++] = 0x77; + // filelist[filelistlen++] = 0x77; // Dump all files in the file list for (int i = 0; i < filelistlen; i++) { emrtd_dg_t *dg = emrtd_tag_to_dg(filelist[i]); @@ -1686,8 +1687,26 @@ int infoHF_EMRTD_offline(const char *path) { return PM3_ESOFT; } free(data); - // Add EF_SOD to the list - filelist[filelistlen++] = 0x77; + + uint8_t dg_hashes[20][64]; + uint8_t hash_out[64]; + + strcpy(filepath, path); + strncat(filepath, PATHSEP, 2); + strcat(filepath, dg_table[EF_SOD].filename); + + if (loadFile_safeEx(filepath, ".BIN", (void **)&data, (size_t *)&datalen, false) != PM3_SUCCESS) { + PrintAndLogEx(ERR, "Failed to read EF_SOD."); + free(filepath); + return PM3_ESOFT; + } + + res = emrtd_parse_ef_sod_hashes(data, datalen, *dg_hashes); + if (res != PM3_SUCCESS) { + PrintAndLogEx(ERR, "Failed to read hash list from EF_SOD. Hash checks will fail."); + } + free(data); + // Read files in the file list for (int i = 0; i < filelistlen; i++) { emrtd_dg_t *dg = emrtd_tag_to_dg(filelist[i]); @@ -1703,6 +1722,12 @@ int infoHF_EMRTD_offline(const char *path) { // we won't halt on parsing errors if (dg->parser != NULL) dg->parser(data, datalen); + sha512hash(data, datalen, hash_out); + if (memcmp(dg_hashes[dg->dgnum], hash_out, 64) == 0) { + PrintAndLogEx(SUCCESS, _GREEN_("Hash verification passed for EF_DG%i."), dg->dgnum); + } else { + PrintAndLogEx(ERR, _RED_("Hash verification failed for EF_DG%i."), dg->dgnum); + } free(data); } } diff --git a/client/src/cmdhfemrtd.h b/client/src/cmdhfemrtd.h index bcae56538..72f5f44b9 100644 --- a/client/src/cmdhfemrtd.h +++ b/client/src/cmdhfemrtd.h @@ -15,6 +15,7 @@ typedef struct emrtd_dg_s { uint8_t tag; + uint8_t dgnum; const char *fileid; const char *filename; const char *desc; From dbe5d9ac9a219265738645ec694ee93666441123 Mon Sep 17 00:00:00 2001 From: Ave Date: Tue, 29 Dec 2020 02:08:30 +0300 Subject: [PATCH 212/682] emrtd info (online): Add basic hash verification support --- client/src/cmdhfemrtd.c | 32 ++++++++++++++++++++++++++++---- 1 file changed, 28 insertions(+), 4 deletions(-) diff --git a/client/src/cmdhfemrtd.c b/client/src/cmdhfemrtd.c index a088bfc7f..2235dc60b 100644 --- a/client/src/cmdhfemrtd.c +++ b/client/src/cmdhfemrtd.c @@ -1633,9 +1633,22 @@ int infoHF_EMRTD(char *documentnumber, char *dob, char *expiry, bool BAC_availab DropField(); return PM3_ESOFT; } - // TODO: DROP THIS TOO A LA OFFLINE - // Add EF_SOD to the list - // filelist[filelistlen++] = 0x77; + + // Grab the hash list + uint8_t dg_hashes[16][64]; + uint8_t hash_out[64]; + + if (!emrtd_select_and_read(response, &resplen, dg_table[EF_SOD].fileid, ks_enc, ks_mac, ssc, BAC, use_14b)) { + PrintAndLogEx(ERR, "Failed to read EF_SOD."); + DropField(); + return PM3_ESOFT; + } + + res = emrtd_parse_ef_sod_hashes(response, resplen, *dg_hashes); + if (res != PM3_SUCCESS) { + PrintAndLogEx(ERR, "Failed to read hash list from EF_SOD. Hash checks will fail."); + } + // Dump all files in the file list for (int i = 0; i < filelistlen; i++) { emrtd_dg_t *dg = emrtd_tag_to_dg(filelist[i]); @@ -1647,6 +1660,14 @@ int infoHF_EMRTD(char *documentnumber, char *dob, char *expiry, bool BAC_availab if (emrtd_select_and_read(response, &resplen, dg->fileid, ks_enc, ks_mac, ssc, BAC, use_14b)) { if (dg->parser != NULL) dg->parser(response, resplen); + + // Check file hash + sha512hash(response, resplen, hash_out); + if (memcmp(dg_hashes[dg->dgnum], hash_out, 64) == 0) { + PrintAndLogEx(SUCCESS, _GREEN_("Hash verification passed for EF_DG%i."), dg->dgnum); + } else { + PrintAndLogEx(ERR, _RED_("Hash verification failed for EF_DG%i."), dg->dgnum); + } } } } @@ -1688,7 +1709,8 @@ int infoHF_EMRTD_offline(const char *path) { } free(data); - uint8_t dg_hashes[20][64]; + // Grab the hash list + uint8_t dg_hashes[16][64]; uint8_t hash_out[64]; strcpy(filepath, path); @@ -1722,6 +1744,8 @@ int infoHF_EMRTD_offline(const char *path) { // we won't halt on parsing errors if (dg->parser != NULL) dg->parser(data, datalen); + + // Check file hash sha512hash(data, datalen, hash_out); if (memcmp(dg_hashes[dg->dgnum], hash_out, 64) == 0) { PrintAndLogEx(SUCCESS, _GREEN_("Hash verification passed for EF_DG%i."), dg->dgnum); From 5a9d47476591458e69f9dcfb9c2f6a6c8a0db76d Mon Sep 17 00:00:00 2001 From: Ave Date: Tue, 29 Dec 2020 02:15:15 +0300 Subject: [PATCH 213/682] emrtd: Better coverity bits for hash verif --- client/src/cmdhfemrtd.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/client/src/cmdhfemrtd.c b/client/src/cmdhfemrtd.c index 2235dc60b..770fde28f 100644 --- a/client/src/cmdhfemrtd.c +++ b/client/src/cmdhfemrtd.c @@ -1532,16 +1532,15 @@ static int emrtd_ef_sod_extract_signatures(uint8_t *data, size_t datalen, uint8_ return PM3_SUCCESS; } -static int emrtd_parse_ef_sod_hashes(uint8_t *data, size_t datalen, uint8_t *hashes) { +static int emrtd_parse_ef_sod_hashes(uint8_t *data, size_t datalen, uint8_t *hashes, int *hashalgo) { uint8_t emrtdsig[EMRTD_MAX_FILE_SIZE] = { 0x00 }; uint8_t hashlist[EMRTD_MAX_FILE_SIZE] = { 0x00 }; - uint8_t hash[65] = { 0x00 }; + uint8_t hash[64] = { 0x00 }; size_t hashlen = 0; uint8_t hashidstr[4] = { 0x00 }; size_t hashidstrlen = 0; - // size_t emrtdsiglen, e_datalen, e_fieldlen = 0; size_t emrtdsiglen = 0; size_t hashlistlen = 0; size_t e_datalen = 0; @@ -1572,8 +1571,10 @@ static int emrtd_parse_ef_sod_hashes(uint8_t *data, size_t datalen, uint8_t *has case 0x30: emrtd_lds_get_data_by_tag(hashlist + offset + e_fieldlen + 1, e_datalen, hashidstr, &hashidstrlen, 0x02, 0x00, false, false, 0); emrtd_lds_get_data_by_tag(hashlist + offset + e_fieldlen + 1, e_datalen, hash, &hashlen, 0x04, 0x00, false, false, 0); - if (hashlen <= 64) { // TODO: This is for coverity, account for it. + if (hashlen <= 64) { memcpy(hashes + (hashidstr[0] * 64), hash, hashlen); + } else { + PrintAndLogEx(ERR, "error (emrtd_parse_ef_sod_hashes) hashlen out-of-bounds"); } break; } From 8b9c6a15f174651e407a77ff843daa19bb68ee87 Mon Sep 17 00:00:00 2001 From: gator96100 Date: Tue, 29 Dec 2020 00:44:06 +0100 Subject: [PATCH 214/682] VSCode debugging test --- .vscode/launch.json | 16 +++++++++++++++- .vscode/tasks.json | 8 ++++++++ 2 files changed, 23 insertions(+), 1 deletion(-) diff --git a/.vscode/launch.json b/.vscode/launch.json index f6a030c7c..65619a2a3 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -55,7 +55,21 @@ "name": "PATH","value": "${workspaceFolder}/../../msys2/mingw64/bin;${workspaceFolder}/../../msys2/usr/local/bin;${workspaceFolder}/../../msys2/usr/bin;${workspaceFolder}/../../msys2/bin" }] } - } + },{ + "type": "cortex-debug", + "request": "launch", + "name": "Debug J-Link", + "cwd": "${workspaceRoot}", + "preLaunchTask": "fullimage: clean & make", + "executable": "${workspaceRoot}/armsrc/obj/fullimage.stage1.elf", + "serverpath": "/opt/SEGGER/JLink/JLinkGDBServerCLExe", + "servertype": "jlink", + "device": "AT91SAM7S512", + "interface": "jtag", + "serialNumber": "", //If you have more than one J-Link probe, add the serial number here. + "runToMain": true, + "armToolchainPath": "/usr/bin/" + } ], "inputs": [ { diff --git a/.vscode/tasks.json b/.vscode/tasks.json index 7354a8a2d..4cc21841d 100644 --- a/.vscode/tasks.json +++ b/.vscode/tasks.json @@ -143,6 +143,14 @@ } }, "problemMatcher": [] + },{ + "label": "fullimage: clean & make", + "type": "shell", + "command": "make armsrc/clean && make armsrc/all SKIP_COMPRESSION=1 DEBUG=1", + "problemMatcher": [ + "$gcc" + ], + "group": "build", } ], "inputs": [ From 637e0179756243477a143c7767ddd175af3bcf77 Mon Sep 17 00:00:00 2001 From: Ave Date: Tue, 29 Dec 2020 03:39:01 +0300 Subject: [PATCH 215/682] emrtd: Support SHA256 --- client/src/cmdhfemrtd.c | 47 +++++++++++++++++++++++++++++++++++++---- 1 file changed, 43 insertions(+), 4 deletions(-) diff --git a/client/src/cmdhfemrtd.c b/client/src/cmdhfemrtd.c index 770fde28f..e782e43ab 100644 --- a/client/src/cmdhfemrtd.c +++ b/client/src/cmdhfemrtd.c @@ -1532,6 +1532,29 @@ static int emrtd_ef_sod_extract_signatures(uint8_t *data, size_t datalen, uint8_ return PM3_SUCCESS; } +static const uint8_t emrtd_hashalgo_sha256[] = {0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01}; +static const uint8_t emrtd_hashalgo_sha512[] = {0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03}; + +static int emrtd_parse_ef_sod_hash_algo(uint8_t *data, size_t datalen, int *hashalgo) { + uint8_t hashalgoset[64] = { 0x00 }; + size_t hashalgosetlen = 0; + + if (!emrtd_lds_get_data_by_tag(data, datalen, hashalgoset, &hashalgosetlen, 0x30, 0x00, false, true, 0)) { + PrintAndLogEx(ERR, "Failed to read hash algo set from EF_SOD."); + return false; + } + + PrintAndLogEx(DEBUG, "hash algo set: %s", sprint_hex_inrow(hashalgoset, hashalgosetlen)); + + if (memcmp(emrtd_hashalgo_sha256, hashalgoset, 11) == 0) { + *hashalgo = 1; + } else if (memcmp(emrtd_hashalgo_sha512, hashalgoset, 11) == 0) { + *hashalgo = 3; + } + + return PM3_SUCCESS; +} + static int emrtd_parse_ef_sod_hashes(uint8_t *data, size_t datalen, uint8_t *hashes, int *hashalgo) { uint8_t emrtdsig[EMRTD_MAX_FILE_SIZE] = { 0x00 }; uint8_t hashlist[EMRTD_MAX_FILE_SIZE] = { 0x00 }; @@ -1553,6 +1576,8 @@ static int emrtd_parse_ef_sod_hashes(uint8_t *data, size_t datalen, uint8_t *has PrintAndLogEx(DEBUG, "hash data: %s", sprint_hex_inrow(emrtdsig, emrtdsiglen)); + emrtd_parse_ef_sod_hash_algo(emrtdsig, emrtdsiglen, hashalgo); + if (!emrtd_lds_get_data_by_tag(emrtdsig, emrtdsiglen, hashlist, &hashlistlen, 0x30, 0x00, false, true, 1)) { PrintAndLogEx(ERR, "Failed to read hash list from EF_SOD."); return false; @@ -1638,6 +1663,7 @@ int infoHF_EMRTD(char *documentnumber, char *dob, char *expiry, bool BAC_availab // Grab the hash list uint8_t dg_hashes[16][64]; uint8_t hash_out[64]; + int hash_algo = 0; if (!emrtd_select_and_read(response, &resplen, dg_table[EF_SOD].fileid, ks_enc, ks_mac, ssc, BAC, use_14b)) { PrintAndLogEx(ERR, "Failed to read EF_SOD."); @@ -1645,7 +1671,7 @@ int infoHF_EMRTD(char *documentnumber, char *dob, char *expiry, bool BAC_availab return PM3_ESOFT; } - res = emrtd_parse_ef_sod_hashes(response, resplen, *dg_hashes); + res = emrtd_parse_ef_sod_hashes(response, resplen, *dg_hashes, &hash_algo); if (res != PM3_SUCCESS) { PrintAndLogEx(ERR, "Failed to read hash list from EF_SOD. Hash checks will fail."); } @@ -1663,7 +1689,13 @@ int infoHF_EMRTD(char *documentnumber, char *dob, char *expiry, bool BAC_availab dg->parser(response, resplen); // Check file hash - sha512hash(response, resplen, hash_out); + memset(hash_out, 0, 64); + if (hash_algo == 1) { + sha256hash(response, resplen, hash_out); + } else if (hash_algo == 3) { + sha512hash(response, resplen, hash_out); + } + if (memcmp(dg_hashes[dg->dgnum], hash_out, 64) == 0) { PrintAndLogEx(SUCCESS, _GREEN_("Hash verification passed for EF_DG%i."), dg->dgnum); } else { @@ -1713,6 +1745,7 @@ int infoHF_EMRTD_offline(const char *path) { // Grab the hash list uint8_t dg_hashes[16][64]; uint8_t hash_out[64]; + int hash_algo = 0; strcpy(filepath, path); strncat(filepath, PATHSEP, 2); @@ -1724,7 +1757,7 @@ int infoHF_EMRTD_offline(const char *path) { return PM3_ESOFT; } - res = emrtd_parse_ef_sod_hashes(data, datalen, *dg_hashes); + res = emrtd_parse_ef_sod_hashes(data, datalen, *dg_hashes, &hash_algo); if (res != PM3_SUCCESS) { PrintAndLogEx(ERR, "Failed to read hash list from EF_SOD. Hash checks will fail."); } @@ -1747,7 +1780,13 @@ int infoHF_EMRTD_offline(const char *path) { dg->parser(data, datalen); // Check file hash - sha512hash(data, datalen, hash_out); + memset(hash_out, 0, 64); + if (hash_algo == 1) { + sha256hash(data, datalen, hash_out); + } else if (hash_algo == 3) { + sha512hash(data, datalen, hash_out); + } + if (memcmp(dg_hashes[dg->dgnum], hash_out, 64) == 0) { PrintAndLogEx(SUCCESS, _GREEN_("Hash verification passed for EF_DG%i."), dg->dgnum); } else { From f47b617a58c6851da9a456c56adb8f5170bae6e6 Mon Sep 17 00:00:00 2001 From: Ave Date: Tue, 29 Dec 2020 03:51:30 +0300 Subject: [PATCH 216/682] emrtd: Check emrtd_parse_ef_sod_hash_algo output --- client/src/cmdhfemrtd.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/client/src/cmdhfemrtd.c b/client/src/cmdhfemrtd.c index e782e43ab..089bb6633 100644 --- a/client/src/cmdhfemrtd.c +++ b/client/src/cmdhfemrtd.c @@ -1550,6 +1550,9 @@ static int emrtd_parse_ef_sod_hash_algo(uint8_t *data, size_t datalen, int *hash *hashalgo = 1; } else if (memcmp(emrtd_hashalgo_sha512, hashalgoset, 11) == 0) { *hashalgo = 3; + } else { + *hashalgo = 0; + return PM3_ESOFT; } return PM3_SUCCESS; @@ -1576,7 +1579,9 @@ static int emrtd_parse_ef_sod_hashes(uint8_t *data, size_t datalen, uint8_t *has PrintAndLogEx(DEBUG, "hash data: %s", sprint_hex_inrow(emrtdsig, emrtdsiglen)); - emrtd_parse_ef_sod_hash_algo(emrtdsig, emrtdsiglen, hashalgo); + if (emrtd_parse_ef_sod_hash_algo(emrtdsig, emrtdsiglen, hashalgo) != PM3_SUCCESS) { + PrintAndLogEx(ERR, "Failed to parse hash list. Unknown algo?"); + } if (!emrtd_lds_get_data_by_tag(emrtdsig, emrtdsiglen, hashlist, &hashlistlen, 0x30, 0x00, false, true, 1)) { PrintAndLogEx(ERR, "Failed to read hash list from EF_SOD."); From bc8c52931bd65816e30109b283f0c70700881777 Mon Sep 17 00:00:00 2001 From: Ave Date: Tue, 29 Dec 2020 04:01:15 +0300 Subject: [PATCH 217/682] emrtd: Split DG hash calc into emrtd_calc_dg_hash --- client/src/cmdhfemrtd.c | 25 +++++++++++++------------ 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/client/src/cmdhfemrtd.c b/client/src/cmdhfemrtd.c index 089bb6633..43a2adeb8 100644 --- a/client/src/cmdhfemrtd.c +++ b/client/src/cmdhfemrtd.c @@ -1532,6 +1532,7 @@ static int emrtd_ef_sod_extract_signatures(uint8_t *data, size_t datalen, uint8_ return PM3_SUCCESS; } +// https://security.stackexchange.com/questions/131241/where-do-magic-constants-for-signature-algorithms-come-from static const uint8_t emrtd_hashalgo_sha256[] = {0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01}; static const uint8_t emrtd_hashalgo_sha512[] = {0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03}; @@ -1615,6 +1616,16 @@ static int emrtd_parse_ef_sod_hashes(uint8_t *data, size_t datalen, uint8_t *has return PM3_SUCCESS; } +static void emrtd_calc_dg_hash(uint8_t *data, size_t datalen, uint8_t *hash_out, int hash_algo) { + memset(hash_out, 0, 64); + + if (hash_algo == 1) { + sha256hash(data, datalen, hash_out); + } else if (hash_algo == 3) { + sha512hash(data, datalen, hash_out); + } +} + int infoHF_EMRTD(char *documentnumber, char *dob, char *expiry, bool BAC_available) { uint8_t response[EMRTD_MAX_FILE_SIZE] = { 0x00 }; int resplen = 0; @@ -1694,12 +1705,7 @@ int infoHF_EMRTD(char *documentnumber, char *dob, char *expiry, bool BAC_availab dg->parser(response, resplen); // Check file hash - memset(hash_out, 0, 64); - if (hash_algo == 1) { - sha256hash(response, resplen, hash_out); - } else if (hash_algo == 3) { - sha512hash(response, resplen, hash_out); - } + emrtd_calc_dg_hash(response, resplen, hash_out, hash_algo); if (memcmp(dg_hashes[dg->dgnum], hash_out, 64) == 0) { PrintAndLogEx(SUCCESS, _GREEN_("Hash verification passed for EF_DG%i."), dg->dgnum); @@ -1785,12 +1791,7 @@ int infoHF_EMRTD_offline(const char *path) { dg->parser(data, datalen); // Check file hash - memset(hash_out, 0, 64); - if (hash_algo == 1) { - sha256hash(data, datalen, hash_out); - } else if (hash_algo == 3) { - sha512hash(data, datalen, hash_out); - } + emrtd_calc_dg_hash(data, datalen, hash_out, hash_algo); if (memcmp(dg_hashes[dg->dgnum], hash_out, 64) == 0) { PrintAndLogEx(SUCCESS, _GREEN_("Hash verification passed for EF_DG%i."), dg->dgnum); From aae3426f8e6f08079ae5648c336c1d5d33c47318 Mon Sep 17 00:00:00 2001 From: Ave Date: Tue, 29 Dec 2020 04:09:53 +0300 Subject: [PATCH 218/682] emrtd: Adjust an include comment --- client/src/cmdhfemrtd.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/src/cmdhfemrtd.c b/client/src/cmdhfemrtd.c index 43a2adeb8..32c2c9e23 100644 --- a/client/src/cmdhfemrtd.c +++ b/client/src/cmdhfemrtd.c @@ -20,7 +20,7 @@ #include "protocols.h" // definitions of ISO14A/7816 protocol #include "emv/apduinfo.h" // GetAPDUCodeDescription #include "sha1.h" // KSeed calculation etc -#include "crypto/libpcrypto.h" // Hash calculation (sha256), TODO: AES too +#include "crypto/libpcrypto.h" // Hash calculation (sha256, sha512) #include "mifare/desfire_crypto.h" // des_encrypt/des_decrypt #include "des.h" // mbedtls_des_key_set_parity #include "cmdhf14b.h" // exchange_14b_apdu From 2c5c58d128e9d7ddc2cdb2a4f7c1a76ffefa807a Mon Sep 17 00:00:00 2001 From: Ave Date: Tue, 29 Dec 2020 04:20:48 +0300 Subject: [PATCH 219/682] emrtd: Remove 'very very very very cursed' comment --- client/src/cmdhfemrtd.c | 1 - 1 file changed, 1 deletion(-) diff --git a/client/src/cmdhfemrtd.c b/client/src/cmdhfemrtd.c index 32c2c9e23..08c53467b 100644 --- a/client/src/cmdhfemrtd.c +++ b/client/src/cmdhfemrtd.c @@ -1485,7 +1485,6 @@ static int emrtd_print_ef_dg12_info(uint8_t *data, size_t datalen) { } static int emrtd_ef_sod_extract_signatures(uint8_t *data, size_t datalen, uint8_t *dataout, size_t *dataoutlen) { - // very very very very cursed code. uint8_t top[EMRTD_MAX_FILE_SIZE] = { 0x00 }; uint8_t signeddata[EMRTD_MAX_FILE_SIZE] = { 0x00 }; uint8_t emrtdsigcontainer[EMRTD_MAX_FILE_SIZE] = { 0x00 }; From 8c29c4231be80b41bc4ee2a31921f4d0c847d9e4 Mon Sep 17 00:00:00 2001 From: gator96100 Date: Tue, 29 Dec 2020 03:30:57 +0100 Subject: [PATCH 220/682] Allow generation of debug information when using no compression --- common_arm/Makefile.hal | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/common_arm/Makefile.hal b/common_arm/Makefile.hal index bfbe56d34..b6519e4ab 100644 --- a/common_arm/Makefile.hal +++ b/common_arm/Makefile.hal @@ -138,7 +138,7 @@ ifneq ($(SKIP_HFPLOT),1) PLATFORM_DEFS += -DWITH_HFPLOT endif ifeq ($(SKIP_COMPRESSION),1) - PLATFORM_DEFS += -DWITH_NO_COMPRESSION + PLATFORM_DEFS += -DWITH_NO_COMPRESSION -g endif # Standalone mode From 654996eeee4f3cd8f1895aa90c57ffc48b04ae63 Mon Sep 17 00:00:00 2001 From: gator96100 Date: Tue, 29 Dec 2020 03:39:59 +0100 Subject: [PATCH 221/682] Fixed debugger waiting for main --- .vscode/launch.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.vscode/launch.json b/.vscode/launch.json index 65619a2a3..d1c5d6ff8 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -58,7 +58,7 @@ },{ "type": "cortex-debug", "request": "launch", - "name": "Debug J-Link", + "name": "Firmware debug", "cwd": "${workspaceRoot}", "preLaunchTask": "fullimage: clean & make", "executable": "${workspaceRoot}/armsrc/obj/fullimage.stage1.elf", @@ -67,7 +67,7 @@ "device": "AT91SAM7S512", "interface": "jtag", "serialNumber": "", //If you have more than one J-Link probe, add the serial number here. - "runToMain": true, + "runToMain": false, "armToolchainPath": "/usr/bin/" } ], From 6d6f3d9f1a1bf7296dad3e654407b832464285cf Mon Sep 17 00:00:00 2001 From: tcprst Date: Mon, 28 Dec 2020 23:00:10 -0500 Subject: [PATCH 222/682] hf 14a sniff, reader - now use cliparser --- client/src/cmdhf14a.c | 110 ++++++++++++++++++++++------------------- doc/cliparser_todo.txt | 2 - 2 files changed, 58 insertions(+), 54 deletions(-) diff --git a/client/src/cmdhf14a.c b/client/src/cmdhf14a.c index 150b49fee..5419239b1 100644 --- a/client/src/cmdhf14a.c +++ b/client/src/cmdhf14a.c @@ -236,26 +236,6 @@ static int usage_hf_14a_sim(void) { PrintAndLogEx(NORMAL, _YELLOW_(" hf 14a sim t 1 u 112233445566778899AA")); return PM3_SUCCESS; } -static int usage_hf_14a_sniff(void) { - PrintAndLogEx(NORMAL, "Collect data from the field and save into command buffer."); - PrintAndLogEx(NORMAL, "Buffer accessible from command 'hf 14a list'"); - PrintAndLogEx(NORMAL, "Usage: hf 14a sniff [c][r]"); - PrintAndLogEx(NORMAL, "c - triggered by first data from card"); - PrintAndLogEx(NORMAL, "r - triggered by first 7-bit request from reader (REQ,WUP,...)"); - PrintAndLogEx(NORMAL, "Examples:"); - PrintAndLogEx(NORMAL, _YELLOW_(" hf 14a sniff c r")); - return PM3_SUCCESS; -} - -static int usage_hf_14a_reader(void) { - PrintAndLogEx(NORMAL, "Usage: hf 14a reader [k|s|x] [3]"); - PrintAndLogEx(NORMAL, " k keep the field active after command executed"); - PrintAndLogEx(NORMAL, " s silent (no messages)"); - PrintAndLogEx(NORMAL, " x just drop the signal field"); - PrintAndLogEx(NORMAL, " 3 ISO14443-3 select only (skip RATS)"); - PrintAndLogEx(NORMAL, " @ continuous mode. Updates hf plot as well"); - return PM3_SUCCESS; -} static int CmdHF14AList(const char *Cmd) { char args[128] = {0}; @@ -462,37 +442,44 @@ int Hf14443_4aGetCardData(iso14a_card_select_t *card) { } static int CmdHF14AReader(const char *Cmd) { + CLIParserContext *ctx; + CLIParserInit(&ctx, "hf 14a reader", + "Reader for ISO 14443A based tags", + "hf 14a reader -@ <- Continuous mode"); + + void *argtable[] = { + arg_param_begin, + arg_lit0("k", "keep", "keep the field active after command executed"), + arg_lit0("s", "silent", "silent (no messages)"), + arg_lit0(NULL, "drop", "just drop the signal field"), + arg_lit0(NULL, "skip", "ISO14443-3 select only (skip RATS)"), + arg_lit0("@", NULL, "optional - continuous reader mode"), + arg_param_end + }; + CLIExecWithReturn(ctx, Cmd, argtable, true); + + bool disconnectAfter = true; + if (arg_get_lit(ctx, 1)) { + disconnectAfter = false; + } + + bool silent = arg_get_lit(ctx, 2); uint32_t cm = ISO14A_CONNECT; - bool disconnectAfter = true, silent = false, continuous = false; - int cmdp = 0; - int res = PM3_SUCCESS; - while (param_getchar(Cmd, cmdp) != 0x00) { - switch (tolower(param_getchar(Cmd, cmdp))) { - case 'h': - return usage_hf_14a_reader(); - case '3': - cm |= ISO14A_NO_RATS; - break; - case 'k': - disconnectAfter = false; - break; - case 's': - silent = true; - break; - case 'x': - cm &= ~ISO14A_CONNECT; - break; - case '@': - continuous = true; - break; - default: - PrintAndLogEx(WARNING, "Unknown command."); - return PM3_EINVARG; - } - cmdp++; + if (arg_get_lit(ctx, 3)) { + cm &= ~ISO14A_CONNECT; } + if (arg_get_lit(ctx, 4)) { + cm |= ISO14A_NO_RATS; + } + + bool continuous = arg_get_lit(ctx, 5); + + CLIParserFree(ctx); + + int res = PM3_SUCCESS; + if (!disconnectAfter) cm |= ISO14A_NO_DISCONNECT; if (continuous) { @@ -768,13 +755,32 @@ int CmdHF14ASim(const char *Cmd) { } int CmdHF14ASniff(const char *Cmd) { + CLIParserContext *ctx; + CLIParserInit(&ctx, "hf 14a sniff", + "Collect data from the field and save into command buffer.\n" + "Buffer accessible from command 'hf 14a list'", + " hf 14a sniff -c -r"); + + void *argtable[] = { + arg_param_begin, + arg_lit0("c", "card", "triggered by first data from card"), + arg_lit0("r", "reader", "triggered by first 7-bit request from reader (REQ,WUP,...)"), + arg_param_end + }; + CLIExecWithReturn(ctx, Cmd, argtable, true); + uint8_t param = 0; - for (uint8_t i = 0; i < 2; i++) { - uint8_t ctmp = tolower(param_getchar(Cmd, i)); - if (ctmp == 'h') return usage_hf_14a_sniff(); - if (ctmp == 'c') param |= 0x01; - if (ctmp == 'r') param |= 0x02; + + if (arg_get_lit(ctx, 1)) { + param |= 0x01; } + + if (arg_get_lit(ctx, 2)) { + param |= 0x02; + } + + CLIParserFree(ctx); + clearCommandBuffer(); SendCommandNG(CMD_HF_ISO14443A_SNIFF, (uint8_t *)¶m, sizeof(uint8_t)); return PM3_SUCCESS; diff --git a/doc/cliparser_todo.txt b/doc/cliparser_todo.txt index 7e333911b..c9dcf077c 100644 --- a/doc/cliparser_todo.txt +++ b/doc/cliparser_todo.txt @@ -41,10 +41,8 @@ data print data samples data setdebugmode data tune -hf 14a reader hf 14a cuids hf 14a sim -hf 14a sniff hf 14a config hf 14b sriwrite hf 15 dump From 2124ef52893d95a251337f385af3ca1d4542e566 Mon Sep 17 00:00:00 2001 From: gator96100 Date: Tue, 29 Dec 2020 05:01:29 +0100 Subject: [PATCH 223/682] Added firmware configuration for wsl --- .vscode/launch.json | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/.vscode/launch.json b/.vscode/launch.json index d1c5d6ff8..abd2cd775 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -58,10 +58,10 @@ },{ "type": "cortex-debug", "request": "launch", - "name": "Firmware debug", + "name": "(Linux) Firmware debug", "cwd": "${workspaceRoot}", "preLaunchTask": "fullimage: clean & make", - "executable": "${workspaceRoot}/armsrc/obj/fullimage.stage1.elf", + "executable": "${workspaceRoot}/armsrc/obj/fullimage.elf", "serverpath": "/opt/SEGGER/JLink/JLinkGDBServerCLExe", "servertype": "jlink", "device": "AT91SAM7S512", @@ -69,7 +69,21 @@ "serialNumber": "", //If you have more than one J-Link probe, add the serial number here. "runToMain": false, "armToolchainPath": "/usr/bin/" - } + },{ + "type": "cortex-debug", + "request": "launch", + "name": "(WSL) Firmware debug", + "cwd": "${workspaceRoot}", + "preLaunchTask": "fullimage: clean & make", + "executable": "${workspaceRoot}/armsrc/obj/fullimage.elf", + "serverpath": "/mnt/c/Program Files (x86)/SEGGER/JLink/JLinkGDBServerCL.exe", + "servertype": "jlink", + "device": "AT91SAM7S512", + "interface": "jtag", + "serialNumber": "", //If you have more than one J-Link probe, add the serial number here. + "runToMain": false, + "armToolchainPath": "/usr/bin/" + } ], "inputs": [ { From 9e224b011b6655e5de59c102731461ffa9adb152 Mon Sep 17 00:00:00 2001 From: gator96100 Date: Tue, 29 Dec 2020 14:55:31 +0100 Subject: [PATCH 224/682] Template files for vscode --- .gitignore | 5 + .vscode/extensions.json | 10 ++ .vscode/launch.json | 108 -------------- .vscode/launch_linux.json | 70 +++++++++ .vscode/launch_ps.json | 45 ++++++ .vscode/launch_wsl.json | 70 +++++++++ .vscode/setup.sh | 4 + .vscode/{tasks.json => tasks_linux.json} | 0 .vscode/tasks_ps.json | 177 +++++++++++++++++++++++ .vscode/tasks_wsl.json | 177 +++++++++++++++++++++++ 10 files changed, 558 insertions(+), 108 deletions(-) create mode 100644 .vscode/extensions.json delete mode 100644 .vscode/launch.json create mode 100644 .vscode/launch_linux.json create mode 100644 .vscode/launch_ps.json create mode 100644 .vscode/launch_wsl.json create mode 100644 .vscode/setup.sh rename .vscode/{tasks.json => tasks_linux.json} (100%) create mode 100644 .vscode/tasks_ps.json create mode 100644 .vscode/tasks_wsl.json diff --git a/.gitignore b/.gitignore index 081c0f8e8..1b27c52a3 100644 --- a/.gitignore +++ b/.gitignore @@ -108,3 +108,8 @@ fpga_version_info.c # .tmp files are created during compilation *.tmp + +#VSCode files +!.vscode/*.json +.vscode/launch.json +.vscode/tasks.json \ No newline at end of file diff --git a/.vscode/extensions.json b/.vscode/extensions.json new file mode 100644 index 000000000..85b3997e2 --- /dev/null +++ b/.vscode/extensions.json @@ -0,0 +1,10 @@ +{ + // See https://go.microsoft.com/fwlink/?LinkId=827846 + // for the documentation about the extensions.json format + "recommendations": [ + "ms-vscode.cpptools", + "austin.code-gnu-global", + "marus25.cortex-debug", + "augustocdias.tasks-shell-input" + ] +} diff --git a/.vscode/launch.json b/.vscode/launch.json deleted file mode 100644 index abd2cd775..000000000 --- a/.vscode/launch.json +++ /dev/null @@ -1,108 +0,0 @@ -{ - // Use IntelliSense to learn about possible attributes. - // Hover to view descriptions of existing attributes. - // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 - "version": "0.2.0", - "configurations": [ - { - "name": "(gdb) Attach", - "type": "cppdbg", - "request": "attach", - "program": "${cwd}/client/proxmark3", - //"processId": "${command:pickProcess}", - "processId": "${input:ProcessID}", - "MIMode": "gdb", - "setupCommands": [ - { - "description": "Enable pretty-printing for gdb", - "text": "-enable-pretty-printing", - "ignoreFailures": true - } - ], - "windows": { - "processId": "${input:ProcessIDWindows}", - "miDebuggerPath": "${workspaceFolder}/../../msys2/mingw64/bin/gdb.exe", - "externalConsole": true,//for ProxSpace externalConsole=true is required, because the internal cosole stops updating after a while - "environment": [{ - "name": "PATH","value": "${workspaceFolder}/../../msys2/mingw64/bin;${workspaceFolder}/../../msys2/usr/local/bin;${workspaceFolder}/../../msys2/usr/bin;${workspaceFolder}/../../msys2/bin" - }] - } - },{ - "name": "(gdb) Build & Launch", - "type": "cppdbg", - "request": "launch", - "program": "${cwd}/client/proxmark3", - "args": ["/dev/ttyACM0"], - "stopAtEntry": false, - "cwd": "${workspaceFolder}", - "environment": [], - "externalConsole": false, - "MIMode": "gdb", - "setupCommands": [ - { - "description": "Enable pretty-printing for gdb", - "text": "-enable-pretty-printing", - "ignoreFailures": true - } - ], - "preLaunchTask": "client: Debug: clean & make", - "miDebuggerPath": "/usr/bin/gdb", - "windows": { - "args": ["COM5"], - "miDebuggerPath": "${workspaceFolder}/../../msys2/mingw64/bin/gdb.exe", - "externalConsole": true,//for ProxSpace externalConsole=true is required, because the internal cosole stops updating after a while - "environment": [{ - "name": "PATH","value": "${workspaceFolder}/../../msys2/mingw64/bin;${workspaceFolder}/../../msys2/usr/local/bin;${workspaceFolder}/../../msys2/usr/bin;${workspaceFolder}/../../msys2/bin" - }] - } - },{ - "type": "cortex-debug", - "request": "launch", - "name": "(Linux) Firmware debug", - "cwd": "${workspaceRoot}", - "preLaunchTask": "fullimage: clean & make", - "executable": "${workspaceRoot}/armsrc/obj/fullimage.elf", - "serverpath": "/opt/SEGGER/JLink/JLinkGDBServerCLExe", - "servertype": "jlink", - "device": "AT91SAM7S512", - "interface": "jtag", - "serialNumber": "", //If you have more than one J-Link probe, add the serial number here. - "runToMain": false, - "armToolchainPath": "/usr/bin/" - },{ - "type": "cortex-debug", - "request": "launch", - "name": "(WSL) Firmware debug", - "cwd": "${workspaceRoot}", - "preLaunchTask": "fullimage: clean & make", - "executable": "${workspaceRoot}/armsrc/obj/fullimage.elf", - "serverpath": "/mnt/c/Program Files (x86)/SEGGER/JLink/JLinkGDBServerCL.exe", - "servertype": "jlink", - "device": "AT91SAM7S512", - "interface": "jtag", - "serialNumber": "", //If you have more than one J-Link probe, add the serial number here. - "runToMain": false, - "armToolchainPath": "/usr/bin/" - } - ], - "inputs": [ - { - // Using Extension "Tasks Shell Input" https://marketplace.visualstudio.com/items?itemName=augustocdias.tasks-shell-input - "id": "ProcessID", - "type": "command", - "command": "shellCommand.execute", - "args": { - "command": "pgrep -n proxmark3", - } - - },{ - "id": "ProcessIDWindows", - "type": "command", - "command": "shellCommand.execute", - "args": { - "command": "${workspaceFolder}/../../runme64.bat -c \"cat /proc/$(pgrep -n proxmark3)/winpid\"", - } - - } - ] -} \ No newline at end of file diff --git a/.vscode/launch_linux.json b/.vscode/launch_linux.json new file mode 100644 index 000000000..0f60495a6 --- /dev/null +++ b/.vscode/launch_linux.json @@ -0,0 +1,70 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "name": "Client: (gdb) Build & Launch", + "type": "cppdbg", + "request": "launch", + "program": "${cwd}/client/proxmark3", + "args": ["${SerialPort}"], + "stopAtEntry": false, + "cwd": "${workspaceFolder}", + "environment": [], + "externalConsole": false, + "MIMode": "gdb", + "setupCommands": [ + { + "description": "Enable pretty-printing for gdb", + "text": "-enable-pretty-printing", + "ignoreFailures": true + } + ], + "preLaunchTask": "client: Debug: clean & make", + "miDebuggerPath": "${DebuggerPath}" + },{ + "name": "Client: (gdb) Attach", + "type": "cppdbg", + "request": "attach", + "program": "${cwd}/client/proxmark3", + //"processId": "${command:pickProcess}", + "processId": "${input:ProcessID}", + "MIMode": "gdb", + "setupCommands": [ + { + "description": "Enable pretty-printing for gdb", + "text": "-enable-pretty-printing", + "ignoreFailures": true + } + ] + },{ + "name": "Firmware: (J-Link) Build & Launch", + "type": "cortex-debug", + "request": "launch", + "cwd": "${workspaceRoot}", + "preLaunchTask": "fullimage: clean & make", + "executable": "${workspaceRoot}/armsrc/obj/fullimage.elf", + "serverpath": "${JLinkServerPath}", + "servertype": "jlink", + "device": "AT91SAM7S${DeviceMem}", + "interface": "jtag", + "serialNumber": "", //If you have more than one J-Link probe, add the serial number here. + "runToMain": false, + "armToolchainPath": "/usr/bin/" + } + ], + "inputs": [ + { + // Using Extension "Tasks Shell Input" https://marketplace.visualstudio.com/items?itemName=augustocdias.tasks-shell-input + "id": "ProcessID", + "type": "command", + "command": "shellCommand.execute", + "args": { + "command": "pgrep -n proxmark3", + } + + } + ] +} \ No newline at end of file diff --git a/.vscode/launch_ps.json b/.vscode/launch_ps.json new file mode 100644 index 000000000..8794ef76e --- /dev/null +++ b/.vscode/launch_ps.json @@ -0,0 +1,45 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "name": "Client: (gdb) Build & Launch", + "type": "cppdbg", + "request": "launch", + "program": "${cwd}/client/proxmark3", + "args": ["${SerialPort}"], + "stopAtEntry": false, + "cwd": "${workspaceFolder}", + "environment": [ + "name": "PATH","value": "${workspaceFolder}/../../msys2/mingw64/bin;${workspaceFolder}/../../msys2/usr/local/bin;${workspaceFolder}/../../msys2/usr/bin;${workspaceFolder}/../../msys2/bin" + ], + "externalConsole": true,//for ProxSpace externalConsole=true is required, because the internal cosole stops updating after a while + "MIMode": "gdb", + "setupCommands": [ + { + "description": "Enable pretty-printing for gdb", + "text": "-enable-pretty-printing", + "ignoreFailures": true + } + ], + "preLaunchTask": "client: Debug: clean & make", + "miDebuggerPath": "${DebuggerPath}" + },{ + "name": "Firmware: (J-Link) Build & Launch", + "type": "cortex-debug", + "request": "launch", + "cwd": "${workspaceRoot}", + "preLaunchTask": "fullimage: clean & make", + "executable": "${workspaceRoot}/armsrc/obj/fullimage.elf", + "serverpath": "${JLinkServerPath}", + "servertype": "jlink", + "device": "AT91SAM7S${DeviceMem}", + "interface": "jtag", + "serialNumber": "", //If you have more than one J-Link probe, add the serial number here. + "runToMain": false, + "armToolchainPath": "/usr/bin/" + } + ] +} \ No newline at end of file diff --git a/.vscode/launch_wsl.json b/.vscode/launch_wsl.json new file mode 100644 index 000000000..0f60495a6 --- /dev/null +++ b/.vscode/launch_wsl.json @@ -0,0 +1,70 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "name": "Client: (gdb) Build & Launch", + "type": "cppdbg", + "request": "launch", + "program": "${cwd}/client/proxmark3", + "args": ["${SerialPort}"], + "stopAtEntry": false, + "cwd": "${workspaceFolder}", + "environment": [], + "externalConsole": false, + "MIMode": "gdb", + "setupCommands": [ + { + "description": "Enable pretty-printing for gdb", + "text": "-enable-pretty-printing", + "ignoreFailures": true + } + ], + "preLaunchTask": "client: Debug: clean & make", + "miDebuggerPath": "${DebuggerPath}" + },{ + "name": "Client: (gdb) Attach", + "type": "cppdbg", + "request": "attach", + "program": "${cwd}/client/proxmark3", + //"processId": "${command:pickProcess}", + "processId": "${input:ProcessID}", + "MIMode": "gdb", + "setupCommands": [ + { + "description": "Enable pretty-printing for gdb", + "text": "-enable-pretty-printing", + "ignoreFailures": true + } + ] + },{ + "name": "Firmware: (J-Link) Build & Launch", + "type": "cortex-debug", + "request": "launch", + "cwd": "${workspaceRoot}", + "preLaunchTask": "fullimage: clean & make", + "executable": "${workspaceRoot}/armsrc/obj/fullimage.elf", + "serverpath": "${JLinkServerPath}", + "servertype": "jlink", + "device": "AT91SAM7S${DeviceMem}", + "interface": "jtag", + "serialNumber": "", //If you have more than one J-Link probe, add the serial number here. + "runToMain": false, + "armToolchainPath": "/usr/bin/" + } + ], + "inputs": [ + { + // Using Extension "Tasks Shell Input" https://marketplace.visualstudio.com/items?itemName=augustocdias.tasks-shell-input + "id": "ProcessID", + "type": "command", + "command": "shellCommand.execute", + "args": { + "command": "pgrep -n proxmark3", + } + + } + ] +} \ No newline at end of file diff --git a/.vscode/setup.sh b/.vscode/setup.sh new file mode 100644 index 000000000..b439f2cbd --- /dev/null +++ b/.vscode/setup.sh @@ -0,0 +1,4 @@ +export SerialPort="/dev/ttyACM0" +export DebuggerPath="/usr/bin/gdb" +export JLinkServerPath="/opt/SEGGER/JLink/JLinkGDBServerCLExe" +export DeviceMem="512" \ No newline at end of file diff --git a/.vscode/tasks.json b/.vscode/tasks_linux.json similarity index 100% rename from .vscode/tasks.json rename to .vscode/tasks_linux.json diff --git a/.vscode/tasks_ps.json b/.vscode/tasks_ps.json new file mode 100644 index 000000000..4cc21841d --- /dev/null +++ b/.vscode/tasks_ps.json @@ -0,0 +1,177 @@ +{ + // See https://go.microsoft.com/fwlink/?LinkId=733558 + // for the documentation about the tasks.json format + "version": "2.0.0", + "tasks": [ + { + "label": "all: Make & run", + "type": "shell", + "command": "make -j && ./pm3", + "windows": { + "options": { + "cwd": "${workspaceFolder}/../..", + "shell": { + "executable": "${workspaceFolder}/../../runme64.bat", + "args": [ + "-c \"cd ${workspaceFolderBasename} &&" + ], + + } + } + }, + "problemMatcher": [ + "$gcc" + ], + "group": { + "kind": "build", + "isDefault": true + } + }, + { + "label": "choose: Make", + "type": "shell", + "command": "make ${input:componentType} -j", + "windows": { + "options": { + "cwd": "${workspaceFolder}/../..", + "shell": { + "executable": "${workspaceFolder}/../../runme64.bat", + "args": [ + "-c \"cd ${workspaceFolderBasename} &&" + ], + + } + } + }, + "problemMatcher": [ + "$gcc" + ], + "group": "build", + }, + { + "label": "client: Debug: make", + "type": "shell", + "command": "make client -j DEBUG=1", + "windows": { + "options": { + "cwd": "${workspaceFolder}/../..", + "shell": { + "executable": "${workspaceFolder}/../../runme64.bat", + "args": [ + "-c \"cd ${workspaceFolderBasename} &&" + ], + + } + } + }, + "problemMatcher": [ + "$gcc" + ], + "group": "build", + }, + { + "label": "client: Debug: clean & make", + "type": "shell", + "command": "make client/clean && make client -j DEBUG=1", + "windows": { + "options": { + "cwd": "${workspaceFolder}/../..", + "shell": { + "executable": "${workspaceFolder}/../../runme64.bat", + "args": [ + "-c \"cd ${workspaceFolderBasename} &&" + ], + + } + } + }, + "problemMatcher": [ + "$gcc" + ], + "group": "build", + }, + { + "label": "fullimage: Make & Flash", + "type": "shell", + "command": "make fullimage && ./pm3-flash-fullimage", + "windows": { + "options": { + "cwd": "${workspaceFolder}/../..", + "shell": { + "executable": "${workspaceFolder}/../../runme64.bat", + "args": [ + "-c \"cd ${workspaceFolderBasename} &&" + ], + + } + } + }, + "problemMatcher": [] + }, + { + "label": "BOOTROM: Make & Flash", + "type": "shell", + "command": "make bootrom && ./pm3-flash-bootrom", + "windows": { + "options": { + "cwd": "${workspaceFolder}/../..", + "shell": { + "executable": "${workspaceFolder}/../../runme64.bat", + "args": [ + "-c \"cd ${workspaceFolderBasename} &&" + ], + + } + } + }, + "problemMatcher": [] + }, + { + "label": "Run client", + "type": "shell", + "command": "./pm3", + "windows": { + "options": { + "cwd": "${workspaceFolder}/../..", + "shell": { + "executable": "${workspaceFolder}/../../runme64.bat", + "args": [ + "-c \"cd ${workspaceFolderBasename} &&" + ], + + } + } + }, + "problemMatcher": [] + },{ + "label": "fullimage: clean & make", + "type": "shell", + "command": "make armsrc/clean && make armsrc/all SKIP_COMPRESSION=1 DEBUG=1", + "problemMatcher": [ + "$gcc" + ], + "group": "build", + } + ], + "inputs": [ + { + "type": "pickString", + "id": "componentType", + "description": "What Makefile target do you want to execute?", + "options": [ + "all", + "client", + "bootrom", + "fullimage", + "recovery", + "clean", + "install", + "uninstall", + "style", + "miscchecks", + "check", + ], + "default": "all" + } + ] +} \ No newline at end of file diff --git a/.vscode/tasks_wsl.json b/.vscode/tasks_wsl.json new file mode 100644 index 000000000..4cc21841d --- /dev/null +++ b/.vscode/tasks_wsl.json @@ -0,0 +1,177 @@ +{ + // See https://go.microsoft.com/fwlink/?LinkId=733558 + // for the documentation about the tasks.json format + "version": "2.0.0", + "tasks": [ + { + "label": "all: Make & run", + "type": "shell", + "command": "make -j && ./pm3", + "windows": { + "options": { + "cwd": "${workspaceFolder}/../..", + "shell": { + "executable": "${workspaceFolder}/../../runme64.bat", + "args": [ + "-c \"cd ${workspaceFolderBasename} &&" + ], + + } + } + }, + "problemMatcher": [ + "$gcc" + ], + "group": { + "kind": "build", + "isDefault": true + } + }, + { + "label": "choose: Make", + "type": "shell", + "command": "make ${input:componentType} -j", + "windows": { + "options": { + "cwd": "${workspaceFolder}/../..", + "shell": { + "executable": "${workspaceFolder}/../../runme64.bat", + "args": [ + "-c \"cd ${workspaceFolderBasename} &&" + ], + + } + } + }, + "problemMatcher": [ + "$gcc" + ], + "group": "build", + }, + { + "label": "client: Debug: make", + "type": "shell", + "command": "make client -j DEBUG=1", + "windows": { + "options": { + "cwd": "${workspaceFolder}/../..", + "shell": { + "executable": "${workspaceFolder}/../../runme64.bat", + "args": [ + "-c \"cd ${workspaceFolderBasename} &&" + ], + + } + } + }, + "problemMatcher": [ + "$gcc" + ], + "group": "build", + }, + { + "label": "client: Debug: clean & make", + "type": "shell", + "command": "make client/clean && make client -j DEBUG=1", + "windows": { + "options": { + "cwd": "${workspaceFolder}/../..", + "shell": { + "executable": "${workspaceFolder}/../../runme64.bat", + "args": [ + "-c \"cd ${workspaceFolderBasename} &&" + ], + + } + } + }, + "problemMatcher": [ + "$gcc" + ], + "group": "build", + }, + { + "label": "fullimage: Make & Flash", + "type": "shell", + "command": "make fullimage && ./pm3-flash-fullimage", + "windows": { + "options": { + "cwd": "${workspaceFolder}/../..", + "shell": { + "executable": "${workspaceFolder}/../../runme64.bat", + "args": [ + "-c \"cd ${workspaceFolderBasename} &&" + ], + + } + } + }, + "problemMatcher": [] + }, + { + "label": "BOOTROM: Make & Flash", + "type": "shell", + "command": "make bootrom && ./pm3-flash-bootrom", + "windows": { + "options": { + "cwd": "${workspaceFolder}/../..", + "shell": { + "executable": "${workspaceFolder}/../../runme64.bat", + "args": [ + "-c \"cd ${workspaceFolderBasename} &&" + ], + + } + } + }, + "problemMatcher": [] + }, + { + "label": "Run client", + "type": "shell", + "command": "./pm3", + "windows": { + "options": { + "cwd": "${workspaceFolder}/../..", + "shell": { + "executable": "${workspaceFolder}/../../runme64.bat", + "args": [ + "-c \"cd ${workspaceFolderBasename} &&" + ], + + } + } + }, + "problemMatcher": [] + },{ + "label": "fullimage: clean & make", + "type": "shell", + "command": "make armsrc/clean && make armsrc/all SKIP_COMPRESSION=1 DEBUG=1", + "problemMatcher": [ + "$gcc" + ], + "group": "build", + } + ], + "inputs": [ + { + "type": "pickString", + "id": "componentType", + "description": "What Makefile target do you want to execute?", + "options": [ + "all", + "client", + "bootrom", + "fullimage", + "recovery", + "clean", + "install", + "uninstall", + "style", + "miscchecks", + "check", + ], + "default": "all" + } + ] +} \ No newline at end of file From 040520d865486184e0165779a16f7774414277ee Mon Sep 17 00:00:00 2001 From: Ave Date: Tue, 29 Dec 2020 17:56:29 +0300 Subject: [PATCH 225/682] emrtd: Improve hashing logic, support SHA1 --- client/src/cmdhfemrtd.c | 86 +++++++++++++++++++--------------- client/src/cmdhfemrtd.h | 8 ++++ client/src/crypto/libpcrypto.c | 10 ++++ client/src/crypto/libpcrypto.h | 1 + 4 files changed, 68 insertions(+), 37 deletions(-) diff --git a/client/src/cmdhfemrtd.c b/client/src/cmdhfemrtd.c index 08c53467b..e563ac7fa 100644 --- a/client/src/cmdhfemrtd.c +++ b/client/src/cmdhfemrtd.c @@ -19,8 +19,7 @@ #include "cmdhf14a.h" // ExchangeAPDU14a #include "protocols.h" // definitions of ISO14A/7816 protocol #include "emv/apduinfo.h" // GetAPDUCodeDescription -#include "sha1.h" // KSeed calculation etc -#include "crypto/libpcrypto.h" // Hash calculation (sha256, sha512) +#include "crypto/libpcrypto.h" // Hash calculation (sha1, sha256, sha512) #include "mifare/desfire_crypto.h" // des_encrypt/des_decrypt #include "des.h" // mbedtls_des_key_set_parity #include "cmdhf14b.h" // exchange_14b_apdu @@ -108,6 +107,16 @@ static emrtd_dg_t dg_table[] = { {0x00, 0, NULL, NULL, NULL, false, false, false, false, NULL, NULL} }; +// https://security.stackexchange.com/questions/131241/where-do-magic-constants-for-signature-algorithms-come-from +// https://tools.ietf.org/html/rfc3447#page-43 +static emrtd_hashalg_t hashalg_table[] = { +// name hash func len len descriptor + {"SHA-1", sha1hash, 20, 9, {0x06, 0x05, 0x2B, 0x0E, 0x03, 0x02, 0x1A, 0x05, 0x00}}, + {"SHA-256", sha256hash, 32, 11, {0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01}}, + {"SHA-512", sha512hash, 64, 11, {0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03}}, + {NULL, NULL, 0, 0, {}} +}; + static emrtd_dg_t *emrtd_tag_to_dg(uint8_t tag) { for (int dgi = 0; dg_table[dgi].filename != NULL; dgi++) { if (dg_table[dgi].tag == tag) { @@ -339,7 +348,7 @@ static void emrtd_deskey(uint8_t *seed, const uint8_t *type, int length, uint8_t // SHA1 the key unsigned char key[64]; - mbedtls_sha1(data, length + 4, key); + sha1hash(data, length + 4, key); PrintAndLogEx(DEBUG, "key............... %s", sprint_hex_inrow(key, length + 4)); // Set parity bits @@ -822,7 +831,7 @@ static bool emrtd_do_bac(char *documentnumber, char *dob, char *expiry, uint8_t PrintAndLogEx(DEBUG, "kmrz.............. " _GREEN_("%s"), kmrz); uint8_t kseed[20] = { 0x00 }; - mbedtls_sha1((unsigned char *)kmrz, strlen(kmrz), kseed); + sha1hash((unsigned char *)kmrz, strlen(kmrz), kseed); PrintAndLogEx(DEBUG, "kseed (sha1)...... %s ", sprint_hex_inrow(kseed, 16)); emrtd_deskey(kseed, KENC_type, 16, kenc); @@ -1531,10 +1540,6 @@ static int emrtd_ef_sod_extract_signatures(uint8_t *data, size_t datalen, uint8_ return PM3_SUCCESS; } -// https://security.stackexchange.com/questions/131241/where-do-magic-constants-for-signature-algorithms-come-from -static const uint8_t emrtd_hashalgo_sha256[] = {0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01}; -static const uint8_t emrtd_hashalgo_sha512[] = {0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03}; - static int emrtd_parse_ef_sod_hash_algo(uint8_t *data, size_t datalen, int *hashalgo) { uint8_t hashalgoset[64] = { 0x00 }; size_t hashalgosetlen = 0; @@ -1546,16 +1551,23 @@ static int emrtd_parse_ef_sod_hash_algo(uint8_t *data, size_t datalen, int *hash PrintAndLogEx(DEBUG, "hash algo set: %s", sprint_hex_inrow(hashalgoset, hashalgosetlen)); - if (memcmp(emrtd_hashalgo_sha256, hashalgoset, 11) == 0) { - *hashalgo = 1; - } else if (memcmp(emrtd_hashalgo_sha512, hashalgoset, 11) == 0) { - *hashalgo = 3; - } else { - *hashalgo = 0; - return PM3_ESOFT; + for (int hashi = 0; hashalg_table[hashi].name != NULL; hashi++) { + PrintAndLogEx(DEBUG, "trying: %s", hashalg_table[hashi].name); + // We're only interested in checking if the length matches to avoid memory shenanigans + if (hashalg_table[hashi].descriptorlen != hashalgosetlen) { + PrintAndLogEx(DEBUG, "len mismatch: %i", hashalgosetlen); + continue; + } + + if (memcmp(hashalg_table[hashi].descriptor, hashalgoset, hashalgosetlen) == 0) { + *hashalgo = hashi; + return PM3_SUCCESS; + } } - return PM3_SUCCESS; + // Return hash algo 0 if we can't find anything + *hashalgo = -1; + return PM3_ESOFT; } static int emrtd_parse_ef_sod_hashes(uint8_t *data, size_t datalen, uint8_t *hashes, int *hashalgo) { @@ -1580,7 +1592,7 @@ static int emrtd_parse_ef_sod_hashes(uint8_t *data, size_t datalen, uint8_t *has PrintAndLogEx(DEBUG, "hash data: %s", sprint_hex_inrow(emrtdsig, emrtdsiglen)); if (emrtd_parse_ef_sod_hash_algo(emrtdsig, emrtdsiglen, hashalgo) != PM3_SUCCESS) { - PrintAndLogEx(ERR, "Failed to parse hash list. Unknown algo?"); + PrintAndLogEx(ERR, "Failed to parse hash list (Unknown algo?). Hash verification won't be available."); } if (!emrtd_lds_get_data_by_tag(emrtdsig, emrtdsiglen, hashlist, &hashlistlen, 0x30, 0x00, false, true, 1)) { @@ -1615,16 +1627,6 @@ static int emrtd_parse_ef_sod_hashes(uint8_t *data, size_t datalen, uint8_t *has return PM3_SUCCESS; } -static void emrtd_calc_dg_hash(uint8_t *data, size_t datalen, uint8_t *hash_out, int hash_algo) { - memset(hash_out, 0, 64); - - if (hash_algo == 1) { - sha256hash(data, datalen, hash_out); - } else if (hash_algo == 3) { - sha512hash(data, datalen, hash_out); - } -} - int infoHF_EMRTD(char *documentnumber, char *dob, char *expiry, bool BAC_available) { uint8_t response[EMRTD_MAX_FILE_SIZE] = { 0x00 }; int resplen = 0; @@ -1703,13 +1705,18 @@ int infoHF_EMRTD(char *documentnumber, char *dob, char *expiry, bool BAC_availab if (dg->parser != NULL) dg->parser(response, resplen); + PrintAndLogEx(DEBUG, "EF_DG%i hash algo: %i", dg->dgnum, hash_algo); // Check file hash - emrtd_calc_dg_hash(response, resplen, hash_out, hash_algo); + if (hash_algo != -1) { + PrintAndLogEx(DEBUG, "EF_DG%i hash on EF_SOD: %s", dg->dgnum, sprint_hex_inrow(dg_hashes[dg->dgnum], hashalg_table[hash_algo].hashlen)); + hashalg_table[hash_algo].hasher(response, resplen, hash_out); + PrintAndLogEx(DEBUG, "EF_DG%i hash calc: %s", dg->dgnum, sprint_hex_inrow(hash_out, hashalg_table[hash_algo].hashlen)); - if (memcmp(dg_hashes[dg->dgnum], hash_out, 64) == 0) { - PrintAndLogEx(SUCCESS, _GREEN_("Hash verification passed for EF_DG%i."), dg->dgnum); - } else { - PrintAndLogEx(ERR, _RED_("Hash verification failed for EF_DG%i."), dg->dgnum); + if (memcmp(dg_hashes[dg->dgnum], hash_out, hashalg_table[hash_algo].hashlen) == 0) { + PrintAndLogEx(SUCCESS, _GREEN_("Hash verification passed for EF_DG%i."), dg->dgnum); + } else { + PrintAndLogEx(ERR, _RED_("Hash verification failed for EF_DG%i."), dg->dgnum); + } } } } @@ -1789,13 +1796,18 @@ int infoHF_EMRTD_offline(const char *path) { if (dg->parser != NULL) dg->parser(data, datalen); + PrintAndLogEx(DEBUG, "EF_DG%i hash algo: %i", dg->dgnum, hash_algo); // Check file hash - emrtd_calc_dg_hash(data, datalen, hash_out, hash_algo); + if (hash_algo != -1) { + PrintAndLogEx(DEBUG, "EF_DG%i hash on EF_SOD: %s", dg->dgnum, sprint_hex_inrow(dg_hashes[dg->dgnum], hashalg_table[hash_algo].hashlen)); + hashalg_table[hash_algo].hasher(data, datalen, hash_out); + PrintAndLogEx(DEBUG, "EF_DG%i hash calc: %s", dg->dgnum, sprint_hex_inrow(hash_out, hashalg_table[hash_algo].hashlen)); - if (memcmp(dg_hashes[dg->dgnum], hash_out, 64) == 0) { - PrintAndLogEx(SUCCESS, _GREEN_("Hash verification passed for EF_DG%i."), dg->dgnum); - } else { - PrintAndLogEx(ERR, _RED_("Hash verification failed for EF_DG%i."), dg->dgnum); + if (memcmp(dg_hashes[dg->dgnum], hash_out, hashalg_table[hash_algo].hashlen) == 0) { + PrintAndLogEx(SUCCESS, _GREEN_("Hash verification passed for EF_DG%i."), dg->dgnum); + } else { + PrintAndLogEx(ERR, _RED_("Hash verification failed for EF_DG%i."), dg->dgnum); + } } free(data); } diff --git a/client/src/cmdhfemrtd.h b/client/src/cmdhfemrtd.h index 72f5f44b9..f7bd64945 100644 --- a/client/src/cmdhfemrtd.h +++ b/client/src/cmdhfemrtd.h @@ -27,6 +27,14 @@ typedef struct emrtd_dg_s { int (*dumper)(uint8_t *data, size_t datalen); } emrtd_dg_t; +typedef struct emrtd_hashalg_s { + const char *name; + int (*hasher)(uint8_t *datain, int datainlen, uint8_t *dataout); + size_t hashlen; + size_t descriptorlen; + const uint8_t descriptor[15]; +} emrtd_hashalg_t; + int CmdHFeMRTD(const char *Cmd); int dumpHF_EMRTD(char *documentnumber, char *dob, char *expiry, bool BAC_available); diff --git a/client/src/crypto/libpcrypto.c b/client/src/crypto/libpcrypto.c index cb73b3f5c..5c5455bf6 100644 --- a/client/src/crypto/libpcrypto.c +++ b/client/src/crypto/libpcrypto.c @@ -19,6 +19,7 @@ #include #include #include +#include #include #include #include @@ -93,6 +94,15 @@ static int fixed_rand(void *rng_state, unsigned char *output, size_t len) { return 0; } +int sha1hash(uint8_t *input, int length, uint8_t *hash) { + if (!hash || !input) + return 1; + + mbedtls_sha1(input, length, hash); + + return 0; +} + int sha256hash(uint8_t *input, int length, uint8_t *hash) { if (!hash || !input) return 1; diff --git a/client/src/crypto/libpcrypto.h b/client/src/crypto/libpcrypto.h index b4307f454..099fd4423 100644 --- a/client/src/crypto/libpcrypto.h +++ b/client/src/crypto/libpcrypto.h @@ -21,6 +21,7 @@ int aes_decode(uint8_t *iv, uint8_t *key, uint8_t *input, uint8_t *output, int l int aes_cmac(uint8_t *iv, uint8_t *key, uint8_t *input, uint8_t *mac, int length); int aes_cmac8(uint8_t *iv, uint8_t *key, uint8_t *input, uint8_t *mac, int length); +int sha1hash(uint8_t *input, int length, uint8_t *hash); int sha256hash(uint8_t *input, int length, uint8_t *hash); int sha512hash(uint8_t *input, int length, uint8_t *hash); From 6f316b8e29559d260f1f3be2ca8b3ce0dd5708f0 Mon Sep 17 00:00:00 2001 From: gator96100 Date: Tue, 29 Dec 2020 16:38:02 +0100 Subject: [PATCH 226/682] detect serial port --- .vscode/setup.sh | 69 +++++++++++++++++++++++++++++++++++++++++++++--- pm3 | 45 +++++++++++++++++-------------- 2 files changed, 90 insertions(+), 24 deletions(-) diff --git a/.vscode/setup.sh b/.vscode/setup.sh index b439f2cbd..ee8476d11 100644 --- a/.vscode/setup.sh +++ b/.vscode/setup.sh @@ -1,4 +1,65 @@ -export SerialPort="/dev/ttyACM0" -export DebuggerPath="/usr/bin/gdb" -export JLinkServerPath="/opt/SEGGER/JLink/JLinkGDBServerCLExe" -export DeviceMem="512" \ No newline at end of file +#!/bin/bash +############################### +# Linux # +# Uncomment to override # +############################### +#export SerialPort="/dev/ttyACM0" +#export DebuggerPath="/usr/bin/gdb" +#export JLinkServerPath="/opt/SEGGER/JLink/JLinkGDBServerCLExe" + +############################### +# WSL # +# Uncomment to override # +############################### +#export SerialPort="/dev/ttyS4" +#export DebuggerPath="/usr/bin/gdb" +#export JLinkServerPath="/mnt/c/Program Files (x86)/SEGGER/JLink/JLinkGDBServerCL.exe" + +############################### +# ProxSpace # +# Uncomment to override # +############################### +#export SerialPort="COM5" +#export DebuggerPath="${workspaceFolder}/../../msys2/mingw64/bin/gdb.exe" +#export JLinkServerPath="c/Program Files (x86)/SEGGER/JLink/JLinkGDBServerCL.exe" + +#Debugging on 256KB systems is not recommended +#This option does not override PLATFORM_SIZE +export DeviceMem="512" + + +VSCODEPATH=$(dirname "$0") + +function get_serial_port { + if [ -z "$SerialPort" ]; then + pm3list=$($VSCODEPATH/../pm3 --list 2>/dev/null) + #Use first port listed + SerialPort=$(echo $pm3list | head -n 1 | cut -c 4-) + if [ -z "$SerialPort" ]; then + echo >&2 "[!!] No serial port found, please set SerialPort manually" + exit 1 + fi + fi + + echo "Using $SerialPort as port" +} + + +HOSTOS=$(uname | awk '{print toupper($0)}') +if [ "$HOSTOS" = "LINUX" ]; then + if uname -a|grep -q Microsoft; then + echo "WSL" + else + echo "LINUX" + fi +elif [ "$HOSTOS" = "DARWIN" ]; then + echo >&2 "[!!] MacOS not supported, sorry!" + exit 1 +elif [[ "$HOSTOS" =~ MINGW(32|64)_NT* ]]; then + echo "ProxSpace" +else + echo >&2 "[!!] Host OS not recognized, abort: $HOSTOS" + exit 1 +fi + +get_serial_port \ No newline at end of file diff --git a/pm3 b/pm3 index 0d3b9863a..1ee2ebeb8 100755 --- a/pm3 +++ b/pm3 @@ -14,27 +14,32 @@ PM3PATH=$(dirname "$0") EVALENV="" FULLIMAGE="fullimage.elf" BOOTIMAGE="bootrom.elf" -# try pm3 dirs in current repo workdir -if [ -d "$PM3PATH/client/" ]; then - if [ -x "$PM3PATH/client/proxmark3" ]; then - CLIENT="$PM3PATH/client/proxmark3" - elif [ -x "$PM3PATH/client/build/proxmark3" ]; then - CLIENT="$PM3PATH/client/build/proxmark3" - else - echo >&2 "[!!] In devel workdir but no executable found, did you compile it?" - exit 1 - fi - # Devel mode: point to workdir pm3.py module - EVALENV+=" PYTHONPATH=$PM3PATH/client/src" -# try install dir -elif [ -x "$PM3PATH/proxmark3" ]; then - CLIENT="$PM3PATH/proxmark3" - EVALENV+=" PYTHONPATH=$PM3PATH/../share/proxmark3/pyscripts/" - # or /usr/[local/]lib/python3/dist-packages/pm3.py ? -else -# hope it's installed somehow, still not sure where fw images and pm3.py are... - CLIENT="proxmark3" + +#Skip check if --list is used +if [ ! "$1" == "--list" ]; then + # try pm3 dirs in current repo workdir + if [ -d "$PM3PATH/client/" ]; then + if [ -x "$PM3PATH/client/proxmark3" ]; then + CLIENT="$PM3PATH/client/proxmark3" + elif [ -x "$PM3PATH/client/build/proxmark3" ]; then + CLIENT="$PM3PATH/client/build/proxmark3" + else + echo >&2 "[!!] In devel workdir but no executable found, did you compile it?" + exit 1 + fi + # Devel mode: point to workdir pm3.py module + EVALENV+=" PYTHONPATH=$PM3PATH/client/src" + # try install dir + elif [ -x "$PM3PATH/proxmark3" ]; then + CLIENT="$PM3PATH/proxmark3" + EVALENV+=" PYTHONPATH=$PM3PATH/../share/proxmark3/pyscripts/" + # or /usr/[local/]lib/python3/dist-packages/pm3.py ? + else + # hope it's installed somehow, still not sure where fw images and pm3.py are... + CLIENT="proxmark3" + fi fi + # LeakSanitizer suppressions if [ -e .lsan_suppressions ]; then EVALENV+=" LSAN_OPTIONS=suppressions=.lsan_suppressions" From 71ac6369d8661bb8c9903638b94545ea11eba3b9 Mon Sep 17 00:00:00 2001 From: Ave Date: Tue, 29 Dec 2020 18:42:29 +0300 Subject: [PATCH 227/682] emrtd: Account for hash algo quirks --- client/src/cmdhfemrtd.c | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/client/src/cmdhfemrtd.c b/client/src/cmdhfemrtd.c index e563ac7fa..4ed1732b4 100644 --- a/client/src/cmdhfemrtd.c +++ b/client/src/cmdhfemrtd.c @@ -111,7 +111,7 @@ static emrtd_dg_t dg_table[] = { // https://tools.ietf.org/html/rfc3447#page-43 static emrtd_hashalg_t hashalg_table[] = { // name hash func len len descriptor - {"SHA-1", sha1hash, 20, 9, {0x06, 0x05, 0x2B, 0x0E, 0x03, 0x02, 0x1A, 0x05, 0x00}}, + {"SHA-1", sha1hash, 20, 7, {0x06, 0x05, 0x2B, 0x0E, 0x03, 0x02, 0x1A}}, {"SHA-256", sha256hash, 32, 11, {0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01}}, {"SHA-512", sha512hash, 64, 11, {0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03}}, {NULL, NULL, 0, 0, {}} @@ -1551,6 +1551,12 @@ static int emrtd_parse_ef_sod_hash_algo(uint8_t *data, size_t datalen, int *hash PrintAndLogEx(DEBUG, "hash algo set: %s", sprint_hex_inrow(hashalgoset, hashalgosetlen)); + // If last two bytes are 05 00, ignore them. + // https://wf.lavatech.top/ave-but-random/emrtd-data-quirks#EF_SOD + if (hashalgoset[hashalgosetlen - 2] == 0x05 && hashalgoset[hashalgosetlen - 1] == 0x00) { + hashalgosetlen -= 2; + } + for (int hashi = 0; hashalg_table[hashi].name != NULL; hashi++) { PrintAndLogEx(DEBUG, "trying: %s", hashalg_table[hashi].name); // We're only interested in checking if the length matches to avoid memory shenanigans @@ -1565,8 +1571,9 @@ static int emrtd_parse_ef_sod_hash_algo(uint8_t *data, size_t datalen, int *hash } } - // Return hash algo 0 if we can't find anything + // Return hash algo -1 if we can't find anything *hashalgo = -1; + PrintAndLogEx(ERR, "Failed to parse hash list (Unknown algo: %s). Hash verification won't be available.", sprint_hex_inrow(hashalgoset, hashalgosetlen)); return PM3_ESOFT; } @@ -1591,9 +1598,7 @@ static int emrtd_parse_ef_sod_hashes(uint8_t *data, size_t datalen, uint8_t *has PrintAndLogEx(DEBUG, "hash data: %s", sprint_hex_inrow(emrtdsig, emrtdsiglen)); - if (emrtd_parse_ef_sod_hash_algo(emrtdsig, emrtdsiglen, hashalgo) != PM3_SUCCESS) { - PrintAndLogEx(ERR, "Failed to parse hash list (Unknown algo?). Hash verification won't be available."); - } + emrtd_parse_ef_sod_hash_algo(emrtdsig, emrtdsiglen, hashalgo); if (!emrtd_lds_get_data_by_tag(emrtdsig, emrtdsiglen, hashlist, &hashlistlen, 0x30, 0x00, false, true, 1)) { PrintAndLogEx(ERR, "Failed to read hash list from EF_SOD."); From d1ec96ed41a55e80fac58a75cbbb54cca66ac4f6 Mon Sep 17 00:00:00 2001 From: Ave Date: Tue, 29 Dec 2020 19:13:10 +0300 Subject: [PATCH 228/682] emrtd: Ensure that emrtd_parse_ef_sod_hash_algo returns -1 on errors too --- client/src/cmdhfemrtd.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/client/src/cmdhfemrtd.c b/client/src/cmdhfemrtd.c index 4ed1732b4..6b966cfad 100644 --- a/client/src/cmdhfemrtd.c +++ b/client/src/cmdhfemrtd.c @@ -1544,6 +1544,9 @@ static int emrtd_parse_ef_sod_hash_algo(uint8_t *data, size_t datalen, int *hash uint8_t hashalgoset[64] = { 0x00 }; size_t hashalgosetlen = 0; + // We'll return hash algo -1 if we can't find anything + *hashalgo = -1; + if (!emrtd_lds_get_data_by_tag(data, datalen, hashalgoset, &hashalgosetlen, 0x30, 0x00, false, true, 0)) { PrintAndLogEx(ERR, "Failed to read hash algo set from EF_SOD."); return false; @@ -1571,8 +1574,6 @@ static int emrtd_parse_ef_sod_hash_algo(uint8_t *data, size_t datalen, int *hash } } - // Return hash algo -1 if we can't find anything - *hashalgo = -1; PrintAndLogEx(ERR, "Failed to parse hash list (Unknown algo: %s). Hash verification won't be available.", sprint_hex_inrow(hashalgoset, hashalgosetlen)); return PM3_ESOFT; } From 5f5e8758ab44d9a20bf2d42bcb6233ba24f501f0 Mon Sep 17 00:00:00 2001 From: gator96100 Date: Tue, 29 Dec 2020 17:22:09 +0100 Subject: [PATCH 229/682] Setup for WSL/Linux done --- .gitignore | 5 +- .vscode/setup.sh | 81 ++++++++++++++++++++--- .vscode/{ => templates}/launch_linux.json | 0 .vscode/{ => templates}/launch_ps.json | 0 .vscode/{ => templates}/launch_wsl.json | 0 .vscode/{ => templates}/tasks_linux.json | 0 .vscode/{ => templates}/tasks_ps.json | 0 .vscode/{ => templates}/tasks_wsl.json | 0 8 files changed, 75 insertions(+), 11 deletions(-) rename .vscode/{ => templates}/launch_linux.json (100%) rename .vscode/{ => templates}/launch_ps.json (100%) rename .vscode/{ => templates}/launch_wsl.json (100%) rename .vscode/{ => templates}/tasks_linux.json (100%) rename .vscode/{ => templates}/tasks_ps.json (100%) rename .vscode/{ => templates}/tasks_wsl.json (100%) diff --git a/.gitignore b/.gitignore index 1b27c52a3..125dc536e 100644 --- a/.gitignore +++ b/.gitignore @@ -110,6 +110,5 @@ fpga_version_info.c *.tmp #VSCode files -!.vscode/*.json -.vscode/launch.json -.vscode/tasks.json \ No newline at end of file +!.vscode/templates/*.json +!.vscode/extensions.json \ No newline at end of file diff --git a/.vscode/setup.sh b/.vscode/setup.sh index ee8476d11..93f7144f2 100644 --- a/.vscode/setup.sh +++ b/.vscode/setup.sh @@ -30,7 +30,7 @@ export DeviceMem="512" VSCODEPATH=$(dirname "$0") -function get_serial_port { +function setup_serial_port { if [ -z "$SerialPort" ]; then pm3list=$($VSCODEPATH/../pm3 --list 2>/dev/null) #Use first port listed @@ -40,26 +40,91 @@ function get_serial_port { exit 1 fi fi - echo "Using $SerialPort as port" } +function setup_gdb_linux { + if [ -z "$DebuggerPath" ]; then + export DebuggerPath="/usr/bin/gdb" + fi + if [ ! -x "$DebuggerPath" ]; then + echo >&2 "[!!] gdb not found, please set DebuggerPath manually" + exit 1 + fi +} + +function setup_jlink_linux { + if [ -z "$JLinkServerPath" ]; then + export JLinkServerPath="/opt/SEGGER/JLink/JLinkGDBServerCLExe" + fi + if [ ! -x "$JLinkServerPath" ]; then + echo >&2 "[!!] JLinkGDBServerCLExe not found, please set JLinkServerPath manually" + exit 1 + fi + +} + +function setup_jlink_wsl { + if [ -z "$JLinkServerPath" ]; then + export JLinkServerPath="/mnt/c/Program Files (x86)/SEGGER/JLink/JLinkGDBServerCL.exe" + fi + if [ ! -x "$JLinkServerPath" ]; then + echo >&2 "[!!] JLinkGDBServerCLExe not found, please set JLinkServerPath manually" + exit 1 + fi +} + +function setup_wsl { + setup_serial_port + setup_gdb_linux + setup_jlink_wsl + cp "$VSCODEPATH/templates/tasks_wsl.json" "$VSCODEPATH/tasks.json" + envsubst <"$VSCODEPATH/templates/launch_wsl.json" > "$VSCODEPATH/launch.json" +} + +function setup_linux { + setup_serial_port + setup_gdb_linux + setup_jlink_linux + cp "$VSCODEPATH/templates/tasks_linux.json" "$VSCODEPATH/tasks.json" + envsubst <"$VSCODEPATH/templates/launch_linux.json" > "$VSCODEPATH/launch.json" +} + +function setup_ps { + setup_serial_port + if [ -z "$JLinkServerPath" ]; then + export JLinkServerPath="c/Program Files (x86)/SEGGER/JLink/JLinkGDBServerCL.exe" + fi +} + +if [ -f "$VSCODEPATH/launch.json" ] || [ -f "$VSCODEPATH/tasks.json" ]; then + read -p "Existing configuration found, do you want to override it? " -n 1 -r + if [[ $REPLY =~ ^[Yy]$ ]] + then + rm "$VSCODEPATH/launch.json.bak" 2> /dev/null + rm "$VSCODEPATH/tasks.json.bak" 2> /dev/null + mv "$VSCODEPATH/launch.json" "$VSCODEPATH/launch.json.bak" 2> /dev/null + mv "$VSCODEPATH/tasks.json" "$VSCODEPATH/tasks.json.bak" 2> /dev/null + else + echo >&2 "[!!] user abort" + exit 1 + fi + +fi HOSTOS=$(uname | awk '{print toupper($0)}') if [ "$HOSTOS" = "LINUX" ]; then if uname -a|grep -q Microsoft; then - echo "WSL" + setup_wsl else - echo "LINUX" + setup_linux fi elif [ "$HOSTOS" = "DARWIN" ]; then echo >&2 "[!!] MacOS not supported, sorry!" exit 1 elif [[ "$HOSTOS" =~ MINGW(32|64)_NT* ]]; then - echo "ProxSpace" + setup_ps else echo >&2 "[!!] Host OS not recognized, abort: $HOSTOS" exit 1 -fi - -get_serial_port \ No newline at end of file +fi \ No newline at end of file diff --git a/.vscode/launch_linux.json b/.vscode/templates/launch_linux.json similarity index 100% rename from .vscode/launch_linux.json rename to .vscode/templates/launch_linux.json diff --git a/.vscode/launch_ps.json b/.vscode/templates/launch_ps.json similarity index 100% rename from .vscode/launch_ps.json rename to .vscode/templates/launch_ps.json diff --git a/.vscode/launch_wsl.json b/.vscode/templates/launch_wsl.json similarity index 100% rename from .vscode/launch_wsl.json rename to .vscode/templates/launch_wsl.json diff --git a/.vscode/tasks_linux.json b/.vscode/templates/tasks_linux.json similarity index 100% rename from .vscode/tasks_linux.json rename to .vscode/templates/tasks_linux.json diff --git a/.vscode/tasks_ps.json b/.vscode/templates/tasks_ps.json similarity index 100% rename from .vscode/tasks_ps.json rename to .vscode/templates/tasks_ps.json diff --git a/.vscode/tasks_wsl.json b/.vscode/templates/tasks_wsl.json similarity index 100% rename from .vscode/tasks_wsl.json rename to .vscode/templates/tasks_wsl.json From a14b5f7b5fbde1aec5c5359ded808fd056d5c38a Mon Sep 17 00:00:00 2001 From: Ave Date: Tue, 29 Dec 2020 19:24:44 +0300 Subject: [PATCH 230/682] emrtd: Employ a workaround for data length of 0x80 This is to make US passport hashes read properly. https://wf.lavatech.top/ave-but-random/emrtd-data-quirks#EF_SOD --- client/src/cmdhfemrtd.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/client/src/cmdhfemrtd.c b/client/src/cmdhfemrtd.c index 6b966cfad..fa9c936e9 100644 --- a/client/src/cmdhfemrtd.c +++ b/client/src/cmdhfemrtd.c @@ -217,6 +217,11 @@ static int emrtd_get_asn1_data_length(uint8_t *datain, int datainlen, int offset PrintAndLogEx(DEBUG, "asn1 datalength, lenfield: %02X", lenfield); if (lenfield <= 0x7f) { return lenfield; + } else if (lenfield == 0x80) { + // TODO: 0x80 means indeterminate. + // Giving rest of the file is a workaround, nothing more, nothing less. + // More at https://letsencrypt.org/docs/a-warm-welcome-to-asn1-and-der/ + return datainlen; } else if (lenfield == 0x81) { return ((int) * (datain + offset + 1)); } else if (lenfield == 0x82) { @@ -231,7 +236,7 @@ static int emrtd_get_asn1_field_length(uint8_t *datain, int datainlen, int offse PrintAndLogEx(DEBUG, "asn1 fieldlength, datain: %s", sprint_hex_inrow(datain, datainlen)); int lenfield = (int) * (datain + offset); PrintAndLogEx(DEBUG, "asn1 fieldlength, lenfield: %02X", lenfield); - if (lenfield <= 0x7F) { + if (lenfield <= 0x80) { return 1; } else if (lenfield == 0x81) { return 2; From f3f47a66e965276f3df44ae4d18c41d7ef27225e Mon Sep 17 00:00:00 2001 From: iceman1001 Date: Tue, 29 Dec 2020 17:25:48 +0100 Subject: [PATCH 231/682] hf mfu info - now supports cliparser, fixed magic detection output, fixed ntag counter output --- client/src/cmdhfmfu.c | 303 ++++++++++++++++++++++++++---------------- client/src/cmdhfmfu.h | 3 + 2 files changed, 188 insertions(+), 118 deletions(-) diff --git a/client/src/cmdhfmfu.c b/client/src/cmdhfmfu.c index c69de053b..639429fba 100644 --- a/client/src/cmdhfmfu.c +++ b/client/src/cmdhfmfu.c @@ -13,6 +13,7 @@ #include "commonutil.h" #include "crypto/libpcrypto.h" #include "des.h" +#include "aes.h" #include "cmdhfmf.h" #include "cmdhf14a.h" #include "comms.h" @@ -23,7 +24,6 @@ #include "cliparser.h" #include "cmdmain.h" - #define MAX_UL_BLOCKS 0x0F #define MAX_ULC_BLOCKS 0x2F #define MAX_ULEV1a_BLOCKS 0x13 @@ -42,26 +42,6 @@ static int CmdHelp(const char *Cmd); -static int usage_hf_mfu_info(void) { - PrintAndLogEx(NORMAL, "It gathers information about the tag and tries to detect what kind it is."); - PrintAndLogEx(NORMAL, "Sometimes the tags are locked down, and you may need a key to be able to read the information"); - PrintAndLogEx(NORMAL, "The following tags can be identified:\n"); - PrintAndLogEx(NORMAL, "Ultralight, Ultralight-C, Ultralight EV1, NTAG 203, NTAG 210,"); - PrintAndLogEx(NORMAL, "NTAG 212, NTAG 213, NTAG 215, NTAG 216, NTAG I2C 1K & 2K"); - PrintAndLogEx(NORMAL, "my-d, my-d NFC, my-d move, my-d move NFC\n"); - PrintAndLogEx(NORMAL, "Usage: hf mfu info k l"); - PrintAndLogEx(NORMAL, " Options : "); - PrintAndLogEx(NORMAL, " k : (optional) key for authentication [UL-C 16bytes, EV1/NTAG 4bytes]"); - PrintAndLogEx(NORMAL, " l : (optional) swap entered key's endianness"); - PrintAndLogEx(NORMAL, ""); - PrintAndLogEx(NORMAL, "Examples:"); - PrintAndLogEx(NORMAL, _YELLOW_(" hf mfu info")); - PrintAndLogEx(NORMAL, _YELLOW_(" hf mfu info k 00112233445566778899AABBCCDDEEFF")); - PrintAndLogEx(NORMAL, _YELLOW_(" hf mfu info k AABBCCDD")); - PrintAndLogEx(NORMAL, ""); - return PM3_SUCCESS; -} - static int usage_hf_mfu_dump(void) { PrintAndLogEx(NORMAL, "Reads all pages from Ultralight, Ultralight-C, Ultralight EV1"); PrintAndLogEx(NORMAL, "NTAG 203, NTAG 210, NTAG 212, NTAG 213, NTAG 215, NTAG 216"); @@ -684,62 +664,80 @@ int ul_print_type(uint32_t tagtype, uint8_t spaces) { if (spaces > 10) spaces = 10; + + char typestr[100]; + memset(typestr, 0x00, sizeof(typestr)); + if (tagtype & UL) - PrintAndLogEx(SUCCESS, "%*sTYPE: " _YELLOW_("MIFARE Ultralight (MF0ICU1) %s"), spaces, "", (tagtype & MAGIC) ? "" : ""); + snprintf(typestr, sizeof(typestr), "%*sTYPE: " _YELLOW_("MIFARE Ultralight (MF0ICU1)s"), spaces, ""); else if (tagtype & UL_C) - PrintAndLogEx(SUCCESS, "%*sTYPE: " _YELLOW_("MIFARE Ultralight C (MF0ULC) %s"), spaces, "", (tagtype & MAGIC) ? "" : ""); + snprintf(typestr, sizeof(typestr), "%*sTYPE: " _YELLOW_("MIFARE Ultralight C (MF0ULC)"), spaces, ""); else if (tagtype & UL_NANO_40) - PrintAndLogEx(SUCCESS, "%*sTYPE: " _YELLOW_("MIFARE Ultralight Nano 40bytes (MF0UNH00)"), spaces, ""); + snprintf(typestr, sizeof(typestr), "%*sTYPE: " _YELLOW_("MIFARE Ultralight Nano 40bytes (MF0UNH00)"), spaces, ""); else if (tagtype & UL_EV1_48) - PrintAndLogEx(SUCCESS, "%*sTYPE: " _YELLOW_("MIFARE Ultralight EV1 48bytes (MF0UL1101)"), spaces, ""); + snprintf(typestr, sizeof(typestr), "%*sTYPE: " _YELLOW_("MIFARE Ultralight EV1 48bytes (MF0UL1101)"), spaces, ""); else if (tagtype & UL_EV1_128) - PrintAndLogEx(SUCCESS, "%*sTYPE: " _YELLOW_("MIFARE Ultralight EV1 128bytes (MF0UL2101)"), spaces, ""); + snprintf(typestr, sizeof(typestr), "%*sTYPE: " _YELLOW_("MIFARE Ultralight EV1 128bytes (MF0UL2101)"), spaces, ""); else if (tagtype & UL_EV1) - PrintAndLogEx(NORMAL, "%*sTYPE: " _YELLOW_("MIFARE Ultralight EV1 UNKNOWN"), spaces, ""); + snprintf(typestr, sizeof(typestr), "%*sTYPE: " _YELLOW_("MIFARE Ultralight EV1 UNKNOWN"), spaces, ""); else if (tagtype & NTAG) - PrintAndLogEx(NORMAL, "%*sTYPE: " _YELLOW_("NTAG UNKNOWN"), spaces, ""); + snprintf(typestr, sizeof(typestr), "%*sTYPE: " _YELLOW_("NTAG UNKNOWN"), spaces, ""); else if (tagtype & NTAG_203) - PrintAndLogEx(SUCCESS, "%*sTYPE: " _YELLOW_("NTAG 203 144bytes (NT2H0301F0DT)"), spaces, ""); + snprintf(typestr, sizeof(typestr), "%*sTYPE: " _YELLOW_("NTAG 203 144bytes (NT2H0301F0DT)"), spaces, ""); else if (tagtype & NTAG_210) - PrintAndLogEx(SUCCESS, "%*sTYPE: " _YELLOW_("NTAG 210 48bytes (NT2L1011G0DU)"), spaces, ""); + snprintf(typestr, sizeof(typestr), "%*sTYPE: " _YELLOW_("NTAG 210 48bytes (NT2L1011G0DU)"), spaces, ""); else if (tagtype & NTAG_212) - PrintAndLogEx(SUCCESS, "%*sTYPE: " _YELLOW_("NTAG 212 128bytes (NT2L1211G0DU)"), spaces, ""); + snprintf(typestr, sizeof(typestr), "%*sTYPE: " _YELLOW_("NTAG 212 128bytes (NT2L1211G0DU)"), spaces, ""); else if (tagtype & NTAG_213) - PrintAndLogEx(SUCCESS, "%*sTYPE: " _YELLOW_("NTAG 213 144bytes (NT2H1311G0DU)"), spaces, ""); + snprintf(typestr, sizeof(typestr), "%*sTYPE: " _YELLOW_("NTAG 213 144bytes (NT2H1311G0DU)"), spaces, ""); else if (tagtype & NTAG_213_F) - PrintAndLogEx(SUCCESS, "%*sTYPE: " _YELLOW_("NTAG 213F 144bytes (NT2H1311F0DTL)"), spaces, ""); + snprintf(typestr, sizeof(typestr), "%*sTYPE: " _YELLOW_("NTAG 213F 144bytes (NT2H1311F0DTL)"), spaces, ""); else if (tagtype & NTAG_213_C) - PrintAndLogEx(SUCCESS, "%*sTYPE: " _YELLOW_("NTAG 213C 144bytes (NT2H1311C1DTL)"), spaces, ""); + snprintf(typestr, sizeof(typestr), "%*sTYPE: " _YELLOW_("NTAG 213C 144bytes (NT2H1311C1DTL)"), spaces, ""); else if (tagtype & NTAG_213_TT) - PrintAndLogEx(SUCCESS, "%*sTYPE: " _YELLOW_("NTAG 213TT 144bytes (NT2H1311TTDU)"), spaces, ""); + snprintf(typestr, sizeof(typestr), "%*sTYPE: " _YELLOW_("NTAG 213TT 144bytes (NT2H1311TTDU)"), spaces, ""); else if (tagtype & NTAG_215) - PrintAndLogEx(SUCCESS, "%*sTYPE: " _YELLOW_("NTAG 215 504bytes (NT2H1511G0DU)"), spaces, ""); + snprintf(typestr, sizeof(typestr), "%*sTYPE: " _YELLOW_("NTAG 215 504bytes (NT2H1511G0DU)"), spaces, ""); else if (tagtype & NTAG_216) - PrintAndLogEx(SUCCESS, "%*sTYPE: " _YELLOW_("NTAG 216 888bytes (NT2H1611G0DU)"), spaces, ""); + snprintf(typestr, sizeof(typestr), "%*sTYPE: " _YELLOW_("NTAG 216 888bytes (NT2H1611G0DU)"), spaces, ""); else if (tagtype & NTAG_216_F) - PrintAndLogEx(SUCCESS, "%*sTYPE: " _YELLOW_("NTAG 216F 888bytes (NT2H1611F0DTL)"), spaces, ""); + snprintf(typestr, sizeof(typestr), "%*sTYPE: " _YELLOW_("NTAG 216F 888bytes (NT2H1611F0DTL)"), spaces, ""); else if (tagtype & NTAG_I2C_1K) - PrintAndLogEx(SUCCESS, "%*sTYPE: " _YELLOW_("NTAG I2C 888bytes (NT3H1101FHK)"), spaces, ""); + snprintf(typestr, sizeof(typestr), "%*sTYPE: " _YELLOW_("NTAG I2C 888bytes (NT3H1101FHK)"), spaces, ""); else if (tagtype & NTAG_I2C_2K) - PrintAndLogEx(SUCCESS, "%*sTYPE: " _YELLOW_("NTAG I2C 1904bytes (NT3H1201FHK)"), spaces, ""); + snprintf(typestr, sizeof(typestr), "%*sTYPE: " _YELLOW_("NTAG I2C 1904bytes (NT3H1201FHK)"), spaces, ""); else if (tagtype & NTAG_I2C_1K_PLUS) - PrintAndLogEx(SUCCESS, "%*sTYPE: " _YELLOW_("NTAG I2C plus 888bytes (NT3H2111FHK)"), spaces, ""); + snprintf(typestr, sizeof(typestr), "%*sTYPE: " _YELLOW_("NTAG I2C plus 888bytes (NT3H2111FHK)"), spaces, ""); else if (tagtype & NTAG_I2C_2K_PLUS) - PrintAndLogEx(SUCCESS, "%*sTYPE: " _YELLOW_("NTAG I2C plus 1912bytes (NT3H2211FHK)"), spaces, ""); + snprintf(typestr, sizeof(typestr), "%*sTYPE: " _YELLOW_("NTAG I2C plus 1912bytes (NT3H2211FHK)"), spaces, ""); else if (tagtype & MY_D) - PrintAndLogEx(SUCCESS, "%*sTYPE: " _YELLOW_("INFINEON my-d\x99 (SLE 66RxxS)"), spaces, ""); + snprintf(typestr, sizeof(typestr), "%*sTYPE: " _YELLOW_("INFINEON my-d\x99 (SLE 66RxxS)"), spaces, ""); else if (tagtype & MY_D_NFC) - PrintAndLogEx(SUCCESS, "%*sTYPE: " _YELLOW_("INFINEON my-d\x99 NFC (SLE 66RxxP)"), spaces, ""); + snprintf(typestr, sizeof(typestr), "%*sTYPE: " _YELLOW_("INFINEON my-d\x99 NFC (SLE 66RxxP)"), spaces, ""); else if (tagtype & MY_D_MOVE) - PrintAndLogEx(SUCCESS, "%*sTYPE: " _YELLOW_("INFINEON my-d\x99 move (SLE 66R01P)"), spaces, ""); + snprintf(typestr, sizeof(typestr), "%*sTYPE: " _YELLOW_("INFINEON my-d\x99 move (SLE 66R01P)"), spaces, ""); else if (tagtype & MY_D_MOVE_NFC) - PrintAndLogEx(SUCCESS, "%*sTYPE: " _YELLOW_("INFINEON my-d\x99 move NFC (SLE 66R01P)"), spaces, ""); + snprintf(typestr, sizeof(typestr), "%*sTYPE: " _YELLOW_("INFINEON my-d\x99 move NFC (SLE 66R01P)"), spaces, ""); else if (tagtype & MY_D_MOVE_LEAN) - PrintAndLogEx(SUCCESS, "%*sTYPE: " _YELLOW_("INFINEON my-d\x99 move lean (SLE 66R01L)"), spaces, ""); + snprintf(typestr, sizeof(typestr), "%*sTYPE: " _YELLOW_("INFINEON my-d\x99 move lean (SLE 66R01L)"), spaces, ""); else if (tagtype & FUDAN_UL) - PrintAndLogEx(SUCCESS, "%*sTYPE: " _YELLOW_("FUDAN Ultralight Compatible (or other compatible) %s"), spaces, "", (tagtype & MAGIC) ? "" : ""); + snprintf(typestr, sizeof(typestr), "%*sTYPE: " _YELLOW_("FUDAN Ultralight Compatible (or other compatible)"), spaces, ""); else - PrintAndLogEx(NORMAL, "%*sTYPE: " _YELLOW_("Unknown %06x"), spaces, "", tagtype); + snprintf(typestr, sizeof(typestr), "%*sTYPE: " _YELLOW_("Unknown %06x"), spaces, "", tagtype); + + bool ismagic = ((tagtype & MAGIC) == MAGIC); + if (ismagic) + snprintf(typestr + strlen(typestr), 4, " ("); + + snprintf(typestr + strlen(typestr) , sizeof(typestr) - strlen(typestr), " %s ", (tagtype & MAGIC) ? _GREEN_("magic") : ""); + tagtype ^= MAGIC; + snprintf(typestr + strlen(typestr) , sizeof(typestr) - strlen(typestr), "%s", (tagtype & MAGIC_1A) ? _GREEN_("Gen 1a") : ""); + snprintf(typestr + strlen(typestr) , sizeof(typestr) - strlen(typestr), "%s", (tagtype & MAGIC_1B) ? _GREEN_("Gen 1b") : ""); + + if (ismagic) + snprintf(typestr + strlen(typestr), 4, " )"); + + PrintAndLogEx(SUCCESS, "%s", typestr); return PM3_SUCCESS; } @@ -895,7 +893,10 @@ static int ulev1_print_counters(void) { len = ulev1_readCounter(i, counter, sizeof(counter)); if (len == 3) { PrintAndLogEx(INFO, " [%0d]: %s", i, sprint_hex(counter, 3)); - PrintAndLogEx(SUCCESS, " - %02X tearing (%s)", tear[0], (tear[0] == 0xBD) ? _GREEN_("ok") : _RED_("failure")); + PrintAndLogEx(SUCCESS, " - %02X tearing (%s)" + , tear[0] + , (tear[0] == 0xBD) ? _GREEN_("ok") : _RED_("fail") + ); } } return len; @@ -983,7 +984,7 @@ static int ulev1_print_signature(TagTypeUL_t tagtype, uint8_t *uid, uint8_t *sig if (is_valid == false || i == ARRAYLEN(nxp_mfu_public_keys)) { PrintAndLogEx(INFO, " Elliptic curve parameters: NID_secp128r1"); PrintAndLogEx(INFO, " TAG IC Signature: %s", sprint_hex_inrow(signature, signature_len)); - PrintAndLogEx(SUCCESS, " Signature verification: " _RED_("failed")); + PrintAndLogEx(SUCCESS, " Signature verification (" _RED_("fail") ")"); return PM3_ESOFT; } @@ -991,7 +992,7 @@ static int ulev1_print_signature(TagTypeUL_t tagtype, uint8_t *uid, uint8_t *sig PrintAndLogEx(INFO, "IC signature public key value: %s", nxp_mfu_public_keys[i].value); PrintAndLogEx(INFO, " Elliptic curve parameters: NID_secp128r1"); PrintAndLogEx(INFO, " TAG IC Signature: %s", sprint_hex_inrow(signature, signature_len)); - PrintAndLogEx(SUCCESS, " Signature verification: " _GREEN_("successful")); + PrintAndLogEx(SUCCESS, " Signature verification (" _GREEN_("successful") ")" ); return PM3_SUCCESS; } @@ -1021,7 +1022,10 @@ static int ntag_print_counter(void) { len = ulev1_readCounter(0x02, counter, sizeof(counter)); (void)len; PrintAndLogEx(INFO, " [02]: %s", sprint_hex(counter, 3)); - PrintAndLogEx(SUCCESS, " - %02X tearing (" _GREEN_("%s")")", tear[0], (tear[0] == 0xBD) ? "ok" : "failure"); + PrintAndLogEx(SUCCESS, " - %02X tearing (%s)" + , tear[0] + , (tear[0] == 0xBD) ? _GREEN_("ok") : _RED_("fail") + ); return len; } @@ -1057,12 +1061,34 @@ static int ul_magic_test(void) { // 2) make a wrong length write to page0, and see if tag answers with ACK/NACK: iso14a_card_select_t card; - if (!ul_select(&card)) + if (ul_select(&card) == false) return UL_ERROR; + int status = ul_comp_write(0, NULL, 0); DropField(); if (status == 0) return MAGIC; + + // check for GEN1A, GEN1B and NTAG21x + uint8_t is_generation = 0; + PacketResponseNG resp; + clearCommandBuffer(); + uint8_t payload[] = { 0 }; + SendCommandNG(CMD_HF_MIFARE_CIDENT, payload, sizeof(payload)); + if (WaitForResponseTimeout(CMD_HF_MIFARE_CIDENT, &resp, 1500)) { + if (resp.status == PM3_SUCCESS) + is_generation = resp.data.asBytes[0]; + } + switch (is_generation) { + case MAGIC_GEN_1A: + return MAGIC_1A; + case MAGIC_GEN_1B: + return MAGIC_1B; + case MAGIC_NTAG21X: + return MAGIC_NTAG; + default: + break; + } return 0; } @@ -1071,7 +1097,8 @@ uint32_t GetHF14AMfU_Type(void) { TagTypeUL_t tagtype = UNKNOWN; iso14a_card_select_t card; - if (!ul_select(&card)) return UL_ERROR; + if (ul_select(&card) == false) + return UL_ERROR; // Ultralight - ATQA / SAK if (card.atqa[1] != 0x00 || card.atqa[0] != 0x44 || card.sak != 0x00) { @@ -1177,7 +1204,8 @@ uint32_t GetHF14AMfU_Type(void) { tagtype = UL_C; } else { // need to re-select after authentication error - if (!ul_select(&card)) return UL_ERROR; + if (ul_select(&card) == false) + return UL_ERROR; uint8_t data[16] = {0x00}; // read page 0x26-0x29 (last valid ntag203 page) @@ -1222,7 +1250,9 @@ uint32_t GetHF14AMfU_Type(void) { } tagtype |= ul_magic_test(); - if (tagtype == (UNKNOWN | MAGIC)) tagtype = (UL_MAGIC); + if (tagtype == (UNKNOWN | MAGIC)) { + tagtype = (UL_MAGIC); + } return tagtype; } // @@ -1230,56 +1260,53 @@ uint32_t GetHF14AMfU_Type(void) { // static int CmdHF14AMfUInfo(const char *Cmd) { + CLIParserContext *ctx; + CLIParserInit(&ctx, "hf mfu info", + "Get info about MIFARE Ultralight Family styled tag.\n" + "Sometimes the tags are locked down, and you may need a key to be able to read the information", + "hf mfu info\n" + "hf mfu info k AABBCCDD\n" + "hf mfu info k 00112233445566778899AABBCCDDEEFF" + ); + + void *argtable[] = { + arg_param_begin, + arg_str0("k", "key", "", "key for authentication (UL-C 16 bytes, EV1/NTAG 4 bytes)"), + arg_lit0("l", NULL, "swap entered key's endianness"), + arg_param_end + }; + CLIExecWithReturn(ctx, Cmd, argtable, true); + + int ak_len = 0; + uint8_t authenticationkey[16] = {0x00}; + CLIGetHexWithReturn(ctx, 1, authenticationkey, &ak_len); + bool swap_endian = arg_get_lit(ctx, 2); + CLIParserFree(ctx); + + if (ak_len) { + if (ak_len != 16 || ak_len != 8) { + PrintAndLogEx(WARNING, "ERROR: Key is incorrect length\n"); + return PM3_EINVARG; + } + } + + bool has_auth_key = false; + if (ak_len > 0) + has_auth_key = true; + uint8_t authlim = 0xff; uint8_t data[16] = {0x00}; iso14a_card_select_t card; int status; - bool errors = false; - bool hasAuthKey = false; - bool locked = false; - bool swapEndian = false; - uint8_t cmdp = 0; - uint8_t dataLen = 0; - uint8_t authenticationkey[16] = {0x00}; uint8_t *authkeyptr = authenticationkey; uint8_t pwd[4] = {0, 0, 0, 0}; uint8_t *key = pwd; uint8_t pack[4] = {0, 0, 0, 0}; int len; - char tempStr[50]; - - while (param_getchar(Cmd, cmdp) != 0x00 && !errors) { - switch (tolower(param_getchar(Cmd, cmdp))) { - case 'h': - return usage_hf_mfu_info(); - case 'k': - dataLen = param_getstr(Cmd, cmdp + 1, tempStr, sizeof(tempStr)); - if (dataLen == 32 || dataLen == 8) { //ul-c or ev1/ntag key length - errors = param_gethex(tempStr, 0, authenticationkey, dataLen); - dataLen /= 2; // handled as bytes from now on - } else { - PrintAndLogEx(WARNING, "ERROR: Key is incorrect length\n"); - errors = true; - } - cmdp += 2; - hasAuthKey = true; - break; - case 'l': - swapEndian = true; - cmdp++; - break; - default: - PrintAndLogEx(WARNING, "Unknown parameter: " _RED_("'%c'"), param_getchar(Cmd, cmdp)); - errors = true; - break; - } - } - //Validations - if (errors) return usage_hf_mfu_info(); - TagTypeUL_t tagtype = GetHF14AMfU_Type(); - if (tagtype == UL_ERROR) return PM3_ESOFT; + if (tagtype == UL_ERROR) + return PM3_ESOFT; PrintAndLogEx(NORMAL, ""); PrintAndLogEx(INFO, "--- " _CYAN_("Tag Information") " --------------------------"); @@ -1287,10 +1314,15 @@ static int CmdHF14AMfUInfo(const char *Cmd) { ul_print_type(tagtype, 6); // Swap endianness - if (swapEndian && hasAuthKey) authkeyptr = SwapEndian64(authenticationkey, dataLen, (dataLen == 16) ? 8 : 4); + if (swap_endian && has_auth_key) { + authkeyptr = SwapEndian64(authenticationkey, ak_len, (ak_len == 16) ? 8 : 4); + } - if (ul_auth_select(&card, tagtype, hasAuthKey, authkeyptr, pack, sizeof(pack)) == PM3_ESOFT) return PM3_ESOFT; + if (ul_auth_select(&card, tagtype, has_auth_key, authkeyptr, pack, sizeof(pack)) == PM3_ESOFT) { + return PM3_ESOFT; + } + bool locked = false; // read pages 0,1,2,3 (should read 4pages) status = ul_read(0, data, sizeof(data)); if (status == -1) { @@ -1329,12 +1361,16 @@ static int CmdHF14AMfUInfo(const char *Cmd) { PrintAndLogEx(ERR, "Error: tag didn't answer to READ magic"); return PM3_ESOFT; } - if (status == 16) ulc_print_3deskey(ulc_deskey); + if (status == 16) { + ulc_print_3deskey(ulc_deskey); + } } else { DropField(); // if we called info with key, just return - if (hasAuthKey) return PM3_SUCCESS; + if (has_auth_key) { + return PM3_SUCCESS; + } // also try to diversify default keys.. look into CmdHF14AMfGenDiverseKeys if (try_default_3des_keys(&key)) { @@ -1353,7 +1389,9 @@ static int CmdHF14AMfUInfo(const char *Cmd) { if ((tagtype & (UL_EV1_48 | UL_EV1_128 | UL_EV1))) { if (ulev1_print_counters() != 3) { // failed - re-select - if (ul_auth_select(&card, tagtype, hasAuthKey, authkeyptr, pack, sizeof(pack)) == PM3_ESOFT) return PM3_ESOFT; + if (ul_auth_select(&card, tagtype, has_auth_key, authkeyptr, pack, sizeof(pack)) == PM3_ESOFT) { + return PM3_ESOFT; + } } } @@ -1361,7 +1399,9 @@ static int CmdHF14AMfUInfo(const char *Cmd) { if ((tagtype & (NTAG_213 | NTAG_213_F | NTAG_213_C | NTAG_213_TT | NTAG_215 | NTAG_216))) { if (ntag_print_counter()) { // failed - re-select - if (ul_auth_select(&card, tagtype, hasAuthKey, authkeyptr, pack, sizeof(pack)) == PM3_ESOFT) return PM3_ESOFT; + if (ul_auth_select(&card, tagtype, has_auth_key, authkeyptr, pack, sizeof(pack)) == PM3_ESOFT) { + return PM3_ESOFT; + } } } @@ -1378,7 +1418,9 @@ static int CmdHF14AMfUInfo(const char *Cmd) { ulev1_print_signature(tagtype, card.uid, ulev1_signature, sizeof(ulev1_signature)); } else { // re-select - if (ul_auth_select(&card, tagtype, hasAuthKey, authkeyptr, pack, sizeof(pack)) == PM3_ESOFT) return PM3_ESOFT; + if (ul_auth_select(&card, tagtype, has_auth_key, authkeyptr, pack, sizeof(pack)) == PM3_ESOFT) { + return PM3_ESOFT; + } } // Get Version @@ -1392,7 +1434,9 @@ static int CmdHF14AMfUInfo(const char *Cmd) { ulev1_print_version(version); } else { locked = true; - if (ul_auth_select(&card, tagtype, hasAuthKey, authkeyptr, pack, sizeof(pack)) == PM3_ESOFT) return PM3_ESOFT; + if (ul_auth_select(&card, tagtype, has_auth_key, authkeyptr, pack, sizeof(pack)) == PM3_ESOFT) { + return PM3_ESOFT; + } } uint8_t startconfigblock = 0; @@ -1416,7 +1460,7 @@ static int CmdHF14AMfUInfo(const char *Cmd) { // save AUTHENTICATION LIMITS for later: authlim = (ulev1_conf[4] & 0x07); // add pwd / pack if used from cli - if (hasAuthKey) { + if (has_auth_key) { memcpy(ulev1_conf + 8, authkeyptr, 4); memcpy(ulev1_conf + 12, pack, 2); } @@ -1428,57 +1472,67 @@ static int CmdHF14AMfUInfo(const char *Cmd) { // 0 = limitless. // 1-7 = limit. No automatic tries then. // hasAuthKey, if we was called with key, skip test. - if (!authlim && !hasAuthKey) { + if (!authlim && !has_auth_key) { PrintAndLogEx(NORMAL, ""); PrintAndLogEx(SUCCESS, "--- " _CYAN_("Known EV1/NTAG passwords")); // test pwd gen A num_to_bytes(ul_ev1_pwdgenA(card.uid), 4, key); len = ulev1_requestAuthentication(key, pack, sizeof(pack)); if (len > -1) { - PrintAndLogEx(SUCCESS, "Found a default password: " _GREEN_("%s") "|| Pack: %02X %02X", sprint_hex(key, 4), pack[0], pack[1]); + PrintAndLogEx(SUCCESS, "Found a default password: " _GREEN_("%s") " Pack: %02X %02X", sprint_hex(key, 4), pack[0], pack[1]); goto out; } - if (ul_auth_select(&card, tagtype, hasAuthKey, authkeyptr, pack, sizeof(pack)) == PM3_ESOFT) return PM3_ESOFT; + if (ul_auth_select(&card, tagtype, has_auth_key, authkeyptr, pack, sizeof(pack)) == PM3_ESOFT) { + return PM3_ESOFT; + } // test pwd gen B num_to_bytes(ul_ev1_pwdgenB(card.uid), 4, key); len = ulev1_requestAuthentication(key, pack, sizeof(pack)); if (len > -1) { - PrintAndLogEx(SUCCESS, "Found a default password: " _GREEN_("%s") " || Pack: %02X %02X", sprint_hex(key, 4), pack[0], pack[1]); + PrintAndLogEx(SUCCESS, "Found a default password: " _GREEN_("%s") " Pack: %02X %02X", sprint_hex(key, 4), pack[0], pack[1]); goto out; } - if (ul_auth_select(&card, tagtype, hasAuthKey, authkeyptr, pack, sizeof(pack)) == PM3_ESOFT) return PM3_ESOFT; + if (ul_auth_select(&card, tagtype, has_auth_key, authkeyptr, pack, sizeof(pack)) == PM3_ESOFT) { + return PM3_ESOFT; + } // test pwd gen C num_to_bytes(ul_ev1_pwdgenC(card.uid), 4, key); len = ulev1_requestAuthentication(key, pack, sizeof(pack)); if (len > -1) { - PrintAndLogEx(SUCCESS, "Found a default password: " _GREEN_("%s") " || Pack: %02X %02X", sprint_hex(key, 4), pack[0], pack[1]); + PrintAndLogEx(SUCCESS, "Found a default password: " _GREEN_("%s") " Pack: %02X %02X", sprint_hex(key, 4), pack[0], pack[1]); goto out; } - if (ul_auth_select(&card, tagtype, hasAuthKey, authkeyptr, pack, sizeof(pack)) == PM3_ESOFT) return PM3_ESOFT; + if (ul_auth_select(&card, tagtype, has_auth_key, authkeyptr, pack, sizeof(pack)) == PM3_ESOFT) { + return PM3_ESOFT; + } // test pwd gen D num_to_bytes(ul_ev1_pwdgenD(card.uid), 4, key); len = ulev1_requestAuthentication(key, pack, sizeof(pack)); if (len > -1) { - PrintAndLogEx(SUCCESS, "Found a default password:" _GREEN_("%s") " || Pack: %02X %02X", sprint_hex(key, 4), pack[0], pack[1]); + PrintAndLogEx(SUCCESS, "Found a default password:" _GREEN_("%s") " Pack: %02X %02X", sprint_hex(key, 4), pack[0], pack[1]); goto out; } - if (ul_auth_select(&card, tagtype, hasAuthKey, authkeyptr, pack, sizeof(pack)) == PM3_ESOFT) return PM3_ESOFT; + if (ul_auth_select(&card, tagtype, has_auth_key, authkeyptr, pack, sizeof(pack)) == PM3_ESOFT) { + return PM3_ESOFT; + } for (uint8_t i = 0; i < ARRAYLEN(default_pwd_pack); ++i) { key = default_pwd_pack[i]; len = ulev1_requestAuthentication(key, pack, sizeof(pack)); if (len > -1) { - PrintAndLogEx(SUCCESS, "Found a default password: " _GREEN_("%s") " || Pack: %02X %02X", sprint_hex(key, 4), pack[0], pack[1]); + PrintAndLogEx(SUCCESS, "Found a default password: " _GREEN_("%s") " Pack: %02X %02X", sprint_hex(key, 4), pack[0], pack[1]); break; } else { - if (ul_auth_select(&card, tagtype, hasAuthKey, authkeyptr, pack, sizeof(pack)) == PM3_ESOFT) return PM3_ESOFT; + if (ul_auth_select(&card, tagtype, has_auth_key, authkeyptr, pack, sizeof(pack)) == PM3_ESOFT) { + return PM3_ESOFT; + } } } if (len < 1) { @@ -1492,7 +1546,7 @@ static int CmdHF14AMfUInfo(const char *Cmd) { out: DropField(); if (locked) { - PrintAndLogEx(INFO, "\nTag appears to be locked, try using the key to get more info"); + PrintAndLogEx(INFO, "\nTag appears to be locked, try using a key to get more info"); PrintAndLogEx(HINT, "Hint: try " _YELLOW_("`hf mfu pwdgen r`") " to get see known pwd gen algo suggestions"); } PrintAndLogEx(NORMAL, ""); @@ -2709,7 +2763,6 @@ static int CmdHF14AMfUGenDiverseKeys(const char *Cmd) { uint8_t dkeyB[8] = { 0x00 }; uint8_t masterkey[] = { 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff }; - uint8_t mix[8] = { 0x00 }; uint8_t divkey[8] = { 0x00 }; @@ -2774,6 +2827,20 @@ static int CmdHF14AMfUGenDiverseKeys(const char *Cmd) { PrintAndLogEx(SUCCESS, "Mifare Pwd :\t %s", sprint_hex(newpwd, sizeof(newpwd))); mbedtls_des3_free(&ctx); + + mbedtls_aes_context ctx_aes; + uint8_t aes_iv[16] = { 0x00 }; + uint8_t aes_masterkey[] = { 0x00, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F }; + uint8_t aes_input[16] = {0x01, 0x04, 0x2A, 0x2E, 0x19, 0x70, 0x1C, 0x80, 0x01, 0x04, 0x2A, 0x2E, 0x19, 0x70, 0x1C, 0x80}; + uint8_t aes_output[16] = {0x00}; + mbedtls_aes_setkey_enc(&ctx_aes, aes_masterkey, 128); + mbedtls_aes_crypt_cbc(&ctx_aes, MBEDTLS_AES_ENCRYPT, 16, aes_iv, aes_input, aes_output); + mbedtls_aes_free(&ctx_aes); + + PrintAndLogEx(SUCCESS, "\n-- AES version"); + PrintAndLogEx(SUCCESS, "Mifare AES m :\t %s", sprint_hex(aes_masterkey, sizeof(aes_masterkey))); + PrintAndLogEx(SUCCESS, "Mifare Div :\t %s", sprint_hex(aes_output, sizeof(aes_output))); + // next. from the diversify_key method. return PM3_SUCCESS; } diff --git a/client/src/cmdhfmfu.h b/client/src/cmdhfmfu.h index d59389434..e3eae9e79 100644 --- a/client/src/cmdhfmfu.h +++ b/client/src/cmdhfmfu.h @@ -59,6 +59,9 @@ typedef enum TAGTYPE_UL { UL_NANO_40 = 0x2000000, NTAG_213_TT = 0x4000000, NTAG_213_C = 0x8000000, + MAGIC_1A = 0x10000000 | MAGIC, + MAGIC_1B = 0x20000000 | MAGIC, + MAGIC_NTAG = 0x40000000 | MAGIC, UL_MAGIC = UL | MAGIC, UL_C_MAGIC = UL_C | MAGIC, UL_ERROR = 0xFFFFFF, From 9b3bc551368bf126e03f504d695518afbf188bca Mon Sep 17 00:00:00 2001 From: tharexde Date: Tue, 29 Dec 2020 17:40:18 +0100 Subject: [PATCH 232/682] aa --- armsrc/em4x50.c | 132 ++++++++++++++++++++++++--------------- client/src/cmdlfem4x50.c | 96 ++++++++++++++++++++++++++-- include/em4x50.h | 5 +- 3 files changed, 178 insertions(+), 55 deletions(-) diff --git a/armsrc/em4x50.c b/armsrc/em4x50.c index a84a911c5..b03872bea 100644 --- a/armsrc/em4x50.c +++ b/armsrc/em4x50.c @@ -62,6 +62,26 @@ static void wait_timer(uint32_t period) { while (AT91C_BASE_TC0->TC_CV < period); } +static void catch_samples(void) { + + uint8_t sample = 0; + + if (EM4X50_MAX_NO_SAMPLES > CARD_MEMORY_SIZE) { + Dbprintf("exeeded emulator memory size"); + return; + } + + uint8_t *em4x50_sample_buffer = BigBuf_get_addr(); + + memcpy(em4x50_sample_buffer, &gHigh, 1); + memcpy(em4x50_sample_buffer + 1, &gLow, 1); + + for (int i = 2; i < EM4X50_MAX_NO_SAMPLES + 2; i++) { + sample = AT91C_BASE_SSC->SSC_RHR; + memcpy(em4x50_sample_buffer + i, &sample, 1); + wait_timer(T0); // 8µs delay + } +} // extract and check parities // return result of parity check and extracted plain data @@ -242,11 +262,13 @@ static bool invalid_bit(void) { // get sample at 3/4 of bit period wait_timer(T0 * EM4X50_T_TAG_THREE_QUARTER_PERIOD); + //wait_timer(T0 * EM4X50_T_TAG_HALF_PERIOD); uint8_t sample = (uint8_t)AT91C_BASE_SSC->SSC_RHR; // wait until end of bit period wait_timer(T0 * EM4X50_T_TAG_QUARTER_PERIOD); + //wait_timer(T0 * EM4X50_T_TAG_HALF_PERIOD); // bit in "undefined" state? if (sample <= gHigh && sample >= gLow) @@ -422,6 +444,8 @@ static int find_double_listen_window(bool bcommand) { // skip the next bit... wait_timer(T0 * EM4X50_T_TAG_FULL_PERIOD); + catch_samples(); + break; // ...and check if the following bit does make sense // (if not it is the correct position within the second @@ -723,24 +747,11 @@ static bool em4x50_sim_send_word(uint32_t word) { static bool em4x50_sim_send_listen_window(void) { - bool cond = false; uint16_t check = 0; - uint32_t tval1[5 * EM4X50_T_TAG_FULL_PERIOD] = {0}; - uint32_t tval2[5 * EM4X50_T_TAG_FULL_PERIOD] = {0}; - - StartTicks(); for (int t = 0; t < 5 * EM4X50_T_TAG_FULL_PERIOD; t++) { - cond = ((t >= 3 * EM4X50_T_TAG_FULL_PERIOD) && (t < 4 * EM4X50_T_TAG_FULL_PERIOD)); - // wait until SSC_CLK goes HIGH - if (cond) { - AT91C_BASE_TC1->TC_CCR = AT91C_TC_SWTRG; - AT91C_BASE_TC0->TC_CCR = AT91C_TC_SWTRG; - while (AT91C_BASE_TC0->TC_CV > 0); - } - while (!(AT91C_BASE_PIOA->PIO_PDSR & GPIO_SSC_CLK)) { WDT_HIT(); @@ -751,8 +762,6 @@ static bool em4x50_sim_send_listen_window(void) { } ++check; } - if (cond) - tval1[t] = GetTicks(); if (t >= 4 * EM4X50_T_TAG_FULL_PERIOD) SHORT_COIL(); @@ -768,12 +777,6 @@ static bool em4x50_sim_send_listen_window(void) { check = 0; // wait until SSC_CLK goes LOW - if (cond) { - AT91C_BASE_TC1->TC_CCR = AT91C_TC_SWTRG; - AT91C_BASE_TC0->TC_CCR = AT91C_TC_SWTRG; - while (AT91C_BASE_TC0->TC_CV > 0); - } - while (AT91C_BASE_PIOA->PIO_PDSR & GPIO_SSC_CLK) { WDT_HIT(); if (check == 1000) { @@ -783,15 +786,7 @@ static bool em4x50_sim_send_listen_window(void) { } ++check; } - if (cond) - tval2[t] = GetTicks(); } - - for (int t = 0; t < 5 * EM4X50_T_TAG_FULL_PERIOD; t++) { - //if (tval[t] > 4) - Dbprintf("%3i probably RM intialization found: delta = %i %i", t, tval1[t], tval2[t]); - } - Dbprintf(""); return true; } @@ -1315,33 +1310,72 @@ void em4x50_test(em4x50_test_t *ett) { int status = PM3_EFAILED; - em4x50_setup_read(); + // set field on or off + if (ett->field != -1) { + em4x50_setup_read(); + if (ett->field == 1) { + LED_A_ON(); + } else { + HIGH(GPIO_SSC_DOUT); + LED_A_OFF(); + } + status = ett->field; + } - if (ett->field) { - LOW(GPIO_SSC_DOUT); - LED_A_ON(); + // check field status + if (ett->check_field) { + em4x50_setup_sim(); + bool field_on = false; + while (BUTTON_PRESS() == false) { - if (DBGLEVEL >= DBG_DEBUG) - Dbprintf("switched field on"); - + if (!(AT91C_BASE_PIOA->PIO_PDSR & GPIO_SSC_CLK)) { + if (field_on == false) { + Dbprintf("field on"); + field_on = true; + } + } else if (AT91C_BASE_PIOA->PIO_PDSR & GPIO_SSC_CLK){ + if (field_on == true) { + Dbprintf("field off"); + field_on = false; + } + } + } status = 1; - } else { - HIGH(GPIO_SSC_DOUT); - LED_A_OFF(); - - if (DBGLEVEL >= DBG_DEBUG) - Dbprintf("switched field off"); - - status = 0; } - while (BUTTON_PRESS() == false) { + // timing values + if (ett->cycles != 0) { + uint32_t tval = 0; + uint32_t tvalhigh[ett->cycles]; + uint32_t tvallow[ett->cycles]; - if (AT91C_BASE_PIOA->PIO_PDSR & GPIO_SSC_CLK) { - Dbprintf("field on"); - } else if (!(AT91C_BASE_PIOA->PIO_PDSR & GPIO_SSC_CLK)){ - Dbprintf("field on"); + em4x50_setup_sim(); + AT91C_BASE_PMC->PMC_PCER |= (1 << AT91C_ID_TC0); + AT91C_BASE_PIOA->PIO_BSR = GPIO_SSC_FRAME; + AT91C_BASE_TC0->TC_CCR = AT91C_TC_CLKDIS; + AT91C_BASE_TC0->TC_CMR = AT91C_TC_CLKS_TIMER_DIV1_CLOCK; + AT91C_BASE_TC0->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG; + while (AT91C_BASE_TC0->TC_CV > 0); + + for (int t = 0; t < ett->cycles; t++) { + + // field on -> high value + AT91C_BASE_TC0->TC_CCR = AT91C_TC_SWTRG; + tval = AT91C_BASE_TC0->TC_CV; + while (!(AT91C_BASE_PIOA->PIO_PDSR & GPIO_SSC_CLK)); + tvalhigh[t] = AT91C_BASE_TC0->TC_CV - tval; + + // filed off -> zero value + AT91C_BASE_TC0->TC_CCR = AT91C_TC_SWTRG; + tval = AT91C_BASE_TC0->TC_CV; + while (AT91C_BASE_PIOA->PIO_PDSR & GPIO_SSC_CLK); + tvallow[t] = AT91C_BASE_TC0->TC_CV - tval; } + + for (int t = 0; t < ett->cycles; t++) { + Dbprintf("%03i %li %li", t, tvallow[t], tvalhigh[t]); + } + } reply_ng(CMD_LF_EM4X50_TEST, status, NULL, 0); diff --git a/client/src/cmdlfem4x50.c b/client/src/cmdlfem4x50.c index 8182a822f..a3da00bcc 100644 --- a/client/src/cmdlfem4x50.c +++ b/client/src/cmdlfem4x50.c @@ -23,6 +23,61 @@ static int CmdHelp(const char *Cmd); +static void write_gnuplot_config_file(int gHigh, int gLow) { + + const char *fn = "../data/data.gnu"; + FILE *fp = NULL; + + if ((fp = fopen(fn, "w+")) == false) { + PrintAndLogEx(WARNING, "Fail, open file %s", fn); + } + + fprintf(fp, "set term qt size 1400, 350 enhanced\n"); + fprintf(fp, "set border 31 front linecolor rgb 'dark-grey' linewidth 1.000 dashtype solid\n"); + fprintf(fp, "set xtics 0, 1 textcolor rgb 'dark-grey'\n"); + fprintf(fp, "set ytics 0, 64 textcolor rgb 'dark-grey'\n"); + fprintf(fp, "set title 'EM4x50 signal (amplitude vs time)'\n"); + fprintf(fp, "set title font ',14' textcolor rgb 'white'\n"); + fprintf(fp, "set xlabel 'time / ms'\n"); + fprintf(fp, "set xlabel font ',12' textcolor rgb 'dark-grey'\n"); + fprintf(fp, "set ylabel 'amplitude'\n"); + fprintf(fp, "set ylabel font ',12' textcolor rgb 'dark-grey'\n"); + fprintf(fp, "set key textcolor 'green'\n"); + fprintf(fp, "set grid\n"); + fprintf(fp, "#set time textcolor 'dark-grey'\n"); + fprintf(fp, "plot [0:][-50:300] '../data/data.dat' u ($1/1000):2 w l linecolor 'green' title '500/4', '../data/data.dat' u ($1/1000):3 w l linecolor 'yellow' title 'gHigh = %i', '../data/data.dat' u ($1/1000):4 w l linecolor 'yellow' title 'gLow = %i'\n", gHigh, gLow); + fprintf(fp, "pause -1\n"); + + fclose(fp); +} + +static void get_samples(void) { + + int gHigh = 0, gLow = 0; + const char *fn = "../data/data.dat"; + FILE *fp = NULL; + + // download from BigBuf memory + uint8_t data[EM4X50_MAX_NO_SAMPLES + 2] = {0x0}; + if (GetFromDevice(BIG_BUF, data, EM4X50_MAX_NO_SAMPLES + 2, 0, NULL, 0, NULL, 2500, false) == false) { + PrintAndLogEx(WARNING, "Fail, transfer from device time-out"); + } + + if ((fp = fopen(fn, "w+")) == false) { + PrintAndLogEx(WARNING, "Fail, open file %s", fn); + } + + gHigh = data[0]; + gLow = data[1]; + for (int i = 2; i < EM4X50_MAX_NO_SAMPLES + 2; i++) { + fprintf(fp, "%i %i %i %i\n", (i - 2) * 8, data[i], gHigh, gLow); + } + + fclose(fp); + + write_gnuplot_config_file(gHigh, gLow); +} + static void prepare_result(const uint8_t *data, int fwr, int lwr, em4x50_word_t *words) { // restructure received result in "em4x50_word_t" structure @@ -612,6 +667,8 @@ int CmdEM4x50Read(const char *Cmd) { } } + get_samples(); + return em4x50_read(&etd, NULL); } @@ -1162,19 +1219,43 @@ int CmdEM4x50Test(const char *Cmd) { CLIParserContext *ctx; CLIParserInit(&ctx, "lf em 4x50 test", "perform EM4x50 tests.", - "lf em 4x50 test --field 1 -> reader field on \n" + "lf em 4x50 test --field on -> reader field on\n" + "lf em 4x50 test --field off -> reader field off\n" + "lf em 4x50 test --check -> check on/off status of reader field\n" + "lf em 4x50 test --cycles 100 -> measure time of 100 field cycles\n" ); void *argtable[] = { arg_param_begin, - arg_lit0("", "field", "field off/on"), + arg_str0(NULL, "field", "on/off", "field on/off"), + arg_lit0(NULL, "check", "check if field is on or off"), + arg_int0(NULL, "cycles", "", "number of field cycles"), arg_param_end }; CLIExecWithReturn(ctx, Cmd, argtable, true); - em4x50_test_t ett; - ett.field = arg_get_lit(ctx, 1); + // option: field + int slen = 0; + char format[3] = {0}; + CLIParamStrToBuf(arg_get_str(ctx, 1), (uint8_t *)format, sizeof(format), &slen); + em4x50_test_t ett = {.field = -1}; + if (slen != 0) { + if (strcmp(format, "on") == 0) { + ett.field = 1; + } else if (strcmp(format, "off") == 0) { + ett.field = 0; + } else { + PrintAndLogEx(INFO, "Unknown option for --field: %s", format); + return PM3_ESOFT; + } + } + + // option: check_field + ett.check_field = arg_get_lit(ctx, 2); + // option: cycles + ett.cycles = arg_get_int_def(ctx, 3, 0); + CLIParserFree(ctx); // start @@ -1185,9 +1266,14 @@ int CmdEM4x50Test(const char *Cmd) { // print response if (resp.status == 1) { - PrintAndLogEx(SUCCESS, "Field switched " _GREEN_("on")); + if (ett.field == 1) + PrintAndLogEx(SUCCESS, "Field switched " _GREEN_("on")); + if (ett.check_field == 1) + PrintAndLogEx(SUCCESS, "Field status evaluated"); } else if (resp.status == 0) { PrintAndLogEx(SUCCESS, "Field switched " _GREEN_("off")); + } else if (resp.status == -1) { + PrintAndLogEx(INFO, "Nothing done"); } else { PrintAndLogEx(FAILED, "Test call " _RED_("failed")); } diff --git a/include/em4x50.h b/include/em4x50.h index 27d71e661..3308a371f 100644 --- a/include/em4x50.h +++ b/include/em4x50.h @@ -36,6 +36,7 @@ // misc #define TIMEOUT 2000 #define DUMP_FILESIZE 136 +#define EM4X50_MAX_NO_SAMPLES 1000 typedef struct { bool addr_given; @@ -47,7 +48,9 @@ typedef struct { } PACKED em4x50_data_t; typedef struct { - bool field; + bool check_field; + int field; + int cycles; } PACKED em4x50_test_t; typedef struct { From 9c43f8e44f379dd5f244f0bbaa3a2730d8d61276 Mon Sep 17 00:00:00 2001 From: gator96100 Date: Tue, 29 Dec 2020 17:50:43 +0100 Subject: [PATCH 233/682] Updated wsl instructions --- .../Windows-Installation-Instructions.md | 39 ++++++++++++------- 1 file changed, 26 insertions(+), 13 deletions(-) diff --git a/doc/md/Installation_Instructions/Windows-Installation-Instructions.md b/doc/md/Installation_Instructions/Windows-Installation-Instructions.md index ea0505268..6d4477de2 100644 --- a/doc/md/Installation_Instructions/Windows-Installation-Instructions.md +++ b/doc/md/Installation_Instructions/Windows-Installation-Instructions.md @@ -149,18 +149,31 @@ Note that it may take a quite long time for a freshly plugged Proxmark3 to be vi Now you're ready to follow the [compilation instructions](/doc/md/Use_of_Proxmark/0_Compilation-Instructions.md). -## Color text on windows 10 -In later versions of windows 10 you may be able to get color to work by setting this registry key -``` -[HKEY_CURRENT_USER\Console] - "VirtualTerminalLevel"=dword:00000001 -``` -You also need to disable "use legacy console" in the cmd.exe properties, or set the following registry key -``` -[HKEY_CURRENT_USER\Console] - "ForceV2"=dword:00000001 -``` -After making these changes, you will need to start a new command prompt (cmd.exe) to ensure its using the new settings. -If after making these changes (and restarting proxmark3.exe) you get extra characters and no color text, set either key to 0 or enable legacy mode again (and restart the command prompt). +## (Optional) Visual Studio Code debugging +Download and install [J-Link Software and Documentation pack for Windows](https://www.segger.com/downloads/jlink/JLink_Windows.exe) + +Enter WSL prompt (`wsl` or `start windows terminal`) and from there, follow the [Linux Installation Instructions](/doc/md/Installation_Instructions/Linux-Installation-Instructions.md) for Ubuntu, summarized here below: + +Install dependencies +```sh +sudo apt-get install --no-install-recommends binutils-arm-none-eabi gdb openocd gdb-multiarch +``` + +The J-Link debugger requires `arm-none-eabi-gdb` which was replaced with `gdb-multiarch`. In order to use the J-Link debugger link `arm-none-eabi-gdb` to `gdb-multiarch`: +```sh +sudo ln -s /usr/bin/gdb-multiarch /usr/bin/arm-none-eabi-gdb +``` + +Setup the Visual Studio Code configuration, by going into your project folder and run: +```sh +./.vscode/setup.sh +``` + +and launch Visual Studio Code +```sh +code . +``` +_note_ +Please install the recommended Visual Studio Code extensions in order for debugging to work. From 800e68d9933bc084e321eed8590ef1862740bc39 Mon Sep 17 00:00:00 2001 From: gator96100 Date: Tue, 29 Dec 2020 17:54:49 +0100 Subject: [PATCH 234/682] Missing step --- .../Windows-Installation-Instructions.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/doc/md/Installation_Instructions/Windows-Installation-Instructions.md b/doc/md/Installation_Instructions/Windows-Installation-Instructions.md index 6d4477de2..1cf1f43c9 100644 --- a/doc/md/Installation_Instructions/Windows-Installation-Instructions.md +++ b/doc/md/Installation_Instructions/Windows-Installation-Instructions.md @@ -152,6 +152,8 @@ Now you're ready to follow the [compilation instructions](/doc/md/Use_of_Proxmar ## (Optional) Visual Studio Code debugging +Download and install [Visual Studio Code](https://code.visualstudio.com/) + Download and install [J-Link Software and Documentation pack for Windows](https://www.segger.com/downloads/jlink/JLink_Windows.exe) Enter WSL prompt (`wsl` or `start windows terminal`) and from there, follow the [Linux Installation Instructions](/doc/md/Installation_Instructions/Linux-Installation-Instructions.md) for Ubuntu, summarized here below: From ff4acf70059d86e0bc63a6094a719e3b8b3c06e1 Mon Sep 17 00:00:00 2001 From: Ave Date: Tue, 29 Dec 2020 20:05:50 +0300 Subject: [PATCH 235/682] emrtd: Improve comment on USA quirk workaround --- client/src/cmdhfemrtd.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/client/src/cmdhfemrtd.c b/client/src/cmdhfemrtd.c index fa9c936e9..670ea804d 100644 --- a/client/src/cmdhfemrtd.c +++ b/client/src/cmdhfemrtd.c @@ -218,9 +218,9 @@ static int emrtd_get_asn1_data_length(uint8_t *datain, int datainlen, int offset if (lenfield <= 0x7f) { return lenfield; } else if (lenfield == 0x80) { - // TODO: 0x80 means indeterminate. + // TODO: 0x80 means indeterminate, and this impl is a workaround. // Giving rest of the file is a workaround, nothing more, nothing less. - // More at https://letsencrypt.org/docs/a-warm-welcome-to-asn1-and-der/ + // https://wf.lavatech.top/ave-but-random/emrtd-data-quirks#EF_SOD return datainlen; } else if (lenfield == 0x81) { return ((int) * (datain + offset + 1)); From d1a6164a10221fd92794adf872e2d34262ab3360 Mon Sep 17 00:00:00 2001 From: gator96100 Date: Tue, 29 Dec 2020 18:08:35 +0100 Subject: [PATCH 236/682] Updated linux instructions --- .../Linux-Installation-Instructions.md | 27 ++++++++++++++++++- 1 file changed, 26 insertions(+), 1 deletion(-) diff --git a/doc/md/Installation_Instructions/Linux-Installation-Instructions.md b/doc/md/Installation_Instructions/Linux-Installation-Instructions.md index 18164398a..aa5cf9042 100644 --- a/doc/md/Installation_Instructions/Linux-Installation-Instructions.md +++ b/doc/md/Installation_Instructions/Linux-Installation-Instructions.md @@ -25,13 +25,16 @@ Install the requirements ```sh sudo apt-get install --no-install-recommends git ca-certificates build-essential pkg-config \ -libreadline-dev gcc-arm-none-eabi libnewlib-dev qtbase5-dev libbz2-dev libbluetooth-dev +libreadline-dev gcc-arm-none-eabi libnewlib-dev qtbase5-dev libbz2-dev libbluetooth-dev \ +binutils-arm-none-eabi gdb openocd gdb-multiarch ``` If you don't need the native Bluetooth support in the client, you can skip the installation of `libbluetooth-dev`. If you don't need the graphical components of the Proxmark3 client (such as in `hw tune`), you can skip the installation of `qtbase5-dev`. +If you don't need the debugging packages, you can skip the installation of `binutils-arm-none-eabi`,`gdb`,`openocd` and `gdb-multiarch`. + If you get some (non blocking) error at runtime such as _Gtk-Message: Failed to load module "canberra-gtk-module"_ you may have to install `libcanberra-gtk-module`. ## On ArchLinux @@ -112,3 +115,25 @@ It must return `ok`. Otherwise this means you've got a permission problem to fix # Compile and use the project Now you're ready to follow the [compilation instructions](/doc/md/Use_of_Proxmark/0_Compilation-Instructions.md). + + +## (Optional) Visual Studio Code debugging + +Download and install [Visual Studio Code](https://code.visualstudio.com/) + +Download and install [J-Link Software and Documentation pack](https://www.segger.com/downloads/jlink) + +On some systems `arm-none-eabi-gdb` was replaced with `gdb-multiarch`. In order to use the J-Link debugger you need to link `arm-none-eabi-gdb` to `gdb-multiarch`: +```sh +ln -s /usr/bin/gdb-multiarch /usr/bin/arm-none-eabi-gdb +``` + +Setup the Visual Studio Code configuration, by going into your project folder and run: +```sh +./.vscode/setup.sh +``` + +now launch Visual Studio Code and open your project folder + +_note_ +Please install the recommended Visual Studio Code extensions in order for debugging to work. From c58b1043b8ca8b9dfb0a0c80ed5ac917502a4cea Mon Sep 17 00:00:00 2001 From: gator96100 Date: Tue, 29 Dec 2020 18:15:09 +0100 Subject: [PATCH 237/682] Make setup executable --- .vscode/setup.sh | 0 1 file changed, 0 insertions(+), 0 deletions(-) mode change 100644 => 100755 .vscode/setup.sh diff --git a/.vscode/setup.sh b/.vscode/setup.sh old mode 100644 new mode 100755 From cc2b36430dece96f66d0f877ccb55f55fc328d77 Mon Sep 17 00:00:00 2001 From: gator96100 Date: Tue, 29 Dec 2020 18:26:51 +0100 Subject: [PATCH 238/682] Fixed removing all variables --- .vscode/setup.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.vscode/setup.sh b/.vscode/setup.sh index 93f7144f2..3e76e03ae 100755 --- a/.vscode/setup.sh +++ b/.vscode/setup.sh @@ -79,7 +79,7 @@ function setup_wsl { setup_gdb_linux setup_jlink_wsl cp "$VSCODEPATH/templates/tasks_wsl.json" "$VSCODEPATH/tasks.json" - envsubst <"$VSCODEPATH/templates/launch_wsl.json" > "$VSCODEPATH/launch.json" + envsubst '${SerialPort} ${DebuggerPath} ${JLinkServerPath} ${DeviceMem}' <"$VSCODEPATH/templates/launch_wsl.json" > "$VSCODEPATH/launch.json" } function setup_linux { @@ -87,7 +87,7 @@ function setup_linux { setup_gdb_linux setup_jlink_linux cp "$VSCODEPATH/templates/tasks_linux.json" "$VSCODEPATH/tasks.json" - envsubst <"$VSCODEPATH/templates/launch_linux.json" > "$VSCODEPATH/launch.json" + envsubst '${SerialPort} ${DebuggerPath} ${JLinkServerPath} ${DeviceMem}' <"$VSCODEPATH/templates/launch_linux.json" > "$VSCODEPATH/launch.json" } function setup_ps { From 7c982c7785bbfe45b6d5b783fd5b3e7e04c127fb Mon Sep 17 00:00:00 2001 From: gator96100 Date: Tue, 29 Dec 2020 18:32:22 +0100 Subject: [PATCH 239/682] Print config --- .vscode/setup.sh | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/.vscode/setup.sh b/.vscode/setup.sh index 3e76e03ae..1cfd3b9b6 100755 --- a/.vscode/setup.sh +++ b/.vscode/setup.sh @@ -30,6 +30,13 @@ export DeviceMem="512" VSCODEPATH=$(dirname "$0") +function print_config { + echo "Updating with following configuration:" + echo "SerialPort: $SerialPort" + echo "DebuggerPath: $DebuggerPath" + echo "JLinkServerPath: $JLinkServerPath" +} + function setup_serial_port { if [ -z "$SerialPort" ]; then pm3list=$($VSCODEPATH/../pm3 --list 2>/dev/null) @@ -40,7 +47,6 @@ function setup_serial_port { exit 1 fi fi - echo "Using $SerialPort as port" } function setup_gdb_linux { @@ -78,6 +84,7 @@ function setup_wsl { setup_serial_port setup_gdb_linux setup_jlink_wsl + print_config cp "$VSCODEPATH/templates/tasks_wsl.json" "$VSCODEPATH/tasks.json" envsubst '${SerialPort} ${DebuggerPath} ${JLinkServerPath} ${DeviceMem}' <"$VSCODEPATH/templates/launch_wsl.json" > "$VSCODEPATH/launch.json" } @@ -86,6 +93,7 @@ function setup_linux { setup_serial_port setup_gdb_linux setup_jlink_linux + print_config cp "$VSCODEPATH/templates/tasks_linux.json" "$VSCODEPATH/tasks.json" envsubst '${SerialPort} ${DebuggerPath} ${JLinkServerPath} ${DeviceMem}' <"$VSCODEPATH/templates/launch_linux.json" > "$VSCODEPATH/launch.json" } @@ -95,6 +103,7 @@ function setup_ps { if [ -z "$JLinkServerPath" ]; then export JLinkServerPath="c/Program Files (x86)/SEGGER/JLink/JLinkGDBServerCL.exe" fi + print_config } if [ -f "$VSCODEPATH/launch.json" ] || [ -f "$VSCODEPATH/tasks.json" ]; then From a103628a351f84521e82521185f8edd18e84612d Mon Sep 17 00:00:00 2001 From: gator96100 Date: Tue, 29 Dec 2020 20:43:24 +0100 Subject: [PATCH 240/682] ProxSpace debugging --- .gitignore | 3 +- .vscode/setup.sh | 32 +++-- .vscode/tasks.json | 102 ++++++++++++++++ .vscode/templates/launch_linux.json | 2 +- .vscode/templates/launch_ps.json | 11 +- .vscode/templates/launch_wsl.json | 2 +- .vscode/templates/tasks_linux.json | 177 ---------------------------- .vscode/templates/tasks_ps.json | 177 ---------------------------- .vscode/templates/tasks_wsl.json | 177 ---------------------------- 9 files changed, 135 insertions(+), 548 deletions(-) create mode 100644 .vscode/tasks.json delete mode 100644 .vscode/templates/tasks_linux.json delete mode 100644 .vscode/templates/tasks_ps.json delete mode 100644 .vscode/templates/tasks_wsl.json diff --git a/.gitignore b/.gitignore index 125dc536e..e1f694327 100644 --- a/.gitignore +++ b/.gitignore @@ -111,4 +111,5 @@ fpga_version_info.c #VSCode files !.vscode/templates/*.json -!.vscode/extensions.json \ No newline at end of file +!.vscode/extensions.json +!.vscode/tasks.json \ No newline at end of file diff --git a/.vscode/setup.sh b/.vscode/setup.sh index 1cfd3b9b6..1dc3b5237 100755 --- a/.vscode/setup.sh +++ b/.vscode/setup.sh @@ -21,7 +21,7 @@ ############################### #export SerialPort="COM5" #export DebuggerPath="${workspaceFolder}/../../msys2/mingw64/bin/gdb.exe" -#export JLinkServerPath="c/Program Files (x86)/SEGGER/JLink/JLinkGDBServerCL.exe" +#export JLinkServerPath="/c/Program Files (x86)/SEGGER/JLink/JLinkGDBServerCL.exe" #Debugging on 256KB systems is not recommended #This option does not override PLATFORM_SIZE @@ -59,6 +59,12 @@ function setup_gdb_linux { fi } +function setup_gdb_ps { + if [ -z "$DebuggerPath" ]; then + export DebuggerPath="${workspaceFolder}/../../msys2/mingw64/bin/gdb.exe" + fi +} + function setup_jlink_linux { if [ -z "$JLinkServerPath" ]; then export JLinkServerPath="/opt/SEGGER/JLink/JLinkGDBServerCLExe" @@ -75,7 +81,17 @@ function setup_jlink_wsl { export JLinkServerPath="/mnt/c/Program Files (x86)/SEGGER/JLink/JLinkGDBServerCL.exe" fi if [ ! -x "$JLinkServerPath" ]; then - echo >&2 "[!!] JLinkGDBServerCLExe not found, please set JLinkServerPath manually" + echo >&2 "[!!] JLinkGDBServerCL.exe not found, please set JLinkServerPath manually" + exit 1 + fi +} + +function setup_jlink_ps { + if [ -z "$JLinkServerPath" ]; then + export JLinkServerPath="/c/Program Files (x86)/SEGGER/JLink/JLinkGDBServerCL.exe" + fi + if [ ! -x "$JLinkServerPath" ]; then + echo >&2 "[!!] JLinkGDBServerCL.exe not found, please set JLinkServerPath manually" exit 1 fi } @@ -85,7 +101,6 @@ function setup_wsl { setup_gdb_linux setup_jlink_wsl print_config - cp "$VSCODEPATH/templates/tasks_wsl.json" "$VSCODEPATH/tasks.json" envsubst '${SerialPort} ${DebuggerPath} ${JLinkServerPath} ${DeviceMem}' <"$VSCODEPATH/templates/launch_wsl.json" > "$VSCODEPATH/launch.json" } @@ -94,26 +109,23 @@ function setup_linux { setup_gdb_linux setup_jlink_linux print_config - cp "$VSCODEPATH/templates/tasks_linux.json" "$VSCODEPATH/tasks.json" envsubst '${SerialPort} ${DebuggerPath} ${JLinkServerPath} ${DeviceMem}' <"$VSCODEPATH/templates/launch_linux.json" > "$VSCODEPATH/launch.json" } function setup_ps { setup_serial_port - if [ -z "$JLinkServerPath" ]; then - export JLinkServerPath="c/Program Files (x86)/SEGGER/JLink/JLinkGDBServerCL.exe" - fi + setup_gdb_ps + setup_jlink_ps print_config + envsubst '${SerialPort} ${DebuggerPath} ${JLinkServerPath} ${DeviceMem}' <"$VSCODEPATH/templates/launch_ps.json" > "$VSCODEPATH/launch.json" } -if [ -f "$VSCODEPATH/launch.json" ] || [ -f "$VSCODEPATH/tasks.json" ]; then +if [ -f "$VSCODEPATH/launch.json" ]; then read -p "Existing configuration found, do you want to override it? " -n 1 -r if [[ $REPLY =~ ^[Yy]$ ]] then rm "$VSCODEPATH/launch.json.bak" 2> /dev/null - rm "$VSCODEPATH/tasks.json.bak" 2> /dev/null mv "$VSCODEPATH/launch.json" "$VSCODEPATH/launch.json.bak" 2> /dev/null - mv "$VSCODEPATH/tasks.json" "$VSCODEPATH/tasks.json.bak" 2> /dev/null else echo >&2 "[!!] user abort" exit 1 diff --git a/.vscode/tasks.json b/.vscode/tasks.json new file mode 100644 index 000000000..463377982 --- /dev/null +++ b/.vscode/tasks.json @@ -0,0 +1,102 @@ +{ + // See https://go.microsoft.com/fwlink/?LinkId=733558 + // for the documentation about the tasks.json format + "version": "2.0.0", + "windows": { + "options": { + "cwd": "${workspaceFolder}", + "env": { + "PATH": "${workspaceFolder}/../../msys2/mingw64/bin;${workspaceFolder}/../../msys2/usr/local/bin;${workspaceFolder}/../../msys2/usr/bin;${workspaceFolder}/../../msys2/bin", + "MSYSTEM": "MINGW64" + } + } + }, + "tasks": [ + { + "label": "all: Make & run", + "type": "shell", + "command": "make -j && ./pm3", + "problemMatcher": [ + "$gcc" + ], + "group": { + "kind": "build", + "isDefault": true + } + }, + { + "label": "choose: Make", + "type": "shell", + "command": "make ${input:componentType} -j", + "problemMatcher": [ + "$gcc" + ], + "group": "build", + }, + { + "label": "client: Debug: make", + "type": "shell", + "command": "make client -j DEBUG=1", + "problemMatcher": [ + "$gcc" + ], + "group": "build", + }, + { + "label": "client: Debug: clean & make", + "type": "shell", + "command": "make client/clean && make client -j DEBUG=1", + "problemMatcher": [ + "$gcc" + ], + "group": "build", + }, + { + "label": "fullimage: Make & Flash", + "type": "shell", + "command": "make fullimage && ./pm3-flash-fullimage", + "problemMatcher": [] + }, + { + "label": "BOOTROM: Make & Flash", + "type": "shell", + "command": "make bootrom && ./pm3-flash-bootrom", + "problemMatcher": [] + }, + { + "label": "Run client", + "type": "shell", + "command": "./pm3", + "problemMatcher": [] + },{ + "label": "fullimage: clean & make debug", + "type": "shell", + "command": "make armsrc/clean && make armsrc/all SKIP_COMPRESSION=1 DEBUG=1", + "problemMatcher": [ + "$gcc" + ], + "group": "build", + } + ], + "inputs": [ + { + "type": "pickString", + "id": "componentType", + "description": "What Makefile target do you want to execute?", + "options": [ + "all", + "client", + "bootrom", + "fullimage", + "recovery", + "clean", + "install", + "uninstall", + "style", + "miscchecks", + "check", + ], + "default": "all" + } + ] +} \ No newline at end of file diff --git a/.vscode/templates/launch_linux.json b/.vscode/templates/launch_linux.json index 0f60495a6..5239c6bda 100644 --- a/.vscode/templates/launch_linux.json +++ b/.vscode/templates/launch_linux.json @@ -44,7 +44,7 @@ "type": "cortex-debug", "request": "launch", "cwd": "${workspaceRoot}", - "preLaunchTask": "fullimage: clean & make", + "preLaunchTask": "fullimage: clean & make debug", "executable": "${workspaceRoot}/armsrc/obj/fullimage.elf", "serverpath": "${JLinkServerPath}", "servertype": "jlink", diff --git a/.vscode/templates/launch_ps.json b/.vscode/templates/launch_ps.json index 8794ef76e..28b724f7b 100644 --- a/.vscode/templates/launch_ps.json +++ b/.vscode/templates/launch_ps.json @@ -3,6 +3,13 @@ // Hover to view descriptions of existing attributes. // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 "version": "0.2.0", + "options": { + "cwd": "${workspaceFolder}", + "env": { + "PATH": "${workspaceFolder}/../../msys2/mingw64/bin;${workspaceFolder}/../../msys2/usr/local/bin;${workspaceFolder}/../../msys2/usr/bin;${workspaceFolder}/../../msys2/bin", + "MSYSTEM": "MINGW64" + } + }, "configurations": [ { "name": "Client: (gdb) Build & Launch", @@ -11,10 +18,6 @@ "program": "${cwd}/client/proxmark3", "args": ["${SerialPort}"], "stopAtEntry": false, - "cwd": "${workspaceFolder}", - "environment": [ - "name": "PATH","value": "${workspaceFolder}/../../msys2/mingw64/bin;${workspaceFolder}/../../msys2/usr/local/bin;${workspaceFolder}/../../msys2/usr/bin;${workspaceFolder}/../../msys2/bin" - ], "externalConsole": true,//for ProxSpace externalConsole=true is required, because the internal cosole stops updating after a while "MIMode": "gdb", "setupCommands": [ diff --git a/.vscode/templates/launch_wsl.json b/.vscode/templates/launch_wsl.json index 0f60495a6..5239c6bda 100644 --- a/.vscode/templates/launch_wsl.json +++ b/.vscode/templates/launch_wsl.json @@ -44,7 +44,7 @@ "type": "cortex-debug", "request": "launch", "cwd": "${workspaceRoot}", - "preLaunchTask": "fullimage: clean & make", + "preLaunchTask": "fullimage: clean & make debug", "executable": "${workspaceRoot}/armsrc/obj/fullimage.elf", "serverpath": "${JLinkServerPath}", "servertype": "jlink", diff --git a/.vscode/templates/tasks_linux.json b/.vscode/templates/tasks_linux.json deleted file mode 100644 index 4cc21841d..000000000 --- a/.vscode/templates/tasks_linux.json +++ /dev/null @@ -1,177 +0,0 @@ -{ - // See https://go.microsoft.com/fwlink/?LinkId=733558 - // for the documentation about the tasks.json format - "version": "2.0.0", - "tasks": [ - { - "label": "all: Make & run", - "type": "shell", - "command": "make -j && ./pm3", - "windows": { - "options": { - "cwd": "${workspaceFolder}/../..", - "shell": { - "executable": "${workspaceFolder}/../../runme64.bat", - "args": [ - "-c \"cd ${workspaceFolderBasename} &&" - ], - - } - } - }, - "problemMatcher": [ - "$gcc" - ], - "group": { - "kind": "build", - "isDefault": true - } - }, - { - "label": "choose: Make", - "type": "shell", - "command": "make ${input:componentType} -j", - "windows": { - "options": { - "cwd": "${workspaceFolder}/../..", - "shell": { - "executable": "${workspaceFolder}/../../runme64.bat", - "args": [ - "-c \"cd ${workspaceFolderBasename} &&" - ], - - } - } - }, - "problemMatcher": [ - "$gcc" - ], - "group": "build", - }, - { - "label": "client: Debug: make", - "type": "shell", - "command": "make client -j DEBUG=1", - "windows": { - "options": { - "cwd": "${workspaceFolder}/../..", - "shell": { - "executable": "${workspaceFolder}/../../runme64.bat", - "args": [ - "-c \"cd ${workspaceFolderBasename} &&" - ], - - } - } - }, - "problemMatcher": [ - "$gcc" - ], - "group": "build", - }, - { - "label": "client: Debug: clean & make", - "type": "shell", - "command": "make client/clean && make client -j DEBUG=1", - "windows": { - "options": { - "cwd": "${workspaceFolder}/../..", - "shell": { - "executable": "${workspaceFolder}/../../runme64.bat", - "args": [ - "-c \"cd ${workspaceFolderBasename} &&" - ], - - } - } - }, - "problemMatcher": [ - "$gcc" - ], - "group": "build", - }, - { - "label": "fullimage: Make & Flash", - "type": "shell", - "command": "make fullimage && ./pm3-flash-fullimage", - "windows": { - "options": { - "cwd": "${workspaceFolder}/../..", - "shell": { - "executable": "${workspaceFolder}/../../runme64.bat", - "args": [ - "-c \"cd ${workspaceFolderBasename} &&" - ], - - } - } - }, - "problemMatcher": [] - }, - { - "label": "BOOTROM: Make & Flash", - "type": "shell", - "command": "make bootrom && ./pm3-flash-bootrom", - "windows": { - "options": { - "cwd": "${workspaceFolder}/../..", - "shell": { - "executable": "${workspaceFolder}/../../runme64.bat", - "args": [ - "-c \"cd ${workspaceFolderBasename} &&" - ], - - } - } - }, - "problemMatcher": [] - }, - { - "label": "Run client", - "type": "shell", - "command": "./pm3", - "windows": { - "options": { - "cwd": "${workspaceFolder}/../..", - "shell": { - "executable": "${workspaceFolder}/../../runme64.bat", - "args": [ - "-c \"cd ${workspaceFolderBasename} &&" - ], - - } - } - }, - "problemMatcher": [] - },{ - "label": "fullimage: clean & make", - "type": "shell", - "command": "make armsrc/clean && make armsrc/all SKIP_COMPRESSION=1 DEBUG=1", - "problemMatcher": [ - "$gcc" - ], - "group": "build", - } - ], - "inputs": [ - { - "type": "pickString", - "id": "componentType", - "description": "What Makefile target do you want to execute?", - "options": [ - "all", - "client", - "bootrom", - "fullimage", - "recovery", - "clean", - "install", - "uninstall", - "style", - "miscchecks", - "check", - ], - "default": "all" - } - ] -} \ No newline at end of file diff --git a/.vscode/templates/tasks_ps.json b/.vscode/templates/tasks_ps.json deleted file mode 100644 index 4cc21841d..000000000 --- a/.vscode/templates/tasks_ps.json +++ /dev/null @@ -1,177 +0,0 @@ -{ - // See https://go.microsoft.com/fwlink/?LinkId=733558 - // for the documentation about the tasks.json format - "version": "2.0.0", - "tasks": [ - { - "label": "all: Make & run", - "type": "shell", - "command": "make -j && ./pm3", - "windows": { - "options": { - "cwd": "${workspaceFolder}/../..", - "shell": { - "executable": "${workspaceFolder}/../../runme64.bat", - "args": [ - "-c \"cd ${workspaceFolderBasename} &&" - ], - - } - } - }, - "problemMatcher": [ - "$gcc" - ], - "group": { - "kind": "build", - "isDefault": true - } - }, - { - "label": "choose: Make", - "type": "shell", - "command": "make ${input:componentType} -j", - "windows": { - "options": { - "cwd": "${workspaceFolder}/../..", - "shell": { - "executable": "${workspaceFolder}/../../runme64.bat", - "args": [ - "-c \"cd ${workspaceFolderBasename} &&" - ], - - } - } - }, - "problemMatcher": [ - "$gcc" - ], - "group": "build", - }, - { - "label": "client: Debug: make", - "type": "shell", - "command": "make client -j DEBUG=1", - "windows": { - "options": { - "cwd": "${workspaceFolder}/../..", - "shell": { - "executable": "${workspaceFolder}/../../runme64.bat", - "args": [ - "-c \"cd ${workspaceFolderBasename} &&" - ], - - } - } - }, - "problemMatcher": [ - "$gcc" - ], - "group": "build", - }, - { - "label": "client: Debug: clean & make", - "type": "shell", - "command": "make client/clean && make client -j DEBUG=1", - "windows": { - "options": { - "cwd": "${workspaceFolder}/../..", - "shell": { - "executable": "${workspaceFolder}/../../runme64.bat", - "args": [ - "-c \"cd ${workspaceFolderBasename} &&" - ], - - } - } - }, - "problemMatcher": [ - "$gcc" - ], - "group": "build", - }, - { - "label": "fullimage: Make & Flash", - "type": "shell", - "command": "make fullimage && ./pm3-flash-fullimage", - "windows": { - "options": { - "cwd": "${workspaceFolder}/../..", - "shell": { - "executable": "${workspaceFolder}/../../runme64.bat", - "args": [ - "-c \"cd ${workspaceFolderBasename} &&" - ], - - } - } - }, - "problemMatcher": [] - }, - { - "label": "BOOTROM: Make & Flash", - "type": "shell", - "command": "make bootrom && ./pm3-flash-bootrom", - "windows": { - "options": { - "cwd": "${workspaceFolder}/../..", - "shell": { - "executable": "${workspaceFolder}/../../runme64.bat", - "args": [ - "-c \"cd ${workspaceFolderBasename} &&" - ], - - } - } - }, - "problemMatcher": [] - }, - { - "label": "Run client", - "type": "shell", - "command": "./pm3", - "windows": { - "options": { - "cwd": "${workspaceFolder}/../..", - "shell": { - "executable": "${workspaceFolder}/../../runme64.bat", - "args": [ - "-c \"cd ${workspaceFolderBasename} &&" - ], - - } - } - }, - "problemMatcher": [] - },{ - "label": "fullimage: clean & make", - "type": "shell", - "command": "make armsrc/clean && make armsrc/all SKIP_COMPRESSION=1 DEBUG=1", - "problemMatcher": [ - "$gcc" - ], - "group": "build", - } - ], - "inputs": [ - { - "type": "pickString", - "id": "componentType", - "description": "What Makefile target do you want to execute?", - "options": [ - "all", - "client", - "bootrom", - "fullimage", - "recovery", - "clean", - "install", - "uninstall", - "style", - "miscchecks", - "check", - ], - "default": "all" - } - ] -} \ No newline at end of file diff --git a/.vscode/templates/tasks_wsl.json b/.vscode/templates/tasks_wsl.json deleted file mode 100644 index 4cc21841d..000000000 --- a/.vscode/templates/tasks_wsl.json +++ /dev/null @@ -1,177 +0,0 @@ -{ - // See https://go.microsoft.com/fwlink/?LinkId=733558 - // for the documentation about the tasks.json format - "version": "2.0.0", - "tasks": [ - { - "label": "all: Make & run", - "type": "shell", - "command": "make -j && ./pm3", - "windows": { - "options": { - "cwd": "${workspaceFolder}/../..", - "shell": { - "executable": "${workspaceFolder}/../../runme64.bat", - "args": [ - "-c \"cd ${workspaceFolderBasename} &&" - ], - - } - } - }, - "problemMatcher": [ - "$gcc" - ], - "group": { - "kind": "build", - "isDefault": true - } - }, - { - "label": "choose: Make", - "type": "shell", - "command": "make ${input:componentType} -j", - "windows": { - "options": { - "cwd": "${workspaceFolder}/../..", - "shell": { - "executable": "${workspaceFolder}/../../runme64.bat", - "args": [ - "-c \"cd ${workspaceFolderBasename} &&" - ], - - } - } - }, - "problemMatcher": [ - "$gcc" - ], - "group": "build", - }, - { - "label": "client: Debug: make", - "type": "shell", - "command": "make client -j DEBUG=1", - "windows": { - "options": { - "cwd": "${workspaceFolder}/../..", - "shell": { - "executable": "${workspaceFolder}/../../runme64.bat", - "args": [ - "-c \"cd ${workspaceFolderBasename} &&" - ], - - } - } - }, - "problemMatcher": [ - "$gcc" - ], - "group": "build", - }, - { - "label": "client: Debug: clean & make", - "type": "shell", - "command": "make client/clean && make client -j DEBUG=1", - "windows": { - "options": { - "cwd": "${workspaceFolder}/../..", - "shell": { - "executable": "${workspaceFolder}/../../runme64.bat", - "args": [ - "-c \"cd ${workspaceFolderBasename} &&" - ], - - } - } - }, - "problemMatcher": [ - "$gcc" - ], - "group": "build", - }, - { - "label": "fullimage: Make & Flash", - "type": "shell", - "command": "make fullimage && ./pm3-flash-fullimage", - "windows": { - "options": { - "cwd": "${workspaceFolder}/../..", - "shell": { - "executable": "${workspaceFolder}/../../runme64.bat", - "args": [ - "-c \"cd ${workspaceFolderBasename} &&" - ], - - } - } - }, - "problemMatcher": [] - }, - { - "label": "BOOTROM: Make & Flash", - "type": "shell", - "command": "make bootrom && ./pm3-flash-bootrom", - "windows": { - "options": { - "cwd": "${workspaceFolder}/../..", - "shell": { - "executable": "${workspaceFolder}/../../runme64.bat", - "args": [ - "-c \"cd ${workspaceFolderBasename} &&" - ], - - } - } - }, - "problemMatcher": [] - }, - { - "label": "Run client", - "type": "shell", - "command": "./pm3", - "windows": { - "options": { - "cwd": "${workspaceFolder}/../..", - "shell": { - "executable": "${workspaceFolder}/../../runme64.bat", - "args": [ - "-c \"cd ${workspaceFolderBasename} &&" - ], - - } - } - }, - "problemMatcher": [] - },{ - "label": "fullimage: clean & make", - "type": "shell", - "command": "make armsrc/clean && make armsrc/all SKIP_COMPRESSION=1 DEBUG=1", - "problemMatcher": [ - "$gcc" - ], - "group": "build", - } - ], - "inputs": [ - { - "type": "pickString", - "id": "componentType", - "description": "What Makefile target do you want to execute?", - "options": [ - "all", - "client", - "bootrom", - "fullimage", - "recovery", - "clean", - "install", - "uninstall", - "style", - "miscchecks", - "check", - ], - "default": "all" - } - ] -} \ No newline at end of file From 7357d17c8c298042f7ac05341fa71b5d300ef4e6 Mon Sep 17 00:00:00 2001 From: gator96100 Date: Tue, 29 Dec 2020 21:02:23 +0100 Subject: [PATCH 241/682] ProxSpace path fixes --- .vscode/setup.sh | 13 +++---------- .vscode/templates/launch_ps.json | 7 ++++--- 2 files changed, 7 insertions(+), 13 deletions(-) diff --git a/.vscode/setup.sh b/.vscode/setup.sh index 1dc3b5237..3b652a6b8 100755 --- a/.vscode/setup.sh +++ b/.vscode/setup.sh @@ -20,8 +20,7 @@ # Uncomment to override # ############################### #export SerialPort="COM5" -#export DebuggerPath="${workspaceFolder}/../../msys2/mingw64/bin/gdb.exe" -#export JLinkServerPath="/c/Program Files (x86)/SEGGER/JLink/JLinkGDBServerCL.exe" +#export JLinkServerPath="C:/Program Files (x86)/SEGGER/JLink/JLinkGDBServerCL.exe" #Debugging on 256KB systems is not recommended #This option does not override PLATFORM_SIZE @@ -59,12 +58,6 @@ function setup_gdb_linux { fi } -function setup_gdb_ps { - if [ -z "$DebuggerPath" ]; then - export DebuggerPath="${workspaceFolder}/../../msys2/mingw64/bin/gdb.exe" - fi -} - function setup_jlink_linux { if [ -z "$JLinkServerPath" ]; then export JLinkServerPath="/opt/SEGGER/JLink/JLinkGDBServerCLExe" @@ -88,9 +81,9 @@ function setup_jlink_wsl { function setup_jlink_ps { if [ -z "$JLinkServerPath" ]; then - export JLinkServerPath="/c/Program Files (x86)/SEGGER/JLink/JLinkGDBServerCL.exe" + export JLinkServerPath="c:/Program Files (x86)/SEGGER/JLink/JLinkGDBServerCL.exe" fi - if [ ! -x "$JLinkServerPath" ]; then + if [ ! -x $(cygpath \"$JLinkServerPath\") ]; then echo >&2 "[!!] JLinkGDBServerCL.exe not found, please set JLinkServerPath manually" exit 1 fi diff --git a/.vscode/templates/launch_ps.json b/.vscode/templates/launch_ps.json index 28b724f7b..045b3d6c5 100644 --- a/.vscode/templates/launch_ps.json +++ b/.vscode/templates/launch_ps.json @@ -15,6 +15,7 @@ "name": "Client: (gdb) Build & Launch", "type": "cppdbg", "request": "launch", + "cwd": "${workspaceFolder}", "program": "${cwd}/client/proxmark3", "args": ["${SerialPort}"], "stopAtEntry": false, @@ -28,13 +29,13 @@ } ], "preLaunchTask": "client: Debug: clean & make", - "miDebuggerPath": "${DebuggerPath}" + "miDebuggerPath": "${workspaceFolder}/../../msys2/mingw64/bin/gdb.exe" },{ "name": "Firmware: (J-Link) Build & Launch", "type": "cortex-debug", "request": "launch", "cwd": "${workspaceRoot}", - "preLaunchTask": "fullimage: clean & make", + "preLaunchTask": "fullimage: clean & make debug", "executable": "${workspaceRoot}/armsrc/obj/fullimage.elf", "serverpath": "${JLinkServerPath}", "servertype": "jlink", @@ -42,7 +43,7 @@ "interface": "jtag", "serialNumber": "", //If you have more than one J-Link probe, add the serial number here. "runToMain": false, - "armToolchainPath": "/usr/bin/" + "armToolchainPath": "${workspaceFolder}/../../msys2/mingw64/bin" } ] } \ No newline at end of file From 3f7e9c8f8279c93a666ff8779cf5317086ce6bc8 Mon Sep 17 00:00:00 2001 From: gator96100 Date: Tue, 29 Dec 2020 21:10:16 +0100 Subject: [PATCH 242/682] Windows path check --- .vscode/setup.sh | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/.vscode/setup.sh b/.vscode/setup.sh index 3b652a6b8..cdfb77e8f 100755 --- a/.vscode/setup.sh +++ b/.vscode/setup.sh @@ -83,7 +83,8 @@ function setup_jlink_ps { if [ -z "$JLinkServerPath" ]; then export JLinkServerPath="c:/Program Files (x86)/SEGGER/JLink/JLinkGDBServerCL.exe" fi - if [ ! -x $(cygpath \"$JLinkServerPath\") ]; then + jlinkpath=$(cygpath "$JLinkServerPath") + if [ ! -x "$jlinkpath" ]; then echo >&2 "[!!] JLinkGDBServerCL.exe not found, please set JLinkServerPath manually" exit 1 fi @@ -107,10 +108,10 @@ function setup_linux { function setup_ps { setup_serial_port - setup_gdb_ps setup_jlink_ps + export DebuggerPath="Using ProxSpace gbd" print_config - envsubst '${SerialPort} ${DebuggerPath} ${JLinkServerPath} ${DeviceMem}' <"$VSCODEPATH/templates/launch_ps.json" > "$VSCODEPATH/launch.json" + envsubst '${SerialPort} ${JLinkServerPath} ${DeviceMem}' <"$VSCODEPATH/templates/launch_ps.json" > "$VSCODEPATH/launch.json" } if [ -f "$VSCODEPATH/launch.json" ]; then From c4729670b6c6c79fc968710b18a2b7a2f0860c8d Mon Sep 17 00:00:00 2001 From: gator96100 Date: Tue, 29 Dec 2020 21:37:01 +0100 Subject: [PATCH 243/682] Fixed serial port not parsing --- .vscode/setup.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.vscode/setup.sh b/.vscode/setup.sh index cdfb77e8f..70672b924 100755 --- a/.vscode/setup.sh +++ b/.vscode/setup.sh @@ -40,7 +40,7 @@ function setup_serial_port { if [ -z "$SerialPort" ]; then pm3list=$($VSCODEPATH/../pm3 --list 2>/dev/null) #Use first port listed - SerialPort=$(echo $pm3list | head -n 1 | cut -c 4-) + export SerialPort=$(echo $pm3list | head -n 1 | cut -c 4-) if [ -z "$SerialPort" ]; then echo >&2 "[!!] No serial port found, please set SerialPort manually" exit 1 From db43f55b98ecef1092b066dae09f468e962a5cb6 Mon Sep 17 00:00:00 2001 From: iceman1001 Date: Tue, 29 Dec 2020 21:38:02 +0100 Subject: [PATCH 244/682] hf mfu wrbl - now supports cliparser --- client/src/cmdhfmfu.c | 185 +++++++++++++++++++----------------------- 1 file changed, 84 insertions(+), 101 deletions(-) diff --git a/client/src/cmdhfmfu.c b/client/src/cmdhfmfu.c index 639429fba..0dbc93998 100644 --- a/client/src/cmdhfmfu.c +++ b/client/src/cmdhfmfu.c @@ -99,21 +99,6 @@ static int usage_hf_mfu_rdbl(void) { return PM3_SUCCESS; } -static int usage_hf_mfu_wrbl(void) { - PrintAndLogEx(NORMAL, "Write a block. It autodetects card type.\n"); - PrintAndLogEx(NORMAL, "Usage: hf mfu wrbl b d k l\n"); - PrintAndLogEx(NORMAL, "Options:"); - PrintAndLogEx(NORMAL, " b : block to write"); - PrintAndLogEx(NORMAL, " d : block data - (8 or 32 hex symbols, 32 hex symbols will do a compatibility write)"); - PrintAndLogEx(NORMAL, " k : (optional) key for authentication [UL-C 16bytes, EV1/NTAG 4bytes]"); - PrintAndLogEx(NORMAL, " l : (optional) swap entered key's endianness"); - PrintAndLogEx(NORMAL, ""); - PrintAndLogEx(NORMAL, "Examples:"); - PrintAndLogEx(NORMAL, _YELLOW_(" hf mfu wrbl b 0 d 01234567")); - PrintAndLogEx(NORMAL, _YELLOW_(" hf mfu wrbl b 0 d 01234567 k AABBCCDD")); - PrintAndLogEx(NORMAL, ""); - return PM3_SUCCESS; -} static int usage_hf_mfu_eload(void) { PrintAndLogEx(NORMAL, "It loads emul dump from the file " _YELLOW_("`filename.eml`")); @@ -1265,8 +1250,8 @@ static int CmdHF14AMfUInfo(const char *Cmd) { "Get info about MIFARE Ultralight Family styled tag.\n" "Sometimes the tags are locked down, and you may need a key to be able to read the information", "hf mfu info\n" - "hf mfu info k AABBCCDD\n" - "hf mfu info k 00112233445566778899AABBCCDDEEFF" + "hf mfu info -k AABBCCDD\n" + "hf mfu info --key 00112233445566778899AABBCCDDEEFF" ); void *argtable[] = { @@ -1284,7 +1269,7 @@ static int CmdHF14AMfUInfo(const char *Cmd) { CLIParserFree(ctx); if (ak_len) { - if (ak_len != 16 || ak_len != 8) { + if (ak_len != 16 && ak_len != 8) { PrintAndLogEx(WARNING, "ERROR: Key is incorrect length\n"); return PM3_EINVARG; } @@ -1558,81 +1543,63 @@ out: // static int CmdHF14AMfUWrBl(const char *Cmd) { - int blockNo = -1; - bool errors = false; - bool hasAuthKey = false; - bool hasPwdKey = false; - bool swapEndian = false; + CLIParserContext *ctx; + CLIParserInit(&ctx, "hf mfu wrbl", + "Write a block. It autodetects card type.", + "hf mfu wrbl -b 0 -d 01234567\n" + "hf mfu wrbl -b 0 -d 01234567 -k AABBCCDD\n" + "hf mfu wrbl -b 0 -d 01234567 -k 00112233445566778899AABBCCDDEEFF" + ); - uint8_t cmdp = 0; - uint8_t keylen = 0; - uint8_t blockdata[16] = {0x00}; - uint8_t data[16] = {0x00}; - uint8_t datalen = 4; + void *argtable[] = { + arg_param_begin, + arg_str0("k", "key", "", "key for authentication (UL-C 16 bytes, EV1/NTAG 4 bytes)"), + arg_lit0("l", NULL, "swap entered key's endianness"), + arg_int1("b", "block", "", "block number to write"), + arg_str1("d", "data", "", "block data (4 or 16 hex bytes, 16 hex bytes will do a compatibility write)"), + arg_param_end + }; + CLIExecWithReturn(ctx, Cmd, argtable, false); + + int ak_len = 0; uint8_t authenticationkey[16] = {0x00}; + CLIGetHexWithReturn(ctx, 1, authenticationkey, &ak_len); + bool swap_endian = arg_get_lit(ctx, 2); + + int blockno = arg_get_int_def(ctx, 3, -1); + + int datalen = 0; + uint8_t data[16] = {0x00}; + CLIGetHexWithReturn(ctx, 4, data, &datalen); + CLIParserFree(ctx); + + bool has_auth_key = false; + bool has_pwd = false; + if (ak_len == 16) { + has_auth_key = true; + } else if (ak_len == 4) { + has_pwd = true; + } else if (ak_len != 0){ + PrintAndLogEx(WARNING, "ERROR: Key is incorrect length\n"); + return PM3_EINVARG; + } + + if (blockno < 0) { + PrintAndLogEx(WARNING, "Wrong block number"); + return PM3_EINVARG; + } + + if (datalen != 16 && datalen != 4) { + PrintAndLogEx(WARNING, "Wrong data length. Expect 16 or 4, got %d", datalen); + return PM3_EINVARG; + } + uint8_t *authKeyPtr = authenticationkey; - while (param_getchar(Cmd, cmdp) != 0x00 && !errors) { - switch (tolower(param_getchar(Cmd, cmdp))) { - case 'h': - return usage_hf_mfu_wrbl(); - case 'k': - // EV1/NTAG size key - keylen = param_gethex(Cmd, cmdp + 1, data, 8); - if (!keylen) { - memcpy(authenticationkey, data, 4); - cmdp += 2; - hasPwdKey = true; - break; - } - // UL-C size key - keylen = param_gethex(Cmd, cmdp + 1, data, 32); - if (!keylen) { - memcpy(authenticationkey, data, 16); - cmdp += 2; - hasAuthKey = true; - break; - } - PrintAndLogEx(WARNING, "ERROR: Key is incorrect length\n"); - errors = true; - break; - case 'b': - blockNo = param_get8(Cmd, cmdp + 1); - if (blockNo < 0) { - PrintAndLogEx(WARNING, "Wrong block number"); - errors = true; - } - cmdp += 2; - break; - case 'l': - swapEndian = true; - cmdp++; - break; - case 'd': - if (param_gethex(Cmd, cmdp + 1, blockdata, 8)) { - if (param_gethex(Cmd, cmdp + 1, blockdata, 32)) { - PrintAndLogEx(WARNING, "Block data must include 8 or 32 HEX symbols"); - errors = true; - break; - } else { - datalen = 16; - } - } - cmdp += 2; - break; - default: - PrintAndLogEx(WARNING, "Unknown parameter: " _RED_("'%c'"), param_getchar(Cmd, cmdp)); - errors = true; - break; - } - } - //Validations - if (errors || cmdp == 0) return usage_hf_mfu_wrbl(); - - if (blockNo == -1) return usage_hf_mfu_wrbl(); // starting with getting tagtype TagTypeUL_t tagtype = GetHF14AMfU_Type(); - if (tagtype == UL_ERROR) return -1; + if (tagtype == UL_ERROR) + return PM3_ESOFT; uint8_t maxblockno = 0; for (uint8_t idx = 0; idx < ARRAYLEN(UL_TYPES_ARRAY); idx++) { @@ -1641,39 +1608,55 @@ static int CmdHF14AMfUWrBl(const char *Cmd) { break; } } - if (blockNo > maxblockno) { + if (blockno > maxblockno) { PrintAndLogEx(WARNING, "block number too large. Max block is %u/0x%02X \n", maxblockno, maxblockno); - return usage_hf_mfu_wrbl(); + return PM3_EINVARG; } // Swap endianness - if (swapEndian && hasAuthKey) authKeyPtr = SwapEndian64(authenticationkey, 16, 8); - if (swapEndian && hasPwdKey) authKeyPtr = SwapEndian64(authenticationkey, 4, 4); + if (swap_endian) { + if (has_auth_key) + authKeyPtr = SwapEndian64(authenticationkey, 16, 8); - if (blockNo <= 3) - PrintAndLogEx(NORMAL, "Special Block: %0d (0x%02X) [ %s]", blockNo, blockNo, sprint_hex(blockdata, 4)); + if (has_pwd) + authKeyPtr = SwapEndian64(authenticationkey, 4, 4); + } + + if (blockno <= 3) + PrintAndLogEx(INFO, "Special block: %0d (0x%02X) [ %s]", blockno, blockno, sprint_hex(data, datalen)); else - PrintAndLogEx(NORMAL, "Block: %0d (0x%02X) [ %s]", blockNo, blockNo, sprint_hex(blockdata, 4)); + PrintAndLogEx(INFO, "Block: %0d (0x%02X) [ %s]", blockno, blockno, sprint_hex(data, datalen)); + if (ak_len) { + PrintAndLogEx(INFO, "Using %s %s", (ak_len == 16) ? "3des" : "pwd", sprint_hex(authenticationkey, ak_len)); + } + //Send write Block + + // 4 or 16. uint8_t cmddata[32]; - memcpy(cmddata, blockdata, datalen); + memcpy(cmddata, data, datalen); + + // 0 - no pwd/key, no authentication + // 1 - 3des key (16 bytes) + // 2 - pwd (4 bytes) uint8_t keytype = 0; - if (hasAuthKey) { + size_t cmdlen = datalen; + if (has_auth_key) { keytype = 1; memcpy(cmddata + datalen, authKeyPtr, 16); - datalen += 16; - } else if (hasPwdKey) { + cmdlen += 16; + } else if (has_pwd) { keytype = 2; memcpy(cmddata + datalen, authKeyPtr, 4); - datalen += 4; + cmdlen += 4; } clearCommandBuffer(); if (datalen == 16) { - SendCommandMIX(CMD_HF_MIFAREU_WRITEBL_COMPAT, blockNo, keytype, 0, cmddata, datalen); + SendCommandMIX(CMD_HF_MIFAREU_WRITEBL_COMPAT, blockno, keytype, 0, cmddata, cmdlen); } else { - SendCommandMIX(CMD_HF_MIFAREU_WRITEBL, blockNo, keytype, 0, cmddata, datalen); + SendCommandMIX(CMD_HF_MIFAREU_WRITEBL, blockno, keytype, 0, cmddata, cmdlen); } PacketResponseNG resp; if (WaitForResponseTimeout(CMD_ACK, &resp, 1500)) { From 3396eeefdd371dacb6444d3228ff8aa9b3bfcec6 Mon Sep 17 00:00:00 2001 From: iceman1001 Date: Tue, 29 Dec 2020 21:41:15 +0100 Subject: [PATCH 245/682] missing quote, Thanks @aveao for pointing it out! --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index b7e942f58..3fd900b42 100644 --- a/Makefile +++ b/Makefile @@ -169,7 +169,7 @@ help: @echo "+ fpga_compress - Make tools/fpga_compress" @echo @echo "+ style - Apply some automated source code formatting rules" - @echo "+ cliparser - Generate cliparser TODO + @echo "+ cliparser - Generate cliparser TODO" @echo "+ check - Run offline tests. Set CHECKARGS to pass arguments to the test script" @echo "+ .../check - Run offline tests against specific target. See above." @echo "+ miscchecks - Detect various encoding issues in source code" From 9bd73c4c0ad826f144ab5096d71cd275d0e5ccc5 Mon Sep 17 00:00:00 2001 From: gator96100 Date: Tue, 29 Dec 2020 21:43:29 +0100 Subject: [PATCH 246/682] Updated installation instructions for ProxSpace --- .../Windows-Installation-Instructions.md | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/doc/md/Installation_Instructions/Windows-Installation-Instructions.md b/doc/md/Installation_Instructions/Windows-Installation-Instructions.md index 1cf1f43c9..80f5b4d5c 100644 --- a/doc/md/Installation_Instructions/Windows-Installation-Instructions.md +++ b/doc/md/Installation_Instructions/Windows-Installation-Instructions.md @@ -64,6 +64,24 @@ To use the compiled client, the only differences are that executables end with ` Now you're ready to follow the [compilation instructions](/doc/md/Use_of_Proxmark/0_Compilation-Instructions.md). +## (Optional) Visual Studio Code debugging + +Download and install [Visual Studio Code](https://code.visualstudio.com/) + +Download and install [J-Link Software and Documentation pack for Windows](https://www.segger.com/downloads/jlink/JLink_Windows.exe) + +Enter PorxSpace (`runme64.bat`) and enter your project folder. + +Setup the Visual Studio Code configuration, by running: +```sh +./.vscode/setup.sh +``` + +now launch Visual Studio Code and open your project folder + +_note_ +Please install the recommended Visual Studio Code extensions in order for debugging to work. + # Installing on Windows with WSL 1 WSL 1 requires to run on Windows 10 version 1709 or above. Previous windows versions didn't have support for COM ports. From d8c8de3204a442bc7c0099f158dee1b963d49cb7 Mon Sep 17 00:00:00 2001 From: iceman1001 Date: Tue, 29 Dec 2020 22:47:50 +0100 Subject: [PATCH 247/682] hf mfu rdbl - now uses cliparser --- client/src/cmdhfmfu.c | 147 ++++++++++++++++++------------------------ 1 file changed, 63 insertions(+), 84 deletions(-) diff --git a/client/src/cmdhfmfu.c b/client/src/cmdhfmfu.c index 0dbc93998..a85e9aaf3 100644 --- a/client/src/cmdhfmfu.c +++ b/client/src/cmdhfmfu.c @@ -83,23 +83,6 @@ static int usage_hf_mfu_restore(void) { return PM3_SUCCESS; } -static int usage_hf_mfu_rdbl(void) { - PrintAndLogEx(NORMAL, "Read a block and print. It autodetects card type.\n"); - PrintAndLogEx(NORMAL, "Usage: hf mfu rdbl b k l\n"); - PrintAndLogEx(NORMAL, "Options:"); - PrintAndLogEx(NORMAL, " b : block to read"); - PrintAndLogEx(NORMAL, " k : (optional) key for authentication [UL-C 16bytes, EV1/NTAG 4bytes]"); - PrintAndLogEx(NORMAL, " l : (optional) swap entered key's endianness"); - PrintAndLogEx(NORMAL, ""); - PrintAndLogEx(NORMAL, "Examples:"); - PrintAndLogEx(NORMAL, _YELLOW_(" hf mfu rdbl b 0")); - PrintAndLogEx(NORMAL, _YELLOW_(" hf mfu rdbl b 0 k 00112233445566778899AABBCCDDEEFF")); - PrintAndLogEx(NORMAL, _YELLOW_(" hf mfu rdbl b 0 k AABBCCDD")); - PrintAndLogEx(NORMAL, ""); - return PM3_SUCCESS; -} - - static int usage_hf_mfu_eload(void) { PrintAndLogEx(NORMAL, "It loads emul dump from the file " _YELLOW_("`filename.eml`")); PrintAndLogEx(NORMAL, "Hint: See " _YELLOW_("`script run hf_mfu_dumptoemulator`") " to convert the .bin to the eml"); @@ -1628,7 +1611,7 @@ static int CmdHF14AMfUWrBl(const char *Cmd) { PrintAndLogEx(INFO, "Block: %0d (0x%02X) [ %s]", blockno, blockno, sprint_hex(data, datalen)); if (ak_len) { - PrintAndLogEx(INFO, "Using %s %s", (ak_len == 16) ? "3des" : "pwd", sprint_hex(authenticationkey, ak_len)); + PrintAndLogEx(INFO, "Using %s " _GREEN_("%s"), (ak_len == 16) ? "3des" : "pwd", sprint_hex(authenticationkey, ak_len)); } //Send write Block @@ -1673,66 +1656,52 @@ static int CmdHF14AMfUWrBl(const char *Cmd) { // static int CmdHF14AMfURdBl(const char *Cmd) { - int blockNo = -1; - bool errors = false; - bool hasAuthKey = false; - bool hasPwdKey = false; - bool swapEndian = false; - uint8_t cmdp = 0; - uint8_t keylen = 0; - uint8_t data[16] = {0x00}; + CLIParserContext *ctx; + CLIParserInit(&ctx, "hf mfu rdbl", + "Read a block and print. It autodetects card type.", + "hf mfu rdbl -b 0\n" + "hf mfu rdbl -b 0 -k AABBCCDD\n" + "hf mfu rdbl -b 0 --key 00112233445566778899AABBCCDDEEFF" + ); + + void *argtable[] = { + arg_param_begin, + arg_str0("k", "key", "", "key for authentication (UL-C 16 bytes, EV1/NTAG 4 bytes)"), + arg_lit0("l", NULL, "swap entered key's endianness"), + arg_int1("b", "block", "", "block number to write"), + arg_param_end + }; + CLIExecWithReturn(ctx, Cmd, argtable, false); + + int ak_len = 0; uint8_t authenticationkey[16] = {0x00}; + CLIGetHexWithReturn(ctx, 1, authenticationkey, &ak_len); + bool swap_endian = arg_get_lit(ctx, 2); + int blockno = arg_get_int_def(ctx, 3, -1); + CLIParserFree(ctx); + + bool has_auth_key = false; + bool has_pwd = false; + if (ak_len == 16) { + has_auth_key = true; + } else if (ak_len == 4) { + has_pwd = true; + } else if (ak_len != 0){ + PrintAndLogEx(WARNING, "ERROR: Key is incorrect length\n"); + return PM3_EINVARG; + } + + if (blockno < 0) { + PrintAndLogEx(WARNING, "Wrong block number"); + return PM3_EINVARG; + } + uint8_t *authKeyPtr = authenticationkey; - while (param_getchar(Cmd, cmdp) != 0x00 && !errors) { - switch (tolower(param_getchar(Cmd, cmdp))) { - case 'h': - return usage_hf_mfu_rdbl(); - case 'k': - // EV1/NTAG size key - keylen = param_gethex(Cmd, cmdp + 1, data, 8); - if (!keylen) { - memcpy(authenticationkey, data, 4); - cmdp += 2; - hasPwdKey = true; - break; - } - // UL-C size key - keylen = param_gethex(Cmd, cmdp + 1, data, 32); - if (!keylen) { - memcpy(authenticationkey, data, 16); - cmdp += 2; - hasAuthKey = true; - break; - } - PrintAndLogEx(WARNING, "ERROR: Key is incorrect length\n"); - errors = true; - break; - case 'b': - blockNo = param_get8(Cmd, cmdp + 1); - if (blockNo < 0) { - PrintAndLogEx(WARNING, "Wrong block number"); - errors = true; - } - cmdp += 2; - break; - case 'l': - swapEndian = true; - cmdp++; - break; - default: - PrintAndLogEx(WARNING, "Unknown parameter: " _RED_("'%c'"), param_getchar(Cmd, cmdp)); - errors = true; - break; - } - } - //Validations - if (errors || cmdp == 0) return usage_hf_mfu_rdbl(); - - if (blockNo == -1) return usage_hf_mfu_rdbl(); // start with getting tagtype TagTypeUL_t tagtype = GetHF14AMfU_Type(); - if (tagtype == UL_ERROR) return -1; + if (tagtype == UL_ERROR) + return PM3_ESOFT; uint8_t maxblockno = 0; for (uint8_t idx = 0; idx < ARRAYLEN(UL_TYPES_ARRAY); idx++) { @@ -1741,43 +1710,53 @@ static int CmdHF14AMfURdBl(const char *Cmd) { break; } } - if (blockNo > maxblockno) { + if (blockno > maxblockno) { PrintAndLogEx(WARNING, "block number to large. Max block is %u/0x%02X \n", maxblockno, maxblockno); - return usage_hf_mfu_rdbl(); + return PM3_EINVARG; } // Swap endianness - if (swapEndian && hasAuthKey) authKeyPtr = SwapEndian64(authenticationkey, 16, 8); - if (swapEndian && hasPwdKey) authKeyPtr = SwapEndian64(authenticationkey, 4, 4); + if (swap_endian) { + if (has_auth_key) + authKeyPtr = SwapEndian64(authenticationkey, ak_len, 8); + + if (has_pwd) + authKeyPtr = SwapEndian64(authenticationkey, ak_len, 4); + } + + if (ak_len) { + PrintAndLogEx(INFO, "Using %s " _GREEN_("%s"), (ak_len == 16) ? "3des" : "pwd", sprint_hex(authenticationkey, ak_len)); + } //Read Block uint8_t keytype = 0; uint8_t datalen = 0; - if (hasAuthKey) { + if (has_auth_key) { keytype = 1; datalen = 16; - } else if (hasPwdKey) { + } else if (has_pwd) { keytype = 2; datalen = 4; } clearCommandBuffer(); - SendCommandMIX(CMD_HF_MIFAREU_READBL, blockNo, keytype, 0, authKeyPtr, datalen); + SendCommandMIX(CMD_HF_MIFAREU_READBL, blockno, keytype, 0, authKeyPtr, datalen); PacketResponseNG resp; if (WaitForResponseTimeout(CMD_ACK, &resp, 1500)) { uint8_t isOK = resp.oldarg[0] & 0xff; if (isOK) { uint8_t *d = resp.data.asBytes; - PrintAndLogEx(NORMAL, "\nBlock# | Data | Ascii"); - PrintAndLogEx(NORMAL, "-----------------------------"); - PrintAndLogEx(NORMAL, "%02d/0x%02X | %s| %s\n", blockNo, blockNo, sprint_hex(d, 4), sprint_ascii(d, 4)); + PrintAndLogEx(NORMAL, ""); + PrintAndLogEx(INFO, "Block# | Data | Ascii"); + PrintAndLogEx(INFO, "-----------------------------"); + PrintAndLogEx(INFO, "%02d/0x%02X | %s| %s\n", blockno, blockno, sprint_hex(d, 4), sprint_ascii(d, 4)); } else { PrintAndLogEx(WARNING, "Failed reading block: (%02x)", isOK); } } else { PrintAndLogEx(WARNING, "Command execute time-out"); } - return 0; + return PM3_SUCCESS; } void printMFUdumpEx(mfu_dump_t *card, uint16_t pages, uint8_t startpage) { From 8c803edfd2b42cd173d3a22615d5ae74e6e703b5 Mon Sep 17 00:00:00 2001 From: iceman1001 Date: Tue, 29 Dec 2020 23:36:38 +0100 Subject: [PATCH 248/682] hf mfu dump - now uses cliparser --- client/src/cmdhfmfu.c | 211 +++++++++++++++++++----------------------- 1 file changed, 94 insertions(+), 117 deletions(-) diff --git a/client/src/cmdhfmfu.c b/client/src/cmdhfmfu.c index a85e9aaf3..2c89cdf73 100644 --- a/client/src/cmdhfmfu.c +++ b/client/src/cmdhfmfu.c @@ -42,28 +42,6 @@ static int CmdHelp(const char *Cmd); -static int usage_hf_mfu_dump(void) { - PrintAndLogEx(NORMAL, "Reads all pages from Ultralight, Ultralight-C, Ultralight EV1"); - PrintAndLogEx(NORMAL, "NTAG 203, NTAG 210, NTAG 212, NTAG 213, NTAG 215, NTAG 216"); - PrintAndLogEx(NORMAL, "and saves binary dump into the file " _YELLOW_("`filename.bin`") " or " _YELLOW_("`cardUID.bin`")); - PrintAndLogEx(NORMAL, "It autodetects card type.\n"); - PrintAndLogEx(NORMAL, "Usage: hf mfu dump k l f p q <#pages>"); - PrintAndLogEx(NORMAL, " Options :"); - PrintAndLogEx(NORMAL, " k : (optional) key for authentication [UL-C 16bytes, EV1/NTAG 4bytes]"); - PrintAndLogEx(NORMAL, " l : (optional) swap entered key's endianness"); - PrintAndLogEx(NORMAL, " f : " _YELLOW_("filename w/o .bin") " to save the dump as"); - PrintAndLogEx(NORMAL, " p : starting Page number to manually set a page to start the dump at"); - PrintAndLogEx(NORMAL, " q : number of Pages to manually set how many pages to dump"); - PrintAndLogEx(NORMAL, ""); - PrintAndLogEx(NORMAL, "Examples:"); - PrintAndLogEx(NORMAL, _YELLOW_(" hf mfu dump")); - PrintAndLogEx(NORMAL, _YELLOW_(" hf mfu dump f myfile")); - PrintAndLogEx(NORMAL, _YELLOW_(" hf mfu dump k 00112233445566778899AABBCCDDEEFF")); - PrintAndLogEx(NORMAL, _YELLOW_(" hf mfu dump k AABBCCDD")); - PrintAndLogEx(NORMAL, ""); - return PM3_SUCCESS; -} - static int usage_hf_mfu_restore(void) { PrintAndLogEx(NORMAL, "Restore dumpfile onto card."); PrintAndLogEx(NORMAL, "Usage: hf mfu restore [h] [l] [s] k n "); @@ -1911,83 +1889,78 @@ void printMFUdumpEx(mfu_dump_t *card, uint16_t pages, uint8_t startpage) { // Read and Dump Card Contents, using auto detection of tag size. static int CmdHF14AMfUDump(const char *Cmd) { - int fileNameLen = 0; - char filename[FILE_PATH_SIZE] = {0x00}; - char *fptr = filename; + CLIParserContext *ctx; + CLIParserInit(&ctx, "hf mfu dump", + "Reads all pages from Ultralight, Ultralight-C, Ultralight EV1\n" + "NTAG 203, NTAG 210, NTAG 212, NTAG 213, NTAG 215, NTAG 216\n" + "and saves data into binary/json files.\n" + "It autodetects card type.", + "hf mfu dump -f myfile -> dump whole tag, save to `myfile.bin`\n" + "hf mfu dump -k AABBCCDD -> dump whole tag using pwd AABBCCDD\n" + "hf mfu dump -p 10 -> start at page 10 and dump rest of blocks\n" + "hf mfu dump -p 10 -q 2 -> start at page 10 and dump two blocks\n" + "hf mfu dump --key 00112233445566778899AABBCCDDEEFF" + ); - uint8_t data[1024] = {0x00}; - memset(data, 0x00, sizeof(data)); + void *argtable[] = { + arg_param_begin, + arg_str0("f", "file", "", "specify a filename for dump file"), + arg_str0("k", "key", "", "key for authentication (UL-C 16 bytes, EV1/NTAG 4 bytes)"), + arg_lit0("l", NULL, "swap entered key's endianness"), + arg_int0("p", "page", "", "manually set start page number to start from"), + arg_int0("q", "qty", "", "manually set number of pages to dump"), + arg_param_end + }; + CLIExecWithReturn(ctx, Cmd, argtable, true); - bool hasAuthKey = false; - int pages = 16; - uint8_t dataLen = 0; - uint8_t cmdp = 0; + int fnlen = 0; + char filename[FILE_PATH_SIZE] = {0}; + CLIParamStrToBuf(arg_get_str(ctx, 1), (uint8_t *)filename, FILE_PATH_SIZE, &fnlen); + + int ak_len = 0; uint8_t authenticationkey[16] = {0x00}; - memset(authenticationkey, 0x00, sizeof(authenticationkey)); uint8_t *authKeyPtr = authenticationkey; + CLIGetHexWithReturn(ctx, 2, authenticationkey, &ak_len); + bool swap_endian = arg_get_lit(ctx, 3); + int start_page = arg_get_int_def(ctx, 4, 0); + int pages = arg_get_int_def(ctx, 5, 16); + CLIParserFree(ctx); - bool errors = false; - bool swapEndian = false; - bool manualPages = false; - uint8_t startPage = 0; - uint8_t card_mem_size = 0; - char tempStr[50]; - - while (param_getchar(Cmd, cmdp) != 0x00 && !errors) { - switch (tolower(param_getchar(Cmd, cmdp))) { - case 'h': - return usage_hf_mfu_dump(); - case 'k': - dataLen = param_getstr(Cmd, cmdp + 1, tempStr, sizeof(tempStr)); - if (dataLen == 32 || dataLen == 8) { //ul-c or ev1/ntag key length - errors = param_gethex(tempStr, 0, authenticationkey, dataLen); - dataLen /= 2; - } else { - PrintAndLogEx(WARNING, "ERROR: Key is incorrect length\n"); - errors = true; - } - cmdp += 2; - hasAuthKey = true; - break; - case 'l': - swapEndian = true; - cmdp++; - break; - case 'f': - fileNameLen = param_getstr(Cmd, cmdp + 1, filename, sizeof(filename)); - if (fileNameLen > FILE_PATH_SIZE - 5) - fileNameLen = FILE_PATH_SIZE - 5; - cmdp += 2; - break; - case 'p': //set start page - startPage = param_get8(Cmd, cmdp + 1); - manualPages = true; - cmdp += 2; - break; - case 'q': - pages = param_get8(Cmd, cmdp + 1); - cmdp += 2; - manualPages = true; - break; - default: - PrintAndLogEx(WARNING, "Unknown parameter: " _RED_("'%c'"), param_getchar(Cmd, cmdp)); - errors = true; - break; - } + bool has_auth_key = false; + bool has_pwd = false; + if (ak_len == 16) { + has_auth_key = true; + } else if (ak_len == 4) { + has_pwd = true; + } else if (ak_len != 0){ + PrintAndLogEx(WARNING, "ERROR: Key is incorrect length\n"); + return PM3_EINVARG; } - //Validations - if (errors) return usage_hf_mfu_dump(); + bool manual_pages = false; + if ( start_page > 0) + manual_pages = true; - //if we entered a key in little endian and set the swapEndian switch - switch it... - if (swapEndian && hasAuthKey) - authKeyPtr = SwapEndian64(authenticationkey, dataLen, (dataLen == 16) ? 8 : 4); + if (pages != 16) + manual_pages = true; + + uint8_t card_mem_size = 0; + + // Swap endianness + if (swap_endian) { + if (has_auth_key) + authKeyPtr = SwapEndian64(authenticationkey, ak_len, 8); + + if (has_pwd) + authKeyPtr = SwapEndian64(authenticationkey, ak_len, 4); + } TagTypeUL_t tagtype = GetHF14AMfU_Type(); - if (tagtype == UL_ERROR) return -1; + if (tagtype == UL_ERROR) + return PM3_ESOFT; //get number of pages to read - if (!manualPages) { + if (manual_pages == false) { for (uint8_t idx = 0; idx < ARRAYLEN(UL_TYPES_ARRAY); idx++) { if (tagtype & UL_TYPES_ARRAY[idx]) { //add one as maxblks starts at 0 @@ -1999,7 +1972,7 @@ static int CmdHF14AMfUDump(const char *Cmd) { ul_print_type(tagtype, 0); PrintAndLogEx(SUCCESS, "Reading tag memory..."); uint8_t keytype = 0; - if (hasAuthKey) { + if (has_auth_key) { if (tagtype & UL_C) keytype = 1; //UL_C auth else @@ -2007,34 +1980,38 @@ static int CmdHF14AMfUDump(const char *Cmd) { } clearCommandBuffer(); - SendCommandMIX(CMD_HF_MIFAREU_READCARD, startPage, pages, keytype, authKeyPtr, dataLen); + SendCommandMIX(CMD_HF_MIFAREU_READCARD, start_page, pages, keytype, authKeyPtr, ak_len); PacketResponseNG resp; if (!WaitForResponseTimeout(CMD_ACK, &resp, 2500)) { PrintAndLogEx(WARNING, "Command execute time-out"); - return 1; + return PM3_ETIMEOUT; } if (resp.oldarg[0] != 1) { PrintAndLogEx(WARNING, "Failed dumping card"); - return 1; + return PM3_ESOFT; } + // read all memory + uint8_t data[1024] = {0x00}; + memset(data, 0x00, sizeof(data)); + uint32_t startindex = resp.oldarg[2]; - uint32_t bufferSize = resp.oldarg[1]; - if (bufferSize > sizeof(data)) { + uint32_t buffer_size = resp.oldarg[1]; + if (buffer_size > sizeof(data)) { PrintAndLogEx(FAILED, "Data exceeded Buffer size!"); - bufferSize = sizeof(data); + buffer_size = sizeof(data); } - if (!GetFromDevice(BIG_BUF, data, bufferSize, startindex, NULL, 0, NULL, 2500, false)) { + if (!GetFromDevice(BIG_BUF, data, buffer_size, startindex, NULL, 0, NULL, 2500, false)) { PrintAndLogEx(WARNING, "command execution time out"); - return 1; + return PM3_ETIMEOUT; } - bool is_partial = (pages != bufferSize / 4); + bool is_partial = (pages != buffer_size / 4); - pages = bufferSize / 4; + pages = buffer_size / 4; iso14a_card_select_t card; mfu_dump_t dump_file_data; @@ -2063,9 +2040,9 @@ static int CmdHF14AMfUDump(const char *Cmd) { memcpy(data + (pages * 4) - 4, get_pack, sizeof(get_pack)); } - if (hasAuthKey) { + if (has_auth_key) { uint8_t dummy_pack[] = {0, 0}; - ul_auth_select(&card, tagtype, hasAuthKey, authKeyPtr, dummy_pack, sizeof(dummy_pack)); + ul_auth_select(&card, tagtype, has_auth_key, authKeyPtr, dummy_pack, sizeof(dummy_pack)); } else { ul_select(&card); } @@ -2083,17 +2060,17 @@ static int CmdHF14AMfUDump(const char *Cmd) { // NTAG can have nfc counter pwd protection enabled for (; n < 3; n++) { - if (hasAuthKey) { + if (has_auth_key) { uint8_t dummy_pack[] = {0, 0}; - ul_auth_select(&card, tagtype, hasAuthKey, authKeyPtr, dummy_pack, sizeof(dummy_pack)); + ul_auth_select(&card, tagtype, has_auth_key, authKeyPtr, dummy_pack, sizeof(dummy_pack)); } else { ul_select(&card); } ulev1_readCounter(n, &get_counter_tearing[n][0], 3); - if (hasAuthKey) { + if (has_auth_key) { uint8_t dummy_pack[] = {0, 0}; - ul_auth_select(&card, tagtype, hasAuthKey, authKeyPtr, dummy_pack, sizeof(dummy_pack)); + ul_auth_select(&card, tagtype, has_auth_key, authKeyPtr, dummy_pack, sizeof(dummy_pack)); } else { ul_select(&card); } @@ -2102,9 +2079,9 @@ static int CmdHF14AMfUDump(const char *Cmd) { DropField(); - if (hasAuthKey) { + if (has_auth_key) { uint8_t dummy_pack[] = {0, 0}; - ul_auth_select(&card, tagtype, hasAuthKey, authKeyPtr, dummy_pack, sizeof(dummy_pack)); + ul_auth_select(&card, tagtype, has_auth_key, authKeyPtr, dummy_pack, sizeof(dummy_pack)); } else ul_select(&card); @@ -2114,21 +2091,21 @@ static int CmdHF14AMfUDump(const char *Cmd) { // format and add keys to block dump output // only add keys if not partial read, and complete pages read - if (!is_partial && pages == card_mem_size && hasAuthKey) { + if (!is_partial && pages == card_mem_size && has_auth_key) { // if we didn't swapendian before - do it now for the sprint_hex call // NOTE: default entry is bigendian (unless swapped), sprint_hex outputs little endian // need to swap to keep it the same - if (!swapEndian) { - authKeyPtr = SwapEndian64(authenticationkey, dataLen, (dataLen == 16) ? 8 : 4); + if (swap_endian == false) { + authKeyPtr = SwapEndian64(authenticationkey, ak_len, (ak_len == 16) ? 8 : 4); } else { authKeyPtr = authenticationkey; } if (tagtype & UL_C) { //add 4 pages - memcpy(data + pages * 4, authKeyPtr, dataLen); - pages += dataLen / 4; + memcpy(data + pages * 4, authKeyPtr, ak_len); + pages += ak_len / 4; } else { // 2nd page from end - memcpy(data + (pages * 4) - 8, authenticationkey, dataLen); + memcpy(data + (pages * 4) - 8, authenticationkey, ak_len); } } @@ -2140,17 +2117,17 @@ static int CmdHF14AMfUDump(const char *Cmd) { memcpy(dump_file_data.counter_tearing, get_counter_tearing, sizeof(dump_file_data.counter_tearing)); memcpy(dump_file_data.data, data, pages * 4); - printMFUdumpEx(&dump_file_data, pages, startPage); + printMFUdumpEx(&dump_file_data, pages, start_page); // user supplied filename? - if (fileNameLen < 1) { + if (fnlen < 1) { PrintAndLogEx(INFO, "Using UID as filename"); uint8_t uid[7] = {0}; memcpy(uid, (uint8_t *)&dump_file_data.data, 3); memcpy(uid + 3, (uint8_t *)&dump_file_data.data + 4, 4); - fptr += sprintf(fptr, "hf-mfu-"); - FillFileNameByUID(fptr, uid, "-dump", sizeof(uid)); + strcat(filename, "hf-mfu-"); + FillFileNameByUID(filename, uid, "-dump", sizeof(uid)); } uint16_t datalen = pages * 4 + MFU_DUMP_PREFIX_LENGTH; saveFile(filename, ".bin", (uint8_t *)&dump_file_data, datalen); @@ -2159,7 +2136,7 @@ static int CmdHF14AMfUDump(const char *Cmd) { if (is_partial) PrintAndLogEx(WARNING, "Partial dump created. (%d of %d blocks)", pages, card_mem_size); - return 0; + return PM3_SUCCESS; } static void wait4response(uint8_t b) { From 483707a45ac05ad162705f3022ec6a3e4b09dbd3 Mon Sep 17 00:00:00 2001 From: gator96100 Date: Wed, 30 Dec 2020 00:00:39 +0100 Subject: [PATCH 249/682] Moved vscode instructions --- .../Linux-Installation-Instructions.md | 27 +------ .../VSCode-Installation-Instructions.md | 72 +++++++++++++++++++ .../Windows-Installation-Instructions.md | 48 ------------- 3 files changed, 73 insertions(+), 74 deletions(-) create mode 100644 doc/md/Installation_Instructions/VSCode-Installation-Instructions.md diff --git a/doc/md/Installation_Instructions/Linux-Installation-Instructions.md b/doc/md/Installation_Instructions/Linux-Installation-Instructions.md index aa5cf9042..18164398a 100644 --- a/doc/md/Installation_Instructions/Linux-Installation-Instructions.md +++ b/doc/md/Installation_Instructions/Linux-Installation-Instructions.md @@ -25,16 +25,13 @@ Install the requirements ```sh sudo apt-get install --no-install-recommends git ca-certificates build-essential pkg-config \ -libreadline-dev gcc-arm-none-eabi libnewlib-dev qtbase5-dev libbz2-dev libbluetooth-dev \ -binutils-arm-none-eabi gdb openocd gdb-multiarch +libreadline-dev gcc-arm-none-eabi libnewlib-dev qtbase5-dev libbz2-dev libbluetooth-dev ``` If you don't need the native Bluetooth support in the client, you can skip the installation of `libbluetooth-dev`. If you don't need the graphical components of the Proxmark3 client (such as in `hw tune`), you can skip the installation of `qtbase5-dev`. -If you don't need the debugging packages, you can skip the installation of `binutils-arm-none-eabi`,`gdb`,`openocd` and `gdb-multiarch`. - If you get some (non blocking) error at runtime such as _Gtk-Message: Failed to load module "canberra-gtk-module"_ you may have to install `libcanberra-gtk-module`. ## On ArchLinux @@ -115,25 +112,3 @@ It must return `ok`. Otherwise this means you've got a permission problem to fix # Compile and use the project Now you're ready to follow the [compilation instructions](/doc/md/Use_of_Proxmark/0_Compilation-Instructions.md). - - -## (Optional) Visual Studio Code debugging - -Download and install [Visual Studio Code](https://code.visualstudio.com/) - -Download and install [J-Link Software and Documentation pack](https://www.segger.com/downloads/jlink) - -On some systems `arm-none-eabi-gdb` was replaced with `gdb-multiarch`. In order to use the J-Link debugger you need to link `arm-none-eabi-gdb` to `gdb-multiarch`: -```sh -ln -s /usr/bin/gdb-multiarch /usr/bin/arm-none-eabi-gdb -``` - -Setup the Visual Studio Code configuration, by going into your project folder and run: -```sh -./.vscode/setup.sh -``` - -now launch Visual Studio Code and open your project folder - -_note_ -Please install the recommended Visual Studio Code extensions in order for debugging to work. diff --git a/doc/md/Installation_Instructions/VSCode-Installation-Instructions.md b/doc/md/Installation_Instructions/VSCode-Installation-Instructions.md new file mode 100644 index 000000000..079f301f6 --- /dev/null +++ b/doc/md/Installation_Instructions/VSCode-Installation-Instructions.md @@ -0,0 +1,72 @@ +# Visual Studio Code for debugging + +Download and install [Visual Studio Code](https://code.visualstudio.com/) + +Download and install [J-Link Software and Documentation pack](https://www.segger.com/downloads/jlink) + + +## Debian / Ubuntu / Kali / ParrotOS / Raspbian + +Install dependencies + +```sh +sudo apt-get install --no-install-recommends binutils-arm-none-eabi gdb openocd gdb-multiarch +``` + +On some systems `arm-none-eabi-gdb` was replaced with `gdb-multiarch`. In order to use the J-Link debugger you need to link `arm-none-eabi-gdb` to `gdb-multiarch`: +```sh +ln -s /usr/bin/gdb-multiarch /usr/bin/arm-none-eabi-gdb +``` + +Setup the Visual Studio Code configuration, by going into your project folder and run: +```sh +./.vscode/setup.sh +``` + +now launch Visual Studio Code and open your project folder + + +## Windows: WSL + +Enter WSL prompt (`wsl` or `start windows terminal`) + +Install dependencies +```sh +sudo apt-get install --no-install-recommends binutils-arm-none-eabi gdb openocd gdb-multiarch +``` + +The J-Link debugger requires `arm-none-eabi-gdb` which was replaced with `gdb-multiarch`. In order to use the J-Link debugger link `arm-none-eabi-gdb` to `gdb-multiarch`: +```sh +sudo ln -s /usr/bin/gdb-multiarch /usr/bin/arm-none-eabi-gdb +``` + +Setup the Visual Studio Code configuration, by going into your project folder and run: +```sh +./.vscode/setup.sh +``` + +and launch Visual Studio Code +```sh +code . +``` + + +## Windows: ProxSpace + +Download and install [Visual Studio Code](https://code.visualstudio.com/) + +Download and install [J-Link Software and Documentation pack for Windows](https://www.segger.com/downloads/jlink/JLink_Windows.exe) + +Enter PorxSpace (`runme64.bat`) and enter your project folder. + +Setup the Visual Studio Code configuration, by running: +```sh +./.vscode/setup.sh +``` + +now launch Visual Studio Code and open your project folder + + + +_note_ +Please install the recommended Visual Studio Code extensions in order for debugging to work. \ No newline at end of file diff --git a/doc/md/Installation_Instructions/Windows-Installation-Instructions.md b/doc/md/Installation_Instructions/Windows-Installation-Instructions.md index 80f5b4d5c..6000f42f2 100644 --- a/doc/md/Installation_Instructions/Windows-Installation-Instructions.md +++ b/doc/md/Installation_Instructions/Windows-Installation-Instructions.md @@ -64,24 +64,6 @@ To use the compiled client, the only differences are that executables end with ` Now you're ready to follow the [compilation instructions](/doc/md/Use_of_Proxmark/0_Compilation-Instructions.md). -## (Optional) Visual Studio Code debugging - -Download and install [Visual Studio Code](https://code.visualstudio.com/) - -Download and install [J-Link Software and Documentation pack for Windows](https://www.segger.com/downloads/jlink/JLink_Windows.exe) - -Enter PorxSpace (`runme64.bat`) and enter your project folder. - -Setup the Visual Studio Code configuration, by running: -```sh -./.vscode/setup.sh -``` - -now launch Visual Studio Code and open your project folder - -_note_ -Please install the recommended Visual Studio Code extensions in order for debugging to work. - # Installing on Windows with WSL 1 WSL 1 requires to run on Windows 10 version 1709 or above. Previous windows versions didn't have support for COM ports. @@ -167,33 +149,3 @@ Note that it may take a quite long time for a freshly plugged Proxmark3 to be vi Now you're ready to follow the [compilation instructions](/doc/md/Use_of_Proxmark/0_Compilation-Instructions.md). - -## (Optional) Visual Studio Code debugging - -Download and install [Visual Studio Code](https://code.visualstudio.com/) - -Download and install [J-Link Software and Documentation pack for Windows](https://www.segger.com/downloads/jlink/JLink_Windows.exe) - -Enter WSL prompt (`wsl` or `start windows terminal`) and from there, follow the [Linux Installation Instructions](/doc/md/Installation_Instructions/Linux-Installation-Instructions.md) for Ubuntu, summarized here below: - -Install dependencies -```sh -sudo apt-get install --no-install-recommends binutils-arm-none-eabi gdb openocd gdb-multiarch -``` - -The J-Link debugger requires `arm-none-eabi-gdb` which was replaced with `gdb-multiarch`. In order to use the J-Link debugger link `arm-none-eabi-gdb` to `gdb-multiarch`: -```sh -sudo ln -s /usr/bin/gdb-multiarch /usr/bin/arm-none-eabi-gdb -``` - -Setup the Visual Studio Code configuration, by going into your project folder and run: -```sh -./.vscode/setup.sh -``` - -and launch Visual Studio Code -```sh -code . -``` -_note_ -Please install the recommended Visual Studio Code extensions in order for debugging to work. From f4c632bd313172ea7620f565f8ae048d3dbb262e Mon Sep 17 00:00:00 2001 From: gator96100 Date: Wed, 30 Dec 2020 00:19:21 +0100 Subject: [PATCH 250/682] Added DEBUG_ARM flag --- .vscode/tasks.json | 2 +- Makefile.defs | 5 +++++ common_arm/Makefile.hal | 2 +- 3 files changed, 7 insertions(+), 2 deletions(-) diff --git a/.vscode/tasks.json b/.vscode/tasks.json index 463377982..67f0f235e 100644 --- a/.vscode/tasks.json +++ b/.vscode/tasks.json @@ -71,7 +71,7 @@ },{ "label": "fullimage: clean & make debug", "type": "shell", - "command": "make armsrc/clean && make armsrc/all SKIP_COMPRESSION=1 DEBUG=1", + "command": "make armsrc/clean && make armsrc/all DEBUG_ARM=1", "problemMatcher": [ "$gcc" ], diff --git a/Makefile.defs b/Makefile.defs index 48567214b..b86b477aa 100644 --- a/Makefile.defs +++ b/Makefile.defs @@ -66,6 +66,11 @@ else DEFCFLAGS = -Wall -Werror -O3 -fstrict-aliasing -pipe DEFLDFLAGS = endif + +ifeq ($(DEBUG_ARM),1) + APP_CFLAGS += -g + SKIP_COMPRESSION=1 +endif # Next ones are activated only if SANITIZE=1 ifeq ($(SANITIZE),1) DEFCFLAGS += -g -fsanitize=address -fno-omit-frame-pointer diff --git a/common_arm/Makefile.hal b/common_arm/Makefile.hal index b6519e4ab..bfbe56d34 100644 --- a/common_arm/Makefile.hal +++ b/common_arm/Makefile.hal @@ -138,7 +138,7 @@ ifneq ($(SKIP_HFPLOT),1) PLATFORM_DEFS += -DWITH_HFPLOT endif ifeq ($(SKIP_COMPRESSION),1) - PLATFORM_DEFS += -DWITH_NO_COMPRESSION -g + PLATFORM_DEFS += -DWITH_NO_COMPRESSION endif # Standalone mode From e3710bbdddb4121497d7df30c1816caeb6ee3b90 Mon Sep 17 00:00:00 2001 From: Philippe Teuwen Date: Wed, 30 Dec 2020 01:13:17 +0100 Subject: [PATCH 251/682] update doc --- doc/md/Development/Makefile-vs-CMake.md | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/doc/md/Development/Makefile-vs-CMake.md b/doc/md/Development/Makefile-vs-CMake.md index 6fa95066c..1a7a0ddb5 100644 --- a/doc/md/Development/Makefile-vs-CMake.md +++ b/doc/md/Development/Makefile-vs-CMake.md @@ -15,6 +15,7 @@ At the moment both are maintained because they don't perfectly overlap yet. |-----|---|---|---| | verbose | `V=1` | `VERBOSE=1` | | | debug build | `DEBUG=1` | `-DCMAKE_BUILD_TYPE=Debug` | client only | +| ARM debug build | `DEBUG_ARM=1` | **no** | for use with JLink and VSCode | | warnings management | yes (1) | **no** | (1) cf Makefile.defs | | extra GCC warnings | GCCEXTRA=1 | **no** | | | extra Clang warnings | CLANGEXTRA=1 | **no** | only on host | @@ -83,7 +84,13 @@ At the moment both are maintained because they don't perfectly overlap yet. `makefile` only at the moment -`PLATFORM`, `PLATFORM_EXTRAS`, `DESTDIR`, `PREFIX`, `FWTAG` +Supposedly via `Makefile.platform`: + +`PLATFORM`, `PLATFORM_SIZE`, `PLATFORM_EXTRAS`, `SKIP_*`, `STANDALONE` + +Other: + +`DESTDIR`, `PREFIX`, `FWTAG` ## Global From 0f833018254edf1bfba08ba68df0f9e030f713ae Mon Sep 17 00:00:00 2001 From: Philippe Teuwen Date: Wed, 30 Dec 2020 01:30:30 +0100 Subject: [PATCH 252/682] update doc --- doc/md/Development/Makefile-vs-CMake.md | 32 ++++++++++++++++++------- 1 file changed, 23 insertions(+), 9 deletions(-) diff --git a/doc/md/Development/Makefile-vs-CMake.md b/doc/md/Development/Makefile-vs-CMake.md index 1a7a0ddb5..675ba0e96 100644 --- a/doc/md/Development/Makefile-vs-CMake.md +++ b/doc/md/Development/Makefile-vs-CMake.md @@ -15,11 +15,10 @@ At the moment both are maintained because they don't perfectly overlap yet. |-----|---|---|---| | verbose | `V=1` | `VERBOSE=1` | | | debug build | `DEBUG=1` | `-DCMAKE_BUILD_TYPE=Debug` | client only | -| ARM debug build | `DEBUG_ARM=1` | **no** | for use with JLink and VSCode | | warnings management | yes (1) | **no** | (1) cf Makefile.defs | -| extra GCC warnings | GCCEXTRA=1 | **no** | | -| extra Clang warnings | CLANGEXTRA=1 | **no** | only on host | -| AddressSanitize | SANITIZE=1 | **no** | only on host | +| extra GCC warnings | `GCCEXTRA=1` | **no** | | +| extra Clang warnings | `CLANGEXTRA=1` | **no** | only on host | +| AddressSanitize | `SANITIZE=1` | **no** | only on host | | compilation | in place | in build dir | | | user `CFLAGS`/`LDFLAGS` | envvars honored (1) | envvars honored (2) | (1) also `LDLIBS` and `INCLUDES_CLIENT` for more tuning (2) only at first cmake call | | Mingw gnu printf | `_ISOC99_SOURCE` | `_ISOC99_SOURCE` | and in cbor.h: `__attribute__((format (__MINGW_PRINTF_FORMAT, 2, 3)))`| @@ -78,19 +77,34 @@ At the moment both are maintained because they don't perfectly overlap yet. `makefile` only at the moment -`SKIPGPU` +| Feature | Makefile | Remarks | +|-----|---|---| +| Skip GPU-dependent code | `SKIPGPU=1` | to skip ht2crack5gpu tool when compiling the hitag2crack toolsuite | ## ARM `makefile` only at the moment -Supposedly via `Makefile.platform`: +### Features to be used via `Makefile.platform`: -`PLATFORM`, `PLATFORM_SIZE`, `PLATFORM_EXTRAS`, `SKIP_*`, `STANDALONE` +`SKIP_*`, `STANDALONE` -Other: +| Feature | Makefile | Remarks | +|-----|---|---| +| Platform choice | `PLATFORM=` | values: `PM3RDV4`, `PM3OTHER` | +| Platform size | `PLATFORM_SIZE=` | values: `256`, `512` | +| Platform extras | `PLATFORM_EXTRAS=` | values: `BTADDON`, `FPC_USART_DEV` | +| Skip LF/HF techs in the firmware | `SKIP_`*`=1` | see `common_arm/Makefile.hal` for a list | +| Standalone mode choice | `STANDALONE=` | see `doc/md/Use_of_Proxmark/4_Advanced-compilation-parameters.md` for a list | -`DESTDIR`, `PREFIX`, `FWTAG` +### Other features: + +| Feature | Makefile | Remarks | +|-----|---|---| +| ARM debug build | `DEBUG_ARM=1` | to be used with JLink and VSCode | +| Install dest dir | `DESTDIR=` | for maintainers | +| Install prefix dir | `PREFIX=` | for maintainers | +| Tag firmware image | `FWTAG=` | for maintainers | ## Global From a0e110941a502bc2135f53b1883c655ba117c331 Mon Sep 17 00:00:00 2001 From: Philippe Teuwen Date: Wed, 30 Dec 2020 01:31:40 +0100 Subject: [PATCH 253/682] make style --- armsrc/appmain.c | 4 +-- armsrc/start.c | 12 ++++----- client/luascripts/hf_mfu_setuid.lua | 10 ++++---- client/src/cmdhfmfu.c | 40 ++++++++++++++--------------- doc/commands.md | 4 +-- 5 files changed, 35 insertions(+), 35 deletions(-) diff --git a/armsrc/appmain.c b/armsrc/appmain.c index b4c3d6a30..480a8632b 100644 --- a/armsrc/appmain.c +++ b/armsrc/appmain.c @@ -314,9 +314,9 @@ static void SendVersion(void) { struct p payload; payload.id = *(AT91C_DBGU_CIDR); #ifdef WITH_NO_COMPRESSION - payload.section_size = (uint32_t)&_bootrom_end - (uint32_t)&_bootrom_start + (uint32_t)&__os_size__; + payload.section_size = (uint32_t)&_bootrom_end - (uint32_t)&_bootrom_start + (uint32_t)&__os_size__; #else - payload.section_size = text_and_rodata_section_size + compressed_data_section_size; + payload.section_size = text_and_rodata_section_size + compressed_data_section_size; #endif payload.versionstr_len = strlen(VersionString) + 1; memcpy(payload.versionstr, VersionString, payload.versionstr_len); diff --git a/armsrc/start.c b/armsrc/start.c index 542b9f3f4..011742447 100644 --- a/armsrc/start.c +++ b/armsrc/start.c @@ -50,23 +50,23 @@ void Vector(void) { common_area.version = 1; } common_area.flags.osimage_present = 1; - + #ifdef WITH_NO_COMPRESSION - /* Set up data segment: Copy from flash to ram */ + /* Set up data segment: Copy from flash to ram */ char *src = &__data_src_start__; char *dst = &__data_start__; char *end = &__data_end__; - while(dst < end) *dst++ = *src++; - dst = &__bss_start__; + while (dst < end) *dst++ = *src++; + dst = &__bss_start__; end = &__bss_end__; #else - uncompress_data_section(); + uncompress_data_section(); /* Set up (that is: clear) BSS. */ char *dst = &__bss_start__; char *end = &__bss_end__; #endif - + while (dst < end) *dst++ = 0; AppMain(); diff --git a/client/luascripts/hf_mfu_setuid.lua b/client/luascripts/hf_mfu_setuid.lua index f64d5cfab..921563ed6 100644 --- a/client/luascripts/hf_mfu_setuid.lua +++ b/client/luascripts/hf_mfu_setuid.lua @@ -73,7 +73,7 @@ end --- Set UID on magic command enabled function magicUID(b0, b1, b2, isgen1a) - if isgen1a then + if isgen1a then print('Using backdoor Magic tag (gen1a) function') else print('Using backdoor Magic tag (gen1b) function') @@ -81,21 +81,21 @@ function magicUID(b0, b1, b2, isgen1a) -- write block 0 core.console('hf 14a raw -k -a -b 7 40') - if isgen1a then + if isgen1a then core.console('hf 14a raw -k -a 43') end core.console('hf 14a raw -c -a A200'..b0) -- write block 1 core.console('hf 14a raw -k -a -b 7 40') - if isgen1a then + if isgen1a then core.console('hf 14a raw -k -a 43') end core.console('hf 14a raw -c -a A201'..b1) -- write block 2 core.console('hf 14a raw -k -a -b 7 40') - if isgen1a then + if isgen1a then core.console('hf 14a raw -k -a 43') end core.console('hf 14a raw -c -a A202'..b2) @@ -154,7 +154,7 @@ function main(args) core.clearCommandBuffer() - if tagtype == 3 then + if tagtype == 3 then brickableUID(block0, block1, block2) else local is_gen1a = (tagtype == 1) diff --git a/client/src/cmdhfmfu.c b/client/src/cmdhfmfu.c index 2c89cdf73..2a32e0a8d 100644 --- a/client/src/cmdhfmfu.c +++ b/client/src/cmdhfmfu.c @@ -675,10 +675,10 @@ int ul_print_type(uint32_t tagtype, uint8_t spaces) { if (ismagic) snprintf(typestr + strlen(typestr), 4, " ("); - snprintf(typestr + strlen(typestr) , sizeof(typestr) - strlen(typestr), " %s ", (tagtype & MAGIC) ? _GREEN_("magic") : ""); + snprintf(typestr + strlen(typestr), sizeof(typestr) - strlen(typestr), " %s ", (tagtype & MAGIC) ? _GREEN_("magic") : ""); tagtype ^= MAGIC; - snprintf(typestr + strlen(typestr) , sizeof(typestr) - strlen(typestr), "%s", (tagtype & MAGIC_1A) ? _GREEN_("Gen 1a") : ""); - snprintf(typestr + strlen(typestr) , sizeof(typestr) - strlen(typestr), "%s", (tagtype & MAGIC_1B) ? _GREEN_("Gen 1b") : ""); + snprintf(typestr + strlen(typestr), sizeof(typestr) - strlen(typestr), "%s", (tagtype & MAGIC_1A) ? _GREEN_("Gen 1a") : ""); + snprintf(typestr + strlen(typestr), sizeof(typestr) - strlen(typestr), "%s", (tagtype & MAGIC_1B) ? _GREEN_("Gen 1b") : ""); if (ismagic) snprintf(typestr + strlen(typestr), 4, " )"); @@ -840,9 +840,9 @@ static int ulev1_print_counters(void) { if (len == 3) { PrintAndLogEx(INFO, " [%0d]: %s", i, sprint_hex(counter, 3)); PrintAndLogEx(SUCCESS, " - %02X tearing (%s)" - , tear[0] - , (tear[0] == 0xBD) ? _GREEN_("ok") : _RED_("fail") - ); + , tear[0] + , (tear[0] == 0xBD) ? _GREEN_("ok") : _RED_("fail") + ); } } return len; @@ -938,7 +938,7 @@ static int ulev1_print_signature(TagTypeUL_t tagtype, uint8_t *uid, uint8_t *sig PrintAndLogEx(INFO, "IC signature public key value: %s", nxp_mfu_public_keys[i].value); PrintAndLogEx(INFO, " Elliptic curve parameters: NID_secp128r1"); PrintAndLogEx(INFO, " TAG IC Signature: %s", sprint_hex_inrow(signature, signature_len)); - PrintAndLogEx(SUCCESS, " Signature verification (" _GREEN_("successful") ")" ); + PrintAndLogEx(SUCCESS, " Signature verification (" _GREEN_("successful") ")"); return PM3_SUCCESS; } @@ -969,9 +969,9 @@ static int ntag_print_counter(void) { (void)len; PrintAndLogEx(INFO, " [02]: %s", sprint_hex(counter, 3)); PrintAndLogEx(SUCCESS, " - %02X tearing (%s)" - , tear[0] - , (tear[0] == 0xBD) ? _GREEN_("ok") : _RED_("fail") - ); + , tear[0] + , (tear[0] == 0xBD) ? _GREEN_("ok") : _RED_("fail") + ); return len; } @@ -1513,7 +1513,7 @@ static int CmdHF14AMfUWrBl(const char *Cmd) { ); void *argtable[] = { - arg_param_begin, + arg_param_begin, arg_str0("k", "key", "", "key for authentication (UL-C 16 bytes, EV1/NTAG 4 bytes)"), arg_lit0("l", NULL, "swap entered key's endianness"), arg_int1("b", "block", "", "block number to write"), @@ -1540,7 +1540,7 @@ static int CmdHF14AMfUWrBl(const char *Cmd) { has_auth_key = true; } else if (ak_len == 4) { has_pwd = true; - } else if (ak_len != 0){ + } else if (ak_len != 0) { PrintAndLogEx(WARNING, "ERROR: Key is incorrect length\n"); return PM3_EINVARG; } @@ -1559,7 +1559,7 @@ static int CmdHF14AMfUWrBl(const char *Cmd) { // starting with getting tagtype TagTypeUL_t tagtype = GetHF14AMfU_Type(); - if (tagtype == UL_ERROR) + if (tagtype == UL_ERROR) return PM3_ESOFT; uint8_t maxblockno = 0; @@ -1576,7 +1576,7 @@ static int CmdHF14AMfUWrBl(const char *Cmd) { // Swap endianness if (swap_endian) { - if (has_auth_key) + if (has_auth_key) authKeyPtr = SwapEndian64(authenticationkey, 16, 8); if (has_pwd) @@ -1591,7 +1591,7 @@ static int CmdHF14AMfUWrBl(const char *Cmd) { if (ak_len) { PrintAndLogEx(INFO, "Using %s " _GREEN_("%s"), (ak_len == 16) ? "3des" : "pwd", sprint_hex(authenticationkey, ak_len)); } - + //Send write Block // 4 or 16. @@ -1643,7 +1643,7 @@ static int CmdHF14AMfURdBl(const char *Cmd) { ); void *argtable[] = { - arg_param_begin, + arg_param_begin, arg_str0("k", "key", "", "key for authentication (UL-C 16 bytes, EV1/NTAG 4 bytes)"), arg_lit0("l", NULL, "swap entered key's endianness"), arg_int1("b", "block", "", "block number to write"), @@ -1664,7 +1664,7 @@ static int CmdHF14AMfURdBl(const char *Cmd) { has_auth_key = true; } else if (ak_len == 4) { has_pwd = true; - } else if (ak_len != 0){ + } else if (ak_len != 0) { PrintAndLogEx(WARNING, "ERROR: Key is incorrect length\n"); return PM3_EINVARG; } @@ -1704,7 +1704,7 @@ static int CmdHF14AMfURdBl(const char *Cmd) { if (ak_len) { PrintAndLogEx(INFO, "Using %s " _GREEN_("%s"), (ak_len == 16) ? "3des" : "pwd", sprint_hex(authenticationkey, ak_len)); - } + } //Read Block uint8_t keytype = 0; @@ -1932,13 +1932,13 @@ static int CmdHF14AMfUDump(const char *Cmd) { has_auth_key = true; } else if (ak_len == 4) { has_pwd = true; - } else if (ak_len != 0){ + } else if (ak_len != 0) { PrintAndLogEx(WARNING, "ERROR: Key is incorrect length\n"); return PM3_EINVARG; } bool manual_pages = false; - if ( start_page > 0) + if (start_page > 0) manual_pages = true; if (pages != 16) diff --git a/doc/commands.md b/doc/commands.md index e1e445296..991f4a590 100644 --- a/doc/commands.md +++ b/doc/commands.md @@ -198,8 +198,8 @@ Check column "offline" for their availability. |command |offline |description |------- |------- |----------- |`hf epa help `|Y |`This help` -|`hf epa cnonces `|N |` Acquire n>0 encrypted PACE nonces of size m>0 with d sec pauses` -|`hf epa preplay `|N |` Perform PACE protocol by replaying given APDUs` +|`hf epa cnonces `|N |`Acquire encrypted PACE nonces of specific size` +|`hf epa preplay `|N |`Perform PACE protocol by replaying given APDUs` ### hf emrtd From b0f122528df093c2df5dd9dccb2ce3a1988dc069 Mon Sep 17 00:00:00 2001 From: Philippe Teuwen Date: Wed, 30 Dec 2020 01:36:44 +0100 Subject: [PATCH 254/682] minor --- armsrc/start.c | 21 +++++++++------------ 1 file changed, 9 insertions(+), 12 deletions(-) diff --git a/armsrc/start.c b/armsrc/start.c index 011742447..062a83eb9 100644 --- a/armsrc/start.c +++ b/armsrc/start.c @@ -51,23 +51,20 @@ void Vector(void) { } common_area.flags.osimage_present = 1; -#ifdef WITH_NO_COMPRESSION /* Set up data segment: Copy from flash to ram */ - char *src = &__data_src_start__; - char *dst = &__data_start__; - char *end = &__data_end__; - while (dst < end) *dst++ = *src++; - dst = &__bss_start__; - end = &__bss_end__; +#ifdef WITH_NO_COMPRESSION + char *data_src = &__data_src_start__; + char *data_dst = &__data_start__; + char *data_end = &__data_end__; + while (data_dst < data_end) *data_dst++ = *data_src++; #else uncompress_data_section(); - - /* Set up (that is: clear) BSS. */ - char *dst = &__bss_start__; - char *end = &__bss_end__; #endif - while (dst < end) *dst++ = 0; + /* Set up (that is: clear) BSS. */ + char *bss_dst = &__bss_start__; + char *bss_end = &__bss_end__; + while (bss_dst < bss_end) *bss_dst++ = 0; AppMain(); } From 49990ab11d01f1758e3723a6b0f74ee5a9ebc0ad Mon Sep 17 00:00:00 2001 From: tcprst Date: Tue, 29 Dec 2020 20:58:13 -0500 Subject: [PATCH 255/682] hf 14a cuids, sim - now use cliparser --- client/luascripts/hf_mf_uidbruteforce.lua | 4 +- client/src/cmdhf14a.c | 177 ++++++++++------------ client/src/cmdhfst.c | 2 +- doc/cliparser_todo.txt | 2 - doc/commands.md | 4 +- tools/pm3_amii_bin2eml.pl | 4 +- 6 files changed, 87 insertions(+), 106 deletions(-) diff --git a/client/luascripts/hf_mf_uidbruteforce.lua b/client/luascripts/hf_mf_uidbruteforce.lua index fc85b63bb..548898606 100644 --- a/client/luascripts/hf_mf_uidbruteforce.lua +++ b/client/luascripts/hf_mf_uidbruteforce.lua @@ -99,10 +99,10 @@ local function main(args) local command = '' if mftype == 'mfc' then - command = 'hf 14a sim t 1 u %014x' + command = 'hf 14a sim -t 1 -u %014x' msg('Bruteforcing Mifare Classic card numbers') elseif mftype == 'mfu' then - command = 'hf 14a sim t 2 u %014x' + command = 'hf 14a sim -t 2 -u %014x' msg('Bruteforcing Mifare Ultralight card numbers') else return print(usage) diff --git a/client/src/cmdhf14a.c b/client/src/cmdhf14a.c index 3cee04ecf..8a6ce45ef 100644 --- a/client/src/cmdhf14a.c +++ b/client/src/cmdhf14a.c @@ -209,34 +209,6 @@ static int usage_hf_14a_config(void) { return PM3_SUCCESS; } -static int usage_hf_14a_sim(void) { - PrintAndLogEx(NORMAL, "\n Emulating ISO/IEC 14443 type A tag with 4,7 or 10 byte UID\n"); - PrintAndLogEx(NORMAL, "Usage: hf 14a sim [h] t u [n ] [x] [e] [v]"); - PrintAndLogEx(NORMAL, "Options:"); - PrintAndLogEx(NORMAL, " h : This help"); - PrintAndLogEx(NORMAL, " t : 1 = MIFARE Classic 1k"); - PrintAndLogEx(NORMAL, " 2 = MIFARE Ultralight"); - PrintAndLogEx(NORMAL, " 3 = MIFARE Desfire"); - PrintAndLogEx(NORMAL, " 4 = ISO/IEC 14443-4"); - PrintAndLogEx(NORMAL, " 5 = MIFARE Tnp3xxx"); - PrintAndLogEx(NORMAL, " 6 = MIFARE Mini"); - PrintAndLogEx(NORMAL, " 7 = AMIIBO (NTAG 215), pack 0x8080"); - PrintAndLogEx(NORMAL, " 8 = MIFARE Classic 4k"); - PrintAndLogEx(NORMAL, " 9 = FM11RF005SH Shanghai Metro"); - PrintAndLogEx(NORMAL, " 10 = JCOP 31/41 Rothult"); - PrintAndLogEx(NORMAL, " u : 4, 7 or 10 byte UID"); - PrintAndLogEx(NORMAL, " n : (Optional) Exit simulation after blocks have been read by reader. 0 = infinite"); - PrintAndLogEx(NORMAL, " x : (Optional) Performs the 'reader attack', nr/ar attack against a reader"); - PrintAndLogEx(NORMAL, " e : (Optional) Fill simulator keys from found keys"); - PrintAndLogEx(NORMAL, " v : (Optional) Verbose"); - PrintAndLogEx(NORMAL, "Examples:"); - PrintAndLogEx(NORMAL, _YELLOW_(" hf 14a sim t 1 u 11223344 x")); - PrintAndLogEx(NORMAL, _YELLOW_(" hf 14a sim t 1 u 11223344")); - PrintAndLogEx(NORMAL, _YELLOW_(" hf 14a sim t 1 u 11223344556677")); - PrintAndLogEx(NORMAL, _YELLOW_(" hf 14a sim t 1 u 112233445566778899AA")); - return PM3_SUCCESS; -} - static int CmdHF14AList(const char *Cmd) { char args[128] = {0}; if (strlen(Cmd) == 0) { @@ -595,10 +567,23 @@ static int CmdHF14AInfo(const char *Cmd) { // Collect ISO14443 Type A UIDs static int CmdHF14ACUIDs(const char *Cmd) { + CLIParserContext *ctx; + CLIParserInit(&ctx, "hf 14a cuids", + "Collect n>0 ISO14443-a UIDs in one go", + "hf 14a cuids -n 5 <-- Collect 5 UIDs"); + + void *argtable[] = { + arg_param_begin, + arg_int0("n", "num", "", "Number of UIDs to collect"), + arg_param_end + }; + CLIExecWithReturn(ctx, Cmd, argtable, true); + // requested number of UIDs - int n = atoi(Cmd); // collect at least 1 (e.g. if no parameter was given) - n = n > 0 ? n : 1; + int n = arg_get_int_def(ctx, 1, 1); + + CLIParserFree(ctx); uint64_t t1 = msclock(); PrintAndLogEx(SUCCESS, "collecting %d UIDs", n); @@ -633,83 +618,81 @@ static int CmdHF14ACUIDs(const char *Cmd) { PrintAndLogEx(SUCCESS, "end: %" PRIu64 " seconds", (msclock() - t1) / 1000); return 1; } + // ## simulate iso14443a tag int CmdHF14ASim(const char *Cmd) { + CLIParserContext *ctx; + CLIParserInit(&ctx, "hf 14a sim", + "Simulate ISO/IEC 14443 type A tag with 4,7 or 10 byte UID", + "hf 14a sim -t 1 --uid 11223344 -> MIFARE Classic 1k\n" + "hf 14a sim -t 2 -> MIFARE Ultralight\n" + "hf 14a sim -t 3 -> MIFARE Desfire\n" + "hf 14a sim -t 4 -> ISO/IEC 14443-4\n" + "hf 14a sim -t 5 -> MIFARE Tnp3xxx\n" + "hf 14a sim -t 6 -> MIFARE Mini\n" + "hf 14a sim -t 7 -> AMIIBO (NTAG 215), pack 0x8080\n" + "hf 14a sim -t 8 -> MIFARE Classic 4k\n" + "hf 14a sim -t 9 -> FM11RF005SH Shanghai Metro\n" + "hf 14a sim -t 10 -> ST25TA IKEA Rothult\n"); - int uidlen = 0; - uint8_t flags = 0, tagtype = 1, cmdp = 0; - uint8_t uid[10] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; + void *argtable[] = { + arg_param_begin, + arg_int1("t", "type", "<1-10> ", "Simulation type to use"), + arg_str0("u", "uid", "", "4, 7 or 10 byte UID"), + arg_int0("n", "num", "", "Exit simulation after blocks have been read by reader. 0 = infinite"), + arg_lit0(NULL, "nr", "Performs the 'reader attack', nr/ar attack against a reader"), + arg_lit0(NULL, "sk", "Fill simulator keys from found keys"), + arg_lit0("v", "verbose", "verbose output"), + arg_param_end + }; + CLIExecWithReturn(ctx, Cmd, argtable, false); + + int tagtype = arg_get_int(ctx, 1); + + int uid_len = 0; + uint8_t uid[10] = {0}; + CLIGetHexWithReturn(ctx, 2, uid, &uid_len); + + uint8_t flags = 0; bool useUIDfromEML = true; - bool setEmulatorMem = false; - bool verbose = false; - bool errors = false; - sector_t *k_sector = NULL; - uint8_t k_sectorsCount = 40; - uint8_t exitAfterNReads = 0; - while (param_getchar(Cmd, cmdp) != 0x00 && !errors) { - switch (tolower(param_getchar(Cmd, cmdp))) { - case 'h': - return usage_hf_14a_sim(); - case 't': - // Retrieve the tag type - tagtype = param_get8ex(Cmd, cmdp + 1, 0, 10); - if (tagtype == 0) - errors = true; - cmdp += 2; + if (uid_len > 0) { + switch (uid_len) { + case 10: + flags |= FLAG_10B_UID_IN_DATA; break; - case 'u': - // Retrieve the full 4,7,10 byte long uid - param_gethex_ex(Cmd, cmdp + 1, uid, &uidlen); - uidlen >>= 1; - switch (uidlen) { - case 10: - flags |= FLAG_10B_UID_IN_DATA; - break; - case 7: - flags |= FLAG_7B_UID_IN_DATA; - break; - case 4: - flags |= FLAG_4B_UID_IN_DATA; - break; - default: - errors = true; - break; - } - if (!errors) { - PrintAndLogEx(SUCCESS, "Emulating " _YELLOW_("ISO/IEC 14443 type A tag")" with " _GREEN_("%d byte UID (%s)"), uidlen, sprint_hex(uid, uidlen)); - useUIDfromEML = false; - } - cmdp += 2; + case 7: + flags |= FLAG_7B_UID_IN_DATA; break; - case 'n': - exitAfterNReads = param_get8(Cmd, cmdp + 1); - cmdp += 2; - break; - case 'v': - verbose = true; - cmdp++; - break; - case 'x': - flags |= FLAG_NR_AR_ATTACK; - cmdp++; - break; - case 'e': - setEmulatorMem = true; - cmdp++; + case 4: + flags |= FLAG_4B_UID_IN_DATA; break; default: - PrintAndLogEx(WARNING, "Unknown parameter " _RED_("'%c'"), param_getchar(Cmd, cmdp)); - errors = true; - break; + PrintAndLogEx(ERR, "Please specify a 4, 7, or 10 byte UID"); + CLIParserFree(ctx); + return PM3_EINVARG; } + PrintAndLogEx(SUCCESS, "Emulating " _YELLOW_("ISO/IEC 14443 type A tag")" with " _GREEN_("%d byte UID (%s)"), uid_len, sprint_hex(uid, uid_len)); + useUIDfromEML = false; } - //Validations - if (errors || cmdp == 0) return usage_hf_14a_sim(); + uint8_t exitAfterNReads = arg_get_int(ctx, 3); - if (useUIDfromEML) + if (arg_get_lit(ctx, 4)) { + flags |= FLAG_NR_AR_ATTACK; + } + + bool setEmulatorMem = arg_get_lit(ctx, 5); + bool verbose = arg_get_lit(ctx, 6); + + CLIParserFree(ctx); + + sector_t *k_sector = NULL; + uint8_t k_sectorsCount = 40; + + if (useUIDfromEML) { flags |= FLAG_UID_IN_EMUL; + } struct { uint8_t tagtype; @@ -721,7 +704,7 @@ int CmdHF14ASim(const char *Cmd) { payload.tagtype = tagtype; payload.flags = flags; payload.exitAfter = exitAfterNReads; - memcpy(payload.uid, uid, uidlen); + memcpy(payload.uid, uid, uid_len); clearCommandBuffer(); SendCommandNG(CMD_HF_ISO14443A_SIMULATE, (uint8_t *)&payload, sizeof(payload)); @@ -2327,11 +2310,11 @@ out: static command_t CommandTable[] = { {"help", CmdHelp, AlwaysAvailable, "This help"}, - {"list", CmdHF14AList, AlwaysAvailable, "List ISO 14443-a history"}, + {"list", CmdHF14AList, AlwaysAvailable, "List ISO 14443-a history"}, {"info", CmdHF14AInfo, IfPm3Iso14443a, "Tag information"}, {"reader", CmdHF14AReader, IfPm3Iso14443a, "Act like an ISO14443-a reader"}, - {"cuids", CmdHF14ACUIDs, IfPm3Iso14443a, " Collect n>0 ISO14443-a UIDs in one go"}, - {"sim", CmdHF14ASim, IfPm3Iso14443a, " -- Simulate ISO 14443-a tag"}, + {"cuids", CmdHF14ACUIDs, IfPm3Iso14443a, "Collect n>0 ISO14443-a UIDs in one go"}, + {"sim", CmdHF14ASim, IfPm3Iso14443a, "Simulate ISO 14443-a tag"}, {"sniff", CmdHF14ASniff, IfPm3Iso14443a, "sniff ISO 14443-a traffic"}, {"apdu", CmdHF14AAPDU, IfPm3Iso14443a, "Send ISO 14443-4 APDU to tag"}, {"chaining", CmdHF14AChaining, IfPm3Iso14443a, "Control ISO 14443-4 input chaining"}, diff --git a/client/src/cmdhfst.c b/client/src/cmdhfst.c index 89633de8a..5fc151cc0 100644 --- a/client/src/cmdhfst.c +++ b/client/src/cmdhfst.c @@ -351,7 +351,7 @@ static int cmd_hf_st_sim(const char *Cmd) { } char param[40]; - snprintf(param, sizeof(param), "t 10 u %s", sprint_hex_inrow(uid, uidlen)); + snprintf(param, sizeof(param), "-t 10 -u %s", sprint_hex_inrow(uid, uidlen)); return CmdHF14ASim(param); } diff --git a/doc/cliparser_todo.txt b/doc/cliparser_todo.txt index c9dcf077c..0a5e5c77e 100644 --- a/doc/cliparser_todo.txt +++ b/doc/cliparser_todo.txt @@ -41,8 +41,6 @@ data print data samples data setdebugmode data tune -hf 14a cuids -hf 14a sim hf 14a config hf 14b sriwrite hf 15 dump diff --git a/doc/commands.md b/doc/commands.md index 991f4a590..f10e7a2bf 100644 --- a/doc/commands.md +++ b/doc/commands.md @@ -134,8 +134,8 @@ Check column "offline" for their availability. |`hf 14a list `|Y |`List ISO 14443-a history` |`hf 14a info `|N |`Tag information` |`hf 14a reader `|N |`Act like an ISO14443-a reader` -|`hf 14a cuids `|N |` Collect n>0 ISO14443-a UIDs in one go` -|`hf 14a sim `|N |` -- Simulate ISO 14443-a tag` +|`hf 14a cuids `|N |`Collect n>0 ISO14443-a UIDs in one go` +|`hf 14a sim `|N |`Simulate ISO 14443-a tag` |`hf 14a sniff `|N |`sniff ISO 14443-a traffic` |`hf 14a apdu `|N |`Send ISO 14443-4 APDU to tag` |`hf 14a chaining `|N |`Control ISO 14443-4 input chaining` diff --git a/tools/pm3_amii_bin2eml.pl b/tools/pm3_amii_bin2eml.pl index 35c95e8e4..c8e8d4f46 100755 --- a/tools/pm3_amii_bin2eml.pl +++ b/tools/pm3_amii_bin2eml.pl @@ -7,7 +7,7 @@ # -samy kamkar 05/28/2017 # # hf mf eload u FILENAME_MINUS_EML -# hf 14a sim t 7 u UID +# hf 14a sim -t 7 -u UID # perl -lne 'chomp; s/\s+(\S+)$//;$f=$1;if($f=~s/-(\S+)//){$g=hex($1);}else{$g=hex($f)}$f=hex($f); for$m($f..$g){print "0x" . substr(unpack("H4",pack("n",$m)),1) ." => \"$_\","}' /tmp/game >> game2 # perl -lne 'if(/^(\S.*?)\s+\w?\w\w\w\w(\s*-\s*\w?\w\w\w\w)?\s*$/){$l=$1} s/(\w{4,5}\s*-\s*)?(\w{4,5})$//; $a=$1;$b=$2; $b=hex($b); $a=$a?hex($a):$b; for$m($a..$b){print "0x" . substr(unpack("H4",pack("n",$m)),0) ." => \"$l\","}' /tmp/g2 @@ -685,7 +685,7 @@ $uid = uc $uid; #print STDERR "amiitool -d -k ../client/amiitool/key_retail.bin -i $input -o $input.decrypted\n"; $input =~ s/\....$//; print STDERR "hf mf eload u $input\n"; -print STDERR "hf 14a sim t 7 u $uid\n"; +print STDERR "hf 14a sim -t 7 -u $uid\n"; __DATA__ From 714470877af87f8be0870d8b141ef762692e1310 Mon Sep 17 00:00:00 2001 From: tcprst Date: Tue, 29 Dec 2020 21:12:11 -0500 Subject: [PATCH 256/682] lf em 410x - textual --- client/src/cmdlfem410x.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/client/src/cmdlfem410x.c b/client/src/cmdlfem410x.c index c8b11a9db..c2ee95a9d 100644 --- a/client/src/cmdlfem410x.c +++ b/client/src/cmdlfem410x.c @@ -585,8 +585,8 @@ static int CmdEM410xClone(const char *Cmd) { CLIParserContext *ctx; CLIParserInit(&ctx, "lf em 410x clone", "Writes EM410x ID to a T55x7 or Q5/T5555 tag", - "lf em 410x clone --id 0F0368568B -> write id to T55x7 tag\n" - "lf em 410x clone --id 0F0368568B --q5 -> write id to Q5/T5555 tag" + "lf em 410x clone --uid 0F0368568B -> write id to T55x7 tag\n" + "lf em 410x clone --uid 0F0368568B --q5 -> write id to Q5/T5555 tag" ); void *argtable[] = { From 2679ea098091957713fce12a510a6b43d0b4db7d Mon Sep 17 00:00:00 2001 From: Ave Date: Wed, 30 Dec 2020 05:50:25 +0300 Subject: [PATCH 257/682] emrtd info: Split EF_SOD into a separate section (only on offline) --- client/src/cmdhfemrtd.c | 66 ++++++++++++++++++++++++++--------------- 1 file changed, 42 insertions(+), 24 deletions(-) diff --git a/client/src/cmdhfemrtd.c b/client/src/cmdhfemrtd.c index 670ea804d..0a98c58b9 100644 --- a/client/src/cmdhfemrtd.c +++ b/client/src/cmdhfemrtd.c @@ -1689,8 +1689,8 @@ int infoHF_EMRTD(char *documentnumber, char *dob, char *expiry, bool BAC_availab } // Grab the hash list - uint8_t dg_hashes[16][64]; - uint8_t hash_out[64]; + uint8_t dg_hashes_sod[17][64] = { 0x00 }; + uint8_t dg_hashes_calc[17][64] = { 0x00 }; int hash_algo = 0; if (!emrtd_select_and_read(response, &resplen, dg_table[EF_SOD].fileid, ks_enc, ks_mac, ssc, BAC, use_14b)) { @@ -1699,7 +1699,7 @@ int infoHF_EMRTD(char *documentnumber, char *dob, char *expiry, bool BAC_availab return PM3_ESOFT; } - res = emrtd_parse_ef_sod_hashes(response, resplen, *dg_hashes, &hash_algo); + res = emrtd_parse_ef_sod_hashes(response, resplen, *dg_hashes_sod, &hash_algo); if (res != PM3_SUCCESS) { PrintAndLogEx(ERR, "Failed to read hash list from EF_SOD. Hash checks will fail."); } @@ -1719,15 +1719,9 @@ int infoHF_EMRTD(char *documentnumber, char *dob, char *expiry, bool BAC_availab PrintAndLogEx(DEBUG, "EF_DG%i hash algo: %i", dg->dgnum, hash_algo); // Check file hash if (hash_algo != -1) { - PrintAndLogEx(DEBUG, "EF_DG%i hash on EF_SOD: %s", dg->dgnum, sprint_hex_inrow(dg_hashes[dg->dgnum], hashalg_table[hash_algo].hashlen)); - hashalg_table[hash_algo].hasher(response, resplen, hash_out); - PrintAndLogEx(DEBUG, "EF_DG%i hash calc: %s", dg->dgnum, sprint_hex_inrow(hash_out, hashalg_table[hash_algo].hashlen)); - - if (memcmp(dg_hashes[dg->dgnum], hash_out, hashalg_table[hash_algo].hashlen) == 0) { - PrintAndLogEx(SUCCESS, _GREEN_("Hash verification passed for EF_DG%i."), dg->dgnum); - } else { - PrintAndLogEx(ERR, _RED_("Hash verification failed for EF_DG%i."), dg->dgnum); - } + PrintAndLogEx(DEBUG, "EF_DG%i hash on EF_SOD: %s", dg->dgnum, sprint_hex_inrow(dg_hashes_sod[dg->dgnum], hashalg_table[hash_algo].hashlen)); + hashalg_table[hash_algo].hasher(response, resplen, dg_hashes_calc[dg->dgnum]); + PrintAndLogEx(DEBUG, "EF_DG%i hash calc: %s", dg->dgnum, sprint_hex_inrow(dg_hashes_calc[dg->dgnum], hashalg_table[hash_algo].hashlen)); } } } @@ -1771,8 +1765,8 @@ int infoHF_EMRTD_offline(const char *path) { free(data); // Grab the hash list - uint8_t dg_hashes[16][64]; - uint8_t hash_out[64]; + uint8_t dg_hashes_sod[17][64] = { 0x00 }; + uint8_t dg_hashes_calc[17][64] = { 0x00 }; int hash_algo = 0; strcpy(filepath, path); @@ -1785,7 +1779,7 @@ int infoHF_EMRTD_offline(const char *path) { return PM3_ESOFT; } - res = emrtd_parse_ef_sod_hashes(data, datalen, *dg_hashes, &hash_algo); + res = emrtd_parse_ef_sod_hashes(data, datalen, *dg_hashes_sod, &hash_algo); if (res != PM3_SUCCESS) { PrintAndLogEx(ERR, "Failed to read hash list from EF_SOD. Hash checks will fail."); } @@ -1810,21 +1804,45 @@ int infoHF_EMRTD_offline(const char *path) { PrintAndLogEx(DEBUG, "EF_DG%i hash algo: %i", dg->dgnum, hash_algo); // Check file hash if (hash_algo != -1) { - PrintAndLogEx(DEBUG, "EF_DG%i hash on EF_SOD: %s", dg->dgnum, sprint_hex_inrow(dg_hashes[dg->dgnum], hashalg_table[hash_algo].hashlen)); - hashalg_table[hash_algo].hasher(data, datalen, hash_out); - PrintAndLogEx(DEBUG, "EF_DG%i hash calc: %s", dg->dgnum, sprint_hex_inrow(hash_out, hashalg_table[hash_algo].hashlen)); - - if (memcmp(dg_hashes[dg->dgnum], hash_out, hashalg_table[hash_algo].hashlen) == 0) { - PrintAndLogEx(SUCCESS, _GREEN_("Hash verification passed for EF_DG%i."), dg->dgnum); - } else { - PrintAndLogEx(ERR, _RED_("Hash verification failed for EF_DG%i."), dg->dgnum); - } + PrintAndLogEx(DEBUG, "EF_DG%i hash on EF_SOD: %s", dg->dgnum, sprint_hex_inrow(dg_hashes_sod[dg->dgnum], hashalg_table[hash_algo].hashlen)); + hashalg_table[hash_algo].hasher(data, datalen, dg_hashes_calc[dg->dgnum]); + PrintAndLogEx(DEBUG, "EF_DG%i hash calc: %s", dg->dgnum, sprint_hex_inrow(dg_hashes_calc[dg->dgnum], hashalg_table[hash_algo].hashlen)); } free(data); } } } free(filepath); + + PrintAndLogEx(NORMAL, ""); + PrintAndLogEx(INFO, "-------------------- " _CYAN_("EF_SOD") " --------------------"); + + if (hash_algo == -1) { + PrintAndLogEx(SUCCESS, "Hash algorithm: " _YELLOW_("Unknown")); + } else { + PrintAndLogEx(SUCCESS, "Hash algorithm: " _YELLOW_("%s"), hashalg_table[hash_algo].name); + + uint8_t all_zeroes[64] = { 0x00 }; + bool calc_all_zero, sod_all_zero, hash_matches; + for (int i = 1; i <= 16; i++) { + calc_all_zero = (memcmp(dg_hashes_calc[i], all_zeroes, hashalg_table[hash_algo].hashlen) == 0); + sod_all_zero = (memcmp(dg_hashes_sod[i], all_zeroes, hashalg_table[hash_algo].hashlen) == 0); + hash_matches = (memcmp(dg_hashes_sod[i], dg_hashes_calc[i], hashalg_table[hash_algo].hashlen) == 0); + // Ignore files we don't haven't read and lack hashes to + if (calc_all_zero == true && sod_all_zero == true) { + continue; + } else if (calc_all_zero == true) { + PrintAndLogEx(SUCCESS, "EF_DG%i: " _YELLOW_("File read access denied, but is in EF_SOD"), i); + } else if (sod_all_zero == true) { + PrintAndLogEx(SUCCESS, "EF_DG%i: " _YELLOW_("File not in EF_SOD"), i); + } else if (hash_matches == false) { + PrintAndLogEx(SUCCESS, "EF_DG%i: " _RED_("Invalid"), i); + } else { + PrintAndLogEx(SUCCESS, "EF_DG%i: " _GREEN_("Valid"), i); + } + } + } + return PM3_SUCCESS; } From 80f035f7ab0087acdcc330074c6cbfdb189b75c2 Mon Sep 17 00:00:00 2001 From: Ave Date: Wed, 30 Dec 2020 05:57:11 +0300 Subject: [PATCH 258/682] emrtd info: Improve EF_SOD wording --- client/src/cmdhfemrtd.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/client/src/cmdhfemrtd.c b/client/src/cmdhfemrtd.c index 0a98c58b9..72832b112 100644 --- a/client/src/cmdhfemrtd.c +++ b/client/src/cmdhfemrtd.c @@ -1832,9 +1832,9 @@ int infoHF_EMRTD_offline(const char *path) { if (calc_all_zero == true && sod_all_zero == true) { continue; } else if (calc_all_zero == true) { - PrintAndLogEx(SUCCESS, "EF_DG%i: " _YELLOW_("File read access denied, but is in EF_SOD"), i); + PrintAndLogEx(SUCCESS, "EF_DG%i: " _YELLOW_("File couldn't be read, but is in EF_SOD."), i); } else if (sod_all_zero == true) { - PrintAndLogEx(SUCCESS, "EF_DG%i: " _YELLOW_("File not in EF_SOD"), i); + PrintAndLogEx(SUCCESS, "EF_DG%i: " _YELLOW_("File is not in EF_SOD."), i); } else if (hash_matches == false) { PrintAndLogEx(SUCCESS, "EF_DG%i: " _RED_("Invalid"), i); } else { From 9f29a839a789842343a3ad0135f3f8c6f4c24708 Mon Sep 17 00:00:00 2001 From: Ave Date: Wed, 30 Dec 2020 06:03:12 +0300 Subject: [PATCH 259/682] emrtd info: Move EF_SOD print to a func, also add to online --- client/src/cmdhfemrtd.c | 65 +++++++++++++++++++++++------------------ 1 file changed, 37 insertions(+), 28 deletions(-) diff --git a/client/src/cmdhfemrtd.c b/client/src/cmdhfemrtd.c index 72832b112..8789656a5 100644 --- a/client/src/cmdhfemrtd.c +++ b/client/src/cmdhfemrtd.c @@ -1638,6 +1638,39 @@ static int emrtd_parse_ef_sod_hashes(uint8_t *data, size_t datalen, uint8_t *has return PM3_SUCCESS; } +static int emrtd_print_ef_sod_info(uint8_t *dg_hashes_calc, uint8_t *dg_hashes_sod, int hash_algo) { + PrintAndLogEx(NORMAL, ""); + PrintAndLogEx(INFO, "-------------------- " _CYAN_("EF_SOD") " --------------------"); + + if (hash_algo == -1) { + PrintAndLogEx(SUCCESS, "Hash algorithm: " _YELLOW_("Unknown")); + } else { + PrintAndLogEx(SUCCESS, "Hash algorithm: " _YELLOW_("%s"), hashalg_table[hash_algo].name); + + uint8_t all_zeroes[64] = { 0x00 }; + bool calc_all_zero, sod_all_zero, hash_matches; + for (int i = 1; i <= 16; i++) { + calc_all_zero = (memcmp(dg_hashes_calc + (i * 64), all_zeroes, hashalg_table[hash_algo].hashlen) == 0); + sod_all_zero = (memcmp(dg_hashes_sod + (i * 64), all_zeroes, hashalg_table[hash_algo].hashlen) == 0); + hash_matches = (memcmp(dg_hashes_sod + (i * 64), dg_hashes_calc + (i * 64), hashalg_table[hash_algo].hashlen) == 0); + // Ignore files we don't haven't read and lack hashes to + if (calc_all_zero == true && sod_all_zero == true) { + continue; + } else if (calc_all_zero == true) { + PrintAndLogEx(SUCCESS, "EF_DG%i: " _YELLOW_("File couldn't be read, but is in EF_SOD."), i); + } else if (sod_all_zero == true) { + PrintAndLogEx(SUCCESS, "EF_DG%i: " _YELLOW_("File is not in EF_SOD."), i); + } else if (hash_matches == false) { + PrintAndLogEx(SUCCESS, "EF_DG%i: " _RED_("Invalid"), i); + } else { + PrintAndLogEx(SUCCESS, "EF_DG%i: " _GREEN_("Valid"), i); + } + } + } + + return PM3_SUCCESS; +} + int infoHF_EMRTD(char *documentnumber, char *dob, char *expiry, bool BAC_available) { uint8_t response[EMRTD_MAX_FILE_SIZE] = { 0x00 }; int resplen = 0; @@ -1727,6 +1760,9 @@ int infoHF_EMRTD(char *documentnumber, char *dob, char *expiry, bool BAC_availab } } DropField(); + + emrtd_print_ef_sod_info(*dg_hashes_calc, *dg_hashes_sod, hash_algo); + return PM3_SUCCESS; } @@ -1814,34 +1850,7 @@ int infoHF_EMRTD_offline(const char *path) { } free(filepath); - PrintAndLogEx(NORMAL, ""); - PrintAndLogEx(INFO, "-------------------- " _CYAN_("EF_SOD") " --------------------"); - - if (hash_algo == -1) { - PrintAndLogEx(SUCCESS, "Hash algorithm: " _YELLOW_("Unknown")); - } else { - PrintAndLogEx(SUCCESS, "Hash algorithm: " _YELLOW_("%s"), hashalg_table[hash_algo].name); - - uint8_t all_zeroes[64] = { 0x00 }; - bool calc_all_zero, sod_all_zero, hash_matches; - for (int i = 1; i <= 16; i++) { - calc_all_zero = (memcmp(dg_hashes_calc[i], all_zeroes, hashalg_table[hash_algo].hashlen) == 0); - sod_all_zero = (memcmp(dg_hashes_sod[i], all_zeroes, hashalg_table[hash_algo].hashlen) == 0); - hash_matches = (memcmp(dg_hashes_sod[i], dg_hashes_calc[i], hashalg_table[hash_algo].hashlen) == 0); - // Ignore files we don't haven't read and lack hashes to - if (calc_all_zero == true && sod_all_zero == true) { - continue; - } else if (calc_all_zero == true) { - PrintAndLogEx(SUCCESS, "EF_DG%i: " _YELLOW_("File couldn't be read, but is in EF_SOD."), i); - } else if (sod_all_zero == true) { - PrintAndLogEx(SUCCESS, "EF_DG%i: " _YELLOW_("File is not in EF_SOD."), i); - } else if (hash_matches == false) { - PrintAndLogEx(SUCCESS, "EF_DG%i: " _RED_("Invalid"), i); - } else { - PrintAndLogEx(SUCCESS, "EF_DG%i: " _GREEN_("Valid"), i); - } - } - } + emrtd_print_ef_sod_info(*dg_hashes_calc, *dg_hashes_sod, hash_algo); return PM3_SUCCESS; } From 5d250339dd7a2d5c5c51b0ba7136ea66539cf300 Mon Sep 17 00:00:00 2001 From: Ave Date: Wed, 30 Dec 2020 06:37:01 +0300 Subject: [PATCH 260/682] emrtd dump: Allow specifying a dump folder --- client/src/cmdhfemrtd.c | 101 ++++++++++++++++++++++++++++++++-------- client/src/cmdhfemrtd.h | 4 +- 2 files changed, 83 insertions(+), 22 deletions(-) diff --git a/client/src/cmdhfemrtd.c b/client/src/cmdhfemrtd.c index 670ea804d..1f9916041 100644 --- a/client/src/cmdhfemrtd.c +++ b/client/src/cmdhfemrtd.c @@ -50,10 +50,10 @@ const uint8_t KENC_type[4] = {0x00, 0x00, 0x00, 0x01}; const uint8_t KMAC_type[4] = {0x00, 0x00, 0x00, 0x02}; -static int emrtd_dump_ef_dg2(uint8_t *file_contents, size_t file_length); -static int emrtd_dump_ef_dg5(uint8_t *file_contents, size_t file_length); -static int emrtd_dump_ef_dg7(uint8_t *file_contents, size_t file_length); -static int emrtd_dump_ef_sod(uint8_t *file_contents, size_t file_length); +static int emrtd_dump_ef_dg2(uint8_t *file_contents, size_t file_length, const char *path); +static int emrtd_dump_ef_dg5(uint8_t *file_contents, size_t file_length, const char *path); +static int emrtd_dump_ef_dg7(uint8_t *file_contents, size_t file_length, const char *path); +static int emrtd_dump_ef_sod(uint8_t *file_contents, size_t file_length, const char *path); static int emrtd_print_ef_com_info(uint8_t *data, size_t datalen); static int emrtd_print_ef_dg1_info(uint8_t *data, size_t datalen); static int emrtd_print_ef_dg11_info(uint8_t *data, size_t datalen); @@ -710,7 +710,7 @@ static bool emrtd_select_and_read(uint8_t *dataout, int *dataoutlen, const char const uint8_t jpeg_header[4] = { 0xFF, 0xD8, 0xFF, 0xE0 }; const uint8_t jpeg2k_header[6] = { 0x00, 0x00, 0x00, 0x0C, 0x6A, 0x50 }; -static int emrtd_dump_ef_dg2(uint8_t *file_contents, size_t file_length) { +static int emrtd_dump_ef_dg2(uint8_t *file_contents, size_t file_length, const char *path) { int offset, datalen = 0; // This is a hacky impl that just looks for the image header. I'll improve it eventually. @@ -730,11 +730,20 @@ static int emrtd_dump_ef_dg2(uint8_t *file_contents, size_t file_length) { return PM3_ESOFT; } - saveFile(dg_table[EF_DG2].filename, file_contents[offset] == 0xFF ? ".jpg" : ".jp2", file_contents + offset, datalen); + char *filepath = calloc(strlen(path) + 100, sizeof(char)); + if (filepath == NULL) + return PM3_EMALLOC; + strcpy(filepath, path); + strncat(filepath, PATHSEP, 2); + strcat(filepath, dg_table[EF_DG2].filename); + + saveFile(filepath, file_contents[offset] == 0xFF ? ".jpg" : ".jp2", file_contents + offset, datalen); + + free(filepath); return PM3_SUCCESS; } -static int emrtd_dump_ef_dg5(uint8_t *file_contents, size_t file_length) { +static int emrtd_dump_ef_dg5(uint8_t *file_contents, size_t file_length, const char *path) { uint8_t data[EMRTD_MAX_FILE_SIZE]; size_t datalen = 0; @@ -744,7 +753,16 @@ static int emrtd_dump_ef_dg5(uint8_t *file_contents, size_t file_length) { } if (datalen < EMRTD_MAX_FILE_SIZE) { - saveFile(dg_table[EF_DG5].filename, data[0] == 0xFF ? ".jpg" : ".jp2", data, datalen); + char *filepath = calloc(strlen(path) + 100, sizeof(char)); + if (filepath == NULL) + return PM3_EMALLOC; + strcpy(filepath, path); + strncat(filepath, PATHSEP, 2); + strcat(filepath, dg_table[EF_DG5].filename); + + saveFile(filepath, data[0] == 0xFF ? ".jpg" : ".jp2", data, datalen); + + free(filepath); } else { PrintAndLogEx(ERR, "error (emrtd_dump_ef_dg5) datalen out-of-bounds"); return PM3_ESOFT; @@ -752,7 +770,7 @@ static int emrtd_dump_ef_dg5(uint8_t *file_contents, size_t file_length) { return PM3_SUCCESS; } -static int emrtd_dump_ef_dg7(uint8_t *file_contents, size_t file_length) { +static int emrtd_dump_ef_dg7(uint8_t *file_contents, size_t file_length, const char *path) { uint8_t data[EMRTD_MAX_FILE_SIZE]; size_t datalen = 0; @@ -762,7 +780,16 @@ static int emrtd_dump_ef_dg7(uint8_t *file_contents, size_t file_length) { } if (datalen < EMRTD_MAX_FILE_SIZE) { - saveFile(dg_table[EF_DG7].filename, data[0] == 0xFF ? ".jpg" : ".jp2", data, datalen); + char *filepath = calloc(strlen(path) + 100, sizeof(char)); + if (filepath == NULL) + return PM3_EMALLOC; + strcpy(filepath, path); + strncat(filepath, PATHSEP, 2); + strcat(filepath, dg_table[EF_DG7].filename); + + saveFile(filepath, data[0] == 0xFF ? ".jpg" : ".jp2", data, datalen); + + free(filepath); } else { PrintAndLogEx(ERR, "error (emrtd_dump_ef_dg7) datalen out-of-bounds"); return PM3_ESOFT; @@ -770,7 +797,7 @@ static int emrtd_dump_ef_dg7(uint8_t *file_contents, size_t file_length) { return PM3_SUCCESS; } -static int emrtd_dump_ef_sod(uint8_t *file_contents, size_t file_length) { +static int emrtd_dump_ef_sod(uint8_t *file_contents, size_t file_length, const char *path) { int fieldlen = emrtd_get_asn1_field_length(file_contents, file_length, 1); int datalen = emrtd_get_asn1_data_length(file_contents, file_length, 1); @@ -779,11 +806,19 @@ static int emrtd_dump_ef_sod(uint8_t *file_contents, size_t file_length) { return PM3_SUCCESS; } - saveFile(dg_table[EF_SOD].filename, ".p7b", file_contents + fieldlen + 1, datalen); + char *filepath = calloc(strlen(path) + 100, sizeof(char)); + if (filepath == NULL) + return PM3_EMALLOC; + strcpy(filepath, path); + strncat(filepath, PATHSEP, 2); + strcat(filepath, dg_table[EF_SOD].filename); + + saveFile(filepath, ".p7b", file_contents + fieldlen + 1, datalen); + free(filepath); return PM3_ESOFT; } -static bool emrtd_dump_file(uint8_t *ks_enc, uint8_t *ks_mac, uint8_t *ssc, const char *file, const char *name, bool use_secure, bool use_14b) { +static bool emrtd_dump_file(uint8_t *ks_enc, uint8_t *ks_mac, uint8_t *ssc, const char *file, const char *name, bool use_secure, bool use_14b, const char *path) { uint8_t response[EMRTD_MAX_FILE_SIZE]; int resplen = 0; @@ -791,13 +826,22 @@ static bool emrtd_dump_file(uint8_t *ks_enc, uint8_t *ks_mac, uint8_t *ssc, cons return false; } + char *filepath = calloc(strlen(path) + 100, sizeof(char)); + if (filepath == NULL) + return PM3_EMALLOC; + strcpy(filepath, path); + strncat(filepath, PATHSEP, 2); + strcat(filepath, name); + PrintAndLogEx(INFO, "Read %s, len: %i.", name, resplen); PrintAndLogEx(DEBUG, "Contents (may be incomplete over 2k chars): %s", sprint_hex_inrow(response, resplen)); - saveFile(name, ".BIN", response, resplen); + saveFile(filepath, ".BIN", response, resplen); emrtd_dg_t *dg = emrtd_fileid_to_dg(file); if ((dg != NULL) && (dg->dumper != NULL)) { - dg->dumper(response, resplen); + dg->dumper(response, resplen, path); } + + free(filepath); return true; } @@ -983,7 +1027,7 @@ static bool emrtd_do_auth(char *documentnumber, char *dob, char *expiry, bool BA return true; } -int dumpHF_EMRTD(char *documentnumber, char *dob, char *expiry, bool BAC_available) { +int dumpHF_EMRTD(char *documentnumber, char *dob, char *expiry, bool BAC_available, const char *path) { uint8_t response[EMRTD_MAX_FILE_SIZE] = { 0x00 }; int resplen = 0; uint8_t ssc[8] = { 0x00 }; @@ -999,7 +1043,7 @@ int dumpHF_EMRTD(char *documentnumber, char *dob, char *expiry, bool BAC_availab } // Dump EF_CardAccess (if available) - if (!emrtd_dump_file(ks_enc, ks_mac, ssc, dg_table[EF_CardAccess].fileid, dg_table[EF_CardAccess].filename, BAC, use_14b)) { + if (!emrtd_dump_file(ks_enc, ks_mac, ssc, dg_table[EF_CardAccess].fileid, dg_table[EF_CardAccess].filename, BAC, use_14b, path)) { PrintAndLogEx(INFO, "Couldn't dump EF_CardAccess, card does not support PACE."); PrintAndLogEx(HINT, "This is expected behavior for cards without PACE, and isn't something to be worried about."); } @@ -1016,9 +1060,20 @@ int dumpHF_EMRTD(char *documentnumber, char *dob, char *expiry, bool BAC_availab DropField(); return PM3_ESOFT; } + + + char *filepath = calloc(strlen(path) + 100, sizeof(char)); + if (filepath == NULL) + return PM3_EMALLOC; + strcpy(filepath, path); + strncat(filepath, PATHSEP, 2); + strcat(filepath, dg_table[EF_COM].filename); + PrintAndLogEx(INFO, "Read EF_COM, len: %i.", resplen); PrintAndLogEx(DEBUG, "Contents (may be incomplete over 2k chars): %s", sprint_hex_inrow(response, resplen)); - saveFile(dg_table[EF_COM].filename, ".BIN", response, resplen); + saveFile(filepath, ".BIN", response, resplen); + + free(filepath); uint8_t filelist[50]; size_t filelistlen = 0; @@ -1041,7 +1096,7 @@ int dumpHF_EMRTD(char *documentnumber, char *dob, char *expiry, bool BAC_availab } PrintAndLogEx(DEBUG, "Current file: %s", dg->filename); if (!dg->pace && !dg->eac) { - emrtd_dump_file(ks_enc, ks_mac, ssc, dg->fileid, dg->filename, BAC, use_14b); + emrtd_dump_file(ks_enc, ks_mac, ssc, dg->fileid, dg->filename, BAC, use_14b, path); } } DropField(); @@ -1864,6 +1919,7 @@ static int cmd_hf_emrtd_dump(const char *Cmd) { arg_str0("d", "dateofbirth", "", "date of birth in YYMMDD format"), arg_str0("e", "expiry", "", "expiry in YYMMDD format"), arg_str0("m", "mrz", "<[0-9A-Z<]>", "2nd line of MRZ, 44 chars"), + arg_str0(NULL, "path", "", "save dump to the given dirpath"), arg_param_end }; CLIExecWithReturn(ctx, Cmd, argtable, true); @@ -1930,11 +1986,16 @@ static int cmd_hf_emrtd_dump(const char *Cmd) { } } + uint8_t path[FILENAME_MAX] = { 0x00 }; + if (CLIParamStrToBuf(arg_get_str(ctx, 5), path, sizeof(path), &slen) != 0 || slen == 0) { + path[0] = '.'; + } + CLIParserFree(ctx); if (error) { return PM3_ESOFT; } - return dumpHF_EMRTD((char *)docnum, (char *)dob, (char *)expiry, BAC); + return dumpHF_EMRTD((char *)docnum, (char *)dob, (char *)expiry, BAC, (const char *)path); } static int cmd_hf_emrtd_info(const char *Cmd) { diff --git a/client/src/cmdhfemrtd.h b/client/src/cmdhfemrtd.h index f7bd64945..bb32fb53d 100644 --- a/client/src/cmdhfemrtd.h +++ b/client/src/cmdhfemrtd.h @@ -24,7 +24,7 @@ typedef struct emrtd_dg_s { bool required; // some are required only if PACE bool fastdump; // fast to dump int (*parser)(uint8_t *data, size_t datalen); - int (*dumper)(uint8_t *data, size_t datalen); + int (*dumper)(uint8_t *data, size_t datalen, const char *path); } emrtd_dg_t; typedef struct emrtd_hashalg_s { @@ -37,7 +37,7 @@ typedef struct emrtd_hashalg_s { int CmdHFeMRTD(const char *Cmd); -int dumpHF_EMRTD(char *documentnumber, char *dob, char *expiry, bool BAC_available); +int dumpHF_EMRTD(char *documentnumber, char *dob, char *expiry, bool BAC_available, const char *path); int infoHF_EMRTD(char *documentnumber, char *dob, char *expiry, bool BAC_available); int infoHF_EMRTD_offline(const char *path); #endif From 037fd47673156a2ef780e1b347bdb612eb04b4e8 Mon Sep 17 00:00:00 2001 From: iceman1001 Date: Wed, 30 Dec 2020 18:57:30 +0100 Subject: [PATCH 261/682] fix #1151 - improved feedback text --- client/src/fileutils.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/src/fileutils.c b/client/src/fileutils.c index f7ccf1516..4d607b9df 100644 --- a/client/src/fileutils.c +++ b/client/src/fileutils.c @@ -735,7 +735,7 @@ int createMfcKeyDump(const char *preferredName, uint8_t sectorsCnt, sector_t *e_ fflush(f); fclose(f); PrintAndLogEx(SUCCESS, "Found keys have been dumped to " _YELLOW_("%s"), fileName); - PrintAndLogEx(INFO, " OBS! --> 0xFFFFFFFFFFFF <-- has been inserted for unknown keys."); + PrintAndLogEx(INFO, "FYI! --> " _YELLOW_("0xFFFFFFFFFFFF") " <-- has been inserted for unknown keys where " _YELLOW_("res") " is " _YELLOW_("0")); free(fileName); return PM3_SUCCESS; } From 49f684c31adb42228da2c45f1edcb717d6e75562 Mon Sep 17 00:00:00 2001 From: iceman1001 Date: Wed, 30 Dec 2020 18:58:04 +0100 Subject: [PATCH 262/682] add noralsy/vigik entry --- client/resources/mad.json | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/client/resources/mad.json b/client/resources/mad.json index d5c413d73..c63190cda 100644 --- a/client/resources/mad.json +++ b/client/resources/mad.json @@ -6096,6 +6096,13 @@ "service_provider": "CDVI", "system_integrator": "CDVI" }, + { + "application": "(access control and security) VIGIK", + "company": "NORALSY", + "mad": "0x4980", + "service_provider": "NORALSY", + "system_integrator": "NORALSY" + }, { "application": "Card Administratin, cardholder adminstration, access control & security, company services, miscellaneous applications", "company": "Ministry of Defense", From cdbd4d7d1e2e8d259119278b4f3501709af32147 Mon Sep 17 00:00:00 2001 From: iceman1001 Date: Wed, 30 Dec 2020 19:16:37 +0100 Subject: [PATCH 263/682] hf mf mad - deals with user supplied keys in a different order now --- client/src/cmdhfmf.c | 35 ++++++++++++++++++++++++++--------- 1 file changed, 26 insertions(+), 9 deletions(-) diff --git a/client/src/cmdhfmf.c b/client/src/cmdhfmf.c index 481a5ce14..8cf0f4e1a 100644 --- a/client/src/cmdhfmf.c +++ b/client/src/cmdhfmf.c @@ -4869,28 +4869,45 @@ static int CmdHF14AMfMAD(const char *Cmd) { CLIExecWithReturn(ctx, Cmd, argtable, true); bool verbose = arg_get_lit(ctx, 1); uint8_t aid[2] = {0}; - int aidlen; + int aidlen = 0; CLIGetHexWithReturn(ctx, 2, aid, &aidlen); - uint8_t key[6] = {0}; - int keylen; - CLIGetHexWithReturn(ctx, 3, key, &keylen); + uint8_t userkey[6] = {0}; + int keylen = 0; + CLIGetHexWithReturn(ctx, 3, userkey, &keylen); bool keyB = arg_get_lit(ctx, 4); bool swapmad = arg_get_lit(ctx, 5); bool decodeholder = arg_get_lit(ctx, 6); CLIParserFree(ctx); - if (aidlen != 2 && !decodeholder && keylen > 0) { - PrintAndLogEx(WARNING, "Using default MAD keys instead"); - } - uint8_t sector0[16 * 4] = {0}; uint8_t sector10[16 * 4] = {0}; + + bool got_first = true; if (mfReadSector(MF_MAD1_SECTOR, MF_KEY_A, (uint8_t *)g_mifare_mad_key, sector0)) { PrintAndLogEx(ERR, "error, read sector 0. card don't have MAD or don't have MAD on default keys"); + got_first = false; + } + + // User supplied key + if (got_first == false && keylen == 6) { + if (mfReadSector(MF_MAD1_SECTOR, MF_KEY_A, userkey, sector0)) { + PrintAndLogEx(ERR, "error, read sector 0. card don't have MAD or don't the custom key is wrong"); + } else { + got_first = true; + } + } + + // Both default and user supplied key failed + if (got_first == false) { return PM3_ESOFT; } +// if (aidlen != 2 && !decodeholder) { +// PrintAndLogEx(WARNING, "Using default MAD keys instead"); + + + PrintAndLogEx(NORMAL, ""); PrintAndLogEx(INFO, "--- " _CYAN_("MIFARE App Directory Information") " ----------------"); PrintAndLogEx(INFO, "-----------------------------------------------------"); @@ -4921,7 +4938,7 @@ static int CmdHF14AMfMAD(const char *Cmd) { // user specified key if (keylen == 6) { - memcpy(akey, key, 6); + memcpy(akey, userkey, 6); } uint16_t aaid = 0x0004; From c3ea0c83ada42c0533b4060d81031f4980ff4ec3 Mon Sep 17 00:00:00 2001 From: iceman1001 Date: Wed, 30 Dec 2020 22:05:28 +0100 Subject: [PATCH 264/682] hf mf mad - text --- client/src/cmdhfmf.c | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/client/src/cmdhfmf.c b/client/src/cmdhfmf.c index 8cf0f4e1a..e9b87add6 100644 --- a/client/src/cmdhfmf.c +++ b/client/src/cmdhfmf.c @@ -4884,16 +4884,20 @@ static int CmdHF14AMfMAD(const char *Cmd) { uint8_t sector10[16 * 4] = {0}; bool got_first = true; - if (mfReadSector(MF_MAD1_SECTOR, MF_KEY_A, (uint8_t *)g_mifare_mad_key, sector0)) { - PrintAndLogEx(ERR, "error, read sector 0. card don't have MAD or don't have MAD on default keys"); + if (mfReadSector(MF_MAD1_SECTOR, MF_KEY_A, (uint8_t *)g_mifare_mad_key, sector0) != PM3_SUCCESS) { + PrintAndLogEx(WARNING, "error, read sector 0. card don't have MAD or don't have MAD on default keys"); got_first = false; + } else { + PrintAndLogEx(INFO, "Authentication ( " _GREEN_("OK") " )"); } // User supplied key if (got_first == false && keylen == 6) { - if (mfReadSector(MF_MAD1_SECTOR, MF_KEY_A, userkey, sector0)) { - PrintAndLogEx(ERR, "error, read sector 0. card don't have MAD or don't the custom key is wrong"); + PrintAndLogEx(INFO, "Trying user specified key..."); + if (mfReadSector(MF_MAD1_SECTOR, MF_KEY_A, userkey, sector0) != PM3_SUCCESS) { + PrintAndLogEx(ERR, "error, read sector 0. card don't have MAD or don't the custom key is wrong"); } else { + PrintAndLogEx(INFO, "Authentication ( " _GREEN_("OK") " )"); got_first = true; } } @@ -4903,11 +4907,6 @@ static int CmdHF14AMfMAD(const char *Cmd) { return PM3_ESOFT; } -// if (aidlen != 2 && !decodeholder) { -// PrintAndLogEx(WARNING, "Using default MAD keys instead"); - - - PrintAndLogEx(NORMAL, ""); PrintAndLogEx(INFO, "--- " _CYAN_("MIFARE App Directory Information") " ----------------"); PrintAndLogEx(INFO, "-----------------------------------------------------"); From 6d62f3f53c47e9f79463e8ef8355874fd6ce7d4a Mon Sep 17 00:00:00 2001 From: ikarus Date: Wed, 30 Dec 2020 23:10:53 +0100 Subject: [PATCH 265/682] hf_mf_format.lua: fixed off by one and typo. --- client/luascripts/hf_mf_format.lua | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/client/luascripts/hf_mf_format.lua b/client/luascripts/hf_mf_format.lua index 0bde3c2d1..7aed6b757 100644 --- a/client/luascripts/hf_mf_format.lua +++ b/client/luascripts/hf_mf_format.lua @@ -14,7 +14,7 @@ This script will generate 'hf mf wrbl' commands for each block to format a Mifar Alla datablocks gets 0x00 As default the script sets the keys A/B to 0xFFFFFFFFFFFF and the access bytes will become 0x78,0x77,0x88 -The GDB will become 0x00 +The GPB will become 0x00 The script will skip the manufactoring block 0. ]] @@ -169,7 +169,7 @@ local function main(args) GetCardInfo() -- Show info - print( string.format('Estimating number of blocks: %d', numBlocks)) + print( string.format('Estimating number of blocks: %d', numBlocks + 1)) print( string.format('Old key: %s', OldKey)) print( string.format('New key: %s', NewKey)) print( string.format('New Access: %s', Accessbytes)) From 027ed5e5589b1c9f577bb28f57953a8369e75ee4 Mon Sep 17 00:00:00 2001 From: Gabriele Gristina Date: Thu, 31 Dec 2020 00:33:42 +0100 Subject: [PATCH 266/682] Fixed build errors on osx --- client/src/cmdhf14a.c | 2 +- client/src/cmdhfemrtd.c | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/client/src/cmdhf14a.c b/client/src/cmdhf14a.c index 8a6ce45ef..1048be3f5 100644 --- a/client/src/cmdhf14a.c +++ b/client/src/cmdhf14a.c @@ -2219,7 +2219,7 @@ static int CmdHf14AFindapdu(const char *Cmd) { bool inc_p1 = true; bool skip_ins = false; - uint64_t all_sw[256][256] = {0}; + uint64_t all_sw[256][256] = { { 0 } }; uint64_t sw_occurences = 0; uint64_t t_start = msclock(); uint64_t t_last_reset = msclock(); diff --git a/client/src/cmdhfemrtd.c b/client/src/cmdhfemrtd.c index 2ba45f5b7..afe5b6b6f 100644 --- a/client/src/cmdhfemrtd.c +++ b/client/src/cmdhfemrtd.c @@ -1777,8 +1777,8 @@ int infoHF_EMRTD(char *documentnumber, char *dob, char *expiry, bool BAC_availab } // Grab the hash list - uint8_t dg_hashes_sod[17][64] = { 0x00 }; - uint8_t dg_hashes_calc[17][64] = { 0x00 }; + uint8_t dg_hashes_sod[17][64] = { { 0 } }; + uint8_t dg_hashes_calc[17][64] = { { 0 } }; int hash_algo = 0; if (!emrtd_select_and_read(response, &resplen, dg_table[EF_SOD].fileid, ks_enc, ks_mac, ssc, BAC, use_14b)) { @@ -1856,8 +1856,8 @@ int infoHF_EMRTD_offline(const char *path) { free(data); // Grab the hash list - uint8_t dg_hashes_sod[17][64] = { 0x00 }; - uint8_t dg_hashes_calc[17][64] = { 0x00 }; + uint8_t dg_hashes_sod[17][64] = { { 0 } }; + uint8_t dg_hashes_calc[17][64] = { { 0 } }; int hash_algo = 0; strcpy(filepath, path); From a9f4f4f80477913d41bf4b44600270e48031d1b6 Mon Sep 17 00:00:00 2001 From: tcprst Date: Wed, 30 Dec 2020 22:42:46 -0500 Subject: [PATCH 267/682] hf 14a config - now use cliparser --- armsrc/iso14443a.c | 2 +- client/src/cmdhf14a.c | 249 +++++++++++++++------------------------ client/src/cmdhf14a.h | 2 +- doc/cliparser_todo.txt | 1 - doc/magic_cards_notes.md | 24 ++-- 5 files changed, 108 insertions(+), 170 deletions(-) diff --git a/armsrc/iso14443a.c b/armsrc/iso14443a.c index db00f5494..4776e555a 100644 --- a/armsrc/iso14443a.c +++ b/armsrc/iso14443a.c @@ -142,7 +142,7 @@ void printHf14aConfig(void) { Dbprintf(" [b] BCC override........%i %s%s%s", hf14aconfig.forcebcc, (hf14aconfig.forcebcc == 0) ? "( " _GREEN_("No") " ) follow standard" : "", - (hf14aconfig.forcebcc == 1) ? "( " _RED_("Yes") " ) always do CL2" : "", + (hf14aconfig.forcebcc == 1) ? "( " _RED_("Yes") " ) force fix of bad BCC" : "", (hf14aconfig.forcebcc == 2) ? "( " _RED_("Yes") " ) always use card BCC" : "" ); Dbprintf(" [2] CL2 override........%i %s%s%s", diff --git a/client/src/cmdhf14a.c b/client/src/cmdhf14a.c index 1048be3f5..02b3a817e 100644 --- a/client/src/cmdhf14a.c +++ b/client/src/cmdhf14a.c @@ -170,45 +170,6 @@ const char *getTagInfo(uint8_t uid) { static uint16_t frameLength = 0; uint16_t atsFSC[] = {16, 24, 32, 40, 48, 64, 96, 128, 256}; -static int usage_hf_14a_config(void) { - PrintAndLogEx(NORMAL, "Usage: hf 14a config [a 0|1|2] [b 0|1|2] [2 0|1|2] [3 0|1|2]"); - PrintAndLogEx(NORMAL, "\nOptions:"); - PrintAndLogEx(NORMAL, " h This help"); - PrintAndLogEx(NORMAL, " a 0|1|2 ATQA<>anticollision: 0=follow standard 1=execute anticol 2=skip anticol"); - PrintAndLogEx(NORMAL, " b 0|1|2 BCC: 0=follow standard 1=use fixed BCC 2=use card BCC"); - PrintAndLogEx(NORMAL, " 2 0|1|2 SAK<>CL2: 0=follow standard 1=execute CL2 2=skip CL2"); - PrintAndLogEx(NORMAL, " 3 0|1|2 SAK<>CL3: 0=follow standard 1=execute CL3 2=skip CL3"); - PrintAndLogEx(NORMAL, " r 0|1|2 SAK<>ATS: 0=follow standard 1=execute RATS 2=skip RATS"); - PrintAndLogEx(NORMAL, "\nExamples:"); - PrintAndLogEx(NORMAL, _YELLOW_(" hf 14a config ")" Print current configuration"); - PrintAndLogEx(NORMAL, _YELLOW_(" hf 14a config a 1 ")" Force execution of anticollision"); - PrintAndLogEx(NORMAL, _YELLOW_(" hf 14a config a 0 ")" Restore ATQA interpretation"); - PrintAndLogEx(NORMAL, _YELLOW_(" hf 14a config b 1 ")" Force fix of bad BCC in anticollision"); - PrintAndLogEx(NORMAL, _YELLOW_(" hf 14a config b 0 ")" Restore BCC check"); - PrintAndLogEx(NORMAL, "\nExamples to revive Gen2/DirectWrite magic cards failing at anticollision:"); - PrintAndLogEx(NORMAL, _CYAN_(" MFC 1k 4b UID")":"); - PrintAndLogEx(NORMAL, _YELLOW_(" hf 14a config a 1 b 2 2 2 r 2")); - PrintAndLogEx(NORMAL, _YELLOW_(" hf mf wrbl 0 A FFFFFFFFFFFF 11223344440804006263646566676869")); - PrintAndLogEx(NORMAL, _YELLOW_(" hf 14a config a 0 b 0 2 0 r 0")); - PrintAndLogEx(NORMAL, _CYAN_(" MFC 4k 4b UID")":"); - PrintAndLogEx(NORMAL, _YELLOW_(" hf 14a config a 1 b 2 2 2 r 2")); - PrintAndLogEx(NORMAL, _YELLOW_(" hf mf wrbl 0 A FFFFFFFFFFFF 11223344441802006263646566676869")); - PrintAndLogEx(NORMAL, _YELLOW_(" hf 14a config a 0 b 0 2 0 r 0")); - PrintAndLogEx(NORMAL, _CYAN_(" MFC 1k 7b UID")":"); - PrintAndLogEx(NORMAL, _YELLOW_(" hf 14a config a 1 b 2 2 1 3 2 r 2")); - PrintAndLogEx(NORMAL, _YELLOW_(" hf mf wrbl 0 A FFFFFFFFFFFF 04112233445566084400626364656667")); - PrintAndLogEx(NORMAL, _YELLOW_(" hf 14a config a 0 b 0 2 0 3 0 r 0")); - PrintAndLogEx(NORMAL, _CYAN_(" MFC 4k 7b UID")":"); - PrintAndLogEx(NORMAL, _YELLOW_(" hf 14a config a 1 b 2 2 1 3 2 r 2")); - PrintAndLogEx(NORMAL, _YELLOW_(" hf mf wrbl 0 A FFFFFFFFFFFF 04112233445566184200626364656667")); - PrintAndLogEx(NORMAL, _YELLOW_(" hf 14a config a 0 b 0 2 0 3 0 r 0")); - PrintAndLogEx(NORMAL, _CYAN_(" MFUL ")"/" _CYAN_(" MFUL EV1 ")"/" _CYAN_(" MFULC")":"); - PrintAndLogEx(NORMAL, _YELLOW_(" hf 14a config a 1 b 2 2 1 3 2 r 2")); - PrintAndLogEx(NORMAL, _YELLOW_(" hf mfu setuid 04112233445566")); - PrintAndLogEx(NORMAL, _YELLOW_(" hf 14a config a 0 b 0 2 0 3 0 r 0")); - return PM3_SUCCESS; -} - static int CmdHF14AList(const char *Cmd) { char args[128] = {0}; if (strlen(Cmd) == 0) { @@ -237,142 +198,120 @@ int hf14a_getconfig(hf14a_config *config) { return PM3_SUCCESS; } -int hf14a_setconfig(hf14a_config *config) { +int hf14a_setconfig(hf14a_config *config, bool verbose) { if (!session.pm3_present) return PM3_ENOTTY; clearCommandBuffer(); - if (config != NULL) + if (config != NULL) { SendCommandNG(CMD_HF_ISO14443A_SET_CONFIG, (uint8_t *)config, sizeof(hf14a_config)); - else + if (verbose) { + SendCommandNG(CMD_HF_ISO14443A_PRINT_CONFIG, NULL, 0); + } + } else { SendCommandNG(CMD_HF_ISO14443A_PRINT_CONFIG, NULL, 0); + } return PM3_SUCCESS; } +static int hf_14a_config_example(void) { + PrintAndLogEx(NORMAL, "\nExamples to revive Gen2/DirectWrite magic cards failing at anticollision:"); + PrintAndLogEx(NORMAL, _CYAN_(" MFC 1k 4b UID")":"); + PrintAndLogEx(NORMAL, _YELLOW_(" hf 14a config --atqa 1 --bcc 2 --cl2 2 --rats 2")); + PrintAndLogEx(NORMAL, _YELLOW_(" hf mf wrbl 0 A FFFFFFFFFFFF 11223344440804006263646566676869")); + PrintAndLogEx(NORMAL, _YELLOW_(" hf 14a config --atqa 0 --bcc 0 --cl2 0 --rats 0")); + PrintAndLogEx(NORMAL, _CYAN_(" MFC 4k 4b UID")":"); + PrintAndLogEx(NORMAL, _YELLOW_(" hf 14a config --atqa 1 --bcc 2 --cl2 2 --rats 2")); + PrintAndLogEx(NORMAL, _YELLOW_(" hf mf wrbl 0 A FFFFFFFFFFFF 11223344441802006263646566676869")); + PrintAndLogEx(NORMAL, _YELLOW_(" hf 14a config --atqa 0 --bcc 0 --cl2 0 --rats 0")); + PrintAndLogEx(NORMAL, _CYAN_(" MFC 1k 7b UID")":"); + PrintAndLogEx(NORMAL, _YELLOW_(" hf 14a config --atqa 1 --bcc 2 --cl2 1 --cl3 2 --rats 2")); + PrintAndLogEx(NORMAL, _YELLOW_(" hf mf wrbl 0 A FFFFFFFFFFFF 04112233445566084400626364656667")); + PrintAndLogEx(NORMAL, _YELLOW_(" hf 14a config --atqa 0 --bcc 0 --cl2 0 --rats 0")); + PrintAndLogEx(NORMAL, _CYAN_(" MFC 4k 7b UID")":"); + PrintAndLogEx(NORMAL, _YELLOW_(" hf 14a config --atqa 1 --bcc 2 --cl2 1 --cl3 2 --rats 2")); + PrintAndLogEx(NORMAL, _YELLOW_(" hf mf wrbl 0 A FFFFFFFFFFFF 04112233445566184200626364656667")); + PrintAndLogEx(NORMAL, _YELLOW_(" hf 14a config --atqa 0 --bcc 0 --cl2 0 --rats 0")); + PrintAndLogEx(NORMAL, _CYAN_(" MFUL ")"/" _CYAN_(" MFUL EV1 ")"/" _CYAN_(" MFULC")":"); + PrintAndLogEx(NORMAL, _YELLOW_(" hf 14a config --atqa 1 --bcc 2 --cl2 1 --cl3 2 r 2")); + PrintAndLogEx(NORMAL, _YELLOW_(" hf mfu setuid 04112233445566")); + PrintAndLogEx(NORMAL, _YELLOW_(" hf 14a config --atqa 0 --bcc 0 --cl2 0 --rats 0")); + return PM3_SUCCESS; +} static int CmdHf14AConfig(const char *Cmd) { - if (!session.pm3_present) return PM3_ENOTTY; - // if called with no params, just print the device config + CLIParserContext *ctx; + CLIParserInit(&ctx, "hf 14a config", + "Configure 14a settings (use with caution)", + "hf 14a config -> Print current configuration\n" + "hf 14a config --atqa 0 -> Follow standard\n" + "hf 14a config --atqa 1 -> Force execution of anticollision\n" + "hf 14a config --atqa 2 -> Skip anticollision\n" + "hf 14a config --bcc 0 -> Follow standard\n" + "hf 14a config --bcc 1 -> Force fix of bad BCC in anticollision\n" + "hf 14a config --bcc 2 -> Use card BCC\n" + "hf 14a config --cl2 0 -> Follow standard\n" + "hf 14a config --cl2 1 -> Execute CL2\n" + "hf 14a config --cl2 2 -> Skip CL2\n" + "hf 14a config --cl3 0 -> Follow standard\n" + "hf 14a config --cl3 1 -> Execute CL3\n" + "hf 14a config --cl3 2 -> Skip CL3\n" + "hf 14a config --rats 0 -> Follow standard\n" + "hf 14a config --rats 1 -> Execute RATS\n" + "hf 14a config --rats 2 -> Skip RATS"); + + void *argtable[] = { + arg_param_begin, + arg_int0(NULL, "atqa", "", "Configure ATQA<>anticollision behavior"), + arg_int0(NULL, "bcc", "", "Configure BCC behavior"), + arg_int0(NULL, "cl2", "", "Configure SAK<>CL2 behavior"), + arg_int0(NULL, "cl3", "", "Configure SAK<>CL3 behavior"), + arg_int0(NULL, "rats", "", "Configure RATS behavior"), + arg_lit0("v", "verbose", "verbose output, also prints examples for reviving Gen2 cards"), + arg_param_end + }; + CLIExecWithReturn(ctx, Cmd, argtable, true); + + int atqa = arg_get_int_def(ctx, 1, -1); + int bcc = arg_get_int_def(ctx, 2, -1); + int cl2 = arg_get_int_def(ctx, 3, -1); + int cl3 = arg_get_int_def(ctx, 4, -1); + int rats = arg_get_int_def(ctx, 5, -1); + + int *config_options[5] = {&atqa, &bcc, &cl2, &cl3, &rats}; + + bool verbose = arg_get_lit(ctx, 6); + + CLIParserFree(ctx); + + // validations if (strlen(Cmd) == 0) { - return hf14a_setconfig(NULL); + return hf14a_setconfig(NULL, verbose); } - hf14a_config config = { - .forceanticol = -1, - .forcebcc = -1, - .forcecl2 = -1, - .forcecl3 = -1, - .forcerats = -1 - }; + if (verbose) { + hf_14a_config_example(); + } - bool errors = false; - uint8_t cmdp = 0; - while (param_getchar(Cmd, cmdp) != 0x00 && !errors) { - switch (param_getchar(Cmd, cmdp)) { - case 'h': - return usage_hf_14a_config(); - case 'a': - switch (param_getchar(Cmd, cmdp + 1)) { - case '0': - config.forceanticol = 0; - break; - case '1': - config.forceanticol = 1; - break; - case '2': - config.forceanticol = 2; - break; - default: - PrintAndLogEx(WARNING, "Unknown value '%c'", param_getchar(Cmd, cmdp + 1)); - errors = 1; - break; - } - cmdp += 2; - break; - case 'b': - switch (param_getchar(Cmd, cmdp + 1)) { - case '0': - config.forcebcc = 0; - break; - case '1': - config.forcebcc = 1; - break; - case '2': - config.forcebcc = 2; - break; - default: - PrintAndLogEx(WARNING, "Unknown value '%c'", param_getchar(Cmd, cmdp + 1)); - errors = 1; - break; - } - cmdp += 2; - break; - case '2': - switch (param_getchar(Cmd, cmdp + 1)) { - case '0': - config.forcecl2 = 0; - break; - case '1': - config.forcecl2 = 1; - break; - case '2': - config.forcecl2 = 2; - break; - default: - PrintAndLogEx(WARNING, "Unknown value '%c'", param_getchar(Cmd, cmdp + 1)); - errors = 1; - break; - } - cmdp += 2; - break; - case '3': - switch (param_getchar(Cmd, cmdp + 1)) { - case '0': - config.forcecl3 = 0; - break; - case '1': - config.forcecl3 = 1; - break; - case '2': - config.forcecl3 = 2; - break; - default: - PrintAndLogEx(WARNING, "Unknown value '%c'", param_getchar(Cmd, cmdp + 1)); - errors = 1; - break; - } - cmdp += 2; - break; - case 'r': - switch (param_getchar(Cmd, cmdp + 1)) { - case '0': - config.forcerats = 0; - break; - case '1': - config.forcerats = 1; - break; - case '2': - config.forcerats = 2; - break; - default: - PrintAndLogEx(WARNING, "Unknown value '%c'", param_getchar(Cmd, cmdp + 1)); - errors = 1; - break; - } - cmdp += 2; - break; - default: - PrintAndLogEx(WARNING, "Unknown parameter '%c'", param_getchar(Cmd, cmdp)); - errors = 1; - break; + for (int i = 0; i < 5; ++i) { + if (*config_options[i] > -1) { + if (*config_options[i] > 2) { + PrintAndLogEx(ERR, "Argument must be 0, 1, or 2"); + return PM3_EINVARG; + } } } - // validations - if (errors) return usage_hf_14a_config(); + hf14a_config config = { + .forceanticol = atqa, + .forcebcc = bcc, + .forcecl2 = cl2, + .forcecl3 = cl3, + .forcerats = rats + }; - return hf14a_setconfig(&config); + return hf14a_setconfig(&config, verbose); } int Hf14443_4aGetCardData(iso14a_card_select_t *card) { diff --git a/client/src/cmdhf14a.h b/client/src/cmdhf14a.h index 925bf8bef..a1a2279a0 100644 --- a/client/src/cmdhf14a.h +++ b/client/src/cmdhf14a.h @@ -27,7 +27,7 @@ int CmdHF14ASniff(const char *Cmd); // used by hf topaz sniff int CmdHF14ASim(const char *Cmd); // used by hf mfu sim int hf14a_getconfig(hf14a_config *config); -int hf14a_setconfig(hf14a_config *config); +int hf14a_setconfig(hf14a_config *config, bool verbose); int infoHF14A(bool verbose, bool do_nack_test, bool do_aid_search); const char *getTagInfo(uint8_t uid); int Hf14443_4aGetCardData(iso14a_card_select_t *card); diff --git a/doc/cliparser_todo.txt b/doc/cliparser_todo.txt index 0a5e5c77e..7f5643b2f 100644 --- a/doc/cliparser_todo.txt +++ b/doc/cliparser_todo.txt @@ -41,7 +41,6 @@ data print data samples data setdebugmode data tune -hf 14a config hf 14b sriwrite hf 15 dump hf 15 info diff --git a/doc/magic_cards_notes.md b/doc/magic_cards_notes.md index 9e4cdce12..08aaa0386 100644 --- a/doc/magic_cards_notes.md +++ b/doc/magic_cards_notes.md @@ -45,12 +45,12 @@ Here are some tips if the card doesn't react or gives error on a simple `hf 14a Let's force a 4b UID anticollision and see what happens: ``` -hf 14a config a 1 b 2 2 2 r 2 +hf 14a config --atqa 1 --bcc 2 --cl2 2 --rats 2 hf 14a reader ``` It it responds, we know it's a TypeA card. But maybe it's a 7b UID, so let's force a 7b UID anticollision: ``` -hf 14a config a 1 b 2 2 1 3 2 r 2 +hf 14a config --atqa 1 --bcc 2 --cl2 1 --cl3 2 --rats 2 hf 14a reader ``` At this stage, you know if it's a TypeA 4b or 7b card and you can check further on this page how to reconfigure different types of cards. @@ -58,7 +58,7 @@ At this stage, you know if it's a TypeA 4b or 7b card and you can check further To restore anticollision config of the Proxmark3: ``` -hf 14a config a 0 b 0 2 0 3 0 r 0 +hf 14a config --atqa 0 --bcc 0 --cl2 0 --cl3 0 --rats 0 ``` # MIFARE Classic @@ -335,26 +335,26 @@ hf mf wrbl 0 A FFFFFFFFFFFF 11223344440804006263646566676869 When "soft-bricked" (by writing invalid data in block0), these ones may help: ``` -hf 14a config h +hf 14a config -h ``` e.g. for 4b UID: ``` -hf 14a config a 1 b 2 2 2 r 2 +hf 14a config --atqa 1 --bcc 2 --cl2 2 --rats 2 hf mf wrbl 0 A FFFFFFFFFFFF 11223344440804006263646566676869 # for 1k hf mf wrbl 0 A FFFFFFFFFFFF 11223344441802006263646566676869 # for 4k -hf 14a config a 0 b 0 2 0 r 0 +hf 14a config --atqa 0 --bcc 0 --cl2 0 --rats 0 hf 14a reader ``` e.g. for 7b UID: ``` -hf 14a config a 1 b 2 2 1 3 2 r 2 +hf 14a config --atqa 1 --bcc 2 --cl2 1 --cl3 2 --rats 2 hf mf wrbl 0 A FFFFFFFFFFFF 04112233445566084400626364656667 # for 1k hf mf wrbl 0 A FFFFFFFFFFFF 04112233445566184200626364656667 # for 4k -hf 14a config a 0 b 0 2 0 3 0 r 0 +hf 14a config --atqa 0 --bcc 0 --cl2 0 --cl3 0 --rats 0 hf 14a reader ``` ## MIFARE Classic DirectWrite, FUID version aka 1-write @@ -537,7 +537,7 @@ script run hf_mfu_setuid -h When "soft-bricked" (by writing invalid data in block0), these ones may help: ``` -hf 14a config h +hf 14a config -h script run run hf_mf_magicrevive -u ``` @@ -599,14 +599,14 @@ hf 14a raw -c a2 02 44480000 When "soft-bricked" (by writing invalid data in block0), these ones may help: ``` -hf 14a config h +hf 14a config -h ``` E.g.: ``` -hf 14a config a 1 b 2 2 1 3 2 r 2 +hf 14a config --atqa 1 --bcc 2 --cl2 1 --cl3 2 --rats 2 hf mfu setuid 04112233445566 -hf 14a config a 0 b 0 2 0 3 0 r 0 +hf 14a config --atqa 0 --bcc 0 --cl2 0 --cl3 0 --rats 0 hf 14a reader ``` From b956d4c148e3c07014375ab36429b1c48d205fa2 Mon Sep 17 00:00:00 2001 From: Philippe Teuwen Date: Thu, 31 Dec 2020 11:39:57 +0100 Subject: [PATCH 268/682] hf 14a config cliparser: use string values --- armsrc/iso14443a.c | 45 ++++++------- client/src/cmdhf14a.c | 146 ++++++++++++++++++++++++++++-------------- 2 files changed, 117 insertions(+), 74 deletions(-) diff --git a/armsrc/iso14443a.c b/armsrc/iso14443a.c index 4776e555a..759e5e646 100644 --- a/armsrc/iso14443a.c +++ b/armsrc/iso14443a.c @@ -133,35 +133,30 @@ static hf14a_config hf14aconfig = { 0, 0, 0, 0, 0 } ; void printHf14aConfig(void) { DbpString(_CYAN_("HF 14a config")); - Dbprintf(" [a] Anticol override....%i %s%s%s", - hf14aconfig.forceanticol, - (hf14aconfig.forceanticol == 0) ? "( " _GREEN_("No") " ) follow standard " : "", - (hf14aconfig.forceanticol == 1) ? "( " _RED_("Yes") " ) always do anticol" : "", - (hf14aconfig.forceanticol == 2) ? "( " _RED_("Yes") " ) always skip anticol" : "" + Dbprintf(" [a] Anticol override....%s%s%s", + (hf14aconfig.forceanticol == 0) ? _GREEN_("std") " : follow standard " : "", + (hf14aconfig.forceanticol == 1) ? _RED_("force") " : always do anticol" : "", + (hf14aconfig.forceanticol == 2) ? _RED_("skip") " : always skip anticol" : "" ); - Dbprintf(" [b] BCC override........%i %s%s%s", - hf14aconfig.forcebcc, - (hf14aconfig.forcebcc == 0) ? "( " _GREEN_("No") " ) follow standard" : "", - (hf14aconfig.forcebcc == 1) ? "( " _RED_("Yes") " ) force fix of bad BCC" : "", - (hf14aconfig.forcebcc == 2) ? "( " _RED_("Yes") " ) always use card BCC" : "" + Dbprintf(" [b] BCC override........%s%s%s", + (hf14aconfig.forcebcc == 0) ? _GREEN_("std") " : follow standard" : "", + (hf14aconfig.forcebcc == 1) ? _RED_("fix") " : fix bad BCC" : "", + (hf14aconfig.forcebcc == 2) ? _RED_("ignore") " : ignore bad BCC, always use card BCC" : "" ); - Dbprintf(" [2] CL2 override........%i %s%s%s", - hf14aconfig.forcecl2, - (hf14aconfig.forcecl2 == 0) ? "( " _GREEN_("No") " ) follow standard" : "", - (hf14aconfig.forcecl2 == 1) ? "( " _RED_("Yes") " ) always do CL2" : "", - (hf14aconfig.forcecl2 == 2) ? "( " _RED_("Yes") " ) always skip CL2" : "" + Dbprintf(" [2] CL2 override........%s%s%s", + (hf14aconfig.forcecl2 == 0) ? _GREEN_("std") " : follow standard" : "", + (hf14aconfig.forcecl2 == 1) ? _RED_("force") " : always do CL2" : "", + (hf14aconfig.forcecl2 == 2) ? _RED_("skip") " : always skip CL2" : "" ); - Dbprintf(" [3] CL3 override........%i %s%s%s", - hf14aconfig.forcecl3, - (hf14aconfig.forcecl3 == 0) ? "( " _GREEN_("No") " ) follow standard" : "", - (hf14aconfig.forcecl3 == 1) ? "( " _RED_("Yes") " ) always do CL3" : "", - (hf14aconfig.forcecl3 == 2) ? "( " _RED_("Yes") " ) always skip CL3" : "" + Dbprintf(" [3] CL3 override........%s%s%s", + (hf14aconfig.forcecl3 == 0) ? _GREEN_("std") " : follow standard" : "", + (hf14aconfig.forcecl3 == 1) ? _RED_("force") " : always do CL3" : "", + (hf14aconfig.forcecl3 == 2) ? _RED_("skip") " : always skip CL3" : "" ); - Dbprintf(" [r] RATS override.......%i %s%s%s", - hf14aconfig.forcerats, - (hf14aconfig.forcerats == 0) ? "( " _GREEN_("No") " ) follow standard " : "", - (hf14aconfig.forcerats == 1) ? "( " _RED_("Yes") " ) always do RATS" : "", - (hf14aconfig.forcerats == 2) ? "( " _RED_("Yes") " ) always skip RATS" : "" + Dbprintf(" [r] RATS override.......%s%s%s", + (hf14aconfig.forcerats == 0) ? _GREEN_("std") " : follow standard " : "", + (hf14aconfig.forcerats == 1) ? _RED_("force") " : always do RATS" : "", + (hf14aconfig.forcerats == 2) ? _RED_("skip") " : always skip RATS" : "" ); } diff --git a/client/src/cmdhf14a.c b/client/src/cmdhf14a.c index 02b3a817e..373e81d49 100644 --- a/client/src/cmdhf14a.c +++ b/client/src/cmdhf14a.c @@ -217,25 +217,25 @@ int hf14a_setconfig(hf14a_config *config, bool verbose) { static int hf_14a_config_example(void) { PrintAndLogEx(NORMAL, "\nExamples to revive Gen2/DirectWrite magic cards failing at anticollision:"); PrintAndLogEx(NORMAL, _CYAN_(" MFC 1k 4b UID")":"); - PrintAndLogEx(NORMAL, _YELLOW_(" hf 14a config --atqa 1 --bcc 2 --cl2 2 --rats 2")); + PrintAndLogEx(NORMAL, _YELLOW_(" hf 14a config --atqa force --bcc ignore --cl2 skip --rats skip")); PrintAndLogEx(NORMAL, _YELLOW_(" hf mf wrbl 0 A FFFFFFFFFFFF 11223344440804006263646566676869")); - PrintAndLogEx(NORMAL, _YELLOW_(" hf 14a config --atqa 0 --bcc 0 --cl2 0 --rats 0")); + PrintAndLogEx(NORMAL, _YELLOW_(" hf 14a config --std")); PrintAndLogEx(NORMAL, _CYAN_(" MFC 4k 4b UID")":"); - PrintAndLogEx(NORMAL, _YELLOW_(" hf 14a config --atqa 1 --bcc 2 --cl2 2 --rats 2")); + PrintAndLogEx(NORMAL, _YELLOW_(" hf 14a config --atqa force --bcc ignore --cl2 skip --rats skip")); PrintAndLogEx(NORMAL, _YELLOW_(" hf mf wrbl 0 A FFFFFFFFFFFF 11223344441802006263646566676869")); - PrintAndLogEx(NORMAL, _YELLOW_(" hf 14a config --atqa 0 --bcc 0 --cl2 0 --rats 0")); + PrintAndLogEx(NORMAL, _YELLOW_(" hf 14a config --std")); PrintAndLogEx(NORMAL, _CYAN_(" MFC 1k 7b UID")":"); - PrintAndLogEx(NORMAL, _YELLOW_(" hf 14a config --atqa 1 --bcc 2 --cl2 1 --cl3 2 --rats 2")); + PrintAndLogEx(NORMAL, _YELLOW_(" hf 14a config --atqa force --bcc ignore --cl2 force --cl3 skip --rats skip")); PrintAndLogEx(NORMAL, _YELLOW_(" hf mf wrbl 0 A FFFFFFFFFFFF 04112233445566084400626364656667")); - PrintAndLogEx(NORMAL, _YELLOW_(" hf 14a config --atqa 0 --bcc 0 --cl2 0 --rats 0")); + PrintAndLogEx(NORMAL, _YELLOW_(" hf 14a config --std")); PrintAndLogEx(NORMAL, _CYAN_(" MFC 4k 7b UID")":"); - PrintAndLogEx(NORMAL, _YELLOW_(" hf 14a config --atqa 1 --bcc 2 --cl2 1 --cl3 2 --rats 2")); + PrintAndLogEx(NORMAL, _YELLOW_(" hf 14a config --atqa forcce --bcc ignore --cl2 force --cl3 skip --rats skip")); PrintAndLogEx(NORMAL, _YELLOW_(" hf mf wrbl 0 A FFFFFFFFFFFF 04112233445566184200626364656667")); - PrintAndLogEx(NORMAL, _YELLOW_(" hf 14a config --atqa 0 --bcc 0 --cl2 0 --rats 0")); + PrintAndLogEx(NORMAL, _YELLOW_(" hf 14a config --std")); PrintAndLogEx(NORMAL, _CYAN_(" MFUL ")"/" _CYAN_(" MFUL EV1 ")"/" _CYAN_(" MFULC")":"); - PrintAndLogEx(NORMAL, _YELLOW_(" hf 14a config --atqa 1 --bcc 2 --cl2 1 --cl3 2 r 2")); + PrintAndLogEx(NORMAL, _YELLOW_(" hf 14a config --atqa force --bcc ignore --cl2 force --cl3 skip -rats skip")); PrintAndLogEx(NORMAL, _YELLOW_(" hf mfu setuid 04112233445566")); - PrintAndLogEx(NORMAL, _YELLOW_(" hf 14a config --atqa 0 --bcc 0 --cl2 0 --rats 0")); + PrintAndLogEx(NORMAL, _YELLOW_(" hf 14a config --std")); return PM3_SUCCESS; } static int CmdHf14AConfig(const char *Cmd) { @@ -244,44 +244,101 @@ static int CmdHf14AConfig(const char *Cmd) { CLIParserContext *ctx; CLIParserInit(&ctx, "hf 14a config", "Configure 14a settings (use with caution)", - "hf 14a config -> Print current configuration\n" - "hf 14a config --atqa 0 -> Follow standard\n" - "hf 14a config --atqa 1 -> Force execution of anticollision\n" - "hf 14a config --atqa 2 -> Skip anticollision\n" - "hf 14a config --bcc 0 -> Follow standard\n" - "hf 14a config --bcc 1 -> Force fix of bad BCC in anticollision\n" - "hf 14a config --bcc 2 -> Use card BCC\n" - "hf 14a config --cl2 0 -> Follow standard\n" - "hf 14a config --cl2 1 -> Execute CL2\n" - "hf 14a config --cl2 2 -> Skip CL2\n" - "hf 14a config --cl3 0 -> Follow standard\n" - "hf 14a config --cl3 1 -> Execute CL3\n" - "hf 14a config --cl3 2 -> Skip CL3\n" - "hf 14a config --rats 0 -> Follow standard\n" - "hf 14a config --rats 1 -> Execute RATS\n" - "hf 14a config --rats 2 -> Skip RATS"); + "hf 14a config -> Print current configuration\n" + "hf 14a config --std -> Reset default configuration (follow standard)\n" + "hf 14a config --atqa std -> Follow standard\n" + "hf 14a config --atqa force -> Force execution of anticollision\n" + "hf 14a config --atqa skip -> Skip anticollision\n" + "hf 14a config --bcc std -> Follow standard\n" + "hf 14a config --bcc fix -> Fix bad BCC in anticollision\n" + "hf 14a config --bcc ignore -> Ignore bad BCC and use it as such\n" + "hf 14a config --cl2 std -> Follow standard\n" + "hf 14a config --cl2 force -> Execute CL2\n" + "hf 14a config --cl2 skip -> Skip CL2\n" + "hf 14a config --cl3 std -> Follow standard\n" + "hf 14a config --cl3 force -> Execute CL3\n" + "hf 14a config --cl3 skip -> Skip CL3\n" + "hf 14a config --rats std -> Follow standard\n" + "hf 14a config --rats force -> Execute RATS\n" + "hf 14a config --rats skip -> Skip RATS"); void *argtable[] = { arg_param_begin, - arg_int0(NULL, "atqa", "", "Configure ATQA<>anticollision behavior"), - arg_int0(NULL, "bcc", "", "Configure BCC behavior"), - arg_int0(NULL, "cl2", "", "Configure SAK<>CL2 behavior"), - arg_int0(NULL, "cl3", "", "Configure SAK<>CL3 behavior"), - arg_int0(NULL, "rats", "", "Configure RATS behavior"), + arg_str0(NULL, "atqa", "", "Configure ATQA<>anticollision behavior"), + arg_str0(NULL, "bcc", "", "Configure BCC behavior"), + arg_str0(NULL, "cl2", "", "Configure SAK<>CL2 behavior"), + arg_str0(NULL, "cl3", "", "Configure SAK<>CL3 behavior"), + arg_str0(NULL, "rats", "", "Configure RATS behavior"), + arg_lit0(NULL, "std", "Reset default configuration: follow all standard"), arg_lit0("v", "verbose", "verbose output, also prints examples for reviving Gen2 cards"), arg_param_end }; CLIExecWithReturn(ctx, Cmd, argtable, true); + bool defaults = arg_get_lit(ctx, 6); + int vlen = 0; + char value[10]; + int atqa = defaults ? 0 : -1; + CLIParamStrToBuf(arg_get_str(ctx, 1), (uint8_t *)value, sizeof(value), &vlen); + if (vlen > 0) { + if (strcmp(value, "std") == 0) atqa = 0; + else if (strcmp(value, "force") == 0) atqa = 1; + else if (strcmp(value, "skip") == 0) atqa = 2; + else { + PrintAndLogEx(ERR, "atqa argument must be 'std', 'force', or 'skip'"); + CLIParserFree(ctx); + return PM3_EINVARG; + } + } + int bcc = defaults ? 0 : -1; + CLIParamStrToBuf(arg_get_str(ctx, 2), (uint8_t *)value, sizeof(value), &vlen); + if (vlen > 0) { + if (strcmp(value, "std") == 0) bcc = 0; + else if (strcmp(value, "fix") == 0) bcc = 1; + else if (strcmp(value, "ignore") == 0) bcc = 2; + else { + PrintAndLogEx(ERR, "bcc argument must be 'std', 'fix', or 'ignore'"); + CLIParserFree(ctx); + return PM3_EINVARG; + } + } + int cl2 = defaults ? 0 : -1; + CLIParamStrToBuf(arg_get_str(ctx, 3), (uint8_t *)value, sizeof(value), &vlen); + if (vlen > 0) { + if (strcmp(value, "std") == 0) cl2 = 0; + else if (strcmp(value, "force") == 0) cl2 = 1; + else if (strcmp(value, "skip") == 0) cl2 = 2; + else { + PrintAndLogEx(ERR, "cl2 argument must be 'std', 'force', or 'skip'"); + CLIParserFree(ctx); + return PM3_EINVARG; + } + } + int cl3 = defaults ? 0 : -1; + CLIParamStrToBuf(arg_get_str(ctx, 4), (uint8_t *)value, sizeof(value), &vlen); + if (vlen > 0) { + if (strcmp(value, "std") == 0) cl3 = 0; + else if (strcmp(value, "force") == 0) cl3 = 1; + else if (strcmp(value, "skip") == 0) cl3 = 2; + else { + PrintAndLogEx(ERR, "cl3 argument must be 'std', 'force', or 'skip'"); + CLIParserFree(ctx); + return PM3_EINVARG; + } + } + int rats = defaults ? 0 : -1; + CLIParamStrToBuf(arg_get_str(ctx, 5), (uint8_t *)value, sizeof(value), &vlen); + if (vlen > 0) { + if (strcmp(value, "std") == 0) rats = 0; + else if (strcmp(value, "force") == 0) rats = 1; + else if (strcmp(value, "skip") == 0) rats = 2; + else { + PrintAndLogEx(ERR, "rats argument must be 'std', 'force', or 'skip'"); + CLIParserFree(ctx); + return PM3_EINVARG; + } + } - int atqa = arg_get_int_def(ctx, 1, -1); - int bcc = arg_get_int_def(ctx, 2, -1); - int cl2 = arg_get_int_def(ctx, 3, -1); - int cl3 = arg_get_int_def(ctx, 4, -1); - int rats = arg_get_int_def(ctx, 5, -1); - - int *config_options[5] = {&atqa, &bcc, &cl2, &cl3, &rats}; - - bool verbose = arg_get_lit(ctx, 6); + bool verbose = arg_get_lit(ctx, 7); CLIParserFree(ctx); @@ -294,15 +351,6 @@ static int CmdHf14AConfig(const char *Cmd) { hf_14a_config_example(); } - for (int i = 0; i < 5; ++i) { - if (*config_options[i] > -1) { - if (*config_options[i] > 2) { - PrintAndLogEx(ERR, "Argument must be 0, 1, or 2"); - return PM3_EINVARG; - } - } - } - hf14a_config config = { .forceanticol = atqa, .forcebcc = bcc, From 0b3931f1b057f9c641711883d0d099c078b574f3 Mon Sep 17 00:00:00 2001 From: Philippe Teuwen Date: Thu, 31 Dec 2020 11:44:19 +0100 Subject: [PATCH 269/682] adapt doc --- doc/magic_cards_notes.md | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/doc/magic_cards_notes.md b/doc/magic_cards_notes.md index 08aaa0386..d24a0b7c5 100644 --- a/doc/magic_cards_notes.md +++ b/doc/magic_cards_notes.md @@ -45,12 +45,12 @@ Here are some tips if the card doesn't react or gives error on a simple `hf 14a Let's force a 4b UID anticollision and see what happens: ``` -hf 14a config --atqa 1 --bcc 2 --cl2 2 --rats 2 +hf 14a config --atqa force --bcc ignore --cl2 skip --rats skip hf 14a reader ``` It it responds, we know it's a TypeA card. But maybe it's a 7b UID, so let's force a 7b UID anticollision: ``` -hf 14a config --atqa 1 --bcc 2 --cl2 1 --cl3 2 --rats 2 +hf 14a config --atqa force --bcc ignore --cl2 force --cl3 skip --rats skip hf 14a reader ``` At this stage, you know if it's a TypeA 4b or 7b card and you can check further on this page how to reconfigure different types of cards. @@ -58,7 +58,7 @@ At this stage, you know if it's a TypeA 4b or 7b card and you can check further To restore anticollision config of the Proxmark3: ``` -hf 14a config --atqa 0 --bcc 0 --cl2 0 --cl3 0 --rats 0 +hf 14a config --std ``` # MIFARE Classic @@ -341,20 +341,20 @@ hf 14a config -h e.g. for 4b UID: ``` -hf 14a config --atqa 1 --bcc 2 --cl2 2 --rats 2 +hf 14a config --atqa force --bcc ignore --cl2 skip --rats skip hf mf wrbl 0 A FFFFFFFFFFFF 11223344440804006263646566676869 # for 1k hf mf wrbl 0 A FFFFFFFFFFFF 11223344441802006263646566676869 # for 4k -hf 14a config --atqa 0 --bcc 0 --cl2 0 --rats 0 +hf 14a config --std hf 14a reader ``` e.g. for 7b UID: ``` -hf 14a config --atqa 1 --bcc 2 --cl2 1 --cl3 2 --rats 2 +hf 14a config --atqa force --bcc ignore --cl2 force --cl3 skip --rats skip hf mf wrbl 0 A FFFFFFFFFFFF 04112233445566084400626364656667 # for 1k hf mf wrbl 0 A FFFFFFFFFFFF 04112233445566184200626364656667 # for 4k -hf 14a config --atqa 0 --bcc 0 --cl2 0 --cl3 0 --rats 0 +hf 14a config --std hf 14a reader ``` ## MIFARE Classic DirectWrite, FUID version aka 1-write @@ -604,9 +604,9 @@ hf 14a config -h E.g.: ``` -hf 14a config --atqa 1 --bcc 2 --cl2 1 --cl3 2 --rats 2 +hf 14a config --atqa force --bcc ignore --cl2 force --cl3 skip --rats skip hf mfu setuid 04112233445566 -hf 14a config --atqa 0 --bcc 0 --cl2 0 --cl3 0 --rats 0 +hf 14a config --std hf 14a reader ``` From afc4d78d68f0ca3e51bd997cd18f0ceeb53949b9 Mon Sep 17 00:00:00 2001 From: iceman1001 Date: Thu, 31 Dec 2020 13:51:38 +0100 Subject: [PATCH 270/682] hf mfu eload/restore/sim/cauth - now uses cliparser --- client/src/cmdhfmfu.c | 371 ++++++++++++++++++++---------------------- 1 file changed, 173 insertions(+), 198 deletions(-) diff --git a/client/src/cmdhfmfu.c b/client/src/cmdhfmfu.c index 2a32e0a8d..8d3e85c36 100644 --- a/client/src/cmdhfmfu.c +++ b/client/src/cmdhfmfu.c @@ -42,73 +42,6 @@ static int CmdHelp(const char *Cmd); -static int usage_hf_mfu_restore(void) { - PrintAndLogEx(NORMAL, "Restore dumpfile onto card."); - PrintAndLogEx(NORMAL, "Usage: hf mfu restore [h] [l] [s] k n "); - PrintAndLogEx(NORMAL, " Options :"); - PrintAndLogEx(NORMAL, " k : (optional) key for authentication [UL-C 16bytes, EV1/NTAG 4bytes]"); - PrintAndLogEx(NORMAL, " l : (optional) swap entered key's endianness"); - PrintAndLogEx(NORMAL, " s : (optional) enable special write UID " _BLUE_("-MAGIC TAG ONLY-")); - PrintAndLogEx(NORMAL, " e : (optional) enable special write version/signature " _BLUE_("-MAGIC NTAG 21* ONLY-")); - PrintAndLogEx(NORMAL, " r : (optional) use the password found in dumpfile to configure tag. requires " _YELLOW_("'e'") " parameter to work"); - PrintAndLogEx(NORMAL, " f : " _YELLOW_("filename w .bin") " to restore"); - PrintAndLogEx(NORMAL, ""); - PrintAndLogEx(NORMAL, "Examples:"); - PrintAndLogEx(NORMAL, _YELLOW_(" hf mfu restore s f myfile")); - PrintAndLogEx(NORMAL, _YELLOW_(" hf mfu restore k AABBCCDD s f myfile")); - PrintAndLogEx(NORMAL, _YELLOW_(" hf mfu restore k AABBCCDD s e r f myfile")); - PrintAndLogEx(NORMAL, ""); - return PM3_SUCCESS; -} - -static int usage_hf_mfu_eload(void) { - PrintAndLogEx(NORMAL, "It loads emul dump from the file " _YELLOW_("`filename.eml`")); - PrintAndLogEx(NORMAL, "Hint: See " _YELLOW_("`script run hf_mfu_dumptoemulator`") " to convert the .bin to the eml"); - PrintAndLogEx(NORMAL, "Usage: hf mfu eload u [numblocks]"); - PrintAndLogEx(NORMAL, " Options:"); - PrintAndLogEx(NORMAL, " h : this help"); - PrintAndLogEx(NORMAL, " u : UL (required)"); - PrintAndLogEx(NORMAL, " [filename] : without `.eml` (required)"); - PrintAndLogEx(NORMAL, " numblocks : number of blocks to load from eml file (optional)"); - PrintAndLogEx(NORMAL, ""); - PrintAndLogEx(NORMAL, "Examples:"); - PrintAndLogEx(NORMAL, _YELLOW_(" hf mfu eload u filename")); - PrintAndLogEx(NORMAL, _YELLOW_(" hf mfu eload u filename 57")); - PrintAndLogEx(NORMAL, ""); - return PM3_SUCCESS; -} - -static int usage_hf_mfu_sim(void) { - PrintAndLogEx(NORMAL, "\nEmulating Ultralight tag from emulator memory\n"); - PrintAndLogEx(NORMAL, "\nBe sure to load the emulator memory first!\n"); - PrintAndLogEx(NORMAL, "Usage: hf mfu sim t 7 u [n ]"); - PrintAndLogEx(NORMAL, "Options:"); - PrintAndLogEx(NORMAL, " h : this help"); - PrintAndLogEx(NORMAL, " t 7 : 7 = NTAG or Ultralight sim (required)"); - PrintAndLogEx(NORMAL, " n : exit simulation after blocks have been read by reader. 0 = infinite (optional)"); - PrintAndLogEx(NORMAL, " u : 4 or 7 byte UID (optional)"); - PrintAndLogEx(NORMAL, ""); - PrintAndLogEx(NORMAL, "Examples:"); - PrintAndLogEx(NORMAL, _YELLOW_(" hf mfu sim t 7")); - PrintAndLogEx(NORMAL, _YELLOW_(" hf mfu sim t 7 u 1122344556677")); - PrintAndLogEx(NORMAL, _YELLOW_(" hf mfu sim t 7 u 1122344556677 n 5")); - PrintAndLogEx(NORMAL, ""); - return PM3_SUCCESS; -} - -static int usage_hf_mfu_ucauth(void) { - PrintAndLogEx(NORMAL, "Tests 3DES password on Mifare Ultralight-C tag."); - PrintAndLogEx(NORMAL, "If password is not specified, a set of known defaults will be tested."); - PrintAndLogEx(NORMAL, "Usage: hf mfu cauth [k] "); - PrintAndLogEx(NORMAL, " k - keep field on (only if a password is provided too)"); - PrintAndLogEx(NORMAL, " [password] - (32 hex symbols)"); - PrintAndLogEx(NORMAL, "Examples:"); - PrintAndLogEx(NORMAL, _YELLOW_(" hf mfu cauth")); - PrintAndLogEx(NORMAL, _YELLOW_(" hf mfu cauth 000102030405060708090a0b0c0d0e0f")); - PrintAndLogEx(NORMAL, ""); - return PM3_SUCCESS; -} - static int usage_hf_mfu_ucsetpwd(void) { PrintAndLogEx(NORMAL, "Set 3DES password on Mifare Ultralight-C tag."); PrintAndLogEx(NORMAL, "Usage: hf mfu setpwd "); @@ -349,10 +282,10 @@ static int try_default_3des_keys(uint8_t **correct_key) { uint8_t *key = default_3des_keys[i]; if (ulc_authentication(key, true)) { *correct_key = key; - return 1; + return PM3_SUCCESS; } } - return 0; + return PM3_ESOFT; } static int ulev1_requestAuthentication(uint8_t *pwd, uint8_t *pack, uint16_t packLength) { @@ -615,7 +548,7 @@ int ul_print_type(uint32_t tagtype, uint8_t spaces) { memset(typestr, 0x00, sizeof(typestr)); if (tagtype & UL) - snprintf(typestr, sizeof(typestr), "%*sTYPE: " _YELLOW_("MIFARE Ultralight (MF0ICU1)s"), spaces, ""); + snprintf(typestr, sizeof(typestr), "%*sTYPE: " _YELLOW_("MIFARE Ultralight (MF0ICU1)"), spaces, ""); else if (tagtype & UL_C) snprintf(typestr, sizeof(typestr), "%*sTYPE: " _YELLOW_("MIFARE Ultralight C (MF0ULC)"), spaces, ""); else if (tagtype & UL_NANO_40) @@ -676,7 +609,7 @@ int ul_print_type(uint32_t tagtype, uint8_t spaces) { snprintf(typestr + strlen(typestr), 4, " ("); snprintf(typestr + strlen(typestr), sizeof(typestr) - strlen(typestr), " %s ", (tagtype & MAGIC) ? _GREEN_("magic") : ""); - tagtype ^= MAGIC; + tagtype &= ~(MAGIC); snprintf(typestr + strlen(typestr), sizeof(typestr) - strlen(typestr), "%s", (tagtype & MAGIC_1A) ? _GREEN_("Gen 1a") : ""); snprintf(typestr + strlen(typestr), sizeof(typestr) - strlen(typestr), "%s", (tagtype & MAGIC_1B) ? _GREEN_("Gen 1b") : ""); @@ -688,11 +621,11 @@ int ul_print_type(uint32_t tagtype, uint8_t spaces) { } static int ulc_print_3deskey(uint8_t *data) { - PrintAndLogEx(NORMAL, " deskey1 [44/0x2C]: %s [%s]", sprint_hex(data, 4), sprint_ascii(data, 4)); - PrintAndLogEx(NORMAL, " deskey1 [45/0x2D]: %s [%s]", sprint_hex(data + 4, 4), sprint_ascii(data + 4, 4)); - PrintAndLogEx(NORMAL, " deskey2 [46/0x2E]: %s [%s]", sprint_hex(data + 8, 4), sprint_ascii(data + 8, 4)); - PrintAndLogEx(NORMAL, " deskey2 [47/0x2F]: %s [%s]", sprint_hex(data + 12, 4), sprint_ascii(data + 12, 4)); - PrintAndLogEx(NORMAL, "\n 3des key: %s", sprint_hex(SwapEndian64(data, 16, 8), 16)); + PrintAndLogEx(INFO, " deskey1 [44/0x2C]: %s [%s]", sprint_hex(data, 4), sprint_ascii(data, 4)); + PrintAndLogEx(INFO, " deskey1 [45/0x2D]: %s [%s]", sprint_hex(data + 4, 4), sprint_ascii(data + 4, 4)); + PrintAndLogEx(INFO, " deskey2 [46/0x2E]: %s [%s]", sprint_hex(data + 8, 4), sprint_ascii(data + 8, 4)); + PrintAndLogEx(INFO, " deskey2 [47/0x2F]: %s [%s]", sprint_hex(data + 12, 4), sprint_ascii(data + 12, 4)); + PrintAndLogEx(INFO, "3des key: " _GREEN_("%s"), sprint_hex_inrow(SwapEndian64(data, 16, 8), 16)); return PM3_SUCCESS; } @@ -839,7 +772,7 @@ static int ulev1_print_counters(void) { len = ulev1_readCounter(i, counter, sizeof(counter)); if (len == 3) { PrintAndLogEx(INFO, " [%0d]: %s", i, sprint_hex(counter, 3)); - PrintAndLogEx(SUCCESS, " - %02X tearing (%s)" + PrintAndLogEx(SUCCESS, " - %02X tearing ( %s )" , tear[0] , (tear[0] == 0xBD) ? _GREEN_("ok") : _RED_("fail") ); @@ -930,7 +863,7 @@ static int ulev1_print_signature(TagTypeUL_t tagtype, uint8_t *uid, uint8_t *sig if (is_valid == false || i == ARRAYLEN(nxp_mfu_public_keys)) { PrintAndLogEx(INFO, " Elliptic curve parameters: NID_secp128r1"); PrintAndLogEx(INFO, " TAG IC Signature: %s", sprint_hex_inrow(signature, signature_len)); - PrintAndLogEx(SUCCESS, " Signature verification (" _RED_("fail") ")"); + PrintAndLogEx(SUCCESS, " Signature verification ( " _RED_("fail") " )"); return PM3_ESOFT; } @@ -938,7 +871,7 @@ static int ulev1_print_signature(TagTypeUL_t tagtype, uint8_t *uid, uint8_t *sig PrintAndLogEx(INFO, "IC signature public key value: %s", nxp_mfu_public_keys[i].value); PrintAndLogEx(INFO, " Elliptic curve parameters: NID_secp128r1"); PrintAndLogEx(INFO, " TAG IC Signature: %s", sprint_hex_inrow(signature, signature_len)); - PrintAndLogEx(SUCCESS, " Signature verification (" _GREEN_("successful") ")"); + PrintAndLogEx(SUCCESS, " Signature verification ( " _GREEN_("successful") " )"); return PM3_SUCCESS; } @@ -968,7 +901,7 @@ static int ntag_print_counter(void) { len = ulev1_readCounter(0x02, counter, sizeof(counter)); (void)len; PrintAndLogEx(INFO, " [02]: %s", sprint_hex(counter, 3)); - PrintAndLogEx(SUCCESS, " - %02X tearing (%s)" + PrintAndLogEx(SUCCESS, " - %02X tearing ( %s )" , tear[0] , (tear[0] == 0xBD) ? _GREEN_("ok") : _RED_("fail") ); @@ -1038,6 +971,19 @@ static int ul_magic_test(void) { return 0; } +static char *GenerateFilename(const char *prefix, const char *suffix) { + iso14a_card_select_t card; + if (ul_select(&card) == false) { + PrintAndLogEx(WARNING, "No tag found."); + return NULL; + } + + char *fptr = calloc(sizeof(char) * (strlen(prefix) + strlen(suffix)) + sizeof(card.uid) * 2 + 1, sizeof(uint8_t)); + strcpy(fptr, prefix); + FillFileNameByUID(fptr, card.uid, suffix, card.uidlen); + return fptr; +} + uint32_t GetHF14AMfU_Type(void) { TagTypeUL_t tagtype = UNKNOWN; @@ -1218,7 +1164,7 @@ static int CmdHF14AMfUInfo(const char *Cmd) { void *argtable[] = { arg_param_begin, arg_str0("k", "key", "", "key for authentication (UL-C 16 bytes, EV1/NTAG 4 bytes)"), - arg_lit0("l", NULL, "swap entered key's endianness"), + arg_lit0("l", NULL, "swap entered key's endianness"), arg_param_end }; CLIExecWithReturn(ctx, Cmd, argtable, true); @@ -1319,7 +1265,7 @@ static int CmdHF14AMfUInfo(const char *Cmd) { } // also try to diversify default keys.. look into CmdHF14AMfGenDiverseKeys - if (try_default_3des_keys(&key)) { + if (try_default_3des_keys(&key) == PM3_SUCCESS) { PrintAndLogEx(SUCCESS, "Found default 3des key: "); uint8_t keySwap[16]; memcpy(keySwap, SwapEndian64(key, 16, 8), 16); @@ -1425,7 +1371,7 @@ static int CmdHF14AMfUInfo(const char *Cmd) { num_to_bytes(ul_ev1_pwdgenA(card.uid), 4, key); len = ulev1_requestAuthentication(key, pack, sizeof(pack)); if (len > -1) { - PrintAndLogEx(SUCCESS, "Found a default password: " _GREEN_("%s") " Pack: %02X %02X", sprint_hex(key, 4), pack[0], pack[1]); + PrintAndLogEx(SUCCESS, "Found default password " _GREEN_("%s") " pack %02X %02X", sprint_hex(key, 4), pack[0], pack[1]); goto out; } @@ -1437,7 +1383,7 @@ static int CmdHF14AMfUInfo(const char *Cmd) { num_to_bytes(ul_ev1_pwdgenB(card.uid), 4, key); len = ulev1_requestAuthentication(key, pack, sizeof(pack)); if (len > -1) { - PrintAndLogEx(SUCCESS, "Found a default password: " _GREEN_("%s") " Pack: %02X %02X", sprint_hex(key, 4), pack[0], pack[1]); + PrintAndLogEx(SUCCESS, "Found default password " _GREEN_("%s") " pack %02X %02X", sprint_hex(key, 4), pack[0], pack[1]); goto out; } @@ -1449,7 +1395,7 @@ static int CmdHF14AMfUInfo(const char *Cmd) { num_to_bytes(ul_ev1_pwdgenC(card.uid), 4, key); len = ulev1_requestAuthentication(key, pack, sizeof(pack)); if (len > -1) { - PrintAndLogEx(SUCCESS, "Found a default password: " _GREEN_("%s") " Pack: %02X %02X", sprint_hex(key, 4), pack[0], pack[1]); + PrintAndLogEx(SUCCESS, "Found default password " _GREEN_("%s") " pack %02X %02X", sprint_hex(key, 4), pack[0], pack[1]); goto out; } @@ -1461,7 +1407,7 @@ static int CmdHF14AMfUInfo(const char *Cmd) { num_to_bytes(ul_ev1_pwdgenD(card.uid), 4, key); len = ulev1_requestAuthentication(key, pack, sizeof(pack)); if (len > -1) { - PrintAndLogEx(SUCCESS, "Found a default password:" _GREEN_("%s") " Pack: %02X %02X", sprint_hex(key, 4), pack[0], pack[1]); + PrintAndLogEx(SUCCESS, "Found default password" _GREEN_("%s") " pack %02X %02X", sprint_hex(key, 4), pack[0], pack[1]); goto out; } @@ -1473,7 +1419,7 @@ static int CmdHF14AMfUInfo(const char *Cmd) { key = default_pwd_pack[i]; len = ulev1_requestAuthentication(key, pack, sizeof(pack)); if (len > -1) { - PrintAndLogEx(SUCCESS, "Found a default password: " _GREEN_("%s") " Pack: %02X %02X", sprint_hex(key, 4), pack[0], pack[1]); + PrintAndLogEx(SUCCESS, "Found default password " _GREEN_("%s") " pack %02X %02X", sprint_hex(key, 4), pack[0], pack[1]); break; } else { if (ul_auth_select(&card, tagtype, has_auth_key, authkeyptr, pack, sizeof(pack)) == PM3_ESOFT) { @@ -1515,7 +1461,7 @@ static int CmdHF14AMfUWrBl(const char *Cmd) { void *argtable[] = { arg_param_begin, arg_str0("k", "key", "", "key for authentication (UL-C 16 bytes, EV1/NTAG 4 bytes)"), - arg_lit0("l", NULL, "swap entered key's endianness"), + arg_lit0("l", NULL, "swap entered key's endianness"), arg_int1("b", "block", "", "block number to write"), arg_str1("d", "data", "", "block data (4 or 16 hex bytes, 16 hex bytes will do a compatibility write)"), arg_param_end @@ -1645,7 +1591,7 @@ static int CmdHF14AMfURdBl(const char *Cmd) { void *argtable[] = { arg_param_begin, arg_str0("k", "key", "", "key for authentication (UL-C 16 bytes, EV1/NTAG 4 bytes)"), - arg_lit0("l", NULL, "swap entered key's endianness"), + arg_lit0("l", NULL, "swap entered key's endianness"), arg_int1("b", "block", "", "block number to write"), arg_param_end }; @@ -1729,7 +1675,7 @@ static int CmdHF14AMfURdBl(const char *Cmd) { PrintAndLogEx(INFO, "-----------------------------"); PrintAndLogEx(INFO, "%02d/0x%02X | %s| %s\n", blockno, blockno, sprint_hex(d, 4), sprint_ascii(d, 4)); } else { - PrintAndLogEx(WARNING, "Failed reading block: (%02x)", isOK); + PrintAndLogEx(WARNING, "Failed reading block: ( %02x )", isOK); } } else { PrintAndLogEx(WARNING, "Command execute time-out"); @@ -1906,7 +1852,7 @@ static int CmdHF14AMfUDump(const char *Cmd) { arg_param_begin, arg_str0("f", "file", "", "specify a filename for dump file"), arg_str0("k", "key", "", "key for authentication (UL-C 16 bytes, EV1/NTAG 4 bytes)"), - arg_lit0("l", NULL, "swap entered key's endianness"), + arg_lit0("l", NULL, "swap entered key's endianness"), arg_int0("p", "page", "", "manually set start page number to start from"), arg_int0("q", "qty", "", "manually set number of pages to dump"), arg_param_end @@ -2154,82 +2100,58 @@ static void wait4response(uint8_t b) { // Restore dump file onto tag // static int CmdHF14AMfURestore(const char *Cmd) { + CLIParserContext *ctx; + CLIParserInit(&ctx, "hf mfu restore", + "Restore dumpfile onto card.", + "hf mfu restore -f myfile -s -> user specified filename and special write\n" + "hf mfu restore -f myfile -k AABBCCDD -s -> user specified filename, special write and use key\n" + "hf mfu restore -f myfile -k AABBCCDD -ser -> user specified filename, special write, use key, ..." + ); - char tempStr[50] = {0}; + void *argtable[] = { + arg_param_begin, + arg_str1("f", "file", "", "specify a filename to restore"), + arg_str0("k", "key", "", "key for authentication (UL-C 16 bytes, EV1/NTAG 4 bytes)"), + arg_lit0("l", NULL, "swap entered key's endianness"), + arg_lit0("s", NULL, "enable special write UID -MAGIC TAG ONLY-"), + arg_lit0("e", NULL, "enable special write version/signature -MAGIC NTAG 21* ONLY-"), + arg_lit0("r", NULL, "use the password found in dumpfile to configure tag. requires " _YELLOW_("'-e'") " parameter to work"), + arg_lit0("v", "verbose", "verbose"), + arg_param_end + }; + CLIExecWithReturn(ctx, Cmd, argtable, false); + + int fnlen = 0; char filename[FILE_PATH_SIZE] = {0}; - uint8_t authkey[16] = {0}; + CLIParamStrToBuf(arg_get_str(ctx, 1), (uint8_t *)filename, FILE_PATH_SIZE, &fnlen); + + int ak_len = 0; + uint8_t authkey[16] = {0x00}; uint8_t *p_authkey = authkey; - uint8_t cmdp = 0, keylen = 0; + CLIGetHexWithReturn(ctx, 2, authkey, &ak_len); + + bool swap_endian = arg_get_lit(ctx, 3); + bool write_special = arg_get_lit(ctx, 4); + bool write_extra = arg_get_lit(ctx, 5); + bool read_key = arg_get_lit(ctx, 6); + bool verbose = arg_get_lit(ctx, 7); + CLIParserFree(ctx); + bool hasKey = false; - bool swapEndian = false; - bool errors = false; - bool write_special = false; - bool write_extra = false; - bool read_key = false; - bool verbose = false; - size_t filelen = 0; - - memset(authkey, 0x00, sizeof(authkey)); - - while (param_getchar(Cmd, cmdp) != 0x00 && !errors) { - switch (tolower(param_getchar(Cmd, cmdp))) { - case 'h': - return usage_hf_mfu_restore(); - case 'k': - keylen = param_getstr(Cmd, cmdp + 1, tempStr, sizeof(tempStr)); - if (keylen == 32 || keylen == 8) { //ul-c or ev1/ntag key length - errors = param_gethex(tempStr, 0, authkey, keylen); - keylen /= 2; - } else { - PrintAndLogEx(WARNING, "ERROR: Key is incorrect length\n"); - errors = true; - } - cmdp += 2; - hasKey = true; - break; - case 'l': - swapEndian = true; - cmdp++; - break; - case 'f': - filelen = param_getstr(Cmd, cmdp + 1, filename, FILE_PATH_SIZE); - - if (filelen > FILE_PATH_SIZE - 5) - filelen = FILE_PATH_SIZE - 5; - - if (filelen < 1) - sprintf(filename, "dumpdata.bin"); - - cmdp += 2; - break; - case 's': - cmdp++; - write_special = true; - break; - case 'e': - cmdp++; - write_extra = true; - break; - case 'r': - cmdp++; - read_key = true; - break; - case 'v': - cmdp++; - verbose = true; - break; - default: - PrintAndLogEx(WARNING, "Unknown parameter: " _RED_("'%c'"), param_getchar(Cmd, cmdp)); - errors = true; - break; - } - } - - //Validations - if (errors || cmdp == 0) return usage_hf_mfu_restore(); uint8_t *dump = NULL; size_t bytes_read = 0; + + if (fnlen == 0) { + char *fptr = GenerateFilename("hf-mfu-", "-dump.bin"); + if (fptr != NULL) { + strcpy(filename, fptr); + } else { + snprintf(filename, sizeof(filename), "dumpdata.bin"); + } + free(fptr); + } + if (loadFile_safe(filename, "", (void **)&dump, &bytes_read) != PM3_SUCCESS) { PrintAndLogEx(WARNING, "Could not find file " _YELLOW_("%s"), filename); return PM3_EIO; @@ -2263,19 +2185,19 @@ static int CmdHF14AMfURestore(const char *Cmd) { printMFUdumpEx(mem, pages, 0); // Swap endianness - if (swapEndian && hasKey) { - if (keylen == 16) - p_authkey = SwapEndian64(authkey, keylen, 8); + if (swap_endian && hasKey) { + if (ak_len == 16) + p_authkey = SwapEndian64(authkey, ak_len, 8); else - p_authkey = SwapEndian64(authkey, keylen, 4); + p_authkey = SwapEndian64(authkey, ak_len, 4); } uint8_t data[20] = {0}; uint8_t keytype = 0; // set key - only once if (hasKey) { - keytype = (keylen == 16) ? 1 : 2; - memcpy(data + 4, p_authkey, keylen); + keytype = (ak_len == 16) ? 1 : 2; + memcpy(data + 4, p_authkey, ak_len); } // write version, signature, pack @@ -2379,16 +2301,54 @@ static int CmdHF14AMfURestore(const char *Cmd) { // Load emulator with dump file // static int CmdHF14AMfUeLoad(const char *Cmd) { - char c = tolower(param_getchar(Cmd, 0)); - if (c == 'h' || c == 0x00) return usage_hf_mfu_eload(); + + CLIParserContext *ctx; + CLIParserInit(&ctx, "hf mfu eload", + "It loads emul dump from the file `filename.eml`", + "hf mfu eload -u -f myfile\n" + "hf mfu eload -u -f myfile -q 57 -> load 57 blocks from myfile" + ); + + void *argtable[] = { + arg_param_begin, + arg_str1("f", "file", "", "specify a filename w/o `.eml` to load"), + arg_lit1("u", NULL, "Ultralight Family type"), + arg_int0("q", "qty", "", "number of blocks to load from eml file"), + arg_param_end + }; + CLIExecWithReturn(ctx, Cmd, argtable, false); + + int fnlen = 0; + char filename[FILE_PATH_SIZE] = {0}; + CLIParamStrToBuf(arg_get_str(ctx, 1), (uint8_t *)filename, FILE_PATH_SIZE, &fnlen); + CLIParserFree(ctx); + + PrintAndLogEx(HINT, "Hint: See " _YELLOW_("`script run hf_mfu_dumptoemulator`") " to convert the .bin to .eml"); return CmdHF14AMfELoad(Cmd); } // // Simulate tag // static int CmdHF14AMfUSim(const char *Cmd) { - char c = tolower(param_getchar(Cmd, 0)); - if (c == 'h' || c == 0x00) return usage_hf_mfu_sim(); + CLIParserContext *ctx; + CLIParserInit(&ctx, "hf mfu sim", + "Simulate MIFARE Ultralight family type based upon\n" + "ISO/IEC 14443 type A tag with 4,7 or 10 byte UID\n" + "from emulator memory. See `hf mfu eload` first", + "hf mfu sim -t 2 --uid 1122344556677 -> MIFARE Ultralight\n" + "hf mfu sim -t 7 --uid 1122344556677 -n 5 -> AMIIBO (NTAG 215), pack 0x8080" + ); + + void *argtable[] = { + arg_param_begin, + arg_int1("t", "type", "<1-10> ", "Simulation type to use"), + arg_str0("u", "uid", "", "4, 7 or 10 byte UID"), + arg_int0("n", "num", "", "Exit simulation after blocks have been read by reader. 0 = infinite"), + arg_lit0("v", "verbose", "verbose output"), + arg_param_end + }; + CLIExecWithReturn(ctx, Cmd, argtable, false); + CLIParserFree(ctx); return CmdHF14ASim(Cmd); } @@ -2396,43 +2356,58 @@ static int CmdHF14AMfUSim(const char *Cmd) { // Ultralight C Methods //------------------------------------------------------------------------------- -// // Ultralight C Authentication // - static int CmdHF14AMfUCAuth(const char *Cmd) { - uint8_t cmdp = 0; - char c = tolower(param_getchar(Cmd, 0)); - if (c == 'h') { - return usage_hf_mfu_ucauth(); - } - bool keep_field_on = false; - if (c == 'k') { - keep_field_on = true; - cmdp++; + CLIParserContext *ctx; + CLIParserInit(&ctx, "hf mfu cauth", + "Tests 3DES password on Mifare Ultralight-C tag.\n" + "If password is not specified, a set of known defaults will be tested.", + "hf mfu cauth\n" + "hf mfu cauth --key 000102030405060708090a0b0c0d0e0f" + ); + + void *argtable[] = { + arg_param_begin, + arg_str0("k", "key", "", "key for authentication (UL-C 16 bytes, EV1/NTAG 4 bytes)"), + arg_lit0("l", NULL, "swap entered key's endianness"), + arg_lit0("k", NULL, "keep field on (only if a password is provided too)"), + arg_param_end + }; + CLIExecWithReturn(ctx, Cmd, argtable, true); + + int ak_len = 0; + uint8_t authenticationkey[16] = {0x00}; + uint8_t *authKeyPtr = authenticationkey; + CLIGetHexWithReturn(ctx, 1, authenticationkey, &ak_len); + bool swap_endian = arg_get_lit(ctx, 2); + bool keep_field_on = arg_get_lit(ctx, 3); + CLIParserFree(ctx); + + if (ak_len != 16 && ak_len != 0) { + PrintAndLogEx(WARNING, "ERROR: Key is incorrect length\n"); + return PM3_EINVARG; } - uint8_t key_buf[16]; - uint8_t *key; - int succeeded; + // Swap endianness + if (swap_endian && ak_len) { + authKeyPtr = SwapEndian64(authenticationkey, 16, 8); + } - // If no hex key is specified, try all known ones - if (strlen(Cmd + cmdp) == 0) { - succeeded = try_default_3des_keys(&key); - // Else try user-supplied + bool isok = false; + + // If no hex key is specified, try default keys + if (ak_len == 0) { + isok = (try_default_3des_keys(&authKeyPtr) == PM3_SUCCESS); } else { - if (param_gethex(Cmd, cmdp, key_buf, 32)) { - PrintAndLogEx(WARNING, "Password must include 32 HEX symbols"); - return PM3_EINVARG; - } - succeeded = ulc_authentication(key_buf, ! keep_field_on); - key = key_buf; + // try user-supplied + isok = ulc_authentication(authKeyPtr, !keep_field_on); } - if (succeeded) - PrintAndLogEx(SUCCESS, "Authentication successful. 3des key: %s", sprint_hex(key, 16)); + if (isok) + PrintAndLogEx(SUCCESS, "Authentication success. 3des key: " _GREEN_("%s"), sprint_hex_inrow(authKeyPtr, 16)); else - PrintAndLogEx(WARNING, "Authentication failed"); + PrintAndLogEx(WARNING, "Authentication ( " _RED_("fail") " )"); return PM3_SUCCESS; } @@ -3484,7 +3459,7 @@ static int CmdHF14MfuNDEF(const char *Cmd) { void *argtable[] = { arg_param_begin, arg_str0("k", "key", "replace default key for NDEF", NULL), - arg_lit0("l", "key", "(optional) swap entered key's endianness"), + arg_lit0("l", NULL, "swap entered key's endianness"), arg_param_end }; CLIExecWithReturn(ctx, Cmd, argtable, true); From d08f0d7fe8aed5899cdec4e2f3baead6e749e11a Mon Sep 17 00:00:00 2001 From: iceman1001 Date: Fri, 1 Jan 2021 21:01:10 +0100 Subject: [PATCH 271/682] hf mfu setpwd/setuid/keygen - now uses cliparser --- client/src/cmdhfmfu.c | 199 +++++++++++++++++++++--------------------- 1 file changed, 100 insertions(+), 99 deletions(-) diff --git a/client/src/cmdhfmfu.c b/client/src/cmdhfmfu.c index 8d3e85c36..5f0548968 100644 --- a/client/src/cmdhfmfu.c +++ b/client/src/cmdhfmfu.c @@ -42,41 +42,7 @@ static int CmdHelp(const char *Cmd); -static int usage_hf_mfu_ucsetpwd(void) { - PrintAndLogEx(NORMAL, "Set 3DES password on Mifare Ultralight-C tag."); - PrintAndLogEx(NORMAL, "Usage: hf mfu setpwd "); - PrintAndLogEx(NORMAL, " [password] - (32 hex symbols)"); - PrintAndLogEx(NORMAL, ""); - PrintAndLogEx(NORMAL, "Examples:"); - PrintAndLogEx(NORMAL, _YELLOW_(" hf mfu setpwd 000102030405060708090a0b0c0d0e0f")); - PrintAndLogEx(NORMAL, ""); - return PM3_SUCCESS; -} -static int usage_hf_mfu_ucsetuid(void) { - PrintAndLogEx(NORMAL, "Usage: hf mfu setuid "); - PrintAndLogEx(NORMAL, " [uid] - (14 hex symbols)"); - PrintAndLogEx(NORMAL, "\n"); - PrintAndLogEx(NORMAL, "This only works for " _BLUE_("Magic Ultralight") " tags."); - PrintAndLogEx(NORMAL, ""); - PrintAndLogEx(NORMAL, "Examples:"); - PrintAndLogEx(NORMAL, _YELLOW_(" hf mfu setuid 11223344556677")); - PrintAndLogEx(NORMAL, ""); - return PM3_SUCCESS; -} - -static int usage_hf_mfu_gendiverse(void) { - PrintAndLogEx(NORMAL, "Usage: hf mfu gen [h] [r] "); - PrintAndLogEx(NORMAL, "Options:"); - PrintAndLogEx(NORMAL, " h : this help"); - PrintAndLogEx(NORMAL, " r : read uid from tag"); - PrintAndLogEx(NORMAL, " : 4 byte UID (optional)"); - PrintAndLogEx(NORMAL, "Examples:"); - PrintAndLogEx(NORMAL, _YELLOW_(" hf mfu gen r")); - PrintAndLogEx(NORMAL, _YELLOW_(" hf mfu gen 11223344")); - PrintAndLogEx(NORMAL, ""); - return PM3_SUCCESS; -} static int usage_hf_mfu_pwdgen(void) { PrintAndLogEx(NORMAL, "Usage: hf mfu pwdgen [h|t] [r] "); @@ -2137,7 +2103,7 @@ static int CmdHF14AMfURestore(const char *Cmd) { bool verbose = arg_get_lit(ctx, 7); CLIParserFree(ctx); - bool hasKey = false; + bool has_key = false; uint8_t *dump = NULL; size_t bytes_read = 0; @@ -2185,7 +2151,7 @@ static int CmdHF14AMfURestore(const char *Cmd) { printMFUdumpEx(mem, pages, 0); // Swap endianness - if (swap_endian && hasKey) { + if (swap_endian && has_key) { if (ak_len == 16) p_authkey = SwapEndian64(authkey, ak_len, 8); else @@ -2195,7 +2161,7 @@ static int CmdHF14AMfURestore(const char *Cmd) { uint8_t data[20] = {0}; uint8_t keytype = 0; // set key - only once - if (hasKey) { + if (has_key) { keytype = (ak_len == 16) ? 1 : 2; memcpy(data + 4, p_authkey, ak_len); } @@ -2209,16 +2175,15 @@ static int CmdHF14AMfURestore(const char *Cmd) { #define MFU_NTAG_SPECIAL_VERSION 0xFA #define MFU_NTAG_SPECIAL_SIGNATURE 0xF2 // pwd - if (hasKey || read_key) { + if (has_key || read_key) { + memcpy(data, p_authkey, 4); if (read_key) { // try reading key from dump and use. memcpy(data, mem->data + (bytes_read - MFU_DUMP_PREFIX_LENGTH - 8), 4); - } else { - memcpy(data, p_authkey, 4); } - PrintAndLogEx(NORMAL, "special PWD block written 0x%X - %s\n", MFU_NTAG_SPECIAL_PWD, sprint_hex(data, 4)); + PrintAndLogEx(INFO, "special PWD block written 0x%X - %s\n", MFU_NTAG_SPECIAL_PWD, sprint_hex(data, 4)); clearCommandBuffer(); SendCommandMIX(CMD_HF_MIFAREU_WRITEBL, MFU_NTAG_SPECIAL_PWD, keytype, 0, data, sizeof(data)); @@ -2234,7 +2199,7 @@ static int CmdHF14AMfURestore(const char *Cmd) { memcpy(data, mem->data + (bytes_read - MFU_DUMP_PREFIX_LENGTH - 4), 2); data[2] = 0; data[3] = 0; - PrintAndLogEx(NORMAL, "special PACK block written 0x%X - %s\n", MFU_NTAG_SPECIAL_PACK, sprint_hex(data, 4)); + PrintAndLogEx(INFO, "special PACK block written 0x%X - %s\n", MFU_NTAG_SPECIAL_PACK, sprint_hex(data, 4)); clearCommandBuffer(); SendCommandMIX(CMD_HF_MIFAREU_WRITEBL, MFU_NTAG_SPECIAL_PACK, keytype, 0, data, sizeof(data)); wait4response(MFU_NTAG_SPECIAL_PACK); @@ -2242,7 +2207,7 @@ static int CmdHF14AMfURestore(const char *Cmd) { // Signature for (uint8_t s = MFU_NTAG_SPECIAL_SIGNATURE, i = 0; s < MFU_NTAG_SPECIAL_SIGNATURE + 8; s++, i += 4) { memcpy(data, mem->signature + i, 4); - PrintAndLogEx(NORMAL, "special SIG block written 0x%X - %s\n", s, sprint_hex(data, 4)); + PrintAndLogEx(INFO, "special SIG block written 0x%X - %s\n", s, sprint_hex(data, 4)); clearCommandBuffer(); SendCommandMIX(CMD_HF_MIFAREU_WRITEBL, s, keytype, 0, data, sizeof(data)); wait4response(s); @@ -2251,7 +2216,7 @@ static int CmdHF14AMfURestore(const char *Cmd) { // Version for (uint8_t s = MFU_NTAG_SPECIAL_VERSION, i = 0; s < MFU_NTAG_SPECIAL_VERSION + 2; s++, i += 4) { memcpy(data, mem->version + i, 4); - PrintAndLogEx(NORMAL, "special VERSION block written 0x%X - %s\n", s, sprint_hex(data, 4)); + PrintAndLogEx(INFO, "special VERSION block written 0x%X - %s\n", s, sprint_hex(data, 4)); clearCommandBuffer(); SendCommandMIX(CMD_HF_MIFAREU_WRITEBL, s, keytype, 0, data, sizeof(data)); wait4response(s); @@ -2271,14 +2236,14 @@ static int CmdHF14AMfURestore(const char *Cmd) { wait4response(b); PrintAndLogEx(NORMAL, "." NOLF); } - PrintAndLogEx(NORMAL, "\n"); + PrintAndLogEx(NORMAL, ""); // write special data last if (write_special) { PrintAndLogEx(INFO, "Restoring configuration blocks.\n"); - PrintAndLogEx(NORMAL, "authentication with keytype[%x] %s\n", (uint8_t)(keytype & 0xff), sprint_hex(p_authkey, 4)); + PrintAndLogEx(INFO, "authentication with keytype[%x] %s\n", (uint8_t)(keytype & 0xff), sprint_hex(p_authkey, 4)); // otp, uid, lock, cfg1, cfg0, dynlockbits uint8_t blocks[] = {3, 0, 1, 2, pages - 5, pages - 4, pages - 3}; @@ -2288,13 +2253,13 @@ static int CmdHF14AMfURestore(const char *Cmd) { clearCommandBuffer(); SendCommandMIX(CMD_HF_MIFAREU_WRITEBL, b, keytype, 0, data, sizeof(data)); wait4response(b); - PrintAndLogEx(NORMAL, "special block written %u - %s\n", b, sprint_hex(data, 4)); + PrintAndLogEx(INFO, "special block written %u - %s\n", b, sprint_hex(data, 4)); } } DropField(); free(dump); - PrintAndLogEx(INFO, "Finish restore"); + PrintAndLogEx(INFO, "Restore finished"); return PM3_SUCCESS; } // @@ -2317,10 +2282,6 @@ static int CmdHF14AMfUeLoad(const char *Cmd) { arg_param_end }; CLIExecWithReturn(ctx, Cmd, argtable, false); - - int fnlen = 0; - char filename[FILE_PATH_SIZE] = {0}; - CLIParamStrToBuf(arg_get_str(ctx, 1), (uint8_t *)filename, FILE_PATH_SIZE, &fnlen); CLIParserFree(ctx); PrintAndLogEx(HINT, "Hint: See " _YELLOW_("`script run hf_mfu_dumptoemulator`") " to convert the .bin to .eml"); @@ -2513,26 +2474,38 @@ static int CmdTestDES(const char * cmd) // Mifare Ultralight C - Set password // static int CmdHF14AMfUCSetPwd(const char *Cmd) { + CLIParserContext *ctx; + CLIParserInit(&ctx, "hf mfu setpwd", + "Set the 3DES key on MIFARE Ultralight-C tag. ", + "hf mfu setpwd --key 000102030405060708090a0b0c0d0e0f" + ); - uint8_t pwd[16] = {0x00}; - char cmdp = tolower(param_getchar(Cmd, 0)); + void *argtable[] = { + arg_param_begin, + arg_str0("k", "key", "", "New key (16 bytes)"), + arg_param_end + }; + CLIExecWithReturn(ctx, Cmd, argtable, true); + + int k_len = 0; + uint8_t key[16] = {0x00}; + CLIGetHexWithReturn(ctx, 1, key, &k_len); + CLIParserFree(ctx); - if (strlen(Cmd) == 0 || cmdp == 'h') return usage_hf_mfu_ucsetpwd(); - - if (param_gethex(Cmd, 0, pwd, 32)) { - PrintAndLogEx(WARNING, "Password must include 32 HEX symbols"); + if (k_len != 16) { + PrintAndLogEx(WARNING, "Key must be 16 hex bytes"); return PM3_EINVARG; } clearCommandBuffer(); - SendCommandMIX(CMD_HF_MIFAREUC_SETPWD, 0, 0, 0, pwd, 16); + SendCommandMIX(CMD_HF_MIFAREUC_SETPWD, 0, 0, 0, key, sizeof(key)); PacketResponseNG resp; if (WaitForResponseTimeout(CMD_ACK, &resp, 1500)) { if ((resp.oldarg[0] & 0xff) == 1) { - PrintAndLogEx(INFO, "Ultralight-C new password: %s", sprint_hex(pwd, 16)); + PrintAndLogEx(INFO, "Ultralight-C new key: %s", sprint_hex(key, sizeof(key))); } else { - PrintAndLogEx(WARNING, "Failed writing at block %u", (uint8_t)(resp.oldarg[1] & 0xff)); + PrintAndLogEx(WARNING, "Failed writing at block %u", (uint8_t)(resp.oldarg[1] & 0xFF)); return PM3_ESOFT; } } else { @@ -2546,20 +2519,35 @@ static int CmdHF14AMfUCSetPwd(const char *Cmd) { // Magic UL / UL-C tags - Set UID // static int CmdHF14AMfUCSetUid(const char *Cmd) { + + CLIParserContext *ctx; + CLIParserInit(&ctx, "hf mfu setuid", + "Set uid on MIFARE Ultralight tag.\n" + "This only works for `magic Ultralight` tags.", + "hf mfu setuid --uid 11223344556677" + ); - PacketResponseNG resp; + void *argtable[] = { + arg_param_begin, + arg_str0("uk", "uid", "", "new uid (7 bytes)"), + arg_param_end + }; + CLIExecWithReturn(ctx, Cmd, argtable, true); + + int u_len = 0; uint8_t uid[7] = {0x00}; - char cmdp = tolower(param_getchar(Cmd, 0)); + CLIGetHexWithReturn(ctx, 1, uid, &u_len); + CLIParserFree(ctx); - if (strlen(Cmd) == 0 || cmdp == 'h') return usage_hf_mfu_ucsetuid(); - - if (param_gethex(Cmd, 0, uid, 14)) { - PrintAndLogEx(WARNING, "UID must include 14 HEX symbols"); + if (u_len != 7) { + PrintAndLogEx(WARNING, "UID must be 7 hex bytes"); return PM3_EINVARG; } PrintAndLogEx(INFO, "Please ignore possible transient BCC warnings"); + // read block2. + PacketResponseNG resp; clearCommandBuffer(); SendCommandMIX(CMD_HF_MIFAREU_READBL, 2, 0, 0, NULL, 0); if (!WaitForResponseTimeout(CMD_ACK, &resp, 1500)) { @@ -2632,12 +2620,28 @@ static int CmdHF14AMfUCSetUid(const char *Cmd) { } static int CmdHF14AMfUGenDiverseKeys(const char *Cmd) { + CLIParserContext *ctx; + CLIParserInit(&ctx, "hf mfu keygen", + "Set the 3DES key on MIFARE Ultralight-C tag. ", + "hf mfu keygen -r\n" + "hf mfu keygen --uid 11223344556677" + ); - uint8_t uid[4]; - char cmdp = tolower(param_getchar(Cmd, 0)); - if (strlen(Cmd) == 0 || cmdp == 'h') return usage_hf_mfu_gendiverse(); + void *argtable[] = { + arg_param_begin, + arg_str0("u", "uid", "", "4|7 hex byte UID"), + arg_lit0("r", NULL, "read UID from tag"), + arg_param_end + }; + CLIExecWithReturn(ctx, Cmd, argtable, true); + + int ulen = 0; + uint8_t uid[7]; + CLIGetHexWithReturn(ctx, 1, uid, &ulen); + bool read_tag = arg_get_lit(ctx, 2); + CLIParserFree(ctx); - if (cmdp == 'r') { + if (read_tag) { // read uid from tag clearCommandBuffer(); SendCommandMIX(CMD_HF_ISO14443A_READER, ISO14A_CONNECT | ISO14A_NO_RATS, 0, 0, NULL, 0); @@ -2656,17 +2660,14 @@ static int CmdHF14AMfUGenDiverseKeys(const char *Cmd) { PrintAndLogEx(WARNING, "iso14443a card select failed"); return PM3_ESOFT; } - /* - if (card.uidlen != 4) { - PrintAndLogEx(WARNING, "Wrong sized UID, expected 4bytes got %d", card.uidlen); - return PM3_ESOFT; - } - */ - memcpy(uid, card.uid, card.uidlen); - } else { - if (param_gethex(Cmd, 0, uid, 8)) return usage_hf_mfu_gendiverse(); - } + if (card.uidlen != 4 && card.uidlen != 7) { + PrintAndLogEx(WARNING, "Wrong sized UID, expected 4|7 bytes got %d", card.uidlen); + return PM3_ESOFT; + } + ulen = card.uidlen; + memcpy(uid, card.uid, card.uidlen); + } uint8_t iv[8] = { 0x00 }; uint8_t block = 0x01; @@ -2687,10 +2688,10 @@ static int CmdHF14AMfUGenDiverseKeys(const char *Cmd) { mix[6] = block ^ uid[2]; mix[7] = uid[3]; - mbedtls_des3_context ctx; - mbedtls_des3_set2key_enc(&ctx, masterkey); + mbedtls_des3_context ctx_des3; + mbedtls_des3_set2key_enc(&ctx_des3, masterkey); - mbedtls_des3_crypt_cbc(&ctx // des3_context + mbedtls_des3_crypt_cbc(&ctx_des3 // des3_context , MBEDTLS_DES_ENCRYPT // int mode , sizeof(mix) // length , iv // iv[8] @@ -2699,12 +2700,12 @@ static int CmdHF14AMfUGenDiverseKeys(const char *Cmd) { ); PrintAndLogEx(SUCCESS, "-- 3DES version"); - PrintAndLogEx(SUCCESS, "Masterkey :\t %s", sprint_hex(masterkey, sizeof(masterkey))); - PrintAndLogEx(SUCCESS, "UID :\t %s", sprint_hex(uid, sizeof(uid))); - PrintAndLogEx(SUCCESS, "block :\t %0d", block); - PrintAndLogEx(SUCCESS, "Mifare key :\t %s", sprint_hex(mifarekeyA, sizeof(mifarekeyA))); - PrintAndLogEx(SUCCESS, "Message :\t %s", sprint_hex(mix, sizeof(mix))); - PrintAndLogEx(SUCCESS, "Diversified key: %s", sprint_hex(divkey + 1, 6)); + PrintAndLogEx(SUCCESS, "Masterkey......... %s", sprint_hex(masterkey, sizeof(masterkey))); + PrintAndLogEx(SUCCESS, "UID............... %s", sprint_hex(uid, ulen)); + PrintAndLogEx(SUCCESS, "block............. %0d", block); + PrintAndLogEx(SUCCESS, "Mifare key........ %s", sprint_hex(mifarekeyA, sizeof(mifarekeyA))); + PrintAndLogEx(SUCCESS, "Message........... %s", sprint_hex(mix, sizeof(mix))); + PrintAndLogEx(SUCCESS, "Diversified key... %s", sprint_hex(divkey + 1, 6)); for (int i = 0; i < ARRAYLEN(mifarekeyA); ++i) { dkeyA[i] = (mifarekeyA[i] << 1) & 0xff; @@ -2724,9 +2725,9 @@ static int CmdHF14AMfUGenDiverseKeys(const char *Cmd) { memcpy(dmkey + 16, dkeyA, 8); memset(iv, 0x00, 8); - mbedtls_des3_set3key_enc(&ctx, dmkey); + mbedtls_des3_set3key_enc(&ctx_des3, dmkey); - mbedtls_des3_crypt_cbc(&ctx // des3_context + mbedtls_des3_crypt_cbc(&ctx_des3 // des3_context , MBEDTLS_DES_ENCRYPT // int mode , sizeof(newpwd) // length , iv // iv[8] @@ -2735,12 +2736,12 @@ static int CmdHF14AMfUGenDiverseKeys(const char *Cmd) { ); PrintAndLogEx(SUCCESS, "\n-- DES version"); - PrintAndLogEx(SUCCESS, "Mifare dkeyA :\t %s", sprint_hex(dkeyA, sizeof(dkeyA))); - PrintAndLogEx(SUCCESS, "Mifare dkeyB :\t %s", sprint_hex(dkeyB, sizeof(dkeyB))); - PrintAndLogEx(SUCCESS, "Mifare ABA :\t %s", sprint_hex(dmkey, sizeof(dmkey))); - PrintAndLogEx(SUCCESS, "Mifare Pwd :\t %s", sprint_hex(newpwd, sizeof(newpwd))); + PrintAndLogEx(SUCCESS, "MIFARE dkeyA...... %s", sprint_hex(dkeyA, sizeof(dkeyA))); + PrintAndLogEx(SUCCESS, "MIFARE dkeyB...... %s", sprint_hex(dkeyB, sizeof(dkeyB))); + PrintAndLogEx(SUCCESS, "MIFARE ABA........ %s", sprint_hex(dmkey, sizeof(dmkey))); + PrintAndLogEx(SUCCESS, "MIFARE PWD........ %s", sprint_hex(newpwd, sizeof(newpwd))); - mbedtls_des3_free(&ctx); + mbedtls_des3_free(&ctx_des3); mbedtls_aes_context ctx_aes; uint8_t aes_iv[16] = { 0x00 }; @@ -2752,8 +2753,8 @@ static int CmdHF14AMfUGenDiverseKeys(const char *Cmd) { mbedtls_aes_free(&ctx_aes); PrintAndLogEx(SUCCESS, "\n-- AES version"); - PrintAndLogEx(SUCCESS, "Mifare AES m :\t %s", sprint_hex(aes_masterkey, sizeof(aes_masterkey))); - PrintAndLogEx(SUCCESS, "Mifare Div :\t %s", sprint_hex(aes_output, sizeof(aes_output))); + PrintAndLogEx(SUCCESS, "MIFARE AES mk..... %s", sprint_hex(aes_masterkey, sizeof(aes_masterkey))); + PrintAndLogEx(SUCCESS, "MIFARE Div........ %s", sprint_hex(aes_output, sizeof(aes_output))); // next. from the diversify_key method. return PM3_SUCCESS; From baa7ca086b7b302b402ef6a82a19ee9c749d3e2b Mon Sep 17 00:00:00 2001 From: iceman1001 Date: Fri, 1 Jan 2021 21:02:22 +0100 Subject: [PATCH 272/682] hf mfu eview - view emulator memory. Defaults to download and show 0xFF blocks * 4 bytes since we dont know the MFU tag type --- client/src/cmdhfmfu.c | 70 ++++++++++++++++++++++++++++++++++++------- 1 file changed, 59 insertions(+), 11 deletions(-) diff --git a/client/src/cmdhfmfu.c b/client/src/cmdhfmfu.c index 5f0548968..d37321b1f 100644 --- a/client/src/cmdhfmfu.c +++ b/client/src/cmdhfmfu.c @@ -3550,26 +3550,74 @@ static int CmdHF14MfuNDEF(const char *Cmd) { free(records); return status; } + +static int CmdHF14AMfuEView(const char *Cmd) { + CLIParserContext *ctx; + CLIParserInit(&ctx, "hf mfu eview", + "It displays emulator memory", + "hf mfu eview" + ); + + void *argtable[] = { + arg_param_begin, + arg_param_end + }; + CLIExecWithReturn(ctx, Cmd, argtable, true); + CLIParserFree(ctx); + + uint16_t blocks = 0xFF; + uint16_t bytes = blocks * 4; + + uint8_t *dump = calloc(bytes, sizeof(uint8_t)); + if (dump == NULL) { + PrintAndLogEx(WARNING, "Fail, cannot allocate memory"); + return PM3_EMALLOC; + } + + PrintAndLogEx(INFO, "downloading from emulator memory"); + if (!GetFromDevice(BIG_BUF_EML, dump, bytes, 0, NULL, 0, NULL, 2500, false)) { + PrintAndLogEx(WARNING, "Fail, transfer from device time-out"); + free(dump); + return PM3_ETIMEOUT; + } + + PrintAndLogEx(NORMAL, ""); + PrintAndLogEx(INFO, "----+-------------+-------"); + PrintAndLogEx(INFO, "blk | data | ascii"); + PrintAndLogEx(INFO, "----+-------------+-------"); + for (uint16_t i = 0; i < blocks; i++) { + PrintAndLogEx(INFO, "%03d | %s ", i, sprint_hex_ascii(dump + (i * 4), 4)); + } + PrintAndLogEx(INFO, "----+-------------+-------"); + PrintAndLogEx(NORMAL, ""); + free(dump); + return PM3_SUCCESS; +} + //------------------------------------ // Menu Stuff //------------------------------------ static command_t CommandTable[] = { {"help", CmdHelp, AlwaysAvailable, "This help"}, - {"info", CmdHF14AMfUInfo, IfPm3Iso14443a, "Tag information"}, - {"dump", CmdHF14AMfUDump, IfPm3Iso14443a, "Dump Ultralight / Ultralight-C / NTAG tag to binary file"}, - {"restore", CmdHF14AMfURestore, IfPm3Iso14443a, "Restore a dump onto a MFU MAGIC tag"}, - {"eload", CmdHF14AMfUeLoad, IfPm3Iso14443a, "load Ultralight .eml dump file into emulator memory"}, - {"rdbl", CmdHF14AMfURdBl, IfPm3Iso14443a, "Read block"}, - {"wrbl", CmdHF14AMfUWrBl, IfPm3Iso14443a, "Write block"}, - {"cauth", CmdHF14AMfUCAuth, IfPm3Iso14443a, "Authentication - Ultralight C"}, - {"setpwd", CmdHF14AMfUCSetPwd, IfPm3Iso14443a, "Set 3des password - Ultralight-C"}, - {"setuid", CmdHF14AMfUCSetUid, IfPm3Iso14443a, "Set UID - MAGIC tags only"}, - {"sim", CmdHF14AMfUSim, IfPm3Iso14443a, "Simulate Ultralight from emulator memory"}, - {"gen", CmdHF14AMfUGenDiverseKeys, AlwaysAvailable, "Generate 3des mifare diversified keys"}, + {"-----------", CmdHelp, IfPm3Iso14443a, "----------------------- " _CYAN_("recovery") " -----------------------"}, + {"keygen", CmdHF14AMfUGenDiverseKeys, AlwaysAvailable, "Generate 3DES MIFARE diversified keys"}, {"pwdgen", CmdHF14AMfUPwdGen, AlwaysAvailable, "Generate pwd from known algos"}, {"otptear", CmdHF14AMfuOtpTearoff, IfPm3Iso14443a, "Tear-off test on OTP bits"}, // {"countertear", CmdHF14AMfuEv1CounterTearoff, IfPm3Iso14443a, "Tear-off test on Ev1 Counter bits"}, + {"-----------", CmdHelp, IfPm3Iso14443a, "----------------------- " _CYAN_("operations") " -----------------------"}, + {"cauth", CmdHF14AMfUCAuth, IfPm3Iso14443a, "Authentication - Ultralight-C"}, + {"dump", CmdHF14AMfUDump, IfPm3Iso14443a, "Dump MIFARE Ultralight family tag to binary file"}, + {"info", CmdHF14AMfUInfo, IfPm3Iso14443a, "Tag information"}, {"ndef", CmdHF14MfuNDEF, IfPm3Iso14443a, "Prints NDEF records from card"}, + {"rdbl", CmdHF14AMfURdBl, IfPm3Iso14443a, "Read block"}, + {"restore", CmdHF14AMfURestore, IfPm3Iso14443a, "Restore a dump onto a MFU MAGIC tag"}, + {"wrbl", CmdHF14AMfUWrBl, IfPm3Iso14443a, "Write block"}, + {"-----------", CmdHelp, IfPm3Iso14443a, "----------------------- " _CYAN_("simulation") " -----------------------"}, + {"eload", CmdHF14AMfUeLoad, IfPm3Iso14443a, "load Ultralight .eml dump file into emulator memory"}, + {"eview", CmdHF14AMfuEView, IfPm3Iso14443a, "View emulator memory"}, + {"sim", CmdHF14AMfUSim, IfPm3Iso14443a, "Simulate MIFARE Ultralight from emulator memory"}, + {"setpwd", CmdHF14AMfUCSetPwd, IfPm3Iso14443a, "Set 3DES key - Ultralight-C"}, + {"setuid", CmdHF14AMfUCSetUid, IfPm3Iso14443a, "Set UID - MAGIC tags only"}, {NULL, NULL, NULL, NULL} }; From db213522d68b41e575ab0f347badaa52e3a7adf8 Mon Sep 17 00:00:00 2001 From: Samy Kamkar Date: Fri, 1 Jan 2021 15:47:47 -0800 Subject: [PATCH 273/682] Reorder Lua libs/includes to compile on macOS Jansson libs/include dirs were taking preference over the included Lua files, causing system Lua files to interfere with expected includes --- client/Makefile | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/client/Makefile b/client/Makefile index 9cfc4fc4b..29cc37180 100644 --- a/client/Makefile +++ b/client/Makefile @@ -115,21 +115,6 @@ STATICLIBS += $(HARDNESTEDLIB) LDLIBS +=$(HARDNESTEDLIBLD) INCLUDES += $(HARDNESTEDLIBINC) -## Jansson -ifneq ($(SKIPJANSSONSYSTEM),1) - JANSSONINCLUDES = $(shell $(PKG_CONFIG_ENV) pkg-config --cflags jansson 2>/dev/null) - JANSSONLDLIBS = $(shell $(PKG_CONFIG_ENV) pkg-config --libs jansson 2>/dev/null) - ifneq ($(JANSSONLDLIBS),) - JANSSONLIB = - JANSSONLIBLD = $(JANSSONLDLIBS) - JANSSONLIBINC = $(JANSSONINCLUDES) - JANSSON_FOUND = 1 - endif -endif -STATICLIBS += $(JANSSONLIB) -LDLIBS += $(JANSSONLIBLD) -INCLUDES += $(JANSSONLIBINC) - ## Lua ifneq ($(SKIPLUASYSTEM),1) LUAINCLUDES = $(shell $(PKG_CONFIG_ENV) pkg-config --cflags lua5.2 2>/dev/null) @@ -145,6 +130,21 @@ STATICLIBS += $(LUALIB) LDLIBS += $(LUALIBLD) INCLUDES += $(LUALIBINC) +## Jansson +ifneq ($(SKIPJANSSONSYSTEM),1) + JANSSONINCLUDES = $(shell $(PKG_CONFIG_ENV) pkg-config --cflags jansson 2>/dev/null) + JANSSONLDLIBS = $(shell $(PKG_CONFIG_ENV) pkg-config --libs jansson 2>/dev/null) + ifneq ($(JANSSONLDLIBS),) + JANSSONLIB = + JANSSONLIBLD = $(JANSSONLDLIBS) + JANSSONLIBINC = $(JANSSONINCLUDES) + JANSSON_FOUND = 1 + endif +endif +STATICLIBS += $(JANSSONLIB) +LDLIBS += $(JANSSONLIBLD) +INCLUDES += $(JANSSONLIBINC) + ## mbed TLS # system library cannot be used because it is compiled by default without CMAC support STATICLIBS += $(MBEDTLSLIB) From 72896b902e37b484139d57a149efcb2befd5a1c5 Mon Sep 17 00:00:00 2001 From: Philippe Teuwen Date: Sat, 2 Jan 2021 13:10:42 +0100 Subject: [PATCH 274/682] comment --- client/Makefile | 1 + 1 file changed, 1 insertion(+) diff --git a/client/Makefile b/client/Makefile index 29cc37180..05a0979ae 100644 --- a/client/Makefile +++ b/client/Makefile @@ -131,6 +131,7 @@ LDLIBS += $(LUALIBLD) INCLUDES += $(LUALIBINC) ## Jansson +# Jansson section needs to be after Lua to avoid interferences on macOS if a locally incompatible Lua was available, see PR 1155 ifneq ($(SKIPJANSSONSYSTEM),1) JANSSONINCLUDES = $(shell $(PKG_CONFIG_ENV) pkg-config --cflags jansson 2>/dev/null) JANSSONLDLIBS = $(shell $(PKG_CONFIG_ENV) pkg-config --libs jansson 2>/dev/null) From 4e1a9694a21810cd2b218be96784a94d589e5e3d Mon Sep 17 00:00:00 2001 From: Gator96100 Date: Sun, 3 Jan 2021 02:49:40 +0100 Subject: [PATCH 275/682] Updated precompiled links Also x86 is no longer supported --- README.md | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 56af79cda..578dccf7f 100644 --- a/README.md +++ b/README.md @@ -82,16 +82,13 @@ If you are having troubles with these files, contact the package maintainer @gat Ref: For Proxmark3 RDV4 -- [Precompiled builds for RDV40 dedicated x86](https://drive.google.com/open?id=13zUs-aiQkYaSl5KWrBtuW5IWCoHJPsue) -- [Precompiled builds for RDV40 dedicated x64](https://drive.google.com/open?id=1SyPB8t5Vo8O0Lh7PjNm3Kv-mO4BNbxjX) +- [Precompiled builds for RDV40 dedicated x64](https://www.proxmarkbuilds.org/#rdv40-64/) For Proxmark3 RDV4 with blueshark addon -- [Precompiled builds for RDV40 dedicated with Bluetooth addon x86](https://drive.google.com/open?id=1TqWYctkRvkLshQ1ZRBHPLDzYHR-asuMO) -- [Precompiled builds for RDV40 dedicated with Bluetooth addon x64](https://drive.google.com/open?id=17ful7u2QyYmMQzQzc5fAf8nJvyoDJfSL) +- [Precompiled builds for RDV40 dedicated with Bluetooth addon x64](https://www.proxmarkbuilds.org/#rdv40_bt-64/) Generice Proxmark3 devices (non RDV4), for Proxmark3 Easy, RDV1, RDV2, RDV3, etc etc -- [Precompiled builds for RRG / Iceman repository x86](https://drive.google.com/open?id=1PI3Xr1mussPBPnYGu4ZjWzGPARK4N7JR) -- [Precompiled builds for RRG / Iceman repository x64](https://drive.google.com/open?id=1uX9RtYGinuFrpHybu4xq_BE3HrobI20e) +- [Precompiled builds for RRG / Iceman repository x64](https://www.proxmarkbuilds.org/#rrg_other-64/) ## Roadmap From eea63a6cb772be7a783f50c11e34d59f57c5481f Mon Sep 17 00:00:00 2001 From: tharexde Date: Sun, 3 Jan 2021 22:50:27 +0100 Subject: [PATCH 276/682] first draft half duplex simulation --- armsrc/appmain.c | 2 +- armsrc/em4x50.c | 523 +++++++++++++++++++++++++++++++++++---- armsrc/em4x50.h | 2 +- client/src/cmdlfem4x50.c | 29 ++- client/src/cmdlfem4x70.h | 2 +- include/em4x50.h | 3 + 6 files changed, 511 insertions(+), 50 deletions(-) diff --git a/armsrc/appmain.c b/armsrc/appmain.c index 87b17afd9..6fba90e0e 100644 --- a/armsrc/appmain.c +++ b/armsrc/appmain.c @@ -1136,7 +1136,7 @@ static void PacketReceived(PacketCommandNG *packet) { // destroy the Emulator Memory. //----------------------------------------------------------------------------- FpgaDownloadAndGo(FPGA_BITSTREAM_LF); - em4x50_sim((uint8_t *)packet->data.asBytes); + em4x50_sim(); break; } case CMD_LF_EM4X50_READER: { diff --git a/armsrc/em4x50.c b/armsrc/em4x50.c index b03872bea..6c6091a8b 100644 --- a/armsrc/em4x50.c +++ b/armsrc/em4x50.c @@ -11,6 +11,7 @@ #include "fpgaloader.h" #include "ticks.h" #include "dbprint.h" +#include "lfsampling.h" #include "lfadc.h" #include "lfdemod.h" #include "commonutil.h" @@ -34,14 +35,15 @@ #define EM4X50_T_TAG_FULL_PERIOD 64 #define EM4X50_T_TAG_TPP 64 #define EM4X50_T_TAG_TWA 64 +#define EM4X50_T_TAG_TINIT 2112 +#define EM4X50_T_TAG_TWEE 3200 #define EM4X50_T_TAG_WAITING_FOR_SIGNAL 75 #define EM4X50_T_WAITING_FOR_DBLLIW 1550 -#define EM4X50_T_WAITING_FOR_SNGLLIW 140 // this value seems to be -// critical; -// if it's too low -// (e.g. < 120) some cards -// are no longer readable -// although they're ok +#define EM4X50_T_WAITING_FOR_ACK 4 + +// the following value seems to be critical; if it's too low (e.g. < 120) +// some cards are no longer readable although they're ok +#define EM4X50_T_WAITING_FOR_SNGLLIW 140 #define EM4X50_TAG_TOLERANCE 8 #define EM4X50_TAG_WORD 45 @@ -55,6 +57,14 @@ int gHigh = 190; int gLow = 60; +int gcount = 0; +int gcycles = 0; +int rm = 0; + +static bool em4x50_sim_send_listen_window(void); +static void em4x50_sim_handle_command(uint8_t command); + +void catch_samples(void); // do nothing for using timer0 static void wait_timer(uint32_t period) { @@ -62,7 +72,7 @@ static void wait_timer(uint32_t period) { while (AT91C_BASE_TC0->TC_CV < period); } -static void catch_samples(void) { +void catch_samples(void) { uint8_t sample = 0; @@ -160,19 +170,22 @@ static void em4x50_setup_read(void) { // Enable Peripheral Clock for // TIMER_CLOCK0, used to measure exact timing before answering - AT91C_BASE_PMC->PMC_PCER |= (1 << AT91C_ID_TC0);// | (1 << AT91C_ID_TC1); + AT91C_BASE_PMC->PMC_PCER |= (1 << AT91C_ID_TC0) | (1 << AT91C_ID_TC1); AT91C_BASE_PIOA->PIO_BSR = GPIO_SSC_FRAME; // Disable timer during configuration AT91C_BASE_TC0->TC_CCR = AT91C_TC_CLKDIS; + AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKDIS; // TC0: Capture mode, default timer source = MCK/2 (TIMER_CLOCK1), no triggers AT91C_BASE_TC0->TC_CMR = AT91C_TC_CLKS_TIMER_DIV1_CLOCK; + AT91C_BASE_TC1->TC_CMR = AT91C_TC_CLKS_TIMER_DIV1_CLOCK; // TC1: Capture mode, default timer source = MCK/2 (TIMER_CLOCK1), no triggers // Enable and reset counters AT91C_BASE_TC0->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG; + AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG; // synchronized startup procedure while (AT91C_BASE_TC0->TC_CV > 0) {}; // wait until TC1 returned to zero @@ -182,13 +195,27 @@ static void em4x50_setup_read(void) { } static void em4x50_setup_sim(void) { + StopTicks(); + FpgaDownloadAndGo(FPGA_BITSTREAM_LF); + + sample_config *sc = getSamplingConfig(); + sc->decimation = 1; + sc->averaging = 0; + sc->divisor = LF_DIVISOR_125; + + FpgaSendCommand(FPGA_CMD_SET_DIVISOR, sc->divisor); FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_EDGE_DETECT); - FpgaSendCommand(FPGA_CMD_SET_DIVISOR, LF_DIVISOR_125); AT91C_BASE_PIOA->PIO_PER = GPIO_SSC_DOUT | GPIO_SSC_CLK; AT91C_BASE_PIOA->PIO_OER = GPIO_SSC_DOUT; AT91C_BASE_PIOA->PIO_ODR = GPIO_SSC_CLK; + + AT91C_BASE_PMC->PMC_PCER |= (1 << AT91C_ID_TC0); + AT91C_BASE_PIOA->PIO_BSR = GPIO_SSC_FRAME; + AT91C_BASE_TC0->TC_CCR = AT91C_TC_CLKDIS; + AT91C_BASE_TC0->TC_CMR = AT91C_TC_CLKS_TIMER_DIV1_CLOCK; + AT91C_BASE_TC0->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG; } // calculate signal properties (mean amplitudes) from measured data: @@ -323,12 +350,12 @@ static void em4x50_reader_send_bit(int bit) { if (bit == 0) { - // disable modulation (drops the field) for 7 cycles of carrier + // disable modulation (activate the field) for 7 cycles of carrier // period (Opt64) LOW(GPIO_SSC_DOUT); while (AT91C_BASE_TC0->TC_CV < T0 * 7); - // enable modulation (activates the field) for remaining first + // enable modulation (drop the field) for remaining first // half of bit period HIGH(GPIO_SSC_DOUT); while (AT91C_BASE_TC0->TC_CV < T0 * EM4X50_T_TAG_HALF_PERIOD); @@ -432,9 +459,7 @@ static int find_double_listen_window(bool bcommand) { // first listen window found if (bcommand) { - -// SpinDelay(10); - + // data transmission from card has to be stopped, because // a commamd shall be issued @@ -444,8 +469,6 @@ static int find_double_listen_window(bool bcommand) { // skip the next bit... wait_timer(T0 * EM4X50_T_TAG_FULL_PERIOD); - catch_samples(); - break; // ...and check if the following bit does make sense // (if not it is the correct position within the second @@ -499,14 +522,19 @@ static int request_receive_mode(void) { // If is true then within the single listen window right after the // ack signal a RM request has to be sent. static bool check_ack(bool bliw) { + int cnt_pulses = 0; + AT91C_BASE_TC0->TC_CCR = AT91C_TC_SWTRG; + //while (cnt_pulses < EM4X50_T_WAITING_FOR_ACK) { while (AT91C_BASE_TC0->TC_CV < T0 * 4 * EM4X50_T_TAG_FULL_PERIOD) { if (BUTTON_PRESS()) return false; - + if (check_pulse_length(get_pulse_length(), 2 * EM4X50_T_TAG_FULL_PERIOD)) { + catch_samples(); + // The received signal is either ACK or NAK. if (check_pulse_length(get_pulse_length(), 2 * EM4X50_T_TAG_FULL_PERIOD)) { @@ -542,6 +570,7 @@ static bool check_ack(bool bliw) { break; } } + cnt_pulses++; } return false; @@ -745,6 +774,154 @@ static bool em4x50_sim_send_word(uint32_t word) { return true; } +static int wait_cycles(int maxperiods) { + + int period = 0; + + while (period < maxperiods) { + + while (!(AT91C_BASE_PIOA->PIO_PDSR & GPIO_SSC_CLK)); + while (AT91C_BASE_PIOA->PIO_PDSR & GPIO_SSC_CLK); + + period++; + } + + return PM3_SUCCESS; +} + +static int get_cycles(void) { + + int cycles = 0; + + AT91C_BASE_TC0->TC_CCR = AT91C_TC_SWTRG; + while (AT91C_BASE_TC0->TC_CV < T0 * EM4X50_T_TAG_FULL_PERIOD) { + + while (!(AT91C_BASE_PIOA->PIO_PDSR & GPIO_SSC_CLK)); + + // check again to minimize desynchronization + if (AT91C_BASE_TC0->TC_CV >= T0 * EM4X50_T_TAG_FULL_PERIOD) + break; + + while (AT91C_BASE_PIOA->PIO_PDSR & GPIO_SSC_CLK); + + cycles++; + } + + return cycles; +} + +static uint8_t em4x50_sim_read_bit(void) { + + int cond = EM4X50_T_TAG_FULL_PERIOD - EM4X50_TAG_TOLERANCE; + + return (get_cycles() < cond) ? 0 : 1; +} + +static uint8_t em4x50_sim_read_byte(void) { + + uint8_t byte = 0; + + for (int i = 0; i < 8; i++) { + byte <<= 1; + byte |= em4x50_sim_read_bit(); + } + + return byte; +} + +static uint8_t em4x50_sim_read_byte_with_parity_check(void) { + + uint8_t byte = 0, parity = 0, pval = 0; + + for (int i = 0; i < 8; i++) { + byte <<= 1; + byte |= em4x50_sim_read_bit(); + parity ^= (byte & 1); + } + + pval = em4x50_sim_read_bit(); + + return (parity == pval) ? byte : 0; +} + +static uint32_t em4x50_sim_read_word(void) { + + uint8_t parities = 0, parities_calculated = 0, stop_bit = 0; + uint8_t bytes[4] = {0}; + + // read plain data + for (int i = 0; i < 4; i++) { + bytes[i] = em4x50_sim_read_byte_with_parity_check(); + } + + // read column parities and stop bit + parities = em4x50_sim_read_byte(); + stop_bit = em4x50_sim_read_bit(); + + // calculate column parities from data + for (int i = 0; i < 8; i++) { + parities_calculated <<= 1; + for (int j = 0; j < 4; j++) { + parities_calculated ^= (bytes[j] >> (7 - i)) & 1; + } + } + + // check parities + if ((parities == parities_calculated) && (stop_bit == 0)) { + return BYTES2UINT32(bytes); + } + + return 0; +} + +static void em4x50_sim_send_ack(void) { + + SHORT_COIL(); + wait_cycles(EM4X50_T_TAG_HALF_PERIOD); + + OPEN_COIL(); + wait_cycles(EM4X50_T_TAG_HALF_PERIOD); + + SHORT_COIL(); + wait_cycles(3 * EM4X50_T_TAG_HALF_PERIOD); + + OPEN_COIL(); + wait_cycles(EM4X50_T_TAG_HALF_PERIOD); + + SHORT_COIL(); + wait_cycles(3 * EM4X50_T_TAG_HALF_PERIOD); + + OPEN_COIL(); + wait_cycles(EM4X50_T_TAG_HALF_PERIOD); + + SHORT_COIL(); +} + +static void em4x50_sim_send_nak(void) { + + SHORT_COIL(); + wait_cycles(EM4X50_T_TAG_HALF_PERIOD); + + OPEN_COIL(); + wait_cycles(EM4X50_T_TAG_HALF_PERIOD); + + SHORT_COIL(); + wait_cycles(3 * EM4X50_T_TAG_HALF_PERIOD); + + OPEN_COIL(); + wait_cycles(EM4X50_T_TAG_HALF_PERIOD); + + SHORT_COIL(); + wait_cycles(EM4X50_T_TAG_FULL_PERIOD); + + OPEN_COIL(); + wait_cycles(EM4X50_T_TAG_HALF_PERIOD); + + SHORT_COIL(); + wait_cycles(EM4X50_T_TAG_HALF_PERIOD); +} + +/* static bool em4x50_sim_send_listen_window(void) { uint16_t check = 0; @@ -790,6 +967,257 @@ static bool em4x50_sim_send_listen_window(void) { return true; } +*/ + +static void em4x50_sim_handle_login_command(void) { + + //uint8_t *em4x50_mem = BigBuf_get_EM_addr(); + uint32_t password = 0; + //uint32_t tag[EM4X50_NO_WORDS] = {0x0}; + + // read password + password = em4x50_sim_read_word(); + + //for (int i = 0; i < EM4X50_NO_WORDS; i++) + // tag[i] = reflect32(bytes_to_num(em4x50_mem + (i * 4), 4)); + + // processing pause time (corresponds to a "1" bit) + em4x50_sim_send_bit(1); + + em4x50_sim_send_ack(); + + /* + if (password == tag[0]) { + em4x50_sim_send_ack(); + } else { + em4x50_sim_send_ack(); + } + */ + + // continue with standard read mode + em4x50_sim_handle_command(0); + Dbprintf("password = %08x", password); + BigBuf_free(); +} + +static void em4x50_sim_handle_reset_command(void) { + + // processing pause time (corresponds to a "1" bit) + em4x50_sim_send_bit(1); + + // send ACK + em4x50_sim_send_ack(); + + // wait for tinit + wait_timer(T0 * EM4X50_T_TAG_TINIT); + + // continue with standard read mode + em4x50_sim_handle_command(0); +} + +static void em4x50_sim_handle_write_command(void) { + + uint8_t *em4x50_mem = BigBuf_get_EM_addr(); + uint8_t address = 0; + uint32_t data = 0; + uint32_t tag[EM4X50_NO_WORDS] = {0x0}; + + // read address + address = em4x50_sim_read_byte_with_parity_check(); + // read data + data = em4x50_sim_read_word(); + + for (int i = 0; i < EM4X50_NO_WORDS; i++) { + tag[i] = reflect32(bytes_to_num(em4x50_mem + (i * 4), 4)); + } + + // extract necessary control data + bool raw = (tag[EM4X50_CONTROL] >> CONFIG_BLOCK) & READ_AFTER_WRITE; + // extract protection data + int fwrp = tag[EM4X50_PROTECTION] & 0xFF; // first word read protected + int lwrp = (tag[EM4X50_PROTECTION] >> 8) & 0xFF; // last word read protected + + // save data to tag + tag[address] = data; + + // write access time + wait_timer(T0 * EM4X50_T_TAG_TWA); + + if ((address >= fwrp) && (address <= lwrp)) { + em4x50_sim_send_nak(); + } else if ((address == EM4X50_DEVICE_SERIAL) + && (address == EM4X50_DEVICE_ID) + && (address == 0) + ) { + em4x50_sim_send_nak(); + } else { + em4x50_sim_send_ack(); + } + + // EEPROM write time + //wait_timer(T0 * EM4X50_T_TAG_TWEE); + + em4x50_sim_send_ack(); + + // if "read after write" (raw) bit is set, repeat written data once + if (raw) { + em4x50_sim_send_listen_window(); + em4x50_sim_send_listen_window(); + em4x50_sim_send_word(tag[address]); + } + + BigBuf_free(); + + // continue with standard read mode + em4x50_sim_handle_command(0); +} + +static void em4x50_sim_handle_selective_read_command(void) { + + uint8_t *em4x50_mem = BigBuf_get_EM_addr(); + uint32_t address = 0; + uint32_t tag[EM4X50_NO_WORDS] = {0x0}; + + // read password + address = em4x50_sim_read_word(); + + // extract control data + int fwr = address & 0xFF; // first word read + int lwr = (address >> 8) & 0xFF; // last word read + + for (int i = 0; i < EM4X50_NO_WORDS; i++) { + tag[i] = reflect32(bytes_to_num(em4x50_mem + (i * 4), 4)); + } + + // extract protection data + int fwrp = tag[EM4X50_PROTECTION] & 0xFF; // first word read protected + int lwrp = (tag[EM4X50_PROTECTION] >> 8) & 0xFF; // last word read protected + + // processing pause time (corresponds to a "1" bit) + em4x50_sim_send_bit(1); + + em4x50_sim_send_ack(); + + while (BUTTON_PRESS() == false) { + + WDT_HIT(); + em4x50_sim_send_listen_window(); + for (int i = fwr; i <= lwr; i++) { + + em4x50_sim_send_listen_window(); + + if ((i >= fwrp) && (i <= lwrp)) { + em4x50_sim_send_word(0x00); + } else { + em4x50_sim_send_word(tag[i]); + } + } + } + + BigBuf_free(); +} + +static void em4x50_sim_handle_standard_read_command(void) { + + uint8_t *em4x50_mem = BigBuf_get_EM_addr(); + uint32_t tag[EM4X50_NO_WORDS] = {0x0}; + + for (int i = 0; i < EM4X50_NO_WORDS; i++) { + tag[i] = reflect32(bytes_to_num(em4x50_mem + (i * 4), 4)); + } + + // extract control data + int fwr = tag[CONFIG_BLOCK] & 0xFF; // first word read + int lwr = (tag[CONFIG_BLOCK] >> 8) & 0xFF; // last word read + // extract protection data + int fwrp = tag[EM4X50_PROTECTION] & 0xFF; // first word read protected + int lwrp = (tag[EM4X50_PROTECTION] >> 8) & 0xFF; // last word read protected + + while (BUTTON_PRESS() == false) { + + WDT_HIT(); + em4x50_sim_send_listen_window(); + for (int i = fwr; i <= lwr; i++) { + + em4x50_sim_send_listen_window(); + + if ((i >= fwrp) && (i <= lwrp)) { + em4x50_sim_send_word(0x00); + } else { + em4x50_sim_send_word(tag[i]); + } + } + } + BigBuf_free(); +} + +static void em4x50_sim_handle_command(uint8_t command) { + + switch (command) { + + case EM4X50_COMMAND_LOGIN: + em4x50_sim_handle_login_command(); + break; + + case EM4X50_COMMAND_RESET: + em4x50_sim_handle_reset_command(); + break; + + case EM4X50_COMMAND_WRITE: + em4x50_sim_handle_write_command(); + break; + + case EM4X50_COMMAND_WRITE_PASSWORD: + Dbprintf("Command = write_password"); + break; + + case EM4X50_COMMAND_SELECTIVE_READ: + em4x50_sim_handle_selective_read_command(); + break; + + default: + em4x50_sim_handle_standard_read_command(); + break; + } +} + +// reader requests receive mode (rm) by sending two zeros +static void check_rm_request(void) { + + int cond = EM4X50_T_TAG_FULL_PERIOD - EM4X50_TAG_TOLERANCE; + + // look for first zero + if (get_cycles() < cond) { + + // look for second zero + if (get_cycles() < cond) { + + // read mode request detected, get command from reader + uint8_t command = em4x50_sim_read_byte_with_parity_check(); + em4x50_sim_handle_command(command); + } + } +} + +static bool em4x50_sim_send_listen_window(void) { + + SHORT_COIL(); + wait_cycles(EM4X50_T_TAG_HALF_PERIOD); + + OPEN_COIL(); + wait_cycles(EM4X50_T_TAG_HALF_PERIOD); + + SHORT_COIL(); + wait_cycles(2 * EM4X50_T_TAG_FULL_PERIOD); + + OPEN_COIL(); + check_rm_request(); + + SHORT_COIL(); + wait_cycles(EM4X50_T_TAG_FULL_PERIOD); + + return true; +} // simple login to EM4x50, // used in operations that require authentication @@ -805,8 +1233,9 @@ static bool login(uint32_t password) { wait_timer(T0 * EM4X50_T_TAG_TPP); // check if ACK is returned - if (check_ack(false)) + if (check_ack(false)) { return PM3_SUCCESS; + } } else { if (DBGLEVEL >= DBG_DEBUG) @@ -1051,6 +1480,7 @@ void em4x50_info(em4x50_data_t *etd) { uint32_t addresses = 0x00002100; // read from fwr = 0 to lwr = 33 (0x21) uint32_t words[EM4X50_NO_WORDS] = {0x0}; + gcount = 0; em4x50_setup_read(); if (get_signalproperties() && find_em4x50_tag()) { @@ -1064,7 +1494,7 @@ void em4x50_info(em4x50_data_t *etd) { } lf_finalize(); - + reply_ng(CMD_LF_EM4X50_INFO, status, (uint8_t *)words, EM4X50_TAG_MAX_NO_BYTES); } @@ -1081,6 +1511,7 @@ void em4x50_reader(void) { LOW(GPIO_SSC_DOUT); lf_finalize(); + reply_ng(CMD_LF_EM4X50_READER, now, (uint8_t *)words, 4 * now); } @@ -1244,35 +1675,22 @@ void em4x50_writepwd(em4x50_data_t *etd) { // simulate uploaded data in emulator memory // (currently simulation allows only a one-way communication) -void em4x50_sim(uint8_t *filename) { +void em4x50_sim() { int status = PM3_SUCCESS; uint8_t *em4x50_mem = BigBuf_get_EM_addr(); uint32_t words[EM4X50_NO_WORDS] = {0x0}; -#ifdef WITH_FLASH - - if (strlen((char *)filename) != 0) { - - BigBuf_free(); - - int changed = rdv40_spiffs_lazy_mount(); - uint32_t size = size_in_spiffs((char *)filename); - em4x50_mem = BigBuf_malloc(size); - - rdv40_spiffs_read_as_filetype((char *)filename, em4x50_mem, size, RDV40_SPIFFS_SAFETY_SAFE); - - if (changed) - rdv40_spiffs_lazy_unmount(); - } - -#endif - for (int i = 0; i < EM4X50_NO_WORDS; i++) words[i] = reflect32(bytes_to_num(em4x50_mem + (i * 4), 4)); // only if valid em4x50 data (e.g. uid == serial) if (words[EM4X50_DEVICE_SERIAL] != words[EM4X50_DEVICE_ID]) { + em4x50_setup_sim(); + + em4x50_sim_handle_command(0); + + /* // extract control data int fwr = words[CONFIG_BLOCK] & 0xFF; // first word read int lwr = (words[CONFIG_BLOCK] >> 8) & 0xFF; // last word read @@ -1280,11 +1698,10 @@ void em4x50_sim(uint8_t *filename) { int fwrp = words[EM4X50_PROTECTION] & 0xFF; // first word read protected int lwrp = (words[EM4X50_PROTECTION] >> 8) & 0xFF; // last word read protected - em4x50_setup_sim(); - // iceman, will need a usb cmd check to break as well while (BUTTON_PRESS() == false) { + rm = 0; WDT_HIT(); em4x50_sim_send_listen_window(); for (int i = fwr; i <= lwr; i++) { @@ -1297,12 +1714,14 @@ void em4x50_sim(uint8_t *filename) { em4x50_sim_send_word(words[i]); } } + */ } else { status = PM3_ENODATA; } BigBuf_free(); lf_finalize(); + reply_ng(CMD_LF_EM4X50_SIM, status, NULL, 0); } @@ -1350,11 +1769,6 @@ void em4x50_test(em4x50_test_t *ett) { uint32_t tvallow[ett->cycles]; em4x50_setup_sim(); - AT91C_BASE_PMC->PMC_PCER |= (1 << AT91C_ID_TC0); - AT91C_BASE_PIOA->PIO_BSR = GPIO_SSC_FRAME; - AT91C_BASE_TC0->TC_CCR = AT91C_TC_CLKDIS; - AT91C_BASE_TC0->TC_CMR = AT91C_TC_CLKS_TIMER_DIV1_CLOCK; - AT91C_BASE_TC0->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG; while (AT91C_BASE_TC0->TC_CV > 0); for (int t = 0; t < ett->cycles; t++) { @@ -1378,5 +1792,24 @@ void em4x50_test(em4x50_test_t *ett) { } + em4x50_setup_sim(); + for (;;) { + em4x50_sim_send_listen_window(); + em4x50_sim_send_listen_window(); + em4x50_sim_send_bit(0); + em4x50_sim_send_bit(0); + em4x50_sim_send_bit(0); + em4x50_sim_send_ack(); + em4x50_sim_send_ack(); + em4x50_sim_send_bit(0); + em4x50_sim_send_bit(0); + em4x50_sim_send_bit(0); + em4x50_sim_send_nak(); + em4x50_sim_send_nak(); + em4x50_sim_send_bit(0); + em4x50_sim_send_bit(0); + em4x50_sim_send_bit(0); + } + reply_ng(CMD_LF_EM4X50_TEST, status, NULL, 0); } diff --git a/armsrc/em4x50.h b/armsrc/em4x50.h index 87451e198..a753b0808 100644 --- a/armsrc/em4x50.h +++ b/armsrc/em4x50.h @@ -19,7 +19,7 @@ void em4x50_writepwd(em4x50_data_t *etd); void em4x50_read(em4x50_data_t *etd); void em4x50_brute(em4x50_data_t *etd); void em4x50_login(uint32_t *password); -void em4x50_sim(uint8_t *filename); +void em4x50_sim(void); void em4x50_reader(void); void em4x50_chk(uint8_t *filename); void em4x50_test(em4x50_test_t *ett); diff --git a/client/src/cmdlfem4x50.c b/client/src/cmdlfem4x50.c index a3da00bcc..402c826e4 100644 --- a/client/src/cmdlfem4x50.c +++ b/client/src/cmdlfem4x50.c @@ -78,6 +78,31 @@ static void get_samples(void) { write_gnuplot_config_file(gHigh, gLow); } +/* +static void get_time_samples(void) { + + const char *fn = "../data/data.dat"; + FILE *fp = NULL; + + // download from BigBuf memory + uint32_t data[EM4X50_MAX_TIME_SAMPLES] = {0x0}; + if (GetFromDevice(BIG_BUF, (uint8_t *)data, EM4X50_MAX_TIME_SAMPLES, 0, NULL, 0, NULL, 2500, false) == false) { + PrintAndLogEx(WARNING, "Fail, transfer from device time-out"); + } + + if ((fp = fopen(fn, "w+")) == false) { + PrintAndLogEx(WARNING, "Fail, open file %s", fn); + } + + for (int i = 0; i < EM4X50_MAX_TIME_SAMPLES; i++) { + PrintAndLogEx(INFO, "%i %"PRIu32"", i, data[i]); + fprintf(fp, "%i %"PRIu32"\n", i, data[i]); + } + + fclose(fp); +} +*/ + static void prepare_result(const uint8_t *data, int fwr, int lwr, em4x50_word_t *words) { // restructure received result in "em4x50_word_t" structure @@ -398,6 +423,8 @@ int CmdEM4x50Login(const char *Cmd) { else PrintAndLogEx(FAILED, "Login " _RED_("failed")); + get_samples(); + return resp.status; } @@ -667,8 +694,6 @@ int CmdEM4x50Read(const char *Cmd) { } } - get_samples(); - return em4x50_read(&etd, NULL); } diff --git a/client/src/cmdlfem4x70.h b/client/src/cmdlfem4x70.h index f0f221b06..c72450e88 100644 --- a/client/src/cmdlfem4x70.h +++ b/client/src/cmdlfem4x70.h @@ -12,7 +12,7 @@ #define CMDLFEM4X70_H__ #include "common.h" -#include "em4x50.h" +#include "em4x70.h" #define TIMEOUT 2000 diff --git a/include/em4x50.h b/include/em4x50.h index 3308a371f..06ca3f10a 100644 --- a/include/em4x50.h +++ b/include/em4x50.h @@ -37,6 +37,9 @@ #define TIMEOUT 2000 #define DUMP_FILESIZE 136 #define EM4X50_MAX_NO_SAMPLES 1000 +#define EM4X50_MAX_TIME_SAMPLES 1000 + +#define BYTES2UINT32(x) ((x[0] << 24) | (x[1] << 16) | (x[2] << 8) | (x[3])) typedef struct { bool addr_given; From 9ce99862e89d38af219583a044ed65bad7652a60 Mon Sep 17 00:00:00 2001 From: Philippe Teuwen Date: Mon, 4 Jan 2021 00:36:34 +0100 Subject: [PATCH 277/682] make style --- client/src/cmdhfmfu.c | 36 ++++++++++++++++++------------------ doc/commands.md | 23 ++++++++++++----------- 2 files changed, 30 insertions(+), 29 deletions(-) diff --git a/client/src/cmdhfmfu.c b/client/src/cmdhfmfu.c index d37321b1f..b29c7ab26 100644 --- a/client/src/cmdhfmfu.c +++ b/client/src/cmdhfmfu.c @@ -2072,7 +2072,7 @@ static int CmdHF14AMfURestore(const char *Cmd) { "hf mfu restore -f myfile -s -> user specified filename and special write\n" "hf mfu restore -f myfile -k AABBCCDD -s -> user specified filename, special write and use key\n" "hf mfu restore -f myfile -k AABBCCDD -ser -> user specified filename, special write, use key, ..." - ); + ); void *argtable[] = { arg_param_begin, @@ -2114,7 +2114,7 @@ static int CmdHF14AMfURestore(const char *Cmd) { strcpy(filename, fptr); } else { snprintf(filename, sizeof(filename), "dumpdata.bin"); - } + } free(fptr); } @@ -2272,7 +2272,7 @@ static int CmdHF14AMfUeLoad(const char *Cmd) { "It loads emul dump from the file `filename.eml`", "hf mfu eload -u -f myfile\n" "hf mfu eload -u -f myfile -q 57 -> load 57 blocks from myfile" - ); + ); void *argtable[] = { arg_param_begin, @@ -2298,7 +2298,7 @@ static int CmdHF14AMfUSim(const char *Cmd) { "from emulator memory. See `hf mfu eload` first", "hf mfu sim -t 2 --uid 1122344556677 -> MIFARE Ultralight\n" "hf mfu sim -t 7 --uid 1122344556677 -n 5 -> AMIIBO (NTAG 215), pack 0x8080" - ); + ); void *argtable[] = { arg_param_begin, @@ -2326,7 +2326,7 @@ static int CmdHF14AMfUCAuth(const char *Cmd) { "If password is not specified, a set of known defaults will be tested.", "hf mfu cauth\n" "hf mfu cauth --key 000102030405060708090a0b0c0d0e0f" - ); + ); void *argtable[] = { arg_param_begin, @@ -2336,7 +2336,7 @@ static int CmdHF14AMfUCAuth(const char *Cmd) { arg_param_end }; CLIExecWithReturn(ctx, Cmd, argtable, true); - + int ak_len = 0; uint8_t authenticationkey[16] = {0x00}; uint8_t *authKeyPtr = authenticationkey; @@ -2359,7 +2359,7 @@ static int CmdHF14AMfUCAuth(const char *Cmd) { // If no hex key is specified, try default keys if (ak_len == 0) { - isok = (try_default_3des_keys(&authKeyPtr) == PM3_SUCCESS); + isok = (try_default_3des_keys(&authKeyPtr) == PM3_SUCCESS); } else { // try user-supplied isok = ulc_authentication(authKeyPtr, !keep_field_on); @@ -2478,7 +2478,7 @@ static int CmdHF14AMfUCSetPwd(const char *Cmd) { CLIParserInit(&ctx, "hf mfu setpwd", "Set the 3DES key on MIFARE Ultralight-C tag. ", "hf mfu setpwd --key 000102030405060708090a0b0c0d0e0f" - ); + ); void *argtable[] = { arg_param_begin, @@ -2486,7 +2486,7 @@ static int CmdHF14AMfUCSetPwd(const char *Cmd) { arg_param_end }; CLIExecWithReturn(ctx, Cmd, argtable, true); - + int k_len = 0; uint8_t key[16] = {0x00}; CLIGetHexWithReturn(ctx, 1, key, &k_len); @@ -2519,13 +2519,13 @@ static int CmdHF14AMfUCSetPwd(const char *Cmd) { // Magic UL / UL-C tags - Set UID // static int CmdHF14AMfUCSetUid(const char *Cmd) { - + CLIParserContext *ctx; CLIParserInit(&ctx, "hf mfu setuid", "Set uid on MIFARE Ultralight tag.\n" "This only works for `magic Ultralight` tags.", "hf mfu setuid --uid 11223344556677" - ); + ); void *argtable[] = { arg_param_begin, @@ -2533,7 +2533,7 @@ static int CmdHF14AMfUCSetUid(const char *Cmd) { arg_param_end }; CLIExecWithReturn(ctx, Cmd, argtable, true); - + int u_len = 0; uint8_t uid[7] = {0x00}; CLIGetHexWithReturn(ctx, 1, uid, &u_len); @@ -2625,7 +2625,7 @@ static int CmdHF14AMfUGenDiverseKeys(const char *Cmd) { "Set the 3DES key on MIFARE Ultralight-C tag. ", "hf mfu keygen -r\n" "hf mfu keygen --uid 11223344556677" - ); + ); void *argtable[] = { arg_param_begin, @@ -2634,7 +2634,7 @@ static int CmdHF14AMfUGenDiverseKeys(const char *Cmd) { arg_param_end }; CLIExecWithReturn(ctx, Cmd, argtable, true); - + int ulen = 0; uint8_t uid[7]; CLIGetHexWithReturn(ctx, 1, uid, &ulen); @@ -3556,7 +3556,7 @@ static int CmdHF14AMfuEView(const char *Cmd) { CLIParserInit(&ctx, "hf mfu eview", "It displays emulator memory", "hf mfu eview" - ); + ); void *argtable[] = { arg_param_begin, @@ -3610,10 +3610,10 @@ static command_t CommandTable[] = { {"info", CmdHF14AMfUInfo, IfPm3Iso14443a, "Tag information"}, {"ndef", CmdHF14MfuNDEF, IfPm3Iso14443a, "Prints NDEF records from card"}, {"rdbl", CmdHF14AMfURdBl, IfPm3Iso14443a, "Read block"}, - {"restore", CmdHF14AMfURestore, IfPm3Iso14443a, "Restore a dump onto a MFU MAGIC tag"}, + {"restore", CmdHF14AMfURestore, IfPm3Iso14443a, "Restore a dump onto a MFU MAGIC tag"}, {"wrbl", CmdHF14AMfUWrBl, IfPm3Iso14443a, "Write block"}, - {"-----------", CmdHelp, IfPm3Iso14443a, "----------------------- " _CYAN_("simulation") " -----------------------"}, - {"eload", CmdHF14AMfUeLoad, IfPm3Iso14443a, "load Ultralight .eml dump file into emulator memory"}, + {"-----------", CmdHelp, IfPm3Iso14443a, "----------------------- " _CYAN_("simulation") " -----------------------"}, + {"eload", CmdHF14AMfUeLoad, IfPm3Iso14443a, "load Ultralight .eml dump file into emulator memory"}, {"eview", CmdHF14AMfuEView, IfPm3Iso14443a, "View emulator memory"}, {"sim", CmdHF14AMfUSim, IfPm3Iso14443a, "Simulate MIFARE Ultralight from emulator memory"}, {"setpwd", CmdHF14AMfUCSetPwd, IfPm3Iso14443a, "Set 3DES key - Ultralight-C"}, diff --git a/doc/commands.md b/doc/commands.md index f10e7a2bf..fa960f973 100644 --- a/doc/commands.md +++ b/doc/commands.md @@ -400,20 +400,21 @@ Check column "offline" for their availability. |command |offline |description |------- |------- |----------- |`hf mfu help `|Y |`This help` -|`hf mfu info `|N |`Tag information` -|`hf mfu dump `|N |`Dump Ultralight / Ultralight-C / NTAG tag to binary file` -|`hf mfu restore `|N |`Restore a dump onto a MFU MAGIC tag` -|`hf mfu eload `|N |`load Ultralight .eml dump file into emulator memory` -|`hf mfu rdbl `|N |`Read block` -|`hf mfu wrbl `|N |`Write block` -|`hf mfu cauth `|N |`Authentication - Ultralight C` -|`hf mfu setpwd `|N |`Set 3des password - Ultralight-C` -|`hf mfu setuid `|N |`Set UID - MAGIC tags only` -|`hf mfu sim `|N |`Simulate Ultralight from emulator memory` -|`hf mfu gen `|Y |`Generate 3des mifare diversified keys` +|`hf mfu keygen `|Y |`Generate 3DES MIFARE diversified keys` |`hf mfu pwdgen `|Y |`Generate pwd from known algos` |`hf mfu otptear `|N |`Tear-off test on OTP bits` +|`hf mfu cauth `|N |`Authentication - Ultralight-C` +|`hf mfu dump `|N |`Dump MIFARE Ultralight family tag to binary file` +|`hf mfu info `|N |`Tag information` |`hf mfu ndef `|N |`Prints NDEF records from card` +|`hf mfu rdbl `|N |`Read block` +|`hf mfu restore `|N |`Restore a dump onto a MFU MAGIC tag` +|`hf mfu wrbl `|N |`Write block` +|`hf mfu eload `|N |`load Ultralight .eml dump file into emulator memory` +|`hf mfu eview `|N |`View emulator memory` +|`hf mfu sim `|N |`Simulate MIFARE Ultralight from emulator memory` +|`hf mfu setpwd `|N |`Set 3DES key - Ultralight-C` +|`hf mfu setuid `|N |`Set UID - MAGIC tags only` ### hf mfdes From eaee80f3d7a2fafabe54c125e7f690f9185697e0 Mon Sep 17 00:00:00 2001 From: Philippe Teuwen Date: Mon, 4 Jan 2021 00:54:34 +0100 Subject: [PATCH 278/682] update changelog --- CHANGELOG.md | 7 ++++++- client/src/ui.c | 1 + 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0f890c8d5..b00aef560 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,7 +3,12 @@ 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 `ICE_STATE_DUMP_SIM` - standalone mode for dumping/simming one iClass tag (@iconicsec) + - Added support for debugging ARM with JTAG & VSCode (@Gator96100) + - Added MFUL "Gen1b" suport to `hf_mfu_setuid.lua` (@iceman1001) + - Added possibility to get bargraph in `lf tune` and `hf tune` (@iceman1001, @doegox) + - Added `hf emrtd` ePassport dumping and parsing (@aveao) + - Added `aidsearch` to `hf 14b info` (@iceman1001) + - Added `ICE_STATE_DUMP_SIM` - standalone mode for dumping/simming one iClass tag (@iconicsec) - Added `lf em 4x50 eview` - show uploaded EM4x50 data in emul memory (@tharexde) - Fix `data rawdemod` parsing for psk2 and user defined clock (@cyberpunk-re) - Added `hf iclass encode` - encode a wiegand binary to a encrypted credential (@iceman1001) diff --git a/client/src/ui.c b/client/src/ui.c index b7e63e7dd..327d266bf 100644 --- a/client/src/ui.c +++ b/client/src/ui.c @@ -22,6 +22,7 @@ #include #ifdef HAVE_READLINE +//Load readline after stdio.h #include #endif From ecd52347fa021f8167147c3c46b3951e6b4e8a41 Mon Sep 17 00:00:00 2001 From: tcprst Date: Sun, 3 Jan 2021 19:27:20 -0500 Subject: [PATCH 279/682] Add support for Apple Silicon (M1) --- CHANGELOG.md | 1 + Makefile.defs | 5 +++++ client/CMakeLists.txt | 16 +++++++++++++--- client/Makefile | 7 +++---- ...ac-OS-X-Homebrew-Installation-Instructions.md | 16 ++++++++++++++++ 5 files changed, 38 insertions(+), 7 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b00aef560..e5050bb6e 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] + - Fixed Makefile to account for changes when running on Apple Silicon (@tcprst) - Added support for debugging ARM with JTAG & VSCode (@Gator96100) - Added MFUL "Gen1b" suport to `hf_mfu_setuid.lua` (@iceman1001) - Added possibility to get bargraph in `lf tune` and `hf tune` (@iceman1001, @doegox) diff --git a/Makefile.defs b/Makefile.defs index b86b477aa..23dab5b32 100644 --- a/Makefile.defs +++ b/Makefile.defs @@ -57,6 +57,11 @@ else RANLIB= ranlib endif +# For detection of Apple Silicon +ifeq ($(platform),Darwin) + BREW_PREFIX = $(shell brew --prefix) +endif + ifeq ($(DEBUG),1) DEFCXXFLAGS = -g -O0 -pipe DEFCFLAGS = -g -O0 -fstrict-aliasing -pipe diff --git a/client/CMakeLists.txt b/client/CMakeLists.txt index ec1a28e60..ddfd288b2 100644 --- a/client/CMakeLists.txt +++ b/client/CMakeLists.txt @@ -32,7 +32,7 @@ find_package(PkgConfig) if (NOT SKIPQT EQUAL 1) if(APPLE AND EXISTS /usr/local/opt/qt5) # Homebrew installs Qt5 (up to at least 5.11.0) in - # /usr/local/qt5. Ensure that it can be found by CMake + # /usr/local/opt/qt5. Ensure that it can be found by CMake # since it is not in the default /usr/local prefix. # Add it to PATHS so that it doesn't override the # CMAKE_PREFIX_PATH environment variable. @@ -40,6 +40,16 @@ if (NOT SKIPQT EQUAL 1) # e.g. find_package(Qt5Core ${QT_FIND_PACKAGE_OPTIONS}) list(APPEND QT_FIND_PACKAGE_OPTIONS PATHS /usr/local/opt/qt5) endif(APPLE AND EXISTS /usr/local/opt/qt5) + if(APPLE AND EXISTS /opt/homebrew/opt/qt5) + # Homebrew on Apple Silicon installs Qt5 in + # /opt/homebrew/opt/qt5. Ensure that it can be found by CMake + # since it is not in the default /usr/local prefix. + # Add it to PATHS so that it doesn't override the + # CMAKE_PREFIX_PATH environment variable. + # QT_FIND_PACKAGE_OPTIONS should be passed to find_package, + # e.g. find_package(Qt5Core ${QT_FIND_PACKAGE_OPTIONS}) + list(APPEND QT_FIND_PACKAGE_OPTIONS PATHS /opt/homebrew/opt/qt5) + endif(APPLE AND EXISTS /opt/homebrew/opt/qt5) set(QT_PACKAGELIST Qt5Core Qt5Widgets @@ -77,8 +87,8 @@ endif (EMBED_READLINE OR EMBED_BZIP2) if (NOT SKIPREADLINE EQUAL 1) if (APPLE) - find_path(READLINE_INCLUDE_DIRS readline/readline.h /usr/local/opt/readline/include /opt/local/include /opt/include /usr/local/include /usr/include NO_DEFAULT_PATH) - find_library(READLINE_LIBRARIES readline /usr/local/opt/readline/lib /opt/local/lib /opt/lib /usr/local/lib /usr/lib NO_DEFAULT_PATH) + find_path(READLINE_INCLUDE_DIRS readline/readline.h /usr/local/opt/readline/include /opt/local/include /opt/include /usr/local/include /usr/include /opt/homebrew/opt/readline/include NO_DEFAULT_PATH) + find_library(READLINE_LIBRARIES readline /usr/local/opt/readline/lib /opt/local/lib /opt/lib /usr/local/lib /usr/lib /opt/homebrew/opt/readline/lib NO_DEFAULT_PATH) endif (APPLE) if (EMBED_READLINE) ExternalProject_Add(ncurses diff --git a/client/Makefile b/client/Makefile index 05a0979ae..a756a2ede 100644 --- a/client/Makefile +++ b/client/Makefile @@ -17,8 +17,7 @@ vpath %.dic dictionaries OBJDIR = obj ifeq ($(platform),Darwin) - # cf brew info qt: qt not symlinked anymore - PKG_CONFIG_ENV := PKG_CONFIG_PATH=/usr/local/opt/qt/lib/pkgconfig + PKG_CONFIG_ENV := PKG_CONFIG_PATH=$(BREW_PREFIX)/opt/qt/lib/pkgconfig endif ################### @@ -279,8 +278,8 @@ CXXINCLUDES += $(QTINCLUDES) ## Readline ifneq ($(SKIPREADLINE),1) ifeq ($(platform),Darwin) - LDLIBS += -L/usr/local/opt/readline/lib - INCLUDES += -I/usr/local/opt/readline/include + LDLIBS += -L$(BREW_PREFIX)/opt/readline/lib + INCLUDES += -I$(BREW_PREFIX)/opt/readline/include endif LDLIBS += -lreadline READLINE_FOUND = 1 diff --git a/doc/md/Installation_Instructions/Mac-OS-X-Homebrew-Installation-Instructions.md b/doc/md/Installation_Instructions/Mac-OS-X-Homebrew-Installation-Instructions.md index 6e21f852b..dbd2b2636 100644 --- a/doc/md/Installation_Instructions/Mac-OS-X-Homebrew-Installation-Instructions.md +++ b/doc/md/Installation_Instructions/Mac-OS-X-Homebrew-Installation-Instructions.md @@ -1,5 +1,21 @@ # Homebrew (Mac OS X), automatic installation +## Apple Silicon (M1) Notes + +Ensure Rosetta 2 is installed as it's currently needed to run `arm-none-eabi-gcc` as it's delivered as a precombiled x86_64 binary. + +If you see an error like: + +```sh +bad CPU type in executable +``` + +Then you are missing Rosetta 2 and need to install it: `/usr/sbin/softwareupdate --install-rosetta` + +Homebrew has changed their prefix to differentiate between native Apple Silicon and Intel compiled binaries. The Makefile attempts to account for this but please note that whichever terminal or application you're using must be running under Architecture "Apple" as seen by Activity Monitor as all child processes inherit the Rosetta 2 environment of their parent. You can check which architecture you're currently running under with a `uname -m` in your terminal. + +Visual Studio Code still runs under Rosetta 2 and if you're developing for proxmark3 on an Apple Silicon Mac you might want to consider running the Insiders build which has support for running natively on Apple Silicon. + ## Install Proxmark3 tools These instructions comes from @Chrisfu, where we got the proxmark3.rb scriptfile from. From 4daf4a8d538b9ee3dfe2fc8002d8472eb67433f3 Mon Sep 17 00:00:00 2001 From: Ave Date: Mon, 4 Jan 2021 00:32:59 +0000 Subject: [PATCH 280/682] Create ubuntu-build-and-test.yml --- .github/workflows/ubuntu-build-and-test.yml | 12 ++++++++++++ 1 file changed, 12 insertions(+) create mode 100644 .github/workflows/ubuntu-build-and-test.yml diff --git a/.github/workflows/ubuntu-build-and-test.yml b/.github/workflows/ubuntu-build-and-test.yml new file mode 100644 index 000000000..8967451c9 --- /dev/null +++ b/.github/workflows/ubuntu-build-and-test.yml @@ -0,0 +1,12 @@ +name: Ubuntu Build and Test + +on: [push, pull_request] + +jobs: + build: + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v2 + - name: make all + run: make all From e3119abd98373dee8b0900f4e280a0b00a371e84 Mon Sep 17 00:00:00 2001 From: Ave Date: Mon, 4 Jan 2021 00:38:58 +0000 Subject: [PATCH 281/682] Install deps on ubuntu builder Stolen from https://gitlab.com/mirrorbuilds/ci-configs/-/blob/master/iceman-pm3/.gitlab-ci.yml by @linuxgemini --- .github/workflows/ubuntu-build-and-test.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/ubuntu-build-and-test.yml b/.github/workflows/ubuntu-build-and-test.yml index 8967451c9..adecebcb8 100644 --- a/.github/workflows/ubuntu-build-and-test.yml +++ b/.github/workflows/ubuntu-build-and-test.yml @@ -8,5 +8,7 @@ jobs: steps: - uses: actions/checkout@v2 + - name: Install dependencies + run: apt-get install -yqq make autoconf build-essential ca-certificates pkg-config libreadline-dev gcc-arm-none-eabi libnewlib-dev qtbase5-dev libbz2-dev libbluetooth-dev libpython3-dev python3 python3-dev libpython3-all-dev liblua5.2-dev liblua5.2-0-dbg liblua5.2-0 lua5.2 sed - name: make all run: make all From cc9b80915117827f4f84a44f55424d8e1689aa4f Mon Sep 17 00:00:00 2001 From: Ave Date: Mon, 4 Jan 2021 00:44:41 +0000 Subject: [PATCH 282/682] sudo --- .github/workflows/ubuntu-build-and-test.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ubuntu-build-and-test.yml b/.github/workflows/ubuntu-build-and-test.yml index adecebcb8..86e8dd0a8 100644 --- a/.github/workflows/ubuntu-build-and-test.yml +++ b/.github/workflows/ubuntu-build-and-test.yml @@ -9,6 +9,6 @@ jobs: steps: - uses: actions/checkout@v2 - name: Install dependencies - run: apt-get install -yqq make autoconf build-essential ca-certificates pkg-config libreadline-dev gcc-arm-none-eabi libnewlib-dev qtbase5-dev libbz2-dev libbluetooth-dev libpython3-dev python3 python3-dev libpython3-all-dev liblua5.2-dev liblua5.2-0-dbg liblua5.2-0 lua5.2 sed + run: sudo apt-get install -yqq make autoconf build-essential ca-certificates pkg-config libreadline-dev gcc-arm-none-eabi libnewlib-dev qtbase5-dev libbz2-dev libbluetooth-dev libpython3-dev python3 python3-dev libpython3-all-dev liblua5.2-dev liblua5.2-0-dbg liblua5.2-0 lua5.2 sed - name: make all run: make all From 37791bbbf84232cab6dbfc9782f509a47546afb5 Mon Sep 17 00:00:00 2001 From: Ave Date: Mon, 4 Jan 2021 00:46:28 +0000 Subject: [PATCH 283/682] Update and upgrade before installing deps --- .github/workflows/ubuntu-build-and-test.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.github/workflows/ubuntu-build-and-test.yml b/.github/workflows/ubuntu-build-and-test.yml index 86e8dd0a8..3ec11b05a 100644 --- a/.github/workflows/ubuntu-build-and-test.yml +++ b/.github/workflows/ubuntu-build-and-test.yml @@ -8,6 +8,10 @@ jobs: steps: - uses: actions/checkout@v2 + - name: Update apt repos + run: sudo apt-get update + - name: Update packages + run: sudo apt-get upgrade -yqq - name: Install dependencies run: sudo apt-get install -yqq make autoconf build-essential ca-certificates pkg-config libreadline-dev gcc-arm-none-eabi libnewlib-dev qtbase5-dev libbz2-dev libbluetooth-dev libpython3-dev python3 python3-dev libpython3-all-dev liblua5.2-dev liblua5.2-0-dbg liblua5.2-0 lua5.2 sed - name: make all From 2d6119b5cd4c19ee6b239f38ac5ed5480435032a Mon Sep 17 00:00:00 2001 From: Ave Date: Mon, 4 Jan 2021 00:57:05 +0000 Subject: [PATCH 284/682] Add tests to ubuntu CI --- .github/workflows/ubuntu-build-and-test.yml | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ubuntu-build-and-test.yml b/.github/workflows/ubuntu-build-and-test.yml index 3ec11b05a..8bc11dbbf 100644 --- a/.github/workflows/ubuntu-build-and-test.yml +++ b/.github/workflows/ubuntu-build-and-test.yml @@ -14,5 +14,7 @@ jobs: run: sudo apt-get upgrade -yqq - name: Install dependencies run: sudo apt-get install -yqq make autoconf build-essential ca-certificates pkg-config libreadline-dev gcc-arm-none-eabi libnewlib-dev qtbase5-dev libbz2-dev libbluetooth-dev libpython3-dev python3 python3-dev libpython3-all-dev liblua5.2-dev liblua5.2-0-dbg liblua5.2-0 lua5.2 sed - - name: make all - run: make all + - name: Build + run: make clean && make V=1 + - name: Test + run: make check From fdb28dd95e287ab00b2381114ecc609f50b2b81d Mon Sep 17 00:00:00 2001 From: Ave Date: Mon, 4 Jan 2021 04:05:19 +0300 Subject: [PATCH 285/682] github actions: add macos action --- .github/workflows/macos-build-and-test.yml | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) create mode 100644 .github/workflows/macos-build-and-test.yml diff --git a/.github/workflows/macos-build-and-test.yml b/.github/workflows/macos-build-and-test.yml new file mode 100644 index 000000000..dff98dd2d --- /dev/null +++ b/.github/workflows/macos-build-and-test.yml @@ -0,0 +1,22 @@ +name: MacOS Build and Test + +on: [push, pull_request] + +jobs: + build: + runs-on: macos-latest + + steps: + - uses: actions/checkout@v2 + - name: Update brew repos + run: brew update + - name: Update packages + run: brew upgrade + - name: Tap RfidResearchGroup/proxmark3 + run: brew tap RfidResearchGroup/proxmark3 + - name: Install dependencies + run: readline qt5 RfidResearchGroup/proxmark3/arm-none-eabi-gcc + - name: Build + run: make clean && make V=1 + - name: Test + run: make check From 7db332a6de4bf2f4abe62b9dca7aebf187fe96c8 Mon Sep 17 00:00:00 2001 From: Ave Date: Mon, 4 Jan 2021 04:13:27 +0300 Subject: [PATCH 286/682] gh actions: Add ubuntu with make w/ btaddon and cmake --- .../{macos-build-and-test.yml => macos.yml} | 0 .github/workflows/ubuntu-cmake.yml | 20 +++++++++++++++++++ .github/workflows/ubuntu-make-btaddon.yml | 20 +++++++++++++++++++ ...ntu-build-and-test.yml => ubuntu-make.yml} | 4 ++-- 4 files changed, 42 insertions(+), 2 deletions(-) rename .github/workflows/{macos-build-and-test.yml => macos.yml} (100%) create mode 100644 .github/workflows/ubuntu-cmake.yml create mode 100644 .github/workflows/ubuntu-make-btaddon.yml rename .github/workflows/{ubuntu-build-and-test.yml => ubuntu-make.yml} (92%) diff --git a/.github/workflows/macos-build-and-test.yml b/.github/workflows/macos.yml similarity index 100% rename from .github/workflows/macos-build-and-test.yml rename to .github/workflows/macos.yml diff --git a/.github/workflows/ubuntu-cmake.yml b/.github/workflows/ubuntu-cmake.yml new file mode 100644 index 000000000..539ac252d --- /dev/null +++ b/.github/workflows/ubuntu-cmake.yml @@ -0,0 +1,20 @@ +name: Ubuntu (cmake) Build and Test + +on: [push, pull_request] + +jobs: + build-and-test: + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v2 + - name: Update apt repos + run: sudo apt-get update + - name: Update packages + run: sudo apt-get upgrade -yqq + - name: Install dependencies + run: sudo apt-get install -yqq make autoconf build-essential ca-certificates pkg-config libreadline-dev gcc-arm-none-eabi libnewlib-dev qtbase5-dev libbz2-dev libbluetooth-dev libpython3-dev python3 python3-dev libpython3-all-dev liblua5.2-dev liblua5.2-0-dbg liblua5.2-0 lua5.2 sed + - name: Build + run: mkdir -p client/build && ( cd client/build && cmake .. && make VERBOSE=1 ) + - name: Test + run: make client/check CHECKARGS="--clientbin ./client/build/proxmark3" diff --git a/.github/workflows/ubuntu-make-btaddon.yml b/.github/workflows/ubuntu-make-btaddon.yml new file mode 100644 index 000000000..e8de696a7 --- /dev/null +++ b/.github/workflows/ubuntu-make-btaddon.yml @@ -0,0 +1,20 @@ +name: Ubuntu (make with BTADDON) Build and Test + +on: [push, pull_request] + +jobs: + build-and-test: + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v2 + - name: Update apt repos + run: sudo apt-get update + - name: Update packages + run: sudo apt-get upgrade -yqq + - name: Install dependencies + run: sudo apt-get install -yqq make autoconf build-essential ca-certificates pkg-config libreadline-dev gcc-arm-none-eabi libnewlib-dev qtbase5-dev libbz2-dev libbluetooth-dev libpython3-dev python3 python3-dev libpython3-all-dev liblua5.2-dev liblua5.2-0-dbg liblua5.2-0 lua5.2 sed + - name: Build + run: make clean && make V=1 PLATFORM_EXTRAS=BTADDON + - name: Test + run: make check diff --git a/.github/workflows/ubuntu-build-and-test.yml b/.github/workflows/ubuntu-make.yml similarity index 92% rename from .github/workflows/ubuntu-build-and-test.yml rename to .github/workflows/ubuntu-make.yml index 8bc11dbbf..958c9c35d 100644 --- a/.github/workflows/ubuntu-build-and-test.yml +++ b/.github/workflows/ubuntu-make.yml @@ -1,9 +1,9 @@ -name: Ubuntu Build and Test +name: Ubuntu (make) Build and Test on: [push, pull_request] jobs: - build: + build-and-test: runs-on: ubuntu-latest steps: From 3dfc068a284e4f49a7aa528983e0f6ba3f097f89 Mon Sep 17 00:00:00 2001 From: Ave Date: Mon, 4 Jan 2021 04:15:54 +0300 Subject: [PATCH 287/682] github actions: macos bugfix --- .github/workflows/macos.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.github/workflows/macos.yml b/.github/workflows/macos.yml index dff98dd2d..ff72a0e3d 100644 --- a/.github/workflows/macos.yml +++ b/.github/workflows/macos.yml @@ -8,9 +8,11 @@ jobs: steps: - uses: actions/checkout@v2 + - name: Brew python bug workaround + run: brew link --overwrite python - name: Update brew repos run: brew update - - name: Update packages + - name: Upgrade packages run: brew upgrade - name: Tap RfidResearchGroup/proxmark3 run: brew tap RfidResearchGroup/proxmark3 From 96127e0da3447bd93a50288990857834aacf9327 Mon Sep 17 00:00:00 2001 From: Ave Date: Mon, 4 Jan 2021 04:17:58 +0300 Subject: [PATCH 288/682] github actions: don't upgrade packages --- .github/workflows/macos.yml | 4 +--- .github/workflows/ubuntu-cmake.yml | 2 -- .github/workflows/ubuntu-make-btaddon.yml | 2 -- .github/workflows/ubuntu-make.yml | 2 -- 4 files changed, 1 insertion(+), 9 deletions(-) diff --git a/.github/workflows/macos.yml b/.github/workflows/macos.yml index ff72a0e3d..3eb0b8584 100644 --- a/.github/workflows/macos.yml +++ b/.github/workflows/macos.yml @@ -12,12 +12,10 @@ jobs: run: brew link --overwrite python - name: Update brew repos run: brew update - - name: Upgrade packages - run: brew upgrade - name: Tap RfidResearchGroup/proxmark3 run: brew tap RfidResearchGroup/proxmark3 - name: Install dependencies - run: readline qt5 RfidResearchGroup/proxmark3/arm-none-eabi-gcc + run: brew install readline qt5 RfidResearchGroup/proxmark3/arm-none-eabi-gcc - name: Build run: make clean && make V=1 - name: Test diff --git a/.github/workflows/ubuntu-cmake.yml b/.github/workflows/ubuntu-cmake.yml index 539ac252d..dd99487f1 100644 --- a/.github/workflows/ubuntu-cmake.yml +++ b/.github/workflows/ubuntu-cmake.yml @@ -10,8 +10,6 @@ jobs: - uses: actions/checkout@v2 - name: Update apt repos run: sudo apt-get update - - name: Update packages - run: sudo apt-get upgrade -yqq - name: Install dependencies run: sudo apt-get install -yqq make autoconf build-essential ca-certificates pkg-config libreadline-dev gcc-arm-none-eabi libnewlib-dev qtbase5-dev libbz2-dev libbluetooth-dev libpython3-dev python3 python3-dev libpython3-all-dev liblua5.2-dev liblua5.2-0-dbg liblua5.2-0 lua5.2 sed - name: Build diff --git a/.github/workflows/ubuntu-make-btaddon.yml b/.github/workflows/ubuntu-make-btaddon.yml index e8de696a7..0e11f01c3 100644 --- a/.github/workflows/ubuntu-make-btaddon.yml +++ b/.github/workflows/ubuntu-make-btaddon.yml @@ -10,8 +10,6 @@ jobs: - uses: actions/checkout@v2 - name: Update apt repos run: sudo apt-get update - - name: Update packages - run: sudo apt-get upgrade -yqq - name: Install dependencies run: sudo apt-get install -yqq make autoconf build-essential ca-certificates pkg-config libreadline-dev gcc-arm-none-eabi libnewlib-dev qtbase5-dev libbz2-dev libbluetooth-dev libpython3-dev python3 python3-dev libpython3-all-dev liblua5.2-dev liblua5.2-0-dbg liblua5.2-0 lua5.2 sed - name: Build diff --git a/.github/workflows/ubuntu-make.yml b/.github/workflows/ubuntu-make.yml index 958c9c35d..f4f7d0113 100644 --- a/.github/workflows/ubuntu-make.yml +++ b/.github/workflows/ubuntu-make.yml @@ -10,8 +10,6 @@ jobs: - uses: actions/checkout@v2 - name: Update apt repos run: sudo apt-get update - - name: Update packages - run: sudo apt-get upgrade -yqq - name: Install dependencies run: sudo apt-get install -yqq make autoconf build-essential ca-certificates pkg-config libreadline-dev gcc-arm-none-eabi libnewlib-dev qtbase5-dev libbz2-dev libbluetooth-dev libpython3-dev python3 python3-dev libpython3-all-dev liblua5.2-dev liblua5.2-0-dbg liblua5.2-0 lua5.2 sed - name: Build From 4a6b2d4390a4666e5208c4a8da3ae37ea68315fa Mon Sep 17 00:00:00 2001 From: Ave Date: Mon, 4 Jan 2021 04:26:56 +0300 Subject: [PATCH 289/682] github actions: Introduce build variants for macos too --- .github/workflows/macos-cmake.yaml | 20 +++++++++++++++++++ .github/workflows/macos-make-btaddon.yml | 20 +++++++++++++++++++ .../workflows/{macos.yml => macos-make.yml} | 4 +--- 3 files changed, 41 insertions(+), 3 deletions(-) create mode 100644 .github/workflows/macos-cmake.yaml create mode 100644 .github/workflows/macos-make-btaddon.yml rename .github/workflows/{macos.yml => macos-make.yml} (81%) diff --git a/.github/workflows/macos-cmake.yaml b/.github/workflows/macos-cmake.yaml new file mode 100644 index 000000000..8c6a41f37 --- /dev/null +++ b/.github/workflows/macos-cmake.yaml @@ -0,0 +1,20 @@ +name: MacOS (cmake) Build and Test + +on: [push, pull_request] + +jobs: + build: + runs-on: macos-latest + + steps: + - uses: actions/checkout@v2 + - name: Update brew repos + run: brew update + - name: Tap RfidResearchGroup/proxmark3 + run: brew tap RfidResearchGroup/proxmark3 + - name: Install dependencies + run: brew install readline qt5 RfidResearchGroup/proxmark3/arm-none-eabi-gcc + - name: Build + run: mkdir -p client/build && ( cd client/build && cmake .. && make VERBOSE=1 ) + - name: Test + run: make client/check CHECKARGS="--clientbin ./client/build/proxmark3" diff --git a/.github/workflows/macos-make-btaddon.yml b/.github/workflows/macos-make-btaddon.yml new file mode 100644 index 000000000..9d5b75ff7 --- /dev/null +++ b/.github/workflows/macos-make-btaddon.yml @@ -0,0 +1,20 @@ +name: MacOS (make with BTADDON) Build and Test + +on: [push, pull_request] + +jobs: + build: + runs-on: macos-latest + + steps: + - uses: actions/checkout@v2 + - name: Update brew repos + run: brew update + - name: Tap RfidResearchGroup/proxmark3 + run: brew tap RfidResearchGroup/proxmark3 + - name: Install dependencies + run: brew install readline qt5 RfidResearchGroup/proxmark3/arm-none-eabi-gcc + - name: Build + run: make clean && make V=1 PLATFORM_EXTRAS=BTADDON + - name: Test + run: make check diff --git a/.github/workflows/macos.yml b/.github/workflows/macos-make.yml similarity index 81% rename from .github/workflows/macos.yml rename to .github/workflows/macos-make.yml index 3eb0b8584..a612bcda2 100644 --- a/.github/workflows/macos.yml +++ b/.github/workflows/macos-make.yml @@ -1,4 +1,4 @@ -name: MacOS Build and Test +name: MacOS (make) Build and Test on: [push, pull_request] @@ -8,8 +8,6 @@ jobs: steps: - uses: actions/checkout@v2 - - name: Brew python bug workaround - run: brew link --overwrite python - name: Update brew repos run: brew update - name: Tap RfidResearchGroup/proxmark3 From 38332d2fcf04f019a4001ae483f8c5db52d67d08 Mon Sep 17 00:00:00 2001 From: iceman1001 Date: Mon, 4 Jan 2021 11:11:05 +0100 Subject: [PATCH 290/682] hf mfu otptear/pwdgen - now supports cliparser --- client/src/cmdhfmfu.c | 289 +++++++++++++++++++---------------------- doc/cliparser_todo.txt | 15 --- 2 files changed, 137 insertions(+), 167 deletions(-) diff --git a/client/src/cmdhfmfu.c b/client/src/cmdhfmfu.c index b29c7ab26..9c0534c75 100644 --- a/client/src/cmdhfmfu.c +++ b/client/src/cmdhfmfu.c @@ -42,45 +42,6 @@ static int CmdHelp(const char *Cmd); - - -static int usage_hf_mfu_pwdgen(void) { - PrintAndLogEx(NORMAL, "Usage: hf mfu pwdgen [h|t] [r] "); - PrintAndLogEx(NORMAL, "Options:"); - PrintAndLogEx(NORMAL, " h : this help"); - PrintAndLogEx(NORMAL, " t : selftest"); - PrintAndLogEx(NORMAL, " r : read uid from tag"); - PrintAndLogEx(NORMAL, " : 7 byte UID (optional)"); - PrintAndLogEx(NORMAL, "Examples:"); - PrintAndLogEx(NORMAL, _YELLOW_(" hf mfu pwdgen r")); - PrintAndLogEx(NORMAL, _YELLOW_(" hf mfu pwdgen 11223344556677")); - PrintAndLogEx(NORMAL, _YELLOW_(" hf mfu pwdgen t")); - PrintAndLogEx(NORMAL, ""); - return PM3_SUCCESS; -} - -static int usage_hf_mfu_otp_tearoff(void) { - PrintAndLogEx(NORMAL, "Tear-off test against OTP block (no 3) on MFU tags - More help sooner or later\n"); - PrintAndLogEx(NORMAL, "Usage: hf mfu otptear b i l s d t \n"); - PrintAndLogEx(NORMAL, "Options:"); - PrintAndLogEx(NORMAL, " b : (optional) block to run the test - default block: 8 (not OTP for safety)"); - PrintAndLogEx(NORMAL, " i