from __future__ import annotations import base64 import hashlib import struct import socket import time from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes from cryptography.hazmat.primitives import padding as sym_padding def verify_signature(token: str, timestamp: str, nonce: str, signature: str) -> bool: params = sorted([token, timestamp, nonce]) sha1 = hashlib.sha1("".join(params).encode()).hexdigest() return sha1 == signature def decrypt_message( encrypted_msg: str, encoding_aes_key: str, ) -> tuple[str, str]: key = base64.b64decode(encoding_aes_key + "=") ciphertext = base64.b64decode(encrypted_msg) cipher = Cipher(algorithms.AES(key), modes.CBC(key[:16])) decryptor = cipher.decryptor() plaintext = decryptor.update(ciphertext) + decryptor.finalize() pad = plaintext[-1] plaintext = plaintext[:-pad] content_len = socket.ntohl(struct.unpack("I", plaintext[16:20])[0]) content = plaintext[20 : 20 + content_len].decode("utf-8") receive_id = plaintext[20 + content_len :].decode("utf-8") return content, receive_id def encrypt_message( content: str, encoding_aes_key: str, app_id: str, ) -> str: key = base64.b64decode(encoding_aes_key + "=") random_bytes = struct.pack("I", int(time.time())) content_bytes = content.encode("utf-8") app_id_bytes = app_id.encode("utf-8") msg_len = struct.pack("!I", len(content_bytes)) raw = random_bytes + msg_len + content_bytes + app_id_bytes padder = sym_padding.PKCS7(128).padder() padded = padder.update(raw) + padder.finalize() cipher = Cipher(algorithms.AES(key), modes.CBC(key[:16])) encryptor = cipher.encryptor() ciphertext = encryptor.update(padded) + encryptor.finalize() return base64.b64encode(ciphertext).decode() def verify_url_signature(token: str, timestamp: str, nonce: str, echostr: str, signature: str) -> tuple[bool, str]: if not verify_signature(token, timestamp, nonce, signature): return False, "" key = base64.b64decode(echostr) return True, key.decode("utf-8")