Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #!/usr/bin/env python
- #coding=utf-8
- # Decrypt sent and received WebSocket messages from WhatsApp Web
- # Version using data from local storage (no need for WebSocket secret or private / public key unlike the other script whatsapp_web_decrypt_init.py since local storage data is derived from it)
- # Only works with Python 2 (you need to install missing packages with a command like python2 -m pip install packagename)
- # Remember when sharing scripts / hacks or findings: "the quieter you become, the more you are able to hear"
- # https://i.blackhat.com/USA-19/Wednesday/us-19-Zaikin-Reverse-Engineering-WhatsApp-Encryption-For-Chat-Manipulation-And-More.pdf
- # https://github.com/romanzaikin/BurpExtension-WhatsApp-Decryption-CheckPoint
- # https://stackoverflow.com/questions/66905708/how-to-decrypt-sent-binary-message-by-whatsapp-web/67226952
- # Dependencies: https://github.com/sigalor/whatsapp-web-reveng/tree/master/backend
- import base64
- import hmac
- import hashlib
- from Crypto.Cipher import AES
- from whatsapp_binary_reader import whatsappReadBinary
- from whatsapp_binary_writer import whatsappWriteBinary
- import os
- # Replace with the value of the JSON key encKey, from the localStorage item WASecretBundle, for example with Firefox Developer Tools
- encKey = "XXX"
- # Replace with the value of the JSON key macKey, from the localStorage item WASecretBundle
- macKey = "XXX"
- # Replace with a WebSocket message copied using a tool like mitmdump from mitmproxy (copying the message with the WebSocket inspector in the network monitor of a web browser like Firefox will fail)
- sent = False # set to True if sent message
- message = b'XXX'
- def decryptMessage(message):
- global messageSplit
- messageSplit = message.split(",", 1)
- content = messageSplit[1]
- if sent:
- # for sent messages (remove first 2 bytes)
- decryptedMessage = decryptBinary(content[2:])
- else:
- decryptedMessage = decryptBinary(content)
- return decryptedMessage
- def decryptBinary(message):
- hashHMAC = HmacSha256(macKey, message[32:])
- if hashHMAC != message[:32]:
- raise ValueError("Hmac mismatch")
- decryptedData = AESDecrypt(encKey, message[32:])
- processedData = whatsappReadBinary(decryptedData, True)
- return processedData
- def encryptMessage(message):
- global messageSplit
- if sent:
- encryptedMessage = bytes(messageSplit[0] + "," + to_bytes(16, 1) + bytearray([0x80]) + encryptBinary(message))
- else:
- encryptedMessage = messageSplit[0] + "," + encryptBinary(message)
- return encryptedMessage
- def encryptBinary(message):
- processedData = whatsappWriteBinary(message)
- enc = AESEncrypt(encKey, processedData)
- encryptedData = HmacSha256(macKey, enc) + enc; # this may need padding to 64 byte boundary
- return encryptedData
- def HmacSha256(key, sign):
- return hmac.new(key, sign, hashlib.sha256).digest()
- # from https://stackoverflow.com/a/20868265
- def AESDecrypt(key, ciphertext):
- iv = ciphertext[:AES.block_size]
- cipher = AES.new(key, AES.MODE_CBC, iv)
- plaintext = cipher.decrypt(ciphertext[AES.block_size:])
- return AESUnpad(plaintext)
- def AESUnpad(s):
- return s[:-ord(s[len(s)-1:])];
- # like "AESPad"/"AESUnpad" from https://stackoverflow.com/a/21928790
- def AESEncrypt(key, plaintext):
- plaintext = AESPad(plaintext);
- iv = os.urandom(AES.block_size);
- cipher = AES.new(key, AES.MODE_CBC, iv);
- return iv + cipher.encrypt(plaintext);
- def AESPad(s):
- bs = AES.block_size;
- return s + (bs - len(s) % bs) * chr(bs - len(s) % bs);
- def to_bytes(n, length, endianess='big'):
- h = '%x' % n
- s = ('0'*(len(h) % 2) + h).zfill(length*2).decode('hex')
- return s if endianess == 'big' else s[::-1]
- encKey = base64.b64decode(encKey)
- macKey = base64.b64decode(macKey)
- #print(message)
- decryptedMessage = decryptMessage(message)
- print(decryptedMessage)
- #encryptedMessage = encryptMessage(decryptedMessage)
- #print(encryptedMessage)
- #print(decryptMessage(encryptedMessage))
Add Comment
Please, Sign In to add comment