summaryrefslogtreecommitdiff
path: root/protocols
diff options
context:
space:
mode:
Diffstat (limited to 'protocols')
-rw-r--r--protocols/WhatsApp/src/appsync.cpp4
-rw-r--r--protocols/WhatsApp/src/crypt.cpp35
-rw-r--r--protocols/WhatsApp/src/iq.cpp1
-rw-r--r--protocols/WhatsApp/src/message.cpp37
-rw-r--r--protocols/WhatsApp/src/proto.cpp29
-rw-r--r--protocols/WhatsApp/src/proto.h7
-rw-r--r--protocols/WhatsApp/src/signal.cpp19
-rw-r--r--protocols/WhatsApp/src/utils.cpp15
-rw-r--r--protocols/WhatsApp/src/utils.h10
9 files changed, 113 insertions, 44 deletions
diff --git a/protocols/WhatsApp/src/appsync.cpp b/protocols/WhatsApp/src/appsync.cpp
index 040983c666..034c51cab6 100644
--- a/protocols/WhatsApp/src/appsync.cpp
+++ b/protocols/WhatsApp/src/appsync.cpp
@@ -105,7 +105,7 @@ void WhatsAppProto::OnIqServerSync(const WANode &node)
continue;
}
- proto::SyncdSnapshot snapshot(unpad16buf(buf));
+ proto::SyncdSnapshot snapshot(unpadBuffer16(buf));
if (!snapshot) {
debugLogA("%s: unable to decode snapshot, skipping");
continue;
@@ -189,7 +189,7 @@ void WhatsAppProto::ParsePatch(WACollection *pColl, const Wa__SyncdRecord *rec,
return;
}
- proto::SyncActionData data(unpad16buf(decoded));
+ proto::SyncActionData data(unpadBuffer16(decoded));
// debugLogA("Applying patch for %s{%d}: %s", pColl->szName.get(), data.version, data.Utf8DebugString().c_str());
diff --git a/protocols/WhatsApp/src/crypt.cpp b/protocols/WhatsApp/src/crypt.cpp
index 1efb93dde4..20e8ddd1bd 100644
--- a/protocols/WhatsApp/src/crypt.cpp
+++ b/protocols/WhatsApp/src/crypt.cpp
@@ -42,6 +42,41 @@ MBinBuffer aesDecrypt(
return ret;
}
+MBinBuffer aesEncrypt(
+ const EVP_CIPHER *cipher,
+ const uint8_t *key,
+ const uint8_t *iv,
+ const void *data, size_t dataLen,
+ const void *additionalData, size_t additionalLen)
+{
+ int tag_len = 0, dec_len = 0, final_len = 0;
+ EVP_CIPHER_CTX *ctx = EVP_CIPHER_CTX_new();
+ EVP_EncryptInit_ex(ctx, cipher, NULL, key, iv);
+
+ if (additionalLen)
+ EVP_EncryptUpdate(ctx, nullptr, &tag_len, (uint8_t *)additionalData, (int)additionalLen);
+
+ if (cipher == EVP_aes_256_gcm()) {
+ dataLen -= 16;
+ EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_SET_TAG, 16, (uint8_t *)data + dataLen);
+ }
+
+ MBinBuffer ret;
+ uint8_t outbuf[2000];
+ for (size_t len = 0; len < dataLen; len += 1024) {
+ size_t portionSize = dataLen - len;
+ EVP_EncryptUpdate(ctx, outbuf, &dec_len, (uint8_t *)data + len, (int)min(portionSize, 1024));
+ ret.append(outbuf, dec_len);
+ }
+
+ EVP_EncryptFinal_ex(ctx, outbuf, &final_len);
+ if (final_len)
+ ret.append(outbuf, final_len);
+
+ EVP_CIPHER_CTX_free(ctx);
+ return ret;
+}
+
/////////////////////////////////////////////////////////////////////////////////////////
static unsigned char *HKDF_Extract(const EVP_MD *evp_md,
diff --git a/protocols/WhatsApp/src/iq.cpp b/protocols/WhatsApp/src/iq.cpp
index 2470162cf5..1e8361cf90 100644
--- a/protocols/WhatsApp/src/iq.cpp
+++ b/protocols/WhatsApp/src/iq.cpp
@@ -495,6 +495,7 @@ void WhatsAppProto::InitPersistentHandlers()
m_arPersistent.insert(new WAPersistentHandler("notification", "server_sync", 0, 0, &WhatsAppProto::OnServerSync));
m_arPersistent.insert(new WAPersistentHandler("notification", 0, 0, 0, &WhatsAppProto::OnNotifyAny));
+ m_arPersistent.insert(new WAPersistentHandler("ack", 0, 0, 0, &WhatsAppProto::OnReceiveAck));
m_arPersistent.insert(new WAPersistentHandler("ib", 0, 0, 0, &WhatsAppProto::OnReceiveInfo));
m_arPersistent.insert(new WAPersistentHandler("message", 0, 0, 0, &WhatsAppProto::OnReceiveMessage));
m_arPersistent.insert(new WAPersistentHandler("receipt", 0, 0, 0, &WhatsAppProto::OnReceiveReceipt));
diff --git a/protocols/WhatsApp/src/message.cpp b/protocols/WhatsApp/src/message.cpp
index 0d7a849c68..bdf0bc9c7a 100644
--- a/protocols/WhatsApp/src/message.cpp
+++ b/protocols/WhatsApp/src/message.cpp
@@ -129,7 +129,7 @@ void WhatsAppProto::OnReceiveMessage(const WANode &node)
iDecryptable++;
- proto::Message encMsg(unpad16buf(msgBody));
+ proto::Message encMsg(unpadBuffer16(msgBody));
if (!encMsg)
throw "Invalid decoded message";
@@ -293,19 +293,41 @@ void WhatsAppProto::ProcessMessage(WAMSG type, const Wa__WebMessageInfo &msg)
/////////////////////////////////////////////////////////////////////////////////////////
+void WhatsAppProto::OnReceiveAck(const WANode &node)
+{
+ auto *pUser = FindUser(node.getAttr("from"));
+ if (pUser == nullptr)
+ return;
+
+ if (!mir_strcmp(node.getAttr("class"), "message")) {
+ WAOwnMessage tmp(0, 0, node.getAttr("id"));
+ {
+ mir_cslock lck(m_csOwnMessages);
+ if (auto *pOwn = m_arOwnMsgs.find(&tmp)) {
+ tmp.pktId = pOwn->pktId;
+ m_arOwnMsgs.remove(pOwn);
+ }
+ else return;
+ }
+ ProtoBroadcastAck(pUser->hContact, ACKTYPE_MESSAGE, ACKRESULT_SUCCESS, (HANDLE)tmp.pktId, (LPARAM)tmp.szMessageId.c_str());
+ }
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
bool WhatsAppProto::CreateMsgParticipant(WANode *pParticipants, const WAJid &jid, const MBinBuffer &orig)
{
int type = 0;
try {
- SignalBuffer pBuffer(m_signalStore.encryptSignalProto(jid, orig, type));
+ MBinBuffer pBuffer(m_signalStore.encryptSignalProto(jid, orig, type));
auto *pNode = pParticipants->addChild("to");
pNode->addAttr("jid", jid.toString());
auto *pEnc = pNode->addChild("enc");
*pEnc << CHAR_PARAM("v", "2") << CHAR_PARAM("type", (type == 3) ? "pkmsg" : "msg");
- pEnc->content.assign(pBuffer.data(), pBuffer.len());
+ pEnc->content.assign(pBuffer.data(), pBuffer.length());
}
catch (const char *) {
}
@@ -315,10 +337,10 @@ bool WhatsAppProto::CreateMsgParticipant(WANode *pParticipants, const WAJid &jid
int WhatsAppProto::SendTextMessage(const char *jid, const char *pszMsg)
{
- char msgId[16], szMsgId[33];
- Utils_GetRandom(msgId, sizeof(msgId));
- bin2hex(msgId, sizeof(msgId), szMsgId);
- strupr(szMsgId);
+ char szMsgId[40];
+ __int64 msgId;
+ Utils_GetRandom(&msgId, sizeof(msgId));
+ _i64toa(msgId, szMsgId, 10);
Wa__Message body;
body.conversation = (char*)pszMsg;
@@ -331,6 +353,7 @@ int WhatsAppProto::SendTextMessage(const char *jid, const char *pszMsg)
msg.devicesentmessage = &sentBody;
MBinBuffer encMsg(proto::Serialize(&msg));
+ padBuffer16(encMsg);
WANode payLoad("message");
payLoad << CHAR_PARAM("id", szMsgId) << CHAR_PARAM("type", "text") << CHAR_PARAM("to", jid);
diff --git a/protocols/WhatsApp/src/proto.cpp b/protocols/WhatsApp/src/proto.cpp
index 863d12df1b..96e379ed73 100644
--- a/protocols/WhatsApp/src/proto.cpp
+++ b/protocols/WhatsApp/src/proto.cpp
@@ -19,7 +19,7 @@ struct SearchParam
static int CompareOwnMsgs(const WAOwnMessage *p1, const WAOwnMessage *p2)
{
- return strcmp(p1->szPrefix, p2->szPrefix);
+ return strcmp(p1->szMessageId, p2->szMessageId);
}
static int CompareUsers(const WAUser *p1, const WAUser *p2)
@@ -203,33 +203,6 @@ int WhatsAppProto::SetStatus(int new_status)
/////////////////////////////////////////////////////////////////////////////////////////
-/*
-void WhatsAppProto::OnSendMessage(const JSONNode &node, void*)
-{
- CMStringA szPrefix= node["$id$"].as_mstring();
-
- WAOwnMessage tmp(0, 0, szPrefix);
- {
- mir_cslock lck(m_csOwnMessages);
- auto *pOwn = m_arOwnMsgs.find(&tmp);
- if (pOwn == nullptr)
- return;
-
- tmp.pktId = pOwn->pktId;
- tmp.hContact = pOwn->hContact;
- m_arOwnMsgs.remove(pOwn);
- }
-
- int status = node["status"].as_int();
- if (status == 200)
- ProtoBroadcastAck(tmp.hContact, ACKTYPE_MESSAGE, ACKRESULT_SUCCESS, (HANDLE)tmp.pktId);
- else {
- CMStringW wszError(FORMAT, TranslateT("Operation failed with server error status %d"), status);
- ProtoBroadcastAck(tmp.hContact, ACKTYPE_MESSAGE, ACKRESULT_FAILED, (HANDLE)tmp.pktId, LPARAM(wszError.c_str()));
- }
-}
-*/
-
int WhatsAppProto::SendMsg(MCONTACT hContact, int, const char *pszMsg)
{
ptrA jid(getStringA(hContact, DBKEY_ID));
diff --git a/protocols/WhatsApp/src/proto.h b/protocols/WhatsApp/src/proto.h
index c6b98a8fb9..ced5aab79d 100644
--- a/protocols/WhatsApp/src/proto.h
+++ b/protocols/WhatsApp/src/proto.h
@@ -100,11 +100,11 @@ struct WAOwnMessage
WAOwnMessage(int _1, const char *_2, const char *_3) :
pktId(_1),
szJid(_2),
- szPrefix(_3)
+ szMessageId(_3)
{}
int pktId;
- CMStringA szPrefix, szJid;
+ CMStringA szJid, szMessageId;
};
struct WACollection
@@ -207,7 +207,7 @@ public:
MBinBuffer decryptSignalProto(const CMStringA &from, const char *pszType, const MBinBuffer &encrypted);
MBinBuffer decryptGroupSignalProto(const CMStringA &from, const CMStringA &author, const MBinBuffer &encrypted);
- signal_buffer* encryptSignalProto(const WAJid &to, const MBinBuffer &buf, int &type);
+ MBinBuffer encryptSignalProto(const WAJid &to, const MBinBuffer &buf, int &type);
MBinBuffer encodeSignedIdentity(bool);
void generatePrekeys(int count);
@@ -357,6 +357,7 @@ class WhatsAppProto : public PROTO<WhatsAppProto>
void OnNotifyAny(const WANode &node);
void OnNotifyDevices(const WANode &node);
void OnNotifyEncrypt(const WANode &node);
+ void OnReceiveAck(const WANode &node);
void OnReceiveInfo(const WANode &node);
void OnReceiveMessage(const WANode &node);
void OnReceiveReceipt(const WANode &node);
diff --git a/protocols/WhatsApp/src/signal.cpp b/protocols/WhatsApp/src/signal.cpp
index 07f213d8d5..8240322baf 100644
--- a/protocols/WhatsApp/src/signal.cpp
+++ b/protocols/WhatsApp/src/signal.cpp
@@ -95,6 +95,18 @@ static int decrypt_func(signal_buffer **output,
return SG_SUCCESS;
}
+static int encrypt_func(signal_buffer **output,
+ int /*cipher*/,
+ const uint8_t *key, size_t /*key_len*/,
+ const uint8_t *iv, size_t /*iv_len*/,
+ const uint8_t *ciphertext, size_t ciphertext_len,
+ void * /*user_data*/)
+{
+ MBinBuffer res = aesEncrypt(EVP_aes_256_cbc(), key, iv, ciphertext, ciphertext_len);
+ *output = signal_buffer_create(res.data(), res.length());
+ return SG_SUCCESS;
+}
+
static int contains_session_func(const signal_protocol_address *address, void *user_data)
{
auto *pStore = (MSignalStore *)user_data;
@@ -354,6 +366,7 @@ void MSignalStore::init()
prov.hmac_sha256_cleanup_func = hmac_sha256_cleanup;
prov.random_func = random_func;
prov.decrypt_func = decrypt_func;
+ prov.encrypt_func = encrypt_func;
signal_context_set_crypto_provider(m_pContext, &prov);
// default values calculation
@@ -550,7 +563,7 @@ MBinBuffer MSignalStore::decryptGroupSignalProto(const CMStringA &group, const C
/////////////////////////////////////////////////////////////////////////////////////////
// encryption
-signal_buffer* MSignalStore::encryptSignalProto(const WAJid &to, const MBinBuffer &buf, int &type)
+MBinBuffer MSignalStore::encryptSignalProto(const WAJid &to, const MBinBuffer &buf, int &type)
{
auto *pSession = createSession(to.user, to.device);
@@ -561,7 +574,9 @@ signal_buffer* MSignalStore::encryptSignalProto(const WAJid &to, const MBinBuffe
type = ciphertext_message_get_type(pEncrypted);
- auto *res = ciphertext_message_get_serialized(pEncrypted);
+ MBinBuffer res;
+ auto *encBuf = ciphertext_message_get_serialized(pEncrypted);
+ res.assign(encBuf->data, encBuf->len);
signal_message_destroy((signal_type_base *)pEncrypted);
return res;
}
diff --git a/protocols/WhatsApp/src/utils.cpp b/protocols/WhatsApp/src/utils.cpp
index 7210c2e5d0..dd59f5d1bf 100644
--- a/protocols/WhatsApp/src/utils.cpp
+++ b/protocols/WhatsApp/src/utils.cpp
@@ -268,7 +268,20 @@ void generateIV(uint8_t *iv, int &pVar)
pVar++;
}
-MBinBuffer unpad16buf(const MBinBuffer &buf)
+/////////////////////////////////////////////////////////////////////////////////////////
+// Padding
+
+void padBuffer16(MBinBuffer &buf)
+{
+ uint8_t c = buf.length() % 16;
+ if (c == 0)
+ c = 16;
+
+ for (uint8_t i = 0; i < c; i++)
+ buf.append(&c, 1);
+}
+
+MBinBuffer unpadBuffer16(const MBinBuffer &buf)
{
size_t len = buf.length();
auto p = buf.data() + len - 1;
diff --git a/protocols/WhatsApp/src/utils.h b/protocols/WhatsApp/src/utils.h
index e883d5617f..75b60767b7 100644
--- a/protocols/WhatsApp/src/utils.h
+++ b/protocols/WhatsApp/src/utils.h
@@ -205,7 +205,8 @@ CMStringA directPath2url(const char *pszDirectPath);
std::string decodeBinStr(const std::string &buf);
MBinBuffer decodeBufStr(const std::string &buf);
-MBinBuffer unpad16buf(const MBinBuffer &buf);
+void padBuffer16(MBinBuffer &buf);
+MBinBuffer unpadBuffer16(const MBinBuffer &buf);
MBinBuffer aesDecrypt(
const EVP_CIPHER *cipher,
@@ -214,6 +215,13 @@ MBinBuffer aesDecrypt(
const void *data, size_t dataLen,
const void *additionalData = 0, size_t additionalLen = 0);
+MBinBuffer aesEncrypt(
+ const EVP_CIPHER *cipher,
+ const uint8_t *key,
+ const uint8_t *iv,
+ const void *data, size_t dataLen,
+ const void *additionalData = 0, size_t additionalLen = 0);
+
uint32_t decodeBigEndian(const ProtobufCBinaryData &buf);
std::string encodeBigEndian(uint32_t num, size_t len = sizeof(uint32_t));