|
@@ -18,10 +18,11 @@ void picopass_scene_read_card_success_widget_callback(
|
|
|
|
|
|
|
|
void picopass_scene_read_card_success_on_enter(void* context) {
|
|
void picopass_scene_read_card_success_on_enter(void* context) {
|
|
|
Picopass* picopass = context;
|
|
Picopass* picopass = context;
|
|
|
|
|
+ PicopassDeviceAuthMethod auth = picopass->dev->dev_data.auth;
|
|
|
|
|
|
|
|
FuriString* csn_str = furi_string_alloc_set("CSN:");
|
|
FuriString* csn_str = furi_string_alloc_set("CSN:");
|
|
|
FuriString* credential_str = furi_string_alloc();
|
|
FuriString* credential_str = furi_string_alloc();
|
|
|
- FuriString* wiegand_str = furi_string_alloc();
|
|
|
|
|
|
|
+ FuriString* info_str = furi_string_alloc();
|
|
|
FuriString* key_str = furi_string_alloc();
|
|
FuriString* key_str = furi_string_alloc();
|
|
|
|
|
|
|
|
dolphin_deed(DolphinDeedNfcReadSuccess);
|
|
dolphin_deed(DolphinDeedNfcReadSuccess);
|
|
@@ -29,28 +30,6 @@ void picopass_scene_read_card_success_on_enter(void* context) {
|
|
|
// Send notification
|
|
// Send notification
|
|
|
notification_message(picopass->notifications, &sequence_success);
|
|
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
|
|
// Setup view
|
|
|
PicopassBlock* card_data = picopass->dev->dev_data.card_data;
|
|
PicopassBlock* card_data = picopass->dev->dev_data.card_data;
|
|
|
PicopassPacs* pacs = &picopass->dev->dev_data.pacs;
|
|
PicopassPacs* pacs = &picopass->dev->dev_data.pacs;
|
|
@@ -62,19 +41,16 @@ void picopass_scene_read_card_success_on_enter(void* context) {
|
|
|
furi_string_cat_printf(csn_str, "%02X", csn[i]);
|
|
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(
|
|
bool empty = picopass_is_memset(
|
|
|
card_data[PICOPASS_ICLASS_PACS_CFG_BLOCK_INDEX].data, 0xFF, PICOPASS_BLOCK_LEN);
|
|
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 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) !=
|
|
bool secured = (card_data[PICOPASS_CONFIG_BLOCK_INDEX].data[7] & PICOPASS_FUSE_CRYPT10) !=
|
|
|
PICOPASS_FUSE_CRYPT0;
|
|
PICOPASS_FUSE_CRYPT0;
|
|
|
bool hid_csn = picopass_device_hid_csn(picopass->dev);
|
|
bool hid_csn = picopass_device_hid_csn(picopass->dev);
|
|
|
|
|
|
|
|
if(!secured) {
|
|
if(!secured) {
|
|
|
- furi_string_cat_printf(wiegand_str, "Non-Secured Chip");
|
|
|
|
|
|
|
+ furi_string_cat_printf(info_str, "Non-Secured Chip");
|
|
|
|
|
|
|
|
if(!hid_csn) {
|
|
if(!hid_csn) {
|
|
|
furi_string_cat_printf(credential_str, "Non-HID CSN");
|
|
furi_string_cat_printf(credential_str, "Non-HID CSN");
|
|
@@ -86,8 +62,8 @@ void picopass_scene_read_card_success_on_enter(void* context) {
|
|
|
"More",
|
|
"More",
|
|
|
picopass_scene_read_card_success_widget_callback,
|
|
picopass_scene_read_card_success_widget_callback,
|
|
|
picopass);
|
|
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) {
|
|
if(pacs->se_enabled) {
|
|
|
furi_string_cat_printf(credential_str, "SE enabled");
|
|
furi_string_cat_printf(credential_str, "SE enabled");
|
|
@@ -109,7 +85,8 @@ void picopass_scene_read_card_success_on_enter(void* context) {
|
|
|
picopass);
|
|
picopass);
|
|
|
} else if(pacs->se_enabled) {
|
|
} else if(pacs->se_enabled) {
|
|
|
furi_string_cat_printf(credential_str, "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_add_button_element(
|
|
|
widget,
|
|
widget,
|
|
|
GuiButtonTypeRight,
|
|
GuiButtonTypeRight,
|
|
@@ -117,9 +94,10 @@ void picopass_scene_read_card_success_on_enter(void* context) {
|
|
|
picopass_scene_read_card_success_widget_callback,
|
|
picopass_scene_read_card_success_widget_callback,
|
|
|
picopass);
|
|
picopass);
|
|
|
} else if(configCard) {
|
|
} else if(configCard) {
|
|
|
- furi_string_cat_printf(wiegand_str, "Config Card");
|
|
|
|
|
|
|
+ furi_string_cat_printf(credential_str, "Config Card");
|
|
|
} else if(empty) {
|
|
} else if(empty) {
|
|
|
- furi_string_cat_printf(wiegand_str, "Empty");
|
|
|
|
|
|
|
+ furi_string_cat_printf(credential_str, "Empty");
|
|
|
|
|
+
|
|
|
widget_add_button_element(
|
|
widget_add_button_element(
|
|
|
widget,
|
|
widget,
|
|
|
GuiButtonTypeCenter,
|
|
GuiButtonTypeCenter,
|
|
@@ -129,10 +107,11 @@ void picopass_scene_read_card_success_on_enter(void* context) {
|
|
|
} else if(pacs->bitLength == 0 || pacs->bitLength == 255) {
|
|
} else if(pacs->bitLength == 0 || pacs->bitLength == 255) {
|
|
|
// Neither of these are valid. Indicates the block was all 0x00 or all 0xff
|
|
// Neither of these are valid. Indicates the block was all 0x00 or all 0xff
|
|
|
if(SE) {
|
|
if(SE) {
|
|
|
- furi_string_cat_printf(wiegand_str, "SIO");
|
|
|
|
|
|
|
+ furi_string_cat_printf(info_str, "SIO");
|
|
|
} else {
|
|
} else {
|
|
|
- furi_string_cat_printf(wiegand_str, "Invalid PACS");
|
|
|
|
|
|
|
+ furi_string_cat_printf(info_str, "Invalid PACS");
|
|
|
}
|
|
}
|
|
|
|
|
+
|
|
|
widget_add_button_element(
|
|
widget_add_button_element(
|
|
|
widget,
|
|
widget,
|
|
|
GuiButtonTypeCenter,
|
|
GuiButtonTypeCenter,
|
|
@@ -148,40 +127,13 @@ void picopass_scene_read_card_success_on_enter(void* context) {
|
|
|
} else {
|
|
} else {
|
|
|
size_t bytesLength = 1 + pacs->bitLength / 8;
|
|
size_t bytesLength = 1 + pacs->bitLength / 8;
|
|
|
furi_string_set(credential_str, "");
|
|
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++) {
|
|
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(credential_str, "%02X", pacs->credential[i]);
|
|
|
}
|
|
}
|
|
|
- furi_string_cat_printf(wiegand_str, "%d bits", pacs->bitLength);
|
|
|
|
|
|
|
|
|
|
if(pacs->sio) {
|
|
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(
|
|
widget_add_button_element(
|
|
@@ -192,6 +144,37 @@ void picopass_scene_read_card_success_on_enter(void* context) {
|
|
|
picopass);
|
|
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_add_button_element(
|
|
|
widget,
|
|
widget,
|
|
|
GuiButtonTypeLeft,
|
|
GuiButtonTypeLeft,
|
|
@@ -201,22 +184,22 @@ void picopass_scene_read_card_success_on_enter(void* context) {
|
|
|
|
|
|
|
|
widget_add_string_element(
|
|
widget_add_string_element(
|
|
|
widget, 64, 5, AlignCenter, AlignCenter, FontSecondary, furi_string_get_cstr(csn_str));
|
|
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_add_string_element(
|
|
|
widget,
|
|
widget,
|
|
|
64,
|
|
64,
|
|
|
- 36,
|
|
|
|
|
|
|
+ 20,
|
|
|
AlignCenter,
|
|
AlignCenter,
|
|
|
AlignCenter,
|
|
AlignCenter,
|
|
|
- FontSecondary,
|
|
|
|
|
|
|
+ FontPrimary,
|
|
|
furi_string_get_cstr(credential_str));
|
|
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_add_string_element(
|
|
|
widget, 64, 46, AlignCenter, AlignCenter, FontSecondary, furi_string_get_cstr(key_str));
|
|
widget, 64, 46, AlignCenter, AlignCenter, FontSecondary, furi_string_get_cstr(key_str));
|
|
|
|
|
|
|
|
furi_string_free(csn_str);
|
|
furi_string_free(csn_str);
|
|
|
furi_string_free(credential_str);
|
|
furi_string_free(credential_str);
|
|
|
- furi_string_free(wiegand_str);
|
|
|
|
|
|
|
+ furi_string_free(info_str);
|
|
|
furi_string_free(key_str);
|
|
furi_string_free(key_str);
|
|
|
|
|
|
|
|
view_dispatcher_switch_to_view(picopass->view_dispatcher, PicopassViewWidget);
|
|
view_dispatcher_switch_to_view(picopass->view_dispatcher, PicopassViewWidget);
|