summaryrefslogtreecommitdiff
path: root/protocols/WhatsAppWeb
diff options
context:
space:
mode:
authorGeorge Hazan <ghazan@miranda.im>2021-04-17 20:42:45 +0300
committerGeorge Hazan <ghazan@miranda.im>2021-04-17 20:42:45 +0300
commitd595e62db874337c8f39255eceb8d2792a4aac89 (patch)
tree4f8d868ac75799efc99a945fa6898dc8f7a2e03f /protocols/WhatsAppWeb
parentdaa4afc8e433fe9c9efd74f381df954591fded70 (diff)
WhatsApp: binary packets processing
Diffstat (limited to 'protocols/WhatsAppWeb')
-rw-r--r--protocols/WhatsAppWeb/src/proto.h4
-rw-r--r--protocols/WhatsAppWeb/src/server.cpp45
-rw-r--r--protocols/WhatsAppWeb/src/utils.cpp35
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;
+}