diff options
-rw-r--r-- | Swiften/SASL/SCRAMSHA1ClientAuthenticator.cpp | 56 | ||||
-rw-r--r-- | Swiften/SASL/SCRAMSHA1ClientAuthenticator.h | 30 | ||||
-rw-r--r-- | Swiften/StringCodecs/HMACSHA1.cpp | 39 | ||||
-rw-r--r-- | Swiften/StringCodecs/HMACSHA1.h | 10 | ||||
-rw-r--r-- | Swiften/StringCodecs/UnitTest/HMACSHA1Test.cpp | 21 |
5 files changed, 156 insertions, 0 deletions
diff --git a/Swiften/SASL/SCRAMSHA1ClientAuthenticator.cpp b/Swiften/SASL/SCRAMSHA1ClientAuthenticator.cpp new file mode 100644 index 0000000..b2e85e9 --- /dev/null +++ b/Swiften/SASL/SCRAMSHA1ClientAuthenticator.cpp @@ -0,0 +1,56 @@ +#include "Swiften/SASL/SCRAMSHA1ClientAuthenticator.h" + +#include <cassert> + +#include "Swiften/StringCodecs/SHA1.h" +#include "Swiften/StringCodecs/HMACSHA1.h" + +namespace Swift { + +SCRAMSHA1ClientAuthenticator::SCRAMSHA1ClientAuthenticator(const String& authcid, const String& password, const String& authzid, const ByteArray& nonce) : step(Initial), authcid(authcid), password(password), authzid(authzid), clientnonce(nonce) { +} + +ByteArray SCRAMSHA1ClientAuthenticator::getMessage() const { + if (step == Initial) { + return getInitialClientMessage(); + } + else { + ByteArray mask = HMACSHA1::getResult(getClientVerifier(), initialServerMessage + getInitialClientMessage()); + ByteArray p = SHA1::getBinaryHash(password); + for (unsigned int i = 0; i < p.getSize(); ++i) { + p[i] ^= mask[i]; + } + return p; + } +} + +bool SCRAMSHA1ClientAuthenticator::setResponse(const ByteArray& response) { + if (step == Initial) { + initialServerMessage = response; + step = Proof; + return getSalt().getSize() > 0; + } + else { + return response == HMACSHA1::getResult(getClientVerifier(), getInitialClientMessage() + initialServerMessage); + } +} + +ByteArray SCRAMSHA1ClientAuthenticator::getSalt() const { + if (initialServerMessage.getSize() < 8) { + std::cerr << "ERROR: SCRAM-SHA1: Invalid server response" << std::endl; + return ByteArray(); + } + else { + return ByteArray(initialServerMessage.getData(), 8); + } +} + +ByteArray SCRAMSHA1ClientAuthenticator::getClientVerifier() const { + return HMACSHA1::getResult(SHA1::getBinaryHash(password), getSalt()); +} + +ByteArray SCRAMSHA1ClientAuthenticator::getInitialClientMessage() const { + return ByteArray(authzid) + '\0' + ByteArray(authcid) + '\0' + ByteArray(clientnonce); +} + +} diff --git a/Swiften/SASL/SCRAMSHA1ClientAuthenticator.h b/Swiften/SASL/SCRAMSHA1ClientAuthenticator.h new file mode 100644 index 0000000..d129468 --- /dev/null +++ b/Swiften/SASL/SCRAMSHA1ClientAuthenticator.h @@ -0,0 +1,30 @@ +#pragma once + +#include "Swiften/Base/String.h" +#include "Swiften/Base/ByteArray.h" + +namespace Swift { + class SCRAMSHA1ClientAuthenticator { + public: + SCRAMSHA1ClientAuthenticator(const String& authcid, const String& password, const String& authzid, const ByteArray& nonce); + + ByteArray getMessage() const; + bool setResponse(const ByteArray&); + + private: + ByteArray getInitialClientMessage() const; + ByteArray getSalt() const; + ByteArray getClientVerifier() const; + + private: + enum Step { + Initial, + Proof + } step; + String authcid; + String password; + String authzid; + ByteArray clientnonce; + ByteArray initialServerMessage; + }; +} diff --git a/Swiften/StringCodecs/HMACSHA1.cpp b/Swiften/StringCodecs/HMACSHA1.cpp new file mode 100644 index 0000000..59f1482 --- /dev/null +++ b/Swiften/StringCodecs/HMACSHA1.cpp @@ -0,0 +1,39 @@ +#include "Swiften/StringCodecs/HMACSHA1.h" + +#include <cassert> + +#include "Swiften/StringCodecs/SHA1.h" +#include "Swiften/Base/ByteArray.h" + +namespace Swift { + +static const unsigned int B = 64; + +ByteArray HMACSHA1::getResult(const ByteArray& key, const ByteArray& data) { + assert(key.getSize() <= B); + + // Create the padded key + ByteArray paddedKey(key); + paddedKey.resize(B); + for (unsigned int i = key.getSize(); i < paddedKey.getSize(); ++i) { + paddedKey[i] = 0x0; + } + + // Create the first value + ByteArray x(paddedKey); + for (unsigned int i = 0; i < x.getSize(); ++i) { + x[i] ^= 0x36; + } + x += data; + + // Create the second value + ByteArray y(paddedKey); + for (unsigned int i = 0; i < y.getSize(); ++i) { + y[i] ^= 0x5c; + } + y += SHA1::getBinaryHash(x); + + return SHA1::getBinaryHash(y); +} + +} diff --git a/Swiften/StringCodecs/HMACSHA1.h b/Swiften/StringCodecs/HMACSHA1.h new file mode 100644 index 0000000..698e4bc --- /dev/null +++ b/Swiften/StringCodecs/HMACSHA1.h @@ -0,0 +1,10 @@ +#pragma once + +namespace Swift { + class ByteArray; + + class HMACSHA1 { + public: + static ByteArray getResult(const ByteArray& key, const ByteArray& data); + }; +} diff --git a/Swiften/StringCodecs/UnitTest/HMACSHA1Test.cpp b/Swiften/StringCodecs/UnitTest/HMACSHA1Test.cpp new file mode 100644 index 0000000..edfae10 --- /dev/null +++ b/Swiften/StringCodecs/UnitTest/HMACSHA1Test.cpp @@ -0,0 +1,21 @@ +#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("foo", "foobar")); + CPPUNIT_ASSERT_EQUAL(ByteArray("\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); |