欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  后端开发

php RAS加密类代码

程序员文章站 2022-04-21 16:25:00
...
通过openssl实现的签名、验签、非对称加解密,需要配合x.509证书(如crt和pem)文件使用。
  1. /**
  2. * RSA算法类
  3. * 签名及密文编码:base64字符串/十六进制字符串/二进制字符串流
  4. * 填充方式: PKCS1Padding(加解密)/NOPadding(解密)
  5. *
  6. * Notice:Only accepts a single block. Block size is equal to the RSA key size!
  7. * 如密钥长度为1024 bit,则加密时数据需小于128字节,加上PKCS1Padding本身的11字节信息,所以明文需小于117字节
  8. *
  9. * @author: linvo
  10. * @version: 1.0.0
  11. * @date: 2013/1/23
  12. */
  13. class RSA{
  14. private $pubKey = null;
  15. private $priKey = null;
  16. /**
  17. * 自定义错误处理
  18. */
  19. private function _error($msg){
  20. die('RSA Error:' . $msg); //TODO
  21. }
  22. /**
  23. * 构造函数
  24. *
  25. * @param string 公钥文件(验签和加密时传入)
  26. * @param string 私钥文件(签名和解密时传入)
  27. */
  28. public function __construct($public_key_file = '', $private_key_file = ''){
  29. if ($public_key_file){
  30. $this->_getPublicKey($public_key_file);
  31. }
  32. if ($private_key_file){
  33. $this->_getPrivateKey($private_key_file);
  34. }
  35. }
  36. /**
  37. * 生成签名
  38. *
  39. * @param string 签名材料
  40. * @param string 签名编码(base64/hex/bin)
  41. * @return 签名值
  42. */
  43. public function sign($data, $code = 'base64'){
  44. $ret = false;
  45. if (openssl_sign($data, $ret, $this->priKey)){
  46. $ret = $this->_encode($ret, $code);
  47. }
  48. return $ret;
  49. }
  50. /**
  51. * 验证签名
  52. *
  53. * @param string 签名材料
  54. * @param string 签名值
  55. * @param string 签名编码(base64/hex/bin)
  56. * @return bool
  57. */
  58. public function verify($data, $sign, $code = 'base64'){
  59. $ret = false;
  60. $sign = $this->_decode($sign, $code);
  61. if ($sign !== false) {
  62. switch (openssl_verify($data, $sign, $this->pubKey)){
  63. case 1: $ret = true; break;
  64. case 0:
  65. case -1:
  66. default: $ret = false;
  67. }
  68. }
  69. return $ret;
  70. }
  71. /**
  72. * 加密
  73. *
  74. * @param string 明文
  75. * @param string 密文编码(base64/hex/bin)
  76. * @param int 填充方式(貌似php有bug,所以目前仅支持OPENSSL_PKCS1_PADDING)
  77. * @return string 密文
  78. */
  79. public function encrypt($data, $code = 'base64', $padding = OPENSSL_PKCS1_PADDING){
  80. $ret = false;
  81. if (!$this->_checkPadding($padding, 'en')) $this->_error('padding error');
  82. if (openssl_public_encrypt($data, $result, $this->pubKey, $padding)){
  83. $ret = $this->_encode($result, $code);
  84. }
  85. return $ret;
  86. }
  87. /**
  88. * 解密
  89. *
  90. * @param string 密文
  91. * @param string 密文编码(base64/hex/bin)
  92. * @param int 填充方式(OPENSSL_PKCS1_PADDING / OPENSSL_NO_PADDING)
  93. * @param bool 是否翻转明文(When passing Microsoft CryptoAPI-generated RSA cyphertext, revert the bytes in the block)
  94. * @return string 明文
  95. */
  96. public function decrypt($data, $code = 'base64', $padding = OPENSSL_PKCS1_PADDING, $rev = false){
  97. $ret = false;
  98. $data = $this->_decode($data, $code);
  99. if (!$this->_checkPadding($padding, 'de')) $this->_error('padding error');
  100. if ($data !== false){
  101. if (openssl_private_decrypt($data, $result, $this->priKey, $padding)){
  102. $ret = $rev ? rtrim(strrev($result), "\0") : ''.$result;
  103. }
  104. }
  105. return $ret;
  106. }
  107. // 私有方法
  108. /**
  109. * 检测填充类型
  110. * 加密只支持PKCS1_PADDING
  111. * 解密支持PKCS1_PADDING和NO_PADDING
  112. *
  113. * @param int 填充模式
  114. * @param string 加密en/解密de
  115. * @return bool
  116. */
  117. private function _checkPadding($padding, $type){
  118. if ($type == 'en'){
  119. switch ($padding){
  120. case OPENSSL_PKCS1_PADDING:
  121. $ret = true;
  122. break;
  123. default:
  124. $ret = false;
  125. }
  126. } else {
  127. switch ($padding){
  128. case OPENSSL_PKCS1_PADDING:
  129. case OPENSSL_NO_PADDING:
  130. $ret = true;
  131. break;
  132. default:
  133. $ret = false;
  134. }
  135. }
  136. return $ret;
  137. }
  138. private function _encode($data, $code){
  139. switch (strtolower($code)){
  140. case 'base64':
  141. $data = base64_encode(''.$data);
  142. break;
  143. case 'hex':
  144. $data = bin2hex($data);
  145. break;
  146. case 'bin':
  147. default:
  148. }
  149. return $data;
  150. }
  151. private function _decode($data, $code){
  152. switch (strtolower($code)){
  153. case 'base64':
  154. $data = base64_decode($data);
  155. break;
  156. case 'hex':
  157. $data = $this->_hex2bin($data);
  158. break;
  159. case 'bin':
  160. default:
  161. }
  162. return $data;
  163. }
  164. private function _getPublicKey($file){
  165. $key_content = $this->_readFile($file);
  166. if ($key_content){
  167. $this->pubKey = openssl_get_publickey($key_content);
  168. }
  169. }
  170. private function _getPrivateKey($file){
  171. $key_content = $this->_readFile($file);
  172. if ($key_content){
  173. $this->priKey = openssl_get_privatekey($key_content);
  174. }
  175. }
  176. private function _readFile($file){
  177. $ret = false;
  178. if (!file_exists($file)){
  179. $this->_error("The file {$file} is not exists");
  180. } else {
  181. $ret = file_get_contents($file);
  182. }
  183. return $ret;
  184. }
  185. private function _hex2bin($hex = false){
  186. $ret = $hex !== false && preg_match('/^[0-9a-fA-F]+$/i', $hex) ? pack("H*", $hex) : false;
  187. return $ret;
  188. }
  189. }
复制代码

测试示例
  1. header('Content-Type:text/html;Charset=utf-8;');
  2. include "rsa.php";
  3. echo '
    '; 
  4. $a = isset($_GET['a']) ? $_GET['a'] : '测试123';
  5. //////////////////////////////////////
  6. $pubfile = 'E:\ssl\cert\pwd.crt';
  7. $prifile = 'E:\ssl\cert\pwd.pem';
  8. $m = new RSA($pubfile, $prifile);
  9. $x = $m->sign($a);
  10. $y = $m->verify($a, $x);
  11. var_dump($x, $y);
  12. $x = $m->encrypt($a);
  13. $y = $m->decrypt($x);
  14. var_dump($x, $y);
复制代码

php, RAS