plugins/sys/classes/yf_encryption.class.php

Summary

Maintainability
A
1 hr
Test Coverage
<?php

/**
 * This class perform crypt/encrypt operations.
 *
 * @author        YFix Team <yfix.dev@gmail.com>
 * @version        1.0
 */
class yf_encryption
{
    /** @var bool Use internal PHP MCrypt module or not */
    public $USE_MCRYPT = true;
    /** @var int Define which cryptographic algorithm to use */
    public $USE_CIPHER = 4;
    /** @var array Available algorithms (sorted in speed descending order) */
    public $_avail_ciphers = [
        4 => 'CAST_256',
        0 => 'CAST_128',
    ];
    /** @var string Secret key */
    public $_secret_key = 'secret__13457890'; // Padded for 16 bytes
    /** @var mixed @conf_skip Mcrypt cipher constant value */
    public $_mcrypt_cipher = null;
    /** @var mixed @conf_skip Current cipher processor */
    public $_cur_cipher = null;
    /** @var mixed @conf_skip Current cipher id */
    public $_cur_cipher_id = null;
    /** @var mixed @conf_skip Key assigned */
    public $_key_assigned = false;
    /** @var mixed @conf_skip Initialization vector (Need in non-ECB mode) */
    public $_iv = null;


    public function __construct()
    {
        $crypto_use_mcrypt = conf('crypto_use_mcrypt');
        if (isset($crypto_use_mcrypt)) {
            $this->USE_MCRYPT = $crypto_use_mcrypt;
        }
        $crypto_use_cipher = conf('crypto_use_cipher');
        if (isset($crypto_use_cipher)) {
            $this->USE_CIPHER = $crypto_use_cipher;
        }
        if ( ! extension_loaded('mcrypt')) {
            $this->USE_MCRYPT = false;
        }
    }

    /**
     * Catch missing method call.
     * @param mixed $name
     * @param mixed $args
     */
    public function __call($name, $args)
    {
        return main()->extend_call($this, $name, $args);
    }


    public function init()
    {
        if ( ! extension_loaded('mcrypt')) {
            $this->USE_MCRYPT = false;
        }
        if ($this->USE_MCRYPT == true) {
            $this->_mcrypt_cipher = constant('MCRYPT_' . $this->_avail_ciphers[$this->USE_CIPHER]);
        } else {/*if ($this->_cur_cipher_id !== $this->USE_CIPHER) {*/
            require_php_lib('phpcrypt');
            $cipher_id_to_name = [
                0 => PHP_Crypt\PHP_Crypt::CIPHER_CAST_128,
                4 => PHP_Crypt\PHP_Crypt::CIPHER_CAST_256,
            ];
            $this->_cur_cipher = new PHP_Crypt\PHP_Crypt($this->_secret_key, $cipher_id_to_name[$this->USE_CIPHER], PHP_Crypt\PHP_Crypt::MODE_CBC);
        }
    }


    public function get_key()
    {
        return $this->_secret_key;
    }

    /**
     * Alias.
     */
    public function get_secret()
    {
        return $this->get_key();
    }

    /**
     * @param mixed $value
     */
    public function set_key($value)
    {
        $this->_secret_key = $value;
        return $this;
    }

    /**
     * Alias.
     * @param mixed $value
     */
    public function set_secret($value)
    {
        return $this->set_key($value);
    }


    public function get_cipher()
    {
        return $this->_avail_ciphers[$this->USE_CIPHER];
    }

    /**
     * Choose encoding/decoding algorithm by its name.
     * Examples: _class('encyption')->set_cipher('cast128'), _class('encyption')->set_cipher('CAST_128').
     * @param mixed $name
     */
    public function set_cipher($name)
    {
        $name = str_replace(['_', '-', ' '], '', strtolower(trim($name)));
        if ( ! strlen($name)) {
            return $this;
        }
        $name_to_id = [];
        foreach ((array) $this->_avail_ciphers as $id => $n) {
            $n = str_replace(['_', '-', ' '], '', strtolower(trim($n)));
            $name_to_id[$n] = $id;
        }
        if (isset($name_to_id[$name])) {
            $this->USE_CIPHER = $name_to_id[$name];
        }
        return $this;
    }


    public function get_iv()
    {
        return $this->_iv;
    }

    /**
     * @param mixed $data
     * @param null|mixed $secret
     * @param null|mixed $cipher
     */
    public function encrypt($data, $secret = null, $cipher = null)
    {
        if (isset($secret)) {
            $this->set_key($secret);
        }
        if (isset($cipher)) {
            $this->set_cipher($cipher);
        }
        $this->init();
        $key = $this->_secret_key;
        // MCrypt PHP module processing (high speed)
        if ($this->USE_MCRYPT && $this->_mcrypt_cipher) {
            $td = mcrypt_module_open($this->_mcrypt_cipher, '', MCRYPT_MODE_CBC, '');
            $key = substr($key, 0, mcrypt_enc_get_key_size($td));
            $this->_iv = mcrypt_create_iv(mcrypt_enc_get_iv_size($td), MCRYPT_RAND);
            mcrypt_generic_init($td, $key, $this->_iv);
            $encrypted = mcrypt_generic($td, $data);
            mcrypt_generic_deinit($td);
        // Use classes written in PHP (less speed, more flexibility)
        } elseif (is_object($this->_cur_cipher)) {
            $this->_cur_cipher->cipherKey($key);
            $this->_iv = $this->_cur_cipher->createIV();
            $this->_cur_cipher->IV($this->_iv);
            $encrypted = $this->_cur_cipher->encrypt($data);
        }
        return $encrypted;
    }

    /**
     * @param mixed $data
     * @param null|mixed $secret
     * @param null|mixed $cipher
     * @param mixed $iv
     */
    public function decrypt($data, $secret = null, $cipher = null, $iv)
    {
        if ( ! $iv) {
            return false;
        }
        if (isset($secret)) {
            $this->set_key($secret);
        }
        if (isset($cipher)) {
            $this->set_cipher($cipher);
        }
        $this->init();
        $key = $this->_secret_key;
        // MCrypt PHP module processing (high speed)
        if ($this->USE_MCRYPT && $this->_mcrypt_cipher) {
            $td = mcrypt_module_open($this->_mcrypt_cipher, '', MCRYPT_MODE_CBC, '');
            $key = substr($key, 0, mcrypt_enc_get_key_size($td));
            mcrypt_generic_init($td, $key, $iv);
            $decrypted = mdecrypt_generic($td, $data);
            mcrypt_generic_deinit($td);
        // Use classes written in PHP (less speed, more flexibility)
        } elseif (is_object($this->_cur_cipher)) {
            $this->_cur_cipher->cipherKey($key);
            $this->_cur_cipher->IV($iv);
            $decrypted = $this->_cur_cipher->decrypt($data);
        }
        return rtrim($decrypted);
    }

    /**
     * Encrypt specified file using private key.
     * @param mixed $source_path
     * @param mixed $encrypted_path
     * @param null|mixed $secret
     * @param null|mixed $cipher
     */
    public function encrypt_file($source_path, $encrypted_path, $secret = null, $cipher = null)
    {
        file_put_contents($encrypted_path, $this->encrypt(file_get_contents($source_path), $secret, $cipher));
        return $this;
    }

    /**
     * Decrypt specified file using private key.
     * @param mixed $source_path
     * @param mixed $decrypted_path
     * @param null|mixed $secret
     * @param null|mixed $cipher
     * @param mixed $iv
     */
    public function decrypt_file($source_path, $decrypted_path, $secret = null, $cipher = null, $iv)
    {
        file_put_contents($decrypted_path, $this->decrypt(file_get_contents($source_path)), $secret, $cipher, $iv);
        return $this;
    }

    /**
     * @param mixed $text
     */
    public function _safe_base64_encode($text)
    {
        $r = [
            '/' => '*',
        ];
        return str_replace(array_keys($r), array_values($r), base64_encode($text));
    }

    /**
     * @param mixed $text
     */
    public function _safe_base64_decode($text)
    {
        $r = [
            '*' => '/',
            ' ' => '+',
            '%20' => '+',
        ];
        return base64_decode(str_replace(array_keys($r), array_values($r), $text));
    }

    /**
     * Safe encrypt data into base64 string (replace '/' symbol).
     * @param mixed $input
     * @param null|mixed $secret
     * @param null|mixed $cipher
     */
    public function _safe_encrypt_with_base64($input, $secret = null, $cipher = null)
    {
        $encrypted = $this->encrypt($input, $secret, $cipher);
        $iv = $this->_iv;
        return $this->_safe_base64_encode($iv) . '|' . $this->_safe_base64_encode($encrypted);
    }

    /**
     * Safe decrypt data from base64 string (replace '/' symbol).
     * @param mixed $input
     * @param null|mixed $secret
     * @param null|mixed $cipher
     */
    public function _safe_decrypt_with_base64($input, $secret = null, $cipher = null)
    {
        if (strpos($input, '|') === false) {
            return false;
        }
        list($iv, $encrypted) = explode('|', $input);
        return $this->decrypt($this->_safe_base64_decode($encrypted), $secret, $cipher, $this->_safe_base64_decode($iv));
    }
}