#!/usr/bin/env python """ Faisanet MIB API decryption tool. Usage: ./decrypt.py ./decrypt.py --key ./decrypt.py --smod """ import sys import json import base64 import hashlib import argparse from urllib.parse import unquote try: from Crypto.Cipher import Blowfish from Crypto.Util.Padding import unpad except ImportError: print("Missing dependency. Run: pip install pycryptodome", file=sys.stderr) sys.exit(1) DEFAULT_KEY = '8M3L9SBF1AC4FRE56788M3L9SBF1AC4FRE5678' # Hardcoded DH parameters from app # NOTE: the variable names in the app's source are misleading — # A_VALUE is the exponent (client private key), the shorter number # P_VALUE is the prime modulus, the longer number A_VALUE = 1563516802667282387226490351799736881442299778484610378722158765594241028592123324764949712696577 P_VALUE = 2410312426921032588552076022197566074856950548502459942654116941958108831682612228890093858261341614673227141477904012196503648957050582631942730706805009223062734745341073406696246014589361659774041027169249453200378729434170325843778659198143763193776859869524088940195577346119843545301547043747207749969763750084308926339295559968882457872412993810129130294592999947926365264059284647209730384947211681434464714438488520940127459844288859336526896320919633919 def derive_session_key(smod: int) -> str: shared_secret = pow(smod, A_VALUE, P_VALUE) sha256_hex = hashlib.sha256(str(shared_secret).encode()).hexdigest().upper() return base64.b64encode(bytes.fromhex(sha256_hex)).decode() def decrypt(ciphertext: str, key: str) -> str: # Strip URL encoding if present ciphertext = unquote(ciphertext).strip() key_bytes = key.encode('latin-1') ct_bytes = base64.b64decode(ciphertext) cipher = Blowfish.new(key_bytes, Blowfish.MODE_ECB) plaintext = unpad(cipher.decrypt(ct_bytes), Blowfish.block_size) return plaintext.decode('utf-8') def main(): parser = argparse.ArgumentParser(description='Decrypt Faisanet MIB API payloads') parser.add_argument('ciphertext', help='Base64 (or URL-encoded) encrypted payload') parser.add_argument('--key', default=None, help='Blowfish key (default: hardcoded DEFAULT_KEY)') parser.add_argument('--smod', default=None, help='Server DH public key (decimal) to derive session key') args = parser.parse_args() if args.smod: key = derive_session_key(int(args.smod)) print(f"[derived session key] {key}", file=sys.stderr) elif args.key: key = args.key else: key = DEFAULT_KEY print(f"[using DEFAULT_KEY]", file=sys.stderr) try: plaintext = decrypt(args.ciphertext, key) except Exception as e: print(f"Decryption failed: {e}", file=sys.stderr) sys.exit(1) # Pretty-print if JSON try: print(json.dumps(json.loads(plaintext), indent=2)) except Exception: print(plaintext) if __name__ == '__main__': main()