/** * \brief Saves the random seed to EEPROM. * * During system startup, noise sources typically won't have accumulated * much entropy. But startup is usually the time when the system most * needs to generate random data for session keys, IV's, and the like. * * The purpose of this function is to pass some of the accumulated entropy * from one session to the next after a loss of power. Thus, once the system * has been running for a while it will get progressively better at generating * random values and the accumulated entropy will not be completely lost. * * Normally it isn't necessary to call save() directly. The loop() function * will automatically save the seed on a periodic basis (default of 1 hour). * * The seed that is saved is generated in such a way that it cannot be used * to predict random values that were generated previously or subsequently * in the current session. So a compromise of the EEPROM contents of a * captured device should not result in compromise of random values * that have already been generated. However, if power is lost and the * system restarted, then there will be a short period of time where the * random state will be predictable from the seed. For this reason it is * very important to stir() in new noise data at startup. * * \sa loop(), stir() */ void RNGClass::save() { // Generate random data from the current state and save // that as the seed. Then force a rekey. ++(block[12]); ChaCha::hashCore(stream, block, RNG_ROUNDS); #if defined(RNG_EEPROM) // We shorten the seed from 48 bytes to 47 to leave room for // the CRC-8 value. We do this to align the data on an 8-byte // boundary in EERPOM. int address = RNG_EEPROM_ADDRESS; eeprom_write_block(stream, (void *)address, SEED_SIZE - 1); eeprom_write_byte((uint8_t *)(address + SEED_SIZE - 1), crypto_crc8('S', stream, SEED_SIZE - 1)); #elif defined(RNG_DUE_TRNG) unsigned posn; ((uint32_t *)(RNG_SEED_ADDR))[0] = crypto_crc8('S', stream, SEED_SIZE); for (posn = 0; posn < 12; ++posn) ((uint32_t *)(RNG_SEED_ADDR))[posn + 1] = stream[posn]; for (posn = 13; posn < (RNG_FLASH_PAGE_SIZE / 4); ++posn) ((uint32_t *)(RNG_SEED_ADDR))[posn + 13] = 0xFFFFFFFF; eraseAndWriteSeed(); #elif defined(RNG_ESP_NVS) // Save the seed into ESP non-volatile storage (NVS). nvs_handle handle = 0; if (nvs_open("rng", NVS_READWRITE, &handle) == 0) { nvs_erase_all(handle); nvs_set_blob(handle, "seed", stream, SEED_SIZE); nvs_commit(handle); nvs_close(handle); } #endif rekey(); timer = millis(); }
int alloc_file(struct lws_context *context, const char *filename, uint8_t **buf, lws_filepos_t *amount) { nvs_handle nvh; size_t s; int n = 0; ESP_ERROR_CHECK(nvs_open("lws-station", NVS_READWRITE, &nvh)); if (nvs_get_blob(nvh, filename, NULL, &s) != ESP_OK) { n = 1; goto bail; } *buf = lws_malloc(s, "alloc_file"); if (!*buf) { n = 2; goto bail; } if (nvs_get_blob(nvh, filename, (char *)*buf, &s) != ESP_OK) { lws_free(*buf); n = 1; goto bail; } *amount = s; bail: nvs_close(nvh); return n; }
void ESP32_Set_NVS_Status(esp_hardware_esp32_t hardware, bool enable){ nvs_handle hardwareHandle; uint32_t status; if(enable) status = 1; else status = 0; nvs_open("nvs",NVS_READWRITE,&hardwareHandle); nvs_set_u32(hardwareHandle,ESP32_hardwareName(hardware),status); nvs_close(hardwareHandle); }
config_t *config_new(const char *filename) { assert(filename != NULL); config_t *config = config_new_empty(); if (!config) { return NULL; } esp_err_t err; nvs_handle fp; err = nvs_open(filename, NVS_READWRITE, &fp); if (err != ESP_OK) { if (err == ESP_ERR_NVS_NOT_INITIALIZED) { LOG_ERROR("%s: NVS not initialized. " "Call nvs_flash_init before initializing bluetooth.", __func__); } else { LOG_ERROR("%s unable to open NVS namespace '%s'\n", __func__, filename); } config_free(config); return NULL; } config_parse(fp, config); nvs_close(fp); return config; }
/** * Save our connection info for retrieval on a subsequent restart. */ static void saveConnectionInfo(connection_info_t *pConnectionInfo) { nvs_handle handle; ESP_ERROR_CHECK(nvs_open(BOOTWIFI_NAMESPACE, NVS_READWRITE, &handle)); ESP_ERROR_CHECK(nvs_set_blob(handle, KEY_CONNECTION_INFO, pConnectionInfo, sizeof(connection_info_t))); ESP_ERROR_CHECK(nvs_set_u32(handle, KEY_VERSION, g_version)); ESP_ERROR_CHECK(nvs_commit(handle)); nvs_close(handle); } // setConnectionInfo
bool ESP32_Get_NVS_Status(esp_hardware_esp32_t hardware){ esp_err_t err;nvs_handle hardwareHandle; uint32_t status; nvs_open("nvs",NVS_READWRITE,&hardwareHandle); err = nvs_get_u32(hardwareHandle,ESP32_hardwareName(hardware),&status); if(err) { status = ESP32HARDWAREDEFAULT; nvs_set_u32(hardwareHandle,ESP32_hardwareName(hardware),ESP32HARDWAREDEFAULT); } nvs_close(hardwareHandle); return (bool) status; }
esp_err_t esp_phy_store_cal_data_to_nvs(const esp_phy_calibration_data_t* cal_data) { nvs_handle handle; esp_err_t err = nvs_open(PHY_NAMESPACE, NVS_READWRITE, &handle); if (err != ESP_OK) { ESP_LOGD(TAG, "%s: failed to open NVS namespace (0x%x)", __func__, err); return err; } else { err = store_cal_data_to_nvs_handle(handle, cal_data); nvs_close(handle); return err; } }
void dhcp_ip_addr_erase(void *netif) { nvs_handle nvs; struct netif *net = (struct netif *)netif; esp_interface_t netif_id = tcpip_adapter_get_esp_if(net); if(VALID_NETIF_ID(netif_id)) { if (nvs_open(DHCP_NAMESPACE, NVS_READWRITE, &nvs) == ESP_OK) { nvs_erase_key(nvs, interface_key[netif_id]); nvs_commit(nvs); nvs_close(nvs); } } }
/** * Retrieve the connection info. A rc==0 means ok. */ static int getConnectionInfo(connection_info_t *pConnectionInfo) { nvs_handle handle; size_t size; esp_err_t err; uint32_t version; err = nvs_open(BOOTWIFI_NAMESPACE, NVS_READWRITE, &handle); if (err != 0) { ESP_LOGE(tag, "nvs_open: %x", err); return -1; } // Get the version that the data was saved against. err = nvs_get_u32(handle, KEY_VERSION, &version); if (err != ESP_OK) { ESP_LOGD(tag, "No version record found (%d).", err); nvs_close(handle); return -1; } // Check the versions match if ((version & 0xff00) != (g_version & 0xff00)) { ESP_LOGD(tag, "Incompatible versions ... current is %x, found is %x", version, g_version); nvs_close(handle); return -1; } size = sizeof(connection_info_t); err = nvs_get_blob(handle, KEY_CONNECTION_INFO, pConnectionInfo, &size); if (err != ESP_OK) { ESP_LOGD(tag, "No connection record found (%d).", err); nvs_close(handle); return -1; } if (err != ESP_OK) { ESP_LOGE(tag, "nvs_open: %x", err); nvs_close(handle); return -1; } // Cleanup nvs_close(handle); // Do a sanity check on the SSID if (strlen(pConnectionInfo->ssid) == 0) { ESP_LOGD(tag, "NULL ssid detected"); return -1; } return 0; } // getConnectionInfo
esp_err_t esp_phy_load_cal_data_from_nvs(esp_phy_calibration_data_t* out_cal_data) { nvs_handle handle; esp_err_t err = nvs_open(PHY_NAMESPACE, NVS_READONLY, &handle); if (err == ESP_ERR_NVS_NOT_INITIALIZED) { ESP_LOGE(TAG, "%s: NVS has not been initialized. " "Call nvs_flash_init before starting WiFi/BT.", __func__); } else if (err != ESP_OK) { ESP_LOGD(TAG, "%s: failed to open NVS namespace (0x%x)", __func__, err); return err; } err = load_cal_data_from_nvs_handle(handle, out_cal_data); nvs_close(handle); return err; }
void dhcp_ip_addr_store(void *netif) { nvs_handle nvs; struct netif *net = (struct netif *)netif; struct dhcp *dhcp = netif_dhcp_data(net); uint32_t ip_addr = dhcp->offered_ip_addr.addr; esp_interface_t netif_id = tcpip_adapter_get_esp_if(net); if(VALID_NETIF_ID(netif_id)) { if (restored_ip_addr[netif_id] != ip_addr) { if (nvs_open(DHCP_NAMESPACE, NVS_READWRITE, &nvs) == ESP_OK) { nvs_set_u32(nvs, interface_key[netif_id], ip_addr); nvs_commit(nvs); nvs_close(nvs); } } } }
bool dhcp_ip_addr_restore(void *netif) { nvs_handle nvs; bool err = false; struct netif *net = (struct netif *)netif; struct dhcp *dhcp = netif_dhcp_data(net); esp_interface_t netif_id = tcpip_adapter_get_esp_if(net); if(VALID_NETIF_ID(netif_id)) { uint32_t *ip_addr = &dhcp->offered_ip_addr.addr; if (nvs_open(DHCP_NAMESPACE, NVS_READONLY, &nvs) == ESP_OK) { if (nvs_get_u32(nvs, interface_key[netif_id], ip_addr) == ESP_OK) { restored_ip_addr[netif_id] = *ip_addr; err = true; } nvs_close(nvs); } } return err; }
/** * \brief Destroys the data in the random number pool and the saved seed * in EEPROM. * * This function attempts to throw away any data that could theoretically be * used to predict previous and future outputs of the random number generator * if the device is captured, sold, or otherwise compromised. * * After this function is called, begin() must be called again to * re-initialize the random number generator. * * \note The rand() and save() functions take some care to manage the * random number pool in a way that makes prediction of past outputs from a * captured state very difficult. Future outputs may be predictable if * noise or other high-entropy data is not mixed in with stir() on a * regular basis. * * \sa begin() */ void RNGClass::destroy() { clean(block); clean(stream); #if defined(RNG_EEPROM) int address = RNG_EEPROM_ADDRESS; for (int posn = 0; posn < SEED_SIZE; ++posn) eeprom_write_byte((uint8_t *)(address + posn), 0xFF); #elif defined(RNG_DUE_TRNG) for (unsigned posn = 0; posn < (RNG_FLASH_PAGE_SIZE / 4); ++posn) ((uint32_t *)(RNG_SEED_ADDR))[posn] = 0xFFFFFFFF; eraseAndWriteSeed(); #elif defined(RNG_ESP_NVS) nvs_handle handle = 0; if (nvs_open("rng", NVS_READWRITE, &handle) == 0) { nvs_erase_all(handle); nvs_commit(handle); nvs_close(handle); } #endif initialized = 0; }
/** * \brief Initializes the random number generator. * * \param tag A string that is stirred into the random pool at startup; * usually this should be a value that is unique to the application and * version such as "MyApp 1.0" so that different applications do not * generate the same sequence of values upon first boot. * * This function should be followed by calls to addNoiseSource() to * register the application's noise sources. * * \sa addNoiseSource(), stir(), save() */ void RNGClass::begin(const char *tag) { // Bail out if we have already done this. if (initialized) return; // Initialize the ChaCha20 input block from the saved seed. memcpy_P(block, tagRNG, sizeof(tagRNG)); memcpy_P(block + 4, initRNG, sizeof(initRNG)); #if defined(RNG_EEPROM) int address = RNG_EEPROM_ADDRESS; eeprom_read_block(stream, (const void *)address, SEED_SIZE); if (crypto_crc8('S', stream, SEED_SIZE - 1) == ((const uint8_t *)stream)[SEED_SIZE - 1]) { // We have a saved seed: XOR it with the initialization block. // Note: the CRC-8 value is included. No point throwing it away. for (int posn = 0; posn < 12; ++posn) block[posn + 4] ^= stream[posn]; } #elif defined(RNG_DUE_TRNG) // Do we have a seed saved in the last page of flash memory on the Due? if (crypto_crc8('S', ((const uint32_t *)RNG_SEED_ADDR) + 1, SEED_SIZE) == ((const uint32_t *)RNG_SEED_ADDR)[0]) { // XOR the saved seed with the initialization block. for (int posn = 0; posn < 12; ++posn) block[posn + 4] ^= ((const uint32_t *)RNG_SEED_ADDR)[posn + 1]; } // If the device has just been reprogrammed, there will be no saved seed. // XOR the initialization block with some output from the CPU's TRNG // to permute the state in a first boot situation after reprogramming. pmc_enable_periph_clk(ID_TRNG); REG_TRNG_CR = TRNG_CR_KEY(0x524E47) | TRNG_CR_ENABLE; REG_TRNG_IDR = TRNG_IDR_DATRDY; // Disable interrupts - we will poll. mixTRNG(); #endif #if defined(RNG_ESP_NVS) // Do we have a seed saved in ESP non-volatile storage (NVS)? nvs_handle handle = 0; if (nvs_open("rng", NVS_READONLY, &handle) == 0) { size_t len = 0; if (nvs_get_blob(handle, "seed", NULL, &len) == 0 && len == SEED_SIZE) { uint32_t seed[12]; if (nvs_get_blob(handle, "seed", seed, &len) == 0) { for (int posn = 0; posn < 12; ++posn) block[posn + 4] ^= seed[posn]; } clean(seed); } nvs_close(handle); } #endif #if defined(RNG_WORD_TRNG) // Mix in some output from a word-based TRNG to initialize the state. mixTRNG(); #endif // No entropy credits for the saved seed. credits = 0; // Trigger an automatic save once the entropy credits max out. firstSave = 1; // Rekey the random number generator immediately. rekey(); // Stir in the supplied tag data but don't credit any entropy to it. if (tag) stir((const uint8_t *)tag, strlen(tag)); #if defined(RNG_DUE_TRNG) // Stir in the unique identifier for the CPU so that different // devices will give different outputs even without seeding. stirUniqueIdentifier(); #elif defined(ESP8266) // ESP8266's have a 32-bit CPU chip ID and 32-bit flash chip ID // that we can use as a device unique identifier. uint32_t ids[2]; ids[0] = ESP.getChipId(); ids[1] = ESP.getFlashChipId(); stir((const uint8_t *)ids, sizeof(ids)); #elif defined(ESP32) // ESP32's have a MAC address that can be used as a device identifier. uint64_t mac = ESP.getEfuseMac(); stir((const uint8_t *)&mac, sizeof(mac)); #else // AVR devices don't have anything like a serial number so it is // difficult to make every device unique. Use the compilation // time and date to provide a little randomness across applications // if not across devices running the same pre-compiled application. tag = __TIME__ __DATE__; stir((const uint8_t *)tag, strlen(tag)); #endif #if defined(RNG_WATCHDOG) // Disable interrupts and reset the watchdog. cli(); wdt_reset(); // Clear the "reset due to watchdog" flag. MCUSR &= ~(1 << WDRF); // Enable the watchdog with the smallest duration (16ms) // and interrupt-only mode. _WD_CONTROL_REG |= (1 << _WD_CHANGE_BIT) | (1 << WDE); _WD_CONTROL_REG = (1 << WDIE); // Re-enable interrupts. The watchdog should be running. sei(); #endif // Re-save the seed to obliterate the previous value and to ensure // that if the system is reset without a call to save() that we won't // accidentally generate the same sequence of random data again. save(); // The RNG has now been initialized. initialized = 1; }
bool config_save(const config_t *config, const char *filename) { assert(config != NULL); assert(filename != NULL); assert(*filename != '\0'); esp_err_t err; int err_code = 0; nvs_handle fp; char *line = osi_calloc(1024); char *keyname = osi_calloc(sizeof(CONFIG_KEY) + 1); int config_size = get_config_size(config); char *buf = osi_calloc(config_size + 100); if (!line || !buf || !keyname) { err_code |= 0x01; goto error; } err = nvs_open(filename, NVS_READWRITE, &fp); if (err != ESP_OK) { if (err == ESP_ERR_NVS_NOT_INITIALIZED) { LOG_ERROR("%s: NVS not initialized. " "Call nvs_flash_init before initializing bluetooth.", __func__); } err_code |= 0x02; goto error; } int w_cnt, w_cnt_total = 0; for (const list_node_t *node = list_begin(config->sections); node != list_end(config->sections); node = list_next(node)) { const section_t *section = (const section_t *)list_node(node); w_cnt = snprintf(line, 1024, "[%s]\n", section->name); LOG_DEBUG("section name: %s, w_cnt + w_cnt_total = %d\n", section->name, w_cnt + w_cnt_total); memcpy(buf + w_cnt_total, line, w_cnt); w_cnt_total += w_cnt; for (const list_node_t *enode = list_begin(section->entries); enode != list_end(section->entries); enode = list_next(enode)) { const entry_t *entry = (const entry_t *)list_node(enode); LOG_DEBUG("(key, val): (%s, %s)\n", entry->key, entry->value); w_cnt = snprintf(line, 1024, "%s = %s\n", entry->key, entry->value); LOG_DEBUG("%s, w_cnt + w_cnt_total = %d", __func__, w_cnt + w_cnt_total); memcpy(buf + w_cnt_total, line, w_cnt); w_cnt_total += w_cnt; } // Only add a separating newline if there are more sections. if (list_next(node) != list_end(config->sections)) { buf[w_cnt_total] = '\n'; w_cnt_total += 1; } else { break; } } buf[w_cnt_total] = '\0'; if (w_cnt_total < CONFIG_FILE_MAX_SIZE) { snprintf(keyname, sizeof(CONFIG_KEY)+1, "%s%d", CONFIG_KEY, 0); err = nvs_set_blob(fp, keyname, buf, w_cnt_total); if (err != ESP_OK) { nvs_close(fp); err_code |= 0x04; goto error; } }else { uint count = (w_cnt_total / CONFIG_FILE_MAX_SIZE); for (int i = 0; i <= count; i++) { snprintf(keyname, sizeof(CONFIG_KEY)+1, "%s%d", CONFIG_KEY, i); if (i == count) { err = nvs_set_blob(fp, keyname, buf + i*CONFIG_FILE_MAX_SIZE, w_cnt_total - i*CONFIG_FILE_MAX_SIZE); LOG_DEBUG("save keyname = %s, i = %d, %d\n", keyname, i, w_cnt_total - i*CONFIG_FILE_MAX_SIZE); }else { err = nvs_set_blob(fp, keyname, buf + i*CONFIG_FILE_MAX_SIZE, CONFIG_FILE_MAX_SIZE); LOG_DEBUG("save keyname = %s, i = %d, %d\n", keyname, i, CONFIG_FILE_MAX_SIZE); } if (err != ESP_OK) { nvs_close(fp); err_code |= 0x04; goto error; } } } err = nvs_commit(fp); if (err != ESP_OK) { nvs_close(fp); err_code |= 0x08; goto error; } nvs_close(fp); osi_free(line); osi_free(buf); osi_free(keyname); return true; error: if (buf) { osi_free(buf); } if (line) { osi_free(line); } if (keyname) { osi_free(keyname); } if (err_code) { LOG_ERROR("%s, err_code: 0x%x\n", __func__, err_code); } return false; }