πŸ’Ύ Radikant-NVS-C

Non Volatile Storage Library for ESP32

NVS

Introduction

NVS (Non-Volatile-Storage) is a special partition in the ESP32 microcontroller Flash Memory. The ESPx-family firmware can read/write data to this parition and is not part regular Flash. In a production line, you cannot hardcode unique data like into the main firmware source code therefore the NVS Partition is usefull to store information like cryprographic certificates, ip adresses, WiFi Passwords, serial numbers or secret keys. It’s unique property is that the data will persist across reboots, and unlike the e-fuse it can also be overwritten/changes many times.

The Espessif Python tool takes a .csv file and then can convert that to a valid NVS paritition and store it to the disk and then another flash utility like ESP Tool can be be used to subsequently upload the NVS to the device.

Radikant-NVS-C can generate valid NVS paritions in-memory and change it's contents in runtime on the fly without the use of the python tool. This is incredibly usefull in a production environment since the NVS partition can be uploaded seperate from the main app, bootloader and parition scheme.

For Example it is possible to use Radikant-Crypto-C to generate a Cryptographic key pair and use Radikant-NVS-C to write this key pair to a valid NVS paritiion in-memory, and use Radikant-Flasher-C to upload the parition directly to the target device.

Futhermore the C binarires are easily embeddable in almost every programming language, this ceates the posibility to create mobile android/ios apps that is are able to interact directly with devices in the field, which can be usefull for field technicans, factory QC if they need to interact with the NVS data directly.

Writing

FileEditViewProject
β–Ά
β– 
NVS-Gen β€” nvs_builder.c
int Write_Example()
{
NVS_Partition_t Partition = {0};
NVS_Page_t Page_1 = {0};
nvs_init_page(&Page_1);
nvs_init_partition(&Partition, 1);
 
const char *Cert =
"-----BEGIN EC PRIVATE KEY-----\n"
"AwEHoUQDQgAEHBvYCIvQxScEi7Sa+CcxB1bz9DDmpgAVlC2qxwPbt8Z9ihGdOfSi\n"
"hPAx0pk2n/Td2/Tim/szAvLVuyfww2tFqA==\n"
"-----END EC PRIVATE KEY-----\n";
 
int index_1 = 0;
add_header(&Page_1, NVS_STATE_FULL, SEQUENCE_0, VERSION2);
add_entry_namespace(NAMESPACE_1, &Page_1, &index_1, NS_entry, "dummyNamespace");
add_entry_integer(NAMESPACE_1, &Page_1, &index_1, U8, "dummyU8Key", 127);
add_entry_integer(NAMESPACE_1, &Page_1, &index_1, I8, "dummyI8Key", 127);
add_entry_string(NAMESPACE_1, &Page_1, &index_1, SZ, "Certificate", Cert);
 
Partition.Pages[0] = Page_1;
 
const char out_file[] = "/Users/charrlie/Desktop/nvs.bin";
return nvs_write_partition_to_file(out_file, &Partition);
}
β– β– β– β– β– β– β– β– β– β– β– β– β– β– β– β– β– β– β– β– β– β– β– β–  RAW BUFFER β– β– β– β– β– β– β– β– β– β– β– β– β– β– β– β– β– β– β– β– β– β– β– β– β–  β– β– β– β– β– β– β– β– β– β– β– β–  NVS_PAGE β– β– β– β– β– β– β– β– β– β– β–  0 HEADER FC FF FF FF 00 00 00 00 FE FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF 84 2D BA B9 CRC βœ“ 1 BITMAP AA AA FA FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF entries = 10 2 NS 00 01 01 FF C9 3E A4 07 64 75 6D 6D 79 4E 61 6D 65 73 70 61 63 65 00 00 01 FF FF FF FF FF FF FF CRC βœ“ Span 1 3 U8 01 01 01 FF 3D 18 8E C3 64 75 6D 6D 79 55 38 4B 65 79 00 00 00 00 00 00 7F FF FF FF FF FF FF FF CRC βœ“ Span 1 4 I8 01 11 01 FF 05 98 71 6E 64 75 6D 6D 79 49 38 4B 65 79 00 00 00 00 00 00 7F FF FF FF FF FF FF FF CRC βœ“ Span 1 5 SZ 01 21 07 FF 0F 91 41 7E 73 6F 6D 65 73 74 72 69 6E 67 00 00 00 00 00 00 A3 00 FF FF F8 72 3C F9 CRC βœ“ Span 7 6 ???? 2D 2D 2D 2D 2D 42 45 47 49 4E 20 45 43 20 50 52 49 56 41 54 45 20 4B 45 59 2D 2D 2D 2D 2D 0A 41 7 ???? 77 45 48 6F 55 51 44 51 67 41 45 48 42 76 59 43 49 76 51 78 53 63 45 69 37 53 61 2B 43 63 78 42 8 ???? 31 62 7A 39 44 44 6D 70 67 41 56 6C 43 32 71 78 77 50 62 74 38 5A 39 69 68 47 64 4F 66 53 69 0A 9 ???? 68 50 41 78 30 70 6B 32 6E 2F 54 64 32 2F 54 69 6D 2F 73 7A 41 76 4C 56 75 79 66 77 77 32 74 46 10 BLOB 71 41 3D 3D 0A 2D 2D 2D 2D 2D 45 4E 44 20 45 43 20 50 52 49 56 41 54 45 20 4B 45 59 2D 2D 2D 2D 11 ???? 2D 0A 00 FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF 12 EMPTY FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF 13 EMPTY FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF 14 EMPTY FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF 15 EMPTY FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF 16 EMPTY FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF

Reading

FileEditViewProject
β–Ά
β– 
NVS-Reader β€” main.c
int Read_Example()
{
NVS_Page_t NVS_Page = {0};
const char *file = "/Users/charrlie/Desktop/nvs.bin";
 
read_file_to_buffer(file, &NVS_Page);
print_Page_Buffer_hex("NVS_PAGE", &NVS_Page);
 
read_header(&NVS_Page);
print_header_hex(&NVS_Page.Header); // print
 
read_bitmap(&NVS_Page);
print_bitmap_hex(&NVS_Page.Bitmap); // print
 
read_entries(&NVS_Page);
print_page(&NVS_Page); // print
 
return 0;
}
MRK INDEX NS Type Span Chunk CRC32 Key Data --------------------------------------------------------------------------------------------------------- DATA 0 0 U8 1 255 TEST CRC dummyNamespace 1 DATA 1 1 U8 1 255 TEST CRC dummyU8Key 127 DATA 2 1 I8 1 255 TEST CRC dummyI8Key 127 SZ 3 1 SZ 7 255 TEST CRC somestring οΏ½ TXT 4 -----BEGIN EC PRIVATE KEY----- A TXT 5 wEHoUQDQgAEHBvYCIvQxScEi7Sa+CcxB TXT 6 1bz9DDmpgAVlC2qxwPbt8Z9ihGdOfSi TXT 7 hPAx0pk2n/Td2/Tim/szAvLVuyfww2tF TXT 8 qA== -----END EC PRIVATE KEY---- TXT 9 -