Viewing file: Encrypter.php (6.54 KB) -rwxrwxrwx Select action/file-type: (+) | (+) | (+) | Code (+) | Session (+) | (+) | SDB (+) | (+) | (+) | (+) | (+) | (+) |
<?php
namespace Illuminate\Encryption;
use Illuminate\Contracts\Encryption\DecryptException; use Illuminate\Contracts\Encryption\Encrypter as EncrypterContract; use Illuminate\Contracts\Encryption\EncryptException; use Illuminate\Contracts\Encryption\StringEncrypter; use RuntimeException;
class Encrypter implements EncrypterContract, StringEncrypter { /** * The encryption key. * * @var string */ protected $key;
/** * The algorithm used for encryption. * * @var string */ protected $cipher;
/** * Create a new encrypter instance. * * @param string $key * @param string $cipher * @return void * * @throws \RuntimeException */ public function __construct($key, $cipher = 'AES-128-CBC') { $key = (string) $key;
if (static::supported($key, $cipher)) { $this->key = $key; $this->cipher = $cipher; } else { throw new RuntimeException('The only supported ciphers are AES-128-CBC and AES-256-CBC with the correct key lengths.'); } }
/** * 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');
return ($cipher === 'AES-128-CBC' && $length === 16) || ($cipher === 'AES-256-CBC' && $length === 32); }
/** * Create a new encryption key for the given cipher. * * @param string $cipher * @return string */ public static function generateKey($cipher) { return random_bytes($cipher === 'AES-128-CBC' ? 16 : 32); }
/** * Encrypt the given value. * * @param mixed $value * @param bool $serialize * @return string * * @throws \Illuminate\Contracts\Encryption\EncryptException */ public function encrypt($value, $serialize = true) { $iv = random_bytes(openssl_cipher_iv_length($this->cipher));
// First we will encrypt the value using OpenSSL. After this is encrypted we // will proceed to calculating a MAC for the encrypted value so that this // value can be verified later as not having been changed by the users. $value = \openssl_encrypt( $serialize ? serialize($value) : $value, $this->cipher, $this->key, 0, $iv );
if ($value === false) { throw new EncryptException('Could not encrypt the data.'); }
// Once we get the encrypted value we'll go ahead and base64_encode the input // vector and create the MAC for the encrypted value so we can then verify // its authenticity. Then, we'll JSON the data into the "payload" array. $mac = $this->hash($iv = base64_encode($iv), $value);
$json = json_encode(compact('iv', 'value', 'mac'), JSON_UNESCAPED_SLASHES);
if (json_last_error() !== JSON_ERROR_NONE) { throw new EncryptException('Could not encrypt the data.'); }
return base64_encode($json); }
/** * Encrypt a string without serialization. * * @param string $value * @return string * * @throws \Illuminate\Contracts\Encryption\EncryptException */ public function encryptString($value) { return $this->encrypt($value, false); }
/** * Decrypt the given value. * * @param string $payload * @param bool $unserialize * @return mixed * * @throws \Illuminate\Contracts\Encryption\DecryptException */ public function decrypt($payload, $unserialize = true) { $payload = $this->getJsonPayload($payload);
$iv = base64_decode($payload['iv']);
// Here we will decrypt the value. If we are able to successfully decrypt it // we will then unserialize it and return it out to the caller. If we are // unable to decrypt this value we will throw out an exception message. $decrypted = \openssl_decrypt( $payload['value'], $this->cipher, $this->key, 0, $iv );
if ($decrypted === false) { throw new DecryptException('Could not decrypt the data.'); }
return $unserialize ? unserialize($decrypted) : $decrypted; }
/** * Decrypt the given string without unserialization. * * @param string $payload * @return string * * @throws \Illuminate\Contracts\Encryption\DecryptException */ public function decryptString($payload) { return $this->decrypt($payload, false); }
/** * Create a MAC for the given value. * * @param string $iv * @param mixed $value * @return string */ protected function hash($iv, $value) { return hash_hmac('sha256', $iv.$value, $this->key); }
/** * Get the JSON array from the given payload. * * @param string $payload * @return array * * @throws \Illuminate\Contracts\Encryption\DecryptException */ protected function getJsonPayload($payload) { $payload = json_decode(base64_decode($payload), true);
// If the payload is not valid JSON or does not have the proper keys set we will // assume it is invalid and bail out of the routine since we will not be able // to decrypt the given value. We'll also check the MAC for this encryption. if (! $this->validPayload($payload)) { throw new DecryptException('The payload is invalid.'); }
if (! $this->validMac($payload)) { throw new DecryptException('The MAC is invalid.'); }
return $payload; }
/** * Verify that the encryption payload is valid. * * @param mixed $payload * @return bool */ protected function validPayload($payload) { return is_array($payload) && isset($payload['iv'], $payload['value'], $payload['mac']) && strlen(base64_decode($payload['iv'], true)) === openssl_cipher_iv_length($this->cipher); }
/** * Determine if the MAC for the given payload is valid. * * @param array $payload * @return bool */ protected function validMac(array $payload) { return hash_equals( $this->hash($payload['iv'], $payload['value']), $payload['mac'] ); }
/** * Get the encryption key. * * @return string */ public function getKey() { return $this->key; } }
|