php RSA和AES的加密
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了php RSA和AES的加密相关的知识,希望对你有一定的参考价值。
# RSA和AES的加密
<?php
/**
* Created by PhpStorm.
* User: code
* Date: 2019/4/15
* Time: 10:55
*/
namespace App\Helper\Classes\ApiCipher;
use App\Helper\Traits\Singleton;
/**
* RSA(非对称)和AES(对称)加密数据
*
* 模拟一个https流程
*
* 有分:
* 1、服务器单向RSA + AES(已实现)
* 2、双向RSA + AES
*/
abstract class BaseRSAAndAES
{
use Singleton;
/**
* @return mixed|array
*/
abstract public function getConfig();
public function getPublicKey()
{
return $this->getConfig()['public'] ?? '';
}
/**
* 直接获取解密后的数据
*
* @param string $key 被RSA公钥加密过的AES的key,此key经过base64和url的转码
* @param string $dataString 被加密的数据
* @return array
*/
public function getData($key, $dataString = '')
{
// 有时候处理xdebug就报错
$aesKey = $this->getDecrypt(urldecode(base64_decode(urldecode($key)))); // 拿到公钥
return [
'aes' => $aesKey,
'data' => $dataString ? $this->getAESData($aesKey, $dataString) : '',
];
}
/**
* 获取AES数据
*
* @param string $aesKey AES的key
* @param string $dataString 被AES加密的数据
* @return string
*/
public function getAESData($aesKey, $dataString)
{
$aes = new \phpseclib\Crypt\AES(\phpseclib\Crypt\AES::MODE_ECB);
$aes->setKey($aesKey);
return $aes->decrypt(urldecode(base64_decode(urldecode($dataString))));
}
/**
* 根据RSA的私钥 解密AES的key
*
* @param string $key
* @return string
*/
public function getDecrypt($key)
{
$rsa = new \phpseclib\Crypt\RSA();
$rsa->loadKey($this->getPrivateKey());
return $rsa->decrypt($key);
}
/**
* RSA根据公钥加密$text
*
* @param string $text
* @return string
*/
public function getEncryptRSA($text)
{
$rsa = new \phpseclib\Crypt\RSA();
$rsa->loadKey($this->getPublicKey());
return $rsa->encrypt($text);
}
/**
* AES加密
*
* @param $key
* @param $text
* @return string
*/
public function getEncryptAES($key, $text)
{
$aes = new \phpseclib\Crypt\AES(\phpseclib\Crypt\AES::MODE_ECB);
$aes->setKey($key);
return $aes->encrypt($text);
}
/**
* 根据公钥加密$text,并base64转码,然后url转码
*
* @param $text
* @return string
*/
public function getEncryptRSAForBase64($text)
{
return urlencode(base64_encode(urlencode($this->getEncryptRSA($text))));
}
public function getEncryptAESForBase64($key, $text)
{
return urlencode(base64_encode(urlencode($this->getEncryptAES($key, $text))));
}
/**
* 创建公钥和私钥
*
* @return array
*/
public function createKey()
{
$rsa = new \phpseclib\Crypt\RSA();
return $rsa->createKey();
}
protected function getPrivateKey()
{
return $this->getConfig()['private'] ?? '';
}
}
<?php
/**
* Created by PhpStorm.
* User: code
* Date: 2019/4/17
* Time: 14:08
*/
namespace App\Helper\Classes\ApiCipher;
use App\Helper\Vendor\Laravel\Cache;
class LaravelRSAAndAES extends BaseRSAAndAES
{
/**
* @return mixed|array
*/
public function getConfig()
{
return config('hashing.rsa');
}
protected function getAESKeyCacheMinute()
{
return config('sys.cache.user-aes-key-minute');
}
/**
* 获取token的缩小版
*
* @return string
*/
protected function getMd5Token()
{
return md5(\Illuminate\Support\Facades\Auth::getToken());
}
/**
* 获取aes的key
*
* @return mixed
*/
public function getUserAESKeyMap()
{
return Cache::get($this->getUserAESKeyToCacheKey(), '');
}
/**
* 保存aes的key
*
* @param $aesKey
*/
public function saveUserAESKeyMap($aesKey)
{
if (empty($aesKey)) {
return;
}
Cache::put($this->getUserAESKeyToCacheKey(), $aesKey, $this->getAESKeyCacheMinute());
}
/**
* 每个接口的AES绑定接口的token
*
* @return string
*/
protected function getUserAESKeyToCacheKey()
{
return 'AES:' . $this->getMd5Token();
}
}
<?php
/**
* Created by PhpStorm.
* User: code
* Date: 2019/4/15
* Time: 11:41
*/
namespace App\Helper\Classes\ApiCipher;
trait RSAAndAESControllerTrait
{
/**
* 保存aes的key,中间件会保存,直接返回成功即可
*
* @return mixed
*/
public function saveAESKey()
{
return $this->success();
}
}
<?php
/**
* Created by PhpStorm.
* User: code
* Date: 2019/4/15
* Time: 11:46
*/
namespace App\Helper\Classes\ApiCipher;
use \App\Helper\Classes\ApiCipher\LaravelRSAAndAES as CipherClass;
class RSAAndAESLaravelInputMiddleware
{
use \Illuminate\Foundation\Validation\ValidatesRequests;
protected $errorText = [
'data_required' => 'data加密的数据不能为空',
'data_error' => 'data加密的数据错误',
'key_error' => 'key密钥错误',
];
/**
* 指定需要加密的AES的key
* 是否加密返回结果
*
* @var string
*/
protected $aesKey = '';
/**
* 处理定义多次的问题
*
* @var bool
*/
protected static $cipherBool = false;
protected function getCipherClass()
{
return CipherClass::instance(); // 系统继承的类
}
/**
* @param \Illuminate\Http\Request $request
* @param \Closure $next
* @param bool $force 强制校验
* @return mixed
* @throws \Illuminate\Validation\ValidationException
*/
public function handle($request, \Closure $next, $force = false)
{
if (
(!$force && ifNotProduction()) // 只有正式环境才加密
|| !ifFirstBool(__CLASS__)
){
return $next($request);
}
// 中间件结束后执行
\Illuminate\Support\Facades\Event::listen(\Illuminate\Foundation\Http\Events\RequestHandled::class, function ($event){
/** @var \Illuminate\Foundation\Http\Events\RequestHandled $event */
$this->cipherResponse($event->response);
});
// 处理加密
if (empty($this->getRequestKey($request))){ // 已保存AES的key,不需要再传参
$this->handleTokenData($request);
}else{
$this->handleKeyData($request);
}
return $next($request);
}
/**
* 根据token找到AES的key
*
* @param \Illuminate\Http\Request $request
* @throws \Illuminate\Validation\ValidationException
*/
protected function handleTokenData($request)
{
$this->aesKey = $this->getCipherClass()->getUserAESKeyMap();
if (empty($this->aesKey)) {
$this->throwValidateError($request, $this->errorText['key_error']);
}
$requestData = $this->getRequestData($request);
$data = [];
try{
$data = (array)json_decode_not_throw($this->getCipherClass()->getAESData($this->aesKey, $requestData['data']));
}catch (\Exception $exception){ // 处理Decryption error报错
$this->throwValidateError($request, $exception->getMessage());
}
$this->requestSet($request, $data);
}
/**
* 每次都传key
*
* @param \Illuminate\Http\Request $request
* @throws \Illuminate\Validation\ValidationException
*/
protected function handleKeyData($request)
{
$requestKey = $this->getRequestKey($request);
$requestData = $this->getRequestData($request);
$data = '';
try{
$this->aesKey = $this->getCipherClass()->getRSADecrypt($requestKey);
$data = !empty($requestData['data']) ? $this->getCipherClass()->getAESData($this->aesKey, $requestData['data']) : '';
}catch (\Exception $exception){ // 处理Decryption error报错
$this->throwValidateError($request, $exception->getMessage());
}
if ($data !== false){
$data = json_decode_not_throw($data);
}else{ // 解密失败,如果是空则返回空字符串
$this->throwValidateError($request, $this->errorText['data_error']);
}
$this->requestSet($request, (array)$data);
$this->getCipherClass()->saveUserAESKeyMap($this->aesKey);
}
/**
* 获取请求参数里的AES的key的字符串
*
* @param \Illuminate\Http\Request $request
* @return array|string|null
*/
protected function getRequestKey($request)
{
return $request->header('aes-key');
}
/**
* 获取请求参数里的被AES加密的数据
*
* @param \Illuminate\Http\Request $request
* @return array
* @throws \Illuminate\Validation\ValidationException
*/
protected function getRequestData($request)
{
$requestData = $this->validate($request, [
'data' => 'sometimes|required'
], ['data.required' => $this->errorText['data_required'],]);
$request->offsetUnset('data');
$requestData['data'] = $requestData['data'] ?? '';
return $requestData;
}
/**
* 抛出验证错误
*
* @param \Illuminate\Http\Request $request
* @param $message
* @throws \Illuminate\Validation\ValidationException
*/
protected function throwValidateError($request, $message)
{
$request->merge(['aesKey' => $this->aesKey]); // 通过request来传参
$this->validate(\Illuminate\Http\Request::create(''), ['key' => 'required'], ['key.required' => $message]);
}
/**
* @param \Illuminate\Http\Request $request
* @param $data
*/
protected function requestSet($request, $data)
{
foreach ($request->keys() as $key) {
unset($request[$key]);
}
$request->merge($data);
}
/**
* 加密response
*
* @param $dataResponse
*/
protected function cipherResponse($dataResponse)
{
if ($this->aesKey){ // 需要加密返回的response
$aesKey = $this->aesKey;
$this->aesKey = '';
if (is_object($dataResponse) && $dataResponse instanceof \Illuminate\Http\JsonResponse){ // 全加密
// 请求要考虑get,所以请求时加密的数据要放在
$dataResponse->setContent($this->getCipherClass()->getEncryptAES($aesKey, $dataResponse->getContent()));
}
}
}
}
以上是关于php RSA和AES的加密的主要内容,如果未能解决你的问题,请参考以下文章