From 38332d2fcf04f019a4001ae483f8c5db52d67d08 Mon Sep 17 00:00:00 2001
From: iceman1001 <iceman@iuse.se>
Date: Mon, 4 Jan 2021 11:11:05 +0100
Subject: [PATCH] hf mfu otptear/pwdgen - now supports cliparser

---
 client/src/cmdhfmfu.c  | 289 +++++++++++++++++++----------------------
 doc/cliparser_todo.txt |  15 ---
 2 files changed, 137 insertions(+), 167 deletions(-)

diff --git a/client/src/cmdhfmfu.c b/client/src/cmdhfmfu.c
index b29c7ab26..9c0534c75 100644
--- a/client/src/cmdhfmfu.c
+++ b/client/src/cmdhfmfu.c
@@ -42,45 +42,6 @@
 
 static int CmdHelp(const char *Cmd);
 
-
-
-static int usage_hf_mfu_pwdgen(void) {
-    PrintAndLogEx(NORMAL, "Usage:  hf mfu pwdgen [h|t] [r] <uid (14 hex symbols)>");
-    PrintAndLogEx(NORMAL, "Options:");
-    PrintAndLogEx(NORMAL, "    h       : this help");
-    PrintAndLogEx(NORMAL, "    t       : selftest");
-    PrintAndLogEx(NORMAL, "    r       : read uid from tag");
-    PrintAndLogEx(NORMAL, "    <uid>   : 7 byte UID (optional)");
-    PrintAndLogEx(NORMAL, "Examples:");
-    PrintAndLogEx(NORMAL, _YELLOW_("        hf mfu pwdgen r"));
-    PrintAndLogEx(NORMAL, _YELLOW_("        hf mfu pwdgen 11223344556677"));
-    PrintAndLogEx(NORMAL, _YELLOW_("        hf mfu pwdgen t"));
-    PrintAndLogEx(NORMAL, "");
-    return PM3_SUCCESS;
-}
-
-static int usage_hf_mfu_otp_tearoff(void) {
-    PrintAndLogEx(NORMAL, "Tear-off test against OTP block (no 3) on MFU tags - More help sooner or later\n");
-    PrintAndLogEx(NORMAL, "Usage:  hf mfu otptear b <block number> i <intervalTime> l <limitTime> s <startTime> d <data before> t <data after>\n");
-    PrintAndLogEx(NORMAL, "Options:");
-    PrintAndLogEx(NORMAL, "  b <no>    : (optional) block to run the test -  default block: 8 (not OTP for safety)");
-    PrintAndLogEx(NORMAL, "  i <time>  : (optional) time interval to increase in each test - default 500 us");
-    PrintAndLogEx(NORMAL, "  l <time>  : (optional) limit time to run the test - default 3000 us");
-    PrintAndLogEx(NORMAL, "  s <time>  : (optional) start time to run the test - default 0 us");
-    PrintAndLogEx(NORMAL, "  d <data>  : (optional) data to full-write before trying the OTP test - default 0x00");
-    PrintAndLogEx(NORMAL, "  t <data>  : (optional) data to write while running the OTP test - default 0x00");
-    PrintAndLogEx(NORMAL, "  m <data>  : (optional) exit criteria, if block matches this value");
-    PrintAndLogEx(NORMAL, "");
-    PrintAndLogEx(NORMAL, "Examples:");
-    PrintAndLogEx(NORMAL, "        hf mfu otptear b 3");
-    PrintAndLogEx(NORMAL, "        hf mfu otptear b 8 i 100 l 3000 s 1000");
-    PrintAndLogEx(NORMAL, "        hf mfu otptear b 3 i 1 l 200");
-    PrintAndLogEx(NORMAL, "        hf mfu otptear b 3 i 100 l 2500 s 200 d FFFFFFFF t EEEEEEEE");
-    PrintAndLogEx(NORMAL, "        hf mfu otptear b 3 i 100 l 2500 s 200 d FFFFFFFF t EEEEEEEE m 00000000    -> such quite when OTP is reset");
-    return PM3_SUCCESS;
-}
-
-
 uint8_t default_3des_keys[][16] = {
     { 0x42, 0x52, 0x45, 0x41, 0x4b, 0x4d, 0x45, 0x49, 0x46, 0x59, 0x4f, 0x55, 0x43, 0x41, 0x4e, 0x21 }, // 3des std key
     { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // all zeroes
@@ -2761,14 +2722,39 @@ static int CmdHF14AMfUGenDiverseKeys(const char *Cmd) {
 }
 
 static int CmdHF14AMfUPwdGen(const char *Cmd) {
+    CLIParserContext *ctx;
+    CLIParserInit(&ctx, "hf mfu pwdgen",
+                  "Generate different passwords from known pwdgen algos",
+                  "hf mfu pwdgen -r\n"
+                  "hf mfu pwdgen -t\n"
+                  "hf mfu pwdgen --uid 11223344556677"
+                 );
 
+    void *argtable[] = {
+        arg_param_begin,
+        arg_str0("u", "uid", "<hex>", "uid (7 bytes)"),
+        arg_lit0("r", NULL, "read uid from tag"),
+        arg_lit0("t", NULL, "selftest"),
+        arg_param_end
+    };
+    CLIExecWithReturn(ctx, Cmd, argtable, true);
+
+    int u_len = 0;
     uint8_t uid[7] = {0x00};
-    char cmdp = tolower(param_getchar(Cmd, 0));
-    if (strlen(Cmd) == 0  || cmdp == 'h') return usage_hf_mfu_pwdgen();
+    CLIGetHexWithReturn(ctx, 1, uid, &u_len);
+    bool use_tag = arg_get_lit(ctx, 2);
+    bool selftest = arg_get_lit(ctx, 3);
+    CLIParserFree(ctx);
 
-    if (cmdp == 't') return generator_selftest();
+    if (selftest) 
+        return generator_selftest();
 
-    if (cmdp == 'r') {
+    if (u_len != 7) {
+        PrintAndLogEx(WARNING, "Key must be 7 hex bytes");
+        return PM3_EINVARG;
+    }
+
+    if (use_tag) {
         // read uid from tag
         clearCommandBuffer();
         SendCommandMIX(CMD_HF_ISO14443A_READER, ISO14A_CONNECT | ISO14A_NO_RATS, 0, 0, NULL, 0);
@@ -2791,22 +2777,20 @@ static int CmdHF14AMfUPwdGen(const char *Cmd) {
             return PM3_ESOFT;
         }
         memcpy(uid, card.uid, sizeof(uid));
-    } else {
-        if (param_gethex(Cmd, 0, uid, 14)) return usage_hf_mfu_pwdgen();
     }
 
-    PrintAndLogEx(NORMAL, "---------------------------------");
-    PrintAndLogEx(NORMAL, " Using UID : %s", sprint_hex(uid, 7));
-    PrintAndLogEx(NORMAL, "---------------------------------");
-    PrintAndLogEx(NORMAL, " algo | pwd      | pack");
-    PrintAndLogEx(NORMAL, "------+----------+-----");
-    PrintAndLogEx(NORMAL, " EV1  | %08X | %04X", ul_ev1_pwdgenA(uid), ul_ev1_packgenA(uid));
-    PrintAndLogEx(NORMAL, " Ami  | %08X | %04X", ul_ev1_pwdgenB(uid), ul_ev1_packgenB(uid));
-    PrintAndLogEx(NORMAL, " LD   | %08X | %04X", ul_ev1_pwdgenC(uid), ul_ev1_packgenC(uid));
-    PrintAndLogEx(NORMAL, " XYZ  | %08X | %04X", ul_ev1_pwdgenD(uid), ul_ev1_packgenD(uid));
-    PrintAndLogEx(NORMAL, "------+----------+-----");
-    PrintAndLogEx(NORMAL, " Vingcard algo");
-    PrintAndLogEx(NORMAL, "--------------------");
+    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, " Vingcard algo");
+    PrintAndLogEx(INFO, "--------------------");
     return PM3_SUCCESS;
 }
 
@@ -2815,85 +2799,87 @@ static int CmdHF14AMfUPwdGen(const char *Cmd) {
 // Moebius et al
 //
 static int CmdHF14AMfuOtpTearoff(const char *Cmd) {
-    uint8_t blockNoUint = 8;
-    uint8_t cmdp = 0;
-    bool errors = 0, use_match = false;
-    uint8_t match[4] = {0x00};
-    uint8_t teardata[8] = {0x00};
-    uint32_t interval = 500; // time in us
-    uint32_t timeLimit = 3000; // time in us
-    uint32_t startTime = 0; // time in us
+    CLIParserContext *ctx;
+    CLIParserInit(&ctx, "hf mfu otptear",
+                  "Tear-off test against OTP block",
+                  "hf mfu otptear -b 3\n"
+                  "hf mfu otptear -b 3 -i 100 -s 1000\n"
+                  "hf mfu otptear -b 3 -i 1 -e 200\n"
+                  "hf mfu otptear -b 3 -i 100 -s 200 -e 2500 -d FFFFFFFF -t EEEEEEEE\n"
+                  "hf mfu otptear -b 3 -i 100 -s 200 -e 2500 -d FFFFFFFF -t EEEEEEEE -m 00000000    -> quite when OTP is reset"
+                 );
 
-    while (param_getchar(Cmd, cmdp) != 0x00 && !errors) {
-        switch (tolower(param_getchar(Cmd, cmdp))) {
-            case 'h':
-                return usage_hf_mfu_otp_tearoff();
-            case 'b':
-                blockNoUint = param_get8(Cmd, cmdp + 1);
-                if (blockNoUint < 2) {
-                    PrintAndLogEx(WARNING, "Wrong block number");
-                    errors = true;
-                }
-                cmdp += 2;
-                break;
-            case 'i':
-                interval = param_get32ex(Cmd, cmdp + 1, interval, 10);
-                cmdp += 2;
-                break;
-            case 'l':
-                timeLimit = param_get32ex(Cmd, cmdp + 1, timeLimit, 10);
-                if (timeLimit < interval) {
-                    PrintAndLogEx(WARNING, "Wrong time limit number");
-                    errors = true;
-                }
-                if (timeLimit > 43000) {
-                    PrintAndLogEx(WARNING, "You can't set delay out of 1..43000 range!");
-                    errors = true;
-                }
-                cmdp += 2;
-                break;
-            case 's':
-                startTime = param_get32ex(Cmd, cmdp + 1, 0, 10);
-                if (startTime > (timeLimit - interval)) {
-                    PrintAndLogEx(WARNING, "Wrong start time number");
-                    errors = true;
-                }
-                cmdp += 2;
-                break;
-            case 'd':
-                if (param_gethex(Cmd, cmdp + 1, teardata, 8)) {
-                    PrintAndLogEx(WARNING, "Block data must include 8 HEX symbols");
-                    errors = true;
-                }
-                cmdp += 2;
-                break;
-            case 't':
-                if (param_gethex(Cmd, cmdp + 1, teardata + 4, 8)) {
-                    PrintAndLogEx(WARNING, "Block data must include 8 HEX symbols");
-                    errors = true;
-                }
-                cmdp += 2;
-                break;
-            case 'm':
-                if (param_gethex(Cmd, cmdp + 1, match, 8)) {
-                    PrintAndLogEx(WARNING, "Block data must include 8 HEX symbols");
-                    errors = true;
-                }
-                use_match = true;
-                cmdp += 2;
-                break;
-            default:
-                PrintAndLogEx(WARNING, "Unknown parameter '%c'", param_getchar(Cmd, cmdp));
-                errors = true;
-                break;
-        }
+    void *argtable[] = {
+        arg_param_begin,
+        arg_u64_0("b", "blk", "<dec>", "target block (def 8)"),
+        arg_u64_0("i", "inc", "<dec>", "increase time steps (def 500 us)"),
+        arg_u64_0("e", "end", "<dec>", "end time (def 3000 us)"),
+        arg_u64_0("s", "start", "<dec>", "start time (def 0 us)"),
+        arg_str0("d", "data", "<hex>", "initialise data before run (4 bytes)"),
+        arg_str0("t", "test", "<hex>", "test write data (4 bytes)"),
+        arg_str0("m", "match", "<hex>", "exit criteria, if block matches this value (4 bytes)"),
+        arg_param_end
+    };
+    CLIExecWithReturn(ctx, Cmd, argtable, true);
+
+    uint8_t blockno = arg_get_u32_def(ctx, 1, 8);
+    uint32_t steps = arg_get_u32_def(ctx, 2, 500);
+    uint32_t end = arg_get_u32_def(ctx, 3, 3000);
+    uint32_t start = arg_get_u32_def(ctx, 4, 0);
+
+    int d_len = 0;
+    uint8_t data[4] = {0x00};
+    CLIGetHexWithReturn(ctx, 5, data, &d_len);
+
+    int t_len = 0;
+    uint8_t test[4] = {0x00};
+    CLIGetHexWithReturn(ctx, 6, test, &t_len);
+
+    int m_len = 0;
+    uint8_t match[4] = {0x00};
+    CLIGetHexWithReturn(ctx, 7, match, &m_len);
+    bool use_match = (m_len > 0);
+    CLIParserFree(ctx);
+
+    if (blockno < 2) {
+        PrintAndLogEx(WARNING, "Block number must be larger than 2.");
+        return PM3_EINVARG;
+    }
+    if (end < steps) {
+        PrintAndLogEx(WARNING, "end time smaller than increase value");
+        return PM3_EINVARG;
+    }
+    if (end > 43000) {
+        PrintAndLogEx(WARNING, "end time - out of 1 .. 43000 range");
+        return PM3_EINVARG;
+    }
+    if (start > (end - steps)) {
+        PrintAndLogEx(WARNING, "Start time larger then (end time + steps)");
+        return PM3_EINVARG;
     }
 
-    if (errors) return usage_hf_mfu_otp_tearoff();
+    if (d_len && d_len != 4) {
+        PrintAndLogEx(WARNING, "data must be 4 hex bytes");
+        return PM3_EINVARG;
+    }
+
+    if (t_len && t_len != 4) {
+        PrintAndLogEx(WARNING, "test data must be 4 hex bytes");
+        return PM3_EINVARG;
+    }
+
+    if (m_len && m_len != 4) {
+        PrintAndLogEx(WARNING, "match data must be 4 hex bytes");
+        return PM3_EINVARG;
+    }
+
+   uint8_t teardata[8] = {0x00};
+   memcpy(teardata, data, sizeof(data));
+   memcpy(teardata + sizeof(data), test, sizeof(test));
 
     PrintAndLogEx(INFO, "----------------- " _CYAN_("MFU Tear off") " ---------------------");
     PrintAndLogEx(INFO, "Starting Tear-off test");
-    PrintAndLogEx(INFO, "Target block no: %u", blockNoUint);
+    PrintAndLogEx(INFO, "Target block no: %u", blockno);
     PrintAndLogEx(INFO, "Target inital block data : %s", sprint_hex_inrow(teardata, 4));
     PrintAndLogEx(INFO, "Target write block data  : %s", sprint_hex_inrow(teardata + 4, 4));
     PrintAndLogEx(INFO, "----------------------------------------------------");
@@ -2901,23 +2887,22 @@ static int CmdHF14AMfuOtpTearoff(const char *Cmd) {
     bool got_pre = false, got_post = false, lock_on = false;
     uint8_t pre[4] = {0};
     uint8_t post[4] = {0};
-    uint32_t actualTime = startTime;
-
+    uint32_t current = start;
     int phase_clear = -1;
     int phase_newwr = -1;
-
     uint8_t retries = 0;
-    while (actualTime <= (timeLimit - interval)) {
+
+    while (current <= (end - steps)) {
 
         if (kbd_enter_pressed()) {
             PrintAndLogEx(INFO, "\naborted via keyboard!\n");
             break;
         }
 
-        PrintAndLogEx(INFO, "Using tear-off delay " _GREEN_("%" PRIu32) " us", actualTime);
+        PrintAndLogEx(INFO, "Using tear-off delay " _GREEN_("%" PRIu32) " us", current);
 
         clearCommandBuffer();
-        SendCommandMIX(CMD_HF_MIFAREU_READBL, blockNoUint, 0, 0, NULL, 0);
+        SendCommandMIX(CMD_HF_MIFAREU_READBL, blockno, 0, 0, NULL, 0);
         PacketResponseNG resp;
 
         got_pre = false;
@@ -2930,7 +2915,7 @@ static int CmdHF14AMfuOtpTearoff(const char *Cmd) {
         }
 
         clearCommandBuffer();
-        SendCommandMIX(CMD_HF_MFU_OTP_TEAROFF, blockNoUint, actualTime, 0, teardata, 8);
+        SendCommandMIX(CMD_HF_MFU_OTP_TEAROFF, blockno, current, 0, teardata, 8);
 
         // we be getting ACK that we are silently ignoring here..
 
@@ -2946,7 +2931,7 @@ static int CmdHF14AMfuOtpTearoff(const char *Cmd) {
 
         got_post = false;
         clearCommandBuffer();
-        SendCommandMIX(CMD_HF_MIFAREU_READBL, blockNoUint, 0, 0, NULL, 0);
+        SendCommandMIX(CMD_HF_MIFAREU_READBL, blockno, 0, 0, NULL, 0);
         if (WaitForResponseTimeout(CMD_ACK, &resp, 1500)) {
             isOK = resp.oldarg[0] & 0xFF;
             if (isOK) {
@@ -2965,19 +2950,19 @@ static int CmdHF14AMfuOtpTearoff(const char *Cmd) {
             if (memcmp(pre, post, sizeof(pre)) == 0) {
 
                 PrintAndLogEx(INFO, "Current %02d (0x%02X) %s"
-                              , blockNoUint
-                              , blockNoUint
+                              , blockno
+                              , blockno
                               , poststr
                              );
             } else {
 
                 // skip first message, since its the reset write.
-                if (actualTime == startTime) {
+                if (current == start) {
                     PrintAndLogEx(INFO, "Inital write");
                 } else {
                     PrintAndLogEx(INFO, _CYAN_("Tear off occured") " : %02d (0x%02X) %s vs " _RED_("%s")
-                                  , blockNoUint
-                                  , blockNoUint
+                                  , blockno
+                                  , blockno
                                   , prestr
                                   , poststr
                                  );
@@ -2985,11 +2970,11 @@ static int CmdHF14AMfuOtpTearoff(const char *Cmd) {
                     lock_on = true;
 
                     if (phase_clear == -1)
-                        phase_clear = actualTime;
+                        phase_clear = current;
 
                     // new write phase must be atleast 100us later..
-                    if (phase_clear > -1 && phase_newwr == -1 && actualTime > (phase_clear + 100))
-                        phase_newwr = actualTime;
+                    if (phase_clear > -1 && phase_newwr == -1 && current > (phase_clear + 100))
+                        phase_newwr = current;
                 }
             }
 
@@ -3017,14 +3002,14 @@ static int CmdHF14AMfuOtpTearoff(const char *Cmd) {
                     PrintAndLogEx(NORMAL, "---------------------------------\n");
                 }
         */
-        if (startTime != timeLimit) {
-            actualTime += interval;
+        if (start != end) {
+            current += steps;
         } else {
             if (lock_on == false) {
                 if (++retries == 20) {
-                    actualTime++;
-                    timeLimit++;
-                    startTime++;
+                    current++;
+                    end++;
+                    start++;
                     retries = 0;
                     PrintAndLogEx(INFO, _CYAN_("Retried %u times, increased delay with 1us"), retries);
                 }
@@ -3603,7 +3588,7 @@ static command_t CommandTable[] = {
     {"keygen",  CmdHF14AMfUGenDiverseKeys, AlwaysAvailable, "Generate 3DES MIFARE diversified keys"},
     {"pwdgen",  CmdHF14AMfUPwdGen,         AlwaysAvailable, "Generate pwd from known algos"},
     {"otptear", CmdHF14AMfuOtpTearoff,     IfPm3Iso14443a,  "Tear-off test on OTP bits"},
-//    {"countertear", CmdHF14AMfuEv1CounterTearoff,     IfPm3Iso14443a,  "Tear-off test on Ev1 Counter bits"},
+//    {"tear_cnt", CmdHF14AMfuEv1CounterTearoff,     IfPm3Iso14443a,  "Tear-off test on Ev1/NTAG Counter bits"},
     {"-----------", CmdHelp,                IfPm3Iso14443a,  "----------------------- " _CYAN_("operations") " -----------------------"},
     {"cauth",   CmdHF14AMfUCAuth,          IfPm3Iso14443a,  "Authentication - Ultralight-C"},
     {"dump",    CmdHF14AMfUDump,           IfPm3Iso14443a,  "Dump MIFARE Ultralight family tag to binary file"},
diff --git a/doc/cliparser_todo.txt b/doc/cliparser_todo.txt
index 7f5643b2f..1b2241b72 100644
--- a/doc/cliparser_todo.txt
+++ b/doc/cliparser_todo.txt
@@ -102,22 +102,7 @@ hf mf gen3uid
 hf mf gen3blk
 hf mf gen3freeze
 hf mf ice
-hf mfu info
-hf mfu dump
-hf mfu restore
-hf mfu eload
-hf mfu rdbl
-hf mfu wrbl
-hf mfu cauth
-hf mfu setpwd
-hf mfu setuid
-hf mfu sim
-hf mfu gen
-hf mfu pwdgen
-hf mfu otptear
-hf mfdes enum
 hf mfdes getuid
-hf mfdes info
 hw connect
 hw dbg
 hw detectreader