Skip to content

Commit

Permalink
Picopass cleanup (#201)
Browse files Browse the repository at this point in the history
  • Loading branch information
bettse authored Apr 22, 2024
1 parent 471e8db commit ae4ce84
Show file tree
Hide file tree
Showing 4 changed files with 65 additions and 77 deletions.
15 changes: 8 additions & 7 deletions scenes/picopass_scene_card_menu.c
Original file line number Diff line number Diff line change
Expand Up @@ -21,16 +21,17 @@ void picopass_scene_card_menu_on_enter(void* context) {
Submenu* submenu = picopass->submenu;
PicopassPacs* pacs = &picopass->dev->dev_data.pacs;
PicopassBlock* card_data = picopass->dev->dev_data.card_data;
PicopassDeviceAuthMethod auth = picopass->dev->dev_data.auth;

bool sio = 0x30 == card_data[PICOPASS_ICLASS_PACS_CFG_BLOCK_INDEX].data[0];
bool SE = card_data[PICOPASS_ICLASS_PACS_CFG_BLOCK_INDEX].valid &&
0x30 == card_data[PICOPASS_ICLASS_PACS_CFG_BLOCK_INDEX].data[0];
bool SR = card_data[10].valid && 0x30 == card_data[10].data[0];
bool has_sio = SE || SR;
bool secured = (card_data[PICOPASS_CONFIG_BLOCK_INDEX].data[7] & PICOPASS_FUSE_CRYPT10) !=
PICOPASS_FUSE_CRYPT0;
bool zero_config = picopass_is_memset(
card_data[PICOPASS_ICLASS_PACS_CFG_BLOCK_INDEX].data, 0x00, PICOPASS_BLOCK_LEN);
bool no_credential = picopass_is_memset(pacs->credential, 0x00, sizeof(pacs->credential));
bool no_key = !card_data[PICOPASS_SECURE_KD_BLOCK_INDEX].valid;

if(secured && zero_config) {
if(auth == PicopassDeviceAuthMethodFailed) {
submenu_add_item(
submenu,
"Save Partial",
Expand All @@ -42,7 +43,7 @@ void picopass_scene_card_menu_on_enter(void* context) {
submenu, "Save", SubmenuIndexSave, picopass_scene_card_menu_submenu_callback, picopass);
}

if(secured && (sio || pacs->sio)) {
if(secured && has_sio) {
submenu_add_item(
submenu,
"Save in Seader fmt",
Expand All @@ -60,7 +61,7 @@ void picopass_scene_card_menu_on_enter(void* context) {
picopass);
}

if(!zero_config && !no_key) {
if(auth == PicopassDeviceAuthMethodNone || auth == PicopassDeviceAuthMethodKey) {
submenu_add_item(
submenu,
"Write",
Expand Down
2 changes: 1 addition & 1 deletion scenes/picopass_scene_more_info.c
Original file line number Diff line number Diff line change
Expand Up @@ -51,5 +51,5 @@ void picopass_scene_more_info_on_exit(void* context) {
Picopass* picopass = context;

// Clear views
widget_reset(picopass->widget);
text_box_reset(picopass->text_box);
}
121 changes: 52 additions & 69 deletions scenes/picopass_scene_read_card_success.c
Original file line number Diff line number Diff line change
Expand Up @@ -18,39 +18,18 @@ void picopass_scene_read_card_success_widget_callback(

void picopass_scene_read_card_success_on_enter(void* context) {
Picopass* picopass = context;
PicopassDeviceAuthMethod auth = picopass->dev->dev_data.auth;

FuriString* csn_str = furi_string_alloc_set("CSN:");
FuriString* credential_str = furi_string_alloc();
FuriString* wiegand_str = furi_string_alloc();
FuriString* info_str = furi_string_alloc();
FuriString* key_str = furi_string_alloc();

dolphin_deed(DolphinDeedNfcReadSuccess);

// Send notification
notification_message(picopass->notifications, &sequence_success);

// For initial testing, print auth method
switch(picopass->dev->dev_data.auth) {
case PicopassDeviceAuthMethodUnset:
FURI_LOG_D(TAG, "Auth: Unset");
break;
case PicopassDeviceAuthMethodNone:
FURI_LOG_D(TAG, "Auth: None");
break;
case PicopassDeviceAuthMethodKey:
FURI_LOG_D(TAG, "Auth: Key");
break;
case PicopassDeviceAuthMethodNrMac:
FURI_LOG_D(TAG, "Auth: NR-MAC");
break;
case PicopassDeviceAuthMethodFailed:
FURI_LOG_D(TAG, "Auth: Failed");
break;
default:
FURI_LOG_D(TAG, "Auth: Unknown");
break;
};

// Setup view
PicopassBlock* card_data = picopass->dev->dev_data.card_data;
PicopassPacs* pacs = &picopass->dev->dev_data.pacs;
Expand All @@ -62,19 +41,16 @@ void picopass_scene_read_card_success_on_enter(void* context) {
furi_string_cat_printf(csn_str, "%02X", csn[i]);
}

// We can't test the pacs->key in case it is intentionally all 0's and we can't test the key block since it is populated with the diversified key before each key test, so we approximate with the PACS config block being blank.
bool zero_config = picopass_is_memset(
card_data[PICOPASS_ICLASS_PACS_CFG_BLOCK_INDEX].data, 0x00, PICOPASS_BLOCK_LEN);
bool empty = picopass_is_memset(
card_data[PICOPASS_ICLASS_PACS_CFG_BLOCK_INDEX].data, 0xFF, PICOPASS_BLOCK_LEN);
bool SE = 0x30 == card_data[PICOPASS_ICLASS_PACS_CFG_BLOCK_INDEX].data[0];
bool SE = pacs->se_enabled;
bool configCard = (card_data[PICOPASS_ICLASS_PACS_CFG_BLOCK_INDEX].data[7] >> 2 & 3) == 2;
bool secured = (card_data[PICOPASS_CONFIG_BLOCK_INDEX].data[7] & PICOPASS_FUSE_CRYPT10) !=
PICOPASS_FUSE_CRYPT0;
bool hid_csn = picopass_device_hid_csn(picopass->dev);

if(!secured) {
furi_string_cat_printf(wiegand_str, "Non-Secured Chip");
furi_string_cat_printf(info_str, "Non-Secured Chip");

if(!hid_csn) {
furi_string_cat_printf(credential_str, "Non-HID CSN");
Expand All @@ -86,8 +62,8 @@ void picopass_scene_read_card_success_on_enter(void* context) {
"More",
picopass_scene_read_card_success_widget_callback,
picopass);
} else if(zero_config) {
furi_string_cat_printf(wiegand_str, "Read Failed");
} else if(auth == PicopassDeviceAuthMethodFailed) {
furi_string_cat_printf(info_str, "Read Failed");

if(pacs->se_enabled) {
furi_string_cat_printf(credential_str, "SE enabled");
Expand All @@ -109,17 +85,19 @@ void picopass_scene_read_card_success_on_enter(void* context) {
picopass);
} else if(pacs->se_enabled) {
furi_string_cat_printf(credential_str, "SE enabled");
furi_string_cat_printf(wiegand_str, "SIO");
furi_string_cat_printf(info_str, "SIO");

widget_add_button_element(
widget,
GuiButtonTypeRight,
"More",
picopass_scene_read_card_success_widget_callback,
picopass);
} else if(configCard) {
furi_string_cat_printf(wiegand_str, "Config Card");
furi_string_cat_printf(credential_str, "Config Card");
} else if(empty) {
furi_string_cat_printf(wiegand_str, "Empty");
furi_string_cat_printf(credential_str, "Empty");

widget_add_button_element(
widget,
GuiButtonTypeCenter,
Expand All @@ -129,10 +107,11 @@ void picopass_scene_read_card_success_on_enter(void* context) {
} else if(pacs->bitLength == 0 || pacs->bitLength == 255) {
// Neither of these are valid. Indicates the block was all 0x00 or all 0xff
if(SE) {
furi_string_cat_printf(wiegand_str, "SIO");
furi_string_cat_printf(info_str, "SIO");
} else {
furi_string_cat_printf(wiegand_str, "Invalid PACS");
furi_string_cat_printf(info_str, "Invalid PACS");
}

widget_add_button_element(
widget,
GuiButtonTypeCenter,
Expand All @@ -148,40 +127,13 @@ void picopass_scene_read_card_success_on_enter(void* context) {
} else {
size_t bytesLength = 1 + pacs->bitLength / 8;
furi_string_set(credential_str, "");
furi_string_cat_printf(credential_str, "(%d) ", pacs->bitLength);
for(uint8_t i = PICOPASS_BLOCK_LEN - bytesLength; i < PICOPASS_BLOCK_LEN; i++) {
furi_string_cat_printf(credential_str, "%02X", pacs->credential[i]);
}
furi_string_cat_printf(wiegand_str, "%d bits", pacs->bitLength);

if(pacs->sio) {
furi_string_cat_printf(credential_str, " +SIO");
}

bool no_key = !card_data[PICOPASS_SECURE_KD_BLOCK_INDEX].valid;

if(no_key) {
furi_string_cat_printf(key_str, "No Key: used NR-MAC");
} else {
furi_string_cat_printf(key_str, "Key: ");
uint8_t key[PICOPASS_BLOCK_LEN];
memcpy(key, &pacs->key, PICOPASS_BLOCK_LEN);

bool standard_key = true;
// Handle DES key being 56bits with parity in LSB
for(uint8_t i = 0; i < PICOPASS_BLOCK_LEN; i++) {
if((key[i] & 0xFE) != (picopass_iclass_key[i] & 0xFE)) {
standard_key = false;
break;
}
}

if(standard_key) {
furi_string_cat_printf(key_str, "Standard");
} else {
for(uint8_t i = 0; i < PICOPASS_BLOCK_LEN; i++) {
furi_string_cat_printf(key_str, "%02X", key[i]);
}
}
furi_string_cat_printf(info_str, " +SIO");
}

widget_add_button_element(
Expand All @@ -192,6 +144,37 @@ void picopass_scene_read_card_success_on_enter(void* context) {
picopass);
}

if(auth == PicopassDeviceAuthMethodUnset) {
furi_string_cat_printf(key_str, "Error: Auth Unset");
} else if(auth == PicopassDeviceAuthMethodNone) {
furi_string_cat_printf(key_str, "Unsecure card");
} else if(auth == PicopassDeviceAuthMethodNrMac) {
furi_string_cat_printf(key_str, "No Key: used NR-MAC");
} else if(auth == PicopassDeviceAuthMethodFailed) {
furi_string_cat_printf(key_str, "Auth Failed");
} else if(auth == PicopassDeviceAuthMethodKey) {
furi_string_cat_printf(key_str, "Key: ");
uint8_t key[PICOPASS_BLOCK_LEN];
memcpy(key, &pacs->key, PICOPASS_BLOCK_LEN);

bool standard_key = true;
// Handle DES key being 56bits with parity in LSB
for(uint8_t i = 0; i < PICOPASS_BLOCK_LEN; i++) {
if((key[i] & 0xFE) != (picopass_iclass_key[i] & 0xFE)) {
standard_key = false;
break;
}
}

if(standard_key) {
furi_string_cat_printf(key_str, "Standard");
} else {
for(uint8_t i = 0; i < PICOPASS_BLOCK_LEN; i++) {
furi_string_cat_printf(key_str, "%02X", key[i]);
}
}
}

widget_add_button_element(
widget,
GuiButtonTypeLeft,
Expand All @@ -201,22 +184,22 @@ void picopass_scene_read_card_success_on_enter(void* context) {

widget_add_string_element(
widget, 64, 5, AlignCenter, AlignCenter, FontSecondary, furi_string_get_cstr(csn_str));
widget_add_string_element(
widget, 64, 20, AlignCenter, AlignCenter, FontPrimary, furi_string_get_cstr(wiegand_str));
widget_add_string_element(
widget,
64,
36,
20,
AlignCenter,
AlignCenter,
FontSecondary,
FontPrimary,
furi_string_get_cstr(credential_str));
widget_add_string_element(
widget, 64, 36, AlignCenter, AlignCenter, FontSecondary, furi_string_get_cstr(info_str));
widget_add_string_element(
widget, 64, 46, AlignCenter, AlignCenter, FontSecondary, furi_string_get_cstr(key_str));

furi_string_free(csn_str);
furi_string_free(credential_str);
furi_string_free(wiegand_str);
furi_string_free(info_str);
furi_string_free(key_str);

view_dispatcher_switch_to_view(picopass->view_dispatcher, PicopassViewWidget);
Expand Down
4 changes: 4 additions & 0 deletions scenes/picopass_scene_read_factory_success.c
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,10 @@ bool picopass_scene_read_factory_success_on_event(void* context, SceneManagerEve
scene_manager_next_scene(picopass->scene_manager, PicopassSceneWriteKey);
consumed = true;
}
} else if(event.type == SceneManagerEventTypeBack) {
scene_manager_search_and_switch_to_previous_scene(
picopass->scene_manager, PicopassSceneStart);
consumed = true;
}
return consumed;
}
Expand Down

0 comments on commit ae4ce84

Please sign in to comment.