#!/usr/bin/env python3
"""
Разбор strADPassword из tblSMCompanyPreference (2610BERRYOILUAP02).
Значение: nflhG^.z,76iMa
Гипотезы: (1) plaintext, (2) C# Security.Encrypt base64+AES, (3) иной.
C# Decrypt: FromBase64String -> AES-CBC, Key/IV = PBKDF2("MHCVNH57HR98UZNB", salt="Ivan Medvedev", 100 iters), Key 32B, IV 16B, plaintext UTF-16LE.
"""
import base64, binascii, string
from hashlib import pbkdf2_hmac

VAL = "nflhG^.z,76iMa"
KEY = b"MHCVNH57HR98UZNB"
SALT = bytes([0x49,0x76,0x61,0x6e,0x20,0x4d,0x65,0x64,0x76,0x65,0x64,0x65,0x76])  # "Ivan Medvedev"

print(f"Значение: {VAL!r}  (len={len(VAL)})")

# 1. base64?
b64chars = set(string.ascii_letters + string.digits + "+/=")
is_b64_charset = set(VAL) <= b64chars
print(f"\n[1] Base64-charset? {is_b64_charset}  (не-b64 символы: {sorted(set(VAL)-b64chars)})")
try:
    dec = base64.b64decode(VAL, validate=True)
    print(f"    строгий b64decode: OK, {len(dec)} байт")
except (binascii.Error, ValueError) as e:
    print(f"    строгий b64decode: ПАДАЕТ ({e}) -> НЕ base64")

# 2. hex (0x...)?
print(f"\n[2] Hex-формат (0x..)? {VAL.lower().startswith('0x')}")

# 3. C# AES decrypt (если бы было base64) — пробуем на pad-вариантах, чтобы убедиться что метод не подходит
def cs_decrypt(b64_text):
    raw = base64.b64decode(b64_text)
    kdf = pbkdf2_hmac("sha1", KEY, SALT, 100)  # Rfc2898DeriveBytes default = SHA1, 100 iters
    # pdb.GetBytes(32) then GetBytes(16): continuous stream
    aes_key = kdf[:32]
    # NOTE: .NET Rfc2898 continues the same stream; emulate: derive 48 bytes
    kdf48 = pbkdf2_hmac("sha1", KEY, SALT, 100, dklen=48)
    aes_key = kdf48[:32]; aes_iv = kdf48[32:48]
    from Crypto.Cipher import AES
    c = AES.new(aes_key, AES.MODE_CBC, aes_iv)
    pt = c.decrypt(raw)
    pad = pt[-1]
    pt = pt[:-pad] if 1 <= pad <= 16 else pt
    return pt.decode("utf-16-le", errors="replace")

try:
    from Crypto.Cipher import AES  # noqa
    have_crypto = True
except Exception:
    have_crypto = False
print(f"\n[3] pycryptodome доступен: {have_crypto}")
if have_crypto:
    for variant in [VAL, VAL + "==", VAL.replace("^","x").replace(",","y")]:
        try:
            r = cs_decrypt(variant)
            print(f"    decrypt({variant!r}) -> {r!r}")
        except Exception as e:
            print(f"    decrypt({variant!r}) -> ошибка: {e}")

# 4. Вывод: если не base64 и не hex -> plaintext
print("\n[4] ВЫВОД:")
if not is_b64_charset:
    print("    Значение НЕ base64 (содержит ^ , .) -> C# Security.Encrypt его НЕ производил")
    print("    -> strADPassword хранится как PLAINTEXT (сырой пароль AD)")
    print(f"    Plaintext AD password = {VAL}")
else:
    print("    base64-подобно — нужен decrypt")
