Picopass standard KDF dictionary (#2478)
* Split iclass dictionaries based on KDF * Allow cancelling during key test Co-authored-by: あく <alleteam@gmail.com>
This commit is contained in:
@@ -5,6 +5,7 @@
|
||||
|
||||
#define ICLASS_ELITE_DICT_FLIPPER_NAME APP_DATA_PATH("assets/iclass_elite_dict.txt")
|
||||
#define ICLASS_ELITE_DICT_USER_NAME APP_DATA_PATH("assets/iclass_elite_dict_user.txt")
|
||||
#define ICLASS_STANDARD_DICT_FLIPPER_NAME APP_DATA_PATH("assets/iclass_standard_dict.txt")
|
||||
|
||||
#define TAG "IclassEliteDict"
|
||||
|
||||
@@ -25,6 +26,9 @@ bool iclass_elite_dict_check_presence(IclassEliteDictType dict_type) {
|
||||
(storage_common_stat(storage, ICLASS_ELITE_DICT_FLIPPER_NAME, NULL) == FSE_OK);
|
||||
} else if(dict_type == IclassEliteDictTypeUser) {
|
||||
dict_present = (storage_common_stat(storage, ICLASS_ELITE_DICT_USER_NAME, NULL) == FSE_OK);
|
||||
} else if(dict_type == IclassStandardDictTypeFlipper) {
|
||||
dict_present =
|
||||
(storage_common_stat(storage, ICLASS_STANDARD_DICT_FLIPPER_NAME, NULL) == FSE_OK);
|
||||
}
|
||||
|
||||
furi_record_close(RECORD_STORAGE);
|
||||
@@ -52,6 +56,15 @@ IclassEliteDict* iclass_elite_dict_alloc(IclassEliteDictType dict_type) {
|
||||
buffered_file_stream_close(dict->stream);
|
||||
break;
|
||||
}
|
||||
} else if(dict_type == IclassStandardDictTypeFlipper) {
|
||||
if(!buffered_file_stream_open(
|
||||
dict->stream,
|
||||
ICLASS_STANDARD_DICT_FLIPPER_NAME,
|
||||
FSAM_READ,
|
||||
FSOM_OPEN_EXISTING)) {
|
||||
buffered_file_stream_close(dict->stream);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Read total amount of keys
|
||||
@@ -148,4 +161,4 @@ bool iclass_elite_dict_add_key(IclassEliteDict* dict, uint8_t* key) {
|
||||
|
||||
furi_string_free(key_str);
|
||||
return key_added;
|
||||
}
|
||||
}
|
||||
|
@@ -9,6 +9,7 @@
|
||||
typedef enum {
|
||||
IclassEliteDictTypeUser,
|
||||
IclassEliteDictTypeFlipper,
|
||||
IclassStandardDictTypeFlipper,
|
||||
} IclassEliteDictType;
|
||||
|
||||
typedef struct IclassEliteDict IclassEliteDict;
|
||||
@@ -25,4 +26,4 @@ bool iclass_elite_dict_get_next_key(IclassEliteDict* dict, uint8_t* key);
|
||||
|
||||
bool iclass_elite_dict_rewind(IclassEliteDict* dict);
|
||||
|
||||
bool iclass_elite_dict_add_key(IclassEliteDict* dict, uint8_t* key);
|
||||
bool iclass_elite_dict_add_key(IclassEliteDict* dict, uint8_t* key);
|
||||
|
46
applications/external/picopass/picopass_worker.c
vendored
46
applications/external/picopass/picopass_worker.c
vendored
@@ -172,14 +172,18 @@ ReturnCode picopass_read_preauth(PicopassBlock* AA1) {
|
||||
return ERR_NONE;
|
||||
}
|
||||
|
||||
static ReturnCode picopass_auth_dict(
|
||||
uint8_t* csn,
|
||||
PicopassPacs* pacs,
|
||||
uint8_t* div_key,
|
||||
IclassEliteDictType dict_type,
|
||||
bool elite) {
|
||||
static ReturnCode
|
||||
picopass_auth_dict(PicopassWorker* picopass_worker, IclassEliteDictType dict_type) {
|
||||
rfalPicoPassReadCheckRes rcRes;
|
||||
rfalPicoPassCheckRes chkRes;
|
||||
bool elite = (dict_type != IclassStandardDictTypeFlipper);
|
||||
|
||||
PicopassDeviceData* dev_data = picopass_worker->dev_data;
|
||||
PicopassBlock* AA1 = dev_data->AA1;
|
||||
PicopassPacs* pacs = &dev_data->pacs;
|
||||
|
||||
uint8_t* csn = AA1[PICOPASS_CSN_BLOCK_INDEX].data;
|
||||
uint8_t* div_key = AA1[PICOPASS_KD_BLOCK_INDEX].data;
|
||||
|
||||
ReturnCode err = ERR_PARAM;
|
||||
|
||||
@@ -204,7 +208,8 @@ static ReturnCode picopass_auth_dict(
|
||||
while(iclass_elite_dict_get_next_key(dict, key)) {
|
||||
FURI_LOG_D(
|
||||
TAG,
|
||||
"Try to auth with key %zu %02x%02x%02x%02x%02x%02x%02x%02x",
|
||||
"Try to %s auth with key %zu %02x%02x%02x%02x%02x%02x%02x%02x",
|
||||
elite ? "elite" : "standard",
|
||||
index++,
|
||||
key[0],
|
||||
key[1],
|
||||
@@ -230,6 +235,8 @@ static ReturnCode picopass_auth_dict(
|
||||
memcpy(pacs->key, key, PICOPASS_BLOCK_LEN);
|
||||
break;
|
||||
}
|
||||
|
||||
if(picopass_worker->state != PicopassWorkerStateDetect) break;
|
||||
}
|
||||
|
||||
iclass_elite_dict_free(dict);
|
||||
@@ -237,38 +244,23 @@ static ReturnCode picopass_auth_dict(
|
||||
return err;
|
||||
}
|
||||
|
||||
ReturnCode picopass_auth(PicopassBlock* AA1, PicopassPacs* pacs) {
|
||||
ReturnCode picopass_auth(PicopassWorker* picopass_worker) {
|
||||
ReturnCode err;
|
||||
|
||||
FURI_LOG_I(TAG, "Starting system dictionary attack [Standard KDF]");
|
||||
err = picopass_auth_dict(
|
||||
AA1[PICOPASS_CSN_BLOCK_INDEX].data,
|
||||
pacs,
|
||||
AA1[PICOPASS_KD_BLOCK_INDEX].data,
|
||||
IclassEliteDictTypeFlipper,
|
||||
false);
|
||||
err = picopass_auth_dict(picopass_worker, IclassStandardDictTypeFlipper);
|
||||
if(err == ERR_NONE) {
|
||||
return ERR_NONE;
|
||||
}
|
||||
|
||||
FURI_LOG_I(TAG, "Starting user dictionary attack [Elite KDF]");
|
||||
err = picopass_auth_dict(
|
||||
AA1[PICOPASS_CSN_BLOCK_INDEX].data,
|
||||
pacs,
|
||||
AA1[PICOPASS_KD_BLOCK_INDEX].data,
|
||||
IclassEliteDictTypeUser,
|
||||
true);
|
||||
err = picopass_auth_dict(picopass_worker, IclassEliteDictTypeUser);
|
||||
if(err == ERR_NONE) {
|
||||
return ERR_NONE;
|
||||
}
|
||||
|
||||
FURI_LOG_I(TAG, "Starting system dictionary attack [Elite KDF]");
|
||||
err = picopass_auth_dict(
|
||||
AA1[PICOPASS_CSN_BLOCK_INDEX].data,
|
||||
pacs,
|
||||
AA1[PICOPASS_KD_BLOCK_INDEX].data,
|
||||
IclassEliteDictTypeFlipper,
|
||||
true);
|
||||
err = picopass_auth_dict(picopass_worker, IclassEliteDictTypeFlipper);
|
||||
if(err == ERR_NONE) {
|
||||
return ERR_NONE;
|
||||
}
|
||||
@@ -520,7 +512,7 @@ void picopass_worker_detect(PicopassWorker* picopass_worker) {
|
||||
}
|
||||
|
||||
if(nextState == PicopassWorkerEventSuccess) {
|
||||
err = picopass_auth(AA1, pacs);
|
||||
err = picopass_auth(picopass_worker);
|
||||
if(err != ERR_NONE) {
|
||||
FURI_LOG_E(TAG, "picopass_try_auth error %d", err);
|
||||
nextState = PicopassWorkerEventFail;
|
||||
|
Reference in New Issue
Block a user