Laravel 的加密机制使用 OpenSSL 提供 AES-256 和 AES-128 的加密

1. 使用方法

  1. 首先是生成秘钥。要需要在.env目录里提供APP_KEY,这个如果没有的话,可以通过命令php artisan key:generate生成,也可以自己设置。生成后例子应该是这样的
    APP_KEY=base64:5BM1BXGOBrGeeqJMAWJZSzyzh5yPcCGOcOGPtUij65g=
  1. 在文件配置加密key和加密算法,在config/app.php的目录里有配置
$    'key' => env('APP_KEY'),'cipher' => 'AES-256-CBC',
  1. 使用方法,在laravel里已经有使用方法了,这里就不在过多的说了。主要使用的两个方法,一个是encrypt的加密,一个是decrypt的解密

2. 查找加密解密的文件

实现方法的位置是在vendor/illuminate/encryption/的目录下发现两个文件,一个是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也是可以解析。相当于省几步操作
另外,在实例化类的时候,需要传入key以及加密方式

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

上面的方法,主要是用来判断加密方式和传的key的长度是否相同,因为不同的加密方式,要求的相应的key的长度也是有要求的,具体每种加密方式要求key的长度可以查找对应的文档

    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方法,并且要求计算长度是按照8bit位来计算的。这样的好处是,不管是在哪种操作系统,计算的长度都是一样的。
通过这个考虑到不同操作系统的情况,不会出现加密出现问题的情况。

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的签名}

以上加密共分了三大步
1、生成随机码
2、生成加密内容
3、生成签名

框架用到一个优雅的方法,使用serialize生成一个值,这个方法高雅在哪里,就是不管你得内容是数组还是字符串,都能转换成字符串。
而使用serialize和使用json_encode的区别在哪,我想最大的好处是,你所要加密的内容比较大的时候,serialize相对于要快。
另外一个地方是,框架在加密的时候使用了一个随机字符串。为什么要使用随机字符串呢,因为使用了随机字符串,使每次加密的内容都是不一样的,防止别人猜出来。

3. 分析decrypt方法

解密数据,可以说是最复杂的一块,不仅要进行数据的解密,而且还要保证数据的完整性,以及数据防篡改

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

以上解密共分了三大步
1、判断数据的完整性
2、判断数据的一致性
3、解密数据内容。

这个验证签名有个奇怪的地方,他并不像我们平常验证签名一样。我们平常验证签名都是,拿原始数据和随机值生成一个签名,然后拿生成的签名和原始数据的签名进行比对来判断是否有被篡改。
而框架却多了一个,他用的是,通过原始数据和随机值生成签名后,又拿这个签名生成了一个签名,而要比对的也是拿原始数据里的签名在生成一个签名,然后进行比对。目前想不出,为什么要多几步操作。
在加密的时候,我们把原始数据使用serialize转换了一下,所以我们相应的也需要使用unserialize把数据转换回来。

注意

  1. 加密时使用的openssl_encrypt里的随机项量值是使用的原始数据raw这种二进制的值,使用openssl_decrypt解密后的值是使用的经过base64位后的随机字符串。
  2. 解密的时候生成签名比较的时候,不是用原来的签名,然后根据原始数据的内容,重新生成一次签名进行比较,而是使用原始签名为基础生成一个签名,然后在拿原始数据为基础生成的签名,在用这个新生成的签名重新生成了一次签名。然后进行比较的。
  3. AES256是加密数据,后面能够逆向在进行解密出数据。而SHA256是生成签名的,这个过程是不可逆的,是为了验证数据的完整性。

原文链接:Dennis`s blog

探索laravel里的encrypt和decrypt实现相关推荐

  1. Laravel中encrypt与decrypt的实现方法详解

    这篇文章主要给大家介绍了关于Laravel中encrypt和decrypt的实现方法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习 ...

  2. oracle 加密怎么解密,oracle加密encrypt,解密decrypt,

    oracle加密encrypt,解密decrypt, 目录 oracle加密encrypt,解密decrypt加密 解密 oracle加密encrypt,解密decrypt 有的oracle版本没有加 ...

  3. Encrypt 和 Decrypt 加密--解密

    [例句]In order to encrypt and decrypt, you need an encryption algorithm and a key. 为了进行加密和解密,您需要加密算法和密 ...

  4. oracle加密 解密,oracle加密encrypt,解密decrypt

    本文将为您描述oracle加密encrypt,解密decrypt,教程操作步骤:oracle加密encrypt,解密decrypt 目录 oracle加密encrypt,解密decrypt 加密 解密 ...

  5. How to encrypt and decrypt the Caesar Cipher with python(Ⅱ)

    上一篇文章中介绍了如何用python来解密凯撒密码,但是那是在已知密钥的情况下才可行的,大多数情况下我们是不知道加密所用的密钥,如果通过人力进行手工破解费时费力,而且极易可能出错,所以我们可以借助py ...

  6. 【JQuery】关于jQuery的load方法在Laravel里的使用

    Laravel版本: Laravel 8 jQuery版本: jquery/3.2.1/jquery.min.js 前言 由于在 jQuery 的 load 的方法里携带参数时,对于对象参数,提交时使 ...

  7. 奇点大学最年轻教职工、三家科技公司创始人,他如何用AI探索放射学里的人与机器...

    总部位于美国旧金山的新兴企业 Enlitic 创立于2014年,种子轮获得了200万美元融资.2015年10月,澳大利亚的医疗图像诊断服务公司 Capitol Health 宣布采用 Enlitic ...

  8. laravel里面的validate参数介绍

    $this->validate([],[],[],[]); //第一个参数是需要进行验证的数据,第二个参数是规则数组,第三个是对进行验证的数据进行自定义显示需哦无信息,第四个参数是对于错误信息中 ...

  9. laravel支付宝sdk接入

    自己学习使的 仅供参考 一.打开蚂蚁金服开放平台 找到研发服务->沙箱应用 设置沙箱应用保证可以使用 二.找到sdkdemo下载放到本地环境并改名为alipay配置里面的config 注释有详细 ...

最新文章

  1. yudian温控表a1温度怎么补偿_冰箱冷藏温度多少合适 冰箱冷藏温度怎么调节 看完这篇你就有答案 冰箱...
  2. 自动发邮件的程序 c语言,5分钟!教你用C语言发送邮件:附送源码+教学!
  3. Unity3D项目实战笔记(10):Unity3D编译IPA的PostEvents–节约时间利器
  4. 【对讲机的那点事】节日出游对讲机选择你了解多少?
  5. “指向指针的指针”的作用和应用
  6. Android IDA 动态调试最完善攻略,跨过各种坑
  7. C++ 拆分字符串-copy()
  8. PHP新闻APP,【优速软件】APP/小程序接口:全部新闻列表,POSCMS,CodeIgniter技术文档,PHP开发文档,迅睿CMS框架官方教程...
  9. Jupyter Lab——使用tqdm.notebook.tqdm时没有出现进度条,提示“HBox(children=(FloatProgress……”
  10. spring中的context:include-filter和context:exclude-filter的区别
  11. [转载] numpy.exp,numpy.sqrt,np.power等函数的详细理解
  12. 如何在一场面试中展现你对Python的coding能力?
  13. LINUX终端可以使用reset清除所有输出
  14. 触屏java版象棋下载 游戏下载安装_中国象棋官方版下载
  15. 中标麒麟操作系统离线安装nginx
  16. SSM+MySQL实现软件管理系统(含源码、MySQL、文档,包运行)
  17. 再追哥德尔开篇---哥德尔逻辑与哲学之一
  18. 网络口碑营销的优势和实施步骤
  19. 人大金仓删除字段_人大金仓kingbaseV7常用命令
  20. 老九学堂【C++】保留字[关键字]

热门文章

  1. linux启动xfce桌面,Xfce桌面环境美化完整教程
  2. EasyUI datagrid 排序
  3. 《软件质量保证与测试》学习笔记【第三章 软件测试过程所需技能】
  4. 送小仙女一个手持稳定器,总算达成了心愿,嘿嘿
  5. AI设计师“鹿班”核心技术公开:如何1秒设计8000张海报? 1
  6. lcm驱动加载及调用流程-MT6739
  7. rust拆自己家门_rust 腐蚀 怎么拆门 | 手游网游页游攻略大全
  8. 【Spring】第三课 Spring框架搭建MVC三层架构
  9. 那些程序员必看的诗歌美句(持续更新...)
  10. 鹦鹉学舌1c语言,鹦鹉学舌的秘密,大脑结构奇特/模仿人类语言(脑力惊人)