Source for file Xtea2.php

Documentation is available at Xtea2.php

  1. <?php
  2. /* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
  3. //
  4. // +----------------------------------------------------------------------+
  5. // | PHP version 4.0 |
  6. // +----------------------------------------------------------------------+
  7. // | Copyright (c) 2002 The PHP Group |
  8. // +----------------------------------------------------------------------+
  9. // | This source file is subject to version 2.02 of the PHP license, |
  10. // | that is bundled with this package in the file LICENSE, and is |
  11. // | available at through the world-wide-web at |
  12. // | http://www.php.net/license/2_02.txt. |
  13. // | If you did not receive a copy of the PHP license and are unable to |
  14. // | obtain it through the world-wide-web, please send a note to |
  15. // | license@php.net so we can mail you a copy immediately. |
  16. // +----------------------------------------------------------------------+
  17. // | Authors: Jeroen Derks <jeroen@derks.it> |
  18. // +----------------------------------------------------------------------+
  19. // | Original code: http://vader.brad.ac.uk/tea/source.shtml#new_ansi |
  20. // +----------------------------------------------------------------------+
  21. //
  22. // $Id: Xtea2.php,v 1.2 2004/09/08 19:21:08 jeroend Exp $
  23. //
  24.  
  25.  
  26.  
  27.  
  28.  
  29. /**
  30. * Class that implements the xTEA encryption algorithm.
  31. * This enables you to encrypt data without requiring mcrypt.
  32. *
  33. * From the C source:
  34. * -----------------------------------------
  35. * The Tiny Encryption Algorithm (TEA) by
  36. * David Wheeler and Roger Needham of the
  37. * Cambridge Computer Laboratory.
  38. *
  39. * Placed in the Public Domain by
  40. * David Wheeler and Roger Needham.
  41. *
  42. * **** ANSI C VERSION (New Variant) ****
  43. *
  44. * Notes:
  45. *
  46. * TEA is a Feistel cipher with XOR and
  47. * and addition as the non-linear mixing
  48. * functions.
  49. *
  50. * Takes 64 bits of data in v[0] and v[1].
  51. * Returns 64 bits of data in w[0] and w[1].
  52. * Takes 128 bits of key in k[0] - k[3].
  53. *
  54. * TEA can be operated in any of the modes
  55. * of DES. Cipher Block Chaining is, for example,
  56. * simple to implement.
  57. *
  58. * n is the number of iterations. 32 is ample,
  59. * 16 is sufficient, as few as eight may be OK.
  60. * The algorithm achieves good dispersion after
  61. * six iterations. The iteration count can be
  62. * made variable if required.
  63. *
  64. * Note this is optimised for 32-bit CPUs with
  65. * fast shift capabilities. It can very easily
  66. * be ported to assembly language on most CPUs.
  67. *
  68. * delta is chosen to be the real part of (the
  69. * golden ratio Sqrt(5/4) - 1/2 ~ 0.618034
  70. * multiplied by 2^32).
  71. *
  72. * This version has been amended to foil two
  73. * weaknesses identified by David A. Wagner
  74. * (daw@cs.berkeley.edu): 1) effective key
  75. * length of old-variant TEA was 126 not 128
  76. * bits 2) a related key attack was possible
  77. * although impractical.
  78. *
  79. * void encipher(unsigned long *const v,unsigned long *const w,
  80. * const unsigned long *const k)
  81. * {
  82. * register unsigned long y=v[0],z=v[1],sum=0,delta=0x9E3779B9,n=32;
  83. *
  84. * while(n-->0)
  85. * {
  86. * y+= (z<<4 ^ z>>5) + z ^ sum + k[sum&3];
  87. * sum += delta;
  88. * z+= (y<<4 ^ y>>5) + y ^ sum + k[sum>>11 & 3];
  89. * }
  90. *
  91. * w[0]=y; w[1]=z;
  92. * }
  93. *
  94. * void decipher(unsigned long *const v,unsigned long *const w,
  95. * const unsigned long *const k)
  96. * {
  97. * register unsigned long y=v[0],z=v[1],sum=0xC6EF3720,
  98. * delta=0x9E3779B9,n=32;
  99. *
  100. * # sum = delta<<5, in general sum = delta * n
  101. *
  102. * while(n-->0)
  103. * {
  104. * z-= (y<<4 ^ y>>5) + y ^ sum + k[sum>>11 & 3];
  105. * sum -= delta;
  106. * y-= (z<<4 ^ z>>5) + z ^ sum + k[sum&3];
  107. * }
  108. *
  109. * w[0]=y; w[1]=z;
  110. * }
  111. *
  112. * -----------------------------------------
  113. *
  114. * @TODO Add CFB.
  115. *
  116. * @package Crypt_Xtea2
  117. * @version $Revision: 1.2 $
  118. * @access public
  119. * @since 2004/Sep/06
  120. * @author Jeroen Derks <jeroen@derks.it>
  121. */
  122.  
  123. class Crypt_Xtea2 {
  124.  
  125. /**
  126. * Number of iterations.
  127. * @var integer
  128. * @access private
  129. * @see setIter(), getIter()
  130. */
  131. private $n_iter;
  132.  
  133.  
  134. // {{{ Crypt_Xtea2()
  135.  
  136.  
  137. /**
  138. * Constructor, sets the number of iterations.
  139. *
  140. * @access public
  141. * @author Jeroen Derks <jeroen@derks.it>
  142. * @see setIter()
  143. */
  144. public function __construct() {
  145. $this->setIter( 32 );
  146. }
  147.  
  148. // }}}
  149. // {{{ setIter()
  150.  
  151.  
  152. /**
  153. * Set the number of iterations to use.
  154. *
  155. * @param integer $n_iter Number of iterations to use.
  156. *
  157. * @access public
  158. * @author Jeroen Derks <jeroen@derks.it>
  159. * @see $n_iter, getIter()
  160. */
  161. public function setIter( $n_iter ) {
  162. $this->n_iter = $n_iter;
  163. }
  164.  
  165. // }}}
  166. // {{{ getIter()
  167.  
  168.  
  169. /**
  170. * Get the number of iterations to use.
  171. *
  172. * @return integer Number of iterations to use.
  173. *
  174. * @access public
  175. * @author Jeroen Derks <jeroen@derks.it>
  176. * @see $n_iter, setIter()
  177. */
  178. public function getIter() {
  179. return $this->n_iter;
  180. }
  181.  
  182. // }}}
  183. // {{{ encrypt()
  184.  
  185.  
  186. /**
  187. * Encrypt a string using a specific key.
  188. *
  189. * @param string $data Data to encrypt.
  190. * @param string $key Key to encrypt data with (binary string).
  191. *
  192. * @return string Binary encrypted character string.
  193. *
  194. * @access public
  195. * @author Jeroen Derks <jeroen@derks.it>
  196. * @see decrypt(), _encipherLong(), _resize(), _str2long()
  197. */
  198. public function encrypt($data, $key) {
  199. // resize data to 32 bits (4 bytes)
  200. $n = $this->_resize($data, 4);
  201.  
  202. // convert data to long
  203. $data_long[0] = $n;
  204. $n_data_long = $this->_str2long(1, $data, $data_long);
  205.  
  206. // resize data_long to 64 bits (2 longs of 32 bits)
  207. $n = count($data_long);
  208. if (($n & 1) == 1) {
  209. $data_long[$n] = chr(0);
  210. $n_data_long++;
  211. }
  212.  
  213. // resize key to a multiple of 128 bits (16 bytes)
  214. $this->_resize($key, 16, true);
  215.  
  216. // convert key to long
  217. $n_key_long = $this->_str2long(0, $key, $key_long);
  218.  
  219. // encrypt the long data with the key
  220. $enc_data = '';
  221. $w = array( 0, 0 );
  222. $j = 0;
  223. $k = array( 0, 0, 0, 0 );
  224. for ($i = 0; $i < $n_data_long; ++$i) {
  225. // get next key part of 128 bits
  226. if ($j + 4 <= $n_key_long) {
  227. $k[0] = $key_long[$j];
  228. $k[1] = $key_long[$j + 1];
  229. $k[2] = $key_long[$j + 2];
  230. $k[3] = $key_long[$j + 3];
  231. } else {
  232. $k[0] = $key_long[$j % $n_key_long];
  233. $k[1] = $key_long[($j + 1) % $n_key_long];
  234. $k[2] = $key_long[($j + 2) % $n_key_long];
  235. $k[3] = $key_long[($j + 3) % $n_key_long];
  236. }
  237. $j = ($j + 4) % $n_key_long;
  238.  
  239. $this->_encipherLong($data_long[$i], $data_long[++$i], $w, $k);
  240.  
  241. // append the enciphered longs to the result
  242. $enc_data .= $this->_long2str($w[0]);
  243. $enc_data .= $this->_long2str($w[1]);
  244. }
  245.  
  246. return $enc_data;
  247. }
  248.  
  249. // }}}
  250. // {{{ decrypt()
  251.  
  252.  
  253. /**
  254. * Decrypt an encrypted string using a specific key.
  255. *
  256. * @param string $data Encrypted data to decrypt.
  257. * @param string $key Key to decrypt encrypted data with (binary string).
  258. *
  259. * @return string Binary decrypted character string.
  260. *
  261. * @access public
  262. * @author Jeroen Derks <jeroen@derks.it>
  263. * @see _encipherLong(), encrypt(), _resize(), _str2long()
  264. */
  265. public function decrypt($enc_data, $key) {
  266. // convert data to long
  267. $n_enc_data_long = $this->_str2long(0, $enc_data, $enc_data_long);
  268.  
  269. // resize key to a multiple of 128 bits (16 bytes)
  270. $this->_resize($key, 16, true);
  271.  
  272. // convert key to long
  273. $n_key_long = $this->_str2long(0, $key, $key_long);
  274.  
  275. // decrypt the long data with the key
  276. $data = '';
  277. $w = array( 0, 0 );
  278. $j = 0;
  279. $len = 0;
  280. $k = array( 0, 0, 0, 0 );
  281. $pos = 0;
  282.  
  283. for ($i = 0; $i < $n_enc_data_long; $i += 2) {
  284. // get next key part of 128 bits
  285. if ($j + 4 <= $n_key_long) {
  286. $k[0] = $key_long[$j];
  287. $k[1] = $key_long[$j + 1];
  288. $k[2] = $key_long[$j + 2];
  289. $k[3] = $key_long[$j + 3];
  290. } else {
  291. $k[0] = $key_long[$j % $n_key_long];
  292. $k[1] = $key_long[($j + 1) % $n_key_long];
  293. $k[2] = $key_long[($j + 2) % $n_key_long];
  294. $k[3] = $key_long[($j + 3) % $n_key_long];
  295. }
  296. $j = ($j + 4) % $n_key_long;
  297.  
  298. $this->_decipherLong($enc_data_long[$i], $enc_data_long[$i + 1], $w, $k);
  299. // append the deciphered longs to the result data (remove padding)
  300. if (0 == $i) {
  301. $len = $w[0];
  302. if (4 <= $len) {
  303. $data .= $this->_long2str($w[1]);
  304. } else {
  305. $data .= substr( $this->_long2str($w[1]), 0, $len % 4 );
  306. }
  307. } else {
  308. $pos = ($i - 1) * 4;
  309. if ($pos + 4 <= $len) {
  310. $data .= $this->_long2str($w[0]);
  311.  
  312. if ($pos + 8 <= $len) {
  313. $data .= $this->_long2str($w[1]);
  314. } elseif ($pos + 4 < $len) {
  315. $data .= substr( $this->_long2str($w[1]), 0, $len % 4 );
  316. }
  317. } else {
  318. $data .= substr( $this->_long2str($w[0]), 0, $len % 4 );
  319. }
  320. }
  321. }
  322. return $data;
  323. }
  324.  
  325. // }}}
  326. // {{{ _encipherLong()
  327.  
  328.  
  329. /**
  330. * Encipher a single long (32-bit) value.
  331. *
  332. * @param integer $y 32 bits of data.
  333. * @param integer $z 32 bits of data.
  334. * @param array &$w Placeholder for enciphered 64 bits (in w[0] and w[1]).
  335. * @param array &$k Key 128 bits (in k[0]-k[3]).
  336. *
  337. * @access private
  338. * @author Jeroen Derks <jeroen@derks.it>
  339. * @see $n_iter, _add(), _rshift(), _decipherLong()
  340. */
  341. private function _encipherLong($y, $z, &$w, &$k) {
  342. $sum = (integer) 0;
  343. $delta = (integer) 0x9E3779B9;
  344. $n = (integer) $this->n_iter;
  345.  
  346. while ($n-- > 0) {
  347. $y = $this->_add($y,
  348. $this->_add($z << 4 ^ $this->_rshift($z, 5), $z) ^
  349. $this->_add($sum, $k[$sum & 3]));
  350. $sum = $this->_add($sum, $delta);
  351. $z = $this->_add($z,
  352. $this->_add($y << 4 ^ $this->_rshift($y, 5), $y) ^
  353. $this->_add($sum, $k[$this->_rshift($sum, 11) & 3]));
  354. }
  355.  
  356. $w[0] = $y;
  357. $w[1] = $z;
  358. }
  359.  
  360. // }}}
  361. // {{{ _decipherLong()
  362.  
  363.  
  364. /**
  365. * Decipher a single long (32-bit) value.
  366. *
  367. * @param integer $y 32 bits of enciphered data.
  368. * @param integer $z 32 bits of enciphered data.
  369. * @param array &$w Placeholder for deciphered 64 bits (in w[0] and w[1]).
  370. * @param array &$k Key 128 bits (in k[0]-k[3]).
  371. *
  372. * @access private
  373. * @author Jeroen Derks <jeroen@derks.it>
  374. * @see $n_iter, _add(), _rshift(), _decipherLong()
  375. */
  376. private function _decipherLong($y, $z, &$w, &$k) {
  377. // sum = delta<<5, in general sum = delta * n
  378. $sum = (integer) 0xC6EF3720;
  379. $delta = (integer) 0x9E3779B9;
  380. $n = (integer) $this->n_iter;
  381.  
  382. while ($n-- > 0) {
  383. $z = $this->_add($z,
  384. -($this->_add($y << 4 ^ $this->_rshift($y, 5), $y) ^
  385. $this->_add($sum, $k[$this->_rshift($sum, 11) & 3])));
  386. $sum = $this->_add($sum, -$delta);
  387. $y = $this->_add($y,
  388. -($this->_add($z << 4 ^ $this->_rshift($z, 5), $z) ^
  389. $this->_add($sum, $k[$sum & 3])));
  390. }
  391.  
  392. $w[0] = $y;
  393. $w[1] = $z;
  394. }
  395.  
  396. // }}}
  397. // {{{ _resize()
  398.  
  399.  
  400. /**
  401. * Resize data string to a multiple of specified size.
  402. *
  403. * @param string $data Data string to resize to specified size.
  404. * @param integer $size Size in bytes to align data to.
  405. * @param boolean $nonull Set to true if padded bytes should not be zero.
  406. *
  407. * @return integer Length of supplied data string.
  408. *
  409. * @access private
  410. * @author Jeroen Derks <jeroen@derks.it>
  411. */
  412. private function _resize(&$data, $size, $nonull = false) {
  413. $n = strlen($data);
  414. $nmod = $n % $size;
  415.  
  416. if ($nmod > 0) {
  417. if ($nonull) {
  418. for ($i = $n; $i < $n - $nmod + $size; ++$i) {
  419. $data[$i] = $data[$i % $n];
  420. }
  421. } else {
  422. for ($i = $n; $i < $n - $nmod + $size; ++$i) {
  423. $data[$i] = chr(0);
  424. }
  425. }
  426. }
  427. return $n;
  428. }
  429.  
  430. // }}}
  431. // {{{ _hex2bin()
  432.  
  433.  
  434. /**
  435. * Convert a hexadecimal string to a binary string (e.g. convert "616263" to "abc").
  436. *
  437. * @param string $str Hexadecimal string to convert to binary string.
  438. *
  439. * @return string Binary string.
  440. *
  441. * @access private
  442. * @author Jeroen Derks <jeroen@derks.it>
  443. */
  444. private function _hex2bin($str) {
  445. $len = strlen($str);
  446. return pack('H' . $len, $str);
  447. }
  448.  
  449. // }}}
  450. // {{{ _str2long()
  451.  
  452.  
  453. /**
  454. * Convert string to array of long.
  455. *
  456. * @param integer $start Index into $data_long for output.
  457. * @param string &$data Input string.
  458. * @param array &$data_long Output array of long.
  459. *
  460. * @return integer Index from which to optionally continue.
  461. *
  462. * @access private
  463. * @author Jeroen Derks <jeroen@derks.it>
  464. */
  465. private function _str2long($start, &$data, &$data_long) {
  466. $n = strlen($data);
  467.  
  468. $tmp = unpack('N*', $data);
  469. $j = $start;
  470.  
  471. foreach ($tmp as $value)
  472. $data_long[$j++] = $value;
  473.  
  474. return $j;
  475. }
  476.  
  477. // }}}
  478. // {{{ _long2str()
  479.  
  480.  
  481. /**
  482. * Convert long to character string.
  483. *
  484. * @param long $l Long to convert to character string.
  485. *
  486. * @return string Character string.
  487. *
  488. * @access private
  489. * @author Jeroen Derks <jeroen@derks.it>
  490. */
  491. private function _long2str($l) {
  492. return pack( 'N', $l );
  493. }
  494.  
  495. // }}}
  496. // {{{ _rshift()
  497. /**
  498. * Handle proper unsigned right shift, dealing with PHP's signed shift.
  499. *
  500. * @access private
  501. * @since 2004/Sep/06
  502. * @author Jeroen Derks <jeroen@derks.it>
  503. */
  504. private function _rshift($integer, $n) {
  505. if (0 > (integer) $integer) {
  506. $integer = $integer >> $n; // shift
  507. $integer &= ~(0x80000000 >> ($n - 1)); // remove shifted-in sign bits
  508. } else {
  509. $integer >>= $n; // use normal shift
  510. }
  511.  
  512. return $integer;
  513. }
  514.  
  515. // }}}
  516. // {{{ _add()
  517. /**
  518. * Handle proper unsigned add, dealing with PHP's signed add.
  519. *
  520. * @access private
  521. * @since 2004/Sep/06
  522. * @author Jeroen Derks <jeroen@derks.it>
  523. */
  524. private function _add($i1, $i2) {
  525. $result = 0.0;
  526.  
  527. foreach (func_get_args() as $value) {
  528. // remove sign if necessary
  529. if (0.0 > $value) {
  530. $value += 0xffffffff + 1.0;
  531. }
  532.  
  533. $result += $value;
  534. }
  535.  
  536. // convert to 32 bit
  537. if (0xffffffff < $result) {
  538. $result = fmod($result, 0xffffffff + 1);
  539. }
  540.  
  541. return (integer) $result;
  542. }
  543.  
  544. // }}}
  545.  
  546. }
  547.  
  548. ?>

Documentation generated on Wed, 8 Sep 2004 21:20:46 +0200 by phpDocumentor 1.3.0RC3