Files
Fallout-Shelter-Save-Editor/test_decryption.py
2025-08-05 04:54:50 +00:00

98 lines
4.3 KiB
Python

#!/usr/bin/env python3
"""
Test script to verify Fallout Shelter save decryption
"""
import base64
import json
from Crypto.Cipher import AES
from Crypto.Util.Padding import unpad
def test_decryption():
"""Test the decryption with the Vault1.sav file."""
# Fallout Shelter encryption constants
AES_KEY = bytes([
(2815074099 >> 24) & 0xFF, (2815074099 >> 16) & 0xFF, (2815074099 >> 8) & 0xFF, 2815074099 & 0xFF,
(1725469378 >> 24) & 0xFF, (1725469378 >> 16) & 0xFF, (1725469378 >> 8) & 0xFF, 1725469378 & 0xFF,
(4039046167 >> 24) & 0xFF, (4039046167 >> 16) & 0xFF, (4039046167 >> 8) & 0xFF, 4039046167 & 0xFF,
(874293617 >> 24) & 0xFF, (874293617 >> 16) & 0xFF, (874293617 >> 8) & 0xFF, 874293617 & 0xFF,
(3063605751 >> 24) & 0xFF, (3063605751 >> 16) & 0xFF, (3063605751 >> 8) & 0xFF, 3063605751 & 0xFF,
(3133984764 >> 24) & 0xFF, (3133984764 >> 16) & 0xFF, (3133984764 >> 8) & 0xFF, 3133984764 & 0xFF,
(4097598161 >> 24) & 0xFF, (4097598161 >> 16) & 0xFF, (4097598161 >> 8) & 0xFF, 4097598161 & 0xFF,
(3620741625 >> 24) & 0xFF, (3620741625 >> 16) & 0xFF, (3620741625 >> 8) & 0xFF, 3620741625 & 0xFF
])
AES_IV = bytes.fromhex("7475383967656A693334307438397532")
try:
# Read the save file
with open("Vault1.sav", "rb") as f:
raw_data = f.read()
print(f"Raw file size: {len(raw_data)} bytes")
print(f"First 50 bytes (hex): {raw_data[:50].hex()}")
# Decode base64
try:
decoded_data = base64.b64decode(raw_data)
print(f"Decoded size: {len(decoded_data)} bytes")
print(f"First 50 bytes of decoded (hex): {decoded_data[:50].hex()}")
except Exception as e:
print(f"Base64 decode failed: {e}")
return
# Decrypt using AES-CBC
try:
cipher = AES.new(AES_KEY, AES.MODE_CBC, AES_IV)
decrypted_data = cipher.decrypt(decoded_data)
print(f"Decrypted size: {len(decrypted_data)} bytes")
# Try to remove padding
try:
unpadded_data = unpad(decrypted_data, AES.block_size)
print(f"Unpadded size: {len(unpadded_data)} bytes")
except ValueError as e:
print(f"Unpadding failed: {e}")
# Try without unpadding
unpadded_data = decrypted_data.rstrip(b'\x00')
print(f"Manual padding removal size: {len(unpadded_data)} bytes")
# Try to decode as UTF-8
try:
json_str = unpadded_data.decode('utf-8')
print(f"UTF-8 decode successful, length: {len(json_str)}")
print(f"First 200 characters: {json_str[:200]}")
# Try to parse as JSON
try:
save_data = json.loads(json_str)
print("JSON parsing successful!")
print(f"Top-level keys: {list(save_data.keys()) if isinstance(save_data, dict) else 'Not a dict'}")
# Save pretty-printed JSON for inspection
with open("decrypted_save.json", "w") as f:
json.dump(save_data, f, indent=2)
print("Decrypted save written to decrypted_save.json")
except json.JSONDecodeError as e:
print(f"JSON parsing failed: {e}")
print("Saving raw decrypted text for inspection...")
with open("decrypted_raw.txt", "w", encoding='utf-8', errors='ignore') as f:
f.write(json_str)
except UnicodeDecodeError as e:
print(f"UTF-8 decode failed: {e}")
print("Saving raw decrypted bytes for inspection...")
with open("decrypted_raw.bin", "wb") as f:
f.write(unpadded_data)
except Exception as e:
print(f"AES decryption failed: {e}")
except FileNotFoundError:
print("Vault1.sav not found in current directory")
except Exception as e:
print(f"Unexpected error: {e}")
if __name__ == "__main__":
test_decryption()