Skip to content

Commit a825b14

Browse files
authored
Merge pull request #105 from bettse/iclass_dump
Iclass dump THANKS TO BETTSE
2 parents e02be79 + 7ab2754 commit a825b14

File tree

5 files changed

+81
-47
lines changed

5 files changed

+81
-47
lines changed

applications/picopass/picopass_device.c

+29-19
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,9 @@ static const uint32_t picopass_file_version = 1;
1010

1111
PicopassDevice* picopass_device_alloc() {
1212
PicopassDevice* picopass_dev = malloc(sizeof(PicopassDevice));
13+
picopass_dev->dev_data.pacs.legacy = false;
14+
picopass_dev->dev_data.pacs.se_enabled = false;
15+
picopass_dev->dev_data.pacs.pin_length = 0;
1316
picopass_dev->storage = furi_record_open("storage");
1417
picopass_dev->dialogs = furi_record_open("dialogs");
1518
return picopass_dev;
@@ -32,7 +35,7 @@ static bool picopass_device_save_file(
3235
bool saved = false;
3336
FlipperFormat* file = flipper_format_file_alloc(dev->storage);
3437
PicopassPacs* pacs = &dev->dev_data.pacs;
35-
ApplicationArea* AA1 = &dev->dev_data.AA1;
38+
PicopassBlock* AA1 = dev->dev_data.AA1;
3639
string_t temp_str;
3740
string_init(temp_str);
3841

@@ -67,27 +70,29 @@ static bool picopass_device_save_file(
6770
if(!flipper_format_write_hex(
6871
file, "Credential", pacs->credential, PICOPASS_BLOCK_LEN))
6972
break;
70-
if(!flipper_format_write_hex(file, "PIN", pacs->pin0, PICOPASS_BLOCK_LEN)) break;
71-
if(!flipper_format_write_hex(file, "PIN(cont.)", pacs->pin1, PICOPASS_BLOCK_LEN))
72-
break;
73-
74-
if(!flipper_format_write_comment_cstr(file, "Picopass blocks")) break;
75-
// TODO: Save CSN, CFG, AA1, etc
76-
bool block_saved = true;
77-
for(size_t i = 0; i < 4; i++) {
78-
string_printf(temp_str, "Block %d", i + 6);
73+
if(pacs->pin_length > 0) {
74+
if(!flipper_format_write_hex(file, "PIN\t\t", pacs->pin0, PICOPASS_BLOCK_LEN))
75+
break;
7976
if(!flipper_format_write_hex(
80-
file,
81-
string_get_cstr(temp_str),
82-
AA1->block[i].data,
83-
PICOPASS_BLOCK_LEN)) {
84-
block_saved = false;
77+
file, "PIN(cont.)\t", pacs->pin1, PICOPASS_BLOCK_LEN))
8578
break;
86-
}
8779
}
88-
if(!block_saved) break;
89-
if(!flipper_format_write_comment_cstr(file, "This is currently incomplete")) break;
9080
}
81+
if(!flipper_format_write_comment_cstr(file, "Picopass blocks")) break;
82+
bool block_saved = true;
83+
84+
size_t app_limit = AA1[PICOPASS_CONFIG_BLOCK_INDEX].data[0] < PICOPASS_MAX_APP_LIMIT ?
85+
AA1[PICOPASS_CONFIG_BLOCK_INDEX].data[0] :
86+
PICOPASS_MAX_APP_LIMIT;
87+
for(size_t i = 0; i < app_limit; i++) {
88+
string_printf(temp_str, "Block %d", i);
89+
if(!flipper_format_write_hex(
90+
file, string_get_cstr(temp_str), AA1[i].data, PICOPASS_BLOCK_LEN)) {
91+
block_saved = false;
92+
break;
93+
}
94+
}
95+
if(!block_saved) break;
9196
} else if(dev->format == PicopassDeviceSaveFormatLF) {
9297
const char* lf_header = "Flipper RFID key";
9398
// Write header
@@ -142,5 +147,10 @@ void picopass_device_free(PicopassDevice* picopass_dev) {
142147
}
143148

144149
void picopass_device_data_clear(PicopassDeviceData* dev_data) {
145-
memset(&dev_data->AA1, 0, sizeof(ApplicationArea));
150+
for(size_t i = 0; i < PICOPASS_MAX_APP_LIMIT; i++) {
151+
memset(dev_data->AA1[i].data, 0, sizeof(dev_data->AA1[i].data));
152+
}
153+
dev_data->pacs.legacy = false;
154+
dev_data->pacs.se_enabled = false;
155+
dev_data->pacs.pin_length = 0;
146156
}

applications/picopass/picopass_device.h

+13-1
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,11 @@
1010
#define PICOPASS_DEV_NAME_MAX_LEN 22
1111
#define PICOPASS_READER_DATA_MAX_SIZE 64
1212
#define PICOPASS_BLOCK_LEN 8
13+
#define PICOPASS_MAX_APP_LIMIT 32
14+
15+
#define PICOPASS_CSN_BLOCK_INDEX 0
16+
#define PICOPASS_CONFIG_BLOCK_INDEX 1
17+
#define PICOPASS_AIA_BLOCK_INDEX 5
1318

1419
#define PICOPASS_APP_FOLDER "/any/picopass"
1520
#define PICOPASS_APP_EXTENSION ".picopass"
@@ -35,7 +40,10 @@ typedef struct {
3540
} PicopassWiegandRecord;
3641

3742
typedef struct {
43+
bool legacy;
44+
bool se_enabled;
3845
bool biometrics;
46+
uint8_t pin_length;
3947
PicopassEncryption encryption;
4048
uint8_t credential[8];
4149
uint8_t pin0[8];
@@ -44,7 +52,11 @@ typedef struct {
4452
} PicopassPacs;
4553

4654
typedef struct {
47-
ApplicationArea AA1;
55+
uint8_t data[PICOPASS_BLOCK_LEN];
56+
} PicopassBlock;
57+
58+
typedef struct {
59+
PicopassBlock AA1[PICOPASS_MAX_APP_LIMIT];
4860
PicopassPacs pacs;
4961
} PicopassDeviceData;
5062

applications/picopass/picopass_worker.c

+33-18
Original file line numberDiff line numberDiff line change
@@ -165,7 +165,7 @@ ReturnCode picopass_detect_card(int timeout) {
165165
return ERR_NONE;
166166
}
167167

168-
ReturnCode picopass_read_card(ApplicationArea* AA1) {
168+
ReturnCode picopass_read_card(PicopassBlock* AA1) {
169169
rfalPicoPassIdentifyRes idRes;
170170
rfalPicoPassSelectRes selRes;
171171
rfalPicoPassReadCheckRes rcRes;
@@ -205,10 +205,20 @@ ReturnCode picopass_read_card(ApplicationArea* AA1) {
205205
return err;
206206
}
207207

208-
for(size_t i = 0; i < 4; i++) {
209-
FURI_LOG_D(TAG, "rfalPicoPassPollerReadBlock block %d", i + 6);
208+
rfalPicoPassReadBlockRes csn;
209+
err = rfalPicoPassPollerReadBlock(PICOPASS_CSN_BLOCK_INDEX, &csn);
210+
memcpy(AA1[PICOPASS_CSN_BLOCK_INDEX].data, csn.data, sizeof(csn.data));
211+
212+
rfalPicoPassReadBlockRes cfg;
213+
err = rfalPicoPassPollerReadBlock(PICOPASS_CONFIG_BLOCK_INDEX, &cfg);
214+
memcpy(AA1[PICOPASS_CONFIG_BLOCK_INDEX].data, cfg.data, sizeof(cfg.data));
215+
216+
size_t app_limit = cfg.data[0] < PICOPASS_MAX_APP_LIMIT ? cfg.data[0] : PICOPASS_MAX_APP_LIMIT;
217+
218+
for(size_t i = 2; i < app_limit; i++) {
219+
FURI_LOG_D(TAG, "rfalPicoPassPollerReadBlock block %d", i);
210220
rfalPicoPassReadBlockRes block;
211-
err = rfalPicoPassPollerReadBlock(i + 6, &block);
221+
err = rfalPicoPassPollerReadBlock(i, &block);
212222
if(err != ERR_NONE) {
213223
FURI_LOG_E(TAG, "rfalPicoPassPollerReadBlock error %d", err);
214224
return err;
@@ -217,7 +227,7 @@ ReturnCode picopass_read_card(ApplicationArea* AA1) {
217227
FURI_LOG_D(
218228
TAG,
219229
"rfalPicoPassPollerReadBlock %d %02x%02x%02x%02x%02x%02x%02x%02x",
220-
i + 6,
230+
i,
221231
block.data[0],
222232
block.data[1],
223233
block.data[2],
@@ -227,7 +237,7 @@ ReturnCode picopass_read_card(ApplicationArea* AA1) {
227237
block.data[6],
228238
block.data[7]);
229239

230-
memcpy(&(AA1->block[i]), &block, sizeof(block));
240+
memcpy(AA1[i].data, block.data, sizeof(block.data));
231241
}
232242

233243
return ERR_NONE;
@@ -251,7 +261,7 @@ void picopass_worker_detect(PicopassWorker* picopass_worker) {
251261
picopass_device_data_clear(picopass_worker->dev_data);
252262
PicopassDeviceData* dev_data = picopass_worker->dev_data;
253263

254-
ApplicationArea* AA1 = &dev_data->AA1;
264+
PicopassBlock* AA1 = dev_data->AA1;
255265
PicopassPacs* pacs = &dev_data->pacs;
256266
ReturnCode err;
257267

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

266-
pacs->biometrics = AA1->block[0].data[4];
267-
pacs->encryption = AA1->block[0].data[7];
276+
// Thank you proxmark!
277+
pacs->legacy = (memcmp(AA1[5].data, "\xff\xff\xff\xff\xff\xff\xff\xff", 8) == 0);
278+
pacs->se_enabled = (memcmp(AA1[5].data, "\xff\xff\xff\x00\x06\xff\xff\xff", 8) == 0);
279+
280+
pacs->biometrics = AA1[6].data[4];
281+
pacs->pin_length = AA1[6].data[6] & 0x0F;
282+
pacs->encryption = AA1[6].data[7];
268283

269-
if(pacs->encryption == 0x17) {
284+
if(pacs->encryption == PicopassDeviceEncryption3DES) {
270285
FURI_LOG_D(TAG, "3DES Encrypted");
271-
err = picopass_worker_decrypt(AA1->block[1].data, pacs->credential);
286+
err = picopass_worker_decrypt(AA1[7].data, pacs->credential);
272287
if(err != ERR_NONE) {
273288
FURI_LOG_E(TAG, "decrypt error %d", err);
274289
break;
275290
}
276291

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

283-
err = picopass_worker_decrypt(AA1->block[3].data, pacs->pin1);
298+
err = picopass_worker_decrypt(AA1[9].data, pacs->pin1);
284299
if(err != ERR_NONE) {
285300
FURI_LOG_E(TAG, "decrypt error %d", err);
286301
break;
287302
}
288-
} else if(pacs->encryption == 0x14) {
303+
} else if(pacs->encryption == PicopassDeviceEncryptionNone) {
289304
FURI_LOG_D(TAG, "No Encryption");
290-
memcpy(pacs->credential, AA1->block[1].data, RFAL_PICOPASS_MAX_BLOCK_LEN);
291-
memcpy(pacs->pin0, AA1->block[2].data, RFAL_PICOPASS_MAX_BLOCK_LEN);
292-
memcpy(pacs->pin1, AA1->block[3].data, RFAL_PICOPASS_MAX_BLOCK_LEN);
293-
} else if(pacs->encryption == 0x15) {
305+
memcpy(pacs->credential, AA1[7].data, PICOPASS_BLOCK_LEN);
306+
memcpy(pacs->pin0, AA1[8].data, PICOPASS_BLOCK_LEN);
307+
memcpy(pacs->pin1, AA1[9].data, PICOPASS_BLOCK_LEN);
308+
} else if(pacs->encryption == PicopassDeviceEncryptionDES) {
294309
FURI_LOG_D(TAG, "DES Encrypted");
295310
} else {
296311
FURI_LOG_D(TAG, "Unknown encryption");

applications/picopass/scenes/picopass_scene_read_card_success.c

+6-5
Original file line numberDiff line numberDiff line change
@@ -29,14 +29,17 @@ void picopass_scene_read_card_success_on_enter(void* context) {
2929
PicopassPacs* pacs = &picopass->dev->dev_data.pacs;
3030
Widget* widget = picopass->widget;
3131

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

3738
if(pacs->record.valid) {
3839
string_cat_printf(
3940
wiegand_str, "FC: %03u CN: %05u", pacs->record.FacilityCode, pacs->record.CardNumber);
41+
} else {
42+
string_cat_printf(wiegand_str, "%d bits", pacs->record.bitLength);
4043
}
4144

4245
widget_add_button_element(
@@ -53,10 +56,8 @@ void picopass_scene_read_card_success_on_enter(void* context) {
5356
picopass_scene_read_card_success_widget_callback,
5457
picopass);
5558

56-
if(pacs->record.valid) {
57-
widget_add_string_element(
58-
widget, 64, 12, AlignCenter, AlignCenter, FontPrimary, string_get_cstr(wiegand_str));
59-
}
59+
widget_add_string_element(
60+
widget, 64, 12, AlignCenter, AlignCenter, FontPrimary, string_get_cstr(wiegand_str));
6061
widget_add_string_element(
6162
widget, 64, 32, AlignCenter, AlignCenter, FontSecondary, string_get_cstr(credential_str));
6263

lib/ST25RFAL002/include/rfal_picopass.h

-4
Original file line numberDiff line numberDiff line change
@@ -51,10 +51,6 @@ typedef struct {
5151
uint8_t crc[2];
5252
} rfalPicoPassReadBlockRes;
5353

54-
typedef struct {
55-
rfalPicoPassReadBlockRes block[4];
56-
} ApplicationArea;
57-
5854
ReturnCode rfalPicoPassPollerInitialize(void);
5955
ReturnCode rfalPicoPassPollerCheckPresence(void);
6056
ReturnCode rfalPicoPassPollerIdentify(rfalPicoPassIdentifyRes* idRes);

0 commit comments

Comments
 (0)