php实现RSA加密类实例

这篇文章主要介绍了php实现RSA加密类,实例分析了php自定义RSA类实现加密与解密的技巧,非常具有实用价值,需要的朋友可以参考下

本文实例讲述了php实现RSA加密类,分享给大家供大家参考,具体分析如下:

通过openssl实现的签名、验签、非对称加解密,需要配合x.509证书(如crt和pem)文件使用。

由于各种原因,该类并不十分完善,欢迎各种测试!

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

测试demo:

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