From 5c5a53963a36fade8c6ad37d4ab207506ad312a1 Mon Sep 17 00:00:00 2001
From: nvx <neovortex@gmail.com>
Date: Fri, 22 Jul 2022 13:52:09 +1000
Subject: [PATCH 1/5] Fixed incorrect card config bit being checked for iClass
 key access flag

---
 CHANGELOG.md             | 1 +
 client/src/cmdhficlass.c | 4 ++--
 2 files changed, 3 insertions(+), 2 deletions(-)

diff --git a/CHANGELOG.md b/CHANGELOG.md
index 9757a2952..4584826d2 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -3,6 +3,7 @@ All notable changes to this project will be documented in this file.
 This project uses the changelog in accordance with [keepchangelog](http://keepachangelog.com/). Please use this to write notable changes, which is not the same as git commit log...
 
 ## [unreleased][unreleased]
+ - Fixed `hf iclass info` and `hf iclass view` key access info looking at the wrong card config bit (@nvx)
  - Added `hf gallagher decode` command and fix Gallagher diversification for card master key (@nvx)
  - Added mmbit-002 (kibi-002, kb5004xk1) russian tag to `hf texkom read` command (@merlokk)
  - Added `hf sniff --smode` skip/group adc data to consume less memory. Now it can sniff very long signals (@merlokk)
diff --git a/client/src/cmdhficlass.c b/client/src/cmdhficlass.c
index ea16de75c..03f9a4b3a 100644
--- a/client/src/cmdhficlass.c
+++ b/client/src/cmdhficlass.c
@@ -588,8 +588,8 @@ static void mem_app_config(const picopass_hdr_t *hdr) {
 
     PrintAndLogEx(INFO, "------------------------- " _CYAN_("KeyAccess") " ------------------------");
     PrintAndLogEx(INFO, " * Kd, Debit key, AA1    Kc, Credit key, AA2 *");
-    uint8_t book = isset(mem, 0x20);
-    if (book) {
+    uint8_t keyAccess = isset(mem, 0x01);
+    if (keyAccess) {
         PrintAndLogEx(INFO, "    Read A....... debit");
         PrintAndLogEx(INFO, "    Read B....... credit");
         PrintAndLogEx(INFO, "    Write A...... debit");

From eb6b170e51b25e95400a58bb9b4b7a2607b8e0e6 Mon Sep 17 00:00:00 2001
From: nvx <neovortex@gmail.com>
Date: Fri, 22 Jul 2022 13:48:34 +1000
Subject: [PATCH 2/5] Changed `hf iclass list` to display matched keys on the
 CHECK command rather than the card response, and made it check for elite keys
 too

---
 CHANGELOG.md             |  1 +
 client/src/cmdhficlass.c | 11 ++++++-----
 client/src/cmdhflist.c   | 15 +++++++++------
 3 files changed, 16 insertions(+), 11 deletions(-)

diff --git a/CHANGELOG.md b/CHANGELOG.md
index 9757a2952..ce9be2aa5 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]
+ - Changed `hf iclass list` to display matched keys on the CHECK command rather than the card response, and made it check for elite keys too (@nvx)
  - Added `hf gallagher decode` command and fix Gallagher diversification for card master key (@nvx)
  - Added mmbit-002 (kibi-002, kb5004xk1) russian tag to `hf texkom read` command (@merlokk)
  - Added `hf sniff --smode` skip/group adc data to consume less memory. Now it can sniff very long signals (@merlokk)
diff --git a/client/src/cmdhficlass.c b/client/src/cmdhficlass.c
index ea16de75c..6836df754 100644
--- a/client/src/cmdhficlass.c
+++ b/client/src/cmdhficlass.c
@@ -87,7 +87,7 @@ static int cmp_uint32(const void *a, const void *b) {
 
 bool check_known_default(uint8_t *csn, uint8_t *epurse, uint8_t *rmac, uint8_t *tmac, uint8_t *key) {
 
-    iclass_prekey_t *prekey = calloc(ICLASS_KEYS_MAX, sizeof(iclass_prekey_t));
+    iclass_prekey_t *prekey = calloc(ICLASS_KEYS_MAX * 2, sizeof(iclass_prekey_t));
     if (prekey == NULL) {
         return false;
     }
@@ -97,17 +97,20 @@ bool check_known_default(uint8_t *csn, uint8_t *epurse, uint8_t *rmac, uint8_t *
     memcpy(ccnr + 8, rmac, 4);
 
     GenerateMacKeyFrom(csn, ccnr, false, false, (uint8_t *)iClass_Key_Table, ICLASS_KEYS_MAX, prekey);
-    qsort(prekey, ICLASS_KEYS_MAX, sizeof(iclass_prekey_t), cmp_uint32);
+    GenerateMacKeyFrom(csn, ccnr, false, true, (uint8_t *)iClass_Key_Table, ICLASS_KEYS_MAX, prekey + ICLASS_KEYS_MAX);
+    qsort(prekey, ICLASS_KEYS_MAX * 2, sizeof(iclass_prekey_t), cmp_uint32);
 
     iclass_prekey_t lookup;
     memcpy(lookup.mac, tmac, 4);
 
     // binsearch
-    iclass_prekey_t *item = (iclass_prekey_t *) bsearch(&lookup, prekey, ICLASS_KEYS_MAX, sizeof(iclass_prekey_t), cmp_uint32);
+    iclass_prekey_t *item = (iclass_prekey_t *) bsearch(&lookup, prekey, ICLASS_KEYS_MAX * 2, sizeof(iclass_prekey_t), cmp_uint32);
     if (item != NULL) {
         memcpy(key, item->key, 8);
+        free(prekey);
         return true;
     }
+    free(prekey);
     return false;
 }
 
@@ -3534,8 +3537,6 @@ void GenerateMacKeyFrom(uint8_t *CSN, uint8_t *CCNR, bool use_raw, bool use_elit
 
     for (int i = 0; i < iclass_tc; i++)
         pthread_join(threads[i], NULL);
-
-    PrintAndLogEx(NORMAL, "");
 }
 
 // print diversified keys
diff --git a/client/src/cmdhflist.c b/client/src/cmdhflist.c
index 7e79b49ee..f326a8abb 100644
--- a/client/src/cmdhflist.c
+++ b/client/src/cmdhflist.c
@@ -464,10 +464,17 @@ void annotateIclass(char *exp, size_t size, uint8_t *cmd, uint8_t cmdsize, bool
                 curr_state = PICO_NONE;
                 break;
             case ICLASS_CMD_CHECK:
-                snprintf(exp, size, "CHECK");
                 curr_state = PICO_AUTH_MACS;
                 memcpy(rmac, cmd + 1, 4);
                 memcpy(tmac, cmd + 5, 4);
+
+                uint8_t key[8];
+                if (check_known_default(csn, epurse, rmac, tmac, key)) {
+                    snprintf(exp, size, "CHECK ( %s )", sprint_hex_inrow(key, 8));
+                } else {
+                    snprintf(exp, size, "CHECK");
+                }
+
                 break;
             case ICLASS_CMD_READ4:
                 snprintf(exp, size, "READ4(%d)", cmd[1]);
@@ -516,11 +523,7 @@ void annotateIclass(char *exp, size_t size, uint8_t *cmd, uint8_t cmdsize, bool
         } else if (curr_state == PICO_AUTH_EPURSE) {
             memcpy(epurse, cmd, 8);
         } else if (curr_state == PICO_AUTH_MACS) {
-
-            uint8_t key[8];
-            if (check_known_default(csn, epurse, rmac, tmac, key)) {
-                snprintf(exp, size, "( " _GREEN_("%s") " )", sprint_hex_inrow(key, 8));
-            }
+            snprintf(exp, size, _GREEN_("CHECK SUCCESS"));
             curr_state = PICO_NONE;
         }
     }

From 30cc57d3aa33abae1dbe99a003854b3556159cb0 Mon Sep 17 00:00:00 2001
From: nvx <neovortex@gmail.com>
Date: Fri, 22 Jul 2022 14:06:47 +1000
Subject: [PATCH 3/5] Fix some bugs in the iClass SIO detection and printing

---
 client/src/cmdhficlass.c | 63 ++++++++++++++++++----------------------
 1 file changed, 28 insertions(+), 35 deletions(-)

diff --git a/client/src/cmdhficlass.c b/client/src/cmdhficlass.c
index ea16de75c..c562263f0 100644
--- a/client/src/cmdhficlass.c
+++ b/client/src/cmdhficlass.c
@@ -2443,8 +2443,9 @@ static int CmdHFiClass_loclass(const char *Cmd) {
 }
 
 static void detect_credential(uint8_t *data, bool *legacy, bool *se, bool *sr) {
-    char* r1 = strstr((char*)data + (5 * 8), "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF");
-    char* r2 = strstr((char*)data + (11 * 8), "\x05\x00\x05\x00");
+    bool r1 = !memcmp(data + (5 * 8), "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF", 8);
+    uint8_t pattern[] = {0x05, 0x00, 0x05, 0x00};
+    bool r2 = byte_strstr(data + (11 * 8), 6 * 8, pattern, sizeof(pattern)) != -1;
 
     *legacy = (r1) && (data[6 * 8] != 0x30);
     *se = (r2) && (data[6 * 8] == 0x30);
@@ -2458,40 +2459,31 @@ static void printIclassSIO(uint8_t *iclass_dump) {
     bool isLegacy, isSE, isSR;
     detect_credential(iclass_dump, &isLegacy, &isSE, &isSR);
 
-    uint8_t pattern[] = {0x05, 0x00, 0x05, 0x00};
+    uint8_t *sio_start;
     if (isSE) {
-
-        int dlen = byte_strstr(iclass_dump + (6 * 8), 8*8, pattern, sizeof(pattern));
-        if (dlen) {
-
-            dlen += sizeof(pattern);
-
-            PrintAndLogEx(NORMAL, "");
-            PrintAndLogEx(INFO, "---------------------------- " _CYAN_("SIO - RAW") " ----------------------------");
-            print_hex_noascii_break(iclass_dump + (6*8), dlen, 32);
-            PrintAndLogEx(NORMAL, "");
-            PrintAndLogEx(INFO, "------------------------- " _CYAN_("SIO - ASN1 TLV") " --------------------------");
-            asn1_print(iclass_dump + (6 * 8), dlen, "  ");
-            PrintAndLogEx(NORMAL, "");
-        }
+        sio_start = iclass_dump + (6 * 8);
+    } else if (isSR) {
+        sio_start = iclass_dump + (10 * 8);
+    } else {
+        return;
     }
 
-    if (isSR) {
-
-        int dlen = byte_strstr(iclass_dump + (10 * 8), 8*8, pattern, sizeof(pattern));
-
-        if (dlen) {
-            dlen += sizeof(pattern);
-
-            PrintAndLogEx(NORMAL, "");
-            PrintAndLogEx(INFO, "---------------------------- " _CYAN_("SIO - RAW") " ----------------------------");
-            print_hex_noascii_break(iclass_dump + (10*8), dlen, 32);
-            PrintAndLogEx(NORMAL, "");
-            PrintAndLogEx(INFO, "------------------------- " _CYAN_("SIO - ASN1 TLV") " --------------------------");
-            asn1_print(iclass_dump + (10 * 8), dlen, "  ");
-            PrintAndLogEx(NORMAL, "");
-        }
+    uint8_t pattern[] = {0x05, 0x00, 0x05, 0x00};
+    int dlen = byte_strstr(sio_start, 8 * 8, pattern, sizeof(pattern));
+    if (dlen == -1) {
+        return;
     }
+
+    dlen += sizeof(pattern);
+
+    PrintAndLogEx(NORMAL, "");
+    PrintAndLogEx(INFO, "---------------------------- " _CYAN_("SIO - RAW") " ----------------------------");
+    print_hex_noascii_break(sio_start, dlen, 32);
+    PrintAndLogEx(NORMAL, "");
+    PrintAndLogEx(INFO, "------------------------- " _CYAN_("SIO - ASN1 TLV") " --------------------------");
+    asn1_print(sio_start, dlen, "  ");
+    PrintAndLogEx(NORMAL, "");
+
 }
 
 void printIclassDumpContents(uint8_t *iclass_dump, uint8_t startblock, uint8_t endblock, size_t filesize) {
@@ -2536,8 +2528,10 @@ void printIclassDumpContents(uint8_t *iclass_dump, uint8_t startblock, uint8_t e
     */
     uint8_t pagemap = get_pagemap(hdr);
 
-    bool isLegacy, isSE, isSR;
-    detect_credential(iclass_dump, &isLegacy, &isSE, &isSR);
+    bool isLegacy = false, isSE = false, isSR = false;
+    if (filemaxblock >= 17) {
+        detect_credential(iclass_dump, &isLegacy, &isSE, &isSR);
+    }
 
     int i = startblock;
     PrintAndLogEx(NORMAL, "");
@@ -4127,4 +4121,3 @@ int info_iclass(void) {
 
     return PM3_SUCCESS;
 }
-

From 881c32e0be7503066edcd32f2aa5d2766e1fcefd Mon Sep 17 00:00:00 2001
From: iceman1001 <iceman@iuse.se>
Date: Fri, 22 Jul 2022 09:47:11 +0200
Subject: [PATCH 4/5] change  - added desfire product type identification

---
 client/src/cmdhfmfdes.c | 53 ++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 52 insertions(+), 1 deletion(-)

diff --git a/client/src/cmdhfmfdes.c b/client/src/cmdhfmfdes.c
index af8726298..2993c8def 100644
--- a/client/src/cmdhfmfdes.c
+++ b/client/src/cmdhfmfdes.c
@@ -149,6 +149,15 @@ typedef enum {
     NTAG413DNA,
 } nxp_cardtype_t;
 
+typedef enum {
+    DESFIRE_UNKNOWN_PROD = 0,
+    DESFIRE_PHYSICAL,
+    DESFIRE_LIGHT_PHYSICAL,
+    DESFIRE_MICROCONTROLLER,
+    DESFIRE_JAVACARD,
+    DESFIRE_HCE,
+} nxp_producttype_t;
+
 typedef struct dfname {
     uint8_t aid[3];
     uint8_t fid[2];
@@ -298,6 +307,43 @@ static nxp_cardtype_t getCardType(uint8_t major, uint8_t minor) {
     return DESFIRE_UNKNOWN;
 }
 
+// ref:  https://www.nxp.com/docs/en/application-note/AN12343.pdf  p7
+static nxp_producttype_t getProductType(uint8_t *versionhw) {
+
+    uint8_t product = versionhw[2];
+
+    if (product == 0x01)
+        return DESFIRE_PHYSICAL;
+    if (product == 0x08)
+        return DESFIRE_LIGHT_PHYSICAL;
+    if (product == 0x81 || product == 0x83)
+        return DESFIRE_MICROCONTROLLER;
+    if (product == 0x91)
+        return DESFIRE_JAVACARD;
+    if (product == 0xA1)
+        return DESFIRE_HCE;
+    return DESFIRE_UNKNOWN_PROD;
+}
+
+static const char* getProductTypeStr(uint8_t *versionhw) {
+
+    uint8_t product = versionhw[2];
+
+    if (product == 0x01)
+        return "MIFARE DESFire native IC (physical card)";
+    if (product == 0x08)
+        return "MIFARE DESFire Light native IC (physical card)";
+    if (product == 0x81 || product == 0x83)
+        return "MIFARE DESFire implementation on microcontroller (physical card)";
+    if (product == 0x91)
+        return "MIFARE DESFire applet on Java card / secure element";
+    if (product == 0xA1)
+        return "MIFARE DESFire HCE (MIFARE 2GO)";
+    return "UNKNOWN PROD";
+}
+
+
+
 static int mfdes_get_info(mfdes_info_res_t *info) {
     SendCommandNG(CMD_HF_DESFIRE_INFO, NULL, 0);
     PacketResponseNG resp;
@@ -627,6 +673,12 @@ static int CmdHF14ADesInfo(const char *Cmd) {
     PrintAndLogEx(SUCCESS, "              UID: " _GREEN_("%s"), sprint_hex(info.uid, info.uidlen));
     PrintAndLogEx(SUCCESS, "     Batch number: " _GREEN_("%s"), sprint_hex(info.details + 7, 5));
     PrintAndLogEx(SUCCESS, "  Production date: week " _GREEN_("%02x") " / " _GREEN_("20%02x"), info.details[12], info.details[13]);
+
+    nxp_producttype_t prodtype = getProductType(info.versionHW);
+    if (prodtype != DESFIRE_UNKNOWN_PROD) {
+        PrintAndLogEx(SUCCESS, "     Product type: %s", getProductTypeStr(info.versionHW));
+    }
+
     PrintAndLogEx(NORMAL, "");
     PrintAndLogEx(INFO, "--- " _CYAN_("Hardware Information"));
     PrintAndLogEx(INFO, "   raw: %s", sprint_hex_inrow(info.versionHW, sizeof(info.versionHW)));
@@ -646,7 +698,6 @@ static int CmdHF14ADesInfo(const char *Cmd) {
     PrintAndLogEx(INFO, "       Version: " _YELLOW_("%d.%d"),  info.versionSW[3], info.versionSW[4]);
     PrintAndLogEx(INFO, "  Storage size: %s", getCardSizeStr(info.versionSW[5]));
     PrintAndLogEx(INFO, "      Protocol: %s", getProtocolStr(info.versionSW[6], false));
-
     PrintAndLogEx(NORMAL, "");
     PrintAndLogEx(INFO, "--------------------------------- " _CYAN_("Card capabilities") " ---------------------------------");
     uint8_t major = info.versionSW[3];

From 8cfbe6657b5bd3dc8646baee5c1e42cc84bebf9b Mon Sep 17 00:00:00 2001
From: Nathaniel McHugh <nathaniel@tutorful.co.uk>
Date: Fri, 22 Jul 2022 21:18:51 +0100
Subject: [PATCH 5/5] Add Paxton hitag2 password

---
 client/dictionaries/ht2_default.dic | 1 +
 1 file changed, 1 insertion(+)

diff --git a/client/dictionaries/ht2_default.dic b/client/dictionaries/ht2_default.dic
index 2dc816512..f503fa543 100644
--- a/client/dictionaries/ht2_default.dic
+++ b/client/dictionaries/ht2_default.dic
@@ -10,3 +10,4 @@
 25293C2F
 #
 # Paxton HT2
+BDF5E846