diff --git a/Software/codegen/wifiAP_passcalc.py b/Software/codegen/wifiAP_passcalc.py new file mode 100644 index 0000000..154efb5 --- /dev/null +++ b/Software/codegen/wifiAP_passcalc.py @@ -0,0 +1,15 @@ +import hashlib + +SEED = "letmelubeyou" + +def generate_password(seed, chip_id): + combined = seed + chip_id + hash_object = hashlib.md5(combined.encode()) + return hash_object.hexdigest()[:16] # First 16 characters of the MD5 hash + +if __name__ == "__main__": + chip_id = input("Enter the Chip ID in hex (e.g., 1A2B3C4D): ").strip() + chip_id = chip_id.zfill(8).upper() # Ensure it's 8 characters, upper case + + password = generate_password(SEED, chip_id) + print(f"Generated Password: {password}") diff --git a/Software/include/sanitycheck.h b/Software/include/sanitycheck.h index 7f82bc8..46ae643 100644 --- a/Software/include/sanitycheck.h +++ b/Software/include/sanitycheck.h @@ -1,31 +1,75 @@ #ifndef _SANITYCHECK_H_ #define _SANITYCHECK_H_ +// Utility macros for handling quotes +#define Q(x) #x +#define QUOTE(x) Q(x) + +// Utility macros for checking string lengths +#define STRING_LENGTH_CHECK(str, max_length) (sizeof(str) <= (max_length) + 1) +#define IS_ALPHANUMERIC(c) ((((c) >= '0') && ((c) <= '9')) || (((c) >= 'A') && ((c) <= 'Z')) || (((c) >= 'a') && ((c) <= 'z'))) +#define IS_PRINTABLE_ASCII(c) ((c) >= 32 && (c) <= 126) +#define IS_VALID_WIFI_CHAR(c) (IS_PRINTABLE_ASCII(c)) +#define IS_ALPHANUMERIC_HELPER(str, i) (i >= sizeof(str) - 1 || IS_ALPHANUMERIC(str[i])) +#define IS_PRINTABLE_ASCII_HELPER(str, i) (i >= sizeof(str) - 1 || IS_PRINTABLE_ASCII(str[i])) +#define IS_VALID_WIFI_CHAR_HELPER(str, i) (i >= sizeof(str) - 1 || IS_VALID_WIFI_CHAR(str[i])) +#define IS_ALPHANUMERIC_IMPL(str, i) (IS_ALPHANUMERIC_HELPER(str, i) && IS_ALPHANUMERIC_HELPER(str, i+1) && IS_ALPHANUMERIC_HELPER(str, i+2) && IS_ALPHANUMERIC_HELPER(str, i+3) && IS_ALPHANUMERIC_HELPER(str, i+4) && IS_ALPHANUMERIC_HELPER(str, i+5) && IS_ALPHANUMERIC_HELPER(str, i+6) && IS_ALPHANUMERIC_HELPER(str, i+7) && IS_ALPHANUMERIC_HELPER(str, i+8) && IS_ALPHANUMERIC_HELPER(str, i+9) && IS_ALPHANUMERIC_HELPER(str, i+10) && IS_ALPHANUMERIC_HELPER(str, i+11) && IS_ALPHANUMERIC_HELPER(str, i+12) && IS_ALPHANUMERIC_HELPER(str, i+13) && IS_ALPHANUMERIC_HELPER(str, i+14) && IS_ALPHANUMERIC_HELPER(str, i+15) && IS_ALPHANUMERIC_HELPER(str, i+16)) +#define IS_PRINTABLE_ASCII_IMPL(str, i) (IS_PRINTABLE_ASCII_HELPER(str, i) && IS_PRINTABLE_ASCII_HELPER(str, i+1) && IS_PRINTABLE_ASCII_HELPER(str, i+2) && IS_PRINTABLE_ASCII_HELPER(str, i+3) && IS_PRINTABLE_ASCII_HELPER(str, i+4) && IS_PRINTABLE_ASCII_HELPER(str, i+5) && IS_PRINTABLE_ASCII_HELPER(str, i+6) && IS_PRINTABLE_ASCII_HELPER(str, i+7) && IS_PRINTABLE_ASCII_HELPER(str, i+8) && IS_PRINTABLE_ASCII_HELPER(str, i+9) && IS_PRINTABLE_ASCII_HELPER(str, i+10) && IS_PRINTABLE_ASCII_HELPER(str, i+11) && IS_PRINTABLE_ASCII_HELPER(str, i+12) && IS_PRINTABLE_ASCII_HELPER(str, i+13) && IS_PRINTABLE_ASCII_HELPER(str, i+14) && IS_PRINTABLE_ASCII_HELPER(str, i+15) && IS_PRINTABLE_ASCII_HELPER(str, i+16) && IS_PRINTABLE_ASCII_HELPER(str, i+17) && IS_PRINTABLE_ASCII_HELPER(str, i+18) && IS_PRINTABLE_ASCII_HELPER(str, i+19) && IS_PRINTABLE_ASCII_HELPER(str, i+20) && IS_PRINTABLE_ASCII_HELPER(str, i+21) && IS_PRINTABLE_ASCII_HELPER(str, i+22) && IS_PRINTABLE_ASCII_HELPER(str, i+23) && IS_PRINTABLE_ASCII_HELPER(str, i+24)) +#define IS_ALPHANUMERIC_STRING(str) (IS_ALPHANUMERIC_IMPL(str, 0)) +#define IS_PRINTABLE_ASCII_STRING(str) (IS_PRINTABLE_ASCII_IMPL(str, 0)) +#define IS_VALID_WIFI_STRING(str) (IS_VALID_WIFI_CHAR_HELPER(str, 0) && IS_VALID_WIFI_CHAR_HELPER(str, 1) && IS_VALID_WIFI_CHAR_HELPER(str, 2) && IS_VALID_WIFI_CHAR_HELPER(str, 3) && IS_VALID_WIFI_CHAR_HELPER(str, 4) && IS_VALID_WIFI_CHAR_HELPER(str, 5) && IS_VALID_WIFI_CHAR_HELPER(str, 6) && IS_VALID_WIFI_CHAR_HELPER(str, 7) && IS_VALID_WIFI_CHAR_HELPER(str, 8) && IS_VALID_WIFI_CHAR_HELPER(str, 9) && IS_VALID_WIFI_CHAR_HELPER(str, 10) && IS_VALID_WIFI_CHAR_HELPER(str, 11) && IS_VALID_WIFI_CHAR_HELPER(str, 12) && IS_VALID_WIFI_CHAR_HELPER(str, 13) && IS_VALID_WIFI_CHAR_HELPER(str, 14) && IS_VALID_WIFI_CHAR_HELPER(str, 15) && IS_VALID_WIFI_CHAR_HELPER(str, 16) && IS_VALID_WIFI_CHAR_HELPER(str, 17) && IS_VALID_WIFI_CHAR_HELPER(str, 18) && IS_VALID_WIFI_CHAR_HELPER(str, 19) && IS_VALID_WIFI_CHAR_HELPER(str, 20) && IS_VALID_WIFI_CHAR_HELPER(str, 21) && IS_VALID_WIFI_CHAR_HELPER(str, 22) && IS_VALID_WIFI_CHAR_HELPER(str, 23) && IS_VALID_WIFI_CHAR_HELPER(str, 24) && IS_VALID_WIFI_CHAR_HELPER(str, 25) && IS_VALID_WIFI_CHAR_HELPER(str, 26) && IS_VALID_WIFI_CHAR_HELPER(str, 27) && IS_VALID_WIFI_CHAR_HELPER(str, 28) && IS_VALID_WIFI_CHAR_HELPER(str, 29) && IS_VALID_WIFI_CHAR_HELPER(str, 30) && IS_VALID_WIFI_CHAR_HELPER(str, 31) && IS_VALID_WIFI_CHAR_HELPER(str, 32)) + +// ADMIN_PASSWORD check #ifndef ADMIN_PASSWORD #error "You need to define ADMIN_PASSWORD for OTA-Update" +#else + _Static_assert(STRING_LENGTH_CHECK(QUOTE(ADMIN_PASSWORD), 16), "ADMIN_PASSWORD must be at most 16 characters long"); #endif +// WIFI_AP_SSID check #ifndef WIFI_AP_SSID #warning "No WIFI_AP_SSID defined. Using DeviceName" #define WIFI_AP_SSID DEVICE_NAME +#else + _Static_assert(STRING_LENGTH_CHECK(QUOTE(WIFI_AP_SSID), 32), "WIFI_AP_SSID must be at most 32 characters long"); + _Static_assert(IS_VALID_WIFI_STRING(QUOTE(WIFI_AP_SSID)), "WIFI_AP_SSID must contain only valid WiFi characters"); #endif -#ifndef WIFI_AP_PASSWORD - #error "You must define an WIFI_AP_PASSWORD for Standalone AP-Mode" +// WIFI_PASS_SEED check +#ifndef WIFI_PASS_SEED + #error "You must define an WIFI_PASS_SEED for Standalone AP-Mode" +#else + _Static_assert(STRING_LENGTH_CHECK(QUOTE(WIFI_PASS_SEED), 16), "WIFI_PASS_SEED must be at most 16 characters long"); + _Static_assert(IS_ALPHANUMERIC_STRING(QUOTE(WIFI_PASS_SEED)), "WIFI_PASS_SEED must contain only alphanumeric characters (a-z, A-Z, 0-9)"); #endif +// DEVICE_NAME check +#ifndef DEVICE_NAME + #error "You must define DEVICE_NAME" +#else + _Static_assert(STRING_LENGTH_CHECK(QUOTE(DEVICE_NAME), 24), "DEVICE_NAME must be at most 24 characters long"); + _Static_assert(IS_VALID_WIFI_STRING(QUOTE(DEVICE_NAME)), "DEVICE_NAME must contain only valid WiFi characters"); +#endif + +// Mutual exclusion check for LoRa features #if defined(FEATURE_ENABLE_UARTLORA) && defined(FEATURE_ENABLE_LORA) #error "You cannot enable LoRa and UART-Protocol at the same time!" #endif +// WIFI_CLIENT checks #ifdef FEATURE_ENABLE_WIFI_CLIENT #ifndef WIFI_PASSWORD_CLIENT - #error "You must define an WIFI_PASSWORD for OTA-Update" + #error "You must define an WIFI_PASSWORD_CLIENT for OTA-Update" + #else + _Static_assert(STRING_LENGTH_CHECK(QUOTE(WIFI_PASSWORD_CLIENT), 63), "WIFI_PASSWORD_CLIENT must be at most 63 characters long"); #endif + #ifndef WIFI_SSID_CLIENT - #error "You must define an WIFI_SSID for OTA-Update" + #error "You must define an WIFI_SSID_CLIENT for OTA-Update" + #else + _Static_assert(STRING_LENGTH_CHECK(QUOTE(WIFI_SSID_CLIENT), 32), "WIFI_SSID_CLIENT must be at most 32 characters long"); + _Static_assert(IS_VALID_WIFI_STRING(QUOTE(WIFI_SSID_CLIENT)), "WIFI_SSID_CLIENT must contain only valid WiFi characters"); #endif #endif - -#endif //_SANITYCHECK_H_ \ No newline at end of file +#endif // _SANITYCHECK_H_ diff --git a/Software/include/utilities.h b/Software/include/utilities.h index 1c74318..e34d620 100644 --- a/Software/include/utilities.h +++ b/Software/include/utilities.h @@ -33,4 +33,16 @@ bool validateWiFiString(char *string, size_t size); */ void sanitizeWiFiString(const char *input, char *buffer, size_t bufferSize); +/** + * @brief Generates a device-specific password based on a seed and the ESP8266 Chip ID. + * + * This function combines a given seed with the unique Chip ID of the ESP8266 device to create a device-specific password. + * The resulting password is stored in the provided character buffer. + * + * @param seed The seed string used for password generation. Should be up to 16 characters long. + * @param passwordBuffer The character buffer where the generated password will be stored. + * @param bufferLength The length of the password buffer. Should be large enough to hold the generated password and null terminator. + */ +void GenerateDeviceSpecificPassword(const char* seed, char* passwordBuffer, size_t bufferLength); + #endif // UTILITIES_H diff --git a/Software/platformio.ini b/Software/platformio.ini index 00f6ae3..70b7d43 100644 --- a/Software/platformio.ini +++ b/Software/platformio.ini @@ -37,7 +37,7 @@ build_flags= -DWIFI_SSID_CLIENT=${wifi_cred.wifi_ssid_client} -DWIFI_PASSWORD_CLIENT=${wifi_cred.wifi_password_client} -DADMIN_PASSWORD=${wifi_cred.admin_password} - -DWIFI_AP_PASSWORD=${wifi_cred.wifi_ap_password} + -DWIFI_PASS_SEED=${wifi_cred.wifi_pass_seed} -DDEVICE_NAME='"Dark Emergency Timer"' ;build_type = debug diff --git a/Software/src/utilities.cpp b/Software/src/utilities.cpp index 5a31703..f7a9fc2 100644 --- a/Software/src/utilities.cpp +++ b/Software/src/utilities.cpp @@ -33,7 +33,7 @@ bool validateWiFiString(char *string, size_t size) c == '.' || c == '/' || c == ':' || c == ';' || c == '<' || c == '=' || c == '>' || c == '?' || c == '@' || c == '[' || c == '\\' || c == ']' || c == '^' || c == '_' || c == '`' || - c == '{' || c == '|' || c == '}' || c == '~')) + c == '{' || c == '|' || c == '}' || c == '~' || c == ' ')) { // Found a character that is not a valid WiFi character. return false; @@ -78,7 +78,7 @@ void sanitizeWiFiString(const char *input, char *buffer, size_t bufferSize) c == '.' || c == '/' || c == ':' || c == ';' || c == '<' || c == '=' || c == '>' || c == '?' || c == '@' || c == '[' || c == '\\' || c == ']' || c == '^' || c == '_' || c == '`' || - c == '{' || c == '|' || c == '}' || c == '~')) + c == '{' || c == '|' || c == '}' || c == '~' || c == ' ')) { // Replace invalid character with placeholder buffer[i] = '_'; @@ -92,3 +92,34 @@ void sanitizeWiFiString(const char *input, char *buffer, size_t bufferSize) // Null-terminate the buffer buffer[i] = '\0'; } + +/** + * @brief Generates a device-specific password based on a seed and the ESP8266 Chip ID. + * + * This function combines a given seed with the unique Chip ID of the ESP8266 device to create a device-specific password. + * The resulting password is stored in the provided character buffer. + * + * @param seed The seed string used for password generation. Should be up to 16 characters long. + * @param passwordBuffer The character buffer where the generated password will be stored. + * @param bufferLength The length of the password buffer. Should be large enough to hold the generated password and null terminator. + */ +void GenerateDeviceSpecificPassword(const char* seed, char* passwordBuffer, size_t bufferLength) { + uint32_t chipId = ESP.getChipId(); + char chipIdStr[9]; // 8 characters + null terminator + snprintf(chipIdStr, sizeof(chipIdStr), "%08X", chipId); + + char combined[33]; // seed (16) + chipId (8) + null terminator (1) + strncpy(combined, seed, 16); + strncat(combined, chipIdStr, 8); + + // Simple hash function for demonstration + unsigned long hash = 5381; + int c; + char *str = combined; + + while ((c = *str++)) { + hash = ((hash << 5) + hash) + c; // hash * 33 + c + } + + snprintf(passwordBuffer, bufferLength, "%08X", hash); +} \ No newline at end of file diff --git a/Software/wifi_credentials.example.ini b/Software/wifi_credentials.example.ini index 604630c..ed8542b 100644 --- a/Software/wifi_credentials.example.ini +++ b/Software/wifi_credentials.example.ini @@ -1,5 +1,5 @@ [wifi_cred] admin_password = chainlube -wifi_ap_password = wifiappass +wifi_pass_seed = wifiapseed wifi_ssid_client = wifi-ssid wifi_password_client = ota-password \ No newline at end of file