<?php

namespace App\Http\Controllers\Miniprogram;

class Decrypt
{
    private $appid;
    private $sessionKey;

    public function __construct($appid, $sessionKey)
    {
        $this->appid = $appid;
        $this->sessionKey = $sessionKey;
    }

    /**
     * 对解密后的明文进行补位删除
     * @param  text decrypted 解密后的明文
     * @return void 删除填充补位后的明文
     */
    public function decode($text)
    {

        $pad = ord(substr($text, -1));
        if ($pad < 1 || $pad > 32) {
            $pad = 0;
        }
        return substr($text, 0, (strlen($text) - $pad));
    }

    /**
     * 对密文进行解密
     * @param $aesKey
     * @param  string  $aesCipher  需要解密的密文
     * @param  string  $aesIV  解密的初始向量
     * @return array 解密得到的明文
     */
    public function decrypt($aesKey, $aesCipher, $aesIV)
    {
        try {
            //解密
            $decrypted = openssl_decrypt($aesCipher, 'AES-128-CBC', $aesKey, OPENSSL_RAW_DATA, $aesIV);
        } catch (\Exception $e) {
            return array($this->IllegalBuffer, null);
        }

        try {
            //去除补位字符
            $result = $this->decode($decrypted);
        } catch (Exception $e) {
            return array(41003, null);
        }
        return array(0, $result);
    }

    /**
     * 检验数据的真实性，并且获取解密后的明文.
     * @param  string  $encryptedData
     * @param $iv string 与用户数据一同返回的初始向量
     * @param $data string 解密后的原文
     * @return void 成功0，失败返回对应的错误码
     */
    public function decryptData(string $encryptedData, string $iv, &$data)
    {
        if (strlen($this->sessionKey) != 24) {
            return 41001;
        }

        $aesKey = base64_decode($this->sessionKey);

        if (strlen($iv) != 24) {
            return 41002;
        }
        $aesIV = base64_decode($iv);

        $aesCipher = base64_decode($encryptedData);

        $result = $this->decrypt($aesKey, $aesCipher, $aesIV);

        if ($result[0] != 0) {
            return $result[0];
        }

        $dataObj = json_decode($result[1]);
        if ($dataObj == null) {
            return 41004;
        }
        if ($dataObj->watermark->appid != $this->appid) {
            return 41003;
        }
        $data = $result[1];
        return 0;
    }
}
