PageRenderTime 23ms CodeModel.GetById 21ms RepoModel.GetById 0ms app.codeStats 0ms

/application/libraries/PEAR/Crypt/RSA/Math/BCMath.php

https://github.com/grandison/budo16
PHP | 482 lines | 235 code | 29 blank | 218 comment | 39 complexity | 78eb088a0e4424c2aa2829ebe4ede5c0 MD5 | raw file
  1. <?php
  2. /**
  3. * Crypt_RSA allows to do following operations:
  4. * - key pair generation
  5. * - encryption and decryption
  6. * - signing and sign validation
  7. *
  8. * PHP versions 4 and 5
  9. *
  10. * LICENSE: This source file is subject to version 3.0 of the PHP license
  11. * that is available through the world-wide-web at the following URI:
  12. * http://www.php.net/license/3_0.txt. If you did not receive a copy of
  13. * the PHP License and are unable to obtain it through the web, please
  14. * send a note to license@php.net so we can mail you a copy immediately.
  15. *
  16. * @category Encryption
  17. * @package Crypt_RSA
  18. * @author Alexander Valyalkin <valyala@gmail.com>
  19. * @copyright 2006 Alexander Valyalkin
  20. * @license http://www.php.net/license/3_0.txt PHP License 3.0
  21. * @version 1.2.0b
  22. * @link http://pear.php.net/package/Crypt_RSA
  23. */
  24. /**
  25. * Crypt_RSA_Math_BCMath class.
  26. *
  27. * Provides set of math functions, which are used by Crypt_RSA package
  28. * This class is a wrapper for PHP BCMath extension.
  29. * See http://php.net/manual/en/ref.bc.php for details.
  30. *
  31. * @category Encryption
  32. * @package Crypt_RSA
  33. * @author Alexander Valyalkin <valyala@gmail.com>
  34. * @copyright 2005, 2006 Alexander Valyalkin
  35. * @license http://www.php.net/license/3_0.txt PHP License 3.0
  36. * @link http://pear.php.net/package/Crypt_RSA
  37. * @version @package_version@
  38. * @access public
  39. */
  40. class Crypt_RSA_Math_BCMath
  41. {
  42. /**
  43. * error description
  44. *
  45. * @var string
  46. * @access public
  47. */
  48. var $errstr = '';
  49. /**
  50. * Performs Miller-Rabin primality test for number $num
  51. * with base $base. Returns true, if $num is strong pseudoprime
  52. * by base $base. Else returns false.
  53. *
  54. * @param string $num
  55. * @param string $base
  56. * @return bool
  57. * @access private
  58. */
  59. function _millerTest($num, $base)
  60. {
  61. if (!bccomp($num, '1')) {
  62. // 1 is not prime ;)
  63. return false;
  64. }
  65. $tmp = bcsub($num, '1');
  66. $zero_bits = 0;
  67. while (!bccomp(bcmod($tmp, '2'), '0')) {
  68. $zero_bits++;
  69. $tmp = bcdiv($tmp, '2');
  70. }
  71. $tmp = $this->powmod($base, $tmp, $num);
  72. if (!bccomp($tmp, '1')) {
  73. // $num is probably prime
  74. return true;
  75. }
  76. while ($zero_bits--) {
  77. if (!bccomp(bcadd($tmp, '1'), $num)) {
  78. // $num is probably prime
  79. return true;
  80. }
  81. $tmp = $this->powmod($tmp, '2', $num);
  82. }
  83. // $num is composite
  84. return false;
  85. }
  86. /**
  87. * Crypt_RSA_Math_BCMath constructor.
  88. * Checks an existance of PHP BCMath extension.
  89. * On failure saves error description in $this->errstr
  90. *
  91. * @access public
  92. */
  93. function Crypt_RSA_Math_BCMath()
  94. {
  95. if (!extension_loaded('bcmath')) {
  96. if (!@dl('bcmath.' . PHP_SHLIB_SUFFIX) && !@dl('php_bcmath.' . PHP_SHLIB_SUFFIX)) {
  97. // cannot load BCMath extension. Set error string
  98. $this->errstr = 'Crypt_RSA package requires the BCMath extension. See http://php.net/manual/en/ref.bc.php for details';
  99. return;
  100. }
  101. }
  102. }
  103. /**
  104. * Transforms binary representation of large integer into its native form.
  105. *
  106. * Example of transformation:
  107. * $str = "\x12\x34\x56\x78\x90";
  108. * $num = 0x9078563412;
  109. *
  110. * @param string $str
  111. * @return string
  112. * @access public
  113. */
  114. function bin2int($str)
  115. {
  116. $result = '0';
  117. $n = strlen($str);
  118. do {
  119. $result = bcadd(bcmul($result, '256'), ord($str{--$n}));
  120. } while ($n > 0);
  121. return $result;
  122. }
  123. /**
  124. * Transforms large integer into binary representation.
  125. *
  126. * Example of transformation:
  127. * $num = 0x9078563412;
  128. * $str = "\x12\x34\x56\x78\x90";
  129. *
  130. * @param string $num
  131. * @return string
  132. * @access public
  133. */
  134. function int2bin($num)
  135. {
  136. $result = '';
  137. do {
  138. $result .= chr(bcmod($num, '256'));
  139. $num = bcdiv($num, '256');
  140. } while (bccomp($num, '0'));
  141. return $result;
  142. }
  143. /**
  144. * Calculates pow($num, $pow) (mod $mod)
  145. *
  146. * @param string $num
  147. * @param string $pow
  148. * @param string $mod
  149. * @return string
  150. * @access public
  151. */
  152. function powmod($num, $pow, $mod)
  153. {
  154. if (function_exists('bcpowmod')) {
  155. // bcpowmod is only available under PHP5
  156. return bcpowmod($num, $pow, $mod);
  157. }
  158. // emulate bcpowmod
  159. $result = '1';
  160. do {
  161. if (!bccomp(bcmod($pow, '2'), '1')) {
  162. $result = bcmod(bcmul($result, $num), $mod);
  163. }
  164. $num = bcmod(bcpow($num, '2'), $mod);
  165. $pow = bcdiv($pow, '2');
  166. } while (bccomp($pow, '0'));
  167. return $result;
  168. }
  169. /**
  170. * Calculates $num1 * $num2
  171. *
  172. * @param string $num1
  173. * @param string $num2
  174. * @return string
  175. * @access public
  176. */
  177. function mul($num1, $num2)
  178. {
  179. return bcmul($num1, $num2);
  180. }
  181. /**
  182. * Calculates $num1 % $num2
  183. *
  184. * @param string $num1
  185. * @param string $num2
  186. * @return string
  187. * @access public
  188. */
  189. function mod($num1, $num2)
  190. {
  191. return bcmod($num1, $num2);
  192. }
  193. /**
  194. * Compares abs($num1) to abs($num2).
  195. * Returns:
  196. * -1, if abs($num1) < abs($num2)
  197. * 0, if abs($num1) == abs($num2)
  198. * 1, if abs($num1) > abs($num2)
  199. *
  200. * @param string $num1
  201. * @param string $num2
  202. * @return int
  203. * @access public
  204. */
  205. function cmpAbs($num1, $num2)
  206. {
  207. return bccomp($num1, $num2);
  208. }
  209. /**
  210. * Tests $num on primality. Returns true, if $num is strong pseudoprime.
  211. * Else returns false.
  212. *
  213. * @param string $num
  214. * @return bool
  215. * @access private
  216. */
  217. function isPrime($num)
  218. {
  219. static $primes = null;
  220. static $primes_cnt = 0;
  221. if (is_null($primes)) {
  222. // generate all primes up to 10000
  223. $primes = array();
  224. for ($i = 0; $i < 10000; $i++) {
  225. $primes[] = $i;
  226. }
  227. $primes[0] = $primes[1] = 0;
  228. for ($i = 2; $i < 100; $i++) {
  229. while (!$primes[$i]) {
  230. $i++;
  231. }
  232. $j = $i;
  233. for ($j += $i; $j < 10000; $j += $i) {
  234. $primes[$j] = 0;
  235. }
  236. }
  237. $j = 0;
  238. for ($i = 0; $i < 10000; $i++) {
  239. if ($primes[$i]) {
  240. $primes[$j++] = $primes[$i];
  241. }
  242. }
  243. $primes_cnt = $j;
  244. }
  245. // try to divide number by small primes
  246. for ($i = 0; $i < $primes_cnt; $i++) {
  247. if (bccomp($num, $primes[$i]) <= 0) {
  248. // number is prime
  249. return true;
  250. }
  251. if (!bccomp(bcmod($num, $primes[$i]), '0')) {
  252. // number divides by $primes[$i]
  253. return false;
  254. }
  255. }
  256. /*
  257. try Miller-Rabin's probable-primality test for first
  258. 7 primes as bases
  259. */
  260. for ($i = 0; $i < 7; $i++) {
  261. if (!$this->_millerTest($num, $primes[$i])) {
  262. // $num is composite
  263. return false;
  264. }
  265. }
  266. // $num is strong pseudoprime
  267. return true;
  268. }
  269. /**
  270. * Generates prime number with length $bits_cnt
  271. * using $random_generator as random generator function.
  272. *
  273. * @param int $bits_cnt
  274. * @param string $rnd_generator
  275. * @access public
  276. */
  277. function getPrime($bits_cnt, $random_generator)
  278. {
  279. $bytes_n = intval($bits_cnt / 8);
  280. $bits_n = $bits_cnt % 8;
  281. do {
  282. $str = '';
  283. for ($i = 0; $i < $bytes_n; $i++) {
  284. $str .= chr(call_user_func($random_generator) & 0xff);
  285. }
  286. $n = call_user_func($random_generator) & 0xff;
  287. $n |= 0x80;
  288. $n >>= 8 - $bits_n;
  289. $str .= chr($n);
  290. $num = $this->bin2int($str);
  291. // search for the next closest prime number after [$num]
  292. if (!bccomp(bcmod($num, '2'), '0')) {
  293. $num = bcadd($num, '1');
  294. }
  295. while (!$this->isPrime($num)) {
  296. $num = bcadd($num, '2');
  297. }
  298. } while ($this->bitLen($num) != $bits_cnt);
  299. return $num;
  300. }
  301. /**
  302. * Calculates $num - 1
  303. *
  304. * @param string $num
  305. * @return string
  306. * @access public
  307. */
  308. function dec($num)
  309. {
  310. return bcsub($num, '1');
  311. }
  312. /**
  313. * Returns true, if $num is equal to one. Else returns false
  314. *
  315. * @param string $num
  316. * @return bool
  317. * @access public
  318. */
  319. function isOne($num)
  320. {
  321. return !bccomp($num, '1');
  322. }
  323. /**
  324. * Finds greatest common divider (GCD) of $num1 and $num2
  325. *
  326. * @param string $num1
  327. * @param string $num2
  328. * @return string
  329. * @access public
  330. */
  331. function GCD($num1, $num2)
  332. {
  333. do {
  334. $tmp = bcmod($num1, $num2);
  335. $num1 = $num2;
  336. $num2 = $tmp;
  337. } while (bccomp($num2, '0'));
  338. return $num1;
  339. }
  340. /**
  341. * Finds inverse number $inv for $num by modulus $mod, such as:
  342. * $inv * $num = 1 (mod $mod)
  343. *
  344. * @param string $num
  345. * @param string $mod
  346. * @return string
  347. * @access public
  348. */
  349. function invmod($num, $mod)
  350. {
  351. $x = '1';
  352. $y = '0';
  353. $num1 = $mod;
  354. do {
  355. $tmp = bcmod($num, $num1);
  356. $q = bcdiv($num, $num1);
  357. $num = $num1;
  358. $num1 = $tmp;
  359. $tmp = bcsub($x, bcmul($y, $q));
  360. $x = $y;
  361. $y = $tmp;
  362. } while (bccomp($num1, '0'));
  363. if (bccomp($x, '0') < 0) {
  364. $x = bcadd($x, $mod);
  365. }
  366. return $x;
  367. }
  368. /**
  369. * Returns bit length of number $num
  370. *
  371. * @param string $num
  372. * @return int
  373. * @access public
  374. */
  375. function bitLen($num)
  376. {
  377. $tmp = $this->int2bin($num);
  378. $bit_len = strlen($tmp) * 8;
  379. $tmp = ord($tmp{strlen($tmp) - 1});
  380. if (!$tmp) {
  381. $bit_len -= 8;
  382. }
  383. else {
  384. while (!($tmp & 0x80)) {
  385. $bit_len--;
  386. $tmp <<= 1;
  387. }
  388. }
  389. return $bit_len;
  390. }
  391. /**
  392. * Calculates bitwise or of $num1 and $num2,
  393. * starting from bit $start_pos for number $num1
  394. *
  395. * @param string $num1
  396. * @param string $num2
  397. * @param int $start_pos
  398. * @return string
  399. * @access public
  400. */
  401. function bitOr($num1, $num2, $start_pos)
  402. {
  403. $start_byte = intval($start_pos / 8);
  404. $start_bit = $start_pos % 8;
  405. $tmp1 = $this->int2bin($num1);
  406. $num2 = bcmul($num2, 1 << $start_bit);
  407. $tmp2 = $this->int2bin($num2);
  408. if ($start_byte < strlen($tmp1)) {
  409. $tmp2 |= substr($tmp1, $start_byte);
  410. $tmp1 = substr($tmp1, 0, $start_byte) . $tmp2;
  411. }
  412. else {
  413. $tmp1 = str_pad($tmp1, $start_byte, "\0") . $tmp2;
  414. }
  415. return $this->bin2int($tmp1);
  416. }
  417. /**
  418. * Returns part of number $num, starting at bit
  419. * position $start with length $length
  420. *
  421. * @param string $num
  422. * @param int start
  423. * @param int length
  424. * @return string
  425. * @access public
  426. */
  427. function subint($num, $start, $length)
  428. {
  429. $start_byte = intval($start / 8);
  430. $start_bit = $start % 8;
  431. $byte_length = intval($length / 8);
  432. $bit_length = $length % 8;
  433. if ($bit_length) {
  434. $byte_length++;
  435. }
  436. $num = bcdiv($num, 1 << $start_bit);
  437. $tmp = substr($this->int2bin($num), $start_byte, $byte_length);
  438. $tmp = str_pad($tmp, $byte_length, "\0");
  439. $tmp = substr_replace($tmp, $tmp{$byte_length - 1} & chr(0xff >> (8 - $bit_length)), $byte_length - 1, 1);
  440. return $this->bin2int($tmp);
  441. }
  442. /**
  443. * Returns name of current wrapper
  444. *
  445. * @return string name of current wrapper
  446. * @access public
  447. */
  448. function getWrapperName()
  449. {
  450. return 'BCMath';
  451. }
  452. }
  453. ?>