@@ -703,60 +703,62 @@ String computeSHA1(const String& input) {
703703}
704704
705705#ifdef ESP32
706- static String dump_raw_block (esp_efuse_block_t block)
707- {
708- const int WORDS = 8 ; // ESP32: 8×32-bit words per block i.e. 256bits
709- uint32_t buf[WORDS] = {0 };
710-
711- const esp_efuse_desc_t d = {
712- .efuse_block = block,
713- .bit_start = 0 ,
714- .bit_count = WORDS * 32
715- };
716- const esp_efuse_desc_t * field[2 ] = { &d, NULL };
717-
718- esp_err_t err = esp_efuse_read_field_blob (field, buf, WORDS * 32 );
719- if (err != ESP_OK) {
720- return " " ;
706+ #include " esp_adc_cal.h"
707+ String generateDeviceFingerprint () {
708+ uint32_t fp[2 ] = {0 , 0 }; // create 64 bit fingerprint
709+ esp_chip_info_t chip_info;
710+ esp_chip_info (&chip_info);
711+ esp_efuse_mac_get_default ((uint8_t *)fp);
712+ fp[1 ] ^= ESP.getFlashChipSize ();
713+ fp[0 ] ^= chip_info.full_revision | (chip_info.model << 16 );
714+ // mix in ADC calibration data:
715+ esp_adc_cal_characteristics_t ch;
716+ #if SOC_ADC_MAX_BITWIDTH == 13 // S2 has 13 bit ADC
717+ #define BIT_WIDTH ADC_WIDTH_BIT_13
718+ #else
719+ #define BIT_WIDTH ADC_WIDTH_BIT_12
720+ #endif
721+ esp_adc_cal_characterize (ADC_UNIT_1, ADC_ATTEN_DB_11, BIT_WIDTH, 1100 , &ch);
722+ fp[0 ] ^= ch.coeff_a ;
723+ fp[1 ] ^= ch.coeff_b ;
724+ if (ch.low_curve ) {
725+ for (int i = 0 ; i < 8 ; i++) {
726+ fp[0 ] ^= ch.low_curve [i];
727+ }
721728 }
722-
723- String result = " " ;
724- for (const unsigned int i : buf) {
725- char line[32 ];
726- sprintf (line, " 0x%08X" , i);
727- result += line;
729+ if (ch.high_curve ) {
730+ for (int i = 0 ; i < 8 ; i++) {
731+ fp[1 ] ^= ch.high_curve [i];
732+ }
728733 }
729- return result;
734+ char fp_string[17 ]; // 16 hex chars + null terminator
735+ sprintf (fp_string, " %08X%08X" , fp[1 ], fp[0 ]);
736+ return String (fp_string);
737+ }
738+ #else // ESP8266
739+ String generateDeviceFingerprint () {
740+ uint32_t fp[2 ] = {0 , 0 }; // create 64 bit fingerprint
741+ WiFi.macAddress ((uint8_t *)&fp); // use MAC address as fingerprint base
742+ fp[0 ] ^= ESP.getFlashChipId ();
743+ fp[1 ] ^= ESP.getFlashChipSize () | ESP.getFlashChipVendorId () << 16 ;
744+ char fp_string[17 ]; // 16 hex chars + null terminator
745+ sprintf (fp_string, " %08X%08X" , fp[1 ], fp[0 ]);
746+ return String (fp_string);
730747}
731748#endif
732749
733-
734- // Generate a device ID based on SHA1 hash of MAC address salted with "WLED"
750+ // Generate a device ID based on SHA1 hash of MAC address salted with other unique device info
735751// Returns: original SHA1 + last 2 chars of double-hashed SHA1 (42 chars total)
736752String getDeviceId () {
737753 static String cachedDeviceId = " " ;
738754 if (cachedDeviceId.length () > 0 ) return cachedDeviceId;
739-
740- uint8_t mac[6 ];
741- WiFi.macAddress (mac);
742- char macStr[18 ];
743- sprintf (macStr, " %02x:%02x:%02x:%02x:%02x:%02x" , mac[0 ], mac[1 ], mac[2 ], mac[3 ], mac[4 ], mac[5 ]);
744-
745755 // The device string is deterministic as it needs to be consistent for the same device, even after a full flash erase
746756 // MAC is salted with other consistent device info to avoid rainbow table attacks.
747757 // If the MAC address is known by malicious actors, they could precompute SHA1 hashes to impersonate devices,
748758 // but as WLED developers are just looking at statistics and not authenticating devices, this is acceptable.
749759 // If the usage data was exfiltrated, you could not easily determine the MAC from the device ID without brute forcing SHA1
750- #ifdef ESP8266
751- String deviceString = String (macStr) + " WLED" + ESP.getFlashChipId ();
752- #else
753- String deviceString = String (macStr) + " WLED" + ESP.getChipModel () + ESP.getChipRevision ();
754- deviceString += dump_raw_block (EFUSE_BLK0);
755- deviceString += dump_raw_block (EFUSE_BLK1);
756- deviceString += dump_raw_block (EFUSE_BLK2);
757- deviceString += dump_raw_block (EFUSE_BLK3);
758- #endif
759- String firstHash = computeSHA1 (deviceString);
760+
761+ String firstHash = computeSHA1 (generateDeviceFingerprint ());
760762
761763 // Second hash: SHA1 of the first hash
762764 String secondHash = computeSHA1 (firstHash);
0 commit comments