<?php

/* 
 * @author SYDEKA
 */

class AESCrypt
{

    private $hex_iv = '00000000000000000000000000000000'; # converted Java byte code in to HEX and placed it here               
    private $key16 = ''; #Same as in JAVA

    function __construct($key16)
    {
        $this->key16 = hash('sha256', $key16, true);
    }

    function encrypt($str)
    {
        /* deprecated
        $td = mcrypt_module_open(MCRYPT_RIJNDAEL_128, '', MCRYPT_MODE_CBC, '');
        mcrypt_generic_init($td, $this->key16, $this->hexToStr($this->hex_iv));
        $block = mcrypt_get_block_size(MCRYPT_RIJNDAEL_128, MCRYPT_MODE_CBC);
        $pad = $block - (strlen($str) % $block);
        $str .= str_repeat(chr($pad), $pad);
        $encrypted = mcrypt_generic($td, $str);
        mcrypt_generic_deinit($td);
        mcrypt_module_close($td);  */

        $cipher = 'AES-256-CBC';
        $key = $this->key16;
        $opts = OPENSSL_RAW_DATA; // | OPENSSL_ZERO_PADDING

        $encrypted = openssl_encrypt($str, $cipher, $key, $opts, $this->hexToStr($this->hex_iv));

        return base64_encode($encrypted);
    }

    function decrypt($code)
    {
        /* deprecated
        $td = mcrypt_module_open(MCRYPT_RIJNDAEL_128, '', MCRYPT_MODE_CBC, '');
        mcrypt_generic_init($td, $this->key16, $this->hexToStr($this->hex_iv));
        $str = mdecrypt_generic($td, base64_decode($code));
        $block = mcrypt_get_block_size(MCRYPT_RIJNDAEL_128, MCRYPT_MODE_CBC);
        mcrypt_generic_deinit($td);
        mcrypt_module_close($td);        
        return $this->strippadding($str);     */

        $cipher = 'AES-256-CBC';
        $key = $this->key16;
        $opts = OPENSSL_RAW_DATA; // | OPENSSL_ZERO_PADDING

        $str = openssl_encrypt($code, $cipher, $key, $opts, $this->hexToStr($this->hex_iv));
        return $this->strippadding($str);
    }

    /*
      For PKCS7 padding
     */

    private function addpadding($string, $blocksize = 16)
    {
        $len = strlen($string);
        $pad = $blocksize - ($len % $blocksize);
        $string .= str_repeat(chr($pad), $pad);
        return $string;
    }

    private function strippadding($string)
    {
        $slast = ord(substr($string, -1));
        $slastc = chr($slast);
        $pcheck = substr($string, -$slast);
        if (preg_match("/$slastc{" . $slast . "}/", $string)) {
            $string = substr($string, 0, strlen($string) - $slast);
            return $string;
        } else {
            return false;
        }
    }

    private function hexToStr($hex)
    {
        $string = '';
        for ($i = 0; $i < strlen($hex) - 1; $i += 2) {
            $string .= chr(hexdec($hex[$i] . $hex[$i + 1]));
        }
        return $string;
    }


    public static function generateToken()
    {
        // le timestamp milli
        @date_default_timezone_set('UTC');
        $m = explode(' ', microtime());
        list($totalSeconds, $extraMilliseconds) = array($m[1], (int)round($m[0] * 1000, 3));
        @date_default_timezone_set("TIMEZONE");
        $timestampNow = $totalSeconds . '.' . $extraMilliseconds;

        // le token
        $NbrCaractere = 6;
        $ChaineBase = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
        $NbrChaineBase = strlen($ChaineBase) - 1;
        mt_srand((float)microtime() * 1000000);
        $Chaine = "";

        for ($i = 0; $i < $NbrCaractere; $i++) {
            $Chaine .= $ChaineBase[mt_rand(0, $NbrChaineBase)];
        }
        $UID = $Chaine;

        $objReturn = new stdClass();
        $objReturn->k = base64_encode($timestampNow);
        $objReturn->UID = $UID;
        $aesCrypt = new AESCrypt(substr($objReturn->k, 3, 16));
        $objReturn->control = base64_encode(trim($aesCrypt->encrypt($UID . $timestampNow)));
        return urlencode(implode("|", [$objReturn->k, $objReturn->UID, $objReturn->control]));
    }

    public static function controleToken($token)
    {
        $tab = explode("|", urldecode($token));
        if (count($tab) === 3) {
            $kBase64 = $tab[0];
            $UID = $tab[1];
            $control = $tab[2];

            $timestamp = base64_decode($kBase64);
            $aesCrypt = new AESCrypt(substr($kBase64, 3, 16));
            if (trim($aesCrypt->encrypt($UID . $timestamp)) != trim(base64_decode($control))) {
                return false;
            }

            @date_default_timezone_set('UTC');
            $m = explode(' ', microtime());
            list($totalSeconds, $extraMilliseconds) = array($m[1], (int)round($m[0] * 1000, 3));
            @date_default_timezone_set("TIMEZONE");
            $timestampNow = $totalSeconds . '.' . $extraMilliseconds;

            $limit = 1 * 60 * 60; // on a une tolerence de 60 min,
            if ($timestamp < ($timestampNow - $limit)) {
                return false;
            }
            return true;
        }
        return false;
    }
}
