"""哈希、Base64、对称/非对称加解密（cryptography）、Unix 账户查询（仅 POSIX）。"""

from __future__ import annotations

import base64
import binascii
import hashlib
import hmac
import os
import secrets
from typing import Any

MAX_TEXT = 512_000
MAX_HEX_LEN = 2_000_000  # ~1MB binary
MAX_B64_LEN = 2_000_000

try:
    from cryptography.hazmat.primitives import hashes, serialization
    from cryptography.hazmat.primitives.asymmetric import ec, padding, rsa
    from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes
    from cryptography.hazmat.primitives.ciphers.aead import AESGCM
    from cryptography.hazmat.primitives.kdf.pbkdf2 import PBKDF2HMAC
    from cryptography.hazmat.backends import default_backend

    _CRYPTO_OK = True
    _CRYPTO_ERR: str | None = None
except ImportError as e:  # pragma: no cover
    _CRYPTO_OK = False
    _CRYPTO_ERR = str(e)


def _need_crypto() -> dict[str, Any] | None:
    if not _CRYPTO_OK:
        return {
            "ok": False,
            "error": f"cryptography not available: {_CRYPTO_ERR}; pip install cryptography",
        }
    return None


def _bytes_from_text_or_hex(payload: dict[str, Any], key: str = "text") -> tuple[bytes | None, dict[str, Any] | None]:
    hx = payload.get("hex")
    if hx is not None:
        s = str(hx).strip()
        if len(s) > MAX_HEX_LEN:
            return None, {"ok": False, "error": "hex input too large"}
        try:
            return binascii.unhexlify(s.replace(" ", "")), None
        except binascii.Error as e:
            return None, {"ok": False, "error": f"invalid hex: {e}"}
    t = str(payload.get(key) or "")
    if len(t) > MAX_TEXT:
        return None, {"ok": False, "error": f"{key} exceeds {MAX_TEXT} chars"}
    return t.encode("utf-8"), None


def op_hash(algo: str, payload: dict[str, Any]) -> dict[str, Any]:
    algo = algo.lower().replace("-", "")
    data, err = _bytes_from_text_or_hex(payload)
    if err:
        return err
    assert data is not None
    if algo == "md5":
        d = hashlib.md5(data, usedforsecurity=False).digest()
    elif algo == "sha1":
        d = hashlib.sha1(data, usedforsecurity=False).digest()
    elif algo == "sha256":
        d = hashlib.sha256(data).digest()
    elif algo == "sha512":
        d = hashlib.sha512(data).digest()
    else:
        return {"ok": False, "error": "algorithm must be md5|sha1|sha256|sha512"}
    out_hex = d.hex()
    return {"ok": True, "algorithm": algo, "hex": out_hex, "bytes": len(d)}


def op_hmac_sha256(payload: dict[str, Any]) -> dict[str, Any]:
    msg, err = _bytes_from_text_or_hex(payload, "message")
    if err:
        return err
    assert msg is not None
    key_raw = payload.get("key_hex")
    if key_raw is not None:
        try:
            key = binascii.unhexlify(str(key_raw).replace(" ", ""))
        except binascii.Error as e:
            return {"ok": False, "error": f"key_hex: {e}"}
    else:
        kt = str(payload.get("key_text") or "")
        key = kt.encode("utf-8")
    if not key:
        return {"ok": False, "error": "need key_hex or key_text"}
    d = hmac.new(key, msg, hashlib.sha256).digest()
    return {"ok": True, "hex": d.hex()}


def op_base64_encode(payload: dict[str, Any]) -> dict[str, Any]:
    data, err = _bytes_from_text_or_hex(payload)
    if err:
        return err
    assert data is not None
    b = base64.standard_b64encode(data).decode("ascii")
    return {"ok": True, "base64": b}


def op_base64_decode(payload: dict[str, Any]) -> dict[str, Any]:
    s = str(payload.get("base64") or "").strip()
    if len(s) > MAX_B64_LEN:
        return {"ok": False, "error": "base64 input too large"}
    try:
        raw = base64.standard_b64decode(s)
    except Exception as e:  # noqa: BLE001
        return {"ok": False, "error": f"decode failed: {e}"}
    try:
        text = raw.decode("utf-8")
        return {"ok": True, "text": text, "bytes": len(raw)}
    except UnicodeDecodeError:
        return {"ok": True, "hex": raw.hex(), "bytes": len(raw), "note": "not valid utf-8; hex returned"}


def op_random_hex(payload: dict[str, Any]) -> dict[str, Any]:
    try:
        n = int(payload.get("byte_length", 16))
    except (TypeError, ValueError):
        return {"ok": False, "error": "byte_length must be int"}
    n = max(1, min(256, n))
    return {"ok": True, "hex": secrets.token_hex(n)}


def op_pbkdf2_hmac_sha256(payload: dict[str, Any]) -> dict[str, Any]:
    err = _need_crypto()
    if err:
        return err
    pw = str(payload.get("password") or "").encode("utf-8")
    salt_hex = str(payload.get("salt_hex") or "")
    try:
        salt = binascii.unhexlify(salt_hex.replace(" ", ""))
    except binascii.Error as e:
        return {"ok": False, "error": f"salt_hex: {e}"}
    try:
        it = int(payload.get("iterations", 390_000))
    except (TypeError, ValueError):
        return {"ok": False, "error": "iterations must be int"}
    it = max(10_000, min(5_000_000, it))
    try:
        length = int(payload.get("length_bytes", 32))
    except (TypeError, ValueError):
        return {"ok": False, "error": "length_bytes must be int"}
    length = max(16, min(64, length))
    kdf = PBKDF2HMAC(
        algorithm=hashes.SHA256(),
        length=length,
        salt=salt,
        iterations=it,
        backend=default_backend(),
    )
    dk = kdf.derive(pw)
    return {"ok": True, "hex": dk.hex(), "iterations": it, "length_bytes": length}


def _pkcs7_pad(data: bytes, block: int) -> bytes:
    p = block - (len(data) % block)
    return data + bytes([p]) * p


def _pkcs7_unpad(data: bytes) -> bytes:
    if not data:
        raise ValueError("empty")
    p = data[-1]
    if p < 1 or p > 16:
        raise ValueError("bad padding")
    if data[-p:] != bytes([p]) * p:
        raise ValueError("bad padding")
    return data[:-p]


def op_aes_gcm_encrypt(payload: dict[str, Any]) -> dict[str, Any]:
    err = _need_crypto()
    if err:
        return err
    key_hex = str(payload.get("key_hex") or "")
    try:
        key = binascii.unhexlify(key_hex.replace(" ", ""))
    except binascii.Error as e:
        return {"ok": False, "error": f"key_hex: {e}"}
    if len(key) not in (16, 24, 32):
        return {"ok": False, "error": "AES key must be 16/24/32 bytes (32/48/64 hex chars)"}
    pt, e2 = _bytes_from_text_or_hex(payload)
    if e2:
        return e2
    assert pt is not None
    nonce_hex = str(payload.get("nonce_hex") or "").strip()
    if nonce_hex:
        try:
            nonce = binascii.unhexlify(nonce_hex.replace(" ", ""))
        except binascii.Error as e:
            return {"ok": False, "error": f"nonce_hex: {e}"}
        if len(nonce) != 12:
            return {"ok": False, "error": "GCM nonce must be 12 bytes"}
    else:
        nonce = secrets.token_bytes(12)
    aesgcm = AESGCM(key)
    ad = str(payload.get("associated_data") or "").encode("utf-8")
    ct = aesgcm.encrypt(nonce, pt, ad if ad else None)
    return {
        "ok": True,
        "nonce_hex": nonce.hex(),
        "ciphertext_hex": ct.hex(),
        "associated_data_was_set": bool(ad),
    }


def op_aes_gcm_decrypt(payload: dict[str, Any]) -> dict[str, Any]:
    err = _need_crypto()
    if err:
        return err
    key_hex = str(payload.get("key_hex") or "")
    try:
        key = binascii.unhexlify(key_hex.replace(" ", ""))
    except binascii.Error as e:
        return {"ok": False, "error": f"key_hex: {e}"}
    if len(key) not in (16, 24, 32):
        return {"ok": False, "error": "AES key length invalid"}
    try:
        nonce = binascii.unhexlify(str(payload.get("nonce_hex") or "").replace(" ", ""))
        ct = binascii.unhexlify(str(payload.get("ciphertext_hex") or "").replace(" ", ""))
    except binascii.Error as e:
        return {"ok": False, "error": f"hex: {e}"}
    aesgcm = AESGCM(key)
    ad = str(payload.get("associated_data") or "").encode("utf-8")
    try:
        pt = aesgcm.decrypt(nonce, ct, ad if ad else None)
    except Exception as e:  # noqa: BLE001
        return {"ok": False, "error": f"decrypt failed: {e}"}
    try:
        return {"ok": True, "text": pt.decode("utf-8")}
    except UnicodeDecodeError:
        return {"ok": True, "hex": pt.hex(), "note": "binary plaintext as hex"}


def op_aes_cbc_encrypt(payload: dict[str, Any]) -> dict[str, Any]:
    err = _need_crypto()
    if err:
        return err
    key_hex = str(payload.get("key_hex") or "")
    iv_hex = str(payload.get("iv_hex") or "")
    try:
        key = binascii.unhexlify(key_hex.replace(" ", ""))
        iv = binascii.unhexlify(iv_hex.replace(" ", ""))
    except binascii.Error as e:
        return {"ok": False, "error": f"hex: {e}"}
    if len(key) not in (16, 24, 32) or len(iv) != 16:
        return {"ok": False, "error": "AES CBC needs 16-byte IV and key 16/24/32 bytes"}
    pt, e2 = _bytes_from_text_or_hex(payload)
    if e2:
        return e2
    assert pt is not None
    padded = _pkcs7_pad(pt, 16)
    cipher = Cipher(algorithms.AES(key), modes.CBC(iv), backend=default_backend())
    enc = cipher.encryptor()
    ct = enc.update(padded) + enc.finalize()
    return {"ok": True, "ciphertext_hex": ct.hex()}


def op_aes_cbc_decrypt(payload: dict[str, Any]) -> dict[str, Any]:
    err = _need_crypto()
    if err:
        return err
    key_hex = str(payload.get("key_hex") or "")
    iv_hex = str(payload.get("iv_hex") or "")
    try:
        key = binascii.unhexlify(key_hex.replace(" ", ""))
        iv = binascii.unhexlify(iv_hex.replace(" ", ""))
        ct = binascii.unhexlify(str(payload.get("ciphertext_hex") or "").replace(" ", ""))
    except binascii.Error as e:
        return {"ok": False, "error": f"hex: {e}"}
    if len(iv) != 16 or len(key) not in (16, 24, 32):
        return {"ok": False, "error": "invalid key/iv length"}
    cipher = Cipher(algorithms.AES(key), modes.CBC(iv), backend=default_backend())
    dec = cipher.decryptor()
    try:
        padded = dec.update(ct) + dec.finalize()
        pt = _pkcs7_unpad(padded)
    except Exception as e:  # noqa: BLE001
        return {"ok": False, "error": f"decrypt: {e}"}
    try:
        return {"ok": True, "text": pt.decode("utf-8")}
    except UnicodeDecodeError:
        return {"ok": True, "hex": pt.hex()}


def op_des_cbc_encrypt(payload: dict[str, Any]) -> dict[str, Any]:
    err = _need_crypto()
    if err:
        return err
    try:
        key = binascii.unhexlify(str(payload.get("key_hex") or "").replace(" ", ""))
        iv = binascii.unhexlify(str(payload.get("iv_hex") or "").replace(" ", ""))
    except binascii.Error as e:
        return {"ok": False, "error": f"hex: {e}"}
    if len(key) != 8 or len(iv) != 8:
        return {"ok": False, "error": "DES needs 8-byte key and 8-byte IV (16 hex each)"}
    pt, e2 = _bytes_from_text_or_hex(payload)
    if e2:
        return e2
    assert pt is not None
    padded = _pkcs7_pad(pt, 8)
    cipher = Cipher(algorithms.DES(key), modes.CBC(iv), backend=default_backend())
    enc = cipher.encryptor()
    ct = enc.update(padded) + enc.finalize()
    return {
        "ok": True,
        "ciphertext_hex": ct.hex(),
        "note": "single DES is weak; prefer AES-GCM",
    }


def op_des_cbc_decrypt(payload: dict[str, Any]) -> dict[str, Any]:
    err = _need_crypto()
    if err:
        return err
    try:
        key = binascii.unhexlify(str(payload.get("key_hex") or "").replace(" ", ""))
        iv = binascii.unhexlify(str(payload.get("iv_hex") or "").replace(" ", ""))
        ct = binascii.unhexlify(str(payload.get("ciphertext_hex") or "").replace(" ", ""))
    except binascii.Error as e:
        return {"ok": False, "error": f"hex: {e}"}
    if len(key) != 8 or len(iv) != 8:
        return {"ok": False, "error": "DES needs 8-byte key and IV"}
    cipher = Cipher(algorithms.DES(key), modes.CBC(iv), backend=default_backend())
    dec = cipher.decryptor()
    try:
        padded = dec.update(ct) + dec.finalize()
        pt = _pkcs7_unpad(padded)
    except Exception as e:  # noqa: BLE001
        return {"ok": False, "error": f"decrypt: {e}"}
    try:
        return {"ok": True, "text": pt.decode("utf-8")}
    except UnicodeDecodeError:
        return {"ok": True, "hex": pt.hex()}


def op_rsa_generate(payload: dict[str, Any]) -> dict[str, Any]:
    err = _need_crypto()
    if err:
        return err
    try:
        bits = int(payload.get("bits", 2048))
    except (TypeError, ValueError):
        return {"ok": False, "error": "bits must be int"}
    bits = max(1024, min(4096, bits))
    sk = rsa.generate_private_key(
        public_exponent=65537, key_size=bits, backend=default_backend()
    )
    pk = sk.public_key()
    priv_pem = sk.private_bytes(
        encoding=serialization.Encoding.PEM,
        format=serialization.PrivateFormat.PKCS8,
        encryption_algorithm=serialization.NoEncryption(),
    ).decode("ascii")
    pub_pem = pk.public_bytes(
        encoding=serialization.Encoding.PEM,
        format=serialization.PublicFormat.SubjectPublicKeyInfo,
    ).decode("ascii")
    return {"ok": True, "bits": bits, "private_pem": priv_pem, "public_pem": pub_pem}


def op_rsa_encrypt(payload: dict[str, Any]) -> dict[str, Any]:
    err = _need_crypto()
    if err:
        return err
    pem = str(payload.get("public_pem") or "")
    data, e2 = _bytes_from_text_or_hex(payload)
    if e2:
        return e2
    assert data is not None
    try:
        pub = serialization.load_pem_public_key(pem.encode("ascii"), backend=default_backend())
    except Exception as e:  # noqa: BLE001
        return {"ok": False, "error": f"PEM public key: {e}"}
    if not isinstance(pub, rsa.RSAPublicKey):
        return {"ok": False, "error": "not an RSA public key"}
    max_len = (pub.key_size // 8) - 2 * 32 - 2
    if len(data) > max_len:
        return {
            "ok": False,
            "error": f"plaintext too long for OAEP-SHA256 (max {max_len} bytes); use AES hybrid",
        }
    ct = pub.encrypt(
        data,
        padding.OAEP(
            mgf=padding.MGF1(algorithm=hashes.SHA256()),
            algorithm=hashes.SHA256(),
            label=None,
        ),
    )
    return {"ok": True, "ciphertext_hex": ct.hex()}


def op_rsa_decrypt(payload: dict[str, Any]) -> dict[str, Any]:
    err = _need_crypto()
    if err:
        return err
    pem = str(payload.get("private_pem") or "")
    try:
        ct = binascii.unhexlify(str(payload.get("ciphertext_hex") or "").replace(" ", ""))
    except binascii.Error as e:
        return {"ok": False, "error": f"ciphertext_hex: {e}"}
    try:
        sk = serialization.load_pem_private_key(
            pem.encode("ascii"), password=None, backend=default_backend()
        )
    except Exception as e:  # noqa: BLE001
        return {"ok": False, "error": f"PEM private key: {e}"}
    if not isinstance(sk, rsa.RSAPrivateKey):
        return {"ok": False, "error": "not an RSA private key"}
    try:
        pt = sk.decrypt(
            ct,
            padding.OAEP(
                mgf=padding.MGF1(algorithm=hashes.SHA256()),
                algorithm=hashes.SHA256(),
                label=None,
            ),
        )
    except Exception as e:  # noqa: BLE001
        return {"ok": False, "error": f"decrypt: {e}"}
    try:
        return {"ok": True, "text": pt.decode("utf-8")}
    except UnicodeDecodeError:
        return {"ok": True, "hex": pt.hex()}


def op_ecc_generate(payload: dict[str, Any]) -> dict[str, Any]:
    err = _need_crypto()
    if err:
        return err
    curve_name = str(payload.get("curve", "secp256r1")).lower()
    curve_map = {
        "secp256r1": ec.SECP256R1(),
        "prime256v1": ec.SECP256R1(),
        "secp384r1": ec.SECP384R1(),
        "secp521r1": ec.SECP521R1(),
    }
    curve = curve_map.get(curve_name)
    if curve is None:
        return {"ok": False, "error": "curve must be secp256r1|secp384r1|secp521r1"}
    sk = ec.generate_private_key(curve, default_backend())
    pk = sk.public_key()
    priv_pem = sk.private_bytes(
        encoding=serialization.Encoding.PEM,
        format=serialization.PrivateFormat.PKCS8,
        encryption_algorithm=serialization.NoEncryption(),
    ).decode("ascii")
    pub_pem = pk.public_bytes(
        encoding=serialization.Encoding.PEM,
        format=serialization.PublicFormat.SubjectPublicKeyInfo,
    ).decode("ascii")
    return {"ok": True, "curve": curve_name, "private_pem": priv_pem, "public_pem": pub_pem}


def op_ecdsa_sign(payload: dict[str, Any]) -> dict[str, Any]:
    err = _need_crypto()
    if err:
        return err
    pem = str(payload.get("private_pem") or "")
    msg, e2 = _bytes_from_text_or_hex(payload, "message")
    if e2:
        return e2
    assert msg is not None
    try:
        sk = serialization.load_pem_private_key(
            pem.encode("ascii"), password=None, backend=default_backend()
        )
    except Exception as e:  # noqa: BLE001
        return {"ok": False, "error": f"PEM: {e}"}
    if not isinstance(sk, ec.EllipticCurvePrivateKey):
        return {"ok": False, "error": "not an EC private key"}
    sig = sk.sign(msg, ec.ECDSA(hashes.SHA256()))
    return {"ok": True, "signature_hex": sig.hex()}


def op_ecdsa_verify(payload: dict[str, Any]) -> dict[str, Any]:
    err = _need_crypto()
    if err:
        return err
    pem = str(payload.get("public_pem") or "")
    msg, e2 = _bytes_from_text_or_hex(payload, "message")
    if e2:
        return e2
    assert msg is not None
    try:
        sig = binascii.unhexlify(str(payload.get("signature_hex") or "").replace(" ", ""))
    except binascii.Error as e:
        return {"ok": False, "error": f"signature_hex: {e}"}
    try:
        pk = serialization.load_pem_public_key(pem.encode("ascii"), backend=default_backend())
    except Exception as e:  # noqa: BLE001
        return {"ok": False, "error": f"PEM: {e}"}
    if not isinstance(pk, ec.EllipticCurvePublicKey):
        return {"ok": False, "error": "not an EC public key"}
    try:
        pk.verify(sig, msg, ec.ECDSA(hashes.SHA256()))
    except Exception:  # noqa: BLE001
        return {"ok": True, "valid": False}
    return {"ok": True, "valid": True}


def op_unix_passwd_list(payload: dict[str, Any]) -> dict[str, Any]:
    if os.name == "nt":
        return {"ok": False, "error": "Unix only: pwd module not available on Windows"}
    try:
        import pwd
    except ImportError:
        return {"ok": False, "error": "pwd module unavailable"}
    try:
        lim = int(payload.get("limit", 200))
    except (TypeError, ValueError):
        lim = 200
    lim = max(1, min(2000, lim))
    out: list[dict[str, Any]] = []
    for i, p in enumerate(pwd.getpwall()):
        if i >= lim:
            break
        out.append(
            {
                "name": p.pw_name,
                "uid": p.pw_uid,
                "gid": p.pw_gid,
                "dir": p.pw_dir,
                "shell": p.pw_shell,
                "gecos": p.pw_gecos,
            }
        )
    return {"ok": True, "entries": out, "truncated": len(out) >= lim, "note": "no password field"}


def op_unix_group_list(payload: dict[str, Any]) -> dict[str, Any]:
    if os.name == "nt":
        return {"ok": False, "error": "Unix only"}
    try:
        import grp
    except ImportError:
        return {"ok": False, "error": "grp module unavailable"}
    try:
        lim = int(payload.get("limit", 200))
    except (TypeError, ValueError):
        lim = 200
    lim = max(1, min(2000, lim))
    out: list[dict[str, Any]] = []
    for i, g in enumerate(grp.getgrall()):
        if i >= lim:
            break
        out.append(
            {
                "name": g.gr_name,
                "gid": g.gr_gid,
                "members": list(g.gr_mem),
            }
        )
    return {"ok": True, "entries": out, "truncated": len(out) >= lim}


def op_unix_getpwnam(payload: dict[str, Any]) -> dict[str, Any]:
    if os.name == "nt":
        return {"ok": False, "error": "Unix only"}
    import pwd

    name = str(payload.get("name") or "")
    if not name:
        return {"ok": False, "error": "name required"}
    try:
        p = pwd.getpwnam(name)
    except KeyError:
        return {"ok": False, "error": "not found"}
    return {
        "ok": True,
        "entry": {
            "name": p.pw_name,
            "uid": p.pw_uid,
            "gid": p.pw_gid,
            "dir": p.pw_dir,
            "shell": p.pw_shell,
            "gecos": p.pw_gecos,
        },
    }


def op_unix_getgrnam(payload: dict[str, Any]) -> dict[str, Any]:
    if os.name == "nt":
        return {"ok": False, "error": "Unix only"}
    import grp

    name = str(payload.get("name") or "")
    if not name:
        return {"ok": False, "error": "name required"}
    try:
        g = grp.getgrnam(name)
    except KeyError:
        return {"ok": False, "error": "not found"}
    return {
        "ok": True,
        "entry": {
            "name": g.gr_name,
            "gid": g.gr_gid,
            "members": list(g.gr_mem),
        },
    }


def run_operation(operation: str, payload: dict[str, Any]) -> dict[str, Any]:
    op = operation.strip().lower().replace("-", "_")
    if op in ("hash_md5", "md5"):
        return op_hash("md5", payload)
    if op in ("hash_sha1", "sha1"):
        return op_hash("sha1", payload)
    if op in ("hash_sha256", "sha256"):
        return op_hash("sha256", payload)
    if op in ("hash_sha512", "sha512"):
        return op_hash("sha512", payload)
    if op == "hash":
        algo = str(payload.get("algorithm") or "sha256").lower()
        return op_hash(algo, payload)
    if op in ("hmac_sha256",):
        return op_hmac_sha256(payload)
    if op in ("base64_encode", "b64encode"):
        return op_base64_encode(payload)
    if op in ("base64_decode", "b64decode"):
        return op_base64_decode(payload)
    if op in ("random_hex", "random_bytes_hex"):
        return op_random_hex(payload)
    if op in ("pbkdf2_hmac_sha256", "pbkdf2"):
        return op_pbkdf2_hmac_sha256(payload)
    if op in ("aes_gcm_encrypt",):
        return op_aes_gcm_encrypt(payload)
    if op in ("aes_gcm_decrypt",):
        return op_aes_gcm_decrypt(payload)
    if op in ("aes_cbc_encrypt",):
        return op_aes_cbc_encrypt(payload)
    if op in ("aes_cbc_decrypt",):
        return op_aes_cbc_decrypt(payload)
    if op in ("des_cbc_encrypt", "des_encrypt"):
        return op_des_cbc_encrypt(payload)
    if op in ("des_cbc_decrypt", "des_decrypt"):
        return op_des_cbc_decrypt(payload)
    if op in ("rsa_generate", "rsa_keygen"):
        return op_rsa_generate(payload)
    if op in ("rsa_encrypt", "rsa_oaep_encrypt"):
        return op_rsa_encrypt(payload)
    if op in ("rsa_decrypt", "rsa_oaep_decrypt"):
        return op_rsa_decrypt(payload)
    if op in ("ecc_generate", "ec_keygen", "ecc_keygen"):
        return op_ecc_generate(payload)
    if op in ("ecdsa_sign", "ecc_sign"):
        return op_ecdsa_sign(payload)
    if op in ("ecdsa_verify", "ecc_verify"):
        return op_ecdsa_verify(payload)
    if op in ("unix_passwd_list", "passwd_list"):
        return op_unix_passwd_list(payload)
    if op in ("unix_group_list", "group_list"):
        return op_unix_group_list(payload)
    if op in ("unix_getpwnam", "getpwnam"):
        return op_unix_getpwnam(payload)
    if op in ("unix_getgrnam", "getgrnam"):
        return op_unix_getgrnam(payload)
    return {
        "ok": False,
        "error": f"unknown operation: {operation!r}",
        "hint": "hash|hmac_sha256|base64_encode|base64_decode|random_hex|pbkdf2_hmac_sha256|"
        "aes_gcm_encrypt|aes_gcm_decrypt|aes_cbc_encrypt|aes_cbc_decrypt|"
        "des_cbc_encrypt|des_cbc_decrypt|rsa_generate|rsa_encrypt|rsa_decrypt|"
        "ecc_generate|ecdsa_sign|ecdsa_verify|unix_passwd_list|unix_group_list|unix_getpwnam|unix_getgrnam",
    }
