diff --git a/cores/esp8266/WString.cpp b/cores/esp8266/WString.cpp index acd62ce9b..6f2134e86 100644 --- a/cores/esp8266/WString.cpp +++ b/cores/esp8266/WString.cpp @@ -477,6 +477,33 @@ unsigned char String::equalsIgnoreCase(const String &s2) const { return 1; } +unsigned char String::equalsConstantTime(const String &s2) const { + // To avoid possible time-based attacks present function + // compares given strings in a constant time. + if(len != s2.len) + return 0; + //at this point lengths are the same + if(len == 0) + return 1; + //at this point lenghts are the same and non-zero + const char *p1 = buffer; + const char *p2 = s2.buffer; + unsigned int equalchars = 0; + unsigned int diffchars = 0; + while(*p1) { + if(*p1 == *p2) + ++equalchars; + else + ++diffchars; + ++p1; + ++p2; + } + //the following should force a constant time eval of the condition without a compiler "logical shortcut" + unsigned char equalcond = (equalchars == len); + unsigned char diffcond = (diffchars == 0); + return (equalcond & diffcond); //bitwise AND +} + unsigned char String::startsWith(const String &s2) const { if(len < s2.len) return 0; diff --git a/cores/esp8266/WString.h b/cores/esp8266/WString.h index a3bb40c13..fbf3c59b2 100644 --- a/cores/esp8266/WString.h +++ b/cores/esp8266/WString.h @@ -194,6 +194,7 @@ class String { unsigned char operator <=(const String &rhs) const; unsigned char operator >=(const String &rhs) const; unsigned char equalsIgnoreCase(const String &s) const; + unsigned char equalsConstantTime(const String &s) const; unsigned char startsWith(const String &prefix) const; unsigned char startsWith(const String &prefix, unsigned int offset) const; unsigned char endsWith(const String &suffix) const; diff --git a/libraries/ArduinoOTA/ArduinoOTA.cpp b/libraries/ArduinoOTA/ArduinoOTA.cpp index d3a4397c6..aaf4c5ff5 100644 --- a/libraries/ArduinoOTA/ArduinoOTA.cpp +++ b/libraries/ArduinoOTA/ArduinoOTA.cpp @@ -229,7 +229,7 @@ void ArduinoOTAClass::_onRx(){ String result = _challengemd5.toString(); ota_ip.addr = (uint32_t)_ota_ip; - if(result.equals(response)){ + if(result.equalsConstantTime(response)) { _state = OTA_RUNUPDATE; } else { _udp_ota->append("Authentication Failed", 21); diff --git a/libraries/ESP8266WebServer/src/ESP8266WebServer.cpp b/libraries/ESP8266WebServer/src/ESP8266WebServer.cpp index 6220dfe4d..6b97505ee 100644 --- a/libraries/ESP8266WebServer/src/ESP8266WebServer.cpp +++ b/libraries/ESP8266WebServer/src/ESP8266WebServer.cpp @@ -119,7 +119,7 @@ bool ESP8266WebServer::authenticate(const char * username, const char * password return false; } sprintf(toencode, "%s:%s", username, password); - if(base64_encode_chars(toencode, toencodeLen, encoded) > 0 && authReq.equals(encoded)){ + if(base64_encode_chars(toencode, toencodeLen, encoded) > 0 && authReq.equalsConstantTime(encoded)) { authReq = String(); delete[] toencode; delete[] encoded;