前言:由于项目快速发展,敏感数据的保密传输也不够完善,前期开发写的比较简陋从而埋下隐患。迫切需要提升安全。翻阅相关文档也写到:‘’PHP服务端
与客户端
交互或者提供开放API时,通常需要对敏感的数据进行加密。这时候RSA非对称加密
就可以派上用处。“对此记录开发过程,总结心得。
翻阅资料,先了解什么是非对称加密算法
在非对称加密中使用的主要算法有:RSA、Elgamal、ESA、背包算法、Rabin、D-H、ECC(椭圆曲线加密算法)等。不同算法的实现机制不同,可参考对应算法的详细资料。
非对称加密算法:
需要两个密钥来进行加密和解密,这两个秘钥是公开密钥(public key,简称公钥)
和私有密钥(private key,简称私钥)
。
工作原理
:用公开密钥
对数据进行加密,只有用对应的私有密钥
才能解密;
如果用私有密钥
对数据进行加密,那么只有用对应的公开密钥
才能解密。
因为加密和解密使用的是两个不同
的密钥,所以这种算法叫作[非对称加密算法]
。
与对称加密算法的对比
优点
:其安全性更好,对称加密的通信双方使用相同的秘钥,如果一方的秘钥遭泄露,那么整个通信就会被破解。而非对称加密使用一对秘钥,一个用来加密,一个用来解密,而且公钥是公开的,秘钥是自己保存的,不需要像对称加密那样在通信之前要先同步秘钥。
缺点
:非对称加密的缺点是加密和解密花费时间长、速度慢,只适合对少量数据进行加密。
前期准备
前提
:本文章是在TP5
下操作。1.准备
RSA算法类
。https://www.kancloud.cn/mikkle/thinkphp5_study/3433032.准备
jsencrypt.js
。https://www.bootcdn.cn/jsencrypt/3.在线生产RSA秘钥工具。http://web.chacuo.net/netrsakeypair
开始实操
先上一个我修改过的RSA算法类
<?php
/**
* Created by PhpStorm.
* User: ***
* Date: 2020/3/4
*/
namespace Library;
/**
* RSA算法类
* 签名及密文编码:base64字符串/十六进制字符串/二进制字符串流
* 填充方式: PKCS1Padding(加解密)/NOPadding(解密)
*
* Notice:Only accepts a single block. Block size is equal to the RSA key size!
* 如密钥长度为1024 bit,则加密时数据需小于128字节,加上PKCS1Padding本身的11字节信息,所以明文需小于117字节
*
* 加入生成私匙和公匙
*/
class RsaEncryption
{
public $pubKey;
private $priKey;
/**
* 初始化
*
*/
public function __construct()
{
$this->pubKey = '你的公钥';
$this->priKey = '你的私钥';
}
/**
* 自定义错误处理
*/
private function _error($msg)
{
die('RSA Error:' . $msg); //TODO
}
/**
* 生成签名
*
* @param string 签名材料
* @param string 签名编码(base64/hex/bin)
* @return 签名值
*/
public function sign($data, $code = 'base64')
{
$ret = false;
if (openssl_sign($data, $ret, $this->priKey)) {
$ret = $this->_encode($ret, $code);
}
return $ret;
}
/**
* 加密
*
* @param string 明文
* @param string 密文编码(base64/hex/bin)
* @param int 填充方式(貌似php有bug,所以目前仅支持OPENSSL_PKCS1_PADDING)
* @return string 密文
*/
public function encrypt($data, $code = 'base64', $padding = OPENSSL_PKCS1_PADDING)
{
$ret = false;
if (!$this->_checkPadding($padding, 'en')) $this->_error('padding error');
if (openssl_public_encrypt($data, $result, $this->pubKey, $padding)) {
$ret = $this->_encode($result, $code);
}
return $ret;
}
/**
* 解密
* @param string $encryptString
* @return string
*/
public function privateDecrypt($encryptString = '')
{
$decrypted = '';
$key = $this->priKey;
$key_eol = (string) implode("\n", str_split((string) $key, 64));
$privateKey = (string) "-----BEGIN RSA PRIVATE KEY-----\n" . $key_eol . "\n-----END RSA PRIVATE KEY-----";
openssl_private_decrypt(base64_decode($encryptString), $decrypted, $privateKey);
return $decrypted;
}
/**
* 加密
* @param string $data
* @return string
*/
public function publicEncrypt($data = '')
{
$encrypt_data = '';
$key = $this->pubKey;
$key_eol = (string) implode("\n", str_split((string) $key, 64));
$publicKey = (string) "-----BEGIN PUBLIC KEY-----\n" . $key_eol . "\n-----END PUBLIC KEY-----";
openssl_public_encrypt($data, $encrypt_data, $publicKey);
$encrypt_data = base64_encode($encrypt_data);
return $encrypt_data;
}
// 私有方法
/**
* 检测填充类型
* 加密只支持PKCS1_PADDING
* 解密支持PKCS1_PADDING和NO_PADDING
*
* @param int 填充模式
* @param string 加密en/解密de
* @return bool
*/
private function _checkPadding($padding, $type)
{
if ($type == 'en') {
switch ($padding) {
case OPENSSL_PKCS1_PADDING:
$ret = true;
break;
default:
$ret = false;
}
} else {
switch ($padding) {
case OPENSSL_PKCS1_PADDING:
case OPENSSL_NO_PADDING:
$ret = true;
break;
default:
$ret = false;
}
}
return $ret;
}
private function _encode($data, $code)
{
switch (strtolower($code)) {
case 'base64':
$data = base64_encode('' . $data);
break;
case 'hex':
$data = bin2hex($data);
break;
case 'bin':
default:
}
return $data;
}
}
1.先引用RSA
use Library\RsaEncryption;
2.在需要加密数据的页面给公钥
public function index()
{
$rsa = new RsaEncryption();
$key = $rsa->pubKey;
$this->assign('key', $key);
//$redisInstall = Cache::getInstance('redis');
return $this->fetch();
}
3.前端页面进行加密处理
比如在表单提交需要对密码加密
//需要加密的数据
var pas = $('#password').val();
var encrypt = new JSEncrypt();
//用传来的公钥进行加密
encrypt.setPublicKey('拿到的公钥');
var encrypted = encrypt.encrypt(pas);
//返给后端加密过后的数据
var pwd = document.getElementById('pwd');
pwd.value = encrypted;
4.在后端解密
$rsa = new RsaEncryption();
$rsaPass = $rsa->privateDecrypt('传回来的数据');
注意
密钥不对可是会报以下错误。
切记格式要正确,不可有换行,要去头去尾。
总结
以上是我对RSA加解密一些简单操作的一个记录,如果有帮助到大家,就可以了~ 望大佬勿喷勿喷。。