Skip to content

Commit cdb3441

Browse files
committed
Make RPC password resistant to timing attacks
Fixes issue#2838; this is a tweaked version of pull#2845 that should not leak the length of the password and is more generic, in case we run into other situations where we need timing-attack-resistant comparisons.
1 parent 38863af commit cdb3441

File tree

3 files changed

+27
-1
lines changed

3 files changed

+27
-1
lines changed

Diff for: src/bitcoinrpc.cpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -479,7 +479,7 @@ bool HTTPAuthorized(map<string, string>& mapHeaders)
479479
return false;
480480
string strUserPass64 = strAuth.substr(6); boost::trim(strUserPass64);
481481
string strUserPass = DecodeBase64(strUserPass64);
482-
return strUserPass == strRPCUserColonPass;
482+
return TimingResistantEqual(strUserPass, strRPCUserColonPass);
483483
}
484484

485485
//

Diff for: src/test/util_tests.cpp

+11
Original file line numberDiff line numberDiff line change
@@ -323,4 +323,15 @@ BOOST_AUTO_TEST_CASE(util_seed_insecure_rand)
323323
}
324324
}
325325

326+
BOOST_AUTO_TEST_CASE(util_TimingResistantEqual)
327+
{
328+
BOOST_CHECK(TimingResistantEqual(std::string(""), std::string("")));
329+
BOOST_CHECK(!TimingResistantEqual(std::string("abc"), std::string("")));
330+
BOOST_CHECK(!TimingResistantEqual(std::string(""), std::string("abc")));
331+
BOOST_CHECK(!TimingResistantEqual(std::string("a"), std::string("aa")));
332+
BOOST_CHECK(!TimingResistantEqual(std::string("aa"), std::string("a")));
333+
BOOST_CHECK(TimingResistantEqual(std::string("abc"), std::string("abc")));
334+
BOOST_CHECK(!TimingResistantEqual(std::string("abc"), std::string("aba")));
335+
}
336+
326337
BOOST_AUTO_TEST_SUITE_END()

Diff for: src/util.h

+15
Original file line numberDiff line numberDiff line change
@@ -433,6 +433,21 @@ static inline uint32_t insecure_rand(void)
433433
*/
434434
void seed_insecure_rand(bool fDeterministic=false);
435435

436+
/**
437+
* Timing-attack-resistant comparison.
438+
* Takes time proportional to length
439+
* of first argument.
440+
*/
441+
template <typename T>
442+
bool TimingResistantEqual(const T& a, const T& b)
443+
{
444+
if (b.size() == 0) return a.size() == 0;
445+
size_t accumulator = a.size() ^ b.size();
446+
for (size_t i = 0; i < a.size(); i++)
447+
accumulator |= a[i] ^ b[i%b.size()];
448+
return accumulator == 0;
449+
}
450+
436451
/** Median filter over a stream of values.
437452
* Returns the median of the last N numbers
438453
*/

0 commit comments

Comments
 (0)