@@ -181,6 +181,27 @@ std::string generateClientProof(const unsigned char saltedPassword[hashSize],
181181 return base64::encode (reinterpret_cast <char *>(clientProof), hashSize);
182182}
183183
184+ /* *
185+ * Compare two arrays of bytes for equality in constant time.
186+ *
187+ * This means that the function runs for the same amount of time even if they differ. Unlike memcmp,
188+ * this function does not exit on the first difference.
189+ *
190+ * Returns true if the two arrays are equal.
191+ *
192+ * TODO: evaluate if LTO inlines or changes the code flow of this function.
193+ */
194+ NOINLINE_DECL
195+ bool memequal (volatile const unsigned char * s1, volatile const unsigned char * s2, size_t length) {
196+ unsigned char ret = 0 ;
197+
198+ for (size_t i = 0 ; i < length; ++i) {
199+ ret |= s1[i] ^ s2[i];
200+ }
201+
202+ return ret == 0 ;
203+ }
204+
184205bool verifyServerSignature (const unsigned char saltedPassword[hashSize],
185206 const std::string& authMessage,
186207 const std::string& receivedServerSignature) {
@@ -207,7 +228,14 @@ bool verifyServerSignature(const unsigned char saltedPassword[hashSize],
207228
208229 std::string encodedServerSignature =
209230 base64::encode (reinterpret_cast <char *>(serverSignature), sizeof (serverSignature));
210- return (receivedServerSignature == encodedServerSignature);
231+
232+ if (encodedServerSignature.size () != receivedServerSignature.size ()) {
233+ return false ;
234+ }
235+
236+ return memequal (reinterpret_cast <const unsigned char *>(encodedServerSignature.c_str ()),
237+ reinterpret_cast <const unsigned char *>(receivedServerSignature.c_str ()),
238+ encodedServerSignature.size ());
211239}
212240
213241} // namespace scram
0 commit comments