diff options
author | Remko Tronçon <git@el-tramo.be> | 2011-04-04 20:51:49 (GMT) |
---|---|---|
committer | Remko Tronçon <git@el-tramo.be> | 2011-04-18 19:11:40 (GMT) |
commit | 1a92834490cda1352a46eaef02a4e7ff76ab94e3 (patch) | |
tree | 393a65efb8eb4aa7f284a9b46f2604bf1d295e5a | |
parent | 36c2dbefc06607483eb0d309e3a9a4ad1f4f8f73 (diff) | |
download | swift-contrib-1a92834490cda1352a46eaef02a4e7ff76ab94e3.zip swift-contrib-1a92834490cda1352a46eaef02a4e7ff76ab94e3.tar.bz2 |
Make SHA1 stateful.
Resolves: #814
-rw-r--r-- | Swiften/StringCodecs/SHA1.cpp | 69 | ||||
-rw-r--r-- | Swiften/StringCodecs/SHA1.h | 27 | ||||
-rw-r--r-- | Swiften/StringCodecs/UnitTest/SHA1Test.cpp | 53 |
3 files changed, 117 insertions, 32 deletions
diff --git a/Swiften/StringCodecs/SHA1.cpp b/Swiften/StringCodecs/SHA1.cpp index 9882f70..a78a7b0 100644 --- a/Swiften/StringCodecs/SHA1.cpp +++ b/Swiften/StringCodecs/SHA1.cpp @@ -4,10 +4,14 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ +#include <Swiften/StringCodecs/SHA1.h> + #include "Swiften/Base/Platform.h" #pragma GCC diagnostic ignored "-Wold-style-cast" +using namespace Swift; + /* SHA-1 in C By Steve Reid <steve@edmweb.com> @@ -25,21 +29,9 @@ A million repetitions of "a" /* #define LITTLE_ENDIAN * This should be #define'd if true. */ /* #define SHA1HANDSOFF * Copies data before messing with it. */ -#include <boost/cstdint.hpp> #include <stdio.h> #include <string.h> -typedef struct { - boost::uint32_t state[5]; - boost::uint32_t count[2]; - boost::uint8_t buffer[64]; -} SHA1_CTX; - -void SHA1Transform(boost::uint32_t state[5], boost::uint8_t buffer[64]); -void SHA1Init(SHA1_CTX* context); -void SHA1Update(SHA1_CTX* context, boost::uint8_t* data, unsigned int len); -void SHA1Final(boost::uint8_t digest[20], SHA1_CTX* context); - #define rol(value, bits) (((value) << (bits)) | ((value) >> (32 - (bits)))) /* blk0() and blk() perform the initial expand. */ @@ -63,7 +55,7 @@ void SHA1Final(boost::uint8_t digest[20], SHA1_CTX* context); /* Hash a single 512-bit block. This is the core of the algorithm. */ -void SHA1Transform(boost::uint32_t state[5], boost::uint8_t buffer[64]) +void SHA1::Transform(boost::uint32_t state[5], boost::uint8_t buffer[64]) { boost::uint32_t a, b, c, d, e; typedef union { @@ -118,7 +110,7 @@ static boost::uint8_t workspace[64]; /* SHA1Init - Initialize new context */ -void SHA1Init(SHA1_CTX* context) +void SHA1::Init(SHA1::CTX* context) { /* SHA1 initialization constants */ context->state[0] = 0x67452301; @@ -132,7 +124,7 @@ void SHA1Init(SHA1_CTX* context) /* Run your data through this. */ -void SHA1Update(SHA1_CTX* context, boost::uint8_t* data, unsigned int len) +void SHA1::Update(SHA1::CTX* context, boost::uint8_t* data, unsigned int len) { unsigned int i, j; @@ -141,9 +133,9 @@ unsigned int i, j; context->count[1] += (len >> 29); if ((j + len) > 63) { memcpy(&context->buffer[j], data, (i = 64-j)); - SHA1Transform(context->state, context->buffer); + Transform(context->state, context->buffer); for ( ; i + 63 < len; i += 64) { - SHA1Transform(context->state, &data[i]); + Transform(context->state, &data[i]); } j = 0; } @@ -154,7 +146,7 @@ unsigned int i, j; /* Add padding and return the message digest. */ -void SHA1Final(boost::uint8_t digest[20], SHA1_CTX* context) +void SHA1::Final(boost::uint8_t digest[20], SHA1::CTX* context) { boost::uint32_t i, j; boost::uint8_t finalcount[8]; @@ -163,11 +155,11 @@ boost::uint8_t finalcount[8]; finalcount[i] = (boost::uint8_t) ((context->count[(i >= 4 ? 0 : 1)] >> ((3-(i & 3)) * 8) ) & 255); /* Endian independent */ } - SHA1Update(context, (boost::uint8_t *)("\200"), 1); + Update(context, (boost::uint8_t *)("\200"), 1); while ((context->count[0] & 504) != 448) { - SHA1Update(context, (boost::uint8_t *)("\0"), 1); + Update(context, (boost::uint8_t *)("\0"), 1); } - SHA1Update(context, finalcount, 8); /* Should cause a SHA1Transform() */ + Update(context, finalcount, 8); /* Should cause a SHA1Transform() */ for (i = 0; i < 20; i++) { digest[i] = (boost::uint8_t) ((context->state[i>>2] >> ((3-(i & 3)) * 8) ) & 255); @@ -179,24 +171,43 @@ boost::uint8_t finalcount[8]; memset(context->count, 0, 8); memset(&finalcount, 0, 8); #ifdef SHA1HANDSOFF /* make SHA1Transform overwrite it's own static vars */ - SHA1Transform(context->state, context->buffer); + Transform(context->state, context->buffer); #endif } // ----------------------------------------------------------------------------- -#include "Swiften/StringCodecs/SHA1.h" - namespace Swift { +SHA1::SHA1() { + Init(&context); +} + +SHA1& SHA1::update(const std::vector<unsigned char>& input) { + std::vector<unsigned char> inputCopy(input); + Update(&context, (boost::uint8_t*) &inputCopy[0], inputCopy.size()); + return *this; +} + +std::vector<unsigned char> SHA1::getHash() const { + std::vector<unsigned char> digest; + digest.resize(20); + CTX contextCopy(context); + Final((boost::uint8_t*) &digest[0], &contextCopy); + return digest; +} + ByteArray SHA1::getHash(const ByteArray& input) { - ByteArray inputCopy(input); + CTX context; + Init(&context); + + std::vector<unsigned char> inputCopy(input.getVector()); + Update(&context, (boost::uint8_t*) &inputCopy[0], inputCopy.size()); + ByteArray digest; digest.resize(20); - SHA1_CTX context; - SHA1Init(&context); - SHA1Update(&context, (boost::uint8_t*) inputCopy.getData(), inputCopy.getSize()); - SHA1Final((boost::uint8_t*) digest.getData(), &context); + Final((boost::uint8_t*) digest.getData(), &context); + return digest; } diff --git a/Swiften/StringCodecs/SHA1.h b/Swiften/StringCodecs/SHA1.h index fc5ba0e..9c0232a 100644 --- a/Swiften/StringCodecs/SHA1.h +++ b/Swiften/StringCodecs/SHA1.h @@ -6,11 +6,38 @@ #pragma once +#include <vector> +#include <boost/cstdint.hpp> + #include "Swiften/Base/ByteArray.h" namespace Swift { class SHA1 { public: + SHA1(); + + SHA1& update(const std::vector<unsigned char>& data); + std::vector<unsigned char> getHash() const; + + /** + * Equivalent of: + * SHA1().update(data),getHash(), but slightly more efficient and + * convenient. + */ static ByteArray getHash(const ByteArray& data); + + private: + typedef struct { + boost::uint32_t state[5]; + boost::uint32_t count[2]; + boost::uint8_t buffer[64]; + } CTX; + static void Init(CTX* context); + static void Transform(boost::uint32_t state[5], boost::uint8_t buffer[64]); + static void Update(CTX* context, boost::uint8_t* data, unsigned int len); + static void Final(boost::uint8_t digest[20], CTX* context); + + private: + CTX context; }; } diff --git a/Swiften/StringCodecs/UnitTest/SHA1Test.cpp b/Swiften/StringCodecs/UnitTest/SHA1Test.cpp index 9434235..984f512 100644 --- a/Swiften/StringCodecs/UnitTest/SHA1Test.cpp +++ b/Swiften/StringCodecs/UnitTest/SHA1Test.cpp @@ -16,18 +16,65 @@ using namespace Swift; class SHA1Test : public CppUnit::TestFixture { CPPUNIT_TEST_SUITE(SHA1Test); CPPUNIT_TEST(testGetHash); - CPPUNIT_TEST(testGetHash_Twice); + CPPUNIT_TEST(testGetHash_TwoUpdates); + CPPUNIT_TEST(testGetHash_TwoGetHash); CPPUNIT_TEST(testGetHash_NoData); + CPPUNIT_TEST(testGetHash_InterleavedUpdate); + CPPUNIT_TEST(testGetHashStatic); + CPPUNIT_TEST(testGetHashStatic_Twice); + CPPUNIT_TEST(testGetHashStatic_NoData); CPPUNIT_TEST_SUITE_END(); public: void testGetHash() { + SHA1 sha; + sha.update(ByteArray::create("client/pc//Exodus 0.9.1<http://jabber.org/protocol/caps<http://jabber.org/protocol/disco#info<http://jabber.org/protocol/disco#items<http://jabber.org/protocol/muc<")); + + CPPUNIT_ASSERT_EQUAL(ByteArray::create("\x42\x06\xb2\x3c\xa6\xb0\xa6\x43\xd2\x0d\x89\xb0\x4f\xf5\x8c\xf7\x8b\x80\x96\xed"), sha.getHash()); + } + + void testGetHash_TwoUpdates() { + SHA1 sha; + sha.update(ByteArray::create("client/pc//Exodus 0.9.1<http://jabber.org/protocol/caps<")); + sha.update(ByteArray::create("http://jabber.org/protocol/disco#info<http://jabber.org/protocol/disco#items<http://jabber.org/protocol/muc<")); + + CPPUNIT_ASSERT_EQUAL(ByteArray::create("\x42\x06\xb2\x3c\xa6\xb0\xa6\x43\xd2\x0d\x89\xb0\x4f\xf5\x8c\xf7\x8b\x80\x96\xed"), sha.getHash()); + } + + void testGetHash_TwoGetHash() { + SHA1 sha; + sha.update(ByteArray::create("client/pc//Exodus 0.9.1<http://jabber.org/protocol/caps<http://jabber.org/protocol/disco#info<http://jabber.org/protocol/disco#items<http://jabber.org/protocol/muc<")); + + sha.getHash(); + + CPPUNIT_ASSERT_EQUAL(ByteArray::create("\x42\x06\xb2\x3c\xa6\xb0\xa6\x43\xd2\x0d\x89\xb0\x4f\xf5\x8c\xf7\x8b\x80\x96\xed"), sha.getHash()); + } + + void testGetHash_InterleavedUpdate() { + SHA1 sha; + + sha.update(ByteArray::create("client/pc//Exodus 0.9.1<http://jabber.org/protocol/caps<")); + sha.getHash(); + sha.update(ByteArray::create("http://jabber.org/protocol/disco#info<http://jabber.org/protocol/disco#items<http://jabber.org/protocol/muc<")); + + CPPUNIT_ASSERT_EQUAL(ByteArray::create("\x42\x06\xb2\x3c\xa6\xb0\xa6\x43\xd2\x0d\x89\xb0\x4f\xf5\x8c\xf7\x8b\x80\x96\xed"), sha.getHash()); + } + + + void testGetHash_NoData() { + SHA1 sha; + sha.update(std::vector<unsigned char>()); + + CPPUNIT_ASSERT_EQUAL(ByteArray::create("\xda\x39\xa3\xee\x5e\x6b\x4b\x0d\x32\x55\xbf\xef\x95\x60\x18\x90\xaf\xd8\x07\x09"), sha.getHash()); + } + + void testGetHashStatic() { ByteArray result(SHA1::getHash("client/pc//Exodus 0.9.1<http://jabber.org/protocol/caps<http://jabber.org/protocol/disco#info<http://jabber.org/protocol/disco#items<http://jabber.org/protocol/muc<")); CPPUNIT_ASSERT_EQUAL(ByteArray("\x42\x06\xb2\x3c\xa6\xb0\xa6\x43\xd2\x0d\x89\xb0\x4f\xf5\x8c\xf7\x8b\x80\x96\xed"), result); } - void testGetHash_Twice() { + void testGetHashStatic_Twice() { ByteArray input("client/pc//Exodus 0.9.1<http://jabber.org/protocol/caps<http://jabber.org/protocol/disco#info<http://jabber.org/protocol/disco#items<http://jabber.org/protocol/muc<"); SHA1::getHash(input); ByteArray result(SHA1::getHash(input)); @@ -35,7 +82,7 @@ class SHA1Test : public CppUnit::TestFixture { CPPUNIT_ASSERT_EQUAL(ByteArray("\x42\x06\xb2\x3c\xa6\xb0\xa6\x43\xd2\x0d\x89\xb0\x4f\xf5\x8c\xf7\x8b\x80\x96\xed"), result); } - void testGetHash_NoData() { + void testGetHashStatic_NoData() { ByteArray result(SHA1::getHash(ByteArray())); CPPUNIT_ASSERT_EQUAL(ByteArray("\xda\x39\xa3\xee\x5e\x6b\x4b\x0d\x32\x55\xbf\xef\x95\x60\x18\x90\xaf\xd8\x07\x09"), result); |