GH #1412: added Poco::DigestEngine::constantTimeEquals()

This commit is contained in:
Guenter Obiltschnig 2017-11-01 17:37:35 +01:00
parent 0db79db029
commit bdbc94d825
4 changed files with 40 additions and 6 deletions

View File

@ -40,19 +40,19 @@ public:
DigestEngine();
virtual ~DigestEngine();
void update(const void* data, std::size_t length);
void update(char data);
void update(const std::string& data);
/// Updates the digest with the given data.
virtual std::size_t digestLength() const = 0;
/// Returns the length of the digest in bytes.
virtual void reset() = 0;
/// Resets the engine so that a new
/// digest can be computed.
virtual const Digest& digest() = 0;
/// Finishes the computation of the digest and
/// returns the message digest. Resets the engine
@ -66,11 +66,16 @@ public:
static Digest digestFromHex(const std::string& digest);
/// Converts a string created by digestToHex back to its Digest presentation
static bool constantTimeEquals(const Digest& d1, const Digest& d2);
/// Compares two Digest values using a constant-time comparison
/// algorithm. This can be used to prevent timing attacks
/// (as discussed in <https://codahale.com/a-lesson-in-timing-attacks/>).
protected:
virtual void updateImpl(const void* data, std::size_t length) = 0;
/// Updates the digest with the given data. Must be implemented
/// by subclasses.
private:
DigestEngine(const DigestEngine&);
DigestEngine& operator = (const DigestEngine&);
@ -96,7 +101,7 @@ inline void DigestEngine::update(char data)
inline void DigestEngine::update(const std::string& data)
{
updateImpl(data.data(), data.size());
updateImpl(data.data(), data.size());
}

View File

@ -79,5 +79,21 @@ DigestEngine::Digest DigestEngine::digestFromHex(const std::string& digest)
}
bool DigestEngine::constantTimeEquals(const Digest& d1, const Digest& d2)
{
if (d1.size() != d2.size()) return false;
int result = 0;
Digest::const_iterator it1 = d1.begin();
Digest::const_iterator it2 = d2.begin();
Digest::const_iterator end1 = d1.end();
while (it1 != end1)
{
result |= *it1++ ^ *it2++;
}
return result == 0;
}
} // namespace Poco

View File

@ -48,7 +48,7 @@ void MD5EngineTest::testMD5()
engine.update("abcdefghijklmnopqrstuvwxyz");
assert (DigestEngine::digestToHex(engine.digest()) == "c3fcd3d76192e4007dfb496cca67e13b");
engine.update("ABCDEFGHIJKLMNOPQRSTUVWXYZ");
engine.update("abcdefghijklmnopqrstuvwxyz0123456789");
assert (DigestEngine::digestToHex(engine.digest()) == "d174ab98d277d9f5a5611c2c9f419d9f");
@ -58,6 +58,17 @@ void MD5EngineTest::testMD5()
}
void MD5EngineTest::testConstantTimeEquals()
{
DigestEngine::Digest d1 = DigestEngine::digestFromHex("d41d8cd98f00b204e9800998ecf8427e");
DigestEngine::Digest d2 = DigestEngine::digestFromHex("d41d8cd98f00b204e9800998ecf8427e");
DigestEngine::Digest d3 = DigestEngine::digestFromHex("0cc175b9c0f1b6a831c399e269772661");
assert (DigestEngine::constantTimeEquals(d1, d2));
assert (!DigestEngine::constantTimeEquals(d1, d3));
}
void MD5EngineTest::setUp()
{
}
@ -73,6 +84,7 @@ CppUnit::Test* MD5EngineTest::suite()
CppUnit::TestSuite* pSuite = new CppUnit::TestSuite("MD5EngineTest");
CppUnit_addTest(pSuite, MD5EngineTest, testMD5);
CppUnit_addTest(pSuite, MD5EngineTest, testConstantTimeEquals);
return pSuite;
}

View File

@ -25,6 +25,7 @@ public:
~MD5EngineTest();
void testMD5();
void testConstantTimeEquals();
void setUp();
void tearDown();