Update code_sniffer build.xml file to be executable on our system
[phpbb.git] / phpBB / includes / libraries / sftp / aes.php
blob612e20830b200a434be4aa49673e6dc22f9db191
1 <?php
2 /**
4 * @package sftp
5 * @version $Id$
6 * @copyright (c) 2006 phpBB Group
7 * @license http://opensource.org/licenses/gpl-license.php GNU Public License
9 */
11 /**
12 * @ignore
14 if (!defined('IN_PHPBB'))
16 exit;
19 /**
20 * Code from http://phpseclib.sourceforge.net/
22 * Modified by phpBB Group to meet our coding standards
23 * and being able to integrate into phpBB
25 * Pure-PHP implementation of AES
27 * Copyright 2007-2009 TerraFrost <terrafrost@php.net>
28 * Copyright 2009+ phpBB
30 * @package sftp
31 * @author TerraFrost <terrafrost@php.net>
34 /**#@+
35 * @access public
36 * @see rijndael::encrypt()
37 * @see rijndael::decrypt()
39 /**
40 * Encrypt / decrypt using the Electronic Code Book mode.
42 * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Electronic_codebook_.28ECB.29
44 define('CRYPT_RIJNDAEL_MODE_ECB', 1);
45 /**
46 * Encrypt / decrypt using the Code Book Chaining mode.
48 * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Cipher-block_chaining_.28CBC.29
50 define('CRYPT_RIJNDAEL_MODE_CBC', 2);
51 /**#@-*/
53 /**#@+
54 * @access private
55 * @see rijndael::__construct()
57 /**
58 * Toggles the internal implementation
60 define('CRYPT_RIJNDAEL_MODE_INTERNAL', 1);
61 /**
62 * Toggles the mcrypt implementation
64 define('CRYPT_RIJNDAEL_MODE_MCRYPT', 2);
65 /**#@-*/
67 /**#@+
68 * @access public
69 * @see aes::encrypt()
70 * @see aes::decrypt()
72 /**
73 * Encrypt / decrypt using the Electronic Code Book mode.
75 * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Electronic_codebook_.28ECB.29
77 define('CRYPT_AES_MODE_ECB', 1);
78 /**
79 * Encrypt / decrypt using the Code Book Chaining mode.
81 * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Cipher-block_chaining_.28CBC.29
83 define('CRYPT_AES_MODE_CBC', 2);
84 /**#@-*/
86 /**#@+
87 * @access private
88 * @see aes::__construct()
90 /**
91 * Toggles the internal implementation
93 define('CRYPT_AES_MODE_INTERNAL', 1);
94 /**
95 * Toggles the mcrypt implementation
97 define('CRYPT_AES_MODE_MCRYPT', 2);
98 /**#@-*/
101 * Pure-PHP implementation of Rijndael.
103 * @author Jim Wigginton <terrafrost@php.net>
104 * @version 0.1.0
105 * @access public
106 * @package rijndael
108 class rijndael
111 * The Encryption Mode
113 * @see rijndael::__construct()
114 * @var Integer
115 * @access private
117 var $mode;
120 * The Key
122 * @see rijndael::set_key()
123 * @var String
124 * @access private
126 var $key = "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0";
129 * The Initialization Vector
131 * @see rijndael::set_iv()
132 * @var String
133 * @access private
135 var $iv = '';
138 * A "sliding" Initialization Vector
140 * @see rijndael::enable_continuous_buffer()
141 * @var String
142 * @access private
144 var $encryptIV = '';
147 * A "sliding" Initialization Vector
149 * @see rijndael::enableContinuousBuffer()
150 * @var String
151 * @access private
153 var $decryptIV = '';
156 * Continuous Buffer status
158 * @see rijndael::enable_continuous_buffer()
159 * @var Boolean
160 * @access private
162 var $continuousBuffer = false;
165 * Padding status
167 * @see rijndael::enable_padding()
168 * @var Boolean
169 * @access private
171 var $padding = true;
174 * Does the key schedule need to be (re)calculated?
176 * @see setKey()
177 * @see setBlockLength()
178 * @see setKeyLength()
179 * @var Boolean
180 * @access private
182 var $changed = true;
185 * Has the key length explicitly been set or should it be derived from the key, itself?
187 * @see setKeyLength()
188 * @var Boolean
189 * @access private
191 var $explicit_key_length = false;
194 * The Key Schedule
196 * @see _setup()
197 * @var Array
198 * @access private
200 var $w;
203 * The Inverse Key Schedule
205 * @see _setup()
206 * @var Array
207 * @access private
209 var $dw;
212 * The Block Length
214 * @see setBlockLength()
215 * @var Integer
216 * @access private
217 * @internal The max value is 32, the min value is 16. All valid values are multiples of 4. Exists in conjunction with
218 * $Nb because we need this value and not $Nb to pad strings appropriately.
220 var $block_size = 16;
223 * The Block Length divided by 32
225 * @see setBlockLength()
226 * @var Integer
227 * @access private
228 * @internal The max value is 256 / 32 = 8, the min value is 128 / 32 = 4. Exists in conjunction with $block_size
229 * because the encryption / decryption / key schedule creation requires this number and not $block_size. We could
230 * derive this from $block_size or vice versa, but that'd mean we'd have to do multiple shift operations, so in lieu
231 * of that, we'll just precompute it once.
234 var $Nb = 4;
237 * The Key Length
239 * @see setKeyLength()
240 * @var Integer
241 * @access private
242 * @internal The max value is 256 / 32 = 8, the min value is 128 / 32 = 4. Exists in conjunction with $key_size
243 * because the encryption / decryption / key schedule creation requires this number and not $key_size. We could
244 * derive this from $key_size or vice versa, but that'd mean we'd have to do multiple shift operations, so in lieu
245 * of that, we'll just precompute it once.
247 var $key_size = 16;
250 * The Key Length divided by 32
252 * @see setKeyLength()
253 * @var Integer
254 * @access private
255 * @internal The max value is 256 / 32 = 8, the min value is 128 / 32 = 4
257 var $Nk = 4;
260 * The Number of Rounds
262 * @var Integer
263 * @access private
264 * @internal The max value is 14, the min value is 10.
266 var $Nr;
269 * Shift offsets
271 * @var Array
272 * @access private
274 var $c;
277 * Precomputed mixColumns table
279 * @see rijndael()
280 * @var Array
281 * @access private
283 var $t0;
286 * Precomputed mixColumns table
288 * @see rijndael()
289 * @var Array
290 * @access private
292 var $t1;
295 * Precomputed mixColumns table
297 * @see rijndael()
298 * @var Array
299 * @access private
301 var $t2;
304 * Precomputed mixColumns table
306 * @see rijndael()
307 * @var Array
308 * @access private
310 var $t3;
313 * Precomputed invMixColumns table
315 * @see rijndael()
316 * @var Array
317 * @access private
319 var $dt0;
322 * Precomputed invMixColumns table
324 * @see rijndael()
325 * @var Array
326 * @access private
328 var $dt1;
331 * Precomputed invMixColumns table
333 * @see rijndael()
334 * @var Array
335 * @access private
337 var $dt2;
340 * Precomputed invMixColumns table
342 * @see rijndael()
343 * @var Array
344 * @access private
346 var $dt3;
349 * Default Constructor.
351 * Determines whether or not the mcrypt extension should be used. $mode should only, at present, be
352 * CRYPT_RIJNDAEL_MODE_ECB or CRYPT_RIJNDAEL_MODE_CBC. If not explictly set, CRYPT_RIJNDAEL_MODE_CBC will be used.
354 * @param optional Integer $mode
355 * @return rijndael
356 * @access public
358 function __construct($mode = CRYPT_MODE_CRYPT_RIJNDAEL_CBC)
360 switch ($mode)
362 case CRYPT_RIJNDAEL_MODE_ECB:
363 case CRYPT_RIJNDAEL_MODE_CBC:
364 $this->mode = $mode;
365 break;
366 default:
367 $this->mode = CRYPT_RIJNDAEL_MODE_CBC;
370 // according to <http://csrc.nist.gov/archive/aes/rijndael/Rijndael-ammended.pdf#page=19> (section 5.2.1),
371 // precomputed tables can be used in the mixColumns phase. in that example, they're assigned t0...t3, so
372 // those are the names we'll use.
373 $this->t3 = array(
374 0x6363A5C6, 0x7C7C84F8, 0x777799EE, 0x7B7B8DF6, 0xF2F20DFF, 0x6B6BBDD6, 0x6F6FB1DE, 0xC5C55491,
375 0x30305060, 0x01010302, 0x6767A9CE, 0x2B2B7D56, 0xFEFE19E7, 0xD7D762B5, 0xABABE64D, 0x76769AEC,
376 0xCACA458F, 0x82829D1F, 0xC9C94089, 0x7D7D87FA, 0xFAFA15EF, 0x5959EBB2, 0x4747C98E, 0xF0F00BFB,
377 0xADADEC41, 0xD4D467B3, 0xA2A2FD5F, 0xAFAFEA45, 0x9C9CBF23, 0xA4A4F753, 0x727296E4, 0xC0C05B9B,
378 0xB7B7C275, 0xFDFD1CE1, 0x9393AE3D, 0x26266A4C, 0x36365A6C, 0x3F3F417E, 0xF7F702F5, 0xCCCC4F83,
379 0x34345C68, 0xA5A5F451, 0xE5E534D1, 0xF1F108F9, 0x717193E2, 0xD8D873AB, 0x31315362, 0x15153F2A,
380 0x04040C08, 0xC7C75295, 0x23236546, 0xC3C35E9D, 0x18182830, 0x9696A137, 0x05050F0A, 0x9A9AB52F,
381 0x0707090E, 0x12123624, 0x80809B1B, 0xE2E23DDF, 0xEBEB26CD, 0x2727694E, 0xB2B2CD7F, 0x75759FEA,
382 0x09091B12, 0x83839E1D, 0x2C2C7458, 0x1A1A2E34, 0x1B1B2D36, 0x6E6EB2DC, 0x5A5AEEB4, 0xA0A0FB5B,
383 0x5252F6A4, 0x3B3B4D76, 0xD6D661B7, 0xB3B3CE7D, 0x29297B52, 0xE3E33EDD, 0x2F2F715E, 0x84849713,
384 0x5353F5A6, 0xD1D168B9, 0x00000000, 0xEDED2CC1, 0x20206040, 0xFCFC1FE3, 0xB1B1C879, 0x5B5BEDB6,
385 0x6A6ABED4, 0xCBCB468D, 0xBEBED967, 0x39394B72, 0x4A4ADE94, 0x4C4CD498, 0x5858E8B0, 0xCFCF4A85,
386 0xD0D06BBB, 0xEFEF2AC5, 0xAAAAE54F, 0xFBFB16ED, 0x4343C586, 0x4D4DD79A, 0x33335566, 0x85859411,
387 0x4545CF8A, 0xF9F910E9, 0x02020604, 0x7F7F81FE, 0x5050F0A0, 0x3C3C4478, 0x9F9FBA25, 0xA8A8E34B,
388 0x5151F3A2, 0xA3A3FE5D, 0x4040C080, 0x8F8F8A05, 0x9292AD3F, 0x9D9DBC21, 0x38384870, 0xF5F504F1,
389 0xBCBCDF63, 0xB6B6C177, 0xDADA75AF, 0x21216342, 0x10103020, 0xFFFF1AE5, 0xF3F30EFD, 0xD2D26DBF,
390 0xCDCD4C81, 0x0C0C1418, 0x13133526, 0xECEC2FC3, 0x5F5FE1BE, 0x9797A235, 0x4444CC88, 0x1717392E,
391 0xC4C45793, 0xA7A7F255, 0x7E7E82FC, 0x3D3D477A, 0x6464ACC8, 0x5D5DE7BA, 0x19192B32, 0x737395E6,
392 0x6060A0C0, 0x81819819, 0x4F4FD19E, 0xDCDC7FA3, 0x22226644, 0x2A2A7E54, 0x9090AB3B, 0x8888830B,
393 0x4646CA8C, 0xEEEE29C7, 0xB8B8D36B, 0x14143C28, 0xDEDE79A7, 0x5E5EE2BC, 0x0B0B1D16, 0xDBDB76AD,
394 0xE0E03BDB, 0x32325664, 0x3A3A4E74, 0x0A0A1E14, 0x4949DB92, 0x06060A0C, 0x24246C48, 0x5C5CE4B8,
395 0xC2C25D9F, 0xD3D36EBD, 0xACACEF43, 0x6262A6C4, 0x9191A839, 0x9595A431, 0xE4E437D3, 0x79798BF2,
396 0xE7E732D5, 0xC8C8438B, 0x3737596E, 0x6D6DB7DA, 0x8D8D8C01, 0xD5D564B1, 0x4E4ED29C, 0xA9A9E049,
397 0x6C6CB4D8, 0x5656FAAC, 0xF4F407F3, 0xEAEA25CF, 0x6565AFCA, 0x7A7A8EF4, 0xAEAEE947, 0x08081810,
398 0xBABAD56F, 0x787888F0, 0x25256F4A, 0x2E2E725C, 0x1C1C2438, 0xA6A6F157, 0xB4B4C773, 0xC6C65197,
399 0xE8E823CB, 0xDDDD7CA1, 0x74749CE8, 0x1F1F213E, 0x4B4BDD96, 0xBDBDDC61, 0x8B8B860D, 0x8A8A850F,
400 0x707090E0, 0x3E3E427C, 0xB5B5C471, 0x6666AACC, 0x4848D890, 0x03030506, 0xF6F601F7, 0x0E0E121C,
401 0x6161A3C2, 0x35355F6A, 0x5757F9AE, 0xB9B9D069, 0x86869117, 0xC1C15899, 0x1D1D273A, 0x9E9EB927,
402 0xE1E138D9, 0xF8F813EB, 0x9898B32B, 0x11113322, 0x6969BBD2, 0xD9D970A9, 0x8E8E8907, 0x9494A733,
403 0x9B9BB62D, 0x1E1E223C, 0x87879215, 0xE9E920C9, 0xCECE4987, 0x5555FFAA, 0x28287850, 0xDFDF7AA5,
404 0x8C8C8F03, 0xA1A1F859, 0x89898009, 0x0D0D171A, 0xBFBFDA65, 0xE6E631D7, 0x4242C684, 0x6868B8D0,
405 0x4141C382, 0x9999B029, 0x2D2D775A, 0x0F0F111E, 0xB0B0CB7B, 0x5454FCA8, 0xBBBBD66D, 0x16163A2C
408 $this->dt3 = array(
409 0xF4A75051, 0x4165537E, 0x17A4C31A, 0x275E963A, 0xAB6BCB3B, 0x9D45F11F, 0xFA58ABAC, 0xE303934B,
410 0x30FA5520, 0x766DF6AD, 0xCC769188, 0x024C25F5, 0xE5D7FC4F, 0x2ACBD7C5, 0x35448026, 0x62A38FB5,
411 0xB15A49DE, 0xBA1B6725, 0xEA0E9845, 0xFEC0E15D, 0x2F7502C3, 0x4CF01281, 0x4697A38D, 0xD3F9C66B,
412 0x8F5FE703, 0x929C9515, 0x6D7AEBBF, 0x5259DA95, 0xBE832DD4, 0x7421D358, 0xE0692949, 0xC9C8448E,
413 0xC2896A75, 0x8E7978F4, 0x583E6B99, 0xB971DD27, 0xE14FB6BE, 0x88AD17F0, 0x20AC66C9, 0xCE3AB47D,
414 0xDF4A1863, 0x1A3182E5, 0x51336097, 0x537F4562, 0x6477E0B1, 0x6BAE84BB, 0x81A01CFE, 0x082B94F9,
415 0x48685870, 0x45FD198F, 0xDE6C8794, 0x7BF8B752, 0x73D323AB, 0x4B02E272, 0x1F8F57E3, 0x55AB2A66,
416 0xEB2807B2, 0xB5C2032F, 0xC57B9A86, 0x3708A5D3, 0x2887F230, 0xBFA5B223, 0x036ABA02, 0x16825CED,
417 0xCF1C2B8A, 0x79B492A7, 0x07F2F0F3, 0x69E2A14E, 0xDAF4CD65, 0x05BED506, 0x34621FD1, 0xA6FE8AC4,
418 0x2E539D34, 0xF355A0A2, 0x8AE13205, 0xF6EB75A4, 0x83EC390B, 0x60EFAA40, 0x719F065E, 0x6E1051BD,
419 0x218AF93E, 0xDD063D96, 0x3E05AEDD, 0xE6BD464D, 0x548DB591, 0xC45D0571, 0x06D46F04, 0x5015FF60,
420 0x98FB2419, 0xBDE997D6, 0x4043CC89, 0xD99E7767, 0xE842BDB0, 0x898B8807, 0x195B38E7, 0xC8EEDB79,
421 0x7C0A47A1, 0x420FE97C, 0x841EC9F8, 0x00000000, 0x80868309, 0x2BED4832, 0x1170AC1E, 0x5A724E6C,
422 0x0EFFFBFD, 0x8538560F, 0xAED51E3D, 0x2D392736, 0x0FD9640A, 0x5CA62168, 0x5B54D19B, 0x362E3A24,
423 0x0A67B10C, 0x57E70F93, 0xEE96D2B4, 0x9B919E1B, 0xC0C54F80, 0xDC20A261, 0x774B695A, 0x121A161C,
424 0x93BA0AE2, 0xA02AE5C0, 0x22E0433C, 0x1B171D12, 0x090D0B0E, 0x8BC7ADF2, 0xB6A8B92D, 0x1EA9C814,
425 0xF1198557, 0x75074CAF, 0x99DDBBEE, 0x7F60FDA3, 0x01269FF7, 0x72F5BC5C, 0x663BC544, 0xFB7E345B,
426 0x4329768B, 0x23C6DCCB, 0xEDFC68B6, 0xE4F163B8, 0x31DCCAD7, 0x63851042, 0x97224013, 0xC6112084,
427 0x4A247D85, 0xBB3DF8D2, 0xF93211AE, 0x29A16DC7, 0x9E2F4B1D, 0xB230F3DC, 0x8652EC0D, 0xC1E3D077,
428 0xB3166C2B, 0x70B999A9, 0x9448FA11, 0xE9642247, 0xFC8CC4A8, 0xF03F1AA0, 0x7D2CD856, 0x3390EF22,
429 0x494EC787, 0x38D1C1D9, 0xCAA2FE8C, 0xD40B3698, 0xF581CFA6, 0x7ADE28A5, 0xB78E26DA, 0xADBFA43F,
430 0x3A9DE42C, 0x78920D50, 0x5FCC9B6A, 0x7E466254, 0x8D13C2F6, 0xD8B8E890, 0x39F75E2E, 0xC3AFF582,
431 0x5D80BE9F, 0xD0937C69, 0xD52DA96F, 0x2512B3CF, 0xAC993BC8, 0x187DA710, 0x9C636EE8, 0x3BBB7BDB,
432 0x267809CD, 0x5918F46E, 0x9AB701EC, 0x4F9AA883, 0x956E65E6, 0xFFE67EAA, 0xBCCF0821, 0x15E8E6EF,
433 0xE79BD9BA, 0x6F36CE4A, 0x9F09D4EA, 0xB07CD629, 0xA4B2AF31, 0x3F23312A, 0xA59430C6, 0xA266C035,
434 0x4EBC3774, 0x82CAA6FC, 0x90D0B0E0, 0xA7D81533, 0x04984AF1, 0xECDAF741, 0xCD500E7F, 0x91F62F17,
435 0x4DD68D76, 0xEFB04D43, 0xAA4D54CC, 0x9604DFE4, 0xD1B5E39E, 0x6A881B4C, 0x2C1FB8C1, 0x65517F46,
436 0x5EEA049D, 0x8C355D01, 0x877473FA, 0x0B412EFB, 0x671D5AB3, 0xDBD25292, 0x105633E9, 0xD647136D,
437 0xD7618C9A, 0xA10C7A37, 0xF8148E59, 0x133C89EB, 0xA927EECE, 0x61C935B7, 0x1CE5EDE1, 0x47B13C7A,
438 0xD2DF599C, 0xF2733F55, 0x14CE7918, 0xC737BF73, 0xF7CDEA53, 0xFDAA5B5F, 0x3D6F14DF, 0x44DB8678,
439 0xAFF381CA, 0x68C43EB9, 0x24342C38, 0xA3405FC2, 0x1DC37216, 0xE2250CBC, 0x3C498B28, 0x0D9541FF,
440 0xA8017139, 0x0CB3DE08, 0xB4E49CD8, 0x56C19064, 0xCB84617B, 0x32B670D5, 0x6C5C7448, 0xB85742D0
443 for ($i = 0; $i < 256; $i++)
445 $this->t2[$i << 8] = (($this->t3[$i] << 8) & 0xFFFFFF00) | (($this->t3[$i] >> 24) & 0x000000FF);
446 $this->t1[$i << 16] = (($this->t3[$i] << 16) & 0xFFFF0000) | (($this->t3[$i] >> 16) & 0x0000FFFF);
447 $this->t0[$i << 24] = (($this->t3[$i] << 24) & 0xFF000000) | (($this->t3[$i] >> 8) & 0x00FFFFFF);
449 $this->dt2[$i << 8] = (($this->dt3[$i] << 8) & 0xFFFFFF00) | (($this->dt3[$i] >> 24) & 0x000000FF);
450 $this->dt1[$i << 16] = (($this->dt3[$i] << 16) & 0xFFFF0000) | (($this->dt3[$i] >> 16) & 0x0000FFFF);
451 $this->dt0[$i << 24] = (($this->dt3[$i] << 24) & 0xFF000000) | (($this->dt3[$i] >> 8) & 0x00FFFFFF);
456 * Sets the key.
458 * Keys can be of any length. Rijndael, itself, requires the use of a key that's between 128-bits and 256-bits long and
459 * whose length is a multiple of 32. If the key is less than 256-bits and the key length isn't set, we round the length
460 * up to the closest valid key length, padding $key with null bytes. If the key is more tan 256-bits, we trim the
461 * excess bits.
463 * If the key is not explicitly set, it'll be assumed to be all null bytes.
465 * @access public
466 * @param String $key
468 function set_key($key)
470 $this->key = $key;
471 $this->changed = true;
475 * Sets the initialization vector. (optional)
477 * SetIV is not required when CRYPT_RIJNDAEL_MODE_ECB is being used. If not explictly set, it'll be assumed
478 * to be all zero's.
480 * @access public
481 * @param String $iv
483 function set_iv($iv)
485 $this->encryptIV = $this->decryptIV = $this->iv = str_pad(substr($iv, 0, $this->block_size), $this->block_size, chr(0));;
489 * Sets the key length
491 * Valid key lengths are 128, 160, 192, 224, and 256. If the length is less than 128, it will be rounded up to
492 * 128. If the length is greater then 128 and invalid, it will be rounded down to the closest valid amount.
494 * @access public
495 * @param Integer $length
497 function set_key_length($length)
499 $length >>= 5;
500 if ($length > 8)
502 $length = 8;
504 else if ($length < 4)
506 $length = 4;
508 $this->Nk = $length;
509 $this->key_size = $length << 2;
511 $this->explicit_key_length = true;
512 $this->changed = true;
516 * Sets the block length
518 * Valid block lengths are 128, 160, 192, 224, and 256. If the length is less than 128, it will be rounded up to
519 * 128. If the length is greater then 128 and invalid, it will be rounded down to the closest valid amount.
521 * @access public
522 * @param Integer $length
524 function set_block_length($length)
526 $length >>= 5;
527 if ($length > 8)
529 $length = 8;
531 else if ($length < 4)
533 $length = 4;
535 $this->Nb = $length;
536 $this->block_size = $length << 2;
537 $this->changed = true;
541 * Encrypts a message.
543 * $plaintext will be padded with additional bytes such that it's length is a multiple of the block size. Other Rjindael
544 * implementations may or may not pad in the same manner. Other common approaches to padding and the reasons why it's
545 * necessary are discussed in the following
546 * URL:
548 * {@link http://www.di-mgt.com.au/cryptopad.html http://www.di-mgt.com.au/cryptopad.html}
550 * An alternative to padding is to, separately, send the length of the file. This is what SSH, in fact, does.
551 * strlen($plaintext) will still need to be a multiple of 8, however, arbitrary values can be added to make it that
552 * length.
554 * @see rijndael::decrypt()
555 * @access public
556 * @param String $plaintext
558 function encrypt($plaintext)
560 $this->_setup();
561 $plaintext = $this->_pad($plaintext);
563 $ciphertext = '';
564 switch ($this->mode)
566 case CRYPT_RIJNDAEL_MODE_ECB:
567 for ($i = 0; $i < strlen($plaintext); $i+=$this->block_size)
569 $ciphertext.= $this->_encrypt_block(substr($plaintext, $i, $this->block_size));
571 break;
572 case CRYPT_RIJNDAEL_MODE_CBC:
573 $xor = $this->encryptIV;
574 for ($i = 0; $i < strlen($plaintext); $i+=$this->block_size)
576 $block = substr($plaintext, $i, $this->block_size);
577 $block = $this->_encrypt_block($block ^ $xor);
578 $xor = $block;
579 $ciphertext.= $block;
581 if ($this->continuousBuffer)
583 $this->encryptIV = $xor;
587 return $ciphertext;
591 * Decrypts a message.
593 * If strlen($ciphertext) is not a multiple of the block size, null bytes will be added to the end of the string until
594 * it is.
596 * @see rijndael::encrypt()
597 * @access public
598 * @param String $ciphertext
600 function decrypt($ciphertext)
602 $this->_setup();
603 // we pad with chr(0) since that's what mcrypt_generic does. to quote from http://php.net/function.mcrypt-generic :
604 // "The data is padded with "\0" to make sure the length of the data is n * blocksize."
605 $ciphertext = str_pad($ciphertext, (strlen($ciphertext) + $this->block_size - 1) % $this->block_size, chr(0));
607 $plaintext = '';
608 switch ($this->mode)
610 case CRYPT_RIJNDAEL_MODE_ECB:
611 for ($i = 0; $i < strlen($ciphertext); $i+=$this->block_size)
613 $plaintext.= $this->_decrypt_block(substr($ciphertext, $i, $this->block_size));
615 break;
616 case CRYPT_RIJNDAEL_MODE_CBC:
617 $xor = $this->decryptIV;
618 for ($i = 0; $i < strlen($ciphertext); $i+=$this->block_size)
620 $block = substr($ciphertext, $i, $this->block_size);
621 $plaintext.= $this->_decrypt_block($block) ^ $xor;
622 $xor = $block;
624 if ($this->continuousBuffer)
626 $this->decryptIV = $xor;
630 return $this->_unpad($plaintext);
634 * Encrypts a block
636 * @access private
637 * @param String $in
638 * @return String
640 function _encrypt_block($in)
642 // unpack starts it's indices at 1 - not 0.
643 $state = unpack('N*', $in);
645 // addRoundKey and reindex $state
646 for ($i = 0; $i < $this->Nb; $i++)
648 $state[$i] = $state[$i + 1] ^ $this->w[0][$i];
650 unset($state[$i]);
652 // fips-197.pdf#page=19, "Figure 5. Pseudo Code for the Cipher", states that this loop has four components -
653 // subBytes, shiftRows, mixColumns, and addRoundKey. fips-197.pdf#page=30, "Implementation Suggestions Regarding
654 // Various Platforms" suggests that performs enhanced implementations are described in Rijndael-ammended.pdf.
655 // Rijndael-ammended.pdf#page=20, "Implementation aspects / 32-bit processor", discusses such an optimization.
656 // Unfortunately, the description given there is not quite correct. Per aes.spec.v316.pdf#page=19 [1],
657 // equation (7.4.7) is supposed to use addition instead of subtraction, so we'll do that here, as well.
659 // [1] http://fp.gladman.plus.com/cryptography_technology/rijndael/aes.spec.v316.pdf
660 $temp = array();
661 for ($round = 1; $round < $this->Nr; $round++)
663 $i = 0; // $this->c[0] == 0
664 $j = $this->c[1];
665 $k = $this->c[2];
666 $l = $this->c[3];
668 while ($i < $this->Nb)
670 $temp[$i] = $this->t0[$state[$i] & 0xFF000000] ^
671 $this->t1[$state[$j] & 0x00FF0000] ^
672 $this->t2[$state[$k] & 0x0000FF00] ^
673 $this->t3[$state[$l] & 0x000000FF] ^
674 $this->w[$round][$i];
675 $i++;
676 $j = ($j + 1) % $this->Nb;
677 $k = ($k + 1) % $this->Nb;
678 $l = ($l + 1) % $this->Nb;
681 for ($i = 0; $i < $this->Nb; $i++)
683 $state[$i] = $temp[$i];
687 // subWord
688 for ($i = 0; $i < $this->Nb; $i++)
690 $state[$i] = $this->_sub_word($state[$i]);
693 // shiftRows + addRoundKey
694 $i = 0; // $this->c[0] == 0
695 $j = $this->c[1];
696 $k = $this->c[2];
697 $l = $this->c[3];
698 while ($i < $this->Nb)
700 $temp[$i] = ($state[$i] & 0xFF000000) ^
701 ($state[$j] & 0x00FF0000) ^
702 ($state[$k] & 0x0000FF00) ^
703 ($state[$l] & 0x000000FF) ^
704 $this->w[$this->Nr][$i];
705 $i++;
706 $j = ($j + 1) % $this->Nb;
707 $k = ($k + 1) % $this->Nb;
708 $l = ($l + 1) % $this->Nb;
710 $state = $temp;
712 array_unshift($state, 'N*');
714 return call_user_func_array('pack', $state);
718 * Decrypts a block
720 * @access private
721 * @param String $in
722 * @return String
724 function _decrypt_block($in)
726 // unpack starts it's indices at 1 - not 0.
727 $state = unpack('N*', $in);
729 // addRoundKey and reindex $state
730 for ($i = 0; $i < $this->Nb; $i++)
732 $state[$i] = $state[$i + 1] ^ $this->dw[$this->Nr][$i];
734 unset($state[$i]);
736 $temp = array();
737 for ($round = $this->Nr - 1; $round > 0; $round--)
739 $i = 0; // $this->c[0] == 0
740 $j = $this->Nb - $this->c[1];
741 $k = $this->Nb - $this->c[2];
742 $l = $this->Nb - $this->c[3];
744 while ($i < $this->Nb)
746 $temp[$i] = $this->dt0[$state[$i] & 0xFF000000] ^
747 $this->dt1[$state[$j] & 0x00FF0000] ^
748 $this->dt2[$state[$k] & 0x0000FF00] ^
749 $this->dt3[$state[$l] & 0x000000FF] ^
750 $this->dw[$round][$i];
751 $i++;
752 $j = ($j + 1) % $this->Nb;
753 $k = ($k + 1) % $this->Nb;
754 $l = ($l + 1) % $this->Nb;
757 for ($i = 0; $i < $this->Nb; $i++)
759 $state[$i] = $temp[$i];
763 // invShiftRows + invSubWord + addRoundKey
764 $i = 0; // $this->c[0] == 0
765 $j = $this->Nb - $this->c[1];
766 $k = $this->Nb - $this->c[2];
767 $l = $this->Nb - $this->c[3];
769 while ($i < $this->Nb)
771 $temp[$i] = $this->dw[0][$i] ^
772 $this->_inv_sub_word(($state[$i] & 0xFF000000) |
773 ($state[$j] & 0x00FF0000) |
774 ($state[$k] & 0x0000FF00) |
775 ($state[$l] & 0x000000FF));
776 $i++;
777 $j = ($j + 1) % $this->Nb;
778 $k = ($k + 1) % $this->Nb;
779 $l = ($l + 1) % $this->Nb;
782 $state = $temp;
784 array_unshift($state, 'N*');
786 return call_user_func_array('pack', $state);
790 * Setup Rijndael
792 * Validates all the variables and calculates $Nr - the number of rounds that need to be performed - and $w - the key
793 * key schedule.
795 * @access private
797 function _setup()
799 // Each number in $rcon is equal to the previous number multiplied by two in Rijndael's finite field.
800 // See http://en.wikipedia.org/wiki/Finite_field_arithmetic#Multiplicative_inverse
801 static $rcon = array(0,
802 0x01000000, 0x02000000, 0x04000000, 0x08000000, 0x10000000,
803 0x20000000, 0x40000000, 0x80000000, 0x1B000000, 0x36000000,
804 0x6C000000, 0xD8000000, 0xAB000000, 0x4D000000, 0x9A000000,
805 0x2F000000, 0x5E000000, 0xBC000000, 0x63000000, 0xC6000000,
806 0x97000000, 0x35000000, 0x6A000000, 0xD4000000, 0xB3000000,
807 0x7D000000, 0xFA000000, 0xEF000000, 0xC5000000, 0x91000000
810 if (!$this->changed)
812 return;
815 if (!$this->explicit_key_length)
817 // we do >> 2, here, and not >> 5, as we do above, since strlen($this->key) tells us the number of bytes - not bits
818 $length = strlen($this->key) >> 2;
819 if ($length > 8)
821 $length = 8;
823 else if ($length < 4)
825 $length = 4;
827 $this->Nk = $length;
828 $this->key_size = $length << 2;
831 $this->key = str_pad(substr($this->key, 0, $this->key_size), $this->key_size, chr(0));
832 $this->encryptIV = $this->decryptIV = $this->iv = str_pad(substr($this->iv, 0, $this->block_size), $this->block_size, chr(0));
834 // see Rijndael-ammended.pdf#page=44
835 $this->Nr = max($this->Nk, $this->Nb) + 6;
837 // shift offsets for Nb = 5, 7 are defined in Rijndael-ammended.pdf#page=44,
838 // "Table 8: Shift offsets in Shiftrow for the alternative block lengths"
839 // shift offsets for Nb = 4, 6, 8 are defined in Rijndael-ammended.pdf#page=14,
840 // "Table 2: Shift offsets for different block lengths"
841 switch ($this->Nb)
843 case 4:
844 case 5:
845 case 6:
846 $this->c = array(0, 1, 2, 3);
847 break;
848 case 7:
849 $this->c = array(0, 1, 2, 4);
850 break;
851 case 8:
852 $this->c = array(0, 1, 3, 4);
855 $key = $this->key;
857 $w = array();
858 for ($i = 0; $i < $this->Nk; $i++)
860 list(, $w[$i]) = unpack('N', $this->_string_shift($key, 4));
863 $length = $this->Nb * ($this->Nr + 1);
864 for (; $i < $length; $i++)
866 $temp = $w[$i - 1];
867 if ($i % $this->Nk == 0)
869 // according to <http://php.net/language.types.integer>, "the size of an integer is platform-dependent".
870 // on a 32-bit machine, it's 32-bits, and on a 64-bit machine, it's 64-bits. on a 32-bit machine,
871 // 0xFFFFFFFF << 8 == 0xFFFFFF00, but on a 64-bit machine, it equals 0xFFFFFFFF00. as such, doing 'and'
872 // with 0xFFFFFFFF (or 0xFFFFFF00) on a 32-bit machine is unnecessary, but on a 64-bit machine, it is.
873 $temp = (($temp << 8) & 0xFFFFFF00) | (($temp >> 24) & 0x000000FF); // rotWord
874 $temp = $this->_sub_word($temp) ^ $rcon[$i / $this->Nk];
876 else if ($this->Nk > 6 && $i % $this->Nk == 4)
878 $temp = $this->_sub_word($temp);
880 $w[$i] = $w[$i - $this->Nk] ^ $temp;
883 // convert the key schedule from a vector of $Nb * ($Nr + 1) length to a matrix with $Nr + 1 rows and $Nb columns
884 // and generate the inverse key schedule. more specifically,
885 // according to <http://csrc.nist.gov/archive/aes/rijndael/Rijndael-ammended.pdf#page=23> (section 5.3.3),
886 // "The key expansion for the Inverse Cipher is defined as follows:
887 // 1. Apply the Key Expansion.
888 // 2. Apply InvMixColumn to all Round Keys except the first and the last one."
889 // also, see fips-197.pdf#page=27, "5.3.5 Equivalent Inverse Cipher"
890 $temp = array();
891 for ($i = $row = $col = 0; $i < $length; $i++, $col++)
893 if ($col == $this->Nb)
895 if ($row == 0)
897 $this->dw[0] = $this->w[0];
899 else
901 // subWord + invMixColumn + invSubWord = invMixColumn
902 $j = 0;
903 while ($j < $this->Nb)
905 $dw = $this->_sub_word($this->w[$row][$j]);
906 $temp[$j] = $this->dt0[$dw & 0xFF000000] ^
907 $this->dt1[$dw & 0x00FF0000] ^
908 $this->dt2[$dw & 0x0000FF00] ^
909 $this->dt3[$dw & 0x000000FF];
910 $j++;
912 $this->dw[$row] = $temp;
915 $col = 0;
916 $row++;
918 $this->w[$row][$col] = $w[$i];
921 $this->dw[$row] = $this->w[$row];
923 $this->changed = false;
927 * Performs S-Box substitutions
929 * @access private
931 function _sub_word($word)
933 static $sbox0, $sbox1, $sbox2, $sbox3;
935 if (empty($sbox0))
937 $sbox0 = array(
938 0x63, 0x7C, 0x77, 0x7B, 0xF2, 0x6B, 0x6F, 0xC5, 0x30, 0x01, 0x67, 0x2B, 0xFE, 0xD7, 0xAB, 0x76,
939 0xCA, 0x82, 0xC9, 0x7D, 0xFA, 0x59, 0x47, 0xF0, 0xAD, 0xD4, 0xA2, 0xAF, 0x9C, 0xA4, 0x72, 0xC0,
940 0xB7, 0xFD, 0x93, 0x26, 0x36, 0x3F, 0xF7, 0xCC, 0x34, 0xA5, 0xE5, 0xF1, 0x71, 0xD8, 0x31, 0x15,
941 0x04, 0xC7, 0x23, 0xC3, 0x18, 0x96, 0x05, 0x9A, 0x07, 0x12, 0x80, 0xE2, 0xEB, 0x27, 0xB2, 0x75,
942 0x09, 0x83, 0x2C, 0x1A, 0x1B, 0x6E, 0x5A, 0xA0, 0x52, 0x3B, 0xD6, 0xB3, 0x29, 0xE3, 0x2F, 0x84,
943 0x53, 0xD1, 0x00, 0xED, 0x20, 0xFC, 0xB1, 0x5B, 0x6A, 0xCB, 0xBE, 0x39, 0x4A, 0x4C, 0x58, 0xCF,
944 0xD0, 0xEF, 0xAA, 0xFB, 0x43, 0x4D, 0x33, 0x85, 0x45, 0xF9, 0x02, 0x7F, 0x50, 0x3C, 0x9F, 0xA8,
945 0x51, 0xA3, 0x40, 0x8F, 0x92, 0x9D, 0x38, 0xF5, 0xBC, 0xB6, 0xDA, 0x21, 0x10, 0xFF, 0xF3, 0xD2,
946 0xCD, 0x0C, 0x13, 0xEC, 0x5F, 0x97, 0x44, 0x17, 0xC4, 0xA7, 0x7E, 0x3D, 0x64, 0x5D, 0x19, 0x73,
947 0x60, 0x81, 0x4F, 0xDC, 0x22, 0x2A, 0x90, 0x88, 0x46, 0xEE, 0xB8, 0x14, 0xDE, 0x5E, 0x0B, 0xDB,
948 0xE0, 0x32, 0x3A, 0x0A, 0x49, 0x06, 0x24, 0x5C, 0xC2, 0xD3, 0xAC, 0x62, 0x91, 0x95, 0xE4, 0x79,
949 0xE7, 0xC8, 0x37, 0x6D, 0x8D, 0xD5, 0x4E, 0xA9, 0x6C, 0x56, 0xF4, 0xEA, 0x65, 0x7A, 0xAE, 0x08,
950 0xBA, 0x78, 0x25, 0x2E, 0x1C, 0xA6, 0xB4, 0xC6, 0xE8, 0xDD, 0x74, 0x1F, 0x4B, 0xBD, 0x8B, 0x8A,
951 0x70, 0x3E, 0xB5, 0x66, 0x48, 0x03, 0xF6, 0x0E, 0x61, 0x35, 0x57, 0xB9, 0x86, 0xC1, 0x1D, 0x9E,
952 0xE1, 0xF8, 0x98, 0x11, 0x69, 0xD9, 0x8E, 0x94, 0x9B, 0x1E, 0x87, 0xE9, 0xCE, 0x55, 0x28, 0xDF,
953 0x8C, 0xA1, 0x89, 0x0D, 0xBF, 0xE6, 0x42, 0x68, 0x41, 0x99, 0x2D, 0x0F, 0xB0, 0x54, 0xBB, 0x16
956 $sbox1 = array();
957 $sbox2 = array();
958 $sbox3 = array();
960 for ($i = 0; $i < 256; $i++)
962 $sbox1[$i << 8] = $sbox0[$i] << 8;
963 $sbox2[$i << 16] = $sbox0[$i] << 16;
964 $sbox3[$i << 24] = $sbox0[$i] << 24;
968 return $sbox0[$word & 0x000000FF] |
969 $sbox1[$word & 0x0000FF00] |
970 $sbox2[$word & 0x00FF0000] |
971 $sbox3[$word & 0xFF000000];
975 * Performs inverse S-Box substitutions
977 * @access private
979 function _inv_sub_word($word)
981 static $sbox0, $sbox1, $sbox2, $sbox3;
983 if (empty($sbox0))
985 $sbox0 = array(
986 0x52, 0x09, 0x6A, 0xD5, 0x30, 0x36, 0xA5, 0x38, 0xBF, 0x40, 0xA3, 0x9E, 0x81, 0xF3, 0xD7, 0xFB,
987 0x7C, 0xE3, 0x39, 0x82, 0x9B, 0x2F, 0xFF, 0x87, 0x34, 0x8E, 0x43, 0x44, 0xC4, 0xDE, 0xE9, 0xCB,
988 0x54, 0x7B, 0x94, 0x32, 0xA6, 0xC2, 0x23, 0x3D, 0xEE, 0x4C, 0x95, 0x0B, 0x42, 0xFA, 0xC3, 0x4E,
989 0x08, 0x2E, 0xA1, 0x66, 0x28, 0xD9, 0x24, 0xB2, 0x76, 0x5B, 0xA2, 0x49, 0x6D, 0x8B, 0xD1, 0x25,
990 0x72, 0xF8, 0xF6, 0x64, 0x86, 0x68, 0x98, 0x16, 0xD4, 0xA4, 0x5C, 0xCC, 0x5D, 0x65, 0xB6, 0x92,
991 0x6C, 0x70, 0x48, 0x50, 0xFD, 0xED, 0xB9, 0xDA, 0x5E, 0x15, 0x46, 0x57, 0xA7, 0x8D, 0x9D, 0x84,
992 0x90, 0xD8, 0xAB, 0x00, 0x8C, 0xBC, 0xD3, 0x0A, 0xF7, 0xE4, 0x58, 0x05, 0xB8, 0xB3, 0x45, 0x06,
993 0xD0, 0x2C, 0x1E, 0x8F, 0xCA, 0x3F, 0x0F, 0x02, 0xC1, 0xAF, 0xBD, 0x03, 0x01, 0x13, 0x8A, 0x6B,
994 0x3A, 0x91, 0x11, 0x41, 0x4F, 0x67, 0xDC, 0xEA, 0x97, 0xF2, 0xCF, 0xCE, 0xF0, 0xB4, 0xE6, 0x73,
995 0x96, 0xAC, 0x74, 0x22, 0xE7, 0xAD, 0x35, 0x85, 0xE2, 0xF9, 0x37, 0xE8, 0x1C, 0x75, 0xDF, 0x6E,
996 0x47, 0xF1, 0x1A, 0x71, 0x1D, 0x29, 0xC5, 0x89, 0x6F, 0xB7, 0x62, 0x0E, 0xAA, 0x18, 0xBE, 0x1B,
997 0xFC, 0x56, 0x3E, 0x4B, 0xC6, 0xD2, 0x79, 0x20, 0x9A, 0xDB, 0xC0, 0xFE, 0x78, 0xCD, 0x5A, 0xF4,
998 0x1F, 0xDD, 0xA8, 0x33, 0x88, 0x07, 0xC7, 0x31, 0xB1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xEC, 0x5F,
999 0x60, 0x51, 0x7F, 0xA9, 0x19, 0xB5, 0x4A, 0x0D, 0x2D, 0xE5, 0x7A, 0x9F, 0x93, 0xC9, 0x9C, 0xEF,
1000 0xA0, 0xE0, 0x3B, 0x4D, 0xAE, 0x2A, 0xF5, 0xB0, 0xC8, 0xEB, 0xBB, 0x3C, 0x83, 0x53, 0x99, 0x61,
1001 0x17, 0x2B, 0x04, 0x7E, 0xBA, 0x77, 0xD6, 0x26, 0xE1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0C, 0x7D
1004 $sbox1 = array();
1005 $sbox2 = array();
1006 $sbox3 = array();
1008 for ($i = 0; $i < 256; $i++)
1010 $sbox1[$i << 8] = $sbox0[$i] << 8;
1011 $sbox2[$i << 16] = $sbox0[$i] << 16;
1012 $sbox3[$i << 24] = $sbox0[$i] << 24;
1016 return $sbox0[$word & 0x000000FF] |
1017 $sbox1[$word & 0x0000FF00] |
1018 $sbox2[$word & 0x00FF0000] |
1019 $sbox3[$word & 0xFF000000];
1023 * Pad "packets".
1025 * Rijndael works by encrypting between sixteen and thirty-two bytes at a time, provided that number is also a multiple
1026 * of four. If you ever need to encrypt or decrypt something that isn't of the proper length, it becomes necessary to
1027 * pad the input so that it is of the proper length.
1029 * Padding is enabled by default. Sometimes, however, it is undesirable to pad strings. Such is the case in SSH,
1030 * where "packets" are padded with random bytes before being encrypted. Unpad these packets and you risk stripping
1031 * away characters that shouldn't be stripped away. (SSH knows how many bytes are added because the length is
1032 * transmitted separately)
1034 * @see rijndael::disable_padding()
1035 * @access public
1037 function enable_padding()
1039 $this->padding = true;
1043 * Do not pad packets.
1045 * @see rijndael::enable_padding()
1046 * @access public
1048 function disable_padding()
1050 $this->padding = false;
1054 * Pads a string
1056 * Pads a string using the RSA PKCS padding standards so that its length is a multiple of the blocksize.
1057 * $block_size - (strlen($text) % $block_size) bytes are added, each of which is equal to
1058 * chr($block_size - (strlen($text) % $block_size)
1060 * If padding is disabled and $text is not a multiple of the blocksize, the string will be padded regardless
1061 * and padding will, hence forth, be enabled.
1063 * @see rijndael::_unpad()
1064 * @access private
1066 function _pad($text)
1068 $length = strlen($text);
1070 if (!$this->padding)
1072 if ($length % $this->block_size == 0)
1074 return $text;
1076 else
1078 $this->padding = true;
1082 $pad = $this->block_size - ($length % $this->block_size);
1084 return str_pad($text, $length + $pad, chr($pad));
1088 * Unpads a string.
1090 * If padding is enabled and the reported padding length exceeds the block size, padding will be, hence forth, disabled.
1092 * @see rijndael::_pad()
1093 * @access private
1095 function _unpad($text)
1097 if (!$this->padding)
1099 return $text;
1102 $length = ord($text[strlen($text) - 1]);
1104 if ($length > $this->block_size)
1106 $this->padding = false;
1107 return $text;
1110 return substr($text, 0, -$length);
1114 * Treat consecutive "packets" as if they are a continuous buffer.
1116 * Say you have a 32-byte plaintext $plaintext. Using the default behavior, the two following code snippets
1117 * will yield different outputs:
1119 * <code>
1120 * echo $rijndael->encrypt(substr($plaintext, 0, 16));
1121 * echo $rijndael->encrypt(substr($plaintext, 16, 16));
1122 * </code>
1123 * <code>
1124 * echo $rijndael->encrypt($plaintext);
1125 * </code>
1127 * The solution is to enable the continuous buffer. Although this will resolve the above discrepancy, it creates
1128 * another, as demonstrated with the following:
1130 * <code>
1131 * $rijndael->encrypt(substr($plaintext, 0, 16));
1132 * echo $rijndael->decrypt($des->encrypt(substr($plaintext, 16, 16)));
1133 * </code>
1134 * <code>
1135 * echo $rijndael->decrypt($des->encrypt(substr($plaintext, 16, 16)));
1136 * </code>
1138 * With the continuous buffer disabled, these would yield the same output. With it enabled, they yield different
1139 * outputs. The reason is due to the fact that the initialization vector's change after every encryption /
1140 * decryption round when the continuous buffer is enabled. When it's disabled, they remain constant.
1142 * Put another way, when the continuous buffer is enabled, the state of the rijndael() object changes after each
1143 * encryption / decryption round, whereas otherwise, it'd remain constant. For this reason, it's recommended that
1144 * continuous buffers not be used. They do offer better security and are, in fact, sometimes required (SSH uses them),
1145 * however, they are also less intuitive and more likely to cause you problems.
1147 * @see rijndael::disable_continuous_buffer()
1148 * @access public
1150 function enable_continuous_buffer()
1152 $this->continuousBuffer = true;
1156 * Treat consecutive packets as if they are a discontinuous buffer.
1158 * The default behavior.
1160 * @see rijndael::enable_continuous_buffer()
1161 * @access public
1163 function disable_continuous_buffer()
1165 $this->continuousBuffer = false;
1166 $this->encryptIV = $this->iv;
1167 $this->decryptIV = $this->iv;
1171 * String Shift
1173 * Inspired by array_shift
1175 * @param String $string
1176 * @param optional Integer $index
1177 * @return String
1178 * @access private
1180 function _string_shift(&$string, $index = 1)
1182 $substr = substr($string, 0, $index);
1183 $string = substr($string, $index);
1184 return $substr;
1189 * Pure-PHP implementation of AES.
1191 * @author Jim Wigginton <terrafrost@php.net>
1192 * @version 0.1.0
1193 * @access public
1194 * @package aes
1196 class aes extends rijndael {
1198 * MCrypt parameters
1200 * @see aes::set_mcypt()
1201 * @var Array
1202 * @access private
1204 var $mcrypt = array('', '');
1207 * Default Constructor.
1209 * Determines whether or not the mcrypt extension should be used. $mode should only, at present, be
1210 * CRYPT_AES_MODE_ECB or CRYPT_AES_MODE_CBC. If not explictly set, CRYPT_AES_MODE_CBC will be used.
1212 * @param optional Integer $mode
1213 * @return aes
1214 * @access public
1216 function __construct($mode = CRYPT_AES_MODE_CBC)
1218 if ( !defined('CRYPT_AES_MODE') )
1220 switch (true)
1222 case extension_loaded('mcrypt'):
1223 // i'd check to see if aes was supported, by doing in_array('des', mcrypt_list_algorithms('')),
1224 // but since that can be changed after the object has been created, there doesn't seem to be
1225 // a lot of point...
1226 define('CRYPT_AES_MODE', CRYPT_AES_MODE_MCRYPT);
1227 break;
1228 default:
1229 define('CRYPT_AES_MODE', CRYPT_AES_MODE_INTERNAL);
1233 switch ( CRYPT_AES_MODE )
1235 case CRYPT_AES_MODE_MCRYPT:
1236 switch ($mode)
1238 case CRYPT_AES_MODE_ECB:
1239 $this->mode = MCRYPT_MODE_ECB;
1240 break;
1241 case CRYPT_AES_MODE_CBC:
1242 default:
1243 $this->mode = MCRYPT_MODE_CBC;
1246 break;
1247 default:
1248 switch ($mode)
1250 case CRYPT_AES_MODE_ECB:
1251 $this->mode = CRYPT_RIJNDAEL_MODE_ECB;
1252 break;
1253 case CRYPT_AES_MODE_CBC:
1254 default:
1255 $this->mode = CRYPT_RIJNDAEL_MODE_CBC;
1259 if (CRYPT_AES_MODE == CRYPT_AES_MODE_INTERNAL)
1261 parent::__construct($this->mode);
1266 * Dummy function
1268 * Since aes extends rijndael, this function is, technically, available, but it doesn't do anything.
1270 * @access public
1271 * @param Integer $length
1273 function set_block_length($length)
1275 return;
1279 * Encrypts a message.
1281 * $plaintext will be padded with up to 16 additional bytes. Other AES implementations may or may not pad in the
1282 * same manner. Other common approaches to padding and the reasons why it's necessary are discussed in the following
1283 * URL:
1285 * {@link http://www.di-mgt.com.au/cryptopad.html http://www.di-mgt.com.au/cryptopad.html}
1287 * An alternative to padding is to, separately, send the length of the file. This is what SSH, in fact, does.
1288 * strlen($plaintext) will still need to be a multiple of 16, however, arbitrary values can be added to make it that
1289 * length.
1291 * @see aes::decrypt()
1292 * @access public
1293 * @param String $plaintext
1295 function encrypt($plaintext)
1297 if ( CRYPT_AES_MODE == CRYPT_AES_MODE_MCRYPT )
1299 $this->_mcrypt_setup();
1300 $plaintext = $this->_pad($plaintext);
1302 $td = mcrypt_module_open(MCRYPT_RIJNDAEL_128, $this->mcrypt[0], $this->mode, $this->mcrypt[1]);
1303 mcrypt_generic_init($td, $this->key, $this->encryptIV);
1305 $ciphertext = mcrypt_generic($td, $plaintext);
1307 mcrypt_generic_deinit($td);
1308 mcrypt_module_close($td);
1310 if ($this->continuousBuffer)
1312 $this->encryptIV = substr($ciphertext, -16);
1315 return $ciphertext;
1318 return parent::encrypt($plaintext);
1322 * Decrypts a message.
1324 * If strlen($ciphertext) is not a multiple of 16, null bytes will be added to the end of the string until it is.
1326 * @see aes::encrypt()
1327 * @access public
1328 * @param String $ciphertext
1330 function decrypt($ciphertext)
1332 // we pad with chr(0) since that's what mcrypt_generic does. to quote from http://php.net/function.mcrypt-generic :
1333 // "The data is padded with "\0" to make sure the length of the data is n * blocksize."
1334 $ciphertext = str_pad($ciphertext, (strlen($ciphertext) + 15) & 0xFFFFFFF0, chr(0));
1336 if ( CRYPT_AES_MODE == CRYPT_AES_MODE_MCRYPT )
1338 $this->_mcryptSetup();
1340 $td = mcrypt_module_open(MCRYPT_RIJNDAEL_128, $this->mcrypt[0], $this->mode, $this->mcrypt[1]);
1341 mcrypt_generic_init($td, $this->key, $this->decryptIV);
1343 $plaintext = mdecrypt_generic($td, $ciphertext);
1345 mcrypt_generic_deinit($td);
1346 mcrypt_module_close($td);
1348 if ($this->continuousBuffer)
1350 $this->decryptIV = substr($ciphertext, -16);
1353 return $this->_unpad($plaintext);
1356 return parent::decrypt($ciphertext);
1360 * Sets MCrypt parameters. (optional)
1362 * If MCrypt is being used, empty strings will be used, unless otherwise specified.
1364 * @link http://php.net/function.mcrypt-module-open#function.mcrypt-module-open
1365 * @access public
1366 * @param optional Integer $algorithm_directory
1367 * @param optional Integer $mode_directory
1369 function set_mcrypt($algorithm_directory = '', $mode_directory = '')
1371 $this->mcrypt = array($algorithm_directory, $mode_directory);
1375 * Setup mcrypt
1377 * Validates all the variables.
1379 * @access private
1381 function _mcrypt_setup()
1383 if (!$this->changed)
1385 return;
1388 if (!$this->explicit_key_length)
1390 // this just copied from rijndael::_setup()
1391 $length = strlen($this->key) >> 2;
1392 if ($length > 8)
1394 $length = 8;
1396 else if ($length < 4)
1398 $length = 4;
1400 $this->Nk = $length;
1401 $this->key_size = $length << 2;
1404 switch ($this->Nk)
1406 case 4: // 128
1407 $this->key_size = 16;
1408 break;
1409 case 5: // 160
1410 case 6: // 192
1411 $this->key_size = 24;
1412 break;
1413 case 7: // 224
1414 case 8: // 256
1415 $this->key_size = 32;
1418 $this->key = substr($this->key, 0, $this->key_size);
1419 $this->encryptIV = $this->decryptIV = $this->iv = str_pad(substr($this->iv, 0, 16), 16, chr(0));
1421 $this->changed = false;
1425 * Encrypts a block
1427 * Optimized over rijndael's implementation by means of loop unrolling.
1429 * @see rijndael::_encrypt_block()
1430 * @access private
1431 * @param String $in
1432 * @return String
1434 function _encrypt_block($in)
1436 // unpack starts it's indices at 1 - not 0.
1437 $state = unpack('N*', $in);
1439 // addRoundKey and reindex $state
1440 $state = array(
1441 $state[1] ^ $this->w[0][0],
1442 $state[2] ^ $this->w[0][1],
1443 $state[3] ^ $this->w[0][2],
1444 $state[4] ^ $this->w[0][3]
1447 // shiftRows + subWord + mixColumns + addRoundKey
1448 // we could loop unroll this and use if statements to do more rounds as necessary, but, in my tests, that yields
1449 // only a marginal improvement. since that also, imho, hinders the readability of the code, i've opted not to do it.
1450 for ($round = 1; $round < $this->Nr; $round++)
1452 $state = array(
1453 $this->t0[$state[0] & 0xFF000000] ^ $this->t1[$state[1] & 0x00FF0000] ^ $this->t2[$state[2] & 0x0000FF00] ^ $this->t3[$state[3] & 0x000000FF] ^ $this->w[$round][0],
1454 $this->t0[$state[1] & 0xFF000000] ^ $this->t1[$state[2] & 0x00FF0000] ^ $this->t2[$state[3] & 0x0000FF00] ^ $this->t3[$state[0] & 0x000000FF] ^ $this->w[$round][1],
1455 $this->t0[$state[2] & 0xFF000000] ^ $this->t1[$state[3] & 0x00FF0000] ^ $this->t2[$state[0] & 0x0000FF00] ^ $this->t3[$state[1] & 0x000000FF] ^ $this->w[$round][2],
1456 $this->t0[$state[3] & 0xFF000000] ^ $this->t1[$state[0] & 0x00FF0000] ^ $this->t2[$state[1] & 0x0000FF00] ^ $this->t3[$state[2] & 0x000000FF] ^ $this->w[$round][3]
1461 // subWord
1462 $state = array(
1463 $this->_sub_word($state[0]),
1464 $this->_sub_word($state[1]),
1465 $this->_sub_word($state[2]),
1466 $this->_sub_word($state[3])
1469 // shiftRows + addRoundKey
1470 $state = array(
1471 ($state[0] & 0xFF000000) ^ ($state[1] & 0x00FF0000) ^ ($state[2] & 0x0000FF00) ^ ($state[3] & 0x000000FF) ^ $this->w[$this->Nr][0],
1472 ($state[1] & 0xFF000000) ^ ($state[2] & 0x00FF0000) ^ ($state[3] & 0x0000FF00) ^ ($state[0] & 0x000000FF) ^ $this->w[$this->Nr][1],
1473 ($state[2] & 0xFF000000) ^ ($state[3] & 0x00FF0000) ^ ($state[0] & 0x0000FF00) ^ ($state[1] & 0x000000FF) ^ $this->w[$this->Nr][2],
1474 ($state[3] & 0xFF000000) ^ ($state[0] & 0x00FF0000) ^ ($state[1] & 0x0000FF00) ^ ($state[2] & 0x000000FF) ^ $this->w[$this->Nr][3]
1477 return pack('N*', $state[0], $state[1], $state[2], $state[3]);
1481 * Decrypts a block
1483 * Optimized over rijndael's implementation by means of loop unrolling.
1485 * @see rijndael::_decrypt_block()
1486 * @access private
1487 * @param String $in
1488 * @return String
1490 function _decrypt_block($in)
1492 // unpack starts it's indices at 1 - not 0.
1493 $state = unpack('N*', $in);
1495 // addRoundKey and reindex $state
1496 $state = array(
1497 $state[1] ^ $this->dw[$this->Nr][0],
1498 $state[2] ^ $this->dw[$this->Nr][1],
1499 $state[3] ^ $this->dw[$this->Nr][2],
1500 $state[4] ^ $this->dw[$this->Nr][3]
1503 // invShiftRows + invSubBytes + invMixColumns + addRoundKey
1504 for ($round = $this->Nr - 1; $round > 0; $round--)
1506 $state = array(
1507 $this->dt0[$state[0] & 0xFF000000] ^ $this->dt1[$state[3] & 0x00FF0000] ^ $this->dt2[$state[2] & 0x0000FF00] ^ $this->dt3[$state[1] & 0x000000FF] ^ $this->dw[$round][0],
1508 $this->dt0[$state[1] & 0xFF000000] ^ $this->dt1[$state[0] & 0x00FF0000] ^ $this->dt2[$state[3] & 0x0000FF00] ^ $this->dt3[$state[2] & 0x000000FF] ^ $this->dw[$round][1],
1509 $this->dt0[$state[2] & 0xFF000000] ^ $this->dt1[$state[1] & 0x00FF0000] ^ $this->dt2[$state[0] & 0x0000FF00] ^ $this->dt3[$state[3] & 0x000000FF] ^ $this->dw[$round][2],
1510 $this->dt0[$state[3] & 0xFF000000] ^ $this->dt1[$state[2] & 0x00FF0000] ^ $this->dt2[$state[1] & 0x0000FF00] ^ $this->dt3[$state[0] & 0x000000FF] ^ $this->dw[$round][3]
1514 // invShiftRows + invSubWord + addRoundKey
1515 $state = array(
1516 $this->_inv_sub_word(($state[0] & 0xFF000000) ^ ($state[3] & 0x00FF0000) ^ ($state[2] & 0x0000FF00) ^ ($state[1] & 0x000000FF)) ^ $this->dw[0][0],
1517 $this->_inv_sub_word(($state[1] & 0xFF000000) ^ ($state[0] & 0x00FF0000) ^ ($state[3] & 0x0000FF00) ^ ($state[2] & 0x000000FF)) ^ $this->dw[0][1],
1518 $this->_inv_sub_word(($state[2] & 0xFF000000) ^ ($state[1] & 0x00FF0000) ^ ($state[0] & 0x0000FF00) ^ ($state[3] & 0x000000FF)) ^ $this->dw[0][2],
1519 $this->_inv_sub_word(($state[3] & 0xFF000000) ^ ($state[2] & 0x00FF0000) ^ ($state[1] & 0x0000FF00) ^ ($state[0] & 0x000000FF)) ^ $this->dw[0][3]
1522 return pack('N*', $state[0], $state[1], $state[2], $state[3]);