<?php
/**
 * Core\SodiumCrypto
 * -------------------------------------------------------------
 *  Minimaler Wrapper um libsodium‑secretbox für symmetrische
 *  Verschlüsselung/Pseudonymisierung.
 * -------------------------------------------------------------
 *  ▸ Key wird als Base64‑String (mit/ohne Präfix "base64:") erwartet.
 *  ▸ Ciphertext‑Format: <24‑Byte Nonce><Cipher>  (binary!)
 * -------------------------------------------------------------
 */

//namespace Core;

final class SodiumCrypto
{
    private const NONCE_BYTES = SODIUM_CRYPTO_SECRETBOX_NONCEBYTES; // 24

    /**
     * Verschlüsselt einen Klartext und liefert Binär‑Ciphertext (nonce+ct).
     */
    public static function encrypt(string $plain, string $b64key): string
    {
        $key   = self::base64KeyToBinary($b64key);
        $nonce = random_bytes(self::NONCE_BYTES);

        return $nonce . sodium_crypto_secretbox($plain, $nonce, $key);
    }

    /**
     * Entschlüsselt Binär‑Ciphertext und gibt Klartext zurück.
     * @throws \RuntimeException wenn Entschlüsselung fehlschlägt
     */
    public static function decrypt(string $cipher, string $b64key): string
    {
        $key   = self::base64KeyToBinary($b64key);
        $nonce = substr($cipher, 0, self::NONCE_BYTES);
        $ct    = substr($cipher, self::NONCE_BYTES);

        $plain = sodium_crypto_secretbox_open($ct, $nonce, $key);
        if ($plain === false) {
            throw new \RuntimeException('Decryption failed');
        }
        return $plain;
    }

    /**
     * Entfernt optionales "base64:"‑Präfix und dekodiert den Schlüssel.
     */
    private static function base64KeyToBinary(string $b64): string
    {
        if (str_starts_with($b64, 'base64:')) {
            $b64 = substr($b64, 7);
        }
        $bin = base64_decode($b64, true);
        if ($bin === false || strlen($bin) !== SODIUM_CRYPTO_SECRETBOX_KEYBYTES) {
            throw new \InvalidArgumentException('Invalid sodium key');
        }
        return $bin;
    }
}
