Blowfish.php 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318
  1. <?php
  2. /* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
  3. /**
  4. * Crypt_Blowfish allows for encryption and decryption on the fly using
  5. * the Blowfish algorithm. Crypt_Blowfish does not require the mcrypt
  6. * PHP extension, it uses only PHP.
  7. * Crypt_Blowfish support encryption/decryption with or without a secret key.
  8. *
  9. *
  10. * PHP versions 4 and 5
  11. *
  12. * LICENSE: This source file is subject to version 3.0 of the PHP license
  13. * that is available through the world-wide-web at the following URI:
  14. * http://www.php.net/license/3_0.txt. If you did not receive a copy of
  15. * the PHP License and are unable to obtain it through the web, please
  16. * send a note to license@php.net so we can mail you a copy immediately.
  17. *
  18. * @category Encryption
  19. * @package Crypt_Blowfish
  20. * @author Matthew Fonda <mfonda@php.net>
  21. * @copyright 2005 Matthew Fonda
  22. * @license http://www.php.net/license/3_0.txt PHP License 3.0
  23. * @version CVS: $Id: Blowfish.php,v 1.81 2005/05/30 18:40:36 mfonda Exp $
  24. * @link http://pear.php.net/package/Crypt_Blowfish
  25. */
  26. require_once 'PEAR.php';
  27. /**
  28. *
  29. * Example usage:
  30. * $bf = new Crypt_Blowfish('some secret key!');
  31. * $encrypted = $bf->encrypt('this is some example plain text');
  32. * $plaintext = $bf->decrypt($encrypted);
  33. * echo "plain text: $plaintext";
  34. *
  35. *
  36. * @category Encryption
  37. * @package Crypt_Blowfish
  38. * @author Matthew Fonda <mfonda@php.net>
  39. * @copyright 2005 Matthew Fonda
  40. * @license http://www.php.net/license/3_0.txt PHP License 3.0
  41. * @link http://pear.php.net/package/Crypt_Blowfish
  42. * @version @package_version@
  43. * @access public
  44. */
  45. class Crypt_Blowfish
  46. {
  47. /**
  48. * P-Array contains 18 32-bit subkeys
  49. *
  50. * @var array
  51. * @access private
  52. */
  53. var $_P = array();
  54. /**
  55. * Array of four S-Blocks each containing 256 32-bit entries
  56. *
  57. * @var array
  58. * @access private
  59. */
  60. var $_S = array();
  61. /**
  62. * Mcrypt td resource
  63. *
  64. * @var resource
  65. * @access private
  66. */
  67. var $_td = null;
  68. /**
  69. * Initialization vector
  70. *
  71. * @var string
  72. * @access private
  73. */
  74. var $_iv = null;
  75. /**
  76. * Crypt_Blowfish Constructor
  77. * Initializes the Crypt_Blowfish object, and gives a sets
  78. * the secret key
  79. *
  80. * @param string $key
  81. * @access public
  82. */
  83. function Crypt_Blowfish($key)
  84. {
  85. if (extension_loaded('mcrypt')) {
  86. $this->_td = mcrypt_module_open(MCRYPT_BLOWFISH, '', 'ecb', '');
  87. $this->_iv = mcrypt_create_iv(8, MCRYPT_RAND);
  88. }
  89. $this->setKey($key);
  90. }
  91. /**
  92. * Deprecated isReady method
  93. *
  94. * @return bool
  95. * @access public
  96. * @deprecated
  97. */
  98. function isReady()
  99. {
  100. return true;
  101. }
  102. /**
  103. * Deprecated init method - init is now a private
  104. * method and has been replaced with _init
  105. *
  106. * @return bool
  107. * @access public
  108. * @deprecated
  109. * @see Crypt_Blowfish::_init()
  110. */
  111. function init()
  112. {
  113. $this->_init();
  114. }
  115. /**
  116. * Initializes the Crypt_Blowfish object
  117. *
  118. * @access private
  119. */
  120. function _init()
  121. {
  122. $defaults = new Crypt_Blowfish_DefaultKey();
  123. $this->_P = $defaults->P;
  124. $this->_S = $defaults->S;
  125. }
  126. /**
  127. * Enciphers a single 64 bit block
  128. *
  129. * @param int &$Xl
  130. * @param int &$Xr
  131. * @access private
  132. */
  133. function _encipher(&$Xl, &$Xr)
  134. {
  135. for ($i = 0; $i < 16; $i++) {
  136. $temp = $Xl ^ $this->_P[$i];
  137. $Xl = ((($this->_S[0][($temp>>24) & 255] +
  138. $this->_S[1][($temp>>16) & 255]) ^
  139. $this->_S[2][($temp>>8) & 255]) +
  140. $this->_S[3][$temp & 255]) ^ $Xr;
  141. $Xr = $temp;
  142. }
  143. $Xr = $Xl ^ $this->_P[16];
  144. $Xl = $temp ^ $this->_P[17];
  145. }
  146. /**
  147. * Deciphers a single 64 bit block
  148. *
  149. * @param int &$Xl
  150. * @param int &$Xr
  151. * @access private
  152. */
  153. function _decipher(&$Xl, &$Xr)
  154. {
  155. for ($i = 17; $i > 1; $i--) {
  156. $temp = $Xl ^ $this->_P[$i];
  157. $Xl = ((($this->_S[0][($temp>>24) & 255] +
  158. $this->_S[1][($temp>>16) & 255]) ^
  159. $this->_S[2][($temp>>8) & 255]) +
  160. $this->_S[3][$temp & 255]) ^ $Xr;
  161. $Xr = $temp;
  162. }
  163. $Xr = $Xl ^ $this->_P[1];
  164. $Xl = $temp ^ $this->_P[0];
  165. }
  166. /**
  167. * Encrypts a string
  168. *
  169. * @param string $plainText
  170. * @return string Returns cipher text on success, PEAR_Error on failure
  171. * @access public
  172. */
  173. function encrypt($plainText)
  174. {
  175. if (!is_string($plainText)) {
  176. PEAR::raiseError('Plain text must be a string', 0, PEAR_ERROR_DIE);
  177. }
  178. if (extension_loaded('mcrypt')) {
  179. return mcrypt_generic($this->_td, $plainText);
  180. }
  181. $cipherText = '';
  182. $len = strlen($plainText);
  183. $plainText .= str_repeat(chr(0),(8 - ($len%8))%8);
  184. for ($i = 0; $i < $len; $i += 8) {
  185. list(,$Xl,$Xr) = unpack("N2",substr($plainText,$i,8));
  186. $this->_encipher($Xl, $Xr);
  187. $cipherText .= pack("N2", $Xl, $Xr);
  188. }
  189. return $cipherText;
  190. }
  191. /**
  192. * Decrypts an encrypted string
  193. *
  194. * @param string $cipherText
  195. * @return string Returns plain text on success, PEAR_Error on failure
  196. * @access public
  197. */
  198. function decrypt($cipherText)
  199. {
  200. if (!is_string($cipherText)) {
  201. PEAR::raiseError('Chiper text must be a string', 1, PEAR_ERROR_DIE);
  202. }
  203. if (extension_loaded('mcrypt')) {
  204. return mdecrypt_generic($this->_td, $cipherText);
  205. }
  206. $plainText = '';
  207. $len = strlen($cipherText);
  208. $cipherText .= str_repeat(chr(0),(8 - ($len%8))%8);
  209. for ($i = 0; $i < $len; $i += 8) {
  210. list(,$Xl,$Xr) = unpack("N2",substr($cipherText,$i,8));
  211. $this->_decipher($Xl, $Xr);
  212. $plainText .= pack("N2", $Xl, $Xr);
  213. }
  214. return $plainText;
  215. }
  216. /**
  217. * Sets the secret key
  218. * The key must be non-zero, and less than or equal to
  219. * 56 characters in length.
  220. *
  221. * @param string $key
  222. * @return bool Returns true on success, PEAR_Error on failure
  223. * @access public
  224. */
  225. function setKey($key)
  226. {
  227. if (!is_string($key)) {
  228. PEAR::raiseError('Key must be a string', 2, PEAR_ERROR_DIE);
  229. }
  230. $len = strlen($key);
  231. if ($len > 56 || $len == 0) {
  232. PEAR::raiseError('Key must be less than 56 characters and non-zero. Supplied key length: ' . $len, 3, PEAR_ERROR_DIE);
  233. }
  234. if (extension_loaded('mcrypt')) {
  235. mcrypt_generic_init($this->_td, $key, $this->_iv);
  236. return true;
  237. }
  238. require_once 'Blowfish/DefaultKey.php';
  239. $this->_init();
  240. $k = 0;
  241. $data = 0;
  242. $datal = 0;
  243. $datar = 0;
  244. for ($i = 0; $i < 18; $i++) {
  245. $data = 0;
  246. for ($j = 4; $j > 0; $j--) {
  247. $data = $data << 8 | ord($key{$k});
  248. $k = ($k+1) % $len;
  249. }
  250. $this->_P[$i] ^= $data;
  251. }
  252. for ($i = 0; $i <= 16; $i += 2) {
  253. $this->_encipher($datal, $datar);
  254. $this->_P[$i] = $datal;
  255. $this->_P[$i+1] = $datar;
  256. }
  257. for ($i = 0; $i < 256; $i += 2) {
  258. $this->_encipher($datal, $datar);
  259. $this->_S[0][$i] = $datal;
  260. $this->_S[0][$i+1] = $datar;
  261. }
  262. for ($i = 0; $i < 256; $i += 2) {
  263. $this->_encipher($datal, $datar);
  264. $this->_S[1][$i] = $datal;
  265. $this->_S[1][$i+1] = $datar;
  266. }
  267. for ($i = 0; $i < 256; $i += 2) {
  268. $this->_encipher($datal, $datar);
  269. $this->_S[2][$i] = $datal;
  270. $this->_S[2][$i+1] = $datar;
  271. }
  272. for ($i = 0; $i < 256; $i += 2) {
  273. $this->_encipher($datal, $datar);
  274. $this->_S[3][$i] = $datal;
  275. $this->_S[3][$i+1] = $datar;
  276. }
  277. return true;
  278. }
  279. }
  280. ?>