<?php

namespace Illuminate\Encryption;

use RuntimeException;
use Illuminate\Contracts\Encryption\DecryptException;
use Illuminate\Contracts\Encryption\EncryptException;
use Illuminate\Contracts\Encryption\Encrypter as EncrypterContract;

class Encrypter extends BaseEncrypter implements EncrypterContract
{// class Encrypter extends base Encrypter implements Encrypter Contract
/**
* The algorithm used for encryption.
*
* @var string
*/
protected $cipher;// a cipher is a string warehouse

/**
* Create a new encrypter instance.
*
* @param string $key
* @param string $cipher
* @return void
*
* @throws \RuntimeException
*/
public function __construct($key, $cipher = 'AES-128-CBC')
{// create a instance about encrypter
$key = (string) $key;// change str to str

if (static::supported($key, $cipher)) {// if it is has supported
$this->key = $key;//set key
$this->cipher = $cipher;// set cipher
} else {// if not support
throw new RuntimeException('The only supported ciphers are AES-128-CBC and AES-256-CBC with the correct key lengths.');
}// throw new Exception
}

/**
* Determine if the given key and cipher combination is valid.
*
* @param string $key
* @param string $cipher
* @return bool
*/
public static function supported($key, $cipher)
{
$length = mb_strlen($key, '8bit');// get length

return ($cipher === 'AES-128-CBC' && $length === 16) || ($cipher === 'AES-256-CBC' && $length === 32);
}// different way to get true or false

/**
* Encrypt the given value.
*
* @param string $value
* @return string
*
* @throws \Illuminate\Contracts\Encryption\EncryptException
*/
public function encrypt($value)
{// this function means to encrypt
$iv = random_bytes($this->getIvSize());//random_bytes create a seed about rand

$value = openssl_encrypt(serialize($value), $this->cipher, $this->key, 0, $iv);
// a way to encrypted the string parameters
if ($value === false) {
throw new EncryptException('Could not encrypt the data.');
}// throw error

// Once we have the encrypted value we will go ahead base64_encode the input
// vector and create the MAC for the encrypted value so we can verify its
// authenticity. Then, we'll JSON encode the data in a "payload" array.
$mac = $this->hash($iv = base64_encode($iv), $value);// get mac value by base64_encode()

$json = json_encode(compact('iv', 'value', 'mac'));// very good use

if (! is_string($json)) {// is_string to check the json string
throw new EncryptException('Could not encrypt the data.');
}// throw E

return base64_encode($json);// two base64_encode to encrypted the value
}

/**
* Decrypt the given value.
*
* @param string $payload
* @return string
*
* @throws \Illuminate\Contracts\Encryption\DecryptException
*/
public function decrypt($payload)
{
$payload = $this->getJsonPayload($payload);// get the payload

$iv = base64_decode($payload['iv']);// get the iv

$decrypted = openssl_decrypt($payload['value'], $this->cipher, $this->key, 0, $iv);
// use the openssl_decrypte
if ($decrypted === false) {
throw new DecryptException('Could not decrypt the data.');
}

return unserialize($decrypted);// use unserialize function
}

/**
* Get the IV size for the cipher.
*
* @return int
*/
protected function getIvSize()
{
return 16;
}// normal size is 16
}