Skip to content

xpr_utils

korobka.balances.xpr204.xpr_utils ¤

Utils for XPR204.

Functions:¤

decrypt_session_id(password, encrypted_session_id_base64, salt, salt_format='base64') ¤

Decrypt the Base64-encoded session ID.

Algorithms used: - PBKDF2-HMAC-SHA1 with 1000 iterations to derive a 32-byte key - AES-256 in ECB mode with PKCS7 padding

Source code in korobka/balances/xpr204/xpr_utils.py
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
def decrypt_session_id(
    password: str,
    encrypted_session_id_base64: str,
    salt: str | bytes,
    salt_format: Literal["base64", "hex", "ascii"] = "base64",
) -> str:
    """Decrypt the Base64-encoded session ID.

    Algorithms used:
    - PBKDF2-HMAC-SHA1 with 1000 iterations to derive a 32-byte key
    - AES-256 in ECB mode with PKCS7 padding
    """
    if isinstance(salt, str):
        salt_bytes = _parse_salt(salt, salt_format)
    else:
        salt_bytes = salt
    if not password or not encrypted_session_id_base64 or not salt_bytes:
        raise ValueError("Password, encrypted session ID, and salt are required.")

    # Derive key (equivalent to C# Rfc2898DeriveBytes with 1000 iters, SHA1)
    kdf = PBKDF2HMAC(
        algorithm=hashes.SHA1(),
        length=32,
        salt=salt_bytes,
        iterations=1000,
        backend=default_backend(),
    )
    key = kdf.derive(password.encode("utf-8"))

    # AES-256-ECB decrypt
    cipher = Cipher(algorithms.AES(key), modes.ECB(), backend=default_backend())
    decryptor = cipher.decryptor()
    ciphertext = b64decode(encrypted_session_id_base64)
    padded_plain = decryptor.update(ciphertext) + decryptor.finalize()

    # Remove PKCS7 padding
    unpadder = padding.PKCS7(128).unpadder()
    plain = unpadder.update(padded_plain) + unpadder.finalize()
    return plain.decode("utf-8")