<?php
/**
 * OTIS Secure Vault Encryption — AES-256-GCM
 * Authenticated encryption (prevents tampering + decryption without key)
 * Namecheap/shared-hosting compatible (requires OpenSSL extension only)
 *
 * UPGRADE from AES-256-CBC:
 * - AES-256-GCM provides authentication (detects tampering) unlike CBC
 * - Uses HKDF to derive separate encryption & authentication sub-keys
 * - Format: base64( salt[16] | iv[12] | tag[16] | ciphertext )
 */

if (!function_exists('otis_encrypt')) {
    function otis_encrypt(string $plainText): string {
        $masterKey = _otis_master_key();
        $salt      = random_bytes(16);
        $key       = hash_hkdf('sha256', $masterKey, 32, 'otis-vault-enc', $salt);
        $iv        = random_bytes(12); // GCM standard IV length
        $tag       = '';

        $ciphertext = openssl_encrypt(
            $plainText,
            'aes-256-gcm',
            $key,
            OPENSSL_RAW_DATA,
            $iv,
            $tag,
            '',
            16
        );

        if ($ciphertext === false) {
            throw new \RuntimeException('Encryption failed.');
        }

        return base64_encode($salt . $iv . $tag . $ciphertext);
    }
}

if (!function_exists('otis_decrypt')) {
    function otis_decrypt(string $encryptedPayload) {
        $decoded = base64_decode($encryptedPayload, true);
        if ($decoded === false || strlen($decoded) < 44) {
            return false;
        }

        $masterKey  = _otis_master_key();
        $salt       = substr($decoded, 0, 16);
        $iv         = substr($decoded, 16, 12);
        $tag        = substr($decoded, 28, 16);
        $ciphertext = substr($decoded, 44);

        $key = hash_hkdf('sha256', $masterKey, 32, 'otis-vault-enc', $salt);

        $plainText = openssl_decrypt(
            $ciphertext,
            'aes-256-gcm',
            $key,
            OPENSSL_RAW_DATA,
            $iv,
            $tag
        );

        return $plainText; // Returns false on authentication failure (tampered data)
    }
}

/**
 * Legacy CBC decrypt — used ONLY to migrate old vault entries.
 * After migrating all entries, this can be removed.
 */
if (!function_exists('otis_decrypt_legacy')) {
    function otis_decrypt_legacy(string $encryptedPayload) {
        $config = require __DIR__ . '/../config/database.php';
        $key    = $config['VAULT_ENCRYPTION_KEY'] ?? '';
        if (empty($key)) return false;

        $decoded = base64_decode($encryptedPayload);
        if (!$decoded) return false;

        $cipher   = 'AES-256-CBC';
        $ivLength = openssl_cipher_iv_length($cipher);
        $iv       = substr($decoded, 0, $ivLength);
        $cipher_t = substr($decoded, $ivLength);

        if (strlen($iv) !== $ivLength) return false;

        return openssl_decrypt($cipher_t, $cipher, $key, OPENSSL_RAW_DATA, $iv);
    }
}

/**
 * Internal: load & validate the master key.
 */
function _otis_master_key(): string {
    $config = require __DIR__ . '/../config/database.php';
    $key    = $config['VAULT_ENCRYPTION_KEY'] ?? '';
    if (strlen($key) < 16) {
        throw new \RuntimeException('VAULT_ENCRYPTION_KEY is missing or too short in config/database.php');
    }
    // Stretch key to exactly 32 bytes (SHA-256) regardless of its format
    return hash('sha256', $key, true);
}
