前言:由于項(xiàng)目快速發(fā)展,敏感數(shù)據(jù)的保密傳輸也不夠完善歉提,前期開發(fā)寫的比較簡陋從而埋下隱患浙炼。迫切需要提升安全。翻閱相關(guān)文檔也寫到:‘’PHP服務(wù)端
與客戶端
交互或者提供開放API時(shí)唯袄,通常需要對(duì)敏感的數(shù)據(jù)進(jìn)行加密弯屈。這時(shí)候RSA非對(duì)稱加密
就可以派上用處×悼剑“對(duì)此記錄開發(fā)過程资厉,總結(jié)心得。
翻閱資料,先了解什么是非對(duì)稱加密算法
在非對(duì)稱加密中使用的主要算法有:RSA蔬顾、Elgamal宴偿、ESA、背包算法诀豁、Rabin窄刘、D-H、ECC(橢圓曲線加密算法)等舷胜。不同算法的實(shí)現(xiàn)機(jī)制不同娩践,可參考對(duì)應(yīng)算法的詳細(xì)資料。
非對(duì)稱加密算法:
需要兩個(gè)密鑰來進(jìn)行加密和解密烹骨,這兩個(gè)秘鑰是公開密鑰(public key翻伺,簡稱公鑰)
和私有密鑰(private key,簡稱私鑰)
沮焕。
工作原理
:用公開密鑰
對(duì)數(shù)據(jù)進(jìn)行加密吨岭,只有用對(duì)應(yīng)的私有密鑰
才能解密;
如果用私有密鑰
對(duì)數(shù)據(jù)進(jìn)行加密峦树,那么只有用對(duì)應(yīng)的公開密鑰
才能解密辣辫。
因?yàn)榧用芎徒饷苁褂玫氖莾蓚€(gè)不同
的密鑰,所以這種算法叫作[非對(duì)稱加密算法]
魁巩。
與對(duì)稱加密算法的對(duì)比
優(yōu)點(diǎn)
:其安全性更好急灭,對(duì)稱加密的通信雙方使用相同的秘鑰,如果一方的秘鑰遭泄露歪赢,那么整個(gè)通信就會(huì)被破解化戳。而非對(duì)稱加密使用一對(duì)秘鑰,一個(gè)用來加密,一個(gè)用來解密点楼,而且公鑰是公開的扫尖,秘鑰是自己保存的,不需要像對(duì)稱加密那樣在通信之前要先同步秘鑰掠廓。
缺點(diǎn)
:非對(duì)稱加密的缺點(diǎn)是加密和解密花費(fèi)時(shí)間長换怖、速度慢,只適合對(duì)少量數(shù)據(jù)進(jìn)行加密蟀瞧。
前期準(zhǔn)備
前提
:本文章是在TP5
下操作沉颂。1.準(zhǔn)備
RSA算法類
。https://www.kancloud.cn/mikkle/thinkphp5_study/3433032.準(zhǔn)備
jsencrypt.js
悦污。https://www.bootcdn.cn/jsencrypt/3.在線生產(chǎn)RSA秘鑰工具铸屉。http://web.chacuo.net/netrsakeypair
開始實(shí)操
先上一個(gè)我修改過的RSA算法類
<?php
/**
* Created by PhpStorm.
* User: ***
* Date: 2020/3/4
*/
namespace Library;
/**
* RSA算法類
* 簽名及密文編碼:base64字符串/十六進(jìn)制字符串/二進(jìn)制字符串流
* 填充方式: PKCS1Padding(加解密)/NOPadding(解密)
*
* Notice:Only accepts a single block. Block size is equal to the RSA key size!
* 如密鑰長度為1024 bit,則加密時(shí)數(shù)據(jù)需小于128字節(jié)切端,加上PKCS1Padding本身的11字節(jié)信息彻坛,所以明文需小于117字節(jié)
*
* 加入生成私匙和公匙
*/
class RsaEncryption
{
public $pubKey;
private $priKey;
/**
* 初始化
*
*/
public function __construct()
{
$this->pubKey = '你的公鑰';
$this->priKey = '你的私鑰';
}
/**
* 自定義錯(cuò)誤處理
*/
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.在需要加密數(shù)據(jù)的頁面給公鑰
public function index()
{
$rsa = new RsaEncryption();
$key = $rsa->pubKey;
$this->assign('key', $key);
//$redisInstall = Cache::getInstance('redis');
return $this->fetch();
}
3.前端頁面進(jìn)行加密處理
比如在表單提交需要對(duì)密碼加密
//需要加密的數(shù)據(jù)
var pas = $('#password').val();
var encrypt = new JSEncrypt();
//用傳來的公鑰進(jìn)行加密
encrypt.setPublicKey('拿到的公鑰');
var encrypted = encrypt.encrypt(pas);
//返給后端加密過后的數(shù)據(jù)
var pwd = document.getElementById('pwd');
pwd.value = encrypted;
4.在后端解密
$rsa = new RsaEncryption();
$rsaPass = $rsa->privateDecrypt('傳回來的數(shù)據(jù)');
注意
密鑰不對(duì)可是會(huì)報(bào)以下錯(cuò)誤踏枣。
切記格式要正確昌屉,不可有換行,要去頭去尾茵瀑。
總結(jié)
以上是我對(duì)RSA加解密一些簡單操作的一個(gè)記錄间驮,如果有幫助到大家,就可以了~ 望大佬勿噴勿噴马昨。竞帽。