1 //-----------------------------------------------------------------------------
2 // Copyright (C) Proxmark3 contributors. See AUTHORS.md for details.
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.
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
19 #include "fileutils.h"
20 #include "preferences.h"
26 #include "commonutil.h"
27 #include "proxmark3.h"
29 #include "cmdhficlass.h" // pagemap
30 #include "iclass_cmd.h"
38 #define PATH_MAX_LENGTH 200
49 uint32_t sample_per_sec
;
50 uint32_t byte_per_sec
;
52 uint16_t bit_per_sample
;
61 * @brief detects if file is of a supported filetype based on extension
65 DumpFileType_t
get_filetype(const char *filename
) {
66 // assume unknown file is BINARY
67 DumpFileType_t o
= BIN
;
68 if (filename
== NULL
) {
72 size_t len
= strlen(filename
);
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
);
80 if (str_endswith(s
, "bin")) {
82 } else if (str_endswith(s
, "eml")) {
84 } else if (str_endswith(s
, "json")) {
86 } else if (str_endswith(s
, "dic")) {
88 } else if (str_endswith(s
, "mct")) {
90 } else if (str_endswith(s
, "nfc")) {
92 } else if (str_endswith(s
, "picopass")) {
95 // mfd, trc, trace is binary
98 // .pm3 is text values of signal data
105 * @brief checks if a file exists
109 int fileExists(const char *filename
) {
113 int result
= _stat(filename
, &st
);
116 int result
= stat(filename
, &st
);
122 * @brief checks if path is directory.
126 static bool is_directory(const char *filename
) {
129 if (_stat(filename
, &st
) == -1)
133 // stat(filename, &st);
134 if (lstat(filename
, &st
) == -1)
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
;
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
);
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
) {
171 strcpy(fileName
, preferredName
);
172 if (str_endswith(fileName
, suffix
)) {
176 strcat(fileName
, suffix
);
180 static size_t path_size(savePaths_t a
) {
181 if (a
>= spItemCount
) {
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
) {
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
) {
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;
230 snprintf(pfn
, len
, "%.*s%s", (int)p_namelen
, preferredName
, suffix
);
236 // check complete path/filename if exists
237 while (fileExists(fileName
)) {
239 snprintf(pfn
, len
, "%.*s-%03d%s", (int)p_namelen
, preferredName
, num
, suffix
);
246 // trunacate down a filename to LEN size
247 void truncate_filename(char *fn
, uint16_t maxlen
) {
248 if (fn
== NULL
|| maxlen
< 5) {
252 // Check if the filename is already shorter than or equal to the desired length
253 if (strlen(fn
) <= maxlen
) {
257 // If there's no extension or it's too long, just truncate the filename
258 fn
[maxlen
- 3] = '\0';
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) {
271 char *fileName
= newfilenamemcopyEx(preferredName
, suffix
, e_save_path
);
272 if (fileName
== NULL
) {
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");
281 PrintAndLogEx(WARNING
, "file not found or locked `" _YELLOW_("%s") "`", fileName
);
285 fwrite(data
, 1, datalen
, f
);
288 PrintAndLogEx(SUCCESS
, "Saved " _YELLOW_("%zu") " bytes to binary file `" _YELLOW_("%s") "`", datalen
, fileName
);
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) {
300 char path
[PATH_MAX_LENGTH
] = {0};
302 JsonSaveStr(root
, "Created", "proxmark3");
305 JsonSaveStr(root
, "FileType", "raw");
306 JsonSaveBufAsHexCompact(root
, "raw", data
, datalen
);
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);
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);
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);
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
);
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);
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
));
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
);
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);
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);
502 // handles ISO15693 in iso15_tag_t format
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
) {
525 snprintf(path
, sizeof(path
), "$.blocks.%u", i
);
526 JsonSaveBufAsHexCompact(root
528 , &tag
->data
[i
* tag
->bytesPerPage
]
535 JsonSaveStr(root
, "FileType", "legic v2");
536 JsonSaveBufAsHexCompact(root
, "$.Card.UID", data
, 4);
538 for (; i
< datalen
/ 16; i
++) {
539 snprintf(path
, sizeof(path
), "$.blocks.%zu", i
);
540 JsonSaveBufAsHexCompact(root
, path
, &data
[i
* 16], 16);
543 snprintf(path
, sizeof(path
), "$.blocks.%zu", i
);
544 JsonSaveBufAsHexCompact(root
, path
, &data
[i
* 16], (datalen
% 16));
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);
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);
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);
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);
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];
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
);
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];
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
);
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.
676 // uint8_t *dynamic_memory;
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);
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);
697 JsonSaveStr(root
, "FileType", "ndef");
698 JsonSaveInt(root
, "Ndef.Size", datalen
);
700 for (; i
< datalen
/ 16; i
++) {
701 snprintf(path
, sizeof(path
), "$.blocks.%zu", i
);
702 JsonSaveBufAsHexCompact(root
, path
, &data
[i
* 16], 16);
705 snprintf(path
, sizeof(path
), "$.blocks.%zu", i
);
706 JsonSaveBufAsHexCompact(root
, path
, &data
[i
* 16], (datalen
% 16));
710 case jsfFM11RF08SNonces
:
711 case jsfFM11RF08SNoncesWithData
: {
712 if (datalen
!= sizeof(iso14a_fm11rf08s_nonces_with_data_t
)) {
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");
719 JsonSaveStr(root
, "FileType", "fm11rf08s_nonces");
721 for (uint16_t sec
= 0; sec
< MIFARE_1K_MAXSECTOR
+ 1; sec
++) {
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
);
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
) {
786 retval
= saveFileJSONrootEx(preferredName
, root
, JSON_INDENT(2), verbose
, false, e_save_path
);
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
) {
799 char *filename
= NULL
;
801 filename
= filenamemcopy(preferredName
, ".json");
803 filename
= newfilenamemcopyEx(preferredName
, ".json", e_save_path
);
805 if (filename
== NULL
)
808 int res
= json_dump_file(root
, filename
, flags
);
812 PrintAndLogEx(SUCCESS
, "Saved to json file `" _YELLOW_("%s") "`", filename
);
817 PrintAndLogEx(FAILED
, "error, can't save the file `" _YELLOW_("%s") "`", filename
);
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
) {
829 char *s
= json_dumps(root
, JSON_INDENT(2));
834 // wave file of trace,
835 int saveFileWAVE(const char *preferredName
, const int *data
, size_t datalen
) {
837 if (data
== NULL
|| datalen
== 0) {
841 char *fileName
= newfilenamemcopyEx(preferredName
, ".wav", spTrace
);
842 if (fileName
== NULL
) {
846 int retval
= PM3_SUCCESS
;
848 struct wave_info_t wave_info
= {
850 .filesize
= sizeof(wave_info
) - sizeof(wave_info
.signature
) - sizeof(wave_info
.filesize
) + datalen
,
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");
866 PrintAndLogEx(WARNING
, "file not found or locked `" _YELLOW_("%s") "`", fileName
);
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
);
880 PrintAndLogEx(SUCCESS
, "Saved " _YELLOW_("%zu") " bytes to wave file `" _YELLOW_("%s") "`", 2 * datalen
, fileName
);
887 // Signal trace file, PM3
888 int saveFilePM3(const char *preferredName
, int *data
, size_t datalen
) {
890 if (data
== NULL
|| datalen
== 0) {
894 char *fileName
= newfilenamemcopyEx(preferredName
, ".pm3", spTrace
);
895 if (fileName
== NULL
) {
899 int retval
= PM3_SUCCESS
;
901 FILE *f
= fopen(fileName
, "w");
903 PrintAndLogEx(WARNING
, "file not found or locked `" _YELLOW_("%s") "`", fileName
);
908 for (uint32_t i
= 0; i
< datalen
; i
++) {
909 fprintf(f
, "%d\n", data
[i
]);
914 PrintAndLogEx(SUCCESS
, "Saved " _YELLOW_("%zu") " bytes to PM3 file `" _YELLOW_("%s") "`", datalen
, fileName
);
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");
931 PrintAndLogEx(WARNING
, "could not create file `" _YELLOW_("%s") "`", fileName
);
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
);
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
);
952 memcpy(tmp
, empty
, sizeof(tmp
));
953 fwrite(tmp
, 1, sizeof(tmp
), 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"));
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
) {
971 int res
= searchFile(&path
, RESOURCES_SUBDIR
, preferredName
, suffix
, false);
972 if (res
!= PM3_SUCCESS
) {
976 FILE *f
= fopen(path
, "rb");
978 PrintAndLogEx(WARNING
, "file not found or locked `" _YELLOW_("%s") "`", 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
);
990 PrintAndLogEx(FAILED
, "error, when getting filesize");
995 *pdata
= calloc(fsize
, sizeof(uint8_t));
997 PrintAndLogEx(FAILED
, "error, cannot allocate memory");
1002 size_t bytes_read
= fread(*pdata
, 1, fsize
, f
);
1006 if (bytes_read
!= fsize
) {
1007 PrintAndLogEx(FAILED
, "error, bytes read mismatch file size");
1012 *datalen
= bytes_read
;
1015 PrintAndLogEx(SUCCESS
, "Loaded " _YELLOW_("%zu") " bytes from binary file `" _YELLOW_("%s") "`", bytes_read
, preferredName
);
1020 int loadFileEML_safe(const char *preferredName
, void **pdata
, size_t *datalen
) {
1022 int res
= searchFile(&path
, RESOURCES_SUBDIR
, preferredName
, "", false);
1023 if (res
!= PM3_SUCCESS
) {
1027 FILE *f
= fopen(path
, "r");
1029 PrintAndLogEx(WARNING
, "file not found or locked `" _YELLOW_("%s") "`", 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
);
1041 PrintAndLogEx(FAILED
, "error, when getting filesize");
1046 *pdata
= calloc(fsize
, sizeof(uint8_t));
1048 PrintAndLogEx(FAILED
, "error, cannot allocate memory");
1053 // 128 + 2 newline chars + 1 null terminator
1055 memset(line
, 0, sizeof(line
));
1056 uint8_t buf
[64] = {0x00};
1058 int retval
= PM3_SUCCESS
, hexlen
= 0;
1060 uint8_t *tmp
= (uint8_t *)*pdata
;
1064 memset(line
, 0, sizeof(line
));
1066 if (fgets(line
, sizeof(line
), f
) == NULL
) {
1071 PrintAndLogEx(FAILED
, "file reading error");
1078 str_cleanrn(line
, sizeof(line
));
1080 res
= param_gethex_to_eol(line
, 0, buf
, sizeof(buf
), &hexlen
);
1082 memcpy(tmp
+ counter
, buf
, hexlen
);
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
) {
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
;
1111 int retval
= PM3_SUCCESS
;
1114 int res
= searchFile(&path
, RESOURCES_SUBDIR
, preferredName
, "", false);
1115 if (res
!= PM3_SUCCESS
) {
1119 FILE *f
= fopen(path
, "r");
1121 PrintAndLogEx(WARNING
, "file not found or locked `" _YELLOW_("%s") "`", 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
;
1133 uint32_t counter
= 0;
1137 memset(line
, 0, sizeof(line
));
1139 if (fgets(line
, sizeof(line
), f
) == NULL
) {
1144 PrintAndLogEx(FAILED
, "file reading error");
1151 str_cleanrn(line
, sizeof(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);
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);
1168 if (str_startswith(line
, "sak:")) {
1169 if (ft
== NFC_DF_MFC
) {
1171 sscanf(line
, "sak: %d", &sak
);
1172 // udata.mfc->card_info.sak = sak & 0xFF;
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
);
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
);
1193 if (str_startswith(line
, "counter 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;
1205 if (str_startswith(line
, "tearing 0:")) {
1206 if (ft
== NFC_DF_MFC
) {
1207 } else if (ft
== NFC_DF_MFU
) {
1209 sscanf(line
, "tearing 0: %02x", &b
);
1210 udata
.mfu
->counter_tearing
[0][3] = b
& 0xFF;
1215 if (str_startswith(line
, "counter 1:")) {
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;
1227 if (str_startswith(line
, "tearing 1:")) {
1228 if (ft
== NFC_DF_MFC
) {
1229 } else if (ft
== NFC_DF_MFU
) {
1231 sscanf(line
, "tearing 1: %02x", &b
);
1232 udata
.mfu
->counter_tearing
[1][3] = b
& 0xFF;
1237 if (str_startswith(line
, "counter 2:")) {
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;
1249 if (str_startswith(line
, "tearing 2:")) {
1250 if (ft
== NFC_DF_MFC
) {
1251 } else if (ft
== NFC_DF_MFU
) {
1253 sscanf(line
, "tearing 2: %02x", &b
);
1254 udata
.mfu
->counter_tearing
[2][3] = b
& 0xFF;
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
;
1268 // Page 0: 04 10 56 CA
1269 if (str_startswith(line
, "page ")) {
1271 sscanf(line
, "page %d:", &pageno
);
1273 if (strcmp(line
, "??") == 0) {
1274 PrintAndLogEx(INFO
, "missing data detected in page %i, skipping...", pageno
);
1278 if (((pageno
* MFU_BLOCK_SIZE
) + MFU_BLOCK_SIZE
) > maxdatalen
) {
1283 while (*p
++ != ':') {};
1286 if (ft
== NFC_DF_MFU
) {
1288 param_gethex_to_eol(p
, 0, udata
.mfu
->data
+ (pageno
* MFU_BLOCK_SIZE
), MFU_BLOCK_SIZE
, &n
);
1289 *datalen
+= MFU_BLOCK_SIZE
;
1294 // Block 0: 11 22 33 44 55 66 77 88 99 AA BB CC DD EE FF
1295 if (str_startswith(line
, "block ")) {
1297 sscanf(line
, "block %d:", &blockno
);
1299 if (strcmp(line
, "??") == 0) {
1300 PrintAndLogEx(INFO
, "missing data detected in block %i, skipping...", blockno
);
1304 if (((blockno
* MFBLOCK_SIZE
) + MFBLOCK_SIZE
) > maxdatalen
) {
1309 while (*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
;
1327 // add header length
1328 if (ft
== NFC_DF_MFC
|| ft
== NFC_DF_PICOPASS
) {
1330 } else if (ft
== NFC_DF_MFU
) {
1331 *datalen
+= MFU_DUMP_PREFIX_LENGTH
;
1335 PrintAndLogEx(SUCCESS
, "Loaded " _YELLOW_("%zu") " bytes from NFC file `" _YELLOW_("%s") "`", *datalen
, preferredName
);
1339 int loadFileMCT_safe(const char *preferredName
, void **pdata
, size_t *datalen
) {
1341 int res
= searchFile(&path
, RESOURCES_SUBDIR
, preferredName
, "", false);
1342 if (res
!= PM3_SUCCESS
) {
1346 FILE *f
= fopen(path
, "r");
1348 PrintAndLogEx(WARNING
, "file not found or locked `" _YELLOW_("%s") "`", 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
);
1360 PrintAndLogEx(FAILED
, "error, when getting filesize");
1365 *pdata
= calloc(fsize
, sizeof(uint8_t));
1367 PrintAndLogEx(FAILED
, "error, cannot allocate memory");
1372 // 128 + 2 newline chars + 1 null terminator
1374 memset(line
, 0, sizeof(line
));
1375 uint8_t buf
[64] = {0x00};
1377 int retval
= PM3_SUCCESS
, hexlen
= 0;
1379 uint8_t *tmp
= (uint8_t *)*pdata
;
1383 memset(line
, 0, sizeof(line
));
1385 if (fgets(line
, sizeof(line
), f
) == NULL
) {
1390 PrintAndLogEx(FAILED
, "file reading error");
1394 // skip lines like "+Sector:"
1398 str_cleanrn(line
, sizeof(line
));
1400 res
= param_gethex_to_eol(line
, 0, buf
, sizeof(buf
), &hexlen
);
1402 memcpy(tmp
+ counter
, buf
, hexlen
);
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
) {
1426 static int load_file_sanity(char *s
, uint32_t datalen
, int i
, size_t len
) {
1428 PrintAndLogEx(DEBUG
, "WARNING: json %s block %d has zero-length data", s
, i
);
1429 PrintAndLogEx(DEBUG
, "File parsing stopped");
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
);
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
;
1446 int retval
= PM3_SUCCESS
;
1449 int res
= searchFile(&path
, RESOURCES_SUBDIR
, preferredName
, ".json", false);
1450 if (res
!= PM3_SUCCESS
) {
1455 json_t
*root
= json_load_file(path
, 0, &error
);
1457 PrintAndLogEx(SUCCESS
, "loaded `" _YELLOW_("%s") "`", path
);
1463 PrintAndLogEx(ERR
, "error, json " _YELLOW_("%s") " error on line %d: %s", preferredName
, error
.line
, error
.text
);
1468 if (!json_is_object(root
)) {
1469 PrintAndLogEx(ERR
, "error, invalid json " _YELLOW_("%s") " format. root must be an object.", preferredName
);
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")) {
1482 udata_t udata
= (udata_t
)data
;
1485 char blocks
[PATH_MAX_LENGTH
] = {0};
1487 if (!strcmp(ctype
, "raw")) {
1488 JsonLoadBufAsHex(root
, "$.raw", udata
.bytes
, maxdatalen
, datalen
);
1492 // depricated mfcard
1493 if (!strcmp(ctype
, "mfcard") || !strcmp(ctype
, "mfc v2")) {
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
;
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) {
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
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
;
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
;
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) {
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
1553 if (!strcmp(ctype
, "fudan")) {
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
;
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) {
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
;
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
;
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) {
1607 // remove one, since pages indicates a index rather than number of available pages
1614 if (!strcmp(ctype
, "hitag")) {
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
;
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) {
1636 if (!strcmp(ctype
, "iclass")) {
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
;
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) {
1657 if (!strcmp(ctype
, "t55x7")) {
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
;
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) {
1678 if (!strcmp(ctype
, "EM4205/EM4305")) {
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
;
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) {
1699 if (!strcmp(ctype
, "EM4469/EM4569")) {
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
;
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) {
1720 if (!strcmp(ctype
, "EM4X50")) {
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
;
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) {
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
;
1747 tag
->bytesPerPage
= 4;
1748 JsonLoadBufAsHex(root
, "$.raw", tag
->data
1749 , MIN(maxdatalen
, ISO15693_TAG_MAX_SIZE
)
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
1760 retval
= PM3_EMALLOC
;
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
1771 retval
= PM3_EMALLOC
;
1774 *datalen
= sizeof(iso15_tag_t
);
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
;
1784 tag
->bytesPerPage
= 4;
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"
1798 retval
= PM3_EMALLOC
;
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) {
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
1818 retval
= PM3_EMALLOC
;
1822 *datalen
= sizeof(iso15_tag_t
);
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
;
1831 tag
->bytesPerPage
= 8;
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"
1845 retval
= PM3_EMALLOC
;
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) {
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
1865 retval
= PM3_EMALLOC
;
1869 *datalen
= sizeof(iso15_tag_t
);
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"
1893 retval
= PM3_EMALLOC
;
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
);
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"
1916 retval
= PM3_EMALLOC
;
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) {
1928 *datalen
= sizeof(iso15_tag_t
);
1932 if (!strcmp(ctype
, "legic v2")) {
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
;
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) {
1954 if (!strcmp(ctype
, "legic")) {
1955 JsonLoadBufAsHex(root
, "$.raw", udata
.bytes
, maxdatalen
, datalen
);
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
);
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
;
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) {
1981 // ICEMAN todo: add dynamic memory.
1983 // uint8_t *dynamic_memory;
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];
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
);
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
);
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];
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));
2064 if (!strcmp(ctype
, "14b v2")) {
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
;
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) {
2085 if (!strcmp(ctype
, "lto")) {
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
;
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) {
2106 if (!strcmp(ctype
, "cryptorf")) {
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
;
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) {
2127 if (!strcmp(ctype
, "ndef")) {
2130 // when we will read and return extra values from NDEF json
2131 json_error_t up_error = {0};
2133 size_t ndefsize = 0;
2134 if (json_unpack_ex(root, &up_error, 0, "{s:i}", "Ndef.Size", &i1) == 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
;
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) {
2161 if (callback
!= NULL
) {
2169 int loadFileJSONroot(const char *preferredName
, void **proot
, bool verbose
) {
2171 int res
= searchFile(&path
, RESOURCES_SUBDIR
, preferredName
, ".json", false);
2172 if (res
!= PM3_SUCCESS
) {
2177 json_t
*root
= json_load_file(path
, 0, &error
);
2179 PrintAndLogEx(SUCCESS
, "Loaded " _YELLOW_("%s"), path
);
2184 int retval
= PM3_SUCCESS
;
2186 PrintAndLogEx(ERR
, "ERROR: json " _YELLOW_("%s") " error on line %d: %s", preferredName
, error
.line
, error
.text
);
2190 if (json_is_object(root
) == false) {
2191 PrintAndLogEx(ERR
, "ERROR: Invalid json " _YELLOW_("%s") " format. root must be an object.", preferredName
);
2195 if (retval
== PM3_ESOFT
)
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
) {
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) {
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
) {
2225 if (endFilePosition
) {
2226 *endFilePosition
= 0;
2230 if (searchFile(&path
, DICTIONARIES_SUBDIR
, preferredName
, ".dic", false) != PM3_SUCCESS
) {
2234 // double up since its chars
2238 uint32_t vkeycnt
= 0;
2240 int retval
= PM3_SUCCESS
;
2242 FILE *f
= fopen(path
, "r");
2244 PrintAndLogEx(WARNING
, "file not found or locked `" _YELLOW_("%s") "`", path
);
2249 if (startFilePosition
) {
2250 if (fseek(f
, startFilePosition
, SEEK_SET
) < 0) {
2257 uint8_t *udata
= (uint8_t *)data
;
2261 long filepos
= ftell(f
);
2263 if (!fgets(line
, sizeof(line
), f
)) {
2264 if (endFilePosition
) {
2265 *endFilePosition
= 0;
2270 // add null terminator
2273 // smaller keys than expected is skipped
2274 if (strlen(line
) < keylen
) {
2278 // The line start with # is comment, skip
2279 if (line
[0] == '#') {
2283 if (!CheckStringIsHEXValue(line
)) {
2287 // cant store more data
2288 if (maxdatalen
&& (counter
+ (keylen
>> 1) > maxdatalen
)) {
2290 if (endFilePosition
) {
2291 *endFilePosition
= filepos
;
2296 if (hex_to_bytes(line
, udata
+ counter
, keylen
>> 1) != (keylen
>> 1)) {
2301 memset(line
, 0, sizeof(line
));
2302 counter
+= (keylen
>> 1);
2308 PrintAndLogEx(SUCCESS
, "Loaded " _GREEN_("%2d") " keys from dictionary file `" _YELLOW_("%s") "`", vkeycnt
, path
);
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
;
2333 if (searchFile(&path
, DICTIONARIES_SUBDIR
, preferredName
, suffix
, false) != PM3_SUCCESS
) {
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) {
2348 size_t block_size
= 10 * keylen
;
2350 // double up since its chars
2355 // allocate some space for the dictionary
2356 *pdata
= calloc(block_size
, sizeof(uint8_t));
2357 if (*pdata
== NULL
) {
2361 mem_size
= block_size
;
2363 FILE *f
= fopen(path
, "r");
2365 PrintAndLogEx(WARNING
, "file not found or locked `" _YELLOW_("%s") "`", path
);
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
) {
2384 memset((uint8_t *)*pdata
+ (mem_size
- block_size
), 0, block_size
);
2388 // The line start with # is comment, skip
2389 if (line
[0] == '#') {
2393 // remove newline/linefeed
2394 str_cleanrn(line
, strlen(line
));
2396 // smaller keys than expected is skipped
2397 if (strlen(line
) < keylen
) {
2401 // larger keys than expected is skipped
2402 if (strlen(line
) > keylen
) {
2406 if (CheckStringIsHEXValue(line
) == false) {
2412 (uint8_t *)*pdata
+ (*keycnt
* (keylen
>> 1)),
2413 keylen
>> 1) != (keylen
>> 1)) {
2419 memset(line
, 0, sizeof(line
));
2424 PrintAndLogEx(SUCCESS
, "Loaded " _GREEN_("%2d") " keys from dictionary file `" _YELLOW_("%s") "`", *keycnt
, path
);
2432 int loadFileBinaryKey(const char *preferredName
, const char *suffix
, void **keya
, void **keyb
, size_t *alen
, size_t *blen
) {
2435 int res
= searchFile(&path
, RESOURCES_SUBDIR
, preferredName
, suffix
, false);
2436 if (res
!= PM3_SUCCESS
) {
2440 FILE *f
= fopen(path
, "rb");
2442 PrintAndLogEx(WARNING
, "file not found or locked `" _YELLOW_("%s") "`", path
);
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
);
2453 PrintAndLogEx(FAILED
, "error, when getting filesize");
2459 // Half is KEY A, half is KEY B
2462 *keya
= calloc(fsize
, sizeof(uint8_t));
2463 if (*keya
== NULL
) {
2464 PrintAndLogEx(FAILED
, "error, cannot allocate memory");
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");
2481 *blen
= fread(*keyb
, 1, fsize
, f
);
2484 PrintAndLogEx(SUCCESS
, "Loaded binary key file `" _YELLOW_("%s") "`", path
);
2489 mfu_df_e
detect_mfu_dump_format(uint8_t **dump
, bool verbose
) {
2491 mfu_df_e retval
= MFU_DF_UNKNOWN
;
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
;
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
;
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
;
2532 PrintAndLogEx(INFO
, "Detected " _GREEN_("new") " mfu dump format");
2535 PrintAndLogEx(INFO
, "Detected " _GREEN_("old") " mfu dump format");
2537 case MFU_DF_PLAINBIN
:
2538 PrintAndLogEx(INFO
, "Detected " _GREEN_("plain") " mfu dump format");
2540 case MFU_DF_UNKNOWN
:
2541 PrintAndLogEx(WARNING
, "Failed to detected mfu dump format");
2548 int detect_nfc_dump_format(const char *preferredName
, nfc_df_e
*dump_type
, bool verbose
) {
2550 *dump_type
= NFC_DF_UNKNOWN
;
2553 int res
= searchFile(&path
, RESOURCES_SUBDIR
, preferredName
, "", false);
2554 if (res
!= PM3_SUCCESS
) {
2558 FILE *f
= fopen(path
, "r");
2560 PrintAndLogEx(WARNING
, "file not found or locked `" _YELLOW_("%s") "`", path
);
2567 memset(line
, 0, sizeof(line
));
2571 memset(line
, 0, sizeof(line
));
2573 if (fgets(line
, sizeof(line
), f
) == NULL
) {
2579 PrintAndLogEx(FAILED
, "file reading error");
2583 str_cleanrn(line
, sizeof(line
));
2586 if (str_startswith(line
, "device type: ntag")) {
2587 *dump_type
= NFC_DF_MFU
;
2590 if (str_startswith(line
, "device type: mifare classic")) {
2591 *dump_type
= NFC_DF_MFC
;
2594 if (str_startswith(line
, "device type: mifare desfire")) {
2595 *dump_type
= NFC_DF_MFDES
;
2598 if (str_startswith(line
, "device type: iso14443-3a")) {
2599 *dump_type
= NFC_DF_14_3A
;
2602 if (str_startswith(line
, "device type: iso14443-3b")) {
2603 *dump_type
= NFC_DF_14_3B
;
2606 if (str_startswith(line
, "device type: iso14443-4a")) {
2607 *dump_type
= NFC_DF_14_4A
;
2610 if (str_startswith(line
, "filetype: flipper picopass device")) {
2611 *dump_type
= NFC_DF_PICOPASS
;
2619 switch (*dump_type
) {
2621 PrintAndLogEx(INFO
, "Detected MIFARE Ultralight / NTAG based dump format");
2624 PrintAndLogEx(INFO
, "Detected MIFARE Classic based dump format");
2627 PrintAndLogEx(INFO
, "Detected MIFARE DESFire based dump format");
2630 PrintAndLogEx(INFO
, "Detected ISO14443-3A based dump format. No data available");
2633 PrintAndLogEx(INFO
, "Detected ISO14443-3B based dump format. No data available");
2636 PrintAndLogEx(INFO
, "Detected ISO14443-4A based dump format. No data available");
2638 case NFC_DF_PICOPASS
:
2639 PrintAndLogEx(INFO
, "Detected PICOPASS based dump format");
2641 case NFC_DF_UNKNOWN
:
2642 PrintAndLogEx(WARNING
, "Failed to detected dump format");
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));
2656 memcpy(mfu
->data
, *dump
, *dumplen
);
2658 mfu
->pages
= *dumplen
/ 4 - 1;
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
;
2669 static int convert_old_mfu_dump(uint8_t **dump
, size_t *dumplen
, bool verbose
) {
2677 uint8_t signature[32];
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
) {
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);
2710 PrintAndLogEx(SUCCESS
, "Old mfu dump format was converted to " _GREEN_("%d") " blocks", mfu_dump
->pages
+ 1);
2714 *dump
= (uint8_t *)mfu_dump
;
2715 *dumplen
= new_dump_len
;
2719 int convert_mfu_dump_format(uint8_t **dump
, size_t *dumplen
, bool verbose
) {
2721 if (!dump
|| !dumplen
|| *dumplen
< OLD_MFU_DUMP_PREFIX_LENGTH
) {
2725 mfu_df_e res
= detect_mfu_dump_format(dump
, verbose
);
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
:
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
;
2744 n
= scandir(path
, &namelist
, NULL
, alphasort
);
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
]);
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
)) {
2773 if (strcmp(namelist
[i
]->d_name
, ".") == 0 || strcmp(namelist
[i
]->d_name
, "..") == 0)
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
));
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
);
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);
2827 static int searchFinalFile(char **foundpath
, const char *pm3dir
, const char *searchname
, bool silent
) {
2829 if ((foundpath
== NULL
) || (pm3dir
== NULL
) || (searchname
== NULL
)) {
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
) {
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
);
2855 if (((strlen(filename
) > 1) && (filename
[0] == '/')) ||
2856 ((strlen(filename
) > 2) && (filename
[0] == '.') && (filename
[1] == '/'))) {
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
) {
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
)) {
2878 *foundpath
= default_path
;
2879 if ((g_debugMode
== 2) && (!silent
)) {
2880 PrintAndLogEx(INFO
, "Found %s", *foundpath
);
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));
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
)) {
2909 if ((g_debugMode
== 2) && (!silent
)) {
2910 PrintAndLogEx(INFO
, "Found %s", *foundpath
);
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));
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
)) {
2944 if ((g_debugMode
== 2) && (!silent
)) {
2945 PrintAndLogEx(INFO
, "Found %s", *foundpath
);
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));
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
)) {
2977 if ((g_debugMode
== 2) && (!silent
)) {
2978 PrintAndLogEx(INFO
, "Found %s", *foundpath
);
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));
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
)) {
3006 if ((g_debugMode
== 2) && (!silent
)) {
3007 PrintAndLogEx(INFO
, "Found %s", *foundpath
);
3019 int searchFile(char **foundpath
, const char *pm3dir
, const char *searchname
, const char *suffix
, bool silent
) {
3021 if (foundpath
== NULL
)
3024 if (searchname
== NULL
|| strlen(searchname
) == 0)
3027 if (is_directory(searchname
))
3030 char *filename
= filenamemcopy(searchname
, suffix
);
3031 if (filename
== NULL
)
3034 if (strlen(filename
) == 0) {
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
);
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
);
3055 res
= loadFile_safe(fn
, ".bin", pdump
, dumplen
);
3056 if (res
== PM3_SUCCESS
&& *dumplen
> maxdumplen
) {
3057 *dumplen
= maxdumplen
;
3062 res
= loadFileEML_safe(fn
, pdump
, dumplen
);
3063 if (res
== PM3_SUCCESS
&& *dumplen
> maxdumplen
) {
3064 *dumplen
= maxdumplen
;
3069 *pdump
= calloc(maxdumplen
, sizeof(uint8_t));
3070 if (*pdump
== NULL
) {
3071 PrintAndLogEx(WARNING
, "fail, cannot allocate memory");
3074 res
= loadFileJSON(fn
, *pdump
, maxdumplen
, dumplen
, NULL
);
3075 if (res
== PM3_SUCCESS
) {
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");
3089 PrintAndLogEx(ERR
, "Only <BIN|EML|JSON|MCT|NFC formats allowed");
3093 res
= loadFileMCT_safe(fn
, pdump
, dumplen
);
3094 if (res
== PM3_SUCCESS
&& *dumplen
> maxdumplen
) {
3095 *dumplen
= maxdumplen
;
3101 res
= detect_nfc_dump_format(fn
, &dumptype
, true);
3102 if (res
!= PM3_SUCCESS
) {
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");
3113 res
= loadFileNFC_safe(fn
, *pdump
, maxdumplen
, dumplen
, dumptype
);
3114 if (res
== PM3_SUCCESS
) {
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");
3126 // unknown dump file type
3135 int pm3_save_dump(const char *fn
, uint8_t *d
, size_t n
, JSONFileType jsft
) {
3136 if (fn
== NULL
|| strlen(fn
) == 0) {
3139 if (d
== NULL
|| n
== 0) {
3140 PrintAndLogEx(INFO
, "No data to save, skipping...");
3143 saveFile(fn
, ".bin", d
, n
);
3144 saveFileJSON(fn
, jsft
, d
, n
, NULL
);
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...");
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
));
3173 PrintAndLogEx(WARNING
, "Invalid dump. UID/SAK/ATQA not found");
3177 saveFileJSON(fn
, jsfMfc_v2
, (uint8_t *)&jd
, sizeof(jd
), NULL
);
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...");
3189 saveFileJSON(fn
, jsfFM11RF08SNoncesWithData
, (uint8_t *)d
, sizeof(*d
), NULL
);
3191 saveFileJSON(fn
, jsfFM11RF08SNonces
, (uint8_t *)d
, sizeof(*d
), NULL
);