<?php

namespace ZenoChatbot\Helper;

class Hash
{

    protected static $options = [
        'key'     => '_zeno_chatbot_salt',
        'cipher'  => 'AES-128-CBC',
        'hmac'    => 'sha256',
        'sha2len' => 32,
    ];

    public static function generateSalt()
    {
        return wp_generate_password();
    }

    public static function getSalt()
    {
        if($salt = get_option(static::$options['key'])){
            return $salt;
        }

        $salt = static::generateSalt();
        update_option(static::$options['key'], $salt, 'no');

        return $salt;
    }

    /**
     * Encrypt a text using a predefined salt.
     *
     * @param string $text
     *
     * @return string $text
     */
    public static function encrypt($text)
    {
        $key = static::getSalt();
        $cipher = static::$options['cipher'];
        $ivLength = openssl_cipher_iv_length($cipher);
        $iv = openssl_random_pseudo_bytes($ivLength);
        $ciphertextRaw = openssl_encrypt($text, $cipher, $key, $options = OPENSSL_RAW_DATA, $iv);
        $hmac = hash_hmac(static::$options['hmac'], $ciphertextRaw, $key, $asBinary = true);
        return base64_encode($iv . $hmac . $ciphertextRaw);
    }

    /**
     * Decrypt a text using a predefined salt.
     *
     * @param string $text
     *
     * @return string $text
     */
    public static function decrypt($text)
    {
        $key = static::getSalt();
        $c = base64_decode($text);
        $cipher = static::$options['cipher'];
        $ivLength = openssl_cipher_iv_length($cipher);
        $iv = substr($c, 0, $ivLength);
        $hmac = substr($c, $ivLength, $sha2len = static::$options['sha2len']);
        $ciphertextRaw = substr($c, $ivLength + $sha2len);
        $originalPlaintext = openssl_decrypt($ciphertextRaw, $cipher, $key, $options = OPENSSL_RAW_DATA, $iv);
        $calcmac = hash_hmac(static::$options['hmac'], $ciphertextRaw, $key, $asBinary = true);

        if (hash_equals($hmac, $calcmac)) { // timing attack safe comparison
            return $originalPlaintext;
        }

        return $originalPlaintext;
    }

    public static function make($text)
    {
        return static::encrypt($text);
    }

    public static function verify($text, $hash)
    {
        return static::check($text, $hash);
    }

    public static function check($text, $hash)
    {
        return static::decrypt($hash) === $text;
    }
    public static function open($hash)
    {
        return static::decrypt($hash);
    }
}
