From 90573fbeedb36767f35529eea3a063d6f06fa6a1 Mon Sep 17 00:00:00 2001 From: Tiernan Date: Wed, 28 Dec 2022 23:04:58 +1000 Subject: [PATCH] Picopass read bug fixes: (#2201) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * fix checking user elite keys * include calculated Kd when saving cards Co-authored-by: あく --- .../plugins/picopass/picopass_device.h | 3 + .../plugins/picopass/picopass_worker.c | 71 +++++++++++++++---- 2 files changed, 61 insertions(+), 13 deletions(-) diff --git a/applications/plugins/picopass/picopass_device.h b/applications/plugins/picopass/picopass_device.h index 26f21594..150b095a 100644 --- a/applications/plugins/picopass/picopass_device.h +++ b/applications/plugins/picopass/picopass_device.h @@ -18,6 +18,9 @@ #define PICOPASS_CSN_BLOCK_INDEX 0 #define PICOPASS_CONFIG_BLOCK_INDEX 1 +#define PICOPASS_EPURSE_BLOCK_INDEX 2 +#define PICOPASS_KD_BLOCK_INDEX 3 +#define PICOPASS_KC_BLOCK_INDEX 4 #define PICOPASS_AIA_BLOCK_INDEX 5 #define PICOPASS_APP_FOLDER ANY_PATH("picopass") diff --git a/applications/plugins/picopass/picopass_worker.c b/applications/plugins/picopass/picopass_worker.c index bb1e513a..1ee814aa 100644 --- a/applications/plugins/picopass/picopass_worker.c +++ b/applications/plugins/picopass/picopass_worker.c @@ -175,13 +175,12 @@ ReturnCode picopass_read_preauth(PicopassBlock* AA1) { return ERR_NONE; } -ReturnCode picopass_auth(PicopassBlock* AA1, PicopassPacs* pacs) { +static ReturnCode picopass_auth_standard(uint8_t* csn, uint8_t* div_key) { rfalPicoPassReadCheckRes rcRes; rfalPicoPassCheckRes chkRes; ReturnCode err; - uint8_t div_key[8] = {0}; uint8_t mac[4] = {0}; uint8_t ccnr[12] = {0}; @@ -192,26 +191,34 @@ ReturnCode picopass_auth(PicopassBlock* AA1, PicopassPacs* pacs) { } memcpy(ccnr, rcRes.CCNR, sizeof(rcRes.CCNR)); // last 4 bytes left 0 - loclass_diversifyKey(AA1[PICOPASS_CSN_BLOCK_INDEX].data, picopass_iclass_key, div_key); + loclass_diversifyKey(csn, picopass_iclass_key, div_key); loclass_opt_doReaderMAC(ccnr, div_key, mac); - err = rfalPicoPassPollerCheck(mac, &chkRes); - if(err == ERR_NONE) { - return ERR_NONE; - } - FURI_LOG_E(TAG, "rfalPicoPassPollerCheck error %d", err); + return rfalPicoPassPollerCheck(mac, &chkRes); +} - FURI_LOG_E(TAG, "Starting dictionary attack"); +static ReturnCode picopass_auth_dict( + uint8_t* csn, + PicopassPacs* pacs, + uint8_t* div_key, + IclassEliteDictType dict_type) { + rfalPicoPassReadCheckRes rcRes; + rfalPicoPassCheckRes chkRes; + + ReturnCode err = ERR_PARAM; + + uint8_t mac[4] = {0}; + uint8_t ccnr[12] = {0}; size_t index = 0; uint8_t key[PICOPASS_BLOCK_LEN] = {0}; - if(!iclass_elite_dict_check_presence(IclassEliteDictTypeFlipper)) { + if(!iclass_elite_dict_check_presence(dict_type)) { FURI_LOG_E(TAG, "Dictionary not found"); return ERR_PARAM; } - IclassEliteDict* dict = iclass_elite_dict_alloc(IclassEliteDictTypeFlipper); + IclassEliteDict* dict = iclass_elite_dict_alloc(dict_type); if(!dict) { FURI_LOG_E(TAG, "Dictionary not allocated"); return ERR_PARAM; @@ -235,11 +242,11 @@ ReturnCode picopass_auth(PicopassBlock* AA1, PicopassPacs* pacs) { err = rfalPicoPassPollerReadCheck(&rcRes); if(err != ERR_NONE) { FURI_LOG_E(TAG, "rfalPicoPassPollerReadCheck error %d", err); - return err; + break; } memcpy(ccnr, rcRes.CCNR, sizeof(rcRes.CCNR)); // last 4 bytes left 0 - loclass_iclass_calc_div_key(AA1[PICOPASS_CSN_BLOCK_INDEX].data, key, div_key, true); + loclass_iclass_calc_div_key(csn, key, div_key, true); loclass_opt_doReaderMAC(ccnr, div_key, mac); err = rfalPicoPassPollerCheck(mac, &chkRes); @@ -254,6 +261,39 @@ ReturnCode picopass_auth(PicopassBlock* AA1, PicopassPacs* pacs) { return err; } +ReturnCode picopass_auth(PicopassBlock* AA1, PicopassPacs* pacs) { + ReturnCode err; + + FURI_LOG_E(TAG, "Trying standard legacy key"); + err = picopass_auth_standard( + AA1[PICOPASS_CSN_BLOCK_INDEX].data, AA1[PICOPASS_KD_BLOCK_INDEX].data); + if(err == ERR_NONE) { + return ERR_NONE; + } + + FURI_LOG_E(TAG, "Starting user dictionary attack"); + err = picopass_auth_dict( + AA1[PICOPASS_CSN_BLOCK_INDEX].data, + pacs, + AA1[PICOPASS_KD_BLOCK_INDEX].data, + IclassEliteDictTypeUser); + if(err == ERR_NONE) { + return ERR_NONE; + } + + FURI_LOG_E(TAG, "Starting in-built dictionary attack"); + err = picopass_auth_dict( + AA1[PICOPASS_CSN_BLOCK_INDEX].data, + pacs, + AA1[PICOPASS_KD_BLOCK_INDEX].data, + IclassEliteDictTypeFlipper); + if(err == ERR_NONE) { + return ERR_NONE; + } + + return err; +} + ReturnCode picopass_read_card(PicopassBlock* AA1) { ReturnCode err; @@ -262,6 +302,11 @@ ReturnCode picopass_read_card(PicopassBlock* AA1) { PICOPASS_MAX_APP_LIMIT; for(size_t i = 2; i < app_limit; i++) { + if(i == PICOPASS_KD_BLOCK_INDEX) { + // Skip over Kd block which is populated earlier (READ of Kd returns all FF's) + continue; + } + rfalPicoPassReadBlockRes block; err = rfalPicoPassPollerReadBlock(i, &block); if(err != ERR_NONE) {