This article mainly introduces you to the implementation methods of encrypt and decrypt in Laravel. The article introduces it in great detail through sample code. It has certain reference learning value for everyone's study or work. Friends who need it follow the editor below. Come and learn together.
Preface
Laravel’s encryption mechanism uses OpenSSL to provide AES-256 and AES-128 encryption. This article will introduce in detail the implementation of encrypt and decrypt in Laravel and share it for your reference and learning. Not much to say below, let’s take a look at the detailed introduction.
1. How to use
The first step is to generate a secret key. You need to provide APP_KEY in the .env directory. If this is not available, you can generate it through the command php artisan key:generate, or you can set it yourself. The generated example should look like this
APP_KEY=base64:5BM1BXGOBrGeeqJMAWJZSzyzh5yPcCGOcOGPtUij65g=
Configure the encryption key and encryption algorithm in the file, and configure it in the config/app.php directory
$ 'key' => env('APP_KEY'), 'cipher' => 'AES-256-CBC',
How to use it, There are already ways to use it in laravel, so I won’t go into too much detail here. The two main methods used are encryption of encrypt and decryption of decrypt
2. Find the encryption and decryption files
The location of the implementation method is in vendor/illuminate/ Two files were found in the encryption/ directory, one is EncryptionServiceProvider and the other is Encrypter
3. Analyze the EncryptionServiceProvider file
public function register() { $this->app->singleton('encrypter', function ($app) { $config = $app->make('config')->get('app'); //从config/app.php里拿到配置文件 if (Str::startsWith($key = $config['key'], 'base64:')) { //分析配置文件里的key里面有没有带'base64' $key = base64_decode(substr($key, 7)); //如果有的话,把key前面的base64:给取消,并且解析出原来的字符串 } return new Encrypter($key, $config['cipher']); //实例化Encrypte类,注入到框架里 }); }
There is not much in this file, but we can see from this, In fact, in the configuration file, we can write the key directly, and it can also be parsed without base64 in front. It is equivalent to saving a few steps
In addition, when instantiating the class, you need to pass in the key and encryption method
4. Analyze the Encrypter file
1. Analyze __construct and execute the
public function __construct($key, $cipher = 'AES-128-CBC') { $key = (string) $key; //把key转换为字符串 if (static::supported($key, $cipher)) { //调用一个自定义的方法,用来判断加密方式和要求的key长度是否一样 $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.'); } }
method above before instantiation. It is mainly used to determine whether the encryption method and the length of the passed key are the same, because different encryption methods require the corresponding key length. If required, the specific key length required for each encryption method can be found in the corresponding document
public static function supported($key, $cipher) { $length = mb_strlen($key, '8bit'); //判断key的字符的长度,按照8bit位的方式计算字符长度 return ($cipher === 'AES-128-CBC' && $length === 16) || ($cipher === 'AES-256-CBC' && $length === 32); //编码格式为AES128的要求字符长度为16。编码格式为AES256的要求字符长度为32位 }
The above method shows a rigorous point, using the mb_strlen method, and the calculation length is required to be calculated based on 8 bits of. The advantage of this is that no matter which operating system it is on, the length of the calculation is the same.
By taking into account the conditions of different operating systems, there will be no encryption problems.
2. Analyze the encrypt method
public function encrypt($value, $serialize = true) { $iv = random_bytes(16); //生成一个16位的随机字符串 // 使用openssl_encrypt把数据生成一个加密的数据 // 1、判断需要不需要生成一个可存储表示的值,这样做是为了不管你的数据是数组还是字符串都能给你转成一个字符串,不至于在判断你传过来的数据是数组还是字符串了。 // 2、使用openssl_encrypt。第一个参数是传入数据,第二个参数是传入加密方式,目前使用AES-256-CBC的加密方式,第三个参数是,返回加密后的原始数据,还是把加密的数据在经过一次base64的编码,0的话表示base64位数据。第四个参数是项量,这个参数传入随机数,是为了在加密数据的时候每次的加密数据都不一样。 $value = \openssl_encrypt( $serialize ? serialize($value) : $value, $this->cipher, $this->key, 0, $iv ); //使用AES256加密内容 if ($value === false) { throw new EncryptException('Could not encrypt the data.'); } $mac = $this->hash($iv = base64_encode($iv), $value); //生成一个签名,用来保证内容参数没有被更改 $json = json_encode(compact('iv', 'value', 'mac')); //把随机码,加密内容,已经签名,组成数组,并转成json格式 if (! is_string($json)) { throw new EncryptException('Could not encrypt the data.'); } return base64_encode($json); //把json格式转换为base64位,用于传输 }
A custom method hash() is used above. We can take a look at the implementation of the method.
protected function hash($iv, $value) { // 生成签名 // 1、把随机值转为base64 // 2、使用hash_hmac生成sha256的加密值,用来验证参数是否更改。第一个参数表示加密方式,目前是使用sha256,第二个是用随机值连上加密过后的内容进行,第三个参数是上步使用的key。生成签名。 return hash_hmac('sha256', $iv.$value, $this->key); /根据随机值和内容,生成一个sha256的签名 }
The above encryption is divided into three major steps
1. Generate random code
2. Generate encrypted content
3 , Generate signature
The framework uses an elegant method, using serialize to generate a value. The elegance of this method is that it can be converted into a string regardless of whether the content you get is an array or a string. What is the difference between using serialize and using json_encode? I think the biggest advantage is that when the content you want to encrypt is relatively large, serialize is relatively faster.
Another place is that the framework uses a random string when encrypting. Why use a random string? Because a random string is used, the encrypted content will be different each time to prevent others from guessing it.
3. Analysis of decrypt method
Decrypting data can be said to be the most complicated part. Not only must the data be decrypted, but the integrity of the data must also be ensured, and the data must be tamper-proof
public function decrypt($payload, $unserialize = true) { $payload = $this->getJsonPayload($payload); //把加密后的字符串转换出成数组。 $iv = base64_decode($payload['iv']); //把随机字符串进行base64解密出来 $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; //把数据转换为原始数据 }
getJsonPayload method
protected function getJsonPayload($payload) { $payload = json_decode(base64_decode($payload), true); //把数据转换为原来的数组形式 if (! $this->validPayload($payload)) { //验证是不是数组以及数组里有没有随机字符串,加密后的内容,签名 throw new DecryptException('The payload is invalid.'); } if (! $this->validMac($payload)) { //验证数据是否被篡改 throw new DecryptException('The MAC is invalid.'); } return $payload; }
I won’t talk about the validPayload method. It is relatively simple and basic. The focus is on validMac verification to ensure that the data is not tampered with. This is the most important thing
protected function validMac(array $payload) { $calculated = $this->calculateMac($payload, $bytes = random_bytes(16)); //拿数据和随机值生成一个签名 return hash_equals( //比对上一步生成的签名和下面生成的签名的hash是否一样。 hash_hmac('sha256', $payload['mac'], $bytes, true), $calculated //根据原始数据里的签名在新生成一个签名 ); }
calculateMac method is to generate a signature based on the original data and random value, and then use this 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 divided into three major steps
1. Determine the data Integrity
2. Determine the consistency of the data
3. Decrypt the data content.
There is something strange about this verification signature. It is not the same as our usual signature verification. We usually verify signatures by using the original data and random values to generate a signature, and then compare the generated signature with the signature of the original data to determine whether it has been tampered with.
But there is one more framework. What he uses is to generate a signature through the original data and random values, and then use this signature to generate a signature, and the comparison is also based on the original data. The signature generates a signature and then compares it. I can't figure out why it takes a few more steps.
During encryption, we converted the original data using serialize, so we also need to use unserialize to convert the data back accordingly.
Note
The random item value in openssl_encrypt used for encryption is the binary value of the original data raw used, and the value decrypted using openssl_decrypt is used A random string after base64 bits.
When generating signatures for comparison during decryption, instead of using the original signature and then regenerating a signature for comparison based on the content of the original data, we use the original signature as the basis to generate a signature, and then Take the signature generated based on the original data, and use this newly generated signature to regenerate a signature. Then compare.
AES256 is encrypted data, which can be decrypted later in reverse. SHA256 generates a signature. This process is irreversible and is used to verify the integrity of the data.
Related recommendations:
How to correctly use AES_ENCRYPT() and AES_DECRYPT() for MySQL encryption and decryption
Solution to No supported encrypter found error when using laravel 5.1
javascript - decryption of encryptData in applet wx.getUserInfo
The above is the detailed content of Example sharing of encrypt and decrypt implementation methods in Laravel. For more information, please follow other related articles on the PHP Chinese website!