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 //-----------------------------------------------------------------------------
16 // Proxmark3 RDV40 Flash memory commands
17 //-----------------------------------------------------------------------------
18 #include "cmdflashmem.h"
20 #include "cmdparser.h" // command_t
21 #include "cliparser.h"
22 #include "pmflash.h" // rdv40validation_t
23 #include "fileutils.h" // saveFile
24 #include "comms.h" // getfromdevice
25 #include "cmdflashmemspiffs.h" // spiffs commands
28 #include "pk.h" // PEM key load functions
31 #define FLASH_MINFAST 24000000 //33000000
32 #define FLASH_BAUD MCK/2
33 #define FLASH_FASTBAUD MCK
34 #define FLASH_MINBAUD FLASH_FASTBAUD
36 static int CmdHelp(const char *Cmd
);
38 //-------------------------------------------------------------------------------------
40 #define RRG_RSA_KEY_LEN 128
42 // public key Exponent E
43 #define RRG_RSA_E "010001"
45 // public key modulus N
46 #define RRG_RSA_N "E28D809BF323171D11D1ACA4C32A5B7E0A8974FD171E75AD120D60E9B76968FF" \
47 "4B0A6364AE50583F9555B8EE1A725F279E949246DF0EFCE4C02B9F3ACDCC623F" \
48 "9337F21C0C066FFB703D8BFCB5067F309E056772096642C2B1A8F50305D5EC33" \
49 "DB7FB5A3C8AC42EB635AE3C148C910750ABAA280CE82DC2F180F49F30A1393B5"
51 //-------------------------------------------------------------------------------------
53 int rdv4_get_signature(rdv40_validation_t
*out
) {
59 SendCommandNG(CMD_FLASHMEM_INFO
, NULL
, 0);
60 PacketResponseNG resp
;
61 if (WaitForResponseTimeout(CMD_ACK
, &resp
, 2500) == false) {
62 PrintAndLogEx(WARNING
, "timeout while waiting for reply");
66 uint8_t isok
= resp
.oldarg
[0] & 0xFF;
68 PrintAndLogEx(FAILED
, "fail reading from flashmemory");
72 //rdv40_validation_t mem;
73 memcpy(out
, (rdv40_validation_t
*)resp
.data
.asBytes
, sizeof(rdv40_validation_t
));
78 int rdv4_validate(rdv40_validation_t
*mem
) {
79 // Flash ID hash (sha1)
80 uint8_t sha_hash
[20] = {0};
81 mbedtls_sha1(mem
->flashid
, sizeof(mem
->flashid
), sha_hash
);
84 mbedtls_rsa_context rsa
;
85 mbedtls_rsa_init(&rsa
, MBEDTLS_RSA_PKCS_V15
, 0);
86 rsa
.len
= RRG_RSA_KEY_LEN
;
87 mbedtls_mpi_read_string(&rsa
.N
, 16, RRG_RSA_N
);
88 mbedtls_mpi_read_string(&rsa
.E
, 16, RRG_RSA_E
);
90 // Verify (public key)
91 int is_verified
= mbedtls_rsa_pkcs1_verify(&rsa
, NULL
, NULL
, MBEDTLS_RSA_PUBLIC
, MBEDTLS_MD_SHA1
, 20, sha_hash
, mem
->signature
);
92 mbedtls_rsa_free(&rsa
);
94 if (is_verified
== 0) {
100 static int rdv4_sign_write(uint8_t *signature
, uint8_t slen
) {
101 flashmem_old_write_t payload
= {
102 .startidx
= FLASH_MEM_SIGNATURE_OFFSET
,
103 .len
= FLASH_MEM_SIGNATURE_LEN
,
105 memcpy(payload
.data
, signature
, slen
);
107 clearCommandBuffer();
108 PacketResponseNG resp
;
109 SendCommandNG(CMD_FLASHMEM_WRITE
, (uint8_t *)&payload
, sizeof(payload
));
111 if (WaitForResponseTimeout(CMD_FLASHMEM_WRITE
, &resp
, 2000) == false) {
112 PrintAndLogEx(WARNING
, "timeout while waiting for reply");
115 if (resp
.status
!= PM3_SUCCESS
) {
116 PrintAndLogEx(FAILED
, "Writing signature ( "_RED_("fail") ")");
120 PrintAndLogEx(SUCCESS
, "Writing signature at offset %u ( "_GREEN_("ok") " )", FLASH_MEM_SIGNATURE_OFFSET
);
124 static int CmdFlashmemSpiBaud(const char *Cmd
) {
126 CLIParserContext
*ctx
;
127 CLIParserInit(&ctx
, "mem baudrate",
128 "Set the baudrate for the SPI flash memory communications.\n"
129 "Reading Flash ID will virtually always fail under 48MHz setting.\n"
130 "Unless you know what you are doing, please stay at 24MHz.\n"
131 "If >= 24MHz, FASTREADS instead of READS instruction will be used.",
132 "mem baudrate --mhz 48"
137 arg_int1(NULL
, "mhz", "<24|48>", "SPI baudrate in MHz"),
140 CLIExecWithReturn(ctx
, Cmd
, argtable
, false);
141 int br
= arg_get_int_def(ctx
, 1, -1);
145 PrintAndLogEx(ERR
, "failed to get baudrate");
149 uint32_t baudrate
= br
* 1000000;
150 if (baudrate
!= FLASH_BAUD
&& baudrate
!= FLASH_MINBAUD
) {
151 PrintAndLogEx(ERR
, "wrong baudrate. Only 24 or 48 is allowed");
154 SendCommandNG(CMD_FLASHMEM_SET_SPIBAUDRATE
, (uint8_t *)&baudrate
, sizeof(uint32_t));
158 static int CmdFlashMemLoad(const char *Cmd
) {
160 CLIParserContext
*ctx
;
161 CLIParserInit(&ctx
, "mem load",
162 "Loads binary file into flash memory on device\n"
163 "Warning: mem area to be written must have been wiped first\n"
164 "( this is already taken care when loading dictionaries )",
165 "mem load -f myfile -> upload file myfile values at default offset 0\n"
166 "mem load -f myfile -o 1024 -> upload file myfile values at offset 1024\n"
167 "mem load -f mfc_default_keys -m -> upload MFC keys\n"
168 "mem load -f t55xx_default_pwds -t -> upload T55XX passwords\n"
169 "mem load -f iclass_default_keys -i -> upload iCLASS keys\n"
174 arg_int0("o", "offset", "<dec>", "offset in memory"),
175 arg_lit0("m", "mifare,mfc", "upload 6 bytes keys (mifare key dictionary)"),
176 arg_lit0("i", "iclass", "upload 8 bytes keys (iClass key dictionary)"),
177 arg_lit0("t", "t55xx", "upload 4 bytes keys (password dictionary)"),
178 arg_str1("f", "file", "<fn>", "file name"),
181 CLIExecWithReturn(ctx
, Cmd
, argtable
, false);
183 int offset
= arg_get_int_def(ctx
, 1, 0);
184 bool is_mfc
= arg_get_lit(ctx
, 2);
185 bool is_iclass
= arg_get_lit(ctx
, 3);
186 bool is_t55xx
= arg_get_lit(ctx
, 4);
188 char filename
[FILE_PATH_SIZE
] = {0};
189 CLIParamStrToBuf(arg_get_str(ctx
, 5), (uint8_t *)filename
, FILE_PATH_SIZE
, &fnlen
);
192 Dictionary_t d
= DICTIONARY_NONE
;
194 d
= DICTIONARY_MIFARE
;
195 PrintAndLogEx(INFO
, "treating file as MIFARE Classic keys");
196 } else if (is_iclass
) {
197 d
= DICTIONARY_ICLASS
;
198 PrintAndLogEx(INFO
, "treating file as iCLASS keys");
199 } else if (is_t55xx
) {
200 d
= DICTIONARY_T55XX
;
201 PrintAndLogEx(INFO
, "treating file as T55xx passwords");
205 uint32_t keycount
= 0;
208 uint8_t *data
= calloc(FLASH_MEM_MAX_SIZE
, sizeof(uint8_t));
211 case DICTIONARY_MIFARE
:
212 offset
= DEFAULT_MF_KEYS_OFFSET
;
214 res
= loadFileDICTIONARY(filename
, data
+ 2, &datalen
, keylen
, &keycount
);
215 if (res
|| !keycount
) {
219 // limited space on flash mem
220 if (keycount
> DEFAULT_MF_KEYS_MAX
) {
221 keycount
= DEFAULT_MF_KEYS_MAX
;
222 datalen
= keycount
* keylen
;
225 data
[0] = (keycount
>> 0) & 0xFF;
226 data
[1] = (keycount
>> 8) & 0xFF;
229 case DICTIONARY_T55XX
:
230 offset
= DEFAULT_T55XX_KEYS_OFFSET
;
232 res
= loadFileDICTIONARY(filename
, data
+ 2, &datalen
, keylen
, &keycount
);
233 if (res
|| !keycount
) {
237 // limited space on flash mem
238 if (keycount
> DEFAULT_T55XX_KEYS_MAX
) {
239 keycount
= DEFAULT_T55XX_KEYS_MAX
;
240 datalen
= keycount
* keylen
;
243 data
[0] = (keycount
>> 0) & 0xFF;
244 data
[1] = (keycount
>> 8) & 0xFF;
247 case DICTIONARY_ICLASS
:
248 offset
= DEFAULT_ICLASS_KEYS_OFFSET
;
249 res
= loadFileDICTIONARY(filename
, data
+ 2, &datalen
, keylen
, &keycount
);
250 if (res
|| !keycount
) {
254 // limited space on flash mem
255 if (keycount
> DEFAULT_ICLASS_KEYS_MAX
) {
256 keycount
= DEFAULT_ICLASS_KEYS_MAX
;
257 datalen
= keycount
* keylen
;
260 data
[0] = (keycount
>> 0) & 0xFF;
261 data
[1] = (keycount
>> 8) & 0xFF;
264 case DICTIONARY_NONE
:
265 res
= loadFile_safe(filename
, ".bin", (void **)&data
, &datalen
);
266 if (res
!= PM3_SUCCESS
) {
271 if (datalen
> FLASH_MEM_MAX_SIZE
) {
272 PrintAndLogEx(ERR
, "error, filesize is larger than available memory");
279 // ICEMAN: not needed when we transite to loadxxxx_safe methods
280 uint8_t *newdata
= realloc(data
, datalen
);
281 if (newdata
== NULL
) {
289 uint32_t bytes_sent
= 0;
290 uint32_t bytes_remaining
= datalen
;
294 g_conn
.block_after_ACK
= true;
296 while (bytes_remaining
> 0) {
297 uint32_t bytes_in_packet
= MIN(FLASH_MEM_BLOCK_SIZE
, bytes_remaining
);
299 clearCommandBuffer();
301 flashmem_old_write_t payload
= {
302 .startidx
= offset
+ bytes_sent
,
303 .len
= bytes_in_packet
,
305 memcpy(payload
.data
, data
+ bytes_sent
, bytes_in_packet
);
306 SendCommandNG(CMD_FLASHMEM_WRITE
, (uint8_t *)&payload
, sizeof(payload
));
308 bytes_remaining
-= bytes_in_packet
;
309 bytes_sent
+= bytes_in_packet
;
311 PacketResponseNG resp
;
312 if (WaitForResponseTimeout(CMD_FLASHMEM_WRITE
, &resp
, 2000) == false) {
313 PrintAndLogEx(WARNING
, "timeout while waiting for reply.");
314 g_conn
.block_after_ACK
= false;
319 if (resp
.status
!= PM3_SUCCESS
) {
320 g_conn
.block_after_ACK
= false;
321 PrintAndLogEx(FAILED
, "Flash write fail [offset %u]", bytes_sent
);
327 g_conn
.block_after_ACK
= false;
329 PrintAndLogEx(SUCCESS
, "Wrote "_GREEN_("%zu")" bytes to offset "_GREEN_("%u"), datalen
, offset
);
333 static int CmdFlashMemDump(const char *Cmd
) {
335 CLIParserContext
*ctx
;
336 CLIParserInit(&ctx
, "mem dump",
337 "Dumps flash memory on device into a file or view in console",
338 "mem dump -f myfile -> download all flashmem to file\n"
339 "mem dump --view -o 262015 --len 128 -> display 128 bytes from offset 262015 (RSA sig)\n"
340 "mem dump --view -f myfile -o 241664 --len 58 -> display 58 bytes from offset 241664 and save to file"
345 arg_int0("o", "offset", "<dec>", "offset in memory"),
346 arg_int0("l", "len", "<dec>", "length"),
347 arg_lit0("v", "view", "view dump"),
348 arg_str0("f", "file", "<fn>", "save filename"),
349 arg_int0("c", "cols", "<dec>", "column breaks (def 32)"),
352 CLIExecWithReturn(ctx
, Cmd
, argtable
, false);
354 int offset
= arg_get_int_def(ctx
, 1, 0);
355 int len
= arg_get_int_def(ctx
, 2, FLASH_MEM_MAX_SIZE
);
356 bool view
= arg_get_lit(ctx
, 3);
358 char filename
[FILE_PATH_SIZE
] = {0};
359 CLIParamStrToBuf(arg_get_str(ctx
, 4), (uint8_t *)filename
, FILE_PATH_SIZE
, &fnlen
);
360 int breaks
= arg_get_int_def(ctx
, 5, 32);
363 uint8_t *dump
= calloc(len
, sizeof(uint8_t));
365 PrintAndLogEx(ERR
, "error, cannot allocate memory ");
369 PrintAndLogEx(INFO
, "downloading "_YELLOW_("%u")" bytes from flash memory", len
);
370 if (!GetFromDevice(FLASH_MEM
, dump
, len
, offset
, NULL
, 0, NULL
, -1, true)) {
371 PrintAndLogEx(FAILED
, "ERROR; downloading from flash memory");
377 PrintAndLogEx(INFO
, "---- " _CYAN_("data") " ---------------");
378 print_hex_break(dump
, len
, breaks
);
381 if (filename
[0] != '\0') {
382 pm3_save_dump(filename
, dump
, len
, jsfRaw
);
389 static int CmdFlashMemWipe(const char *Cmd
) {
391 CLIParserContext
*ctx
;
392 CLIParserInit(&ctx
, "mem wipe",
393 "Wipe flash memory on device, which fills it with 0xFF\n"
394 _WHITE_("[ ") _RED_("!!! OBS") _WHITE_(" ] use with caution"),
395 "mem wipe -p 0 -> wipes first page"
396 // "mem wipe -i -> initial total wipe"
401 arg_int0("p", NULL
, "<dec>", "0,1,2 page memory"),
402 // arg_lit0("i", NULL, "initial total wipe"),
405 CLIExecWithReturn(ctx
, Cmd
, argtable
, false);
407 bool initialwipe
= false;
408 int page
= arg_get_int_def(ctx
, 1, -1);
409 // initialwipe = arg_get_lit(ctx, 2);
412 if (page
< 0 || page
> 2) {
413 PrintAndLogEx(WARNING
, "page must be 0, 1 or 2");
417 clearCommandBuffer();
418 SendCommandMIX(CMD_FLASHMEM_WIPE
, page
, initialwipe
, 0, NULL
, 0);
419 PacketResponseNG resp
;
420 if (!WaitForResponseTimeout(CMD_ACK
, &resp
, 8000)) {
421 PrintAndLogEx(WARNING
, "timeout while waiting for reply.");
425 const char *msg
= "Flash WIPE ";
426 uint8_t isok
= resp
.oldarg
[0] & 0xFF;
428 PrintAndLogEx(SUCCESS
, "%s ( " _GREEN_("ok")" )", msg
);
430 PrintAndLogEx(FAILED
, "%s ( " _RED_("failed") " )", msg
);
437 static int CmdFlashMemInfo(const char *Cmd
) {
439 CLIParserContext
*ctx
;
440 CLIParserInit(&ctx
, "mem info",
441 "Collect signature and verify it from flash memory",
447 arg_lit0("s", "sign", "create a signature"),
448 arg_str0("d", NULL
, "<hex>", "flash memory id, 8 hex bytes"),
449 arg_str0("p", "pem", "<fn>", "key in PEM format"),
450 arg_lit0("v", "verbose", "verbose output"),
451 // arg_lit0("w", "write", "write signature to flash memory"),
454 CLIExecWithReturn(ctx
, Cmd
, argtable
, true);
456 bool shall_sign
= arg_get_lit(ctx
, 1);
460 int res
= CLIParamHexToBuf(arg_get_str(ctx
, 2), id
, sizeof(id
), &dlen
);
463 char pem_fn
[FILE_PATH_SIZE
] = {0};
464 CLIParamStrToBuf(arg_get_str(ctx
, 3), (uint8_t *)pem_fn
, FILE_PATH_SIZE
, &pemlen
);
466 bool verbose
= arg_get_lit(ctx
, 4);
467 bool shall_write
= false;
468 // shall_write = arg_get_lit(ctx, 5);
475 if (dlen
> 0 && dlen
< sizeof(id
)) {
476 PrintAndLogEx(FAILED
, "Error parsing flash memory id, expect 8, got %d", dlen
);
480 // set up PK key context now.
481 mbedtls_pk_context pkctx
;
482 mbedtls_pk_init(&pkctx
);
483 bool got_private
= false;
488 if (searchFile(&path
, RESOURCES_SUBDIR
, pem_fn
, ".pem", true) != PM3_SUCCESS
) {
489 if (searchFile(&path
, RESOURCES_SUBDIR
, pem_fn
, "", false) != PM3_SUCCESS
) {
494 PrintAndLogEx(INFO
, "loading file `" _YELLOW_("%s") "`" NOLF
, path
);
497 res
= mbedtls_pk_parse_keyfile(&pkctx
, path
, NULL
);
499 //res = mbedtls_pk_parse_public_keyfile(&pkctx, path);
501 PrintAndLogEx(NORMAL
, " ( " _GREEN_("ok") " )");
503 PrintAndLogEx(NORMAL
, " ( " _RED_("fail") " )");
504 mbedtls_pk_free(&pkctx
);
508 mbedtls_rsa_context
*rsa
= (mbedtls_rsa_context
*)pkctx
.pk_ctx
;
510 PrintAndLogEx(FAILED
, "failed to allocate rsa context memory");
516 // it not loaded, we need to setup the context manually
517 if (mbedtls_pk_setup(&pkctx
, mbedtls_pk_info_from_type((mbedtls_pk_type_t
) MBEDTLS_PK_RSA
)) != 0) {
518 PrintAndLogEx(FAILED
, "failed, mbedtls_pk_setup returned ");
523 // validate devicesignature data
524 rdv40_validation_t mem
;
525 res
= rdv4_get_signature(&mem
);
526 if (res
!= PM3_SUCCESS
) {
530 res
= rdv4_validate(&mem
);
532 // Flash ID hash (sha1)
533 uint8_t sha_hash
[20] = {0};
534 mbedtls_sha1(mem
.flashid
, sizeof(mem
.flashid
), sha_hash
);
537 PrintAndLogEx(NORMAL
, "");
538 PrintAndLogEx(INFO
, "--- " _CYAN_("Flash memory Information") " ---------");
539 PrintAndLogEx(INFO
, "ID................... %s", sprint_hex_inrow(mem
.flashid
, sizeof(mem
.flashid
)));
540 PrintAndLogEx(INFO
, "SHA1................. %s", sprint_hex_inrow(sha_hash
, sizeof(sha_hash
)));
541 PrintAndLogEx(NORMAL
, "");
542 PrintAndLogEx(INFO
, "--- " _CYAN_("RDV4 RSA signature") " ---------------");
543 for (int i
= 0; i
< (sizeof(mem
.signature
) / 32); i
++) {
544 PrintAndLogEx(INFO
, " %s", sprint_hex_inrow(mem
.signature
+ (i
* 32), 32));
547 (res
== PM3_SUCCESS
) ? SUCCESS
: FAILED
,
548 "Signature............ ( %s )",
549 (res
== PM3_SUCCESS
) ? _GREEN_("ok") : _RED_("fail")
551 PrintAndLogEx(NORMAL
, "");
553 mbedtls_rsa_context
*rsa
= NULL
;
556 rsa
= mbedtls_pk_rsa(pkctx
);
557 rsa
->padding
= MBEDTLS_RSA_PKCS_V15
;
559 rsa
->len
= RRG_RSA_KEY_LEN
;
562 rsa
= (mbedtls_rsa_context
*)calloc(1, sizeof(mbedtls_rsa_context
));
563 mbedtls_rsa_init(rsa
, MBEDTLS_RSA_PKCS_V15
, 0);
564 rsa
->len
= RRG_RSA_KEY_LEN
;
567 mbedtls_mpi_read_string(&rsa
->N
, 16, RRG_RSA_N
);
568 mbedtls_mpi_read_string(&rsa
->E
, 16, RRG_RSA_E
);
571 PrintAndLogEx(INFO
, "--- " _CYAN_("RDV4 RSA Public key") " --------------");
575 size_t exlen
= 0, pklen
= 0;
576 mbedtls_mpi_write_string(&rsa
->E
, 16, str_exp
, sizeof(str_exp
), &exlen
);
577 mbedtls_mpi_write_string(&rsa
->N
, 16, str_pk
, sizeof(str_pk
), &pklen
);
579 PrintAndLogEx(INFO
, "Len.................. %"PRIu64
, rsa
->len
);
580 PrintAndLogEx(INFO
, "Exponent............. %s", str_exp
);
581 PrintAndLogEx(INFO
, "Public key modulus N");
582 PrintAndLogEx(INFO
, " %.64s", str_pk
);
583 PrintAndLogEx(INFO
, " %.64s", str_pk
+ 64);
584 PrintAndLogEx(INFO
, " %.64s", str_pk
+ 128);
585 PrintAndLogEx(INFO
, " %.64s", str_pk
+ 192);
586 PrintAndLogEx(NORMAL
, "");
589 bool is_keyok
= (mbedtls_rsa_check_pubkey(rsa
) == 0);
591 (is_keyok
) ? SUCCESS
: FAILED
,
592 "RDV4 RSA public key check.... ( %s )",
593 (is_keyok
) ? _GREEN_("ok") : _RED_("fail")
596 is_keyok
= (mbedtls_rsa_check_privkey(rsa
) == 0);
599 (is_keyok
) ? SUCCESS
: FAILED
,
600 "RDV4 RSA private key check... ( %s )",
601 (is_keyok
) ? _GREEN_("ok") : _YELLOW_("n/aA")
606 uint8_t from_device
[RRG_RSA_KEY_LEN
];
607 memcpy(from_device
, mem
.signature
, RRG_RSA_KEY_LEN
);
610 uint8_t sign
[RRG_RSA_KEY_LEN
];
611 memset(sign
, 0, RRG_RSA_KEY_LEN
);
613 // Signing (private key)
618 PrintAndLogEx(NORMAL
, "");
619 PrintAndLogEx(INFO
, "--- " _CYAN_("Enter signing") " --------------------");
622 mbedtls_sha1(id
, sizeof(id
), sha_hash
);
624 PrintAndLogEx(INFO
, "Signing....... %s", sprint_hex_inrow(sha_hash
, sizeof(sha_hash
)));
626 int is_signed
= mbedtls_rsa_pkcs1_sign(rsa
, NULL
, NULL
, MBEDTLS_RSA_PRIVATE
, MBEDTLS_MD_SHA1
, 20, sha_hash
, sign
);
628 (is_signed
== 0) ? SUCCESS
: FAILED
,
629 "RSA signing... ( %s )",
630 (is_signed
== 0) ? _GREEN_("ok") : _RED_("fail")
634 rdv4_sign_write(sign
, RRG_RSA_KEY_LEN
);
636 PrintAndLogEx(INFO
, "New signature");
637 for (int i
= 0; i
< (sizeof(sign
) / 32); i
++) {
638 PrintAndLogEx(INFO
, " %s", sprint_hex_inrow(sign
+ (i
* 32), 32));
641 PrintAndLogEx(FAILED
, "no private key available to sign");
645 // Verify (public key)
646 bool is_verified
= (mbedtls_rsa_pkcs1_verify(rsa
, NULL
, NULL
, MBEDTLS_RSA_PUBLIC
, MBEDTLS_MD_SHA1
, 20, sha_hash
, from_device
) == 0);
648 if (got_private
== false) {
649 mbedtls_rsa_free(rsa
);
653 mbedtls_pk_free(&pkctx
);
655 PrintAndLogEx(NORMAL
, "");
657 (is_verified
) ? SUCCESS
: FAILED
,
658 "Genuine Proxmark3 RDV4 signature detected... %s",
659 (is_verified
) ? ":heavy_check_mark:" : ":x:"
661 PrintAndLogEx(NORMAL
, "");
665 static command_t CommandTable
[] = {
666 {"spiffs", CmdFlashMemSpiFFS
, IfPm3Flash
, "{ SPI File system }"},
667 {"help", CmdHelp
, AlwaysAvailable
, "This help"},
668 {"baudrate", CmdFlashmemSpiBaud
, IfPm3Flash
, "Set Flash memory Spi baudrate"},
669 {"dump", CmdFlashMemDump
, IfPm3Flash
, "Dump data from flash memory"},
670 {"info", CmdFlashMemInfo
, IfPm3Flash
, "Flash memory information"},
671 {"load", CmdFlashMemLoad
, IfPm3Flash
, "Load data to flash memory"},
672 {"wipe", CmdFlashMemWipe
, IfPm3Flash
, "Wipe data from flash memory"},
673 {NULL
, NULL
, NULL
, NULL
}
676 static int CmdHelp(const char *Cmd
) {
677 (void)Cmd
; // Cmd is not used so far
678 CmdsHelp(CommandTable
);
682 int CmdFlashMem(const char *Cmd
) {
683 clearCommandBuffer();
684 return CmdsParse(CommandTable
, Cmd
);