From c6ffcd27e94d2f90fd4a3bcb5d2d3c6550ead59c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Remko=20Tron=C3=A7on?= <git@el-tramo.be> Date: Fri, 12 Aug 2011 19:29:21 +0200 Subject: Refactored stringcodec functions to make them independent of hash algos. diff --git a/Swiften/SASL/SCRAMSHA1ClientAuthenticator.cpp b/Swiften/SASL/SCRAMSHA1ClientAuthenticator.cpp index 20b3d8a..bcd6c5d 100644 --- a/Swiften/SASL/SCRAMSHA1ClientAuthenticator.cpp +++ b/Swiften/SASL/SCRAMSHA1ClientAuthenticator.cpp @@ -12,7 +12,8 @@ #include <Swiften/StringCodecs/SHA1.h> #include <Swiften/StringCodecs/Base64.h> -#include <Swiften/StringCodecs/HMACSHA1.h> +#include <Swiften/StringCodecs/HMAC.h> +#include <Swiften/StringCodecs/SHA1.h> #include <Swiften/StringCodecs/PBKDF2.h> #include <Swiften/IDN/StringPrep.h> #include <Swiften/Base/Concat.h> @@ -44,9 +45,9 @@ boost::optional<SafeByteArray> SCRAMSHA1ClientAuthenticator::getResponse() const return createSafeByteArray(concat(getGS2Header(), getInitialBareClientMessage())); } else if (step == Proof) { - ByteArray clientKey = HMACSHA1::getResult(saltedPassword, createByteArray("Client Key")); + ByteArray clientKey = HMAC<SHA1>()(saltedPassword, createByteArray("Client Key")); ByteArray storedKey = SHA1::getHash(clientKey); - ByteArray clientSignature = HMACSHA1::getResult(createSafeByteArray(storedKey), authMessage); + ByteArray clientSignature = HMAC<SHA1>()(createSafeByteArray(storedKey), authMessage); ByteArray clientProof = clientKey; for (unsigned int i = 0; i < clientProof.size(); ++i) { clientProof[i] ^= clientSignature[i]; @@ -101,13 +102,13 @@ bool SCRAMSHA1ClientAuthenticator::setChallenge(const boost::optional<ByteArray> // Compute all the values needed for the server signature try { - saltedPassword = PBKDF2::encode(StringPrep::getPrepared(getPassword(), StringPrep::SASLPrep), salt, iterations); + saltedPassword = PBKDF2::encode<HMAC<SHA1> >(StringPrep::getPrepared(getPassword(), StringPrep::SASLPrep), salt, iterations); } catch (const std::exception&) { } authMessage = concat(getInitialBareClientMessage(), createByteArray(","), initialServerMessage, createByteArray(","), getFinalMessageWithoutProof()); - ByteArray serverKey = HMACSHA1::getResult(saltedPassword, createByteArray("Server Key")); - serverSignature = HMACSHA1::getResult(serverKey, authMessage); + ByteArray serverKey = HMAC<SHA1>()(saltedPassword, createByteArray("Server Key")); + serverSignature = HMAC<SHA1>()(serverKey, authMessage); step = Proof; return true; diff --git a/Swiften/SConscript b/Swiften/SConscript index 6d38717..6d2d14a 100644 --- a/Swiften/SConscript +++ b/Swiften/SConscript @@ -175,9 +175,7 @@ if env["SCONS_STAGE"] == "build" : "Session/BasicSessionStream.cpp", "StringCodecs/Base64.cpp", "StringCodecs/SHA1.cpp", - "StringCodecs/HMACSHA1.cpp", "StringCodecs/MD5.cpp", - "StringCodecs/PBKDF2.cpp", "StringCodecs/Hexify.cpp", ] @@ -349,7 +347,7 @@ if env["SCONS_STAGE"] == "build" : File("StringCodecs/UnitTest/SHA1Test.cpp"), File("StringCodecs/UnitTest/MD5Test.cpp"), File("StringCodecs/UnitTest/HexifyTest.cpp"), - File("StringCodecs/UnitTest/HMACSHA1Test.cpp"), + File("StringCodecs/UnitTest/HMACTest.cpp"), File("StringCodecs/UnitTest/PBKDF2Test.cpp"), File("TLS/UnitTest/ServerIdentityVerifierTest.cpp"), File("TLS/UnitTest/CertificateTest.cpp"), diff --git a/Swiften/StringCodecs/HMAC.h b/Swiften/StringCodecs/HMAC.h new file mode 100644 index 0000000..438a3a7 --- /dev/null +++ b/Swiften/StringCodecs/HMAC.h @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2010 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#pragma once + +#include <Swiften/Base/ByteArray.h> +#include <Swiften/Base/Algorithm.h> +#include <cassert> + +namespace Swift { + namespace HMAC_Detail { + static const unsigned int B = 64; + + template<typename Hash, typename KeyType> + static ByteArray getHMAC(const KeyType& key, const ByteArray& data) { + assert(key.size() <= B); + Hash hash; + + // Create the padded key + KeyType paddedKey(key); + paddedKey.resize(B, 0x0); + + // Create the first value + KeyType x(paddedKey); + for (unsigned int i = 0; i < x.size(); ++i) { + x[i] ^= 0x36; + } + append(x, data); + + // Create the second value + KeyType y(paddedKey); + for (unsigned int i = 0; i < y.size(); ++i) { + y[i] ^= 0x5c; + } + append(y, hash(x)); + + return hash(y); + } + }; + + template<typename Hash> + class HMAC { + private: + + public: + ByteArray operator()(const ByteArray& key, const ByteArray& data) const { + return HMAC_Detail::getHMAC<Hash,ByteArray>(key, data); + } + + ByteArray operator()(const SafeByteArray& key, const ByteArray& data) const { + return HMAC_Detail::getHMAC<Hash,SafeByteArray>(key, data); + } + }; +} diff --git a/Swiften/StringCodecs/HMACSHA1.cpp b/Swiften/StringCodecs/HMACSHA1.cpp deleted file mode 100644 index fd951ae..0000000 --- a/Swiften/StringCodecs/HMACSHA1.cpp +++ /dev/null @@ -1,95 +0,0 @@ -/* - * Copyright (c) 2010 Remko Tronçon - * Licensed under the GNU General Public License v3. - * See Documentation/Licenses/GPLv3.txt for more information. - */ - -#include <Swiften/StringCodecs/HMACSHA1.h> - -#include <cassert> - -#include <Swiften/StringCodecs/SHA1.h> -#include <Swiften/Base/Algorithm.h> - -using namespace Swift; - -namespace { - static const unsigned int B = 64; - - template<typename SourceType> - ByteArray getHMACSHA1(const SourceType& key, const ByteArray& data) { - assert(key.size() <= B); - - // Create the padded key - SourceType paddedKey(key); - paddedKey.resize(B, 0x0); - - // Create the first value - SourceType x(paddedKey); - for (unsigned int i = 0; i < x.size(); ++i) { - x[i] ^= 0x36; - } - append(x, data); - - // Create the second value - SourceType y(paddedKey); - for (unsigned int i = 0; i < y.size(); ++i) { - y[i] ^= 0x5c; - } - append(y, SHA1::getHash(x)); - - return SHA1::getHash(y); - } -} - -namespace Swift { - -ByteArray HMACSHA1::getResult(const SafeByteArray& key, const ByteArray& data) { - return getHMACSHA1(key, data); -} - -ByteArray HMACSHA1::getResult(const ByteArray& key, const ByteArray& data) { - return getHMACSHA1(key, data); -} - - - -#if 0 - -// A tweaked version of HMACSHA1 that is more than twice as fast as the one above. -// After this, more than 80% is spent in SHA1. -// Optimizations: -// - Avoids using ByteArray/std::vector -// - Uses openssl's SHA1, which is slightly faster -// - Does 'xor' on word basis -// - Passes return value as a parameter - -#include <openssl/sha.h> - -void HMACSHA1::getResult(const ByteArray& key, const ByteArray& data, ByteArray& result) { - // Create first value - size_t xSize = B + data.size(); - unsigned char* x = (unsigned char*) malloc(xSize * sizeof(unsigned char)); - memset(x, 0, B); - memcpy(x, key.getData(), key.size()); - for (unsigned int i = 0; i < (B>>32); ++i) { - x[i<<32] ^= 0x36363636; - } - memcpy(x + B, data.getData(), data.size()); - - // Create the second value - unsigned char y[B + 20]; - memset(y, 0, B); - memcpy(y, key.getData(), key.size()); - for (unsigned int i = 0; i < (B>>32); ++i) { - y[i<<32] ^= 0x5c5c5c5c; - } - ::SHA1(x, xSize, y + B); - free(x); - - ::SHA1(y, B + 20, (unsigned char*) result.getData()); -} - -#endif - -} diff --git a/Swiften/StringCodecs/HMACSHA1.h b/Swiften/StringCodecs/HMACSHA1.h deleted file mode 100644 index 0463e64..0000000 --- a/Swiften/StringCodecs/HMACSHA1.h +++ /dev/null @@ -1,18 +0,0 @@ -/* - * Copyright (c) 2010 Remko Tronçon - * Licensed under the GNU General Public License v3. - * See Documentation/Licenses/GPLv3.txt for more information. - */ - -#pragma once - -#include <Swiften/Base/ByteArray.h> -#include <Swiften/Base/SafeByteArray.h> - -namespace Swift { - class HMACSHA1 { - public: - static ByteArray getResult(const SafeByteArray& key, const ByteArray& data); - static ByteArray getResult(const ByteArray& key, const ByteArray& data); - }; -} diff --git a/Swiften/StringCodecs/PBKDF2.cpp b/Swiften/StringCodecs/PBKDF2.cpp deleted file mode 100644 index 81e1208..0000000 --- a/Swiften/StringCodecs/PBKDF2.cpp +++ /dev/null @@ -1,27 +0,0 @@ -/* - * Copyright (c) 2010 Remko Tronçon - * Licensed under the GNU General Public License v3. - * See Documentation/Licenses/GPLv3.txt for more information. - */ - -#include <Swiften/StringCodecs/PBKDF2.h> -#include <Swiften/StringCodecs/HMACSHA1.h> -#include <Swiften/Base/Concat.h> - -namespace Swift { - -ByteArray PBKDF2::encode(const SafeByteArray& password, const ByteArray& salt, int iterations) { - ByteArray u = HMACSHA1::getResult(password, concat(salt, createByteArray("\0\0\0\1", 4))); - ByteArray result(u); - int i = 1; - while (i < iterations) { - u = HMACSHA1::getResult(password, u); - for (unsigned int j = 0; j < u.size(); ++j) { - result[j] ^= u[j]; - } - ++i; - } - return result; -} - -} diff --git a/Swiften/StringCodecs/PBKDF2.h b/Swiften/StringCodecs/PBKDF2.h index b1a5986..0c04145 100644 --- a/Swiften/StringCodecs/PBKDF2.h +++ b/Swiften/StringCodecs/PBKDF2.h @@ -7,10 +7,25 @@ #pragma once #include <Swiften/Base/SafeByteArray.h> +#include <Swiften/Base/Concat.h> namespace Swift { class PBKDF2 { public: - static ByteArray encode(const SafeByteArray& password, const ByteArray& salt, int iterations); + template<typename PRF> + static ByteArray encode(const SafeByteArray& password, const ByteArray& salt, int iterations) { + PRF prf; + ByteArray u = prf(password, concat(salt, createByteArray("\0\0\0\1", 4))); + ByteArray result(u); + int i = 1; + while (i < iterations) { + u = prf(password, u); + for (unsigned int j = 0; j < u.size(); ++j) { + result[j] ^= u[j]; + } + ++i; + } + return result; + } }; } diff --git a/Swiften/StringCodecs/SHA1.h b/Swiften/StringCodecs/SHA1.h index 25bfa54..19488cb 100644 --- a/Swiften/StringCodecs/SHA1.h +++ b/Swiften/StringCodecs/SHA1.h @@ -26,9 +26,16 @@ namespace Swift { * convenient. */ static ByteArray getHash(const ByteArray& data); - static ByteArray getHash(const SafeByteArray& data); + ByteArray operator()(const SafeByteArray& data) { + return getHash(data); + } + + ByteArray operator()(const ByteArray& data) { + return getHash(data); + } + private: typedef struct { boost::uint32_t state[5]; diff --git a/Swiften/StringCodecs/UnitTest/HMACSHA1Test.cpp b/Swiften/StringCodecs/UnitTest/HMACSHA1Test.cpp deleted file mode 100644 index d8cba42..0000000 --- a/Swiften/StringCodecs/UnitTest/HMACSHA1Test.cpp +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Copyright (c) 2010 Remko Tronçon - * Licensed under the GNU General Public License v3. - * See Documentation/Licenses/GPLv3.txt for more information. - */ - -#include <Swiften/Base/ByteArray.h> -#include <QA/Checker/IO.h> - -#include <cppunit/extensions/HelperMacros.h> -#include <cppunit/extensions/TestFactoryRegistry.h> - -#include <Swiften/Base/ByteArray.h> -#include <Swiften/StringCodecs/HMACSHA1.h> - -using namespace Swift; - -class HMACSHA1Test : public CppUnit::TestFixture { - CPPUNIT_TEST_SUITE(HMACSHA1Test); - CPPUNIT_TEST(testGetResult); - CPPUNIT_TEST_SUITE_END(); - - public: - void testGetResult() { - ByteArray result(HMACSHA1::getResult(createSafeByteArray("foo"), createByteArray("foobar"))); - CPPUNIT_ASSERT_EQUAL(createByteArray("\xa4\xee\xba\x8e\x63\x3d\x77\x88\x69\xf5\x68\xd0\x5a\x1b\x3d\xc7\x2b\xfd\x4\xdd"), result); - } -}; - -CPPUNIT_TEST_SUITE_REGISTRATION(HMACSHA1Test); diff --git a/Swiften/StringCodecs/UnitTest/HMACTest.cpp b/Swiften/StringCodecs/UnitTest/HMACTest.cpp new file mode 100644 index 0000000..bdb0d96 --- /dev/null +++ b/Swiften/StringCodecs/UnitTest/HMACTest.cpp @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2010 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#include <Swiften/Base/ByteArray.h> +#include <QA/Checker/IO.h> + +#include <cppunit/extensions/HelperMacros.h> +#include <cppunit/extensions/TestFactoryRegistry.h> + +#include <Swiften/Base/ByteArray.h> +#include <Swiften/StringCodecs/HMAC.h> +#include <Swiften/StringCodecs/SHA1.h> + +using namespace Swift; + +class HMACTest : public CppUnit::TestFixture { + CPPUNIT_TEST_SUITE(HMACTest); + CPPUNIT_TEST(testGetResult); + CPPUNIT_TEST_SUITE_END(); + + public: + void testGetResult() { + ByteArray result(HMAC<SHA1>()(createSafeByteArray("foo"), createByteArray("foobar"))); + CPPUNIT_ASSERT_EQUAL(createByteArray("\xa4\xee\xba\x8e\x63\x3d\x77\x88\x69\xf5\x68\xd0\x5a\x1b\x3d\xc7\x2b\xfd\x4\xdd"), result); + } +}; + +CPPUNIT_TEST_SUITE_REGISTRATION(HMACTest); diff --git a/Swiften/StringCodecs/UnitTest/PBKDF2Test.cpp b/Swiften/StringCodecs/UnitTest/PBKDF2Test.cpp index d0aacd3..377e5c9 100644 --- a/Swiften/StringCodecs/UnitTest/PBKDF2Test.cpp +++ b/Swiften/StringCodecs/UnitTest/PBKDF2Test.cpp @@ -12,6 +12,8 @@ #include <Swiften/Base/ByteArray.h> #include <Swiften/StringCodecs/PBKDF2.h> +#include <Swiften/StringCodecs/HMAC.h> +#include <Swiften/StringCodecs/SHA1.h> using namespace Swift; @@ -24,19 +26,19 @@ class PBKDF2Test : public CppUnit::TestFixture { public: void testGetResult_I1() { - ByteArray result(PBKDF2::encode(createSafeByteArray("password"), createByteArray("salt"), 1)); + ByteArray result(PBKDF2::encode<HMAC<SHA1> >(createSafeByteArray("password"), createByteArray("salt"), 1)); CPPUNIT_ASSERT_EQUAL(createByteArray("\x0c\x60\xc8\x0f\x96\x1f\x0e\x71\xf3\xa9\xb5\x24\xaf\x60\x12\x06\x2f\xe0\x37\xa6"), result); } void testGetResult_I2() { - ByteArray result(PBKDF2::encode(createSafeByteArray("password"), createByteArray("salt"), 2)); + ByteArray result(PBKDF2::encode<HMAC<SHA1> >(createSafeByteArray("password"), createByteArray("salt"), 2)); CPPUNIT_ASSERT_EQUAL(createByteArray("\xea\x6c\x1\x4d\xc7\x2d\x6f\x8c\xcd\x1e\xd9\x2a\xce\x1d\x41\xf0\xd8\xde\x89\x57"), result); } void testGetResult_I4096() { - ByteArray result(PBKDF2::encode(createSafeByteArray("password"), createByteArray("salt"), 4096)); + ByteArray result(PBKDF2::encode<HMAC<SHA1> >(createSafeByteArray("password"), createByteArray("salt"), 4096)); CPPUNIT_ASSERT_EQUAL(createByteArray("\x4b\x00\x79\x1\xb7\x65\x48\x9a\xbe\xad\x49\xd9\x26\xf7\x21\xd0\x65\xa4\x29\xc1", 20), result); } -- cgit v0.10.2-6-g49f6