baptx

whatsapp_web_decrypt_encrypt.py

Jun 22nd, 2021 (edited)
139
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. #!/usr/bin/env python
  2. #coding=utf-8
  3.  
  4. # Decrypt sent and received WebSocket messages from WhatsApp Web
  5. # 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)
  6. # Only works with Python 2 (you need to install missing packages with a command like python2 -m pip install packagename)
  7. # Remember when sharing scripts / hacks or findings: "the quieter you become, the more you are able to hear"
  8.  
  9. # https://i.blackhat.com/USA-19/Wednesday/us-19-Zaikin-Reverse-Engineering-WhatsApp-Encryption-For-Chat-Manipulation-And-More.pdf
  10. # https://github.com/romanzaikin/BurpExtension-WhatsApp-Decryption-CheckPoint
  11. # https://stackoverflow.com/questions/66905708/how-to-decrypt-sent-binary-message-by-whatsapp-web/67226952
  12. # Dependencies: https://github.com/sigalor/whatsapp-web-reveng/tree/master/backend
  13.  
  14. import base64
  15. import hmac
  16. import hashlib
  17. from Crypto.Cipher import AES
  18. from whatsapp_binary_reader import whatsappReadBinary
  19.  
  20. from whatsapp_binary_writer import whatsappWriteBinary
  21. import os
  22.  
  23. # Replace with the value of the JSON key encKey, from the localStorage item WASecretBundle, for example with Firefox Developer Tools
  24. encKey = "XXX"
  25. # Replace with the value of the JSON key macKey, from the localStorage item WASecretBundle
  26. macKey = "XXX"
  27. # 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)
  28. sent = False # set to True if sent message
  29. message = b'XXX'
  30.  
  31. def decryptMessage(message):
  32.     global messageSplit
  33.     messageSplit = message.split(",", 1)
  34.     content = messageSplit[1]
  35.     if sent:
  36.         # for sent messages (remove first 2 bytes)
  37.         decryptedMessage = decryptBinary(content[2:])
  38.     else:
  39.         decryptedMessage = decryptBinary(content)
  40.     return decryptedMessage
  41.  
  42. def decryptBinary(message):
  43.     hashHMAC = HmacSha256(macKey, message[32:])
  44.     if hashHMAC != message[:32]:
  45.       raise ValueError("Hmac mismatch")
  46.     decryptedData = AESDecrypt(encKey, message[32:])
  47.     processedData = whatsappReadBinary(decryptedData, True)
  48.     return processedData
  49.  
  50. def encryptMessage(message):
  51.     global messageSplit
  52.     if sent:
  53.         encryptedMessage = bytes(messageSplit[0] + "," + to_bytes(16, 1) + bytearray([0x80]) + encryptBinary(message))
  54.     else:
  55.         encryptedMessage = messageSplit[0] + "," + encryptBinary(message)
  56.     return encryptedMessage
  57.  
  58. def encryptBinary(message):
  59.     processedData = whatsappWriteBinary(message)
  60.     enc = AESEncrypt(encKey, processedData)
  61.     encryptedData = HmacSha256(macKey, enc) + enc; # this may need padding to 64 byte boundary
  62.     return encryptedData
  63.  
  64. def HmacSha256(key, sign):
  65.     return hmac.new(key, sign, hashlib.sha256).digest()
  66.  
  67. # from https://stackoverflow.com/a/20868265
  68. def AESDecrypt(key, ciphertext):
  69.     iv = ciphertext[:AES.block_size]
  70.     cipher = AES.new(key, AES.MODE_CBC, iv)
  71.     plaintext = cipher.decrypt(ciphertext[AES.block_size:])
  72.     return AESUnpad(plaintext)
  73.  
  74. def AESUnpad(s):
  75.     return s[:-ord(s[len(s)-1:])];
  76.  
  77. # like "AESPad"/"AESUnpad" from https://stackoverflow.com/a/21928790
  78. def AESEncrypt(key, plaintext):
  79.     plaintext = AESPad(plaintext);
  80.     iv = os.urandom(AES.block_size);
  81.     cipher = AES.new(key, AES.MODE_CBC, iv);
  82.     return iv + cipher.encrypt(plaintext);
  83.  
  84. def AESPad(s):
  85.     bs = AES.block_size;
  86.     return s + (bs - len(s) % bs) * chr(bs - len(s) % bs);
  87.  
  88. def to_bytes(n, length, endianess='big'):
  89.     h = '%x' % n
  90.     s = ('0'*(len(h) % 2) + h).zfill(length*2).decode('hex')
  91.     return s if endianess == 'big' else s[::-1]
  92.  
  93. encKey = base64.b64decode(encKey)
  94. macKey = base64.b64decode(macKey)
  95.  
  96. #print(message)
  97.  
  98. decryptedMessage = decryptMessage(message)
  99. print(decryptedMessage)
  100.  
  101. #encryptedMessage = encryptMessage(decryptedMessage)
  102. #print(encryptedMessage)
  103. #print(decryptMessage(encryptedMessage))
  104.  
RAW Paste Data