Skip to content
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
48 changes: 29 additions & 19 deletions applications/picopass/picopass_device.c
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,9 @@ static const uint32_t picopass_file_version = 1;

PicopassDevice* picopass_device_alloc() {
PicopassDevice* picopass_dev = malloc(sizeof(PicopassDevice));
picopass_dev->dev_data.pacs.legacy = false;
picopass_dev->dev_data.pacs.se_enabled = false;
picopass_dev->dev_data.pacs.pin_length = 0;
picopass_dev->storage = furi_record_open("storage");
picopass_dev->dialogs = furi_record_open("dialogs");
return picopass_dev;
Expand All @@ -32,7 +35,7 @@ static bool picopass_device_save_file(
bool saved = false;
FlipperFormat* file = flipper_format_file_alloc(dev->storage);
PicopassPacs* pacs = &dev->dev_data.pacs;
ApplicationArea* AA1 = &dev->dev_data.AA1;
PicopassBlock* AA1 = dev->dev_data.AA1;
string_t temp_str;
string_init(temp_str);

Expand Down Expand Up @@ -67,27 +70,29 @@ static bool picopass_device_save_file(
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(pacs->pin_length > 0) {
if(!flipper_format_write_hex(file, "PIN\t\t", pacs->pin0, PICOPASS_BLOCK_LEN))
break;
if(!flipper_format_write_hex(
file,
string_get_cstr(temp_str),
AA1->block[i].data,
PICOPASS_BLOCK_LEN)) {
block_saved = false;
file, "PIN(cont.)\t", pacs->pin1, PICOPASS_BLOCK_LEN))
break;
}
}
if(!block_saved) break;
if(!flipper_format_write_comment_cstr(file, "This is currently incomplete")) break;
}
if(!flipper_format_write_comment_cstr(file, "Picopass blocks")) break;
bool block_saved = true;

size_t app_limit = AA1[PICOPASS_CONFIG_BLOCK_INDEX].data[0] < PICOPASS_MAX_APP_LIMIT ?
AA1[PICOPASS_CONFIG_BLOCK_INDEX].data[0] :
PICOPASS_MAX_APP_LIMIT;
for(size_t i = 0; i < app_limit; i++) {
string_printf(temp_str, "Block %d", i);
if(!flipper_format_write_hex(
file, string_get_cstr(temp_str), AA1[i].data, PICOPASS_BLOCK_LEN)) {
block_saved = false;
break;
}
}
if(!block_saved) break;
} else if(dev->format == PicopassDeviceSaveFormatLF) {
const char* lf_header = "Flipper RFID key";
// Write header
Expand Down Expand Up @@ -142,5 +147,10 @@ void picopass_device_free(PicopassDevice* picopass_dev) {
}

void picopass_device_data_clear(PicopassDeviceData* dev_data) {
memset(&dev_data->AA1, 0, sizeof(ApplicationArea));
for(size_t i = 0; i < PICOPASS_MAX_APP_LIMIT; i++) {
memset(dev_data->AA1[i].data, 0, sizeof(dev_data->AA1[i].data));
}
dev_data->pacs.legacy = false;
dev_data->pacs.se_enabled = false;
dev_data->pacs.pin_length = 0;
}
14 changes: 13 additions & 1 deletion applications/picopass/picopass_device.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,11 @@
#define PICOPASS_DEV_NAME_MAX_LEN 22
#define PICOPASS_READER_DATA_MAX_SIZE 64
#define PICOPASS_BLOCK_LEN 8
#define PICOPASS_MAX_APP_LIMIT 32

#define PICOPASS_CSN_BLOCK_INDEX 0
#define PICOPASS_CONFIG_BLOCK_INDEX 1
#define PICOPASS_AIA_BLOCK_INDEX 5

#define PICOPASS_APP_FOLDER "/any/picopass"
#define PICOPASS_APP_EXTENSION ".picopass"
Expand All @@ -35,7 +40,10 @@ typedef struct {
} PicopassWiegandRecord;

typedef struct {
bool legacy;
bool se_enabled;
bool biometrics;
uint8_t pin_length;
PicopassEncryption encryption;
uint8_t credential[8];
uint8_t pin0[8];
Expand All @@ -44,7 +52,11 @@ typedef struct {
} PicopassPacs;

typedef struct {
ApplicationArea AA1;
uint8_t data[PICOPASS_BLOCK_LEN];
} PicopassBlock;

typedef struct {
PicopassBlock AA1[PICOPASS_MAX_APP_LIMIT];
PicopassPacs pacs;
} PicopassDeviceData;

Expand Down
51 changes: 33 additions & 18 deletions applications/picopass/picopass_worker.c
Original file line number Diff line number Diff line change
Expand Up @@ -165,7 +165,7 @@ ReturnCode picopass_detect_card(int timeout) {
return ERR_NONE;
}

ReturnCode picopass_read_card(ApplicationArea* AA1) {
ReturnCode picopass_read_card(PicopassBlock* AA1) {
rfalPicoPassIdentifyRes idRes;
rfalPicoPassSelectRes selRes;
rfalPicoPassReadCheckRes rcRes;
Expand Down Expand Up @@ -205,10 +205,20 @@ ReturnCode picopass_read_card(ApplicationArea* AA1) {
return err;
}

for(size_t i = 0; i < 4; i++) {
FURI_LOG_D(TAG, "rfalPicoPassPollerReadBlock block %d", i + 6);
rfalPicoPassReadBlockRes csn;
err = rfalPicoPassPollerReadBlock(PICOPASS_CSN_BLOCK_INDEX, &csn);
memcpy(AA1[PICOPASS_CSN_BLOCK_INDEX].data, csn.data, sizeof(csn.data));

rfalPicoPassReadBlockRes cfg;
err = rfalPicoPassPollerReadBlock(PICOPASS_CONFIG_BLOCK_INDEX, &cfg);
memcpy(AA1[PICOPASS_CONFIG_BLOCK_INDEX].data, cfg.data, sizeof(cfg.data));

size_t app_limit = cfg.data[0] < PICOPASS_MAX_APP_LIMIT ? cfg.data[0] : PICOPASS_MAX_APP_LIMIT;

for(size_t i = 2; i < app_limit; i++) {
FURI_LOG_D(TAG, "rfalPicoPassPollerReadBlock block %d", i);
rfalPicoPassReadBlockRes block;
err = rfalPicoPassPollerReadBlock(i + 6, &block);
err = rfalPicoPassPollerReadBlock(i, &block);
if(err != ERR_NONE) {
FURI_LOG_E(TAG, "rfalPicoPassPollerReadBlock error %d", err);
return err;
Expand All @@ -217,7 +227,7 @@ ReturnCode picopass_read_card(ApplicationArea* AA1) {
FURI_LOG_D(
TAG,
"rfalPicoPassPollerReadBlock %d %02x%02x%02x%02x%02x%02x%02x%02x",
i + 6,
i,
block.data[0],
block.data[1],
block.data[2],
Expand All @@ -227,7 +237,7 @@ ReturnCode picopass_read_card(ApplicationArea* AA1) {
block.data[6],
block.data[7]);

memcpy(&(AA1->block[i]), &block, sizeof(block));
memcpy(AA1[i].data, block.data, sizeof(block.data));
}

return ERR_NONE;
Expand All @@ -251,7 +261,7 @@ void picopass_worker_detect(PicopassWorker* picopass_worker) {
picopass_device_data_clear(picopass_worker->dev_data);
PicopassDeviceData* dev_data = picopass_worker->dev_data;

ApplicationArea* AA1 = &dev_data->AA1;
PicopassBlock* AA1 = dev_data->AA1;
PicopassPacs* pacs = &dev_data->pacs;
ReturnCode err;

Expand All @@ -263,34 +273,39 @@ void picopass_worker_detect(PicopassWorker* picopass_worker) {
FURI_LOG_E(TAG, "picopass_read_card error %d", err);
}

pacs->biometrics = AA1->block[0].data[4];
pacs->encryption = AA1->block[0].data[7];
// Thank you proxmark!
pacs->legacy = (memcmp(AA1[5].data, "\xff\xff\xff\xff\xff\xff\xff\xff", 8) == 0);
pacs->se_enabled = (memcmp(AA1[5].data, "\xff\xff\xff\x00\x06\xff\xff\xff", 8) == 0);

pacs->biometrics = AA1[6].data[4];
pacs->pin_length = AA1[6].data[6] & 0x0F;
pacs->encryption = AA1[6].data[7];

if(pacs->encryption == 0x17) {
if(pacs->encryption == PicopassDeviceEncryption3DES) {
FURI_LOG_D(TAG, "3DES Encrypted");
err = picopass_worker_decrypt(AA1->block[1].data, pacs->credential);
err = picopass_worker_decrypt(AA1[7].data, pacs->credential);
if(err != ERR_NONE) {
FURI_LOG_E(TAG, "decrypt error %d", err);
break;
}

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

err = picopass_worker_decrypt(AA1->block[3].data, pacs->pin1);
err = picopass_worker_decrypt(AA1[9].data, pacs->pin1);
if(err != ERR_NONE) {
FURI_LOG_E(TAG, "decrypt error %d", err);
break;
}
} else if(pacs->encryption == 0x14) {
} else if(pacs->encryption == PicopassDeviceEncryptionNone) {
FURI_LOG_D(TAG, "No Encryption");
memcpy(pacs->credential, AA1->block[1].data, RFAL_PICOPASS_MAX_BLOCK_LEN);
memcpy(pacs->pin0, AA1->block[2].data, RFAL_PICOPASS_MAX_BLOCK_LEN);
memcpy(pacs->pin1, AA1->block[3].data, RFAL_PICOPASS_MAX_BLOCK_LEN);
} else if(pacs->encryption == 0x15) {
memcpy(pacs->credential, AA1[7].data, PICOPASS_BLOCK_LEN);
memcpy(pacs->pin0, AA1[8].data, PICOPASS_BLOCK_LEN);
memcpy(pacs->pin1, AA1[9].data, PICOPASS_BLOCK_LEN);
} else if(pacs->encryption == PicopassDeviceEncryptionDES) {
FURI_LOG_D(TAG, "DES Encrypted");
} else {
FURI_LOG_D(TAG, "Unknown encryption");
Expand Down
11 changes: 6 additions & 5 deletions applications/picopass/scenes/picopass_scene_read_card_success.c
Original file line number Diff line number Diff line change
Expand Up @@ -29,14 +29,17 @@ void picopass_scene_read_card_success_on_enter(void* context) {
PicopassPacs* pacs = &picopass->dev->dev_data.pacs;
Widget* widget = picopass->widget;

size_t bytesLength = 1 + pacs->record.bitLength / 8;
string_set_str(credential_str, "");
for(uint8_t i = 0; i < RFAL_PICOPASS_MAX_BLOCK_LEN; i++) {
for(uint8_t i = PICOPASS_BLOCK_LEN - bytesLength; i < PICOPASS_BLOCK_LEN; i++) {
string_cat_printf(credential_str, " %02X", pacs->credential[i]);
}

if(pacs->record.valid) {
string_cat_printf(
wiegand_str, "FC: %03u CN: %05u", pacs->record.FacilityCode, pacs->record.CardNumber);
} else {
string_cat_printf(wiegand_str, "%d bits", pacs->record.bitLength);
}

widget_add_button_element(
Expand All @@ -53,10 +56,8 @@ void picopass_scene_read_card_success_on_enter(void* context) {
picopass_scene_read_card_success_widget_callback,
picopass);

if(pacs->record.valid) {
widget_add_string_element(
widget, 64, 12, AlignCenter, AlignCenter, FontPrimary, string_get_cstr(wiegand_str));
}
widget_add_string_element(
widget, 64, 12, AlignCenter, AlignCenter, FontPrimary, string_get_cstr(wiegand_str));
widget_add_string_element(
widget, 64, 32, AlignCenter, AlignCenter, FontSecondary, string_get_cstr(credential_str));

Expand Down
4 changes: 0 additions & 4 deletions lib/ST25RFAL002/include/rfal_picopass.h
Original file line number Diff line number Diff line change
Expand Up @@ -51,10 +51,6 @@ typedef struct {
uint8_t crc[2];
} rfalPicoPassReadBlockRes;

typedef struct {
rfalPicoPassReadBlockRes block[4];
} ApplicationArea;

ReturnCode rfalPicoPassPollerInitialize(void);
ReturnCode rfalPicoPassPollerCheckPresence(void);
ReturnCode rfalPicoPassPollerIdentify(rfalPicoPassIdentifyRes* idRes);
Expand Down