Rsa.php 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200
  1. <?php
  2. /**
  3. * +----------------------------------------------------------------------
  4. * | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
  5. * +----------------------------------------------------------------------
  6. * | Copyright (c) 2016~2022 https://www.crmeb.com All rights reserved.
  7. * +----------------------------------------------------------------------
  8. * | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
  9. * +----------------------------------------------------------------------
  10. * | Author: CRMEB Team <admin@crmeb.com>
  11. * +----------------------------------------------------------------------
  12. */
  13. namespace crmeb\utils;
  14. use think\exception\ValidateException;
  15. /**
  16. * Class Rsa
  17. * @author 等风来
  18. * @email 136327134@qq.com
  19. * @date 2023/5/16
  20. * @package crmeb\utils
  21. */
  22. class Rsa
  23. {
  24. /**
  25. * @var string
  26. */
  27. protected $publicKey;
  28. /**
  29. * @var string
  30. */
  31. protected $privateKey;
  32. /**
  33. * @var string
  34. */
  35. protected $basePath;
  36. /**
  37. * 获取证书文件
  38. * @param $publicKey
  39. * @param $privateKey
  40. */
  41. public function __construct(string $publicKey = 'cert_public_password.key', string $privateKey = 'cert_private_password.key')
  42. {
  43. $this->basePath = app()->getRootPath();
  44. if ($publicKey) {
  45. $this->publicKey = $this->basePath . $publicKey;
  46. }
  47. if ($privateKey) {
  48. $this->privateKey = $this->basePath . $publicKey;
  49. }
  50. if (!is_file($this->publicKey) || !is_file($this->privateKey)) {
  51. $this->exportOpenSSLFile();
  52. }
  53. }
  54. /**
  55. * @return false|string
  56. * @author 等风来
  57. * @email 136327134@qq.com
  58. * @date 2023/5/16
  59. */
  60. public function getPublicKey()
  61. {
  62. if (!is_file($this->publicKey)) {
  63. $this->exportOpenSSLFile();
  64. }
  65. return file_get_contents($this->publicKey);
  66. }
  67. /**
  68. * 生成证书
  69. * @return bool
  70. */
  71. public function exportOpenSSLFile($passwork = null)
  72. {
  73. $publicKey = $privateKey = '';
  74. $dir = app()->getRootPath() . 'runtime/conf';
  75. $conf = 'openssl.cnf';
  76. if (!is_dir($dir)) {
  77. mkdir($dir, 0700);
  78. }
  79. if (!file_exists($conf)) {
  80. touch($dir . '/' . $conf);
  81. }
  82. //参数设置
  83. $config = [
  84. "digest_alg" => "sha256",
  85. //字节数 512 1024 2048 4096 等
  86. "private_key_bits" => 1024,
  87. "config" => $dir . '/' . $conf,
  88. //加密类型
  89. "private_key_type" => OPENSSL_KEYTYPE_RSA,
  90. ];
  91. //创建私钥和公钥
  92. $res = openssl_pkey_new($config);
  93. if ($res == false) {
  94. //创建失败,请检查openssl.cnf文件是否存在
  95. return false;
  96. }
  97. //将密钥导出为PEM编码的字符串,并输出(通过引用传递)。
  98. openssl_pkey_export($res, $privateKey, $passwork, $config);
  99. $publicKey = openssl_pkey_get_details($res);
  100. $publicKey = $publicKey["key"];
  101. //生成证书
  102. $createPublicFileRet = file_put_contents($this->publicKey, $publicKey);
  103. $createPrivateFileRet = file_put_contents($this->privateKey, $privateKey);
  104. if (!($createPublicFileRet || $createPrivateFileRet)) {
  105. return false;
  106. }
  107. openssl_free_key($res);
  108. return true;
  109. }
  110. /**
  111. * 数据加密
  112. * @param string $data
  113. * @param string|null $passwork
  114. * @return false|string
  115. * @author 等风来
  116. * @email 136327134@qq.com
  117. * @date 2023/5/16
  118. */
  119. function privateEncrypt(string $data, string $passwork = null)
  120. {
  121. $encrypted = '';
  122. $pi_key = openssl_pkey_get_private(file_get_contents($this->privateKey), $passwork);//这个函数可用来判断私钥是否是可用的,可用返回资源id Resource id
  123. //最大允许加密长度为117,得分段加密
  124. $plainData = str_split($data, 100);//生成密钥位数 1024 bit key
  125. foreach ($plainData as $chunk) {
  126. $partialEncrypted = '';
  127. $encryptionOk = openssl_private_encrypt($chunk, $partialEncrypted, $pi_key);//私钥加密
  128. if ($encryptionOk === false) {
  129. return false;
  130. }
  131. $encrypted .= $partialEncrypted;
  132. }
  133. $encrypted = base64_encode($encrypted);//加密后的内容通常含有特殊字符,需要编码转换下,在网络间通过url传输时要注意base64编码是否是url安全的
  134. return $encrypted;
  135. }
  136. /**
  137. * RSA公钥解密(私钥加密的内容通过公钥可以解密出来)
  138. * @param string $public_key 公钥
  139. * @param string $data 私钥加密后的字符串
  140. * @return string $decrypted 返回解密后的字符串
  141. * @author mosishu
  142. */
  143. function publicDecrypt(string $data)
  144. {
  145. $decrypted = '';
  146. $pu_key = openssl_pkey_get_public(file_get_contents($this->publicKey));//这个函数可用来判断公钥是否是可用的
  147. $plainData = str_split(base64_decode($data), 128);//生成密钥位数 1024 bit key
  148. foreach ($plainData as $chunk) {
  149. $str = '';
  150. $decryptionOk = openssl_public_decrypt($chunk, $str, $pu_key);//公钥解密
  151. if ($decryptionOk === false) {
  152. return false;
  153. }
  154. $decrypted .= $str;
  155. }
  156. return $decrypted;
  157. }
  158. /**
  159. * 私钥解密
  160. * @param string $data
  161. * @return mixed
  162. * @author 等风来
  163. * @email 136327134@qq.com
  164. * @date 2023/5/16
  165. */
  166. public function privateDecrypt(string $data)
  167. {
  168. if (!is_file($this->privateKey)) {
  169. $this->exportOpenSSLFile();
  170. }
  171. $res = openssl_private_decrypt(base64_decode($data), $decryptedData, file_get_contents($this->privateKey));
  172. if (false === $res) {
  173. throw new ValidateException('RSA:解密失败');
  174. }
  175. return $decryptedData;
  176. }
  177. }