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