Merge pull request #5111 from DedeHai/safe_UID_generation
Safe uid generation
This commit is contained in:
commit
dc5732a5f5
@ -1159,60 +1159,62 @@ String computeSHA1(const String& input) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#ifdef ESP32
|
#ifdef ESP32
|
||||||
static String dump_raw_block(esp_efuse_block_t block)
|
#include "esp_adc_cal.h"
|
||||||
{
|
String generateDeviceFingerprint() {
|
||||||
const int WORDS = 8; // ESP32: 8×32-bit words per block i.e. 256bits
|
uint32_t fp[2] = {0, 0}; // create 64 bit fingerprint
|
||||||
uint32_t buf[WORDS] = {0};
|
esp_chip_info_t chip_info;
|
||||||
|
esp_chip_info(&chip_info);
|
||||||
const esp_efuse_desc_t d = {
|
esp_efuse_mac_get_default((uint8_t*)fp);
|
||||||
.efuse_block = block,
|
fp[1] ^= ESP.getFlashChipSize();
|
||||||
.bit_start = 0,
|
fp[0] ^= chip_info.full_revision | (chip_info.model << 16);
|
||||||
.bit_count = WORDS * 32
|
// mix in ADC calibration data:
|
||||||
};
|
esp_adc_cal_characteristics_t ch;
|
||||||
const esp_efuse_desc_t* field[2] = { &d, NULL };
|
#if SOC_ADC_MAX_BITWIDTH == 13 // S2 has 13 bit ADC
|
||||||
|
#define BIT_WIDTH ADC_WIDTH_BIT_13
|
||||||
esp_err_t err = esp_efuse_read_field_blob(field, buf, WORDS * 32);
|
#else
|
||||||
if (err != ESP_OK) {
|
#define BIT_WIDTH ADC_WIDTH_BIT_12
|
||||||
return "";
|
#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];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
if (ch.high_curve) {
|
||||||
String result = "";
|
for (int i = 0; i < 8; i++) {
|
||||||
for (const unsigned int i : buf) {
|
fp[1] ^= ch.high_curve[i];
|
||||||
char line[32];
|
}
|
||||||
sprintf(line, "0x%08X", i);
|
|
||||||
result += line;
|
|
||||||
}
|
}
|
||||||
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() {
|
||||||
|
uint32_t fp[2] = {0, 0}; // 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
|
#endif
|
||||||
|
|
||||||
|
// Generate a device ID based on SHA1 hash of MAC address salted with other unique device info
|
||||||
// Generate a device ID based on SHA1 hash of MAC address salted with "WLED"
|
|
||||||
// Returns: original SHA1 + last 2 chars of double-hashed SHA1 (42 chars total)
|
// Returns: original SHA1 + last 2 chars of double-hashed SHA1 (42 chars total)
|
||||||
String getDeviceId() {
|
String getDeviceId() {
|
||||||
static String cachedDeviceId = "";
|
static String cachedDeviceId = "";
|
||||||
if (cachedDeviceId.length() > 0) return 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
|
// 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.
|
// 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,
|
// 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.
|
// 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
|
// 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();
|
String firstHash = computeSHA1(generateDeviceFingerprint());
|
||||||
#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);
|
|
||||||
|
|
||||||
// Second hash: SHA1 of the first hash
|
// Second hash: SHA1 of the first hash
|
||||||
String secondHash = computeSHA1(firstHash);
|
String secondHash = computeSHA1(firstHash);
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user