3 # conversations_http_downloader - download files uploaded by Conversations
5 # Copyright (C) 2016 Antonio Ospite <ao2@ao2.it>
7 # This program is free software: you can redistribute it and/or modify
8 # it under the terms of the GNU General Public License as published by
9 # the Free Software Foundation, either version 3 of the License, or
10 # (at your option) any later version.
12 # This program is distributed in the hope that it will be useful,
13 # but WITHOUT ANY WARRANTY; without even the implied warranty of
14 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 # GNU General Public License for more details.
17 # You should have received a copy of the GNU General Public License
18 # along with this program. If not, see <http://www.gnu.org/licenses/>.
26 from cryptography.hazmat.backends import default_backend
27 from cryptography.hazmat.primitives.ciphers import algorithms
28 from cryptography.hazmat.primitives.ciphers import Cipher
29 from cryptography.hazmat.primitives.ciphers.modes import GCM
32 # Taken verbatim from python-omemo
33 def aes_decrypt(key, iv, payload):
34 """ Use AES128 GCM with the given key and iv to decrypt the payload. """
37 backend = default_backend()
41 backend=backend).decryptor()
42 return decryptor.update(data) + decryptor.finalize()
45 # Inspired by https://github.com/iNPUTmice/ImageDownloader
46 def decrypt(data, anchor):
47 """ Use the iv an key that Conversations put into the URL anchor. """
48 key_and_iv = bytes.fromhex(anchor)
50 key = key_and_iv[16:48]
51 return aes_decrypt(key, iv, data)
55 print("usage: %s <URL>" % name)
59 if len(sys.argv) != 2:
65 if url.startswith("aesgcm://"):
66 url = "https://" + url[len("aesgcm://"):]
68 parsed_url = urllib.parse.urlparse(url)
69 anchor = parsed_url.fragment
72 response = urllib.request.urlopen(url)
73 data = response.read()
74 except (urllib.error.URLError, urllib.error.HTTPError) as error:
75 sys.stderr.write("Error: %s\n" % error)
78 filename = os.path.basename(parsed_url.path)
79 with open(filename, "xb") as output_file:
81 output_file.write(decrypt(data, anchor))
83 output_file.write(data)
88 if __name__ == "__main__":