<?php
namespace app;
class RsaUtil
{
const CHAR_SET = "UTF-8";
const BASE_64_FORMAT = "UrlSafeNoPadding";
const RSA_ALGORITHM_KEY_TYPE = OPENSSL_KEYTYPE_RSA;
const RSA_ALGORITHM_SIGN = OPENSSL_ALGO_SHA256;
protected $public_key;
protected $private_key;
protected $key_len;
public function __construct($pub_key = '', $pri_key = null)
{
if ($pub_key) {
$this->public_key = $pub_key;
$pub_id = openssl_pkey_get_public($this->public_key);
$this->key_len = openssl_pkey_get_details($pub_id)['bits'];
}
if ($pri_key) {
$this->private_key = $pri_key;
$pri_id = openssl_pkey_get_private($this->private_key);
$this->key_len = openssl_pkey_get_details($pri_id)['bits'];
}
}
/*
* 创建密钥对
*/
public static function createKeys($key_size = 1024)
{
$config = array(
"private_key_bits" => $key_size,
"private_key_type" => self::RSA_ALGORITHM_KEY_TYPE,
);
$res = openssl_pkey_new($config);
openssl_pkey_export($res, $private_key);
$public_key_detail = openssl_pkey_get_details($res);
$public_key = $public_key_detail["key"];
return array(
"public_key" => $public_key,
"private_key" => $private_key,
);
}
/*
* 公钥加密
*/
public function publicEncrypt($data)
{
return $this->encryptUnicodeLong($data,$this->public_key);
}
function encryptUnicodeLong($string,$key) {
// 获取密钥的长度并计算分段长度
$maxLength = (int)($this->key_len / 8) - 11;
$subStr = "";
$encryptedString = "";
$subStart = 0;
$subEnd = 0;
$bitLen = 0;
$tmpPoint = 0;
for ($i = 0, $len = mb_strlen($string, 'UTF-8'); $i < $len; $i++) {
$char = mb_substr($string, $i, 1, 'UTF-8');
$charCode = unpack('N', mb_convert_encoding($char, 'UCS-4BE', 'UTF-8'))[1];
if ($charCode <= 0x007f) {
$bitLen += 1;
} elseif ($charCode <= 0x07ff) {
$bitLen += 2;
} elseif ($charCode <= 0xffff) {
$bitLen += 3;
} else {
$bitLen += 4;
}
if ($bitLen > $maxLength) {
$subStr = mb_substr($string, $subStart, $subEnd - $subStart, 'UTF-8');
$encrypted_temp = '';
openssl_public_encrypt($subStr, $encrypted_temp, $key);
$encryptedString .= $encrypted_temp;
$subStart = $subEnd;
$bitLen = $bitLen - $tmpPoint;
} else {
$subEnd = $i + 1;
$tmpPoint = $bitLen;
}
}
$subStr = mb_substr($string, $subStart, null, 'UTF-8');
$encrypted_temp = '';
openssl_public_encrypt($subStr, $encrypted_temp, $key);
$encryptedString .= $encrypted_temp;
return base64_encode($encryptedString);
}
/*
* 私钥解密
*/
public function privateDecrypt($encrypted)
{
$decrypted = "";
$part_len = $this->key_len / 8;
//url 中的get传值默认会吧+号过滤成' ',替换回来就好了
str_replace('% ', '+', $encrypted);
// echo $encrypted;
$base64_decoded = base64_decode($encrypted);
$parts = str_split($base64_decoded, $part_len);
foreach ($parts as $part) {
$decrypted_temp = '';
openssl_private_decrypt($part, $decrypted_temp, $this->private_key);
$decrypted .= $decrypted_temp;
}
return $decrypted;
}
/*
* 私钥加密
*/
public function privateEncrypt($data)
{
return $this->encryptUnicodeLong($data,$this->private_key);
}
/*
* 公钥解密
*/
public function publicDecrypt($encrypted)
{
$decrypted = "";
$part_len = $this->key_len / 8;
$base64_decoded = base64_decode($encrypted);
$parts = str_split($base64_decoded, $part_len);
foreach ($parts as $part) {
$decrypted_temp = '';
openssl_public_decrypt($part, $decrypted_temp, $this->public_key);
$decrypted .= $decrypted_temp;
}
return $decrypted;
}
/*
* 数据加签
*/
public function sign($data)
{
openssl_sign($data, $sign, $this->private_key, self::RSA_ALGORITHM_SIGN);
return base64_encode($sign);
}
/*
* 数据签名验证
*/
public function verify($data, $sign)
{
$pub_id = openssl_get_publickey($this->public_key);
$res = openssl_verify($data, base64_decode($sign), $pub_id, self::RSA_ALGORITHM_SIGN);
return $res;
}
}
js
npm install jsencrypt
直接改动jsencrypt.js文件,在文件最下方的 JSEncrypt.version = “3.0.0-rc.1”; 前面,添加下面的代码:
//任意长度RSA Key分段加密解密长字符串
//获取RSA key 长度
JSEncrypt.prototype.getkeylength = function () {
return ((this.key.n.bitLength()+7)>>3);
};
// 分段解密,支持中文
JSEncrypt.prototype.decryptUnicodeLong = function (string) {
var k = this.getKey();
//解密长度=key size.hex2b64结果是每字节每两字符,所以直接*2
var maxLength = ((k.n.bitLength()+7)>>3)*2;
try {
var hexString = b64tohex(string);
var decryptedString = "";
var rexStr=".{1," + maxLength + "}";
var rex =new RegExp(rexStr, 'g');
var subStrArray = hexString.match(rex);
if(subStrArray){
subStrArray.forEach(function (entry) {
decryptedString += k.decrypt(entry);
});
return decryptedString;
}
} catch (ex) {
return false;
}
};
// 分段加密,支持中文
JSEncrypt.prototype.encryptUnicodeLong = function (string) {
var k = this.getKey();
//根据key所能编码的最大长度来定分段长度。key size - 11:11字节随机padding使每次加密结果都不同。
var maxLength = ((k.n.bitLength()+7)>>3)-11;
try {
var subStr="", encryptedString = "";
var subStart = 0, subEnd=0;
var bitLen=0, tmpPoint=0;
for(var i = 0, len = string.length; i < len; i++){
//js 是使用 Unicode 编码的,每个字符所占用的字节数不同
var charCode = string.charCodeAt(i);
if(charCode <= 0x007f) {
bitLen += 1;
}else if(charCode <= 0x07ff){
bitLen += 2;
}else if(charCode <= 0xffff){
bitLen += 3;
}else{
bitLen += 4;
}
//字节数到达上限,获取子字符串加密并追加到总字符串后。更新下一个字符串起始位置及字节计算。
if(bitLen>maxLength){
subStr=string.substring(subStart,subEnd)
encryptedString += k.encrypt(subStr);
subStart=subEnd;
bitLen=bitLen-tmpPoint;
}else{
subEnd=i;
tmpPoint=bitLen;
}
}
subStr=string.substring(subStart,len)
encryptedString += k.encrypt(subStr);
return hex2b64(encryptedString);
} catch (ex) {
return false;
}
};
//添加的函数与方法结束
js使用
import JsEncrypt from 'jsencrypt';
const publicKey = `-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA33xP6Qr1qSAl43+HLXYO
oNCSobEE6BlQ5zUfG+NWeubj7yWqmP8100V95uteHB3gTJFJyYb6BxV2KTeBmvMZ
RjGA7HCWmlSLKW72L1kg6/oca4m+IsthhDHyGgOypIbpYaMP5DttVfO6mluOkvGi
N8uZt5yGDwPn6rLQyIuMsCagjMGSv8Ibm3WSfMvn1ICL4ZRZqHU94R1Xr8sdAwfS
Dq9Md/DsxNUD9w9jSp815aAt2jvrYYmGZ2uPcpCfgDuy2SZT87JnfdsYCjMGkom3
6Ry9b8obZ8pWlb+h9apU93cf46EiqjrHLwH8DFULbNLKsPgF7Xt/gOZOek33bYu0
dwIDAQAB
-----END PUBLIC KEY-----`;
export const $encruption = (str, key = publicKey) => {
const ENCRYPT = new JsEncrypt();
ENCRYPT.setPublicKey(key);
return ENCRYPT.encryptUnicodeLong(str.toString());
};
const privateKey = `-----BEGIN RSA PRIVATE KEY-----
MIIEpQIBAAKCAQEA33xP6Qr1qSAl43+HLXYOoNCSobEE6BlQ5zUfG+NWeubj7yWq
mP8100V95uteHB3gTJFJyYb6BxV2KTeBmvMZRjGA7HCWmlSLKW72L1kg6/oca4m+
IsthhDHyGgOypIbpYaMP5DttVfO6mluOkvGiN8uZt5yGDwPn6rLQyIuMsCagjMGS
v8Ibm3WSfMvn1ICL4ZRZqHU94R1Xr8sdAwfSDq9Md/DsxNUD9w9jSp815aAt2jvr
YYmGZ2uPcpCfgDuy2SZT87JnfdsYCjMGkom36Ry9b8obZ8pWlb+h9apU93cf46Ei
qjrHLwH8DFULbNLKsPgF7Xt/gOZOek33bYu0dwIDAQABAoIBAQDJBgLDNs5+UKKE
HkQzikviL3qV4qrtM0hokInpBfbWGjXQ+WqYsId0AMAdJH3EgMMvXEio87aXBKEC
tiDohd6oGwNCqottSrrajCr5sAxC9vj1ajMTDSosRNjmuYjJIWlwH8K9ow7YD6I8
EjsOxjcKRSOB21Ni0jqcDDhtC8mC762JpTGUFsrT88aIPN+WAxFdelh+GfCZMclt
HAsYiWcOEU02tyjcvhHd7azbLo4Wfx8wvWGGRN8U62USkVB5+Xmfd8tAqr5YFw2V
ZxNEs9NlrQ35lkYIJ9vg6QpxMG06im2N5PDf0724wSVgq34mthXOSRHMP4bB5e/w
0PHZ0rYxAoGBAPHIEtGXycJ456Qk1S97r5CKeW0heeYTUbaefPraVAfcwkldCPqc
NZBXspcAelyd1XxBgJ6pfzohqiy4/FcVvMNQYhcfQzmtYcx8DPXLtTrHQLDkWTOH
p2GM57RBTxMEk9crIuq+1cXxbx25KSLoCo/Txpc4yRcbgVZMCZjCrS/bAoGBAOyg
zOVeTcyTvS1Wldp59yOe1HFQtslius/Kb2xj1HCSzOfVRi79uw0MfuA1xU39Qfq4
DqAkmucbURxHRRyRHqSpomV+FbT/clkpxzgG0ZrWly8/m75StIXpQD37Y9Y/HJtX
wPQBb2ump1kO246HdMmqpASBL+pC9nd8qmkqKK6VAoGBANkKoJITryNrQ43fHpy8
bFLVa8Fibrnxl8XWqhzKBurz6ljPMnM97PuBLilNXYpsiSs85cgIIdS+SbRR7vwB
4Gx4aUWWY9OP6B4XMc8oKaz1FwZ0RfrzCHeSdKEki2ZoEoryBysxWleRrwzAncPf
BzQriLdRW3rpzwX3xhmikLNHAoGBAKPCSOq3z+mzmOmGkaCoZbO+GNHvBQDsFdL2
CxSdJgleXvZWcALXUBsgubGbJNfrXD0SIfUMQDOOgRyr6hVyDR3x09SfZJBldJJm
SlvoxCh/OBPX1oXpoMtH+FCs6JP+C2MqYPu8/oomxIvqr2G9NsLWGDqR2UIrY3yf
xyOOrKbdAoGAdR1cC8uz2Wlx37xwx/QUYv67bAwxgfUtd18bCjtfwS5Nkyf55hIU
jIwlWamZntUTItsC7bAewT7gQxOhX4E+T2U+6NQg4x71OP8AGQZe2OHAuXjXucey
trAkib1EZOKwnCTEJe7wNPorvNBFynqGgh3OTnMKykbqzO7MeLVaQnI=
-----END RSA PRIVATE KEY-----`;
export const $decryption = (str, key = privateKey) => {
const ENCRYPT = new JsEncrypt();
ENCRYPT.setPrivateKey(key);
let data = ENCRYPT.decryptUnicodeLong(str.toString());
return /^{.+}$/g.test(data) && JSON.parse(data) || data
};