summaryrefslogtreecommitdiff
path: root/protocols/WhatsApp
diff options
context:
space:
mode:
authorGeorge Hazan <ghazan@miranda.im>2022-11-17 18:38:47 +0300
committerGeorge Hazan <ghazan@miranda.im>2022-11-17 18:38:47 +0300
commit6d4ab3925c39c234cefd6b6145eb98c169693681 (patch)
tree99d37f497b0f1867d9161e58b92201648db75a7c /protocols/WhatsApp
parentec6ddc5feabf87a067ea22bea943befb169a8684 (diff)
WhatsApp: fix for reading own keys
Diffstat (limited to 'protocols/WhatsApp')
-rw-r--r--protocols/WhatsApp/src/appsync.cpp2
-rw-r--r--protocols/WhatsApp/src/iq.cpp20
-rw-r--r--protocols/WhatsApp/src/message.cpp3
-rw-r--r--protocols/WhatsApp/src/proto.h4
-rw-r--r--protocols/WhatsApp/src/signal.cpp53
-rw-r--r--protocols/WhatsApp/src/utils.cpp6
-rw-r--r--protocols/WhatsApp/src/utils.h10
-rw-r--r--protocols/WhatsApp/src/wanode.cpp24
8 files changed, 106 insertions, 16 deletions
diff --git a/protocols/WhatsApp/src/appsync.cpp b/protocols/WhatsApp/src/appsync.cpp
index 1a0d1b2191..4209160b79 100644
--- a/protocols/WhatsApp/src/appsync.cpp
+++ b/protocols/WhatsApp/src/appsync.cpp
@@ -308,8 +308,8 @@ void WhatsAppProto::ProcessHistorySync(const Wa__HistorySync *pSync)
case WA__HISTORY_SYNC__HISTORY_SYNC_TYPE__INITIAL_STATUS_V3:
for (int i = 0; i < pSync->n_statusv3messages; i++) {
- auto *pStatus = pSync->statusv3messages[i];
// TODO
+ // auto *pStatus = pSync->statusv3messages[i];
}
break;
}
diff --git a/protocols/WhatsApp/src/iq.cpp b/protocols/WhatsApp/src/iq.cpp
index 3c0cd8c64f..2f8b7fb3d6 100644
--- a/protocols/WhatsApp/src/iq.cpp
+++ b/protocols/WhatsApp/src/iq.cpp
@@ -82,6 +82,16 @@ void WhatsAppProto::OnIqDoNothing(const WANode&)
/////////////////////////////////////////////////////////////////////////////////////////
+void WhatsAppProto::OnIqGetKeys(const WANode &node)
+{
+ if (auto *pList = node.getChild("list"))
+ for (auto &it : pList->getChildren())
+ if (it->title == "user")
+ m_signalStore.injectSession(it);
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
void WhatsAppProto::OnIqGetUsync(const WANode &node)
{
m_arDevices.destroy();
@@ -92,6 +102,16 @@ void WhatsAppProto::OnIqGetUsync(const WANode &node)
for (auto &it : pList->getChildren())
if (it->title == "device")
m_arDevices.insert(new WAJid(pszJid, it->getAttrInt("id")));
+
+ WANodeIq iq(IQ::GET, "encrypt");
+ auto *pKey = iq.addChild("key");
+ for (auto &it : m_arDevices) {
+ auto blob = getBlob(MSignalSession(it->user, it->device).getSetting());
+ if (blob.isEmpty())
+ pKey->addChild("user")->addAttr("jid", it->toString());
+ }
+ if (pKey->getChildren().getCount() > 0)
+ WSSendNode(iq, &WhatsAppProto::OnIqGetKeys);
}
}
diff --git a/protocols/WhatsApp/src/message.cpp b/protocols/WhatsApp/src/message.cpp
index 78567f355a..3a768961ee 100644
--- a/protocols/WhatsApp/src/message.cpp
+++ b/protocols/WhatsApp/src/message.cpp
@@ -341,6 +341,9 @@ void WhatsAppProto::OnReceiveAck(const WANode &node)
bool WhatsAppProto::CreateMsgParticipant(WANode *pParticipants, const WAJid &jid, const MBinBuffer &orig)
{
+ if (jid.device == (int)getDword(DBKEY_DEVICE_ID))
+ return false;
+
int type = 0;
try {
diff --git a/protocols/WhatsApp/src/proto.h b/protocols/WhatsApp/src/proto.h
index 4f52f0409e..36ecbfcbf9 100644
--- a/protocols/WhatsApp/src/proto.h
+++ b/protocols/WhatsApp/src/proto.h
@@ -169,6 +169,8 @@ class MSignalStore
signal_context *m_pContext;
signal_protocol_store_context *m_pStore;
+ void importPublicKey(ec_public_key **result, MBinBuffer &buf);
+
public:
PROTO_INTERFACE *pProto;
const char *prefix;
@@ -195,6 +197,7 @@ public:
MSignalSession* createSession(const CMStringA &szName, int deviceId);
MSignalSession* getSession(const signal_protocol_address *address);
+ void injectSession(const WANode *pNode);
MBinBuffer decryptSignalProto(const CMStringA &from, const char *pszType, const MBinBuffer &encrypted);
MBinBuffer decryptGroupSignalProto(const CMStringA &from, const CMStringA &author, const MBinBuffer &encrypted);
@@ -350,6 +353,7 @@ class WhatsAppProto : public PROTO<WhatsAppProto>
void OnIqDoNothing(const WANode &node);
void OnIqGcGetAllMetadata(const WANode &node);
void OnIqGetAvatar(const WANode &node);
+ void OnIqGetKeys(const WANode &node);
void OnIqGetUsync(const WANode &node);
void OnIqPairDevice(const WANode &node);
void OnIqPairSuccess(const WANode &node);
diff --git a/protocols/WhatsApp/src/signal.cpp b/protocols/WhatsApp/src/signal.cpp
index 5ad985db27..3da969a722 100644
--- a/protocols/WhatsApp/src/signal.cpp
+++ b/protocols/WhatsApp/src/signal.cpp
@@ -504,7 +504,7 @@ CMStringA MSignalSession::getSetting() const
MSignalSession* MSignalStore::createSession(const CMStringA &szName, int deviceId)
{
- signal_protocol_address tmp = {szName.c_str(), szName.GetLength(), deviceId};
+ signal_protocol_address tmp = {szName.c_str(), (unsigned)szName.GetLength(), deviceId};
auto *pSession = getSession(&tmp);
if (pSession == nullptr) {
pSession = new MSignalSession(szName, deviceId);
@@ -536,6 +536,55 @@ MSignalSession* MSignalStore::getSession(const signal_protocol_address *address)
return pSession;
}
+void MSignalStore::importPublicKey(ec_public_key **result, MBinBuffer &buf)
+{
+ buf.appendBefore("\x05", 1);
+ curve_decode_point(result, buf.data(), buf.length(), m_pContext);
+}
+
+void MSignalStore::injectSession(const WANode *pNode)
+{
+ WAJid jid(pNode->getAttr("jid"));
+ auto *signedKey = pNode->getChild("skey");
+ auto *key = pNode->getChild("key");
+ auto *identity = pNode->getChild("identity");
+ auto *registration = pNode->getChild("registration");
+ if (!signedKey || !key || !identity || !registration) {
+ pProto->debugLogA("Bad key data for %s", jid.toString().c_str());
+ return;
+ }
+
+ signal_protocol_address address = {jid.user.c_str(), (unsigned)jid.user.GetLength(), jid.device};
+
+ session_builder *builder;
+ logError(
+ session_builder_create(&builder, m_pStore, &address, m_pContext),
+ "unable to create session cipher");
+
+ int regId = decodeBigEndian(registration->content);
+ int preKeyId = decodeBigEndian(key->getChild("id")->content);
+ int signedPreKeyId = decodeBigEndian(signedKey->getChild("id")->content);
+
+ ec_public_key *preKeyPub, *signedPreKeyPub, *identityKey;
+ importPublicKey(&preKeyPub, key->getChild("value")->content);
+ importPublicKey(&identityKey, identity->content);
+ importPublicKey(&signedPreKeyPub, signedKey->getChild("value")->content);
+
+ auto &sign = signedKey->getChild("signature")->content;
+
+ session_pre_key_bundle *bundle;
+ logError(
+ session_pre_key_bundle_create(&bundle, regId, jid.device, preKeyId, preKeyPub, signedPreKeyId, signedPreKeyPub, sign.data(), sign.length(), identityKey),
+ "unable to create pre key bundle");
+
+ logError(
+ session_builder_process_pre_key_bundle(builder, bundle),
+ "unable to process pre key bundle");
+
+ session_pre_key_bundle_destroy((signal_type_base*)bundle);
+ session_builder_free(builder);
+}
+
/////////////////////////////////////////////////////////////////////////////////////////
MBinBuffer MSignalStore::decryptSignalProto(const CMStringA &from, const char *pszType, const MBinBuffer &encrypted)
@@ -696,7 +745,7 @@ MBinBuffer MSignalStore::encryptSignalProto(const WAJid &to, const MBinBuffer &b
MBinBuffer res;
auto *encBuf = ciphertext_message_get_serialized(pEncrypted);
res.assign(encBuf->data, encBuf->len);
- signal_message_destroy((signal_type_base *)pEncrypted);
+ SIGNAL_UNREF(pEncrypted);
return res;
}
diff --git a/protocols/WhatsApp/src/utils.cpp b/protocols/WhatsApp/src/utils.cpp
index 9f4d64a4d4..de72fd5b92 100644
--- a/protocols/WhatsApp/src/utils.cpp
+++ b/protocols/WhatsApp/src/utils.cpp
@@ -240,12 +240,12 @@ MBinBuffer decodeBufStr(const std::string &buf)
return res;
}
-uint32_t decodeBigEndian(const ProtobufCBinaryData &buf)
+uint32_t decodeBigEndian(const uint8_t *buf, size_t len)
{
uint32_t ret = 0;
- for (int i = 0; i < buf.len; i++) {
+ for (int i = 0; i < len; i++) {
ret <<= 8;
- ret += buf.data[i];
+ ret += buf[i];
}
return ret;
diff --git a/protocols/WhatsApp/src/utils.h b/protocols/WhatsApp/src/utils.h
index 5eafb39628..37e48793b2 100644
--- a/protocols/WhatsApp/src/utils.h
+++ b/protocols/WhatsApp/src/utils.h
@@ -224,7 +224,15 @@ MBinBuffer aesEncrypt(
const void *data, size_t dataLen,
const void *additionalData = 0, size_t additionalLen = 0);
-uint32_t decodeBigEndian(const ProtobufCBinaryData &buf);
+uint32_t decodeBigEndian(const uint8_t *pData, size_t len);
+
+__forceinline uint32_t decodeBigEndian(const ProtobufCBinaryData &buf) {
+ return decodeBigEndian(buf.data, buf.len);
+}
+__forceinline uint32_t decodeBigEndian(const MBinBuffer &buf) {
+ return decodeBigEndian(buf.data(), buf.length());
+}
+
std::string encodeBigEndian(uint32_t num, size_t len = sizeof(uint32_t));
void generateIV(uint8_t *iv, uint32_t &pVar);
diff --git a/protocols/WhatsApp/src/wanode.cpp b/protocols/WhatsApp/src/wanode.cpp
index 8d5a2ef7f0..f48ceaebd9 100644
--- a/protocols/WhatsApp/src/wanode.cpp
+++ b/protocols/WhatsApp/src/wanode.cpp
@@ -576,17 +576,23 @@ void WAWriter::writeString(const char *str)
auto *pszDelimiter = strchr(str, '@');
if (pszDelimiter) {
- writeByte(JID_PAIR);
+ WAJid jid(str);
+ if (jid.device || jid.agent) {
+ writeByte(AD_JID);
+ writeByte(jid.agent);
+ writeByte(jid.device);
+ writeString(jid.user);
+ }
+ else {
+ writeByte(JID_PAIR);
- if (pszDelimiter == str) // empty jid
- writeByte(LIST_EMPTY);
- else
- writeString(CMStringA(str, int(pszDelimiter - str)));
+ if (jid.user.IsEmpty()) // empty user
+ writeByte(LIST_EMPTY);
+ else
+ writeString(jid.user);
- if (pszDelimiter[1] == 0) // empty jid
- writeByte(LIST_EMPTY);
- else
- writeString(pszDelimiter + 1);
+ writeString(jid.server);
+ }
}
else {
CMStringA buf(str);