diff options
author | George Hazan <ghazan@miranda.im> | 2021-04-17 20:42:45 +0300 |
---|---|---|
committer | George Hazan <ghazan@miranda.im> | 2021-04-17 20:42:45 +0300 |
commit | d595e62db874337c8f39255eceb8d2792a4aac89 (patch) | |
tree | 4f8d868ac75799efc99a945fa6898dc8f7a2e03f /protocols/WhatsAppWeb | |
parent | daa4afc8e433fe9c9efd74f381df954591fded70 (diff) |
WhatsApp: binary packets processing
Diffstat (limited to 'protocols/WhatsAppWeb')
-rw-r--r-- | protocols/WhatsAppWeb/src/proto.h | 4 | ||||
-rw-r--r-- | protocols/WhatsAppWeb/src/server.cpp | 45 | ||||
-rw-r--r-- | protocols/WhatsAppWeb/src/utils.cpp | 35 |
3 files changed, 74 insertions, 10 deletions
diff --git a/protocols/WhatsAppWeb/src/proto.h b/protocols/WhatsAppWeb/src/proto.h index 1ba9d27257..93d2c075fb 100644 --- a/protocols/WhatsAppWeb/src/proto.h +++ b/protocols/WhatsAppWeb/src/proto.h @@ -93,12 +93,16 @@ class WhatsAppProto : public PROTO<WhatsAppProto> bool ProcessChallenge(const CMStringA &szChallenge); bool ProcessSecret(const CMStringA &szSecret); + bool decryptBinaryMessage(size_t cbSize, const void *buf, MBinBuffer &res); + /// Request handlers /////////////////////////////////////////////////////////////////// void OnRestoreSession1(const JSONNode &node); void OnRestoreSession2(const JSONNode &node); void OnStartSession(const JSONNode &node); + void ProcessBinaryPacket(const MBinBuffer &buf); + void ProcessPacket(const JSONNode &node); void ProcessBlocked(const JSONNode &node); void ProcessCmd(const JSONNode &node); diff --git a/protocols/WhatsAppWeb/src/server.cpp b/protocols/WhatsAppWeb/src/server.cpp index e46a3b62a6..1a66504532 100644 --- a/protocols/WhatsAppWeb/src/server.cpp +++ b/protocols/WhatsAppWeb/src/server.cpp @@ -335,20 +335,38 @@ bool WhatsAppProto::ServerThreadWorker() while (true) { switch (hdr.opCode) { case 1: // json packet + case 2: // binary packet if (hdr.bIsFinal) { // process a packet here - CMStringA szJson(netbuf.data() + hdr.headerSize, (int)hdr.payloadSize); - debugLogA("JSON received:\n%s", szJson.c_str()); + const char *start = netbuf.data() + hdr.headerSize; + const char *pos = strchr(start, ','); + if (pos == nullptr) { + debugLogA("invalid packet received, no comma"); + break; + } + pos++; + size_t dataSize = hdr.payloadSize - size_t(pos - start); + + // try to decode + if (hdr.opCode == 2 && hdr.payloadSize > 32) { + MBinBuffer dest; + if (!decryptBinaryMessage(dataSize, pos, dest)) { + Netlib_Dump(m_hServerConn, netbuf.data(), hdr.headerSize + hdr.payloadSize, false, 0); + debugLogA("cannot decrypt incoming message"); + break; + } - int pos = szJson.Find(','); - if (pos != -1) { - CMStringA szPrefix = szJson.Left(pos); - szJson.Delete(0, pos+1); + Netlib_Dump(m_hServerConn, dest.data(), dest.length(), false, 0); + ProcessBinaryPacket(dest); + } + else { + CMStringA szJson(pos, (int)dataSize); + debugLogA("JSON received:\n%s", szJson.c_str()); JSONNode root = JSONNode::parse(szJson); if (root) { int sessId, pktId; - if (sscanf(szPrefix, "%d.--%d,", &sessId, &pktId) == 2) { + if (sscanf(start, "%d.--%d,", &sessId, &pktId) == 2) { auto *pReq = m_arPacketQueue.find((WARequest *)&pktId); if (pReq != nullptr) { (this->*pReq->pHandler)(root); @@ -360,9 +378,6 @@ bool WhatsAppProto::ServerThreadWorker() } break; - case 2: // binary packet - break; - case 8: // close debugLogA("server required to exit"); bExit = true; // simply reconnect, don't exit @@ -404,6 +419,16 @@ bool WhatsAppProto::ServerThreadWorker() return false; } +///////////////////////////////////////////////////////////////////////////////////////// +// Binary data processing + +void WhatsAppProto::ProcessBinaryPacket(const MBinBuffer &buf) +{ +} + +///////////////////////////////////////////////////////////////////////////////////////// +// Json data processing + void WhatsAppProto::ProcessPacket(const JSONNode &root) { CMStringA szType = root[(size_t)0].as_mstring(); diff --git a/protocols/WhatsAppWeb/src/utils.cpp b/protocols/WhatsAppWeb/src/utils.cpp index 49ece0557a..bc35b6ef5f 100644 --- a/protocols/WhatsAppWeb/src/utils.cpp +++ b/protocols/WhatsAppWeb/src/utils.cpp @@ -34,3 +34,38 @@ WAUser* WhatsAppProto::AddUser(const char *szId, bool bTemporary) m_arUsers.insert(pUser); return pUser; } + +///////////////////////////////////////////////////////////////////////////////////////// + +bool WhatsAppProto::decryptBinaryMessage(size_t cbSize, const void *buf, MBinBuffer &res) +{ + if (cbSize <= 32) + return false; + + // validate message first + { + unsigned int md_len = 32; + BYTE md[32]; + HMAC(EVP_sha256(), mac_key.data(), (int)mac_key.length(), (unsigned char *)buf+32, (int)cbSize-32, md, &md_len); + if (memcmp(buf, md, sizeof(md))) { + debugLogA("Message cannot be decrypted, check your keys"); + return false; + } + } + + // okay, let's decrypt this thing + { + BYTE iv[16]; + memcpy(iv, (char*)buf + 32, sizeof(iv)); + res.assign((char*)buf + 48, cbSize - 48); + res.append((char*)mac_key.data(), 32); // reserve 32 more bytes for temp data + + int dec_len = 0, final_len = 0; + EVP_CIPHER_CTX *ctx = EVP_CIPHER_CTX_new(); + EVP_DecryptInit_ex(ctx, EVP_aes_256_cbc(), NULL, (BYTE*)enc_key.data(), iv); + EVP_DecryptUpdate(ctx, (BYTE*)res.data(), &dec_len, (BYTE*)buf + 48, (int)cbSize - 48); + EVP_DecryptFinal_ex(ctx, (BYTE*)res.data() + dec_len, &final_len); + EVP_CIPHER_CTX_free(ctx); + } + return true; +} |