baptx

whatsapp_web_decrypt_init.py

Jun 30th, 2021 (edited)
94
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. # To use this version, you need to get data before QR code generation (less convenient than the other script whatsapp_web_decrypt_encrypt.py)
  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 curve25519
  16. import hmac
  17. import hashlib
  18. from Crypto.Cipher import AES
  19. from whatsapp_binary_reader import whatsappReadBinary
  20.  
  21. # JSON key "secret" found with the WebSocket inspector in the network monitor of a web browser after QR code scan
  22. qr_code_secret = "XXX"
  23. # found with a breakpoint on the line "keyPair: t" (without quotes) in the file bootstrap_qr.*.js and a watcher "new Uint8Array(t.privKey)" (without quotes)
  24. priv_key_list = [X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X]
  25. # found with a breakpoint on the line "keyPair: t" (without quotes) in the file bootstrap_qr.*.js and a watcher "new Uint8Array(t.pubKey)" (without quotes)
  26. pub_key_list = [X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X]
  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. message = b'XXX'
  29.  
  30. def hmac_sha256(key, sign):
  31.     return hmac.new(key, sign, hashlib.sha256).digest()
  32.  
  33. def HKDF(key, length, app_info=""):
  34.     key = hmac_sha256("\0" * 32, key)
  35.     key_stream = ""
  36.     key_block = ""
  37.     block_index = 1
  38.     while len(key_stream) < length:
  39.         key_block = hmac.new(key, msg=key_block + app_info + chr(block_index), digestmod=hashlib.sha256).digest()
  40.         block_index += 1
  41.         key_stream += key_block
  42.     return key_stream[:length]
  43.  
  44. def aes_decrypt(key, ciphertext):
  45.     iv = ciphertext[:AES.block_size]
  46.     cipher = AES.new(key, AES.MODE_CBC, iv)
  47.     plaintext = cipher.decrypt(ciphertext[AES.block_size:])
  48.     return aes_unpad(plaintext)
  49.  
  50. def aes_unpad(s):
  51.     return s[:-ord(s[len(s) - 1:])]
  52.  
  53. secret = base64.b64decode(qr_code_secret)
  54.  
  55. private_key = curve25519.Private("".join([chr(x) for x in priv_key_list]))
  56.  
  57. public_key = private_key.get_public()
  58.  
  59. assert (public_key.serialize() == "".join([chr(x) for x in pub_key_list]))
  60.  
  61. shared_secret = private_key.get_shared_key(curve25519.Public(secret[:32]), lambda key: key)
  62. shared_secret_ex = HKDF(shared_secret, 80)
  63. check_hmac = hmac_sha256(shared_secret_ex[32:64], secret[:32] + secret[64:])
  64. if check_hmac != secret[32:64]:
  65.     raise ValueError("hmac mismatch")
  66. key_decrypted = aes_decrypt(shared_secret_ex[:32], shared_secret_ex[64:] + secret[64:])
  67. aes_key = key_decrypted[:32]
  68. mac_key = key_decrypted[32:64]
  69.  
  70. message_parts = message.split(",", 1)
  71. content = message_parts[1]
  72.  
  73. decrypted_content = aes_decrypt(aes_key, content[32:])
  74.  
  75. processedData = whatsappReadBinary(decrypted_content, True)
  76. print(processedData)
  77.  
RAW Paste Data