From e9a0d8fd4b1ffc40453054816a617b4e70d7138d Mon Sep 17 00:00:00 2001 From: Alexander Weidinger Date: Tue, 12 Jun 2018 03:00:28 +0200 Subject: [PATCH] Add a script to decrypt a Signal-Desktop backup --- SignalDesktopDecrypt.py | 56 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 56 insertions(+) create mode 100755 SignalDesktopDecrypt.py diff --git a/SignalDesktopDecrypt.py b/SignalDesktopDecrypt.py new file mode 100755 index 0000000..d40182d --- /dev/null +++ b/SignalDesktopDecrypt.py @@ -0,0 +1,56 @@ +#!/usr/bin/env python3 +import hashlib +from Crypto.Cipher import AES +from Crypto.Util import Padding +from Crypto.Hash import HMAC, SHA256 +import sys +IV_LENGTH = 16 +NONCE_LENGTH = 16 +MAC_LENGTH = 16 + +FORMAT_STRING = 'window.Signal.Backup.exportToDirectory(\'{0}\', {{\'key\':new Uint8Array({1})}});' + +def read_file(path): + with open(path, 'rb') as fh: + return fh.read() + +def decrypt(cipherkey, iv, ciphertext): + cipher = AES.new(cipherkey, AES.MODE_CBC, iv) + return Padding.unpad(cipher.decrypt(ciphertext), AES.block_size) + +def generate_cipherkey(key, nonce): + h = HMAC.new(key, digestmod=SHA256) + h.update(nonce) + return h.digest() + +def generate_key(password): + m = hashlib.sha256() + m.update(password) + return m.digest() + +def main(): + password = input('Password: ') + key = generate_key(password.encode('utf-8')) + + # generate string to be pasted in Signal-Desktop + if len(sys.argv) == 1: + print(FORMAT_STRING.format('/tmp/signal/', [elem for elem in key])) + return + + # read encrypted file from disk + data = read_file(sys.argv[1]) + + # crypto foo + iv = bytearray(IV_LENGTH) # IV is just 16 zeros + + nonce = data[:NONCE_LENGTH] + ciphertext = data[NONCE_LENGTH:-MAC_LENGTH] + + cipherkey = generate_cipherkey(key, nonce) + + # save decrypted file to 'decrypted' + with open('decrypted', 'wb') as fh: + fh.write(decrypt(cipherkey, iv, ciphertext)) + +if __name__ == '__main__': + main()