From be25db28048d06b58b9851d8915a69a24eeb8402 Mon Sep 17 00:00:00 2001 From: Akif Dinc Date: Tue, 16 Feb 2021 20:53:53 +0100 Subject: [PATCH 01/58] Adding Figurine Type ID and Figurine ID parameters for hf jooki --- client/src/cmdhfjooki.c | 39 +++++++++++++++++++++++++++++++++------ 1 file changed, 33 insertions(+), 6 deletions(-) diff --git a/client/src/cmdhfjooki.c b/client/src/cmdhfjooki.c index 82e3787e6..5144a90a7 100644 --- a/client/src/cmdhfjooki.c +++ b/client/src/cmdhfjooki.c @@ -278,7 +278,8 @@ static int CmdHF14AJookiEncode(const char *Cmd) { "Encode a Jooki token to base64 NDEF URI format", "hf jooki encode -t --> selftest\n" "hf jooki encode -r --dragon --> read uid from tag and use for encoding\n" - "hf jooki encode --uid 04010203040506 --dragon" + "hf jooki encode --uid 04010203040506 --dragon\n" + "hf jooki encode --uid 04010203040506 -y 1 -f 1" ); void *argtable[] = { @@ -300,6 +301,8 @@ static int CmdHF14AJookiEncode(const char *Cmd) { arg_lit0(NULL, "whitefox", "figurine type"), arg_lit0(NULL, "whiteknight", "figurine type"), arg_lit0(NULL, "whitewhale", "figurine type"), + arg_u64_0("y", "tid", "", "figurine type id"), + arg_u64_0("f", "fid", "", "figurine id"), arg_param_end }; CLIExecWithReturn(ctx, Cmd, argtable, false); @@ -328,18 +331,42 @@ static int CmdHF14AJookiEncode(const char *Cmd) { bool tb = arg_get_lit(ctx, 15); bool tc = arg_get_lit(ctx, 16); bool td = arg_get_lit(ctx, 17); + + bool figure_abbr = true; + + uint8_t ftid = arg_get_u32_def(ctx, 18, 0); + uint8_t ffid = arg_get_u32_def(ctx, 19, 0); //default 0 ist schlecht + CLIParserFree(ctx); if (selftest) { return jooki_selftest(); } - if ((t0 + t1 + t2 + t3 + t5 + t6 + t7 + t8 + t9 + ta + tb + tc + td) > 1) { - PrintAndLogEx(ERR, "Select one tag type"); + uint8_t tid, fid; + + if( ftid && ffid ) { + figure_abbr = true; + tid = 0x01; + fid = 0x00; + } + + if ( ftid > 0x04 || ffid > 0x20 ) { + PrintAndLogEx(ERR, "Use a valid Figure Type ID and Figure ID"); return PM3_EINVARG; - } - uint8_t tid = 0x01; - uint8_t fid = 0x00; + } else { + figure_abbr = false; + } + + if ((t0 + t1 + t2 + t3 + t5 + t6 + t7 + t8 + t9 + ta + tb + tc + td) > 1 && !figure_abbr) { + PrintAndLogEx(ERR, "Select one tag type or use figurine type id and figurine id"); + return PM3_EINVARG; + } else { + tid = ftid; + fid = ffid; + } + + PrintAndLogEx(INFO, "Figurine Type ID %u and Figurine ID %u ", ftid, ffid); if (t1) fid = 0x01; if (t2) From 5c385e8f2fc3ab389889d6d80dbff9021dc6dcff Mon Sep 17 00:00:00 2001 From: Akif Dinc Date: Tue, 16 Feb 2021 20:55:48 +0100 Subject: [PATCH 02/58] Changes to Jooki command codes --- client/src/cmdhfjooki.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/client/src/cmdhfjooki.c b/client/src/cmdhfjooki.c index 5144a90a7..d31218b08 100644 --- a/client/src/cmdhfjooki.c +++ b/client/src/cmdhfjooki.c @@ -67,7 +67,7 @@ jooki_figure_t jooks_figures[] = { {0x01, 0x0C, "White Knight", "Figurine"}, {0x01, 0x0D, "White Whale", "Figurine"}, - {0x02, 0x01, "Generic Flat", "Stone"}, + {0x02, 0x00, "Generic Flat", "Stone"}, {0x03, 0x00, "record", "Sys"}, {0x03, 0x01, "factory_mode_on", "Sys"}, @@ -77,9 +77,10 @@ jooki_figure_t jooks_figures[] = { {0x03, 0x05, "toy_safe_on", "Sys"}, {0x03, 0x06, "toy_safe_off", "Sys"}, {0x03, 0x07, "wifi_on", "Sys"}, - {0x03, 0x08, "bt_on", "Sys"}, - {0x03, 0x0a, "bt_off", "Sys"}, - {0x03, 0x0b, "production_finished", "Sys"}, + {0x03, 0x08, "wifi_off", "Sys"}, + {0x03, 0x09, "bt_on", "Sys"}, + {0x03, 0x0A, "bt_off", "Sys"}, + {0x03, 0x0B, "production_finished", "Sys"}, {0x04, 0x00, "test.0", "Test"}, {0x04, 0x01, "test.1", "Test"}, From 76b73b26d360330b03eccd9f032d399522d35f96 Mon Sep 17 00:00:00 2001 From: Akif Dinc Date: Tue, 16 Feb 2021 22:34:39 +0100 Subject: [PATCH 03/58] Fixing short commands for figurine names --- client/src/cmdhfjooki.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/client/src/cmdhfjooki.c b/client/src/cmdhfjooki.c index d31218b08..df7cba428 100644 --- a/client/src/cmdhfjooki.c +++ b/client/src/cmdhfjooki.c @@ -348,8 +348,6 @@ static int CmdHF14AJookiEncode(const char *Cmd) { if( ftid && ffid ) { figure_abbr = true; - tid = 0x01; - fid = 0x00; } if ( ftid > 0x04 || ffid > 0x20 ) { @@ -363,7 +361,7 @@ static int CmdHF14AJookiEncode(const char *Cmd) { PrintAndLogEx(ERR, "Select one tag type or use figurine type id and figurine id"); return PM3_EINVARG; } else { - tid = ftid; + tid = 0x01; fid = ffid; } From 23be1158c6dc8818b1343a02acb8dba69545e8c2 Mon Sep 17 00:00:00 2001 From: Akif Dinc Date: Tue, 16 Feb 2021 22:37:17 +0100 Subject: [PATCH 04/58] Remove useless comment --- client/src/cmdhfjooki.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/src/cmdhfjooki.c b/client/src/cmdhfjooki.c index df7cba428..c6b14914f 100644 --- a/client/src/cmdhfjooki.c +++ b/client/src/cmdhfjooki.c @@ -336,7 +336,7 @@ static int CmdHF14AJookiEncode(const char *Cmd) { bool figure_abbr = true; uint8_t ftid = arg_get_u32_def(ctx, 18, 0); - uint8_t ffid = arg_get_u32_def(ctx, 19, 0); //default 0 ist schlecht + uint8_t ffid = arg_get_u32_def(ctx, 19, 0); CLIParserFree(ctx); From bb823762fa7c2f700bd6532bf460410e68708d25 Mon Sep 17 00:00:00 2001 From: iceman1001 Date: Tue, 16 Feb 2021 22:40:54 +0100 Subject: [PATCH 05/58] textual --- client/src/cmdhfmfu.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/client/src/cmdhfmfu.c b/client/src/cmdhfmfu.c index 94fff01ea..926642e1d 100644 --- a/client/src/cmdhfmfu.c +++ b/client/src/cmdhfmfu.c @@ -1385,17 +1385,17 @@ static int CmdHF14AMfUInfo(const char *Cmd) { } if (len < 1) { PrintAndLogEx(WARNING, _YELLOW_("password not known")); - PrintAndLogEx(HINT, "Hint: try " _YELLOW_("`hf mfu pwdgen r`") " to get see known pwd gen algo suggestions"); + PrintAndLogEx(HINT, "Hint: try " _YELLOW_("`hf mfu pwdgen -r`") " to get see known pwd gen algo suggestions"); } } else { - PrintAndLogEx(HINT, "Hint: try " _YELLOW_("`hf mfu pwdgen r`") " to get see known pwd gen algo suggestions"); + PrintAndLogEx(HINT, "Hint: try " _YELLOW_("`hf mfu pwdgen -r`") " to get see known pwd gen algo suggestions"); } } out: DropField(); if (locked) { 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(HINT, "Hint: try " _YELLOW_("`hf mfu pwdgen -r`") " to get see known pwd gen algo suggestions"); } PrintAndLogEx(NORMAL, ""); return PM3_SUCCESS; From f7359bcc656041db5da3e30167ce897678375a48 Mon Sep 17 00:00:00 2001 From: Akif Dinc Date: Tue, 16 Feb 2021 23:30:40 +0100 Subject: [PATCH 06/58] Fixing bug in tid selection --- client/src/cmdhfjooki.c | 40 ++++++++++++++++++++++++---------------- 1 file changed, 24 insertions(+), 16 deletions(-) diff --git a/client/src/cmdhfjooki.c b/client/src/cmdhfjooki.c index c6b14914f..7c2d9aa08 100644 --- a/client/src/cmdhfjooki.c +++ b/client/src/cmdhfjooki.c @@ -280,7 +280,7 @@ static int CmdHF14AJookiEncode(const char *Cmd) { "hf jooki encode -t --> selftest\n" "hf jooki encode -r --dragon --> read uid from tag and use for encoding\n" "hf jooki encode --uid 04010203040506 --dragon\n" - "hf jooki encode --uid 04010203040506 -y 1 -f 1" + "hf jooki encode --uid 04010203040506 --tid 1 --fid 1" ); void *argtable[] = { @@ -302,8 +302,8 @@ static int CmdHF14AJookiEncode(const char *Cmd) { arg_lit0(NULL, "whitefox", "figurine type"), arg_lit0(NULL, "whiteknight", "figurine type"), arg_lit0(NULL, "whitewhale", "figurine type"), - arg_u64_0("y", "tid", "", "figurine type id"), - arg_u64_0("f", "fid", "", "figurine id"), + arg_u64_0(NULL, "tid", "", "figurine type id"), + arg_u64_0(NULL, "fid", "", "figurine id"), arg_param_end }; CLIExecWithReturn(ctx, Cmd, argtable, false); @@ -333,11 +333,11 @@ static int CmdHF14AJookiEncode(const char *Cmd) { bool tc = arg_get_lit(ctx, 16); bool td = arg_get_lit(ctx, 17); - bool figure_abbr = true; - uint8_t ftid = arg_get_u32_def(ctx, 18, 0); uint8_t ffid = arg_get_u32_def(ctx, 19, 0); + bool figure_abbr = true; + CLIParserFree(ctx); if (selftest) { @@ -346,26 +346,34 @@ static int CmdHF14AJookiEncode(const char *Cmd) { uint8_t tid, fid; - if( ftid && ffid ) { - figure_abbr = true; + if( ftid || ffid ) { + figure_abbr = false; } if ( ftid > 0x04 || ffid > 0x20 ) { PrintAndLogEx(ERR, "Use a valid Figure Type ID and Figure ID"); return PM3_EINVARG; - } else { - figure_abbr = false; - } + } + + uint8_t figure_abbr_val = t0 + t1 + t2 + t3 + t5 + t6 + t7 + t8 + t9 + ta + tb + tc + td; - if ((t0 + t1 + t2 + t3 + t5 + t6 + t7 + t8 + t9 + ta + tb + tc + td) > 1 && !figure_abbr) { + if (figure_abbr_val > 1) { PrintAndLogEx(ERR, "Select one tag type or use figurine type id and figurine id"); return PM3_EINVARG; - } else { - tid = 0x01; - fid = ffid; - } + } + + if (figure_abbr_val == 1 && !figure_abbr) { + PrintAndLogEx(ERR, "Use either --tid and --fid or one of the figurine types"); + return PM3_EINVARG; + } + + if (figure_abbr) { + tid = 0x01; + } else { + tid = ftid; + } + fid = ffid; - PrintAndLogEx(INFO, "Figurine Type ID %u and Figurine ID %u ", ftid, ffid); if (t1) fid = 0x01; if (t2) From 45fea410844bd5ab3429693adccbd633c2876839 Mon Sep 17 00:00:00 2001 From: iceman1001 Date: Wed, 17 Feb 2021 07:32:38 +0100 Subject: [PATCH 07/58] text --- client/src/cmdwiegand.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/src/cmdwiegand.c b/client/src/cmdwiegand.c index 55e4d6e9c..3cdeb66b3 100644 --- a/client/src/cmdwiegand.c +++ b/client/src/cmdwiegand.c @@ -60,7 +60,7 @@ int CmdWiegandEncode(const char *Cmd) { arg_u64_0(NULL, "issue", "", "issue level"), arg_u64_0(NULL, "oem", "", "OEM code"), arg_str0("w", "wiegand", "", "see `wiegand list` for available formats"), - arg_lit0(NULL, "pre", "add HID preamble to wiegand"), + arg_lit0(NULL, "pre", "add HID ProxII preamble to wiegand output"), arg_param_end }; CLIExecWithReturn(ctx, Cmd, argtable, true); From b979ed3e17b5427c11c2dad603acc3ad5f09803a Mon Sep 17 00:00:00 2001 From: iceman1001 Date: Wed, 17 Feb 2021 07:33:29 +0100 Subject: [PATCH 08/58] style --- client/src/cmdhfjooki.c | 132 ++++++++++++++++++++-------------------- 1 file changed, 66 insertions(+), 66 deletions(-) diff --git a/client/src/cmdhfjooki.c b/client/src/cmdhfjooki.c index 7c2d9aa08..a513109a0 100644 --- a/client/src/cmdhfjooki.c +++ b/client/src/cmdhfjooki.c @@ -40,7 +40,7 @@ typedef struct { // sample set for selftest. jooki_test_t jooks[] = { { {0x04, 0xDA, 0xB7, 0x6A, 0xE7, 0x4C, 0x80}, "ruxow8lnn88uyeX+", 0x01, 0x00}, - { {0x04, 0xf0, 0x22, 0xc2, 0x33, 0x5e, 0x80}, "\0", 0x01 , 0x00}, + { {0x04, 0xf0, 0x22, 0xc2, 0x33, 0x5e, 0x80}, "\0", 0x01, 0x00}, { {0x04, 0x8C, 0xEC, 0xDA, 0xF0, 0x4A, 0x80}, "ONrsVf7jX6IaSNV6", 0x01, 0x01}, { {0x04, 0x92, 0xA7, 0x6A, 0xE7, 0x4C, 0x81}, "Hjjpcx/mZwuveTF+", 0x01, 0x02}, { {0x04, 0xD0, 0xB0, 0x3A, 0xD3, 0x63, 0x80}, "\0", 0x01, 0x02}, @@ -59,11 +59,11 @@ jooki_figure_t jooks_figures[] = { {0x01, 0x04, "ThankYou", "Figurine"}, {0x01, 0x05, "Whale", "Figurine"}, {0x01, 0x06, "Black Dragon", "Figurine"}, - {0x01, 0x07, "Black Fox", "Figurine"}, + {0x01, 0x07, "Black Fox", "Figurine"}, {0x01, 0x08, "Black Knight", "Figurine"}, {0x01, 0x09, "Black Whale", "Figurine"}, {0x01, 0x0A, "White Dragon", "Figurine"}, - {0x01, 0x0B, "White Fox", "Figurine"}, + {0x01, 0x0B, "White Fox", "Figurine"}, {0x01, 0x0C, "White Knight", "Figurine"}, {0x01, 0x0D, "White Whale", "Figurine"}, @@ -106,7 +106,7 @@ jooki_figure_t jooks_figures[] = { }; static int jooki_lookup(uint8_t tid, uint8_t fid) { - for (int i=0; i < ARRAYLEN(jooks_figures); i++) { + for (int i = 0; i < ARRAYLEN(jooks_figures); i++) { jooki_figure_t tmp = jooks_figures[i]; if (tmp.typeid == tid && tmp.figureid == fid) { return i; @@ -127,7 +127,7 @@ static int jooki_encode(uint8_t *iv, uint8_t tid, uint8_t fid, uint8_t *uid, uin if (out == NULL) { PrintAndLogEx(ERR, "(encode jooki) base64ndef param is NULL"); return PM3_EINVARG; - } + } out[0] = 0x00; if (iv == NULL || uid == NULL) { @@ -135,7 +135,7 @@ static int jooki_encode(uint8_t *iv, uint8_t tid, uint8_t fid, uint8_t *uid, uin return PM3_EINVARG; } - uint8_t d[JOOKI_PLAIN_LEN] = {iv[0], iv[1],iv[2], tid, fid, uid[0], uid[1], uid[2], uid[3], uid[4], uid[5], uid[6]}; + uint8_t d[JOOKI_PLAIN_LEN] = {iv[0], iv[1], iv[2], tid, fid, uid[0], uid[1], uid[2], uid[3], uid[4], uid[5], uid[6]}; uint8_t enc[JOOKI_PLAIN_LEN] = {0}; for (uint8_t i = 0; i < JOOKI_PLAIN_LEN; i++) { @@ -150,7 +150,7 @@ static int jooki_encode(uint8_t *iv, uint8_t tid, uint8_t fid, uint8_t *uid, uin size_t b64len = 0; uint8_t b64[20]; memset(b64, 0, 20); - mbedtls_base64_encode(b64, sizeof(b64), &b64len, (const unsigned char*)enc, sizeof(enc)); + mbedtls_base64_encode(b64, sizeof(b64), &b64len, (const unsigned char *)enc, sizeof(enc)); memcpy(out, b64, b64len); return PM3_SUCCESS; } @@ -158,7 +158,7 @@ static int jooki_encode(uint8_t *iv, uint8_t tid, uint8_t fid, uint8_t *uid, uin static int jooki_decode(uint8_t *b64, uint8_t *result) { uint8_t ndef[JOOKI_PLAIN_LEN] = {0}; size_t outputlen = 0; - mbedtls_base64_decode(ndef, sizeof(ndef), &outputlen, (const unsigned char*)b64, 16); + mbedtls_base64_decode(ndef, sizeof(ndef), &outputlen, (const unsigned char *)b64, 16); PrintAndLogEx(DEBUG, "(decode_jooki) raw encoded... " _GREEN_("%s"), sprint_hex(ndef, sizeof(ndef))); @@ -178,11 +178,11 @@ static int jooki_create_ndef(uint8_t *b64ndef, uint8_t *ndefrecord) { PrintAndLogEx(ERR, "(jooki_create_ndef) ndefrecord param is NULL"); return PM3_EINVARG; } - memcpy(ndefrecord, - "\x01\x03\xa0\x0c\x34\x03\x29\xd1" - "\x01\x25\x55\x04\x73\x2e\x6a\x6f" - "\x6f\x6b\x69\x2e\x72\x6f\x63\x6b" - "\x73\x2f\x73\x2f\x3f\x73\x3d", 31); + memcpy(ndefrecord, + "\x01\x03\xa0\x0c\x34\x03\x29\xd1" + "\x01\x25\x55\x04\x73\x2e\x6a\x6f" + "\x6f\x6b\x69\x2e\x72\x6f\x63\x6b" + "\x73\x2f\x73\x2f\x3f\x73\x3d", 31); memcpy(ndefrecord + 31, b64ndef, 16); memcpy(ndefrecord + 47, "\x0a\xFE\x00\x00\x00", 5); return PM3_SUCCESS; @@ -193,13 +193,13 @@ static void jooki_printEx(uint8_t *b64, uint8_t *iv, uint8_t tid, uint8_t fid, u PrintAndLogEx(INFO, "Encoded URL.. %s ( %s )", sprint_hex(b64, 12), b64); PrintAndLogEx(INFO, "Figurine..... %02x %02x - " _GREEN_("%s, %s") - , tid - , fid - , (idx != -1) ? jooks_figures[idx].typedesc : "n/a" - , (idx != -1) ? jooks_figures[idx].figdesc : "n/a" - ); - PrintAndLogEx(INFO, "iv........... %s", sprint_hex(iv, JOOKI_IV_LEN)); - PrintAndLogEx(INFO, "uid.......... %s", sprint_hex(uid, JOOKI_UID_LEN)); + , tid + , fid + , (idx != -1) ? jooks_figures[idx].typedesc : "n/a" + , (idx != -1) ? jooks_figures[idx].figdesc : "n/a" + ); + PrintAndLogEx(INFO, "iv........... %s", sprint_hex(iv, JOOKI_IV_LEN)); + PrintAndLogEx(INFO, "uid.......... %s", sprint_hex(uid, JOOKI_UID_LEN)); uint8_t ndefmsg[52] = {0}; jooki_create_ndef(b64, ndefmsg); @@ -228,8 +228,8 @@ static void jooki_print(uint8_t *b64, uint8_t *result, bool verbose) { } static int jooki_selftest(void) { - - PrintAndLogEx(INFO, "======== " _CYAN_("selftest") " ==========================================="); + + PrintAndLogEx(INFO, "======== " _CYAN_("selftest") " ==========================================="); for (int i = 0; i < ARRAYLEN(jooks); i++) { if (strlen(jooks[i].b64) == 0) continue; @@ -237,38 +237,38 @@ static int jooki_selftest(void) { uint8_t iv[JOOKI_IV_LEN] = {0}; uint8_t uid[JOOKI_UID_LEN] = {0}; uint8_t result[JOOKI_PLAIN_LEN] = {0}; - jooki_decode((uint8_t*)jooks[i].b64, result); + jooki_decode((uint8_t *)jooks[i].b64, result); memcpy(iv, result, JOOKI_IV_LEN); uint8_t tid = result[3]; uint8_t fid = result[4]; memcpy(uid, result + 5, sizeof(uid)); - bool tid_ok = (tid == jooks[i].typeid); - bool fid_ok = (fid == jooks[i].figureid); + bool tid_ok = (tid == jooks[i].typeid); + bool fid_ok = (fid == jooks[i].figureid); bool uid_ok = (memcmp(uid, jooks[i].uid, sizeof(uid)) == 0); int idx = jooki_lookup(tid, fid); - PrintAndLogEx(INFO, "Encoded URL.. %s ( %s )", sprint_hex((const uint8_t*)jooks[i].b64, 12), jooks[i].b64); - PrintAndLogEx(INFO, "Type......... %02x - " _GREEN_("%s") " ( %s )", tid, (idx != -1) ? jooks_figures[idx].typedesc : "n/a", tid_ok ? _GREEN_("ok") : _RED_("fail")); - PrintAndLogEx(INFO, "Figurine..... %02x - " _GREEN_("%s") " ( %s )", fid, (idx != -1) ? jooks_figures[idx].figdesc : "n/a", fid_ok ? _GREEN_("ok") : _RED_("fail")); - PrintAndLogEx(INFO, "iv........... %s", sprint_hex(iv, sizeof(iv))); - PrintAndLogEx(INFO, "uid.......... %s ( %s )", sprint_hex(uid, sizeof(uid)), uid_ok ? _GREEN_("ok") : _RED_("fail")); + PrintAndLogEx(INFO, "Encoded URL.. %s ( %s )", sprint_hex((const uint8_t *)jooks[i].b64, 12), jooks[i].b64); + PrintAndLogEx(INFO, "Type......... %02x - " _GREEN_("%s") " ( %s )", tid, (idx != -1) ? jooks_figures[idx].typedesc : "n/a", tid_ok ? _GREEN_("ok") : _RED_("fail")); + PrintAndLogEx(INFO, "Figurine..... %02x - " _GREEN_("%s") " ( %s )", fid, (idx != -1) ? jooks_figures[idx].figdesc : "n/a", fid_ok ? _GREEN_("ok") : _RED_("fail")); + PrintAndLogEx(INFO, "iv........... %s", sprint_hex(iv, sizeof(iv))); + PrintAndLogEx(INFO, "uid.......... %s ( %s )", sprint_hex(uid, sizeof(uid)), uid_ok ? _GREEN_("ok") : _RED_("fail")); uint8_t b64[JOOKI_B64_LEN] = {0}; - memset(b64, 0, sizeof(b64)); + memset(b64, 0, sizeof(b64)); jooki_encode(iv, tid, fid, uid, b64); uint8_t ndefmsg[52] = {0}; jooki_create_ndef(b64, ndefmsg); PrintAndLogEx(INFO, "NDEF raw .... %s", sprint_hex(ndefmsg, sizeof(ndefmsg))); - + int status = NDEFRecordsDecodeAndPrint(ndefmsg, sizeof(ndefmsg)); - if ( status != PM3_SUCCESS) { + if (status != PM3_SUCCESS) { status = NDEFDecodeAndPrint(ndefmsg, sizeof(ndefmsg), true); } - PrintAndLogEx(INFO, "=================================================================="); + PrintAndLogEx(INFO, "=================================================================="); } return PM3_SUCCESS; } @@ -280,7 +280,7 @@ static int CmdHF14AJookiEncode(const char *Cmd) { "hf jooki encode -t --> selftest\n" "hf jooki encode -r --dragon --> read uid from tag and use for encoding\n" "hf jooki encode --uid 04010203040506 --dragon\n" - "hf jooki encode --uid 04010203040506 --tid 1 --fid 1" + "hf jooki encode --uid 04010203040506 --tid 1 --fid 1" ); void *argtable[] = { @@ -302,8 +302,8 @@ static int CmdHF14AJookiEncode(const char *Cmd) { arg_lit0(NULL, "whitefox", "figurine type"), arg_lit0(NULL, "whiteknight", "figurine type"), arg_lit0(NULL, "whitewhale", "figurine type"), - arg_u64_0(NULL, "tid", "", "figurine type id"), - arg_u64_0(NULL, "fid", "", "figurine id"), + arg_u64_0(NULL, "tid", "", "figurine type id"), + arg_u64_0(NULL, "fid", "", "figurine id"), arg_param_end }; CLIExecWithReturn(ctx, Cmd, argtable, false); @@ -333,46 +333,46 @@ static int CmdHF14AJookiEncode(const char *Cmd) { bool tc = arg_get_lit(ctx, 16); bool td = arg_get_lit(ctx, 17); - uint8_t ftid = arg_get_u32_def(ctx, 18, 0); - uint8_t ffid = arg_get_u32_def(ctx, 19, 0); + uint8_t ftid = arg_get_u32_def(ctx, 18, 0); + uint8_t ffid = arg_get_u32_def(ctx, 19, 0); - bool figure_abbr = true; + bool figure_abbr = true; CLIParserFree(ctx); - + if (selftest) { return jooki_selftest(); } - uint8_t tid, fid; + uint8_t tid, fid; - if( ftid || ffid ) { - figure_abbr = false; - } + if (ftid || ffid) { + figure_abbr = false; + } - if ( ftid > 0x04 || ffid > 0x20 ) { + if (ftid > 0x04 || ffid > 0x20) { PrintAndLogEx(ERR, "Use a valid Figure Type ID and Figure ID"); return PM3_EINVARG; - } - - uint8_t figure_abbr_val = t0 + t1 + t2 + t3 + t5 + t6 + t7 + t8 + t9 + ta + tb + tc + td; + } + + uint8_t figure_abbr_val = t0 + t1 + t2 + t3 + t5 + t6 + t7 + t8 + t9 + ta + tb + tc + td; if (figure_abbr_val > 1) { PrintAndLogEx(ERR, "Select one tag type or use figurine type id and figurine id"); return PM3_EINVARG; - } + } - if (figure_abbr_val == 1 && !figure_abbr) { + if (figure_abbr_val == 1 && !figure_abbr) { PrintAndLogEx(ERR, "Use either --tid and --fid or one of the figurine types"); return PM3_EINVARG; - } + } - if (figure_abbr) { - tid = 0x01; - } else { - tid = ftid; - } - fid = ffid; + if (figure_abbr) { + tid = 0x01; + } else { + tid = ftid; + } + fid = ffid; if (t1) fid = 0x01; @@ -413,8 +413,8 @@ static int CmdHF14AJookiEncode(const char *Cmd) { } uint8_t b64[JOOKI_B64_LEN] = {0}; - memset(b64, 0, sizeof(b64)); - jooki_encode(iv, tid, fid, uid, b64); + memset(b64, 0, sizeof(b64)); + jooki_encode(iv, tid, fid, uid, b64); jooki_printEx(b64, iv, tid, fid, uid, verbose); return PM3_SUCCESS; } @@ -484,7 +484,7 @@ static int CmdHF14AJookiSim(const char *Cmd) { uint8_t *data = calloc(144, sizeof(uint8_t)); memcpy(data, uid, 3); - memcpy(data + (1*4), uid + 3, 4); + memcpy(data + (1 * 4), uid + 3, 4); // bbc0 data[3] = 0x88 ^ data[0] ^ data[1] ^ data[2]; @@ -492,8 +492,8 @@ static int CmdHF14AJookiSim(const char *Cmd) { // bbc1 data[8] = data[4] ^ data[5] ^ data[6] ^ data[7]; - // copy NDEF magic firs, skip BBC1 - memcpy(data + (2*4) + 1, "\x48\x00\x00\xE1\x10\x12\x00", 7); + // copy NDEF magic firs, skip BBC1 + memcpy(data + (2 * 4) + 1, "\x48\x00\x00\xE1\x10\x12\x00", 7); // copy raw NDEF jooki_create_ndef(b64, data + (4 * 4)); @@ -568,12 +568,12 @@ static int CmdHF14AJookiSim(const char *Cmd) { if (WaitForResponseTimeout(CMD_HF_MIFARE_SIMULATE, &resp, 1500) == 0) continue; - if (resp.status != PM3_SUCCESS) + if (resp.status != PM3_SUCCESS) break; } free(data); PrintAndLogEx(INFO, "Done"); - PrintAndLogEx(HINT, "Try `" _YELLOW_("hf 14a list") "` to view trace log" ); + PrintAndLogEx(HINT, "Try `" _YELLOW_("hf 14a list") "` to view trace log"); return PM3_SUCCESS; } @@ -651,7 +651,7 @@ static int CmdHF14AJookiClone(const char *Cmd) { } PrintAndLogEx(INFO, "Done"); - PrintAndLogEx(HINT, "Try `" _YELLOW_("hf mfu ndef") "` to view" ); + PrintAndLogEx(HINT, "Try `" _YELLOW_("hf mfu ndef") "` to view"); return PM3_SUCCESS; } From 563f703d6a4628ce2e02e00fdf34e85f4a119455 Mon Sep 17 00:00:00 2001 From: iceman1001 Date: Wed, 17 Feb 2021 08:56:42 +0100 Subject: [PATCH 09/58] lf hid clone - hooked up the binary input --- client/src/cmdlfhid.c | 13 ++++++++++--- client/src/util.c | 30 +++++++++++++++++++++++++++--- client/src/util.h | 1 + 3 files changed, 38 insertions(+), 6 deletions(-) diff --git a/client/src/cmdlfhid.c b/client/src/cmdlfhid.c index 47eeca45b..319fbc9e6 100644 --- a/client/src/cmdlfhid.c +++ b/client/src/cmdlfhid.c @@ -356,11 +356,9 @@ static int CmdHIDClone(const char *Cmd) { bool q5 = arg_get_lit(ctx, 7); bool em = arg_get_lit(ctx, 8); - int bin_len = 63; uint8_t bin[70] = {0}; CLIGetStrWithReturn(ctx, 9, bin, &bin_len); - CLIParserFree(ctx); if (q5 && em) { @@ -383,12 +381,21 @@ static int CmdHIDClone(const char *Cmd) { return PM3_EINVARG; } + uint32_t top = 0, mid = 0, bot = 0; if (raw_len) { - uint32_t top = 0, mid = 0, bot = 0; hexstring_to_u96(&top, &mid, &bot, raw); packed.Top = top; packed.Mid = mid; packed.Bot = bot; + } else if (bin_len) { + int res = binstring_to_u96(&top, &mid, &bot, bin); + if (res != bin_len) { + PrintAndLogEx(ERR, "Binary string contains none <0|1> chars"); + return PM3_EINVARG; + } + packed.Top = top; + packed.Mid = mid; + packed.Bot = bot; } else { if (HIDPack(format_idx, &card, &packed, true) == false) { PrintAndLogEx(WARNING, "The card data could not be encoded in the selected format."); diff --git a/client/src/util.c b/client/src/util.c index 03a1e68f8..53825f28b 100644 --- a/client/src/util.c +++ b/client/src/util.c @@ -951,13 +951,13 @@ char *str_ndup(const char *src, size_t len) { } /** - * Converts a hex string to component "hi2", "hi" and "lo" 32-bit integers, one nibble - * at a time. + * Converts a hex string to component "hi2", "hi" and "lo" 32-bit integers + * one nibble at a time. * * Returns the number of nibbles (4 bits) entered. */ int hexstring_to_u96(uint32_t *hi2, uint32_t *hi, uint32_t *lo, const char *str) { - unsigned int n = 0, i = 0; + uint32_t n = 0, i = 0; while (sscanf(&str[i++], "%1x", &n) == 1) { *hi2 = (*hi2 << 4) | (*hi >> 28); @@ -967,6 +967,30 @@ int hexstring_to_u96(uint32_t *hi2, uint32_t *hi, uint32_t *lo, const char *str) return i - 1; } +/** + * Converts a binary string to component "hi2", "hi" and "lo" 32-bit integers, + * one bit at a time. + * + * Returns the number of bits entered. + */ +int binstring_to_u96(uint32_t *hi2, uint32_t *hi, uint32_t *lo, const char *str) { + uint32_t n = 0, i = 0; + + for(;;) { + + int res = sscanf(&str[i], "%1u", &n); + if ((res != 1) || (n > 1)) + break; + + *hi2 = (*hi2 << 1) | (*hi >> 31); + *hi = (*hi << 1) | (*lo >> 31); + *lo = (*lo << 1) | (n & 0x1); + + i++; + } + return i; +} + inline uint32_t bitcount32(uint32_t a) { #if defined __GNUC__ return __builtin_popcountl(a); diff --git a/client/src/util.h b/client/src/util.h index 4d86553c2..7577c216e 100644 --- a/client/src/util.h +++ b/client/src/util.h @@ -105,6 +105,7 @@ void strcreplace(char *buf, size_t len, char from, char to); char *str_dup(const char *src); char *str_ndup(const char *src, size_t len); int hexstring_to_u96(uint32_t *hi2, uint32_t *hi, uint32_t *lo, const char *str); +int binstring_to_u96(uint32_t *hi2, uint32_t *hi, uint32_t *lo, const char *str); uint32_t bitcount32(uint32_t a); uint64_t bitcount64(uint64_t a); From 0a405ca21ea9be6ae71255670f86e492353c1bef Mon Sep 17 00:00:00 2001 From: iceman1001 Date: Wed, 17 Feb 2021 08:57:22 +0100 Subject: [PATCH 10/58] text --- doc/commands.md | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/doc/commands.md b/doc/commands.md index c6411b58c..1c9938d16 100644 --- a/doc/commands.md +++ b/doc/commands.md @@ -143,7 +143,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 apdufind `|N |`Enuerate APDUs - CLA/INS/P1P2` +|`hf 14a apdufind `|N |`Enumerate APDUs - CLA/INS/P1P2` ### hf 14b @@ -255,6 +255,19 @@ Check column "offline" for their availability. |`hf fido assert `|N |`FIDO2 GetAssertion command.` +### hf jooki + + { Jooki RFIDs... } + +|command |offline |description +|------- |------- |----------- +|`hf jooki help `|Y |`This help` +|`hf jooki clone `|N |`Write a Jooki token` +|`hf jooki decode `|Y |`Decode Jooki token` +|`hf jooki encode `|Y |`Encode Jooki token` +|`hf jooki sim `|N |`Simulate Jooki token` + + ### hf iclass { ICLASS RFIDs... } From b3064c48881176f940917cbc73fd6cf4099961ea Mon Sep 17 00:00:00 2001 From: iceman1001 Date: Wed, 17 Feb 2021 08:59:20 +0100 Subject: [PATCH 11/58] style --- client/src/cmdhfmfu.c | 6 +++--- client/src/fileutils.c | 2 +- client/src/fileutils.h | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/client/src/cmdhfmfu.c b/client/src/cmdhfmfu.c index 926642e1d..5a74149a5 100644 --- a/client/src/cmdhfmfu.c +++ b/client/src/cmdhfmfu.c @@ -3560,14 +3560,14 @@ static int CmdHF14MfuNDEF(const char *Cmd) { DropField(); status = NDEFRecordsDecodeAndPrint(records, (size_t)maxsize); - if ( status != PM3_SUCCESS) { + if (status != PM3_SUCCESS) { status = NDEFDecodeAndPrint(records, (size_t)maxsize, true); } - char *jooki = strstr((char*)records, "s.jooki.rocks/s/?s="); + char *jooki = strstr((char *)records, "s.jooki.rocks/s/?s="); if (jooki) { jooki += 17; - while(jooki) { + while (jooki) { if ((*jooki) != '=') jooki++; else { diff --git a/client/src/fileutils.c b/client/src/fileutils.c index 137d2640b..dc7ac530a 100644 --- a/client/src/fileutils.c +++ b/client/src/fileutils.c @@ -90,7 +90,7 @@ DumpFileType_t getfiletype(const char *filename) { } size_t len = strlen(filename); - if (len > 4) { + if (len > 4) { // check if valid file extension and attempt to load data char s[FILE_PATH_SIZE]; memset(s, 0, sizeof(s)); diff --git a/client/src/fileutils.h b/client/src/fileutils.h index 5e5cee664..bc06bd061 100644 --- a/client/src/fileutils.h +++ b/client/src/fileutils.h @@ -276,7 +276,7 @@ int searchFile(char **foundpath, const char *pm3dir, const char *searchname, con /** * @brief detects if file is of a supported filetype based on extension * @param filename - * @return + * @return */ DumpFileType_t getfiletype(const char *filename); #endif // FILEUTILS_H From e129244a6638c89933e31347e6a4d5f3be6d9579 Mon Sep 17 00:00:00 2001 From: iceman1001 Date: Wed, 17 Feb 2021 10:46:58 +0100 Subject: [PATCH 12/58] ..types --- client/src/cmdlfhid.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/src/cmdlfhid.c b/client/src/cmdlfhid.c index 319fbc9e6..02ccd5801 100644 --- a/client/src/cmdlfhid.c +++ b/client/src/cmdlfhid.c @@ -388,7 +388,7 @@ static int CmdHIDClone(const char *Cmd) { packed.Mid = mid; packed.Bot = bot; } else if (bin_len) { - int res = binstring_to_u96(&top, &mid, &bot, bin); + int res = binstring_to_u96(&top, &mid, &bot, (const char*)bin); if (res != bin_len) { PrintAndLogEx(ERR, "Binary string contains none <0|1> chars"); return PM3_EINVARG; From 88d95b639f2826b754c233a65d5b789db3cad708 Mon Sep 17 00:00:00 2001 From: iceman1001 Date: Wed, 17 Feb 2021 11:42:37 +0100 Subject: [PATCH 13/58] text --- client/src/cmdhfjooki.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/src/cmdhfjooki.c b/client/src/cmdhfjooki.c index a513109a0..39a4d4286 100644 --- a/client/src/cmdhfjooki.c +++ b/client/src/cmdhfjooki.c @@ -581,7 +581,7 @@ static int CmdHF14AJookiClone(const char *Cmd) { CLIParserContext *ctx; CLIParserInit(&ctx, "hf jooki clone", "Write a Jooki token to a Ultralight or NTAG tag", - "hf jooki clone -d --> where hex is raw NDEF" + "hf jooki clone -d --> where hex is raw NDEF\n" "hf jooki clone --b64 7WzlgEzqLgwTnWNy --> using base64 url parameter" ); From e5b879cbe9770896a627b8195d059bb8f0d57a67 Mon Sep 17 00:00:00 2001 From: iceman1001 Date: Wed, 17 Feb 2021 11:52:23 +0100 Subject: [PATCH 14/58] rdv4 device detection added --- client/src/cmdflashmem.c | 272 ++++++++++++++++++++++----------------- client/src/cmdflashmem.h | 4 +- client/src/cmdhw.c | 26 +++- 3 files changed, 179 insertions(+), 123 deletions(-) diff --git a/client/src/cmdflashmem.c b/client/src/cmdflashmem.c index 7f663c45b..23acad47d 100644 --- a/client/src/cmdflashmem.c +++ b/client/src/cmdflashmem.c @@ -11,7 +11,7 @@ #include #include "cmdparser.h" // command_t #include "cliparser.h" -#include "pmflash.h" +#include "pmflash.h" // rdv40validation_t #include "fileutils.h" // saveFile #include "comms.h" // getfromdevice #include "cmdflashmemspiffs.h" // spiffs commands @@ -26,6 +26,123 @@ static int CmdHelp(const char *Cmd); +//------------------------------------------------------------------------------------- +// RRG Public RSA Key +#define RRG_RSA_KEY_LEN 128 + +// public key Exponent E +#define RRG_RSA_E "010001" + +// public key modulus N +#define RRG_RSA_N "E28D809BF323171D11D1ACA4C32A5B7E0A8974FD171E75AD120D60E9B76968FF" \ + "4B0A6364AE50583F9555B8EE1A725F279E949246DF0EFCE4C02B9F3ACDCC623F" \ + "9337F21C0C066FFB703D8BFCB5067F309E056772096642C2B1A8F50305D5EC33" \ + "DB7FB5A3C8AC42EB635AE3C148C910750ABAA280CE82DC2F180F49F30A1393B5" + +// Following example RSA-1024 keypair, for test purposes (from common/polarssl/rsa.c) +// private key - Exponent D +#define RSA_D "24BF6185468786FDD303083D25E64EFC" \ + "66CA472BC44D253102F8B4A9D3BFA750" \ + "91386C0077937FE33FA3252D28855837" \ + "AE1B484A8A9A45F7EE8C0C634F99E8CD" \ + "DF79C5CE07EE72C7F123142198164234" \ + "CABB724CF78B8173B9F880FC86322407" \ + "AF1FEDFDDE2BEB674CA15F3E81A1521E" \ + "071513A1E85B5DFA031F21ECAE91A34D" + +// prime P +#define RSA_P "C36D0EB7FCD285223CFB5AABA5BDA3D8" \ + "2C01CAD19EA484A87EA4377637E75500" \ + "FCB2005C5C7DD6EC4AC023CDA285D796" \ + "C3D9E75E1EFC42488BB4F1D13AC30A57" + +// prime Q +#define RSA_Q "C000DF51A7C77AE8D7C7370C1FF55B69" \ + "E211C2B9E5DB1ED0BF61D0D9899620F4" \ + "910E4168387E3C30AA1E00C339A79508" \ + "8452DD96A9A5EA5D9DCA68DA636032AF" + +#define RSA_DP "C1ACF567564274FB07A0BBAD5D26E298" \ + "3C94D22288ACD763FD8E5600ED4A702D" \ + "F84198A5F06C2E72236AE490C93F07F8" \ + "3CC559CD27BC2D1CA488811730BB5725" + +#define RSA_DQ "4959CBF6F8FEF750AEE6977C155579C7" \ + "D8AAEA56749EA28623272E4F7D0592AF" \ + "7C1F1313CAC9471B5C523BFE592F517B" \ + "407A1BD76C164B93DA2D32A383E58357" + +#define RSA_QP "9AE7FBC99546432DF71896FC239EADAE" \ + "F38D18D2B2F0E2DD275AA977E2BF4411" \ + "F5A3B2A5D33605AEBBCCBA7FEB9F2D2F" \ + "A74206CEC169D74BF5A8C50D6F48EA08" + +int rdv4_get_signature(rdv40_validation_t *out) { + if (out == NULL) { + return PM3_EINVARG; + } + + clearCommandBuffer(); + SendCommandNG(CMD_FLASHMEM_INFO, NULL, 0); + PacketResponseNG resp; + if (WaitForResponseTimeout(CMD_ACK, &resp, 2500) == false) { + PrintAndLogEx(WARNING, "timeout while waiting for reply"); + return PM3_ETIMEOUT; + } + + uint8_t isok = resp.oldarg[0] & 0xFF; + if (isok == false) { + PrintAndLogEx(FAILED, "fail reading from flashmemory"); + return PM3_EFLASH; + } + + //rdv40_validation_t mem; + memcpy(out, (rdv40_validation_t *)resp.data.asBytes, sizeof(rdv40_validation_t)); + return PM3_SUCCESS; +} + +// validate signature +int rdv4_validate(rdv40_validation_t *mem) { + + // Flash ID hash (sha1) + uint8_t sha_hash[20] = {0}; + mbedtls_sha1(mem->flashid, sizeof(mem->flashid), sha_hash); + + // set up RSA + mbedtls_rsa_context rsa; + mbedtls_rsa_init(&rsa, MBEDTLS_RSA_PKCS_V15, 0); + rsa.len = RRG_RSA_KEY_LEN; + mbedtls_mpi_read_string(&rsa.N, 16, RRG_RSA_N); + mbedtls_mpi_read_string(&rsa.E, 16, RRG_RSA_E); + + // Verify (public key) + int is_verified = mbedtls_rsa_pkcs1_verify(&rsa, NULL, NULL, MBEDTLS_RSA_PUBLIC, MBEDTLS_MD_SHA1, 20, sha_hash, mem->signature); + mbedtls_rsa_free(&rsa); + + if (is_verified == 0) { + return PM3_SUCCESS; + } + return PM3_EFAILED; +} + +static int rdv4_sign_write(uint8_t *signature, uint8_t slen){ + // save to mem + clearCommandBuffer(); + PacketResponseNG resp; + SendCommandOLD(CMD_FLASHMEM_WRITE, FLASH_MEM_SIGNATURE_OFFSET, FLASH_MEM_SIGNATURE_LEN, 0, signature, slen); + if (!WaitForResponseTimeout(CMD_ACK, &resp, 2000)) { + PrintAndLogEx(WARNING, "timeout while waiting for reply."); + } else { + if (!resp.oldarg[0]) { + PrintAndLogEx(FAILED, "Writing signature ( "_RED_("fail") ")"); + } else { + PrintAndLogEx(SUCCESS, "Writing signature ( "_GREEN_("ok") " ) at offset %u", FLASH_MEM_SIGNATURE_OFFSET); + return PM3_SUCCESS; + } + } + return PM3_EFAILED; +} + static int CmdFlashmemSpiBaudrate(const char *Cmd) { CLIParserContext *ctx; @@ -344,23 +461,14 @@ static int CmdFlashMemInfo(const char *Cmd) { // shall_write = arg_get_lit(ctx, 2); CLIParserFree(ctx); - clearCommandBuffer(); - SendCommandNG(CMD_FLASHMEM_INFO, NULL, 0); - PacketResponseNG resp; - if (WaitForResponseTimeout(CMD_ACK, &resp, 2500) == false) { - PrintAndLogEx(WARNING, "timeout while waiting for reply"); - return PM3_ETIMEOUT; - } - - uint8_t isok = resp.oldarg[0] & 0xFF; - if (isok == false) { - PrintAndLogEx(FAILED, "failed"); - return PM3_EFLASH; - } - - // validate signature here + // validate signature data rdv40_validation_t mem; - memcpy(&mem, (rdv40_validation_t *)resp.data.asBytes, sizeof(rdv40_validation_t)); + int res = rdv4_get_signature(&mem); + if (res != PM3_SUCCESS) { + return res; + } + + res = rdv4_validate(&mem); // Flash ID hash (sha1) uint8_t sha_hash[20] = {0}; @@ -369,7 +477,6 @@ static int CmdFlashMemInfo(const char *Cmd) { // print header PrintAndLogEx(NORMAL, ""); PrintAndLogEx(INFO, "--- " _CYAN_("Flash memory Information") " ---------"); -// PrintAndLogEx(INFO, "-----------------------------------------------------------------"); PrintAndLogEx(INFO, "ID................... %s", sprint_hex_inrow(mem.flashid, sizeof(mem.flashid))); PrintAndLogEx(INFO, "SHA1................. %s", sprint_hex_inrow(sha_hash, sizeof(sha_hash))); PrintAndLogEx(NORMAL, ""); @@ -378,69 +485,16 @@ static int CmdFlashMemInfo(const char *Cmd) { PrintAndLogEx(INFO, " %s", sprint_hex_inrow(mem.signature + (i * 32), 32)); } -//------------------------------------------------------------------------------- -// RRG Public RSA Key -// - -// public key Exponent E -#define RSA_E "010001" - -// public key modulus N -#define RSA_N "E28D809BF323171D11D1ACA4C32A5B7E0A8974FD171E75AD120D60E9B76968FF" \ - "4B0A6364AE50583F9555B8EE1A725F279E949246DF0EFCE4C02B9F3ACDCC623F" \ - "9337F21C0C066FFB703D8BFCB5067F309E056772096642C2B1A8F50305D5EC33" \ - "DB7FB5A3C8AC42EB635AE3C148C910750ABAA280CE82DC2F180F49F30A1393B5" - -//------------------------------------------------------------------------------- -// Example RSA-1024 keypair, for test purposes (from common/polarssl/rsa.c) -// - -// private key Exponent D -#define RSA_D "24BF6185468786FDD303083D25E64EFC" \ - "66CA472BC44D253102F8B4A9D3BFA750" \ - "91386C0077937FE33FA3252D28855837" \ - "AE1B484A8A9A45F7EE8C0C634F99E8CD" \ - "DF79C5CE07EE72C7F123142198164234" \ - "CABB724CF78B8173B9F880FC86322407" \ - "AF1FEDFDDE2BEB674CA15F3E81A1521E" \ - "071513A1E85B5DFA031F21ECAE91A34D" - -// prime P -#define RSA_P "C36D0EB7FCD285223CFB5AABA5BDA3D8" \ - "2C01CAD19EA484A87EA4377637E75500" \ - "FCB2005C5C7DD6EC4AC023CDA285D796" \ - "C3D9E75E1EFC42488BB4F1D13AC30A57" - -// prime Q -#define RSA_Q "C000DF51A7C77AE8D7C7370C1FF55B69" \ - "E211C2B9E5DB1ED0BF61D0D9899620F4" \ - "910E4168387E3C30AA1E00C339A79508" \ - "8452DD96A9A5EA5D9DCA68DA636032AF" - -#define RSA_DP "C1ACF567564274FB07A0BBAD5D26E298" \ - "3C94D22288ACD763FD8E5600ED4A702D" \ - "F84198A5F06C2E72236AE490C93F07F8" \ - "3CC559CD27BC2D1CA488811730BB5725" - -#define RSA_DQ "4959CBF6F8FEF750AEE6977C155579C7" \ - "D8AAEA56749EA28623272E4F7D0592AF" \ - "7C1F1313CAC9471B5C523BFE592F517B" \ - "407A1BD76C164B93DA2D32A383E58357" - -#define RSA_QP "9AE7FBC99546432DF71896FC239EADAE" \ - "F38D18D2B2F0E2DD275AA977E2BF4411" \ - "F5A3B2A5D33605AEBBCCBA7FEB9F2D2F" \ - "A74206CEC169D74BF5A8C50D6F48EA08" - -#define KEY_LEN 128 - mbedtls_rsa_context rsa; mbedtls_rsa_init(&rsa, MBEDTLS_RSA_PKCS_V15, 0); - rsa.len = KEY_LEN; + rsa.len = RRG_RSA_KEY_LEN; - mbedtls_mpi_read_string(&rsa.N, 16, RSA_N); - mbedtls_mpi_read_string(&rsa.E, 16, RSA_E); + // add public key + mbedtls_mpi_read_string(&rsa.N, 16, RRG_RSA_N); + mbedtls_mpi_read_string(&rsa.E, 16, RRG_RSA_E); + + // add private key mbedtls_mpi_read_string(&rsa.D, 16, RSA_D); mbedtls_mpi_read_string(&rsa.P, 16, RSA_P); mbedtls_mpi_read_string(&rsa.Q, 16, RSA_Q); @@ -448,8 +502,6 @@ static int CmdFlashMemInfo(const char *Cmd) { mbedtls_mpi_read_string(&rsa.DQ, 16, RSA_DQ); mbedtls_mpi_read_string(&rsa.QP, 16, RSA_QP); - bool is_keyok = (mbedtls_rsa_check_pubkey(&rsa) == 0 || mbedtls_rsa_check_privkey(&rsa) == 0); - PrintAndLogEx(NORMAL, ""); PrintAndLogEx(INFO, "--- " _CYAN_("RDV4 RSA Public key") " --------------"); @@ -466,48 +518,35 @@ static int CmdFlashMemInfo(const char *Cmd) { PrintAndLogEx(INFO, " %.64s", str_pk + 64); PrintAndLogEx(INFO, " %.64s", str_pk + 128); PrintAndLogEx(INFO, " %.64s", str_pk + 192); - PrintAndLogEx(NORMAL, ""); - const char *msgkey = "RSA key validation... "; - if (is_keyok) - PrintAndLogEx(SUCCESS, "%s( " _GREEN_("ok") " )", msgkey); - else - PrintAndLogEx(FAILED, "%s( " _RED_("failed") " )", msgkey); - // - uint8_t from_device[KEY_LEN]; - uint8_t sign[KEY_LEN]; + bool is_keyok = (mbedtls_rsa_check_pubkey(&rsa) == 0 || mbedtls_rsa_check_privkey(&rsa) == 0); + PrintAndLogEx( + (is_keyok) ? SUCCESS : FAILED, + "RSA key validation... ( %s )", + (is_keyok) ? _GREEN_("ok") : _RED_("fail") + ); // to be verified - memcpy(from_device, mem.signature, KEY_LEN); + uint8_t from_device[RRG_RSA_KEY_LEN]; + memcpy(from_device, mem.signature, RRG_RSA_KEY_LEN); - // to be signed (all zeros - memset(sign, 0, KEY_LEN); + // to be signed + uint8_t sign[RRG_RSA_KEY_LEN]; + memset(sign, 0, RRG_RSA_KEY_LEN); // Signing (private key) if (shall_sign) { int is_signed = mbedtls_rsa_pkcs1_sign(&rsa, NULL, NULL, MBEDTLS_RSA_PRIVATE, MBEDTLS_MD_SHA1, 20, sha_hash, sign); - const char *msgsign = "RSA signing.......... "; - if (is_signed == 0) - PrintAndLogEx(SUCCESS, "%s( " _GREEN_("ok") " )", msgsign); - else - PrintAndLogEx(FAILED, "%s( " _RED_("failed") " )", msgsign); - + PrintAndLogEx( + (is_signed == 0) ? SUCCESS : FAILED, + "RSA signing.......... ( %s )", + (is_signed == 0) ? _GREEN_("ok") : _RED_("fail") + ); + if (shall_write) { - // save to mem - clearCommandBuffer(); - SendCommandOLD(CMD_FLASHMEM_WRITE, FLASH_MEM_SIGNATURE_OFFSET, FLASH_MEM_SIGNATURE_LEN, 0, sign, sizeof(sign)); - if (!WaitForResponseTimeout(CMD_ACK, &resp, 2000)) { - PrintAndLogEx(WARNING, "timeout while waiting for reply."); - } else { - - if (!resp.oldarg[0]) - PrintAndLogEx(FAILED, "Writing signature failed"); - else - PrintAndLogEx(SUCCESS, "Writing signature ok [offset: %u]", FLASH_MEM_SIGNATURE_OFFSET); - - } + rdv4_sign_write(sign, RRG_RSA_KEY_LEN); } PrintAndLogEx(INFO, "Signed"); for (int i = 0; i < (sizeof(sign) / 32); i++) { @@ -517,14 +556,15 @@ static int CmdFlashMemInfo(const char *Cmd) { // Verify (public key) int is_verified = mbedtls_rsa_pkcs1_verify(&rsa, NULL, NULL, MBEDTLS_RSA_PUBLIC, MBEDTLS_MD_SHA1, 20, sha_hash, from_device); - const char *msgverify = "RSA verification..... "; - if (is_verified == 0) - PrintAndLogEx(SUCCESS, "%s( " _GREEN_("ok") " )", msgverify); - else - PrintAndLogEx(FAILED, "%s( " _RED_("failed") " )", msgverify); + mbedtls_rsa_free(&rsa); + + PrintAndLogEx( + (is_verified == 0) ? SUCCESS : FAILED, + "RSA verification..... ( %s )", + (is_verified == 0) ? _GREEN_("ok") : _RED_("fail") + ); PrintAndLogEx(NORMAL, ""); - mbedtls_rsa_free(&rsa); return PM3_SUCCESS; } diff --git a/client/src/cmdflashmem.h b/client/src/cmdflashmem.h index 011b57a14..5a8f6eebc 100644 --- a/client/src/cmdflashmem.h +++ b/client/src/cmdflashmem.h @@ -12,6 +12,7 @@ #define CMDFLASHMEM_H__ #include "common.h" +#include "pmflash.h" // rdv40validation_t typedef enum { DICTIONARY_NONE = 0, @@ -21,5 +22,6 @@ typedef enum { } Dictionary_t; int CmdFlashMem(const char *Cmd); - +int rdv4_get_signature(rdv40_validation_t *out); +int rdv4_validate(rdv40_validation_t *mem); #endif diff --git a/client/src/cmdhw.c b/client/src/cmdhw.c index 49da91a83..24c292bbe 100644 --- a/client/src/cmdhw.c +++ b/client/src/cmdhw.c @@ -23,6 +23,8 @@ #include "cmddata.h" #include "commonutil.h" #include "pm3_cmd.h" +#include "pmflash.h" // rdv40validation_t +#include "cmdflashmem.h" // get_signature.. static int CmdHelp(const char *Cmd); @@ -959,17 +961,29 @@ void pm3_version(bool verbose, bool oneliner) { PrintAndLogEx(NORMAL, " compiled with " PM3CLIENTCOMPILER __VERSION__ PM3HOSTOS PM3HOSTARCH); PrintAndLogEx(NORMAL, "\n [ " _YELLOW_("PROXMARK3") " ]"); - if (IfPm3Rdv4Fw() == false) { - PrintAndLogEx(NORMAL, " firmware.................. %s", _YELLOW_("PM3GENERIC")); - if (IfPm3FpcUsartHost()) { - PrintAndLogEx(NORMAL, " FPC USART for BT add-on... %s", _GREEN_("present")); + if (IfPm3Rdv4Fw()) { + + bool is_genuine_rdv4 = false; + // validate signature data + rdv40_validation_t mem; + if (rdv4_get_signature(&mem) == PM3_SUCCESS) { + if (rdv4_validate(&mem) == PM3_SUCCESS) { + is_genuine_rdv4 = true; + } } - } else { - PrintAndLogEx(NORMAL, " firmware.................. %s", _YELLOW_("PM3RDV4")); + + PrintAndLogEx(NORMAL, " device.................... %s", (is_genuine_rdv4) ? _GREEN_("RDV4") : _RED_("device / fw mismatch")); + PrintAndLogEx(NORMAL, " firmware.................. %s", _YELLOW_("RDV4")); PrintAndLogEx(NORMAL, " external flash............ %s", IfPm3Flash() ? _GREEN_("present") : _YELLOW_("absent")); PrintAndLogEx(NORMAL, " smartcard reader.......... %s", IfPm3Smartcard() ? _GREEN_("present") : _YELLOW_("absent")); PrintAndLogEx(NORMAL, " FPC USART for BT add-on... %s", IfPm3FpcUsartHost() ? _GREEN_("present") : _YELLOW_("absent")); + } else { + PrintAndLogEx(NORMAL, " firmware.................. %s", _YELLOW_("PM3 GENERIC")); + if (IfPm3FpcUsartHost()) { + PrintAndLogEx(NORMAL, " FPC USART for BT add-on... %s", _GREEN_("present")); + } } + if (IfPm3FpcUsartDevFromUsb()) { PrintAndLogEx(NORMAL, " FPC USART for developer... %s", _GREEN_("present")); } From a1f9a03823ad43db9be9ce6e8ead05ef0cd2e060 Mon Sep 17 00:00:00 2001 From: Akif Dinc Date: Wed, 17 Feb 2021 13:31:44 +0100 Subject: [PATCH 15/58] Adding Jooki documentation --- doc/jooki_notes.md | 148 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 148 insertions(+) create mode 100644 doc/jooki_notes.md diff --git a/doc/jooki_notes.md b/doc/jooki_notes.md new file mode 100644 index 000000000..1e1cd5552 --- /dev/null +++ b/doc/jooki_notes.md @@ -0,0 +1,148 @@ +# Jooki Figurine Notes +- NTAG213 (Should be tested if other NTAG2xx work) +- A single NDEF record of type URL +- Physical figurines are Fox, Dragon, Knight, Ghost, Whale, Generic Flat. Than there are variations of those figures with different colors. + +## Jooki proxmark commands +You can `encode`, `decode` a NDEF record, write with `clone` a record to a card or simulate with`sim`. + +### Decoding NDEF URL parameter +`hf jooki decode -d g+t07s57aX1bB6tk` + +### Encoding NDEF record +You can either use figurine abbreviation arguments: +``` + --dragon + --fox + --ghost + --knight + --whale + --blackdragon + --blackfox + --blackknight + --blackwhale + --whitedragon + --whitefox + --whiteknight + --whitewhale +``` +Or pass directly the figurine type id `--tid` and figurine id `--fid` + +Example encoding NDEF record for UID `04010203040506` + +`hf jooki encode --uid 04010203040506 --tid 1 --fid 1` + +or use `--dragon` parameter to achieve the same: + + +`hf jooki encode --uid 04010203040506 --dragon` + +Output: +``` +[=] Encoded URL.. 67 2B 74 30 37 73 35 37 61 58 31 62 ( g+t07s57aX1bB6tk ) +[=] Figurine..... 01 00 - Figurine, Dragon +[=] iv........... 80 77 51 +[=] uid.......... 04 01 02 03 04 05 06 +[=] NDEF raw..... 0103A00C340329D101255504732E6A6F6F6B692E726F636B732F732F3F733D672B743037733537615831624236746B0AFE000000 +``` + +Use `-r` parameter to read UID directly from tag. + +### Simulation +To simulate the above figurine use the encoded URL parameter given in `encode` output and type following command into your proxmark: + +`hf jooki sim -b g+t07s57aX1bB6tk` + +If no parameter is given to the simulation command, last loaded dump is used. + +### Cloning to a NTAG213 tag +``` + hf jooki clone [-h] [-b ] [-d ] [-p ] + +options: + -h, --help This help + -b, --b64 base64 url parameter + -d, --data raw NDEF bytes + -p, --pwd password for authentication (EV1/NTAG 4 bytes) + +examples/notes: + hf jooki clone -d -> where hex is raw NDEFhf jooki clone --b64 7WzlgEzqLgwTnWNy --> using base64 url parameter +``` + +Use either the above NDEF raw output from `encode` to write a new record to a tag: + +`hf jooki clone -d 0103A00C340329D101255504732E6A6F6F6B692E726F636B732F732F3F733D672B743037733537615831624236746B0AFE000000` + +or use the base64 encoded parameter to clone: + +`hf jooki clone -b A5wlbrkq6QoKh9w1 + + +Note: Jooki doesn't like more than one NDEF record, so make sure you just have one. Check with `hf mfu ndef` + +### List of known figurine types +`Value`|`Figurine Type`| +|------|---------------| +**01** | Stones | +**02** | Generic Flat | +**03** | System Commands | +**04** | Tests | + +| `Figurine Type` | `Figurine ID` | `Figurine` | +|---------------|-------------|--------------------------| +| 01 | 00 | 狐狸 Fox | +| 01 | 01 | 龙 Dragon | +| 01 | 02 | 骑士 Knight | +| 01 | 03 | 鬼 Ghost | +| 01 | 04 | 鲸 Whale | +| 01 | 05 | ThankYou | +| 01 | 06 | Black.Fox | +| 01 | 07 | Black.Dragon | +| 01 | 08 | Black.Whale | +| 01 | 09 | Black.Knight | +| 01 | 0a | White.Fox | +| 01 | 0b | White.Dragon | +| 01 | 0c | White.Whale | +| 01 | 0d | White.Knight | +| | | | +| `02` | | `Generic Flat` | +| 02 | 00 | 圆盘 Generic Flat | +| 02 | 01 | unknown_0201 | +| | | | +| `03` | | `System Commands` | +| 03 | 00 | sys.record | +| 03 | 01 | sys.factory_mode_on | +| 03 | 02 | sys.factory_mode_off | +| 03 | 03 | sys.airplane_mode_on | +| 03 | 04 | sys.airplane_mode_off | +| 03 | 05 | sys.toy_safe_on | +| 03 | 06 | sys.toy_safe_off | +| 03 | 07 | sys.wifi_on | +| 03 | 08 | sys.wifi_off | +| 03 | 09 | sys.bt_on | +| 03 | 0a | sys.bt_off | +| 03 | 0b | sys.production_finished | +| | | | +| `04` | | `Tests` | +| 04 | 00 | Hello test.0 | +| 04 | 01 | Hello test.1 | +| 04 | 02 | Hello test.2 | +| 04 | 03 | Hello test.3 | +| 04 | 04 | Hello test.4 | +| 04 | 05 | Hello test.5 | +| 04 | 06 | Hello test.6 | +| 04 | 07 | Hello test.7 | +| 04 | 08 | Hello test.8 | +| 04 | 09 | Hello test.9 | +| 04 | 0a | Hello unknown_040A | +| 04 | 10 | Hello test.10 | +| 04 | 11 | Hello test.11 | +| 04 | 12 | Hello test.12 | +| 04 | 13 | Hello test.13 | +| 04 | 14 | Hello test.14 | +| 04 | 15 | Hello test.15 | +| 04 | 16 | Hello test.16 | +| 04 | 17 | Hello test.17 | +| 04 | 18 | Hello test.18 | +| 04 | 19 | Hello test.19 | + From 8d4d1cc3a6ae1ca5faa806216378a888c1e00a65 Mon Sep 17 00:00:00 2001 From: iceman1001 Date: Wed, 17 Feb 2021 17:31:08 +0100 Subject: [PATCH 16/58] text --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index b2581d98c..cf8ad802b 100644 --- a/README.md +++ b/README.md @@ -77,7 +77,7 @@ quite a lot, see the [Changelog file](CHANGELOG.md) which we try to keep updated This repo compiles nicely on - Proxspace v3.x - - [latest release v3.7.2](https://github.com/Gator96100/ProxSpace/releases) + - [latest release v3.7.3](https://github.com/Gator96100/ProxSpace/releases) - Windows/mingw environment with Qt5.6.1 & GCC 4.9 - Ubuntu 16.04 -> 20.04 - ParrotOS, Gentoo, Pentoo, Kali, Nethunter, Archlinux, Fedora, Debian From 84ab8e904f47be46e68c1cb510a8d125fa61f272 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C4=B0lteri=C5=9F=20Ero=C4=9Flu?= Date: Fri, 19 Feb 2021 02:40:40 +0300 Subject: [PATCH 17/58] Add another sig sample for MFC EV1 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: İlteriş Yağıztegin Eroğlu --- tools/recover_pk.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tools/recover_pk.py b/tools/recover_pk.py index 9c393a2d2..a268181f9 100755 --- a/tools/recover_pk.py +++ b/tools/recover_pk.py @@ -471,7 +471,8 @@ def selftests(): {'name': "Mifare Classic EV1", 'samples': ["0433619AB35780", "B9FAE369EC21C980650D87ED9AE9B1610E859131B4B8699C647548AB68D249BB", "524374E2", "F8758CE30A58553A9985C458FB9C7D340FCFB04847B928A0667939272BC58B5E", - "53424B8A", "B4F533E8C06C021E242EFE8558C1672ED7022E5AE4E7AA2D46113B0AB6928AFC"], + "53424B8A", "B4F533E8C06C021E242EFE8558C1672ED7022E5AE4E7AA2D46113B0AB6928AFC", + "BD2A4146", "19505576ED327D8F8870C86B1ED00898BFEDFFF27CC82FC515BA2EEC26050873"], 'pk': "044F6D3F294DEA5737F0F46FFEE88A356EED95695DD7E0C27A591E6F6F65962BAF" }, {'name': "DESFire Light", 'samples': ["0439556ACB6480", "D5BD0978106E1E38B513642335966AB21E9F950DCFCFAB45FF13D0DC3CA4C2AE7E0D671DF1240937D040DAC4601C5F66ED62C546EE03ED08", From 9293a25e3e6556354e4138ab674dd53c58190239 Mon Sep 17 00:00:00 2001 From: iceman1001 Date: Fri, 19 Feb 2021 13:39:35 +0100 Subject: [PATCH 18/58] hf 14a info - add MFC EV1 signature checks --- .../amiitool => resources}/key_retail.bin | Bin client/src/cmdhf14a.c | 10 +- client/src/cmdhfmf.c | 120 ++++++++++-------- client/src/cmdhfmf.h | 2 + client/src/crypto/libpcrypto.c | 7 +- client/src/mifare/mifarehost.c | 42 +++++- client/src/mifare/mifarehost.h | 3 + 7 files changed, 126 insertions(+), 58 deletions(-) rename client/{deps/amiitool => resources}/key_retail.bin (100%) diff --git a/client/deps/amiitool/key_retail.bin b/client/resources/key_retail.bin similarity index 100% rename from client/deps/amiitool/key_retail.bin rename to client/resources/key_retail.bin diff --git a/client/src/cmdhf14a.c b/client/src/cmdhf14a.c index a2212005f..2b1631963 100644 --- a/client/src/cmdhf14a.c +++ b/client/src/cmdhf14a.c @@ -1658,7 +1658,7 @@ int infoHF14A(bool verbose, bool do_nack_test, bool do_aid_search) { } else { // Double & triple sized UID, can be mapped to a manufacturer. - PrintAndLogEx(SUCCESS, "MANUFACTURER: " _YELLOW_("%s"), getTagInfo(card.uid[0])); + PrintAndLogEx(SUCCESS, "MANUFACTURER: " _YELLOW_("%s"), getTagInfo(card.uid[0])); switch (card.uid[0]) { case 0x02: // ST @@ -2101,6 +2101,14 @@ int infoHF14A(bool verbose, bool do_nack_test, bool do_aid_search) { if (do_nack_test) detect_classic_nackbug(false); } + + uint8_t signature[32] = {0}; + res = detect_mfc_ev1_signature(signature); + if (res == PM3_SUCCESS) { + mfc_ev1_print_signature(card.uid, card.uidlen, signature, sizeof(signature)); + } + + PrintAndLogEx(HINT, "Hint: try " _YELLOW_("`hf mf`") " commands"); } if (isMifareUltralight) diff --git a/client/src/cmdhfmf.c b/client/src/cmdhfmf.c index b8671c4b1..7b877658b 100644 --- a/client/src/cmdhfmf.c +++ b/client/src/cmdhfmf.c @@ -27,6 +27,7 @@ #include "des.h" // des ecb #include "crapto1/crapto1.h" // prng_successor #include "cmdhf14a.h" // exchange APDU +#include "crypto/libpcrypto.h" #define MFBLOCK_SIZE 16 @@ -425,6 +426,46 @@ static int usage_hf14_gen3freeze(void) { return PM3_SUCCESS; } +int mfc_ev1_print_signature(uint8_t *uid, uint8_t uidlen, uint8_t *signature, int signature_len) { + + // ref: MIFARE Classic EV1 Originality Signature Validation +#define PUBLIC_MFCEV1_ECDA_KEYLEN 33 + const ecdsa_publickey_t nxp_mfc_public_keys[] = { + {"NXP Mifare Classic MFC1C14_x", "044F6D3F294DEA5737F0F46FFEE88A356EED95695DD7E0C27A591E6F6F65962BAF"}, + }; + + uint8_t i; + bool is_valid = false; + + for (i = 0; i < ARRAYLEN(nxp_mfc_public_keys); i++) { + + int dl = 0; + uint8_t key[PUBLIC_MFCEV1_ECDA_KEYLEN]; + param_gethex_to_eol(nxp_mfc_public_keys[i].value, 0, key, PUBLIC_MFCEV1_ECDA_KEYLEN, &dl); + + int res = ecdsa_signature_r_s_verify(MBEDTLS_ECP_DP_SECP128R1, key, uid, uidlen, signature, signature_len, false); + is_valid = (res == 0); + if (is_valid) + break; + } + + PrintAndLogEx(INFO, ""); + PrintAndLogEx(INFO, "--- " _CYAN_("Tag Signature")); + if (is_valid == false || i == ARRAYLEN(nxp_mfc_public_keys)) { + PrintAndLogEx(INFO, " Elliptic curve parameters: NID_secp128r1"); + PrintAndLogEx(INFO, " TAG IC Signature: %s", sprint_hex_inrow(signature, 32)); + PrintAndLogEx(SUCCESS, " Signature verification: " _RED_("failed")); + return PM3_ESOFT; + } + + PrintAndLogEx(INFO, " IC signature public key name: %s", nxp_mfc_public_keys[i].desc); + PrintAndLogEx(INFO, "IC signature public key value: %s", nxp_mfc_public_keys[i].value); + PrintAndLogEx(INFO, " Elliptic curve parameters: NID_secp128r1"); + PrintAndLogEx(INFO, " TAG IC Signature: %s", sprint_hex_inrow(signature, 32)); + PrintAndLogEx(SUCCESS, " Signature verification: " _GREEN_("successful")); + return PM3_SUCCESS; +} + static int GetHFMF14AUID(uint8_t *uid, int *uidlen) { clearCommandBuffer(); SendCommandMIX(CMD_HF_ISO14443A_READER, ISO14A_CONNECT, 0, 0, NULL, 0); @@ -634,14 +675,14 @@ static int CmdHF14AMfWrBl(const char *Cmd) { PrintAndLogEx(NORMAL, "Usage: hf mf wrbl "); PrintAndLogEx(NORMAL, "Examples:"); PrintAndLogEx(NORMAL, " hf mf wrbl 1 A FFFFFFFFFFFF 000102030405060708090A0B0C0D0E0F"); - return 0; + return PM3_SUCCESS; } blockNo = param_get8(Cmd, 0); cmdp = tolower(param_getchar(Cmd, 1)); if (cmdp == 0x00) { PrintAndLogEx(NORMAL, "Key type must be A or B"); - return 1; + return PM3_EINVARG; } if (cmdp != 'a') @@ -649,12 +690,12 @@ static int CmdHF14AMfWrBl(const char *Cmd) { if (param_gethex(Cmd, 2, key, 12)) { PrintAndLogEx(NORMAL, "Key must include 12 HEX symbols"); - return 1; + return PM3_EINVARG; } if (param_gethex(Cmd, 3, bldata, 32)) { PrintAndLogEx(NORMAL, "Block data must include 32 HEX symbols"); - return 1; + return PM3_EINVARG; } PrintAndLogEx(NORMAL, "--block no %d, key %c - %s", blockNo, keyType ? 'B' : 'A', sprint_hex(key, 6)); @@ -674,7 +715,7 @@ static int CmdHF14AMfWrBl(const char *Cmd) { PrintAndLogEx(NORMAL, "Command execute timeout"); } - return 0; + return PM3_SUCCESS; } static int CmdHF14AMfRdBl(const char *Cmd) { @@ -706,34 +747,15 @@ static int CmdHF14AMfRdBl(const char *Cmd) { } PrintAndLogEx(NORMAL, "--block no %d, key %c - %s", blockNo, keyType ? 'B' : 'A', sprint_hex(key, 6)); - mf_readblock_t payload; - payload.blockno = blockNo; - payload.keytype = keyType; - memcpy(payload.key, key, sizeof(payload.key)); - - clearCommandBuffer(); - SendCommandNG(CMD_HF_MIFARE_READBL, (uint8_t *)&payload, sizeof(mf_readblock_t)); - - PacketResponseNG resp; - if (WaitForResponseTimeout(CMD_HF_MIFARE_READBL, &resp, 1500)) { - uint8_t *data = resp.data.asBytes; - - if (resp.status == PM3_SUCCESS) { - PrintAndLogEx(NORMAL, "data: %s", sprint_hex(data, 16)); - } else { - PrintAndLogEx(FAILED, "failed reading block"); - return PM3_ESOFT; - } - + uint8_t data[16] = {0}; + int res = mfReadBlock(blockNo, keyType, key, data); + if (res == PM3_SUCCESS) { + PrintAndLogEx(SUCCESS, "data: %s", sprint_hex(data, 16)); if ((data[6] || data[7] || data[8])) { decode_print_st(blockNo, data); } - } else { - PrintAndLogEx(WARNING, "Command execute timeout"); - return PM3_ETIMEOUT; } - - return 0; + return PM3_SUCCESS; } static int CmdHF14AMfRdSc(const char *Cmd) { @@ -769,30 +791,26 @@ static int CmdHF14AMfRdSc(const char *Cmd) { } PrintAndLogEx(NORMAL, "--sector no %d, key %c - %s ", sectorNo, keyType ? 'B' : 'A', sprint_hex(key, 6)); - clearCommandBuffer(); - SendCommandMIX(CMD_HF_MIFARE_READSC, sectorNo, keyType, 0, key, 6); - PrintAndLogEx(NORMAL, ""); - - PacketResponseNG resp; - if (WaitForResponseTimeout(CMD_ACK, &resp, 1500)) { - uint8_t isOK = resp.oldarg[0] & 0xff; - uint8_t *data = resp.data.asBytes; - - PrintAndLogEx(NORMAL, "isOk:%02x", isOK); - if (isOK) { - - uint8_t blocks = NumBlocksPerSector(sectorNo); - uint8_t start = FirstBlockOfSector(sectorNo); - - for (int i = 0; i < blocks; i++) { - PrintAndLogEx(NORMAL, "%3d | %s", start + i, sprint_hex(data + (i * 16), 16)); - } - decode_print_st(start + blocks - 1, data + ((blocks - 1) * 16)); - } - } else { - PrintAndLogEx(WARNING, "Command execute timeout"); + uint8_t sc_size = mfNumBlocksPerSector(sectorNo) * 16; + uint8_t *data = calloc(sc_size, sizeof(uint8_t)); + if (data == NULL) { + PrintAndLogEx(ERR, "failed to allocate memory"); + return PM3_EMALLOC; } + int res = mfReadSector(sectorNo, keyType, key, data); + if (res == PM3_SUCCESS) { + + uint8_t blocks = NumBlocksPerSector(sectorNo); + uint8_t start = FirstBlockOfSector(sectorNo); + + for (int i = 0; i < blocks; i++) { + PrintAndLogEx(NORMAL, "%3d | %s", start + i, sprint_hex(data + (i * 16), 16)); + } + decode_print_st(start + blocks - 1, data + ((blocks - 1) * 16)); + + } + free(data); return PM3_SUCCESS; } diff --git a/client/src/cmdhfmf.h b/client/src/cmdhfmf.h index 5325a7956..a4258bc67 100644 --- a/client/src/cmdhfmf.h +++ b/client/src/cmdhfmf.h @@ -24,4 +24,6 @@ void readerAttack(sector_t *k_sector, uint8_t k_sectorsCount, nonces_t data, boo void printKeyTable(uint8_t sectorscnt, sector_t *e_sector); void printKeyTableEx(uint8_t sectorscnt, sector_t *e_sector, uint8_t start_sector); void printKeyTable_fast(uint8_t sectorscnt, icesector_t *e_sector, uint64_t bar, uint64_t foo); + +int mfc_ev1_print_signature(uint8_t *uid, uint8_t uidlen, uint8_t *signature, int signature_len); #endif diff --git a/client/src/crypto/libpcrypto.c b/client/src/crypto/libpcrypto.c index 5c5455bf6..723753d5f 100644 --- a/client/src/crypto/libpcrypto.c +++ b/client/src/crypto/libpcrypto.c @@ -384,9 +384,8 @@ int ecdsa_signature_verify(mbedtls_ecp_group_id curveid, uint8_t *key_xy, uint8_ // take signature bytes, converts to ASN1 signature and tries to verify int ecdsa_signature_r_s_verify(mbedtls_ecp_group_id curveid, uint8_t *key_xy, uint8_t *input, int length, uint8_t *r_s, size_t r_s_len, bool hash) { - int res; - uint8_t signature[MBEDTLS_ECDSA_MAX_LEN]; - size_t signature_len; + uint8_t signature[MBEDTLS_ECDSA_MAX_LEN] = {0}; + size_t signature_len = 0; // convert r & s to ASN.1 signature mbedtls_mpi r, s; @@ -395,7 +394,7 @@ int ecdsa_signature_r_s_verify(mbedtls_ecp_group_id curveid, uint8_t *key_xy, ui mbedtls_mpi_read_binary(&r, r_s, r_s_len / 2); mbedtls_mpi_read_binary(&s, r_s + r_s_len / 2, r_s_len / 2); - res = ecdsa_signature_to_asn1(&r, &s, signature, &signature_len); + int res = ecdsa_signature_to_asn1(&r, &s, signature, &signature_len); if (res < 0) { return res; } diff --git a/client/src/mifare/mifarehost.c b/client/src/mifare/mifarehost.c index 3df2e295c..c6e02013e 100644 --- a/client/src/mifare/mifarehost.c +++ b/client/src/mifare/mifarehost.c @@ -748,7 +748,6 @@ int mfReadSector(uint8_t sectorNo, uint8_t keyType, uint8_t *key, uint8_t *data) clearCommandBuffer(); SendCommandMIX(CMD_HF_MIFARE_READSC, sectorNo, keyType, 0, key, 6); - PacketResponseNG resp; if (WaitForResponseTimeout(CMD_ACK, &resp, 1500)) { uint8_t isOK = resp.oldarg[0] & 0xff; @@ -760,10 +759,33 @@ int mfReadSector(uint8_t sectorNo, uint8_t keyType, uint8_t *key, uint8_t *data) return PM3_EUNDEF; } } else { - PrintAndLogEx(ERR, "Command execute timeout"); + PrintAndLogEx(DEBUG, "Command execute timeout"); return PM3_ETIMEOUT; } + return PM3_SUCCESS; +} +int mfReadBlock(uint8_t blockNo, uint8_t keyType, uint8_t *key, uint8_t *data) { + mf_readblock_t payload = { + .blockno = blockNo, + .keytype = keyType + }; + memcpy(payload.key, key, sizeof(payload.key)); + + clearCommandBuffer(); + SendCommandNG(CMD_HF_MIFARE_READBL, (uint8_t *)&payload, sizeof(mf_readblock_t)); + PacketResponseNG resp; + if (WaitForResponseTimeout(CMD_HF_MIFARE_READBL, &resp, 1500)) { + memcpy(data, resp.data.asBytes, 16); + + if (resp.status != PM3_SUCCESS) { + PrintAndLogEx(DEBUG, "failed reading block"); + return PM3_ESOFT; + } + } else { + PrintAndLogEx(DEBUG, "Command execute timeout"); + return PM3_ETIMEOUT; + } return PM3_SUCCESS; } @@ -1196,3 +1218,19 @@ int detect_mf_magic(bool is_mfc) { } return isGeneration; } + +int detect_mfc_ev1_signature(uint8_t *signature) { + if (signature == NULL) { + return PM3_EINVARG; + } + uint8_t sign[32] = {0}; + uint8_t key[] = {0x4b, 0x79, 0x1b, 0xea, 0x7b, 0xcc}; + int res = mfReadBlock(69, 1, key, sign); + if ( res == PM3_SUCCESS) { + res = mfReadBlock(70, 1, key, sign + 16); + if (res == PM3_SUCCESS) { + memcpy(signature, sign, sizeof(sign)); + } + } + return res; +} \ No newline at end of file diff --git a/client/src/mifare/mifarehost.h b/client/src/mifare/mifarehost.h index 7a3535257..c4c65737a 100644 --- a/client/src/mifare/mifarehost.h +++ b/client/src/mifare/mifarehost.h @@ -70,6 +70,7 @@ int mfCheckKeys_file(uint8_t *destfn, uint64_t *key); int mfKeyBrute(uint8_t blockNo, uint8_t keyType, uint8_t *key, uint64_t *resultkey); int mfReadSector(uint8_t sectorNo, uint8_t keyType, uint8_t *key, uint8_t *data); +int mfReadBlock(uint8_t blockNo, uint8_t keyType, uint8_t *key, uint8_t *data); int mfEmlGetMem(uint8_t *data, int blockNum, int blocksCount); int mfEmlSetMem(uint8_t *data, int blockNum, int blocksCount); @@ -90,5 +91,7 @@ int detect_classic_prng(void); int detect_classic_nackbug(bool verbose); int detect_mf_magic(bool is_mfc); int detect_classic_static_nonce(void); +int detect_mfc_ev1_signature(uint8_t *signature); + void mf_crypto1_decrypt(struct Crypto1State *pcs, uint8_t *data, int len, bool isEncrypted); #endif From bb0d3093040905677b2b8035b095bac2a3e3fe1f Mon Sep 17 00:00:00 2001 From: iceman1001 Date: Fri, 19 Feb 2021 13:41:28 +0100 Subject: [PATCH 19/58] amii tool now using fileutils --- client/deps/amiitool/Makefile | 2 +- client/deps/amiitool/amiibo.c | 25 ++++++++++++++++--------- client/deps/amiitool/amiibo.h | 2 +- client/deps/amiitool/amiitool.c | 9 --------- 4 files changed, 18 insertions(+), 20 deletions(-) diff --git a/client/deps/amiitool/Makefile b/client/deps/amiitool/Makefile index dd064227e..f72a675d8 100644 --- a/client/deps/amiitool/Makefile +++ b/client/deps/amiitool/Makefile @@ -1,5 +1,5 @@ MYSRCPATHS = -MYINCLUDES = -I. -I.. -I../jansson -I../../../common -I../../../common/mbedtls -I../../../include +MYINCLUDES = -I. -I.. -I../../../common -I../../../common/mbedtls -I../../../include -I../../src -I../../../include -I../jansson MYCFLAGS = MYDEFS = MYSRCS = \ diff --git a/client/deps/amiitool/amiibo.c b/client/deps/amiitool/amiibo.c index cbe3a0ba0..d41a291fa 100644 --- a/client/deps/amiitool/amiibo.c +++ b/client/deps/amiitool/amiibo.c @@ -9,7 +9,9 @@ #include "md.h" #include "aes.h" #include "commonutil.h" +#include "../src/fileutils.h" +#pragma endregion #define HMAC_POS_DATA 0x008 #define HMAC_POS_TAG 0x1B4 @@ -131,24 +133,29 @@ void nfc3d_amiibo_pack(const nfc3d_amiibo_keys *amiiboKeys, const uint8_t *plain nfc3d_amiibo_internal_to_tag(cipher, tag); } -bool nfc3d_amiibo_load_keys(nfc3d_amiibo_keys *amiiboKeys, const char *path) { - FILE *f = fopen(path, "rb"); - if (!f) { +bool nfc3d_amiibo_load_keys(nfc3d_amiibo_keys *amiiboKeys) { + +#define amiboo_key_fn "key_retail.bin" + + uint8_t *dump = NULL; + size_t bytes_read = 0; + if (loadFile_safe(amiboo_key_fn, "", (void **)&dump, &bytes_read) != PM3_SUCCESS) { + PrintAndLogEx(FAILED, "File: " _YELLOW_("%s") ": not found or locked.", amiboo_key_fn); return false; } - size_t len = fread(amiiboKeys, sizeof(*amiiboKeys), 1, f); - fclose(f); - - if (len != sizeof(*amiiboKeys)) { + if (bytes_read != sizeof(*amiiboKeys)) { + free(dump); return false; } - if ((amiiboKeys->data.magicBytesSize > 16) || - (amiiboKeys->tag.magicBytesSize > 16)) { + if ((amiiboKeys->data.magicBytesSize > 16) || (amiiboKeys->tag.magicBytesSize > 16)) { + free(dump); return false; } + memcpy(amiiboKeys, dump, bytes_read); + free(dump); return true; } diff --git a/client/deps/amiitool/amiibo.h b/client/deps/amiitool/amiibo.h index 47d544875..4ba0db7cd 100644 --- a/client/deps/amiitool/amiibo.h +++ b/client/deps/amiitool/amiibo.h @@ -25,7 +25,7 @@ typedef struct { bool nfc3d_amiibo_unpack(const nfc3d_amiibo_keys *amiiboKeys, const uint8_t *tag, uint8_t *plain); void nfc3d_amiibo_pack(const nfc3d_amiibo_keys *amiiboKeys, const uint8_t *plain, uint8_t *tag); -bool nfc3d_amiibo_load_keys(nfc3d_amiibo_keys *amiiboKeys, const char *path); +bool nfc3d_amiibo_load_keys(nfc3d_amiibo_keys *amiiboKeys); void nfc3d_amiibo_copy_app_data(const uint8_t *src, uint8_t *dst); #endif diff --git a/client/deps/amiitool/amiitool.c b/client/deps/amiitool/amiitool.c index d7cd08351..61f4abd81 100644 --- a/client/deps/amiitool/amiitool.c +++ b/client/deps/amiitool/amiitool.c @@ -33,15 +33,6 @@ void amiitool_usage(void) { ); } -static bool LoadAmiikey(nfc3d_amiibo_keys keys, char *keyfile) { - - if (!nfc3d_amiibo_load_keys(&keys, keyfile)) { - PrintAndLogEx(ERR, "Could not load keys from '%s'", keyfile); - return false; - } - return true; -} - int main(int argc, char **argv) { self = argv[0]; From 17bce5fb5a66831b2c8fb5563ec81f0be27089c7 Mon Sep 17 00:00:00 2001 From: iceman1001 Date: Fri, 19 Feb 2021 13:42:15 +0100 Subject: [PATCH 20/58] stack warning fix, dont like to fiddle with mbedtls but all our tests works.. --- common/mbedtls/ecdsa.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/common/mbedtls/ecdsa.c b/common/mbedtls/ecdsa.c index 1d087f386..a7d7bb720 100644 --- a/common/mbedtls/ecdsa.c +++ b/common/mbedtls/ecdsa.c @@ -289,20 +289,18 @@ cleanup: int ecdsa_signature_to_asn1(const mbedtls_mpi *r, const mbedtls_mpi *s, unsigned char *sig, size_t *slen) { int ret; - unsigned char buf[MBEDTLS_ECDSA_MAX_LEN]; - unsigned char *p = buf + sizeof(buf); + unsigned char buf[MBEDTLS_ECDSA_MAX_LEN] = {0}; + unsigned char *p = buf + sizeof(buf) - 1; size_t len = 0; MBEDTLS_ASN1_CHK_ADD(len, mbedtls_asn1_write_mpi(&p, buf, s)); MBEDTLS_ASN1_CHK_ADD(len, mbedtls_asn1_write_mpi(&p, buf, r)); MBEDTLS_ASN1_CHK_ADD(len, mbedtls_asn1_write_len(&p, buf, len)); - MBEDTLS_ASN1_CHK_ADD(len, mbedtls_asn1_write_tag(&p, buf, - MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE)); + MBEDTLS_ASN1_CHK_ADD(len, mbedtls_asn1_write_tag(&p, buf, MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE)); memcpy(sig, p, len); *slen = len; - return (0); } From 0bfb6cd625f20195b3f1f1b9973bbe546edab85a Mon Sep 17 00:00:00 2001 From: iceman1001 Date: Fri, 19 Feb 2021 14:20:04 +0100 Subject: [PATCH 21/58] fix NIL --- client/luascripts/data_mf_bin2eml.lua | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/client/luascripts/data_mf_bin2eml.lua b/client/luascripts/data_mf_bin2eml.lua index 8312fc292..5f9354e55 100644 --- a/client/luascripts/data_mf_bin2eml.lua +++ b/client/luascripts/data_mf_bin2eml.lua @@ -115,8 +115,7 @@ local function main(args) local dumpdata = readdump(infile) -- The hex-data is now in ascii-format, - if dumpdata == NIL then return oops('Dumpfle not loaded') end - + if dumpdata == nil then return oops('Dumpfle not loaded') end -- But first, check the uid local uid = string.sub(dumpdata, 1, 8) @@ -124,8 +123,7 @@ local function main(args) -- Format some linebreaks dumpdata = convert_to_emulform(dumpdata) - if dumpdata == NIL then return oops('Dumpfle not loaded') end - + if dumpdata == nil then return oops('Dumpfle not loaded') end local outfile = io.open(output, 'w') if outfile == nil then From aa65426e563a712d1207d0a1a9f91a361f910fd3 Mon Sep 17 00:00:00 2001 From: iceman1001 Date: Fri, 19 Feb 2021 14:30:36 +0100 Subject: [PATCH 22/58] fix compilation --- client/deps/amiitool/amiibo.c | 1 - 1 file changed, 1 deletion(-) diff --git a/client/deps/amiitool/amiibo.c b/client/deps/amiitool/amiibo.c index d41a291fa..edf7eb45f 100644 --- a/client/deps/amiitool/amiibo.c +++ b/client/deps/amiitool/amiibo.c @@ -11,7 +11,6 @@ #include "commonutil.h" #include "../src/fileutils.h" -#pragma endregion #define HMAC_POS_DATA 0x008 #define HMAC_POS_TAG 0x1B4 From f6b1cfd64c282cc3232ef850168f5d033f15b8fd Mon Sep 17 00:00:00 2001 From: iceman1001 Date: Fri, 19 Feb 2021 16:56:22 +0100 Subject: [PATCH 23/58] maur pk --- client/src/cmdhfmfdes.c | 9 +++++---- client/src/cmdhfmfp.c | 3 ++- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/client/src/cmdhfmfdes.c b/client/src/cmdhfmfdes.c index fa9b29b18..fc55a2c26 100644 --- a/client/src/cmdhfmfdes.c +++ b/client/src/cmdhfmfdes.c @@ -1306,11 +1306,12 @@ static int desfire_print_signature(uint8_t *uid, uint8_t uidlen, uint8_t *signat const ecdsa_publickey_t nxp_desfire_public_keys[] = { {"NTAG424DNA, DESFire EV2", "048A9B380AF2EE1B98DC417FECC263F8449C7625CECE82D9B916C992DA209D68422B81EC20B65A66B5102A61596AF3379200599316A00A1410"}, {"NTAG413DNA, DESFire EV1", "04BB5D514F7050025C7D0F397310360EEC91EAF792E96FC7E0F496CB4E669D414F877B7B27901FE67C2E3B33CD39D1C797715189AC951C2ADD"}, - {"DESFire EV2", "04B304DC4C615F5326FE9383DDEC9AA892DF3A57FA7FFB3276192BC0EAA252ED45A865E3B093A3D0DCE5BE29E92F1392CE7DE321E3E5C52B3A"}, - {"DESFire EV3", "041DB46C145D0A36539C6544BD6D9B0AA62FF91EC48CBC6ABAE36E0089A46F0D08C8A715EA40A63313B92E90DDC1730230E0458A33276FB743"}, + {"DESFire EV2", "04B304DC4C615F5326FE9383DDEC9AA892DF3A57FA7FFB3276192BC0EAA252ED45A865E3B093A3D0DCE5BE29E92F1392CE7DE321E3E5C52B3A"}, + {"DESFire EV3", "041DB46C145D0A36539C6544BD6D9B0AA62FF91EC48CBC6ABAE36E0089A46F0D08C8A715EA40A63313B92E90DDC1730230E0458A33276FB743"}, {"NTAG424DNA, NTAG424DNATT, DESFire Light EV2", "04B304DC4C615F5326FE9383DDEC9AA892DF3A57FA7FFB3276192BC0EAA252ED45A865E3B093A3D0DCE5BE29E92F1392CE7DE321E3E5C52B3B"}, - {"DESFire Light", "040E98E117AAA36457F43173DC920A8757267F44CE4EC5ADD3C54075571AEBBF7B942A9774A1D94AD02572427E5AE0A2DD36591B1FB34FCF3D"}, - {"MIFARE Plus EV1", "044409ADC42F91A8394066BA83D872FB1D16803734E911170412DDF8BAD1A4DADFD0416291AFE1C748253925DA39A5F39A1C557FFACD34C62E"} + {"DESFire Light", "040E98E117AAA36457F43173DC920A8757267F44CE4EC5ADD3C54075571AEBBF7B942A9774A1D94AD02572427E5AE0A2DD36591B1FB34FCF3D"}, + {"MIFARE Plus EV1", "044409ADC42F91A8394066BA83D872FB1D16803734E911170412DDF8BAD1A4DADFD0416291AFE1C748253925DA39A5F39A1C557FFACD34C62E"} + {"MIFARE Pluc Evx", "04BB49AE4447E6B1B6D21C098C1538B594A11A4A1DBF3D5E673DEACDEB3CC512D1C08AFA1A2768CE20A200BACD2DC7804CD7523A0131ABF607"}, }; diff --git a/client/src/cmdhfmfp.c b/client/src/cmdhfmfp.c index ab41bcf41..411c96bbf 100644 --- a/client/src/cmdhfmfp.c +++ b/client/src/cmdhfmfp.c @@ -163,7 +163,8 @@ static int plus_print_signature(uint8_t *uid, uint8_t uidlen, uint8_t *signature // ref: MIFARE Plus EV1 Originality Signature Validation #define PUBLIC_PLUS_ECDA_KEYLEN 57 const ecdsa_publickey_t nxp_plus_public_keys[] = { - {"Mifare Plus EV1", "044409ADC42F91A8394066BA83D872FB1D16803734E911170412DDF8BAD1A4DADFD0416291AFE1C748253925DA39A5F39A1C557FFACD34C62E"} + {"MIFARE Plus EV1", "044409ADC42F91A8394066BA83D872FB1D16803734E911170412DDF8BAD1A4DADFD0416291AFE1C748253925DA39A5F39A1C557FFACD34C62E"}, + {"MIFARE Pluc Ev_x", "04BB49AE4447E6B1B6D21C098C1538B594A11A4A1DBF3D5E673DEACDEB3CC512D1C08AFA1A2768CE20A200BACD2DC7804CD7523A0131ABF607"} }; uint8_t i; From bf62e4757584736bdcd76eac89c91f1c28a78321 Mon Sep 17 00:00:00 2001 From: iceman1001 Date: Fri, 19 Feb 2021 17:37:41 +0100 Subject: [PATCH 24/58] fix.... --- client/src/cmdhfmfdes.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/src/cmdhfmfdes.c b/client/src/cmdhfmfdes.c index fc55a2c26..c208367bc 100644 --- a/client/src/cmdhfmfdes.c +++ b/client/src/cmdhfmfdes.c @@ -1310,7 +1310,7 @@ static int desfire_print_signature(uint8_t *uid, uint8_t uidlen, uint8_t *signat {"DESFire EV3", "041DB46C145D0A36539C6544BD6D9B0AA62FF91EC48CBC6ABAE36E0089A46F0D08C8A715EA40A63313B92E90DDC1730230E0458A33276FB743"}, {"NTAG424DNA, NTAG424DNATT, DESFire Light EV2", "04B304DC4C615F5326FE9383DDEC9AA892DF3A57FA7FFB3276192BC0EAA252ED45A865E3B093A3D0DCE5BE29E92F1392CE7DE321E3E5C52B3B"}, {"DESFire Light", "040E98E117AAA36457F43173DC920A8757267F44CE4EC5ADD3C54075571AEBBF7B942A9774A1D94AD02572427E5AE0A2DD36591B1FB34FCF3D"}, - {"MIFARE Plus EV1", "044409ADC42F91A8394066BA83D872FB1D16803734E911170412DDF8BAD1A4DADFD0416291AFE1C748253925DA39A5F39A1C557FFACD34C62E"} + {"MIFARE Plus EV1", "044409ADC42F91A8394066BA83D872FB1D16803734E911170412DDF8BAD1A4DADFD0416291AFE1C748253925DA39A5F39A1C557FFACD34C62E"}, {"MIFARE Pluc Evx", "04BB49AE4447E6B1B6D21C098C1538B594A11A4A1DBF3D5E673DEACDEB3CC512D1C08AFA1A2768CE20A200BACD2DC7804CD7523A0131ABF607"}, }; From 937e754830ca2a2713ccfa3cd755e41e10c8629d Mon Sep 17 00:00:00 2001 From: iceman1001 Date: Fri, 19 Feb 2021 19:10:21 +0100 Subject: [PATCH 25/58] sort out amiitool linking to pm3 client in cmake --- client/deps/amiibo.cmake | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/client/deps/amiibo.cmake b/client/deps/amiibo.cmake index 491d90d60..c946c0682 100644 --- a/client/deps/amiibo.cmake +++ b/client/deps/amiibo.cmake @@ -14,10 +14,18 @@ add_library(pm3rrg_rdv4_amiibo STATIC if (NOT TARGET pm3rrg_rdv4_mbedtls) include(mbedtls.cmake) endif() + target_link_libraries(pm3rrg_rdv4_amiibo PRIVATE m pm3rrg_rdv4_mbedtls) -target_include_directories(pm3rrg_rdv4_amiibo PRIVATE ../../include ../../common) -target_include_directories(pm3rrg_rdv4_amiibo INTERFACE amiitool) + target_compile_options(pm3rrg_rdv4_amiibo PRIVATE -Wall -Werror -O3) set_property(TARGET pm3rrg_rdv4_amiibo PROPERTY POSITION_INDEPENDENT_CODE ON) + +target_include_directories(pm3rrg_rdv4_amiibo PRIVATE amiitool + ../../common + ../../include + ../src + jansson) + +target_include_directories(pm3rrg_rdv4_amiibo INTERFACE amiitool) \ No newline at end of file From c954180399dc9853630122ad38dc3ad0188eb5db Mon Sep 17 00:00:00 2001 From: iceman1001 Date: Fri, 19 Feb 2021 19:32:50 +0100 Subject: [PATCH 26/58] text --- CHANGELOG.md | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b730df269..ab629c19e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,11 +3,19 @@ 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] + - Change, numerous commands more uses cliparser (@tcprst, @iceman1001) + - Added more originality public keys (@anon) + - Added `hf 14a info` - now also verify MFC Ev1 signatures (@iceman1001) - Added `LF_THAREXDE` standalone mode which simulates and reads EM4x50 cards (@tharexde) - Added `hf jooki` commands (@iceman1001) + - Changed `lf hid clone` - also accepts binary wiegand (@iceman1001) - Changed `wiegand encode` - format param is now optional, w/o it will try encode all formats (@iceman1001) - Fix cppchecker warnings (@iceman1001) - - Added `trace list -t mf` - now can use external dictionary keys file + - Added `trace list -t mf` - now can use external dictionary keys file (@McEloff) + - Fix `lf gallagher read` - now correctly decodes card data + - Add support to `lf gallagher clone` and `lf gallagher sim` for writing specific card region, facility, card & issue numbers (@DarkMatterMatt) + - Added support for older vid/pid detection (@Gator96100) + - Added `hf mfdes bruteaid` - proper bruteforce of DESFire AID when no reading of files is possible (@craftbyte) - Added support for bidirectional communication for `lf em 4x50 sim` (@tharexde) - Change `PLATFORM=PM3OTHER` to `PLATFORM=PM3GENERIC` (@iceman1001) - Added `tools/hitag2crack/crack5opencl`, an optimized version of `crack5gpu` (@matrix) @@ -133,8 +141,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) - - Fix `lf gallagher read` - now correctly decodes card data - - Add support to `lf gallagher clone` and `lf gallagher sim` for writing specific card region, facility, card & issue numbers (@DarkMatterMatt) ## [ice coffee.4.9237][2020-05-21] - Updated documentation (@doegox, @iceman1001) From 292bbe5738372302f6387e258951ce05a710699a Mon Sep 17 00:00:00 2001 From: iceman1001 Date: Fri, 19 Feb 2021 20:14:11 +0100 Subject: [PATCH 27/58] Added new bulk enrolling lua script for EM4100 for Amal --- client/luascripts/lf_em4100_bulk.lua | 168 +++++++++++++++++++++++++++ 1 file changed, 168 insertions(+) create mode 100644 client/luascripts/lf_em4100_bulk.lua diff --git a/client/luascripts/lf_em4100_bulk.lua b/client/luascripts/lf_em4100_bulk.lua new file mode 100644 index 000000000..30aaa98fc --- /dev/null +++ b/client/luascripts/lf_em4100_bulk.lua @@ -0,0 +1,168 @@ +local getopt = require('getopt') +local utils = require('utils') +local ac = require('ansicolors') + +copyright = '' +author = "Christian Herrmann" +version = 'v1.0.0' +desc = [[ +Perform bulk EM410x enrollment of T5577 RFID tags. It keeps track of last card id used. +If called with -s, this value resets "session". + +if press it defaults to Y, which writes a ID. +Any other input char will exit the script. + +]] +example = [[ + -- resets and start enrolling EM410x id 11CC334455 + script run lf_em4100_bulk.lua -s 11CC334455 + + -- continue enrolling from where last iteration + script run lf_em4100_bulk.lua -c +]] +usage = [[ +script run lf_en4100_bulk.lua [-h] [-c] [-s ] +]] +arguments = [[ + -h : this help + -c : continue from last card number used + -s : starting card number + ]] + + -- Some globals +local DEBUG = false +local ENROLL_STATUS_FN = 'lf_em4100_status.txt' +--- +-- A debug printout-function +local function dbg(args) + if not DEBUG then return end + if type(args) == 'table' then + local i = 1 + while args[i] do + dbg(args[i]) + i = i+1 + end + else + print('###', args) + end +end +--- +-- This is only meant to be used when errors occur +local function oops(err) + print('ERROR:', err) + core.clearCommandBuffer() + return nil, errr +end +--- +-- Usage help +local function help() + print(copyright) + print(author) + print(version) + print(desc) + print(ac.cyan..'Usage'..ac.reset) + print(usage) + print(ac.cyan..'Arguments'..ac.reset) + print(arguments) + print(ac.cyan..'Example usage'..ac.reset) + print(example) +end +--- +-- Exit message +local function exitMsg(msg) + print( string.rep('--',20) ) + print( string.rep('--',20) ) + print(msg) + print() +end +--- +-- +local function readfile() + local f = io.open(ENROLL_STATUS_FN, "r") + if f == nil then + return nil, string.format("Could not read file %s", ENROLL_STATUS_FN) + end + local t = f:read("*all") + f:close() + local cn = tonumber(t, 16) + print(('Using EM4100 ID '..ac.green..'%010X'..ac.reset..' from `'..ac.yellow..'%s'..ac.reset..'`'):format(cn, ENROLL_STATUS_FN)) + return cn +end +--- +-- +local function writefile(cn) + local f = io.open(ENROLL_STATUS_FN, "w") + if f == nil then + return nil, string.format("Could not write to file %s", ENROLL_STATUS_FN) + end + f:write(("%010X\n"):format(cn)) + f:close() + print(('Wrote EM4100 ID '..ac.green..'%010X'..ac.reset..' to `'..ac.yellow..'%s'..ac.reset..'`'):format(cn, ENROLL_STATUS_FN)) + return true, 'Ok' +end + +--- +-- main +local function main(args) + + print( string.rep('--',20) ) + print( string.rep('--',20) ) + print() + + if #args == 0 then return help() end + + local shall_continue = false + local startid = '' + + for o, a in getopt.getopt(args, 'cs:h') do + if o == 'h' then return help() end + if o == 'c' then + shall_continue = true + end + if o == 's' then startid = a end + end + + -- if reset/start over, check -s + if not shall_continue then + if startid == nil then return oops('empty card number string') end + if #startid == 0 then return oops('empty card number string') end + if #startid ~= 10 then return oops('card number wrong length. Should be 5 hex bytes') end + end + + core.console('clear') + print(ac.red..'disable hints for less output'..ac.reset) + core.console('pref set hint --off') + print('') + + local sid = tonumber(startid, 16) + if shall_continue then + print('Continue enrolling from last save') + sid = readfile() + else + print('reset & starting enrolling from refresh') + end + + local template = 'EM4100 ID '..ac.green..'%010X'..ac.reset + local curr = sid + for i = sid, sid + 10000, 1 do + curr = i + + print('') + print( string.rep('--',20) ) + local msg = (template):format(curr) + local ans = utils.input(msg, 'y'):lower() + if ans == 'y' then + core.console( ('lf em 410x clone --id %010X'):format(curr) ) + -- print ( ('lf em 410x clone --id %010X'):format(curr) ) + else + print(ac.red..'User aborted'..ac.reset) + break + end + end + writefile(curr) + + print('enabling hints again') + core.console('pref set hint --on') +end + +main(args) From bee970721c2543a6b2ef71c94236cfa7a4df0e7f Mon Sep 17 00:00:00 2001 From: iceman1001 Date: Fri, 19 Feb 2021 20:38:53 +0100 Subject: [PATCH 28/58] text --- doc/md/Use_of_Proxmark/1_Validation.md | 38 ++++++++++++-------------- 1 file changed, 18 insertions(+), 20 deletions(-) diff --git a/doc/md/Use_of_Proxmark/1_Validation.md b/doc/md/Use_of_Proxmark/1_Validation.md index 9bb93c453..6f644d206 100644 --- a/doc/md/Use_of_Proxmark/1_Validation.md +++ b/doc/md/Use_of_Proxmark/1_Validation.md @@ -4,7 +4,6 @@ If all went well you should get some information about the firmware and memory u ``` [=] Session log /home/iceman/.proxmark3/log_20200521.txt -[=] Loading Preferences... [+] loaded from JSON file /home/iceman/.proxmark3/preferences.json [=] Using UART port /dev/ttyS7 [=] Communicating with PM3 over USB-CDC @@ -13,10 +12,11 @@ If all went well you should get some information about the firmware and memory u ██████╗ ███╗ ███╗ ████╗ ██╔══██╗████╗ ████║ ══█║ ██████╔╝██╔████╔██║ ████╔╝ -██╔═══╝ ██║╚██╔╝██║ ══█║ iceman@icesql.net -██║ ██║ ╚═╝ ██║ ████╔╝ https://github.com/rfidresearchgroup/proxmark3/ -╚═╝ ╚═╝ ╚═╝ ╚═══╝ Release v4.9237 - Ice Coffee - +██╔═══╝ ██║╚██╔╝██║ ══█║ +██║ ██║ ╚═╝ ██║ ████╔╝ Iceman ☕ +╚═╝ ╚═╝ ╚═╝ ╚═══╝ ❄️ bleeding edge + + https://github.com/rfidresearchgroup/proxmark3/ [ Proxmark3 RFID instrument ] @@ -25,30 +25,28 @@ If all went well you should get some information about the firmware and memory u compiled with GCC 9.3.0 OS:Linux ARCH:x86_64 [ PROXMARK RDV4 ] - external flash: present - smartcard reader: present - - [ PROXMARK RDV4 Extras ] - FPC USART for BT add-on support: absent + device.................... RDV4 + firmware.................. RDV4 + external flash............ present + smartcard reader.......... present + FPC USART for BT add-on... absent [ ARM ] bootrom: RRG/Iceman/master/v4.9237-2-g2cb19874 2020-05-21 22:00:10 os: RRG/Iceman/master/v4.9237-2-g2cb19874 2019-05-21 22:00:26 - compiled with GCC 8.3.1 20190703 (release) [gcc-8-branch revision 273027] + compiled with GCC 9.2.1 20191025 (release) [ARM/arm-9-branch revision 277599] [ FPGA ] - LF image built for 2s30vq100 on 2020/02/22 at 12:51:14 - HF image built for 2s30vq100 on 2020/01/12 at 15:31:16 + LF image built for 2s30vq100 on 2020-07-08 at 23: 8: 7 + HF image built for 2s30vq100 on 2020-07-08 at 23: 8:19 + HF FeliCa image built for 2s30vq100 on 2020-07-08 at 23: 8:30 [ Hardware ] - --= uC: AT91SAM7S512 Rev B + --= uC: AT91SAM7S512 Rev A --= Embedded Processor: ARM7TDMI - --= Nonvolatile Program Memory Size: 512K bytes, Used: 291382 bytes (56%) Free: 232906 bytes (44%) - --= Second Nonvolatile Program Memory Size: None - --= Internal SRAM Size: 64K bytes - --= Architecture Identifier: AT91SAM7Sxx Series - --= Nonvolatile Program Memory Type: Embedded Flash Memory - + --= Internal SRAM size: 64K bytes + --= Architecture identifier: AT91SAM7Sxx Series + --= Embedded flash memory 512K bytes ( 59% used ) [usb] pm3 --> ``` From e729d1804da83a6bfab16db08610cca67532bf84 Mon Sep 17 00:00:00 2001 From: iceman1001 Date: Fri, 19 Feb 2021 20:40:00 +0100 Subject: [PATCH 29/58] text --- client/src/cmdhw.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/client/src/cmdhw.c b/client/src/cmdhw.c index 24c292bbe..fb560b2ee 100644 --- a/client/src/cmdhw.c +++ b/client/src/cmdhw.c @@ -226,10 +226,10 @@ static void lookupChipID(uint32_t iChipID, uint32_t mem_used) { sprintf(asBuff, "ROMless or on-chip Flash"); break; case 2: - sprintf(asBuff, "Embedded Flash Memory"); + sprintf(asBuff, "Embedded flash memory"); break; case 3: - sprintf(asBuff, "ROM and Embedded Flash Memory\nNVPSIZ is ROM size\nNVPSIZ2 is Flash size"); + sprintf(asBuff, "ROM and Embedded flash memory\nNVPSIZ is ROM size\nNVPSIZ2 is Flash size"); break; case 4: sprintf(asBuff, "SRAM emulating ROM"); @@ -268,12 +268,13 @@ static void lookupChipID(uint32_t iChipID, uint32_t mem_used) { break; } - PrintAndLogEx(NORMAL, " --= Nonvolatile program memory: " _YELLOW_("%uK") " bytes %s ( " _YELLOW_("%2.0f%%") " used )" - , mem_avail + PrintAndLogEx(NORMAL, " --= %s " _YELLOW_("%uK") " bytes ( " _YELLOW_("%2.0f%%") " used )" , asBuff + , mem_avail , mem_avail == 0 ? 0.0f : (float)mem_used / (mem_avail * 1024) * 100 ); + /* switch ((iChipID & 0xF000) >> 12) { case 0: sprintf(asBuff, "None"); @@ -307,6 +308,7 @@ static void lookupChipID(uint32_t iChipID, uint32_t mem_used) { break; } PrintAndLogEx(NORMAL, " --= Second nonvolatile program memory size: %s", asBuff); + */ } static int CmdDbg(const char *Cmd) { @@ -1003,5 +1005,5 @@ void pm3_version(bool verbose, bool oneliner) { lookupChipID(payload->id, payload->section_size); } - PrintAndLogEx(NORMAL, "\n"); + PrintAndLogEx(NORMAL, ""); } From f00c00c150bc28e9d244dc8e95e487d214245b6c Mon Sep 17 00:00:00 2001 From: iceman1001 Date: Fri, 19 Feb 2021 20:41:32 +0100 Subject: [PATCH 30/58] hf mfu info - start in identify system of a mfu/ntag tag --- client/src/cmdhfmfu.c | 280 +++++++++++++++++++++++++++++++++++++++--- 1 file changed, 264 insertions(+), 16 deletions(-) diff --git a/client/src/cmdhfmfu.c b/client/src/cmdhfmfu.c index 5a74149a5..3c974e743 100644 --- a/client/src/cmdhfmfu.c +++ b/client/src/cmdhfmfu.c @@ -745,13 +745,13 @@ static int ulev1_print_signature(TagTypeUL_t tagtype, uint8_t *uid, uint8_t *sig // ref: AN11350 NTAG 21x Originality Signature Validation // ref: AN11341 MIFARE Ultralight EV1 Originality Signature Validation const ecdsa_publickey_t nxp_mfu_public_keys[] = { - {"NXP Mifare Classic MFC1C14_x", "044F6D3F294DEA5737F0F46FFEE88A356EED95695DD7E0C27A591E6F6F65962BAF"}, - {"Manufacturer Mifare Classic MFC1C14_x", "046F70AC557F5461CE5052C8E4A7838C11C7A236797E8A0730A101837C004039C2"}, - {"NXP ICODE DNA, ICODE SLIX2", "048878A2A2D3EEC336B4F261A082BD71F9BE11C4E2E896648B32EFA59CEA6E59F0"}, - {"NXP Public key", "04A748B6A632FBEE2C0897702B33BEA1C074998E17B84ACA04FF267E5D2C91F6DC"}, - {"NXP Ultralight Ev1", "0490933BDCD6E99B4E255E3DA55389A827564E11718E017292FAF23226A96614B8"}, - {"NXP NTAG21x (2013)", "04494E1A386D3D3CFE3DC10E5DE68A499B1C202DB5B132393E89ED19FE5BE8BC61"}, - {"MIKRON Public key", "04f971eda742a4a80d32dcf6a814a707cc3dc396d35902f72929fdcd698b3468f2"}, + {"NXP MIFARE Classic MFC1C14_x", "044F6D3F294DEA5737F0F46FFEE88A356EED95695DD7E0C27A591E6F6F65962BAF"}, + {"Manufacturer MIFARE Classic MFC1C14_x", "046F70AC557F5461CE5052C8E4A7838C11C7A236797E8A0730A101837C004039C2"}, + {"NXP ICODE DNA, ICODE SLIX2", "048878A2A2D3EEC336B4F261A082BD71F9BE11C4E2E896648B32EFA59CEA6E59F0"}, + {"NXP Public key", "04A748B6A632FBEE2C0897702B33BEA1C074998E17B84ACA04FF267E5D2C91F6DC"}, + {"NXP Ultralight Ev1", "0490933BDCD6E99B4E255E3DA55389A827564E11718E017292FAF23226A96614B8"}, + {"NXP NTAG21x (2013)", "04494E1A386D3D3CFE3DC10E5DE68A499B1C202DB5B132393E89ED19FE5BE8BC61"}, + {"MIKRON Public key", "04f971eda742a4a80d32dcf6a814a707cc3dc396d35902f72929fdcd698b3468f2"}, }; /* @@ -805,7 +805,7 @@ static int ulev1_print_signature(TagTypeUL_t tagtype, uint8_t *uid, uint8_t *sig for (i = 0; i < ARRAYLEN(nxp_mfu_public_keys); i++) { int dl = 0; - uint8_t key[PUBLIC_ECDA_KEYLEN]; + uint8_t key[PUBLIC_ECDA_KEYLEN] = {0}; param_gethex_to_eol(nxp_mfu_public_keys[i].value, 0, key, PUBLIC_ECDA_KEYLEN, &dl); int res = ecdsa_signature_r_s_verify(MBEDTLS_ECP_DP_SECP128R1, key, uid, 7, signature, signature_len, false); @@ -941,6 +941,249 @@ static char *GenerateFilename(const char *prefix, const char *suffix) { return fptr; } +//------------------------------------ +/* +static int mfu_decrypt_amiibo(uint8_t *encrypted, uint16_t elen, uint8_t *decrypted, uint16_t *dlen) { + + if (elen < NFC3D_AMIIBO_SIZE / 4) { + PrintAndLogEx(ERR, "ERR, data wrong length, got %zu , expected %zu", elen, (NFC3D_AMIIBO_SIZE / 4)); + return PM3_ESOFT; + } + + nfc3d_amiibo_keys amiibo_keys = {0}; + if (nfc3d_amiibo_load_keys(&amiibo_keys) == false) { + return PM3_ESOFT; + } + + if (nfc3d_amiibo_unpack(&amiibo_keys, encrypted, decrypted) == false) { + PrintAndLogEx(ERR, "WARNING, Tag signature was NOT valid"); + } + + *dlen = NFC3D_AMIIBO_SIZE; + return PM3_SUCCESS; +} +static int mfu_dump_tag(uint16_t pages, void **pdata, uint16_t *len) { + + int res = PM3_SUCCESS; + uint16_t maxbytes = (pages * 4); + + *pdata = calloc(maxbytes, sizeof(uint8_t)); + if (*pdata == NULL) { + PrintAndLogEx(FAILED, "error, cannot allocate memory"); + res = PM3_EMALLOC; + goto out; + } + + clearCommandBuffer(); + SendCommandMIX(CMD_HF_MIFAREU_READCARD, 0, pages, 0, NULL, 0); + PacketResponseNG resp; + if (WaitForResponseTimeout(CMD_ACK, &resp, 2500) == false) { + PrintAndLogEx(WARNING, "Command execute time-out"); + free(*pdata); + res = PM3_ETIMEOUT; + goto out; + } + + if (resp.oldarg[0] != 1) { + PrintAndLogEx(WARNING, "Failed reading card"); + free(*pdata); + res = PM3_ESOFT; + goto out; + } + + // read all memory + uint32_t startindex = resp.oldarg[2]; + uint32_t buffer_size = resp.oldarg[1]; + if (buffer_size > maxbytes) { + PrintAndLogEx(FAILED, "Data exceeded buffer size!"); + buffer_size = maxbytes; + } + + if (!GetFromDevice(BIG_BUF, *pdata, buffer_size, startindex, NULL, 0, NULL, 2500, false)) { + PrintAndLogEx(WARNING, "command execution time out"); + free(*pdata); + res = PM3_ETIMEOUT; + goto out; + } + + if (len) + *len = buffer_size; + +out: + return res; +} +*/ +/* +Lego Dimensions, + Version: 00 04 04 02 01 00 0F 03 + + matching bytes: + index 12 ( 3 * 4 ) + E1 10 12 00 01 03 A0 0C 34 03 13 D1 01 0F 54 02 65 6E +*/ + +typedef struct { + const char *desc; + const char *version; + uint8_t mpos; + uint8_t mlen; + const char *match; + uint32_t (*Pwd)(uint8_t *uid); + uint16_t (*Pack)(uint8_t *uid); + const char *hint; +} PACKED mfu_identify_t; + +static mfu_identify_t mfu_ident_table[] = { + { + "Jooki", "0004040201000F03", + 12, 32, "E11012000103A00C340329D101255504732E6A6F6F6B692E726F636B732F732F", + NULL, NULL, + "hf jooki decode -r" + }, + { + "Lego Dimensions", "0004040201000F03", + 12, 18, "E11012000103A00C340313D1010F5402656E", + ul_ev1_pwdgenC, ul_ev1_packgenC, + "hf mfu dump -k %08x" + }, + { + "Amiibo", "0004040201001103", + 9, 9, "480FE0F110FFEEA500", + ul_ev1_pwdgenB, ul_ev1_packgenB, + "hf mfu dump -k %08x" + }, + {NULL, NULL, 0, 0, NULL, NULL, NULL, NULL} +}; + +static mfu_identify_t* mfu_match_fingerprint(uint8_t *version, uint8_t *data) { + uint8_t i = 0; + do { + + int vl = 0; + uint8_t vtmp[10] = {0}; + param_gethex_to_eol(mfu_ident_table[i].version, 0, vtmp, sizeof(vtmp), &vl); + + bool m1 = (memcmp(vtmp, version, vl) == 0); + if (m1 == false) { + PrintAndLogEx(DEBUG, "(fingerprint) wrong version"); + continue; + } + + int ml = 0; + uint8_t mtmp[40] = {0}; + param_gethex_to_eol(mfu_ident_table[i].match, 0, mtmp, sizeof(mtmp), &ml); + + bool m2 = (memcmp(mtmp, data + mfu_ident_table[i].mpos, mfu_ident_table[i].mlen) == 0); + if (m2) { + PrintAndLogEx(DEBUG, "(fingerprint) found %s", mfu_ident_table[i].desc); + return &mfu_ident_table[i]; + } + } while (mfu_ident_table[++i].desc); + return NULL; +} + +static uint8_t mfu_max_len(void) { + uint8_t n = 0, i = 0; + do { + uint8_t tmp = mfu_ident_table[i].mpos + mfu_ident_table[i].mlen; + if (tmp > n) { + n = tmp; + } + } while (mfu_ident_table[++i].desc); + return n; +} + +static int mfu_get_version_uid(uint8_t *version, uint8_t *uid) { + iso14a_card_select_t card; + if (ul_select(&card) == false) + return PM3_ESOFT; + + uint8_t v[10] = {0x00}; + int len = ulev1_getVersion(v, sizeof(v)); + DropField(); + if (len != sizeof(v)) + return PM3_ESOFT; + + memcpy(version, v, 8); + memcpy(uid, card.uid, 7); + return PM3_SUCCESS; +} + +static int mfu_fingerprint(void) { + + uint8_t *data = NULL; + int res = PM3_SUCCESS; + PrintAndLogEx(INFO, "------------------------ " _CYAN_("Fingerprint") " -----------------------"); + uint8_t maxbytes = mfu_max_len(); + if (maxbytes == 0) { + PrintAndLogEx(ERR, "fingerprint table wrong"); + res = PM3_ESOFT; + goto out; + } + + maxbytes = ((maxbytes / 4) + 1) * 4; + data = calloc(maxbytes, sizeof(uint8_t)); + if (data == NULL) { + PrintAndLogEx(ERR, "failed to allocate memory"); + res = PM3_EMALLOC; + goto out; + } + + uint8_t pages = (maxbytes / 4); + PrintAndLogEx(INFO, "Reading tag memory..."); + + clearCommandBuffer(); + SendCommandMIX(CMD_HF_MIFAREU_READCARD, 0, pages, 0, NULL, 0); + PacketResponseNG resp; + if (!WaitForResponseTimeout(CMD_ACK, &resp, 2500)) { + PrintAndLogEx(WARNING, "Command execute time-out"); + res = PM3_ETIMEOUT; + goto out; + } + + if (resp.oldarg[0] != 1) { + PrintAndLogEx(WARNING, "Failed reading card"); + res = PM3_ESOFT; + goto out; + } + + // read all memory + uint32_t startindex = resp.oldarg[2]; + uint32_t buffer_size = resp.oldarg[1]; + if (buffer_size > maxbytes) { + PrintAndLogEx(FAILED, "Data exceeded buffer size!"); + buffer_size = maxbytes; + } + + if (!GetFromDevice(BIG_BUF, data, buffer_size, startindex, NULL, 0, NULL, 2500, false)) { + PrintAndLogEx(WARNING, "command execution time out"); + res = PM3_ETIMEOUT; + goto out; + } + + uint8_t version[8] = {0}; + uint8_t uid[7] = {0}; + if (mfu_get_version_uid(version, uid) == PM3_SUCCESS) { + mfu_identify_t* item = mfu_match_fingerprint(version, data); + if (item) { + PrintAndLogEx(SUCCESS, "Found " _GREEN_("%s"), item->desc); + + if (item->Pwd) { + char s[40] = {0}; + sprintf(s, item->hint, item->Pwd(uid)); + PrintAndLogEx(HINT, "Use `" _YELLOW_("%s") "`", s); + } else { + PrintAndLogEx(HINT, "Use `" _YELLOW_("%s") "`", item->hint); + } + } + } + +out: + free(data); + PrintAndLogEx(INFO, "------------------------------------------------------------"); + return res; +} + uint32_t GetHF14AMfU_Type(void) { TagTypeUL_t tagtype = UNKNOWN; @@ -1391,6 +1634,9 @@ static int CmdHF14AMfUInfo(const char *Cmd) { PrintAndLogEx(HINT, "Hint: try " _YELLOW_("`hf mfu pwdgen -r`") " to get see known pwd gen algo suggestions"); } } + + mfu_fingerprint(); + out: DropField(); if (locked) { @@ -2223,6 +2469,7 @@ static int CmdHF14AMfURestore(const char *Cmd) { } PrintAndLogEx(INFO, "Restoring data blocks."); + PrintAndLogEx(INFO, "." NOLF); // write all other data // Skip block 0,1,2,3 (only magic tags can write to them) // Skip last 5 blocks usually is configuration @@ -2234,6 +2481,7 @@ static int CmdHF14AMfURestore(const char *Cmd) { SendCommandMIX(CMD_HF_MIFAREU_WRITEBL, b, keytype, 0, data, sizeof(data)); wait4response(b); PrintAndLogEx(NORMAL, "." NOLF); + fflush(stdout); } PrintAndLogEx(NORMAL, ""); @@ -2810,15 +3058,15 @@ static int CmdHF14AMfUPwdGen(const char *Cmd) { PrintAndLogEx(INFO, "---------------------------------"); PrintAndLogEx(INFO, " Using UID : %s", sprint_hex(uid, 7)); PrintAndLogEx(INFO, "---------------------------------"); - PrintAndLogEx(INFO, " algo | pwd | pack"); - PrintAndLogEx(INFO, "------+----------+-----"); - PrintAndLogEx(INFO, " EV1 | %08X | %04X", ul_ev1_pwdgenA(uid), ul_ev1_packgenA(uid)); - PrintAndLogEx(INFO, " Ami | %08X | %04X", ul_ev1_pwdgenB(uid), ul_ev1_packgenB(uid)); - PrintAndLogEx(INFO, " LD | %08X | %04X", ul_ev1_pwdgenC(uid), ul_ev1_packgenC(uid)); - PrintAndLogEx(INFO, " XYZ | %08X | %04X", ul_ev1_pwdgenD(uid), ul_ev1_packgenD(uid)); - PrintAndLogEx(INFO, "------+----------+-----"); + PrintAndLogEx(INFO, " algo | pwd | pack"); + PrintAndLogEx(INFO, "----------------+----------+-----"); + PrintAndLogEx(INFO, " EV1 | %08X | %04X", ul_ev1_pwdgenA(uid), ul_ev1_packgenA(uid)); + PrintAndLogEx(INFO, " Amiibo | %08X | %04X", ul_ev1_pwdgenB(uid), ul_ev1_packgenB(uid)); + PrintAndLogEx(INFO, " Lego Dimension | %08X | %04X", ul_ev1_pwdgenC(uid), ul_ev1_packgenC(uid)); + PrintAndLogEx(INFO, " XYZ 3D printer | %08X | %04X", ul_ev1_pwdgenD(uid), ul_ev1_packgenD(uid)); + PrintAndLogEx(INFO, "----------------+----------+-----"); PrintAndLogEx(INFO, " Vingcard algo"); - PrintAndLogEx(INFO, "--------------------"); + PrintAndLogEx(INFO, "---------------------------------"); return PM3_SUCCESS; } From c299b102ee410261eb212277b16fcadcf1c6d454 Mon Sep 17 00:00:00 2001 From: Philippe Teuwen Date: Sat, 20 Feb 2021 00:30:27 +0100 Subject: [PATCH 31/58] recover_pk: flake8 --- tools/recover_pk.py | 112 +++++++++++++++++++++++--------------------- 1 file changed, 59 insertions(+), 53 deletions(-) diff --git a/tools/recover_pk.py b/tools/recover_pk.py index a268181f9..0310b4750 100755 --- a/tools/recover_pk.py +++ b/tools/recover_pk.py @@ -4,6 +4,7 @@ import binascii import sys +import hashlib debug = False @@ -15,9 +16,11 @@ debug = False # code snippets we needed: ####################################################################### # code snippets from JacobianCurve: -# This code is public domain. Everyone has the right to do whatever they want with it for any purpose. +# This code is public domain. Everyone has the right to do whatever +# they want with it for any purpose. # Copyright (c) 2013 Vitalik Buterin + class JacobianCurve: def __init__(self, p, n, a, b, g): self.p = p @@ -27,11 +30,9 @@ class JacobianCurve: self.g = g self.n_length = len(bin(self.n).replace("0b", "")) - def to_jacobian(self, p): return p[0], p[1], 1 - def jacobian_double(self, p): if not p[1]: return 0, 0, 0 @@ -43,7 +44,6 @@ class JacobianCurve: nz = (2 * p[1] * p[2]) % self.p return nx, ny, nz - def jacobian_add(self, p, q): if not p[1]: return q @@ -67,12 +67,10 @@ class JacobianCurve: nz = (h * p[2] * q[2]) % self.p return (nx, ny, nz) - def from_jacobian(self, p): z = inverse(p[2], self.p) return (p[0] * z ** 2) % self.p, (p[1] * z ** 3) % self.p - def jacobian_shamir(self, a, n, b, m): ab = self.jacobian_add(a, b) if n < 0 or n >= self.n: @@ -97,17 +95,15 @@ class JacobianCurve: return res def fast_shamir(self, a, n, b, m): - return self.from_jacobian(self.jacobian_shamir(self.to_jacobian(a), n, self.to_jacobian(b), m)) + return self.from_jacobian( + self.jacobian_shamir( + self.to_jacobian(a), n, self.to_jacobian(b), m)) ####################################################################### # code snippets from sslcrypto # MIT License # Copyright (c) 2019 Ivan Machugovskiy -import hmac -import os -import hashlib -import struct def int_to_bytes(raw, length): data = [] @@ -123,6 +119,7 @@ def bytes_to_int(data): raw = raw * 256 + byte return raw + def legendre(a, p): res = pow(a, (p - 1) // 2, p) if res == p - 1: @@ -130,6 +127,7 @@ def legendre(a, p): else: return res + def inverse(a, n): if a == 0: return 0 @@ -141,6 +139,7 @@ def inverse(a, n): lm, low, hm, high = nm, new, lm, low return lm % n + def square_root_mod_prime(n, p): if n == 0: return 0 @@ -186,8 +185,9 @@ def square_root_mod_prime(n, p): r = r * b % p return r -# name: (nid, p, n, a, b, (Gx, Gy)), + CURVES = { + # name: (nid, p, n, a, b, (Gx, Gy)), "secp128r1": ( 706, 0xFFFFFFFDFFFFFFFFFFFFFFFFFFFFFFFF, @@ -199,7 +199,6 @@ CURVES = { 0xCF5AC8395BAFEB13C02DA292DDED7A83 ) ), - # ! h=4, how to handle that? "secp128r2": ( 707, 0xFFFFFFFDFFFFFFFFFFFFFFFFFFFFFFFF, @@ -305,13 +304,14 @@ CURVES = { ) } + def get_curve(name): if name not in CURVES: raise ValueError("Unknown curve {}".format(name)) nid, p, n, a, b, g = CURVES[name] - params = {"p": p, "n": n, "a": a, "b": b, "g": g} return EllipticCurve(nid, p, n, a, b, g) + class EllipticCurve: def __init__(self, nid, p, n, a, b, g): self.p, self.n, self.a, self.b, self.g = p, n, a, b, g @@ -319,15 +319,12 @@ class EllipticCurve: self.public_key_length = (len(bin(p).replace("0b", "")) + 7) // 8 self.order_bitlength = len(bin(n).replace("0b", "")) - def _int_to_bytes(self, raw, len=None): return int_to_bytes(raw, len or self.public_key_length) - def _subject_to_int(self, subject): return bytes_to_int(subject[:(self.order_bitlength + 7) // 8]) - def recover(self, signature, data, hash="sha256"): # Sanity check: is this signature recoverable? if len(signature) != 1 + 2 * self.public_key_length: @@ -395,24 +392,26 @@ class EllipticCurve: ####################################################################### + def guess_curvename(signature): - l = (len(signature) // 2) & 0xfe - if l == 32 : - curves = [ "secp128r1", "secp128r2" ] - elif l == 48: - curves = [ "secp192k1", "secp192r1" ] - elif l == 56: - curves = [ "secp224k1", "secp224r1" ] - elif l == 64: - curves = [ "secp256k1", "secp256r1" ] - elif l == 96: - curves = [ "secp384r1" ] - elif l == 132: - curves = [ "secp521r1" ] + siglen = (len(signature) // 2) & 0xfe + if siglen == 32: + curves = ["secp128r1", "secp128r2"] + elif siglen == 48: + curves = ["secp192k1", "secp192r1"] + elif siglen == 56: + curves = ["secp224k1", "secp224r1"] + elif siglen == 64: + curves = ["secp256k1", "secp256r1"] + elif siglen == 96: + curves = ["secp384r1"] + elif siglen == 132: + curves = ["secp521r1"] else: raise ValueError("Unsupported signature size %i" % len(signature)) return curves + def recover(data, signature, curvename, alghash=None): recovered = set() curve = get_curve(curvename) @@ -423,7 +422,7 @@ def recover(data, signature, curvename, alghash=None): recovered.add(pk) if debug: print("Possible Pk: ", binascii.hexlify(pk)) - except: + except ValueError: pass else: for i in range(2): @@ -434,20 +433,23 @@ def recover(data, signature, curvename, alghash=None): recovered.add(pk) if debug: print("Possible Pk: ", binascii.hexlify(pk)) - except: + except ValueError: pass return recovered + def recover_multiple(uids, sigs, curvename, alghash=None): recovered = set() assert len(uids) == len(sigs) for i in range(len(uids)): data = binascii.unhexlify(uids[i]) if debug: - print("UID (%2i): " % len(data), binascii.hexlify(data)) + print("UID (%2i): " % + len(data), binascii.hexlify(data)) signature = binascii.unhexlify(sigs[i]) if debug: - print("Signature (%2i): " % len(signature), binascii.hexlify(signature)) + print("Signature (%2i): " % + len(signature), binascii.hexlify(signature)) recovered_tmp = recover(data, signature, curvename, alghash) if i == 0: if recovered_tmp == set(): @@ -458,60 +460,63 @@ def recover_multiple(uids, sigs, curvename, alghash=None): recovered &= recovered_tmp return recovered + def selftests(): tests = [ {'name': "Mifare Ultralight EV1", 'samples': ["04C1285A373080", "CEA2EB0B3C95D0844A95B824A7553703B3702378033BF0987899DB70151A19E7", "04C2285A373080", "A561506723D422D29ED9F93E60D20B9ED1E05CC1BF81DA19FE500CA0B81CC0ED"], - 'pk': "0490933BDCD6E99B4E255E3DA55389A827564E11718E017292FAF23226A96614B8" }, + 'pk': "0490933BDCD6E99B4E255E3DA55389A827564E11718E017292FAF23226A96614B8"}, {'name': "NTAG21x", 'samples': ["04E10CDA993C80", "8B76052EE42F5567BEB53238B3E3F9950707C0DCC956B5C5EFCFDB709B2D82B3", "04DB0BDA993C80", "6048EFD9417CD10F6B7F1818D471A7FE5B46868D2EABDC6307A1E0AAE139D8D0"], - 'pk': "04494E1A386D3D3CFE3DC10E5DE68A499B1C202DB5B132393E89ED19FE5BE8BC61" }, + 'pk': "04494E1A386D3D3CFE3DC10E5DE68A499B1C202DB5B132393E89ED19FE5BE8BC61"}, {'name': "Mifare Classic EV1", 'samples': ["0433619AB35780", "B9FAE369EC21C980650D87ED9AE9B1610E859131B4B8699C647548AB68D249BB", "524374E2", "F8758CE30A58553A9985C458FB9C7D340FCFB04847B928A0667939272BC58B5E", "53424B8A", "B4F533E8C06C021E242EFE8558C1672ED7022E5AE4E7AA2D46113B0AB6928AFC", "BD2A4146", "19505576ED327D8F8870C86B1ED00898BFEDFFF27CC82FC515BA2EEC26050873"], - 'pk': "044F6D3F294DEA5737F0F46FFEE88A356EED95695DD7E0C27A591E6F6F65962BAF" }, + 'pk': "044F6D3F294DEA5737F0F46FFEE88A356EED95695DD7E0C27A591E6F6F65962BAF"}, {'name': "DESFire Light", 'samples': ["0439556ACB6480", "D5BD0978106E1E38B513642335966AB21E9F950DCFCFAB45FF13D0DC3CA4C2AE7E0D671DF1240937D040DAC4601C5F66ED62C546EE03ED08", "043B156ACB6480", "76B46932BF2FCF4931A24C755F5CB1686B914F1856177686B864BDAD58EFA6A7493E5C2232F3ADDAA434EA4647BFD1D385BDA6115E77D74C"], - 'pk': "040E98E117AAA36457F43173DC920A8757267F44CE4EC5ADD3C54075571AEBBF7B942A9774A1D94AD02572427E5AE0A2DD36591B1FB34FCF3D" }, + 'pk': "040E98E117AAA36457F43173DC920A8757267F44CE4EC5ADD3C54075571AEBBF7B942A9774A1D94AD02572427E5AE0A2DD36591B1FB34FCF3D"}, {'name': "DESFire EV2", 'samples': ["042A41CAE45380", "B2769F8DDB575AEA2A680ADCA8FFED4FAB81A1E9908E2B82FE0FABB697BBD9B23835C416970E75768F12902ACA491349E94E6589EAF4F508", "045640CAE45380", "D34B53A8C2C100D700DEA1C4C0D0DE4409F3A418CD8D57C4F41F146E42AD9A55F014199ABBF5CA259C7799DB0AE20D5E77D4950AC7E95D33"], - 'pk': "04B304DC4C615F5326FE9383DDEC9AA892DF3A57FA7FFB3276192BC0EAA252ED45A865E3B093A3D0DCE5BE29E92F1392CE7DE321E3E5C52B3A" }, + 'pk': "04B304DC4C615F5326FE9383DDEC9AA892DF3A57FA7FFB3276192BC0EAA252ED45A865E3B093A3D0DCE5BE29E92F1392CE7DE321E3E5C52B3A"}, {'name': "DESFire EV3", 'samples': ["04448BD2DB6B80", "5CBB5632795C8F15263FEFB095B51C7B541AFD914A1AE44EF6FB8AF605EDF13DBFEE6C3A2DB372245E671DFE0D42CB1F0D0B8FE67A89D2F6", "04445DD2DB6B80", "166BFD9F9BFAA451172566101580DF9894F582C4A4E258C15037AD2F35A475CF1D7FB817618623A6569F991931AFB2766984E21A18512A6D"], - 'pk': "041DB46C145D0A36539C6544BD6D9B0AA62FF91EC48CBC6ABAE36E0089A46F0D08C8A715EA40A63313B92E90DDC1730230E0458A33276FB743" }, -# TODO one more Mifare Plus EV1... + 'pk': "041DB46C145D0A36539C6544BD6D9B0AA62FF91EC48CBC6ABAE36E0089A46F0D08C8A715EA40A63313B92E90DDC1730230E0458A33276FB743"}, {'name': "Mifare Plus EV1", + # TODO one more Mifare Plus EV1... 'samples': ["042A2B221C5080", "BAC40CD88E9193C58ADA5055350C4F648EB5A7AEC4FCF9BD4CDD7B1C558DE5F59C6636F26286ED48622AAA2331D4DF1CEE23B57B94BDA631"], - 'pk': "044409ADC42F91A8394066BA83D872FB1D16803734E911170412DDF8BAD1A4DADFD0416291AFE1C748253925DA39A5F39A1C557FFACD34C62E" }, + 'pk': "044409ADC42F91A8394066BA83D872FB1D16803734E911170412DDF8BAD1A4DADFD0416291AFE1C748253925DA39A5F39A1C557FFACD34C62E"}, {'name': "NTAG413DNA", 'samples': ["042468222F5C80", "B9211E320F321BD1D0E158E10FF15109B389638BAE15D9909D7725BF1250ED236D66F1AF75C94D60330E4E92535F5E6997675281A5687173", "042938222F5C80", "18B642797D1FD71806146A7A6EC778D3FDD04F39C4A3B36A592BD1A114DC44E5528380FA766C0B7EA32B284AFBE84300B620369F0686D8CC"], - 'pk': "04bb5d514f7050025c7d0f397310360eec91eaf792e96fc7e0f496cb4e669d414f877b7b27901fe67c2e3b33cd39d1c797715189ac951c2add" }, + 'pk': "04bb5d514f7050025c7d0f397310360eec91eaf792e96fc7e0f496cb4e669d414f877b7b27901fe67c2e3b33cd39d1c797715189ac951c2add"}, {'name': "NTAG424DNA", 'samples': ["0463474AA26A80", "27E9A50E6CA4BA9037C02F7D20A80D0284D0C1D83C67F5A5AC1D8A4EF86C9508417E4E9C6F85AA7920F0ABDED984CAF20467D66EA54BBF08", "04C46C222A6380", "344A806EBF704C05C19215D2F840529CE365AAD2D08A469A95896D75D477D9FAB02A0C827E9F215BD8EB0E56A3A9A008FB75D706AABBD4DA"], - 'pk': "048A9B380AF2EE1B98DC417FECC263F8449C7625CECE82D9B916C992DA209D68422B81EC20B65A66B5102A61596AF3379200599316A00A1410" }, + 'pk': "048A9B380AF2EE1B98DC417FECC263F8449C7625CECE82D9B916C992DA209D68422B81EC20B65A66B5102A61596AF3379200599316A00A1410"}, {'name': "Vivokey Spark1", -# ! tag signature bytes output by pm3 must be read right to left: echo $sig |sed 's/\(..\)/\1\n/g'|tac|tr -d '\n' (and it uses a SHA256) + # ! tag signature bytes output by pm3 must be read right to left: + # echo $sig |sed 's/\(..\)/\1\n/g'|tac|tr -d '\n' + # (and it uses a SHA256) 'samples': ["E0040118009C870C", "4B4E03E1211952EF6A5F9D84AB218CD4D7549D0CDF8CA8779F9AD16C9A9CBF3B", "E0040118009B4D62", "25CF13747C3389EC7889DE916E3747584978511CC78B51CFB1883B494CBED7AB"], - 'pk': "04d64bb732c0d214e7ec580736acf847284b502c25c0f7f2fa86aace1dada4387a" }, -# ! tag UID is considered inversed: E0040118009B5FEE => EE5F9B00180104E0 -# TODO one more ICODE-DNA... + 'pk': "04d64bb732c0d214e7ec580736acf847284b502c25c0f7f2fa86aace1dada4387a"}, {'name': "ICODE DNA, ICODE SLIX2", + # ! tag UID is considered inverted: E0040118009B5FEE => EE5F9B00180104E0 + # TODO one more ICODE-DNA... 'samples': ["EE5F9B00180104E0", "32D9E7579CD77E6F1FA11419231E874826984C5F189FDE1421684563A9663377"], - 'pk': "048878A2A2D3EEC336B4F261A082BD71F9BE11C4E2E896648B32EFA59CEA6E59F0" }, -# uses secp256r1?, SHA-256, -# {'name': "Minecraft Earth", -# 'samples': ["aa", "DF0E506DFF8FCFC4B7B979D917644445F1230D2C7CDC342AFA842CA240C210BE7275F62073A9670F2DCEFC602CBEE771C2B4CD4A04F3D1EA11F49ABDF7E8B721"], -# 'pk': "" }, + 'pk': "048878A2A2D3EEC336B4F261A082BD71F9BE11C4E2E896648B32EFA59CEA6E59F0"}, + # {'name': "Minecraft Earth", + # # uses secp256r1?, SHA-256, + # 'samples': ["aa", "DF0E506DFF8FCFC4B7B979D917644445F1230D2C7CDC342AFA842CA240C210BE7275F62073A9670F2DCEFC602CBEE771C2B4CD4A04F3D1EA11F49ABDF7E8B721"], + # 'pk': ""}, ] succeeded = True for t in tests: @@ -541,6 +546,7 @@ def selftests(): print("[FAIL]") print("Tests: [%s]" % ["FAIL", "OK"][succeeded]) + if __name__ == "__main__": if len(sys.argv) == 2 and sys.argv[1] == "selftests": selftests() From e13108023a2b5c3c1bb6c764d8bff83eaf0c606f Mon Sep 17 00:00:00 2001 From: iceman1001 Date: Sat, 20 Feb 2021 08:36:33 +0100 Subject: [PATCH 32/58] adapt lua script to handle PS odd 32b limit, my best guess the WIN32 macro is set. --- client/luascripts/lf_em4100_bulk.lua | 37 ++++++++++++++-------------- 1 file changed, 19 insertions(+), 18 deletions(-) diff --git a/client/luascripts/lf_em4100_bulk.lua b/client/luascripts/lf_em4100_bulk.lua index 30aaa98fc..d1f4aa845 100644 --- a/client/luascripts/lf_em4100_bulk.lua +++ b/client/luascripts/lf_em4100_bulk.lua @@ -4,7 +4,7 @@ local ac = require('ansicolors') copyright = '' author = "Christian Herrmann" -version = 'v1.0.0' +version = 'v1.0.1' desc = [[ Perform bulk EM410x enrollment of T5577 RFID tags. It keeps track of last card id used. If called with -s, this value resets "session". @@ -84,20 +84,21 @@ local function readfile() end local t = f:read("*all") f:close() - local cn = tonumber(t, 16) - print(('Using EM4100 ID '..ac.green..'%010X'..ac.reset..' from `'..ac.yellow..'%s'..ac.reset..'`'):format(cn, ENROLL_STATUS_FN)) - return cn + local cn_hi = tonumber(t:sub(1, 2), 16) + local cn_low = tonumber(t:sub(3, 10), 16) + print(('Using EM4100 ID '..ac.green..'%02X%08X'..ac.reset..' from `'..ac.yellow..'%s'..ac.reset..'`'):format(cn_hi, cn_low, ENROLL_STATUS_FN)) + return cn_hi, cn_low end --- -- -local function writefile(cn) +local function writefile(cn_hi, cn_low) local f = io.open(ENROLL_STATUS_FN, "w") if f == nil then return nil, string.format("Could not write to file %s", ENROLL_STATUS_FN) end - f:write(("%010X\n"):format(cn)) + f:write(("%02X%08X\n"):format(cn_hi, cn_low)) f:close() - print(('Wrote EM4100 ID '..ac.green..'%010X'..ac.reset..' to `'..ac.yellow..'%s'..ac.reset..'`'):format(cn, ENROLL_STATUS_FN)) + print(('Wrote EM4100 ID '..ac.green..'%02X%08X'..ac.reset..' to `'..ac.yellow..'%s'..ac.reset..'`'):format(cn_hi, cn_low, ENROLL_STATUS_FN)) return true, 'Ok' end @@ -134,32 +135,32 @@ local function main(args) core.console('pref set hint --off') print('') - local sid = tonumber(startid, 16) + local hi = tonumber(startid:sub(1, 2), 16) + local low = tonumber(startid:sub(3, 10), 16) + if shall_continue then print('Continue enrolling from last save') - sid = readfile() + hi, low = readfile() else print('reset & starting enrolling from refresh') end - local template = 'EM4100 ID '..ac.green..'%010X'..ac.reset - local curr = sid - for i = sid, sid + 10000, 1 do - curr = i - + local template = 'EM4100 ID '..ac.green..'%02X%08X'..ac.reset + for i = low, low + 10000, 1 do print('') print( string.rep('--',20) ) - local msg = (template):format(curr) + local msg = (template):format(hi, i) local ans = utils.input(msg, 'y'):lower() if ans == 'y' then - core.console( ('lf em 410x clone --id %010X'):format(curr) ) - -- print ( ('lf em 410x clone --id %010X'):format(curr) ) + core.console( ('lf em 410x clone --id %02X%08X'):format(hi, i) ) + -- print ( ('lf em 410x clone --id %02X%08X'):format(hi, i) ) else print(ac.red..'User aborted'..ac.reset) + low = i break end end - writefile(curr) + writefile(hi, low) print('enabling hints again') core.console('pref set hint --on') From 602c9d15425447d854f9154de89d7b3a6fc99629 Mon Sep 17 00:00:00 2001 From: iceman1001 Date: Sat, 20 Feb 2021 13:04:58 +0100 Subject: [PATCH 33/58] added some default generators --- common/generator.c | 7 +++++++ common/generator.h | 2 ++ 2 files changed, 9 insertions(+) diff --git a/common/generator.c b/common/generator.c index 85be456f4..5918ce7c8 100644 --- a/common/generator.c +++ b/common/generator.c @@ -182,6 +182,13 @@ uint16_t ul_ev1_packgenD(uint8_t *uid) { return BSWAP_16(p & 0xFFFF); } +uint32_t ul_ev1_pwdgen_def(uint8_t *uid) { + return 0xFFFFFFFF; +} +uint16_t ul_ev1_packgen_def(uint8_t *uid) { + return 0x0000; +} + //------------------------------------ // MFC key generation stuff // Each algo implementation should offer two key generation functions. diff --git a/common/generator.h b/common/generator.h index e0c045426..5467ed470 100644 --- a/common/generator.h +++ b/common/generator.h @@ -13,11 +13,13 @@ #include "common.h" +uint32_t ul_ev1_pwdgen_def(uint8_t *uid); uint32_t ul_ev1_pwdgenA(uint8_t *uid); uint32_t ul_ev1_pwdgenB(uint8_t *uid); uint32_t ul_ev1_pwdgenC(uint8_t *uid); uint32_t ul_ev1_pwdgenD(uint8_t *uid); +uint16_t ul_ev1_packgen_def(uint8_t *uid); uint16_t ul_ev1_packgenA(uint8_t *uid); uint16_t ul_ev1_packgenB(uint8_t *uid); uint16_t ul_ev1_packgenC(uint8_t *uid); From de42d3c55ecca91e5c4722ac20f53ad798e7e7a5 Mon Sep 17 00:00:00 2001 From: iceman1001 Date: Sat, 20 Feb 2021 13:06:01 +0100 Subject: [PATCH 34/58] hf mfu info - adapted the fingerprinting --- client/src/cmdhfmfu.c | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/client/src/cmdhfmfu.c b/client/src/cmdhfmfu.c index 3c974e743..8227a55c0 100644 --- a/client/src/cmdhfmfu.c +++ b/client/src/cmdhfmfu.c @@ -1037,7 +1037,7 @@ static mfu_identify_t mfu_ident_table[] = { { "Jooki", "0004040201000F03", 12, 32, "E11012000103A00C340329D101255504732E6A6F6F6B692E726F636B732F732F", - NULL, NULL, + ul_ev1_pwdgen_def, ul_ev1_packgen_def, "hf jooki decode -r" }, { @@ -1046,6 +1046,24 @@ static mfu_identify_t mfu_ident_table[] = { ul_ev1_pwdgenC, ul_ev1_packgenC, "hf mfu dump -k %08x" }, + { + "Hotwheels", "0004040201000F03", + 9, 9, "E110120F", + ul_ev1_pwdgen_def, ul_ev1_packgen_def, + "hf mfu dump -k %08x" + }, + { + "Minecraft Earth", "0004040201000F03", + 9, 26, "48F6FFE1101200037C91012C55027069642E6D617474656C2F4167", + ul_ev1_pwdgen_def, ul_ev1_packgen_def, + "hf mfu dump -k %08x" + }, + { + "Snackworld", "0004040101000B03", + 9, 7, "483000E1100600", + NULL, NULL, + "hf mfu dump -k %08x" + }, { "Amiibo", "0004040201001103", 9, 9, "480FE0F110FFEEA500", From 71b73cad0fc6ae426a31d9c04b374c5d689dba6e Mon Sep 17 00:00:00 2001 From: Ave Date: Sat, 20 Feb 2021 22:28:03 +0300 Subject: [PATCH 35/58] emrtd: add a PACE display to hf emrtd info Also reword things so that they don't misuse BAC in place of any form of passive authentication --- client/src/cmdhfemrtd.c | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/client/src/cmdhfemrtd.c b/client/src/cmdhfemrtd.c index 229f84dee..882d43bae 100644 --- a/client/src/cmdhfemrtd.c +++ b/client/src/cmdhfemrtd.c @@ -992,7 +992,7 @@ 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, dg_table[EF_COM].fileid, *use_14b) == false) { *BAC = true; - PrintAndLogEx(INFO, "Basic Access Control is enforced. Will attempt external authentication."); + PrintAndLogEx(INFO, "Authentication is enforced. Will attempt external authentication."); } else { *BAC = false; // Select EF_DG1 @@ -1000,7 +1000,7 @@ static bool emrtd_do_auth(char *documentnumber, char *dob, char *expiry, bool BA 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."); + PrintAndLogEx(INFO, "Authentication is enforced. Will attempt external authentication."); } else { *BAC = false; } @@ -1010,7 +1010,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 supply MRZ data. Cannot proceed."); + PrintAndLogEx(ERR, "This eMRTD enforces authentication, but you didn't supply MRZ data. Cannot proceed."); PrintAndLogEx(HINT, "Check out hf emrtd info/dump --help, supply data with -n -d and -e."); return false; } @@ -1733,6 +1733,7 @@ int infoHF_EMRTD(char *documentnumber, char *dob, char *expiry, bool BAC_availab uint8_t ks_enc[16] = { 0x00 }; uint8_t ks_mac[16] = { 0x00 }; bool BAC = false; + bool PACE_available = true; bool use_14b = false; // Select the eMRTD @@ -1741,13 +1742,20 @@ int infoHF_EMRTD(char *documentnumber, char *dob, char *expiry, bool BAC_availab return PM3_ESOFT; } + // Read EF_CardAccess + if (!emrtd_select_and_read(response, &resplen, dg_table[EF_CardAccess].fileid, ks_enc, ks_mac, ssc, BAC, use_14b)) { + PACE_available = false; + PrintAndLogEx(HINT, "The error above this is normal. It just means that your eMRTD lacks PACE."); + } + // 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........: %s", BAC ? _GREEN_("Enforced") : _RED_("Not enforced")); + PrintAndLogEx(SUCCESS, "PACE..................: %s", PACE_available ? _GREEN_("Available") : _YELLOW_("Not available")); PrintAndLogEx(SUCCESS, "Authentication result.: %s", auth_result ? _GREEN_("Successful") : _RED_("Failed")); if (!auth_result) { @@ -1755,6 +1763,7 @@ int infoHF_EMRTD(char *documentnumber, char *dob, char *expiry, bool BAC_availab return PM3_ESOFT; } + // Read EF_COM to get file list 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(); @@ -1776,7 +1785,7 @@ int infoHF_EMRTD(char *documentnumber, char *dob, char *expiry, bool BAC_availab return PM3_ESOFT; } - // Grab the hash list + // Grab the hash list from EF_SOD uint8_t dg_hashes_sod[17][64] = { { 0 } }; uint8_t dg_hashes_calc[17][64] = { { 0 } }; int hash_algo = 0; From 4a738963b3e97103186d83b312773305fb045938 Mon Sep 17 00:00:00 2001 From: Ave Date: Sat, 20 Feb 2021 22:35:31 +0000 Subject: [PATCH 36/58] lf t55: Fix typos --- client/src/cmdlft55xx.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/client/src/cmdlft55xx.c b/client/src/cmdlft55xx.c index 46ef31744..1c3993454 100644 --- a/client/src/cmdlft55xx.c +++ b/client/src/cmdlft55xx.c @@ -3869,8 +3869,8 @@ static int CmdT55xxSniff(const char *Cmd) { "Sniff LF t55xx based trafic and decode possible cmd / blocks.\n" "Lower tolerance means tighter pulses. ", "lf t55xx sniff\n" - "lf t55xx sniff -1 -t 2 -> use buffer with tolernace of 2\n" - "lf t55xx sniff -1 --zero 7 --one 14 -> use buffer, zero pulse width 7, one pulse width 15" + "lf t55xx sniff -1 -t 2 -> use buffer with tolerance of 2\n" + "lf t55xx sniff -1 --zero 7 --one 14 -> use buffer, zero pulse width 7, one pulse width 15" ); void *argtable[] = { From 0f1ba33b6931d051a987c2b47c399aa89c0414e5 Mon Sep 17 00:00:00 2001 From: Ave Date: Sun, 21 Feb 2021 01:43:59 +0300 Subject: [PATCH 37/58] emrtd: Add PACE algo detection --- client/src/cmdhfemrtd.c | 99 ++++++++++++++++++++++++++++++++--------- client/src/cmdhfemrtd.h | 6 +++ 2 files changed, 84 insertions(+), 21 deletions(-) diff --git a/client/src/cmdhfemrtd.c b/client/src/cmdhfemrtd.c index 882d43bae..4621a3b39 100644 --- a/client/src/cmdhfemrtd.c +++ b/client/src/cmdhfemrtd.c @@ -58,6 +58,7 @@ 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_cardaccess_info(uint8_t *data, size_t datalen); typedef enum { // list must match dg_table EF_COM = 0, @@ -83,27 +84,27 @@ typedef enum { // list must match dg_table } emrtd_dg_enum; static emrtd_dg_t dg_table[] = { -// 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}, +// 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, emrtd_print_ef_cardaccess_info, 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} }; @@ -117,6 +118,27 @@ static emrtd_hashalg_t hashalg_table[] = { {NULL, NULL, 0, 0, {}} }; +static emrtd_pacealg_t pacealg_table[] = { +// name keygen descriptor + {"DH, Generic Mapping, 3DES-CBC-CBC", NULL, {0x04, 0x00, 0x7F, 0x00, 0x07, 0x02, 0x02, 0x04, 0x01, 0x01}}, + {"DH, Generic Mapping, AES-CMAC-128", NULL, {0x04, 0x00, 0x7F, 0x00, 0x07, 0x02, 0x02, 0x04, 0x01, 0x02}}, + {"DH, Generic Mapping, AES-CMAC-192", NULL, {0x04, 0x00, 0x7F, 0x00, 0x07, 0x02, 0x02, 0x04, 0x01, 0x03}}, + {"DH, Generic Mapping, AES-CMAC-256", NULL, {0x04, 0x00, 0x7F, 0x00, 0x07, 0x02, 0x02, 0x04, 0x01, 0x04}}, + {"ECDH, Generic Mapping, 3DES-CBC-CBC", NULL, {0x04, 0x00, 0x7F, 0x00, 0x07, 0x02, 0x02, 0x04, 0x02, 0x01}}, + {"ECDH, Generic Mapping, AES-CMAC-128", NULL, {0x04, 0x00, 0x7F, 0x00, 0x07, 0x02, 0x02, 0x04, 0x02, 0x02}}, + {"ECDH, Generic Mapping, AES-CMAC-192", NULL, {0x04, 0x00, 0x7F, 0x00, 0x07, 0x02, 0x02, 0x04, 0x02, 0x03}}, + {"ECDH, Generic Mapping, AES-CMAC-256", NULL, {0x04, 0x00, 0x7F, 0x00, 0x07, 0x02, 0x02, 0x04, 0x02, 0x04}}, + {"DH, Integrated Mapping, 3DES-CBC-CBC", NULL, {0x04, 0x00, 0x7F, 0x00, 0x07, 0x02, 0x02, 0x04, 0x03, 0x01}}, + {"DH, Integrated Mapping, AES-CMAC-128", NULL, {0x04, 0x00, 0x7F, 0x00, 0x07, 0x02, 0x02, 0x04, 0x03, 0x02}}, + {"DH, Integrated Mapping, AES-CMAC-192", NULL, {0x04, 0x00, 0x7F, 0x00, 0x07, 0x02, 0x02, 0x04, 0x03, 0x03}}, + {"DH, Integrated Mapping, AES-CMAC-256", NULL, {0x04, 0x00, 0x7F, 0x00, 0x07, 0x02, 0x02, 0x04, 0x03, 0x04}}, + {"ECDH, Integrated Mapping, 3DES-CBC-CBC", NULL, {0x04, 0x00, 0x7F, 0x00, 0x07, 0x02, 0x02, 0x04, 0x04, 0x01}}, + {"ECDH, Integrated Mapping, AES-CMAC-128", NULL, {0x04, 0x00, 0x7F, 0x00, 0x07, 0x02, 0x02, 0x04, 0x04, 0x02}}, + {"ECDH, Integrated Mapping, AES-CMAC-192", NULL, {0x04, 0x00, 0x7F, 0x00, 0x07, 0x02, 0x02, 0x04, 0x04, 0x03}}, + {"ECDH, Integrated Mapping, AES-CMAC-256", NULL, {0x04, 0x00, 0x7F, 0x00, 0x07, 0x02, 0x02, 0x04, 0x04, 0x04}}, + {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) { @@ -1726,6 +1748,37 @@ static int emrtd_print_ef_sod_info(uint8_t *dg_hashes_calc, uint8_t *dg_hashes_s return PM3_SUCCESS; } +static int emrtd_print_ef_cardaccess_info(uint8_t *data, size_t datalen) { + uint8_t dataset[100] = { 0x00 }; + size_t datasetlen = 0; + uint8_t pacealgorithm[100] = { 0x00 }; + size_t pacealgorithmlen = 0; + + PrintAndLogEx(NORMAL, ""); + PrintAndLogEx(INFO, "----------------- " _CYAN_("EF_CardAccess") " ----------------"); + + if (!emrtd_lds_get_data_by_tag(data, datalen, dataset, &datasetlen, 0x30, 0x00, false, true, 0)) { + PrintAndLogEx(ERR, "Failed to read set from EF_CardAccess."); + return PM3_ESOFT; + } + + if (!emrtd_lds_get_data_by_tag(dataset, datasetlen, pacealgorithm, &pacealgorithmlen, 0x06, 0x00, false, false, 0)) { + PrintAndLogEx(ERR, "Failed to read PACE algorithm from EF_CardAccess."); + return PM3_ESOFT; + } + + for (int pacei = 0; pacealg_table[pacei].name != NULL; pacei++) { + PrintAndLogEx(DEBUG, "Trying: %s", hashalg_table[pacei].name); + + if (memcmp(pacealg_table[pacei].descriptor, pacealgorithm, pacealgorithmlen) == 0) { + PrintAndLogEx(SUCCESS, "PACE algorithm........: " _YELLOW_("%s"), pacealg_table[pacei].name); + 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 }; int resplen = 0; @@ -1758,6 +1811,10 @@ int infoHF_EMRTD(char *documentnumber, char *dob, char *expiry, bool BAC_availab PrintAndLogEx(SUCCESS, "PACE..................: %s", PACE_available ? _GREEN_("Available") : _YELLOW_("Not available")); PrintAndLogEx(SUCCESS, "Authentication result.: %s", auth_result ? _GREEN_("Successful") : _RED_("Failed")); + if (PACE_available) { + emrtd_print_ef_cardaccess_info(response, resplen); + } + if (!auth_result) { DropField(); return PM3_ESOFT; diff --git a/client/src/cmdhfemrtd.h b/client/src/cmdhfemrtd.h index bb32fb53d..afa814f0a 100644 --- a/client/src/cmdhfemrtd.h +++ b/client/src/cmdhfemrtd.h @@ -35,6 +35,12 @@ typedef struct emrtd_hashalg_s { const uint8_t descriptor[15]; } emrtd_hashalg_t; +typedef struct emrtd_pacealg_s { + const char *name; + int (*keygenerator)(uint8_t *datain, int datainlen, uint8_t *dataout); + const uint8_t descriptor[10]; +} emrtd_pacealg_t; + int CmdHFeMRTD(const char *Cmd); int dumpHF_EMRTD(char *documentnumber, char *dob, char *expiry, bool BAC_available, const char *path); From dd62a9f8dd1ca0eca6d1aee25cbb0906af425a05 Mon Sep 17 00:00:00 2001 From: Ave Date: Sun, 21 Feb 2021 02:18:10 +0300 Subject: [PATCH 38/58] emrtd: Parse some other parts of EF_CardAccess --- client/src/cmdhfemrtd.c | 56 +++++++++++++++++++++++++++++++++++++---- client/src/cmdhfemrtd.h | 7 ++++++ 2 files changed, 58 insertions(+), 5 deletions(-) diff --git a/client/src/cmdhfemrtd.c b/client/src/cmdhfemrtd.c index 4621a3b39..18040bc2e 100644 --- a/client/src/cmdhfemrtd.c +++ b/client/src/cmdhfemrtd.c @@ -139,6 +139,25 @@ static emrtd_pacealg_t pacealg_table[] = { {NULL, NULL, {}} }; +static emrtd_pacesdp_t pacesdp_table[] = { +// id name size + {0, "1024-bit MODP Group with 160-bit Prime Order Subgroup", 1024}, + {1, "2048-bit MODP Group with 224-bit Prime Order Subgroup", 2048}, + {2, "2048-bit MODP Group with 256-bit Prime Order Subgroup", 2048}, + {8, "NIST P-192 (secp192r1)", 192}, + {10, "NIST P-224 (secp224r1)", 224}, + {12, "NIST P-256 (secp256r1)", 256}, + {15, "NIST P-384 (secp384r1)", 384}, + {18, "NIST P-521 (secp521r1)", 521}, + {9, "BrainpoolP192r1", 192}, + {11, "BrainpoolP224r1", 224}, + {13, "BrainpoolP256r1", 256}, + {14, "BrainpoolP320r1", 320}, + {16, "BrainpoolP384r1", 384}, + {17, "BrainpoolP521r1", 521}, + {32, NULL, 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) { @@ -1751,8 +1770,9 @@ static int emrtd_print_ef_sod_info(uint8_t *dg_hashes_calc, uint8_t *dg_hashes_s static int emrtd_print_ef_cardaccess_info(uint8_t *data, size_t datalen) { uint8_t dataset[100] = { 0x00 }; size_t datasetlen = 0; - uint8_t pacealgorithm[100] = { 0x00 }; - size_t pacealgorithmlen = 0; + uint8_t datafromtag[100] = { 0x00 }; + size_t datafromtaglen = 0; + uint8_t parsednum = 0; PrintAndLogEx(NORMAL, ""); PrintAndLogEx(INFO, "----------------- " _CYAN_("EF_CardAccess") " ----------------"); @@ -1762,7 +1782,17 @@ static int emrtd_print_ef_cardaccess_info(uint8_t *data, size_t datalen) { return PM3_ESOFT; } - if (!emrtd_lds_get_data_by_tag(dataset, datasetlen, pacealgorithm, &pacealgorithmlen, 0x06, 0x00, false, false, 0)) { + // Get PACE version + if (!emrtd_lds_get_data_by_tag(dataset, datasetlen, datafromtag, &datafromtaglen, 0x02, 0x00, false, false, 0)) { + PrintAndLogEx(ERR, "Failed to read PACE version from EF_CardAccess."); + return PM3_ESOFT; + } + // TODO: hack!!! + memcpy(&parsednum, datafromtag, datafromtaglen); + PrintAndLogEx(SUCCESS, "PACE version..........: " _YELLOW_("%i"), parsednum); + + // Get PACE algorithm + if (!emrtd_lds_get_data_by_tag(dataset, datasetlen, datafromtag, &datafromtaglen, 0x06, 0x00, false, false, 0)) { PrintAndLogEx(ERR, "Failed to read PACE algorithm from EF_CardAccess."); return PM3_ESOFT; } @@ -1770,12 +1800,28 @@ static int emrtd_print_ef_cardaccess_info(uint8_t *data, size_t datalen) { for (int pacei = 0; pacealg_table[pacei].name != NULL; pacei++) { PrintAndLogEx(DEBUG, "Trying: %s", hashalg_table[pacei].name); - if (memcmp(pacealg_table[pacei].descriptor, pacealgorithm, pacealgorithmlen) == 0) { + if (memcmp(pacealg_table[pacei].descriptor, datafromtag, datafromtaglen) == 0) { PrintAndLogEx(SUCCESS, "PACE algorithm........: " _YELLOW_("%s"), pacealg_table[pacei].name); - return PM3_SUCCESS; } } + // Get PACE parameter ID + if (!emrtd_lds_get_data_by_tag(dataset, datasetlen, datafromtag, &datafromtaglen, 0x02, 0x00, false, false, 1)) { + PrintAndLogEx(ERR, "Failed to read PACE parameter ID from EF_CardAccess."); + return PM3_ESOFT; + } + + // TODO: hack!!! + memcpy(&parsednum, datafromtag, datafromtaglen); + for (int pacepari = 0; pacesdp_table[pacepari].id != 32; pacepari++) { + PrintAndLogEx(DEBUG, "Trying: %s", hashalg_table[pacepari].name); + + if (pacesdp_table[pacepari].id == parsednum) { + PrintAndLogEx(SUCCESS, "PACE parameter........: " _YELLOW_("%s"), pacesdp_table[pacepari].name); + } + // TODO: account for RFU + } + return PM3_SUCCESS; } diff --git a/client/src/cmdhfemrtd.h b/client/src/cmdhfemrtd.h index afa814f0a..35429a568 100644 --- a/client/src/cmdhfemrtd.h +++ b/client/src/cmdhfemrtd.h @@ -41,6 +41,13 @@ typedef struct emrtd_pacealg_s { const uint8_t descriptor[10]; } emrtd_pacealg_t; +// Standardized Domain Parameters +typedef struct emrtd_pacesdp_s { + uint8_t id; + const char *name; + size_t size; +} emrtd_pacesdp_t; + int CmdHFeMRTD(const char *Cmd); int dumpHF_EMRTD(char *documentnumber, char *dob, char *expiry, bool BAC_available, const char *path); From 9cefece2a7342d7ee606e9710102ba05e8129a7e Mon Sep 17 00:00:00 2001 From: iceman1001 Date: Sun, 21 Feb 2021 00:42:52 +0100 Subject: [PATCH 39/58] defaults --- client/dictionaries/t55xx_default_pwds.dic | 2 ++ 1 file changed, 2 insertions(+) diff --git a/client/dictionaries/t55xx_default_pwds.dic b/client/dictionaries/t55xx_default_pwds.dic index 348c79e0d..eaff04048 100644 --- a/client/dictionaries/t55xx_default_pwds.dic +++ b/client/dictionaries/t55xx_default_pwds.dic @@ -27,6 +27,8 @@ A5B4C3D2 00434343 44B44CAE 88661858 +# MKF fobs +E9920427 # paxton bullit? 575F4F4B # From 8904162d7a04d18d872c6ca9b32841e16063736c Mon Sep 17 00:00:00 2001 From: Ave Date: Sun, 21 Feb 2021 03:15:26 +0300 Subject: [PATCH 40/58] emrtd: Add EF_CardAccess parsing to offline info --- client/src/cmdhfemrtd.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/client/src/cmdhfemrtd.c b/client/src/cmdhfemrtd.c index 18040bc2e..4b4a895eb 100644 --- a/client/src/cmdhfemrtd.c +++ b/client/src/cmdhfemrtd.c @@ -1972,6 +1972,16 @@ int infoHF_EMRTD_offline(const char *path) { uint8_t dg_hashes_calc[17][64] = { { 0 } }; int hash_algo = 0; + strcpy(filepath, path); + strncat(filepath, PATHSEP, 2); + strcat(filepath, dg_table[EF_CardAccess].filename); + + if (loadFile_safeEx(filepath, ".BIN", (void **)&data, (size_t *)&datalen, false) == PM3_SUCCESS) { + emrtd_print_ef_cardaccess_info(data, datalen); + } else { + PrintAndLogEx(HINT, "The error above this is normal. It just means that your eMRTD lacks PACE."); + } + strcpy(filepath, path); strncat(filepath, PATHSEP, 2); strcat(filepath, dg_table[EF_SOD].filename); From 3a6c06e998568801d747a78f64094b317749bf45 Mon Sep 17 00:00:00 2001 From: Ave Date: Sun, 21 Feb 2021 00:27:18 +0000 Subject: [PATCH 41/58] changelog: Add hf emrtd info changes --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index ab629c19e..c05e5a084 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 parsing of EF_CardAccess to display PACE algorithm, version and parameter in `hf emrtd info` (@aveao) - Change, numerous commands more uses cliparser (@tcprst, @iceman1001) - Added more originality public keys (@anon) - Added `hf 14a info` - now also verify MFC Ev1 signatures (@iceman1001) From 0073fc1a71105078547b29bb78e7c0ed771d61ca Mon Sep 17 00:00:00 2001 From: iceman1001 Date: Sun, 21 Feb 2021 10:46:39 +0100 Subject: [PATCH 42/58] Modified the flashing feedback text to include suggest steps --- client/src/flash.c | 11 +++++++++++ client/src/proxmark3.c | 4 +++- 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/client/src/flash.c b/client/src/flash.c index 1541b8d17..9693d8803 100644 --- a/client/src/flash.c +++ b/client/src/flash.c @@ -403,9 +403,19 @@ static int wait_for_ack(PacketResponseNG *ack) { return PM3_SUCCESS; } +static bool g_printed_msg = false; static void flash_suggest_update_bootloader(void) { + if (g_printed_msg) + return; + PrintAndLogEx(ERR, _RED_("It is recommended that you first" _YELLOW_(" update your bootloader") _RED_(" alone,"))); PrintAndLogEx(ERR, _RED_("reboot the Proxmark3 then only update the main firmware") "\n"); + PrintAndLogEx(ERR, "Follow these steps :"); + PrintAndLogEx(ERR, " 1) ./pm3-flash-bootrom"); + PrintAndLogEx(ERR, " 2) ./pm3-flash-flash-all"); + PrintAndLogEx(ERR, " 3) ./pm3"); + PrintAndLogEx(INFO, "--------------------------------------------------------"); + g_printed_msg = true; } static void flash_suggest_update_flasher(void) { @@ -532,6 +542,7 @@ const char ice[] = " !!: :!! !!: !!: !!: !!: !!! !!: !!!\n : :: :: : : :: ::: : : : : : :: : \n" _RED_(" . .. .. . . .. ... . . . . . .. . ") "\n...................................................................\n" + "...................................................................\n" ; // Write a file's segments to Flash diff --git a/client/src/proxmark3.c b/client/src/proxmark3.c index a1e4761c7..3d92b8d00 100644 --- a/client/src/proxmark3.c +++ b/client/src/proxmark3.c @@ -673,6 +673,8 @@ static int flash_pm3(char *serial_port_name, uint8_t num_files, char *filenames[ } finish: + if (ret != PM3_SUCCESS) + PrintAndLogEx(INFO, "The flashing procedure failed, follow the suggested steps!"); ret = flash_stop_flashing(); CloseProxmark(session.current_device); finish2: @@ -684,7 +686,7 @@ finish2: PrintAndLogEx(SUCCESS, _CYAN_("All done")); else PrintAndLogEx(ERR, "Aborted on error"); - PrintAndLogEx(NORMAL, "\nHave a nice day!"); + PrintAndLogEx(INFO, "\nHave a nice day!"); return ret; } #endif //LIBPM3 From fad29cb7553b949084e38c48639973faba038a86 Mon Sep 17 00:00:00 2001 From: iceman1001 Date: Sun, 21 Feb 2021 11:04:15 +0100 Subject: [PATCH 43/58] only look if no key is applied --- client/src/cmdhficlass.c | 55 ++++++++++++++++++++++++---------------- 1 file changed, 33 insertions(+), 22 deletions(-) diff --git a/client/src/cmdhficlass.c b/client/src/cmdhficlass.c index 45268b4da..716e03436 100644 --- a/client/src/cmdhficlass.c +++ b/client/src/cmdhficlass.c @@ -940,22 +940,27 @@ static int CmdHFiClassDecrypt(const char *Cmd) { } bool verbose = arg_get_lit(clictx, 4); - CLIParserFree(clictx); - size_t keylen = 0; uint8_t dec_data[8] = {0}; - - bool use_sc = IsCryptoHelperPresent(verbose); - - if (have_key == false && use_sc == false) { - int res = loadFile_safe(ICLASS_DECRYPTION_BIN, "", (void **)&keyptr, &keylen); - if (res != PM3_SUCCESS) { - PrintAndLogEx(INFO, "Couldn't find any decryption methods"); - return PM3_EINVARG; + bool use_sc = false; + if (have_key == false) { + use_sc = IsCryptoHelperPresent(verbose); + if (use_sc == false) { + size_t keylen = 0; + int res = loadFile_safe(ICLASS_DECRYPTION_BIN, "", (void **)&keyptr, &keylen); + if (res != PM3_SUCCESS) { + PrintAndLogEx(INFO, "Couldn't find any decryption methods"); + return PM3_EINVARG; + } + + if (keylen != 16) { + PrintAndLogEx(ERR, "Failed to load transport key from file"); + return PM3_EINVARG; + } + memcpy(key, keyptr, sizeof(key)); + free(keyptr); } - memcpy(key, keyptr, sizeof(key)); - free(keyptr); } // tripledes @@ -1157,18 +1162,24 @@ static int CmdHFiClassEncryptBlk(const char *Cmd) { CLIParserFree(clictx); - bool use_sc = IsCryptoHelperPresent(verbose); + bool use_sc = false; + if (have_key == false) { + use_sc = IsCryptoHelperPresent(verbose); + if (use_sc == false) { + size_t keylen = 0; + int res = loadFile_safe(ICLASS_DECRYPTION_BIN, "", (void **)&keyptr, &keylen); + if (res != PM3_SUCCESS) { + PrintAndLogEx(ERR, "Failed to find any encryption methods"); + return PM3_EINVARG; + } - 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) { - 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(key, keyptr, sizeof(key)); + free(keyptr); } - - memcpy(key, keyptr, sizeof(key)); - free(keyptr); } if (use_sc) { From b41be82a6c4547de4570e4984909f5b5d8e6fe1f Mon Sep 17 00:00:00 2001 From: iceman1001 Date: Mon, 22 Feb 2021 13:12:37 +0100 Subject: [PATCH 44/58] hf 15 - prepcmd beyond array boundery fix --- client/src/cmdhf15.c | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/client/src/cmdhf15.c b/client/src/cmdhf15.c index 04ffbae45..6cb4dfe53 100644 --- a/client/src/cmdhf15.c +++ b/client/src/cmdhf15.c @@ -575,6 +575,10 @@ bool readHF15Uid(bool loop, bool verbose) { * **cmd command line */ static bool prepareHF15Cmd(char **cmd, uint16_t *reqlen, uint8_t *arg1, uint8_t *req, uint8_t iso15cmd) { // reqlen arg0 + + if (*cmd == NULL || strlen(*cmd) == 0) + return false; + int temp; uint8_t uid[8] = {0x00}; uint32_t tmpreqlen = 0; @@ -598,13 +602,12 @@ static bool prepareHF15Cmd(char **cmd, uint16_t *reqlen, uint8_t *arg1, uint8_t // strip while (**cmd == ' ' || **cmd == '\t')(*cmd)++; - switch (**cmd) { + char c = tolower(**cmd); + switch (c) { case 0: PrintAndLogEx(WARNING, "missing addr"); return false; - break; case 'u': - case 'U': // unaddressed mode may not be supported by all vendors req[tmpreqlen++] |= ISO15_REQ_SUBCARRIER_SINGLE | ISO15_REQ_DATARATE_HIGH | ISO15_REQ_NONINVENTORY; req[tmpreqlen++] = iso15cmd; @@ -637,9 +640,9 @@ static bool prepareHF15Cmd(char **cmd, uint16_t *reqlen, uint8_t *arg1, uint8_t break; } // skip to next space - while (**cmd != ' ' && **cmd != '\t')(*cmd)++; + while (**cmd != NULL && **cmd != ' ' && **cmd != '\t')(*cmd)++; // skip over the space - while (**cmd == ' ' || **cmd == '\t')(*cmd)++; + while (**cmd != NULL && **cmd == ' ' || **cmd == '\t')(*cmd)++; *reqlen = tmpreqlen; return true; From 954ad74bc0ec5d0cc23dd863693f276d7ac2a71d Mon Sep 17 00:00:00 2001 From: iceman1001 Date: Mon, 22 Feb 2021 13:48:58 +0100 Subject: [PATCH 45/58] ... this time fix out bounds loop.. and some nice outputs --- client/src/cmdhf15.c | 31 ++++++++++++++++++------------- 1 file changed, 18 insertions(+), 13 deletions(-) diff --git a/client/src/cmdhf15.c b/client/src/cmdhf15.c index 6cb4dfe53..1fd1fb034 100644 --- a/client/src/cmdhf15.c +++ b/client/src/cmdhf15.c @@ -640,9 +640,9 @@ static bool prepareHF15Cmd(char **cmd, uint16_t *reqlen, uint8_t *arg1, uint8_t break; } // skip to next space - while (**cmd != NULL && **cmd != ' ' && **cmd != '\t')(*cmd)++; + while (**cmd != '\0' && **cmd != ' ' && **cmd != '\t')(*cmd)++; // skip over the space - while (**cmd != NULL && **cmd == ' ' || **cmd == '\t')(*cmd)++; + while (**cmd != '\0' && (**cmd == ' ' || **cmd == '\t'))(*cmd)++; *reqlen = tmpreqlen; return true; @@ -1355,7 +1355,8 @@ static int CmdHF15Dump(const char *Cmd) { // copy uid to read command memcpy(req + 2, uid, sizeof(uid)); - + + PrintAndLogEx(INFO, "." NOLF); for (int retry = 0; retry < 5; retry++) { req[10] = blocknum; @@ -1371,6 +1372,7 @@ static int CmdHF15Dump(const char *Cmd) { continue; } if (len < 2) { + PrintAndLogEx(NORMAL, ""); PrintAndLogEx(FAILED, "iso15693 command failed"); continue; } @@ -1378,11 +1380,13 @@ static int CmdHF15Dump(const char *Cmd) { recv = resp.data.asBytes; if (CheckCrc15(recv, len) == false) { + PrintAndLogEx(NORMAL, ""); PrintAndLogEx(FAILED, "crc (" _RED_("fail") ")"); continue; } if ((recv[0] & ISO15_RES_ERROR) == ISO15_RES_ERROR) { + PrintAndLogEx(NORMAL, ""); PrintAndLogEx(FAILED, "Tag returned Error %i: %s", recv[1], TagErrorStr(recv[1])); break; } @@ -1402,12 +1406,12 @@ static int CmdHF15Dump(const char *Cmd) { DropField(); PrintAndLogEx(NORMAL, ""); - PrintAndLogEx(NORMAL, "block# | data |lck| ascii"); - PrintAndLogEx(NORMAL, "---------+--------------+---+----------"); + PrintAndLogEx(INFO, "block# | data |lck| ascii"); + PrintAndLogEx(INFO, "---------+--------------+---+----------"); for (int i = 0; i < blocknum; i++) { - PrintAndLogEx(NORMAL, "%3d/0x%02X | %s | %d | %s", i, i, sprint_hex(mem[i].block, 4), mem[i].lock, sprint_ascii(mem[i].block, 4)); + PrintAndLogEx(INFO, "%3d/0x%02X | %s | %d | %s", i, i, sprint_hex(mem[i].block, 4), mem[i].lock, sprint_ascii(mem[i].block, 4)); } - PrintAndLogEx(NORMAL, "\n"); + PrintAndLogEx(NORMAL, ""); size_t datalen = blocknum * 4; saveFile(filename, ".bin", data, datalen); @@ -1598,14 +1602,15 @@ static int CmdHF15Readmulti(const char *Cmd) { PrintAndLogEx(NORMAL, ""); - PrintAndLogEx(NORMAL, "block# | data |lck| ascii"); - PrintAndLogEx(NORMAL, "---------+--------------+---+----------"); + PrintAndLogEx(INFO, "block# | data |lck| ascii"); + PrintAndLogEx(INFO, "---------+--------------+---+----------"); for (int i = start; i < stop; i += 5) { - PrintAndLogEx(NORMAL, "%3d/0x%02X | %s | %d | %s", currblock, currblock, sprint_hex(data + i + 1, 4), data[i], sprint_ascii(data + i + 1, 4)); + PrintAndLogEx(INFO, "%3d/0x%02X | %s | %d | %s", currblock, currblock, sprint_hex(data + i + 1, 4), data[i], sprint_ascii(data + i + 1, 4)); currblock++; } + PrintAndLogEx(NORMAL, ""); return PM3_SUCCESS; } @@ -1679,9 +1684,9 @@ static int CmdHF15Read(const char *Cmd) { // print response PrintAndLogEx(NORMAL, ""); - PrintAndLogEx(NORMAL, "block #%3d |lck| ascii", blocknum); - PrintAndLogEx(NORMAL, "------------+---+------"); - PrintAndLogEx(NORMAL, "%s| %d | %s", sprint_hex(data + 2, status - 4), data[1], sprint_ascii(data + 2, status - 4)); + PrintAndLogEx(INFO, "block #%3d |lck| ascii", blocknum); + PrintAndLogEx(INFO, "------------+---+------"); + PrintAndLogEx(INFO, "%s| %d | %s", sprint_hex(data + 2, status - 4), data[1], sprint_ascii(data + 2, status - 4)); PrintAndLogEx(NORMAL, ""); return PM3_SUCCESS; } From 226b82536ad6a4eda7d7afdacc7e838e79298d5a Mon Sep 17 00:00:00 2001 From: iceman1001 Date: Mon, 22 Feb 2021 21:25:25 +0100 Subject: [PATCH 46/58] color and text, which introduced a new dependency.. --- tools/recover_pk.py | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/tools/recover_pk.py b/tools/recover_pk.py index 0310b4750..c46180d41 100755 --- a/tools/recover_pk.py +++ b/tools/recover_pk.py @@ -5,6 +5,9 @@ import binascii import sys import hashlib +from colors import * + +# pip3 install ansicolors debug = False @@ -460,7 +463,6 @@ def recover_multiple(uids, sigs, curvename, alghash=None): recovered &= recovered_tmp return recovered - def selftests(): tests = [ {'name': "Mifare Ultralight EV1", @@ -556,14 +558,17 @@ if __name__ == "__main__": print("Example: \n%s 04ee45daa34084 ebb6102bff74b087d18a57a54bc375159a04ea9bc61080b7f4a85afe1587d73b" % sys.argv[0]) exit(1) uids, sigs = sys.argv[1:][::2], sys.argv[1:][1::2] + once = True curvenames = guess_curvename(sigs[0]) for c in curvenames: - print("\nAssuming curve=%s" % c) - print("========================") for h in [None, "md5", "sha1", "sha256", "sha512"]: - print("Assuming hash=%s" % h) recovered = recover_multiple(uids, sigs, c, alghash=h) if recovered: + if once: + print(color('curve=%s', fg='yellow') % c) + once = False + print(color('hash=%s', fg='yellow') % h) print("Possible uncompressed Pk(s):") for pk in list(recovered): print(binascii.hexlify(pk).decode('utf8')) + once = True From da9d041301f05a08df0bccfd2b7bd191b0172209 Mon Sep 17 00:00:00 2001 From: iceman1001 Date: Mon, 22 Feb 2021 21:58:09 +0100 Subject: [PATCH 47/58] added the possibility to protect and manually verify the write --- client/luascripts/lf_em4100_bulk.lua | 61 ++++++++++++++++++++++++---- 1 file changed, 52 insertions(+), 9 deletions(-) diff --git a/client/luascripts/lf_em4100_bulk.lua b/client/luascripts/lf_em4100_bulk.lua index d1f4aa845..d4cdfdd8d 100644 --- a/client/luascripts/lf_em4100_bulk.lua +++ b/client/luascripts/lf_em4100_bulk.lua @@ -4,7 +4,7 @@ local ac = require('ansicolors') copyright = '' author = "Christian Herrmann" -version = 'v1.0.1' +version = 'v1.0.2' desc = [[ Perform bulk EM410x enrollment of T5577 RFID tags. It keeps track of last card id used. If called with -s, this value resets "session". @@ -12,6 +12,11 @@ If called with -s, this value resets "session". if press it defaults to Y, which writes a ID. Any other input char will exit the script. +You can supply a password, which will set the config block / block 7 on the T5577. + +The verify option will issue a 'lf em 410x reader' command, so you can manually verify +that the write worked. + ]] example = [[ -- resets and start enrolling EM410x id 11CC334455 @@ -19,14 +24,21 @@ example = [[ -- continue enrolling from where last iteration script run lf_em4100_bulk.lua -c + + -- reset and start enrolling from 11223344, + -- protecting the tag with password 010203 + -- and verify the em id write. + script run lf_em4100_bulk.lua -s 1122334455 -p 01020304 -v ]] usage = [[ -script run lf_en4100_bulk.lua [-h] [-c] [-s ] +script run lf_en4100_bulk.lua [-h] [-c] [-p password] [-s ] [-v] ]] arguments = [[ -h : this help -c : continue from last card number used + -p : Password protecting the T5577. -s : starting card number + -v : verify write by executing a `lf em 410x reader` ]] -- Some globals @@ -112,22 +124,35 @@ local function main(args) if #args == 0 then return help() end + local shall_verify = false local shall_continue = false + local got_pwd = false local startid = '' + local ipwd = '' - for o, a in getopt.getopt(args, 'cs:h') do + + for o, a in getopt.getopt(args, 'cp:s:hv') do if o == 'h' then return help() end - if o == 'c' then - shall_continue = true - end + if o == 'c' then shall_continue = true end if o == 's' then startid = a end + if o == 'p' then + ipwd = a + got_pwd = true + end + if o == 'v' then shall_verify = true end end -- if reset/start over, check -s if not shall_continue then if startid == nil then return oops('empty card number string') end if #startid == 0 then return oops('empty card number string') end - if #startid ~= 10 then return oops('card number wrong length. Should be 5 hex bytes') end + if #startid ~= 10 then return oops('card number wrong length. Must be 5 hex bytes') end + end + + if got_pwd then + if ipwd == nil then return oops('empty password') end + if #ipwd == 0 then return oops('empty password') end + if #ipwd ~= 8 then return oops('password wrong length. Must be 4 hex bytes') end end core.console('clear') @@ -137,7 +162,16 @@ local function main(args) local hi = tonumber(startid:sub(1, 2), 16) local low = tonumber(startid:sub(3, 10), 16) - + local pwd = tonumber(ipwd, 16) + + if got_pwd then + print(('Will protect T5577 with password '..ac.green..'%08X'..ac.reset):format(pwd)) + end + + if shall_verify then + print('Will verify write afterwards') + end + if shall_continue then print('Continue enrolling from last save') hi, low = readfile() @@ -152,8 +186,17 @@ local function main(args) local msg = (template):format(hi, i) local ans = utils.input(msg, 'y'):lower() if ans == 'y' then - core.console( ('lf em 410x clone --id %02X%08X'):format(hi, i) ) + core.console( ('lf em 410x clone --id %02X%08X'):format(hi, i) ) -- print ( ('lf em 410x clone --id %02X%08X'):format(hi, i) ) + + if got_pwd then + core.console('lf t55 detect') + core.console(('lf t55 protect -n %08x'):format(pwd)) + end + + if shall_verify then + core.console('lf em 410x reader') + end else print(ac.red..'User aborted'..ac.reset) low = i From 8b09f7aa71e68186e80cd47fa8752895bdd4e5c2 Mon Sep 17 00:00:00 2001 From: iceman1001 Date: Mon, 22 Feb 2021 22:17:28 +0100 Subject: [PATCH 48/58] add python pip dependencies --- .github/workflows/ubuntu.yml | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/.github/workflows/ubuntu.yml b/.github/workflows/ubuntu.yml index 57a6caa1d..d3143196c 100644 --- a/.github/workflows/ubuntu.yml +++ b/.github/workflows/ubuntu.yml @@ -15,6 +15,12 @@ jobs: - 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: Install Python dependencies + run: | + python -m pip install --upgrade pip + python -m pip install ansicolors + if [ -f requirements.txt ]; then pip install -r requirements.txt; fi + - name: make clean run: make clean @@ -40,6 +46,12 @@ jobs: - 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: Install Python dependencies + run: | + python -m pip install --upgrade pip + python -m pip install ansicolors + if [ -f requirements.txt ]; then pip install -r requirements.txt; fi + - name: make clean run: make clean @@ -66,6 +78,12 @@ jobs: - 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: Install Python dependencies + run: | + python -m pip install --upgrade pip + python -m pip install ansicolors + if [ -f requirements.txt ]; then pip install -r requirements.txt; fi + - name: Prepare Build Folders run: mkdir -p client/build From 6a6a444a573c2b507e6e1499ca842bbdb05b7849 Mon Sep 17 00:00:00 2001 From: iceman1001 Date: Mon, 22 Feb 2021 22:21:31 +0100 Subject: [PATCH 49/58] fixes workflow --- .github/workflows/ubuntu.yml | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/.github/workflows/ubuntu.yml b/.github/workflows/ubuntu.yml index d3143196c..4b5965bc7 100644 --- a/.github/workflows/ubuntu.yml +++ b/.github/workflows/ubuntu.yml @@ -17,9 +17,9 @@ jobs: - name: Install Python dependencies run: | - python -m pip install --upgrade pip - python -m pip install ansicolors - if [ -f requirements.txt ]; then pip install -r requirements.txt; fi + python -m pip install --upgrade pip + pip install ansicolors + if [ -f requirements.txt ]; then pip install -r requirements.txt; fi - name: make clean run: make clean @@ -48,9 +48,9 @@ jobs: - name: Install Python dependencies run: | - python -m pip install --upgrade pip - python -m pip install ansicolors - if [ -f requirements.txt ]; then pip install -r requirements.txt; fi + python -m pip install --upgrade pip + pip install ansicolors + if [ -f requirements.txt ]; then pip install -r requirements.txt; fi - name: make clean run: make clean @@ -80,9 +80,9 @@ jobs: - name: Install Python dependencies run: | - python -m pip install --upgrade pip - python -m pip install ansicolors - if [ -f requirements.txt ]; then pip install -r requirements.txt; fi + python -m pip install --upgrade pip + pip install ansicolors + if [ -f requirements.txt ]; then pip install -r requirements.txt; fi - name: Prepare Build Folders run: mkdir -p client/build From c069bf2653ef2bbdeef6211785166f66f6c89a82 Mon Sep 17 00:00:00 2001 From: iceman1001 Date: Mon, 22 Feb 2021 22:27:36 +0100 Subject: [PATCH 50/58] fixes workflow --- .github/workflows/ubuntu.yml | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/.github/workflows/ubuntu.yml b/.github/workflows/ubuntu.yml index 4b5965bc7..d594a4d06 100644 --- a/.github/workflows/ubuntu.yml +++ b/.github/workflows/ubuntu.yml @@ -18,8 +18,8 @@ jobs: - name: Install Python dependencies run: | python -m pip install --upgrade pip - pip install ansicolors - if [ -f requirements.txt ]; then pip install -r requirements.txt; fi + python -m pip install ansicolors + if [ -f requirements.txt ]; then python -m pip install -r requirements.txt; fi - name: make clean run: make clean @@ -49,8 +49,8 @@ jobs: - name: Install Python dependencies run: | python -m pip install --upgrade pip - pip install ansicolors - if [ -f requirements.txt ]; then pip install -r requirements.txt; fi + python -m pip install ansicolors + if [ -f requirements.txt ]; then python -m pip install -r requirements.txt; fi - name: make clean run: make clean @@ -81,8 +81,8 @@ jobs: - name: Install Python dependencies run: | python -m pip install --upgrade pip - pip install ansicolors - if [ -f requirements.txt ]; then pip install -r requirements.txt; fi + python -m pip install ansicolors + if [ -f requirements.txt ]; then python -m pip install -r requirements.txt; fi - name: Prepare Build Folders run: mkdir -p client/build From 655e5a8ffa36b14a88cd88e327771a9ab5631a93 Mon Sep 17 00:00:00 2001 From: iceman1001 Date: Mon, 22 Feb 2021 22:28:40 +0100 Subject: [PATCH 51/58] maybe python3 --- .github/workflows/ubuntu.yml | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/.github/workflows/ubuntu.yml b/.github/workflows/ubuntu.yml index d594a4d06..9601893c0 100644 --- a/.github/workflows/ubuntu.yml +++ b/.github/workflows/ubuntu.yml @@ -17,9 +17,9 @@ jobs: - name: Install Python dependencies run: | - python -m pip install --upgrade pip - python -m pip install ansicolors - if [ -f requirements.txt ]; then python -m pip install -r requirements.txt; fi + python3 -m pip install --upgrade pip + python3 -m pip install ansicolors + if [ -f requirements.txt ]; then python3 -m pip install -r requirements.txt; fi - name: make clean run: make clean @@ -48,9 +48,9 @@ jobs: - name: Install Python dependencies run: | - python -m pip install --upgrade pip - python -m pip install ansicolors - if [ -f requirements.txt ]; then python -m pip install -r requirements.txt; fi + python3 -m pip install --upgrade pip + python3 -m pip install ansicolors + if [ -f requirements.txt ]; then python3 -m pip install -r requirements.txt; fi - name: make clean run: make clean @@ -80,9 +80,9 @@ jobs: - name: Install Python dependencies run: | - python -m pip install --upgrade pip - python -m pip install ansicolors - if [ -f requirements.txt ]; then python -m pip install -r requirements.txt; fi + python3 -m pip install --upgrade pip + python3 -m pip install ansicolors + if [ -f requirements.txt ]; then python3 -m pip install -r requirements.txt; fi - name: Prepare Build Folders run: mkdir -p client/build From a9e3c2779e51c052d642cfc594c1e14859384952 Mon Sep 17 00:00:00 2001 From: iceman1001 Date: Mon, 22 Feb 2021 22:33:47 +0100 Subject: [PATCH 52/58] adapt workflow for macos and python dependencies --- .github/workflows/macos.yml | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/.github/workflows/macos.yml b/.github/workflows/macos.yml index c476fbefe..9f3ec3023 100644 --- a/.github/workflows/macos.yml +++ b/.github/workflows/macos.yml @@ -25,6 +25,12 @@ jobs: - name: Install dependencies run: brew install readline qt5 RfidResearchGroup/proxmark3/arm-none-eabi-gcc + - name: Install Python dependencies + run: | + python3 -m pip install --upgrade pip + python3 -m pip install ansicolors + if [ -f requirements.txt ]; then python3 -m pip install -r requirements.txt; fi + - name: make clean run: make clean @@ -60,6 +66,12 @@ jobs: - name: Install dependencies run: brew install readline qt5 RfidResearchGroup/proxmark3/arm-none-eabi-gcc + - name: Install Python dependencies + run: | + python3 -m pip install --upgrade pip + python3 -m pip install ansicolors + if [ -f requirements.txt ]; then python3 -m pip install -r requirements.txt; fi + - name: make clean run: make clean @@ -96,6 +108,12 @@ jobs: - name: Install dependencies run: brew install readline qt5 RfidResearchGroup/proxmark3/arm-none-eabi-gcc + - name: Install Python dependencies + run: | + python3 -m pip install --upgrade pip + python3 -m pip install ansicolors + if [ -f requirements.txt ]; then python3 -m pip install -r requirements.txt; fi + - name: Prepare Build Folders run: mkdir -p client/build From 6d329a0462eb7d1f26702285b893547c6812e081 Mon Sep 17 00:00:00 2001 From: iceman1001 Date: Tue, 23 Feb 2021 18:23:53 +0100 Subject: [PATCH 53/58] coverity fixes --- client/src/cmdhficlass.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/client/src/cmdhficlass.c b/client/src/cmdhficlass.c index 716e03436..2fda649b8 100644 --- a/client/src/cmdhficlass.c +++ b/client/src/cmdhficlass.c @@ -956,6 +956,7 @@ static int CmdHFiClassDecrypt(const char *Cmd) { if (keylen != 16) { PrintAndLogEx(ERR, "Failed to load transport key from file"); + free(keyptr); return PM3_EINVARG; } memcpy(key, keyptr, sizeof(key)); @@ -1175,6 +1176,7 @@ static int CmdHFiClassEncryptBlk(const char *Cmd) { if (keylen != 16) { PrintAndLogEx(ERR, "Failed to load transport key from file"); + free(keyptr); return PM3_EINVARG; } memcpy(key, keyptr, sizeof(key)); From eade85b3f564b8ac8519866e909d293bcfbb6531 Mon Sep 17 00:00:00 2001 From: Philippe Teuwen Date: Tue, 23 Feb 2021 18:24:23 +0100 Subject: [PATCH 54/58] so, let's use sslcrypto... --- .github/workflows/macos.yml | 6 +- .github/workflows/ubuntu.yml | 6 +- tools/recover_pk.py | 395 +---------------------------------- 3 files changed, 12 insertions(+), 395 deletions(-) diff --git a/.github/workflows/macos.yml b/.github/workflows/macos.yml index 9f3ec3023..74e6854b7 100644 --- a/.github/workflows/macos.yml +++ b/.github/workflows/macos.yml @@ -28,7 +28,7 @@ jobs: - name: Install Python dependencies run: | python3 -m pip install --upgrade pip - python3 -m pip install ansicolors + python3 -m pip install ansicolors sslcrypto if [ -f requirements.txt ]; then python3 -m pip install -r requirements.txt; fi - name: make clean @@ -69,7 +69,7 @@ jobs: - name: Install Python dependencies run: | python3 -m pip install --upgrade pip - python3 -m pip install ansicolors + python3 -m pip install ansicolors sslcrypto if [ -f requirements.txt ]; then python3 -m pip install -r requirements.txt; fi - name: make clean @@ -111,7 +111,7 @@ jobs: - name: Install Python dependencies run: | python3 -m pip install --upgrade pip - python3 -m pip install ansicolors + python3 -m pip install ansicolors sslcrypto if [ -f requirements.txt ]; then python3 -m pip install -r requirements.txt; fi - name: Prepare Build Folders diff --git a/.github/workflows/ubuntu.yml b/.github/workflows/ubuntu.yml index 9601893c0..417c06aca 100644 --- a/.github/workflows/ubuntu.yml +++ b/.github/workflows/ubuntu.yml @@ -18,7 +18,7 @@ jobs: - name: Install Python dependencies run: | python3 -m pip install --upgrade pip - python3 -m pip install ansicolors + python3 -m pip install ansicolors sslcrypto if [ -f requirements.txt ]; then python3 -m pip install -r requirements.txt; fi - name: make clean @@ -49,7 +49,7 @@ jobs: - name: Install Python dependencies run: | python3 -m pip install --upgrade pip - python3 -m pip install ansicolors + python3 -m pip install ansicolors sslcrypto if [ -f requirements.txt ]; then python3 -m pip install -r requirements.txt; fi - name: make clean @@ -81,7 +81,7 @@ jobs: - name: Install Python dependencies run: | python3 -m pip install --upgrade pip - python3 -m pip install ansicolors + python3 -m pip install ansicolors sslcrypto if [ -f requirements.txt ]; then python3 -m pip install -r requirements.txt; fi - name: Prepare Build Folders diff --git a/tools/recover_pk.py b/tools/recover_pk.py index c46180d41..c71064cf3 100755 --- a/tools/recover_pk.py +++ b/tools/recover_pk.py @@ -2,399 +2,16 @@ # MIT License # Copyright (c) 2020 @doegox +# Requirements: +# python3 -m pip install ansicolors sslcrypto + import binascii import sys -import hashlib -from colors import * - -# pip3 install ansicolors +import sslcrypto +from colors import color debug = False -####################################################################### -# Using external sslcrypto library: -# import sslcrypto -# ... sslcrypto.ecc.get_curve() -# But to get this script autonomous, i.e. for CI, we embedded the -# code snippets we needed: -####################################################################### -# code snippets from JacobianCurve: -# This code is public domain. Everyone has the right to do whatever -# they want with it for any purpose. -# Copyright (c) 2013 Vitalik Buterin - - -class JacobianCurve: - def __init__(self, p, n, a, b, g): - self.p = p - self.n = n - self.a = a - self.b = b - self.g = g - self.n_length = len(bin(self.n).replace("0b", "")) - - def to_jacobian(self, p): - return p[0], p[1], 1 - - def jacobian_double(self, p): - if not p[1]: - return 0, 0, 0 - ysq = (p[1] ** 2) % self.p - s = (4 * p[0] * ysq) % self.p - m = (3 * p[0] ** 2 + self.a * p[2] ** 4) % self.p - nx = (m ** 2 - 2 * s) % self.p - ny = (m * (s - nx) - 8 * ysq ** 2) % self.p - nz = (2 * p[1] * p[2]) % self.p - return nx, ny, nz - - def jacobian_add(self, p, q): - if not p[1]: - return q - if not q[1]: - return p - u1 = (p[0] * q[2] ** 2) % self.p - u2 = (q[0] * p[2] ** 2) % self.p - s1 = (p[1] * q[2] ** 3) % self.p - s2 = (q[1] * p[2] ** 3) % self.p - if u1 == u2: - if s1 != s2: - return (0, 0, 1) - return self.jacobian_double(p) - h = u2 - u1 - r = s2 - s1 - h2 = (h * h) % self.p - h3 = (h * h2) % self.p - u1h2 = (u1 * h2) % self.p - nx = (r ** 2 - h3 - 2 * u1h2) % self.p - ny = (r * (u1h2 - nx) - s1 * h3) % self.p - nz = (h * p[2] * q[2]) % self.p - return (nx, ny, nz) - - def from_jacobian(self, p): - z = inverse(p[2], self.p) - return (p[0] * z ** 2) % self.p, (p[1] * z ** 3) % self.p - - def jacobian_shamir(self, a, n, b, m): - ab = self.jacobian_add(a, b) - if n < 0 or n >= self.n: - n %= self.n - if m < 0 or m >= self.n: - m %= self.n - res = 0, 0, 1 # point on infinity - for i in range(self.n_length - 1, -1, -1): - res = self.jacobian_double(res) - has_n = n & (1 << i) - has_m = m & (1 << i) - if has_n: - if has_m == 0: - res = self.jacobian_add(res, a) - if has_m != 0: - res = self.jacobian_add(res, ab) - else: - if has_m == 0: - res = self.jacobian_add(res, (0, 0, 1)) # Try not to leak - if has_m != 0: - res = self.jacobian_add(res, b) - return res - - def fast_shamir(self, a, n, b, m): - return self.from_jacobian( - self.jacobian_shamir( - self.to_jacobian(a), n, self.to_jacobian(b), m)) - -####################################################################### -# code snippets from sslcrypto -# MIT License -# Copyright (c) 2019 Ivan Machugovskiy - - -def int_to_bytes(raw, length): - data = [] - for _ in range(length): - data.append(raw % 256) - raw //= 256 - return bytes(data[::-1]) - - -def bytes_to_int(data): - raw = 0 - for byte in data: - raw = raw * 256 + byte - return raw - - -def legendre(a, p): - res = pow(a, (p - 1) // 2, p) - if res == p - 1: - return -1 - else: - return res - - -def inverse(a, n): - if a == 0: - return 0 - lm, hm = 1, 0 - low, high = a % n, n - while low > 1: - r = high // low - nm, new = hm - lm * r, high - low * r - lm, low, hm, high = nm, new, lm, low - return lm % n - - -def square_root_mod_prime(n, p): - if n == 0: - return 0 - if p == 2: - return n # We should never get here but it might be useful - if legendre(n, p) != 1: - raise ValueError("No square root") - # Optimizations - if p % 4 == 3: - return pow(n, (p + 1) // 4, p) - # 1. By factoring out powers of 2, find Q and S such that p - 1 = - # Q * 2 ** S with Q odd - q = p - 1 - s = 0 - while q % 2 == 0: - q //= 2 - s += 1 - # 2. Search for z in Z/pZ which is a quadratic non-residue - z = 1 - while legendre(z, p) != -1: - z += 1 - m, c, t, r = s, pow(z, q, p), pow(n, q, p), pow(n, (q + 1) // 2, p) - while True: - if t == 0: - return 0 - elif t == 1: - return r - # Use repeated squaring to find the least i, 0 < i < M, such - # that t ** (2 ** i) = 1 - t_sq = t - i = 0 - for i in range(1, m): - t_sq = t_sq * t_sq % p - if t_sq == 1: - break - else: - raise ValueError("Should never get here") - # Let b = c ** (2 ** (m - i - 1)) - b = pow(c, 2 ** (m - i - 1), p) - m = i - c = b * b % p - t = t * b * b % p - r = r * b % p - return r - - -CURVES = { - # name: (nid, p, n, a, b, (Gx, Gy)), - "secp128r1": ( - 706, - 0xFFFFFFFDFFFFFFFFFFFFFFFFFFFFFFFF, - 0xFFFFFFFE0000000075A30D1B9038A115, - 0xFFFFFFFDFFFFFFFFFFFFFFFFFFFFFFFC, - 0xE87579C11079F43DD824993C2CEE5ED3, - ( - 0x161FF7528B899B2D0C28607CA52C5B86, - 0xCF5AC8395BAFEB13C02DA292DDED7A83 - ) - ), - "secp128r2": ( - 707, - 0xFFFFFFFDFFFFFFFFFFFFFFFFFFFFFFFF, - 0x3FFFFFFF7FFFFFFFBE0024720613B5A3, - 0xD6031998D1B3BBFEBF59CC9BBFF9AEE1, - 0x5EEEFCA380D02919DC2C6558BB6D8A5D, - ( - 0x7B6AA5D85E572983E6FB32A7CDEBC140, - 0x27B6916A894D3AEE7106FE805FC34B44 - ) - ), - "secp192k1": ( - 711, - 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFEE37, - 0xFFFFFFFFFFFFFFFFFFFFFFFE26F2FC170F69466A74DEFD8D, - 0x000000000000000000000000000000000000000000000000, - 0x000000000000000000000000000000000000000000000003, - ( - 0xDB4FF10EC057E9AE26B07D0280B7F4341DA5D1B1EAE06C7D, - 0x9B2F2F6D9C5628A7844163D015BE86344082AA88D95E2F9D - ) - ), - # p192 - "secp192r1": ( - 409, - 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFFFFFFFFFF, - 0xFFFFFFFFFFFFFFFFFFFFFFFF99DEF836146BC9B1B4D22831, - 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFFFFFFFFFC, - 0x64210519E59C80E70FA7E9AB72243049FEB8DEECC146B9B1, - ( - 0x188DA80EB03090F67CBF20EB43A18800F4FF0AFD82FF1012, - 0x07192B95FFC8DA78631011ED6B24CDD573F977A11E794811 - ) - ), - "secp224k1": ( - 712, - 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFE56D, - 0x10000000000000000000000000001DCE8D2EC6184CAF0A971769FB1F7, - 0x00000000000000000000000000000000000000000000000000000000, - 0x00000000000000000000000000000000000000000000000000000005, - ( - 0xA1455B334DF099DF30FC28A169A467E9E47075A90F7E650EB6B7A45C, - 0x7E089FED7FBA344282CAFBD6F7E319F7C0B0BD59E2CA4BDB556D61A5 - ) - ), - # p224 - "secp224r1": ( - 713, - 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF000000000000000000000001, - 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFF16A2E0B8F03E13DD29455C5C2A3D, - 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFE, - 0xB4050A850C04B3ABF54132565044B0B7D7BFD8BA270B39432355FFB4, - ( - 0xB70E0CBD6BB4BF7F321390B94A03C1D356C21122343280D6115C1D21, - 0xBD376388B5F723FB4C22DFE6CD4375A05A07476444D5819985007E34 - ) - ), - "secp256k1": ( - 714, - 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F, - 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141, - 0x0000000000000000000000000000000000000000000000000000000000000000, - 0x0000000000000000000000000000000000000000000000000000000000000007, - ( - 0x79BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798, - 0x483ADA7726A3C4655DA4FBFC0E1108A8FD17B448A68554199C47D08FFB10D4B8 - ) - ), - # p256, openssl uses the name: prime256v1. - "secp256r1": ( - 415, - 0xFFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFF, - 0xFFFFFFFF00000000FFFFFFFFFFFFFFFFBCE6FAADA7179E84F3B9CAC2FC632551, - 0xFFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFC, - 0x5AC635D8AA3A93E7B3EbBD55769886BC651D06B0CC53B0F63BCE3C3E27D2604B, - ( - 0x6B17D1F2E12c4247F8BCE6E563A440F277037D812DEB33A0F4A13945D898C296, - 0x4FE342E2FE1A7F9B8EE7EB4A7C0F9E162BCE33576B315ECECBB6406837BF51F5 - ) - ), - # p384 - "secp384r1": ( - 715, - 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFF0000000000000000FFFFFFFF, - 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC7634D81F4372DDF581A0DB248B0A77AECEC196ACCC52973, - 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFF0000000000000000FFFFFFFC, - 0xB3312FA7E23EE7E4988E056BE3F82D19181D9C6EFE8141120314088F5013875AC656398D8A2ED19D2A85C8EDD3EC2AEF, - ( - 0xAA87CA22BE8B05378EB1C71EF320AD746E1D3B628BA79B9859F741E082542A385502F25DBF55296C3A545E3872760AB7, - 0x3617DE4A96262C6F5D9E98BF9292DC29F8F41DBD289A147CE9DA3113B5F0B8C00A60B1CE1D7E819D7A431D7C90EA0E5F - ) - ), - "secp521r1": ( - 716, - 0x01FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF, - 0x01FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA51868783BF2F966B7FCC0148F709A5D03BB5C9B8899C47AEBB6FB71E91386409, - 0x01FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC, - 0x0051953EB9618E1C9A1F929A21A0B68540EEA2DA725B99B315F3B8B489918EF109E156193951EC7E937B1652C0BD3BB1BF073573DF883D2C34F1EF451FD46B503F00, - ( - 0x00C6858E06B70404E9CD9E3ECB662395B4429C648139053FB521F828AF606B4D3DBAA14B5E77EFE75928FE1DC127A2FFA8DE3348B3C1856A429BF97E7E31C2E5BD66, - 0x011839296A789A3BC0045C8A5FB42C7D1BD998F54449579B446817AFBD17273E662C97EE72995EF42640C550B9013FAD0761353C7086A272C24088BE94769FD16650 - ) - ) -} - - -def get_curve(name): - if name not in CURVES: - raise ValueError("Unknown curve {}".format(name)) - nid, p, n, a, b, g = CURVES[name] - return EllipticCurve(nid, p, n, a, b, g) - - -class EllipticCurve: - def __init__(self, nid, p, n, a, b, g): - self.p, self.n, self.a, self.b, self.g = p, n, a, b, g - self.jacobian = JacobianCurve(self.p, self.n, self.a, self.b, self.g) - self.public_key_length = (len(bin(p).replace("0b", "")) + 7) // 8 - self.order_bitlength = len(bin(n).replace("0b", "")) - - def _int_to_bytes(self, raw, len=None): - return int_to_bytes(raw, len or self.public_key_length) - - def _subject_to_int(self, subject): - return bytes_to_int(subject[:(self.order_bitlength + 7) // 8]) - - def recover(self, signature, data, hash="sha256"): - # Sanity check: is this signature recoverable? - if len(signature) != 1 + 2 * self.public_key_length: - raise ValueError("Cannot recover an unrecoverable signature") - subject = self._digest(data, hash) - z = self._subject_to_int(subject) - - recid = signature[0] - 27 if signature[0] < 31 else signature[0] - 31 - r = bytes_to_int(signature[1:self.public_key_length + 1]) - s = bytes_to_int(signature[self.public_key_length + 1:]) - - # Verify bounds - if not 0 <= recid < 2 * (self.p // self.n + 1): - raise ValueError("Invalid recovery ID") - if r >= self.n: - raise ValueError("r is out of bounds") - if s >= self.n: - raise ValueError("s is out of bounds") - - rinv = inverse(r, self.n) - u1 = (-z * rinv) % self.n - u2 = (s * rinv) % self.n - - # Recover R - rx = r + (recid // 2) * self.n - if rx >= self.p: - raise ValueError("Rx is out of bounds") - - # Almost copied from decompress_point - ry_square = (pow(rx, 3, self.p) + self.a * rx + self.b) % self.p - try: - ry = square_root_mod_prime(ry_square, self.p) - except Exception: - raise ValueError("Invalid recovered public key") from None - - # Ensure the point is correct - if ry % 2 != recid % 2: - # Fix Ry sign - ry = self.p - ry - - x, y = self.jacobian.fast_shamir(self.g, u1, (rx, ry), u2) - x, y = self._int_to_bytes(x), self._int_to_bytes(y) - - is_compressed = signature[0] >= 31 - if is_compressed: - return bytes([0x02 + (y[-1] % 2)]) + x - else: - return bytes([0x04]) + x + y - - def _digest(self, data, hash): - if hash is None: - 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": - return hashlib.sha256(data).digest() - elif hash == "sha512": - return hashlib.sha512(data).digest() - else: - raise ValueError("Unknown hash/derivation method") - -####################################################################### - def guess_curvename(signature): siglen = (len(signature) // 2) & 0xfe @@ -417,7 +34,7 @@ def guess_curvename(signature): def recover(data, signature, curvename, alghash=None): recovered = set() - curve = get_curve(curvename) + curve = sslcrypto.ecc.get_curve(curvename) recoverable = len(signature) % 1 == 1 if (recoverable): try: From c8d38340ab0e9c5ffbd81066ede349fa3fe1c092 Mon Sep 17 00:00:00 2001 From: Philippe Teuwen Date: Tue, 23 Feb 2021 18:38:10 +0100 Subject: [PATCH 55/58] fixes workflow --- .github/workflows/macos.yml | 6 +++--- .github/workflows/ubuntu.yml | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/.github/workflows/macos.yml b/.github/workflows/macos.yml index 74e6854b7..ca45ac8da 100644 --- a/.github/workflows/macos.yml +++ b/.github/workflows/macos.yml @@ -28,7 +28,7 @@ jobs: - name: Install Python dependencies run: | python3 -m pip install --upgrade pip - python3 -m pip install ansicolors sslcrypto + python3 -m pip install ansicolors sslcrypto setuptools if [ -f requirements.txt ]; then python3 -m pip install -r requirements.txt; fi - name: make clean @@ -69,7 +69,7 @@ jobs: - name: Install Python dependencies run: | python3 -m pip install --upgrade pip - python3 -m pip install ansicolors sslcrypto + python3 -m pip install ansicolors sslcrypto setuptools if [ -f requirements.txt ]; then python3 -m pip install -r requirements.txt; fi - name: make clean @@ -111,7 +111,7 @@ jobs: - name: Install Python dependencies run: | python3 -m pip install --upgrade pip - python3 -m pip install ansicolors sslcrypto + python3 -m pip install ansicolors sslcrypto setuptools if [ -f requirements.txt ]; then python3 -m pip install -r requirements.txt; fi - name: Prepare Build Folders diff --git a/.github/workflows/ubuntu.yml b/.github/workflows/ubuntu.yml index 417c06aca..d7bc06b2c 100644 --- a/.github/workflows/ubuntu.yml +++ b/.github/workflows/ubuntu.yml @@ -18,7 +18,7 @@ jobs: - name: Install Python dependencies run: | python3 -m pip install --upgrade pip - python3 -m pip install ansicolors sslcrypto + python3 -m pip install ansicolors sslcrypto setuptools if [ -f requirements.txt ]; then python3 -m pip install -r requirements.txt; fi - name: make clean @@ -49,7 +49,7 @@ jobs: - name: Install Python dependencies run: | python3 -m pip install --upgrade pip - python3 -m pip install ansicolors sslcrypto + python3 -m pip install ansicolors sslcrypto setuptools if [ -f requirements.txt ]; then python3 -m pip install -r requirements.txt; fi - name: make clean @@ -81,7 +81,7 @@ jobs: - name: Install Python dependencies run: | python3 -m pip install --upgrade pip - python3 -m pip install ansicolors sslcrypto + python3 -m pip install ansicolors sslcrypto setuptools if [ -f requirements.txt ]; then python3 -m pip install -r requirements.txt; fi - name: Prepare Build Folders From 18984f63d78ddd029b84d13c5db7d9da24eb4d76 Mon Sep 17 00:00:00 2001 From: iceman1001 Date: Tue, 23 Feb 2021 18:46:56 +0100 Subject: [PATCH 56/58] test --- .github/workflows/macos.yml | 6 +++--- .github/workflows/ubuntu.yml | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/.github/workflows/macos.yml b/.github/workflows/macos.yml index ca45ac8da..27e53d9a5 100644 --- a/.github/workflows/macos.yml +++ b/.github/workflows/macos.yml @@ -28,7 +28,7 @@ jobs: - name: Install Python dependencies run: | python3 -m pip install --upgrade pip - python3 -m pip install ansicolors sslcrypto setuptools + python3 -m pip install setuptools ansicolors sslcrypto if [ -f requirements.txt ]; then python3 -m pip install -r requirements.txt; fi - name: make clean @@ -69,7 +69,7 @@ jobs: - name: Install Python dependencies run: | python3 -m pip install --upgrade pip - python3 -m pip install ansicolors sslcrypto setuptools + python3 -m pip install setuptools ansicolors sslcrypto if [ -f requirements.txt ]; then python3 -m pip install -r requirements.txt; fi - name: make clean @@ -111,7 +111,7 @@ jobs: - name: Install Python dependencies run: | python3 -m pip install --upgrade pip - python3 -m pip install ansicolors sslcrypto setuptools + python3 -m pip install setuptools ansicolors sslcrypto if [ -f requirements.txt ]; then python3 -m pip install -r requirements.txt; fi - name: Prepare Build Folders diff --git a/.github/workflows/ubuntu.yml b/.github/workflows/ubuntu.yml index d7bc06b2c..613aaa3f4 100644 --- a/.github/workflows/ubuntu.yml +++ b/.github/workflows/ubuntu.yml @@ -18,7 +18,7 @@ jobs: - name: Install Python dependencies run: | python3 -m pip install --upgrade pip - python3 -m pip install ansicolors sslcrypto setuptools + python3 -m pip install setuptools ansicolors sslcrypto if [ -f requirements.txt ]; then python3 -m pip install -r requirements.txt; fi - name: make clean @@ -49,7 +49,7 @@ jobs: - name: Install Python dependencies run: | python3 -m pip install --upgrade pip - python3 -m pip install ansicolors sslcrypto setuptools + python3 -m pip install setuptools ansicolors sslcrypto if [ -f requirements.txt ]; then python3 -m pip install -r requirements.txt; fi - name: make clean @@ -81,7 +81,7 @@ jobs: - name: Install Python dependencies run: | python3 -m pip install --upgrade pip - python3 -m pip install ansicolors sslcrypto setuptools + python3 -m pip install setuptools ansicolors sslcrypto if [ -f requirements.txt ]; then python3 -m pip install -r requirements.txt; fi - name: Prepare Build Folders From 811ed8040a5ee4d46619a6ac889cdc780a996097 Mon Sep 17 00:00:00 2001 From: iceman1001 Date: Tue, 23 Feb 2021 19:00:18 +0100 Subject: [PATCH 57/58] test --- .github/workflows/ubuntu.yml | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/.github/workflows/ubuntu.yml b/.github/workflows/ubuntu.yml index 613aaa3f4..2d2b461e3 100644 --- a/.github/workflows/ubuntu.yml +++ b/.github/workflows/ubuntu.yml @@ -18,7 +18,8 @@ jobs: - name: Install Python dependencies run: | python3 -m pip install --upgrade pip - python3 -m pip install setuptools ansicolors sslcrypto + python3 -m pip install setuptools + python3 -m pip install ansicolors sslcrypto if [ -f requirements.txt ]; then python3 -m pip install -r requirements.txt; fi - name: make clean @@ -49,7 +50,8 @@ jobs: - name: Install Python dependencies run: | python3 -m pip install --upgrade pip - python3 -m pip install setuptools ansicolors sslcrypto + python3 -m pip install setuptools + python3 -m pip install ansicolors sslcrypto if [ -f requirements.txt ]; then python3 -m pip install -r requirements.txt; fi - name: make clean @@ -81,7 +83,8 @@ jobs: - name: Install Python dependencies run: | python3 -m pip install --upgrade pip - python3 -m pip install setuptools ansicolors sslcrypto + python3 -m pip install setuptools + python3 -m pip install ansicolors sslcrypto if [ -f requirements.txt ]; then python3 -m pip install -r requirements.txt; fi - name: Prepare Build Folders From 603e288c4f2b8c138b6a46e9bf74eaa69d7956ba Mon Sep 17 00:00:00 2001 From: iceman1001 Date: Tue, 23 Feb 2021 21:53:31 +0100 Subject: [PATCH 58/58] path updates --- tools/pm3_amii_bin2eml.pl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/pm3_amii_bin2eml.pl b/tools/pm3_amii_bin2eml.pl index c8e8d4f46..f15b0de75 100755 --- a/tools/pm3_amii_bin2eml.pl +++ b/tools/pm3_amii_bin2eml.pl @@ -14,8 +14,8 @@ my $UIDLOC = -540; # UID is 540 bytes from the end my $BLOCKSIZE = 4; # in bytes -my $AMIITOOL = '../client/amiitool/amiitool'; # path to amiitool (unless in $PATH) -my $KEYFILE = '../client/amiitool/key_retail.bin'; # path to retail key file +my $AMIITOOL = '../client/deps/amiitool/amiitool'; # path to amiitool (unless in $PATH) +my $KEYFILE = '../client/resources/key_retail.bin'; # path to retail key file my $ADDHDR = 1; # add 56 byte header? my $FIXPWD = 1; # recalculate PWD if dump value is 0 my $FIXACK = 1; # set ACK if dump value is 0