diff --git a/wled00/util.cpp b/wled00/util.cpp index cfaea2f0..8d71d16e 100644 --- a/wled00/util.cpp +++ b/wled00/util.cpp @@ -1159,60 +1159,61 @@ String computeSHA1(const String& input) { } #ifdef ESP32 -static String dump_raw_block(esp_efuse_block_t block) -{ - const int WORDS = 8; // ESP32: 8×32-bit words per block i.e. 256bits - uint32_t buf[WORDS] = {0}; - - const esp_efuse_desc_t d = { - .efuse_block = block, - .bit_start = 0, - .bit_count = WORDS * 32 - }; - const esp_efuse_desc_t* field[2] = { &d, NULL }; - - esp_err_t err = esp_efuse_read_field_blob(field, buf, WORDS * 32); - if (err != ESP_OK) { - return ""; +#include "esp_adc_cal.h" +uint32_t* generateDeviceFingerprint() { + uint32_t fp[2]; // create 64 bit fingerprint + esp_chip_info_t chip_info; + esp_chip_info(&chip_info); + esp_efuse_mac_get_default((uint8_t*)fp); + fp[1] ^= ESP.getFlashChipSize(); + fp[0] ^= chip_info.full_revision | (chip_info.model << 16); + // mix in ADC calibration data: + esp_adc_cal_characteristics_t ch; + #if SOC_ADC_MAX_BITWIDTH == 13 // S2 has 13 bit ADC + #define BIT_WIDTH ADC_WIDTH_BIT_13 + #else + #define BIT_WIDTH ADC_WIDTH_BIT_12 + #endif + esp_adc_cal_characterize(ADC_UNIT_1, ADC_ATTEN_DB_11, BIT_WIDTH, 1100, &ch); + fp[0] ^= ch.coeff_a; + fp[1] ^= ch.coeff_b; + if (ch.low_curve) { + for (int i = 0; i < 8; i++) { + fp[0] ^= ch.low_curve[i]; + } } - - String result = ""; - for (const unsigned int i : buf) { - char line[32]; - sprintf(line, "0x%08X", i); - result += line; + if (ch.high_curve) { + for (int i = 0; i < 8; i++) { + fp[1] ^= ch.high_curve[i]; + } } - return result; + char fp_string[17]; // 16 hex chars + null terminator + sprintf(fp_string, "%08X%08X", fp[1], fp[0]); + return String(fp_string); +} +#else // ESP8266 +String generateDeviceFingerprint() { + static uint32_t fp[2]; // create 64 bit fingerprint + WiFi.macAddress((uint8_t*)&fp); // use MAC address as fingerprint base + fp[0] ^= ESP.getFlashChipId(); + fp[1] ^= ESP.getFlashChipSize() | ESP.getFlashChipVendorId() << 16; + char fp_string[17]; // 16 hex chars + null terminator + sprintf(fp_string, "%08X%08X", fp[1], fp[0]); + return String(fp_string); } #endif - -// Generate a device ID based on SHA1 hash of MAC address salted with "WLED" +// Generate a device ID based on SHA1 hash of MAC address salted with other unique device info // Returns: original SHA1 + last 2 chars of double-hashed SHA1 (42 chars total) String getDeviceId() { static String cachedDeviceId = ""; - if (cachedDeviceId.length() > 0) return cachedDeviceId; - - uint8_t mac[6]; - WiFi.macAddress(mac); - char macStr[18]; - sprintf(macStr, "%02x:%02x:%02x:%02x:%02x:%02x", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); - // The device string is deterministic as it needs to be consistent for the same device, even after a full flash erase // MAC is salted with other consistent device info to avoid rainbow table attacks. // If the MAC address is known by malicious actors, they could precompute SHA1 hashes to impersonate devices, // but as WLED developers are just looking at statistics and not authenticating devices, this is acceptable. // If the usage data was exfiltrated, you could not easily determine the MAC from the device ID without brute forcing SHA1 -#ifdef ESP8266 - String deviceString = String(macStr) + "WLED" + ESP.getFlashChipId(); -#else - String deviceString = String(macStr) + "WLED" + ESP.getChipModel() + ESP.getChipRevision(); - deviceString += dump_raw_block(EFUSE_BLK0); - deviceString += dump_raw_block(EFUSE_BLK1); - deviceString += dump_raw_block(EFUSE_BLK2); - deviceString += dump_raw_block(EFUSE_BLK3); -#endif - String firstHash = computeSHA1(deviceString); + + String firstHash = computeSHA1(generateDeviceFingerprint()); // Second hash: SHA1 of the first hash String secondHash = computeSHA1(firstHash);