Rsa.class.php 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184
  1. <?php
  2. // +----------------------------------------------------------------------
  3. // | ThinkPHP [ WE CAN DO IT JUST THINK IT ]
  4. // +----------------------------------------------------------------------
  5. // | Copyright (c) 2009 http://thinkphp.cn All rights reserved.
  6. // +----------------------------------------------------------------------
  7. // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
  8. // +----------------------------------------------------------------------
  9. // | Author: liu21st <liu21st@gmail.com>
  10. // +----------------------------------------------------------------------
  11. define("BCCOMP_LARGER", 1);
  12. /**
  13. * Rsa 加密实现类
  14. * @category ORG
  15. * @package ORG
  16. * @subpackage Crypt
  17. * @author liu21st <liu21st@gmail.com>
  18. */
  19. class Rsa {
  20. /**
  21. * 加密字符串
  22. * @access static
  23. * @param string $str 字符串
  24. * @param string $key 加密key
  25. * @return string
  26. */
  27. public static function encrypt($message, $public_key, $modulus, $keylength) {
  28. $padded = self::add_PKCS1_padding($message, true, $keylength / 8);
  29. $number = self::binary_to_number($padded);
  30. $encrypted = self::pow_mod($number, $public_key, $modulus);
  31. $result = self::number_to_binary($encrypted, $keylength / 8);
  32. return $result;
  33. }
  34. /**
  35. * 解密字符串
  36. * @access static
  37. * @param string $str 字符串
  38. * @param string $key 加密key
  39. * @return string
  40. */
  41. public static function decrypt($message, $private_key, $modulus, $keylength) {
  42. $number = self::binary_to_number($message);
  43. $decrypted = self::pow_mod($number, $private_key, $modulus);
  44. $result = self::number_to_binary($decrypted, $keylength / 8);
  45. return self::remove_PKCS1_padding($result, $keylength / 8);
  46. }
  47. function sign($message, $private_key, $modulus, $keylength) {
  48. $padded = self::add_PKCS1_padding($message, false, $keylength / 8);
  49. $number = self::binary_to_number($padded);
  50. $signed = self::pow_mod($number, $private_key, $modulus);
  51. $result = self::number_to_binary($signed, $keylength / 8);
  52. return $result;
  53. }
  54. function verify($message, $public_key, $modulus, $keylength) {
  55. return decrypt($message, $public_key, $modulus, $keylength);
  56. }
  57. function pow_mod($p, $q, $r) {
  58. // Extract powers of 2 from $q
  59. $factors = array();
  60. $div = $q;
  61. $power_of_two = 0;
  62. while(bccomp($div, "0") == BCCOMP_LARGER)
  63. {
  64. $rem = bcmod($div, 2);
  65. $div = bcdiv($div, 2);
  66. if($rem) array_push($factors, $power_of_two);
  67. $power_of_two++;
  68. }
  69. // Calculate partial results for each factor, using each partial result as a
  70. // starting point for the next. This depends of the factors of two being
  71. // generated in increasing order.
  72. $partial_results = array();
  73. $part_res = $p;
  74. $idx = 0;
  75. foreach($factors as $factor)
  76. {
  77. while($idx < $factor)
  78. {
  79. $part_res = bcpow($part_res, "2");
  80. $part_res = bcmod($part_res, $r);
  81. $idx++;
  82. }
  83. array_push($partial_results, $part_res);
  84. }
  85. // Calculate final result
  86. $result = "1";
  87. foreach($partial_results as $part_res)
  88. {
  89. $result = bcmul($result, $part_res);
  90. $result = bcmod($result, $r);
  91. }
  92. return $result;
  93. }
  94. //--
  95. // Function to add padding to a decrypted string
  96. // We need to know if this is a private or a public key operation [4]
  97. //--
  98. function add_PKCS1_padding($data, $isPublicKey, $blocksize) {
  99. $pad_length = $blocksize - 3 - strlen($data);
  100. if($isPublicKey)
  101. {
  102. $block_type = "\x02";
  103. $padding = "";
  104. for($i = 0; $i < $pad_length; $i++)
  105. {
  106. $rnd = mt_rand(1, 255);
  107. $padding .= chr($rnd);
  108. }
  109. }
  110. else
  111. {
  112. $block_type = "\x01";
  113. $padding = str_repeat("\xFF", $pad_length);
  114. }
  115. return "\x00" . $block_type . $padding . "\x00" . $data;
  116. }
  117. //--
  118. // Remove padding from a decrypted string
  119. // See [4] for more details.
  120. //--
  121. function remove_PKCS1_padding($data, $blocksize) {
  122. assert(strlen($data) == $blocksize);
  123. $data = substr($data, 1);
  124. // We cannot deal with block type 0
  125. if($data{0} == '\0')
  126. die("Block type 0 not implemented.");
  127. // Then the block type must be 1 or 2
  128. assert(($data{0} == "\x01") || ($data{0} == "\x02"));
  129. // Remove the padding
  130. $offset = strpos($data, "\0", 1);
  131. return substr($data, $offset + 1);
  132. }
  133. //--
  134. // Convert binary data to a decimal number
  135. //--
  136. function binary_to_number($data) {
  137. $base = "256";
  138. $radix = "1";
  139. $result = "0";
  140. for($i = strlen($data) - 1; $i >= 0; $i--)
  141. {
  142. $digit = ord($data{$i});
  143. $part_res = bcmul($digit, $radix);
  144. $result = bcadd($result, $part_res);
  145. $radix = bcmul($radix, $base);
  146. }
  147. return $result;
  148. }
  149. //--
  150. // Convert a number back into binary form
  151. //--
  152. function number_to_binary($number, $blocksize) {
  153. $base = "256";
  154. $result = "";
  155. $div = $number;
  156. while($div > 0)
  157. {
  158. $mod = bcmod($div, $base);
  159. $div = bcdiv($div, $base);
  160. $result = chr($mod) . $result;
  161. }
  162. return str_pad($result, $blocksize, "\x00", STR_PAD_LEFT);
  163. }
  164. }