<?php

if (!defined('ABSPATH')) {
    exit;
}

class BS2FA_Crypto {
    protected static function key_material() {
        $material = AUTH_KEY . SECURE_AUTH_KEY . LOGGED_IN_KEY . NONCE_KEY . wp_salt('auth');
        return hash('sha256', $material, true);
    }

    public static function encrypt($plaintext) {
        if ($plaintext === '' || $plaintext === null) {
            return '';
        }

        $key = self::key_material();

        if (function_exists('sodium_crypto_secretbox')) {
            $nonce  = random_bytes(SODIUM_CRYPTO_SECRETBOX_NONCEBYTES);
            $cipher = sodium_crypto_secretbox($plaintext, $nonce, $key);
            return 'sbx:' . BS2FA_Helpers::base64url_encode($nonce . $cipher);
        }

        $iv        = random_bytes(12);
        $tag       = '';
        $cipher    = openssl_encrypt($plaintext, 'aes-256-gcm', $key, OPENSSL_RAW_DATA, $iv, $tag);
        $encrypted = $iv . $tag . $cipher;
        return 'gcm:' . BS2FA_Helpers::base64url_encode($encrypted);
    }

    public static function decrypt($payload) {
        if (!$payload || !is_string($payload)) {
            return '';
        }

        $key = self::key_material();

        if (strpos($payload, 'sbx:') === 0 && function_exists('sodium_crypto_secretbox_open')) {
            $raw   = BS2FA_Helpers::base64url_decode(substr($payload, 4));
            $nonce = substr($raw, 0, SODIUM_CRYPTO_SECRETBOX_NONCEBYTES);
            $cipher = substr($raw, SODIUM_CRYPTO_SECRETBOX_NONCEBYTES);
            $plain = sodium_crypto_secretbox_open($cipher, $nonce, $key);
            return false === $plain ? '' : $plain;
        }

        if (strpos($payload, 'gcm:') === 0) {
            $raw  = BS2FA_Helpers::base64url_decode(substr($payload, 4));
            $iv   = substr($raw, 0, 12);
            $tag  = substr($raw, 12, 16);
            $data = substr($raw, 28);
            $plain = openssl_decrypt($data, 'aes-256-gcm', $key, OPENSSL_RAW_DATA, $iv, $tag);
            return false === $plain ? '' : $plain;
        }

        return '';
    }

    public static function encrypt_user_meta($user_id, $meta_key, $value) {
        return update_user_meta($user_id, $meta_key, self::encrypt($value));
    }

    public static function decrypt_user_meta($user_id, $meta_key) {
        $stored = get_user_meta($user_id, $meta_key, true);
        return self::decrypt($stored);
    }
}
