<?php
/**
 * Data Encryption Middleware
 * AES-256 encryption for sensitive data storage
 */

class DataEncryption {
    private static $cipher = 'AES-256-CBC';
    private static $keySize = 32; // 256 bits

    /**
     * Generate encryption key from environment
     */
    private static function getEncryptionKey() {
        $key = getenv('ENCRYPTION_KEY');
        if (!$key) {
            // Fallback: generate from JWT secret (for development only)
            $jwtSecret = getenv('JWT_SECRET');
            if ($jwtSecret) {
                $key = substr(hash('sha256', $jwtSecret), 0, self::$keySize);
            } else {
                throw new Exception('Encryption key not configured');
            }
        }
        return substr($key, 0, self::$keySize);
    }

    /**
     * Encrypt sensitive data
     */
    public static function encrypt($data) {
        if (empty($data)) {
            return $data;
        }

        $key = self::getEncryptionKey();
        $iv = openssl_random_pseudo_bytes(openssl_cipher_iv_length(self::$cipher));

        $encrypted = openssl_encrypt($data, self::$cipher, $key, OPENSSL_RAW_DATA, $iv);

        if ($encrypted === false) {
            throw new Exception('Encryption failed');
        }

        // Combine IV and encrypted data
        return base64_encode($iv . $encrypted);
    }

    /**
     * Decrypt sensitive data
     */
    public static function decrypt($encryptedData) {
        if (empty($encryptedData)) {
            return $encryptedData;
        }

        $key = self::getEncryptionKey();
        $data = base64_decode($encryptedData);

        if ($data === false) {
            throw new Exception('Invalid encrypted data format');
        }

        $ivLength = openssl_cipher_iv_length(self::$cipher);

        if (strlen($data) < $ivLength) {
            throw new Exception('Invalid encrypted data length');
        }

        $iv = substr($data, 0, $ivLength);
        $encrypted = substr($data, $ivLength);

        $decrypted = openssl_decrypt($encrypted, self::$cipher, $key, OPENSSL_RAW_DATA, $iv);

        if ($decrypted === false) {
            throw new Exception('Decryption failed');
        }

        return $decrypted;
    }

    /**
     * Hash password with proper algorithm
     */
    public static function hashPassword($password) {
        return password_hash($password, PASSWORD_ARGON2ID, [
            'memory_cost' => 65536, // 64MB
            'time_cost' => 4,
            'threads' => 3
        ]);
    }

    /**
     * Verify password against hash
     */
    public static function verifyPassword($password, $hash) {
        return password_verify($password, $hash);
    }

    /**
     * Check if password needs rehash (for algorithm updates)
     */
    public static function needsRehash($hash) {
        return password_needs_rehash($hash, PASSWORD_ARGON2ID, [
            'memory_cost' => 65536,
            'time_cost' => 4,
            'threads' => 3
        ]);
    }

    /**
     * Generate secure token for sensitive operations
     */
    public static function generateSecureToken($length = 32) {
        return bin2hex(random_bytes($length));
    }

    /**
     * Encrypt data before database storage
     * Use this for sensitive fields like phone numbers, emails, etc.
     */
    public static function encryptForStorage($data) {
        if (is_array($data)) {
            $encrypted = [];
            foreach ($data as $key => $value) {
                $encrypted[$key] = self::encrypt($value);
            }
            return $encrypted;
        }

        return self::encrypt($data);
    }

    /**
     * Decrypt data after database retrieval
     */
    public static function decryptFromStorage($data) {
        if (is_array($data)) {
            $decrypted = [];
            foreach ($data as $key => $value) {
                $decrypted[$key] = self::decrypt($value);
            }
            return $decrypted;
        }

        return self::decrypt($data);
    }

    /**
     * Generate encryption key (for development/setup)
     */
    public static function generateKey() {
        return bin2hex(random_bytes(self::$keySize));
    }

    /**
     * Test encryption/decryption
     */
    public static function testEncryption() {
        $testData = 'Test sensitive data 123';
        $encrypted = self::encrypt($testData);
        $decrypted = self::decrypt($encrypted);

        return $decrypted === $testData;
    }
}
?>
