1
0
mirror of https://github.com/esp8266/Arduino.git synced 2025-04-19 23:22:16 +03:00

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
This commit is contained in:
Alessio Leoncini 2017-11-21 05:56:05 +01:00 committed by Develo
parent cbfbc1ad63
commit 03f1a540ca
4 changed files with 30 additions and 2 deletions

View File

@ -477,6 +477,33 @@ unsigned char String::equalsIgnoreCase(const String &s2) const {
return 1; 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 { unsigned char String::startsWith(const String &s2) const {
if(len < s2.len) if(len < s2.len)
return 0; return 0;

View File

@ -194,6 +194,7 @@ class String {
unsigned char operator <=(const String &rhs) const; unsigned char operator <=(const String &rhs) const;
unsigned char operator >=(const String &rhs) const; unsigned char operator >=(const String &rhs) const;
unsigned char equalsIgnoreCase(const String &s) 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) const;
unsigned char startsWith(const String &prefix, unsigned int offset) const; unsigned char startsWith(const String &prefix, unsigned int offset) const;
unsigned char endsWith(const String &suffix) const; unsigned char endsWith(const String &suffix) const;

View File

@ -229,7 +229,7 @@ void ArduinoOTAClass::_onRx(){
String result = _challengemd5.toString(); String result = _challengemd5.toString();
ota_ip.addr = (uint32_t)_ota_ip; ota_ip.addr = (uint32_t)_ota_ip;
if(result.equals(response)){ if(result.equalsConstantTime(response)) {
_state = OTA_RUNUPDATE; _state = OTA_RUNUPDATE;
} else { } else {
_udp_ota->append("Authentication Failed", 21); _udp_ota->append("Authentication Failed", 21);

View File

@ -119,7 +119,7 @@ bool ESP8266WebServer::authenticate(const char * username, const char * password
return false; return false;
} }
sprintf(toencode, "%s:%s", username, password); 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(); authReq = String();
delete[] toencode; delete[] toencode;
delete[] encoded; delete[] encoded;