summaryrefslogtreecommitdiff
path: root/protocols/WhatsAppWeb/src/utils.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'protocols/WhatsAppWeb/src/utils.cpp')
-rw-r--r--protocols/WhatsAppWeb/src/utils.cpp127
1 files changed, 50 insertions, 77 deletions
diff --git a/protocols/WhatsAppWeb/src/utils.cpp b/protocols/WhatsAppWeb/src/utils.cpp
index fba42e8b8d..73ceb1ea94 100644
--- a/protocols/WhatsAppWeb/src/utils.cpp
+++ b/protocols/WhatsAppWeb/src/utils.cpp
@@ -7,8 +7,6 @@ Copyright © 2019 George Hazan
#include "stdafx.h"
-#define sharedKey(A, B, C) crypto_scalarmult((unsigned char*)A, (const unsigned char*)B, (const unsigned char*)C)
-
WAUser* WhatsAppProto::FindUser(const char *szId)
{
mir_cslock lck(m_csUsers);
@@ -100,28 +98,6 @@ int WhatsAppProto::WSSendNode(const char *pszPrefix, int flags, WANode &node, WA
BYTE iv[16];
Utils_GetRandom(iv, sizeof(iv));
- // allocate the buffer of the same size + 32 bytes for temporary operations
- MBinBuffer enc;
- enc.assign(writer.body.data(), writer.body.length());
- enc.append(mac_key.data(), mac_key.length());
-
- int enc_len = 0, final_len = 0;
- EVP_CIPHER_CTX *ctx = EVP_CIPHER_CTX_new();
- EVP_EncryptInit_ex(ctx, EVP_aes_256_cbc(), NULL, (BYTE *)enc_key.data(), iv);
- EVP_EncryptUpdate(ctx, (BYTE *)enc.data(), &enc_len, (BYTE *)writer.body.data(), (int)writer.body.length());
- EVP_EncryptFinal_ex(ctx, (BYTE *)enc.data() + enc_len, &final_len);
- EVP_CIPHER_CTX_free(ctx);
-
- // build the resulting buffer of the following structure:
- // - packet prefix
- // - 32 bytes of HMAC
- // - 16 bytes of iv
- // - rest of encoded data
-
- BYTE hmac[32];
- unsigned int hmac_len = 32;
- HMAC(EVP_sha256(), mac_key.data(), (int)mac_key.length(), (BYTE *)enc.data(), enc_len, hmac, &hmac_len);
-
int pktId = ++m_iPktNumber;
if (pHandler != nullptr) {
@@ -138,57 +114,19 @@ int WhatsAppProto::WSSendNode(const char *pszPrefix, int flags, WANode &node, WA
MBinBuffer ret;
ret.append(pszPrefix, strlen(pszPrefix));
ret.append(postPrefix, sizeof(postPrefix));
- ret.append(hmac, sizeof(hmac));
- ret.append(iv, sizeof(iv));
- ret.append(enc.data(), enc_len);
WebSocket_SendBinary(m_hServerConn, ret.data(), ret.length());
return pktId;
}
/////////////////////////////////////////////////////////////////////////////////////////
-
-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
- auto *pBuf = (const unsigned char *)buf;
- {
- BYTE iv[16];
- memcpy(iv, pBuf + 32, sizeof(iv));
- res.assign(pBuf + 48, cbSize - 48);
- res.append(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, pBuf + 48, (int)cbSize - 48);
- EVP_DecryptFinal_ex(ctx, (BYTE*)res.data() + dec_len, &final_len);
- EVP_CIPHER_CTX_free(ctx);
- }
- return true;
-}
-
-/////////////////////////////////////////////////////////////////////////////////////////
// WANoise members
static uint8_t intro_header[] = { 87, 65, 6, DICT_VERSION };
static uint8_t noise_init[] = "Noise_XX_25519_AESGCM_SHA256\0\0\0\0";
-WANoise::WANoise()
+WANoise::WANoise(WhatsAppProto *_ppro) :
+ ppro(_ppro)
{
salt.assign(noise_init, 32);
encKey.assign(noise_init, 32);
@@ -229,18 +167,24 @@ void WANoise::deriveKey(const void *pData, size_t cbLen, MBinBuffer &write, MBin
read.assign(out + 32, 32);
}
-void WANoise::mixIntoKey(const void *pData, size_t cbLen)
+void WANoise::mixIntoKey(const void *n, const void *p)
{
- deriveKey(pData, cbLen, salt, encKey);
+ uint8_t tmp[32];
+ crypto_scalarmult((unsigned char *)tmp, (const unsigned char *)n, (const unsigned char *)p);
+
+ deriveKey(tmp, sizeof(tmp), salt, encKey);
decKey.assign(encKey.data(), encKey.length());
readCounter = writeCounter = 0;
}
void WANoise::decrypt(const void *pData, size_t cbLen, MBinBuffer &dest)
{
+ auto &pVar = (bInitFinished) ? readCounter : writeCounter;
+
uint8_t iv[12];
memset(iv, 0, 8);
- memcpy(iv + 8, (bInitFinished) ? &readCounter : &writeCounter, sizeof(int));
+ memcpy(iv + 8, &pVar, sizeof(int));
+ pVar++;
uint8_t outbuf[1024 + EVP_MAX_BLOCK_LENGTH];
@@ -249,7 +193,7 @@ void WANoise::decrypt(const void *pData, size_t cbLen, MBinBuffer &dest)
EVP_DecryptInit_ex(ctx, EVP_aes_256_gcm(), NULL, (BYTE *)decKey.data(), iv);
for (size_t len = 0; len < cbLen; len += 1024) {
size_t portionSize = cbLen - len;
- EVP_DecryptUpdate(ctx, outbuf, &dec_len, (BYTE*)pData + len, min(portionSize, 1024));
+ EVP_DecryptUpdate(ctx, outbuf, &dec_len, (BYTE*)pData + len, (int)min(portionSize, 1024));
if (len == 0)
dest.assign(outbuf, dec_len);
else
@@ -259,6 +203,8 @@ void WANoise::decrypt(const void *pData, size_t cbLen, MBinBuffer &dest)
if (final_len)
dest.append(outbuf, final_len);
EVP_CIPHER_CTX_free(ctx);
+
+ updateHash(pData, cbLen);
}
bool WANoise::decodeFrame(const void *pData, size_t cbLen)
@@ -270,25 +216,29 @@ bool WANoise::decodeFrame(const void *pData, size_t cbLen)
auto &static_ = msg.serverhello().static_();
auto &payload = msg.serverhello().payload();
- uint8_t tmp[32];
-
updateHash(ephemeral.c_str(), ephemeral.size());
-
- sharedKey(tmp, privKey.data(), ephemeral.c_str());
- mixIntoKey(tmp, sizeof(tmp));
+ mixIntoKey(privKey.data(), ephemeral.c_str());
MBinBuffer decryptedStatic, decryptedCert;
decrypt(static_.c_str(), static_.size(), decryptedStatic);
-
- sharedKey(tmp, privKey.data(), decryptedStatic.data());
- mixIntoKey(tmp, sizeof(tmp));
+ mixIntoKey(privKey.data(), decryptedStatic.data());
decrypt(payload.c_str(), payload.size(), decryptedCert);
proto::CertChain cert; cert.ParseFromArray(decryptedCert.data(), (int)decryptedCert.length());
proto::CertChain::NoiseCertificate::Details details; details.ParseFromString(cert.intermediate().details());
- if (details.issuerserial() != 0)
+ if (details.issuerserial() != 0) {
+ ppro->ShutdownSession();
return false;
+ }
+
+ MBinBuffer mainPub, mainPriv;
+ ppro->getBlob(DBKEY_PUB_KEY, mainPub);
+ ppro->getBlob(DBKEY_PRIVATE_KEY, mainPriv);
+
+ MBinBuffer encryptedPub;
+ encrypt(mainPub.data(), mainPub.length(), encryptedPub);
+ mixIntoKey(mainPriv.data(), ephemeral.c_str());
}
return true;
}
@@ -315,7 +265,30 @@ void WANoise::encodeFrame(const void *pData, size_t cbLen, MBinBuffer &res)
void WANoise::encrypt(const void *pData, size_t cbLen, MBinBuffer &dest)
{
+ uint8_t iv[12];
+ memset(iv, 0, 8);
+ memcpy(iv + 8, &writeCounter, sizeof(int));
+ writeCounter++;
+
+ uint8_t outbuf[1024 + 64];
+
+ int enc_len = 0, final_len = 0;
+ EVP_CIPHER_CTX *ctx = EVP_CIPHER_CTX_new();
+ EVP_EncryptInit_ex(ctx, EVP_aes_256_gcm(), NULL, (BYTE *)encKey.data(), iv);
+ for (size_t len = 0; len < cbLen; len += 1024) {
+ size_t portionSize = cbLen - len;
+ EVP_EncryptUpdate(ctx, outbuf, &enc_len, (BYTE *)pData + len, (int)min(portionSize, 1024));
+ if (len == 0)
+ dest.assign(outbuf, enc_len);
+ else
+ dest.append(outbuf, enc_len);
+ }
+ EVP_EncryptFinal_ex(ctx, outbuf, &final_len);
+ if (final_len)
+ dest.append(outbuf, final_len);
+ EVP_CIPHER_CTX_free(ctx);
+ updateHash(dest.data(), dest.length());
}
void WANoise::updateHash(const void *pData, size_t cbLen)