Вход Регистрация
Файл: Main Website Files/system/libraries/Encryption.php
Строк: 660
<?php
/**
 * CodeIgniter
 *
 * An open source application development framework for PHP
 *
 * This content is released under the MIT License (MIT)
 *
 * Copyright (c) 2014 - 2015, British Columbia Institute of Technology
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 *
 * @package    CodeIgniter
 * @author    EllisLab Dev Team
 * @copyright    Copyright (c) 2008 - 2014, EllisLab, Inc. (http://ellislab.com/)
 * @copyright    Copyright (c) 2014 - 2015, British Columbia Institute of Technology (http://bcit.ca/)
 * @license    http://opensource.org/licenses/MIT    MIT License
 * @link    http://codeigniter.com
 * @since    Version 3.0.0
 * @filesource
 */
defined('BASEPATH') OR exit('No direct script access allowed');

/**
 * CodeIgniter Encryption Class
 *
 * Provides two-way keyed encryption via PHP's MCrypt and/or OpenSSL extensions.
 *
 * @package        CodeIgniter
 * @subpackage    Libraries
 * @category    Libraries
 * @author        Andrey Andreev
 * @link        http://codeigniter.com/user_guide/libraries/encryption.html
 */
class CI_Encryption {

    
/**
     * Encryption cipher
     *
     * @var    string
     */
    
protected $_cipher 'aes-128';

    
/**
     * Cipher mode
     *
     * @var    string
     */
    
protected $_mode 'cbc';

    
/**
     * Cipher handle
     *
     * @var    mixed
     */
    
protected $_handle;

    
/**
     * Encryption key
     *
     * @var    string
     */
    
protected $_key;

    
/**
     * PHP extension to be used
     *
     * @var    string
     */
    
protected $_driver;

    
/**
     * List of usable drivers (PHP extensions)
     *
     * @var    array
     */
    
protected $_drivers = array();

    
/**
     * List of available modes
     *
     * @var    array
     */
    
protected $_modes = array(
        
'mcrypt' => array(
            
'cbc' => 'cbc',
            
'ecb' => 'ecb',
            
'ofb' => 'nofb',
            
'ofb8' => 'ofb',
            
'cfb' => 'ncfb',
            
'cfb8' => 'cfb',
            
'ctr' => 'ctr',
            
'stream' => 'stream'
        
),
        
'openssl' => array(
            
'cbc' => 'cbc',
            
'ecb' => 'ecb',
            
'ofb' => 'ofb',
            
'cfb' => 'cfb',
            
'cfb8' => 'cfb8',
            
'ctr' => 'ctr',
            
'stream' => '',
            
'xts' => 'xts'
        
)
    );

    
/**
     * List of supported HMAC algorightms
     *
     * name => digest size pairs
     *
     * @var    array
     */
    
protected $_digests = array(
        
'sha224' => 28,
        
'sha256' => 32,
        
'sha384' => 48,
        
'sha512' => 64
    
);

    
/**
     * mbstring.func_override flag
     *
     * @var    bool
     */
    
protected static $func_override;

    
// --------------------------------------------------------------------

    /**
     * Class constructor
     *
     * @param    array    $params    Configuration parameters
     * @return    void
     */
    
public function __construct(array $params = array())
    {
        
$this->_drivers = array(
            
'mcrypt' => defined('MCRYPT_DEV_URANDOM'),
            
// While OpenSSL is available for PHP 5.3.0, an IV parameter
            // for the encrypt/decrypt functions is only available since 5.3.3
            
'openssl' => (is_php('5.3.3') && extension_loaded('openssl'))
        );

        if ( ! 
$this->_drivers['mcrypt'] && ! $this->_drivers['openssl'])
        {
            
show_error('Encryption: Unable to find an available encryption driver.');
        }

        isset(
self::$func_override) OR self::$func_override = (extension_loaded('mbstring') && ini_get('mbstring.func_override'));
        
$this->initialize($params);

        if ( ! isset(
$this->_key) && self::strlen($key config_item('encryption_key')) > 0)
        {
            
$this->_key $key;
        }

        
log_message('info''Encryption Class Initialized');
    }

    
// --------------------------------------------------------------------

    /**
     * Initialize
     *
     * @param    array    $params    Configuration parameters
     * @return    CI_Encryption
     */
    
public function initialize(array $params)
    {
        if ( ! empty(
$params['driver']))
        {
            if (isset(
$this->_drivers[$params['driver']]))
            {
                if (
$this->_drivers[$params['driver']])
                {
                    
$this->_driver $params['driver'];
                }
                else
                {
                    
log_message('error'"Encryption: Driver '".$params['driver']."' is not available.");
                }
            }
            else
            {
                
log_message('error'"Encryption: Unknown driver '".$params['driver']."' cannot be configured.");
            }
        }

        if (empty(
$this->_driver))
        {
            
$this->_driver = ($this->_drivers['openssl'] === TRUE)
                ? 
'openssl'
                
'mcrypt';

            
log_message('debug'"Encryption: Auto-configured driver '".$this->_driver."'.");
        }

        empty(
$params['cipher']) && $params['cipher'] = $this->_cipher;
        empty(
$params['key']) OR $this->_key $params['key'];
        
$this->{'_'.$this->_driver.'_initialize'}($params);
        return 
$this;
    }

    
// --------------------------------------------------------------------

    /**
     * Initialize MCrypt
     *
     * @param    array    $params    Configuration parameters
     * @return    void
     */
    
protected function _mcrypt_initialize($params)
    {
        if ( ! empty(
$params['cipher']))
        {
            
$params['cipher'] = strtolower($params['cipher']);
            
$this->_cipher_alias($params['cipher']);

            if ( ! 
in_array($params['cipher'], mcrypt_list_algorithms(), TRUE))
            {
                
log_message('error''Encryption: MCrypt cipher '.strtoupper($params['cipher']).' is not available.');
            }
            else
            {
                
$this->_cipher $params['cipher'];
            }
        }

        if ( ! empty(
$params['mode']))
        {
            
$params['mode'] = strtolower($params['mode']);
            if ( ! isset(
$this->_modes['mcrypt'][$params['mode']]))
            {
                
log_message('error''Encryption: MCrypt mode '.strtoupper($params['mode']).' is not available.');
            }
            else
            {
                
$this->_mode $this->_modes['mcrypt'][$params['mode']];
            }
        }

        if (isset(
$this->_cipher$this->_mode))
        {
            if (
is_resource($this->_handle)
                && (
strtolower(mcrypt_enc_get_algorithms_name($this->_handle)) !== $this->_cipher
                    
OR strtolower(mcrypt_enc_get_modes_name($this->_handle)) !== $this->_mode)
            )
            {
                
mcrypt_module_close($this->_handle);
            }

            if (
$this->_handle mcrypt_module_open($this->_cipher''$this->_mode''))
            {
                
log_message('info''Encryption: MCrypt cipher '.strtoupper($this->_cipher).' initialized in '.strtoupper($this->_mode).' mode.');
            }
            else
            {
                
log_message('error''Encryption: Unable to initialize MCrypt with cipher '.strtoupper($this->_cipher).' in '.strtoupper($this->_mode).' mode.');
            }
        }
    }

    
// --------------------------------------------------------------------

    /**
     * Initialize OpenSSL
     *
     * @param    array    $params    Configuration parameters
     * @return    void
     */
    
protected function _openssl_initialize($params)
    {
        if ( ! empty(
$params['cipher']))
        {
            
$params['cipher'] = strtolower($params['cipher']);
            
$this->_cipher_alias($params['cipher']);
            
$this->_cipher $params['cipher'];
        }

        if ( ! empty(
$params['mode']))
        {
            
$params['mode'] = strtolower($params['mode']);
            if ( ! isset(
$this->_modes['openssl'][$params['mode']]))
            {
                
log_message('error''Encryption: OpenSSL mode '.strtoupper($params['mode']).' is not available.');
            }
            else
            {
                
$this->_mode $this->_modes['openssl'][$params['mode']];
            }
        }

        if (isset(
$this->_cipher$this->_mode))
        {
            
// This is mostly for the stream mode, which doesn't get suffixed in OpenSSL
            
$handle = empty($this->_mode)
                ? 
$this->_cipher
                
$this->_cipher.'-'.$this->_mode;

            if ( ! 
in_array($handleopenssl_get_cipher_methods(), TRUE))
            {
                
$this->_handle NULL;
                
log_message('error''Encryption: Unable to initialize OpenSSL with method '.strtoupper($handle).'.');
            }
            else
            {
                
$this->_handle $handle;
                
log_message('info''Encryption: OpenSSL initialized with method '.strtoupper($handle).'.');
            }
        }
    }

    
// --------------------------------------------------------------------

    /**
     * Create a random key
     *
     * @param    int    $length    Output length
     * @return    string
     */
    
public function create_key($length)
    {
        return (
$this->_driver === 'mcrypt')
            ? 
mcrypt_create_iv($lengthMCRYPT_DEV_URANDOM)
            : 
openssl_random_pseudo_bytes($length);
    }

    
// --------------------------------------------------------------------

    /**
     * Encrypt
     *
     * @param    string    $data    Input data
     * @param    array    $params    Input parameters
     * @return    string
     */
    
public function encrypt($data, array $params NULL)
    {
        if ((
$params $this->_get_params($params)) === FALSE)
        {
            return 
FALSE;
        }

        isset(
$params['key']) OR $params['key'] = $this->hkdf($this->_key'sha512'NULLself::strlen($this->_key), 'encryption');

        if ((
$data $this->{'_'.$this->_driver.'_encrypt'}($data$params)) === FALSE)
        {
            return 
FALSE;
        }

        
$params['base64'] && $data base64_encode($data);

        if (isset(
$params['hmac_digest']))
        {
            isset(
$params['hmac_key']) OR $params['hmac_key'] = $this->hkdf($this->_key'sha512'NULLNULL'authentication');
            return 
hash_hmac($params['hmac_digest'], $data$params['hmac_key'], ! $params['base64']).$data;
        }

        return 
$data;
    }

    
// --------------------------------------------------------------------

    /**
     * Encrypt via MCrypt
     *
     * @param    string    $data    Input data
     * @param    array    $params    Input parameters
     * @return    string
     */
    
protected function _mcrypt_encrypt($data$params)
    {
        if ( ! 
is_resource($params['handle']))
        {
            return 
FALSE;
        }

        
// The greater-than-1 comparison is mostly a work-around for a bug,
        // where 1 is returned for ARCFour instead of 0.
        
$iv = (($iv_size mcrypt_enc_get_iv_size($params['handle'])) > 1)
            ? 
mcrypt_create_iv($iv_sizeMCRYPT_DEV_URANDOM)
            : 
NULL;

        if (
mcrypt_generic_init($params['handle'], $params['key'], $iv) < 0)
        {
            if (
$params['handle'] !== $this->_handle)
            {
                
mcrypt_module_close($params['handle']);
            }

            return 
FALSE;
        }

        
// Use PKCS#7 padding in order to ensure compatibility with OpenSSL
        // and other implementations outside of PHP.
        
if (in_array(strtolower(mcrypt_enc_get_modes_name($params['handle'])), array('cbc''ecb'), TRUE))
        {
            
$block_size mcrypt_enc_get_block_size($params['handle']);
            
$pad $block_size - (self::strlen($data) % $block_size);
            
$data .= str_repeat(chr($pad), $pad);
        }

        
// Work-around for yet another strange behavior in MCrypt.
        //
        // When encrypting in ECB mode, the IV is ignored. Yet
        // mcrypt_enc_get_iv_size() returns a value larger than 0
        // even if ECB is used AND mcrypt_generic_init() complains
        // if you don't pass an IV with length equal to the said
        // return value.
        //
        // This probably would've been fine (even though still wasteful),
        // but OpenSSL isn't that dumb and we need to make the process
        // portable, so ...
        
$data = (mcrypt_enc_get_modes_name($params['handle']) !== 'ECB')
            ? 
$iv.mcrypt_generic($params['handle'], $data)
            : 
mcrypt_generic($params['handle'], $data);

        
mcrypt_generic_deinit($params['handle']);
        if (
$params['handle'] !== $this->_handle)
        {
            
mcrypt_module_close($params['handle']);
        }

        return 
$data;
    }

    
// --------------------------------------------------------------------

    /**
     * Encrypt via OpenSSL
     *
     * @param    string    $data    Input data
     * @param    array    $params    Input parameters
     * @return    string
     */
    
protected function _openssl_encrypt($data$params)
    {
        if (empty(
$params['handle']))
        {
            return 
FALSE;
        }

        
$iv = ($iv_size openssl_cipher_iv_length($params['handle']))
            ? 
openssl_random_pseudo_bytes($iv_size)
            : 
NULL;

        
$data openssl_encrypt(
            
$data,
            
$params['handle'],
            
$params['key'],
            
1// DO NOT TOUCH!
            
$iv
        
);

        if (
$data === FALSE)
        {
            return 
FALSE;
        }

        return 
$iv.$data;
    }

    
// --------------------------------------------------------------------

    /**
     * Decrypt
     *
     * @param    string    $data    Encrypted data
     * @param    array    $params    Input parameters
     * @return    string
     */
    
public function decrypt($data, array $params NULL)
    {
        if ((
$params $this->_get_params($params)) === FALSE)
        {
            return 
FALSE;
        }

        if (isset(
$params['hmac_digest']))
        {
            
// This might look illogical, but it is done during encryption as well ...
            // The 'base64' value is effectively an inverted "raw data" parameter
            
$digest_size = ($params['base64'])
                ? 
$this->_digests[$params['hmac_digest']] * 2
                
$this->_digests[$params['hmac_digest']];

            if (
self::strlen($data) <= $digest_size)
            {
                return 
FALSE;
            }

            
$hmac_input self::substr($data0$digest_size);
            
$data self::substr($data$digest_size);

            isset(
$params['hmac_key']) OR $params['hmac_key'] = $this->hkdf($this->_key'sha512'NULLNULL'authentication');
            
$hmac_check hash_hmac($params['hmac_digest'], $data$params['hmac_key'], ! $params['base64']);

            
// Time-attack-safe comparison
            
$diff 0;
            for (
$i 0$i $digest_size$i++)
            {
                
$diff |= ord($hmac_input[$i]) ^ ord($hmac_check[$i]);
            }

            if (
$diff !== 0)
            {
                return 
FALSE;
            }
        }

        if (
$params['base64'])
        {
            
$data base64_decode($data);
        }

        isset(
$params['key']) OR $params['key'] = $this->hkdf($this->_key'sha512'NULLself::strlen($this->_key), 'encryption');

        return 
$this->{'_'.$this->_driver.'_decrypt'}($data$params);
    }

    
// --------------------------------------------------------------------

    /**
     * Decrypt via MCrypt
     *
     * @param    string    $data    Encrypted data
     * @param    array    $params    Input parameters
     * @return    string
     */
    
protected function _mcrypt_decrypt($data$params)
    {
        if ( ! 
is_resource($params['handle']))
        {
            return 
FALSE;
        }

        
// The greater-than-1 comparison is mostly a work-around for a bug,
        // where 1 is returned for ARCFour instead of 0.
        
if (($iv_size mcrypt_enc_get_iv_size($params['handle'])) > 1)
        {
            if (
mcrypt_enc_get_modes_name($params['handle']) !== 'ECB')
            {
                
$iv self::substr($data0$iv_size);
                
$data self::substr($data$iv_size);
            }
            else
            {
                
// MCrypt is dumb and this is ignored, only size matters
                
$iv str_repeat("x0"$iv_size);
            }
        }
        else
        {
            
$iv NULL;
        }

        if (
mcrypt_generic_init($params['handle'], $params['key'], $iv) < 0)
        {
            if (
$params['handle'] !== $this->_handle)
            {
                
mcrypt_module_close($params['handle']);
            }

            return 
FALSE;
        }

        
$data mdecrypt_generic($params['handle'], $data);
        
// Remove PKCS#7 padding, if necessary
        
if (in_array(strtolower(mcrypt_enc_get_modes_name($params['handle'])), array('cbc''ecb'), TRUE))
        {
            
$data self::substr($data0, -ord($data[self::strlen($data)-1]));
        }

        
mcrypt_generic_deinit($params['handle']);
        if (
$params['handle'] !== $this->_handle)
        {
            
mcrypt_module_close($params['handle']);
        }

        return 
$data;
    }

    
// --------------------------------------------------------------------

    /**
     * Decrypt via OpenSSL
     *
     * @param    string    $data    Encrypted data
     * @param    array    $params    Input parameters
     * @return    string
     */
    
protected function _openssl_decrypt($data$params)
    {
        if (
$iv_size openssl_cipher_iv_length($params['handle']))
        {
            
$iv self::substr($data0$iv_size);
            
$data self::substr($data$iv_size);
        }
        else
        {
            
$iv NULL;
        }

        return empty(
$params['handle'])
            ? 
FALSE
            
openssl_decrypt(
                
$data,
                
$params['handle'],
                
$params['key'],
                
1// DO NOT TOUCH!
                
$iv
            
);
    }

    
// --------------------------------------------------------------------

    /**
     * Get params
     *
     * @param    array    $params    Input parameters
     * @return    array
     */
    
protected function _get_params($params)
    {
        if (empty(
$params))
        {
            return isset(
$this->_cipher$this->_mode$this->_key$this->_handle)
                ? array(
                    
'handle' => $this->_handle,
                    
'cipher' => $this->_cipher,
                    
'mode' => $this->_mode,
                    
'key' => NULL,
                    
'base64' => TRUE,
                    
'hmac_digest' => 'sha512',
                    
'hmac_key' => NULL
                
)
                : 
FALSE;
        }
        elseif ( ! isset(
$params['cipher'], $params['mode'], $params['key']))
        {
            return 
FALSE;
        }

        if (isset(
$params['mode']))
        {
            
$params['mode'] = strtolower($params['mode']);
            if ( ! isset(
$this->_modes[$this->_driver][$params['mode']]))
            {
                return 
FALSE;
            }
            else
            {
                
$params['mode'] = $this->_modes[$this->_driver][$params['mode']];
            }
        }

        if (isset(
$params['hmac']) && $params['hmac'] === FALSE)
        {
            
$params['hmac_digest'] = $params['hmac_key'] = NULL;
        }
        else
        {
            if ( ! isset(
$params['hmac_key']))
            {
                return 
FALSE;
            }
            elseif (isset(
$params['hmac_digest']))
            {
                
$params['hmac_digest'] = strtolower($params['hmac_digest']);
                if ( ! isset(
$this->_digests[$params['hmac_digest']]))
                {
                    return 
FALSE;
                }
            }
            else
            {
                
$params['hmac_digest'] = 'sha512';
            }
        }

        
$params = array(
            
'handle' => NULL,
            
'cipher' => $params['cipher'],
            
'mode' => $params['mode'],
            
'key' => $params['key'],
            
'base64' => isset($params['raw_data']) ? ! $params['raw_data'] : FALSE,
            
'hmac_digest' => $params['hmac_digest'],
            
'hmac_key' => $params['hmac_key']
        );

        
$this->_cipher_alias($params['cipher']);
        
$params['handle'] = ($params['cipher'] !== $this->_cipher OR $params['mode'] !== $this->_mode)
            ? 
$this->{'_'.$this->_driver.'_get_handle'}($params['cipher'], $params['mode'])
            : 
$this->_handle;

        return 
$params;
    }

    
// --------------------------------------------------------------------

    /**
     * Get MCrypt handle
     *
     * @param    string    $cipher    Cipher name
     * @param    string    $mode    Encryption mode
     * @return    resource
     */
    
protected function _mcrypt_get_handle($cipher$mode)
    {
        return 
mcrypt_module_open($cipher''$mode'');
    }

    
// --------------------------------------------------------------------

    /**
     * Get OpenSSL handle
     *
     * @param    string    $cipher    Cipher name
     * @param    string    $mode    Encryption mode
     * @return    string
     */
    
protected function _openssl_get_handle($cipher$mode)
    {
        
// OpenSSL methods aren't suffixed with '-stream' for this mode
        
return ($mode === 'stream')
            ? 
$cipher
            
$cipher.'-'.$mode;
    }

    
// --------------------------------------------------------------------

    /**
     * Cipher alias
     *
     * Tries to translate cipher names between MCrypt and OpenSSL's "dialects".
     *
     * @param    string    $cipher    Cipher name
     * @return    void
     */
    
protected function _cipher_alias(&$cipher)
    {
        static 
$dictionary;

        if (empty(
$dictionary))
        {
            
$dictionary = array(
                
'mcrypt' => array(
                    
'aes-128' => 'rijndael-128',
                    
'aes-192' => 'rijndael-128',
                    
'aes-256' => 'rijndael-128',
                    
'des3-ede3' => 'tripledes',
                    
'bf' => 'blowfish',
                    
'cast5' => 'cast-128',
                    
'rc4' => 'arcfour',
                    
'rc4-40' => 'arcfour'
                
),
                
'openssl' => array(
                    
'rijndael-128' => 'aes-128',
                    
'tripledes' => 'des-ede3',
                    
'blowfish' => 'bf',
                    
'cast-128' => 'cast5',
                    
'arcfour' => 'rc4-40',
                    
'rc4' => 'rc4-40'
                
)
            );

            
// Notes:
            //
            // - Rijndael-128 is, at the same time all three of AES-128,
            //   AES-192 and AES-256. The only difference between them is
            //   the key size. Rijndael-192, Rijndael-256 on the other hand
            //   also have different block sizes and are NOT AES-compatible.
            //
            // - Blowfish is said to be supporting key sizes between
            //   4 and 56 bytes, but it appears that between MCrypt and
            //   OpenSSL, only those of 16 and more bytes are compatible.
            //   Also, don't know what MCrypt's 'blowfish-compat' is.
            //
            // - CAST-128/CAST5 produces a longer cipher when encrypted via
            //   OpenSSL, but (strangely enough) can be decrypted by either
            //   extension anyway.
            //   Also, it appears that OpenSSL uses 16 rounds regardless of
            //   the key size, while RFC2144 says that for key sizes lower
            //   than 11 bytes, only 12 rounds should be used. This makes
            //   it portable only with keys of between 11 and 16 bytes.
            //
            // - RC4 (ARCFour) has a strange implementation under OpenSSL.
            //   Its 'rc4-40' cipher method seems to work flawlessly, yet
            //   there's another one, 'rc4' that only works with a 16-byte key.
            //
            // - DES is compatible, but doesn't need an alias.
            //
            // Other seemingly matching ciphers between MCrypt, OpenSSL:
            //
            // - RC2 is NOT compatible and only an obscure forum post
            //   confirms that it is MCrypt's fault.
        
}

        if (isset(
$dictionary[$this->_driver][$cipher]))
        {
            
$cipher $dictionary[$this->_driver][$cipher];
        }
    }

    
// --------------------------------------------------------------------

    /**
     * HKDF
     *
     * @link    https://tools.ietf.org/rfc/rfc5869.txt
     * @param    $key    Input key
     * @param    $digest    A SHA-2 hashing algorithm
     * @param    $salt    Optional salt
     * @param    $length    Output length (defaults to the selected digest size)
     * @param    $info    Optional context/application-specific info
     * @return    string    A pseudo-random key
     */
    
public function hkdf($key$digest 'sha512'$salt NULL$length NULL$info '')
    {
        if ( ! isset(
$this->_digests[$digest]))
        {
            return 
FALSE;
        }

        if (empty(
$length) OR ! is_int($length))
        {
            
$length $this->_digests[$digest];
        }
        elseif (
$length > (255 $this->_digests[$digest]))
        {
            return 
FALSE;
        }

        
self::strlen($salt) OR $salt str_repeat(""$this->_digests[$digest]);

        
$prk hash_hmac($digest$key$saltTRUE);
        
$key '';
        for (
$key_block ''$block_index 1self::strlen($key) < $length$block_index++)
        {
            
$key_block hash_hmac($digest$key_block.$info.chr($block_index), $prkTRUE);
            
$key .= $key_block;
        }

        return 
self::substr($key0$length);
    }

    
// --------------------------------------------------------------------

    /**
     * __get() magic
     *
     * @param    string    $key    Property name
     * @return    mixed
     */
    
public function __get($key)
    {
        
// Because aliases
        
if ($key === 'mode')
        {
            return 
array_search($this->_mode$this->_modes[$this->_driver], TRUE);
        }
        elseif (
in_array($key, array('cipher''driver''drivers''digests'), TRUE))
        {
            return 
$this->{'_'.$key};
        }

        return 
NULL;
    }

    
// --------------------------------------------------------------------

    /**
     * Byte-safe strlen()
     *
     * @param    string    $str
     * @return    integer
     */
    
protected static function strlen($str)
    {
        return (
self::$func_override)
            ? 
mb_strlen($str'8bit')
            : 
strlen($str);
    }

    
// --------------------------------------------------------------------

    /**
     * Byte-safe substr()
     *
     * @param    string    $str
     * @param    int    $start
     * @param    int    $length
     * @return    string
     */
    
protected static function substr($str$start$length NULL)
    {
        if (
self::$func_override)
        {
            
// mb_substr($str, $start, null, '8bit') returns an empty
            // string on PHP 5.3
            
isset($length) OR $length = ($start >= self::strlen($str) - $start : -$start);
            return 
mb_substr($str$start$length'8bit');
        }

        return isset(
$length)
            ? 
substr($str$start$length)
            : 
substr($str$start);
    }
}
Онлайн: 0
Реклама