From 87d5557ecba47f0cfd323e79f7d9284c484f825a Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Remko=20Tron=C3=A7on?= <git@el-tramo.be>
Date: Sat, 27 Apr 2013 17:30:27 +0200
Subject: Make HMACSHA1 not be a Hash.

Change-Id: I798d468614d2285c6f77640c365b51b19df2bf73

diff --git a/Swiften/Crypto/CommonCryptoCryptoProvider.cpp b/Swiften/Crypto/CommonCryptoCryptoProvider.cpp
index f1810ba..14f9284 100644
--- a/Swiften/Crypto/CommonCryptoCryptoProvider.cpp
+++ b/Swiften/Crypto/CommonCryptoCryptoProvider.cpp
@@ -100,42 +100,11 @@ namespace {
 	};
 
 	template<typename T>
-	class HMACHash : public Hash {
-		public:
-			HMACHash(const T& key) : finalized(false) {
-				CCHmacInit(&context, kCCHmacAlgSHA1, vecptr(key), key.size());
-			}
-
-			~HMACHash() {
-			}
-
-			virtual Hash& update(const ByteArray& data) SWIFTEN_OVERRIDE {
-				return updateInternal(data);
-			}
-
-			virtual Hash& update(const SafeByteArray& data) SWIFTEN_OVERRIDE {
-				return updateInternal(data);
-			}
-
-			virtual std::vector<unsigned char> getHash() {
-				assert(!finalized);
-				std::vector<unsigned char> result(CC_SHA1_DIGEST_LENGTH);
-				CCHmacFinal(&context, vecptr(result));
-				return result;
-			}
-
-		private:
-			template<typename ContainerType>
-			Hash& updateInternal(const ContainerType& data) {
-				assert(!finalized);
-				CCHmacUpdate(&context, vecptr(data), boost::numeric_cast<CC_LONG>(data.size()));
-				return *this;
-			}
-
-		private:
-			CCHmacContext context;
-			bool finalized;
-	};
+	ByteArray getHMACSHA1Internal(const T& key, const ByteArray& data) {
+		std::vector<unsigned char> result(CC_SHA1_DIGEST_LENGTH);
+		CCHmac(kCCHmacAlgSHA1, vecptr(key), key.size(), vecptr(data), boost::numeric_cast<CC_LONG>(data.size()), vecptr(result));
+		return result;
+	}
 }
 
 CommonCryptoCryptoProvider::CommonCryptoCryptoProvider() {
@@ -152,15 +121,14 @@ Hash* CommonCryptoCryptoProvider::createMD5() {
 	return new MD5Hash();
 }
 
-Hash* CommonCryptoCryptoProvider::createHMACSHA1(const SafeByteArray& key) {
-	return new HMACHash<SafeByteArray>(key);
+ByteArray CommonCryptoCryptoProvider::getHMACSHA1(const SafeByteArray& key, const ByteArray& data) {
+	return getHMACSHA1Internal(key, data);
 }
 
-Hash* CommonCryptoCryptoProvider::createHMACSHA1(const ByteArray& key) {
-	return new HMACHash<ByteArray>(key);
+ByteArray CommonCryptoCryptoProvider::getHMACSHA1(const ByteArray& key, const ByteArray& data) {
+	return getHMACSHA1Internal(key, data);
 }
 
-
 bool CommonCryptoCryptoProvider::isMD5AllowedForCrypto() const {
 	return true;
 }
diff --git a/Swiften/Crypto/CommonCryptoCryptoProvider.h b/Swiften/Crypto/CommonCryptoCryptoProvider.h
index 8072c0d..f921e17 100644
--- a/Swiften/Crypto/CommonCryptoCryptoProvider.h
+++ b/Swiften/Crypto/CommonCryptoCryptoProvider.h
@@ -17,8 +17,8 @@ namespace Swift {
 
 			virtual Hash* createSHA1() SWIFTEN_OVERRIDE;
 			virtual Hash* createMD5() SWIFTEN_OVERRIDE;
-			virtual Hash* createHMACSHA1(const SafeByteArray& key) SWIFTEN_OVERRIDE;
-			virtual Hash* createHMACSHA1(const ByteArray& key) SWIFTEN_OVERRIDE;
+			virtual ByteArray getHMACSHA1(const SafeByteArray& key, const ByteArray& data) SWIFTEN_OVERRIDE;
+			virtual ByteArray getHMACSHA1(const ByteArray& key, const ByteArray& data) SWIFTEN_OVERRIDE;
 			virtual bool isMD5AllowedForCrypto() const SWIFTEN_OVERRIDE;
 	};
 }
diff --git a/Swiften/Crypto/CryptoProvider.h b/Swiften/Crypto/CryptoProvider.h
index afee8c4..c1e1eb9 100644
--- a/Swiften/Crypto/CryptoProvider.h
+++ b/Swiften/Crypto/CryptoProvider.h
@@ -1,39 +1,36 @@
-/*
- * Copyright (c) 2013 Remko Tronçon
- * Licensed under the GNU General Public License.
- * See the COPYING file for more information.
- */
-
-#pragma once
-
-#include <Swiften/Base/ByteArray.h>
-#include <Swiften/Base/SafeByteArray.h>
-#include <Swiften/Crypto/Hash.h>
-
-namespace Swift {
-	class Hash;
-
-	class CryptoProvider {
-		public:
-			virtual ~CryptoProvider();
-
-			virtual Hash* createSHA1() = 0;
-			virtual Hash* createMD5() = 0;
-			virtual Hash* createHMACSHA1(const SafeByteArray& key) = 0;
-			virtual Hash* createHMACSHA1(const ByteArray& key) = 0;
-			virtual bool isMD5AllowedForCrypto() const = 0;
-
-			// Convenience
-			template<typename T> ByteArray getSHA1Hash(const T& data) {
-				return boost::shared_ptr<Hash>(createSHA1())->update(data).getHash();
-			}
-
-			template<typename T> ByteArray getMD5Hash(const T& data) {
-				return boost::shared_ptr<Hash>(createMD5())->update(data).getHash();
-			}
-
-			template<typename T, typename U> ByteArray getHMACSHA1(const T& key, const U& data) {
-				return boost::shared_ptr<Hash>(createHMACSHA1(key))->update(data).getHash();
-			}
-	};
-}
+/*
+ * Copyright (c) 2013 Remko Tronçon
+ * Licensed under the GNU General Public License.
+ * See the COPYING file for more information.
+ */
+
+#pragma once
+
+#include <Swiften/Base/API.h>
+#include <Swiften/Base/ByteArray.h>
+#include <Swiften/Base/SafeByteArray.h>
+#include <Swiften/Crypto/Hash.h>
+
+namespace Swift {
+	class Hash;
+
+	class SWIFTEN_API CryptoProvider {
+		public:
+			virtual ~CryptoProvider();
+
+			virtual Hash* createSHA1() = 0;
+			virtual Hash* createMD5() = 0;
+			virtual ByteArray getHMACSHA1(const SafeByteArray& key, const ByteArray& data) = 0;
+			virtual ByteArray getHMACSHA1(const ByteArray& key, const ByteArray& data) = 0;
+			virtual bool isMD5AllowedForCrypto() const = 0;
+
+			// Convenience
+			template<typename T> ByteArray getSHA1Hash(const T& data) {
+				return boost::shared_ptr<Hash>(createSHA1())->update(data).getHash();
+			}
+
+			template<typename T> ByteArray getMD5Hash(const T& data) {
+				return boost::shared_ptr<Hash>(createMD5())->update(data).getHash();
+			}
+	};
+}
diff --git a/Swiften/Crypto/OpenSSLCryptoProvider.cpp b/Swiften/Crypto/OpenSSLCryptoProvider.cpp
index afe73aa..9b1d544 100644
--- a/Swiften/Crypto/OpenSSLCryptoProvider.cpp
+++ b/Swiften/Crypto/OpenSSLCryptoProvider.cpp
@@ -104,45 +104,12 @@ namespace {
 
 
 	template<typename T>
-	class HMACHash : public Hash {
-		public:
-			HMACHash(const T& key) : finalized(false) {
-				HMAC_CTX_init(&context);
-				HMAC_Init(&context, vecptr(key), boost::numeric_cast<int>(key.size()), EVP_sha1());
-			}
-
-			~HMACHash() {
-				HMAC_CTX_cleanup(&context);
-			}
-
-			virtual Hash& update(const ByteArray& data) SWIFTEN_OVERRIDE {
-				return updateInternal(data);
-			}
-
-			virtual Hash& update(const SafeByteArray& data) SWIFTEN_OVERRIDE {
-				return updateInternal(data);
-			}
-
-			virtual std::vector<unsigned char> getHash() {
-				assert(!finalized);
-				std::vector<unsigned char> result(SHA_DIGEST_LENGTH);
-				unsigned int len = SHA_DIGEST_LENGTH;
-				HMAC_Final(&context, vecptr(result), &len);
-				return result;
-			}
-
-		private:
-			template<typename ContainerType>
-			Hash& updateInternal(const ContainerType& data) {
-				assert(!finalized);
-				HMAC_Update(&context, vecptr(data), data.size());
-				return *this;
-			}
-
-		private:
-			HMAC_CTX context;
-			bool finalized;
-	};
+	ByteArray getHMACSHA1Internal(const T& key, const ByteArray& data) {
+		unsigned int len = SHA_DIGEST_LENGTH;
+		std::vector<unsigned char> result(len);
+		HMAC(EVP_sha1(), vecptr(key), boost::numeric_cast<int>(key.size()), vecptr(data), data.size(), vecptr(result), &len);
+		return result;
+	}
 }
 
 OpenSSLCryptoProvider::OpenSSLCryptoProvider() {
@@ -159,12 +126,12 @@ Hash* OpenSSLCryptoProvider::createMD5() {
 	return new MD5Hash();
 }
 
-Hash* OpenSSLCryptoProvider::createHMACSHA1(const SafeByteArray& key) {
-	return new HMACHash<SafeByteArray>(key);
+ByteArray OpenSSLCryptoProvider::getHMACSHA1(const SafeByteArray& key, const ByteArray& data) {
+	return getHMACSHA1Internal(key, data);
 }
 
-Hash* OpenSSLCryptoProvider::createHMACSHA1(const ByteArray& key) {
-	return new HMACHash<ByteArray>(key);
+ByteArray OpenSSLCryptoProvider::getHMACSHA1(const ByteArray& key, const ByteArray& data) {
+	return getHMACSHA1Internal(key, data);
 }
 
 bool OpenSSLCryptoProvider::isMD5AllowedForCrypto() const {
diff --git a/Swiften/Crypto/OpenSSLCryptoProvider.h b/Swiften/Crypto/OpenSSLCryptoProvider.h
index e9ca37b..9440aee 100644
--- a/Swiften/Crypto/OpenSSLCryptoProvider.h
+++ b/Swiften/Crypto/OpenSSLCryptoProvider.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013  Remko Tronçon
+ * Copyright (c) 2013 Remko Tronçon
  * Licensed under the GNU General Public License.
  * See the COPYING file for more information.
  */
@@ -17,8 +17,8 @@ namespace Swift {
 
 			virtual Hash* createSHA1() SWIFTEN_OVERRIDE;
 			virtual Hash* createMD5() SWIFTEN_OVERRIDE;
-			virtual Hash* createHMACSHA1(const SafeByteArray& key) SWIFTEN_OVERRIDE;
-			virtual Hash* createHMACSHA1(const ByteArray& key) SWIFTEN_OVERRIDE;
+			virtual ByteArray getHMACSHA1(const SafeByteArray& key, const ByteArray& data) SWIFTEN_OVERRIDE;
+			virtual ByteArray getHMACSHA1(const ByteArray& key, const ByteArray& data) SWIFTEN_OVERRIDE;
 			virtual bool isMD5AllowedForCrypto() const SWIFTEN_OVERRIDE;
 	};
 }
diff --git a/Swiften/Crypto/WindowsCryptoProvider.cpp b/Swiften/Crypto/WindowsCryptoProvider.cpp
index 7cc6a46..9ca4c14 100644
--- a/Swiften/Crypto/WindowsCryptoProvider.cpp
+++ b/Swiften/Crypto/WindowsCryptoProvider.cpp
@@ -1,256 +1,222 @@
-/*
- * Copyright (c) 2012 Kevin Smith
- * Licensed under the GNU General Public License.
- * See the COPYING file for more information.
- */
-
-/*
- * Copyright (c) 2013 Remko Tronçon
- * Licensed under the GNU General Public License.
- * See the COPYING file for more information.
- */
-
-#include <Swiften/Crypto/WindowsCryptoProvider.h>
-
-#include <Windows.h>
-#define SECURITY_WIN32
-#include <security.h>
-#include <Wincrypt.h>
-#include <cassert>
-#include <boost/smart_ptr/make_shared.hpp>
-
-#include <Swiften/Crypto/Hash.h>
-#include <Swiften/Base/ByteArray.h>
-#include <Swiften/Base/Algorithm.h>
-#include <Swiften/Base/WindowsRegistry.h>
-
-using namespace Swift;
-
-struct WindowsCryptoProvider::Private {
-	HCRYPTPROV context;
-};
-
-namespace {
-	class WindowsHash : public Hash {
-		public:
-			WindowsHash(HCRYPTPROV context, ALG_ID algorithm) : hash(NULL) {
-				if (!CryptCreateHash(context, algorithm, 0, 0, &hash)) {
-					assert(false);
-				}
-			}
-
-			~WindowsHash() {
-				CryptDestroyHash(hash);
-			}
-
-			virtual Hash& update(const ByteArray& data) SWIFTEN_OVERRIDE {
-				return updateInternal(data);
-			}
-
-			virtual Hash& update(const SafeByteArray& data) SWIFTEN_OVERRIDE {
-				return updateInternal(data);
-			}
-
-			virtual std::vector<unsigned char> getHash() {
-				std::vector<unsigned char> result;
-				DWORD hashLength = sizeof(DWORD);
-				DWORD hashSize;
-				CryptGetHashParam(hash, HP_HASHSIZE, reinterpret_cast<BYTE*>(&hashSize), &hashLength, 0);
-				result.resize(static_cast<size_t>(hashSize));
-				if (!CryptGetHashParam(hash, HP_HASHVAL, vecptr(result), &hashSize, 0)) {
-					assert(false);
-				}
-				result.resize(static_cast<size_t>(hashSize));
-				return result;
-			}
-
-		private:
-			template<typename ContainerType>
-			Hash& updateInternal(const ContainerType& data) {
-				if (!CryptHashData(hash, const_cast<BYTE*>(vecptr(data)), data.size(), 0)) {
-					assert(false);
-				}
-				return *this;
-			}
-
-		private:
-			HCRYPTHASH hash;
-	};
-
-#if 0
-	// Haven't tested the code below properly yet, but figured out after writing
-	// it that PLAINTEXTKEYBLOB doesn't work on XP or 2k, and the workaround is a
-	// bit too ugly to try this now. So, using our own algorithm for now.  See
-	// http://support.microsoft.com/kb/228786/en-us
-	
-	// MSDN describes this as PLAINTEXTKEYBLOB, but this struct doesn't exist,
-	// and seems to even conflict with the PLAINTEXTKEYBLOB constant. Redefining
-	// here.
-	struct PlainTextKeyBlob {
-		BLOBHEADER hdr;
-		DWORD dwKeySize;
-	};
-
-	class HMACHash : public Hash {
-		public:
-			template<typename T>
-			HMACHash(HCRYPTPROV context, const T& rawKey) : hash(NULL) {
-				// Import raw key
-				T blobData(sizeof(PlainTextKeyBlob) + rawKey.size());
-				PlainTextKeyBlob* blob = reinterpret_cast<PlainTextKeyBlob*>(vecptr(blobData));
-				blob->hdr.bType = PLAINTEXTKEYBLOB;
-				blob->hdr.bVersion = CUR_BLOB_VERSION;
-				blob->hdr.reserved = 0;
-				blob->hdr.aiKeyAlg = CALG_RC2;
-				blob->dwKeySize = rawKey.size();
-				std::copy(rawKey.begin(), rawKey.end(), blobData.begin() + sizeof(PlainTextKeyBlob));
-				HCRYPTKEY key;
-				if (!CryptImportKey(context, vecptr(blobData), blobData.size(), 0, CRYPT_IPSEC_HMAC_KEY, &key)) {
-					assert(false);
-					return;
-				}
-
-				// Create hash
-				if (!CryptCreateHash(context, CALG_HMAC, key, 0, &hash)) {
-					assert(false);
-					return;
-				}
-				ZeroMemory(&info, sizeof(info));
-				info.HashAlgid = CALG_SHA1;
-			}
-
-			~HMACHash() {
-				CryptDestroyHash(hash);
-			}
-
-			virtual Hash& update(const ByteArray& data) SWIFTEN_OVERRIDE {
-				return updateInternal(data);
-			}
-
-			virtual Hash& update(const SafeByteArray& data) SWIFTEN_OVERRIDE {
-				return updateInternal(data);
-			}
-
-			virtual std::vector<unsigned char> getHash() {
-				std::vector<unsigned char> result;
-				DWORD hashLength = sizeof(DWORD);
-				DWORD hashSize;
-				CryptGetHashParam(hash, HP_HASHSIZE, reinterpret_cast<BYTE*>(&hashSize), &hashLength, 0);
-				result.resize(static_cast<size_t>(hashSize));
-				if (!CryptGetHashParam(hash, HP_HASHVAL, vecptr(result), &hashSize, 0)) {
-					assert(false);
-				}
-				result.resize(static_cast<size_t>(hashSize));
-				return result;
-			}
-
-		private:
-			template<typename ContainerType>
-			Hash& updateInternal(const ContainerType& data) {
-				if (!CryptHashData(hash, const_cast<BYTE*>(vecptr(data)), data.size(), 0)) {
-					assert(false);
-				}
-				return *this;
-			}
-
-		private:
-			HCRYPTHASH hash;
-			HMAC_INFO info;
-	};
-#endif
-
-	// Simple implementation. You can only call 'update' once.
-	template<typename T>
-	class HMACHash : public Hash {
-		public:
-			HMACHash(const T& key, CryptoProvider* crypto) : crypto(crypto), finished(false) {
-				if (key.size() <= BLOCK_SIZE) {
-					paddedKey = key;
-				}
-				else {
-					assign(paddedKey, crypto->getSHA1Hash(key));
-				}
-				paddedKey.resize(BLOCK_SIZE, 0x0);
-			}
-
-			~HMACHash() {
-			}
-
-			virtual Hash& update(const ByteArray& data) SWIFTEN_OVERRIDE {
-				return updateInternal(data);
-			}
-
-			virtual Hash& update(const SafeByteArray& data) SWIFTEN_OVERRIDE {
-				return updateInternal(data);
-			}
-
-			virtual std::vector<unsigned char> getHash() {
-				return result;
-			}
-
-		private:
-			template<typename ContainerType>
-			Hash& updateInternal(const ContainerType& data) {
-				assert(!finished);
-
-				// Create the first value
-				T x(paddedKey);
-				for (unsigned int i = 0; i < x.size(); ++i) {
-					x[i] ^= 0x36;
-				}
-				append(x, data);
-
-				// Create the second value
-				T y(paddedKey);
-				for (unsigned int i = 0; i < y.size(); ++i) {
-					y[i] ^= 0x5c;
-				}
-				append(y, crypto->getSHA1Hash(x));
-				result = crypto->getSHA1Hash(y);
-
-				finished = true;
-				return *this;
-			}
-
-		private:
-			static const int BLOCK_SIZE = 64;
-			CryptoProvider* crypto;
-			T paddedKey;
-			SafeByteArray data;
-			bool finished;
-			std::vector<unsigned char> result;
-	};
-
-
-}
-
-WindowsCryptoProvider::WindowsCryptoProvider() {
-	p = boost::make_shared<Private>();
-	if (!CryptAcquireContext(&p->context, NULL, NULL, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT)) {
-		assert(false);
-	}
-}
-
-WindowsCryptoProvider::~WindowsCryptoProvider() {
-	CryptReleaseContext(p->context, 0);
-}
-
-Hash* WindowsCryptoProvider::createSHA1() {
-	return new WindowsHash(p->context, CALG_SHA1);
-}
-
-Hash* WindowsCryptoProvider::createMD5() {
-	return new WindowsHash(p->context, CALG_MD5);
-}
-
-bool WindowsCryptoProvider::isMD5AllowedForCrypto() const {
-	return !WindowsRegistry::isFIPSEnabled();
-}
-
-Hash* WindowsCryptoProvider::createHMACSHA1(const SafeByteArray& key) {
-	return new HMACHash<SafeByteArray>(key, this);
-}
-
-Hash* WindowsCryptoProvider::createHMACSHA1(const ByteArray& key) {
-	return new HMACHash<ByteArray>(key, this);
-}
+/*
+ * Copyright (c) 2012 Kevin Smith
+ * Licensed under the GNU General Public License.
+ * See the COPYING file for more information.
+ */
+
+/*
+ * Copyright (c) 2013 Remko Tronçon
+ * Licensed under the GNU General Public License.
+ * See the COPYING file for more information.
+ */
+
+#include <Swiften/Crypto/WindowsCryptoProvider.h>
+
+#include <Windows.h>
+#define SECURITY_WIN32
+#include <security.h>
+#include <Wincrypt.h>
+#include <cassert>
+#include <boost/smart_ptr/make_shared.hpp>
+
+#include <Swiften/Crypto/Hash.h>
+#include <Swiften/Base/ByteArray.h>
+#include <Swiften/Base/Algorithm.h>
+#include <Swiften/Base/WindowsRegistry.h>
+
+using namespace Swift;
+
+struct WindowsCryptoProvider::Private {
+	HCRYPTPROV context;
+};
+
+namespace {
+	class WindowsHash : public Hash {
+		public:
+			WindowsHash(HCRYPTPROV context, ALG_ID algorithm) : hash(NULL) {
+				if (!CryptCreateHash(context, algorithm, 0, 0, &hash)) {
+					assert(false);
+				}
+			}
+
+			~WindowsHash() {
+				CryptDestroyHash(hash);
+			}
+
+			virtual Hash& update(const ByteArray& data) SWIFTEN_OVERRIDE {
+				return updateInternal(data);
+			}
+
+			virtual Hash& update(const SafeByteArray& data) SWIFTEN_OVERRIDE {
+				return updateInternal(data);
+			}
+
+			virtual std::vector<unsigned char> getHash() {
+				std::vector<unsigned char> result;
+				DWORD hashLength = sizeof(DWORD);
+				DWORD hashSize;
+				CryptGetHashParam(hash, HP_HASHSIZE, reinterpret_cast<BYTE*>(&hashSize), &hashLength, 0);
+				result.resize(static_cast<size_t>(hashSize));
+				if (!CryptGetHashParam(hash, HP_HASHVAL, vecptr(result), &hashSize, 0)) {
+					assert(false);
+				}
+				result.resize(static_cast<size_t>(hashSize));
+				return result;
+			}
+
+		private:
+			template<typename ContainerType>
+			Hash& updateInternal(const ContainerType& data) {
+				if (!CryptHashData(hash, const_cast<BYTE*>(vecptr(data)), data.size(), 0)) {
+					assert(false);
+				}
+				return *this;
+			}
+
+		private:
+			HCRYPTHASH hash;
+	};
+
+#if 0 // NOT YET DONE
+	// Haven't tested the code below properly yet, but figured out after writing
+	// it that PLAINTEXTKEYBLOB doesn't work on XP or 2k, and the workaround is a
+	// bit too ugly to try this now. So, using our own algorithm for now.  See
+	// http://support.microsoft.com/kb/228786/en-us
+	
+	// MSDN describes this as PLAINTEXTKEYBLOB, but this struct doesn't exist,
+	// and seems to even conflict with the PLAINTEXTKEYBLOB constant. Redefining
+	// here.
+	struct PlainTextKeyBlob {
+		BLOBHEADER hdr;
+		DWORD dwKeySize;
+	};
+
+	class HMACHash : public Hash {
+		public:
+			template<typename T>
+			HMACHash(HCRYPTPROV context, const T& rawKey) : hash(NULL) {
+				// Import raw key
+				T blobData(sizeof(PlainTextKeyBlob) + rawKey.size());
+				PlainTextKeyBlob* blob = reinterpret_cast<PlainTextKeyBlob*>(vecptr(blobData));
+				blob->hdr.bType = PLAINTEXTKEYBLOB;
+				blob->hdr.bVersion = CUR_BLOB_VERSION;
+				blob->hdr.reserved = 0;
+				blob->hdr.aiKeyAlg = CALG_RC2;
+				blob->dwKeySize = rawKey.size();
+				std::copy(rawKey.begin(), rawKey.end(), blobData.begin() + sizeof(PlainTextKeyBlob));
+				HCRYPTKEY key;
+				if (!CryptImportKey(context, vecptr(blobData), blobData.size(), 0, CRYPT_IPSEC_HMAC_KEY, &key)) {
+					assert(false);
+					return;
+				}
+
+				// Create hash
+				if (!CryptCreateHash(context, CALG_HMAC, key, 0, &hash)) {
+					assert(false);
+					return;
+				}
+				ZeroMemory(&info, sizeof(info));
+				info.HashAlgid = CALG_SHA1;
+			}
+
+			~HMACHash() {
+				CryptDestroyHash(hash);
+			}
+
+			virtual Hash& update(const ByteArray& data) SWIFTEN_OVERRIDE {
+				return updateInternal(data);
+			}
+
+			virtual Hash& update(const SafeByteArray& data) SWIFTEN_OVERRIDE {
+				return updateInternal(data);
+			}
+
+			virtual std::vector<unsigned char> getHash() {
+				std::vector<unsigned char> result;
+				DWORD hashLength = sizeof(DWORD);
+				DWORD hashSize;
+				CryptGetHashParam(hash, HP_HASHSIZE, reinterpret_cast<BYTE*>(&hashSize), &hashLength, 0);
+				result.resize(static_cast<size_t>(hashSize));
+				if (!CryptGetHashParam(hash, HP_HASHVAL, vecptr(result), &hashSize, 0)) {
+					assert(false);
+				}
+				result.resize(static_cast<size_t>(hashSize));
+				return result;
+			}
+
+		private:
+			template<typename ContainerType>
+			Hash& updateInternal(const ContainerType& data) {
+				if (!CryptHashData(hash, const_cast<BYTE*>(vecptr(data)), data.size(), 0)) {
+					assert(false);
+				}
+				return *this;
+			}
+
+		private:
+			HCRYPTHASH hash;
+			HMAC_INFO info;
+	};
+#endif
+
+	// Simple implementation.
+	template<typename T>
+	ByteArray getHMACSHA1Internal(const T& key, const ByteArray& data, CryptoProvider* crypto) {
+		static const int BLOCK_SIZE = 64;
+
+		T paddedKey;
+		if (key.size() <= BLOCK_SIZE) {
+			paddedKey = key;
+		}
+		else {
+			assign(paddedKey, crypto->getSHA1Hash(key));
+		}
+		paddedKey.resize(BLOCK_SIZE, 0x0);
+
+		// Create the first value
+		T x(paddedKey);
+		for (unsigned int i = 0; i < x.size(); ++i) {
+			x[i] ^= 0x36;
+		}
+		append(x, data);
+
+		// Create the second value
+		T y(paddedKey);
+		for (unsigned int i = 0; i < y.size(); ++i) {
+			y[i] ^= 0x5c;
+		}
+		append(y, crypto->getSHA1Hash(x));
+		return crypto->getSHA1Hash(y);
+	}
+}
+
+WindowsCryptoProvider::WindowsCryptoProvider() {
+	p = boost::make_shared<Private>();
+	if (!CryptAcquireContext(&p->context, NULL, NULL, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT)) {
+		assert(false);
+	}
+}
+
+WindowsCryptoProvider::~WindowsCryptoProvider() {
+	CryptReleaseContext(p->context, 0);
+}
+
+Hash* WindowsCryptoProvider::createSHA1() {
+	return new WindowsHash(p->context, CALG_SHA1);
+}
+
+Hash* WindowsCryptoProvider::createMD5() {
+	return new WindowsHash(p->context, CALG_MD5);
+}
+
+bool WindowsCryptoProvider::isMD5AllowedForCrypto() const {
+	return !WindowsRegistry::isFIPSEnabled();
+}
+
+ByteArray WindowsCryptoProvider::getHMACSHA1(const SafeByteArray& key, const ByteArray& data) {
+	return getHMACSHA1Internal(key, data, this);
+}
+
+ByteArray WindowsCryptoProvider::getHMACSHA1(const ByteArray& key, const ByteArray& data) {
+	return getHMACSHA1Internal(key, data, this);
+}
diff --git a/Swiften/Crypto/WindowsCryptoProvider.h b/Swiften/Crypto/WindowsCryptoProvider.h
index 242d4c2..9418fc0 100644
--- a/Swiften/Crypto/WindowsCryptoProvider.h
+++ b/Swiften/Crypto/WindowsCryptoProvider.h
@@ -1,30 +1,30 @@
-/*
- * Copyright (c) 2013  Remko Tronçon
- * Licensed under the GNU General Public License.
- * See the COPYING file for more information.
- */
-
-#pragma once
-
-#include <Swiften/Crypto/CryptoProvider.h>
-#include <Swiften/Base/Override.h>
-#include <boost/noncopyable.hpp>
-#include <boost/shared_ptr.hpp>
-
-namespace Swift {
-	class WindowsCryptoProvider : public CryptoProvider, public boost::noncopyable {
-		public:
-			WindowsCryptoProvider();
-			~WindowsCryptoProvider();
-
-			virtual Hash* createSHA1() SWIFTEN_OVERRIDE;
-			virtual Hash* createMD5() SWIFTEN_OVERRIDE;
-			virtual Hash* createHMACSHA1(const SafeByteArray& key) SWIFTEN_OVERRIDE;
-			virtual Hash* createHMACSHA1(const ByteArray& key) SWIFTEN_OVERRIDE;
-			virtual bool isMD5AllowedForCrypto() const SWIFTEN_OVERRIDE;
-
-		private:
-			struct Private;
-			boost::shared_ptr<Private> p;
-	};
-}
+/*
+ * Copyright (c) 2013  Remko Tronçon
+ * Licensed under the GNU General Public License.
+ * See the COPYING file for more information.
+ */
+
+#pragma once
+
+#include <Swiften/Crypto/CryptoProvider.h>
+#include <Swiften/Base/Override.h>
+#include <boost/noncopyable.hpp>
+#include <boost/shared_ptr.hpp>
+
+namespace Swift {
+	class WindowsCryptoProvider : public CryptoProvider, public boost::noncopyable {
+		public:
+			WindowsCryptoProvider();
+			~WindowsCryptoProvider();
+
+			virtual Hash* createSHA1() SWIFTEN_OVERRIDE;
+			virtual Hash* createMD5() SWIFTEN_OVERRIDE;
+			virtual ByteArray getHMACSHA1(const SafeByteArray& key, const ByteArray& data) SWIFTEN_OVERRIDE;
+			virtual ByteArray getHMACSHA1(const ByteArray& key, const ByteArray& data) SWIFTEN_OVERRIDE;
+			virtual bool isMD5AllowedForCrypto() const SWIFTEN_OVERRIDE;
+
+		private:
+			struct Private;
+			boost::shared_ptr<Private> p;
+	};
+}
-- 
cgit v0.10.2-6-g49f6