def test_hash_verification(self): data = b"Test bytes" cyphertext, keys = encrypt_attachment(data) with pytest.raises(EncryptionError): decrypt_attachment(cyphertext, keys["key"]["k"], "Fake hash", keys["iv"])
def test_invalid_iv(self): data = b"Test bytes" cyphertext, keys = encrypt_attachment(data) with pytest.raises(EncryptionError): decrypt_attachment(cyphertext, keys["key"]["k"], keys["hashes"]["sha256"], "Fake iv")
async def test_short_key(self): data, cyphertext, keys = await self._get_data_cypher_keys() with pytest.raises(EncryptionError): decrypt_attachment( cyphertext, unpaddedbase64.encode_base64(b"Fake key", urlsafe=True), keys["hashes"]["sha256"], keys["iv"], )
async def test_hash_verification(self): data, cyphertext, keys = await self._get_data_cypher_keys() with pytest.raises(EncryptionError): decrypt_attachment( cyphertext, keys["key"]["k"], "Fake hash", keys["iv"], )
async def test_invalid_iv(self): data, cyphertext, keys = await self._get_data_cypher_keys() with pytest.raises(EncryptionError): decrypt_attachment( cyphertext, keys["key"]["k"], keys["hashes"]["sha256"], "Fake iv", )
def test_short_key(self): data = b"Test bytes" cyphertext, keys = encrypt_attachment(data) with pytest.raises(EncryptionError): decrypt_attachment( cyphertext, unpaddedbase64.encode_base64(b"Fake key", urlsafe=True), keys["hashes"]["sha256"], keys["iv"])
def main(): parser = argparse.ArgumentParser( description='Download and decrypt matrix attachments') parser.add_argument('url', help='the url of the attachment') parser.add_argument('--plumber', help='program that gets called with the ' 'dowloaded file') args = parser.parse_args() url = urlparse(args.url) query = parse_qs(url.query) if not query["key"] or not query["iv"] or not query["hash"]: print("Missing decryption argument") return -1 key = query["key"][0] iv = query["iv"][0] hash = query["hash"][0] http_url = "https://{}{}".format(url.netloc, url.path) request = requests.get(http_url) if not request.ok: print("Error downloading file") return -2 plumber = args.plumber or "/usr/bin/rifle" plaintext = decrypt_attachment(request.content, key, hash, iv) file_name = save_file(plaintext) subprocess.run([plumber, "{file}".format(file=file_name)]) return 0
def test_encrypt(self): data = b"Test bytes" cyphertext, keys = encrypt_attachment(data) plaintext = decrypt_attachment(cyphertext, keys["key"]["k"], keys["hashes"]["sha256"], keys["iv"]) assert data == plaintext
async def test_short_iv(self): data, cyphertext, keys = await self._get_data_cypher_keys() plaintext = decrypt_attachment( cyphertext, keys["key"]["k"], keys["hashes"]["sha256"], unpaddedbase64.encode_base64(b"F" + b"\x00" * 8), ) assert plaintext != data
def test_fake_key(self): data = b"Test bytes" cyphertext, keys = encrypt_attachment(data) fake_key = Random.new().read(32) plaintext = decrypt_attachment( cyphertext, unpaddedbase64.encode_base64(fake_key, urlsafe=True), keys["hashes"]["sha256"], keys["iv"]) assert plaintext != data
async def test_encrypt(self, data=b"Test bytes", large=False): _, cyphertext, keys = await self._get_data_cypher_keys(data) plaintext = decrypt_attachment( cyphertext, keys["key"]["k"], keys["hashes"]["sha256"], keys["iv"], ) assert plaintext == b"Test bytes" * (16384 if large else 1)
def test_short_iv(self): data = b"Test bytes" cyphertext, keys = encrypt_attachment(data) plaintext = decrypt_attachment( cyphertext, keys["key"]["k"], keys["hashes"]["sha256"], unpaddedbase64.encode_base64(b"F" + b"\x00" * 8), ) assert plaintext != data
async def test_fake_key(self): data, cyphertext, keys = await self._get_data_cypher_keys() fake_key = Random.new().read(32) plaintext = decrypt_attachment( cyphertext, unpaddedbase64.encode_base64(fake_key, urlsafe=True), keys["hashes"]["sha256"], keys["iv"], ) assert plaintext != data
async def _handle_matrix_image( self, sender: 'u.User', message: MediaMessageEventContent) -> Optional[str]: if message.file and decrypt_attachment: data = await self.main_intent.download_media(message.file.url) data = decrypt_attachment(data, message.file.key.key, message.file.hashes.get("sha256"), message.file.iv) elif message.url: data = await self.main_intent.download_media(message.url) else: return None image = await sender.client.upload_image(io.BytesIO(data), filename=message.body) return await sender.send_image(self.gid, image)
async def _handle_matrix_image( self, sender: 'u.User', message: MediaMessageEventContent) -> Optional[str]: if message.file and decrypt_attachment: data = await self.main_intent.download_media(message.file.url) data = decrypt_attachment(data, message.file.key.key, message.file.hashes.get("sha256"), message.file.iv) elif message.url: data = await self.main_intent.download_media(message.url) else: return None mime = message.info.mimetype or magic.from_buffer(data, mime=True) files = await sender._upload([(message.body, data, mime)]) return await sender._send_files(files, thread_id=self.fbid, thread_type=self.fb_type)
def main(): parser = argparse.ArgumentParser( description='Download and decrypt matrix attachments' ) parser.add_argument('url', help='the url of the attachment') parser.add_argument('file', nargs='?', help='save attachment to <file>') parser.add_argument('--plumber', help='program that gets called with the ' 'dowloaded file') args = parser.parse_args() url = urlparse(args.url) query = parse_qs(url.query) if not query["key"] or not query["iv"] or not query["hash"]: print("Missing decryption argument") return -1 key = query["key"][0] iv = query["iv"][0] hash = query["hash"][0] http_url = "https://{}{}".format(url.netloc, url.path) request = requests.get(http_url) if not request.ok: print("Error downloading file") return -2 plumber = args.plumber plaintext = decrypt_attachment(request.content, key, hash, iv) if args.file is None: file_name = save_file(plaintext) if plumber is None: plumber = "xdg-open" else: file_name = args.file open(file_name, "wb").write(plaintext) if plumber is not None: subprocess.run([plumber, file_name]) return 0
async def _handle_matrix_file(self, sender_id: TelegramID, event_id: EventID, space: TelegramID, client: 'MautrixTelegramClient', content: MediaMessageEventContent, reply_to: TelegramID, caption: TextMessageEventContent = None) -> None: mime = content.info.mimetype w, h = content.info.width, content.info.height file_name = content["net.maunium.telegram.internal.filename"] max_image_size = config["bridge.image_as_file_size"] * 1000 ** 2 if config["bridge.parallel_file_transfer"] and content.url: file_handle, file_size = await parallel_transfer_to_telegram(client, self.main_intent, content.url, sender_id) else: if content.file: if not decrypt_attachment: self.log.warning(f"Can't bridge encrypted media event {event_id}:" " matrix-nio not installed") return file = await self.main_intent.download_media(content.file.url) file = decrypt_attachment(file, content.file.key.key, content.file.hashes.get("sha256"), content.file.iv) else: file = await self.main_intent.download_media(content.url) if content.msgtype == MessageType.STICKER: if mime != "image/gif": mime, file, w, h = util.convert_image(file, source_mime=mime, target_type="webp") else: # Remove sticker description file_name = "sticker.gif" file_handle = await client.upload_file(file) file_size = len(file) file_handle.name = file_name attributes = [DocumentAttributeFilename(file_name=file_name)] if w and h: attributes.append(DocumentAttributeImageSize(w, h)) if (mime == "image/png" or mime == "image/jpeg") and file_size < max_image_size: media = InputMediaUploadedPhoto(file_handle) else: media = InputMediaUploadedDocument(file=file_handle, attributes=attributes, mime_type=mime or "application/octet-stream") caption, entities = self._matrix_event_to_entities(caption) if caption else (None, None) async with self.send_lock(sender_id): if await self._matrix_document_edit(client, content, space, caption, media, event_id): return try: response = await client.send_media(self.peer, media, reply_to=reply_to, caption=caption, entities=entities) except (PhotoInvalidDimensionsError, PhotoSaveFileInvalidError, PhotoExtInvalidError): media = InputMediaUploadedDocument(file=media.file, mime_type=mime, attributes=attributes) response = await client.send_media(self.peer, media, reply_to=reply_to, caption=caption, entities=entities) self._add_telegram_message_to_db(event_id, space, 0, response)