summaryrefslogtreecommitdiff
path: root/protocols/WhatsApp/src/WhatsAPI++
diff options
context:
space:
mode:
authorGeorge Hazan <george.hazan@gmail.com>2015-01-24 16:35:14 +0000
committerGeorge Hazan <george.hazan@gmail.com>2015-01-24 16:35:14 +0000
commitc47ca004ba979d23a86211393c9e35deadd66c46 (patch)
treece49a57e87bf5caac81d2d54a590e3aea3d61ea3 /protocols/WhatsApp/src/WhatsAPI++
parent126f606ea6a845d914e3ff074dc725443bb57bf0 (diff)
adaptation of WhatsApp for protocol version 1.5/2.0
git-svn-id: http://svn.miranda-ng.org/main/trunk@11898 1316c22d-e87f-b044-9b9b-93d7a3e3ba9c
Diffstat (limited to 'protocols/WhatsApp/src/WhatsAPI++')
-rw-r--r--protocols/WhatsApp/src/WhatsAPI++/BinTreeNodeReader.cpp289
-rw-r--r--protocols/WhatsApp/src/WhatsAPI++/BinTreeNodeReader.h1
-rw-r--r--protocols/WhatsApp/src/WhatsAPI++/BinTreeNodeWriter.cpp111
-rw-r--r--protocols/WhatsApp/src/WhatsAPI++/ISocketConnection.h7
-rw-r--r--protocols/WhatsApp/src/WhatsAPI++/WAConnection.cpp263
-rw-r--r--protocols/WhatsApp/src/WhatsAPI++/WAConnection.h3
-rw-r--r--protocols/WhatsApp/src/WhatsAPI++/WALogin.cpp180
-rw-r--r--protocols/WhatsApp/src/WhatsAPI++/WALogin.h11
-rw-r--r--protocols/WhatsApp/src/WhatsAPI++/WARegister.cpp37
9 files changed, 340 insertions, 562 deletions
diff --git a/protocols/WhatsApp/src/WhatsAPI++/BinTreeNodeReader.cpp b/protocols/WhatsApp/src/WhatsAPI++/BinTreeNodeReader.cpp
index 388bf10e4a..573afb4680 100644
--- a/protocols/WhatsApp/src/WhatsAPI++/BinTreeNodeReader.cpp
+++ b/protocols/WhatsApp/src/WhatsAPI++/BinTreeNodeReader.cpp
@@ -11,7 +11,32 @@
#include "ProtocolTreeNode.h"
#include "utilities.h"
-BinTreeNodeReader::BinTreeNodeReader(WAConnection* conn, ISocketConnection* connection, const char** dictionary, const int dictionarysize) {
+static const char *secondary_dict[] = {
+ "mpeg4", "wmv", "audio/3gpp", "audio/aac", "audio/amr", "audio/mp4", "audio/mpeg", "audio/ogg", "audio/qcelp", "audio/wav",
+ "audio/webm", "audio/x-caf", "audio/x-ms-wma", "image/gif", "image/jpeg", "image/png", "video/3gpp", "video/avi", "video/mp4",
+ "video/mpeg", "video/quicktime", "video/x-flv", "video/x-ms-asf", "302", "400", "401", "402", "403", "404", "405", "406", "407",
+ "409", "410", "500", "501", "503", "504", "abitrate", "acodec", "app_uptime", "asampfmt", "asampfreq", "audio", "clear", "conflict",
+ "conn_no_nna", "cost", "currency", "duration", "extend", "file", "fps", "g_notify", "g_sound", "gcm", "gone", "google_play", "hash",
+ "height", "invalid", "jid-malformed", "latitude", "lc", "lg", "live", "location", "log", "longitude", "max_groups", "max_participants",
+ "max_subject", "mimetype", "mode", "napi_version", "normalize", "orighash", "origin", "passive", "password", "played",
+ "policy-violation", "pop_mean_time", "pop_plus_minus", "price", "pricing", "redeem", "Replaced by new connection", "resume",
+ "signature", "size", "sound", "source", "system-shutdown", "username", "vbitrate", "vcard", "vcodec", "video", "width",
+ "xml-not-well-formed", "checkmarks", "image_max_edge", "image_max_kbytes", "image_quality", "ka", "ka_grow", "ka_shrink", "newmedia",
+ "library", "caption", "forward", "c0", "c1", "c2", "c3", "clock_skew", "cts", "k0", "k1", "login_rtt", "m_id", "nna_msg_rtt",
+ "nna_no_off_count", "nna_offline_ratio", "nna_push_rtt", "no_nna_con_count", "off_msg_rtt", "on_msg_rtt", "stat_name", "sts",
+ "suspect_conn", "lists", "self", "qr", "web", "w:b", "recipient", "w:stats", "forbidden", "aurora.m4r", "bamboo.m4r", "chord.m4r",
+ "circles.m4r", "complete.m4r", "hello.m4r", "input.m4r", "keys.m4r", "note.m4r", "popcorn.m4r", "pulse.m4r", "synth.m4r", "filehash",
+ "max_list_recipients", "en-AU", "en-GB", "es-MX", "pt-PT", "zh-Hans", "zh-Hant", "relayelection", "relaylatency", "interruption",
+ "Apex.m4r", "Beacon.m4r", "Bulletin.m4r", "By The Seaside.m4r", "Chimes.m4r", "Circuit.m4r", "Constellation.m4r", "Cosmic.m4r",
+ "Crystals.m4r", "Hillside.m4r", "Illuminate.m4r", "Night Owl.m4r", "Opening.m4r", "Playtime.m4r", "Presto.m4r", "Radar.m4r",
+ "Radiate.m4r", "Ripples.m4r", "Sencha.m4r", "Signal.m4r", "Silk.m4r", "Slow Rise.m4r", "Stargaze.m4r", "Summit.m4r", "Twinkle.m4r",
+ "Uplift.m4r", "Waves.m4r", "voip", "eligible", "upgrade", "planned", "current", "future", "disable", "expire", "start", "stop",
+ "accuracy", "speed", "bearing", "recording", "encrypt", "key", "identity", "w:gp2", "admin", "locked", "unlocked", "new", "battery",
+ "archive", "adm", "plaintext_size", "compressed_size", "delivered", "msg", "pkmsg", "everyone", "v", "transport", "call-id"
+};
+
+BinTreeNodeReader::BinTreeNodeReader(WAConnection* conn, ISocketConnection* connection, const char** dictionary, const int dictionarysize)
+{
this->conn = conn;
this->rawIn = connection;
this->tokenMap = dictionary;
@@ -21,14 +46,16 @@ BinTreeNodeReader::BinTreeNodeReader(WAConnection* conn, ISocketConnection* conn
this->buf = new std::vector<unsigned char>(BUFFER_SIZE);
}
-BinTreeNodeReader::~BinTreeNodeReader() {
+BinTreeNodeReader::~BinTreeNodeReader()
+{
if (this->buf != NULL)
delete this->buf;
if (this->in != NULL)
delete this->in;
}
-ProtocolTreeNode* BinTreeNodeReader::nextTreeInternal() {
+ProtocolTreeNode* BinTreeNodeReader::nextTreeInternal()
+{
int b = this->in->read();
int size = readListSize(b);
b = this->in->read();
@@ -40,7 +67,7 @@ ProtocolTreeNode* BinTreeNodeReader::nextTreeInternal() {
if ((size == 0) || (tag == NULL))
throw WAException("nextTree sees 0 list or null tag", WAException::CORRUPT_STREAM_EX, -1);
int attribCount = (size - 2 + size % 2) / 2;
- std::map<string,string>* attribs = readAttributes(attribCount);
+ std::map<string, string>* attribs = readAttributes(attribCount);
if (size % 2 == 1) {
ProtocolTreeNode* ret = new ProtocolTreeNode(*tag, attribs);
delete tag;
@@ -59,7 +86,8 @@ ProtocolTreeNode* BinTreeNodeReader::nextTreeInternal() {
std::string* s = (std::string*) obj->data;
data = new std::vector<unsigned char>(s->begin(), s->end());
delete s;
- } else {
+ }
+ else {
data = (std::vector<unsigned char>*) obj->data;
}
@@ -69,25 +97,31 @@ ProtocolTreeNode* BinTreeNodeReader::nextTreeInternal() {
return ret;
}
-bool BinTreeNodeReader::isListTag(int b) {
+bool BinTreeNodeReader::isListTag(int b)
+{
return (b == 248) || (b == 0) || (b == 249);
}
-void BinTreeNodeReader::decodeStream(int flags, int offset, int length) {
+void BinTreeNodeReader::decodeStream(int flags, int offset, int length)
+{
if ((flags & 8) != 0) {
- if (length < 4) {
- throw WAException("invalid length" + length, WAException::CORRUPT_STREAM_EX, 0);
- }
- offset += 4;
+ if (length < 4)
+ throw WAException("invalid length" + length, WAException::CORRUPT_STREAM_EX, 0);
+
length -= 4;
- this->conn->inputKey->decodeMessage(&(*this->buf)[0], offset - 4, offset, length);
+
+ unsigned char *pData = (unsigned char*)&(*this->buf)[0];
+ this->conn->inputKey->decodeMessage(pData, offset + length, 0, length);
+ this->rawIn->dump(pData + offset, length);
}
+
if (this->in != NULL)
delete this->in;
this->in = new ByteArrayInputStream(this->buf, offset, length);
}
-std::map<string, string>* BinTreeNodeReader::readAttributes(int attribCount) {
+std::map<string, string>* BinTreeNodeReader::readAttributes(int attribCount)
+{
std::map<string, string>* attribs = new std::map<string, string>();
for (int i = 0; i < attribCount; i++) {
std::string* key = readStringAsString();
@@ -99,91 +133,106 @@ std::map<string, string>* BinTreeNodeReader::readAttributes(int attribCount) {
return attribs;
}
-std::vector<ProtocolTreeNode*>* BinTreeNodeReader::readList(int token) {
+std::vector<ProtocolTreeNode*>* BinTreeNodeReader::readList(int token)
+{
int size = readListSize(token);
std::vector<ProtocolTreeNode*>* list = new std::vector<ProtocolTreeNode*>(size);
- for (int i = 0; i < size; i++) {
+ for (int i = 0; i < size; i++)
(*list)[i] = nextTreeInternal();
- }
return list;
}
-int BinTreeNodeReader::readListSize(int token) {
- int size;
- if (token == 0) {
- size = 0;
+int BinTreeNodeReader::readListSize(int token)
+{
+ switch (token) {
+ case 0: return 0;
+ case 248: return readInt8(this->in);
+ case 249: return readInt16(this->in);
+ default:
+ throw new WAException("invalid list size in readListSize: token " + token, WAException::CORRUPT_STREAM_EX, 0);
}
- else {
- size = 0;
- if (token == 248) {
- size = readInt8(this->in);
- }
- else
- {
- size = 0;
- if (token == 249)
- size = readInt16(this->in);
- else
- throw new WAException("invalid list size in readListSize: token " + token, WAException::CORRUPT_STREAM_EX, 0);
- }
- }
-
- return size;
+ return 0;
}
-std::vector<ProtocolTreeNode*>* BinTreeNodeReader::readList() {
+std::vector<ProtocolTreeNode*>* BinTreeNodeReader::readList()
+{
return readList(this->in->read());
}
-ReadData* BinTreeNodeReader::readString() {
+ReadData* BinTreeNodeReader::readString()
+{
return readString(this->in->read());
}
-ReadData* BinTreeNodeReader::readString(int token) {
- if (token == -1) {
+ReadData* BinTreeNodeReader::readString(int token)
+{
+ if (token == -1)
throw WAException("-1 token in readString", WAException::CORRUPT_STREAM_EX, -1);
- }
+ int bSize;
ReadData* ret = new ReadData();
- if ((token > 4) && (token < 245)) {
+ if (token > 2 && token <= this->tokenmapsize) {
+ if (token != this->tokenmapsize)
+ ret->data = new std::string(this->tokenMap[token]);
+ else {
+ token = readInt8(this->in);
+ if (token >= 0 && token < _countof(secondary_dict))
+ ret->data = new std::string(secondary_dict[token]);
+ else
+ throw WAException("invalid token/length in getToken", WAException::CORRUPT_STREAM_EX, 0);
+ }
+
ret->type = STRING;
- ret->data = new std::string(getToken(token));
return ret;
}
- switch(token) {
+ switch (token) {
case 0:
return NULL;
- case 252: {
- int size8 = readInt8(this->in);
- std::vector<unsigned char>* buf8 = new std::vector<unsigned char>(size8);
- fillArray(*buf8, size8, this->in);
- // std::string* ret = new std::string(buf8->begin(), buf8->end());
- // delete buf8;
- ret->type = ARRAY;
- ret->data = buf8;
- return ret;
- }
- case 253: {
- int size24 = readInt24(this->in);
- std::vector<unsigned char>* buf24 = new std::vector<unsigned char>(size24);
- fillArray(*buf24, size24, this->in);
- // std::string* ret = new std::string(buf24->begin(), buf24->end());
- // delete buf24;
- ret->type = ARRAY;
- ret->data = buf24;
+ case 252:
+ bSize = readInt8(this->in);
+ {
+ std::vector<unsigned char>* buf8 = new std::vector<unsigned char>(bSize);
+ fillArray(*buf8, bSize, this->in);
+ ret->type = ARRAY;
+ ret->data = buf8;
+ }
return ret;
- }
- case 254: {
- token = (unsigned char) this->in->read();
- ret->type = STRING;
- ret->data = new std::string(getToken(245 + token));
+
+ case 253:
+ bSize = readInt24(this->in);
+ {
+ std::vector<unsigned char>* buf24 = new std::vector<unsigned char>(bSize);
+ fillArray(*buf24, bSize, this->in);
+ ret->type = ARRAY;
+ ret->data = buf24;
+ }
return ret;
- }
- case 250: {
+
+ case 255:
+ bSize = readInt8(this->in);
+ {
+ int size = bSize & 0x7f;
+ int numnibbles = size * 2 - ((bSize & 0x80) ? 1 : 0);
+
+ std::vector<unsigned char> tmp(size);
+ fillArray(tmp, size, this->in);
+ std::string s;
+ for (int i = 0; i < numnibbles; i++) {
+ char c = (tmp[i / 2] >> (4 - ((i & 1) << 2))) & 0xF;
+ if (c < 10) s += (c + '0');
+ else s += (c - 10 + '-');
+ }
+
+ ret->type = STRING;
+ ret->data = new std::string(s);
+ }
+ return ret;
+
+ case 250:
std::string* user = readStringAsString();
std::string* server = readStringAsString();
if ((user != NULL) && (server != NULL)) {
@@ -201,14 +250,13 @@ ReadData* BinTreeNodeReader::readString(int token) {
}
throw WAException("readString couldn't reconstruct jid", WAException::CORRUPT_STREAM_EX, -1);
}
- }
- throw WAException("readString couldn't match token" + (int) token, WAException::CORRUPT_STREAM_EX, -1);
+ throw WAException("readString couldn't match token" + (int)token, WAException::CORRUPT_STREAM_EX, -1);
}
-std::string* BinTreeNodeReader::objectAsString(ReadData* o) {
- if (o->type == STRING) {
+std::string* BinTreeNodeReader::objectAsString(ReadData* o)
+{
+ if (o->type == STRING)
return (std::string*) o->data;
- }
if (o->type == ARRAY) {
std::vector<unsigned char>* v = (std::vector<unsigned char>*) o->data;
@@ -220,61 +268,44 @@ std::string* BinTreeNodeReader::objectAsString(ReadData* o) {
return NULL;
}
-std::string* BinTreeNodeReader::readStringAsString() {
+std::string* BinTreeNodeReader::readStringAsString()
+{
ReadData* o = this->readString();
std::string* ret = this->objectAsString(o);
delete o;
return ret;
}
-std::string* BinTreeNodeReader::readStringAsString(int token) {
+std::string* BinTreeNodeReader::readStringAsString(int token)
+{
ReadData* o = this->readString(token);
std::string* ret = this->objectAsString(o);
delete o;
return ret;
}
-
-void BinTreeNodeReader::fillArray(std::vector<unsigned char>& buff, int len, ByteArrayInputStream* in) {
+void BinTreeNodeReader::fillArray(std::vector<unsigned char>& buff, int len, ByteArrayInputStream* in)
+{
int count = 0;
- while (count < len) {
+ while (count < len)
count += in->read(buff, count, len - count);
- }
}
-void BinTreeNodeReader::fillArray(std::vector<unsigned char>& buff, int len, ISocketConnection* in) {
+void BinTreeNodeReader::fillArray(std::vector<unsigned char>& buff, int len, ISocketConnection* in)
+{
int count = 0;
- while (count < len) {
+ while (count < len)
count += in->read(buff, count, len - count);
- }
}
+void BinTreeNodeReader::getTopLevelStream()
+{
+ int stanzaSize = readInt24(this->rawIn);
+ int flags = (stanzaSize >> 20);
+ stanzaSize &= 0x0FFFFF;
-std::string BinTreeNodeReader::getToken(int token) {
- std::string ret;
-
- if ((token >= 0) && (token < this->tokenmapsize))
- ret = std::string(this->tokenMap[token]);
- if (ret.empty()) {
- throw WAException("invalid token/length in getToken", WAException::CORRUPT_STREAM_EX, 0);
- }
- return ret;
-}
-
-
-void BinTreeNodeReader::getTopLevelStream() {
- int stanzaSize;
- int flags;
- int byte = readInt8(this->rawIn);
- flags = byte >> 4;
- int size0 = byte & 15;
- int size1 = readInt8(this->rawIn);
- int size2 = readInt8(this->rawIn);
-
- stanzaSize = (size0 << 16) + (size1 << 8) + size2;
-
- if (this->buf->size() < (size_t) stanzaSize) {
- int newsize = max((int) (this->buf->size() * 3 / 2), stanzaSize);
+ if (this->buf->size() < (size_t)stanzaSize) {
+ int newsize = max((int)(this->buf->size() * 3 / 2), stanzaSize);
delete this->buf;
this->buf = new std::vector<unsigned char>(newsize);
}
@@ -283,18 +314,21 @@ void BinTreeNodeReader::getTopLevelStream() {
this->decodeStream(flags, 0, stanzaSize);
}
-int BinTreeNodeReader::readInt8(ByteArrayInputStream* in) {
+int BinTreeNodeReader::readInt8(ByteArrayInputStream* in)
+{
return in->read();
}
-int BinTreeNodeReader::readInt16(ByteArrayInputStream* in) {
+int BinTreeNodeReader::readInt16(ByteArrayInputStream* in)
+{
int intTop = in->read();
int intBot = in->read();
int value = (intTop << 8) + intBot;
return value;
}
-int BinTreeNodeReader::readInt24(ByteArrayInputStream* in) {
+int BinTreeNodeReader::readInt24(ByteArrayInputStream* in)
+{
int int1 = in->read();
int int2 = in->read();
int int3 = in->read();
@@ -303,12 +337,14 @@ int BinTreeNodeReader::readInt24(ByteArrayInputStream* in) {
return value;
}
-ProtocolTreeNode* BinTreeNodeReader::nextTree() {
+ProtocolTreeNode* BinTreeNodeReader::nextTree()
+{
this->getTopLevelStream();
return nextTreeInternal();
}
-void BinTreeNodeReader::streamStart() {
+void BinTreeNodeReader::streamStart()
+{
this->getTopLevelStream();
int tag = this->in->read();
@@ -319,26 +355,25 @@ void BinTreeNodeReader::streamStart() {
}
int attribCount = (size - 2 + size % 2) / 2;
- std::map<string,string>* attributes = readAttributes(attribCount);
+ std::map<string, string>* attributes = readAttributes(attribCount);
delete attributes;
}
-int BinTreeNodeReader::readInt8(ISocketConnection* in) {
+int BinTreeNodeReader::readInt8(ISocketConnection* in)
+{
return in->read();
}
-int BinTreeNodeReader::readInt16(ISocketConnection* in) {
- int intTop = in->read();
- int intBot = in->read();
- int value = (intTop << 8) + intBot;
- return value;
+int BinTreeNodeReader::readInt16(ISocketConnection* in)
+{
+ unsigned char data[2];
+ in->read(data, 2);
+ return (int(data[0]) << 8) + int(data[1]);
}
-int BinTreeNodeReader::readInt24(ISocketConnection* in) {
- int int1 = in->read();
- int int2 = in->read();
- int int3 = in->read();
- int value = (int1 << 16) + (int2 << 8) + int3;
-
- return value;
+int BinTreeNodeReader::readInt24(ISocketConnection* in)
+{
+ unsigned char data[3];
+ in->read(data, 3);
+ return (int(data[0]) << 16) + (int(data[1]) << 8) + int(data[2]);
}
diff --git a/protocols/WhatsApp/src/WhatsAPI++/BinTreeNodeReader.h b/protocols/WhatsApp/src/WhatsAPI++/BinTreeNodeReader.h
index 61b70b218b..4288c671f3 100644
--- a/protocols/WhatsApp/src/WhatsAPI++/BinTreeNodeReader.h
+++ b/protocols/WhatsApp/src/WhatsAPI++/BinTreeNodeReader.h
@@ -54,7 +54,6 @@ private:
std::string* objectAsString(ReadData* o);
std::string* readStringAsString();
std::string* readStringAsString(int token);
- std::string getToken(int token);
void getTopLevelStream();
static int readInt8(ByteArrayInputStream* in);
static int readInt8(ISocketConnection* in);
diff --git a/protocols/WhatsApp/src/WhatsAPI++/BinTreeNodeWriter.cpp b/protocols/WhatsApp/src/WhatsAPI++/BinTreeNodeWriter.cpp
index 6936de9a8b..b79bdcfd09 100644
--- a/protocols/WhatsApp/src/WhatsAPI++/BinTreeNodeWriter.cpp
+++ b/protocols/WhatsApp/src/WhatsAPI++/BinTreeNodeWriter.cpp
@@ -10,8 +10,9 @@
#include "utilities.h"
BinTreeNodeWriter::BinTreeNodeWriter(WAConnection* conn, ISocketConnection* connection,
- const char** dictionary, const int dictionarysize, IMutex* mutex) {
- this->mutex = mutex;
+ const char** dictionary, const int dictionarysize, IMutex* mutex)
+{
+ this->mutex = mutex;
this->conn = conn;
this->out = new ByteArrayOutputStream(2048);
this->realOut = connection;
@@ -37,22 +38,19 @@ void BinTreeNodeWriter::processBuffer()
{
bool flag = this->conn->outputKey != NULL;
unsigned int num = 0u;
- if (flag)
- {
+ if (flag) {
long num2 = (long)this->out->getLength() + 4L;
this->out->setLength(num2);
this->out->setPosition(num2);
num |= 1u;
}
long num3 = (long)this->out->getLength() - 3L - (long) this->dataBegin;
- if (num3 >= 1048576L)
- {
+ if (num3 >= 1048576L) {
throw WAException("Buffer too large: " + num3, WAException::CORRUPT_STREAM_EX, 0);
}
std::vector<unsigned char>* buffer = this->out->getBuffer();
- if (flag)
- {
+ if (flag) {
int num4 = (int)num3 - 4;
this->conn->outputKey->encodeMessage(buffer->data(), this->dataBegin + 3 + num4, this->dataBegin + 3, num4);
}
@@ -61,15 +59,16 @@ void BinTreeNodeWriter::processBuffer()
(*buffer)[this->dataBegin + 2] = (unsigned char)(num3 & 255L);
}
-void BinTreeNodeWriter::streamStart(std::string domain, std::string resource) {
+void BinTreeNodeWriter::streamStart(std::string domain, std::string resource)
+{
this->mutex->lock();
try {
this->out->setPosition(0);
this->out->setLength(0);
- this->out->write(87);
- this->out->write(65);
+ this->out->write('W');
+ this->out->write('A');
this->out->write(1);
- this->out->write(2);
+ this->out->write(5);
std::map<string, string> attributes;
attributes["to"] = domain;
@@ -80,44 +79,53 @@ void BinTreeNodeWriter::streamStart(std::string domain, std::string resource) {
this->writeAttributes(&attributes);
this->processBuffer();
this->flushBuffer(true, 0);
- } catch (exception& ex) {
+ }
+ catch (exception& ex) {
this->mutex->unlock();
throw ex;
}
this->mutex->unlock();
}
-void BinTreeNodeWriter::writeListStart(int i) {
+void BinTreeNodeWriter::writeListStart(int i)
+{
if (i == 0) {
this->out->write(0);
- } else if (i < 256) {
+ }
+ else if (i < 256) {
this->out->write(248);
writeInt8(i);
- } else {
+ }
+ else {
this->out->write(249);
writeInt16(i);
}
}
-void BinTreeNodeWriter::writeInt8(int v) {
+void BinTreeNodeWriter::writeInt8(int v)
+{
this->out->write(v & 0xFF);
}
-void BinTreeNodeWriter::writeInt16(int v, ISocketConnection* o) {
+void BinTreeNodeWriter::writeInt16(int v, ISocketConnection* o)
+{
o->write((v & 0xFF00) >> 8);
o->write((v & 0xFF) >> 0);
}
-void BinTreeNodeWriter::writeInt16(int v) {
+void BinTreeNodeWriter::writeInt16(int v)
+{
writeInt16(v, this->out);
}
-void BinTreeNodeWriter::writeInt16(int v, ByteArrayOutputStream* o) {
+void BinTreeNodeWriter::writeInt16(int v, ByteArrayOutputStream* o)
+{
o->write((v & 0xFF00) >> 8);
o->write((v & 0xFF) >> 0);
}
-void BinTreeNodeWriter::writeAttributes(std::map<string, string>* attributes) {
+void BinTreeNodeWriter::writeAttributes(std::map<string, string>* attributes)
+{
if (attributes != NULL) {
std::map<string, string>::iterator ii;
for (ii = attributes->begin(); ii != attributes->end(); ii++) {
@@ -127,14 +135,15 @@ void BinTreeNodeWriter::writeAttributes(std::map<string, string>* attributes) {
}
}
-void BinTreeNodeWriter::writeString(const std::string& tag) {
+void BinTreeNodeWriter::writeString(const std::string& tag)
+{
std::map<string, int>::iterator it = this->tokenMap.find(tag);
if (it != this->tokenMap.end())
writeToken(it->second);
else {
size_t atIndex = tag.find('@');
if (atIndex == 0 || atIndex == string::npos)
- writeBytes((unsigned char*) tag.data(), (int)tag.length());
+ writeBytes((unsigned char*)tag.data(), (int)tag.length());
else {
std::string server = tag.substr(atIndex + 1);
std::string user = tag.substr(0, atIndex);
@@ -143,18 +152,21 @@ void BinTreeNodeWriter::writeString(const std::string& tag) {
}
}
-void BinTreeNodeWriter::writeJid(std::string* user, const std::string& server) {
+void BinTreeNodeWriter::writeJid(std::string* user, const std::string& server)
+{
this->out->write(250);
if (user != NULL && !user->empty()) {
writeString(*user);
- } else {
+ }
+ else {
writeToken(0);
}
writeString(server);
}
-void BinTreeNodeWriter::writeToken(int intValue) {
+void BinTreeNodeWriter::writeToken(int intValue)
+{
if (intValue < 245)
this->out->write(intValue);
else if (intValue <= 500) {
@@ -163,32 +175,36 @@ void BinTreeNodeWriter::writeToken(int intValue) {
}
}
-void BinTreeNodeWriter::writeBytes(unsigned char* bytes, int length) {
+void BinTreeNodeWriter::writeBytes(unsigned char* bytes, int length)
+{
if (length >= 256) {
this->out->write(253);
writeInt24(length);
- } else {
+ }
+ else {
this->out->write(252);
writeInt8(length);
}
this->out->write(bytes, length);
}
-void BinTreeNodeWriter::writeInt24(int v) {
+void BinTreeNodeWriter::writeInt24(int v)
+{
this->out->write((v & 0xFF0000) >> 16);
this->out->write((v & 0xFF00) >> 8);
this->out->write(v & 0xFF);
}
-void BinTreeNodeWriter::writeInternal(ProtocolTreeNode* node) {
+void BinTreeNodeWriter::writeInternal(ProtocolTreeNode* node)
+{
writeListStart(
- 1 + (node->attributes == NULL ? 0 : (int)node->attributes->size() * 2)
- + (node->children == NULL ? 0 : 1)
- + (node->data == NULL ? 0 : 1));
+ 1 + (node->attributes == NULL ? 0 : (int)node->attributes->size() * 2)
+ + (node->children == NULL ? 0 : 1)
+ + (node->data == NULL ? 0 : 1));
writeString(node->tag);
writeAttributes(node->attributes);
if (node->data != NULL) {
- writeBytes((unsigned char*) node->data->data(), (int)node->data->size());
+ writeBytes((unsigned char*)node->data->data(), (int)node->data->size());
}
if (node->children != NULL && !node->children->empty()) {
writeListStart((int)node->children->size());
@@ -203,10 +219,12 @@ void BinTreeNodeWriter::flushBuffer(bool flushNetwork)
this->flushBuffer(flushNetwork, this->dataBegin);
}
-void BinTreeNodeWriter::flushBuffer(bool flushNetwork, int startingOffset) {
+void BinTreeNodeWriter::flushBuffer(bool flushNetwork, int startingOffset)
+{
try {
this->processBuffer();
- } catch (WAException& ex) {
+ }
+ catch (WAException& ex) {
this->out->setPosition(0);
this->out->setLength(0);
throw ex;
@@ -216,8 +234,7 @@ void BinTreeNodeWriter::flushBuffer(bool flushNetwork, int startingOffset) {
std::vector<unsigned char> buffer(this->out->getBuffer()->begin(), this->out->getBuffer()->end());
int num = (int)(this->out->getLength() - (long)startingOffset);
- if (flushNetwork && ((long)this->out->getCapacity() - this->out->getLength() < 3L || this->out->getLength() > 4096L))
- {
+ if (flushNetwork && ((long)this->out->getCapacity() - this->out->getLength() < 3L || this->out->getLength() > 4096L)) {
delete this->out;
this->out = new ByteArrayOutputStream(4096);
}
@@ -226,24 +243,28 @@ void BinTreeNodeWriter::flushBuffer(bool flushNetwork, int startingOffset) {
this->realOut->write(buffer, startingOffset, num);
}
-void BinTreeNodeWriter::streamEnd() {
+void BinTreeNodeWriter::streamEnd()
+{
this->mutex->lock();
try {
writeListStart(1);
this->out->write(2);
flushBuffer(true);
- } catch (exception& ex) {
+ }
+ catch (exception& ex) {
this->mutex->unlock();
throw ex;
}
this->mutex->unlock();
}
-void BinTreeNodeWriter::write(ProtocolTreeNode* node) {
+void BinTreeNodeWriter::write(ProtocolTreeNode* node)
+{
write(node, true);
}
-void BinTreeNodeWriter::write(ProtocolTreeNode* node, bool needsFlush) {
+void BinTreeNodeWriter::write(ProtocolTreeNode* node, bool needsFlush)
+{
this->mutex->lock();
try {
this->writeDummyHeader();
@@ -253,14 +274,16 @@ void BinTreeNodeWriter::write(ProtocolTreeNode* node, bool needsFlush) {
writeInternal(node);
}
flushBuffer(needsFlush);
- } catch (exception& ex) {
+ }
+ catch (exception& ex) {
this->mutex->unlock();
throw WAException(ex.what());
}
this->mutex->unlock();
}
-BinTreeNodeWriter::~BinTreeNodeWriter() {
+BinTreeNodeWriter::~BinTreeNodeWriter()
+{
if (this->out != NULL)
delete this->out;
}
diff --git a/protocols/WhatsApp/src/WhatsAPI++/ISocketConnection.h b/protocols/WhatsApp/src/WhatsAPI++/ISocketConnection.h
index a2d82efc64..b9fa3d5faa 100644
--- a/protocols/WhatsApp/src/WhatsAPI++/ISocketConnection.h
+++ b/protocols/WhatsApp/src/WhatsAPI++/ISocketConnection.h
@@ -7,19 +7,20 @@ class ISocketConnection {
public:
ISocketConnection() {}
+ virtual ~ISocketConnection() {}
+
virtual void write(int i) = 0;
virtual unsigned char read() = 0;
virtual void flush() = 0;
virtual void write(const std::vector<unsigned char>& b, int length) = 0;
virtual void write(const std::vector<unsigned char>& bytes, int offset, int length) = 0;
+ virtual int read(unsigned char*, int length) = 0;
virtual int read(std::vector<unsigned char>& b, int off, int length) = 0;
virtual void makeNonBlock() = 0;
virtual int waitForRead() = 0;
virtual void forceShutdown() = 0;
- virtual ~ISocketConnection() {}
- //static void initNetwork();
- //static void quitNetwork();
+ virtual void dump(const void *buf, int length) = 0;
};
#endif /* ISOCKETCONNECTION_H_ */
diff --git a/protocols/WhatsApp/src/WhatsAPI++/WAConnection.cpp b/protocols/WhatsApp/src/WhatsAPI++/WAConnection.cpp
index 8fb24b443b..352d49b07d 100644
--- a/protocols/WhatsApp/src/WhatsAPI++/WAConnection.cpp
+++ b/protocols/WhatsApp/src/WhatsAPI++/WAConnection.cpp
@@ -12,245 +12,31 @@
#include "utilities.h"
const char* WAConnection::dictionary[] = {
- "",
- "",
- "",
- "",
- "",
- "account",
- "ack",
- "action",
- "active",
- "add",
- "after",
- "ib",
- "all",
- "allow",
- "apple",
- "audio",
- "auth",
- "author",
- "available",
- "bad-protocol",
- "bad-request",
- "before",
- "Bell.caf",
- "body",
- "Boing.caf",
- "cancel",
- "category",
- "challenge",
- "chat",
- "clean",
- "code",
- "composing",
- "config",
- "conflict",
- "contacts",
- "count",
- "create",
- "creation",
- "default",
- "delay",
- "delete",
- "delivered",
- "deny",
- "digest",
- "DIGEST-MD5-1",
- "DIGEST-MD5-2",
- "dirty",
- "elapsed",
- "broadcast",
- "enable",
- "encoding",
- "duplicate",
- "error",
- "event",
- "expiration",
- "expired",
- "fail",
- "failure",
- "false",
- "favorites",
- "feature",
- "features",
- "field",
- "first",
- "free",
- "from",
- "g.us",
- "get",
- "Glass.caf",
- "google",
- "group",
- "groups",
- "g_notify",
- "g_sound",
- "Harp.caf",
- "http://etherx.jabber.org/streams",
- "http://jabber.org/protocol/chatstates",
- "id",
- "image",
- "img",
- "inactive",
- "index",
- "internal-server-error",
- "invalid-mechanism",
- "ip",
- "iq",
- "item",
- "item-not-found",
- "user-not-found",
- "jabber:iq:last",
- "jabber:iq:privacy",
- "jabber:x:delay",
- "jabber:x:event",
- "jid",
- "jid-malformed",
- "kind",
- "last",
- "latitude",
- "lc",
- "leave",
- "leave-all",
- "lg",
- "list",
- "location",
- "longitude",
- "max",
- "max_groups",
- "max_participants",
- "max_subject",
- "mechanism",
- "media",
- "message",
- "message_acks",
- "method",
- "microsoft",
- "missing",
- "modify",
- "mute",
- "name",
- "nokia",
- "none",
- "not-acceptable",
- "not-allowed",
- "not-authorized",
- "notification",
- "notify",
- "off",
- "offline",
- "order",
- "owner",
- "owning",
- "paid",
- "participant",
- "participants",
- "participating",
- "password",
- "paused",
- "picture",
- "pin",
- "ping",
- "platform",
- "pop_mean_time",
- "pop_plus_minus",
- "port",
- "presence",
- "preview",
- "probe",
- "proceed",
- "prop",
- "props",
- "p_o",
- "p_t",
- "query",
- "raw",
- "reason",
- "receipt",
- "receipt_acks",
- "received",
- "registration",
- "relay",
- "remote-server-timeout",
- "remove",
- "Replaced by new connection",
- "request",
- "required",
- "resource",
- "resource-constraint",
- "response",
- "result",
- "retry",
- "rim",
- "s.whatsapp.net",
- "s.us",
- "seconds",
- "server",
- "server-error",
- "service-unavailable",
- "set",
- "show",
- "sid",
- "silent",
- "sound",
- "stamp",
- "unsubscribe",
- "stat",
- "status",
- "stream:error",
- "stream:features",
- "subject",
- "subscribe",
- "success",
- "sync",
- "system-shutdown",
- "s_o",
- "s_t",
- "t",
- "text",
- "timeout",
- "TimePassing.caf",
- "timestamp",
- "to",
- "Tri-tone.caf",
- "true",
- "type",
- "unavailable",
- "uri",
- "url",
- "urn:ietf:params:xml:ns:xmpp-sasl",
- "urn:ietf:params:xml:ns:xmpp-stanzas",
- "urn:ietf:params:xml:ns:xmpp-streams",
- "urn:xmpp:delay",
- "urn:xmpp:ping",
- "urn:xmpp:receipts",
- "urn:xmpp:whatsapp",
- "urn:xmpp:whatsapp:account",
- "urn:xmpp:whatsapp:dirty",
- "urn:xmpp:whatsapp:mms",
- "urn:xmpp:whatsapp:push",
- "user",
- "username",
- "value",
- "vcard",
- "version",
- "video",
- "w",
- "w:g",
- "w:p",
- "w:p:r",
- "w:profile:picture",
- "wait",
- "x",
- "xml-not-well-formed",
- "xmlns",
- "xmlns:stream",
- "Xylophone.caf",
- "1",
- "WAUTH-1"
+ "", "", "", "account", "ack", "action", "active", "add", "after", "all", "allow", "apple", "auth", "author", "available",
+ "bad-protocol", "bad-request", "before", "body", "broadcast", "cancel", "category", "challenge", "chat", "clean", "code",
+ "composing", "config", "contacts", "count", "create", "creation", "debug", "default", "delete", "delivery", "delta", "deny",
+ "digest", "dirty", "duplicate", "elapsed", "enable", "encoding", "error", "event", "expiration", "expired", "fail", "failure",
+ "false", "favorites", "feature", "features", "feature-not-implemented", "field", "first", "free", "from", "g.us", "get", "google",
+ "group", "groups", "groups_v2", "http://etherx.jabber.org/streams", "http://jabber.org/protocol/chatstates", "ib", "id", "image",
+ "img", "index", "internal-server-error", "ip", "iq", "item-not-found", "item", "jabber:iq:last", "jabber:iq:privacy", "jabber:x:event",
+ "jid", "kind", "last", "leave", "list", "max", "mechanism", "media", "message_acks", "message", "method", "microsoft", "missing",
+ "modify", "mute", "name", "nokia", "none", "not-acceptable", "not-allowed", "not-authorized", "notification", "notify", "off",
+ "offline", "order", "owner", "owning", "p_o", "p_t", "paid", "participant", "participants", "participating", "paused", "picture",
+ "pin", "ping", "platform", "port", "presence", "preview", "probe", "prop", "props", "query", "raw", "read", "readreceipts", "reason",
+ "receipt", "relay", "remote-server-timeout", "remove", "request", "required", "resource-constraint", "resource", "response", "result",
+ "retry", "rim", "s_o", "s_t", "s.us", "s.whatsapp.net", "seconds", "server-error", "server", "service-unavailable", "set", "show", "silent",
+ "stat", "status", "stream:error", "stream:features", "subject", "subscribe", "success", "sync", "t", "text", "timeout", "timestamp", "to",
+ "true", "type", "unavailable", "unsubscribe", "uri", "url", "urn:ietf:params:xml:ns:xmpp-sasl", "urn:ietf:params:xml:ns:xmpp-stanzas",
+ "urn:ietf:params:xml:ns:xmpp-streams", "urn:xmpp:ping", "urn:xmpp:whatsapp:account", "urn:xmpp:whatsapp:dirty", "urn:xmpp:whatsapp:mms",
+ "urn:xmpp:whatsapp:push", "urn:xmpp:whatsapp", "user", "user-not-found", "value", "version", "w:g", "w:p:r", "w:p", "w:profile:picture",
+ "w", "wait", "WAUTH-2", "xmlns:stream", "xmlns", "1", "chatstate", "crypto", "phash", "enc", "class", "off_cnt", "w:g2", "promote",
+ "demote", "creator", "Bell.caf", "Boing.caf", "Glass.caf", "Harp.caf", "TimePassing.caf", "Tri-tone.caf", "Xylophone.caf", "background",
+ "backoff", "chunked", "context", "full", "in", "interactive", "out", "registration", "sid", "urn:xmpp:whatsapp:sync", "flt", "s16", "u8",
+ "adpcm", "amrnb", "amrwb", "mp3", "pcm", "qcelp", "wma", "h263", "h264", "jpeg"
};
+const int WAConnection::DICTIONARY_LEN = _countof(WAConnection::dictionary);
+
WAConnection::WAConnection(IMutex* mutex, WAListener* event_handler, WAGroupListener* group_event_handler)
{
this->init(event_handler, group_event_handler, mutex);
@@ -263,9 +49,8 @@ WAConnection::~WAConnection()
delete this->in;
delete this->out;
std::map<string, IqResultHandler*>::iterator it;
- for (it = this->pending_server_requests.begin(); it != this->pending_server_requests.end(); it++) {
+ for (it = this->pending_server_requests.begin(); it != this->pending_server_requests.end(); it++)
delete it->second;
- }
}
void WAConnection::init(WAListener* event_handler, WAGroupListener* group_event_handler, IMutex* mutex)
diff --git a/protocols/WhatsApp/src/WhatsAPI++/WAConnection.h b/protocols/WhatsApp/src/WhatsAPI++/WAConnection.h
index 9fbfde8484..92a8b82e4c 100644
--- a/protocols/WhatsApp/src/WhatsAPI++/WAConnection.h
+++ b/protocols/WhatsApp/src/WhatsAPI++/WAConnection.h
@@ -393,13 +393,12 @@ class WAConnection {
time_t expire_date;
int account_kind;
time_t lastTreeRead;
- static const int DICTIONARY_LEN = 237;
+ static const int DICTIONARY_LEN;
static const char* dictionary[];
static MessageStore* message_store;
KeyStream* inputKey;
KeyStream* outputKey;
-
static std::string removeResourceFromJid(const std::string& jid);
WALogin* getLogin();
diff --git a/protocols/WhatsApp/src/WhatsAPI++/WALogin.cpp b/protocols/WhatsApp/src/WhatsAPI++/WALogin.cpp
index 311edc70a5..459cc7efe9 100644
--- a/protocols/WhatsApp/src/WhatsAPI++/WALogin.cpp
+++ b/protocols/WhatsApp/src/WhatsAPI++/WALogin.cpp
@@ -7,7 +7,6 @@
#include "WALogin.h"
#include "ByteArray.h"
-//#include "ApplicationData.h"
#include "ProtocolTreeNode.h"
#include "WAException.h"
#include <iostream>
@@ -56,86 +55,26 @@ std::vector<unsigned char>* WALogin::login(const std::vector<unsigned char>& aut
return this->readFeaturesUntilChallengeOrSuccess();
}
-BinTreeNodeReader* WALogin::getTreeNodeReader() {
+BinTreeNodeReader* WALogin::getTreeNodeReader()
+{
return this->inn;
}
-BinTreeNodeWriter* WALogin::getTreeNodeWriter() {
+BinTreeNodeWriter* WALogin::getTreeNodeWriter()
+{
return this->out;
}
-std::string WALogin::getResponse(const std::string& challenge) {
- unsigned char md5_buffer[16];
-
- size_t i = challenge.find(WALogin::NONCE_KEY);
- i += WALogin::NONCE_KEY.length();
-
- size_t j = challenge.find('"', i);
- std::string nonce = challenge.substr(i,j-i);
-
- std::string cnonce = str(absLong(randLong()), 36);
- _LOGDATA("cnonce = %s", cnonce.c_str());
- std::string nc = "00000001";
- std::string cinfo(this->user + ":" + this->domain + ":" + this->password);
-
- _LOGDATA("cinfo = %s", cinfo.c_str());
-
- ByteArrayOutputStream bos;
- bos.write(utils::md5string(cinfo, md5_buffer), SIZEOF(md5_buffer));
- bos.write(58);
- bos.write(nonce);
- bos.write(58);
- bos.write(cnonce);
- // bos.print();
-
- std::string digest_uri = "xmpp/" + this->domain;
- std::vector<unsigned char>* A1 = bos.toByteArray();
- std::string A2 = "AUTHENTICATE:" + digest_uri;
- std::string KD = bytesToHex(utils::md5string(&A1->front(), (int)A1->size(), md5_buffer), SIZEOF(md5_buffer));
- KD += + ":" + nonce + ":" + nc + ":" + cnonce + ":auth:" + bytesToHex(utils::md5string(A2, md5_buffer), SIZEOF(md5_buffer));
-
- _LOGDATA("KD = %s", KD.c_str());
-
- std::string response = bytesToHex(utils::md5string(KD, md5_buffer), SIZEOF(md5_buffer));
-
- _LOGDATA("response = %s", response.c_str());
-
- std::string bigger_response;
- bigger_response.append("realm=\"");
- bigger_response.append(this->domain);
- bigger_response.append("\",response=");
- bigger_response.append(response);
- bigger_response.append(",nonce=\"");
- bigger_response.append(nonce);
- bigger_response.append("\",digest-uri=\"");
- bigger_response.append(digest_uri);
- bigger_response.append("\",cnonce=\"");
- bigger_response.append(cnonce);
- bigger_response.append("\",qop=auth");
- bigger_response.append(",username=\"");
- bigger_response.append(this->user);
- bigger_response.append("\",nc=");
- bigger_response.append(nc);
-
- _LOGDATA("biggerresponse = %s", bigger_response.c_str());
-
- delete A1;
-
- return bigger_response;
-}
-
void WALogin::sendResponse(const std::vector<unsigned char>& challengeData) {
std::vector<unsigned char>* authBlob = this->getAuthBlob(challengeData);
- // std::string response = this->getResponse(challengeData);
- std::map<string, string> *attributes = new std::map<string,string>();
- (*attributes)["xmlns"] = "urn:ietf:params:xml:ns:xmpp-sasl";
- ProtocolTreeNode node("response", attributes, authBlob);
+ ProtocolTreeNode node("response", NULL, authBlob);
this->out->write(&node);
}
-void WALogin::sendFeatures() {
+void WALogin::sendFeatures()
+{
ProtocolTreeNode* child = new ProtocolTreeNode("receipt_acks", NULL);
std::vector<ProtocolTreeNode*>* children = new std::vector<ProtocolTreeNode*>();
children->push_back(child);
@@ -151,47 +90,47 @@ void WALogin::sendFeatures() {
this->out->write(&node, true);
}
-void WALogin::sendAuth(const std::vector<unsigned char>& existingChallenge) {
+void WALogin::sendAuth(const std::vector<unsigned char>& existingChallenge)
+{
std::vector<unsigned char>* data = NULL;
if (!existingChallenge.empty()) {
data = this->getAuthBlob(existingChallenge);
}
std::map<string, string>* attributes = new std::map<string, string>();
- (*attributes)["xmlns"] = "urn:ietf:params:xml:ns:xmpp-sasl";
- (*attributes)["mechanism"] = "WAUTH-1";
+ (*attributes)["mechanism"] = "WAUTH-2";
(*attributes)["user"] = this->user;
ProtocolTreeNode node("auth", attributes, data, NULL);
this->out->write(&node, true);
}
-std::vector<unsigned char>* WALogin::getAuthBlob(const std::vector<unsigned char>& nonce) {
- unsigned char out[20];
+std::vector<unsigned char>* WALogin::getAuthBlob(const std::vector<unsigned char>& nonce)
+{
+ unsigned char out[4*20];
KeyStream::keyFromPasswordAndNonce(this->password, nonce, out);
if (this->connection->inputKey != NULL)
delete this->connection->inputKey;
- this->connection->inputKey = new KeyStream(out, 20);
+ this->connection->inputKey = new KeyStream(out + 40, out + 60);
if (this->outputKey != NULL)
delete this->outputKey;
+ this->outputKey = new KeyStream(out, out + 20);
- this->outputKey = new KeyStream(out, 20);
std::vector<unsigned char>* list = new std::vector<unsigned char>(0);
for (int i = 0; i < 4; i++)
list->push_back(0);
list->insert(list->end(), this->user.begin(), this->user.end());
list->insert(list->end(), nonce.begin(), nonce.end());
- std::string strTime = Utilities::intToStr( time(NULL));
- list->insert(list->end(), strTime.begin(), strTime.end());
this->outputKey->encodeMessage(&((*list)[0]), 0, 4, (int)list->size() - 4);
return list;
}
-std::vector<unsigned char>* WALogin::readFeaturesUntilChallengeOrSuccess() {
+std::vector<unsigned char>* WALogin::readFeaturesUntilChallengeOrSuccess()
+{
ProtocolTreeNode* root;
while ((root = this->inn->nextTree()) != NULL) {
if (ProtocolTreeNode::tagEquals(root, "stream:features")) {
@@ -221,7 +160,8 @@ std::vector<unsigned char>* WALogin::readFeaturesUntilChallengeOrSuccess() {
throw WAException("fell out of loop in readFeaturesAndChallenge", WAException::CORRUPT_STREAM_EX, 0);
}
-void WALogin::parseSuccessNode(ProtocolTreeNode* node) {
+void WALogin::parseSuccessNode(ProtocolTreeNode* node)
+{
const string &expiration = node->getAttributeValue("expiration");
if (!expiration.empty()) {
this->expire_date = atol(expiration.c_str());
@@ -242,7 +182,8 @@ void WALogin::parseSuccessNode(ProtocolTreeNode* node) {
this->connection->outputKey = this->outputKey;
}
-std::vector<unsigned char> WALogin::readSuccess() {
+std::vector<unsigned char> WALogin::readSuccess()
+{
ProtocolTreeNode* node = this->inn->nextTree();
if (ProtocolTreeNode::tagEquals(node, "failure")) {
@@ -271,58 +212,79 @@ std::vector<unsigned char> WALogin::readSuccess() {
return data;
}
-WALogin::~WALogin() {
-}
+WALogin::~WALogin()
+{}
-KeyStream::KeyStream(unsigned char* key, size_t keyLength) {
- unsigned char drop[256];
+KeyStream::KeyStream(unsigned char* _key, unsigned char* _keyMac) :
+ seq(0)
+{
+ memcpy(key, _key, 20);
+ memcpy(keyMac, _keyMac, 20);
- this->key = new unsigned char[keyLength];
- memcpy(this->key, key, keyLength);
- this->keyLength = (int)keyLength;
+ RC4_set_key(&this->rc4, 20, this->key);
- RC4_set_key(&this->rc4, this->keyLength, this->key);
- RC4(&this->rc4, 256, drop, drop);
- HMAC_CTX_init(&this->hmac);
+ unsigned char drop[768];
+ RC4(&this->rc4, sizeof(drop), drop, drop);
+
+ HMAC_CTX_init(&hmac);
}
-KeyStream::~KeyStream() {
- delete [] this->key;
- HMAC_CTX_cleanup(&this->hmac);
+KeyStream::~KeyStream()
+{
+ HMAC_CTX_cleanup(&hmac);
}
-void KeyStream::keyFromPasswordAndNonce(const std::string& pass, const std::vector<unsigned char>& nonce, unsigned char *out) {
- PKCS5_PBKDF2_HMAC_SHA1(pass.data(), (int)pass.size(), nonce.data(), (int)nonce.size(), 16, 20, out);
+void KeyStream::keyFromPasswordAndNonce(const std::string& pass, const std::vector<unsigned char>& nonce, unsigned char *out)
+{
+ size_t cbSize = nonce.size();
+
+ uint8_t *pNonce = (uint8_t*)_alloca(cbSize + 1);
+ memcpy(pNonce, nonce.data(), cbSize);
+
+ for (int i = 0; i < 4; i++) {
+ pNonce[cbSize] = i + 1;
+ PKCS5_PBKDF2_HMAC_SHA1(pass.data(), (int)pass.size(), pNonce, (int)cbSize+1, 2, 20, out + i*20);
+ }
}
-void KeyStream::decodeMessage(unsigned char* buffer, int macOffset, int offset, const int length) {
+void KeyStream::decodeMessage(unsigned char* buffer, int macOffset, int offset, const int length)
+{
unsigned char digest[20];
this->hmacsha1(buffer + offset, length, digest);
- for (int i = 0; i < 4; i++) {
- if (buffer[macOffset + i] != digest[i]) {
- throw WAException("invalid MAC", WAException::CORRUPT_STREAM_EX, 0);
- }
- }
- unsigned char* out = new unsigned char[length];
+ if (memcmp(&buffer[macOffset], digest, 4))
+ throw WAException("invalid MAC", WAException::CORRUPT_STREAM_EX, 0);
+
+ unsigned char* out = (unsigned char*)_alloca(length);
RC4(&this->rc4, length, buffer + offset, out);
memcpy(buffer + offset, out, length);
- delete[] out;
}
-void KeyStream::encodeMessage(unsigned char* buffer, int macOffset, int offset, const int length) {
- unsigned char* out = new unsigned char[length];
+void KeyStream::encodeMessage(unsigned char* buffer, int macOffset, int offset, const int length)
+{
+ unsigned char* out = (unsigned char*)_alloca(length);
RC4(&this->rc4, length, buffer + offset, out);
memcpy(buffer + offset, out, length);
- delete[] out;
unsigned char digest[20];
this->hmacsha1(buffer + offset, length, digest);
-
memcpy(buffer + macOffset, digest, 4);
}
-void KeyStream::hmacsha1(unsigned char* text, int textLength, unsigned char *out) {
+void KeyStream::hmacsha1(unsigned char* text, int textLength, unsigned char *out)
+{
+ HMAC_Init(&hmac, this->keyMac, 20, EVP_sha1());
+ HMAC_Update(&hmac, text, textLength);
+
+ unsigned char hmacInt[4];
+ hmacInt[0] = (this->seq >> 24);
+ hmacInt[1] = (this->seq >> 16);
+ hmacInt[2] = (this->seq >> 8);
+ hmacInt[3] = (this->seq);
+ HMAC_Update(&hmac, hmacInt, sizeof(hmacInt));
+
unsigned int mdLength;
- HMAC(EVP_sha1(), this->key, this->keyLength, text, textLength, out, &mdLength);
+ HMAC_Final(&hmac, out, &mdLength);
+
+ this->seq++;
}
diff --git a/protocols/WhatsApp/src/WhatsAPI++/WALogin.h b/protocols/WhatsApp/src/WhatsAPI++/WALogin.h
index 868e806880..2949213e53 100644
--- a/protocols/WhatsApp/src/WhatsAPI++/WALogin.h
+++ b/protocols/WhatsApp/src/WhatsAPI++/WALogin.h
@@ -23,15 +23,15 @@ class BinTreeNodeWriter;
class KeyStream {
private:
RC4_KEY rc4;
- HMAC_CTX hmac;
- unsigned char* key;
- int keyLength;
+ unsigned char key[20], keyMac[20];
+ int seq;
+ HMAC_CTX hmac;
void hmacsha1(unsigned char* text, int textLength, unsigned char *out);
public:
- KeyStream(unsigned char* key, size_t keyLegnth);
- virtual ~KeyStream();
+ KeyStream(unsigned char* _key, unsigned char* _keyMac);
+ ~KeyStream();
static void keyFromPasswordAndNonce(const std::string& pass, const std::vector<unsigned char>& nonce, unsigned char *out);
void decodeMessage(unsigned char* buffer, int macOffset, int offset, const int length);
@@ -54,7 +54,6 @@ private:
std::vector<unsigned char>* readFeaturesUntilChallengeOrSuccess();
void parseSuccessNode(ProtocolTreeNode* node);
std::vector<unsigned char> readSuccess();
- std::string getResponse(const std::string& challenge);
public:
std::string user;
diff --git a/protocols/WhatsApp/src/WhatsAPI++/WARegister.cpp b/protocols/WhatsApp/src/WhatsAPI++/WARegister.cpp
index a27c3c42eb..d2ff14411a 100644
--- a/protocols/WhatsApp/src/WhatsAPI++/WARegister.cpp
+++ b/protocols/WhatsApp/src/WhatsAPI++/WARegister.cpp
@@ -13,41 +13,16 @@ using namespace Utilities;
/////////////////////////////////////////////////////////////////////////////////////////
// Token generation
-static char WaKey[] = "/UIGKU1FVQa+ATM2A0za7G2KI9S/CwPYjgAbc67v7ep42eO/WeTLx1lb1cHwxpsEgF4+PmYpLd2YpGUdX/A2JQitsHzDwgcdBpUf7psX1BU=";
-static char WaSignature[] = "MIIDMjCCAvCgAwIBAgIETCU2pDALBgcqhkjOOAQDBQAwfDELMAkGA1UEBhMCVVMxEzARBgNVBAgTCkNhbGlmb3JuaWExFDASBgNVBAcTC1NhbnRhIENsYXJhMRYwFAYDVQQKEw1XaGF0c0FwcCBJbmMuMRQwEgYDVQQLEwtFbmdpbmVlcmluZzEUMBIGA1UEAxMLQnJpYW4gQWN0b24wHhcNMTAwNjI1MjMwNzE2WhcNNDQwMjE1MjMwNzE2WjB8MQswCQYDVQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTEUMBIGA1UEBxMLU2FudGEgQ2xhcmExFjAUBgNVBAoTDVdoYXRzQXBwIEluYy4xFDASBgNVBAsTC0VuZ2luZWVyaW5nMRQwEgYDVQQDEwtCcmlhbiBBY3RvbjCCAbgwggEsBgcqhkjOOAQBMIIBHwKBgQD9f1OBHXUSKVLfSpwu7OTn9hG3UjzvRADDHj+AtlEmaUVdQCJR+1k9jVj6v8X1ujD2y5tVbNeBO4AdNG/yZmC3a5lQpaSfn+gEexAiwk+7qdf+t8Yb+DtX58aophUPBPuD9tPFHsMCNVQTWhaRMvZ1864rYdcq7/IiAxmd0UgBxwIVAJdgUI8VIwvMspK5gqLrhAvwWBz1AoGBAPfhoIXWmz3ey7yrXDa4V7l5lK+7+jrqgvlXTAs9B4JnUVlXjrrUWU/mcQcQgYC0SRZxI+hMKBYTt88JMozIpuE8FnqLVHyNKOCjrh4rs6Z1kW6jfwv6ITVi8ftiegEkO8yk8b6oUZCJqIPf4VrlnwaSi2ZegHtVJWQBTDv+z0kqA4GFAAKBgQDRGYtLgWh7zyRtQainJfCpiaUbzjJuhMgo4fVWZIvXHaSHBU1t5w//S0lDK2hiqkj8KpMWGywVov9eZxZy37V26dEqr/c2m5qZ0E+ynSu7sqUD7kGx/zeIcGT0H+KAVgkGNQCo5Uc0koLRWYHNtYoIvt5R3X6YZylbPftF/8ayWTALBgcqhkjOOAQDBQADLwAwLAIUAKYCp0d6z4QQdyN74JDfQ2WCyi8CFDUM4CaNB+ceVXdKtOrNTQcc0e+t";
-static char WaClassesMd5[] = "xOyKd7AoN0uoos7Fkeup5w=="; // 2.11.407
+static char WaToken[] = "PdA2DJyKoUrwLw1Bg6EIhzh502dF9noR9uFCllGk1418865329241";
std::string WAToken::GenerateToken(const string &number)
{
- unsigned int keyLen, dataLen, classesLen;
- mir_ptr<BYTE> key((BYTE*)mir_base64_decode(WaKey, &keyLen));
- mir_ptr<BYTE> data((BYTE*)mir_base64_decode(WaSignature, &dataLen));
- mir_ptr<BYTE> classes((BYTE*)mir_base64_decode(WaClassesMd5, &classesLen));
-
- BYTE opad[64], ipad[64];
- memset(opad, 0x5C, sizeof(opad));
- memset(ipad, 0x36, sizeof(ipad));
- for (int i = 0; i < sizeof(opad); i++) {
- opad[i] = (BYTE)(opad[i] ^ key[i]);
- ipad[i] = (BYTE)(ipad[i] ^ key[i]);
- }
+ uint8_t digest[16];
+ md5_string(WaToken + number, digest);
- BYTE hash1[MIR_SHA1_HASH_SIZE], hash2[MIR_SHA1_HASH_SIZE];
- mir_sha1_ctx ctx;
- mir_sha1_init(&ctx);
- mir_sha1_append(&ctx, ipad, sizeof(ipad));
- mir_sha1_append(&ctx, data, dataLen);
- mir_sha1_append(&ctx, classes, classesLen);
- mir_sha1_append(&ctx, (PBYTE)number.c_str(), (int)number.size());
- mir_sha1_finish(&ctx, hash1);
-
- mir_sha1_init(&ctx);
- mir_sha1_append(&ctx, opad, sizeof(opad));
- mir_sha1_append(&ctx, hash1, sizeof(hash1));
- mir_sha1_finish(&ctx, hash2);
-
- ptrA result(mir_urlEncode(ptrA(mir_base64_encode(hash2, sizeof(hash2)))));
- return std::string(result);
+ char dest[33];
+ bin2hex(digest, sizeof(digest), dest);
+ return dest;
}
/////////////////////////////////////////////////////////////////////////////////////////