renamed 'hf mfdes readdata, writedata' to 'read/write'
[RRG-proxmark3.git] / client / src / cmdflashmem.c
blob649809283a2bdc326f6c80c5b95a6d5c3c6ba772
1 //-----------------------------------------------------------------------------
2 // Copyright (C) 2018 iceman
3 //
4 // This code is licensed to you under the terms of the GNU GPL, version 2 or,
5 // at your option, any later version. See the LICENSE.txt file for the text of
6 // the license.
7 //-----------------------------------------------------------------------------
8 // Proxmark3 RDV40 Flash memory commands
9 //-----------------------------------------------------------------------------
10 #include "cmdflashmem.h"
11 #include <ctype.h>
12 #include "cmdparser.h" // command_t
13 #include "cliparser.h"
14 #include "pmflash.h" // rdv40validation_t
15 #include "fileutils.h" // saveFile
16 #include "comms.h" // getfromdevice
17 #include "cmdflashmemspiffs.h" // spiffs commands
18 #include "rsa.h"
19 #include "sha1.h"
20 #include "pk.h" // PEM key load functions
22 #define MCK 48000000
23 #define FLASH_MINFAST 24000000 //33000000
24 #define FLASH_BAUD MCK/2
25 #define FLASH_FASTBAUD MCK
26 #define FLASH_MINBAUD FLASH_FASTBAUD
28 static int CmdHelp(const char *Cmd);
30 //-------------------------------------------------------------------------------------
31 // RRG Public RSA Key
32 #define RRG_RSA_KEY_LEN 128
34 // public key Exponent E
35 #define RRG_RSA_E "010001"
37 // public key modulus N
38 #define RRG_RSA_N "E28D809BF323171D11D1ACA4C32A5B7E0A8974FD171E75AD120D60E9B76968FF" \
39 "4B0A6364AE50583F9555B8EE1A725F279E949246DF0EFCE4C02B9F3ACDCC623F" \
40 "9337F21C0C066FFB703D8BFCB5067F309E056772096642C2B1A8F50305D5EC33" \
41 "DB7FB5A3C8AC42EB635AE3C148C910750ABAA280CE82DC2F180F49F30A1393B5"
43 //-------------------------------------------------------------------------------------
45 int rdv4_get_signature(rdv40_validation_t *out) {
46 if (out == NULL) {
47 return PM3_EINVARG;
50 clearCommandBuffer();
51 SendCommandNG(CMD_FLASHMEM_INFO, NULL, 0);
52 PacketResponseNG resp;
53 if (WaitForResponseTimeout(CMD_ACK, &resp, 2500) == false) {
54 PrintAndLogEx(WARNING, "timeout while waiting for reply");
55 return PM3_ETIMEOUT;
58 uint8_t isok = resp.oldarg[0] & 0xFF;
59 if (isok == false) {
60 PrintAndLogEx(FAILED, "fail reading from flashmemory");
61 return PM3_EFLASH;
64 //rdv40_validation_t mem;
65 memcpy(out, (rdv40_validation_t *)resp.data.asBytes, sizeof(rdv40_validation_t));
66 return PM3_SUCCESS;
69 // validate signature
70 int rdv4_validate(rdv40_validation_t *mem) {
71 // Flash ID hash (sha1)
72 uint8_t sha_hash[20] = {0};
73 mbedtls_sha1(mem->flashid, sizeof(mem->flashid), sha_hash);
75 // set up RSA
76 mbedtls_rsa_context rsa;
77 mbedtls_rsa_init(&rsa, MBEDTLS_RSA_PKCS_V15, 0);
78 rsa.len = RRG_RSA_KEY_LEN;
79 mbedtls_mpi_read_string(&rsa.N, 16, RRG_RSA_N);
80 mbedtls_mpi_read_string(&rsa.E, 16, RRG_RSA_E);
82 // Verify (public key)
83 int is_verified = mbedtls_rsa_pkcs1_verify(&rsa, NULL, NULL, MBEDTLS_RSA_PUBLIC, MBEDTLS_MD_SHA1, 20, sha_hash, mem->signature);
84 mbedtls_rsa_free(&rsa);
86 if (is_verified == 0) {
87 return PM3_SUCCESS;
89 return PM3_EFAILED;
92 static int rdv4_sign_write(uint8_t *signature, uint8_t slen) {
93 flashmem_old_write_t payload = {
94 .startidx = FLASH_MEM_SIGNATURE_OFFSET,
95 .len = FLASH_MEM_SIGNATURE_LEN,
97 memcpy(payload.data, signature, slen);
99 clearCommandBuffer();
100 PacketResponseNG resp;
101 SendCommandNG(CMD_FLASHMEM_WRITE, (uint8_t *)&payload, sizeof(payload));
103 if (WaitForResponseTimeout(CMD_FLASHMEM_WRITE, &resp, 2000) == false) {
104 PrintAndLogEx(WARNING, "timeout while waiting for reply");
105 return PM3_EFAILED;
106 } else {
107 if (resp.status != PM3_SUCCESS) {
108 PrintAndLogEx(FAILED, "Writing signature ( "_RED_("fail") ")");
109 return PM3_EFAILED;
112 PrintAndLogEx(SUCCESS, "Writing signature at offset %u ( "_GREEN_("ok") " )", FLASH_MEM_SIGNATURE_OFFSET);
113 return PM3_SUCCESS;
116 static int CmdFlashmemSpiBaud(const char *Cmd) {
118 CLIParserContext *ctx;
119 CLIParserInit(&ctx, "mem baudrate",
120 "Set the baudrate for the SPI flash memory communications.\n"
121 "Reading Flash ID will virtually always fail under 48MHz setting.\n"
122 "Unless you know what you are doing, please stay at 24MHz.\n"
123 "If >= 24MHz, FASTREADS instead of READS instruction will be used.",
124 "mem baudrate --mhz 48"
127 void *argtable[] = {
128 arg_param_begin,
129 arg_int1(NULL, "mhz", "<24|48>", "SPI baudrate in MHz"),
130 arg_param_end
132 CLIExecWithReturn(ctx, Cmd, argtable, false);
133 int br = arg_get_int_def(ctx, 1, -1);
134 CLIParserFree(ctx);
136 if (br == -1) {
137 PrintAndLogEx(ERR, "failed to get baudrate");
138 return PM3_EINVARG;
141 uint32_t baudrate = br * 1000000;
142 if (baudrate != FLASH_BAUD && baudrate != FLASH_MINBAUD) {
143 PrintAndLogEx(ERR, "wrong baudrate. Only 24 or 48 is allowed");
144 return PM3_EINVARG;
146 SendCommandNG(CMD_FLASHMEM_SET_SPIBAUDRATE, (uint8_t *)&baudrate, sizeof(uint32_t));
147 return PM3_SUCCESS;
150 static int CmdFlashMemLoad(const char *Cmd) {
152 CLIParserContext *ctx;
153 CLIParserInit(&ctx, "mem load",
154 "Loads binary file into flash memory on device\n"
155 "Warning: mem area to be written must have been wiped first\n"
156 "( this is already taken care when loading dictionaries )",
157 "mem load -f myfile -> upload file myfile values at default offset 0\n"
158 "mem load -f myfile -o 1024 -> upload file myfile values at offset 1024\n"
159 "mem load -f mfc_default_keys -m -> upload MFC keys\n"
160 "mem load -f t55xx_default_pwds -t -> upload T55XX passwords\n"
161 "mem load -f iclass_default_keys -i -> upload iCLASS keys\n"
164 void *argtable[] = {
165 arg_param_begin,
166 arg_int0("o", "offset", "<dec>", "offset in memory"),
167 arg_lit0("m", "mifare,mfc", "upload 6 bytes keys (mifare key dictionary)"),
168 arg_lit0("i", "iclass", "upload 8 bytes keys (iClass key dictionary)"),
169 arg_lit0("t", "t55xx", "upload 4 bytes keys (password dictionary)"),
170 arg_strx0("f", "file", "<filename>", "file name"),
171 arg_param_end
173 CLIExecWithReturn(ctx, Cmd, argtable, false);
175 int offset = arg_get_int_def(ctx, 1, 0);
176 bool is_mfc = arg_get_lit(ctx, 2);
177 bool is_iclass = arg_get_lit(ctx, 3);
178 bool is_t55xx = arg_get_lit(ctx, 4);
179 int fnlen = 0;
180 char filename[FILE_PATH_SIZE] = {0};
181 CLIParamStrToBuf(arg_get_str(ctx, 5), (uint8_t *)filename, FILE_PATH_SIZE, &fnlen);
182 CLIParserFree(ctx);
184 Dictionary_t d = DICTIONARY_NONE;
185 if (is_mfc) {
186 d = DICTIONARY_MIFARE;
187 PrintAndLogEx(INFO, "treating file as MIFARE Classic keys");
188 } else if (is_iclass) {
189 d = DICTIONARY_ICLASS;
190 PrintAndLogEx(INFO, "treating file as iCLASS keys");
191 } else if (is_t55xx) {
192 d = DICTIONARY_T55XX;
193 PrintAndLogEx(INFO, "treating file as T55xx passwords");
196 size_t datalen = 0;
197 uint32_t keycount = 0;
198 int res = 0;
199 uint8_t *data = calloc(FLASH_MEM_MAX_SIZE, sizeof(uint8_t));
201 switch (d) {
202 case DICTIONARY_MIFARE:
203 offset = DEFAULT_MF_KEYS_OFFSET;
204 res = loadFileDICTIONARY(filename, data + 2, &datalen, 6, &keycount);
205 if (res || !keycount) {
206 free(data);
207 return PM3_EFILE;
209 // limited space on flash mem
210 if (keycount > 0xFFFF)
211 keycount &= 0xFFFF;
213 data[0] = (keycount >> 0) & 0xFF;
214 data[1] = (keycount >> 8) & 0xFF;
215 datalen += 2;
216 break;
217 case DICTIONARY_T55XX:
218 offset = DEFAULT_T55XX_KEYS_OFFSET;
219 res = loadFileDICTIONARY(filename, data + 2, &datalen, 4, &keycount);
220 if (res || !keycount) {
221 free(data);
222 return PM3_EFILE;
224 // limited space on flash mem
225 if (keycount > 0xFFFF)
226 keycount &= 0xFFFF;
228 data[0] = (keycount >> 0) & 0xFF;
229 data[1] = (keycount >> 8) & 0xFF;
230 datalen += 2;
231 break;
232 case DICTIONARY_ICLASS:
233 offset = DEFAULT_ICLASS_KEYS_OFFSET;
234 res = loadFileDICTIONARY(filename, data + 2, &datalen, 8, &keycount);
235 if (res || !keycount) {
236 free(data);
237 return PM3_EFILE;
239 // limited space on flash mem
240 if (keycount > 0xFFFF)
241 keycount &= 0xFFFF;
243 data[0] = (keycount >> 0) & 0xFF;
244 data[1] = (keycount >> 8) & 0xFF;
245 datalen += 2;
246 break;
247 case DICTIONARY_NONE:
248 res = loadFile_safe(filename, ".bin", (void **)&data, &datalen);
249 if (res != PM3_SUCCESS) {
250 free(data);
251 return PM3_EFILE;
254 if (datalen > FLASH_MEM_MAX_SIZE) {
255 PrintAndLogEx(ERR, "error, filesize is larger than available memory");
256 free(data);
257 return PM3_EOVFLOW;
259 break;
261 // not needed when we transite to loadxxxx_safe methods.(iceman)
262 uint8_t *newdata = realloc(data, datalen);
263 if (newdata == NULL) {
264 free(data);
265 return PM3_EMALLOC;
266 } else {
267 data = newdata;
270 //Send to device
271 uint32_t bytes_sent = 0;
272 uint32_t bytes_remaining = datalen;
275 // fast push mode
276 conn.block_after_ACK = true;
278 while (bytes_remaining > 0) {
279 uint32_t bytes_in_packet = MIN(FLASH_MEM_BLOCK_SIZE, bytes_remaining);
281 clearCommandBuffer();
283 flashmem_old_write_t payload = {
284 .startidx = offset + bytes_sent,
285 .len = bytes_in_packet,
287 memcpy(payload.data, data + bytes_sent, bytes_in_packet);
288 SendCommandNG(CMD_FLASHMEM_WRITE, (uint8_t *)&payload, sizeof(payload));
290 bytes_remaining -= bytes_in_packet;
291 bytes_sent += bytes_in_packet;
293 PacketResponseNG resp;
294 if (WaitForResponseTimeout(CMD_FLASHMEM_WRITE, &resp, 2000) == false) {
295 PrintAndLogEx(WARNING, "timeout while waiting for reply.");
296 conn.block_after_ACK = false;
297 free(data);
298 return PM3_ETIMEOUT;
301 if (resp.status != PM3_SUCCESS) {
302 conn.block_after_ACK = false;
303 PrintAndLogEx(FAILED, "Flash write fail [offset %u]", bytes_sent);
304 free(data);
305 return PM3_EFLASH;
309 conn.block_after_ACK = false;
310 free(data);
311 PrintAndLogEx(SUCCESS, "Wrote "_GREEN_("%zu")" bytes to offset "_GREEN_("%u"), datalen, offset);
312 return PM3_SUCCESS;
315 static int CmdFlashMemDump(const char *Cmd) {
317 CLIParserContext *ctx;
318 CLIParserInit(&ctx, "mem dump",
319 "Dumps flash memory on device into a file or view in console",
320 "mem dump -f myfile -> download all flashmem to file\n"
321 "mem dump --view -o 262015 --len 128 -> display 128 bytes from offset 262015 (RSA sig)\n"
322 "mem dump --view -f myfile -o 241664 --len 58 -> display 58 bytes from offset 241664 and save to file"
325 void *argtable[] = {
326 arg_param_begin,
327 arg_int0("o", "offset", "<dec>", "offset in memory"),
328 arg_int0("l", "len", "<dec>", "length"),
329 arg_lit0("v", "view", "view dump"),
330 arg_strx0("f", "file", "<filename>", "file name"),
331 arg_int0("c", "cols", "<dec>", "column breaks (def 32)"),
332 arg_param_end
334 CLIExecWithReturn(ctx, Cmd, argtable, false);
336 int offset = arg_get_int_def(ctx, 1, 0);
337 int len = arg_get_int_def(ctx, 2, FLASH_MEM_MAX_SIZE);
338 bool view = arg_get_lit(ctx, 3);
339 int fnlen = 0;
340 char filename[FILE_PATH_SIZE] = {0};
341 CLIParamStrToBuf(arg_get_str(ctx, 4), (uint8_t *)filename, FILE_PATH_SIZE, &fnlen);
342 int breaks = arg_get_int_def(ctx, 5, 32);
343 CLIParserFree(ctx);
345 uint8_t *dump = calloc(len, sizeof(uint8_t));
346 if (!dump) {
347 PrintAndLogEx(ERR, "error, cannot allocate memory ");
348 return PM3_EMALLOC;
351 PrintAndLogEx(INFO, "downloading "_YELLOW_("%u")" bytes from flash memory", len);
352 if (!GetFromDevice(FLASH_MEM, dump, len, offset, NULL, 0, NULL, -1, true)) {
353 PrintAndLogEx(FAILED, "ERROR; downloading from flash memory");
354 free(dump);
355 return PM3_EFLASH;
358 if (view) {
359 PrintAndLogEx(INFO, "---- " _CYAN_("data") " ---------------");
360 print_hex_break(dump, len, breaks);
363 if (filename[0] != '\0') {
364 saveFile(filename, ".bin", dump, len);
365 saveFileEML(filename, dump, len, 16);
368 free(dump);
369 return PM3_SUCCESS;
372 static int CmdFlashMemWipe(const char *Cmd) {
374 CLIParserContext *ctx;
375 CLIParserInit(&ctx, "mem wipe",
376 "Wipe flash memory on device, which fills it with 0xFF\n"
377 _WHITE_("[ ") _RED_("!!! OBS") _WHITE_(" ] use with caution"),
378 "mem wipe -p 0 -> wipes first page"
379 // "mem wipe -i -> inital total wipe"
382 void *argtable[] = {
383 arg_param_begin,
384 arg_int0("p", NULL, "<dec>", "0,1,2 page memory"),
385 // arg_lit0("i", NULL, "inital total wipe"),
386 arg_param_end
388 CLIExecWithReturn(ctx, Cmd, argtable, false);
390 bool initalwipe = false;
391 int page = arg_get_int_def(ctx, 1, -1);
392 // initalwipe = arg_get_lit(ctx, 2);
393 CLIParserFree(ctx);
395 if (page < 0 || page > 2) {
396 PrintAndLogEx(WARNING, "page must be 0, 1 or 2");
397 return PM3_EINVARG;
400 clearCommandBuffer();
401 SendCommandMIX(CMD_FLASHMEM_WIPE, page, initalwipe, 0, NULL, 0);
402 PacketResponseNG resp;
403 if (!WaitForResponseTimeout(CMD_ACK, &resp, 8000)) {
404 PrintAndLogEx(WARNING, "timeout while waiting for reply.");
405 return PM3_ETIMEOUT;
408 const char *msg = "Flash WIPE ";
409 uint8_t isok = resp.oldarg[0] & 0xFF;
410 if (isok)
411 PrintAndLogEx(SUCCESS, "%s ( " _GREEN_("ok")" )", msg);
412 else {
413 PrintAndLogEx(FAILED, "%s ( " _RED_("failed") " )", msg);
414 return PM3_EFLASH;
417 return PM3_SUCCESS;
420 static int CmdFlashMemInfo(const char *Cmd) {
422 CLIParserContext *ctx;
423 CLIParserInit(&ctx, "mem info",
424 "Collect signature and verify it from flash memory",
425 "mem info"
428 void *argtable[] = {
429 arg_param_begin,
430 arg_lit0("s", "sign", "create a signature"),
431 arg_str0("d", NULL, "<hex>", "flash memory id, 8 hex bytes"),
432 arg_str0("p", "pem", "<fn>", "key in PEM format"),
433 arg_lit0("v", "verbose", "verbose output"),
434 // arg_lit0("w", "write", "write signature to flash memory"),
435 arg_param_end
437 CLIExecWithReturn(ctx, Cmd, argtable, true);
439 bool shall_sign = arg_get_lit(ctx, 1);
441 int dlen = 0;
442 uint8_t id[8] = {0};
443 int res = CLIParamHexToBuf(arg_get_str(ctx, 2), id, sizeof(id), &dlen);
445 int pemlen = 0;
446 char pem_fn[FILE_PATH_SIZE] = {0};
447 CLIParamStrToBuf(arg_get_str(ctx, 3), (uint8_t *)pem_fn, FILE_PATH_SIZE, &pemlen);
449 bool verbose = arg_get_lit(ctx, 4);
450 bool shall_write = false;
451 // shall_write = arg_get_lit(ctx, 5);
452 CLIParserFree(ctx);
454 if (res || (dlen > 0 && dlen < sizeof(id))) {
455 PrintAndLogEx(FAILED, "Error parsing flash memory id, expect 8, got %d", dlen);
456 return PM3_EINVARG;
459 // set up PK key context now.
460 mbedtls_pk_context pkctx;
461 mbedtls_pk_init(&pkctx);
462 bool got_private = false;
463 // PEM
464 if (pemlen) {
465 // PEM file
466 char *path = NULL;
467 if (searchFile(&path, RESOURCES_SUBDIR, pem_fn, ".pem", true) != PM3_SUCCESS) {
468 if (searchFile(&path, RESOURCES_SUBDIR, pem_fn, "", false) != PM3_SUCCESS) {
469 return PM3_EFILE;
473 PrintAndLogEx(INFO, "loading file `" _YELLOW_("%s") "`" NOLF, path);
475 // load private
476 res = mbedtls_pk_parse_keyfile(&pkctx, path, NULL);
477 free(path);
478 //res = mbedtls_pk_parse_public_keyfile(&pkctx, path);
479 if (res == 0) {
480 PrintAndLogEx(NORMAL, " ( " _GREEN_("ok") " )");
481 } else {
482 PrintAndLogEx(NORMAL, " ( " _RED_("fail") " )");
483 mbedtls_pk_free(&pkctx);
484 return PM3_EFILE;
487 mbedtls_rsa_context *rsa = (mbedtls_rsa_context *)pkctx.pk_ctx;
488 if (rsa == NULL) {
489 PrintAndLogEx(FAILED, "failed to allocate rsa context memory");
490 return PM3_EMALLOC;
492 got_private = true;
493 } else {
495 // it not loaded, we need to setup the context manually
496 if (mbedtls_pk_setup(&pkctx, mbedtls_pk_info_from_type((mbedtls_pk_type_t) MBEDTLS_PK_RSA)) != 0) {
497 PrintAndLogEx(FAILED, "failed, mbedtls_pk_setup returned ");
498 return PM3_ESOFT;
502 // validate devicesignature data
503 rdv40_validation_t mem;
504 res = rdv4_get_signature(&mem);
505 if (res != PM3_SUCCESS) {
506 return res;
509 res = rdv4_validate(&mem);
511 // Flash ID hash (sha1)
512 uint8_t sha_hash[20] = {0};
513 mbedtls_sha1(mem.flashid, sizeof(mem.flashid), sha_hash);
515 // print header
516 PrintAndLogEx(NORMAL, "");
517 PrintAndLogEx(INFO, "--- " _CYAN_("Flash memory Information") " ---------");
518 PrintAndLogEx(INFO, "ID................... %s", sprint_hex_inrow(mem.flashid, sizeof(mem.flashid)));
519 PrintAndLogEx(INFO, "SHA1................. %s", sprint_hex_inrow(sha_hash, sizeof(sha_hash)));
520 PrintAndLogEx(NORMAL, "");
521 PrintAndLogEx(INFO, "--- " _CYAN_("RDV4 RSA signature") " ---------------");
522 for (int i = 0; i < (sizeof(mem.signature) / 32); i++) {
523 PrintAndLogEx(INFO, " %s", sprint_hex_inrow(mem.signature + (i * 32), 32));
525 PrintAndLogEx(
526 (res == PM3_SUCCESS) ? SUCCESS : FAILED,
527 "Signature............ ( %s )",
528 (res == PM3_SUCCESS) ? _GREEN_("ok") : _RED_("fail")
530 PrintAndLogEx(NORMAL, "");
532 mbedtls_rsa_context *rsa = NULL;
534 if (got_private) {
535 rsa = mbedtls_pk_rsa(pkctx);
536 rsa->padding = MBEDTLS_RSA_PKCS_V15;
537 rsa->hash_id = 0;
538 rsa->len = RRG_RSA_KEY_LEN;
539 } else {
541 rsa = (mbedtls_rsa_context *)calloc(1, sizeof(mbedtls_rsa_context));
542 mbedtls_rsa_init(rsa, MBEDTLS_RSA_PKCS_V15, 0);
543 rsa->len = RRG_RSA_KEY_LEN;
545 // add public key
546 mbedtls_mpi_read_string(&rsa->N, 16, RRG_RSA_N);
547 mbedtls_mpi_read_string(&rsa->E, 16, RRG_RSA_E);
550 PrintAndLogEx(INFO, "--- " _CYAN_("RDV4 RSA Public key") " --------------");
551 if (verbose) {
552 char str_exp[10];
553 char str_pk[261];
554 size_t exlen = 0, pklen = 0;
555 mbedtls_mpi_write_string(&rsa->E, 16, str_exp, sizeof(str_exp), &exlen);
556 mbedtls_mpi_write_string(&rsa->N, 16, str_pk, sizeof(str_pk), &pklen);
558 PrintAndLogEx(INFO, "Len.................. %"PRIu64, rsa->len);
559 PrintAndLogEx(INFO, "Exponent............. %s", str_exp);
560 PrintAndLogEx(INFO, "Public key modulus N");
561 PrintAndLogEx(INFO, " %.64s", str_pk);
562 PrintAndLogEx(INFO, " %.64s", str_pk + 64);
563 PrintAndLogEx(INFO, " %.64s", str_pk + 128);
564 PrintAndLogEx(INFO, " %.64s", str_pk + 192);
565 PrintAndLogEx(NORMAL, "");
568 bool is_keyok = (mbedtls_rsa_check_pubkey(rsa) == 0);
569 PrintAndLogEx(
570 (is_keyok) ? SUCCESS : FAILED,
571 "RRG/Iceman RSA public key check.... ( %s )",
572 (is_keyok) ? _GREEN_("ok") : _RED_("fail")
575 is_keyok = (mbedtls_rsa_check_privkey(rsa) == 0);
576 if (verbose) {
577 PrintAndLogEx(
578 (is_keyok) ? SUCCESS : FAILED,
579 "RRG/Iceman RSA private key check... ( %s )",
580 (is_keyok) ? _GREEN_("ok") : _YELLOW_("N/A")
584 // to be verified
585 uint8_t from_device[RRG_RSA_KEY_LEN];
586 memcpy(from_device, mem.signature, RRG_RSA_KEY_LEN);
588 // to be signed
589 uint8_t sign[RRG_RSA_KEY_LEN];
590 memset(sign, 0, RRG_RSA_KEY_LEN);
592 // Signing (private key)
593 if (shall_sign) {
595 if (is_keyok) {
597 PrintAndLogEx(NORMAL, "");
598 PrintAndLogEx(INFO, "--- " _CYAN_("Enter signing") " --------------------");
600 if (dlen == 8) {
601 mbedtls_sha1(id, sizeof(id), sha_hash);
603 PrintAndLogEx(INFO, "Signing....... %s", sprint_hex_inrow(sha_hash, sizeof(sha_hash)));
605 int is_signed = mbedtls_rsa_pkcs1_sign(rsa, NULL, NULL, MBEDTLS_RSA_PRIVATE, MBEDTLS_MD_SHA1, 20, sha_hash, sign);
606 PrintAndLogEx(
607 (is_signed == 0) ? SUCCESS : FAILED,
608 "RSA signing... ( %s )",
609 (is_signed == 0) ? _GREEN_("ok") : _RED_("fail")
612 if (shall_write) {
613 rdv4_sign_write(sign, RRG_RSA_KEY_LEN);
615 PrintAndLogEx(INFO, "New signature");
616 for (int i = 0; i < (sizeof(sign) / 32); i++) {
617 PrintAndLogEx(INFO, " %s", sprint_hex_inrow(sign + (i * 32), 32));
619 } else {
620 PrintAndLogEx(FAILED, "no private key available to sign");
624 // Verify (public key)
625 bool is_verified = (mbedtls_rsa_pkcs1_verify(rsa, NULL, NULL, MBEDTLS_RSA_PUBLIC, MBEDTLS_MD_SHA1, 20, sha_hash, from_device) == 0);
627 mbedtls_pk_free(&pkctx);
629 PrintAndLogEx(NORMAL, "");
630 PrintAndLogEx(
631 (is_verified) ? SUCCESS : FAILED,
632 "Genuine Proxmark3 RDV4 signature detected... %s",
633 (is_verified) ? ":heavy_check_mark:" : ":x:"
635 PrintAndLogEx(NORMAL, "");
636 return PM3_SUCCESS;
639 static command_t CommandTable[] = {
640 {"spiffs", CmdFlashMemSpiFFS, IfPm3Flash, "{ SPI File system }"},
641 {"help", CmdHelp, AlwaysAvailable, "This help"},
642 {"baudrate", CmdFlashmemSpiBaud, IfPm3Flash, "Set Flash memory Spi baudrate"},
643 {"dump", CmdFlashMemDump, IfPm3Flash, "Dump data from flash memory"},
644 {"info", CmdFlashMemInfo, IfPm3Flash, "Flash memory information"},
645 {"load", CmdFlashMemLoad, IfPm3Flash, "Load data to flash memory"},
646 {"wipe", CmdFlashMemWipe, IfPm3Flash, "Wipe data from flash memory"},
647 {NULL, NULL, NULL, NULL}
650 static int CmdHelp(const char *Cmd) {
651 (void)Cmd; // Cmd is not used so far
652 CmdsHelp(CommandTable);
653 return PM3_SUCCESS;
656 int CmdFlashMem(const char *Cmd) {
657 clearCommandBuffer();
658 return CmdsParse(CommandTable, Cmd);