Skip to content

Commit

Permalink
[FL-3593] Picopass rework. Part 1 (#68)
Browse files Browse the repository at this point in the history
Co-authored-by: あく <alleteam@gmail.com>
  • Loading branch information
gornekich and skotopes committed Oct 31, 2023
1 parent 77e776a commit 6ccba6c
Show file tree
Hide file tree
Showing 33 changed files with 2,283 additions and 1,927 deletions.
2 changes: 2 additions & 0 deletions .catalog/changelog.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
## 1.7
- Rework application with new NFC API
## 1.6
- Faster loclass response collection
- Save as LF for all bit lengths
Expand Down
2 changes: 1 addition & 1 deletion application.fam
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ App(
],
stack_size=4 * 1024,
fap_description="App to communicate with NFC tags using the PicoPass(iClass) format",
fap_version="1.6",
fap_version="1.7",
fap_icon="125_10px.png",
fap_category="NFC",
fap_libs=["mbedtls"],
Expand Down
9 changes: 4 additions & 5 deletions picopass.c
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@ void picopass_tick_event_callback(void* context) {
Picopass* picopass_alloc() {
Picopass* picopass = malloc(sizeof(Picopass));

picopass->worker = picopass_worker_alloc();
picopass->view_dispatcher = view_dispatcher_alloc();
picopass->scene_manager = scene_manager_alloc(&picopass_scene_handlers, picopass);
view_dispatcher_enable_queue(picopass->view_dispatcher);
Expand All @@ -35,6 +34,8 @@ Picopass* picopass_alloc() {
view_dispatcher_set_tick_event_callback(
picopass->view_dispatcher, picopass_tick_event_callback, 100);

picopass->nfc = nfc_alloc();

// Picopass device
picopass->dev = picopass_device_alloc();

Expand Down Expand Up @@ -100,6 +101,8 @@ void picopass_free(Picopass* picopass) {
picopass_device_free(picopass->dev);
picopass->dev = NULL;

nfc_free(picopass->nfc);

// Submenu
view_dispatcher_remove_view(picopass->view_dispatcher, PicopassViewMenu);
submenu_free(picopass->submenu);
Expand Down Expand Up @@ -130,10 +133,6 @@ void picopass_free(Picopass* picopass) {
view_dispatcher_remove_view(picopass->view_dispatcher, PicopassViewLoclass);
loclass_free(picopass->loclass);

// Worker
picopass_worker_stop(picopass->worker);
picopass_worker_free(picopass->worker);

// View Dispatcher
view_dispatcher_free(picopass->view_dispatcher);

Expand Down
35 changes: 8 additions & 27 deletions picopass_device.c
Original file line number Diff line number Diff line change
Expand Up @@ -225,8 +225,8 @@ static bool picopass_device_load_data(PicopassDevice* dev, FuriString* path, boo
}
if(!block_read) break;

if(picopass_device_parse_credential(AA1, pacs) != ERR_NONE) break;
if(picopass_device_parse_wiegand(pacs->credential, pacs) != ERR_NONE) break;
picopass_device_parse_credential(AA1, pacs);
picopass_device_parse_wiegand(pacs->credential, pacs);

parsed = true;
} while(false);
Expand Down Expand Up @@ -343,43 +343,28 @@ void picopass_device_set_loading_callback(
dev->loading_cb_ctx = context;
}

ReturnCode picopass_device_decrypt(uint8_t* enc_data, uint8_t* dec_data) {
void picopass_device_decrypt(uint8_t* enc_data, uint8_t* dec_data) {
uint8_t key[32] = {0};
memcpy(key, picopass_iclass_decryptionkey, sizeof(picopass_iclass_decryptionkey));
mbedtls_des3_context ctx;
mbedtls_des3_init(&ctx);
mbedtls_des3_set2key_dec(&ctx, key);
mbedtls_des3_crypt_ecb(&ctx, enc_data, dec_data);
mbedtls_des3_free(&ctx);
return ERR_NONE;
}

ReturnCode picopass_device_parse_credential(PicopassBlock* AA1, PicopassPacs* pacs) {
ReturnCode err;

void picopass_device_parse_credential(PicopassBlock* AA1, PicopassPacs* pacs) {
pacs->biometrics = AA1[6].data[4];
pacs->pin_length = AA1[6].data[6] & 0x0F;
pacs->encryption = AA1[6].data[7];

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

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

err = picopass_device_decrypt(AA1[9].data, pacs->pin1);
if(err != ERR_NONE) {
FURI_LOG_E(TAG, "decrypt error %d", err);
return err;
}
picopass_device_decrypt(AA1[9].data, pacs->pin1);
} else if(pacs->encryption == PicopassDeviceEncryptionNone) {
FURI_LOG_D(TAG, "No Encryption");
memcpy(pacs->credential, AA1[7].data, PICOPASS_BLOCK_LEN);
Expand All @@ -392,11 +377,9 @@ ReturnCode picopass_device_parse_credential(PicopassBlock* AA1, PicopassPacs* pa
}

pacs->sio = (AA1[10].data[0] == 0x30); // rough check

return ERR_NONE;
}

ReturnCode picopass_device_parse_wiegand(uint8_t* credential, PicopassPacs* pacs) {
void picopass_device_parse_wiegand(uint8_t* credential, PicopassPacs* pacs) {
uint32_t* halves = (uint32_t*)credential;
if(halves[0] == 0) {
uint8_t leading0s = __builtin_clz(REVERSE_BYTES_U32(halves[1]));
Expand All @@ -413,8 +396,6 @@ ReturnCode picopass_device_parse_wiegand(uint8_t* credential, PicopassPacs* pacs
swapped = swapped ^ sentinel;
memcpy(credential, &swapped, sizeof(uint64_t));
FURI_LOG_D(TAG, "PACS: (%d) %016llx", pacs->bitLength, swapped);

return ERR_NONE;
}

bool picopass_device_hid_csn(PicopassDevice* dev) {
Expand Down
5 changes: 2 additions & 3 deletions picopass_device.h
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,6 @@ typedef struct {
typedef struct {
PicopassBlock AA1[PICOPASS_MAX_APP_LIMIT];
PicopassPacs pacs;
IclassEliteDictAttackData iclass_elite_dict_attack_data;
} PicopassDeviceData;

typedef struct {
Expand Down Expand Up @@ -147,6 +146,6 @@ void picopass_device_set_loading_callback(
PicopassLoadingCallback callback,
void* context);

ReturnCode picopass_device_parse_credential(PicopassBlock* AA1, PicopassPacs* pacs);
ReturnCode picopass_device_parse_wiegand(uint8_t* credential, PicopassPacs* pacs);
void picopass_device_parse_credential(PicopassBlock* AA1, PicopassPacs* pacs);
void picopass_device_parse_wiegand(uint8_t* credential, PicopassPacs* pacs);
bool picopass_device_hid_csn(PicopassDevice* dev);
42 changes: 40 additions & 2 deletions picopass_i.h
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
#pragma once

#include "picopass.h"
#include "picopass_worker.h"
#include "picopass_device.h"

#include "rfal_picopass.h"
Expand Down Expand Up @@ -29,8 +28,17 @@
#include <lib/toolbox/path.h>
#include <picopass_icons.h>

#include <nfc/nfc.h>
#include <nfc/helpers/nfc_dict.h>
#include "protocol/picopass_poller.h"
#include "protocol/picopass_listener.h"

#define PICOPASS_TEXT_STORE_SIZE 128

#define PICOPASS_ICLASS_ELITE_DICT_FLIPPER_NAME APP_ASSETS_PATH("iclass_elite_dict.txt")
#define PICOPASS_ICLASS_STANDARD_DICT_FLIPPER_NAME APP_ASSETS_PATH("iclass_standard_dict.txt")
#define PICOPASS_ICLASS_ELITE_DICT_USER_NAME APP_DATA_PATH("assets/iclass_elite_dict_user.txt")

enum PicopassCustomEvent {
// Reserve first 100 events for button types and indexes, starting from 0
PicopassCustomEventReserved = 100,
Expand All @@ -40,21 +48,47 @@ enum PicopassCustomEvent {
PicopassCustomEventByteInputDone,
PicopassCustomEventTextInputDone,
PicopassCustomEventDictAttackSkip,
PicopassCustomEventDictAttackUpdateView,
PicopassCustomEventLoclassGotMac,
PicopassCustomEventLoclassGotStandardKey,

PicopassCustomEventPollerSuccess,
PicopassCustomEventPollerFail,
};

typedef enum {
EventTypeTick,
EventTypeKey,
} EventType;

typedef struct {
const char* name;
uint16_t total_keys;
uint16_t current_key;
bool card_detected;
} PicopassDictAttackContext;

typedef struct {
uint8_t key_to_write[PICOPASS_BLOCK_LEN];
bool is_elite;
} PicopassWriteKeyContext;

typedef struct {
size_t macs_collected;
} PicopassLoclassContext;

struct Picopass {
PicopassWorker* worker;
ViewDispatcher* view_dispatcher;
Gui* gui;
NotificationApp* notifications;
SceneManager* scene_manager;
PicopassDevice* dev;

Nfc* nfc;
PicopassPoller* poller;
PicopassListener* listener;
NfcDict* dict;

char text_store[PICOPASS_TEXT_STORE_SIZE + 1];
FuriString* text_box_store;
uint8_t byte_input_store[PICOPASS_BLOCK_LEN];
Expand All @@ -68,6 +102,10 @@ struct Picopass {
Widget* widget;
DictAttack* dict_attack;
Loclass* loclass;

PicopassDictAttackContext dict_attack_ctx;
PicopassWriteKeyContext write_key_context;
PicopassLoclassContext loclass_context;
};

typedef enum {
Expand Down
Loading

0 comments on commit 6ccba6c

Please sign in to comment.