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
56 changes: 28 additions & 28 deletions picopass/picopass_device.c
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ static bool picopass_device_save_file_seader(
FuriString* file_path) {
furi_assert(dev);
PicopassPacs* pacs = &dev->dev_data.pacs;
PicopassBlock* AA1 = dev->dev_data.AA1;
PicopassBlock* card_data = dev->dev_data.card_data;
bool result = false;

const char* seader_file_header = "Flipper Seader Credential";
Expand All @@ -67,17 +67,17 @@ static bool picopass_device_save_file_seader(
// TODO: save SR vs SE more properly
if(pacs->sio) { // SR
for(uint8_t i = 0; i < 8; i++) {
memcpy(sio + (i * 8), AA1[10 + i].data, PICOPASS_BLOCK_LEN);
memcpy(sio + (i * 8), card_data[10 + i].data, PICOPASS_BLOCK_LEN);
}
if(!flipper_format_write_hex(file, "SIO", sio, sizeof(sio))) break;
} else if(pacs->se_enabled) { //SE
for(uint8_t i = 0; i < 8; i++) {
memcpy(sio + (i * 8), AA1[6 + i].data, PICOPASS_BLOCK_LEN);
memcpy(sio + (i * 8), card_data[6 + i].data, PICOPASS_BLOCK_LEN);
}
if(!flipper_format_write_hex(file, "SIO", sio, sizeof(sio))) break;
}
if(!flipper_format_write_hex(
file, "Diversifier", AA1[PICOPASS_CSN_BLOCK_INDEX].data, PICOPASS_BLOCK_LEN))
file, "Diversifier", card_data[PICOPASS_CSN_BLOCK_INDEX].data, PICOPASS_BLOCK_LEN))
break;

result = true;
Expand Down Expand Up @@ -162,13 +162,13 @@ static bool picopass_device_save_file(
bool saved = false;
FlipperFormat* file = flipper_format_file_alloc(dev->storage);
PicopassPacs* pacs = &dev->dev_data.pacs;
PicopassBlock* AA1 = dev->dev_data.AA1;
PicopassBlock* card_data = dev->dev_data.card_data;
FuriString* temp_str;
temp_str = furi_string_alloc();

if(dev->format == PicopassDeviceSaveFormatPartial) {
// Clear key that may have been set when doing key tests for legacy
memset(AA1[PICOPASS_SECURE_KD_BLOCK_INDEX].data, 0, PICOPASS_BLOCK_LEN);
memset(card_data[PICOPASS_SECURE_KD_BLOCK_INDEX].data, 0, PICOPASS_BLOCK_LEN);
}

do {
Expand Down Expand Up @@ -197,13 +197,13 @@ static bool picopass_device_save_file(
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] :
size_t app_limit = card_data[PICOPASS_CONFIG_BLOCK_INDEX].data[0] < PICOPASS_MAX_APP_LIMIT ?
card_data[PICOPASS_CONFIG_BLOCK_INDEX].data[0] :
PICOPASS_MAX_APP_LIMIT;
for(size_t i = 0; i < app_limit; i++) {
furi_string_printf(temp_str, "Block %d", i);
if(!flipper_format_write_hex(
file, furi_string_get_cstr(temp_str), AA1[i].data, PICOPASS_BLOCK_LEN)) {
file, furi_string_get_cstr(temp_str), card_data[i].data, PICOPASS_BLOCK_LEN)) {
block_saved = false;
break;
}
Expand Down Expand Up @@ -245,7 +245,7 @@ bool picopass_device_save(PicopassDevice* dev, const char* dev_name) {
static bool picopass_device_load_data(PicopassDevice* dev, FuriString* path, bool show_dialog) {
bool parsed = false;
FlipperFormat* file = flipper_format_file_alloc(dev->storage);
PicopassBlock* AA1 = dev->dev_data.AA1;
PicopassBlock* card_data = dev->dev_data.card_data;
PicopassPacs* pacs = &dev->dev_data.pacs;
FuriString* temp_str;
temp_str = furi_string_alloc();
Expand All @@ -272,26 +272,26 @@ static bool picopass_device_load_data(PicopassDevice* dev, FuriString* path, boo
for(size_t i = 0; i < 6; i++) {
furi_string_printf(temp_str, "Block %d", i);
if(!flipper_format_read_hex(
file, furi_string_get_cstr(temp_str), AA1[i].data, PICOPASS_BLOCK_LEN)) {
file, furi_string_get_cstr(temp_str), card_data[i].data, PICOPASS_BLOCK_LEN)) {
block_read = false;
break;
}
}

size_t app_limit = AA1[PICOPASS_CONFIG_BLOCK_INDEX].data[0];
size_t app_limit = card_data[PICOPASS_CONFIG_BLOCK_INDEX].data[0];
// Fix for unpersonalized cards that have app_limit set to 0xFF
if(app_limit > PICOPASS_MAX_APP_LIMIT) app_limit = PICOPASS_MAX_APP_LIMIT;
for(size_t i = 6; i < app_limit; i++) {
furi_string_printf(temp_str, "Block %d", i);
if(!flipper_format_read_hex(
file, furi_string_get_cstr(temp_str), AA1[i].data, PICOPASS_BLOCK_LEN)) {
file, furi_string_get_cstr(temp_str), card_data[i].data, PICOPASS_BLOCK_LEN)) {
block_read = false;
break;
}
}
if(!block_read) break;

picopass_device_parse_credential(AA1, pacs);
picopass_device_parse_credential(card_data, pacs);
picopass_device_parse_wiegand(pacs->credential, pacs);

parsed = true;
Expand Down Expand Up @@ -364,7 +364,7 @@ bool picopass_file_select(PicopassDevice* dev) {

void picopass_device_data_clear(PicopassDeviceData* dev_data) {
for(size_t i = 0; i < PICOPASS_MAX_APP_LIMIT; i++) {
memset(dev_data->AA1[i].data, 0, sizeof(dev_data->AA1[i].data));
memset(dev_data->card_data[i].data, 0, sizeof(dev_data->card_data[i].data));
}
dev_data->pacs.legacy = false;
dev_data->pacs.se_enabled = false;
Expand Down Expand Up @@ -419,30 +419,30 @@ void picopass_device_decrypt(uint8_t* enc_data, uint8_t* dec_data) {
mbedtls_des3_free(&ctx);
}

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];
void picopass_device_parse_credential(PicopassBlock* card_data, PicopassPacs* pacs) {
pacs->biometrics = card_data[6].data[4];
pacs->pin_length = card_data[6].data[6] & 0x0F;
pacs->encryption = card_data[6].data[7];

if(pacs->encryption == PicopassDeviceEncryption3DES) {
FURI_LOG_D(TAG, "3DES Encrypted");
picopass_device_decrypt(AA1[7].data, pacs->credential);
picopass_device_decrypt(card_data[7].data, pacs->credential);

picopass_device_decrypt(AA1[8].data, pacs->pin0);
picopass_device_decrypt(card_data[8].data, pacs->pin0);

picopass_device_decrypt(AA1[9].data, pacs->pin1);
picopass_device_decrypt(card_data[9].data, pacs->pin1);
} else if(pacs->encryption == PicopassDeviceEncryptionNone) {
FURI_LOG_D(TAG, "No Encryption");
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);
memcpy(pacs->credential, card_data[7].data, PICOPASS_BLOCK_LEN);
memcpy(pacs->pin0, card_data[8].data, PICOPASS_BLOCK_LEN);
memcpy(pacs->pin1, card_data[9].data, PICOPASS_BLOCK_LEN);
} else if(pacs->encryption == PicopassDeviceEncryptionDES) {
FURI_LOG_D(TAG, "DES Encrypted");
} else {
FURI_LOG_D(TAG, "Unknown encryption");
}

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

void picopass_device_parse_wiegand(uint8_t* credential, PicopassPacs* pacs) {
Expand All @@ -466,8 +466,8 @@ void picopass_device_parse_wiegand(uint8_t* credential, PicopassPacs* pacs) {

bool picopass_device_hid_csn(PicopassDevice* dev) {
furi_assert(dev);
PicopassBlock* AA1 = dev->dev_data.AA1;
uint8_t* csn = AA1[PICOPASS_CSN_BLOCK_INDEX].data;
PicopassBlock* card_data = dev->dev_data.card_data;
uint8_t* csn = card_data[PICOPASS_CSN_BLOCK_INDEX].data;
// From Proxmark3 RRG sourcecode
bool isHidRange = (memcmp(csn + 5, "\xFF\x12\xE0", 3) == 0) && ((csn[4] & 0xF0) == 0xF0);

Expand Down
4 changes: 2 additions & 2 deletions picopass/picopass_device.h
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ typedef struct {
} PicopassBlock;

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

Expand Down Expand Up @@ -148,6 +148,6 @@ void picopass_device_set_loading_callback(
PicopassLoadingCallback callback,
void* context);

void picopass_device_parse_credential(PicopassBlock* AA1, PicopassPacs* pacs);
void picopass_device_parse_credential(PicopassBlock* card_data, PicopassPacs* pacs);
void picopass_device_parse_wiegand(uint8_t* credential, PicopassPacs* pacs);
bool picopass_device_hid_csn(PicopassDevice* dev);
42 changes: 21 additions & 21 deletions picopass/protocol/picopass_listener.c
Original file line number Diff line number Diff line change
Expand Up @@ -43,11 +43,11 @@ static void picopass_listener_loclass_update_csn(PicopassListener* instance) {
// collect LOCLASS_NUM_PER_CSN nonces in a row for each CSN
const uint8_t* csn =
loclass_csns[(instance->key_block_num / LOCLASS_NUM_PER_CSN) % LOCLASS_NUM_CSNS];
memcpy(instance->data->AA1[PICOPASS_CSN_BLOCK_INDEX].data, csn, sizeof(PicopassBlock));
memcpy(instance->data->card_data[PICOPASS_CSN_BLOCK_INDEX].data, csn, sizeof(PicopassBlock));

uint8_t key[PICOPASS_BLOCK_LEN] = {};
loclass_iclass_calc_div_key(csn, picopass_iclass_key, key, false);
memcpy(instance->data->AA1[PICOPASS_SECURE_KD_BLOCK_INDEX].data, key, sizeof(PicopassBlock));
memcpy(instance->data->card_data[PICOPASS_SECURE_KD_BLOCK_INDEX].data, key, sizeof(PicopassBlock));

picopass_listener_init_cipher_state_key(instance, key);
}
Expand Down Expand Up @@ -118,7 +118,7 @@ PicopassListenerCommand
(instance->state == PicopassListenerStateIdle)) {
bit_buffer_copy_bytes(
instance->tmp_buffer,
instance->data->AA1[PICOPASS_CSN_BLOCK_INDEX].data,
instance->data->card_data[PICOPASS_CSN_BLOCK_INDEX].data,
sizeof(PicopassBlock));
} else {
picopass_listener_write_anticoll_csn(instance, instance->tmp_buffer);
Expand All @@ -139,7 +139,7 @@ PicopassListenerCommand
instance->state = PicopassListenerStateSelected;
bit_buffer_copy_bytes(
instance->tx_buffer,
instance->data->AA1[PICOPASS_CSN_BLOCK_INDEX].data,
instance->data->card_data[PICOPASS_CSN_BLOCK_INDEX].data,
sizeof(PicopassBlock));

PicopassError error = picopass_listener_send_frame(instance, instance->tx_buffer);
Expand All @@ -162,7 +162,7 @@ PicopassListenerCommand
uint8_t block_num = bit_buffer_get_byte(buf, 1);
if(block_num > PICOPASS_MAX_APP_LIMIT) break;

bool secured = (instance->data->AA1[PICOPASS_CONFIG_BLOCK_INDEX].data[7] &
bool secured = (instance->data->card_data[PICOPASS_CONFIG_BLOCK_INDEX].data[7] &
PICOPASS_FUSE_CRYPT10) != PICOPASS_FUSE_CRYPT0;

// TODO: Check CRC?
Expand All @@ -176,7 +176,7 @@ PicopassListenerCommand
}
} else {
bit_buffer_copy_bytes(
instance->tx_buffer, instance->data->AA1[block_num].data, sizeof(PicopassBlock));
instance->tx_buffer, instance->data->card_data[block_num].data, sizeof(PicopassBlock));
}
PicopassError error = picopass_listener_send_frame(instance, instance->tx_buffer);
if(error != PicopassErrorNone) {
Expand Down Expand Up @@ -211,7 +211,7 @@ static PicopassListenerCommand

// DATA(8)
bit_buffer_copy_bytes(
instance->tx_buffer, instance->data->AA1[block_num].data, sizeof(PicopassBlock));
instance->tx_buffer, instance->data->card_data[block_num].data, sizeof(PicopassBlock));
NfcError error = nfc_listener_tx(instance->nfc, instance->tx_buffer);
if(error != NfcErrorNone) {
FURI_LOG_D(TAG, "Failed to tx read check response: %d", error);
Expand Down Expand Up @@ -244,7 +244,7 @@ PicopassListenerCommand
#ifndef PICOPASS_DEBUG_IGNORE_LOCLASS_STD_KEY
// loclass mode stores the derived standard debit key in Kd to check

PicopassBlock key = instance->data->AA1[PICOPASS_SECURE_KD_BLOCK_INDEX];
PicopassBlock key = instance->data->card_data[PICOPASS_SECURE_KD_BLOCK_INDEX];
uint8_t rmac[4];
const uint8_t* rx_data = bit_buffer_get_data(buf);
loclass_opt_doReaderMAC_2(instance->cipher_state, &rx_data[1], rmac, key.data);
Expand Down Expand Up @@ -285,8 +285,8 @@ PicopassListenerCommand
loclass_writer_write_params(
instance->writer,
instance->key_block_num + i - LOCLASS_NUM_PER_CSN,
instance->data->AA1[PICOPASS_CSN_BLOCK_INDEX].data,
instance->data->AA1[PICOPASS_SECURE_EPURSE_BLOCK_INDEX].data,
instance->data->card_data[PICOPASS_CSN_BLOCK_INDEX].data,
instance->data->card_data[PICOPASS_SECURE_EPURSE_BLOCK_INDEX].data,
instance->loclass_mac_buffer + (i * 8),
instance->loclass_mac_buffer + (i * 8) + 4);
}
Expand Down Expand Up @@ -314,8 +314,8 @@ PicopassListenerCommand

PicopassDevice* dev = picopass->dev;

const uint8_t* csn = instance->data->AA1[PICOPASS_CSN_BLOCK_INDEX].data;
const uint8_t* epurse = instance->data->AA1[PICOPASS_SECURE_EPURSE_BLOCK_INDEX].data;
const uint8_t* csn = instance->data->card_data[PICOPASS_CSN_BLOCK_INDEX].data;
const uint8_t* epurse = instance->data->card_data[PICOPASS_SECURE_EPURSE_BLOCK_INDEX].data;

FuriString* temp_str = furi_string_alloc();
FuriString* filename = furi_string_alloc();
Expand Down Expand Up @@ -368,13 +368,13 @@ PicopassListenerCommand
PicopassListenerCommand command = PicopassListenerCommandSilent;

do {
bool secured = (instance->data->AA1[PICOPASS_CONFIG_BLOCK_INDEX].data[7] &
bool secured = (instance->data->card_data[PICOPASS_CONFIG_BLOCK_INDEX].data[7] &
PICOPASS_FUSE_CRYPT10) != PICOPASS_FUSE_CRYPT0;
if(!secured) break;

uint8_t rmac[4] = {};
uint8_t tmac[4] = {};
const uint8_t* key = instance->data->AA1[instance->key_block_num].data;
const uint8_t* key = instance->data->card_data[instance->key_block_num].data;
bool no_key = picopass_is_memset(key, 0x00, PICOPASS_BLOCK_LEN);
const uint8_t* rx_data = bit_buffer_get_data(buf);

Expand Down Expand Up @@ -432,9 +432,9 @@ PicopassListenerCommand
if(instance->mode == PicopassListenerModeLoclass) break;
if(instance->state != PicopassListenerStateSelected) break;

PicopassBlock config_block = instance->data->AA1[PICOPASS_CONFIG_BLOCK_INDEX];
PicopassBlock config_block = instance->data->card_data[PICOPASS_CONFIG_BLOCK_INDEX];
bool pers_mode = PICOPASS_LISTENER_HAS_MASK(config_block.data[7], PICOPASS_FUSE_PERS);
bool secured = (instance->data->AA1[PICOPASS_CONFIG_BLOCK_INDEX].data[7] &
bool secured = (instance->data->card_data[PICOPASS_CONFIG_BLOCK_INDEX].data[7] &
PICOPASS_FUSE_CRYPT10) != PICOPASS_FUSE_CRYPT0;

const uint8_t* rx_data = bit_buffer_get_data(buf);
Expand Down Expand Up @@ -502,7 +502,7 @@ PicopassListenerCommand
// fallthrough
case PICOPASS_SECURE_KC_BLOCK_INDEX:
if(!pers_mode && secured) {
new_block = instance->data->AA1[block_num];
new_block = instance->data->card_data[block_num];
for(size_t i = 0; i < sizeof(PicopassBlock); i++) {
new_block.data[i] ^= rx_data[i + 2];
}
Expand All @@ -515,7 +515,7 @@ PicopassListenerCommand
break;
}

instance->data->AA1[block_num] = new_block;
instance->data->card_data[block_num] = new_block;
if(secured && ((block_num == instance->key_block_num) ||
(block_num == PICOPASS_SECURE_EPURSE_BLOCK_INDEX))) {
picopass_listener_init_cipher_state(instance);
Expand All @@ -530,7 +530,7 @@ PicopassListenerCommand
}
} else {
bit_buffer_copy_bytes(
instance->tx_buffer, instance->data->AA1[block_num].data, sizeof(PicopassBlock));
instance->tx_buffer, instance->data->card_data[block_num].data, sizeof(PicopassBlock));
}

PicopassError error = picopass_listener_send_frame(instance, instance->tx_buffer);
Expand All @@ -555,7 +555,7 @@ PicopassListenerCommand
uint8_t block_start = bit_buffer_get_byte(buf, 1);
if(block_start + 4 >= PICOPASS_MAX_APP_LIMIT) break;

bool secured = (instance->data->AA1[PICOPASS_CONFIG_BLOCK_INDEX].data[7] &
bool secured = (instance->data->card_data[PICOPASS_CONFIG_BLOCK_INDEX].data[7] &
PICOPASS_FUSE_CRYPT10) != PICOPASS_FUSE_CRYPT0;

// TODO: Check CRC?
Expand All @@ -570,7 +570,7 @@ PicopassListenerCommand
}
} else {
bit_buffer_append_bytes(
instance->tx_buffer, instance->data->AA1[i].data, sizeof(PicopassBlock));
instance->tx_buffer, instance->data->card_data[i].data, sizeof(PicopassBlock));
}
}

Expand Down
6 changes: 3 additions & 3 deletions picopass/protocol/picopass_listener_i.c
Original file line number Diff line number Diff line change
Expand Up @@ -21,14 +21,14 @@ static PicopassError picopass_listener_process_error(NfcError error) {
void picopass_listener_init_cipher_state_key(PicopassListener* instance, const uint8_t* key) {
uint8_t cc[PICOPASS_BLOCK_LEN] = {};
memcpy(
cc, instance->data->AA1[PICOPASS_SECURE_EPURSE_BLOCK_INDEX].data, sizeof(PicopassBlock));
cc, instance->data->card_data[PICOPASS_SECURE_EPURSE_BLOCK_INDEX].data, sizeof(PicopassBlock));

instance->cipher_state = loclass_opt_doTagMAC_1(cc, key);
}

void picopass_listener_init_cipher_state(PicopassListener* instance) {
uint8_t key[PICOPASS_BLOCK_LEN] = {};
memcpy(key, instance->data->AA1[instance->key_block_num].data, sizeof(PicopassBlock));
memcpy(key, instance->data->card_data[instance->key_block_num].data, sizeof(PicopassBlock));

picopass_listener_init_cipher_state_key(instance, key);
}
Expand All @@ -42,7 +42,7 @@ PicopassError picopass_listener_send_frame(PicopassListener* instance, BitBuffer

// from proxmark3 armsrc/iclass.c rotateCSN
PicopassError picopass_listener_write_anticoll_csn(PicopassListener* instance, BitBuffer* buffer) {
const uint8_t* uid = instance->data->AA1[PICOPASS_CSN_BLOCK_INDEX].data;
const uint8_t* uid = instance->data->card_data[PICOPASS_CSN_BLOCK_INDEX].data;
bit_buffer_reset(buffer);
for(size_t i = 0; i < PICOPASS_BLOCK_LEN; i++) {
bit_buffer_append_byte(buffer, (uid[i] >> 3) | (uid[(i + 1) % 8] << 5));
Expand Down
Loading