summaryrefslogtreecommitdiff
path: root/protocols/WhatsAppWeb
diff options
context:
space:
mode:
authorGeorge Hazan <ghazan@miranda.im>2022-09-28 13:56:13 +0300
committerGeorge Hazan <ghazan@miranda.im>2022-09-28 13:56:13 +0300
commit3e1bb4ac88fe352f955cd639aeb1e3f57163b180 (patch)
tree589fc168398d7a27c66d8dfab5b862b1540035ff /protocols/WhatsAppWeb
parent49069bcc23da6ef9790c6efb2d0e5d3c92c6b7fd (diff)
WhatsApp: fix for packet decoding
Diffstat (limited to 'protocols/WhatsAppWeb')
-rw-r--r--protocols/WhatsAppWeb/src/noise.cpp70
-rw-r--r--protocols/WhatsAppWeb/src/proto.cpp9
-rw-r--r--protocols/WhatsAppWeb/src/proto.h20
-rw-r--r--protocols/WhatsAppWeb/src/server.cpp126
-rw-r--r--protocols/WhatsAppWeb/src/utils.cpp25
-rw-r--r--protocols/WhatsAppWeb/src/utils.h1
6 files changed, 145 insertions, 106 deletions
diff --git a/protocols/WhatsAppWeb/src/noise.cpp b/protocols/WhatsAppWeb/src/noise.cpp
index 79dc19e266..b85bc8eb7b 100644
--- a/protocols/WhatsAppWeb/src/noise.cpp
+++ b/protocols/WhatsAppWeb/src/noise.cpp
@@ -30,6 +30,9 @@ WANoise::WANoise(WhatsAppProto *_ppro) :
ephemeral.priv.assign(pPrivKey->data, sizeof(pPrivKey->data));
ec_key_pair_destroy(pKeys);
+ // ephemeral.pub.assign("\xd7\x58\xeb\xcc\x79\xb8\x58\xde\xc7\x60\x5c\x12\x22\xc1\x3b\x7c\xf6\x73\x38\x0b\x89\x56\xf1\xe2\xa1\xb0\xaa\x3a\xba\xbc\x08\x3f", 32);
+ // ephemeral.priv.assign("\xa0\xef\xd2\xbd\x2d\x4a\x6f\x9c\xd0\x9e\xc5\x75\x3c\x78\x78\xed\xe5\xec\x99\xd7\x4b\xeb\xf8\xb0\xdd\x1e\xe2\xc1\x85\xc4\xd8\x72", 32);
+
// prepare hash
memcpy(hash, noise_init, 32);
updateHash(intro_header, 4);
@@ -132,6 +135,15 @@ void WANoise::init()
preKey.keyid = ppro->getDword(DBKEY_PREKEY_KEYID);
}
+void WANoise::finish()
+{
+ deriveKey("", 0, salt, encKey);
+ decKey.assign(encKey.data(), encKey.length());
+ readCounter = writeCounter = 0;
+ memset(hash, 0, sizeof(hash));
+ bInitFinished = true;
+}
+
void WANoise::deriveKey(const void *pData, size_t cbLen, MBinBuffer &write, MBinBuffer &read)
{
auto *pctx = EVP_PKEY_CTX_new_id(EVP_PKEY_HKDF, NULL);
@@ -162,65 +174,46 @@ void WANoise::mixIntoKey(const void *n, const void *p)
MBinBuffer WANoise::decrypt(const void *pData, size_t cbLen)
{
- auto &pVar = (bInitFinished) ? readCounter : writeCounter;
-
uint8_t iv[12];
- memset(iv, 0, 8);
- memcpy(iv + 8, &pVar, sizeof(int));
- pVar++;
+ generateIV(iv, (bInitFinished) ? readCounter : writeCounter);
MBinBuffer res;
uint8_t outbuf[1024 + EVP_MAX_BLOCK_LENGTH];
- int dec_len = 0, final_len = 0;
+ int tag_len = 0, dec_len = 0, final_len = 0;
EVP_CIPHER_CTX *ctx = EVP_CIPHER_CTX_new();
EVP_DecryptInit_ex(ctx, EVP_aes_256_gcm(), NULL, (BYTE *)decKey.data(), iv);
+
+ EVP_DecryptUpdate(ctx, nullptr, &tag_len, hash, sizeof(hash));
+ cbLen -= 16;
+ EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_SET_TAG, 16, (BYTE *)pData + cbLen);
+
for (size_t len = 0; len < cbLen; len += 1024) {
size_t portionSize = cbLen - len;
EVP_DecryptUpdate(ctx, outbuf, &dec_len, (BYTE *)pData + len, (int)min(portionSize, 1024));
res.append(outbuf, dec_len);
}
- EVP_DecryptFinal_ex(ctx, outbuf, &final_len);
+
+ if (!EVP_DecryptFinal_ex(ctx, outbuf, &final_len))
+ ppro->debugLogA("Decryption failed");
+
if (final_len)
res.append(outbuf, final_len);
EVP_CIPHER_CTX_free(ctx);
- updateHash(pData, cbLen);
+ updateHash(pData, cbLen + 16);
return res;
}
-bool WANoise::decodeFrame(const void *pData, size_t cbLen)
+MBinBuffer WANoise::decodeFrame(const void *pData, size_t cbLen)
{
if (!bInitFinished) {
- proto::HandshakeMessage msg;
- if (msg.ParseFromArray(pData, (int)cbLen)) {
- auto &static_ = msg.serverhello().static_();
- auto &payload_ = msg.serverhello().payload();
- auto &ephemeral_ = msg.serverhello().ephemeral();
-
- updateHash(ephemeral_.c_str(), ephemeral_.size());
- mixIntoKey(ephemeral.priv.data(), ephemeral_.c_str());
-
- MBinBuffer decryptedStatic = decrypt(static_.c_str(), static_.size());
- mixIntoKey(ephemeral.priv.data(), decryptedStatic.data());
-
- MBinBuffer decryptedCert = decrypt(payload_.c_str(), payload_.size());
-
- proto::CertChain cert; cert.ParseFromArray(decryptedCert.data(), (int)decryptedCert.length());
- proto::CertChain::NoiseCertificate::Details details; details.ParseFromString(cert.intermediate().details());
- if (details.issuerserial() != 0) {
- ppro->ShutdownSession();
- return false;
- }
-
- MBinBuffer encryptedPub = encrypt(noiseKeys.pub.data(), noiseKeys.pub.length());
- mixIntoKey(noiseKeys.priv.data(), ephemeral_.c_str());
- ppro->ProcessHandshake(encryptedPub);
- }
- return true;
+ MBinBuffer res;
+ res.assign(pData, cbLen);
+ return res;
}
- return false;
+ return decrypt(pData, cbLen);
}
MBinBuffer WANoise::encodeFrame(const void *pData, size_t cbLen)
@@ -244,11 +237,8 @@ MBinBuffer WANoise::encodeFrame(const void *pData, size_t cbLen)
MBinBuffer WANoise::encrypt(const void *pData, size_t cbLen)
{
- auto counter = encodeBigEndian(writeCounter);
uint8_t iv[12];
- memset(iv, 0, sizeof(iv));
- memcpy(iv + 8, counter.c_str(), sizeof(int));
- writeCounter++;
+ generateIV(iv, writeCounter);
MBinBuffer res;
uint8_t outbuf[1024 + 64];
diff --git a/protocols/WhatsAppWeb/src/proto.cpp b/protocols/WhatsAppWeb/src/proto.cpp
index 6ca625e2e4..c21b6e24c7 100644
--- a/protocols/WhatsAppWeb/src/proto.cpp
+++ b/protocols/WhatsAppWeb/src/proto.cpp
@@ -22,11 +22,6 @@ static int CompareOwnMsgs(const WAOwnMessage *p1, const WAOwnMessage *p2)
return strcmp(p1->szPrefix, p2->szPrefix);
}
-static int CompareRequests(const WARequest *p1, const WARequest *p2)
-{
- return strcmp(p1->szPrefix, p2->szPrefix);
-}
-
static int CompareUsers(const WAUser *p1, const WAUser *p2)
{
return strcmp(p1->szId, p2->szId);
@@ -38,7 +33,7 @@ WhatsAppProto::WhatsAppProto(const char *proto_name, const wchar_t *username) :
m_tszDefaultGroup(getWStringA(DBKEY_DEF_GROUP)),
m_arUsers(10, CompareUsers),
m_arOwnMsgs(1, CompareOwnMsgs),
- m_arPacketQueue(10, CompareRequests),
+ m_arPacketQueue(10),
m_wszDefaultGroup(this, "DefaultGroup", L"WhatsApp"),
m_bHideGroupchats(this, "HideChats", true)
{
@@ -258,7 +253,7 @@ int WhatsAppProto::SendMsg(MCONTACT hContact, int, const char *pszMsg)
payLoad.addAttr("type", "relay");
payLoad.content.assign(pBuf, cbBinaryLen);
- int pktId = WSSendNode(szMsgId, 0, payLoad, &WhatsAppProto::OnSendMessage);
+ int pktId = WSSendNode(0, payLoad);
mir_cslock lck(m_csOwnMessages);
m_arOwnMsgs.insert(new WAOwnMessage(pktId, hContact, szMsgId));
diff --git a/protocols/WhatsAppWeb/src/proto.h b/protocols/WhatsAppWeb/src/proto.h
index 7d5263952c..7d02b425bb 100644
--- a/protocols/WhatsAppWeb/src/proto.h
+++ b/protocols/WhatsAppWeb/src/proto.h
@@ -12,11 +12,15 @@ Copyright © 2019-22 George Hazan
#define KEY_BUNDLE_TYPE "\x05"
class WhatsAppProto;
-typedef void (WhatsAppProto:: *WA_PKT_HANDLER)(const JSONNode &node, void*);
+typedef void (WhatsAppProto:: *WA_PKT_HANDLER)(const void *pData, int cbLen);
struct WARequest
{
- CMStringA szPrefix;
+ WARequest(WA_PKT_HANDLER _1, void *_2 = nullptr) :
+ pHandler(_1),
+ pUserInfo(_2)
+ {}
+
WA_PKT_HANDLER pHandler;
void *pUserInfo;
};
@@ -89,13 +93,13 @@ class WANoise
public:
WANoise(WhatsAppProto *_ppro);
- void finish() { bInitFinished = true; }
+ void finish();
void init();
MBinBuffer decrypt(const void *pData, size_t cbLen);
MBinBuffer encrypt(const void *pData, size_t cbLen);
- bool decodeFrame(const void *pData, size_t cbLen);
+ MBinBuffer decodeFrame(const void *pData, size_t cbLen);
MBinBuffer encodeFrame(const void *pData, size_t cbLen);
};
@@ -164,15 +168,13 @@ class WhatsAppProto : public PROTO<WhatsAppProto>
bool WSReadPacket(const WSHeader &hdr, MBinBuffer &buf);
int WSSend(const MessageLite &msg, WA_PKT_HANDLER = nullptr, void *pUserIndo = nullptr);
- int WSSendNode(const char *pszPrefix, int flags, WANode &node, WA_PKT_HANDLER = nullptr);
+ int WSSendNode(int flags, WANode &node, WA_PKT_HANDLER = nullptr);
void OnLoggedIn(void);
void OnLoggedOut(void);
bool ServerThreadWorker(void);
void ShutdownSession(void);
- bool ProcessHandshake(const MBinBuffer &szkeyEnc);
-
void SendKeepAlive();
/// Request handlers ///////////////////////////////////////////////////////////////////
@@ -180,7 +182,9 @@ class WhatsAppProto : public PROTO<WhatsAppProto>
void OnGetAvatarInfo(const JSONNode &node, void*);
void OnGetChatInfo(const JSONNode &node, void*);
void OnSendMessage(const JSONNode &node, void*);
- void OnStartSession(const JSONNode &node, void*);
+
+ void OnProcessHandshake(const void *pData, int cbLen);
+ void OnStartSession(const void *pData, int cbLen);
// binary packets
void ProcessBinaryPacket(const uint8_t *pData, size_t cbLen);
diff --git a/protocols/WhatsAppWeb/src/server.cpp b/protocols/WhatsAppWeb/src/server.cpp
index 4633fd74ac..1bd6c70b49 100644
--- a/protocols/WhatsAppWeb/src/server.cpp
+++ b/protocols/WhatsAppWeb/src/server.cpp
@@ -52,8 +52,73 @@ void WhatsAppProto::SendKeepAlive()
/////////////////////////////////////////////////////////////////////////////////////////
-bool WhatsAppProto::ProcessHandshake(const MBinBuffer &keyEnc)
+void WhatsAppProto::ShutdownSession()
+{
+ if (m_bTerminated)
+ return;
+
+ debugLogA("WhatsAppProto::ShutdownSession");
+
+ // shutdown all resources
+ if (m_hServerConn)
+ Netlib_Shutdown(m_hServerConn);
+
+ OnLoggedOut();
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+void WhatsAppProto::OnStartSession(const void *pData, int cbLen)
+{
+ proto::HandshakeMessage msg;
+ if (!msg.ParseFromArray(pData, cbLen)) {
+ debugLogA("Error parsing data, exiting");
+ ShutdownSession();
+ return;
+ }
+
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+void WhatsAppProto::OnProcessHandshake(const void *pData, int cbLen)
{
+ proto::HandshakeMessage msg;
+ if (!msg.ParseFromArray(pData, cbLen)) {
+ debugLogA("Error parsing data, exiting");
+
+LBL_Error:
+ ShutdownSession();
+ return;
+ }
+
+ auto &static_ = msg.serverhello().static_();
+ auto &payload_ = msg.serverhello().payload();
+ auto &ephemeral_ = msg.serverhello().ephemeral();
+
+ // std::string ephemeral_("\xe5\x3d\xff\xc6\x59\xef\xa7\x64\xf6\x48\xf3\x46\x15\xb4\x4f\x13\xfa\xc6\x29\x18\x34\xd4\xa4\xa9\xad\xa0\xa3\x05\xaa\x4d\xda\x36", 32);
+ // std::string static_("\xa9\x70\xc0\xfe\xe0\x72\x3b\x0a\x6e\x0a\xd4\xe1\xb4\x5f\xcd\xb8\x06\x68\xdd\x6b\x45\x36\xe0\x7d\x0d\xe9\x00\x4d\xb6\xaf\xfa\xa3\xb7\x54\x82\x24\xa9\xe4\x2c\xd4\xe5\xd0\x2f\xd6\x31\x2b\xca\xec", 48);
+ // std::string payload_("\x11\xcc\xb8\x74\xe6\x27\x29\x37\x65\xb2\x9e\x47\x53\x89\xf7\xce\x23\x03\x9c\xd4\x9e\x4b\x12\xdc\x3f\x10\xe4\x68\xfe\xfd\x31\x80\x1d\x48\x01\x9c\x31\xef\x54\xdb\xa1\x8f\xdb\x6b\x53\x84\xbb\x6d\xb4\x0c\x61\x1f\xcd\xe7\x3c\x0e\xe2\x18\xe4\x95\xf7\xbc\x5b\xbf\x80\x93\x21\x98\x80\x20\x9b\x71\x27\x47\x39\xe9\x04\x08\x5d\xd2\x62\x48\xf6\x23\xba\xa0\x31\xfc\x7c\xeb\xa0\xaa\x56\x04\x71\x71\x84\x9b\x08\xa4\xc9\x33\xd5\x07\x04\x5f\x1c\xd2\x6f\x7d\x5d\x83\x29\x5f\x80\x4a\xbf\x7c\xd9\x7c\xd0\x2b\x9a\x1e\xe0\x28\x33\x89\xb5\x3b\xd2\xe7\x7f\xfc\xd6\xa8\x55\xe2\x9c\x6e\x5f\x6f\x08\xa1\xf3\xfd\x5e\xff\x56\xee\x6f\x31\x47\xeb\xd4\x07\x92\x81\x72\x68\x91\x9d\xe9\xb3\x5f\x1d\x61\x8e\xce\x55\x4b\xbe\x74\x5d\xef\xea\xe4\x23\x63\x0d\x7c\xd4\xa3\xf8\xa1\x29\x60\xd7\x2c\xe8\xfc\xb5\x89\x99\x32\x95\xfc\xec\x6f\x7b\x2a\x23\xf4\x75\xbe\xe3\x21\x6a\x71\x3f\xc4\x1b\x99\x9f\x42\xd5\x19\xd8\xcc\xe7\xab\x90\xdd\xe5\xd8\xa5\xe3\xb5\x5c\xa2\x54\xf3\x4b\x0c\xa1\xe2\xa2\x91\xa3\xd0\x92\x6d\xfa\xab\x5a\xf6\x80\xee\x84\xbe\xaa\x75\x5e\xee\x6b\x91\x49", 257);
+
+ m_noise->updateHash(ephemeral_.c_str(), ephemeral_.size());
+ m_noise->mixIntoKey(m_noise->ephemeral.priv.data(), ephemeral_.c_str());
+
+ MBinBuffer decryptedStatic = m_noise->decrypt(static_.c_str(), static_.size());
+ m_noise->mixIntoKey(m_noise->ephemeral.priv.data(), decryptedStatic.data());
+
+ MBinBuffer decryptedCert = m_noise->decrypt(payload_.c_str(), payload_.size());
+
+ proto::CertChain cert; cert.ParseFromArray(decryptedCert.data(), (int)decryptedCert.length());
+ proto::CertChain::NoiseCertificate::Details details; details.ParseFromString(cert.intermediate().details());
+ if (details.issuerserial() != 0) {
+ debugLogA("Invalid certificate serial number, exiting");
+ goto LBL_Error;
+ }
+
+ MBinBuffer encryptedPub = m_noise->encrypt(m_noise->noiseKeys.pub.data(), m_noise->noiseKeys.pub.length());
+ m_noise->mixIntoKey(m_noise->noiseKeys.priv.data(), ephemeral_.c_str());
+
+ // create reply
proto::ClientPayload node;
MFileVersion v;
@@ -89,7 +154,7 @@ bool WhatsAppProto::ProcessHandshake(const MBinBuffer &keyEnc)
pPairingData->set_eskeyval(m_noise->preKey.pub.data(), m_noise->preKey.pub.length());
pPairingData->set_eskeysig(m_noise->preKey.signature.data(), m_noise->preKey.signature.length());
node.set_allocated_devicepairingdata(pPairingData);
-
+
node.set_passive(false);
}
// generate login packet
@@ -125,50 +190,18 @@ bool WhatsAppProto::ProcessHandshake(const MBinBuffer &keyEnc)
MBinBuffer payload(node.ByteSize());
node.SerializeToArray(payload.data(), (int)payload.length());
-
+
MBinBuffer payloadEnc = m_noise->encrypt(payload.data(), payload.length());
-
+
auto *pFinish = new proto::HandshakeMessage_ClientFinish();
pFinish->set_payload(payloadEnc.data(), payloadEnc.length());
- pFinish->set_static_(keyEnc.data(), keyEnc.length());
+ pFinish->set_static_(encryptedPub.data(), encryptedPub.length());
proto::HandshakeMessage handshake;
handshake.set_allocated_clientfinish(pFinish);
- WSSend(handshake);
-
- m_noise->finish();
- return true;
-}
-
-/////////////////////////////////////////////////////////////////////////////////////////
-
-void WhatsAppProto::ShutdownSession()
-{
- if (m_bTerminated)
- return;
-
- debugLogA("WhatsAppProto::ShutdownSession");
+ WSSend(handshake, &WhatsAppProto::OnStartSession);
- // shutdown all resources
- if (m_hServerConn)
- Netlib_Shutdown(m_hServerConn);
-
- OnLoggedOut();
-}
-
-/////////////////////////////////////////////////////////////////////////////////////////
-
-void WhatsAppProto::OnStartSession(const JSONNode &root, void*)
-{
- int status = root["status"].as_int();
- if (status != 200) {
- debugLogA("Session start failed with error %d", status);
- ShutdownSession();
- return;
- }
-
- CMStringA ref = root["ref"].as_mstring();
- ShowQrCode(ref);
+ m_noise->finish();
}
/////////////////////////////////////////////////////////////////////////////////////////
@@ -236,7 +269,8 @@ bool WhatsAppProto::ServerThreadWorker()
auto &pubKey = m_noise->ephemeral.pub;
auto *client = new proto::HandshakeMessage::ClientHello(); client->set_ephemeral(pubKey.data(), pubKey.length());
proto::HandshakeMessage msg; msg.set_allocated_clienthello(client);
- WSSend(msg, &WhatsAppProto::OnStartSession);
+ WSSend(msg, &WhatsAppProto::OnProcessHandshake);
+ // OnProcessHandshake(0, 0);
bool bExit = false;
MBinBuffer netbuf;
@@ -302,7 +336,6 @@ bool WhatsAppProto::ServerThreadWorker()
auto *pReq = m_arPacketQueue.find((WARequest *)&szPrefix);
if (pReq != nullptr) {
root << CHAR_PARAM("$id$", szPrefix);
- (this->*pReq->pHandler)(root, pReq->pUserInfo);
}
else ProcessPacket(root);
}
@@ -370,8 +403,15 @@ void WhatsAppProto::ProcessBinaryPacket(const uint8_t *pData, size_t cbDataLen)
return;
}
- if (!m_noise->decodeFrame(pData, payloadLen))
- debugLogA("cannot decrypt incoming message");
+ MBinBuffer pkt = m_noise->decodeFrame(pData, payloadLen);
+
+ if (m_arPacketQueue.getCount()) {
+ WARequest req = m_arPacketQueue[0];
+ m_arPacketQueue.remove(0);
+
+ (this->*req.pHandler)(pkt.data(), (int)pkt.length());
+ }
+ else debugLogA("cannot handle incoming message");
pData += payloadLen;
cbDataLen -= payloadLen;
diff --git a/protocols/WhatsAppWeb/src/utils.cpp b/protocols/WhatsAppWeb/src/utils.cpp
index 9f687d0368..a584d2431c 100644
--- a/protocols/WhatsAppWeb/src/utils.cpp
+++ b/protocols/WhatsAppWeb/src/utils.cpp
@@ -51,13 +51,18 @@ bool WhatsAppProto::getBlob(const char *szSetting, MBinBuffer &buf)
/////////////////////////////////////////////////////////////////////////////////////////
// sends a piece of JSON to a server via a websocket, masked
-int WhatsAppProto::WSSend(const MessageLite &msg, WA_PKT_HANDLER /*pHandler*/, void * /*pUserInfo*/)
+int WhatsAppProto::WSSend(const MessageLite &msg, WA_PKT_HANDLER pHandler, void *pUserInfo)
{
if (m_hServerConn == nullptr)
return -1;
// debugLogA("Sending packet: %s", msg..DebugString().c_str());
+ if (pHandler != nullptr) {
+ mir_cslock lck(m_csPacketQueue);
+ m_arPacketQueue.insert(new WARequest(pHandler, pUserInfo));
+ }
+
int cbLen = msg.ByteSize();
ptrA protoBuf((char *)mir_alloc(cbLen));
msg.SerializeToArray(protoBuf, cbLen);
@@ -71,7 +76,7 @@ int WhatsAppProto::WSSend(const MessageLite &msg, WA_PKT_HANDLER /*pHandler*/, v
static char zeroData[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
-int WhatsAppProto::WSSendNode(const char *pszPrefix, int flags, WANode &node, WA_PKT_HANDLER pHandler)
+int WhatsAppProto::WSSendNode(int flags, WANode &node, WA_PKT_HANDLER pHandler)
{
if (m_hServerConn == nullptr)
return 0;
@@ -100,18 +105,13 @@ int WhatsAppProto::WSSendNode(const char *pszPrefix, int flags, WANode &node, WA
int pktId = ++m_iPktNumber;
if (pHandler != nullptr) {
- auto *pReq = new WARequest;
- pReq->pHandler = pHandler;
- pReq->szPrefix = pszPrefix;
-
mir_cslock lck(m_csPacketQueue);
- m_arPacketQueue.insert(pReq);
+ m_arPacketQueue.insert(new WARequest(pHandler));
}
char postPrefix[3] = {',', 0, (char)flags};
MBinBuffer ret;
- ret.append(pszPrefix, strlen(pszPrefix));
ret.append(postPrefix, sizeof(postPrefix));
WebSocket_SendBinary(m_hServerConn, ret.data(), ret.length());
@@ -639,3 +639,12 @@ std::string encodeBigEndian(uint32_t num, size_t len)
}
return res;
}
+
+void generateIV(uint8_t *iv, int &pVar)
+{
+ auto counter = encodeBigEndian(pVar);
+ memset(iv, 0, sizeof(iv));
+ memcpy(iv + 8, counter.c_str(), sizeof(int));
+
+ pVar++;
+}
diff --git a/protocols/WhatsAppWeb/src/utils.h b/protocols/WhatsAppWeb/src/utils.h
index aa8f220292..c05dbd5410 100644
--- a/protocols/WhatsAppWeb/src/utils.h
+++ b/protocols/WhatsAppWeb/src/utils.h
@@ -103,3 +103,4 @@ public:
/////////////////////////////////////////////////////////////////////////////////////////
std::string encodeBigEndian(uint32_t num, size_t len = sizeof(uint32_t));
+void generateIV(uint8_t *iv, int &pVar);