Source for file Xtea.php

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

Documentation generated on Thu, 25 May 2006 15:31:26 +0200 by phpDocumentor 1.3.0RC3