Home  >  Article  >  Backend Development  >  Introduction to encrypt and decrypt in Laravel

Introduction to encrypt and decrypt in Laravel

巴扎黑
巴扎黑Original
2017-09-26 09:45:481727browse

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 below Let’s learn together.

Preface

Laravel’s encryption mechanism uses OpenSSL to provide AES-256 and AES-128 encryption. This article will introduce in detail about encrypt in Laravel And the implementation of decrypt is shared for everyone's reference and study. I won't say much below, let's take a look at the detailed introduction.

1. Usage method

First, generate the secret key. You need to provide APP_KEY in the .env directory. If it does not exist, 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',

The usage method is already available in laravel, so I won’t go into too much detail here. The two main methods used are encryption by encrypt and decryption by decrypt

2. Find encrypted and decrypted files

The location of the implementation method is to find two files in the directory of vendor/illuminate/encryption/, 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 that in fact, in the configuration file, we can write the key directly without base64 in front of it. It can also be parsed. 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 above method


##

 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.');
  }
 }

before instantiation, mainly using To determine whether the encryption method and the length of the key passed are the same, because different encryption methods also require the length of the corresponding key. Specifically, the length of the key required by 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 requiring the calculation length to be calculated based on 8 bits. 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位,用于传输
 }

The above uses a custom method hash(), we can take a look at the method realization.


 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 does not matter what the content is Both arrays and strings can be converted into strings. 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. As well as data 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;
 }

validPayload method is not mentioned, it is relatively simple and basic. The key point is to talk about validMac verification 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)); //拿数据和随机值生成一个签名

  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 values. Then use this signature to generate another signature


 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 integrity of the data Property


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 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 to use the signature in the original data to generate a signature. , and then compare. 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 during encryption is the original data raw used Binary value, the value decrypted using openssl_decrypt is a random string after base64 bits are used.

  • 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. Sign, 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.

The above is the detailed content of Introduction to encrypt and decrypt in Laravel. For more information, please follow other related articles on the PHP Chinese website!

Statement:
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn