This paper mainly introduces
the implementation of encrypt and decrypt in Laravel, the article introduces the example code in very detailed, to everyone's study or work has a certain reference learning value, the need for friends below with the small series to learn together.
Objective
Laravel encryption mechanism using OpenSSL to provide AES-256 and AES-128 encryption, this article will be introduced in detail about Laravel encrypt and decrypt implementation, sharing out for everyone to reference the study, the following words do not say, come together to see the detailed introduction bar.
1. How to use
The first is to generate the secret key. You need to provide app_key in the. Env directory, which if not, can be generated by command PHP artisan key:generate, or you can set it yourself. The post-build example should look like this
app_key=base64:5bm1bxgobrgeeqjmawjzszyzh5ypccgocogptuij65g=
Configure encryption key and encryption algorithm in file, config in config/app.php directory
$ ' key ' = env (' App_key '), ' cipher ' = ' AES-256-CBC ',
Using the method, there is already a way to use in the Laravel, here is not too much to say. The main use of the two methods, one is encrypt encryption, one is the decryption of decrypt
2. Find encrypted and decrypted files
The implementation method is located in the vendor/illuminate/encryption/directory found two files, one is Encryptionserviceprovider and the other is Encrypter
3. Analyzing Encryptionserviceprovider Files
public function register()
{
$this->app->singleton('encrypter', function ($app) {
$config = $app->make('config')->get('app'); //get the configuration file from config/app.php
if (Str::startsWith($key = $config['key'],'base64:')) {//Analyze whether there is'base64' in the key in the configuration file
$key = base64_decode(substr($key, 7)); //If there is any, cancel the base64: in front of the key, and parse the original string
}
return new Encrypter($key, $config['cipher']); //Instantiate the Encrypte class and inject it into the framework
});
}
This file does not have a lot of things, but through this we can see, in fact, in the configuration file, we can directly write key, and the front without Base64 is also can parse. Equivalent to a few steps of the province
In addition, when you instantiate a class, you need to pass in the key and the encryption method
4. Analyzing encrypter Files
1. Analyze __construct, execute before instantiation
public function __construct($key, $cipher ='AES-128-CBC')
{
$key = (string) $key; //Convert key to string
if (static::supported($key, $cipher)) {//Call a custom method to determine whether the encryption method is the same as the required key length
$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.');
}
}
The above method is mainly used to determine whether the encryption method and the length of the key passed is the same, because different encryption methods, the required length of the corresponding key is also required, each encryption method requires key length can find the corresponding document
public static function supported($key, $cipher)
{
$length = mb_strlen($key, '8bit'); //Judging the length of the key character, and calculating the character length according to 8bit
return ($cipher ==='AES-128-CBC' && $length === 16) ||
($cipher ==='AES-256-CBC' && $length === 32); //The required character length for encoding format of AES128 is 16. The encoding format is AES256, the required character length is 32 bits
}
The above method shows a rigorous place, using the Mb_strlen method, and requires that the calculation length is calculated according to the 8bit bit. The advantage is that the length of the calculation is the same regardless of the operating system.
With this consideration of the different operating systems, there will be no problem with encryption.
2. Analyzing the Encrypt method
public function encrypt($value, $serialize = true)
{
$iv = random_bytes(16); //Generate a 16-bit random string
// Use openssl_encrypt to generate an encrypted data from the data
// 1. It is judged that there is no need to generate a value that can be stored. This is to convert your data into a string regardless of whether your data is an array or a string, so as not to judge that the data you pass is an array Still a string.
// 2. Use openssl_encrypt. The first parameter is the incoming data, the second parameter is the incoming encryption method, currently the AES-256-CBC encryption method is used, and the third parameter is whether to return the encrypted original data or to pass the encrypted data Once base64 encoding, 0 means base64 data. The fourth parameter is the item amount, this parameter is passed in a random number, so that the encrypted data is different every time when the data is encrypted.
$value = \openssl_encrypt(
$serialize? serialize($value): $value,
$this->cipher, $this->key, 0, $iv
); //Use AES256 to encrypt content
if ($value === false) {
throw new EncryptException('Could not encrypt the data.');
}
$mac = $this->hash($iv = base64_encode($iv), $value); //Generate a signature to ensure that the content parameters have not been changed
$json = json_encode(compact('iv','value','mac')); //The random code, encrypted content, signed, form an array, and convert it to json format
if (! is_string($json)) {
throw new EncryptException('Could not encrypt the data.');
}
return base64_encode($json); //Convert json format to base64 bits for transmission
}
The above uses a custom method hash (), we can see the implementation of the method.
protected function hash($iv, $value)
{
// Generate signature
// 1. Convert the random value to base64
// 2. Use hash_hmac to generate the sha256 encrypted value to verify whether the parameter has changed. The first parameter indicates the encryption method, currently sha256 is used, the second is to connect the encrypted content with a random value, and the third parameter is the key used in the previous step. Generate a signature.
return hash_hmac('sha256', $iv.$value, $this->key); /According to the random value and content, generate a sha256 signature
}
The above encryption is a total of three major strides
1. Generate Random Code
2. Generate Encrypted Content
3. Generate signature
The framework uses an elegant approach, using serialize to generate a value, which is elegant, that is, whether your content is an array or a string, it can be converted to a string. And the difference between using serialize and using Json_encode, I think the biggest advantage is that you want to encrypt the content is relatively large, serialize relative to the faster.
Another place is that the framework uses a random string when it is encrypted. Why use random strings, because the use of random strings, so that each time the contents of the encryption is different, to prevent others to guess.
3. Analyzing the Decrypt method
Decryption of data, can be said to be the most complex piece, not only to decrypt the data, but also to ensure the integrity of the data, as well as data anti-tampering
public function decrypt($payload, $unserialize = true)
{
$payload = $this->getJsonPayload($payload); //Convert the encrypted string into an array.
$iv = base64_decode($payload['iv']); //decrypt the random string to base64
$decrypted = \openssl_decrypt( //Decrypted data
$payload['value'], $this->cipher, $this->key, 0, $iv
);
if ($decrypted === false) {
throw new DecryptException('Could not decrypt the data.');
}
return $unserialize? unserialize($decrypted): $decrypted; //Convert data to original data
}
Getjsonpayload method
protected function getJsonPayload($payload)
{
$payload = json_decode(base64_decode($payload), true); //Convert the data to the original array form
if (! $this->validPayload($payload)) {//Verify whether the array and whether there is a random string in the array, the encrypted content, and the signature
throw new DecryptException('The payload is invalid.');
}
if (! $this->validMac($payload)) {//Verify whether the data has been tampered with
throw new DecryptException('The MAC is invalid.');
}
return $payload;
}
Validpayload method does not say, relatively simple and basic, the focus is to say Validmac verify this piece, to ensure that the data is not tampered with, this is the most important
protected function validMac(array $payload)
{
$calculated = $this->calculateMac($payload, $bytes = random_bytes(16)); //Take data and random values to generate a signature
return hash_equals( //Compare the hash of the signature generated in the previous step with the signature generated below.
hash_hmac('sha256', $payload['mac'], $bytes, true), $calculated //A new signature is generated based on the signature in the original data
);
}
The Calculatemac method is to generate a signature based on the original data and random values, and then use that signature to generate a signature again
protected function calculateMac($payload, $bytes)
{
return hash_hmac(
'sha256', $this->hash($payload['iv'], $payload['value']), $bytes, true
);
}
The above decryption is a three-step
1, judge the integrity of the data
2, judge the consistency of the data
3. Decrypt the contents of the data.
This verification signature has a strange place, and he is not the same as we usually verify the signature. We normally verify signatures by generating a signature with raw data and random values, and then determining whether there has been tampering with the generated signature and the signature of the original data.
And the framework is one more, he used, after the original data and random values to generate a signature, and then take the signature generated a signature, rather than the original data in the signature is generated by a signature, and then the comparison. At the moment, I can't figure out why we need a few more steps.
At the time of encryption, we converted the raw data using serialize, so we also need to use Unserialize to convert the data back.
Attention
-
The value of the random item in the Openssl_encrypt used when encrypting is the raw data raw this binary value, using the Openssl_decrypt decrypted values is the random string that is used after the base64 bit.
-
When decrypting a signature comparison, instead of using the original signature, and then comparing it with the original data's contents, regenerate the signature, instead, generate a signature based on the original signature, and then regenerate the signature with the newly generated signature, using the signature generated from the original data. And then the comparison is made.
-
AES256 is encrypted data, which can be reversed to decrypt the data later. While SHA256 is a signature generation, this process is irreversible and is intended to verify the integrity of the data.