From c47ca004ba979d23a86211393c9e35deadd66c46 Mon Sep 17 00:00:00 2001 From: George Hazan Date: Sat, 24 Jan 2015 16:35:14 +0000 Subject: 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 --- protocols/WhatsApp/src/WhatsAPI++/WALogin.cpp | 180 ++++++++++---------------- 1 file changed, 71 insertions(+), 109 deletions(-) (limited to 'protocols/WhatsApp/src/WhatsAPI++/WALogin.cpp') 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 @@ -56,86 +55,26 @@ std::vector* WALogin::login(const std::vector& 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* 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& challengeData) { std::vector* authBlob = this->getAuthBlob(challengeData); - // std::string response = this->getResponse(challengeData); - std::map *attributes = new std::map(); - (*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* children = new std::vector(); children->push_back(child); @@ -151,47 +90,47 @@ void WALogin::sendFeatures() { this->out->write(&node, true); } -void WALogin::sendAuth(const std::vector& existingChallenge) { +void WALogin::sendAuth(const std::vector& existingChallenge) +{ std::vector* data = NULL; if (!existingChallenge.empty()) { data = this->getAuthBlob(existingChallenge); } std::map* attributes = new std::map(); - (*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* WALogin::getAuthBlob(const std::vector& nonce) { - unsigned char out[20]; +std::vector* WALogin::getAuthBlob(const std::vector& 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* list = new std::vector(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* WALogin::readFeaturesUntilChallengeOrSuccess() { +std::vector* WALogin::readFeaturesUntilChallengeOrSuccess() +{ ProtocolTreeNode* root; while ((root = this->inn->nextTree()) != NULL) { if (ProtocolTreeNode::tagEquals(root, "stream:features")) { @@ -221,7 +160,8 @@ std::vector* 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 WALogin::readSuccess() { +std::vector WALogin::readSuccess() +{ ProtocolTreeNode* node = this->inn->nextTree(); if (ProtocolTreeNode::tagEquals(node, "failure")) { @@ -271,58 +212,79 @@ std::vector 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& 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& 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++; } -- cgit v1.2.3