summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
Diffstat (limited to 'Swiften/StringCodecs')
-rw-r--r--Swiften/StringCodecs/Base64.cpp109
-rw-r--r--Swiften/StringCodecs/Base64.h18
-rw-r--r--Swiften/StringCodecs/Makefile.inc5
-rw-r--r--Swiften/StringCodecs/SHA1.cpp196
-rw-r--r--Swiften/StringCodecs/SHA1.h13
-rw-r--r--Swiften/StringCodecs/UnitTest/Base64Test.cpp35
-rw-r--r--Swiften/StringCodecs/UnitTest/Makefile.inc3
-rw-r--r--Swiften/StringCodecs/UnitTest/SHA1Test.cpp23
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);