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