diff options
Diffstat (limited to 'Swiften/StringCodecs')
-rw-r--r-- | Swiften/StringCodecs/Base64.cpp | 109 | ||||
-rw-r--r-- | Swiften/StringCodecs/Base64.h | 18 | ||||
-rw-r--r-- | Swiften/StringCodecs/Makefile.inc | 5 | ||||
-rw-r--r-- | Swiften/StringCodecs/SHA1.cpp | 196 | ||||
-rw-r--r-- | Swiften/StringCodecs/SHA1.h | 13 | ||||
-rw-r--r-- | Swiften/StringCodecs/UnitTest/Base64Test.cpp | 35 | ||||
-rw-r--r-- | Swiften/StringCodecs/UnitTest/Makefile.inc | 3 | ||||
-rw-r--r-- | Swiften/StringCodecs/UnitTest/SHA1Test.cpp | 23 |
8 files changed, 402 insertions, 0 deletions
diff --git a/Swiften/StringCodecs/Base64.cpp b/Swiften/StringCodecs/Base64.cpp new file mode 100644 index 0000000..03b0896 --- /dev/null +++ b/Swiften/StringCodecs/Base64.cpp @@ -0,0 +1,109 @@ +#include <boost/numeric/conversion/cast.hpp> + +#include "Swiften/StringCodecs/Base64.h" + +namespace Swift { + +#pragma GCC diagnostic ignored "-Wold-style-cast" + +String Base64::encode(const ByteArray &s) { + int i; + int len = s.getSize(); + char tbl[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/="; + int a, b, c; + + std::string p; + p.resize((len+2)/3*4); + int at = 0; + for( i = 0; i < len; i += 3 ) { + a = ((unsigned char) (s[i]) & 3) << 4; + if(i + 1 < len) { + a += (unsigned char) (s[i + 1]) >> 4; + b = ((unsigned char) (s[i + 1]) & 0xF) << 2; + if(i + 2 < len) { + b += (unsigned char) (s[i + 2]) >> 6; + c = (unsigned char) (s[i + 2]) & 0x3F; + } + else + c = 64; + } + else { + b = c = 64; + } + + p[at++] = tbl[(unsigned char) (s[i]) >> 2]; + p[at++] = tbl[a]; + p[at++] = tbl[b]; + p[at++] = tbl[c]; + } + return p; +} + +ByteArray Base64::decode(const String& input) { + String inputWithoutNewlines(input); + inputWithoutNewlines.removeAll('\n'); + + const std::string& s = inputWithoutNewlines.getUTF8String(); + ByteArray p; + + // -1 specifies invalid + // 64 specifies eof + // everything else specifies data + + char tbl[] = { + -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, + -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, + -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,62,-1,-1,-1,63, + 52,53,54,55,56,57,58,59,60,61,-1,-1,-1,64,-1,-1, + -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11,12,13,14, + 15,16,17,18,19,20,21,22,23,24,25,-1,-1,-1,-1,-1, + -1,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40, + 41,42,43,44,45,46,47,48,49,50,51,-1,-1,-1,-1,-1, + -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, + -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, + -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, + -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, + -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, + -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, + -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, + -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, + }; + + // this should be a multiple of 4 + int len = s.size(); + + if(len % 4) { + return p; + } + + p.resize(len / 4 * 3); + + int i; + int at = 0; + + int a, b, c, d; + c = d = 0; + + for( i = 0; i < len; i += 4 ) { + a = tbl[boost::numeric_cast<int>(s[i])]; + b = tbl[boost::numeric_cast<int>(s[i + 1])]; + c = tbl[boost::numeric_cast<int>(s[i + 2])]; + d = tbl[boost::numeric_cast<int>(s[i + 3])]; + if((a == 64 || b == 64) || (a < 0 || b < 0 || c < 0 || d < 0)) { + p.resize(0); + return p; + } + p[at++] = ((a & 0x3F) << 2) | ((b >> 4) & 0x03); + p[at++] = ((b & 0x0F) << 4) | ((c >> 2) & 0x0F); + p[at++] = ((c & 0x03) << 6) | ((d >> 0) & 0x3F); + } + + if(c & 64) + p.resize(at - 2); + else if(d & 64) + p.resize(at - 1); + + return p; +} + +} diff --git a/Swiften/StringCodecs/Base64.h b/Swiften/StringCodecs/Base64.h new file mode 100644 index 0000000..41ff62e --- /dev/null +++ b/Swiften/StringCodecs/Base64.h @@ -0,0 +1,18 @@ +#ifndef SWIFTEN_STRINGCODECS_BASE64_H +#define SWIFTEN_STRINGCODECS_BASE64_H + +#include <vector> + +#include "Swiften/Base/String.h" +#include "Swiften/Base/ByteArray.h" + +namespace Swift { + class Base64 + { + public: + static String encode(const ByteArray& s); + static ByteArray decode(const String &s); + }; +} + +#endif diff --git a/Swiften/StringCodecs/Makefile.inc b/Swiften/StringCodecs/Makefile.inc new file mode 100644 index 0000000..dd91014 --- /dev/null +++ b/Swiften/StringCodecs/Makefile.inc @@ -0,0 +1,5 @@ +SWIFTEN_SOURCES += \ + Swiften/StringCodecs/Base64.cpp \ + Swiften/StringCodecs/SHA1.cpp + +include Swiften/StringCodecs/UnitTest/Makefile.inc diff --git a/Swiften/StringCodecs/SHA1.cpp b/Swiften/StringCodecs/SHA1.cpp new file mode 100644 index 0000000..367f3c9 --- /dev/null +++ b/Swiften/StringCodecs/SHA1.cpp @@ -0,0 +1,196 @@ +#include "Swiften/Base/Platform.h" + +#pragma GCC diagnostic ignored "-Wold-style-cast" + +/* +SHA-1 in C +By Steve Reid <steve@edmweb.com> +100% Public Domain + +Test Vectors (from FIPS PUB 180-1) +"abc" + A9993E36 4706816A BA3E2571 7850C26C 9CD0D89D +"abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq" + 84983E44 1C3BD26E BAAE4AA1 F95129E5 E54670F1 +A million repetitions of "a" + 34AA973C D4C4DAA4 F61EEB2B DBAD2731 6534016F +*/ + +/* #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. */ +/* I got the idea of expanding during the round function from SSLeay */ +#ifdef SWIFTEN_LITTLE_ENDIAN +#define blk0(i) (block->l[i] = (rol(block->l[i],24)&0xFF00FF00) \ + |(rol(block->l[i],8)&0x00FF00FF)) +#else +#define blk0(i) block->l[i] +#endif +#define blk(i) (block->l[i&15] = rol(block->l[(i+13)&15]^block->l[(i+8)&15] \ + ^block->l[(i+2)&15]^block->l[i&15],1)) + +/* (R0+R1), R2, R3, R4 are the different operations used in SHA1 */ +#define R0(v,w,x,y,z,i) z+=((w&(x^y))^y)+blk0(i)+0x5A827999+rol(v,5);w=rol(w,30); +#define R1(v,w,x,y,z,i) z+=((w&(x^y))^y)+blk(i)+0x5A827999+rol(v,5);w=rol(w,30); +#define R2(v,w,x,y,z,i) z+=(w^x^y)+blk(i)+0x6ED9EBA1+rol(v,5);w=rol(w,30); +#define R3(v,w,x,y,z,i) z+=(((w|x)&y)|(w&x))+blk(i)+0x8F1BBCDC+rol(v,5);w=rol(w,30); +#define R4(v,w,x,y,z,i) z+=(w^x^y)+blk(i)+0xCA62C1D6+rol(v,5);w=rol(w,30); + + +/* 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]) +{ +boost::uint32_t a, b, c, d, e; +typedef union { + boost::uint8_t c[64]; + boost::uint32_t l[16]; +} CHAR64LONG16; +CHAR64LONG16* block; +#ifdef SHA1HANDSOFF +static boost::uint8_t workspace[64]; + block = (CHAR64LONG16*)workspace; + memcpy(block, buffer, 64); +#else + block = reinterpret_cast<CHAR64LONG16*>(buffer); +#endif + /* Copy context->state[] to working vars */ + a = state[0]; + b = state[1]; + c = state[2]; + d = state[3]; + e = state[4]; + /* 4 rounds of 20 operations each. Loop unrolled. */ + R0(a,b,c,d,e, 0); R0(e,a,b,c,d, 1); R0(d,e,a,b,c, 2); R0(c,d,e,a,b, 3); + R0(b,c,d,e,a, 4); R0(a,b,c,d,e, 5); R0(e,a,b,c,d, 6); R0(d,e,a,b,c, 7); + R0(c,d,e,a,b, 8); R0(b,c,d,e,a, 9); R0(a,b,c,d,e,10); R0(e,a,b,c,d,11); + R0(d,e,a,b,c,12); R0(c,d,e,a,b,13); R0(b,c,d,e,a,14); R0(a,b,c,d,e,15); + R1(e,a,b,c,d,16); R1(d,e,a,b,c,17); R1(c,d,e,a,b,18); R1(b,c,d,e,a,19); + R2(a,b,c,d,e,20); R2(e,a,b,c,d,21); R2(d,e,a,b,c,22); R2(c,d,e,a,b,23); + R2(b,c,d,e,a,24); R2(a,b,c,d,e,25); R2(e,a,b,c,d,26); R2(d,e,a,b,c,27); + R2(c,d,e,a,b,28); R2(b,c,d,e,a,29); R2(a,b,c,d,e,30); R2(e,a,b,c,d,31); + R2(d,e,a,b,c,32); R2(c,d,e,a,b,33); R2(b,c,d,e,a,34); R2(a,b,c,d,e,35); + R2(e,a,b,c,d,36); R2(d,e,a,b,c,37); R2(c,d,e,a,b,38); R2(b,c,d,e,a,39); + R3(a,b,c,d,e,40); R3(e,a,b,c,d,41); R3(d,e,a,b,c,42); R3(c,d,e,a,b,43); + R3(b,c,d,e,a,44); R3(a,b,c,d,e,45); R3(e,a,b,c,d,46); R3(d,e,a,b,c,47); + R3(c,d,e,a,b,48); R3(b,c,d,e,a,49); R3(a,b,c,d,e,50); R3(e,a,b,c,d,51); + R3(d,e,a,b,c,52); R3(c,d,e,a,b,53); R3(b,c,d,e,a,54); R3(a,b,c,d,e,55); + R3(e,a,b,c,d,56); R3(d,e,a,b,c,57); R3(c,d,e,a,b,58); R3(b,c,d,e,a,59); + R4(a,b,c,d,e,60); R4(e,a,b,c,d,61); R4(d,e,a,b,c,62); R4(c,d,e,a,b,63); + R4(b,c,d,e,a,64); R4(a,b,c,d,e,65); R4(e,a,b,c,d,66); R4(d,e,a,b,c,67); + R4(c,d,e,a,b,68); R4(b,c,d,e,a,69); R4(a,b,c,d,e,70); R4(e,a,b,c,d,71); + R4(d,e,a,b,c,72); R4(c,d,e,a,b,73); R4(b,c,d,e,a,74); R4(a,b,c,d,e,75); + R4(e,a,b,c,d,76); R4(d,e,a,b,c,77); R4(c,d,e,a,b,78); R4(b,c,d,e,a,79); + /* Add the working vars back into context.state[] */ + state[0] += a; + state[1] += b; + state[2] += c; + state[3] += d; + state[4] += e; + /* Wipe variables */ + a = b = c = d = e = 0; +} + + +/* SHA1Init - Initialize new context */ + +void SHA1Init(SHA1_CTX* context) +{ + /* SHA1 initialization constants */ + context->state[0] = 0x67452301; + context->state[1] = 0xEFCDAB89; + context->state[2] = 0x98BADCFE; + context->state[3] = 0x10325476; + context->state[4] = 0xC3D2E1F0; + context->count[0] = context->count[1] = 0; +} + + +/* Run your data through this. */ + +void SHA1Update(SHA1_CTX* context, boost::uint8_t* data, unsigned int len) +{ +unsigned int i, j; + + j = (context->count[0] >> 3) & 63; + if ((context->count[0] += len << 3) < (len << 3)) context->count[1]++; + context->count[1] += (len >> 29); + if ((j + len) > 63) { + memcpy(&context->buffer[j], data, (i = 64-j)); + SHA1Transform(context->state, context->buffer); + for ( ; i + 63 < len; i += 64) { + SHA1Transform(context->state, &data[i]); + } + j = 0; + } + else i = 0; + memcpy(&context->buffer[j], &data[i], len - i); +} + + +/* Add padding and return the message digest. */ + +void SHA1Final(boost::uint8_t digest[20], SHA1_CTX* context) +{ +boost::uint32_t i, j; +boost::uint8_t finalcount[8]; + + for (i = 0; i < 8; i++) { + 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); + while ((context->count[0] & 504) != 448) { + SHA1Update(context, (boost::uint8_t *)("\0"), 1); + } + SHA1Update(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); + } + /* Wipe variables */ + i = j = 0; + memset(context->buffer, 0, 64); + memset(context->state, 0, 20); + memset(context->count, 0, 8); + memset(&finalcount, 0, 8); +#ifdef SHA1HANDSOFF /* make SHA1Transform overwrite it's own static vars */ + SHA1Transform(context->state, context->buffer); +#endif +} + +// ----------------------------------------------------------------------------- + +#include "Swiften/StringCodecs/SHA1.h" + +namespace Swift { + +ByteArray SHA1::getBinaryHash(const ByteArray& input) { + ByteArray digest; + digest.resize(20); + SHA1_CTX context; + SHA1Init(&context); + SHA1Update(&context, (boost::uint8_t*) input.getData(), input.getSize()); + SHA1Final((boost::uint8_t*) digest.getData(), &context); + return digest; +} + +} diff --git a/Swiften/StringCodecs/SHA1.h b/Swiften/StringCodecs/SHA1.h new file mode 100644 index 0000000..7d432ac --- /dev/null +++ b/Swiften/StringCodecs/SHA1.h @@ -0,0 +1,13 @@ +#ifndef SWIFTEN_SHA1_H +#define SWIFTEN_SHA1_H + +#include "Swiften/Base/ByteArray.h" + +namespace Swift { + class SHA1 { + public: + static ByteArray getBinaryHash(const ByteArray& data); + }; +} + +#endif diff --git a/Swiften/StringCodecs/UnitTest/Base64Test.cpp b/Swiften/StringCodecs/UnitTest/Base64Test.cpp new file mode 100644 index 0000000..22f3020 --- /dev/null +++ b/Swiften/StringCodecs/UnitTest/Base64Test.cpp @@ -0,0 +1,35 @@ +#include <cppunit/extensions/HelperMacros.h> +#include <cppunit/extensions/TestFactoryRegistry.h> + +#include "Swiften/StringCodecs/Base64.h" + +using namespace Swift; + +class Base64Test : public CppUnit::TestFixture +{ + CPPUNIT_TEST_SUITE(Base64Test); + CPPUNIT_TEST(testEncode); + CPPUNIT_TEST(testEncode_NonAscii); + CPPUNIT_TEST(testDecode); + CPPUNIT_TEST_SUITE_END(); + + public: + Base64Test() {} + + void testEncode() { + String result(Base64::encode("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz1234567890")); + CPPUNIT_ASSERT_EQUAL(String("QUJDREVGR0hJSktMTU5PUFFSU1RVVldYWVphYmNkZWZnaGlqa2xtbm9wcXJzdHV2d3h5ejEyMzQ1Njc4OTA="), result); + } + + void testEncode_NonAscii() { + String result(Base64::encode(ByteArray("\x42\x06\xb2\x3c\xa6\xb0\xa6\x43\xd2\x0d\x89\xb0\x4f\xf5\x8c\xf7\x8b\x80\x96\xed"))); + CPPUNIT_ASSERT_EQUAL(String("QgayPKawpkPSDYmwT/WM94uAlu0="), result); + } + + void testDecode() { + ByteArray result(Base64::decode("QUJDREVGR0hJSktMTU5PUFFSU1RVVldYWVphYmNkZWZnaGlqa2xtbm9wcXJzdHV2d3h5ejEyMzQ1Njc4OTA=")); + CPPUNIT_ASSERT_EQUAL(ByteArray("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz1234567890"), result); + } +}; + +CPPUNIT_TEST_SUITE_REGISTRATION(Base64Test); diff --git a/Swiften/StringCodecs/UnitTest/Makefile.inc b/Swiften/StringCodecs/UnitTest/Makefile.inc new file mode 100644 index 0000000..ce9fd60 --- /dev/null +++ b/Swiften/StringCodecs/UnitTest/Makefile.inc @@ -0,0 +1,3 @@ +UNITTEST_SOURCES += \ + Swiften/StringCodecs/UnitTest/Base64Test.cpp \ + Swiften/StringCodecs/UnitTest/SHA1Test.cpp diff --git a/Swiften/StringCodecs/UnitTest/SHA1Test.cpp b/Swiften/StringCodecs/UnitTest/SHA1Test.cpp new file mode 100644 index 0000000..16e96ad --- /dev/null +++ b/Swiften/StringCodecs/UnitTest/SHA1Test.cpp @@ -0,0 +1,23 @@ +#include <cppunit/extensions/HelperMacros.h> +#include <cppunit/extensions/TestFactoryRegistry.h> + +#include "Swiften/StringCodecs/SHA1.h" + +using namespace Swift; + +class SHA1Test : public CppUnit::TestFixture +{ + CPPUNIT_TEST_SUITE(SHA1Test); + CPPUNIT_TEST(testEncode); + CPPUNIT_TEST_SUITE_END(); + + public: + SHA1Test() {} + + void testEncode() { + ByteArray result(SHA1::getBinaryHash("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); + } +}; + +CPPUNIT_TEST_SUITE_REGISTRATION(SHA1Test); |