From 45fea410844bd5ab3429693adccbd633c2876839 Mon Sep 17 00:00:00 2001 From: iceman1001 Date: Wed, 17 Feb 2021 07:32:38 +0100 Subject: [PATCH 1/8] 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 2/8] 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 3/8] 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 4/8] 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 5/8] 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 6/8] ..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 7/8] 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 8/8] 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")); }