diff options
Diffstat (limited to 'protocols')
-rw-r--r-- | protocols/WhatsApp/src/appsync.cpp | 4 | ||||
-rw-r--r-- | protocols/WhatsApp/src/crypt.cpp | 35 | ||||
-rw-r--r-- | protocols/WhatsApp/src/iq.cpp | 1 | ||||
-rw-r--r-- | protocols/WhatsApp/src/message.cpp | 37 | ||||
-rw-r--r-- | protocols/WhatsApp/src/proto.cpp | 29 | ||||
-rw-r--r-- | protocols/WhatsApp/src/proto.h | 7 | ||||
-rw-r--r-- | protocols/WhatsApp/src/signal.cpp | 19 | ||||
-rw-r--r-- | protocols/WhatsApp/src/utils.cpp | 15 | ||||
-rw-r--r-- | protocols/WhatsApp/src/utils.h | 10 |
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)); |