ホームページ  >  記事  >  バックエンド開発  >  Laravel での暗号化と復号化の概要

Laravel での暗号化と復号化の概要

巴扎黑
巴扎黑オリジナル
2017-09-26 09:45:481727ブラウズ

この記事は、Laravel での暗号化と復号化の実装方法を主に紹介しており、学習や仕事に役立つ情報を提供しています。そして一緒に学びましょう。

前書き

この記事では、Laravel の暗号化と復号化の実装を詳しく紹介し、参考と学習のために OpenSSL を使用します。以下に言います。そうは言っても、詳細な紹介を見てみましょう。

1. 使い方

まず秘密鍵を生成します。 .env ディレクトリに APP_KEY を指定する必要があります。これが利用できない場合は、コマンド php artisan key:generate を使用して生成するか、自分で設定できます。生成された例は次のようになります


APP_KEY=base64:5BM1BXGOBrGeeqJMAWJZSzyzh5yPcCGOcOGPtUij65g=

config/app.php ディレクトリに設定されているファイルに暗号化キーと暗号化アルゴリズムを設定します


$ 'key' => env('APP_KEY'),
 
  'cipher' => 'AES-256-CBC',

使用方法はで使用されていますlaravel メソッドについては、ここでは詳しく説明しません。使用される 2 つの主な方法は、encrypt の暗号化と decrypt の復号化です

2. 暗号化ファイルと復号化ファイルを見つけます

実装メソッドの場所は、vendor/illuminate/encryption/ のディレクトリにあります。 1 つは EncryptionServiceProvider で、もう 1 つは Encrypter

3. EncryptionServiceProvider ファイルを分析します


 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类,注入到框架里
  });
 }

キーは直接記述することができ、先頭にbase64を付けずに解析することもできます。これは、いくつかの手順を節約することに相当します

さらに、クラスをインスタンス化するときに、キーと暗号化メソッドを渡す必要があります

4. Encrypter ファイルを分析します

1. __construct を分析して実行します。インスタンス化の前にそれを実行します


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

上記の方法は主に、暗号化方式と送信されたキーの長さが同じかどうかを判断するために使用されます。これは、異なる暗号化方式では、特に各暗号化について、対応するキーの長さも必要となるためです。メソッド 対応するドキュメントを見つけるにはキーの長さが必要です


 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位
 }

上記のメソッドは、mb_strlen メソッドを使用し、8 ビットに基づいて長さを計算する必要がある厳密な点を示しています。この利点は、どのオペレーティング システム上であっても、計算の長さが同じであることです。


さまざまなオペレーティング システムの条件を考慮することで、暗号化の問題は発生しません。

2. encrypt メソッドを分析する


 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位,用于传输
 }

カスタム メソッド hash() が使用されているメソッドの実装を見てみましょう。


 protected function hash($iv, $value)
 {
  // 生成签名
  // 1、把随机值转为base64
  // 2、使用hash_hmac生成sha256的加密值,用来验证参数是否更改。第一个参数表示加密方式,目前是使用sha256,第二个是用随机值连上加密过后的内容进行,第三个参数是上步使用的key。生成签名。
  return hash_hmac('sha256', $iv.$value, $this->key); /根据随机值和内容,生成一个sha256的签名
 }

上記の暗号化は 3 つの主要なステップに分かれています

1. ランダム コードを生成します


2. 暗号化されたコンテンツを生成します


3. 署名を生成します

フレームワークは、serialize を使用するエレガントな方法を使用します。値を生成します。このメソッドの優れた点は、取得した内容が配列であるか文字列であるかに関係なく、値を文字列に変換できることです。 Serialize を使用することと json_encode を使用することの違いは何ですか? 最大の利点は、暗号化するコンテンツが比較的大きい場合、serialize の方が比較的高速であることだと思います。


もう 1 つは、フレームワークが暗号化するときにランダムな文字列を使用することです。ランダムな文字列を使用する理由 ランダムな文字列が使用されるため、暗号化されたコンテンツは他人に推測されるのを防ぐために毎回異なります。

3. 復号化メソッドを分析する

データの復号化は、データを復号化する必要があるだけでなく、データの改ざん防止も保証する必要があります


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メソッド


 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メソッドは、データが改ざんされていないことを確認するためのvalidMac検証に重点を置いています


 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メソッド。元のデータとランダムな値に従って計算して署名を生成し、この署名を使用して再度署名を生成することです


 protected function calculateMac($payload, $bytes)
 {
  return hash_hmac(
   'sha256', $this->hash($payload['iv'], $payload['value']), $bytes, true
  );
 }

上記の復号は大きく3つのステップに分かれています

1.データの整合性


2. データの一貫性を判断します。性別


3. データの内容を復号化します。

この検証署名には、通常の署名検証とは異なります。通常、元のデータとランダムな値を使用して署名を検証し、署名を生成し、生成された署名を元のデータの署名と比較して改ざんされているかどうかを判断します。


しかし、彼が使用するフレームワークは、元のデータとランダムな値を通じて署名を生成し、この署名を使用して署名を生成することです。また、比較では、元のデータの署名を使用して署名を生成します。 、比較してみます。なぜさらにいくつかの手順が必要なのかわかりません。

暗号化中に、serialize を使用して元のデータを変換したため、それに応じてデータを逆変換するために unserialize も使用する必要があります。

  • 暗号化に使用される openssl_encrypt のランダム項目値は、使用された元のデータ生のバイナリ値であり、openssl_decrypt を使用して復号化された値は、base64 ビット文字列の後に使用されるランダム文字です。

  • 復号化時に比較用の署名を生成する場合、元の署名を使用し、元のデータの内容に基づいて比較用の署名を再生成するのではなく、元の署名をベースとして署名を生成し、その後、元のデータは、署名に基づいて生成された署名が、この新たに生成された署名を使用して再生成されます。次に比較します。

  • AES256 は暗号化されたデータであり、後で逆に復号化することができます。 SHA256 は署名を生成します。このプロセスは元に戻すことができず、データの整合性を検証するために使用されます。

以上がLaravel での暗号化と復号化の概要の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

声明:
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。