You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
220 lines
5.0 KiB
220 lines
5.0 KiB
<?php
|
|
class Crypt
|
|
{
|
|
// 配置
|
|
public $config;
|
|
// 错误信息
|
|
public $err_msg = '';
|
|
|
|
|
|
/**
|
|
* 构造函数
|
|
*/
|
|
public function __construct(array $config)
|
|
{
|
|
$this->config = $config;
|
|
}
|
|
|
|
|
|
/**
|
|
* 数据校验
|
|
* @param array $data 待校验数据
|
|
* @return bool
|
|
*/
|
|
private function checkData(array $data)
|
|
{
|
|
// 非空校验
|
|
if( count($data) == 0 )
|
|
{
|
|
$this->err_msg = '待签名数据为空';
|
|
return false;
|
|
}
|
|
// 一维数组校验
|
|
if( count($data) != count($data, 1) )
|
|
{
|
|
$this->err_msg = '待签名数据不能是多维数组';
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
/**
|
|
* 生成签名
|
|
* @param array $data 待签名数据
|
|
* @return bool|string
|
|
*/
|
|
public function makeSign(array $data)
|
|
{
|
|
// 数据校验
|
|
$check_data = $this->checkData($data);
|
|
if($check_data === false)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
// 升序排列
|
|
ksort($data);
|
|
// 转字符串
|
|
$pre_sign_str = http_build_query($data);
|
|
// echo "[pre_sign_str(jiao yi message)]: {$pre_sign_str}";
|
|
// die();
|
|
|
|
// 读取私钥
|
|
$private_key = file_get_contents($this->config['private_key']);
|
|
$private_key = openssl_pkey_get_private($private_key);
|
|
|
|
// 私钥签名
|
|
$res = openssl_sign($pre_sign_str, $sign, $private_key);
|
|
if($res === false)
|
|
{
|
|
$this->err_msg = openssl_error_string();
|
|
return false;
|
|
}
|
|
// 签名转Base64
|
|
$sign = base64_encode($sign);
|
|
|
|
return $sign;
|
|
}
|
|
|
|
|
|
/**
|
|
* 校验签名
|
|
* @param array $data 待校验数据
|
|
* @param string $sign 签名
|
|
* @return bool
|
|
*/
|
|
public function checkSign(array $data, string $sign)
|
|
{
|
|
// 数据校验
|
|
$check_data = $this->checkData($data);
|
|
if($check_data === false)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
// 签名转二进制
|
|
$sign = base64_decode($sign);
|
|
|
|
// 升序排列
|
|
ksort($data);
|
|
// 转字符串
|
|
$pre_sign_str = http_build_query($data);
|
|
$pre_sign_str = urldecode($pre_sign_str);
|
|
// echo "[pre sign str]: {$pre_sign_str}";
|
|
// die();
|
|
|
|
// 读取公钥
|
|
$public_key = file_get_contents($this->config['public_key']);
|
|
$public_key = openssl_pkey_get_public($public_key);
|
|
|
|
// 公钥验签
|
|
$res = openssl_verify($pre_sign_str, $sign, $public_key);
|
|
if($res === false)
|
|
{
|
|
$this->err_msg = openssl_error_string();
|
|
return false;
|
|
}
|
|
|
|
return $res;
|
|
}
|
|
|
|
|
|
/**
|
|
* 加密交易报文
|
|
* @param array $data 待签名数据
|
|
* @return bool|string
|
|
*/
|
|
public function encryptTradeData(array $data)
|
|
{
|
|
// 数据校验
|
|
$check_data = $this->checkData($data);
|
|
if($check_data === false)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
// 读取公钥
|
|
$public_key = file_get_contents($this->config['public_key']);
|
|
$public_key = openssl_pkey_get_public($public_key);
|
|
// 公钥长度(bit)
|
|
$public_key_info = openssl_pkey_get_details($public_key);
|
|
$public_key_bit = $public_key_info['bits'];
|
|
// 数据长度(数据长度=密钥字节数-11,11为OPENSSL_PKCS1_PADDING的填充长度)
|
|
$data_length = $public_key_bit / 8 - 11;
|
|
|
|
// 待加密数据转json
|
|
$pre_encrypt_data = json_encode($data, JSON_UNESCAPED_UNICODE|JSON_UNESCAPED_SLASHES);
|
|
// 按密钥长度拆分数据
|
|
$pre_encrypt_data_arr = str_split($pre_encrypt_data, $data_length);
|
|
// 分段公钥加密
|
|
$crypted_data = '';
|
|
foreach($pre_encrypt_data_arr as $key=>$val)
|
|
{
|
|
$res = openssl_public_encrypt($val, $crypted_data_tmp, $public_key, OPENSSL_PKCS1_PADDING);
|
|
if($res === false)
|
|
{
|
|
$this->err_msg = openssl_error_string();
|
|
return false;
|
|
}
|
|
$crypted_data .= $crypted_data_tmp;
|
|
}
|
|
// 加密结果转Base64
|
|
$crypted_data = base64_encode($crypted_data);
|
|
|
|
return $crypted_data;
|
|
}
|
|
|
|
|
|
/**
|
|
* 解密交易报文
|
|
* @param string $data 加密的交易报文
|
|
* @return bool|array
|
|
*/
|
|
public function decryptTradeData($data)
|
|
{
|
|
// 加密数据转二进制
|
|
$pre_decrypt_data = base64_decode($data);
|
|
|
|
// 读取私钥
|
|
$private_key = file_get_contents($this->config['private_key']);
|
|
$private_key = openssl_pkey_get_private($private_key);
|
|
// 私钥长度(bit)
|
|
$private_key_info = openssl_pkey_get_details($private_key);
|
|
$private_key_bit = $private_key_info['bits'];
|
|
// 数据长度(数据长度=密钥字节数,解密时无需考虑OPENSSL_PKCS1_PADDING的填充占位)
|
|
$data_length = $private_key_bit / 8;
|
|
|
|
// 按密钥长度拆分数据
|
|
$pre_decrypt_data_arr = str_split($pre_decrypt_data, $data_length);
|
|
// 分段私钥解密
|
|
$decrypted_data = '';
|
|
foreach($pre_decrypt_data_arr as $key=>$val)
|
|
{
|
|
$res = openssl_private_decrypt($val, $decrypted_data_tmp, $private_key, OPENSSL_PKCS1_PADDING);
|
|
if($res === false)
|
|
{
|
|
$this->err_msg = openssl_error_string();
|
|
return false;
|
|
}
|
|
$decrypted_data .= $decrypted_data_tmp;
|
|
}
|
|
// 解密结果编码转换(JAVA处理后的中文一般为GBK编码)
|
|
// echo "\r\n";
|
|
// var_dump($decrypted_data);
|
|
$charset = mb_detect_encoding($decrypted_data); // 这个东西有点问题 解析出来是false 先不用了
|
|
// echo "\r\n";
|
|
// var_dump($charset);
|
|
// echo "\r\n";
|
|
|
|
$decrypted_data = mb_convert_encoding($decrypted_data, 'UTF-8', 'GBK');
|
|
// echo "\r\n";
|
|
// var_dump($decrypted_data);
|
|
return $decrypted_data;
|
|
}
|
|
|
|
|
|
}
|
|
|
|
?>
|
|
|