欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Laravel中encrypt和decrypt的實現(xiàn)方法

 更新時間:2017年09月24日 09:40:07   作者:Dennis  
這篇文章主要給大家介紹了關(guān)于Laravel中encrypt和decrypt的實現(xiàn)方法,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧。

前言

Laravel 的加密機(jī)制使用 OpenSSL 提供 AES-256 和 AES-128 的加密,本文將詳細(xì)介紹關(guān)于Laravel中encrypt和decrypt的實現(xiàn),分享出來供大家參考學(xué)習(xí),下面話不多說了,來一起看看詳細(xì)的介紹吧。

1. 使用方法

首先是生成秘鑰。要需要在.env目錄里提供APP_KEY,這個如果沒有的話,可以通過命令php artisan key:generate生成,也可以自己設(shè)置。生成后例子應(yīng)該是這樣的

APP_KEY=base64:5BM1BXGOBrGeeqJMAWJZSzyzh5yPcCGOcOGPtUij65g=

在文件配置加密key和加密算法,在config/app.php的目錄里有配置

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

使用方法,在laravel里已經(jīng)有使用方法了,這里就不在過多的說了。主要使用的兩個方法,一個是encrypt的加密,一個是decrypt的解密

2. 查找加密解密的文件

實現(xiàn)方法的位置是在vendor/illuminate/encryption/的目錄下發(fā)現(xiàn)兩個文件,一個是EncryptionServiceProvider另外一個是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類,注入到框架里
  });
 }

這個文件沒太多東西,但是通過這個我們可以看出,其實在配置文件的,我們能直接寫key,并且前面不帶base64也是可以解析。相當(dāng)于省幾步操作

另外,在實例化類的時候,需要傳入key以及加密方式

4. 分析Encrypter文件

1. 分析__construct,在實例化之前執(zhí)行

 public function __construct($key, $cipher = 'AES-128-CBC')
 {
  $key = (string) $key; //把key轉(zhuǎn)換為字符串

  if (static::supported($key, $cipher)) { //調(diào)用一個自定義的方法,用來判斷加密方式和要求的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.');
  }
 }

上面的方法,主要是用來判斷加密方式和傳的key的長度是否相同,因為不同的加密方式,要求的相應(yīng)的key的長度也是有要求的,具體每種加密方式要求key的長度可以查找對應(yīng)的文檔

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

上面這個方法展現(xiàn)了一個嚴(yán)謹(jǐn)?shù)牡胤剑昧薽b_strlen方法,并且要求計算長度是按照8bit位來計算的。這樣的好處是,不管是在哪種操作系統(tǒng),計算的長度都是一樣的。

通過這個考慮到不同操作系統(tǒng)的情況,不會出現(xiàn)加密出現(xiàn)問題的情況。

2. 分析encrypt方法

 public function encrypt($value, $serialize = true)
 {
  $iv = random_bytes(16); //生成一個16位的隨機(jī)字符串
  
  
  // 使用openssl_encrypt把數(shù)據(jù)生成一個加密的數(shù)據(jù)
  // 1、判斷需要不需要生成一個可存儲表示的值,這樣做是為了不管你的數(shù)據(jù)是數(shù)組還是字符串都能給你轉(zhuǎn)成一個字符串,不至于在判斷你傳過來的數(shù)據(jù)是數(shù)組還是字符串了。
  // 2、使用openssl_encrypt。第一個參數(shù)是傳入數(shù)據(jù),第二個參數(shù)是傳入加密方式,目前使用AES-256-CBC的加密方式,第三個參數(shù)是,返回加密后的原始數(shù)據(jù),還是把加密的數(shù)據(jù)在經(jīng)過一次base64的編碼,0的話表示base64位數(shù)據(jù)。第四個參數(shù)是項量,這個參數(shù)傳入隨機(jī)數(shù),是為了在加密數(shù)據(jù)的時候每次的加密數(shù)據(jù)都不一樣。
  $value = \openssl_encrypt(
   $serialize ? serialize($value) : $value,
   $this->cipher, $this->key, 0, $iv
  ); //使用AES256加密內(nèi)容

  if ($value === false) {
   throw new EncryptException('Could not encrypt the data.');
  }

  $mac = $this->hash($iv = base64_encode($iv), $value); //生成一個簽名,用來保證內(nèi)容參數(shù)沒有被更改

  $json = json_encode(compact('iv', 'value', 'mac')); //把隨機(jī)碼,加密內(nèi)容,已經(jīng)簽名,組成數(shù)組,并轉(zhuǎn)成json格式

  if (! is_string($json)) {
   throw new EncryptException('Could not encrypt the data.');
  }

  return base64_encode($json); //把json格式轉(zhuǎn)換為base64位,用于傳輸
 }

上面用到了一個自定義的方法hash(),我們可以看下方法的實現(xiàn)。

 protected function hash($iv, $value)
 {
  // 生成簽名
  // 1、把隨機(jī)值轉(zhuǎn)為base64
  // 2、使用hash_hmac生成sha256的加密值,用來驗證參數(shù)是否更改。第一個參數(shù)表示加密方式,目前是使用sha256,第二個是用隨機(jī)值連上加密過后的內(nèi)容進(jìn)行,第三個參數(shù)是上步使用的key。生成簽名。
  return hash_hmac('sha256', $iv.$value, $this->key); /根據(jù)隨機(jī)值和內(nèi)容,生成一個sha256的簽名
 }

以上加密共分了三大步

     1、生成隨機(jī)碼

     2、生成加密內(nèi)容

     3、生成簽名

框架用到一個優(yōu)雅的方法,使用serialize生成一個值,這個方法高雅在哪里,就是不管你得內(nèi)容是數(shù)組還是字符串,都能轉(zhuǎn)換成字符串。 而使用serialize和使用json_encode的區(qū)別在哪,我想最大的好處是,你所要加密的內(nèi)容比較大的時候,serialize相對于要快。

另外一個地方是,框架在加密的時候使用了一個隨機(jī)字符串。為什么要使用隨機(jī)字符串呢,因為使用了隨機(jī)字符串,使每次加密的內(nèi)容都是不一樣的,防止別人猜出來。

3. 分析decrypt方法

解密數(shù)據(jù),可以說是最復(fù)雜的一塊,不僅要進(jìn)行數(shù)據(jù)的解密,而且還要保證數(shù)據(jù)的完整性,以及數(shù)據(jù)防篡改

public function decrypt($payload, $unserialize = true)
 {
  $payload = $this->getJsonPayload($payload); //把加密后的字符串轉(zhuǎn)換出成數(shù)組。

  $iv = base64_decode($payload['iv']); //把隨機(jī)字符串進(jìn)行base64解密出來

  $decrypted = \openssl_decrypt( //解密數(shù)據(jù)
   $payload['value'], $this->cipher, $this->key, 0, $iv
  );

  if ($decrypted === false) {
   throw new DecryptException('Could not decrypt the data.');
  }

  return $unserialize ? unserialize($decrypted) : $decrypted; //把數(shù)據(jù)轉(zhuǎn)換為原始數(shù)據(jù)
 }

getJsonPayload方法

 protected function getJsonPayload($payload)
 {
  $payload = json_decode(base64_decode($payload), true); //把數(shù)據(jù)轉(zhuǎn)換為原來的數(shù)組形式

  if (! $this->validPayload($payload)) { //驗證是不是數(shù)組以及數(shù)組里有沒有隨機(jī)字符串,加密后的內(nèi)容,簽名
   throw new DecryptException('The payload is invalid.');
  }

  if (! $this->validMac($payload)) { //驗證數(shù)據(jù)是否被篡改
   throw new DecryptException('The MAC is invalid.');
  }

  return $payload;
 }

validPayload方法就不說了,比較簡單和基本,重點就說說validMac驗證這塊,保證數(shù)據(jù)不被篡改,這是最重要的

 protected function validMac(array $payload)
 {
  $calculated = $this->calculateMac($payload, $bytes = random_bytes(16)); //拿數(shù)據(jù)和隨機(jī)值生成一個簽名

  return hash_equals( //比對上一步生成的簽名和下面生成的簽名的hash是否一樣。
   hash_hmac('sha256', $payload['mac'], $bytes, true), $calculated //根據(jù)原始數(shù)據(jù)里的簽名在新生成一個簽名
  );
 }

calculateMac方法是為了根據(jù)原始數(shù)據(jù)和隨機(jī)值生成一個簽名,然后用這簽名再次生成一個簽名

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

以上解密共分了三大步

     1、判斷數(shù)據(jù)的完整性

     2、判斷數(shù)據(jù)的一致性

     3、解密數(shù)據(jù)內(nèi)容。

這個驗證簽名有個奇怪的地方,他并不像我們平常驗證簽名一樣。我們平常驗證簽名都是,拿原始數(shù)據(jù)和隨機(jī)值生成一個簽名,然后拿生成的簽名和原始數(shù)據(jù)的簽名進(jìn)行比對來判斷是否有被篡改。

而框架卻多了一個,他用的是,通過原始數(shù)據(jù)和隨機(jī)值生成簽名后,又拿這個簽名生成了一個簽名,而要比對的也是拿原始數(shù)據(jù)里的簽名在生成一個簽名,然后進(jìn)行比對。目前想不出,為什么要多幾步操作。

在加密的時候,我們把原始數(shù)據(jù)使用serialize轉(zhuǎn)換了一下,所以我們相應(yīng)的也需要使用unserialize把數(shù)據(jù)轉(zhuǎn)換回來。

注意

  • 加密時使用的openssl_encrypt里的隨機(jī)項量值是使用的原始數(shù)據(jù)raw這種二進(jìn)制的值,使用openssl_decrypt解密后的值是使用的經(jīng)過base64位后的隨機(jī)字符串。
  • 解密的時候生成簽名比較的時候,不是用原來的簽名,然后根據(jù)原始數(shù)據(jù)的內(nèi)容,重新生成一次簽名進(jìn)行比較,而是使用原始簽名為基礎(chǔ)生成一個簽名,然后在拿原始數(shù)據(jù)為基礎(chǔ)生成的簽名,在用這個新生成的簽名重新生成了一次簽名。然后進(jìn)行比較的。
  • AES256是加密數(shù)據(jù),后面能夠逆向在進(jìn)行解密出數(shù)據(jù)。而SHA256是生成簽名的,這個過程是不可逆的,是為了驗證數(shù)據(jù)的完整性。

總結(jié)

以上就是這篇文章的全部內(nèi)容了,希望本文的內(nèi)容對大家的學(xué)習(xí)或者工作能帶來一定的幫助,如果有疑問大家可以留言交流,謝謝大家對腳本之家的支持。

相關(guān)文章

  • 在Laravel中實現(xiàn)使用AJAX動態(tài)刷新部分頁面

    在Laravel中實現(xiàn)使用AJAX動態(tài)刷新部分頁面

    今天小編就為大家分享一篇在Laravel中實現(xiàn)使用AJAX動態(tài)刷新部分頁面,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2019-10-10
  • php設(shè)計模式之備忘模式分析【星際爭霸游戲案例】

    php設(shè)計模式之備忘模式分析【星際爭霸游戲案例】

    這篇文章主要介紹了php設(shè)計模式之備忘模式,結(jié)合星際爭霸游戲案例形式分析了PHP備忘模式相關(guān)原理、使用技巧與操作注意事項,需要的朋友可以參考下
    2020-03-03
  • ThinkPHP5與單元測試PHPUnit使用詳解

    ThinkPHP5與單元測試PHPUnit使用詳解

    這篇文章主要介紹了ThinkPHP5與單元測試PHPUnit使用詳解,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-02-02
  • Symfony2針對輸入時間進(jìn)行查詢的方法分析

    Symfony2針對輸入時間進(jìn)行查詢的方法分析

    這篇文章主要介紹了Symfony2針對輸入時間進(jìn)行查詢的方法,結(jié)合實例形式分析了Symfony2針對mysql及MongoDB的輸入時間進(jìn)行轉(zhuǎn)換與查詢的相關(guān)操作技巧,需要的朋友可以參考下
    2017-06-06
  • Zend的Registry機(jī)制的使用說明

    Zend的Registry機(jī)制的使用說明

    本篇文章介紹了,Zend的Registry機(jī)制的使用說明。需要的朋友參考下
    2013-05-05
  • PHP dirname簡單使用代碼實例

    PHP dirname簡單使用代碼實例

    這篇文章主要介紹了PHP dirname簡單使用代碼實例,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下
    2020-11-11
  • PHP模板引擎Smarty中變量的使用方法示例

    PHP模板引擎Smarty中變量的使用方法示例

    這篇文章主要介紹了PHP模板引擎Smarty中變量的使用方法,詳細(xì)講述了Smarty模板的原理,下載,配置方法與變量的使用技巧,需要的朋友可以參考下
    2016-04-04
  • Centos下升級php5.2到php5.4全記錄(編譯安裝)

    Centos下升級php5.2到php5.4全記錄(編譯安裝)

    這篇文章主要介紹了Centos下升級php5.2到php5.4全記錄(編譯安裝),本文還同時講解了解決htmlspecialchars默認(rèn)編碼UTF-8問題的解決方法,需要的朋友可以參考下
    2015-04-04
  • 全新的PDO數(shù)據(jù)庫操作類php版(僅適用Mysql)

    全新的PDO數(shù)據(jù)庫操作類php版(僅適用Mysql)

    在公司里也用了1年之久。如今公司規(guī)模變大了,產(chǎn)品也日益完善,曾經(jīng)的那個數(shù)據(jù)庫操作函數(shù)雖說使用上沒出什么大問題,但為了更顯專業(yè),花了1天時間重寫了這個,現(xiàn)在,它確實是個類了
    2012-07-07
  • PHP rsa加密解密使用方法

    PHP rsa加密解密使用方法

    這篇文章主要介紹了PHP rsa加密解密使用方法,本文講解了生成公鑰、私鑰及PHP中使用生成的公鑰、私鑰進(jìn)行加密解密實例,需要的朋友可以參考下
    2015-04-04

最新評論