fix length check when reading a dictionary file
[RRG-proxmark3.git] / client / src / fileutils.c
blobefd5d9ef4055bad2a6f34570a9d70c97977fd787
1 //-----------------------------------------------------------------------------
2 // Copyright (C) Proxmark3 contributors. See AUTHORS.md for details.
3 //
4 // This program is free software: you can redistribute it and/or modify
5 // it under the terms of the GNU General Public License as published by
6 // the Free Software Foundation, either version 3 of the License, or
7 // (at your option) any later version.
8 //
9 // This program is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 // GNU General Public License for more details.
14 // See LICENSE.txt for the text of the license.
15 //-----------------------------------------------------------------------------
17 // this define is needed for scandir/alphasort to work
18 #define _GNU_SOURCE
19 #include "fileutils.h"
20 #include "preferences.h"
22 #include <dirent.h>
23 #include <ctype.h>
25 #include "pm3_cmd.h"
26 #include "commonutil.h"
27 #include "proxmark3.h"
28 #include "util.h"
29 #include "cmdhficlass.h" // pagemap
30 #include "iclass_cmd.h"
31 #include "iso15.h"
33 #ifdef _WIN32
34 #include "scandir.h"
35 #include <direct.h>
36 #endif
38 #define PATH_MAX_LENGTH 200
40 struct wave_info_t {
41 char signature[4];
42 uint32_t filesize;
43 char type[4];
44 struct {
45 char tag[4];
46 uint32_t size;
47 uint16_t codec;
48 uint16_t nb_channel;
49 uint32_t sample_per_sec;
50 uint32_t byte_per_sec;
51 uint16_t block_align;
52 uint16_t bit_per_sample;
53 } PACKED format;
54 struct {
55 char tag[4];
56 uint32_t size;
57 } PACKED audio_data;
58 } PACKED;
60 /**
61 * @brief detects if file is of a supported filetype based on extension
62 * @param filename
63 * @return o
65 DumpFileType_t get_filetype(const char *filename) {
66 // assume unknown file is BINARY
67 DumpFileType_t o = BIN;
68 if (filename == NULL) {
69 return o;
72 size_t len = strlen(filename);
73 if (len > 4) {
74 // check if valid file extension and attempt to load data
75 char s[FILE_PATH_SIZE];
76 memset(s, 0, sizeof(s));
77 memcpy(s, filename, len);
78 str_lower(s);
80 if (str_endswith(s, "bin")) {
81 o = BIN;
82 } else if (str_endswith(s, "eml")) {
83 o = EML;
84 } else if (str_endswith(s, "json")) {
85 o = JSON;
86 } else if (str_endswith(s, "dic")) {
87 o = DICTIONARY;
88 } else if (str_endswith(s, "mct")) {
89 o = MCT;
90 } else if (str_endswith(s, "nfc")) {
91 o = FLIPPER;
92 } else if (str_endswith(s, "picopass")) {
93 o = FLIPPER;
94 } else {
95 // mfd, trc, trace is binary
96 o = BIN;
97 // log is text
98 // .pm3 is text values of signal data
101 return o;
105 * @brief checks if a file exists
106 * @param filename
107 * @return
109 int fileExists(const char *filename) {
111 #ifdef _WIN32
112 struct _stat st;
113 int result = _stat(filename, &st);
114 #else
115 struct stat st;
116 int result = stat(filename, &st);
117 #endif
118 return result == 0;
122 * @brief checks if path is directory.
123 * @param filename
124 * @return
126 static bool is_directory(const char *filename) {
127 #ifdef _WIN32
128 struct _stat st;
129 if (_stat(filename, &st) == -1)
130 return false;
131 #else
132 struct stat st;
133 // stat(filename, &st);
134 if (lstat(filename, &st) == -1)
135 return false;
136 #endif
137 return S_ISDIR(st.st_mode) != 0;
140 bool setDefaultPath(savePaths_t pathIndex, const char *path) {
142 if (pathIndex < spItemCount) {
144 if ((path == NULL) && (g_session.defaultPaths[pathIndex] != NULL)) {
145 free(g_session.defaultPaths[pathIndex]);
146 g_session.defaultPaths[pathIndex] = NULL;
149 if (path == NULL) {
150 return false;
153 size_t len = strlen(path);
155 g_session.defaultPaths[pathIndex] = (char *)realloc(g_session.defaultPaths[pathIndex], len + 1);
156 strcpy(g_session.defaultPaths[pathIndex], path);
157 return true;
159 return false;
162 static char *filenamemcopy(const char *preferredName, const char *suffix) {
163 if (preferredName == NULL) return NULL;
164 if (suffix == NULL) return NULL;
166 char *fileName = (char *) calloc(strlen(preferredName) + strlen(suffix) + 1, sizeof(uint8_t));
167 if (fileName == NULL) {
168 return NULL;
171 strcpy(fileName, preferredName);
172 if (str_endswith(fileName, suffix)) {
173 return fileName;
176 strcat(fileName, suffix);
177 return fileName;
180 static size_t path_size(savePaths_t a) {
181 if (a >= spItemCount) {
182 return 0;
184 return strlen(g_session.defaultPaths[a]);
187 char *newfilenamemcopy(const char *preferredName, const char *suffix) {
188 return newfilenamemcopyEx(preferredName, suffix, spDefault);
191 char *newfilenamemcopyEx(const char *preferredName, const char *suffix, savePaths_t e_save_path) {
192 if (preferredName == NULL || suffix == NULL) {
193 return NULL;
196 // 1: null terminator
197 // 16: room for filenum to ensure new filename
198 // save_path_len + strlen(PATHSEP): the user preference save paths
199 //const size_t len = p_namelen + strlen(suffix) + 1 + 16 + save_path_len + strlen(PATHSEP);
200 size_t len = FILE_PATH_SIZE;
202 char *fileName = (char *) calloc(len, sizeof(uint8_t));
203 if (fileName == NULL) {
204 return NULL;
207 char *pfn = fileName;
209 // if given path is not an absolute path
210 if ((preferredName[0] != '/') && (preferredName[0] != '\\')) {
211 // user preference save paths
212 size_t save_path_len = path_size(e_save_path);
213 if (save_path_len && save_path_len < (FILE_PATH_SIZE - strlen(PATHSEP))) {
214 snprintf(pfn, len, "%s%s", g_session.defaultPaths[e_save_path], PATHSEP);
215 pfn += save_path_len + strlen(PATHSEP);
216 len -= save_path_len + strlen(PATHSEP);
220 // remove file extension if exist in name
221 size_t p_namelen = strlen(preferredName);
222 if (str_endswith(preferredName, suffix)) {
223 p_namelen -= strlen(suffix);
226 len -= strlen(suffix) + 1;
227 len -= p_namelen;
229 // modify filename
230 snprintf(pfn, len, "%.*s%s", (int)p_namelen, preferredName, suffix);
232 // "-001"
233 len -= 4;
235 int num = 1;
236 // check complete path/filename if exists
237 while (fileExists(fileName)) {
238 // modify filename
239 snprintf(pfn, len, "%.*s-%03d%s", (int)p_namelen, preferredName, num, suffix);
240 num++;
243 return fileName;
246 // trunacate down a filename to LEN size
247 void truncate_filename(char *fn, uint16_t maxlen) {
248 if (fn == NULL || maxlen < 5) {
249 return;
252 // Check if the filename is already shorter than or equal to the desired length
253 if (strlen(fn) <= maxlen) {
254 return;
257 // If there's no extension or it's too long, just truncate the filename
258 fn[maxlen - 3] = '\0';
259 strcat(fn, "...");
262 // --------- SAVE FILES
263 int saveFile(const char *preferredName, const char *suffix, const void *data, size_t datalen) {
264 return saveFileEx(preferredName, suffix, data, datalen, spDefault);
266 int saveFileEx(const char *preferredName, const char *suffix, const void *data, size_t datalen, savePaths_t e_save_path) {
267 if (data == NULL || datalen == 0) {
268 return PM3_EINVARG;
271 char *fileName = newfilenamemcopyEx(preferredName, suffix, e_save_path);
272 if (fileName == NULL) {
273 return PM3_EMALLOC;
276 // We should have a valid filename now, e.g. dumpdata-3.bin
278 // Opening file for writing in binary mode
279 FILE *f = fopen(fileName, "wb");
280 if (!f) {
281 PrintAndLogEx(WARNING, "file not found or locked `" _YELLOW_("%s") "`", fileName);
282 free(fileName);
283 return PM3_EFILE;
285 fwrite(data, 1, datalen, f);
286 fflush(f);
287 fclose(f);
288 PrintAndLogEx(SUCCESS, "Saved " _YELLOW_("%zu") " bytes to binary file `" _YELLOW_("%s") "`", datalen, fileName);
289 free(fileName);
290 return PM3_SUCCESS;
293 int prepareJSON(json_t *root, JSONFileType ftype, uint8_t *data, size_t datalen, bool verbose, void (*callback)(json_t *)) {
294 if (ftype != jsfCustom) {
295 if (data == NULL || datalen == 0) {
296 return PM3_EINVARG;
300 char path[PATH_MAX_LENGTH] = {0};
302 JsonSaveStr(root, "Created", "proxmark3");
303 switch (ftype) {
304 case jsfRaw: {
305 JsonSaveStr(root, "FileType", "raw");
306 JsonSaveBufAsHexCompact(root, "raw", data, datalen);
307 break;
309 case jsfMfc_v2: {
311 iso14a_mf_extdump_t xdump;
312 memcpy(&xdump, data, sizeof(iso14a_mf_extdump_t));
314 JsonSaveStr(root, "FileType", "mfc v2");
315 JsonSaveBufAsHexCompact(root, "$.Card.UID", xdump.card_info.uid, xdump.card_info.uidlen);
316 JsonSaveBufAsHexCompact(root, "$.Card.ATQA", xdump.card_info.atqa, 2);
317 JsonSaveBufAsHexCompact(root, "$.Card.SAK", &(xdump.card_info.sak), 1);
318 for (size_t i = 0; i < (xdump.dumplen / MFBLOCK_SIZE); i++) {
320 snprintf(path, sizeof(path), "$.blocks.%zu", i);
321 JsonSaveBufAsHexCompact(root, path, &xdump.dump[i * MFBLOCK_SIZE], MFBLOCK_SIZE);
322 if (mfIsSectorTrailer(i)) {
323 snprintf(path, sizeof(path), "$.SectorKeys.%d.KeyA", mfSectorNum(i));
324 JsonSaveBufAsHexCompact(root, path, &xdump.dump[i * MFBLOCK_SIZE], 6);
326 snprintf(path, sizeof(path), "$.SectorKeys.%d.KeyB", mfSectorNum(i));
327 JsonSaveBufAsHexCompact(root, path, &xdump.dump[i * MFBLOCK_SIZE + 10], 6);
329 uint8_t *adata = &xdump.dump[i * MFBLOCK_SIZE + 6];
330 snprintf(path, sizeof(path), "$.SectorKeys.%d.AccessConditions", mfSectorNum(i));
331 JsonSaveBufAsHexCompact(root, path, &xdump.dump[i * MFBLOCK_SIZE + 6], 4);
333 snprintf(path, sizeof(path), "$.SectorKeys.%d.AccessConditionsText.block%zu", mfSectorNum(i), i - 3);
334 JsonSaveStr(root, path, mfGetAccessConditionsDesc(0, adata));
336 snprintf(path, sizeof(path), "$.SectorKeys.%d.AccessConditionsText.block%zu", mfSectorNum(i), i - 2);
337 JsonSaveStr(root, path, mfGetAccessConditionsDesc(1, adata));
339 snprintf(path, sizeof(path), "$.SectorKeys.%d.AccessConditionsText.block%zu", mfSectorNum(i), i - 1);
340 JsonSaveStr(root, path, mfGetAccessConditionsDesc(2, adata));
342 snprintf(path, sizeof(path), "$.SectorKeys.%d.AccessConditionsText.block%zu", mfSectorNum(i), i);
343 JsonSaveStr(root, path, mfGetAccessConditionsDesc(3, adata));
345 snprintf(path, sizeof(path), "$.SectorKeys.%d.AccessConditionsText.UserData", mfSectorNum(i));
346 JsonSaveBufAsHexCompact(root, path, &adata[3], 1);
349 break;
351 case jsfMfc_v3: {
353 iso14a_mf_dump_ev1_t xdump;
354 memcpy(&xdump, data, sizeof(iso14a_mf_dump_ev1_t));
356 JsonSaveStr(root, "FileType", "mfc v3");
357 JsonSaveBufAsHexCompact(root, "$.Card.UID", xdump.card.ev1.uid, xdump.card.ev1.uidlen);
358 JsonSaveBufAsHexCompact(root, "$.Card.ATQA", xdump.card.ev1.atqa, 2);
359 JsonSaveBufAsHexCompact(root, "$.Card.SAK", &(xdump.card.ev1.sak), 1);
360 JsonSaveBufAsHexCompact(root, "$.Card.ATS", xdump.card.ev1.ats, sizeof(xdump.card.ev1.ats_len));
361 JsonSaveBufAsHexCompact(root, "$.Card.SIGNATURE", xdump.card.ev1.signature, sizeof(xdump.card.ev1.signature));
363 for (size_t i = 0; i < (xdump.dumplen / MFBLOCK_SIZE); i++) {
365 snprintf(path, sizeof(path), "$.blocks.%zu", i);
366 JsonSaveBufAsHexCompact(root, path, &xdump.dump[i * MFBLOCK_SIZE], MFBLOCK_SIZE);
367 if (mfIsSectorTrailer(i)) {
368 snprintf(path, sizeof(path), "$.SectorKeys.%d.KeyA", mfSectorNum(i));
369 JsonSaveBufAsHexCompact(root, path, &xdump.dump[i * MFBLOCK_SIZE], 6);
371 snprintf(path, sizeof(path), "$.SectorKeys.%d.KeyB", mfSectorNum(i));
372 JsonSaveBufAsHexCompact(root, path, &xdump.dump[i * MFBLOCK_SIZE + 10], 6);
374 uint8_t *adata = &xdump.dump[i * MFBLOCK_SIZE + 6];
375 snprintf(path, sizeof(path), "$.SectorKeys.%d.AccessConditions", mfSectorNum(i));
376 JsonSaveBufAsHexCompact(root, path, &xdump.dump[i * MFBLOCK_SIZE + 6], 4);
378 snprintf(path, sizeof(path), "$.SectorKeys.%d.AccessConditionsText.block%zu", mfSectorNum(i), i - 3);
379 JsonSaveStr(root, path, mfGetAccessConditionsDesc(0, adata));
381 snprintf(path, sizeof(path), "$.SectorKeys.%d.AccessConditionsText.block%zu", mfSectorNum(i), i - 2);
382 JsonSaveStr(root, path, mfGetAccessConditionsDesc(1, adata));
384 snprintf(path, sizeof(path), "$.SectorKeys.%d.AccessConditionsText.block%zu", mfSectorNum(i), i - 1);
385 JsonSaveStr(root, path, mfGetAccessConditionsDesc(2, adata));
387 snprintf(path, sizeof(path), "$.SectorKeys.%d.AccessConditionsText.block%zu", mfSectorNum(i), i);
388 JsonSaveStr(root, path, mfGetAccessConditionsDesc(3, adata));
390 snprintf(path, sizeof(path), "$.SectorKeys.%d.AccessConditionsText.UserData", mfSectorNum(i));
391 JsonSaveBufAsHexCompact(root, path, &adata[3], 1);
394 break;
396 case jsfFudan: {
397 iso14a_mf_extdump_t xdump;
398 memcpy(&xdump, data, sizeof(iso14a_mf_extdump_t));
400 JsonSaveStr(root, "FileType", "fudan");
401 JsonSaveBufAsHexCompact(root, "$.Card.UID", xdump.card_info.uid, xdump.card_info.uidlen);
402 JsonSaveBufAsHexCompact(root, "$.Card.ATQA", xdump.card_info.atqa, 2);
403 JsonSaveBufAsHexCompact(root, "$.Card.SAK", &(xdump.card_info.sak), 1);
404 for (size_t i = 0; i < (xdump.dumplen / 4); i++) {
406 snprintf(path, sizeof(path), "$.blocks.%zu", i);
407 JsonSaveBufAsHexCompact(root, path, &xdump.dump[i * 4], 4);
409 break;
411 case jsfMfuMemory: {
412 mfu_dump_t tmp;
413 memcpy(&tmp, data, sizeof(mfu_dump_t));
415 uint8_t uid[7] = {0};
416 memcpy(uid, tmp.data, 3);
417 memcpy(uid + 3, tmp.data + 4, 4);
419 JsonSaveStr(root, "FileType", "mfu");
420 JsonSaveBufAsHexCompact(root, "$.Card.UID", uid, sizeof(uid));
421 JsonSaveBufAsHexCompact(root, "$.Card.Version", tmp.version, sizeof(tmp.version));
422 JsonSaveBufAsHexCompact(root, "$.Card.TBO_0", tmp.tbo, sizeof(tmp.tbo));
423 JsonSaveBufAsHexCompact(root, "$.Card.TBO_1", tmp.tbo1, sizeof(tmp.tbo1));
424 JsonSaveBufAsHexCompact(root, "$.Card.Signature", tmp.signature, sizeof(tmp.signature));
425 for (uint8_t i = 0; i < 3; i ++) {
426 snprintf(path, sizeof(path), "$.Card.Counter%d", i);
427 JsonSaveBufAsHexCompact(root, path, tmp.counter_tearing[i], 3);
428 snprintf(path, sizeof(path), "$.Card.Tearing%d", i);
429 JsonSaveBufAsHexCompact(root, path, tmp.counter_tearing[i] + 3, 1);
432 // size of header 56b
434 size_t len = (datalen - MFU_DUMP_PREFIX_LENGTH) / MFU_BLOCK_SIZE;
436 for (size_t i = 0; i < len; i++) {
437 snprintf(path, sizeof(path), "$.blocks.%zu", i);
438 JsonSaveBufAsHexCompact(root, path, tmp.data + (i * MFU_BLOCK_SIZE), MFU_BLOCK_SIZE);
440 break;
442 case jsfHitag: {
443 uint8_t uid[4] = {0};
444 memcpy(uid, data, 4);
445 JsonSaveStr(root, "FileType", "hitag");
446 JsonSaveBufAsHexCompact(root, "$.Card.UID", uid, sizeof(uid));
448 for (size_t i = 0; i < (datalen / 4); i++) {
449 snprintf(path, sizeof(path), "$.blocks.%zu", i);
450 JsonSaveBufAsHexCompact(root, path, data + (i * 4), 4);
452 break;
454 case jsfIclass: {
456 picopass_hdr_t hdr;
457 memcpy(&hdr, data, sizeof(picopass_hdr_t));
459 JsonSaveStr(root, "FileType", "iclass");
460 JsonSaveBufAsHexCompact(root, "$.Card.CSN", hdr.csn, sizeof(hdr.csn));
461 JsonSaveBufAsHexCompact(root, "$.Card.Configuration", (uint8_t *)&hdr.conf, sizeof(hdr.conf));
463 uint8_t pagemap = get_pagemap(&hdr);
464 if (pagemap == PICOPASS_NON_SECURE_PAGEMODE) {
465 picopass_ns_hdr_t ns_hdr;
466 memcpy(&ns_hdr, data, sizeof(picopass_ns_hdr_t));
467 JsonSaveBufAsHexCompact(root, "$.Card.AIA", ns_hdr.app_issuer_area, sizeof(ns_hdr.app_issuer_area));
468 } else {
469 JsonSaveBufAsHexCompact(root, "$.Card.Epurse", hdr.epurse, sizeof(hdr.epurse));
470 JsonSaveBufAsHexCompact(root, "$.Card.Kd", hdr.key_d, sizeof(hdr.key_d));
471 JsonSaveBufAsHexCompact(root, "$.Card.Kc", hdr.key_c, sizeof(hdr.key_c));
472 JsonSaveBufAsHexCompact(root, "$.Card.AIA", hdr.app_issuer_area, sizeof(hdr.app_issuer_area));
475 for (size_t i = 0; i < (datalen / PICOPASS_BLOCK_SIZE); i++) {
476 snprintf(path, sizeof(path), "$.blocks.%zu", i);
477 JsonSaveBufAsHexCompact(root, path, data + (i * PICOPASS_BLOCK_SIZE), PICOPASS_BLOCK_SIZE);
480 break;
482 case jsfT55x7: {
483 JsonSaveStr(root, "FileType", "t55x7");
484 uint8_t conf[4] = {0};
485 memcpy(conf, data, 4);
486 JsonSaveBufAsHexCompact(root, "$.Card.ConfigBlock", conf, sizeof(conf));
488 for (size_t i = 0; i < (datalen / 4); i++) {
489 snprintf(path, sizeof(path), "$.blocks.%zu", i);
490 JsonSaveBufAsHexCompact(root, path, data + (i * 4), 4);
492 break;
494 case jsf14b_v2: {
495 JsonSaveStr(root, "FileType", "14b v2");
496 for (size_t i = 0; i < datalen / 4; i++) {
497 snprintf(path, sizeof(path), "$.blocks.%zu", i);
498 JsonSaveBufAsHexCompact(root, path, &data[i * 4], 4);
500 break;
502 // handles ISO15693 in iso15_tag_t format
503 case jsf15_v4: {
504 JsonSaveStr(root, "FileType", "15693 v4");
505 iso15_tag_t *tag = (iso15_tag_t *)data;
506 JsonSaveBufAsHexCompact(root, "$.Card.uid", tag->uid, sizeof(tag->uid));
507 JsonSaveBufAsHexCompact(root, "$.Card.dsfid", &tag->dsfid, 1);
508 JsonSaveBufAsHexCompact(root, "$.Card.dsfidlock", (uint8_t *)&tag->dsfidLock, 1);
509 JsonSaveBufAsHexCompact(root, "$.Card.afi", &tag->afi, 1);
510 JsonSaveBufAsHexCompact(root, "$.Card.afilock", (uint8_t *)&tag->afiLock, 1);
511 JsonSaveBufAsHexCompact(root, "$.Card.bytesperpage", &tag->bytesPerPage, 1);
512 JsonSaveBufAsHexCompact(root, "$.Card.pagescount", &tag->pagesCount, 1);
513 JsonSaveBufAsHexCompact(root, "$.Card.ic", &tag->ic, 1);
514 JsonSaveBufAsHexCompact(root, "$.Card.locks", tag->locks, tag->pagesCount);
515 JsonSaveBufAsHexCompact(root, "$.Card.random", tag->random, 2);
516 JsonSaveBufAsHexCompact(root, "$.Card.privacypasswd", tag->privacyPasswd, sizeof(tag->privacyPasswd));
517 JsonSaveBufAsHexCompact(root, "$.Card.state", (uint8_t *)&tag->state, 1);
519 for (uint8_t i = 0 ; i < tag->pagesCount ; i++) {
521 if (((i + 1) * tag->bytesPerPage) > ISO15693_TAG_MAX_SIZE) {
522 break;
525 snprintf(path, sizeof(path), "$.blocks.%u", i);
526 JsonSaveBufAsHexCompact(root
527 , path
528 , &tag->data[i * tag->bytesPerPage]
529 , tag->bytesPerPage
532 break;
534 case jsfLegic_v2: {
535 JsonSaveStr(root, "FileType", "legic v2");
536 JsonSaveBufAsHexCompact(root, "$.Card.UID", data, 4);
537 size_t i = 0;
538 for (; i < datalen / 16; i++) {
539 snprintf(path, sizeof(path), "$.blocks.%zu", i);
540 JsonSaveBufAsHexCompact(root, path, &data[i * 16], 16);
542 if (datalen % 16) {
543 snprintf(path, sizeof(path), "$.blocks.%zu", i);
544 JsonSaveBufAsHexCompact(root, path, &data[i * 16], (datalen % 16));
546 break;
548 case jsfT5555: {
549 JsonSaveStr(root, "FileType", "t5555");
550 uint8_t conf[4] = {0};
551 memcpy(conf, data, 4);
552 JsonSaveBufAsHexCompact(root, "$.Card.ConfigBlock", conf, sizeof(conf));
554 for (size_t i = 0; i < (datalen / 4); i++) {
555 snprintf(path, sizeof(path), "$.blocks.%zu", i);
556 JsonSaveBufAsHexCompact(root, path, data + (i * 4), 4);
558 break;
560 case jsfEM4x05: {
561 JsonSaveStr(root, "FileType", "EM4205/EM4305");
562 JsonSaveBufAsHexCompact(root, "$.Card.UID", data + (1 * 4), 4);
563 JsonSaveBufAsHexCompact(root, "$.Card.Config", data + (4 * 4), 4);
564 JsonSaveBufAsHexCompact(root, "$.Card.Protection1", data + (14 * 4), 4);
565 JsonSaveBufAsHexCompact(root, "$.Card.Protection2", data + (15 * 4), 4);
567 for (size_t i = 0; i < (datalen / 4); i++) {
568 snprintf(path, sizeof(path), "$.blocks.%zu", i);
569 JsonSaveBufAsHexCompact(root, path, data + (i * 4), 4);
571 break;
573 case jsfEM4x69: {
574 JsonSaveStr(root, "FileType", "EM4469/EM4569");
575 JsonSaveBufAsHexCompact(root, "$.Card.UID", data + (1 * 4), 4);
576 JsonSaveBufAsHexCompact(root, "$.Card.Protection", data + (3 * 4), 4);
577 JsonSaveBufAsHexCompact(root, "$.Card.Config", data + (4 * 4), 4);
579 for (size_t i = 0; i < (datalen / 4); i++) {
580 snprintf(path, sizeof(path), "$.blocks.%zu", i);
581 JsonSaveBufAsHexCompact(root, path, data + (i * 4), 4);
583 break;
585 case jsfEM4x50: {
586 JsonSaveStr(root, "FileType", "EM4X50");
587 JsonSaveBufAsHexCompact(root, "$.Card.Protection", data + (1 * 4), 4);
588 JsonSaveBufAsHexCompact(root, "$.Card.Config", data + (2 * 4), 4);
589 JsonSaveBufAsHexCompact(root, "$.Card.Serial", data + (32 * 4), 4);
590 JsonSaveBufAsHexCompact(root, "$.Card.UID", data + (33 * 4), 4);
592 for (size_t i = 0; i < (datalen / 4); i++) {
593 snprintf(path, sizeof(path), "$.blocks.%zu", i);
594 JsonSaveBufAsHexCompact(root, path, data + (i * 4), 4);
596 break;
598 case jsfMfPlusKeys: {
599 JsonSaveStr(root, "FileType", "mfpkeys");
600 JsonSaveBufAsHexCompact(root, "$.Card.UID", &data[0], 7);
601 JsonSaveBufAsHexCompact(root, "$.Card.SAK", &data[10], 1);
602 JsonSaveBufAsHexCompact(root, "$.Card.ATQA", &data[11], 2);
603 uint8_t atslen = data[13];
604 if (atslen > 0) {
605 JsonSaveBufAsHexCompact(root, "$.Card.ATS", &data[14], atslen);
608 uint8_t vdata[2][64][17] = {{{0}}};
609 memcpy(vdata, data + (14 + atslen), 2 * 64 * 17);
611 for (size_t i = 0; i < datalen; i++) {
612 if (vdata[0][i][0]) {
613 snprintf(path, sizeof(path), "$.SectorKeys.%zu.KeyA", i);
614 JsonSaveBufAsHexCompact(root, path, &vdata[0][i][1], AES_KEY_LEN);
617 if (vdata[1][i][0]) {
618 snprintf(path, sizeof(path), "$.SectorKeys.%zu.KeyB", i);
619 JsonSaveBufAsHexCompact(root, path, &vdata[1][i][1], AES_KEY_LEN);
622 break;
624 case jsfMfDesfireKeys: {
625 JsonSaveStr(root, "FileType", "mfdes");
626 JsonSaveBufAsHexCompact(root, "$.Card.UID", &data[0], 7);
627 JsonSaveBufAsHexCompact(root, "$.Card.SAK", &data[10], 1);
628 JsonSaveBufAsHexCompact(root, "$.Card.ATQA", &data[11], 2);
629 uint8_t datslen = data[13];
630 if (datslen > 0)
631 JsonSaveBufAsHexCompact(root, "$.Card.ATS", &data[14], datslen);
633 uint8_t dvdata[4][0xE][24 + 1] = {{{0}}};
634 memcpy(dvdata, &data[14 + datslen], 4 * 0xE * (24 + 1));
636 for (int i = 0; i < (int)datalen; i++) {
638 if (dvdata[0][i][0]) {
639 snprintf(path, sizeof(path), "$.DES.%d.Key", i);
640 JsonSaveBufAsHexCompact(root, path, &dvdata[0][i][1], DES_KEY_LEN);
643 if (dvdata[1][i][0]) {
644 snprintf(path, sizeof(path), "$.3DES.%d.Key", i);
645 JsonSaveBufAsHexCompact(root, path, &dvdata[1][i][1], T2DES_KEY_LEN);
647 if (dvdata[2][i][0]) {
648 snprintf(path, sizeof(path), "$.AES.%d.Key", i);
649 JsonSaveBufAsHexCompact(root, path, &dvdata[2][i][1], AES_KEY_LEN);
651 if (dvdata[3][i][0]) {
652 snprintf(path, sizeof(path), "$.K3KDES.%d.Key", i);
653 JsonSaveBufAsHexCompact(root, path, &dvdata[3][i][1], T3DES_KEY_LEN);
656 break;
658 case jsfCustom: {
659 (*callback)(root);
660 break;
662 case jsfTopaz: {
663 topaz_tag_t *tag = (topaz_tag_t *)(void *) data;
664 JsonSaveStr(root, "FileType", "topaz");
665 JsonSaveBufAsHexCompact(root, "$.Card.UID", tag->uid, sizeof(tag->uid));
666 JsonSaveBufAsHexCompact(root, "$.Card.H0R1", tag->HR01, sizeof(tag->HR01));
667 JsonSaveBufAsHexCompact(root, "$.Card.Size", (uint8_t *) & (tag->size), 2);
669 for (size_t i = 0; i < TOPAZ_STATIC_MEMORY / 8; i++) {
670 snprintf(path, sizeof(path), "$.blocks.%zu", i);
671 JsonSaveBufAsHexCompact(root, path, &tag->data_blocks[i][0], TOPAZ_BLOCK_SIZE);
674 // ICEMAN todo: add dynamic memory.
675 // uint16_z Size
676 // uint8_t *dynamic_memory;
678 break;
680 case jsfLto: {
681 JsonSaveStr(root, "FileType", "lto");
682 for (size_t i = 0; i < datalen / 32; i++) {
683 snprintf(path, sizeof(path), "$.blocks.%zu", i);
684 JsonSaveBufAsHexCompact(root, path, &data[i * 32], 32);
686 break;
688 case jsfCryptorf: {
689 JsonSaveStr(root, "FileType", "cryptorf");
690 for (size_t i = 0; i < datalen / 8; i++) {
691 snprintf(path, sizeof(path), "$.blocks.%zu", i);
692 JsonSaveBufAsHexCompact(root, path, &data[i * 8], 8);
694 break;
696 case jsfNDEF: {
697 JsonSaveStr(root, "FileType", "ndef");
698 JsonSaveInt(root, "Ndef.Size", datalen);
699 size_t i = 0;
700 for (; i < datalen / 16; i++) {
701 snprintf(path, sizeof(path), "$.blocks.%zu", i);
702 JsonSaveBufAsHexCompact(root, path, &data[i * 16], 16);
704 if (datalen % 16) {
705 snprintf(path, sizeof(path), "$.blocks.%zu", i);
706 JsonSaveBufAsHexCompact(root, path, &data[i * 16], (datalen % 16));
708 break;
710 case jsfFM11RF08SNonces:
711 case jsfFM11RF08SNoncesWithData: {
712 if (datalen != sizeof(iso14a_fm11rf08s_nonces_with_data_t)) {
713 return PM3_EINVARG;
715 iso14a_fm11rf08s_nonces_with_data_t *p = (iso14a_fm11rf08s_nonces_with_data_t *)data;
716 if (ftype == jsfFM11RF08SNoncesWithData) {
717 JsonSaveStr(root, "FileType", "fm11rf08s_nonces_with_data");
718 } else {
719 JsonSaveStr(root, "FileType", "fm11rf08s_nonces");
721 for (uint16_t sec = 0; sec < MIFARE_1K_MAXSECTOR + 1; sec++) {
722 uint8_t par2[2];
723 uint8_t par;
724 uint16_t real_sec = sec;
725 if (sec == MIFARE_1K_MAXSECTOR) {
726 real_sec = 32; // advanced verification method block
728 snprintf(path, sizeof(path), "$.nt.%u.a", real_sec);
729 JsonSaveBufAsHexCompact(root, path, p->nt[sec][0], 4);
730 snprintf(path, sizeof(path), "$.nt.%u.b", real_sec);
731 JsonSaveBufAsHexCompact(root, path, p->nt[sec][1], 4);
732 snprintf(path, sizeof(path), "$.nt_enc.%u.a", real_sec);
733 JsonSaveBufAsHexCompact(root, path, p->nt_enc[sec][0], 4);
734 snprintf(path, sizeof(path), "$.nt_enc.%u.b", real_sec);
735 JsonSaveBufAsHexCompact(root, path, p->nt_enc[sec][1], 4);
737 snprintf(path, sizeof(path), "$.par_err.%u.a", real_sec);
738 par = p->par_err[sec][0];
739 par2[0] = (((par >> 3) & 1) << 4) | ((par >> 2) & 1);
740 par2[1] = (((par >> 1) & 1) << 4) | ((par >> 0) & 1);
741 JsonSaveBufAsHexCompact(root, path, par2, 2);
742 snprintf(path, sizeof(path), "$.par_err.%u.b", real_sec);
743 par = p->par_err[sec][1];
744 par2[0] = (((par >> 3) & 1) << 4) | ((par >> 2) & 1);
745 par2[1] = (((par >> 1) & 1) << 4) | ((par >> 0) & 1);
746 JsonSaveBufAsHexCompact(root, path, par2, 2);
748 if (ftype == jsfFM11RF08SNoncesWithData) {
749 for (uint16_t blk = 0; blk < MIFARE_1K_MAXBLOCK; blk++) {
750 snprintf(path, sizeof(path), "$.blocks.%u", blk);
751 JsonSaveBufAsHexCompact(root, path, p->blocks[blk], MFBLOCK_SIZE);
754 break;
756 // no action
757 case jsfFido:
758 break;
759 // depricated
760 case jsfCardMemory:
761 case jsf14b:
762 case jsf15:
763 case jsf15_v2:
764 case jsf15_v3:
765 case jsfLegic:
766 default:
767 break;
769 return PM3_SUCCESS;
772 // dump file (normally, we also got preference file, etc)
773 int saveFileJSON(const char *preferredName, JSONFileType ftype, uint8_t *data, size_t datalen, void (*callback)(json_t *)) {
774 return saveFileJSONex(preferredName, ftype, data, datalen, true, callback, spDump);
777 int saveFileJSONex(const char *preferredName, JSONFileType ftype, uint8_t *data, size_t datalen, bool verbose, void (*callback)(json_t *), savePaths_t e_save_path) {
779 int retval = PM3_SUCCESS;
781 json_t *root = json_object();
782 retval = prepareJSON(root, ftype, data, datalen, verbose, callback);
783 if (retval != PM3_SUCCESS) {
784 return retval;
786 retval = saveFileJSONrootEx(preferredName, root, JSON_INDENT(2), verbose, false, e_save_path);
787 json_decref(root);
788 return retval;
791 int saveFileJSONroot(const char *preferredName, void *root, size_t flags, bool verbose) {
792 return saveFileJSONrootEx(preferredName, root, flags, verbose, false, spDump);
795 int saveFileJSONrootEx(const char *preferredName, const void *root, size_t flags, bool verbose, bool overwrite, savePaths_t e_save_path) {
796 if (root == NULL)
797 return PM3_EINVARG;
799 char *filename = NULL;
800 if (overwrite)
801 filename = filenamemcopy(preferredName, ".json");
802 else
803 filename = newfilenamemcopyEx(preferredName, ".json", e_save_path);
805 if (filename == NULL)
806 return PM3_EMALLOC;
808 int res = json_dump_file(root, filename, flags);
810 if (res == 0) {
811 if (verbose) {
812 PrintAndLogEx(SUCCESS, "Saved to json file `" _YELLOW_("%s") "`", filename);
814 free(filename);
815 return PM3_SUCCESS;
816 } else {
817 PrintAndLogEx(FAILED, "error, can't save the file `" _YELLOW_("%s") "`", filename);
819 free(filename);
820 return PM3_EFILE;
823 char *sprintJSON(JSONFileType ftype, uint8_t *data, size_t datalen, bool verbose, void (*callback)(json_t *)) {
825 json_t *root = json_object();
826 if (prepareJSON(root, ftype, data, datalen, verbose, callback) != PM3_SUCCESS) {
827 return NULL;
829 char *s = json_dumps(root, JSON_INDENT(2));
830 json_decref(root);
831 return s;
834 // wave file of trace,
835 int saveFileWAVE(const char *preferredName, const int *data, size_t datalen) {
837 if (data == NULL || datalen == 0) {
838 return PM3_EINVARG;
841 char *fileName = newfilenamemcopyEx(preferredName, ".wav", spTrace);
842 if (fileName == NULL) {
843 return PM3_EMALLOC;
846 int retval = PM3_SUCCESS;
848 struct wave_info_t wave_info = {
849 .signature = "RIFF",
850 .filesize = sizeof(wave_info) - sizeof(wave_info.signature) - sizeof(wave_info.filesize) + datalen,
851 .type = "WAVE",
852 .format.tag = "fmt ",
853 .format.size = sizeof(wave_info.format) - sizeof(wave_info.format.tag) - sizeof(wave_info.format.size),
854 .format.codec = 1, // PCM
855 .format.nb_channel = 1,
856 .format.sample_per_sec = 125000, // TODO update for other tag types
857 .format.byte_per_sec = 125000, // TODO update for other tag types
858 .format.block_align = 1,
859 .format.bit_per_sample = 8,
860 .audio_data.tag = "data",
861 .audio_data.size = datalen,
864 FILE *wave_file = fopen(fileName, "wb");
865 if (!wave_file) {
866 PrintAndLogEx(WARNING, "file not found or locked `" _YELLOW_("%s") "`", fileName);
867 retval = PM3_EFILE;
868 goto out;
871 fwrite(&wave_info, sizeof(wave_info), 1, wave_file);
873 for (int i = 0; i < datalen; i++) {
874 uint8_t sample = data[i] + 128;
875 fwrite(&sample, 1, 1, wave_file);
878 fclose(wave_file);
880 PrintAndLogEx(SUCCESS, "Saved " _YELLOW_("%zu") " bytes to wave file `" _YELLOW_("%s") "`", 2 * datalen, fileName);
882 out:
883 free(fileName);
884 return retval;
887 // Signal trace file, PM3
888 int saveFilePM3(const char *preferredName, int *data, size_t datalen) {
890 if (data == NULL || datalen == 0) {
891 return PM3_EINVARG;
894 char *fileName = newfilenamemcopyEx(preferredName, ".pm3", spTrace);
895 if (fileName == NULL) {
896 return PM3_EMALLOC;
899 int retval = PM3_SUCCESS;
901 FILE *f = fopen(fileName, "w");
902 if (!f) {
903 PrintAndLogEx(WARNING, "file not found or locked `" _YELLOW_("%s") "`", fileName);
904 retval = PM3_EFILE;
905 goto out;
908 for (uint32_t i = 0; i < datalen; i++) {
909 fprintf(f, "%d\n", data[i]);
912 fflush(f);
913 fclose(f);
914 PrintAndLogEx(SUCCESS, "Saved " _YELLOW_("%zu") " bytes to PM3 file `" _YELLOW_("%s") "`", datalen, fileName);
916 out:
917 free(fileName);
918 return retval;
921 // key file dump
922 int createMfcKeyDump(const char *preferredName, uint8_t sectorsCnt, const sector_t *e_sector) {
924 if (e_sector == NULL) return PM3_EINVARG;
926 char *fileName = newfilenamemcopyEx(preferredName, ".bin", spDump);
927 if (fileName == NULL) return PM3_EMALLOC;
929 FILE *f = fopen(fileName, "wb");
930 if (f == NULL) {
931 PrintAndLogEx(WARNING, "could not create file `" _YELLOW_("%s") "`", fileName);
932 free(fileName);
933 return PM3_EFILE;
935 PrintAndLogEx(SUCCESS, "Generating binary key file");
937 uint8_t empty[6] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
938 uint8_t tmp[6] = {0, 0, 0, 0, 0, 0};
940 for (int i = 0; i < sectorsCnt; i++) {
941 if (e_sector[i].foundKey[0])
942 num_to_bytes(e_sector[i].Key[0], sizeof(tmp), tmp);
943 else
944 memcpy(tmp, empty, sizeof(tmp));
945 fwrite(tmp, 1, sizeof(tmp), f);
948 for (int i = 0; i < sectorsCnt; i++) {
949 if (e_sector[i].foundKey[0])
950 num_to_bytes(e_sector[i].Key[1], sizeof(tmp), tmp);
951 else
952 memcpy(tmp, empty, sizeof(tmp));
953 fwrite(tmp, 1, sizeof(tmp), f);
956 fflush(f);
957 fclose(f);
958 PrintAndLogEx(SUCCESS, "Found keys have been dumped to `" _YELLOW_("%s") "`", fileName);
959 PrintAndLogEx(INFO, "--[ " _YELLOW_("FFFFFFFFFFFF") " ]-- has been inserted for unknown keys where " _YELLOW_("res") " is " _RED_("0"));
960 free(fileName);
961 return PM3_SUCCESS;
964 // --------- LOAD FILES
965 int loadFile_safe(const char *preferredName, const char *suffix, void **pdata, size_t *datalen) {
966 return loadFile_safeEx(preferredName, suffix, pdata, datalen, true);
968 int loadFile_safeEx(const char *preferredName, const char *suffix, void **pdata, size_t *datalen, bool verbose) {
970 char *path;
971 int res = searchFile(&path, RESOURCES_SUBDIR, preferredName, suffix, false);
972 if (res != PM3_SUCCESS) {
973 return PM3_EFILE;
976 FILE *f = fopen(path, "rb");
977 if (!f) {
978 PrintAndLogEx(WARNING, "file not found or locked `" _YELLOW_("%s") "`", path);
979 free(path);
980 return PM3_EFILE;
982 free(path);
984 // get filesize in order to malloc memory
985 fseek(f, 0, SEEK_END);
986 long fsize = ftell(f);
987 fseek(f, 0, SEEK_SET);
989 if (fsize <= 0) {
990 PrintAndLogEx(FAILED, "error, when getting filesize");
991 fclose(f);
992 return PM3_EFILE;
995 *pdata = calloc(fsize, sizeof(uint8_t));
996 if (!*pdata) {
997 PrintAndLogEx(FAILED, "error, cannot allocate memory");
998 fclose(f);
999 return PM3_EMALLOC;
1002 size_t bytes_read = fread(*pdata, 1, fsize, f);
1004 fclose(f);
1006 if (bytes_read != fsize) {
1007 PrintAndLogEx(FAILED, "error, bytes read mismatch file size");
1008 free(*pdata);
1009 return PM3_EFILE;
1012 *datalen = bytes_read;
1014 if (verbose) {
1015 PrintAndLogEx(SUCCESS, "Loaded " _YELLOW_("%zu") " bytes from binary file `" _YELLOW_("%s") "`", bytes_read, preferredName);
1017 return PM3_SUCCESS;
1020 int loadFileEML_safe(const char *preferredName, void **pdata, size_t *datalen) {
1021 char *path;
1022 int res = searchFile(&path, RESOURCES_SUBDIR, preferredName, "", false);
1023 if (res != PM3_SUCCESS) {
1024 return PM3_EFILE;
1027 FILE *f = fopen(path, "r");
1028 if (!f) {
1029 PrintAndLogEx(WARNING, "file not found or locked `" _YELLOW_("%s") "`", path);
1030 free(path);
1031 return PM3_EFILE;
1033 free(path);
1035 // get filesize in order to malloc memory
1036 fseek(f, 0, SEEK_END);
1037 long fsize = ftell(f);
1038 fseek(f, 0, SEEK_SET);
1040 if (fsize <= 0) {
1041 PrintAndLogEx(FAILED, "error, when getting filesize");
1042 fclose(f);
1043 return PM3_EFILE;
1046 *pdata = calloc(fsize, sizeof(uint8_t));
1047 if (!*pdata) {
1048 PrintAndLogEx(FAILED, "error, cannot allocate memory");
1049 fclose(f);
1050 return PM3_EMALLOC;
1053 // 128 + 2 newline chars + 1 null terminator
1054 char line[131];
1055 memset(line, 0, sizeof(line));
1056 uint8_t buf[64] = {0x00};
1057 size_t counter = 0;
1058 int retval = PM3_SUCCESS, hexlen = 0;
1060 uint8_t *tmp = (uint8_t *)*pdata;
1062 while (!feof(f)) {
1064 memset(line, 0, sizeof(line));
1066 if (fgets(line, sizeof(line), f) == NULL) {
1067 if (feof(f))
1068 break;
1070 fclose(f);
1071 PrintAndLogEx(FAILED, "file reading error");
1072 return PM3_EFILE;
1075 if (line[0] == '#')
1076 continue;
1078 str_cleanrn(line, sizeof(line));
1080 res = param_gethex_to_eol(line, 0, buf, sizeof(buf), &hexlen);
1081 if (res == 0) {
1082 memcpy(tmp + counter, buf, hexlen);
1083 counter += hexlen;
1084 } else {
1085 retval = PM3_ESOFT;
1088 fclose(f);
1089 PrintAndLogEx(SUCCESS, "Loaded " _YELLOW_("%zu") " bytes from text file `" _YELLOW_("%s") "`", counter, preferredName);
1092 uint8_t *newdump = realloc(*pdata, counter);
1093 if (newdump == NULL) {
1094 free(*pdata);
1095 return PM3_EMALLOC;
1096 } else {
1097 *pdata = newdump;
1100 if (datalen)
1101 *datalen = counter;
1103 return retval;
1106 int loadFileNFC_safe(const char *preferredName, void *data, size_t maxdatalen, size_t *datalen, nfc_df_e ft) {
1108 if (data == NULL) return PM3_EINVARG;
1110 *datalen = 0;
1111 int retval = PM3_SUCCESS;
1113 char *path;
1114 int res = searchFile(&path, RESOURCES_SUBDIR, preferredName, "", false);
1115 if (res != PM3_SUCCESS) {
1116 return PM3_EFILE;
1119 FILE *f = fopen(path, "r");
1120 if (!f) {
1121 PrintAndLogEx(WARNING, "file not found or locked `" _YELLOW_("%s") "`", path);
1122 free(path);
1123 return PM3_EFILE;
1125 free(path);
1127 // 256 + 2 newline chars + 1 null terminator
1128 char line[256 + 2 + 1];
1129 memset(line, 0, sizeof(line));
1131 udata_t udata = (udata_t)data;
1132 int n = 0;
1133 uint32_t counter = 0;
1135 while (!feof(f)) {
1137 memset(line, 0, sizeof(line));
1139 if (fgets(line, sizeof(line), f) == NULL) {
1140 if (feof(f))
1141 break;
1143 fclose(f);
1144 PrintAndLogEx(FAILED, "file reading error");
1145 return PM3_EFILE;
1148 if (line[0] == '#')
1149 continue;
1151 str_cleanrn(line, sizeof(line));
1152 str_lower(line);
1154 if (str_startswith(line, "uid:")) {
1155 if (ft == NFC_DF_MFC) {
1156 // param_gethex_to_eol(line + 4, 0, udata.mfc->card_info.uid, sizeof(udata.mfc->card_info.uid), &n);
1158 continue;
1161 if (str_startswith(line, "atqa:")) {
1162 if (ft == NFC_DF_MFC) {
1163 // param_gethex_to_eol(line + 5, 0, udata.mfc->card_info.atqa, sizeof(udata.mfc->card_info.atqa), &n);
1165 continue;
1168 if (str_startswith(line, "sak:")) {
1169 if (ft == NFC_DF_MFC) {
1170 int sak = 0;
1171 sscanf(line, "sak: %d", &sak);
1172 // udata.mfc->card_info.sak = sak & 0xFF;
1174 continue;
1177 if (str_startswith(line, "signature:")) {
1178 if (ft == NFC_DF_MFC) {
1179 } else if (ft == NFC_DF_MFU) {
1180 param_gethex_to_eol(line + 11, 0, udata.mfu->signature, sizeof(udata.mfu->signature), &n);
1182 continue;
1185 if (str_startswith(line, "mifare version:")) {
1186 if (ft == NFC_DF_MFC) {
1187 } else if (ft == NFC_DF_MFU) {
1188 param_gethex_to_eol(line + 16, 0, udata.mfu->version, sizeof(udata.mfu->version), &n);
1190 continue;
1193 if (str_startswith(line, "counter 0:")) {
1194 int no = 0;
1195 sscanf(line, "counter 0: %d", &no);
1196 if (ft == NFC_DF_MFC) {
1197 } else if (ft == NFC_DF_MFU) {
1198 udata.mfu->counter_tearing[0][0] = no & 0xFF;
1199 udata.mfu->counter_tearing[0][1] = no & 0xFF;
1200 udata.mfu->counter_tearing[0][2] = no & 0xFF;
1202 continue;
1205 if (str_startswith(line, "tearing 0:")) {
1206 if (ft == NFC_DF_MFC) {
1207 } else if (ft == NFC_DF_MFU) {
1208 uint32_t b = 0;
1209 sscanf(line, "tearing 0: %02x", &b);
1210 udata.mfu->counter_tearing[0][3] = b & 0xFF;
1212 continue;
1215 if (str_startswith(line, "counter 1:")) {
1216 int no = 0;
1217 sscanf(line, "counter 1: %d", &no);
1218 if (ft == NFC_DF_MFC) {
1219 } else if (ft == NFC_DF_MFU) {
1220 udata.mfu->counter_tearing[1][0] = no & 0xFF;
1221 udata.mfu->counter_tearing[1][1] = no & 0xFF;
1222 udata.mfu->counter_tearing[1][2] = no & 0xFF;
1224 continue;
1227 if (str_startswith(line, "tearing 1:")) {
1228 if (ft == NFC_DF_MFC) {
1229 } else if (ft == NFC_DF_MFU) {
1230 uint32_t b = 0;
1231 sscanf(line, "tearing 1: %02x", &b);
1232 udata.mfu->counter_tearing[1][3] = b & 0xFF;
1234 continue;
1237 if (str_startswith(line, "counter 2:")) {
1238 int no = 0;
1239 sscanf(line, "counter 2: %d", &no);
1240 if (ft == NFC_DF_MFC) {
1241 } else if (ft == NFC_DF_MFU) {
1242 udata.mfu->counter_tearing[2][0] = no & 0xFF;
1243 udata.mfu->counter_tearing[2][1] = no & 0xFF;
1244 udata.mfu->counter_tearing[2][2] = no & 0xFF;
1246 continue;
1249 if (str_startswith(line, "tearing 2:")) {
1250 if (ft == NFC_DF_MFC) {
1251 } else if (ft == NFC_DF_MFU) {
1252 uint32_t b = 0;
1253 sscanf(line, "tearing 2: %02x", &b);
1254 udata.mfu->counter_tearing[2][3] = b & 0xFF;
1256 continue;
1259 if (str_startswith(line, "pages total:")) {
1260 sscanf(line, "pages total: %d", &n);
1261 if (ft == NFC_DF_MFC) {
1262 } else if (ft == NFC_DF_MFU) {
1263 udata.mfu->pages = n;
1265 continue;
1268 // Page 0: 04 10 56 CA
1269 if (str_startswith(line, "page ")) {
1270 int pageno = 0;
1271 sscanf(line, "page %d:", &pageno);
1273 if (strcmp(line, "??") == 0) {
1274 PrintAndLogEx(INFO, "missing data detected in page %i, skipping...", pageno);
1275 continue;
1278 if (((pageno * MFU_BLOCK_SIZE) + MFU_BLOCK_SIZE) > maxdatalen) {
1279 continue;
1282 char *p = line;
1283 while (*p++ != ':') {};
1284 p++;
1286 if (ft == NFC_DF_MFU) {
1287 n = 0;
1288 param_gethex_to_eol(p, 0, udata.mfu->data + (pageno * MFU_BLOCK_SIZE), MFU_BLOCK_SIZE, &n);
1289 *datalen += MFU_BLOCK_SIZE;
1291 continue;
1294 // Block 0: 11 22 33 44 55 66 77 88 99 AA BB CC DD EE FF
1295 if (str_startswith(line, "block ")) {
1296 int blockno = 0;
1297 sscanf(line, "block %d:", &blockno);
1299 if (strcmp(line, "??") == 0) {
1300 PrintAndLogEx(INFO, "missing data detected in block %i, skipping...", blockno);
1301 continue;
1304 if (((blockno * MFBLOCK_SIZE) + MFBLOCK_SIZE) > maxdatalen) {
1305 continue;
1308 char *p = line;
1309 while (*p++ != ':') {};
1310 p++;
1312 if (ft == NFC_DF_MFC) {
1313 uint8_t block[MFBLOCK_SIZE] = {0};
1314 param_gethex_to_eol(p, 0, block, MFBLOCK_SIZE, &n);
1315 memcpy(&udata.bytes[(blockno * MFBLOCK_SIZE)], block, MFBLOCK_SIZE);
1316 counter += MFBLOCK_SIZE;
1317 } else if (ft == NFC_DF_PICOPASS) {
1318 uint8_t block[PICOPASS_BLOCK_SIZE] = {0};
1319 param_gethex_to_eol(p, 0, block, PICOPASS_BLOCK_SIZE, &n);
1320 memcpy(&udata.bytes[(blockno * PICOPASS_BLOCK_SIZE)], block, PICOPASS_BLOCK_SIZE);
1321 counter += PICOPASS_BLOCK_SIZE;
1323 continue;
1327 // add header length
1328 if (ft == NFC_DF_MFC || ft == NFC_DF_PICOPASS) {
1329 *datalen = counter;
1330 } else if (ft == NFC_DF_MFU) {
1331 *datalen += MFU_DUMP_PREFIX_LENGTH;
1334 fclose(f);
1335 PrintAndLogEx(SUCCESS, "Loaded " _YELLOW_("%zu") " bytes from NFC file `" _YELLOW_("%s") "`", *datalen, preferredName);
1336 return retval;
1339 int loadFileMCT_safe(const char *preferredName, void **pdata, size_t *datalen) {
1340 char *path;
1341 int res = searchFile(&path, RESOURCES_SUBDIR, preferredName, "", false);
1342 if (res != PM3_SUCCESS) {
1343 return PM3_EFILE;
1346 FILE *f = fopen(path, "r");
1347 if (!f) {
1348 PrintAndLogEx(WARNING, "file not found or locked `" _YELLOW_("%s") "`", path);
1349 free(path);
1350 return PM3_EFILE;
1352 free(path);
1354 // get filesize in order to malloc memory
1355 fseek(f, 0, SEEK_END);
1356 long fsize = ftell(f);
1357 fseek(f, 0, SEEK_SET);
1359 if (fsize <= 0) {
1360 PrintAndLogEx(FAILED, "error, when getting filesize");
1361 fclose(f);
1362 return PM3_EFILE;
1365 *pdata = calloc(fsize, sizeof(uint8_t));
1366 if (!*pdata) {
1367 PrintAndLogEx(FAILED, "error, cannot allocate memory");
1368 fclose(f);
1369 return PM3_EMALLOC;
1372 // 128 + 2 newline chars + 1 null terminator
1373 char line[131];
1374 memset(line, 0, sizeof(line));
1375 uint8_t buf[64] = {0x00};
1376 size_t counter = 0;
1377 int retval = PM3_SUCCESS, hexlen = 0;
1379 uint8_t *tmp = (uint8_t *)*pdata;
1381 while (!feof(f)) {
1383 memset(line, 0, sizeof(line));
1385 if (fgets(line, sizeof(line), f) == NULL) {
1386 if (feof(f))
1387 break;
1389 fclose(f);
1390 PrintAndLogEx(FAILED, "file reading error");
1391 return PM3_EFILE;
1394 // skip lines like "+Sector:"
1395 if (line[0] == '+')
1396 continue;
1398 str_cleanrn(line, sizeof(line));
1400 res = param_gethex_to_eol(line, 0, buf, sizeof(buf), &hexlen);
1401 if (res == 0) {
1402 memcpy(tmp + counter, buf, hexlen);
1403 counter += hexlen;
1404 } else {
1405 retval = PM3_ESOFT;
1408 fclose(f);
1409 PrintAndLogEx(SUCCESS, "Loaded " _YELLOW_("%zu") " bytes from MCT file `" _YELLOW_("%s") "`", counter, preferredName);
1412 uint8_t *newdump = realloc(*pdata, counter);
1413 if (newdump == NULL) {
1414 free(*pdata);
1415 return PM3_EMALLOC;
1416 } else {
1417 *pdata = newdump;
1420 if (datalen)
1421 *datalen = counter;
1423 return retval;
1426 static int load_file_sanity(char *s, uint32_t datalen, int i, size_t len) {
1427 if (len == 0) {
1428 PrintAndLogEx(DEBUG, "WARNING: json %s block %d has zero-length data", s, i);
1429 PrintAndLogEx(DEBUG, "File parsing stopped");
1430 return false;
1431 } else if (len != datalen) {
1432 PrintAndLogEx(WARNING, "WARNING: json %s block %d only has %zu bytes", s, i, len);
1433 PrintAndLogEx(INFO, "Expected %d - padding with zeros", datalen);
1435 return true;
1438 int loadFileJSON(const char *preferredName, void *data, size_t maxdatalen, size_t *datalen, void (*callback)(json_t *)) {
1439 return loadFileJSONex(preferredName, data, maxdatalen, datalen, true, callback);
1441 int loadFileJSONex(const char *preferredName, void *data, size_t maxdatalen, size_t *datalen, bool verbose, void (*callback)(json_t *)) {
1443 if (data == NULL) return PM3_EINVARG;
1445 *datalen = 0;
1446 int retval = PM3_SUCCESS;
1448 char *path;
1449 int res = searchFile(&path, RESOURCES_SUBDIR, preferredName, ".json", false);
1450 if (res != PM3_SUCCESS) {
1451 return PM3_EFILE;
1454 json_error_t error;
1455 json_t *root = json_load_file(path, 0, &error);
1456 if (verbose) {
1457 PrintAndLogEx(SUCCESS, "loaded `" _YELLOW_("%s") "`", path);
1460 free(path);
1462 if (!root) {
1463 PrintAndLogEx(ERR, "error, json " _YELLOW_("%s") " error on line %d: %s", preferredName, error.line, error.text);
1464 retval = PM3_ESOFT;
1465 goto out;
1468 if (!json_is_object(root)) {
1469 PrintAndLogEx(ERR, "error, invalid json " _YELLOW_("%s") " format. root must be an object.", preferredName);
1470 retval = PM3_ESOFT;
1471 goto out;
1474 char ctype[100] = {0};
1475 JsonLoadStr(root, "$.FileType", ctype);
1477 // Proxmark3 settings file. Nothing to do except call the callback function
1478 if (!strcmp(ctype, "settings")) {
1479 goto out;
1482 udata_t udata = (udata_t)data;
1484 size_t len = 0;
1485 char blocks[PATH_MAX_LENGTH] = {0};
1487 if (!strcmp(ctype, "raw")) {
1488 JsonLoadBufAsHex(root, "$.raw", udata.bytes, maxdatalen, datalen);
1489 goto out;
1492 // depricated mfcard
1493 if (!strcmp(ctype, "mfcard") || !strcmp(ctype, "mfc v2")) {
1494 size_t sptr = 0;
1495 // load blocks (i) from 0..N, but check sptr against total data length, not `i`
1496 for (int i = 0; sptr < maxdatalen; i++) {
1497 if (sptr + MFBLOCK_SIZE > maxdatalen) {
1498 PrintAndLogEx(ERR, "loadFileJSONex: maxdatalen=%zu (%04zx) block (i)=%4d (%04x) sptr=%zu (%04zx) -- exceeded maxdatalen", maxdatalen, maxdatalen, i, i, sptr, sptr);
1499 retval = PM3_EMALLOC;
1500 goto out;
1503 snprintf(blocks, sizeof(blocks), "$.blocks.%d", i);
1504 uint8_t block[MFBLOCK_SIZE] = {0}; // ensure zero-filled when partial block of data read
1505 JsonLoadBufAsHex(root, blocks, block, MFBLOCK_SIZE, &len);
1506 if (load_file_sanity(ctype, MFBLOCK_SIZE, i, len) == false) {
1507 break;
1510 memcpy(&udata.bytes[sptr], block, MFBLOCK_SIZE);
1511 sptr += MFBLOCK_SIZE; // always increment pointer by the full block size, even if only partial data read from dump file
1514 *datalen = sptr;
1515 goto out;
1518 if (!strcmp(ctype, "mfc v3")) {
1520 JsonLoadBufAsHex(root, "$.Card.UID", udata.mfc_ev1->card.ev1.uid, udata.mfc_ev1->card.ev1.uidlen, datalen);
1521 JsonLoadBufAsHex(root, "$.Card.ATQA", udata.mfc_ev1->card.ev1.atqa, 2, datalen);
1522 JsonLoadBufAsHex(root, "$.Card.SAK", &(udata.mfc_ev1->card.ev1.sak), 1, datalen);
1523 JsonLoadBufAsHex(root, "$.Card.ATS", udata.mfc_ev1->card.ev1.ats, sizeof(udata.mfc_ev1->card.ev1.ats_len), datalen);
1524 JsonLoadBufAsHex(root, "$.Card.SIGNATURE", udata.mfc_ev1->card.ev1.signature, sizeof(udata.mfc_ev1->card.ev1.signature), datalen);
1526 *datalen = MFU_DUMP_PREFIX_LENGTH;
1528 size_t sptr = 0;
1529 // load blocks (i) from 0..N, but check sptr against total data length, not `i`
1530 for (int i = 0; sptr < maxdatalen; i++) {
1531 if (sptr + MFBLOCK_SIZE > maxdatalen) {
1532 PrintAndLogEx(ERR, "loadFileJSONex: maxdatalen=%zu (%04zx) block (i)=%4d (%04x) sptr=%zu (%04zx) -- exceeded maxdatalen", maxdatalen, maxdatalen, i, i, sptr, sptr);
1533 retval = PM3_EMALLOC;
1534 goto out;
1537 snprintf(blocks, sizeof(blocks), "$.blocks.%d", i);
1538 uint8_t block[MFBLOCK_SIZE] = {0}; // ensure zero-filled when partial block of data read
1539 JsonLoadBufAsHex(root, blocks, block, MFBLOCK_SIZE, &len);
1541 if (load_file_sanity(ctype, MFBLOCK_SIZE, i, len) == false) {
1542 break;
1545 memcpy(&udata.bytes[sptr], block, MFBLOCK_SIZE);
1546 sptr += MFBLOCK_SIZE; // always increment pointer by the full block size, even if only partial data read from dump file
1549 *datalen = sptr;
1550 goto out;
1553 if (!strcmp(ctype, "fudan")) {
1554 size_t sptr = 0;
1555 for (int i = 0; i < maxdatalen; i++) {
1556 if (sptr + 4 > maxdatalen) {
1557 PrintAndLogEx(ERR, "loadFileJSONex: maxdatalen=%zu (%04zx) block (i)=%4d (%04x) sptr=%zu (%04zx) -- exceeded maxdatalen", maxdatalen, maxdatalen, i, i, sptr, sptr);
1558 retval = PM3_EMALLOC;
1559 goto out;
1562 snprintf(blocks, sizeof(blocks), "$.blocks.%d", i);
1563 JsonLoadBufAsHex(root, blocks, &udata.bytes[sptr], 4, &len);
1565 if (load_file_sanity(ctype, 4, i, len) == false) {
1566 break;
1568 sptr += len;
1571 *datalen = sptr;
1572 goto out;
1575 if (!strcmp(ctype, "mfu")) {
1577 JsonLoadBufAsHex(root, "$.Card.Version", udata.mfu->version, sizeof(udata.mfu->version), datalen);
1578 JsonLoadBufAsHex(root, "$.Card.TBO_0", udata.mfu->tbo, sizeof(udata.mfu->tbo), datalen);
1579 JsonLoadBufAsHex(root, "$.Card.TBO_1", udata.mfu->tbo1, sizeof(udata.mfu->tbo1), datalen);
1580 JsonLoadBufAsHex(root, "$.Card.Signature", udata.mfu->signature, sizeof(udata.mfu->signature), datalen);
1581 JsonLoadBufAsHex(root, "$.Card.Counter0", &udata.mfu->counter_tearing[0][0], 3, datalen);
1582 JsonLoadBufAsHex(root, "$.Card.Tearing0", &udata.mfu->counter_tearing[0][3], 1, datalen);
1583 JsonLoadBufAsHex(root, "$.Card.Counter1", &udata.mfu->counter_tearing[1][0], 3, datalen);
1584 JsonLoadBufAsHex(root, "$.Card.Tearing1", &udata.mfu->counter_tearing[1][3], 1, datalen);
1585 JsonLoadBufAsHex(root, "$.Card.Counter2", &udata.mfu->counter_tearing[2][0], 3, datalen);
1586 JsonLoadBufAsHex(root, "$.Card.Tearing2", &udata.mfu->counter_tearing[2][3], 1, datalen);
1587 *datalen = MFU_DUMP_PREFIX_LENGTH;
1589 size_t sptr = 0;
1590 for (int i = 0; i < 256; i++) {
1591 if (sptr + 4 > maxdatalen) {
1592 PrintAndLogEx(ERR, "loadFileJSONex: maxdatalen=%zu (%04zx) block (i)=%4d (%04x) sptr=%zu (%04zx) -- exceeded maxdatalen", maxdatalen, maxdatalen, i, i, sptr, sptr);
1593 retval = PM3_EMALLOC;
1594 goto out;
1597 snprintf(blocks, sizeof(blocks), "$.blocks.%d", i);
1598 JsonLoadBufAsHex(root, blocks, &udata.mfu->data[sptr], MFU_BLOCK_SIZE, &len);
1600 if (load_file_sanity(ctype, MFU_BLOCK_SIZE, i, len) == false) {
1601 break;
1604 sptr += len;
1605 udata.mfu->pages++;
1607 // remove one, since pages indicates a index rather than number of available pages
1608 --udata.mfu->pages;
1610 *datalen += sptr;
1611 goto out;
1614 if (!strcmp(ctype, "hitag")) {
1615 size_t sptr = 0;
1616 for (int i = 0; i < (maxdatalen / 4); i++) {
1617 if (sptr + 4 > maxdatalen) {
1618 PrintAndLogEx(ERR, "loadFileJSONex: maxdatalen=%zu (%04zx) block (i)=%4d (%04x) sptr=%zu (%04zx) -- exceeded maxdatalen", maxdatalen, maxdatalen, i, i, sptr, sptr);
1619 retval = PM3_EMALLOC;
1620 goto out;
1623 snprintf(blocks, sizeof(blocks), "$.blocks.%d", i);
1624 JsonLoadBufAsHex(root, blocks, &udata.bytes[sptr], 4, &len);
1625 if (load_file_sanity(ctype, 4, i, len) == false) {
1626 break;
1629 sptr += len;
1632 *datalen = sptr;
1633 goto out;
1636 if (!strcmp(ctype, "iclass")) {
1637 size_t sptr = 0;
1638 for (int i = 0; i < (maxdatalen / PICOPASS_BLOCK_SIZE); i++) {
1639 if (sptr + PICOPASS_BLOCK_SIZE > maxdatalen) {
1640 PrintAndLogEx(ERR, "loadFileJSONex: maxdatalen=%zu (%04zx) block (i)=%4d (%04x) sptr=%zu (%04zx) -- exceeded maxdatalen", maxdatalen, maxdatalen, i, i, sptr, sptr);
1641 retval = PM3_EMALLOC;
1642 goto out;
1645 snprintf(blocks, sizeof(blocks), "$.blocks.%d", i);
1646 JsonLoadBufAsHex(root, blocks, &udata.bytes[sptr], PICOPASS_BLOCK_SIZE, &len);
1647 if (load_file_sanity(ctype, PICOPASS_BLOCK_SIZE, i, len) == false) {
1648 break;
1651 sptr += len;
1653 *datalen = sptr;
1654 goto out;
1657 if (!strcmp(ctype, "t55x7")) {
1658 size_t sptr = 0;
1659 for (int i = 0; i < (maxdatalen / 4); i++) {
1660 if (sptr + 4 > maxdatalen) {
1661 PrintAndLogEx(ERR, "loadFileJSONex: maxdatalen=%zu (%04zx) block (i)=%4d (%04x) sptr=%zu (%04zx) -- exceeded maxdatalen", maxdatalen, maxdatalen, i, i, sptr, sptr);
1662 retval = PM3_EMALLOC;
1663 goto out;
1666 snprintf(blocks, sizeof(blocks), "$.blocks.%d", i);
1667 JsonLoadBufAsHex(root, blocks, &udata.bytes[sptr], 4, &len);
1668 if (load_file_sanity(ctype, 4, i, len) == false) {
1669 break;
1672 sptr += len;
1674 *datalen = sptr;
1675 goto out;
1678 if (!strcmp(ctype, "EM4205/EM4305")) {
1679 size_t sptr = 0;
1680 for (int i = 0; i < (maxdatalen / 4); i++) {
1681 if (sptr + 4 > maxdatalen) {
1682 PrintAndLogEx(ERR, "loadFileJSONex: maxdatalen=%zu (%04zx) block (i)=%4d (%04x) sptr=%zu (%04zx) -- exceeded maxdatalen", maxdatalen, maxdatalen, i, i, sptr, sptr);
1683 retval = PM3_EMALLOC;
1684 goto out;
1687 snprintf(blocks, sizeof(blocks), "$.blocks.%d", i);
1688 JsonLoadBufAsHex(root, blocks, &udata.bytes[sptr], 4, &len);
1689 if (load_file_sanity(ctype, 4, i, len) == false) {
1690 break;
1693 sptr += len;
1695 *datalen = sptr;
1696 goto out;
1699 if (!strcmp(ctype, "EM4469/EM4569")) {
1700 size_t sptr = 0;
1701 for (int i = 0; i < (maxdatalen / 4); i++) {
1702 if (sptr + 4 > maxdatalen) {
1703 PrintAndLogEx(ERR, "loadFileJSONex: maxdatalen=%zu (%04zx) block (i)=%4d (%04x) sptr=%zu (%04zx) -- exceeded maxdatalen", maxdatalen, maxdatalen, i, i, sptr, sptr);
1704 retval = PM3_EMALLOC;
1705 goto out;
1708 snprintf(blocks, sizeof(blocks), "$.blocks.%d", i);
1709 JsonLoadBufAsHex(root, blocks, &udata.bytes[sptr], 4, &len);
1710 if (load_file_sanity(ctype, 4, i, len) == false) {
1711 break;
1714 sptr += len;
1716 *datalen = sptr;
1717 goto out;
1720 if (!strcmp(ctype, "EM4X50")) {
1721 size_t sptr = 0;
1722 for (int i = 0; i < (maxdatalen / 4); i++) {
1723 if (sptr + 4 > maxdatalen) {
1724 PrintAndLogEx(ERR, "loadFileJSONex: maxdatalen=%zu (%04zx) block (i)=%4d (%04x) sptr=%zu (%04zx) -- exceeded maxdatalen", maxdatalen, maxdatalen, i, i, sptr, sptr);
1725 retval = PM3_EMALLOC;
1726 goto out;
1729 snprintf(blocks, sizeof(blocks), "$.blocks.%d", i);
1730 JsonLoadBufAsHex(root, blocks, &udata.bytes[sptr], 4, &len);
1731 if (load_file_sanity(ctype, 4, i, len) == false) {
1732 break;
1735 sptr += len;
1737 *datalen = sptr;
1738 goto out;
1741 // depricated
1742 if (!strcmp(ctype, "15693")) {
1743 PrintAndLogEx(WARNING, "loadFileJSONex: loading deprecated 15693 format");
1744 // will set every metadata to 0 except 1st UID byte to E0 and memory layout
1745 iso15_tag_t *tag = (iso15_tag_t *)udata.bytes;
1746 tag->uid[7] = 0xE0;
1747 tag->bytesPerPage = 4;
1748 JsonLoadBufAsHex(root, "$.raw", tag->data
1749 , MIN(maxdatalen, ISO15693_TAG_MAX_SIZE)
1750 , datalen
1753 if (*datalen > ISO15693_TAG_MAX_SIZE) {
1754 PrintAndLogEx(ERR, "loadFileJSONex: maxdatalen=%zu (%04zx) sptr=%zu (%04zx) -- exceeded maxdatalen"
1755 , ISO15693_TAG_MAX_SIZE
1756 , ISO15693_TAG_MAX_SIZE
1757 , *datalen
1758 , *datalen
1760 retval = PM3_EMALLOC;
1761 goto out;
1763 tag->pagesCount = *datalen / 4;
1764 if (tag->pagesCount > ISO15693_TAG_MAX_PAGES) {
1765 PrintAndLogEx(ERR, "loadFileJSONex: maxpagecount=%zu (%04zx) pagecount=%u (%04x) -- exceeded maxpagecount"
1766 , ISO15693_TAG_MAX_PAGES
1767 , ISO15693_TAG_MAX_PAGES
1768 , tag->pagesCount
1769 , tag->pagesCount
1771 retval = PM3_EMALLOC;
1772 goto out;
1774 *datalen = sizeof(iso15_tag_t);
1775 goto out;
1778 // depricated: handles ISO15693 w blocksize of 4 bytes.
1779 if (!strcmp(ctype, "15693 v2")) {
1780 PrintAndLogEx(WARNING, "loadFileJSONex: loading deprecated 15693 v2 format");
1781 // will set every metadata to 0 except 1st UID byte to E0 and memory layout
1782 iso15_tag_t *tag = (iso15_tag_t *)udata.bytes;
1783 tag->uid[7] = 0xE0;
1784 tag->bytesPerPage = 4;
1785 size_t sptr = 0;
1787 for (uint32_t i = 0; i < (maxdatalen / 4) ; i++) {
1788 if (((i + 1) * 4) > ISO15693_TAG_MAX_SIZE) {
1789 PrintAndLogEx(ERR, "loadFileJSONex: maxdatalen=%zu (%04zx) block (i)=%4d (%04x) sptr=%zu (%04zx) -- exceeded maxdatalen"
1790 , maxdatalen
1791 , maxdatalen
1794 , sptr
1795 , sptr
1798 retval = PM3_EMALLOC;
1799 goto out;
1802 snprintf(blocks, sizeof(blocks), "$.blocks.%u", i);
1803 JsonLoadBufAsHex(root, blocks, &tag->data[sptr], 4, &len);
1804 if (load_file_sanity(ctype, tag->bytesPerPage, i, len) == false) {
1805 break;
1807 sptr += len;
1810 tag->pagesCount = sptr / 4;
1811 if (tag->pagesCount > ISO15693_TAG_MAX_PAGES) {
1812 PrintAndLogEx(ERR, "loadFileJSONex: maxpagecount=%zu (%04zx) pagecount=%u (%04x) -- exceeded maxpagecount"
1813 , ISO15693_TAG_MAX_PAGES
1814 , ISO15693_TAG_MAX_PAGES
1815 , tag->pagesCount
1816 , tag->pagesCount
1818 retval = PM3_EMALLOC;
1819 goto out;
1822 *datalen = sizeof(iso15_tag_t);
1823 goto out;
1825 // depricated: handles ISO15693 w blocksize of 8 bytes.
1826 if (!strcmp(ctype, "15693 v3")) {
1827 PrintAndLogEx(WARNING, "loadFileJSONex: loading deprecated 15693 v3 format");
1828 // will set every metadata to 0 except 1st UID byte to E0 and memory layout
1829 iso15_tag_t *tag = (iso15_tag_t *)udata.bytes;
1830 tag->uid[7] = 0xE0;
1831 tag->bytesPerPage = 8;
1832 size_t sptr = 0;
1834 for (uint32_t i = 0; i < (maxdatalen / 8) ; i++) {
1835 if (((i + 1) * 8) > ISO15693_TAG_MAX_SIZE) {
1836 PrintAndLogEx(ERR, "loadFileJSONex: maxdatalen=%zu (%04zx) block (i)=%4d (%04x) sptr=%zu (%04zx) -- exceeded maxdatalen"
1837 , maxdatalen
1838 , maxdatalen
1841 , sptr
1842 , sptr
1845 retval = PM3_EMALLOC;
1846 goto out;
1849 snprintf(blocks, sizeof(blocks), "$.blocks.%u", i);
1850 JsonLoadBufAsHex(root, blocks, &tag->data[sptr], 8, &len);
1851 if (load_file_sanity(ctype, tag->bytesPerPage, i, len) == false) {
1852 break;
1854 sptr += len;
1857 tag->pagesCount = sptr / 8;
1858 if (tag->pagesCount > ISO15693_TAG_MAX_PAGES) {
1859 PrintAndLogEx(ERR, "loadFileJSONex: maxpagecount=%zu (%04zx) pagecount=%u (%04x) -- exceeded maxpagecount"
1860 , ISO15693_TAG_MAX_PAGES
1861 , ISO15693_TAG_MAX_PAGES
1862 , tag->pagesCount
1863 , tag->pagesCount
1865 retval = PM3_EMALLOC;
1866 goto out;
1869 *datalen = sizeof(iso15_tag_t);
1870 goto out;
1873 if (!strcmp(ctype, "15693 v4")) {
1874 iso15_tag_t *tag = (iso15_tag_t *)udata.bytes;
1875 JsonLoadBufAsHex(root, "$.Card.uid", tag->uid, 8, datalen);
1876 JsonLoadBufAsHex(root, "$.Card.dsfid", &tag->dsfid, 1, datalen);
1877 JsonLoadBufAsHex(root, "$.Card.dsfidlock", (uint8_t *)&tag->dsfidLock, 1, datalen);
1878 JsonLoadBufAsHex(root, "$.Card.afi", &tag->afi, 1, datalen);
1879 JsonLoadBufAsHex(root, "$.Card.afilock", (uint8_t *)&tag->afiLock, 1, datalen);
1880 JsonLoadBufAsHex(root, "$.Card.bytesperpage", &tag->bytesPerPage, 1, datalen);
1881 JsonLoadBufAsHex(root, "$.Card.pagescount", &tag->pagesCount, 1, datalen);
1883 if ((tag->pagesCount > ISO15693_TAG_MAX_PAGES) ||
1884 ((tag->pagesCount * tag->bytesPerPage) > ISO15693_TAG_MAX_SIZE) ||
1885 (tag->pagesCount == 0) ||
1886 (tag->bytesPerPage == 0)) {
1887 PrintAndLogEx(ERR, "loadFileJSONex: pagesCount=%u (%04x) bytesPerPage=%u (%04x) -- invalid tag memory layout"
1888 , tag->pagesCount
1889 , tag->pagesCount
1890 , tag->bytesPerPage
1891 , tag->bytesPerPage
1893 retval = PM3_EMALLOC;
1894 goto out;
1897 JsonLoadBufAsHex(root, "$.Card.ic", &tag->ic, 1, datalen);
1898 JsonLoadBufAsHex(root, "$.Card.locks", tag->locks, tag->pagesCount, datalen);
1899 JsonLoadBufAsHex(root, "$.Card.random", tag->random, 2, datalen);
1900 JsonLoadBufAsHex(root, "$.Card.privacypasswd", tag->privacyPasswd, 4, datalen);
1901 JsonLoadBufAsHex(root, "$.Card.state", (uint8_t *)&tag->state, 1, datalen);
1903 size_t sptr = 0;
1904 for (uint8_t i = 0; i < tag->pagesCount ; i++) {
1906 if (((i + 1) * tag->bytesPerPage) > ISO15693_TAG_MAX_SIZE) {
1907 PrintAndLogEx(ERR, "loadFileJSONex: maxdatalen=%zu (%04zx) block (i)=%4d (%04x) sptr=%zu (%04zx) -- exceeded maxdatalen"
1908 , maxdatalen
1909 , maxdatalen
1912 , sptr
1913 , sptr
1916 retval = PM3_EMALLOC;
1917 goto out;
1920 snprintf(blocks, sizeof(blocks), "$.blocks.%d", i);
1921 JsonLoadBufAsHex(root, blocks, &tag->data[sptr], tag->bytesPerPage, &len);
1922 if (load_file_sanity(ctype, tag->bytesPerPage, i, len) == false) {
1923 break;
1925 sptr += len;
1928 *datalen = sizeof(iso15_tag_t);
1929 goto out;
1932 if (!strcmp(ctype, "legic v2")) {
1933 size_t sptr = 0;
1934 for (int i = 0; i < 64; i++) {
1935 if (sptr + 16 > maxdatalen) {
1936 PrintAndLogEx(ERR, "loadFileJSONex: maxdatalen=%zu (%04zx) block (i)=%4d (%04x) sptr=%zu (%04zx) -- exceeded maxdatalen", maxdatalen, maxdatalen, i, i, sptr, sptr);
1937 retval = PM3_EMALLOC;
1938 goto out;
1941 snprintf(blocks, sizeof(blocks), "$.blocks.%d", i);
1942 JsonLoadBufAsHex(root, blocks, &udata.bytes[sptr], 16, &len);
1943 if (load_file_sanity(ctype, 16, i, len) == false) {
1944 break;
1946 sptr += len;
1949 *datalen = sptr;
1950 goto out;
1953 // depricated
1954 if (!strcmp(ctype, "legic")) {
1955 JsonLoadBufAsHex(root, "$.raw", udata.bytes, maxdatalen, datalen);
1956 goto out;
1959 if (!strcmp(ctype, "topaz")) {
1961 JsonLoadBufAsHex(root, "$.Card.UID", udata.topaz->uid, sizeof(udata.topaz->uid), datalen);
1962 JsonLoadBufAsHex(root, "$.Card.HR01", udata.topaz->HR01, sizeof(udata.topaz->HR01), datalen);
1963 JsonLoadBufAsHex(root, "$.Card.Size", (uint8_t *) & (udata.topaz->size), 2, datalen);
1965 size_t sptr = 0;
1966 for (int i = 0; i < (TOPAZ_STATIC_MEMORY / 8); i++) {
1968 if (sptr + TOPAZ_BLOCK_SIZE > maxdatalen) {
1969 PrintAndLogEx(ERR, "loadFileJSONex: maxdatalen=%zu (%04zx) block (i)=%4d (%04x) sptr=%zu (%04zx) -- exceeded maxdatalen", maxdatalen, maxdatalen, i, i, sptr, sptr);
1970 retval = PM3_EMALLOC;
1971 goto out;
1974 snprintf(blocks, sizeof(blocks), "$.blocks.%d", i);
1975 JsonLoadBufAsHex(root, blocks, &udata.topaz->data_blocks[sptr][0], TOPAZ_BLOCK_SIZE, &len);
1976 if (load_file_sanity(ctype, TOPAZ_BLOCK_SIZE, i, len) == false) {
1977 break;
1980 sptr += len;
1981 // ICEMAN todo: add dynamic memory.
1982 // uint16_z Size
1983 // uint8_t *dynamic_memory;
1986 *datalen += sptr;
1987 goto out;
1990 if (!strcmp(ctype, "mfpkeys")) {
1992 JsonLoadBufAsHex(root, "$.Card.UID", udata.bytes, 7, datalen);
1993 JsonLoadBufAsHex(root, "$.Card.SAK", udata.bytes + 10, 1, datalen);
1994 JsonLoadBufAsHex(root, "$.Card.ATQA", udata.bytes + 11, 2, datalen);
1995 uint8_t atslen = udata.bytes[13];
1996 if (atslen > 0) {
1997 JsonLoadBufAsHex(root, "$.Card.ATS", udata.bytes + 14, atslen, datalen);
2000 size_t sptr = (14 + atslen);
2002 // memcpy(vdata, udata.bytes + (14 + atslen), 2 * 64 * 17);
2003 for (int i = 0; i < 64; i++) {
2005 if ((sptr + (AES_KEY_LEN * 2)) > maxdatalen) {
2006 PrintAndLogEx(ERR, "loadFileJSONex: maxdatalen=%zu (%04zx) block (i)=%4d (%04x) sptr=%zu (%04zx) -- exceeded maxdatalen", maxdatalen, maxdatalen, i, i, sptr, sptr);
2007 break;
2010 size_t offset = (14 + atslen) + (i * 2 * AES_KEY_LEN);
2012 snprintf(blocks, sizeof(blocks), "$.SectorKeys.%d.KeyA", i);
2013 JsonLoadBufAsHex(root, blocks, udata.bytes + offset, AES_KEY_LEN, datalen);
2015 snprintf(blocks, sizeof(blocks), "$.SectorKeys.%d.KeyB", i);
2016 JsonLoadBufAsHex(root, blocks, udata.bytes + offset + AES_KEY_LEN, AES_KEY_LEN, datalen);
2018 sptr += (2 * AES_KEY_LEN);
2020 *datalen += sptr;
2021 goto out;
2024 if (!strcmp(ctype, "mfdes")) {
2025 JsonLoadBufAsHex(root, "$.Card.UID", udata.bytes, 7, datalen);
2026 JsonLoadBufAsHex(root, "$.Card.SAK", udata.bytes + 10, 1, datalen);
2027 JsonLoadBufAsHex(root, "$.Card.ATQA", udata.bytes + 11, 2, datalen);
2028 uint8_t atslen = udata.bytes[13];
2029 if (atslen > 0) {
2030 JsonLoadBufAsHex(root, "$.Card.ATS", udata.bytes + 14, atslen, datalen);
2033 // size_t sptr = (14 + atslen);
2034 // uint8_t dvdata[4][0xE][24 + 1] = {{{0}}};
2037 for (int i = 0; i < (int)datalen; i++) {
2038 char path[PATH_MAX_LENGTH] = {0};
2040 if (dvdata[0][i][0]) {
2041 snprintf(path, sizeof(path), "$.DES.%d.Key", i);
2042 JsonSaveBufAsHexCompact(root, path, &dvdata[0][i][1], DES_KEY_LEN);
2045 if (dvdata[1][i][0]) {
2046 snprintf(path, sizeof(path), "$.3DES.%d.Key", i);
2047 JsonSaveBufAsHexCompact(root, path, &dvdata[1][i][1], T2DES_KEY_LEN);
2049 if (dvdata[2][i][0]) {
2050 snprintf(path, sizeof(path), "$.AES.%d.Key", i);
2051 JsonSaveBufAsHexCompact(root, path, &dvdata[2][i][1], AES_KEY_LEN);
2053 if (dvdata[3][i][0]) {
2054 snprintf(path, sizeof(path), "$.K3KDES.%d.Key", i);
2055 JsonSaveBufAsHexCompact(root, path, &dvdata[3][i][1], T3DES_KEY_LEN);
2059 // memcpy(&data[14 + atslen], dvdata, 4 * 0xE * (24 + 1));
2061 goto out;
2064 if (!strcmp(ctype, "14b v2")) {
2065 size_t sptr = 0;
2066 for (int i = 0; i < (maxdatalen / 4); i++) {
2067 if (sptr + 4 > maxdatalen) {
2068 PrintAndLogEx(ERR, "loadFileJSONex: maxdatalen=%zu (%04zx) block (i)=%4d (%04x) sptr=%zu (%04zx) -- exceeded maxdatalen", maxdatalen, maxdatalen, i, i, sptr, sptr);
2069 retval = PM3_EMALLOC;
2070 goto out;
2073 snprintf(blocks, sizeof(blocks), "$.blocks.%d", i);
2074 JsonLoadBufAsHex(root, blocks, &udata.bytes[sptr], 4, &len);
2075 if (load_file_sanity(ctype, 4, i, len) == false) {
2076 break;
2078 sptr += len;
2081 *datalen = sptr;
2082 goto out;
2085 if (!strcmp(ctype, "lto")) {
2086 size_t sptr = 0;
2087 for (int i = 0; i < (maxdatalen / 32); i++) {
2088 if (sptr + 32 > maxdatalen) {
2089 PrintAndLogEx(ERR, "loadFileJSONex: maxdatalen=%zu (%04zx) block (i)=%4d (%04x) sptr=%zu (%04zx) -- exceeded maxdatalen", maxdatalen, maxdatalen, i, i, sptr, sptr);
2090 retval = PM3_EMALLOC;
2091 goto out;
2094 snprintf(blocks, sizeof(blocks), "$.blocks.%d", i);
2095 JsonLoadBufAsHex(root, blocks, &udata.bytes[sptr], 32, &len);
2096 if (load_file_sanity(ctype, 32, i, len) == false) {
2097 break;
2099 sptr += len;
2102 *datalen = sptr;
2103 goto out;
2106 if (!strcmp(ctype, "cryptorf")) {
2107 size_t sptr = 0;
2108 for (int i = 0; i < (maxdatalen / 8); i++) {
2109 if (sptr + 8 > maxdatalen) {
2110 PrintAndLogEx(ERR, "loadFileJSONex: maxdatalen=%zu (%04zx) block (i)=%4d (%04x) sptr=%zu (%04zx) -- exceeded maxdatalen", maxdatalen, maxdatalen, i, i, sptr, sptr);
2111 retval = PM3_EMALLOC;
2112 goto out;
2115 snprintf(blocks, sizeof(blocks), "$.blocks.%d", i);
2116 JsonLoadBufAsHex(root, blocks, &udata.bytes[sptr], 8, &len);
2117 if (load_file_sanity(ctype, 8, i, len) == false) {
2118 break;
2120 sptr += len;
2123 *datalen = sptr;
2124 goto out;
2127 if (!strcmp(ctype, "ndef")) {
2130 // when we will read and return extra values from NDEF json
2131 json_error_t up_error = {0};
2132 int i1 = 0;
2133 size_t ndefsize = 0;
2134 if (json_unpack_ex(root, &up_error, 0, "{s:i}", "Ndef.Size", &i1) == 0) {
2135 ndefsize = i1;
2139 size_t sptr = 0;
2140 for (int i = 0; i < (maxdatalen / 16); i++) {
2141 if (sptr + 16 > maxdatalen) {
2142 PrintAndLogEx(ERR, "loadFileJSONex: maxdatalen=%zu (%04zx) block (i)=%4d (%04x) sptr=%zu (%04zx) -- exceeded maxdatalen", maxdatalen, maxdatalen, i, i, sptr, sptr);
2143 retval = PM3_EMALLOC;
2144 goto out;
2147 snprintf(blocks, sizeof(blocks), "$.blocks.%d", i);
2148 JsonLoadBufAsHex(root, blocks, &udata.bytes[sptr], 16, &len);
2149 if (load_file_sanity(ctype, 16, i, len) == false) {
2150 break;
2153 sptr += len;
2156 *datalen = sptr;
2157 goto out;
2160 out:
2161 if (callback != NULL) {
2162 (*callback)(root);
2165 json_decref(root);
2166 return retval;
2169 int loadFileJSONroot(const char *preferredName, void **proot, bool verbose) {
2170 char *path;
2171 int res = searchFile(&path, RESOURCES_SUBDIR, preferredName, ".json", false);
2172 if (res != PM3_SUCCESS) {
2173 return PM3_EFILE;
2176 json_error_t error;
2177 json_t *root = json_load_file(path, 0, &error);
2178 if (verbose) {
2179 PrintAndLogEx(SUCCESS, "Loaded " _YELLOW_("%s"), path);
2182 free(path);
2184 int retval = PM3_SUCCESS;
2185 if (root == NULL) {
2186 PrintAndLogEx(ERR, "ERROR: json " _YELLOW_("%s") " error on line %d: %s", preferredName, error.line, error.text);
2187 retval = PM3_ESOFT;
2190 if (json_is_object(root) == false) {
2191 PrintAndLogEx(ERR, "ERROR: Invalid json " _YELLOW_("%s") " format. root must be an object.", preferredName);
2192 retval = PM3_ESOFT;
2195 if (retval == PM3_ESOFT)
2196 json_decref(root);
2197 else
2198 *proot = root;
2200 return retval;
2203 // iceman: todo - move all unsafe functions like this from client source.
2204 int loadFileDICTIONARY(const char *preferredName, void *data, size_t *datalen, uint8_t keylen, uint32_t *keycnt) {
2205 // t5577 == 4 bytes
2206 // mifare == 6 bytes
2207 // mf plus == 16 bytes
2208 // mf desfire == 3des3k 24 bytes
2209 // iclass == 8 bytes
2210 // default to 6 bytes.
2211 if (keylen != 4 && keylen != 6 && keylen != 8 && keylen != 16 && keylen != 24) {
2212 keylen = 6;
2215 return loadFileDICTIONARYEx(preferredName, data, 0, datalen, keylen, keycnt, 0, NULL, true);
2218 int loadFileDICTIONARYEx(const char *preferredName, void *data, size_t maxdatalen, size_t *datalen, uint8_t keylen, uint32_t *keycnt,
2219 size_t startFilePosition, size_t *endFilePosition, bool verbose) {
2221 if (data == NULL) {
2222 return PM3_EINVARG;
2225 if (endFilePosition) {
2226 *endFilePosition = 0;
2229 char *path;
2230 if (searchFile(&path, DICTIONARIES_SUBDIR, preferredName, ".dic", false) != PM3_SUCCESS) {
2231 return PM3_EFILE;
2234 // double up since its chars
2235 keylen <<= 1;
2237 char line[255];
2238 uint32_t vkeycnt = 0;
2239 size_t counter = 0;
2240 int retval = PM3_SUCCESS;
2242 FILE *f = fopen(path, "r");
2243 if (!f) {
2244 PrintAndLogEx(WARNING, "file not found or locked `" _YELLOW_("%s") "`", path);
2245 retval = PM3_EFILE;
2246 goto out;
2249 if (startFilePosition) {
2250 if (fseek(f, startFilePosition, SEEK_SET) < 0) {
2251 fclose(f);
2252 retval = PM3_EFILE;
2253 goto out;
2257 uint8_t *udata = (uint8_t *)data;
2259 // read file
2260 while (!feof(f)) {
2261 long filepos = ftell(f);
2263 if (!fgets(line, sizeof(line), f)) {
2264 if (endFilePosition) {
2265 *endFilePosition = 0;
2267 break;
2270 // add null terminator
2271 line[keylen] = 0;
2273 // smaller keys than expected is skipped
2274 if (strlen(line) < keylen) {
2275 continue;
2278 // The line start with # is comment, skip
2279 if (line[0] == '#') {
2280 continue;
2283 if (!CheckStringIsHEXValue(line)) {
2284 continue;
2287 // cant store more data
2288 if (maxdatalen && (counter + (keylen >> 1) > maxdatalen)) {
2289 retval = 1;
2290 if (endFilePosition) {
2291 *endFilePosition = filepos;
2293 break;
2296 if (hex_to_bytes(line, udata + counter, keylen >> 1) != (keylen >> 1)) {
2297 continue;
2300 vkeycnt++;
2301 memset(line, 0, sizeof(line));
2302 counter += (keylen >> 1);
2305 fclose(f);
2307 if (verbose) {
2308 PrintAndLogEx(SUCCESS, "Loaded " _GREEN_("%2d") " keys from dictionary file `" _YELLOW_("%s") "`", vkeycnt, path);
2311 if (datalen) {
2312 *datalen = counter;
2315 if (keycnt) {
2316 *keycnt = vkeycnt;
2318 out:
2319 free(path);
2320 return retval;
2324 int loadFileDICTIONARY_safe(const char *preferredName, void **pdata, uint8_t keylen, uint32_t *keycnt) {
2325 return loadFileDICTIONARY_safe_ex(preferredName, ".dic", pdata, keylen, keycnt, true);
2328 int loadFileDICTIONARY_safe_ex(const char *preferredName, const char *suffix, void **pdata, uint8_t keylen, uint32_t *keycnt, bool verbose) {
2330 int retval = PM3_SUCCESS;
2332 char *path;
2333 if (searchFile(&path, DICTIONARIES_SUBDIR, preferredName, suffix, false) != PM3_SUCCESS) {
2334 return PM3_EFILE;
2337 // t5577 == 4bytes
2338 // mifare == 6 bytes
2339 // mf plus == 16 bytes
2340 // mf desfire == 3des3k 24 bytes
2341 // iclass == 8 bytes
2342 // default to 6 bytes.
2343 if (keylen != 4 && keylen != 5 && keylen != 6 && keylen != 8 && keylen != 16 && keylen != 24) {
2344 keylen = 6;
2347 size_t mem_size;
2348 size_t block_size = 10 * keylen;
2350 // double up since its chars
2351 keylen <<= 1;
2353 char line[255];
2355 // allocate some space for the dictionary
2356 *pdata = calloc(block_size, sizeof(uint8_t));
2357 if (*pdata == NULL) {
2358 free(path);
2359 return PM3_EFILE;
2361 mem_size = block_size;
2363 FILE *f = fopen(path, "r");
2364 if (!f) {
2365 PrintAndLogEx(WARNING, "file not found or locked `" _YELLOW_("%s") "`", path);
2366 retval = PM3_EFILE;
2367 goto out;
2370 // read file
2371 while (fgets(line, sizeof(line), f)) {
2373 // check if we have enough space (if not allocate more)
2374 if ((*keycnt * (keylen >> 1)) >= mem_size) {
2376 mem_size += block_size;
2377 *pdata = realloc(*pdata, mem_size);
2379 if (*pdata == NULL) {
2380 retval = PM3_EFILE;
2381 fclose(f);
2382 goto out;
2383 } else {
2384 memset((uint8_t *)*pdata + (mem_size - block_size), 0, block_size);
2388 // The line start with # is comment, skip
2389 if (line[0] == '#') {
2390 continue;
2393 // remove newline/linefeed
2394 str_cleanrn(line, strlen(line));
2396 // smaller keys than expected is skipped
2397 if (strlen(line) < keylen) {
2398 continue;
2401 // larger keys than expected is skipped
2402 if (strlen(line) > keylen) {
2403 continue;
2406 if (CheckStringIsHEXValue(line) == false) {
2407 continue;
2410 if (hex_to_bytes(
2411 line,
2412 (uint8_t *)*pdata + (*keycnt * (keylen >> 1)),
2413 keylen >> 1) != (keylen >> 1)) {
2414 continue;
2417 (*keycnt)++;
2419 memset(line, 0, sizeof(line));
2421 fclose(f);
2423 if (verbose) {
2424 PrintAndLogEx(SUCCESS, "Loaded " _GREEN_("%2d") " keys from dictionary file `" _YELLOW_("%s") "`", *keycnt, path);
2427 out:
2428 free(path);
2429 return retval;
2432 int loadFileBinaryKey(const char *preferredName, const char *suffix, void **keya, void **keyb, size_t *alen, size_t *blen) {
2434 char *path;
2435 int res = searchFile(&path, RESOURCES_SUBDIR, preferredName, suffix, false);
2436 if (res != PM3_SUCCESS) {
2437 return PM3_EFILE;
2440 FILE *f = fopen(path, "rb");
2441 if (!f) {
2442 PrintAndLogEx(WARNING, "file not found or locked `" _YELLOW_("%s") "`", path);
2443 free(path);
2444 return PM3_EFILE;
2447 // get filesize in order to malloc memory
2448 fseek(f, 0, SEEK_END);
2449 long fsize = ftell(f);
2450 fseek(f, 0, SEEK_SET);
2452 if (fsize <= 0) {
2453 PrintAndLogEx(FAILED, "error, when getting filesize");
2454 fclose(f);
2455 free(path);
2456 return PM3_EFILE;
2459 // Half is KEY A, half is KEY B
2460 fsize /= 2;
2462 *keya = calloc(fsize, sizeof(uint8_t));
2463 if (*keya == NULL) {
2464 PrintAndLogEx(FAILED, "error, cannot allocate memory");
2465 fclose(f);
2466 free(path);
2467 return PM3_EMALLOC;
2470 *alen = fread(*keya, 1, fsize, f);
2472 *keyb = calloc(fsize, sizeof(uint8_t));
2473 if (*keyb == NULL) {
2474 PrintAndLogEx(FAILED, "error, cannot allocate memory");
2475 fclose(f);
2476 free(*keya);
2477 free(path);
2478 return PM3_EMALLOC;
2481 *blen = fread(*keyb, 1, fsize, f);
2482 fclose(f);
2484 PrintAndLogEx(SUCCESS, "Loaded binary key file `" _YELLOW_("%s") "`", path);
2485 free(path);
2486 return PM3_SUCCESS;
2489 mfu_df_e detect_mfu_dump_format(uint8_t **dump, bool verbose) {
2491 mfu_df_e retval = MFU_DF_UNKNOWN;
2492 uint8_t bcc0, bcc1;
2493 uint8_t ct = 0x88;
2495 // detect new
2496 mfu_dump_t *new = (mfu_dump_t *)*dump;
2497 bcc0 = ct ^ new->data[0] ^ new->data[1] ^ new->data[2];
2498 bcc1 = new->data[4] ^ new->data[5] ^ new->data[6] ^ new->data[7];
2499 if (bcc0 == new->data[3] && bcc1 == new->data[8]) {
2500 retval = MFU_DF_NEWBIN;
2503 // Memory layout is different for NTAG I2C 1K/2K plus
2504 // Sak 00, atqa 44 00
2505 if (0 == new->data[7] && 0x44 == new->data[8] && 0x00 == new->data[9]) {
2506 retval = MFU_DF_NEWBIN;
2509 // detect old
2510 if (retval == MFU_DF_UNKNOWN) {
2511 old_mfu_dump_t *old = (old_mfu_dump_t *)*dump;
2512 bcc0 = ct ^ old->data[0] ^ old->data[1] ^ old->data[2];
2513 bcc1 = old->data[4] ^ old->data[5] ^ old->data[6] ^ old->data[7];
2514 if (bcc0 == old->data[3] && bcc1 == old->data[8]) {
2515 retval = MFU_DF_OLDBIN;
2519 // detect plain
2520 if (retval == MFU_DF_UNKNOWN) {
2521 const uint8_t *plain = *dump;
2522 bcc0 = ct ^ plain[0] ^ plain[1] ^ plain[2];
2523 bcc1 = plain[4] ^ plain[5] ^ plain[6] ^ plain[7];
2524 if ((bcc0 == plain[3]) && (bcc1 == plain[8])) {
2525 retval = MFU_DF_PLAINBIN;
2529 if (verbose) {
2530 switch (retval) {
2531 case MFU_DF_NEWBIN:
2532 PrintAndLogEx(INFO, "Detected " _GREEN_("new") " mfu dump format");
2533 break;
2534 case MFU_DF_OLDBIN:
2535 PrintAndLogEx(INFO, "Detected " _GREEN_("old") " mfu dump format");
2536 break;
2537 case MFU_DF_PLAINBIN:
2538 PrintAndLogEx(INFO, "Detected " _GREEN_("plain") " mfu dump format");
2539 break;
2540 case MFU_DF_UNKNOWN:
2541 PrintAndLogEx(WARNING, "Failed to detected mfu dump format");
2542 break;
2545 return retval;
2548 int detect_nfc_dump_format(const char *preferredName, nfc_df_e *dump_type, bool verbose) {
2550 *dump_type = NFC_DF_UNKNOWN;
2552 char *path;
2553 int res = searchFile(&path, RESOURCES_SUBDIR, preferredName, "", false);
2554 if (res != PM3_SUCCESS) {
2555 return PM3_EFILE;
2558 FILE *f = fopen(path, "r");
2559 if (!f) {
2560 PrintAndLogEx(WARNING, "file not found or locked `" _YELLOW_("%s") "`", path);
2561 free(path);
2562 return PM3_EFILE;
2564 free(path);
2566 char line[256];
2567 memset(line, 0, sizeof(line));
2569 while (!feof(f)) {
2571 memset(line, 0, sizeof(line));
2573 if (fgets(line, sizeof(line), f) == NULL) {
2574 if (feof(f)) {
2575 break;
2578 fclose(f);
2579 PrintAndLogEx(FAILED, "file reading error");
2580 return PM3_EFILE;
2583 str_cleanrn(line, sizeof(line));
2584 str_lower(line);
2586 if (str_startswith(line, "device type: ntag")) {
2587 *dump_type = NFC_DF_MFU;
2588 break;
2590 if (str_startswith(line, "device type: mifare classic")) {
2591 *dump_type = NFC_DF_MFC;
2592 break;
2594 if (str_startswith(line, "device type: mifare desfire")) {
2595 *dump_type = NFC_DF_MFDES;
2596 break;
2598 if (str_startswith(line, "device type: iso14443-3a")) {
2599 *dump_type = NFC_DF_14_3A;
2600 break;
2602 if (str_startswith(line, "device type: iso14443-3b")) {
2603 *dump_type = NFC_DF_14_3B;
2604 break;
2606 if (str_startswith(line, "device type: iso14443-4a")) {
2607 *dump_type = NFC_DF_14_4A;
2608 break;
2610 if (str_startswith(line, "filetype: flipper picopass device")) {
2611 *dump_type = NFC_DF_PICOPASS;
2612 break;
2616 fclose(f);
2618 if (verbose) {
2619 switch (*dump_type) {
2620 case NFC_DF_MFU:
2621 PrintAndLogEx(INFO, "Detected MIFARE Ultralight / NTAG based dump format");
2622 break;
2623 case NFC_DF_MFC:
2624 PrintAndLogEx(INFO, "Detected MIFARE Classic based dump format");
2625 break;
2626 case NFC_DF_MFDES:
2627 PrintAndLogEx(INFO, "Detected MIFARE DESFire based dump format");
2628 break;
2629 case NFC_DF_14_3A:
2630 PrintAndLogEx(INFO, "Detected ISO14443-3A based dump format. No data available");
2631 break;
2632 case NFC_DF_14_3B:
2633 PrintAndLogEx(INFO, "Detected ISO14443-3B based dump format. No data available");
2634 break;
2635 case NFC_DF_14_4A:
2636 PrintAndLogEx(INFO, "Detected ISO14443-4A based dump format. No data available");
2637 break;
2638 case NFC_DF_PICOPASS:
2639 PrintAndLogEx(INFO, "Detected PICOPASS based dump format");
2640 break;
2641 case NFC_DF_UNKNOWN:
2642 PrintAndLogEx(WARNING, "Failed to detected dump format");
2643 break;
2646 return PM3_SUCCESS;
2649 static int convert_plain_mfu_dump(uint8_t **dump, size_t *dumplen, bool verbose) {
2651 mfu_dump_t *mfu = (mfu_dump_t *) calloc(sizeof(mfu_dump_t), sizeof(uint8_t));
2652 if (mfu == NULL) {
2653 return PM3_EMALLOC;
2656 memcpy(mfu->data, *dump, *dumplen);
2658 mfu->pages = *dumplen / 4 - 1;
2660 if (verbose) {
2661 PrintAndLogEx(SUCCESS, "Plain mfu dump format was converted to " _GREEN_("%d") " blocks", mfu->pages + 1);
2664 *dump = (uint8_t *)mfu;
2665 *dumplen += MFU_DUMP_PREFIX_LENGTH ;
2666 return PM3_SUCCESS;
2669 static int convert_old_mfu_dump(uint8_t **dump, size_t *dumplen, bool verbose) {
2670 /* For reference
2671 typedef struct {
2672 uint8_t version[8];
2673 uint8_t tbo[2];
2674 uint8_t tearing[3];
2675 uint8_t pack[2];
2676 uint8_t tbo1[1];
2677 uint8_t signature[32];
2678 uint8_t data[1024];
2679 } PACKED old_mfu_dump_t;
2682 // convert old format
2683 old_mfu_dump_t *old_mfu_dump = (old_mfu_dump_t *)*dump;
2685 size_t old_data_len = *dumplen - OLD_MFU_DUMP_PREFIX_LENGTH;
2686 size_t new_dump_len = old_data_len + MFU_DUMP_PREFIX_LENGTH;
2688 mfu_dump_t *mfu_dump = (mfu_dump_t *) calloc(sizeof(mfu_dump_t), sizeof(uint8_t));
2689 if (mfu_dump == NULL) {
2690 return PM3_EMALLOC;
2693 memcpy(mfu_dump->version, old_mfu_dump->version, sizeof(mfu_dump->version));
2694 memcpy(mfu_dump->tbo, old_mfu_dump->tbo, sizeof(mfu_dump->tbo));
2695 memcpy(mfu_dump->signature, old_mfu_dump->signature, sizeof(mfu_dump->signature));
2697 mfu_dump->tbo1[0] = old_mfu_dump->tbo1[0];
2699 for (int i = 0; i < 3; i++) {
2700 mfu_dump->counter_tearing[i][3] = old_mfu_dump->tearing[i];
2703 memcpy(mfu_dump->data, old_mfu_dump->data, sizeof(mfu_dump->data));
2704 mfu_dump->pages = old_data_len / 4 - 1;
2706 // Add PACK to last block of memory.
2707 memcpy(mfu_dump->data + (mfu_dump->pages * 4 + MFU_DUMP_PREFIX_LENGTH), old_mfu_dump->pack, 2);
2709 if (verbose) {
2710 PrintAndLogEx(SUCCESS, "Old mfu dump format was converted to " _GREEN_("%d") " blocks", mfu_dump->pages + 1);
2713 free(*dump);
2714 *dump = (uint8_t *)mfu_dump;
2715 *dumplen = new_dump_len;
2716 return PM3_SUCCESS;
2719 int convert_mfu_dump_format(uint8_t **dump, size_t *dumplen, bool verbose) {
2721 if (!dump || !dumplen || *dumplen < OLD_MFU_DUMP_PREFIX_LENGTH) {
2722 return PM3_EINVARG;
2725 mfu_df_e res = detect_mfu_dump_format(dump, verbose);
2727 switch (res) {
2728 case MFU_DF_NEWBIN:
2729 return PM3_SUCCESS;
2730 case MFU_DF_OLDBIN:
2731 return convert_old_mfu_dump(dump, dumplen, verbose);
2732 case MFU_DF_PLAINBIN:
2733 return convert_plain_mfu_dump(dump, dumplen, verbose);
2734 case MFU_DF_UNKNOWN:
2735 default:
2736 return PM3_ESOFT;
2740 static int filelist(const char *path, const char *ext, uint8_t last, bool tentative, uint8_t indent, uint16_t strip) {
2741 struct dirent **namelist;
2742 int n;
2744 n = scandir(path, &namelist, NULL, alphasort);
2745 if (n == -1) {
2747 if (tentative == false) {
2749 for (uint8_t j = 0; j < indent; j++) {
2750 PrintAndLogEx(NORMAL, "%s " NOLF, ((last >> j) & 1) ? " " : "│");
2752 PrintAndLogEx(NORMAL, "%s── "_GREEN_("%s"), last ? "└" : "├", &path[strip]);
2754 return PM3_EFILE;
2757 for (uint8_t j = 0; j < indent; j++) {
2758 PrintAndLogEx(NORMAL, "%s " NOLF, ((last >> j) & 1) ? " " : "│");
2761 PrintAndLogEx(NORMAL, "%s── "_GREEN_("%s"), last ? "└" : "├", &path[strip]);
2763 for (int i = 0; i < n; i++) {
2765 char tmp_fullpath[1024] = {0};
2766 strncat(tmp_fullpath, path, sizeof(tmp_fullpath) - 1);
2767 tmp_fullpath[1023] = 0x00;
2768 strncat(tmp_fullpath, namelist[i]->d_name, strlen(tmp_fullpath) - 1);
2770 if (is_directory(tmp_fullpath)) {
2772 char newpath[1024];
2773 if (strcmp(namelist[i]->d_name, ".") == 0 || strcmp(namelist[i]->d_name, "..") == 0)
2774 continue;
2776 snprintf(newpath, sizeof(newpath), "%s", path);
2777 strncat(newpath, namelist[i]->d_name, sizeof(newpath) - strlen(newpath) - 1);
2778 strncat(newpath, "/", sizeof(newpath) - strlen(newpath) - 1);
2780 filelist(newpath, ext, last + ((i == n - 1) << (indent + 1)), tentative, indent + 1, strlen(path));
2781 } else {
2783 if ((ext == NULL) || ((str_endswith(namelist[i]->d_name, ext)))) {
2785 for (uint8_t j = 0; j < indent + 1; j++) {
2786 PrintAndLogEx(NORMAL, "%s " NOLF, ((last >> j) & 1) ? " " : "│");
2788 PrintAndLogEx(NORMAL, "%s── %-21s", i == n - 1 ? "└" : "├", namelist[i]->d_name);
2791 free(namelist[i]);
2793 free(namelist);
2794 return PM3_SUCCESS;
2797 int searchAndList(const char *pm3dir, const char *ext) {
2798 // display in same order as searched by searchFile
2799 // try pm3 dirs in current workdir (dev mode)
2800 if (get_my_executable_directory() != NULL) {
2801 char script_directory_path[strlen(get_my_executable_directory()) + strlen(pm3dir) + 1];
2802 strcpy(script_directory_path, get_my_executable_directory());
2803 strcat(script_directory_path, pm3dir);
2804 filelist(script_directory_path, ext, false, true, 0, 0);
2806 // try pm3 dirs in user .proxmark3 (user mode)
2807 const char *user_path = get_my_user_directory();
2808 if (user_path != NULL) {
2809 char script_directory_path[strlen(user_path) + strlen(PM3_USER_DIRECTORY) + strlen(pm3dir) + 1];
2810 strcpy(script_directory_path, user_path);
2811 strcat(script_directory_path, PM3_USER_DIRECTORY);
2812 strcat(script_directory_path, pm3dir);
2813 filelist(script_directory_path, ext, false, false, 0, 0);
2815 // try pm3 dirs in pm3 installation dir (install mode)
2816 const char *exec_path = get_my_executable_directory();
2817 if (exec_path != NULL) {
2818 char script_directory_path[strlen(exec_path) + strlen(PM3_SHARE_RELPATH) + strlen(pm3dir) + 1];
2819 strcpy(script_directory_path, exec_path);
2820 strcat(script_directory_path, PM3_SHARE_RELPATH);
2821 strcat(script_directory_path, pm3dir);
2822 filelist(script_directory_path, ext, true, false, 0, 0);
2824 return PM3_SUCCESS;
2827 static int searchFinalFile(char **foundpath, const char *pm3dir, const char *searchname, bool silent) {
2829 if ((foundpath == NULL) || (pm3dir == NULL) || (searchname == NULL)) {
2830 return PM3_ESOFT;
2833 // explicit absolute (/) or relative path (./) => try only to match it directly
2834 char *filename = calloc(strlen(searchname) + 1, sizeof(char));
2835 if (filename == NULL) {
2836 return PM3_EMALLOC;
2839 strcpy(filename, searchname);
2840 if ((g_debugMode == 2) && (!silent)) {
2841 PrintAndLogEx(INFO, "pm3dir...... %s", pm3dir);
2842 PrintAndLogEx(INFO, "Searching... %s", filename);
2845 // try implicit relative path
2846 PrintAndLogEx(DEBUG, "Searching implicit relative paths");
2847 if (fileExists(filename)) {
2848 *foundpath = filename;
2849 if ((g_debugMode == 2) && (!silent)) {
2850 PrintAndLogEx(INFO, "Found %s", *foundpath);
2852 return PM3_SUCCESS;
2855 if (((strlen(filename) > 1) && (filename[0] == '/')) ||
2856 ((strlen(filename) > 2) && (filename[0] == '.') && (filename[1] == '/'))) {
2857 goto out;
2860 // try the session paths
2861 PrintAndLogEx(DEBUG, "Searching preferences paths");
2862 for (int i = 0; i < spItemCount; i++) {
2864 size_t sn = strlen(g_session.defaultPaths[i]) + strlen(filename) + strlen(PATHSEP) + 1;
2865 char *default_path = calloc(sn, sizeof(char));
2866 if (default_path == NULL) {
2867 goto out;
2870 snprintf(default_path, sn, "%s%s%s", g_session.defaultPaths[i], PATHSEP, filename);
2872 if ((g_debugMode == 2) && (!silent)) {
2873 PrintAndLogEx(INFO, "Searching %s", default_path);
2876 if (fileExists(default_path)) {
2877 free(filename);
2878 *foundpath = default_path;
2879 if ((g_debugMode == 2) && (!silent)) {
2880 PrintAndLogEx(INFO, "Found %s", *foundpath);
2882 return PM3_SUCCESS;
2883 } else {
2884 free(default_path);
2888 // try pm3 dirs in user .proxmark3 (user mode)
2889 PrintAndLogEx(DEBUG, "Searching user .proxmark3 paths");
2890 const char *user_path = get_my_user_directory();
2891 if (user_path != NULL) {
2892 char *path = calloc(strlen(user_path) + strlen(PM3_USER_DIRECTORY) + strlen(pm3dir) + strlen(filename) + 1, sizeof(char));
2893 if (path == NULL) {
2894 goto out;
2897 strcpy(path, user_path);
2898 strcat(path, PM3_USER_DIRECTORY);
2899 strcat(path, pm3dir);
2900 strcat(path, filename);
2902 if ((g_debugMode == 2) && (!silent)) {
2903 PrintAndLogEx(INFO, "Searching %s", path);
2906 if (fileExists(path)) {
2907 free(filename);
2908 *foundpath = path;
2909 if ((g_debugMode == 2) && (!silent)) {
2910 PrintAndLogEx(INFO, "Found %s", *foundpath);
2912 return PM3_SUCCESS;
2913 } else {
2914 free(path);
2918 // try pm3 dirs in current client workdir (dev mode)
2919 PrintAndLogEx(DEBUG, "Searching current workdir paths");
2920 const char *exec_path = get_my_executable_directory();
2921 if ((exec_path != NULL) &&
2922 ((strcmp(DICTIONARIES_SUBDIR, pm3dir) == 0) ||
2923 (strcmp(LUA_LIBRARIES_SUBDIR, pm3dir) == 0) ||
2924 (strcmp(LUA_SCRIPTS_SUBDIR, pm3dir) == 0) ||
2925 (strcmp(CMD_SCRIPTS_SUBDIR, pm3dir) == 0) ||
2926 (strcmp(PYTHON_SCRIPTS_SUBDIR, pm3dir) == 0) ||
2927 (strcmp(RESOURCES_SUBDIR, pm3dir) == 0))) {
2928 char *path = calloc(strlen(exec_path) + strlen(pm3dir) + strlen(filename) + 1, sizeof(char));
2929 if (path == NULL) {
2930 goto out;
2933 strcpy(path, exec_path);
2934 strcat(path, pm3dir);
2935 strcat(path, filename);
2937 if ((g_debugMode == 2) && (!silent)) {
2938 PrintAndLogEx(INFO, "Searching %s", path);
2941 if (fileExists(path)) {
2942 free(filename);
2943 *foundpath = path;
2944 if ((g_debugMode == 2) && (!silent)) {
2945 PrintAndLogEx(INFO, "Found %s", *foundpath);
2947 return PM3_SUCCESS;
2948 } else {
2949 free(path);
2953 // try pm3 dirs in current repo workdir (dev mode)
2954 PrintAndLogEx(DEBUG, "Searching PM3 dirs in current workdir");
2955 if ((exec_path != NULL) &&
2956 ((strcmp(TRACES_SUBDIR, pm3dir) == 0) ||
2957 (strcmp(FIRMWARES_SUBDIR, pm3dir) == 0) ||
2958 (strcmp(BOOTROM_SUBDIR, pm3dir) == 0) ||
2959 (strcmp(FULLIMAGE_SUBDIR, pm3dir) == 0))) {
2960 char *path = calloc(strlen(exec_path) + strlen(ABOVE) + strlen(pm3dir) + strlen(filename) + 1, sizeof(char));
2961 if (path == NULL) {
2962 goto out;
2965 strcpy(path, exec_path);
2966 strcat(path, ABOVE);
2967 strcat(path, pm3dir);
2968 strcat(path, filename);
2970 if ((g_debugMode == 2) && (!silent)) {
2971 PrintAndLogEx(INFO, "Searching %s", path);
2974 if (fileExists(path)) {
2975 free(filename);
2976 *foundpath = path;
2977 if ((g_debugMode == 2) && (!silent)) {
2978 PrintAndLogEx(INFO, "Found %s", *foundpath);
2980 return PM3_SUCCESS;
2981 } else {
2982 free(path);
2986 // try pm3 dirs in pm3 installation dir (install mode)
2987 PrintAndLogEx(DEBUG, "Searching PM3 installation dir paths");
2988 if (exec_path != NULL) {
2989 char *path = calloc(strlen(exec_path) + strlen(PM3_SHARE_RELPATH) + strlen(pm3dir) + strlen(filename) + 1, sizeof(char));
2990 if (path == NULL) {
2991 goto out;
2994 strcpy(path, exec_path);
2995 strcat(path, PM3_SHARE_RELPATH);
2996 strcat(path, pm3dir);
2997 strcat(path, filename);
2999 if ((g_debugMode == 2) && (!silent)) {
3000 PrintAndLogEx(INFO, "Searching %s", path);
3003 if (fileExists(path)) {
3004 free(filename);
3005 *foundpath = path;
3006 if ((g_debugMode == 2) && (!silent)) {
3007 PrintAndLogEx(INFO, "Found %s", *foundpath);
3009 return PM3_SUCCESS;
3010 } else {
3011 free(path);
3014 out:
3015 free(filename);
3016 return PM3_EFILE;
3019 int searchFile(char **foundpath, const char *pm3dir, const char *searchname, const char *suffix, bool silent) {
3021 if (foundpath == NULL)
3022 return PM3_EINVARG;
3024 if (searchname == NULL || strlen(searchname) == 0)
3025 return PM3_EINVARG;
3027 if (is_directory(searchname))
3028 return PM3_EINVARG;
3030 char *filename = filenamemcopy(searchname, suffix);
3031 if (filename == NULL)
3032 return PM3_EMALLOC;
3034 if (strlen(filename) == 0) {
3035 free(filename);
3036 return PM3_EFILE;
3039 int res = searchFinalFile(foundpath, pm3dir, filename, silent);
3040 if (res != PM3_SUCCESS) {
3041 if ((res == PM3_EFILE) && (!silent)) {
3042 PrintAndLogEx(FAILED, "Error - can't find `" _YELLOW_("%s") "`", filename);
3045 free(filename);
3046 return res;
3049 int pm3_load_dump(const char *fn, void **pdump, size_t *dumplen, size_t maxdumplen) {
3051 int res = PM3_SUCCESS;
3052 DumpFileType_t dt = get_filetype(fn);
3053 switch (dt) {
3054 case BIN: {
3055 res = loadFile_safe(fn, ".bin", pdump, dumplen);
3056 if (res == PM3_SUCCESS && *dumplen > maxdumplen) {
3057 *dumplen = maxdumplen;
3059 break;
3061 case EML: {
3062 res = loadFileEML_safe(fn, pdump, dumplen);
3063 if (res == PM3_SUCCESS && *dumplen > maxdumplen) {
3064 *dumplen = maxdumplen;
3066 break;
3068 case JSON: {
3069 *pdump = calloc(maxdumplen, sizeof(uint8_t));
3070 if (*pdump == NULL) {
3071 PrintAndLogEx(WARNING, "fail, cannot allocate memory");
3072 return PM3_EMALLOC;
3074 res = loadFileJSON(fn, *pdump, maxdumplen, dumplen, NULL);
3075 if (res == PM3_SUCCESS) {
3076 return res;
3079 free(*pdump);
3081 if (res == PM3_ESOFT) {
3082 PrintAndLogEx(WARNING, "JSON objects failed to load");
3083 } else if (res == PM3_EMALLOC) {
3084 PrintAndLogEx(WARNING, "Wrong size of allocated memory. Check your parameters");
3086 break;
3088 case DICTIONARY: {
3089 PrintAndLogEx(ERR, "Only <BIN|EML|JSON|MCT|NFC formats allowed");
3090 return PM3_EINVARG;
3092 case MCT: {
3093 res = loadFileMCT_safe(fn, pdump, dumplen);
3094 if (res == PM3_SUCCESS && *dumplen > maxdumplen) {
3095 *dumplen = maxdumplen;
3097 break;
3099 case FLIPPER: {
3100 nfc_df_e dumptype;
3101 res = detect_nfc_dump_format(fn, &dumptype, true);
3102 if (res != PM3_SUCCESS) {
3103 break;
3106 if (dumptype == NFC_DF_MFC || dumptype == NFC_DF_MFU || dumptype == NFC_DF_PICOPASS) {
3108 *pdump = calloc(maxdumplen, sizeof(uint8_t));
3109 if (*pdump == NULL) {
3110 PrintAndLogEx(WARNING, "Fail, cannot allocate memory");
3111 return PM3_EMALLOC;
3113 res = loadFileNFC_safe(fn, *pdump, maxdumplen, dumplen, dumptype);
3114 if (res == PM3_SUCCESS) {
3115 return res;
3118 free(*pdump);
3120 if (res == PM3_ESOFT) {
3121 PrintAndLogEx(WARNING, "NFC objects failed to load");
3122 } else if (res == PM3_EMALLOC) {
3123 PrintAndLogEx(WARNING, "wrong size of allocated memory. Check your parameters");
3125 } else {
3126 // unknown dump file type
3127 res = PM3_ESOFT;
3129 break;
3132 return res;
3135 int pm3_save_dump(const char *fn, uint8_t *d, size_t n, JSONFileType jsft) {
3136 if (fn == NULL || strlen(fn) == 0) {
3137 return PM3_EINVARG;
3139 if (d == NULL || n == 0) {
3140 PrintAndLogEx(INFO, "No data to save, skipping...");
3141 return PM3_EINVARG;
3143 saveFile(fn, ".bin", d, n);
3144 saveFileJSON(fn, jsft, d, n, NULL);
3145 return PM3_SUCCESS;
3148 int pm3_save_mf_dump(const char *fn, uint8_t *d, size_t n, JSONFileType jsft) {
3150 if (fn == NULL || d == NULL || n == 0) {
3151 PrintAndLogEx(INFO, "No data to save, skipping...");
3152 return PM3_EINVARG;
3154 saveFileEx(fn, ".bin", d, n, spDump);
3156 iso14a_mf_extdump_t jd = {0};
3157 jd.card_info.ats_len = 0;
3159 // Check for 4 bytes uid: bcc corrected and single size uid bits in ATQA
3160 if ((d[0] ^ d[1] ^ d[2] ^ d[3]) == d[4] && (d[6] & 0xC0) == 0) {
3161 jd.card_info.uidlen = 4;
3162 memcpy(jd.card_info.uid, d, jd.card_info.uidlen);
3163 jd.card_info.sak = d[5];
3164 memcpy(jd.card_info.atqa, &d[6], sizeof(jd.card_info.atqa));
3166 // Check for 7 bytes UID: double size uid bits in ATQA
3167 else if ((d[8] & 0xC0) == 0x40) {
3168 jd.card_info.uidlen = 7;
3169 memcpy(jd.card_info.uid, d, jd.card_info.uidlen);
3170 jd.card_info.sak = d[7];
3171 memcpy(jd.card_info.atqa, &d[8], sizeof(jd.card_info.atqa));
3172 } else {
3173 PrintAndLogEx(WARNING, "Invalid dump. UID/SAK/ATQA not found");
3175 jd.dump = d;
3176 jd.dumplen = n;
3177 saveFileJSON(fn, jsfMfc_v2, (uint8_t *)&jd, sizeof(jd), NULL);
3178 return PM3_SUCCESS;
3181 int pm3_save_fm11rf08s_nonces(const char *fn, iso14a_fm11rf08s_nonces_with_data_t *d, bool with_data) {
3183 if (fn == NULL || d == NULL) {
3184 PrintAndLogEx(INFO, "No data to save, skipping...");
3185 return PM3_EINVARG;
3188 if (with_data) {
3189 saveFileJSON(fn, jsfFM11RF08SNoncesWithData, (uint8_t *)d, sizeof(*d), NULL);
3190 } else {
3191 saveFileJSON(fn, jsfFM11RF08SNonces, (uint8_t *)d, sizeof(*d), NULL);
3193 return PM3_SUCCESS;