From e9b08fdbf234af016b34d8ed4f3528b74bb2485f Mon Sep 17 00:00:00 2001 From: net909 Date: Fri, 24 Nov 2023 22:45:30 +0800 Subject: [PATCH] 1.7 --- install.sql | 6 +- plugin/dev/cert/App.php | 106 ++++++ plugin/dev/cert/index.html | 180 ++++++++++ plugin/dev/cert_convert/App.php | 210 +++++++++++ plugin/dev/cert_convert/index.html | 327 ++++++++++++++++++ plugin/dev/csr/App.php | 107 ++++++ plugin/dev/csr/index.html | 382 ++++++++++++++++++++ plugin/dev/encrypt/index.html | 156 ++++++--- plugin/dev/guomi/App.php | 53 +++ plugin/dev/guomi/index.html | 478 ++++++++++++++++++++++++++ plugin/dev/rsa/App.php | 65 +++- plugin/dev/rsa/index.html | 318 +++++++++++++---- plugin/fun/bandwidth_waste/index.html | 3 - plugin/utility/str_hash/index.html | 15 +- plugin/web/icp/App.php | 14 +- public/assets/sm/sm2.js | 1 + public/assets/sm/sm2_utils.js | 70 ++++ public/assets/sm/sm3.js | 1 + public/assets/sm/sm4.js | 1 + update.sql | 5 + 20 files changed, 2360 insertions(+), 138 deletions(-) create mode 100644 plugin/dev/cert/App.php create mode 100644 plugin/dev/cert/index.html create mode 100644 plugin/dev/cert_convert/App.php create mode 100644 plugin/dev/cert_convert/index.html create mode 100644 plugin/dev/csr/App.php create mode 100644 plugin/dev/csr/index.html create mode 100644 plugin/dev/guomi/App.php create mode 100644 plugin/dev/guomi/index.html create mode 100644 public/assets/sm/sm2.js create mode 100644 public/assets/sm/sm2_utils.js create mode 100644 public/assets/sm/sm3.js create mode 100644 public/assets/sm/sm4.js create mode 100644 update.sql diff --git a/install.sql b/install.sql index 4c4ab96..e0b5ea4 100644 --- a/install.sql +++ b/install.sql @@ -179,7 +179,11 @@ INSERT INTO `toolbox_plugin` (`id`, `title`, `alias`, `class`, `keyword`, `weigh (92, '银行卡归属地查询', 'bankcard', 'utility\\bankcard', 'yinhangkaguishudichaxun,yhkgsdcx', 89, 1, 0, 0, 0, 3, '', '2022-10-14 16:55:08', '2022-10-21 17:35:56'), (93, '微博图片反查', 'wbimg', 'utility\\wbimg', 'weibotupianfancha,wbtpfc', 67, 1, 0, 0, 0, 3, '', '2022-10-21 17:34:20', '2022-11-08 22:06:30'), (94, 'QQ等级查询', 'qqlevel', 'wqq\\qqlevel', 'qqdengjichaxun,qqdjcx', 0, 0, 0, 0, 0, 5, '', '2023-04-23 18:06:05', '2023-04-23 18:06:05'), -(95, '短视频去水印解析', 'videoparse', 'utility\\videoparse', 'duanshipinqushuiyinjiexi,dspqsyjx', 95, 1, 0, 0, 0, 3, '', '2023-09-22 23:25:17', '2023-09-28 15:29:46'); +(95, '短视频去水印解析', 'videoparse', 'utility\\videoparse', 'duanshipinqushuiyinjiexi,dspqsyjx', 95, 1, 0, 0, 0, 3, '', '2023-09-22 23:25:17', '2023-09-28 15:29:46'), +(96, '国密SM2工具', 'guomi', 'dev\\guomi', 'guomism2,gmsm2', 0, 1, 0, 0, 19, 2, '', '2023-10-26 17:50:38', '2023-10-26 21:35:10'), +(97, '证书信息查看', 'cert', 'dev\\cert', 'zhengshuxinxichakan,zsxxck', 0, 1, 0, 0, 18, 2, '', '2023-10-27 16:05:08', '2023-10-27 16:05:08'), +(98, '证书格式转换', 'cert_convert', 'dev\\cert_convert', 'rsazhengshugeshizhuanhuan,rsazsgszh', 0, 1, 0, 0, 8, 2, '', '2023-10-24 21:25:15', '2023-10-27 16:03:56'), +(99, 'CSR生成与查看', 'csr', 'dev\\csr', 'csrshengchengchakan,csrscck', 0, 1, 0, 0, 8, 2, '', '2023-11-09 20:18:19', '2023-11-10 17:14:02'); DROP TABLE IF EXISTS `toolbox_querycache`; diff --git a/plugin/dev/cert/App.php b/plugin/dev/cert/App.php new file mode 100644 index 0000000..8dae698 --- /dev/null +++ b/plugin/dev/cert/App.php @@ -0,0 +1,106 @@ +view(); + } + + public function query(){ + if(input('post.type/d') == 2){ + $domain = input('post.domain', null, 'trim'); + if(!$domain) return msg('error','no domain'); + $port = 443; + if(strpos($domain, ':')){ + $a = explode(':', $domain); + $domain = $a[0]; + if(is_numeric($a[1])) $port = intval($a[1]); + } + if(!checkdomain($domain)) return msg('error','域名格式不正确'); + try{ + $cert = $this->getSSLCertificate($domain, $port); + }catch(Exception $e){ + return msg('error', $e->getMessage()); + } + }else{ + $cert = input('post.cert'); + if(!$cert) return msg('error','no cert'); + } + + $arr = openssl_x509_parse($cert); + if(!$arr){ + return msg('error', '证书文件错误'); + } + $pkey_detail = openssl_pkey_get_details(openssl_pkey_get_public($cert)); + + $subject_info = [ + '通用名称(CN)' => $this->format($arr['subject']['CN']), + '国家(C)' => $this->format($arr['subject']['C']), + '省份(S)' => $this->format($arr['subject']['ST']), + '城市(L)' => $this->format($arr['subject']['L']), + '组织(O)' => $this->format($arr['subject']['O']), + '部门(OU)' => $this->format($arr['subject']['OU']), + ]; + $issuer_info = [ + '通用名称(CN)' => $this->format($arr['issuer']['CN']), + '国家(C)' => $this->format($arr['issuer']['C']), + '组织(O)' => $this->format($arr['issuer']['O']), + ]; + $cert_info = [ + '序列号' => $arr['serialNumberHex'], + '签名算法' => $arr['signatureTypeSN'], + '密钥类型' => isset(self::$key_type[$pkey_detail['type']]) ? self::$key_type[$pkey_detail['type']] : '未知', + '密钥强度' => $pkey_detail['bits'], + '颁发时间' => date('Y-m-d H:i:s', $arr['validFrom_time_t']), + '过期时间' => date('Y-m-d H:i:s', $arr['validTo_time_t']), + '有效期' => round(($arr['validTo_time_t']-time()) / 3600 / 24).'天', + '备用名' => $arr['extensions']['subjectAltName'], + ]; + + return msg('ok','success',['subject_info'=>$subject_info, 'issuer_info'=>$issuer_info, 'cert_info'=>$cert_info]); + } + + private function format($mixed){ + if(is_array($mixed)){ + return $mixed[array_key_first($mixed)]; + } + return $mixed; + } + + private function getSSLCertificate($domain, $port = 443) { + $context = stream_context_create([ + "ssl" => [ + "capture_peer_cert" => true, + ], + ]); + + $socket = stream_socket_client('ssl://'.$domain.':'.$port, $errno, $errstr, 10, STREAM_CLIENT_CONNECT, $context); + + if ($socket) { + $params = stream_context_get_params($socket); + if(!isset($params["options"]["ssl"]["peer_certificate"])){ + throw new Exception('域名未找到SSL证书信息'); + } + fclose($socket); + return $params["options"]["ssl"]["peer_certificate"]; + } else { + $errstr = mb_convert_encoding($errstr, 'UTF-8', 'GB2312'); + throw new Exception('域名443端口连接失败,'.$errstr); + } + } + +} \ No newline at end of file diff --git a/plugin/dev/cert/index.html b/plugin/dev/cert/index.html new file mode 100644 index 0000000..8b2f25b --- /dev/null +++ b/plugin/dev/cert/index.html @@ -0,0 +1,180 @@ +{extend name="common/plugin_layout" /} +{block name="title"}{$plugin.title} - {:config_get('title')}{/block} +{block name="main"} + +
+
+
+
+
+ 证书信息查看 +
+
+
+
+ + +
+
+ + +
+
+ + +
+
+
+
+ +
+ +
+
+
+ +
+
+ + +
+
+
+
+ +
+ +
+
+ +
+
+ +
+
+{/block} +{block name="script"} + + +{/block} \ No newline at end of file diff --git a/plugin/dev/cert_convert/App.php b/plugin/dev/cert_convert/App.php new file mode 100644 index 0000000..c4cf8b7 --- /dev/null +++ b/plugin/dev/cert_convert/App.php @@ -0,0 +1,210 @@ +view(); + } + + public function convert() + { + $from = input('post.from'); + $to = input('post.to'); + if(empty($from) || empty($to)) return msg('error', '必填项不能为空'); + + try{ + $params = []; + if($from == 'PEM' && $to != 'DER' && $to != 'PKCS7'){ + if(!isset($_FILES['private'])) return msg('error', 'PEM私钥文件不存在'); + $private_path = $_FILES['private']['tmp_name']; + $this->check_cert('PEM私钥', $private_path); + + if(!isset($_FILES['cert'])) return msg('error', 'PEM证书文件不存在'); + $cert_path = $_FILES['cert']['tmp_name']; + $this->check_cert('PEM证书', $cert_path); + + if(isset($_FILES['cacert'])){ + $cacert_path = $_FILES['cacert']['tmp_name']; + $this->check_cert('PEM证书', $cacert_path); + file_put_contents($cert_path, PHP_EOL.file_get_contents($cacert_path), FILE_APPEND); + } + + $params['private'] = new CURLFile($private_path); + $params['cert'] = new CURLFile($cert_path); + $params['pass'] = input('post.pass', null, 'trim'); + $this->check_pass('证书密码', $params['pass'], true); + $act = $to == 'JKS' ? 'pem_to_jks' : 'pem_to_pfx'; + + }elseif($from == 'PEM' && $to == 'DER'){ + if(!isset($_FILES['cert'])) return msg('error', 'PEM证书文件不存在'); + $cert_path = $_FILES['cert']['tmp_name']; + $this->check_cert('PEM证书', $cert_path); + $params['cert'] = new CURLFile($cert_path); + $act = 'pem_to_der'; + + }elseif($from == 'DER' && $to == 'PEM'){ + if(!isset($_FILES['cert'])) return msg('error', 'DER证书文件不存在'); + $cert_path = $_FILES['cert']['tmp_name']; + $this->check_cert('DER证书', $cert_path); + $params['cert'] = new CURLFile($cert_path); + $act = 'der_to_pem'; + + }elseif($from == 'PKCS12'){ + if(!isset($_FILES['cert'])) return msg('error', 'PKCS12证书文件不存在'); + $cert_path = $_FILES['cert']['tmp_name']; + $this->check_cert('PKCS12证书', $cert_path); + $params['cert'] = new CURLFile($cert_path); + if($to == 'JKS'){ + $params['srcpass'] = input('post.srcpass', null, 'trim'); + $params['destpass'] = input('post.destpass', null, 'trim'); + $this->check_pass('原证书密码', $params['srcpass'], true); + $this->check_pass('新证书密码', $params['destpass']); + $act = 'pfx_to_jks'; + }elseif($to == 'PEM'){ + $params['pass'] = input('post.pass', null, 'trim'); + $this->check_pass('原证书密码', $params['pass'], true); + $act = 'pfx_to_pem'; + } + + }elseif($from == 'JKS'){ + if(!isset($_FILES['cert'])) return msg('error', 'JKS证书文件不存在'); + $cert_path = $_FILES['cert']['tmp_name']; + $this->check_cert('JKS证书', $cert_path); + $params['cert'] = new CURLFile($cert_path); + if($to == 'PKCS12'){ + $params['srcpass'] = input('post.srcpass', null, 'trim'); + $params['destpass'] = input('post.destpass', null, 'trim'); + $this->check_pass('原证书密码', $params['srcpass']); + $this->check_pass('新证书密码', $params['destpass'], true); + if(empty($params['destpass'])) $params['destpass'] = $params['srcpass']; + $act = 'jks_to_pfx'; + }elseif($to == 'PEM'){ + $params['pass'] = input('post.pass', null, 'trim'); + $this->check_pass('原证书密码', $params['pass']); + $act = 'jks_to_pem'; + } + + }elseif($from == 'PEM' && $to == 'PKCS7'){ + if(!isset($_FILES['cert'])) return msg('error', 'PEM证书文件不存在'); + $cert_path = $_FILES['cert']['tmp_name']; + $this->check_cert('PEM证书', $cert_path); + + if(isset($_FILES['cacert'])){ + $cacert_path = $_FILES['cacert']['tmp_name']; + $this->check_cert('PEM证书', $cacert_path); + file_put_contents($cert_path, PHP_EOL.file_get_contents($cacert_path), FILE_APPEND); + } + + $params['cert'] = new CURLFile($cert_path); + $act = 'pem_to_p7b'; + + }elseif($from == 'PKCS7' && $to == 'PEM'){ + if(!isset($_FILES['cert'])) return msg('error', 'PKCS7证书文件不存在'); + $cert_path = $_FILES['cert']['tmp_name']; + $this->check_cert('PKCS7证书', $cert_path); + $params['cert'] = new CURLFile($cert_path); + $act = 'p7b_to_pem'; + + }else{ + return msg('error', '转换类型不存在'); + } + + $response = $this->requestApi($act, $params); + + $files = []; + if($to == 'PEM' && $from != 'DER' && $from != 'PKCS7' && substr($response, 0, 1) == '{'){ + $arr = json_decode($response, true); + $files[] = ['name'=>'PEM 服务器证书', 'file'=>'cert.pem', 'data'=>base64_encode($arr['cert'])]; + if(!empty($arr['extra_certs'])){ + $cacert = implode(PHP_EOL, $arr['extra_certs']); + $files[] = ['name'=>'PEM 中间/根证书', 'file'=>'cacert.pem', 'data'=>base64_encode($cacert)]; + } + $files[] = ['name'=>'PEM 私钥', 'file'=>'privatekey.pem', 'data'=>base64_encode($arr['private_key'])]; + $files[] = ['name'=>'PEM 公钥', 'file'=>'publickey.pem', 'data'=>base64_encode($arr['public_key'])]; + }elseif($to == 'PEM'){ + $files[] = ['name'=>'PEM 证书文件', 'file'=>'cert.pem', 'data'=>base64_encode($response)]; + }elseif($to == 'DER'){ + $files[] = ['name'=>'DER 证书文件', 'file'=>'cert.der', 'data'=>base64_encode($response)]; + }elseif($to == 'PKCS12'){ + $files[] = ['name'=>'PKCS12 证书文件', 'file'=>'cert.pfx', 'data'=>base64_encode($response)]; + }elseif($to == 'JKS'){ + $files[] = ['name'=>'JKS 证书文件', 'file'=>'cert.jks', 'data'=>base64_encode($response)]; + }elseif($to == 'PKCS7'){ + $files[] = ['name'=>'PKCS7 证书文件', 'file'=>'cert.p7b', 'data'=>base64_encode($response)]; + } + + return msg('ok', 'success', ['files'=>$files]); + + }catch(Exception $e){ + return msg('error', $e->getMessage()); + } + } + + private function check_cert($name, $path){ + $file_size = filesize($path); + if($file_size < 100 || $file_size > 50 * 1024){ + throw new Exception($name.'文件大小超过限制'); + } + } + + private function check_pass($name, $value, $empty = false){ + if($empty && empty($value)) return; + if(empty($value)){ + throw new Exception($name.'不能为空'); + } + if(strlen($value) < 6){ + throw new Exception($name.'至少6个字符'); + } + if(strlen($value) > 32){ + throw new Exception($name.'最多32个字符'); + } + } + + private function requestApi($act, $params){ + $requrl = self::$apiurl . '?act=' . $act; + + $ch = curl_init(); + curl_setopt($ch, CURLOPT_URL, $requrl); + curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); + curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false); + $httpheader[] = "Accept: */*"; + $httpheader[] = "Accept-Encoding: gzip,deflate,sdch"; + $httpheader[] = "Accept-Language: zh-CN,zh;q=0.8"; + $httpheader[] = "Connection: close"; + curl_setopt($ch, CURLOPT_HTTPHEADER, $httpheader); + curl_setopt($ch, CURLOPT_POST, 1); + curl_setopt($ch, CURLOPT_POSTFIELDS, $params); + curl_setopt($ch, CURLOPT_ENCODING, "gzip"); + curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); + $response = curl_exec($ch); + + if (curl_errno($ch) > 0) { + curl_close($ch); + throw new Exception('接口请求失败'); + } + + $httpStatusCode = curl_getinfo($ch, CURLINFO_HTTP_CODE); + if ($httpStatusCode != 200) { + curl_close($ch); + $arr = json_decode($response, true); + throw new Exception($arr ? $arr['msg'] : '接口返回数据解析失败'); + } + + curl_close($ch); + return $response; + } + +} \ No newline at end of file diff --git a/plugin/dev/cert_convert/index.html b/plugin/dev/cert_convert/index.html new file mode 100644 index 0000000..e43a171 --- /dev/null +++ b/plugin/dev/cert_convert/index.html @@ -0,0 +1,327 @@ +{extend name="common/plugin_layout" /} +{block name="title"}{$plugin.title} - {:config_get('title')}{/block} +{block name="main"} +
+
+
+
+
+ RSA证书格式转换 +
+
+
+ +
+ +
+
+
+ +
+ +
+
+
+
+ +
+
+ + +
+
+
+
+ +
+
+ + +
+
+
+
+ +
+
+ + +
+
+
+
+ +
+ +
+
+
+ +
+ +
+
+
+ +
+
+ + +
+
+
+
+
+ +
+ +
+
+
+ +
+ +
+
+
+
+ +
+
+ + +
+
+
+
+
+ +
+ +
+
+
+ +
+ +
+
+
+
+ +
+
+ + +
+
+
+
+ +
+
+ + +
+
+
+
+ +
+
+ + +
+
+
+ +
+
+ +
+
+
工具说明
+
+

本工具支持PEM、DER、PKCS12、PKCS7、JKS等格式的证书转换

+

证书格式介绍

+

PEM:以base64的形式存放证书、私钥,常见后缀是.pem .crt .cer .key

+

DER:以二进制的形式存放证书、私钥,常见后缀是.der .crt .cer

+

PKCS#12:以二进制的形式存放证书+私钥,通常包含保护密码,常见后缀是.pfx .p12

+

PKCS#7:以树状展示证书链,也支持单个证书,不含私钥,常见后缀是.p7b .p7c .spc

+

JKS:是Java平台使用的证书存储库文件,存放证书+私钥,有密码保护,常见后缀是.jks .ks .keystore

+
+
+
+
+
+{/block} +{block name="script"} + + + +{/block} \ No newline at end of file diff --git a/plugin/dev/csr/App.php b/plugin/dev/csr/App.php new file mode 100644 index 0000000..730fef6 --- /dev/null +++ b/plugin/dev/csr/App.php @@ -0,0 +1,107 @@ +view(); + } + + public function query(){ + $csr = input('post.csr'); + if(!$csr) return msg('error','no csr'); + + $subject_info = openssl_csr_get_subject($csr); + if(!$subject_info){ + return msg('error', 'CSR文件错误'); + } + + $pkey_detail = openssl_pkey_get_details(openssl_csr_get_public_key($csr)); + + $info = [ + '通用名称(CN)' => $this->format($subject_info['CN']), + '国家(C)' => $this->format($subject_info['C']), + '省份(S)' => $this->format($subject_info['ST']), + '城市(L)' => $this->format($subject_info['L']), + '组织(O)' => $this->format($subject_info['O']), + '部门(OU)' => $this->format($subject_info['OU']), + '密钥类型' => isset(self::$key_type[$pkey_detail['type']]) ? self::$key_type[$pkey_detail['type']] : '未知', + '密钥强度' => $pkey_detail['bits'], + ]; + + return msg('ok','success',['info'=>$info]); + } + + private function format($mixed){ + if(is_array($mixed)){ + return $mixed[array_key_first($mixed)]; + } + return $mixed; + } + + public function generate(){ + $commonName = input('post.commonName', null, 'trim');//通用名 + $countryName = input('post.countryName', null, 'trim');//国家 + $stateOrProvinceName = input('post.stateOrProvinceName', null, 'trim');//省份 + $localityName = input('post.localityName', null, 'trim');//城市 + $organizationName = input('post.organizationName', null, 'trim');//组织 + $organizationalUnitName = input('post.organizationalUnitName', null, 'trim');//部门 + $subjectAltName = input('post.subjectAltName', null, 'trim');//备用名 + $emailAddress = input('post.emailAddress', null, 'trim');//邮箱 + + $private_key_type = input('post.private_key_type/d');//密钥算法 + $private_key_bits = input('post.private_key_bits/d');//密钥长度 + $curve_name = input('post.curve_name');//曲线名称 + $digest_alg = input('post.digest_alg');//签名算法 + $pass_phrase = input('post.pass_phrase', null, 'trim');//私钥密码 + + //生成公私钥 + $config = [ + "private_key_bits" => $private_key_bits, + "private_key_type" => $private_key_type, + "curve_name" => $curve_name + ]; + $privkey = openssl_pkey_new($config); + if(!$privkey){ + return msg('error', '私钥生成失败'.openssl_error_string()); + } + $privateKey = ''; + openssl_pkey_export($privkey, $privateKey, $pass_phrase?$pass_phrase:null, $config); + $pubKey = openssl_pkey_get_details($privkey); + $publicKey = $pubKey['key']; + + //生成CSR + $dn = array( + "countryName" => $countryName, + "stateOrProvinceName" => $stateOrProvinceName, + "localityName" => $localityName, + "organizationName" => $organizationName, + "organizationalUnitName" => $organizationalUnitName, + "commonName" => $commonName, + "emailAddress" => $emailAddress, + "subjectAltName" => $subjectAltName + ); + $dn = array_filter($dn); + $csr = openssl_csr_new($dn, $privkey, array('digest_alg' => $digest_alg)); + if(!$csr){ + return msg('error', 'CSR生成失败'.openssl_error_string()); + } + openssl_csr_export($csr, $csrout); + + return msg('ok', 'success', ['public_key'=>$publicKey, 'private_key'=>$privateKey, 'csr'=>$csrout]); + } + +} \ No newline at end of file diff --git a/plugin/dev/csr/index.html b/plugin/dev/csr/index.html new file mode 100644 index 0000000..6f4966f --- /dev/null +++ b/plugin/dev/csr/index.html @@ -0,0 +1,382 @@ +{extend name="common/plugin_layout" /} +{block name="title"}{$plugin.title} - {:config_get('title')}{/block} +{block name="main"} + +
+
+
+
+
+ CSR生成与查看 +
+ +
+
+
+
+
+ + +
+
+ + +
+
+
+
+ +
+ +
+
+
+ +
+
+ + +
+
+
+ +
+
+
主题信息(以下均为选填)
+
+
+ +
+ +
+
+
+ +
+ +
+
+
+ +
+ +
+
+
+ +
+ +
+
+
+ +
+ +
+
+
+ +
+ +
+
+
+ +
+ +
+
+
+ +
+ +
+
+
+
密钥信息
+
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ +
+ +
+
+
+ +
+
+
+
+ + +
+
+{/block} +{block name="script"} + + + +{/block} \ No newline at end of file diff --git a/plugin/dev/encrypt/index.html b/plugin/dev/encrypt/index.html index 16025d2..a440dfc 100644 --- a/plugin/dev/encrypt/index.html +++ b/plugin/dev/encrypt/index.html @@ -11,45 +11,45 @@
- +
-
-
-
-
-
-
-
+
- + +
+
+
+ +
+
-
-
-
-
@@ -57,7 +57,7 @@
- +
@@ -66,44 +66,98 @@ {/block} {block name="script"} + + {/block} \ No newline at end of file diff --git a/plugin/dev/guomi/App.php b/plugin/dev/guomi/App.php new file mode 100644 index 0000000..df341f0 --- /dev/null +++ b/plugin/dev/guomi/App.php @@ -0,0 +1,53 @@ +view(); + } + + public function output() + { + $type = input('post.type/d'); + if($type == 1){ + $cert = input('post.cert'); + $pkey_res = openssl_pkey_get_public($cert); + if(!$pkey_res){ + return msg('error', '导出失败,公钥证书不正确'); + } + $pkey_detail = openssl_pkey_get_details($pkey_res); + $pkey_hex = bin2hex($this->pem2der($pkey_detail['key'])); + if(strlen($pkey_hex) > 130) $pkey_hex = substr($pkey_hex, -130); + return msg('ok', '导出成功', $pkey_hex); + }elseif($type == 2){ + $csr = input('post.csr'); + $pkey_res = openssl_csr_get_public_key($csr); + if(!$pkey_res){ + return msg('error', '导出失败,CSR不正确'); + } + $pkey_detail = openssl_pkey_get_details($pkey_res); + $pkey_hex = bin2hex($this->pem2der($pkey_detail['key'])); + if(strlen($pkey_hex) > 130) $pkey_hex = substr($pkey_hex, -130); + return msg('ok', '导出成功', $pkey_hex); + } + } + + private function pem2der($pem_data) + { + $begin = "-----"; + $end = "-----END"; + $pem_data = substr($pem_data, strpos($pem_data, $begin, 6) + strlen($begin)); + $pem_data = substr($pem_data, 0, strpos($pem_data, $end)); + $der = base64_decode($pem_data); + return $der; + } +} \ No newline at end of file diff --git a/plugin/dev/guomi/index.html b/plugin/dev/guomi/index.html new file mode 100644 index 0000000..c2e2c11 --- /dev/null +++ b/plugin/dev/guomi/index.html @@ -0,0 +1,478 @@ +{extend name="common/plugin_layout" /} +{block name="title"}{$plugin.title} - {:config_get('title')}{/block} +{block name="main"} +
+
+
+
+
+ 国密SM2公私钥生成、签名、加解密 +
+ +
+
+ +
+
+ +
+ +
+
+
+ +
+ +
+
+
+
+ + +
+
+
+
+ + +
+
+ + +
+
+
+ +
+
+ +
+
+
+ +
+ +
+
+
+ +
+ +
+
+
+
+
+ + +
+
+ + +
+
+ + +
+
+ +
+ +
+
+
+
+ +
+
+ +
+
+
+ +
+ +
+
+
+ +
+ +
+
+
+
+
+
+ +
+ +
+
+
+ +
+ +
+
+
+
+ + +
+ +
+
+
+ + +
+
+
+ +
+ +
+
+
+ +
+ +
+
+
+ +
+ +
+
+
+ +
+ +
+
+
+
+ + +
+ +
+
+
+ +
+ +
+
+
+ + +
+
+
+ +
+
+ +
+
+
+
+
+
+
+
+{/block} +{block name="script"} + + + + + +{/block} \ No newline at end of file diff --git a/plugin/dev/rsa/App.php b/plugin/dev/rsa/App.php index bb8b005..a10a9fd 100644 --- a/plugin/dev/rsa/App.php +++ b/plugin/dev/rsa/App.php @@ -19,6 +19,7 @@ class App extends Plugin "private_key_bits" => 1024, //选择在创建CSR时应该使用哪些扩展。可选值有 OPENSSL_KEYTYPE_DSA, OPENSSL_KEYTYPE_DH, OPENSSL_KEYTYPE_RSA 或 OPENSSL_KEYTYPE_EC. 默认值是 OPENSSL_KEYTYPE_RSA. "private_key_type" => OPENSSL_KEYTYPE_RSA, + "curve_name" => '' ]; private $passPhrase; private $rsaPrivateKey; @@ -28,6 +29,7 @@ class App extends Plugin private $origin; private $coded; private $opensslPadding; + private $opensslAlgo = 1; public function __construct() @@ -35,13 +37,16 @@ class App extends Plugin $this->passPhrase = request()->param("pass_phrase"); if($this->passPhrase == '') $this->passPhrase = null; $this->rsaPrivateKey = request()->param("private_key"); - $this->rsaPublicKey = request()->param("public_key"); - $this->config["private_key_bits"] = request()->param("private_key_bits"); + $this->rsaPublicKey = $this->getPemKey(request()->param("public_key"), 'PUBLIC KEY'); + $this->config["private_key_type"] = request()->param("private_key_type/d"); + $this->config["private_key_bits"] = request()->param("private_key_bits/d"); + $this->config["curve_name"] = request()->param("curve_name"); $this->data = request()->param("data"); $this->origin = request()->param("origin"); $this->coded = request()->param("coded"); $this->sign = request()->param("sign"); $this->opensslPadding = request()->param("openssl_padding"); + $this->opensslAlgo = intval(request()->param("openssl_algo")); } public function index() @@ -179,7 +184,7 @@ class App extends Plugin public function sign() { try { - if (openssl_sign($this->data, $ret, $this->getRsaPrivateKey())) { + if (openssl_sign($this->data, $ret, $this->getRsaPrivateKey(), $this->opensslAlgo)) { $ret = base64_encode($ret); return msg('ok', 'success', $ret); } @@ -203,7 +208,7 @@ class App extends Plugin $ret = false; $sign = base64_decode($this->sign); if ($sign !== false) { - if (openssl_verify($this->data, $sign, $this->rsaPublicKey) === 1) { + if (openssl_verify($this->data, $sign, $this->rsaPublicKey, $this->opensslAlgo) === 1) { $ret = true; } } @@ -231,7 +236,25 @@ class App extends Plugin public function output() { + $type = input('post.type/d'); try { + if($type == 1){ + $cert = input('post.cert'); + $pkey_res = openssl_pkey_get_public($cert); + if(!$pkey_res){ + return msg('error', '导出失败,公钥证书不正确'); + } + $pkey_detail = openssl_pkey_get_details($pkey_res); + return msg('ok', '导出成功', $pkey_detail['key']); + }elseif($type == 2){ + $csr = input('post.csr'); + $pkey_res = openssl_csr_get_public_key($csr); + if(!$pkey_res){ + return msg('error', '导出失败,CSR不正确'); + } + $pkey_detail = openssl_pkey_get_details($pkey_res); + return msg('ok', '导出成功', $pkey_detail['key']); + } $openssl_pkey_get_details = openssl_pkey_get_details($this->getRsaPrivateKey()); if ($openssl_pkey_get_details && !empty($openssl_pkey_get_details['key'])) { return msg('ok', '导出成功', $openssl_pkey_get_details['key']); @@ -242,15 +265,47 @@ class App extends Plugin } } + public function key_encrypt() + { + try { + $privateKey = openssl_pkey_get_private($this->getPemKey($this->rsaPrivateKey, 'PRIVATE KEY')); + if ($privateKey === false) { + throw new \Exception('私钥不正确或已被加密'); + } + openssl_pkey_export($privateKey, $encrypted, $this->passPhrase); + return msg('ok', '加密成功', $encrypted); + } catch (\Exception $e) { + return msg('error', $e->getMessage()); + } + } + + public function key_decrypt() + { + try { + openssl_pkey_export($this->getRsaPrivateKey(), $decrypted); + return msg('ok', '解密成功', $decrypted); + } catch (\Exception $e) { + return msg('error', $e->getMessage()); + } + } + /** * @return array|mixed|null */ public function getRsaPrivateKey() { - $privateKey = openssl_pkey_get_private($this->rsaPrivateKey, $this->passPhrase); + $privateKey = openssl_pkey_get_private($this->getPemKey($this->rsaPrivateKey, $this->passPhrase ? 'ENCRYPTED PRIVATE KEY' : 'PRIVATE KEY'), $this->passPhrase); if ($privateKey === false) { throw new \Exception('私钥不正确或密码错误'); } return $privateKey; } + + private function getPemKey($str, $type){ + if(empty($str) || strpos($str, '-----BEGIN')!==false) return $str; + $pem = "-----BEGIN ".$type."-----\n" . + wordwrap($str, 64, "\n", true) . + "\n-----END ".$type."-----"; + return $pem; + } } \ No newline at end of file diff --git a/plugin/dev/rsa/index.html b/plugin/dev/rsa/index.html index d6416df..29f3932 100644 --- a/plugin/dev/rsa/index.html +++ b/plugin/dev/rsa/index.html @@ -6,21 +6,34 @@
- RSA公私钥生成、验证、加密和解密 + RSA公私钥生成、签名、加解密
+ + +
+
+
+
+ +
@@ -34,18 +47,25 @@
- +
- +
+
+ + +
@@ -61,12 +81,6 @@
-
- -
- -
-
-
-
- -
- -
-
-
- -
- -
-
-
@@ -113,12 +113,6 @@
-
- -
- -
-
-
-
- -
- -
-
-
- -
- -
-
-
@@ -159,52 +139,119 @@
+
+
+ +
+ +
+
+
+ +
+ +
+
+
+
+ + +
+
+
+
+ + +
- +
-
+
+
+ +
+ +
+
+
+ +
+ +
+
-
-
-
+
+
+ + +
-
-
- -
- -
+
+
+
+ +
+
-
- -
- -
+
+
+ +
+ +
+
+
+ + +
+
+
+ +
+
+
@@ -216,11 +263,43 @@ {/block} {block name="script"} + diff --git a/plugin/fun/bandwidth_waste/index.html b/plugin/fun/bandwidth_waste/index.html index 73ac93b..a9fd179 100644 --- a/plugin/fun/bandwidth_waste/index.html +++ b/plugin/fun/bandwidth_waste/index.html @@ -141,9 +141,6 @@ new Vue({ const index = this.tasks.push(speed) - 1 return axios.request({ url: this.set.input, - params: { - [id]: id, - }, cancelToken: this.cancelSource.token, onDownloadProgress: function (progressEvent) { // 处理原生进度事件 diff --git a/plugin/utility/str_hash/index.html b/plugin/utility/str_hash/index.html index dcc8a41..14c45dd 100644 --- a/plugin/utility/str_hash/index.html +++ b/plugin/utility/str_hash/index.html @@ -50,6 +50,7 @@ {block name="script"} +