Noka/Infinity Encryption Version 1.00.00

Advertisement
directory-software-online-bussiness-script

<?php
###########################################################################################
#                                                                                         #
#    Copyright 2018 Khang H. Nguyen (kevinhg86)                                           #
#    E-mail: kevin@fai.host | Web: http://kevinhng86.iblog.website                        #
#    Contributors: https://github.com/kevinhng86/noka-encryption/blob/master/CONTRIBUTORS #                                                    #
#                                                                                         #    
#                                                                                         #
#    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.                                                                        #
#                                                                                         #
###########################################################################################
 
class noka_encryption
{   
    # Version number.
    public $version = '1.00.00'; 
    
    # This is the default algo for the hash() function if none was inputted. It also used by nk_hashc() and nk_hash() function.
    private $default_hash_algo = 'sha512';
    
    # This is used by the nk_hashc() and nk_hash() function.
    private $default_hash_key = '787f353e9aed9891ce8e5e06c7677d9b7f744f339c330e069c3aad3b62c85e30';
    
    # This is the default algo for the crypt() function. It also used by the nk_hashc() function.
    # sha512/sha256/blowfish
    private $default_crypt_algo = 'sha512';
    
    # This is the encryption algo that is used by the nk_hash(), nk_hashc(), and encrypt() function.
    private $default_encr_algo = 'aes-256-ctr';
    
    # This is the default encryption key that is used by the nk_hash() and nk_hashc(), and encrypt() function.
    private $default_encr_key = '07ea0b59140f53ae1a11a01313c2bddec90f2158459a9cfb26c57fd3c7564fed';
    
    # This array of algo name is used by nk_hashc(), nk_hash(), and hashx() function. Each function
    # required a different amount of algorithms. However, for them all to work, there must 
    # at least 3 algorithms that are defined in this array.
    private $hash_algos = array( 'ripemd320',
                                 'gost', 
                                 'haval256,5',
                               );
    
    # This array of keys is used by nk_hashc(), nk_hash(), and hashx() function. Each function
    # required a different amount of keys. However, for them all to work, there must 
    # at least 3 kyes that are defined in this array.
    private $hash_keys = array( '98c9b9afeb5774f0410505b2825d460e2af6cbef01dfd0ff21287ae93e916b70',
                                '8e2bbe0f642d4621a0a4976a82a531b06a4dc6941fbd7212f1225a60385c3347',
                                'be1ae0e606539a935ab92d110513bbbab6cba5d7baa3ef8f2646b99af285e0b9',
                               );
                               
    # All password that is going to be hashed need to be pad to the maximum allowable password's length.
    # This is to prevent timing guesses. This string is premade to save time and also make guessing the password's length
    # base on script execution time is almost an impossible task. Thus, this string must be as long as the maximum
    # allowable password length. Also, this pad string can't be random as we need to verify the hash later.
    private $pwd_pad_str = ')skvUtURrzhyY2@^nVZ`^1QwK8F8eK9b4^xym$@E';

    # Maximum allowable password length.
    private $pwd_len_max = 40;    

    # Default encryption round used by nk_encryption.
    private $encr_rounds = 7; 

    # Algos that will be utilized by nk_encryption.
    private $encr_algos = array('aes-256-xts', 'bf-ecb', 'aes-256-ctr', 'camellia-256-cbc', 'aes-128-cbc', 'aes-192-cbc', 'aes-192-ecb' );    

    # Keys that will be used by nk_encryption.
    private $encr_keys = array( '1451b406352fc73cf9fa522d1400f0cae932ff4a7d36c492e08f1d92e31ed718',
                                '67d40dcbb9183c4d5ebc4afc4d6c35bd835c295ef0d9b949255baad7277d8016',
                                'bdd78331a3c1c8de11509cd001db78f365f835201057dda53e36fea060670558',
                                '266b1659c1c402a5c35e308012413991a9cb0a14c3db2ddea71934a63d177a17',
                                '82be74af2a541bd1aeefdb2c12ec76f0',
                                'd7b7921cca7ff0bda12852e1020913312051666b24ae4c71',
                                '657df124b460a7a974953a8a8fa36566e15784214f7ee145');

    # Separator used for joining strings for the nk_hashc(), nk_hash(), scramble(), and the descramble() function.
    # A separator must be a one character and must not be a hexadecimal digits(a-f, A-F, and 0-9).
    private $sep = '|';

    # Configuration of the scrambler.
    private $scramble = array( 'random_min' => 3, 'random_max' => 9,
                               'original_min' => 3, 'original_max' => 9,
                               'char_from' => 1, 'char_to' => 255,
                               'min_char' => 15,
                             );

    # If hex_detect_key is set to true then keys that consisted of hexadecimal digits and with their length divisble by two will be convert
    # from hexadecimal to binary. hex_detect_key only accept a true or a false value. Any other's values will make all the functions
    # return a false value. This is to prevent mistake in placement of value. 
    # To override hex_detect_key as the function level, pass a false value or a true value to the 
    # hex_detect_key argument(if available) instead of a null value.
    private $hex_detect_key = true;

    # Future planned usage where if debug mode is on if there is a mistake in input an error will be thrown instead of returning a boolean false.
    private $debug = false;

    # Any random_salt_* function is stricly meant to generate a salt string for functions that depended on the crypt() function.
    # If random salt is needed, generate_key( $len ) and generate_random_str( $len ) can be used. Generate key will return a random
    # string with the defined in hexadecimal.
    public function random_salt_blowfish(){
        
        $salt_pre = '$2a$';
        $salt_post = '$';
        $salt_low = 4;
        $salt_high = 9;
        $salt_char = '0123456789abcdefghijklmopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ./';
        $salt_char_length = strlen($salt_char) - 1;
        $salt_length = 22;
        $salt_two_digit_cost = mt_rand( $salt_low , $salt_high );
        if ($salt_two_digit_cost < 10) $salt_two_digit_cost = "0" . $salt_two_digit_cost;        
        $str = $salt_pre . $salt_two_digit_cost . '$';

        for ( $i = 0 ; $i < $salt_length ; $i++ ){
            $str .=  $salt_char[mt_rand(0, $salt_char_length)];
        }

        return ($str . '$');
    }
    
    public function random_salt_sha512(){

        $salt_char = '0123456789abcdefghijklmopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
        $salt_char_length = strlen($salt_char) - 1;
        $min = 5000;
        $max = 10000;
        $len = 16;
        $str = '$6$rounds=' . mt_rand( $min, $max ) . '$';
     
        for ( $i = 0; $i < $len; $i++ ){
            $str .= $salt_char[ mt_rand(0, $salt_char_length) ]; 
        }
    
        return ($str . '$');
    }


    public function random_salt_sha256(){

        $salt_char = '0123456789abcdefghijklmopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
        $salt_char_length = strlen($salt_char) - 1;
        $min = 5000;
        $max = 10000;
        $len = 16;
        $str = '$5$rounds=' . mt_rand( $min, $max ) . '$';
     
        for ( $i = 0; $i < $len; $i++ ){
            $str .= $salt_char[ mt_rand(0, $salt_char_length) ]; 
        }
    
        return ($str . '$');
    }

    public function crypt ( $password , $algo = null ){

        if ( $algo === null ) $algo = $this->default_crypt_algo;

        if ( !$this->chk_str($password, 1) ) return false;
        if ( !is_string($algo) ) return false;    

        $algo = strtolower($algo);
                        
        if ( $algo === 'blowfish' ){
            $salt = $this->random_salt_blowfish();
        } else if ( $algo === 'sha256' ){
            $salt = $this->random_salt_sha256();
        } else if ( $algo === 'sha512' ){
            $salt = $this->random_salt_sha512();
        } else {
            return false;
        }
        
        $output = crypt($password, $salt);
        
        return (strlen($output) > 0 && $output !== '*0'? $output : false);
    }

    public function hash( $password , $key = null , $algo = null, $hex_detect_key = null ){

    ################################################################################################################################
    #                                                                                                                              #
    # Arguments: *password, key, algo, hex_detect_key                                                                              #
    # If "key" is an empty string or is null then the function will not use a key for hashing.                                     #
    # If "algo" is an empty string or is null then the function will use the value from the "hash_algo_1" variable of this class.  #
    # Although hash_hmac can take a 0 length key, the function hash() was chosen for hashing 0 length keys.                        #
    # If "hex_detect_key" is a boolean true then all keys that are divisible by 2 and contained only hexadecimal digits will       #
    # be converted to binary string. "hex_detect_key" only accepts boolean true/false, any other's values will generate an error   #
    # except of the case of a null value. Where null value is inputted then "hex_detect_key" will use the value of                 # 
    # $this->hex_detect_key. The value of $this->hex_detect_key must only be a boolean true/false.                                 #
    #                                                                                                                              #
    ################################################################################################################################
    
        if( $hex_detect_key === null ) $hex_detect_key = $this->hex_detect_key;
        if( $algo === null ) $algo = '';
        if( $key === null ) $key = '';
 
        if( !$this->chk_str($password, 1) ) return false;        
        if( !is_string($key) ) return false;
        if( !is_string($algo) ) return false;
        if( !is_bool($hex_detect_key) ) return false;
  
        if( strlen($algo) < 1 ) $algo = $this->default_hash_algo;

        if ( ($keylen = strlen($key)) > 0 ){
                        
            if ( $hex_detect_key === true ) {
                if ( ctype_xdigit($key) && $keylen % 2 === 0 ) $key = hex2bin($key);
            } 

            return hash_hmac($algo, $password, $key);
            
        } else {
            return hash($algo, $password);
        }
    }

    public function hashcrypt( array $args ){
        
    ####################################################################################################################################
    #                                                                                                                                  # 
    #    Arguments: array( *password: str, hash_key: str, hash_algo: str, mode: 0(raw)/1(hex)/2(base64).                               #
    #    This function does not do error checking on input, as the hash() and the crypt() function does all the error                  #
    #    checking. The only error checking this function does is for the "password" and the "mode" argument.                           #
    #                                                                                                                                  #                                   
    #    Values pass to the "mode" argument must be of an integer type. For currently this function supports 3 modes. Mode 0           #
    #    will return the output as the raw crypt string, mode 1 will return the output as a hexadecimal string, and mode 2             #
    #    will return the output as a base64 encoded string.                                                                            #
    #                                                                                                                                  # 
    #    Except the "password" arguments, all arguments that is not set will be set with a null value and the default                  #
    #    configuration from the class's variables will be used. For "mode", the default mode of this function is mode 0.               #
    #                                                                                                                                  #
    #                                                                                                                                  #
    ####################################################################################################################################
        
        if ( !isset($args['password']) ) return false;
        if ( !$this->chk_str($args['password'], 1) ) return false;
 
        if ( !isset($args['hash_key']) ) $args['hash_key'] = null;      
        if ( !isset($args['hash_algo']) ) $args['hash_algo'] = null;
        if ( !isset($args['crypt_algo']) ) $args['crypt_algo'] = null;
        if ( !isset($args['hex_detect_key']) ) $args['hex_detect_key'] = null;

        if ( isset($args['mode']) ){
            if ( !$this->chk_int($args['mode'], 0, 2) ) return false;
        } else {
            $args['mode'] = 0;
        }
        
        $password = $this->hash( $args['password'], $args['hash_key'], $args['hash_algo'], $args['hex_detect_key'] );
        if ( $password == false ) return false;

        $password = $this->crypt( $password , $args['crypt_algo'] );
        
        if ( $args['mode'] === 1 ) {
            $password = bin2hex( $password );
        } else if ( $args['mode'] === 2 ) {
            $password = base64_encode( $password );
        }

        return $password;
    }

    public function hashx ( $password, $round, $keys = null, $algos = null, $hex_detect_key = null ){
                
        if ( $keys === null ) $keys = $this->hash_keys;
        if ( $algos === null ) $algos = $this->hash_algos;
 
        if ( !$this->chk_str($password, 1) ) return false;
        if ( !$this->chk_int($round, 1) ) return false;
        if ( !is_array($keys) ) return false;
        if ( !is_array($algos) ) return false;
        if ( ( $ck = count($keys) ) < 1 ) return false;
        if ( ( $ca = count($algos) ) < 1 ) return false;

        $keys = array_values( $keys );
        $algos = array_values( $algos );
  
        for ( $i = 0; $i < $ck; $i++ ){
            if ( !is_string($keys[$i]) && $keys[$i] !== null ) return false;
        }
        
        for ( $i = 0; $i < $ca; $i++ ){
            if ( !is_string($algos[$i]) && $algos[$i] !== null ) return false;
        }
        
        $ik = 0;
        $ia = 0;

        for ( $i = 0; $i < $round; $i++ ){
            if ( $ik === $ck ) $ik = 0;
            if ( $ia === $ca ) $ia = 0;
            $password = $this->hash( $password, $keys[$ik], $algos[$ia], $hex_detect_key );
            if ( $password == false ) return false;
            $ik++;
            $ia++;            
        }

        return $password;        
    }

    public function nk_hashc ( $password, $hex_detect_key = null ){
        
        if ( !$this->chk_str($password, 1) ) return false;
        if ( ctype_xdigit($this->sep) || !$this->chk_str($this->sep, 1, 1) ) return false; 
        
        # To be as closely to the drawing model as possible, this function requires that there are at least two keys 
        # and two algorithms that are going to be used for the hashing process.
        # The keys and algorithms array that is going to be used for this function are defined by the $this->hash_algos
        # and $this->hash_keys variable. However, the hashx() function only require one key and one algorithms in their
        # respective array. This function does not check for error. So if you placed an empty string in the array
        # it will still use it as the key. This function's counter part, verify_nk_hashc() possessed the same characteristic. 
        if ( !$this->chk_array($this->hash_keys, 2) ) return false;
        if ( !$this->chk_array($this->hash_algos, 2) ) return false;

        # Pad the password so that all passwords are the same in length. This is to prevent timing guessing.
        $password = $this->pad( $password, $this->pwd_pad_str, $this->pwd_len_max );

        # Encrypt the password before hashing. The encrypted version is in index 0. While the IV is in index 1.
        $password = $this->encrypt( $password, $this->default_encr_key, $this->default_encr_algo, null, null, $hex_detect_key );
        
        # If the encryption process return something equal to a false value then a boolean false value will be returned.
        if ( $password == false ) return false;
        
        # Create two hash version of the password.
        # The hash crypt version of the encrypted password.
        # Note that, except of the index 'password' and 'mode', all indexes can be defined with a null value.
        # This defining method below is just to demonstrate the hashcrypt() function and also to 
        # keep track of which variable is used for what method.  
        $hashcrypt = $this->hashcrypt( array( 'password' => $password[0],
                                            'hash_key' => $this->default_hash_key,
                                            'hash_algo' => $this->default_hash_algo,
                                            'crypt_algo' => $this->default_crypt_algo,
                                            'mode' => 1,
                                            'hex_detect_key' => $hex_detect_key,
                                            ) );
        
        if ( $hashcrypt == false ) return false;                                    

        # The hash double version of the encrypted password.
        $hashdouble = $this->hashx( $password[0], 2, $this->hash_keys, $this->hash_algos, $hex_detect_key );
                                                
        if ( $hashdouble == false ) return false;

        # The password string is now the hash crypt version, a seperator, a double hash version, and the IV.
        # All values, except the separator, are stored as hexadecimal strings.
        $password = $hashcrypt . $this->sep . $hashdouble . $this->sep . bin2hex($password[1]);

        return $password;
    }
    
    public function nk_hash ( $password, $round = null, $keys = null, $algos = null, $hex_detect_key = null ){

        if ( $round === null ) $round = 3;
        if ( $keys === null ) $keys = $this->hash_keys;
        if ( $algos === null ) $algos = $this->hash_algos;

        if ( ctype_xdigit($this->sep) || !$this->chk_str($this->sep, 1, 1) ) return false; 
        if ( !$this->chk_str($password, 1) ) return false;
        if ( !$this->chk_int($round, 3) ) return false;
        if ( !is_array($keys) ) return false;
        if ( !is_array($algos) )return false;
        if ( ( $ck = count($keys) ) < 3 ) return false;
        if ( ( $ca = count($algos) ) < 3 ) return false;

        $keys = array_values( $keys );
        $algos = array_values( $algos );
        
        # This function strictly checked to be sure that there is at least one character in a key.
        # Also, it check that each string in the algorithms array contained at least one character.
        # This is for security reason, so that the benefits of this method can be utilized to the 
        # maximum extend.
        for ( $i = 0; $i < $ck; $i++){
            if ( !$this->chk_str($keys[$i], 1) ) return false;
        }
        
        for ( $i = 0; $i < $ca; $i++){
            if ( !$this->chk_str($algos[$i], 1) ) return false;
        }

        $password = $this->pad( $password, $this->pwd_pad_str, $this->pwd_len_max );
        $password = $this->encrypt( $password, $this->default_encr_key, $this->default_encr_algo, null, null, $hex_detect_key );
        if ( $password == false ) return false;

        $hash_1 = $this->hash( $password[0], $this->default_hash_key, $this->default_hash_algo, $hex_detect_key );
        if ( $hash_1 == false ) return false;
        
        $olen = $len = strlen($hash_1);        
        $pad_str = '';
        
        while ( $len / $round < 8 ){
            $pad_str .= $hash_1;
            $len += $olen;
        }

        $hash_1 .= $pad_str;

        if ( ( $mod_round = $len % $round ) !== 0 ){
            $hash_1 .= substr($hash_1, 0, $round - $mod_round );
            $len += $round - $mod_round;
        }

        $hash_1 = str_split( $hash_1, $len / $round );
        $output = '';
        $temp = '';
        $ik = 0;
        $ia = 0;
        
        for ( $i = 0; $i < $round; $i++ ){        
            if ( $ik === $ck ) $ik = 0;
            if ( $ia === $ca ) $ia = 0;
            
            $temp = $this->hash( $password[0] . $hash_1[$i], $keys[$ik], $algos[$ia], $hex_detect_key );
            if ( $temp == false ) return false;
            $output .= $temp;

            $ik++;
            $ia++;
        }

        $output .= $this->sep . bin2hex($password[1]);
                
        return $output;
    }


    public function verify_hash( $password , $hash , $key = null , $algo = null, $hex_detect_key = null ){

        if ( $key === null ) $key = '';
        if ( $algo === null ) $algo = '';
        
        if ( !$this->chk_str($password, 1) ) throw new Exception('verify_hash(): $password must be a string with a length of at least 1.');
        if ( !$this->chk_str($hash, 1) ) throw new Exception('verify_hash(): $hash must be a string with a length of at least 1.');
        if ( !is_string($key) ) throw new Exception('verify_hash(): $key must be a string');
        if ( !is_string($algo) ) throw new Exception('verify_hash(): $algo must be a string.');
        if ( !is_bool($hex_detect_key) && $hex_detect_key !== null ) throw new Exception('verify_hash(): $hex_detect_key must be a boolean true/false.');

        return $this->hash( $password, $key, $algo, $hex_detect_key ) === $hash;
    }

    public function verify_hashx( $password, $hash, $round, $keys = null, $algos = null, $hex_detect_key = null ){

        if ( $keys === null ) $keys = $this->hash_keys;
        if ( $algos === null ) $algos = $this->hash_algos;
        
        if ( !$this->chk_str($password, 1) ) throw new Exception('verify_hashx(): $password must be a string with a length of at least 1.');
        if ( !$this->chk_str($hash, 1) ) throw new Exception('verify_hashx(): $hash must be a string with a length of at least 1.');
        if ( !$this->chk_int($round, 1) ) throw new Exception('verify_hashx(): $round must be an integer with a value of at least 1.');
        if ( !$this->chk_array($keys, 1) ) throw new Exception('verify_hashX(): $keys must be an array with at least 1 index.');
        if ( !$this->chk_array($algos, 1) ) throw new Exception('verify_hashx(): $algos must be an array with at least 1 index.');
        if ( !is_bool($hex_detect_key) && $hex_detect_key !== null) throw new Exception('verify_hashx(): $hex_detect_key must be a boolean true/false.');
        
        $keys = array_values($keys);
        $algos = array_values($algos);
        
        for ( $i = 0; $i < count($keys); $i++ ){
            if ( !is_string($keys[$i]) && $keys[$i] !== null ) throw new Exception('verify_hashx(): indexes of $keys must either be a string or a null value');
        }
        
        for ( $i = 0; $i < count($algos); $i++ ){
            if ( !is_string($algos[$i]) && $algos[$i] !== null ) throw new Exception('verify_hashx(): indexes of $algos must either be a string or a null value');
        }
        
        return $hash === $this->hashx( $password, $round, $keys, $algos, $hex_detect_key );
    }

    # Array: *str password, *str crypt_string, str hash_key, str hash_algo, boolean hex_detect_key
    public function verify_hashcrypt( array $args ){
        
        if ( !isset($args['hash_key']) ) $args['hash_key'] = null;
        if ( !isset($args['hash_algo']) ) $args['hash_algo'] = null;
        if ( !isset($args['mode']) ) $args['mode'] = 0;
        if ( !isset($args['hex_detect_key']) ) $args['hex_detect_key'] = null;
                         
        if ( !isset($args['password']) ) throw new Exception('verify_hashcrypt(): $args["password"] must be set.');
        if ( !$this->chk_str($args['password'], 1) ) throw new Exception('verify_hashcrypt(): $args["password"] must be a string with a length of at least 1.');
        if ( !isset($args['crypt_string']) ) throw new Exception('verify_hashcrypt(): $args["crypt_string"] must be set.');
        if ( !$this->chk_str($args['crypt_string'], 1) ) throw new Exception('verify_hashcrypt(): $args["crypt_string"] must be a string with a length of at least 1.');
        if ( !is_string($args['hash_key']) && $args['hash_key'] !== null ) throw new Exception('verify_hashcrypt(): $args["hash_key"] must be a string or a value of null.');
        if ( !is_string($args['hash_algo']) && $args['hash_algo'] !== null ) throw new Exception('verify_hashcrypt(): $args["hash_algo"] must be a string or a value of null.');
        if ( !$this->chk_int($args['mode'], 0, 2) ) throw new Exception('verify_hashcrypt(): $args["mode"] must be an integer with a value from 0 to 2.');
        if ( !is_bool($args['hex_detect_key']) && $args['hex_detect_key'] !== null )  throw new Exception('verify_hashcrypt(): $args["hex_detect_key"] must be a boolean true/false or a value of null.');

        $args['password'] = $this->hash( $args['password'], $args['hash_key'], $args['hash_algo'], $args['hex_detect_key'] );        
        if ( $args['password'] == false ) return false;
        
        if ( $args['mode'] === 1 ){
            $args['crypt_string'] = hex2bin($args['crypt_string']);
        } else if ( $args['mode'] === 2 ){
            $args['crypt_string'] = base64_decode($args['crypt_string']);
        }
        
        return password_verify( $args['password'], $args['crypt_string'] );
    }

    public function verify_nk_hashc ( $password , $hash, $hex_detect_key = null ){

        if ( !$this->chk_str($password, 1) ) throw new Exception('verify_nk_hashc(): $password must be a string with a length of at least 1.');
        if ( !$this->chk_str($hash, 1) ) throw new Exception('verify_nk_hashc(): $hash must be a string with a length of at least 1.');
        if ( !$this->chk_array($this->hash_keys, 2) ) throw new Exception('verify_nk_hashc(): $this->hash_keys must have at least 2 indexes.');
        if ( !$this->chk_array($this->hash_algos, 2) ) throw new Exception('verify_nk_hashc(): $this->hash_algos must have at least 2 indexes.');
        if ( !is_bool($hex_detect_key) && $hex_detect_key !== null ) throw new Exception('verify_nk_hashc(): $hex_detect_key must be a boolean true/false.');
        if ( ctype_xdigit($this->sep) || !$this->chk_str($this->sep, 1, 1) ) throw new Exception('verify_nk_hashc(): $this->sep must be a string with just one character and that character must not be a hexadecimal digit.');
        $hash = explode( $this->sep, $hash );
        if ( count($hash) < 3 ) throw new Exception('verify_nk_hashc(): something is wrong with the hash string. It could not be divided by 3 using the specified separator.');

        ################################################################
        #                                                              #
        # Hashcrypt, hex to bin.                                       #
        # 0 = Crypt() string.                                          #
        # 1 = Double hash string.                                      #
        # 2 = IV for encryption.                                       # 
        #                                                              #
        ################################################################
        #                                                              #
        # Futures updates: there might be a check here to throw an     #
        # error instead of relying the error that would be generated   # 
        # by the hex2bin() function. Here we can also pass the hex     #
        # version of the crypt_string to verify_hashcrypt() with mode  #
        # 1. Nonetheless, having this here would be more flexible      # 
        # for error handling in futures updates.                       #
        #                                                              #
        ################################################################
        $hash[0] = hex2bin( $hash[0] );
        $hash[2] = hex2bin( $hash[2] );

        # Since noka_hashc padded the password.
        # Thus, the password is padded before being encrypted.
        $password = $this->pad( $password, $this->pwd_pad_str, $this->pwd_len_max );
        
        # Encrypt the password before hashing. This time, we only need the encryption string and not the IV.
        $password = $this->encrypt( $password, $this->default_encr_key, $this->default_encr_algo, $hash[2], null, $hex_detect_key )[0];
        if ( $password === null ) throw new Exception('verify_nk_hashc(): possible incorrect format for hash string.');
        
        # Verify the hash crypt() version of the password. 
        $hc = $this->verify_hashcrypt( array( 'password' => $password,
                                              'crypt_string' => $hash[0],
                                              'hash_key' => $this->default_hash_key,
                                              'hash_algo' => $this->default_hash_algo,
                                              'hex_detect_key' => $hex_detect_key,
                                              'mode' => 0,
                                             ));
                                            
        # Verify the double hash version of the password.
        $hx = $this->verify_hashx( $password, $hash[1], 2, $this->hash_keys, $this->hash_algos, $hex_detect_key );
                                                
        # Only return true if both, the hash crypt() and the hash hash version of the password matched the original(Stored) hash.
        if ( $hc === true && $hx === true ){
            return true;
        } else {
            return false;
        }
    }
    
    public function verify_nk_hash( $password , $hash, $round = null, $keys = null, $algos = null, $hex_detect_key = null ){

        if ( $round === null ) $round = 3;
        if ( $keys === null ) $keys = $this->hash_keys;
        if ( $algos === null ) $algos = $this->hash_algos;
     
        if ( ctype_xdigit($this->sep) || !$this->chk_str($this->sep, 1, 1) ) throw new Exception('verify_nk_hash(): $this->sep must be a string with just one character and that character must not be a hexadecimal digit.'); 
        if ( !$this->chk_str($password, 1) ) throw new Exception('verify_nk_hash(): $password must be a string with a length of at least 1.');
        if ( !$this->chk_str($hash, 1) ) throw new Exception('verify_nk_hash(): $hash must be a string with a length of at least 1.');
        if ( !$this->chk_int($round, 3) ) throw new Exception('verify_nk_hash(): $round must be an integer with a value of at least 3.');        
        if ( !is_array($keys) ) throw new Exception('verify_nk_hash(): $keys must be an array.');
        if ( !is_array($algos) ) throw new Exception('verify_nk_hash(): $algos must be an array.');
        if ( ( $ck = count($keys) ) < 3 ) throw new Exception('verify_nk_hash(): $keys or $this->hash_keys must have at least 3 indexes.');
        if ( ( $ca = count($algos) ) < 3 ) throw new Exception('verify_nk_hash(): $algos or $this->hash_algos must have at least 3 indexes.');
        if ( !is_bool($hex_detect_key) && $hex_detect_key !== null ) throw new Exception('verify_nk_hash(): $hex_detect_key must be a boolean true/false.');
        
        $keys = array_values( $keys );
        $algos = array_values( $algos );
        
        for ( $i = 0; $i < $ck; $i++){
            if ( !$this->chk_str($keys[$i], 1) ) throw new Exception('verify_nk_hash(): $keys\'s indexes must all be strings with at least one character.');
        }
        
        for ( $i = 0; $i < $ca; $i++){
            if ( !$this->chk_str($algos[$i], 1) ) throw new Exception('verify_nk_hash(): $algos\'s indexes must all be strings with at least one character.');
        }
        
        $hash = explode( $this->sep, $hash );
        
        if ( !$this->chk_array($hash, 2, 2) ) throw new Exception('verify_nk_hash(): something is wrong with the hash string, incorrect format.');
        if ( !ctype_xdigit($hash[0]) ) throw new Exception('verify_nk_hash(): something is wrong with the hash string, incorrect format.');
        if ( ( $ivlen = strlen($hash[1]) ) > 0 ){
            if ( !ctype_xdigit($hash[1]) || $ivlen % 2 !== 0 ) throw new Exception('verify_nk_hash(): something is wrong with the hash string, incorrect format.');
            $hash[1] = hex2bin( $hash[1] );
        }
        
        $password = $this->pad( $password, $this->pwd_pad_str, $this->pwd_len_max );
        $password = $this->encrypt( $password, $this->default_encr_key, $this->default_encr_algo, $hash[1], null, $hex_detect_key )[0];
        if ( $password == false ) throw new Exception('verify_nk_hash(): something is wrong, the encryption process yielded error.');
    
        $hash_1 = $this->hash( $password, $this->default_hash_key, $this->default_hash_algo, $hex_detect_key );
        if ( $hash_1 == false ) throw new Exception('verify_nk_hash(): something is wrong, the hashing round #1 yielded error.');  
        
        $olen = $len = strlen($hash_1);
        $pad_str = '';
        
        while ( $len / $round < 8 ){
            $pad_str .= $hash_1;
            $len += $olen;
        }
        
        $hash_1 .= $pad_str;

        if ( ( $mod_round = $len % $round ) !== 0 ){
            $hash_1 .= substr($hash_1, 0, $round - $mod_round );
            $len += $round - $mod_round;
        }

        $hash_1 = str_split( $hash_1, $len / $round );
        $cmpr_str = '';
        $temp = '';
        $ik = 0;
        $ia = 0;
        
        for ( $i = 0; $i < $round; $i++ ){        
            if ( $ik === $ck ) $ik = 0;
            if ( $ia === $ca ) $ia = 0;
            
            $temp = $this->hash( $password . $hash_1[$i], $keys[$ik], $algos[$ia], $hex_detect_key );
            if ( $temp == false ) throw new Exception('verify_nk_hash(): something is wrong, the hashing round #'. $i + 2 .' yeilded error.');
            $cmpr_str .= $temp;
                
            $ik++;
            $ia++;
        }

        if ( $hash[0] === $cmpr_str ){
            return true;
        } else {
            return false;
        }
    } 
    
    # Arguments: *msg, key, algo, iv, options, hex_detect_key
    function encrypt( $msg, $key = null, $algo = null, $iv = null, $options = null, $hex_detect_key = null ) {
    
        if ( $key === null ) $key = $this->default_encr_key;
        if ( $algo === null ) $algo = $this->default_encr_algo;
        if ( $options === null ) $options = OPENSSL_RAW_DATA;
        if ( $iv === null ) $iv = '';
        if ( $hex_detect_key === null ) $hex_detect_key = $this->hex_detect_key;
        
        if ( !$this->chk_str($msg, 1) ) return false;
        if ( !is_string($key) ) return false;
        if ( ( $keylen = strlen($key) ) < 1 ) return false;
        if ( !is_string($algo) ) return false;
        if ( !in_array($algo, openssl_get_cipher_methods()) ) return false;
        if ( !is_string($iv) ) return false;
        if ( !is_bool($hex_detect_key) ) return false;
        
        if ( $hex_detect_key === true ){
            if ( ctype_xdigit($key) && $keylen % 2 === 0 ) $key = hex2bin($key);
        }
        
        $ivlen = openssl_cipher_iv_length($algo);
        
        if ( strlen($iv) < 1 && $ivlen > 0 ) $iv = $ivlen > 0? openssl_random_pseudo_bytes($ivlen) : '';
        if ( strlen($iv) !== $ivlen ) return false;

        $output = openssl_encrypt($msg, $algo, $key, $options, $iv);

        if ( $output === false ) return false;

        return array($output, $iv);
    }

    # Arguments: *cipher Text, key, algo, iv, options, hex_detect_key 
    function decrypt( $cipher_text, $key = null, $algo = null, $iv = null, $options = null, $hex_detect_key = null ){
        
        if ( $key === null ) $key = $this->default_encr_key;
        if ( $algo === null ) $algo = $this->default_encr_algo;
        if ( $iv === null ) $iv = '';
        if ( $options === null ) $options = OPENSSL_RAW_DATA;
        if ( $hex_detect_key === null ) $hex_detect_key = $this->hex_detect_key;

        if ( !$this->chk_str($cipher_text, 1) ) throw new Exception('decrypt(): $cipher_text must be a string with a length of at least 1.');
        if ( !is_string($key) ) throw new Exception('decrypt(): $key must be a string with a length of at least 1.');
        if ( ( $keylen = strlen($key) ) < 1 ) throw new Exception('decrypt(): $key must be a string with a length of at least 1.');
        if ( !is_string($algo) ) throw new Exception('decrypt(): $algo must be a string.');
        if ( !in_array($algo, openssl_get_cipher_methods()) ) throw new Exception('decrypt(): $algo\'s encryption algorithm is unknown or not supported.');
        if ( !is_string($iv) ) throw new Exception('decrypt(): $iv must be a string or a null value.');    
        if ( strlen($iv) !== openssl_cipher_iv_length($algo) ) throw new Exception('decrypt(): $iv\'s length must match the IV length of the used algorithm.');        
        if ( !is_bool($hex_detect_key) ) throw new Exception('decrypt(): $hex_detect_key must be a boolean true/false or a null value to use the default value of $this->hash_detect_key, of which, must also be a boolean true/false.');
        
        if ( $hex_detect_key === true ){
            if ( ctype_xdigit($key) && $keylen % 2 === 0 ) $key = hex2bin($key);
        }

        return openssl_decrypt($cipher_text, $algo, $key, $options, $iv);
    }


    # Arguments: *text, *round, array keys, array algos, mode, hex_detect_key
    public function nk_encrypt( $text, $round, $keys = null, $algos = null, $mode = 2, $hex_detect_key = null){

        if ( $algos === null ) $algos = $this->encr_algos;
        if ( $keys === null ) $keys = $this->encr_keys;

        if ( !$this->chk_str($text, 1) ) return false;
        if ( !$this->chk_int($round, 1) ) return false;
        if ( !is_array($keys) ) return false;
        if ( !is_array($algos) ) return false; 
        if ( ( $ck = count($keys) ) < 1 ) return false;
        if ( ( $ca = count($algos) ) < 1 ) return false;
        if ( !$this->chk_int($mode, 0, 2) ) return false;

        $keys = array_values( $keys );
        $algos = array_values( $algos );
        # The largest iv_length at the time of writing this script is 16. Nonetheless, as technology change this may change.
        # If $common_iv_length value must be the same for both nk_decrypt() and nk_encrypt().
        # This is to prevent guessing the algorithm used based on the IV length.
        # Another method of which may implement in future versions is prevent guessing the algorithms used based on the final
        # blocksize of the encryption. Nonetheless, this version does not implement that.
        $common_iv_length = 16;

        for ( $i = 0; $i < $ck; $i++ ){
            if ( !$this->chk_str($keys[$i], 1) ) return false;
        }

        for ( $i = 0; $i < $ca; $i++ ){
            if ( !is_string($algos[$i]) ) return false;
            if ( !in_array($algos[$i], openssl_get_cipher_methods()) ) return false;
        }

        $text = $this->scramble($text);
        $text = $this->random_pad($text);    
        $ik = 0;
        $ia = 0;

        for ( $i = 0; $i < $round; $i++ ){
            if ( $ik >= $ck ) $ik = 0;
            if ( $ia >= $ca ) $ia = 0;
            
            $text = $this->encrypt( $text, $keys[$ik], $algos[$ia], null, null, $hex_detect_key );
            if ( $text === false || !is_array($text) ) return false;
            if ( ( $ivlen = strlen($text[1]) ) < $common_iv_length ) $text[1] = openssl_random_pseudo_bytes( $common_iv_length - $ivlen ) . $text[1];
            
            $text = $text[0] . $text[1];

            $ia++; $ik++;
        }
        
        if ( $mode === 1 ) {
            $text = bin2hex($text);
        } else if ( $mode === 2 ) {
            $text = base64_encode($text);
        }
        
        return $text;
    }

    # Arguments:  *c_text, *round, array keys, array algos, input_mode, hex_detect_key
    public function nk_decrypt( $c_text, $round, $keys = null, $algos = null, $input_mode = 2, $hex_detect_key = null ) {
        
        if ( $algos === null ) $algos = $this->encr_algos;
        if ( $keys === null ) $keys = $this->encr_keys;

        if ( !$this->chk_str($c_text, 1) ) throw new Exception('nk_decrypt(): $c_text must be a string with a length of at least 1.');
        if ( !$this->chk_int($round, 1) ) throw new Exception('nk_decrypt(): $round must be an integer with a value of at least 1.');

        if ( !is_array($keys) ) throw new Exception('nk_decrypt(): $keys must be an array with at least one index.');
        if ( !is_array($algos) ) throw new Exception('nk_decrypt(): $algos must be an array with at least one index.'); 
        if ( ( $ck = count($keys) ) < 1 ) throw new Exception('nk_decrypt(): $keys must be an array with at least one index.');
        if ( ( $ca = count($algos) ) < 1 ) throw new Exception('nk_decrypt(): $algos must be an array with at least one index.');
        if ( !$this->chk_int($input_mode, 0, 2) ) throw new Exception('nk_decrypt(): $input_mode must be an integer with a value from 0 to 2.');
        if ( !is_bool($hex_detect_key) && $hex_detect_key !== null ) throw new Exception('nk_decrypt(): hex_detect key must be a boolean true/false or null to used the default value of $this->hex_detect_key, of which, must also be a boolean true/false.');
        
        $keys = array_values($keys);
        $algos = array_values($algos);
        $common_iv_length = 16; 

        for ( $i = 0; $i < $ck ; $i++ ){
            if ( !$this->chk_str($keys[$i], 1) ) throw new Exception('nk_decrypt(): $keys["'. $i .'"] must be a string with a length of at least 1.');
        }

        for ( $i = 0; $i < $ca ; $i++ ){
            if ( !is_string($algos[$i]) ) throw new Exception('nk_decrypt(): $algos["'. $i .'"] must be a string.');
            if ( !in_array($algos[$i], openssl_get_cipher_methods()) ) throw new Exception("nk_decrypt(): \$algos['{$i}]') = {$algos[$i]} is an unknown or unsupported encryption algorithm.");
        }

        if ( $input_mode === 1 ){
            $c_text = hex2bin($c_text);
        } else if ( $input_mode === 2 ){
            $c_text = base64_decode($c_text);
        }

        $ik = 0;
        $ia = 0;
        $iv = '';
        $ivlen = 0;
        $r = array();
        
        for ( $i = 0; $i < $round; $i++ ){
            if ( $ik >= $ck ) $ik = 0;
            if ( $ia >= $ca ) $ia = 0;

            $r[$i] = array( 'k' => $ik, 'a' => $ia );
            $ik++; $ia++;
        }


        for ( $i = $round - 1; $i > -1; $i-- ){
            $ivlen = openssl_cipher_iv_length( $algos[$r[$i]['a']] ) ;

            if ( $ivlen > 0 ) {
                $iv = substr( $c_text, $ivlen * -1 );
                $c_text = $ivlen < $common_iv_length? substr( $c_text, 0, strlen($c_text) - $common_iv_length ) : substr( $c_text, 0, strlen($c_text) - $ivlen );
            } else {
                $iv = '';
                $c_text = substr( $c_text, 0, strlen($c_text) - $common_iv_length );
            }

            $c_text = $c_text;
            $c_text = $this->decrypt( $c_text, $keys[ $r[$i]['k'] ], $algos[ $r[$i]['a'] ], $iv, null, $hex_detect_key );
        }

        $c_text = $c_text;
        $c_text = $this->random_pad_remove( $c_text );
        $c_text = $this->descramble( $c_text );

        return $c_text;
    }

    function generate_random_str( $len ){
        
        if( !$this->chk_int($len, 1) ) return false;
        
        $chars = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJLKMNOPQRSTUVWXYZ0123456789-=`~!@#$%^&*()_+';
        $chars_len = strlen($chars) - 1;
        $output = '';
        
        for ( $i = 0; $i < $len; $i++ ){
            $output .= $chars[rand(0, $chars_len)];
        }

        return $output;
    }
    
    function generate_key( $len ){
        if( !$this->chk_int( $len, 1 ) ) return false;
        return bin2hex( openssl_random_pseudo_bytes( $len ) );
    }

    function pad( $password , $pad_str = null, $pad_len = null, $side = STR_PAD_LEFT ){
        
        if ( $pad_str === null ) $pad_str = $this->pwd_pad_str;
        if ( $pad_len === null ) $pad_len = $this->pwd_len_max;
        
        if ( !$this->chk_str($password, 1) ) return false;
        if ( !is_string($pad_str) ) return false;
        if ( !is_int($pad_len) ) return false;
        if ( !$this->chk_int($side, 0, 1) ) return false;
        if ( $pad_len !== strlen($pad_str) ) return false;
        
        # There is no reason to prevent timing guessing if the password is longer than the maximum allowable password length.
        # As that information is most likely available to anyone. Also, in a scenario like that, most program would built with an error
        # checking mechanism that would most likely throw an error.
        if ( strlen($password) > $pad_len ) return $password;

        if ( $side === STR_PAD_LEFT ){
            $password = substr($pad_str . $password, $pad_len * -1);
        } else if ( $side === STR_PAD_RIGHT ) {
            $password = substr($password . $pad_str, 0, $pad_len);
        }

        return $password;
    }
    
    function scramble ( $str, $args = null ){

        $ceil = 255;

        if ( $args === null ) $args = array();
        if ( !is_array($args) )return false;
        if ( !is_string( $str ) ) return false;
        if ( ($len = strlen($str)) < 1 ) return false; 

        if ( !isset($args['min_char']) ) $args['min_char'] = $this->scramble['min_char'];
        if ( !isset($args['random_min']) ) $args['random_min'] = $this->scramble['random_min'];
        if ( !isset($args['random_max']) ) $args['random_max'] = $this->scramble['random_max'];
        if ( !isset($args['original_min']) ) $args['original_min'] = $this->scramble['original_min'];
        if ( !isset($args['original_max']) ) $args['original_max'] = $this->scramble['original_max'];
        if ( !isset($args['char_from']) ) $args['char_from'] = $this->scramble['char_from'];
        if ( !isset($args['char_to']) ) $args['char_to'] = $this->scramble['char_to'];

        if ( !$this->chk_int( $args['min_char'], 1 ) ) return false;
        if ( !$this->chk_int( $args['random_min'], 1, 255 ) ) return false;
        if ( !$this->chk_int( $args['random_max'], 1, 255 ) ) return false;
        if ( !$this->chk_int( $args['original_min'], 1, 255 ) ) return false;
        if ( !$this->chk_int( $args['original_max'], 1, 255 ) ) return false;
        if ( !$this->chk_int( $args['char_from'], 1, 255 ) ) return false;
        if ( !$this->chk_int( $args['char_to'], 1, 255 ) ) return false;

        if ( $args['original_max'] < $args['original_min'] ) return false; 
        if ( $args['random_max'] < $args['random_min'] ) return false; 
        if ( $args['char_to'] < $args['char_from'] ) return false; 
        if ( $args['min_char'] + $args['original_max'] > $ceil ) return false;     
 
        $padded = 1;
        $pad_str = '';
        $blk_random = mt_rand( 1, 255 );
        $blk_original = mt_rand( 1, 255 );
        $mode = mt_rand( 1, 255 );
        $output = chr( $blk_random ) . chr( $blk_original ) . chr( $mode );    
        $blk_random = $args['random_min'] + $blk_random % ($args['random_max'] + 1 - $args['random_min']);
        $blk_original = $args['original_min'] + $blk_original % ($args['original_max'] + 1 - $args['original_min']);

        if ( isset($args['mode']) ){
            if ( !$this->chk_int($args['mode'], 0, 3) ) return false;
            $mode = array( $args['mode'], 
                           $mode % 2 === 0,
                         );
        } else {
            $mode = array( 0 + $mode % (3 + 1 - 0), 
                           $mode % 2 === 0,
                         );
        }
    
        if ( $mode[1] === true ){
        
            while ( $len < $args['min_char'] ){
                $str .= chr( mt_rand($args['char_from'], $args['char_to']) );
                $padded++;
                $len++;
            }
        
            while ( $len % $blk_original !== 0 ){
                $str .= chr( mt_rand($args['char_from'], $args['char_to']) );
                $padded++;
                $len++;
            }
     
        } else {
        
            while ( $len < $args['min_char'] ){
                $pad_str .= chr( mt_rand($args['char_from'], $args['char_to']) );
                $padded++;
                $len++;
            }
        
            while ( $len % $blk_original !== 0 ){
                $pad_str .= chr( mt_rand($args['char_from'], $args['char_to']) );
                $padded++;
                $len++;
            }
        
            $str = $pad_str . $str;
        }
    
        $str = str_split( $str, $blk_original );
     
        if ( $mode[0] === 0 ){
               
            for ( $i = 0; $i < count($str); $i++ ){
                $pad_str = '';
                $ind = 0;

                while( $ind < $blk_random ){
                    $pad_str .= chr( mt_rand($args['char_from'], $args['char_to']) );
                    $ind++;
                }
            
                $str[$i] = $pad_str . $str[$i];
            }
        
        } else if ( $mode[0] === 1 ){
        
            for ( $i = 0; $i < count($str); $i++ ){
                $pad_str = '';
                $ind = 0;

                while( $ind < $blk_random ){
                    $pad_str .= chr( mt_rand($args['char_from'], $args['char_to']) );
                    $ind++;
                }
            
                $str[$i] .= $pad_str;
            }

        } else if ( $mode[0] === 2 ){

            for ( $i = 0; $i < count($str); $i++ ){
                $pad_str = '';
                $ind = 0;

                while( $ind < $blk_random ){
                    $pad_str .= chr( mt_rand($args['char_from'], $args['char_to']) );
                    $ind++;
                }
            
                if ( $i % 2 === 0 ){
                    $str[$i] .= $pad_str;
                } else {
                    $str[$i] = $pad_str . strrev( $str[$i] );
                }
            }

        } else if ( $mode[0] === 3 ){
        
            $next = $mode[1];

            for ( $i = 0; $i < count($str); $i++ ){
                $pad_str = '';
                $ind = 0;

                while( $ind < $blk_random ){
                    $pad_str .= chr( mt_rand($args['char_from'], $args['char_to']) );
                    $ind++;
                }
            
                if ( $next === true ){
                    $str[$i] .= $pad_str ;
                } else {
                    $str[$i] = $pad_str . strrev( $str[$i] );
                }
            
                $next = ord( $pad_str[0] ) % 2 === 0;
            }
        
        } 
        
        $output .= chr( $padded ) . implode( '', $str );

        return $output;    
    }

    function descramble ( $str, $args = null ){
    
        $ceil = 255;
    
        if ( $args === null ) $args = array();
        if ( !is_array($args) ) throw new Exception('descramble(): $args must be an array');
        if ( !$this->chk_str( $str, 5) )  throw new Exception('descramble(): $str must be a string with a length of at least 5.');

        if ( !isset($args['random_min']) ) $args['random_min'] = $this->scramble['random_min'];
        if ( !isset($args['random_max']) ) $args['random_max'] = $this->scramble['random_max'];
        if ( !isset($args['original_min']) ) $args['original_min'] = $this->scramble['original_min'];
        if ( !isset($args['original_max']) ) $args['original_max'] = $this->scramble['original_max'];
    
        if ( !$this->chk_int( $args['random_min'], 1, 255 ) ) throw new Exception('descramble(): $args["random_min"] must be an integer with a value between 1 and 255.');
        if ( !$this->chk_int( $args['random_max'], 1, 255 ) ) throw new Exception('descramble(): $args["random_max"] must be an integer with a value between 1 and 255.');
        if ( !$this->chk_int( $args['original_min'], 1, 255 ) ) throw new Exception('descramble(): $args["original_min"] must be an integer with a value between 1 and 255.');
        if ( !$this->chk_int( $args['original_max'], 1, 255 ) ) throw new Exception('descramble(): $args["original_max"] must be an integer with a value between 1 and 255.');
    
        if ( $args['original_max'] < $args['original_min'] ) throw new Exception('descramble(): $args["original_min"] can\' be larger than $args["original_max"].'); 
        if ( $args['random_max'] < $args['random_min'] ) throw new Exception('descramble(): $args["random_min"] can\' be larger than $args["random_max"].'); 

        $blk_random = $args['random_min'] + ord( $str[0] ) % ($args['random_max'] + 1 - $args['random_min']);
        $blk_original = $args['original_min'] + ord( $str[1] ) % ($args['original_max'] + 1 - $args['original_min']);
                 
        if ( isset($args['mode']) ){
            if ( !$this->chk_int($args['mode'], 0, 3) ) throw new Exception('descramble(): $args["mode"] must be an integer with a value between 0 and 3, or not set.');
            $mode = array( $args['mode'], 
                           ord( $str[2] ) % 2 === 0,
                         );
        } else {
            $mode = array( 0 + ord( $str[2] ) % (3 + 1 - 0), 
                           ord( $str[2] ) % 2 === 0,
                          );
        }
    
        $padded = ord( $str[3] ) - 1 ;    
        $blk_full = $blk_random + $blk_original;
   
        $str = substr( $str, 4 );
        if ( strlen($str) % $blk_full !== 0 ) throw new Exception('descramble(): Incorrect input or configuration, string couldn\'t be split into the required chunks based on input and configuration.');
        $str = str_split( $str, $blk_full );
         
        if ( $mode[0] === 0 ){
        
            for ( $i = 0; $i < count($str); $i++){
                $str[$i] = substr( $str[$i], $blk_random );
            }

        } else if ( $mode[0] === 1 ){
        
            for ( $i = 0; $i < count($str); $i++){
                $str[$i] = substr( $str[$i], 0, $blk_random * -1 );
            }        
                
        } else if ( $mode[0] === 2 ){
        
            for ( $i = 0; $i < count($str); $i++){
            
                if ( $i % 2 === 0 ){
                    $str[$i] = substr( $str[$i], 0, $blk_random * -1 );
                } else {
                    $str[$i] = strrev( substr( $str[$i], $blk_random ) );
                }
            } 
        
        } else if ( $mode[0] === 3 ){
        
            $next = $mode[1];

            for ( $i = 0; $i < count($str); $i++ ){
    
                if ( $next === true ){
                    $next = ord( $str[$i][$blk_full - $blk_random] ) % 2 === 0; 
                    $str[$i] = substr( $str[$i], 0, $blk_random * -1 );
                } else {
                    $next = ord ( $str[$i][0] ) % 2 === 0; 
                    $str[$i] = strrev( substr( $str[$i], $blk_random ) );
                }
            }
        }
        
        $str = implode ( '', $str );

        if ( $padded > 0 ) {
        
            if ( $mode[1] === true ){
                $str = substr ( $str, 0, $padded * -1 );
            } else {
                $str = substr ( $str, $padded );
            }
            
        }

        return $str;
    }

    function random_pad ( $str, $sep = null ){
    
        if ( $sep === null ) $sep = $this->sep;

        if ( !is_string($str) ) return false;
        if ( ($len = strlen($str)) < 1 ) return false;
        if ( !$this->chk_str($sep, 1, 1) ) return false;
        
        $str .= $sep;
        $pad_str = '';
        $max = $len < 500? 700 : 200;
        $pad_len = mt_rand(0 , $max);
        $replace = ord( $sep ) < 128? chr ( mt_rand(128, 255) ) : chr( mt_rand(1, 127) );

        for ( $i = 0; $i < $pad_len; $i++ ){
            $pad_str .= chr( mt_rand(1, 255) );
        } 

        $pad_str = str_replace( $sep , $replace , $pad_str );

        return ($str . $pad_str);
    }

    function random_pad_remove ( $str, $sep = null ){

        if ( $sep === null ) $sep = $this->sep;

        if ( !$this->chk_str($str, 1) ) return false;
        if ( !$this->chk_str($sep, 1, 1) ) return false;
       
        $pos = strrpos( $str, $sep );        
        if ( $pos == false ) return false;
        $str = substr( $str, 0, $pos );  
        
        return $str;
    }
    
    function chk_str( $input, $min_len = null, $max_len = null ){

        if ( !is_int($min_len) && $min_len !== null ) throw new Exception('chk_str(): $min_len must be an integer or a null value.');
        if ( !is_int($max_len) && $max_len !== null ) throw new Exception('chk_str(): $max_len must be an integer or a null value.'); 

        if ( $min_len !== null && $max_len !== null ){
             if ( $min_len > $max_len ) throw new Exception('chk_str(): $min_len can\'t be larger than $max_len.');
        }

        if ( !is_string( $input ) ) {
            return false;
        } else {
            $output = true;
        }

        if ( $min_len !== null ){
            if ( strlen($input) < $min_len ) $output = false;
        }
    
        if ( $max_len !== null ){
            if ( strlen($input) > $max_len ) $output = false;
        }
    
        return $output;
    }


    function chk_int ( $input, $min = null, $max = null ){

        if ( !is_int($min) && $min !== null ) throw new Exception('chk_int(): $min must an integer or a null value.');
        if ( !is_int($max) && $max !== null ) throw new Exception('chk_int(): $max must an integer or a null value.'); 

        if ( $min !== null && $max !== null ){
             if ( $min > $max ) throw new Exception('chk_int(): $min can\'t be larger than $max.');
        }

        if ( !is_int( $input ) ) {
            return false;
        } else {
            $output = true;
        }

        if ( $min !== null ){
            if ( $input < $min ) $output = false;
        }

        if ( $max !== null ){
            if ( $input > $max ) $output = false;
        }
        
        return $output;
    }
    
    function chk_array ( $input, $min_index = null, $max_index = null ){

        if ( !is_int($min_index) && $min_index !== null ) throw new Exception('chk_array(): $min_index must be an integer or a null value.');
        if ( !is_int($max_index) && $max_index !== null ) throw new Exception('chk_array(): $max_index must be an integer or a null value.'); 

        if ( $min_index !== null && $max_index !== null ){
             if ( $min_index > $max_index ) throw new Exception('chk_array(): $min-index can\'t be larger than $max_index.');
        }

        if ( !is_array( $input ) ) {
            return false;
        } else {
            $output = true;
        }

        if ( $min_index !== null ){
            if ( count($input) < $min_index ) $output = false;
        }

        if ( $max_index !== null ){
            if ( count($input) > $max_index ) $output = false;
        }
        
        return $output;
    }
    
}
Advertisement


Random Article You May Like