Skip to content

Commit d8303dc

Browse files
authored
Picopass: handle NR-MAC auth for legacy cards (#95)
1 parent ef3333a commit d8303dc

File tree

5 files changed

+23
-7
lines changed

5 files changed

+23
-7
lines changed

.catalog/README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,8 @@ There are some situations when the offline loclass may not find a key, such as:
3535

3636
Due to the nature of how secure picopass works, it is possible to emulate some public fields from a card and capture the reader's response, which can be used to authenticate. Two of the pieces involved in this are the NR and MAC.
3737

38+
These instructions are intended to be performed all at the same time. If you use the card with the reader between Card Part 1 and Card Part 2, then Card Part 2 will fail.
39+
3840
## Card Part 1
3941

4042
1. Place card against Flipper Zero

picopass_device.c

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -167,6 +167,11 @@ static bool picopass_device_save_file(
167167
FuriString* temp_str;
168168
temp_str = furi_string_alloc();
169169

170+
if(dev->format == PicopassDeviceSaveFormatPartial) {
171+
// Clear key that may have been set when doing key tests for legacy
172+
memset(AA1[PICOPASS_SECURE_KD_BLOCK_INDEX].data, 0, PICOPASS_BLOCK_LEN);
173+
}
174+
170175
do {
171176
if(use_load_path && !furi_string_empty(dev->load_path)) {
172177
// Get directory name
@@ -178,7 +183,8 @@ static bool picopass_device_save_file(
178183
furi_string_printf(temp_str, "%s/%s%s", folder, dev_name, extension);
179184
}
180185

181-
if(dev->format == PicopassDeviceSaveFormatHF) {
186+
if(dev->format == PicopassDeviceSaveFormatHF ||
187+
dev->format == PicopassDeviceSaveFormatPartial) {
182188
// Open file
183189
if(!flipper_format_file_open_always(file, furi_string_get_cstr(temp_str))) break;
184190

@@ -229,6 +235,9 @@ bool picopass_device_save(PicopassDevice* dev, const char* dev_name) {
229235
} else if(dev->format == PicopassDeviceSaveFormatSeader) {
230236
return picopass_device_save_file(
231237
dev, dev_name, EXT_PATH("apps_data/seader"), ".credential", true);
238+
} else if(dev->format == PicopassDeviceSaveFormatPartial) {
239+
return picopass_device_save_file(
240+
dev, dev_name, STORAGE_APP_DATA_PATH_PREFIX, PICOPASS_APP_EXTENSION, true);
232241
}
233242

234243
return false;

picopass_device.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,7 @@ typedef enum {
7171
PicopassDeviceSaveFormatHF,
7272
PicopassDeviceSaveFormatLF,
7373
PicopassDeviceSaveFormatSeader,
74+
PicopassDeviceSaveFormatPartial,
7475
} PicopassDeviceSaveFormat;
7576

7677
typedef enum {

protocol/picopass_poller.c

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -187,10 +187,9 @@ NfcCommand picopass_poller_check_security(PicopassPoller* instance) {
187187

188188
if(instance->data->pacs.se_enabled) {
189189
FURI_LOG_D(TAG, "SE enabled");
190-
instance->state = PicopassPollerStateNrMacAuth;
191-
} else {
192-
instance->state = PicopassPollerStateAuth;
193190
}
191+
// Always try the NR-MAC auth in case we have the file.
192+
instance->state = PicopassPollerStateNrMacAuth;
194193
return command;
195194
}
196195

@@ -221,8 +220,13 @@ NfcCommand picopass_poller_nr_mac_auth(PicopassPoller* instance) {
221220
FURI_LOG_D(TAG, "Looking for %s", furi_string_get_cstr(temp_str));
222221
uint8_t nr_mac[PICOPASS_BLOCK_LEN];
223222

224-
// Presume failure unless all steps are successful and the state is made "read block"
225-
instance->state = PicopassPollerStateFail;
223+
// Set next state so breaking do/while will jump to it. If successful, do/while will set to ReadBlock
224+
if(instance->data->pacs.se_enabled) {
225+
instance->state = PicopassPollerStateFail;
226+
} else {
227+
// For non-SE, run through normal key check
228+
instance->state = PicopassPollerStateAuth;
229+
}
226230
do {
227231
//check for file
228232
if(!flipper_format_file_open_existing(file, furi_string_get_cstr(temp_str))) break;

scenes/picopass_scene_card_menu.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -106,7 +106,7 @@ bool picopass_scene_card_menu_on_event(void* context, SceneManagerEvent event) {
106106
scene_manager_set_scene_state(
107107
picopass->scene_manager, PicopassSceneCardMenu, SubmenuIndexSave);
108108
scene_manager_next_scene(picopass->scene_manager, PicopassSceneSaveName);
109-
picopass->dev->format = PicopassDeviceSaveFormatHF;
109+
picopass->dev->format = PicopassDeviceSaveFormatPartial;
110110
consumed = true;
111111
} else if(event.event == SubmenuIndexSaveAsSeader) {
112112
scene_manager_set_scene_state(

0 commit comments

Comments
 (0)