Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Picopass cleanup #201

Merged
merged 4 commits into from
Apr 22, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 8 additions & 7 deletions picopass/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 picopass/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 picopass/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 picopass/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