textual
[RRG-proxmark3.git] / client / src / fileutils.c
blob415a0bb3c9aaef0f61cb0e4b73959689aad6a291
1 /*****************************************************************************
2 * WARNING
4 * THIS CODE IS CREATED FOR EXPERIMENTATION AND EDUCATIONAL USE ONLY.
6 * USAGE OF THIS CODE IN OTHER WAYS MAY INFRINGE UPON THE INTELLECTUAL
7 * PROPERTY OF OTHER PARTIES, SUCH AS INSIDE SECURE AND HID GLOBAL,
8 * AND MAY EXPOSE YOU TO AN INFRINGEMENT ACTION FROM THOSE PARTIES.
10 * THIS CODE SHOULD NEVER BE USED TO INFRINGE PATENTS OR INTELLECTUAL PROPERTY RIGHTS.
12 *****************************************************************************
14 * This file is part of loclass. It is a reconstructon of the cipher engine
15 * used in iClass, and RFID techology.
17 * The implementation is based on the work performed by
18 * Flavio D. Garcia, Gerhard de Koning Gans, Roel Verdult and
19 * Milosch Meriac in the paper "Dismantling IClass".
21 * Copyright (C) 2014 Martin Holst Swende
23 * This is free software: you can redistribute it and/or modify
24 * it under the terms of the GNU General Public License version 2 as published
25 * by the Free Software Foundation, or, at your option, any later version.
27 * This file is distributed in the hope that it will be useful,
28 * but WITHOUT ANY WARRANTY; without even the implied warranty of
29 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
30 * GNU General Public License for more details.
32 * You should have received a copy of the GNU General Public License
33 * along with loclass. If not, see <http://www.gnu.org/licenses/>.
36 ****************************************************************************/
38 // this define is needed for scandir/alphasort to work
39 #define _GNU_SOURCE
40 #include "fileutils.h"
41 #include "preferences.h"
43 #include <dirent.h>
44 #include <ctype.h>
46 #include "pm3_cmd.h"
47 #include "commonutil.h"
48 #include "proxmark3.h"
49 #include "util.h"
50 #include "cmdhficlass.h" // pagemap
51 #include "protocols.h" // iclass defines
53 #ifdef _WIN32
54 #include "scandir.h"
55 #include <direct.h>
56 #endif
58 #define PATH_MAX_LENGTH 200
60 struct wave_info_t {
61 char signature[4];
62 uint32_t filesize;
63 char type[4];
64 struct {
65 char tag[4];
66 uint32_t size;
67 uint16_t codec;
68 uint16_t nb_channel;
69 uint32_t sample_per_sec;
70 uint32_t byte_per_sec;
71 uint16_t block_align;
72 uint16_t bit_per_sample;
73 } PACKED format;
74 struct {
75 char tag[4];
76 uint32_t size;
77 } PACKED audio_data;
78 } PACKED;
80 /**
81 * @brief detects if file is of a supported filetype based on extension
82 * @param filename
83 * @return o
85 DumpFileType_t getfiletype(const char *filename) {
86 // assume unknown file is BINARY
87 DumpFileType_t o = BIN;
88 if (filename == NULL) {
89 return o;
92 size_t len = strlen(filename);
93 if (len > 4) {
94 // check if valid file extension and attempt to load data
95 char s[FILE_PATH_SIZE];
96 memset(s, 0, sizeof(s));
97 memcpy(s, filename, len);
98 str_lower(s);
100 if (str_endswith(s, "bin")) {
101 o = BIN;
102 } else if (str_endswith(s, "eml")) {
103 o = EML;
104 } else if (str_endswith(s, "json")) {
105 o = JSON;
106 } else if (str_endswith(s, "dic")) {
107 o = DICTIONARY;
108 } else {
109 // mfd, trc, trace is binary
110 o = BIN;
111 // log is text
112 // .pm3 is text values of signal data
115 return o;
119 * @brief checks if a file exists
120 * @param filename
121 * @return
123 int fileExists(const char *filename) {
125 #ifdef _WIN32
126 struct _stat st;
127 int result = _stat(filename, &st);
128 #else
129 struct stat st;
130 int result = stat(filename, &st);
131 #endif
132 return result == 0;
136 * @brief checks if path is file.
137 * @param filename
138 * @return
141 static bool is_regular_file(const char *filename) {
142 #ifdef _WIN32
143 struct _stat st;
144 if (_stat(filename, &st) == -1)
145 return false;
146 #else
147 struct stat st;
148 // stat(filename, &st);
149 if (lstat(filename, &st) == -1)
150 return false;
151 #endif
152 return S_ISREG(st.st_mode) != 0;
157 * @brief checks if path is directory.
158 * @param filename
159 * @return
161 static bool is_directory(const char *filename) {
162 #ifdef _WIN32
163 struct _stat st;
164 if (_stat(filename, &st) == -1)
165 return false;
166 #else
167 struct stat st;
168 // stat(filename, &st);
169 if (lstat(filename, &st) == -1)
170 return false;
171 #endif
172 return S_ISDIR(st.st_mode) != 0;
176 * @brief create a new directory.
177 * @param dirname
178 * @return
180 // Not used...
182 #ifdef _WIN32
183 #define make_dir(a) _mkdir(a)
184 #else
185 #define make_dir(a) mkdir(a,0755) //note 0755 MUST have leading 0 for octal linux file permissions
186 #endif
187 bool create_path(const char *dirname) {
189 if (dirname == NULL) // nothing to do
190 return false;
192 if ((strlen(dirname) == 1) && (dirname[0] == '/'))
193 return true;
195 if ((strlen(dirname) == 2) && (dirname[1] == ':'))
196 return true;
198 if (fileExists(dirname) == 0) {
200 char *bs = strrchr(dirname, '\\');
201 char *fs = strrchr(dirname, '/');
203 if ((bs == NULL) && (fs != NULL)) {
204 *fs = 0x00;
205 create_path (dirname);
206 *fs = '/';
209 if ((bs != NULL) && (fs == NULL)) {
210 *bs = 0x00;
211 create_path (dirname);
212 *bs = '\\';
215 if ((bs != NULL) && (fs != NULL)) {
216 if (strlen (bs) > strlen (fs)) {
217 *fs = 0x00; // No slash
218 create_path (dirname);
219 *fs = '/';
220 } else {
221 *bs = 0x00;
222 create_path (dirname);
223 *bs = '\\';
228 if (make_dir(dirname) != 0) {
229 PrintAndLogEx(ERR, "could not create directory.... "_RED_("%s"),dirname);
230 return false;
233 return true;
237 bool setDefaultPath(savePaths_t pathIndex, const char *Path) {
239 if (pathIndex < spItemCount) {
240 if ((Path == NULL) && (session.defaultPaths[pathIndex] != NULL)) {
241 free(session.defaultPaths[pathIndex]);
242 session.defaultPaths[pathIndex] = NULL;
245 if (Path != NULL) {
246 session.defaultPaths[pathIndex] = (char *)realloc(session.defaultPaths[pathIndex], strlen(Path) + 1);
247 strcpy(session.defaultPaths[pathIndex], Path);
249 return true;
251 return false;
254 static char *filenamemcopy(const char *preferredName, const char *suffix) {
255 if (preferredName == NULL) return NULL;
256 if (suffix == NULL) return NULL;
257 char *fileName = (char *) calloc(strlen(preferredName) + strlen(suffix) + 1, sizeof(uint8_t));
258 if (fileName == NULL)
259 return NULL;
260 strcpy(fileName, preferredName);
261 if (str_endswith(fileName, suffix))
262 return fileName;
263 strcat(fileName, suffix);
264 return fileName;
267 char *newfilenamemcopy(const char *preferredName, const char *suffix) {
268 if (preferredName == NULL) return NULL;
269 if (suffix == NULL) return NULL;
271 uint16_t p_namelen = strlen(preferredName);
272 if (str_endswith(preferredName, suffix))
273 p_namelen -= strlen(suffix);
275 char *fileName = (char *) calloc(p_namelen + strlen(suffix) + 1 + 10, sizeof(uint8_t)); // 10: room for filenum to ensure new filename
276 if (fileName == NULL) {
277 return NULL;
280 int num = 1;
281 sprintf(fileName, "%.*s%s", p_namelen, preferredName, suffix);
282 while (fileExists(fileName)) {
283 sprintf(fileName, "%.*s-%d%s", p_namelen, preferredName, num, suffix);
284 num++;
286 return fileName;
289 int saveFile(const char *preferredName, const char *suffix, const void *data, size_t datalen) {
291 if (data == NULL) return PM3_EINVARG;
292 char *fileName = newfilenamemcopy(preferredName, suffix);
293 if (fileName == NULL) return PM3_EMALLOC;
295 /* We should have a valid filename now, e.g. dumpdata-3.bin */
297 /*Opening file for writing in binary mode*/
298 FILE *f = fopen(fileName, "wb");
299 if (!f) {
300 PrintAndLogEx(WARNING, "file not found or locked. '" _YELLOW_("%s")"'", fileName);
301 free(fileName);
302 return PM3_EFILE;
304 fwrite(data, 1, datalen, f);
305 fflush(f);
306 fclose(f);
307 PrintAndLogEx(SUCCESS, "saved " _YELLOW_("%zu") " bytes to binary file " _YELLOW_("%s"), datalen, fileName);
308 free(fileName);
309 return PM3_SUCCESS;
312 int saveFileEML(const char *preferredName, uint8_t *data, size_t datalen, size_t blocksize) {
314 if (data == NULL) return PM3_EINVARG;
315 char *fileName = newfilenamemcopy(preferredName, ".eml");
316 if (fileName == NULL) return PM3_EMALLOC;
318 int retval = PM3_SUCCESS;
319 int blocks = datalen / blocksize;
320 uint16_t currblock = 1;
322 /* We should have a valid filename now, e.g. dumpdata-3.bin */
324 /*Opening file for writing in text mode*/
325 FILE *f = fopen(fileName, "w+");
326 if (!f) {
327 PrintAndLogEx(WARNING, "file not found or locked. '" _YELLOW_("%s")"'", fileName);
328 retval = PM3_EFILE;
329 goto out;
332 for (size_t i = 0; i < datalen; i++) {
333 fprintf(f, "%02X", data[i]);
335 // no extra line in the end
336 if ((i + 1) % blocksize == 0 && currblock != blocks) {
337 fprintf(f, "\n");
338 currblock++;
341 // left overs
342 if (datalen % blocksize != 0) {
343 int index = blocks * blocksize;
344 for (size_t j = 0; j < datalen % blocksize; j++) {
345 fprintf(f, "%02X", data[index + j]);
348 fflush(f);
349 fclose(f);
350 PrintAndLogEx(SUCCESS, "saved " _YELLOW_("%" PRId32) " blocks to text file " _YELLOW_("%s"), blocks, fileName);
352 out:
353 free(fileName);
354 return retval;
357 int saveFileJSON(const char *preferredName, JSONFileType ftype, uint8_t *data, size_t datalen, void (*callback)(json_t *)) {
358 return saveFileJSONex(preferredName, ftype, data, datalen, true, callback);
360 int saveFileJSONex(const char *preferredName, JSONFileType ftype, uint8_t *data, size_t datalen, bool verbose, void (*callback)(json_t *)) {
362 if (data == NULL) return PM3_EINVARG;
364 char *fileName = newfilenamemcopy(preferredName, ".json");
365 if (fileName == NULL) return PM3_EMALLOC;
367 int retval = PM3_SUCCESS;
369 json_t *root = json_object();
370 JsonSaveStr(root, "Created", "proxmark3");
371 switch (ftype) {
372 case jsfRaw: {
373 JsonSaveStr(root, "FileType", "raw");
374 JsonSaveBufAsHexCompact(root, "raw", data, datalen);
375 break;
377 case jsfCardMemory: {
378 JsonSaveStr(root, "FileType", "mfcard");
379 for (size_t i = 0; i < (datalen / 16); i++) {
380 char path[PATH_MAX_LENGTH] = {0};
381 sprintf(path, "$.blocks.%zu", i);
382 JsonSaveBufAsHexCompact(root, path, &data[i * 16], 16);
384 if (i == 0) {
385 JsonSaveBufAsHexCompact(root, "$.Card.UID", &data[0], 4);
386 JsonSaveBufAsHexCompact(root, "$.Card.SAK", &data[5], 1);
387 JsonSaveBufAsHexCompact(root, "$.Card.ATQA", &data[6], 2);
390 if (mfIsSectorTrailer(i)) {
392 snprintf(path, sizeof(path), "$.SectorKeys.%d.KeyA", mfSectorNum(i));
393 JsonSaveBufAsHexCompact(root, path, &data[i * 16], 6);
395 snprintf(path, sizeof(path), "$.SectorKeys.%d.KeyB", mfSectorNum(i));
396 JsonSaveBufAsHexCompact(root, path, &data[i * 16 + 10], 6);
398 uint8_t *adata = &data[i * 16 + 6];
399 snprintf(path, sizeof(path), "$.SectorKeys.%d.AccessConditions", mfSectorNum(i));
400 JsonSaveBufAsHexCompact(root, path, &data[i * 16 + 6], 4);
402 snprintf(path, sizeof(path), "$.SectorKeys.%d.AccessConditionsText.block%zu", mfSectorNum(i), i - 3);
403 JsonSaveStr(root, path, mfGetAccessConditionsDesc(0, adata));
405 snprintf(path, sizeof(path), "$.SectorKeys.%d.AccessConditionsText.block%zu", mfSectorNum(i), i - 2);
406 JsonSaveStr(root, path, mfGetAccessConditionsDesc(1, adata));
408 snprintf(path, sizeof(path), "$.SectorKeys.%d.AccessConditionsText.block%zu", mfSectorNum(i), i - 1);
409 JsonSaveStr(root, path, mfGetAccessConditionsDesc(2, adata));
411 snprintf(path, sizeof(path), "$.SectorKeys.%d.AccessConditionsText.block%zu", mfSectorNum(i), i);
412 JsonSaveStr(root, path, mfGetAccessConditionsDesc(3, adata));
414 snprintf(path, sizeof(path), "$.SectorKeys.%d.AccessConditionsText.UserData", mfSectorNum(i));
415 JsonSaveBufAsHexCompact(root, path, &adata[3], 1);
418 break;
420 case jsfMfuMemory: {
421 JsonSaveStr(root, "FileType", "mfu");
423 mfu_dump_t *tmp = (mfu_dump_t *)data;
425 uint8_t uid[7] = {0};
426 memcpy(uid, tmp->data, 3);
427 memcpy(uid + 3, tmp->data + 4, 4);
429 char path[PATH_MAX_LENGTH] = {0};
431 JsonSaveBufAsHexCompact(root, "$.Card.UID", uid, sizeof(uid));
432 JsonSaveBufAsHexCompact(root, "$.Card.Version", tmp->version, sizeof(tmp->version));
433 JsonSaveBufAsHexCompact(root, "$.Card.TBO_0", tmp->tbo, sizeof(tmp->tbo));
434 JsonSaveBufAsHexCompact(root, "$.Card.TBO_1", tmp->tbo1, sizeof(tmp->tbo1));
435 JsonSaveBufAsHexCompact(root, "$.Card.Signature", tmp->signature, sizeof(tmp->signature));
436 for (uint8_t i = 0; i < 3; i ++) {
437 sprintf(path, "$.Card.Counter%d", i);
438 JsonSaveBufAsHexCompact(root, path, tmp->counter_tearing[i], 3);
439 sprintf(path, "$.Card.Tearing%d", i);
440 JsonSaveBufAsHexCompact(root, path, tmp->counter_tearing[i] + 3, 1);
443 // size of header 56b
444 size_t len = (datalen - MFU_DUMP_PREFIX_LENGTH) / 4;
446 for (size_t i = 0; i < len; i++) {
447 sprintf(path, "$.blocks.%zu", i);
448 JsonSaveBufAsHexCompact(root, path, tmp->data + (i * 4), 4);
450 break;
452 case jsfHitag: {
453 JsonSaveStr(root, "FileType", "hitag");
454 uint8_t uid[4] = {0};
455 memcpy(uid, data, 4);
457 JsonSaveBufAsHexCompact(root, "$.Card.UID", uid, sizeof(uid));
459 for (size_t i = 0; i < (datalen / 4); i++) {
460 char path[PATH_MAX_LENGTH] = {0};
461 sprintf(path, "$.blocks.%zu", i);
462 JsonSaveBufAsHexCompact(root, path, data + (i * 4), 4);
464 break;
466 case jsfIclass: {
467 JsonSaveStr(root, "FileType", "iclass");
469 picopass_hdr_t *hdr = (picopass_hdr_t *)data;
470 JsonSaveBufAsHexCompact(root, "$.Card.CSN", hdr->csn, sizeof(hdr->csn));
471 JsonSaveBufAsHexCompact(root, "$.Card.Configuration", (uint8_t *)&hdr->conf, sizeof(hdr->conf));
473 uint8_t pagemap = get_pagemap(hdr);
474 if (pagemap == PICOPASS_NON_SECURE_PAGEMODE) {
475 picopass_ns_hdr_t *ns_hdr = (picopass_ns_hdr_t *)data;
476 JsonSaveBufAsHexCompact(root, "$.Card.AIA", ns_hdr->app_issuer_area, sizeof(ns_hdr->app_issuer_area));
477 } else {
478 JsonSaveBufAsHexCompact(root, "$.Card.Epurse", hdr->epurse, sizeof(hdr->epurse));
479 JsonSaveBufAsHexCompact(root, "$.Card.Kd", hdr->key_d, sizeof(hdr->key_d));
480 JsonSaveBufAsHexCompact(root, "$.Card.Kc", hdr->key_c, sizeof(hdr->key_c));
481 JsonSaveBufAsHexCompact(root, "$.Card.AIA", hdr->app_issuer_area, sizeof(hdr->app_issuer_area));
484 for (size_t i = 0; i < (datalen / 8); i++) {
485 char path[PATH_MAX_LENGTH] = {0};
486 sprintf(path, "$.blocks.%zu", i);
487 JsonSaveBufAsHexCompact(root, path, data + (i * 8), 8);
490 break;
492 case jsfT55x7: {
493 JsonSaveStr(root, "FileType", "t55x7");
494 uint8_t conf[4] = {0};
495 memcpy(conf, data, 4);
496 JsonSaveBufAsHexCompact(root, "$.Card.ConfigBlock", conf, sizeof(conf));
498 for (size_t i = 0; i < (datalen / 4); i++) {
499 char path[PATH_MAX_LENGTH] = {0};
500 sprintf(path, "$.blocks.%zu", i);
501 JsonSaveBufAsHexCompact(root, path, data + (i * 4), 4);
503 break;
505 case jsf14b: {
506 JsonSaveStr(root, "FileType", "14b");
507 JsonSaveBufAsHexCompact(root, "raw", data, datalen);
508 break;
510 case jsf15: {
511 JsonSaveStr(root, "FileType", "15693");
512 JsonSaveBufAsHexCompact(root, "raw", data, datalen);
513 break;
515 case jsfLegic: {
516 JsonSaveStr(root, "FileType", "legic");
517 JsonSaveBufAsHexCompact(root, "raw", data, datalen);
518 break;
520 case jsfT5555: {
521 JsonSaveStr(root, "FileType", "t5555");
522 uint8_t conf[4] = {0};
523 memcpy(conf, data, 4);
524 JsonSaveBufAsHexCompact(root, "$.Card.ConfigBlock", conf, sizeof(conf));
526 for (size_t i = 0; i < (datalen / 4); i++) {
527 char path[PATH_MAX_LENGTH] = {0};
528 sprintf(path, "$.blocks.%zu", i);
529 JsonSaveBufAsHexCompact(root, path, data + (i * 4), 4);
531 break;
533 case jsfEM4x05: {
534 JsonSaveStr(root, "FileType", "EM4205/EM4305");
535 JsonSaveBufAsHexCompact(root, "$.Card.UID", data + (1 * 4), 4);
536 JsonSaveBufAsHexCompact(root, "$.Card.Config", data + (4 * 4), 4);
537 JsonSaveBufAsHexCompact(root, "$.Card.Protection1", data + (14 * 4), 4);
538 JsonSaveBufAsHexCompact(root, "$.Card.Protection2", data + (15 * 4), 4);
540 for (size_t i = 0; i < (datalen / 4); i++) {
541 char path[PATH_MAX_LENGTH] = {0};
542 sprintf(path, "$.blocks.%zu", i);
543 JsonSaveBufAsHexCompact(root, path, data + (i * 4), 4);
545 break;
547 case jsfEM4x69: {
548 JsonSaveStr(root, "FileType", "EM4469/EM4569");
549 JsonSaveBufAsHexCompact(root, "$.Card.UID", data + (1 * 4), 4);
550 JsonSaveBufAsHexCompact(root, "$.Card.Protection", data + (3 * 4), 4);
551 JsonSaveBufAsHexCompact(root, "$.Card.Config", data + (4 * 4), 4);
553 for (size_t i = 0; i < (datalen / 4); i++) {
554 char path[PATH_MAX_LENGTH] = {0};
555 sprintf(path, "$.blocks.%zu", i);
556 JsonSaveBufAsHexCompact(root, path, data + (i * 4), 4);
558 break;
560 case jsfEM4x50: {
561 JsonSaveStr(root, "FileType", "EM4X50");
562 JsonSaveBufAsHexCompact(root, "$.Card.Protection", data + (1 * 4), 4);
563 JsonSaveBufAsHexCompact(root, "$.Card.Config", data + (2 * 4), 4);
564 JsonSaveBufAsHexCompact(root, "$.Card.Serial", data + (32 * 4), 4);
565 JsonSaveBufAsHexCompact(root, "$.Card.UID", data + (33 * 4), 4);
567 for (size_t i = 0; i < (datalen / 4); i++) {
568 char path[PATH_MAX_LENGTH] = {0};
569 sprintf(path, "$.blocks.%zu", i);
570 JsonSaveBufAsHexCompact(root, path, data + (i * 4), 4);
572 break;
574 case jsfMfPlusKeys: {
575 JsonSaveStr(root, "FileType", "mfp");
576 JsonSaveBufAsHexCompact(root, "$.Card.UID", &data[0], 7);
577 JsonSaveBufAsHexCompact(root, "$.Card.SAK", &data[10], 1);
578 JsonSaveBufAsHexCompact(root, "$.Card.ATQA", &data[11], 2);
579 uint8_t atslen = data[13];
580 if (atslen > 0)
581 JsonSaveBufAsHexCompact(root, "$.Card.ATS", &data[14], atslen);
583 uint8_t vdata[2][64][16 + 1] = {{{0}}};
584 memcpy(vdata, &data[14 + atslen], 2 * 64 * 17);
586 for (size_t i = 0; i < datalen; i++) {
587 char path[PATH_MAX_LENGTH] = {0};
589 if (vdata[0][i][0]) {
590 memset(path, 0x00, sizeof(path));
591 sprintf(path, "$.SectorKeys.%d.KeyA", mfSectorNum(i));
592 JsonSaveBufAsHexCompact(root, path, &vdata[0][i][1], 16);
595 if (vdata[1][i][0]) {
596 memset(path, 0x00, sizeof(path));
597 sprintf(path, "$.SectorKeys.%d.KeyB", mfSectorNum(i));
598 JsonSaveBufAsHexCompact(root, path, &vdata[1][i][1], 16);
601 break;
603 case jsfMfDesfireKeys: {
604 JsonSaveStr(root, "FileType", "mfdes");
605 JsonSaveBufAsHexCompact(root, "$.Card.UID", &data[0], 7);
606 JsonSaveBufAsHexCompact(root, "$.Card.SAK", &data[10], 1);
607 JsonSaveBufAsHexCompact(root, "$.Card.ATQA", &data[11], 2);
608 uint8_t datslen = data[13];
609 if (datslen > 0)
610 JsonSaveBufAsHexCompact(root, "$.Card.ATS", &data[14], datslen);
612 uint8_t dvdata[4][0xE][24 + 1] = {{{0}}};
613 memcpy(dvdata, &data[14 + datslen], 4 * 0xE * (24 + 1));
615 for (int i = 0; i < (int)datalen; i++) {
616 char path[PATH_MAX_LENGTH] = {0};
618 if (dvdata[0][i][0]) {
619 memset(path, 0x00, sizeof(path));
620 sprintf(path, "$.DES.%d.Key", i);
621 JsonSaveBufAsHexCompact(root, path, &dvdata[0][i][1], 8);
624 if (dvdata[1][i][0]) {
625 memset(path, 0x00, sizeof(path));
626 sprintf(path, "$.3DES.%d.Key", i);
627 JsonSaveBufAsHexCompact(root, path, &dvdata[1][i][1], 16);
629 if (dvdata[2][i][0]) {
630 memset(path, 0x00, sizeof(path));
631 sprintf(path, "$.AES.%d.Key", i);
632 JsonSaveBufAsHexCompact(root, path, &dvdata[2][i][1], 16);
634 if (dvdata[3][i][0]) {
635 memset(path, 0x00, sizeof(path));
636 sprintf(path, "$.K3KDES.%d.Key", i);
637 JsonSaveBufAsHexCompact(root, path, &dvdata[3][i][1], 24);
640 break;
642 case jsfFido: {
643 break;
645 case jsfCustom: {
646 (*callback)(root);
647 break;
649 default:
650 break;
653 int res = json_dump_file(root, fileName, JSON_INDENT(2));
654 if (res) {
655 PrintAndLogEx(FAILED, "error: can't save the file: " _YELLOW_("%s"), fileName);
656 retval = 200;
657 goto out;
660 if (verbose) {
661 PrintAndLogEx(SUCCESS, "saved to json file " _YELLOW_("%s"), fileName);
664 out:
665 json_decref(root);
666 free(fileName);
667 return retval;
669 int saveFileJSONroot(const char *preferredName, void *root, size_t flags, bool verbose) {
670 return saveFileJSONrootEx(preferredName, root, flags, verbose, false);
672 int saveFileJSONrootEx(const char *preferredName, void *root, size_t flags, bool verbose, bool overwrite) {
673 if (root == NULL)
674 return PM3_EINVARG;
676 char *filename = NULL;
677 if (overwrite)
678 filename = filenamemcopy(preferredName, ".json");
679 else
680 filename = newfilenamemcopy(preferredName, ".json");
682 if (filename == NULL)
683 return PM3_EMALLOC;
685 int res = json_dump_file(root, filename, flags);
687 if (res == 0) {
688 if (verbose) {
689 PrintAndLogEx(SUCCESS, "saved to json file " _YELLOW_("%s"), filename);
691 free(filename);
692 return PM3_SUCCESS;
693 } else {
694 PrintAndLogEx(FAILED, "error: can't save the file: " _YELLOW_("%s"), filename);
696 free(filename);
697 return PM3_EFILE;
700 int saveFileWAVE(const char *preferredName, int *data, size_t datalen) {
702 if (data == NULL) return PM3_EINVARG;
703 char *fileName = newfilenamemcopy(preferredName, ".wav");
704 if (fileName == NULL) return PM3_EMALLOC;
705 int retval = PM3_SUCCESS;
707 struct wave_info_t wave_info = {
708 .signature = "RIFF",
709 .filesize = sizeof(wave_info) - sizeof(wave_info.signature) - sizeof(wave_info.filesize) + datalen,
710 .type = "WAVE",
711 .format.tag = "fmt ",
712 .format.size = sizeof(wave_info.format) - sizeof(wave_info.format.tag) - sizeof(wave_info.format.size),
713 .format.codec = 1, // PCM
714 .format.nb_channel = 1,
715 .format.sample_per_sec = 125000, // TODO update for other tag types
716 .format.byte_per_sec = 125000, // TODO update for other tag types
717 .format.block_align = 1,
718 .format.bit_per_sample = 8,
719 .audio_data.tag = "data",
720 .audio_data.size = datalen,
723 FILE *wave_file = fopen(fileName, "wb");
724 if (!wave_file) {
725 PrintAndLogEx(WARNING, "file not found or locked. "_YELLOW_("'%s'"), fileName);
726 retval = PM3_EFILE;
727 goto out;
729 fwrite(&wave_info, sizeof(wave_info), 1, wave_file);
730 for (int i = 0; i < datalen; i++) {
731 uint8_t sample = data[i] + 128;
732 fwrite(&sample, 1, 1, wave_file);
734 fclose(wave_file);
736 PrintAndLogEx(SUCCESS, "saved " _YELLOW_("%zu") " bytes to wave file " _YELLOW_("'%s'"), 2 * datalen, fileName);
738 out:
739 free(fileName);
740 return retval;
743 int saveFilePM3(const char *preferredName, int *data, size_t datalen) {
745 if (data == NULL) return PM3_EINVARG;
746 char *fileName = newfilenamemcopy(preferredName, ".pm3");
747 if (fileName == NULL) return PM3_EMALLOC;
749 int retval = PM3_SUCCESS;
751 FILE *f = fopen(fileName, "w");
752 if (!f) {
753 PrintAndLogEx(WARNING, "file not found or locked. "_YELLOW_("'%s'"), fileName);
754 retval = PM3_EFILE;
755 goto out;
758 for (uint32_t i = 0; i < datalen; i++)
759 fprintf(f, "%d\n", data[i]);
761 fflush(f);
762 fclose(f);
763 PrintAndLogEx(SUCCESS, "saved " _YELLOW_("%zu") " bytes to PM3 file " _YELLOW_("'%s'"), datalen, fileName);
765 out:
766 free(fileName);
767 return retval;
770 int createMfcKeyDump(const char *preferredName, uint8_t sectorsCnt, sector_t *e_sector) {
772 if (e_sector == NULL) return PM3_EINVARG;
774 char *fileName = newfilenamemcopy(preferredName, ".bin");
775 if (fileName == NULL) return PM3_EMALLOC;
777 FILE *f = fopen(fileName, "wb");
778 if (f == NULL) {
779 PrintAndLogEx(WARNING, "Could not create file " _YELLOW_("%s"), fileName);
780 free(fileName);
781 return PM3_EFILE;
783 PrintAndLogEx(SUCCESS, "Generating binary key file");
785 uint8_t empty[6] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
786 uint8_t tmp[6] = {0, 0, 0, 0, 0, 0};
788 for (int i = 0; i < sectorsCnt; i++) {
789 if (e_sector[i].foundKey[0])
790 num_to_bytes(e_sector[i].Key[0], sizeof(tmp), tmp);
791 else
792 memcpy(tmp, empty, sizeof(tmp));
793 fwrite(tmp, 1, sizeof(tmp), f);
796 for (int i = 0; i < sectorsCnt; i++) {
797 if (e_sector[i].foundKey[0])
798 num_to_bytes(e_sector[i].Key[1], sizeof(tmp), tmp);
799 else
800 memcpy(tmp, empty, sizeof(tmp));
801 fwrite(tmp, 1, sizeof(tmp), f);
804 fflush(f);
805 fclose(f);
806 PrintAndLogEx(SUCCESS, "Found keys have been dumped to " _YELLOW_("%s"), fileName);
807 PrintAndLogEx(INFO, "FYI! --> " _YELLOW_("0xFFFFFFFFFFFF") " <-- has been inserted for unknown keys where " _YELLOW_("res") " is " _YELLOW_("0"));
808 free(fileName);
809 return PM3_SUCCESS;
812 int loadFile(const char *preferredName, const char *suffix, void *data, size_t maxdatalen, size_t *datalen) {
814 if (data == NULL) return 1;
815 char *fileName = filenamemcopy(preferredName, suffix);
816 if (fileName == NULL) return PM3_EINVARG;
818 int retval = PM3_SUCCESS;
820 FILE *f = fopen(fileName, "rb");
821 if (!f) {
822 PrintAndLogEx(WARNING, "file not found or locked. '" _YELLOW_("%s")"'", fileName);
823 free(fileName);
824 return PM3_EFILE;
827 // get filesize in order to malloc memory
828 fseek(f, 0, SEEK_END);
829 long fsize = ftell(f);
830 fseek(f, 0, SEEK_SET);
832 if (fsize <= 0) {
833 PrintAndLogEx(FAILED, "error, when getting filesize");
834 retval = PM3_EFILE;
835 goto out;
838 uint8_t *dump = calloc(fsize, sizeof(uint8_t));
839 if (!dump) {
840 PrintAndLogEx(FAILED, "error, cannot allocate memory");
841 retval = PM3_EMALLOC;
842 goto out;
845 size_t bytes_read = fread(dump, 1, fsize, f);
847 if (bytes_read != fsize) {
848 PrintAndLogEx(FAILED, "error, bytes read mismatch file size");
849 free(dump);
850 retval = PM3_EFILE;
851 goto out;
854 if (bytes_read > maxdatalen) {
855 PrintAndLogEx(WARNING, "Warning, bytes read exceed calling array limit. Max bytes is %zu bytes", maxdatalen);
856 bytes_read = maxdatalen;
859 memcpy((data), dump, bytes_read);
860 free(dump);
862 PrintAndLogEx(SUCCESS, "loaded " _YELLOW_("%zu") " bytes from binary file " _YELLOW_("%s"), bytes_read, fileName);
864 *datalen = bytes_read;
866 out:
867 fclose(f);
868 free(fileName);
869 return retval;
872 int loadFile_safe(const char *preferredName, const char *suffix, void **pdata, size_t *datalen) {
873 return loadFile_safeEx(preferredName, suffix, pdata, datalen, true);
875 int loadFile_safeEx(const char *preferredName, const char *suffix, void **pdata, size_t *datalen, bool verbose) {
877 char *path;
878 int res = searchFile(&path, RESOURCES_SUBDIR, preferredName, suffix, false);
879 if (res != PM3_SUCCESS) {
880 return PM3_EFILE;
883 FILE *f = fopen(path, "rb");
884 if (!f) {
885 PrintAndLogEx(WARNING, "file not found or locked. '" _YELLOW_("%s")"'", path);
886 free(path);
887 return PM3_EFILE;
889 free(path);
891 // get filesize in order to malloc memory
892 fseek(f, 0, SEEK_END);
893 long fsize = ftell(f);
894 fseek(f, 0, SEEK_SET);
896 if (fsize <= 0) {
897 PrintAndLogEx(FAILED, "error, when getting filesize");
898 fclose(f);
899 return PM3_EFILE;
902 *pdata = calloc(fsize, sizeof(uint8_t));
903 if (!*pdata) {
904 PrintAndLogEx(FAILED, "error, cannot allocate memory");
905 fclose(f);
906 return PM3_EMALLOC;
909 size_t bytes_read = fread(*pdata, 1, fsize, f);
911 fclose(f);
913 if (bytes_read != fsize) {
914 PrintAndLogEx(FAILED, "error, bytes read mismatch file size");
915 free(*pdata);
916 return PM3_EFILE;
919 *datalen = bytes_read;
921 if (verbose)
922 PrintAndLogEx(SUCCESS, "loaded " _YELLOW_("%zu") " bytes from binary file " _YELLOW_("%s"), bytes_read, preferredName);
923 return PM3_SUCCESS;
926 int loadFileEML(const char *preferredName, void *data, size_t *datalen) {
928 if (data == NULL) return PM3_EINVARG;
930 char *fileName = filenamemcopy(preferredName, ".eml");
931 if (fileName == NULL) return PM3_EMALLOC;
933 size_t counter = 0;
934 int retval = PM3_SUCCESS, hexlen = 0;
936 FILE *f = fopen(fileName, "r");
937 if (!f) {
938 PrintAndLogEx(WARNING, "file not found or locked. '" _YELLOW_("%s")"'", fileName);
939 retval = PM3_EFILE;
940 goto out;
943 // 128 + 2 newline chars + 1 null terminator
944 char line[131];
945 memset(line, 0, sizeof(line));
946 uint8_t buf[64] = {0x00};
948 uint8_t *udata = (uint8_t *)data;
950 while (!feof(f)) {
952 memset(line, 0, sizeof(line));
954 if (fgets(line, sizeof(line), f) == NULL) {
955 if (feof(f))
956 break;
958 fclose(f);
959 PrintAndLogEx(FAILED, "File reading error.");
960 retval = PM3_EFILE;
961 goto out;
964 if (line[0] == '#')
965 continue;
967 strcleanrn(line, sizeof(line));
969 int res = param_gethex_to_eol(line, 0, buf, sizeof(buf), &hexlen);
970 if (res == 0) {
971 memcpy(udata + counter, buf, hexlen);
972 counter += hexlen;
973 } else {
974 retval = PM3_ESOFT;
977 fclose(f);
978 PrintAndLogEx(SUCCESS, "loaded " _YELLOW_("%zu") " bytes from text file " _YELLOW_("%s"), counter, fileName);
980 if (datalen)
981 *datalen = counter;
983 out:
984 free(fileName);
985 return retval;
987 int loadFileEML_safe(const char *preferredName, void **pdata, size_t *datalen) {
988 char *path;
989 int res = searchFile(&path, RESOURCES_SUBDIR, preferredName, "", false);
990 if (res != PM3_SUCCESS) {
991 return PM3_EFILE;
994 FILE *f = fopen(path, "r");
995 if (!f) {
996 PrintAndLogEx(WARNING, "file not found or locked. '" _YELLOW_("%s")"'", path);
997 free(path);
998 return PM3_EFILE;
1000 free(path);
1002 // get filesize in order to malloc memory
1003 fseek(f, 0, SEEK_END);
1004 long fsize = ftell(f);
1005 fseek(f, 0, SEEK_SET);
1007 if (fsize <= 0) {
1008 PrintAndLogEx(FAILED, "error, when getting filesize");
1009 fclose(f);
1010 return PM3_EFILE;
1013 *pdata = calloc(fsize, sizeof(uint8_t));
1014 if (!*pdata) {
1015 PrintAndLogEx(FAILED, "error, cannot allocate memory");
1016 fclose(f);
1017 return PM3_EMALLOC;
1020 // 128 + 2 newline chars + 1 null terminator
1021 char line[131];
1022 memset(line, 0, sizeof(line));
1023 uint8_t buf[64] = {0x00};
1024 size_t counter = 0;
1025 int retval = PM3_SUCCESS, hexlen = 0;
1027 uint8_t *tmp = (uint8_t *)*pdata;
1029 while (!feof(f)) {
1031 memset(line, 0, sizeof(line));
1033 if (fgets(line, sizeof(line), f) == NULL) {
1034 if (feof(f))
1035 break;
1037 fclose(f);
1038 PrintAndLogEx(FAILED, "File reading error.");
1039 return PM3_EFILE;
1042 if (line[0] == '#')
1043 continue;
1045 strcleanrn(line, sizeof(line));
1047 res = param_gethex_to_eol(line, 0, buf, sizeof(buf), &hexlen);
1048 if (res == 0) {
1049 memcpy(tmp + counter, buf, hexlen);
1050 counter += hexlen;
1051 } else {
1052 retval = PM3_ESOFT;
1055 fclose(f);
1056 PrintAndLogEx(SUCCESS, "loaded " _YELLOW_("%zu") " bytes from text file " _YELLOW_("%s"), counter, preferredName);
1059 uint8_t *newdump = realloc(*pdata, counter);
1060 if (newdump == NULL) {
1061 free(*pdata);
1062 return PM3_EMALLOC;
1063 } else {
1064 *pdata = newdump;
1067 if (datalen)
1068 *datalen = counter;
1070 return retval;
1073 int loadFileJSON(const char *preferredName, void *data, size_t maxdatalen, size_t *datalen, void (*callback)(json_t *)) {
1074 return loadFileJSONex(preferredName, data, maxdatalen, datalen, true, callback);
1076 int loadFileJSONex(const char *preferredName, void *data, size_t maxdatalen, size_t *datalen, bool verbose, void (*callback)(json_t *)) {
1078 if (data == NULL) return PM3_EINVARG;
1080 *datalen = 0;
1081 int retval = PM3_SUCCESS;
1083 char *path;
1084 int res = searchFile(&path, RESOURCES_SUBDIR, preferredName, ".json", false);
1085 if (res != PM3_SUCCESS) {
1086 return PM3_EFILE;
1089 json_error_t error;
1090 json_t *root = json_load_file(path, 0, &error);
1091 if (verbose)
1092 PrintAndLogEx(SUCCESS, "loaded from JSON file " _YELLOW_("%s"), path);
1094 free(path);
1096 if (!root) {
1097 PrintAndLogEx(ERR, "ERROR: json " _YELLOW_("%s") " error on line %d: %s", preferredName, error.line, error.text);
1098 retval = PM3_ESOFT;
1099 goto out;
1102 if (!json_is_object(root)) {
1103 PrintAndLogEx(ERR, "ERROR: Invalid json " _YELLOW_("%s") " format. root must be an object.", preferredName);
1104 retval = PM3_ESOFT;
1105 goto out;
1108 uint8_t *udata = (uint8_t *)data;
1109 char ctype[100] = {0};
1110 JsonLoadStr(root, "$.FileType", ctype);
1112 if (!strcmp(ctype, "raw")) {
1113 JsonLoadBufAsHex(root, "$.raw", udata, maxdatalen, datalen);
1116 if (!strcmp(ctype, "mfcard")) {
1117 size_t sptr = 0;
1118 for (int i = 0; i < 256; i++) {
1119 if (sptr + 16 > maxdatalen) {
1120 retval = PM3_EMALLOC;
1121 goto out;
1124 char blocks[30] = {0};
1125 sprintf(blocks, "$.blocks.%d", i);
1127 size_t len = 0;
1128 JsonLoadBufAsHex(root, blocks, &udata[sptr], 16, &len);
1129 if (!len)
1130 break;
1132 sptr += len;
1135 *datalen = sptr;
1138 if (!strcmp(ctype, "mfu")) {
1139 size_t sptr = 0;
1140 for (int i = 0; i < 256; i++) {
1141 if (sptr + 4 > maxdatalen) {
1142 retval = PM3_EMALLOC;
1143 goto out;
1146 char blocks[30] = {0};
1147 sprintf(blocks, "$.blocks.%d", i);
1149 size_t len = 0;
1150 JsonLoadBufAsHex(root, blocks, &udata[sptr], 4, &len);
1151 if (!len)
1152 break;
1154 sptr += len;
1157 *datalen = sptr;
1160 if (!strcmp(ctype, "hitag")) {
1161 size_t sptr = 0;
1162 for (size_t i = 0; i < (maxdatalen / 4); i++) {
1163 if (sptr + 4 > maxdatalen) {
1164 retval = PM3_EMALLOC;
1165 goto out;
1168 char blocks[30] = {0};
1169 sprintf(blocks, "$.blocks.%zu", i);
1171 size_t len = 0;
1172 JsonLoadBufAsHex(root, blocks, &udata[sptr], 4, &len);
1173 if (!len)
1174 break;
1176 sptr += len;
1179 *datalen = sptr;
1182 if (!strcmp(ctype, "iclass")) {
1183 size_t sptr = 0;
1184 for (size_t i = 0; i < (maxdatalen / 8); i++) {
1185 if (sptr + 8 > maxdatalen) {
1186 retval = PM3_EMALLOC;
1187 goto out;
1190 char blocks[30] = {0};
1191 sprintf(blocks, "$.blocks.%zu", i);
1193 size_t len = 0;
1194 JsonLoadBufAsHex(root, blocks, &udata[sptr], 8, &len);
1195 if (!len)
1196 break;
1198 sptr += len;
1200 *datalen = sptr;
1203 if (!strcmp(ctype, "t55x7")) {
1204 size_t sptr = 0;
1205 for (size_t i = 0; i < (maxdatalen / 4); i++) {
1206 if (sptr + 4 > maxdatalen) {
1207 retval = PM3_EMALLOC;
1208 goto out;
1211 char blocks[30] = {0};
1212 sprintf(blocks, "$.blocks.%zu", i);
1214 size_t len = 0;
1215 JsonLoadBufAsHex(root, blocks, &udata[sptr], 4, &len);
1216 if (!len)
1217 break;
1219 sptr += len;
1221 *datalen = sptr;
1224 if (!strcmp(ctype, "EM4X50")) {
1225 size_t sptr = 0;
1226 for (size_t i = 0; i < (maxdatalen / 4); i++) {
1227 if (sptr + 4 > maxdatalen) {
1228 retval = PM3_EMALLOC;
1229 goto out;
1232 char blocks[30] = {0};
1233 sprintf(blocks, "$.blocks.%zu", i);
1235 size_t len = 0;
1236 JsonLoadBufAsHex(root, blocks, &udata[sptr], 4, &len);
1237 if (!len)
1238 break;
1240 sptr += len;
1242 *datalen = sptr;
1245 if (!strcmp(ctype, "15693")) {
1246 JsonLoadBufAsHex(root, "$.raw", udata, maxdatalen, datalen);
1249 out:
1251 if (callback != NULL) {
1252 (*callback)(root);
1255 json_decref(root);
1256 return retval;
1259 int loadFileJSONroot(const char *preferredName, void **proot, bool verbose) {
1260 char *path;
1261 int res = searchFile(&path, RESOURCES_SUBDIR, preferredName, ".json", false);
1262 if (res != PM3_SUCCESS) {
1263 return PM3_EFILE;
1266 json_error_t error;
1267 json_t *root = json_load_file(path, 0, &error);
1268 if (verbose)
1269 PrintAndLogEx(SUCCESS, "loaded from JSON file " _YELLOW_("%s"), path);
1271 free(path);
1273 int retval = PM3_SUCCESS;
1274 if (root == NULL) {
1275 PrintAndLogEx(ERR, "ERROR: json " _YELLOW_("%s") " error on line %d: %s", preferredName, error.line, error.text);
1276 retval = PM3_ESOFT;
1277 goto out;
1280 if (!json_is_object(root)) {
1281 PrintAndLogEx(ERR, "ERROR: Invalid json " _YELLOW_("%s") " format. root must be an object.", preferredName);
1282 retval = PM3_ESOFT;
1283 goto out;
1286 *proot = root;
1287 return PM3_SUCCESS;
1289 out:
1290 json_decref(root);
1291 return retval;
1294 int loadFileDICTIONARY(const char *preferredName, void *data, size_t *datalen, uint8_t keylen, uint32_t *keycnt) {
1295 // t5577 == 4bytes
1296 // mifare == 6 bytes
1297 // mf plus == 16 bytes
1298 // iclass == 8 bytes
1299 // default to 6 bytes.
1300 if (keylen != 4 && keylen != 6 && keylen != 8 && keylen != 16) {
1301 keylen = 6;
1304 return loadFileDICTIONARYEx(preferredName, data, 0, datalen, keylen, keycnt, 0, NULL, true);
1307 int loadFileDICTIONARYEx(const char *preferredName, void *data, size_t maxdatalen, size_t *datalen, uint8_t keylen, uint32_t *keycnt,
1308 size_t startFilePosition, size_t *endFilePosition, bool verbose) {
1310 if (data == NULL) return PM3_EINVARG;
1312 if (endFilePosition)
1313 *endFilePosition = 0;
1315 char *path;
1316 if (searchFile(&path, DICTIONARIES_SUBDIR, preferredName, ".dic", false) != PM3_SUCCESS)
1317 return PM3_EFILE;
1319 // double up since its chars
1320 keylen <<= 1;
1322 char line[255];
1323 uint32_t vkeycnt = 0;
1324 size_t counter = 0;
1325 int retval = PM3_SUCCESS;
1327 FILE *f = fopen(path, "r");
1328 if (!f) {
1329 PrintAndLogEx(WARNING, "file not found or locked. '" _YELLOW_("%s")"'", path);
1330 retval = PM3_EFILE;
1331 goto out;
1334 if (startFilePosition) {
1335 if (fseek(f, startFilePosition, SEEK_SET) < 0) {
1336 fclose(f);
1337 retval = PM3_EFILE;
1338 goto out;
1342 uint8_t *udata = (uint8_t *)data;
1344 // read file
1345 while (!feof(f)) {
1346 long filepos = ftell(f);
1348 if (!fgets(line, sizeof(line), f)) {
1349 if (endFilePosition)
1350 *endFilePosition = 0;
1351 break;
1354 // add null terminator
1355 line[keylen] = 0;
1357 // smaller keys than expected is skipped
1358 if (strlen(line) < keylen)
1359 continue;
1361 // The line start with # is comment, skip
1362 if (line[0] == '#')
1363 continue;
1365 if (!CheckStringIsHEXValue(line))
1366 continue;
1368 // cant store more data
1369 if (maxdatalen && (counter + (keylen >> 1) > maxdatalen)) {
1370 retval = 1;
1371 if (endFilePosition)
1372 *endFilePosition = filepos;
1373 break;
1376 if (hex_to_bytes(line, udata + counter, keylen >> 1) != (keylen >> 1))
1377 continue;
1379 vkeycnt++;
1380 memset(line, 0, sizeof(line));
1381 counter += (keylen >> 1);
1383 fclose(f);
1384 if (verbose)
1385 PrintAndLogEx(SUCCESS, "loaded " _GREEN_("%2d") " keys from dictionary file " _YELLOW_("%s"), vkeycnt, path);
1387 if (datalen)
1388 *datalen = counter;
1389 if (keycnt)
1390 *keycnt = vkeycnt;
1391 out:
1392 free(path);
1393 return retval;
1396 int loadFileDICTIONARY_safe(const char *preferredName, void **pdata, uint8_t keylen, uint32_t *keycnt) {
1398 int retval = PM3_SUCCESS;
1400 char *path;
1401 if (searchFile(&path, DICTIONARIES_SUBDIR, preferredName, ".dic", false) != PM3_SUCCESS)
1402 return PM3_EFILE;
1404 // t5577 == 4bytes
1405 // mifare == 6 bytes
1406 // mf plus == 16 bytes
1407 // iclass == 8 bytes
1408 // default to 6 bytes.
1409 if (keylen != 4 && keylen != 6 && keylen != 8 && keylen != 16) {
1410 keylen = 6;
1413 size_t mem_size;
1414 size_t block_size = 10 * keylen;
1416 // double up since its chars
1417 keylen <<= 1;
1419 char line[255];
1421 // allocate some space for the dictionary
1422 *pdata = calloc(block_size, sizeof(uint8_t));
1423 if (*pdata == NULL) {
1424 free(path);
1425 return PM3_EFILE;
1427 mem_size = block_size;
1429 FILE *f = fopen(path, "r");
1430 if (!f) {
1431 PrintAndLogEx(WARNING, "file not found or locked. '" _YELLOW_("%s")"'", path);
1432 retval = PM3_EFILE;
1433 goto out;
1436 // read file
1437 while (fgets(line, sizeof(line), f)) {
1439 // check if we have enough space (if not allocate more)
1440 if ((*keycnt * (keylen >> 1)) >= mem_size) {
1442 mem_size += block_size;
1443 *pdata = realloc(*pdata, mem_size);
1445 if (*pdata == NULL) {
1446 retval = PM3_EFILE;
1447 fclose(f);
1448 goto out;
1449 } else {
1450 memset((uint8_t *)*pdata + (mem_size - block_size), 0, block_size);
1454 // add null terminator
1455 line[keylen] = 0;
1457 // smaller keys than expected is skipped
1458 if (strlen(line) < keylen)
1459 continue;
1461 // The line start with # is comment, skip
1462 if (line[0] == '#')
1463 continue;
1465 if (!CheckStringIsHEXValue(line))
1466 continue;
1468 uint64_t key = strtoull(line, NULL, 16);
1470 num_to_bytes(key, keylen >> 1, (uint8_t *)*pdata + (*keycnt * (keylen >> 1)));
1472 (*keycnt)++;
1474 memset(line, 0, sizeof(line));
1476 fclose(f);
1477 PrintAndLogEx(SUCCESS, "loaded " _GREEN_("%2d") " keys from dictionary file " _YELLOW_("%s"), *keycnt, path);
1479 out:
1480 free(path);
1481 return retval;
1484 mfu_df_e detect_mfu_dump_format(uint8_t **dump, size_t *dumplen, bool verbose) {
1486 mfu_df_e retval = MFU_DF_UNKNOWN;
1487 uint8_t bcc0, bcc1;
1488 uint8_t ct = 0x88;
1490 // detect new
1491 mfu_dump_t *new = (mfu_dump_t *)*dump;
1492 bcc0 = ct ^ new->data[0] ^ new->data[1] ^ new->data[2];
1493 bcc1 = new->data[4] ^ new->data[5] ^ new->data[6] ^ new->data[7];
1494 if (bcc0 == new->data[3] && bcc1 == new->data[8]) {
1495 retval = MFU_DF_NEWBIN;
1498 // detect old
1499 if (retval == MFU_DF_UNKNOWN) {
1500 old_mfu_dump_t *old = (old_mfu_dump_t *)*dump;
1501 bcc0 = ct ^ old->data[0] ^ old->data[1] ^ old->data[2];
1502 bcc1 = old->data[4] ^ old->data[5] ^ old->data[6] ^ old->data[7];
1503 if (bcc0 == old->data[3] && bcc1 == old->data[8]) {
1504 retval = MFU_DF_OLDBIN;
1508 // detect plain
1509 if (retval == MFU_DF_UNKNOWN) {
1510 uint8_t *plain = *dump;
1511 bcc0 = ct ^ plain[0] ^ plain[1] ^ plain[2];
1512 bcc1 = plain[4] ^ plain[5] ^ plain[6] ^ plain[7];
1513 if ((bcc0 == plain[3]) && (bcc1 == plain[8])) {
1514 retval = MFU_DF_PLAINBIN;
1518 if (verbose) {
1519 switch (retval) {
1520 case MFU_DF_NEWBIN:
1521 PrintAndLogEx(INFO, "detected " _GREEN_("new") " mfu dump format");
1522 break;
1523 case MFU_DF_OLDBIN:
1524 PrintAndLogEx(INFO, "detected " _GREEN_("old") " mfu dump format");
1525 break;
1526 case MFU_DF_PLAINBIN:
1527 PrintAndLogEx(INFO, "detected " _GREEN_("plain") " mfu dump format");
1528 break;
1529 case MFU_DF_UNKNOWN:
1530 PrintAndLogEx(WARNING, "failed to detected mfu dump format");
1531 break;
1534 return retval;
1537 static int convert_plain_mfu_dump(uint8_t **dump, size_t *dumplen, bool verbose) {
1539 mfu_dump_t *mfu = (mfu_dump_t *) calloc(sizeof(mfu_dump_t), sizeof(uint8_t));
1540 if (mfu == NULL) {
1541 return PM3_EMALLOC;
1544 memcpy(mfu->data, *dump, *dumplen);
1546 mfu->pages = *dumplen / 4 - 1;
1548 if (verbose) {
1549 PrintAndLogEx(SUCCESS, "plain mfu dump format was converted to " _GREEN_("%d") " blocks", mfu->pages + 1);
1552 *dump = (uint8_t *)mfu;
1553 *dumplen += MFU_DUMP_PREFIX_LENGTH ;
1554 return PM3_SUCCESS;
1557 static int convert_old_mfu_dump(uint8_t **dump, size_t *dumplen, bool verbose) {
1558 /* For reference
1559 typedef struct {
1560 uint8_t version[8];
1561 uint8_t tbo[2];
1562 uint8_t tearing[3];
1563 uint8_t pack[2];
1564 uint8_t tbo1[1];
1565 uint8_t signature[32];
1566 uint8_t data[1024];
1567 } PACKED old_mfu_dump_t;
1570 // convert old format
1571 old_mfu_dump_t *old_mfu_dump = (old_mfu_dump_t *)*dump;
1573 size_t old_data_len = *dumplen - OLD_MFU_DUMP_PREFIX_LENGTH;
1574 size_t new_dump_len = old_data_len + MFU_DUMP_PREFIX_LENGTH;
1576 mfu_dump_t *mfu_dump = (mfu_dump_t *) calloc(sizeof(mfu_dump_t), sizeof(uint8_t));
1577 if (mfu_dump == NULL) {
1578 return PM3_EMALLOC;
1581 memcpy(mfu_dump->version, old_mfu_dump->version, sizeof(mfu_dump->version));
1582 memcpy(mfu_dump->tbo, old_mfu_dump->tbo, sizeof(mfu_dump->tbo));
1583 memcpy(mfu_dump->signature, old_mfu_dump->signature, sizeof(mfu_dump->signature));
1585 mfu_dump->tbo1[0] = old_mfu_dump->tbo1[0];
1587 for (int i = 0; i < 3; i++) {
1588 mfu_dump->counter_tearing[i][3] = old_mfu_dump->tearing[i];
1591 memcpy(mfu_dump->data, old_mfu_dump->data, sizeof(mfu_dump->data));
1592 mfu_dump->pages = old_data_len / 4 - 1;
1594 // Add PACK to last block of memory.
1595 memcpy(mfu_dump->data + (mfu_dump->pages * 4 + MFU_DUMP_PREFIX_LENGTH), old_mfu_dump->pack, 2);
1597 if (verbose) {
1598 PrintAndLogEx(SUCCESS, "old mfu dump format was converted to " _GREEN_("%d") " blocks", mfu_dump->pages + 1);
1601 free(*dump);
1602 *dump = (uint8_t *)mfu_dump;
1603 *dumplen = new_dump_len;
1604 return PM3_SUCCESS;
1607 int convert_mfu_dump_format(uint8_t **dump, size_t *dumplen, bool verbose) {
1609 if (!dump || !dumplen || *dumplen < OLD_MFU_DUMP_PREFIX_LENGTH) {
1610 return PM3_EINVARG;
1613 mfu_df_e res = detect_mfu_dump_format(dump, dumplen, verbose);
1615 switch (res) {
1616 case MFU_DF_NEWBIN:
1617 return PM3_SUCCESS;
1618 case MFU_DF_OLDBIN:
1619 return convert_old_mfu_dump(dump, dumplen, verbose);
1620 case MFU_DF_PLAINBIN:
1621 return convert_plain_mfu_dump(dump, dumplen, verbose);
1622 case MFU_DF_UNKNOWN:
1623 default:
1624 return PM3_ESOFT;
1628 static int filelist(const char *path, const char *ext, uint8_t last, bool tentative, uint8_t indent, uint16_t strip) {
1629 struct dirent **namelist;
1630 int n;
1632 n = scandir(path, &namelist, NULL, alphasort);
1633 if (n == -1) {
1635 if (tentative == false) {
1637 for (uint8_t j = 0; j < indent; j++) {
1638 PrintAndLogEx(NORMAL, "%s " NOLF, ((last >> j) & 1) ? " " : "│");
1640 PrintAndLogEx(NORMAL, "%s── "_GREEN_("%s"), last ? "└" : "├", &path[strip]);
1642 return PM3_EFILE;
1645 for (uint8_t j = 0; j < indent; j++) {
1646 PrintAndLogEx(NORMAL, "%s " NOLF, ((last >> j) & 1) ? " " : "│");
1649 PrintAndLogEx(NORMAL, "%s── "_GREEN_("%s"), last ? "└" : "├", &path[strip]);
1651 for (uint16_t i = 0; i < n; i++) {
1653 char tmp_fullpath[1024] = {0};
1654 strncat(tmp_fullpath, path, sizeof(tmp_fullpath) - 1);
1655 tmp_fullpath[1023] = 0x00;
1656 strncat(tmp_fullpath, namelist[i]->d_name, strlen(tmp_fullpath) - 1);
1658 if (is_directory(tmp_fullpath)) {
1660 char newpath[1024];
1661 if (strcmp(namelist[i]->d_name, ".") == 0 || strcmp(namelist[i]->d_name, "..") == 0)
1662 continue;
1664 snprintf(newpath, sizeof(newpath), "%s", path);
1665 strncat(newpath, namelist[i]->d_name, sizeof(newpath) - strlen(newpath) - 1);
1666 strncat(newpath, "/", sizeof(newpath) - strlen(newpath) - 1);
1668 filelist(newpath, ext, last + ((i == n - 1) << (indent + 1)), tentative, indent + 1, strlen(path));
1669 } else {
1671 if ((ext == NULL) || ((str_endswith(namelist[i]->d_name, ext)))) {
1673 for (uint8_t j = 0; j < indent + 1; j++) {
1674 PrintAndLogEx(NORMAL, "%s " NOLF, ((last >> j) & 1) ? " " : "│");
1676 PrintAndLogEx(NORMAL, "%s── %-21s", i == n - 1 ? "└" : "├", namelist[i]->d_name);
1679 free(namelist[i]);
1681 free(namelist);
1682 return PM3_SUCCESS;
1685 int searchAndList(const char *pm3dir, const char *ext) {
1686 // display in same order as searched by searchFile
1687 // try pm3 dirs in current workdir (dev mode)
1688 if (get_my_executable_directory() != NULL) {
1689 char script_directory_path[strlen(get_my_executable_directory()) + strlen(pm3dir) + 1];
1690 strcpy(script_directory_path, get_my_executable_directory());
1691 strcat(script_directory_path, pm3dir);
1692 filelist(script_directory_path, ext, false, true, 0, 0);
1694 // try pm3 dirs in user .proxmark3 (user mode)
1695 const char *user_path = get_my_user_directory();
1696 if (user_path != NULL) {
1697 char script_directory_path[strlen(user_path) + strlen(PM3_USER_DIRECTORY) + strlen(pm3dir) + 1];
1698 strcpy(script_directory_path, user_path);
1699 strcat(script_directory_path, PM3_USER_DIRECTORY);
1700 strcat(script_directory_path, pm3dir);
1701 filelist(script_directory_path, ext, false, false, 0, 0);
1703 // try pm3 dirs in pm3 installation dir (install mode)
1704 const char *exec_path = get_my_executable_directory();
1705 if (exec_path != NULL) {
1706 char script_directory_path[strlen(exec_path) + strlen(PM3_SHARE_RELPATH) + strlen(pm3dir) + 1];
1707 strcpy(script_directory_path, exec_path);
1708 strcat(script_directory_path, PM3_SHARE_RELPATH);
1709 strcat(script_directory_path, pm3dir);
1710 filelist(script_directory_path, ext, true, false, 0, 0);
1712 return PM3_SUCCESS;
1715 static int searchFinalFile(char **foundpath, const char *pm3dir, const char *searchname, bool silent) {
1716 if ((foundpath == NULL) || (pm3dir == NULL) || (searchname == NULL)) return PM3_ESOFT;
1717 // explicit absolute (/) or relative path (./) => try only to match it directly
1718 char *filename = calloc(strlen(searchname) + 1, sizeof(char));
1719 if (filename == NULL) return PM3_EMALLOC;
1720 strcpy(filename, searchname);
1721 if ((g_debugMode == 2) && (!silent)) {
1722 PrintAndLogEx(INFO, "Searching %s", filename);
1724 if (((strlen(filename) > 1) && (filename[0] == '/')) ||
1725 ((strlen(filename) > 2) && (filename[0] == '.') && (filename[1] == '/'))) {
1726 if (fileExists(filename)) {
1727 *foundpath = filename;
1728 if ((g_debugMode == 2) && (!silent)) {
1729 PrintAndLogEx(INFO, "Found %s", *foundpath);
1731 return PM3_SUCCESS;
1732 } else {
1733 goto out;
1736 // else
1738 // try implicit relative path
1740 if (fileExists(filename)) {
1741 *foundpath = filename;
1742 if ((g_debugMode == 2) && (!silent)) {
1743 PrintAndLogEx(INFO, "Found %s", *foundpath);
1745 return PM3_SUCCESS;
1748 // try pm3 dirs in user .proxmark3 (user mode)
1749 const char *user_path = get_my_user_directory();
1750 if (user_path != NULL) {
1751 char *path = calloc(strlen(user_path) + strlen(PM3_USER_DIRECTORY) + strlen(pm3dir) + strlen(filename) + 1, sizeof(char));
1752 if (path == NULL)
1753 goto out;
1754 strcpy(path, user_path);
1755 strcat(path, PM3_USER_DIRECTORY);
1756 strcat(path, pm3dir);
1757 strcat(path, filename);
1758 if ((g_debugMode == 2) && (!silent)) {
1759 PrintAndLogEx(INFO, "Searching %s", path);
1761 if (fileExists(path)) {
1762 free(filename);
1763 *foundpath = path;
1764 if ((g_debugMode == 2) && (!silent)) {
1765 PrintAndLogEx(INFO, "Found %s", *foundpath);
1767 return PM3_SUCCESS;
1768 } else {
1769 free(path);
1772 // try pm3 dirs in current client workdir (dev mode)
1773 const char *exec_path = get_my_executable_directory();
1774 if ((exec_path != NULL) &&
1775 ((strcmp(DICTIONARIES_SUBDIR, pm3dir) == 0) ||
1776 (strcmp(LUA_LIBRARIES_SUBDIR, pm3dir) == 0) ||
1777 (strcmp(LUA_SCRIPTS_SUBDIR, pm3dir) == 0) ||
1778 (strcmp(CMD_SCRIPTS_SUBDIR, pm3dir) == 0) ||
1779 (strcmp(PYTHON_SCRIPTS_SUBDIR, pm3dir) == 0) ||
1780 (strcmp(RESOURCES_SUBDIR, pm3dir) == 0))) {
1781 char *path = calloc(strlen(exec_path) + strlen(pm3dir) + strlen(filename) + 1, sizeof(char));
1782 if (path == NULL)
1783 goto out;
1784 strcpy(path, exec_path);
1785 strcat(path, pm3dir);
1786 strcat(path, filename);
1787 if ((g_debugMode == 2) && (!silent)) {
1788 PrintAndLogEx(INFO, "Searching %s", path);
1790 if (fileExists(path)) {
1791 free(filename);
1792 *foundpath = path;
1793 if ((g_debugMode == 2) && (!silent)) {
1794 PrintAndLogEx(INFO, "Found %s", *foundpath);
1796 return PM3_SUCCESS;
1797 } else {
1798 free(path);
1801 // try pm3 dirs in current repo workdir (dev mode)
1802 if ((exec_path != NULL) &&
1803 ((strcmp(TRACES_SUBDIR, pm3dir) == 0) ||
1804 (strcmp(FIRMWARES_SUBDIR, pm3dir) == 0) ||
1805 (strcmp(BOOTROM_SUBDIR, pm3dir) == 0) ||
1806 (strcmp(FULLIMAGE_SUBDIR, pm3dir) == 0))) {
1807 const char *above = "../";
1808 char *path = calloc(strlen(exec_path) + strlen(above) + strlen(pm3dir) + strlen(filename) + 1, sizeof(char));
1809 if (path == NULL)
1810 goto out;
1811 strcpy(path, exec_path);
1812 strcat(path, above);
1813 strcat(path, pm3dir);
1814 strcat(path, filename);
1815 if ((g_debugMode == 2) && (!silent)) {
1816 PrintAndLogEx(INFO, "Searching %s", path);
1818 if (fileExists(path)) {
1819 free(filename);
1820 *foundpath = path;
1821 if ((g_debugMode == 2) && (!silent)) {
1822 PrintAndLogEx(INFO, "Found %s", *foundpath);
1824 return PM3_SUCCESS;
1825 } else {
1826 free(path);
1829 // try pm3 dirs in pm3 installation dir (install mode)
1830 if (exec_path != NULL) {
1831 char *path = calloc(strlen(exec_path) + strlen(PM3_SHARE_RELPATH) + strlen(pm3dir) + strlen(filename) + 1, sizeof(char));
1832 if (path == NULL)
1833 goto out;
1834 strcpy(path, exec_path);
1835 strcat(path, PM3_SHARE_RELPATH);
1836 strcat(path, pm3dir);
1837 strcat(path, filename);
1838 if ((g_debugMode == 2) && (!silent)) {
1839 PrintAndLogEx(INFO, "Searching %s", path);
1841 if (fileExists(path)) {
1842 free(filename);
1843 *foundpath = path;
1844 if ((g_debugMode == 2) && (!silent)) {
1845 PrintAndLogEx(INFO, "Found %s", *foundpath);
1847 return PM3_SUCCESS;
1848 } else {
1849 free(path);
1852 out:
1853 free(filename);
1854 return PM3_EFILE;
1857 int searchFile(char **foundpath, const char *pm3dir, const char *searchname, const char *suffix, bool silent) {
1859 if (foundpath == NULL)
1860 return PM3_EINVARG;
1862 if (searchname == NULL || strlen(searchname) == 0)
1863 return PM3_EINVARG;
1865 if (is_directory(searchname))
1866 return PM3_EINVARG;
1868 char *filename = filenamemcopy(searchname, suffix);
1869 if (filename == NULL)
1870 return PM3_EMALLOC;
1872 if (strlen(filename) == 0) {
1873 free(filename);
1874 return PM3_EFILE;
1876 int res = searchFinalFile(foundpath, pm3dir, filename, silent);
1877 if (res != PM3_SUCCESS) {
1878 if ((res == PM3_EFILE) && (!silent))
1879 PrintAndLogEx(FAILED, "Error - can't find `" _YELLOW_("%s") "`", filename);
1880 free(filename);
1881 return res;
1883 free(filename);
1884 return PM3_SUCCESS;