diff options
Diffstat (limited to 'protocols/WhatsAppWeb/src/utils.cpp')
-rw-r--r-- | protocols/WhatsAppWeb/src/utils.cpp | 127 |
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) |