1<?php 2/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */ 3 4/** 5 * PHP implementation of XXTEA encryption algorithm. 6 * 7 * XXTEA is a secure and fast encryption algorithm, suitable for web 8 * development. 9 * 10 * PHP versions 4 and 5 11 * 12 * LICENSE: This library is free software; you can redistribute it 13 * and/or modify it under the terms of the GNU Lesser General Public 14 * License as published by the Free Software Foundation; either 15 * version 2.1 of the License, or (at your option) any later version. 16 * 17 * This library is distributed in the hope that it will be useful, 18 * but WITHOUT ANY WARRANTY; without even the implied warranty of 19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 20 * Lesser General Public License for more details. 21 * 22 * You should have received a copy of the GNU Lesser General Public 23 * License along with this library; if not, write to the Free Software 24 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, 25 * MA 02110-1301 USA. 26 * 27 * @category Encryption 28 * @package Crypt_XXTEA 29 * @author Wudi Liu <wudicgi@gmail.com> 30 * @author Ma Bingyao <andot@ujn.edu.cn> 31 * @copyright 2005-2008 Coolcode.CN 32 * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 33 * @version CVS: $Id: XXTEA.php,v 1.3 2008/03/06 11:38:45 wudicgi Exp $ 34 * @link http://pear.php.net/package/Crypt_XXTEA 35 */ 36 37/** 38 * Needed for error handling 39 */ 40require_once 'PEAR.php'; 41 42// {{{ constants 43 44define('CRYPT_XXTEA_DELTA', 0x9E3779B9); 45 46// }}} 47 48/** 49 * The main class 50 * 51 * @category Encryption 52 * @package Crypt_XXTEA 53 * @author Wudi Liu <wudicgi@gmail.com> 54 * @author Ma Bingyao <andot@ujn.edu.cn> 55 * @copyright 2005-2008 Coolcode.CN 56 * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 57 * @version Release: 0.9.0 58 * @link http://pear.php.net/package/Crypt_XXTEA 59 */ 60class Crypt_XXTEA { 61 // {{{ properties 62 63 /** 64 * The long integer array of secret key 65 * 66 * @access private 67 * 68 * @var array 69 */ 70 var $_key; 71 72 // }}} 73 74 // {{{ setKey() 75 76 /** 77 * Sets the secret key 78 * 79 * The key must be non-empty, and not more than 16 characters or 4 long values 80 * 81 * @access public 82 * 83 * @param mixed $key the secret key (string or long integer array) 84 * 85 * @return bool true on success, PEAR_Error on failure 86 */ 87 function setKey($key) { 88 if (is_string($key)) { 89 $k = $this->_str2long($key, false); 90 } elseif (is_array($key)) { 91 $k = $key; 92 } else { 93 return PEAR::raiseError('The secret key must be a string or long integer array.'); 94 } 95 if (count($k) > 4) { 96 return PEAR::raiseError('The secret key cannot be more than 16 characters or 4 long values.'); 97 } elseif (count($k) == 0) { 98 return PEAR::raiseError('The secret key cannot be empty.'); 99 } elseif (count($k) < 4) { 100 for ($i = count($k); $i < 4; $i++) { 101 $k[$i] = 0; 102 } 103 } 104 $this->_key = $k; 105 return true; 106 } 107 108 // }}} 109 110 // {{{ encrypt() 111 112 /** 113 * Encrypts a plain text 114 * 115 * As the XXTEA encryption algorithm is designed for encrypting and decrypting 116 * the long integer array type of data, there is not a standard that defines 117 * how to convert between long integer array and text or binary data for it. 118 * So this package provides the ability to encrypt and decrypt the long integer 119 * arrays directly to satisfy the requirement for working with other 120 * implementations. And at the same time, for convenience, it also provides 121 * the ability to process strings, which uses its own method to group the text 122 * into array. 123 * 124 * @access public 125 * 126 * @param mixed $plaintext the plain text (string or long integer array) 127 * 128 * @return mixed the cipher text as the same type as the parameter $plaintext 129 * on success, PEAR_Error on failure 130 */ 131 function encrypt($plaintext) { 132 if ($this->_key == null) { 133 return PEAR::raiseError('Secret key is undefined.'); 134 } 135 if (is_string($plaintext)) { 136 return $this->_encryptString($plaintext); 137 } elseif (is_array($plaintext)) { 138 return $this->_encryptArray($plaintext); 139 } else { 140 return PEAR::raiseError('The plain text must be a string or long integer array.'); 141 } 142 } 143 144 // }}} 145 146 // {{{ decrypt() 147 148 /** 149 * Decrypts a cipher text 150 * 151 * @access public 152 * 153 * @param mixed $chipertext the cipher text (string or long integer array) 154 * 155 * @return mixed the plain text as the same type as the parameter $chipertext 156 * on success, PEAR_Error on failure 157 */ 158 function decrypt($chipertext) { 159 if ($this->_key == null) { 160 return PEAR::raiseError('Secret key is undefined.'); 161 } 162 if (is_string($chipertext)) { 163 return $this->_decryptString($chipertext); 164 } elseif (is_array($chipertext)) { 165 return $this->_decryptArray($chipertext); 166 } else { 167 return PEAR::raiseError('The chiper text must be a string or long integer array.'); 168 } 169 } 170 171 // }}} 172 173 // {{{ _encryptString() 174 175 /** 176 * Encrypts a string 177 * 178 * @access private 179 * 180 * @param string $str the string to encrypt 181 * 182 * @return string the string type of the cipher text on success, 183 * PEAR_Error on failure 184 */ 185 function _encryptString($str) { 186 if ($str == '') { 187 return ''; 188 } 189 $v = $this->_str2long($str, true); 190 $v = $this->_encryptArray($v); 191 return $this->_long2str($v, false); 192 } 193 194 // }}} 195 196 // {{{ _encryptArray() 197 198 /** 199 * Encrypts a long integer array 200 * 201 * @access private 202 * 203 * @param array $v the long integer array to encrypt 204 * 205 * @return array the array type of the cipher text on success, 206 * PEAR_Error on failure 207 */ 208 function _encryptArray($v) { 209 $n = count($v) - 1; 210 $z = $v[$n]; 211 $y = $v[0]; 212 $q = floor(6 + 52 / ($n + 1)); 213 $sum = 0; 214 while (0 < $q--) { 215 $sum = $this->_int32($sum + CRYPT_XXTEA_DELTA); 216 $e = $sum >> 2 & 3; 217 for ($p = 0; $p < $n; $p++) { 218 $y = $v[$p + 1]; 219 $mx = $this->_int32((($z >> 5 & 0x07FFFFFF) ^ $y << 2) + (($y >> 3 & 0x1FFFFFFF) ^ $z << 4)) ^ $this->_int32(($sum ^ $y) + ($this->_key[$p & 3 ^ $e] ^ $z)); 220 $z = $v[$p] = $this->_int32($v[$p] + $mx); 221 } 222 $y = $v[0]; 223 $mx = $this->_int32((($z >> 5 & 0x07FFFFFF) ^ $y << 2) + (($y >> 3 & 0x1FFFFFFF) ^ $z << 4)) ^ $this->_int32(($sum ^ $y) + ($this->_key[$p & 3 ^ $e] ^ $z)); 224 $z = $v[$n] = $this->_int32($v[$n] + $mx); 225 } 226 return $v; 227 } 228 229 // }}} 230 231 // {{{ _decryptString() 232 233 /** 234 * Decrypts a string 235 * 236 * @access private 237 * 238 * @param string $str the string to decrypt 239 * 240 * @return string the string type of the plain text on success, 241 * PEAR_Error on failure 242 */ 243 function _decryptString($str) { 244 if ($str == '') { 245 return ''; 246 } 247 $v = $this->_str2long($str, false); 248 $v = $this->_decryptArray($v); 249 return $this->_long2str($v, true); 250 } 251 252 // }}} 253 254 // {{{ _encryptArray() 255 256 /** 257 * Decrypts a long integer array 258 * 259 * @access private 260 * 261 * @param array $v the long integer array to decrypt 262 * 263 * @return array the array type of the plain text on success, 264 * PEAR_Error on failure 265 */ 266 function _decryptArray($v) { 267 $n = count($v) - 1; 268 $z = $v[$n]; 269 $y = $v[0]; 270 $q = floor(6 + 52 / ($n + 1)); 271 $sum = $this->_int32($q * CRYPT_XXTEA_DELTA); 272 while ($sum != 0) { 273 $e = $sum >> 2 & 3; 274 for ($p = $n; $p > 0; $p--) { 275 $z = $v[$p - 1]; 276 $mx = $this->_int32((($z >> 5 & 0x07FFFFFF) ^ $y << 2) + (($y >> 3 & 0x1FFFFFFF) ^ $z << 4)) ^ $this->_int32(($sum ^ $y) + ($this->_key[$p & 3 ^ $e] ^ $z)); 277 $y = $v[$p] = $this->_int32($v[$p] - $mx); 278 } 279 $z = $v[$n]; 280 $mx = $this->_int32((($z >> 5 & 0x07FFFFFF) ^ $y << 2) + (($y >> 3 & 0x1FFFFFFF) ^ $z << 4)) ^ $this->_int32(($sum ^ $y) + ($this->_key[$p & 3 ^ $e] ^ $z)); 281 $y = $v[0] = $this->_int32($v[0] - $mx); 282 $sum = $this->_int32($sum - CRYPT_XXTEA_DELTA); 283 } 284 return $v; 285 } 286 287 // }}} 288 289 // {{{ _long2str() 290 291 /** 292 * Converts long integer array to string 293 * 294 * @access private 295 * 296 * @param array $v the long integer array 297 * @param bool $w whether the given array contains the length of 298 * original plain text 299 * 300 * @return string the string 301 */ 302 function _long2str($v, $w) { 303 $len = count($v); 304 $s = ''; 305 for ($i = 0; $i < $len; $i++) { 306 $s .= pack('V', $v[$i]); 307 } 308 if ($w) { 309 return substr($s, 0, $v[$len - 1]); 310 } else { 311 return $s; 312 } 313 } 314 315 // }}} 316 317 // {{{ _str2long() 318 319 /** 320 * Converts string to long integer array 321 * 322 * @access private 323 * 324 * @param string $s the string 325 * @param bool $w whether to append the length of string to array 326 * 327 * @return string the long integer array 328 */ 329 function _str2long($s, $w) { 330 $v = array_values(unpack('V*', $s.str_repeat("\0", (4-strlen($s)%4)&3))); 331 if ($w) { 332 $v[] = strlen($s); 333 } 334 return $v; 335 } 336 337 // }}} 338 339 // {{{ _int32() 340 341 /** 342 * Corrects long integer value 343 * 344 * Because a number beyond the bounds of the integer type will be automatically 345 * interpreted as a float, the simulation of integer overflow is needed. 346 * 347 * @access private 348 * 349 * @param int $n the integer 350 * 351 * @return int the correct integer 352 */ 353 function _int32($n) { 354 while ($n >= 2147483648) $n -= 4294967296; 355 while ($n <= -2147483649) $n += 4294967296; 356 return (int)$n; 357 } 358 359 // }}} 360 361} 362 363?> 364