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

Save picopass as picopass or, for 26bit, as lfrfid #1380

Merged
merged 1 commit into from
Jul 10, 2022
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
31 changes: 28 additions & 3 deletions applications/picopass/picopass.c
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,13 @@ Picopass* picopass_alloc() {
view_dispatcher_add_view(
picopass->view_dispatcher, PicopassViewPopup, popup_get_view(picopass->popup));

// Text Input
picopass->text_input = text_input_alloc();
view_dispatcher_add_view(
picopass->view_dispatcher,
PicopassViewTextInput,
text_input_get_view(picopass->text_input));

// Custom Widget
picopass->widget = widget_alloc();
view_dispatcher_add_view(
Expand All @@ -67,6 +74,10 @@ Picopass* picopass_alloc() {
void picopass_free(Picopass* picopass) {
furi_assert(picopass);

// Picopass device
picopass_device_free(picopass->dev);
picopass->dev = NULL;

// Submenu
view_dispatcher_remove_view(picopass->view_dispatcher, PicopassViewMenu);
submenu_free(picopass->submenu);
Expand All @@ -75,6 +86,10 @@ void picopass_free(Picopass* picopass) {
view_dispatcher_remove_view(picopass->view_dispatcher, PicopassViewPopup);
popup_free(picopass->popup);

// TextInput
view_dispatcher_remove_view(picopass->view_dispatcher, PicopassViewTextInput);
text_input_free(picopass->text_input);

// Custom Widget
view_dispatcher_remove_view(picopass->view_dispatcher, PicopassViewWidget);
widget_free(picopass->widget);
Expand All @@ -97,12 +112,22 @@ void picopass_free(Picopass* picopass) {
furi_record_close("notification");
picopass->notifications = NULL;

picopass_device_free(picopass->dev);
picopass->dev = NULL;

free(picopass);
}

void picopass_text_store_set(Picopass* picopass, const char* text, ...) {
va_list args;
va_start(args, text);

vsnprintf(picopass->text_store, sizeof(picopass->text_store), text, args);

va_end(args);
}

void picopass_text_store_clear(Picopass* picopass) {
memset(picopass->text_store, 0, sizeof(picopass->text_store));
}

static const NotificationSequence picopass_sequence_blink_start_blue = {
&message_blink_start_10,
&message_blink_set_color_blue,
Expand Down
115 changes: 114 additions & 1 deletion applications/picopass/picopass_device.c
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,126 @@

#define TAG "PicopassDevice"

static const char* picopass_file_header = "Flipper Picopass device";
static const uint32_t picopass_file_version = 1;

PicopassDevice* picopass_device_alloc() {
PicopassDevice* picopass_dev = malloc(sizeof(PicopassDevice));
picopass_dev->storage = furi_record_open("storage");
picopass_dev->dialogs = furi_record_open("dialogs");
return picopass_dev;
}

void picopass_device_set_name(PicopassDevice* dev, const char* name) {
furi_assert(dev);

strlcpy(dev->dev_name, name, PICOPASS_DEV_NAME_MAX_LEN);
}

static bool picopass_device_save_file(
PicopassDevice* dev,
const char* dev_name,
const char* folder,
const char* extension,
bool use_load_path) {
furi_assert(dev);

bool saved = false;
FlipperFormat* file = flipper_format_file_alloc(dev->storage);
PicopassPacs* pacs = &dev->dev_data.pacs;
ApplicationArea* AA1 = &dev->dev_data.AA1;
string_t temp_str;
string_init(temp_str);

do {
if(use_load_path && !string_empty_p(dev->load_path)) {
// Get directory name
path_extract_dirname(string_get_cstr(dev->load_path), temp_str);
// Create picopass directory if necessary
if(!storage_simply_mkdir(dev->storage, string_get_cstr(temp_str))) break;
// Make path to file to save
string_cat_printf(temp_str, "/%s%s", dev_name, extension);
} else {
// Create picopass directory if necessary
if(!storage_simply_mkdir(dev->storage, PICOPASS_APP_FOLDER)) break;
// First remove picopass device file if it was saved
string_printf(temp_str, "%s/%s%s", folder, dev_name, extension);
}
// Open file
if(!flipper_format_file_open_always(file, string_get_cstr(temp_str))) break;

if(dev->format == PicopassDeviceSaveFormatHF) {
// Write header
if(!flipper_format_write_header_cstr(file, picopass_file_header, picopass_file_version))
break;
if(pacs->record.valid) {
if(!flipper_format_write_uint32(
file, "Facility Code", (uint32_t*)&pacs->record.FacilityCode, 1))
break;
if(!flipper_format_write_uint32(
file, "Card Number", (uint32_t*)&pacs->record.CardNumber, 1))
break;
if(!flipper_format_write_hex(
file, "Credential", pacs->credential, PICOPASS_BLOCK_LEN))
break;
if(!flipper_format_write_hex(file, "PIN", pacs->pin0, PICOPASS_BLOCK_LEN)) break;
if(!flipper_format_write_hex(file, "PIN(cont.)", pacs->pin1, PICOPASS_BLOCK_LEN))
break;

if(!flipper_format_write_comment_cstr(file, "Picopass blocks")) break;
// TODO: Save CSN, CFG, AA1, etc
bool block_saved = true;
for(size_t i = 0; i < 4; i++) {
string_printf(temp_str, "Block %d", i + 6);
if(!flipper_format_write_hex(
file,
string_get_cstr(temp_str),
AA1->block[i].data,
PICOPASS_BLOCK_LEN)) {
block_saved = false;
break;
}
}
if(!block_saved) break;
if(!flipper_format_write_comment_cstr(file, "This is currently incomplete")) break;
}
} else if(dev->format == PicopassDeviceSaveFormatLF) {
const char* lf_header = "Flipper RFID key";
// Write header
if(!flipper_format_write_header_cstr(file, lf_header, 1)) break;
if(!flipper_format_write_comment_cstr(
file,
"This was generated from the Picopass plugin and may not match current lfrfid"))
break;
// When lfrfid supports more formats, update this
if(!flipper_format_write_string_cstr(file, "Key type", "H10301")) break;
uint8_t H10301[3] = {0};
H10301[0] = pacs->record.FacilityCode;
H10301[1] = pacs->record.CardNumber >> 8;
H10301[2] = pacs->record.CardNumber & 0x00FF;
if(!flipper_format_write_hex(file, "Data", H10301, 3)) break;
}
saved = true;
} while(0);

if(!saved) {
dialog_message_show_storage_error(dev->dialogs, "Can not save\nkey file");
}
string_clear(temp_str);
flipper_format_free(file);
return saved;
}

bool picopass_device_save(PicopassDevice* dev, const char* dev_name) {
if(dev->format == PicopassDeviceSaveFormatHF) {
return picopass_device_save_file(
dev, dev_name, PICOPASS_APP_FOLDER, PICOPASS_APP_EXTENSION, true);
} else if(dev->format == PicopassDeviceSaveFormatLF) {
return picopass_device_save_file(dev, dev_name, "/any/lfrfid", ".rfid", true);
}
return false;
}

void picopass_device_clear(PicopassDevice* dev) {
furi_assert(dev);

Expand All @@ -24,10 +137,10 @@ void picopass_device_free(PicopassDevice* picopass_dev) {
picopass_device_clear(picopass_dev);
furi_record_close("storage");
furi_record_close("dialogs");
string_clear(picopass_dev->load_path);
free(picopass_dev);
}

void picopass_device_data_clear(PicopassDeviceData* dev_data) {
FURI_LOG_D(TAG, "picopass_device_data_clear");
memset(&dev_data->AA1, 0, sizeof(ApplicationArea));
}
29 changes: 28 additions & 1 deletion applications/picopass/picopass_device.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,26 @@

#include <rfal_picopass.h>

#define PICOPASS_DEV_NAME_MAX_LEN 22
#define PICOPASS_READER_DATA_MAX_SIZE 64
#define PICOPASS_BLOCK_LEN 8

#define PICOPASS_APP_FOLDER "/any/picopass"
#define PICOPASS_APP_EXTENSION ".picopass"
#define PICOPASS_APP_SHADOW_EXTENSION ".pas"

typedef enum {
PicopassDeviceEncryptionUnknown = 0,
PicopassDeviceEncryptionNone = 0x14,
PicopassDeviceEncryptionDES = 0x15,
PicopassDeviceEncryption3DES = 0x17,
} PicopassEncryption;

typedef enum {
PicopassDeviceSaveFormatHF,
PicopassDeviceSaveFormatLF,
} PicopassDeviceSaveFormat;

typedef struct {
bool valid;
uint8_t bitLength;
Expand All @@ -16,7 +36,7 @@ typedef struct {

typedef struct {
bool biometrics;
uint8_t encryption;
PicopassEncryption encryption;
uint8_t credential[8];
uint8_t pin0[8];
uint8_t pin1[8];
Expand All @@ -32,12 +52,19 @@ typedef struct {
Storage* storage;
DialogsApp* dialogs;
PicopassDeviceData dev_data;
char dev_name[PICOPASS_DEV_NAME_MAX_LEN + 1];
string_t load_path;
PicopassDeviceSaveFormat format;
} PicopassDevice;

PicopassDevice* picopass_device_alloc();

void picopass_device_free(PicopassDevice* picopass_dev);

void picopass_device_set_name(PicopassDevice* dev, const char* name);

bool picopass_device_save(PicopassDevice* dev, const char* dev_name);

void picopass_device_data_clear(PicopassDeviceData* dev_data);

void picopass_device_clear(PicopassDevice* dev);
13 changes: 12 additions & 1 deletion applications/picopass/picopass_i.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@

#include <gui/modules/submenu.h>
#include <gui/modules/popup.h>
#include <gui/modules/text_input.h>
#include <gui/modules/widget.h>

#include <input/input.h>
Expand All @@ -23,6 +24,8 @@
#include <storage/storage.h>
#include <lib/toolbox/path.h>

#define PICOPASS_TEXT_STORE_SIZE 128

enum PicopassCustomEvent {
// Reserve first 100 events for button types and indexes, starting from 0
PicopassCustomEventReserved = 100,
Expand All @@ -31,7 +34,6 @@ enum PicopassCustomEvent {
PicopassCustomEventWorkerExit,
PicopassCustomEventByteInputDone,
PicopassCustomEventTextInputDone,
PicopassCustomEventDictAttackDone,
};

typedef enum {
Expand All @@ -47,20 +49,29 @@ struct Picopass {
SceneManager* scene_manager;
PicopassDevice* dev;

char text_store[PICOPASS_TEXT_STORE_SIZE + 1];
string_t text_box_store;

// Common Views
Submenu* submenu;
Popup* popup;
TextInput* text_input;
Widget* widget;
};

typedef enum {
PicopassViewMenu,
PicopassViewPopup,
PicopassViewTextInput,
PicopassViewWidget,
} PicopassView;

Picopass* picopass_alloc();

void picopass_text_store_set(Picopass* picopass, const char* text, ...);

void picopass_text_store_clear(Picopass* picopass);

void picopass_blink_start(Picopass* picopass);

void picopass_blink_stop(Picopass* picopass);
7 changes: 0 additions & 7 deletions applications/picopass/picopass_worker.c
Original file line number Diff line number Diff line change
Expand Up @@ -114,8 +114,6 @@ void picopass_worker_start(
furi_assert(picopass_worker);
furi_assert(dev_data);

FURI_LOG_D(TAG, "picopass_worker_start");

picopass_worker->callback = callback;
picopass_worker->context = context;
picopass_worker->dev_data = dev_data;
Expand Down Expand Up @@ -258,10 +256,8 @@ void picopass_worker_detect(PicopassWorker* picopass_worker) {
ReturnCode err;

while(picopass_worker->state == PicopassWorkerStateDetect) {
FURI_LOG_D(TAG, "PicopassWorkerStateDetect");
if(picopass_detect_card(1000) == ERR_NONE) {
// Process first found device
FURI_LOG_D(TAG, "picopass_read_card");
err = picopass_read_card(AA1);
if(err != ERR_NONE) {
FURI_LOG_E(TAG, "picopass_read_card error %d", err);
Expand All @@ -277,21 +273,18 @@ void picopass_worker_detect(PicopassWorker* picopass_worker) {
FURI_LOG_E(TAG, "decrypt error %d", err);
break;
}
FURI_LOG_D(TAG, "Decrypted 7");

err = picopass_worker_decrypt(AA1->block[2].data, pacs->pin0);
if(err != ERR_NONE) {
FURI_LOG_E(TAG, "decrypt error %d", err);
break;
}
FURI_LOG_D(TAG, "Decrypted 8");

err = picopass_worker_decrypt(AA1->block[3].data, pacs->pin1);
if(err != ERR_NONE) {
FURI_LOG_E(TAG, "decrypt error %d", err);
break;
}
FURI_LOG_D(TAG, "Decrypted 9");
} else if(pacs->encryption == 0x14) {
FURI_LOG_D(TAG, "No Encryption");
memcpy(pacs->credential, AA1->block[1].data, RFAL_PICOPASS_MAX_BLOCK_LEN);
Expand Down
Loading