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.
 
 
 
 

238 lines
5.6 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,null,'&'); // bug 这里默认进行url编码 导致Sign错误
// $pre_sign_str = $data . '';
// 构建排序后的字符串
$pre_sign_str = '';
foreach ($data as $key => $value) {
$sortedString .= $key . '=' . $value . '&';
}
// 移除末尾的多余字符
$pre_sign_str = rtrim($sortedString, '&');
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);
// $pre_decrypt_data = mb_convert_encoding($pre_decrypt_data, 'UTF-8', 'GBK'); // sc_test
// echo "pre_decrypt_data\r\n";
// echo $pre_decrypt_data . "\r\n";
// 读取私钥
$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);
// echo "res:\r\n";
// echo $res . "\r\n";
if($res === false)
{
$this->err_msg = openssl_error_string();
return false;
}
$decrypted_data .= $decrypted_data_tmp;
}
// echo "after decrypted.\r\n";
// $decrypted_data = mb_convert_encoding($decrypted_data, 'UTF-8', 'GBK');
// echo $decrypted_data . "\r\n";
// 解密结果编码转换(JAVA处理后的中文一般为GBK编码)
// echo "\r\n";
// var_dump($decrypted_data);
$charset = mb_detect_encoding($decrypted_data);
// echo "\r\n";
// var_dump($charset);
// echo "\r\n";
$decrypted_data = mb_convert_encoding($decrypted_data, 'UTF-8', $charset);
// echo "\r\n";
// var_dump($decrypted_data);
return $decrypted_data;
}
}
?>