This repository has been archived on 2025-04-28. You can view files and clone it, but cannot push or open issues or pull requests.
Files
Blue-Archive---Asset-Downlo…/lib/TableEncryptionService.py
2023-04-03 09:35:47 +08:00

105 lines
3.0 KiB
Python

from typing import Union
from struct import Struct
from . import XXHashService
from .MersenneTwister import MersenneTwister
from base64 import b64decode, b64encode
# from itertools import cycle
from Crypto.Util.strxor import strxor, strxor_c
uint32 = Struct("<I")
uint64 = Struct("<Q")
int32 = Struct("<i")
int64 = Struct("<q")
float32 = Struct("<f")
float64 = Struct("<d")
def CreateKey(name: str) -> bytes: # 0x02AAE200-0x02AAE288
# v3 = XXHashService_CalculateHash(name, 0LL);
seed = XXHashService.CalculateHash(name)
# v4 = sub_1996DC4(MersenneTwister__TypeInfo);
# MersenneTwister__ctor_1(v4, v3, 0LL);
return MersenneTwister(seed).NextBytes(8)
def XOR(name: str, data: bytes) -> bytes:
seed = XXHashService.CalculateHash(name)
twister = MersenneTwister(seed)
key = twister.NextBytes(len(data))
if len(data) >= 1:
data = _XOR(data, key)
return data
def _XOR(value: bytes, key: bytes) -> bytes:
# return bytes(x ^ y for x, y in zip(value, key))
if len(value) == len(key):
return strxor(value, key)
elif len(value) < len(key):
return strxor(value, key[: len(value)])
else:
return b"".join(
strxor(value[i : i + len(key)], key) for i in range(0, len(value) - len(key) + 1, len(key))
) + strxor(
value[(len(value) - (len(value) % len(key))) :],
key[: len(value) % len(key)],
)
def _XOR_Struct(value: Union[int, float], key: bytes, struct: str) -> Union[int, float]:
return struct.unpack(_XOR(struct.pack(value), key))[0]
def ConvertInt(value: int, key: bytes) -> int:
return _XOR_Struct(value, key, int32) if value else 0
def ConvertLong(value: int, key: bytes) -> int:
return _XOR_Struct(value, key, int64) if value else 0
def ConvertUInt(value: int, key: bytes) -> int:
return _XOR_Struct(value, key, uint32) if value else 0
def ConvertULong(value: int, key: bytes) -> int:
return _XOR_Struct(value, key, uint64) if value else 0
def ConvertFloat(value: float, key: bytes) -> float:
return ConvertInt(int(value), key) * 0.00001 if value else 0.0
def ConvertDouble(value: float, key: bytes) -> float:
return ConvertLong(int(value), key) * 0.00001 if value else 0.0
def EncryptFloat(value: float, key: bytes) -> float:
return ConvertInt(int(value * 100000), key) if value else 0.0
def EncryptDouble(value: str, key: bytes) -> str:
return ConvertLong(int(value * 100000), key) if value else 0.0
def ConvertString(value: str, key: bytes) -> str:
if not value:
return ""
# the animator table contain strings that are not base64 encoded
try:
raw = b64decode(value)
return _XOR(raw, key).decode("utf16")
except:
return value.decode("utf8")
def EncryptString(value: str, key: bytes) -> str:
if not value or len(value) < 8:
return value.encode() if value else b""
raw = value.encode("utf16")
return b64encode(_XOR(raw, key)).decode()
# return b64encode(bytes(r ^ k for r, k in zip(raw, cycle(key))))