Files
basedbank/docs/mibapi/decrypt.py

81 lines
3.0 KiB
Python
Executable File

#!/usr/bin/env python
"""
Faisanet MIB API decryption tool.
Usage:
./decrypt.py <encrypted_base64>
./decrypt.py <encrypted_base64> --key <blowfish_key>
./decrypt.py <encrypted_base64> --smod <server_dh_public_key>
"""
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()