Skip to content

Commit 03f1a54

Browse files
bluemurderdevyte
authored andcommittedNov 21, 2017
Added constant time string comparison to avoid possible time-based attacks. (#3836)
* Added constant time strings comparison to avoid possible time-based attacks * Fixed data types * Fixed indentation * Moved string comnparison in constant time to String class; modified function body to assure constant time comparison despite compiler optimizations * Removed wrong code * Fixed error and prevented compiler optimization to delete u1 local variable * Avoid timing attacks on string comparison * Minor * changed counter names, removed else
1 parent cbfbc1a commit 03f1a54

File tree

4 files changed

+30
-2
lines changed

4 files changed

+30
-2
lines changed
 

‎cores/esp8266/WString.cpp

+27
Original file line numberDiff line numberDiff line change
@@ -477,6 +477,33 @@ unsigned char String::equalsIgnoreCase(const String &s2) const {
477477
return 1;
478478
}
479479

480+
unsigned char String::equalsConstantTime(const String &s2) const {
481+
// To avoid possible time-based attacks present function
482+
// compares given strings in a constant time.
483+
if(len != s2.len)
484+
return 0;
485+
//at this point lengths are the same
486+
if(len == 0)
487+
return 1;
488+
//at this point lenghts are the same and non-zero
489+
const char *p1 = buffer;
490+
const char *p2 = s2.buffer;
491+
unsigned int equalchars = 0;
492+
unsigned int diffchars = 0;
493+
while(*p1) {
494+
if(*p1 == *p2)
495+
++equalchars;
496+
else
497+
++diffchars;
498+
++p1;
499+
++p2;
500+
}
501+
//the following should force a constant time eval of the condition without a compiler "logical shortcut"
502+
unsigned char equalcond = (equalchars == len);
503+
unsigned char diffcond = (diffchars == 0);
504+
return (equalcond & diffcond); //bitwise AND
505+
}
506+
480507
unsigned char String::startsWith(const String &s2) const {
481508
if(len < s2.len)
482509
return 0;

‎cores/esp8266/WString.h

+1
Original file line numberDiff line numberDiff line change
@@ -194,6 +194,7 @@ class String {
194194
unsigned char operator <=(const String &rhs) const;
195195
unsigned char operator >=(const String &rhs) const;
196196
unsigned char equalsIgnoreCase(const String &s) const;
197+
unsigned char equalsConstantTime(const String &s) const;
197198
unsigned char startsWith(const String &prefix) const;
198199
unsigned char startsWith(const String &prefix, unsigned int offset) const;
199200
unsigned char endsWith(const String &suffix) const;

‎libraries/ArduinoOTA/ArduinoOTA.cpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -229,7 +229,7 @@ void ArduinoOTAClass::_onRx(){
229229
String result = _challengemd5.toString();
230230

231231
ota_ip.addr = (uint32_t)_ota_ip;
232-
if(result.equals(response)){
232+
if(result.equalsConstantTime(response)) {
233233
_state = OTA_RUNUPDATE;
234234
} else {
235235
_udp_ota->append("Authentication Failed", 21);

‎libraries/ESP8266WebServer/src/ESP8266WebServer.cpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -119,7 +119,7 @@ bool ESP8266WebServer::authenticate(const char * username, const char * password
119119
return false;
120120
}
121121
sprintf(toencode, "%s:%s", username, password);
122-
if(base64_encode_chars(toencode, toencodeLen, encoded) > 0 && authReq.equals(encoded)){
122+
if(base64_encode_chars(toencode, toencodeLen, encoded) > 0 && authReq.equalsConstantTime(encoded)) {
123123
authReq = String();
124124
delete[] toencode;
125125
delete[] encoded;

0 commit comments

Comments
 (0)