SSH SFTP Updater Support - Version 0.5

Version Description

  • update phpseclib to latest version
Download this release

Release Info

Developer TerraFrost
Plugin Icon wp plugin SSH SFTP Updater Support
Version 0.5
Comparing to
See all releases

Code changes from version 0.4 to 0.5

phpseclib/Crypt/AES.php CHANGED
@@ -1,631 +1,207 @@
1
- <?php
2
- /* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
3
-
4
- /**
5
- * Pure-PHP implementation of AES.
6
- *
7
- * Uses mcrypt, if available, and an internal implementation, otherwise.
8
- *
9
- * PHP versions 4 and 5
10
- *
11
- * If {@link Crypt_AES::setKeyLength() setKeyLength()} isn't called, it'll be calculated from
12
- * {@link Crypt_AES::setKey() setKey()}. ie. if the key is 128-bits, the key length will be 128-bits. If it's 136-bits
13
- * it'll be null-padded to 160-bits and 160 bits will be the key length until {@link Crypt_Rijndael::setKey() setKey()}
14
- * is called, again, at which point, it'll be recalculated.
15
- *
16
- * Since Crypt_AES extends Crypt_Rijndael, some functions are available to be called that, in the context of AES, don't
17
- * make a whole lot of sense. {@link Crypt_AES::setBlockLength() setBlockLength()}, for instance. Calling that function,
18
- * however possible, won't do anything (AES has a fixed block length whereas Rijndael has a variable one).
19
- *
20
- * Here's a short example of how to use this library:
21
- * <code>
22
- * <?php
23
- * include('Crypt/AES.php');
24
- *
25
- * $aes = new Crypt_AES();
26
- *
27
- * $aes->setKey('abcdefghijklmnop');
28
- *
29
- * $size = 10 * 1024;
30
- * $plaintext = '';
31
- * for ($i = 0; $i < $size; $i++) {
32
- * $plaintext.= 'a';
33
- * }
34
- *
35
- * echo $aes->decrypt($aes->encrypt($plaintext));
36
- * ?>
37
- * </code>
38
- *
39
- * LICENSE: Permission is hereby granted, free of charge, to any person obtaining a copy
40
- * of this software and associated documentation files (the "Software"), to deal
41
- * in the Software without restriction, including without limitation the rights
42
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
43
- * copies of the Software, and to permit persons to whom the Software is
44
- * furnished to do so, subject to the following conditions:
45
- *
46
- * The above copyright notice and this permission notice shall be included in
47
- * all copies or substantial portions of the Software.
48
- *
49
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
50
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
51
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
52
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
53
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
54
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
55
- * THE SOFTWARE.
56
- *
57
- * @category Crypt
58
- * @package Crypt_AES
59
- * @author Jim Wigginton <terrafrost@php.net>
60
- * @copyright MMVIII Jim Wigginton
61
- * @license http://www.opensource.org/licenses/mit-license.html MIT License
62
- * @version $Id: AES.php,v 1.7 2010/02/09 06:10:25 terrafrost Exp $
63
- * @link http://phpseclib.sourceforge.net
64
- */
65
-
66
- /**
67
- * Include Crypt_Rijndael
68
- */
69
- if (!class_exists('Crypt_Rijndael')) {
70
- require_once 'Rijndael.php';
71
- }
72
-
73
- /**#@+
74
- * @access public
75
- * @see Crypt_AES::encrypt()
76
- * @see Crypt_AES::decrypt()
77
- */
78
- /**
79
- * Encrypt / decrypt using the Counter mode.
80
- *
81
- * Set to -1 since that's what Crypt/Random.php uses to index the CTR mode.
82
- *
83
- * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Counter_.28CTR.29
84
- */
85
- define('CRYPT_AES_MODE_CTR', -1);
86
- /**
87
- * Encrypt / decrypt using the Electronic Code Book mode.
88
- *
89
- * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Electronic_codebook_.28ECB.29
90
- */
91
- define('CRYPT_AES_MODE_ECB', 1);
92
- /**
93
- * Encrypt / decrypt using the Code Book Chaining mode.
94
- *
95
- * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Cipher-block_chaining_.28CBC.29
96
- */
97
- define('CRYPT_AES_MODE_CBC', 2);
98
- /**
99
- * Encrypt / decrypt using the Cipher Feedback mode.
100
- *
101
- * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Cipher_feedback_.28CFB.29
102
- */
103
- define('CRYPT_AES_MODE_CFB', 3);
104
- /**
105
- * Encrypt / decrypt using the Cipher Feedback mode.
106
- *
107
- * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Output_feedback_.28OFB.29
108
- */
109
- define('CRYPT_AES_MODE_OFB', 4);
110
- /**#@-*/
111
-
112
- /**#@+
113
- * @access private
114
- * @see Crypt_AES::Crypt_AES()
115
- */
116
- /**
117
- * Toggles the internal implementation
118
- */
119
- define('CRYPT_AES_MODE_INTERNAL', 1);
120
- /**
121
- * Toggles the mcrypt implementation
122
- */
123
- define('CRYPT_AES_MODE_MCRYPT', 2);
124
- /**#@-*/
125
-
126
- /**
127
- * Pure-PHP implementation of AES.
128
- *
129
- * @author Jim Wigginton <terrafrost@php.net>
130
- * @version 0.1.0
131
- * @access public
132
- * @package Crypt_AES
133
- */
134
- class Crypt_AES extends Crypt_Rijndael {
135
- /**
136
- * mcrypt resource for encryption
137
- *
138
- * The mcrypt resource can be recreated every time something needs to be created or it can be created just once.
139
- * Since mcrypt operates in continuous mode, by default, it'll need to be recreated when in non-continuous mode.
140
- *
141
- * @see Crypt_AES::encrypt()
142
- * @var String
143
- * @access private
144
- */
145
- var $enmcrypt;
146
-
147
- /**
148
- * mcrypt resource for decryption
149
- *
150
- * The mcrypt resource can be recreated every time something needs to be created or it can be created just once.
151
- * Since mcrypt operates in continuous mode, by default, it'll need to be recreated when in non-continuous mode.
152
- *
153
- * @see Crypt_AES::decrypt()
154
- * @var String
155
- * @access private
156
- */
157
- var $demcrypt;
158
-
159
- /**
160
- * mcrypt resource for CFB mode
161
- *
162
- * @see Crypt_AES::encrypt()
163
- * @see Crypt_AES::decrypt()
164
- * @var String
165
- * @access private
166
- */
167
- var $ecb;
168
-
169
- /**
170
- * Default Constructor.
171
- *
172
- * Determines whether or not the mcrypt extension should be used. $mode should only, at present, be
173
- * CRYPT_AES_MODE_ECB or CRYPT_AES_MODE_CBC. If not explictly set, CRYPT_AES_MODE_CBC will be used.
174
- *
175
- * @param optional Integer $mode
176
- * @return Crypt_AES
177
- * @access public
178
- */
179
- function Crypt_AES($mode = CRYPT_AES_MODE_CBC)
180
- {
181
- if ( !defined('CRYPT_AES_MODE') ) {
182
- switch (true) {
183
- case extension_loaded('mcrypt') && in_array('rijndael-128', mcrypt_list_algorithms()):
184
- define('CRYPT_AES_MODE', CRYPT_AES_MODE_MCRYPT);
185
- break;
186
- default:
187
- define('CRYPT_AES_MODE', CRYPT_AES_MODE_INTERNAL);
188
- }
189
- }
190
-
191
- switch ( CRYPT_AES_MODE ) {
192
- case CRYPT_AES_MODE_MCRYPT:
193
- switch ($mode) {
194
- case CRYPT_AES_MODE_ECB:
195
- $this->paddable = true;
196
- $this->mode = MCRYPT_MODE_ECB;
197
- break;
198
- case CRYPT_AES_MODE_CTR:
199
- // ctr doesn't have a constant associated with it even though it appears to be fairly widely
200
- // supported. in lieu of knowing just how widely supported it is, i've, for now, opted not to
201
- // include a compatibility layer. the layer has been implemented but, for now, is commented out.
202
- $this->mode = 'ctr';
203
- //$this->mode = in_array('ctr', mcrypt_list_modes()) ? 'ctr' : CRYPT_AES_MODE_CTR;
204
- break;
205
- case CRYPT_AES_MODE_CFB:
206
- $this->mode = 'ncfb';
207
- break;
208
- case CRYPT_AES_MODE_OFB:
209
- $this->mode = MCRYPT_MODE_NOFB;
210
- break;
211
- case CRYPT_AES_MODE_CBC:
212
- default:
213
- $this->paddable = true;
214
- $this->mode = MCRYPT_MODE_CBC;
215
- }
216
-
217
- break;
218
- default:
219
- switch ($mode) {
220
- case CRYPT_AES_MODE_ECB:
221
- $this->paddable = true;
222
- $this->mode = CRYPT_RIJNDAEL_MODE_ECB;
223
- break;
224
- case CRYPT_AES_MODE_CTR:
225
- $this->mode = CRYPT_RIJNDAEL_MODE_CTR;
226
- break;
227
- case CRYPT_AES_MODE_CFB:
228
- $this->mode = CRYPT_RIJNDAEL_MODE_CFB;
229
- break;
230
- case CRYPT_AES_MODE_OFB:
231
- $this->mode = CRYPT_RIJNDAEL_MODE_OFB;
232
- break;
233
- case CRYPT_AES_MODE_CBC:
234
- default:
235
- $this->paddable = true;
236
- $this->mode = CRYPT_RIJNDAEL_MODE_CBC;
237
- }
238
- }
239
-
240
- if (CRYPT_AES_MODE == CRYPT_AES_MODE_INTERNAL) {
241
- parent::Crypt_Rijndael($this->mode);
242
- }
243
- }
244
-
245
- /**
246
- * Dummy function
247
- *
248
- * Since Crypt_AES extends Crypt_Rijndael, this function is, technically, available, but it doesn't do anything.
249
- *
250
- * @access public
251
- * @param Integer $length
252
- */
253
- function setBlockLength($length)
254
- {
255
- return;
256
- }
257
-
258
-
259
- /**
260
- * Sets the initialization vector. (optional)
261
- *
262
- * SetIV is not required when CRYPT_RIJNDAEL_MODE_ECB is being used. If not explictly set, it'll be assumed
263
- * to be all zero's.
264
- *
265
- * @access public
266
- * @param String $iv
267
- */
268
- function setIV($iv)
269
- {
270
- parent::setIV($iv);
271
- if ( CRYPT_AES_MODE == CRYPT_AES_MODE_MCRYPT ) {
272
- $this->changed = true;
273
- }
274
- }
275
-
276
- /**
277
- * Encrypts a message.
278
- *
279
- * $plaintext will be padded with up to 16 additional bytes. Other AES implementations may or may not pad in the
280
- * same manner. Other common approaches to padding and the reasons why it's necessary are discussed in the following
281
- * URL:
282
- *
283
- * {@link http://www.di-mgt.com.au/cryptopad.html http://www.di-mgt.com.au/cryptopad.html}
284
- *
285
- * An alternative to padding is to, separately, send the length of the file. This is what SSH, in fact, does.
286
- * strlen($plaintext) will still need to be a multiple of 16, however, arbitrary values can be added to make it that
287
- * length.
288
- *
289
- * @see Crypt_AES::decrypt()
290
- * @access public
291
- * @param String $plaintext
292
- */
293
- function encrypt($plaintext)
294
- {
295
- if ( CRYPT_AES_MODE == CRYPT_AES_MODE_MCRYPT ) {
296
- $changed = $this->changed;
297
- $this->_mcryptSetup();
298
- /*
299
- if ($this->mode == CRYPT_AES_MODE_CTR) {
300
- $iv = $this->encryptIV;
301
- $xor = mcrypt_generic($this->enmcrypt, $this->_generate_xor(strlen($plaintext), $iv));
302
- $ciphertext = $plaintext ^ $xor;
303
- if ($this->continuousBuffer) {
304
- $this->encryptIV = $iv;
305
- }
306
- return $ciphertext;
307
- }
308
- */
309
- // re: http://phpseclib.sourceforge.net/cfb-demo.phps
310
- // using mcrypt's default handing of CFB the above would output two different things. using phpseclib's
311
- // rewritten CFB implementation the above outputs the same thing twice.
312
- if ($this->mode == 'ncfb' && $this->continuousBuffer) {
313
- if ($changed) {
314
- $this->ecb = mcrypt_module_open(MCRYPT_RIJNDAEL_128, '', MCRYPT_MODE_ECB, '');
315
- mcrypt_generic_init($this->ecb, $this->key, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0");
316
- }
317
-
318
- $buffer = &$this->enbuffer['encrypted'];
319
-
320
- if (strlen($buffer)) {
321
- $ciphertext = $plaintext ^ substr($this->encryptIV, strlen($buffer));
322
- $buffer.= $ciphertext;
323
- if (strlen($buffer) == 16) {
324
- $this->encryptIV = $buffer;
325
- $buffer = '';
326
- mcrypt_generic_init($this->enmcrypt, $this->key, $this->encryptIV);
327
- }
328
- $plaintext = substr($plaintext, strlen($ciphertext));
329
- } else {
330
- $ciphertext = '';
331
- }
332
-
333
- $last_pos = strlen($plaintext) & 0xFFFFFFF0;
334
- if ($last_pos) {
335
- $ciphertext.= mcrypt_generic($this->enmcrypt, substr($plaintext, 0, $last_pos));
336
- $this->encryptIV = substr($ciphertext, -16);
337
- }
338
-
339
- if (strlen($plaintext) & 0xF) {
340
- $this->encryptIV = mcrypt_generic($this->ecb, $this->encryptIV);
341
- $buffer = substr($plaintext, $last_pos) ^ $this->encryptIV;
342
- $ciphertext.= $buffer;
343
- }
344
-
345
- return $ciphertext;
346
- }
347
-
348
- if ($this->paddable) {
349
- $plaintext = $this->_pad($plaintext);
350
- }
351
-
352
- $ciphertext = mcrypt_generic($this->enmcrypt, $plaintext);
353
-
354
- if (!$this->continuousBuffer) {
355
- mcrypt_generic_init($this->enmcrypt, $this->key, $this->iv);
356
- }
357
-
358
- return $ciphertext;
359
- }
360
-
361
- return parent::encrypt($plaintext);
362
- }
363
-
364
- /**
365
- * Decrypts a message.
366
- *
367
- * If strlen($ciphertext) is not a multiple of 16, null bytes will be added to the end of the string until it is.
368
- *
369
- * @see Crypt_AES::encrypt()
370
- * @access public
371
- * @param String $ciphertext
372
- */
373
- function decrypt($ciphertext)
374
- {
375
- if ( CRYPT_AES_MODE == CRYPT_AES_MODE_MCRYPT ) {
376
- $changed = $this->changed;
377
- $this->_mcryptSetup();
378
- /*
379
- if ($this->mode == CRYPT_AES_MODE_CTR) {
380
- $iv = $this->decryptIV;
381
- $xor = mcrypt_generic($this->enmcrypt, $this->_generate_xor(strlen($ciphertext), $iv));
382
- $plaintext = $ciphertext ^ $xor;
383
- if ($this->continuousBuffer) {
384
- $this->decryptIV = $iv;
385
- }
386
- return $plaintext;
387
- }
388
- */
389
- if ($this->mode == 'ncfb' && $this->continuousBuffer) {
390
- if ($changed) {
391
- $this->ecb = mcrypt_module_open(MCRYPT_RIJNDAEL_128, '', MCRYPT_MODE_ECB, '');
392
- mcrypt_generic_init($this->ecb, $this->key, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0");
393
- }
394
-
395
- $buffer = &$this->debuffer['ciphertext'];
396
-
397
- if (strlen($buffer)) {
398
- $plaintext = $ciphertext ^ substr($this->decryptIV, strlen($buffer));
399
-
400
- $buffer.= substr($ciphertext, 0, strlen($plaintext));
401
- if (strlen($buffer) == 16) {
402
- $this->decryptIV = $buffer;
403
- $buffer = '';
404
- mcrypt_generic_init($this->demcrypt, $this->key, $this->decryptIV);
405
- }
406
- $ciphertext = substr($ciphertext, strlen($plaintext));
407
- } else {
408
- $plaintext = '';
409
- }
410
-
411
- $last_pos = strlen($ciphertext) & 0xFFFFFFF0;
412
- if ($last_pos) {
413
- $plaintext = mdecrypt_generic($this->demcrypt, substr($ciphertext, 0, $last_pos));
414
- $this->decryptIV = substr($ciphertext, $last_pos - 16, 16);
415
- $this->decryptIV = mcrypt_generic($this->ecb, $this->decryptIV);
416
- }
417
-
418
- if (strlen($ciphertext) & 0xF) {
419
- $buffer = substr($ciphertext, $last_pos);
420
- $plaintext.= $buffer ^ $this->decryptIV;
421
- }
422
-
423
- return $plaintext;
424
- }
425
-
426
- if ($this->paddable) {
427
- // we pad with chr(0) since that's what mcrypt_generic does. to quote from http://php.net/function.mcrypt-generic :
428
- // "The data is padded with "\0" to make sure the length of the data is n * blocksize."
429
- $ciphertext = str_pad($ciphertext, (strlen($ciphertext) + 15) & 0xFFFFFFF0, chr(0));
430
- }
431
-
432
- $plaintext = mdecrypt_generic($this->demcrypt, $ciphertext);
433
-
434
- if (!$this->continuousBuffer) {
435
- mcrypt_generic_init($this->demcrypt, $this->key, $this->iv);
436
- }
437
-
438
- return $this->paddable ? $this->_unpad($plaintext) : $plaintext;
439
- }
440
-
441
- return parent::decrypt($ciphertext);
442
- }
443
-
444
- /**
445
- * Setup mcrypt
446
- *
447
- * Validates all the variables.
448
- *
449
- * @access private
450
- */
451
- function _mcryptSetup()
452
- {
453
- if (!$this->changed) {
454
- return;
455
- }
456
-
457
- if (!$this->explicit_key_length) {
458
- // this just copied from Crypt_Rijndael::_setup()
459
- $length = strlen($this->key) >> 2;
460
- if ($length > 8) {
461
- $length = 8;
462
- } else if ($length < 4) {
463
- $length = 4;
464
- }
465
- $this->Nk = $length;
466
- $this->key_size = $length << 2;
467
- }
468
-
469
- switch ($this->Nk) {
470
- case 4: // 128
471
- $this->key_size = 16;
472
- break;
473
- case 5: // 160
474
- case 6: // 192
475
- $this->key_size = 24;
476
- break;
477
- case 7: // 224
478
- case 8: // 256
479
- $this->key_size = 32;
480
- }
481
-
482
- $this->key = str_pad(substr($this->key, 0, $this->key_size), $this->key_size, chr(0));
483
- $this->encryptIV = $this->decryptIV = $this->iv = str_pad(substr($this->iv, 0, 16), 16, chr(0));
484
-
485
- if (!isset($this->enmcrypt)) {
486
- $mode = $this->mode;
487
- //$mode = $this->mode == CRYPT_AES_MODE_CTR ? MCRYPT_MODE_ECB : $this->mode;
488
-
489
- $this->demcrypt = mcrypt_module_open(MCRYPT_RIJNDAEL_128, '', $mode, '');
490
- $this->enmcrypt = mcrypt_module_open(MCRYPT_RIJNDAEL_128, '', $mode, '');
491
- } // else should mcrypt_generic_deinit be called?
492
-
493
- mcrypt_generic_init($this->demcrypt, $this->key, $this->iv);
494
- mcrypt_generic_init($this->enmcrypt, $this->key, $this->iv);
495
-
496
- $this->changed = false;
497
- }
498
-
499
- /**
500
- * Encrypts a block
501
- *
502
- * Optimized over Crypt_Rijndael's implementation by means of loop unrolling.
503
- *
504
- * @see Crypt_Rijndael::_encryptBlock()
505
- * @access private
506
- * @param String $in
507
- * @return String
508
- */
509
- function _encryptBlock($in)
510
- {
511
- $state = unpack('N*word', $in);
512
-
513
- $Nr = $this->Nr;
514
- $w = $this->w;
515
- $t0 = $this->t0;
516
- $t1 = $this->t1;
517
- $t2 = $this->t2;
518
- $t3 = $this->t3;
519
-
520
- // addRoundKey and reindex $state
521
- $state = array(
522
- $state['word1'] ^ $w[0][0],
523
- $state['word2'] ^ $w[0][1],
524
- $state['word3'] ^ $w[0][2],
525
- $state['word4'] ^ $w[0][3]
526
- );
527
-
528
- // shiftRows + subWord + mixColumns + addRoundKey
529
- // we could loop unroll this and use if statements to do more rounds as necessary, but, in my tests, that yields
530
- // only a marginal improvement. since that also, imho, hinders the readability of the code, i've opted not to do it.
531
- for ($round = 1; $round < $Nr; $round++) {
532
- $state = array(
533
- $t0[$state[0] & 0xFF000000] ^ $t1[$state[1] & 0x00FF0000] ^ $t2[$state[2] & 0x0000FF00] ^ $t3[$state[3] & 0x000000FF] ^ $w[$round][0],
534
- $t0[$state[1] & 0xFF000000] ^ $t1[$state[2] & 0x00FF0000] ^ $t2[$state[3] & 0x0000FF00] ^ $t3[$state[0] & 0x000000FF] ^ $w[$round][1],
535
- $t0[$state[2] & 0xFF000000] ^ $t1[$state[3] & 0x00FF0000] ^ $t2[$state[0] & 0x0000FF00] ^ $t3[$state[1] & 0x000000FF] ^ $w[$round][2],
536
- $t0[$state[3] & 0xFF000000] ^ $t1[$state[0] & 0x00FF0000] ^ $t2[$state[1] & 0x0000FF00] ^ $t3[$state[2] & 0x000000FF] ^ $w[$round][3]
537
- );
538
-
539
- }
540
-
541
- // subWord
542
- $state = array(
543
- $this->_subWord($state[0]),
544
- $this->_subWord($state[1]),
545
- $this->_subWord($state[2]),
546
- $this->_subWord($state[3])
547
- );
548
-
549
- // shiftRows + addRoundKey
550
- $state = array(
551
- ($state[0] & 0xFF000000) ^ ($state[1] & 0x00FF0000) ^ ($state[2] & 0x0000FF00) ^ ($state[3] & 0x000000FF) ^ $this->w[$this->Nr][0],
552
- ($state[1] & 0xFF000000) ^ ($state[2] & 0x00FF0000) ^ ($state[3] & 0x0000FF00) ^ ($state[0] & 0x000000FF) ^ $this->w[$this->Nr][1],
553
- ($state[2] & 0xFF000000) ^ ($state[3] & 0x00FF0000) ^ ($state[0] & 0x0000FF00) ^ ($state[1] & 0x000000FF) ^ $this->w[$this->Nr][2],
554
- ($state[3] & 0xFF000000) ^ ($state[0] & 0x00FF0000) ^ ($state[1] & 0x0000FF00) ^ ($state[2] & 0x000000FF) ^ $this->w[$this->Nr][3]
555
- );
556
-
557
- return pack('N*', $state[0], $state[1], $state[2], $state[3]);
558
- }
559
-
560
- /**
561
- * Decrypts a block
562
- *
563
- * Optimized over Crypt_Rijndael's implementation by means of loop unrolling.
564
- *
565
- * @see Crypt_Rijndael::_decryptBlock()
566
- * @access private
567
- * @param String $in
568
- * @return String
569
- */
570
- function _decryptBlock($in)
571
- {
572
- $state = unpack('N*word', $in);
573
-
574
- $Nr = $this->Nr;
575
- $dw = $this->dw;
576
- $dt0 = $this->dt0;
577
- $dt1 = $this->dt1;
578
- $dt2 = $this->dt2;
579
- $dt3 = $this->dt3;
580
-
581
- // addRoundKey and reindex $state
582
- $state = array(
583
- $state['word1'] ^ $dw[$this->Nr][0],
584
- $state['word2'] ^ $dw[$this->Nr][1],
585
- $state['word3'] ^ $dw[$this->Nr][2],
586
- $state['word4'] ^ $dw[$this->Nr][3]
587
- );
588
-
589
-
590
- // invShiftRows + invSubBytes + invMixColumns + addRoundKey
591
- for ($round = $Nr - 1; $round > 0; $round--) {
592
- $state = array(
593
- $dt0[$state[0] & 0xFF000000] ^ $dt1[$state[3] & 0x00FF0000] ^ $dt2[$state[2] & 0x0000FF00] ^ $dt3[$state[1] & 0x000000FF] ^ $dw[$round][0],
594
- $dt0[$state[1] & 0xFF000000] ^ $dt1[$state[0] & 0x00FF0000] ^ $dt2[$state[3] & 0x0000FF00] ^ $dt3[$state[2] & 0x000000FF] ^ $dw[$round][1],
595
- $dt0[$state[2] & 0xFF000000] ^ $dt1[$state[1] & 0x00FF0000] ^ $dt2[$state[0] & 0x0000FF00] ^ $dt3[$state[3] & 0x000000FF] ^ $dw[$round][2],
596
- $dt0[$state[3] & 0xFF000000] ^ $dt1[$state[2] & 0x00FF0000] ^ $dt2[$state[1] & 0x0000FF00] ^ $dt3[$state[0] & 0x000000FF] ^ $dw[$round][3]
597
- );
598
- }
599
-
600
- // invShiftRows + invSubWord + addRoundKey
601
- $state = array(
602
- $this->_invSubWord(($state[0] & 0xFF000000) ^ ($state[3] & 0x00FF0000) ^ ($state[2] & 0x0000FF00) ^ ($state[1] & 0x000000FF)) ^ $dw[0][0],
603
- $this->_invSubWord(($state[1] & 0xFF000000) ^ ($state[0] & 0x00FF0000) ^ ($state[3] & 0x0000FF00) ^ ($state[2] & 0x000000FF)) ^ $dw[0][1],
604
- $this->_invSubWord(($state[2] & 0xFF000000) ^ ($state[1] & 0x00FF0000) ^ ($state[0] & 0x0000FF00) ^ ($state[3] & 0x000000FF)) ^ $dw[0][2],
605
- $this->_invSubWord(($state[3] & 0xFF000000) ^ ($state[2] & 0x00FF0000) ^ ($state[1] & 0x0000FF00) ^ ($state[0] & 0x000000FF)) ^ $dw[0][3]
606
- );
607
-
608
- return pack('N*', $state[0], $state[1], $state[2], $state[3]);
609
- }
610
-
611
- /**
612
- * Treat consecutive packets as if they are a discontinuous buffer.
613
- *
614
- * The default behavior.
615
- *
616
- * @see Crypt_Rijndael::enableContinuousBuffer()
617
- * @access public
618
- */
619
- function disableContinuousBuffer()
620
- {
621
- parent::disableContinuousBuffer();
622
-
623
- if (CRYPT_AES_MODE == CRYPT_AES_MODE_MCRYPT) {
624
- mcrypt_generic_init($this->enmcrypt, $this->key, $this->iv);
625
- mcrypt_generic_init($this->demcrypt, $this->key, $this->iv);
626
- }
627
- }
628
- }
629
-
630
- // vim: ts=4:sw=4:et:
631
- // vim6: fdl=1:
1
+ <?php
2
+
3
+ /**
4
+ * Pure-PHP implementation of AES.
5
+ *
6
+ * Uses mcrypt, if available/possible, and an internal implementation, otherwise.
7
+ *
8
+ * PHP versions 4 and 5
9
+ *
10
+ * If {@link Crypt_AES::setKeyLength() setKeyLength()} isn't called, it'll be calculated from
11
+ * {@link Crypt_AES::setKey() setKey()}. ie. if the key is 128-bits, the key length will be 128-bits. If it's 136-bits
12
+ * it'll be null-padded to 192-bits and 192 bits will be the key length until {@link Crypt_AES::setKey() setKey()}
13
+ * is called, again, at which point, it'll be recalculated.
14
+ *
15
+ * Since Crypt_AES extends Crypt_Rijndael, some functions are available to be called that, in the context of AES, don't
16
+ * make a whole lot of sense. {@link Crypt_AES::setBlockLength() setBlockLength()}, for instance. Calling that function,
17
+ * however possible, won't do anything (AES has a fixed block length whereas Rijndael has a variable one).
18
+ *
19
+ * Here's a short example of how to use this library:
20
+ * <code>
21
+ * <?php
22
+ * include 'Crypt/AES.php';
23
+ *
24
+ * $aes = new Crypt_AES();
25
+ *
26
+ * $aes->setKey('abcdefghijklmnop');
27
+ *
28
+ * $size = 10 * 1024;
29
+ * $plaintext = '';
30
+ * for ($i = 0; $i < $size; $i++) {
31
+ * $plaintext.= 'a';
32
+ * }
33
+ *
34
+ * echo $aes->decrypt($aes->encrypt($plaintext));
35
+ * ?>
36
+ * </code>
37
+ *
38
+ * LICENSE: Permission is hereby granted, free of charge, to any person obtaining a copy
39
+ * of this software and associated documentation files (the "Software"), to deal
40
+ * in the Software without restriction, including without limitation the rights
41
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
42
+ * copies of the Software, and to permit persons to whom the Software is
43
+ * furnished to do so, subject to the following conditions:
44
+ *
45
+ * The above copyright notice and this permission notice shall be included in
46
+ * all copies or substantial portions of the Software.
47
+ *
48
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
49
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
50
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
51
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
52
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
53
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
54
+ * THE SOFTWARE.
55
+ *
56
+ * @category Crypt
57
+ * @package Crypt_AES
58
+ * @author Jim Wigginton <terrafrost@php.net>
59
+ * @copyright MMVIII Jim Wigginton
60
+ * @license http://www.opensource.org/licenses/mit-license.html MIT License
61
+ * @link http://phpseclib.sourceforge.net
62
+ */
63
+
64
+ /**
65
+ * Include Crypt_Rijndael
66
+ */
67
+ if (!class_exists('Crypt_Rijndael')) {
68
+ include_once 'Rijndael.php';
69
+ }
70
+
71
+ /**#@+
72
+ * @access public
73
+ * @see Crypt_AES::encrypt()
74
+ * @see Crypt_AES::decrypt()
75
+ */
76
+ /**
77
+ * Encrypt / decrypt using the Counter mode.
78
+ *
79
+ * Set to -1 since that's what Crypt/Random.php uses to index the CTR mode.
80
+ *
81
+ * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Counter_.28CTR.29
82
+ */
83
+ define('CRYPT_AES_MODE_CTR', CRYPT_MODE_CTR);
84
+ /**
85
+ * Encrypt / decrypt using the Electronic Code Book mode.
86
+ *
87
+ * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Electronic_codebook_.28ECB.29
88
+ */
89
+ define('CRYPT_AES_MODE_ECB', CRYPT_MODE_ECB);
90
+ /**
91
+ * Encrypt / decrypt using the Code Book Chaining mode.
92
+ *
93
+ * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Cipher-block_chaining_.28CBC.29
94
+ */
95
+ define('CRYPT_AES_MODE_CBC', CRYPT_MODE_CBC);
96
+ /**
97
+ * Encrypt / decrypt using the Cipher Feedback mode.
98
+ *
99
+ * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Cipher_feedback_.28CFB.29
100
+ */
101
+ define('CRYPT_AES_MODE_CFB', CRYPT_MODE_CFB);
102
+ /**
103
+ * Encrypt / decrypt using the Cipher Feedback mode.
104
+ *
105
+ * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Output_feedback_.28OFB.29
106
+ */
107
+ define('CRYPT_AES_MODE_OFB', CRYPT_MODE_OFB);
108
+ /**#@-*/
109
+
110
+ /**#@+
111
+ * @access private
112
+ * @see Crypt_Base::Crypt_Base()
113
+ */
114
+ /**
115
+ * Toggles the internal implementation
116
+ */
117
+ define('CRYPT_AES_MODE_INTERNAL', CRYPT_MODE_INTERNAL);
118
+ /**
119
+ * Toggles the mcrypt implementation
120
+ */
121
+ define('CRYPT_AES_MODE_MCRYPT', CRYPT_MODE_MCRYPT);
122
+ /**#@-*/
123
+
124
+ /**
125
+ * Pure-PHP implementation of AES.
126
+ *
127
+ * @package Crypt_AES
128
+ * @author Jim Wigginton <terrafrost@php.net>
129
+ * @access public
130
+ */
131
+ class Crypt_AES extends Crypt_Rijndael
132
+ {
133
+ /**
134
+ * The namespace used by the cipher for its constants.
135
+ *
136
+ * @see Crypt_Base::const_namespace
137
+ * @var String
138
+ * @access private
139
+ */
140
+ var $const_namespace = 'AES';
141
+
142
+ /**
143
+ * Dummy function
144
+ *
145
+ * Since Crypt_AES extends Crypt_Rijndael, this function is, technically, available, but it doesn't do anything.
146
+ *
147
+ * @see Crypt_Rijndael::setBlockLength()
148
+ * @access public
149
+ * @param Integer $length
150
+ */
151
+ function setBlockLength($length)
152
+ {
153
+ return;
154
+ }
155
+
156
+ /**
157
+ * Sets the key length
158
+ *
159
+ * Valid key lengths are 128, 192, and 256. If the length is less than 128, it will be rounded up to
160
+ * 128. If the length is greater than 128 and invalid, it will be rounded down to the closest valid amount.
161
+ *
162
+ * @see Crypt_Rijndael:setKeyLength()
163
+ * @access public
164
+ * @param Integer $length
165
+ */
166
+ function setKeyLength($length)
167
+ {
168
+ switch ($length) {
169
+ case 160:
170
+ $length = 192;
171
+ break;
172
+ case 224:
173
+ $length = 256;
174
+ }
175
+ parent::setKeyLength($length);
176
+ }
177
+
178
+ /**
179
+ * Sets the key.
180
+ *
181
+ * Rijndael supports five different key lengths, AES only supports three.
182
+ *
183
+ * @see Crypt_Rijndael:setKey()
184
+ * @see setKeyLength()
185
+ * @access public
186
+ * @param String $key
187
+ */
188
+ function setKey($key)
189
+ {
190
+ parent::setKey($key);
191
+
192
+ if (!$this->explicit_key_length) {
193
+ $length = strlen($key);
194
+ switch (true) {
195
+ case $length <= 16:
196
+ $this->key_size = 16;
197
+ break;
198
+ case $length <= 24:
199
+ $this->key_size = 24;
200
+ break;
201
+ default:
202
+ $this->key_size = 32;
203
+ }
204
+ $this->_setupEngine();
205
+ }
206
+ }
207
+ }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
phpseclib/Crypt/Base.php ADDED
@@ -0,0 +1,2011 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * Base Class for all Crypt_* cipher classes
5
+ *
6
+ * PHP versions 4 and 5
7
+ *
8
+ * Internally for phpseclib developers:
9
+ * If you plan to add a new cipher class, please note following rules:
10
+ *
11
+ * - The new Crypt_* cipher class should extend Crypt_Base
12
+ *
13
+ * - Following methods are then required to be overridden/overloaded:
14
+ *
15
+ * - _encryptBlock()
16
+ *
17
+ * - _decryptBlock()
18
+ *
19
+ * - _setupKey()
20
+ *
21
+ * - All other methods are optional to be overridden/overloaded
22
+ *
23
+ * - Look at the source code of the current ciphers how they extend Crypt_Base
24
+ * and take one of them as a start up for the new cipher class.
25
+ *
26
+ * - Please read all the other comments/notes/hints here also for each class var/method
27
+ *
28
+ * LICENSE: Permission is hereby granted, free of charge, to any person obtaining a copy
29
+ * of this software and associated documentation files (the "Software"), to deal
30
+ * in the Software without restriction, including without limitation the rights
31
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
32
+ * copies of the Software, and to permit persons to whom the Software is
33
+ * furnished to do so, subject to the following conditions:
34
+ *
35
+ * The above copyright notice and this permission notice shall be included in
36
+ * all copies or substantial portions of the Software.
37
+ *
38
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
39
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
40
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
41
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
42
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
43
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
44
+ * THE SOFTWARE.
45
+ *
46
+ * @category Crypt
47
+ * @package Crypt_Base
48
+ * @author Jim Wigginton <terrafrost@php.net>
49
+ * @author Hans-Juergen Petrich <petrich@tronic-media.com>
50
+ * @copyright MMVII Jim Wigginton
51
+ * @license http://www.opensource.org/licenses/mit-license.html MIT License
52
+ * @link http://phpseclib.sourceforge.net
53
+ */
54
+
55
+ /**#@+
56
+ * @access public
57
+ * @see Crypt_Base::encrypt()
58
+ * @see Crypt_Base::decrypt()
59
+ */
60
+ /**
61
+ * Encrypt / decrypt using the Counter mode.
62
+ *
63
+ * Set to -1 since that's what Crypt/Random.php uses to index the CTR mode.
64
+ *
65
+ * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Counter_.28CTR.29
66
+ */
67
+ define('CRYPT_MODE_CTR', -1);
68
+ /**
69
+ * Encrypt / decrypt using the Electronic Code Book mode.
70
+ *
71
+ * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Electronic_codebook_.28ECB.29
72
+ */
73
+ define('CRYPT_MODE_ECB', 1);
74
+ /**
75
+ * Encrypt / decrypt using the Code Book Chaining mode.
76
+ *
77
+ * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Cipher-block_chaining_.28CBC.29
78
+ */
79
+ define('CRYPT_MODE_CBC', 2);
80
+ /**
81
+ * Encrypt / decrypt using the Cipher Feedback mode.
82
+ *
83
+ * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Cipher_feedback_.28CFB.29
84
+ */
85
+ define('CRYPT_MODE_CFB', 3);
86
+ /**
87
+ * Encrypt / decrypt using the Output Feedback mode.
88
+ *
89
+ * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Output_feedback_.28OFB.29
90
+ */
91
+ define('CRYPT_MODE_OFB', 4);
92
+ /**
93
+ * Encrypt / decrypt using streaming mode.
94
+ *
95
+ */
96
+ define('CRYPT_MODE_STREAM', 5);
97
+ /**#@-*/
98
+
99
+ /**#@+
100
+ * @access private
101
+ * @see Crypt_Base::Crypt_Base()
102
+ */
103
+ /**
104
+ * Base value for the internal implementation $engine switch
105
+ */
106
+ define('CRYPT_MODE_INTERNAL', 1);
107
+ /**
108
+ * Base value for the mcrypt implementation $engine switch
109
+ */
110
+ define('CRYPT_MODE_MCRYPT', 2);
111
+ /**#@-*/
112
+
113
+ /**
114
+ * Base Class for all Crypt_* cipher classes
115
+ *
116
+ * @package Crypt_Base
117
+ * @author Jim Wigginton <terrafrost@php.net>
118
+ * @author Hans-Juergen Petrich <petrich@tronic-media.com>
119
+ * @access public
120
+ */
121
+ class Crypt_Base
122
+ {
123
+ /**
124
+ * The Encryption Mode
125
+ *
126
+ * @see Crypt_Base::Crypt_Base()
127
+ * @var Integer
128
+ * @access private
129
+ */
130
+ var $mode;
131
+
132
+ /**
133
+ * The Block Length of the block cipher
134
+ *
135
+ * @var Integer
136
+ * @access private
137
+ */
138
+ var $block_size = 16;
139
+
140
+ /**
141
+ * The Key
142
+ *
143
+ * @see Crypt_Base::setKey()
144
+ * @var String
145
+ * @access private
146
+ */
147
+ var $key = "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0";
148
+
149
+ /**
150
+ * The Initialization Vector
151
+ *
152
+ * @see Crypt_Base::setIV()
153
+ * @var String
154
+ * @access private
155
+ */
156
+ var $iv;
157
+
158
+ /**
159
+ * A "sliding" Initialization Vector
160
+ *
161
+ * @see Crypt_Base::enableContinuousBuffer()
162
+ * @see Crypt_Base::_clearBuffers()
163
+ * @var String
164
+ * @access private
165
+ */
166
+ var $encryptIV;
167
+
168
+ /**
169
+ * A "sliding" Initialization Vector
170
+ *
171
+ * @see Crypt_Base::enableContinuousBuffer()
172
+ * @see Crypt_Base::_clearBuffers()
173
+ * @var String
174
+ * @access private
175
+ */
176
+ var $decryptIV;
177
+
178
+ /**
179
+ * Continuous Buffer status
180
+ *
181
+ * @see Crypt_Base::enableContinuousBuffer()
182
+ * @var Boolean
183
+ * @access private
184
+ */
185
+ var $continuousBuffer = false;
186
+
187
+ /**
188
+ * Encryption buffer for CTR, OFB and CFB modes
189
+ *
190
+ * @see Crypt_Base::encrypt()
191
+ * @see Crypt_Base::_clearBuffers()
192
+ * @var Array
193
+ * @access private
194
+ */
195
+ var $enbuffer;
196
+
197
+ /**
198
+ * Decryption buffer for CTR, OFB and CFB modes
199
+ *
200
+ * @see Crypt_Base::decrypt()
201
+ * @see Crypt_Base::_clearBuffers()
202
+ * @var Array
203
+ * @access private
204
+ */
205
+ var $debuffer;
206
+
207
+ /**
208
+ * mcrypt resource for encryption
209
+ *
210
+ * The mcrypt resource can be recreated every time something needs to be created or it can be created just once.
211
+ * Since mcrypt operates in continuous mode, by default, it'll need to be recreated when in non-continuous mode.
212
+ *
213
+ * @see Crypt_Base::encrypt()
214
+ * @var Resource
215
+ * @access private
216
+ */
217
+ var $enmcrypt;
218
+
219
+ /**
220
+ * mcrypt resource for decryption
221
+ *
222
+ * The mcrypt resource can be recreated every time something needs to be created or it can be created just once.
223
+ * Since mcrypt operates in continuous mode, by default, it'll need to be recreated when in non-continuous mode.
224
+ *
225
+ * @see Crypt_Base::decrypt()
226
+ * @var Resource
227
+ * @access private
228
+ */
229
+ var $demcrypt;
230
+
231
+ /**
232
+ * Does the enmcrypt resource need to be (re)initialized?
233
+ *
234
+ * @see Crypt_Twofish::setKey()
235
+ * @see Crypt_Twofish::setIV()
236
+ * @var Boolean
237
+ * @access private
238
+ */
239
+ var $enchanged = true;
240
+
241
+ /**
242
+ * Does the demcrypt resource need to be (re)initialized?
243
+ *
244
+ * @see Crypt_Twofish::setKey()
245
+ * @see Crypt_Twofish::setIV()
246
+ * @var Boolean
247
+ * @access private
248
+ */
249
+ var $dechanged = true;
250
+
251
+ /**
252
+ * mcrypt resource for CFB mode
253
+ *
254
+ * mcrypt's CFB mode, in (and only in) buffered context,
255
+ * is broken, so phpseclib implements the CFB mode by it self,
256
+ * even when the mcrypt php extension is available.
257
+ *
258
+ * In order to do the CFB-mode work (fast) phpseclib
259
+ * use a separate ECB-mode mcrypt resource.
260
+ *
261
+ * @link http://phpseclib.sourceforge.net/cfb-demo.phps
262
+ * @see Crypt_Base::encrypt()
263
+ * @see Crypt_Base::decrypt()
264
+ * @see Crypt_Base::_setupMcrypt()
265
+ * @var Resource
266
+ * @access private
267
+ */
268
+ var $ecb;
269
+
270
+ /**
271
+ * Optimizing value while CFB-encrypting
272
+ *
273
+ * Only relevant if $continuousBuffer enabled
274
+ * and $engine == CRYPT_MODE_MCRYPT
275
+ *
276
+ * It's faster to re-init $enmcrypt if
277
+ * $buffer bytes > $cfb_init_len than
278
+ * using the $ecb resource furthermore.
279
+ *
280
+ * This value depends of the chosen cipher
281
+ * and the time it would be needed for it's
282
+ * initialization [by mcrypt_generic_init()]
283
+ * which, typically, depends on the complexity
284
+ * on its internaly Key-expanding algorithm.
285
+ *
286
+ * @see Crypt_Base::encrypt()
287
+ * @var Integer
288
+ * @access private
289
+ */
290
+ var $cfb_init_len = 600;
291
+
292
+ /**
293
+ * Does internal cipher state need to be (re)initialized?
294
+ *
295
+ * @see setKey()
296
+ * @see setIV()
297
+ * @see disableContinuousBuffer()
298
+ * @var Boolean
299
+ * @access private
300
+ */
301
+ var $changed = true;
302
+
303
+ /**
304
+ * Padding status
305
+ *
306
+ * @see Crypt_Base::enablePadding()
307
+ * @var Boolean
308
+ * @access private
309
+ */
310
+ var $padding = true;
311
+
312
+ /**
313
+ * Is the mode one that is paddable?
314
+ *
315
+ * @see Crypt_Base::Crypt_Base()
316
+ * @var Boolean
317
+ * @access private
318
+ */
319
+ var $paddable = false;
320
+
321
+ /**
322
+ * Holds which crypt engine internaly should be use,
323
+ * which will be determined automatically on __construct()
324
+ *
325
+ * Currently available $engines are:
326
+ * - CRYPT_MODE_MCRYPT (fast, php-extension: mcrypt, extension_loaded('mcrypt') required)
327
+ * - CRYPT_MODE_INTERNAL (slower, pure php-engine, no php-extension required)
328
+ *
329
+ * In the pipeline... maybe. But currently not available:
330
+ * - CRYPT_MODE_OPENSSL (very fast, php-extension: openssl, extension_loaded('openssl') required)
331
+ *
332
+ * If possible, CRYPT_MODE_MCRYPT will be used for each cipher.
333
+ * Otherwise CRYPT_MODE_INTERNAL
334
+ *
335
+ * @see Crypt_Base::encrypt()
336
+ * @see Crypt_Base::decrypt()
337
+ * @var Integer
338
+ * @access private
339
+ */
340
+ var $engine;
341
+
342
+ /**
343
+ * The mcrypt specific name of the cipher
344
+ *
345
+ * Only used if $engine == CRYPT_MODE_MCRYPT
346
+ *
347
+ * @link http://www.php.net/mcrypt_module_open
348
+ * @link http://www.php.net/mcrypt_list_algorithms
349
+ * @see Crypt_Base::_setupMcrypt()
350
+ * @var String
351
+ * @access private
352
+ */
353
+ var $cipher_name_mcrypt;
354
+
355
+ /**
356
+ * The default password key_size used by setPassword()
357
+ *
358
+ * @see Crypt_Base::setPassword()
359
+ * @var Integer
360
+ * @access private
361
+ */
362
+ var $password_key_size = 32;
363
+
364
+ /**
365
+ * The default salt used by setPassword()
366
+ *
367
+ * @see Crypt_Base::setPassword()
368
+ * @var String
369
+ * @access private
370
+ */
371
+ var $password_default_salt = 'phpseclib/salt';
372
+
373
+ /**
374
+ * The namespace used by the cipher for its constants.
375
+ *
376
+ * ie: AES.php is using CRYPT_AES_MODE_* for its constants
377
+ * so $const_namespace is AES
378
+ *
379
+ * DES.php is using CRYPT_DES_MODE_* for its constants
380
+ * so $const_namespace is DES... and so on
381
+ *
382
+ * All CRYPT_<$const_namespace>_MODE_* are aliases of
383
+ * the generic CRYPT_MODE_* constants, so both could be used
384
+ * for each cipher.
385
+ *
386
+ * Example:
387
+ * $aes = new Crypt_AES(CRYPT_AES_MODE_CFB); // $aes will operate in cfb mode
388
+ * $aes = new Crypt_AES(CRYPT_MODE_CFB); // identical
389
+ *
390
+ * @see Crypt_Base::Crypt_Base()
391
+ * @var String
392
+ * @access private
393
+ */
394
+ var $const_namespace;
395
+
396
+ /**
397
+ * The name of the performance-optimized callback function
398
+ *
399
+ * Used by encrypt() / decrypt()
400
+ * only if $engine == CRYPT_MODE_INTERNAL
401
+ *
402
+ * @see Crypt_Base::encrypt()
403
+ * @see Crypt_Base::decrypt()
404
+ * @see Crypt_Base::_setupInlineCrypt()
405
+ * @see Crypt_Base::$use_inline_crypt
406
+ * @var Callback
407
+ * @access private
408
+ */
409
+ var $inline_crypt;
410
+
411
+ /**
412
+ * Holds whether performance-optimized $inline_crypt() can/should be used.
413
+ *
414
+ * @see Crypt_Base::encrypt()
415
+ * @see Crypt_Base::decrypt()
416
+ * @see Crypt_Base::inline_crypt
417
+ * @var mixed
418
+ * @access private
419
+ */
420
+ var $use_inline_crypt;
421
+
422
+ /**
423
+ * Default Constructor.
424
+ *
425
+ * Determines whether or not the mcrypt extension should be used.
426
+ *
427
+ * $mode could be:
428
+ *
429
+ * - CRYPT_MODE_ECB
430
+ *
431
+ * - CRYPT_MODE_CBC
432
+ *
433
+ * - CRYPT_MODE_CTR
434
+ *
435
+ * - CRYPT_MODE_CFB
436
+ *
437
+ * - CRYPT_MODE_OFB
438
+ *
439
+ * (or the alias constants of the chosen cipher, for example for AES: CRYPT_AES_MODE_ECB or CRYPT_AES_MODE_CBC ...)
440
+ *
441
+ * If not explicitly set, CRYPT_MODE_CBC will be used.
442
+ *
443
+ * @param optional Integer $mode
444
+ * @access public
445
+ */
446
+ function Crypt_Base($mode = CRYPT_MODE_CBC)
447
+ {
448
+ $const_crypt_mode = 'CRYPT_' . $this->const_namespace . '_MODE';
449
+
450
+ // Determining the availibility of mcrypt support for the cipher
451
+ if (!defined($const_crypt_mode)) {
452
+ switch (true) {
453
+ case extension_loaded('mcrypt') && in_array($this->cipher_name_mcrypt, mcrypt_list_algorithms()):
454
+ define($const_crypt_mode, CRYPT_MODE_MCRYPT);
455
+ break;
456
+ default:
457
+ define($const_crypt_mode, CRYPT_MODE_INTERNAL);
458
+ }
459
+ }
460
+
461
+ // Determining which internal $engine should be used.
462
+ // The fastes possible first.
463
+ switch (true) {
464
+ case empty($this->cipher_name_mcrypt): // The cipher module has no mcrypt-engine support at all so we force CRYPT_MODE_INTERNAL
465
+ $this->engine = CRYPT_MODE_INTERNAL;
466
+ break;
467
+ case constant($const_crypt_mode) == CRYPT_MODE_MCRYPT:
468
+ $this->engine = CRYPT_MODE_MCRYPT;
469
+ break;
470
+ default:
471
+ $this->engine = CRYPT_MODE_INTERNAL;
472
+ }
473
+
474
+ // $mode dependent settings
475
+ switch ($mode) {
476
+ case CRYPT_MODE_ECB:
477
+ $this->paddable = true;
478
+ $this->mode = $mode;
479
+ break;
480
+ case CRYPT_MODE_CTR:
481
+ case CRYPT_MODE_CFB:
482
+ case CRYPT_MODE_OFB:
483
+ case CRYPT_MODE_STREAM:
484
+ $this->mode = $mode;
485
+ break;
486
+ case CRYPT_MODE_CBC:
487
+ default:
488
+ $this->paddable = true;
489
+ $this->mode = CRYPT_MODE_CBC;
490
+ }
491
+
492
+ // Determining whether inline crypting can be used by the cipher
493
+ if ($this->use_inline_crypt !== false && function_exists('create_function')) {
494
+ $this->use_inline_crypt = true;
495
+ }
496
+ }
497
+
498
+ /**
499
+ * Sets the initialization vector. (optional)
500
+ *
501
+ * SetIV is not required when CRYPT_MODE_ECB (or ie for AES: CRYPT_AES_MODE_ECB) is being used. If not explicitly set, it'll be assumed
502
+ * to be all zero's.
503
+ *
504
+ * Note: Could, but not must, extend by the child Crypt_* class
505
+ *
506
+ * @access public
507
+ * @param String $iv
508
+ */
509
+ function setIV($iv)
510
+ {
511
+ if ($this->mode == CRYPT_MODE_ECB) {
512
+ return;
513
+ }
514
+
515
+ $this->iv = $iv;
516
+ $this->changed = true;
517
+ }
518
+
519
+ /**
520
+ * Sets the key.
521
+ *
522
+ * The min/max length(s) of the key depends on the cipher which is used.
523
+ * If the key not fits the length(s) of the cipher it will paded with null bytes
524
+ * up to the closest valid key length. If the key is more than max length,
525
+ * we trim the excess bits.
526
+ *
527
+ * If the key is not explicitly set, it'll be assumed to be all null bytes.
528
+ *
529
+ * Note: Could, but not must, extend by the child Crypt_* class
530
+ *
531
+ * @access public
532
+ * @param String $key
533
+ */
534
+ function setKey($key)
535
+ {
536
+ $this->key = $key;
537
+ $this->changed = true;
538
+ }
539
+
540
+ /**
541
+ * Sets the password.
542
+ *
543
+ * Depending on what $method is set to, setPassword()'s (optional) parameters are as follows:
544
+ * {@link http://en.wikipedia.org/wiki/PBKDF2 pbkdf2} or pbkdf1:
545
+ * $hash, $salt, $count, $dkLen
546
+ *
547
+ * Where $hash (default = sha1) currently supports the following hashes: see: Crypt/Hash.php
548
+ *
549
+ * Note: Could, but not must, extend by the child Crypt_* class
550
+ *
551
+ * @see Crypt/Hash.php
552
+ * @param String $password
553
+ * @param optional String $method
554
+ * @return Boolean
555
+ * @access public
556
+ */
557
+ function setPassword($password, $method = 'pbkdf2')
558
+ {
559
+ $key = '';
560
+
561
+ switch ($method) {
562
+ default: // 'pbkdf2' or 'pbkdf1'
563
+ $func_args = func_get_args();
564
+
565
+ // Hash function
566
+ $hash = isset($func_args[2]) ? $func_args[2] : 'sha1';
567
+
568
+ // WPA and WPA2 use the SSID as the salt
569
+ $salt = isset($func_args[3]) ? $func_args[3] : $this->password_default_salt;
570
+
571
+ // RFC2898#section-4.2 uses 1,000 iterations by default
572
+ // WPA and WPA2 use 4,096.
573
+ $count = isset($func_args[4]) ? $func_args[4] : 1000;
574
+
575
+ // Keylength
576
+ if (isset($func_args[5])) {
577
+ $dkLen = $func_args[5];
578
+ } else {
579
+ $dkLen = $method == 'pbkdf1' ? 2 * $this->password_key_size : $this->password_key_size;
580
+ }
581
+
582
+ switch (true) {
583
+ case $method == 'pbkdf1':
584
+ if (!class_exists('Crypt_Hash')) {
585
+ include_once 'Crypt/Hash.php';
586
+ }
587
+ $hashObj = new Crypt_Hash();
588
+ $hashObj->setHash($hash);
589
+ if ($dkLen > $hashObj->getLength()) {
590
+ user_error('Derived key too long');
591
+ return false;
592
+ }
593
+ $t = $password . $salt;
594
+ for ($i = 0; $i < $count; ++$i) {
595
+ $t = $hashObj->hash($t);
596
+ }
597
+ $key = substr($t, 0, $dkLen);
598
+
599
+ $this->setKey(substr($key, 0, $dkLen >> 1));
600
+ $this->setIV(substr($key, $dkLen >> 1));
601
+
602
+ return true;
603
+ // Determining if php[>=5.5.0]'s hash_pbkdf2() function avail- and useable
604
+ case !function_exists('hash_pbkdf2'):
605
+ case !function_exists('hash_algos'):
606
+ case !in_array($hash, hash_algos()):
607
+ if (!class_exists('Crypt_Hash')) {
608
+ include_once 'Crypt/Hash.php';
609
+ }
610
+ $i = 1;
611
+ while (strlen($key) < $dkLen) {
612
+ $hmac = new Crypt_Hash();
613
+ $hmac->setHash($hash);
614
+ $hmac->setKey($password);
615
+ $f = $u = $hmac->hash($salt . pack('N', $i++));
616
+ for ($j = 2; $j <= $count; ++$j) {
617
+ $u = $hmac->hash($u);
618
+ $f^= $u;
619
+ }
620
+ $key.= $f;
621
+ }
622
+ $key = substr($key, 0, $dkLen);
623
+ break;
624
+ default:
625
+ $key = hash_pbkdf2($hash, $password, $salt, $count, $dkLen, true);
626
+ }
627
+ }
628
+
629
+ $this->setKey($key);
630
+
631
+ return true;
632
+ }
633
+
634
+ /**
635
+ * Encrypts a message.
636
+ *
637
+ * $plaintext will be padded with additional bytes such that it's length is a multiple of the block size. Other cipher
638
+ * implementations may or may not pad in the same manner. Other common approaches to padding and the reasons why it's
639
+ * necessary are discussed in the following
640
+ * URL:
641
+ *
642
+ * {@link http://www.di-mgt.com.au/cryptopad.html http://www.di-mgt.com.au/cryptopad.html}
643
+ *
644
+ * An alternative to padding is to, separately, send the length of the file. This is what SSH, in fact, does.
645
+ * strlen($plaintext) will still need to be a multiple of the block size, however, arbitrary values can be added to make it that
646
+ * length.
647
+ *
648
+ * Note: Could, but not must, extend by the child Crypt_* class
649
+ *
650
+ * @see Crypt_Base::decrypt()
651
+ * @access public
652
+ * @param String $plaintext
653
+ * @return String $cipertext
654
+ */
655
+ function encrypt($plaintext)
656
+ {
657
+ if ($this->engine == CRYPT_MODE_MCRYPT) {
658
+ if ($this->changed) {
659
+ $this->_setupMcrypt();
660
+ $this->changed = false;
661
+ }
662
+ if ($this->enchanged) {
663
+ mcrypt_generic_init($this->enmcrypt, $this->key, $this->encryptIV);
664
+ $this->enchanged = false;
665
+ }
666
+
667
+ // re: {@link http://phpseclib.sourceforge.net/cfb-demo.phps}
668
+ // using mcrypt's default handing of CFB the above would output two different things. using phpseclib's
669
+ // rewritten CFB implementation the above outputs the same thing twice.
670
+ if ($this->mode == CRYPT_MODE_CFB && $this->continuousBuffer) {
671
+ $block_size = $this->block_size;
672
+ $iv = &$this->encryptIV;
673
+ $pos = &$this->enbuffer['pos'];
674
+ $len = strlen($plaintext);
675
+ $ciphertext = '';
676
+ $i = 0;
677
+ if ($pos) {
678
+ $orig_pos = $pos;
679
+ $max = $block_size - $pos;
680
+ if ($len >= $max) {
681
+ $i = $max;
682
+ $len-= $max;
683
+ $pos = 0;
684
+ } else {
685
+ $i = $len;
686
+ $pos+= $len;
687
+ $len = 0;
688
+ }
689
+ $ciphertext = substr($iv, $orig_pos) ^ $plaintext;
690
+ $iv = substr_replace($iv, $ciphertext, $orig_pos, $i);
691
+ $this->enbuffer['enmcrypt_init'] = true;
692
+ }
693
+ if ($len >= $block_size) {
694
+ if ($this->enbuffer['enmcrypt_init'] === false || $len > $this->cfb_init_len) {
695
+ if ($this->enbuffer['enmcrypt_init'] === true) {
696
+ mcrypt_generic_init($this->enmcrypt, $this->key, $iv);
697
+ $this->enbuffer['enmcrypt_init'] = false;
698
+ }
699
+ $ciphertext.= mcrypt_generic($this->enmcrypt, substr($plaintext, $i, $len - $len % $block_size));
700
+ $iv = substr($ciphertext, -$block_size);
701
+ $len%= $block_size;
702
+ } else {
703
+ while ($len >= $block_size) {
704
+ $iv = mcrypt_generic($this->ecb, $iv) ^ substr($plaintext, $i, $block_size);
705
+ $ciphertext.= $iv;
706
+ $len-= $block_size;
707
+ $i+= $block_size;
708
+ }
709
+ }
710
+ }
711
+
712
+ if ($len) {
713
+ $iv = mcrypt_generic($this->ecb, $iv);
714
+ $block = $iv ^ substr($plaintext, -$len);
715
+ $iv = substr_replace($iv, $block, 0, $len);
716
+ $ciphertext.= $block;
717
+ $pos = $len;
718
+ }
719
+
720
+ return $ciphertext;
721
+ }
722
+
723
+ if ($this->paddable) {
724
+ $plaintext = $this->_pad($plaintext);
725
+ }
726
+
727
+ $ciphertext = mcrypt_generic($this->enmcrypt, $plaintext);
728
+
729
+ if (!$this->continuousBuffer) {
730
+ mcrypt_generic_init($this->enmcrypt, $this->key, $this->encryptIV);
731
+ }
732
+
733
+ return $ciphertext;
734
+ }
735
+
736
+ if ($this->changed) {
737
+ $this->_setup();
738
+ $this->changed = false;
739
+ }
740
+ if ($this->use_inline_crypt) {
741
+ $inline = $this->inline_crypt;
742
+ return $inline('encrypt', $this, $plaintext);
743
+ }
744
+ if ($this->paddable) {
745
+ $plaintext = $this->_pad($plaintext);
746
+ }
747
+
748
+ $buffer = &$this->enbuffer;
749
+ $block_size = $this->block_size;
750
+ $ciphertext = '';
751
+ switch ($this->mode) {
752
+ case CRYPT_MODE_ECB:
753
+ for ($i = 0; $i < strlen($plaintext); $i+=$block_size) {
754
+ $ciphertext.= $this->_encryptBlock(substr($plaintext, $i, $block_size));
755
+ }
756
+ break;
757
+ case CRYPT_MODE_CBC:
758
+ $xor = $this->encryptIV;
759
+ for ($i = 0; $i < strlen($plaintext); $i+=$block_size) {
760
+ $block = substr($plaintext, $i, $block_size);
761
+ $block = $this->_encryptBlock($block ^ $xor);
762
+ $xor = $block;
763
+ $ciphertext.= $block;
764
+ }
765
+ if ($this->continuousBuffer) {
766
+ $this->encryptIV = $xor;
767
+ }
768
+ break;
769
+ case CRYPT_MODE_CTR:
770
+ $xor = $this->encryptIV;
771
+ if (strlen($buffer['encrypted'])) {
772
+ for ($i = 0; $i < strlen($plaintext); $i+=$block_size) {
773
+ $block = substr($plaintext, $i, $block_size);
774
+ if (strlen($block) > strlen($buffer['encrypted'])) {
775
+ $buffer['encrypted'].= $this->_encryptBlock($this->_generateXor($xor, $block_size));
776
+ }
777
+ $key = $this->_stringShift($buffer['encrypted'], $block_size);
778
+ $ciphertext.= $block ^ $key;
779
+ }
780
+ } else {
781
+ for ($i = 0; $i < strlen($plaintext); $i+=$block_size) {
782
+ $block = substr($plaintext, $i, $block_size);
783
+ $key = $this->_encryptBlock($this->_generateXor($xor, $block_size));
784
+ $ciphertext.= $block ^ $key;
785
+ }
786
+ }
787
+ if ($this->continuousBuffer) {
788
+ $this->encryptIV = $xor;
789
+ if ($start = strlen($plaintext) % $block_size) {
790
+ $buffer['encrypted'] = substr($key, $start) . $buffer['encrypted'];
791
+ }
792
+ }
793
+ break;
794
+ case CRYPT_MODE_CFB:
795
+ // cfb loosely routines inspired by openssl's:
796
+ // {@link http://cvs.openssl.org/fileview?f=openssl/crypto/modes/cfb128.c&v=1.3.2.2.2.1}
797
+ if ($this->continuousBuffer) {
798
+ $iv = &$this->encryptIV;
799
+ $pos = &$buffer['pos'];
800
+ } else {
801
+ $iv = $this->encryptIV;
802
+ $pos = 0;
803
+ }
804
+ $len = strlen($plaintext);
805
+ $i = 0;
806
+ if ($pos) {
807
+ $orig_pos = $pos;
808
+ $max = $block_size - $pos;
809
+ if ($len >= $max) {
810
+ $i = $max;
811
+ $len-= $max;
812
+ $pos = 0;
813
+ } else {
814
+ $i = $len;
815
+ $pos+= $len;
816
+ $len = 0;
817
+ }
818
+ // ie. $i = min($max, $len), $len-= $i, $pos+= $i, $pos%= $blocksize
819
+ $ciphertext = substr($iv, $orig_pos) ^ $plaintext;
820
+ $iv = substr_replace($iv, $ciphertext, $orig_pos, $i);
821
+ }
822
+ while ($len >= $block_size) {
823
+ $iv = $this->_encryptBlock($iv) ^ substr($plaintext, $i, $block_size);
824
+ $ciphertext.= $iv;
825
+ $len-= $block_size;
826
+ $i+= $block_size;
827
+ }
828
+ if ($len) {
829
+ $iv = $this->_encryptBlock($iv);
830
+ $block = $iv ^ substr($plaintext, $i);
831
+ $iv = substr_replace($iv, $block, 0, $len);
832
+ $ciphertext.= $block;
833
+ $pos = $len;
834
+ }
835
+ break;
836
+ case CRYPT_MODE_OFB:
837
+ $xor = $this->encryptIV;
838
+ if (strlen($buffer['xor'])) {
839
+ for ($i = 0; $i < strlen($plaintext); $i+=$block_size) {
840
+ $block = substr($plaintext, $i, $block_size);
841
+ if (strlen($block) > strlen($buffer['xor'])) {
842
+ $xor = $this->_encryptBlock($xor);
843
+ $buffer['xor'].= $xor;
844
+ }
845
+ $key = $this->_stringShift($buffer['xor'], $block_size);
846
+ $ciphertext.= $block ^ $key;
847
+ }
848
+ } else {
849
+ for ($i = 0; $i < strlen($plaintext); $i+=$block_size) {
850
+ $xor = $this->_encryptBlock($xor);
851
+ $ciphertext.= substr($plaintext, $i, $block_size) ^ $xor;
852
+ }
853
+ $key = $xor;
854
+ }
855
+ if ($this->continuousBuffer) {
856
+ $this->encryptIV = $xor;
857
+ if ($start = strlen($plaintext) % $block_size) {
858
+ $buffer['xor'] = substr($key, $start) . $buffer['xor'];
859
+ }
860
+ }
861
+ break;
862
+ case CRYPT_MODE_STREAM:
863
+ $ciphertext = $this->_encryptBlock($plaintext);
864
+ break;
865
+ }
866
+
867
+ return $ciphertext;
868
+ }
869
+
870
+ /**
871
+ * Decrypts a message.
872
+ *
873
+ * If strlen($ciphertext) is not a multiple of the block size, null bytes will be added to the end of the string until
874
+ * it is.
875
+ *
876
+ * Note: Could, but not must, extend by the child Crypt_* class
877
+ *
878
+ * @see Crypt_Base::encrypt()
879
+ * @access public
880
+ * @param String $ciphertext
881
+ * @return String $plaintext
882
+ */
883
+ function decrypt($ciphertext)
884
+ {
885
+ if ($this->engine == CRYPT_MODE_MCRYPT) {
886
+ $block_size = $this->block_size;
887
+ if ($this->changed) {
888
+ $this->_setupMcrypt();
889
+ $this->changed = false;
890
+ }
891
+ if ($this->dechanged) {
892
+ mcrypt_generic_init($this->demcrypt, $this->key, $this->decryptIV);
893
+ $this->dechanged = false;
894
+ }
895
+
896
+ if ($this->mode == CRYPT_MODE_CFB && $this->continuousBuffer) {
897
+ $iv = &$this->decryptIV;
898
+ $pos = &$this->debuffer['pos'];
899
+ $len = strlen($ciphertext);
900
+ $plaintext = '';
901
+ $i = 0;
902
+ if ($pos) {
903
+ $orig_pos = $pos;
904
+ $max = $block_size - $pos;
905
+ if ($len >= $max) {
906
+ $i = $max;
907
+ $len-= $max;
908
+ $pos = 0;
909
+ } else {
910
+ $i = $len;
911
+ $pos+= $len;
912
+ $len = 0;
913
+ }
914
+ // ie. $i = min($max, $len), $len-= $i, $pos+= $i, $pos%= $blocksize
915
+ $plaintext = substr($iv, $orig_pos) ^ $ciphertext;
916
+ $iv = substr_replace($iv, substr($ciphertext, 0, $i), $orig_pos, $i);
917
+ }
918
+ if ($len >= $block_size) {
919
+ $cb = substr($ciphertext, $i, $len - $len % $block_size);
920
+ $plaintext.= mcrypt_generic($this->ecb, $iv . $cb) ^ $cb;
921
+ $iv = substr($cb, -$block_size);
922
+ $len%= $block_size;
923
+ }
924
+ if ($len) {
925
+ $iv = mcrypt_generic($this->ecb, $iv);
926
+ $plaintext.= $iv ^ substr($ciphertext, -$len);
927
+ $iv = substr_replace($iv, substr($ciphertext, -$len), 0, $len);
928
+ $pos = $len;
929
+ }
930
+
931
+ return $plaintext;
932
+ }
933
+
934
+ if ($this->paddable) {
935
+ // we pad with chr(0) since that's what mcrypt_generic does. to quote from {@link http://www.php.net/function.mcrypt-generic}:
936
+ // "The data is padded with "\0" to make sure the length of the data is n * blocksize."
937
+ $ciphertext = str_pad($ciphertext, strlen($ciphertext) + ($block_size - strlen($ciphertext) % $block_size) % $block_size, chr(0));
938
+ }
939
+
940
+ $plaintext = mdecrypt_generic($this->demcrypt, $ciphertext);
941
+
942
+ if (!$this->continuousBuffer) {
943
+ mcrypt_generic_init($this->demcrypt, $this->key, $this->decryptIV);
944
+ }
945
+
946
+ return $this->paddable ? $this->_unpad($plaintext) : $plaintext;
947
+ }
948
+
949
+ if ($this->changed) {
950
+ $this->_setup();
951
+ $this->changed = false;
952
+ }
953
+ if ($this->use_inline_crypt) {
954
+ $inline = $this->inline_crypt;
955
+ return $inline('decrypt', $this, $ciphertext);
956
+ }
957
+
958
+ $block_size = $this->block_size;
959
+ if ($this->paddable) {
960
+ // we pad with chr(0) since that's what mcrypt_generic does [...]
961
+ $ciphertext = str_pad($ciphertext, strlen($ciphertext) + ($block_size - strlen($ciphertext) % $block_size) % $block_size, chr(0));
962
+ }
963
+
964
+ $buffer = &$this->debuffer;
965
+ $plaintext = '';
966
+ switch ($this->mode) {
967
+ case CRYPT_MODE_ECB:
968
+ for ($i = 0; $i < strlen($ciphertext); $i+=$block_size) {
969
+ $plaintext.= $this->_decryptBlock(substr($ciphertext, $i, $block_size));
970
+ }
971
+ break;
972
+ case CRYPT_MODE_CBC:
973
+ $xor = $this->decryptIV;
974
+ for ($i = 0; $i < strlen($ciphertext); $i+=$block_size) {
975
+ $block = substr($ciphertext, $i, $block_size);
976
+ $plaintext.= $this->_decryptBlock($block) ^ $xor;
977
+ $xor = $block;
978
+ }
979
+ if ($this->continuousBuffer) {
980
+ $this->decryptIV = $xor;
981
+ }
982
+ break;
983
+ case CRYPT_MODE_CTR:
984
+ $xor = $this->decryptIV;
985
+ if (strlen($buffer['ciphertext'])) {
986
+ for ($i = 0; $i < strlen($ciphertext); $i+=$block_size) {
987
+ $block = substr($ciphertext, $i, $block_size);
988
+ if (strlen($block) > strlen($buffer['ciphertext'])) {
989
+ $buffer['ciphertext'].= $this->_encryptBlock($this->_generateXor($xor, $block_size));
990
+ }
991
+ $key = $this->_stringShift($buffer['ciphertext'], $block_size);
992
+ $plaintext.= $block ^ $key;
993
+ }
994
+ } else {
995
+ for ($i = 0; $i < strlen($ciphertext); $i+=$block_size) {
996
+ $block = substr($ciphertext, $i, $block_size);
997
+ $key = $this->_encryptBlock($this->_generateXor($xor, $block_size));
998
+ $plaintext.= $block ^ $key;
999
+ }
1000
+ }
1001
+ if ($this->continuousBuffer) {
1002
+ $this->decryptIV = $xor;
1003
+ if ($start = strlen($ciphertext) % $block_size) {
1004
+ $buffer['ciphertext'] = substr($key, $start) . $buffer['ciphertext'];
1005
+ }
1006
+ }
1007
+ break;
1008
+ case CRYPT_MODE_CFB:
1009
+ if ($this->continuousBuffer) {
1010
+ $iv = &$this->decryptIV;
1011
+ $pos = &$buffer['pos'];
1012
+ } else {
1013
+ $iv = $this->decryptIV;
1014
+ $pos = 0;
1015
+ }
1016
+ $len = strlen($ciphertext);
1017
+ $i = 0;
1018
+ if ($pos) {
1019
+ $orig_pos = $pos;
1020
+ $max = $block_size - $pos;
1021
+ if ($len >= $max) {
1022
+ $i = $max;
1023
+ $len-= $max;
1024
+ $pos = 0;
1025
+ } else {
1026
+ $i = $len;
1027
+ $pos+= $len;
1028
+ $len = 0;
1029
+ }
1030
+ // ie. $i = min($max, $len), $len-= $i, $pos+= $i, $pos%= $blocksize
1031
+ $plaintext = substr($iv, $orig_pos) ^ $ciphertext;
1032
+ $iv = substr_replace($iv, substr($ciphertext, 0, $i), $orig_pos, $i);
1033
+ }
1034
+ while ($len >= $block_size) {
1035
+ $iv = $this->_encryptBlock($iv);
1036
+ $cb = substr($ciphertext, $i, $block_size);
1037
+ $plaintext.= $iv ^ $cb;
1038
+ $iv = $cb;
1039
+ $len-= $block_size;
1040
+ $i+= $block_size;
1041
+ }
1042
+ if ($len) {
1043
+ $iv = $this->_encryptBlock($iv);
1044
+ $plaintext.= $iv ^ substr($ciphertext, $i);
1045
+ $iv = substr_replace($iv, substr($ciphertext, $i), 0, $len);
1046
+ $pos = $len;
1047
+ }
1048
+ break;
1049
+ case CRYPT_MODE_OFB:
1050
+ $xor = $this->decryptIV;
1051
+ if (strlen($buffer['xor'])) {
1052
+ for ($i = 0; $i < strlen($ciphertext); $i+=$block_size) {
1053
+ $block = substr($ciphertext, $i, $block_size);
1054
+ if (strlen($block) > strlen($buffer['xor'])) {
1055
+ $xor = $this->_encryptBlock($xor);
1056
+ $buffer['xor'].= $xor;
1057
+ }
1058
+ $key = $this->_stringShift($buffer['xor'], $block_size);
1059
+ $plaintext.= $block ^ $key;
1060
+ }
1061
+ } else {
1062
+ for ($i = 0; $i < strlen($ciphertext); $i+=$block_size) {
1063
+ $xor = $this->_encryptBlock($xor);
1064
+ $plaintext.= substr($ciphertext, $i, $block_size) ^ $xor;
1065
+ }
1066
+ $key = $xor;
1067
+ }
1068
+ if ($this->continuousBuffer) {
1069
+ $this->decryptIV = $xor;
1070
+ if ($start = strlen($ciphertext) % $block_size) {
1071
+ $buffer['xor'] = substr($key, $start) . $buffer['xor'];
1072
+ }
1073
+ }
1074
+ break;
1075
+ case CRYPT_MODE_STREAM:
1076
+ $plaintext = $this->_decryptBlock($ciphertext);
1077
+ break;
1078
+ }
1079
+ return $this->paddable ? $this->_unpad($plaintext) : $plaintext;
1080
+ }
1081
+
1082
+ /**
1083
+ * Pad "packets".
1084
+ *
1085
+ * Block ciphers working by encrypting between their specified [$this->]block_size at a time
1086
+ * If you ever need to encrypt or decrypt something that isn't of the proper length, it becomes necessary to
1087
+ * pad the input so that it is of the proper length.
1088
+ *
1089
+ * Padding is enabled by default. Sometimes, however, it is undesirable to pad strings. Such is the case in SSH,
1090
+ * where "packets" are padded with random bytes before being encrypted. Unpad these packets and you risk stripping
1091
+ * away characters that shouldn't be stripped away. (SSH knows how many bytes are added because the length is
1092
+ * transmitted separately)
1093
+ *
1094
+ * @see Crypt_Base::disablePadding()
1095
+ * @access public
1096
+ */
1097
+ function enablePadding()
1098
+ {
1099
+ $this->padding = true;
1100
+ }
1101
+
1102
+ /**
1103
+ * Do not pad packets.
1104
+ *
1105
+ * @see Crypt_Base::enablePadding()
1106
+ * @access public
1107
+ */
1108
+ function disablePadding()
1109
+ {
1110
+ $this->padding = false;
1111
+ }
1112
+
1113
+ /**
1114
+ * Treat consecutive "packets" as if they are a continuous buffer.
1115
+ *
1116
+ * Say you have a 32-byte plaintext $plaintext. Using the default behavior, the two following code snippets
1117
+ * will yield different outputs:
1118
+ *
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>
1126
+ *
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:
1129
+ *
1130
+ * <code>
1131
+ * $rijndael->encrypt(substr($plaintext, 0, 16));
1132
+ * echo $rijndael->decrypt($rijndael->encrypt(substr($plaintext, 16, 16)));
1133
+ * </code>
1134
+ * <code>
1135
+ * echo $rijndael->decrypt($rijndael->encrypt(substr($plaintext, 16, 16)));
1136
+ * </code>
1137
+ *
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.
1141
+ *
1142
+ * Put another way, when the continuous buffer is enabled, the state of the Crypt_*() 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.
1146
+ *
1147
+ * Note: Could, but not must, extend by the child Crypt_* class
1148
+ *
1149
+ * @see Crypt_Base::disableContinuousBuffer()
1150
+ * @access public
1151
+ */
1152
+ function enableContinuousBuffer()
1153
+ {
1154
+ if ($this->mode == CRYPT_MODE_ECB) {
1155
+ return;
1156
+ }
1157
+
1158
+ $this->continuousBuffer = true;
1159
+ }
1160
+
1161
+ /**
1162
+ * Treat consecutive packets as if they are a discontinuous buffer.
1163
+ *
1164
+ * The default behavior.
1165
+ *
1166
+ * Note: Could, but not must, extend by the child Crypt_* class
1167
+ *
1168
+ * @see Crypt_Base::enableContinuousBuffer()
1169
+ * @access public
1170
+ */
1171
+ function disableContinuousBuffer()
1172
+ {
1173
+ if ($this->mode == CRYPT_MODE_ECB) {
1174
+ return;
1175
+ }
1176
+ if (!$this->continuousBuffer) {
1177
+ return;
1178
+ }
1179
+
1180
+ $this->continuousBuffer = false;
1181
+ $this->changed = true;
1182
+ }
1183
+
1184
+ /**
1185
+ * Encrypts a block
1186
+ *
1187
+ * Note: Must extend by the child Crypt_* class
1188
+ *
1189
+ * @access private
1190
+ * @param String $in
1191
+ * @return String
1192
+ */
1193
+ function _encryptBlock($in)
1194
+ {
1195
+ user_error((version_compare(PHP_VERSION, '5.0.0', '>=') ? __METHOD__ : __FUNCTION__) . '() must extend by class ' . get_class($this), E_USER_ERROR);
1196
+ }
1197
+
1198
+ /**
1199
+ * Decrypts a block
1200
+ *
1201
+ * Note: Must extend by the child Crypt_* class
1202
+ *
1203
+ * @access private
1204
+ * @param String $in
1205
+ * @return String
1206
+ */
1207
+ function _decryptBlock($in)
1208
+ {
1209
+ user_error((version_compare(PHP_VERSION, '5.0.0', '>=') ? __METHOD__ : __FUNCTION__) . '() must extend by class ' . get_class($this), E_USER_ERROR);
1210
+ }
1211
+
1212
+ /**
1213
+ * Setup the key (expansion)
1214
+ *
1215
+ * Only used if $engine == CRYPT_MODE_INTERNAL
1216
+ *
1217
+ * Note: Must extend by the child Crypt_* class
1218
+ *
1219
+ * @see Crypt_Base::_setup()
1220
+ * @access private
1221
+ */
1222
+ function _setupKey()
1223
+ {
1224
+ user_error((version_compare(PHP_VERSION, '5.0.0', '>=') ? __METHOD__ : __FUNCTION__) . '() must extend by class ' . get_class($this), E_USER_ERROR);
1225
+ }
1226
+
1227
+ /**
1228
+ * Setup the CRYPT_MODE_INTERNAL $engine
1229
+ *
1230
+ * (re)init, if necessary, the internal cipher $engine and flush all $buffers
1231
+ * Used (only) if $engine == CRYPT_MODE_INTERNAL
1232
+ *
1233
+ * _setup() will be called each time if $changed === true
1234
+ * typically this happens when using one or more of following public methods:
1235
+ *
1236
+ * - setKey()
1237
+ *
1238
+ * - setIV()
1239
+ *
1240
+ * - disableContinuousBuffer()
1241
+ *
1242
+ * - First run of encrypt() / decrypt() with no init-settings
1243
+ *
1244
+ * Internally: _setup() is called always before(!) en/decryption.
1245
+ *
1246
+ * Note: Could, but not must, extend by the child Crypt_* class
1247
+ *
1248
+ * @see setKey()
1249
+ * @see setIV()
1250
+ * @see disableContinuousBuffer()
1251
+ * @access private
1252
+ */
1253
+ function _setup()
1254
+ {
1255
+ $this->_clearBuffers();
1256
+ $this->_setupKey();
1257
+
1258
+ if ($this->use_inline_crypt) {
1259
+ $this->_setupInlineCrypt();
1260
+ }
1261
+ }
1262
+
1263
+ /**
1264
+ * Setup the CRYPT_MODE_MCRYPT $engine
1265
+ *
1266
+ * (re)init, if necessary, the (ext)mcrypt resources and flush all $buffers
1267
+ * Used (only) if $engine = CRYPT_MODE_MCRYPT
1268
+ *
1269
+ * _setupMcrypt() will be called each time if $changed === true
1270
+ * typically this happens when using one or more of following public methods:
1271
+ *
1272
+ * - setKey()
1273
+ *
1274
+ * - setIV()
1275
+ *
1276
+ * - disableContinuousBuffer()
1277
+ *
1278
+ * - First run of encrypt() / decrypt()
1279
+ *
1280
+ *
1281
+ * Note: Could, but not must, extend by the child Crypt_* class
1282
+ *
1283
+ * @see setKey()
1284
+ * @see setIV()
1285
+ * @see disableContinuousBuffer()
1286
+ * @access private
1287
+ */
1288
+ function _setupMcrypt()
1289
+ {
1290
+ $this->_clearBuffers();
1291
+ $this->enchanged = $this->dechanged = true;
1292
+
1293
+ if (!isset($this->enmcrypt)) {
1294
+ static $mcrypt_modes = array(
1295
+ CRYPT_MODE_CTR => 'ctr',
1296
+ CRYPT_MODE_ECB => MCRYPT_MODE_ECB,
1297
+ CRYPT_MODE_CBC => MCRYPT_MODE_CBC,
1298
+ CRYPT_MODE_CFB => 'ncfb',
1299
+ CRYPT_MODE_OFB => MCRYPT_MODE_NOFB,
1300
+ CRYPT_MODE_STREAM => MCRYPT_MODE_STREAM,
1301
+ );
1302
+
1303
+ $this->demcrypt = mcrypt_module_open($this->cipher_name_mcrypt, '', $mcrypt_modes[$this->mode], '');
1304
+ $this->enmcrypt = mcrypt_module_open($this->cipher_name_mcrypt, '', $mcrypt_modes[$this->mode], '');
1305
+
1306
+ // we need the $ecb mcrypt resource (only) in MODE_CFB with enableContinuousBuffer()
1307
+ // to workaround mcrypt's broken ncfb implementation in buffered mode
1308
+ // see: {@link http://phpseclib.sourceforge.net/cfb-demo.phps}
1309
+ if ($this->mode == CRYPT_MODE_CFB) {
1310
+ $this->ecb = mcrypt_module_open($this->cipher_name_mcrypt, '', MCRYPT_MODE_ECB, '');
1311
+ }
1312
+
1313
+ } // else should mcrypt_generic_deinit be called?
1314
+
1315
+ if ($this->mode == CRYPT_MODE_CFB) {
1316
+ mcrypt_generic_init($this->ecb, $this->key, str_repeat("\0", $this->block_size));
1317
+ }
1318
+ }
1319
+
1320
+ /**
1321
+ * Pads a string
1322
+ *
1323
+ * Pads a string using the RSA PKCS padding standards so that its length is a multiple of the blocksize.
1324
+ * $this->block_size - (strlen($text) % $this->block_size) bytes are added, each of which is equal to
1325
+ * chr($this->block_size - (strlen($text) % $this->block_size)
1326
+ *
1327
+ * If padding is disabled and $text is not a multiple of the blocksize, the string will be padded regardless
1328
+ * and padding will, hence forth, be enabled.
1329
+ *
1330
+ * @see Crypt_Base::_unpad()
1331
+ * @param String $text
1332
+ * @access private
1333
+ * @return String
1334
+ */
1335
+ function _pad($text)
1336
+ {
1337
+ $length = strlen($text);
1338
+
1339
+ if (!$this->padding) {
1340
+ if ($length % $this->block_size == 0) {
1341
+ return $text;
1342
+ } else {
1343
+ user_error("The plaintext's length ($length) is not a multiple of the block size ({$this->block_size})");
1344
+ $this->padding = true;
1345
+ }
1346
+ }
1347
+
1348
+ $pad = $this->block_size - ($length % $this->block_size);
1349
+
1350
+ return str_pad($text, $length + $pad, chr($pad));
1351
+ }
1352
+
1353
+ /**
1354
+ * Unpads a string.
1355
+ *
1356
+ * If padding is enabled and the reported padding length is invalid the encryption key will be assumed to be wrong
1357
+ * and false will be returned.
1358
+ *
1359
+ * @see Crypt_Base::_pad()
1360
+ * @param String $text
1361
+ * @access private
1362
+ * @return String
1363
+ */
1364
+ function _unpad($text)
1365
+ {
1366
+ if (!$this->padding) {
1367
+ return $text;
1368
+ }
1369
+
1370
+ $length = ord($text[strlen($text) - 1]);
1371
+
1372
+ if (!$length || $length > $this->block_size) {
1373
+ return false;
1374
+ }
1375
+
1376
+ return substr($text, 0, -$length);
1377
+ }
1378
+
1379
+ /**
1380
+ * Clears internal buffers
1381
+ *
1382
+ * Clearing/resetting the internal buffers is done everytime
1383
+ * after disableContinuousBuffer() or on cipher $engine (re)init
1384
+ * ie after setKey() or setIV()
1385
+ *
1386
+ * Note: Could, but not must, extend by the child Crypt_* class
1387
+ *
1388
+ * @access public
1389
+ */
1390
+ function _clearBuffers()
1391
+ {
1392
+ $this->enbuffer = array('encrypted' => '', 'xor' => '', 'pos' => 0, 'enmcrypt_init' => true);
1393
+ $this->debuffer = array('ciphertext' => '', 'xor' => '', 'pos' => 0, 'demcrypt_init' => true);
1394
+
1395
+ // mcrypt's handling of invalid's $iv:
1396
+ // $this->encryptIV = $this->decryptIV = strlen($this->iv) == $this->block_size ? $this->iv : str_repeat("\0", $this->block_size);
1397
+ $this->encryptIV = $this->decryptIV = str_pad(substr($this->iv, 0, $this->block_size), $this->block_size, "\0");
1398
+ }
1399
+
1400
+ /**
1401
+ * String Shift
1402
+ *
1403
+ * Inspired by array_shift
1404
+ *
1405
+ * @param String $string
1406
+ * @param optional Integer $index
1407
+ * @access private
1408
+ * @return String
1409
+ */
1410
+ function _stringShift(&$string, $index = 1)
1411
+ {
1412
+ $substr = substr($string, 0, $index);
1413
+ $string = substr($string, $index);
1414
+ return $substr;
1415
+ }
1416
+
1417
+ /**
1418
+ * Generate CTR XOR encryption key
1419
+ *
1420
+ * Encrypt the output of this and XOR it against the ciphertext / plaintext to get the
1421
+ * plaintext / ciphertext in CTR mode.
1422
+ *
1423
+ * @see Crypt_Base::decrypt()
1424
+ * @see Crypt_Base::encrypt()
1425
+ * @param String $iv
1426
+ * @param Integer $length
1427
+ * @access private
1428
+ * @return String $xor
1429
+ */
1430
+ function _generateXor(&$iv, $length)
1431
+ {
1432
+ $xor = '';
1433
+ $block_size = $this->block_size;
1434
+ $num_blocks = floor(($length + ($block_size - 1)) / $block_size);
1435
+ for ($i = 0; $i < $num_blocks; $i++) {
1436
+ $xor.= $iv;
1437
+ for ($j = 4; $j <= $block_size; $j+= 4) {
1438
+ $temp = substr($iv, -$j, 4);
1439
+ switch ($temp) {
1440
+ case "\xFF\xFF\xFF\xFF":
1441
+ $iv = substr_replace($iv, "\x00\x00\x00\x00", -$j, 4);
1442
+ break;
1443
+ case "\x7F\xFF\xFF\xFF":
1444
+ $iv = substr_replace($iv, "\x80\x00\x00\x00", -$j, 4);
1445
+ break 2;
1446
+ default:
1447
+ extract(unpack('Ncount', $temp));
1448
+ $iv = substr_replace($iv, pack('N', $count + 1), -$j, 4);
1449
+ break 2;
1450
+ }
1451
+ }
1452
+ }
1453
+
1454
+ return $xor;
1455
+ }
1456
+
1457
+ /**
1458
+ * Setup the performance-optimized function for de/encrypt()
1459
+ *
1460
+ * Stores the created (or existing) callback function-name
1461
+ * in $this->inline_crypt
1462
+ *
1463
+ * Internally for phpseclib developers:
1464
+ *
1465
+ * _setupInlineCrypt() would be called only if:
1466
+ *
1467
+ * - $engine == CRYPT_MODE_INTERNAL and
1468
+ *
1469
+ * - $use_inline_crypt === true
1470
+ *
1471
+ * - each time on _setup(), after(!) _setupKey()
1472
+ *
1473
+ *
1474
+ * This ensures that _setupInlineCrypt() has always a
1475
+ * full ready2go initializated internal cipher $engine state
1476
+ * where, for example, the keys allready expanded,
1477
+ * keys/block_size calculated and such.
1478
+ *
1479
+ * It is, each time if called, the responsibility of _setupInlineCrypt():
1480
+ *
1481
+ * - to set $this->inline_crypt to a valid and fully working callback function
1482
+ * as a (faster) replacement for encrypt() / decrypt()
1483
+ *
1484
+ * - NOT to create unlimited callback functions (for memory reasons!)
1485
+ * no matter how often _setupInlineCrypt() would be called. At some
1486
+ * point of amount they must be generic re-useable.
1487
+ *
1488
+ * - the code of _setupInlineCrypt() it self,
1489
+ * and the generated callback code,
1490
+ * must be, in following order:
1491
+ * - 100% safe
1492
+ * - 100% compatible to encrypt()/decrypt()
1493
+ * - using only php5+ features/lang-constructs/php-extensions if
1494
+ * compatibility (down to php4) or fallback is provided
1495
+ * - readable/maintainable/understandable/commented and... not-cryptic-styled-code :-)
1496
+ * - >= 10% faster than encrypt()/decrypt() [which is, by the way,
1497
+ * the reason for the existence of _setupInlineCrypt() :-)]
1498
+ * - memory-nice
1499
+ * - short (as good as possible)
1500
+ *
1501
+ * Note: - _setupInlineCrypt() is using _createInlineCryptFunction() to create the full callback function code.
1502
+ * - In case of using inline crypting, _setupInlineCrypt() must extend by the child Crypt_* class.
1503
+ * - The following variable names are reserved:
1504
+ * - $_* (all variable names prefixed with an underscore)
1505
+ * - $self (object reference to it self. Do not use $this, but $self instead)
1506
+ * - $in (the content of $in has to en/decrypt by the generated code)
1507
+ * - The callback function should not use the 'return' statement, but en/decrypt'ing the content of $in only
1508
+ *
1509
+ *
1510
+ * @see Crypt_Base::_setup()
1511
+ * @see Crypt_Base::_createInlineCryptFunction()
1512
+ * @see Crypt_Base::encrypt()
1513
+ * @see Crypt_Base::decrypt()
1514
+ * @access private
1515
+ */
1516
+ function _setupInlineCrypt()
1517
+ {
1518
+ // If a Crypt_* class providing inline crypting it must extend _setupInlineCrypt()
1519
+
1520
+ // If, for any reason, an extending Crypt_Base() Crypt_* class
1521
+ // not using inline crypting then it must be ensured that: $this->use_inline_crypt = false
1522
+ // ie in the class var declaration of $use_inline_crypt in general for the Crypt_* class,
1523
+ // in the constructor at object instance-time
1524
+ // or, if it's runtime-specific, at runtime
1525
+
1526
+ $this->use_inline_crypt = false;
1527
+ }
1528
+
1529
+ /**
1530
+ * Creates the performance-optimized function for en/decrypt()
1531
+ *
1532
+ * Internally for phpseclib developers:
1533
+ *
1534
+ * _createInlineCryptFunction():
1535
+ *
1536
+ * - merge the $cipher_code [setup'ed by _setupInlineCrypt()]
1537
+ * with the current [$this->]mode of operation code
1538
+ *
1539
+ * - create the $inline function, which called by encrypt() / decrypt()
1540
+ * as its replacement to speed up the en/decryption operations.
1541
+ *
1542
+ * - return the name of the created $inline callback function
1543
+ *
1544
+ * - used to speed up en/decryption
1545
+ *
1546
+ *
1547
+ *
1548
+ * The main reason why can speed up things [up to 50%] this way are:
1549
+ *
1550
+ * - using variables more effective then regular.
1551
+ * (ie no use of expensive arrays but integers $k_0, $k_1 ...
1552
+ * or even, for example, the pure $key[] values hardcoded)
1553
+ *
1554
+ * - avoiding 1000's of function calls of ie _encryptBlock()
1555
+ * but inlining the crypt operations.
1556
+ * in the mode of operation for() loop.
1557
+ *
1558
+ * - full loop unroll the (sometimes key-dependent) rounds
1559
+ * avoiding this way ++$i counters and runtime-if's etc...
1560
+ *
1561
+ * The basic code architectur of the generated $inline en/decrypt()
1562
+ * lambda function, in pseudo php, is:
1563
+ *
1564
+ * <code>
1565
+ * +----------------------------------------------------------------------------------------------+
1566
+ * | callback $inline = create_function: |
1567
+ * | lambda_function_0001_crypt_ECB($action, $text) |
1568
+ * | { |
1569
+ * | INSERT PHP CODE OF: |
1570
+ * | $cipher_code['init_crypt']; // general init code. |
1571
+ * | // ie: $sbox'es declarations used for |
1572
+ * | // encrypt and decrypt'ing. |
1573
+ * | |
1574
+ * | switch ($action) { |
1575
+ * | case 'encrypt': |
1576
+ * | INSERT PHP CODE OF: |
1577
+ * | $cipher_code['init_encrypt']; // encrypt sepcific init code. |
1578
+ * | ie: specified $key or $box |
1579
+ * | declarations for encrypt'ing. |
1580
+ * | |
1581
+ * | foreach ($ciphertext) { |
1582
+ * | $in = $block_size of $ciphertext; |
1583
+ * | |
1584
+ * | INSERT PHP CODE OF: |
1585
+ * | $cipher_code['encrypt_block']; // encrypt's (string) $in, which is always: |
1586
+ * | // strlen($in) == $this->block_size |
1587
+ * | // here comes the cipher algorithm in action |
1588
+ * | // for encryption. |
1589
+ * | // $cipher_code['encrypt_block'] has to |
1590
+ * | // encrypt the content of the $in variable |
1591
+ * | |
1592
+ * | $plaintext .= $in; |
1593
+ * | } |
1594
+ * | return $plaintext; |
1595
+ * | |
1596
+ * | case 'decrypt': |
1597
+ * | INSERT PHP CODE OF: |
1598
+ * | $cipher_code['init_decrypt']; // decrypt sepcific init code |
1599
+ * | ie: specified $key or $box |
1600
+ * | declarations for decrypt'ing. |
1601
+ * | foreach ($plaintext) { |
1602
+ * | $in = $block_size of $plaintext; |
1603
+ * | |
1604
+ * | INSERT PHP CODE OF: |
1605
+ * | $cipher_code['decrypt_block']; // decrypt's (string) $in, which is always |
1606
+ * | // strlen($in) == $this->block_size |
1607
+ * | // here comes the cipher algorithm in action |
1608
+ * | // for decryption. |
1609
+ * | // $cipher_code['decrypt_block'] has to |
1610
+ * | // decrypt the content of the $in variable |
1611
+ * | $ciphertext .= $in; |
1612
+ * | } |
1613
+ * | return $ciphertext; |
1614
+ * | } |
1615
+ * | } |
1616
+ * +----------------------------------------------------------------------------------------------+
1617
+ * </code>
1618
+ *
1619
+ * See also the Crypt_*::_setupInlineCrypt()'s for
1620
+ * productive inline $cipher_code's how they works.
1621
+ *
1622
+ * Structure of:
1623
+ * <code>
1624
+ * $cipher_code = array(
1625
+ * 'init_crypt' => (string) '', // optional
1626
+ * 'init_encrypt' => (string) '', // optional
1627
+ * 'init_decrypt' => (string) '', // optional
1628
+ * 'encrypt_block' => (string) '', // required
1629
+ * 'decrypt_block' => (string) '' // required
1630
+ * );
1631
+ * </code>
1632
+ *
1633
+ * @see Crypt_Base::_setupInlineCrypt()
1634
+ * @see Crypt_Base::encrypt()
1635
+ * @see Crypt_Base::decrypt()
1636
+ * @param Array $cipher_code
1637
+ * @access private
1638
+ * @return String (the name of the created callback function)
1639
+ */
1640
+ function _createInlineCryptFunction($cipher_code)
1641
+ {
1642
+ $block_size = $this->block_size;
1643
+
1644
+ // optional
1645
+ $init_crypt = isset($cipher_code['init_crypt']) ? $cipher_code['init_crypt'] : '';
1646
+ $init_encrypt = isset($cipher_code['init_encrypt']) ? $cipher_code['init_encrypt'] : '';
1647
+ $init_decrypt = isset($cipher_code['init_decrypt']) ? $cipher_code['init_decrypt'] : '';
1648
+ // required
1649
+ $encrypt_block = $cipher_code['encrypt_block'];
1650
+ $decrypt_block = $cipher_code['decrypt_block'];
1651
+
1652
+ // Generating mode of operation inline code,
1653
+ // merged with the $cipher_code algorithm
1654
+ // for encrypt- and decryption.
1655
+ switch ($this->mode) {
1656
+ case CRYPT_MODE_ECB:
1657
+ $encrypt = $init_encrypt . '
1658
+ $_ciphertext = "";
1659
+ $_text = $self->_pad($_text);
1660
+ $_plaintext_len = strlen($_text);
1661
+
1662
+ for ($_i = 0; $_i < $_plaintext_len; $_i+= '.$block_size.') {
1663
+ $in = substr($_text, $_i, '.$block_size.');
1664
+ '.$encrypt_block.'
1665
+ $_ciphertext.= $in;
1666
+ }
1667
+
1668
+ return $_ciphertext;
1669
+ ';
1670
+
1671
+ $decrypt = $init_decrypt . '
1672
+ $_plaintext = "";
1673
+ $_text = str_pad($_text, strlen($_text) + ('.$block_size.' - strlen($_text) % '.$block_size.') % '.$block_size.', chr(0));
1674
+ $_ciphertext_len = strlen($_text);
1675
+
1676
+ for ($_i = 0; $_i < $_ciphertext_len; $_i+= '.$block_size.') {
1677
+ $in = substr($_text, $_i, '.$block_size.');
1678
+ '.$decrypt_block.'
1679
+ $_plaintext.= $in;
1680
+ }
1681
+
1682
+ return $self->_unpad($_plaintext);
1683
+ ';
1684
+ break;
1685
+ case CRYPT_MODE_CTR:
1686
+ $encrypt = $init_encrypt . '
1687
+ $_ciphertext = "";
1688
+ $_plaintext_len = strlen($_text);
1689
+ $_xor = $self->encryptIV;
1690
+ $_buffer = &$self->enbuffer;
1691
+
1692
+ if (strlen($_buffer["encrypted"])) {
1693
+ for ($_i = 0; $_i < $_plaintext_len; $_i+= '.$block_size.') {
1694
+ $_block = substr($_text, $_i, '.$block_size.');
1695
+ if (strlen($_block) > strlen($_buffer["encrypted"])) {
1696
+ $in = $self->_generateXor($_xor, '.$block_size.');
1697
+ '.$encrypt_block.'
1698
+ $_buffer["encrypted"].= $in;
1699
+ }
1700
+ $_key = $self->_stringShift($_buffer["encrypted"], '.$block_size.');
1701
+ $_ciphertext.= $_block ^ $_key;
1702
+ }
1703
+ } else {
1704
+ for ($_i = 0; $_i < $_plaintext_len; $_i+= '.$block_size.') {
1705
+ $_block = substr($_text, $_i, '.$block_size.');
1706
+ $in = $self->_generateXor($_xor, '.$block_size.');
1707
+ '.$encrypt_block.'
1708
+ $_key = $in;
1709
+ $_ciphertext.= $_block ^ $_key;
1710
+ }
1711
+ }
1712
+ if ($self->continuousBuffer) {
1713
+ $self->encryptIV = $_xor;
1714
+ if ($_start = $_plaintext_len % '.$block_size.') {
1715
+ $_buffer["encrypted"] = substr($_key, $_start) . $_buffer["encrypted"];
1716
+ }
1717
+ }
1718
+
1719
+ return $_ciphertext;
1720
+ ';
1721
+
1722
+ $decrypt = $init_encrypt . '
1723
+ $_plaintext = "";
1724
+ $_ciphertext_len = strlen($_text);
1725
+ $_xor = $self->decryptIV;
1726
+ $_buffer = &$self->debuffer;
1727
+
1728
+ if (strlen($_buffer["ciphertext"])) {
1729
+ for ($_i = 0; $_i < $_ciphertext_len; $_i+= '.$block_size.') {
1730
+ $_block = substr($_text, $_i, '.$block_size.');
1731
+ if (strlen($_block) > strlen($_buffer["ciphertext"])) {
1732
+ $in = $self->_generateXor($_xor, '.$block_size.');
1733
+ '.$encrypt_block.'
1734
+ $_buffer["ciphertext"].= $in;
1735
+ }
1736
+ $_key = $self->_stringShift($_buffer["ciphertext"], '.$block_size.');
1737
+ $_plaintext.= $_block ^ $_key;
1738
+ }
1739
+ } else {
1740
+ for ($_i = 0; $_i < $_ciphertext_len; $_i+= '.$block_size.') {
1741
+ $_block = substr($_text, $_i, '.$block_size.');
1742
+ $in = $self->_generateXor($_xor, '.$block_size.');
1743
+ '.$encrypt_block.'
1744
+ $_key = $in;
1745
+ $_plaintext.= $_block ^ $_key;
1746
+ }
1747
+ }
1748
+ if ($self->continuousBuffer) {
1749
+ $self->decryptIV = $_xor;
1750
+ if ($_start = $_ciphertext_len % '.$block_size.') {
1751
+ $_buffer["ciphertext"] = substr($_key, $_start) . $_buffer["ciphertext"];
1752
+ }
1753
+ }
1754
+
1755
+ return $_plaintext;
1756
+ ';
1757
+ break;
1758
+ case CRYPT_MODE_CFB:
1759
+ $encrypt = $init_encrypt . '
1760
+ $_ciphertext = "";
1761
+ $_buffer = &$self->enbuffer;
1762
+
1763
+ if ($self->continuousBuffer) {
1764
+ $_iv = &$self->encryptIV;
1765
+ $_pos = &$_buffer["pos"];
1766
+ } else {
1767
+ $_iv = $self->encryptIV;
1768
+ $_pos = 0;
1769
+ }
1770
+ $_len = strlen($_text);
1771
+ $_i = 0;
1772
+ if ($_pos) {
1773
+ $_orig_pos = $_pos;
1774
+ $_max = '.$block_size.' - $_pos;
1775
+ if ($_len >= $_max) {
1776
+ $_i = $_max;
1777
+ $_len-= $_max;
1778
+ $_pos = 0;
1779
+ } else {
1780
+ $_i = $_len;
1781
+ $_pos+= $_len;
1782
+ $_len = 0;
1783
+ }
1784
+ $_ciphertext = substr($_iv, $_orig_pos) ^ $_text;
1785
+ $_iv = substr_replace($_iv, $_ciphertext, $_orig_pos, $_i);
1786
+ }
1787
+ while ($_len >= '.$block_size.') {
1788
+ $in = $_iv;
1789
+ '.$encrypt_block.';
1790
+ $_iv = $in ^ substr($_text, $_i, '.$block_size.');
1791
+ $_ciphertext.= $_iv;
1792
+ $_len-= '.$block_size.';
1793
+ $_i+= '.$block_size.';
1794
+ }
1795
+ if ($_len) {
1796
+ $in = $_iv;
1797
+ '.$encrypt_block.'
1798
+ $_iv = $in;
1799
+ $_block = $_iv ^ substr($_text, $_i);
1800
+ $_iv = substr_replace($_iv, $_block, 0, $_len);
1801
+ $_ciphertext.= $_block;
1802
+ $_pos = $_len;
1803
+ }
1804
+ return $_ciphertext;
1805
+ ';
1806
+
1807
+ $decrypt = $init_encrypt . '
1808
+ $_plaintext = "";
1809
+ $_buffer = &$self->debuffer;
1810
+
1811
+ if ($self->continuousBuffer) {
1812
+ $_iv = &$self->decryptIV;
1813
+ $_pos = &$_buffer["pos"];
1814
+ } else {
1815
+ $_iv = $self->decryptIV;
1816
+ $_pos = 0;
1817
+ }
1818
+ $_len = strlen($_text);
1819
+ $_i = 0;
1820
+ if ($_pos) {
1821
+ $_orig_pos = $_pos;
1822
+ $_max = '.$block_size.' - $_pos;
1823
+ if ($_len >= $_max) {
1824
+ $_i = $_max;
1825
+ $_len-= $_max;
1826
+ $_pos = 0;
1827
+ } else {
1828
+ $_i = $_len;
1829
+ $_pos+= $_len;
1830
+ $_len = 0;
1831
+ }
1832
+ $_plaintext = substr($_iv, $_orig_pos) ^ $_text;
1833
+ $_iv = substr_replace($_iv, substr($_text, 0, $_i), $_orig_pos, $_i);
1834
+ }
1835
+ while ($_len >= '.$block_size.') {
1836
+ $in = $_iv;
1837
+ '.$encrypt_block.'
1838
+ $_iv = $in;
1839
+ $cb = substr($_text, $_i, '.$block_size.');
1840
+ $_plaintext.= $_iv ^ $cb;
1841
+ $_iv = $cb;
1842
+ $_len-= '.$block_size.';
1843
+ $_i+= '.$block_size.';
1844
+ }
1845
+ if ($_len) {
1846
+ $in = $_iv;
1847
+ '.$encrypt_block.'
1848
+ $_iv = $in;
1849
+ $_plaintext.= $_iv ^ substr($_text, $_i);
1850
+ $_iv = substr_replace($_iv, substr($_text, $_i), 0, $_len);
1851
+ $_pos = $_len;
1852
+ }
1853
+
1854
+ return $_plaintext;
1855
+ ';
1856
+ break;
1857
+ case CRYPT_MODE_OFB:
1858
+ $encrypt = $init_encrypt . '
1859
+ $_ciphertext = "";
1860
+ $_plaintext_len = strlen($_text);
1861
+ $_xor = $self->encryptIV;
1862
+ $_buffer = &$self->enbuffer;
1863
+
1864
+ if (strlen($_buffer["xor"])) {
1865
+ for ($_i = 0; $_i < $_plaintext_len; $_i+= '.$block_size.') {
1866
+ $_block = substr($_text, $_i, '.$block_size.');
1867
+ if (strlen($_block) > strlen($_buffer["xor"])) {
1868
+ $in = $_xor;
1869
+ '.$encrypt_block.'
1870
+ $_xor = $in;
1871
+ $_buffer["xor"].= $_xor;
1872
+ }
1873
+ $_key = $self->_stringShift($_buffer["xor"], '.$block_size.');
1874
+ $_ciphertext.= $_block ^ $_key;
1875
+ }
1876
+ } else {
1877
+ for ($_i = 0; $_i < $_plaintext_len; $_i+= '.$block_size.') {
1878
+ $in = $_xor;
1879
+ '.$encrypt_block.'
1880
+ $_xor = $in;
1881
+ $_ciphertext.= substr($_text, $_i, '.$block_size.') ^ $_xor;
1882
+ }
1883
+ $_key = $_xor;
1884
+ }
1885
+ if ($self->continuousBuffer) {
1886
+ $self->encryptIV = $_xor;
1887
+ if ($_start = $_plaintext_len % '.$block_size.') {
1888
+ $_buffer["xor"] = substr($_key, $_start) . $_buffer["xor"];
1889
+ }
1890
+ }
1891
+ return $_ciphertext;
1892
+ ';
1893
+
1894
+ $decrypt = $init_encrypt . '
1895
+ $_plaintext = "";
1896
+ $_ciphertext_len = strlen($_text);
1897
+ $_xor = $self->decryptIV;
1898
+ $_buffer = &$self->debuffer;
1899
+
1900
+ if (strlen($_buffer["xor"])) {
1901
+ for ($_i = 0; $_i < $_ciphertext_len; $_i+= '.$block_size.') {
1902
+ $_block = substr($_text, $_i, '.$block_size.');
1903
+ if (strlen($_block) > strlen($_buffer["xor"])) {
1904
+ $in = $_xor;
1905
+ '.$encrypt_block.'
1906
+ $_xor = $in;
1907
+ $_buffer["xor"].= $_xor;
1908
+ }
1909
+ $_key = $self->_stringShift($_buffer["xor"], '.$block_size.');
1910
+ $_plaintext.= $_block ^ $_key;
1911
+ }
1912
+ } else {
1913
+ for ($_i = 0; $_i < $_ciphertext_len; $_i+= '.$block_size.') {
1914
+ $in = $_xor;
1915
+ '.$encrypt_block.'
1916
+ $_xor = $in;
1917
+ $_plaintext.= substr($_text, $_i, '.$block_size.') ^ $_xor;
1918
+ }
1919
+ $_key = $_xor;
1920
+ }
1921
+ if ($self->continuousBuffer) {
1922
+ $self->decryptIV = $_xor;
1923
+ if ($_start = $_ciphertext_len % '.$block_size.') {
1924
+ $_buffer["xor"] = substr($_key, $_start) . $_buffer["xor"];
1925
+ }
1926
+ }
1927
+ return $_plaintext;
1928
+ ';
1929
+ break;
1930
+ case CRYPT_MODE_STREAM:
1931
+ $encrypt = $init_encrypt . '
1932
+ $_ciphertext = "";
1933
+ '.$encrypt_block.'
1934
+ return $_ciphertext;
1935
+ ';
1936
+ $decrypt = $init_decrypt . '
1937
+ $_plaintext = "";
1938
+ '.$decrypt_block.'
1939
+ return $_plaintext;
1940
+ ';
1941
+ break;
1942
+ // case CRYPT_MODE_CBC:
1943
+ default:
1944
+ $encrypt = $init_encrypt . '
1945
+ $_ciphertext = "";
1946
+ $_text = $self->_pad($_text);
1947
+ $_plaintext_len = strlen($_text);
1948
+
1949
+ $in = $self->encryptIV;
1950
+
1951
+ for ($_i = 0; $_i < $_plaintext_len; $_i+= '.$block_size.') {
1952
+ $in = substr($_text, $_i, '.$block_size.') ^ $in;
1953
+ '.$encrypt_block.'
1954
+ $_ciphertext.= $in;
1955
+ }
1956
+
1957
+ if ($self->continuousBuffer) {
1958
+ $self->encryptIV = $in;
1959
+ }
1960
+
1961
+ return $_ciphertext;
1962
+ ';
1963
+
1964
+ $decrypt = $init_decrypt . '
1965
+ $_plaintext = "";
1966
+ $_text = str_pad($_text, strlen($_text) + ('.$block_size.' - strlen($_text) % '.$block_size.') % '.$block_size.', chr(0));
1967
+ $_ciphertext_len = strlen($_text);
1968
+
1969
+ $_iv = $self->decryptIV;
1970
+
1971
+ for ($_i = 0; $_i < $_ciphertext_len; $_i+= '.$block_size.') {
1972
+ $in = $_block = substr($_text, $_i, '.$block_size.');
1973
+ '.$decrypt_block.'
1974
+ $_plaintext.= $in ^ $_iv;
1975
+ $_iv = $_block;
1976
+ }
1977
+
1978
+ if ($self->continuousBuffer) {
1979
+ $self->decryptIV = $_iv;
1980
+ }
1981
+
1982
+ return $self->_unpad($_plaintext);
1983
+ ';
1984
+ break;
1985
+ }
1986
+
1987
+ // Create the $inline function and return its name as string. Ready to run!
1988
+ return create_function('$_action, &$self, $_text', $init_crypt . 'if ($_action == "encrypt") { ' . $encrypt . ' } else { ' . $decrypt . ' }');
1989
+ }
1990
+
1991
+ /**
1992
+ * Holds the lambda_functions table (classwide)
1993
+ *
1994
+ * Each name of the lambda function, created from
1995
+ * _setupInlineCrypt() && _createInlineCryptFunction()
1996
+ * is stored, classwide (!), here for reusing.
1997
+ *
1998
+ * The string-based index of $function is a classwide
1999
+ * uniqe value representing, at least, the $mode of
2000
+ * operation (or more... depends of the optimizing level)
2001
+ * for which $mode the lambda function was created.
2002
+ *
2003
+ * @access private
2004
+ * @return &Array
2005
+ */
2006
+ function &_getLambdaFunctions()
2007
+ {
2008
+ static $functions = array();
2009
+ return $functions;
2010
+ }
2011
+ }
phpseclib/Crypt/Blowfish.php ADDED
@@ -0,0 +1,644 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * Pure-PHP implementation of Blowfish.
5
+ *
6
+ * Uses mcrypt, if available, and an internal implementation, otherwise.
7
+ *
8
+ * PHP versions 4 and 5
9
+ *
10
+ * Useful resources are as follows:
11
+ *
12
+ * - {@link http://en.wikipedia.org/wiki/Blowfish_(cipher) Wikipedia description of Blowfish}
13
+ *
14
+ * Here's a short example of how to use this library:
15
+ * <code>
16
+ * <?php
17
+ * include 'Crypt/Blowfish.php';
18
+ *
19
+ * $blowfish = new Crypt_Blowfish();
20
+ *
21
+ * $blowfish->setKey('12345678901234567890123456789012');
22
+ *
23
+ * $plaintext = str_repeat('a', 1024);
24
+ *
25
+ * echo $blowfish->decrypt($blowfish->encrypt($plaintext));
26
+ * ?>
27
+ * </code>
28
+ *
29
+ * LICENSE: Permission is hereby granted, free of charge, to any person obtaining a copy
30
+ * of this software and associated documentation files (the "Software"), to deal
31
+ * in the Software without restriction, including without limitation the rights
32
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
33
+ * copies of the Software, and to permit persons to whom the Software is
34
+ * furnished to do so, subject to the following conditions:
35
+ *
36
+ * The above copyright notice and this permission notice shall be included in
37
+ * all copies or substantial portions of the Software.
38
+ *
39
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
40
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
41
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
42
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
43
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
44
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
45
+ * THE SOFTWARE.
46
+ *
47
+ * @category Crypt
48
+ * @package Crypt_Blowfish
49
+ * @author Jim Wigginton <terrafrost@php.net>
50
+ * @author Hans-Juergen Petrich <petrich@tronic-media.com>
51
+ * @copyright MMVII Jim Wigginton
52
+ * @license http://www.opensource.org/licenses/mit-license.html MIT License
53
+ * @link http://phpseclib.sourceforge.net
54
+ */
55
+
56
+ /**
57
+ * Include Crypt_Base
58
+ *
59
+ * Base cipher class
60
+ */
61
+ if (!class_exists('Crypt_Base')) {
62
+ include_once 'Base.php';
63
+ }
64
+
65
+ /**#@+
66
+ * @access public
67
+ * @see Crypt_Blowfish::encrypt()
68
+ * @see Crypt_Blowfish::decrypt()
69
+ */
70
+ /**
71
+ * Encrypt / decrypt using the Counter mode.
72
+ *
73
+ * Set to -1 since that's what Crypt/Random.php uses to index the CTR mode.
74
+ *
75
+ * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Counter_.28CTR.29
76
+ */
77
+ define('CRYPT_BLOWFISH_MODE_CTR', CRYPT_MODE_CTR);
78
+ /**
79
+ * Encrypt / decrypt using the Electronic Code Book mode.
80
+ *
81
+ * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Electronic_codebook_.28ECB.29
82
+ */
83
+ define('CRYPT_BLOWFISH_MODE_ECB', CRYPT_MODE_ECB);
84
+ /**
85
+ * Encrypt / decrypt using the Code Book Chaining mode.
86
+ *
87
+ * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Cipher-block_chaining_.28CBC.29
88
+ */
89
+ define('CRYPT_BLOWFISH_MODE_CBC', CRYPT_MODE_CBC);
90
+ /**
91
+ * Encrypt / decrypt using the Cipher Feedback mode.
92
+ *
93
+ * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Cipher_feedback_.28CFB.29
94
+ */
95
+ define('CRYPT_BLOWFISH_MODE_CFB', CRYPT_MODE_CFB);
96
+ /**
97
+ * Encrypt / decrypt using the Cipher Feedback mode.
98
+ *
99
+ * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Output_feedback_.28OFB.29
100
+ */
101
+ define('CRYPT_BLOWFISH_MODE_OFB', CRYPT_MODE_OFB);
102
+ /**#@-*/
103
+
104
+ /**#@+
105
+ * @access private
106
+ * @see Crypt_Base::Crypt_Base()
107
+ */
108
+ /**
109
+ * Toggles the internal implementation
110
+ */
111
+ define('CRYPT_BLOWFISH_MODE_INTERNAL', CRYPT_MODE_INTERNAL);
112
+ /**
113
+ * Toggles the mcrypt implementation
114
+ */
115
+ define('CRYPT_BLOWFISH_MODE_MCRYPT', CRYPT_MODE_MCRYPT);
116
+ /**#@-*/
117
+
118
+ /**
119
+ * Pure-PHP implementation of Blowfish.
120
+ *
121
+ * @package Crypt_Blowfish
122
+ * @author Jim Wigginton <terrafrost@php.net>
123
+ * @author Hans-Juergen Petrich <petrich@tronic-media.com>
124
+ * @access public
125
+ */
126
+ class Crypt_Blowfish extends Crypt_Base
127
+ {
128
+ /**
129
+ * Block Length of the cipher
130
+ *
131
+ * @see Crypt_Base::block_size
132
+ * @var Integer
133
+ * @access private
134
+ */
135
+ var $block_size = 8;
136
+
137
+ /**
138
+ * The default password key_size used by setPassword()
139
+ *
140
+ * @see Crypt_Base::password_key_size
141
+ * @see Crypt_Base::setPassword()
142
+ * @var Integer
143
+ * @access private
144
+ */
145
+ var $password_key_size = 56;
146
+
147
+ /**
148
+ * The namespace used by the cipher for its constants.
149
+ *
150
+ * @see Crypt_Base::const_namespace
151
+ * @var String
152
+ * @access private
153
+ */
154
+ var $const_namespace = 'BLOWFISH';
155
+
156
+ /**
157
+ * The mcrypt specific name of the cipher
158
+ *
159
+ * @see Crypt_Base::cipher_name_mcrypt
160
+ * @var String
161
+ * @access private
162
+ */
163
+ var $cipher_name_mcrypt = 'blowfish';
164
+
165
+ /**
166
+ * Optimizing value while CFB-encrypting
167
+ *
168
+ * @see Crypt_Base::cfb_init_len
169
+ * @var Integer
170
+ * @access private
171
+ */
172
+ var $cfb_init_len = 500;
173
+
174
+ /**
175
+ * The fixed subkeys boxes ($sbox0 - $sbox3) with 256 entries each
176
+ *
177
+ * S-Box 1
178
+ *
179
+ * @access private
180
+ * @var array
181
+ */
182
+ var $sbox0 = array (
183
+ 0xd1310ba6, 0x98dfb5ac, 0x2ffd72db, 0xd01adfb7, 0xb8e1afed, 0x6a267e96, 0xba7c9045, 0xf12c7f99,
184
+ 0x24a19947, 0xb3916cf7, 0x0801f2e2, 0x858efc16, 0x636920d8, 0x71574e69, 0xa458fea3, 0xf4933d7e,
185
+ 0x0d95748f, 0x728eb658, 0x718bcd58, 0x82154aee, 0x7b54a41d, 0xc25a59b5, 0x9c30d539, 0x2af26013,
186
+ 0xc5d1b023, 0x286085f0, 0xca417918, 0xb8db38ef, 0x8e79dcb0, 0x603a180e, 0x6c9e0e8b, 0xb01e8a3e,
187
+ 0xd71577c1, 0xbd314b27, 0x78af2fda, 0x55605c60, 0xe65525f3, 0xaa55ab94, 0x57489862, 0x63e81440,
188
+ 0x55ca396a, 0x2aab10b6, 0xb4cc5c34, 0x1141e8ce, 0xa15486af, 0x7c72e993, 0xb3ee1411, 0x636fbc2a,
189
+ 0x2ba9c55d, 0x741831f6, 0xce5c3e16, 0x9b87931e, 0xafd6ba33, 0x6c24cf5c, 0x7a325381, 0x28958677,
190
+ 0x3b8f4898, 0x6b4bb9af, 0xc4bfe81b, 0x66282193, 0x61d809cc, 0xfb21a991, 0x487cac60, 0x5dec8032,
191
+ 0xef845d5d, 0xe98575b1, 0xdc262302, 0xeb651b88, 0x23893e81, 0xd396acc5, 0x0f6d6ff3, 0x83f44239,
192
+ 0x2e0b4482, 0xa4842004, 0x69c8f04a, 0x9e1f9b5e, 0x21c66842, 0xf6e96c9a, 0x670c9c61, 0xabd388f0,
193
+ 0x6a51a0d2, 0xd8542f68, 0x960fa728, 0xab5133a3, 0x6eef0b6c, 0x137a3be4, 0xba3bf050, 0x7efb2a98,
194
+ 0xa1f1651d, 0x39af0176, 0x66ca593e, 0x82430e88, 0x8cee8619, 0x456f9fb4, 0x7d84a5c3, 0x3b8b5ebe,
195
+ 0xe06f75d8, 0x85c12073, 0x401a449f, 0x56c16aa6, 0x4ed3aa62, 0x363f7706, 0x1bfedf72, 0x429b023d,
196
+ 0x37d0d724, 0xd00a1248, 0xdb0fead3, 0x49f1c09b, 0x075372c9, 0x80991b7b, 0x25d479d8, 0xf6e8def7,
197
+ 0xe3fe501a, 0xb6794c3b, 0x976ce0bd, 0x04c006ba, 0xc1a94fb6, 0x409f60c4, 0x5e5c9ec2, 0x196a2463,
198
+ 0x68fb6faf, 0x3e6c53b5, 0x1339b2eb, 0x3b52ec6f, 0x6dfc511f, 0x9b30952c, 0xcc814544, 0xaf5ebd09,
199
+ 0xbee3d004, 0xde334afd, 0x660f2807, 0x192e4bb3, 0xc0cba857, 0x45c8740f, 0xd20b5f39, 0xb9d3fbdb,
200
+ 0x5579c0bd, 0x1a60320a, 0xd6a100c6, 0x402c7279, 0x679f25fe, 0xfb1fa3cc, 0x8ea5e9f8, 0xdb3222f8,
201
+ 0x3c7516df, 0xfd616b15, 0x2f501ec8, 0xad0552ab, 0x323db5fa, 0xfd238760, 0x53317b48, 0x3e00df82,
202
+ 0x9e5c57bb, 0xca6f8ca0, 0x1a87562e, 0xdf1769db, 0xd542a8f6, 0x287effc3, 0xac6732c6, 0x8c4f5573,
203
+ 0x695b27b0, 0xbbca58c8, 0xe1ffa35d, 0xb8f011a0, 0x10fa3d98, 0xfd2183b8, 0x4afcb56c, 0x2dd1d35b,
204
+ 0x9a53e479, 0xb6f84565, 0xd28e49bc, 0x4bfb9790, 0xe1ddf2da, 0xa4cb7e33, 0x62fb1341, 0xcee4c6e8,
205
+ 0xef20cada, 0x36774c01, 0xd07e9efe, 0x2bf11fb4, 0x95dbda4d, 0xae909198, 0xeaad8e71, 0x6b93d5a0,
206
+ 0xd08ed1d0, 0xafc725e0, 0x8e3c5b2f, 0x8e7594b7, 0x8ff6e2fb, 0xf2122b64, 0x8888b812, 0x900df01c,
207
+ 0x4fad5ea0, 0x688fc31c, 0xd1cff191, 0xb3a8c1ad, 0x2f2f2218, 0xbe0e1777, 0xea752dfe, 0x8b021fa1,
208
+ 0xe5a0cc0f, 0xb56f74e8, 0x18acf3d6, 0xce89e299, 0xb4a84fe0, 0xfd13e0b7, 0x7cc43b81, 0xd2ada8d9,
209
+ 0x165fa266, 0x80957705, 0x93cc7314, 0x211a1477, 0xe6ad2065, 0x77b5fa86, 0xc75442f5, 0xfb9d35cf,
210
+ 0xebcdaf0c, 0x7b3e89a0, 0xd6411bd3, 0xae1e7e49, 0x00250e2d, 0x2071b35e, 0x226800bb, 0x57b8e0af,
211
+ 0x2464369b, 0xf009b91e, 0x5563911d, 0x59dfa6aa, 0x78c14389, 0xd95a537f, 0x207d5ba2, 0x02e5b9c5,
212
+ 0x83260376, 0x6295cfa9, 0x11c81968, 0x4e734a41, 0xb3472dca, 0x7b14a94a, 0x1b510052, 0x9a532915,
213
+ 0xd60f573f, 0xbc9bc6e4, 0x2b60a476, 0x81e67400, 0x08ba6fb5, 0x571be91f, 0xf296ec6b, 0x2a0dd915,
214
+ 0xb6636521, 0xe7b9f9b6, 0xff34052e, 0xc5855664, 0x53b02d5d, 0xa99f8fa1, 0x08ba4799, 0x6e85076a
215
+ );
216
+
217
+ /**
218
+ * S-Box 1
219
+ *
220
+ * @access private
221
+ * @var array
222
+ */
223
+ var $sbox1 = array(
224
+ 0x4b7a70e9, 0xb5b32944, 0xdb75092e, 0xc4192623, 0xad6ea6b0, 0x49a7df7d, 0x9cee60b8, 0x8fedb266,
225
+ 0xecaa8c71, 0x699a17ff, 0x5664526c, 0xc2b19ee1, 0x193602a5, 0x75094c29, 0xa0591340, 0xe4183a3e,
226
+ 0x3f54989a, 0x5b429d65, 0x6b8fe4d6, 0x99f73fd6, 0xa1d29c07, 0xefe830f5, 0x4d2d38e6, 0xf0255dc1,
227
+ 0x4cdd2086, 0x8470eb26, 0x6382e9c6, 0x021ecc5e, 0x09686b3f, 0x3ebaefc9, 0x3c971814, 0x6b6a70a1,
228
+ 0x687f3584, 0x52a0e286, 0xb79c5305, 0xaa500737, 0x3e07841c, 0x7fdeae5c, 0x8e7d44ec, 0x5716f2b8,
229
+ 0xb03ada37, 0xf0500c0d, 0xf01c1f04, 0x0200b3ff, 0xae0cf51a, 0x3cb574b2, 0x25837a58, 0xdc0921bd,
230
+ 0xd19113f9, 0x7ca92ff6, 0x94324773, 0x22f54701, 0x3ae5e581, 0x37c2dadc, 0xc8b57634, 0x9af3dda7,
231
+ 0xa9446146, 0x0fd0030e, 0xecc8c73e, 0xa4751e41, 0xe238cd99, 0x3bea0e2f, 0x3280bba1, 0x183eb331,
232
+ 0x4e548b38, 0x4f6db908, 0x6f420d03, 0xf60a04bf, 0x2cb81290, 0x24977c79, 0x5679b072, 0xbcaf89af,
233
+ 0xde9a771f, 0xd9930810, 0xb38bae12, 0xdccf3f2e, 0x5512721f, 0x2e6b7124, 0x501adde6, 0x9f84cd87,
234
+ 0x7a584718, 0x7408da17, 0xbc9f9abc, 0xe94b7d8c, 0xec7aec3a, 0xdb851dfa, 0x63094366, 0xc464c3d2,
235
+ 0xef1c1847, 0x3215d908, 0xdd433b37, 0x24c2ba16, 0x12a14d43, 0x2a65c451, 0x50940002, 0x133ae4dd,
236
+ 0x71dff89e, 0x10314e55, 0x81ac77d6, 0x5f11199b, 0x043556f1, 0xd7a3c76b, 0x3c11183b, 0x5924a509,
237
+ 0xf28fe6ed, 0x97f1fbfa, 0x9ebabf2c, 0x1e153c6e, 0x86e34570, 0xeae96fb1, 0x860e5e0a, 0x5a3e2ab3,
238
+ 0x771fe71c, 0x4e3d06fa, 0x2965dcb9, 0x99e71d0f, 0x803e89d6, 0x5266c825, 0x2e4cc978, 0x9c10b36a,
239
+ 0xc6150eba, 0x94e2ea78, 0xa5fc3c53, 0x1e0a2df4, 0xf2f74ea7, 0x361d2b3d, 0x1939260f, 0x19c27960,
240
+ 0x5223a708, 0xf71312b6, 0xebadfe6e, 0xeac31f66, 0xe3bc4595, 0xa67bc883, 0xb17f37d1, 0x018cff28,
241
+ 0xc332ddef, 0xbe6c5aa5, 0x65582185, 0x68ab9802, 0xeecea50f, 0xdb2f953b, 0x2aef7dad, 0x5b6e2f84,
242
+ 0x1521b628, 0x29076170, 0xecdd4775, 0x619f1510, 0x13cca830, 0xeb61bd96, 0x0334fe1e, 0xaa0363cf,
243
+ 0xb5735c90, 0x4c70a239, 0xd59e9e0b, 0xcbaade14, 0xeecc86bc, 0x60622ca7, 0x9cab5cab, 0xb2f3846e,
244
+ 0x648b1eaf, 0x19bdf0ca, 0xa02369b9, 0x655abb50, 0x40685a32, 0x3c2ab4b3, 0x319ee9d5, 0xc021b8f7,
245
+ 0x9b540b19, 0x875fa099, 0x95f7997e, 0x623d7da8, 0xf837889a, 0x97e32d77, 0x11ed935f, 0x16681281,
246
+ 0x0e358829, 0xc7e61fd6, 0x96dedfa1, 0x7858ba99, 0x57f584a5, 0x1b227263, 0x9b83c3ff, 0x1ac24696,
247
+ 0xcdb30aeb, 0x532e3054, 0x8fd948e4, 0x6dbc3128, 0x58ebf2ef, 0x34c6ffea, 0xfe28ed61, 0xee7c3c73,
248
+ 0x5d4a14d9, 0xe864b7e3, 0x42105d14, 0x203e13e0, 0x45eee2b6, 0xa3aaabea, 0xdb6c4f15, 0xfacb4fd0,
249
+ 0xc742f442, 0xef6abbb5, 0x654f3b1d, 0x41cd2105, 0xd81e799e, 0x86854dc7, 0xe44b476a, 0x3d816250,
250
+ 0xcf62a1f2, 0x5b8d2646, 0xfc8883a0, 0xc1c7b6a3, 0x7f1524c3, 0x69cb7492, 0x47848a0b, 0x5692b285,
251
+ 0x095bbf00, 0xad19489d, 0x1462b174, 0x23820e00, 0x58428d2a, 0x0c55f5ea, 0x1dadf43e, 0x233f7061,
252
+ 0x3372f092, 0x8d937e41, 0xd65fecf1, 0x6c223bdb, 0x7cde3759, 0xcbee7460, 0x4085f2a7, 0xce77326e,
253
+ 0xa6078084, 0x19f8509e, 0xe8efd855, 0x61d99735, 0xa969a7aa, 0xc50c06c2, 0x5a04abfc, 0x800bcadc,
254
+ 0x9e447a2e, 0xc3453484, 0xfdd56705, 0x0e1e9ec9, 0xdb73dbd3, 0x105588cd, 0x675fda79, 0xe3674340,
255
+ 0xc5c43465, 0x713e38d8, 0x3d28f89e, 0xf16dff20, 0x153e21e7, 0x8fb03d4a, 0xe6e39f2b, 0xdb83adf7
256
+ );
257
+
258
+ /**
259
+ * S-Box 2
260
+ *
261
+ * @access private
262
+ * @var array
263
+ */
264
+ var $sbox2 = array(
265
+ 0xe93d5a68, 0x948140f7, 0xf64c261c, 0x94692934, 0x411520f7, 0x7602d4f7, 0xbcf46b2e, 0xd4a20068,
266
+ 0xd4082471, 0x3320f46a, 0x43b7d4b7, 0x500061af, 0x1e39f62e, 0x97244546, 0x14214f74, 0xbf8b8840,
267
+ 0x4d95fc1d, 0x96b591af, 0x70f4ddd3, 0x66a02f45, 0xbfbc09ec, 0x03bd9785, 0x7fac6dd0, 0x31cb8504,
268
+ 0x96eb27b3, 0x55fd3941, 0xda2547e6, 0xabca0a9a, 0x28507825, 0x530429f4, 0x0a2c86da, 0xe9b66dfb,
269
+ 0x68dc1462, 0xd7486900, 0x680ec0a4, 0x27a18dee, 0x4f3ffea2, 0xe887ad8c, 0xb58ce006, 0x7af4d6b6,
270
+ 0xaace1e7c, 0xd3375fec, 0xce78a399, 0x406b2a42, 0x20fe9e35, 0xd9f385b9, 0xee39d7ab, 0x3b124e8b,
271
+ 0x1dc9faf7, 0x4b6d1856, 0x26a36631, 0xeae397b2, 0x3a6efa74, 0xdd5b4332, 0x6841e7f7, 0xca7820fb,
272
+ 0xfb0af54e, 0xd8feb397, 0x454056ac, 0xba489527, 0x55533a3a, 0x20838d87, 0xfe6ba9b7, 0xd096954b,
273
+ 0x55a867bc, 0xa1159a58, 0xcca92963, 0x99e1db33, 0xa62a4a56, 0x3f3125f9, 0x5ef47e1c, 0x9029317c,
274
+ 0xfdf8e802, 0x04272f70, 0x80bb155c, 0x05282ce3, 0x95c11548, 0xe4c66d22, 0x48c1133f, 0xc70f86dc,
275
+ 0x07f9c9ee, 0x41041f0f, 0x404779a4, 0x5d886e17, 0x325f51eb, 0xd59bc0d1, 0xf2bcc18f, 0x41113564,
276
+ 0x257b7834, 0x602a9c60, 0xdff8e8a3, 0x1f636c1b, 0x0e12b4c2, 0x02e1329e, 0xaf664fd1, 0xcad18115,
277
+ 0x6b2395e0, 0x333e92e1, 0x3b240b62, 0xeebeb922, 0x85b2a20e, 0xe6ba0d99, 0xde720c8c, 0x2da2f728,
278
+ 0xd0127845, 0x95b794fd, 0x647d0862, 0xe7ccf5f0, 0x5449a36f, 0x877d48fa, 0xc39dfd27, 0xf33e8d1e,
279
+ 0x0a476341, 0x992eff74, 0x3a6f6eab, 0xf4f8fd37, 0xa812dc60, 0xa1ebddf8, 0x991be14c, 0xdb6e6b0d,
280
+ 0xc67b5510, 0x6d672c37, 0x2765d43b, 0xdcd0e804, 0xf1290dc7, 0xcc00ffa3, 0xb5390f92, 0x690fed0b,
281
+ 0x667b9ffb, 0xcedb7d9c, 0xa091cf0b, 0xd9155ea3, 0xbb132f88, 0x515bad24, 0x7b9479bf, 0x763bd6eb,
282
+ 0x37392eb3, 0xcc115979, 0x8026e297, 0xf42e312d, 0x6842ada7, 0xc66a2b3b, 0x12754ccc, 0x782ef11c,
283
+ 0x6a124237, 0xb79251e7, 0x06a1bbe6, 0x4bfb6350, 0x1a6b1018, 0x11caedfa, 0x3d25bdd8, 0xe2e1c3c9,
284
+ 0x44421659, 0x0a121386, 0xd90cec6e, 0xd5abea2a, 0x64af674e, 0xda86a85f, 0xbebfe988, 0x64e4c3fe,
285
+ 0x9dbc8057, 0xf0f7c086, 0x60787bf8, 0x6003604d, 0xd1fd8346, 0xf6381fb0, 0x7745ae04, 0xd736fccc,
286
+ 0x83426b33, 0xf01eab71, 0xb0804187, 0x3c005e5f, 0x77a057be, 0xbde8ae24, 0x55464299, 0xbf582e61,
287
+ 0x4e58f48f, 0xf2ddfda2, 0xf474ef38, 0x8789bdc2, 0x5366f9c3, 0xc8b38e74, 0xb475f255, 0x46fcd9b9,
288
+ 0x7aeb2661, 0x8b1ddf84, 0x846a0e79, 0x915f95e2, 0x466e598e, 0x20b45770, 0x8cd55591, 0xc902de4c,
289
+ 0xb90bace1, 0xbb8205d0, 0x11a86248, 0x7574a99e, 0xb77f19b6, 0xe0a9dc09, 0x662d09a1, 0xc4324633,
290
+ 0xe85a1f02, 0x09f0be8c, 0x4a99a025, 0x1d6efe10, 0x1ab93d1d, 0x0ba5a4df, 0xa186f20f, 0x2868f169,
291
+ 0xdcb7da83, 0x573906fe, 0xa1e2ce9b, 0x4fcd7f52, 0x50115e01, 0xa70683fa, 0xa002b5c4, 0x0de6d027,
292
+ 0x9af88c27, 0x773f8641, 0xc3604c06, 0x61a806b5, 0xf0177a28, 0xc0f586e0, 0x006058aa, 0x30dc7d62,
293
+ 0x11e69ed7, 0x2338ea63, 0x53c2dd94, 0xc2c21634, 0xbbcbee56, 0x90bcb6de, 0xebfc7da1, 0xce591d76,
294
+ 0x6f05e409, 0x4b7c0188, 0x39720a3d, 0x7c927c24, 0x86e3725f, 0x724d9db9, 0x1ac15bb4, 0xd39eb8fc,
295
+ 0xed545578, 0x08fca5b5, 0xd83d7cd3, 0x4dad0fc4, 0x1e50ef5e, 0xb161e6f8, 0xa28514d9, 0x6c51133c,
296
+ 0x6fd5c7e7, 0x56e14ec4, 0x362abfce, 0xddc6c837, 0xd79a3234, 0x92638212, 0x670efa8e, 0x406000e0
297
+ );
298
+
299
+ /**
300
+ * S-Box 3
301
+ *
302
+ * @access private
303
+ * @var array
304
+ */
305
+ var $sbox3 = array(
306
+ 0x3a39ce37, 0xd3faf5cf, 0xabc27737, 0x5ac52d1b, 0x5cb0679e, 0x4fa33742, 0xd3822740, 0x99bc9bbe,
307
+ 0xd5118e9d, 0xbf0f7315, 0xd62d1c7e, 0xc700c47b, 0xb78c1b6b, 0x21a19045, 0xb26eb1be, 0x6a366eb4,
308
+ 0x5748ab2f, 0xbc946e79, 0xc6a376d2, 0x6549c2c8, 0x530ff8ee, 0x468dde7d, 0xd5730a1d, 0x4cd04dc6,
309
+ 0x2939bbdb, 0xa9ba4650, 0xac9526e8, 0xbe5ee304, 0xa1fad5f0, 0x6a2d519a, 0x63ef8ce2, 0x9a86ee22,
310
+ 0xc089c2b8, 0x43242ef6, 0xa51e03aa, 0x9cf2d0a4, 0x83c061ba, 0x9be96a4d, 0x8fe51550, 0xba645bd6,
311
+ 0x2826a2f9, 0xa73a3ae1, 0x4ba99586, 0xef5562e9, 0xc72fefd3, 0xf752f7da, 0x3f046f69, 0x77fa0a59,
312
+ 0x80e4a915, 0x87b08601, 0x9b09e6ad, 0x3b3ee593, 0xe990fd5a, 0x9e34d797, 0x2cf0b7d9, 0x022b8b51,
313
+ 0x96d5ac3a, 0x017da67d, 0xd1cf3ed6, 0x7c7d2d28, 0x1f9f25cf, 0xadf2b89b, 0x5ad6b472, 0x5a88f54c,
314
+ 0xe029ac71, 0xe019a5e6, 0x47b0acfd, 0xed93fa9b, 0xe8d3c48d, 0x283b57cc, 0xf8d56629, 0x79132e28,
315
+ 0x785f0191, 0xed756055, 0xf7960e44, 0xe3d35e8c, 0x15056dd4, 0x88f46dba, 0x03a16125, 0x0564f0bd,
316
+ 0xc3eb9e15, 0x3c9057a2, 0x97271aec, 0xa93a072a, 0x1b3f6d9b, 0x1e6321f5, 0xf59c66fb, 0x26dcf319,
317
+ 0x7533d928, 0xb155fdf5, 0x03563482, 0x8aba3cbb, 0x28517711, 0xc20ad9f8, 0xabcc5167, 0xccad925f,
318
+ 0x4de81751, 0x3830dc8e, 0x379d5862, 0x9320f991, 0xea7a90c2, 0xfb3e7bce, 0x5121ce64, 0x774fbe32,
319
+ 0xa8b6e37e, 0xc3293d46, 0x48de5369, 0x6413e680, 0xa2ae0810, 0xdd6db224, 0x69852dfd, 0x09072166,
320
+ 0xb39a460a, 0x6445c0dd, 0x586cdecf, 0x1c20c8ae, 0x5bbef7dd, 0x1b588d40, 0xccd2017f, 0x6bb4e3bb,
321
+ 0xdda26a7e, 0x3a59ff45, 0x3e350a44, 0xbcb4cdd5, 0x72eacea8, 0xfa6484bb, 0x8d6612ae, 0xbf3c6f47,
322
+ 0xd29be463, 0x542f5d9e, 0xaec2771b, 0xf64e6370, 0x740e0d8d, 0xe75b1357, 0xf8721671, 0xaf537d5d,
323
+ 0x4040cb08, 0x4eb4e2cc, 0x34d2466a, 0x0115af84, 0xe1b00428, 0x95983a1d, 0x06b89fb4, 0xce6ea048,
324
+ 0x6f3f3b82, 0x3520ab82, 0x011a1d4b, 0x277227f8, 0x611560b1, 0xe7933fdc, 0xbb3a792b, 0x344525bd,
325
+ 0xa08839e1, 0x51ce794b, 0x2f32c9b7, 0xa01fbac9, 0xe01cc87e, 0xbcc7d1f6, 0xcf0111c3, 0xa1e8aac7,
326
+ 0x1a908749, 0xd44fbd9a, 0xd0dadecb, 0xd50ada38, 0x0339c32a, 0xc6913667, 0x8df9317c, 0xe0b12b4f,
327
+ 0xf79e59b7, 0x43f5bb3a, 0xf2d519ff, 0x27d9459c, 0xbf97222c, 0x15e6fc2a, 0x0f91fc71, 0x9b941525,
328
+ 0xfae59361, 0xceb69ceb, 0xc2a86459, 0x12baa8d1, 0xb6c1075e, 0xe3056a0c, 0x10d25065, 0xcb03a442,
329
+ 0xe0ec6e0e, 0x1698db3b, 0x4c98a0be, 0x3278e964, 0x9f1f9532, 0xe0d392df, 0xd3a0342b, 0x8971f21e,
330
+ 0x1b0a7441, 0x4ba3348c, 0xc5be7120, 0xc37632d8, 0xdf359f8d, 0x9b992f2e, 0xe60b6f47, 0x0fe3f11d,
331
+ 0xe54cda54, 0x1edad891, 0xce6279cf, 0xcd3e7e6f, 0x1618b166, 0xfd2c1d05, 0x848fd2c5, 0xf6fb2299,
332
+ 0xf523f357, 0xa6327623, 0x93a83531, 0x56cccd02, 0xacf08162, 0x5a75ebb5, 0x6e163697, 0x88d273cc,
333
+ 0xde966292, 0x81b949d0, 0x4c50901b, 0x71c65614, 0xe6c6c7bd, 0x327a140a, 0x45e1d006, 0xc3f27b9a,
334
+ 0xc9aa53fd, 0x62a80f00, 0xbb25bfe2, 0x35bdd2f6, 0x71126905, 0xb2040222, 0xb6cbcf7c, 0xcd769c2b,
335
+ 0x53113ec0, 0x1640e3d3, 0x38abbd60, 0x2547adf0, 0xba38209c, 0xf746ce76, 0x77afa1c5, 0x20756060,
336
+ 0x85cbfe4e, 0x8ae88dd8, 0x7aaaf9b0, 0x4cf9aa7e, 0x1948c25c, 0x02fb8a8c, 0x01c36ae4, 0xd6ebe1f9,
337
+ 0x90d4f869, 0xa65cdea0, 0x3f09252d, 0xc208e69f, 0xb74e6132, 0xce77e25b, 0x578fdfe3, 0x3ac372e6
338
+ );
339
+
340
+ /**
341
+ * P-Array consists of 18 32-bit subkeys
342
+ *
343
+ * @var array $parray
344
+ * @access private
345
+ */
346
+ var $parray = array(
347
+ 0x243f6a88, 0x85a308d3, 0x13198a2e, 0x03707344, 0xa4093822, 0x299f31d0,
348
+ 0x082efa98, 0xec4e6c89, 0x452821e6, 0x38d01377, 0xbe5466cf, 0x34e90c6c,
349
+ 0xc0ac29b7, 0xc97c50dd, 0x3f84d5b5, 0xb5470917, 0x9216d5d9, 0x8979fb1b
350
+ );
351
+
352
+ /**
353
+ * The BCTX-working Array
354
+ *
355
+ * Holds the expanded key [p] and the key-depended s-boxes [sb]
356
+ *
357
+ * @var array $bctx
358
+ * @access private
359
+ */
360
+ var $bctx;
361
+
362
+ /**
363
+ * Holds the last used key
364
+ *
365
+ * @var Array
366
+ * @access private
367
+ */
368
+ var $kl;
369
+
370
+ /**
371
+ * Sets the key.
372
+ *
373
+ * Keys can be of any length. Blowfish, itself, requires the use of a key between 32 and max. 448-bits long.
374
+ * If the key is less than 32-bits we NOT fill the key to 32bit but let the key as it is to be compatible
375
+ * with mcrypt because mcrypt act this way with blowfish key's < 32 bits.
376
+ *
377
+ * If the key is more than 448-bits, we trim the excess bits.
378
+ *
379
+ * If the key is not explicitly set, or empty, it'll be assumed a 128 bits key to be all null bytes.
380
+ *
381
+ * @access public
382
+ * @see Crypt_Base::setKey()
383
+ * @param String $key
384
+ */
385
+ function setKey($key)
386
+ {
387
+ $keylength = strlen($key);
388
+
389
+ if (!$keylength) {
390
+ $key = "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0";
391
+ } elseif ($keylength > 56) {
392
+ $key = substr($key, 0, 56);
393
+ }
394
+
395
+ parent::setKey($key);
396
+ }
397
+
398
+ /**
399
+ * Setup the key (expansion)
400
+ *
401
+ * @see Crypt_Base::_setupKey()
402
+ * @access private
403
+ */
404
+ function _setupKey()
405
+ {
406
+ if (isset($this->kl['key']) && $this->key === $this->kl['key']) {
407
+ // already expanded
408
+ return;
409
+ }
410
+ $this->kl = array('key' => $this->key);
411
+
412
+ /* key-expanding p[] and S-Box building sb[] */
413
+ $this->bctx = array(
414
+ 'p' => array(),
415
+ 'sb' => array(
416
+ $this->sbox0,
417
+ $this->sbox1,
418
+ $this->sbox2,
419
+ $this->sbox3
420
+ )
421
+ );
422
+
423
+ // unpack binary string in unsigned chars
424
+ $key = array_values(unpack('C*', $this->key));
425
+ $keyl = count($key);
426
+ for ($j = 0, $i = 0; $i < 18; ++$i) {
427
+ // xor P1 with the first 32-bits of the key, xor P2 with the second 32-bits ...
428
+ for ($data = 0, $k = 0; $k < 4; ++$k) {
429
+ $data = ($data << 8) | $key[$j];
430
+ if (++$j >= $keyl) {
431
+ $j = 0;
432
+ }
433
+ }
434
+ $this->bctx['p'][] = $this->parray[$i] ^ $data;
435
+ }
436
+
437
+ // encrypt the zero-string, replace P1 and P2 with the encrypted data,
438
+ // encrypt P3 and P4 with the new P1 and P2, do it with all P-array and subkeys
439
+ $data = "\0\0\0\0\0\0\0\0";
440
+ for ($i = 0; $i < 18; $i += 2) {
441
+ list($l, $r) = array_values(unpack('N*', $data = $this->_encryptBlock($data)));
442
+ $this->bctx['p'][$i ] = $l;
443
+ $this->bctx['p'][$i + 1] = $r;
444
+ }
445
+ for ($i = 0; $i < 4; ++$i) {
446
+ for ($j = 0; $j < 256; $j += 2) {
447
+ list($l, $r) = array_values(unpack('N*', $data = $this->_encryptBlock($data)));
448
+ $this->bctx['sb'][$i][$j ] = $l;
449
+ $this->bctx['sb'][$i][$j + 1] = $r;
450
+ }
451
+ }
452
+ }
453
+
454
+ /**
455
+ * Encrypts a block
456
+ *
457
+ * @access private
458
+ * @param String $in
459
+ * @return String
460
+ */
461
+ function _encryptBlock($in)
462
+ {
463
+ $p = $this->bctx["p"];
464
+ // extract($this->bctx["sb"], EXTR_PREFIX_ALL, "sb"); // slower
465
+ $sb_0 = $this->bctx["sb"][0];
466
+ $sb_1 = $this->bctx["sb"][1];
467
+ $sb_2 = $this->bctx["sb"][2];
468
+ $sb_3 = $this->bctx["sb"][3];
469
+
470
+ $in = unpack("N*", $in);
471
+ $l = $in[1];
472
+ $r = $in[2];
473
+
474
+ for ($i = 0; $i < 16; $i+= 2) {
475
+ $l^= $p[$i];
476
+ $r^= ($sb_0[$l >> 24 & 0xff] +
477
+ $sb_1[$l >> 16 & 0xff] ^
478
+ $sb_2[$l >> 8 & 0xff]) +
479
+ $sb_3[$l & 0xff];
480
+
481
+ $r^= $p[$i + 1];
482
+ $l^= ($sb_0[$r >> 24 & 0xff] +
483
+ $sb_1[$r >> 16 & 0xff] ^
484
+ $sb_2[$r >> 8 & 0xff]) +
485
+ $sb_3[$r & 0xff];
486
+ }
487
+ return pack("N*", $r ^ $p[17], $l ^ $p[16]);
488
+ }
489
+
490
+ /**
491
+ * Decrypts a block
492
+ *
493
+ * @access private
494
+ * @param String $in
495
+ * @return String
496
+ */
497
+ function _decryptBlock($in)
498
+ {
499
+ $p = $this->bctx["p"];
500
+ $sb_0 = $this->bctx["sb"][0];
501
+ $sb_1 = $this->bctx["sb"][1];
502
+ $sb_2 = $this->bctx["sb"][2];
503
+ $sb_3 = $this->bctx["sb"][3];
504
+
505
+ $in = unpack("N*", $in);
506
+ $l = $in[1];
507
+ $r = $in[2];
508
+
509
+ for ($i = 17; $i > 2; $i-= 2) {
510
+ $l^= $p[$i];
511
+ $r^= ($sb_0[$l >> 24 & 0xff] +
512
+ $sb_1[$l >> 16 & 0xff] ^
513
+ $sb_2[$l >> 8 & 0xff]) +
514
+ $sb_3[$l & 0xff];
515
+
516
+ $r^= $p[$i - 1];
517
+ $l^= ($sb_0[$r >> 24 & 0xff] +
518
+ $sb_1[$r >> 16 & 0xff] ^
519
+ $sb_2[$r >> 8 & 0xff]) +
520
+ $sb_3[$r & 0xff];
521
+ }
522
+
523
+ return pack("N*", $r ^ $p[0], $l ^ $p[1]);
524
+ }
525
+
526
+ /**
527
+ * Setup the performance-optimized function for de/encrypt()
528
+ *
529
+ * @see Crypt_Base::_setupInlineCrypt()
530
+ * @access private
531
+ */
532
+ function _setupInlineCrypt()
533
+ {
534
+ $lambda_functions =& Crypt_Blowfish::_getLambdaFunctions();
535
+
536
+ // We create max. 10 hi-optimized code for memory reason. Means: For each $key one ultra fast inline-crypt function.
537
+ // After that, we'll still create very fast optimized code but not the hi-ultimative code, for each $mode one.
538
+ $gen_hi_opt_code = (bool)( count($lambda_functions) < 10);
539
+
540
+ switch (true) {
541
+ case $gen_hi_opt_code:
542
+ $code_hash = md5(str_pad("Crypt_Blowfish, {$this->mode}, ", 32, "\0") . $this->key);
543
+ break;
544
+ default:
545
+ $code_hash = "Crypt_Blowfish, {$this->mode}";
546
+ }
547
+
548
+ if (!isset($lambda_functions[$code_hash])) {
549
+ switch (true) {
550
+ case $gen_hi_opt_code:
551
+ $p = $this->bctx['p'];
552
+ $init_crypt = '
553
+ static $sb_0, $sb_1, $sb_2, $sb_3;
554
+ if (!$sb_0) {
555
+ $sb_0 = $self->bctx["sb"][0];
556
+ $sb_1 = $self->bctx["sb"][1];
557
+ $sb_2 = $self->bctx["sb"][2];
558
+ $sb_3 = $self->bctx["sb"][3];
559
+ }
560
+ ';
561
+ break;
562
+ default:
563
+ $p = array();
564
+ for ($i = 0; $i < 18; ++$i) {
565
+ $p[] = '$p_' . $i;
566
+ }
567
+ $init_crypt = '
568
+ list($sb_0, $sb_1, $sb_2, $sb_3) = $self->bctx["sb"];
569
+ list(' . implode(',', $p) . ') = $self->bctx["p"];
570
+
571
+ ';
572
+ }
573
+
574
+ // Generating encrypt code:
575
+ $encrypt_block = '
576
+ $in = unpack("N*", $in);
577
+ $l = $in[1];
578
+ $r = $in[2];
579
+ ';
580
+ for ($i = 0; $i < 16; $i+= 2) {
581
+ $encrypt_block.= '
582
+ $l^= ' . $p[$i] . ';
583
+ $r^= ($sb_0[$l >> 24 & 0xff] +
584
+ $sb_1[$l >> 16 & 0xff] ^
585
+ $sb_2[$l >> 8 & 0xff]) +
586
+ $sb_3[$l & 0xff];
587
+
588
+ $r^= ' . $p[$i + 1] . ';
589
+ $l^= ($sb_0[$r >> 24 & 0xff] +
590
+ $sb_1[$r >> 16 & 0xff] ^
591
+ $sb_2[$r >> 8 & 0xff]) +
592
+ $sb_3[$r & 0xff];
593
+ ';
594
+ }
595
+ $encrypt_block.= '
596
+ $in = pack("N*",
597
+ $r ^ ' . $p[17] . ',
598
+ $l ^ ' . $p[16] . '
599
+ );
600
+ ';
601
+
602
+ // Generating decrypt code:
603
+ $decrypt_block = '
604
+ $in = unpack("N*", $in);
605
+ $l = $in[1];
606
+ $r = $in[2];
607
+ ';
608
+
609
+ for ($i = 17; $i > 2; $i-= 2) {
610
+ $decrypt_block.= '
611
+ $l^= ' . $p[$i] . ';
612
+ $r^= ($sb_0[$l >> 24 & 0xff] +
613
+ $sb_1[$l >> 16 & 0xff] ^
614
+ $sb_2[$l >> 8 & 0xff]) +
615
+ $sb_3[$l & 0xff];
616
+
617
+ $r^= ' . $p[$i - 1] . ';
618
+ $l^= ($sb_0[$r >> 24 & 0xff] +
619
+ $sb_1[$r >> 16 & 0xff] ^
620
+ $sb_2[$r >> 8 & 0xff]) +
621
+ $sb_3[$r & 0xff];
622
+ ';
623
+ }
624
+
625
+ $decrypt_block.= '
626
+ $in = pack("N*",
627
+ $r ^ ' . $p[0] . ',
628
+ $l ^ ' . $p[1] . '
629
+ );
630
+ ';
631
+
632
+ $lambda_functions[$code_hash] = $this->_createInlineCryptFunction(
633
+ array(
634
+ 'init_crypt' => $init_crypt,
635
+ 'init_encrypt' => '',
636
+ 'init_decrypt' => '',
637
+ 'encrypt_block' => $encrypt_block,
638
+ 'decrypt_block' => $decrypt_block
639
+ )
640
+ );
641
+ }
642
+ $this->inline_crypt = $lambda_functions[$code_hash];
643
+ }
644
+ }
phpseclib/Crypt/DES.php CHANGED
@@ -1,1297 +1,1506 @@
1
- <?php
2
- /* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
3
-
4
- /**
5
- * Pure-PHP implementation of DES.
6
- *
7
- * Uses mcrypt, if available, and an internal implementation, otherwise.
8
- *
9
- * PHP versions 4 and 5
10
- *
11
- * Useful resources are as follows:
12
- *
13
- * - {@link http://en.wikipedia.org/wiki/DES_supplementary_material Wikipedia: DES supplementary material}
14
- * - {@link http://www.itl.nist.gov/fipspubs/fip46-2.htm FIPS 46-2 - (DES), Data Encryption Standard}
15
- * - {@link http://www.cs.eku.edu/faculty/styer/460/Encrypt/JS-DES.html JavaScript DES Example}
16
- *
17
- * Here's a short example of how to use this library:
18
- * <code>
19
- * <?php
20
- * include('Crypt/DES.php');
21
- *
22
- * $des = new Crypt_DES();
23
- *
24
- * $des->setKey('abcdefgh');
25
- *
26
- * $size = 10 * 1024;
27
- * $plaintext = '';
28
- * for ($i = 0; $i < $size; $i++) {
29
- * $plaintext.= 'a';
30
- * }
31
- *
32
- * echo $des->decrypt($des->encrypt($plaintext));
33
- * ?>
34
- * </code>
35
- *
36
- * LICENSE: Permission is hereby granted, free of charge, to any person obtaining a copy
37
- * of this software and associated documentation files (the "Software"), to deal
38
- * in the Software without restriction, including without limitation the rights
39
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
40
- * copies of the Software, and to permit persons to whom the Software is
41
- * furnished to do so, subject to the following conditions:
42
- *
43
- * The above copyright notice and this permission notice shall be included in
44
- * all copies or substantial portions of the Software.
45
- *
46
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
47
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
48
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
49
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
50
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
51
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
52
- * THE SOFTWARE.
53
- *
54
- * @category Crypt
55
- * @package Crypt_DES
56
- * @author Jim Wigginton <terrafrost@php.net>
57
- * @copyright MMVII Jim Wigginton
58
- * @license http://www.opensource.org/licenses/mit-license.html MIT License
59
- * @version $Id: DES.php,v 1.12 2010/02/09 06:10:26 terrafrost Exp $
60
- * @link http://phpseclib.sourceforge.net
61
- */
62
-
63
- /**#@+
64
- * @access private
65
- * @see Crypt_DES::_prepareKey()
66
- * @see Crypt_DES::_processBlock()
67
- */
68
- /**
69
- * Contains array_reverse($keys[CRYPT_DES_DECRYPT])
70
- */
71
- define('CRYPT_DES_ENCRYPT', 0);
72
- /**
73
- * Contains array_reverse($keys[CRYPT_DES_ENCRYPT])
74
- */
75
- define('CRYPT_DES_DECRYPT', 1);
76
- /**#@-*/
77
-
78
- /**#@+
79
- * @access public
80
- * @see Crypt_DES::encrypt()
81
- * @see Crypt_DES::decrypt()
82
- */
83
- /**
84
- * Encrypt / decrypt using the Counter mode.
85
- *
86
- * Set to -1 since that's what Crypt/Random.php uses to index the CTR mode.
87
- *
88
- * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Counter_.28CTR.29
89
- */
90
- define('CRYPT_DES_MODE_CTR', -1);
91
- /**
92
- * Encrypt / decrypt using the Electronic Code Book mode.
93
- *
94
- * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Electronic_codebook_.28ECB.29
95
- */
96
- define('CRYPT_DES_MODE_ECB', 1);
97
- /**
98
- * Encrypt / decrypt using the Code Book Chaining mode.
99
- *
100
- * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Cipher-block_chaining_.28CBC.29
101
- */
102
- define('CRYPT_DES_MODE_CBC', 2);
103
- /**
104
- * Encrypt / decrypt using the Cipher Feedback mode.
105
- *
106
- * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Cipher_feedback_.28CFB.29
107
- */
108
- define('CRYPT_DES_MODE_CFB', 3);
109
- /**
110
- * Encrypt / decrypt using the Cipher Feedback mode.
111
- *
112
- * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Output_feedback_.28OFB.29
113
- */
114
- define('CRYPT_DES_MODE_OFB', 4);
115
- /**#@-*/
116
-
117
- /**#@+
118
- * @access private
119
- * @see Crypt_DES::Crypt_DES()
120
- */
121
- /**
122
- * Toggles the internal implementation
123
- */
124
- define('CRYPT_DES_MODE_INTERNAL', 1);
125
- /**
126
- * Toggles the mcrypt implementation
127
- */
128
- define('CRYPT_DES_MODE_MCRYPT', 2);
129
- /**#@-*/
130
-
131
- /**
132
- * Pure-PHP implementation of DES.
133
- *
134
- * @author Jim Wigginton <terrafrost@php.net>
135
- * @version 0.1.0
136
- * @access public
137
- * @package Crypt_DES
138
- */
139
- class Crypt_DES {
140
- /**
141
- * The Key Schedule
142
- *
143
- * @see Crypt_DES::setKey()
144
- * @var Array
145
- * @access private
146
- */
147
- var $keys = "\0\0\0\0\0\0\0\0";
148
-
149
- /**
150
- * The Encryption Mode
151
- *
152
- * @see Crypt_DES::Crypt_DES()
153
- * @var Integer
154
- * @access private
155
- */
156
- var $mode;
157
-
158
- /**
159
- * Continuous Buffer status
160
- *
161
- * @see Crypt_DES::enableContinuousBuffer()
162
- * @var Boolean
163
- * @access private
164
- */
165
- var $continuousBuffer = false;
166
-
167
- /**
168
- * Padding status
169
- *
170
- * @see Crypt_DES::enablePadding()
171
- * @var Boolean
172
- * @access private
173
- */
174
- var $padding = true;
175
-
176
- /**
177
- * The Initialization Vector
178
- *
179
- * @see Crypt_DES::setIV()
180
- * @var String
181
- * @access private
182
- */
183
- var $iv = "\0\0\0\0\0\0\0\0";
184
-
185
- /**
186
- * A "sliding" Initialization Vector
187
- *
188
- * @see Crypt_DES::enableContinuousBuffer()
189
- * @var String
190
- * @access private
191
- */
192
- var $encryptIV = "\0\0\0\0\0\0\0\0";
193
-
194
- /**
195
- * A "sliding" Initialization Vector
196
- *
197
- * @see Crypt_DES::enableContinuousBuffer()
198
- * @var String
199
- * @access private
200
- */
201
- var $decryptIV = "\0\0\0\0\0\0\0\0";
202
-
203
- /**
204
- * mcrypt resource for encryption
205
- *
206
- * The mcrypt resource can be recreated every time something needs to be created or it can be created just once.
207
- * Since mcrypt operates in continuous mode, by default, it'll need to be recreated when in non-continuous mode.
208
- *
209
- * @see Crypt_DES::encrypt()
210
- * @var String
211
- * @access private
212
- */
213
- var $enmcrypt;
214
-
215
- /**
216
- * mcrypt resource for decryption
217
- *
218
- * The mcrypt resource can be recreated every time something needs to be created or it can be created just once.
219
- * Since mcrypt operates in continuous mode, by default, it'll need to be recreated when in non-continuous mode.
220
- *
221
- * @see Crypt_DES::decrypt()
222
- * @var String
223
- * @access private
224
- */
225
- var $demcrypt;
226
-
227
- /**
228
- * Does the enmcrypt resource need to be (re)initialized?
229
- *
230
- * @see Crypt_DES::setKey()
231
- * @see Crypt_DES::setIV()
232
- * @var Boolean
233
- * @access private
234
- */
235
- var $enchanged = true;
236
-
237
- /**
238
- * Does the demcrypt resource need to be (re)initialized?
239
- *
240
- * @see Crypt_DES::setKey()
241
- * @see Crypt_DES::setIV()
242
- * @var Boolean
243
- * @access private
244
- */
245
- var $dechanged = true;
246
-
247
- /**
248
- * Is the mode one that is paddable?
249
- *
250
- * @see Crypt_DES::Crypt_DES()
251
- * @var Boolean
252
- * @access private
253
- */
254
- var $paddable = false;
255
-
256
- /**
257
- * Encryption buffer for CTR, OFB and CFB modes
258
- *
259
- * @see Crypt_DES::encrypt()
260
- * @var String
261
- * @access private
262
- */
263
- var $enbuffer = '';
264
-
265
- /**
266
- * Decryption buffer for CTR, OFB and CFB modes
267
- *
268
- * @see Crypt_DES::decrypt()
269
- * @var String
270
- * @access private
271
- */
272
- var $debuffer = '';
273
-
274
- /**
275
- * mcrypt resource for CFB mode
276
- *
277
- * @see Crypt_DES::encrypt()
278
- * @see Crypt_DES::decrypt()
279
- * @var String
280
- * @access private
281
- */
282
- var $ecb;
283
-
284
- /**
285
- * Default Constructor.
286
- *
287
- * Determines whether or not the mcrypt extension should be used. $mode should only, at present, be
288
- * CRYPT_DES_MODE_ECB or CRYPT_DES_MODE_CBC. If not explictly set, CRYPT_DES_MODE_CBC will be used.
289
- *
290
- * @param optional Integer $mode
291
- * @return Crypt_DES
292
- * @access public
293
- */
294
- function Crypt_DES($mode = CRYPT_DES_MODE_CBC)
295
- {
296
- if ( !defined('CRYPT_DES_MODE') ) {
297
- switch (true) {
298
- case extension_loaded('mcrypt') && in_array('des', mcrypt_list_algorithms()):
299
- define('CRYPT_DES_MODE', CRYPT_DES_MODE_MCRYPT);
300
- break;
301
- default:
302
- define('CRYPT_DES_MODE', CRYPT_DES_MODE_INTERNAL);
303
- }
304
- }
305
-
306
- switch ( CRYPT_DES_MODE ) {
307
- case CRYPT_DES_MODE_MCRYPT:
308
- switch ($mode) {
309
- case CRYPT_DES_MODE_ECB:
310
- $this->paddable = true;
311
- $this->mode = MCRYPT_MODE_ECB;
312
- break;
313
- case CRYPT_DES_MODE_CTR:
314
- $this->mode = 'ctr';
315
- //$this->mode = in_array('ctr', mcrypt_list_modes()) ? 'ctr' : CRYPT_DES_MODE_CTR;
316
- break;
317
- case CRYPT_DES_MODE_CFB:
318
- $this->mode = 'ncfb';
319
- break;
320
- case CRYPT_DES_MODE_OFB:
321
- $this->mode = MCRYPT_MODE_NOFB;
322
- break;
323
- case CRYPT_DES_MODE_CBC:
324
- default:
325
- $this->paddable = true;
326
- $this->mode = MCRYPT_MODE_CBC;
327
- }
328
-
329
- break;
330
- default:
331
- switch ($mode) {
332
- case CRYPT_DES_MODE_ECB:
333
- case CRYPT_DES_MODE_CBC:
334
- $this->paddable = true;
335
- $this->mode = $mode;
336
- break;
337
- case CRYPT_DES_MODE_CTR:
338
- case CRYPT_DES_MODE_CFB:
339
- case CRYPT_DES_MODE_OFB:
340
- $this->mode = $mode;
341
- break;
342
- default:
343
- $this->paddable = true;
344
- $this->mode = CRYPT_DES_MODE_CBC;
345
- }
346
- }
347
- }
348
-
349
- /**
350
- * Sets the key.
351
- *
352
- * Keys can be of any length. DES, itself, uses 64-bit keys (eg. strlen($key) == 8), however, we
353
- * only use the first eight, if $key has more then eight characters in it, and pad $key with the
354
- * null byte if it is less then eight characters long.
355
- *
356
- * DES also requires that every eighth bit be a parity bit, however, we'll ignore that.
357
- *
358
- * If the key is not explicitly set, it'll be assumed to be all zero's.
359
- *
360
- * @access public
361
- * @param String $key
362
- */
363
- function setKey($key)
364
- {
365
- $this->keys = ( CRYPT_DES_MODE == CRYPT_DES_MODE_MCRYPT ) ? str_pad(substr($key, 0, 8), 8, chr(0)) : $this->_prepareKey($key);
366
- $this->changed = true;
367
- }
368
-
369
- /**
370
- * Sets the password.
371
- *
372
- * Depending on what $method is set to, setPassword()'s (optional) parameters are as follows:
373
- * {@link http://en.wikipedia.org/wiki/PBKDF2 pbkdf2}:
374
- * $hash, $salt, $count
375
- *
376
- * @param String $password
377
- * @param optional String $method
378
- * @access public
379
- */
380
- function setPassword($password, $method = 'pbkdf2')
381
- {
382
- $key = '';
383
-
384
- switch ($method) {
385
- default: // 'pbkdf2'
386
- list(, , $hash, $salt, $count) = func_get_args();
387
- if (!isset($hash)) {
388
- $hash = 'sha1';
389
- }
390
- // WPA and WPA use the SSID as the salt
391
- if (!isset($salt)) {
392
- $salt = 'phpseclib/salt';
393
- }
394
- // RFC2898#section-4.2 uses 1,000 iterations by default
395
- // WPA and WPA2 use 4,096.
396
- if (!isset($count)) {
397
- $count = 1000;
398
- }
399
-
400
- if (!class_exists('Crypt_Hash')) {
401
- require_once('Crypt/Hash.php');
402
- }
403
-
404
- $i = 1;
405
- while (strlen($key) < 8) { // $dkLen == 8
406
- //$dk.= $this->_pbkdf($password, $salt, $count, $i++);
407
- $hmac = new Crypt_Hash();
408
- $hmac->setHash($hash);
409
- $hmac->setKey($password);
410
- $f = $u = $hmac->hash($salt . pack('N', $i++));
411
- for ($j = 2; $j <= $count; $j++) {
412
- $u = $hmac->hash($u);
413
- $f^= $u;
414
- }
415
- $key.= $f;
416
- }
417
- }
418
-
419
- $this->setKey($key);
420
- }
421
-
422
- /**
423
- * Sets the initialization vector. (optional)
424
- *
425
- * SetIV is not required when CRYPT_DES_MODE_ECB is being used. If not explictly set, it'll be assumed
426
- * to be all zero's.
427
- *
428
- * @access public
429
- * @param String $iv
430
- */
431
- function setIV($iv)
432
- {
433
- $this->encryptIV = $this->decryptIV = $this->iv = str_pad(substr($iv, 0, 8), 8, chr(0));
434
- $this->changed = true;
435
- }
436
-
437
- /**
438
- * Generate CTR XOR encryption key
439
- *
440
- * Encrypt the output of this and XOR it against the ciphertext / plaintext to get the
441
- * plaintext / ciphertext in CTR mode.
442
- *
443
- * @see Crypt_DES::decrypt()
444
- * @see Crypt_DES::encrypt()
445
- * @access public
446
- * @param Integer $length
447
- * @param String $iv
448
- */
449
- function _generate_xor($length, &$iv)
450
- {
451
- $xor = '';
452
- $num_blocks = ($length + 7) >> 3;
453
- for ($i = 0; $i < $num_blocks; $i++) {
454
- $xor.= $iv;
455
- for ($j = 4; $j <= 8; $j+=4) {
456
- $temp = substr($iv, -$j, 4);
457
- switch ($temp) {
458
- case "\xFF\xFF\xFF\xFF":
459
- $iv = substr_replace($iv, "\x00\x00\x00\x00", -$j, 4);
460
- break;
461
- case "\x7F\xFF\xFF\xFF":
462
- $iv = substr_replace($iv, "\x80\x00\x00\x00", -$j, 4);
463
- break 2;
464
- default:
465
- extract(unpack('Ncount', $temp));
466
- $iv = substr_replace($iv, pack('N', $count + 1), -$j, 4);
467
- break 2;
468
- }
469
- }
470
- }
471
-
472
- return $xor;
473
- }
474
-
475
- /**
476
- * Encrypts a message.
477
- *
478
- * $plaintext will be padded with up to 8 additional bytes. Other DES implementations may or may not pad in the
479
- * same manner. Other common approaches to padding and the reasons why it's necessary are discussed in the following
480
- * URL:
481
- *
482
- * {@link http://www.di-mgt.com.au/cryptopad.html http://www.di-mgt.com.au/cryptopad.html}
483
- *
484
- * An alternative to padding is to, separately, send the length of the file. This is what SSH, in fact, does.
485
- * strlen($plaintext) will still need to be a multiple of 8, however, arbitrary values can be added to make it that
486
- * length.
487
- *
488
- * @see Crypt_DES::decrypt()
489
- * @access public
490
- * @param String $plaintext
491
- */
492
- function encrypt($plaintext)
493
- {
494
- if ($this->paddable) {
495
- $plaintext = $this->_pad($plaintext);
496
- }
497
-
498
- if ( CRYPT_DES_MODE == CRYPT_DES_MODE_MCRYPT ) {
499
- if ($this->enchanged) {
500
- if (!isset($this->enmcrypt)) {
501
- $this->enmcrypt = mcrypt_module_open(MCRYPT_DES, '', $this->mode, '');
502
- }
503
- mcrypt_generic_init($this->enmcrypt, $this->keys, $this->encryptIV);
504
- if ($this->mode != 'ncfb') {
505
- $this->enchanged = false;
506
- }
507
- }
508
-
509
- if ($this->mode != 'ncfb') {
510
- $ciphertext = mcrypt_generic($this->enmcrypt, $plaintext);
511
- } else {
512
- if ($this->enchanged) {
513
- $this->ecb = mcrypt_module_open(MCRYPT_DES, '', MCRYPT_MODE_ECB, '');
514
- mcrypt_generic_init($this->ecb, $this->keys, "\0\0\0\0\0\0\0\0");
515
- $this->enchanged = false;
516
- }
517
-
518
- if (strlen($this->enbuffer)) {
519
- $ciphertext = $plaintext ^ substr($this->encryptIV, strlen($this->enbuffer));
520
- $this->enbuffer.= $ciphertext;
521
- if (strlen($this->enbuffer) == 8) {
522
- $this->encryptIV = $this->enbuffer;
523
- $this->enbuffer = '';
524
- mcrypt_generic_init($this->enmcrypt, $this->keys, $this->encryptIV);
525
- }
526
- $plaintext = substr($plaintext, strlen($ciphertext));
527
- } else {
528
- $ciphertext = '';
529
- }
530
-
531
- $last_pos = strlen($plaintext) & 0xFFFFFFF8;
532
- $ciphertext.= $last_pos ? mcrypt_generic($this->enmcrypt, substr($plaintext, 0, $last_pos)) : '';
533
-
534
- if (strlen($plaintext) & 0x7) {
535
- if (strlen($ciphertext)) {
536
- $this->encryptIV = substr($ciphertext, -8);
537
- }
538
- $this->encryptIV = mcrypt_generic($this->ecb, $this->encryptIV);
539
- $this->enbuffer = substr($plaintext, $last_pos) ^ $this->encryptIV;
540
- $ciphertext.= $this->enbuffer;
541
- }
542
- }
543
-
544
- if (!$this->continuousBuffer) {
545
- mcrypt_generic_init($this->enmcrypt, $this->keys, $this->encryptIV);
546
- }
547
-
548
- return $ciphertext;
549
- }
550
-
551
- if (!is_array($this->keys)) {
552
- $this->keys = $this->_prepareKey("\0\0\0\0\0\0\0\0");
553
- }
554
-
555
- $buffer = &$this->enbuffer;
556
- $continuousBuffer = $this->continuousBuffer;
557
- $ciphertext = '';
558
- switch ($this->mode) {
559
- case CRYPT_DES_MODE_ECB:
560
- for ($i = 0; $i < strlen($plaintext); $i+=8) {
561
- $ciphertext.= $this->_processBlock(substr($plaintext, $i, 8), CRYPT_DES_ENCRYPT);
562
- }
563
- break;
564
- case CRYPT_DES_MODE_CBC:
565
- $xor = $this->encryptIV;
566
- for ($i = 0; $i < strlen($plaintext); $i+=8) {
567
- $block = substr($plaintext, $i, 8);
568
- $block = $this->_processBlock($block ^ $xor, CRYPT_DES_ENCRYPT);
569
- $xor = $block;
570
- $ciphertext.= $block;
571
- }
572
- if ($this->continuousBuffer) {
573
- $this->encryptIV = $xor;
574
- }
575
- break;
576
- case CRYPT_DES_MODE_CTR:
577
- $xor = $this->encryptIV;
578
- if (strlen($buffer['encrypted'])) {
579
- for ($i = 0; $i < strlen($plaintext); $i+=8) {
580
- $block = substr($plaintext, $i, 8);
581
- $buffer['encrypted'].= $this->_processBlock($this->_generate_xor(8, $xor), CRYPT_DES_ENCRYPT);
582
- $key = $this->_string_shift($buffer['encrypted'], 8);
583
- $ciphertext.= $block ^ $key;
584
- }
585
- } else {
586
- for ($i = 0; $i < strlen($plaintext); $i+=8) {
587
- $block = substr($plaintext, $i, 8);
588
- $key = $this->_processBlock($this->_generate_xor(8, $xor), CRYPT_DES_ENCRYPT);
589
- $ciphertext.= $block ^ $key;
590
- }
591
- }
592
- if ($this->continuousBuffer) {
593
- $this->encryptIV = $xor;
594
- if ($start = strlen($plaintext) & 7) {
595
- $buffer['encrypted'] = substr($key, $start) . $buffer['encrypted'];
596
- }
597
- }
598
- break;
599
- case CRYPT_DES_MODE_CFB:
600
- if (strlen($buffer['xor'])) {
601
- $ciphertext = $plaintext ^ $buffer['xor'];
602
- $iv = $buffer['encrypted'] . $ciphertext;
603
- $start = strlen($ciphertext);
604
- $buffer['encrypted'].= $ciphertext;
605
- $buffer['xor'] = substr($buffer['xor'], strlen($ciphertext));
606
- } else {
607
- $ciphertext = '';
608
- $iv = $this->encryptIV;
609
- $start = 0;
610
- }
611
-
612
- for ($i = $start; $i < strlen($plaintext); $i+=8) {
613
- $block = substr($plaintext, $i, 8);
614
- $xor = $this->_processBlock($iv, CRYPT_DES_ENCRYPT);
615
- $iv = $block ^ $xor;
616
- if ($continuousBuffer && strlen($iv) != 8) {
617
- $buffer = array(
618
- 'encrypted' => $iv,
619
- 'xor' => substr($xor, strlen($iv))
620
- );
621
- }
622
- $ciphertext.= $iv;
623
- }
624
-
625
- if ($this->continuousBuffer) {
626
- $this->encryptIV = $iv;
627
- }
628
- break;
629
- case CRYPT_DES_MODE_OFB:
630
- $xor = $this->encryptIV;
631
- if (strlen($buffer)) {
632
- for ($i = 0; $i < strlen($plaintext); $i+=8) {
633
- $xor = $this->_processBlock($xor, CRYPT_DES_ENCRYPT);
634
- $buffer.= $xor;
635
- $key = $this->_string_shift($buffer, 8);
636
- $ciphertext.= substr($plaintext, $i, 8) ^ $key;
637
- }
638
- } else {
639
- for ($i = 0; $i < strlen($plaintext); $i+=8) {
640
- $xor = $this->_processBlock($xor, CRYPT_DES_ENCRYPT);
641
- $ciphertext.= substr($plaintext, $i, 8) ^ $xor;
642
- }
643
- $key = $xor;
644
- }
645
- if ($this->continuousBuffer) {
646
- $this->encryptIV = $xor;
647
- if ($start = strlen($plaintext) & 7) {
648
- $buffer = substr($key, $start) . $buffer;
649
- }
650
- }
651
- }
652
-
653
- return $ciphertext;
654
- }
655
-
656
- /**
657
- * Decrypts a message.
658
- *
659
- * If strlen($ciphertext) is not a multiple of 8, null bytes will be added to the end of the string until it is.
660
- *
661
- * @see Crypt_DES::encrypt()
662
- * @access public
663
- * @param String $ciphertext
664
- */
665
- function decrypt($ciphertext)
666
- {
667
- if ($this->paddable) {
668
- // we pad with chr(0) since that's what mcrypt_generic does. to quote from http://php.net/function.mcrypt-generic :
669
- // "The data is padded with "\0" to make sure the length of the data is n * blocksize."
670
- $ciphertext = str_pad($ciphertext, (strlen($ciphertext) + 7) & 0xFFFFFFF8, chr(0));
671
- }
672
-
673
- if ( CRYPT_DES_MODE == CRYPT_DES_MODE_MCRYPT ) {
674
- if ($this->dechanged) {
675
- if (!isset($this->demcrypt)) {
676
- $this->demcrypt = mcrypt_module_open(MCRYPT_DES, '', $this->mode, '');
677
- }
678
- mcrypt_generic_init($this->demcrypt, $this->keys, $this->decryptIV);
679
- if ($this->mode != 'ncfb') {
680
- $this->dechanged = false;
681
- }
682
- }
683
-
684
- if ($this->mode != 'ncfb') {
685
- $plaintext = mdecrypt_generic($this->demcrypt, $ciphertext);
686
- } else {
687
- if ($this->dechanged) {
688
- $this->ecb = mcrypt_module_open(MCRYPT_DES, '', MCRYPT_MODE_ECB, '');
689
- mcrypt_generic_init($this->ecb, $this->keys, "\0\0\0\0\0\0\0\0");
690
- $this->dechanged = false;
691
- }
692
-
693
- if (strlen($this->debuffer)) {
694
- $plaintext = $ciphertext ^ substr($this->decryptIV, strlen($this->debuffer));
695
-
696
- $this->debuffer.= substr($ciphertext, 0, strlen($plaintext));
697
- if (strlen($this->debuffer) == 8) {
698
- $this->decryptIV = $this->debuffer;
699
- $this->debuffer = '';
700
- mcrypt_generic_init($this->demcrypt, $this->keys, $this->decryptIV);
701
- }
702
- $ciphertext = substr($ciphertext, strlen($plaintext));
703
- } else {
704
- $plaintext = '';
705
- }
706
-
707
- $last_pos = strlen($ciphertext) & 0xFFFFFFF8;
708
- $plaintext.= $last_pos ? mdecrypt_generic($this->demcrypt, substr($ciphertext, 0, $last_pos)) : '';
709
-
710
- if (strlen($ciphertext) & 0x7) {
711
- if (strlen($plaintext)) {
712
- $this->decryptIV = substr($ciphertext, $last_pos - 8, 8);
713
- }
714
- $this->decryptIV = mcrypt_generic($this->ecb, $this->decryptIV);
715
- $this->debuffer = substr($ciphertext, $last_pos);
716
- $plaintext.= $this->debuffer ^ $this->decryptIV;
717
- }
718
-
719
- return $plaintext;
720
- }
721
-
722
- if (!$this->continuousBuffer) {
723
- mcrypt_generic_init($this->demcrypt, $this->keys, $this->decryptIV);
724
- }
725
-
726
- return $this->paddable ? $this->_unpad($plaintext) : $plaintext;
727
- }
728
-
729
- if (!is_array($this->keys)) {
730
- $this->keys = $this->_prepareKey("\0\0\0\0\0\0\0\0");
731
- }
732
-
733
- $buffer = &$this->debuffer;
734
- $continuousBuffer = $this->continuousBuffer;
735
- $plaintext = '';
736
- switch ($this->mode) {
737
- case CRYPT_DES_MODE_ECB:
738
- for ($i = 0; $i < strlen($ciphertext); $i+=8) {
739
- $plaintext.= $this->_processBlock(substr($ciphertext, $i, 8), CRYPT_DES_DECRYPT);
740
- }
741
- break;
742
- case CRYPT_DES_MODE_CBC:
743
- $xor = $this->decryptIV;
744
- for ($i = 0; $i < strlen($ciphertext); $i+=8) {
745
- $block = substr($ciphertext, $i, 8);
746
- $plaintext.= $this->_processBlock($block, CRYPT_DES_DECRYPT) ^ $xor;
747
- $xor = $block;
748
- }
749
- if ($this->continuousBuffer) {
750
- $this->decryptIV = $xor;
751
- }
752
- break;
753
- case CRYPT_DES_MODE_CTR:
754
- $xor = $this->decryptIV;
755
- if (strlen($buffer['ciphertext'])) {
756
- for ($i = 0; $i < strlen($ciphertext); $i+=8) {
757
- $block = substr($ciphertext, $i, 8);
758
- $buffer['ciphertext'].= $this->_processBlock($this->_generate_xor(8, $xor), CRYPT_DES_ENCRYPT);
759
- $key = $this->_string_shift($buffer['ciphertext'], 8);
760
- $plaintext.= $block ^ $key;
761
- }
762
- } else {
763
- for ($i = 0; $i < strlen($ciphertext); $i+=8) {
764
- $block = substr($ciphertext, $i, 8);
765
- $key = $this->_processBlock($this->_generate_xor(8, $xor), CRYPT_DES_ENCRYPT);
766
- $plaintext.= $block ^ $key;
767
- }
768
- }
769
- if ($this->continuousBuffer) {
770
- $this->decryptIV = $xor;
771
- if ($start = strlen($ciphertext) % 8) {
772
- $buffer['ciphertext'] = substr($key, $start) . $buffer['ciphertext'];
773
- }
774
- }
775
- break;
776
- case CRYPT_DES_MODE_CFB:
777
- if (strlen($buffer['ciphertext'])) {
778
- $plaintext = $ciphertext ^ substr($this->decryptIV, strlen($buffer['ciphertext']));
779
- $buffer['ciphertext'].= substr($ciphertext, 0, strlen($plaintext));
780
- if (strlen($buffer['ciphertext']) != 8) {
781
- $block = $this->decryptIV;
782
- } else {
783
- $block = $buffer['ciphertext'];
784
- $xor = $this->_processBlock($buffer['ciphertext'], CRYPT_DES_ENCRYPT);
785
- $buffer['ciphertext'] = '';
786
- }
787
- $start = strlen($plaintext);
788
- } else {
789
- $plaintext = '';
790
- $xor = $this->_processBlock($this->decryptIV, CRYPT_DES_ENCRYPT);
791
- $start = 0;
792
- }
793
-
794
- for ($i = $start; $i < strlen($ciphertext); $i+=8) {
795
- $block = substr($ciphertext, $i, 8);
796
- $plaintext.= $block ^ $xor;
797
- if ($continuousBuffer && strlen($block) != 8) {
798
- $buffer['ciphertext'].= $block;
799
- $block = $xor;
800
- } else if (strlen($block) == 8) {
801
- $xor = $this->_processBlock($block, CRYPT_DES_ENCRYPT);
802
- }
803
- }
804
- if ($this->continuousBuffer) {
805
- $this->decryptIV = $block;
806
- }
807
- break;
808
- case CRYPT_DES_MODE_OFB:
809
- $xor = $this->decryptIV;
810
- if (strlen($buffer)) {
811
- for ($i = 0; $i < strlen($ciphertext); $i+=8) {
812
- $xor = $this->_processBlock($xor, CRYPT_DES_ENCRYPT);
813
- $buffer.= $xor;
814
- $key = $this->_string_shift($buffer, 8);
815
- $plaintext.= substr($ciphertext, $i, 8) ^ $key;
816
- }
817
- } else {
818
- for ($i = 0; $i < strlen($ciphertext); $i+=8) {
819
- $xor = $this->_processBlock($xor, CRYPT_DES_ENCRYPT);
820
- $plaintext.= substr($ciphertext, $i, 8) ^ $xor;
821
- }
822
- $key = $xor;
823
- }
824
- if ($this->continuousBuffer) {
825
- $this->decryptIV = $xor;
826
- if ($start = strlen($ciphertext) % 8) {
827
- $buffer = substr($key, $start) . $buffer;
828
- }
829
- }
830
- }
831
-
832
- return $this->paddable ? $this->_unpad($plaintext) : $plaintext;
833
- }
834
-
835
- /**
836
- * Treat consecutive "packets" as if they are a continuous buffer.
837
- *
838
- * Say you have a 16-byte plaintext $plaintext. Using the default behavior, the two following code snippets
839
- * will yield different outputs:
840
- *
841
- * <code>
842
- * echo $des->encrypt(substr($plaintext, 0, 8));
843
- * echo $des->encrypt(substr($plaintext, 8, 8));
844
- * </code>
845
- * <code>
846
- * echo $des->encrypt($plaintext);
847
- * </code>
848
- *
849
- * The solution is to enable the continuous buffer. Although this will resolve the above discrepancy, it creates
850
- * another, as demonstrated with the following:
851
- *
852
- * <code>
853
- * $des->encrypt(substr($plaintext, 0, 8));
854
- * echo $des->decrypt($des->encrypt(substr($plaintext, 8, 8)));
855
- * </code>
856
- * <code>
857
- * echo $des->decrypt($des->encrypt(substr($plaintext, 8, 8)));
858
- * </code>
859
- *
860
- * With the continuous buffer disabled, these would yield the same output. With it enabled, they yield different
861
- * outputs. The reason is due to the fact that the initialization vector's change after every encryption /
862
- * decryption round when the continuous buffer is enabled. When it's disabled, they remain constant.
863
- *
864
- * Put another way, when the continuous buffer is enabled, the state of the Crypt_DES() object changes after each
865
- * encryption / decryption round, whereas otherwise, it'd remain constant. For this reason, it's recommended that
866
- * continuous buffers not be used. They do offer better security and are, in fact, sometimes required (SSH uses them),
867
- * however, they are also less intuitive and more likely to cause you problems.
868
- *
869
- * @see Crypt_DES::disableContinuousBuffer()
870
- * @access public
871
- */
872
- function enableContinuousBuffer()
873
- {
874
- $this->continuousBuffer = true;
875
- }
876
-
877
- /**
878
- * Treat consecutive packets as if they are a discontinuous buffer.
879
- *
880
- * The default behavior.
881
- *
882
- * @see Crypt_DES::enableContinuousBuffer()
883
- * @access public
884
- */
885
- function disableContinuousBuffer()
886
- {
887
- $this->continuousBuffer = false;
888
- $this->encryptIV = $this->iv;
889
- $this->decryptIV = $this->iv;
890
- }
891
-
892
- /**
893
- * Pad "packets".
894
- *
895
- * DES works by encrypting eight bytes at a time. If you ever need to encrypt or decrypt something that's not
896
- * a multiple of eight, it becomes necessary to pad the input so that it's length is a multiple of eight.
897
- *
898
- * Padding is enabled by default. Sometimes, however, it is undesirable to pad strings. Such is the case in SSH1,
899
- * where "packets" are padded with random bytes before being encrypted. Unpad these packets and you risk stripping
900
- * away characters that shouldn't be stripped away. (SSH knows how many bytes are added because the length is
901
- * transmitted separately)
902
- *
903
- * @see Crypt_DES::disablePadding()
904
- * @access public
905
- */
906
- function enablePadding()
907
- {
908
- $this->padding = true;
909
- }
910
-
911
- /**
912
- * Do not pad packets.
913
- *
914
- * @see Crypt_DES::enablePadding()
915
- * @access public
916
- */
917
- function disablePadding()
918
- {
919
- $this->padding = false;
920
- }
921
-
922
- /**
923
- * Pads a string
924
- *
925
- * Pads a string using the RSA PKCS padding standards so that its length is a multiple of the blocksize (8).
926
- * 8 - (strlen($text) & 7) bytes are added, each of which is equal to chr(8 - (strlen($text) & 7)
927
- *
928
- * If padding is disabled and $text is not a multiple of the blocksize, the string will be padded regardless
929
- * and padding will, hence forth, be enabled.
930
- *
931
- * @see Crypt_DES::_unpad()
932
- * @access private
933
- */
934
- function _pad($text)
935
- {
936
- $length = strlen($text);
937
-
938
- if (!$this->padding) {
939
- if (($length & 7) == 0) {
940
- return $text;
941
- } else {
942
- user_error("The plaintext's length ($length) is not a multiple of the block size (8)");
943
- $this->padding = true;
944
- }
945
- }
946
-
947
- $pad = 8 - ($length & 7);
948
- return str_pad($text, $length + $pad, chr($pad));
949
- }
950
-
951
- /**
952
- * Unpads a string
953
- *
954
- * If padding is enabled and the reported padding length is invalid the encryption key will be assumed to be wrong
955
- * and false will be returned.
956
- *
957
- * @see Crypt_DES::_pad()
958
- * @access private
959
- */
960
- function _unpad($text)
961
- {
962
- if (!$this->padding) {
963
- return $text;
964
- }
965
-
966
- $length = ord($text[strlen($text) - 1]);
967
-
968
- if (!$length || $length > 8) {
969
- return false;
970
- }
971
-
972
- return substr($text, 0, -$length);
973
- }
974
-
975
- /**
976
- * Encrypts or decrypts a 64-bit block
977
- *
978
- * $mode should be either CRYPT_DES_ENCRYPT or CRYPT_DES_DECRYPT. See
979
- * {@link http://en.wikipedia.org/wiki/Image:Feistel.png Feistel.png} to get a general
980
- * idea of what this function does.
981
- *
982
- * @access private
983
- * @param String $block
984
- * @param Integer $mode
985
- * @return String
986
- */
987
- function _processBlock($block, $mode)
988
- {
989
- // s-boxes. in the official DES docs, they're described as being matrices that
990
- // one accesses by using the first and last bits to determine the row and the
991
- // middle four bits to determine the column. in this implementation, they've
992
- // been converted to vectors
993
- static $sbox = array(
994
- array(
995
- 14, 0, 4, 15, 13, 7, 1, 4, 2, 14, 15, 2, 11, 13, 8, 1,
996
- 3, 10 ,10, 6, 6, 12, 12, 11, 5, 9, 9, 5, 0, 3, 7, 8,
997
- 4, 15, 1, 12, 14, 8, 8, 2, 13, 4, 6, 9, 2, 1, 11, 7,
998
- 15, 5, 12, 11, 9, 3, 7, 14, 3, 10, 10, 0, 5, 6, 0, 13
999
- ),
1000
- array(
1001
- 15, 3, 1, 13, 8, 4, 14, 7, 6, 15, 11, 2, 3, 8, 4, 14,
1002
- 9, 12, 7, 0, 2, 1, 13, 10, 12, 6, 0, 9, 5, 11, 10, 5,
1003
- 0, 13, 14, 8, 7, 10, 11, 1, 10, 3, 4, 15, 13, 4, 1, 2,
1004
- 5, 11, 8, 6, 12, 7, 6, 12, 9, 0, 3, 5, 2, 14, 15, 9
1005
- ),
1006
- array(
1007
- 10, 13, 0, 7, 9, 0, 14, 9, 6, 3, 3, 4, 15, 6, 5, 10,
1008
- 1, 2, 13, 8, 12, 5, 7, 14, 11, 12, 4, 11, 2, 15, 8, 1,
1009
- 13, 1, 6, 10, 4, 13, 9, 0, 8, 6, 15, 9, 3, 8, 0, 7,
1010
- 11, 4, 1, 15, 2, 14, 12, 3, 5, 11, 10, 5, 14, 2, 7, 12
1011
- ),
1012
- array(
1013
- 7, 13, 13, 8, 14, 11, 3, 5, 0, 6, 6, 15, 9, 0, 10, 3,
1014
- 1, 4, 2, 7, 8, 2, 5, 12, 11, 1, 12, 10, 4, 14, 15, 9,
1015
- 10, 3, 6, 15, 9, 0, 0, 6, 12, 10, 11, 1, 7, 13, 13, 8,
1016
- 15, 9, 1, 4, 3, 5, 14, 11, 5, 12, 2, 7, 8, 2, 4, 14
1017
- ),
1018
- array(
1019
- 2, 14, 12, 11, 4, 2, 1, 12, 7, 4, 10, 7, 11, 13, 6, 1,
1020
- 8, 5, 5, 0, 3, 15, 15, 10, 13, 3, 0, 9, 14, 8, 9, 6,
1021
- 4, 11, 2, 8, 1, 12, 11, 7, 10, 1, 13, 14, 7, 2, 8, 13,
1022
- 15, 6, 9, 15, 12, 0, 5, 9, 6, 10, 3, 4, 0, 5, 14, 3
1023
- ),
1024
- array(
1025
- 12, 10, 1, 15, 10, 4, 15, 2, 9, 7, 2, 12, 6, 9, 8, 5,
1026
- 0, 6, 13, 1, 3, 13, 4, 14, 14, 0, 7, 11, 5, 3, 11, 8,
1027
- 9, 4, 14, 3, 15, 2, 5, 12, 2, 9, 8, 5, 12, 15, 3, 10,
1028
- 7, 11, 0, 14, 4, 1, 10, 7, 1, 6, 13, 0, 11, 8, 6, 13
1029
- ),
1030
- array(
1031
- 4, 13, 11, 0, 2, 11, 14, 7, 15, 4, 0, 9, 8, 1, 13, 10,
1032
- 3, 14, 12, 3, 9, 5, 7, 12, 5, 2, 10, 15, 6, 8, 1, 6,
1033
- 1, 6, 4, 11, 11, 13, 13, 8, 12, 1, 3, 4, 7, 10, 14, 7,
1034
- 10, 9, 15, 5, 6, 0, 8, 15, 0, 14, 5, 2, 9, 3, 2, 12
1035
- ),
1036
- array(
1037
- 13, 1, 2, 15, 8, 13, 4, 8, 6, 10, 15, 3, 11, 7, 1, 4,
1038
- 10, 12, 9, 5, 3, 6, 14, 11, 5, 0, 0, 14, 12, 9, 7, 2,
1039
- 7, 2, 11, 1, 4, 14, 1, 7, 9, 4, 12, 10, 14, 8, 2, 13,
1040
- 0, 15, 6, 12, 10, 9, 13, 0, 15, 3, 3, 5, 5, 6, 8, 11
1041
- )
1042
- );
1043
-
1044
- $keys = $this->keys;
1045
-
1046
- $temp = unpack('Na/Nb', $block);
1047
- $block = array($temp['a'], $temp['b']);
1048
-
1049
- // because php does arithmetic right shifts, if the most significant bits are set, right
1050
- // shifting those into the correct position will add 1's - not 0's. this will intefere
1051
- // with the | operation unless a second & is done. so we isolate these bits and left shift
1052
- // them into place. we then & each block with 0x7FFFFFFF to prevennt 1's from being added
1053
- // for any other shifts.
1054
- $msb = array(
1055
- ($block[0] >> 31) & 1,
1056
- ($block[1] >> 31) & 1
1057
- );
1058
- $block[0] &= 0x7FFFFFFF;
1059
- $block[1] &= 0x7FFFFFFF;
1060
-
1061
- // we isolate the appropriate bit in the appropriate integer and shift as appropriate. in
1062
- // some cases, there are going to be multiple bits in the same integer that need to be shifted
1063
- // in the same way. we combine those into one shift operation.
1064
- $block = array(
1065
- (($block[1] & 0x00000040) << 25) | (($block[1] & 0x00004000) << 16) |
1066
- (($block[1] & 0x00400001) << 7) | (($block[1] & 0x40000100) >> 2) |
1067
- (($block[0] & 0x00000040) << 21) | (($block[0] & 0x00004000) << 12) |
1068
- (($block[0] & 0x00400001) << 3) | (($block[0] & 0x40000100) >> 6) |
1069
- (($block[1] & 0x00000010) << 19) | (($block[1] & 0x00001000) << 10) |
1070
- (($block[1] & 0x00100000) << 1) | (($block[1] & 0x10000000) >> 8) |
1071
- (($block[0] & 0x00000010) << 15) | (($block[0] & 0x00001000) << 6) |
1072
- (($block[0] & 0x00100000) >> 3) | (($block[0] & 0x10000000) >> 12) |
1073
- (($block[1] & 0x00000004) << 13) | (($block[1] & 0x00000400) << 4) |
1074
- (($block[1] & 0x00040000) >> 5) | (($block[1] & 0x04000000) >> 14) |
1075
- (($block[0] & 0x00000004) << 9) | ( $block[0] & 0x00000400 ) |
1076
- (($block[0] & 0x00040000) >> 9) | (($block[0] & 0x04000000) >> 18) |
1077
- (($block[1] & 0x00010000) >> 11) | (($block[1] & 0x01000000) >> 20) |
1078
- (($block[0] & 0x00010000) >> 15) | (($block[0] & 0x01000000) >> 24)
1079
- ,
1080
- (($block[1] & 0x00000080) << 24) | (($block[1] & 0x00008000) << 15) |
1081
- (($block[1] & 0x00800002) << 6) | (($block[0] & 0x00000080) << 20) |
1082
- (($block[0] & 0x00008000) << 11) | (($block[0] & 0x00800002) << 2) |
1083
- (($block[1] & 0x00000020) << 18) | (($block[1] & 0x00002000) << 9) |
1084
- ( $block[1] & 0x00200000 ) | (($block[1] & 0x20000000) >> 9) |
1085
- (($block[0] & 0x00000020) << 14) | (($block[0] & 0x00002000) << 5) |
1086
- (($block[0] & 0x00200000) >> 4) | (($block[0] & 0x20000000) >> 13) |
1087
- (($block[1] & 0x00000008) << 12) | (($block[1] & 0x00000800) << 3) |
1088
- (($block[1] & 0x00080000) >> 6) | (($block[1] & 0x08000000) >> 15) |
1089
- (($block[0] & 0x00000008) << 8) | (($block[0] & 0x00000800) >> 1) |
1090
- (($block[0] & 0x00080000) >> 10) | (($block[0] & 0x08000000) >> 19) |
1091
- (($block[1] & 0x00000200) >> 3) | (($block[0] & 0x00000200) >> 7) |
1092
- (($block[1] & 0x00020000) >> 12) | (($block[1] & 0x02000000) >> 21) |
1093
- (($block[0] & 0x00020000) >> 16) | (($block[0] & 0x02000000) >> 25) |
1094
- ($msb[1] << 28) | ($msb[0] << 24)
1095
- );
1096
-
1097
- for ($i = 0; $i < 16; $i++) {
1098
- // start of "the Feistel (F) function" - see the following URL:
1099
- // http://en.wikipedia.org/wiki/Image:Data_Encryption_Standard_InfoBox_Diagram.png
1100
- $temp = (($sbox[0][((($block[1] >> 27) & 0x1F) | (($block[1] & 1) << 5)) ^ $keys[$mode][$i][0]]) << 28)
1101
- | (($sbox[1][(($block[1] & 0x1F800000) >> 23) ^ $keys[$mode][$i][1]]) << 24)
1102
- | (($sbox[2][(($block[1] & 0x01F80000) >> 19) ^ $keys[$mode][$i][2]]) << 20)
1103
- | (($sbox[3][(($block[1] & 0x001F8000) >> 15) ^ $keys[$mode][$i][3]]) << 16)
1104
- | (($sbox[4][(($block[1] & 0x0001F800) >> 11) ^ $keys[$mode][$i][4]]) << 12)
1105
- | (($sbox[5][(($block[1] & 0x00001F80) >> 7) ^ $keys[$mode][$i][5]]) << 8)
1106
- | (($sbox[6][(($block[1] & 0x000001F8) >> 3) ^ $keys[$mode][$i][6]]) << 4)
1107
- | ( $sbox[7][((($block[1] & 0x1F) << 1) | (($block[1] >> 31) & 1)) ^ $keys[$mode][$i][7]]);
1108
-
1109
- $msb = ($temp >> 31) & 1;
1110
- $temp &= 0x7FFFFFFF;
1111
- $newBlock = (($temp & 0x00010000) << 15) | (($temp & 0x02020120) << 5)
1112
- | (($temp & 0x00001800) << 17) | (($temp & 0x01000000) >> 10)
1113
- | (($temp & 0x00000008) << 24) | (($temp & 0x00100000) << 6)
1114
- | (($temp & 0x00000010) << 21) | (($temp & 0x00008000) << 9)
1115
- | (($temp & 0x00000200) << 12) | (($temp & 0x10000000) >> 27)
1116
- | (($temp & 0x00000040) << 14) | (($temp & 0x08000000) >> 8)
1117
- | (($temp & 0x00004000) << 4) | (($temp & 0x00000002) << 16)
1118
- | (($temp & 0x00442000) >> 6) | (($temp & 0x40800000) >> 15)
1119
- | (($temp & 0x00000001) << 11) | (($temp & 0x20000000) >> 20)
1120
- | (($temp & 0x00080000) >> 13) | (($temp & 0x00000004) << 3)
1121
- | (($temp & 0x04000000) >> 22) | (($temp & 0x00000480) >> 7)
1122
- | (($temp & 0x00200000) >> 19) | ($msb << 23);
1123
- // end of "the Feistel (F) function" - $newBlock is F's output
1124
-
1125
- $temp = $block[1];
1126
- $block[1] = $block[0] ^ $newBlock;
1127
- $block[0] = $temp;
1128
- }
1129
-
1130
- $msb = array(
1131
- ($block[0] >> 31) & 1,
1132
- ($block[1] >> 31) & 1
1133
- );
1134
- $block[0] &= 0x7FFFFFFF;
1135
- $block[1] &= 0x7FFFFFFF;
1136
-
1137
- $block = array(
1138
- (($block[0] & 0x01000004) << 7) | (($block[1] & 0x01000004) << 6) |
1139
- (($block[0] & 0x00010000) << 13) | (($block[1] & 0x00010000) << 12) |
1140
- (($block[0] & 0x00000100) << 19) | (($block[1] & 0x00000100) << 18) |
1141
- (($block[0] & 0x00000001) << 25) | (($block[1] & 0x00000001) << 24) |
1142
- (($block[0] & 0x02000008) >> 2) | (($block[1] & 0x02000008) >> 3) |
1143
- (($block[0] & 0x00020000) << 4) | (($block[1] & 0x00020000) << 3) |
1144
- (($block[0] & 0x00000200) << 10) | (($block[1] & 0x00000200) << 9) |
1145
- (($block[0] & 0x00000002) << 16) | (($block[1] & 0x00000002) << 15) |
1146
- (($block[0] & 0x04000000) >> 11) | (($block[1] & 0x04000000) >> 12) |
1147
- (($block[0] & 0x00040000) >> 5) | (($block[1] & 0x00040000) >> 6) |
1148
- (($block[0] & 0x00000400) << 1) | ( $block[1] & 0x00000400 ) |
1149
- (($block[0] & 0x08000000) >> 20) | (($block[1] & 0x08000000) >> 21) |
1150
- (($block[0] & 0x00080000) >> 14) | (($block[1] & 0x00080000) >> 15) |
1151
- (($block[0] & 0x00000800) >> 8) | (($block[1] & 0x00000800) >> 9)
1152
- ,
1153
- (($block[0] & 0x10000040) << 3) | (($block[1] & 0x10000040) << 2) |
1154
- (($block[0] & 0x00100000) << 9) | (($block[1] & 0x00100000) << 8) |
1155
- (($block[0] & 0x00001000) << 15) | (($block[1] & 0x00001000) << 14) |
1156
- (($block[0] & 0x00000010) << 21) | (($block[1] & 0x00000010) << 20) |
1157
- (($block[0] & 0x20000080) >> 6) | (($block[1] & 0x20000080) >> 7) |
1158
- ( $block[0] & 0x00200000 ) | (($block[1] & 0x00200000) >> 1) |
1159
- (($block[0] & 0x00002000) << 6) | (($block[1] & 0x00002000) << 5) |
1160
- (($block[0] & 0x00000020) << 12) | (($block[1] & 0x00000020) << 11) |
1161
- (($block[0] & 0x40000000) >> 15) | (($block[1] & 0x40000000) >> 16) |
1162
- (($block[0] & 0x00400000) >> 9) | (($block[1] & 0x00400000) >> 10) |
1163
- (($block[0] & 0x00004000) >> 3) | (($block[1] & 0x00004000) >> 4) |
1164
- (($block[0] & 0x00800000) >> 18) | (($block[1] & 0x00800000) >> 19) |
1165
- (($block[0] & 0x00008000) >> 12) | (($block[1] & 0x00008000) >> 13) |
1166
- ($msb[0] << 7) | ($msb[1] << 6)
1167
- );
1168
-
1169
- return pack('NN', $block[0], $block[1]);
1170
- }
1171
-
1172
- /**
1173
- * Creates the key schedule.
1174
- *
1175
- * @access private
1176
- * @param String $key
1177
- * @return Array
1178
- */
1179
- function _prepareKey($key)
1180
- {
1181
- static $shifts = array( // number of key bits shifted per round
1182
- 1, 1, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 1
1183
- );
1184
-
1185
- // pad the key and remove extra characters as appropriate.
1186
- $key = str_pad(substr($key, 0, 8), 8, chr(0));
1187
-
1188
- $temp = unpack('Na/Nb', $key);
1189
- $key = array($temp['a'], $temp['b']);
1190
- $msb = array(
1191
- ($key[0] >> 31) & 1,
1192
- ($key[1] >> 31) & 1
1193
- );
1194
- $key[0] &= 0x7FFFFFFF;
1195
- $key[1] &= 0x7FFFFFFF;
1196
-
1197
- $key = array(
1198
- (($key[1] & 0x00000002) << 26) | (($key[1] & 0x00000204) << 17) |
1199
- (($key[1] & 0x00020408) << 8) | (($key[1] & 0x02040800) >> 1) |
1200
- (($key[0] & 0x00000002) << 22) | (($key[0] & 0x00000204) << 13) |
1201
- (($key[0] & 0x00020408) << 4) | (($key[0] & 0x02040800) >> 5) |
1202
- (($key[1] & 0x04080000) >> 10) | (($key[0] & 0x04080000) >> 14) |
1203
- (($key[1] & 0x08000000) >> 19) | (($key[0] & 0x08000000) >> 23) |
1204
- (($key[0] & 0x00000010) >> 1) | (($key[0] & 0x00001000) >> 10) |
1205
- (($key[0] & 0x00100000) >> 19) | (($key[0] & 0x10000000) >> 28)
1206
- ,
1207
- (($key[1] & 0x00000080) << 20) | (($key[1] & 0x00008000) << 11) |
1208
- (($key[1] & 0x00800000) << 2) | (($key[0] & 0x00000080) << 16) |
1209
- (($key[0] & 0x00008000) << 7) | (($key[0] & 0x00800000) >> 2) |
1210
- (($key[1] & 0x00000040) << 13) | (($key[1] & 0x00004000) << 4) |
1211
- (($key[1] & 0x00400000) >> 5) | (($key[1] & 0x40000000) >> 14) |
1212
- (($key[0] & 0x00000040) << 9) | ( $key[0] & 0x00004000 ) |
1213
- (($key[0] & 0x00400000) >> 9) | (($key[0] & 0x40000000) >> 18) |
1214
- (($key[1] & 0x00000020) << 6) | (($key[1] & 0x00002000) >> 3) |
1215
- (($key[1] & 0x00200000) >> 12) | (($key[1] & 0x20000000) >> 21) |
1216
- (($key[0] & 0x00000020) << 2) | (($key[0] & 0x00002000) >> 7) |
1217
- (($key[0] & 0x00200000) >> 16) | (($key[0] & 0x20000000) >> 25) |
1218
- (($key[1] & 0x00000010) >> 1) | (($key[1] & 0x00001000) >> 10) |
1219
- (($key[1] & 0x00100000) >> 19) | (($key[1] & 0x10000000) >> 28) |
1220
- ($msb[1] << 24) | ($msb[0] << 20)
1221
- );
1222
-
1223
- $keys = array();
1224
- for ($i = 0; $i < 16; $i++) {
1225
- $key[0] <<= $shifts[$i];
1226
- $temp = ($key[0] & 0xF0000000) >> 28;
1227
- $key[0] = ($key[0] | $temp) & 0x0FFFFFFF;
1228
-
1229
- $key[1] <<= $shifts[$i];
1230
- $temp = ($key[1] & 0xF0000000) >> 28;
1231
- $key[1] = ($key[1] | $temp) & 0x0FFFFFFF;
1232
-
1233
- $temp = array(
1234
- (($key[1] & 0x00004000) >> 9) | (($key[1] & 0x00000800) >> 7) |
1235
- (($key[1] & 0x00020000) >> 14) | (($key[1] & 0x00000010) >> 2) |
1236
- (($key[1] & 0x08000000) >> 26) | (($key[1] & 0x00800000) >> 23)
1237
- ,
1238
- (($key[1] & 0x02400000) >> 20) | (($key[1] & 0x00000001) << 4) |
1239
- (($key[1] & 0x00002000) >> 10) | (($key[1] & 0x00040000) >> 18) |
1240
- (($key[1] & 0x00000080) >> 6)
1241
- ,
1242
- ( $key[1] & 0x00000020 ) | (($key[1] & 0x00000200) >> 5) |
1243
- (($key[1] & 0x00010000) >> 13) | (($key[1] & 0x01000000) >> 22) |
1244
- (($key[1] & 0x00000004) >> 1) | (($key[1] & 0x00100000) >> 20)
1245
- ,
1246
- (($key[1] & 0x00001000) >> 7) | (($key[1] & 0x00200000) >> 17) |
1247
- (($key[1] & 0x00000002) << 2) | (($key[1] & 0x00000100) >> 6) |
1248
- (($key[1] & 0x00008000) >> 14) | (($key[1] & 0x04000000) >> 26)
1249
- ,
1250
- (($key[0] & 0x00008000) >> 10) | ( $key[0] & 0x00000010 ) |
1251
- (($key[0] & 0x02000000) >> 22) | (($key[0] & 0x00080000) >> 17) |
1252
- (($key[0] & 0x00000200) >> 8) | (($key[0] & 0x00000002) >> 1)
1253
- ,
1254
- (($key[0] & 0x04000000) >> 21) | (($key[0] & 0x00010000) >> 12) |
1255
- (($key[0] & 0x00000020) >> 2) | (($key[0] & 0x00000800) >> 9) |
1256
- (($key[0] & 0x00800000) >> 22) | (($key[0] & 0x00000100) >> 8)
1257
- ,
1258
- (($key[0] & 0x00001000) >> 7) | (($key[0] & 0x00000088) >> 3) |
1259
- (($key[0] & 0x00020000) >> 14) | (($key[0] & 0x00000001) << 2) |
1260
- (($key[0] & 0x00400000) >> 21)
1261
- ,
1262
- (($key[0] & 0x00000400) >> 5) | (($key[0] & 0x00004000) >> 10) |
1263
- (($key[0] & 0x00000040) >> 3) | (($key[0] & 0x00100000) >> 18) |
1264
- (($key[0] & 0x08000000) >> 26) | (($key[0] & 0x01000000) >> 24)
1265
- );
1266
-
1267
- $keys[] = $temp;
1268
- }
1269
-
1270
- $temp = array(
1271
- CRYPT_DES_ENCRYPT => $keys,
1272
- CRYPT_DES_DECRYPT => array_reverse($keys)
1273
- );
1274
-
1275
- return $temp;
1276
- }
1277
-
1278
- /**
1279
- * String Shift
1280
- *
1281
- * Inspired by array_shift
1282
- *
1283
- * @param String $string
1284
- * @param optional Integer $index
1285
- * @return String
1286
- * @access private
1287
- */
1288
- function _string_shift(&$string, $index = 1)
1289
- {
1290
- $substr = substr($string, 0, $index);
1291
- $string = substr($string, $index);
1292
- return $substr;
1293
- }
1294
- }
1295
-
1296
- // vim: ts=4:sw=4:et:
1297
- // vim6: fdl=1:
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * Pure-PHP implementation of DES.
5
+ *
6
+ * Uses mcrypt, if available, and an internal implementation, otherwise.
7
+ *
8
+ * PHP versions 4 and 5
9
+ *
10
+ * Useful resources are as follows:
11
+ *
12
+ * - {@link http://en.wikipedia.org/wiki/DES_supplementary_material Wikipedia: DES supplementary material}
13
+ * - {@link http://www.itl.nist.gov/fipspubs/fip46-2.htm FIPS 46-2 - (DES), Data Encryption Standard}
14
+ * - {@link http://www.cs.eku.edu/faculty/styer/460/Encrypt/JS-DES.html JavaScript DES Example}
15
+ *
16
+ * Here's a short example of how to use this library:
17
+ * <code>
18
+ * <?php
19
+ * include 'Crypt/DES.php';
20
+ *
21
+ * $des = new Crypt_DES();
22
+ *
23
+ * $des->setKey('abcdefgh');
24
+ *
25
+ * $size = 10 * 1024;
26
+ * $plaintext = '';
27
+ * for ($i = 0; $i < $size; $i++) {
28
+ * $plaintext.= 'a';
29
+ * }
30
+ *
31
+ * echo $des->decrypt($des->encrypt($plaintext));
32
+ * ?>
33
+ * </code>
34
+ *
35
+ * LICENSE: Permission is hereby granted, free of charge, to any person obtaining a copy
36
+ * of this software and associated documentation files (the "Software"), to deal
37
+ * in the Software without restriction, including without limitation the rights
38
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
39
+ * copies of the Software, and to permit persons to whom the Software is
40
+ * furnished to do so, subject to the following conditions:
41
+ *
42
+ * The above copyright notice and this permission notice shall be included in
43
+ * all copies or substantial portions of the Software.
44
+ *
45
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
46
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
47
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
48
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
49
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
50
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
51
+ * THE SOFTWARE.
52
+ *
53
+ * @category Crypt
54
+ * @package Crypt_DES
55
+ * @author Jim Wigginton <terrafrost@php.net>
56
+ * @copyright MMVII Jim Wigginton
57
+ * @license http://www.opensource.org/licenses/mit-license.html MIT License
58
+ * @link http://phpseclib.sourceforge.net
59
+ */
60
+
61
+ /**
62
+ * Include Crypt_Base
63
+ *
64
+ * Base cipher class
65
+ */
66
+ if (!class_exists('Crypt_Base')) {
67
+ include_once 'Base.php';
68
+ }
69
+
70
+ /**#@+
71
+ * @access private
72
+ * @see Crypt_DES::_setupKey()
73
+ * @see Crypt_DES::_processBlock()
74
+ */
75
+ /**
76
+ * Contains $keys[CRYPT_DES_ENCRYPT]
77
+ */
78
+ define('CRYPT_DES_ENCRYPT', 0);
79
+ /**
80
+ * Contains $keys[CRYPT_DES_DECRYPT]
81
+ */
82
+ define('CRYPT_DES_DECRYPT', 1);
83
+ /**#@-*/
84
+
85
+ /**#@+
86
+ * @access public
87
+ * @see Crypt_DES::encrypt()
88
+ * @see Crypt_DES::decrypt()
89
+ */
90
+ /**
91
+ * Encrypt / decrypt using the Counter mode.
92
+ *
93
+ * Set to -1 since that's what Crypt/Random.php uses to index the CTR mode.
94
+ *
95
+ * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Counter_.28CTR.29
96
+ */
97
+ define('CRYPT_DES_MODE_CTR', CRYPT_MODE_CTR);
98
+ /**
99
+ * Encrypt / decrypt using the Electronic Code Book mode.
100
+ *
101
+ * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Electronic_codebook_.28ECB.29
102
+ */
103
+ define('CRYPT_DES_MODE_ECB', CRYPT_MODE_ECB);
104
+ /**
105
+ * Encrypt / decrypt using the Code Book Chaining mode.
106
+ *
107
+ * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Cipher-block_chaining_.28CBC.29
108
+ */
109
+ define('CRYPT_DES_MODE_CBC', CRYPT_MODE_CBC);
110
+ /**
111
+ * Encrypt / decrypt using the Cipher Feedback mode.
112
+ *
113
+ * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Cipher_feedback_.28CFB.29
114
+ */
115
+ define('CRYPT_DES_MODE_CFB', CRYPT_MODE_CFB);
116
+ /**
117
+ * Encrypt / decrypt using the Cipher Feedback mode.
118
+ *
119
+ * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Output_feedback_.28OFB.29
120
+ */
121
+ define('CRYPT_DES_MODE_OFB', CRYPT_MODE_OFB);
122
+ /**#@-*/
123
+
124
+ /**#@+
125
+ * @access private
126
+ * @see Crypt_Base::Crypt_Base()
127
+ */
128
+ /**
129
+ * Toggles the internal implementation
130
+ */
131
+ define('CRYPT_DES_MODE_INTERNAL', CRYPT_MODE_INTERNAL);
132
+ /**
133
+ * Toggles the mcrypt implementation
134
+ */
135
+ define('CRYPT_DES_MODE_MCRYPT', CRYPT_MODE_MCRYPT);
136
+ /**#@-*/
137
+
138
+ /**
139
+ * Pure-PHP implementation of DES.
140
+ *
141
+ * @package Crypt_DES
142
+ * @author Jim Wigginton <terrafrost@php.net>
143
+ * @access public
144
+ */
145
+ class Crypt_DES extends Crypt_Base
146
+ {
147
+ /**
148
+ * Block Length of the cipher
149
+ *
150
+ * @see Crypt_Base::block_size
151
+ * @var Integer
152
+ * @access private
153
+ */
154
+ var $block_size = 8;
155
+
156
+ /**
157
+ * The Key
158
+ *
159
+ * @see Crypt_Base::key
160
+ * @see setKey()
161
+ * @var String
162
+ * @access private
163
+ */
164
+ var $key = "\0\0\0\0\0\0\0\0";
165
+
166
+ /**
167
+ * The default password key_size used by setPassword()
168
+ *
169
+ * @see Crypt_Base::password_key_size
170
+ * @see Crypt_Base::setPassword()
171
+ * @var Integer
172
+ * @access private
173
+ */
174
+ var $password_key_size = 8;
175
+
176
+ /**
177
+ * The namespace used by the cipher for its constants.
178
+ *
179
+ * @see Crypt_Base::const_namespace
180
+ * @var String
181
+ * @access private
182
+ */
183
+ var $const_namespace = 'DES';
184
+
185
+ /**
186
+ * The mcrypt specific name of the cipher
187
+ *
188
+ * @see Crypt_Base::cipher_name_mcrypt
189
+ * @var String
190
+ * @access private
191
+ */
192
+ var $cipher_name_mcrypt = 'des';
193
+
194
+ /**
195
+ * Optimizing value while CFB-encrypting
196
+ *
197
+ * @see Crypt_Base::cfb_init_len
198
+ * @var Integer
199
+ * @access private
200
+ */
201
+ var $cfb_init_len = 500;
202
+
203
+ /**
204
+ * Switch for DES/3DES encryption
205
+ *
206
+ * Used only if $engine == CRYPT_DES_MODE_INTERNAL
207
+ *
208
+ * @see Crypt_DES::_setupKey()
209
+ * @see Crypt_DES::_processBlock()
210
+ * @var Integer
211
+ * @access private
212
+ */
213
+ var $des_rounds = 1;
214
+
215
+ /**
216
+ * max possible size of $key
217
+ *
218
+ * @see Crypt_DES::setKey()
219
+ * @var String
220
+ * @access private
221
+ */
222
+ var $key_size_max = 8;
223
+
224
+ /**
225
+ * The Key Schedule
226
+ *
227
+ * @see Crypt_DES::_setupKey()
228
+ * @var Array
229
+ * @access private
230
+ */
231
+ var $keys;
232
+
233
+ /**
234
+ * Shuffle table.
235
+ *
236
+ * For each byte value index, the entry holds an 8-byte string
237
+ * with each byte containing all bits in the same state as the
238
+ * corresponding bit in the index value.
239
+ *
240
+ * @see Crypt_DES::_processBlock()
241
+ * @see Crypt_DES::_setupKey()
242
+ * @var Array
243
+ * @access private
244
+ */
245
+ var $shuffle = array(
246
+ "\x00\x00\x00\x00\x00\x00\x00\x00", "\x00\x00\x00\x00\x00\x00\x00\xFF",
247
+ "\x00\x00\x00\x00\x00\x00\xFF\x00", "\x00\x00\x00\x00\x00\x00\xFF\xFF",
248
+ "\x00\x00\x00\x00\x00\xFF\x00\x00", "\x00\x00\x00\x00\x00\xFF\x00\xFF",
249
+ "\x00\x00\x00\x00\x00\xFF\xFF\x00", "\x00\x00\x00\x00\x00\xFF\xFF\xFF",
250
+ "\x00\x00\x00\x00\xFF\x00\x00\x00", "\x00\x00\x00\x00\xFF\x00\x00\xFF",
251
+ "\x00\x00\x00\x00\xFF\x00\xFF\x00", "\x00\x00\x00\x00\xFF\x00\xFF\xFF",
252
+ "\x00\x00\x00\x00\xFF\xFF\x00\x00", "\x00\x00\x00\x00\xFF\xFF\x00\xFF",
253
+ "\x00\x00\x00\x00\xFF\xFF\xFF\x00", "\x00\x00\x00\x00\xFF\xFF\xFF\xFF",
254
+ "\x00\x00\x00\xFF\x00\x00\x00\x00", "\x00\x00\x00\xFF\x00\x00\x00\xFF",
255
+ "\x00\x00\x00\xFF\x00\x00\xFF\x00", "\x00\x00\x00\xFF\x00\x00\xFF\xFF",
256
+ "\x00\x00\x00\xFF\x00\xFF\x00\x00", "\x00\x00\x00\xFF\x00\xFF\x00\xFF",
257
+ "\x00\x00\x00\xFF\x00\xFF\xFF\x00", "\x00\x00\x00\xFF\x00\xFF\xFF\xFF",
258
+ "\x00\x00\x00\xFF\xFF\x00\x00\x00", "\x00\x00\x00\xFF\xFF\x00\x00\xFF",
259
+ "\x00\x00\x00\xFF\xFF\x00\xFF\x00", "\x00\x00\x00\xFF\xFF\x00\xFF\xFF",
260
+ "\x00\x00\x00\xFF\xFF\xFF\x00\x00", "\x00\x00\x00\xFF\xFF\xFF\x00\xFF",
261
+ "\x00\x00\x00\xFF\xFF\xFF\xFF\x00", "\x00\x00\x00\xFF\xFF\xFF\xFF\xFF",
262
+ "\x00\x00\xFF\x00\x00\x00\x00\x00", "\x00\x00\xFF\x00\x00\x00\x00\xFF",
263
+ "\x00\x00\xFF\x00\x00\x00\xFF\x00", "\x00\x00\xFF\x00\x00\x00\xFF\xFF",
264
+ "\x00\x00\xFF\x00\x00\xFF\x00\x00", "\x00\x00\xFF\x00\x00\xFF\x00\xFF",
265
+ "\x00\x00\xFF\x00\x00\xFF\xFF\x00", "\x00\x00\xFF\x00\x00\xFF\xFF\xFF",
266
+ "\x00\x00\xFF\x00\xFF\x00\x00\x00", "\x00\x00\xFF\x00\xFF\x00\x00\xFF",
267
+ "\x00\x00\xFF\x00\xFF\x00\xFF\x00", "\x00\x00\xFF\x00\xFF\x00\xFF\xFF",
268
+ "\x00\x00\xFF\x00\xFF\xFF\x00\x00", "\x00\x00\xFF\x00\xFF\xFF\x00\xFF",
269
+ "\x00\x00\xFF\x00\xFF\xFF\xFF\x00", "\x00\x00\xFF\x00\xFF\xFF\xFF\xFF",
270
+ "\x00\x00\xFF\xFF\x00\x00\x00\x00", "\x00\x00\xFF\xFF\x00\x00\x00\xFF",
271
+ "\x00\x00\xFF\xFF\x00\x00\xFF\x00", "\x00\x00\xFF\xFF\x00\x00\xFF\xFF",
272
+ "\x00\x00\xFF\xFF\x00\xFF\x00\x00", "\x00\x00\xFF\xFF\x00\xFF\x00\xFF",
273
+ "\x00\x00\xFF\xFF\x00\xFF\xFF\x00", "\x00\x00\xFF\xFF\x00\xFF\xFF\xFF",
274
+ "\x00\x00\xFF\xFF\xFF\x00\x00\x00", "\x00\x00\xFF\xFF\xFF\x00\x00\xFF",
275
+ "\x00\x00\xFF\xFF\xFF\x00\xFF\x00", "\x00\x00\xFF\xFF\xFF\x00\xFF\xFF",
276
+ "\x00\x00\xFF\xFF\xFF\xFF\x00\x00", "\x00\x00\xFF\xFF\xFF\xFF\x00\xFF",
277
+ "\x00\x00\xFF\xFF\xFF\xFF\xFF\x00", "\x00\x00\xFF\xFF\xFF\xFF\xFF\xFF",
278
+ "\x00\xFF\x00\x00\x00\x00\x00\x00", "\x00\xFF\x00\x00\x00\x00\x00\xFF",
279
+ "\x00\xFF\x00\x00\x00\x00\xFF\x00", "\x00\xFF\x00\x00\x00\x00\xFF\xFF",
280
+ "\x00\xFF\x00\x00\x00\xFF\x00\x00", "\x00\xFF\x00\x00\x00\xFF\x00\xFF",
281
+ "\x00\xFF\x00\x00\x00\xFF\xFF\x00", "\x00\xFF\x00\x00\x00\xFF\xFF\xFF",
282
+ "\x00\xFF\x00\x00\xFF\x00\x00\x00", "\x00\xFF\x00\x00\xFF\x00\x00\xFF",
283
+ "\x00\xFF\x00\x00\xFF\x00\xFF\x00", "\x00\xFF\x00\x00\xFF\x00\xFF\xFF",
284
+ "\x00\xFF\x00\x00\xFF\xFF\x00\x00", "\x00\xFF\x00\x00\xFF\xFF\x00\xFF",
285
+ "\x00\xFF\x00\x00\xFF\xFF\xFF\x00", "\x00\xFF\x00\x00\xFF\xFF\xFF\xFF",
286
+ "\x00\xFF\x00\xFF\x00\x00\x00\x00", "\x00\xFF\x00\xFF\x00\x00\x00\xFF",
287
+ "\x00\xFF\x00\xFF\x00\x00\xFF\x00", "\x00\xFF\x00\xFF\x00\x00\xFF\xFF",
288
+ "\x00\xFF\x00\xFF\x00\xFF\x00\x00", "\x00\xFF\x00\xFF\x00\xFF\x00\xFF",
289
+ "\x00\xFF\x00\xFF\x00\xFF\xFF\x00", "\x00\xFF\x00\xFF\x00\xFF\xFF\xFF",
290
+ "\x00\xFF\x00\xFF\xFF\x00\x00\x00", "\x00\xFF\x00\xFF\xFF\x00\x00\xFF",
291
+ "\x00\xFF\x00\xFF\xFF\x00\xFF\x00", "\x00\xFF\x00\xFF\xFF\x00\xFF\xFF",
292
+ "\x00\xFF\x00\xFF\xFF\xFF\x00\x00", "\x00\xFF\x00\xFF\xFF\xFF\x00\xFF",
293
+ "\x00\xFF\x00\xFF\xFF\xFF\xFF\x00", "\x00\xFF\x00\xFF\xFF\xFF\xFF\xFF",
294
+ "\x00\xFF\xFF\x00\x00\x00\x00\x00", "\x00\xFF\xFF\x00\x00\x00\x00\xFF",
295
+ "\x00\xFF\xFF\x00\x00\x00\xFF\x00", "\x00\xFF\xFF\x00\x00\x00\xFF\xFF",
296
+ "\x00\xFF\xFF\x00\x00\xFF\x00\x00", "\x00\xFF\xFF\x00\x00\xFF\x00\xFF",
297
+ "\x00\xFF\xFF\x00\x00\xFF\xFF\x00", "\x00\xFF\xFF\x00\x00\xFF\xFF\xFF",
298
+ "\x00\xFF\xFF\x00\xFF\x00\x00\x00", "\x00\xFF\xFF\x00\xFF\x00\x00\xFF",
299
+ "\x00\xFF\xFF\x00\xFF\x00\xFF\x00", "\x00\xFF\xFF\x00\xFF\x00\xFF\xFF",
300
+ "\x00\xFF\xFF\x00\xFF\xFF\x00\x00", "\x00\xFF\xFF\x00\xFF\xFF\x00\xFF",
301
+ "\x00\xFF\xFF\x00\xFF\xFF\xFF\x00", "\x00\xFF\xFF\x00\xFF\xFF\xFF\xFF",
302
+ "\x00\xFF\xFF\xFF\x00\x00\x00\x00", "\x00\xFF\xFF\xFF\x00\x00\x00\xFF",
303
+ "\x00\xFF\xFF\xFF\x00\x00\xFF\x00", "\x00\xFF\xFF\xFF\x00\x00\xFF\xFF",
304
+ "\x00\xFF\xFF\xFF\x00\xFF\x00\x00", "\x00\xFF\xFF\xFF\x00\xFF\x00\xFF",
305
+ "\x00\xFF\xFF\xFF\x00\xFF\xFF\x00", "\x00\xFF\xFF\xFF\x00\xFF\xFF\xFF",
306
+ "\x00\xFF\xFF\xFF\xFF\x00\x00\x00", "\x00\xFF\xFF\xFF\xFF\x00\x00\xFF",
307
+ "\x00\xFF\xFF\xFF\xFF\x00\xFF\x00", "\x00\xFF\xFF\xFF\xFF\x00\xFF\xFF",
308
+ "\x00\xFF\xFF\xFF\xFF\xFF\x00\x00", "\x00\xFF\xFF\xFF\xFF\xFF\x00\xFF",
309
+ "\x00\xFF\xFF\xFF\xFF\xFF\xFF\x00", "\x00\xFF\xFF\xFF\xFF\xFF\xFF\xFF",
310
+ "\xFF\x00\x00\x00\x00\x00\x00\x00", "\xFF\x00\x00\x00\x00\x00\x00\xFF",
311
+ "\xFF\x00\x00\x00\x00\x00\xFF\x00", "\xFF\x00\x00\x00\x00\x00\xFF\xFF",
312
+ "\xFF\x00\x00\x00\x00\xFF\x00\x00", "\xFF\x00\x00\x00\x00\xFF\x00\xFF",
313
+ "\xFF\x00\x00\x00\x00\xFF\xFF\x00", "\xFF\x00\x00\x00\x00\xFF\xFF\xFF",
314
+ "\xFF\x00\x00\x00\xFF\x00\x00\x00", "\xFF\x00\x00\x00\xFF\x00\x00\xFF",
315
+ "\xFF\x00\x00\x00\xFF\x00\xFF\x00", "\xFF\x00\x00\x00\xFF\x00\xFF\xFF",
316
+ "\xFF\x00\x00\x00\xFF\xFF\x00\x00", "\xFF\x00\x00\x00\xFF\xFF\x00\xFF",
317
+ "\xFF\x00\x00\x00\xFF\xFF\xFF\x00", "\xFF\x00\x00\x00\xFF\xFF\xFF\xFF",
318
+ "\xFF\x00\x00\xFF\x00\x00\x00\x00", "\xFF\x00\x00\xFF\x00\x00\x00\xFF",
319
+ "\xFF\x00\x00\xFF\x00\x00\xFF\x00", "\xFF\x00\x00\xFF\x00\x00\xFF\xFF",
320
+ "\xFF\x00\x00\xFF\x00\xFF\x00\x00", "\xFF\x00\x00\xFF\x00\xFF\x00\xFF",
321
+ "\xFF\x00\x00\xFF\x00\xFF\xFF\x00", "\xFF\x00\x00\xFF\x00\xFF\xFF\xFF",
322
+ "\xFF\x00\x00\xFF\xFF\x00\x00\x00", "\xFF\x00\x00\xFF\xFF\x00\x00\xFF",
323
+ "\xFF\x00\x00\xFF\xFF\x00\xFF\x00", "\xFF\x00\x00\xFF\xFF\x00\xFF\xFF",
324
+ "\xFF\x00\x00\xFF\xFF\xFF\x00\x00", "\xFF\x00\x00\xFF\xFF\xFF\x00\xFF",
325
+ "\xFF\x00\x00\xFF\xFF\xFF\xFF\x00", "\xFF\x00\x00\xFF\xFF\xFF\xFF\xFF",
326
+ "\xFF\x00\xFF\x00\x00\x00\x00\x00", "\xFF\x00\xFF\x00\x00\x00\x00\xFF",
327
+ "\xFF\x00\xFF\x00\x00\x00\xFF\x00", "\xFF\x00\xFF\x00\x00\x00\xFF\xFF",
328
+ "\xFF\x00\xFF\x00\x00\xFF\x00\x00", "\xFF\x00\xFF\x00\x00\xFF\x00\xFF",
329
+ "\xFF\x00\xFF\x00\x00\xFF\xFF\x00", "\xFF\x00\xFF\x00\x00\xFF\xFF\xFF",
330
+ "\xFF\x00\xFF\x00\xFF\x00\x00\x00", "\xFF\x00\xFF\x00\xFF\x00\x00\xFF",
331
+ "\xFF\x00\xFF\x00\xFF\x00\xFF\x00", "\xFF\x00\xFF\x00\xFF\x00\xFF\xFF",
332
+ "\xFF\x00\xFF\x00\xFF\xFF\x00\x00", "\xFF\x00\xFF\x00\xFF\xFF\x00\xFF",
333
+ "\xFF\x00\xFF\x00\xFF\xFF\xFF\x00", "\xFF\x00\xFF\x00\xFF\xFF\xFF\xFF",
334
+ "\xFF\x00\xFF\xFF\x00\x00\x00\x00", "\xFF\x00\xFF\xFF\x00\x00\x00\xFF",
335
+ "\xFF\x00\xFF\xFF\x00\x00\xFF\x00", "\xFF\x00\xFF\xFF\x00\x00\xFF\xFF",
336
+ "\xFF\x00\xFF\xFF\x00\xFF\x00\x00", "\xFF\x00\xFF\xFF\x00\xFF\x00\xFF",
337
+ "\xFF\x00\xFF\xFF\x00\xFF\xFF\x00", "\xFF\x00\xFF\xFF\x00\xFF\xFF\xFF",
338
+ "\xFF\x00\xFF\xFF\xFF\x00\x00\x00", "\xFF\x00\xFF\xFF\xFF\x00\x00\xFF",
339
+ "\xFF\x00\xFF\xFF\xFF\x00\xFF\x00", "\xFF\x00\xFF\xFF\xFF\x00\xFF\xFF",
340
+ "\xFF\x00\xFF\xFF\xFF\xFF\x00\x00", "\xFF\x00\xFF\xFF\xFF\xFF\x00\xFF",
341
+ "\xFF\x00\xFF\xFF\xFF\xFF\xFF\x00", "\xFF\x00\xFF\xFF\xFF\xFF\xFF\xFF",
342
+ "\xFF\xFF\x00\x00\x00\x00\x00\x00", "\xFF\xFF\x00\x00\x00\x00\x00\xFF",
343
+ "\xFF\xFF\x00\x00\x00\x00\xFF\x00", "\xFF\xFF\x00\x00\x00\x00\xFF\xFF",
344
+ "\xFF\xFF\x00\x00\x00\xFF\x00\x00", "\xFF\xFF\x00\x00\x00\xFF\x00\xFF",
345
+ "\xFF\xFF\x00\x00\x00\xFF\xFF\x00", "\xFF\xFF\x00\x00\x00\xFF\xFF\xFF",
346
+ "\xFF\xFF\x00\x00\xFF\x00\x00\x00", "\xFF\xFF\x00\x00\xFF\x00\x00\xFF",
347
+ "\xFF\xFF\x00\x00\xFF\x00\xFF\x00", "\xFF\xFF\x00\x00\xFF\x00\xFF\xFF",
348
+ "\xFF\xFF\x00\x00\xFF\xFF\x00\x00", "\xFF\xFF\x00\x00\xFF\xFF\x00\xFF",
349
+ "\xFF\xFF\x00\x00\xFF\xFF\xFF\x00", "\xFF\xFF\x00\x00\xFF\xFF\xFF\xFF",
350
+ "\xFF\xFF\x00\xFF\x00\x00\x00\x00", "\xFF\xFF\x00\xFF\x00\x00\x00\xFF",
351
+ "\xFF\xFF\x00\xFF\x00\x00\xFF\x00", "\xFF\xFF\x00\xFF\x00\x00\xFF\xFF",
352
+ "\xFF\xFF\x00\xFF\x00\xFF\x00\x00", "\xFF\xFF\x00\xFF\x00\xFF\x00\xFF",
353
+ "\xFF\xFF\x00\xFF\x00\xFF\xFF\x00", "\xFF\xFF\x00\xFF\x00\xFF\xFF\xFF",
354
+ "\xFF\xFF\x00\xFF\xFF\x00\x00\x00", "\xFF\xFF\x00\xFF\xFF\x00\x00\xFF",
355
+ "\xFF\xFF\x00\xFF\xFF\x00\xFF\x00", "\xFF\xFF\x00\xFF\xFF\x00\xFF\xFF",
356
+ "\xFF\xFF\x00\xFF\xFF\xFF\x00\x00", "\xFF\xFF\x00\xFF\xFF\xFF\x00\xFF",
357
+ "\xFF\xFF\x00\xFF\xFF\xFF\xFF\x00", "\xFF\xFF\x00\xFF\xFF\xFF\xFF\xFF",
358
+ "\xFF\xFF\xFF\x00\x00\x00\x00\x00", "\xFF\xFF\xFF\x00\x00\x00\x00\xFF",
359
+ "\xFF\xFF\xFF\x00\x00\x00\xFF\x00", "\xFF\xFF\xFF\x00\x00\x00\xFF\xFF",
360
+ "\xFF\xFF\xFF\x00\x00\xFF\x00\x00", "\xFF\xFF\xFF\x00\x00\xFF\x00\xFF",
361
+ "\xFF\xFF\xFF\x00\x00\xFF\xFF\x00", "\xFF\xFF\xFF\x00\x00\xFF\xFF\xFF",
362
+ "\xFF\xFF\xFF\x00\xFF\x00\x00\x00", "\xFF\xFF\xFF\x00\xFF\x00\x00\xFF",
363
+ "\xFF\xFF\xFF\x00\xFF\x00\xFF\x00", "\xFF\xFF\xFF\x00\xFF\x00\xFF\xFF",
364
+ "\xFF\xFF\xFF\x00\xFF\xFF\x00\x00", "\xFF\xFF\xFF\x00\xFF\xFF\x00\xFF",
365
+ "\xFF\xFF\xFF\x00\xFF\xFF\xFF\x00", "\xFF\xFF\xFF\x00\xFF\xFF\xFF\xFF",
366
+ "\xFF\xFF\xFF\xFF\x00\x00\x00\x00", "\xFF\xFF\xFF\xFF\x00\x00\x00\xFF",
367
+ "\xFF\xFF\xFF\xFF\x00\x00\xFF\x00", "\xFF\xFF\xFF\xFF\x00\x00\xFF\xFF",
368
+ "\xFF\xFF\xFF\xFF\x00\xFF\x00\x00", "\xFF\xFF\xFF\xFF\x00\xFF\x00\xFF",
369
+ "\xFF\xFF\xFF\xFF\x00\xFF\xFF\x00", "\xFF\xFF\xFF\xFF\x00\xFF\xFF\xFF",
370
+ "\xFF\xFF\xFF\xFF\xFF\x00\x00\x00", "\xFF\xFF\xFF\xFF\xFF\x00\x00\xFF",
371
+ "\xFF\xFF\xFF\xFF\xFF\x00\xFF\x00", "\xFF\xFF\xFF\xFF\xFF\x00\xFF\xFF",
372
+ "\xFF\xFF\xFF\xFF\xFF\xFF\x00\x00", "\xFF\xFF\xFF\xFF\xFF\xFF\x00\xFF",
373
+ "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x00", "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
374
+ );
375
+
376
+ /**
377
+ * IP mapping helper table.
378
+ *
379
+ * Indexing this table with each source byte performs the initial bit permutation.
380
+ *
381
+ * @var Array
382
+ * @access private
383
+ */
384
+ var $ipmap = array(
385
+ 0x00, 0x10, 0x01, 0x11, 0x20, 0x30, 0x21, 0x31,
386
+ 0x02, 0x12, 0x03, 0x13, 0x22, 0x32, 0x23, 0x33,
387
+ 0x40, 0x50, 0x41, 0x51, 0x60, 0x70, 0x61, 0x71,
388
+ 0x42, 0x52, 0x43, 0x53, 0x62, 0x72, 0x63, 0x73,
389
+ 0x04, 0x14, 0x05, 0x15, 0x24, 0x34, 0x25, 0x35,
390
+ 0x06, 0x16, 0x07, 0x17, 0x26, 0x36, 0x27, 0x37,
391
+ 0x44, 0x54, 0x45, 0x55, 0x64, 0x74, 0x65, 0x75,
392
+ 0x46, 0x56, 0x47, 0x57, 0x66, 0x76, 0x67, 0x77,
393
+ 0x80, 0x90, 0x81, 0x91, 0xA0, 0xB0, 0xA1, 0xB1,
394
+ 0x82, 0x92, 0x83, 0x93, 0xA2, 0xB2, 0xA3, 0xB3,
395
+ 0xC0, 0xD0, 0xC1, 0xD1, 0xE0, 0xF0, 0xE1, 0xF1,
396
+ 0xC2, 0xD2, 0xC3, 0xD3, 0xE2, 0xF2, 0xE3, 0xF3,
397
+ 0x84, 0x94, 0x85, 0x95, 0xA4, 0xB4, 0xA5, 0xB5,
398
+ 0x86, 0x96, 0x87, 0x97, 0xA6, 0xB6, 0xA7, 0xB7,
399
+ 0xC4, 0xD4, 0xC5, 0xD5, 0xE4, 0xF4, 0xE5, 0xF5,
400
+ 0xC6, 0xD6, 0xC7, 0xD7, 0xE6, 0xF6, 0xE7, 0xF7,
401
+ 0x08, 0x18, 0x09, 0x19, 0x28, 0x38, 0x29, 0x39,
402
+ 0x0A, 0x1A, 0x0B, 0x1B, 0x2A, 0x3A, 0x2B, 0x3B,
403
+ 0x48, 0x58, 0x49, 0x59, 0x68, 0x78, 0x69, 0x79,
404
+ 0x4A, 0x5A, 0x4B, 0x5B, 0x6A, 0x7A, 0x6B, 0x7B,
405
+ 0x0C, 0x1C, 0x0D, 0x1D, 0x2C, 0x3C, 0x2D, 0x3D,
406
+ 0x0E, 0x1E, 0x0F, 0x1F, 0x2E, 0x3E, 0x2F, 0x3F,
407
+ 0x4C, 0x5C, 0x4D, 0x5D, 0x6C, 0x7C, 0x6D, 0x7D,
408
+ 0x4E, 0x5E, 0x4F, 0x5F, 0x6E, 0x7E, 0x6F, 0x7F,
409
+ 0x88, 0x98, 0x89, 0x99, 0xA8, 0xB8, 0xA9, 0xB9,
410
+ 0x8A, 0x9A, 0x8B, 0x9B, 0xAA, 0xBA, 0xAB, 0xBB,
411
+ 0xC8, 0xD8, 0xC9, 0xD9, 0xE8, 0xF8, 0xE9, 0xF9,
412
+ 0xCA, 0xDA, 0xCB, 0xDB, 0xEA, 0xFA, 0xEB, 0xFB,
413
+ 0x8C, 0x9C, 0x8D, 0x9D, 0xAC, 0xBC, 0xAD, 0xBD,
414
+ 0x8E, 0x9E, 0x8F, 0x9F, 0xAE, 0xBE, 0xAF, 0xBF,
415
+ 0xCC, 0xDC, 0xCD, 0xDD, 0xEC, 0xFC, 0xED, 0xFD,
416
+ 0xCE, 0xDE, 0xCF, 0xDF, 0xEE, 0xFE, 0xEF, 0xFF
417
+ );
418
+
419
+ /**
420
+ * Inverse IP mapping helper table.
421
+ * Indexing this table with a byte value reverses the bit order.
422
+ *
423
+ * @var Array
424
+ * @access private
425
+ */
426
+ var $invipmap = array(
427
+ 0x00, 0x80, 0x40, 0xC0, 0x20, 0xA0, 0x60, 0xE0,
428
+ 0x10, 0x90, 0x50, 0xD0, 0x30, 0xB0, 0x70, 0xF0,
429
+ 0x08, 0x88, 0x48, 0xC8, 0x28, 0xA8, 0x68, 0xE8,
430
+ 0x18, 0x98, 0x58, 0xD8, 0x38, 0xB8, 0x78, 0xF8,
431
+ 0x04, 0x84, 0x44, 0xC4, 0x24, 0xA4, 0x64, 0xE4,
432
+ 0x14, 0x94, 0x54, 0xD4, 0x34, 0xB4, 0x74, 0xF4,
433
+ 0x0C, 0x8C, 0x4C, 0xCC, 0x2C, 0xAC, 0x6C, 0xEC,
434
+ 0x1C, 0x9C, 0x5C, 0xDC, 0x3C, 0xBC, 0x7C, 0xFC,
435
+ 0x02, 0x82, 0x42, 0xC2, 0x22, 0xA2, 0x62, 0xE2,
436
+ 0x12, 0x92, 0x52, 0xD2, 0x32, 0xB2, 0x72, 0xF2,
437
+ 0x0A, 0x8A, 0x4A, 0xCA, 0x2A, 0xAA, 0x6A, 0xEA,
438
+ 0x1A, 0x9A, 0x5A, 0xDA, 0x3A, 0xBA, 0x7A, 0xFA,
439
+ 0x06, 0x86, 0x46, 0xC6, 0x26, 0xA6, 0x66, 0xE6,
440
+ 0x16, 0x96, 0x56, 0xD6, 0x36, 0xB6, 0x76, 0xF6,
441
+ 0x0E, 0x8E, 0x4E, 0xCE, 0x2E, 0xAE, 0x6E, 0xEE,
442
+ 0x1E, 0x9E, 0x5E, 0xDE, 0x3E, 0xBE, 0x7E, 0xFE,
443
+ 0x01, 0x81, 0x41, 0xC1, 0x21, 0xA1, 0x61, 0xE1,
444
+ 0x11, 0x91, 0x51, 0xD1, 0x31, 0xB1, 0x71, 0xF1,
445
+ 0x09, 0x89, 0x49, 0xC9, 0x29, 0xA9, 0x69, 0xE9,
446
+ 0x19, 0x99, 0x59, 0xD9, 0x39, 0xB9, 0x79, 0xF9,
447
+ 0x05, 0x85, 0x45, 0xC5, 0x25, 0xA5, 0x65, 0xE5,
448
+ 0x15, 0x95, 0x55, 0xD5, 0x35, 0xB5, 0x75, 0xF5,
449
+ 0x0D, 0x8D, 0x4D, 0xCD, 0x2D, 0xAD, 0x6D, 0xED,
450
+ 0x1D, 0x9D, 0x5D, 0xDD, 0x3D, 0xBD, 0x7D, 0xFD,
451
+ 0x03, 0x83, 0x43, 0xC3, 0x23, 0xA3, 0x63, 0xE3,
452
+ 0x13, 0x93, 0x53, 0xD3, 0x33, 0xB3, 0x73, 0xF3,
453
+ 0x0B, 0x8B, 0x4B, 0xCB, 0x2B, 0xAB, 0x6B, 0xEB,
454
+ 0x1B, 0x9B, 0x5B, 0xDB, 0x3B, 0xBB, 0x7B, 0xFB,
455
+ 0x07, 0x87, 0x47, 0xC7, 0x27, 0xA7, 0x67, 0xE7,
456
+ 0x17, 0x97, 0x57, 0xD7, 0x37, 0xB7, 0x77, 0xF7,
457
+ 0x0F, 0x8F, 0x4F, 0xCF, 0x2F, 0xAF, 0x6F, 0xEF,
458
+ 0x1F, 0x9F, 0x5F, 0xDF, 0x3F, 0xBF, 0x7F, 0xFF
459
+ );
460
+
461
+ /**
462
+ * Pre-permuted S-box1
463
+ *
464
+ * Each box ($sbox1-$sbox8) has been vectorized, then each value pre-permuted using the
465
+ * P table: concatenation can then be replaced by exclusive ORs.
466
+ *
467
+ * @var Array
468
+ * @access private
469
+ */
470
+ var $sbox1 = array(
471
+ 0x00808200, 0x00000000, 0x00008000, 0x00808202,
472
+ 0x00808002, 0x00008202, 0x00000002, 0x00008000,
473
+ 0x00000200, 0x00808200, 0x00808202, 0x00000200,
474
+ 0x00800202, 0x00808002, 0x00800000, 0x00000002,
475
+ 0x00000202, 0x00800200, 0x00800200, 0x00008200,
476
+ 0x00008200, 0x00808000, 0x00808000, 0x00800202,
477
+ 0x00008002, 0x00800002, 0x00800002, 0x00008002,
478
+ 0x00000000, 0x00000202, 0x00008202, 0x00800000,
479
+ 0x00008000, 0x00808202, 0x00000002, 0x00808000,
480
+ 0x00808200, 0x00800000, 0x00800000, 0x00000200,
481
+ 0x00808002, 0x00008000, 0x00008200, 0x00800002,
482
+ 0x00000200, 0x00000002, 0x00800202, 0x00008202,
483
+ 0x00808202, 0x00008002, 0x00808000, 0x00800202,
484
+ 0x00800002, 0x00000202, 0x00008202, 0x00808200,
485
+ 0x00000202, 0x00800200, 0x00800200, 0x00000000,
486
+ 0x00008002, 0x00008200, 0x00000000, 0x00808002
487
+ );
488
+
489
+ /**
490
+ * Pre-permuted S-box2
491
+ *
492
+ * @var Array
493
+ * @access private
494
+ */
495
+ var $sbox2 = array(
496
+ 0x40084010, 0x40004000, 0x00004000, 0x00084010,
497
+ 0x00080000, 0x00000010, 0x40080010, 0x40004010,
498
+ 0x40000010, 0x40084010, 0x40084000, 0x40000000,
499
+ 0x40004000, 0x00080000, 0x00000010, 0x40080010,
500
+ 0x00084000, 0x00080010, 0x40004010, 0x00000000,
501
+ 0x40000000, 0x00004000, 0x00084010, 0x40080000,
502
+ 0x00080010, 0x40000010, 0x00000000, 0x00084000,
503
+ 0x00004010, 0x40084000, 0x40080000, 0x00004010,
504
+ 0x00000000, 0x00084010, 0x40080010, 0x00080000,
505
+ 0x40004010, 0x40080000, 0x40084000, 0x00004000,
506
+ 0x40080000, 0x40004000, 0x00000010, 0x40084010,
507
+ 0x00084010, 0x00000010, 0x00004000, 0x40000000,
508
+ 0x00004010, 0x40084000, 0x00080000, 0x40000010,
509
+ 0x00080010, 0x40004010, 0x40000010, 0x00080010,
510
+ 0x00084000, 0x00000000, 0x40004000, 0x00004010,
511
+ 0x40000000, 0x40080010, 0x40084010, 0x00084000
512
+ );
513
+
514
+ /**
515
+ * Pre-permuted S-box3
516
+ *
517
+ * @var Array
518
+ * @access private
519
+ */
520
+ var $sbox3 = array(
521
+ 0x00000104, 0x04010100, 0x00000000, 0x04010004,
522
+ 0x04000100, 0x00000000, 0x00010104, 0x04000100,
523
+ 0x00010004, 0x04000004, 0x04000004, 0x00010000,
524
+ 0x04010104, 0x00010004, 0x04010000, 0x00000104,
525
+ 0x04000000, 0x00000004, 0x04010100, 0x00000100,
526
+ 0x00010100, 0x04010000, 0x04010004, 0x00010104,
527
+ 0x04000104, 0x00010100, 0x00010000, 0x04000104,
528
+ 0x00000004, 0x04010104, 0x00000100, 0x04000000,
529
+ 0x04010100, 0x04000000, 0x00010004, 0x00000104,
530
+ 0x00010000, 0x04010100, 0x04000100, 0x00000000,
531
+ 0x00000100, 0x00010004, 0x04010104, 0x04000100,
532
+ 0x04000004, 0x00000100, 0x00000000, 0x04010004,
533
+ 0x04000104, 0x00010000, 0x04000000, 0x04010104,
534
+ 0x00000004, 0x00010104, 0x00010100, 0x04000004,
535
+ 0x04010000, 0x04000104, 0x00000104, 0x04010000,
536
+ 0x00010104, 0x00000004, 0x04010004, 0x00010100
537
+ );
538
+
539
+ /**
540
+ * Pre-permuted S-box4
541
+ *
542
+ * @var Array
543
+ * @access private
544
+ */
545
+ var $sbox4 = array(
546
+ 0x80401000, 0x80001040, 0x80001040, 0x00000040,
547
+ 0x00401040, 0x80400040, 0x80400000, 0x80001000,
548
+ 0x00000000, 0x00401000, 0x00401000, 0x80401040,
549
+ 0x80000040, 0x00000000, 0x00400040, 0x80400000,
550
+ 0x80000000, 0x00001000, 0x00400000, 0x80401000,
551
+ 0x00000040, 0x00400000, 0x80001000, 0x00001040,
552
+ 0x80400040, 0x80000000, 0x00001040, 0x00400040,
553
+ 0x00001000, 0x00401040, 0x80401040, 0x80000040,
554
+ 0x00400040, 0x80400000, 0x00401000, 0x80401040,
555
+ 0x80000040, 0x00000000, 0x00000000, 0x00401000,
556
+ 0x00001040, 0x00400040, 0x80400040, 0x80000000,
557
+ 0x80401000, 0x80001040, 0x80001040, 0x00000040,
558
+ 0x80401040, 0x80000040, 0x80000000, 0x00001000,
559
+ 0x80400000, 0x80001000, 0x00401040, 0x80400040,
560
+ 0x80001000, 0x00001040, 0x00400000, 0x80401000,
561
+ 0x00000040, 0x00400000, 0x00001000, 0x00401040
562
+ );
563
+
564
+ /**
565
+ * Pre-permuted S-box5
566
+ *
567
+ * @var Array
568
+ * @access private
569
+ */
570
+ var $sbox5 = array(
571
+ 0x00000080, 0x01040080, 0x01040000, 0x21000080,
572
+ 0x00040000, 0x00000080, 0x20000000, 0x01040000,
573
+ 0x20040080, 0x00040000, 0x01000080, 0x20040080,
574
+ 0x21000080, 0x21040000, 0x00040080, 0x20000000,
575
+ 0x01000000, 0x20040000, 0x20040000, 0x00000000,
576
+ 0x20000080, 0x21040080, 0x21040080, 0x01000080,
577
+ 0x21040000, 0x20000080, 0x00000000, 0x21000000,
578
+ 0x01040080, 0x01000000, 0x21000000, 0x00040080,
579
+ 0x00040000, 0x21000080, 0x00000080, 0x01000000,
580
+ 0x20000000, 0x01040000, 0x21000080, 0x20040080,
581
+ 0x01000080, 0x20000000, 0x21040000, 0x01040080,
582
+ 0x20040080, 0x00000080, 0x01000000, 0x21040000,
583
+ 0x21040080, 0x00040080, 0x21000000, 0x21040080,
584
+ 0x01040000, 0x00000000, 0x20040000, 0x21000000,
585
+ 0x00040080, 0x01000080, 0x20000080, 0x00040000,
586
+ 0x00000000, 0x20040000, 0x01040080, 0x20000080
587
+ );
588
+
589
+ /**
590
+ * Pre-permuted S-box6
591
+ *
592
+ * @var Array
593
+ * @access private
594
+ */
595
+ var $sbox6 = array(
596
+ 0x10000008, 0x10200000, 0x00002000, 0x10202008,
597
+ 0x10200000, 0x00000008, 0x10202008, 0x00200000,
598
+ 0x10002000, 0x00202008, 0x00200000, 0x10000008,
599
+ 0x00200008, 0x10002000, 0x10000000, 0x00002008,
600
+ 0x00000000, 0x00200008, 0x10002008, 0x00002000,
601
+ 0x00202000, 0x10002008, 0x00000008, 0x10200008,
602
+ 0x10200008, 0x00000000, 0x00202008, 0x10202000,
603
+ 0x00002008, 0x00202000, 0x10202000, 0x10000000,
604
+ 0x10002000, 0x00000008, 0x10200008, 0x00202000,
605
+ 0x10202008, 0x00200000, 0x00002008, 0x10000008,
606
+ 0x00200000, 0x10002000, 0x10000000, 0x00002008,
607
+ 0x10000008, 0x10202008, 0x00202000, 0x10200000,
608
+ 0x00202008, 0x10202000, 0x00000000, 0x10200008,
609
+ 0x00000008, 0x00002000, 0x10200000, 0x00202008,
610
+ 0x00002000, 0x00200008, 0x10002008, 0x00000000,
611
+ 0x10202000, 0x10000000, 0x00200008, 0x10002008
612
+ );
613
+
614
+ /**
615
+ * Pre-permuted S-box7
616
+ *
617
+ * @var Array
618
+ * @access private
619
+ */
620
+ var $sbox7 = array(
621
+ 0x00100000, 0x02100001, 0x02000401, 0x00000000,
622
+ 0x00000400, 0x02000401, 0x00100401, 0x02100400,
623
+ 0x02100401, 0x00100000, 0x00000000, 0x02000001,
624
+ 0x00000001, 0x02000000, 0x02100001, 0x00000401,
625
+ 0x02000400, 0x00100401, 0x00100001, 0x02000400,
626
+ 0x02000001, 0x02100000, 0x02100400, 0x00100001,
627
+ 0x02100000, 0x00000400, 0x00000401, 0x02100401,
628
+ 0x00100400, 0x00000001, 0x02000000, 0x00100400,
629
+ 0x02000000, 0x00100400, 0x00100000, 0x02000401,
630
+ 0x02000401, 0x02100001, 0x02100001, 0x00000001,
631
+ 0x00100001, 0x02000000, 0x02000400, 0x00100000,
632
+ 0x02100400, 0x00000401, 0x00100401, 0x02100400,
633
+ 0x00000401, 0x02000001, 0x02100401, 0x02100000,
634
+ 0x00100400, 0x00000000, 0x00000001, 0x02100401,
635
+ 0x00000000, 0x00100401, 0x02100000, 0x00000400,
636
+ 0x02000001, 0x02000400, 0x00000400, 0x00100001
637
+ );
638
+
639
+ /**
640
+ * Pre-permuted S-box8
641
+ *
642
+ * @var Array
643
+ * @access private
644
+ */
645
+ var $sbox8 = array(
646
+ 0x08000820, 0x00000800, 0x00020000, 0x08020820,
647
+ 0x08000000, 0x08000820, 0x00000020, 0x08000000,
648
+ 0x00020020, 0x08020000, 0x08020820, 0x00020800,
649
+ 0x08020800, 0x00020820, 0x00000800, 0x00000020,
650
+ 0x08020000, 0x08000020, 0x08000800, 0x00000820,
651
+ 0x00020800, 0x00020020, 0x08020020, 0x08020800,
652
+ 0x00000820, 0x00000000, 0x00000000, 0x08020020,
653
+ 0x08000020, 0x08000800, 0x00020820, 0x00020000,
654
+ 0x00020820, 0x00020000, 0x08020800, 0x00000800,
655
+ 0x00000020, 0x08020020, 0x00000800, 0x00020820,
656
+ 0x08000800, 0x00000020, 0x08000020, 0x08020000,
657
+ 0x08020020, 0x08000000, 0x00020000, 0x08000820,
658
+ 0x00000000, 0x08020820, 0x00020020, 0x08000020,
659
+ 0x08020000, 0x08000800, 0x08000820, 0x00000000,
660
+ 0x08020820, 0x00020800, 0x00020800, 0x00000820,
661
+ 0x00000820, 0x00020020, 0x08000000, 0x08020800
662
+ );
663
+
664
+ /**
665
+ * Sets the key.
666
+ *
667
+ * Keys can be of any length. DES, itself, uses 64-bit keys (eg. strlen($key) == 8), however, we
668
+ * only use the first eight, if $key has more then eight characters in it, and pad $key with the
669
+ * null byte if it is less then eight characters long.
670
+ *
671
+ * DES also requires that every eighth bit be a parity bit, however, we'll ignore that.
672
+ *
673
+ * If the key is not explicitly set, it'll be assumed to be all zero's.
674
+ *
675
+ * @see Crypt_Base::setKey()
676
+ * @access public
677
+ * @param String $key
678
+ */
679
+ function setKey($key)
680
+ {
681
+ // We check/cut here only up to max length of the key.
682
+ // Key padding to the proper length will be done in _setupKey()
683
+ if (strlen($key) > $this->key_size_max) {
684
+ $key = substr($key, 0, $this->key_size_max);
685
+ }
686
+
687
+ // Sets the key
688
+ parent::setKey($key);
689
+ }
690
+
691
+ /**
692
+ * Encrypts a block
693
+ *
694
+ * @see Crypt_Base::_encryptBlock()
695
+ * @see Crypt_Base::encrypt()
696
+ * @see Crypt_DES::encrypt()
697
+ * @access private
698
+ * @param String $in
699
+ * @return String
700
+ */
701
+ function _encryptBlock($in)
702
+ {
703
+ return $this->_processBlock($in, CRYPT_DES_ENCRYPT);
704
+ }
705
+
706
+ /**
707
+ * Decrypts a block
708
+ *
709
+ * @see Crypt_Base::_decryptBlock()
710
+ * @see Crypt_Base::decrypt()
711
+ * @see Crypt_DES::decrypt()
712
+ * @access private
713
+ * @param String $in
714
+ * @return String
715
+ */
716
+ function _decryptBlock($in)
717
+ {
718
+ return $this->_processBlock($in, CRYPT_DES_DECRYPT);
719
+ }
720
+
721
+ /**
722
+ * Encrypts or decrypts a 64-bit block
723
+ *
724
+ * $mode should be either CRYPT_DES_ENCRYPT or CRYPT_DES_DECRYPT. See
725
+ * {@link http://en.wikipedia.org/wiki/Image:Feistel.png Feistel.png} to get a general
726
+ * idea of what this function does.
727
+ *
728
+ * @see Crypt_DES::_encryptBlock()
729
+ * @see Crypt_DES::_decryptBlock()
730
+ * @access private
731
+ * @param String $block
732
+ * @param Integer $mode
733
+ * @return String
734
+ */
735
+ function _processBlock($block, $mode)
736
+ {
737
+ static $sbox1, $sbox2, $sbox3, $sbox4, $sbox5, $sbox6, $sbox7, $sbox8, $shuffleip, $shuffleinvip;
738
+ if (!$sbox1) {
739
+ $sbox1 = array_map("intval", $this->sbox1);
740
+ $sbox2 = array_map("intval", $this->sbox2);
741
+ $sbox3 = array_map("intval", $this->sbox3);
742
+ $sbox4 = array_map("intval", $this->sbox4);
743
+ $sbox5 = array_map("intval", $this->sbox5);
744
+ $sbox6 = array_map("intval", $this->sbox6);
745
+ $sbox7 = array_map("intval", $this->sbox7);
746
+ $sbox8 = array_map("intval", $this->sbox8);
747
+ /* Merge $shuffle with $[inv]ipmap */
748
+ for ($i = 0; $i < 256; ++$i) {
749
+ $shuffleip[] = $this->shuffle[$this->ipmap[$i]];
750
+ $shuffleinvip[] = $this->shuffle[$this->invipmap[$i]];
751
+ }
752
+ }
753
+
754
+ $keys = $this->keys[$mode];
755
+ $ki = -1;
756
+
757
+ // Do the initial IP permutation.
758
+ $t = unpack('Nl/Nr', $block);
759
+ list($l, $r) = array($t['l'], $t['r']);
760
+ $block = ($shuffleip[ $r & 0xFF] & "\x80\x80\x80\x80\x80\x80\x80\x80") |
761
+ ($shuffleip[($r >> 8) & 0xFF] & "\x40\x40\x40\x40\x40\x40\x40\x40") |
762
+ ($shuffleip[($r >> 16) & 0xFF] & "\x20\x20\x20\x20\x20\x20\x20\x20") |
763
+ ($shuffleip[($r >> 24) & 0xFF] & "\x10\x10\x10\x10\x10\x10\x10\x10") |
764
+ ($shuffleip[ $l & 0xFF] & "\x08\x08\x08\x08\x08\x08\x08\x08") |
765
+ ($shuffleip[($l >> 8) & 0xFF] & "\x04\x04\x04\x04\x04\x04\x04\x04") |
766
+ ($shuffleip[($l >> 16) & 0xFF] & "\x02\x02\x02\x02\x02\x02\x02\x02") |
767
+ ($shuffleip[($l >> 24) & 0xFF] & "\x01\x01\x01\x01\x01\x01\x01\x01");
768
+
769
+ // Extract L0 and R0.
770
+ $t = unpack('Nl/Nr', $block);
771
+ list($l, $r) = array($t['l'], $t['r']);
772
+
773
+ for ($des_round = 0; $des_round < $this->des_rounds; ++$des_round) {
774
+ // Perform the 16 steps.
775
+ for ($i = 0; $i < 16; $i++) {
776
+ // start of "the Feistel (F) function" - see the following URL:
777
+ // http://en.wikipedia.org/wiki/Image:Data_Encryption_Standard_InfoBox_Diagram.png
778
+ // Merge key schedule.
779
+ $b1 = (($r >> 3) & 0x1FFFFFFF) ^ ($r << 29) ^ $keys[++$ki];
780
+ $b2 = (($r >> 31) & 0x00000001) ^ ($r << 1) ^ $keys[++$ki];
781
+
782
+ // S-box indexing.
783
+ $t = $sbox1[($b1 >> 24) & 0x3F] ^ $sbox2[($b2 >> 24) & 0x3F] ^
784
+ $sbox3[($b1 >> 16) & 0x3F] ^ $sbox4[($b2 >> 16) & 0x3F] ^
785
+ $sbox5[($b1 >> 8) & 0x3F] ^ $sbox6[($b2 >> 8) & 0x3F] ^
786
+ $sbox7[ $b1 & 0x3F] ^ $sbox8[ $b2 & 0x3F] ^ $l;
787
+ // end of "the Feistel (F) function"
788
+
789
+ $l = $r;
790
+ $r = $t;
791
+ }
792
+
793
+ // Last step should not permute L & R.
794
+ $t = $l;
795
+ $l = $r;
796
+ $r = $t;
797
+ }
798
+
799
+ // Perform the inverse IP permutation.
800
+ return ($shuffleinvip[($r >> 24) & 0xFF] & "\x80\x80\x80\x80\x80\x80\x80\x80") |
801
+ ($shuffleinvip[($l >> 24) & 0xFF] & "\x40\x40\x40\x40\x40\x40\x40\x40") |
802
+ ($shuffleinvip[($r >> 16) & 0xFF] & "\x20\x20\x20\x20\x20\x20\x20\x20") |
803
+ ($shuffleinvip[($l >> 16) & 0xFF] & "\x10\x10\x10\x10\x10\x10\x10\x10") |
804
+ ($shuffleinvip[($r >> 8) & 0xFF] & "\x08\x08\x08\x08\x08\x08\x08\x08") |
805
+ ($shuffleinvip[($l >> 8) & 0xFF] & "\x04\x04\x04\x04\x04\x04\x04\x04") |
806
+ ($shuffleinvip[ $r & 0xFF] & "\x02\x02\x02\x02\x02\x02\x02\x02") |
807
+ ($shuffleinvip[ $l & 0xFF] & "\x01\x01\x01\x01\x01\x01\x01\x01");
808
+ }
809
+
810
+ /**
811
+ * Creates the key schedule
812
+ *
813
+ * @see Crypt_Base::_setupKey()
814
+ * @access private
815
+ */
816
+ function _setupKey()
817
+ {
818
+ if (isset($this->kl['key']) && $this->key === $this->kl['key'] && $this->des_rounds === $this->kl['des_rounds']) {
819
+ // already expanded
820
+ return;
821
+ }
822
+ $this->kl = array('key' => $this->key, 'des_rounds' => $this->des_rounds);
823
+
824
+ static $shifts = array( // number of key bits shifted per round
825
+ 1, 1, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 1
826
+ );
827
+
828
+ static $pc1map = array(
829
+ 0x00, 0x00, 0x08, 0x08, 0x04, 0x04, 0x0C, 0x0C,
830
+ 0x02, 0x02, 0x0A, 0x0A, 0x06, 0x06, 0x0E, 0x0E,
831
+ 0x10, 0x10, 0x18, 0x18, 0x14, 0x14, 0x1C, 0x1C,
832
+ 0x12, 0x12, 0x1A, 0x1A, 0x16, 0x16, 0x1E, 0x1E,
833
+ 0x20, 0x20, 0x28, 0x28, 0x24, 0x24, 0x2C, 0x2C,
834
+ 0x22, 0x22, 0x2A, 0x2A, 0x26, 0x26, 0x2E, 0x2E,
835
+ 0x30, 0x30, 0x38, 0x38, 0x34, 0x34, 0x3C, 0x3C,
836
+ 0x32, 0x32, 0x3A, 0x3A, 0x36, 0x36, 0x3E, 0x3E,
837
+ 0x40, 0x40, 0x48, 0x48, 0x44, 0x44, 0x4C, 0x4C,
838
+ 0x42, 0x42, 0x4A, 0x4A, 0x46, 0x46, 0x4E, 0x4E,
839
+ 0x50, 0x50, 0x58, 0x58, 0x54, 0x54, 0x5C, 0x5C,
840
+ 0x52, 0x52, 0x5A, 0x5A, 0x56, 0x56, 0x5E, 0x5E,
841
+ 0x60, 0x60, 0x68, 0x68, 0x64, 0x64, 0x6C, 0x6C,
842
+ 0x62, 0x62, 0x6A, 0x6A, 0x66, 0x66, 0x6E, 0x6E,
843
+ 0x70, 0x70, 0x78, 0x78, 0x74, 0x74, 0x7C, 0x7C,
844
+ 0x72, 0x72, 0x7A, 0x7A, 0x76, 0x76, 0x7E, 0x7E,
845
+ 0x80, 0x80, 0x88, 0x88, 0x84, 0x84, 0x8C, 0x8C,
846
+ 0x82, 0x82, 0x8A, 0x8A, 0x86, 0x86, 0x8E, 0x8E,
847
+ 0x90, 0x90, 0x98, 0x98, 0x94, 0x94, 0x9C, 0x9C,
848
+ 0x92, 0x92, 0x9A, 0x9A, 0x96, 0x96, 0x9E, 0x9E,
849
+ 0xA0, 0xA0, 0xA8, 0xA8, 0xA4, 0xA4, 0xAC, 0xAC,
850
+ 0xA2, 0xA2, 0xAA, 0xAA, 0xA6, 0xA6, 0xAE, 0xAE,
851
+ 0xB0, 0xB0, 0xB8, 0xB8, 0xB4, 0xB4, 0xBC, 0xBC,
852
+ 0xB2, 0xB2, 0xBA, 0xBA, 0xB6, 0xB6, 0xBE, 0xBE,
853
+ 0xC0, 0xC0, 0xC8, 0xC8, 0xC4, 0xC4, 0xCC, 0xCC,
854
+ 0xC2, 0xC2, 0xCA, 0xCA, 0xC6, 0xC6, 0xCE, 0xCE,
855
+ 0xD0, 0xD0, 0xD8, 0xD8, 0xD4, 0xD4, 0xDC, 0xDC,
856
+ 0xD2, 0xD2, 0xDA, 0xDA, 0xD6, 0xD6, 0xDE, 0xDE,
857
+ 0xE0, 0xE0, 0xE8, 0xE8, 0xE4, 0xE4, 0xEC, 0xEC,
858
+ 0xE2, 0xE2, 0xEA, 0xEA, 0xE6, 0xE6, 0xEE, 0xEE,
859
+ 0xF0, 0xF0, 0xF8, 0xF8, 0xF4, 0xF4, 0xFC, 0xFC,
860
+ 0xF2, 0xF2, 0xFA, 0xFA, 0xF6, 0xF6, 0xFE, 0xFE
861
+ );
862
+
863
+ // Mapping tables for the PC-2 transformation.
864
+ static $pc2mapc1 = array(
865
+ 0x00000000, 0x00000400, 0x00200000, 0x00200400,
866
+ 0x00000001, 0x00000401, 0x00200001, 0x00200401,
867
+ 0x02000000, 0x02000400, 0x02200000, 0x02200400,
868
+ 0x02000001, 0x02000401, 0x02200001, 0x02200401
869
+ );
870
+ static $pc2mapc2 = array(
871
+ 0x00000000, 0x00000800, 0x08000000, 0x08000800,
872
+ 0x00010000, 0x00010800, 0x08010000, 0x08010800,
873
+ 0x00000000, 0x00000800, 0x08000000, 0x08000800,
874
+ 0x00010000, 0x00010800, 0x08010000, 0x08010800,
875
+ 0x00000100, 0x00000900, 0x08000100, 0x08000900,
876
+ 0x00010100, 0x00010900, 0x08010100, 0x08010900,
877
+ 0x00000100, 0x00000900, 0x08000100, 0x08000900,
878
+ 0x00010100, 0x00010900, 0x08010100, 0x08010900,
879
+ 0x00000010, 0x00000810, 0x08000010, 0x08000810,
880
+ 0x00010010, 0x00010810, 0x08010010, 0x08010810,
881
+ 0x00000010, 0x00000810, 0x08000010, 0x08000810,
882
+ 0x00010010, 0x00010810, 0x08010010, 0x08010810,
883
+ 0x00000110, 0x00000910, 0x08000110, 0x08000910,
884
+ 0x00010110, 0x00010910, 0x08010110, 0x08010910,
885
+ 0x00000110, 0x00000910, 0x08000110, 0x08000910,
886
+ 0x00010110, 0x00010910, 0x08010110, 0x08010910,
887
+ 0x00040000, 0x00040800, 0x08040000, 0x08040800,
888
+ 0x00050000, 0x00050800, 0x08050000, 0x08050800,
889
+ 0x00040000, 0x00040800, 0x08040000, 0x08040800,
890
+ 0x00050000, 0x00050800, 0x08050000, 0x08050800,
891
+ 0x00040100, 0x00040900, 0x08040100, 0x08040900,
892
+ 0x00050100, 0x00050900, 0x08050100, 0x08050900,
893
+ 0x00040100, 0x00040900, 0x08040100, 0x08040900,
894
+ 0x00050100, 0x00050900, 0x08050100, 0x08050900,
895
+ 0x00040010, 0x00040810, 0x08040010, 0x08040810,
896
+ 0x00050010, 0x00050810, 0x08050010, 0x08050810,
897
+ 0x00040010, 0x00040810, 0x08040010, 0x08040810,
898
+ 0x00050010, 0x00050810, 0x08050010, 0x08050810,
899
+ 0x00040110, 0x00040910, 0x08040110, 0x08040910,
900
+ 0x00050110, 0x00050910, 0x08050110, 0x08050910,
901
+ 0x00040110, 0x00040910, 0x08040110, 0x08040910,
902
+ 0x00050110, 0x00050910, 0x08050110, 0x08050910,
903
+ 0x01000000, 0x01000800, 0x09000000, 0x09000800,
904
+ 0x01010000, 0x01010800, 0x09010000, 0x09010800,
905
+ 0x01000000, 0x01000800, 0x09000000, 0x09000800,
906
+ 0x01010000, 0x01010800, 0x09010000, 0x09010800,
907
+ 0x01000100, 0x01000900, 0x09000100, 0x09000900,
908
+ 0x01010100, 0x01010900, 0x09010100, 0x09010900,
909
+ 0x01000100, 0x01000900, 0x09000100, 0x09000900,
910
+ 0x01010100, 0x01010900, 0x09010100, 0x09010900,
911
+ 0x01000010, 0x01000810, 0x09000010, 0x09000810,
912
+ 0x01010010, 0x01010810, 0x09010010, 0x09010810,
913
+ 0x01000010, 0x01000810, 0x09000010, 0x09000810,
914
+ 0x01010010, 0x01010810, 0x09010010, 0x09010810,
915
+ 0x01000110, 0x01000910, 0x09000110, 0x09000910,
916
+ 0x01010110, 0x01010910, 0x09010110, 0x09010910,
917
+ 0x01000110, 0x01000910, 0x09000110, 0x09000910,
918
+ 0x01010110, 0x01010910, 0x09010110, 0x09010910,
919
+ 0x01040000, 0x01040800, 0x09040000, 0x09040800,
920
+ 0x01050000, 0x01050800, 0x09050000, 0x09050800,
921
+ 0x01040000, 0x01040800, 0x09040000, 0x09040800,
922
+ 0x01050000, 0x01050800, 0x09050000, 0x09050800,
923
+ 0x01040100, 0x01040900, 0x09040100, 0x09040900,
924
+ 0x01050100, 0x01050900, 0x09050100, 0x09050900,
925
+ 0x01040100, 0x01040900, 0x09040100, 0x09040900,
926
+ 0x01050100, 0x01050900, 0x09050100, 0x09050900,
927
+ 0x01040010, 0x01040810, 0x09040010, 0x09040810,
928
+ 0x01050010, 0x01050810, 0x09050010, 0x09050810,
929
+ 0x01040010, 0x01040810, 0x09040010, 0x09040810,
930
+ 0x01050010, 0x01050810, 0x09050010, 0x09050810,
931
+ 0x01040110, 0x01040910, 0x09040110, 0x09040910,
932
+ 0x01050110, 0x01050910, 0x09050110, 0x09050910,
933
+ 0x01040110, 0x01040910, 0x09040110, 0x09040910,
934
+ 0x01050110, 0x01050910, 0x09050110, 0x09050910
935
+ );
936
+ static $pc2mapc3 = array(
937
+ 0x00000000, 0x00000004, 0x00001000, 0x00001004,
938
+ 0x00000000, 0x00000004, 0x00001000, 0x00001004,
939
+ 0x10000000, 0x10000004, 0x10001000, 0x10001004,
940
+ 0x10000000, 0x10000004, 0x10001000, 0x10001004,
941
+ 0x00000020, 0x00000024, 0x00001020, 0x00001024,
942
+ 0x00000020, 0x00000024, 0x00001020, 0x00001024,
943
+ 0x10000020, 0x10000024, 0x10001020, 0x10001024,
944
+ 0x10000020, 0x10000024, 0x10001020, 0x10001024,
945
+ 0x00080000, 0x00080004, 0x00081000, 0x00081004,
946
+ 0x00080000, 0x00080004, 0x00081000, 0x00081004,
947
+ 0x10080000, 0x10080004, 0x10081000, 0x10081004,
948
+ 0x10080000, 0x10080004, 0x10081000, 0x10081004,
949
+ 0x00080020, 0x00080024, 0x00081020, 0x00081024,
950
+ 0x00080020, 0x00080024, 0x00081020, 0x00081024,
951
+ 0x10080020, 0x10080024, 0x10081020, 0x10081024,
952
+ 0x10080020, 0x10080024, 0x10081020, 0x10081024,
953
+ 0x20000000, 0x20000004, 0x20001000, 0x20001004,
954
+ 0x20000000, 0x20000004, 0x20001000, 0x20001004,
955
+ 0x30000000, 0x30000004, 0x30001000, 0x30001004,
956
+ 0x30000000, 0x30000004, 0x30001000, 0x30001004,
957
+ 0x20000020, 0x20000024, 0x20001020, 0x20001024,
958
+ 0x20000020, 0x20000024, 0x20001020, 0x20001024,
959
+ 0x30000020, 0x30000024, 0x30001020, 0x30001024,
960
+ 0x30000020, 0x30000024, 0x30001020, 0x30001024,
961
+ 0x20080000, 0x20080004, 0x20081000, 0x20081004,
962
+ 0x20080000, 0x20080004, 0x20081000, 0x20081004,
963
+ 0x30080000, 0x30080004, 0x30081000, 0x30081004,
964
+ 0x30080000, 0x30080004, 0x30081000, 0x30081004,
965
+ 0x20080020, 0x20080024, 0x20081020, 0x20081024,
966
+ 0x20080020, 0x20080024, 0x20081020, 0x20081024,
967
+ 0x30080020, 0x30080024, 0x30081020, 0x30081024,
968
+ 0x30080020, 0x30080024, 0x30081020, 0x30081024,
969
+ 0x00000002, 0x00000006, 0x00001002, 0x00001006,
970
+ 0x00000002, 0x00000006, 0x00001002, 0x00001006,
971
+ 0x10000002, 0x10000006, 0x10001002, 0x10001006,
972
+ 0x10000002, 0x10000006, 0x10001002, 0x10001006,
973
+ 0x00000022, 0x00000026, 0x00001022, 0x00001026,
974
+ 0x00000022, 0x00000026, 0x00001022, 0x00001026,
975
+ 0x10000022, 0x10000026, 0x10001022, 0x10001026,
976
+ 0x10000022, 0x10000026, 0x10001022, 0x10001026,
977
+ 0x00080002, 0x00080006, 0x00081002, 0x00081006,
978
+ 0x00080002, 0x00080006, 0x00081002, 0x00081006,
979
+ 0x10080002, 0x10080006, 0x10081002, 0x10081006,
980
+ 0x10080002, 0x10080006, 0x10081002, 0x10081006,
981
+ 0x00080022, 0x00080026, 0x00081022, 0x00081026,
982
+ 0x00080022, 0x00080026, 0x00081022, 0x00081026,
983
+ 0x10080022, 0x10080026, 0x10081022, 0x10081026,
984
+ 0x10080022, 0x10080026, 0x10081022, 0x10081026,
985
+ 0x20000002, 0x20000006, 0x20001002, 0x20001006,
986
+ 0x20000002, 0x20000006, 0x20001002, 0x20001006,
987
+ 0x30000002, 0x30000006, 0x30001002, 0x30001006,
988
+ 0x30000002, 0x30000006, 0x30001002, 0x30001006,
989
+ 0x20000022, 0x20000026, 0x20001022, 0x20001026,
990
+ 0x20000022, 0x20000026, 0x20001022, 0x20001026,
991
+ 0x30000022, 0x30000026, 0x30001022, 0x30001026,
992
+ 0x30000022, 0x30000026, 0x30001022, 0x30001026,
993
+ 0x20080002, 0x20080006, 0x20081002, 0x20081006,
994
+ 0x20080002, 0x20080006, 0x20081002, 0x20081006,
995
+ 0x30080002, 0x30080006, 0x30081002, 0x30081006,
996
+ 0x30080002, 0x30080006, 0x30081002, 0x30081006,
997
+ 0x20080022, 0x20080026, 0x20081022, 0x20081026,
998
+ 0x20080022, 0x20080026, 0x20081022, 0x20081026,
999
+ 0x30080022, 0x30080026, 0x30081022, 0x30081026,
1000
+ 0x30080022, 0x30080026, 0x30081022, 0x30081026
1001
+ );
1002
+ static $pc2mapc4 = array(
1003
+ 0x00000000, 0x00100000, 0x00000008, 0x00100008,
1004
+ 0x00000200, 0x00100200, 0x00000208, 0x00100208,
1005
+ 0x00000000, 0x00100000, 0x00000008, 0x00100008,
1006
+ 0x00000200, 0x00100200, 0x00000208, 0x00100208,
1007
+ 0x04000000, 0x04100000, 0x04000008, 0x04100008,
1008
+ 0x04000200, 0x04100200, 0x04000208, 0x04100208,
1009
+ 0x04000000, 0x04100000, 0x04000008, 0x04100008,
1010
+ 0x04000200, 0x04100200, 0x04000208, 0x04100208,
1011
+ 0x00002000, 0x00102000, 0x00002008, 0x00102008,
1012
+ 0x00002200, 0x00102200, 0x00002208, 0x00102208,
1013
+ 0x00002000, 0x00102000, 0x00002008, 0x00102008,
1014
+ 0x00002200, 0x00102200, 0x00002208, 0x00102208,
1015
+ 0x04002000, 0x04102000, 0x04002008, 0x04102008,
1016
+ 0x04002200, 0x04102200, 0x04002208, 0x04102208,
1017
+ 0x04002000, 0x04102000, 0x04002008, 0x04102008,
1018
+ 0x04002200, 0x04102200, 0x04002208, 0x04102208,
1019
+ 0x00000000, 0x00100000, 0x00000008, 0x00100008,
1020
+ 0x00000200, 0x00100200, 0x00000208, 0x00100208,
1021
+ 0x00000000, 0x00100000, 0x00000008, 0x00100008,
1022
+ 0x00000200, 0x00100200, 0x00000208, 0x00100208,
1023
+ 0x04000000, 0x04100000, 0x04000008, 0x04100008,
1024
+ 0x04000200, 0x04100200, 0x04000208, 0x04100208,
1025
+ 0x04000000, 0x04100000, 0x04000008, 0x04100008,
1026
+ 0x04000200, 0x04100200, 0x04000208, 0x04100208,
1027
+ 0x00002000, 0x00102000, 0x00002008, 0x00102008,
1028
+ 0x00002200, 0x00102200, 0x00002208, 0x00102208,
1029
+ 0x00002000, 0x00102000, 0x00002008, 0x00102008,
1030
+ 0x00002200, 0x00102200, 0x00002208, 0x00102208,
1031
+ 0x04002000, 0x04102000, 0x04002008, 0x04102008,
1032
+ 0x04002200, 0x04102200, 0x04002208, 0x04102208,
1033
+ 0x04002000, 0x04102000, 0x04002008, 0x04102008,
1034
+ 0x04002200, 0x04102200, 0x04002208, 0x04102208,
1035
+ 0x00020000, 0x00120000, 0x00020008, 0x00120008,
1036
+ 0x00020200, 0x00120200, 0x00020208, 0x00120208,
1037
+ 0x00020000, 0x00120000, 0x00020008, 0x00120008,
1038
+ 0x00020200, 0x00120200, 0x00020208, 0x00120208,
1039
+ 0x04020000, 0x04120000, 0x04020008, 0x04120008,
1040
+ 0x04020200, 0x04120200, 0x04020208, 0x04120208,
1041
+ 0x04020000, 0x04120000, 0x04020008, 0x04120008,
1042
+ 0x04020200, 0x04120200, 0x04020208, 0x04120208,
1043
+ 0x00022000, 0x00122000, 0x00022008, 0x00122008,
1044
+ 0x00022200, 0x00122200, 0x00022208, 0x00122208,
1045
+ 0x00022000, 0x00122000, 0x00022008, 0x00122008,
1046
+ 0x00022200, 0x00122200, 0x00022208, 0x00122208,
1047
+ 0x04022000, 0x04122000, 0x04022008, 0x04122008,
1048
+ 0x04022200, 0x04122200, 0x04022208, 0x04122208,
1049
+ 0x04022000, 0x04122000, 0x04022008, 0x04122008,
1050
+ 0x04022200, 0x04122200, 0x04022208, 0x04122208,
1051
+ 0x00020000, 0x00120000, 0x00020008, 0x00120008,
1052
+ 0x00020200, 0x00120200, 0x00020208, 0x00120208,
1053
+ 0x00020000, 0x00120000, 0x00020008, 0x00120008,
1054
+ 0x00020200, 0x00120200, 0x00020208, 0x00120208,
1055
+ 0x04020000, 0x04120000, 0x04020008, 0x04120008,
1056
+ 0x04020200, 0x04120200, 0x04020208, 0x04120208,
1057
+ 0x04020000, 0x04120000, 0x04020008, 0x04120008,
1058
+ 0x04020200, 0x04120200, 0x04020208, 0x04120208,
1059
+ 0x00022000, 0x00122000, 0x00022008, 0x00122008,
1060
+ 0x00022200, 0x00122200, 0x00022208, 0x00122208,
1061
+ 0x00022000, 0x00122000, 0x00022008, 0x00122008,
1062
+ 0x00022200, 0x00122200, 0x00022208, 0x00122208,
1063
+ 0x04022000, 0x04122000, 0x04022008, 0x04122008,
1064
+ 0x04022200, 0x04122200, 0x04022208, 0x04122208,
1065
+ 0x04022000, 0x04122000, 0x04022008, 0x04122008,
1066
+ 0x04022200, 0x04122200, 0x04022208, 0x04122208
1067
+ );
1068
+ static $pc2mapd1 = array(
1069
+ 0x00000000, 0x00000001, 0x08000000, 0x08000001,
1070
+ 0x00200000, 0x00200001, 0x08200000, 0x08200001,
1071
+ 0x00000002, 0x00000003, 0x08000002, 0x08000003,
1072
+ 0x00200002, 0x00200003, 0x08200002, 0x08200003
1073
+ );
1074
+ static $pc2mapd2 = array(
1075
+ 0x00000000, 0x00100000, 0x00000800, 0x00100800,
1076
+ 0x00000000, 0x00100000, 0x00000800, 0x00100800,
1077
+ 0x04000000, 0x04100000, 0x04000800, 0x04100800,
1078
+ 0x04000000, 0x04100000, 0x04000800, 0x04100800,
1079
+ 0x00000004, 0x00100004, 0x00000804, 0x00100804,
1080
+ 0x00000004, 0x00100004, 0x00000804, 0x00100804,
1081
+ 0x04000004, 0x04100004, 0x04000804, 0x04100804,
1082
+ 0x04000004, 0x04100004, 0x04000804, 0x04100804,
1083
+ 0x00000000, 0x00100000, 0x00000800, 0x00100800,
1084
+ 0x00000000, 0x00100000, 0x00000800, 0x00100800,
1085
+ 0x04000000, 0x04100000, 0x04000800, 0x04100800,
1086
+ 0x04000000, 0x04100000, 0x04000800, 0x04100800,
1087
+ 0x00000004, 0x00100004, 0x00000804, 0x00100804,
1088
+ 0x00000004, 0x00100004, 0x00000804, 0x00100804,
1089
+ 0x04000004, 0x04100004, 0x04000804, 0x04100804,
1090
+ 0x04000004, 0x04100004, 0x04000804, 0x04100804,
1091
+ 0x00000200, 0x00100200, 0x00000A00, 0x00100A00,
1092
+ 0x00000200, 0x00100200, 0x00000A00, 0x00100A00,
1093
+ 0x04000200, 0x04100200, 0x04000A00, 0x04100A00,
1094
+ 0x04000200, 0x04100200, 0x04000A00, 0x04100A00,
1095
+ 0x00000204, 0x00100204, 0x00000A04, 0x00100A04,
1096
+ 0x00000204, 0x00100204, 0x00000A04, 0x00100A04,
1097
+ 0x04000204, 0x04100204, 0x04000A04, 0x04100A04,
1098
+ 0x04000204, 0x04100204, 0x04000A04, 0x04100A04,
1099
+ 0x00000200, 0x00100200, 0x00000A00, 0x00100A00,
1100
+ 0x00000200, 0x00100200, 0x00000A00, 0x00100A00,
1101
+ 0x04000200, 0x04100200, 0x04000A00, 0x04100A00,
1102
+ 0x04000200, 0x04100200, 0x04000A00, 0x04100A00,
1103
+ 0x00000204, 0x00100204, 0x00000A04, 0x00100A04,
1104
+ 0x00000204, 0x00100204, 0x00000A04, 0x00100A04,
1105
+ 0x04000204, 0x04100204, 0x04000A04, 0x04100A04,
1106
+ 0x04000204, 0x04100204, 0x04000A04, 0x04100A04,
1107
+ 0x00020000, 0x00120000, 0x00020800, 0x00120800,
1108
+ 0x00020000, 0x00120000, 0x00020800, 0x00120800,
1109
+ 0x04020000, 0x04120000, 0x04020800, 0x04120800,
1110
+ 0x04020000, 0x04120000, 0x04020800, 0x04120800,
1111
+ 0x00020004, 0x00120004, 0x00020804, 0x00120804,
1112
+ 0x00020004, 0x00120004, 0x00020804, 0x00120804,
1113
+ 0x04020004, 0x04120004, 0x04020804, 0x04120804,
1114
+ 0x04020004, 0x04120004, 0x04020804, 0x04120804,
1115
+ 0x00020000, 0x00120000, 0x00020800, 0x00120800,
1116
+ 0x00020000, 0x00120000, 0x00020800, 0x00120800,
1117
+ 0x04020000, 0x04120000, 0x04020800, 0x04120800,
1118
+ 0x04020000, 0x04120000, 0x04020800, 0x04120800,
1119
+ 0x00020004, 0x00120004, 0x00020804, 0x00120804,
1120
+ 0x00020004, 0x00120004, 0x00020804, 0x00120804,
1121
+ 0x04020004, 0x04120004, 0x04020804, 0x04120804,
1122
+ 0x04020004, 0x04120004, 0x04020804, 0x04120804,
1123
+ 0x00020200, 0x00120200, 0x00020A00, 0x00120A00,
1124
+ 0x00020200, 0x00120200, 0x00020A00, 0x00120A00,
1125
+ 0x04020200, 0x04120200, 0x04020A00, 0x04120A00,
1126
+ 0x04020200, 0x04120200, 0x04020A00, 0x04120A00,
1127
+ 0x00020204, 0x00120204, 0x00020A04, 0x00120A04,
1128
+ 0x00020204, 0x00120204, 0x00020A04, 0x00120A04,
1129
+ 0x04020204, 0x04120204, 0x04020A04, 0x04120A04,
1130
+ 0x04020204, 0x04120204, 0x04020A04, 0x04120A04,
1131
+ 0x00020200, 0x00120200, 0x00020A00, 0x00120A00,
1132
+ 0x00020200, 0x00120200, 0x00020A00, 0x00120A00,
1133
+ 0x04020200, 0x04120200, 0x04020A00, 0x04120A00,
1134
+ 0x04020200, 0x04120200, 0x04020A00, 0x04120A00,
1135
+ 0x00020204, 0x00120204, 0x00020A04, 0x00120A04,
1136
+ 0x00020204, 0x00120204, 0x00020A04, 0x00120A04,
1137
+ 0x04020204, 0x04120204, 0x04020A04, 0x04120A04,
1138
+ 0x04020204, 0x04120204, 0x04020A04, 0x04120A04
1139
+ );
1140
+ static $pc2mapd3 = array(
1141
+ 0x00000000, 0x00010000, 0x02000000, 0x02010000,
1142
+ 0x00000020, 0x00010020, 0x02000020, 0x02010020,
1143
+ 0x00040000, 0x00050000, 0x02040000, 0x02050000,
1144
+ 0x00040020, 0x00050020, 0x02040020, 0x02050020,
1145
+ 0x00002000, 0x00012000, 0x02002000, 0x02012000,
1146
+ 0x00002020, 0x00012020, 0x02002020, 0x02012020,
1147
+ 0x00042000, 0x00052000, 0x02042000, 0x02052000,
1148
+ 0x00042020, 0x00052020, 0x02042020, 0x02052020,
1149
+ 0x00000000, 0x00010000, 0x02000000, 0x02010000,
1150
+ 0x00000020, 0x00010020, 0x02000020, 0x02010020,
1151
+ 0x00040000, 0x00050000, 0x02040000, 0x02050000,
1152
+ 0x00040020, 0x00050020, 0x02040020, 0x02050020,
1153
+ 0x00002000, 0x00012000, 0x02002000, 0x02012000,
1154
+ 0x00002020, 0x00012020, 0x02002020, 0x02012020,
1155
+ 0x00042000, 0x00052000, 0x02042000, 0x02052000,
1156
+ 0x00042020, 0x00052020, 0x02042020, 0x02052020,
1157
+ 0x00000010, 0x00010010, 0x02000010, 0x02010010,
1158
+ 0x00000030, 0x00010030, 0x02000030, 0x02010030,
1159
+ 0x00040010, 0x00050010, 0x02040010, 0x02050010,
1160
+ 0x00040030, 0x00050030, 0x02040030, 0x02050030,
1161
+ 0x00002010, 0x00012010, 0x02002010, 0x02012010,
1162
+ 0x00002030, 0x00012030, 0x02002030, 0x02012030,
1163
+ 0x00042010, 0x00052010, 0x02042010, 0x02052010,
1164
+ 0x00042030, 0x00052030, 0x02042030, 0x02052030,
1165
+ 0x00000010, 0x00010010, 0x02000010, 0x02010010,
1166
+ 0x00000030, 0x00010030, 0x02000030, 0x02010030,
1167
+ 0x00040010, 0x00050010, 0x02040010, 0x02050010,
1168
+ 0x00040030, 0x00050030, 0x02040030, 0x02050030,
1169
+ 0x00002010, 0x00012010, 0x02002010, 0x02012010,
1170
+ 0x00002030, 0x00012030, 0x02002030, 0x02012030,
1171
+ 0x00042010, 0x00052010, 0x02042010, 0x02052010,
1172
+ 0x00042030, 0x00052030, 0x02042030, 0x02052030,
1173
+ 0x20000000, 0x20010000, 0x22000000, 0x22010000,
1174
+ 0x20000020, 0x20010020, 0x22000020, 0x22010020,
1175
+ 0x20040000, 0x20050000, 0x22040000, 0x22050000,
1176
+ 0x20040020, 0x20050020, 0x22040020, 0x22050020,
1177
+ 0x20002000, 0x20012000, 0x22002000, 0x22012000,
1178
+ 0x20002020, 0x20012020, 0x22002020, 0x22012020,
1179
+ 0x20042000, 0x20052000, 0x22042000, 0x22052000,
1180
+ 0x20042020, 0x20052020, 0x22042020, 0x22052020,
1181
+ 0x20000000, 0x20010000, 0x22000000, 0x22010000,
1182
+ 0x20000020, 0x20010020, 0x22000020, 0x22010020,
1183
+ 0x20040000, 0x20050000, 0x22040000, 0x22050000,
1184
+ 0x20040020, 0x20050020, 0x22040020, 0x22050020,
1185
+ 0x20002000, 0x20012000, 0x22002000, 0x22012000,
1186
+ 0x20002020, 0x20012020, 0x22002020, 0x22012020,
1187
+ 0x20042000, 0x20052000, 0x22042000, 0x22052000,
1188
+ 0x20042020, 0x20052020, 0x22042020, 0x22052020,
1189
+ 0x20000010, 0x20010010, 0x22000010, 0x22010010,
1190
+ 0x20000030, 0x20010030, 0x22000030, 0x22010030,
1191
+ 0x20040010, 0x20050010, 0x22040010, 0x22050010,
1192
+ 0x20040030, 0x20050030, 0x22040030, 0x22050030,
1193
+ 0x20002010, 0x20012010, 0x22002010, 0x22012010,
1194
+ 0x20002030, 0x20012030, 0x22002030, 0x22012030,
1195
+ 0x20042010, 0x20052010, 0x22042010, 0x22052010,
1196
+ 0x20042030, 0x20052030, 0x22042030, 0x22052030,
1197
+ 0x20000010, 0x20010010, 0x22000010, 0x22010010,
1198
+ 0x20000030, 0x20010030, 0x22000030, 0x22010030,
1199
+ 0x20040010, 0x20050010, 0x22040010, 0x22050010,
1200
+ 0x20040030, 0x20050030, 0x22040030, 0x22050030,
1201
+ 0x20002010, 0x20012010, 0x22002010, 0x22012010,
1202
+ 0x20002030, 0x20012030, 0x22002030, 0x22012030,
1203
+ 0x20042010, 0x20052010, 0x22042010, 0x22052010,
1204
+ 0x20042030, 0x20052030, 0x22042030, 0x22052030
1205
+ );
1206
+ static $pc2mapd4 = array(
1207
+ 0x00000000, 0x00000400, 0x01000000, 0x01000400,
1208
+ 0x00000000, 0x00000400, 0x01000000, 0x01000400,
1209
+ 0x00000100, 0x00000500, 0x01000100, 0x01000500,
1210
+ 0x00000100, 0x00000500, 0x01000100, 0x01000500,
1211
+ 0x10000000, 0x10000400, 0x11000000, 0x11000400,
1212
+ 0x10000000, 0x10000400, 0x11000000, 0x11000400,
1213
+ 0x10000100, 0x10000500, 0x11000100, 0x11000500,
1214
+ 0x10000100, 0x10000500, 0x11000100, 0x11000500,
1215
+ 0x00080000, 0x00080400, 0x01080000, 0x01080400,
1216
+ 0x00080000, 0x00080400, 0x01080000, 0x01080400,
1217
+ 0x00080100, 0x00080500, 0x01080100, 0x01080500,
1218
+ 0x00080100, 0x00080500, 0x01080100, 0x01080500,
1219
+ 0x10080000, 0x10080400, 0x11080000, 0x11080400,
1220
+ 0x10080000, 0x10080400, 0x11080000, 0x11080400,
1221
+ 0x10080100, 0x10080500, 0x11080100, 0x11080500,
1222
+ 0x10080100, 0x10080500, 0x11080100, 0x11080500,
1223
+ 0x00000008, 0x00000408, 0x01000008, 0x01000408,
1224
+ 0x00000008, 0x00000408, 0x01000008, 0x01000408,
1225
+ 0x00000108, 0x00000508, 0x01000108, 0x01000508,
1226
+ 0x00000108, 0x00000508, 0x01000108, 0x01000508,
1227
+ 0x10000008, 0x10000408, 0x11000008, 0x11000408,
1228
+ 0x10000008, 0x10000408, 0x11000008, 0x11000408,
1229
+ 0x10000108, 0x10000508, 0x11000108, 0x11000508,
1230
+ 0x10000108, 0x10000508, 0x11000108, 0x11000508,
1231
+ 0x00080008, 0x00080408, 0x01080008, 0x01080408,
1232
+ 0x00080008, 0x00080408, 0x01080008, 0x01080408,
1233
+ 0x00080108, 0x00080508, 0x01080108, 0x01080508,
1234
+ 0x00080108, 0x00080508, 0x01080108, 0x01080508,
1235
+ 0x10080008, 0x10080408, 0x11080008, 0x11080408,
1236
+ 0x10080008, 0x10080408, 0x11080008, 0x11080408,
1237
+ 0x10080108, 0x10080508, 0x11080108, 0x11080508,
1238
+ 0x10080108, 0x10080508, 0x11080108, 0x11080508,
1239
+ 0x00001000, 0x00001400, 0x01001000, 0x01001400,
1240
+ 0x00001000, 0x00001400, 0x01001000, 0x01001400,
1241
+ 0x00001100, 0x00001500, 0x01001100, 0x01001500,
1242
+ 0x00001100, 0x00001500, 0x01001100, 0x01001500,
1243
+ 0x10001000, 0x10001400, 0x11001000, 0x11001400,
1244
+ 0x10001000, 0x10001400, 0x11001000, 0x11001400,
1245
+ 0x10001100, 0x10001500, 0x11001100, 0x11001500,
1246
+ 0x10001100, 0x10001500, 0x11001100, 0x11001500,
1247
+ 0x00081000, 0x00081400, 0x01081000, 0x01081400,
1248
+ 0x00081000, 0x00081400, 0x01081000, 0x01081400,
1249
+ 0x00081100, 0x00081500, 0x01081100, 0x01081500,
1250
+ 0x00081100, 0x00081500, 0x01081100, 0x01081500,
1251
+ 0x10081000, 0x10081400, 0x11081000, 0x11081400,
1252
+ 0x10081000, 0x10081400, 0x11081000, 0x11081400,
1253
+ 0x10081100, 0x10081500, 0x11081100, 0x11081500,
1254
+ 0x10081100, 0x10081500, 0x11081100, 0x11081500,
1255
+ 0x00001008, 0x00001408, 0x01001008, 0x01001408,
1256
+ 0x00001008, 0x00001408, 0x01001008, 0x01001408,
1257
+ 0x00001108, 0x00001508, 0x01001108, 0x01001508,
1258
+ 0x00001108, 0x00001508, 0x01001108, 0x01001508,
1259
+ 0x10001008, 0x10001408, 0x11001008, 0x11001408,
1260
+ 0x10001008, 0x10001408, 0x11001008, 0x11001408,
1261
+ 0x10001108, 0x10001508, 0x11001108, 0x11001508,
1262
+ 0x10001108, 0x10001508, 0x11001108, 0x11001508,
1263
+ 0x00081008, 0x00081408, 0x01081008, 0x01081408,
1264
+ 0x00081008, 0x00081408, 0x01081008, 0x01081408,
1265
+ 0x00081108, 0x00081508, 0x01081108, 0x01081508,
1266
+ 0x00081108, 0x00081508, 0x01081108, 0x01081508,
1267
+ 0x10081008, 0x10081408, 0x11081008, 0x11081408,
1268
+ 0x10081008, 0x10081408, 0x11081008, 0x11081408,
1269
+ 0x10081108, 0x10081508, 0x11081108, 0x11081508,
1270
+ 0x10081108, 0x10081508, 0x11081108, 0x11081508
1271
+ );
1272
+
1273
+ $keys = array();
1274
+ for ($des_round = 0; $des_round < $this->des_rounds; ++$des_round) {
1275
+ // pad the key and remove extra characters as appropriate.
1276
+ $key = str_pad(substr($this->key, $des_round * 8, 8), 8, "\0");
1277
+
1278
+ // Perform the PC/1 transformation and compute C and D.
1279
+ $t = unpack('Nl/Nr', $key);
1280
+ list($l, $r) = array($t['l'], $t['r']);
1281
+ $key = ($this->shuffle[$pc1map[ $r & 0xFF]] & "\x80\x80\x80\x80\x80\x80\x80\x00") |
1282
+ ($this->shuffle[$pc1map[($r >> 8) & 0xFF]] & "\x40\x40\x40\x40\x40\x40\x40\x00") |
1283
+ ($this->shuffle[$pc1map[($r >> 16) & 0xFF]] & "\x20\x20\x20\x20\x20\x20\x20\x00") |
1284
+ ($this->shuffle[$pc1map[($r >> 24) & 0xFF]] & "\x10\x10\x10\x10\x10\x10\x10\x00") |
1285
+ ($this->shuffle[$pc1map[ $l & 0xFF]] & "\x08\x08\x08\x08\x08\x08\x08\x00") |
1286
+ ($this->shuffle[$pc1map[($l >> 8) & 0xFF]] & "\x04\x04\x04\x04\x04\x04\x04\x00") |
1287
+ ($this->shuffle[$pc1map[($l >> 16) & 0xFF]] & "\x02\x02\x02\x02\x02\x02\x02\x00") |
1288
+ ($this->shuffle[$pc1map[($l >> 24) & 0xFF]] & "\x01\x01\x01\x01\x01\x01\x01\x00");
1289
+ $key = unpack('Nc/Nd', $key);
1290
+ $c = ( $key['c'] >> 4) & 0x0FFFFFFF;
1291
+ $d = (($key['d'] >> 4) & 0x0FFFFFF0) | ($key['c'] & 0x0F);
1292
+
1293
+ $keys[$des_round] = array(
1294
+ CRYPT_DES_ENCRYPT => array(),
1295
+ CRYPT_DES_DECRYPT => array_fill(0, 32, 0)
1296
+ );
1297
+ for ($i = 0, $ki = 31; $i < 16; ++$i, $ki-= 2) {
1298
+ $c <<= $shifts[$i];
1299
+ $c = ($c | ($c >> 28)) & 0x0FFFFFFF;
1300
+ $d <<= $shifts[$i];
1301
+ $d = ($d | ($d >> 28)) & 0x0FFFFFFF;
1302
+
1303
+ // Perform the PC-2 transformation.
1304
+ $cp = $pc2mapc1[ $c >> 24 ] | $pc2mapc2[($c >> 16) & 0xFF] |
1305
+ $pc2mapc3[($c >> 8) & 0xFF] | $pc2mapc4[ $c & 0xFF];
1306
+ $dp = $pc2mapd1[ $d >> 24 ] | $pc2mapd2[($d >> 16) & 0xFF] |
1307
+ $pc2mapd3[($d >> 8) & 0xFF] | $pc2mapd4[ $d & 0xFF];
1308
+
1309
+ // Reorder: odd bytes/even bytes. Push the result in key schedule.
1310
+ $val1 = ( $cp & 0xFF000000) | (($cp << 8) & 0x00FF0000) |
1311
+ (($dp >> 16) & 0x0000FF00) | (($dp >> 8) & 0x000000FF);
1312
+ $val2 = (($cp << 8) & 0xFF000000) | (($cp << 16) & 0x00FF0000) |
1313
+ (($dp >> 8) & 0x0000FF00) | ( $dp & 0x000000FF);
1314
+ $keys[$des_round][CRYPT_DES_ENCRYPT][ ] = $val1;
1315
+ $keys[$des_round][CRYPT_DES_DECRYPT][$ki - 1] = $val1;
1316
+ $keys[$des_round][CRYPT_DES_ENCRYPT][ ] = $val2;
1317
+ $keys[$des_round][CRYPT_DES_DECRYPT][$ki ] = $val2;
1318
+ }
1319
+ }
1320
+
1321
+ switch ($this->des_rounds) {
1322
+ case 3: // 3DES keys
1323
+ $this->keys = array(
1324
+ CRYPT_DES_ENCRYPT => array_merge(
1325
+ $keys[0][CRYPT_DES_ENCRYPT],
1326
+ $keys[1][CRYPT_DES_DECRYPT],
1327
+ $keys[2][CRYPT_DES_ENCRYPT]
1328
+ ),
1329
+ CRYPT_DES_DECRYPT => array_merge(
1330
+ $keys[2][CRYPT_DES_DECRYPT],
1331
+ $keys[1][CRYPT_DES_ENCRYPT],
1332
+ $keys[0][CRYPT_DES_DECRYPT]
1333
+ )
1334
+ );
1335
+ break;
1336
+ // case 1: // DES keys
1337
+ default:
1338
+ $this->keys = array(
1339
+ CRYPT_DES_ENCRYPT => $keys[0][CRYPT_DES_ENCRYPT],
1340
+ CRYPT_DES_DECRYPT => $keys[0][CRYPT_DES_DECRYPT]
1341
+ );
1342
+ }
1343
+ }
1344
+
1345
+ /**
1346
+ * Setup the performance-optimized function for de/encrypt()
1347
+ *
1348
+ * @see Crypt_Base::_setupInlineCrypt()
1349
+ * @access private
1350
+ */
1351
+ function _setupInlineCrypt()
1352
+ {
1353
+ $lambda_functions =& Crypt_DES::_getLambdaFunctions();
1354
+
1355
+ // Engine configuration for:
1356
+ // - DES ($des_rounds == 1) or
1357
+ // - 3DES ($des_rounds == 3)
1358
+ $des_rounds = $this->des_rounds;
1359
+
1360
+ // We create max. 10 hi-optimized code for memory reason. Means: For each $key one ultra fast inline-crypt function.
1361
+ // After that, we'll still create very fast optimized code but not the hi-ultimative code, for each $mode one
1362
+ $gen_hi_opt_code = (bool)( count($lambda_functions) < 10 );
1363
+
1364
+ // Generation of a uniqe hash for our generated code
1365
+ switch (true) {
1366
+ case $gen_hi_opt_code:
1367
+ // For hi-optimized code, we create for each combination of
1368
+ // $mode, $des_rounds and $this->key its own encrypt/decrypt function.
1369
+ $code_hash = md5(str_pad("Crypt_DES, $des_rounds, {$this->mode}, ", 32, "\0") . $this->key);
1370
+ break;
1371
+ default:
1372
+ // After max 10 hi-optimized functions, we create generic
1373
+ // (still very fast.. but not ultra) functions for each $mode/$des_rounds
1374
+ // Currently 2 * 5 generic functions will be then max. possible.
1375
+ $code_hash = "Crypt_DES, $des_rounds, {$this->mode}";
1376
+ }
1377
+
1378
+ // Is there a re-usable $lambda_functions in there? If not, we have to create it.
1379
+ if (!isset($lambda_functions[$code_hash])) {
1380
+ // Init code for both, encrypt and decrypt.
1381
+ $init_crypt = 'static $sbox1, $sbox2, $sbox3, $sbox4, $sbox5, $sbox6, $sbox7, $sbox8, $shuffleip, $shuffleinvip;
1382
+ if (!$sbox1) {
1383
+ $sbox1 = array_map("intval", $self->sbox1);
1384
+ $sbox2 = array_map("intval", $self->sbox2);
1385
+ $sbox3 = array_map("intval", $self->sbox3);
1386
+ $sbox4 = array_map("intval", $self->sbox4);
1387
+ $sbox5 = array_map("intval", $self->sbox5);
1388
+ $sbox6 = array_map("intval", $self->sbox6);
1389
+ $sbox7 = array_map("intval", $self->sbox7);
1390
+ $sbox8 = array_map("intval", $self->sbox8);'
1391
+ /* Merge $shuffle with $[inv]ipmap */ . '
1392
+ for ($i = 0; $i < 256; ++$i) {
1393
+ $shuffleip[] = $self->shuffle[$self->ipmap[$i]];
1394
+ $shuffleinvip[] = $self->shuffle[$self->invipmap[$i]];
1395
+ }
1396
+ }
1397
+ ';
1398
+
1399
+ switch (true) {
1400
+ case $gen_hi_opt_code:
1401
+ // In Hi-optimized code mode, we use our [3]DES key schedule as hardcoded integers.
1402
+ // No futher initialisation of the $keys schedule is necessary.
1403
+ // That is the extra performance boost.
1404
+ $k = array(
1405
+ CRYPT_DES_ENCRYPT => $this->keys[CRYPT_DES_ENCRYPT],
1406
+ CRYPT_DES_DECRYPT => $this->keys[CRYPT_DES_DECRYPT]
1407
+ );
1408
+ $init_encrypt = '';
1409
+ $init_decrypt = '';
1410
+ break;
1411
+ default:
1412
+ // In generic optimized code mode, we have to use, as the best compromise [currently],
1413
+ // our key schedule as $ke/$kd arrays. (with hardcoded indexes...)
1414
+ $k = array(
1415
+ CRYPT_DES_ENCRYPT => array(),
1416
+ CRYPT_DES_DECRYPT => array()
1417
+ );
1418
+ for ($i = 0, $c = count($this->keys[CRYPT_DES_ENCRYPT]); $i < $c; ++$i) {
1419
+ $k[CRYPT_DES_ENCRYPT][$i] = '$ke[' . $i . ']';
1420
+ $k[CRYPT_DES_DECRYPT][$i] = '$kd[' . $i . ']';
1421
+ }
1422
+ $init_encrypt = '$ke = $self->keys[CRYPT_DES_ENCRYPT];';
1423
+ $init_decrypt = '$kd = $self->keys[CRYPT_DES_DECRYPT];';
1424
+ break;
1425
+ }
1426
+
1427
+ // Creating code for en- and decryption.
1428
+ $crypt_block = array();
1429
+ foreach (array(CRYPT_DES_ENCRYPT, CRYPT_DES_DECRYPT) as $c) {
1430
+
1431
+ /* Do the initial IP permutation. */
1432
+ $crypt_block[$c] = '
1433
+ $in = unpack("N*", $in);
1434
+ $l = $in[1];
1435
+ $r = $in[2];
1436
+ $in = unpack("N*",
1437
+ ($shuffleip[ $r & 0xFF] & "\x80\x80\x80\x80\x80\x80\x80\x80") |
1438
+ ($shuffleip[($r >> 8) & 0xFF] & "\x40\x40\x40\x40\x40\x40\x40\x40") |
1439
+ ($shuffleip[($r >> 16) & 0xFF] & "\x20\x20\x20\x20\x20\x20\x20\x20") |
1440
+ ($shuffleip[($r >> 24) & 0xFF] & "\x10\x10\x10\x10\x10\x10\x10\x10") |
1441
+ ($shuffleip[ $l & 0xFF] & "\x08\x08\x08\x08\x08\x08\x08\x08") |
1442
+ ($shuffleip[($l >> 8) & 0xFF] & "\x04\x04\x04\x04\x04\x04\x04\x04") |
1443
+ ($shuffleip[($l >> 16) & 0xFF] & "\x02\x02\x02\x02\x02\x02\x02\x02") |
1444
+ ($shuffleip[($l >> 24) & 0xFF] & "\x01\x01\x01\x01\x01\x01\x01\x01")
1445
+ );
1446
+ ' . /* Extract L0 and R0 */ '
1447
+ $l = $in[1];
1448
+ $r = $in[2];
1449
+ ';
1450
+
1451
+ $l = '$l';
1452
+ $r = '$r';
1453
+
1454
+ // Perform DES or 3DES.
1455
+ for ($ki = -1, $des_round = 0; $des_round < $des_rounds; ++$des_round) {
1456
+ // Perform the 16 steps.
1457
+ for ($i = 0; $i < 16; ++$i) {
1458
+ // start of "the Feistel (F) function" - see the following URL:
1459
+ // http://en.wikipedia.org/wiki/Image:Data_Encryption_Standard_InfoBox_Diagram.png
1460
+ // Merge key schedule.
1461
+ $crypt_block[$c].= '
1462
+ $b1 = ((' . $r . ' >> 3) & 0x1FFFFFFF) ^ (' . $r . ' << 29) ^ ' . $k[$c][++$ki] . ';
1463
+ $b2 = ((' . $r . ' >> 31) & 0x00000001) ^ (' . $r . ' << 1) ^ ' . $k[$c][++$ki] . ';' .
1464
+ /* S-box indexing. */
1465
+ $l . ' = $sbox1[($b1 >> 24) & 0x3F] ^ $sbox2[($b2 >> 24) & 0x3F] ^
1466
+ $sbox3[($b1 >> 16) & 0x3F] ^ $sbox4[($b2 >> 16) & 0x3F] ^
1467
+ $sbox5[($b1 >> 8) & 0x3F] ^ $sbox6[($b2 >> 8) & 0x3F] ^
1468
+ $sbox7[ $b1 & 0x3F] ^ $sbox8[ $b2 & 0x3F] ^ ' . $l . ';
1469
+ ';
1470
+ // end of "the Feistel (F) function"
1471
+
1472
+ // swap L & R
1473
+ list($l, $r) = array($r, $l);
1474
+ }
1475
+ list($l, $r) = array($r, $l);
1476
+ }
1477
+
1478
+ // Perform the inverse IP permutation.
1479
+ $crypt_block[$c].= '$in =
1480
+ ($shuffleinvip[($l >> 24) & 0xFF] & "\x80\x80\x80\x80\x80\x80\x80\x80") |
1481
+ ($shuffleinvip[($r >> 24) & 0xFF] & "\x40\x40\x40\x40\x40\x40\x40\x40") |
1482
+ ($shuffleinvip[($l >> 16) & 0xFF] & "\x20\x20\x20\x20\x20\x20\x20\x20") |
1483
+ ($shuffleinvip[($r >> 16) & 0xFF] & "\x10\x10\x10\x10\x10\x10\x10\x10") |
1484
+ ($shuffleinvip[($l >> 8) & 0xFF] & "\x08\x08\x08\x08\x08\x08\x08\x08") |
1485
+ ($shuffleinvip[($r >> 8) & 0xFF] & "\x04\x04\x04\x04\x04\x04\x04\x04") |
1486
+ ($shuffleinvip[ $l & 0xFF] & "\x02\x02\x02\x02\x02\x02\x02\x02") |
1487
+ ($shuffleinvip[ $r & 0xFF] & "\x01\x01\x01\x01\x01\x01\x01\x01");
1488
+ ';
1489
+ }
1490
+
1491
+ // Creates the inline-crypt function
1492
+ $lambda_functions[$code_hash] = $this->_createInlineCryptFunction(
1493
+ array(
1494
+ 'init_crypt' => $init_crypt,
1495
+ 'init_encrypt' => $init_encrypt,
1496
+ 'init_decrypt' => $init_decrypt,
1497
+ 'encrypt_block' => $crypt_block[CRYPT_DES_ENCRYPT],
1498
+ 'decrypt_block' => $crypt_block[CRYPT_DES_DECRYPT]
1499
+ )
1500
+ );
1501
+ }
1502
+
1503
+ // Set the inline-crypt function as callback in: $this->inline_crypt
1504
+ $this->inline_crypt = $lambda_functions[$code_hash];
1505
+ }
1506
+ }
phpseclib/Crypt/Hash.php CHANGED
@@ -1,25 +1,24 @@
1
  <?php
2
- /* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
3
 
4
  /**
5
  * Pure-PHP implementations of keyed-hash message authentication codes (HMACs) and various cryptographic hashing functions.
6
  *
7
  * Uses hash() or mhash() if available and an internal implementation, otherwise. Currently supports the following:
8
  *
9
- * md2, md5, md5-96, sha1, sha1-96, sha256, sha384, and sha512
10
  *
11
  * If {@link Crypt_Hash::setKey() setKey()} is called, {@link Crypt_Hash::hash() hash()} will return the HMAC as opposed to
12
  * the hash. If no valid algorithm is provided, sha1 will be used.
13
  *
14
  * PHP versions 4 and 5
15
  *
16
- * {@internal The variable names are the same as those in
17
  * {@link http://tools.ietf.org/html/rfc2104#section-2 RFC2104}.}}
18
  *
19
  * Here's a short example of how to use this library:
20
  * <code>
21
  * <?php
22
- * include('Crypt/Hash.php');
23
  *
24
  * $hash = new Crypt_Hash('sha1');
25
  *
@@ -35,10 +34,10 @@
35
  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
36
  * copies of the Software, and to permit persons to whom the Software is
37
  * furnished to do so, subject to the following conditions:
38
- *
39
  * The above copyright notice and this permission notice shall be included in
40
  * all copies or substantial portions of the Software.
41
- *
42
  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
43
  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
44
  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
@@ -47,13 +46,12 @@
47
  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
48
  * THE SOFTWARE.
49
  *
50
- * @category Crypt
51
- * @package Crypt_Hash
52
- * @author Jim Wigginton <terrafrost@php.net>
53
- * @copyright MMVII Jim Wigginton
54
- * @license http://www.opensource.org/licenses/mit-license.html MIT License
55
- * @version $Id: Hash.php,v 1.6 2009/11/23 23:37:07 terrafrost Exp $
56
- * @link http://phpseclib.sourceforge.net
57
  */
58
 
59
  /**#@+
@@ -77,12 +75,21 @@ define('CRYPT_HASH_MODE_HASH', 3);
77
  /**
78
  * Pure-PHP implementations of keyed-hash message authentication codes (HMACs) and various cryptographic hashing functions.
79
  *
 
80
  * @author Jim Wigginton <terrafrost@php.net>
81
- * @version 0.1.0
82
  * @access public
83
- * @package Crypt_Hash
84
  */
85
- class Crypt_Hash {
 
 
 
 
 
 
 
 
 
 
86
  /**
87
  * Byte-length of compression blocks / key (Internal HMAC)
88
  *
@@ -168,13 +175,26 @@ class Crypt_Hash {
168
  * Keys can be of any length.
169
  *
170
  * @access public
171
- * @param String $key
172
  */
173
  function setKey($key = false)
174
  {
175
  $this->key = $key;
176
  }
177
 
 
 
 
 
 
 
 
 
 
 
 
 
 
178
  /**
179
  * Sets the hash function.
180
  *
@@ -183,10 +203,13 @@ class Crypt_Hash {
183
  */
184
  function setHash($hash)
185
  {
186
- $hash = strtolower($hash);
187
  switch ($hash) {
188
  case 'md5-96':
189
  case 'sha1-96':
 
 
 
190
  $this->l = 12; // 96 / 8 = 12
191
  break;
192
  case 'md2':
@@ -223,14 +246,12 @@ class Crypt_Hash {
223
  case CRYPT_HASH_MODE_MHASH:
224
  switch ($hash) {
225
  case 'md5':
226
- case 'md5-96':
227
  $this->hash = MHASH_MD5;
228
  break;
229
  case 'sha256':
230
  $this->hash = MHASH_SHA256;
231
  break;
232
  case 'sha1':
233
- case 'sha1-96':
234
  default:
235
  $this->hash = MHASH_SHA1;
236
  }
@@ -238,7 +259,6 @@ class Crypt_Hash {
238
  case CRYPT_HASH_MODE_HASH:
239
  switch ($hash) {
240
  case 'md5':
241
- case 'md5-96':
242
  $this->hash = 'md5';
243
  return;
244
  case 'md2':
@@ -248,7 +268,6 @@ class Crypt_Hash {
248
  $this->hash = $hash;
249
  return;
250
  case 'sha1':
251
- case 'sha1-96':
252
  default:
253
  $this->hash = 'sha1';
254
  }
@@ -261,7 +280,6 @@ class Crypt_Hash {
261
  $this->hash = array($this, '_md2');
262
  break;
263
  case 'md5':
264
- case 'md5-96':
265
  $this->b = 64;
266
  $this->hash = array($this, '_md5');
267
  break;
@@ -275,7 +293,6 @@ class Crypt_Hash {
275
  $this->hash = array($this, '_sha512');
276
  break;
277
  case 'sha1':
278
- case 'sha1-96':
279
  default:
280
  $this->b = 64;
281
  $this->hash = array($this, '_sha1');
@@ -350,7 +367,7 @@ class Crypt_Hash {
350
  * Wrapper for MD5
351
  *
352
  * @access private
353
- * @param String $text
354
  */
355
  function _md5($m)
356
  {
@@ -361,7 +378,7 @@ class Crypt_Hash {
361
  * Wrapper for SHA1
362
  *
363
  * @access private
364
- * @param String $text
365
  */
366
  function _sha1($m)
367
  {
@@ -374,7 +391,7 @@ class Crypt_Hash {
374
  * See {@link http://tools.ietf.org/html/rfc1319 RFC1319}.
375
  *
376
  * @access private
377
- * @param String $text
378
  */
379
  function _md2($m)
380
  {
@@ -450,7 +467,7 @@ class Crypt_Hash {
450
  * See {@link http://en.wikipedia.org/wiki/SHA_hash_functions#SHA-256_.28a_SHA-2_variant.29_pseudocode SHA-256 (a SHA-2 variant) pseudocode - Wikipedia}.
451
  *
452
  * @access private
453
- * @param String $text
454
  */
455
  function _sha256($m)
456
  {
@@ -555,12 +572,12 @@ class Crypt_Hash {
555
  * Pure-PHP implementation of SHA384 and SHA512
556
  *
557
  * @access private
558
- * @param String $text
559
  */
560
  function _sha512($m)
561
  {
562
  if (!class_exists('Math_BigInteger')) {
563
- require_once('Math/BigInteger.php');
564
  }
565
 
566
  static $init384, $init512, $k;
@@ -568,11 +585,11 @@ class Crypt_Hash {
568
  if (!isset($k)) {
569
  // Initialize variables
570
  $init384 = array( // initial values for SHA384
571
- 'cbbb9d5dc1059ed8', '629a292a367cd507', '9159015a3070dd17', '152fecd8f70e5939',
572
  '67332667ffc00b31', '8eb44a8768581511', 'db0c2e0d64f98fa7', '47b5481dbefa4fa4'
573
  );
574
  $init512 = array( // initial values for SHA512
575
- '6a09e667f3bcc908', 'bb67ae8584caa73b', '3c6ef372fe94f82b', 'a54ff53a5f1d36f1',
576
  '510e527fade682d1', '9b05688c2b3e6c1f', '1f83d9abfb41bd6b', '5be0cd19137e2179'
577
  );
578
 
@@ -784,9 +801,8 @@ class Crypt_Hash {
784
  * _sha256() adds multiple unsigned 32-bit integers. Since PHP doesn't support unsigned integers and since the
785
  * possibility of overflow exists, care has to be taken. Math_BigInteger() could be used but this should be faster.
786
  *
787
- * @param String $string
788
- * @param optional Integer $index
789
- * @return String
790
  * @see _sha256()
791
  * @access private
792
  */
1
  <?php
 
2
 
3
  /**
4
  * Pure-PHP implementations of keyed-hash message authentication codes (HMACs) and various cryptographic hashing functions.
5
  *
6
  * Uses hash() or mhash() if available and an internal implementation, otherwise. Currently supports the following:
7
  *
8
+ * md2, md5, md5-96, sha1, sha1-96, sha256, sha256-96, sha384, and sha512, sha512-96
9
  *
10
  * If {@link Crypt_Hash::setKey() setKey()} is called, {@link Crypt_Hash::hash() hash()} will return the HMAC as opposed to
11
  * the hash. If no valid algorithm is provided, sha1 will be used.
12
  *
13
  * PHP versions 4 and 5
14
  *
15
+ * {@internal The variable names are the same as those in
16
  * {@link http://tools.ietf.org/html/rfc2104#section-2 RFC2104}.}}
17
  *
18
  * Here's a short example of how to use this library:
19
  * <code>
20
  * <?php
21
+ * include 'Crypt/Hash.php';
22
  *
23
  * $hash = new Crypt_Hash('sha1');
24
  *
34
  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
35
  * copies of the Software, and to permit persons to whom the Software is
36
  * furnished to do so, subject to the following conditions:
37
+ *
38
  * The above copyright notice and this permission notice shall be included in
39
  * all copies or substantial portions of the Software.
40
+ *
41
  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
42
  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
43
  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
46
  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
47
  * THE SOFTWARE.
48
  *
49
+ * @category Crypt
50
+ * @package Crypt_Hash
51
+ * @author Jim Wigginton <terrafrost@php.net>
52
+ * @copyright MMVII Jim Wigginton
53
+ * @license http://www.opensource.org/licenses/mit-license.html MIT License
54
+ * @link http://phpseclib.sourceforge.net
 
55
  */
56
 
57
  /**#@+
75
  /**
76
  * Pure-PHP implementations of keyed-hash message authentication codes (HMACs) and various cryptographic hashing functions.
77
  *
78
+ * @package Crypt_Hash
79
  * @author Jim Wigginton <terrafrost@php.net>
 
80
  * @access public
 
81
  */
82
+ class Crypt_Hash
83
+ {
84
+ /**
85
+ * Hash Parameter
86
+ *
87
+ * @see Crypt_Hash::setHash()
88
+ * @var Integer
89
+ * @access private
90
+ */
91
+ var $hashParam;
92
+
93
  /**
94
  * Byte-length of compression blocks / key (Internal HMAC)
95
  *
175
  * Keys can be of any length.
176
  *
177
  * @access public
178
+ * @param optional String $key
179
  */
180
  function setKey($key = false)
181
  {
182
  $this->key = $key;
183
  }
184
 
185
+ /**
186
+ * Gets the hash function.
187
+ *
188
+ * As set by the constructor or by the setHash() method.
189
+ *
190
+ * @access public
191
+ * @return String
192
+ */
193
+ function getHash()
194
+ {
195
+ return $this->hashParam;
196
+ }
197
+
198
  /**
199
  * Sets the hash function.
200
  *
203
  */
204
  function setHash($hash)
205
  {
206
+ $this->hashParam = $hash = strtolower($hash);
207
  switch ($hash) {
208
  case 'md5-96':
209
  case 'sha1-96':
210
+ case 'sha256-96':
211
+ case 'sha512-96':
212
+ $hash = substr($hash, 0, -3);
213
  $this->l = 12; // 96 / 8 = 12
214
  break;
215
  case 'md2':
246
  case CRYPT_HASH_MODE_MHASH:
247
  switch ($hash) {
248
  case 'md5':
 
249
  $this->hash = MHASH_MD5;
250
  break;
251
  case 'sha256':
252
  $this->hash = MHASH_SHA256;
253
  break;
254
  case 'sha1':
 
255
  default:
256
  $this->hash = MHASH_SHA1;
257
  }
259
  case CRYPT_HASH_MODE_HASH:
260
  switch ($hash) {
261
  case 'md5':
 
262
  $this->hash = 'md5';
263
  return;
264
  case 'md2':
268
  $this->hash = $hash;
269
  return;
270
  case 'sha1':
 
271
  default:
272
  $this->hash = 'sha1';
273
  }
280
  $this->hash = array($this, '_md2');
281
  break;
282
  case 'md5':
 
283
  $this->b = 64;
284
  $this->hash = array($this, '_md5');
285
  break;
293
  $this->hash = array($this, '_sha512');
294
  break;
295
  case 'sha1':
 
296
  default:
297
  $this->b = 64;
298
  $this->hash = array($this, '_sha1');
367
  * Wrapper for MD5
368
  *
369
  * @access private
370
+ * @param String $m
371
  */
372
  function _md5($m)
373
  {
378
  * Wrapper for SHA1
379
  *
380
  * @access private
381
+ * @param String $m
382
  */
383
  function _sha1($m)
384
  {
391
  * See {@link http://tools.ietf.org/html/rfc1319 RFC1319}.
392
  *
393
  * @access private
394
+ * @param String $m
395
  */
396
  function _md2($m)
397
  {
467
  * See {@link http://en.wikipedia.org/wiki/SHA_hash_functions#SHA-256_.28a_SHA-2_variant.29_pseudocode SHA-256 (a SHA-2 variant) pseudocode - Wikipedia}.
468
  *
469
  * @access private
470
+ * @param String $m
471
  */
472
  function _sha256($m)
473
  {
572
  * Pure-PHP implementation of SHA384 and SHA512
573
  *
574
  * @access private
575
+ * @param String $m
576
  */
577
  function _sha512($m)
578
  {
579
  if (!class_exists('Math_BigInteger')) {
580
+ include_once 'Math/BigInteger.php';
581
  }
582
 
583
  static $init384, $init512, $k;
585
  if (!isset($k)) {
586
  // Initialize variables
587
  $init384 = array( // initial values for SHA384
588
+ 'cbbb9d5dc1059ed8', '629a292a367cd507', '9159015a3070dd17', '152fecd8f70e5939',
589
  '67332667ffc00b31', '8eb44a8768581511', 'db0c2e0d64f98fa7', '47b5481dbefa4fa4'
590
  );
591
  $init512 = array( // initial values for SHA512
592
+ '6a09e667f3bcc908', 'bb67ae8584caa73b', '3c6ef372fe94f82b', 'a54ff53a5f1d36f1',
593
  '510e527fade682d1', '9b05688c2b3e6c1f', '1f83d9abfb41bd6b', '5be0cd19137e2179'
594
  );
595
 
801
  * _sha256() adds multiple unsigned 32-bit integers. Since PHP doesn't support unsigned integers and since the
802
  * possibility of overflow exists, care has to be taken. Math_BigInteger() could be used but this should be faster.
803
  *
804
+ * @param Integer $...
805
+ * @return Integer
 
806
  * @see _sha256()
807
  * @access private
808
  */
phpseclib/Crypt/RC4.php CHANGED
@@ -1,5 +1,4 @@
1
  <?php
2
- /* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
3
 
4
  /**
5
  * Pure-PHP implementation of RC4.
@@ -14,12 +13,12 @@
14
  * - {@link http://en.wikipedia.org/wiki/RC4 - Wikipedia: RC4}
15
  *
16
  * RC4 is also known as ARCFOUR or ARC4. The reason is elaborated upon at Wikipedia. This class is named RC4 and not
17
- * ARCFOUR or ARC4 because RC4 is how it is refered to in the SSH1 specification.
18
  *
19
  * Here's a short example of how to use this library:
20
  * <code>
21
  * <?php
22
- * include('Crypt/RC4.php');
23
  *
24
  * $rc4 = new Crypt_RC4();
25
  *
@@ -41,10 +40,10 @@
41
  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
42
  * copies of the Software, and to permit persons to whom the Software is
43
  * furnished to do so, subject to the following conditions:
44
- *
45
  * The above copyright notice and this permission notice shall be included in
46
  * all copies or substantial portions of the Software.
47
- *
48
  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
49
  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
50
  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
@@ -53,15 +52,23 @@
53
  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
54
  * THE SOFTWARE.
55
  *
56
- * @category Crypt
57
- * @package Crypt_RC4
58
- * @author Jim Wigginton <terrafrost@php.net>
59
- * @copyright MMVII Jim Wigginton
60
- * @license http://www.opensource.org/licenses/mit-license.html MIT License
61
- * @version $Id: RC4.php,v 1.8 2009/06/09 04:00:38 terrafrost Exp $
62
- * @link http://phpseclib.sourceforge.net
63
  */
64
 
 
 
 
 
 
 
 
 
 
65
  /**#@+
66
  * @access private
67
  * @see Crypt_RC4::Crypt_RC4()
@@ -69,11 +76,11 @@
69
  /**
70
  * Toggles the internal implementation
71
  */
72
- define('CRYPT_RC4_MODE_INTERNAL', 1);
73
  /**
74
  * Toggles the mcrypt implementation
75
  */
76
- define('CRYPT_RC4_MODE_MCRYPT', 2);
77
  /**#@-*/
78
 
79
  /**#@+
@@ -87,202 +94,91 @@ define('CRYPT_RC4_DECRYPT', 1);
87
  /**
88
  * Pure-PHP implementation of RC4.
89
  *
 
90
  * @author Jim Wigginton <terrafrost@php.net>
91
- * @version 0.1.0
92
  * @access public
93
- * @package Crypt_RC4
94
  */
95
- class Crypt_RC4 {
 
96
  /**
97
- * The Key
98
  *
99
- * @see Crypt_RC4::setKey()
100
- * @var String
 
 
 
101
  * @access private
102
  */
103
- var $key = "\0";
104
 
105
  /**
106
- * The Key Stream for encryption
107
- *
108
- * If CRYPT_RC4_MODE == CRYPT_RC4_MODE_MCRYPT, this will be equal to the mcrypt object
109
  *
110
- * @see Crypt_RC4::setKey()
111
- * @var Array
 
112
  * @access private
113
  */
114
- var $encryptStream = false;
115
 
116
  /**
117
- * The Key Stream for decryption
118
- *
119
- * If CRYPT_RC4_MODE == CRYPT_RC4_MODE_MCRYPT, this will be equal to the mcrypt object
120
  *
121
- * @see Crypt_RC4::setKey()
122
- * @var Array
123
  * @access private
124
  */
125
- var $decryptStream = false;
126
 
127
  /**
128
- * The $i and $j indexes for encryption
129
  *
130
- * @see Crypt_RC4::_crypt()
131
- * @var Integer
132
  * @access private
133
  */
134
- var $encryptIndex = 0;
135
 
136
  /**
137
- * The $i and $j indexes for decryption
138
  *
139
- * @see Crypt_RC4::_crypt()
140
- * @var Integer
141
  * @access private
142
  */
143
- var $decryptIndex = 0;
144
 
145
  /**
146
- * The Encryption Algorithm
147
- *
148
- * Only used if CRYPT_RC4_MODE == CRYPT_RC4_MODE_MCRYPT. Only possible values are MCRYPT_RC4 or MCRYPT_ARCFOUR.
149
  *
150
- * @see Crypt_RC4::Crypt_RC4()
151
- * @var Integer
152
  * @access private
153
  */
154
- var $mode;
155
 
156
  /**
157
- * Continuous Buffer status
158
  *
159
- * @see Crypt_RC4::enableContinuousBuffer()
160
- * @var Boolean
161
  * @access private
162
  */
163
- var $continuousBuffer = false;
164
 
165
  /**
166
  * Default Constructor.
167
  *
168
  * Determines whether or not the mcrypt extension should be used.
169
  *
170
- * @param optional Integer $mode
171
  * @return Crypt_RC4
172
  * @access public
173
  */
174
  function Crypt_RC4()
175
  {
176
- if ( !defined('CRYPT_RC4_MODE') ) {
177
- switch (true) {
178
- case extension_loaded('mcrypt') && (defined('MCRYPT_ARCFOUR') || defined('MCRYPT_RC4')) && in_array('arcfour', mcrypt_list_algorithms()):
179
- define('CRYPT_RC4_MODE', CRYPT_RC4_MODE_MCRYPT);
180
- break;
181
- default:
182
- define('CRYPT_RC4_MODE', CRYPT_RC4_MODE_INTERNAL);
183
- }
184
- }
185
-
186
- switch ( CRYPT_RC4_MODE ) {
187
- case CRYPT_RC4_MODE_MCRYPT:
188
- switch (true) {
189
- case defined('MCRYPT_ARCFOUR'):
190
- $this->mode = MCRYPT_ARCFOUR;
191
- break;
192
- case defined('MCRYPT_RC4');
193
- $this->mode = MCRYPT_RC4;
194
- }
195
- }
196
- }
197
-
198
- /**
199
- * Sets the key.
200
- *
201
- * Keys can be between 1 and 256 bytes long. If they are longer then 256 bytes, the first 256 bytes will
202
- * be used. If no key is explicitly set, it'll be assumed to be a single null byte.
203
- *
204
- * @access public
205
- * @param String $key
206
- */
207
- function setKey($key)
208
- {
209
- $this->key = $key;
210
-
211
- if ( CRYPT_RC4_MODE == CRYPT_RC4_MODE_MCRYPT ) {
212
- return;
213
- }
214
-
215
- $keyLength = strlen($key);
216
- $keyStream = array();
217
- for ($i = 0; $i < 256; $i++) {
218
- $keyStream[$i] = $i;
219
- }
220
- $j = 0;
221
- for ($i = 0; $i < 256; $i++) {
222
- $j = ($j + $keyStream[$i] + ord($key[$i % $keyLength])) & 255;
223
- $temp = $keyStream[$i];
224
- $keyStream[$i] = $keyStream[$j];
225
- $keyStream[$j] = $temp;
226
- }
227
-
228
- $this->encryptIndex = $this->decryptIndex = array(0, 0);
229
- $this->encryptStream = $this->decryptStream = $keyStream;
230
- }
231
-
232
- /**
233
- * Sets the password.
234
- *
235
- * Depending on what $method is set to, setPassword()'s (optional) parameters are as follows:
236
- * {@link http://en.wikipedia.org/wiki/PBKDF2 pbkdf2}:
237
- * $hash, $salt, $count, $dkLen
238
- *
239
- * @param String $password
240
- * @param optional String $method
241
- * @access public
242
- */
243
- function setPassword($password, $method = 'pbkdf2')
244
- {
245
- $key = '';
246
-
247
- switch ($method) {
248
- default: // 'pbkdf2'
249
- list(, , $hash, $salt, $count) = func_get_args();
250
- if (!isset($hash)) {
251
- $hash = 'sha1';
252
- }
253
- // WPA and WPA use the SSID as the salt
254
- if (!isset($salt)) {
255
- $salt = 'phpseclib/salt';
256
- }
257
- // RFC2898#section-4.2 uses 1,000 iterations by default
258
- // WPA and WPA2 use 4,096.
259
- if (!isset($count)) {
260
- $count = 1000;
261
- }
262
- if (!isset($dkLen)) {
263
- $dkLen = 128;
264
- }
265
-
266
- if (!class_exists('Crypt_Hash')) {
267
- require_once('Crypt/Hash.php');
268
- }
269
-
270
- $i = 1;
271
- while (strlen($key) < $dkLen) {
272
- //$dk.= $this->_pbkdf($password, $salt, $count, $i++);
273
- $hmac = new Crypt_Hash();
274
- $hmac->setHash($hash);
275
- $hmac->setKey($password);
276
- $f = $u = $hmac->hash($salt . pack('N', $i++));
277
- for ($j = 2; $j <= $count; $j++) {
278
- $u = $hmac->hash($u);
279
- $f^= $u;
280
- }
281
- $key.= $f;
282
- }
283
- }
284
-
285
- $this->setKey(substr($key, 0, $dkLen));
286
  }
287
 
288
  /**
@@ -308,15 +204,35 @@ class Crypt_RC4 {
308
  {
309
  }
310
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
311
  /**
312
  * Encrypts a message.
313
  *
 
314
  * @see Crypt_RC4::_crypt()
315
  * @access public
316
  * @param String $plaintext
 
317
  */
318
  function encrypt($plaintext)
319
  {
 
 
 
320
  return $this->_crypt($plaintext, CRYPT_RC4_ENCRYPT);
321
  }
322
 
@@ -324,208 +240,90 @@ class Crypt_RC4 {
324
  * Decrypts a message.
325
  *
326
  * $this->decrypt($this->encrypt($plaintext)) == $this->encrypt($this->encrypt($plaintext)).
327
- * Atleast if the continuous buffer is disabled.
328
  *
 
329
  * @see Crypt_RC4::_crypt()
330
  * @access public
331
  * @param String $ciphertext
 
332
  */
333
  function decrypt($ciphertext)
334
  {
 
 
 
335
  return $this->_crypt($ciphertext, CRYPT_RC4_DECRYPT);
336
  }
337
 
 
338
  /**
339
- * Encrypts or decrypts a message.
340
  *
341
- * @see Crypt_RC4::encrypt()
342
- * @see Crypt_RC4::decrypt()
343
  * @access private
344
- * @param String $text
345
- * @param Integer $mode
346
  */
347
- function _crypt($text, $mode)
348
  {
349
- if ( CRYPT_RC4_MODE == CRYPT_RC4_MODE_MCRYPT ) {
350
- $keyStream = $mode == CRYPT_RC4_ENCRYPT ? 'encryptStream' : 'decryptStream';
351
-
352
- if ($this->$keyStream === false) {
353
- $this->$keyStream = mcrypt_module_open($this->mode, '', MCRYPT_MODE_STREAM, '');
354
- mcrypt_generic_init($this->$keyStream, $this->key, '');
355
- } else if (!$this->continuousBuffer) {
356
- mcrypt_generic_init($this->$keyStream, $this->key, '');
357
- }
358
- $newText = mcrypt_generic($this->$keyStream, $text);
359
- if (!$this->continuousBuffer) {
360
- mcrypt_generic_deinit($this->$keyStream);
361
- }
362
-
363
- return $newText;
364
- }
365
-
366
- if ($this->encryptStream === false) {
367
- $this->setKey($this->key);
368
- }
369
-
370
- switch ($mode) {
371
- case CRYPT_RC4_ENCRYPT:
372
- $keyStream = $this->encryptStream;
373
- list($i, $j) = $this->encryptIndex;
374
- break;
375
- case CRYPT_RC4_DECRYPT:
376
- $keyStream = $this->decryptStream;
377
- list($i, $j) = $this->decryptIndex;
378
- }
379
-
380
- $newText = '';
381
- for ($k = 0; $k < strlen($text); $k++) {
382
- $i = ($i + 1) & 255;
383
- $j = ($j + $keyStream[$i]) & 255;
384
  $temp = $keyStream[$i];
385
  $keyStream[$i] = $keyStream[$j];
386
  $keyStream[$j] = $temp;
387
- $temp = $keyStream[($keyStream[$i] + $keyStream[$j]) & 255];
388
- $newText.= chr(ord($text[$k]) ^ $temp);
389
  }
390
 
391
- if ($this->continuousBuffer) {
392
- switch ($mode) {
393
- case CRYPT_RC4_ENCRYPT:
394
- $this->encryptStream = $keyStream;
395
- $this->encryptIndex = array($i, $j);
396
- break;
397
- case CRYPT_RC4_DECRYPT:
398
- $this->decryptStream = $keyStream;
399
- $this->decryptIndex = array($i, $j);
400
- }
401
- }
402
-
403
- return $newText;
404
- }
405
-
406
- /**
407
- * Treat consecutive "packets" as if they are a continuous buffer.
408
- *
409
- * Say you have a 16-byte plaintext $plaintext. Using the default behavior, the two following code snippets
410
- * will yield different outputs:
411
- *
412
- * <code>
413
- * echo $rc4->encrypt(substr($plaintext, 0, 8));
414
- * echo $rc4->encrypt(substr($plaintext, 8, 8));
415
- * </code>
416
- * <code>
417
- * echo $rc4->encrypt($plaintext);
418
- * </code>
419
- *
420
- * The solution is to enable the continuous buffer. Although this will resolve the above discrepancy, it creates
421
- * another, as demonstrated with the following:
422
- *
423
- * <code>
424
- * $rc4->encrypt(substr($plaintext, 0, 8));
425
- * echo $rc4->decrypt($des->encrypt(substr($plaintext, 8, 8)));
426
- * </code>
427
- * <code>
428
- * echo $rc4->decrypt($des->encrypt(substr($plaintext, 8, 8)));
429
- * </code>
430
- *
431
- * With the continuous buffer disabled, these would yield the same output. With it enabled, they yield different
432
- * outputs. The reason is due to the fact that the initialization vector's change after every encryption /
433
- * decryption round when the continuous buffer is enabled. When it's disabled, they remain constant.
434
- *
435
- * Put another way, when the continuous buffer is enabled, the state of the Crypt_DES() object changes after each
436
- * encryption / decryption round, whereas otherwise, it'd remain constant. For this reason, it's recommended that
437
- * continuous buffers not be used. They do offer better security and are, in fact, sometimes required (SSH uses them),
438
- * however, they are also less intuitive and more likely to cause you problems.
439
- *
440
- * @see Crypt_RC4::disableContinuousBuffer()
441
- * @access public
442
- */
443
- function enableContinuousBuffer()
444
- {
445
- $this->continuousBuffer = true;
446
  }
447
 
448
  /**
449
- * Treat consecutive packets as if they are a discontinuous buffer.
450
- *
451
- * The default behavior.
452
  *
453
- * @see Crypt_RC4::enableContinuousBuffer()
454
- * @access public
 
 
 
 
455
  */
456
- function disableContinuousBuffer()
457
  {
458
- if ( CRYPT_RC4_MODE == CRYPT_RC4_MODE_INTERNAL ) {
459
- $this->encryptIndex = $this->decryptIndex = array(0, 0);
460
- $this->setKey($this->key);
461
  }
462
 
463
- $this->continuousBuffer = false;
464
- }
465
-
466
- /**
467
- * Dummy function.
468
- *
469
- * Since RC4 is a stream cipher and not a block cipher, no padding is necessary. The only reason this function is
470
- * included is so that you can switch between a block cipher and a stream cipher transparently.
471
- *
472
- * @see Crypt_RC4::disablePadding()
473
- * @access public
474
- */
475
- function enablePadding()
476
- {
477
- }
478
-
479
- /**
480
- * Dummy function.
481
- *
482
- * @see Crypt_RC4::enablePadding()
483
- * @access public
484
- */
485
- function disablePadding()
486
- {
487
- }
488
-
489
- /**
490
- * Class destructor.
491
- *
492
- * Will be called, automatically, if you're using PHP5. If you're using PHP4, call it yourself. Only really
493
- * needs to be called if mcrypt is being used.
494
- *
495
- * @access public
496
- */
497
- function __destruct()
498
- {
499
- if ( CRYPT_RC4_MODE == CRYPT_RC4_MODE_MCRYPT ) {
500
- $this->_closeMCrypt();
501
  }
502
- }
503
-
504
- /**
505
- * Properly close the MCrypt objects.
506
- *
507
- * @access prviate
508
- */
509
- function _closeMCrypt()
510
- {
511
- if ( $this->encryptStream !== false ) {
512
- if ( $this->continuousBuffer ) {
513
- mcrypt_generic_deinit($this->encryptStream);
514
- }
515
 
516
- mcrypt_module_close($this->encryptStream);
 
 
 
 
 
517
 
518
- $this->encryptStream = false;
 
 
519
  }
520
 
521
- if ( $this->decryptStream !== false ) {
522
- if ( $this->continuousBuffer ) {
523
- mcrypt_generic_deinit($this->decryptStream);
524
- }
525
-
526
- mcrypt_module_close($this->decryptStream);
527
-
528
- $this->decryptStream = false;
529
- }
530
  }
531
  }
1
  <?php
 
2
 
3
  /**
4
  * Pure-PHP implementation of RC4.
13
  * - {@link http://en.wikipedia.org/wiki/RC4 - Wikipedia: RC4}
14
  *
15
  * RC4 is also known as ARCFOUR or ARC4. The reason is elaborated upon at Wikipedia. This class is named RC4 and not
16
+ * ARCFOUR or ARC4 because RC4 is how it is referred to in the SSH1 specification.
17
  *
18
  * Here's a short example of how to use this library:
19
  * <code>
20
  * <?php
21
+ * include 'Crypt/RC4.php';
22
  *
23
  * $rc4 = new Crypt_RC4();
24
  *
40
  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
41
  * copies of the Software, and to permit persons to whom the Software is
42
  * furnished to do so, subject to the following conditions:
43
+ *
44
  * The above copyright notice and this permission notice shall be included in
45
  * all copies or substantial portions of the Software.
46
+ *
47
  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
48
  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
49
  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
52
  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
53
  * THE SOFTWARE.
54
  *
55
+ * @category Crypt
56
+ * @package Crypt_RC4
57
+ * @author Jim Wigginton <terrafrost@php.net>
58
+ * @copyright MMVII Jim Wigginton
59
+ * @license http://www.opensource.org/licenses/mit-license.html MIT License
60
+ * @link http://phpseclib.sourceforge.net
 
61
  */
62
 
63
+ /**
64
+ * Include Crypt_Base
65
+ *
66
+ * Base cipher class
67
+ */
68
+ if (!class_exists('Crypt_Base')) {
69
+ include_once 'Base.php';
70
+ }
71
+
72
  /**#@+
73
  * @access private
74
  * @see Crypt_RC4::Crypt_RC4()
76
  /**
77
  * Toggles the internal implementation
78
  */
79
+ define('CRYPT_RC4_MODE_INTERNAL', CRYPT_MODE_INTERNAL);
80
  /**
81
  * Toggles the mcrypt implementation
82
  */
83
+ define('CRYPT_RC4_MODE_MCRYPT', CRYPT_MODE_MCRYPT);
84
  /**#@-*/
85
 
86
  /**#@+
94
  /**
95
  * Pure-PHP implementation of RC4.
96
  *
97
+ * @package Crypt_RC4
98
  * @author Jim Wigginton <terrafrost@php.net>
 
99
  * @access public
 
100
  */
101
+ class Crypt_RC4 extends Crypt_Base
102
+ {
103
  /**
104
+ * Block Length of the cipher
105
  *
106
+ * RC4 is a stream cipher
107
+ * so we the block_size to 0
108
+ *
109
+ * @see Crypt_Base::block_size
110
+ * @var Integer
111
  * @access private
112
  */
113
+ var $block_size = 0;
114
 
115
  /**
116
+ * The default password key_size used by setPassword()
 
 
117
  *
118
+ * @see Crypt_Base::password_key_size
119
+ * @see Crypt_Base::setPassword()
120
+ * @var Integer
121
  * @access private
122
  */
123
+ var $password_key_size = 128; // = 1024 bits
124
 
125
  /**
126
+ * The namespace used by the cipher for its constants.
 
 
127
  *
128
+ * @see Crypt_Base::const_namespace
129
+ * @var String
130
  * @access private
131
  */
132
+ var $const_namespace = 'RC4';
133
 
134
  /**
135
+ * The mcrypt specific name of the cipher
136
  *
137
+ * @see Crypt_Base::cipher_name_mcrypt
138
+ * @var String
139
  * @access private
140
  */
141
+ var $cipher_name_mcrypt = 'arcfour';
142
 
143
  /**
144
+ * Holds whether performance-optimized $inline_crypt() can/should be used.
145
  *
146
+ * @see Crypt_Base::inline_crypt
147
+ * @var mixed
148
  * @access private
149
  */
150
+ var $use_inline_crypt = false; // currently not available
151
 
152
  /**
153
+ * The Key
 
 
154
  *
155
+ * @see Crypt_RC4::setKey()
156
+ * @var String
157
  * @access private
158
  */
159
+ var $key = "\0";
160
 
161
  /**
162
+ * The Key Stream for decryption and encryption
163
  *
164
+ * @see Crypt_RC4::setKey()
165
+ * @var Array
166
  * @access private
167
  */
168
+ var $stream;
169
 
170
  /**
171
  * Default Constructor.
172
  *
173
  * Determines whether or not the mcrypt extension should be used.
174
  *
175
+ * @see Crypt_Base::Crypt_Base()
176
  * @return Crypt_RC4
177
  * @access public
178
  */
179
  function Crypt_RC4()
180
  {
181
+ parent::Crypt_Base(CRYPT_MODE_STREAM);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
182
  }
183
 
184
  /**
204
  {
205
  }
206
 
207
+ /**
208
+ * Sets the key.
209
+ *
210
+ * Keys can be between 1 and 256 bytes long. If they are longer then 256 bytes, the first 256 bytes will
211
+ * be used. If no key is explicitly set, it'll be assumed to be a single null byte.
212
+ *
213
+ * @access public
214
+ * @see Crypt_Base::setKey()
215
+ * @param String $key
216
+ */
217
+ function setKey($key)
218
+ {
219
+ parent::setKey(substr($key, 0, 256));
220
+ }
221
+
222
  /**
223
  * Encrypts a message.
224
  *
225
+ * @see Crypt_Base::decrypt()
226
  * @see Crypt_RC4::_crypt()
227
  * @access public
228
  * @param String $plaintext
229
+ * @return String $ciphertext
230
  */
231
  function encrypt($plaintext)
232
  {
233
+ if ($this->engine == CRYPT_MODE_MCRYPT) {
234
+ return parent::encrypt($plaintext);
235
+ }
236
  return $this->_crypt($plaintext, CRYPT_RC4_ENCRYPT);
237
  }
238
 
240
  * Decrypts a message.
241
  *
242
  * $this->decrypt($this->encrypt($plaintext)) == $this->encrypt($this->encrypt($plaintext)).
243
+ * At least if the continuous buffer is disabled.
244
  *
245
+ * @see Crypt_Base::encrypt()
246
  * @see Crypt_RC4::_crypt()
247
  * @access public
248
  * @param String $ciphertext
249
+ * @return String $plaintext
250
  */
251
  function decrypt($ciphertext)
252
  {
253
+ if ($this->engine == CRYPT_MODE_MCRYPT) {
254
+ return parent::decrypt($ciphertext);
255
+ }
256
  return $this->_crypt($ciphertext, CRYPT_RC4_DECRYPT);
257
  }
258
 
259
+
260
  /**
261
+ * Setup the key (expansion)
262
  *
263
+ * @see Crypt_Base::_setupKey()
 
264
  * @access private
 
 
265
  */
266
+ function _setupKey()
267
  {
268
+ $key = $this->key;
269
+ $keyLength = strlen($key);
270
+ $keyStream = range(0, 255);
271
+ $j = 0;
272
+ for ($i = 0; $i < 256; $i++) {
273
+ $j = ($j + $keyStream[$i] + ord($key[$i % $keyLength])) & 255;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
274
  $temp = $keyStream[$i];
275
  $keyStream[$i] = $keyStream[$j];
276
  $keyStream[$j] = $temp;
 
 
277
  }
278
 
279
+ $this->stream = array();
280
+ $this->stream[CRYPT_RC4_DECRYPT] = $this->stream[CRYPT_RC4_ENCRYPT] = array(
281
+ 0, // index $i
282
+ 0, // index $j
283
+ $keyStream
284
+ );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
285
  }
286
 
287
  /**
288
+ * Encrypts or decrypts a message.
 
 
289
  *
290
+ * @see Crypt_RC4::encrypt()
291
+ * @see Crypt_RC4::decrypt()
292
+ * @access private
293
+ * @param String $text
294
+ * @param Integer $mode
295
+ * @return String $text
296
  */
297
+ function _crypt($text, $mode)
298
  {
299
+ if ($this->changed) {
300
+ $this->_setup();
301
+ $this->changed = false;
302
  }
303
 
304
+ $stream = &$this->stream[$mode];
305
+ if ($this->continuousBuffer) {
306
+ $i = &$stream[0];
307
+ $j = &$stream[1];
308
+ $keyStream = &$stream[2];
309
+ } else {
310
+ $i = $stream[0];
311
+ $j = $stream[1];
312
+ $keyStream = $stream[2];
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
313
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
314
 
315
+ $len = strlen($text);
316
+ for ($k = 0; $k < $len; ++$k) {
317
+ $i = ($i + 1) & 255;
318
+ $ksi = $keyStream[$i];
319
+ $j = ($j + $ksi) & 255;
320
+ $ksj = $keyStream[$j];
321
 
322
+ $keyStream[$i] = $ksj;
323
+ $keyStream[$j] = $ksi;
324
+ $text[$k] = $text[$k] ^ chr($keyStream[($ksj + $ksi) & 255]);
325
  }
326
 
327
+ return $text;
 
 
 
 
 
 
 
 
328
  }
329
  }
phpseclib/Crypt/RSA.php CHANGED
@@ -1,2646 +1,2990 @@
1
- <?php
2
- /* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
3
-
4
- /**
5
- * Pure-PHP PKCS#1 (v2.1) compliant implementation of RSA.
6
- *
7
- * PHP versions 4 and 5
8
- *
9
- * Here's an example of how to encrypt and decrypt text with this library:
10
- * <code>
11
- * <?php
12
- * include('Crypt/RSA.php');
13
- *
14
- * $rsa = new Crypt_RSA();
15
- * extract($rsa->createKey());
16
- *
17
- * $plaintext = 'terrafrost';
18
- *
19
- * $rsa->loadKey($privatekey);
20
- * $ciphertext = $rsa->encrypt($plaintext);
21
- *
22
- * $rsa->loadKey($publickey);
23
- * echo $rsa->decrypt($ciphertext);
24
- * ?>
25
- * </code>
26
- *
27
- * Here's an example of how to create signatures and verify signatures with this library:
28
- * <code>
29
- * <?php
30
- * include('Crypt/RSA.php');
31
- *
32
- * $rsa = new Crypt_RSA();
33
- * extract($rsa->createKey());
34
- *
35
- * $plaintext = 'terrafrost';
36
- *
37
- * $rsa->loadKey($privatekey);
38
- * $signature = $rsa->sign($plaintext);
39
- *
40
- * $rsa->loadKey($publickey);
41
- * echo $rsa->verify($plaintext, $signature) ? 'verified' : 'unverified';
42
- * ?>
43
- * </code>
44
- *
45
- * LICENSE: Permission is hereby granted, free of charge, to any person obtaining a copy
46
- * of this software and associated documentation files (the "Software"), to deal
47
- * in the Software without restriction, including without limitation the rights
48
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
49
- * copies of the Software, and to permit persons to whom the Software is
50
- * furnished to do so, subject to the following conditions:
51
- *
52
- * The above copyright notice and this permission notice shall be included in
53
- * all copies or substantial portions of the Software.
54
- *
55
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
56
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
57
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
58
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
59
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
60
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
61
- * THE SOFTWARE.
62
- *
63
- * @category Crypt
64
- * @package Crypt_RSA
65
- * @author Jim Wigginton <terrafrost@php.net>
66
- * @copyright MMIX Jim Wigginton
67
- * @license http://www.opensource.org/licenses/mit-license.html MIT License
68
- * @version $Id: RSA.php,v 1.19 2010/09/12 21:58:54 terrafrost Exp $
69
- * @link http://phpseclib.sourceforge.net
70
- */
71
-
72
- /**
73
- * Include Math_BigInteger
74
- */
75
- if (!class_exists('Math_BigInteger')) {
76
- require_once('Math/BigInteger.php');
77
- }
78
-
79
- /**
80
- * Include Crypt_Random
81
- */
82
- // the class_exists() will only be called if the crypt_random_string function hasn't been defined and
83
- // will trigger a call to __autoload() if you're wanting to auto-load classes
84
- // call function_exists() a second time to stop the require_once from being called outside
85
- // of the auto loader
86
- if (!function_exists('crypt_random_string') && !class_exists('Crypt_Random') && !function_exists('crypt_random_string')) {
87
- require_once('Crypt/Random.php');
88
- }
89
-
90
- /**
91
- * Include Crypt_Hash
92
- */
93
- if (!class_exists('Crypt_Hash')) {
94
- require_once('Crypt/Hash.php');
95
- }
96
-
97
- /**#@+
98
- * @access public
99
- * @see Crypt_RSA::encrypt()
100
- * @see Crypt_RSA::decrypt()
101
- */
102
- /**
103
- * Use {@link http://en.wikipedia.org/wiki/Optimal_Asymmetric_Encryption_Padding Optimal Asymmetric Encryption Padding}
104
- * (OAEP) for encryption / decryption.
105
- *
106
- * Uses sha1 by default.
107
- *
108
- * @see Crypt_RSA::setHash()
109
- * @see Crypt_RSA::setMGFHash()
110
- */
111
- define('CRYPT_RSA_ENCRYPTION_OAEP', 1);
112
- /**
113
- * Use PKCS#1 padding.
114
- *
115
- * Although CRYPT_RSA_ENCRYPTION_OAEP offers more security, including PKCS#1 padding is necessary for purposes of backwards
116
- * compatability with protocols (like SSH-1) written before OAEP's introduction.
117
- */
118
- define('CRYPT_RSA_ENCRYPTION_PKCS1', 2);
119
- /**#@-*/
120
-
121
- /**#@+
122
- * @access public
123
- * @see Crypt_RSA::sign()
124
- * @see Crypt_RSA::verify()
125
- * @see Crypt_RSA::setHash()
126
- */
127
- /**
128
- * Use the Probabilistic Signature Scheme for signing
129
- *
130
- * Uses sha1 by default.
131
- *
132
- * @see Crypt_RSA::setSaltLength()
133
- * @see Crypt_RSA::setMGFHash()
134
- */
135
- define('CRYPT_RSA_SIGNATURE_PSS', 1);
136
- /**
137
- * Use the PKCS#1 scheme by default.
138
- *
139
- * Although CRYPT_RSA_SIGNATURE_PSS offers more security, including PKCS#1 signing is necessary for purposes of backwards
140
- * compatability with protocols (like SSH-2) written before PSS's introduction.
141
- */
142
- define('CRYPT_RSA_SIGNATURE_PKCS1', 2);
143
- /**#@-*/
144
-
145
- /**#@+
146
- * @access private
147
- * @see Crypt_RSA::createKey()
148
- */
149
- /**
150
- * ASN1 Integer
151
- */
152
- define('CRYPT_RSA_ASN1_INTEGER', 2);
153
- /**
154
- * ASN1 Bit String
155
- */
156
- define('CRYPT_RSA_ASN1_BITSTRING', 3);
157
- /**
158
- * ASN1 Sequence (with the constucted bit set)
159
- */
160
- define('CRYPT_RSA_ASN1_SEQUENCE', 48);
161
- /**#@-*/
162
-
163
- /**#@+
164
- * @access private
165
- * @see Crypt_RSA::Crypt_RSA()
166
- */
167
- /**
168
- * To use the pure-PHP implementation
169
- */
170
- define('CRYPT_RSA_MODE_INTERNAL', 1);
171
- /**
172
- * To use the OpenSSL library
173
- *
174
- * (if enabled; otherwise, the internal implementation will be used)
175
- */
176
- define('CRYPT_RSA_MODE_OPENSSL', 2);
177
- /**#@-*/
178
-
179
- /**
180
- * Default openSSL configuration file.
181
- */
182
- define('CRYPT_RSA_OPENSSL_CONFIG', dirname(__FILE__) . '/../openssl.cnf');
183
-
184
-
185
- /**#@+
186
- * @access public
187
- * @see Crypt_RSA::createKey()
188
- * @see Crypt_RSA::setPrivateKeyFormat()
189
- */
190
- /**
191
- * PKCS#1 formatted private key
192
- *
193
- * Used by OpenSSH
194
- */
195
- define('CRYPT_RSA_PRIVATE_FORMAT_PKCS1', 0);
196
- /**
197
- * PuTTY formatted private key
198
- */
199
- define('CRYPT_RSA_PRIVATE_FORMAT_PUTTY', 1);
200
- /**
201
- * XML formatted private key
202
- */
203
- define('CRYPT_RSA_PRIVATE_FORMAT_XML', 2);
204
- /**#@-*/
205
-
206
- /**#@+
207
- * @access public
208
- * @see Crypt_RSA::createKey()
209
- * @see Crypt_RSA::setPublicKeyFormat()
210
- */
211
- /**
212
- * Raw public key
213
- *
214
- * An array containing two Math_BigInteger objects.
215
- *
216
- * The exponent can be indexed with any of the following:
217
- *
218
- * 0, e, exponent, publicExponent
219
- *
220
- * The modulus can be indexed with any of the following:
221
- *
222
- * 1, n, modulo, modulus
223
- */
224
- define('CRYPT_RSA_PUBLIC_FORMAT_RAW', 3);
225
- /**
226
- * PKCS#1 formatted public key (raw)
227
- *
228
- * Used by File/X509.php
229
- */
230
- define('CRYPT_RSA_PUBLIC_FORMAT_PKCS1_RAW', 4);
231
- /**
232
- * XML formatted public key
233
- */
234
- define('CRYPT_RSA_PUBLIC_FORMAT_XML', 5);
235
- /**
236
- * OpenSSH formatted public key
237
- *
238
- * Place in $HOME/.ssh/authorized_keys
239
- */
240
- define('CRYPT_RSA_PUBLIC_FORMAT_OPENSSH', 6);
241
- /**
242
- * PKCS#1 formatted public key (encapsulated)
243
- *
244
- * Used by PHP's openssl_public_encrypt() and openssl's rsautl (when -pubin is set)
245
- */
246
- define('CRYPT_RSA_PUBLIC_FORMAT_PKCS1', 7);
247
- /**#@-*/
248
-
249
- /**
250
- * Pure-PHP PKCS#1 compliant implementation of RSA.
251
- *
252
- * @author Jim Wigginton <terrafrost@php.net>
253
- * @version 0.1.0
254
- * @access public
255
- * @package Crypt_RSA
256
- */
257
- class Crypt_RSA {
258
- /**
259
- * Precomputed Zero
260
- *
261
- * @var Array
262
- * @access private
263
- */
264
- var $zero;
265
-
266
- /**
267
- * Precomputed One
268
- *
269
- * @var Array
270
- * @access private
271
- */
272
- var $one;
273
-
274
- /**
275
- * Private Key Format
276
- *
277
- * @var Integer
278
- * @access private
279
- */
280
- var $privateKeyFormat = CRYPT_RSA_PRIVATE_FORMAT_PKCS1;
281
-
282
- /**
283
- * Public Key Format
284
- *
285
- * @var Integer
286
- * @access public
287
- */
288
- var $publicKeyFormat = CRYPT_RSA_PUBLIC_FORMAT_PKCS1;
289
-
290
- /**
291
- * Modulus (ie. n)
292
- *
293
- * @var Math_BigInteger
294
- * @access private
295
- */
296
- var $modulus;
297
-
298
- /**
299
- * Modulus length
300
- *
301
- * @var Math_BigInteger
302
- * @access private
303
- */
304
- var $k;
305
-
306
- /**
307
- * Exponent (ie. e or d)
308
- *
309
- * @var Math_BigInteger
310
- * @access private
311
- */
312
- var $exponent;
313
-
314
- /**
315
- * Primes for Chinese Remainder Theorem (ie. p and q)
316
- *
317
- * @var Array
318
- * @access private
319
- */
320
- var $primes;
321
-
322
- /**
323
- * Exponents for Chinese Remainder Theorem (ie. dP and dQ)
324
- *
325
- * @var Array
326
- * @access private
327
- */
328
- var $exponents;
329
-
330
- /**
331
- * Coefficients for Chinese Remainder Theorem (ie. qInv)
332
- *
333
- * @var Array
334
- * @access private
335
- */
336
- var $coefficients;
337
-
338
- /**
339
- * Hash name
340
- *
341
- * @var String
342
- * @access private
343
- */
344
- var $hashName;
345
-
346
- /**
347
- * Hash function
348
- *
349
- * @var Crypt_Hash
350
- * @access private
351
- */
352
- var $hash;
353
-
354
- /**
355
- * Length of hash function output
356
- *
357
- * @var Integer
358
- * @access private
359
- */
360
- var $hLen;
361
-
362
- /**
363
- * Length of salt
364
- *
365
- * @var Integer
366
- * @access private
367
- */
368
- var $sLen;
369
-
370
- /**
371
- * Hash function for the Mask Generation Function
372
- *
373
- * @var Crypt_Hash
374
- * @access private
375
- */
376
- var $mgfHash;
377
-
378
- /**
379
- * Length of MGF hash function output
380
- *
381
- * @var Integer
382
- * @access private
383
- */
384
- var $mgfHLen;
385
-
386
- /**
387
- * Encryption mode
388
- *
389
- * @var Integer
390
- * @access private
391
- */
392
- var $encryptionMode = CRYPT_RSA_ENCRYPTION_OAEP;
393
-
394
- /**
395
- * Signature mode
396
- *
397
- * @var Integer
398
- * @access private
399
- */
400
- var $signatureMode = CRYPT_RSA_SIGNATURE_PSS;
401
-
402
- /**
403
- * Public Exponent
404
- *
405
- * @var Mixed
406
- * @access private
407
- */
408
- var $publicExponent = false;
409
-
410
- /**
411
- * Password
412
- *
413
- * @var String
414
- * @access private
415
- */
416
- var $password = false;
417
-
418
- /**
419
- * Components
420
- *
421
- * For use with parsing XML formatted keys. PHP's XML Parser functions use utilized - instead of PHP's DOM functions -
422
- * because PHP's XML Parser functions work on PHP4 whereas PHP's DOM functions - although surperior - don't.
423
- *
424
- * @see Crypt_RSA::_start_element_handler()
425
- * @var Array
426
- * @access private
427
- */
428
- var $components = array();
429
-
430
- /**
431
- * Current String
432
- *
433
- * For use with parsing XML formatted keys.
434
- *
435
- * @see Crypt_RSA::_character_handler()
436
- * @see Crypt_RSA::_stop_element_handler()
437
- * @var Mixed
438
- * @access private
439
- */
440
- var $current;
441
-
442
- /**
443
- * OpenSSL configuration file name.
444
- *
445
- * Set to NULL to use system configuration file.
446
- * @see Crypt_RSA::createKey()
447
- * @var Mixed
448
- * @Access public
449
- */
450
- var $configFile;
451
-
452
- /**
453
- * The constructor
454
- *
455
- * If you want to make use of the openssl extension, you'll need to set the mode manually, yourself. The reason
456
- * Crypt_RSA doesn't do it is because OpenSSL doesn't fail gracefully. openssl_pkey_new(), in particular, requires
457
- * openssl.cnf be present somewhere and, unfortunately, the only real way to find out is too late.
458
- *
459
- * @return Crypt_RSA
460
- * @access public
461
- */
462
- function Crypt_RSA()
463
- {
464
- $this->configFile = CRYPT_RSA_OPENSSL_CONFIG;
465
-
466
- if ( !defined('CRYPT_RSA_MODE') ) {
467
- switch (true) {
468
- case extension_loaded('openssl') && version_compare(PHP_VERSION, '4.2.0', '>='):
469
- define('CRYPT_RSA_MODE', CRYPT_RSA_MODE_OPENSSL);
470
- break;
471
- default:
472
- define('CRYPT_RSA_MODE', CRYPT_RSA_MODE_INTERNAL);
473
- }
474
- }
475
-
476
- if (!defined('CRYPT_RSA_COMMENT')) {
477
- define('CRYPT_RSA_COMMENT', 'phpseclib-generated-key');
478
- }
479
-
480
- $this->zero = new Math_BigInteger();
481
- $this->one = new Math_BigInteger(1);
482
-
483
- $this->hash = new Crypt_Hash('sha1');
484
- $this->hLen = $this->hash->getLength();
485
- $this->hashName = 'sha1';
486
- $this->mgfHash = new Crypt_Hash('sha1');
487
- $this->mgfHLen = $this->mgfHash->getLength();
488
- }
489
-
490
- /**
491
- * Create public / private key pair
492
- *
493
- * Returns an array with the following three elements:
494
- * - 'privatekey': The private key.
495
- * - 'publickey': The public key.
496
- * - 'partialkey': A partially computed key (if the execution time exceeded $timeout).
497
- * Will need to be passed back to Crypt_RSA::createKey() as the third parameter for further processing.
498
- *
499
- * @access public
500
- * @param optional Integer $bits
501
- * @param optional Integer $timeout
502
- * @param optional Math_BigInteger $p
503
- */
504
- function createKey($bits = 1024, $timeout = false, $partial = array())
505
- {
506
- if (!defined('CRYPT_RSA_EXPONENT')) {
507
- // http://en.wikipedia.org/wiki/65537_%28number%29
508
- define('CRYPT_RSA_EXPONENT', '65537');
509
- }
510
- // per <http://cseweb.ucsd.edu/~hovav/dist/survey.pdf#page=5>, this number ought not result in primes smaller
511
- // than 256 bits. as a consequence if the key you're trying to create is 1024 bits and you've set CRYPT_RSA_SMALLEST_PRIME
512
- // to 384 bits then you're going to get a 384 bit prime and a 640 bit prime (384 + 1024 % 384). at least if
513
- // CRYPT_RSA_MODE is set to CRYPT_RSA_MODE_INTERNAL. if CRYPT_RSA_MODE is set to CRYPT_RSA_MODE_OPENSSL then
514
- // CRYPT_RSA_SMALLEST_PRIME is ignored (ie. multi-prime RSA support is more intended as a way to speed up RSA key
515
- // generation when there's a chance neither gmp nor OpenSSL are installed)
516
- if (!defined('CRYPT_RSA_SMALLEST_PRIME')) {
517
- define('CRYPT_RSA_SMALLEST_PRIME', 4096);
518
- }
519
-
520
- // OpenSSL uses 65537 as the exponent and requires RSA keys be 384 bits minimum
521
- if ( CRYPT_RSA_MODE == CRYPT_RSA_MODE_OPENSSL && $bits >= 384 && CRYPT_RSA_EXPONENT == 65537) {
522
- $config = array();
523
- if (isset($this->configFile)) {
524
- $config['config'] = $this->configFile;
525
- }
526
- $rsa = openssl_pkey_new(array('private_key_bits' => $bits) + $config);
527
- openssl_pkey_export($rsa, $privatekey, NULL, $config);
528
- $publickey = openssl_pkey_get_details($rsa);
529
- $publickey = $publickey['key'];
530
-
531
- $privatekey = call_user_func_array(array($this, '_convertPrivateKey'), array_values($this->_parseKey($privatekey, CRYPT_RSA_PRIVATE_FORMAT_PKCS1)));
532
- $publickey = call_user_func_array(array($this, '_convertPublicKey'), array_values($this->_parseKey($publickey, CRYPT_RSA_PUBLIC_FORMAT_PKCS1)));
533
-
534
- // clear the buffer of error strings stemming from a minimalistic openssl.cnf
535
- while (openssl_error_string() !== false);
536
-
537
- return array(
538
- 'privatekey' => $privatekey,
539
- 'publickey' => $publickey,
540
- 'partialkey' => false
541
- );
542
- }
543
-
544
- static $e;
545
- if (!isset($e)) {
546
- $e = new Math_BigInteger(CRYPT_RSA_EXPONENT);
547
- }
548
-
549
- extract($this->_generateMinMax($bits));
550
- $absoluteMin = $min;
551
- $temp = $bits >> 1; // divide by two to see how many bits P and Q would be
552
- if ($temp > CRYPT_RSA_SMALLEST_PRIME) {
553
- $num_primes = floor($bits / CRYPT_RSA_SMALLEST_PRIME);
554
- $temp = CRYPT_RSA_SMALLEST_PRIME;
555
- } else {
556
- $num_primes = 2;
557
- }
558
- extract($this->_generateMinMax($temp + $bits % $temp));
559
- $finalMax = $max;
560
- extract($this->_generateMinMax($temp));
561
-
562
- $generator = new Math_BigInteger();
563
-
564
- $n = $this->one->copy();
565
- if (!empty($partial)) {
566
- extract(unserialize($partial));
567
- } else {
568
- $exponents = $coefficients = $primes = array();
569
- $lcm = array(
570
- 'top' => $this->one->copy(),
571
- 'bottom' => false
572
- );
573
- }
574
-
575
- $start = time();
576
- $i0 = count($primes) + 1;
577
-
578
- do {
579
- for ($i = $i0; $i <= $num_primes; $i++) {
580
- if ($timeout !== false) {
581
- $timeout-= time() - $start;
582
- $start = time();
583
- if ($timeout <= 0) {
584
- return array(
585
- 'privatekey' => '',
586
- 'publickey' => '',
587
- 'partialkey' => serialize(array(
588
- 'primes' => $primes,
589
- 'coefficients' => $coefficients,
590
- 'lcm' => $lcm,
591
- 'exponents' => $exponents
592
- ))
593
- );
594
- }
595
- }
596
-
597
- if ($i == $num_primes) {
598
- list($min, $temp) = $absoluteMin->divide($n);
599
- if (!$temp->equals($this->zero)) {
600
- $min = $min->add($this->one); // ie. ceil()
601
- }
602
- $primes[$i] = $generator->randomPrime($min, $finalMax, $timeout);
603
- } else {
604
- $primes[$i] = $generator->randomPrime($min, $max, $timeout);
605
- }
606
-
607
- if ($primes[$i] === false) { // if we've reached the timeout
608
- if (count($primes) > 1) {
609
- $partialkey = '';
610
- } else {
611
- array_pop($primes);
612
- $partialkey = serialize(array(
613
- 'primes' => $primes,
614
- 'coefficients' => $coefficients,
615
- 'lcm' => $lcm,
616
- 'exponents' => $exponents
617
- ));
618
- }
619
-
620
- return array(
621
- 'privatekey' => '',
622
- 'publickey' => '',
623
- 'partialkey' => $partialkey
624
- );
625
- }
626
-
627
- // the first coefficient is calculated differently from the rest
628
- // ie. instead of being $primes[1]->modInverse($primes[2]), it's $primes[2]->modInverse($primes[1])
629
- if ($i > 2) {
630
- $coefficients[$i] = $n->modInverse($primes[$i]);
631
- }
632
-
633
- $n = $n->multiply($primes[$i]);
634
-
635
- $temp = $primes[$i]->subtract($this->one);
636
-
637
- // textbook RSA implementations use Euler's totient function instead of the least common multiple.
638
- // see http://en.wikipedia.org/wiki/Euler%27s_totient_function
639
- $lcm['top'] = $lcm['top']->multiply($temp);
640
- $lcm['bottom'] = $lcm['bottom'] === false ? $temp : $lcm['bottom']->gcd($temp);
641
-
642
- $exponents[$i] = $e->modInverse($temp);
643
- }
644
-
645
- list($lcm) = $lcm['top']->divide($lcm['bottom']);
646
- $gcd = $lcm->gcd($e);
647
- $i0 = 1;
648
- } while (!$gcd->equals($this->one));
649
-
650
- $d = $e->modInverse($lcm);
651
-
652
- $coefficients[2] = $primes[2]->modInverse($primes[1]);
653
-
654
- // from <http://tools.ietf.org/html/rfc3447#appendix-A.1.2>:
655
- // RSAPrivateKey ::= SEQUENCE {
656
- // version Version,
657
- // modulus INTEGER, -- n
658
- // publicExponent INTEGER, -- e
659
- // privateExponent INTEGER, -- d
660
- // prime1 INTEGER, -- p
661
- // prime2 INTEGER, -- q
662
- // exponent1 INTEGER, -- d mod (p-1)
663
- // exponent2 INTEGER, -- d mod (q-1)
664
- // coefficient INTEGER, -- (inverse of q) mod p
665
- // otherPrimeInfos OtherPrimeInfos OPTIONAL
666
- // }
667
-
668
- return array(
669
- 'privatekey' => $this->_convertPrivateKey($n, $e, $d, $primes, $exponents, $coefficients),
670
- 'publickey' => $this->_convertPublicKey($n, $e),
671
- 'partialkey' => false
672
- );
673
- }
674
-
675
- /**
676
- * Convert a private key to the appropriate format.
677
- *
678
- * @access private
679
- * @see setPrivateKeyFormat()
680
- * @param String $RSAPrivateKey
681
- * @return String
682
- */
683
- function _convertPrivateKey($n, $e, $d, $primes, $exponents, $coefficients)
684
- {
685
- $num_primes = count($primes);
686
- $raw = array(
687
- 'version' => $num_primes == 2 ? chr(0) : chr(1), // two-prime vs. multi
688
- 'modulus' => $n->toBytes(true),
689
- 'publicExponent' => $e->toBytes(true),
690
- 'privateExponent' => $d->toBytes(true),
691
- 'prime1' => $primes[1]->toBytes(true),
692
- 'prime2' => $primes[2]->toBytes(true),
693
- 'exponent1' => $exponents[1]->toBytes(true),
694
- 'exponent2' => $exponents[2]->toBytes(true),
695
- 'coefficient' => $coefficients[2]->toBytes(true)
696
- );
697
-
698
- // if the format in question does not support multi-prime rsa and multi-prime rsa was used,
699
- // call _convertPublicKey() instead.
700
- switch ($this->privateKeyFormat) {
701
- case CRYPT_RSA_PRIVATE_FORMAT_XML:
702
- if ($num_primes != 2) {
703
- return false;
704
- }
705
- return "<RSAKeyValue>\r\n" .
706
- ' <Modulus>' . base64_encode($raw['modulus']) . "</Modulus>\r\n" .
707
- ' <Exponent>' . base64_encode($raw['publicExponent']) . "</Exponent>\r\n" .
708
- ' <P>' . base64_encode($raw['prime1']) . "</P>\r\n" .
709
- ' <Q>' . base64_encode($raw['prime2']) . "</Q>\r\n" .
710
- ' <DP>' . base64_encode($raw['exponent1']) . "</DP>\r\n" .
711
- ' <DQ>' . base64_encode($raw['exponent2']) . "</DQ>\r\n" .
712
- ' <InverseQ>' . base64_encode($raw['coefficient']) . "</InverseQ>\r\n" .
713
- ' <D>' . base64_encode($raw['privateExponent']) . "</D>\r\n" .
714
- '</RSAKeyValue>';
715
- break;
716
- case CRYPT_RSA_PRIVATE_FORMAT_PUTTY:
717
- if ($num_primes != 2) {
718
- return false;
719
- }
720
- $key = "PuTTY-User-Key-File-2: ssh-rsa\r\nEncryption: ";
721
- $encryption = (!empty($this->password) || is_string($this->password)) ? 'aes256-cbc' : 'none';
722
- $key.= $encryption;
723
- $key.= "\r\nComment: " . CRYPT_RSA_COMMENT . "\r\n";
724
- $public = pack('Na*Na*Na*',
725
- strlen('ssh-rsa'), 'ssh-rsa', strlen($raw['publicExponent']), $raw['publicExponent'], strlen($raw['modulus']), $raw['modulus']
726
- );
727
- $source = pack('Na*Na*Na*Na*',
728
- strlen('ssh-rsa'), 'ssh-rsa', strlen($encryption), $encryption,
729
- strlen(CRYPT_RSA_COMMENT), CRYPT_RSA_COMMENT, strlen($public), $public
730
- );
731
- $public = base64_encode($public);
732
- $key.= "Public-Lines: " . ((strlen($public) + 32) >> 6) . "\r\n";
733
- $key.= chunk_split($public, 64);
734
- $private = pack('Na*Na*Na*Na*',
735
- strlen($raw['privateExponent']), $raw['privateExponent'], strlen($raw['prime1']), $raw['prime1'],
736
- strlen($raw['prime2']), $raw['prime2'], strlen($raw['coefficient']), $raw['coefficient']
737
- );
738
- if (empty($this->password) && !is_string($this->password)) {
739
- $source.= pack('Na*', strlen($private), $private);
740
- $hashkey = 'putty-private-key-file-mac-key';
741
- } else {
742
- $private.= crypt_random_string(16 - (strlen($private) & 15));
743
- $source.= pack('Na*', strlen($private), $private);
744
- if (!class_exists('Crypt_AES')) {
745
- require_once('Crypt/AES.php');
746
- }
747
- $sequence = 0;
748
- $symkey = '';
749
- while (strlen($symkey) < 32) {
750
- $temp = pack('Na*', $sequence++, $this->password);
751
- $symkey.= pack('H*', sha1($temp));
752
- }
753
- $symkey = substr($symkey, 0, 32);
754
- $crypto = new Crypt_AES();
755
-
756
- $crypto->setKey($symkey);
757
- $crypto->disablePadding();
758
- $private = $crypto->encrypt($private);
759
- $hashkey = 'putty-private-key-file-mac-key' . $this->password;
760
- }
761
-
762
- $private = base64_encode($private);
763
- $key.= 'Private-Lines: ' . ((strlen($private) + 32) >> 6) . "\r\n";
764
- $key.= chunk_split($private, 64);
765
- if (!class_exists('Crypt_Hash')) {
766
- require_once('Crypt/Hash.php');
767
- }
768
- $hash = new Crypt_Hash('sha1');
769
- $hash->setKey(pack('H*', sha1($hashkey)));
770
- $key.= 'Private-MAC: ' . bin2hex($hash->hash($source)) . "\r\n";
771
-
772
- return $key;
773
- default: // eg. CRYPT_RSA_PRIVATE_FORMAT_PKCS1
774
- $components = array();
775
- foreach ($raw as $name => $value) {
776
- $components[$name] = pack('Ca*a*', CRYPT_RSA_ASN1_INTEGER, $this->_encodeLength(strlen($value)), $value);
777
- }
778
-
779
- $RSAPrivateKey = implode('', $components);
780
-
781
- if ($num_primes > 2) {
782
- $OtherPrimeInfos = '';
783
- for ($i = 3; $i <= $num_primes; $i++) {
784
- // OtherPrimeInfos ::= SEQUENCE SIZE(1..MAX) OF OtherPrimeInfo
785
- //
786
- // OtherPrimeInfo ::= SEQUENCE {
787
- // prime INTEGER, -- ri
788
- // exponent INTEGER, -- di
789
- // coefficient INTEGER -- ti
790
- // }
791
- $OtherPrimeInfo = pack('Ca*a*', CRYPT_RSA_ASN1_INTEGER, $this->_encodeLength(strlen($primes[$i]->toBytes(true))), $primes[$i]->toBytes(true));
792
- $OtherPrimeInfo.= pack('Ca*a*', CRYPT_RSA_ASN1_INTEGER, $this->_encodeLength(strlen($exponents[$i]->toBytes(true))), $exponents[$i]->toBytes(true));
793
- $OtherPrimeInfo.= pack('Ca*a*', CRYPT_RSA_ASN1_INTEGER, $this->_encodeLength(strlen($coefficients[$i]->toBytes(true))), $coefficients[$i]->toBytes(true));
794
- $OtherPrimeInfos.= pack('Ca*a*', CRYPT_RSA_ASN1_SEQUENCE, $this->_encodeLength(strlen($OtherPrimeInfo)), $OtherPrimeInfo);
795
- }
796
- $RSAPrivateKey.= pack('Ca*a*', CRYPT_RSA_ASN1_SEQUENCE, $this->_encodeLength(strlen($OtherPrimeInfos)), $OtherPrimeInfos);
797
- }
798
-
799
- $RSAPrivateKey = pack('Ca*a*', CRYPT_RSA_ASN1_SEQUENCE, $this->_encodeLength(strlen($RSAPrivateKey)), $RSAPrivateKey);
800
-
801
- if (!empty($this->password) || is_string($this->password)) {
802
- $iv = crypt_random_string(8);
803
- $symkey = pack('H*', md5($this->password . $iv)); // symkey is short for symmetric key
804
- $symkey.= substr(pack('H*', md5($symkey . $this->password . $iv)), 0, 8);
805
- if (!class_exists('Crypt_TripleDES')) {
806
- require_once('Crypt/TripleDES.php');
807
- }
808
- $des = new Crypt_TripleDES();
809
- $des->setKey($symkey);
810
- $des->setIV($iv);
811
- $iv = strtoupper(bin2hex($iv));
812
- $RSAPrivateKey = "-----BEGIN RSA PRIVATE KEY-----\r\n" .
813
- "Proc-Type: 4,ENCRYPTED\r\n" .
814
- "DEK-Info: DES-EDE3-CBC,$iv\r\n" .
815
- "\r\n" .
816
- chunk_split(base64_encode($des->encrypt($RSAPrivateKey)), 64) .
817
- '-----END RSA PRIVATE KEY-----';
818
- } else {
819
- $RSAPrivateKey = "-----BEGIN RSA PRIVATE KEY-----\r\n" .
820
- chunk_split(base64_encode($RSAPrivateKey), 64) .
821
- '-----END RSA PRIVATE KEY-----';
822
- }
823
-
824
- return $RSAPrivateKey;
825
- }
826
- }
827
-
828
- /**
829
- * Convert a public key to the appropriate format
830
- *
831
- * @access private
832
- * @see setPublicKeyFormat()
833
- * @param String $RSAPrivateKey
834
- * @return String
835
- */
836
- function _convertPublicKey($n, $e)
837
- {
838
- $modulus = $n->toBytes(true);
839
- $publicExponent = $e->toBytes(true);
840
-
841
- switch ($this->publicKeyFormat) {
842
- case CRYPT_RSA_PUBLIC_FORMAT_RAW:
843
- return array('e' => $e->copy(), 'n' => $n->copy());
844
- case CRYPT_RSA_PUBLIC_FORMAT_XML:
845
- return "<RSAKeyValue>\r\n" .
846
- ' <Modulus>' . base64_encode($modulus) . "</Modulus>\r\n" .
847
- ' <Exponent>' . base64_encode($publicExponent) . "</Exponent>\r\n" .
848
- '</RSAKeyValue>';
849
- break;
850
- case CRYPT_RSA_PUBLIC_FORMAT_OPENSSH:
851
- // from <http://tools.ietf.org/html/rfc4253#page-15>:
852
- // string "ssh-rsa"
853
- // mpint e
854
- // mpint n
855
- $RSAPublicKey = pack('Na*Na*Na*', strlen('ssh-rsa'), 'ssh-rsa', strlen($publicExponent), $publicExponent, strlen($modulus), $modulus);
856
- $RSAPublicKey = 'ssh-rsa ' . base64_encode($RSAPublicKey) . ' ' . CRYPT_RSA_COMMENT;
857
-
858
- return $RSAPublicKey;
859
- default: // eg. CRYPT_RSA_PUBLIC_FORMAT_PKCS1_RAW or CRYPT_RSA_PUBLIC_FORMAT_PKCS1
860
- // from <http://tools.ietf.org/html/rfc3447#appendix-A.1.1>:
861
- // RSAPublicKey ::= SEQUENCE {
862
- // modulus INTEGER, -- n
863
- // publicExponent INTEGER -- e
864
- // }
865
- $components = array(
866
- 'modulus' => pack('Ca*a*', CRYPT_RSA_ASN1_INTEGER, $this->_encodeLength(strlen($modulus)), $modulus),
867
- 'publicExponent' => pack('Ca*a*', CRYPT_RSA_ASN1_INTEGER, $this->_encodeLength(strlen($publicExponent)), $publicExponent)
868
- );
869
-
870
- $RSAPublicKey = pack('Ca*a*a*',
871
- CRYPT_RSA_ASN1_SEQUENCE, $this->_encodeLength(strlen($components['modulus']) + strlen($components['publicExponent'])),
872
- $components['modulus'], $components['publicExponent']
873
- );
874
-
875
- if ($this->publicKeyFormat == CRYPT_RSA_PUBLIC_FORMAT_PKCS1) {
876
- // sequence(oid(1.2.840.113549.1.1.1), null)) = rsaEncryption.
877
- $rsaOID = pack('H*', '300d06092a864886f70d0101010500'); // hex version of MA0GCSqGSIb3DQEBAQUA
878
- $RSAPublicKey = chr(0) . $RSAPublicKey;
879
- $RSAPublicKey = chr(3) . $this->_encodeLength(strlen($RSAPublicKey)) . $RSAPublicKey;
880
-
881
- $RSAPublicKey = pack('Ca*a*',
882
- CRYPT_RSA_ASN1_SEQUENCE, $this->_encodeLength(strlen($rsaOID . $RSAPublicKey)), $rsaOID . $RSAPublicKey
883
- );
884
- }
885
-
886
- $RSAPublicKey = "-----BEGIN PUBLIC KEY-----\r\n" .
887
- chunk_split(base64_encode($RSAPublicKey), 64) .
888
- '-----END PUBLIC KEY-----';
889
-
890
- return $RSAPublicKey;
891
- }
892
- }
893
-
894
- /**
895
- * Break a public or private key down into its constituant components
896
- *
897
- * @access private
898
- * @see _convertPublicKey()
899
- * @see _convertPrivateKey()
900
- * @param String $key
901
- * @param Integer $type
902
- * @return Array
903
- */
904
- function _parseKey($key, $type)
905
- {
906
- if ($type != CRYPT_RSA_PUBLIC_FORMAT_RAW && !is_string($key)) {
907
- return false;
908
- }
909
-
910
- switch ($type) {
911
- case CRYPT_RSA_PUBLIC_FORMAT_RAW:
912
- if (!is_array($key)) {
913
- return false;
914
- }
915
- $components = array();
916
- switch (true) {
917
- case isset($key['e']):
918
- $components['publicExponent'] = $key['e']->copy();
919
- break;
920
- case isset($key['exponent']):
921
- $components['publicExponent'] = $key['exponent']->copy();
922
- break;
923
- case isset($key['publicExponent']):
924
- $components['publicExponent'] = $key['publicExponent']->copy();
925
- break;
926
- case isset($key[0]):
927
- $components['publicExponent'] = $key[0]->copy();
928
- }
929
- switch (true) {
930
- case isset($key['n']):
931
- $components['modulus'] = $key['n']->copy();
932
- break;
933
- case isset($key['modulo']):
934
- $components['modulus'] = $key['modulo']->copy();
935
- break;
936
- case isset($key['modulus']):
937
- $components['modulus'] = $key['modulus']->copy();
938
- break;
939
- case isset($key[1]):
940
- $components['modulus'] = $key[1]->copy();
941
- }
942
- return isset($components['modulus']) && isset($components['publicExponent']) ? $components : false;
943
- case CRYPT_RSA_PRIVATE_FORMAT_PKCS1:
944
- case CRYPT_RSA_PUBLIC_FORMAT_PKCS1:
945
- /* Although PKCS#1 proposes a format that public and private keys can use, encrypting them is
946
- "outside the scope" of PKCS#1. PKCS#1 then refers you to PKCS#12 and PKCS#15 if you're wanting to
947
- protect private keys, however, that's not what OpenSSL* does. OpenSSL protects private keys by adding
948
- two new "fields" to the key - DEK-Info and Proc-Type. These fields are discussed here:
949
-
950
- http://tools.ietf.org/html/rfc1421#section-4.6.1.1
951
- http://tools.ietf.org/html/rfc1421#section-4.6.1.3
952
-
953
- DES-EDE3-CBC as an algorithm, however, is not discussed anywhere, near as I can tell.
954
- DES-CBC and DES-EDE are discussed in RFC1423, however, DES-EDE3-CBC isn't, nor is its key derivation
955
- function. As is, the definitive authority on this encoding scheme isn't the IETF but rather OpenSSL's
956
- own implementation. ie. the implementation *is* the standard and any bugs that may exist in that
957
- implementation are part of the standard, as well.
958
-
959
- * OpenSSL is the de facto standard. It's utilized by OpenSSH and other projects */
960
- if (preg_match('#DEK-Info: (.+),(.+)#', $key, $matches)) {
961
- $iv = pack('H*', trim($matches[2]));
962
- $symkey = pack('H*', md5($this->password . substr($iv, 0, 8))); // symkey is short for symmetric key
963
- $symkey.= substr(pack('H*', md5($symkey . $this->password . $iv)), 0, 8);
964
- $ciphertext = preg_replace('#.+(\r|\n|\r\n)\1|[\r\n]|-.+-| #s', '', $key);
965
- $ciphertext = preg_match('#^[a-zA-Z\d/+]*={0,2}$#', $ciphertext) ? base64_decode($ciphertext) : false;
966
- if ($ciphertext === false) {
967
- $ciphertext = $key;
968
- }
969
- switch ($matches[1]) {
970
- case 'AES-128-CBC':
971
- if (!class_exists('Crypt_AES')) {
972
- require_once('Crypt/AES.php');
973
- }
974
- $symkey = substr($symkey, 0, 16);
975
- $crypto = new Crypt_AES();
976
- break;
977
- case 'DES-EDE3-CFB':
978
- if (!class_exists('Crypt_TripleDES')) {
979
- require_once('Crypt/TripleDES.php');
980
- }
981
- $crypto = new Crypt_TripleDES(CRYPT_DES_MODE_CFB);
982
- break;
983
- case 'DES-EDE3-CBC':
984
- if (!class_exists('Crypt_TripleDES')) {
985
- require_once('Crypt/TripleDES.php');
986
- }
987
- $crypto = new Crypt_TripleDES();
988
- break;
989
- case 'DES-CBC':
990
- if (!class_exists('Crypt_DES')) {
991
- require_once('Crypt/DES.php');
992
- }
993
- $crypto = new Crypt_DES();
994
- break;
995
- default:
996
- return false;
997
- }
998
- $crypto->setKey($symkey);
999
- $crypto->setIV($iv);
1000
- $decoded = $crypto->decrypt($ciphertext);
1001
- } else {
1002
- $decoded = preg_replace('#-.+-|[\r\n]| #', '', $key);
1003
- $decoded = preg_match('#^[a-zA-Z\d/+]*={0,2}$#', $decoded) ? base64_decode($decoded) : false;
1004
- }
1005
-
1006
- if ($decoded !== false) {
1007
- $key = $decoded;
1008
- }
1009
-
1010
- $components = array();
1011
-
1012
- if (ord($this->_string_shift($key)) != CRYPT_RSA_ASN1_SEQUENCE) {
1013
- return false;
1014
- }
1015
- if ($this->_decodeLength($key) != strlen($key)) {
1016
- return false;
1017
- }
1018
-
1019
- $tag = ord($this->_string_shift($key));
1020
- /* intended for keys for which OpenSSL's asn1parse returns the following:
1021
-
1022
- 0:d=0 hl=4 l= 631 cons: SEQUENCE
1023
- 4:d=1 hl=2 l= 1 prim: INTEGER :00
1024
- 7:d=1 hl=2 l= 13 cons: SEQUENCE
1025
- 9:d=2 hl=2 l= 9 prim: OBJECT :rsaEncryption
1026
- 20:d=2 hl=2 l= 0 prim: NULL
1027
- 22:d=1 hl=4 l= 609 prim: OCTET STRING */
1028
-
1029
- if ($tag == CRYPT_RSA_ASN1_INTEGER && substr($key, 0, 3) == "\x01\x00\x30") {
1030
- $this->_string_shift($key, 3);
1031
- $tag = CRYPT_RSA_ASN1_SEQUENCE;
1032
- }
1033
-
1034
- if ($tag == CRYPT_RSA_ASN1_SEQUENCE) {
1035
- /* intended for keys for which OpenSSL's asn1parse returns the following:
1036
-
1037
- 0:d=0 hl=4 l= 290 cons: SEQUENCE
1038
- 4:d=1 hl=2 l= 13 cons: SEQUENCE
1039
- 6:d=2 hl=2 l= 9 prim: OBJECT :rsaEncryption
1040
- 17:d=2 hl=2 l= 0 prim: NULL
1041
- 19:d=1 hl=4 l= 271 prim: BIT STRING */
1042
- $this->_string_shift($key, $this->_decodeLength($key));
1043
- $tag = ord($this->_string_shift($key)); // skip over the BIT STRING / OCTET STRING tag
1044
- $this->_decodeLength($key); // skip over the BIT STRING / OCTET STRING length
1045
- // "The initial octet shall encode, as an unsigned binary integer wtih bit 1 as the least significant bit, the number of
1046
- // unused bits in the final subsequent octet. The number shall be in the range zero to seven."
1047
- // -- http://www.itu.int/ITU-T/studygroups/com17/languages/X.690-0207.pdf (section 8.6.2.2)
1048
- if ($tag == CRYPT_RSA_ASN1_BITSTRING) {
1049
- $this->_string_shift($key);
1050
- }
1051
- if (ord($this->_string_shift($key)) != CRYPT_RSA_ASN1_SEQUENCE) {
1052
- return false;
1053
- }
1054
- if ($this->_decodeLength($key) != strlen($key)) {
1055
- return false;
1056
- }
1057
- $tag = ord($this->_string_shift($key));
1058
- }
1059
- if ($tag != CRYPT_RSA_ASN1_INTEGER) {
1060
- return false;
1061
- }
1062
-
1063
- $length = $this->_decodeLength($key);
1064
- $temp = $this->_string_shift($key, $length);
1065
- if (strlen($temp) != 1 || ord($temp) > 2) {
1066
- $components['modulus'] = new Math_BigInteger($temp, 256);
1067
- $this->_string_shift($key); // skip over CRYPT_RSA_ASN1_INTEGER
1068
- $length = $this->_decodeLength($key);
1069
- $components[$type == CRYPT_RSA_PUBLIC_FORMAT_PKCS1 ? 'publicExponent' : 'privateExponent'] = new Math_BigInteger($this->_string_shift($key, $length), 256);
1070
-
1071
- return $components;
1072
- }
1073
- if (ord($this->_string_shift($key)) != CRYPT_RSA_ASN1_INTEGER) {
1074
- return false;
1075
- }
1076
- $length = $this->_decodeLength($key);
1077
- $components['modulus'] = new Math_BigInteger($this->_string_shift($key, $length), 256);
1078
- $this->_string_shift($key);
1079
- $length = $this->_decodeLength($key);
1080
- $components['publicExponent'] = new Math_BigInteger($this->_string_shift($key, $length), 256);
1081
- $this->_string_shift($key);
1082
- $length = $this->_decodeLength($key);
1083
- $components['privateExponent'] = new Math_BigInteger($this->_string_shift($key, $length), 256);
1084
- $this->_string_shift($key);
1085
- $length = $this->_decodeLength($key);
1086
- $components['primes'] = array(1 => new Math_BigInteger($this->_string_shift($key, $length), 256));
1087
- $this->_string_shift($key);
1088
- $length = $this->_decodeLength($key);
1089
- $components['primes'][] = new Math_BigInteger($this->_string_shift($key, $length), 256);
1090
- $this->_string_shift($key);
1091
- $length = $this->_decodeLength($key);
1092
- $components['exponents'] = array(1 => new Math_BigInteger($this->_string_shift($key, $length), 256));
1093
- $this->_string_shift($key);
1094
- $length = $this->_decodeLength($key);
1095
- $components['exponents'][] = new Math_BigInteger($this->_string_shift($key, $length), 256);
1096
- $this->_string_shift($key);
1097
- $length = $this->_decodeLength($key);
1098
- $components['coefficients'] = array(2 => new Math_BigInteger($this->_string_shift($key, $length), 256));
1099
-
1100
- if (!empty($key)) {
1101
- if (ord($this->_string_shift($key)) != CRYPT_RSA_ASN1_SEQUENCE) {
1102
- return false;
1103
- }
1104
- $this->_decodeLength($key);
1105
- while (!empty($key)) {
1106
- if (ord($this->_string_shift($key)) != CRYPT_RSA_ASN1_SEQUENCE) {
1107
- return false;
1108
- }
1109
- $this->_decodeLength($key);
1110
- $key = substr($key, 1);
1111
- $length = $this->_decodeLength($key);
1112
- $components['primes'][] = new Math_BigInteger($this->_string_shift($key, $length), 256);
1113
- $this->_string_shift($key);
1114
- $length = $this->_decodeLength($key);
1115
- $components['exponents'][] = new Math_BigInteger($this->_string_shift($key, $length), 256);
1116
- $this->_string_shift($key);
1117
- $length = $this->_decodeLength($key);
1118
- $components['coefficients'][] = new Math_BigInteger($this->_string_shift($key, $length), 256);
1119
- }
1120
- }
1121
-
1122
- return $components;
1123
- case CRYPT_RSA_PUBLIC_FORMAT_OPENSSH:
1124
- $key = base64_decode(preg_replace('#^ssh-rsa | .+$#', '', $key));
1125
- if ($key === false) {
1126
- return false;
1127
- }
1128
-
1129
- $cleanup = substr($key, 0, 11) == "\0\0\0\7ssh-rsa";
1130
-
1131
- if (strlen($key) <= 4) {
1132
- return false;
1133
- }
1134
- extract(unpack('Nlength', $this->_string_shift($key, 4)));
1135
- $publicExponent = new Math_BigInteger($this->_string_shift($key, $length), -256);
1136
- if (strlen($key) <= 4) {
1137
- return false;
1138
- }
1139
- extract(unpack('Nlength', $this->_string_shift($key, 4)));
1140
- $modulus = new Math_BigInteger($this->_string_shift($key, $length), -256);
1141
-
1142
- if ($cleanup && strlen($key)) {
1143
- if (strlen($key) <= 4) {
1144
- return false;
1145
- }
1146
- extract(unpack('Nlength', $this->_string_shift($key, 4)));
1147
- $realModulus = new Math_BigInteger($this->_string_shift($key, $length), -256);
1148
- return strlen($key) ? false : array(
1149
- 'modulus' => $realModulus,
1150
- 'publicExponent' => $modulus
1151
- );
1152
- } else {
1153
- return strlen($key) ? false : array(
1154
- 'modulus' => $modulus,
1155
- 'publicExponent' => $publicExponent
1156
- );
1157
- }
1158
- // http://www.w3.org/TR/xmldsig-core/#sec-RSAKeyValue
1159
- // http://en.wikipedia.org/wiki/XML_Signature
1160
- case CRYPT_RSA_PRIVATE_FORMAT_XML:
1161
- case CRYPT_RSA_PUBLIC_FORMAT_XML:
1162
- $this->components = array();
1163
-
1164
- $xml = xml_parser_create('UTF-8');
1165
- xml_set_object($xml, $this);
1166
- xml_set_element_handler($xml, '_start_element_handler', '_stop_element_handler');
1167
- xml_set_character_data_handler($xml, '_data_handler');
1168
- // add <xml></xml> to account for "dangling" tags like <BitStrength>...</BitStrength> that are sometimes added
1169
- if (!xml_parse($xml, '<xml>' . $key . '</xml>')) {
1170
- return false;
1171
- }
1172
-
1173
- return isset($this->components['modulus']) && isset($this->components['publicExponent']) ? $this->components : false;
1174
- // from PuTTY's SSHPUBK.C
1175
- case CRYPT_RSA_PRIVATE_FORMAT_PUTTY:
1176
- $components = array();
1177
- $key = preg_split('#\r\n|\r|\n#', $key);
1178
- $type = trim(preg_replace('#PuTTY-User-Key-File-2: (.+)#', '$1', $key[0]));
1179
- if ($type != 'ssh-rsa') {
1180
- return false;
1181
- }
1182
- $encryption = trim(preg_replace('#Encryption: (.+)#', '$1', $key[1]));
1183
-
1184
- $publicLength = trim(preg_replace('#Public-Lines: (\d+)#', '$1', $key[3]));
1185
- $public = base64_decode(implode('', array_map('trim', array_slice($key, 4, $publicLength))));
1186
- $public = substr($public, 11);
1187
- extract(unpack('Nlength', $this->_string_shift($public, 4)));
1188
- $components['publicExponent'] = new Math_BigInteger($this->_string_shift($public, $length), -256);
1189
- extract(unpack('Nlength', $this->_string_shift($public, 4)));
1190
- $components['modulus'] = new Math_BigInteger($this->_string_shift($public, $length), -256);
1191
-
1192
- $privateLength = trim(preg_replace('#Private-Lines: (\d+)#', '$1', $key[$publicLength + 4]));
1193
- $private = base64_decode(implode('', array_map('trim', array_slice($key, $publicLength + 5, $privateLength))));
1194
-
1195
- switch ($encryption) {
1196
- case 'aes256-cbc':
1197
- if (!class_exists('Crypt_AES')) {
1198
- require_once('Crypt/AES.php');
1199
- }
1200
- $symkey = '';
1201
- $sequence = 0;
1202
- while (strlen($symkey) < 32) {
1203
- $temp = pack('Na*', $sequence++, $this->password);
1204
- $symkey.= pack('H*', sha1($temp));
1205
- }
1206
- $symkey = substr($symkey, 0, 32);
1207
- $crypto = new Crypt_AES();
1208
- }
1209
-
1210
- if ($encryption != 'none') {
1211
- $crypto->setKey($symkey);
1212
- $crypto->disablePadding();
1213
- $private = $crypto->decrypt($private);
1214
- if ($private === false) {
1215
- return false;
1216
- }
1217
- }
1218
-
1219
- extract(unpack('Nlength', $this->_string_shift($private, 4)));
1220
- if (strlen($private) < $length) {
1221
- return false;
1222
- }
1223
- $components['privateExponent'] = new Math_BigInteger($this->_string_shift($private, $length), -256);
1224
- extract(unpack('Nlength', $this->_string_shift($private, 4)));
1225
- if (strlen($private) < $length) {
1226
- return false;
1227
- }
1228
- $components['primes'] = array(1 => new Math_BigInteger($this->_string_shift($private, $length), -256));
1229
- extract(unpack('Nlength', $this->_string_shift($private, 4)));
1230
- if (strlen($private) < $length) {
1231
- return false;
1232
- }
1233
- $components['primes'][] = new Math_BigInteger($this->_string_shift($private, $length), -256);
1234
-
1235
- $temp = $components['primes'][1]->subtract($this->one);
1236
- $components['exponents'] = array(1 => $components['publicExponent']->modInverse($temp));
1237
- $temp = $components['primes'][2]->subtract($this->one);
1238
- $components['exponents'][] = $components['publicExponent']->modInverse($temp);
1239
-
1240
- extract(unpack('Nlength', $this->_string_shift($private, 4)));
1241
- if (strlen($private) < $length) {
1242
- return false;
1243
- }
1244
- $components['coefficients'] = array(2 => new Math_BigInteger($this->_string_shift($private, $length), -256));
1245
-
1246
- return $components;
1247
- }
1248
- }
1249
-
1250
- /**
1251
- * Returns the key size
1252
- *
1253
- * More specifically, this returns the size of the modulo in bits.
1254
- *
1255
- * @access public
1256
- * @return Integer
1257
- */
1258
- function getSize()
1259
- {
1260
- return !isset($this->modulus) ? 0 : strlen($this->modulus->toBits());
1261
- }
1262
-
1263
- /**
1264
- * Start Element Handler
1265
- *
1266
- * Called by xml_set_element_handler()
1267
- *
1268
- * @access private
1269
- * @param Resource $parser
1270
- * @param String $name
1271
- * @param Array $attribs
1272
- */
1273
- function _start_element_handler($parser, $name, $attribs)
1274
- {
1275
- //$name = strtoupper($name);
1276
- switch ($name) {
1277
- case 'MODULUS':
1278
- $this->current = &$this->components['modulus'];
1279
- break;
1280
- case 'EXPONENT':
1281
- $this->current = &$this->components['publicExponent'];
1282
- break;
1283
- case 'P':
1284
- $this->current = &$this->components['primes'][1];
1285
- break;
1286
- case 'Q':
1287
- $this->current = &$this->components['primes'][2];
1288
- break;
1289
- case 'DP':
1290
- $this->current = &$this->components['exponents'][1];
1291
- break;
1292
- case 'DQ':
1293
- $this->current = &$this->components['exponents'][2];
1294
- break;
1295
- case 'INVERSEQ':
1296
- $this->current = &$this->components['coefficients'][2];
1297
- break;
1298
- case 'D':
1299
- $this->current = &$this->components['privateExponent'];
1300
- break;
1301
- default:
1302
- unset($this->current);
1303
- }
1304
- $this->current = '';
1305
- }
1306
-
1307
- /**
1308
- * Stop Element Handler
1309
- *
1310
- * Called by xml_set_element_handler()
1311
- *
1312
- * @access private
1313
- * @param Resource $parser
1314
- * @param String $name
1315
- */
1316
- function _stop_element_handler($parser, $name)
1317
- {
1318
- //$name = strtoupper($name);
1319
- if ($name == 'RSAKEYVALUE') {
1320
- return;
1321
- }
1322
- $this->current = new Math_BigInteger(base64_decode($this->current), 256);
1323
- }
1324
-
1325
- /**
1326
- * Data Handler
1327
- *
1328
- * Called by xml_set_character_data_handler()
1329
- *
1330
- * @access private
1331
- * @param Resource $parser
1332
- * @param String $data
1333
- */
1334
- function _data_handler($parser, $data)
1335
- {
1336
- if (!isset($this->current) || is_object($this->current)) {
1337
- return;
1338
- }
1339
- $this->current.= trim($data);
1340
- }
1341
-
1342
- /**
1343
- * Loads a public or private key
1344
- *
1345
- * Returns true on success and false on failure (ie. an incorrect password was provided or the key was malformed)
1346
- *
1347
- * @access public
1348
- * @param String $key
1349
- * @param Integer $type optional
1350
- */
1351
- function loadKey($key, $type = false)
1352
- {
1353
- if ($type === false) {
1354
- $types = array(
1355
- CRYPT_RSA_PUBLIC_FORMAT_RAW,
1356
- CRYPT_RSA_PRIVATE_FORMAT_PKCS1,
1357
- CRYPT_RSA_PRIVATE_FORMAT_XML,
1358
- CRYPT_RSA_PRIVATE_FORMAT_PUTTY,
1359
- CRYPT_RSA_PUBLIC_FORMAT_OPENSSH
1360
- );
1361
- foreach ($types as $type) {
1362
- $components = $this->_parseKey($key, $type);
1363
- if ($components !== false) {
1364
- break;
1365
- }
1366
- }
1367
-
1368
- } else {
1369
- $components = $this->_parseKey($key, $type);
1370
- }
1371
-
1372
- if ($components === false) {
1373
- return false;
1374
- }
1375
-
1376
- $this->modulus = $components['modulus'];
1377
- $this->k = strlen($this->modulus->toBytes());
1378
- $this->exponent = isset($components['privateExponent']) ? $components['privateExponent'] : $components['publicExponent'];
1379
- if (isset($components['primes'])) {
1380
- $this->primes = $components['primes'];
1381
- $this->exponents = $components['exponents'];
1382
- $this->coefficients = $components['coefficients'];
1383
- $this->publicExponent = $components['publicExponent'];
1384
- } else {
1385
- $this->primes = array();
1386
- $this->exponents = array();
1387
- $this->coefficients = array();
1388
- $this->publicExponent = false;
1389
- }
1390
-
1391
- return true;
1392
- }
1393
-
1394
- /**
1395
- * Sets the password
1396
- *
1397
- * Private keys can be encrypted with a password. To unset the password, pass in the empty string or false.
1398
- * Or rather, pass in $password such that empty($password) && !is_string($password) is true.
1399
- *
1400
- * @see createKey()
1401
- * @see loadKey()
1402
- * @access public
1403
- * @param String $password
1404
- */
1405
- function setPassword($password = false)
1406
- {
1407
- $this->password = $password;
1408
- }
1409
-
1410
- /**
1411
- * Defines the public key
1412
- *
1413
- * Some private key formats define the public exponent and some don't. Those that don't define it are problematic when
1414
- * used in certain contexts. For example, in SSH-2, RSA authentication works by sending the public key along with a
1415
- * message signed by the private key to the server. The SSH-2 server looks the public key up in an index of public keys
1416
- * and if it's present then proceeds to verify the signature. Problem is, if your private key doesn't include the public
1417
- * exponent this won't work unless you manually add the public exponent.
1418
- *
1419
- * Do note that when a new key is loaded the index will be cleared.
1420
- *
1421
- * Returns true on success, false on failure
1422
- *
1423
- * @see getPublicKey()
1424
- * @access public
1425
- * @param String $key optional
1426
- * @param Integer $type optional
1427
- * @return Boolean
1428
- */
1429
- function setPublicKey($key = false, $type = false)
1430
- {
1431
- if ($key === false && !empty($this->modulus)) {
1432
- $this->publicExponent = $this->exponent;
1433
- return true;
1434
- }
1435
-
1436
- if ($type === false) {
1437
- $types = array(
1438
- CRYPT_RSA_PUBLIC_FORMAT_RAW,
1439
- CRYPT_RSA_PUBLIC_FORMAT_PKCS1,
1440
- CRYPT_RSA_PUBLIC_FORMAT_XML,
1441
- CRYPT_RSA_PUBLIC_FORMAT_OPENSSH
1442
- );
1443
- foreach ($types as $type) {
1444
- $components = $this->_parseKey($key, $type);
1445
- if ($components !== false) {
1446
- break;
1447
- }
1448
- }
1449
- } else {
1450
- $components = $this->_parseKey($key, $type);
1451
- }
1452
-
1453
- if ($components === false) {
1454
- return false;
1455
- }
1456
-
1457
- if (empty($this->modulus) || !$this->modulus->equals($components['modulus'])) {
1458
- $this->modulus = $components['modulus'];
1459
- $this->exponent = $this->publicExponent = $components['publicExponent'];
1460
- return true;
1461
- }
1462
-
1463
- $this->publicExponent = $components['publicExponent'];
1464
-
1465
- return true;
1466
- }
1467
-
1468
- /**
1469
- * Returns the public key
1470
- *
1471
- * The public key is only returned under two circumstances - if the private key had the public key embedded within it
1472
- * or if the public key was set via setPublicKey(). If the currently loaded key is supposed to be the public key this
1473
- * function won't return it since this library, for the most part, doesn't distinguish between public and private keys.
1474
- *
1475
- * @see getPublicKey()
1476
- * @access public
1477
- * @param String $key
1478
- * @param Integer $type optional
1479
- */
1480
- function getPublicKey($type = CRYPT_RSA_PUBLIC_FORMAT_PKCS1)
1481
- {
1482
- if (empty($this->modulus) || empty($this->publicExponent)) {
1483
- return false;
1484
- }
1485
-
1486
- $oldFormat = $this->publicKeyFormat;
1487
- $this->publicKeyFormat = $type;
1488
- $temp = $this->_convertPublicKey($this->modulus, $this->publicExponent);
1489
- $this->publicKeyFormat = $oldFormat;
1490
- return $temp;
1491
- }
1492
-
1493
- /**
1494
- * Returns the private key
1495
- *
1496
- * The private key is only returned if the currently loaded key contains the constituent prime numbers.
1497
- *
1498
- * @see getPublicKey()
1499
- * @access public
1500
- * @param String $key
1501
- * @param Integer $type optional
1502
- */
1503
- function getPrivateKey($type = CRYPT_RSA_PUBLIC_FORMAT_PKCS1)
1504
- {
1505
- if (empty($this->primes)) {
1506
- return false;
1507
- }
1508
-
1509
- $oldFormat = $this->privateKeyFormat;
1510
- $this->privateKeyFormat = $type;
1511
- $temp = $this->_convertPrivateKey($this->modulus, $this->publicExponent, $this->exponent, $this->primes, $this->exponents, $this->coefficients);
1512
- $this->privateKeyFormat = $oldFormat;
1513
- return $temp;
1514
- }
1515
-
1516
- /**
1517
- * Returns a minimalistic private key
1518
- *
1519
- * Returns the private key without the prime number constituants. Structurally identical to a public key that
1520
- * hasn't been set as the public key
1521
- *
1522
- * @see getPrivateKey()
1523
- * @access private
1524
- * @param String $key
1525
- * @param Integer $type optional
1526
- */
1527
- function _getPrivatePublicKey($mode = CRYPT_RSA_PUBLIC_FORMAT_PKCS1)
1528
- {
1529
- if (empty($this->modulus) || empty($this->exponent)) {
1530
- return false;
1531
- }
1532
-
1533
- $oldFormat = $this->publicKeyFormat;
1534
- $this->publicKeyFormat = $mode;
1535
- $temp = $this->_convertPublicKey($this->modulus, $this->exponent);
1536
- $this->publicKeyFormat = $oldFormat;
1537
- return $temp;
1538
- }
1539
-
1540
- /**
1541
- * __toString() magic method
1542
- *
1543
- * @access public
1544
- */
1545
- function __toString()
1546
- {
1547
- $key = $this->getPrivateKey($this->privateKeyFormat);
1548
- if ($key !== false) {
1549
- return $key;
1550
- }
1551
- $key = $this->_getPrivatePublicKey($this->publicKeyFormat);
1552
- return $key !== false ? $key : '';
1553
- }
1554
-
1555
- /**
1556
- * Generates the smallest and largest numbers requiring $bits bits
1557
- *
1558
- * @access private
1559
- * @param Integer $bits
1560
- * @return Array
1561
- */
1562
- function _generateMinMax($bits)
1563
- {
1564
- $bytes = $bits >> 3;
1565
- $min = str_repeat(chr(0), $bytes);
1566
- $max = str_repeat(chr(0xFF), $bytes);
1567
- $msb = $bits & 7;
1568
- if ($msb) {
1569
- $min = chr(1 << ($msb - 1)) . $min;
1570
- $max = chr((1 << $msb) - 1) . $max;
1571
- } else {
1572
- $min[0] = chr(0x80);
1573
- }
1574
-
1575
- return array(
1576
- 'min' => new Math_BigInteger($min, 256),
1577
- 'max' => new Math_BigInteger($max, 256)
1578
- );
1579
- }
1580
-
1581
- /**
1582
- * DER-decode the length
1583
- *
1584
- * DER supports lengths up to (2**8)**127, however, we'll only support lengths up to (2**8)**4. See
1585
- * {@link http://itu.int/ITU-T/studygroups/com17/languages/X.690-0207.pdf#p=13 X.690 � 8.1.3} for more information.
1586
- *
1587
- * @access private
1588
- * @param String $string
1589
- * @return Integer
1590
- */
1591
- function _decodeLength(&$string)
1592
- {
1593
- $length = ord($this->_string_shift($string));
1594
- if ( $length & 0x80 ) { // definite length, long form
1595
- $length&= 0x7F;
1596
- $temp = $this->_string_shift($string, $length);
1597
- list(, $length) = unpack('N', substr(str_pad($temp, 4, chr(0), STR_PAD_LEFT), -4));
1598
- }
1599
- return $length;
1600
- }
1601
-
1602
- /**
1603
- * DER-encode the length
1604
- *
1605
- * DER supports lengths up to (2**8)**127, however, we'll only support lengths up to (2**8)**4. See
1606
- * {@link http://itu.int/ITU-T/studygroups/com17/languages/X.690-0207.pdf#p=13 X.690 � 8.1.3} for more information.
1607
- *
1608
- * @access private
1609
- * @param Integer $length
1610
- * @return String
1611
- */
1612
- function _encodeLength($length)
1613
- {
1614
- if ($length <= 0x7F) {
1615
- return chr($length);
1616
- }
1617
-
1618
- $temp = ltrim(pack('N', $length), chr(0));
1619
- return pack('Ca*', 0x80 | strlen($temp), $temp);
1620
- }
1621
-
1622
- /**
1623
- * String Shift
1624
- *
1625
- * Inspired by array_shift
1626
- *
1627
- * @param String $string
1628
- * @param optional Integer $index
1629
- * @return String
1630
- * @access private
1631
- */
1632
- function _string_shift(&$string, $index = 1)
1633
- {
1634
- $substr = substr($string, 0, $index);
1635
- $string = substr($string, $index);
1636
- return $substr;
1637
- }
1638
-
1639
- /**
1640
- * Determines the private key format
1641
- *
1642
- * @see createKey()
1643
- * @access public
1644
- * @param Integer $format
1645
- */
1646
- function setPrivateKeyFormat($format)
1647
- {
1648
- $this->privateKeyFormat = $format;
1649
- }
1650
-
1651
- /**
1652
- * Determines the public key format
1653
- *
1654
- * @see createKey()
1655
- * @access public
1656
- * @param Integer $format
1657
- */
1658
- function setPublicKeyFormat($format)
1659
- {
1660
- $this->publicKeyFormat = $format;
1661
- }
1662
-
1663
- /**
1664
- * Determines which hashing function should be used
1665
- *
1666
- * Used with signature production / verification and (if the encryption mode is CRYPT_RSA_ENCRYPTION_OAEP) encryption and
1667
- * decryption. If $hash isn't supported, sha1 is used.
1668
- *
1669
- * @access public
1670
- * @param String $hash
1671
- */
1672
- function setHash($hash)
1673
- {
1674
- // Crypt_Hash supports algorithms that PKCS#1 doesn't support. md5-96 and sha1-96, for example.
1675
- switch ($hash) {
1676
- case 'md2':
1677
- case 'md5':
1678
- case 'sha1':
1679
- case 'sha256':
1680
- case 'sha384':
1681
- case 'sha512':
1682
- $this->hash = new Crypt_Hash($hash);
1683
- $this->hashName = $hash;
1684
- break;
1685
- default:
1686
- $this->hash = new Crypt_Hash('sha1');
1687
- $this->hashName = 'sha1';
1688
- }
1689
- $this->hLen = $this->hash->getLength();
1690
- }
1691
-
1692
- /**
1693
- * Determines which hashing function should be used for the mask generation function
1694
- *
1695
- * The mask generation function is used by CRYPT_RSA_ENCRYPTION_OAEP and CRYPT_RSA_SIGNATURE_PSS and although it's
1696
- * best if Hash and MGFHash are set to the same thing this is not a requirement.
1697
- *
1698
- * @access public
1699
- * @param String $hash
1700
- */
1701
- function setMGFHash($hash)
1702
- {
1703
- // Crypt_Hash supports algorithms that PKCS#1 doesn't support. md5-96 and sha1-96, for example.
1704
- switch ($hash) {
1705
- case 'md2':
1706
- case 'md5':
1707
- case 'sha1':
1708
- case 'sha256':
1709
- case 'sha384':
1710
- case 'sha512':
1711
- $this->mgfHash = new Crypt_Hash($hash);
1712
- break;
1713
- default:
1714
- $this->mgfHash = new Crypt_Hash('sha1');
1715
- }
1716
- $this->mgfHLen = $this->mgfHash->getLength();
1717
- }
1718
-
1719
- /**
1720
- * Determines the salt length
1721
- *
1722
- * To quote from {@link http://tools.ietf.org/html/rfc3447#page-38 RFC3447#page-38}:
1723
- *
1724
- * Typical salt lengths in octets are hLen (the length of the output
1725
- * of the hash function Hash) and 0.
1726
- *
1727
- * @access public
1728
- * @param Integer $format
1729
- */
1730
- function setSaltLength($sLen)
1731
- {
1732
- $this->sLen = $sLen;
1733
- }
1734
-
1735
- /**
1736
- * Integer-to-Octet-String primitive
1737
- *
1738
- * See {@link http://tools.ietf.org/html/rfc3447#section-4.1 RFC3447#section-4.1}.
1739
- *
1740
- * @access private
1741
- * @param Math_BigInteger $x
1742
- * @param Integer $xLen
1743
- * @return String
1744
- */
1745
- function _i2osp($x, $xLen)
1746
- {
1747
- $x = $x->toBytes();
1748
- if (strlen($x) > $xLen) {
1749
- user_error('Integer too large');
1750
- return false;
1751
- }
1752
- return str_pad($x, $xLen, chr(0), STR_PAD_LEFT);
1753
- }
1754
-
1755
- /**
1756
- * Octet-String-to-Integer primitive
1757
- *
1758
- * See {@link http://tools.ietf.org/html/rfc3447#section-4.2 RFC3447#section-4.2}.
1759
- *
1760
- * @access private
1761
- * @param String $x
1762
- * @return Math_BigInteger
1763
- */
1764
- function _os2ip($x)
1765
- {
1766
- return new Math_BigInteger($x, 256);
1767
- }
1768
-
1769
- /**
1770
- * Exponentiate with or without Chinese Remainder Theorem
1771
- *
1772
- * See {@link http://tools.ietf.org/html/rfc3447#section-5.1.1 RFC3447#section-5.1.2}.
1773
- *
1774
- * @access private
1775
- * @param Math_BigInteger $x
1776
- * @return Math_BigInteger
1777
- */
1778
- function _exponentiate($x)
1779
- {
1780
- if (empty($this->primes) || empty($this->coefficients) || empty($this->exponents)) {
1781
- return $x->modPow($this->exponent, $this->modulus);
1782
- }
1783
-
1784
- $num_primes = count($this->primes);
1785
-
1786
- if (defined('CRYPT_RSA_DISABLE_BLINDING')) {
1787
- $m_i = array(
1788
- 1 => $x->modPow($this->exponents[1], $this->primes[1]),
1789
- 2 => $x->modPow($this->exponents[2], $this->primes[2])
1790
- );
1791
- $h = $m_i[1]->subtract($m_i[2]);
1792
- $h = $h->multiply($this->coefficients[2]);
1793
- list(, $h) = $h->divide($this->primes[1]);
1794
- $m = $m_i[2]->add($h->multiply($this->primes[2]));
1795
-
1796
- $r = $this->primes[1];
1797
- for ($i = 3; $i <= $num_primes; $i++) {
1798
- $m_i = $x->modPow($this->exponents[$i], $this->primes[$i]);
1799
-
1800
- $r = $r->multiply($this->primes[$i - 1]);
1801
-
1802
- $h = $m_i->subtract($m);
1803
- $h = $h->multiply($this->coefficients[$i]);
1804
- list(, $h) = $h->divide($this->primes[$i]);
1805
-
1806
- $m = $m->add($r->multiply($h));
1807
- }
1808
- } else {
1809
- $smallest = $this->primes[1];
1810
- for ($i = 2; $i <= $num_primes; $i++) {
1811
- if ($smallest->compare($this->primes[$i]) > 0) {
1812
- $smallest = $this->primes[$i];
1813
- }
1814
- }
1815
-
1816
- $one = new Math_BigInteger(1);
1817
-
1818
- $r = $one->random($one, $smallest->subtract($one));
1819
-
1820
- $m_i = array(
1821
- 1 => $this->_blind($x, $r, 1),
1822
- 2 => $this->_blind($x, $r, 2)
1823
- );
1824
- $h = $m_i[1]->subtract($m_i[2]);
1825
- $h = $h->multiply($this->coefficients[2]);
1826
- list(, $h) = $h->divide($this->primes[1]);
1827
- $m = $m_i[2]->add($h->multiply($this->primes[2]));
1828
-
1829
- $r = $this->primes[1];
1830
- for ($i = 3; $i <= $num_primes; $i++) {
1831
- $m_i = $this->_blind($x, $r, $i);
1832
-
1833
- $r = $r->multiply($this->primes[$i - 1]);
1834
-
1835
- $h = $m_i->subtract($m);
1836
- $h = $h->multiply($this->coefficients[$i]);
1837
- list(, $h) = $h->divide($this->primes[$i]);
1838
-
1839
- $m = $m->add($r->multiply($h));
1840
- }
1841
- }
1842
-
1843
- return $m;
1844
- }
1845
-
1846
- /**
1847
- * Performs RSA Blinding
1848
- *
1849
- * Protects against timing attacks by employing RSA Blinding.
1850
- * Returns $x->modPow($this->exponents[$i], $this->primes[$i])
1851
- *
1852
- * @access private
1853
- * @param Math_BigInteger $x
1854
- * @param Math_BigInteger $r
1855
- * @param Integer $i
1856
- * @return Math_BigInteger
1857
- */
1858
- function _blind($x, $r, $i)
1859
- {
1860
- $x = $x->multiply($r->modPow($this->publicExponent, $this->primes[$i]));
1861
- $x = $x->modPow($this->exponents[$i], $this->primes[$i]);
1862
-
1863
- $r = $r->modInverse($this->primes[$i]);
1864
- $x = $x->multiply($r);
1865
- list(, $x) = $x->divide($this->primes[$i]);
1866
-
1867
- return $x;
1868
- }
1869
-
1870
- /**
1871
- * Performs blinded RSA equality testing
1872
- *
1873
- * Protects against a particular type of timing attack described.
1874
- *
1875
- * See {@link http://codahale.com/a-lesson-in-timing-attacks/ A Lesson In Timing Attacks (or, Don�t use MessageDigest.isEquals)}
1876
- *
1877
- * Thanks for the heads up singpolyma!
1878
- *
1879
- * @access private
1880
- * @param String $x
1881
- * @param String $y
1882
- * @return Boolean
1883
- */
1884
- function _equals($x, $y)
1885
- {
1886
- if (strlen($x) != strlen($y)) {
1887
- return false;
1888
- }
1889
-
1890
- $result = 0;
1891
- for ($i = 0; $i < strlen($x); $i++) {
1892
- $result |= ord($x[$i]) ^ ord($y[$i]);
1893
- }
1894
-
1895
- return $result == 0;
1896
- }
1897
-
1898
- /**
1899
- * RSAEP
1900
- *
1901
- * See {@link http://tools.ietf.org/html/rfc3447#section-5.1.1 RFC3447#section-5.1.1}.
1902
- *
1903
- * @access private
1904
- * @param Math_BigInteger $m
1905
- * @return Math_BigInteger
1906
- */
1907
- function _rsaep($m)
1908
- {
1909
- if ($m->compare($this->zero) < 0 || $m->compare($this->modulus) > 0) {
1910
- user_error('Message representative out of range');
1911
- return false;
1912
- }
1913
- return $this->_exponentiate($m);
1914
- }
1915
-
1916
- /**
1917
- * RSADP
1918
- *
1919
- * See {@link http://tools.ietf.org/html/rfc3447#section-5.1.2 RFC3447#section-5.1.2}.
1920
- *
1921
- * @access private
1922
- * @param Math_BigInteger $c
1923
- * @return Math_BigInteger
1924
- */
1925
- function _rsadp($c)
1926
- {
1927
- if ($c->compare($this->zero) < 0 || $c->compare($this->modulus) > 0) {
1928
- user_error('Ciphertext representative out of range');
1929
- return false;
1930
- }
1931
- return $this->_exponentiate($c);
1932
- }
1933
-
1934
- /**
1935
- * RSASP1
1936
- *
1937
- * See {@link http://tools.ietf.org/html/rfc3447#section-5.2.1 RFC3447#section-5.2.1}.
1938
- *
1939
- * @access private
1940
- * @param Math_BigInteger $m
1941
- * @return Math_BigInteger
1942
- */
1943
- function _rsasp1($m)
1944
- {
1945
- if ($m->compare($this->zero) < 0 || $m->compare($this->modulus) > 0) {
1946
- user_error('Message representative out of range');
1947
- return false;
1948
- }
1949
- return $this->_exponentiate($m);
1950
- }
1951
-
1952
- /**
1953
- * RSAVP1
1954
- *
1955
- * See {@link http://tools.ietf.org/html/rfc3447#section-5.2.2 RFC3447#section-5.2.2}.
1956
- *
1957
- * @access private
1958
- * @param Math_BigInteger $s
1959
- * @return Math_BigInteger
1960
- */
1961
- function _rsavp1($s)
1962
- {
1963
- if ($s->compare($this->zero) < 0 || $s->compare($this->modulus) > 0) {
1964
- user_error('Signature representative out of range');
1965
- return false;
1966
- }
1967
- return $this->_exponentiate($s);
1968
- }
1969
-
1970
- /**
1971
- * MGF1
1972
- *
1973
- * See {@link http://tools.ietf.org/html/rfc3447#appendix-B.2.1 RFC3447#appendix-B.2.1}.
1974
- *
1975
- * @access private
1976
- * @param String $mgfSeed
1977
- * @param Integer $mgfLen
1978
- * @return String
1979
- */
1980
- function _mgf1($mgfSeed, $maskLen)
1981
- {
1982
- // if $maskLen would yield strings larger than 4GB, PKCS#1 suggests a "Mask too long" error be output.
1983
-
1984
- $t = '';
1985
- $count = ceil($maskLen / $this->mgfHLen);
1986
- for ($i = 0; $i < $count; $i++) {
1987
- $c = pack('N', $i);
1988
- $t.= $this->mgfHash->hash($mgfSeed . $c);
1989
- }
1990
-
1991
- return substr($t, 0, $maskLen);
1992
- }
1993
-
1994
- /**
1995
- * RSAES-OAEP-ENCRYPT
1996
- *
1997
- * See {@link http://tools.ietf.org/html/rfc3447#section-7.1.1 RFC3447#section-7.1.1} and
1998
- * {http://en.wikipedia.org/wiki/Optimal_Asymmetric_Encryption_Padding OAES}.
1999
- *
2000
- * @access private
2001
- * @param String $m
2002
- * @param String $l
2003
- * @return String
2004
- */
2005
- function _rsaes_oaep_encrypt($m, $l = '')
2006
- {
2007
- $mLen = strlen($m);
2008
-
2009
- // Length checking
2010
-
2011
- // if $l is larger than two million terrabytes and you're using sha1, PKCS#1 suggests a "Label too long" error
2012
- // be output.
2013
-
2014
- if ($mLen > $this->k - 2 * $this->hLen - 2) {
2015
- user_error('Message too long');
2016
- return false;
2017
- }
2018
-
2019
- // EME-OAEP encoding
2020
-
2021
- $lHash = $this->hash->hash($l);
2022
- $ps = str_repeat(chr(0), $this->k - $mLen - 2 * $this->hLen - 2);
2023
- $db = $lHash . $ps . chr(1) . $m;
2024
- $seed = crypt_random_string($this->hLen);
2025
- $dbMask = $this->_mgf1($seed, $this->k - $this->hLen - 1);
2026
- $maskedDB = $db ^ $dbMask;
2027
- $seedMask = $this->_mgf1($maskedDB, $this->hLen);
2028
- $maskedSeed = $seed ^ $seedMask;
2029
- $em = chr(0) . $maskedSeed . $maskedDB;
2030
-
2031
- // RSA encryption
2032
-
2033
- $m = $this->_os2ip($em);
2034
- $c = $this->_rsaep($m);
2035
- $c = $this->_i2osp($c, $this->k);
2036
-
2037
- // Output the ciphertext C
2038
-
2039
- return $c;
2040
- }
2041
-
2042
- /**
2043
- * RSAES-OAEP-DECRYPT
2044
- *
2045
- * See {@link http://tools.ietf.org/html/rfc3447#section-7.1.2 RFC3447#section-7.1.2}. The fact that the error
2046
- * messages aren't distinguishable from one another hinders debugging, but, to quote from RFC3447#section-7.1.2:
2047
- *
2048
- * Note. Care must be taken to ensure that an opponent cannot
2049
- * distinguish the different error conditions in Step 3.g, whether by
2050
- * error message or timing, or, more generally, learn partial
2051
- * information about the encoded message EM. Otherwise an opponent may
2052
- * be able to obtain useful information about the decryption of the
2053
- * ciphertext C, leading to a chosen-ciphertext attack such as the one
2054
- * observed by Manger [36].
2055
- *
2056
- * As for $l... to quote from {@link http://tools.ietf.org/html/rfc3447#page-17 RFC3447#page-17}:
2057
- *
2058
- * Both the encryption and the decryption operations of RSAES-OAEP take
2059
- * the value of a label L as input. In this version of PKCS #1, L is
2060
- * the empty string; other uses of the label are outside the scope of
2061
- * this document.
2062
- *
2063
- * @access private
2064
- * @param String $c
2065
- * @param String $l
2066
- * @return String
2067
- */
2068
- function _rsaes_oaep_decrypt($c, $l = '')
2069
- {
2070
- // Length checking
2071
-
2072
- // if $l is larger than two million terrabytes and you're using sha1, PKCS#1 suggests a "Label too long" error
2073
- // be output.
2074
-
2075
- if (strlen($c) != $this->k || $this->k < 2 * $this->hLen + 2) {
2076
- user_error('Decryption error');
2077
- return false;
2078
- }
2079
-
2080
- // RSA decryption
2081
-
2082
- $c = $this->_os2ip($c);
2083
- $m = $this->_rsadp($c);
2084
- if ($m === false) {
2085
- user_error('Decryption error');
2086
- return false;
2087
- }
2088
- $em = $this->_i2osp($m, $this->k);
2089
-
2090
- // EME-OAEP decoding
2091
-
2092
- $lHash = $this->hash->hash($l);
2093
- $y = ord($em[0]);
2094
- $maskedSeed = substr($em, 1, $this->hLen);
2095
- $maskedDB = substr($em, $this->hLen + 1);
2096
- $seedMask = $this->_mgf1($maskedDB, $this->hLen);
2097
- $seed = $maskedSeed ^ $seedMask;
2098
- $dbMask = $this->_mgf1($seed, $this->k - $this->hLen - 1);
2099
- $db = $maskedDB ^ $dbMask;
2100
- $lHash2 = substr($db, 0, $this->hLen);
2101
- $m = substr($db, $this->hLen);
2102
- if ($lHash != $lHash2) {
2103
- user_error('Decryption error');
2104
- return false;
2105
- }
2106
- $m = ltrim($m, chr(0));
2107
- if (ord($m[0]) != 1) {
2108
- user_error('Decryption error');
2109
- return false;
2110
- }
2111
-
2112
- // Output the message M
2113
-
2114
- return substr($m, 1);
2115
- }
2116
-
2117
- /**
2118
- * RSAES-PKCS1-V1_5-ENCRYPT
2119
- *
2120
- * See {@link http://tools.ietf.org/html/rfc3447#section-7.2.1 RFC3447#section-7.2.1}.
2121
- *
2122
- * @access private
2123
- * @param String $m
2124
- * @return String
2125
- */
2126
- function _rsaes_pkcs1_v1_5_encrypt($m)
2127
- {
2128
- $mLen = strlen($m);
2129
-
2130
- // Length checking
2131
-
2132
- if ($mLen > $this->k - 11) {
2133
- user_error('Message too long');
2134
- return false;
2135
- }
2136
-
2137
- // EME-PKCS1-v1_5 encoding
2138
- $psLen = $this->k - $mLen - 3;
2139
- $ps = '';
2140
- while (strlen($ps) != $psLen) {
2141
- $temp = crypt_random_string($psLen - strlen($ps));
2142
- $temp = str_replace("\x00", '', $temp);
2143
- $ps.= $temp;
2144
- }
2145
- $em = chr(0) . chr(2) . $ps . chr(0) . $m;
2146
-
2147
- // RSA encryption
2148
- $m = $this->_os2ip($em);
2149
- $c = $this->_rsaep($m);
2150
- $c = $this->_i2osp($c, $this->k);
2151
-
2152
- // Output the ciphertext C
2153
-
2154
- return $c;
2155
- }
2156
-
2157
- /**
2158
- * RSAES-PKCS1-V1_5-DECRYPT
2159
- *
2160
- * See {@link http://tools.ietf.org/html/rfc3447#section-7.2.2 RFC3447#section-7.2.2}.
2161
- *
2162
- * For compatability purposes, this function departs slightly from the description given in RFC3447.
2163
- * The reason being that RFC2313#section-8.1 (PKCS#1 v1.5) states that ciphertext's encrypted by the
2164
- * private key should have the second byte set to either 0 or 1 and that ciphertext's encrypted by the
2165
- * public key should have the second byte set to 2. In RFC3447 (PKCS#1 v2.1), the second byte is supposed
2166
- * to be 2 regardless of which key is used. For compatability purposes, we'll just check to make sure the
2167
- * second byte is 2 or less. If it is, we'll accept the decrypted string as valid.
2168
- *
2169
- * As a consequence of this, a private key encrypted ciphertext produced with Crypt_RSA may not decrypt
2170
- * with a strictly PKCS#1 v1.5 compliant RSA implementation. Public key encrypted ciphertext's should but
2171
- * not private key encrypted ciphertext's.
2172
- *
2173
- * @access private
2174
- * @param String $c
2175
- * @return String
2176
- */
2177
- function _rsaes_pkcs1_v1_5_decrypt($c)
2178
- {
2179
- // Length checking
2180
-
2181
- if (strlen($c) != $this->k) { // or if k < 11
2182
- user_error('Decryption error');
2183
- return false;
2184
- }
2185
-
2186
- // RSA decryption
2187
-
2188
- $c = $this->_os2ip($c);
2189
- $m = $this->_rsadp($c);
2190
-
2191
- if ($m === false) {
2192
- user_error('Decryption error');
2193
- return false;
2194
- }
2195
- $em = $this->_i2osp($m, $this->k);
2196
-
2197
- // EME-PKCS1-v1_5 decoding
2198
-
2199
- if (ord($em[0]) != 0 || ord($em[1]) > 2) {
2200
- user_error('Decryption error');
2201
- return false;
2202
- }
2203
-
2204
- $ps = substr($em, 2, strpos($em, chr(0), 2) - 2);
2205
- $m = substr($em, strlen($ps) + 3);
2206
-
2207
- if (strlen($ps) < 8) {
2208
- user_error('Decryption error');
2209
- return false;
2210
- }
2211
-
2212
- // Output M
2213
-
2214
- return $m;
2215
- }
2216
-
2217
- /**
2218
- * EMSA-PSS-ENCODE
2219
- *
2220
- * See {@link http://tools.ietf.org/html/rfc3447#section-9.1.1 RFC3447#section-9.1.1}.
2221
- *
2222
- * @access private
2223
- * @param String $m
2224
- * @param Integer $emBits
2225
- */
2226
- function _emsa_pss_encode($m, $emBits)
2227
- {
2228
- // if $m is larger than two million terrabytes and you're using sha1, PKCS#1 suggests a "Label too long" error
2229
- // be output.
2230
-
2231
- $emLen = ($emBits + 1) >> 3; // ie. ceil($emBits / 8)
2232
- $sLen = $this->sLen == false ? $this->hLen : $this->sLen;
2233
-
2234
- $mHash = $this->hash->hash($m);
2235
- if ($emLen < $this->hLen + $sLen + 2) {
2236
- user_error('Encoding error');
2237
- return false;
2238
- }
2239
-
2240
- $salt = crypt_random_string($sLen);
2241
- $m2 = "\0\0\0\0\0\0\0\0" . $mHash . $salt;
2242
- $h = $this->hash->hash($m2);
2243
- $ps = str_repeat(chr(0), $emLen - $sLen - $this->hLen - 2);
2244
- $db = $ps . chr(1) . $salt;
2245
- $dbMask = $this->_mgf1($h, $emLen - $this->hLen - 1);
2246
- $maskedDB = $db ^ $dbMask;
2247
- $maskedDB[0] = ~chr(0xFF << ($emBits & 7)) & $maskedDB[0];
2248
- $em = $maskedDB . $h . chr(0xBC);
2249
-
2250
- return $em;
2251
- }
2252
-
2253
- /**
2254
- * EMSA-PSS-VERIFY
2255
- *
2256
- * See {@link http://tools.ietf.org/html/rfc3447#section-9.1.2 RFC3447#section-9.1.2}.
2257
- *
2258
- * @access private
2259
- * @param String $m
2260
- * @param String $em
2261
- * @param Integer $emBits
2262
- * @return String
2263
- */
2264
- function _emsa_pss_verify($m, $em, $emBits)
2265
- {
2266
- // if $m is larger than two million terrabytes and you're using sha1, PKCS#1 suggests a "Label too long" error
2267
- // be output.
2268
-
2269
- $emLen = ($emBits + 1) >> 3; // ie. ceil($emBits / 8);
2270
- $sLen = $this->sLen == false ? $this->hLen : $this->sLen;
2271
-
2272
- $mHash = $this->hash->hash($m);
2273
- if ($emLen < $this->hLen + $sLen + 2) {
2274
- return false;
2275
- }
2276
-
2277
- if ($em[strlen($em) - 1] != chr(0xBC)) {
2278
- return false;
2279
- }
2280
-
2281
- $maskedDB = substr($em, 0, -$this->hLen - 1);
2282
- $h = substr($em, -$this->hLen - 1, $this->hLen);
2283
- $temp = chr(0xFF << ($emBits & 7));
2284
- if ((~$maskedDB[0] & $temp) != $temp) {
2285
- return false;
2286
- }
2287
- $dbMask = $this->_mgf1($h, $emLen - $this->hLen - 1);
2288
- $db = $maskedDB ^ $dbMask;
2289
- $db[0] = ~chr(0xFF << ($emBits & 7)) & $db[0];
2290
- $temp = $emLen - $this->hLen - $sLen - 2;
2291
- if (substr($db, 0, $temp) != str_repeat(chr(0), $temp) || ord($db[$temp]) != 1) {
2292
- return false;
2293
- }
2294
- $salt = substr($db, $temp + 1); // should be $sLen long
2295
- $m2 = "\0\0\0\0\0\0\0\0" . $mHash . $salt;
2296
- $h2 = $this->hash->hash($m2);
2297
- return $this->_equals($h, $h2);
2298
- }
2299
-
2300
- /**
2301
- * RSASSA-PSS-SIGN
2302
- *
2303
- * See {@link http://tools.ietf.org/html/rfc3447#section-8.1.1 RFC3447#section-8.1.1}.
2304
- *
2305
- * @access private
2306
- * @param String $m
2307
- * @return String
2308
- */
2309
- function _rsassa_pss_sign($m)
2310
- {
2311
- // EMSA-PSS encoding
2312
-
2313
- $em = $this->_emsa_pss_encode($m, 8 * $this->k - 1);
2314
-
2315
- // RSA signature
2316
-
2317
- $m = $this->_os2ip($em);
2318
- $s = $this->_rsasp1($m);
2319
- $s = $this->_i2osp($s, $this->k);
2320
-
2321
- // Output the signature S
2322
-
2323
- return $s;
2324
- }
2325
-
2326
- /**
2327
- * RSASSA-PSS-VERIFY
2328
- *
2329
- * See {@link http://tools.ietf.org/html/rfc3447#section-8.1.2 RFC3447#section-8.1.2}.
2330
- *
2331
- * @access private
2332
- * @param String $m
2333
- * @param String $s
2334
- * @return String
2335
- */
2336
- function _rsassa_pss_verify($m, $s)
2337
- {
2338
- // Length checking
2339
-
2340
- if (strlen($s) != $this->k) {
2341
- user_error('Invalid signature');
2342
- return false;
2343
- }
2344
-
2345
- // RSA verification
2346
-
2347
- $modBits = 8 * $this->k;
2348
-
2349
- $s2 = $this->_os2ip($s);
2350
- $m2 = $this->_rsavp1($s2);
2351
- if ($m2 === false) {
2352
- user_error('Invalid signature');
2353
- return false;
2354
- }
2355
- $em = $this->_i2osp($m2, $modBits >> 3);
2356
- if ($em === false) {
2357
- user_error('Invalid signature');
2358
- return false;
2359
- }
2360
-
2361
- // EMSA-PSS verification
2362
-
2363
- return $this->_emsa_pss_verify($m, $em, $modBits - 1);
2364
- }
2365
-
2366
- /**
2367
- * EMSA-PKCS1-V1_5-ENCODE
2368
- *
2369
- * See {@link http://tools.ietf.org/html/rfc3447#section-9.2 RFC3447#section-9.2}.
2370
- *
2371
- * @access private
2372
- * @param String $m
2373
- * @param Integer $emLen
2374
- * @return String
2375
- */
2376
- function _emsa_pkcs1_v1_5_encode($m, $emLen)
2377
- {
2378
- $h = $this->hash->hash($m);
2379
- if ($h === false) {
2380
- return false;
2381
- }
2382
-
2383
- // see http://tools.ietf.org/html/rfc3447#page-43
2384
- switch ($this->hashName) {
2385
- case 'md2':
2386
- $t = pack('H*', '3020300c06082a864886f70d020205000410');
2387
- break;
2388
- case 'md5':
2389
- $t = pack('H*', '3020300c06082a864886f70d020505000410');
2390
- break;
2391
- case 'sha1':
2392
- $t = pack('H*', '3021300906052b0e03021a05000414');
2393
- break;
2394
- case 'sha256':
2395
- $t = pack('H*', '3031300d060960864801650304020105000420');
2396
- break;
2397
- case 'sha384':
2398
- $t = pack('H*', '3041300d060960864801650304020205000430');
2399
- break;
2400
- case 'sha512':
2401
- $t = pack('H*', '3051300d060960864801650304020305000440');
2402
- }
2403
- $t.= $h;
2404
- $tLen = strlen($t);
2405
-
2406
- if ($emLen < $tLen + 11) {
2407
- user_error('Intended encoded message length too short');
2408
- return false;
2409
- }
2410
-
2411
- $ps = str_repeat(chr(0xFF), $emLen - $tLen - 3);
2412
-
2413
- $em = "\0\1$ps\0$t";
2414
-
2415
- return $em;
2416
- }
2417
-
2418
- /**
2419
- * RSASSA-PKCS1-V1_5-SIGN
2420
- *
2421
- * See {@link http://tools.ietf.org/html/rfc3447#section-8.2.1 RFC3447#section-8.2.1}.
2422
- *
2423
- * @access private
2424
- * @param String $m
2425
- * @return String
2426
- */
2427
- function _rsassa_pkcs1_v1_5_sign($m)
2428
- {
2429
- // EMSA-PKCS1-v1_5 encoding
2430
-
2431
- $em = $this->_emsa_pkcs1_v1_5_encode($m, $this->k);
2432
- if ($em === false) {
2433
- user_error('RSA modulus too short');
2434
- return false;
2435
- }
2436
-
2437
- // RSA signature
2438
-
2439
- $m = $this->_os2ip($em);
2440
- $s = $this->_rsasp1($m);
2441
- $s = $this->_i2osp($s, $this->k);
2442
-
2443
- // Output the signature S
2444
-
2445
- return $s;
2446
- }
2447
-
2448
- /**
2449
- * RSASSA-PKCS1-V1_5-VERIFY
2450
- *
2451
- * See {@link http://tools.ietf.org/html/rfc3447#section-8.2.2 RFC3447#section-8.2.2}.
2452
- *
2453
- * @access private
2454
- * @param String $m
2455
- * @return String
2456
- */
2457
- function _rsassa_pkcs1_v1_5_verify($m, $s)
2458
- {
2459
- // Length checking
2460
-
2461
- if (strlen($s) != $this->k) {
2462
- user_error('Invalid signature');
2463
- return false;
2464
- }
2465
-
2466
- // RSA verification
2467
-
2468
- $s = $this->_os2ip($s);
2469
- $m2 = $this->_rsavp1($s);
2470
- if ($m2 === false) {
2471
- user_error('Invalid signature');
2472
- return false;
2473
- }
2474
- $em = $this->_i2osp($m2, $this->k);
2475
- if ($em === false) {
2476
- user_error('Invalid signature');
2477
- return false;
2478
- }
2479
-
2480
- // EMSA-PKCS1-v1_5 encoding
2481
-
2482
- $em2 = $this->_emsa_pkcs1_v1_5_encode($m, $this->k);
2483
- if ($em2 === false) {
2484
- user_error('RSA modulus too short');
2485
- return false;
2486
- }
2487
-
2488
- // Compare
2489
- return $this->_equals($em, $em2);
2490
- }
2491
-
2492
- /**
2493
- * Set Encryption Mode
2494
- *
2495
- * Valid values include CRYPT_RSA_ENCRYPTION_OAEP and CRYPT_RSA_ENCRYPTION_PKCS1.
2496
- *
2497
- * @access public
2498
- * @param Integer $mode
2499
- */
2500
- function setEncryptionMode($mode)
2501
- {
2502
- $this->encryptionMode = $mode;
2503
- }
2504
-
2505
- /**
2506
- * Set Signature Mode
2507
- *
2508
- * Valid values include CRYPT_RSA_SIGNATURE_PSS and CRYPT_RSA_SIGNATURE_PKCS1
2509
- *
2510
- * @access public
2511
- * @param Integer $mode
2512
- */
2513
- function setSignatureMode($mode)
2514
- {
2515
- $this->signatureMode = $mode;
2516
- }
2517
-
2518
- /**
2519
- * Encryption
2520
- *
2521
- * Both CRYPT_RSA_ENCRYPTION_OAEP and CRYPT_RSA_ENCRYPTION_PKCS1 both place limits on how long $plaintext can be.
2522
- * If $plaintext exceeds those limits it will be broken up so that it does and the resultant ciphertext's will
2523
- * be concatenated together.
2524
- *
2525
- * @see decrypt()
2526
- * @access public
2527
- * @param String $plaintext
2528
- * @return String
2529
- */
2530
- function encrypt($plaintext)
2531
- {
2532
- switch ($this->encryptionMode) {
2533
- case CRYPT_RSA_ENCRYPTION_PKCS1:
2534
- $length = $this->k - 11;
2535
- if ($length <= 0) {
2536
- return false;
2537
- }
2538
-
2539
- $plaintext = str_split($plaintext, $length);
2540
- $ciphertext = '';
2541
- foreach ($plaintext as $m) {
2542
- $ciphertext.= $this->_rsaes_pkcs1_v1_5_encrypt($m);
2543
- }
2544
- return $ciphertext;
2545
- //case CRYPT_RSA_ENCRYPTION_OAEP:
2546
- default:
2547
- $length = $this->k - 2 * $this->hLen - 2;
2548
- if ($length <= 0) {
2549
- return false;
2550
- }
2551
-
2552
- $plaintext = str_split($plaintext, $length);
2553
- $ciphertext = '';
2554
- foreach ($plaintext as $m) {
2555
- $ciphertext.= $this->_rsaes_oaep_encrypt($m);
2556
- }
2557
- return $ciphertext;
2558
- }
2559
- }
2560
-
2561
- /**
2562
- * Decryption
2563
- *
2564
- * @see encrypt()
2565
- * @access public
2566
- * @param String $plaintext
2567
- * @return String
2568
- */
2569
- function decrypt($ciphertext)
2570
- {
2571
- if ($this->k <= 0) {
2572
- return false;
2573
- }
2574
-
2575
- $ciphertext = str_split($ciphertext, $this->k);
2576
- $ciphertext[count($ciphertext) - 1] = str_pad($ciphertext[count($ciphertext) - 1], $this->k, chr(0), STR_PAD_LEFT);
2577
-
2578
- $plaintext = '';
2579
-
2580
- switch ($this->encryptionMode) {
2581
- case CRYPT_RSA_ENCRYPTION_PKCS1:
2582
- $decrypt = '_rsaes_pkcs1_v1_5_decrypt';
2583
- break;
2584
- //case CRYPT_RSA_ENCRYPTION_OAEP:
2585
- default:
2586
- $decrypt = '_rsaes_oaep_decrypt';
2587
- }
2588
-
2589
- foreach ($ciphertext as $c) {
2590
- $temp = $this->$decrypt($c);
2591
- if ($temp === false) {
2592
- return false;
2593
- }
2594
- $plaintext.= $temp;
2595
- }
2596
-
2597
- return $plaintext;
2598
- }
2599
-
2600
- /**
2601
- * Create a signature
2602
- *
2603
- * @see verify()
2604
- * @access public
2605
- * @param String $message
2606
- * @return String
2607
- */
2608
- function sign($message)
2609
- {
2610
- if (empty($this->modulus) || empty($this->exponent)) {
2611
- return false;
2612
- }
2613
-
2614
- switch ($this->signatureMode) {
2615
- case CRYPT_RSA_SIGNATURE_PKCS1:
2616
- return $this->_rsassa_pkcs1_v1_5_sign($message);
2617
- //case CRYPT_RSA_SIGNATURE_PSS:
2618
- default:
2619
- return $this->_rsassa_pss_sign($message);
2620
- }
2621
- }
2622
-
2623
- /**
2624
- * Verifies a signature
2625
- *
2626
- * @see sign()
2627
- * @access public
2628
- * @param String $message
2629
- * @param String $signature
2630
- * @return Boolean
2631
- */
2632
- function verify($message, $signature)
2633
- {
2634
- if (empty($this->modulus) || empty($this->exponent)) {
2635
- return false;
2636
- }
2637
-
2638
- switch ($this->signatureMode) {
2639
- case CRYPT_RSA_SIGNATURE_PKCS1:
2640
- return $this->_rsassa_pkcs1_v1_5_verify($message, $signature);
2641
- //case CRYPT_RSA_SIGNATURE_PSS:
2642
- default:
2643
- return $this->_rsassa_pss_verify($message, $signature);
2644
- }
2645
- }
2646
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * Pure-PHP PKCS#1 (v2.1) compliant implementation of RSA.
5
+ *
6
+ * PHP versions 4 and 5
7
+ *
8
+ * Here's an example of how to encrypt and decrypt text with this library:
9
+ * <code>
10
+ * <?php
11
+ * include 'Crypt/RSA.php';
12
+ *
13
+ * $rsa = new Crypt_RSA();
14
+ * extract($rsa->createKey());
15
+ *
16
+ * $plaintext = 'terrafrost';
17
+ *
18
+ * $rsa->loadKey($privatekey);
19
+ * $ciphertext = $rsa->encrypt($plaintext);
20
+ *
21
+ * $rsa->loadKey($publickey);
22
+ * echo $rsa->decrypt($ciphertext);
23
+ * ?>
24
+ * </code>
25
+ *
26
+ * Here's an example of how to create signatures and verify signatures with this library:
27
+ * <code>
28
+ * <?php
29
+ * include 'Crypt/RSA.php';
30
+ *
31
+ * $rsa = new Crypt_RSA();
32
+ * extract($rsa->createKey());
33
+ *
34
+ * $plaintext = 'terrafrost';
35
+ *
36
+ * $rsa->loadKey($privatekey);
37
+ * $signature = $rsa->sign($plaintext);
38
+ *
39
+ * $rsa->loadKey($publickey);
40
+ * echo $rsa->verify($plaintext, $signature) ? 'verified' : 'unverified';
41
+ * ?>
42
+ * </code>
43
+ *
44
+ * LICENSE: Permission is hereby granted, free of charge, to any person obtaining a copy
45
+ * of this software and associated documentation files (the "Software"), to deal
46
+ * in the Software without restriction, including without limitation the rights
47
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
48
+ * copies of the Software, and to permit persons to whom the Software is
49
+ * furnished to do so, subject to the following conditions:
50
+ *
51
+ * The above copyright notice and this permission notice shall be included in
52
+ * all copies or substantial portions of the Software.
53
+ *
54
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
55
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
56
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
57
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
58
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
59
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
60
+ * THE SOFTWARE.
61
+ *
62
+ * @category Crypt
63
+ * @package Crypt_RSA
64
+ * @author Jim Wigginton <terrafrost@php.net>
65
+ * @copyright MMIX Jim Wigginton
66
+ * @license http://www.opensource.org/licenses/mit-license.html MIT License
67
+ * @link http://phpseclib.sourceforge.net
68
+ */
69
+
70
+ /**
71
+ * Include Crypt_Random
72
+ */
73
+ // the class_exists() will only be called if the crypt_random_string function hasn't been defined and
74
+ // will trigger a call to __autoload() if you're wanting to auto-load classes
75
+ // call function_exists() a second time to stop the include_once from being called outside
76
+ // of the auto loader
77
+ if (!function_exists('crypt_random_string')) {
78
+ include_once 'Random.php';
79
+ }
80
+
81
+ /**
82
+ * Include Crypt_Hash
83
+ */
84
+ if (!class_exists('Crypt_Hash')) {
85
+ include_once 'Hash.php';
86
+ }
87
+
88
+ /**#@+
89
+ * @access public
90
+ * @see Crypt_RSA::encrypt()
91
+ * @see Crypt_RSA::decrypt()
92
+ */
93
+ /**
94
+ * Use {@link http://en.wikipedia.org/wiki/Optimal_Asymmetric_Encryption_Padding Optimal Asymmetric Encryption Padding}
95
+ * (OAEP) for encryption / decryption.
96
+ *
97
+ * Uses sha1 by default.
98
+ *
99
+ * @see Crypt_RSA::setHash()
100
+ * @see Crypt_RSA::setMGFHash()
101
+ */
102
+ define('CRYPT_RSA_ENCRYPTION_OAEP', 1);
103
+ /**
104
+ * Use PKCS#1 padding.
105
+ *
106
+ * Although CRYPT_RSA_ENCRYPTION_OAEP offers more security, including PKCS#1 padding is necessary for purposes of backwards
107
+ * compatibility with protocols (like SSH-1) written before OAEP's introduction.
108
+ */
109
+ define('CRYPT_RSA_ENCRYPTION_PKCS1', 2);
110
+ /**#@-*/
111
+
112
+ /**#@+
113
+ * @access public
114
+ * @see Crypt_RSA::sign()
115
+ * @see Crypt_RSA::verify()
116
+ * @see Crypt_RSA::setHash()
117
+ */
118
+ /**
119
+ * Use the Probabilistic Signature Scheme for signing
120
+ *
121
+ * Uses sha1 by default.
122
+ *
123
+ * @see Crypt_RSA::setSaltLength()
124
+ * @see Crypt_RSA::setMGFHash()
125
+ */
126
+ define('CRYPT_RSA_SIGNATURE_PSS', 1);
127
+ /**
128
+ * Use the PKCS#1 scheme by default.
129
+ *
130
+ * Although CRYPT_RSA_SIGNATURE_PSS offers more security, including PKCS#1 signing is necessary for purposes of backwards
131
+ * compatibility with protocols (like SSH-2) written before PSS's introduction.
132
+ */
133
+ define('CRYPT_RSA_SIGNATURE_PKCS1', 2);
134
+ /**#@-*/
135
+
136
+ /**#@+
137
+ * @access private
138
+ * @see Crypt_RSA::createKey()
139
+ */
140
+ /**
141
+ * ASN1 Integer
142
+ */
143
+ define('CRYPT_RSA_ASN1_INTEGER', 2);
144
+ /**
145
+ * ASN1 Bit String
146
+ */
147
+ define('CRYPT_RSA_ASN1_BITSTRING', 3);
148
+ /**
149
+ * ASN1 Octet String
150
+ */
151
+ define('CRYPT_RSA_ASN1_OCTETSTRING', 4);
152
+ /**
153
+ * ASN1 Object Identifier
154
+ */
155
+ define('CRYPT_RSA_ASN1_OBJECT', 6);
156
+ /**
157
+ * ASN1 Sequence (with the constucted bit set)
158
+ */
159
+ define('CRYPT_RSA_ASN1_SEQUENCE', 48);
160
+ /**#@-*/
161
+
162
+ /**#@+
163
+ * @access private
164
+ * @see Crypt_RSA::Crypt_RSA()
165
+ */
166
+ /**
167
+ * To use the pure-PHP implementation
168
+ */
169
+ define('CRYPT_RSA_MODE_INTERNAL', 1);
170
+ /**
171
+ * To use the OpenSSL library
172
+ *
173
+ * (if enabled; otherwise, the internal implementation will be used)
174
+ */
175
+ define('CRYPT_RSA_MODE_OPENSSL', 2);
176
+ /**#@-*/
177
+
178
+ /**
179
+ * Default openSSL configuration file.
180
+ */
181
+ define('CRYPT_RSA_OPENSSL_CONFIG', dirname(__FILE__) . '/../openssl.cnf');
182
+
183
+ /**#@+
184
+ * @access public
185
+ * @see Crypt_RSA::createKey()
186
+ * @see Crypt_RSA::setPrivateKeyFormat()
187
+ */
188
+ /**
189
+ * PKCS#1 formatted private key
190
+ *
191
+ * Used by OpenSSH
192
+ */
193
+ define('CRYPT_RSA_PRIVATE_FORMAT_PKCS1', 0);
194
+ /**
195
+ * PuTTY formatted private key
196
+ */
197
+ define('CRYPT_RSA_PRIVATE_FORMAT_PUTTY', 1);
198
+ /**
199
+ * XML formatted private key
200
+ */
201
+ define('CRYPT_RSA_PRIVATE_FORMAT_XML', 2);
202
+ /**
203
+ * PKCS#8 formatted private key
204
+ */
205
+ define('CRYPT_RSA_PRIVATE_FORMAT_PKCS8', 3);
206
+ /**#@-*/
207
+
208
+ /**#@+
209
+ * @access public
210
+ * @see Crypt_RSA::createKey()
211
+ * @see Crypt_RSA::setPublicKeyFormat()
212
+ */
213
+ /**
214
+ * Raw public key
215
+ *
216
+ * An array containing two Math_BigInteger objects.
217
+ *
218
+ * The exponent can be indexed with any of the following:
219
+ *
220
+ * 0, e, exponent, publicExponent
221
+ *
222
+ * The modulus can be indexed with any of the following:
223
+ *
224
+ * 1, n, modulo, modulus
225
+ */
226
+ define('CRYPT_RSA_PUBLIC_FORMAT_RAW', 3);
227
+ /**
228
+ * PKCS#1 formatted public key (raw)
229
+ *
230
+ * Used by File/X509.php
231
+ *
232
+ * Has the following header:
233
+ *
234
+ * -----BEGIN RSA PUBLIC KEY-----
235
+ *
236
+ * Analogous to ssh-keygen's pem format (as specified by -m)
237
+ */
238
+ define('CRYPT_RSA_PUBLIC_FORMAT_PKCS1', 4);
239
+ define('CRYPT_RSA_PUBLIC_FORMAT_PKCS1_RAW', 4);
240
+ /**
241
+ * XML formatted public key
242
+ */
243
+ define('CRYPT_RSA_PUBLIC_FORMAT_XML', 5);
244
+ /**
245
+ * OpenSSH formatted public key
246
+ *
247
+ * Place in $HOME/.ssh/authorized_keys
248
+ */
249
+ define('CRYPT_RSA_PUBLIC_FORMAT_OPENSSH', 6);
250
+ /**
251
+ * PKCS#1 formatted public key (encapsulated)
252
+ *
253
+ * Used by PHP's openssl_public_encrypt() and openssl's rsautl (when -pubin is set)
254
+ *
255
+ * Has the following header:
256
+ *
257
+ * -----BEGIN PUBLIC KEY-----
258
+ *
259
+ * Analogous to ssh-keygen's pkcs8 format (as specified by -m). Although PKCS8
260
+ * is specific to private keys it's basically creating a DER-encoded wrapper
261
+ * for keys. This just extends that same concept to public keys (much like ssh-keygen)
262
+ */
263
+ define('CRYPT_RSA_PUBLIC_FORMAT_PKCS8', 7);
264
+ /**#@-*/
265
+
266
+ /**
267
+ * Pure-PHP PKCS#1 compliant implementation of RSA.
268
+ *
269
+ * @package Crypt_RSA
270
+ * @author Jim Wigginton <terrafrost@php.net>
271
+ * @access public
272
+ */
273
+ class Crypt_RSA
274
+ {
275
+ /**
276
+ * Precomputed Zero
277
+ *
278
+ * @var Array
279
+ * @access private
280
+ */
281
+ var $zero;
282
+
283
+ /**
284
+ * Precomputed One
285
+ *
286
+ * @var Array
287
+ * @access private
288
+ */
289
+ var $one;
290
+
291
+ /**
292
+ * Private Key Format
293
+ *
294
+ * @var Integer
295
+ * @access private
296
+ */
297
+ var $privateKeyFormat = CRYPT_RSA_PRIVATE_FORMAT_PKCS1;
298
+
299
+ /**
300
+ * Public Key Format
301
+ *
302
+ * @var Integer
303
+ * @access public
304
+ */
305
+ var $publicKeyFormat = CRYPT_RSA_PUBLIC_FORMAT_PKCS8;
306
+
307
+ /**
308
+ * Modulus (ie. n)
309
+ *
310
+ * @var Math_BigInteger
311
+ * @access private
312
+ */
313
+ var $modulus;
314
+
315
+ /**
316
+ * Modulus length
317
+ *
318
+ * @var Math_BigInteger
319
+ * @access private
320
+ */
321
+ var $k;
322
+
323
+ /**
324
+ * Exponent (ie. e or d)
325
+ *
326
+ * @var Math_BigInteger
327
+ * @access private
328
+ */
329
+ var $exponent;
330
+
331
+ /**
332
+ * Primes for Chinese Remainder Theorem (ie. p and q)
333
+ *
334
+ * @var Array
335
+ * @access private
336
+ */
337
+ var $primes;
338
+
339
+ /**
340
+ * Exponents for Chinese Remainder Theorem (ie. dP and dQ)
341
+ *
342
+ * @var Array
343
+ * @access private
344
+ */
345
+ var $exponents;
346
+
347
+ /**
348
+ * Coefficients for Chinese Remainder Theorem (ie. qInv)
349
+ *
350
+ * @var Array
351
+ * @access private
352
+ */
353
+ var $coefficients;
354
+
355
+ /**
356
+ * Hash name
357
+ *
358
+ * @var String
359
+ * @access private
360
+ */
361
+ var $hashName;
362
+
363
+ /**
364
+ * Hash function
365
+ *
366
+ * @var Crypt_Hash
367
+ * @access private
368
+ */
369
+ var $hash;
370
+
371
+ /**
372
+ * Length of hash function output
373
+ *
374
+ * @var Integer
375
+ * @access private
376
+ */
377
+ var $hLen;
378
+
379
+ /**
380
+ * Length of salt
381
+ *
382
+ * @var Integer
383
+ * @access private
384
+ */
385
+ var $sLen;
386
+
387
+ /**
388
+ * Hash function for the Mask Generation Function
389
+ *
390
+ * @var Crypt_Hash
391
+ * @access private
392
+ */
393
+ var $mgfHash;
394
+
395
+ /**
396
+ * Length of MGF hash function output
397
+ *
398
+ * @var Integer
399
+ * @access private
400
+ */
401
+ var $mgfHLen;
402
+
403
+ /**
404
+ * Encryption mode
405
+ *
406
+ * @var Integer
407
+ * @access private
408
+ */
409
+ var $encryptionMode = CRYPT_RSA_ENCRYPTION_OAEP;
410
+
411
+ /**
412
+ * Signature mode
413
+ *
414
+ * @var Integer
415
+ * @access private
416
+ */
417
+ var $signatureMode = CRYPT_RSA_SIGNATURE_PSS;
418
+
419
+ /**
420
+ * Public Exponent
421
+ *
422
+ * @var Mixed
423
+ * @access private
424
+ */
425
+ var $publicExponent = false;
426
+
427
+ /**
428
+ * Password
429
+ *
430
+ * @var String
431
+ * @access private
432
+ */
433
+ var $password = false;
434
+
435
+ /**
436
+ * Components
437
+ *
438
+ * For use with parsing XML formatted keys. PHP's XML Parser functions use utilized - instead of PHP's DOM functions -
439
+ * because PHP's XML Parser functions work on PHP4 whereas PHP's DOM functions - although surperior - don't.
440
+ *
441
+ * @see Crypt_RSA::_start_element_handler()
442
+ * @var Array
443
+ * @access private
444
+ */
445
+ var $components = array();
446
+
447
+ /**
448
+ * Current String
449
+ *
450
+ * For use with parsing XML formatted keys.
451
+ *
452
+ * @see Crypt_RSA::_character_handler()
453
+ * @see Crypt_RSA::_stop_element_handler()
454
+ * @var Mixed
455
+ * @access private
456
+ */
457
+ var $current;
458
+
459
+ /**
460
+ * OpenSSL configuration file name.
461
+ *
462
+ * Set to null to use system configuration file.
463
+ * @see Crypt_RSA::createKey()
464
+ * @var Mixed
465
+ * @Access public
466
+ */
467
+ var $configFile;
468
+
469
+ /**
470
+ * Public key comment field.
471
+ *
472
+ * @var String
473
+ * @access private
474
+ */
475
+ var $comment = 'phpseclib-generated-key';
476
+
477
+ /**
478
+ * The constructor
479
+ *
480
+ * If you want to make use of the openssl extension, you'll need to set the mode manually, yourself. The reason
481
+ * Crypt_RSA doesn't do it is because OpenSSL doesn't fail gracefully. openssl_pkey_new(), in particular, requires
482
+ * openssl.cnf be present somewhere and, unfortunately, the only real way to find out is too late.
483
+ *
484
+ * @return Crypt_RSA
485
+ * @access public
486
+ */
487
+ function Crypt_RSA()
488
+ {
489
+ if (!class_exists('Math_BigInteger')) {
490
+ include_once 'Math/BigInteger.php';
491
+ }
492
+
493
+ $this->configFile = CRYPT_RSA_OPENSSL_CONFIG;
494
+
495
+ if ( !defined('CRYPT_RSA_MODE') ) {
496
+ switch (true) {
497
+ // Math/BigInteger's openssl requirements are a little less stringent than Crypt/RSA's. in particular,
498
+ // Math/BigInteger doesn't require an openssl.cfg file whereas Crypt/RSA does. so if Math/BigInteger
499
+ // can't use OpenSSL it can be pretty trivially assumed, then, that Crypt/RSA can't either.
500
+ case defined('MATH_BIGINTEGER_OPENSSL_DISABLE'):
501
+ define('CRYPT_RSA_MODE', CRYPT_RSA_MODE_INTERNAL);
502
+ break;
503
+ // openssl_pkey_get_details - which is used in the only place Crypt/RSA.php uses OpenSSL - was introduced in PHP 5.2.0
504
+ case !function_exists('openssl_pkey_get_details'):
505
+ define('CRYPT_RSA_MODE', CRYPT_RSA_MODE_INTERNAL);
506
+ break;
507
+ case extension_loaded('openssl') && version_compare(PHP_VERSION, '4.2.0', '>=') && file_exists($this->configFile):
508
+ // some versions of XAMPP have mismatched versions of OpenSSL which causes it not to work
509
+ ob_start();
510
+ @phpinfo();
511
+ $content = ob_get_contents();
512
+ ob_end_clean();
513
+
514
+ preg_match_all('#OpenSSL (Header|Library) Version(.*)#im', $content, $matches);
515
+
516
+ $versions = array();
517
+ if (!empty($matches[1])) {
518
+ for ($i = 0; $i < count($matches[1]); $i++) {
519
+ $versions[$matches[1][$i]] = trim(str_replace('=>', '', strip_tags($matches[2][$i])));
520
+ }
521
+ }
522
+
523
+ // it doesn't appear that OpenSSL versions were reported upon until PHP 5.3+
524
+ switch (true) {
525
+ case !isset($versions['Header']):
526
+ case !isset($versions['Library']):
527
+ case $versions['Header'] == $versions['Library']:
528
+ define('CRYPT_RSA_MODE', CRYPT_RSA_MODE_OPENSSL);
529
+ break;
530
+ default:
531
+ define('CRYPT_RSA_MODE', CRYPT_RSA_MODE_INTERNAL);
532
+ define('MATH_BIGINTEGER_OPENSSL_DISABLE', true);
533
+ }
534
+ break;
535
+ default:
536
+ define('CRYPT_RSA_MODE', CRYPT_RSA_MODE_INTERNAL);
537
+ }
538
+ }
539
+
540
+ $this->zero = new Math_BigInteger();
541
+ $this->one = new Math_BigInteger(1);
542
+
543
+ $this->hash = new Crypt_Hash('sha1');
544
+ $this->hLen = $this->hash->getLength();
545
+ $this->hashName = 'sha1';
546
+ $this->mgfHash = new Crypt_Hash('sha1');
547
+ $this->mgfHLen = $this->mgfHash->getLength();
548
+ }
549
+
550
+ /**
551
+ * Create public / private key pair
552
+ *
553
+ * Returns an array with the following three elements:
554
+ * - 'privatekey': The private key.
555
+ * - 'publickey': The public key.
556
+ * - 'partialkey': A partially computed key (if the execution time exceeded $timeout).
557
+ * Will need to be passed back to Crypt_RSA::createKey() as the third parameter for further processing.
558
+ *
559
+ * @access public
560
+ * @param optional Integer $bits
561
+ * @param optional Integer $timeout
562
+ * @param optional Math_BigInteger $p
563
+ */
564
+ function createKey($bits = 1024, $timeout = false, $partial = array())
565
+ {
566
+ if (!defined('CRYPT_RSA_EXPONENT')) {
567
+ // http://en.wikipedia.org/wiki/65537_%28number%29
568
+ define('CRYPT_RSA_EXPONENT', '65537');
569
+ }
570
+ // per <http://cseweb.ucsd.edu/~hovav/dist/survey.pdf#page=5>, this number ought not result in primes smaller
571
+ // than 256 bits. as a consequence if the key you're trying to create is 1024 bits and you've set CRYPT_RSA_SMALLEST_PRIME
572
+ // to 384 bits then you're going to get a 384 bit prime and a 640 bit prime (384 + 1024 % 384). at least if
573
+ // CRYPT_RSA_MODE is set to CRYPT_RSA_MODE_INTERNAL. if CRYPT_RSA_MODE is set to CRYPT_RSA_MODE_OPENSSL then
574
+ // CRYPT_RSA_SMALLEST_PRIME is ignored (ie. multi-prime RSA support is more intended as a way to speed up RSA key
575
+ // generation when there's a chance neither gmp nor OpenSSL are installed)
576
+ if (!defined('CRYPT_RSA_SMALLEST_PRIME')) {
577
+ define('CRYPT_RSA_SMALLEST_PRIME', 4096);
578
+ }
579
+
580
+ // OpenSSL uses 65537 as the exponent and requires RSA keys be 384 bits minimum
581
+ if ( CRYPT_RSA_MODE == CRYPT_RSA_MODE_OPENSSL && $bits >= 384 && CRYPT_RSA_EXPONENT == 65537) {
582
+ $config = array();
583
+ if (isset($this->configFile)) {
584
+ $config['config'] = $this->configFile;
585
+ }
586
+ $rsa = openssl_pkey_new(array('private_key_bits' => $bits) + $config);
587
+ openssl_pkey_export($rsa, $privatekey, null, $config);
588
+ $publickey = openssl_pkey_get_details($rsa);
589
+ $publickey = $publickey['key'];
590
+
591
+ $privatekey = call_user_func_array(array($this, '_convertPrivateKey'), array_values($this->_parseKey($privatekey, CRYPT_RSA_PRIVATE_FORMAT_PKCS1)));
592
+ $publickey = call_user_func_array(array($this, '_convertPublicKey'), array_values($this->_parseKey($publickey, CRYPT_RSA_PUBLIC_FORMAT_PKCS1)));
593
+
594
+ // clear the buffer of error strings stemming from a minimalistic openssl.cnf
595
+ while (openssl_error_string() !== false);
596
+
597
+ return array(
598
+ 'privatekey' => $privatekey,
599
+ 'publickey' => $publickey,
600
+ 'partialkey' => false
601
+ );
602
+ }
603
+
604
+ static $e;
605
+ if (!isset($e)) {
606
+ $e = new Math_BigInteger(CRYPT_RSA_EXPONENT);
607
+ }
608
+
609
+ extract($this->_generateMinMax($bits));
610
+ $absoluteMin = $min;
611
+ $temp = $bits >> 1; // divide by two to see how many bits P and Q would be
612
+ if ($temp > CRYPT_RSA_SMALLEST_PRIME) {
613
+ $num_primes = floor($bits / CRYPT_RSA_SMALLEST_PRIME);
614
+ $temp = CRYPT_RSA_SMALLEST_PRIME;
615
+ } else {
616
+ $num_primes = 2;
617
+ }
618
+ extract($this->_generateMinMax($temp + $bits % $temp));
619
+ $finalMax = $max;
620
+ extract($this->_generateMinMax($temp));
621
+
622
+ $generator = new Math_BigInteger();
623
+
624
+ $n = $this->one->copy();
625
+ if (!empty($partial)) {
626
+ extract(unserialize($partial));
627
+ } else {
628
+ $exponents = $coefficients = $primes = array();
629
+ $lcm = array(
630
+ 'top' => $this->one->copy(),
631
+ 'bottom' => false
632
+ );
633
+ }
634
+
635
+ $start = time();
636
+ $i0 = count($primes) + 1;
637
+
638
+ do {
639
+ for ($i = $i0; $i <= $num_primes; $i++) {
640
+ if ($timeout !== false) {
641
+ $timeout-= time() - $start;
642
+ $start = time();
643
+ if ($timeout <= 0) {
644
+ return array(
645
+ 'privatekey' => '',
646
+ 'publickey' => '',
647
+ 'partialkey' => serialize(array(
648
+ 'primes' => $primes,
649
+ 'coefficients' => $coefficients,
650
+ 'lcm' => $lcm,
651
+ 'exponents' => $exponents
652
+ ))
653
+ );
654
+ }
655
+ }
656
+
657
+ if ($i == $num_primes) {
658
+ list($min, $temp) = $absoluteMin->divide($n);
659
+ if (!$temp->equals($this->zero)) {
660
+ $min = $min->add($this->one); // ie. ceil()
661
+ }
662
+ $primes[$i] = $generator->randomPrime($min, $finalMax, $timeout);
663
+ } else {
664
+ $primes[$i] = $generator->randomPrime($min, $max, $timeout);
665
+ }
666
+
667
+ if ($primes[$i] === false) { // if we've reached the timeout
668
+ if (count($primes) > 1) {
669
+ $partialkey = '';
670
+ } else {
671
+ array_pop($primes);
672
+ $partialkey = serialize(array(
673
+ 'primes' => $primes,
674
+ 'coefficients' => $coefficients,
675
+ 'lcm' => $lcm,
676
+ 'exponents' => $exponents
677
+ ));
678
+ }
679
+
680
+ return array(
681
+ 'privatekey' => '',
682
+ 'publickey' => '',
683
+ 'partialkey' => $partialkey
684
+ );
685
+ }
686
+
687
+ // the first coefficient is calculated differently from the rest
688
+ // ie. instead of being $primes[1]->modInverse($primes[2]), it's $primes[2]->modInverse($primes[1])
689
+ if ($i > 2) {
690
+ $coefficients[$i] = $n->modInverse($primes[$i]);
691
+ }
692
+
693
+ $n = $n->multiply($primes[$i]);
694
+
695
+ $temp = $primes[$i]->subtract($this->one);
696
+
697
+ // textbook RSA implementations use Euler's totient function instead of the least common multiple.
698
+ // see http://en.wikipedia.org/wiki/Euler%27s_totient_function
699
+ $lcm['top'] = $lcm['top']->multiply($temp);
700
+ $lcm['bottom'] = $lcm['bottom'] === false ? $temp : $lcm['bottom']->gcd($temp);
701
+
702
+ $exponents[$i] = $e->modInverse($temp);
703
+ }
704
+
705
+ list($temp) = $lcm['top']->divide($lcm['bottom']);
706
+ $gcd = $temp->gcd($e);
707
+ $i0 = 1;
708
+ } while (!$gcd->equals($this->one));
709
+
710
+ $d = $e->modInverse($temp);
711
+
712
+ $coefficients[2] = $primes[2]->modInverse($primes[1]);
713
+
714
+ // from <http://tools.ietf.org/html/rfc3447#appendix-A.1.2>:
715
+ // RSAPrivateKey ::= SEQUENCE {
716
+ // version Version,
717
+ // modulus INTEGER, -- n
718
+ // publicExponent INTEGER, -- e
719
+ // privateExponent INTEGER, -- d
720
+ // prime1 INTEGER, -- p
721
+ // prime2 INTEGER, -- q
722
+ // exponent1 INTEGER, -- d mod (p-1)
723
+ // exponent2 INTEGER, -- d mod (q-1)
724
+ // coefficient INTEGER, -- (inverse of q) mod p
725
+ // otherPrimeInfos OtherPrimeInfos OPTIONAL
726
+ // }
727
+
728
+ return array(
729
+ 'privatekey' => $this->_convertPrivateKey($n, $e, $d, $primes, $exponents, $coefficients),
730
+ 'publickey' => $this->_convertPublicKey($n, $e),
731
+ 'partialkey' => false
732
+ );
733
+ }
734
+
735
+ /**
736
+ * Convert a private key to the appropriate format.
737
+ *
738
+ * @access private
739
+ * @see setPrivateKeyFormat()
740
+ * @param String $RSAPrivateKey
741
+ * @return String
742
+ */
743
+ function _convertPrivateKey($n, $e, $d, $primes, $exponents, $coefficients)
744
+ {
745
+ $signed = $this->privateKeyFormat != CRYPT_RSA_PRIVATE_FORMAT_XML;
746
+ $num_primes = count($primes);
747
+ $raw = array(
748
+ 'version' => $num_primes == 2 ? chr(0) : chr(1), // two-prime vs. multi
749
+ 'modulus' => $n->toBytes($signed),
750
+ 'publicExponent' => $e->toBytes($signed),
751
+ 'privateExponent' => $d->toBytes($signed),
752
+ 'prime1' => $primes[1]->toBytes($signed),
753
+ 'prime2' => $primes[2]->toBytes($signed),
754
+ 'exponent1' => $exponents[1]->toBytes($signed),
755
+ 'exponent2' => $exponents[2]->toBytes($signed),
756
+ 'coefficient' => $coefficients[2]->toBytes($signed)
757
+ );
758
+
759
+ // if the format in question does not support multi-prime rsa and multi-prime rsa was used,
760
+ // call _convertPublicKey() instead.
761
+ switch ($this->privateKeyFormat) {
762
+ case CRYPT_RSA_PRIVATE_FORMAT_XML:
763
+ if ($num_primes != 2) {
764
+ return false;
765
+ }
766
+ return "<RSAKeyValue>\r\n" .
767
+ ' <Modulus>' . base64_encode($raw['modulus']) . "</Modulus>\r\n" .
768
+ ' <Exponent>' . base64_encode($raw['publicExponent']) . "</Exponent>\r\n" .
769
+ ' <P>' . base64_encode($raw['prime1']) . "</P>\r\n" .
770
+ ' <Q>' . base64_encode($raw['prime2']) . "</Q>\r\n" .
771
+ ' <DP>' . base64_encode($raw['exponent1']) . "</DP>\r\n" .
772
+ ' <DQ>' . base64_encode($raw['exponent2']) . "</DQ>\r\n" .
773
+ ' <InverseQ>' . base64_encode($raw['coefficient']) . "</InverseQ>\r\n" .
774
+ ' <D>' . base64_encode($raw['privateExponent']) . "</D>\r\n" .
775
+ '</RSAKeyValue>';
776
+ break;
777
+ case CRYPT_RSA_PRIVATE_FORMAT_PUTTY:
778
+ if ($num_primes != 2) {
779
+ return false;
780
+ }
781
+ $key = "PuTTY-User-Key-File-2: ssh-rsa\r\nEncryption: ";
782
+ $encryption = (!empty($this->password) || is_string($this->password)) ? 'aes256-cbc' : 'none';
783
+ $key.= $encryption;
784
+ $key.= "\r\nComment: " . $this->comment . "\r\n";
785
+ $public = pack('Na*Na*Na*',
786
+ strlen('ssh-rsa'), 'ssh-rsa', strlen($raw['publicExponent']), $raw['publicExponent'], strlen($raw['modulus']), $raw['modulus']
787
+ );
788
+ $source = pack('Na*Na*Na*Na*',
789
+ strlen('ssh-rsa'), 'ssh-rsa', strlen($encryption), $encryption,
790
+ strlen($this->comment), $this->comment, strlen($public), $public
791
+ );
792
+ $public = base64_encode($public);
793
+ $key.= "Public-Lines: " . ((strlen($public) + 63) >> 6) . "\r\n";
794
+ $key.= chunk_split($public, 64);
795
+ $private = pack('Na*Na*Na*Na*',
796
+ strlen($raw['privateExponent']), $raw['privateExponent'], strlen($raw['prime1']), $raw['prime1'],
797
+ strlen($raw['prime2']), $raw['prime2'], strlen($raw['coefficient']), $raw['coefficient']
798
+ );
799
+ if (empty($this->password) && !is_string($this->password)) {
800
+ $source.= pack('Na*', strlen($private), $private);
801
+ $hashkey = 'putty-private-key-file-mac-key';
802
+ } else {
803
+ $private.= crypt_random_string(16 - (strlen($private) & 15));
804
+ $source.= pack('Na*', strlen($private), $private);
805
+ if (!class_exists('Crypt_AES')) {
806
+ include_once 'Crypt/AES.php';
807
+ }
808
+ $sequence = 0;
809
+ $symkey = '';
810
+ while (strlen($symkey) < 32) {
811
+ $temp = pack('Na*', $sequence++, $this->password);
812
+ $symkey.= pack('H*', sha1($temp));
813
+ }
814
+ $symkey = substr($symkey, 0, 32);
815
+ $crypto = new Crypt_AES();
816
+
817
+ $crypto->setKey($symkey);
818
+ $crypto->disablePadding();
819
+ $private = $crypto->encrypt($private);
820
+ $hashkey = 'putty-private-key-file-mac-key' . $this->password;
821
+ }
822
+
823
+ $private = base64_encode($private);
824
+ $key.= 'Private-Lines: ' . ((strlen($private) + 63) >> 6) . "\r\n";
825
+ $key.= chunk_split($private, 64);
826
+ if (!class_exists('Crypt_Hash')) {
827
+ include_once 'Crypt/Hash.php';
828
+ }
829
+ $hash = new Crypt_Hash('sha1');
830
+ $hash->setKey(pack('H*', sha1($hashkey)));
831
+ $key.= 'Private-MAC: ' . bin2hex($hash->hash($source)) . "\r\n";
832
+
833
+ return $key;
834
+ default: // eg. CRYPT_RSA_PRIVATE_FORMAT_PKCS1
835
+ $components = array();
836
+ foreach ($raw as $name => $value) {
837
+ $components[$name] = pack('Ca*a*', CRYPT_RSA_ASN1_INTEGER, $this->_encodeLength(strlen($value)), $value);
838
+ }
839
+
840
+ $RSAPrivateKey = implode('', $components);
841
+
842
+ if ($num_primes > 2) {
843
+ $OtherPrimeInfos = '';
844
+ for ($i = 3; $i <= $num_primes; $i++) {
845
+ // OtherPrimeInfos ::= SEQUENCE SIZE(1..MAX) OF OtherPrimeInfo
846
+ //
847
+ // OtherPrimeInfo ::= SEQUENCE {
848
+ // prime INTEGER, -- ri
849
+ // exponent INTEGER, -- di
850
+ // coefficient INTEGER -- ti
851
+ // }
852
+ $OtherPrimeInfo = pack('Ca*a*', CRYPT_RSA_ASN1_INTEGER, $this->_encodeLength(strlen($primes[$i]->toBytes(true))), $primes[$i]->toBytes(true));
853
+ $OtherPrimeInfo.= pack('Ca*a*', CRYPT_RSA_ASN1_INTEGER, $this->_encodeLength(strlen($exponents[$i]->toBytes(true))), $exponents[$i]->toBytes(true));
854
+ $OtherPrimeInfo.= pack('Ca*a*', CRYPT_RSA_ASN1_INTEGER, $this->_encodeLength(strlen($coefficients[$i]->toBytes(true))), $coefficients[$i]->toBytes(true));
855
+ $OtherPrimeInfos.= pack('Ca*a*', CRYPT_RSA_ASN1_SEQUENCE, $this->_encodeLength(strlen($OtherPrimeInfo)), $OtherPrimeInfo);
856
+ }
857
+ $RSAPrivateKey.= pack('Ca*a*', CRYPT_RSA_ASN1_SEQUENCE, $this->_encodeLength(strlen($OtherPrimeInfos)), $OtherPrimeInfos);
858
+ }
859
+
860
+ $RSAPrivateKey = pack('Ca*a*', CRYPT_RSA_ASN1_SEQUENCE, $this->_encodeLength(strlen($RSAPrivateKey)), $RSAPrivateKey);
861
+
862
+ if ($this->privateKeyFormat == CRYPT_RSA_PRIVATE_FORMAT_PKCS8) {
863
+ $rsaOID = pack('H*', '300d06092a864886f70d0101010500'); // hex version of MA0GCSqGSIb3DQEBAQUA
864
+ $RSAPrivateKey = pack('Ca*a*Ca*a*',
865
+ CRYPT_RSA_ASN1_INTEGER, "\01\00", $rsaOID, 4, $this->_encodeLength(strlen($RSAPrivateKey)), $RSAPrivateKey
866
+ );
867
+ $RSAPrivateKey = pack('Ca*a*', CRYPT_RSA_ASN1_SEQUENCE, $this->_encodeLength(strlen($RSAPrivateKey)), $RSAPrivateKey);
868
+ if (!empty($this->password) || is_string($this->password)) {
869
+ $salt = crypt_random_string(8);
870
+ $iterationCount = 2048;
871
+
872
+ if (!class_exists('Crypt_DES')) {
873
+ include_once 'Crypt/DES.php';
874
+ }
875
+ $crypto = new Crypt_DES();
876
+ $crypto->setPassword($this->password, 'pbkdf1', 'md5', $salt, $iterationCount);
877
+ $RSAPrivateKey = $crypto->encrypt($RSAPrivateKey);
878
+
879
+ $parameters = pack('Ca*a*Ca*N',
880
+ CRYPT_RSA_ASN1_OCTETSTRING, $this->_encodeLength(strlen($salt)), $salt,
881
+ CRYPT_RSA_ASN1_INTEGER, $this->_encodeLength(4), $iterationCount
882
+ );
883
+ $pbeWithMD5AndDES_CBC = "\x2a\x86\x48\x86\xf7\x0d\x01\x05\x03";
884
+
885
+ $encryptionAlgorithm = pack('Ca*a*Ca*a*',
886
+ CRYPT_RSA_ASN1_OBJECT, $this->_encodeLength(strlen($pbeWithMD5AndDES_CBC)), $pbeWithMD5AndDES_CBC,
887
+ CRYPT_RSA_ASN1_SEQUENCE, $this->_encodeLength(strlen($parameters)), $parameters
888
+ );
889
+
890
+ $RSAPrivateKey = pack('Ca*a*Ca*a*',
891
+ CRYPT_RSA_ASN1_SEQUENCE, $this->_encodeLength(strlen($encryptionAlgorithm)), $encryptionAlgorithm,
892
+ CRYPT_RSA_ASN1_OCTETSTRING, $this->_encodeLength(strlen($RSAPrivateKey)), $RSAPrivateKey
893
+ );
894
+
895
+ $RSAPrivateKey = pack('Ca*a*', CRYPT_RSA_ASN1_SEQUENCE, $this->_encodeLength(strlen($RSAPrivateKey)), $RSAPrivateKey);
896
+
897
+ $RSAPrivateKey = "-----BEGIN ENCRYPTED PRIVATE KEY-----\r\n" .
898
+ chunk_split(base64_encode($RSAPrivateKey), 64) .
899
+ '-----END ENCRYPTED PRIVATE KEY-----';
900
+ } else {
901
+ $RSAPrivateKey = "-----BEGIN PRIVATE KEY-----\r\n" .
902
+ chunk_split(base64_encode($RSAPrivateKey), 64) .
903
+ '-----END PRIVATE KEY-----';
904
+ }
905
+ return $RSAPrivateKey;
906
+ }
907
+
908
+ if (!empty($this->password) || is_string($this->password)) {
909
+ $iv = crypt_random_string(8);
910
+ $symkey = pack('H*', md5($this->password . $iv)); // symkey is short for symmetric key
911
+ $symkey.= substr(pack('H*', md5($symkey . $this->password . $iv)), 0, 8);
912
+ if (!class_exists('Crypt_TripleDES')) {
913
+ include_once 'Crypt/TripleDES.php';
914
+ }
915
+ $des = new Crypt_TripleDES();
916
+ $des->setKey($symkey);
917
+ $des->setIV($iv);
918
+ $iv = strtoupper(bin2hex($iv));
919
+ $RSAPrivateKey = "-----BEGIN RSA PRIVATE KEY-----\r\n" .
920
+ "Proc-Type: 4,ENCRYPTED\r\n" .
921
+ "DEK-Info: DES-EDE3-CBC,$iv\r\n" .
922
+ "\r\n" .
923
+ chunk_split(base64_encode($des->encrypt($RSAPrivateKey)), 64) .
924
+ '-----END RSA PRIVATE KEY-----';
925
+ } else {
926
+ $RSAPrivateKey = "-----BEGIN RSA PRIVATE KEY-----\r\n" .
927
+ chunk_split(base64_encode($RSAPrivateKey), 64) .
928
+ '-----END RSA PRIVATE KEY-----';
929
+ }
930
+
931
+ return $RSAPrivateKey;
932
+ }
933
+ }
934
+
935
+ /**
936
+ * Convert a public key to the appropriate format
937
+ *
938
+ * @access private
939
+ * @see setPublicKeyFormat()
940
+ * @param String $RSAPrivateKey
941
+ * @return String
942
+ */
943
+ function _convertPublicKey($n, $e)
944
+ {
945
+ $signed = $this->publicKeyFormat != CRYPT_RSA_PUBLIC_FORMAT_XML;
946
+
947
+ $modulus = $n->toBytes($signed);
948
+ $publicExponent = $e->toBytes($signed);
949
+
950
+ switch ($this->publicKeyFormat) {
951
+ case CRYPT_RSA_PUBLIC_FORMAT_RAW:
952
+ return array('e' => $e->copy(), 'n' => $n->copy());
953
+ case CRYPT_RSA_PUBLIC_FORMAT_XML:
954
+ return "<RSAKeyValue>\r\n" .
955
+ ' <Modulus>' . base64_encode($modulus) . "</Modulus>\r\n" .
956
+ ' <Exponent>' . base64_encode($publicExponent) . "</Exponent>\r\n" .
957
+ '</RSAKeyValue>';
958
+ break;
959
+ case CRYPT_RSA_PUBLIC_FORMAT_OPENSSH:
960
+ // from <http://tools.ietf.org/html/rfc4253#page-15>:
961
+ // string "ssh-rsa"
962
+ // mpint e
963
+ // mpint n
964
+ $RSAPublicKey = pack('Na*Na*Na*', strlen('ssh-rsa'), 'ssh-rsa', strlen($publicExponent), $publicExponent, strlen($modulus), $modulus);
965
+ $RSAPublicKey = 'ssh-rsa ' . base64_encode($RSAPublicKey) . ' ' . $this->comment;
966
+
967
+ return $RSAPublicKey;
968
+ default: // eg. CRYPT_RSA_PUBLIC_FORMAT_PKCS1_RAW or CRYPT_RSA_PUBLIC_FORMAT_PKCS1
969
+ // from <http://tools.ietf.org/html/rfc3447#appendix-A.1.1>:
970
+ // RSAPublicKey ::= SEQUENCE {
971
+ // modulus INTEGER, -- n
972
+ // publicExponent INTEGER -- e
973
+ // }
974
+ $components = array(
975
+ 'modulus' => pack('Ca*a*', CRYPT_RSA_ASN1_INTEGER, $this->_encodeLength(strlen($modulus)), $modulus),
976
+ 'publicExponent' => pack('Ca*a*', CRYPT_RSA_ASN1_INTEGER, $this->_encodeLength(strlen($publicExponent)), $publicExponent)
977
+ );
978
+
979
+ $RSAPublicKey = pack('Ca*a*a*',
980
+ CRYPT_RSA_ASN1_SEQUENCE, $this->_encodeLength(strlen($components['modulus']) + strlen($components['publicExponent'])),
981
+ $components['modulus'], $components['publicExponent']
982
+ );
983
+
984
+ if ($this->publicKeyFormat == CRYPT_RSA_PUBLIC_FORMAT_PKCS1_RAW) {
985
+ $RSAPublicKey = "-----BEGIN RSA PUBLIC KEY-----\r\n" .
986
+ chunk_split(base64_encode($RSAPublicKey), 64) .
987
+ '-----END RSA PUBLIC KEY-----';
988
+ } else {
989
+ // sequence(oid(1.2.840.113549.1.1.1), null)) = rsaEncryption.
990
+ $rsaOID = pack('H*', '300d06092a864886f70d0101010500'); // hex version of MA0GCSqGSIb3DQEBAQUA
991
+ $RSAPublicKey = chr(0) . $RSAPublicKey;
992
+ $RSAPublicKey = chr(3) . $this->_encodeLength(strlen($RSAPublicKey)) . $RSAPublicKey;
993
+
994
+ $RSAPublicKey = pack('Ca*a*',
995
+ CRYPT_RSA_ASN1_SEQUENCE, $this->_encodeLength(strlen($rsaOID . $RSAPublicKey)), $rsaOID . $RSAPublicKey
996
+ );
997
+
998
+ $RSAPublicKey = "-----BEGIN PUBLIC KEY-----\r\n" .
999
+ chunk_split(base64_encode($RSAPublicKey), 64) .
1000
+ '-----END PUBLIC KEY-----';
1001
+ }
1002
+
1003
+ return $RSAPublicKey;
1004
+ }
1005
+ }
1006
+
1007
+ /**
1008
+ * Break a public or private key down into its constituant components
1009
+ *
1010
+ * @access private
1011
+ * @see _convertPublicKey()
1012
+ * @see _convertPrivateKey()
1013
+ * @param String $key
1014
+ * @param Integer $type
1015
+ * @return Array
1016
+ */
1017
+ function _parseKey($key, $type)
1018
+ {
1019
+ if ($type != CRYPT_RSA_PUBLIC_FORMAT_RAW && !is_string($key)) {
1020
+ return false;
1021
+ }
1022
+
1023
+ switch ($type) {
1024
+ case CRYPT_RSA_PUBLIC_FORMAT_RAW:
1025
+ if (!is_array($key)) {
1026
+ return false;
1027
+ }
1028
+ $components = array();
1029
+ switch (true) {
1030
+ case isset($key['e']):
1031
+ $components['publicExponent'] = $key['e']->copy();
1032
+ break;
1033
+ case isset($key['exponent']):
1034
+ $components['publicExponent'] = $key['exponent']->copy();
1035
+ break;
1036
+ case isset($key['publicExponent']):
1037
+ $components['publicExponent'] = $key['publicExponent']->copy();
1038
+ break;
1039
+ case isset($key[0]):
1040
+ $components['publicExponent'] = $key[0]->copy();
1041
+ }
1042
+ switch (true) {
1043
+ case isset($key['n']):
1044
+ $components['modulus'] = $key['n']->copy();
1045
+ break;
1046
+ case isset($key['modulo']):
1047
+ $components['modulus'] = $key['modulo']->copy();
1048
+ break;
1049
+ case isset($key['modulus']):
1050
+ $components['modulus'] = $key['modulus']->copy();
1051
+ break;
1052
+ case isset($key[1]):
1053
+ $components['modulus'] = $key[1]->copy();
1054
+ }
1055
+ return isset($components['modulus']) && isset($components['publicExponent']) ? $components : false;
1056
+ case CRYPT_RSA_PRIVATE_FORMAT_PKCS1:
1057
+ case CRYPT_RSA_PRIVATE_FORMAT_PKCS8:
1058
+ case CRYPT_RSA_PUBLIC_FORMAT_PKCS1:
1059
+ /* Although PKCS#1 proposes a format that public and private keys can use, encrypting them is
1060
+ "outside the scope" of PKCS#1. PKCS#1 then refers you to PKCS#12 and PKCS#15 if you're wanting to
1061
+ protect private keys, however, that's not what OpenSSL* does. OpenSSL protects private keys by adding
1062
+ two new "fields" to the key - DEK-Info and Proc-Type. These fields are discussed here:
1063
+
1064
+ http://tools.ietf.org/html/rfc1421#section-4.6.1.1
1065
+ http://tools.ietf.org/html/rfc1421#section-4.6.1.3
1066
+
1067
+ DES-EDE3-CBC as an algorithm, however, is not discussed anywhere, near as I can tell.
1068
+ DES-CBC and DES-EDE are discussed in RFC1423, however, DES-EDE3-CBC isn't, nor is its key derivation
1069
+ function. As is, the definitive authority on this encoding scheme isn't the IETF but rather OpenSSL's
1070
+ own implementation. ie. the implementation *is* the standard and any bugs that may exist in that
1071
+ implementation are part of the standard, as well.
1072
+
1073
+ * OpenSSL is the de facto standard. It's utilized by OpenSSH and other projects */
1074
+ if (preg_match('#DEK-Info: (.+),(.+)#', $key, $matches)) {
1075
+ $iv = pack('H*', trim($matches[2]));
1076
+ $symkey = pack('H*', md5($this->password . substr($iv, 0, 8))); // symkey is short for symmetric key
1077
+ $symkey.= pack('H*', md5($symkey . $this->password . substr($iv, 0, 8)));
1078
+ // remove the Proc-Type / DEK-Info sections as they're no longer needed
1079
+ $key = preg_replace('#^(?:Proc-Type|DEK-Info): .*#m', '', $key);
1080
+ $ciphertext = $this->_extractBER($key);
1081
+ if ($ciphertext === false) {
1082
+ $ciphertext = $key;
1083
+ }
1084
+ switch ($matches[1]) {
1085
+ case 'AES-256-CBC':
1086
+ if (!class_exists('Crypt_AES')) {
1087
+ include_once 'Crypt/AES.php';
1088
+ }
1089
+ $crypto = new Crypt_AES();
1090
+ break;
1091
+ case 'AES-128-CBC':
1092
+ if (!class_exists('Crypt_AES')) {
1093
+ include_once 'Crypt/AES.php';
1094
+ }
1095
+ $symkey = substr($symkey, 0, 16);
1096
+ $crypto = new Crypt_AES();
1097
+ break;
1098
+ case 'DES-EDE3-CFB':
1099
+ if (!class_exists('Crypt_TripleDES')) {
1100
+ include_once 'Crypt/TripleDES.php';
1101
+ }
1102
+ $crypto = new Crypt_TripleDES(CRYPT_DES_MODE_CFB);
1103
+ break;
1104
+ case 'DES-EDE3-CBC':
1105
+ if (!class_exists('Crypt_TripleDES')) {
1106
+ include_once 'Crypt/TripleDES.php';
1107
+ }
1108
+ $symkey = substr($symkey, 0, 24);
1109
+ $crypto = new Crypt_TripleDES();
1110
+ break;
1111
+ case 'DES-CBC':
1112
+ if (!class_exists('Crypt_DES')) {
1113
+ include_once 'Crypt/DES.php';
1114
+ }
1115
+ $crypto = new Crypt_DES();
1116
+ break;
1117
+ default:
1118
+ return false;
1119
+ }
1120
+ $crypto->setKey($symkey);
1121
+ $crypto->setIV($iv);
1122
+ $decoded = $crypto->decrypt($ciphertext);
1123
+ } else {
1124
+ $decoded = $this->_extractBER($key);
1125
+ }
1126
+
1127
+ if ($decoded !== false) {
1128
+ $key = $decoded;
1129
+ }
1130
+
1131
+ $components = array();
1132
+
1133
+ if (ord($this->_string_shift($key)) != CRYPT_RSA_ASN1_SEQUENCE) {
1134
+ return false;
1135
+ }
1136
+ if ($this->_decodeLength($key) != strlen($key)) {
1137
+ return false;
1138
+ }
1139
+
1140
+ $tag = ord($this->_string_shift($key));
1141
+ /* intended for keys for which OpenSSL's asn1parse returns the following:
1142
+
1143
+ 0:d=0 hl=4 l= 631 cons: SEQUENCE
1144
+ 4:d=1 hl=2 l= 1 prim: INTEGER :00
1145
+ 7:d=1 hl=2 l= 13 cons: SEQUENCE
1146
+ 9:d=2 hl=2 l= 9 prim: OBJECT :rsaEncryption
1147
+ 20:d=2 hl=2 l= 0 prim: NULL
1148
+ 22:d=1 hl=4 l= 609 prim: OCTET STRING
1149
+
1150
+ ie. PKCS8 keys*/
1151
+
1152
+ if ($tag == CRYPT_RSA_ASN1_INTEGER && substr($key, 0, 3) == "\x01\x00\x30") {
1153
+ $this->_string_shift($key, 3);
1154
+ $tag = CRYPT_RSA_ASN1_SEQUENCE;
1155
+ }
1156
+
1157
+ if ($tag == CRYPT_RSA_ASN1_SEQUENCE) {
1158
+ $temp = $this->_string_shift($key, $this->_decodeLength($key));
1159
+ if (ord($this->_string_shift($temp)) != CRYPT_RSA_ASN1_OBJECT) {
1160
+ return false;
1161
+ }
1162
+ $length = $this->_decodeLength($temp);
1163
+ switch ($this->_string_shift($temp, $length)) {
1164
+ case "\x2a\x86\x48\x86\xf7\x0d\x01\x01\x01": // rsaEncryption
1165
+ break;
1166
+ case "\x2a\x86\x48\x86\xf7\x0d\x01\x05\x03": // pbeWithMD5AndDES-CBC
1167
+ /*
1168
+ PBEParameter ::= SEQUENCE {
1169
+ salt OCTET STRING (SIZE(8)),
1170
+ iterationCount INTEGER }
1171
+ */
1172
+ if (ord($this->_string_shift($temp)) != CRYPT_RSA_ASN1_SEQUENCE) {
1173
+ return false;
1174
+ }
1175
+ if ($this->_decodeLength($temp) != strlen($temp)) {
1176
+ return false;
1177
+ }
1178
+ $this->_string_shift($temp); // assume it's an octet string
1179
+ $salt = $this->_string_shift($temp, $this->_decodeLength($temp));
1180
+ if (ord($this->_string_shift($temp)) != CRYPT_RSA_ASN1_INTEGER) {
1181
+ return false;
1182
+ }
1183
+ $this->_decodeLength($temp);
1184
+ list(, $iterationCount) = unpack('N', str_pad($temp, 4, chr(0), STR_PAD_LEFT));
1185
+ $this->_string_shift($key); // assume it's an octet string
1186
+ $length = $this->_decodeLength($key);
1187
+ if (strlen($key) != $length) {
1188
+ return false;
1189
+ }
1190
+
1191
+ if (!class_exists('Crypt_DES')) {
1192
+ include_once 'Crypt/DES.php';
1193
+ }
1194
+ $crypto = new Crypt_DES();
1195
+ $crypto->setPassword($this->password, 'pbkdf1', 'md5', $salt, $iterationCount);
1196
+ $key = $crypto->decrypt($key);
1197
+ if ($key === false) {
1198
+ return false;
1199
+ }
1200
+ return $this->_parseKey($key, CRYPT_RSA_PRIVATE_FORMAT_PKCS1);
1201
+ default:
1202
+ return false;
1203
+ }
1204
+ /* intended for keys for which OpenSSL's asn1parse returns the following:
1205
+
1206
+ 0:d=0 hl=4 l= 290 cons: SEQUENCE
1207
+ 4:d=1 hl=2 l= 13 cons: SEQUENCE
1208
+ 6:d=2 hl=2 l= 9 prim: OBJECT :rsaEncryption
1209
+ 17:d=2 hl=2 l= 0 prim: NULL
1210
+ 19:d=1 hl=4 l= 271 prim: BIT STRING */
1211
+ $tag = ord($this->_string_shift($key)); // skip over the BIT STRING / OCTET STRING tag
1212
+ $this->_decodeLength($key); // skip over the BIT STRING / OCTET STRING length
1213
+ // "The initial octet shall encode, as an unsigned binary integer wtih bit 1 as the least significant bit, the number of
1214
+ // unused bits in the final subsequent octet. The number shall be in the range zero to seven."
1215
+ // -- http://www.itu.int/ITU-T/studygroups/com17/languages/X.690-0207.pdf (section 8.6.2.2)
1216
+ if ($tag == CRYPT_RSA_ASN1_BITSTRING) {
1217
+ $this->_string_shift($key);
1218
+ }
1219
+ if (ord($this->_string_shift($key)) != CRYPT_RSA_ASN1_SEQUENCE) {
1220
+ return false;
1221
+ }
1222
+ if ($this->_decodeLength($key) != strlen($key)) {
1223
+ return false;
1224
+ }
1225
+ $tag = ord($this->_string_shift($key));
1226
+ }
1227
+ if ($tag != CRYPT_RSA_ASN1_INTEGER) {
1228
+ return false;
1229
+ }
1230
+
1231
+ $length = $this->_decodeLength($key);
1232
+ $temp = $this->_string_shift($key, $length);
1233
+ if (strlen($temp) != 1 || ord($temp) > 2) {
1234
+ $components['modulus'] = new Math_BigInteger($temp, 256);
1235
+ $this->_string_shift($key); // skip over CRYPT_RSA_ASN1_INTEGER
1236
+ $length = $this->_decodeLength($key);
1237
+ $components[$type == CRYPT_RSA_PUBLIC_FORMAT_PKCS1 ? 'publicExponent' : 'privateExponent'] = new Math_BigInteger($this->_string_shift($key, $length), 256);
1238
+
1239
+ return $components;
1240
+ }
1241
+ if (ord($this->_string_shift($key)) != CRYPT_RSA_ASN1_INTEGER) {
1242
+ return false;
1243
+ }
1244
+ $length = $this->_decodeLength($key);
1245
+ $components['modulus'] = new Math_BigInteger($this->_string_shift($key, $length), 256);
1246
+ $this->_string_shift($key);
1247
+ $length = $this->_decodeLength($key);
1248
+ $components['publicExponent'] = new Math_BigInteger($this->_string_shift($key, $length), 256);
1249
+ $this->_string_shift($key);
1250
+ $length = $this->_decodeLength($key);
1251
+ $components['privateExponent'] = new Math_BigInteger($this->_string_shift($key, $length), 256);
1252
+ $this->_string_shift($key);
1253
+ $length = $this->_decodeLength($key);
1254
+ $components['primes'] = array(1 => new Math_BigInteger($this->_string_shift($key, $length), 256));
1255
+ $this->_string_shift($key);
1256
+ $length = $this->_decodeLength($key);
1257
+ $components['primes'][] = new Math_BigInteger($this->_string_shift($key, $length), 256);
1258
+ $this->_string_shift($key);
1259
+ $length = $this->_decodeLength($key);
1260
+ $components['exponents'] = array(1 => new Math_BigInteger($this->_string_shift($key, $length), 256));
1261
+ $this->_string_shift($key);
1262
+ $length = $this->_decodeLength($key);
1263
+ $components['exponents'][] = new Math_BigInteger($this->_string_shift($key, $length), 256);
1264
+ $this->_string_shift($key);
1265
+ $length = $this->_decodeLength($key);
1266
+ $components['coefficients'] = array(2 => new Math_BigInteger($this->_string_shift($key, $length), 256));
1267
+
1268
+ if (!empty($key)) {
1269
+ if (ord($this->_string_shift($key)) != CRYPT_RSA_ASN1_SEQUENCE) {
1270
+ return false;
1271
+ }
1272
+ $this->_decodeLength($key);
1273
+ while (!empty($key)) {
1274
+ if (ord($this->_string_shift($key)) != CRYPT_RSA_ASN1_SEQUENCE) {
1275
+ return false;
1276
+ }
1277
+ $this->_decodeLength($key);
1278
+ $key = substr($key, 1);
1279
+ $length = $this->_decodeLength($key);
1280
+ $components['primes'][] = new Math_BigInteger($this->_string_shift($key, $length), 256);
1281
+ $this->_string_shift($key);
1282
+ $length = $this->_decodeLength($key);
1283
+ $components['exponents'][] = new Math_BigInteger($this->_string_shift($key, $length), 256);
1284
+ $this->_string_shift($key);
1285
+ $length = $this->_decodeLength($key);
1286
+ $components['coefficients'][] = new Math_BigInteger($this->_string_shift($key, $length), 256);
1287
+ }
1288
+ }
1289
+
1290
+ return $components;
1291
+ case CRYPT_RSA_PUBLIC_FORMAT_OPENSSH:
1292
+ $parts = explode(' ', $key, 3);
1293
+
1294
+ $key = isset($parts[1]) ? base64_decode($parts[1]) : false;
1295
+ if ($key === false) {
1296
+ return false;
1297
+ }
1298
+
1299
+ $comment = isset($parts[2]) ? $parts[2] : false;
1300
+
1301
+ $cleanup = substr($key, 0, 11) == "\0\0\0\7ssh-rsa";
1302
+
1303
+ if (strlen($key) <= 4) {
1304
+ return false;
1305
+ }
1306
+ extract(unpack('Nlength', $this->_string_shift($key, 4)));
1307
+ $publicExponent = new Math_BigInteger($this->_string_shift($key, $length), -256);
1308
+ if (strlen($key) <= 4) {
1309
+ return false;
1310
+ }
1311
+ extract(unpack('Nlength', $this->_string_shift($key, 4)));
1312
+ $modulus = new Math_BigInteger($this->_string_shift($key, $length), -256);
1313
+
1314
+ if ($cleanup && strlen($key)) {
1315
+ if (strlen($key) <= 4) {
1316
+ return false;
1317
+ }
1318
+ extract(unpack('Nlength', $this->_string_shift($key, 4)));
1319
+ $realModulus = new Math_BigInteger($this->_string_shift($key, $length), -256);
1320
+ return strlen($key) ? false : array(
1321
+ 'modulus' => $realModulus,
1322
+ 'publicExponent' => $modulus,
1323
+ 'comment' => $comment
1324
+ );
1325
+ } else {
1326
+ return strlen($key) ? false : array(
1327
+ 'modulus' => $modulus,
1328
+ 'publicExponent' => $publicExponent,
1329
+ 'comment' => $comment
1330
+ );
1331
+ }
1332
+ // http://www.w3.org/TR/xmldsig-core/#sec-RSAKeyValue
1333
+ // http://en.wikipedia.org/wiki/XML_Signature
1334
+ case CRYPT_RSA_PRIVATE_FORMAT_XML:
1335
+ case CRYPT_RSA_PUBLIC_FORMAT_XML:
1336
+ $this->components = array();
1337
+
1338
+ $xml = xml_parser_create('UTF-8');
1339
+ xml_set_object($xml, $this);
1340
+ xml_set_element_handler($xml, '_start_element_handler', '_stop_element_handler');
1341
+ xml_set_character_data_handler($xml, '_data_handler');
1342
+ // add <xml></xml> to account for "dangling" tags like <BitStrength>...</BitStrength> that are sometimes added
1343
+ if (!xml_parse($xml, '<xml>' . $key . '</xml>')) {
1344
+ return false;
1345
+ }
1346
+
1347
+ return isset($this->components['modulus']) && isset($this->components['publicExponent']) ? $this->components : false;
1348
+ // from PuTTY's SSHPUBK.C
1349
+ case CRYPT_RSA_PRIVATE_FORMAT_PUTTY:
1350
+ $components = array();
1351
+ $key = preg_split('#\r\n|\r|\n#', $key);
1352
+ $type = trim(preg_replace('#PuTTY-User-Key-File-2: (.+)#', '$1', $key[0]));
1353
+ if ($type != 'ssh-rsa') {
1354
+ return false;
1355
+ }
1356
+ $encryption = trim(preg_replace('#Encryption: (.+)#', '$1', $key[1]));
1357
+ $comment = trim(preg_replace('#Comment: (.+)#', '$1', $key[2]));
1358
+
1359
+ $publicLength = trim(preg_replace('#Public-Lines: (\d+)#', '$1', $key[3]));
1360
+ $public = base64_decode(implode('', array_map('trim', array_slice($key, 4, $publicLength))));
1361
+ $public = substr($public, 11);
1362
+ extract(unpack('Nlength', $this->_string_shift($public, 4)));
1363
+ $components['publicExponent'] = new Math_BigInteger($this->_string_shift($public, $length), -256);
1364
+ extract(unpack('Nlength', $this->_string_shift($public, 4)));
1365
+ $components['modulus'] = new Math_BigInteger($this->_string_shift($public, $length), -256);
1366
+
1367
+ $privateLength = trim(preg_replace('#Private-Lines: (\d+)#', '$1', $key[$publicLength + 4]));
1368
+ $private = base64_decode(implode('', array_map('trim', array_slice($key, $publicLength + 5, $privateLength))));
1369
+
1370
+ switch ($encryption) {
1371
+ case 'aes256-cbc':
1372
+ if (!class_exists('Crypt_AES')) {
1373
+ include_once 'Crypt/AES.php';
1374
+ }
1375
+ $symkey = '';
1376
+ $sequence = 0;
1377
+ while (strlen($symkey) < 32) {
1378
+ $temp = pack('Na*', $sequence++, $this->password);
1379
+ $symkey.= pack('H*', sha1($temp));
1380
+ }
1381
+ $symkey = substr($symkey, 0, 32);
1382
+ $crypto = new Crypt_AES();
1383
+ }
1384
+
1385
+ if ($encryption != 'none') {
1386
+ $crypto->setKey($symkey);
1387
+ $crypto->disablePadding();
1388
+ $private = $crypto->decrypt($private);
1389
+ if ($private === false) {
1390
+ return false;
1391
+ }
1392
+ }
1393
+
1394
+ extract(unpack('Nlength', $this->_string_shift($private, 4)));
1395
+ if (strlen($private) < $length) {
1396
+ return false;
1397
+ }
1398
+ $components['privateExponent'] = new Math_BigInteger($this->_string_shift($private, $length), -256);
1399
+ extract(unpack('Nlength', $this->_string_shift($private, 4)));
1400
+ if (strlen($private) < $length) {
1401
+ return false;
1402
+ }
1403
+ $components['primes'] = array(1 => new Math_BigInteger($this->_string_shift($private, $length), -256));
1404
+ extract(unpack('Nlength', $this->_string_shift($private, 4)));
1405
+ if (strlen($private) < $length) {
1406
+ return false;
1407
+ }
1408
+ $components['primes'][] = new Math_BigInteger($this->_string_shift($private, $length), -256);
1409
+
1410
+ $temp = $components['primes'][1]->subtract($this->one);
1411
+ $components['exponents'] = array(1 => $components['publicExponent']->modInverse($temp));
1412
+ $temp = $components['primes'][2]->subtract($this->one);
1413
+ $components['exponents'][] = $components['publicExponent']->modInverse($temp);
1414
+
1415
+ extract(unpack('Nlength', $this->_string_shift($private, 4)));
1416
+ if (strlen($private) < $length) {
1417
+ return false;
1418
+ }
1419
+ $components['coefficients'] = array(2 => new Math_BigInteger($this->_string_shift($private, $length), -256));
1420
+
1421
+ return $components;
1422
+ }
1423
+ }
1424
+
1425
+ /**
1426
+ * Returns the key size
1427
+ *
1428
+ * More specifically, this returns the size of the modulo in bits.
1429
+ *
1430
+ * @access public
1431
+ * @return Integer
1432
+ */
1433
+ function getSize()
1434
+ {
1435
+ return !isset($this->modulus) ? 0 : strlen($this->modulus->toBits());
1436
+ }
1437
+
1438
+ /**
1439
+ * Start Element Handler
1440
+ *
1441
+ * Called by xml_set_element_handler()
1442
+ *
1443
+ * @access private
1444
+ * @param Resource $parser
1445
+ * @param String $name
1446
+ * @param Array $attribs
1447
+ */
1448
+ function _start_element_handler($parser, $name, $attribs)
1449
+ {
1450
+ //$name = strtoupper($name);
1451
+ switch ($name) {
1452
+ case 'MODULUS':
1453
+ $this->current = &$this->components['modulus'];
1454
+ break;
1455
+ case 'EXPONENT':
1456
+ $this->current = &$this->components['publicExponent'];
1457
+ break;
1458
+ case 'P':
1459
+ $this->current = &$this->components['primes'][1];
1460
+ break;
1461
+ case 'Q':
1462
+ $this->current = &$this->components['primes'][2];
1463
+ break;
1464
+ case 'DP':
1465
+ $this->current = &$this->components['exponents'][1];
1466
+ break;
1467
+ case 'DQ':
1468
+ $this->current = &$this->components['exponents'][2];
1469
+ break;
1470
+ case 'INVERSEQ':
1471
+ $this->current = &$this->components['coefficients'][2];
1472
+ break;
1473
+ case 'D':
1474
+ $this->current = &$this->components['privateExponent'];
1475
+ }
1476
+ $this->current = '';
1477
+ }
1478
+
1479
+ /**
1480
+ * Stop Element Handler
1481
+ *
1482
+ * Called by xml_set_element_handler()
1483
+ *
1484
+ * @access private
1485
+ * @param Resource $parser
1486
+ * @param String $name
1487
+ */
1488
+ function _stop_element_handler($parser, $name)
1489
+ {
1490
+ if (isset($this->current)) {
1491
+ $this->current = new Math_BigInteger(base64_decode($this->current), 256);
1492
+ unset($this->current);
1493
+ }
1494
+ }
1495
+
1496
+ /**
1497
+ * Data Handler
1498
+ *
1499
+ * Called by xml_set_character_data_handler()
1500
+ *
1501
+ * @access private
1502
+ * @param Resource $parser
1503
+ * @param String $data
1504
+ */
1505
+ function _data_handler($parser, $data)
1506
+ {
1507
+ if (!isset($this->current) || is_object($this->current)) {
1508
+ return;
1509
+ }
1510
+ $this->current.= trim($data);
1511
+ }
1512
+
1513
+ /**
1514
+ * Loads a public or private key
1515
+ *
1516
+ * Returns true on success and false on failure (ie. an incorrect password was provided or the key was malformed)
1517
+ *
1518
+ * @access public
1519
+ * @param String $key
1520
+ * @param Integer $type optional
1521
+ */
1522
+ function loadKey($key, $type = false)
1523
+ {
1524
+ if (is_object($key) && strtolower(get_class($key)) == 'crypt_rsa') {
1525
+ $this->privateKeyFormat = $key->privateKeyFormat;
1526
+ $this->publicKeyFormat = $key->publicKeyFormat;
1527
+ $this->k = $key->k;
1528
+ $this->hLen = $key->hLen;
1529
+ $this->sLen = $key->sLen;
1530
+ $this->mgfHLen = $key->mgfHLen;
1531
+ $this->encryptionMode = $key->encryptionMode;
1532
+ $this->signatureMode = $key->signatureMode;
1533
+ $this->password = $key->password;
1534
+ $this->configFile = $key->configFile;
1535
+ $this->comment = $key->comment;
1536
+
1537
+ if (is_object($key->hash)) {
1538
+ $this->hash = new Crypt_Hash($key->hash->getHash());
1539
+ }
1540
+ if (is_object($key->mgfHash)) {
1541
+ $this->mgfHash = new Crypt_Hash($key->mgfHash->getHash());
1542
+ }
1543
+
1544
+ if (is_object($key->modulus)) {
1545
+ $this->modulus = $key->modulus->copy();
1546
+ }
1547
+ if (is_object($key->exponent)) {
1548
+ $this->exponent = $key->exponent->copy();
1549
+ }
1550
+ if (is_object($key->publicExponent)) {
1551
+ $this->publicExponent = $key->publicExponent->copy();
1552
+ }
1553
+
1554
+ $this->primes = array();
1555
+ $this->exponents = array();
1556
+ $this->coefficients = array();
1557
+
1558
+ foreach ($this->primes as $prime) {
1559
+ $this->primes[] = $prime->copy();
1560
+ }
1561
+ foreach ($this->exponents as $exponent) {
1562
+ $this->exponents[] = $exponent->copy();
1563
+ }
1564
+ foreach ($this->coefficients as $coefficient) {
1565
+ $this->coefficients[] = $coefficient->copy();
1566
+ }
1567
+
1568
+ return true;
1569
+ }
1570
+
1571
+ if ($type === false) {
1572
+ $types = array(
1573
+ CRYPT_RSA_PUBLIC_FORMAT_RAW,
1574
+ CRYPT_RSA_PRIVATE_FORMAT_PKCS1,
1575
+ CRYPT_RSA_PRIVATE_FORMAT_XML,
1576
+ CRYPT_RSA_PRIVATE_FORMAT_PUTTY,
1577
+ CRYPT_RSA_PUBLIC_FORMAT_OPENSSH
1578
+ );
1579
+ foreach ($types as $type) {
1580
+ $components = $this->_parseKey($key, $type);
1581
+ if ($components !== false) {
1582
+ break;
1583
+ }
1584
+ }
1585
+
1586
+ } else {
1587
+ $components = $this->_parseKey($key, $type);
1588
+ }
1589
+
1590
+ if ($components === false) {
1591
+ return false;
1592
+ }
1593
+
1594
+ if (isset($components['comment']) && $components['comment'] !== false) {
1595
+ $this->comment = $components['comment'];
1596
+ }
1597
+ $this->modulus = $components['modulus'];
1598
+ $this->k = strlen($this->modulus->toBytes());
1599
+ $this->exponent = isset($components['privateExponent']) ? $components['privateExponent'] : $components['publicExponent'];
1600
+ if (isset($components['primes'])) {
1601
+ $this->primes = $components['primes'];
1602
+ $this->exponents = $components['exponents'];
1603
+ $this->coefficients = $components['coefficients'];
1604
+ $this->publicExponent = $components['publicExponent'];
1605
+ } else {
1606
+ $this->primes = array();
1607
+ $this->exponents = array();
1608
+ $this->coefficients = array();
1609
+ $this->publicExponent = false;
1610
+ }
1611
+
1612
+ switch ($type) {
1613
+ case CRYPT_RSA_PUBLIC_FORMAT_OPENSSH:
1614
+ case CRYPT_RSA_PUBLIC_FORMAT_RAW:
1615
+ $this->setPublicKey();
1616
+ break;
1617
+ case CRYPT_RSA_PRIVATE_FORMAT_PKCS1:
1618
+ switch (true) {
1619
+ case strpos($key, '-BEGIN PUBLIC KEY-') !== false:
1620
+ case strpos($key, '-BEGIN RSA PUBLIC KEY-') !== false:
1621
+ $this->setPublicKey();
1622
+ }
1623
+ }
1624
+
1625
+ return true;
1626
+ }
1627
+
1628
+ /**
1629
+ * Sets the password
1630
+ *
1631
+ * Private keys can be encrypted with a password. To unset the password, pass in the empty string or false.
1632
+ * Or rather, pass in $password such that empty($password) && !is_string($password) is true.
1633
+ *
1634
+ * @see createKey()
1635
+ * @see loadKey()
1636
+ * @access public
1637
+ * @param String $password
1638
+ */
1639
+ function setPassword($password = false)
1640
+ {
1641
+ $this->password = $password;
1642
+ }
1643
+
1644
+ /**
1645
+ * Defines the public key
1646
+ *
1647
+ * Some private key formats define the public exponent and some don't. Those that don't define it are problematic when
1648
+ * used in certain contexts. For example, in SSH-2, RSA authentication works by sending the public key along with a
1649
+ * message signed by the private key to the server. The SSH-2 server looks the public key up in an index of public keys
1650
+ * and if it's present then proceeds to verify the signature. Problem is, if your private key doesn't include the public
1651
+ * exponent this won't work unless you manually add the public exponent. phpseclib tries to guess if the key being used
1652
+ * is the public key but in the event that it guesses incorrectly you might still want to explicitly set the key as being
1653
+ * public.
1654
+ *
1655
+ * Do note that when a new key is loaded the index will be cleared.
1656
+ *
1657
+ * Returns true on success, false on failure
1658
+ *
1659
+ * @see getPublicKey()
1660
+ * @access public
1661
+ * @param String $key optional
1662
+ * @param Integer $type optional
1663
+ * @return Boolean
1664
+ */
1665
+ function setPublicKey($key = false, $type = false)
1666
+ {
1667
+ // if a public key has already been loaded return false
1668
+ if (!empty($this->publicExponent)) {
1669
+ return false;
1670
+ }
1671
+
1672
+ if ($key === false && !empty($this->modulus)) {
1673
+ $this->publicExponent = $this->exponent;
1674
+ return true;
1675
+ }
1676
+
1677
+ if ($type === false) {
1678
+ $types = array(
1679
+ CRYPT_RSA_PUBLIC_FORMAT_RAW,
1680
+ CRYPT_RSA_PUBLIC_FORMAT_PKCS1,
1681
+ CRYPT_RSA_PUBLIC_FORMAT_XML,
1682
+ CRYPT_RSA_PUBLIC_FORMAT_OPENSSH
1683
+ );
1684
+ foreach ($types as $type) {
1685
+ $components = $this->_parseKey($key, $type);
1686
+ if ($components !== false) {
1687
+ break;
1688
+ }
1689
+ }
1690
+ } else {
1691
+ $components = $this->_parseKey($key, $type);
1692
+ }
1693
+
1694
+ if ($components === false) {
1695
+ return false;
1696
+ }
1697
+
1698
+ if (empty($this->modulus) || !$this->modulus->equals($components['modulus'])) {
1699
+ $this->modulus = $components['modulus'];
1700
+ $this->exponent = $this->publicExponent = $components['publicExponent'];
1701
+ return true;
1702
+ }
1703
+
1704
+ $this->publicExponent = $components['publicExponent'];
1705
+
1706
+ return true;
1707
+ }
1708
+
1709
+ /**
1710
+ * Defines the private key
1711
+ *
1712
+ * If phpseclib guessed a private key was a public key and loaded it as such it might be desirable to force
1713
+ * phpseclib to treat the key as a private key. This function will do that.
1714
+ *
1715
+ * Do note that when a new key is loaded the index will be cleared.
1716
+ *
1717
+ * Returns true on success, false on failure
1718
+ *
1719
+ * @see getPublicKey()
1720
+ * @access public
1721
+ * @param String $key optional
1722
+ * @param Integer $type optional
1723
+ * @return Boolean
1724
+ */
1725
+ function setPrivateKey($key = false, $type = false)
1726
+ {
1727
+ if ($key === false && !empty($this->publicExponent)) {
1728
+ unset($this->publicExponent);
1729
+ return true;
1730
+ }
1731
+
1732
+ $rsa = new Crypt_RSA();
1733
+ if (!$rsa->loadKey($key, $type)) {
1734
+ return false;
1735
+ }
1736
+ unset($rsa->publicExponent);
1737
+
1738
+ // don't overwrite the old key if the new key is invalid
1739
+ $this->loadKey($rsa);
1740
+ return true;
1741
+ }
1742
+
1743
+ /**
1744
+ * Returns the public key
1745
+ *
1746
+ * The public key is only returned under two circumstances - if the private key had the public key embedded within it
1747
+ * or if the public key was set via setPublicKey(). If the currently loaded key is supposed to be the public key this
1748
+ * function won't return it since this library, for the most part, doesn't distinguish between public and private keys.
1749
+ *
1750
+ * @see getPublicKey()
1751
+ * @access public
1752
+ * @param String $key
1753
+ * @param Integer $type optional
1754
+ */
1755
+ function getPublicKey($type = CRYPT_RSA_PUBLIC_FORMAT_PKCS8)
1756
+ {
1757
+ if (empty($this->modulus) || empty($this->publicExponent)) {
1758
+ return false;
1759
+ }
1760
+
1761
+ $oldFormat = $this->publicKeyFormat;
1762
+ $this->publicKeyFormat = $type;
1763
+ $temp = $this->_convertPublicKey($this->modulus, $this->publicExponent);
1764
+ $this->publicKeyFormat = $oldFormat;
1765
+ return $temp;
1766
+ }
1767
+
1768
+ /**
1769
+ * Returns the private key
1770
+ *
1771
+ * The private key is only returned if the currently loaded key contains the constituent prime numbers.
1772
+ *
1773
+ * @see getPublicKey()
1774
+ * @access public
1775
+ * @param String $key
1776
+ * @param Integer $type optional
1777
+ */
1778
+ function getPrivateKey($type = CRYPT_RSA_PUBLIC_FORMAT_PKCS1)
1779
+ {
1780
+ if (empty($this->primes)) {
1781
+ return false;
1782
+ }
1783
+
1784
+ $oldFormat = $this->privateKeyFormat;
1785
+ $this->privateKeyFormat = $type;
1786
+ $temp = $this->_convertPrivateKey($this->modulus, $this->publicExponent, $this->exponent, $this->primes, $this->exponents, $this->coefficients);
1787
+ $this->privateKeyFormat = $oldFormat;
1788
+ return $temp;
1789
+ }
1790
+
1791
+ /**
1792
+ * Returns a minimalistic private key
1793
+ *
1794
+ * Returns the private key without the prime number constituants. Structurally identical to a public key that
1795
+ * hasn't been set as the public key
1796
+ *
1797
+ * @see getPrivateKey()
1798
+ * @access private
1799
+ * @param String $key
1800
+ * @param Integer $type optional
1801
+ */
1802
+ function _getPrivatePublicKey($mode = CRYPT_RSA_PUBLIC_FORMAT_PKCS8)
1803
+ {
1804
+ if (empty($this->modulus) || empty($this->exponent)) {
1805
+ return false;
1806
+ }
1807
+
1808
+ $oldFormat = $this->publicKeyFormat;
1809
+ $this->publicKeyFormat = $mode;
1810
+ $temp = $this->_convertPublicKey($this->modulus, $this->exponent);
1811
+ $this->publicKeyFormat = $oldFormat;
1812
+ return $temp;
1813
+ }
1814
+
1815
+ /**
1816
+ * __toString() magic method
1817
+ *
1818
+ * @access public
1819
+ */
1820
+ function __toString()
1821
+ {
1822
+ $key = $this->getPrivateKey($this->privateKeyFormat);
1823
+ if ($key !== false) {
1824
+ return $key;
1825
+ }
1826
+ $key = $this->_getPrivatePublicKey($this->publicKeyFormat);
1827
+ return $key !== false ? $key : '';
1828
+ }
1829
+
1830
+ /**
1831
+ * __clone() magic method
1832
+ *
1833
+ * @access public
1834
+ */
1835
+ function __clone()
1836
+ {
1837
+ $key = new Crypt_RSA();
1838
+ $key->loadKey($this);
1839
+ return $key;
1840
+ }
1841
+
1842
+ /**
1843
+ * Generates the smallest and largest numbers requiring $bits bits
1844
+ *
1845
+ * @access private
1846
+ * @param Integer $bits
1847
+ * @return Array
1848
+ */
1849
+ function _generateMinMax($bits)
1850
+ {
1851
+ $bytes = $bits >> 3;
1852
+ $min = str_repeat(chr(0), $bytes);
1853
+ $max = str_repeat(chr(0xFF), $bytes);
1854
+ $msb = $bits & 7;
1855
+ if ($msb) {
1856
+ $min = chr(1 << ($msb - 1)) . $min;
1857
+ $max = chr((1 << $msb) - 1) . $max;
1858
+ } else {
1859
+ $min[0] = chr(0x80);
1860
+ }
1861
+
1862
+ return array(
1863
+ 'min' => new Math_BigInteger($min, 256),
1864
+ 'max' => new Math_BigInteger($max, 256)
1865
+ );
1866
+ }
1867
+
1868
+ /**
1869
+ * DER-decode the length
1870
+ *
1871
+ * DER supports lengths up to (2**8)**127, however, we'll only support lengths up to (2**8)**4. See
1872
+ * {@link http://itu.int/ITU-T/studygroups/com17/languages/X.690-0207.pdf#p=13 X.690 paragraph 8.1.3} for more information.
1873
+ *
1874
+ * @access private
1875
+ * @param String $string
1876
+ * @return Integer
1877
+ */
1878
+ function _decodeLength(&$string)
1879
+ {
1880
+ $length = ord($this->_string_shift($string));
1881
+ if ( $length & 0x80 ) { // definite length, long form
1882
+ $length&= 0x7F;
1883
+ $temp = $this->_string_shift($string, $length);
1884
+ list(, $length) = unpack('N', substr(str_pad($temp, 4, chr(0), STR_PAD_LEFT), -4));
1885
+ }
1886
+ return $length;
1887
+ }
1888
+
1889
+ /**
1890
+ * DER-encode the length
1891
+ *
1892
+ * DER supports lengths up to (2**8)**127, however, we'll only support lengths up to (2**8)**4. See
1893
+ * {@link http://itu.int/ITU-T/studygroups/com17/languages/X.690-0207.pdf#p=13 X.690 paragraph 8.1.3} for more information.
1894
+ *
1895
+ * @access private
1896
+ * @param Integer $length
1897
+ * @return String
1898
+ */
1899
+ function _encodeLength($length)
1900
+ {
1901
+ if ($length <= 0x7F) {
1902
+ return chr($length);
1903
+ }
1904
+
1905
+ $temp = ltrim(pack('N', $length), chr(0));
1906
+ return pack('Ca*', 0x80 | strlen($temp), $temp);
1907
+ }
1908
+
1909
+ /**
1910
+ * String Shift
1911
+ *
1912
+ * Inspired by array_shift
1913
+ *
1914
+ * @param String $string
1915
+ * @param optional Integer $index
1916
+ * @return String
1917
+ * @access private
1918
+ */
1919
+ function _string_shift(&$string, $index = 1)
1920
+ {
1921
+ $substr = substr($string, 0, $index);
1922
+ $string = substr($string, $index);
1923
+ return $substr;
1924
+ }
1925
+
1926
+ /**
1927
+ * Determines the private key format
1928
+ *
1929
+ * @see createKey()
1930
+ * @access public
1931
+ * @param Integer $format
1932
+ */
1933
+ function setPrivateKeyFormat($format)
1934
+ {
1935
+ $this->privateKeyFormat = $format;
1936
+ }
1937
+
1938
+ /**
1939
+ * Determines the public key format
1940
+ *
1941
+ * @see createKey()
1942
+ * @access public
1943
+ * @param Integer $format
1944
+ */
1945
+ function setPublicKeyFormat($format)
1946
+ {
1947
+ $this->publicKeyFormat = $format;
1948
+ }
1949
+
1950
+ /**
1951
+ * Determines which hashing function should be used
1952
+ *
1953
+ * Used with signature production / verification and (if the encryption mode is CRYPT_RSA_ENCRYPTION_OAEP) encryption and
1954
+ * decryption. If $hash isn't supported, sha1 is used.
1955
+ *
1956
+ * @access public
1957
+ * @param String $hash
1958
+ */
1959
+ function setHash($hash)
1960
+ {
1961
+ // Crypt_Hash supports algorithms that PKCS#1 doesn't support. md5-96 and sha1-96, for example.
1962
+ switch ($hash) {
1963
+ case 'md2':
1964
+ case 'md5':
1965
+ case 'sha1':
1966
+ case 'sha256':
1967
+ case 'sha384':
1968
+ case 'sha512':
1969
+ $this->hash = new Crypt_Hash($hash);
1970
+ $this->hashName = $hash;
1971
+ break;
1972
+ default:
1973
+ $this->hash = new Crypt_Hash('sha1');
1974
+ $this->hashName = 'sha1';
1975
+ }
1976
+ $this->hLen = $this->hash->getLength();
1977
+ }
1978
+
1979
+ /**
1980
+ * Determines which hashing function should be used for the mask generation function
1981
+ *
1982
+ * The mask generation function is used by CRYPT_RSA_ENCRYPTION_OAEP and CRYPT_RSA_SIGNATURE_PSS and although it's
1983
+ * best if Hash and MGFHash are set to the same thing this is not a requirement.
1984
+ *
1985
+ * @access public
1986
+ * @param String $hash
1987
+ */
1988
+ function setMGFHash($hash)
1989
+ {
1990
+ // Crypt_Hash supports algorithms that PKCS#1 doesn't support. md5-96 and sha1-96, for example.
1991
+ switch ($hash) {
1992
+ case 'md2':
1993
+ case 'md5':
1994
+ case 'sha1':
1995
+ case 'sha256':
1996
+ case 'sha384':
1997
+ case 'sha512':
1998
+ $this->mgfHash = new Crypt_Hash($hash);
1999
+ break;
2000
+ default:
2001
+ $this->mgfHash = new Crypt_Hash('sha1');
2002
+ }
2003
+ $this->mgfHLen = $this->mgfHash->getLength();
2004
+ }
2005
+
2006
+ /**
2007
+ * Determines the salt length
2008
+ *
2009
+ * To quote from {@link http://tools.ietf.org/html/rfc3447#page-38 RFC3447#page-38}:
2010
+ *
2011
+ * Typical salt lengths in octets are hLen (the length of the output
2012
+ * of the hash function Hash) and 0.
2013
+ *
2014
+ * @access public
2015
+ * @param Integer $format
2016
+ */
2017
+ function setSaltLength($sLen)
2018
+ {
2019
+ $this->sLen = $sLen;
2020
+ }
2021
+
2022
+ /**
2023
+ * Integer-to-Octet-String primitive
2024
+ *
2025
+ * See {@link http://tools.ietf.org/html/rfc3447#section-4.1 RFC3447#section-4.1}.
2026
+ *
2027
+ * @access private
2028
+ * @param Math_BigInteger $x
2029
+ * @param Integer $xLen
2030
+ * @return String
2031
+ */
2032
+ function _i2osp($x, $xLen)
2033
+ {
2034
+ $x = $x->toBytes();
2035
+ if (strlen($x) > $xLen) {
2036
+ user_error('Integer too large');
2037
+ return false;
2038
+ }
2039
+ return str_pad($x, $xLen, chr(0), STR_PAD_LEFT);
2040
+ }
2041
+
2042
+ /**
2043
+ * Octet-String-to-Integer primitive
2044
+ *
2045
+ * See {@link http://tools.ietf.org/html/rfc3447#section-4.2 RFC3447#section-4.2}.
2046
+ *
2047
+ * @access private
2048
+ * @param String $x
2049
+ * @return Math_BigInteger
2050
+ */
2051
+ function _os2ip($x)
2052
+ {
2053
+ return new Math_BigInteger($x, 256);
2054
+ }
2055
+
2056
+ /**
2057
+ * Exponentiate with or without Chinese Remainder Theorem
2058
+ *
2059
+ * See {@link http://tools.ietf.org/html/rfc3447#section-5.1.1 RFC3447#section-5.1.2}.
2060
+ *
2061
+ * @access private
2062
+ * @param Math_BigInteger $x
2063
+ * @return Math_BigInteger
2064
+ */
2065
+ function _exponentiate($x)
2066
+ {
2067
+ if (empty($this->primes) || empty($this->coefficients) || empty($this->exponents)) {
2068
+ return $x->modPow($this->exponent, $this->modulus);
2069
+ }
2070
+
2071
+ $num_primes = count($this->primes);
2072
+
2073
+ if (defined('CRYPT_RSA_DISABLE_BLINDING')) {
2074
+ $m_i = array(
2075
+ 1 => $x->modPow($this->exponents[1], $this->primes[1]),
2076
+ 2 => $x->modPow($this->exponents[2], $this->primes[2])
2077
+ );
2078
+ $h = $m_i[1]->subtract($m_i[2]);
2079
+ $h = $h->multiply($this->coefficients[2]);
2080
+ list(, $h) = $h->divide($this->primes[1]);
2081
+ $m = $m_i[2]->add($h->multiply($this->primes[2]));
2082
+
2083
+ $r = $this->primes[1];
2084
+ for ($i = 3; $i <= $num_primes; $i++) {
2085
+ $m_i = $x->modPow($this->exponents[$i], $this->primes[$i]);
2086
+
2087
+ $r = $r->multiply($this->primes[$i - 1]);
2088
+
2089
+ $h = $m_i->subtract($m);
2090
+ $h = $h->multiply($this->coefficients[$i]);
2091
+ list(, $h) = $h->divide($this->primes[$i]);
2092
+
2093
+ $m = $m->add($r->multiply($h));
2094
+ }
2095
+ } else {
2096
+ $smallest = $this->primes[1];
2097
+ for ($i = 2; $i <= $num_primes; $i++) {
2098
+ if ($smallest->compare($this->primes[$i]) > 0) {
2099
+ $smallest = $this->primes[$i];
2100
+ }
2101
+ }
2102
+
2103
+ $one = new Math_BigInteger(1);
2104
+
2105
+ $r = $one->random($one, $smallest->subtract($one));
2106
+
2107
+ $m_i = array(
2108
+ 1 => $this->_blind($x, $r, 1),
2109
+ 2 => $this->_blind($x, $r, 2)
2110
+ );
2111
+ $h = $m_i[1]->subtract($m_i[2]);
2112
+ $h = $h->multiply($this->coefficients[2]);
2113
+ list(, $h) = $h->divide($this->primes[1]);
2114
+ $m = $m_i[2]->add($h->multiply($this->primes[2]));
2115
+
2116
+ $r = $this->primes[1];
2117
+ for ($i = 3; $i <= $num_primes; $i++) {
2118
+ $m_i = $this->_blind($x, $r, $i);
2119
+
2120
+ $r = $r->multiply($this->primes[$i - 1]);
2121
+
2122
+ $h = $m_i->subtract($m);
2123
+ $h = $h->multiply($this->coefficients[$i]);
2124
+ list(, $h) = $h->divide($this->primes[$i]);
2125
+
2126
+ $m = $m->add($r->multiply($h));
2127
+ }
2128
+ }
2129
+
2130
+ return $m;
2131
+ }
2132
+
2133
+ /**
2134
+ * Performs RSA Blinding
2135
+ *
2136
+ * Protects against timing attacks by employing RSA Blinding.
2137
+ * Returns $x->modPow($this->exponents[$i], $this->primes[$i])
2138
+ *
2139
+ * @access private
2140
+ * @param Math_BigInteger $x
2141
+ * @param Math_BigInteger $r
2142
+ * @param Integer $i
2143
+ * @return Math_BigInteger
2144
+ */
2145
+ function _blind($x, $r, $i)
2146
+ {
2147
+ $x = $x->multiply($r->modPow($this->publicExponent, $this->primes[$i]));
2148
+ $x = $x->modPow($this->exponents[$i], $this->primes[$i]);
2149
+
2150
+ $r = $r->modInverse($this->primes[$i]);
2151
+ $x = $x->multiply($r);
2152
+ list(, $x) = $x->divide($this->primes[$i]);
2153
+
2154
+ return $x;
2155
+ }
2156
+
2157
+ /**
2158
+ * Performs blinded RSA equality testing
2159
+ *
2160
+ * Protects against a particular type of timing attack described.
2161
+ *
2162
+ * See {@link http://codahale.com/a-lesson-in-timing-attacks/ A Lesson In Timing Attacks (or, Don't use MessageDigest.isEquals)}
2163
+ *
2164
+ * Thanks for the heads up singpolyma!
2165
+ *
2166
+ * @access private
2167
+ * @param String $x
2168
+ * @param String $y
2169
+ * @return Boolean
2170
+ */
2171
+ function _equals($x, $y)
2172
+ {
2173
+ if (strlen($x) != strlen($y)) {
2174
+ return false;
2175
+ }
2176
+
2177
+ $result = 0;
2178
+ for ($i = 0; $i < strlen($x); $i++) {
2179
+ $result |= ord($x[$i]) ^ ord($y[$i]);
2180
+ }
2181
+
2182
+ return $result == 0;
2183
+ }
2184
+
2185
+ /**
2186
+ * RSAEP
2187
+ *
2188
+ * See {@link http://tools.ietf.org/html/rfc3447#section-5.1.1 RFC3447#section-5.1.1}.
2189
+ *
2190
+ * @access private
2191
+ * @param Math_BigInteger $m
2192
+ * @return Math_BigInteger
2193
+ */
2194
+ function _rsaep($m)
2195
+ {
2196
+ if ($m->compare($this->zero) < 0 || $m->compare($this->modulus) > 0) {
2197
+ user_error('Message representative out of range');
2198
+ return false;
2199
+ }
2200
+ return $this->_exponentiate($m);
2201
+ }
2202
+
2203
+ /**
2204
+ * RSADP
2205
+ *
2206
+ * See {@link http://tools.ietf.org/html/rfc3447#section-5.1.2 RFC3447#section-5.1.2}.
2207
+ *
2208
+ * @access private
2209
+ * @param Math_BigInteger $c
2210
+ * @return Math_BigInteger
2211
+ */
2212
+ function _rsadp($c)
2213
+ {
2214
+ if ($c->compare($this->zero) < 0 || $c->compare($this->modulus) > 0) {
2215
+ user_error('Ciphertext representative out of range');
2216
+ return false;
2217
+ }
2218
+ return $this->_exponentiate($c);
2219
+ }
2220
+
2221
+ /**
2222
+ * RSASP1
2223
+ *
2224
+ * See {@link http://tools.ietf.org/html/rfc3447#section-5.2.1 RFC3447#section-5.2.1}.
2225
+ *
2226
+ * @access private
2227
+ * @param Math_BigInteger $m
2228
+ * @return Math_BigInteger
2229
+ */
2230
+ function _rsasp1($m)
2231
+ {
2232
+ if ($m->compare($this->zero) < 0 || $m->compare($this->modulus) > 0) {
2233
+ user_error('Message representative out of range');
2234
+ return false;
2235
+ }
2236
+ return $this->_exponentiate($m);
2237
+ }
2238
+
2239
+ /**
2240
+ * RSAVP1
2241
+ *
2242
+ * See {@link http://tools.ietf.org/html/rfc3447#section-5.2.2 RFC3447#section-5.2.2}.
2243
+ *
2244
+ * @access private
2245
+ * @param Math_BigInteger $s
2246
+ * @return Math_BigInteger
2247
+ */
2248
+ function _rsavp1($s)
2249
+ {
2250
+ if ($s->compare($this->zero) < 0 || $s->compare($this->modulus) > 0) {
2251
+ user_error('Signature representative out of range');
2252
+ return false;
2253
+ }
2254
+ return $this->_exponentiate($s);
2255
+ }
2256
+
2257
+ /**
2258
+ * MGF1
2259
+ *
2260
+ * See {@link http://tools.ietf.org/html/rfc3447#appendix-B.2.1 RFC3447#appendix-B.2.1}.
2261
+ *
2262
+ * @access private
2263
+ * @param String $mgfSeed
2264
+ * @param Integer $mgfLen
2265
+ * @return String
2266
+ */
2267
+ function _mgf1($mgfSeed, $maskLen)
2268
+ {
2269
+ // if $maskLen would yield strings larger than 4GB, PKCS#1 suggests a "Mask too long" error be output.
2270
+
2271
+ $t = '';
2272
+ $count = ceil($maskLen / $this->mgfHLen);
2273
+ for ($i = 0; $i < $count; $i++) {
2274
+ $c = pack('N', $i);
2275
+ $t.= $this->mgfHash->hash($mgfSeed . $c);
2276
+ }
2277
+
2278
+ return substr($t, 0, $maskLen);
2279
+ }
2280
+
2281
+ /**
2282
+ * RSAES-OAEP-ENCRYPT
2283
+ *
2284
+ * See {@link http://tools.ietf.org/html/rfc3447#section-7.1.1 RFC3447#section-7.1.1} and
2285
+ * {http://en.wikipedia.org/wiki/Optimal_Asymmetric_Encryption_Padding OAES}.
2286
+ *
2287
+ * @access private
2288
+ * @param String $m
2289
+ * @param String $l
2290
+ * @return String
2291
+ */
2292
+ function _rsaes_oaep_encrypt($m, $l = '')
2293
+ {
2294
+ $mLen = strlen($m);
2295
+
2296
+ // Length checking
2297
+
2298
+ // if $l is larger than two million terrabytes and you're using sha1, PKCS#1 suggests a "Label too long" error
2299
+ // be output.
2300
+
2301
+ if ($mLen > $this->k - 2 * $this->hLen - 2) {
2302
+ user_error('Message too long');
2303
+ return false;
2304
+ }
2305
+
2306
+ // EME-OAEP encoding
2307
+
2308
+ $lHash = $this->hash->hash($l);
2309
+ $ps = str_repeat(chr(0), $this->k - $mLen - 2 * $this->hLen - 2);
2310
+ $db = $lHash . $ps . chr(1) . $m;
2311
+ $seed = crypt_random_string($this->hLen);
2312
+ $dbMask = $this->_mgf1($seed, $this->k - $this->hLen - 1);
2313
+ $maskedDB = $db ^ $dbMask;
2314
+ $seedMask = $this->_mgf1($maskedDB, $this->hLen);
2315
+ $maskedSeed = $seed ^ $seedMask;
2316
+ $em = chr(0) . $maskedSeed . $maskedDB;
2317
+
2318
+ // RSA encryption
2319
+
2320
+ $m = $this->_os2ip($em);
2321
+ $c = $this->_rsaep($m);
2322
+ $c = $this->_i2osp($c, $this->k);
2323
+
2324
+ // Output the ciphertext C
2325
+
2326
+ return $c;
2327
+ }
2328
+
2329
+ /**
2330
+ * RSAES-OAEP-DECRYPT
2331
+ *
2332
+ * See {@link http://tools.ietf.org/html/rfc3447#section-7.1.2 RFC3447#section-7.1.2}. The fact that the error
2333
+ * messages aren't distinguishable from one another hinders debugging, but, to quote from RFC3447#section-7.1.2:
2334
+ *
2335
+ * Note. Care must be taken to ensure that an opponent cannot
2336
+ * distinguish the different error conditions in Step 3.g, whether by
2337
+ * error message or timing, or, more generally, learn partial
2338
+ * information about the encoded message EM. Otherwise an opponent may
2339
+ * be able to obtain useful information about the decryption of the
2340
+ * ciphertext C, leading to a chosen-ciphertext attack such as the one
2341
+ * observed by Manger [36].
2342
+ *
2343
+ * As for $l... to quote from {@link http://tools.ietf.org/html/rfc3447#page-17 RFC3447#page-17}:
2344
+ *
2345
+ * Both the encryption and the decryption operations of RSAES-OAEP take
2346
+ * the value of a label L as input. In this version of PKCS #1, L is
2347
+ * the empty string; other uses of the label are outside the scope of
2348
+ * this document.
2349
+ *
2350
+ * @access private
2351
+ * @param String $c
2352
+ * @param String $l
2353
+ * @return String
2354
+ */
2355
+ function _rsaes_oaep_decrypt($c, $l = '')
2356
+ {
2357
+ // Length checking
2358
+
2359
+ // if $l is larger than two million terrabytes and you're using sha1, PKCS#1 suggests a "Label too long" error
2360
+ // be output.
2361
+
2362
+ if (strlen($c) != $this->k || $this->k < 2 * $this->hLen + 2) {
2363
+ user_error('Decryption error');
2364
+ return false;
2365
+ }
2366
+
2367
+ // RSA decryption
2368
+
2369
+ $c = $this->_os2ip($c);
2370
+ $m = $this->_rsadp($c);
2371
+ if ($m === false) {
2372
+ user_error('Decryption error');
2373
+ return false;
2374
+ }
2375
+ $em = $this->_i2osp($m, $this->k);
2376
+
2377
+ // EME-OAEP decoding
2378
+
2379
+ $lHash = $this->hash->hash($l);
2380
+ $y = ord($em[0]);
2381
+ $maskedSeed = substr($em, 1, $this->hLen);
2382
+ $maskedDB = substr($em, $this->hLen + 1);
2383
+ $seedMask = $this->_mgf1($maskedDB, $this->hLen);
2384
+ $seed = $maskedSeed ^ $seedMask;
2385
+ $dbMask = $this->_mgf1($seed, $this->k - $this->hLen - 1);
2386
+ $db = $maskedDB ^ $dbMask;
2387
+ $lHash2 = substr($db, 0, $this->hLen);
2388
+ $m = substr($db, $this->hLen);
2389
+ if ($lHash != $lHash2) {
2390
+ user_error('Decryption error');
2391
+ return false;
2392
+ }
2393
+ $m = ltrim($m, chr(0));
2394
+ if (ord($m[0]) != 1) {
2395
+ user_error('Decryption error');
2396
+ return false;
2397
+ }
2398
+
2399
+ // Output the message M
2400
+
2401
+ return substr($m, 1);
2402
+ }
2403
+
2404
+ /**
2405
+ * RSAES-PKCS1-V1_5-ENCRYPT
2406
+ *
2407
+ * See {@link http://tools.ietf.org/html/rfc3447#section-7.2.1 RFC3447#section-7.2.1}.
2408
+ *
2409
+ * @access private
2410
+ * @param String $m
2411
+ * @return String
2412
+ */
2413
+ function _rsaes_pkcs1_v1_5_encrypt($m)
2414
+ {
2415
+ $mLen = strlen($m);
2416
+
2417
+ // Length checking
2418
+
2419
+ if ($mLen > $this->k - 11) {
2420
+ user_error('Message too long');
2421
+ return false;
2422
+ }
2423
+
2424
+ // EME-PKCS1-v1_5 encoding
2425
+
2426
+ $psLen = $this->k - $mLen - 3;
2427
+ $ps = '';
2428
+ while (strlen($ps) != $psLen) {
2429
+ $temp = crypt_random_string($psLen - strlen($ps));
2430
+ $temp = str_replace("\x00", '', $temp);
2431
+ $ps.= $temp;
2432
+ }
2433
+ $type = 2;
2434
+ // see the comments of _rsaes_pkcs1_v1_5_decrypt() to understand why this is being done
2435
+ if (defined('CRYPT_RSA_PKCS15_COMPAT') && (!isset($this->publicExponent) || $this->exponent !== $this->publicExponent)) {
2436
+ $type = 1;
2437
+ // "The padding string PS shall consist of k-3-||D|| octets. ... for block type 01, they shall have value FF"
2438
+ $ps = str_repeat("\xFF", $psLen);
2439
+ }
2440
+ $em = chr(0) . chr($type) . $ps . chr(0) . $m;
2441
+
2442
+ // RSA encryption
2443
+ $m = $this->_os2ip($em);
2444
+ $c = $this->_rsaep($m);
2445
+ $c = $this->_i2osp($c, $this->k);
2446
+
2447
+ // Output the ciphertext C
2448
+
2449
+ return $c;
2450
+ }
2451
+
2452
+ /**
2453
+ * RSAES-PKCS1-V1_5-DECRYPT
2454
+ *
2455
+ * See {@link http://tools.ietf.org/html/rfc3447#section-7.2.2 RFC3447#section-7.2.2}.
2456
+ *
2457
+ * For compatibility purposes, this function departs slightly from the description given in RFC3447.
2458
+ * The reason being that RFC2313#section-8.1 (PKCS#1 v1.5) states that ciphertext's encrypted by the
2459
+ * private key should have the second byte set to either 0 or 1 and that ciphertext's encrypted by the
2460
+ * public key should have the second byte set to 2. In RFC3447 (PKCS#1 v2.1), the second byte is supposed
2461
+ * to be 2 regardless of which key is used. For compatibility purposes, we'll just check to make sure the
2462
+ * second byte is 2 or less. If it is, we'll accept the decrypted string as valid.
2463
+ *
2464
+ * As a consequence of this, a private key encrypted ciphertext produced with Crypt_RSA may not decrypt
2465
+ * with a strictly PKCS#1 v1.5 compliant RSA implementation. Public key encrypted ciphertext's should but
2466
+ * not private key encrypted ciphertext's.
2467
+ *
2468
+ * @access private
2469
+ * @param String $c
2470
+ * @return String
2471
+ */
2472
+ function _rsaes_pkcs1_v1_5_decrypt($c)
2473
+ {
2474
+ // Length checking
2475
+
2476
+ if (strlen($c) != $this->k) { // or if k < 11
2477
+ user_error('Decryption error');
2478
+ return false;
2479
+ }
2480
+
2481
+ // RSA decryption
2482
+
2483
+ $c = $this->_os2ip($c);
2484
+ $m = $this->_rsadp($c);
2485
+
2486
+ if ($m === false) {
2487
+ user_error('Decryption error');
2488
+ return false;
2489
+ }
2490
+ $em = $this->_i2osp($m, $this->k);
2491
+
2492
+ // EME-PKCS1-v1_5 decoding
2493
+
2494
+ if (ord($em[0]) != 0 || ord($em[1]) > 2) {
2495
+ user_error('Decryption error');
2496
+ return false;
2497
+ }
2498
+
2499
+ $ps = substr($em, 2, strpos($em, chr(0), 2) - 2);
2500
+ $m = substr($em, strlen($ps) + 3);
2501
+
2502
+ if (strlen($ps) < 8) {
2503
+ user_error('Decryption error');
2504
+ return false;
2505
+ }
2506
+
2507
+ // Output M
2508
+
2509
+ return $m;
2510
+ }
2511
+
2512
+ /**
2513
+ * EMSA-PSS-ENCODE
2514
+ *
2515
+ * See {@link http://tools.ietf.org/html/rfc3447#section-9.1.1 RFC3447#section-9.1.1}.
2516
+ *
2517
+ * @access private
2518
+ * @param String $m
2519
+ * @param Integer $emBits
2520
+ */
2521
+ function _emsa_pss_encode($m, $emBits)
2522
+ {
2523
+ // if $m is larger than two million terrabytes and you're using sha1, PKCS#1 suggests a "Label too long" error
2524
+ // be output.
2525
+
2526
+ $emLen = ($emBits + 1) >> 3; // ie. ceil($emBits / 8)
2527
+ $sLen = $this->sLen == false ? $this->hLen : $this->sLen;
2528
+
2529
+ $mHash = $this->hash->hash($m);
2530
+ if ($emLen < $this->hLen + $sLen + 2) {
2531
+ user_error('Encoding error');
2532
+ return false;
2533
+ }
2534
+
2535
+ $salt = crypt_random_string($sLen);
2536
+ $m2 = "\0\0\0\0\0\0\0\0" . $mHash . $salt;
2537
+ $h = $this->hash->hash($m2);
2538
+ $ps = str_repeat(chr(0), $emLen - $sLen - $this->hLen - 2);
2539
+ $db = $ps . chr(1) . $salt;
2540
+ $dbMask = $this->_mgf1($h, $emLen - $this->hLen - 1);
2541
+ $maskedDB = $db ^ $dbMask;
2542
+ $maskedDB[0] = ~chr(0xFF << ($emBits & 7)) & $maskedDB[0];
2543
+ $em = $maskedDB . $h . chr(0xBC);
2544
+
2545
+ return $em;
2546
+ }
2547
+
2548
+ /**
2549
+ * EMSA-PSS-VERIFY
2550
+ *
2551
+ * See {@link http://tools.ietf.org/html/rfc3447#section-9.1.2 RFC3447#section-9.1.2}.
2552
+ *
2553
+ * @access private
2554
+ * @param String $m
2555
+ * @param String $em
2556
+ * @param Integer $emBits
2557
+ * @return String
2558
+ */
2559
+ function _emsa_pss_verify($m, $em, $emBits)
2560
+ {
2561
+ // if $m is larger than two million terrabytes and you're using sha1, PKCS#1 suggests a "Label too long" error
2562
+ // be output.
2563
+
2564
+ $emLen = ($emBits + 1) >> 3; // ie. ceil($emBits / 8);
2565
+ $sLen = $this->sLen == false ? $this->hLen : $this->sLen;
2566
+
2567
+ $mHash = $this->hash->hash($m);
2568
+ if ($emLen < $this->hLen + $sLen + 2) {
2569
+ return false;
2570
+ }
2571
+
2572
+ if ($em[strlen($em) - 1] != chr(0xBC)) {
2573
+ return false;
2574
+ }
2575
+
2576
+ $maskedDB = substr($em, 0, -$this->hLen - 1);
2577
+ $h = substr($em, -$this->hLen - 1, $this->hLen);
2578
+ $temp = chr(0xFF << ($emBits & 7));
2579
+ if ((~$maskedDB[0] & $temp) != $temp) {
2580
+ return false;
2581
+ }
2582
+ $dbMask = $this->_mgf1($h, $emLen - $this->hLen - 1);
2583
+ $db = $maskedDB ^ $dbMask;
2584
+ $db[0] = ~chr(0xFF << ($emBits & 7)) & $db[0];
2585
+ $temp = $emLen - $this->hLen - $sLen - 2;
2586
+ if (substr($db, 0, $temp) != str_repeat(chr(0), $temp) || ord($db[$temp]) != 1) {
2587
+ return false;
2588
+ }
2589
+ $salt = substr($db, $temp + 1); // should be $sLen long
2590
+ $m2 = "\0\0\0\0\0\0\0\0" . $mHash . $salt;
2591
+ $h2 = $this->hash->hash($m2);
2592
+ return $this->_equals($h, $h2);
2593
+ }
2594
+
2595
+ /**
2596
+ * RSASSA-PSS-SIGN
2597
+ *
2598
+ * See {@link http://tools.ietf.org/html/rfc3447#section-8.1.1 RFC3447#section-8.1.1}.
2599
+ *
2600
+ * @access private
2601
+ * @param String $m
2602
+ * @return String
2603
+ */
2604
+ function _rsassa_pss_sign($m)
2605
+ {
2606
+ // EMSA-PSS encoding
2607
+
2608
+ $em = $this->_emsa_pss_encode($m, 8 * $this->k - 1);
2609
+
2610
+ // RSA signature
2611
+
2612
+ $m = $this->_os2ip($em);
2613
+ $s = $this->_rsasp1($m);
2614
+ $s = $this->_i2osp($s, $this->k);
2615
+
2616
+ // Output the signature S
2617
+
2618
+ return $s;
2619
+ }
2620
+
2621
+ /**
2622
+ * RSASSA-PSS-VERIFY
2623
+ *
2624
+ * See {@link http://tools.ietf.org/html/rfc3447#section-8.1.2 RFC3447#section-8.1.2}.
2625
+ *
2626
+ * @access private
2627
+ * @param String $m
2628
+ * @param String $s
2629
+ * @return String
2630
+ */
2631
+ function _rsassa_pss_verify($m, $s)
2632
+ {
2633
+ // Length checking
2634
+
2635
+ if (strlen($s) != $this->k) {
2636
+ user_error('Invalid signature');
2637
+ return false;
2638
+ }
2639
+
2640
+ // RSA verification
2641
+
2642
+ $modBits = 8 * $this->k;
2643
+
2644
+ $s2 = $this->_os2ip($s);
2645
+ $m2 = $this->_rsavp1($s2);
2646
+ if ($m2 === false) {
2647
+ user_error('Invalid signature');
2648
+ return false;
2649
+ }
2650
+ $em = $this->_i2osp($m2, $modBits >> 3);
2651
+ if ($em === false) {
2652
+ user_error('Invalid signature');
2653
+ return false;
2654
+ }
2655
+
2656
+ // EMSA-PSS verification
2657
+
2658
+ return $this->_emsa_pss_verify($m, $em, $modBits - 1);
2659
+ }
2660
+
2661
+ /**
2662
+ * EMSA-PKCS1-V1_5-ENCODE
2663
+ *
2664
+ * See {@link http://tools.ietf.org/html/rfc3447#section-9.2 RFC3447#section-9.2}.
2665
+ *
2666
+ * @access private
2667
+ * @param String $m
2668
+ * @param Integer $emLen
2669
+ * @return String
2670
+ */
2671
+ function _emsa_pkcs1_v1_5_encode($m, $emLen)
2672
+ {
2673
+ $h = $this->hash->hash($m);
2674
+ if ($h === false) {
2675
+ return false;
2676
+ }
2677
+
2678
+ // see http://tools.ietf.org/html/rfc3447#page-43
2679
+ switch ($this->hashName) {
2680
+ case 'md2':
2681
+ $t = pack('H*', '3020300c06082a864886f70d020205000410');
2682
+ break;
2683
+ case 'md5':
2684
+ $t = pack('H*', '3020300c06082a864886f70d020505000410');
2685
+ break;
2686
+ case 'sha1':
2687
+ $t = pack('H*', '3021300906052b0e03021a05000414');
2688
+ break;
2689
+ case 'sha256':
2690
+ $t = pack('H*', '3031300d060960864801650304020105000420');
2691
+ break;
2692
+ case 'sha384':
2693
+ $t = pack('H*', '3041300d060960864801650304020205000430');
2694
+ break;
2695
+ case 'sha512':
2696
+ $t = pack('H*', '3051300d060960864801650304020305000440');
2697
+ }
2698
+ $t.= $h;
2699
+ $tLen = strlen($t);
2700
+
2701
+ if ($emLen < $tLen + 11) {
2702
+ user_error('Intended encoded message length too short');
2703
+ return false;
2704
+ }
2705
+
2706
+ $ps = str_repeat(chr(0xFF), $emLen - $tLen - 3);
2707
+
2708
+ $em = "\0\1$ps\0$t";
2709
+
2710
+ return $em;
2711
+ }
2712
+
2713
+ /**
2714
+ * RSASSA-PKCS1-V1_5-SIGN
2715
+ *
2716
+ * See {@link http://tools.ietf.org/html/rfc3447#section-8.2.1 RFC3447#section-8.2.1}.
2717
+ *
2718
+ * @access private
2719
+ * @param String $m
2720
+ * @return String
2721
+ */
2722
+ function _rsassa_pkcs1_v1_5_sign($m)
2723
+ {
2724
+ // EMSA-PKCS1-v1_5 encoding
2725
+
2726
+ $em = $this->_emsa_pkcs1_v1_5_encode($m, $this->k);
2727
+ if ($em === false) {
2728
+ user_error('RSA modulus too short');
2729
+ return false;
2730
+ }
2731
+
2732
+ // RSA signature
2733
+
2734
+ $m = $this->_os2ip($em);
2735
+ $s = $this->_rsasp1($m);
2736
+ $s = $this->_i2osp($s, $this->k);
2737
+
2738
+ // Output the signature S
2739
+
2740
+ return $s;
2741
+ }
2742
+
2743
+ /**
2744
+ * RSASSA-PKCS1-V1_5-VERIFY
2745
+ *
2746
+ * See {@link http://tools.ietf.org/html/rfc3447#section-8.2.2 RFC3447#section-8.2.2}.
2747
+ *
2748
+ * @access private
2749
+ * @param String $m
2750
+ * @return String
2751
+ */
2752
+ function _rsassa_pkcs1_v1_5_verify($m, $s)
2753
+ {
2754
+ // Length checking
2755
+
2756
+ if (strlen($s) != $this->k) {
2757
+ user_error('Invalid signature');
2758
+ return false;
2759
+ }
2760
+
2761
+ // RSA verification
2762
+
2763
+ $s = $this->_os2ip($s);
2764
+ $m2 = $this->_rsavp1($s);
2765
+ if ($m2 === false) {
2766
+ user_error('Invalid signature');
2767
+ return false;
2768
+ }
2769
+ $em = $this->_i2osp($m2, $this->k);
2770
+ if ($em === false) {
2771
+ user_error('Invalid signature');
2772
+ return false;
2773
+ }
2774
+
2775
+ // EMSA-PKCS1-v1_5 encoding
2776
+
2777
+ $em2 = $this->_emsa_pkcs1_v1_5_encode($m, $this->k);
2778
+ if ($em2 === false) {
2779
+ user_error('RSA modulus too short');
2780
+ return false;
2781
+ }
2782
+
2783
+ // Compare
2784
+ return $this->_equals($em, $em2);
2785
+ }
2786
+
2787
+ /**
2788
+ * Set Encryption Mode
2789
+ *
2790
+ * Valid values include CRYPT_RSA_ENCRYPTION_OAEP and CRYPT_RSA_ENCRYPTION_PKCS1.
2791
+ *
2792
+ * @access public
2793
+ * @param Integer $mode
2794
+ */
2795
+ function setEncryptionMode($mode)
2796
+ {
2797
+ $this->encryptionMode = $mode;
2798
+ }
2799
+
2800
+ /**
2801
+ * Set Signature Mode
2802
+ *
2803
+ * Valid values include CRYPT_RSA_SIGNATURE_PSS and CRYPT_RSA_SIGNATURE_PKCS1
2804
+ *
2805
+ * @access public
2806
+ * @param Integer $mode
2807
+ */
2808
+ function setSignatureMode($mode)
2809
+ {
2810
+ $this->signatureMode = $mode;
2811
+ }
2812
+
2813
+ /**
2814
+ * Set public key comment.
2815
+ *
2816
+ * @access public
2817
+ * @param String $comment
2818
+ */
2819
+ function setComment($comment)
2820
+ {
2821
+ $this->comment = $comment;
2822
+ }
2823
+
2824
+ /**
2825
+ * Get public key comment.
2826
+ *
2827
+ * @access public
2828
+ * @return String
2829
+ */
2830
+ function getComment()
2831
+ {
2832
+ return $this->comment;
2833
+ }
2834
+
2835
+ /**
2836
+ * Encryption
2837
+ *
2838
+ * Both CRYPT_RSA_ENCRYPTION_OAEP and CRYPT_RSA_ENCRYPTION_PKCS1 both place limits on how long $plaintext can be.
2839
+ * If $plaintext exceeds those limits it will be broken up so that it does and the resultant ciphertext's will
2840
+ * be concatenated together.
2841
+ *
2842
+ * @see decrypt()
2843
+ * @access public
2844
+ * @param String $plaintext
2845
+ * @return String
2846
+ */
2847
+ function encrypt($plaintext)
2848
+ {
2849
+ switch ($this->encryptionMode) {
2850
+ case CRYPT_RSA_ENCRYPTION_PKCS1:
2851
+ $length = $this->k - 11;
2852
+ if ($length <= 0) {
2853
+ return false;
2854
+ }
2855
+
2856
+ $plaintext = str_split($plaintext, $length);
2857
+ $ciphertext = '';
2858
+ foreach ($plaintext as $m) {
2859
+ $ciphertext.= $this->_rsaes_pkcs1_v1_5_encrypt($m);
2860
+ }
2861
+ return $ciphertext;
2862
+ //case CRYPT_RSA_ENCRYPTION_OAEP:
2863
+ default:
2864
+ $length = $this->k - 2 * $this->hLen - 2;
2865
+ if ($length <= 0) {
2866
+ return false;
2867
+ }
2868
+
2869
+ $plaintext = str_split($plaintext, $length);
2870
+ $ciphertext = '';
2871
+ foreach ($plaintext as $m) {
2872
+ $ciphertext.= $this->_rsaes_oaep_encrypt($m);
2873
+ }
2874
+ return $ciphertext;
2875
+ }
2876
+ }
2877
+
2878
+ /**
2879
+ * Decryption
2880
+ *
2881
+ * @see encrypt()
2882
+ * @access public
2883
+ * @param String $plaintext
2884
+ * @return String
2885
+ */
2886
+ function decrypt($ciphertext)
2887
+ {
2888
+ if ($this->k <= 0) {
2889
+ return false;
2890
+ }
2891
+
2892
+ $ciphertext = str_split($ciphertext, $this->k);
2893
+ $ciphertext[count($ciphertext) - 1] = str_pad($ciphertext[count($ciphertext) - 1], $this->k, chr(0), STR_PAD_LEFT);
2894
+
2895
+ $plaintext = '';
2896
+
2897
+ switch ($this->encryptionMode) {
2898
+ case CRYPT_RSA_ENCRYPTION_PKCS1:
2899
+ $decrypt = '_rsaes_pkcs1_v1_5_decrypt';
2900
+ break;
2901
+ //case CRYPT_RSA_ENCRYPTION_OAEP:
2902
+ default:
2903
+ $decrypt = '_rsaes_oaep_decrypt';
2904
+ }
2905
+
2906
+ foreach ($ciphertext as $c) {
2907
+ $temp = $this->$decrypt($c);
2908
+ if ($temp === false) {
2909
+ return false;
2910
+ }
2911
+ $plaintext.= $temp;
2912
+ }
2913
+
2914
+ return $plaintext;
2915
+ }
2916
+
2917
+ /**
2918
+ * Create a signature
2919
+ *
2920
+ * @see verify()
2921
+ * @access public
2922
+ * @param String $message
2923
+ * @return String
2924
+ */
2925
+ function sign($message)
2926
+ {
2927
+ if (empty($this->modulus) || empty($this->exponent)) {
2928
+ return false;
2929
+ }
2930
+
2931
+ switch ($this->signatureMode) {
2932
+ case CRYPT_RSA_SIGNATURE_PKCS1:
2933
+ return $this->_rsassa_pkcs1_v1_5_sign($message);
2934
+ //case CRYPT_RSA_SIGNATURE_PSS:
2935
+ default:
2936
+ return $this->_rsassa_pss_sign($message);
2937
+ }
2938
+ }
2939
+
2940
+ /**
2941
+ * Verifies a signature
2942
+ *
2943
+ * @see sign()
2944
+ * @access public
2945
+ * @param String $message
2946
+ * @param String $signature
2947
+ * @return Boolean
2948
+ */
2949
+ function verify($message, $signature)
2950
+ {
2951
+ if (empty($this->modulus) || empty($this->exponent)) {
2952
+ return false;
2953
+ }
2954
+
2955
+ switch ($this->signatureMode) {
2956
+ case CRYPT_RSA_SIGNATURE_PKCS1:
2957
+ return $this->_rsassa_pkcs1_v1_5_verify($message, $signature);
2958
+ //case CRYPT_RSA_SIGNATURE_PSS:
2959
+ default:
2960
+ return $this->_rsassa_pss_verify($message, $signature);
2961
+ }
2962
+ }
2963
+
2964
+ /**
2965
+ * Extract raw BER from Base64 encoding
2966
+ *
2967
+ * @access private
2968
+ * @param String $str
2969
+ * @return String
2970
+ */
2971
+ function _extractBER($str)
2972
+ {
2973
+ /* X.509 certs are assumed to be base64 encoded but sometimes they'll have additional things in them
2974
+ * above and beyond the ceritificate.
2975
+ * ie. some may have the following preceding the -----BEGIN CERTIFICATE----- line:
2976
+ *
2977
+ * Bag Attributes
2978
+ * localKeyID: 01 00 00 00
2979
+ * subject=/O=organization/OU=org unit/CN=common name
2980
+ * issuer=/O=organization/CN=common name
2981
+ */
2982
+ $temp = preg_replace('#.*?^-+[^-]+-+#ms', '', $str, 1);
2983
+ // remove the -----BEGIN CERTIFICATE----- and -----END CERTIFICATE----- stuff
2984
+ $temp = preg_replace('#-+[^-]+-+#', '', $temp);
2985
+ // remove new lines
2986
+ $temp = str_replace(array("\r", "\n", ' '), '', $temp);
2987
+ $temp = preg_match('#^[a-zA-Z\d/+]*={0,2}$#', $temp) ? base64_decode($temp) : false;
2988
+ return $temp != false ? $temp : $str;
2989
+ }
2990
+ }
phpseclib/Crypt/Random.php CHANGED
@@ -1,243 +1,300 @@
1
- <?php
2
- /* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
3
-
4
- /**
5
- * Random Number Generator
6
- *
7
- * PHP versions 4 and 5
8
- *
9
- * Here's a short example of how to use this library:
10
- * <code>
11
- * <?php
12
- * include('Crypt/Random.php');
13
- *
14
- * echo bin2hex(crypt_random_string(8));
15
- * ?>
16
- * </code>
17
- *
18
- * LICENSE: Permission is hereby granted, free of charge, to any person obtaining a copy
19
- * of this software and associated documentation files (the "Software"), to deal
20
- * in the Software without restriction, including without limitation the rights
21
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
22
- * copies of the Software, and to permit persons to whom the Software is
23
- * furnished to do so, subject to the following conditions:
24
- *
25
- * The above copyright notice and this permission notice shall be included in
26
- * all copies or substantial portions of the Software.
27
- *
28
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
29
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
30
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
31
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
32
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
33
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
34
- * THE SOFTWARE.
35
- *
36
- * @category Crypt
37
- * @package Crypt_Random
38
- * @author Jim Wigginton <terrafrost@php.net>
39
- * @copyright MMVII Jim Wigginton
40
- * @license http://www.opensource.org/licenses/mit-license.html MIT License
41
- * @version $Id: Random.php,v 1.9 2010/04/24 06:40:48 terrafrost Exp $
42
- * @link http://phpseclib.sourceforge.net
43
- */
44
-
45
- /**
46
- * Generate a random string.
47
- *
48
- * Although microoptimizations are generally discouraged as they impair readability this function is ripe with
49
- * microoptimizations because this function has the potential of being called a huge number of times.
50
- * eg. for RSA key generation.
51
- *
52
- * @param Integer $length
53
- * @return String
54
- * @access public
55
- */
56
- function crypt_random_string($length) {
57
- // PHP_OS & "\xDF\xDF\xDF" == strtoupper(substr(PHP_OS, 0, 3)), but a lot faster
58
- if ((PHP_OS & "\xDF\xDF\xDF") === 'WIN') {
59
- // method 1. prior to PHP 5.3 this would call rand() on windows hence the function_exists('class_alias') call.
60
- // ie. class_alias is a function that was introduced in PHP 5.3
61
- if (function_exists('mcrypt_create_iv') && function_exists('class_alias')) {
62
- return mcrypt_create_iv($length);
63
- }
64
- // method 2. openssl_random_pseudo_bytes was introduced in PHP 5.3.0 but prior to PHP 5.3.4 there was,
65
- // to quote <http://php.net/ChangeLog-5.php#5.3.4>, "possible blocking behavior". as of 5.3.4
66
- // openssl_random_pseudo_bytes and mcrypt_create_iv do the exact same thing on Windows. ie. they both
67
- // call php_win32_get_random_bytes():
68
- //
69
- // https://github.com/php/php-src/blob/7014a0eb6d1611151a286c0ff4f2238f92c120d6/ext/openssl/openssl.c#L5008
70
- // https://github.com/php/php-src/blob/7014a0eb6d1611151a286c0ff4f2238f92c120d6/ext/mcrypt/mcrypt.c#L1392
71
- //
72
- // php_win32_get_random_bytes() is defined thusly:
73
- //
74
- // https://github.com/php/php-src/blob/7014a0eb6d1611151a286c0ff4f2238f92c120d6/win32/winutil.c#L80
75
- //
76
- // we're calling it, all the same, in the off chance that the mcrypt extension is not available
77
- if (function_exists('openssl_random_pseudo_bytes') && version_compare(PHP_VERSION, '5.3.4', '>=')) {
78
- return openssl_random_pseudo_bytes($length);
79
- }
80
- } else {
81
- // method 1. the fastest
82
- if (function_exists('openssl_random_pseudo_bytes')) {
83
- return openssl_random_pseudo_bytes($length);
84
- }
85
- // method 2
86
- static $fp = true;
87
- if ($fp === true) {
88
- // warning's will be output unles the error suppression operator is used. errors such as
89
- // "open_basedir restriction in effect", "Permission denied", "No such file or directory", etc.
90
- $fp = @fopen('/dev/urandom', 'rb');
91
- }
92
- if ($fp !== true && $fp !== false) { // surprisingly faster than !is_bool() or is_resource()
93
- return fread($fp, $length);
94
- }
95
- // method 3. pretty much does the same thing as method 2 per the following url:
96
- // https://github.com/php/php-src/blob/7014a0eb6d1611151a286c0ff4f2238f92c120d6/ext/mcrypt/mcrypt.c#L1391
97
- // surprisingly slower than method 2. maybe that's because mcrypt_create_iv does a bunch of error checking that we're
98
- // not doing. regardless, this'll only be called if this PHP script couldn't open /dev/urandom due to open_basedir
99
- // restrictions or some such
100
- if (function_exists('mcrypt_create_iv')) {
101
- return mcrypt_create_iv($length, MCRYPT_DEV_URANDOM);
102
- }
103
- }
104
- // at this point we have no choice but to use a pure-PHP CSPRNG
105
-
106
- // cascade entropy across multiple PHP instances by fixing the session and collecting all
107
- // environmental variables, including the previous session data and the current session
108
- // data.
109
- //
110
- // mt_rand seeds itself by looking at the PID and the time, both of which are (relatively)
111
- // easy to guess at. linux uses mouse clicks, keyboard timings, etc, as entropy sources, but
112
- // PHP isn't low level to be able to use those as sources and on a web server there's not likely
113
- // going to be a ton of keyboard or mouse action. web servers do have one thing that we can use
114
- // however. a ton of people visiting the website. obviously you don't want to base your seeding
115
- // soley on parameters a potential attacker sends but (1) not everything in $_SERVER is controlled
116
- // by the user and (2) this isn't just looking at the data sent by the current user - it's based
117
- // on the data sent by all users. one user requests the page and a hash of their info is saved.
118
- // another user visits the page and the serialization of their data is utilized along with the
119
- // server envirnment stuff and a hash of the previous http request data (which itself utilizes
120
- // a hash of the session data before that). certainly an attacker should be assumed to have
121
- // full control over his own http requests. he, however, is not going to have control over
122
- // everyone's http requests.
123
- static $crypto = false, $v;
124
- if ($crypto === false) {
125
- // save old session data
126
- $old_session_id = session_id();
127
- $old_use_cookies = ini_get('session.use_cookies');
128
- $old_session_cache_limiter = session_cache_limiter();
129
- if (isset($_SESSION)) {
130
- $_OLD_SESSION = $_SESSION;
131
- }
132
- if ($old_session_id != '') {
133
- session_write_close();
134
- }
135
-
136
- session_id(1);
137
- ini_set('session.use_cookies', 0);
138
- session_cache_limiter('');
139
- session_start();
140
-
141
- $v = $seed = $_SESSION['seed'] = pack('H*', sha1(
142
- serialize($_SERVER) .
143
- serialize($_POST) .
144
- serialize($_GET) .
145
- serialize($_COOKIE) .
146
- serialize($_GLOBAL) .
147
- serialize($_SESSION) .
148
- serialize($_OLD_SESSION)
149
- ));
150
- if (!isset($_SESSION['count'])) {
151
- $_SESSION['count'] = 0;
152
- }
153
- $_SESSION['count']++;
154
-
155
- session_write_close();
156
-
157
- // restore old session data
158
- if ($old_session_id != '') {
159
- session_id($old_session_id);
160
- session_start();
161
- ini_set('session.use_cookies', $old_use_cookies);
162
- session_cache_limiter($old_session_cache_limiter);
163
- } else {
164
- if (isset($_OLD_SESSION)) {
165
- $_SESSION = $_OLD_SESSION;
166
- unset($_OLD_SESSION);
167
- } else {
168
- unset($_SESSION);
169
- }
170
- }
171
-
172
- // in SSH2 a shared secret and an exchange hash are generated through the key exchange process.
173
- // the IV client to server is the hash of that "nonce" with the letter A and for the encryption key it's the letter C.
174
- // if the hash doesn't produce enough a key or an IV that's long enough concat successive hashes of the
175
- // original hash and the current hash. we'll be emulating that. for more info see the following URL:
176
- //
177
- // http://tools.ietf.org/html/rfc4253#section-7.2
178
- //
179
- // see the is_string($crypto) part for an example of how to expand the keys
180
- $key = pack('H*', sha1($seed . 'A'));
181
- $iv = pack('H*', sha1($seed . 'C'));
182
-
183
- // ciphers are used as per the nist.gov link below. also, see this link:
184
- //
185
- // http://en.wikipedia.org/wiki/Cryptographically_secure_pseudorandom_number_generator#Designs_based_on_cryptographic_primitives
186
- switch (true) {
187
- case class_exists('Crypt_AES'):
188
- $crypto = new Crypt_AES(CRYPT_AES_MODE_CTR);
189
- break;
190
- case class_exists('Crypt_TripleDES'):
191
- $crypto = new Crypt_TripleDES(CRYPT_DES_MODE_CTR);
192
- break;
193
- case class_exists('Crypt_DES'):
194
- $crypto = new Crypt_DES(CRYPT_DES_MODE_CTR);
195
- break;
196
- case class_exists('Crypt_RC4'):
197
- $crypto = new Crypt_RC4();
198
- break;
199
- default:
200
- $crypto = $seed;
201
- return crypt_random_string($length);
202
- }
203
-
204
- $crypto->setKey($key);
205
- $crypto->setIV($iv);
206
- $crypto->enableContinuousBuffer();
207
- }
208
-
209
- if (is_string($crypto)) {
210
- // the following is based off of ANSI X9.31:
211
- //
212
- // http://csrc.nist.gov/groups/STM/cavp/documents/rng/931rngext.pdf
213
- //
214
- // OpenSSL uses that same standard for it's random numbers:
215
- //
216
- // http://www.opensource.apple.com/source/OpenSSL/OpenSSL-38/openssl/fips-1.0/rand/fips_rand.c
217
- // (do a search for "ANS X9.31 A.2.4")
218
- //
219
- // ANSI X9.31 recommends ciphers be used and phpseclib does use them if they're available (see
220
- // later on in the code) but if they're not we'll use sha1
221
- $result = '';
222
- while (strlen($result) < $length) { // each loop adds 20 bytes
223
- // microtime() isn't packed as "densely" as it could be but then neither is that the idea.
224
- // the idea is simply to ensure that each "block" has a unique element to it.
225
- $i = pack('H*', sha1(microtime()));
226
- $r = pack('H*', sha1($i ^ $v));
227
- $v = pack('H*', sha1($r ^ $i));
228
- $result.= $r;
229
- }
230
- return substr($result, 0, $length);
231
- }
232
-
233
- //return $crypto->encrypt(str_repeat("\0", $length));
234
-
235
- $result = '';
236
- while (strlen($result) < $length) {
237
- $i = $crypto->encrypt(microtime());
238
- $r = $crypto->encrypt($i ^ $v);
239
- $v = $crypto->encrypt($r ^ $i);
240
- $result.= $r;
241
- }
242
- return substr($result, 0, $length);
243
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * Random Number Generator
5
+ *
6
+ * The idea behind this function is that it can be easily replaced with your own crypt_random_string()
7
+ * function. eg. maybe you have a better source of entropy for creating the initial states or whatever.
8
+ *
9
+ * PHP versions 4 and 5
10
+ *
11
+ * Here's a short example of how to use this library:
12
+ * <code>
13
+ * <?php
14
+ * include 'Crypt/Random.php';
15
+ *
16
+ * echo bin2hex(crypt_random_string(8));
17
+ * ?>
18
+ * </code>
19
+ *
20
+ * LICENSE: Permission is hereby granted, free of charge, to any person obtaining a copy
21
+ * of this software and associated documentation files (the "Software"), to deal
22
+ * in the Software without restriction, including without limitation the rights
23
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
24
+ * copies of the Software, and to permit persons to whom the Software is
25
+ * furnished to do so, subject to the following conditions:
26
+ *
27
+ * The above copyright notice and this permission notice shall be included in
28
+ * all copies or substantial portions of the Software.
29
+ *
30
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
31
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
32
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
33
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
34
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
35
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
36
+ * THE SOFTWARE.
37
+ *
38
+ * @category Crypt
39
+ * @package Crypt_Random
40
+ * @author Jim Wigginton <terrafrost@php.net>
41
+ * @copyright MMVII Jim Wigginton
42
+ * @license http://www.opensource.org/licenses/mit-license.html MIT License
43
+ * @link http://phpseclib.sourceforge.net
44
+ */
45
+
46
+ // laravel is a PHP framework that utilizes phpseclib. laravel workbenches may, independently,
47
+ // have phpseclib as a requirement as well. if you're developing such a program you may encounter
48
+ // a "Cannot redeclare crypt_random_string()" error.
49
+ if (!function_exists('crypt_random_string')) {
50
+ /**
51
+ * "Is Windows" test
52
+ *
53
+ * @access private
54
+ */
55
+ define('CRYPT_RANDOM_IS_WINDOWS', strtoupper(substr(PHP_OS, 0, 3)) === 'WIN');
56
+
57
+ /**
58
+ * Generate a random string.
59
+ *
60
+ * Although microoptimizations are generally discouraged as they impair readability this function is ripe with
61
+ * microoptimizations because this function has the potential of being called a huge number of times.
62
+ * eg. for RSA key generation.
63
+ *
64
+ * @param Integer $length
65
+ * @return String
66
+ * @access public
67
+ */
68
+ function crypt_random_string($length)
69
+ {
70
+ if (CRYPT_RANDOM_IS_WINDOWS) {
71
+ // method 1. prior to PHP 5.3 this would call rand() on windows hence the function_exists('class_alias') call.
72
+ // ie. class_alias is a function that was introduced in PHP 5.3
73
+ if (function_exists('mcrypt_create_iv') && function_exists('class_alias')) {
74
+ return mcrypt_create_iv($length);
75
+ }
76
+ // method 2. openssl_random_pseudo_bytes was introduced in PHP 5.3.0 but prior to PHP 5.3.4 there was,
77
+ // to quote <http://php.net/ChangeLog-5.php#5.3.4>, "possible blocking behavior". as of 5.3.4
78
+ // openssl_random_pseudo_bytes and mcrypt_create_iv do the exact same thing on Windows. ie. they both
79
+ // call php_win32_get_random_bytes():
80
+ //
81
+ // https://github.com/php/php-src/blob/7014a0eb6d1611151a286c0ff4f2238f92c120d6/ext/openssl/openssl.c#L5008
82
+ // https://github.com/php/php-src/blob/7014a0eb6d1611151a286c0ff4f2238f92c120d6/ext/mcrypt/mcrypt.c#L1392
83
+ //
84
+ // php_win32_get_random_bytes() is defined thusly:
85
+ //
86
+ // https://github.com/php/php-src/blob/7014a0eb6d1611151a286c0ff4f2238f92c120d6/win32/winutil.c#L80
87
+ //
88
+ // we're calling it, all the same, in the off chance that the mcrypt extension is not available
89
+ if (function_exists('openssl_random_pseudo_bytes') && version_compare(PHP_VERSION, '5.3.4', '>=')) {
90
+ return openssl_random_pseudo_bytes($length);
91
+ }
92
+ } else {
93
+ // method 1. the fastest
94
+ if (function_exists('openssl_random_pseudo_bytes')) {
95
+ return openssl_random_pseudo_bytes($length);
96
+ }
97
+ // method 2
98
+ static $fp = true;
99
+ if ($fp === true) {
100
+ // warning's will be output unles the error suppression operator is used. errors such as
101
+ // "open_basedir restriction in effect", "Permission denied", "No such file or directory", etc.
102
+ $fp = @fopen('/dev/urandom', 'rb');
103
+ }
104
+ if ($fp !== true && $fp !== false) { // surprisingly faster than !is_bool() or is_resource()
105
+ return fread($fp, $length);
106
+ }
107
+ // method 3. pretty much does the same thing as method 2 per the following url:
108
+ // https://github.com/php/php-src/blob/7014a0eb6d1611151a286c0ff4f2238f92c120d6/ext/mcrypt/mcrypt.c#L1391
109
+ // surprisingly slower than method 2. maybe that's because mcrypt_create_iv does a bunch of error checking that we're
110
+ // not doing. regardless, this'll only be called if this PHP script couldn't open /dev/urandom due to open_basedir
111
+ // restrictions or some such
112
+ if (function_exists('mcrypt_create_iv')) {
113
+ return mcrypt_create_iv($length, MCRYPT_DEV_URANDOM);
114
+ }
115
+ }
116
+ // at this point we have no choice but to use a pure-PHP CSPRNG
117
+
118
+ // cascade entropy across multiple PHP instances by fixing the session and collecting all
119
+ // environmental variables, including the previous session data and the current session
120
+ // data.
121
+ //
122
+ // mt_rand seeds itself by looking at the PID and the time, both of which are (relatively)
123
+ // easy to guess at. linux uses mouse clicks, keyboard timings, etc, as entropy sources, but
124
+ // PHP isn't low level to be able to use those as sources and on a web server there's not likely
125
+ // going to be a ton of keyboard or mouse action. web servers do have one thing that we can use
126
+ // however, a ton of people visiting the website. obviously you don't want to base your seeding
127
+ // soley on parameters a potential attacker sends but (1) not everything in $_SERVER is controlled
128
+ // by the user and (2) this isn't just looking at the data sent by the current user - it's based
129
+ // on the data sent by all users. one user requests the page and a hash of their info is saved.
130
+ // another user visits the page and the serialization of their data is utilized along with the
131
+ // server envirnment stuff and a hash of the previous http request data (which itself utilizes
132
+ // a hash of the session data before that). certainly an attacker should be assumed to have
133
+ // full control over his own http requests. he, however, is not going to have control over
134
+ // everyone's http requests.
135
+ static $crypto = false, $v;
136
+ if ($crypto === false) {
137
+ // save old session data
138
+ $old_session_id = session_id();
139
+ $old_use_cookies = ini_get('session.use_cookies');
140
+ $old_session_cache_limiter = session_cache_limiter();
141
+ $_OLD_SESSION = isset($_SESSION) ? $_SESSION : false;
142
+ if ($old_session_id != '') {
143
+ session_write_close();
144
+ }
145
+
146
+ session_id(1);
147
+ ini_set('session.use_cookies', 0);
148
+ session_cache_limiter('');
149
+ session_start();
150
+
151
+ $v = $seed = $_SESSION['seed'] = pack('H*', sha1(
152
+ serialize($_SERVER) .
153
+ serialize($_POST) .
154
+ serialize($_GET) .
155
+ serialize($_COOKIE) .
156
+ serialize($GLOBALS) .
157
+ serialize($_SESSION) .
158
+ serialize($_OLD_SESSION)
159
+ ));
160
+ if (!isset($_SESSION['count'])) {
161
+ $_SESSION['count'] = 0;
162
+ }
163
+ $_SESSION['count']++;
164
+
165
+ session_write_close();
166
+
167
+ // restore old session data
168
+ if ($old_session_id != '') {
169
+ session_id($old_session_id);
170
+ session_start();
171
+ ini_set('session.use_cookies', $old_use_cookies);
172
+ session_cache_limiter($old_session_cache_limiter);
173
+ } else {
174
+ if ($_OLD_SESSION !== false) {
175
+ $_SESSION = $_OLD_SESSION;
176
+ unset($_OLD_SESSION);
177
+ } else {
178
+ unset($_SESSION);
179
+ }
180
+ }
181
+
182
+ // in SSH2 a shared secret and an exchange hash are generated through the key exchange process.
183
+ // the IV client to server is the hash of that "nonce" with the letter A and for the encryption key it's the letter C.
184
+ // if the hash doesn't produce enough a key or an IV that's long enough concat successive hashes of the
185
+ // original hash and the current hash. we'll be emulating that. for more info see the following URL:
186
+ //
187
+ // http://tools.ietf.org/html/rfc4253#section-7.2
188
+ //
189
+ // see the is_string($crypto) part for an example of how to expand the keys
190
+ $key = pack('H*', sha1($seed . 'A'));
191
+ $iv = pack('H*', sha1($seed . 'C'));
192
+
193
+ // ciphers are used as per the nist.gov link below. also, see this link:
194
+ //
195
+ // http://en.wikipedia.org/wiki/Cryptographically_secure_pseudorandom_number_generator#Designs_based_on_cryptographic_primitives
196
+ switch (true) {
197
+ case phpseclib_resolve_include_path('Crypt/AES.php'):
198
+ if (!class_exists('Crypt_AES')) {
199
+ include_once 'AES.php';
200
+ }
201
+ $crypto = new Crypt_AES(CRYPT_AES_MODE_CTR);
202
+ break;
203
+ case phpseclib_resolve_include_path('Crypt/Twofish.php'):
204
+ if (!class_exists('Crypt_Twofish')) {
205
+ include_once 'Twofish.php';
206
+ }
207
+ $crypto = new Crypt_Twofish(CRYPT_TWOFISH_MODE_CTR);
208
+ break;
209
+ case phpseclib_resolve_include_path('Crypt/Blowfish.php'):
210
+ if (!class_exists('Crypt_Blowfish')) {
211
+ include_once 'Blowfish.php';
212
+ }
213
+ $crypto = new Crypt_Blowfish(CRYPT_BLOWFISH_MODE_CTR);
214
+ break;
215
+ case phpseclib_resolve_include_path('Crypt/TripleDES.php'):
216
+ if (!class_exists('Crypt_TripleDES')) {
217
+ include_once 'TripleDES.php';
218
+ }
219
+ $crypto = new Crypt_TripleDES(CRYPT_DES_MODE_CTR);
220
+ break;
221
+ case phpseclib_resolve_include_path('Crypt/DES.php'):
222
+ if (!class_exists('Crypt_DES')) {
223
+ include_once 'DES.php';
224
+ }
225
+ $crypto = new Crypt_DES(CRYPT_DES_MODE_CTR);
226
+ break;
227
+ case phpseclib_resolve_include_path('Crypt/RC4.php'):
228
+ if (!class_exists('Crypt_RC4')) {
229
+ include_once 'RC4.php';
230
+ }
231
+ $crypto = new Crypt_RC4();
232
+ break;
233
+ default:
234
+ user_error('crypt_random_string requires at least one symmetric cipher be loaded');
235
+ return false;
236
+ }
237
+
238
+ $crypto->setKey($key);
239
+ $crypto->setIV($iv);
240
+ $crypto->enableContinuousBuffer();
241
+ }
242
+
243
+ //return $crypto->encrypt(str_repeat("\0", $length));
244
+
245
+ // the following is based off of ANSI X9.31:
246
+ //
247
+ // http://csrc.nist.gov/groups/STM/cavp/documents/rng/931rngext.pdf
248
+ //
249
+ // OpenSSL uses that same standard for it's random numbers:
250
+ //
251
+ // http://www.opensource.apple.com/source/OpenSSL/OpenSSL-38/openssl/fips-1.0/rand/fips_rand.c
252
+ // (do a search for "ANS X9.31 A.2.4")
253
+ $result = '';
254
+ while (strlen($result) < $length) {
255
+ $i = $crypto->encrypt(microtime()); // strlen(microtime()) == 21
256
+ $r = $crypto->encrypt($i ^ $v); // strlen($v) == 20
257
+ $v = $crypto->encrypt($r ^ $i); // strlen($r) == 20
258
+ $result.= $r;
259
+ }
260
+ return substr($result, 0, $length);
261
+ }
262
+ }
263
+
264
+ if (!function_exists('phpseclib_resolve_include_path')) {
265
+ /**
266
+ * Resolve filename against the include path.
267
+ *
268
+ * Wrapper around stream_resolve_include_path() (which was introduced in
269
+ * PHP 5.3.2) with fallback implementation for earlier PHP versions.
270
+ *
271
+ * @param string $filename
272
+ * @return mixed Filename (string) on success, false otherwise.
273
+ * @access public
274
+ */
275
+ function phpseclib_resolve_include_path($filename)
276
+ {
277
+ if (function_exists('stream_resolve_include_path')) {
278
+ return stream_resolve_include_path($filename);
279
+ }
280
+
281
+ // handle non-relative paths
282
+ if (file_exists($filename)) {
283
+ return realpath($filename);
284
+ }
285
+
286
+ $paths = PATH_SEPARATOR == ':' ?
287
+ preg_split('#(?<!phar):#', get_include_path()) :
288
+ explode(PATH_SEPARATOR, get_include_path());
289
+ foreach ($paths as $prefix) {
290
+ // path's specified in include_path don't always end in /
291
+ $ds = substr($prefix, -1) == DIRECTORY_SEPARATOR ? '' : DIRECTORY_SEPARATOR;
292
+ $file = $prefix . $ds . $filename;
293
+ if (file_exists($file)) {
294
+ return realpath($file);
295
+ }
296
+ }
297
+
298
+ return false;
299
+ }
300
+ }
phpseclib/Crypt/Rijndael.php CHANGED
@@ -1,34 +1,34 @@
1
  <?php
2
- /* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
3
 
4
  /**
5
  * Pure-PHP implementation of Rijndael.
6
  *
7
- * Does not use mcrypt, even when available, for reasons that are explained below.
8
  *
9
  * PHP versions 4 and 5
10
  *
11
- * If {@link Crypt_Rijndael::setBlockLength() setBlockLength()} isn't called, it'll be assumed to be 128 bits. If
12
- * {@link Crypt_Rijndael::setKeyLength() setKeyLength()} isn't called, it'll be calculated from
13
- * {@link Crypt_Rijndael::setKey() setKey()}. ie. if the key is 128-bits, the key length will be 128-bits. If it's
14
- * 136-bits it'll be null-padded to 160-bits and 160 bits will be the key length until
15
  * {@link Crypt_Rijndael::setKey() setKey()} is called, again, at which point, it'll be recalculated.
16
  *
17
  * Not all Rijndael implementations may support 160-bits or 224-bits as the block length / key length. mcrypt, for example,
18
  * does not. AES, itself, only supports block lengths of 128 and key lengths of 128, 192, and 256.
19
  * {@link http://csrc.nist.gov/archive/aes/rijndael/Rijndael-ammended.pdf#page=10 Rijndael-ammended.pdf#page=10} defines the
20
  * algorithm for block lengths of 192 and 256 but not for block lengths / key lengths of 160 and 224. Indeed, 160 and 224
21
- * are first defined as valid key / block lengths in
22
- * {@link http://csrc.nist.gov/archive/aes/rijndael/Rijndael-ammended.pdf#page=44 Rijndael-ammended.pdf#page=44}:
23
  * Extensions: Other block and Cipher Key lengths.
 
24
  *
25
- * {@internal The variable names are the same as those in
26
  * {@link http://www.csrc.nist.gov/publications/fips/fips197/fips-197.pdf#page=10 fips-197.pdf#page=10}.}}
27
  *
28
  * Here's a short example of how to use this library:
29
  * <code>
30
  * <?php
31
- * include('Crypt/Rijndael.php');
32
  *
33
  * $rijndael = new Crypt_Rijndael();
34
  *
@@ -50,10 +50,10 @@
50
  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
51
  * copies of the Software, and to permit persons to whom the Software is
52
  * furnished to do so, subject to the following conditions:
53
- *
54
  * The above copyright notice and this permission notice shall be included in
55
  * all copies or substantial portions of the Software.
56
- *
57
  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
58
  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
59
  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
@@ -62,15 +62,23 @@
62
  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
63
  * THE SOFTWARE.
64
  *
65
- * @category Crypt
66
- * @package Crypt_Rijndael
67
- * @author Jim Wigginton <terrafrost@php.net>
68
- * @copyright MMVIII Jim Wigginton
69
- * @license http://www.opensource.org/licenses/mit-license.html MIT License
70
- * @version $Id: Rijndael.php,v 1.12 2010/02/09 06:10:26 terrafrost Exp $
71
- * @link http://phpseclib.sourceforge.net
72
  */
73
 
 
 
 
 
 
 
 
 
 
74
  /**#@+
75
  * @access public
76
  * @see Crypt_Rijndael::encrypt()
@@ -83,129 +91,100 @@
83
  *
84
  * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Counter_.28CTR.29
85
  */
86
- define('CRYPT_RIJNDAEL_MODE_CTR', -1);
87
  /**
88
  * Encrypt / decrypt using the Electronic Code Book mode.
89
  *
90
  * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Electronic_codebook_.28ECB.29
91
  */
92
- define('CRYPT_RIJNDAEL_MODE_ECB', 1);
93
  /**
94
  * Encrypt / decrypt using the Code Book Chaining mode.
95
  *
96
  * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Cipher-block_chaining_.28CBC.29
97
  */
98
- define('CRYPT_RIJNDAEL_MODE_CBC', 2);
99
  /**
100
  * Encrypt / decrypt using the Cipher Feedback mode.
101
  *
102
  * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Cipher_feedback_.28CFB.29
103
  */
104
- define('CRYPT_RIJNDAEL_MODE_CFB', 3);
105
  /**
106
  * Encrypt / decrypt using the Cipher Feedback mode.
107
  *
108
  * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Output_feedback_.28OFB.29
109
  */
110
- define('CRYPT_RIJNDAEL_MODE_OFB', 4);
111
  /**#@-*/
112
 
113
  /**#@+
114
  * @access private
115
- * @see Crypt_Rijndael::Crypt_Rijndael()
116
  */
117
  /**
118
  * Toggles the internal implementation
119
  */
120
- define('CRYPT_RIJNDAEL_MODE_INTERNAL', 1);
121
  /**
122
  * Toggles the mcrypt implementation
123
  */
124
- define('CRYPT_RIJNDAEL_MODE_MCRYPT', 2);
125
  /**#@-*/
126
 
127
  /**
128
  * Pure-PHP implementation of Rijndael.
129
  *
 
130
  * @author Jim Wigginton <terrafrost@php.net>
131
- * @version 0.1.0
132
  * @access public
133
- * @package Crypt_Rijndael
134
  */
135
- class Crypt_Rijndael {
 
136
  /**
137
- * The Encryption Mode
138
  *
139
- * @see Crypt_Rijndael::Crypt_Rijndael()
 
140
  * @var Integer
141
  * @access private
142
  */
143
- var $mode;
144
 
145
  /**
146
- * The Key
147
  *
148
- * @see Crypt_Rijndael::setKey()
149
  * @var String
150
  * @access private
151
  */
152
- var $key = "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0";
153
 
154
  /**
155
- * The Initialization Vector
156
  *
157
- * @see Crypt_Rijndael::setIV()
158
- * @var String
159
- * @access private
160
- */
161
- var $iv = '';
162
-
163
- /**
164
- * A "sliding" Initialization Vector
165
  *
166
- * @see Crypt_Rijndael::enableContinuousBuffer()
 
 
167
  * @var String
168
  * @access private
169
  */
170
- var $encryptIV = '';
171
 
172
  /**
173
- * A "sliding" Initialization Vector
174
  *
175
- * @see Crypt_Rijndael::enableContinuousBuffer()
 
176
  * @var String
177
  * @access private
178
  */
179
- var $decryptIV = '';
180
-
181
- /**
182
- * Continuous Buffer status
183
- *
184
- * @see Crypt_Rijndael::enableContinuousBuffer()
185
- * @var Boolean
186
- * @access private
187
- */
188
- var $continuousBuffer = false;
189
-
190
- /**
191
- * Padding status
192
- *
193
- * @see Crypt_Rijndael::enablePadding()
194
- * @var Boolean
195
- * @access private
196
- */
197
- var $padding = true;
198
-
199
- /**
200
- * Does the key schedule need to be (re)calculated?
201
- *
202
- * @see setKey()
203
- * @see setBlockLength()
204
- * @see setKeyLength()
205
- * @var Boolean
206
- * @access private
207
- */
208
- var $changed = true;
209
 
210
  /**
211
  * Has the key length explicitly been set or should it be derived from the key, itself?
@@ -234,25 +213,14 @@ class Crypt_Rijndael {
234
  */
235
  var $dw;
236
 
237
- /**
238
- * The Block Length
239
- *
240
- * @see setBlockLength()
241
- * @var Integer
242
- * @access private
243
- * @internal The max value is 32, the min value is 16. All valid values are multiples of 4. Exists in conjunction with
244
- * $Nb because we need this value and not $Nb to pad strings appropriately.
245
- */
246
- var $block_size = 16;
247
-
248
  /**
249
  * The Block Length divided by 32
250
  *
251
  * @see setBlockLength()
252
  * @var Integer
253
  * @access private
254
- * @internal The max value is 256 / 32 = 8, the min value is 128 / 32 = 4. Exists in conjunction with $block_size
255
- * because the encryption / decryption / key schedule creation requires this number and not $block_size. We could
256
  * derive this from $block_size or vice versa, but that'd mean we'd have to do multiple shift operations, so in lieu
257
  * of that, we'll just precompute it once.
258
  *
@@ -265,8 +233,8 @@ class Crypt_Rijndael {
265
  * @see setKeyLength()
266
  * @var Integer
267
  * @access private
268
- * @internal The max value is 256 / 8 = 32, the min value is 128 / 8 = 16. Exists in conjunction with $key_size
269
- * because the encryption / decryption / key schedule creation requires this number and not $key_size. We could
270
  * derive this from $key_size or vice versa, but that'd mean we'd have to do multiple shift operations, so in lieu
271
  * of that, we'll just precompute it once.
272
  */
@@ -300,225 +268,412 @@ class Crypt_Rijndael {
300
  var $c;
301
 
302
  /**
303
- * Precomputed mixColumns table
304
  *
305
- * @see Crypt_Rijndael()
306
  * @var Array
307
  * @access private
308
  */
309
- var $t0;
310
 
311
  /**
312
  * Precomputed mixColumns table
313
  *
314
- * @see Crypt_Rijndael()
 
 
 
 
 
315
  * @var Array
316
  * @access private
317
  */
318
- var $t1;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
319
 
320
  /**
321
  * Precomputed mixColumns table
322
  *
323
- * @see Crypt_Rijndael()
 
324
  * @var Array
325
  * @access private
326
  */
327
- var $t2;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
328
 
329
  /**
330
  * Precomputed mixColumns table
331
  *
332
- * @see Crypt_Rijndael()
 
333
  * @var Array
334
  * @access private
335
  */
336
- var $t3;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
337
 
338
  /**
339
- * Precomputed invMixColumns table
340
  *
341
- * @see Crypt_Rijndael()
 
342
  * @var Array
343
  * @access private
344
  */
345
- var $dt0;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
346
 
347
  /**
348
  * Precomputed invMixColumns table
349
  *
350
- * @see Crypt_Rijndael()
 
351
  * @var Array
352
  * @access private
353
  */
354
- var $dt1;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
355
 
356
  /**
357
  * Precomputed invMixColumns table
358
  *
359
- * @see Crypt_Rijndael()
 
360
  * @var Array
361
  * @access private
362
  */
363
- var $dt2;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
364
 
365
  /**
366
  * Precomputed invMixColumns table
367
  *
368
- * @see Crypt_Rijndael()
 
369
  * @var Array
370
  * @access private
371
  */
372
- var $dt3;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
373
 
374
  /**
375
- * Is the mode one that is paddable?
376
  *
377
- * @see Crypt_Rijndael::Crypt_Rijndael()
378
- * @var Boolean
 
379
  * @access private
380
  */
381
- var $paddable = false;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
382
 
383
  /**
384
- * Encryption buffer for CTR, OFB and CFB modes
385
  *
386
- * @see Crypt_Rijndael::encrypt()
387
- * @var String
388
  * @access private
389
  */
390
- var $enbuffer = array('encrypted' => '', 'xor' => '', 'pos' => 0);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
391
 
392
  /**
393
- * Decryption buffer for CTR, OFB and CFB modes
394
  *
395
- * @see Crypt_Rijndael::decrypt()
396
- * @var String
397
  * @access private
398
  */
399
- var $debuffer = array('ciphertext' => '', 'xor' => '', 'pos' => 0);
400
-
401
- /**
402
- * Default Constructor.
403
- *
404
- * Determines whether or not the mcrypt extension should be used. $mode should only, at present, be
405
- * CRYPT_RIJNDAEL_MODE_ECB or CRYPT_RIJNDAEL_MODE_CBC. If not explictly set, CRYPT_RIJNDAEL_MODE_CBC will be used.
406
- *
407
- * @param optional Integer $mode
408
- * @return Crypt_Rijndael
409
- * @access public
410
- */
411
- function Crypt_Rijndael($mode = CRYPT_RIJNDAEL_MODE_CBC)
412
- {
413
- switch ($mode) {
414
- case CRYPT_RIJNDAEL_MODE_ECB:
415
- case CRYPT_RIJNDAEL_MODE_CBC:
416
- $this->paddable = true;
417
- $this->mode = $mode;
418
- break;
419
- case CRYPT_RIJNDAEL_MODE_CTR:
420
- case CRYPT_RIJNDAEL_MODE_CFB:
421
- case CRYPT_RIJNDAEL_MODE_OFB:
422
- $this->mode = $mode;
423
- break;
424
- default:
425
- $this->paddable = true;
426
- $this->mode = CRYPT_RIJNDAEL_MODE_CBC;
427
- }
428
-
429
- $t3 = &$this->t3;
430
- $t2 = &$this->t2;
431
- $t1 = &$this->t1;
432
- $t0 = &$this->t0;
433
-
434
- $dt3 = &$this->dt3;
435
- $dt2 = &$this->dt2;
436
- $dt1 = &$this->dt1;
437
- $dt0 = &$this->dt0;
438
-
439
- // according to <http://csrc.nist.gov/archive/aes/rijndael/Rijndael-ammended.pdf#page=19> (section 5.2.1),
440
- // precomputed tables can be used in the mixColumns phase. in that example, they're assigned t0...t3, so
441
- // those are the names we'll use.
442
- $t3 = array(
443
- 0x6363A5C6, 0x7C7C84F8, 0x777799EE, 0x7B7B8DF6, 0xF2F20DFF, 0x6B6BBDD6, 0x6F6FB1DE, 0xC5C55491,
444
- 0x30305060, 0x01010302, 0x6767A9CE, 0x2B2B7D56, 0xFEFE19E7, 0xD7D762B5, 0xABABE64D, 0x76769AEC,
445
- 0xCACA458F, 0x82829D1F, 0xC9C94089, 0x7D7D87FA, 0xFAFA15EF, 0x5959EBB2, 0x4747C98E, 0xF0F00BFB,
446
- 0xADADEC41, 0xD4D467B3, 0xA2A2FD5F, 0xAFAFEA45, 0x9C9CBF23, 0xA4A4F753, 0x727296E4, 0xC0C05B9B,
447
- 0xB7B7C275, 0xFDFD1CE1, 0x9393AE3D, 0x26266A4C, 0x36365A6C, 0x3F3F417E, 0xF7F702F5, 0xCCCC4F83,
448
- 0x34345C68, 0xA5A5F451, 0xE5E534D1, 0xF1F108F9, 0x717193E2, 0xD8D873AB, 0x31315362, 0x15153F2A,
449
- 0x04040C08, 0xC7C75295, 0x23236546, 0xC3C35E9D, 0x18182830, 0x9696A137, 0x05050F0A, 0x9A9AB52F,
450
- 0x0707090E, 0x12123624, 0x80809B1B, 0xE2E23DDF, 0xEBEB26CD, 0x2727694E, 0xB2B2CD7F, 0x75759FEA,
451
- 0x09091B12, 0x83839E1D, 0x2C2C7458, 0x1A1A2E34, 0x1B1B2D36, 0x6E6EB2DC, 0x5A5AEEB4, 0xA0A0FB5B,
452
- 0x5252F6A4, 0x3B3B4D76, 0xD6D661B7, 0xB3B3CE7D, 0x29297B52, 0xE3E33EDD, 0x2F2F715E, 0x84849713,
453
- 0x5353F5A6, 0xD1D168B9, 0x00000000, 0xEDED2CC1, 0x20206040, 0xFCFC1FE3, 0xB1B1C879, 0x5B5BEDB6,
454
- 0x6A6ABED4, 0xCBCB468D, 0xBEBED967, 0x39394B72, 0x4A4ADE94, 0x4C4CD498, 0x5858E8B0, 0xCFCF4A85,
455
- 0xD0D06BBB, 0xEFEF2AC5, 0xAAAAE54F, 0xFBFB16ED, 0x4343C586, 0x4D4DD79A, 0x33335566, 0x85859411,
456
- 0x4545CF8A, 0xF9F910E9, 0x02020604, 0x7F7F81FE, 0x5050F0A0, 0x3C3C4478, 0x9F9FBA25, 0xA8A8E34B,
457
- 0x5151F3A2, 0xA3A3FE5D, 0x4040C080, 0x8F8F8A05, 0x9292AD3F, 0x9D9DBC21, 0x38384870, 0xF5F504F1,
458
- 0xBCBCDF63, 0xB6B6C177, 0xDADA75AF, 0x21216342, 0x10103020, 0xFFFF1AE5, 0xF3F30EFD, 0xD2D26DBF,
459
- 0xCDCD4C81, 0x0C0C1418, 0x13133526, 0xECEC2FC3, 0x5F5FE1BE, 0x9797A235, 0x4444CC88, 0x1717392E,
460
- 0xC4C45793, 0xA7A7F255, 0x7E7E82FC, 0x3D3D477A, 0x6464ACC8, 0x5D5DE7BA, 0x19192B32, 0x737395E6,
461
- 0x6060A0C0, 0x81819819, 0x4F4FD19E, 0xDCDC7FA3, 0x22226644, 0x2A2A7E54, 0x9090AB3B, 0x8888830B,
462
- 0x4646CA8C, 0xEEEE29C7, 0xB8B8D36B, 0x14143C28, 0xDEDE79A7, 0x5E5EE2BC, 0x0B0B1D16, 0xDBDB76AD,
463
- 0xE0E03BDB, 0x32325664, 0x3A3A4E74, 0x0A0A1E14, 0x4949DB92, 0x06060A0C, 0x24246C48, 0x5C5CE4B8,
464
- 0xC2C25D9F, 0xD3D36EBD, 0xACACEF43, 0x6262A6C4, 0x9191A839, 0x9595A431, 0xE4E437D3, 0x79798BF2,
465
- 0xE7E732D5, 0xC8C8438B, 0x3737596E, 0x6D6DB7DA, 0x8D8D8C01, 0xD5D564B1, 0x4E4ED29C, 0xA9A9E049,
466
- 0x6C6CB4D8, 0x5656FAAC, 0xF4F407F3, 0xEAEA25CF, 0x6565AFCA, 0x7A7A8EF4, 0xAEAEE947, 0x08081810,
467
- 0xBABAD56F, 0x787888F0, 0x25256F4A, 0x2E2E725C, 0x1C1C2438, 0xA6A6F157, 0xB4B4C773, 0xC6C65197,
468
- 0xE8E823CB, 0xDDDD7CA1, 0x74749CE8, 0x1F1F213E, 0x4B4BDD96, 0xBDBDDC61, 0x8B8B860D, 0x8A8A850F,
469
- 0x707090E0, 0x3E3E427C, 0xB5B5C471, 0x6666AACC, 0x4848D890, 0x03030506, 0xF6F601F7, 0x0E0E121C,
470
- 0x6161A3C2, 0x35355F6A, 0x5757F9AE, 0xB9B9D069, 0x86869117, 0xC1C15899, 0x1D1D273A, 0x9E9EB927,
471
- 0xE1E138D9, 0xF8F813EB, 0x9898B32B, 0x11113322, 0x6969BBD2, 0xD9D970A9, 0x8E8E8907, 0x9494A733,
472
- 0x9B9BB62D, 0x1E1E223C, 0x87879215, 0xE9E920C9, 0xCECE4987, 0x5555FFAA, 0x28287850, 0xDFDF7AA5,
473
- 0x8C8C8F03, 0xA1A1F859, 0x89898009, 0x0D0D171A, 0xBFBFDA65, 0xE6E631D7, 0x4242C684, 0x6868B8D0,
474
- 0x4141C382, 0x9999B029, 0x2D2D775A, 0x0F0F111E, 0xB0B0CB7B, 0x5454FCA8, 0xBBBBD66D, 0x16163A2C
475
- );
476
-
477
- $dt3 = array(
478
- 0xF4A75051, 0x4165537E, 0x17A4C31A, 0x275E963A, 0xAB6BCB3B, 0x9D45F11F, 0xFA58ABAC, 0xE303934B,
479
- 0x30FA5520, 0x766DF6AD, 0xCC769188, 0x024C25F5, 0xE5D7FC4F, 0x2ACBD7C5, 0x35448026, 0x62A38FB5,
480
- 0xB15A49DE, 0xBA1B6725, 0xEA0E9845, 0xFEC0E15D, 0x2F7502C3, 0x4CF01281, 0x4697A38D, 0xD3F9C66B,
481
- 0x8F5FE703, 0x929C9515, 0x6D7AEBBF, 0x5259DA95, 0xBE832DD4, 0x7421D358, 0xE0692949, 0xC9C8448E,
482
- 0xC2896A75, 0x8E7978F4, 0x583E6B99, 0xB971DD27, 0xE14FB6BE, 0x88AD17F0, 0x20AC66C9, 0xCE3AB47D,
483
- 0xDF4A1863, 0x1A3182E5, 0x51336097, 0x537F4562, 0x6477E0B1, 0x6BAE84BB, 0x81A01CFE, 0x082B94F9,
484
- 0x48685870, 0x45FD198F, 0xDE6C8794, 0x7BF8B752, 0x73D323AB, 0x4B02E272, 0x1F8F57E3, 0x55AB2A66,
485
- 0xEB2807B2, 0xB5C2032F, 0xC57B9A86, 0x3708A5D3, 0x2887F230, 0xBFA5B223, 0x036ABA02, 0x16825CED,
486
- 0xCF1C2B8A, 0x79B492A7, 0x07F2F0F3, 0x69E2A14E, 0xDAF4CD65, 0x05BED506, 0x34621FD1, 0xA6FE8AC4,
487
- 0x2E539D34, 0xF355A0A2, 0x8AE13205, 0xF6EB75A4, 0x83EC390B, 0x60EFAA40, 0x719F065E, 0x6E1051BD,
488
- 0x218AF93E, 0xDD063D96, 0x3E05AEDD, 0xE6BD464D, 0x548DB591, 0xC45D0571, 0x06D46F04, 0x5015FF60,
489
- 0x98FB2419, 0xBDE997D6, 0x4043CC89, 0xD99E7767, 0xE842BDB0, 0x898B8807, 0x195B38E7, 0xC8EEDB79,
490
- 0x7C0A47A1, 0x420FE97C, 0x841EC9F8, 0x00000000, 0x80868309, 0x2BED4832, 0x1170AC1E, 0x5A724E6C,
491
- 0x0EFFFBFD, 0x8538560F, 0xAED51E3D, 0x2D392736, 0x0FD9640A, 0x5CA62168, 0x5B54D19B, 0x362E3A24,
492
- 0x0A67B10C, 0x57E70F93, 0xEE96D2B4, 0x9B919E1B, 0xC0C54F80, 0xDC20A261, 0x774B695A, 0x121A161C,
493
- 0x93BA0AE2, 0xA02AE5C0, 0x22E0433C, 0x1B171D12, 0x090D0B0E, 0x8BC7ADF2, 0xB6A8B92D, 0x1EA9C814,
494
- 0xF1198557, 0x75074CAF, 0x99DDBBEE, 0x7F60FDA3, 0x01269FF7, 0x72F5BC5C, 0x663BC544, 0xFB7E345B,
495
- 0x4329768B, 0x23C6DCCB, 0xEDFC68B6, 0xE4F163B8, 0x31DCCAD7, 0x63851042, 0x97224013, 0xC6112084,
496
- 0x4A247D85, 0xBB3DF8D2, 0xF93211AE, 0x29A16DC7, 0x9E2F4B1D, 0xB230F3DC, 0x8652EC0D, 0xC1E3D077,
497
- 0xB3166C2B, 0x70B999A9, 0x9448FA11, 0xE9642247, 0xFC8CC4A8, 0xF03F1AA0, 0x7D2CD856, 0x3390EF22,
498
- 0x494EC787, 0x38D1C1D9, 0xCAA2FE8C, 0xD40B3698, 0xF581CFA6, 0x7ADE28A5, 0xB78E26DA, 0xADBFA43F,
499
- 0x3A9DE42C, 0x78920D50, 0x5FCC9B6A, 0x7E466254, 0x8D13C2F6, 0xD8B8E890, 0x39F75E2E, 0xC3AFF582,
500
- 0x5D80BE9F, 0xD0937C69, 0xD52DA96F, 0x2512B3CF, 0xAC993BC8, 0x187DA710, 0x9C636EE8, 0x3BBB7BDB,
501
- 0x267809CD, 0x5918F46E, 0x9AB701EC, 0x4F9AA883, 0x956E65E6, 0xFFE67EAA, 0xBCCF0821, 0x15E8E6EF,
502
- 0xE79BD9BA, 0x6F36CE4A, 0x9F09D4EA, 0xB07CD629, 0xA4B2AF31, 0x3F23312A, 0xA59430C6, 0xA266C035,
503
- 0x4EBC3774, 0x82CAA6FC, 0x90D0B0E0, 0xA7D81533, 0x04984AF1, 0xECDAF741, 0xCD500E7F, 0x91F62F17,
504
- 0x4DD68D76, 0xEFB04D43, 0xAA4D54CC, 0x9604DFE4, 0xD1B5E39E, 0x6A881B4C, 0x2C1FB8C1, 0x65517F46,
505
- 0x5EEA049D, 0x8C355D01, 0x877473FA, 0x0B412EFB, 0x671D5AB3, 0xDBD25292, 0x105633E9, 0xD647136D,
506
- 0xD7618C9A, 0xA10C7A37, 0xF8148E59, 0x133C89EB, 0xA927EECE, 0x61C935B7, 0x1CE5EDE1, 0x47B13C7A,
507
- 0xD2DF599C, 0xF2733F55, 0x14CE7918, 0xC737BF73, 0xF7CDEA53, 0xFDAA5B5F, 0x3D6F14DF, 0x44DB8678,
508
- 0xAFF381CA, 0x68C43EB9, 0x24342C38, 0xA3405FC2, 0x1DC37216, 0xE2250CBC, 0x3C498B28, 0x0D9541FF,
509
- 0xA8017139, 0x0CB3DE08, 0xB4E49CD8, 0x56C19064, 0xCB84617B, 0x32B670D5, 0x6C5C7448, 0xB85742D0
510
- );
511
-
512
- for ($i = 0; $i < 256; $i++) {
513
- $t2[$i << 8] = (($t3[$i] << 8) & 0xFFFFFF00) | (($t3[$i] >> 24) & 0x000000FF);
514
- $t1[$i << 16] = (($t3[$i] << 16) & 0xFFFF0000) | (($t3[$i] >> 16) & 0x0000FFFF);
515
- $t0[$i << 24] = (($t3[$i] << 24) & 0xFF000000) | (($t3[$i] >> 8) & 0x00FFFFFF);
516
-
517
- $dt2[$i << 8] = (($this->dt3[$i] << 8) & 0xFFFFFF00) | (($dt3[$i] >> 24) & 0x000000FF);
518
- $dt1[$i << 16] = (($this->dt3[$i] << 16) & 0xFFFF0000) | (($dt3[$i] >> 16) & 0x0000FFFF);
519
- $dt0[$i << 24] = (($this->dt3[$i] << 24) & 0xFF000000) | (($dt3[$i] >> 8) & 0x00FFFFFF);
520
- }
521
- }
522
 
523
  /**
524
  * Sets the key.
@@ -530,112 +685,88 @@ class Crypt_Rijndael {
530
  *
531
  * If the key is not explicitly set, it'll be assumed to be all null bytes.
532
  *
 
 
 
 
533
  * @access public
534
  * @param String $key
535
  */
536
  function setKey($key)
537
  {
538
- $this->key = $key;
539
- $this->changed = true;
540
- }
541
 
542
- /**
543
- * Sets the initialization vector. (optional)
544
- *
545
- * SetIV is not required when CRYPT_RIJNDAEL_MODE_ECB is being used. If not explictly set, it'll be assumed
546
- * to be all zero's.
547
- *
548
- * @access public
549
- * @param String $iv
550
- */
551
- function setIV($iv)
552
- {
553
- $this->encryptIV = $this->decryptIV = $this->iv = str_pad(substr($iv, 0, $this->block_size), $this->block_size, chr(0));
 
 
 
 
 
 
 
 
554
  }
555
 
556
  /**
557
  * Sets the key length
558
  *
559
  * Valid key lengths are 128, 160, 192, 224, and 256. If the length is less than 128, it will be rounded up to
560
- * 128. If the length is greater then 128 and invalid, it will be rounded down to the closest valid amount.
 
 
 
 
 
 
 
 
 
 
 
561
  *
562
  * @access public
563
  * @param Integer $length
564
  */
565
  function setKeyLength($length)
566
  {
567
- $length >>= 5;
568
- if ($length > 8) {
569
- $length = 8;
570
- } else if ($length < 4) {
571
- $length = 4;
 
 
 
 
 
 
 
 
 
 
572
  }
573
- $this->Nk = $length;
574
- $this->key_size = $length << 2;
575
 
576
  $this->explicit_key_length = true;
577
  $this->changed = true;
578
- }
579
-
580
- /**
581
- * Sets the password.
582
- *
583
- * Depending on what $method is set to, setPassword()'s (optional) parameters are as follows:
584
- * {@link http://en.wikipedia.org/wiki/PBKDF2 pbkdf2}:
585
- * $hash, $salt, $method
586
- * Set $dkLen by calling setKeyLength()
587
- *
588
- * @param String $password
589
- * @param optional String $method
590
- * @access public
591
- */
592
- function setPassword($password, $method = 'pbkdf2')
593
- {
594
- $key = '';
595
-
596
- switch ($method) {
597
- default: // 'pbkdf2'
598
- list(, , $hash, $salt, $count) = func_get_args();
599
- if (!isset($hash)) {
600
- $hash = 'sha1';
601
- }
602
- // WPA and WPA use the SSID as the salt
603
- if (!isset($salt)) {
604
- $salt = 'phpseclib';
605
- }
606
- // RFC2898#section-4.2 uses 1,000 iterations by default
607
- // WPA and WPA2 use 4,096.
608
- if (!isset($count)) {
609
- $count = 1000;
610
- }
611
-
612
- if (!class_exists('Crypt_Hash')) {
613
- require_once('Crypt/Hash.php');
614
- }
615
-
616
- $i = 1;
617
- while (strlen($key) < $this->key_size) { // $dkLen == $this->key_size
618
- //$dk.= $this->_pbkdf($password, $salt, $count, $i++);
619
- $hmac = new Crypt_Hash();
620
- $hmac->setHash($hash);
621
- $hmac->setKey($password);
622
- $f = $u = $hmac->hash($salt . pack('N', $i++));
623
- for ($j = 2; $j <= $count; $j++) {
624
- $u = $hmac->hash($u);
625
- $f^= $u;
626
- }
627
- $key.= $f;
628
- }
629
- }
630
-
631
- $this->setKey(substr($key, 0, $this->key_size));
632
  }
633
 
634
  /**
635
  * Sets the block length
636
  *
637
  * Valid block lengths are 128, 160, 192, 224, and 256. If the length is less than 128, it will be rounded up to
638
- * 128. If the length is greater then 128 and invalid, it will be rounded down to the closest valid amount.
639
  *
640
  * @access public
641
  * @param Integer $length
@@ -651,315 +782,76 @@ class Crypt_Rijndael {
651
  $this->Nb = $length;
652
  $this->block_size = $length << 2;
653
  $this->changed = true;
 
654
  }
655
 
656
  /**
657
- * Generate CTR XOR encryption key
658
  *
659
- * Encrypt the output of this and XOR it against the ciphertext / plaintext to get the
660
- * plaintext / ciphertext in CTR mode.
661
  *
662
- * @see Crypt_Rijndael::decrypt()
663
- * @see Crypt_Rijndael::encrypt()
664
- * @access public
665
- * @param Integer $length
666
- * @param String $iv
 
667
  */
668
- function _generate_xor($length, &$iv)
669
  {
670
- $xor = '';
671
- $block_size = $this->block_size;
672
- $num_blocks = floor(($length + ($block_size - 1)) / $block_size);
673
- for ($i = 0; $i < $num_blocks; $i++) {
674
- $xor.= $iv;
675
- for ($j = 4; $j <= $block_size; $j+=4) {
676
- $temp = substr($iv, -$j, 4);
677
- switch ($temp) {
678
- case "\xFF\xFF\xFF\xFF":
679
- $iv = substr_replace($iv, "\x00\x00\x00\x00", -$j, 4);
680
- break;
681
- case "\x7F\xFF\xFF\xFF":
682
- $iv = substr_replace($iv, "\x80\x00\x00\x00", -$j, 4);
683
- break 2;
684
- default:
685
- extract(unpack('Ncount', $temp));
686
- $iv = substr_replace($iv, pack('N', $count + 1), -$j, 4);
687
- break 2;
688
- }
689
- }
690
  }
691
 
692
- return $xor;
693
- }
694
 
695
- /**
696
- * Encrypts a message.
697
- *
698
- * $plaintext will be padded with additional bytes such that it's length is a multiple of the block size. Other Rjindael
699
- * implementations may or may not pad in the same manner. Other common approaches to padding and the reasons why it's
700
- * necessary are discussed in the following
701
- * URL:
702
- *
703
- * {@link http://www.di-mgt.com.au/cryptopad.html http://www.di-mgt.com.au/cryptopad.html}
704
- *
705
- * An alternative to padding is to, separately, send the length of the file. This is what SSH, in fact, does.
706
- * strlen($plaintext) will still need to be a multiple of 8, however, arbitrary values can be added to make it that
707
- * length.
708
- *
709
- * @see Crypt_Rijndael::decrypt()
710
- * @access public
711
- * @param String $plaintext
712
- */
713
- function encrypt($plaintext)
714
- {
715
- $this->_setup();
716
- if ($this->paddable) {
717
- $plaintext = $this->_pad($plaintext);
718
  }
719
 
720
- $block_size = $this->block_size;
721
- $buffer = &$this->enbuffer;
722
- $continuousBuffer = $this->continuousBuffer;
723
- $ciphertext = '';
724
- switch ($this->mode) {
725
- case CRYPT_RIJNDAEL_MODE_ECB:
726
- for ($i = 0; $i < strlen($plaintext); $i+=$block_size) {
727
- $ciphertext.= $this->_encryptBlock(substr($plaintext, $i, $block_size));
728
- }
729
- break;
730
- case CRYPT_RIJNDAEL_MODE_CBC:
731
- $xor = $this->encryptIV;
732
- for ($i = 0; $i < strlen($plaintext); $i+=$block_size) {
733
- $block = substr($plaintext, $i, $block_size);
734
- $block = $this->_encryptBlock($block ^ $xor);
735
- $xor = $block;
736
- $ciphertext.= $block;
737
- }
738
- if ($this->continuousBuffer) {
739
- $this->encryptIV = $xor;
740
- }
741
- break;
742
- case CRYPT_RIJNDAEL_MODE_CTR:
743
- $xor = $this->encryptIV;
744
- if (strlen($buffer['encrypted'])) {
745
- for ($i = 0; $i < strlen($plaintext); $i+=$block_size) {
746
- $block = substr($plaintext, $i, $block_size);
747
- $buffer['encrypted'].= $this->_encryptBlock($this->_generate_xor($block_size, $xor));
748
- $key = $this->_string_shift($buffer['encrypted'], $block_size);
749
- $ciphertext.= $block ^ $key;
750
- }
751
- } else {
752
- for ($i = 0; $i < strlen($plaintext); $i+=$block_size) {
753
- $block = substr($plaintext, $i, $block_size);
754
- $key = $this->_encryptBlock($this->_generate_xor($block_size, $xor));
755
- $ciphertext.= $block ^ $key;
756
- }
757
- }
758
- if ($this->continuousBuffer) {
759
- $this->encryptIV = $xor;
760
- if ($start = strlen($plaintext) % $block_size) {
761
- $buffer['encrypted'] = substr($key, $start) . $buffer['encrypted'];
762
- }
763
- }
764
- break;
765
- case CRYPT_RIJNDAEL_MODE_CFB:
766
- // cfb loosely routines inspired by openssl's:
767
- // http://cvs.openssl.org/fileview?f=openssl/crypto/modes/cfb128.c&v=1.3.2.2.2.1
768
- $iv = $this->encryptIV;
769
- $pos = $this->continuousBuffer === true ? $buffer['pos'] : 0;
770
- $len = strlen($plaintext);
771
- $i = 0;
772
- if ($pos) {
773
- $orig_pos = $pos;
774
- $max = $block_size - $pos;
775
- if ($len >= $max) {
776
- $i = $max;
777
- $len-= $max;
778
- $pos = 0;
779
- } else {
780
- $i = $len;
781
- $pos+= $len;
782
- $len = 0;
783
- }
784
- // ie. $i = min($max, $len), $len-= $i, $pos+= $i, $pos%= $blocksize
785
- $ciphertext = substr($iv, $orig_pos) ^ $plaintext;
786
- $iv = substr_replace($iv, $ciphertext, $orig_pos, $i);
787
- }
788
- while ($len >= $block_size) {
789
- $iv = $this->_encryptBlock($iv) ^ substr($plaintext, $i, $block_size);
790
- $ciphertext.= $iv;
791
- $len-= $block_size;
792
- $i+= $block_size;
793
- }
794
- if ($len) {
795
- $iv = $this->_encryptBlock($iv);
796
- //$block = substr($iv, $pos, $len) ^ substr($plaintext, $i, $len);
797
- $block = substr($iv, $pos) ^ substr($plaintext, $i);
798
- $iv = substr_replace($iv, $block, $pos, $len);
799
- $ciphertext.= $block;
800
- $pos+= $len;
801
- }
802
- if($this->continuousBuffer) {
803
- $this->encryptIV = $iv;
804
- $buffer['pos'] = $pos;
805
- }
806
- break;
807
- case CRYPT_RIJNDAEL_MODE_OFB:
808
- $xor = $this->encryptIV;
809
- if (strlen($buffer['xor'])) {
810
- for ($i = 0; $i < strlen($plaintext); $i+=$block_size) {
811
- $xor = $this->_encryptBlock($xor);
812
- $buffer['xor'].= $xor;
813
- $key = $this->_string_shift($buffer['xor'], $block_size);
814
- $ciphertext.= substr($plaintext, $i, $block_size) ^ $key;
815
- }
816
- } else {
817
- for ($i = 0; $i < strlen($plaintext); $i+=$block_size) {
818
- $xor = $this->_encryptBlock($xor);
819
- $ciphertext.= substr($plaintext, $i, $block_size) ^ $xor;
820
- }
821
- $key = $xor;
822
- }
823
- if ($this->continuousBuffer) {
824
- $this->encryptIV = $xor;
825
- if ($start = strlen($plaintext) % $block_size) {
826
- $buffer['xor'] = substr($key, $start) . $buffer['xor'];
827
- }
828
- }
829
  }
830
 
831
- return $ciphertext;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
832
  }
833
 
834
  /**
835
- * Decrypts a message.
836
  *
837
- * If strlen($ciphertext) is not a multiple of the block size, null bytes will be added to the end of the string until
838
- * it is.
839
- *
840
- * @see Crypt_Rijndael::encrypt()
841
- * @access public
842
- * @param String $ciphertext
843
  */
844
- function decrypt($ciphertext)
845
  {
846
- $this->_setup();
847
-
848
- if ($this->paddable) {
849
- // we pad with chr(0) since that's what mcrypt_generic does. to quote from http://php.net/function.mcrypt-generic :
850
- // "The data is padded with "\0" to make sure the length of the data is n * blocksize."
851
- $ciphertext = str_pad($ciphertext, strlen($ciphertext) + ($this->block_size - strlen($ciphertext) % $this->block_size) % $this->block_size, chr(0));
852
- }
853
-
854
- $block_size = $this->block_size;
855
- $buffer = &$this->debuffer;
856
- $continuousBuffer = $this->continuousBuffer;
857
- $plaintext = '';
858
- switch ($this->mode) {
859
- case CRYPT_RIJNDAEL_MODE_ECB:
860
- for ($i = 0; $i < strlen($ciphertext); $i+=$block_size) {
861
- $plaintext.= $this->_decryptBlock(substr($ciphertext, $i, $block_size));
862
- }
863
- break;
864
- case CRYPT_RIJNDAEL_MODE_CBC:
865
- $xor = $this->decryptIV;
866
- for ($i = 0; $i < strlen($ciphertext); $i+=$block_size) {
867
- $block = substr($ciphertext, $i, $block_size);
868
- $plaintext.= $this->_decryptBlock($block) ^ $xor;
869
- $xor = $block;
870
- }
871
- if ($this->continuousBuffer) {
872
- $this->decryptIV = $xor;
873
- }
874
- break;
875
- case CRYPT_RIJNDAEL_MODE_CTR:
876
- $xor = $this->decryptIV;
877
- if (strlen($buffer['ciphertext'])) {
878
- for ($i = 0; $i < strlen($ciphertext); $i+=$block_size) {
879
- $block = substr($ciphertext, $i, $block_size);
880
- $buffer['ciphertext'].= $this->_encryptBlock($this->_generate_xor($block_size, $xor));
881
- $key = $this->_string_shift($buffer['ciphertext'], $block_size);
882
- $plaintext.= $block ^ $key;
883
- }
884
- } else {
885
- for ($i = 0; $i < strlen($ciphertext); $i+=$block_size) {
886
- $block = substr($ciphertext, $i, $block_size);
887
- $key = $this->_encryptBlock($this->_generate_xor($block_size, $xor));
888
- $plaintext.= $block ^ $key;
889
- }
890
- }
891
- if ($this->continuousBuffer) {
892
- $this->decryptIV = $xor;
893
- if ($start = strlen($ciphertext) % $block_size) {
894
- $buffer['ciphertext'] = substr($key, $start) . $buffer['ciphertext'];
895
- }
896
- }
897
- break;
898
- case CRYPT_RIJNDAEL_MODE_CFB:
899
- $iv = $this->decryptIV;
900
- $pos = $this->continuousBuffer === true ? $buffer['pos'] : 0;
901
- $len = strlen($ciphertext);
902
- $i = 0;
903
- if ($pos) {
904
- $orig_pos = $pos;
905
- $max = $block_size - $pos;
906
- if ($len >= $max) {
907
- $i = $max;
908
- $len-= $max;
909
- $pos = 0;
910
- } else {
911
- $i = $len;
912
- $pos+= $len;
913
- $len = 0;
914
- }
915
- // ie. $i = min($max, $len), $len-= $i, $pos+= $i, $pos%= $blocksize
916
- $plaintext = substr($iv, $orig_pos) ^ $ciphertext;
917
- $iv = substr_replace($iv, substr($ciphertext, 0, $i), $orig_pos, $i);
918
- }
919
- while ($len >= $block_size) {
920
- $iv = $this->_encryptBlock($iv);
921
- $cb = substr($ciphertext, $i, $block_size);
922
- $plaintext.= $iv ^ $cb;
923
- $iv = $cb;
924
- $len-= $block_size;
925
- $i+= $block_size;
926
- }
927
- if ($len) {
928
- $iv = $this->_encryptBlock($iv);
929
- $plaintext.= substr($iv, $pos) ^ substr($ciphertext, $i);
930
- $iv = substr_replace($iv, substr($ciphertext, $i, $len), $pos, $len);
931
- $pos+= $len;
932
- }
933
- if ($this->continuousBuffer) {
934
- $this->decryptIV = $iv;
935
- $buffer['pos'] = $pos;
936
- }
937
- break;
938
- case CRYPT_RIJNDAEL_MODE_OFB:
939
- $xor = $this->decryptIV;
940
- if (strlen($buffer['xor'])) {
941
- for ($i = 0; $i < strlen($ciphertext); $i+=$block_size) {
942
- $xor = $this->_encryptBlock($xor);
943
- $buffer['xor'].= $xor;
944
- $key = $this->_string_shift($buffer['xor'], $block_size);
945
- $plaintext.= substr($ciphertext, $i, $block_size) ^ $key;
946
- }
947
- } else {
948
- for ($i = 0; $i < strlen($ciphertext); $i+=$block_size) {
949
- $xor = $this->_encryptBlock($xor);
950
- $plaintext.= substr($ciphertext, $i, $block_size) ^ $xor;
951
- }
952
- $key = $xor;
953
- }
954
- if ($this->continuousBuffer) {
955
- $this->decryptIV = $xor;
956
- if ($start = strlen($ciphertext) % $block_size) {
957
- $buffer['xor'] = substr($key, $start) . $buffer['xor'];
958
- }
959
- }
960
- }
961
-
962
- return $this->paddable ? $this->_unpad($plaintext) : $plaintext;
963
  }
964
 
965
  /**
@@ -971,59 +863,66 @@ class Crypt_Rijndael {
971
  */
972
  function _encryptBlock($in)
973
  {
 
 
 
 
 
 
 
 
 
 
 
974
  $state = array();
975
- $words = unpack('N*word', $in);
976
 
 
977
  $w = $this->w;
978
- $t0 = $this->t0;
979
- $t1 = $this->t1;
980
- $t2 = $this->t2;
981
- $t3 = $this->t3;
982
  $Nb = $this->Nb;
983
  $Nr = $this->Nr;
984
- $c = $this->c;
985
 
986
  // addRoundKey
987
- $i = 0;
988
  foreach ($words as $word) {
989
- $state[] = $word ^ $w[0][$i++];
990
  }
991
 
992
- // fips-197.pdf#page=19, "Figure 5. Pseudo Code for the Cipher", states that this loop has four components -
993
- // subBytes, shiftRows, mixColumns, and addRoundKey. fips-197.pdf#page=30, "Implementation Suggestions Regarding
994
  // Various Platforms" suggests that performs enhanced implementations are described in Rijndael-ammended.pdf.
995
  // Rijndael-ammended.pdf#page=20, "Implementation aspects / 32-bit processor", discusses such an optimization.
996
- // Unfortunately, the description given there is not quite correct. Per aes.spec.v316.pdf#page=19 [1],
997
  // equation (7.4.7) is supposed to use addition instead of subtraction, so we'll do that here, as well.
998
 
999
  // [1] http://fp.gladman.plus.com/cryptography_technology/rijndael/aes.spec.v316.pdf
1000
  $temp = array();
1001
- for ($round = 1; $round < $Nr; $round++) {
1002
  $i = 0; // $c[0] == 0
1003
  $j = $c[1];
1004
  $k = $c[2];
1005
  $l = $c[3];
1006
 
1007
- while ($i < $this->Nb) {
1008
- $temp[$i] = $t0[$state[$i] & 0xFF000000] ^
1009
- $t1[$state[$j] & 0x00FF0000] ^
1010
- $t2[$state[$k] & 0x0000FF00] ^
1011
- $t3[$state[$l] & 0x000000FF] ^
1012
  $w[$round][$i];
1013
- $i++;
1014
  $j = ($j + 1) % $Nb;
1015
  $k = ($k + 1) % $Nb;
1016
  $l = ($l + 1) % $Nb;
1017
  }
1018
-
1019
- for ($i = 0; $i < $Nb; $i++) {
1020
- $state[$i] = $temp[$i];
1021
- }
1022
  }
1023
 
1024
  // subWord
1025
- for ($i = 0; $i < $Nb; $i++) {
1026
- $state[$i] = $this->_subWord($state[$i]);
 
 
 
1027
  }
1028
 
1029
  // shiftRows + addRoundKey
@@ -1031,22 +930,30 @@ class Crypt_Rijndael {
1031
  $j = $c[1];
1032
  $k = $c[2];
1033
  $l = $c[3];
1034
- while ($i < $this->Nb) {
1035
- $temp[$i] = ($state[$i] & 0xFF000000) ^
1036
- ($state[$j] & 0x00FF0000) ^
1037
- ($state[$k] & 0x0000FF00) ^
1038
  ($state[$l] & 0x000000FF) ^
1039
  $w[$Nr][$i];
1040
- $i++;
1041
  $j = ($j + 1) % $Nb;
1042
  $k = ($k + 1) % $Nb;
1043
  $l = ($l + 1) % $Nb;
1044
  }
1045
- $state = $temp;
1046
 
1047
- array_unshift($state, 'N*');
1048
-
1049
- return call_user_func_array('pack', $state);
 
 
 
 
 
 
 
 
 
1050
  }
1051
 
1052
  /**
@@ -1058,47 +965,50 @@ class Crypt_Rijndael {
1058
  */
1059
  function _decryptBlock($in)
1060
  {
 
 
 
 
 
 
 
 
 
 
 
1061
  $state = array();
1062
- $words = unpack('N*word', $in);
1063
 
1064
- $num_states = count($state);
1065
  $dw = $this->dw;
1066
- $dt0 = $this->dt0;
1067
- $dt1 = $this->dt1;
1068
- $dt2 = $this->dt2;
1069
- $dt3 = $this->dt3;
1070
  $Nb = $this->Nb;
1071
  $Nr = $this->Nr;
1072
- $c = $this->c;
1073
 
1074
  // addRoundKey
1075
- $i = 0;
1076
  foreach ($words as $word) {
1077
- $state[] = $word ^ $dw[$Nr][$i++];
1078
  }
1079
 
1080
  $temp = array();
1081
- for ($round = $Nr - 1; $round > 0; $round--) {
1082
  $i = 0; // $c[0] == 0
1083
  $j = $Nb - $c[1];
1084
  $k = $Nb - $c[2];
1085
  $l = $Nb - $c[3];
1086
 
1087
  while ($i < $Nb) {
1088
- $temp[$i] = $dt0[$state[$i] & 0xFF000000] ^
1089
- $dt1[$state[$j] & 0x00FF0000] ^
1090
- $dt2[$state[$k] & 0x0000FF00] ^
1091
- $dt3[$state[$l] & 0x000000FF] ^
1092
  $dw[$round][$i];
1093
- $i++;
1094
  $j = ($j + 1) % $Nb;
1095
  $k = ($k + 1) % $Nb;
1096
  $l = ($l + 1) % $Nb;
1097
  }
1098
-
1099
- for ($i = 0; $i < $Nb; $i++) {
1100
- $state[$i] = $temp[$i];
1101
- }
1102
  }
1103
 
1104
  // invShiftRows + invSubWord + addRoundKey
@@ -1108,33 +1018,42 @@ class Crypt_Rijndael {
1108
  $l = $Nb - $c[3];
1109
 
1110
  while ($i < $Nb) {
1111
- $temp[$i] = $dw[0][$i] ^
1112
- $this->_invSubWord(($state[$i] & 0xFF000000) |
1113
- ($state[$j] & 0x00FF0000) |
1114
- ($state[$k] & 0x0000FF00) |
1115
- ($state[$l] & 0x000000FF));
1116
- $i++;
 
 
 
 
1117
  $j = ($j + 1) % $Nb;
1118
  $k = ($k + 1) % $Nb;
1119
  $l = ($l + 1) % $Nb;
1120
  }
1121
 
1122
- $state = $temp;
1123
-
1124
- array_unshift($state, 'N*');
1125
-
1126
- return call_user_func_array('pack', $state);
 
 
 
 
 
 
 
1127
  }
1128
 
1129
  /**
1130
- * Setup Rijndael
1131
- *
1132
- * Validates all the variables and calculates $Nr - the number of rounds that need to be performed - and $w - the key
1133
- * key schedule.
1134
  *
 
1135
  * @access private
1136
  */
1137
- function _setup()
1138
  {
1139
  // Each number in $rcon is equal to the previous number multiplied by two in Rijndael's finite field.
1140
  // See http://en.wikipedia.org/wiki/Finite_field_arithmetic#Multiplicative_inverse
@@ -1147,25 +1066,15 @@ class Crypt_Rijndael {
1147
  0x7D000000, 0xFA000000, 0xEF000000, 0xC5000000, 0x91000000
1148
  );
1149
 
1150
- if (!$this->changed) {
1151
- return;
1152
- }
1153
 
1154
- if (!$this->explicit_key_length) {
1155
- // we do >> 2, here, and not >> 5, as we do above, since strlen($this->key) tells us the number of bytes - not bits
1156
- $length = strlen($this->key) >> 2;
1157
- if ($length > 8) {
1158
- $length = 8;
1159
- } else if ($length < 4) {
1160
- $length = 4;
1161
- }
1162
- $this->Nk = $length;
1163
- $this->key_size = $length << 2;
1164
  }
 
1165
 
1166
- $this->key = str_pad(substr($this->key, 0, $this->key_size), $this->key_size, chr(0));
1167
- $this->encryptIV = $this->decryptIV = $this->iv = str_pad(substr($this->iv, 0, $this->block_size), $this->block_size, chr(0));
1168
-
1169
  // see Rijndael-ammended.pdf#page=44
1170
  $this->Nr = max($this->Nk, $this->Nb) + 6;
1171
 
@@ -1186,9 +1095,7 @@ class Crypt_Rijndael {
1186
  $this->c = array(0, 1, 3, 4);
1187
  }
1188
 
1189
- $key = $this->key;
1190
-
1191
- $w = array_values(unpack('N*words', $key));
1192
 
1193
  $length = $this->Nb * ($this->Nr + 1);
1194
  for ($i = $this->Nk; $i < $length; $i++) {
@@ -1208,12 +1115,12 @@ class Crypt_Rijndael {
1208
 
1209
  // convert the key schedule from a vector of $Nb * ($Nr + 1) length to a matrix with $Nr + 1 rows and $Nb columns
1210
  // and generate the inverse key schedule. more specifically,
1211
- // according to <http://csrc.nist.gov/archive/aes/rijndael/Rijndael-ammended.pdf#page=23> (section 5.3.3),
1212
  // "The key expansion for the Inverse Cipher is defined as follows:
1213
  // 1. Apply the Key Expansion.
1214
  // 2. Apply InvMixColumn to all Round Keys except the first and the last one."
1215
  // also, see fips-197.pdf#page=27, "5.3.5 Equivalent Inverse Cipher"
1216
- $temp = array();
1217
  for ($i = $row = $col = 0; $i < $length; $i++, $col++) {
1218
  if ($col == $this->Nb) {
1219
  if ($row == 0) {
@@ -1223,10 +1130,10 @@ class Crypt_Rijndael {
1223
  $j = 0;
1224
  while ($j < $this->Nb) {
1225
  $dw = $this->_subWord($this->w[$row][$j]);
1226
- $temp[$j] = $this->dt0[$dw & 0xFF000000] ^
1227
- $this->dt1[$dw & 0x00FF0000] ^
1228
- $this->dt2[$dw & 0x0000FF00] ^
1229
- $this->dt3[$dw & 0x000000FF];
1230
  $j++;
1231
  }
1232
  $this->dw[$row] = $temp;
@@ -1240,263 +1147,202 @@ class Crypt_Rijndael {
1240
 
1241
  $this->dw[$row] = $this->w[$row];
1242
 
1243
- $this->changed = false;
 
 
 
 
 
 
 
 
 
 
 
 
 
1244
  }
1245
 
1246
  /**
1247
  * Performs S-Box substitutions
1248
  *
1249
  * @access private
 
1250
  */
1251
  function _subWord($word)
1252
  {
1253
- static $sbox0, $sbox1, $sbox2, $sbox3;
1254
-
1255
- if (empty($sbox0)) {
1256
- $sbox0 = array(
1257
- 0x63, 0x7C, 0x77, 0x7B, 0xF2, 0x6B, 0x6F, 0xC5, 0x30, 0x01, 0x67, 0x2B, 0xFE, 0xD7, 0xAB, 0x76,
1258
- 0xCA, 0x82, 0xC9, 0x7D, 0xFA, 0x59, 0x47, 0xF0, 0xAD, 0xD4, 0xA2, 0xAF, 0x9C, 0xA4, 0x72, 0xC0,
1259
- 0xB7, 0xFD, 0x93, 0x26, 0x36, 0x3F, 0xF7, 0xCC, 0x34, 0xA5, 0xE5, 0xF1, 0x71, 0xD8, 0x31, 0x15,
1260
- 0x04, 0xC7, 0x23, 0xC3, 0x18, 0x96, 0x05, 0x9A, 0x07, 0x12, 0x80, 0xE2, 0xEB, 0x27, 0xB2, 0x75,
1261
- 0x09, 0x83, 0x2C, 0x1A, 0x1B, 0x6E, 0x5A, 0xA0, 0x52, 0x3B, 0xD6, 0xB3, 0x29, 0xE3, 0x2F, 0x84,
1262
- 0x53, 0xD1, 0x00, 0xED, 0x20, 0xFC, 0xB1, 0x5B, 0x6A, 0xCB, 0xBE, 0x39, 0x4A, 0x4C, 0x58, 0xCF,
1263
- 0xD0, 0xEF, 0xAA, 0xFB, 0x43, 0x4D, 0x33, 0x85, 0x45, 0xF9, 0x02, 0x7F, 0x50, 0x3C, 0x9F, 0xA8,
1264
- 0x51, 0xA3, 0x40, 0x8F, 0x92, 0x9D, 0x38, 0xF5, 0xBC, 0xB6, 0xDA, 0x21, 0x10, 0xFF, 0xF3, 0xD2,
1265
- 0xCD, 0x0C, 0x13, 0xEC, 0x5F, 0x97, 0x44, 0x17, 0xC4, 0xA7, 0x7E, 0x3D, 0x64, 0x5D, 0x19, 0x73,
1266
- 0x60, 0x81, 0x4F, 0xDC, 0x22, 0x2A, 0x90, 0x88, 0x46, 0xEE, 0xB8, 0x14, 0xDE, 0x5E, 0x0B, 0xDB,
1267
- 0xE0, 0x32, 0x3A, 0x0A, 0x49, 0x06, 0x24, 0x5C, 0xC2, 0xD3, 0xAC, 0x62, 0x91, 0x95, 0xE4, 0x79,
1268
- 0xE7, 0xC8, 0x37, 0x6D, 0x8D, 0xD5, 0x4E, 0xA9, 0x6C, 0x56, 0xF4, 0xEA, 0x65, 0x7A, 0xAE, 0x08,
1269
- 0xBA, 0x78, 0x25, 0x2E, 0x1C, 0xA6, 0xB4, 0xC6, 0xE8, 0xDD, 0x74, 0x1F, 0x4B, 0xBD, 0x8B, 0x8A,
1270
- 0x70, 0x3E, 0xB5, 0x66, 0x48, 0x03, 0xF6, 0x0E, 0x61, 0x35, 0x57, 0xB9, 0x86, 0xC1, 0x1D, 0x9E,
1271
- 0xE1, 0xF8, 0x98, 0x11, 0x69, 0xD9, 0x8E, 0x94, 0x9B, 0x1E, 0x87, 0xE9, 0xCE, 0x55, 0x28, 0xDF,
1272
- 0x8C, 0xA1, 0x89, 0x0D, 0xBF, 0xE6, 0x42, 0x68, 0x41, 0x99, 0x2D, 0x0F, 0xB0, 0x54, 0xBB, 0x16
1273
- );
1274
-
1275
- $sbox1 = array();
1276
- $sbox2 = array();
1277
- $sbox3 = array();
1278
-
1279
- for ($i = 0; $i < 256; $i++) {
1280
- $sbox1[$i << 8] = $sbox0[$i] << 8;
1281
- $sbox2[$i << 16] = $sbox0[$i] << 16;
1282
- $sbox3[$i << 24] = $sbox0[$i] << 24;
1283
- }
1284
- }
1285
 
1286
- return $sbox0[$word & 0x000000FF] |
1287
- $sbox1[$word & 0x0000FF00] |
1288
- $sbox2[$word & 0x00FF0000] |
1289
- $sbox3[$word & 0xFF000000];
1290
  }
1291
 
1292
  /**
1293
- * Performs inverse S-Box substitutions
1294
  *
 
1295
  * @access private
1296
  */
1297
- function _invSubWord($word)
1298
  {
1299
- static $sbox0, $sbox1, $sbox2, $sbox3;
1300
-
1301
- if (empty($sbox0)) {
1302
- $sbox0 = array(
1303
- 0x52, 0x09, 0x6A, 0xD5, 0x30, 0x36, 0xA5, 0x38, 0xBF, 0x40, 0xA3, 0x9E, 0x81, 0xF3, 0xD7, 0xFB,
1304
- 0x7C, 0xE3, 0x39, 0x82, 0x9B, 0x2F, 0xFF, 0x87, 0x34, 0x8E, 0x43, 0x44, 0xC4, 0xDE, 0xE9, 0xCB,
1305
- 0x54, 0x7B, 0x94, 0x32, 0xA6, 0xC2, 0x23, 0x3D, 0xEE, 0x4C, 0x95, 0x0B, 0x42, 0xFA, 0xC3, 0x4E,
1306
- 0x08, 0x2E, 0xA1, 0x66, 0x28, 0xD9, 0x24, 0xB2, 0x76, 0x5B, 0xA2, 0x49, 0x6D, 0x8B, 0xD1, 0x25,
1307
- 0x72, 0xF8, 0xF6, 0x64, 0x86, 0x68, 0x98, 0x16, 0xD4, 0xA4, 0x5C, 0xCC, 0x5D, 0x65, 0xB6, 0x92,
1308
- 0x6C, 0x70, 0x48, 0x50, 0xFD, 0xED, 0xB9, 0xDA, 0x5E, 0x15, 0x46, 0x57, 0xA7, 0x8D, 0x9D, 0x84,
1309
- 0x90, 0xD8, 0xAB, 0x00, 0x8C, 0xBC, 0xD3, 0x0A, 0xF7, 0xE4, 0x58, 0x05, 0xB8, 0xB3, 0x45, 0x06,
1310
- 0xD0, 0x2C, 0x1E, 0x8F, 0xCA, 0x3F, 0x0F, 0x02, 0xC1, 0xAF, 0xBD, 0x03, 0x01, 0x13, 0x8A, 0x6B,
1311
- 0x3A, 0x91, 0x11, 0x41, 0x4F, 0x67, 0xDC, 0xEA, 0x97, 0xF2, 0xCF, 0xCE, 0xF0, 0xB4, 0xE6, 0x73,
1312
- 0x96, 0xAC, 0x74, 0x22, 0xE7, 0xAD, 0x35, 0x85, 0xE2, 0xF9, 0x37, 0xE8, 0x1C, 0x75, 0xDF, 0x6E,
1313
- 0x47, 0xF1, 0x1A, 0x71, 0x1D, 0x29, 0xC5, 0x89, 0x6F, 0xB7, 0x62, 0x0E, 0xAA, 0x18, 0xBE, 0x1B,
1314
- 0xFC, 0x56, 0x3E, 0x4B, 0xC6, 0xD2, 0x79, 0x20, 0x9A, 0xDB, 0xC0, 0xFE, 0x78, 0xCD, 0x5A, 0xF4,
1315
- 0x1F, 0xDD, 0xA8, 0x33, 0x88, 0x07, 0xC7, 0x31, 0xB1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xEC, 0x5F,
1316
- 0x60, 0x51, 0x7F, 0xA9, 0x19, 0xB5, 0x4A, 0x0D, 0x2D, 0xE5, 0x7A, 0x9F, 0x93, 0xC9, 0x9C, 0xEF,
1317
- 0xA0, 0xE0, 0x3B, 0x4D, 0xAE, 0x2A, 0xF5, 0xB0, 0xC8, 0xEB, 0xBB, 0x3C, 0x83, 0x53, 0x99, 0x61,
1318
- 0x17, 0x2B, 0x04, 0x7E, 0xBA, 0x77, 0xD6, 0x26, 0xE1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0C, 0x7D
1319
- );
1320
-
1321
- $sbox1 = array();
1322
- $sbox2 = array();
1323
- $sbox3 = array();
1324
-
1325
- for ($i = 0; $i < 256; $i++) {
1326
- $sbox1[$i << 8] = $sbox0[$i] << 8;
1327
- $sbox2[$i << 16] = $sbox0[$i] << 16;
1328
- $sbox3[$i << 24] = $sbox0[$i] << 24;
1329
  }
 
 
1330
  }
1331
 
1332
- return $sbox0[$word & 0x000000FF] |
1333
- $sbox1[$word & 0x0000FF00] |
1334
- $sbox2[$word & 0x00FF0000] |
1335
- $sbox3[$word & 0xFF000000];
1336
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1337
 
1338
- /**
1339
- * Pad "packets".
1340
- *
1341
- * Rijndael works by encrypting between sixteen and thirty-two bytes at a time, provided that number is also a multiple
1342
- * of four. If you ever need to encrypt or decrypt something that isn't of the proper length, it becomes necessary to
1343
- * pad the input so that it is of the proper length.
1344
- *
1345
- * Padding is enabled by default. Sometimes, however, it is undesirable to pad strings. Such is the case in SSH,
1346
- * where "packets" are padded with random bytes before being encrypted. Unpad these packets and you risk stripping
1347
- * away characters that shouldn't be stripped away. (SSH knows how many bytes are added because the length is
1348
- * transmitted separately)
1349
- *
1350
- * @see Crypt_Rijndael::disablePadding()
1351
- * @access public
1352
- */
1353
- function enablePadding()
1354
- {
1355
- $this->padding = true;
1356
- }
1357
 
1358
- /**
1359
- * Do not pad packets.
1360
- *
1361
- * @see Crypt_Rijndael::enablePadding()
1362
- * @access public
1363
- */
1364
- function disablePadding()
1365
- {
1366
- $this->padding = false;
1367
- }
1368
 
1369
- /**
1370
- * Pads a string
1371
- *
1372
- * Pads a string using the RSA PKCS padding standards so that its length is a multiple of the blocksize.
1373
- * $block_size - (strlen($text) % $block_size) bytes are added, each of which is equal to
1374
- * chr($block_size - (strlen($text) % $block_size)
1375
- *
1376
- * If padding is disabled and $text is not a multiple of the blocksize, the string will be padded regardless
1377
- * and padding will, hence forth, be enabled.
1378
- *
1379
- * @see Crypt_Rijndael::_unpad()
1380
- * @access private
1381
- */
1382
- function _pad($text)
1383
- {
1384
- $length = strlen($text);
1385
-
1386
- if (!$this->padding) {
1387
- if ($length % $this->block_size == 0) {
1388
- return $text;
1389
- } else {
1390
- user_error("The plaintext's length ($length) is not a multiple of the block size ({$this->block_size})");
1391
- $this->padding = true;
1392
  }
1393
- }
1394
 
1395
- $pad = $this->block_size - ($length % $this->block_size);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1396
 
1397
- return str_pad($text, $length + $pad, chr($pad));
1398
- }
 
1399
 
1400
- /**
1401
- * Unpads a string.
1402
- *
1403
- * If padding is enabled and the reported padding length is invalid the encryption key will be assumed to be wrong
1404
- * and false will be returned.
1405
- *
1406
- * @see Crypt_Rijndael::_pad()
1407
- * @access private
1408
- */
1409
- function _unpad($text)
1410
- {
1411
- if (!$this->padding) {
1412
- return $text;
1413
- }
1414
 
1415
- $length = ord($text[strlen($text) - 1]);
 
 
 
 
 
 
 
 
 
 
 
 
1416
 
1417
- if (!$length || $length > $this->block_size) {
1418
- return false;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1419
  }
1420
-
1421
- return substr($text, 0, -$length);
1422
- }
1423
-
1424
- /**
1425
- * Treat consecutive "packets" as if they are a continuous buffer.
1426
- *
1427
- * Say you have a 32-byte plaintext $plaintext. Using the default behavior, the two following code snippets
1428
- * will yield different outputs:
1429
- *
1430
- * <code>
1431
- * echo $rijndael->encrypt(substr($plaintext, 0, 16));
1432
- * echo $rijndael->encrypt(substr($plaintext, 16, 16));
1433
- * </code>
1434
- * <code>
1435
- * echo $rijndael->encrypt($plaintext);
1436
- * </code>
1437
- *
1438
- * The solution is to enable the continuous buffer. Although this will resolve the above discrepancy, it creates
1439
- * another, as demonstrated with the following:
1440
- *
1441
- * <code>
1442
- * $rijndael->encrypt(substr($plaintext, 0, 16));
1443
- * echo $rijndael->decrypt($des->encrypt(substr($plaintext, 16, 16)));
1444
- * </code>
1445
- * <code>
1446
- * echo $rijndael->decrypt($des->encrypt(substr($plaintext, 16, 16)));
1447
- * </code>
1448
- *
1449
- * With the continuous buffer disabled, these would yield the same output. With it enabled, they yield different
1450
- * outputs. The reason is due to the fact that the initialization vector's change after every encryption /
1451
- * decryption round when the continuous buffer is enabled. When it's disabled, they remain constant.
1452
- *
1453
- * Put another way, when the continuous buffer is enabled, the state of the Crypt_Rijndael() object changes after each
1454
- * encryption / decryption round, whereas otherwise, it'd remain constant. For this reason, it's recommended that
1455
- * continuous buffers not be used. They do offer better security and are, in fact, sometimes required (SSH uses them),
1456
- * however, they are also less intuitive and more likely to cause you problems.
1457
- *
1458
- * @see Crypt_Rijndael::disableContinuousBuffer()
1459
- * @access public
1460
- */
1461
- function enableContinuousBuffer()
1462
- {
1463
- $this->continuousBuffer = true;
1464
- }
1465
-
1466
- /**
1467
- * Treat consecutive packets as if they are a discontinuous buffer.
1468
- *
1469
- * The default behavior.
1470
- *
1471
- * @see Crypt_Rijndael::enableContinuousBuffer()
1472
- * @access public
1473
- */
1474
- function disableContinuousBuffer()
1475
- {
1476
- $this->continuousBuffer = false;
1477
- $this->encryptIV = $this->iv;
1478
- $this->decryptIV = $this->iv;
1479
- $this->enbuffer = array('encrypted' => '', 'xor' => '', 'pos' => 0);
1480
- $this->debuffer = array('ciphertext' => '', 'xor' => '', 'pos' => 0);
1481
- }
1482
-
1483
- /**
1484
- * String Shift
1485
- *
1486
- * Inspired by array_shift
1487
- *
1488
- * @param String $string
1489
- * @param optional Integer $index
1490
- * @return String
1491
- * @access private
1492
- */
1493
- function _string_shift(&$string, $index = 1)
1494
- {
1495
- $substr = substr($string, 0, $index);
1496
- $string = substr($string, $index);
1497
- return $substr;
1498
  }
1499
  }
1500
-
1501
- // vim: ts=4:sw=4:et:
1502
- // vim6: fdl=1:
1
  <?php
 
2
 
3
  /**
4
  * Pure-PHP implementation of Rijndael.
5
  *
6
+ * Uses mcrypt, if available/possible, and an internal implementation, otherwise.
7
  *
8
  * PHP versions 4 and 5
9
  *
10
+ * If {@link Crypt_Rijndael::setBlockLength() setBlockLength()} isn't called, it'll be assumed to be 128 bits. If
11
+ * {@link Crypt_Rijndael::setKeyLength() setKeyLength()} isn't called, it'll be calculated from
12
+ * {@link Crypt_Rijndael::setKey() setKey()}. ie. if the key is 128-bits, the key length will be 128-bits. If it's
13
+ * 136-bits it'll be null-padded to 192-bits and 192 bits will be the key length until
14
  * {@link Crypt_Rijndael::setKey() setKey()} is called, again, at which point, it'll be recalculated.
15
  *
16
  * Not all Rijndael implementations may support 160-bits or 224-bits as the block length / key length. mcrypt, for example,
17
  * does not. AES, itself, only supports block lengths of 128 and key lengths of 128, 192, and 256.
18
  * {@link http://csrc.nist.gov/archive/aes/rijndael/Rijndael-ammended.pdf#page=10 Rijndael-ammended.pdf#page=10} defines the
19
  * algorithm for block lengths of 192 and 256 but not for block lengths / key lengths of 160 and 224. Indeed, 160 and 224
20
+ * are first defined as valid key / block lengths in
21
+ * {@link http://csrc.nist.gov/archive/aes/rijndael/Rijndael-ammended.pdf#page=44 Rijndael-ammended.pdf#page=44}:
22
  * Extensions: Other block and Cipher Key lengths.
23
+ * Note: Use of 160/224-bit Keys must be explicitly set by setKeyLength(160) respectively setKeyLength(224).
24
  *
25
+ * {@internal The variable names are the same as those in
26
  * {@link http://www.csrc.nist.gov/publications/fips/fips197/fips-197.pdf#page=10 fips-197.pdf#page=10}.}}
27
  *
28
  * Here's a short example of how to use this library:
29
  * <code>
30
  * <?php
31
+ * include 'Crypt/Rijndael.php';
32
  *
33
  * $rijndael = new Crypt_Rijndael();
34
  *
50
  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
51
  * copies of the Software, and to permit persons to whom the Software is
52
  * furnished to do so, subject to the following conditions:
53
+ *
54
  * The above copyright notice and this permission notice shall be included in
55
  * all copies or substantial portions of the Software.
56
+ *
57
  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
58
  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
59
  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
62
  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
63
  * THE SOFTWARE.
64
  *
65
+ * @category Crypt
66
+ * @package Crypt_Rijndael
67
+ * @author Jim Wigginton <terrafrost@php.net>
68
+ * @copyright MMVIII Jim Wigginton
69
+ * @license http://www.opensource.org/licenses/mit-license.html MIT License
70
+ * @link http://phpseclib.sourceforge.net
 
71
  */
72
 
73
+ /**
74
+ * Include Crypt_Base
75
+ *
76
+ * Base cipher class
77
+ */
78
+ if (!class_exists('Crypt_Base')) {
79
+ include_once 'Base.php';
80
+ }
81
+
82
  /**#@+
83
  * @access public
84
  * @see Crypt_Rijndael::encrypt()
91
  *
92
  * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Counter_.28CTR.29
93
  */
94
+ define('CRYPT_RIJNDAEL_MODE_CTR', CRYPT_MODE_CTR);
95
  /**
96
  * Encrypt / decrypt using the Electronic Code Book mode.
97
  *
98
  * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Electronic_codebook_.28ECB.29
99
  */
100
+ define('CRYPT_RIJNDAEL_MODE_ECB', CRYPT_MODE_ECB);
101
  /**
102
  * Encrypt / decrypt using the Code Book Chaining mode.
103
  *
104
  * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Cipher-block_chaining_.28CBC.29
105
  */
106
+ define('CRYPT_RIJNDAEL_MODE_CBC', CRYPT_MODE_CBC);
107
  /**
108
  * Encrypt / decrypt using the Cipher Feedback mode.
109
  *
110
  * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Cipher_feedback_.28CFB.29
111
  */
112
+ define('CRYPT_RIJNDAEL_MODE_CFB', CRYPT_MODE_CFB);
113
  /**
114
  * Encrypt / decrypt using the Cipher Feedback mode.
115
  *
116
  * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Output_feedback_.28OFB.29
117
  */
118
+ define('CRYPT_RIJNDAEL_MODE_OFB', CRYPT_MODE_OFB);
119
  /**#@-*/
120
 
121
  /**#@+
122
  * @access private
123
+ * @see Crypt_Base::Crypt_Base()
124
  */
125
  /**
126
  * Toggles the internal implementation
127
  */
128
+ define('CRYPT_RIJNDAEL_MODE_INTERNAL', CRYPT_MODE_INTERNAL);
129
  /**
130
  * Toggles the mcrypt implementation
131
  */
132
+ define('CRYPT_RIJNDAEL_MODE_MCRYPT', CRYPT_MODE_MCRYPT);
133
  /**#@-*/
134
 
135
  /**
136
  * Pure-PHP implementation of Rijndael.
137
  *
138
+ * @package Crypt_Rijndael
139
  * @author Jim Wigginton <terrafrost@php.net>
 
140
  * @access public
 
141
  */
142
+ class Crypt_Rijndael extends Crypt_Base
143
+ {
144
  /**
145
+ * The default password key_size used by setPassword()
146
  *
147
+ * @see Crypt_Base::password_key_size
148
+ * @see Crypt_Base::setPassword()
149
  * @var Integer
150
  * @access private
151
  */
152
+ var $password_key_size = 16;
153
 
154
  /**
155
+ * The namespace used by the cipher for its constants.
156
  *
157
+ * @see Crypt_Base::const_namespace
158
  * @var String
159
  * @access private
160
  */
161
+ var $const_namespace = 'RIJNDAEL';
162
 
163
  /**
164
+ * The mcrypt specific name of the cipher
165
  *
166
+ * Mcrypt is useable for 128/192/256-bit $block_size/$key_size. For 160/224 not.
167
+ * Crypt_Rijndael determines automatically whether mcrypt is useable
168
+ * or not for the current $block_size/$key_size.
169
+ * In case of, $cipher_name_mcrypt will be set dynamically at run time accordingly.
 
 
 
 
170
  *
171
+ * @see Crypt_Base::cipher_name_mcrypt
172
+ * @see Crypt_Base::engine
173
+ * @see _setupEngine()
174
  * @var String
175
  * @access private
176
  */
177
+ var $cipher_name_mcrypt = 'rijndael-128';
178
 
179
  /**
180
+ * The default salt used by setPassword()
181
  *
182
+ * @see Crypt_Base::password_default_salt
183
+ * @see Crypt_Base::setPassword()
184
  * @var String
185
  * @access private
186
  */
187
+ var $password_default_salt = 'phpseclib';
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
188
 
189
  /**
190
  * Has the key length explicitly been set or should it be derived from the key, itself?
213
  */
214
  var $dw;
215
 
 
 
 
 
 
 
 
 
 
 
 
216
  /**
217
  * The Block Length divided by 32
218
  *
219
  * @see setBlockLength()
220
  * @var Integer
221
  * @access private
222
+ * @internal The max value is 256 / 32 = 8, the min value is 128 / 32 = 4. Exists in conjunction with $block_size
223
+ * because the encryption / decryption / key schedule creation requires this number and not $block_size. We could
224
  * derive this from $block_size or vice versa, but that'd mean we'd have to do multiple shift operations, so in lieu
225
  * of that, we'll just precompute it once.
226
  *
233
  * @see setKeyLength()
234
  * @var Integer
235
  * @access private
236
+ * @internal The max value is 256 / 8 = 32, the min value is 128 / 8 = 16. Exists in conjunction with $Nk
237
+ * because the encryption / decryption / key schedule creation requires this number and not $key_size. We could
238
  * derive this from $key_size or vice versa, but that'd mean we'd have to do multiple shift operations, so in lieu
239
  * of that, we'll just precompute it once.
240
  */
268
  var $c;
269
 
270
  /**
271
+ * Holds the last used key- and block_size information
272
  *
 
273
  * @var Array
274
  * @access private
275
  */
276
+ var $kl;
277
 
278
  /**
279
  * Precomputed mixColumns table
280
  *
281
+ * According to <http://csrc.nist.gov/archive/aes/rijndael/Rijndael-ammended.pdf#page=19> (section 5.2.1),
282
+ * precomputed tables can be used in the mixColumns phase. in that example, they're assigned t0...t3, so
283
+ * those are the names we'll use.
284
+ *
285
+ * @see Crypt_Rijndael:_encryptBlock()
286
+ * @see Crypt_Rijndael:_decryptBlock()
287
  * @var Array
288
  * @access private
289
  */
290
+ var $t0 = array(
291
+ 0xC66363A5, 0xF87C7C84, 0xEE777799, 0xF67B7B8D, 0xFFF2F20D, 0xD66B6BBD, 0xDE6F6FB1, 0x91C5C554,
292
+ 0x60303050, 0x02010103, 0xCE6767A9, 0x562B2B7D, 0xE7FEFE19, 0xB5D7D762, 0x4DABABE6, 0xEC76769A,
293
+ 0x8FCACA45, 0x1F82829D, 0x89C9C940, 0xFA7D7D87, 0xEFFAFA15, 0xB25959EB, 0x8E4747C9, 0xFBF0F00B,
294
+ 0x41ADADEC, 0xB3D4D467, 0x5FA2A2FD, 0x45AFAFEA, 0x239C9CBF, 0x53A4A4F7, 0xE4727296, 0x9BC0C05B,
295
+ 0x75B7B7C2, 0xE1FDFD1C, 0x3D9393AE, 0x4C26266A, 0x6C36365A, 0x7E3F3F41, 0xF5F7F702, 0x83CCCC4F,
296
+ 0x6834345C, 0x51A5A5F4, 0xD1E5E534, 0xF9F1F108, 0xE2717193, 0xABD8D873, 0x62313153, 0x2A15153F,
297
+ 0x0804040C, 0x95C7C752, 0x46232365, 0x9DC3C35E, 0x30181828, 0x379696A1, 0x0A05050F, 0x2F9A9AB5,
298
+ 0x0E070709, 0x24121236, 0x1B80809B, 0xDFE2E23D, 0xCDEBEB26, 0x4E272769, 0x7FB2B2CD, 0xEA75759F,
299
+ 0x1209091B, 0x1D83839E, 0x582C2C74, 0x341A1A2E, 0x361B1B2D, 0xDC6E6EB2, 0xB45A5AEE, 0x5BA0A0FB,
300
+ 0xA45252F6, 0x763B3B4D, 0xB7D6D661, 0x7DB3B3CE, 0x5229297B, 0xDDE3E33E, 0x5E2F2F71, 0x13848497,
301
+ 0xA65353F5, 0xB9D1D168, 0x00000000, 0xC1EDED2C, 0x40202060, 0xE3FCFC1F, 0x79B1B1C8, 0xB65B5BED,
302
+ 0xD46A6ABE, 0x8DCBCB46, 0x67BEBED9, 0x7239394B, 0x944A4ADE, 0x984C4CD4, 0xB05858E8, 0x85CFCF4A,
303
+ 0xBBD0D06B, 0xC5EFEF2A, 0x4FAAAAE5, 0xEDFBFB16, 0x864343C5, 0x9A4D4DD7, 0x66333355, 0x11858594,
304
+ 0x8A4545CF, 0xE9F9F910, 0x04020206, 0xFE7F7F81, 0xA05050F0, 0x783C3C44, 0x259F9FBA, 0x4BA8A8E3,
305
+ 0xA25151F3, 0x5DA3A3FE, 0x804040C0, 0x058F8F8A, 0x3F9292AD, 0x219D9DBC, 0x70383848, 0xF1F5F504,
306
+ 0x63BCBCDF, 0x77B6B6C1, 0xAFDADA75, 0x42212163, 0x20101030, 0xE5FFFF1A, 0xFDF3F30E, 0xBFD2D26D,
307
+ 0x81CDCD4C, 0x180C0C14, 0x26131335, 0xC3ECEC2F, 0xBE5F5FE1, 0x359797A2, 0x884444CC, 0x2E171739,
308
+ 0x93C4C457, 0x55A7A7F2, 0xFC7E7E82, 0x7A3D3D47, 0xC86464AC, 0xBA5D5DE7, 0x3219192B, 0xE6737395,
309
+ 0xC06060A0, 0x19818198, 0x9E4F4FD1, 0xA3DCDC7F, 0x44222266, 0x542A2A7E, 0x3B9090AB, 0x0B888883,
310
+ 0x8C4646CA, 0xC7EEEE29, 0x6BB8B8D3, 0x2814143C, 0xA7DEDE79, 0xBC5E5EE2, 0x160B0B1D, 0xADDBDB76,
311
+ 0xDBE0E03B, 0x64323256, 0x743A3A4E, 0x140A0A1E, 0x924949DB, 0x0C06060A, 0x4824246C, 0xB85C5CE4,
312
+ 0x9FC2C25D, 0xBDD3D36E, 0x43ACACEF, 0xC46262A6, 0x399191A8, 0x319595A4, 0xD3E4E437, 0xF279798B,
313
+ 0xD5E7E732, 0x8BC8C843, 0x6E373759, 0xDA6D6DB7, 0x018D8D8C, 0xB1D5D564, 0x9C4E4ED2, 0x49A9A9E0,
314
+ 0xD86C6CB4, 0xAC5656FA, 0xF3F4F407, 0xCFEAEA25, 0xCA6565AF, 0xF47A7A8E, 0x47AEAEE9, 0x10080818,
315
+ 0x6FBABAD5, 0xF0787888, 0x4A25256F, 0x5C2E2E72, 0x381C1C24, 0x57A6A6F1, 0x73B4B4C7, 0x97C6C651,
316
+ 0xCBE8E823, 0xA1DDDD7C, 0xE874749C, 0x3E1F1F21, 0x964B4BDD, 0x61BDBDDC, 0x0D8B8B86, 0x0F8A8A85,
317
+ 0xE0707090, 0x7C3E3E42, 0x71B5B5C4, 0xCC6666AA, 0x904848D8, 0x06030305, 0xF7F6F601, 0x1C0E0E12,
318
+ 0xC26161A3, 0x6A35355F, 0xAE5757F9, 0x69B9B9D0, 0x17868691, 0x99C1C158, 0x3A1D1D27, 0x279E9EB9,
319
+ 0xD9E1E138, 0xEBF8F813, 0x2B9898B3, 0x22111133, 0xD26969BB, 0xA9D9D970, 0x078E8E89, 0x339494A7,
320
+ 0x2D9B9BB6, 0x3C1E1E22, 0x15878792, 0xC9E9E920, 0x87CECE49, 0xAA5555FF, 0x50282878, 0xA5DFDF7A,
321
+ 0x038C8C8F, 0x59A1A1F8, 0x09898980, 0x1A0D0D17, 0x65BFBFDA, 0xD7E6E631, 0x844242C6, 0xD06868B8,
322
+ 0x824141C3, 0x299999B0, 0x5A2D2D77, 0x1E0F0F11, 0x7BB0B0CB, 0xA85454FC, 0x6DBBBBD6, 0x2C16163A
323
+ );
324
 
325
  /**
326
  * Precomputed mixColumns table
327
  *
328
+ * @see Crypt_Rijndael:_encryptBlock()
329
+ * @see Crypt_Rijndael:_decryptBlock()
330
  * @var Array
331
  * @access private
332
  */
333
+ var $t1 = array(
334
+ 0xA5C66363, 0x84F87C7C, 0x99EE7777, 0x8DF67B7B, 0x0DFFF2F2, 0xBDD66B6B, 0xB1DE6F6F, 0x5491C5C5,
335
+ 0x50603030, 0x03020101, 0xA9CE6767, 0x7D562B2B, 0x19E7FEFE, 0x62B5D7D7, 0xE64DABAB, 0x9AEC7676,
336
+ 0x458FCACA, 0x9D1F8282, 0x4089C9C9, 0x87FA7D7D, 0x15EFFAFA, 0xEBB25959, 0xC98E4747, 0x0BFBF0F0,
337
+ 0xEC41ADAD, 0x67B3D4D4, 0xFD5FA2A2, 0xEA45AFAF, 0xBF239C9C, 0xF753A4A4, 0x96E47272, 0x5B9BC0C0,
338
+ 0xC275B7B7, 0x1CE1FDFD, 0xAE3D9393, 0x6A4C2626, 0x5A6C3636, 0x417E3F3F, 0x02F5F7F7, 0x4F83CCCC,
339
+ 0x5C683434, 0xF451A5A5, 0x34D1E5E5, 0x08F9F1F1, 0x93E27171, 0x73ABD8D8, 0x53623131, 0x3F2A1515,
340
+ 0x0C080404, 0x5295C7C7, 0x65462323, 0x5E9DC3C3, 0x28301818, 0xA1379696, 0x0F0A0505, 0xB52F9A9A,
341
+ 0x090E0707, 0x36241212, 0x9B1B8080, 0x3DDFE2E2, 0x26CDEBEB, 0x694E2727, 0xCD7FB2B2, 0x9FEA7575,
342
+ 0x1B120909, 0x9E1D8383, 0x74582C2C, 0x2E341A1A, 0x2D361B1B, 0xB2DC6E6E, 0xEEB45A5A, 0xFB5BA0A0,
343
+ 0xF6A45252, 0x4D763B3B, 0x61B7D6D6, 0xCE7DB3B3, 0x7B522929, 0x3EDDE3E3, 0x715E2F2F, 0x97138484,
344
+ 0xF5A65353, 0x68B9D1D1, 0x00000000, 0x2CC1EDED, 0x60402020, 0x1FE3FCFC, 0xC879B1B1, 0xEDB65B5B,
345
+ 0xBED46A6A, 0x468DCBCB, 0xD967BEBE, 0x4B723939, 0xDE944A4A, 0xD4984C4C, 0xE8B05858, 0x4A85CFCF,
346
+ 0x6BBBD0D0, 0x2AC5EFEF, 0xE54FAAAA, 0x16EDFBFB, 0xC5864343, 0xD79A4D4D, 0x55663333, 0x94118585,
347
+ 0xCF8A4545, 0x10E9F9F9, 0x06040202, 0x81FE7F7F, 0xF0A05050, 0x44783C3C, 0xBA259F9F, 0xE34BA8A8,
348
+ 0xF3A25151, 0xFE5DA3A3, 0xC0804040, 0x8A058F8F, 0xAD3F9292, 0xBC219D9D, 0x48703838, 0x04F1F5F5,
349
+ 0xDF63BCBC, 0xC177B6B6, 0x75AFDADA, 0x63422121, 0x30201010, 0x1AE5FFFF, 0x0EFDF3F3, 0x6DBFD2D2,
350
+ 0x4C81CDCD, 0x14180C0C, 0x35261313, 0x2FC3ECEC, 0xE1BE5F5F, 0xA2359797, 0xCC884444, 0x392E1717,
351
+ 0x5793C4C4, 0xF255A7A7, 0x82FC7E7E, 0x477A3D3D, 0xACC86464, 0xE7BA5D5D, 0x2B321919, 0x95E67373,
352
+ 0xA0C06060, 0x98198181, 0xD19E4F4F, 0x7FA3DCDC, 0x66442222, 0x7E542A2A, 0xAB3B9090, 0x830B8888,
353
+ 0xCA8C4646, 0x29C7EEEE, 0xD36BB8B8, 0x3C281414, 0x79A7DEDE, 0xE2BC5E5E, 0x1D160B0B, 0x76ADDBDB,
354
+ 0x3BDBE0E0, 0x56643232, 0x4E743A3A, 0x1E140A0A, 0xDB924949, 0x0A0C0606, 0x6C482424, 0xE4B85C5C,
355
+ 0x5D9FC2C2, 0x6EBDD3D3, 0xEF43ACAC, 0xA6C46262, 0xA8399191, 0xA4319595, 0x37D3E4E4, 0x8BF27979,
356
+ 0x32D5E7E7, 0x438BC8C8, 0x596E3737, 0xB7DA6D6D, 0x8C018D8D, 0x64B1D5D5, 0xD29C4E4E, 0xE049A9A9,
357
+ 0xB4D86C6C, 0xFAAC5656, 0x07F3F4F4, 0x25CFEAEA, 0xAFCA6565, 0x8EF47A7A, 0xE947AEAE, 0x18100808,
358
+ 0xD56FBABA, 0x88F07878, 0x6F4A2525, 0x725C2E2E, 0x24381C1C, 0xF157A6A6, 0xC773B4B4, 0x5197C6C6,
359
+ 0x23CBE8E8, 0x7CA1DDDD, 0x9CE87474, 0x213E1F1F, 0xDD964B4B, 0xDC61BDBD, 0x860D8B8B, 0x850F8A8A,
360
+ 0x90E07070, 0x427C3E3E, 0xC471B5B5, 0xAACC6666, 0xD8904848, 0x05060303, 0x01F7F6F6, 0x121C0E0E,
361
+ 0xA3C26161, 0x5F6A3535, 0xF9AE5757, 0xD069B9B9, 0x91178686, 0x5899C1C1, 0x273A1D1D, 0xB9279E9E,
362
+ 0x38D9E1E1, 0x13EBF8F8, 0xB32B9898, 0x33221111, 0xBBD26969, 0x70A9D9D9, 0x89078E8E, 0xA7339494,
363
+ 0xB62D9B9B, 0x223C1E1E, 0x92158787, 0x20C9E9E9, 0x4987CECE, 0xFFAA5555, 0x78502828, 0x7AA5DFDF,
364
+ 0x8F038C8C, 0xF859A1A1, 0x80098989, 0x171A0D0D, 0xDA65BFBF, 0x31D7E6E6, 0xC6844242, 0xB8D06868,
365
+ 0xC3824141, 0xB0299999, 0x775A2D2D, 0x111E0F0F, 0xCB7BB0B0, 0xFCA85454, 0xD66DBBBB, 0x3A2C1616
366
+ );
367
 
368
  /**
369
  * Precomputed mixColumns table
370
  *
371
+ * @see Crypt_Rijndael:_encryptBlock()
372
+ * @see Crypt_Rijndael:_decryptBlock()
373
  * @var Array
374
  * @access private
375
  */
376
+ var $t2 = array(
377
+ 0x63A5C663, 0x7C84F87C, 0x7799EE77, 0x7B8DF67B, 0xF20DFFF2, 0x6BBDD66B, 0x6FB1DE6F, 0xC55491C5,
378
+ 0x30506030, 0x01030201, 0x67A9CE67, 0x2B7D562B, 0xFE19E7FE, 0xD762B5D7, 0xABE64DAB, 0x769AEC76,
379
+ 0xCA458FCA, 0x829D1F82, 0xC94089C9, 0x7D87FA7D, 0xFA15EFFA, 0x59EBB259, 0x47C98E47, 0xF00BFBF0,
380
+ 0xADEC41AD, 0xD467B3D4, 0xA2FD5FA2, 0xAFEA45AF, 0x9CBF239C, 0xA4F753A4, 0x7296E472, 0xC05B9BC0,
381
+ 0xB7C275B7, 0xFD1CE1FD, 0x93AE3D93, 0x266A4C26, 0x365A6C36, 0x3F417E3F, 0xF702F5F7, 0xCC4F83CC,
382
+ 0x345C6834, 0xA5F451A5, 0xE534D1E5, 0xF108F9F1, 0x7193E271, 0xD873ABD8, 0x31536231, 0x153F2A15,
383
+ 0x040C0804, 0xC75295C7, 0x23654623, 0xC35E9DC3, 0x18283018, 0x96A13796, 0x050F0A05, 0x9AB52F9A,
384
+ 0x07090E07, 0x12362412, 0x809B1B80, 0xE23DDFE2, 0xEB26CDEB, 0x27694E27, 0xB2CD7FB2, 0x759FEA75,
385
+ 0x091B1209, 0x839E1D83, 0x2C74582C, 0x1A2E341A, 0x1B2D361B, 0x6EB2DC6E, 0x5AEEB45A, 0xA0FB5BA0,
386
+ 0x52F6A452, 0x3B4D763B, 0xD661B7D6, 0xB3CE7DB3, 0x297B5229, 0xE33EDDE3, 0x2F715E2F, 0x84971384,
387
+ 0x53F5A653, 0xD168B9D1, 0x00000000, 0xED2CC1ED, 0x20604020, 0xFC1FE3FC, 0xB1C879B1, 0x5BEDB65B,
388
+ 0x6ABED46A, 0xCB468DCB, 0xBED967BE, 0x394B7239, 0x4ADE944A, 0x4CD4984C, 0x58E8B058, 0xCF4A85CF,
389
+ 0xD06BBBD0, 0xEF2AC5EF, 0xAAE54FAA, 0xFB16EDFB, 0x43C58643, 0x4DD79A4D, 0x33556633, 0x85941185,
390
+ 0x45CF8A45, 0xF910E9F9, 0x02060402, 0x7F81FE7F, 0x50F0A050, 0x3C44783C, 0x9FBA259F, 0xA8E34BA8,
391
+ 0x51F3A251, 0xA3FE5DA3, 0x40C08040, 0x8F8A058F, 0x92AD3F92, 0x9DBC219D, 0x38487038, 0xF504F1F5,
392
+ 0xBCDF63BC, 0xB6C177B6, 0xDA75AFDA, 0x21634221, 0x10302010, 0xFF1AE5FF, 0xF30EFDF3, 0xD26DBFD2,
393
+ 0xCD4C81CD, 0x0C14180C, 0x13352613, 0xEC2FC3EC, 0x5FE1BE5F, 0x97A23597, 0x44CC8844, 0x17392E17,
394
+ 0xC45793C4, 0xA7F255A7, 0x7E82FC7E, 0x3D477A3D, 0x64ACC864, 0x5DE7BA5D, 0x192B3219, 0x7395E673,
395
+ 0x60A0C060, 0x81981981, 0x4FD19E4F, 0xDC7FA3DC, 0x22664422, 0x2A7E542A, 0x90AB3B90, 0x88830B88,
396
+ 0x46CA8C46, 0xEE29C7EE, 0xB8D36BB8, 0x143C2814, 0xDE79A7DE, 0x5EE2BC5E, 0x0B1D160B, 0xDB76ADDB,
397
+ 0xE03BDBE0, 0x32566432, 0x3A4E743A, 0x0A1E140A, 0x49DB9249, 0x060A0C06, 0x246C4824, 0x5CE4B85C,
398
+ 0xC25D9FC2, 0xD36EBDD3, 0xACEF43AC, 0x62A6C462, 0x91A83991, 0x95A43195, 0xE437D3E4, 0x798BF279,
399
+ 0xE732D5E7, 0xC8438BC8, 0x37596E37, 0x6DB7DA6D, 0x8D8C018D, 0xD564B1D5, 0x4ED29C4E, 0xA9E049A9,
400
+ 0x6CB4D86C, 0x56FAAC56, 0xF407F3F4, 0xEA25CFEA, 0x65AFCA65, 0x7A8EF47A, 0xAEE947AE, 0x08181008,
401
+ 0xBAD56FBA, 0x7888F078, 0x256F4A25, 0x2E725C2E, 0x1C24381C, 0xA6F157A6, 0xB4C773B4, 0xC65197C6,
402
+ 0xE823CBE8, 0xDD7CA1DD, 0x749CE874, 0x1F213E1F, 0x4BDD964B, 0xBDDC61BD, 0x8B860D8B, 0x8A850F8A,
403
+ 0x7090E070, 0x3E427C3E, 0xB5C471B5, 0x66AACC66, 0x48D89048, 0x03050603, 0xF601F7F6, 0x0E121C0E,
404
+ 0x61A3C261, 0x355F6A35, 0x57F9AE57, 0xB9D069B9, 0x86911786, 0xC15899C1, 0x1D273A1D, 0x9EB9279E,
405
+ 0xE138D9E1, 0xF813EBF8, 0x98B32B98, 0x11332211, 0x69BBD269, 0xD970A9D9, 0x8E89078E, 0x94A73394,
406
+ 0x9BB62D9B, 0x1E223C1E, 0x87921587, 0xE920C9E9, 0xCE4987CE, 0x55FFAA55, 0x28785028, 0xDF7AA5DF,
407
+ 0x8C8F038C, 0xA1F859A1, 0x89800989, 0x0D171A0D, 0xBFDA65BF, 0xE631D7E6, 0x42C68442, 0x68B8D068,
408
+ 0x41C38241, 0x99B02999, 0x2D775A2D, 0x0F111E0F, 0xB0CB7BB0, 0x54FCA854, 0xBBD66DBB, 0x163A2C16
409
+ );
410
 
411
  /**
412
+ * Precomputed mixColumns table
413
  *
414
+ * @see Crypt_Rijndael:_encryptBlock()
415
+ * @see Crypt_Rijndael:_decryptBlock()
416
  * @var Array
417
  * @access private
418
  */
419
+ var $t3 = array(
420
+ 0x6363A5C6, 0x7C7C84F8, 0x777799EE, 0x7B7B8DF6, 0xF2F20DFF, 0x6B6BBDD6, 0x6F6FB1DE, 0xC5C55491,
421
+ 0x30305060, 0x01010302, 0x6767A9CE, 0x2B2B7D56, 0xFEFE19E7, 0xD7D762B5, 0xABABE64D, 0x76769AEC,
422
+ 0xCACA458F, 0x82829D1F, 0xC9C94089, 0x7D7D87FA, 0xFAFA15EF, 0x5959EBB2, 0x4747C98E, 0xF0F00BFB,
423
+ 0xADADEC41, 0xD4D467B3, 0xA2A2FD5F, 0xAFAFEA45, 0x9C9CBF23, 0xA4A4F753, 0x727296E4, 0xC0C05B9B,
424
+ 0xB7B7C275, 0xFDFD1CE1, 0x9393AE3D, 0x26266A4C, 0x36365A6C, 0x3F3F417E, 0xF7F702F5, 0xCCCC4F83,
425
+ 0x34345C68, 0xA5A5F451, 0xE5E534D1, 0xF1F108F9, 0x717193E2, 0xD8D873AB, 0x31315362, 0x15153F2A,
426
+ 0x04040C08, 0xC7C75295, 0x23236546, 0xC3C35E9D, 0x18182830, 0x9696A137, 0x05050F0A, 0x9A9AB52F,
427
+ 0x0707090E, 0x12123624, 0x80809B1B, 0xE2E23DDF, 0xEBEB26CD, 0x2727694E, 0xB2B2CD7F, 0x75759FEA,
428
+ 0x09091B12, 0x83839E1D, 0x2C2C7458, 0x1A1A2E34, 0x1B1B2D36, 0x6E6EB2DC, 0x5A5AEEB4, 0xA0A0FB5B,
429
+ 0x5252F6A4, 0x3B3B4D76, 0xD6D661B7, 0xB3B3CE7D, 0x29297B52, 0xE3E33EDD, 0x2F2F715E, 0x84849713,
430
+ 0x5353F5A6, 0xD1D168B9, 0x00000000, 0xEDED2CC1, 0x20206040, 0xFCFC1FE3, 0xB1B1C879, 0x5B5BEDB6,
431
+ 0x6A6ABED4, 0xCBCB468D, 0xBEBED967, 0x39394B72, 0x4A4ADE94, 0x4C4CD498, 0x5858E8B0, 0xCFCF4A85,
432
+ 0xD0D06BBB, 0xEFEF2AC5, 0xAAAAE54F, 0xFBFB16ED, 0x4343C586, 0x4D4DD79A, 0x33335566, 0x85859411,
433
+ 0x4545CF8A, 0xF9F910E9, 0x02020604, 0x7F7F81FE, 0x5050F0A0, 0x3C3C4478, 0x9F9FBA25, 0xA8A8E34B,
434
+ 0x5151F3A2, 0xA3A3FE5D, 0x4040C080, 0x8F8F8A05, 0x9292AD3F, 0x9D9DBC21, 0x38384870, 0xF5F504F1,
435
+ 0xBCBCDF63, 0xB6B6C177, 0xDADA75AF, 0x21216342, 0x10103020, 0xFFFF1AE5, 0xF3F30EFD, 0xD2D26DBF,
436
+ 0xCDCD4C81, 0x0C0C1418, 0x13133526, 0xECEC2FC3, 0x5F5FE1BE, 0x9797A235, 0x4444CC88, 0x1717392E,
437
+ 0xC4C45793, 0xA7A7F255, 0x7E7E82FC, 0x3D3D477A, 0x6464ACC8, 0x5D5DE7BA, 0x19192B32, 0x737395E6,
438
+ 0x6060A0C0, 0x81819819, 0x4F4FD19E, 0xDCDC7FA3, 0x22226644, 0x2A2A7E54, 0x9090AB3B, 0x8888830B,
439
+ 0x4646CA8C, 0xEEEE29C7, 0xB8B8D36B, 0x14143C28, 0xDEDE79A7, 0x5E5EE2BC, 0x0B0B1D16, 0xDBDB76AD,
440
+ 0xE0E03BDB, 0x32325664, 0x3A3A4E74, 0x0A0A1E14, 0x4949DB92, 0x06060A0C, 0x24246C48, 0x5C5CE4B8,
441
+ 0xC2C25D9F, 0xD3D36EBD, 0xACACEF43, 0x6262A6C4, 0x9191A839, 0x9595A431, 0xE4E437D3, 0x79798BF2,
442
+ 0xE7E732D5, 0xC8C8438B, 0x3737596E, 0x6D6DB7DA, 0x8D8D8C01, 0xD5D564B1, 0x4E4ED29C, 0xA9A9E049,
443
+ 0x6C6CB4D8, 0x5656FAAC, 0xF4F407F3, 0xEAEA25CF, 0x6565AFCA, 0x7A7A8EF4, 0xAEAEE947, 0x08081810,
444
+ 0xBABAD56F, 0x787888F0, 0x25256F4A, 0x2E2E725C, 0x1C1C2438, 0xA6A6F157, 0xB4B4C773, 0xC6C65197,
445
+ 0xE8E823CB, 0xDDDD7CA1, 0x74749CE8, 0x1F1F213E, 0x4B4BDD96, 0xBDBDDC61, 0x8B8B860D, 0x8A8A850F,
446
+ 0x707090E0, 0x3E3E427C, 0xB5B5C471, 0x6666AACC, 0x4848D890, 0x03030506, 0xF6F601F7, 0x0E0E121C,
447
+ 0x6161A3C2, 0x35355F6A, 0x5757F9AE, 0xB9B9D069, 0x86869117, 0xC1C15899, 0x1D1D273A, 0x9E9EB927,
448
+ 0xE1E138D9, 0xF8F813EB, 0x9898B32B, 0x11113322, 0x6969BBD2, 0xD9D970A9, 0x8E8E8907, 0x9494A733,
449
+ 0x9B9BB62D, 0x1E1E223C, 0x87879215, 0xE9E920C9, 0xCECE4987, 0x5555FFAA, 0x28287850, 0xDFDF7AA5,
450
+ 0x8C8C8F03, 0xA1A1F859, 0x89898009, 0x0D0D171A, 0xBFBFDA65, 0xE6E631D7, 0x4242C684, 0x6868B8D0,
451
+ 0x4141C382, 0x9999B029, 0x2D2D775A, 0x0F0F111E, 0xB0B0CB7B, 0x5454FCA8, 0xBBBBD66D, 0x16163A2C
452
+ );
453
 
454
  /**
455
  * Precomputed invMixColumns table
456
  *
457
+ * @see Crypt_Rijndael:_encryptBlock()
458
+ * @see Crypt_Rijndael:_decryptBlock()
459
  * @var Array
460
  * @access private
461
  */
462
+ var $dt0 = array(
463
+ 0x51F4A750, 0x7E416553, 0x1A17A4C3, 0x3A275E96, 0x3BAB6BCB, 0x1F9D45F1, 0xACFA58AB, 0x4BE30393,
464
+ 0x2030FA55, 0xAD766DF6, 0x88CC7691, 0xF5024C25, 0x4FE5D7FC, 0xC52ACBD7, 0x26354480, 0xB562A38F,
465
+ 0xDEB15A49, 0x25BA1B67, 0x45EA0E98, 0x5DFEC0E1, 0xC32F7502, 0x814CF012, 0x8D4697A3, 0x6BD3F9C6,
466
+ 0x038F5FE7, 0x15929C95, 0xBF6D7AEB, 0x955259DA, 0xD4BE832D, 0x587421D3, 0x49E06929, 0x8EC9C844,
467
+ 0x75C2896A, 0xF48E7978, 0x99583E6B, 0x27B971DD, 0xBEE14FB6, 0xF088AD17, 0xC920AC66, 0x7DCE3AB4,
468
+ 0x63DF4A18, 0xE51A3182, 0x97513360, 0x62537F45, 0xB16477E0, 0xBB6BAE84, 0xFE81A01C, 0xF9082B94,
469
+ 0x70486858, 0x8F45FD19, 0x94DE6C87, 0x527BF8B7, 0xAB73D323, 0x724B02E2, 0xE31F8F57, 0x6655AB2A,
470
+ 0xB2EB2807, 0x2FB5C203, 0x86C57B9A, 0xD33708A5, 0x302887F2, 0x23BFA5B2, 0x02036ABA, 0xED16825C,
471
+ 0x8ACF1C2B, 0xA779B492, 0xF307F2F0, 0x4E69E2A1, 0x65DAF4CD, 0x0605BED5, 0xD134621F, 0xC4A6FE8A,
472
+ 0x342E539D, 0xA2F355A0, 0x058AE132, 0xA4F6EB75, 0x0B83EC39, 0x4060EFAA, 0x5E719F06, 0xBD6E1051,
473
+ 0x3E218AF9, 0x96DD063D, 0xDD3E05AE, 0x4DE6BD46, 0x91548DB5, 0x71C45D05, 0x0406D46F, 0x605015FF,
474
+ 0x1998FB24, 0xD6BDE997, 0x894043CC, 0x67D99E77, 0xB0E842BD, 0x07898B88, 0xE7195B38, 0x79C8EEDB,
475
+ 0xA17C0A47, 0x7C420FE9, 0xF8841EC9, 0x00000000, 0x09808683, 0x322BED48, 0x1E1170AC, 0x6C5A724E,
476
+ 0xFD0EFFFB, 0x0F853856, 0x3DAED51E, 0x362D3927, 0x0A0FD964, 0x685CA621, 0x9B5B54D1, 0x24362E3A,
477
+ 0x0C0A67B1, 0x9357E70F, 0xB4EE96D2, 0x1B9B919E, 0x80C0C54F, 0x61DC20A2, 0x5A774B69, 0x1C121A16,
478
+ 0xE293BA0A, 0xC0A02AE5, 0x3C22E043, 0x121B171D, 0x0E090D0B, 0xF28BC7AD, 0x2DB6A8B9, 0x141EA9C8,
479
+ 0x57F11985, 0xAF75074C, 0xEE99DDBB, 0xA37F60FD, 0xF701269F, 0x5C72F5BC, 0x44663BC5, 0x5BFB7E34,
480
+ 0x8B432976, 0xCB23C6DC, 0xB6EDFC68, 0xB8E4F163, 0xD731DCCA, 0x42638510, 0x13972240, 0x84C61120,
481
+ 0x854A247D, 0xD2BB3DF8, 0xAEF93211, 0xC729A16D, 0x1D9E2F4B, 0xDCB230F3, 0x0D8652EC, 0x77C1E3D0,
482
+ 0x2BB3166C, 0xA970B999, 0x119448FA, 0x47E96422, 0xA8FC8CC4, 0xA0F03F1A, 0x567D2CD8, 0x223390EF,
483
+ 0x87494EC7, 0xD938D1C1, 0x8CCAA2FE, 0x98D40B36, 0xA6F581CF, 0xA57ADE28, 0xDAB78E26, 0x3FADBFA4,
484
+ 0x2C3A9DE4, 0x5078920D, 0x6A5FCC9B, 0x547E4662, 0xF68D13C2, 0x90D8B8E8, 0x2E39F75E, 0x82C3AFF5,
485
+ 0x9F5D80BE, 0x69D0937C, 0x6FD52DA9, 0xCF2512B3, 0xC8AC993B, 0x10187DA7, 0xE89C636E, 0xDB3BBB7B,
486
+ 0xCD267809, 0x6E5918F4, 0xEC9AB701, 0x834F9AA8, 0xE6956E65, 0xAAFFE67E, 0x21BCCF08, 0xEF15E8E6,
487
+ 0xBAE79BD9, 0x4A6F36CE, 0xEA9F09D4, 0x29B07CD6, 0x31A4B2AF, 0x2A3F2331, 0xC6A59430, 0x35A266C0,
488
+ 0x744EBC37, 0xFC82CAA6, 0xE090D0B0, 0x33A7D815, 0xF104984A, 0x41ECDAF7, 0x7FCD500E, 0x1791F62F,
489
+ 0x764DD68D, 0x43EFB04D, 0xCCAA4D54, 0xE49604DF, 0x9ED1B5E3, 0x4C6A881B, 0xC12C1FB8, 0x4665517F,
490
+ 0x9D5EEA04, 0x018C355D, 0xFA877473, 0xFB0B412E, 0xB3671D5A, 0x92DBD252, 0xE9105633, 0x6DD64713,
491
+ 0x9AD7618C, 0x37A10C7A, 0x59F8148E, 0xEB133C89, 0xCEA927EE, 0xB761C935, 0xE11CE5ED, 0x7A47B13C,
492
+ 0x9CD2DF59, 0x55F2733F, 0x1814CE79, 0x73C737BF, 0x53F7CDEA, 0x5FFDAA5B, 0xDF3D6F14, 0x7844DB86,
493
+ 0xCAAFF381, 0xB968C43E, 0x3824342C, 0xC2A3405F, 0x161DC372, 0xBCE2250C, 0x283C498B, 0xFF0D9541,
494
+ 0x39A80171, 0x080CB3DE, 0xD8B4E49C, 0x6456C190, 0x7BCB8461, 0xD532B670, 0x486C5C74, 0xD0B85742
495
+ );
496
 
497
  /**
498
  * Precomputed invMixColumns table
499
  *
500
+ * @see Crypt_Rijndael:_encryptBlock()
501
+ * @see Crypt_Rijndael:_decryptBlock()
502
  * @var Array
503
  * @access private
504
  */
505
+ var $dt1 = array(
506
+ 0x5051F4A7, 0x537E4165, 0xC31A17A4, 0x963A275E, 0xCB3BAB6B, 0xF11F9D45, 0xABACFA58, 0x934BE303,
507
+ 0x552030FA, 0xF6AD766D, 0x9188CC76, 0x25F5024C, 0xFC4FE5D7, 0xD7C52ACB, 0x80263544, 0x8FB562A3,
508
+ 0x49DEB15A, 0x6725BA1B, 0x9845EA0E, 0xE15DFEC0, 0x02C32F75, 0x12814CF0, 0xA38D4697, 0xC66BD3F9,
509
+ 0xE7038F5F, 0x9515929C, 0xEBBF6D7A, 0xDA955259, 0x2DD4BE83, 0xD3587421, 0x2949E069, 0x448EC9C8,
510
+ 0x6A75C289, 0x78F48E79, 0x6B99583E, 0xDD27B971, 0xB6BEE14F, 0x17F088AD, 0x66C920AC, 0xB47DCE3A,
511
+ 0x1863DF4A, 0x82E51A31, 0x60975133, 0x4562537F, 0xE0B16477, 0x84BB6BAE, 0x1CFE81A0, 0x94F9082B,
512
+ 0x58704868, 0x198F45FD, 0x8794DE6C, 0xB7527BF8, 0x23AB73D3, 0xE2724B02, 0x57E31F8F, 0x2A6655AB,
513
+ 0x07B2EB28, 0x032FB5C2, 0x9A86C57B, 0xA5D33708, 0xF2302887, 0xB223BFA5, 0xBA02036A, 0x5CED1682,
514
+ 0x2B8ACF1C, 0x92A779B4, 0xF0F307F2, 0xA14E69E2, 0xCD65DAF4, 0xD50605BE, 0x1FD13462, 0x8AC4A6FE,
515
+ 0x9D342E53, 0xA0A2F355, 0x32058AE1, 0x75A4F6EB, 0x390B83EC, 0xAA4060EF, 0x065E719F, 0x51BD6E10,
516
+ 0xF93E218A, 0x3D96DD06, 0xAEDD3E05, 0x464DE6BD, 0xB591548D, 0x0571C45D, 0x6F0406D4, 0xFF605015,
517
+ 0x241998FB, 0x97D6BDE9, 0xCC894043, 0x7767D99E, 0xBDB0E842, 0x8807898B, 0x38E7195B, 0xDB79C8EE,
518
+ 0x47A17C0A, 0xE97C420F, 0xC9F8841E, 0x00000000, 0x83098086, 0x48322BED, 0xAC1E1170, 0x4E6C5A72,
519
+ 0xFBFD0EFF, 0x560F8538, 0x1E3DAED5, 0x27362D39, 0x640A0FD9, 0x21685CA6, 0xD19B5B54, 0x3A24362E,
520
+ 0xB10C0A67, 0x0F9357E7, 0xD2B4EE96, 0x9E1B9B91, 0x4F80C0C5, 0xA261DC20, 0x695A774B, 0x161C121A,
521
+ 0x0AE293BA, 0xE5C0A02A, 0x433C22E0, 0x1D121B17, 0x0B0E090D, 0xADF28BC7, 0xB92DB6A8, 0xC8141EA9,
522
+ 0x8557F119, 0x4CAF7507, 0xBBEE99DD, 0xFDA37F60, 0x9FF70126, 0xBC5C72F5, 0xC544663B, 0x345BFB7E,
523
+ 0x768B4329, 0xDCCB23C6, 0x68B6EDFC, 0x63B8E4F1, 0xCAD731DC, 0x10426385, 0x40139722, 0x2084C611,
524
+ 0x7D854A24, 0xF8D2BB3D, 0x11AEF932, 0x6DC729A1, 0x4B1D9E2F, 0xF3DCB230, 0xEC0D8652, 0xD077C1E3,
525
+ 0x6C2BB316, 0x99A970B9, 0xFA119448, 0x2247E964, 0xC4A8FC8C, 0x1AA0F03F, 0xD8567D2C, 0xEF223390,
526
+ 0xC787494E, 0xC1D938D1, 0xFE8CCAA2, 0x3698D40B, 0xCFA6F581, 0x28A57ADE, 0x26DAB78E, 0xA43FADBF,
527
+ 0xE42C3A9D, 0x0D507892, 0x9B6A5FCC, 0x62547E46, 0xC2F68D13, 0xE890D8B8, 0x5E2E39F7, 0xF582C3AF,
528
+ 0xBE9F5D80, 0x7C69D093, 0xA96FD52D, 0xB3CF2512, 0x3BC8AC99, 0xA710187D, 0x6EE89C63, 0x7BDB3BBB,
529
+ 0x09CD2678, 0xF46E5918, 0x01EC9AB7, 0xA8834F9A, 0x65E6956E, 0x7EAAFFE6, 0x0821BCCF, 0xE6EF15E8,
530
+ 0xD9BAE79B, 0xCE4A6F36, 0xD4EA9F09, 0xD629B07C, 0xAF31A4B2, 0x312A3F23, 0x30C6A594, 0xC035A266,
531
+ 0x37744EBC, 0xA6FC82CA, 0xB0E090D0, 0x1533A7D8, 0x4AF10498, 0xF741ECDA, 0x0E7FCD50, 0x2F1791F6,
532
+ 0x8D764DD6, 0x4D43EFB0, 0x54CCAA4D, 0xDFE49604, 0xE39ED1B5, 0x1B4C6A88, 0xB8C12C1F, 0x7F466551,
533
+ 0x049D5EEA, 0x5D018C35, 0x73FA8774, 0x2EFB0B41, 0x5AB3671D, 0x5292DBD2, 0x33E91056, 0x136DD647,
534
+ 0x8C9AD761, 0x7A37A10C, 0x8E59F814, 0x89EB133C, 0xEECEA927, 0x35B761C9, 0xEDE11CE5, 0x3C7A47B1,
535
+ 0x599CD2DF, 0x3F55F273, 0x791814CE, 0xBF73C737, 0xEA53F7CD, 0x5B5FFDAA, 0x14DF3D6F, 0x867844DB,
536
+ 0x81CAAFF3, 0x3EB968C4, 0x2C382434, 0x5FC2A340, 0x72161DC3, 0x0CBCE225, 0x8B283C49, 0x41FF0D95,
537
+ 0x7139A801, 0xDE080CB3, 0x9CD8B4E4, 0x906456C1, 0x617BCB84, 0x70D532B6, 0x74486C5C, 0x42D0B857
538
+ );
539
 
540
  /**
541
  * Precomputed invMixColumns table
542
  *
543
+ * @see Crypt_Rijndael:_encryptBlock()
544
+ * @see Crypt_Rijndael:_decryptBlock()
545
  * @var Array
546
  * @access private
547
  */
548
+ var $dt2 = array(
549
+ 0xA75051F4, 0x65537E41, 0xA4C31A17, 0x5E963A27, 0x6BCB3BAB, 0x45F11F9D, 0x58ABACFA, 0x03934BE3,
550
+ 0xFA552030, 0x6DF6AD76, 0x769188CC, 0x4C25F502, 0xD7FC4FE5, 0xCBD7C52A, 0x44802635, 0xA38FB562,
551
+ 0x5A49DEB1, 0x1B6725BA, 0x0E9845EA, 0xC0E15DFE, 0x7502C32F, 0xF012814C, 0x97A38D46, 0xF9C66BD3,
552
+ 0x5FE7038F, 0x9C951592, 0x7AEBBF6D, 0x59DA9552, 0x832DD4BE, 0x21D35874, 0x692949E0, 0xC8448EC9,
553
+ 0x896A75C2, 0x7978F48E, 0x3E6B9958, 0x71DD27B9, 0x4FB6BEE1, 0xAD17F088, 0xAC66C920, 0x3AB47DCE,
554
+ 0x4A1863DF, 0x3182E51A, 0x33609751, 0x7F456253, 0x77E0B164, 0xAE84BB6B, 0xA01CFE81, 0x2B94F908,
555
+ 0x68587048, 0xFD198F45, 0x6C8794DE, 0xF8B7527B, 0xD323AB73, 0x02E2724B, 0x8F57E31F, 0xAB2A6655,
556
+ 0x2807B2EB, 0xC2032FB5, 0x7B9A86C5, 0x08A5D337, 0x87F23028, 0xA5B223BF, 0x6ABA0203, 0x825CED16,
557
+ 0x1C2B8ACF, 0xB492A779, 0xF2F0F307, 0xE2A14E69, 0xF4CD65DA, 0xBED50605, 0x621FD134, 0xFE8AC4A6,
558
+ 0x539D342E, 0x55A0A2F3, 0xE132058A, 0xEB75A4F6, 0xEC390B83, 0xEFAA4060, 0x9F065E71, 0x1051BD6E,
559
+ 0x8AF93E21, 0x063D96DD, 0x05AEDD3E, 0xBD464DE6, 0x8DB59154, 0x5D0571C4, 0xD46F0406, 0x15FF6050,
560
+ 0xFB241998, 0xE997D6BD, 0x43CC8940, 0x9E7767D9, 0x42BDB0E8, 0x8B880789, 0x5B38E719, 0xEEDB79C8,
561
+ 0x0A47A17C, 0x0FE97C42, 0x1EC9F884, 0x00000000, 0x86830980, 0xED48322B, 0x70AC1E11, 0x724E6C5A,
562
+ 0xFFFBFD0E, 0x38560F85, 0xD51E3DAE, 0x3927362D, 0xD9640A0F, 0xA621685C, 0x54D19B5B, 0x2E3A2436,
563
+ 0x67B10C0A, 0xE70F9357, 0x96D2B4EE, 0x919E1B9B, 0xC54F80C0, 0x20A261DC, 0x4B695A77, 0x1A161C12,
564
+ 0xBA0AE293, 0x2AE5C0A0, 0xE0433C22, 0x171D121B, 0x0D0B0E09, 0xC7ADF28B, 0xA8B92DB6, 0xA9C8141E,
565
+ 0x198557F1, 0x074CAF75, 0xDDBBEE99, 0x60FDA37F, 0x269FF701, 0xF5BC5C72, 0x3BC54466, 0x7E345BFB,
566
+ 0x29768B43, 0xC6DCCB23, 0xFC68B6ED, 0xF163B8E4, 0xDCCAD731, 0x85104263, 0x22401397, 0x112084C6,
567
+ 0x247D854A, 0x3DF8D2BB, 0x3211AEF9, 0xA16DC729, 0x2F4B1D9E, 0x30F3DCB2, 0x52EC0D86, 0xE3D077C1,
568
+ 0x166C2BB3, 0xB999A970, 0x48FA1194, 0x642247E9, 0x8CC4A8FC, 0x3F1AA0F0, 0x2CD8567D, 0x90EF2233,
569
+ 0x4EC78749, 0xD1C1D938, 0xA2FE8CCA, 0x0B3698D4, 0x81CFA6F5, 0xDE28A57A, 0x8E26DAB7, 0xBFA43FAD,
570
+ 0x9DE42C3A, 0x920D5078, 0xCC9B6A5F, 0x4662547E, 0x13C2F68D, 0xB8E890D8, 0xF75E2E39, 0xAFF582C3,
571
+ 0x80BE9F5D, 0x937C69D0, 0x2DA96FD5, 0x12B3CF25, 0x993BC8AC, 0x7DA71018, 0x636EE89C, 0xBB7BDB3B,
572
+ 0x7809CD26, 0x18F46E59, 0xB701EC9A, 0x9AA8834F, 0x6E65E695, 0xE67EAAFF, 0xCF0821BC, 0xE8E6EF15,
573
+ 0x9BD9BAE7, 0x36CE4A6F, 0x09D4EA9F, 0x7CD629B0, 0xB2AF31A4, 0x23312A3F, 0x9430C6A5, 0x66C035A2,
574
+ 0xBC37744E, 0xCAA6FC82, 0xD0B0E090, 0xD81533A7, 0x984AF104, 0xDAF741EC, 0x500E7FCD, 0xF62F1791,
575
+ 0xD68D764D, 0xB04D43EF, 0x4D54CCAA, 0x04DFE496, 0xB5E39ED1, 0x881B4C6A, 0x1FB8C12C, 0x517F4665,
576
+ 0xEA049D5E, 0x355D018C, 0x7473FA87, 0x412EFB0B, 0x1D5AB367, 0xD25292DB, 0x5633E910, 0x47136DD6,
577
+ 0x618C9AD7, 0x0C7A37A1, 0x148E59F8, 0x3C89EB13, 0x27EECEA9, 0xC935B761, 0xE5EDE11C, 0xB13C7A47,
578
+ 0xDF599CD2, 0x733F55F2, 0xCE791814, 0x37BF73C7, 0xCDEA53F7, 0xAA5B5FFD, 0x6F14DF3D, 0xDB867844,
579
+ 0xF381CAAF, 0xC43EB968, 0x342C3824, 0x405FC2A3, 0xC372161D, 0x250CBCE2, 0x498B283C, 0x9541FF0D,
580
+ 0x017139A8, 0xB3DE080C, 0xE49CD8B4, 0xC1906456, 0x84617BCB, 0xB670D532, 0x5C74486C, 0x5742D0B8
581
+ );
582
 
583
  /**
584
+ * Precomputed invMixColumns table
585
  *
586
+ * @see Crypt_Rijndael:_encryptBlock()
587
+ * @see Crypt_Rijndael:_decryptBlock()
588
+ * @var Array
589
  * @access private
590
  */
591
+ var $dt3 = array(
592
+ 0xF4A75051, 0x4165537E, 0x17A4C31A, 0x275E963A, 0xAB6BCB3B, 0x9D45F11F, 0xFA58ABAC, 0xE303934B,
593
+ 0x30FA5520, 0x766DF6AD, 0xCC769188, 0x024C25F5, 0xE5D7FC4F, 0x2ACBD7C5, 0x35448026, 0x62A38FB5,
594
+ 0xB15A49DE, 0xBA1B6725, 0xEA0E9845, 0xFEC0E15D, 0x2F7502C3, 0x4CF01281, 0x4697A38D, 0xD3F9C66B,
595
+ 0x8F5FE703, 0x929C9515, 0x6D7AEBBF, 0x5259DA95, 0xBE832DD4, 0x7421D358, 0xE0692949, 0xC9C8448E,
596
+ 0xC2896A75, 0x8E7978F4, 0x583E6B99, 0xB971DD27, 0xE14FB6BE, 0x88AD17F0, 0x20AC66C9, 0xCE3AB47D,
597
+ 0xDF4A1863, 0x1A3182E5, 0x51336097, 0x537F4562, 0x6477E0B1, 0x6BAE84BB, 0x81A01CFE, 0x082B94F9,
598
+ 0x48685870, 0x45FD198F, 0xDE6C8794, 0x7BF8B752, 0x73D323AB, 0x4B02E272, 0x1F8F57E3, 0x55AB2A66,
599
+ 0xEB2807B2, 0xB5C2032F, 0xC57B9A86, 0x3708A5D3, 0x2887F230, 0xBFA5B223, 0x036ABA02, 0x16825CED,
600
+ 0xCF1C2B8A, 0x79B492A7, 0x07F2F0F3, 0x69E2A14E, 0xDAF4CD65, 0x05BED506, 0x34621FD1, 0xA6FE8AC4,
601
+ 0x2E539D34, 0xF355A0A2, 0x8AE13205, 0xF6EB75A4, 0x83EC390B, 0x60EFAA40, 0x719F065E, 0x6E1051BD,
602
+ 0x218AF93E, 0xDD063D96, 0x3E05AEDD, 0xE6BD464D, 0x548DB591, 0xC45D0571, 0x06D46F04, 0x5015FF60,
603
+ 0x98FB2419, 0xBDE997D6, 0x4043CC89, 0xD99E7767, 0xE842BDB0, 0x898B8807, 0x195B38E7, 0xC8EEDB79,
604
+ 0x7C0A47A1, 0x420FE97C, 0x841EC9F8, 0x00000000, 0x80868309, 0x2BED4832, 0x1170AC1E, 0x5A724E6C,
605
+ 0x0EFFFBFD, 0x8538560F, 0xAED51E3D, 0x2D392736, 0x0FD9640A, 0x5CA62168, 0x5B54D19B, 0x362E3A24,
606
+ 0x0A67B10C, 0x57E70F93, 0xEE96D2B4, 0x9B919E1B, 0xC0C54F80, 0xDC20A261, 0x774B695A, 0x121A161C,
607
+ 0x93BA0AE2, 0xA02AE5C0, 0x22E0433C, 0x1B171D12, 0x090D0B0E, 0x8BC7ADF2, 0xB6A8B92D, 0x1EA9C814,
608
+ 0xF1198557, 0x75074CAF, 0x99DDBBEE, 0x7F60FDA3, 0x01269FF7, 0x72F5BC5C, 0x663BC544, 0xFB7E345B,
609
+ 0x4329768B, 0x23C6DCCB, 0xEDFC68B6, 0xE4F163B8, 0x31DCCAD7, 0x63851042, 0x97224013, 0xC6112084,
610
+ 0x4A247D85, 0xBB3DF8D2, 0xF93211AE, 0x29A16DC7, 0x9E2F4B1D, 0xB230F3DC, 0x8652EC0D, 0xC1E3D077,
611
+ 0xB3166C2B, 0x70B999A9, 0x9448FA11, 0xE9642247, 0xFC8CC4A8, 0xF03F1AA0, 0x7D2CD856, 0x3390EF22,
612
+ 0x494EC787, 0x38D1C1D9, 0xCAA2FE8C, 0xD40B3698, 0xF581CFA6, 0x7ADE28A5, 0xB78E26DA, 0xADBFA43F,
613
+ 0x3A9DE42C, 0x78920D50, 0x5FCC9B6A, 0x7E466254, 0x8D13C2F6, 0xD8B8E890, 0x39F75E2E, 0xC3AFF582,
614
+ 0x5D80BE9F, 0xD0937C69, 0xD52DA96F, 0x2512B3CF, 0xAC993BC8, 0x187DA710, 0x9C636EE8, 0x3BBB7BDB,
615
+ 0x267809CD, 0x5918F46E, 0x9AB701EC, 0x4F9AA883, 0x956E65E6, 0xFFE67EAA, 0xBCCF0821, 0x15E8E6EF,
616
+ 0xE79BD9BA, 0x6F36CE4A, 0x9F09D4EA, 0xB07CD629, 0xA4B2AF31, 0x3F23312A, 0xA59430C6, 0xA266C035,
617
+ 0x4EBC3774, 0x82CAA6FC, 0x90D0B0E0, 0xA7D81533, 0x04984AF1, 0xECDAF741, 0xCD500E7F, 0x91F62F17,
618
+ 0x4DD68D76, 0xEFB04D43, 0xAA4D54CC, 0x9604DFE4, 0xD1B5E39E, 0x6A881B4C, 0x2C1FB8C1, 0x65517F46,
619
+ 0x5EEA049D, 0x8C355D01, 0x877473FA, 0x0B412EFB, 0x671D5AB3, 0xDBD25292, 0x105633E9, 0xD647136D,
620
+ 0xD7618C9A, 0xA10C7A37, 0xF8148E59, 0x133C89EB, 0xA927EECE, 0x61C935B7, 0x1CE5EDE1, 0x47B13C7A,
621
+ 0xD2DF599C, 0xF2733F55, 0x14CE7918, 0xC737BF73, 0xF7CDEA53, 0xFDAA5B5F, 0x3D6F14DF, 0x44DB8678,
622
+ 0xAFF381CA, 0x68C43EB9, 0x24342C38, 0xA3405FC2, 0x1DC37216, 0xE2250CBC, 0x3C498B28, 0x0D9541FF,
623
+ 0xA8017139, 0x0CB3DE08, 0xB4E49CD8, 0x56C19064, 0xCB84617B, 0x32B670D5, 0x6C5C7448, 0xB85742D0
624
+ );
625
 
626
  /**
627
+ * The SubByte S-Box
628
  *
629
+ * @see Crypt_Rijndael::_encryptBlock()
630
+ * @var Array
631
  * @access private
632
  */
633
+ var $sbox = array(
634
+ 0x63, 0x7C, 0x77, 0x7B, 0xF2, 0x6B, 0x6F, 0xC5, 0x30, 0x01, 0x67, 0x2B, 0xFE, 0xD7, 0xAB, 0x76,
635
+ 0xCA, 0x82, 0xC9, 0x7D, 0xFA, 0x59, 0x47, 0xF0, 0xAD, 0xD4, 0xA2, 0xAF, 0x9C, 0xA4, 0x72, 0xC0,
636
+ 0xB7, 0xFD, 0x93, 0x26, 0x36, 0x3F, 0xF7, 0xCC, 0x34, 0xA5, 0xE5, 0xF1, 0x71, 0xD8, 0x31, 0x15,
637
+ 0x04, 0xC7, 0x23, 0xC3, 0x18, 0x96, 0x05, 0x9A, 0x07, 0x12, 0x80, 0xE2, 0xEB, 0x27, 0xB2, 0x75,
638
+ 0x09, 0x83, 0x2C, 0x1A, 0x1B, 0x6E, 0x5A, 0xA0, 0x52, 0x3B, 0xD6, 0xB3, 0x29, 0xE3, 0x2F, 0x84,
639
+ 0x53, 0xD1, 0x00, 0xED, 0x20, 0xFC, 0xB1, 0x5B, 0x6A, 0xCB, 0xBE, 0x39, 0x4A, 0x4C, 0x58, 0xCF,
640
+ 0xD0, 0xEF, 0xAA, 0xFB, 0x43, 0x4D, 0x33, 0x85, 0x45, 0xF9, 0x02, 0x7F, 0x50, 0x3C, 0x9F, 0xA8,
641
+ 0x51, 0xA3, 0x40, 0x8F, 0x92, 0x9D, 0x38, 0xF5, 0xBC, 0xB6, 0xDA, 0x21, 0x10, 0xFF, 0xF3, 0xD2,
642
+ 0xCD, 0x0C, 0x13, 0xEC, 0x5F, 0x97, 0x44, 0x17, 0xC4, 0xA7, 0x7E, 0x3D, 0x64, 0x5D, 0x19, 0x73,
643
+ 0x60, 0x81, 0x4F, 0xDC, 0x22, 0x2A, 0x90, 0x88, 0x46, 0xEE, 0xB8, 0x14, 0xDE, 0x5E, 0x0B, 0xDB,
644
+ 0xE0, 0x32, 0x3A, 0x0A, 0x49, 0x06, 0x24, 0x5C, 0xC2, 0xD3, 0xAC, 0x62, 0x91, 0x95, 0xE4, 0x79,
645
+ 0xE7, 0xC8, 0x37, 0x6D, 0x8D, 0xD5, 0x4E, 0xA9, 0x6C, 0x56, 0xF4, 0xEA, 0x65, 0x7A, 0xAE, 0x08,
646
+ 0xBA, 0x78, 0x25, 0x2E, 0x1C, 0xA6, 0xB4, 0xC6, 0xE8, 0xDD, 0x74, 0x1F, 0x4B, 0xBD, 0x8B, 0x8A,
647
+ 0x70, 0x3E, 0xB5, 0x66, 0x48, 0x03, 0xF6, 0x0E, 0x61, 0x35, 0x57, 0xB9, 0x86, 0xC1, 0x1D, 0x9E,
648
+ 0xE1, 0xF8, 0x98, 0x11, 0x69, 0xD9, 0x8E, 0x94, 0x9B, 0x1E, 0x87, 0xE9, 0xCE, 0x55, 0x28, 0xDF,
649
+ 0x8C, 0xA1, 0x89, 0x0D, 0xBF, 0xE6, 0x42, 0x68, 0x41, 0x99, 0x2D, 0x0F, 0xB0, 0x54, 0xBB, 0x16
650
+ );
651
 
652
  /**
653
+ * The inverse SubByte S-Box
654
  *
655
+ * @see Crypt_Rijndael::_decryptBlock()
656
+ * @var Array
657
  * @access private
658
  */
659
+ var $isbox = array(
660
+ 0x52, 0x09, 0x6A, 0xD5, 0x30, 0x36, 0xA5, 0x38, 0xBF, 0x40, 0xA3, 0x9E, 0x81, 0xF3, 0xD7, 0xFB,
661
+ 0x7C, 0xE3, 0x39, 0x82, 0x9B, 0x2F, 0xFF, 0x87, 0x34, 0x8E, 0x43, 0x44, 0xC4, 0xDE, 0xE9, 0xCB,
662
+ 0x54, 0x7B, 0x94, 0x32, 0xA6, 0xC2, 0x23, 0x3D, 0xEE, 0x4C, 0x95, 0x0B, 0x42, 0xFA, 0xC3, 0x4E,
663
+ 0x08, 0x2E, 0xA1, 0x66, 0x28, 0xD9, 0x24, 0xB2, 0x76, 0x5B, 0xA2, 0x49, 0x6D, 0x8B, 0xD1, 0x25,
664
+ 0x72, 0xF8, 0xF6, 0x64, 0x86, 0x68, 0x98, 0x16, 0xD4, 0xA4, 0x5C, 0xCC, 0x5D, 0x65, 0xB6, 0x92,
665
+ 0x6C, 0x70, 0x48, 0x50, 0xFD, 0xED, 0xB9, 0xDA, 0x5E, 0x15, 0x46, 0x57, 0xA7, 0x8D, 0x9D, 0x84,
666
+ 0x90, 0xD8, 0xAB, 0x00, 0x8C, 0xBC, 0xD3, 0x0A, 0xF7, 0xE4, 0x58, 0x05, 0xB8, 0xB3, 0x45, 0x06,
667
+ 0xD0, 0x2C, 0x1E, 0x8F, 0xCA, 0x3F, 0x0F, 0x02, 0xC1, 0xAF, 0xBD, 0x03, 0x01, 0x13, 0x8A, 0x6B,
668
+ 0x3A, 0x91, 0x11, 0x41, 0x4F, 0x67, 0xDC, 0xEA, 0x97, 0xF2, 0xCF, 0xCE, 0xF0, 0xB4, 0xE6, 0x73,
669
+ 0x96, 0xAC, 0x74, 0x22, 0xE7, 0xAD, 0x35, 0x85, 0xE2, 0xF9, 0x37, 0xE8, 0x1C, 0x75, 0xDF, 0x6E,
670
+ 0x47, 0xF1, 0x1A, 0x71, 0x1D, 0x29, 0xC5, 0x89, 0x6F, 0xB7, 0x62, 0x0E, 0xAA, 0x18, 0xBE, 0x1B,
671
+ 0xFC, 0x56, 0x3E, 0x4B, 0xC6, 0xD2, 0x79, 0x20, 0x9A, 0xDB, 0xC0, 0xFE, 0x78, 0xCD, 0x5A, 0xF4,
672
+ 0x1F, 0xDD, 0xA8, 0x33, 0x88, 0x07, 0xC7, 0x31, 0xB1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xEC, 0x5F,
673
+ 0x60, 0x51, 0x7F, 0xA9, 0x19, 0xB5, 0x4A, 0x0D, 0x2D, 0xE5, 0x7A, 0x9F, 0x93, 0xC9, 0x9C, 0xEF,
674
+ 0xA0, 0xE0, 0x3B, 0x4D, 0xAE, 0x2A, 0xF5, 0xB0, 0xC8, 0xEB, 0xBB, 0x3C, 0x83, 0x53, 0x99, 0x61,
675
+ 0x17, 0x2B, 0x04, 0x7E, 0xBA, 0x77, 0xD6, 0x26, 0xE1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0C, 0x7D
676
+ );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
677
 
678
  /**
679
  * Sets the key.
685
  *
686
  * If the key is not explicitly set, it'll be assumed to be all null bytes.
687
  *
688
+ * Note: 160/224-bit keys must explicitly set by setKeyLength(), otherwise they will be round/pad up to 192/256 bits.
689
+ *
690
+ * @see Crypt_Base:setKey()
691
+ * @see setKeyLength()
692
  * @access public
693
  * @param String $key
694
  */
695
  function setKey($key)
696
  {
697
+ parent::setKey($key);
 
 
698
 
699
+ if (!$this->explicit_key_length) {
700
+ $length = strlen($key);
701
+ switch (true) {
702
+ case $length <= 16:
703
+ $this->key_size = 16;
704
+ break;
705
+ case $length <= 20:
706
+ $this->key_size = 20;
707
+ break;
708
+ case $length <= 24:
709
+ $this->key_size = 24;
710
+ break;
711
+ case $length <= 28:
712
+ $this->key_size = 28;
713
+ break;
714
+ default:
715
+ $this->key_size = 32;
716
+ }
717
+ $this->_setupEngine();
718
+ }
719
  }
720
 
721
  /**
722
  * Sets the key length
723
  *
724
  * Valid key lengths are 128, 160, 192, 224, and 256. If the length is less than 128, it will be rounded up to
725
+ * 128. If the length is greater than 128 and invalid, it will be rounded down to the closest valid amount.
726
+ *
727
+ * Note: phpseclib extends Rijndael (and AES) for using 160- and 224-bit keys but they are officially not defined
728
+ * and the most (if not all) implementations are not able using 160/224-bit keys but round/pad them up to
729
+ * 192/256 bits as, for example, mcrypt will do.
730
+ *
731
+ * That said, if you want be compatible with other Rijndael and AES implementations,
732
+ * you should not setKeyLength(160) or setKeyLength(224).
733
+ *
734
+ * Additional: In case of 160- and 224-bit keys, phpseclib will/can, for that reason, not use
735
+ * the mcrypt php extension, even if available.
736
+ * This results then in slower encryption.
737
  *
738
  * @access public
739
  * @param Integer $length
740
  */
741
  function setKeyLength($length)
742
  {
743
+ switch (true) {
744
+ case $length == 160:
745
+ $this->key_size = 20;
746
+ break;
747
+ case $length == 224:
748
+ $this->key_size = 28;
749
+ break;
750
+ case $length <= 128:
751
+ $this->key_size = 16;
752
+ break;
753
+ case $length <= 192:
754
+ $this->key_size = 24;
755
+ break;
756
+ default:
757
+ $this->key_size = 32;
758
  }
 
 
759
 
760
  $this->explicit_key_length = true;
761
  $this->changed = true;
762
+ $this->_setupEngine();
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
763
  }
764
 
765
  /**
766
  * Sets the block length
767
  *
768
  * Valid block lengths are 128, 160, 192, 224, and 256. If the length is less than 128, it will be rounded up to
769
+ * 128. If the length is greater than 128 and invalid, it will be rounded down to the closest valid amount.
770
  *
771
  * @access public
772
  * @param Integer $length
782
  $this->Nb = $length;
783
  $this->block_size = $length << 2;
784
  $this->changed = true;
785
+ $this->_setupEngine();
786
  }
787
 
788
  /**
789
+ * Setup the fastest possible $engine
790
  *
791
+ * Determines if the mcrypt (MODE_MCRYPT) $engine available
792
+ * and usable for the current $block_size and $key_size.
793
  *
794
+ * If not, the slower MODE_INTERNAL $engine will be set.
795
+ *
796
+ * @see setKey()
797
+ * @see setKeyLength()
798
+ * @see setBlockLength()
799
+ * @access private
800
  */
801
+ function _setupEngine()
802
  {
803
+ if (constant('CRYPT_' . $this->const_namespace . '_MODE') == CRYPT_MODE_INTERNAL) {
804
+ // No mcrypt support at all for rijndael
805
+ return;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
806
  }
807
 
808
+ // The required mcrypt module name for the current $block_size of rijndael
809
+ $cipher_name_mcrypt = 'rijndael-' . ($this->block_size << 3);
810
 
811
+ // Determining the availibility/usability of $cipher_name_mcrypt
812
+ switch (true) {
813
+ case $this->key_size % 8: // mcrypt is not usable for 160/224-bit keys, only for 128/192/256-bit keys
814
+ case !in_array($cipher_name_mcrypt, mcrypt_list_algorithms()): // $cipher_name_mcrypt is not available for the current $block_size
815
+ $engine = CRYPT_MODE_INTERNAL;
816
+ break;
817
+ default:
818
+ $engine = CRYPT_MODE_MCRYPT;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
819
  }
820
 
821
+ if ($this->engine == $engine && $this->cipher_name_mcrypt == $cipher_name_mcrypt) {
822
+ // allready set, so we not unnecessary close $this->enmcrypt/demcrypt/ecb
823
+ return;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
824
  }
825
 
826
+ // Set the $engine
827
+ $this->engine = $engine;
828
+ $this->cipher_name_mcrypt = $cipher_name_mcrypt;
829
+
830
+ if ($this->enmcrypt) {
831
+ // Closing the current mcrypt resource(s). _mcryptSetup() will, if needed,
832
+ // (re)open them with the module named in $this->cipher_name_mcrypt
833
+ mcrypt_module_close($this->enmcrypt);
834
+ mcrypt_module_close($this->demcrypt);
835
+ $this->enmcrypt = null;
836
+ $this->demcrypt = null;
837
+
838
+ if ($this->ecb) {
839
+ mcrypt_module_close($this->ecb);
840
+ $this->ecb = null;
841
+ }
842
+ }
843
  }
844
 
845
  /**
846
+ * Setup the CRYPT_MODE_MCRYPT $engine
847
  *
848
+ * @see Crypt_Base::_setupMcrypt()
849
+ * @access private
 
 
 
 
850
  */
851
+ function _setupMcrypt()
852
  {
853
+ $this->key = str_pad(substr($this->key, 0, $this->key_size), $this->key_size, "\0");
854
+ parent::_setupMcrypt();
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
855
  }
856
 
857
  /**
863
  */
864
  function _encryptBlock($in)
865
  {
866
+ static $t0, $t1, $t2, $t3, $sbox;
867
+ if (!$t0) {
868
+ for ($i = 0; $i < 256; ++$i) {
869
+ $t0[] = (int)$this->t0[$i];
870
+ $t1[] = (int)$this->t1[$i];
871
+ $t2[] = (int)$this->t2[$i];
872
+ $t3[] = (int)$this->t3[$i];
873
+ $sbox[] = (int)$this->sbox[$i];
874
+ }
875
+ }
876
+
877
  $state = array();
878
+ $words = unpack('N*', $in);
879
 
880
+ $c = $this->c;
881
  $w = $this->w;
 
 
 
 
882
  $Nb = $this->Nb;
883
  $Nr = $this->Nr;
 
884
 
885
  // addRoundKey
886
+ $i = -1;
887
  foreach ($words as $word) {
888
+ $state[] = $word ^ $w[0][++$i];
889
  }
890
 
891
+ // fips-197.pdf#page=19, "Figure 5. Pseudo Code for the Cipher", states that this loop has four components -
892
+ // subBytes, shiftRows, mixColumns, and addRoundKey. fips-197.pdf#page=30, "Implementation Suggestions Regarding
893
  // Various Platforms" suggests that performs enhanced implementations are described in Rijndael-ammended.pdf.
894
  // Rijndael-ammended.pdf#page=20, "Implementation aspects / 32-bit processor", discusses such an optimization.
895
+ // Unfortunately, the description given there is not quite correct. Per aes.spec.v316.pdf#page=19 [1],
896
  // equation (7.4.7) is supposed to use addition instead of subtraction, so we'll do that here, as well.
897
 
898
  // [1] http://fp.gladman.plus.com/cryptography_technology/rijndael/aes.spec.v316.pdf
899
  $temp = array();
900
+ for ($round = 1; $round < $Nr; ++$round) {
901
  $i = 0; // $c[0] == 0
902
  $j = $c[1];
903
  $k = $c[2];
904
  $l = $c[3];
905
 
906
+ while ($i < $Nb) {
907
+ $temp[$i] = $t0[$state[$i] >> 24 & 0x000000FF] ^
908
+ $t1[$state[$j] >> 16 & 0x000000FF] ^
909
+ $t2[$state[$k] >> 8 & 0x000000FF] ^
910
+ $t3[$state[$l] & 0x000000FF] ^
911
  $w[$round][$i];
912
+ ++$i;
913
  $j = ($j + 1) % $Nb;
914
  $k = ($k + 1) % $Nb;
915
  $l = ($l + 1) % $Nb;
916
  }
917
+ $state = $temp;
 
 
 
918
  }
919
 
920
  // subWord
921
+ for ($i = 0; $i < $Nb; ++$i) {
922
+ $state[$i] = $sbox[$state[$i] & 0x000000FF] |
923
+ ($sbox[$state[$i] >> 8 & 0x000000FF] << 8) |
924
+ ($sbox[$state[$i] >> 16 & 0x000000FF] << 16) |
925
+ ($sbox[$state[$i] >> 24 & 0x000000FF] << 24);
926
  }
927
 
928
  // shiftRows + addRoundKey
930
  $j = $c[1];
931
  $k = $c[2];
932
  $l = $c[3];
933
+ while ($i < $Nb) {
934
+ $temp[$i] = ($state[$i] & 0xFF000000) ^
935
+ ($state[$j] & 0x00FF0000) ^
936
+ ($state[$k] & 0x0000FF00) ^
937
  ($state[$l] & 0x000000FF) ^
938
  $w[$Nr][$i];
939
+ ++$i;
940
  $j = ($j + 1) % $Nb;
941
  $k = ($k + 1) % $Nb;
942
  $l = ($l + 1) % $Nb;
943
  }
 
944
 
945
+ switch ($Nb) {
946
+ case 8:
947
+ return pack('N*', $temp[0], $temp[1], $temp[2], $temp[3], $temp[4], $temp[5], $temp[6], $temp[7]);
948
+ case 7:
949
+ return pack('N*', $temp[0], $temp[1], $temp[2], $temp[3], $temp[4], $temp[5], $temp[6]);
950
+ case 6:
951
+ return pack('N*', $temp[0], $temp[1], $temp[2], $temp[3], $temp[4], $temp[5]);
952
+ case 5:
953
+ return pack('N*', $temp[0], $temp[1], $temp[2], $temp[3], $temp[4]);
954
+ default:
955
+ return pack('N*', $temp[0], $temp[1], $temp[2], $temp[3]);
956
+ }
957
  }
958
 
959
  /**
965
  */
966
  function _decryptBlock($in)
967
  {
968
+ static $dt0, $dt1, $dt2, $dt3, $isbox;
969
+ if (!$dt0) {
970
+ for ($i = 0; $i < 256; ++$i) {
971
+ $dt0[] = (int)$this->dt0[$i];
972
+ $dt1[] = (int)$this->dt1[$i];
973
+ $dt2[] = (int)$this->dt2[$i];
974
+ $dt3[] = (int)$this->dt3[$i];
975
+ $isbox[] = (int)$this->isbox[$i];
976
+ }
977
+ }
978
+
979
  $state = array();
980
+ $words = unpack('N*', $in);
981
 
982
+ $c = $this->c;
983
  $dw = $this->dw;
 
 
 
 
984
  $Nb = $this->Nb;
985
  $Nr = $this->Nr;
 
986
 
987
  // addRoundKey
988
+ $i = -1;
989
  foreach ($words as $word) {
990
+ $state[] = $word ^ $dw[$Nr][++$i];
991
  }
992
 
993
  $temp = array();
994
+ for ($round = $Nr - 1; $round > 0; --$round) {
995
  $i = 0; // $c[0] == 0
996
  $j = $Nb - $c[1];
997
  $k = $Nb - $c[2];
998
  $l = $Nb - $c[3];
999
 
1000
  while ($i < $Nb) {
1001
+ $temp[$i] = $dt0[$state[$i] >> 24 & 0x000000FF] ^
1002
+ $dt1[$state[$j] >> 16 & 0x000000FF] ^
1003
+ $dt2[$state[$k] >> 8 & 0x000000FF] ^
1004
+ $dt3[$state[$l] & 0x000000FF] ^
1005
  $dw[$round][$i];
1006
+ ++$i;
1007
  $j = ($j + 1) % $Nb;
1008
  $k = ($k + 1) % $Nb;
1009
  $l = ($l + 1) % $Nb;
1010
  }
1011
+ $state = $temp;
 
 
 
1012
  }
1013
 
1014
  // invShiftRows + invSubWord + addRoundKey
1018
  $l = $Nb - $c[3];
1019
 
1020
  while ($i < $Nb) {
1021
+ $word = ($state[$i] & 0xFF000000) |
1022
+ ($state[$j] & 0x00FF0000) |
1023
+ ($state[$k] & 0x0000FF00) |
1024
+ ($state[$l] & 0x000000FF);
1025
+
1026
+ $temp[$i] = $dw[0][$i] ^ ($isbox[$word & 0x000000FF] |
1027
+ ($isbox[$word >> 8 & 0x000000FF] << 8) |
1028
+ ($isbox[$word >> 16 & 0x000000FF] << 16) |
1029
+ ($isbox[$word >> 24 & 0x000000FF] << 24));
1030
+ ++$i;
1031
  $j = ($j + 1) % $Nb;
1032
  $k = ($k + 1) % $Nb;
1033
  $l = ($l + 1) % $Nb;
1034
  }
1035
 
1036
+ switch ($Nb) {
1037
+ case 8:
1038
+ return pack('N*', $temp[0], $temp[1], $temp[2], $temp[3], $temp[4], $temp[5], $temp[6], $temp[7]);
1039
+ case 7:
1040
+ return pack('N*', $temp[0], $temp[1], $temp[2], $temp[3], $temp[4], $temp[5], $temp[6]);
1041
+ case 6:
1042
+ return pack('N*', $temp[0], $temp[1], $temp[2], $temp[3], $temp[4], $temp[5]);
1043
+ case 5:
1044
+ return pack('N*', $temp[0], $temp[1], $temp[2], $temp[3], $temp[4]);
1045
+ default:
1046
+ return pack('N*', $temp[0], $temp[1], $temp[2], $temp[3]);
1047
+ }
1048
  }
1049
 
1050
  /**
1051
+ * Setup the key (expansion)
 
 
 
1052
  *
1053
+ * @see Crypt_Base::_setupKey()
1054
  * @access private
1055
  */
1056
+ function _setupKey()
1057
  {
1058
  // Each number in $rcon is equal to the previous number multiplied by two in Rijndael's finite field.
1059
  // See http://en.wikipedia.org/wiki/Finite_field_arithmetic#Multiplicative_inverse
1066
  0x7D000000, 0xFA000000, 0xEF000000, 0xC5000000, 0x91000000
1067
  );
1068
 
1069
+ $this->key = str_pad(substr($this->key, 0, $this->key_size), $this->key_size, "\0");
 
 
1070
 
1071
+ if (isset($this->kl['key']) && $this->key === $this->kl['key'] && $this->key_size === $this->kl['key_size'] && $this->block_size === $this->kl['block_size']) {
1072
+ // already expanded
1073
+ return;
 
 
 
 
 
 
 
1074
  }
1075
+ $this->kl = array('key' => $this->key, 'key_size' => $this->key_size, 'block_size' => $this->block_size);
1076
 
1077
+ $this->Nk = $this->key_size >> 2;
 
 
1078
  // see Rijndael-ammended.pdf#page=44
1079
  $this->Nr = max($this->Nk, $this->Nb) + 6;
1080
 
1095
  $this->c = array(0, 1, 3, 4);
1096
  }
1097
 
1098
+ $w = array_values(unpack('N*words', $this->key));
 
 
1099
 
1100
  $length = $this->Nb * ($this->Nr + 1);
1101
  for ($i = $this->Nk; $i < $length; $i++) {
1115
 
1116
  // convert the key schedule from a vector of $Nb * ($Nr + 1) length to a matrix with $Nr + 1 rows and $Nb columns
1117
  // and generate the inverse key schedule. more specifically,
1118
+ // according to <http://csrc.nist.gov/archive/aes/rijndael/Rijndael-ammended.pdf#page=23> (section 5.3.3),
1119
  // "The key expansion for the Inverse Cipher is defined as follows:
1120
  // 1. Apply the Key Expansion.
1121
  // 2. Apply InvMixColumn to all Round Keys except the first and the last one."
1122
  // also, see fips-197.pdf#page=27, "5.3.5 Equivalent Inverse Cipher"
1123
+ $temp = $this->w = $this->dw = array();
1124
  for ($i = $row = $col = 0; $i < $length; $i++, $col++) {
1125
  if ($col == $this->Nb) {
1126
  if ($row == 0) {
1130
  $j = 0;
1131
  while ($j < $this->Nb) {
1132
  $dw = $this->_subWord($this->w[$row][$j]);
1133
+ $temp[$j] = $this->dt0[$dw >> 24 & 0x000000FF] ^
1134
+ $this->dt1[$dw >> 16 & 0x000000FF] ^
1135
+ $this->dt2[$dw >> 8 & 0x000000FF] ^
1136
+ $this->dt3[$dw & 0x000000FF];
1137
  $j++;
1138
  }
1139
  $this->dw[$row] = $temp;
1147
 
1148
  $this->dw[$row] = $this->w[$row];
1149
 
1150
+ // In case of $this->use_inline_crypt === true we have to use 1-dim key arrays (both ascending)
1151
+ if ($this->use_inline_crypt) {
1152
+ $this->dw = array_reverse($this->dw);
1153
+ $w = array_pop($this->w);
1154
+ $dw = array_pop($this->dw);
1155
+ foreach ($this->w as $r => $wr) {
1156
+ foreach ($wr as $c => $wc) {
1157
+ $w[] = $wc;
1158
+ $dw[] = $this->dw[$r][$c];
1159
+ }
1160
+ }
1161
+ $this->w = $w;
1162
+ $this->dw = $dw;
1163
+ }
1164
  }
1165
 
1166
  /**
1167
  * Performs S-Box substitutions
1168
  *
1169
  * @access private
1170
+ * @param Integer $word
1171
  */
1172
  function _subWord($word)
1173
  {
1174
+ $sbox = $this->sbox;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1175
 
1176
+ return $sbox[$word & 0x000000FF] |
1177
+ ($sbox[$word >> 8 & 0x000000FF] << 8) |
1178
+ ($sbox[$word >> 16 & 0x000000FF] << 16) |
1179
+ ($sbox[$word >> 24 & 0x000000FF] << 24);
1180
  }
1181
 
1182
  /**
1183
+ * Setup the performance-optimized function for de/encrypt()
1184
  *
1185
+ * @see Crypt_Base::_setupInlineCrypt()
1186
  * @access private
1187
  */
1188
+ function _setupInlineCrypt()
1189
  {
1190
+ // Note: _setupInlineCrypt() will be called only if $this->changed === true
1191
+ // So here we are'nt under the same heavy timing-stress as we are in _de/encryptBlock() or de/encrypt().
1192
+ // However...the here generated function- $code, stored as php callback in $this->inline_crypt, must work as fast as even possible.
1193
+
1194
+ $lambda_functions =& Crypt_Rijndael::_getLambdaFunctions();
1195
+
1196
+ // The first 10 generated $lambda_functions will use the key-words hardcoded for better performance.
1197
+ // For memory reason we limit those ultra-optimized functions.
1198
+ // After that, we use pure (extracted) integer vars for the key-words which is faster than accessing them via array.
1199
+ if (count($lambda_functions) < 10) {
1200
+ $w = $this->w;
1201
+ $dw = $this->dw;
1202
+ $init_encrypt = '';
1203
+ $init_decrypt = '';
1204
+ } else {
1205
+ for ($i = 0, $cw = count($this->w); $i < $cw; ++$i) {
1206
+ $w[] = '$w[' . $i . ']';
1207
+ $dw[] = '$dw[' . $i . ']';
 
 
 
 
 
 
 
 
 
 
 
 
1208
  }
1209
+ $init_encrypt = '$w = $self->w;';
1210
+ $init_decrypt = '$dw = $self->dw;';
1211
  }
1212
 
1213
+ $code_hash = md5(str_pad("Crypt_Rijndael, {$this->mode}, {$this->block_size}, ", 32, "\0") . implode(',', $w));
1214
+
1215
+ if (!isset($lambda_functions[$code_hash])) {
1216
+ $Nr = $this->Nr;
1217
+ $Nb = $this->Nb;
1218
+ $c = $this->c;
1219
+
1220
+ // Generating encrypt code:
1221
+ $init_encrypt.= '
1222
+ static $t0, $t1, $t2, $t3, $sbox;
1223
+ if (!$t0) {
1224
+ for ($i = 0; $i < 256; ++$i) {
1225
+ $t0[$i] = (int)$self->t0[$i];
1226
+ $t1[$i] = (int)$self->t1[$i];
1227
+ $t2[$i] = (int)$self->t2[$i];
1228
+ $t3[$i] = (int)$self->t3[$i];
1229
+ $sbox[$i] = (int)$self->sbox[$i];
1230
+ }
1231
+ }
1232
+ ';
1233
 
1234
+ $s = 'e';
1235
+ $e = 's';
1236
+ $wc = $Nb - 1;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1237
 
1238
+ // Preround: addRoundKey
1239
+ $encrypt_block = '$in = unpack("N*", $in);'."\n";
1240
+ for ($i = 0; $i < $Nb; ++$i) {
1241
+ $encrypt_block .= '$s'.$i.' = $in['.($i + 1).'] ^ '.$w[++$wc].";\n";
1242
+ }
 
 
 
 
 
1243
 
1244
+ // Mainrounds: shiftRows + subWord + mixColumns + addRoundKey
1245
+ for ($round = 1; $round < $Nr; ++$round) {
1246
+ list($s, $e) = array($e, $s);
1247
+ for ($i = 0; $i < $Nb; ++$i) {
1248
+ $encrypt_block.=
1249
+ '$'.$e.$i.' =
1250
+ $t0[($'.$s.$i .' >> 24) & 0xff] ^
1251
+ $t1[($'.$s.(($i + $c[1]) % $Nb).' >> 16) & 0xff] ^
1252
+ $t2[($'.$s.(($i + $c[2]) % $Nb).' >> 8) & 0xff] ^
1253
+ $t3[ $'.$s.(($i + $c[3]) % $Nb).' & 0xff] ^
1254
+ '.$w[++$wc].";\n";
1255
+ }
 
 
 
 
 
 
 
 
 
 
 
1256
  }
 
1257
 
1258
+ // Finalround: subWord + shiftRows + addRoundKey
1259
+ for ($i = 0; $i < $Nb; ++$i) {
1260
+ $encrypt_block.=
1261
+ '$'.$e.$i.' =
1262
+ $sbox[ $'.$e.$i.' & 0xff] |
1263
+ ($sbox[($'.$e.$i.' >> 8) & 0xff] << 8) |
1264
+ ($sbox[($'.$e.$i.' >> 16) & 0xff] << 16) |
1265
+ ($sbox[($'.$e.$i.' >> 24) & 0xff] << 24);'."\n";
1266
+ }
1267
+ $encrypt_block .= '$in = pack("N*"'."\n";
1268
+ for ($i = 0; $i < $Nb; ++$i) {
1269
+ $encrypt_block.= ',
1270
+ ($'.$e.$i .' & 0xFF000000) ^
1271
+ ($'.$e.(($i + $c[1]) % $Nb).' & 0x00FF0000) ^
1272
+ ($'.$e.(($i + $c[2]) % $Nb).' & 0x0000FF00) ^
1273
+ ($'.$e.(($i + $c[3]) % $Nb).' & 0x000000FF) ^
1274
+ '.$w[$i]."\n";
1275
+ }
1276
+ $encrypt_block .= ');';
1277
+
1278
+ // Generating decrypt code:
1279
+ $init_decrypt.= '
1280
+ static $dt0, $dt1, $dt2, $dt3, $isbox;
1281
+ if (!$dt0) {
1282
+ for ($i = 0; $i < 256; ++$i) {
1283
+ $dt0[$i] = (int)$self->dt0[$i];
1284
+ $dt1[$i] = (int)$self->dt1[$i];
1285
+ $dt2[$i] = (int)$self->dt2[$i];
1286
+ $dt3[$i] = (int)$self->dt3[$i];
1287
+ $isbox[$i] = (int)$self->isbox[$i];
1288
+ }
1289
+ }
1290
+ ';
1291
 
1292
+ $s = 'e';
1293
+ $e = 's';
1294
+ $wc = $Nb - 1;
1295
 
1296
+ // Preround: addRoundKey
1297
+ $decrypt_block = '$in = unpack("N*", $in);'."\n";
1298
+ for ($i = 0; $i < $Nb; ++$i) {
1299
+ $decrypt_block .= '$s'.$i.' = $in['.($i + 1).'] ^ '.$dw[++$wc].';'."\n";
1300
+ }
 
 
 
 
 
 
 
 
 
1301
 
1302
+ // Mainrounds: shiftRows + subWord + mixColumns + addRoundKey
1303
+ for ($round = 1; $round < $Nr; ++$round) {
1304
+ list($s, $e) = array($e, $s);
1305
+ for ($i = 0; $i < $Nb; ++$i) {
1306
+ $decrypt_block.=
1307
+ '$'.$e.$i.' =
1308
+ $dt0[($'.$s.$i .' >> 24) & 0xff] ^
1309
+ $dt1[($'.$s.(($Nb + $i - $c[1]) % $Nb).' >> 16) & 0xff] ^
1310
+ $dt2[($'.$s.(($Nb + $i - $c[2]) % $Nb).' >> 8) & 0xff] ^
1311
+ $dt3[ $'.$s.(($Nb + $i - $c[3]) % $Nb).' & 0xff] ^
1312
+ '.$dw[++$wc].";\n";
1313
+ }
1314
+ }
1315
 
1316
+ // Finalround: subWord + shiftRows + addRoundKey
1317
+ for ($i = 0; $i < $Nb; ++$i) {
1318
+ $decrypt_block.=
1319
+ '$'.$e.$i.' =
1320
+ $isbox[ $'.$e.$i.' & 0xff] |
1321
+ ($isbox[($'.$e.$i.' >> 8) & 0xff] << 8) |
1322
+ ($isbox[($'.$e.$i.' >> 16) & 0xff] << 16) |
1323
+ ($isbox[($'.$e.$i.' >> 24) & 0xff] << 24);'."\n";
1324
+ }
1325
+ $decrypt_block .= '$in = pack("N*"'."\n";
1326
+ for ($i = 0; $i < $Nb; ++$i) {
1327
+ $decrypt_block.= ',
1328
+ ($'.$e.$i. ' & 0xFF000000) ^
1329
+ ($'.$e.(($Nb + $i - $c[1]) % $Nb).' & 0x00FF0000) ^
1330
+ ($'.$e.(($Nb + $i - $c[2]) % $Nb).' & 0x0000FF00) ^
1331
+ ($'.$e.(($Nb + $i - $c[3]) % $Nb).' & 0x000000FF) ^
1332
+ '.$dw[$i]."\n";
1333
+ }
1334
+ $decrypt_block .= ');';
1335
+
1336
+ $lambda_functions[$code_hash] = $this->_createInlineCryptFunction(
1337
+ array(
1338
+ 'init_crypt' => '',
1339
+ 'init_encrypt' => $init_encrypt,
1340
+ 'init_decrypt' => $init_decrypt,
1341
+ 'encrypt_block' => $encrypt_block,
1342
+ 'decrypt_block' => $decrypt_block
1343
+ )
1344
+ );
1345
  }
1346
+ $this->inline_crypt = $lambda_functions[$code_hash];
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1347
  }
1348
  }
 
 
 
phpseclib/Crypt/TripleDES.php CHANGED
@@ -1,1063 +1,428 @@
1
- <?php
2
- /* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
3
-
4
- /**
5
- * Pure-PHP implementation of Triple DES.
6
- *
7
- * Uses mcrypt, if available, and an internal implementation, otherwise. Operates in the EDE3 mode (encrypt-decrypt-encrypt).
8
- *
9
- * PHP versions 4 and 5
10
- *
11
- * Here's a short example of how to use this library:
12
- * <code>
13
- * <?php
14
- * include('Crypt/TripleDES.php');
15
- *
16
- * $des = new Crypt_TripleDES();
17
- *
18
- * $des->setKey('abcdefghijklmnopqrstuvwx');
19
- *
20
- * $size = 10 * 1024;
21
- * $plaintext = '';
22
- * for ($i = 0; $i < $size; $i++) {
23
- * $plaintext.= 'a';
24
- * }
25
- *
26
- * echo $des->decrypt($des->encrypt($plaintext));
27
- * ?>
28
- * </code>
29
- *
30
- * LICENSE: Permission is hereby granted, free of charge, to any person obtaining a copy
31
- * of this software and associated documentation files (the "Software"), to deal
32
- * in the Software without restriction, including without limitation the rights
33
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
34
- * copies of the Software, and to permit persons to whom the Software is
35
- * furnished to do so, subject to the following conditions:
36
- *
37
- * The above copyright notice and this permission notice shall be included in
38
- * all copies or substantial portions of the Software.
39
- *
40
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
41
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
42
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
43
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
44
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
45
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
46
- * THE SOFTWARE.
47
- *
48
- * @category Crypt
49
- * @package Crypt_TripleDES
50
- * @author Jim Wigginton <terrafrost@php.net>
51
- * @copyright MMVII Jim Wigginton
52
- * @license http://www.opensource.org/licenses/mit-license.html MIT License
53
- * @version $Id: TripleDES.php,v 1.13 2010/02/26 03:40:25 terrafrost Exp $
54
- * @link http://phpseclib.sourceforge.net
55
- */
56
-
57
- /**
58
- * Include Crypt_DES
59
- */
60
- if (!class_exists('Crypt_DES')) {
61
- require_once('DES.php');
62
- }
63
-
64
- /**
65
- * Encrypt / decrypt using inner chaining
66
- *
67
- * Inner chaining is used by SSH-1 and is generally considered to be less secure then outer chaining (CRYPT_DES_MODE_CBC3).
68
- */
69
- define('CRYPT_DES_MODE_3CBC', -2);
70
-
71
- /**
72
- * Encrypt / decrypt using outer chaining
73
- *
74
- * Outer chaining is used by SSH-2 and when the mode is set to CRYPT_DES_MODE_CBC.
75
- */
76
- define('CRYPT_DES_MODE_CBC3', CRYPT_DES_MODE_CBC);
77
-
78
- /**
79
- * Pure-PHP implementation of Triple DES.
80
- *
81
- * @author Jim Wigginton <terrafrost@php.net>
82
- * @version 0.1.0
83
- * @access public
84
- * @package Crypt_TerraDES
85
- */
86
- class Crypt_TripleDES {
87
- /**
88
- * The Three Keys
89
- *
90
- * @see Crypt_TripleDES::setKey()
91
- * @var String
92
- * @access private
93
- */
94
- var $key = "\0\0\0\0\0\0\0\0";
95
-
96
- /**
97
- * The Encryption Mode
98
- *
99
- * @see Crypt_TripleDES::Crypt_TripleDES()
100
- * @var Integer
101
- * @access private
102
- */
103
- var $mode = CRYPT_DES_MODE_CBC;
104
-
105
- /**
106
- * Continuous Buffer status
107
- *
108
- * @see Crypt_TripleDES::enableContinuousBuffer()
109
- * @var Boolean
110
- * @access private
111
- */
112
- var $continuousBuffer = false;
113
-
114
- /**
115
- * Padding status
116
- *
117
- * @see Crypt_TripleDES::enablePadding()
118
- * @var Boolean
119
- * @access private
120
- */
121
- var $padding = true;
122
-
123
- /**
124
- * The Initialization Vector
125
- *
126
- * @see Crypt_TripleDES::setIV()
127
- * @var String
128
- * @access private
129
- */
130
- var $iv = "\0\0\0\0\0\0\0\0";
131
-
132
- /**
133
- * A "sliding" Initialization Vector
134
- *
135
- * @see Crypt_TripleDES::enableContinuousBuffer()
136
- * @var String
137
- * @access private
138
- */
139
- var $encryptIV = "\0\0\0\0\0\0\0\0";
140
-
141
- /**
142
- * A "sliding" Initialization Vector
143
- *
144
- * @see Crypt_TripleDES::enableContinuousBuffer()
145
- * @var String
146
- * @access private
147
- */
148
- var $decryptIV = "\0\0\0\0\0\0\0\0";
149
-
150
- /**
151
- * The Crypt_DES objects
152
- *
153
- * @var Array
154
- * @access private
155
- */
156
- var $des;
157
-
158
- /**
159
- * mcrypt resource for encryption
160
- *
161
- * The mcrypt resource can be recreated every time something needs to be created or it can be created just once.
162
- * Since mcrypt operates in continuous mode, by default, it'll need to be recreated when in non-continuous mode.
163
- *
164
- * @see Crypt_TripleDES::encrypt()
165
- * @var String
166
- * @access private
167
- */
168
- var $enmcrypt;
169
-
170
- /**
171
- * mcrypt resource for decryption
172
- *
173
- * The mcrypt resource can be recreated every time something needs to be created or it can be created just once.
174
- * Since mcrypt operates in continuous mode, by default, it'll need to be recreated when in non-continuous mode.
175
- *
176
- * @see Crypt_TripleDES::decrypt()
177
- * @var String
178
- * @access private
179
- */
180
- var $demcrypt;
181
-
182
- /**
183
- * Does the enmcrypt resource need to be (re)initialized?
184
- *
185
- * @see Crypt_TripleDES::setKey()
186
- * @see Crypt_TripleDES::setIV()
187
- * @var Boolean
188
- * @access private
189
- */
190
- var $enchanged = true;
191
-
192
- /**
193
- * Does the demcrypt resource need to be (re)initialized?
194
- *
195
- * @see Crypt_TripleDES::setKey()
196
- * @see Crypt_TripleDES::setIV()
197
- * @var Boolean
198
- * @access private
199
- */
200
- var $dechanged = true;
201
-
202
- /**
203
- * Is the mode one that is paddable?
204
- *
205
- * @see Crypt_TripleDES::Crypt_TripleDES()
206
- * @var Boolean
207
- * @access private
208
- */
209
- var $paddable = false;
210
-
211
- /**
212
- * Encryption buffer for CTR, OFB and CFB modes
213
- *
214
- * @see Crypt_TripleDES::encrypt()
215
- * @var String
216
- * @access private
217
- */
218
- var $enbuffer = '';
219
-
220
- /**
221
- * Decryption buffer for CTR, OFB and CFB modes
222
- *
223
- * @see Crypt_TripleDES::decrypt()
224
- * @var String
225
- * @access private
226
- */
227
- var $debuffer = '';
228
-
229
- /**
230
- * mcrypt resource for CFB mode
231
- *
232
- * @see Crypt_TripleDES::encrypt()
233
- * @see Crypt_TripleDES::decrypt()
234
- * @var String
235
- * @access private
236
- */
237
- var $ecb;
238
-
239
- /**
240
- * Default Constructor.
241
- *
242
- * Determines whether or not the mcrypt extension should be used. $mode should only, at present, be
243
- * CRYPT_DES_MODE_ECB or CRYPT_DES_MODE_CBC. If not explictly set, CRYPT_DES_MODE_CBC will be used.
244
- *
245
- * @param optional Integer $mode
246
- * @return Crypt_TripleDES
247
- * @access public
248
- */
249
- function Crypt_TripleDES($mode = CRYPT_DES_MODE_CBC)
250
- {
251
- if ( !defined('CRYPT_DES_MODE') ) {
252
- switch (true) {
253
- case extension_loaded('mcrypt') && in_array('tripledes', mcrypt_list_algorithms()):
254
- define('CRYPT_DES_MODE', CRYPT_DES_MODE_MCRYPT);
255
- break;
256
- default:
257
- define('CRYPT_DES_MODE', CRYPT_DES_MODE_INTERNAL);
258
- }
259
- }
260
-
261
- if ( $mode == CRYPT_DES_MODE_3CBC ) {
262
- $this->mode = CRYPT_DES_MODE_3CBC;
263
- $this->des = array(
264
- new Crypt_DES(CRYPT_DES_MODE_CBC),
265
- new Crypt_DES(CRYPT_DES_MODE_CBC),
266
- new Crypt_DES(CRYPT_DES_MODE_CBC)
267
- );
268
- $this->paddable = true;
269
-
270
- // we're going to be doing the padding, ourselves, so disable it in the Crypt_DES objects
271
- $this->des[0]->disablePadding();
272
- $this->des[1]->disablePadding();
273
- $this->des[2]->disablePadding();
274
-
275
- return;
276
- }
277
-
278
- switch ( CRYPT_DES_MODE ) {
279
- case CRYPT_DES_MODE_MCRYPT:
280
- switch ($mode) {
281
- case CRYPT_DES_MODE_ECB:
282
- $this->paddable = true;
283
- $this->mode = MCRYPT_MODE_ECB;
284
- break;
285
- case CRYPT_DES_MODE_CTR:
286
- $this->mode = 'ctr';
287
- break;
288
- case CRYPT_DES_MODE_CFB:
289
- $this->mode = 'ncfb';
290
- break;
291
- case CRYPT_DES_MODE_OFB:
292
- $this->mode = MCRYPT_MODE_NOFB;
293
- break;
294
- case CRYPT_DES_MODE_CBC:
295
- default:
296
- $this->paddable = true;
297
- $this->mode = MCRYPT_MODE_CBC;
298
- }
299
-
300
- break;
301
- default:
302
- $this->des = array(
303
- new Crypt_DES(CRYPT_DES_MODE_ECB),
304
- new Crypt_DES(CRYPT_DES_MODE_ECB),
305
- new Crypt_DES(CRYPT_DES_MODE_ECB)
306
- );
307
-
308
- // we're going to be doing the padding, ourselves, so disable it in the Crypt_DES objects
309
- $this->des[0]->disablePadding();
310
- $this->des[1]->disablePadding();
311
- $this->des[2]->disablePadding();
312
-
313
- switch ($mode) {
314
- case CRYPT_DES_MODE_ECB:
315
- case CRYPT_DES_MODE_CBC:
316
- $this->paddable = true;
317
- $this->mode = $mode;
318
- break;
319
- case CRYPT_DES_MODE_CTR:
320
- case CRYPT_DES_MODE_CFB:
321
- case CRYPT_DES_MODE_OFB:
322
- $this->mode = $mode;
323
- break;
324
- default:
325
- $this->paddable = true;
326
- $this->mode = CRYPT_DES_MODE_CBC;
327
- }
328
- }
329
- }
330
-
331
- /**
332
- * Sets the key.
333
- *
334
- * Keys can be of any length. Triple DES, itself, can use 128-bit (eg. strlen($key) == 16) or
335
- * 192-bit (eg. strlen($key) == 24) keys. This function pads and truncates $key as appropriate.
336
- *
337
- * DES also requires that every eighth bit be a parity bit, however, we'll ignore that.
338
- *
339
- * If the key is not explicitly set, it'll be assumed to be all zero's.
340
- *
341
- * @access public
342
- * @param String $key
343
- */
344
- function setKey($key)
345
- {
346
- $length = strlen($key);
347
- if ($length > 8) {
348
- $key = str_pad($key, 24, chr(0));
349
- // if $key is between 64 and 128-bits, use the first 64-bits as the last, per this:
350
- // http://php.net/function.mcrypt-encrypt#47973
351
- //$key = $length <= 16 ? substr_replace($key, substr($key, 0, 8), 16) : substr($key, 0, 24);
352
- } else {
353
- $key = str_pad($key, 8, chr(0));
354
- }
355
- $this->key = $key;
356
- switch (true) {
357
- case CRYPT_DES_MODE == CRYPT_DES_MODE_INTERNAL:
358
- case $this->mode == CRYPT_DES_MODE_3CBC:
359
- $this->des[0]->setKey(substr($key, 0, 8));
360
- $this->des[1]->setKey(substr($key, 8, 8));
361
- $this->des[2]->setKey(substr($key, 16, 8));
362
- }
363
- $this->enchanged = $this->dechanged = true;
364
- }
365
-
366
- /**
367
- * Sets the password.
368
- *
369
- * Depending on what $method is set to, setPassword()'s (optional) parameters are as follows:
370
- * {@link http://en.wikipedia.org/wiki/PBKDF2 pbkdf2}:
371
- * $hash, $salt, $method
372
- *
373
- * @param String $password
374
- * @param optional String $method
375
- * @access public
376
- */
377
- function setPassword($password, $method = 'pbkdf2')
378
- {
379
- $key = '';
380
-
381
- switch ($method) {
382
- default: // 'pbkdf2'
383
- list(, , $hash, $salt, $count) = func_get_args();
384
- if (!isset($hash)) {
385
- $hash = 'sha1';
386
- }
387
- // WPA and WPA use the SSID as the salt
388
- if (!isset($salt)) {
389
- $salt = 'phpseclib';
390
- }
391
- // RFC2898#section-4.2 uses 1,000 iterations by default
392
- // WPA and WPA2 use 4,096.
393
- if (!isset($count)) {
394
- $count = 1000;
395
- }
396
-
397
- if (!class_exists('Crypt_Hash')) {
398
- require_once('Crypt/Hash.php');
399
- }
400
-
401
- $i = 1;
402
- while (strlen($key) < 24) { // $dkLen == 24
403
- $hmac = new Crypt_Hash();
404
- $hmac->setHash($hash);
405
- $hmac->setKey($password);
406
- $f = $u = $hmac->hash($salt . pack('N', $i++));
407
- for ($j = 2; $j <= $count; $j++) {
408
- $u = $hmac->hash($u);
409
- $f^= $u;
410
- }
411
- $key.= $f;
412
- }
413
- }
414
-
415
- $this->setKey($key);
416
- }
417
-
418
- /**
419
- * Sets the initialization vector. (optional)
420
- *
421
- * SetIV is not required when CRYPT_DES_MODE_ECB is being used. If not explictly set, it'll be assumed
422
- * to be all zero's.
423
- *
424
- * @access public
425
- * @param String $iv
426
- */
427
- function setIV($iv)
428
- {
429
- $this->encryptIV = $this->decryptIV = $this->iv = str_pad(substr($iv, 0, 8), 8, chr(0));
430
- if ($this->mode == CRYPT_DES_MODE_3CBC) {
431
- $this->des[0]->setIV($iv);
432
- $this->des[1]->setIV($iv);
433
- $this->des[2]->setIV($iv);
434
- }
435
- $this->enchanged = $this->dechanged = true;
436
- }
437
-
438
- /**
439
- * Generate CTR XOR encryption key
440
- *
441
- * Encrypt the output of this and XOR it against the ciphertext / plaintext to get the
442
- * plaintext / ciphertext in CTR mode.
443
- *
444
- * @see Crypt_TripleDES::decrypt()
445
- * @see Crypt_TripleDES::encrypt()
446
- * @access private
447
- * @param Integer $length
448
- * @param String $iv
449
- */
450
- function _generate_xor($length, &$iv)
451
- {
452
- $xor = '';
453
- $num_blocks = ($length + 7) >> 3;
454
- for ($i = 0; $i < $num_blocks; $i++) {
455
- $xor.= $iv;
456
- for ($j = 4; $j <= 8; $j+=4) {
457
- $temp = substr($iv, -$j, 4);
458
- switch ($temp) {
459
- case "\xFF\xFF\xFF\xFF":
460
- $iv = substr_replace($iv, "\x00\x00\x00\x00", -$j, 4);
461
- break;
462
- case "\x7F\xFF\xFF\xFF":
463
- $iv = substr_replace($iv, "\x80\x00\x00\x00", -$j, 4);
464
- break 2;
465
- default:
466
- extract(unpack('Ncount', $temp));
467
- $iv = substr_replace($iv, pack('N', $count + 1), -$j, 4);
468
- break 2;
469
- }
470
- }
471
- }
472
-
473
- return $xor;
474
- }
475
-
476
- /**
477
- * Encrypts a message.
478
- *
479
- * @access public
480
- * @param String $plaintext
481
- */
482
- function encrypt($plaintext)
483
- {
484
- if ($this->paddable) {
485
- $plaintext = $this->_pad($plaintext);
486
- }
487
-
488
- // if the key is smaller then 8, do what we'd normally do
489
- if ($this->mode == CRYPT_DES_MODE_3CBC && strlen($this->key) > 8) {
490
- $ciphertext = $this->des[2]->encrypt($this->des[1]->decrypt($this->des[0]->encrypt($plaintext)));
491
-
492
- return $ciphertext;
493
- }
494
-
495
- if ( CRYPT_DES_MODE == CRYPT_DES_MODE_MCRYPT ) {
496
- if ($this->enchanged) {
497
- if (!isset($this->enmcrypt)) {
498
- $this->enmcrypt = mcrypt_module_open(MCRYPT_3DES, '', $this->mode, '');
499
- }
500
- mcrypt_generic_init($this->enmcrypt, $this->key, $this->encryptIV);
501
- if ($this->mode != 'ncfb') {
502
- $this->enchanged = false;
503
- }
504
- }
505
-
506
- if ($this->mode != 'ncfb') {
507
- $ciphertext = mcrypt_generic($this->enmcrypt, $plaintext);
508
- } else {
509
- if ($this->enchanged) {
510
- $this->ecb = mcrypt_module_open(MCRYPT_3DES, '', MCRYPT_MODE_ECB, '');
511
- mcrypt_generic_init($this->ecb, $this->key, "\0\0\0\0\0\0\0\0");
512
- $this->enchanged = false;
513
- }
514
-
515
- if (strlen($this->enbuffer)) {
516
- $ciphertext = $plaintext ^ substr($this->encryptIV, strlen($this->enbuffer));
517
- $this->enbuffer.= $ciphertext;
518
- if (strlen($this->enbuffer) == 8) {
519
- $this->encryptIV = $this->enbuffer;
520
- $this->enbuffer = '';
521
- mcrypt_generic_init($this->enmcrypt, $this->key, $this->encryptIV);
522
- }
523
- $plaintext = substr($plaintext, strlen($ciphertext));
524
- } else {
525
- $ciphertext = '';
526
- }
527
-
528
- $last_pos = strlen($plaintext) & 0xFFFFFFF8;
529
- $ciphertext.= $last_pos ? mcrypt_generic($this->enmcrypt, substr($plaintext, 0, $last_pos)) : '';
530
-
531
- if (strlen($plaintext) & 0x7) {
532
- if (strlen($ciphertext)) {
533
- $this->encryptIV = substr($ciphertext, -8);
534
- }
535
- $this->encryptIV = mcrypt_generic($this->ecb, $this->encryptIV);
536
- $this->enbuffer = substr($plaintext, $last_pos) ^ $this->encryptIV;
537
- $ciphertext.= $this->enbuffer;
538
- }
539
- }
540
-
541
- if (!$this->continuousBuffer) {
542
- mcrypt_generic_init($this->enmcrypt, $this->key, $this->encryptIV);
543
- }
544
-
545
- return $ciphertext;
546
- }
547
-
548
- if (strlen($this->key) <= 8) {
549
- $this->des[0]->mode = $this->mode;
550
-
551
- return $this->des[0]->encrypt($plaintext);
552
- }
553
-
554
- $des = $this->des;
555
-
556
- $buffer = &$this->enbuffer;
557
- $continuousBuffer = $this->continuousBuffer;
558
- $ciphertext = '';
559
- switch ($this->mode) {
560
- case CRYPT_DES_MODE_ECB:
561
- for ($i = 0; $i < strlen($plaintext); $i+=8) {
562
- $block = substr($plaintext, $i, 8);
563
- // all of these _processBlock calls could, in theory, be put in a function - say Crypt_TripleDES::_ede_encrypt() or something.
564
- // only problem with that: it would slow encryption and decryption down. $this->des would have to be called every time that
565
- // function is called, instead of once for the whole string of text that's being encrypted, which would, in turn, make
566
- // encryption and decryption take more time, per this:
567
- //
568
- // http://blog.libssh2.org/index.php?/archives/21-Compiled-Variables.html
569
- $block = $des[0]->_processBlock($block, CRYPT_DES_ENCRYPT);
570
- $block = $des[1]->_processBlock($block, CRYPT_DES_DECRYPT);
571
- $block = $des[2]->_processBlock($block, CRYPT_DES_ENCRYPT);
572
- $ciphertext.= $block;
573
- }
574
- break;
575
- case CRYPT_DES_MODE_CBC:
576
- $xor = $this->encryptIV;
577
- for ($i = 0; $i < strlen($plaintext); $i+=8) {
578
- $block = substr($plaintext, $i, 8) ^ $xor;
579
- $block = $des[0]->_processBlock($block, CRYPT_DES_ENCRYPT);
580
- $block = $des[1]->_processBlock($block, CRYPT_DES_DECRYPT);
581
- $block = $des[2]->_processBlock($block, CRYPT_DES_ENCRYPT);
582
- $xor = $block;
583
- $ciphertext.= $block;
584
- }
585
- if ($this->continuousBuffer) {
586
- $this->encryptIV = $xor;
587
- }
588
- break;
589
- case CRYPT_DES_MODE_CTR:
590
- $xor = $this->encryptIV;
591
- if (strlen($buffer['encrypted'])) {
592
- for ($i = 0; $i < strlen($plaintext); $i+=8) {
593
- $block = substr($plaintext, $i, 8);
594
- $key = $this->_generate_xor(8, $xor);
595
- $key = $des[0]->_processBlock($key, CRYPT_DES_ENCRYPT);
596
- $key = $des[1]->_processBlock($key, CRYPT_DES_DECRYPT);
597
- $key = $des[2]->_processBlock($key, CRYPT_DES_ENCRYPT);
598
- $buffer['encrypted'].= $key;
599
- $key = $this->_string_shift($buffer['encrypted'], 8);
600
- $ciphertext.= $block ^ $key;
601
- }
602
- } else {
603
- for ($i = 0; $i < strlen($plaintext); $i+=8) {
604
- $block = substr($plaintext, $i, 8);
605
- $key = $this->_generate_xor(8, $xor);
606
- $key = $des[0]->_processBlock($key, CRYPT_DES_ENCRYPT);
607
- $key = $des[1]->_processBlock($key, CRYPT_DES_DECRYPT);
608
- $key = $des[2]->_processBlock($key, CRYPT_DES_ENCRYPT);
609
- $ciphertext.= $block ^ $key;
610
- }
611
- }
612
- if ($this->continuousBuffer) {
613
- $this->encryptIV = $xor;
614
- if ($start = strlen($plaintext) & 7) {
615
- $buffer['encrypted'] = substr($key, $start) . $buffer;
616
- }
617
- }
618
- break;
619
- case CRYPT_DES_MODE_CFB:
620
- if (strlen($buffer['xor'])) {
621
- $ciphertext = $plaintext ^ $buffer['xor'];
622
- $iv = $buffer['encrypted'] . $ciphertext;
623
- $start = strlen($ciphertext);
624
- $buffer['encrypted'].= $ciphertext;
625
- $buffer['xor'] = substr($buffer['xor'], strlen($ciphertext));
626
- } else {
627
- $ciphertext = '';
628
- $iv = $this->encryptIV;
629
- $start = 0;
630
- }
631
-
632
- for ($i = $start; $i < strlen($plaintext); $i+=8) {
633
- $block = substr($plaintext, $i, 8);
634
- $iv = $des[0]->_processBlock($iv, CRYPT_DES_ENCRYPT);
635
- $iv = $des[1]->_processBlock($iv, CRYPT_DES_DECRYPT);
636
- $xor= $des[2]->_processBlock($iv, CRYPT_DES_ENCRYPT);
637
-
638
- $iv = $block ^ $xor;
639
- if ($continuousBuffer && strlen($iv) != 8) {
640
- $buffer = array(
641
- 'encrypted' => $iv,
642
- 'xor' => substr($xor, strlen($iv))
643
- );
644
- }
645
- $ciphertext.= $iv;
646
- }
647
-
648
- if ($this->continuousBuffer) {
649
- $this->encryptIV = $iv;
650
- }
651
- break;
652
- case CRYPT_DES_MODE_OFB:
653
- $xor = $this->encryptIV;
654
- if (strlen($buffer)) {
655
- for ($i = 0; $i < strlen($plaintext); $i+=8) {
656
- $xor = $des[0]->_processBlock($xor, CRYPT_DES_ENCRYPT);
657
- $xor = $des[1]->_processBlock($xor, CRYPT_DES_DECRYPT);
658
- $xor = $des[2]->_processBlock($xor, CRYPT_DES_ENCRYPT);
659
- $buffer.= $xor;
660
- $key = $this->_string_shift($buffer, 8);
661
- $ciphertext.= substr($plaintext, $i, 8) ^ $key;
662
- }
663
- } else {
664
- for ($i = 0; $i < strlen($plaintext); $i+=8) {
665
- $xor = $des[0]->_processBlock($xor, CRYPT_DES_ENCRYPT);
666
- $xor = $des[1]->_processBlock($xor, CRYPT_DES_DECRYPT);
667
- $xor = $des[2]->_processBlock($xor, CRYPT_DES_ENCRYPT);
668
- $ciphertext.= substr($plaintext, $i, 8) ^ $xor;
669
- }
670
- $key = $xor;
671
- }
672
- if ($this->continuousBuffer) {
673
- $this->encryptIV = $xor;
674
- if ($start = strlen($plaintext) & 7) {
675
- $buffer = substr($key, $start) . $buffer;
676
- }
677
- }
678
- }
679
-
680
- return $ciphertext;
681
- }
682
-
683
- /**
684
- * Decrypts a message.
685
- *
686
- * @access public
687
- * @param String $ciphertext
688
- */
689
- function decrypt($ciphertext)
690
- {
691
- if ($this->mode == CRYPT_DES_MODE_3CBC && strlen($this->key) > 8) {
692
- $plaintext = $this->des[0]->decrypt($this->des[1]->encrypt($this->des[2]->decrypt($ciphertext)));
693
-
694
- return $this->_unpad($plaintext);
695
- }
696
-
697
- if ($this->paddable) {
698
- // we pad with chr(0) since that's what mcrypt_generic does. to quote from http://php.net/function.mcrypt-generic :
699
- // "The data is padded with "\0" to make sure the length of the data is n * blocksize."
700
- $ciphertext = str_pad($ciphertext, (strlen($ciphertext) + 7) & 0xFFFFFFF8, chr(0));
701
- }
702
-
703
- if ( CRYPT_DES_MODE == CRYPT_DES_MODE_MCRYPT ) {
704
- if ($this->dechanged) {
705
- if (!isset($this->demcrypt)) {
706
- $this->demcrypt = mcrypt_module_open(MCRYPT_3DES, '', $this->mode, '');
707
- }
708
- mcrypt_generic_init($this->demcrypt, $this->key, $this->decryptIV);
709
- if ($this->mode != 'ncfb') {
710
- $this->dechanged = false;
711
- }
712
- }
713
-
714
- if ($this->mode != 'ncfb') {
715
- $plaintext = mdecrypt_generic($this->demcrypt, $ciphertext);
716
- } else {
717
- if ($this->dechanged) {
718
- $this->ecb = mcrypt_module_open(MCRYPT_3DES, '', MCRYPT_MODE_ECB, '');
719
- mcrypt_generic_init($this->ecb, $this->key, "\0\0\0\0\0\0\0\0");
720
- $this->dechanged = false;
721
- }
722
-
723
- if (strlen($this->debuffer)) {
724
- $plaintext = $ciphertext ^ substr($this->decryptIV, strlen($this->debuffer));
725
-
726
- $this->debuffer.= substr($ciphertext, 0, strlen($plaintext));
727
- if (strlen($this->debuffer) == 8) {
728
- $this->decryptIV = $this->debuffer;
729
- $this->debuffer = '';
730
- mcrypt_generic_init($this->demcrypt, $this->key, $this->decryptIV);
731
- }
732
- $ciphertext = substr($ciphertext, strlen($plaintext));
733
- } else {
734
- $plaintext = '';
735
- }
736
-
737
- $last_pos = strlen($ciphertext) & 0xFFFFFFF8;
738
- $plaintext.= $last_pos ? mdecrypt_generic($this->demcrypt, substr($ciphertext, 0, $last_pos)) : '';
739
-
740
- if (strlen($ciphertext) & 0x7) {
741
- if (strlen($plaintext)) {
742
- $this->decryptIV = substr($ciphertext, $last_pos - 8, 8);
743
- }
744
- $this->decryptIV = mcrypt_generic($this->ecb, $this->decryptIV);
745
- $this->debuffer = substr($ciphertext, $last_pos);
746
- $plaintext.= $this->debuffer ^ $this->decryptIV;
747
- }
748
-
749
- return $plaintext;
750
- }
751
-
752
- if (!$this->continuousBuffer) {
753
- mcrypt_generic_init($this->demcrypt, $this->key, $this->decryptIV);
754
- }
755
-
756
- return $this->paddable ? $this->_unpad($plaintext) : $plaintext;
757
- }
758
-
759
- if (strlen($this->key) <= 8) {
760
- $this->des[0]->mode = $this->mode;
761
- $plaintext = $this->des[0]->decrypt($ciphertext);
762
- return $this->paddable ? $this->_unpad($plaintext) : $plaintext;
763
- }
764
-
765
- $des = $this->des;
766
-
767
- $buffer = &$this->enbuffer;
768
- $continuousBuffer = $this->continuousBuffer;
769
- $plaintext = '';
770
- switch ($this->mode) {
771
- case CRYPT_DES_MODE_ECB:
772
- for ($i = 0; $i < strlen($ciphertext); $i+=8) {
773
- $block = substr($ciphertext, $i, 8);
774
- $block = $des[2]->_processBlock($block, CRYPT_DES_DECRYPT);
775
- $block = $des[1]->_processBlock($block, CRYPT_DES_ENCRYPT);
776
- $block = $des[0]->_processBlock($block, CRYPT_DES_DECRYPT);
777
- $plaintext.= $block;
778
- }
779
- break;
780
- case CRYPT_DES_MODE_CBC:
781
- $xor = $this->decryptIV;
782
- for ($i = 0; $i < strlen($ciphertext); $i+=8) {
783
- $orig = $block = substr($ciphertext, $i, 8);
784
- $block = $des[2]->_processBlock($block, CRYPT_DES_DECRYPT);
785
- $block = $des[1]->_processBlock($block, CRYPT_DES_ENCRYPT);
786
- $block = $des[0]->_processBlock($block, CRYPT_DES_DECRYPT);
787
- $plaintext.= $block ^ $xor;
788
- $xor = $orig;
789
- }
790
- if ($this->continuousBuffer) {
791
- $this->decryptIV = $xor;
792
- }
793
- break;
794
- case CRYPT_DES_MODE_CTR:
795
- $xor = $this->decryptIV;
796
- if (strlen($buffer['ciphertext'])) {
797
- for ($i = 0; $i < strlen($ciphertext); $i+=8) {
798
- $block = substr($ciphertext, $i, 8);
799
- $key = $this->_generate_xor(8, $xor);
800
- $key = $des[0]->_processBlock($key, CRYPT_DES_ENCRYPT);
801
- $key = $des[1]->_processBlock($key, CRYPT_DES_DECRYPT);
802
- $key = $des[2]->_processBlock($key, CRYPT_DES_ENCRYPT);
803
- $buffer['ciphertext'].= $key;
804
- $key = $this->_string_shift($buffer['ciphertext'], 8);
805
- $plaintext.= $block ^ $key;
806
- }
807
- } else {
808
- for ($i = 0; $i < strlen($ciphertext); $i+=8) {
809
- $block = substr($ciphertext, $i, 8);
810
- $key = $this->_generate_xor(8, $xor);
811
- $key = $des[0]->_processBlock($key, CRYPT_DES_ENCRYPT);
812
- $key = $des[1]->_processBlock($key, CRYPT_DES_DECRYPT);
813
- $key = $des[2]->_processBlock($key, CRYPT_DES_ENCRYPT);
814
- $plaintext.= $block ^ $key;
815
- }
816
- }
817
- if ($this->continuousBuffer) {
818
- $this->decryptIV = $xor;
819
- if ($start = strlen($plaintext) & 7) {
820
- $buffer['ciphertext'] = substr($key, $start) . $buffer['ciphertext'];
821
- }
822
- }
823
- break;
824
- case CRYPT_DES_MODE_CFB:
825
- if (strlen($buffer['ciphertext'])) {
826
- $plaintext = $ciphertext ^ substr($this->decryptIV, strlen($buffer['ciphertext']));
827
- $buffer['ciphertext'].= substr($ciphertext, 0, strlen($plaintext));
828
- if (strlen($buffer['ciphertext']) != 8) {
829
- $block = $this->decryptIV;
830
- } else {
831
- $block = $buffer['ciphertext'];
832
- $xor = $des[0]->_processBlock($buffer['ciphertext'], CRYPT_DES_ENCRYPT);
833
- $xor = $des[1]->_processBlock($xor, CRYPT_DES_DECRYPT);
834
- $xor = $des[2]->_processBlock($xor, CRYPT_DES_ENCRYPT);
835
- $buffer['ciphertext'] = '';
836
- }
837
- $start = strlen($plaintext);
838
- } else {
839
- $plaintext = '';
840
- $xor = $des[0]->_processBlock($this->decryptIV, CRYPT_DES_ENCRYPT);
841
- $xor = $des[1]->_processBlock($xor, CRYPT_DES_DECRYPT);
842
- $xor = $des[2]->_processBlock($xor, CRYPT_DES_ENCRYPT);
843
- $start = 0;
844
- }
845
-
846
- for ($i = $start; $i < strlen($ciphertext); $i+=8) {
847
- $block = substr($ciphertext, $i, 8);
848
- $plaintext.= $block ^ $xor;
849
- if ($continuousBuffer && strlen($block) != 8) {
850
- $buffer['ciphertext'].= $block;
851
- $block = $xor;
852
- } else if (strlen($block) == 8) {
853
- $xor = $des[0]->_processBlock($block, CRYPT_DES_ENCRYPT);
854
- $xor = $des[1]->_processBlock($xor, CRYPT_DES_DECRYPT);
855
- $xor = $des[2]->_processBlock($xor, CRYPT_DES_ENCRYPT);
856
- }
857
- }
858
- if ($this->continuousBuffer) {
859
- $this->decryptIV = $block;
860
- }
861
- break;
862
- case CRYPT_DES_MODE_OFB:
863
- $xor = $this->decryptIV;
864
- if (strlen($buffer)) {
865
- for ($i = 0; $i < strlen($ciphertext); $i+=8) {
866
- $xor = $des[0]->_processBlock($xor, CRYPT_DES_ENCRYPT);
867
- $xor = $des[1]->_processBlock($xor, CRYPT_DES_DECRYPT);
868
- $xor = $des[2]->_processBlock($xor, CRYPT_DES_ENCRYPT);
869
- $buffer.= $xor;
870
- $key = $this->_string_shift($buffer, 8);
871
- $plaintext.= substr($ciphertext, $i, 8) ^ $key;
872
- }
873
- } else {
874
- for ($i = 0; $i < strlen($ciphertext); $i+=8) {
875
- $xor = $des[0]->_processBlock($xor, CRYPT_DES_ENCRYPT);
876
- $xor = $des[1]->_processBlock($xor, CRYPT_DES_DECRYPT);
877
- $xor = $des[2]->_processBlock($xor, CRYPT_DES_ENCRYPT);
878
- $plaintext.= substr($ciphertext, $i, 8) ^ $xor;
879
- }
880
- $key = $xor;
881
- }
882
- if ($this->continuousBuffer) {
883
- $this->decryptIV = $xor;
884
- if ($start = strlen($ciphertext) & 7) {
885
- $buffer = substr($key, $start) . $buffer;
886
- }
887
- }
888
- }
889
-
890
- return $this->paddable ? $this->_unpad($plaintext) : $plaintext;
891
- }
892
-
893
- /**
894
- * Treat consecutive "packets" as if they are a continuous buffer.
895
- *
896
- * Say you have a 16-byte plaintext $plaintext. Using the default behavior, the two following code snippets
897
- * will yield different outputs:
898
- *
899
- * <code>
900
- * echo $des->encrypt(substr($plaintext, 0, 8));
901
- * echo $des->encrypt(substr($plaintext, 8, 8));
902
- * </code>
903
- * <code>
904
- * echo $des->encrypt($plaintext);
905
- * </code>
906
- *
907
- * The solution is to enable the continuous buffer. Although this will resolve the above discrepancy, it creates
908
- * another, as demonstrated with the following:
909
- *
910
- * <code>
911
- * $des->encrypt(substr($plaintext, 0, 8));
912
- * echo $des->decrypt($des->encrypt(substr($plaintext, 8, 8)));
913
- * </code>
914
- * <code>
915
- * echo $des->decrypt($des->encrypt(substr($plaintext, 8, 8)));
916
- * </code>
917
- *
918
- * With the continuous buffer disabled, these would yield the same output. With it enabled, they yield different
919
- * outputs. The reason is due to the fact that the initialization vector's change after every encryption /
920
- * decryption round when the continuous buffer is enabled. When it's disabled, they remain constant.
921
- *
922
- * Put another way, when the continuous buffer is enabled, the state of the Crypt_DES() object changes after each
923
- * encryption / decryption round, whereas otherwise, it'd remain constant. For this reason, it's recommended that
924
- * continuous buffers not be used. They do offer better security and are, in fact, sometimes required (SSH uses them),
925
- * however, they are also less intuitive and more likely to cause you problems.
926
- *
927
- * @see Crypt_TripleDES::disableContinuousBuffer()
928
- * @access public
929
- */
930
- function enableContinuousBuffer()
931
- {
932
- $this->continuousBuffer = true;
933
- if ($this->mode == CRYPT_DES_MODE_3CBC) {
934
- $this->des[0]->enableContinuousBuffer();
935
- $this->des[1]->enableContinuousBuffer();
936
- $this->des[2]->enableContinuousBuffer();
937
- }
938
- }
939
-
940
- /**
941
- * Treat consecutive packets as if they are a discontinuous buffer.
942
- *
943
- * The default behavior.
944
- *
945
- * @see Crypt_TripleDES::enableContinuousBuffer()
946
- * @access public
947
- */
948
- function disableContinuousBuffer()
949
- {
950
- $this->continuousBuffer = false;
951
- $this->encryptIV = $this->iv;
952
- $this->decryptIV = $this->iv;
953
-
954
- if ($this->mode == CRYPT_DES_MODE_3CBC) {
955
- $this->des[0]->disableContinuousBuffer();
956
- $this->des[1]->disableContinuousBuffer();
957
- $this->des[2]->disableContinuousBuffer();
958
- }
959
- }
960
-
961
- /**
962
- * Pad "packets".
963
- *
964
- * DES works by encrypting eight bytes at a time. If you ever need to encrypt or decrypt something that's not
965
- * a multiple of eight, it becomes necessary to pad the input so that it's length is a multiple of eight.
966
- *
967
- * Padding is enabled by default. Sometimes, however, it is undesirable to pad strings. Such is the case in SSH1,
968
- * where "packets" are padded with random bytes before being encrypted. Unpad these packets and you risk stripping
969
- * away characters that shouldn't be stripped away. (SSH knows how many bytes are added because the length is
970
- * transmitted separately)
971
- *
972
- * @see Crypt_TripleDES::disablePadding()
973
- * @access public
974
- */
975
- function enablePadding()
976
- {
977
- $this->padding = true;
978
- }
979
-
980
- /**
981
- * Do not pad packets.
982
- *
983
- * @see Crypt_TripleDES::enablePadding()
984
- * @access public
985
- */
986
- function disablePadding()
987
- {
988
- $this->padding = false;
989
- }
990
-
991
- /**
992
- * Pads a string
993
- *
994
- * Pads a string using the RSA PKCS padding standards so that its length is a multiple of the blocksize (8).
995
- * 8 - (strlen($text) & 7) bytes are added, each of which is equal to chr(8 - (strlen($text) & 7)
996
- *
997
- * If padding is disabled and $text is not a multiple of the blocksize, the string will be padded regardless
998
- * and padding will, hence forth, be enabled.
999
- *
1000
- * @see Crypt_TripleDES::_unpad()
1001
- * @access private
1002
- */
1003
- function _pad($text)
1004
- {
1005
- $length = strlen($text);
1006
-
1007
- if (!$this->padding) {
1008
- if (($length & 7) == 0) {
1009
- return $text;
1010
- } else {
1011
- user_error("The plaintext's length ($length) is not a multiple of the block size (8)", E_USER_NOTICE);
1012
- $this->padding = true;
1013
- }
1014
- }
1015
-
1016
- $pad = 8 - ($length & 7);
1017
- return str_pad($text, $length + $pad, chr($pad));
1018
- }
1019
-
1020
- /**
1021
- * Unpads a string
1022
- *
1023
- * If padding is enabled and the reported padding length is invalid the encryption key will be assumed to be wrong
1024
- * and false will be returned.
1025
- *
1026
- * @see Crypt_TripleDES::_pad()
1027
- * @access private
1028
- */
1029
- function _unpad($text)
1030
- {
1031
- if (!$this->padding) {
1032
- return $text;
1033
- }
1034
-
1035
- $length = ord($text[strlen($text) - 1]);
1036
-
1037
- if (!$length || $length > 8) {
1038
- return false;
1039
- }
1040
-
1041
- return substr($text, 0, -$length);
1042
- }
1043
-
1044
- /**
1045
- * String Shift
1046
- *
1047
- * Inspired by array_shift
1048
- *
1049
- * @param String $string
1050
- * @param optional Integer $index
1051
- * @return String
1052
- * @access private
1053
- */
1054
- function _string_shift(&$string, $index = 1)
1055
- {
1056
- $substr = substr($string, 0, $index);
1057
- $string = substr($string, $index);
1058
- return $substr;
1059
- }
1060
- }
1061
-
1062
- // vim: ts=4:sw=4:et:
1063
- // vim6: fdl=1:
1
+ <?php
2
+
3
+ /**
4
+ * Pure-PHP implementation of Triple DES.
5
+ *
6
+ * Uses mcrypt, if available, and an internal implementation, otherwise. Operates in the EDE3 mode (encrypt-decrypt-encrypt).
7
+ *
8
+ * PHP versions 4 and 5
9
+ *
10
+ * Here's a short example of how to use this library:
11
+ * <code>
12
+ * <?php
13
+ * include 'Crypt/TripleDES.php';
14
+ *
15
+ * $des = new Crypt_TripleDES();
16
+ *
17
+ * $des->setKey('abcdefghijklmnopqrstuvwx');
18
+ *
19
+ * $size = 10 * 1024;
20
+ * $plaintext = '';
21
+ * for ($i = 0; $i < $size; $i++) {
22
+ * $plaintext.= 'a';
23
+ * }
24
+ *
25
+ * echo $des->decrypt($des->encrypt($plaintext));
26
+ * ?>
27
+ * </code>
28
+ *
29
+ * LICENSE: Permission is hereby granted, free of charge, to any person obtaining a copy
30
+ * of this software and associated documentation files (the "Software"), to deal
31
+ * in the Software without restriction, including without limitation the rights
32
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
33
+ * copies of the Software, and to permit persons to whom the Software is
34
+ * furnished to do so, subject to the following conditions:
35
+ *
36
+ * The above copyright notice and this permission notice shall be included in
37
+ * all copies or substantial portions of the Software.
38
+ *
39
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
40
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
41
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
42
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
43
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
44
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
45
+ * THE SOFTWARE.
46
+ *
47
+ * @category Crypt
48
+ * @package Crypt_TripleDES
49
+ * @author Jim Wigginton <terrafrost@php.net>
50
+ * @copyright MMVII Jim Wigginton
51
+ * @license http://www.opensource.org/licenses/mit-license.html MIT License
52
+ * @link http://phpseclib.sourceforge.net
53
+ */
54
+
55
+ /**
56
+ * Include Crypt_DES
57
+ */
58
+ if (!class_exists('Crypt_DES')) {
59
+ include_once 'DES.php';
60
+ }
61
+
62
+ /**
63
+ * Encrypt / decrypt using inner chaining
64
+ *
65
+ * Inner chaining is used by SSH-1 and is generally considered to be less secure then outer chaining (CRYPT_DES_MODE_CBC3).
66
+ */
67
+ define('CRYPT_DES_MODE_3CBC', -2);
68
+
69
+ /**
70
+ * Encrypt / decrypt using outer chaining
71
+ *
72
+ * Outer chaining is used by SSH-2 and when the mode is set to CRYPT_DES_MODE_CBC.
73
+ */
74
+ define('CRYPT_DES_MODE_CBC3', CRYPT_DES_MODE_CBC);
75
+
76
+ /**
77
+ * Pure-PHP implementation of Triple DES.
78
+ *
79
+ * @package Crypt_TripleDES
80
+ * @author Jim Wigginton <terrafrost@php.net>
81
+ * @access public
82
+ */
83
+ class Crypt_TripleDES extends Crypt_DES
84
+ {
85
+ /**
86
+ * The default password key_size used by setPassword()
87
+ *
88
+ * @see Crypt_DES::password_key_size
89
+ * @see Crypt_Base::password_key_size
90
+ * @see Crypt_Base::setPassword()
91
+ * @var Integer
92
+ * @access private
93
+ */
94
+ var $password_key_size = 24;
95
+
96
+ /**
97
+ * The default salt used by setPassword()
98
+ *
99
+ * @see Crypt_Base::password_default_salt
100
+ * @see Crypt_Base::setPassword()
101
+ * @var String
102
+ * @access private
103
+ */
104
+ var $password_default_salt = 'phpseclib';
105
+
106
+ /**
107
+ * The namespace used by the cipher for its constants.
108
+ *
109
+ * @see Crypt_DES::const_namespace
110
+ * @see Crypt_Base::const_namespace
111
+ * @var String
112
+ * @access private
113
+ */
114
+ var $const_namespace = 'DES';
115
+
116
+ /**
117
+ * The mcrypt specific name of the cipher
118
+ *
119
+ * @see Crypt_DES::cipher_name_mcrypt
120
+ * @see Crypt_Base::cipher_name_mcrypt
121
+ * @var String
122
+ * @access private
123
+ */
124
+ var $cipher_name_mcrypt = 'tripledes';
125
+
126
+ /**
127
+ * Optimizing value while CFB-encrypting
128
+ *
129
+ * @see Crypt_Base::cfb_init_len
130
+ * @var Integer
131
+ * @access private
132
+ */
133
+ var $cfb_init_len = 750;
134
+
135
+ /**
136
+ * max possible size of $key
137
+ *
138
+ * @see Crypt_TripleDES::setKey()
139
+ * @see Crypt_DES::setKey()
140
+ * @var String
141
+ * @access private
142
+ */
143
+ var $key_size_max = 24;
144
+
145
+ /**
146
+ * Internal flag whether using CRYPT_DES_MODE_3CBC or not
147
+ *
148
+ * @var Boolean
149
+ * @access private
150
+ */
151
+ var $mode_3cbc;
152
+
153
+ /**
154
+ * The Crypt_DES objects
155
+ *
156
+ * Used only if $mode_3cbc === true
157
+ *
158
+ * @var Array
159
+ * @access private
160
+ */
161
+ var $des;
162
+
163
+ /**
164
+ * Default Constructor.
165
+ *
166
+ * Determines whether or not the mcrypt extension should be used.
167
+ *
168
+ * $mode could be:
169
+ *
170
+ * - CRYPT_DES_MODE_ECB
171
+ *
172
+ * - CRYPT_DES_MODE_CBC
173
+ *
174
+ * - CRYPT_DES_MODE_CTR
175
+ *
176
+ * - CRYPT_DES_MODE_CFB
177
+ *
178
+ * - CRYPT_DES_MODE_OFB
179
+ *
180
+ * - CRYPT_DES_MODE_3CBC
181
+ *
182
+ * If not explicitly set, CRYPT_DES_MODE_CBC will be used.
183
+ *
184
+ * @see Crypt_DES::Crypt_DES()
185
+ * @see Crypt_Base::Crypt_Base()
186
+ * @param optional Integer $mode
187
+ * @access public
188
+ */
189
+ function Crypt_TripleDES($mode = CRYPT_DES_MODE_CBC)
190
+ {
191
+ switch ($mode) {
192
+ // In case of CRYPT_DES_MODE_3CBC, we init as CRYPT_DES_MODE_CBC
193
+ // and additional flag us internally as 3CBC
194
+ case CRYPT_DES_MODE_3CBC:
195
+ parent::Crypt_Base(CRYPT_DES_MODE_CBC);
196
+ $this->mode_3cbc = true;
197
+
198
+ // This three $des'es will do the 3CBC work (if $key > 64bits)
199
+ $this->des = array(
200
+ new Crypt_DES(CRYPT_DES_MODE_CBC),
201
+ new Crypt_DES(CRYPT_DES_MODE_CBC),
202
+ new Crypt_DES(CRYPT_DES_MODE_CBC),
203
+ );
204
+
205
+ // we're going to be doing the padding, ourselves, so disable it in the Crypt_DES objects
206
+ $this->des[0]->disablePadding();
207
+ $this->des[1]->disablePadding();
208
+ $this->des[2]->disablePadding();
209
+ break;
210
+ // If not 3CBC, we init as usual
211
+ default:
212
+ parent::Crypt_Base($mode);
213
+ }
214
+ }
215
+
216
+ /**
217
+ * Sets the initialization vector. (optional)
218
+ *
219
+ * SetIV is not required when CRYPT_DES_MODE_ECB is being used. If not explicitly set, it'll be assumed
220
+ * to be all zero's.
221
+ *
222
+ * @see Crypt_Base::setIV()
223
+ * @access public
224
+ * @param String $iv
225
+ */
226
+ function setIV($iv)
227
+ {
228
+ parent::setIV($iv);
229
+ if ($this->mode_3cbc) {
230
+ $this->des[0]->setIV($iv);
231
+ $this->des[1]->setIV($iv);
232
+ $this->des[2]->setIV($iv);
233
+ }
234
+ }
235
+
236
+ /**
237
+ * Sets the key.
238
+ *
239
+ * Keys can be of any length. Triple DES, itself, can use 128-bit (eg. strlen($key) == 16) or
240
+ * 192-bit (eg. strlen($key) == 24) keys. This function pads and truncates $key as appropriate.
241
+ *
242
+ * DES also requires that every eighth bit be a parity bit, however, we'll ignore that.
243
+ *
244
+ * If the key is not explicitly set, it'll be assumed to be all null bytes.
245
+ *
246
+ * @access public
247
+ * @see Crypt_DES::setKey()
248
+ * @see Crypt_Base::setKey()
249
+ * @param String $key
250
+ */
251
+ function setKey($key)
252
+ {
253
+ $length = strlen($key);
254
+ if ($length > 8) {
255
+ $key = str_pad(substr($key, 0, 24), 24, chr(0));
256
+ // if $key is between 64 and 128-bits, use the first 64-bits as the last, per this:
257
+ // http://php.net/function.mcrypt-encrypt#47973
258
+ //$key = $length <= 16 ? substr_replace($key, substr($key, 0, 8), 16) : substr($key, 0, 24);
259
+ } else {
260
+ $key = str_pad($key, 8, chr(0));
261
+ }
262
+ parent::setKey($key);
263
+
264
+ // And in case of CRYPT_DES_MODE_3CBC:
265
+ // if key <= 64bits we not need the 3 $des to work,
266
+ // because we will then act as regular DES-CBC with just a <= 64bit key.
267
+ // So only if the key > 64bits (> 8 bytes) we will call setKey() for the 3 $des.
268
+ if ($this->mode_3cbc && $length > 8) {
269
+ $this->des[0]->setKey(substr($key, 0, 8));
270
+ $this->des[1]->setKey(substr($key, 8, 8));
271
+ $this->des[2]->setKey(substr($key, 16, 8));
272
+ }
273
+ }
274
+
275
+ /**
276
+ * Encrypts a message.
277
+ *
278
+ * @see Crypt_Base::encrypt()
279
+ * @access public
280
+ * @param String $plaintext
281
+ * @return String $cipertext
282
+ */
283
+ function encrypt($plaintext)
284
+ {
285
+ // parent::en/decrypt() is able to do all the work for all modes and keylengths,
286
+ // except for: CRYPT_DES_MODE_3CBC (inner chaining CBC) with a key > 64bits
287
+
288
+ // if the key is smaller then 8, do what we'd normally do
289
+ if ($this->mode_3cbc && strlen($this->key) > 8) {
290
+ return $this->des[2]->encrypt(
291
+ $this->des[1]->decrypt(
292
+ $this->des[0]->encrypt(
293
+ $this->_pad($plaintext)
294
+ )
295
+ )
296
+ );
297
+ }
298
+
299
+ return parent::encrypt($plaintext);
300
+ }
301
+
302
+ /**
303
+ * Decrypts a message.
304
+ *
305
+ * @see Crypt_Base::decrypt()
306
+ * @access public
307
+ * @param String $ciphertext
308
+ * @return String $plaintext
309
+ */
310
+ function decrypt($ciphertext)
311
+ {
312
+ if ($this->mode_3cbc && strlen($this->key) > 8) {
313
+ return $this->_unpad(
314
+ $this->des[0]->decrypt(
315
+ $this->des[1]->encrypt(
316
+ $this->des[2]->decrypt(
317
+ str_pad($ciphertext, (strlen($ciphertext) + 7) & 0xFFFFFFF8, "\0")
318
+ )
319
+ )
320
+ )
321
+ );
322
+ }
323
+
324
+ return parent::decrypt($ciphertext);
325
+ }
326
+
327
+ /**
328
+ * Treat consecutive "packets" as if they are a continuous buffer.
329
+ *
330
+ * Say you have a 16-byte plaintext $plaintext. Using the default behavior, the two following code snippets
331
+ * will yield different outputs:
332
+ *
333
+ * <code>
334
+ * echo $des->encrypt(substr($plaintext, 0, 8));
335
+ * echo $des->encrypt(substr($plaintext, 8, 8));
336
+ * </code>
337
+ * <code>
338
+ * echo $des->encrypt($plaintext);
339
+ * </code>
340
+ *
341
+ * The solution is to enable the continuous buffer. Although this will resolve the above discrepancy, it creates
342
+ * another, as demonstrated with the following:
343
+ *
344
+ * <code>
345
+ * $des->encrypt(substr($plaintext, 0, 8));
346
+ * echo $des->decrypt($des->encrypt(substr($plaintext, 8, 8)));
347
+ * </code>
348
+ * <code>
349
+ * echo $des->decrypt($des->encrypt(substr($plaintext, 8, 8)));
350
+ * </code>
351
+ *
352
+ * With the continuous buffer disabled, these would yield the same output. With it enabled, they yield different
353
+ * outputs. The reason is due to the fact that the initialization vector's change after every encryption /
354
+ * decryption round when the continuous buffer is enabled. When it's disabled, they remain constant.
355
+ *
356
+ * Put another way, when the continuous buffer is enabled, the state of the Crypt_DES() object changes after each
357
+ * encryption / decryption round, whereas otherwise, it'd remain constant. For this reason, it's recommended that
358
+ * continuous buffers not be used. They do offer better security and are, in fact, sometimes required (SSH uses them),
359
+ * however, they are also less intuitive and more likely to cause you problems.
360
+ *
361
+ * @see Crypt_Base::enableContinuousBuffer()
362
+ * @see Crypt_TripleDES::disableContinuousBuffer()
363
+ * @access public
364
+ */
365
+ function enableContinuousBuffer()
366
+ {
367
+ parent::enableContinuousBuffer();
368
+ if ($this->mode_3cbc) {
369
+ $this->des[0]->enableContinuousBuffer();
370
+ $this->des[1]->enableContinuousBuffer();
371
+ $this->des[2]->enableContinuousBuffer();
372
+ }
373
+ }
374
+
375
+ /**
376
+ * Treat consecutive packets as if they are a discontinuous buffer.
377
+ *
378
+ * The default behavior.
379
+ *
380
+ * @see Crypt_Base::disableContinuousBuffer()
381
+ * @see Crypt_TripleDES::enableContinuousBuffer()
382
+ * @access public
383
+ */
384
+ function disableContinuousBuffer()
385
+ {
386
+ parent::disableContinuousBuffer();
387
+ if ($this->mode_3cbc) {
388
+ $this->des[0]->disableContinuousBuffer();
389
+ $this->des[1]->disableContinuousBuffer();
390
+ $this->des[2]->disableContinuousBuffer();
391
+ }
392
+ }
393
+
394
+ /**
395
+ * Creates the key schedule
396
+ *
397
+ * @see Crypt_DES::_setupKey()
398
+ * @see Crypt_Base::_setupKey()
399
+ * @access private
400
+ */
401
+ function _setupKey()
402
+ {
403
+ switch (true) {
404
+ // if $key <= 64bits we configure our internal pure-php cipher engine
405
+ // to act as regular [1]DES, not as 3DES. mcrypt.so::tripledes does the same.
406
+ case strlen($this->key) <= 8:
407
+ $this->des_rounds = 1;
408
+ break;
409
+
410
+ // otherwise, if $key > 64bits, we configure our engine to work as 3DES.
411
+ default:
412
+ $this->des_rounds = 3;
413
+
414
+ // (only) if 3CBC is used we have, of course, to setup the $des[0-2] keys also separately.
415
+ if ($this->mode_3cbc) {
416
+ $this->des[0]->_setupKey();
417
+ $this->des[1]->_setupKey();
418
+ $this->des[2]->_setupKey();
419
+
420
+ // because $des[0-2] will, now, do all the work we can return here
421
+ // not need unnecessary stress parent::_setupKey() with our, now unused, $key.
422
+ return;
423
+ }
424
+ }
425
+ // setup our key
426
+ parent::_setupKey();
427
+ }
428
+ }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
phpseclib/Crypt/Twofish.php ADDED
@@ -0,0 +1,895 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * Pure-PHP implementation of Twofish.
5
+ *
6
+ * Uses mcrypt, if available, and an internal implementation, otherwise.
7
+ *
8
+ * PHP versions 4 and 5
9
+ *
10
+ * Useful resources are as follows:
11
+ *
12
+ * - {@link http://en.wikipedia.org/wiki/Twofish Wikipedia description of Twofish}
13
+ *
14
+ * Here's a short example of how to use this library:
15
+ * <code>
16
+ * <?php
17
+ * include 'Crypt/Twofish.php';
18
+ *
19
+ * $twofish = new Crypt_Twofish();
20
+ *
21
+ * $twofish->setKey('12345678901234567890123456789012');
22
+ *
23
+ * $plaintext = str_repeat('a', 1024);
24
+ *
25
+ * echo $twofish->decrypt($twofish->encrypt($plaintext));
26
+ * ?>
27
+ * </code>
28
+ *
29
+ * LICENSE: Permission is hereby granted, free of charge, to any person obtaining a copy
30
+ * of this software and associated documentation files (the "Software"), to deal
31
+ * in the Software without restriction, including without limitation the rights
32
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
33
+ * copies of the Software, and to permit persons to whom the Software is
34
+ * furnished to do so, subject to the following conditions:
35
+ *
36
+ * The above copyright notice and this permission notice shall be included in
37
+ * all copies or substantial portions of the Software.
38
+ *
39
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
40
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
41
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
42
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
43
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
44
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
45
+ * THE SOFTWARE.
46
+ *
47
+ * @category Crypt
48
+ * @package Crypt_Twofish
49
+ * @author Jim Wigginton <terrafrost@php.net>
50
+ * @author Hans-Juergen Petrich <petrich@tronic-media.com>
51
+ * @copyright MMVII Jim Wigginton
52
+ * @license http://www.opensource.org/licenses/mit-license.html MIT License
53
+ * @link http://phpseclib.sourceforge.net
54
+ */
55
+
56
+ /**
57
+ * Include Crypt_Base
58
+ *
59
+ * Base cipher class
60
+ */
61
+ if (!class_exists('Crypt_Base')) {
62
+ include_once 'Base.php';
63
+ }
64
+
65
+ /**#@+
66
+ * @access public
67
+ * @see Crypt_Twofish::encrypt()
68
+ * @see Crypt_Twofish::decrypt()
69
+ */
70
+ /**
71
+ * Encrypt / decrypt using the Counter mode.
72
+ *
73
+ * Set to -1 since that's what Crypt/Random.php uses to index the CTR mode.
74
+ *
75
+ * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Counter_.28CTR.29
76
+ */
77
+ define('CRYPT_TWOFISH_MODE_CTR', CRYPT_MODE_CTR);
78
+ /**
79
+ * Encrypt / decrypt using the Electronic Code Book mode.
80
+ *
81
+ * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Electronic_codebook_.28ECB.29
82
+ */
83
+ define('CRYPT_TWOFISH_MODE_ECB', CRYPT_MODE_ECB);
84
+ /**
85
+ * Encrypt / decrypt using the Code Book Chaining mode.
86
+ *
87
+ * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Cipher-block_chaining_.28CBC.29
88
+ */
89
+ define('CRYPT_TWOFISH_MODE_CBC', CRYPT_MODE_CBC);
90
+ /**
91
+ * Encrypt / decrypt using the Cipher Feedback mode.
92
+ *
93
+ * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Cipher_feedback_.28CFB.29
94
+ */
95
+ define('CRYPT_TWOFISH_MODE_CFB', CRYPT_MODE_CFB);
96
+ /**
97
+ * Encrypt / decrypt using the Cipher Feedback mode.
98
+ *
99
+ * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Output_feedback_.28OFB.29
100
+ */
101
+ define('CRYPT_TWOFISH_MODE_OFB', CRYPT_MODE_OFB);
102
+ /**#@-*/
103
+
104
+ /**#@+
105
+ * @access private
106
+ * @see Crypt_Base::Crypt_Base()
107
+ */
108
+ /**
109
+ * Toggles the internal implementation
110
+ */
111
+ define('CRYPT_TWOFISH_MODE_INTERNAL', CRYPT_MODE_INTERNAL);
112
+ /**
113
+ * Toggles the mcrypt implementation
114
+ */
115
+ define('CRYPT_TWOFISH_MODE_MCRYPT', CRYPT_MODE_MCRYPT);
116
+ /**#@-*/
117
+
118
+ /**
119
+ * Pure-PHP implementation of Twofish.
120
+ *
121
+ * @package Crypt_Twofish
122
+ * @author Jim Wigginton <terrafrost@php.net>
123
+ * @author Hans-Juergen Petrich <petrich@tronic-media.com>
124
+ * @access public
125
+ */
126
+ class Crypt_Twofish extends Crypt_Base
127
+ {
128
+ /**
129
+ * The namespace used by the cipher for its constants.
130
+ *
131
+ * @see Crypt_Base::const_namespace
132
+ * @var String
133
+ * @access private
134
+ */
135
+ var $const_namespace = 'TWOFISH';
136
+
137
+ /**
138
+ * The mcrypt specific name of the cipher
139
+ *
140
+ * @see Crypt_Base::cipher_name_mcrypt
141
+ * @var String
142
+ * @access private
143
+ */
144
+ var $cipher_name_mcrypt = 'twofish';
145
+
146
+ /**
147
+ * Optimizing value while CFB-encrypting
148
+ *
149
+ * @see Crypt_Base::cfb_init_len
150
+ * @var Integer
151
+ * @access private
152
+ */
153
+ var $cfb_init_len = 800;
154
+
155
+ /**
156
+ * Q-Table
157
+ *
158
+ * @var Array
159
+ * @access private
160
+ */
161
+ var $q0 = array (
162
+ 0xA9, 0x67, 0xB3, 0xE8, 0x04, 0xFD, 0xA3, 0x76,
163
+ 0x9A, 0x92, 0x80, 0x78, 0xE4, 0xDD, 0xD1, 0x38,
164
+ 0x0D, 0xC6, 0x35, 0x98, 0x18, 0xF7, 0xEC, 0x6C,
165
+ 0x43, 0x75, 0x37, 0x26, 0xFA, 0x13, 0x94, 0x48,
166
+ 0xF2, 0xD0, 0x8B, 0x30, 0x84, 0x54, 0xDF, 0x23,
167
+ 0x19, 0x5B, 0x3D, 0x59, 0xF3, 0xAE, 0xA2, 0x82,
168
+ 0x63, 0x01, 0x83, 0x2E, 0xD9, 0x51, 0x9B, 0x7C,
169
+ 0xA6, 0xEB, 0xA5, 0xBE, 0x16, 0x0C, 0xE3, 0x61,
170
+ 0xC0, 0x8C, 0x3A, 0xF5, 0x73, 0x2C, 0x25, 0x0B,
171
+ 0xBB, 0x4E, 0x89, 0x6B, 0x53, 0x6A, 0xB4, 0xF1,
172
+ 0xE1, 0xE6, 0xBD, 0x45, 0xE2, 0xF4, 0xB6, 0x66,
173
+ 0xCC, 0x95, 0x03, 0x56, 0xD4, 0x1C, 0x1E, 0xD7,
174
+ 0xFB, 0xC3, 0x8E, 0xB5, 0xE9, 0xCF, 0xBF, 0xBA,
175
+ 0xEA, 0x77, 0x39, 0xAF, 0x33, 0xC9, 0x62, 0x71,
176
+ 0x81, 0x79, 0x09, 0xAD, 0x24, 0xCD, 0xF9, 0xD8,
177
+ 0xE5, 0xC5, 0xB9, 0x4D, 0x44, 0x08, 0x86, 0xE7,
178
+ 0xA1, 0x1D, 0xAA, 0xED, 0x06, 0x70, 0xB2, 0xD2,
179
+ 0x41, 0x7B, 0xA0, 0x11, 0x31, 0xC2, 0x27, 0x90,
180
+ 0x20, 0xF6, 0x60, 0xFF, 0x96, 0x5C, 0xB1, 0xAB,
181
+ 0x9E, 0x9C, 0x52, 0x1B, 0x5F, 0x93, 0x0A, 0xEF,
182
+ 0x91, 0x85, 0x49, 0xEE, 0x2D, 0x4F, 0x8F, 0x3B,
183
+ 0x47, 0x87, 0x6D, 0x46, 0xD6, 0x3E, 0x69, 0x64,
184
+ 0x2A, 0xCE, 0xCB, 0x2F, 0xFC, 0x97, 0x05, 0x7A,
185
+ 0xAC, 0x7F, 0xD5, 0x1A, 0x4B, 0x0E, 0xA7, 0x5A,
186
+ 0x28, 0x14, 0x3F, 0x29, 0x88, 0x3C, 0x4C, 0x02,
187
+ 0xB8, 0xDA, 0xB0, 0x17, 0x55, 0x1F, 0x8A, 0x7D,
188
+ 0x57, 0xC7, 0x8D, 0x74, 0xB7, 0xC4, 0x9F, 0x72,
189
+ 0x7E, 0x15, 0x22, 0x12, 0x58, 0x07, 0x99, 0x34,
190
+ 0x6E, 0x50, 0xDE, 0x68, 0x65, 0xBC, 0xDB, 0xF8,
191
+ 0xC8, 0xA8, 0x2B, 0x40, 0xDC, 0xFE, 0x32, 0xA4,
192
+ 0xCA, 0x10, 0x21, 0xF0, 0xD3, 0x5D, 0x0F, 0x00,
193
+ 0x6F, 0x9D, 0x36, 0x42, 0x4A, 0x5E, 0xC1, 0xE0
194
+ );
195
+
196
+ /**
197
+ * Q-Table
198
+ *
199
+ * @var Array
200
+ * @access private
201
+ */
202
+ var $q1 = array (
203
+ 0x75, 0xF3, 0xC6, 0xF4, 0xDB, 0x7B, 0xFB, 0xC8,
204
+ 0x4A, 0xD3, 0xE6, 0x6B, 0x45, 0x7D, 0xE8, 0x4B,
205
+ 0xD6, 0x32, 0xD8, 0xFD, 0x37, 0x71, 0xF1, 0xE1,
206
+ 0x30, 0x0F, 0xF8, 0x1B, 0x87, 0xFA, 0x06, 0x3F,
207
+ 0x5E, 0xBA, 0xAE, 0x5B, 0x8A, 0x00, 0xBC, 0x9D,
208
+ 0x6D, 0xC1, 0xB1, 0x0E, 0x80, 0x5D, 0xD2, 0xD5,
209
+ 0xA0, 0x84, 0x07, 0x14, 0xB5, 0x90, 0x2C, 0xA3,
210
+ 0xB2, 0x73, 0x4C, 0x54, 0x92, 0x74, 0x36, 0x51,
211
+ 0x38, 0xB0, 0xBD, 0x5A, 0xFC, 0x60, 0x62, 0x96,
212
+ 0x6C, 0x42, 0xF7, 0x10, 0x7C, 0x28, 0x27, 0x8C,
213
+ 0x13, 0x95, 0x9C, 0xC7, 0x24, 0x46, 0x3B, 0x70,
214
+ 0xCA, 0xE3, 0x85, 0xCB, 0x11, 0xD0, 0x93, 0xB8,
215
+ 0xA6, 0x83, 0x20, 0xFF, 0x9F, 0x77, 0xC3, 0xCC,
216
+ 0x03, 0x6F, 0x08, 0xBF, 0x40, 0xE7, 0x2B, 0xE2,
217
+ 0x79, 0x0C, 0xAA, 0x82, 0x41, 0x3A, 0xEA, 0xB9,
218
+ 0xE4, 0x9A, 0xA4, 0x97, 0x7E, 0xDA, 0x7A, 0x17,
219
+ 0x66, 0x94, 0xA1, 0x1D, 0x3D, 0xF0, 0xDE, 0xB3,
220
+ 0x0B, 0x72, 0xA7, 0x1C, 0xEF, 0xD1, 0x53, 0x3E,
221
+ 0x8F, 0x33, 0x26, 0x5F, 0xEC, 0x76, 0x2A, 0x49,
222
+ 0x81, 0x88, 0xEE, 0x21, 0xC4, 0x1A, 0xEB, 0xD9,
223
+ 0xC5, 0x39, 0x99, 0xCD, 0xAD, 0x31, 0x8B, 0x01,
224
+ 0x18, 0x23, 0xDD, 0x1F, 0x4E, 0x2D, 0xF9, 0x48,
225
+ 0x4F, 0xF2, 0x65, 0x8E, 0x78, 0x5C, 0x58, 0x19,
226
+ 0x8D, 0xE5, 0x98, 0x57, 0x67, 0x7F, 0x05, 0x64,
227
+ 0xAF, 0x63, 0xB6, 0xFE, 0xF5, 0xB7, 0x3C, 0xA5,
228
+ 0xCE, 0xE9, 0x68, 0x44, 0xE0, 0x4D, 0x43, 0x69,
229
+ 0x29, 0x2E, 0xAC, 0x15, 0x59, 0xA8, 0x0A, 0x9E,
230
+ 0x6E, 0x47, 0xDF, 0x34, 0x35, 0x6A, 0xCF, 0xDC,
231
+ 0x22, 0xC9, 0xC0, 0x9B, 0x89, 0xD4, 0xED, 0xAB,
232
+ 0x12, 0xA2, 0x0D, 0x52, 0xBB, 0x02, 0x2F, 0xA9,
233
+ 0xD7, 0x61, 0x1E, 0xB4, 0x50, 0x04, 0xF6, 0xC2,
234
+ 0x16, 0x25, 0x86, 0x56, 0x55, 0x09, 0xBE, 0x91
235
+ );
236
+
237
+ /**
238
+ * M-Table
239
+ *
240
+ * @var Array
241
+ * @access private
242
+ */
243
+ var $m0 = array (
244
+ 0xBCBC3275, 0xECEC21F3, 0x202043C6, 0xB3B3C9F4, 0xDADA03DB, 0x02028B7B, 0xE2E22BFB, 0x9E9EFAC8,
245
+ 0xC9C9EC4A, 0xD4D409D3, 0x18186BE6, 0x1E1E9F6B, 0x98980E45, 0xB2B2387D, 0xA6A6D2E8, 0x2626B74B,
246
+ 0x3C3C57D6, 0x93938A32, 0x8282EED8, 0x525298FD, 0x7B7BD437, 0xBBBB3771, 0x5B5B97F1, 0x474783E1,
247
+ 0x24243C30, 0x5151E20F, 0xBABAC6F8, 0x4A4AF31B, 0xBFBF4887, 0x0D0D70FA, 0xB0B0B306, 0x7575DE3F,
248
+ 0xD2D2FD5E, 0x7D7D20BA, 0x666631AE, 0x3A3AA35B, 0x59591C8A, 0x00000000, 0xCDCD93BC, 0x1A1AE09D,
249
+ 0xAEAE2C6D, 0x7F7FABC1, 0x2B2BC7B1, 0xBEBEB90E, 0xE0E0A080, 0x8A8A105D, 0x3B3B52D2, 0x6464BAD5,
250
+ 0xD8D888A0, 0xE7E7A584, 0x5F5FE807, 0x1B1B1114, 0x2C2CC2B5, 0xFCFCB490, 0x3131272C, 0x808065A3,
251
+ 0x73732AB2, 0x0C0C8173, 0x79795F4C, 0x6B6B4154, 0x4B4B0292, 0x53536974, 0x94948F36, 0x83831F51,
252
+ 0x2A2A3638, 0xC4C49CB0, 0x2222C8BD, 0xD5D5F85A, 0xBDBDC3FC, 0x48487860, 0xFFFFCE62, 0x4C4C0796,
253
+ 0x4141776C, 0xC7C7E642, 0xEBEB24F7, 0x1C1C1410, 0x5D5D637C, 0x36362228, 0x6767C027, 0xE9E9AF8C,
254
+ 0x4444F913, 0x1414EA95, 0xF5F5BB9C, 0xCFCF18C7, 0x3F3F2D24, 0xC0C0E346, 0x7272DB3B, 0x54546C70,
255
+ 0x29294CCA, 0xF0F035E3, 0x0808FE85, 0xC6C617CB, 0xF3F34F11, 0x8C8CE4D0, 0xA4A45993, 0xCACA96B8,
256
+ 0x68683BA6, 0xB8B84D83, 0x38382820, 0xE5E52EFF, 0xADAD569F, 0x0B0B8477, 0xC8C81DC3, 0x9999FFCC,
257
+ 0x5858ED03, 0x19199A6F, 0x0E0E0A08, 0x95957EBF, 0x70705040, 0xF7F730E7, 0x6E6ECF2B, 0x1F1F6EE2,
258
+ 0xB5B53D79, 0x09090F0C, 0x616134AA, 0x57571682, 0x9F9F0B41, 0x9D9D803A, 0x111164EA, 0x2525CDB9,
259
+ 0xAFAFDDE4, 0x4545089A, 0xDFDF8DA4, 0xA3A35C97, 0xEAEAD57E, 0x353558DA, 0xEDEDD07A, 0x4343FC17,
260
+ 0xF8F8CB66, 0xFBFBB194, 0x3737D3A1, 0xFAFA401D, 0xC2C2683D, 0xB4B4CCF0, 0x32325DDE, 0x9C9C71B3,
261
+ 0x5656E70B, 0xE3E3DA72, 0x878760A7, 0x15151B1C, 0xF9F93AEF, 0x6363BFD1, 0x3434A953, 0x9A9A853E,
262
+ 0xB1B1428F, 0x7C7CD133, 0x88889B26, 0x3D3DA65F, 0xA1A1D7EC, 0xE4E4DF76, 0x8181942A, 0x91910149,
263
+ 0x0F0FFB81, 0xEEEEAA88, 0x161661EE, 0xD7D77321, 0x9797F5C4, 0xA5A5A81A, 0xFEFE3FEB, 0x6D6DB5D9,
264
+ 0x7878AEC5, 0xC5C56D39, 0x1D1DE599, 0x7676A4CD, 0x3E3EDCAD, 0xCBCB6731, 0xB6B6478B, 0xEFEF5B01,
265
+ 0x12121E18, 0x6060C523, 0x6A6AB0DD, 0x4D4DF61F, 0xCECEE94E, 0xDEDE7C2D, 0x55559DF9, 0x7E7E5A48,
266
+ 0x2121B24F, 0x03037AF2, 0xA0A02665, 0x5E5E198E, 0x5A5A6678, 0x65654B5C, 0x62624E58, 0xFDFD4519,
267
+ 0x0606F48D, 0x404086E5, 0xF2F2BE98, 0x3333AC57, 0x17179067, 0x05058E7F, 0xE8E85E05, 0x4F4F7D64,
268
+ 0x89896AAF, 0x10109563, 0x74742FB6, 0x0A0A75FE, 0x5C5C92F5, 0x9B9B74B7, 0x2D2D333C, 0x3030D6A5,
269
+ 0x2E2E49CE, 0x494989E9, 0x46467268, 0x77775544, 0xA8A8D8E0, 0x9696044D, 0x2828BD43, 0xA9A92969,
270
+ 0xD9D97929, 0x8686912E, 0xD1D187AC, 0xF4F44A15, 0x8D8D1559, 0xD6D682A8, 0xB9B9BC0A, 0x42420D9E,
271
+ 0xF6F6C16E, 0x2F2FB847, 0xDDDD06DF, 0x23233934, 0xCCCC6235, 0xF1F1C46A, 0xC1C112CF, 0x8585EBDC,
272
+ 0x8F8F9E22, 0x7171A1C9, 0x9090F0C0, 0xAAAA539B, 0x0101F189, 0x8B8BE1D4, 0x4E4E8CED, 0x8E8E6FAB,
273
+ 0xABABA212, 0x6F6F3EA2, 0xE6E6540D, 0xDBDBF252, 0x92927BBB, 0xB7B7B602, 0x6969CA2F, 0x3939D9A9,
274
+ 0xD3D30CD7, 0xA7A72361, 0xA2A2AD1E, 0xC3C399B4, 0x6C6C4450, 0x07070504, 0x04047FF6, 0x272746C2,
275
+ 0xACACA716, 0xD0D07625, 0x50501386, 0xDCDCF756, 0x84841A55, 0xE1E15109, 0x7A7A25BE, 0x1313EF91
276
+ );
277
+
278
+ /**
279
+ * M-Table
280
+ *
281
+ * @var Array
282
+ * @access private
283
+ */
284
+ var $m1 = array (
285
+ 0xA9D93939, 0x67901717, 0xB3719C9C, 0xE8D2A6A6, 0x04050707, 0xFD985252, 0xA3658080, 0x76DFE4E4,
286
+ 0x9A084545, 0x92024B4B, 0x80A0E0E0, 0x78665A5A, 0xE4DDAFAF, 0xDDB06A6A, 0xD1BF6363, 0x38362A2A,
287
+ 0x0D54E6E6, 0xC6432020, 0x3562CCCC, 0x98BEF2F2, 0x181E1212, 0xF724EBEB, 0xECD7A1A1, 0x6C774141,
288
+ 0x43BD2828, 0x7532BCBC, 0x37D47B7B, 0x269B8888, 0xFA700D0D, 0x13F94444, 0x94B1FBFB, 0x485A7E7E,
289
+ 0xF27A0303, 0xD0E48C8C, 0x8B47B6B6, 0x303C2424, 0x84A5E7E7, 0x54416B6B, 0xDF06DDDD, 0x23C56060,
290
+ 0x1945FDFD, 0x5BA33A3A, 0x3D68C2C2, 0x59158D8D, 0xF321ECEC, 0xAE316666, 0xA23E6F6F, 0x82165757,
291
+ 0x63951010, 0x015BEFEF, 0x834DB8B8, 0x2E918686, 0xD9B56D6D, 0x511F8383, 0x9B53AAAA, 0x7C635D5D,
292
+ 0xA63B6868, 0xEB3FFEFE, 0xA5D63030, 0xBE257A7A, 0x16A7ACAC, 0x0C0F0909, 0xE335F0F0, 0x6123A7A7,
293
+ 0xC0F09090, 0x8CAFE9E9, 0x3A809D9D, 0xF5925C5C, 0x73810C0C, 0x2C273131, 0x2576D0D0, 0x0BE75656,
294
+ 0xBB7B9292, 0x4EE9CECE, 0x89F10101, 0x6B9F1E1E, 0x53A93434, 0x6AC4F1F1, 0xB499C3C3, 0xF1975B5B,
295
+ 0xE1834747, 0xE66B1818, 0xBDC82222, 0x450E9898, 0xE26E1F1F, 0xF4C9B3B3, 0xB62F7474, 0x66CBF8F8,
296
+ 0xCCFF9999, 0x95EA1414, 0x03ED5858, 0x56F7DCDC, 0xD4E18B8B, 0x1C1B1515, 0x1EADA2A2, 0xD70CD3D3,
297
+ 0xFB2BE2E2, 0xC31DC8C8, 0x8E195E5E, 0xB5C22C2C, 0xE9894949, 0xCF12C1C1, 0xBF7E9595, 0xBA207D7D,
298
+ 0xEA641111, 0x77840B0B, 0x396DC5C5, 0xAF6A8989, 0x33D17C7C, 0xC9A17171, 0x62CEFFFF, 0x7137BBBB,
299
+ 0x81FB0F0F, 0x793DB5B5, 0x0951E1E1, 0xADDC3E3E, 0x242D3F3F, 0xCDA47676, 0xF99D5555, 0xD8EE8282,
300
+ 0xE5864040, 0xC5AE7878, 0xB9CD2525, 0x4D049696, 0x44557777, 0x080A0E0E, 0x86135050, 0xE730F7F7,
301
+ 0xA1D33737, 0x1D40FAFA, 0xAA346161, 0xED8C4E4E, 0x06B3B0B0, 0x706C5454, 0xB22A7373, 0xD2523B3B,
302
+ 0x410B9F9F, 0x7B8B0202, 0xA088D8D8, 0x114FF3F3, 0x3167CBCB, 0xC2462727, 0x27C06767, 0x90B4FCFC,
303
+ 0x20283838, 0xF67F0404, 0x60784848, 0xFF2EE5E5, 0x96074C4C, 0x5C4B6565, 0xB1C72B2B, 0xAB6F8E8E,
304
+ 0x9E0D4242, 0x9CBBF5F5, 0x52F2DBDB, 0x1BF34A4A, 0x5FA63D3D, 0x9359A4A4, 0x0ABCB9B9, 0xEF3AF9F9,
305
+ 0x91EF1313, 0x85FE0808, 0x49019191, 0xEE611616, 0x2D7CDEDE, 0x4FB22121, 0x8F42B1B1, 0x3BDB7272,
306
+ 0x47B82F2F, 0x8748BFBF, 0x6D2CAEAE, 0x46E3C0C0, 0xD6573C3C, 0x3E859A9A, 0x6929A9A9, 0x647D4F4F,
307
+ 0x2A948181, 0xCE492E2E, 0xCB17C6C6, 0x2FCA6969, 0xFCC3BDBD, 0x975CA3A3, 0x055EE8E8, 0x7AD0EDED,
308
+ 0xAC87D1D1, 0x7F8E0505, 0xD5BA6464, 0x1AA8A5A5, 0x4BB72626, 0x0EB9BEBE, 0xA7608787, 0x5AF8D5D5,
309
+ 0x28223636, 0x14111B1B, 0x3FDE7575, 0x2979D9D9, 0x88AAEEEE, 0x3C332D2D, 0x4C5F7979, 0x02B6B7B7,
310
+ 0xB896CACA, 0xDA583535, 0xB09CC4C4, 0x17FC4343, 0x551A8484, 0x1FF64D4D, 0x8A1C5959, 0x7D38B2B2,
311
+ 0x57AC3333, 0xC718CFCF, 0x8DF40606, 0x74695353, 0xB7749B9B, 0xC4F59797, 0x9F56ADAD, 0x72DAE3E3,
312
+ 0x7ED5EAEA, 0x154AF4F4, 0x229E8F8F, 0x12A2ABAB, 0x584E6262, 0x07E85F5F, 0x99E51D1D, 0x34392323,
313
+ 0x6EC1F6F6, 0x50446C6C, 0xDE5D3232, 0x68724646, 0x6526A0A0, 0xBC93CDCD, 0xDB03DADA, 0xF8C6BABA,
314
+ 0xC8FA9E9E, 0xA882D6D6, 0x2BCF6E6E, 0x40507070, 0xDCEB8585, 0xFE750A0A, 0x328A9393, 0xA48DDFDF,
315
+ 0xCA4C2929, 0x10141C1C, 0x2173D7D7, 0xF0CCB4B4, 0xD309D4D4, 0x5D108A8A, 0x0FE25151, 0x00000000,
316
+ 0x6F9A1919, 0x9DE01A1A, 0x368F9494, 0x42E6C7C7, 0x4AECC9C9, 0x5EFDD2D2, 0xC1AB7F7F, 0xE0D8A8A8
317
+ );
318
+
319
+ /**
320
+ * M-Table
321
+ *
322
+ * @var Array
323
+ * @access private
324
+ */
325
+ var $m2 = array (
326
+ 0xBC75BC32, 0xECF3EC21, 0x20C62043, 0xB3F4B3C9, 0xDADBDA03, 0x027B028B, 0xE2FBE22B, 0x9EC89EFA,
327
+ 0xC94AC9EC, 0xD4D3D409, 0x18E6186B, 0x1E6B1E9F, 0x9845980E, 0xB27DB238, 0xA6E8A6D2, 0x264B26B7,
328
+ 0x3CD63C57, 0x9332938A, 0x82D882EE, 0x52FD5298, 0x7B377BD4, 0xBB71BB37, 0x5BF15B97, 0x47E14783,
329
+ 0x2430243C, 0x510F51E2, 0xBAF8BAC6, 0x4A1B4AF3, 0xBF87BF48, 0x0DFA0D70, 0xB006B0B3, 0x753F75DE,
330
+ 0xD25ED2FD, 0x7DBA7D20, 0x66AE6631, 0x3A5B3AA3, 0x598A591C, 0x00000000, 0xCDBCCD93, 0x1A9D1AE0,
331
+ 0xAE6DAE2C, 0x7FC17FAB, 0x2BB12BC7, 0xBE0EBEB9, 0xE080E0A0, 0x8A5D8A10, 0x3BD23B52, 0x64D564BA,
332
+ 0xD8A0D888, 0xE784E7A5, 0x5F075FE8, 0x1B141B11, 0x2CB52CC2, 0xFC90FCB4, 0x312C3127, 0x80A38065,
333
+ 0x73B2732A, 0x0C730C81, 0x794C795F, 0x6B546B41, 0x4B924B02, 0x53745369, 0x9436948F, 0x8351831F,
334
+ 0x2A382A36, 0xC4B0C49C, 0x22BD22C8, 0xD55AD5F8, 0xBDFCBDC3, 0x48604878, 0xFF62FFCE, 0x4C964C07,
335
+ 0x416C4177, 0xC742C7E6, 0xEBF7EB24, 0x1C101C14, 0x5D7C5D63, 0x36283622, 0x672767C0, 0xE98CE9AF,
336
+ 0x441344F9, 0x149514EA, 0xF59CF5BB, 0xCFC7CF18, 0x3F243F2D, 0xC046C0E3, 0x723B72DB, 0x5470546C,
337
+ 0x29CA294C, 0xF0E3F035, 0x088508FE, 0xC6CBC617, 0xF311F34F, 0x8CD08CE4, 0xA493A459, 0xCAB8CA96,
338
+ 0x68A6683B, 0xB883B84D, 0x38203828, 0xE5FFE52E, 0xAD9FAD56, 0x0B770B84, 0xC8C3C81D, 0x99CC99FF,
339
+ 0x580358ED, 0x196F199A, 0x0E080E0A, 0x95BF957E, 0x70407050, 0xF7E7F730, 0x6E2B6ECF, 0x1FE21F6E,
340
+ 0xB579B53D, 0x090C090F, 0x61AA6134, 0x57825716, 0x9F419F0B, 0x9D3A9D80, 0x11EA1164, 0x25B925CD,
341
+ 0xAFE4AFDD, 0x459A4508, 0xDFA4DF8D, 0xA397A35C, 0xEA7EEAD5, 0x35DA3558, 0xED7AEDD0, 0x431743FC,
342
+ 0xF866F8CB, 0xFB94FBB1, 0x37A137D3, 0xFA1DFA40, 0xC23DC268, 0xB4F0B4CC, 0x32DE325D, 0x9CB39C71,
343
+ 0x560B56E7, 0xE372E3DA, 0x87A78760, 0x151C151B, 0xF9EFF93A, 0x63D163BF, 0x345334A9, 0x9A3E9A85,
344
+ 0xB18FB142, 0x7C337CD1, 0x8826889B, 0x3D5F3DA6, 0xA1ECA1D7, 0xE476E4DF, 0x812A8194, 0x91499101,
345
+ 0x0F810FFB, 0xEE88EEAA, 0x16EE1661, 0xD721D773, 0x97C497F5, 0xA51AA5A8, 0xFEEBFE3F, 0x6DD96DB5,
346
+ 0x78C578AE, 0xC539C56D, 0x1D991DE5, 0x76CD76A4, 0x3EAD3EDC, 0xCB31CB67, 0xB68BB647, 0xEF01EF5B,
347
+ 0x1218121E, 0x602360C5, 0x6ADD6AB0, 0x4D1F4DF6, 0xCE4ECEE9, 0xDE2DDE7C, 0x55F9559D, 0x7E487E5A,
348
+ 0x214F21B2, 0x03F2037A, 0xA065A026, 0x5E8E5E19, 0x5A785A66, 0x655C654B, 0x6258624E, 0xFD19FD45,
349
+ 0x068D06F4, 0x40E54086, 0xF298F2BE, 0x335733AC, 0x17671790, 0x057F058E, 0xE805E85E, 0x4F644F7D,
350
+ 0x89AF896A, 0x10631095, 0x74B6742F, 0x0AFE0A75, 0x5CF55C92, 0x9BB79B74, 0x2D3C2D33, 0x30A530D6,
351
+ 0x2ECE2E49, 0x49E94989, 0x46684672, 0x77447755, 0xA8E0A8D8, 0x964D9604, 0x284328BD, 0xA969A929,
352
+ 0xD929D979, 0x862E8691, 0xD1ACD187, 0xF415F44A, 0x8D598D15, 0xD6A8D682, 0xB90AB9BC, 0x429E420D,
353
+ 0xF66EF6C1, 0x2F472FB8, 0xDDDFDD06, 0x23342339, 0xCC35CC62, 0xF16AF1C4, 0xC1CFC112, 0x85DC85EB,
354
+ 0x8F228F9E, 0x71C971A1, 0x90C090F0, 0xAA9BAA53, 0x018901F1, 0x8BD48BE1, 0x4EED4E8C, 0x8EAB8E6F,
355
+ 0xAB12ABA2, 0x6FA26F3E, 0xE60DE654, 0xDB52DBF2, 0x92BB927B, 0xB702B7B6, 0x692F69CA, 0x39A939D9,
356
+ 0xD3D7D30C, 0xA761A723, 0xA21EA2AD, 0xC3B4C399, 0x6C506C44, 0x07040705, 0x04F6047F, 0x27C22746,
357
+ 0xAC16ACA7, 0xD025D076, 0x50865013, 0xDC56DCF7, 0x8455841A, 0xE109E151, 0x7ABE7A25, 0x139113EF
358
+ );
359
+
360
+ /**
361
+ * M-Table
362
+ *
363
+ * @var Array
364
+ * @access private
365
+ */
366
+ var $m3 = array (
367
+ 0xD939A9D9, 0x90176790, 0x719CB371, 0xD2A6E8D2, 0x05070405, 0x9852FD98, 0x6580A365, 0xDFE476DF,
368
+ 0x08459A08, 0x024B9202, 0xA0E080A0, 0x665A7866, 0xDDAFE4DD, 0xB06ADDB0, 0xBF63D1BF, 0x362A3836,
369
+ 0x54E60D54, 0x4320C643, 0x62CC3562, 0xBEF298BE, 0x1E12181E, 0x24EBF724, 0xD7A1ECD7, 0x77416C77,
370
+ 0xBD2843BD, 0x32BC7532, 0xD47B37D4, 0x9B88269B, 0x700DFA70, 0xF94413F9, 0xB1FB94B1, 0x5A7E485A,
371
+ 0x7A03F27A, 0xE48CD0E4, 0x47B68B47, 0x3C24303C, 0xA5E784A5, 0x416B5441, 0x06DDDF06, 0xC56023C5,
372
+ 0x45FD1945, 0xA33A5BA3, 0x68C23D68, 0x158D5915, 0x21ECF321, 0x3166AE31, 0x3E6FA23E, 0x16578216,
373
+ 0x95106395, 0x5BEF015B, 0x4DB8834D, 0x91862E91, 0xB56DD9B5, 0x1F83511F, 0x53AA9B53, 0x635D7C63,
374
+ 0x3B68A63B, 0x3FFEEB3F, 0xD630A5D6, 0x257ABE25, 0xA7AC16A7, 0x0F090C0F, 0x35F0E335, 0x23A76123,
375
+ 0xF090C0F0, 0xAFE98CAF, 0x809D3A80, 0x925CF592, 0x810C7381, 0x27312C27, 0x76D02576, 0xE7560BE7,
376
+ 0x7B92BB7B, 0xE9CE4EE9, 0xF10189F1, 0x9F1E6B9F, 0xA93453A9, 0xC4F16AC4, 0x99C3B499, 0x975BF197,
377
+ 0x8347E183, 0x6B18E66B, 0xC822BDC8, 0x0E98450E, 0x6E1FE26E, 0xC9B3F4C9, 0x2F74B62F, 0xCBF866CB,
378
+ 0xFF99CCFF, 0xEA1495EA, 0xED5803ED, 0xF7DC56F7, 0xE18BD4E1, 0x1B151C1B, 0xADA21EAD, 0x0CD3D70C,
379
+ 0x2BE2FB2B, 0x1DC8C31D, 0x195E8E19, 0xC22CB5C2, 0x8949E989, 0x12C1CF12, 0x7E95BF7E, 0x207DBA20,
380
+ 0x6411EA64, 0x840B7784, 0x6DC5396D, 0x6A89AF6A, 0xD17C33D1, 0xA171C9A1, 0xCEFF62CE, 0x37BB7137,
381
+ 0xFB0F81FB, 0x3DB5793D, 0x51E10951, 0xDC3EADDC, 0x2D3F242D, 0xA476CDA4, 0x9D55F99D, 0xEE82D8EE,
382
+ 0x8640E586, 0xAE78C5AE, 0xCD25B9CD, 0x04964D04, 0x55774455, 0x0A0E080A, 0x13508613, 0x30F7E730,
383
+ 0xD337A1D3, 0x40FA1D40, 0x3461AA34, 0x8C4EED8C, 0xB3B006B3, 0x6C54706C, 0x2A73B22A, 0x523BD252,
384
+ 0x0B9F410B, 0x8B027B8B, 0x88D8A088, 0x4FF3114F, 0x67CB3167, 0x4627C246, 0xC06727C0, 0xB4FC90B4,
385
+ 0x28382028, 0x7F04F67F, 0x78486078, 0x2EE5FF2E, 0x074C9607, 0x4B655C4B, 0xC72BB1C7, 0x6F8EAB6F,
386
+ 0x0D429E0D, 0xBBF59CBB, 0xF2DB52F2, 0xF34A1BF3, 0xA63D5FA6, 0x59A49359, 0xBCB90ABC, 0x3AF9EF3A,
387
+ 0xEF1391EF, 0xFE0885FE, 0x01914901, 0x6116EE61, 0x7CDE2D7C, 0xB2214FB2, 0x42B18F42, 0xDB723BDB,
388
+ 0xB82F47B8, 0x48BF8748, 0x2CAE6D2C, 0xE3C046E3, 0x573CD657, 0x859A3E85, 0x29A96929, 0x7D4F647D,
389
+ 0x94812A94, 0x492ECE49, 0x17C6CB17, 0xCA692FCA, 0xC3BDFCC3, 0x5CA3975C, 0x5EE8055E, 0xD0ED7AD0,
390
+ 0x87D1AC87, 0x8E057F8E, 0xBA64D5BA, 0xA8A51AA8, 0xB7264BB7, 0xB9BE0EB9, 0x6087A760, 0xF8D55AF8,
391
+ 0x22362822, 0x111B1411, 0xDE753FDE, 0x79D92979, 0xAAEE88AA, 0x332D3C33, 0x5F794C5F, 0xB6B702B6,
392
+ 0x96CAB896, 0x5835DA58, 0x9CC4B09C, 0xFC4317FC, 0x1A84551A, 0xF64D1FF6, 0x1C598A1C, 0x38B27D38,
393
+ 0xAC3357AC, 0x18CFC718, 0xF4068DF4, 0x69537469, 0x749BB774, 0xF597C4F5, 0x56AD9F56, 0xDAE372DA,
394
+ 0xD5EA7ED5, 0x4AF4154A, 0x9E8F229E, 0xA2AB12A2, 0x4E62584E, 0xE85F07E8, 0xE51D99E5, 0x39233439,
395
+ 0xC1F66EC1, 0x446C5044, 0x5D32DE5D, 0x72466872, 0x26A06526, 0x93CDBC93, 0x03DADB03, 0xC6BAF8C6,
396
+ 0xFA9EC8FA, 0x82D6A882, 0xCF6E2BCF, 0x50704050, 0xEB85DCEB, 0x750AFE75, 0x8A93328A, 0x8DDFA48D,
397
+ 0x4C29CA4C, 0x141C1014, 0x73D72173, 0xCCB4F0CC, 0x09D4D309, 0x108A5D10, 0xE2510FE2, 0x00000000,
398
+ 0x9A196F9A, 0xE01A9DE0, 0x8F94368F, 0xE6C742E6, 0xECC94AEC, 0xFDD25EFD, 0xAB7FC1AB, 0xD8A8E0D8
399
+ );
400
+
401
+ /**
402
+ * The Key Schedule Array
403
+ *
404
+ * @var Array
405
+ * @access private
406
+ */
407
+ var $K = array();
408
+
409
+ /**
410
+ * The Key depended S-Table 0
411
+ *
412
+ * @var Array
413
+ * @access private
414
+ */
415
+ var $S0 = array();
416
+
417
+ /**
418
+ * The Key depended S-Table 1
419
+ *
420
+ * @var Array
421
+ * @access private
422
+ */
423
+ var $S1 = array();
424
+
425
+ /**
426
+ * The Key depended S-Table 2
427
+ *
428
+ * @var Array
429
+ * @access private
430
+ */
431
+ var $S2 = array();
432
+
433
+ /**
434
+ * The Key depended S-Table 3
435
+ *
436
+ * @var Array
437
+ * @access private
438
+ */
439
+ var $S3 = array();
440
+
441
+ /**
442
+ * Holds the last used key
443
+ *
444
+ * @var Array
445
+ * @access private
446
+ */
447
+ var $kl;
448
+
449
+ /**
450
+ * Sets the key.
451
+ *
452
+ * Keys can be of any length. Twofish, itself, requires the use of a key that's 128, 192 or 256-bits long.
453
+ * If the key is less than 256-bits we round the length up to the closest valid key length,
454
+ * padding $key with null bytes. If the key is more than 256-bits, we trim the excess bits.
455
+ *
456
+ * If the key is not explicitly set, it'll be assumed a 128 bits key to be all null bytes.
457
+ *
458
+ * @access public
459
+ * @see Crypt_Base::setKey()
460
+ * @param String $key
461
+ */
462
+ function setKey($key)
463
+ {
464
+ $keylength = strlen($key);
465
+ switch (true) {
466
+ case $keylength <= 16:
467
+ $key = str_pad($key, 16, "\0");
468
+ break;
469
+ case $keylength <= 24:
470
+ $key = str_pad($key, 24, "\0");
471
+ break;
472
+ case $keylength < 32:
473
+ $key = str_pad($key, 32, "\0");
474
+ break;
475
+ case $keylength > 32:
476
+ $key = substr($key, 0, 32);
477
+ }
478
+ parent::setKey($key);
479
+ }
480
+
481
+ /**
482
+ * Setup the key (expansion)
483
+ *
484
+ * @see Crypt_Base::_setupKey()
485
+ * @access private
486
+ */
487
+ function _setupKey()
488
+ {
489
+ if (isset($this->kl['key']) && $this->key === $this->kl['key']) {
490
+ // already expanded
491
+ return;
492
+ }
493
+ $this->kl = array('key' => $this->key);
494
+
495
+ /* Key expanding and generating the key-depended s-boxes */
496
+ $le_longs = unpack('V*', $this->key);
497
+ $key = unpack('C*', $this->key);
498
+ $m0 = $this->m0;
499
+ $m1 = $this->m1;
500
+ $m2 = $this->m2;
501
+ $m3 = $this->m3;
502
+ $q0 = $this->q0;
503
+ $q1 = $this->q1;
504
+
505
+ $K = $S0 = $S1 = $S2 = $S3 = array();
506
+
507
+ switch (strlen($this->key)) {
508
+ case 16:
509
+ list ($s7, $s6, $s5, $s4) = $this->_mdsrem($le_longs[1], $le_longs[2]);
510
+ list ($s3, $s2, $s1, $s0) = $this->_mdsrem($le_longs[3], $le_longs[4]);
511
+ for ($i = 0, $j = 1; $i < 40; $i+= 2,$j+= 2) {
512
+ $A = $m0[$q0[$q0[$i] ^ $key[ 9]] ^ $key[1]] ^
513
+ $m1[$q0[$q1[$i] ^ $key[10]] ^ $key[2]] ^
514
+ $m2[$q1[$q0[$i] ^ $key[11]] ^ $key[3]] ^
515
+ $m3[$q1[$q1[$i] ^ $key[12]] ^ $key[4]];
516
+ $B = $m0[$q0[$q0[$j] ^ $key[13]] ^ $key[5]] ^
517
+ $m1[$q0[$q1[$j] ^ $key[14]] ^ $key[6]] ^
518
+ $m2[$q1[$q0[$j] ^ $key[15]] ^ $key[7]] ^
519
+ $m3[$q1[$q1[$j] ^ $key[16]] ^ $key[8]];
520
+ $B = ($B << 8) | ($B >> 24 & 0xff);
521
+ $K[] = $A+= $B;
522
+ $K[] = (($A+= $B) << 9 | $A >> 23 & 0x1ff);
523
+ }
524
+ for ($i = 0; $i < 256; ++$i) {
525
+ $S0[$i] = $m0[$q0[$q0[$i] ^ $s4] ^ $s0];
526
+ $S1[$i] = $m1[$q0[$q1[$i] ^ $s5] ^ $s1];
527
+ $S2[$i] = $m2[$q1[$q0[$i] ^ $s6] ^ $s2];
528
+ $S3[$i] = $m3[$q1[$q1[$i] ^ $s7] ^ $s3];
529
+ }
530
+ break;
531
+ case 24:
532
+ list ($sb, $sa, $s9, $s8) = $this->_mdsrem($le_longs[1], $le_longs[2]);
533
+ list ($s7, $s6, $s5, $s4) = $this->_mdsrem($le_longs[3], $le_longs[4]);
534
+ list ($s3, $s2, $s1, $s0) = $this->_mdsrem($le_longs[5], $le_longs[6]);
535
+ for ($i = 0, $j = 1; $i < 40; $i+= 2, $j+= 2) {
536
+ $A = $m0[$q0[$q0[$q1[$i] ^ $key[17]] ^ $key[ 9]] ^ $key[1]] ^
537
+ $m1[$q0[$q1[$q1[$i] ^ $key[18]] ^ $key[10]] ^ $key[2]] ^
538
+ $m2[$q1[$q0[$q0[$i] ^ $key[19]] ^ $key[11]] ^ $key[3]] ^
539
+ $m3[$q1[$q1[$q0[$i] ^ $key[20]] ^ $key[12]] ^ $key[4]];
540
+ $B = $m0[$q0[$q0[$q1[$j] ^ $key[21]] ^ $key[13]] ^ $key[5]] ^
541
+ $m1[$q0[$q1[$q1[$j] ^ $key[22]] ^ $key[14]] ^ $key[6]] ^
542
+ $m2[$q1[$q0[$q0[$j] ^ $key[23]] ^ $key[15]] ^ $key[7]] ^
543
+ $m3[$q1[$q1[$q0[$j] ^ $key[24]] ^ $key[16]] ^ $key[8]];
544
+ $B = ($B << 8) | ($B >> 24 & 0xff);
545
+ $K[] = $A+= $B;
546
+ $K[] = (($A+= $B) << 9 | $A >> 23 & 0x1ff);
547
+ }
548
+ for ($i = 0; $i < 256; ++$i) {
549
+ $S0[$i] = $m0[$q0[$q0[$q1[$i] ^ $s8] ^ $s4] ^ $s0];
550
+ $S1[$i] = $m1[$q0[$q1[$q1[$i] ^ $s9] ^ $s5] ^ $s1];
551
+ $S2[$i] = $m2[$q1[$q0[$q0[$i] ^ $sa] ^ $s6] ^ $s2];
552
+ $S3[$i] = $m3[$q1[$q1[$q0[$i] ^ $sb] ^ $s7] ^ $s3];
553
+ }
554
+ break;
555
+ default: // 32
556
+ list ($sf, $se, $sd, $sc) = $this->_mdsrem($le_longs[1], $le_longs[2]);
557
+ list ($sb, $sa, $s9, $s8) = $this->_mdsrem($le_longs[3], $le_longs[4]);
558
+ list ($s7, $s6, $s5, $s4) = $this->_mdsrem($le_longs[5], $le_longs[6]);
559
+ list ($s3, $s2, $s1, $s0) = $this->_mdsrem($le_longs[7], $le_longs[8]);
560
+ for ($i = 0, $j = 1; $i < 40; $i+= 2, $j+= 2) {
561
+ $A = $m0[$q0[$q0[$q1[$q1[$i] ^ $key[25]] ^ $key[17]] ^ $key[ 9]] ^ $key[1]] ^
562
+ $m1[$q0[$q1[$q1[$q0[$i] ^ $key[26]] ^ $key[18]] ^ $key[10]] ^ $key[2]] ^
563
+ $m2[$q1[$q0[$q0[$q0[$i] ^ $key[27]] ^ $key[19]] ^ $key[11]] ^ $key[3]] ^
564
+ $m3[$q1[$q1[$q0[$q1[$i] ^ $key[28]] ^ $key[20]] ^ $key[12]] ^ $key[4]];
565
+ $B = $m0[$q0[$q0[$q1[$q1[$j] ^ $key[29]] ^ $key[21]] ^ $key[13]] ^ $key[5]] ^
566
+ $m1[$q0[$q1[$q1[$q0[$j] ^ $key[30]] ^ $key[22]] ^ $key[14]] ^ $key[6]] ^
567
+ $m2[$q1[$q0[$q0[$q0[$j] ^ $key[31]] ^ $key[23]] ^ $key[15]] ^ $key[7]] ^
568
+ $m3[$q1[$q1[$q0[$q1[$j] ^ $key[32]] ^ $key[24]] ^ $key[16]] ^ $key[8]];
569
+ $B = ($B << 8) | ($B >> 24 & 0xff);
570
+ $K[] = $A+= $B;
571
+ $K[] = (($A+= $B) << 9 | $A >> 23 & 0x1ff);
572
+ }
573
+ for ($i = 0; $i < 256; ++$i) {
574
+ $S0[$i] = $m0[$q0[$q0[$q1[$q1[$i] ^ $sc] ^ $s8] ^ $s4] ^ $s0];
575
+ $S1[$i] = $m1[$q0[$q1[$q1[$q0[$i] ^ $sd] ^ $s9] ^ $s5] ^ $s1];
576
+ $S2[$i] = $m2[$q1[$q0[$q0[$q0[$i] ^ $se] ^ $sa] ^ $s6] ^ $s2];
577
+ $S3[$i] = $m3[$q1[$q1[$q0[$q1[$i] ^ $sf] ^ $sb] ^ $s7] ^ $s3];
578
+ }
579
+ }
580
+
581
+ $this->K = $K;
582
+ $this->S0 = $S0;
583
+ $this->S1 = $S1;
584
+ $this->S2 = $S2;
585
+ $this->S3 = $S3;
586
+ }
587
+
588
+ /**
589
+ * _mdsrem function using by the twofish cipher algorithm
590
+ *
591
+ * @access private
592
+ * @param String $A
593
+ * @param String $B
594
+ * @return Array
595
+ */
596
+ function _mdsrem($A, $B)
597
+ {
598
+ // No gain by unrolling this loop.
599
+ for ($i = 0; $i < 8; ++$i) {
600
+ // Get most significant coefficient.
601
+ $t = 0xff & ($B >> 24);
602
+
603
+ // Shift the others up.
604
+ $B = ($B << 8) | (0xff & ($A >> 24));
605
+ $A<<= 8;
606
+
607
+ $u = $t << 1;
608
+
609
+ // Subtract the modular polynomial on overflow.
610
+ if ($t & 0x80) {
611
+ $u^= 0x14d;
612
+ }
613
+
614
+ // Remove t * (a * x^2 + 1).
615
+ $B ^= $t ^ ($u << 16);
616
+
617
+ // Form u = a*t + t/a = t*(a + 1/a).
618
+ $u^= 0x7fffffff & ($t >> 1);
619
+
620
+ // Add the modular polynomial on underflow.
621
+ if ($t & 0x01) $u^= 0xa6 ;
622
+
623
+ // Remove t * (a + 1/a) * (x^3 + x).
624
+ $B^= ($u << 24) | ($u << 8);
625
+ }
626
+
627
+ return array(
628
+ 0xff & $B >> 24,
629
+ 0xff & $B >> 16,
630
+ 0xff & $B >> 8,
631
+ 0xff & $B);
632
+ }
633
+
634
+ /**
635
+ * Encrypts a block
636
+ *
637
+ * @access private
638
+ * @param String $in
639
+ * @return String
640
+ */
641
+ function _encryptBlock($in)
642
+ {
643
+ $S0 = $this->S0;
644
+ $S1 = $this->S1;
645
+ $S2 = $this->S2;
646
+ $S3 = $this->S3;
647
+ $K = $this->K;
648
+
649
+ $in = unpack("V4", $in);
650
+ $R0 = $K[0] ^ $in[1];
651
+ $R1 = $K[1] ^ $in[2];
652
+ $R2 = $K[2] ^ $in[3];
653
+ $R3 = $K[3] ^ $in[4];
654
+
655
+ $ki = 7;
656
+ while ($ki < 39) {
657
+ $t0 = $S0[ $R0 & 0xff] ^
658
+ $S1[($R0 >> 8) & 0xff] ^
659
+ $S2[($R0 >> 16) & 0xff] ^
660
+ $S3[($R0 >> 24) & 0xff];
661
+ $t1 = $S0[($R1 >> 24) & 0xff] ^
662
+ $S1[ $R1 & 0xff] ^
663
+ $S2[($R1 >> 8) & 0xff] ^
664
+ $S3[($R1 >> 16) & 0xff];
665
+ $R2^= $t0 + $t1 + $K[++$ki];
666
+ $R2 = ($R2 >> 1 & 0x7fffffff) | ($R2 << 31);
667
+ $R3 = ((($R3 >> 31) & 1) | ($R3 << 1)) ^ ($t0 + ($t1 << 1) + $K[++$ki]);
668
+
669
+ $t0 = $S0[ $R2 & 0xff] ^
670
+ $S1[($R2 >> 8) & 0xff] ^
671
+ $S2[($R2 >> 16) & 0xff] ^
672
+ $S3[($R2 >> 24) & 0xff];
673
+ $t1 = $S0[($R3 >> 24) & 0xff] ^
674
+ $S1[ $R3 & 0xff] ^
675
+ $S2[($R3 >> 8) & 0xff] ^
676
+ $S3[($R3 >> 16) & 0xff];
677
+ $R0^= ($t0 + $t1 + $K[++$ki]);
678
+ $R0 = ($R0 >> 1 & 0x7fffffff) | ($R0 << 31);
679
+ $R1 = ((($R1 >> 31) & 1) | ($R1 << 1)) ^ ($t0 + ($t1 << 1) + $K[++$ki]);
680
+ }
681
+
682
+ // @codingStandardsIgnoreStart
683
+ return pack("V4", $K[4] ^ $R2,
684
+ $K[5] ^ $R3,
685
+ $K[6] ^ $R0,
686
+ $K[7] ^ $R1);
687
+ // @codingStandardsIgnoreEnd
688
+ }
689
+
690
+ /**
691
+ * Decrypts a block
692
+ *
693
+ * @access private
694
+ * @param String $in
695
+ * @return String
696
+ */
697
+ function _decryptBlock($in)
698
+ {
699
+ $S0 = $this->S0;
700
+ $S1 = $this->S1;
701
+ $S2 = $this->S2;
702
+ $S3 = $this->S3;
703
+ $K = $this->K;
704
+
705
+ $in = unpack("V4", $in);
706
+ $R0 = $K[4] ^ $in[1];
707
+ $R1 = $K[5] ^ $in[2];
708
+ $R2 = $K[6] ^ $in[3];
709
+ $R3 = $K[7] ^ $in[4];
710
+
711
+ $ki = 40;
712
+ while ($ki > 8) {
713
+ $t0 = $S0[$R0 & 0xff] ^
714
+ $S1[$R0 >> 8 & 0xff] ^
715
+ $S2[$R0 >> 16 & 0xff] ^
716
+ $S3[$R0 >> 24 & 0xff];
717
+ $t1 = $S0[$R1 >> 24 & 0xff] ^
718
+ $S1[$R1 & 0xff] ^
719
+ $S2[$R1 >> 8 & 0xff] ^
720
+ $S3[$R1 >> 16 & 0xff];
721
+ $R3^= $t0 + ($t1 << 1) + $K[--$ki];
722
+ $R3 = $R3 >> 1 & 0x7fffffff | $R3 << 31;
723
+ $R2 = ($R2 >> 31 & 0x1 | $R2 << 1) ^ ($t0 + $t1 + $K[--$ki]);
724
+
725
+ $t0 = $S0[$R2 & 0xff] ^
726
+ $S1[$R2 >> 8 & 0xff] ^
727
+ $S2[$R2 >> 16 & 0xff] ^
728
+ $S3[$R2 >> 24 & 0xff];
729
+ $t1 = $S0[$R3 >> 24 & 0xff] ^
730
+ $S1[$R3 & 0xff] ^
731
+ $S2[$R3 >> 8 & 0xff] ^
732
+ $S3[$R3 >> 16 & 0xff];
733
+ $R1^= $t0 + ($t1 << 1) + $K[--$ki];
734
+ $R1 = $R1 >> 1 & 0x7fffffff | $R1 << 31;
735
+ $R0 = ($R0 >> 31 & 0x1 | $R0 << 1) ^ ($t0 + $t1 + $K[--$ki]);
736
+ }
737
+
738
+ // @codingStandardsIgnoreStart
739
+ return pack("V4", $K[0] ^ $R2,
740
+ $K[1] ^ $R3,
741
+ $K[2] ^ $R0,
742
+ $K[3] ^ $R1);
743
+ // @codingStandardsIgnoreEnd
744
+ }
745
+
746
+ /**
747
+ * Setup the performance-optimized function for de/encrypt()
748
+ *
749
+ * @see Crypt_Base::_setupInlineCrypt()
750
+ * @access private
751
+ */
752
+ function _setupInlineCrypt()
753
+ {
754
+ $lambda_functions =& Crypt_Twofish::_getLambdaFunctions();
755
+
756
+ // Max. 10 Ultra-Hi-optimized inline-crypt functions. After that, we'll (still) create very fast code, but not the ultimate fast one.
757
+ $gen_hi_opt_code = (bool)( count($lambda_functions) < 10 );
758
+
759
+ switch (true) {
760
+ case $gen_hi_opt_code:
761
+ $code_hash = md5(str_pad("Crypt_Twofish, {$this->mode}, ", 32, "\0") . $this->key);
762
+ break;
763
+ default:
764
+ $code_hash = "Crypt_Twofish, {$this->mode}";
765
+ }
766
+
767
+ if (!isset($lambda_functions[$code_hash])) {
768
+ switch (true) {
769
+ case $gen_hi_opt_code:
770
+ $K = $this->K;
771
+
772
+ $init_crypt = '
773
+ static $S0, $S1, $S2, $S3;
774
+ if (!$S0) {
775
+ for ($i = 0; $i < 256; ++$i) {
776
+ $S0[] = (int)$self->S0[$i];
777
+ $S1[] = (int)$self->S1[$i];
778
+ $S2[] = (int)$self->S2[$i];
779
+ $S3[] = (int)$self->S3[$i];
780
+ }
781
+ }
782
+ ';
783
+ break;
784
+ default:
785
+ $K = array();
786
+ for ($i = 0; $i < 40; ++$i) {
787
+ $K[] = '$K_' . $i;
788
+ }
789
+
790
+ $init_crypt = '
791
+ $S0 = $self->S0;
792
+ $S1 = $self->S1;
793
+ $S2 = $self->S2;
794
+ $S3 = $self->S3;
795
+ list(' . implode(',', $K) . ') = $self->K;
796
+ ';
797
+ }
798
+
799
+ // Generating encrypt code:
800
+ $encrypt_block = '
801
+ $in = unpack("V4", $in);
802
+ $R0 = '.$K[0].' ^ $in[1];
803
+ $R1 = '.$K[1].' ^ $in[2];
804
+ $R2 = '.$K[2].' ^ $in[3];
805
+ $R3 = '.$K[3].' ^ $in[4];
806
+ ';
807
+ for ($ki = 7, $i = 0; $i < 8; ++$i) {
808
+ $encrypt_block.= '
809
+ $t0 = $S0[ $R0 & 0xff] ^
810
+ $S1[($R0 >> 8) & 0xff] ^
811
+ $S2[($R0 >> 16) & 0xff] ^
812
+ $S3[($R0 >> 24) & 0xff];
813
+ $t1 = $S0[($R1 >> 24) & 0xff] ^
814
+ $S1[ $R1 & 0xff] ^
815
+ $S2[($R1 >> 8) & 0xff] ^
816
+ $S3[($R1 >> 16) & 0xff];
817
+ $R2^= ($t0 + $t1 + '.$K[++$ki].');
818
+ $R2 = ($R2 >> 1 & 0x7fffffff) | ($R2 << 31);
819
+ $R3 = ((($R3 >> 31) & 1) | ($R3 << 1)) ^ ($t0 + ($t1 << 1) + '.$K[++$ki].');
820
+
821
+ $t0 = $S0[ $R2 & 0xff] ^
822
+ $S1[($R2 >> 8) & 0xff] ^
823
+ $S2[($R2 >> 16) & 0xff] ^
824
+ $S3[($R2 >> 24) & 0xff];
825
+ $t1 = $S0[($R3 >> 24) & 0xff] ^
826
+ $S1[ $R3 & 0xff] ^
827
+ $S2[($R3 >> 8) & 0xff] ^
828
+ $S3[($R3 >> 16) & 0xff];
829
+ $R0^= ($t0 + $t1 + '.$K[++$ki].');
830
+ $R0 = ($R0 >> 1 & 0x7fffffff) | ($R0 << 31);
831
+ $R1 = ((($R1 >> 31) & 1) | ($R1 << 1)) ^ ($t0 + ($t1 << 1) + '.$K[++$ki].');
832
+ ';
833
+ }
834
+ $encrypt_block.= '
835
+ $in = pack("V4", '.$K[4].' ^ $R2,
836
+ '.$K[5].' ^ $R3,
837
+ '.$K[6].' ^ $R0,
838
+ '.$K[7].' ^ $R1);
839
+ ';
840
+
841
+ // Generating decrypt code:
842
+ $decrypt_block = '
843
+ $in = unpack("V4", $in);
844
+ $R0 = '.$K[4].' ^ $in[1];
845
+ $R1 = '.$K[5].' ^ $in[2];
846
+ $R2 = '.$K[6].' ^ $in[3];
847
+ $R3 = '.$K[7].' ^ $in[4];
848
+ ';
849
+ for ($ki = 40, $i = 0; $i < 8; ++$i) {
850
+ $decrypt_block.= '
851
+ $t0 = $S0[$R0 & 0xff] ^
852
+ $S1[$R0 >> 8 & 0xff] ^
853
+ $S2[$R0 >> 16 & 0xff] ^
854
+ $S3[$R0 >> 24 & 0xff];
855
+ $t1 = $S0[$R1 >> 24 & 0xff] ^
856
+ $S1[$R1 & 0xff] ^
857
+ $S2[$R1 >> 8 & 0xff] ^
858
+ $S3[$R1 >> 16 & 0xff];
859
+ $R3^= $t0 + ($t1 << 1) + '.$K[--$ki].';
860
+ $R3 = $R3 >> 1 & 0x7fffffff | $R3 << 31;
861
+ $R2 = ($R2 >> 31 & 0x1 | $R2 << 1) ^ ($t0 + $t1 + '.$K[--$ki].');
862
+
863
+ $t0 = $S0[$R2 & 0xff] ^
864
+ $S1[$R2 >> 8 & 0xff] ^
865
+ $S2[$R2 >> 16 & 0xff] ^
866
+ $S3[$R2 >> 24 & 0xff];
867
+ $t1 = $S0[$R3 >> 24 & 0xff] ^
868
+ $S1[$R3 & 0xff] ^
869
+ $S2[$R3 >> 8 & 0xff] ^
870
+ $S3[$R3 >> 16 & 0xff];
871
+ $R1^= $t0 + ($t1 << 1) + '.$K[--$ki].';
872
+ $R1 = $R1 >> 1 & 0x7fffffff | $R1 << 31;
873
+ $R0 = ($R0 >> 31 & 0x1 | $R0 << 1) ^ ($t0 + $t1 + '.$K[--$ki].');
874
+ ';
875
+ }
876
+ $decrypt_block.= '
877
+ $in = pack("V4", '.$K[0].' ^ $R2,
878
+ '.$K[1].' ^ $R3,
879
+ '.$K[2].' ^ $R0,
880
+ '.$K[3].' ^ $R1);
881
+ ';
882
+
883
+ $lambda_functions[$code_hash] = $this->_createInlineCryptFunction(
884
+ array(
885
+ 'init_crypt' => $init_crypt,
886
+ 'init_encrypt' => '',
887
+ 'init_decrypt' => '',
888
+ 'encrypt_block' => $encrypt_block,
889
+ 'decrypt_block' => $decrypt_block
890
+ )
891
+ );
892
+ }
893
+ $this->inline_crypt = $lambda_functions[$code_hash];
894
+ }
895
+ }
phpseclib/Math/BigInteger.php CHANGED
@@ -1,3633 +1,3751 @@
1
- <?php
2
- /* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
3
-
4
- /**
5
- * Pure-PHP arbitrary precision integer arithmetic library.
6
- *
7
- * Supports base-2, base-10, base-16, and base-256 numbers. Uses the GMP or BCMath extensions, if available,
8
- * and an internal implementation, otherwise.
9
- *
10
- * PHP versions 4 and 5
11
- *
12
- * {@internal (all DocBlock comments regarding implementation - such as the one that follows - refer to the
13
- * {@link MATH_BIGINTEGER_MODE_INTERNAL MATH_BIGINTEGER_MODE_INTERNAL} mode)
14
- *
15
- * Math_BigInteger uses base-2**26 to perform operations such as multiplication and division and
16
- * base-2**52 (ie. two base 2**26 digits) to perform addition and subtraction. Because the largest possible
17
- * value when multiplying two base-2**26 numbers together is a base-2**52 number, double precision floating
18
- * point numbers - numbers that should be supported on most hardware and whose significand is 53 bits - are
19
- * used. As a consequence, bitwise operators such as >> and << cannot be used, nor can the modulo operator %,
20
- * which only supports integers. Although this fact will slow this library down, the fact that such a high
21
- * base is being used should more than compensate.
22
- *
23
- * When PHP version 6 is officially released, we'll be able to use 64-bit integers. This should, once again,
24
- * allow bitwise operators, and will increase the maximum possible base to 2**31 (or 2**62 for addition /
25
- * subtraction).
26
- *
27
- * Numbers are stored in {@link http://en.wikipedia.org/wiki/Endianness little endian} format. ie.
28
- * (new Math_BigInteger(pow(2, 26)))->value = array(0, 1)
29
- *
30
- * Useful resources are as follows:
31
- *
32
- * - {@link http://www.cacr.math.uwaterloo.ca/hac/about/chap14.pdf Handbook of Applied Cryptography (HAC)}
33
- * - {@link http://math.libtomcrypt.com/files/tommath.pdf Multi-Precision Math (MPM)}
34
- * - Java's BigInteger classes. See /j2se/src/share/classes/java/math in jdk-1_5_0-src-jrl.zip
35
- *
36
- * Here's an example of how to use this library:
37
- * <code>
38
- * <?php
39
- * include('Math/BigInteger.php');
40
- *
41
- * $a = new Math_BigInteger(2);
42
- * $b = new Math_BigInteger(3);
43
- *
44
- * $c = $a->add($b);
45
- *
46
- * echo $c->toString(); // outputs 5
47
- * ?>
48
- * </code>
49
- *
50
- * LICENSE: Permission is hereby granted, free of charge, to any person obtaining a copy
51
- * of this software and associated documentation files (the "Software"), to deal
52
- * in the Software without restriction, including without limitation the rights
53
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
54
- * copies of the Software, and to permit persons to whom the Software is
55
- * furnished to do so, subject to the following conditions:
56
- *
57
- * The above copyright notice and this permission notice shall be included in
58
- * all copies or substantial portions of the Software.
59
- *
60
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
61
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
62
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
63
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
64
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
65
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
66
- * THE SOFTWARE.
67
- *
68
- * @category Math
69
- * @package Math_BigInteger
70
- * @author Jim Wigginton <terrafrost@php.net>
71
- * @copyright MMVI Jim Wigginton
72
- * @license http://www.opensource.org/licenses/mit-license.html MIT License
73
- * @version $Id: BigInteger.php,v 1.33 2010/03/22 22:32:03 terrafrost Exp $
74
- * @link http://pear.php.net/package/Math_BigInteger
75
- */
76
-
77
- /**#@+
78
- * Reduction constants
79
- *
80
- * @access private
81
- * @see Math_BigInteger::_reduce()
82
- */
83
- /**
84
- * @see Math_BigInteger::_montgomery()
85
- * @see Math_BigInteger::_prepMontgomery()
86
- */
87
- define('MATH_BIGINTEGER_MONTGOMERY', 0);
88
- /**
89
- * @see Math_BigInteger::_barrett()
90
- */
91
- define('MATH_BIGINTEGER_BARRETT', 1);
92
- /**
93
- * @see Math_BigInteger::_mod2()
94
- */
95
- define('MATH_BIGINTEGER_POWEROF2', 2);
96
- /**
97
- * @see Math_BigInteger::_remainder()
98
- */
99
- define('MATH_BIGINTEGER_CLASSIC', 3);
100
- /**
101
- * @see Math_BigInteger::__clone()
102
- */
103
- define('MATH_BIGINTEGER_NONE', 4);
104
- /**#@-*/
105
-
106
- /**#@+
107
- * Array constants
108
- *
109
- * Rather than create a thousands and thousands of new Math_BigInteger objects in repeated function calls to add() and
110
- * multiply() or whatever, we'll just work directly on arrays, taking them in as parameters and returning them.
111
- *
112
- * @access private
113
- */
114
- /**
115
- * $result[MATH_BIGINTEGER_VALUE] contains the value.
116
- */
117
- define('MATH_BIGINTEGER_VALUE', 0);
118
- /**
119
- * $result[MATH_BIGINTEGER_SIGN] contains the sign.
120
- */
121
- define('MATH_BIGINTEGER_SIGN', 1);
122
- /**#@-*/
123
-
124
- /**#@+
125
- * @access private
126
- * @see Math_BigInteger::_montgomery()
127
- * @see Math_BigInteger::_barrett()
128
- */
129
- /**
130
- * Cache constants
131
- *
132
- * $cache[MATH_BIGINTEGER_VARIABLE] tells us whether or not the cached data is still valid.
133
- */
134
- define('MATH_BIGINTEGER_VARIABLE', 0);
135
- /**
136
- * $cache[MATH_BIGINTEGER_DATA] contains the cached data.
137
- */
138
- define('MATH_BIGINTEGER_DATA', 1);
139
- /**#@-*/
140
-
141
- /**#@+
142
- * Mode constants.
143
- *
144
- * @access private
145
- * @see Math_BigInteger::Math_BigInteger()
146
- */
147
- /**
148
- * To use the pure-PHP implementation
149
- */
150
- define('MATH_BIGINTEGER_MODE_INTERNAL', 1);
151
- /**
152
- * To use the BCMath library
153
- *
154
- * (if enabled; otherwise, the internal implementation will be used)
155
- */
156
- define('MATH_BIGINTEGER_MODE_BCMATH', 2);
157
- /**
158
- * To use the GMP library
159
- *
160
- * (if present; otherwise, either the BCMath or the internal implementation will be used)
161
- */
162
- define('MATH_BIGINTEGER_MODE_GMP', 3);
163
- /**#@-*/
164
-
165
- /**
166
- * The largest digit that may be used in addition / subtraction
167
- *
168
- * (we do pow(2, 52) instead of using 4503599627370496, directly, because some PHP installations
169
- * will truncate 4503599627370496)
170
- *
171
- * @access private
172
- */
173
- define('MATH_BIGINTEGER_MAX_DIGIT52', pow(2, 52));
174
-
175
- /**
176
- * Karatsuba Cutoff
177
- *
178
- * At what point do we switch between Karatsuba multiplication and schoolbook long multiplication?
179
- *
180
- * @access private
181
- */
182
- define('MATH_BIGINTEGER_KARATSUBA_CUTOFF', 25);
183
-
184
- /**
185
- * Pure-PHP arbitrary precision integer arithmetic library. Supports base-2, base-10, base-16, and base-256
186
- * numbers.
187
- *
188
- * @author Jim Wigginton <terrafrost@php.net>
189
- * @version 1.0.0RC4
190
- * @access public
191
- * @package Math_BigInteger
192
- */
193
- class Math_BigInteger {
194
- /**
195
- * Holds the BigInteger's value.
196
- *
197
- * @var Array
198
- * @access private
199
- */
200
- var $value;
201
-
202
- /**
203
- * Holds the BigInteger's magnitude.
204
- *
205
- * @var Boolean
206
- * @access private
207
- */
208
- var $is_negative = false;
209
-
210
- /**
211
- * Random number generator function
212
- *
213
- * @see setRandomGenerator()
214
- * @access private
215
- */
216
- var $generator = 'mt_rand';
217
-
218
- /**
219
- * Precision
220
- *
221
- * @see setPrecision()
222
- * @access private
223
- */
224
- var $precision = -1;
225
-
226
- /**
227
- * Precision Bitmask
228
- *
229
- * @see setPrecision()
230
- * @access private
231
- */
232
- var $bitmask = false;
233
-
234
- /**
235
- * Mode independant value used for serialization.
236
- *
237
- * If the bcmath or gmp extensions are installed $this->value will be a non-serializable resource, hence the need for
238
- * a variable that'll be serializable regardless of whether or not extensions are being used. Unlike $this->value,
239
- * however, $this->hex is only calculated when $this->__sleep() is called.
240
- *
241
- * @see __sleep()
242
- * @see __wakeup()
243
- * @var String
244
- * @access private
245
- */
246
- var $hex;
247
-
248
- /**
249
- * Converts base-2, base-10, base-16, and binary strings (eg. base-256) to BigIntegers.
250
- *
251
- * If the second parameter - $base - is negative, then it will be assumed that the number's are encoded using
252
- * two's compliment. The sole exception to this is -10, which is treated the same as 10 is.
253
- *
254
- * Here's an example:
255
- * <code>
256
- * <?php
257
- * include('Math/BigInteger.php');
258
- *
259
- * $a = new Math_BigInteger('0x32', 16); // 50 in base-16
260
- *
261
- * echo $a->toString(); // outputs 50
262
- * ?>
263
- * </code>
264
- *
265
- * @param optional $x base-10 number or base-$base number if $base set.
266
- * @param optional integer $base
267
- * @return Math_BigInteger
268
- * @access public
269
- */
270
- function Math_BigInteger($x = 0, $base = 10)
271
- {
272
- if ( !defined('MATH_BIGINTEGER_MODE') ) {
273
- switch (true) {
274
- case extension_loaded('gmp'):
275
- define('MATH_BIGINTEGER_MODE', MATH_BIGINTEGER_MODE_GMP);
276
- break;
277
- case extension_loaded('bcmath'):
278
- define('MATH_BIGINTEGER_MODE', MATH_BIGINTEGER_MODE_BCMATH);
279
- break;
280
- default:
281
- define('MATH_BIGINTEGER_MODE', MATH_BIGINTEGER_MODE_INTERNAL);
282
- }
283
- }
284
-
285
- if (function_exists('openssl_public_encrypt') && !defined('MATH_BIGINTEGER_OPENSSL_DISABLE') && !defined('MATH_BIGINTEGER_OPENSSL_ENABLED')) {
286
- define('MATH_BIGINTEGER_OPENSSL_ENABLED', true);
287
- }
288
-
289
- switch ( MATH_BIGINTEGER_MODE ) {
290
- case MATH_BIGINTEGER_MODE_GMP:
291
- if (is_resource($x) && get_resource_type($x) == 'GMP integer') {
292
- $this->value = $x;
293
- return;
294
- }
295
- $this->value = gmp_init(0);
296
- break;
297
- case MATH_BIGINTEGER_MODE_BCMATH:
298
- $this->value = '0';
299
- break;
300
- default:
301
- $this->value = array();
302
- }
303
-
304
- // '0' counts as empty() but when the base is 256 '0' is equal to ord('0') or 48
305
- // '0' is the only value like this per http://php.net/empty
306
- if (empty($x) && (abs($base) != 256 || $x !== '0')) {
307
- return;
308
- }
309
-
310
- switch ($base) {
311
- case -256:
312
- if (ord($x[0]) & 0x80) {
313
- $x = ~$x;
314
- $this->is_negative = true;
315
- }
316
- case 256:
317
- switch ( MATH_BIGINTEGER_MODE ) {
318
- case MATH_BIGINTEGER_MODE_GMP:
319
- $sign = $this->is_negative ? '-' : '';
320
- $this->value = gmp_init($sign . '0x' . bin2hex($x));
321
- break;
322
- case MATH_BIGINTEGER_MODE_BCMATH:
323
- // round $len to the nearest 4 (thanks, DavidMJ!)
324
- $len = (strlen($x) + 3) & 0xFFFFFFFC;
325
-
326
- $x = str_pad($x, $len, chr(0), STR_PAD_LEFT);
327
-
328
- for ($i = 0; $i < $len; $i+= 4) {
329
- $this->value = bcmul($this->value, '4294967296', 0); // 4294967296 == 2**32
330
- $this->value = bcadd($this->value, 0x1000000 * ord($x[$i]) + ((ord($x[$i + 1]) << 16) | (ord($x[$i + 2]) << 8) | ord($x[$i + 3])), 0);
331
- }
332
-
333
- if ($this->is_negative) {
334
- $this->value = '-' . $this->value;
335
- }
336
-
337
- break;
338
- // converts a base-2**8 (big endian / msb) number to base-2**26 (little endian / lsb)
339
- default:
340
- while (strlen($x)) {
341
- $this->value[] = $this->_bytes2int($this->_base256_rshift($x, 26));
342
- }
343
- }
344
-
345
- if ($this->is_negative) {
346
- if (MATH_BIGINTEGER_MODE != MATH_BIGINTEGER_MODE_INTERNAL) {
347
- $this->is_negative = false;
348
- }
349
- $temp = $this->add(new Math_BigInteger('-1'));
350
- $this->value = $temp->value;
351
- }
352
- break;
353
- case 16:
354
- case -16:
355
- if ($base > 0 && $x[0] == '-') {
356
- $this->is_negative = true;
357
- $x = substr($x, 1);
358
- }
359
-
360
- $x = preg_replace('#^(?:0x)?([A-Fa-f0-9]*).*#', '$1', $x);
361
-
362
- $is_negative = false;
363
- if ($base < 0 && hexdec($x[0]) >= 8) {
364
- $this->is_negative = $is_negative = true;
365
- $x = bin2hex(~pack('H*', $x));
366
- }
367
-
368
- switch ( MATH_BIGINTEGER_MODE ) {
369
- case MATH_BIGINTEGER_MODE_GMP:
370
- $temp = $this->is_negative ? '-0x' . $x : '0x' . $x;
371
- $this->value = gmp_init($temp);
372
- $this->is_negative = false;
373
- break;
374
- case MATH_BIGINTEGER_MODE_BCMATH:
375
- $x = ( strlen($x) & 1 ) ? '0' . $x : $x;
376
- $temp = new Math_BigInteger(pack('H*', $x), 256);
377
- $this->value = $this->is_negative ? '-' . $temp->value : $temp->value;
378
- $this->is_negative = false;
379
- break;
380
- default:
381
- $x = ( strlen($x) & 1 ) ? '0' . $x : $x;
382
- $temp = new Math_BigInteger(pack('H*', $x), 256);
383
- $this->value = $temp->value;
384
- }
385
-
386
- if ($is_negative) {
387
- $temp = $this->add(new Math_BigInteger('-1'));
388
- $this->value = $temp->value;
389
- }
390
- break;
391
- case 10:
392
- case -10:
393
- $x = preg_replace('#^(-?[0-9]*).*#', '$1', $x);
394
-
395
- switch ( MATH_BIGINTEGER_MODE ) {
396
- case MATH_BIGINTEGER_MODE_GMP:
397
- $this->value = gmp_init($x);
398
- break;
399
- case MATH_BIGINTEGER_MODE_BCMATH:
400
- // explicitly casting $x to a string is necessary, here, since doing $x[0] on -1 yields different
401
- // results then doing it on '-1' does (modInverse does $x[0])
402
- $this->value = (string) $x;
403
- break;
404
- default:
405
- $temp = new Math_BigInteger();
406
-
407
- // array(10000000) is 10**7 in base-2**26. 10**7 is the closest to 2**26 we can get without passing it.
408
- $multiplier = new Math_BigInteger();
409
- $multiplier->value = array(10000000);
410
-
411
- if ($x[0] == '-') {
412
- $this->is_negative = true;
413
- $x = substr($x, 1);
414
- }
415
-
416
- $x = str_pad($x, strlen($x) + (6 * strlen($x)) % 7, 0, STR_PAD_LEFT);
417
-
418
- while (strlen($x)) {
419
- $temp = $temp->multiply($multiplier);
420
- $temp = $temp->add(new Math_BigInteger($this->_int2bytes(substr($x, 0, 7)), 256));
421
- $x = substr($x, 7);
422
- }
423
-
424
- $this->value = $temp->value;
425
- }
426
- break;
427
- case 2: // base-2 support originally implemented by Lluis Pamies - thanks!
428
- case -2:
429
- if ($base > 0 && $x[0] == '-') {
430
- $this->is_negative = true;
431
- $x = substr($x, 1);
432
- }
433
-
434
- $x = preg_replace('#^([01]*).*#', '$1', $x);
435
- $x = str_pad($x, strlen($x) + (3 * strlen($x)) % 4, 0, STR_PAD_LEFT);
436
-
437
- $str = '0x';
438
- while (strlen($x)) {
439
- $part = substr($x, 0, 4);
440
- $str.= dechex(bindec($part));
441
- $x = substr($x, 4);
442
- }
443
-
444
- if ($this->is_negative) {
445
- $str = '-' . $str;
446
- }
447
-
448
- $temp = new Math_BigInteger($str, 8 * $base); // ie. either -16 or +16
449
- $this->value = $temp->value;
450
- $this->is_negative = $temp->is_negative;
451
-
452
- break;
453
- default:
454
- // base not supported, so we'll let $this == 0
455
- }
456
- }
457
-
458
- /**
459
- * Converts a BigInteger to a byte string (eg. base-256).
460
- *
461
- * Negative numbers are saved as positive numbers, unless $twos_compliment is set to true, at which point, they're
462
- * saved as two's compliment.
463
- *
464
- * Here's an example:
465
- * <code>
466
- * <?php
467
- * include('Math/BigInteger.php');
468
- *
469
- * $a = new Math_BigInteger('65');
470
- *
471
- * echo $a->toBytes(); // outputs chr(65)
472
- * ?>
473
- * </code>
474
- *
475
- * @param Boolean $twos_compliment
476
- * @return String
477
- * @access public
478
- * @internal Converts a base-2**26 number to base-2**8
479
- */
480
- function toBytes($twos_compliment = false)
481
- {
482
- if ($twos_compliment) {
483
- $comparison = $this->compare(new Math_BigInteger());
484
- if ($comparison == 0) {
485
- return $this->precision > 0 ? str_repeat(chr(0), ($this->precision + 1) >> 3) : '';
486
- }
487
-
488
- $temp = $comparison < 0 ? $this->add(new Math_BigInteger(1)) : $this->copy();
489
- $bytes = $temp->toBytes();
490
-
491
- if (empty($bytes)) { // eg. if the number we're trying to convert is -1
492
- $bytes = chr(0);
493
- }
494
-
495
- if (ord($bytes[0]) & 0x80) {
496
- $bytes = chr(0) . $bytes;
497
- }
498
-
499
- return $comparison < 0 ? ~$bytes : $bytes;
500
- }
501
-
502
- switch ( MATH_BIGINTEGER_MODE ) {
503
- case MATH_BIGINTEGER_MODE_GMP:
504
- if (gmp_cmp($this->value, gmp_init(0)) == 0) {
505
- return $this->precision > 0 ? str_repeat(chr(0), ($this->precision + 1) >> 3) : '';
506
- }
507
-
508
- $temp = gmp_strval(gmp_abs($this->value), 16);
509
- $temp = ( strlen($temp) & 1 ) ? '0' . $temp : $temp;
510
- $temp = pack('H*', $temp);
511
-
512
- return $this->precision > 0 ?
513
- substr(str_pad($temp, $this->precision >> 3, chr(0), STR_PAD_LEFT), -($this->precision >> 3)) :
514
- ltrim($temp, chr(0));
515
- case MATH_BIGINTEGER_MODE_BCMATH:
516
- if ($this->value === '0') {
517
- return $this->precision > 0 ? str_repeat(chr(0), ($this->precision + 1) >> 3) : '';
518
- }
519
-
520
- $value = '';
521
- $current = $this->value;
522
-
523
- if ($current[0] == '-') {
524
- $current = substr($current, 1);
525
- }
526
-
527
- while (bccomp($current, '0', 0) > 0) {
528
- $temp = bcmod($current, '16777216');
529
- $value = chr($temp >> 16) . chr($temp >> 8) . chr($temp) . $value;
530
- $current = bcdiv($current, '16777216', 0);
531
- }
532
-
533
- return $this->precision > 0 ?
534
- substr(str_pad($value, $this->precision >> 3, chr(0), STR_PAD_LEFT), -($this->precision >> 3)) :
535
- ltrim($value, chr(0));
536
- }
537
-
538
- if (!count($this->value)) {
539
- return $this->precision > 0 ? str_repeat(chr(0), ($this->precision + 1) >> 3) : '';
540
- }
541
- $result = $this->_int2bytes($this->value[count($this->value) - 1]);
542
-
543
- $temp = $this->copy();
544
-
545
- for ($i = count($temp->value) - 2; $i >= 0; --$i) {
546
- $temp->_base256_lshift($result, 26);
547
- $result = $result | str_pad($temp->_int2bytes($temp->value[$i]), strlen($result), chr(0), STR_PAD_LEFT);
548
- }
549
-
550
- return $this->precision > 0 ?
551
- str_pad(substr($result, -(($this->precision + 7) >> 3)), ($this->precision + 7) >> 3, chr(0), STR_PAD_LEFT) :
552
- $result;
553
- }
554
-
555
- /**
556
- * Converts a BigInteger to a hex string (eg. base-16)).
557
- *
558
- * Negative numbers are saved as positive numbers, unless $twos_compliment is set to true, at which point, they're
559
- * saved as two's compliment.
560
- *
561
- * Here's an example:
562
- * <code>
563
- * <?php
564
- * include('Math/BigInteger.php');
565
- *
566
- * $a = new Math_BigInteger('65');
567
- *
568
- * echo $a->toHex(); // outputs '41'
569
- * ?>
570
- * </code>
571
- *
572
- * @param Boolean $twos_compliment
573
- * @return String
574
- * @access public
575
- * @internal Converts a base-2**26 number to base-2**8
576
- */
577
- function toHex($twos_compliment = false)
578
- {
579
- return bin2hex($this->toBytes($twos_compliment));
580
- }
581
-
582
- /**
583
- * Converts a BigInteger to a bit string (eg. base-2).
584
- *
585
- * Negative numbers are saved as positive numbers, unless $twos_compliment is set to true, at which point, they're
586
- * saved as two's compliment.
587
- *
588
- * Here's an example:
589
- * <code>
590
- * <?php
591
- * include('Math/BigInteger.php');
592
- *
593
- * $a = new Math_BigInteger('65');
594
- *
595
- * echo $a->toBits(); // outputs '1000001'
596
- * ?>
597
- * </code>
598
- *
599
- * @param Boolean $twos_compliment
600
- * @return String
601
- * @access public
602
- * @internal Converts a base-2**26 number to base-2**2
603
- */
604
- function toBits($twos_compliment = false)
605
- {
606
- $hex = $this->toHex($twos_compliment);
607
- $bits = '';
608
- for ($i = strlen($hex) - 8, $start = strlen($hex) & 7; $i >= $start; $i-=8) {
609
- $bits = str_pad(decbin(hexdec(substr($hex, $i, 8))), 32, '0', STR_PAD_LEFT) . $bits;
610
- }
611
- if ($start) { // hexdec('') == 0
612
- $bits = str_pad(decbin(hexdec(substr($hex, 0, $start))), 8, '0', STR_PAD_LEFT) . $bits;
613
- }
614
- $result = $this->precision > 0 ? substr($bits, -$this->precision) : ltrim($bits, '0');
615
-
616
- if ($twos_compliment && $this->compare(new Math_BigInteger()) > 0 && $this->precision <= 0) {
617
- return '0' . $result;
618
- }
619
-
620
- return $result;
621
- }
622
-
623
- /**
624
- * Converts a BigInteger to a base-10 number.
625
- *
626
- * Here's an example:
627
- * <code>
628
- * <?php
629
- * include('Math/BigInteger.php');
630
- *
631
- * $a = new Math_BigInteger('50');
632
- *
633
- * echo $a->toString(); // outputs 50
634
- * ?>
635
- * </code>
636
- *
637
- * @return String
638
- * @access public
639
- * @internal Converts a base-2**26 number to base-10**7 (which is pretty much base-10)
640
- */
641
- function toString()
642
- {
643
- switch ( MATH_BIGINTEGER_MODE ) {
644
- case MATH_BIGINTEGER_MODE_GMP:
645
- return gmp_strval($this->value);
646
- case MATH_BIGINTEGER_MODE_BCMATH:
647
- if ($this->value === '0') {
648
- return '0';
649
- }
650
-
651
- return ltrim($this->value, '0');
652
- }
653
-
654
- if (!count($this->value)) {
655
- return '0';
656
- }
657
-
658
- $temp = $this->copy();
659
- $temp->is_negative = false;
660
-
661
- $divisor = new Math_BigInteger();
662
- $divisor->value = array(10000000); // eg. 10**7
663
- $result = '';
664
- while (count($temp->value)) {
665
- list($temp, $mod) = $temp->divide($divisor);
666
- $result = str_pad(isset($mod->value[0]) ? $mod->value[0] : '', 7, '0', STR_PAD_LEFT) . $result;
667
- }
668
- $result = ltrim($result, '0');
669
- if (empty($result)) {
670
- $result = '0';
671
- }
672
-
673
- if ($this->is_negative) {
674
- $result = '-' . $result;
675
- }
676
-
677
- return $result;
678
- }
679
-
680
- /**
681
- * Copy an object
682
- *
683
- * PHP5 passes objects by reference while PHP4 passes by value. As such, we need a function to guarantee
684
- * that all objects are passed by value, when appropriate. More information can be found here:
685
- *
686
- * {@link http://php.net/language.oop5.basic#51624}
687
- *
688
- * @access public
689
- * @see __clone()
690
- * @return Math_BigInteger
691
- */
692
- function copy()
693
- {
694
- $temp = new Math_BigInteger();
695
- $temp->value = $this->value;
696
- $temp->is_negative = $this->is_negative;
697
- $temp->generator = $this->generator;
698
- $temp->precision = $this->precision;
699
- $temp->bitmask = $this->bitmask;
700
- return $temp;
701
- }
702
-
703
- /**
704
- * __toString() magic method
705
- *
706
- * Will be called, automatically, if you're supporting just PHP5. If you're supporting PHP4, you'll need to call
707
- * toString().
708
- *
709
- * @access public
710
- * @internal Implemented per a suggestion by Techie-Michael - thanks!
711
- */
712
- function __toString()
713
- {
714
- return $this->toString();
715
- }
716
-
717
- /**
718
- * __clone() magic method
719
- *
720
- * Although you can call Math_BigInteger::__toString() directly in PHP5, you cannot call Math_BigInteger::__clone()
721
- * directly in PHP5. You can in PHP4 since it's not a magic method, but in PHP5, you have to call it by using the PHP5
722
- * only syntax of $y = clone $x. As such, if you're trying to write an application that works on both PHP4 and PHP5,
723
- * call Math_BigInteger::copy(), instead.
724
- *
725
- * @access public
726
- * @see copy()
727
- * @return Math_BigInteger
728
- */
729
- function __clone()
730
- {
731
- return $this->copy();
732
- }
733
-
734
- /**
735
- * __sleep() magic method
736
- *
737
- * Will be called, automatically, when serialize() is called on a Math_BigInteger object.
738
- *
739
- * @see __wakeup()
740
- * @access public
741
- */
742
- function __sleep()
743
- {
744
- $this->hex = $this->toHex(true);
745
- $vars = array('hex');
746
- if ($this->generator != 'mt_rand') {
747
- $vars[] = 'generator';
748
- }
749
- if ($this->precision > 0) {
750
- $vars[] = 'precision';
751
- }
752
- return $vars;
753
-
754
- }
755
-
756
- /**
757
- * __wakeup() magic method
758
- *
759
- * Will be called, automatically, when unserialize() is called on a Math_BigInteger object.
760
- *
761
- * @see __sleep()
762
- * @access public
763
- */
764
- function __wakeup()
765
- {
766
- $temp = new Math_BigInteger($this->hex, -16);
767
- $this->value = $temp->value;
768
- $this->is_negative = $temp->is_negative;
769
- $this->setRandomGenerator($this->generator);
770
- if ($this->precision > 0) {
771
- // recalculate $this->bitmask
772
- $this->setPrecision($this->precision);
773
- }
774
- }
775
-
776
- /**
777
- * Adds two BigIntegers.
778
- *
779
- * Here's an example:
780
- * <code>
781
- * <?php
782
- * include('Math/BigInteger.php');
783
- *
784
- * $a = new Math_BigInteger('10');
785
- * $b = new Math_BigInteger('20');
786
- *
787
- * $c = $a->add($b);
788
- *
789
- * echo $c->toString(); // outputs 30
790
- * ?>
791
- * </code>
792
- *
793
- * @param Math_BigInteger $y
794
- * @return Math_BigInteger
795
- * @access public
796
- * @internal Performs base-2**52 addition
797
- */
798
- function add($y)
799
- {
800
- switch ( MATH_BIGINTEGER_MODE ) {
801
- case MATH_BIGINTEGER_MODE_GMP:
802
- $temp = new Math_BigInteger();
803
- $temp->value = gmp_add($this->value, $y->value);
804
-
805
- return $this->_normalize($temp);
806
- case MATH_BIGINTEGER_MODE_BCMATH:
807
- $temp = new Math_BigInteger();
808
- $temp->value = bcadd($this->value, $y->value, 0);
809
-
810
- return $this->_normalize($temp);
811
- }
812
-
813
- $temp = $this->_add($this->value, $this->is_negative, $y->value, $y->is_negative);
814
-
815
- $result = new Math_BigInteger();
816
- $result->value = $temp[MATH_BIGINTEGER_VALUE];
817
- $result->is_negative = $temp[MATH_BIGINTEGER_SIGN];
818
-
819
- return $this->_normalize($result);
820
- }
821
-
822
- /**
823
- * Performs addition.
824
- *
825
- * @param Array $x_value
826
- * @param Boolean $x_negative
827
- * @param Array $y_value
828
- * @param Boolean $y_negative
829
- * @return Array
830
- * @access private
831
- */
832
- function _add($x_value, $x_negative, $y_value, $y_negative)
833
- {
834
- $x_size = count($x_value);
835
- $y_size = count($y_value);
836
-
837
- if ($x_size == 0) {
838
- return array(
839
- MATH_BIGINTEGER_VALUE => $y_value,
840
- MATH_BIGINTEGER_SIGN => $y_negative
841
- );
842
- } else if ($y_size == 0) {
843
- return array(
844
- MATH_BIGINTEGER_VALUE => $x_value,
845
- MATH_BIGINTEGER_SIGN => $x_negative
846
- );
847
- }
848
-
849
- // subtract, if appropriate
850
- if ( $x_negative != $y_negative ) {
851
- if ( $x_value == $y_value ) {
852
- return array(
853
- MATH_BIGINTEGER_VALUE => array(),
854
- MATH_BIGINTEGER_SIGN => false
855
- );
856
- }
857
-
858
- $temp = $this->_subtract($x_value, false, $y_value, false);
859
- $temp[MATH_BIGINTEGER_SIGN] = $this->_compare($x_value, false, $y_value, false) > 0 ?
860
- $x_negative : $y_negative;
861
-
862
- return $temp;
863
- }
864
-
865
- if ($x_size < $y_size) {
866
- $size = $x_size;
867
- $value = $y_value;
868
- } else {
869
- $size = $y_size;
870
- $value = $x_value;
871
- }
872
-
873
- $value[] = 0; // just in case the carry adds an extra digit
874
-
875
- $carry = 0;
876
- for ($i = 0, $j = 1; $j < $size; $i+=2, $j+=2) {
877
- $sum = $x_value[$j] * 0x4000000 + $x_value[$i] + $y_value[$j] * 0x4000000 + $y_value[$i] + $carry;
878
- $carry = $sum >= MATH_BIGINTEGER_MAX_DIGIT52; // eg. floor($sum / 2**52); only possible values (in any base) are 0 and 1
879
- $sum = $carry ? $sum - MATH_BIGINTEGER_MAX_DIGIT52 : $sum;
880
-
881
- $temp = (int) ($sum / 0x4000000);
882
-
883
- $value[$i] = (int) ($sum - 0x4000000 * $temp); // eg. a faster alternative to fmod($sum, 0x4000000)
884
- $value[$j] = $temp;
885
- }
886
-
887
- if ($j == $size) { // ie. if $y_size is odd
888
- $sum = $x_value[$i] + $y_value[$i] + $carry;
889
- $carry = $sum >= 0x4000000;
890
- $value[$i] = $carry ? $sum - 0x4000000 : $sum;
891
- ++$i; // ie. let $i = $j since we've just done $value[$i]
892
- }
893
-
894
- if ($carry) {
895
- for (; $value[$i] == 0x3FFFFFF; ++$i) {
896
- $value[$i] = 0;
897
- }
898
- ++$value[$i];
899
- }
900
-
901
- return array(
902
- MATH_BIGINTEGER_VALUE => $this->_trim($value),
903
- MATH_BIGINTEGER_SIGN => $x_negative
904
- );
905
- }
906
-
907
- /**
908
- * Subtracts two BigIntegers.
909
- *
910
- * Here's an example:
911
- * <code>
912
- * <?php
913
- * include('Math/BigInteger.php');
914
- *
915
- * $a = new Math_BigInteger('10');
916
- * $b = new Math_BigInteger('20');
917
- *
918
- * $c = $a->subtract($b);
919
- *
920
- * echo $c->toString(); // outputs -10
921
- * ?>
922
- * </code>
923
- *
924
- * @param Math_BigInteger $y
925
- * @return Math_BigInteger
926
- * @access public
927
- * @internal Performs base-2**52 subtraction
928
- */
929
- function subtract($y)
930
- {
931
- switch ( MATH_BIGINTEGER_MODE ) {
932
- case MATH_BIGINTEGER_MODE_GMP:
933
- $temp = new Math_BigInteger();
934
- $temp->value = gmp_sub($this->value, $y->value);
935
-
936
- return $this->_normalize($temp);
937
- case MATH_BIGINTEGER_MODE_BCMATH:
938
- $temp = new Math_BigInteger();
939
- $temp->value = bcsub($this->value, $y->value, 0);
940
-
941
- return $this->_normalize($temp);
942
- }
943
-
944
- $temp = $this->_subtract($this->value, $this->is_negative, $y->value, $y->is_negative);
945
-
946
- $result = new Math_BigInteger();
947
- $result->value = $temp[MATH_BIGINTEGER_VALUE];
948
- $result->is_negative = $temp[MATH_BIGINTEGER_SIGN];
949
-
950
- return $this->_normalize($result);
951
- }
952
-
953
- /**
954
- * Performs subtraction.
955
- *
956
- * @param Array $x_value
957
- * @param Boolean $x_negative
958
- * @param Array $y_value
959
- * @param Boolean $y_negative
960
- * @return Array
961
- * @access private
962
- */
963
- function _subtract($x_value, $x_negative, $y_value, $y_negative)
964
- {
965
- $x_size = count($x_value);
966
- $y_size = count($y_value);
967
-
968
- if ($x_size == 0) {
969
- return array(
970
- MATH_BIGINTEGER_VALUE => $y_value,
971
- MATH_BIGINTEGER_SIGN => !$y_negative
972
- );
973
- } else if ($y_size == 0) {
974
- return array(
975
- MATH_BIGINTEGER_VALUE => $x_value,
976
- MATH_BIGINTEGER_SIGN => $x_negative
977
- );
978
- }
979
-
980
- // add, if appropriate (ie. -$x - +$y or +$x - -$y)
981
- if ( $x_negative != $y_negative ) {
982
- $temp = $this->_add($x_value, false, $y_value, false);
983
- $temp[MATH_BIGINTEGER_SIGN] = $x_negative;
984
-
985
- return $temp;
986
- }
987
-
988
- $diff = $this->_compare($x_value, $x_negative, $y_value, $y_negative);
989
-
990
- if ( !$diff ) {
991
- return array(
992
- MATH_BIGINTEGER_VALUE => array(),
993
- MATH_BIGINTEGER_SIGN => false
994
- );
995
- }
996
-
997
- // switch $x and $y around, if appropriate.
998
- if ( (!$x_negative && $diff < 0) || ($x_negative && $diff > 0) ) {
999
- $temp = $x_value;
1000
- $x_value = $y_value;
1001
- $y_value = $temp;
1002
-
1003
- $x_negative = !$x_negative;
1004
-
1005
- $x_size = count($x_value);
1006
- $y_size = count($y_value);
1007
- }
1008
-
1009
- // at this point, $x_value should be at least as big as - if not bigger than - $y_value
1010
-
1011
- $carry = 0;
1012
- for ($i = 0, $j = 1; $j < $y_size; $i+=2, $j+=2) {
1013
- $sum = $x_value[$j] * 0x4000000 + $x_value[$i] - $y_value[$j] * 0x4000000 - $y_value[$i] - $carry;
1014
- $carry = $sum < 0; // eg. floor($sum / 2**52); only possible values (in any base) are 0 and 1
1015
- $sum = $carry ? $sum + MATH_BIGINTEGER_MAX_DIGIT52 : $sum;
1016
-
1017
- $temp = (int) ($sum / 0x4000000);
1018
-
1019
- $x_value[$i] = (int) ($sum - 0x4000000 * $temp);
1020
- $x_value[$j] = $temp;
1021
- }
1022
-
1023
- if ($j == $y_size) { // ie. if $y_size is odd
1024
- $sum = $x_value[$i] - $y_value[$i] - $carry;
1025
- $carry = $sum < 0;
1026
- $x_value[$i] = $carry ? $sum + 0x4000000 : $sum;
1027
- ++$i;
1028
- }
1029
-
1030
- if ($carry) {
1031
- for (; !$x_value[$i]; ++$i) {
1032
- $x_value[$i] = 0x3FFFFFF;
1033
- }
1034
- --$x_value[$i];
1035
- }
1036
-
1037
- return array(
1038
- MATH_BIGINTEGER_VALUE => $this->_trim($x_value),
1039
- MATH_BIGINTEGER_SIGN => $x_negative
1040
- );
1041
- }
1042
-
1043
- /**
1044
- * Multiplies two BigIntegers
1045
- *
1046
- * Here's an example:
1047
- * <code>
1048
- * <?php
1049
- * include('Math/BigInteger.php');
1050
- *
1051
- * $a = new Math_BigInteger('10');
1052
- * $b = new Math_BigInteger('20');
1053
- *
1054
- * $c = $a->multiply($b);
1055
- *
1056
- * echo $c->toString(); // outputs 200
1057
- * ?>
1058
- * </code>
1059
- *
1060
- * @param Math_BigInteger $x
1061
- * @return Math_BigInteger
1062
- * @access public
1063
- */
1064
- function multiply($x)
1065
- {
1066
- switch ( MATH_BIGINTEGER_MODE ) {
1067
- case MATH_BIGINTEGER_MODE_GMP:
1068
- $temp = new Math_BigInteger();
1069
- $temp->value = gmp_mul($this->value, $x->value);
1070
-
1071
- return $this->_normalize($temp);
1072
- case MATH_BIGINTEGER_MODE_BCMATH:
1073
- $temp = new Math_BigInteger();
1074
- $temp->value = bcmul($this->value, $x->value, 0);
1075
-
1076
- return $this->_normalize($temp);
1077
- }
1078
-
1079
- $temp = $this->_multiply($this->value, $this->is_negative, $x->value, $x->is_negative);
1080
-
1081
- $product = new Math_BigInteger();
1082
- $product->value = $temp[MATH_BIGINTEGER_VALUE];
1083
- $product->is_negative = $temp[MATH_BIGINTEGER_SIGN];
1084
-
1085
- return $this->_normalize($product);
1086
- }
1087
-
1088
- /**
1089
- * Performs multiplication.
1090
- *
1091
- * @param Array $x_value
1092
- * @param Boolean $x_negative
1093
- * @param Array $y_value
1094
- * @param Boolean $y_negative
1095
- * @return Array
1096
- * @access private
1097
- */
1098
- function _multiply($x_value, $x_negative, $y_value, $y_negative)
1099
- {
1100
- //if ( $x_value == $y_value ) {
1101
- // return array(
1102
- // MATH_BIGINTEGER_VALUE => $this->_square($x_value),
1103
- // MATH_BIGINTEGER_SIGN => $x_sign != $y_value
1104
- // );
1105
- //}
1106
-
1107
- $x_length = count($x_value);
1108
- $y_length = count($y_value);
1109
-
1110
- if ( !$x_length || !$y_length ) { // a 0 is being multiplied
1111
- return array(
1112
- MATH_BIGINTEGER_VALUE => array(),
1113
- MATH_BIGINTEGER_SIGN => false
1114
- );
1115
- }
1116
-
1117
- return array(
1118
- MATH_BIGINTEGER_VALUE => min($x_length, $y_length) < 2 * MATH_BIGINTEGER_KARATSUBA_CUTOFF ?
1119
- $this->_trim($this->_regularMultiply($x_value, $y_value)) :
1120
- $this->_trim($this->_karatsuba($x_value, $y_value)),
1121
- MATH_BIGINTEGER_SIGN => $x_negative != $y_negative
1122
- );
1123
- }
1124
-
1125
- /**
1126
- * Performs long multiplication on two BigIntegers
1127
- *
1128
- * Modeled after 'multiply' in MutableBigInteger.java.
1129
- *
1130
- * @param Array $x_value
1131
- * @param Array $y_value
1132
- * @return Array
1133
- * @access private
1134
- */
1135
- function _regularMultiply($x_value, $y_value)
1136
- {
1137
- $x_length = count($x_value);
1138
- $y_length = count($y_value);
1139
-
1140
- if ( !$x_length || !$y_length ) { // a 0 is being multiplied
1141
- return array();
1142
- }
1143
-
1144
- if ( $x_length < $y_length ) {
1145
- $temp = $x_value;
1146
- $x_value = $y_value;
1147
- $y_value = $temp;
1148
-
1149
- $x_length = count($x_value);
1150
- $y_length = count($y_value);
1151
- }
1152
-
1153
- $product_value = $this->_array_repeat(0, $x_length + $y_length);
1154
-
1155
- // the following for loop could be removed if the for loop following it
1156
- // (the one with nested for loops) initially set $i to 0, but
1157
- // doing so would also make the result in one set of unnecessary adds,
1158
- // since on the outermost loops first pass, $product->value[$k] is going
1159
- // to always be 0
1160
-
1161
- $carry = 0;
1162
-
1163
- for ($j = 0; $j < $x_length; ++$j) { // ie. $i = 0
1164
- $temp = $x_value[$j] * $y_value[0] + $carry; // $product_value[$k] == 0
1165
- $carry = (int) ($temp / 0x4000000);
1166
- $product_value[$j] = (int) ($temp - 0x4000000 * $carry);
1167
- }
1168
-
1169
- $product_value[$j] = $carry;
1170
-
1171
- // the above for loop is what the previous comment was talking about. the
1172
- // following for loop is the "one with nested for loops"
1173
- for ($i = 1; $i < $y_length; ++$i) {
1174
- $carry = 0;
1175
-
1176
- for ($j = 0, $k = $i; $j < $x_length; ++$j, ++$k) {
1177
- $temp = $product_value[$k] + $x_value[$j] * $y_value[$i] + $carry;
1178
- $carry = (int) ($temp / 0x4000000);
1179
- $product_value[$k] = (int) ($temp - 0x4000000 * $carry);
1180
- }
1181
-
1182
- $product_value[$k] = $carry;
1183
- }
1184
-
1185
- return $product_value;
1186
- }
1187
-
1188
- /**
1189
- * Performs Karatsuba multiplication on two BigIntegers
1190
- *
1191
- * See {@link http://en.wikipedia.org/wiki/Karatsuba_algorithm Karatsuba algorithm} and
1192
- * {@link http://math.libtomcrypt.com/files/tommath.pdf#page=120 MPM 5.2.3}.
1193
- *
1194
- * @param Array $x_value
1195
- * @param Array $y_value
1196
- * @return Array
1197
- * @access private
1198
- */
1199
- function _karatsuba($x_value, $y_value)
1200
- {
1201
- $m = min(count($x_value) >> 1, count($y_value) >> 1);
1202
-
1203
- if ($m < MATH_BIGINTEGER_KARATSUBA_CUTOFF) {
1204
- return $this->_regularMultiply($x_value, $y_value);
1205
- }
1206
-
1207
- $x1 = array_slice($x_value, $m);
1208
- $x0 = array_slice($x_value, 0, $m);
1209
- $y1 = array_slice($y_value, $m);
1210
- $y0 = array_slice($y_value, 0, $m);
1211
-
1212
- $z2 = $this->_karatsuba($x1, $y1);
1213
- $z0 = $this->_karatsuba($x0, $y0);
1214
-
1215
- $z1 = $this->_add($x1, false, $x0, false);
1216
- $temp = $this->_add($y1, false, $y0, false);
1217
- $z1 = $this->_karatsuba($z1[MATH_BIGINTEGER_VALUE], $temp[MATH_BIGINTEGER_VALUE]);
1218
- $temp = $this->_add($z2, false, $z0, false);
1219
- $z1 = $this->_subtract($z1, false, $temp[MATH_BIGINTEGER_VALUE], false);
1220
-
1221
- $z2 = array_merge(array_fill(0, 2 * $m, 0), $z2);
1222
- $z1[MATH_BIGINTEGER_VALUE] = array_merge(array_fill(0, $m, 0), $z1[MATH_BIGINTEGER_VALUE]);
1223
-
1224
- $xy = $this->_add($z2, false, $z1[MATH_BIGINTEGER_VALUE], $z1[MATH_BIGINTEGER_SIGN]);
1225
- $xy = $this->_add($xy[MATH_BIGINTEGER_VALUE], $xy[MATH_BIGINTEGER_SIGN], $z0, false);
1226
-
1227
- return $xy[MATH_BIGINTEGER_VALUE];
1228
- }
1229
-
1230
- /**
1231
- * Performs squaring
1232
- *
1233
- * @param Array $x
1234
- * @return Array
1235
- * @access private
1236
- */
1237
- function _square($x = false)
1238
- {
1239
- return count($x) < 2 * MATH_BIGINTEGER_KARATSUBA_CUTOFF ?
1240
- $this->_trim($this->_baseSquare($x)) :
1241
- $this->_trim($this->_karatsubaSquare($x));
1242
- }
1243
-
1244
- /**
1245
- * Performs traditional squaring on two BigIntegers
1246
- *
1247
- * Squaring can be done faster than multiplying a number by itself can be. See
1248
- * {@link http://www.cacr.math.uwaterloo.ca/hac/about/chap14.pdf#page=7 HAC 14.2.4} /
1249
- * {@link http://math.libtomcrypt.com/files/tommath.pdf#page=141 MPM 5.3} for more information.
1250
- *
1251
- * @param Array $value
1252
- * @return Array
1253
- * @access private
1254
- */
1255
- function _baseSquare($value)
1256
- {
1257
- if ( empty($value) ) {
1258
- return array();
1259
- }
1260
- $square_value = $this->_array_repeat(0, 2 * count($value));
1261
-
1262
- for ($i = 0, $max_index = count($value) - 1; $i <= $max_index; ++$i) {
1263
- $i2 = $i << 1;
1264
-
1265
- $temp = $square_value[$i2] + $value[$i] * $value[$i];
1266
- $carry = (int) ($temp / 0x4000000);
1267
- $square_value[$i2] = (int) ($temp - 0x4000000 * $carry);
1268
-
1269
- // note how we start from $i+1 instead of 0 as we do in multiplication.
1270
- for ($j = $i + 1, $k = $i2 + 1; $j <= $max_index; ++$j, ++$k) {
1271
- $temp = $square_value[$k] + 2 * $value[$j] * $value[$i] + $carry;
1272
- $carry = (int) ($temp / 0x4000000);
1273
- $square_value[$k] = (int) ($temp - 0x4000000 * $carry);
1274
- }
1275
-
1276
- // the following line can yield values larger 2**15. at this point, PHP should switch
1277
- // over to floats.
1278
- $square_value[$i + $max_index + 1] = $carry;
1279
- }
1280
-
1281
- return $square_value;
1282
- }
1283
-
1284
- /**
1285
- * Performs Karatsuba "squaring" on two BigIntegers
1286
- *
1287
- * See {@link http://en.wikipedia.org/wiki/Karatsuba_algorithm Karatsuba algorithm} and
1288
- * {@link http://math.libtomcrypt.com/files/tommath.pdf#page=151 MPM 5.3.4}.
1289
- *
1290
- * @param Array $value
1291
- * @return Array
1292
- * @access private
1293
- */
1294
- function _karatsubaSquare($value)
1295
- {
1296
- $m = count($value) >> 1;
1297
-
1298
- if ($m < MATH_BIGINTEGER_KARATSUBA_CUTOFF) {
1299
- return $this->_baseSquare($value);
1300
- }
1301
-
1302
- $x1 = array_slice($value, $m);
1303
- $x0 = array_slice($value, 0, $m);
1304
-
1305
- $z2 = $this->_karatsubaSquare($x1);
1306
- $z0 = $this->_karatsubaSquare($x0);
1307
-
1308
- $z1 = $this->_add($x1, false, $x0, false);
1309
- $z1 = $this->_karatsubaSquare($z1[MATH_BIGINTEGER_VALUE]);
1310
- $temp = $this->_add($z2, false, $z0, false);
1311
- $z1 = $this->_subtract($z1, false, $temp[MATH_BIGINTEGER_VALUE], false);
1312
-
1313
- $z2 = array_merge(array_fill(0, 2 * $m, 0), $z2);
1314
- $z1[MATH_BIGINTEGER_VALUE] = array_merge(array_fill(0, $m, 0), $z1[MATH_BIGINTEGER_VALUE]);
1315
-
1316
- $xx = $this->_add($z2, false, $z1[MATH_BIGINTEGER_VALUE], $z1[MATH_BIGINTEGER_SIGN]);
1317
- $xx = $this->_add($xx[MATH_BIGINTEGER_VALUE], $xx[MATH_BIGINTEGER_SIGN], $z0, false);
1318
-
1319
- return $xx[MATH_BIGINTEGER_VALUE];
1320
- }
1321
-
1322
- /**
1323
- * Divides two BigIntegers.
1324
- *
1325
- * Returns an array whose first element contains the quotient and whose second element contains the
1326
- * "common residue". If the remainder would be positive, the "common residue" and the remainder are the
1327
- * same. If the remainder would be negative, the "common residue" is equal to the sum of the remainder
1328
- * and the divisor (basically, the "common residue" is the first positive modulo).
1329
- *
1330
- * Here's an example:
1331
- * <code>
1332
- * <?php
1333
- * include('Math/BigInteger.php');
1334
- *
1335
- * $a = new Math_BigInteger('10');
1336
- * $b = new Math_BigInteger('20');
1337
- *
1338
- * list($quotient, $remainder) = $a->divide($b);
1339
- *
1340
- * echo $quotient->toString(); // outputs 0
1341
- * echo "\r\n";
1342
- * echo $remainder->toString(); // outputs 10
1343
- * ?>
1344
- * </code>
1345
- *
1346
- * @param Math_BigInteger $y
1347
- * @return Array
1348
- * @access public
1349
- * @internal This function is based off of {@link http://www.cacr.math.uwaterloo.ca/hac/about/chap14.pdf#page=9 HAC 14.20}.
1350
- */
1351
- function divide($y)
1352
- {
1353
- switch ( MATH_BIGINTEGER_MODE ) {
1354
- case MATH_BIGINTEGER_MODE_GMP:
1355
- $quotient = new Math_BigInteger();
1356
- $remainder = new Math_BigInteger();
1357
-
1358
- list($quotient->value, $remainder->value) = gmp_div_qr($this->value, $y->value);
1359
-
1360
- if (gmp_sign($remainder->value) < 0) {
1361
- $remainder->value = gmp_add($remainder->value, gmp_abs($y->value));
1362
- }
1363
-
1364
- return array($this->_normalize($quotient), $this->_normalize($remainder));
1365
- case MATH_BIGINTEGER_MODE_BCMATH:
1366
- $quotient = new Math_BigInteger();
1367
- $remainder = new Math_BigInteger();
1368
-
1369
- $quotient->value = bcdiv($this->value, $y->value, 0);
1370
- $remainder->value = bcmod($this->value, $y->value);
1371
-
1372
- if ($remainder->value[0] == '-') {
1373
- $remainder->value = bcadd($remainder->value, $y->value[0] == '-' ? substr($y->value, 1) : $y->value, 0);
1374
- }
1375
-
1376
- return array($this->_normalize($quotient), $this->_normalize($remainder));
1377
- }
1378
-
1379
- if (count($y->value) == 1) {
1380
- list($q, $r) = $this->_divide_digit($this->value, $y->value[0]);
1381
- $quotient = new Math_BigInteger();
1382
- $remainder = new Math_BigInteger();
1383
- $quotient->value = $q;
1384
- $remainder->value = array($r);
1385
- $quotient->is_negative = $this->is_negative != $y->is_negative;
1386
- return array($this->_normalize($quotient), $this->_normalize($remainder));
1387
- }
1388
-
1389
- static $zero;
1390
- if ( !isset($zero) ) {
1391
- $zero = new Math_BigInteger();
1392
- }
1393
-
1394
- $x = $this->copy();
1395
- $y = $y->copy();
1396
-
1397
- $x_sign = $x->is_negative;
1398
- $y_sign = $y->is_negative;
1399
-
1400
- $x->is_negative = $y->is_negative = false;
1401
-
1402
- $diff = $x->compare($y);
1403
-
1404
- if ( !$diff ) {
1405
- $temp = new Math_BigInteger();
1406
- $temp->value = array(1);
1407
- $temp->is_negative = $x_sign != $y_sign;
1408
- return array($this->_normalize($temp), $this->_normalize(new Math_BigInteger()));
1409
- }
1410
-
1411
- if ( $diff < 0 ) {
1412
- // if $x is negative, "add" $y.
1413
- if ( $x_sign ) {
1414
- $x = $y->subtract($x);
1415
- }
1416
- return array($this->_normalize(new Math_BigInteger()), $this->_normalize($x));
1417
- }
1418
-
1419
- // normalize $x and $y as described in HAC 14.23 / 14.24
1420
- $msb = $y->value[count($y->value) - 1];
1421
- for ($shift = 0; !($msb & 0x2000000); ++$shift) {
1422
- $msb <<= 1;
1423
- }
1424
- $x->_lshift($shift);
1425
- $y->_lshift($shift);
1426
- $y_value = &$y->value;
1427
-
1428
- $x_max = count($x->value) - 1;
1429
- $y_max = count($y->value) - 1;
1430
-
1431
- $quotient = new Math_BigInteger();
1432
- $quotient_value = &$quotient->value;
1433
- $quotient_value = $this->_array_repeat(0, $x_max - $y_max + 1);
1434
-
1435
- static $temp, $lhs, $rhs;
1436
- if (!isset($temp)) {
1437
- $temp = new Math_BigInteger();
1438
- $lhs = new Math_BigInteger();
1439
- $rhs = new Math_BigInteger();
1440
- }
1441
- $temp_value = &$temp->value;
1442
- $rhs_value = &$rhs->value;
1443
-
1444
- // $temp = $y << ($x_max - $y_max-1) in base 2**26
1445
- $temp_value = array_merge($this->_array_repeat(0, $x_max - $y_max), $y_value);
1446
-
1447
- while ( $x->compare($temp) >= 0 ) {
1448
- // calculate the "common residue"
1449
- ++$quotient_value[$x_max - $y_max];
1450
- $x = $x->subtract($temp);
1451
- $x_max = count($x->value) - 1;
1452
- }
1453
-
1454
- for ($i = $x_max; $i >= $y_max + 1; --$i) {
1455
- $x_value = &$x->value;
1456
- $x_window = array(
1457
- isset($x_value[$i]) ? $x_value[$i] : 0,
1458
- isset($x_value[$i - 1]) ? $x_value[$i - 1] : 0,
1459
- isset($x_value[$i - 2]) ? $x_value[$i - 2] : 0
1460
- );
1461
- $y_window = array(
1462
- $y_value[$y_max],
1463
- ( $y_max > 0 ) ? $y_value[$y_max - 1] : 0
1464
- );
1465
-
1466
- $q_index = $i - $y_max - 1;
1467
- if ($x_window[0] == $y_window[0]) {
1468
- $quotient_value[$q_index] = 0x3FFFFFF;
1469
- } else {
1470
- $quotient_value[$q_index] = (int) (
1471
- ($x_window[0] * 0x4000000 + $x_window[1])
1472
- /
1473
- $y_window[0]
1474
- );
1475
- }
1476
-
1477
- $temp_value = array($y_window[1], $y_window[0]);
1478
-
1479
- $lhs->value = array($quotient_value[$q_index]);
1480
- $lhs = $lhs->multiply($temp);
1481
-
1482
- $rhs_value = array($x_window[2], $x_window[1], $x_window[0]);
1483
-
1484
- while ( $lhs->compare($rhs) > 0 ) {
1485
- --$quotient_value[$q_index];
1486
-
1487
- $lhs->value = array($quotient_value[$q_index]);
1488
- $lhs = $lhs->multiply($temp);
1489
- }
1490
-
1491
- $adjust = $this->_array_repeat(0, $q_index);
1492
- $temp_value = array($quotient_value[$q_index]);
1493
- $temp = $temp->multiply($y);
1494
- $temp_value = &$temp->value;
1495
- $temp_value = array_merge($adjust, $temp_value);
1496
-
1497
- $x = $x->subtract($temp);
1498
-
1499
- if ($x->compare($zero) < 0) {
1500
- $temp_value = array_merge($adjust, $y_value);
1501
- $x = $x->add($temp);
1502
-
1503
- --$quotient_value[$q_index];
1504
- }
1505
-
1506
- $x_max = count($x_value) - 1;
1507
- }
1508
-
1509
- // unnormalize the remainder
1510
- $x->_rshift($shift);
1511
-
1512
- $quotient->is_negative = $x_sign != $y_sign;
1513
-
1514
- // calculate the "common residue", if appropriate
1515
- if ( $x_sign ) {
1516
- $y->_rshift($shift);
1517
- $x = $y->subtract($x);
1518
- }
1519
-
1520
- return array($this->_normalize($quotient), $this->_normalize($x));
1521
- }
1522
-
1523
- /**
1524
- * Divides a BigInteger by a regular integer
1525
- *
1526
- * abc / x = a00 / x + b0 / x + c / x
1527
- *
1528
- * @param Array $dividend
1529
- * @param Array $divisor
1530
- * @return Array
1531
- * @access private
1532
- */
1533
- function _divide_digit($dividend, $divisor)
1534
- {
1535
- $carry = 0;
1536
- $result = array();
1537
-
1538
- for ($i = count($dividend) - 1; $i >= 0; --$i) {
1539
- $temp = 0x4000000 * $carry + $dividend[$i];
1540
- $result[$i] = (int) ($temp / $divisor);
1541
- $carry = (int) ($temp - $divisor * $result[$i]);
1542
- }
1543
-
1544
- return array($result, $carry);
1545
- }
1546
-
1547
- /**
1548
- * Performs modular exponentiation.
1549
- *
1550
- * Here's an example:
1551
- * <code>
1552
- * <?php
1553
- * include('Math/BigInteger.php');
1554
- *
1555
- * $a = new Math_BigInteger('10');
1556
- * $b = new Math_BigInteger('20');
1557
- * $c = new Math_BigInteger('30');
1558
- *
1559
- * $c = $a->modPow($b, $c);
1560
- *
1561
- * echo $c->toString(); // outputs 10
1562
- * ?>
1563
- * </code>
1564
- *
1565
- * @param Math_BigInteger $e
1566
- * @param Math_BigInteger $n
1567
- * @return Math_BigInteger
1568
- * @access public
1569
- * @internal The most naive approach to modular exponentiation has very unreasonable requirements, and
1570
- * and although the approach involving repeated squaring does vastly better, it, too, is impractical
1571
- * for our purposes. The reason being that division - by far the most complicated and time-consuming
1572
- * of the basic operations (eg. +,-,*,/) - occurs multiple times within it.
1573
- *
1574
- * Modular reductions resolve this issue. Although an individual modular reduction takes more time
1575
- * then an individual division, when performed in succession (with the same modulo), they're a lot faster.
1576
- *
1577
- * The two most commonly used modular reductions are Barrett and Montgomery reduction. Montgomery reduction,
1578
- * although faster, only works when the gcd of the modulo and of the base being used is 1. In RSA, when the
1579
- * base is a power of two, the modulo - a product of two primes - is always going to have a gcd of 1 (because
1580
- * the product of two odd numbers is odd), but what about when RSA isn't used?
1581
- *
1582
- * In contrast, Barrett reduction has no such constraint. As such, some bigint implementations perform a
1583
- * Barrett reduction after every operation in the modpow function. Others perform Barrett reductions when the
1584
- * modulo is even and Montgomery reductions when the modulo is odd. BigInteger.java's modPow method, however,
1585
- * uses a trick involving the Chinese Remainder Theorem to factor the even modulo into two numbers - one odd and
1586
- * the other, a power of two - and recombine them, later. This is the method that this modPow function uses.
1587
- * {@link http://islab.oregonstate.edu/papers/j34monex.pdf Montgomery Reduction with Even Modulus} elaborates.
1588
- */
1589
- function modPow($e, $n)
1590
- {
1591
- $n = $this->bitmask !== false && $this->bitmask->compare($n) < 0 ? $this->bitmask : $n->abs();
1592
-
1593
- if ($e->compare(new Math_BigInteger()) < 0) {
1594
- $e = $e->abs();
1595
-
1596
- $temp = $this->modInverse($n);
1597
- if ($temp === false) {
1598
- return false;
1599
- }
1600
-
1601
- return $this->_normalize($temp->modPow($e, $n));
1602
- }
1603
-
1604
- if ( MATH_BIGINTEGER_MODE == MATH_BIGINTEGER_MODE_GMP ) {
1605
- $temp = new Math_BigInteger();
1606
- $temp->value = gmp_powm($this->value, $e->value, $n->value);
1607
-
1608
- return $this->_normalize($temp);
1609
- }
1610
-
1611
- if ($this->compare(new Math_BigInteger()) < 0 || $this->compare($n) > 0) {
1612
- list(, $temp) = $this->divide($n);
1613
- return $temp->modPow($e, $n);
1614
- }
1615
-
1616
- if (defined('MATH_BIGINTEGER_OPENSSL_ENABLED')) {
1617
- $components = array(
1618
- 'modulus' => $n->toBytes(true),
1619
- 'publicExponent' => $e->toBytes(true)
1620
- );
1621
-
1622
- $components = array(
1623
- 'modulus' => pack('Ca*a*', 2, $this->_encodeASN1Length(strlen($components['modulus'])), $components['modulus']),
1624
- 'publicExponent' => pack('Ca*a*', 2, $this->_encodeASN1Length(strlen($components['publicExponent'])), $components['publicExponent'])
1625
- );
1626
-
1627
- $RSAPublicKey = pack('Ca*a*a*',
1628
- 48, $this->_encodeASN1Length(strlen($components['modulus']) + strlen($components['publicExponent'])),
1629
- $components['modulus'], $components['publicExponent']
1630
- );
1631
-
1632
- $rsaOID = pack('H*', '300d06092a864886f70d0101010500'); // hex version of MA0GCSqGSIb3DQEBAQUA
1633
- $RSAPublicKey = chr(0) . $RSAPublicKey;
1634
- $RSAPublicKey = chr(3) . $this->_encodeASN1Length(strlen($RSAPublicKey)) . $RSAPublicKey;
1635
-
1636
- $encapsulated = pack('Ca*a*',
1637
- 48, $this->_encodeASN1Length(strlen($rsaOID . $RSAPublicKey)), $rsaOID . $RSAPublicKey
1638
- );
1639
-
1640
- $RSAPublicKey = "-----BEGIN PUBLIC KEY-----\r\n" .
1641
- chunk_split(base64_encode($encapsulated)) .
1642
- '-----END PUBLIC KEY-----';
1643
-
1644
- $plaintext = str_pad($this->toBytes(), strlen($n->toBytes(true)) - 1, "\0", STR_PAD_LEFT);
1645
-
1646
- if (openssl_public_encrypt($plaintext, $result, $RSAPublicKey, OPENSSL_NO_PADDING)) {
1647
- return new Math_BigInteger($result, 256);
1648
- }
1649
- }
1650
-
1651
- if ( MATH_BIGINTEGER_MODE == MATH_BIGINTEGER_MODE_BCMATH ) {
1652
- $temp = new Math_BigInteger();
1653
- $temp->value = bcpowmod($this->value, $e->value, $n->value, 0);
1654
-
1655
- return $this->_normalize($temp);
1656
- }
1657
-
1658
- if ( empty($e->value) ) {
1659
- $temp = new Math_BigInteger();
1660
- $temp->value = array(1);
1661
- return $this->_normalize($temp);
1662
- }
1663
-
1664
- if ( $e->value == array(1) ) {
1665
- list(, $temp) = $this->divide($n);
1666
- return $this->_normalize($temp);
1667
- }
1668
-
1669
- if ( $e->value == array(2) ) {
1670
- $temp = new Math_BigInteger();
1671
- $temp->value = $this->_square($this->value);
1672
- list(, $temp) = $temp->divide($n);
1673
- return $this->_normalize($temp);
1674
- }
1675
-
1676
- return $this->_normalize($this->_slidingWindow($e, $n, MATH_BIGINTEGER_BARRETT));
1677
-
1678
- // is the modulo odd?
1679
- if ( $n->value[0] & 1 ) {
1680
- return $this->_normalize($this->_slidingWindow($e, $n, MATH_BIGINTEGER_MONTGOMERY));
1681
- }
1682
- // if it's not, it's even
1683
-
1684
- // find the lowest set bit (eg. the max pow of 2 that divides $n)
1685
- for ($i = 0; $i < count($n->value); ++$i) {
1686
- if ( $n->value[$i] ) {
1687
- $temp = decbin($n->value[$i]);
1688
- $j = strlen($temp) - strrpos($temp, '1') - 1;
1689
- $j+= 26 * $i;
1690
- break;
1691
- }
1692
- }
1693
- // at this point, 2^$j * $n/(2^$j) == $n
1694
-
1695
- $mod1 = $n->copy();
1696
- $mod1->_rshift($j);
1697
- $mod2 = new Math_BigInteger();
1698
- $mod2->value = array(1);
1699
- $mod2->_lshift($j);
1700
-
1701
- $part1 = ( $mod1->value != array(1) ) ? $this->_slidingWindow($e, $mod1, MATH_BIGINTEGER_MONTGOMERY) : new Math_BigInteger();
1702
- $part2 = $this->_slidingWindow($e, $mod2, MATH_BIGINTEGER_POWEROF2);
1703
-
1704
- $y1 = $mod2->modInverse($mod1);
1705
- $y2 = $mod1->modInverse($mod2);
1706
-
1707
- $result = $part1->multiply($mod2);
1708
- $result = $result->multiply($y1);
1709
-
1710
- $temp = $part2->multiply($mod1);
1711
- $temp = $temp->multiply($y2);
1712
-
1713
- $result = $result->add($temp);
1714
- list(, $result) = $result->divide($n);
1715
-
1716
- return $this->_normalize($result);
1717
- }
1718
-
1719
- /**
1720
- * Performs modular exponentiation.
1721
- *
1722
- * Alias for Math_BigInteger::modPow()
1723
- *
1724
- * @param Math_BigInteger $e
1725
- * @param Math_BigInteger $n
1726
- * @return Math_BigInteger
1727
- * @access public
1728
- */
1729
- function powMod($e, $n)
1730
- {
1731
- return $this->modPow($e, $n);
1732
- }
1733
-
1734
- /**
1735
- * Sliding Window k-ary Modular Exponentiation
1736
- *
1737
- * Based on {@link http://www.cacr.math.uwaterloo.ca/hac/about/chap14.pdf#page=27 HAC 14.85} /
1738
- * {@link http://math.libtomcrypt.com/files/tommath.pdf#page=210 MPM 7.7}. In a departure from those algorithims,
1739
- * however, this function performs a modular reduction after every multiplication and squaring operation.
1740
- * As such, this function has the same preconditions that the reductions being used do.
1741
- *
1742
- * @param Math_BigInteger $e
1743
- * @param Math_BigInteger $n
1744
- * @param Integer $mode
1745
- * @return Math_BigInteger
1746
- * @access private
1747
- */
1748
- function _slidingWindow($e, $n, $mode)
1749
- {
1750
- static $window_ranges = array(7, 25, 81, 241, 673, 1793); // from BigInteger.java's oddModPow function
1751
- //static $window_ranges = array(0, 7, 36, 140, 450, 1303, 3529); // from MPM 7.3.1
1752
-
1753
- $e_value = $e->value;
1754
- $e_length = count($e_value) - 1;
1755
- $e_bits = decbin($e_value[$e_length]);
1756
- for ($i = $e_length - 1; $i >= 0; --$i) {
1757
- $e_bits.= str_pad(decbin($e_value[$i]), 26, '0', STR_PAD_LEFT);
1758
- }
1759
-
1760
- $e_length = strlen($e_bits);
1761
-
1762
- // calculate the appropriate window size.
1763
- // $window_size == 3 if $window_ranges is between 25 and 81, for example.
1764
- for ($i = 0, $window_size = 1; $e_length > $window_ranges[$i] && $i < count($window_ranges); ++$window_size, ++$i);
1765
-
1766
- $n_value = $n->value;
1767
-
1768
- // precompute $this^0 through $this^$window_size
1769
- $powers = array();
1770
- $powers[1] = $this->_prepareReduce($this->value, $n_value, $mode);
1771
- $powers[2] = $this->_squareReduce($powers[1], $n_value, $mode);
1772
-
1773
- // we do every other number since substr($e_bits, $i, $j+1) (see below) is supposed to end
1774
- // in a 1. ie. it's supposed to be odd.
1775
- $temp = 1 << ($window_size - 1);
1776
- for ($i = 1; $i < $temp; ++$i) {
1777
- $i2 = $i << 1;
1778
- $powers[$i2 + 1] = $this->_multiplyReduce($powers[$i2 - 1], $powers[2], $n_value, $mode);
1779
- }
1780
-
1781
- $result = array(1);
1782
- $result = $this->_prepareReduce($result, $n_value, $mode);
1783
-
1784
- for ($i = 0; $i < $e_length; ) {
1785
- if ( !$e_bits[$i] ) {
1786
- $result = $this->_squareReduce($result, $n_value, $mode);
1787
- ++$i;
1788
- } else {
1789
- for ($j = $window_size - 1; $j > 0; --$j) {
1790
- if ( !empty($e_bits[$i + $j]) ) {
1791
- break;
1792
- }
1793
- }
1794
-
1795
- for ($k = 0; $k <= $j; ++$k) {// eg. the length of substr($e_bits, $i, $j+1)
1796
- $result = $this->_squareReduce($result, $n_value, $mode);
1797
- }
1798
-
1799
- $result = $this->_multiplyReduce($result, $powers[bindec(substr($e_bits, $i, $j + 1))], $n_value, $mode);
1800
-
1801
- $i+=$j + 1;
1802
- }
1803
- }
1804
-
1805
- $temp = new Math_BigInteger();
1806
- $temp->value = $this->_reduce($result, $n_value, $mode);
1807
-
1808
- return $temp;
1809
- }
1810
-
1811
- /**
1812
- * Modular reduction
1813
- *
1814
- * For most $modes this will return the remainder.
1815
- *
1816
- * @see _slidingWindow()
1817
- * @access private
1818
- * @param Array $x
1819
- * @param Array $n
1820
- * @param Integer $mode
1821
- * @return Array
1822
- */
1823
- function _reduce($x, $n, $mode)
1824
- {
1825
- switch ($mode) {
1826
- case MATH_BIGINTEGER_MONTGOMERY:
1827
- return $this->_montgomery($x, $n);
1828
- case MATH_BIGINTEGER_BARRETT:
1829
- return $this->_barrett($x, $n);
1830
- case MATH_BIGINTEGER_POWEROF2:
1831
- $lhs = new Math_BigInteger();
1832
- $lhs->value = $x;
1833
- $rhs = new Math_BigInteger();
1834
- $rhs->value = $n;
1835
- return $x->_mod2($n);
1836
- case MATH_BIGINTEGER_CLASSIC:
1837
- $lhs = new Math_BigInteger();
1838
- $lhs->value = $x;
1839
- $rhs = new Math_BigInteger();
1840
- $rhs->value = $n;
1841
- list(, $temp) = $lhs->divide($rhs);
1842
- return $temp->value;
1843
- case MATH_BIGINTEGER_NONE:
1844
- return $x;
1845
- default:
1846
- // an invalid $mode was provided
1847
- }
1848
- }
1849
-
1850
- /**
1851
- * Modular reduction preperation
1852
- *
1853
- * @see _slidingWindow()
1854
- * @access private
1855
- * @param Array $x
1856
- * @param Array $n
1857
- * @param Integer $mode
1858
- * @return Array
1859
- */
1860
- function _prepareReduce($x, $n, $mode)
1861
- {
1862
- if ($mode == MATH_BIGINTEGER_MONTGOMERY) {
1863
- return $this->_prepMontgomery($x, $n);
1864
- }
1865
- return $this->_reduce($x, $n, $mode);
1866
- }
1867
-
1868
- /**
1869
- * Modular multiply
1870
- *
1871
- * @see _slidingWindow()
1872
- * @access private
1873
- * @param Array $x
1874
- * @param Array $y
1875
- * @param Array $n
1876
- * @param Integer $mode
1877
- * @return Array
1878
- */
1879
- function _multiplyReduce($x, $y, $n, $mode)
1880
- {
1881
- if ($mode == MATH_BIGINTEGER_MONTGOMERY) {
1882
- return $this->_montgomeryMultiply($x, $y, $n);
1883
- }
1884
- $temp = $this->_multiply($x, false, $y, false);
1885
- return $this->_reduce($temp[MATH_BIGINTEGER_VALUE], $n, $mode);
1886
- }
1887
-
1888
- /**
1889
- * Modular square
1890
- *
1891
- * @see _slidingWindow()
1892
- * @access private
1893
- * @param Array $x
1894
- * @param Array $n
1895
- * @param Integer $mode
1896
- * @return Array
1897
- */
1898
- function _squareReduce($x, $n, $mode)
1899
- {
1900
- if ($mode == MATH_BIGINTEGER_MONTGOMERY) {
1901
- return $this->_montgomeryMultiply($x, $x, $n);
1902
- }
1903
- return $this->_reduce($this->_square($x), $n, $mode);
1904
- }
1905
-
1906
- /**
1907
- * Modulos for Powers of Two
1908
- *
1909
- * Calculates $x%$n, where $n = 2**$e, for some $e. Since this is basically the same as doing $x & ($n-1),
1910
- * we'll just use this function as a wrapper for doing that.
1911
- *
1912
- * @see _slidingWindow()
1913
- * @access private
1914
- * @param Math_BigInteger
1915
- * @return Math_BigInteger
1916
- */
1917
- function _mod2($n)
1918
- {
1919
- $temp = new Math_BigInteger();
1920
- $temp->value = array(1);
1921
- return $this->bitwise_and($n->subtract($temp));
1922
- }
1923
-
1924
- /**
1925
- * Barrett Modular Reduction
1926
- *
1927
- * See {@link http://www.cacr.math.uwaterloo.ca/hac/about/chap14.pdf#page=14 HAC 14.3.3} /
1928
- * {@link http://math.libtomcrypt.com/files/tommath.pdf#page=165 MPM 6.2.5} for more information. Modified slightly,
1929
- * so as not to require negative numbers (initially, this script didn't support negative numbers).
1930
- *
1931
- * Employs "folding", as described at
1932
- * {@link http://www.cosic.esat.kuleuven.be/publications/thesis-149.pdf#page=66 thesis-149.pdf#page=66}. To quote from
1933
- * it, "the idea [behind folding] is to find a value x' such that x (mod m) = x' (mod m), with x' being smaller than x."
1934
- *
1935
- * Unfortunately, the "Barrett Reduction with Folding" algorithm described in thesis-149.pdf is not, as written, all that
1936
- * usable on account of (1) its not using reasonable radix points as discussed in
1937
- * {@link http://math.libtomcrypt.com/files/tommath.pdf#page=162 MPM 6.2.2} and (2) the fact that, even with reasonable
1938
- * radix points, it only works when there are an even number of digits in the denominator. The reason for (2) is that
1939
- * (x >> 1) + (x >> 1) != x / 2 + x / 2. If x is even, they're the same, but if x is odd, they're not. See the in-line
1940
- * comments for details.
1941
- *
1942
- * @see _slidingWindow()
1943
- * @access private
1944
- * @param Array $n
1945
- * @param Array $m
1946
- * @return Array
1947
- */
1948
- function _barrett($n, $m)
1949
- {
1950
- static $cache = array(
1951
- MATH_BIGINTEGER_VARIABLE => array(),
1952
- MATH_BIGINTEGER_DATA => array()
1953
- );
1954
-
1955
- $m_length = count($m);
1956
-
1957
- // if ($this->_compare($n, $this->_square($m)) >= 0) {
1958
- if (count($n) > 2 * $m_length) {
1959
- $lhs = new Math_BigInteger();
1960
- $rhs = new Math_BigInteger();
1961
- $lhs->value = $n;
1962
- $rhs->value = $m;
1963
- list(, $temp) = $lhs->divide($rhs);
1964
- return $temp->value;
1965
- }
1966
-
1967
- // if (m.length >> 1) + 2 <= m.length then m is too small and n can't be reduced
1968
- if ($m_length < 5) {
1969
- return $this->_regularBarrett($n, $m);
1970
- }
1971
-
1972
- // n = 2 * m.length
1973
-
1974
- if ( ($key = array_search($m, $cache[MATH_BIGINTEGER_VARIABLE])) === false ) {
1975
- $key = count($cache[MATH_BIGINTEGER_VARIABLE]);
1976
- $cache[MATH_BIGINTEGER_VARIABLE][] = $m;
1977
-
1978
- $lhs = new Math_BigInteger();
1979
- $lhs_value = &$lhs->value;
1980
- $lhs_value = $this->_array_repeat(0, $m_length + ($m_length >> 1));
1981
- $lhs_value[] = 1;
1982
- $rhs = new Math_BigInteger();
1983
- $rhs->value = $m;
1984
-
1985
- list($u, $m1) = $lhs->divide($rhs);
1986
- $u = $u->value;
1987
- $m1 = $m1->value;
1988
-
1989
- $cache[MATH_BIGINTEGER_DATA][] = array(
1990
- 'u' => $u, // m.length >> 1 (technically (m.length >> 1) + 1)
1991
- 'm1'=> $m1 // m.length
1992
- );
1993
- } else {
1994
- extract($cache[MATH_BIGINTEGER_DATA][$key]);
1995
- }
1996
-
1997
- $cutoff = $m_length + ($m_length >> 1);
1998
- $lsd = array_slice($n, 0, $cutoff); // m.length + (m.length >> 1)
1999
- $msd = array_slice($n, $cutoff); // m.length >> 1
2000
- $lsd = $this->_trim($lsd);
2001
- $temp = $this->_multiply($msd, false, $m1, false);
2002
- $n = $this->_add($lsd, false, $temp[MATH_BIGINTEGER_VALUE], false); // m.length + (m.length >> 1) + 1
2003
-
2004
- if ($m_length & 1) {
2005
- return $this->_regularBarrett($n[MATH_BIGINTEGER_VALUE], $m);
2006
- }
2007
-
2008
- // (m.length + (m.length >> 1) + 1) - (m.length - 1) == (m.length >> 1) + 2
2009
- $temp = array_slice($n[MATH_BIGINTEGER_VALUE], $m_length - 1);
2010
- // if even: ((m.length >> 1) + 2) + (m.length >> 1) == m.length + 2
2011
- // if odd: ((m.length >> 1) + 2) + (m.length >> 1) == (m.length - 1) + 2 == m.length + 1
2012
- $temp = $this->_multiply($temp, false, $u, false);
2013
- // if even: (m.length + 2) - ((m.length >> 1) + 1) = m.length - (m.length >> 1) + 1
2014
- // if odd: (m.length + 1) - ((m.length >> 1) + 1) = m.length - (m.length >> 1)
2015
- $temp = array_slice($temp[MATH_BIGINTEGER_VALUE], ($m_length >> 1) + 1);
2016
- // if even: (m.length - (m.length >> 1) + 1) + m.length = 2 * m.length - (m.length >> 1) + 1
2017
- // if odd: (m.length - (m.length >> 1)) + m.length = 2 * m.length - (m.length >> 1)
2018
- $temp = $this->_multiply($temp, false, $m, false);
2019
-
2020
- // at this point, if m had an odd number of digits, we'd be subtracting a 2 * m.length - (m.length >> 1) digit
2021
- // number from a m.length + (m.length >> 1) + 1 digit number. ie. there'd be an extra digit and the while loop
2022
- // following this comment would loop a lot (hence our calling _regularBarrett() in that situation).
2023
-
2024
- $result = $this->_subtract($n[MATH_BIGINTEGER_VALUE], false, $temp[MATH_BIGINTEGER_VALUE], false);
2025
-
2026
- while ($this->_compare($result[MATH_BIGINTEGER_VALUE], $result[MATH_BIGINTEGER_SIGN], $m, false) >= 0) {
2027
- $result = $this->_subtract($result[MATH_BIGINTEGER_VALUE], $result[MATH_BIGINTEGER_SIGN], $m, false);
2028
- }
2029
-
2030
- return $result[MATH_BIGINTEGER_VALUE];
2031
- }
2032
-
2033
- /**
2034
- * (Regular) Barrett Modular Reduction
2035
- *
2036
- * For numbers with more than four digits Math_BigInteger::_barrett() is faster. The difference between that and this
2037
- * is that this function does not fold the denominator into a smaller form.
2038
- *
2039
- * @see _slidingWindow()
2040
- * @access private
2041
- * @param Array $x
2042
- * @param Array $n
2043
- * @return Array
2044
- */
2045
- function _regularBarrett($x, $n)
2046
- {
2047
- static $cache = array(
2048
- MATH_BIGINTEGER_VARIABLE => array(),
2049
- MATH_BIGINTEGER_DATA => array()
2050
- );
2051
-
2052
- $n_length = count($n);
2053
-
2054
- if (count($x) > 2 * $n_length) {
2055
- $lhs = new Math_BigInteger();
2056
- $rhs = new Math_BigInteger();
2057
- $lhs->value = $x;
2058
- $rhs->value = $n;
2059
- list(, $temp) = $lhs->divide($rhs);
2060
- return $temp->value;
2061
- }
2062
-
2063
- if ( ($key = array_search($n, $cache[MATH_BIGINTEGER_VARIABLE])) === false ) {
2064
- $key = count($cache[MATH_BIGINTEGER_VARIABLE]);
2065
- $cache[MATH_BIGINTEGER_VARIABLE][] = $n;
2066
- $lhs = new Math_BigInteger();
2067
- $lhs_value = &$lhs->value;
2068
- $lhs_value = $this->_array_repeat(0, 2 * $n_length);
2069
- $lhs_value[] = 1;
2070
- $rhs = new Math_BigInteger();
2071
- $rhs->value = $n;
2072
- list($temp, ) = $lhs->divide($rhs); // m.length
2073
- $cache[MATH_BIGINTEGER_DATA][] = $temp->value;
2074
- }
2075
-
2076
- // 2 * m.length - (m.length - 1) = m.length + 1
2077
- $temp = array_slice($x, $n_length - 1);
2078
- // (m.length + 1) + m.length = 2 * m.length + 1
2079
- $temp = $this->_multiply($temp, false, $cache[MATH_BIGINTEGER_DATA][$key], false);
2080
- // (2 * m.length + 1) - (m.length - 1) = m.length + 2
2081
- $temp = array_slice($temp[MATH_BIGINTEGER_VALUE], $n_length + 1);
2082
-
2083
- // m.length + 1
2084
- $result = array_slice($x, 0, $n_length + 1);
2085
- // m.length + 1
2086
- $temp = $this->_multiplyLower($temp, false, $n, false, $n_length + 1);
2087
- // $temp == array_slice($temp->_multiply($temp, false, $n, false)->value, 0, $n_length + 1)
2088
-
2089
- if ($this->_compare($result, false, $temp[MATH_BIGINTEGER_VALUE], $temp[MATH_BIGINTEGER_SIGN]) < 0) {
2090
- $corrector_value = $this->_array_repeat(0, $n_length + 1);
2091
- $corrector_value[] = 1;
2092
- $result = $this->_add($result, false, $corrector, false);
2093
- $result = $result[MATH_BIGINTEGER_VALUE];
2094
- }
2095
-
2096
- // at this point, we're subtracting a number with m.length + 1 digits from another number with m.length + 1 digits
2097
- $result = $this->_subtract($result, false, $temp[MATH_BIGINTEGER_VALUE], $temp[MATH_BIGINTEGER_SIGN]);
2098
- while ($this->_compare($result[MATH_BIGINTEGER_VALUE], $result[MATH_BIGINTEGER_SIGN], $n, false) > 0) {
2099
- $result = $this->_subtract($result[MATH_BIGINTEGER_VALUE], $result[MATH_BIGINTEGER_SIGN], $n, false);
2100
- }
2101
-
2102
- return $result[MATH_BIGINTEGER_VALUE];
2103
- }
2104
-
2105
- /**
2106
- * Performs long multiplication up to $stop digits
2107
- *
2108
- * If you're going to be doing array_slice($product->value, 0, $stop), some cycles can be saved.
2109
- *
2110
- * @see _regularBarrett()
2111
- * @param Array $x_value
2112
- * @param Boolean $x_negative
2113
- * @param Array $y_value
2114
- * @param Boolean $y_negative
2115
- * @return Array
2116
- * @access private
2117
- */
2118
- function _multiplyLower($x_value, $x_negative, $y_value, $y_negative, $stop)
2119
- {
2120
- $x_length = count($x_value);
2121
- $y_length = count($y_value);
2122
-
2123
- if ( !$x_length || !$y_length ) { // a 0 is being multiplied
2124
- return array(
2125
- MATH_BIGINTEGER_VALUE => array(),
2126
- MATH_BIGINTEGER_SIGN => false
2127
- );
2128
- }
2129
-
2130
- if ( $x_length < $y_length ) {
2131
- $temp = $x_value;
2132
- $x_value = $y_value;
2133
- $y_value = $temp;
2134
-
2135
- $x_length = count($x_value);
2136
- $y_length = count($y_value);
2137
- }
2138
-
2139
- $product_value = $this->_array_repeat(0, $x_length + $y_length);
2140
-
2141
- // the following for loop could be removed if the for loop following it
2142
- // (the one with nested for loops) initially set $i to 0, but
2143
- // doing so would also make the result in one set of unnecessary adds,
2144
- // since on the outermost loops first pass, $product->value[$k] is going
2145
- // to always be 0
2146
-
2147
- $carry = 0;
2148
-
2149
- for ($j = 0; $j < $x_length; ++$j) { // ie. $i = 0, $k = $i
2150
- $temp = $x_value[$j] * $y_value[0] + $carry; // $product_value[$k] == 0
2151
- $carry = (int) ($temp / 0x4000000);
2152
- $product_value[$j] = (int) ($temp - 0x4000000 * $carry);
2153
- }
2154
-
2155
- if ($j < $stop) {
2156
- $product_value[$j] = $carry;
2157
- }
2158
-
2159
- // the above for loop is what the previous comment was talking about. the
2160
- // following for loop is the "one with nested for loops"
2161
-
2162
- for ($i = 1; $i < $y_length; ++$i) {
2163
- $carry = 0;
2164
-
2165
- for ($j = 0, $k = $i; $j < $x_length && $k < $stop; ++$j, ++$k) {
2166
- $temp = $product_value[$k] + $x_value[$j] * $y_value[$i] + $carry;
2167
- $carry = (int) ($temp / 0x4000000);
2168
- $product_value[$k] = (int) ($temp - 0x4000000 * $carry);
2169
- }
2170
-
2171
- if ($k < $stop) {
2172
- $product_value[$k] = $carry;
2173
- }
2174
- }
2175
-
2176
- return array(
2177
- MATH_BIGINTEGER_VALUE => $this->_trim($product_value),
2178
- MATH_BIGINTEGER_SIGN => $x_negative != $y_negative
2179
- );
2180
- }
2181
-
2182
- /**
2183
- * Montgomery Modular Reduction
2184
- *
2185
- * ($x->_prepMontgomery($n))->_montgomery($n) yields $x % $n.
2186
- * {@link http://math.libtomcrypt.com/files/tommath.pdf#page=170 MPM 6.3} provides insights on how this can be
2187
- * improved upon (basically, by using the comba method). gcd($n, 2) must be equal to one for this function
2188
- * to work correctly.
2189
- *
2190
- * @see _prepMontgomery()
2191
- * @see _slidingWindow()
2192
- * @access private
2193
- * @param Array $x
2194
- * @param Array $n
2195
- * @return Array
2196
- */
2197
- function _montgomery($x, $n)
2198
- {
2199
- static $cache = array(
2200
- MATH_BIGINTEGER_VARIABLE => array(),
2201
- MATH_BIGINTEGER_DATA => array()
2202
- );
2203
-
2204
- if ( ($key = array_search($n, $cache[MATH_BIGINTEGER_VARIABLE])) === false ) {
2205
- $key = count($cache[MATH_BIGINTEGER_VARIABLE]);
2206
- $cache[MATH_BIGINTEGER_VARIABLE][] = $x;
2207
- $cache[MATH_BIGINTEGER_DATA][] = $this->_modInverse67108864($n);
2208
- }
2209
-
2210
- $k = count($n);
2211
-
2212
- $result = array(MATH_BIGINTEGER_VALUE => $x);
2213
-
2214
- for ($i = 0; $i < $k; ++$i) {
2215
- $temp = $result[MATH_BIGINTEGER_VALUE][$i] * $cache[MATH_BIGINTEGER_DATA][$key];
2216
- $temp = (int) ($temp - 0x4000000 * ((int) ($temp / 0x4000000)));
2217
- $temp = $this->_regularMultiply(array($temp), $n);
2218
- $temp = array_merge($this->_array_repeat(0, $i), $temp);
2219
- $result = $this->_add($result[MATH_BIGINTEGER_VALUE], false, $temp, false);
2220
- }
2221
-
2222
- $result[MATH_BIGINTEGER_VALUE] = array_slice($result[MATH_BIGINTEGER_VALUE], $k);
2223
-
2224
- if ($this->_compare($result, false, $n, false) >= 0) {
2225
- $result = $this->_subtract($result[MATH_BIGINTEGER_VALUE], false, $n, false);
2226
- }
2227
-
2228
- return $result[MATH_BIGINTEGER_VALUE];
2229
- }
2230
-
2231
- /**
2232
- * Montgomery Multiply
2233
- *
2234
- * Interleaves the montgomery reduction and long multiplication algorithms together as described in
2235
- * {@link http://www.cacr.math.uwaterloo.ca/hac/about/chap14.pdf#page=13 HAC 14.36}
2236
- *
2237
- * @see _prepMontgomery()
2238
- * @see _montgomery()
2239
- * @access private
2240
- * @param Array $x
2241
- * @param Array $y
2242
- * @param Array $m
2243
- * @return Array
2244
- */
2245
- function _montgomeryMultiply($x, $y, $m)
2246
- {
2247
- $temp = $this->_multiply($x, false, $y, false);
2248
- return $this->_montgomery($temp[MATH_BIGINTEGER_VALUE], $m);
2249
-
2250
- static $cache = array(
2251
- MATH_BIGINTEGER_VARIABLE => array(),
2252
- MATH_BIGINTEGER_DATA => array()
2253
- );
2254
-
2255
- if ( ($key = array_search($m, $cache[MATH_BIGINTEGER_VARIABLE])) === false ) {
2256
- $key = count($cache[MATH_BIGINTEGER_VARIABLE]);
2257
- $cache[MATH_BIGINTEGER_VARIABLE][] = $m;
2258
- $cache[MATH_BIGINTEGER_DATA][] = $this->_modInverse67108864($m);
2259
- }
2260
-
2261
- $n = max(count($x), count($y), count($m));
2262
- $x = array_pad($x, $n, 0);
2263
- $y = array_pad($y, $n, 0);
2264
- $m = array_pad($m, $n, 0);
2265
- $a = array(MATH_BIGINTEGER_VALUE => $this->_array_repeat(0, $n + 1));
2266
- for ($i = 0; $i < $n; ++$i) {
2267
- $temp = $a[MATH_BIGINTEGER_VALUE][0] + $x[$i] * $y[0];
2268
- $temp = (int) ($temp - 0x4000000 * ((int) ($temp / 0x4000000)));
2269
- $temp = $temp * $cache[MATH_BIGINTEGER_DATA][$key];
2270
- $temp = (int) ($temp - 0x4000000 * ((int) ($temp / 0x4000000)));
2271
- $temp = $this->_add($this->_regularMultiply(array($x[$i]), $y), false, $this->_regularMultiply(array($temp), $m), false);
2272
- $a = $this->_add($a[MATH_BIGINTEGER_VALUE], false, $temp[MATH_BIGINTEGER_VALUE], false);
2273
- $a[MATH_BIGINTEGER_VALUE] = array_slice($a[MATH_BIGINTEGER_VALUE], 1);
2274
- }
2275
- if ($this->_compare($a[MATH_BIGINTEGER_VALUE], false, $m, false) >= 0) {
2276
- $a = $this->_subtract($a[MATH_BIGINTEGER_VALUE], false, $m, false);
2277
- }
2278
- return $a[MATH_BIGINTEGER_VALUE];
2279
- }
2280
-
2281
- /**
2282
- * Prepare a number for use in Montgomery Modular Reductions
2283
- *
2284
- * @see _montgomery()
2285
- * @see _slidingWindow()
2286
- * @access private
2287
- * @param Array $x
2288
- * @param Array $n
2289
- * @return Array
2290
- */
2291
- function _prepMontgomery($x, $n)
2292
- {
2293
- $lhs = new Math_BigInteger();
2294
- $lhs->value = array_merge($this->_array_repeat(0, count($n)), $x);
2295
- $rhs = new Math_BigInteger();
2296
- $rhs->value = $n;
2297
-
2298
- list(, $temp) = $lhs->divide($rhs);
2299
- return $temp->value;
2300
- }
2301
-
2302
- /**
2303
- * Modular Inverse of a number mod 2**26 (eg. 67108864)
2304
- *
2305
- * Based off of the bnpInvDigit function implemented and justified in the following URL:
2306
- *
2307
- * {@link http://www-cs-students.stanford.edu/~tjw/jsbn/jsbn.js}
2308
- *
2309
- * The following URL provides more info:
2310
- *
2311
- * {@link http://groups.google.com/group/sci.crypt/msg/7a137205c1be7d85}
2312
- *
2313
- * As for why we do all the bitmasking... strange things can happen when converting from floats to ints. For
2314
- * instance, on some computers, var_dump((int) -4294967297) yields int(-1) and on others, it yields
2315
- * int(-2147483648). To avoid problems stemming from this, we use bitmasks to guarantee that ints aren't
2316
- * auto-converted to floats. The outermost bitmask is present because without it, there's no guarantee that
2317
- * the "residue" returned would be the so-called "common residue". We use fmod, in the last step, because the
2318
- * maximum possible $x is 26 bits and the maximum $result is 16 bits. Thus, we have to be able to handle up to
2319
- * 40 bits, which only 64-bit floating points will support.
2320
- *
2321
- * Thanks to Pedro Gimeno Fortea for input!
2322
- *
2323
- * @see _montgomery()
2324
- * @access private
2325
- * @param Array $x
2326
- * @return Integer
2327
- */
2328
- function _modInverse67108864($x) // 2**26 == 67108864
2329
- {
2330
- $x = -$x[0];
2331
- $result = $x & 0x3; // x**-1 mod 2**2
2332
- $result = ($result * (2 - $x * $result)) & 0xF; // x**-1 mod 2**4
2333
- $result = ($result * (2 - ($x & 0xFF) * $result)) & 0xFF; // x**-1 mod 2**8
2334
- $result = ($result * ((2 - ($x & 0xFFFF) * $result) & 0xFFFF)) & 0xFFFF; // x**-1 mod 2**16
2335
- $result = fmod($result * (2 - fmod($x * $result, 0x4000000)), 0x4000000); // x**-1 mod 2**26
2336
- return $result & 0x3FFFFFF;
2337
- }
2338
-
2339
- /**
2340
- * Calculates modular inverses.
2341
- *
2342
- * Say you have (30 mod 17 * x mod 17) mod 17 == 1. x can be found using modular inverses.
2343
- *
2344
- * Here's an example:
2345
- * <code>
2346
- * <?php
2347
- * include('Math/BigInteger.php');
2348
- *
2349
- * $a = new Math_BigInteger(30);
2350
- * $b = new Math_BigInteger(17);
2351
- *
2352
- * $c = $a->modInverse($b);
2353
- * echo $c->toString(); // outputs 4
2354
- *
2355
- * echo "\r\n";
2356
- *
2357
- * $d = $a->multiply($c);
2358
- * list(, $d) = $d->divide($b);
2359
- * echo $d; // outputs 1 (as per the definition of modular inverse)
2360
- * ?>
2361
- * </code>
2362
- *
2363
- * @param Math_BigInteger $n
2364
- * @return mixed false, if no modular inverse exists, Math_BigInteger, otherwise.
2365
- * @access public
2366
- * @internal See {@link http://www.cacr.math.uwaterloo.ca/hac/about/chap14.pdf#page=21 HAC 14.64} for more information.
2367
- */
2368
- function modInverse($n)
2369
- {
2370
- switch ( MATH_BIGINTEGER_MODE ) {
2371
- case MATH_BIGINTEGER_MODE_GMP:
2372
- $temp = new Math_BigInteger();
2373
- $temp->value = gmp_invert($this->value, $n->value);
2374
-
2375
- return ( $temp->value === false ) ? false : $this->_normalize($temp);
2376
- }
2377
-
2378
- static $zero, $one;
2379
- if (!isset($zero)) {
2380
- $zero = new Math_BigInteger();
2381
- $one = new Math_BigInteger(1);
2382
- }
2383
-
2384
- // $x mod -$n == $x mod $n.
2385
- $n = $n->abs();
2386
-
2387
- if ($this->compare($zero) < 0) {
2388
- $temp = $this->abs();
2389
- $temp = $temp->modInverse($n);
2390
- return $this->_normalize($n->subtract($temp));
2391
- }
2392
-
2393
- extract($this->extendedGCD($n));
2394
-
2395
- if (!$gcd->equals($one)) {
2396
- return false;
2397
- }
2398
-
2399
- $x = $x->compare($zero) < 0 ? $x->add($n) : $x;
2400
-
2401
- return $this->compare($zero) < 0 ? $this->_normalize($n->subtract($x)) : $this->_normalize($x);
2402
- }
2403
-
2404
- /**
2405
- * Calculates the greatest common divisor and B�zout's identity.
2406
- *
2407
- * Say you have 693 and 609. The GCD is 21. B�zout's identity states that there exist integers x and y such that
2408
- * 693*x + 609*y == 21. In point of fact, there are actually an infinite number of x and y combinations and which
2409
- * combination is returned is dependant upon which mode is in use. See
2410
- * {@link http://en.wikipedia.org/wiki/B%C3%A9zout%27s_identity B�zout's identity - Wikipedia} for more information.
2411
- *
2412
- * Here's an example:
2413
- * <code>
2414
- * <?php
2415
- * include('Math/BigInteger.php');
2416
- *
2417
- * $a = new Math_BigInteger(693);
2418
- * $b = new Math_BigInteger(609);
2419
- *
2420
- * extract($a->extendedGCD($b));
2421
- *
2422
- * echo $gcd->toString() . "\r\n"; // outputs 21
2423
- * echo $a->toString() * $x->toString() + $b->toString() * $y->toString(); // outputs 21
2424
- * ?>
2425
- * </code>
2426
- *
2427
- * @param Math_BigInteger $n
2428
- * @return Math_BigInteger
2429
- * @access public
2430
- * @internal Calculates the GCD using the binary xGCD algorithim described in
2431
- * {@link http://www.cacr.math.uwaterloo.ca/hac/about/chap14.pdf#page=19 HAC 14.61}. As the text above 14.61 notes,
2432
- * the more traditional algorithim requires "relatively costly multiple-precision divisions".
2433
- */
2434
- function extendedGCD($n)
2435
- {
2436
- switch ( MATH_BIGINTEGER_MODE ) {
2437
- case MATH_BIGINTEGER_MODE_GMP:
2438
- extract(gmp_gcdext($this->value, $n->value));
2439
-
2440
- return array(
2441
- 'gcd' => $this->_normalize(new Math_BigInteger($g)),
2442
- 'x' => $this->_normalize(new Math_BigInteger($s)),
2443
- 'y' => $this->_normalize(new Math_BigInteger($t))
2444
- );
2445
- case MATH_BIGINTEGER_MODE_BCMATH:
2446
- // it might be faster to use the binary xGCD algorithim here, as well, but (1) that algorithim works
2447
- // best when the base is a power of 2 and (2) i don't think it'd make much difference, anyway. as is,
2448
- // the basic extended euclidean algorithim is what we're using.
2449
-
2450
- $u = $this->value;
2451
- $v = $n->value;
2452
-
2453
- $a = '1';
2454
- $b = '0';
2455
- $c = '0';
2456
- $d = '1';
2457
-
2458
- while (bccomp($v, '0', 0) != 0) {
2459
- $q = bcdiv($u, $v, 0);
2460
-
2461
- $temp = $u;
2462
- $u = $v;
2463
- $v = bcsub($temp, bcmul($v, $q, 0), 0);
2464
-
2465
- $temp = $a;
2466
- $a = $c;
2467
- $c = bcsub($temp, bcmul($a, $q, 0), 0);
2468
-
2469
- $temp = $b;
2470
- $b = $d;
2471
- $d = bcsub($temp, bcmul($b, $q, 0), 0);
2472
- }
2473
-
2474
- return array(
2475
- 'gcd' => $this->_normalize(new Math_BigInteger($u)),
2476
- 'x' => $this->_normalize(new Math_BigInteger($a)),
2477
- 'y' => $this->_normalize(new Math_BigInteger($b))
2478
- );
2479
- }
2480
-
2481
- $y = $n->copy();
2482
- $x = $this->copy();
2483
- $g = new Math_BigInteger();
2484
- $g->value = array(1);
2485
-
2486
- while ( !(($x->value[0] & 1)|| ($y->value[0] & 1)) ) {
2487
- $x->_rshift(1);
2488
- $y->_rshift(1);
2489
- $g->_lshift(1);
2490
- }
2491
-
2492
- $u = $x->copy();
2493
- $v = $y->copy();
2494
-
2495
- $a = new Math_BigInteger();
2496
- $b = new Math_BigInteger();
2497
- $c = new Math_BigInteger();
2498
- $d = new Math_BigInteger();
2499
-
2500
- $a->value = $d->value = $g->value = array(1);
2501
- $b->value = $c->value = array();
2502
-
2503
- while ( !empty($u->value) ) {
2504
- while ( !($u->value[0] & 1) ) {
2505
- $u->_rshift(1);
2506
- if ( (!empty($a->value) && ($a->value[0] & 1)) || (!empty($b->value) && ($b->value[0] & 1)) ) {
2507
- $a = $a->add($y);
2508
- $b = $b->subtract($x);
2509
- }
2510
- $a->_rshift(1);
2511
- $b->_rshift(1);
2512
- }
2513
-
2514
- while ( !($v->value[0] & 1) ) {
2515
- $v->_rshift(1);
2516
- if ( (!empty($d->value) && ($d->value[0] & 1)) || (!empty($c->value) && ($c->value[0] & 1)) ) {
2517
- $c = $c->add($y);
2518
- $d = $d->subtract($x);
2519
- }
2520
- $c->_rshift(1);
2521
- $d->_rshift(1);
2522
- }
2523
-
2524
- if ($u->compare($v) >= 0) {
2525
- $u = $u->subtract($v);
2526
- $a = $a->subtract($c);
2527
- $b = $b->subtract($d);
2528
- } else {
2529
- $v = $v->subtract($u);
2530
- $c = $c->subtract($a);
2531
- $d = $d->subtract($b);
2532
- }
2533
- }
2534
-
2535
- return array(
2536
- 'gcd' => $this->_normalize($g->multiply($v)),
2537
- 'x' => $this->_normalize($c),
2538
- 'y' => $this->_normalize($d)
2539
- );
2540
- }
2541
-
2542
- /**
2543
- * Calculates the greatest common divisor
2544
- *
2545
- * Say you have 693 and 609. The GCD is 21.
2546
- *
2547
- * Here's an example:
2548
- * <code>
2549
- * <?php
2550
- * include('Math/BigInteger.php');
2551
- *
2552
- * $a = new Math_BigInteger(693);
2553
- * $b = new Math_BigInteger(609);
2554
- *
2555
- * $gcd = a->extendedGCD($b);
2556
- *
2557
- * echo $gcd->toString() . "\r\n"; // outputs 21
2558
- * ?>
2559
- * </code>
2560
- *
2561
- * @param Math_BigInteger $n
2562
- * @return Math_BigInteger
2563
- * @access public
2564
- */
2565
- function gcd($n)
2566
- {
2567
- extract($this->extendedGCD($n));
2568
- return $gcd;
2569
- }
2570
-
2571
- /**
2572
- * Absolute value.
2573
- *
2574
- * @return Math_BigInteger
2575
- * @access public
2576
- */
2577
- function abs()
2578
- {
2579
- $temp = new Math_BigInteger();
2580
-
2581
- switch ( MATH_BIGINTEGER_MODE ) {
2582
- case MATH_BIGINTEGER_MODE_GMP:
2583
- $temp->value = gmp_abs($this->value);
2584
- break;
2585
- case MATH_BIGINTEGER_MODE_BCMATH:
2586
- $temp->value = (bccomp($this->value, '0', 0) < 0) ? substr($this->value, 1) : $this->value;
2587
- break;
2588
- default:
2589
- $temp->value = $this->value;
2590
- }
2591
-
2592
- return $temp;
2593
- }
2594
-
2595
- /**
2596
- * Compares two numbers.
2597
- *
2598
- * Although one might think !$x->compare($y) means $x != $y, it, in fact, means the opposite. The reason for this is
2599
- * demonstrated thusly:
2600
- *
2601
- * $x > $y: $x->compare($y) > 0
2602
- * $x < $y: $x->compare($y) < 0
2603
- * $x == $y: $x->compare($y) == 0
2604
- *
2605
- * Note how the same comparison operator is used. If you want to test for equality, use $x->equals($y).
2606
- *
2607
- * @param Math_BigInteger $x
2608
- * @return Integer < 0 if $this is less than $x; > 0 if $this is greater than $x, and 0 if they are equal.
2609
- * @access public
2610
- * @see equals()
2611
- * @internal Could return $this->subtract($x), but that's not as fast as what we do do.
2612
- */
2613
- function compare($y)
2614
- {
2615
- switch ( MATH_BIGINTEGER_MODE ) {
2616
- case MATH_BIGINTEGER_MODE_GMP:
2617
- return gmp_cmp($this->value, $y->value);
2618
- case MATH_BIGINTEGER_MODE_BCMATH:
2619
- return bccomp($this->value, $y->value, 0);
2620
- }
2621
-
2622
- return $this->_compare($this->value, $this->is_negative, $y->value, $y->is_negative);
2623
- }
2624
-
2625
- /**
2626
- * Compares two numbers.
2627
- *
2628
- * @param Array $x_value
2629
- * @param Boolean $x_negative
2630
- * @param Array $y_value
2631
- * @param Boolean $y_negative
2632
- * @return Integer
2633
- * @see compare()
2634
- * @access private
2635
- */
2636
- function _compare($x_value, $x_negative, $y_value, $y_negative)
2637
- {
2638
- if ( $x_negative != $y_negative ) {
2639
- return ( !$x_negative && $y_negative ) ? 1 : -1;
2640
- }
2641
-
2642
- $result = $x_negative ? -1 : 1;
2643
-
2644
- if ( count($x_value) != count($y_value) ) {
2645
- return ( count($x_value) > count($y_value) ) ? $result : -$result;
2646
- }
2647
- $size = max(count($x_value), count($y_value));
2648
-
2649
- $x_value = array_pad($x_value, $size, 0);
2650
- $y_value = array_pad($y_value, $size, 0);
2651
-
2652
- for ($i = count($x_value) - 1; $i >= 0; --$i) {
2653
- if ($x_value[$i] != $y_value[$i]) {
2654
- return ( $x_value[$i] > $y_value[$i] ) ? $result : -$result;
2655
- }
2656
- }
2657
-
2658
- return 0;
2659
- }
2660
-
2661
- /**
2662
- * Tests the equality of two numbers.
2663
- *
2664
- * If you need to see if one number is greater than or less than another number, use Math_BigInteger::compare()
2665
- *
2666
- * @param Math_BigInteger $x
2667
- * @return Boolean
2668
- * @access public
2669
- * @see compare()
2670
- */
2671
- function equals($x)
2672
- {
2673
- switch ( MATH_BIGINTEGER_MODE ) {
2674
- case MATH_BIGINTEGER_MODE_GMP:
2675
- return gmp_cmp($this->value, $x->value) == 0;
2676
- default:
2677
- return $this->value === $x->value && $this->is_negative == $x->is_negative;
2678
- }
2679
- }
2680
-
2681
- /**
2682
- * Set Precision
2683
- *
2684
- * Some bitwise operations give different results depending on the precision being used. Examples include left
2685
- * shift, not, and rotates.
2686
- *
2687
- * @param Math_BigInteger $x
2688
- * @access public
2689
- * @return Math_BigInteger
2690
- */
2691
- function setPrecision($bits)
2692
- {
2693
- $this->precision = $bits;
2694
- if ( MATH_BIGINTEGER_MODE != MATH_BIGINTEGER_MODE_BCMATH ) {
2695
- $this->bitmask = new Math_BigInteger(chr((1 << ($bits & 0x7)) - 1) . str_repeat(chr(0xFF), $bits >> 3), 256);
2696
- } else {
2697
- $this->bitmask = new Math_BigInteger(bcpow('2', $bits, 0));
2698
- }
2699
-
2700
- $temp = $this->_normalize($this);
2701
- $this->value = $temp->value;
2702
- }
2703
-
2704
- /**
2705
- * Logical And
2706
- *
2707
- * @param Math_BigInteger $x
2708
- * @access public
2709
- * @internal Implemented per a request by Lluis Pamies i Juarez <lluis _a_ pamies.cat>
2710
- * @return Math_BigInteger
2711
- */
2712
- function bitwise_and($x)
2713
- {
2714
- switch ( MATH_BIGINTEGER_MODE ) {
2715
- case MATH_BIGINTEGER_MODE_GMP:
2716
- $temp = new Math_BigInteger();
2717
- $temp->value = gmp_and($this->value, $x->value);
2718
-
2719
- return $this->_normalize($temp);
2720
- case MATH_BIGINTEGER_MODE_BCMATH:
2721
- $left = $this->toBytes();
2722
- $right = $x->toBytes();
2723
-
2724
- $length = max(strlen($left), strlen($right));
2725
-
2726
- $left = str_pad($left, $length, chr(0), STR_PAD_LEFT);
2727
- $right = str_pad($right, $length, chr(0), STR_PAD_LEFT);
2728
-
2729
- return $this->_normalize(new Math_BigInteger($left & $right, 256));
2730
- }
2731
-
2732
- $result = $this->copy();
2733
-
2734
- $length = min(count($x->value), count($this->value));
2735
-
2736
- $result->value = array_slice($result->value, 0, $length);
2737
-
2738
- for ($i = 0; $i < $length; ++$i) {
2739
- $result->value[$i] = $result->value[$i] & $x->value[$i];
2740
- }
2741
-
2742
- return $this->_normalize($result);
2743
- }
2744
-
2745
- /**
2746
- * Logical Or
2747
- *
2748
- * @param Math_BigInteger $x
2749
- * @access public
2750
- * @internal Implemented per a request by Lluis Pamies i Juarez <lluis _a_ pamies.cat>
2751
- * @return Math_BigInteger
2752
- */
2753
- function bitwise_or($x)
2754
- {
2755
- switch ( MATH_BIGINTEGER_MODE ) {
2756
- case MATH_BIGINTEGER_MODE_GMP:
2757
- $temp = new Math_BigInteger();
2758
- $temp->value = gmp_or($this->value, $x->value);
2759
-
2760
- return $this->_normalize($temp);
2761
- case MATH_BIGINTEGER_MODE_BCMATH:
2762
- $left = $this->toBytes();
2763
- $right = $x->toBytes();
2764
-
2765
- $length = max(strlen($left), strlen($right));
2766
-
2767
- $left = str_pad($left, $length, chr(0), STR_PAD_LEFT);
2768
- $right = str_pad($right, $length, chr(0), STR_PAD_LEFT);
2769
-
2770
- return $this->_normalize(new Math_BigInteger($left | $right, 256));
2771
- }
2772
-
2773
- $length = max(count($this->value), count($x->value));
2774
- $result = $this->copy();
2775
- $result->value = array_pad($result->value, 0, $length);
2776
- $x->value = array_pad($x->value, 0, $length);
2777
-
2778
- for ($i = 0; $i < $length; ++$i) {
2779
- $result->value[$i] = $this->value[$i] | $x->value[$i];
2780
- }
2781
-
2782
- return $this->_normalize($result);
2783
- }
2784
-
2785
- /**
2786
- * Logical Exclusive-Or
2787
- *
2788
- * @param Math_BigInteger $x
2789
- * @access public
2790
- * @internal Implemented per a request by Lluis Pamies i Juarez <lluis _a_ pamies.cat>
2791
- * @return Math_BigInteger
2792
- */
2793
- function bitwise_xor($x)
2794
- {
2795
- switch ( MATH_BIGINTEGER_MODE ) {
2796
- case MATH_BIGINTEGER_MODE_GMP:
2797
- $temp = new Math_BigInteger();
2798
- $temp->value = gmp_xor($this->value, $x->value);
2799
-
2800
- return $this->_normalize($temp);
2801
- case MATH_BIGINTEGER_MODE_BCMATH:
2802
- $left = $this->toBytes();
2803
- $right = $x->toBytes();
2804
-
2805
- $length = max(strlen($left), strlen($right));
2806
-
2807
- $left = str_pad($left, $length, chr(0), STR_PAD_LEFT);
2808
- $right = str_pad($right, $length, chr(0), STR_PAD_LEFT);
2809
-
2810
- return $this->_normalize(new Math_BigInteger($left ^ $right, 256));
2811
- }
2812
-
2813
- $length = max(count($this->value), count($x->value));
2814
- $result = $this->copy();
2815
- $result->value = array_pad($result->value, 0, $length);
2816
- $x->value = array_pad($x->value, 0, $length);
2817
-
2818
- for ($i = 0; $i < $length; ++$i) {
2819
- $result->value[$i] = $this->value[$i] ^ $x->value[$i];
2820
- }
2821
-
2822
- return $this->_normalize($result);
2823
- }
2824
-
2825
- /**
2826
- * Logical Not
2827
- *
2828
- * @access public
2829
- * @internal Implemented per a request by Lluis Pamies i Juarez <lluis _a_ pamies.cat>
2830
- * @return Math_BigInteger
2831
- */
2832
- function bitwise_not()
2833
- {
2834
- // calculuate "not" without regard to $this->precision
2835
- // (will always result in a smaller number. ie. ~1 isn't 1111 1110 - it's 0)
2836
- $temp = $this->toBytes();
2837
- $pre_msb = decbin(ord($temp[0]));
2838
- $temp = ~$temp;
2839
- $msb = decbin(ord($temp[0]));
2840
- if (strlen($msb) == 8) {
2841
- $msb = substr($msb, strpos($msb, '0'));
2842
- }
2843
- $temp[0] = chr(bindec($msb));
2844
-
2845
- // see if we need to add extra leading 1's
2846
- $current_bits = strlen($pre_msb) + 8 * strlen($temp) - 8;
2847
- $new_bits = $this->precision - $current_bits;
2848
- if ($new_bits <= 0) {
2849
- return $this->_normalize(new Math_BigInteger($temp, 256));
2850
- }
2851
-
2852
- // generate as many leading 1's as we need to.
2853
- $leading_ones = chr((1 << ($new_bits & 0x7)) - 1) . str_repeat(chr(0xFF), $new_bits >> 3);
2854
- $this->_base256_lshift($leading_ones, $current_bits);
2855
-
2856
- $temp = str_pad($temp, ceil($this->bits / 8), chr(0), STR_PAD_LEFT);
2857
-
2858
- return $this->_normalize(new Math_BigInteger($leading_ones | $temp, 256));
2859
- }
2860
-
2861
- /**
2862
- * Logical Right Shift
2863
- *
2864
- * Shifts BigInteger's by $shift bits, effectively dividing by 2**$shift.
2865
- *
2866
- * @param Integer $shift
2867
- * @return Math_BigInteger
2868
- * @access public
2869
- * @internal The only version that yields any speed increases is the internal version.
2870
- */
2871
- function bitwise_rightShift($shift)
2872
- {
2873
- $temp = new Math_BigInteger();
2874
-
2875
- switch ( MATH_BIGINTEGER_MODE ) {
2876
- case MATH_BIGINTEGER_MODE_GMP:
2877
- static $two;
2878
-
2879
- if (!isset($two)) {
2880
- $two = gmp_init('2');
2881
- }
2882
-
2883
- $temp->value = gmp_div_q($this->value, gmp_pow($two, $shift));
2884
-
2885
- break;
2886
- case MATH_BIGINTEGER_MODE_BCMATH:
2887
- $temp->value = bcdiv($this->value, bcpow('2', $shift, 0), 0);
2888
-
2889
- break;
2890
- default: // could just replace _lshift with this, but then all _lshift() calls would need to be rewritten
2891
- // and I don't want to do that...
2892
- $temp->value = $this->value;
2893
- $temp->_rshift($shift);
2894
- }
2895
-
2896
- return $this->_normalize($temp);
2897
- }
2898
-
2899
- /**
2900
- * Logical Left Shift
2901
- *
2902
- * Shifts BigInteger's by $shift bits, effectively multiplying by 2**$shift.
2903
- *
2904
- * @param Integer $shift
2905
- * @return Math_BigInteger
2906
- * @access public
2907
- * @internal The only version that yields any speed increases is the internal version.
2908
- */
2909
- function bitwise_leftShift($shift)
2910
- {
2911
- $temp = new Math_BigInteger();
2912
-
2913
- switch ( MATH_BIGINTEGER_MODE ) {
2914
- case MATH_BIGINTEGER_MODE_GMP:
2915
- static $two;
2916
-
2917
- if (!isset($two)) {
2918
- $two = gmp_init('2');
2919
- }
2920
-
2921
- $temp->value = gmp_mul($this->value, gmp_pow($two, $shift));
2922
-
2923
- break;
2924
- case MATH_BIGINTEGER_MODE_BCMATH:
2925
- $temp->value = bcmul($this->value, bcpow('2', $shift, 0), 0);
2926
-
2927
- break;
2928
- default: // could just replace _rshift with this, but then all _lshift() calls would need to be rewritten
2929
- // and I don't want to do that...
2930
- $temp->value = $this->value;
2931
- $temp->_lshift($shift);
2932
- }
2933
-
2934
- return $this->_normalize($temp);
2935
- }
2936
-
2937
- /**
2938
- * Logical Left Rotate
2939
- *
2940
- * Instead of the top x bits being dropped they're appended to the shifted bit string.
2941
- *
2942
- * @param Integer $shift
2943
- * @return Math_BigInteger
2944
- * @access public
2945
- */
2946
- function bitwise_leftRotate($shift)
2947
- {
2948
- $bits = $this->toBytes();
2949
-
2950
- if ($this->precision > 0) {
2951
- $precision = $this->precision;
2952
- if ( MATH_BIGINTEGER_MODE == MATH_BIGINTEGER_MODE_BCMATH ) {
2953
- $mask = $this->bitmask->subtract(new Math_BigInteger(1));
2954
- $mask = $mask->toBytes();
2955
- } else {
2956
- $mask = $this->bitmask->toBytes();
2957
- }
2958
- } else {
2959
- $temp = ord($bits[0]);
2960
- for ($i = 0; $temp >> $i; ++$i);
2961
- $precision = 8 * strlen($bits) - 8 + $i;
2962
- $mask = chr((1 << ($precision & 0x7)) - 1) . str_repeat(chr(0xFF), $precision >> 3);
2963
- }
2964
-
2965
- if ($shift < 0) {
2966
- $shift+= $precision;
2967
- }
2968
- $shift%= $precision;
2969
-
2970
- if (!$shift) {
2971
- return $this->copy();
2972
- }
2973
-
2974
- $left = $this->bitwise_leftShift($shift);
2975
- $left = $left->bitwise_and(new Math_BigInteger($mask, 256));
2976
- $right = $this->bitwise_rightShift($precision - $shift);
2977
- $result = MATH_BIGINTEGER_MODE != MATH_BIGINTEGER_MODE_BCMATH ? $left->bitwise_or($right) : $left->add($right);
2978
- return $this->_normalize($result);
2979
- }
2980
-
2981
- /**
2982
- * Logical Right Rotate
2983
- *
2984
- * Instead of the bottom x bits being dropped they're prepended to the shifted bit string.
2985
- *
2986
- * @param Integer $shift
2987
- * @return Math_BigInteger
2988
- * @access public
2989
- */
2990
- function bitwise_rightRotate($shift)
2991
- {
2992
- return $this->bitwise_leftRotate(-$shift);
2993
- }
2994
-
2995
- /**
2996
- * Set random number generator function
2997
- *
2998
- * This function is deprecated.
2999
- *
3000
- * @param String $generator
3001
- * @access public
3002
- */
3003
- function setRandomGenerator($generator)
3004
- {
3005
- }
3006
-
3007
- /**
3008
- * Generate a random number
3009
- *
3010
- * @param optional Integer $min
3011
- * @param optional Integer $max
3012
- * @return Math_BigInteger
3013
- * @access public
3014
- */
3015
- function random($min = false, $max = false)
3016
- {
3017
- if ($min === false) {
3018
- $min = new Math_BigInteger(0);
3019
- }
3020
-
3021
- if ($max === false) {
3022
- $max = new Math_BigInteger(0x7FFFFFFF);
3023
- }
3024
-
3025
- $compare = $max->compare($min);
3026
-
3027
- if (!$compare) {
3028
- return $this->_normalize($min);
3029
- } else if ($compare < 0) {
3030
- // if $min is bigger then $max, swap $min and $max
3031
- $temp = $max;
3032
- $max = $min;
3033
- $min = $temp;
3034
- }
3035
-
3036
- $generator = $this->generator;
3037
-
3038
- $max = $max->subtract($min);
3039
- $max = ltrim($max->toBytes(), chr(0));
3040
- $size = strlen($max) - 1;
3041
-
3042
- $crypt_random = function_exists('crypt_random_string') || (!class_exists('Crypt_Random') && function_exists('crypt_random_string'));
3043
- if ($crypt_random) {
3044
- $random = crypt_random_string($size);
3045
- } else {
3046
- $random = '';
3047
-
3048
- if ($size & 1) {
3049
- $random.= chr(mt_rand(0, 255));
3050
- }
3051
-
3052
- $blocks = $size >> 1;
3053
- for ($i = 0; $i < $blocks; ++$i) {
3054
- // mt_rand(-2147483648, 0x7FFFFFFF) always produces -2147483648 on some systems
3055
- $random.= pack('n', mt_rand(0, 0xFFFF));
3056
- }
3057
- }
3058
-
3059
- $fragment = new Math_BigInteger($random, 256);
3060
- $leading = $fragment->compare(new Math_BigInteger(substr($max, 1), 256)) > 0 ?
3061
- ord($max[0]) - 1 : ord($max[0]);
3062
-
3063
- if (!$crypt_random) {
3064
- $msb = chr(mt_rand(0, $leading));
3065
- } else {
3066
- $cutoff = floor(0xFF / $leading) * $leading;
3067
- while (true) {
3068
- $msb = ord(crypt_random_string(1));
3069
- if ($msb <= $cutoff) {
3070
- $msb%= $leading;
3071
- break;
3072
- }
3073
- }
3074
- $msb = chr($msb);
3075
- }
3076
-
3077
- $random = new Math_BigInteger($msb . $random, 256);
3078
-
3079
- return $this->_normalize($random->add($min));
3080
- }
3081
-
3082
- /**
3083
- * Generate a random prime number.
3084
- *
3085
- * If there's not a prime within the given range, false will be returned. If more than $timeout seconds have elapsed,
3086
- * give up and return false.
3087
- *
3088
- * @param optional Integer $min
3089
- * @param optional Integer $max
3090
- * @param optional Integer $timeout
3091
- * @return Math_BigInteger
3092
- * @access public
3093
- * @internal See {@link http://www.cacr.math.uwaterloo.ca/hac/about/chap4.pdf#page=15 HAC 4.44}.
3094
- */
3095
- function randomPrime($min = false, $max = false, $timeout = false)
3096
- {
3097
- $compare = $max->compare($min);
3098
-
3099
- if (!$compare) {
3100
- return $min;
3101
- } else if ($compare < 0) {
3102
- // if $min is bigger then $max, swap $min and $max
3103
- $temp = $max;
3104
- $max = $min;
3105
- $min = $temp;
3106
- }
3107
-
3108
- // gmp_nextprime() requires PHP 5 >= 5.2.0 per <http://php.net/gmp-nextprime>.
3109
- if ( MATH_BIGINTEGER_MODE == MATH_BIGINTEGER_MODE_GMP && function_exists('gmp_nextprime') ) {
3110
- // we don't rely on Math_BigInteger::random()'s min / max when gmp_nextprime() is being used since this function
3111
- // does its own checks on $max / $min when gmp_nextprime() is used. When gmp_nextprime() is not used, however,
3112
- // the same $max / $min checks are not performed.
3113
- if ($min === false) {
3114
- $min = new Math_BigInteger(0);
3115
- }
3116
-
3117
- if ($max === false) {
3118
- $max = new Math_BigInteger(0x7FFFFFFF);
3119
- }
3120
-
3121
- $x = $this->random($min, $max);
3122
-
3123
- $x->value = gmp_nextprime($x->value);
3124
-
3125
- if ($x->compare($max) <= 0) {
3126
- return $x;
3127
- }
3128
-
3129
- $x->value = gmp_nextprime($min->value);
3130
-
3131
- if ($x->compare($max) <= 0) {
3132
- return $x;
3133
- }
3134
-
3135
- return false;
3136
- }
3137
-
3138
- static $one, $two;
3139
- if (!isset($one)) {
3140
- $one = new Math_BigInteger(1);
3141
- $two = new Math_BigInteger(2);
3142
- }
3143
-
3144
- $start = time();
3145
-
3146
- $x = $this->random($min, $max);
3147
- if ($x->equals($two)) {
3148
- return $x;
3149
- }
3150
-
3151
- $x->_make_odd();
3152
- if ($x->compare($max) > 0) {
3153
- // if $x > $max then $max is even and if $min == $max then no prime number exists between the specified range
3154
- if ($min->equals($max)) {
3155
- return false;
3156
- }
3157
- $x = $min->copy();
3158
- $x->_make_odd();
3159
- }
3160
-
3161
- $initial_x = $x->copy();
3162
-
3163
- while (true) {
3164
- if ($timeout !== false && time() - $start > $timeout) {
3165
- return false;
3166
- }
3167
-
3168
- if ($x->isPrime()) {
3169
- return $x;
3170
- }
3171
-
3172
- $x = $x->add($two);
3173
-
3174
- if ($x->compare($max) > 0) {
3175
- $x = $min->copy();
3176
- if ($x->equals($two)) {
3177
- return $x;
3178
- }
3179
- $x->_make_odd();
3180
- }
3181
-
3182
- if ($x->equals($initial_x)) {
3183
- return false;
3184
- }
3185
- }
3186
- }
3187
-
3188
- /**
3189
- * Make the current number odd
3190
- *
3191
- * If the current number is odd it'll be unchanged. If it's even, one will be added to it.
3192
- *
3193
- * @see randomPrime()
3194
- * @access private
3195
- */
3196
- function _make_odd()
3197
- {
3198
- switch ( MATH_BIGINTEGER_MODE ) {
3199
- case MATH_BIGINTEGER_MODE_GMP:
3200
- gmp_setbit($this->value, 0);
3201
- break;
3202
- case MATH_BIGINTEGER_MODE_BCMATH:
3203
- if ($this->value[strlen($this->value) - 1] % 2 == 0) {
3204
- $this->value = bcadd($this->value, '1');
3205
- }
3206
- break;
3207
- default:
3208
- $this->value[0] |= 1;
3209
- }
3210
- }
3211
-
3212
- /**
3213
- * Checks a numer to see if it's prime
3214
- *
3215
- * Assuming the $t parameter is not set, this function has an error rate of 2**-80. The main motivation for the
3216
- * $t parameter is distributability. Math_BigInteger::randomPrime() can be distributed accross multiple pageloads
3217
- * on a website instead of just one.
3218
- *
3219
- * @param optional Integer $t
3220
- * @return Boolean
3221
- * @access public
3222
- * @internal Uses the
3223
- * {@link http://en.wikipedia.org/wiki/Miller%E2%80%93Rabin_primality_test Miller-Rabin primality test}. See
3224
- * {@link http://www.cacr.math.uwaterloo.ca/hac/about/chap4.pdf#page=8 HAC 4.24}.
3225
- */
3226
- function isPrime($t = false)
3227
- {
3228
- $length = strlen($this->toBytes());
3229
-
3230
- if (!$t) {
3231
- // see HAC 4.49 "Note (controlling the error probability)"
3232
- if ($length >= 163) { $t = 2; } // floor(1300 / 8)
3233
- else if ($length >= 106) { $t = 3; } // floor( 850 / 8)
3234
- else if ($length >= 81 ) { $t = 4; } // floor( 650 / 8)
3235
- else if ($length >= 68 ) { $t = 5; } // floor( 550 / 8)
3236
- else if ($length >= 56 ) { $t = 6; } // floor( 450 / 8)
3237
- else if ($length >= 50 ) { $t = 7; } // floor( 400 / 8)
3238
- else if ($length >= 43 ) { $t = 8; } // floor( 350 / 8)
3239
- else if ($length >= 37 ) { $t = 9; } // floor( 300 / 8)
3240
- else if ($length >= 31 ) { $t = 12; } // floor( 250 / 8)
3241
- else if ($length >= 25 ) { $t = 15; } // floor( 200 / 8)
3242
- else if ($length >= 18 ) { $t = 18; } // floor( 150 / 8)
3243
- else { $t = 27; }
3244
- }
3245
-
3246
- // ie. gmp_testbit($this, 0)
3247
- // ie. isEven() or !isOdd()
3248
- switch ( MATH_BIGINTEGER_MODE ) {
3249
- case MATH_BIGINTEGER_MODE_GMP:
3250
- return gmp_prob_prime($this->value, $t) != 0;
3251
- case MATH_BIGINTEGER_MODE_BCMATH:
3252
- if ($this->value === '2') {
3253
- return true;
3254
- }
3255
- if ($this->value[strlen($this->value) - 1] % 2 == 0) {
3256
- return false;
3257
- }
3258
- break;
3259
- default:
3260
- if ($this->value == array(2)) {
3261
- return true;
3262
- }
3263
- if (~$this->value[0] & 1) {
3264
- return false;
3265
- }
3266
- }
3267
-
3268
- static $primes, $zero, $one, $two;
3269
-
3270
- if (!isset($primes)) {
3271
- $primes = array(
3272
- 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59,
3273
- 61, 67, 71, 73, 79, 83, 89, 97, 101, 103, 107, 109, 113, 127, 131, 137,
3274
- 139, 149, 151, 157, 163, 167, 173, 179, 181, 191, 193, 197, 199, 211, 223, 227,
3275
- 229, 233, 239, 241, 251, 257, 263, 269, 271, 277, 281, 283, 293, 307, 311, 313,
3276
- 317, 331, 337, 347, 349, 353, 359, 367, 373, 379, 383, 389, 397, 401, 409, 419,
3277
- 421, 431, 433, 439, 443, 449, 457, 461, 463, 467, 479, 487, 491, 499, 503, 509,
3278
- 521, 523, 541, 547, 557, 563, 569, 571, 577, 587, 593, 599, 601, 607, 613, 617,
3279
- 619, 631, 641, 643, 647, 653, 659, 661, 673, 677, 683, 691, 701, 709, 719, 727,
3280
- 733, 739, 743, 751, 757, 761, 769, 773, 787, 797, 809, 811, 821, 823, 827, 829,
3281
- 839, 853, 857, 859, 863, 877, 881, 883, 887, 907, 911, 919, 929, 937, 941, 947,
3282
- 953, 967, 971, 977, 983, 991, 997
3283
- );
3284
-
3285
- if ( MATH_BIGINTEGER_MODE != MATH_BIGINTEGER_MODE_INTERNAL ) {
3286
- for ($i = 0; $i < count($primes); ++$i) {
3287
- $primes[$i] = new Math_BigInteger($primes[$i]);
3288
- }
3289
- }
3290
-
3291
- $zero = new Math_BigInteger();
3292
- $one = new Math_BigInteger(1);
3293
- $two = new Math_BigInteger(2);
3294
- }
3295
-
3296
- if ($this->equals($one)) {
3297
- return false;
3298
- }
3299
-
3300
- // see HAC 4.4.1 "Random search for probable primes"
3301
- if ( MATH_BIGINTEGER_MODE != MATH_BIGINTEGER_MODE_INTERNAL ) {
3302
- foreach ($primes as $prime) {
3303
- list(, $r) = $this->divide($prime);
3304
- if ($r->equals($zero)) {
3305
- return $this->equals($prime);
3306
- }
3307
- }
3308
- } else {
3309
- $value = $this->value;
3310
- foreach ($primes as $prime) {
3311
- list(, $r) = $this->_divide_digit($value, $prime);
3312
- if (!$r) {
3313
- return count($value) == 1 && $value[0] == $prime;
3314
- }
3315
- }
3316
- }
3317
-
3318
- $n = $this->copy();
3319
- $n_1 = $n->subtract($one);
3320
- $n_2 = $n->subtract($two);
3321
-
3322
- $r = $n_1->copy();
3323
- $r_value = $r->value;
3324
- // ie. $s = gmp_scan1($n, 0) and $r = gmp_div_q($n, gmp_pow(gmp_init('2'), $s));
3325
- if ( MATH_BIGINTEGER_MODE == MATH_BIGINTEGER_MODE_BCMATH ) {
3326
- $s = 0;
3327
- // if $n was 1, $r would be 0 and this would be an infinite loop, hence our $this->equals($one) check earlier
3328
- while ($r->value[strlen($r->value) - 1] % 2 == 0) {
3329
- $r->value = bcdiv($r->value, '2', 0);
3330
- ++$s;
3331
- }
3332
- } else {
3333
- for ($i = 0, $r_length = count($r_value); $i < $r_length; ++$i) {
3334
- $temp = ~$r_value[$i] & 0xFFFFFF;
3335
- for ($j = 1; ($temp >> $j) & 1; ++$j);
3336
- if ($j != 25) {
3337
- break;
3338
- }
3339
- }
3340
- $s = 26 * $i + $j - 1;
3341
- $r->_rshift($s);
3342
- }
3343
-
3344
- for ($i = 0; $i < $t; ++$i) {
3345
- $a = $this->random($two, $n_2);
3346
- $y = $a->modPow($r, $n);
3347
-
3348
- if (!$y->equals($one) && !$y->equals($n_1)) {
3349
- for ($j = 1; $j < $s && !$y->equals($n_1); ++$j) {
3350
- $y = $y->modPow($two, $n);
3351
- if ($y->equals($one)) {
3352
- return false;
3353
- }
3354
- }
3355
-
3356
- if (!$y->equals($n_1)) {
3357
- return false;
3358
- }
3359
- }
3360
- }
3361
- return true;
3362
- }
3363
-
3364
- /**
3365
- * Logical Left Shift
3366
- *
3367
- * Shifts BigInteger's by $shift bits.
3368
- *
3369
- * @param Integer $shift
3370
- * @access private
3371
- */
3372
- function _lshift($shift)
3373
- {
3374
- if ( $shift == 0 ) {
3375
- return;
3376
- }
3377
-
3378
- $num_digits = (int) ($shift / 26);
3379
- $shift %= 26;
3380
- $shift = 1 << $shift;
3381
-
3382
- $carry = 0;
3383
-
3384
- for ($i = 0; $i < count($this->value); ++$i) {
3385
- $temp = $this->value[$i] * $shift + $carry;
3386
- $carry = (int) ($temp / 0x4000000);
3387
- $this->value[$i] = (int) ($temp - $carry * 0x4000000);
3388
- }
3389
-
3390
- if ( $carry ) {
3391
- $this->value[] = $carry;
3392
- }
3393
-
3394
- while ($num_digits--) {
3395
- array_unshift($this->value, 0);
3396
- }
3397
- }
3398
-
3399
- /**
3400
- * Logical Right Shift
3401
- *
3402
- * Shifts BigInteger's by $shift bits.
3403
- *
3404
- * @param Integer $shift
3405
- * @access private
3406
- */
3407
- function _rshift($shift)
3408
- {
3409
- if ($shift == 0) {
3410
- return;
3411
- }
3412
-
3413
- $num_digits = (int) ($shift / 26);
3414
- $shift %= 26;
3415
- $carry_shift = 26 - $shift;
3416
- $carry_mask = (1 << $shift) - 1;
3417
-
3418
- if ( $num_digits ) {
3419
- $this->value = array_slice($this->value, $num_digits);
3420
- }
3421
-
3422
- $carry = 0;
3423
-
3424
- for ($i = count($this->value) - 1; $i >= 0; --$i) {
3425
- $temp = $this->value[$i] >> $shift | $carry;
3426
- $carry = ($this->value[$i] & $carry_mask) << $carry_shift;
3427
- $this->value[$i] = $temp;
3428
- }
3429
-
3430
- $this->value = $this->_trim($this->value);
3431
- }
3432
-
3433
- /**
3434
- * Normalize
3435
- *
3436
- * Removes leading zeros and truncates (if necessary) to maintain the appropriate precision
3437
- *
3438
- * @param Math_BigInteger
3439
- * @return Math_BigInteger
3440
- * @see _trim()
3441
- * @access private
3442
- */
3443
- function _normalize($result)
3444
- {
3445
- $result->precision = $this->precision;
3446
- $result->bitmask = $this->bitmask;
3447
-
3448
- switch ( MATH_BIGINTEGER_MODE ) {
3449
- case MATH_BIGINTEGER_MODE_GMP:
3450
- if (!empty($result->bitmask->value)) {
3451
- $result->value = gmp_and($result->value, $result->bitmask->value);
3452
- }
3453
-
3454
- return $result;
3455
- case MATH_BIGINTEGER_MODE_BCMATH:
3456
- if (!empty($result->bitmask->value)) {
3457
- $result->value = bcmod($result->value, $result->bitmask->value);
3458
- }
3459
-
3460
- return $result;
3461
- }
3462
-
3463
- $value = &$result->value;
3464
-
3465
- if ( !count($value) ) {
3466
- return $result;
3467
- }
3468
-
3469
- $value = $this->_trim($value);
3470
-
3471
- if (!empty($result->bitmask->value)) {
3472
- $length = min(count($value), count($this->bitmask->value));
3473
- $value = array_slice($value, 0, $length);
3474
-
3475
- for ($i = 0; $i < $length; ++$i) {
3476
- $value[$i] = $value[$i] & $this->bitmask->value[$i];
3477
- }
3478
- }
3479
-
3480
- return $result;
3481
- }
3482
-
3483
- /**
3484
- * Trim
3485
- *
3486
- * Removes leading zeros
3487
- *
3488
- * @return Math_BigInteger
3489
- * @access private
3490
- */
3491
- function _trim($value)
3492
- {
3493
- for ($i = count($value) - 1; $i >= 0; --$i) {
3494
- if ( $value[$i] ) {
3495
- break;
3496
- }
3497
- unset($value[$i]);
3498
- }
3499
-
3500
- return $value;
3501
- }
3502
-
3503
- /**
3504
- * Array Repeat
3505
- *
3506
- * @param $input Array
3507
- * @param $multiplier mixed
3508
- * @return Array
3509
- * @access private
3510
- */
3511
- function _array_repeat($input, $multiplier)
3512
- {
3513
- return ($multiplier) ? array_fill(0, $multiplier, $input) : array();
3514
- }
3515
-
3516
- /**
3517
- * Logical Left Shift
3518
- *
3519
- * Shifts binary strings $shift bits, essentially multiplying by 2**$shift.
3520
- *
3521
- * @param $x String
3522
- * @param $shift Integer
3523
- * @return String
3524
- * @access private
3525
- */
3526
- function _base256_lshift(&$x, $shift)
3527
- {
3528
- if ($shift == 0) {
3529
- return;
3530
- }
3531
-
3532
- $num_bytes = $shift >> 3; // eg. floor($shift/8)
3533
- $shift &= 7; // eg. $shift % 8
3534
-
3535
- $carry = 0;
3536
- for ($i = strlen($x) - 1; $i >= 0; --$i) {
3537
- $temp = ord($x[$i]) << $shift | $carry;
3538
- $x[$i] = chr($temp);
3539
- $carry = $temp >> 8;
3540
- }
3541
- $carry = ($carry != 0) ? chr($carry) : '';
3542
- $x = $carry . $x . str_repeat(chr(0), $num_bytes);
3543
- }
3544
-
3545
- /**
3546
- * Logical Right Shift
3547
- *
3548
- * Shifts binary strings $shift bits, essentially dividing by 2**$shift and returning the remainder.
3549
- *
3550
- * @param $x String
3551
- * @param $shift Integer
3552
- * @return String
3553
- * @access private
3554
- */
3555
- function _base256_rshift(&$x, $shift)
3556
- {
3557
- if ($shift == 0) {
3558
- $x = ltrim($x, chr(0));
3559
- return '';
3560
- }
3561
-
3562
- $num_bytes = $shift >> 3; // eg. floor($shift/8)
3563
- $shift &= 7; // eg. $shift % 8
3564
-
3565
- $remainder = '';
3566
- if ($num_bytes) {
3567
- $start = $num_bytes > strlen($x) ? -strlen($x) : -$num_bytes;
3568
- $remainder = substr($x, $start);
3569
- $x = substr($x, 0, -$num_bytes);
3570
- }
3571
-
3572
- $carry = 0;
3573
- $carry_shift = 8 - $shift;
3574
- for ($i = 0; $i < strlen($x); ++$i) {
3575
- $temp = (ord($x[$i]) >> $shift) | $carry;
3576
- $carry = (ord($x[$i]) << $carry_shift) & 0xFF;
3577
- $x[$i] = chr($temp);
3578
- }
3579
- $x = ltrim($x, chr(0));
3580
-
3581
- $remainder = chr($carry >> $carry_shift) . $remainder;
3582
-
3583
- return ltrim($remainder, chr(0));
3584
- }
3585
-
3586
- // one quirk about how the following functions are implemented is that PHP defines N to be an unsigned long
3587
- // at 32-bits, while java's longs are 64-bits.
3588
-
3589
- /**
3590
- * Converts 32-bit integers to bytes.
3591
- *
3592
- * @param Integer $x
3593
- * @return String
3594
- * @access private
3595
- */
3596
- function _int2bytes($x)
3597
- {
3598
- return ltrim(pack('N', $x), chr(0));
3599
- }
3600
-
3601
- /**
3602
- * Converts bytes to 32-bit integers
3603
- *
3604
- * @param String $x
3605
- * @return Integer
3606
- * @access private
3607
- */
3608
- function _bytes2int($x)
3609
- {
3610
- $temp = unpack('Nint', str_pad($x, 4, chr(0), STR_PAD_LEFT));
3611
- return $temp['int'];
3612
- }
3613
-
3614
- /**
3615
- * DER-encode an integer
3616
- *
3617
- * The ability to DER-encode integers is needed to create RSA public keys for use with OpenSSL
3618
- *
3619
- * @see modPow()
3620
- * @access private
3621
- * @param Integer $length
3622
- * @return String
3623
- */
3624
- function _encodeASN1Length($length)
3625
- {
3626
- if ($length <= 0x7F) {
3627
- return chr($length);
3628
- }
3629
-
3630
- $temp = ltrim(pack('N', $length), chr(0));
3631
- return pack('Ca*', 0x80 | strlen($temp), $temp);
3632
- }
3633
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * Pure-PHP arbitrary precision integer arithmetic library.
5
+ *
6
+ * Supports base-2, base-10, base-16, and base-256 numbers. Uses the GMP or BCMath extensions, if available,
7
+ * and an internal implementation, otherwise.
8
+ *
9
+ * PHP versions 4 and 5
10
+ *
11
+ * {@internal (all DocBlock comments regarding implementation - such as the one that follows - refer to the
12
+ * {@link MATH_BIGINTEGER_MODE_INTERNAL MATH_BIGINTEGER_MODE_INTERNAL} mode)
13
+ *
14
+ * Math_BigInteger uses base-2**26 to perform operations such as multiplication and division and
15
+ * base-2**52 (ie. two base 2**26 digits) to perform addition and subtraction. Because the largest possible
16
+ * value when multiplying two base-2**26 numbers together is a base-2**52 number, double precision floating
17
+ * point numbers - numbers that should be supported on most hardware and whose significand is 53 bits - are
18
+ * used. As a consequence, bitwise operators such as >> and << cannot be used, nor can the modulo operator %,
19
+ * which only supports integers. Although this fact will slow this library down, the fact that such a high
20
+ * base is being used should more than compensate.
21
+ *
22
+ * Numbers are stored in {@link http://en.wikipedia.org/wiki/Endianness little endian} format. ie.
23
+ * (new Math_BigInteger(pow(2, 26)))->value = array(0, 1)
24
+ *
25
+ * Useful resources are as follows:
26
+ *
27
+ * - {@link http://www.cacr.math.uwaterloo.ca/hac/about/chap14.pdf Handbook of Applied Cryptography (HAC)}
28
+ * - {@link http://math.libtomcrypt.com/files/tommath.pdf Multi-Precision Math (MPM)}
29
+ * - Java's BigInteger classes. See /j2se/src/share/classes/java/math in jdk-1_5_0-src-jrl.zip
30
+ *
31
+ * Here's an example of how to use this library:
32
+ * <code>
33
+ * <?php
34
+ * include 'Math/BigInteger.php';
35
+ *
36
+ * $a = new Math_BigInteger(2);
37
+ * $b = new Math_BigInteger(3);
38
+ *
39
+ * $c = $a->add($b);
40
+ *
41
+ * echo $c->toString(); // outputs 5
42
+ * ?>
43
+ * </code>
44
+ *
45
+ * LICENSE: Permission is hereby granted, free of charge, to any person obtaining a copy
46
+ * of this software and associated documentation files (the "Software"), to deal
47
+ * in the Software without restriction, including without limitation the rights
48
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
49
+ * copies of the Software, and to permit persons to whom the Software is
50
+ * furnished to do so, subject to the following conditions:
51
+ *
52
+ * The above copyright notice and this permission notice shall be included in
53
+ * all copies or substantial portions of the Software.
54
+ *
55
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
56
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
57
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
58
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
59
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
60
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
61
+ * THE SOFTWARE.
62
+ *
63
+ * @category Math
64
+ * @package Math_BigInteger
65
+ * @author Jim Wigginton <terrafrost@php.net>
66
+ * @copyright MMVI Jim Wigginton
67
+ * @license http://www.opensource.org/licenses/mit-license.html MIT License
68
+ * @link http://pear.php.net/package/Math_BigInteger
69
+ */
70
+
71
+ /**#@+
72
+ * Reduction constants
73
+ *
74
+ * @access private
75
+ * @see Math_BigInteger::_reduce()
76
+ */
77
+ /**
78
+ * @see Math_BigInteger::_montgomery()
79
+ * @see Math_BigInteger::_prepMontgomery()
80
+ */
81
+ define('MATH_BIGINTEGER_MONTGOMERY', 0);
82
+ /**
83
+ * @see Math_BigInteger::_barrett()
84
+ */
85
+ define('MATH_BIGINTEGER_BARRETT', 1);
86
+ /**
87
+ * @see Math_BigInteger::_mod2()
88
+ */
89
+ define('MATH_BIGINTEGER_POWEROF2', 2);
90
+ /**
91
+ * @see Math_BigInteger::_remainder()
92
+ */
93
+ define('MATH_BIGINTEGER_CLASSIC', 3);
94
+ /**
95
+ * @see Math_BigInteger::__clone()
96
+ */
97
+ define('MATH_BIGINTEGER_NONE', 4);
98
+ /**#@-*/
99
+
100
+ /**#@+
101
+ * Array constants
102
+ *
103
+ * Rather than create a thousands and thousands of new Math_BigInteger objects in repeated function calls to add() and
104
+ * multiply() or whatever, we'll just work directly on arrays, taking them in as parameters and returning them.
105
+ *
106
+ * @access private
107
+ */
108
+ /**
109
+ * $result[MATH_BIGINTEGER_VALUE] contains the value.
110
+ */
111
+ define('MATH_BIGINTEGER_VALUE', 0);
112
+ /**
113
+ * $result[MATH_BIGINTEGER_SIGN] contains the sign.
114
+ */
115
+ define('MATH_BIGINTEGER_SIGN', 1);
116
+ /**#@-*/
117
+
118
+ /**#@+
119
+ * @access private
120
+ * @see Math_BigInteger::_montgomery()
121
+ * @see Math_BigInteger::_barrett()
122
+ */
123
+ /**
124
+ * Cache constants
125
+ *
126
+ * $cache[MATH_BIGINTEGER_VARIABLE] tells us whether or not the cached data is still valid.
127
+ */
128
+ define('MATH_BIGINTEGER_VARIABLE', 0);
129
+ /**
130
+ * $cache[MATH_BIGINTEGER_DATA] contains the cached data.
131
+ */
132
+ define('MATH_BIGINTEGER_DATA', 1);
133
+ /**#@-*/
134
+
135
+ /**#@+
136
+ * Mode constants.
137
+ *
138
+ * @access private
139
+ * @see Math_BigInteger::Math_BigInteger()
140
+ */
141
+ /**
142
+ * To use the pure-PHP implementation
143
+ */
144
+ define('MATH_BIGINTEGER_MODE_INTERNAL', 1);
145
+ /**
146
+ * To use the BCMath library
147
+ *
148
+ * (if enabled; otherwise, the internal implementation will be used)
149
+ */
150
+ define('MATH_BIGINTEGER_MODE_BCMATH', 2);
151
+ /**
152
+ * To use the GMP library
153
+ *
154
+ * (if present; otherwise, either the BCMath or the internal implementation will be used)
155
+ */
156
+ define('MATH_BIGINTEGER_MODE_GMP', 3);
157
+ /**#@-*/
158
+
159
+ /**
160
+ * Karatsuba Cutoff
161
+ *
162
+ * At what point do we switch between Karatsuba multiplication and schoolbook long multiplication?
163
+ *
164
+ * @access private
165
+ */
166
+ define('MATH_BIGINTEGER_KARATSUBA_CUTOFF', 25);
167
+
168
+ /**
169
+ * Pure-PHP arbitrary precision integer arithmetic library. Supports base-2, base-10, base-16, and base-256
170
+ * numbers.
171
+ *
172
+ * @package Math_BigInteger
173
+ * @author Jim Wigginton <terrafrost@php.net>
174
+ * @access public
175
+ */
176
+ class Math_BigInteger
177
+ {
178
+ /**
179
+ * Holds the BigInteger's value.
180
+ *
181
+ * @var Array
182
+ * @access private
183
+ */
184
+ var $value;
185
+
186
+ /**
187
+ * Holds the BigInteger's magnitude.
188
+ *
189
+ * @var Boolean
190
+ * @access private
191
+ */
192
+ var $is_negative = false;
193
+
194
+ /**
195
+ * Random number generator function
196
+ *
197
+ * @see setRandomGenerator()
198
+ * @access private
199
+ */
200
+ var $generator = 'mt_rand';
201
+
202
+ /**
203
+ * Precision
204
+ *
205
+ * @see setPrecision()
206
+ * @access private
207
+ */
208
+ var $precision = -1;
209
+
210
+ /**
211
+ * Precision Bitmask
212
+ *
213
+ * @see setPrecision()
214
+ * @access private
215
+ */
216
+ var $bitmask = false;
217
+
218
+ /**
219
+ * Mode independent value used for serialization.
220
+ *
221
+ * If the bcmath or gmp extensions are installed $this->value will be a non-serializable resource, hence the need for
222
+ * a variable that'll be serializable regardless of whether or not extensions are being used. Unlike $this->value,
223
+ * however, $this->hex is only calculated when $this->__sleep() is called.
224
+ *
225
+ * @see __sleep()
226
+ * @see __wakeup()
227
+ * @var String
228
+ * @access private
229
+ */
230
+ var $hex;
231
+
232
+ /**
233
+ * Converts base-2, base-10, base-16, and binary strings (base-256) to BigIntegers.
234
+ *
235
+ * If the second parameter - $base - is negative, then it will be assumed that the number's are encoded using
236
+ * two's compliment. The sole exception to this is -10, which is treated the same as 10 is.
237
+ *
238
+ * Here's an example:
239
+ * <code>
240
+ * <?php
241
+ * include 'Math/BigInteger.php';
242
+ *
243
+ * $a = new Math_BigInteger('0x32', 16); // 50 in base-16
244
+ *
245
+ * echo $a->toString(); // outputs 50
246
+ * ?>
247
+ * </code>
248
+ *
249
+ * @param optional $x base-10 number or base-$base number if $base set.
250
+ * @param optional integer $base
251
+ * @return Math_BigInteger
252
+ * @access public
253
+ */
254
+ function Math_BigInteger($x = 0, $base = 10)
255
+ {
256
+ if ( !defined('MATH_BIGINTEGER_MODE') ) {
257
+ switch (true) {
258
+ case extension_loaded('gmp'):
259
+ define('MATH_BIGINTEGER_MODE', MATH_BIGINTEGER_MODE_GMP);
260
+ break;
261
+ case extension_loaded('bcmath'):
262
+ define('MATH_BIGINTEGER_MODE', MATH_BIGINTEGER_MODE_BCMATH);
263
+ break;
264
+ default:
265
+ define('MATH_BIGINTEGER_MODE', MATH_BIGINTEGER_MODE_INTERNAL);
266
+ }
267
+ }
268
+
269
+ if (function_exists('openssl_public_encrypt') && !defined('MATH_BIGINTEGER_OPENSSL_DISABLE') && !defined('MATH_BIGINTEGER_OPENSSL_ENABLED')) {
270
+ // some versions of XAMPP have mismatched versions of OpenSSL which causes it not to work
271
+ ob_start();
272
+ @phpinfo();
273
+ $content = ob_get_contents();
274
+ ob_end_clean();
275
+
276
+ preg_match_all('#OpenSSL (Header|Library) Version(.*)#im', $content, $matches);
277
+
278
+ $versions = array();
279
+ if (!empty($matches[1])) {
280
+ for ($i = 0; $i < count($matches[1]); $i++) {
281
+ $versions[$matches[1][$i]] = trim(str_replace('=>', '', strip_tags($matches[2][$i])));
282
+ }
283
+ }
284
+
285
+ // it doesn't appear that OpenSSL versions were reported upon until PHP 5.3+
286
+ switch (true) {
287
+ case !isset($versions['Header']):
288
+ case !isset($versions['Library']):
289
+ case $versions['Header'] == $versions['Library']:
290
+ define('MATH_BIGINTEGER_OPENSSL_ENABLED', true);
291
+ break;
292
+ default:
293
+ define('MATH_BIGINTEGER_OPENSSL_DISABLE', true);
294
+ }
295
+ }
296
+
297
+ if (!defined('PHP_INT_SIZE')) {
298
+ define('PHP_INT_SIZE', 4);
299
+ }
300
+
301
+ if (!defined('MATH_BIGINTEGER_BASE') && MATH_BIGINTEGER_MODE == MATH_BIGINTEGER_MODE_INTERNAL) {
302
+ switch (PHP_INT_SIZE) {
303
+ case 8: // use 64-bit integers if int size is 8 bytes
304
+ define('MATH_BIGINTEGER_BASE', 31);
305
+ define('MATH_BIGINTEGER_BASE_FULL', 0x80000000);
306
+ define('MATH_BIGINTEGER_MAX_DIGIT', 0x7FFFFFFF);
307
+ define('MATH_BIGINTEGER_MSB', 0x40000000);
308
+ // 10**9 is the closest we can get to 2**31 without passing it
309
+ define('MATH_BIGINTEGER_MAX10', 1000000000);
310
+ define('MATH_BIGINTEGER_MAX10_LEN', 9);
311
+ // the largest digit that may be used in addition / subtraction
312
+ define('MATH_BIGINTEGER_MAX_DIGIT2', pow(2, 62));
313
+ break;
314
+ //case 4: // use 64-bit floats if int size is 4 bytes
315
+ default:
316
+ define('MATH_BIGINTEGER_BASE', 26);
317
+ define('MATH_BIGINTEGER_BASE_FULL', 0x4000000);
318
+ define('MATH_BIGINTEGER_MAX_DIGIT', 0x3FFFFFF);
319
+ define('MATH_BIGINTEGER_MSB', 0x2000000);
320
+ // 10**7 is the closest to 2**26 without passing it
321
+ define('MATH_BIGINTEGER_MAX10', 10000000);
322
+ define('MATH_BIGINTEGER_MAX10_LEN', 7);
323
+ // the largest digit that may be used in addition / subtraction
324
+ // we do pow(2, 52) instead of using 4503599627370496 directly because some
325
+ // PHP installations will truncate 4503599627370496.
326
+ define('MATH_BIGINTEGER_MAX_DIGIT2', pow(2, 52));
327
+ }
328
+ }
329
+
330
+ switch ( MATH_BIGINTEGER_MODE ) {
331
+ case MATH_BIGINTEGER_MODE_GMP:
332
+ switch (true) {
333
+ case is_resource($x) && get_resource_type($x) == 'GMP integer':
334
+ // PHP 5.6 switched GMP from using resources to objects
335
+ case is_object($x) && get_class($x) == 'GMP':
336
+ $this->value = $x;
337
+ return;
338
+ }
339
+ $this->value = gmp_init(0);
340
+ break;
341
+ case MATH_BIGINTEGER_MODE_BCMATH:
342
+ $this->value = '0';
343
+ break;
344
+ default:
345
+ $this->value = array();
346
+ }
347
+
348
+ // '0' counts as empty() but when the base is 256 '0' is equal to ord('0') or 48
349
+ // '0' is the only value like this per http://php.net/empty
350
+ if (empty($x) && (abs($base) != 256 || $x !== '0')) {
351
+ return;
352
+ }
353
+
354
+ switch ($base) {
355
+ case -256:
356
+ if (ord($x[0]) & 0x80) {
357
+ $x = ~$x;
358
+ $this->is_negative = true;
359
+ }
360
+ case 256:
361
+ switch ( MATH_BIGINTEGER_MODE ) {
362
+ case MATH_BIGINTEGER_MODE_GMP:
363
+ $sign = $this->is_negative ? '-' : '';
364
+ $this->value = gmp_init($sign . '0x' . bin2hex($x));
365
+ break;
366
+ case MATH_BIGINTEGER_MODE_BCMATH:
367
+ // round $len to the nearest 4 (thanks, DavidMJ!)
368
+ $len = (strlen($x) + 3) & 0xFFFFFFFC;
369
+
370
+ $x = str_pad($x, $len, chr(0), STR_PAD_LEFT);
371
+
372
+ for ($i = 0; $i < $len; $i+= 4) {
373
+ $this->value = bcmul($this->value, '4294967296', 0); // 4294967296 == 2**32
374
+ $this->value = bcadd($this->value, 0x1000000 * ord($x[$i]) + ((ord($x[$i + 1]) << 16) | (ord($x[$i + 2]) << 8) | ord($x[$i + 3])), 0);
375
+ }
376
+
377
+ if ($this->is_negative) {
378
+ $this->value = '-' . $this->value;
379
+ }
380
+
381
+ break;
382
+ // converts a base-2**8 (big endian / msb) number to base-2**26 (little endian / lsb)
383
+ default:
384
+ while (strlen($x)) {
385
+ $this->value[] = $this->_bytes2int($this->_base256_rshift($x, MATH_BIGINTEGER_BASE));
386
+ }
387
+ }
388
+
389
+ if ($this->is_negative) {
390
+ if (MATH_BIGINTEGER_MODE != MATH_BIGINTEGER_MODE_INTERNAL) {
391
+ $this->is_negative = false;
392
+ }
393
+ $temp = $this->add(new Math_BigInteger('-1'));
394
+ $this->value = $temp->value;
395
+ }
396
+ break;
397
+ case 16:
398
+ case -16:
399
+ if ($base > 0 && $x[0] == '-') {
400
+ $this->is_negative = true;
401
+ $x = substr($x, 1);
402
+ }
403
+
404
+ $x = preg_replace('#^(?:0x)?([A-Fa-f0-9]*).*#', '$1', $x);
405
+
406
+ $is_negative = false;
407
+ if ($base < 0 && hexdec($x[0]) >= 8) {
408
+ $this->is_negative = $is_negative = true;
409
+ $x = bin2hex(~pack('H*', $x));
410
+ }
411
+
412
+ switch ( MATH_BIGINTEGER_MODE ) {
413
+ case MATH_BIGINTEGER_MODE_GMP:
414
+ $temp = $this->is_negative ? '-0x' . $x : '0x' . $x;
415
+ $this->value = gmp_init($temp);
416
+ $this->is_negative = false;
417
+ break;
418
+ case MATH_BIGINTEGER_MODE_BCMATH:
419
+ $x = ( strlen($x) & 1 ) ? '0' . $x : $x;
420
+ $temp = new Math_BigInteger(pack('H*', $x), 256);
421
+ $this->value = $this->is_negative ? '-' . $temp->value : $temp->value;
422
+ $this->is_negative = false;
423
+ break;
424
+ default:
425
+ $x = ( strlen($x) & 1 ) ? '0' . $x : $x;
426
+ $temp = new Math_BigInteger(pack('H*', $x), 256);
427
+ $this->value = $temp->value;
428
+ }
429
+
430
+ if ($is_negative) {
431
+ $temp = $this->add(new Math_BigInteger('-1'));
432
+ $this->value = $temp->value;
433
+ }
434
+ break;
435
+ case 10:
436
+ case -10:
437
+ // (?<!^)(?:-).*: find any -'s that aren't at the beginning and then any characters that follow that
438
+ // (?<=^|-)0*: find any 0's that are preceded by the start of the string or by a - (ie. octals)
439
+ // [^-0-9].*: find any non-numeric characters and then any characters that follow that
440
+ $x = preg_replace('#(?<!^)(?:-).*|(?<=^|-)0*|[^-0-9].*#', '', $x);
441
+
442
+ switch ( MATH_BIGINTEGER_MODE ) {
443
+ case MATH_BIGINTEGER_MODE_GMP:
444
+ $this->value = gmp_init($x);
445
+ break;
446
+ case MATH_BIGINTEGER_MODE_BCMATH:
447
+ // explicitly casting $x to a string is necessary, here, since doing $x[0] on -1 yields different
448
+ // results then doing it on '-1' does (modInverse does $x[0])
449
+ $this->value = $x === '-' ? '0' : (string) $x;
450
+ break;
451
+ default:
452
+ $temp = new Math_BigInteger();
453
+
454
+ $multiplier = new Math_BigInteger();
455
+ $multiplier->value = array(MATH_BIGINTEGER_MAX10);
456
+
457
+ if ($x[0] == '-') {
458
+ $this->is_negative = true;
459
+ $x = substr($x, 1);
460
+ }
461
+
462
+ $x = str_pad($x, strlen($x) + ((MATH_BIGINTEGER_MAX10_LEN - 1) * strlen($x)) % MATH_BIGINTEGER_MAX10_LEN, 0, STR_PAD_LEFT);
463
+ while (strlen($x)) {
464
+ $temp = $temp->multiply($multiplier);
465
+ $temp = $temp->add(new Math_BigInteger($this->_int2bytes(substr($x, 0, MATH_BIGINTEGER_MAX10_LEN)), 256));
466
+ $x = substr($x, MATH_BIGINTEGER_MAX10_LEN);
467
+ }
468
+
469
+ $this->value = $temp->value;
470
+ }
471
+ break;
472
+ case 2: // base-2 support originally implemented by Lluis Pamies - thanks!
473
+ case -2:
474
+ if ($base > 0 && $x[0] == '-') {
475
+ $this->is_negative = true;
476
+ $x = substr($x, 1);
477
+ }
478
+
479
+ $x = preg_replace('#^([01]*).*#', '$1', $x);
480
+ $x = str_pad($x, strlen($x) + (3 * strlen($x)) % 4, 0, STR_PAD_LEFT);
481
+
482
+ $str = '0x';
483
+ while (strlen($x)) {
484
+ $part = substr($x, 0, 4);
485
+ $str.= dechex(bindec($part));
486
+ $x = substr($x, 4);
487
+ }
488
+
489
+ if ($this->is_negative) {
490
+ $str = '-' . $str;
491
+ }
492
+
493
+ $temp = new Math_BigInteger($str, 8 * $base); // ie. either -16 or +16
494
+ $this->value = $temp->value;
495
+ $this->is_negative = $temp->is_negative;
496
+
497
+ break;
498
+ default:
499
+ // base not supported, so we'll let $this == 0
500
+ }
501
+ }
502
+
503
+ /**
504
+ * Converts a BigInteger to a byte string (eg. base-256).
505
+ *
506
+ * Negative numbers are saved as positive numbers, unless $twos_compliment is set to true, at which point, they're
507
+ * saved as two's compliment.
508
+ *
509
+ * Here's an example:
510
+ * <code>
511
+ * <?php
512
+ * include 'Math/BigInteger.php';
513
+ *
514
+ * $a = new Math_BigInteger('65');
515
+ *
516
+ * echo $a->toBytes(); // outputs chr(65)
517
+ * ?>
518
+ * </code>
519
+ *
520
+ * @param Boolean $twos_compliment
521
+ * @return String
522
+ * @access public
523
+ * @internal Converts a base-2**26 number to base-2**8
524
+ */
525
+ function toBytes($twos_compliment = false)
526
+ {
527
+ if ($twos_compliment) {
528
+ $comparison = $this->compare(new Math_BigInteger());
529
+ if ($comparison == 0) {
530
+ return $this->precision > 0 ? str_repeat(chr(0), ($this->precision + 1) >> 3) : '';
531
+ }
532
+
533
+ $temp = $comparison < 0 ? $this->add(new Math_BigInteger(1)) : $this->copy();
534
+ $bytes = $temp->toBytes();
535
+
536
+ if (empty($bytes)) { // eg. if the number we're trying to convert is -1
537
+ $bytes = chr(0);
538
+ }
539
+
540
+ if (ord($bytes[0]) & 0x80) {
541
+ $bytes = chr(0) . $bytes;
542
+ }
543
+
544
+ return $comparison < 0 ? ~$bytes : $bytes;
545
+ }
546
+
547
+ switch ( MATH_BIGINTEGER_MODE ) {
548
+ case MATH_BIGINTEGER_MODE_GMP:
549
+ if (gmp_cmp($this->value, gmp_init(0)) == 0) {
550
+ return $this->precision > 0 ? str_repeat(chr(0), ($this->precision + 1) >> 3) : '';
551
+ }
552
+
553
+ $temp = gmp_strval(gmp_abs($this->value), 16);
554
+ $temp = ( strlen($temp) & 1 ) ? '0' . $temp : $temp;
555
+ $temp = pack('H*', $temp);
556
+
557
+ return $this->precision > 0 ?
558
+ substr(str_pad($temp, $this->precision >> 3, chr(0), STR_PAD_LEFT), -($this->precision >> 3)) :
559
+ ltrim($temp, chr(0));
560
+ case MATH_BIGINTEGER_MODE_BCMATH:
561
+ if ($this->value === '0') {
562
+ return $this->precision > 0 ? str_repeat(chr(0), ($this->precision + 1) >> 3) : '';
563
+ }
564
+
565
+ $value = '';
566
+ $current = $this->value;
567
+
568
+ if ($current[0] == '-') {
569
+ $current = substr($current, 1);
570
+ }
571
+
572
+ while (bccomp($current, '0', 0) > 0) {
573
+ $temp = bcmod($current, '16777216');
574
+ $value = chr($temp >> 16) . chr($temp >> 8) . chr($temp) . $value;
575
+ $current = bcdiv($current, '16777216', 0);
576
+ }
577
+
578
+ return $this->precision > 0 ?
579
+ substr(str_pad($value, $this->precision >> 3, chr(0), STR_PAD_LEFT), -($this->precision >> 3)) :
580
+ ltrim($value, chr(0));
581
+ }
582
+
583
+ if (!count($this->value)) {
584
+ return $this->precision > 0 ? str_repeat(chr(0), ($this->precision + 1) >> 3) : '';
585
+ }
586
+ $result = $this->_int2bytes($this->value[count($this->value) - 1]);
587
+
588
+ $temp = $this->copy();
589
+
590
+ for ($i = count($temp->value) - 2; $i >= 0; --$i) {
591
+ $temp->_base256_lshift($result, MATH_BIGINTEGER_BASE);
592
+ $result = $result | str_pad($temp->_int2bytes($temp->value[$i]), strlen($result), chr(0), STR_PAD_LEFT);
593
+ }
594
+
595
+ return $this->precision > 0 ?
596
+ str_pad(substr($result, -(($this->precision + 7) >> 3)), ($this->precision + 7) >> 3, chr(0), STR_PAD_LEFT) :
597
+ $result;
598
+ }
599
+
600
+ /**
601
+ * Converts a BigInteger to a hex string (eg. base-16)).
602
+ *
603
+ * Negative numbers are saved as positive numbers, unless $twos_compliment is set to true, at which point, they're
604
+ * saved as two's compliment.
605
+ *
606
+ * Here's an example:
607
+ * <code>
608
+ * <?php
609
+ * include 'Math/BigInteger.php';
610
+ *
611
+ * $a = new Math_BigInteger('65');
612
+ *
613
+ * echo $a->toHex(); // outputs '41'
614
+ * ?>
615
+ * </code>
616
+ *
617
+ * @param Boolean $twos_compliment
618
+ * @return String
619
+ * @access public
620
+ * @internal Converts a base-2**26 number to base-2**8
621
+ */
622
+ function toHex($twos_compliment = false)
623
+ {
624
+ return bin2hex($this->toBytes($twos_compliment));
625
+ }
626
+
627
+ /**
628
+ * Converts a BigInteger to a bit string (eg. base-2).
629
+ *
630
+ * Negative numbers are saved as positive numbers, unless $twos_compliment is set to true, at which point, they're
631
+ * saved as two's compliment.
632
+ *
633
+ * Here's an example:
634
+ * <code>
635
+ * <?php
636
+ * include 'Math/BigInteger.php';
637
+ *
638
+ * $a = new Math_BigInteger('65');
639
+ *
640
+ * echo $a->toBits(); // outputs '1000001'
641
+ * ?>
642
+ * </code>
643
+ *
644
+ * @param Boolean $twos_compliment
645
+ * @return String
646
+ * @access public
647
+ * @internal Converts a base-2**26 number to base-2**2
648
+ */
649
+ function toBits($twos_compliment = false)
650
+ {
651
+ $hex = $this->toHex($twos_compliment);
652
+ $bits = '';
653
+ for ($i = strlen($hex) - 8, $start = strlen($hex) & 7; $i >= $start; $i-=8) {
654
+ $bits = str_pad(decbin(hexdec(substr($hex, $i, 8))), 32, '0', STR_PAD_LEFT) . $bits;
655
+ }
656
+ if ($start) { // hexdec('') == 0
657
+ $bits = str_pad(decbin(hexdec(substr($hex, 0, $start))), 8, '0', STR_PAD_LEFT) . $bits;
658
+ }
659
+ $result = $this->precision > 0 ? substr($bits, -$this->precision) : ltrim($bits, '0');
660
+
661
+ if ($twos_compliment && $this->compare(new Math_BigInteger()) > 0 && $this->precision <= 0) {
662
+ return '0' . $result;
663
+ }
664
+
665
+ return $result;
666
+ }
667
+
668
+ /**
669
+ * Converts a BigInteger to a base-10 number.
670
+ *
671
+ * Here's an example:
672
+ * <code>
673
+ * <?php
674
+ * include 'Math/BigInteger.php';
675
+ *
676
+ * $a = new Math_BigInteger('50');
677
+ *
678
+ * echo $a->toString(); // outputs 50
679
+ * ?>
680
+ * </code>
681
+ *
682
+ * @return String
683
+ * @access public
684
+ * @internal Converts a base-2**26 number to base-10**7 (which is pretty much base-10)
685
+ */
686
+ function toString()
687
+ {
688
+ switch ( MATH_BIGINTEGER_MODE ) {
689
+ case MATH_BIGINTEGER_MODE_GMP:
690
+ return gmp_strval($this->value);
691
+ case MATH_BIGINTEGER_MODE_BCMATH:
692
+ if ($this->value === '0') {
693
+ return '0';
694
+ }
695
+
696
+ return ltrim($this->value, '0');
697
+ }
698
+
699
+ if (!count($this->value)) {
700
+ return '0';
701
+ }
702
+
703
+ $temp = $this->copy();
704
+ $temp->is_negative = false;
705
+
706
+ $divisor = new Math_BigInteger();
707
+ $divisor->value = array(MATH_BIGINTEGER_MAX10);
708
+ $result = '';
709
+ while (count($temp->value)) {
710
+ list($temp, $mod) = $temp->divide($divisor);
711
+ $result = str_pad(isset($mod->value[0]) ? $mod->value[0] : '', MATH_BIGINTEGER_MAX10_LEN, '0', STR_PAD_LEFT) . $result;
712
+ }
713
+ $result = ltrim($result, '0');
714
+ if (empty($result)) {
715
+ $result = '0';
716
+ }
717
+
718
+ if ($this->is_negative) {
719
+ $result = '-' . $result;
720
+ }
721
+
722
+ return $result;
723
+ }
724
+
725
+ /**
726
+ * Copy an object
727
+ *
728
+ * PHP5 passes objects by reference while PHP4 passes by value. As such, we need a function to guarantee
729
+ * that all objects are passed by value, when appropriate. More information can be found here:
730
+ *
731
+ * {@link http://php.net/language.oop5.basic#51624}
732
+ *
733
+ * @access public
734
+ * @see __clone()
735
+ * @return Math_BigInteger
736
+ */
737
+ function copy()
738
+ {
739
+ $temp = new Math_BigInteger();
740
+ $temp->value = $this->value;
741
+ $temp->is_negative = $this->is_negative;
742
+ $temp->generator = $this->generator;
743
+ $temp->precision = $this->precision;
744
+ $temp->bitmask = $this->bitmask;
745
+ return $temp;
746
+ }
747
+
748
+ /**
749
+ * __toString() magic method
750
+ *
751
+ * Will be called, automatically, if you're supporting just PHP5. If you're supporting PHP4, you'll need to call
752
+ * toString().
753
+ *
754
+ * @access public
755
+ * @internal Implemented per a suggestion by Techie-Michael - thanks!
756
+ */
757
+ function __toString()
758
+ {
759
+ return $this->toString();
760
+ }
761
+
762
+ /**
763
+ * __clone() magic method
764
+ *
765
+ * Although you can call Math_BigInteger::__toString() directly in PHP5, you cannot call Math_BigInteger::__clone()
766
+ * directly in PHP5. You can in PHP4 since it's not a magic method, but in PHP5, you have to call it by using the PHP5
767
+ * only syntax of $y = clone $x. As such, if you're trying to write an application that works on both PHP4 and PHP5,
768
+ * call Math_BigInteger::copy(), instead.
769
+ *
770
+ * @access public
771
+ * @see copy()
772
+ * @return Math_BigInteger
773
+ */
774
+ function __clone()
775
+ {
776
+ return $this->copy();
777
+ }
778
+
779
+ /**
780
+ * __sleep() magic method
781
+ *
782
+ * Will be called, automatically, when serialize() is called on a Math_BigInteger object.
783
+ *
784
+ * @see __wakeup()
785
+ * @access public
786
+ */
787
+ function __sleep()
788
+ {
789
+ $this->hex = $this->toHex(true);
790
+ $vars = array('hex');
791
+ if ($this->generator != 'mt_rand') {
792
+ $vars[] = 'generator';
793
+ }
794
+ if ($this->precision > 0) {
795
+ $vars[] = 'precision';
796
+ }
797
+ return $vars;
798
+
799
+ }
800
+
801
+ /**
802
+ * __wakeup() magic method
803
+ *
804
+ * Will be called, automatically, when unserialize() is called on a Math_BigInteger object.
805
+ *
806
+ * @see __sleep()
807
+ * @access public
808
+ */
809
+ function __wakeup()
810
+ {
811
+ $temp = new Math_BigInteger($this->hex, -16);
812
+ $this->value = $temp->value;
813
+ $this->is_negative = $temp->is_negative;
814
+ $this->setRandomGenerator($this->generator);
815
+ if ($this->precision > 0) {
816
+ // recalculate $this->bitmask
817
+ $this->setPrecision($this->precision);
818
+ }
819
+ }
820
+
821
+ /**
822
+ * Adds two BigIntegers.
823
+ *
824
+ * Here's an example:
825
+ * <code>
826
+ * <?php
827
+ * include 'Math/BigInteger.php';
828
+ *
829
+ * $a = new Math_BigInteger('10');
830
+ * $b = new Math_BigInteger('20');
831
+ *
832
+ * $c = $a->add($b);
833
+ *
834
+ * echo $c->toString(); // outputs 30
835
+ * ?>
836
+ * </code>
837
+ *
838
+ * @param Math_BigInteger $y
839
+ * @return Math_BigInteger
840
+ * @access public
841
+ * @internal Performs base-2**52 addition
842
+ */
843
+ function add($y)
844
+ {
845
+ switch ( MATH_BIGINTEGER_MODE ) {
846
+ case MATH_BIGINTEGER_MODE_GMP:
847
+ $temp = new Math_BigInteger();
848
+ $temp->value = gmp_add($this->value, $y->value);
849
+
850
+ return $this->_normalize($temp);
851
+ case MATH_BIGINTEGER_MODE_BCMATH:
852
+ $temp = new Math_BigInteger();
853
+ $temp->value = bcadd($this->value, $y->value, 0);
854
+
855
+ return $this->_normalize($temp);
856
+ }
857
+
858
+ $temp = $this->_add($this->value, $this->is_negative, $y->value, $y->is_negative);
859
+
860
+ $result = new Math_BigInteger();
861
+ $result->value = $temp[MATH_BIGINTEGER_VALUE];
862
+ $result->is_negative = $temp[MATH_BIGINTEGER_SIGN];
863
+
864
+ return $this->_normalize($result);
865
+ }
866
+
867
+ /**
868
+ * Performs addition.
869
+ *
870
+ * @param Array $x_value
871
+ * @param Boolean $x_negative
872
+ * @param Array $y_value
873
+ * @param Boolean $y_negative
874
+ * @return Array
875
+ * @access private
876
+ */
877
+ function _add($x_value, $x_negative, $y_value, $y_negative)
878
+ {
879
+ $x_size = count($x_value);
880
+ $y_size = count($y_value);
881
+
882
+ if ($x_size == 0) {
883
+ return array(
884
+ MATH_BIGINTEGER_VALUE => $y_value,
885
+ MATH_BIGINTEGER_SIGN => $y_negative
886
+ );
887
+ } else if ($y_size == 0) {
888
+ return array(
889
+ MATH_BIGINTEGER_VALUE => $x_value,
890
+ MATH_BIGINTEGER_SIGN => $x_negative
891
+ );
892
+ }
893
+
894
+ // subtract, if appropriate
895
+ if ( $x_negative != $y_negative ) {
896
+ if ( $x_value == $y_value ) {
897
+ return array(
898
+ MATH_BIGINTEGER_VALUE => array(),
899
+ MATH_BIGINTEGER_SIGN => false
900
+ );
901
+ }
902
+
903
+ $temp = $this->_subtract($x_value, false, $y_value, false);
904
+ $temp[MATH_BIGINTEGER_SIGN] = $this->_compare($x_value, false, $y_value, false) > 0 ?
905
+ $x_negative : $y_negative;
906
+
907
+ return $temp;
908
+ }
909
+
910
+ if ($x_size < $y_size) {
911
+ $size = $x_size;
912
+ $value = $y_value;
913
+ } else {
914
+ $size = $y_size;
915
+ $value = $x_value;
916
+ }
917
+
918
+ $value[count($value)] = 0; // just in case the carry adds an extra digit
919
+
920
+ $carry = 0;
921
+ for ($i = 0, $j = 1; $j < $size; $i+=2, $j+=2) {
922
+ $sum = $x_value[$j] * MATH_BIGINTEGER_BASE_FULL + $x_value[$i] + $y_value[$j] * MATH_BIGINTEGER_BASE_FULL + $y_value[$i] + $carry;
923
+ $carry = $sum >= MATH_BIGINTEGER_MAX_DIGIT2; // eg. floor($sum / 2**52); only possible values (in any base) are 0 and 1
924
+ $sum = $carry ? $sum - MATH_BIGINTEGER_MAX_DIGIT2 : $sum;
925
+
926
+ $temp = MATH_BIGINTEGER_BASE === 26 ? intval($sum / 0x4000000) : ($sum >> 31);
927
+
928
+ $value[$i] = (int) ($sum - MATH_BIGINTEGER_BASE_FULL * $temp); // eg. a faster alternative to fmod($sum, 0x4000000)
929
+ $value[$j] = $temp;
930
+ }
931
+
932
+ if ($j == $size) { // ie. if $y_size is odd
933
+ $sum = $x_value[$i] + $y_value[$i] + $carry;
934
+ $carry = $sum >= MATH_BIGINTEGER_BASE_FULL;
935
+ $value[$i] = $carry ? $sum - MATH_BIGINTEGER_BASE_FULL : $sum;
936
+ ++$i; // ie. let $i = $j since we've just done $value[$i]
937
+ }
938
+
939
+ if ($carry) {
940
+ for (; $value[$i] == MATH_BIGINTEGER_MAX_DIGIT; ++$i) {
941
+ $value[$i] = 0;
942
+ }
943
+ ++$value[$i];
944
+ }
945
+
946
+ return array(
947
+ MATH_BIGINTEGER_VALUE => $this->_trim($value),
948
+ MATH_BIGINTEGER_SIGN => $x_negative
949
+ );
950
+ }
951
+
952
+ /**
953
+ * Subtracts two BigIntegers.
954
+ *
955
+ * Here's an example:
956
+ * <code>
957
+ * <?php
958
+ * include 'Math/BigInteger.php';
959
+ *
960
+ * $a = new Math_BigInteger('10');
961
+ * $b = new Math_BigInteger('20');
962
+ *
963
+ * $c = $a->subtract($b);
964
+ *
965
+ * echo $c->toString(); // outputs -10
966
+ * ?>
967
+ * </code>
968
+ *
969
+ * @param Math_BigInteger $y
970
+ * @return Math_BigInteger
971
+ * @access public
972
+ * @internal Performs base-2**52 subtraction
973
+ */
974
+ function subtract($y)
975
+ {
976
+ switch ( MATH_BIGINTEGER_MODE ) {
977
+ case MATH_BIGINTEGER_MODE_GMP:
978
+ $temp = new Math_BigInteger();
979
+ $temp->value = gmp_sub($this->value, $y->value);
980
+
981
+ return $this->_normalize($temp);
982
+ case MATH_BIGINTEGER_MODE_BCMATH:
983
+ $temp = new Math_BigInteger();
984
+ $temp->value = bcsub($this->value, $y->value, 0);
985
+
986
+ return $this->_normalize($temp);
987
+ }
988
+
989
+ $temp = $this->_subtract($this->value, $this->is_negative, $y->value, $y->is_negative);
990
+
991
+ $result = new Math_BigInteger();
992
+ $result->value = $temp[MATH_BIGINTEGER_VALUE];
993
+ $result->is_negative = $temp[MATH_BIGINTEGER_SIGN];
994
+
995
+ return $this->_normalize($result);
996
+ }
997
+
998
+ /**
999
+ * Performs subtraction.
1000
+ *
1001
+ * @param Array $x_value
1002
+ * @param Boolean $x_negative
1003
+ * @param Array $y_value
1004
+ * @param Boolean $y_negative
1005
+ * @return Array
1006
+ * @access private
1007
+ */
1008
+ function _subtract($x_value, $x_negative, $y_value, $y_negative)
1009
+ {
1010
+ $x_size = count($x_value);
1011
+ $y_size = count($y_value);
1012
+
1013
+ if ($x_size == 0) {
1014
+ return array(
1015
+ MATH_BIGINTEGER_VALUE => $y_value,
1016
+ MATH_BIGINTEGER_SIGN => !$y_negative
1017
+ );
1018
+ } else if ($y_size == 0) {
1019
+ return array(
1020
+ MATH_BIGINTEGER_VALUE => $x_value,
1021
+ MATH_BIGINTEGER_SIGN => $x_negative
1022
+ );
1023
+ }
1024
+
1025
+ // add, if appropriate (ie. -$x - +$y or +$x - -$y)
1026
+ if ( $x_negative != $y_negative ) {
1027
+ $temp = $this->_add($x_value, false, $y_value, false);
1028
+ $temp[MATH_BIGINTEGER_SIGN] = $x_negative;
1029
+
1030
+ return $temp;
1031
+ }
1032
+
1033
+ $diff = $this->_compare($x_value, $x_negative, $y_value, $y_negative);
1034
+
1035
+ if ( !$diff ) {
1036
+ return array(
1037
+ MATH_BIGINTEGER_VALUE => array(),
1038
+ MATH_BIGINTEGER_SIGN => false
1039
+ );
1040
+ }
1041
+
1042
+ // switch $x and $y around, if appropriate.
1043
+ if ( (!$x_negative && $diff < 0) || ($x_negative && $diff > 0) ) {
1044
+ $temp = $x_value;
1045
+ $x_value = $y_value;
1046
+ $y_value = $temp;
1047
+
1048
+ $x_negative = !$x_negative;
1049
+
1050
+ $x_size = count($x_value);
1051
+ $y_size = count($y_value);
1052
+ }
1053
+
1054
+ // at this point, $x_value should be at least as big as - if not bigger than - $y_value
1055
+
1056
+ $carry = 0;
1057
+ for ($i = 0, $j = 1; $j < $y_size; $i+=2, $j+=2) {
1058
+ $sum = $x_value[$j] * MATH_BIGINTEGER_BASE_FULL + $x_value[$i] - $y_value[$j] * MATH_BIGINTEGER_BASE_FULL - $y_value[$i] - $carry;
1059
+ $carry = $sum < 0; // eg. floor($sum / 2**52); only possible values (in any base) are 0 and 1
1060
+ $sum = $carry ? $sum + MATH_BIGINTEGER_MAX_DIGIT2 : $sum;
1061
+
1062
+ $temp = MATH_BIGINTEGER_BASE === 26 ? intval($sum / 0x4000000) : ($sum >> 31);
1063
+
1064
+ $x_value[$i] = (int) ($sum - MATH_BIGINTEGER_BASE_FULL * $temp);
1065
+ $x_value[$j] = $temp;
1066
+ }
1067
+
1068
+ if ($j == $y_size) { // ie. if $y_size is odd
1069
+ $sum = $x_value[$i] - $y_value[$i] - $carry;
1070
+ $carry = $sum < 0;
1071
+ $x_value[$i] = $carry ? $sum + MATH_BIGINTEGER_BASE_FULL : $sum;
1072
+ ++$i;
1073
+ }
1074
+
1075
+ if ($carry) {
1076
+ for (; !$x_value[$i]; ++$i) {
1077
+ $x_value[$i] = MATH_BIGINTEGER_MAX_DIGIT;
1078
+ }
1079
+ --$x_value[$i];
1080
+ }
1081
+
1082
+ return array(
1083
+ MATH_BIGINTEGER_VALUE => $this->_trim($x_value),
1084
+ MATH_BIGINTEGER_SIGN => $x_negative
1085
+ );
1086
+ }
1087
+
1088
+ /**
1089
+ * Multiplies two BigIntegers
1090
+ *
1091
+ * Here's an example:
1092
+ * <code>
1093
+ * <?php
1094
+ * include 'Math/BigInteger.php';
1095
+ *
1096
+ * $a = new Math_BigInteger('10');
1097
+ * $b = new Math_BigInteger('20');
1098
+ *
1099
+ * $c = $a->multiply($b);
1100
+ *
1101
+ * echo $c->toString(); // outputs 200
1102
+ * ?>
1103
+ * </code>
1104
+ *
1105
+ * @param Math_BigInteger $x
1106
+ * @return Math_BigInteger
1107
+ * @access public
1108
+ */
1109
+ function multiply($x)
1110
+ {
1111
+ switch ( MATH_BIGINTEGER_MODE ) {
1112
+ case MATH_BIGINTEGER_MODE_GMP:
1113
+ $temp = new Math_BigInteger();
1114
+ $temp->value = gmp_mul($this->value, $x->value);
1115
+
1116
+ return $this->_normalize($temp);
1117
+ case MATH_BIGINTEGER_MODE_BCMATH:
1118
+ $temp = new Math_BigInteger();
1119
+ $temp->value = bcmul($this->value, $x->value, 0);
1120
+
1121
+ return $this->_normalize($temp);
1122
+ }
1123
+
1124
+ $temp = $this->_multiply($this->value, $this->is_negative, $x->value, $x->is_negative);
1125
+
1126
+ $product = new Math_BigInteger();
1127
+ $product->value = $temp[MATH_BIGINTEGER_VALUE];
1128
+ $product->is_negative = $temp[MATH_BIGINTEGER_SIGN];
1129
+
1130
+ return $this->_normalize($product);
1131
+ }
1132
+
1133
+ /**
1134
+ * Performs multiplication.
1135
+ *
1136
+ * @param Array $x_value
1137
+ * @param Boolean $x_negative
1138
+ * @param Array $y_value
1139
+ * @param Boolean $y_negative
1140
+ * @return Array
1141
+ * @access private
1142
+ */
1143
+ function _multiply($x_value, $x_negative, $y_value, $y_negative)
1144
+ {
1145
+ //if ( $x_value == $y_value ) {
1146
+ // return array(
1147
+ // MATH_BIGINTEGER_VALUE => $this->_square($x_value),
1148
+ // MATH_BIGINTEGER_SIGN => $x_sign != $y_value
1149
+ // );
1150
+ //}
1151
+
1152
+ $x_length = count($x_value);
1153
+ $y_length = count($y_value);
1154
+
1155
+ if ( !$x_length || !$y_length ) { // a 0 is being multiplied
1156
+ return array(
1157
+ MATH_BIGINTEGER_VALUE => array(),
1158
+ MATH_BIGINTEGER_SIGN => false
1159
+ );
1160
+ }
1161
+
1162
+ return array(
1163
+ MATH_BIGINTEGER_VALUE => min($x_length, $y_length) < 2 * MATH_BIGINTEGER_KARATSUBA_CUTOFF ?
1164
+ $this->_trim($this->_regularMultiply($x_value, $y_value)) :
1165
+ $this->_trim($this->_karatsuba($x_value, $y_value)),
1166
+ MATH_BIGINTEGER_SIGN => $x_negative != $y_negative
1167
+ );
1168
+ }
1169
+
1170
+ /**
1171
+ * Performs long multiplication on two BigIntegers
1172
+ *
1173
+ * Modeled after 'multiply' in MutableBigInteger.java.
1174
+ *
1175
+ * @param Array $x_value
1176
+ * @param Array $y_value
1177
+ * @return Array
1178
+ * @access private
1179
+ */
1180
+ function _regularMultiply($x_value, $y_value)
1181
+ {
1182
+ $x_length = count($x_value);
1183
+ $y_length = count($y_value);
1184
+
1185
+ if ( !$x_length || !$y_length ) { // a 0 is being multiplied
1186
+ return array();
1187
+ }
1188
+
1189
+ if ( $x_length < $y_length ) {
1190
+ $temp = $x_value;
1191
+ $x_value = $y_value;
1192
+ $y_value = $temp;
1193
+
1194
+ $x_length = count($x_value);
1195
+ $y_length = count($y_value);
1196
+ }
1197
+
1198
+ $product_value = $this->_array_repeat(0, $x_length + $y_length);
1199
+
1200
+ // the following for loop could be removed if the for loop following it
1201
+ // (the one with nested for loops) initially set $i to 0, but
1202
+ // doing so would also make the result in one set of unnecessary adds,
1203
+ // since on the outermost loops first pass, $product->value[$k] is going
1204
+ // to always be 0
1205
+
1206
+ $carry = 0;
1207
+
1208
+ for ($j = 0; $j < $x_length; ++$j) { // ie. $i = 0
1209
+ $temp = $x_value[$j] * $y_value[0] + $carry; // $product_value[$k] == 0
1210
+ $carry = MATH_BIGINTEGER_BASE === 26 ? intval($temp / 0x4000000) : ($temp >> 31);
1211
+ $product_value[$j] = (int) ($temp - MATH_BIGINTEGER_BASE_FULL * $carry);
1212
+ }
1213
+
1214
+ $product_value[$j] = $carry;
1215
+
1216
+ // the above for loop is what the previous comment was talking about. the
1217
+ // following for loop is the "one with nested for loops"
1218
+ for ($i = 1; $i < $y_length; ++$i) {
1219
+ $carry = 0;
1220
+
1221
+ for ($j = 0, $k = $i; $j < $x_length; ++$j, ++$k) {
1222
+ $temp = $product_value[$k] + $x_value[$j] * $y_value[$i] + $carry;
1223
+ $carry = MATH_BIGINTEGER_BASE === 26 ? intval($temp / 0x4000000) : ($temp >> 31);
1224
+ $product_value[$k] = (int) ($temp - MATH_BIGINTEGER_BASE_FULL * $carry);
1225
+ }
1226
+
1227
+ $product_value[$k] = $carry;
1228
+ }
1229
+
1230
+ return $product_value;
1231
+ }
1232
+
1233
+ /**
1234
+ * Performs Karatsuba multiplication on two BigIntegers
1235
+ *
1236
+ * See {@link http://en.wikipedia.org/wiki/Karatsuba_algorithm Karatsuba algorithm} and
1237
+ * {@link http://math.libtomcrypt.com/files/tommath.pdf#page=120 MPM 5.2.3}.
1238
+ *
1239
+ * @param Array $x_value
1240
+ * @param Array $y_value
1241
+ * @return Array
1242
+ * @access private
1243
+ */
1244
+ function _karatsuba($x_value, $y_value)
1245
+ {
1246
+ $m = min(count($x_value) >> 1, count($y_value) >> 1);
1247
+
1248
+ if ($m < MATH_BIGINTEGER_KARATSUBA_CUTOFF) {
1249
+ return $this->_regularMultiply($x_value, $y_value);
1250
+ }
1251
+
1252
+ $x1 = array_slice($x_value, $m);
1253
+ $x0 = array_slice($x_value, 0, $m);
1254
+ $y1 = array_slice($y_value, $m);
1255
+ $y0 = array_slice($y_value, 0, $m);
1256
+
1257
+ $z2 = $this->_karatsuba($x1, $y1);
1258
+ $z0 = $this->_karatsuba($x0, $y0);
1259
+
1260
+ $z1 = $this->_add($x1, false, $x0, false);
1261
+ $temp = $this->_add($y1, false, $y0, false);
1262
+ $z1 = $this->_karatsuba($z1[MATH_BIGINTEGER_VALUE], $temp[MATH_BIGINTEGER_VALUE]);
1263
+ $temp = $this->_add($z2, false, $z0, false);
1264
+ $z1 = $this->_subtract($z1, false, $temp[MATH_BIGINTEGER_VALUE], false);
1265
+
1266
+ $z2 = array_merge(array_fill(0, 2 * $m, 0), $z2);
1267
+ $z1[MATH_BIGINTEGER_VALUE] = array_merge(array_fill(0, $m, 0), $z1[MATH_BIGINTEGER_VALUE]);
1268
+
1269
+ $xy = $this->_add($z2, false, $z1[MATH_BIGINTEGER_VALUE], $z1[MATH_BIGINTEGER_SIGN]);
1270
+ $xy = $this->_add($xy[MATH_BIGINTEGER_VALUE], $xy[MATH_BIGINTEGER_SIGN], $z0, false);
1271
+
1272
+ return $xy[MATH_BIGINTEGER_VALUE];
1273
+ }
1274
+
1275
+ /**
1276
+ * Performs squaring
1277
+ *
1278
+ * @param Array $x
1279
+ * @return Array
1280
+ * @access private
1281
+ */
1282
+ function _square($x = false)
1283
+ {
1284
+ return count($x) < 2 * MATH_BIGINTEGER_KARATSUBA_CUTOFF ?
1285
+ $this->_trim($this->_baseSquare($x)) :
1286
+ $this->_trim($this->_karatsubaSquare($x));
1287
+ }
1288
+
1289
+ /**
1290
+ * Performs traditional squaring on two BigIntegers
1291
+ *
1292
+ * Squaring can be done faster than multiplying a number by itself can be. See
1293
+ * {@link http://www.cacr.math.uwaterloo.ca/hac/about/chap14.pdf#page=7 HAC 14.2.4} /
1294
+ * {@link http://math.libtomcrypt.com/files/tommath.pdf#page=141 MPM 5.3} for more information.
1295
+ *
1296
+ * @param Array $value
1297
+ * @return Array
1298
+ * @access private
1299
+ */
1300
+ function _baseSquare($value)
1301
+ {
1302
+ if ( empty($value) ) {
1303
+ return array();
1304
+ }
1305
+ $square_value = $this->_array_repeat(0, 2 * count($value));
1306
+
1307
+ for ($i = 0, $max_index = count($value) - 1; $i <= $max_index; ++$i) {
1308
+ $i2 = $i << 1;
1309
+
1310
+ $temp = $square_value[$i2] + $value[$i] * $value[$i];
1311
+ $carry = MATH_BIGINTEGER_BASE === 26 ? intval($temp / 0x4000000) : ($temp >> 31);
1312
+ $square_value[$i2] = (int) ($temp - MATH_BIGINTEGER_BASE_FULL * $carry);
1313
+
1314
+ // note how we start from $i+1 instead of 0 as we do in multiplication.
1315
+ for ($j = $i + 1, $k = $i2 + 1; $j <= $max_index; ++$j, ++$k) {
1316
+ $temp = $square_value[$k] + 2 * $value[$j] * $value[$i] + $carry;
1317
+ $carry = MATH_BIGINTEGER_BASE === 26 ? intval($temp / 0x4000000) : ($temp >> 31);
1318
+ $square_value[$k] = (int) ($temp - MATH_BIGINTEGER_BASE_FULL * $carry);
1319
+ }
1320
+
1321
+ // the following line can yield values larger 2**15. at this point, PHP should switch
1322
+ // over to floats.
1323
+ $square_value[$i + $max_index + 1] = $carry;
1324
+ }
1325
+
1326
+ return $square_value;
1327
+ }
1328
+
1329
+ /**
1330
+ * Performs Karatsuba "squaring" on two BigIntegers
1331
+ *
1332
+ * See {@link http://en.wikipedia.org/wiki/Karatsuba_algorithm Karatsuba algorithm} and
1333
+ * {@link http://math.libtomcrypt.com/files/tommath.pdf#page=151 MPM 5.3.4}.
1334
+ *
1335
+ * @param Array $value
1336
+ * @return Array
1337
+ * @access private
1338
+ */
1339
+ function _karatsubaSquare($value)
1340
+ {
1341
+ $m = count($value) >> 1;
1342
+
1343
+ if ($m < MATH_BIGINTEGER_KARATSUBA_CUTOFF) {
1344
+ return $this->_baseSquare($value);
1345
+ }
1346
+
1347
+ $x1 = array_slice($value, $m);
1348
+ $x0 = array_slice($value, 0, $m);
1349
+
1350
+ $z2 = $this->_karatsubaSquare($x1);
1351
+ $z0 = $this->_karatsubaSquare($x0);
1352
+
1353
+ $z1 = $this->_add($x1, false, $x0, false);
1354
+ $z1 = $this->_karatsubaSquare($z1[MATH_BIGINTEGER_VALUE]);
1355
+ $temp = $this->_add($z2, false, $z0, false);
1356
+ $z1 = $this->_subtract($z1, false, $temp[MATH_BIGINTEGER_VALUE], false);
1357
+
1358
+ $z2 = array_merge(array_fill(0, 2 * $m, 0), $z2);
1359
+ $z1[MATH_BIGINTEGER_VALUE] = array_merge(array_fill(0, $m, 0), $z1[MATH_BIGINTEGER_VALUE]);
1360
+
1361
+ $xx = $this->_add($z2, false, $z1[MATH_BIGINTEGER_VALUE], $z1[MATH_BIGINTEGER_SIGN]);
1362
+ $xx = $this->_add($xx[MATH_BIGINTEGER_VALUE], $xx[MATH_BIGINTEGER_SIGN], $z0, false);
1363
+
1364
+ return $xx[MATH_BIGINTEGER_VALUE];
1365
+ }
1366
+
1367
+ /**
1368
+ * Divides two BigIntegers.
1369
+ *
1370
+ * Returns an array whose first element contains the quotient and whose second element contains the
1371
+ * "common residue". If the remainder would be positive, the "common residue" and the remainder are the
1372
+ * same. If the remainder would be negative, the "common residue" is equal to the sum of the remainder
1373
+ * and the divisor (basically, the "common residue" is the first positive modulo).
1374
+ *
1375
+ * Here's an example:
1376
+ * <code>
1377
+ * <?php
1378
+ * include 'Math/BigInteger.php';
1379
+ *
1380
+ * $a = new Math_BigInteger('10');
1381
+ * $b = new Math_BigInteger('20');
1382
+ *
1383
+ * list($quotient, $remainder) = $a->divide($b);
1384
+ *
1385
+ * echo $quotient->toString(); // outputs 0
1386
+ * echo "\r\n";
1387
+ * echo $remainder->toString(); // outputs 10
1388
+ * ?>
1389
+ * </code>
1390
+ *
1391
+ * @param Math_BigInteger $y
1392
+ * @return Array
1393
+ * @access public
1394
+ * @internal This function is based off of {@link http://www.cacr.math.uwaterloo.ca/hac/about/chap14.pdf#page=9 HAC 14.20}.
1395
+ */
1396
+ function divide($y)
1397
+ {
1398
+ switch ( MATH_BIGINTEGER_MODE ) {
1399
+ case MATH_BIGINTEGER_MODE_GMP:
1400
+ $quotient = new Math_BigInteger();
1401
+ $remainder = new Math_BigInteger();
1402
+
1403
+ list($quotient->value, $remainder->value) = gmp_div_qr($this->value, $y->value);
1404
+
1405
+ if (gmp_sign($remainder->value) < 0) {
1406
+ $remainder->value = gmp_add($remainder->value, gmp_abs($y->value));
1407
+ }
1408
+
1409
+ return array($this->_normalize($quotient), $this->_normalize($remainder));
1410
+ case MATH_BIGINTEGER_MODE_BCMATH:
1411
+ $quotient = new Math_BigInteger();
1412
+ $remainder = new Math_BigInteger();
1413
+
1414
+ $quotient->value = bcdiv($this->value, $y->value, 0);
1415
+ $remainder->value = bcmod($this->value, $y->value);
1416
+
1417
+ if ($remainder->value[0] == '-') {
1418
+ $remainder->value = bcadd($remainder->value, $y->value[0] == '-' ? substr($y->value, 1) : $y->value, 0);
1419
+ }
1420
+
1421
+ return array($this->_normalize($quotient), $this->_normalize($remainder));
1422
+ }
1423
+
1424
+ if (count($y->value) == 1) {
1425
+ list($q, $r) = $this->_divide_digit($this->value, $y->value[0]);
1426
+ $quotient = new Math_BigInteger();
1427
+ $remainder = new Math_BigInteger();
1428
+ $quotient->value = $q;
1429
+ $remainder->value = array($r);
1430
+ $quotient->is_negative = $this->is_negative != $y->is_negative;
1431
+ return array($this->_normalize($quotient), $this->_normalize($remainder));
1432
+ }
1433
+
1434
+ static $zero;
1435
+ if ( !isset($zero) ) {
1436
+ $zero = new Math_BigInteger();
1437
+ }
1438
+
1439
+ $x = $this->copy();
1440
+ $y = $y->copy();
1441
+
1442
+ $x_sign = $x->is_negative;
1443
+ $y_sign = $y->is_negative;
1444
+
1445
+ $x->is_negative = $y->is_negative = false;
1446
+
1447
+ $diff = $x->compare($y);
1448
+
1449
+ if ( !$diff ) {
1450
+ $temp = new Math_BigInteger();
1451
+ $temp->value = array(1);
1452
+ $temp->is_negative = $x_sign != $y_sign;
1453
+ return array($this->_normalize($temp), $this->_normalize(new Math_BigInteger()));
1454
+ }
1455
+
1456
+ if ( $diff < 0 ) {
1457
+ // if $x is negative, "add" $y.
1458
+ if ( $x_sign ) {
1459
+ $x = $y->subtract($x);
1460
+ }
1461
+ return array($this->_normalize(new Math_BigInteger()), $this->_normalize($x));
1462
+ }
1463
+
1464
+ // normalize $x and $y as described in HAC 14.23 / 14.24
1465
+ $msb = $y->value[count($y->value) - 1];
1466
+ for ($shift = 0; !($msb & MATH_BIGINTEGER_MSB); ++$shift) {
1467
+ $msb <<= 1;
1468
+ }
1469
+ $x->_lshift($shift);
1470
+ $y->_lshift($shift);
1471
+ $y_value = &$y->value;
1472
+
1473
+ $x_max = count($x->value) - 1;
1474
+ $y_max = count($y->value) - 1;
1475
+
1476
+ $quotient = new Math_BigInteger();
1477
+ $quotient_value = &$quotient->value;
1478
+ $quotient_value = $this->_array_repeat(0, $x_max - $y_max + 1);
1479
+
1480
+ static $temp, $lhs, $rhs;
1481
+ if (!isset($temp)) {
1482
+ $temp = new Math_BigInteger();
1483
+ $lhs = new Math_BigInteger();
1484
+ $rhs = new Math_BigInteger();
1485
+ }
1486
+ $temp_value = &$temp->value;
1487
+ $rhs_value = &$rhs->value;
1488
+
1489
+ // $temp = $y << ($x_max - $y_max-1) in base 2**26
1490
+ $temp_value = array_merge($this->_array_repeat(0, $x_max - $y_max), $y_value);
1491
+
1492
+ while ( $x->compare($temp) >= 0 ) {
1493
+ // calculate the "common residue"
1494
+ ++$quotient_value[$x_max - $y_max];
1495
+ $x = $x->subtract($temp);
1496
+ $x_max = count($x->value) - 1;
1497
+ }
1498
+
1499
+ for ($i = $x_max; $i >= $y_max + 1; --$i) {
1500
+ $x_value = &$x->value;
1501
+ $x_window = array(
1502
+ isset($x_value[$i]) ? $x_value[$i] : 0,
1503
+ isset($x_value[$i - 1]) ? $x_value[$i - 1] : 0,
1504
+ isset($x_value[$i - 2]) ? $x_value[$i - 2] : 0
1505
+ );
1506
+ $y_window = array(
1507
+ $y_value[$y_max],
1508
+ ( $y_max > 0 ) ? $y_value[$y_max - 1] : 0
1509
+ );
1510
+
1511
+ $q_index = $i - $y_max - 1;
1512
+ if ($x_window[0] == $y_window[0]) {
1513
+ $quotient_value[$q_index] = MATH_BIGINTEGER_MAX_DIGIT;
1514
+ } else {
1515
+ $quotient_value[$q_index] = $this->_safe_divide(
1516
+ $x_window[0] * MATH_BIGINTEGER_BASE_FULL + $x_window[1],
1517
+ $y_window[0]
1518
+ );
1519
+ }
1520
+
1521
+ $temp_value = array($y_window[1], $y_window[0]);
1522
+
1523
+ $lhs->value = array($quotient_value[$q_index]);
1524
+ $lhs = $lhs->multiply($temp);
1525
+
1526
+ $rhs_value = array($x_window[2], $x_window[1], $x_window[0]);
1527
+
1528
+ while ( $lhs->compare($rhs) > 0 ) {
1529
+ --$quotient_value[$q_index];
1530
+
1531
+ $lhs->value = array($quotient_value[$q_index]);
1532
+ $lhs = $lhs->multiply($temp);
1533
+ }
1534
+
1535
+ $adjust = $this->_array_repeat(0, $q_index);
1536
+ $temp_value = array($quotient_value[$q_index]);
1537
+ $temp = $temp->multiply($y);
1538
+ $temp_value = &$temp->value;
1539
+ $temp_value = array_merge($adjust, $temp_value);
1540
+
1541
+ $x = $x->subtract($temp);
1542
+
1543
+ if ($x->compare($zero) < 0) {
1544
+ $temp_value = array_merge($adjust, $y_value);
1545
+ $x = $x->add($temp);
1546
+
1547
+ --$quotient_value[$q_index];
1548
+ }
1549
+
1550
+ $x_max = count($x_value) - 1;
1551
+ }
1552
+
1553
+ // unnormalize the remainder
1554
+ $x->_rshift($shift);
1555
+
1556
+ $quotient->is_negative = $x_sign != $y_sign;
1557
+
1558
+ // calculate the "common residue", if appropriate
1559
+ if ( $x_sign ) {
1560
+ $y->_rshift($shift);
1561
+ $x = $y->subtract($x);
1562
+ }
1563
+
1564
+ return array($this->_normalize($quotient), $this->_normalize($x));
1565
+ }
1566
+
1567
+ /**
1568
+ * Divides a BigInteger by a regular integer
1569
+ *
1570
+ * abc / x = a00 / x + b0 / x + c / x
1571
+ *
1572
+ * @param Array $dividend
1573
+ * @param Array $divisor
1574
+ * @return Array
1575
+ * @access private
1576
+ */
1577
+ function _divide_digit($dividend, $divisor)
1578
+ {
1579
+ $carry = 0;
1580
+ $result = array();
1581
+
1582
+ for ($i = count($dividend) - 1; $i >= 0; --$i) {
1583
+ $temp = MATH_BIGINTEGER_BASE_FULL * $carry + $dividend[$i];
1584
+ $result[$i] = $this->_safe_divide($temp, $divisor);
1585
+ $carry = (int) ($temp - $divisor * $result[$i]);
1586
+ }
1587
+
1588
+ return array($result, $carry);
1589
+ }
1590
+
1591
+ /**
1592
+ * Performs modular exponentiation.
1593
+ *
1594
+ * Here's an example:
1595
+ * <code>
1596
+ * <?php
1597
+ * include 'Math/BigInteger.php';
1598
+ *
1599
+ * $a = new Math_BigInteger('10');
1600
+ * $b = new Math_BigInteger('20');
1601
+ * $c = new Math_BigInteger('30');
1602
+ *
1603
+ * $c = $a->modPow($b, $c);
1604
+ *
1605
+ * echo $c->toString(); // outputs 10
1606
+ * ?>
1607
+ * </code>
1608
+ *
1609
+ * @param Math_BigInteger $e
1610
+ * @param Math_BigInteger $n
1611
+ * @return Math_BigInteger
1612
+ * @access public
1613
+ * @internal The most naive approach to modular exponentiation has very unreasonable requirements, and
1614
+ * and although the approach involving repeated squaring does vastly better, it, too, is impractical
1615
+ * for our purposes. The reason being that division - by far the most complicated and time-consuming
1616
+ * of the basic operations (eg. +,-,*,/) - occurs multiple times within it.
1617
+ *
1618
+ * Modular reductions resolve this issue. Although an individual modular reduction takes more time
1619
+ * then an individual division, when performed in succession (with the same modulo), they're a lot faster.
1620
+ *
1621
+ * The two most commonly used modular reductions are Barrett and Montgomery reduction. Montgomery reduction,
1622
+ * although faster, only works when the gcd of the modulo and of the base being used is 1. In RSA, when the
1623
+ * base is a power of two, the modulo - a product of two primes - is always going to have a gcd of 1 (because
1624
+ * the product of two odd numbers is odd), but what about when RSA isn't used?
1625
+ *
1626
+ * In contrast, Barrett reduction has no such constraint. As such, some bigint implementations perform a
1627
+ * Barrett reduction after every operation in the modpow function. Others perform Barrett reductions when the
1628
+ * modulo is even and Montgomery reductions when the modulo is odd. BigInteger.java's modPow method, however,
1629
+ * uses a trick involving the Chinese Remainder Theorem to factor the even modulo into two numbers - one odd and
1630
+ * the other, a power of two - and recombine them, later. This is the method that this modPow function uses.
1631
+ * {@link http://islab.oregonstate.edu/papers/j34monex.pdf Montgomery Reduction with Even Modulus} elaborates.
1632
+ */
1633
+ function modPow($e, $n)
1634
+ {
1635
+ $n = $this->bitmask !== false && $this->bitmask->compare($n) < 0 ? $this->bitmask : $n->abs();
1636
+
1637
+ if ($e->compare(new Math_BigInteger()) < 0) {
1638
+ $e = $e->abs();
1639
+
1640
+ $temp = $this->modInverse($n);
1641
+ if ($temp === false) {
1642
+ return false;
1643
+ }
1644
+
1645
+ return $this->_normalize($temp->modPow($e, $n));
1646
+ }
1647
+
1648
+ if ( MATH_BIGINTEGER_MODE == MATH_BIGINTEGER_MODE_GMP ) {
1649
+ $temp = new Math_BigInteger();
1650
+ $temp->value = gmp_powm($this->value, $e->value, $n->value);
1651
+
1652
+ return $this->_normalize($temp);
1653
+ }
1654
+
1655
+ if ($this->compare(new Math_BigInteger()) < 0 || $this->compare($n) > 0) {
1656
+ list(, $temp) = $this->divide($n);
1657
+ return $temp->modPow($e, $n);
1658
+ }
1659
+
1660
+ if (defined('MATH_BIGINTEGER_OPENSSL_ENABLED')) {
1661
+ $components = array(
1662
+ 'modulus' => $n->toBytes(true),
1663
+ 'publicExponent' => $e->toBytes(true)
1664
+ );
1665
+
1666
+ $components = array(
1667
+ 'modulus' => pack('Ca*a*', 2, $this->_encodeASN1Length(strlen($components['modulus'])), $components['modulus']),
1668
+ 'publicExponent' => pack('Ca*a*', 2, $this->_encodeASN1Length(strlen($components['publicExponent'])), $components['publicExponent'])
1669
+ );
1670
+
1671
+ $RSAPublicKey = pack('Ca*a*a*',
1672
+ 48, $this->_encodeASN1Length(strlen($components['modulus']) + strlen($components['publicExponent'])),
1673
+ $components['modulus'], $components['publicExponent']
1674
+ );
1675
+
1676
+ $rsaOID = pack('H*', '300d06092a864886f70d0101010500'); // hex version of MA0GCSqGSIb3DQEBAQUA
1677
+ $RSAPublicKey = chr(0) . $RSAPublicKey;
1678
+ $RSAPublicKey = chr(3) . $this->_encodeASN1Length(strlen($RSAPublicKey)) . $RSAPublicKey;
1679
+
1680
+ $encapsulated = pack('Ca*a*',
1681
+ 48, $this->_encodeASN1Length(strlen($rsaOID . $RSAPublicKey)), $rsaOID . $RSAPublicKey
1682
+ );
1683
+
1684
+ $RSAPublicKey = "-----BEGIN PUBLIC KEY-----\r\n" .
1685
+ chunk_split(base64_encode($encapsulated)) .
1686
+ '-----END PUBLIC KEY-----';
1687
+
1688
+ $plaintext = str_pad($this->toBytes(), strlen($n->toBytes(true)) - 1, "\0", STR_PAD_LEFT);
1689
+
1690
+ if (openssl_public_encrypt($plaintext, $result, $RSAPublicKey, OPENSSL_NO_PADDING)) {
1691
+ return new Math_BigInteger($result, 256);
1692
+ }
1693
+ }
1694
+
1695
+ if ( MATH_BIGINTEGER_MODE == MATH_BIGINTEGER_MODE_BCMATH ) {
1696
+ $temp = new Math_BigInteger();
1697
+ $temp->value = bcpowmod($this->value, $e->value, $n->value, 0);
1698
+
1699
+ return $this->_normalize($temp);
1700
+ }
1701
+
1702
+ if ( empty($e->value) ) {
1703
+ $temp = new Math_BigInteger();
1704
+ $temp->value = array(1);
1705
+ return $this->_normalize($temp);
1706
+ }
1707
+
1708
+ if ( $e->value == array(1) ) {
1709
+ list(, $temp) = $this->divide($n);
1710
+ return $this->_normalize($temp);
1711
+ }
1712
+
1713
+ if ( $e->value == array(2) ) {
1714
+ $temp = new Math_BigInteger();
1715
+ $temp->value = $this->_square($this->value);
1716
+ list(, $temp) = $temp->divide($n);
1717
+ return $this->_normalize($temp);
1718
+ }
1719
+
1720
+ return $this->_normalize($this->_slidingWindow($e, $n, MATH_BIGINTEGER_BARRETT));
1721
+
1722
+ // the following code, although not callable, can be run independently of the above code
1723
+ // although the above code performed better in my benchmarks the following could might
1724
+ // perform better under different circumstances. in lieu of deleting it it's just been
1725
+ // made uncallable
1726
+
1727
+ // is the modulo odd?
1728
+ if ( $n->value[0] & 1 ) {
1729
+ return $this->_normalize($this->_slidingWindow($e, $n, MATH_BIGINTEGER_MONTGOMERY));
1730
+ }
1731
+ // if it's not, it's even
1732
+
1733
+ // find the lowest set bit (eg. the max pow of 2 that divides $n)
1734
+ for ($i = 0; $i < count($n->value); ++$i) {
1735
+ if ( $n->value[$i] ) {
1736
+ $temp = decbin($n->value[$i]);
1737
+ $j = strlen($temp) - strrpos($temp, '1') - 1;
1738
+ $j+= 26 * $i;
1739
+ break;
1740
+ }
1741
+ }
1742
+ // at this point, 2^$j * $n/(2^$j) == $n
1743
+
1744
+ $mod1 = $n->copy();
1745
+ $mod1->_rshift($j);
1746
+ $mod2 = new Math_BigInteger();
1747
+ $mod2->value = array(1);
1748
+ $mod2->_lshift($j);
1749
+
1750
+ $part1 = ( $mod1->value != array(1) ) ? $this->_slidingWindow($e, $mod1, MATH_BIGINTEGER_MONTGOMERY) : new Math_BigInteger();
1751
+ $part2 = $this->_slidingWindow($e, $mod2, MATH_BIGINTEGER_POWEROF2);
1752
+
1753
+ $y1 = $mod2->modInverse($mod1);
1754
+ $y2 = $mod1->modInverse($mod2);
1755
+
1756
+ $result = $part1->multiply($mod2);
1757
+ $result = $result->multiply($y1);
1758
+
1759
+ $temp = $part2->multiply($mod1);
1760
+ $temp = $temp->multiply($y2);
1761
+
1762
+ $result = $result->add($temp);
1763
+ list(, $result) = $result->divide($n);
1764
+
1765
+ return $this->_normalize($result);
1766
+ }
1767
+
1768
+ /**
1769
+ * Performs modular exponentiation.
1770
+ *
1771
+ * Alias for Math_BigInteger::modPow()
1772
+ *
1773
+ * @param Math_BigInteger $e
1774
+ * @param Math_BigInteger $n
1775
+ * @return Math_BigInteger
1776
+ * @access public
1777
+ */
1778
+ function powMod($e, $n)
1779
+ {
1780
+ return $this->modPow($e, $n);
1781
+ }
1782
+
1783
+ /**
1784
+ * Sliding Window k-ary Modular Exponentiation
1785
+ *
1786
+ * Based on {@link http://www.cacr.math.uwaterloo.ca/hac/about/chap14.pdf#page=27 HAC 14.85} /
1787
+ * {@link http://math.libtomcrypt.com/files/tommath.pdf#page=210 MPM 7.7}. In a departure from those algorithims,
1788
+ * however, this function performs a modular reduction after every multiplication and squaring operation.
1789
+ * As such, this function has the same preconditions that the reductions being used do.
1790
+ *
1791
+ * @param Math_BigInteger $e
1792
+ * @param Math_BigInteger $n
1793
+ * @param Integer $mode
1794
+ * @return Math_BigInteger
1795
+ * @access private
1796
+ */
1797
+ function _slidingWindow($e, $n, $mode)
1798
+ {
1799
+ static $window_ranges = array(7, 25, 81, 241, 673, 1793); // from BigInteger.java's oddModPow function
1800
+ //static $window_ranges = array(0, 7, 36, 140, 450, 1303, 3529); // from MPM 7.3.1
1801
+
1802
+ $e_value = $e->value;
1803
+ $e_length = count($e_value) - 1;
1804
+ $e_bits = decbin($e_value[$e_length]);
1805
+ for ($i = $e_length - 1; $i >= 0; --$i) {
1806
+ $e_bits.= str_pad(decbin($e_value[$i]), MATH_BIGINTEGER_BASE, '0', STR_PAD_LEFT);
1807
+ }
1808
+
1809
+ $e_length = strlen($e_bits);
1810
+
1811
+ // calculate the appropriate window size.
1812
+ // $window_size == 3 if $window_ranges is between 25 and 81, for example.
1813
+ for ($i = 0, $window_size = 1; $e_length > $window_ranges[$i] && $i < count($window_ranges); ++$window_size, ++$i);
1814
+
1815
+ $n_value = $n->value;
1816
+
1817
+ // precompute $this^0 through $this^$window_size
1818
+ $powers = array();
1819
+ $powers[1] = $this->_prepareReduce($this->value, $n_value, $mode);
1820
+ $powers[2] = $this->_squareReduce($powers[1], $n_value, $mode);
1821
+
1822
+ // we do every other number since substr($e_bits, $i, $j+1) (see below) is supposed to end
1823
+ // in a 1. ie. it's supposed to be odd.
1824
+ $temp = 1 << ($window_size - 1);
1825
+ for ($i = 1; $i < $temp; ++$i) {
1826
+ $i2 = $i << 1;
1827
+ $powers[$i2 + 1] = $this->_multiplyReduce($powers[$i2 - 1], $powers[2], $n_value, $mode);
1828
+ }
1829
+
1830
+ $result = array(1);
1831
+ $result = $this->_prepareReduce($result, $n_value, $mode);
1832
+
1833
+ for ($i = 0; $i < $e_length; ) {
1834
+ if ( !$e_bits[$i] ) {
1835
+ $result = $this->_squareReduce($result, $n_value, $mode);
1836
+ ++$i;
1837
+ } else {
1838
+ for ($j = $window_size - 1; $j > 0; --$j) {
1839
+ if ( !empty($e_bits[$i + $j]) ) {
1840
+ break;
1841
+ }
1842
+ }
1843
+
1844
+ for ($k = 0; $k <= $j; ++$k) {// eg. the length of substr($e_bits, $i, $j+1)
1845
+ $result = $this->_squareReduce($result, $n_value, $mode);
1846
+ }
1847
+
1848
+ $result = $this->_multiplyReduce($result, $powers[bindec(substr($e_bits, $i, $j + 1))], $n_value, $mode);
1849
+
1850
+ $i+=$j + 1;
1851
+ }
1852
+ }
1853
+
1854
+ $temp = new Math_BigInteger();
1855
+ $temp->value = $this->_reduce($result, $n_value, $mode);
1856
+
1857
+ return $temp;
1858
+ }
1859
+
1860
+ /**
1861
+ * Modular reduction
1862
+ *
1863
+ * For most $modes this will return the remainder.
1864
+ *
1865
+ * @see _slidingWindow()
1866
+ * @access private
1867
+ * @param Array $x
1868
+ * @param Array $n
1869
+ * @param Integer $mode
1870
+ * @return Array
1871
+ */
1872
+ function _reduce($x, $n, $mode)
1873
+ {
1874
+ switch ($mode) {
1875
+ case MATH_BIGINTEGER_MONTGOMERY:
1876
+ return $this->_montgomery($x, $n);
1877
+ case MATH_BIGINTEGER_BARRETT:
1878
+ return $this->_barrett($x, $n);
1879
+ case MATH_BIGINTEGER_POWEROF2:
1880
+ $lhs = new Math_BigInteger();
1881
+ $lhs->value = $x;
1882
+ $rhs = new Math_BigInteger();
1883
+ $rhs->value = $n;
1884
+ return $x->_mod2($n);
1885
+ case MATH_BIGINTEGER_CLASSIC:
1886
+ $lhs = new Math_BigInteger();
1887
+ $lhs->value = $x;
1888
+ $rhs = new Math_BigInteger();
1889
+ $rhs->value = $n;
1890
+ list(, $temp) = $lhs->divide($rhs);
1891
+ return $temp->value;
1892
+ case MATH_BIGINTEGER_NONE:
1893
+ return $x;
1894
+ default:
1895
+ // an invalid $mode was provided
1896
+ }
1897
+ }
1898
+
1899
+ /**
1900
+ * Modular reduction preperation
1901
+ *
1902
+ * @see _slidingWindow()
1903
+ * @access private
1904
+ * @param Array $x
1905
+ * @param Array $n
1906
+ * @param Integer $mode
1907
+ * @return Array
1908
+ */
1909
+ function _prepareReduce($x, $n, $mode)
1910
+ {
1911
+ if ($mode == MATH_BIGINTEGER_MONTGOMERY) {
1912
+ return $this->_prepMontgomery($x, $n);
1913
+ }
1914
+ return $this->_reduce($x, $n, $mode);
1915
+ }
1916
+
1917
+ /**
1918
+ * Modular multiply
1919
+ *
1920
+ * @see _slidingWindow()
1921
+ * @access private
1922
+ * @param Array $x
1923
+ * @param Array $y
1924
+ * @param Array $n
1925
+ * @param Integer $mode
1926
+ * @return Array
1927
+ */
1928
+ function _multiplyReduce($x, $y, $n, $mode)
1929
+ {
1930
+ if ($mode == MATH_BIGINTEGER_MONTGOMERY) {
1931
+ return $this->_montgomeryMultiply($x, $y, $n);
1932
+ }
1933
+ $temp = $this->_multiply($x, false, $y, false);
1934
+ return $this->_reduce($temp[MATH_BIGINTEGER_VALUE], $n, $mode);
1935
+ }
1936
+
1937
+ /**
1938
+ * Modular square
1939
+ *
1940
+ * @see _slidingWindow()
1941
+ * @access private
1942
+ * @param Array $x
1943
+ * @param Array $n
1944
+ * @param Integer $mode
1945
+ * @return Array
1946
+ */
1947
+ function _squareReduce($x, $n, $mode)
1948
+ {
1949
+ if ($mode == MATH_BIGINTEGER_MONTGOMERY) {
1950
+ return $this->_montgomeryMultiply($x, $x, $n);
1951
+ }
1952
+ return $this->_reduce($this->_square($x), $n, $mode);
1953
+ }
1954
+
1955
+ /**
1956
+ * Modulos for Powers of Two
1957
+ *
1958
+ * Calculates $x%$n, where $n = 2**$e, for some $e. Since this is basically the same as doing $x & ($n-1),
1959
+ * we'll just use this function as a wrapper for doing that.
1960
+ *
1961
+ * @see _slidingWindow()
1962
+ * @access private
1963
+ * @param Math_BigInteger
1964
+ * @return Math_BigInteger
1965
+ */
1966
+ function _mod2($n)
1967
+ {
1968
+ $temp = new Math_BigInteger();
1969
+ $temp->value = array(1);
1970
+ return $this->bitwise_and($n->subtract($temp));
1971
+ }
1972
+
1973
+ /**
1974
+ * Barrett Modular Reduction
1975
+ *
1976
+ * See {@link http://www.cacr.math.uwaterloo.ca/hac/about/chap14.pdf#page=14 HAC 14.3.3} /
1977
+ * {@link http://math.libtomcrypt.com/files/tommath.pdf#page=165 MPM 6.2.5} for more information. Modified slightly,
1978
+ * so as not to require negative numbers (initially, this script didn't support negative numbers).
1979
+ *
1980
+ * Employs "folding", as described at
1981
+ * {@link http://www.cosic.esat.kuleuven.be/publications/thesis-149.pdf#page=66 thesis-149.pdf#page=66}. To quote from
1982
+ * it, "the idea [behind folding] is to find a value x' such that x (mod m) = x' (mod m), with x' being smaller than x."
1983
+ *
1984
+ * Unfortunately, the "Barrett Reduction with Folding" algorithm described in thesis-149.pdf is not, as written, all that
1985
+ * usable on account of (1) its not using reasonable radix points as discussed in
1986
+ * {@link http://math.libtomcrypt.com/files/tommath.pdf#page=162 MPM 6.2.2} and (2) the fact that, even with reasonable
1987
+ * radix points, it only works when there are an even number of digits in the denominator. The reason for (2) is that
1988
+ * (x >> 1) + (x >> 1) != x / 2 + x / 2. If x is even, they're the same, but if x is odd, they're not. See the in-line
1989
+ * comments for details.
1990
+ *
1991
+ * @see _slidingWindow()
1992
+ * @access private
1993
+ * @param Array $n
1994
+ * @param Array $m
1995
+ * @return Array
1996
+ */
1997
+ function _barrett($n, $m)
1998
+ {
1999
+ static $cache = array(
2000
+ MATH_BIGINTEGER_VARIABLE => array(),
2001
+ MATH_BIGINTEGER_DATA => array()
2002
+ );
2003
+
2004
+ $m_length = count($m);
2005
+
2006
+ // if ($this->_compare($n, $this->_square($m)) >= 0) {
2007
+ if (count($n) > 2 * $m_length) {
2008
+ $lhs = new Math_BigInteger();
2009
+ $rhs = new Math_BigInteger();
2010
+ $lhs->value = $n;
2011
+ $rhs->value = $m;
2012
+ list(, $temp) = $lhs->divide($rhs);
2013
+ return $temp->value;
2014
+ }
2015
+
2016
+ // if (m.length >> 1) + 2 <= m.length then m is too small and n can't be reduced
2017
+ if ($m_length < 5) {
2018
+ return $this->_regularBarrett($n, $m);
2019
+ }
2020
+
2021
+ // n = 2 * m.length
2022
+
2023
+ if ( ($key = array_search($m, $cache[MATH_BIGINTEGER_VARIABLE])) === false ) {
2024
+ $key = count($cache[MATH_BIGINTEGER_VARIABLE]);
2025
+ $cache[MATH_BIGINTEGER_VARIABLE][] = $m;
2026
+
2027
+ $lhs = new Math_BigInteger();
2028
+ $lhs_value = &$lhs->value;
2029
+ $lhs_value = $this->_array_repeat(0, $m_length + ($m_length >> 1));
2030
+ $lhs_value[] = 1;
2031
+ $rhs = new Math_BigInteger();
2032
+ $rhs->value = $m;
2033
+
2034
+ list($u, $m1) = $lhs->divide($rhs);
2035
+ $u = $u->value;
2036
+ $m1 = $m1->value;
2037
+
2038
+ $cache[MATH_BIGINTEGER_DATA][] = array(
2039
+ 'u' => $u, // m.length >> 1 (technically (m.length >> 1) + 1)
2040
+ 'm1'=> $m1 // m.length
2041
+ );
2042
+ } else {
2043
+ extract($cache[MATH_BIGINTEGER_DATA][$key]);
2044
+ }
2045
+
2046
+ $cutoff = $m_length + ($m_length >> 1);
2047
+ $lsd = array_slice($n, 0, $cutoff); // m.length + (m.length >> 1)
2048
+ $msd = array_slice($n, $cutoff); // m.length >> 1
2049
+ $lsd = $this->_trim($lsd);
2050
+ $temp = $this->_multiply($msd, false, $m1, false);
2051
+ $n = $this->_add($lsd, false, $temp[MATH_BIGINTEGER_VALUE], false); // m.length + (m.length >> 1) + 1
2052
+
2053
+ if ($m_length & 1) {
2054
+ return $this->_regularBarrett($n[MATH_BIGINTEGER_VALUE], $m);
2055
+ }
2056
+
2057
+ // (m.length + (m.length >> 1) + 1) - (m.length - 1) == (m.length >> 1) + 2
2058
+ $temp = array_slice($n[MATH_BIGINTEGER_VALUE], $m_length - 1);
2059
+ // if even: ((m.length >> 1) + 2) + (m.length >> 1) == m.length + 2
2060
+ // if odd: ((m.length >> 1) + 2) + (m.length >> 1) == (m.length - 1) + 2 == m.length + 1
2061
+ $temp = $this->_multiply($temp, false, $u, false);
2062
+ // if even: (m.length + 2) - ((m.length >> 1) + 1) = m.length - (m.length >> 1) + 1
2063
+ // if odd: (m.length + 1) - ((m.length >> 1) + 1) = m.length - (m.length >> 1)
2064
+ $temp = array_slice($temp[MATH_BIGINTEGER_VALUE], ($m_length >> 1) + 1);
2065
+ // if even: (m.length - (m.length >> 1) + 1) + m.length = 2 * m.length - (m.length >> 1) + 1
2066
+ // if odd: (m.length - (m.length >> 1)) + m.length = 2 * m.length - (m.length >> 1)
2067
+ $temp = $this->_multiply($temp, false, $m, false);
2068
+
2069
+ // at this point, if m had an odd number of digits, we'd be subtracting a 2 * m.length - (m.length >> 1) digit
2070
+ // number from a m.length + (m.length >> 1) + 1 digit number. ie. there'd be an extra digit and the while loop
2071
+ // following this comment would loop a lot (hence our calling _regularBarrett() in that situation).
2072
+
2073
+ $result = $this->_subtract($n[MATH_BIGINTEGER_VALUE], false, $temp[MATH_BIGINTEGER_VALUE], false);
2074
+
2075
+ while ($this->_compare($result[MATH_BIGINTEGER_VALUE], $result[MATH_BIGINTEGER_SIGN], $m, false) >= 0) {
2076
+ $result = $this->_subtract($result[MATH_BIGINTEGER_VALUE], $result[MATH_BIGINTEGER_SIGN], $m, false);
2077
+ }
2078
+
2079
+ return $result[MATH_BIGINTEGER_VALUE];
2080
+ }
2081
+
2082
+ /**
2083
+ * (Regular) Barrett Modular Reduction
2084
+ *
2085
+ * For numbers with more than four digits Math_BigInteger::_barrett() is faster. The difference between that and this
2086
+ * is that this function does not fold the denominator into a smaller form.
2087
+ *
2088
+ * @see _slidingWindow()
2089
+ * @access private
2090
+ * @param Array $x
2091
+ * @param Array $n
2092
+ * @return Array
2093
+ */
2094
+ function _regularBarrett($x, $n)
2095
+ {
2096
+ static $cache = array(
2097
+ MATH_BIGINTEGER_VARIABLE => array(),
2098
+ MATH_BIGINTEGER_DATA => array()
2099
+ );
2100
+
2101
+ $n_length = count($n);
2102
+
2103
+ if (count($x) > 2 * $n_length) {
2104
+ $lhs = new Math_BigInteger();
2105
+ $rhs = new Math_BigInteger();
2106
+ $lhs->value = $x;
2107
+ $rhs->value = $n;
2108
+ list(, $temp) = $lhs->divide($rhs);
2109
+ return $temp->value;
2110
+ }
2111
+
2112
+ if ( ($key = array_search($n, $cache[MATH_BIGINTEGER_VARIABLE])) === false ) {
2113
+ $key = count($cache[MATH_BIGINTEGER_VARIABLE]);
2114
+ $cache[MATH_BIGINTEGER_VARIABLE][] = $n;
2115
+ $lhs = new Math_BigInteger();
2116
+ $lhs_value = &$lhs->value;
2117
+ $lhs_value = $this->_array_repeat(0, 2 * $n_length);
2118
+ $lhs_value[] = 1;
2119
+ $rhs = new Math_BigInteger();
2120
+ $rhs->value = $n;
2121
+ list($temp, ) = $lhs->divide($rhs); // m.length
2122
+ $cache[MATH_BIGINTEGER_DATA][] = $temp->value;
2123
+ }
2124
+
2125
+ // 2 * m.length - (m.length - 1) = m.length + 1
2126
+ $temp = array_slice($x, $n_length - 1);
2127
+ // (m.length + 1) + m.length = 2 * m.length + 1
2128
+ $temp = $this->_multiply($temp, false, $cache[MATH_BIGINTEGER_DATA][$key], false);
2129
+ // (2 * m.length + 1) - (m.length - 1) = m.length + 2
2130
+ $temp = array_slice($temp[MATH_BIGINTEGER_VALUE], $n_length + 1);
2131
+
2132
+ // m.length + 1
2133
+ $result = array_slice($x, 0, $n_length + 1);
2134
+ // m.length + 1
2135
+ $temp = $this->_multiplyLower($temp, false, $n, false, $n_length + 1);
2136
+ // $temp == array_slice($temp->_multiply($temp, false, $n, false)->value, 0, $n_length + 1)
2137
+
2138
+ if ($this->_compare($result, false, $temp[MATH_BIGINTEGER_VALUE], $temp[MATH_BIGINTEGER_SIGN]) < 0) {
2139
+ $corrector_value = $this->_array_repeat(0, $n_length + 1);
2140
+ $corrector_value[count($corrector_value)] = 1;
2141
+ $result = $this->_add($result, false, $corrector_value, false);
2142
+ $result = $result[MATH_BIGINTEGER_VALUE];
2143
+ }
2144
+
2145
+ // at this point, we're subtracting a number with m.length + 1 digits from another number with m.length + 1 digits
2146
+ $result = $this->_subtract($result, false, $temp[MATH_BIGINTEGER_VALUE], $temp[MATH_BIGINTEGER_SIGN]);
2147
+ while ($this->_compare($result[MATH_BIGINTEGER_VALUE], $result[MATH_BIGINTEGER_SIGN], $n, false) > 0) {
2148
+ $result = $this->_subtract($result[MATH_BIGINTEGER_VALUE], $result[MATH_BIGINTEGER_SIGN], $n, false);
2149
+ }
2150
+
2151
+ return $result[MATH_BIGINTEGER_VALUE];
2152
+ }
2153
+
2154
+ /**
2155
+ * Performs long multiplication up to $stop digits
2156
+ *
2157
+ * If you're going to be doing array_slice($product->value, 0, $stop), some cycles can be saved.
2158
+ *
2159
+ * @see _regularBarrett()
2160
+ * @param Array $x_value
2161
+ * @param Boolean $x_negative
2162
+ * @param Array $y_value
2163
+ * @param Boolean $y_negative
2164
+ * @param Integer $stop
2165
+ * @return Array
2166
+ * @access private
2167
+ */
2168
+ function _multiplyLower($x_value, $x_negative, $y_value, $y_negative, $stop)
2169
+ {
2170
+ $x_length = count($x_value);
2171
+ $y_length = count($y_value);
2172
+
2173
+ if ( !$x_length || !$y_length ) { // a 0 is being multiplied
2174
+ return array(
2175
+ MATH_BIGINTEGER_VALUE => array(),
2176
+ MATH_BIGINTEGER_SIGN => false
2177
+ );
2178
+ }
2179
+
2180
+ if ( $x_length < $y_length ) {
2181
+ $temp = $x_value;
2182
+ $x_value = $y_value;
2183
+ $y_value = $temp;
2184
+
2185
+ $x_length = count($x_value);
2186
+ $y_length = count($y_value);
2187
+ }
2188
+
2189
+ $product_value = $this->_array_repeat(0, $x_length + $y_length);
2190
+
2191
+ // the following for loop could be removed if the for loop following it
2192
+ // (the one with nested for loops) initially set $i to 0, but
2193
+ // doing so would also make the result in one set of unnecessary adds,
2194
+ // since on the outermost loops first pass, $product->value[$k] is going
2195
+ // to always be 0
2196
+
2197
+ $carry = 0;
2198
+
2199
+ for ($j = 0; $j < $x_length; ++$j) { // ie. $i = 0, $k = $i
2200
+ $temp = $x_value[$j] * $y_value[0] + $carry; // $product_value[$k] == 0
2201
+ $carry = MATH_BIGINTEGER_BASE === 26 ? intval($temp / 0x4000000) : ($temp >> 31);
2202
+ $product_value[$j] = (int) ($temp - MATH_BIGINTEGER_BASE_FULL * $carry);
2203
+ }
2204
+
2205
+ if ($j < $stop) {
2206
+ $product_value[$j] = $carry;
2207
+ }
2208
+
2209
+ // the above for loop is what the previous comment was talking about. the
2210
+ // following for loop is the "one with nested for loops"
2211
+
2212
+ for ($i = 1; $i < $y_length; ++$i) {
2213
+ $carry = 0;
2214
+
2215
+ for ($j = 0, $k = $i; $j < $x_length && $k < $stop; ++$j, ++$k) {
2216
+ $temp = $product_value[$k] + $x_value[$j] * $y_value[$i] + $carry;
2217
+ $carry = MATH_BIGINTEGER_BASE === 26 ? intval($temp / 0x4000000) : ($temp >> 31);
2218
+ $product_value[$k] = (int) ($temp - MATH_BIGINTEGER_BASE_FULL * $carry);
2219
+ }
2220
+
2221
+ if ($k < $stop) {
2222
+ $product_value[$k] = $carry;
2223
+ }
2224
+ }
2225
+
2226
+ return array(
2227
+ MATH_BIGINTEGER_VALUE => $this->_trim($product_value),
2228
+ MATH_BIGINTEGER_SIGN => $x_negative != $y_negative
2229
+ );
2230
+ }
2231
+
2232
+ /**
2233
+ * Montgomery Modular Reduction
2234
+ *
2235
+ * ($x->_prepMontgomery($n))->_montgomery($n) yields $x % $n.
2236
+ * {@link http://math.libtomcrypt.com/files/tommath.pdf#page=170 MPM 6.3} provides insights on how this can be
2237
+ * improved upon (basically, by using the comba method). gcd($n, 2) must be equal to one for this function
2238
+ * to work correctly.
2239
+ *
2240
+ * @see _prepMontgomery()
2241
+ * @see _slidingWindow()
2242
+ * @access private
2243
+ * @param Array $x
2244
+ * @param Array $n
2245
+ * @return Array
2246
+ */
2247
+ function _montgomery($x, $n)
2248
+ {
2249
+ static $cache = array(
2250
+ MATH_BIGINTEGER_VARIABLE => array(),
2251
+ MATH_BIGINTEGER_DATA => array()
2252
+ );
2253
+
2254
+ if ( ($key = array_search($n, $cache[MATH_BIGINTEGER_VARIABLE])) === false ) {
2255
+ $key = count($cache[MATH_BIGINTEGER_VARIABLE]);
2256
+ $cache[MATH_BIGINTEGER_VARIABLE][] = $x;
2257
+ $cache[MATH_BIGINTEGER_DATA][] = $this->_modInverse67108864($n);
2258
+ }
2259
+
2260
+ $k = count($n);
2261
+
2262
+ $result = array(MATH_BIGINTEGER_VALUE => $x);
2263
+
2264
+ for ($i = 0; $i < $k; ++$i) {
2265
+ $temp = $result[MATH_BIGINTEGER_VALUE][$i] * $cache[MATH_BIGINTEGER_DATA][$key];
2266
+ $temp = $temp - MATH_BIGINTEGER_BASE_FULL * (MATH_BIGINTEGER_BASE === 26 ? intval($temp / 0x4000000) : ($temp >> 31));
2267
+ $temp = $this->_regularMultiply(array($temp), $n);
2268
+ $temp = array_merge($this->_array_repeat(0, $i), $temp);
2269
+ $result = $this->_add($result[MATH_BIGINTEGER_VALUE], false, $temp, false);
2270
+ }
2271
+
2272
+ $result[MATH_BIGINTEGER_VALUE] = array_slice($result[MATH_BIGINTEGER_VALUE], $k);
2273
+
2274
+ if ($this->_compare($result, false, $n, false) >= 0) {
2275
+ $result = $this->_subtract($result[MATH_BIGINTEGER_VALUE], false, $n, false);
2276
+ }
2277
+
2278
+ return $result[MATH_BIGINTEGER_VALUE];
2279
+ }
2280
+
2281
+ /**
2282
+ * Montgomery Multiply
2283
+ *
2284
+ * Interleaves the montgomery reduction and long multiplication algorithms together as described in
2285
+ * {@link http://www.cacr.math.uwaterloo.ca/hac/about/chap14.pdf#page=13 HAC 14.36}
2286
+ *
2287
+ * @see _prepMontgomery()
2288
+ * @see _montgomery()
2289
+ * @access private
2290
+ * @param Array $x
2291
+ * @param Array $y
2292
+ * @param Array $m
2293
+ * @return Array
2294
+ */
2295
+ function _montgomeryMultiply($x, $y, $m)
2296
+ {
2297
+ $temp = $this->_multiply($x, false, $y, false);
2298
+ return $this->_montgomery($temp[MATH_BIGINTEGER_VALUE], $m);
2299
+
2300
+ // the following code, although not callable, can be run independently of the above code
2301
+ // although the above code performed better in my benchmarks the following could might
2302
+ // perform better under different circumstances. in lieu of deleting it it's just been
2303
+ // made uncallable
2304
+
2305
+ static $cache = array(
2306
+ MATH_BIGINTEGER_VARIABLE => array(),
2307
+ MATH_BIGINTEGER_DATA => array()
2308
+ );
2309
+
2310
+ if ( ($key = array_search($m, $cache[MATH_BIGINTEGER_VARIABLE])) === false ) {
2311
+ $key = count($cache[MATH_BIGINTEGER_VARIABLE]);
2312
+ $cache[MATH_BIGINTEGER_VARIABLE][] = $m;
2313
+ $cache[MATH_BIGINTEGER_DATA][] = $this->_modInverse67108864($m);
2314
+ }
2315
+
2316
+ $n = max(count($x), count($y), count($m));
2317
+ $x = array_pad($x, $n, 0);
2318
+ $y = array_pad($y, $n, 0);
2319
+ $m = array_pad($m, $n, 0);
2320
+ $a = array(MATH_BIGINTEGER_VALUE => $this->_array_repeat(0, $n + 1));
2321
+ for ($i = 0; $i < $n; ++$i) {
2322
+ $temp = $a[MATH_BIGINTEGER_VALUE][0] + $x[$i] * $y[0];
2323
+ $temp = $temp - MATH_BIGINTEGER_BASE_FULL * (MATH_BIGINTEGER_BASE === 26 ? intval($temp / 0x4000000) : ($temp >> 31));
2324
+ $temp = $temp * $cache[MATH_BIGINTEGER_DATA][$key];
2325
+ $temp = $temp - MATH_BIGINTEGER_BASE_FULL * (MATH_BIGINTEGER_BASE === 26 ? intval($temp / 0x4000000) : ($temp >> 31));
2326
+ $temp = $this->_add($this->_regularMultiply(array($x[$i]), $y), false, $this->_regularMultiply(array($temp), $m), false);
2327
+ $a = $this->_add($a[MATH_BIGINTEGER_VALUE], false, $temp[MATH_BIGINTEGER_VALUE], false);
2328
+ $a[MATH_BIGINTEGER_VALUE] = array_slice($a[MATH_BIGINTEGER_VALUE], 1);
2329
+ }
2330
+ if ($this->_compare($a[MATH_BIGINTEGER_VALUE], false, $m, false) >= 0) {
2331
+ $a = $this->_subtract($a[MATH_BIGINTEGER_VALUE], false, $m, false);
2332
+ }
2333
+ return $a[MATH_BIGINTEGER_VALUE];
2334
+ }
2335
+
2336
+ /**
2337
+ * Prepare a number for use in Montgomery Modular Reductions
2338
+ *
2339
+ * @see _montgomery()
2340
+ * @see _slidingWindow()
2341
+ * @access private
2342
+ * @param Array $x
2343
+ * @param Array $n
2344
+ * @return Array
2345
+ */
2346
+ function _prepMontgomery($x, $n)
2347
+ {
2348
+ $lhs = new Math_BigInteger();
2349
+ $lhs->value = array_merge($this->_array_repeat(0, count($n)), $x);
2350
+ $rhs = new Math_BigInteger();
2351
+ $rhs->value = $n;
2352
+
2353
+ list(, $temp) = $lhs->divide($rhs);
2354
+ return $temp->value;
2355
+ }
2356
+
2357
+ /**
2358
+ * Modular Inverse of a number mod 2**26 (eg. 67108864)
2359
+ *
2360
+ * Based off of the bnpInvDigit function implemented and justified in the following URL:
2361
+ *
2362
+ * {@link http://www-cs-students.stanford.edu/~tjw/jsbn/jsbn.js}
2363
+ *
2364
+ * The following URL provides more info:
2365
+ *
2366
+ * {@link http://groups.google.com/group/sci.crypt/msg/7a137205c1be7d85}
2367
+ *
2368
+ * As for why we do all the bitmasking... strange things can happen when converting from floats to ints. For
2369
+ * instance, on some computers, var_dump((int) -4294967297) yields int(-1) and on others, it yields
2370
+ * int(-2147483648). To avoid problems stemming from this, we use bitmasks to guarantee that ints aren't
2371
+ * auto-converted to floats. The outermost bitmask is present because without it, there's no guarantee that
2372
+ * the "residue" returned would be the so-called "common residue". We use fmod, in the last step, because the
2373
+ * maximum possible $x is 26 bits and the maximum $result is 16 bits. Thus, we have to be able to handle up to
2374
+ * 40 bits, which only 64-bit floating points will support.
2375
+ *
2376
+ * Thanks to Pedro Gimeno Fortea for input!
2377
+ *
2378
+ * @see _montgomery()
2379
+ * @access private
2380
+ * @param Array $x
2381
+ * @return Integer
2382
+ */
2383
+ function _modInverse67108864($x) // 2**26 == 67,108,864
2384
+ {
2385
+ $x = -$x[0];
2386
+ $result = $x & 0x3; // x**-1 mod 2**2
2387
+ $result = ($result * (2 - $x * $result)) & 0xF; // x**-1 mod 2**4
2388
+ $result = ($result * (2 - ($x & 0xFF) * $result)) & 0xFF; // x**-1 mod 2**8
2389
+ $result = ($result * ((2 - ($x & 0xFFFF) * $result) & 0xFFFF)) & 0xFFFF; // x**-1 mod 2**16
2390
+ $result = fmod($result * (2 - fmod($x * $result, MATH_BIGINTEGER_BASE_FULL)), MATH_BIGINTEGER_BASE_FULL); // x**-1 mod 2**26
2391
+ return $result & MATH_BIGINTEGER_MAX_DIGIT;
2392
+ }
2393
+
2394
+ /**
2395
+ * Calculates modular inverses.
2396
+ *
2397
+ * Say you have (30 mod 17 * x mod 17) mod 17 == 1. x can be found using modular inverses.
2398
+ *
2399
+ * Here's an example:
2400
+ * <code>
2401
+ * <?php
2402
+ * include 'Math/BigInteger.php';
2403
+ *
2404
+ * $a = new Math_BigInteger(30);
2405
+ * $b = new Math_BigInteger(17);
2406
+ *
2407
+ * $c = $a->modInverse($b);
2408
+ * echo $c->toString(); // outputs 4
2409
+ *
2410
+ * echo "\r\n";
2411
+ *
2412
+ * $d = $a->multiply($c);
2413
+ * list(, $d) = $d->divide($b);
2414
+ * echo $d; // outputs 1 (as per the definition of modular inverse)
2415
+ * ?>
2416
+ * </code>
2417
+ *
2418
+ * @param Math_BigInteger $n
2419
+ * @return mixed false, if no modular inverse exists, Math_BigInteger, otherwise.
2420
+ * @access public
2421
+ * @internal See {@link http://www.cacr.math.uwaterloo.ca/hac/about/chap14.pdf#page=21 HAC 14.64} for more information.
2422
+ */
2423
+ function modInverse($n)
2424
+ {
2425
+ switch ( MATH_BIGINTEGER_MODE ) {
2426
+ case MATH_BIGINTEGER_MODE_GMP:
2427
+ $temp = new Math_BigInteger();
2428
+ $temp->value = gmp_invert($this->value, $n->value);
2429
+
2430
+ return ( $temp->value === false ) ? false : $this->_normalize($temp);
2431
+ }
2432
+
2433
+ static $zero, $one;
2434
+ if (!isset($zero)) {
2435
+ $zero = new Math_BigInteger();
2436
+ $one = new Math_BigInteger(1);
2437
+ }
2438
+
2439
+ // $x mod -$n == $x mod $n.
2440
+ $n = $n->abs();
2441
+
2442
+ if ($this->compare($zero) < 0) {
2443
+ $temp = $this->abs();
2444
+ $temp = $temp->modInverse($n);
2445
+ return $this->_normalize($n->subtract($temp));
2446
+ }
2447
+
2448
+ extract($this->extendedGCD($n));
2449
+
2450
+ if (!$gcd->equals($one)) {
2451
+ return false;
2452
+ }
2453
+
2454
+ $x = $x->compare($zero) < 0 ? $x->add($n) : $x;
2455
+
2456
+ return $this->compare($zero) < 0 ? $this->_normalize($n->subtract($x)) : $this->_normalize($x);
2457
+ }
2458
+
2459
+ /**
2460
+ * Calculates the greatest common divisor and Bezout's identity.
2461
+ *
2462
+ * Say you have 693 and 609. The GCD is 21. Bezout's identity states that there exist integers x and y such that
2463
+ * 693*x + 609*y == 21. In point of fact, there are actually an infinite number of x and y combinations and which
2464
+ * combination is returned is dependant upon which mode is in use. See
2465
+ * {@link http://en.wikipedia.org/wiki/B%C3%A9zout%27s_identity Bezout's identity - Wikipedia} for more information.
2466
+ *
2467
+ * Here's an example:
2468
+ * <code>
2469
+ * <?php
2470
+ * include 'Math/BigInteger.php';
2471
+ *
2472
+ * $a = new Math_BigInteger(693);
2473
+ * $b = new Math_BigInteger(609);
2474
+ *
2475
+ * extract($a->extendedGCD($b));
2476
+ *
2477
+ * echo $gcd->toString() . "\r\n"; // outputs 21
2478
+ * echo $a->toString() * $x->toString() + $b->toString() * $y->toString(); // outputs 21
2479
+ * ?>
2480
+ * </code>
2481
+ *
2482
+ * @param Math_BigInteger $n
2483
+ * @return Math_BigInteger
2484
+ * @access public
2485
+ * @internal Calculates the GCD using the binary xGCD algorithim described in
2486
+ * {@link http://www.cacr.math.uwaterloo.ca/hac/about/chap14.pdf#page=19 HAC 14.61}. As the text above 14.61 notes,
2487
+ * the more traditional algorithim requires "relatively costly multiple-precision divisions".
2488
+ */
2489
+ function extendedGCD($n)
2490
+ {
2491
+ switch ( MATH_BIGINTEGER_MODE ) {
2492
+ case MATH_BIGINTEGER_MODE_GMP:
2493
+ extract(gmp_gcdext($this->value, $n->value));
2494
+
2495
+ return array(
2496
+ 'gcd' => $this->_normalize(new Math_BigInteger($g)),
2497
+ 'x' => $this->_normalize(new Math_BigInteger($s)),
2498
+ 'y' => $this->_normalize(new Math_BigInteger($t))
2499
+ );
2500
+ case MATH_BIGINTEGER_MODE_BCMATH:
2501
+ // it might be faster to use the binary xGCD algorithim here, as well, but (1) that algorithim works
2502
+ // best when the base is a power of 2 and (2) i don't think it'd make much difference, anyway. as is,
2503
+ // the basic extended euclidean algorithim is what we're using.
2504
+
2505
+ $u = $this->value;
2506
+ $v = $n->value;
2507
+
2508
+ $a = '1';
2509
+ $b = '0';
2510
+ $c = '0';
2511
+ $d = '1';
2512
+
2513
+ while (bccomp($v, '0', 0) != 0) {
2514
+ $q = bcdiv($u, $v, 0);
2515
+
2516
+ $temp = $u;
2517
+ $u = $v;
2518
+ $v = bcsub($temp, bcmul($v, $q, 0), 0);
2519
+
2520
+ $temp = $a;
2521
+ $a = $c;
2522
+ $c = bcsub($temp, bcmul($a, $q, 0), 0);
2523
+
2524
+ $temp = $b;
2525
+ $b = $d;
2526
+ $d = bcsub($temp, bcmul($b, $q, 0), 0);
2527
+ }
2528
+
2529
+ return array(
2530
+ 'gcd' => $this->_normalize(new Math_BigInteger($u)),
2531
+ 'x' => $this->_normalize(new Math_BigInteger($a)),
2532
+ 'y' => $this->_normalize(new Math_BigInteger($b))
2533
+ );
2534
+ }
2535
+
2536
+ $y = $n->copy();
2537
+ $x = $this->copy();
2538
+ $g = new Math_BigInteger();
2539
+ $g->value = array(1);
2540
+
2541
+ while ( !(($x->value[0] & 1)|| ($y->value[0] & 1)) ) {
2542
+ $x->_rshift(1);
2543
+ $y->_rshift(1);
2544
+ $g->_lshift(1);
2545
+ }
2546
+
2547
+ $u = $x->copy();
2548
+ $v = $y->copy();
2549
+
2550
+ $a = new Math_BigInteger();
2551
+ $b = new Math_BigInteger();
2552
+ $c = new Math_BigInteger();
2553
+ $d = new Math_BigInteger();
2554
+
2555
+ $a->value = $d->value = $g->value = array(1);
2556
+ $b->value = $c->value = array();
2557
+
2558
+ while ( !empty($u->value) ) {
2559
+ while ( !($u->value[0] & 1) ) {
2560
+ $u->_rshift(1);
2561
+ if ( (!empty($a->value) && ($a->value[0] & 1)) || (!empty($b->value) && ($b->value[0] & 1)) ) {
2562
+ $a = $a->add($y);
2563
+ $b = $b->subtract($x);
2564
+ }
2565
+ $a->_rshift(1);
2566
+ $b->_rshift(1);
2567
+ }
2568
+
2569
+ while ( !($v->value[0] & 1) ) {
2570
+ $v->_rshift(1);
2571
+ if ( (!empty($d->value) && ($d->value[0] & 1)) || (!empty($c->value) && ($c->value[0] & 1)) ) {
2572
+ $c = $c->add($y);
2573
+ $d = $d->subtract($x);
2574
+ }
2575
+ $c->_rshift(1);
2576
+ $d->_rshift(1);
2577
+ }
2578
+
2579
+ if ($u->compare($v) >= 0) {
2580
+ $u = $u->subtract($v);
2581
+ $a = $a->subtract($c);
2582
+ $b = $b->subtract($d);
2583
+ } else {
2584
+ $v = $v->subtract($u);
2585
+ $c = $c->subtract($a);
2586
+ $d = $d->subtract($b);
2587
+ }
2588
+ }
2589
+
2590
+ return array(
2591
+ 'gcd' => $this->_normalize($g->multiply($v)),
2592
+ 'x' => $this->_normalize($c),
2593
+ 'y' => $this->_normalize($d)
2594
+ );
2595
+ }
2596
+
2597
+ /**
2598
+ * Calculates the greatest common divisor
2599
+ *
2600
+ * Say you have 693 and 609. The GCD is 21.
2601
+ *
2602
+ * Here's an example:
2603
+ * <code>
2604
+ * <?php
2605
+ * include 'Math/BigInteger.php';
2606
+ *
2607
+ * $a = new Math_BigInteger(693);
2608
+ * $b = new Math_BigInteger(609);
2609
+ *
2610
+ * $gcd = a->extendedGCD($b);
2611
+ *
2612
+ * echo $gcd->toString() . "\r\n"; // outputs 21
2613
+ * ?>
2614
+ * </code>
2615
+ *
2616
+ * @param Math_BigInteger $n
2617
+ * @return Math_BigInteger
2618
+ * @access public
2619
+ */
2620
+ function gcd($n)
2621
+ {
2622
+ extract($this->extendedGCD($n));
2623
+ return $gcd;
2624
+ }
2625
+
2626
+ /**
2627
+ * Absolute value.
2628
+ *
2629
+ * @return Math_BigInteger
2630
+ * @access public
2631
+ */
2632
+ function abs()
2633
+ {
2634
+ $temp = new Math_BigInteger();
2635
+
2636
+ switch ( MATH_BIGINTEGER_MODE ) {
2637
+ case MATH_BIGINTEGER_MODE_GMP:
2638
+ $temp->value = gmp_abs($this->value);
2639
+ break;
2640
+ case MATH_BIGINTEGER_MODE_BCMATH:
2641
+ $temp->value = (bccomp($this->value, '0', 0) < 0) ? substr($this->value, 1) : $this->value;
2642
+ break;
2643
+ default:
2644
+ $temp->value = $this->value;
2645
+ }
2646
+
2647
+ return $temp;
2648
+ }
2649
+
2650
+ /**
2651
+ * Compares two numbers.
2652
+ *
2653
+ * Although one might think !$x->compare($y) means $x != $y, it, in fact, means the opposite. The reason for this is
2654
+ * demonstrated thusly:
2655
+ *
2656
+ * $x > $y: $x->compare($y) > 0
2657
+ * $x < $y: $x->compare($y) < 0
2658
+ * $x == $y: $x->compare($y) == 0
2659
+ *
2660
+ * Note how the same comparison operator is used. If you want to test for equality, use $x->equals($y).
2661
+ *
2662
+ * @param Math_BigInteger $y
2663
+ * @return Integer < 0 if $this is less than $y; > 0 if $this is greater than $y, and 0 if they are equal.
2664
+ * @access public
2665
+ * @see equals()
2666
+ * @internal Could return $this->subtract($x), but that's not as fast as what we do do.
2667
+ */
2668
+ function compare($y)
2669
+ {
2670
+ switch ( MATH_BIGINTEGER_MODE ) {
2671
+ case MATH_BIGINTEGER_MODE_GMP:
2672
+ return gmp_cmp($this->value, $y->value);
2673
+ case MATH_BIGINTEGER_MODE_BCMATH:
2674
+ return bccomp($this->value, $y->value, 0);
2675
+ }
2676
+
2677
+ return $this->_compare($this->value, $this->is_negative, $y->value, $y->is_negative);
2678
+ }
2679
+
2680
+ /**
2681
+ * Compares two numbers.
2682
+ *
2683
+ * @param Array $x_value
2684
+ * @param Boolean $x_negative
2685
+ * @param Array $y_value
2686
+ * @param Boolean $y_negative
2687
+ * @return Integer
2688
+ * @see compare()
2689
+ * @access private
2690
+ */
2691
+ function _compare($x_value, $x_negative, $y_value, $y_negative)
2692
+ {
2693
+ if ( $x_negative != $y_negative ) {
2694
+ return ( !$x_negative && $y_negative ) ? 1 : -1;
2695
+ }
2696
+
2697
+ $result = $x_negative ? -1 : 1;
2698
+
2699
+ if ( count($x_value) != count($y_value) ) {
2700
+ return ( count($x_value) > count($y_value) ) ? $result : -$result;
2701
+ }
2702
+ $size = max(count($x_value), count($y_value));
2703
+
2704
+ $x_value = array_pad($x_value, $size, 0);
2705
+ $y_value = array_pad($y_value, $size, 0);
2706
+
2707
+ for ($i = count($x_value) - 1; $i >= 0; --$i) {
2708
+ if ($x_value[$i] != $y_value[$i]) {
2709
+ return ( $x_value[$i] > $y_value[$i] ) ? $result : -$result;
2710
+ }
2711
+ }
2712
+
2713
+ return 0;
2714
+ }
2715
+
2716
+ /**
2717
+ * Tests the equality of two numbers.
2718
+ *
2719
+ * If you need to see if one number is greater than or less than another number, use Math_BigInteger::compare()
2720
+ *
2721
+ * @param Math_BigInteger $x
2722
+ * @return Boolean
2723
+ * @access public
2724
+ * @see compare()
2725
+ */
2726
+ function equals($x)
2727
+ {
2728
+ switch ( MATH_BIGINTEGER_MODE ) {
2729
+ case MATH_BIGINTEGER_MODE_GMP:
2730
+ return gmp_cmp($this->value, $x->value) == 0;
2731
+ default:
2732
+ return $this->value === $x->value && $this->is_negative == $x->is_negative;
2733
+ }
2734
+ }
2735
+
2736
+ /**
2737
+ * Set Precision
2738
+ *
2739
+ * Some bitwise operations give different results depending on the precision being used. Examples include left
2740
+ * shift, not, and rotates.
2741
+ *
2742
+ * @param Integer $bits
2743
+ * @access public
2744
+ */
2745
+ function setPrecision($bits)
2746
+ {
2747
+ $this->precision = $bits;
2748
+ if ( MATH_BIGINTEGER_MODE != MATH_BIGINTEGER_MODE_BCMATH ) {
2749
+ $this->bitmask = new Math_BigInteger(chr((1 << ($bits & 0x7)) - 1) . str_repeat(chr(0xFF), $bits >> 3), 256);
2750
+ } else {
2751
+ $this->bitmask = new Math_BigInteger(bcpow('2', $bits, 0));
2752
+ }
2753
+
2754
+ $temp = $this->_normalize($this);
2755
+ $this->value = $temp->value;
2756
+ }
2757
+
2758
+ /**
2759
+ * Logical And
2760
+ *
2761
+ * @param Math_BigInteger $x
2762
+ * @access public
2763
+ * @internal Implemented per a request by Lluis Pamies i Juarez <lluis _a_ pamies.cat>
2764
+ * @return Math_BigInteger
2765
+ */
2766
+ function bitwise_and($x)
2767
+ {
2768
+ switch ( MATH_BIGINTEGER_MODE ) {
2769
+ case MATH_BIGINTEGER_MODE_GMP:
2770
+ $temp = new Math_BigInteger();
2771
+ $temp->value = gmp_and($this->value, $x->value);
2772
+
2773
+ return $this->_normalize($temp);
2774
+ case MATH_BIGINTEGER_MODE_BCMATH:
2775
+ $left = $this->toBytes();
2776
+ $right = $x->toBytes();
2777
+
2778
+ $length = max(strlen($left), strlen($right));
2779
+
2780
+ $left = str_pad($left, $length, chr(0), STR_PAD_LEFT);
2781
+ $right = str_pad($right, $length, chr(0), STR_PAD_LEFT);
2782
+
2783
+ return $this->_normalize(new Math_BigInteger($left & $right, 256));
2784
+ }
2785
+
2786
+ $result = $this->copy();
2787
+
2788
+ $length = min(count($x->value), count($this->value));
2789
+
2790
+ $result->value = array_slice($result->value, 0, $length);
2791
+
2792
+ for ($i = 0; $i < $length; ++$i) {
2793
+ $result->value[$i]&= $x->value[$i];
2794
+ }
2795
+
2796
+ return $this->_normalize($result);
2797
+ }
2798
+
2799
+ /**
2800
+ * Logical Or
2801
+ *
2802
+ * @param Math_BigInteger $x
2803
+ * @access public
2804
+ * @internal Implemented per a request by Lluis Pamies i Juarez <lluis _a_ pamies.cat>
2805
+ * @return Math_BigInteger
2806
+ */
2807
+ function bitwise_or($x)
2808
+ {
2809
+ switch ( MATH_BIGINTEGER_MODE ) {
2810
+ case MATH_BIGINTEGER_MODE_GMP:
2811
+ $temp = new Math_BigInteger();
2812
+ $temp->value = gmp_or($this->value, $x->value);
2813
+
2814
+ return $this->_normalize($temp);
2815
+ case MATH_BIGINTEGER_MODE_BCMATH:
2816
+ $left = $this->toBytes();
2817
+ $right = $x->toBytes();
2818
+
2819
+ $length = max(strlen($left), strlen($right));
2820
+
2821
+ $left = str_pad($left, $length, chr(0), STR_PAD_LEFT);
2822
+ $right = str_pad($right, $length, chr(0), STR_PAD_LEFT);
2823
+
2824
+ return $this->_normalize(new Math_BigInteger($left | $right, 256));
2825
+ }
2826
+
2827
+ $length = max(count($this->value), count($x->value));
2828
+ $result = $this->copy();
2829
+ $result->value = array_pad($result->value, $length, 0);
2830
+ $x->value = array_pad($x->value, $length, 0);
2831
+
2832
+ for ($i = 0; $i < $length; ++$i) {
2833
+ $result->value[$i]|= $x->value[$i];
2834
+ }
2835
+
2836
+ return $this->_normalize($result);
2837
+ }
2838
+
2839
+ /**
2840
+ * Logical Exclusive-Or
2841
+ *
2842
+ * @param Math_BigInteger $x
2843
+ * @access public
2844
+ * @internal Implemented per a request by Lluis Pamies i Juarez <lluis _a_ pamies.cat>
2845
+ * @return Math_BigInteger
2846
+ */
2847
+ function bitwise_xor($x)
2848
+ {
2849
+ switch ( MATH_BIGINTEGER_MODE ) {
2850
+ case MATH_BIGINTEGER_MODE_GMP:
2851
+ $temp = new Math_BigInteger();
2852
+ $temp->value = gmp_xor($this->value, $x->value);
2853
+
2854
+ return $this->_normalize($temp);
2855
+ case MATH_BIGINTEGER_MODE_BCMATH:
2856
+ $left = $this->toBytes();
2857
+ $right = $x->toBytes();
2858
+
2859
+ $length = max(strlen($left), strlen($right));
2860
+
2861
+ $left = str_pad($left, $length, chr(0), STR_PAD_LEFT);
2862
+ $right = str_pad($right, $length, chr(0), STR_PAD_LEFT);
2863
+
2864
+ return $this->_normalize(new Math_BigInteger($left ^ $right, 256));
2865
+ }
2866
+
2867
+ $length = max(count($this->value), count($x->value));
2868
+ $result = $this->copy();
2869
+ $result->value = array_pad($result->value, $length, 0);
2870
+ $x->value = array_pad($x->value, $length, 0);
2871
+
2872
+ for ($i = 0; $i < $length; ++$i) {
2873
+ $result->value[$i]^= $x->value[$i];
2874
+ }
2875
+
2876
+ return $this->_normalize($result);
2877
+ }
2878
+
2879
+ /**
2880
+ * Logical Not
2881
+ *
2882
+ * @access public
2883
+ * @internal Implemented per a request by Lluis Pamies i Juarez <lluis _a_ pamies.cat>
2884
+ * @return Math_BigInteger
2885
+ */
2886
+ function bitwise_not()
2887
+ {
2888
+ // calculuate "not" without regard to $this->precision
2889
+ // (will always result in a smaller number. ie. ~1 isn't 1111 1110 - it's 0)
2890
+ $temp = $this->toBytes();
2891
+ $pre_msb = decbin(ord($temp[0]));
2892
+ $temp = ~$temp;
2893
+ $msb = decbin(ord($temp[0]));
2894
+ if (strlen($msb) == 8) {
2895
+ $msb = substr($msb, strpos($msb, '0'));
2896
+ }
2897
+ $temp[0] = chr(bindec($msb));
2898
+
2899
+ // see if we need to add extra leading 1's
2900
+ $current_bits = strlen($pre_msb) + 8 * strlen($temp) - 8;
2901
+ $new_bits = $this->precision - $current_bits;
2902
+ if ($new_bits <= 0) {
2903
+ return $this->_normalize(new Math_BigInteger($temp, 256));
2904
+ }
2905
+
2906
+ // generate as many leading 1's as we need to.
2907
+ $leading_ones = chr((1 << ($new_bits & 0x7)) - 1) . str_repeat(chr(0xFF), $new_bits >> 3);
2908
+ $this->_base256_lshift($leading_ones, $current_bits);
2909
+
2910
+ $temp = str_pad($temp, strlen($leading_ones), chr(0), STR_PAD_LEFT);
2911
+
2912
+ return $this->_normalize(new Math_BigInteger($leading_ones | $temp, 256));
2913
+ }
2914
+
2915
+ /**
2916
+ * Logical Right Shift
2917
+ *
2918
+ * Shifts BigInteger's by $shift bits, effectively dividing by 2**$shift.
2919
+ *
2920
+ * @param Integer $shift
2921
+ * @return Math_BigInteger
2922
+ * @access public
2923
+ * @internal The only version that yields any speed increases is the internal version.
2924
+ */
2925
+ function bitwise_rightShift($shift)
2926
+ {
2927
+ $temp = new Math_BigInteger();
2928
+
2929
+ switch ( MATH_BIGINTEGER_MODE ) {
2930
+ case MATH_BIGINTEGER_MODE_GMP:
2931
+ static $two;
2932
+
2933
+ if (!isset($two)) {
2934
+ $two = gmp_init('2');
2935
+ }
2936
+
2937
+ $temp->value = gmp_div_q($this->value, gmp_pow($two, $shift));
2938
+
2939
+ break;
2940
+ case MATH_BIGINTEGER_MODE_BCMATH:
2941
+ $temp->value = bcdiv($this->value, bcpow('2', $shift, 0), 0);
2942
+
2943
+ break;
2944
+ default: // could just replace _lshift with this, but then all _lshift() calls would need to be rewritten
2945
+ // and I don't want to do that...
2946
+ $temp->value = $this->value;
2947
+ $temp->_rshift($shift);
2948
+ }
2949
+
2950
+ return $this->_normalize($temp);
2951
+ }
2952
+
2953
+ /**
2954
+ * Logical Left Shift
2955
+ *
2956
+ * Shifts BigInteger's by $shift bits, effectively multiplying by 2**$shift.
2957
+ *
2958
+ * @param Integer $shift
2959
+ * @return Math_BigInteger
2960
+ * @access public
2961
+ * @internal The only version that yields any speed increases is the internal version.
2962
+ */
2963
+ function bitwise_leftShift($shift)
2964
+ {
2965
+ $temp = new Math_BigInteger();
2966
+
2967
+ switch ( MATH_BIGINTEGER_MODE ) {
2968
+ case MATH_BIGINTEGER_MODE_GMP:
2969
+ static $two;
2970
+
2971
+ if (!isset($two)) {
2972
+ $two = gmp_init('2');
2973
+ }
2974
+
2975
+ $temp->value = gmp_mul($this->value, gmp_pow($two, $shift));
2976
+
2977
+ break;
2978
+ case MATH_BIGINTEGER_MODE_BCMATH:
2979
+ $temp->value = bcmul($this->value, bcpow('2', $shift, 0), 0);
2980
+
2981
+ break;
2982
+ default: // could just replace _rshift with this, but then all _lshift() calls would need to be rewritten
2983
+ // and I don't want to do that...
2984
+ $temp->value = $this->value;
2985
+ $temp->_lshift($shift);
2986
+ }
2987
+
2988
+ return $this->_normalize($temp);
2989
+ }
2990
+
2991
+ /**
2992
+ * Logical Left Rotate
2993
+ *
2994
+ * Instead of the top x bits being dropped they're appended to the shifted bit string.
2995
+ *
2996
+ * @param Integer $shift
2997
+ * @return Math_BigInteger
2998
+ * @access public
2999
+ */
3000
+ function bitwise_leftRotate($shift)
3001
+ {
3002
+ $bits = $this->toBytes();
3003
+
3004
+ if ($this->precision > 0) {
3005
+ $precision = $this->precision;
3006
+ if ( MATH_BIGINTEGER_MODE == MATH_BIGINTEGER_MODE_BCMATH ) {
3007
+ $mask = $this->bitmask->subtract(new Math_BigInteger(1));
3008
+ $mask = $mask->toBytes();
3009
+ } else {
3010
+ $mask = $this->bitmask->toBytes();
3011
+ }
3012
+ } else {
3013
+ $temp = ord($bits[0]);
3014
+ for ($i = 0; $temp >> $i; ++$i);
3015
+ $precision = 8 * strlen($bits) - 8 + $i;
3016
+ $mask = chr((1 << ($precision & 0x7)) - 1) . str_repeat(chr(0xFF), $precision >> 3);
3017
+ }
3018
+
3019
+ if ($shift < 0) {
3020
+ $shift+= $precision;
3021
+ }
3022
+ $shift%= $precision;
3023
+
3024
+ if (!$shift) {
3025
+ return $this->copy();
3026
+ }
3027
+
3028
+ $left = $this->bitwise_leftShift($shift);
3029
+ $left = $left->bitwise_and(new Math_BigInteger($mask, 256));
3030
+ $right = $this->bitwise_rightShift($precision - $shift);
3031
+ $result = MATH_BIGINTEGER_MODE != MATH_BIGINTEGER_MODE_BCMATH ? $left->bitwise_or($right) : $left->add($right);
3032
+ return $this->_normalize($result);
3033
+ }
3034
+
3035
+ /**
3036
+ * Logical Right Rotate
3037
+ *
3038
+ * Instead of the bottom x bits being dropped they're prepended to the shifted bit string.
3039
+ *
3040
+ * @param Integer $shift
3041
+ * @return Math_BigInteger
3042
+ * @access public
3043
+ */
3044
+ function bitwise_rightRotate($shift)
3045
+ {
3046
+ return $this->bitwise_leftRotate(-$shift);
3047
+ }
3048
+
3049
+ /**
3050
+ * Set random number generator function
3051
+ *
3052
+ * This function is deprecated.
3053
+ *
3054
+ * @param String $generator
3055
+ * @access public
3056
+ */
3057
+ function setRandomGenerator($generator)
3058
+ {
3059
+ }
3060
+
3061
+ /**
3062
+ * Generates a random BigInteger
3063
+ *
3064
+ * Byte length is equal to $length. Uses crypt_random if it's loaded and mt_rand if it's not.
3065
+ *
3066
+ * @param Integer $length
3067
+ * @return Math_BigInteger
3068
+ * @access private
3069
+ */
3070
+ function _random_number_helper($size)
3071
+ {
3072
+ if (function_exists('crypt_random_string')) {
3073
+ $random = crypt_random_string($size);
3074
+ } else {
3075
+ $random = '';
3076
+
3077
+ if ($size & 1) {
3078
+ $random.= chr(mt_rand(0, 255));
3079
+ }
3080
+
3081
+ $blocks = $size >> 1;
3082
+ for ($i = 0; $i < $blocks; ++$i) {
3083
+ // mt_rand(-2147483648, 0x7FFFFFFF) always produces -2147483648 on some systems
3084
+ $random.= pack('n', mt_rand(0, 0xFFFF));
3085
+ }
3086
+ }
3087
+
3088
+ return new Math_BigInteger($random, 256);
3089
+ }
3090
+
3091
+ /**
3092
+ * Generate a random number
3093
+ *
3094
+ * Returns a random number between $min and $max where $min and $max
3095
+ * can be defined using one of the two methods:
3096
+ *
3097
+ * $min->random($max)
3098
+ * $max->random($min)
3099
+ *
3100
+ * @param Math_BigInteger $arg1
3101
+ * @param optional Math_BigInteger $arg2
3102
+ * @return Math_BigInteger
3103
+ * @access public
3104
+ * @internal The API for creating random numbers used to be $a->random($min, $max), where $a was a Math_BigInteger object.
3105
+ * That method is still supported for BC purposes.
3106
+ */
3107
+ function random($arg1, $arg2 = false)
3108
+ {
3109
+ if ($arg1 === false) {
3110
+ return false;
3111
+ }
3112
+
3113
+ if ($arg2 === false) {
3114
+ $max = $arg1;
3115
+ $min = $this;
3116
+ } else {
3117
+ $min = $arg1;
3118
+ $max = $arg2;
3119
+ }
3120
+
3121
+ $compare = $max->compare($min);
3122
+
3123
+ if (!$compare) {
3124
+ return $this->_normalize($min);
3125
+ } else if ($compare < 0) {
3126
+ // if $min is bigger then $max, swap $min and $max
3127
+ $temp = $max;
3128
+ $max = $min;
3129
+ $min = $temp;
3130
+ }
3131
+
3132
+ static $one;
3133
+ if (!isset($one)) {
3134
+ $one = new Math_BigInteger(1);
3135
+ }
3136
+
3137
+ $max = $max->subtract($min->subtract($one));
3138
+ $size = strlen(ltrim($max->toBytes(), chr(0)));
3139
+
3140
+ /*
3141
+ doing $random % $max doesn't work because some numbers will be more likely to occur than others.
3142
+ eg. if $max is 140 and $random's max is 255 then that'd mean both $random = 5 and $random = 145
3143
+ would produce 5 whereas the only value of random that could produce 139 would be 139. ie.
3144
+ not all numbers would be equally likely. some would be more likely than others.
3145
+
3146
+ creating a whole new random number until you find one that is within the range doesn't work
3147
+ because, for sufficiently small ranges, the likelihood that you'd get a number within that range
3148
+ would be pretty small. eg. with $random's max being 255 and if your $max being 1 the probability
3149
+ would be pretty high that $random would be greater than $max.
3150
+
3151
+ phpseclib works around this using the technique described here:
3152
+
3153
+ http://crypto.stackexchange.com/questions/5708/creating-a-small-number-from-a-cryptographically-secure-random-string
3154
+ */
3155
+ $random_max = new Math_BigInteger(chr(1) . str_repeat("\0", $size), 256);
3156
+ $random = $this->_random_number_helper($size);
3157
+
3158
+ list($max_multiple) = $random_max->divide($max);
3159
+ $max_multiple = $max_multiple->multiply($max);
3160
+
3161
+ while ($random->compare($max_multiple) >= 0) {
3162
+ $random = $random->subtract($max_multiple);
3163
+ $random_max = $random_max->subtract($max_multiple);
3164
+ $random = $random->bitwise_leftShift(8);
3165
+ $random = $random->add($this->_random_number_helper(1));
3166
+ $random_max = $random_max->bitwise_leftShift(8);
3167
+ list($max_multiple) = $random_max->divide($max);
3168
+ $max_multiple = $max_multiple->multiply($max);
3169
+ }
3170
+ list(, $random) = $random->divide($max);
3171
+
3172
+ return $this->_normalize($random->add($min));
3173
+ }
3174
+
3175
+ /**
3176
+ * Generate a random prime number.
3177
+ *
3178
+ * If there's not a prime within the given range, false will be returned. If more than $timeout seconds have elapsed,
3179
+ * give up and return false.
3180
+ *
3181
+ * @param Math_BigInteger $arg1
3182
+ * @param optional Math_BigInteger $arg2
3183
+ * @param optional Integer $timeout
3184
+ * @return Mixed
3185
+ * @access public
3186
+ * @internal See {@link http://www.cacr.math.uwaterloo.ca/hac/about/chap4.pdf#page=15 HAC 4.44}.
3187
+ */
3188
+ function randomPrime($arg1, $arg2 = false, $timeout = false)
3189
+ {
3190
+ if ($arg1 === false) {
3191
+ return false;
3192
+ }
3193
+
3194
+ if ($arg2 === false) {
3195
+ $max = $arg1;
3196
+ $min = $this;
3197
+ } else {
3198
+ $min = $arg1;
3199
+ $max = $arg2;
3200
+ }
3201
+
3202
+ $compare = $max->compare($min);
3203
+
3204
+ if (!$compare) {
3205
+ return $min->isPrime() ? $min : false;
3206
+ } else if ($compare < 0) {
3207
+ // if $min is bigger then $max, swap $min and $max
3208
+ $temp = $max;
3209
+ $max = $min;
3210
+ $min = $temp;
3211
+ }
3212
+
3213
+ static $one, $two;
3214
+ if (!isset($one)) {
3215
+ $one = new Math_BigInteger(1);
3216
+ $two = new Math_BigInteger(2);
3217
+ }
3218
+
3219
+ $start = time();
3220
+
3221
+ $x = $this->random($min, $max);
3222
+
3223
+ // gmp_nextprime() requires PHP 5 >= 5.2.0 per <http://php.net/gmp-nextprime>.
3224
+ if ( MATH_BIGINTEGER_MODE == MATH_BIGINTEGER_MODE_GMP && function_exists('gmp_nextprime') ) {
3225
+ $p = new Math_BigInteger();
3226
+ $p->value = gmp_nextprime($x->value);
3227
+
3228
+ if ($p->compare($max) <= 0) {
3229
+ return $p;
3230
+ }
3231
+
3232
+ if (!$min->equals($x)) {
3233
+ $x = $x->subtract($one);
3234
+ }
3235
+
3236
+ return $x->randomPrime($min, $x);
3237
+ }
3238
+
3239
+ if ($x->equals($two)) {
3240
+ return $x;
3241
+ }
3242
+
3243
+ $x->_make_odd();
3244
+ if ($x->compare($max) > 0) {
3245
+ // if $x > $max then $max is even and if $min == $max then no prime number exists between the specified range
3246
+ if ($min->equals($max)) {
3247
+ return false;
3248
+ }
3249
+ $x = $min->copy();
3250
+ $x->_make_odd();
3251
+ }
3252
+
3253
+ $initial_x = $x->copy();
3254
+
3255
+ while (true) {
3256
+ if ($timeout !== false && time() - $start > $timeout) {
3257
+ return false;
3258
+ }
3259
+
3260
+ if ($x->isPrime()) {
3261
+ return $x;
3262
+ }
3263
+
3264
+ $x = $x->add($two);
3265
+
3266
+ if ($x->compare($max) > 0) {
3267
+ $x = $min->copy();
3268
+ if ($x->equals($two)) {
3269
+ return $x;
3270
+ }
3271
+ $x->_make_odd();
3272
+ }
3273
+
3274
+ if ($x->equals($initial_x)) {
3275
+ return false;
3276
+ }
3277
+ }
3278
+ }
3279
+
3280
+ /**
3281
+ * Make the current number odd
3282
+ *
3283
+ * If the current number is odd it'll be unchanged. If it's even, one will be added to it.
3284
+ *
3285
+ * @see randomPrime()
3286
+ * @access private
3287
+ */
3288
+ function _make_odd()
3289
+ {
3290
+ switch ( MATH_BIGINTEGER_MODE ) {
3291
+ case MATH_BIGINTEGER_MODE_GMP:
3292
+ gmp_setbit($this->value, 0);
3293
+ break;
3294
+ case MATH_BIGINTEGER_MODE_BCMATH:
3295
+ if ($this->value[strlen($this->value) - 1] % 2 == 0) {
3296
+ $this->value = bcadd($this->value, '1');
3297
+ }
3298
+ break;
3299
+ default:
3300
+ $this->value[0] |= 1;
3301
+ }
3302
+ }
3303
+
3304
+ /**
3305
+ * Checks a numer to see if it's prime
3306
+ *
3307
+ * Assuming the $t parameter is not set, this function has an error rate of 2**-80. The main motivation for the
3308
+ * $t parameter is distributability. Math_BigInteger::randomPrime() can be distributed across multiple pageloads
3309
+ * on a website instead of just one.
3310
+ *
3311
+ * @param optional Math_BigInteger $t
3312
+ * @return Boolean
3313
+ * @access public
3314
+ * @internal Uses the
3315
+ * {@link http://en.wikipedia.org/wiki/Miller%E2%80%93Rabin_primality_test Miller-Rabin primality test}. See
3316
+ * {@link http://www.cacr.math.uwaterloo.ca/hac/about/chap4.pdf#page=8 HAC 4.24}.
3317
+ */
3318
+ function isPrime($t = false)
3319
+ {
3320
+ $length = strlen($this->toBytes());
3321
+
3322
+ if (!$t) {
3323
+ // see HAC 4.49 "Note (controlling the error probability)"
3324
+ // @codingStandardsIgnoreStart
3325
+ if ($length >= 163) { $t = 2; } // floor(1300 / 8)
3326
+ else if ($length >= 106) { $t = 3; } // floor( 850 / 8)
3327
+ else if ($length >= 81 ) { $t = 4; } // floor( 650 / 8)
3328
+ else if ($length >= 68 ) { $t = 5; } // floor( 550 / 8)
3329
+ else if ($length >= 56 ) { $t = 6; } // floor( 450 / 8)
3330
+ else if ($length >= 50 ) { $t = 7; } // floor( 400 / 8)
3331
+ else if ($length >= 43 ) { $t = 8; } // floor( 350 / 8)
3332
+ else if ($length >= 37 ) { $t = 9; } // floor( 300 / 8)
3333
+ else if ($length >= 31 ) { $t = 12; } // floor( 250 / 8)
3334
+ else if ($length >= 25 ) { $t = 15; } // floor( 200 / 8)
3335
+ else if ($length >= 18 ) { $t = 18; } // floor( 150 / 8)
3336
+ else { $t = 27; }
3337
+ // @codingStandardsIgnoreEnd
3338
+ }
3339
+
3340
+ // ie. gmp_testbit($this, 0)
3341
+ // ie. isEven() or !isOdd()
3342
+ switch ( MATH_BIGINTEGER_MODE ) {
3343
+ case MATH_BIGINTEGER_MODE_GMP:
3344
+ return gmp_prob_prime($this->value, $t) != 0;
3345
+ case MATH_BIGINTEGER_MODE_BCMATH:
3346
+ if ($this->value === '2') {
3347
+ return true;
3348
+ }
3349
+ if ($this->value[strlen($this->value) - 1] % 2 == 0) {
3350
+ return false;
3351
+ }
3352
+ break;
3353
+ default:
3354
+ if ($this->value == array(2)) {
3355
+ return true;
3356
+ }
3357
+ if (~$this->value[0] & 1) {
3358
+ return false;
3359
+ }
3360
+ }
3361
+
3362
+ static $primes, $zero, $one, $two;
3363
+
3364
+ if (!isset($primes)) {
3365
+ $primes = array(
3366
+ 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59,
3367
+ 61, 67, 71, 73, 79, 83, 89, 97, 101, 103, 107, 109, 113, 127, 131, 137,
3368
+ 139, 149, 151, 157, 163, 167, 173, 179, 181, 191, 193, 197, 199, 211, 223, 227,
3369
+ 229, 233, 239, 241, 251, 257, 263, 269, 271, 277, 281, 283, 293, 307, 311, 313,
3370
+ 317, 331, 337, 347, 349, 353, 359, 367, 373, 379, 383, 389, 397, 401, 409, 419,
3371
+ 421, 431, 433, 439, 443, 449, 457, 461, 463, 467, 479, 487, 491, 499, 503, 509,
3372
+ 521, 523, 541, 547, 557, 563, 569, 571, 577, 587, 593, 599, 601, 607, 613, 617,
3373
+ 619, 631, 641, 643, 647, 653, 659, 661, 673, 677, 683, 691, 701, 709, 719, 727,
3374
+ 733, 739, 743, 751, 757, 761, 769, 773, 787, 797, 809, 811, 821, 823, 827, 829,
3375
+ 839, 853, 857, 859, 863, 877, 881, 883, 887, 907, 911, 919, 929, 937, 941, 947,
3376
+ 953, 967, 971, 977, 983, 991, 997
3377
+ );
3378
+
3379
+ if ( MATH_BIGINTEGER_MODE != MATH_BIGINTEGER_MODE_INTERNAL ) {
3380
+ for ($i = 0; $i < count($primes); ++$i) {
3381
+ $primes[$i] = new Math_BigInteger($primes[$i]);
3382
+ }
3383
+ }
3384
+
3385
+ $zero = new Math_BigInteger();
3386
+ $one = new Math_BigInteger(1);
3387
+ $two = new Math_BigInteger(2);
3388
+ }
3389
+
3390
+ if ($this->equals($one)) {
3391
+ return false;
3392
+ }
3393
+
3394
+ // see HAC 4.4.1 "Random search for probable primes"
3395
+ if ( MATH_BIGINTEGER_MODE != MATH_BIGINTEGER_MODE_INTERNAL ) {
3396
+ foreach ($primes as $prime) {
3397
+ list(, $r) = $this->divide($prime);
3398
+ if ($r->equals($zero)) {
3399
+ return $this->equals($prime);
3400
+ }
3401
+ }
3402
+ } else {
3403
+ $value = $this->value;
3404
+ foreach ($primes as $prime) {
3405
+ list(, $r) = $this->_divide_digit($value, $prime);
3406
+ if (!$r) {
3407
+ return count($value) == 1 && $value[0] == $prime;
3408
+ }
3409
+ }
3410
+ }
3411
+
3412
+ $n = $this->copy();
3413
+ $n_1 = $n->subtract($one);
3414
+ $n_2 = $n->subtract($two);
3415
+
3416
+ $r = $n_1->copy();
3417
+ $r_value = $r->value;
3418
+ // ie. $s = gmp_scan1($n, 0) and $r = gmp_div_q($n, gmp_pow(gmp_init('2'), $s));
3419
+ if ( MATH_BIGINTEGER_MODE == MATH_BIGINTEGER_MODE_BCMATH ) {
3420
+ $s = 0;
3421
+ // if $n was 1, $r would be 0 and this would be an infinite loop, hence our $this->equals($one) check earlier
3422
+ while ($r->value[strlen($r->value) - 1] % 2 == 0) {
3423
+ $r->value = bcdiv($r->value, '2', 0);
3424
+ ++$s;
3425
+ }
3426
+ } else {
3427
+ for ($i = 0, $r_length = count($r_value); $i < $r_length; ++$i) {
3428
+ $temp = ~$r_value[$i] & 0xFFFFFF;
3429
+ for ($j = 1; ($temp >> $j) & 1; ++$j);
3430
+ if ($j != 25) {
3431
+ break;
3432
+ }
3433
+ }
3434
+ $s = 26 * $i + $j - 1;
3435
+ $r->_rshift($s);
3436
+ }
3437
+
3438
+ for ($i = 0; $i < $t; ++$i) {
3439
+ $a = $this->random($two, $n_2);
3440
+ $y = $a->modPow($r, $n);
3441
+
3442
+ if (!$y->equals($one) && !$y->equals($n_1)) {
3443
+ for ($j = 1; $j < $s && !$y->equals($n_1); ++$j) {
3444
+ $y = $y->modPow($two, $n);
3445
+ if ($y->equals($one)) {
3446
+ return false;
3447
+ }
3448
+ }
3449
+
3450
+ if (!$y->equals($n_1)) {
3451
+ return false;
3452
+ }
3453
+ }
3454
+ }
3455
+ return true;
3456
+ }
3457
+
3458
+ /**
3459
+ * Logical Left Shift
3460
+ *
3461
+ * Shifts BigInteger's by $shift bits.
3462
+ *
3463
+ * @param Integer $shift
3464
+ * @access private
3465
+ */
3466
+ function _lshift($shift)
3467
+ {
3468
+ if ( $shift == 0 ) {
3469
+ return;
3470
+ }
3471
+
3472
+ $num_digits = (int) ($shift / MATH_BIGINTEGER_BASE);
3473
+ $shift %= MATH_BIGINTEGER_BASE;
3474
+ $shift = 1 << $shift;
3475
+
3476
+ $carry = 0;
3477
+
3478
+ for ($i = 0; $i < count($this->value); ++$i) {
3479
+ $temp = $this->value[$i] * $shift + $carry;
3480
+ $carry = MATH_BIGINTEGER_BASE === 26 ? intval($temp / 0x4000000) : ($temp >> 31);
3481
+ $this->value[$i] = (int) ($temp - $carry * MATH_BIGINTEGER_BASE_FULL);
3482
+ }
3483
+
3484
+ if ( $carry ) {
3485
+ $this->value[count($this->value)] = $carry;
3486
+ }
3487
+
3488
+ while ($num_digits--) {
3489
+ array_unshift($this->value, 0);
3490
+ }
3491
+ }
3492
+
3493
+ /**
3494
+ * Logical Right Shift
3495
+ *
3496
+ * Shifts BigInteger's by $shift bits.
3497
+ *
3498
+ * @param Integer $shift
3499
+ * @access private
3500
+ */
3501
+ function _rshift($shift)
3502
+ {
3503
+ if ($shift == 0) {
3504
+ return;
3505
+ }
3506
+
3507
+ $num_digits = (int) ($shift / MATH_BIGINTEGER_BASE);
3508
+ $shift %= MATH_BIGINTEGER_BASE;
3509
+ $carry_shift = MATH_BIGINTEGER_BASE - $shift;
3510
+ $carry_mask = (1 << $shift) - 1;
3511
+
3512
+ if ( $num_digits ) {
3513
+ $this->value = array_slice($this->value, $num_digits);
3514
+ }
3515
+
3516
+ $carry = 0;
3517
+
3518
+ for ($i = count($this->value) - 1; $i >= 0; --$i) {
3519
+ $temp = $this->value[$i] >> $shift | $carry;
3520
+ $carry = ($this->value[$i] & $carry_mask) << $carry_shift;
3521
+ $this->value[$i] = $temp;
3522
+ }
3523
+
3524
+ $this->value = $this->_trim($this->value);
3525
+ }
3526
+
3527
+ /**
3528
+ * Normalize
3529
+ *
3530
+ * Removes leading zeros and truncates (if necessary) to maintain the appropriate precision
3531
+ *
3532
+ * @param Math_BigInteger
3533
+ * @return Math_BigInteger
3534
+ * @see _trim()
3535
+ * @access private
3536
+ */
3537
+ function _normalize($result)
3538
+ {
3539
+ $result->precision = $this->precision;
3540
+ $result->bitmask = $this->bitmask;
3541
+
3542
+ switch ( MATH_BIGINTEGER_MODE ) {
3543
+ case MATH_BIGINTEGER_MODE_GMP:
3544
+ if (!empty($result->bitmask->value)) {
3545
+ $result->value = gmp_and($result->value, $result->bitmask->value);
3546
+ }
3547
+
3548
+ return $result;
3549
+ case MATH_BIGINTEGER_MODE_BCMATH:
3550
+ if (!empty($result->bitmask->value)) {
3551
+ $result->value = bcmod($result->value, $result->bitmask->value);
3552
+ }
3553
+
3554
+ return $result;
3555
+ }
3556
+
3557
+ $value = &$result->value;
3558
+
3559
+ if ( !count($value) ) {
3560
+ return $result;
3561
+ }
3562
+
3563
+ $value = $this->_trim($value);
3564
+
3565
+ if (!empty($result->bitmask->value)) {
3566
+ $length = min(count($value), count($this->bitmask->value));
3567
+ $value = array_slice($value, 0, $length);
3568
+
3569
+ for ($i = 0; $i < $length; ++$i) {
3570
+ $value[$i] = $value[$i] & $this->bitmask->value[$i];
3571
+ }
3572
+ }
3573
+
3574
+ return $result;
3575
+ }
3576
+
3577
+ /**
3578
+ * Trim
3579
+ *
3580
+ * Removes leading zeros
3581
+ *
3582
+ * @param Array $value
3583
+ * @return Math_BigInteger
3584
+ * @access private
3585
+ */
3586
+ function _trim($value)
3587
+ {
3588
+ for ($i = count($value) - 1; $i >= 0; --$i) {
3589
+ if ( $value[$i] ) {
3590
+ break;
3591
+ }
3592
+ unset($value[$i]);
3593
+ }
3594
+
3595
+ return $value;
3596
+ }
3597
+
3598
+ /**
3599
+ * Array Repeat
3600
+ *
3601
+ * @param $input Array
3602
+ * @param $multiplier mixed
3603
+ * @return Array
3604
+ * @access private
3605
+ */
3606
+ function _array_repeat($input, $multiplier)
3607
+ {
3608
+ return ($multiplier) ? array_fill(0, $multiplier, $input) : array();
3609
+ }
3610
+
3611
+ /**
3612
+ * Logical Left Shift
3613
+ *
3614
+ * Shifts binary strings $shift bits, essentially multiplying by 2**$shift.
3615
+ *
3616
+ * @param $x String
3617
+ * @param $shift Integer
3618
+ * @return String
3619
+ * @access private
3620
+ */
3621
+ function _base256_lshift(&$x, $shift)
3622
+ {
3623
+ if ($shift == 0) {
3624
+ return;
3625
+ }
3626
+
3627
+ $num_bytes = $shift >> 3; // eg. floor($shift/8)
3628
+ $shift &= 7; // eg. $shift % 8
3629
+
3630
+ $carry = 0;
3631
+ for ($i = strlen($x) - 1; $i >= 0; --$i) {
3632
+ $temp = ord($x[$i]) << $shift | $carry;
3633
+ $x[$i] = chr($temp);
3634
+ $carry = $temp >> 8;
3635
+ }
3636
+ $carry = ($carry != 0) ? chr($carry) : '';
3637
+ $x = $carry . $x . str_repeat(chr(0), $num_bytes);
3638
+ }
3639
+
3640
+ /**
3641
+ * Logical Right Shift
3642
+ *
3643
+ * Shifts binary strings $shift bits, essentially dividing by 2**$shift and returning the remainder.
3644
+ *
3645
+ * @param $x String
3646
+ * @param $shift Integer
3647
+ * @return String
3648
+ * @access private
3649
+ */
3650
+ function _base256_rshift(&$x, $shift)
3651
+ {
3652
+ if ($shift == 0) {
3653
+ $x = ltrim($x, chr(0));
3654
+ return '';
3655
+ }
3656
+
3657
+ $num_bytes = $shift >> 3; // eg. floor($shift/8)
3658
+ $shift &= 7; // eg. $shift % 8
3659
+
3660
+ $remainder = '';
3661
+ if ($num_bytes) {
3662
+ $start = $num_bytes > strlen($x) ? -strlen($x) : -$num_bytes;
3663
+ $remainder = substr($x, $start);
3664
+ $x = substr($x, 0, -$num_bytes);
3665
+ }
3666
+
3667
+ $carry = 0;
3668
+ $carry_shift = 8 - $shift;
3669
+ for ($i = 0; $i < strlen($x); ++$i) {
3670
+ $temp = (ord($x[$i]) >> $shift) | $carry;
3671
+ $carry = (ord($x[$i]) << $carry_shift) & 0xFF;
3672
+ $x[$i] = chr($temp);
3673
+ }
3674
+ $x = ltrim($x, chr(0));
3675
+
3676
+ $remainder = chr($carry >> $carry_shift) . $remainder;
3677
+
3678
+ return ltrim($remainder, chr(0));
3679
+ }
3680
+
3681
+ // one quirk about how the following functions are implemented is that PHP defines N to be an unsigned long
3682
+ // at 32-bits, while java's longs are 64-bits.
3683
+
3684
+ /**
3685
+ * Converts 32-bit integers to bytes.
3686
+ *
3687
+ * @param Integer $x
3688
+ * @return String
3689
+ * @access private
3690
+ */
3691
+ function _int2bytes($x)
3692
+ {
3693
+ return ltrim(pack('N', $x), chr(0));
3694
+ }
3695
+
3696
+ /**
3697
+ * Converts bytes to 32-bit integers
3698
+ *
3699
+ * @param String $x
3700
+ * @return Integer
3701
+ * @access private
3702
+ */
3703
+ function _bytes2int($x)
3704
+ {
3705
+ $temp = unpack('Nint', str_pad($x, 4, chr(0), STR_PAD_LEFT));
3706
+ return $temp['int'];
3707
+ }
3708
+
3709
+ /**
3710
+ * DER-encode an integer
3711
+ *
3712
+ * The ability to DER-encode integers is needed to create RSA public keys for use with OpenSSL
3713
+ *
3714
+ * @see modPow()
3715
+ * @access private
3716
+ * @param Integer $length
3717
+ * @return String
3718
+ */
3719
+ function _encodeASN1Length($length)
3720
+ {
3721
+ if ($length <= 0x7F) {
3722
+ return chr($length);
3723
+ }
3724
+
3725
+ $temp = ltrim(pack('N', $length), chr(0));
3726
+ return pack('Ca*', 0x80 | strlen($temp), $temp);
3727
+ }
3728
+
3729
+ /**
3730
+ * Single digit division
3731
+ *
3732
+ * Even if int64 is being used the division operator will return a float64 value
3733
+ * if the dividend is not evenly divisible by the divisor. Since a float64 doesn't
3734
+ * have the precision of int64 this is a problem so, when int64 is being used,
3735
+ * we'll guarantee that the dividend is divisible by first subtracting the remainder.
3736
+ *
3737
+ * @access private
3738
+ * @param Integer $x
3739
+ * @param Integer $y
3740
+ * @return Integer
3741
+ */
3742
+ function _safe_divide($x, $y)
3743
+ {
3744
+ if (MATH_BIGINTEGER_BASE === 26) {
3745
+ return (int) ($x / $y);
3746
+ }
3747
+
3748
+ // MATH_BIGINTEGER_BASE === 31
3749
+ return ($x - ($x % $y)) / $y;
3750
+ }
3751
+ }
phpseclib/Net/SFTP.php CHANGED
@@ -1,5 +1,4 @@
1
  <?php
2
- /* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
3
 
4
  /**
5
  * Pure-PHP implementation of SFTP.
@@ -15,7 +14,7 @@
15
  * Here's a short example of how to use this library:
16
  * <code>
17
  * <?php
18
- * include('Net/SFTP.php');
19
  *
20
  * $sftp = new Net_SFTP('www.domain.tld');
21
  * if (!$sftp->login('username', 'password')) {
@@ -34,10 +33,10 @@
34
  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
35
  * copies of the Software, and to permit persons to whom the Software is
36
  * furnished to do so, subject to the following conditions:
37
- *
38
  * The above copyright notice and this permission notice shall be included in
39
  * all copies or substantial portions of the Software.
40
- *
41
  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
42
  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
43
  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
@@ -46,19 +45,19 @@
46
  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
47
  * THE SOFTWARE.
48
  *
49
- * @category Net
50
- * @package Net_SFTP
51
- * @author Jim Wigginton <terrafrost@php.net>
52
- * @copyright MMIX Jim Wigginton
53
- * @license http://www.opensource.org/licenses/mit-license.html MIT License
54
- * @link http://phpseclib.sourceforge.net
55
  */
56
 
57
  /**
58
  * Include Net_SSH2
59
  */
60
  if (!class_exists('Net_SSH2')) {
61
- require_once('Net/SSH2.php');
62
  }
63
 
64
  /**#@+
@@ -88,7 +87,7 @@ define('NET_SFTP_LOG_REALTIME', 3);
88
  * @see Net_SSH2::_get_channel_packet()
89
  * @access private
90
  */
91
- define('NET_SFTP_CHANNEL', 2);
92
 
93
  /**#@+
94
  * @access public
@@ -97,27 +96,31 @@ define('NET_SFTP_CHANNEL', 2);
97
  /**
98
  * Reads data from a local file.
99
  */
100
- define('NET_SFTP_LOCAL_FILE', 1);
101
  /**
102
  * Reads data from a string.
103
  */
104
  // this value isn't really used anymore but i'm keeping it reserved for historical reasons
105
- define('NET_SFTP_STRING', 2);
106
  /**
107
  * Resumes an upload
108
  */
109
- define('NET_SFTP_RESUME', 4);
 
 
 
 
110
  /**#@-*/
111
 
112
  /**
113
  * Pure-PHP implementations of SFTP.
114
  *
 
115
  * @author Jim Wigginton <terrafrost@php.net>
116
- * @version 0.1.0
117
  * @access public
118
- * @package Net_SFTP
119
  */
120
- class Net_SFTP extends Net_SSH2 {
 
121
  /**
122
  * Packet Types
123
  *
@@ -226,27 +229,48 @@ class Net_SFTP extends Net_SSH2 {
226
  var $sftp_errors = array();
227
 
228
  /**
229
- * File Type
230
  *
231
- * @see Net_SFTP::_parseLongname()
232
- * @var Integer
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
233
  * @access private
234
  */
235
- var $fileType = 0;
236
 
237
  /**
238
- * Directory Cache
239
  *
240
- * Rather than always having to open a directory and close it immediately there after to see if a file is a directory or
241
- * rather than always
 
 
 
 
 
 
 
242
  *
243
- * @see Net_SFTP::_save_dir()
244
- * @see Net_SFTP::_remove_dir()
245
- * @see Net_SFTP::_is_dir()
246
  * @var Array
247
  * @access private
248
  */
249
- var $dirs = array();
250
 
251
  /**
252
  * Default Constructor.
@@ -262,6 +286,9 @@ class Net_SFTP extends Net_SSH2 {
262
  function Net_SFTP($host, $port = 22, $timeout = 10)
263
  {
264
  parent::Net_SSH2($host, $port, $timeout);
 
 
 
265
  $this->packet_types = array(
266
  1 => 'NET_SFTP_INIT',
267
  2 => 'NET_SFTP_VERSION',
@@ -285,6 +312,8 @@ class Net_SFTP extends Net_SSH2 {
285
  SFTPv5+: http://tools.ietf.org/html/draft-ietf-secsh-filexfer-13#section-8.3
286
  pre-SFTPv5 : http://tools.ietf.org/html/draft-ietf-secsh-filexfer-04#section-6.5 */
287
  18 => 'NET_SFTP_RENAME',
 
 
288
 
289
  101=> 'NET_SFTP_STATUS',
290
  102=> 'NET_SFTP_HANDLE',
@@ -306,7 +335,30 @@ class Net_SFTP extends Net_SSH2 {
306
  5 => 'NET_SFTP_STATUS_BAD_MESSAGE',
307
  6 => 'NET_SFTP_STATUS_NO_CONNECTION',
308
  7 => 'NET_SFTP_STATUS_CONNECTION_LOST',
309
- 8 => 'NET_SFTP_STATUS_OP_UNSUPPORTED'
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
310
  );
311
  // http://tools.ietf.org/html/draft-ietf-secsh-filexfer-13#section-7.1
312
  // the order, in this case, matters quite a lot - see Net_SFTP::_parseAttributes() to understand why
@@ -316,7 +368,7 @@ class Net_SFTP extends Net_SSH2 {
316
  0x00000004 => 'NET_SFTP_ATTR_PERMISSIONS',
317
  0x00000008 => 'NET_SFTP_ATTR_ACCESSTIME',
318
  // 0x80000000 will yield a floating point on 32-bit systems and converting floating points to integers
319
- // yields inconsistent behavior depending on how php is compiled. so we left shift -1 (which, in
320
  // two's compliment, consists of all 1 bits) by 31. on 64-bit systems this'll yield 0xFFFFFFFF80000000.
321
  // that's not a problem, however, and 'anded' and a 32-bit number, as all the leading 1 bits are ignored.
322
  -1 << 31 => 'NET_SFTP_ATTR_EXTENDED'
@@ -329,7 +381,8 @@ class Net_SFTP extends Net_SSH2 {
329
  0x00000002 => 'NET_SFTP_OPEN_WRITE',
330
  0x00000004 => 'NET_SFTP_OPEN_APPEND',
331
  0x00000008 => 'NET_SFTP_OPEN_CREATE',
332
- 0x00000010 => 'NET_SFTP_OPEN_TRUNCATE'
 
333
  );
334
  // http://tools.ietf.org/html/draft-ietf-secsh-filexfer-04#section-5.2
335
  // see Net_SFTP::_parseLongname() for an explanation
@@ -337,7 +390,14 @@ class Net_SFTP extends Net_SSH2 {
337
  1 => 'NET_SFTP_TYPE_REGULAR',
338
  2 => 'NET_SFTP_TYPE_DIRECTORY',
339
  3 => 'NET_SFTP_TYPE_SYMLINK',
340
- 4 => 'NET_SFTP_TYPE_SPECIAL'
 
 
 
 
 
 
 
341
  );
342
  $this->_define_array(
343
  $this->packet_types,
@@ -346,6 +406,10 @@ class Net_SFTP extends Net_SSH2 {
346
  $this->open_flags,
347
  $this->file_types
348
  );
 
 
 
 
349
  }
350
 
351
  /**
@@ -356,13 +420,14 @@ class Net_SFTP extends Net_SSH2 {
356
  * @return Boolean
357
  * @access public
358
  */
359
- function login($username, $password = '')
360
  {
361
- if (!parent::login($username, $password)) {
 
362
  return false;
363
  }
364
 
365
- $this->window_size_client_to_server[NET_SFTP_CHANNEL] = $this->window_size;
366
 
367
  $packet = pack('CNa*N3',
368
  NET_SSH2_MSG_CHANNEL_OPEN, strlen('session'), 'session', NET_SFTP_CHANNEL, $this->window_size, 0x4000);
@@ -388,7 +453,24 @@ class Net_SFTP extends Net_SSH2 {
388
 
389
  $response = $this->_get_channel_packet(NET_SFTP_CHANNEL);
390
  if ($response === false) {
391
- return false;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
392
  }
393
 
394
  $this->channel_status[NET_SFTP_CHANNEL] = NET_SSH2_MSG_CHANNEL_DATA;
@@ -460,13 +542,43 @@ class Net_SFTP extends Net_SSH2 {
460
  return false;
461
  }
462
 
463
- $this->pwd = $this->_realpath('.', false);
464
 
465
- $this->_save_dir($this->pwd);
466
 
467
  return true;
468
  }
469
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
470
  /**
471
  * Returns the current directory name
472
  *
@@ -485,7 +597,8 @@ class Net_SFTP extends Net_SSH2 {
485
  * @param optional Integer $status
486
  * @access public
487
  */
488
- function _logError($response, $status = -1) {
 
489
  if ($status == -1) {
490
  extract(unpack('Nstatus', $this->_string_shift($response, 4)));
491
  }
@@ -507,98 +620,57 @@ class Net_SFTP extends Net_SSH2 {
507
  * the absolute (canonicalized) path.
508
  *
509
  * @see Net_SFTP::chdir()
510
- * @param String $dir
511
  * @return Mixed
512
  * @access private
513
  */
514
- function _realpath($dir, $check_dir = true)
515
  {
516
- if ($check_dir && $this->_is_dir($dir)) {
517
- return true;
518
- }
519
-
520
- /*
521
- "This protocol represents file names as strings. File names are
522
- assumed to use the slash ('/') character as a directory separator.
523
-
524
- File names starting with a slash are "absolute", and are relative to
525
- the root of the file system. Names starting with any other character
526
- are relative to the user's default directory (home directory). Note
527
- that identifying the user is assumed to take place outside of this
528
- protocol."
529
-
530
- -- http://tools.ietf.org/html/draft-ietf-secsh-filexfer-13#section-6
531
- */
532
- $file = '';
533
- if ($this->pwd !== false) {
534
- // if the SFTP server returned the canonicalized path even for non-existant files this wouldn't be necessary
535
- // on OpenSSH it isn't necessary but on other SFTP servers it is. that and since the specs say nothing on
536
- // the subject, we'll go ahead and work around it with the following.
537
- if (empty($dir) || $dir[strlen($dir) - 1] != '/') {
538
- $file = basename($dir);
539
- $dir = dirname($dir);
540
- }
541
-
542
- $dir = $dir[0] == '/' ? '/' . rtrim(substr($dir, 1), '/') : rtrim($dir, '/');
543
-
544
- if ($dir == '.' || $dir == $this->pwd) {
545
- $temp = $this->pwd;
546
- if (!empty($file)) {
547
- $temp.= '/' . $file;
548
- }
549
- return $temp;
550
  }
551
 
552
- if ($dir[0] != '/') {
553
- $dir = $this->pwd . '/' . $dir;
 
 
 
 
 
 
 
 
 
 
 
 
 
554
  }
555
- // on the surface it seems like maybe resolving a path beginning with / is unnecessary, but such paths
556
- // can contain .'s and ..'s just like any other. we could parse those out as appropriate or we can let
557
- // the server do it. we'll do the latter.
558
- }
559
-
560
- /*
561
- that SSH_FXP_REALPATH returns SSH_FXP_NAME does not necessarily mean that anything actually exists at the
562
- specified path. generally speaking, no attributes are returned with this particular SSH_FXP_NAME packet
563
- regardless of whether or not a file actually exists. and in SFTPv3, the longname field and the filename
564
- field match for this particular SSH_FXP_NAME packet. for other SSH_FXP_NAME packets, this will likely
565
- not be the case, but for this one, it is.
566
- */
567
- // http://tools.ietf.org/html/draft-ietf-secsh-filexfer-13#section-8.9
568
- if (!$this->_send_sftp_packet(NET_SFTP_REALPATH, pack('Na*', strlen($dir), $dir))) {
569
- return false;
570
  }
571
 
572
- $response = $this->_get_sftp_packet();
573
- switch ($this->packet_type) {
574
- case NET_SFTP_NAME:
575
- // although SSH_FXP_NAME is implemented differently in SFTPv3 than it is in SFTPv4+, the following
576
- // should work on all SFTP versions since the only part of the SSH_FXP_NAME packet the following looks
577
- // at is the first part and that part is defined the same in SFTP versions 3 through 6.
578
- $this->_string_shift($response, 4); // skip over the count - it should be 1, anyway
579
- extract(unpack('Nlength', $this->_string_shift($response, 4)));
580
- $realpath = $this->_string_shift($response, $length);
581
- // the following is SFTPv3 only code. see Net_SFTP::_parseLongname() for more information.
582
- // per the above comment, this is a shot in the dark that, on most servers, won't help us in determining
583
- // the file type for Net_SFTP::stat() and Net_SFTP::lstat() but it's worth a shot.
584
- extract(unpack('Nlength', $this->_string_shift($response, 4)));
585
- $this->fileType = $this->_parseLongname($this->_string_shift($response, $length));
586
- break;
587
- case NET_SFTP_STATUS:
588
- $this->_logError($response);
589
- return false;
590
- default:
591
- user_error('Expected SSH_FXP_NAME or SSH_FXP_STATUS');
592
- return false;
593
  }
594
 
595
- // if $this->pwd isn't set than the only thing $realpath could be is for '.', which is pretty much guaranteed to
596
- // be a bonafide directory
597
- if (!empty($file)) {
598
- $realpath.= '/' . $file;
 
 
 
 
 
 
 
 
 
 
599
  }
600
 
601
- return $realpath;
602
  }
603
 
604
  /**
@@ -614,22 +686,26 @@ class Net_SFTP extends Net_SSH2 {
614
  return false;
615
  }
616
 
617
- if ($dir[strlen($dir) - 1] != '/') {
 
 
 
 
618
  $dir.= '/';
619
  }
620
 
 
 
621
  // confirm that $dir is, in fact, a valid directory
622
- if ($this->_is_dir($dir)) {
623
  $this->pwd = $dir;
624
  return true;
625
  }
626
 
627
- $dir = $this->_realpath($dir, false);
628
-
629
- if ($this->_is_dir($dir)) {
630
- $this->pwd = $dir;
631
- return true;
632
- }
633
 
634
  if (!$this->_send_sftp_packet(NET_SFTP_OPENDIR, pack('Na*', strlen($dir), $dir))) {
635
  return false;
@@ -649,23 +725,11 @@ class Net_SFTP extends Net_SSH2 {
649
  return false;
650
  }
651
 
652
- if (!$this->_send_sftp_packet(NET_SFTP_CLOSE, pack('Na*', strlen($handle), $handle))) {
653
- return false;
654
- }
655
-
656
- $response = $this->_get_sftp_packet();
657
- if ($this->packet_type != NET_SFTP_STATUS) {
658
- user_error('Expected SSH_FXP_STATUS');
659
- return false;
660
- }
661
-
662
- extract(unpack('Nstatus', $this->_string_shift($response, 4)));
663
- if ($status != NET_SFTP_STATUS_OK) {
664
- $this->_logError($response, $status);
665
  return false;
666
  }
667
 
668
- $this->_save_dir($dir);
669
 
670
  $this->pwd = $dir;
671
  return true;
@@ -675,39 +739,94 @@ class Net_SFTP extends Net_SSH2 {
675
  * Returns a list of files in the given directory
676
  *
677
  * @param optional String $dir
 
678
  * @return Mixed
679
  * @access public
680
  */
681
- function nlist($dir = '.')
 
 
 
 
 
 
 
 
 
 
 
 
 
 
682
  {
683
- return $this->_list($dir, false);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
684
  }
685
 
686
  /**
687
  * Returns a detailed list of files in the given directory
688
  *
689
  * @param optional String $dir
 
690
  * @return Mixed
691
  * @access public
692
  */
693
- function rawlist($dir = '.')
694
  {
695
- return $this->_list($dir, true);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
696
  }
697
 
698
  /**
699
  * Reads a list, be it detailed or not, of files in the given directory
700
  *
701
- * $realpath exists because, in the case of the recursive deletes and recursive chmod's $realpath has already
702
- * been calculated.
703
- *
704
  * @param String $dir
705
  * @param optional Boolean $raw
706
- * @param optional Boolean $realpath
707
  * @return Mixed
708
  * @access private
709
  */
710
- function _list($dir, $raw = true, $realpath = true)
711
  {
712
  if (!($this->bitmap & NET_SSH2_MASK_LOGIN)) {
713
  return false;
@@ -740,7 +859,7 @@ class Net_SFTP extends Net_SSH2 {
740
  return false;
741
  }
742
 
743
- $this->_save_dir($dir);
744
 
745
  $contents = array();
746
  while (true) {
@@ -760,18 +879,24 @@ class Net_SFTP extends Net_SSH2 {
760
  $shortname = $this->_string_shift($response, $length);
761
  extract(unpack('Nlength', $this->_string_shift($response, 4)));
762
  $longname = $this->_string_shift($response, $length);
763
- $attributes = $this->_parseAttributes($response); // we also don't care about the attributes
764
- if (!$raw) {
765
- $contents[] = $shortname;
766
- } else {
767
- $contents[$shortname] = $attributes;
768
  $fileType = $this->_parseLongname($longname);
769
  if ($fileType) {
770
- if ($fileType == NET_SFTP_TYPE_DIRECTORY && ($shortname != '.' && $shortname != '..')) {
771
- $this->_save_dir($dir . '/' . $shortname);
772
- }
773
- $contents[$shortname]['type'] = $fileType;
 
 
 
 
 
 
 
 
774
  }
 
775
  }
776
  // SFTPv6 has an optional boolean end-of-list field, but we'll ignore that, since the
777
  // final SSH_FXP_STATUS packet should tell us that, already.
@@ -790,25 +915,115 @@ class Net_SFTP extends Net_SSH2 {
790
  }
791
  }
792
 
793
- if (!$this->_send_sftp_packet(NET_SFTP_CLOSE, pack('Na*', strlen($handle), $handle))) {
794
  return false;
795
  }
796
 
797
- // "The client MUST release all resources associated with the handle regardless of the status."
798
- // -- http://tools.ietf.org/html/draft-ietf-secsh-filexfer-13#section-8.1.3
799
- $response = $this->_get_sftp_packet();
800
- if ($this->packet_type != NET_SFTP_STATUS) {
801
- user_error('Expected SSH_FXP_STATUS');
802
- return false;
803
  }
804
 
805
- extract(unpack('Nstatus', $this->_string_shift($response, 4)));
806
- if ($status != NET_SFTP_STATUS_OK) {
807
- $this->_logError($response, $status);
808
- return false;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
809
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
810
 
811
- return $contents;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
812
  }
813
 
814
  /**
@@ -826,47 +1041,54 @@ class Net_SFTP extends Net_SSH2 {
826
  return false;
827
  }
828
 
829
- $filename = $this->_realpath($filename);
830
- if ($filename === false) {
831
  return false;
832
  }
833
-
834
- return $this->_size($filename);
835
  }
836
 
837
  /**
838
- * Save directories to cache
839
  *
840
- * @param String $dir
 
841
  * @access private
842
  */
843
- function _save_dir($dir)
844
  {
845
- // preg_replace('#^/|/(?=/)|/$#', '', $dir) == str_replace('//', '/', trim($dir, '/'))
846
- $dirs = explode('/', preg_replace('#^/|/(?=/)|/$#', '', $dir));
847
 
848
- $temp = &$this->dirs;
849
- foreach ($dirs as $dir) {
 
850
  if (!isset($temp[$dir])) {
851
  $temp[$dir] = array();
852
  }
 
 
 
 
853
  $temp = &$temp[$dir];
854
  }
855
  }
856
 
857
  /**
858
- * Remove directories from cache
859
  *
860
- * @param String $dir
 
861
  * @access private
862
  */
863
- function _remove_dir($dir)
864
  {
865
- $dirs = explode('/', preg_replace('#^/|/(?=/)|/$#', '', $dir));
866
 
867
- $temp = &$this->dirs;
868
- foreach ($dirs as $dir) {
869
- if ($dir == end($dirs)) {
 
870
  unset($temp[$dir]);
871
  return true;
872
  }
@@ -878,22 +1100,26 @@ class Net_SFTP extends Net_SSH2 {
878
  }
879
 
880
  /**
881
- * Checks cache for directory
 
 
882
  *
883
  * @param String $dir
 
884
  * @access private
885
  */
886
- function _is_dir($dir)
887
  {
888
- $dirs = explode('/', preg_replace('#^/|/(?=/)|/$#', '', $dir));
889
 
890
- $temp = &$this->dirs;
891
  foreach ($dirs as $dir) {
892
  if (!isset($temp[$dir])) {
893
- return false;
894
  }
895
  $temp = &$temp[$dir];
896
  }
 
897
  }
898
 
899
  /**
@@ -916,10 +1142,28 @@ class Net_SFTP extends Net_SSH2 {
916
  return false;
917
  }
918
 
 
 
 
 
 
 
 
 
 
 
919
  $stat = $this->_stat($filename, NET_SFTP_STAT);
920
  if ($stat === false) {
 
921
  return false;
922
  }
 
 
 
 
 
 
 
923
 
924
  $pwd = $this->pwd;
925
  $stat['type'] = $this->chdir($filename) ?
@@ -927,6 +1171,11 @@ class Net_SFTP extends Net_SSH2 {
927
  NET_SFTP_TYPE_REGULAR;
928
  $this->pwd = $pwd;
929
 
 
 
 
 
 
930
  return $stat;
931
  }
932
 
@@ -950,14 +1199,35 @@ class Net_SFTP extends Net_SSH2 {
950
  return false;
951
  }
952
 
 
 
 
 
 
 
 
 
 
 
953
  $lstat = $this->_stat($filename, NET_SFTP_LSTAT);
954
- $stat = $this->_stat($filename, NET_SFTP_STAT);
955
- if ($stat === false) {
956
  return false;
957
  }
 
 
 
 
 
 
 
 
 
958
 
959
  if ($lstat != $stat) {
960
- return array_merge($lstat, array('type' => NET_SFTP_TYPE_SYMLINK));
 
 
961
  }
962
 
963
  $pwd = $this->pwd;
@@ -966,6 +1236,11 @@ class Net_SFTP extends Net_SSH2 {
966
  NET_SFTP_TYPE_REGULAR;
967
  $this->pwd = $pwd;
968
 
 
 
 
 
 
969
  return $lstat;
970
  }
971
 
@@ -991,11 +1266,7 @@ class Net_SFTP extends Net_SSH2 {
991
  $response = $this->_get_sftp_packet();
992
  switch ($this->packet_type) {
993
  case NET_SFTP_ATTRS:
994
- $attributes = $this->_parseAttributes($response);
995
- if ($this->fileType) {
996
- $attributes['type'] = $this->fileType;
997
- }
998
- return $attributes;
999
  case NET_SFTP_STATUS:
1000
  $this->_logError($response);
1001
  return false;
@@ -1006,61 +1277,169 @@ class Net_SFTP extends Net_SSH2 {
1006
  }
1007
 
1008
  /**
1009
- * Attempt to identify the file type
1010
  *
1011
- * @param String $path
1012
- * @param Array $stat
1013
- * @param Array $lstat
1014
- * @return Integer
1015
- * @access private
1016
  */
1017
- function _identify_type($path, $stat1, $stat2)
1018
  {
1019
- $stat1 = $this->_stat($path, $stat1);
1020
- $stat2 = $this->_stat($path, $stat2);
1021
-
1022
- if ($stat1 != $stat2) {
1023
- return array_merge($stat1, array('type' => NET_SFTP_TYPE_SYMLINK));
1024
- }
1025
-
1026
- $pwd = $this->pwd;
1027
- $stat1['type'] = $this->chdir($path) ?
1028
- NET_SFTP_TYPE_DIRECTORY :
1029
- NET_SFTP_TYPE_REGULAR;
1030
- $this->pwd = $pwd;
1031
 
1032
- return $stat1;
1033
  }
1034
 
1035
  /**
1036
- * Returns the file size, in bytes, or false, on failure
1037
  *
1038
- * Determines the size without calling Net_SFTP::_realpath()
1039
  *
1040
  * @param String $filename
1041
- * @return Mixed
1042
- * @access private
 
 
1043
  */
1044
- function _size($filename)
1045
  {
1046
- $result = $this->_stat($filename, NET_SFTP_LSTAT);
1047
- if ($result === false) {
1048
  return false;
1049
  }
1050
- return isset($result['size']) ? $result['size'] : -1;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1051
  }
1052
 
1053
  /**
1054
  * Set permissions on a file.
1055
  *
1056
- * Returns the new file permissions on success or FALSE on error.
 
1057
  *
1058
  * @param Integer $mode
1059
  * @param String $filename
 
1060
  * @return Mixed
1061
  * @access public
1062
  */
1063
  function chmod($mode, $filename, $recursive = false)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1064
  {
1065
  if (!($this->bitmap & NET_SSH2_MASK_LOGIN)) {
1066
  return false;
@@ -1071,22 +1450,23 @@ class Net_SFTP extends Net_SSH2 {
1071
  return false;
1072
  }
1073
 
 
 
1074
  if ($recursive) {
1075
  $i = 0;
1076
- $result = $this->_chmod_recursive($mode, $filename, $i);
1077
  $this->_read_put_responses($i);
1078
  return $result;
1079
  }
1080
 
1081
  // SFTPv4+ has an additional byte field - type - that would need to be sent, as well. setting it to
1082
  // SSH_FILEXFER_TYPE_UNKNOWN might work. if not, we'd have to do an SSH_FXP_STAT before doing an SSH_FXP_SETSTAT.
1083
- $attr = pack('N2', NET_SFTP_ATTR_PERMISSIONS, $mode & 07777);
1084
  if (!$this->_send_sftp_packet(NET_SFTP_SETSTAT, pack('Na*a*', strlen($filename), $filename, $attr))) {
1085
  return false;
1086
  }
1087
 
1088
  /*
1089
- "Because some systems must use separate system calls to set various attributes, it is possible that a failure
1090
  response will be returned, but yet some of the attributes may be have been successfully modified. If possible,
1091
  servers SHOULD avoid this situation; however, clients MUST be aware that this is possible."
1092
 
@@ -1101,50 +1481,33 @@ class Net_SFTP extends Net_SSH2 {
1101
  extract(unpack('Nstatus', $this->_string_shift($response, 4)));
1102
  if ($status != NET_SFTP_STATUS_OK) {
1103
  $this->_logError($response, $status);
1104
- }
1105
-
1106
- // rather than return what the permissions *should* be, we'll return what they actually are. this will also
1107
- // tell us if the file actually exists.
1108
- // incidentally, SFTPv4+ adds an additional 32-bit integer field - flags - to the following:
1109
- $packet = pack('Na*', strlen($filename), $filename);
1110
- if (!$this->_send_sftp_packet(NET_SFTP_STAT, $packet)) {
1111
  return false;
1112
  }
1113
 
1114
- $response = $this->_get_sftp_packet();
1115
- switch ($this->packet_type) {
1116
- case NET_SFTP_ATTRS:
1117
- $attrs = $this->_parseAttributes($response);
1118
- return $attrs['permissions'];
1119
- case NET_SFTP_STATUS:
1120
- $this->_logError($response);
1121
- return false;
1122
- }
1123
-
1124
- user_error('Expected SSH_FXP_ATTRS or SSH_FXP_STATUS');
1125
- return false;
1126
  }
1127
 
1128
  /**
1129
- * Recursively chmods directories on the SFTP server
1130
  *
1131
  * Minimizes directory lookups and SSH_FXP_STATUS requests for speed.
1132
  *
1133
- * @param Integer $mode
1134
- * @param String $filename
 
1135
  * @return Boolean
1136
  * @access private
1137
  */
1138
- function _chmod_recursive($mode, $path, &$i)
1139
  {
1140
  if (!$this->_read_put_responses($i)) {
1141
  return false;
1142
  }
1143
  $i = 0;
1144
- $entries = $this->_list($path, true, false);
1145
 
1146
  if ($entries === false) {
1147
- return $this->chmod($mode, $path);
1148
  }
1149
 
1150
  // normally $entries would have at least . and .. but it might not if the directories
@@ -1153,29 +1516,25 @@ class Net_SFTP extends Net_SSH2 {
1153
  return false;
1154
  }
1155
 
 
1156
  foreach ($entries as $filename=>$props) {
1157
- if ($filename == '.' || $filename == '..') {
1158
- continue;
1159
- }
1160
-
1161
  if (!isset($props['type'])) {
1162
  return false;
1163
  }
1164
 
1165
  $temp = $path . '/' . $filename;
1166
  if ($props['type'] == NET_SFTP_TYPE_DIRECTORY) {
1167
- if (!$this->_chmod_recursive($mode, $temp, $i)) {
1168
  return false;
1169
  }
1170
  } else {
1171
- $attr = pack('N2', NET_SFTP_ATTR_PERMISSIONS, $mode & 07777);
1172
  if (!$this->_send_sftp_packet(NET_SFTP_SETSTAT, pack('Na*a*', strlen($temp), $temp, $attr))) {
1173
  return false;
1174
  }
1175
 
1176
  $i++;
1177
 
1178
- if ($i >= 50) {
1179
  if (!$this->_read_put_responses($i)) {
1180
  return false;
1181
  }
@@ -1184,14 +1543,13 @@ class Net_SFTP extends Net_SSH2 {
1184
  }
1185
  }
1186
 
1187
- $attr = pack('N2', NET_SFTP_ATTR_PERMISSIONS, $mode & 07777);
1188
  if (!$this->_send_sftp_packet(NET_SFTP_SETSTAT, pack('Na*a*', strlen($path), $path, $attr))) {
1189
  return false;
1190
  }
1191
 
1192
  $i++;
1193
 
1194
- if ($i >= 50) {
1195
  if (!$this->_read_put_responses($i)) {
1196
  return false;
1197
  }
@@ -1201,6 +1559,86 @@ class Net_SFTP extends Net_SSH2 {
1201
  return true;
1202
  }
1203
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
  <?php
 
2
 
3
  /**
4
  * Pure-PHP implementation of SFTP.
14
  * Here's a short example of how to use this library:
15
  * <code>
16
  * <?php
17
+ * include 'Net/SFTP.php';
18
  *
19
  * $sftp = new Net_SFTP('www.domain.tld');
20
  * if (!$sftp->login('username', 'password')) {
33
  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
34
  * copies of the Software, and to permit persons to whom the Software is
35
  * furnished to do so, subject to the following conditions:
36
+ *
37
  * The above copyright notice and this permission notice shall be included in
38
  * all copies or substantial portions of the Software.
39
+ *
40
  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
41
  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
42
  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
45
  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
46
  * THE SOFTWARE.
47
  *
48
+ * @category Net
49
+ * @package Net_SFTP
50
+ * @author Jim Wigginton <terrafrost@php.net>
51
+ * @copyright MMIX Jim Wigginton
52
+ * @license http://www.opensource.org/licenses/mit-license.html MIT License
53
+ * @link http://phpseclib.sourceforge.net
54
  */
55
 
56
  /**
57
  * Include Net_SSH2
58
  */
59
  if (!class_exists('Net_SSH2')) {
60
+ include_once 'SSH2.php';
61
  }
62
 
63
  /**#@+
87
  * @see Net_SSH2::_get_channel_packet()
88
  * @access private
89
  */
90
+ define('NET_SFTP_CHANNEL', 0x100);
91
 
92
  /**#@+
93
  * @access public
96
  /**
97
  * Reads data from a local file.
98
  */
99
+ define('NET_SFTP_LOCAL_FILE', 1);
100
  /**
101
  * Reads data from a string.
102
  */
103
  // this value isn't really used anymore but i'm keeping it reserved for historical reasons
104
+ define('NET_SFTP_STRING', 2);
105
  /**
106
  * Resumes an upload
107
  */
108
+ define('NET_SFTP_RESUME', 4);
109
+ /**
110
+ * Append a local file to an already existing remote file
111
+ */
112
+ define('NET_SFTP_RESUME_START', 8);
113
  /**#@-*/
114
 
115
  /**
116
  * Pure-PHP implementations of SFTP.
117
  *
118
+ * @package Net_SFTP
119
  * @author Jim Wigginton <terrafrost@php.net>
 
120
  * @access public
 
121
  */
122
+ class Net_SFTP extends Net_SSH2
123
+ {
124
  /**
125
  * Packet Types
126
  *
229
  var $sftp_errors = array();
230
 
231
  /**
232
+ * Stat Cache
233
  *
234
+ * Rather than always having to open a directory and close it immediately there after to see if a file is a directory
235
+ * we'll cache the results.
236
+ *
237
+ * @see Net_SFTP::_update_stat_cache()
238
+ * @see Net_SFTP::_remove_from_stat_cache()
239
+ * @see Net_SFTP::_query_stat_cache()
240
+ * @var Array
241
+ * @access private
242
+ */
243
+ var $stat_cache = array();
244
+
245
+ /**
246
+ * Max SFTP Packet Size
247
+ *
248
+ * @see Net_SFTP::Net_SFTP()
249
+ * @see Net_SFTP::get()
250
+ * @var Array
251
  * @access private
252
  */
253
+ var $max_sftp_packet;
254
 
255
  /**
256
+ * Stat Cache Flag
257
  *
258
+ * @see Net_SFTP::disableStatCache()
259
+ * @see Net_SFTP::enableStatCache()
260
+ * @var Boolean
261
+ * @access private
262
+ */
263
+ var $use_stat_cache = true;
264
+
265
+ /**
266
+ * Sort Options
267
  *
268
+ * @see Net_SFTP::_comparator()
269
+ * @see Net_SFTP::setListOrder()
 
270
  * @var Array
271
  * @access private
272
  */
273
+ var $sortOptions = array();
274
 
275
  /**
276
  * Default Constructor.
286
  function Net_SFTP($host, $port = 22, $timeout = 10)
287
  {
288
  parent::Net_SSH2($host, $port, $timeout);
289
+
290
+ $this->max_sftp_packet = 1 << 15;
291
+
292
  $this->packet_types = array(
293
  1 => 'NET_SFTP_INIT',
294
  2 => 'NET_SFTP_VERSION',
312
  SFTPv5+: http://tools.ietf.org/html/draft-ietf-secsh-filexfer-13#section-8.3
313
  pre-SFTPv5 : http://tools.ietf.org/html/draft-ietf-secsh-filexfer-04#section-6.5 */
314
  18 => 'NET_SFTP_RENAME',
315
+ 19 => 'NET_SFTP_READLINK',
316
+ 20 => 'NET_SFTP_SYMLINK',
317
 
318
  101=> 'NET_SFTP_STATUS',
319
  102=> 'NET_SFTP_HANDLE',
335
  5 => 'NET_SFTP_STATUS_BAD_MESSAGE',
336
  6 => 'NET_SFTP_STATUS_NO_CONNECTION',
337
  7 => 'NET_SFTP_STATUS_CONNECTION_LOST',
338
+ 8 => 'NET_SFTP_STATUS_OP_UNSUPPORTED',
339
+ 9 => 'NET_SFTP_STATUS_INVALID_HANDLE',
340
+ 10 => 'NET_SFTP_STATUS_NO_SUCH_PATH',
341
+ 11 => 'NET_SFTP_STATUS_FILE_ALREADY_EXISTS',
342
+ 12 => 'NET_SFTP_STATUS_WRITE_PROTECT',
343
+ 13 => 'NET_SFTP_STATUS_NO_MEDIA',
344
+ 14 => 'NET_SFTP_STATUS_NO_SPACE_ON_FILESYSTEM',
345
+ 15 => 'NET_SFTP_STATUS_QUOTA_EXCEEDED',
346
+ 16 => 'NET_SFTP_STATUS_UNKNOWN_PRINCIPAL',
347
+ 17 => 'NET_SFTP_STATUS_LOCK_CONFLICT',
348
+ 18 => 'NET_SFTP_STATUS_DIR_NOT_EMPTY',
349
+ 19 => 'NET_SFTP_STATUS_NOT_A_DIRECTORY',
350
+ 20 => 'NET_SFTP_STATUS_INVALID_FILENAME',
351
+ 21 => 'NET_SFTP_STATUS_LINK_LOOP',
352
+ 22 => 'NET_SFTP_STATUS_CANNOT_DELETE',
353
+ 23 => 'NET_SFTP_STATUS_INVALID_PARAMETER',
354
+ 24 => 'NET_SFTP_STATUS_FILE_IS_A_DIRECTORY',
355
+ 25 => 'NET_SFTP_STATUS_BYTE_RANGE_LOCK_CONFLICT',
356
+ 26 => 'NET_SFTP_STATUS_BYTE_RANGE_LOCK_REFUSED',
357
+ 27 => 'NET_SFTP_STATUS_DELETE_PENDING',
358
+ 28 => 'NET_SFTP_STATUS_FILE_CORRUPT',
359
+ 29 => 'NET_SFTP_STATUS_OWNER_INVALID',
360
+ 30 => 'NET_SFTP_STATUS_GROUP_INVALID',
361
+ 31 => 'NET_SFTP_STATUS_NO_MATCHING_BYTE_RANGE_LOCK'
362
  );
363
  // http://tools.ietf.org/html/draft-ietf-secsh-filexfer-13#section-7.1
364
  // the order, in this case, matters quite a lot - see Net_SFTP::_parseAttributes() to understand why
368
  0x00000004 => 'NET_SFTP_ATTR_PERMISSIONS',
369
  0x00000008 => 'NET_SFTP_ATTR_ACCESSTIME',
370
  // 0x80000000 will yield a floating point on 32-bit systems and converting floating points to integers
371
+ // yields inconsistent behavior depending on how php is compiled. so we left shift -1 (which, in
372
  // two's compliment, consists of all 1 bits) by 31. on 64-bit systems this'll yield 0xFFFFFFFF80000000.
373
  // that's not a problem, however, and 'anded' and a 32-bit number, as all the leading 1 bits are ignored.
374
  -1 << 31 => 'NET_SFTP_ATTR_EXTENDED'
381
  0x00000002 => 'NET_SFTP_OPEN_WRITE',
382
  0x00000004 => 'NET_SFTP_OPEN_APPEND',
383
  0x00000008 => 'NET_SFTP_OPEN_CREATE',
384
+ 0x00000010 => 'NET_SFTP_OPEN_TRUNCATE',
385
+ 0x00000020 => 'NET_SFTP_OPEN_EXCL'
386
  );
387
  // http://tools.ietf.org/html/draft-ietf-secsh-filexfer-04#section-5.2
388
  // see Net_SFTP::_parseLongname() for an explanation
390
  1 => 'NET_SFTP_TYPE_REGULAR',
391
  2 => 'NET_SFTP_TYPE_DIRECTORY',
392
  3 => 'NET_SFTP_TYPE_SYMLINK',
393
+ 4 => 'NET_SFTP_TYPE_SPECIAL',
394
+ 5 => 'NET_SFTP_TYPE_UNKNOWN',
395
+ // the followin types were first defined for use in SFTPv5+
396
+ // http://tools.ietf.org/html/draft-ietf-secsh-filexfer-05#section-5.2
397
+ 6 => 'NET_SFTP_TYPE_SOCKET',
398
+ 7 => 'NET_SFTP_TYPE_CHAR_DEVICE',
399
+ 8 => 'NET_SFTP_TYPE_BLOCK_DEVICE',
400
+ 9 => 'NET_SFTP_TYPE_FIFO'
401
  );
402
  $this->_define_array(
403
  $this->packet_types,
406
  $this->open_flags,
407
  $this->file_types
408
  );
409
+
410
+ if (!defined('NET_SFTP_QUEUE_SIZE')) {
411
+ define('NET_SFTP_QUEUE_SIZE', 50);
412
+ }
413
  }
414
 
415
  /**
420
  * @return Boolean
421
  * @access public
422
  */
423
+ function login($username)
424
  {
425
+ $args = func_get_args();
426
+ if (!call_user_func_array(array(&$this, '_login'), $args)) {
427
  return false;
428
  }
429
 
430
+ $this->window_size_server_to_client[NET_SFTP_CHANNEL] = $this->window_size;
431
 
432
  $packet = pack('CNa*N3',
433
  NET_SSH2_MSG_CHANNEL_OPEN, strlen('session'), 'session', NET_SFTP_CHANNEL, $this->window_size, 0x4000);
453
 
454
  $response = $this->_get_channel_packet(NET_SFTP_CHANNEL);
455
  if ($response === false) {
456
+ // from PuTTY's psftp.exe
457
+ $command = "test -x /usr/lib/sftp-server && exec /usr/lib/sftp-server\n" .
458
+ "test -x /usr/local/lib/sftp-server && exec /usr/local/lib/sftp-server\n" .
459
+ "exec sftp-server";
460
+ // we don't do $this->exec($command, false) because exec() operates on a different channel and plus the SSH_MSG_CHANNEL_OPEN that exec() does
461
+ // is redundant
462
+ $packet = pack('CNNa*CNa*',
463
+ NET_SSH2_MSG_CHANNEL_REQUEST, $this->server_channels[NET_SFTP_CHANNEL], strlen('exec'), 'exec', 1, strlen($command), $command);
464
+ if (!$this->_send_binary_packet($packet)) {
465
+ return false;
466
+ }
467
+
468
+ $this->channel_status[NET_SFTP_CHANNEL] = NET_SSH2_MSG_CHANNEL_REQUEST;
469
+
470
+ $response = $this->_get_channel_packet(NET_SFTP_CHANNEL);
471
+ if ($response === false) {
472
+ return false;
473
+ }
474
  }
475
 
476
  $this->channel_status[NET_SFTP_CHANNEL] = NET_SSH2_MSG_CHANNEL_DATA;
542
  return false;
543
  }
544
 
545
+ $this->pwd = $this->_realpath('.');
546
 
547
+ $this->_update_stat_cache($this->pwd, array());
548
 
549
  return true;
550
  }
551
 
552
+ /**
553
+ * Disable the stat cache
554
+ *
555
+ * @access public
556
+ */
557
+ function disableStatCache()
558
+ {
559
+ $this->use_stat_cache = false;
560
+ }
561
+
562
+ /**
563
+ * Enable the stat cache
564
+ *
565
+ * @access public
566
+ */
567
+ function enableStatCache()
568
+ {
569
+ $this->use_stat_cache = true;
570
+ }
571
+
572
+ /**
573
+ * Clear the stat cache
574
+ *
575
+ * @access public
576
+ */
577
+ function clearStatCache()
578
+ {
579
+ $this->stat_cache = array();
580
+ }
581
+
582
  /**
583
  * Returns the current directory name
584
  *
597
  * @param optional Integer $status
598
  * @access public
599
  */
600
+ function _logError($response, $status = -1)
601
+ {
602
  if ($status == -1) {
603
  extract(unpack('Nstatus', $this->_string_shift($response, 4)));
604
  }
620
  * the absolute (canonicalized) path.
621
  *
622
  * @see Net_SFTP::chdir()
623
+ * @param String $path
624
  * @return Mixed
625
  * @access private
626
  */
627
+ function _realpath($path)
628
  {
629
+ if ($this->pwd === false) {
630
+ // http://tools.ietf.org/html/draft-ietf-secsh-filexfer-13#section-8.9
631
+ if (!$this->_send_sftp_packet(NET_SFTP_REALPATH, pack('Na*', strlen($path), $path))) {
632
+ return false;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
633
  }
634
 
635
+ $response = $this->_get_sftp_packet();
636
+ switch ($this->packet_type) {
637
+ case NET_SFTP_NAME:
638
+ // although SSH_FXP_NAME is implemented differently in SFTPv3 than it is in SFTPv4+, the following
639
+ // should work on all SFTP versions since the only part of the SSH_FXP_NAME packet the following looks
640
+ // at is the first part and that part is defined the same in SFTP versions 3 through 6.
641
+ $this->_string_shift($response, 4); // skip over the count - it should be 1, anyway
642
+ extract(unpack('Nlength', $this->_string_shift($response, 4)));
643
+ return $this->_string_shift($response, $length);
644
+ case NET_SFTP_STATUS:
645
+ $this->_logError($response);
646
+ return false;
647
+ default:
648
+ user_error('Expected SSH_FXP_NAME or SSH_FXP_STATUS');
649
+ return false;
650
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
651
  }
652
 
653
+ if ($path[0] != '/') {
654
+ $path = $this->pwd . '/' . $path;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
655
  }
656
 
657
+ $path = explode('/', $path);
658
+ $new = array();
659
+ foreach ($path as $dir) {
660
+ if (!strlen($dir)) {
661
+ continue;
662
+ }
663
+ switch ($dir) {
664
+ case '..':
665
+ array_pop($new);
666
+ case '.':
667
+ break;
668
+ default:
669
+ $new[] = $dir;
670
+ }
671
  }
672
 
673
+ return '/' . implode('/', $new);
674
  }
675
 
676
  /**
686
  return false;
687
  }
688
 
689
+ // assume current dir if $dir is empty
690
+ if ($dir === '') {
691
+ $dir = './';
692
+ // suffix a slash if needed
693
+ } elseif ($dir[strlen($dir) - 1] != '/') {
694
  $dir.= '/';
695
  }
696
 
697
+ $dir = $this->_realpath($dir);
698
+
699
  // confirm that $dir is, in fact, a valid directory
700
+ if ($this->use_stat_cache && is_array($this->_query_stat_cache($dir))) {
701
  $this->pwd = $dir;
702
  return true;
703
  }
704
 
705
+ // we could do a stat on the alleged $dir to see if it's a directory but that doesn't tell us
706
+ // the currently logged in user has the appropriate permissions or not. maybe you could see if
707
+ // the file's uid / gid match the currently logged in user's uid / gid but how there's no easy
708
+ // way to get those with SFTP
 
 
709
 
710
  if (!$this->_send_sftp_packet(NET_SFTP_OPENDIR, pack('Na*', strlen($dir), $dir))) {
711
  return false;
725
  return false;
726
  }
727
 
728
+ if (!$this->_close_handle($handle)) {
 
 
 
 
 
 
 
 
 
 
 
 
729
  return false;
730
  }
731
 
732
+ $this->_update_stat_cache($dir, array());
733
 
734
  $this->pwd = $dir;
735
  return true;
739
  * Returns a list of files in the given directory
740
  *
741
  * @param optional String $dir
742
+ * @param optional Boolean $recursive
743
  * @return Mixed
744
  * @access public
745
  */
746
+ function nlist($dir = '.', $recursive = false)
747
+ {
748
+ return $this->_nlist_helper($dir, $recursive, '');
749
+ }
750
+
751
+ /**
752
+ * Helper method for nlist
753
+ *
754
+ * @param String $dir
755
+ * @param Boolean $recursive
756
+ * @param String $relativeDir
757
+ * @return Mixed
758
+ * @access private
759
+ */
760
+ function _nlist_helper($dir, $recursive, $relativeDir)
761
  {
762
+ $files = $this->_list($dir, false);
763
+
764
+ if (!$recursive) {
765
+ return $files;
766
+ }
767
+
768
+ $result = array();
769
+ foreach ($files as $value) {
770
+ if ($value == '.' || $value == '..') {
771
+ if ($relativeDir == '') {
772
+ $result[] = $value;
773
+ }
774
+ continue;
775
+ }
776
+ if (is_array($this->_query_stat_cache($this->_realpath($dir . '/' . $value)))) {
777
+ $temp = $this->_nlist_helper($dir . '/' . $value, true, $relativeDir . $value . '/');
778
+ $result = array_merge($result, $temp);
779
+ } else {
780
+ $result[] = $relativeDir . $value;
781
+ }
782
+ }
783
+
784
+ return $result;
785
  }
786
 
787
  /**
788
  * Returns a detailed list of files in the given directory
789
  *
790
  * @param optional String $dir
791
+ * @param optional Boolean $recursive
792
  * @return Mixed
793
  * @access public
794
  */
795
+ function rawlist($dir = '.', $recursive = false)
796
  {
797
+ $files = $this->_list($dir, true);
798
+ if (!$recursive || $files === false) {
799
+ return $files;
800
+ }
801
+
802
+ static $depth = 0;
803
+
804
+ foreach ($files as $key=>$value) {
805
+ if ($depth != 0 && $key == '..') {
806
+ unset($files[$key]);
807
+ continue;
808
+ }
809
+ if ($key != '.' && $key != '..' && is_array($this->_query_stat_cache($this->_realpath($dir . '/' . $key)))) {
810
+ $depth++;
811
+ $files[$key] = $this->rawlist($dir . '/' . $key, true);
812
+ $depth--;
813
+ } else {
814
+ $files[$key] = (object) $value;
815
+ }
816
+ }
817
+
818
+ return $files;
819
  }
820
 
821
  /**
822
  * Reads a list, be it detailed or not, of files in the given directory
823
  *
 
 
 
824
  * @param String $dir
825
  * @param optional Boolean $raw
 
826
  * @return Mixed
827
  * @access private
828
  */
829
+ function _list($dir, $raw = true)
830
  {
831
  if (!($this->bitmap & NET_SSH2_MASK_LOGIN)) {
832
  return false;
859
  return false;
860
  }
861
 
862
+ $this->_update_stat_cache($dir, array());
863
 
864
  $contents = array();
865
  while (true) {
879
  $shortname = $this->_string_shift($response, $length);
880
  extract(unpack('Nlength', $this->_string_shift($response, 4)));
881
  $longname = $this->_string_shift($response, $length);
882
+ $attributes = $this->_parseAttributes($response);
883
+ if (!isset($attributes['type'])) {
 
 
 
884
  $fileType = $this->_parseLongname($longname);
885
  if ($fileType) {
886
+ $attributes['type'] = $fileType;
887
+ }
888
+ }
889
+ $contents[$shortname] = $attributes + array('filename' => $shortname);
890
+
891
+ if (isset($attributes['type']) && $attributes['type'] == NET_SFTP_TYPE_DIRECTORY && ($shortname != '.' && $shortname != '..')) {
892
+ $this->_update_stat_cache($dir . '/' . $shortname, array());
893
+ } else {
894
+ if ($shortname == '..') {
895
+ $temp = $this->_realpath($dir . '/..') . '/.';
896
+ } else {
897
+ $temp = $dir . '/' . $shortname;
898
  }
899
+ $this->_update_stat_cache($temp, (object) $attributes);
900
  }
901
  // SFTPv6 has an optional boolean end-of-list field, but we'll ignore that, since the
902
  // final SSH_FXP_STATUS packet should tell us that, already.
915
  }
916
  }
917
 
918
+ if (!$this->_close_handle($handle)) {
919
  return false;
920
  }
921
 
922
+ if (count($this->sortOptions)) {
923
+ uasort($contents, array(&$this, '_comparator'));
 
 
 
 
924
  }
925
 
926
+ return $raw ? $contents : array_keys($contents);
927
+ }
928
+
929
+ /**
930
+ * Compares two rawlist entries using parameters set by setListOrder()
931
+ *
932
+ * Intended for use with uasort()
933
+ *
934
+ * @param Array $a
935
+ * @param Array $b
936
+ * @return Integer
937
+ * @access private
938
+ */
939
+ function _comparator($a, $b)
940
+ {
941
+ switch (true) {
942
+ case $a['filename'] === '.' || $b['filename'] === '.':
943
+ if ($a['filename'] === $b['filename']) {
944
+ return 0;
945
+ }
946
+ return $a['filename'] === '.' ? -1 : 1;
947
+ case $a['filename'] === '..' || $b['filename'] === '..':
948
+ if ($a['filename'] === $b['filename']) {
949
+ return 0;
950
+ }
951
+ return $a['filename'] === '..' ? -1 : 1;
952
+ case isset($a['type']) && $a['type'] === NET_SFTP_TYPE_DIRECTORY:
953
+ if (!isset($b['type'])) {
954
+ return 1;
955
+ }
956
+ if ($b['type'] !== $a['type']) {
957
+ return -1;
958
+ }
959
+ break;
960
+ case isset($b['type']) && $b['type'] === NET_SFTP_TYPE_DIRECTORY:
961
+ return 1;
962
  }
963
+ foreach ($this->sortOptions as $sort => $order) {
964
+ if (!isset($a[$sort]) || !isset($b[$sort])) {
965
+ if (isset($a[$sort])) {
966
+ return -1;
967
+ }
968
+ if (isset($b[$sort])) {
969
+ return 1;
970
+ }
971
+ return 0;
972
+ }
973
+ switch ($sort) {
974
+ case 'filename':
975
+ $result = strcasecmp($a['filename'], $b['filename']);
976
+ if ($result) {
977
+ return $order === SORT_DESC ? -$result : $result;
978
+ }
979
+ break;
980
+ case 'permissions':
981
+ case 'mode':
982
+ $a[$sort]&= 07777;
983
+ $b[$sort]&= 07777;
984
+ default:
985
+ if ($a[$sort] === $b[$sort]) {
986
+ break;
987
+ }
988
+ return $order === SORT_ASC ? $a[$sort] - $b[$sort] : $b[$sort] - $a[$sort];
989
+ }
990
+ }
991
+ }
992
 
993
+ /**
994
+ * Defines how nlist() and rawlist() will be sorted - if at all.
995
+ *
996
+ * If sorting is enabled directories and files will be sorted independently with
997
+ * directories appearing before files in the resultant array that is returned.
998
+ *
999
+ * Any parameter returned by stat is a valid sort parameter for this function.
1000
+ * Filename comparisons are case insensitive.
1001
+ *
1002
+ * Examples:
1003
+ *
1004
+ * $sftp->setListOrder('filename', SORT_ASC);
1005
+ * $sftp->setListOrder('size', SORT_DESC, 'filename', SORT_ASC);
1006
+ * $sftp->setListOrder(true);
1007
+ * Separates directories from files but doesn't do any sorting beyond that
1008
+ * $sftp->setListOrder();
1009
+ * Don't do any sort of sorting
1010
+ *
1011
+ * @access public
1012
+ */
1013
+ function setListOrder()
1014
+ {
1015
+ $this->sortOptions = array();
1016
+ $args = func_get_args();
1017
+ if (empty($args)) {
1018
+ return;
1019
+ }
1020
+ $len = count($args) & 0x7FFFFFFE;
1021
+ for ($i = 0; $i < $len; $i+=2) {
1022
+ $this->sortOptions[$args[$i]] = $args[$i + 1];
1023
+ }
1024
+ if (!count($this->sortOptions)) {
1025
+ $this->sortOptions = array('bogus' => true);
1026
+ }
1027
  }
1028
 
1029
  /**
1041
  return false;
1042
  }
1043
 
1044
+ $result = $this->stat($filename);
1045
+ if ($result === false) {
1046
  return false;
1047
  }
1048
+ return isset($result['size']) ? $result['size'] : -1;
 
1049
  }
1050
 
1051
  /**
1052
+ * Save files / directories to cache
1053
  *
1054
+ * @param String $path
1055
+ * @param Mixed $value
1056
  * @access private
1057
  */
1058
+ function _update_stat_cache($path, $value)
1059
  {
1060
+ // preg_replace('#^/|/(?=/)|/$#', '', $dir) == str_replace('//', '/', trim($path, '/'))
1061
+ $dirs = explode('/', preg_replace('#^/|/(?=/)|/$#', '', $path));
1062
 
1063
+ $temp = &$this->stat_cache;
1064
+ $max = count($dirs) - 1;
1065
+ foreach ($dirs as $i=>$dir) {
1066
  if (!isset($temp[$dir])) {
1067
  $temp[$dir] = array();
1068
  }
1069
+ if ($i === $max) {
1070
+ $temp[$dir] = $value;
1071
+ break;
1072
+ }
1073
  $temp = &$temp[$dir];
1074
  }
1075
  }
1076
 
1077
  /**
1078
+ * Remove files / directories from cache
1079
  *
1080
+ * @param String $path
1081
+ * @return Boolean
1082
  * @access private
1083
  */
1084
+ function _remove_from_stat_cache($path)
1085
  {
1086
+ $dirs = explode('/', preg_replace('#^/|/(?=/)|/$#', '', $path));
1087
 
1088
+ $temp = &$this->stat_cache;
1089
+ $max = count($dirs) - 1;
1090
+ foreach ($dirs as $i=>$dir) {
1091
+ if ($i === $max) {
1092
  unset($temp[$dir]);
1093
  return true;
1094
  }
1100
  }
1101
 
1102
  /**
1103
+ * Checks cache for path
1104
+ *
1105
+ * Mainly used by file_exists
1106
  *
1107
  * @param String $dir
1108
+ * @return Mixed
1109
  * @access private
1110
  */
1111
+ function _query_stat_cache($path)
1112
  {
1113
+ $dirs = explode('/', preg_replace('#^/|/(?=/)|/$#', '', $path));
1114
 
1115
+ $temp = &$this->stat_cache;
1116
  foreach ($dirs as $dir) {
1117
  if (!isset($temp[$dir])) {
1118
+ return null;
1119
  }
1120
  $temp = &$temp[$dir];
1121
  }
1122
+ return $temp;
1123
  }
1124
 
1125
  /**
1142
  return false;
1143
  }
1144
 
1145
+ if ($this->use_stat_cache) {
1146
+ $result = $this->_query_stat_cache($filename);
1147
+ if (is_array($result) && isset($result['.'])) {
1148
+ return (array) $result['.'];
1149
+ }
1150
+ if (is_object($result)) {
1151
+ return (array) $result;
1152
+ }
1153
+ }
1154
+
1155
  $stat = $this->_stat($filename, NET_SFTP_STAT);
1156
  if ($stat === false) {
1157
+ $this->_remove_from_stat_cache($filename);
1158
  return false;
1159
  }
1160
+ if (isset($stat['type'])) {
1161
+ if ($stat['type'] == NET_SFTP_TYPE_DIRECTORY) {
1162
+ $filename.= '/.';
1163
+ }
1164
+ $this->_update_stat_cache($filename, (object) $stat);
1165
+ return $stat;
1166
+ }
1167
 
1168
  $pwd = $this->pwd;
1169
  $stat['type'] = $this->chdir($filename) ?
1171
  NET_SFTP_TYPE_REGULAR;
1172
  $this->pwd = $pwd;
1173
 
1174
+ if ($stat['type'] == NET_SFTP_TYPE_DIRECTORY) {
1175
+ $filename.= '/.';
1176
+ }
1177
+ $this->_update_stat_cache($filename, (object) $stat);
1178
+
1179
  return $stat;
1180
  }
1181
 
1199
  return false;
1200
  }
1201
 
1202
+ if ($this->use_stat_cache) {
1203
+ $result = $this->_query_stat_cache($filename);
1204
+ if (is_array($result) && isset($result['.'])) {
1205
+ return (array) $result['.'];
1206
+ }
1207
+ if (is_object($result)) {
1208
+ return (array) $result;
1209
+ }
1210
+ }
1211
+
1212
  $lstat = $this->_stat($filename, NET_SFTP_LSTAT);
1213
+ if ($lstat === false) {
1214
+ $this->_remove_from_stat_cache($filename);
1215
  return false;
1216
  }
1217
+ if (isset($lstat['type'])) {
1218
+ if ($lstat['type'] == NET_SFTP_TYPE_DIRECTORY) {
1219
+ $filename.= '/.';
1220
+ }
1221
+ $this->_update_stat_cache($filename, (object) $lstat);
1222
+ return $lstat;
1223
+ }
1224
+
1225
+ $stat = $this->_stat($filename, NET_SFTP_STAT);
1226
 
1227
  if ($lstat != $stat) {
1228
+ $lstat = array_merge($lstat, array('type' => NET_SFTP_TYPE_SYMLINK));
1229
+ $this->_update_stat_cache($filename, (object) $lstat);
1230
+ return $stat;
1231
  }
1232
 
1233
  $pwd = $this->pwd;
1236
  NET_SFTP_TYPE_REGULAR;
1237
  $this->pwd = $pwd;
1238
 
1239
+ if ($lstat['type'] == NET_SFTP_TYPE_DIRECTORY) {
1240
+ $filename.= '/.';
1241
+ }
1242
+ $this->_update_stat_cache($filename, (object) $lstat);
1243
+
1244
  return $lstat;
1245
  }
1246
 
1266
  $response = $this->_get_sftp_packet();
1267
  switch ($this->packet_type) {
1268
  case NET_SFTP_ATTRS:
1269
+ return $this->_parseAttributes($response);
 
 
 
 
1270
  case NET_SFTP_STATUS:
1271
  $this->_logError($response);
1272
  return false;
1277
  }
1278
 
1279
  /**
1280
+ * Truncates a file to a given length
1281
  *
1282
+ * @param String $filename
1283
+ * @param Integer $new_size
1284
+ * @return Boolean
1285
+ * @access public
 
1286
  */
1287
+ function truncate($filename, $new_size)
1288
  {
1289
+ $attr = pack('N3', NET_SFTP_ATTR_SIZE, $new_size / 4294967296, $new_size); // 4294967296 == 0x100000000 == 1<<32
 
 
 
 
 
 
 
 
 
 
 
1290
 
1291
+ return $this->_setstat($filename, $attr, false);
1292
  }
1293
 
1294
  /**
1295
+ * Sets access and modification time of file.
1296
  *
1297
+ * If the file does not exist, it will be created.
1298
  *
1299
  * @param String $filename
1300
+ * @param optional Integer $time
1301
+ * @param optional Integer $atime
1302
+ * @return Boolean
1303
+ * @access public
1304
  */
1305
+ function touch($filename, $time = null, $atime = null)
1306
  {
1307
+ if (!($this->bitmap & NET_SSH2_MASK_LOGIN)) {
 
1308
  return false;
1309
  }
1310
+
1311
+ $filename = $this->_realpath($filename);
1312
+ if ($filename === false) {
1313
+ return false;
1314
+ }
1315
+
1316
+ if (!isset($time)) {
1317
+ $time = time();
1318
+ }
1319
+ if (!isset($atime)) {
1320
+ $atime = $time;
1321
+ }
1322
+
1323
+ $flags = NET_SFTP_OPEN_WRITE | NET_SFTP_OPEN_CREATE | NET_SFTP_OPEN_EXCL;
1324
+ $attr = pack('N3', NET_SFTP_ATTR_ACCESSTIME, $time, $atime);
1325
+ $packet = pack('Na*Na*', strlen($filename), $filename, $flags, $attr);
1326
+ if (!$this->_send_sftp_packet(NET_SFTP_OPEN, $packet)) {
1327
+ return false;
1328
+ }
1329
+
1330
+ $response = $this->_get_sftp_packet();
1331
+ switch ($this->packet_type) {
1332
+ case NET_SFTP_HANDLE:
1333
+ return $this->_close_handle(substr($response, 4));
1334
+ case NET_SFTP_STATUS:
1335
+ $this->_logError($response);
1336
+ break;
1337
+ default:
1338
+ user_error('Expected SSH_FXP_HANDLE or SSH_FXP_STATUS');
1339
+ return false;
1340
+ }
1341
+
1342
+ return $this->_setstat($filename, $attr, false);
1343
+ }
1344
+
1345
+ /**
1346
+ * Changes file or directory owner
1347
+ *
1348
+ * Returns true on success or false on error.
1349
+ *
1350
+ * @param String $filename
1351
+ * @param Integer $uid
1352
+ * @param optional Boolean $recursive
1353
+ * @return Boolean
1354
+ * @access public
1355
+ */
1356
+ function chown($filename, $uid, $recursive = false)
1357
+ {
1358
+ // quoting from <http://www.kernel.org/doc/man-pages/online/pages/man2/chown.2.html>,
1359
+ // "if the owner or group is specified as -1, then that ID is not changed"
1360
+ $attr = pack('N3', NET_SFTP_ATTR_UIDGID, $uid, -1);
1361
+
1362
+ return $this->_setstat($filename, $attr, $recursive);
1363
+ }
1364
+
1365
+ /**
1366
+ * Changes file or directory group
1367
+ *
1368
+ * Returns true on success or false on error.
1369
+ *
1370
+ * @param String $filename
1371
+ * @param Integer $gid
1372
+ * @param optional Boolean $recursive
1373
+ * @return Boolean
1374
+ * @access public
1375
+ */
1376
+ function chgrp($filename, $gid, $recursive = false)
1377
+ {
1378
+ $attr = pack('N3', NET_SFTP_ATTR_UIDGID, -1, $gid);
1379
+
1380
+ return $this->_setstat($filename, $attr, $recursive);
1381
  }
1382
 
1383
  /**
1384
  * Set permissions on a file.
1385
  *
1386
+ * Returns the new file permissions on success or false on error.
1387
+ * If $recursive is true than this just returns true or false.
1388
  *
1389
  * @param Integer $mode
1390
  * @param String $filename
1391
+ * @param optional Boolean $recursive
1392
  * @return Mixed
1393
  * @access public
1394
  */
1395
  function chmod($mode, $filename, $recursive = false)
1396
+ {
1397
+ if (is_string($mode) && is_int($filename)) {
1398
+ $temp = $mode;
1399
+ $mode = $filename;
1400
+ $filename = $temp;
1401
+ }
1402
+
1403
+ $attr = pack('N2', NET_SFTP_ATTR_PERMISSIONS, $mode & 07777);
1404
+ if (!$this->_setstat($filename, $attr, $recursive)) {
1405
+ return false;
1406
+ }
1407
+ if ($recursive) {
1408
+ return true;
1409
+ }
1410
+
1411
+ // rather than return what the permissions *should* be, we'll return what they actually are. this will also
1412
+ // tell us if the file actually exists.
1413
+ // incidentally, SFTPv4+ adds an additional 32-bit integer field - flags - to the following:
1414
+ $packet = pack('Na*', strlen($filename), $filename);
1415
+ if (!$this->_send_sftp_packet(NET_SFTP_STAT, $packet)) {
1416
+ return false;
1417
+ }
1418
+
1419
+ $response = $this->_get_sftp_packet();
1420
+ switch ($this->packet_type) {
1421
+ case NET_SFTP_ATTRS:
1422
+ $attrs = $this->_parseAttributes($response);
1423
+ return $attrs['permissions'];
1424
+ case NET_SFTP_STATUS:
1425
+ $this->_logError($response);
1426
+ return false;
1427
+ }
1428
+
1429
+ user_error('Expected SSH_FXP_ATTRS or SSH_FXP_STATUS');
1430
+ return false;
1431
+ }
1432
+
1433
+ /**
1434
+ * Sets information about a file
1435
+ *
1436
+ * @param String $filename
1437
+ * @param String $attr
1438
+ * @param Boolean $recursive
1439
+ * @return Boolean
1440
+ * @access private
1441
+ */
1442
+ function _setstat($filename, $attr, $recursive)
1443
  {
1444
  if (!($this->bitmap & NET_SSH2_MASK_LOGIN)) {
1445
  return false;
1450
  return false;
1451
  }
1452
 
1453
+ $this->_remove_from_stat_cache($filename);
1454
+
1455
  if ($recursive) {
1456
  $i = 0;
1457
+ $result = $this->_setstat_recursive($filename, $attr, $i);
1458
  $this->_read_put_responses($i);
1459
  return $result;
1460
  }
1461
 
1462
  // SFTPv4+ has an additional byte field - type - that would need to be sent, as well. setting it to
1463
  // SSH_FILEXFER_TYPE_UNKNOWN might work. if not, we'd have to do an SSH_FXP_STAT before doing an SSH_FXP_SETSTAT.
 
1464
  if (!$this->_send_sftp_packet(NET_SFTP_SETSTAT, pack('Na*a*', strlen($filename), $filename, $attr))) {
1465
  return false;
1466
  }
1467
 
1468
  /*
1469
+ "Because some systems must use separate system calls to set various attributes, it is possible that a failure
1470
  response will be returned, but yet some of the attributes may be have been successfully modified. If possible,
1471
  servers SHOULD avoid this situation; however, clients MUST be aware that this is possible."
1472
 
1481
  extract(unpack('Nstatus', $this->_string_shift($response, 4)));
1482
  if ($status != NET_SFTP_STATUS_OK) {
1483
  $this->_logError($response, $status);
 
 
 
 
 
 
 
1484
  return false;
1485
  }
1486
 
1487
+ return true;
 
 
 
 
 
 
 
 
 
 
 
1488
  }
1489
 
1490
  /**
1491
+ * Recursively sets information on directories on the SFTP server
1492
  *
1493
  * Minimizes directory lookups and SSH_FXP_STATUS requests for speed.
1494
  *
1495
+ * @param String $path
1496
+ * @param String $attr
1497
+ * @param Integer $i
1498
  * @return Boolean
1499
  * @access private
1500
  */
1501
+ function _setstat_recursive($path, $attr, &$i)
1502
  {
1503
  if (!$this->_read_put_responses($i)) {
1504
  return false;
1505
  }
1506
  $i = 0;
1507
+ $entries = $this->_list($path, true);
1508
 
1509
  if ($entries === false) {
1510
+ return $this->_setstat($path, $attr, false);
1511
  }
1512
 
1513
  // normally $entries would have at least . and .. but it might not if the directories
1516
  return false;
1517
  }
1518
 
1519
+ unset($entries['.'], $entries['..']);
1520
  foreach ($entries as $filename=>$props) {
 
 
 
 
1521
  if (!isset($props['type'])) {
1522
  return false;
1523
  }
1524
 
1525
  $temp = $path . '/' . $filename;
1526
  if ($props['type'] == NET_SFTP_TYPE_DIRECTORY) {
1527
+ if (!$this->_setstat_recursive($temp, $attr, $i)) {
1528
  return false;
1529
  }
1530
  } else {
 
1531
  if (!$this->_send_sftp_packet(NET_SFTP_SETSTAT, pack('Na*a*', strlen($temp), $temp, $attr))) {
1532
  return false;
1533
  }
1534
 
1535
  $i++;
1536
 
1537
+ if ($i >= NET_SFTP_QUEUE_SIZE) {
1538
  if (!$this->_read_put_responses($i)) {
1539
  return false;
1540
  }
1543
  }
1544
  }
1545
 
 
1546
  if (!$this->_send_sftp_packet(NET_SFTP_SETSTAT, pack('Na*a*', strlen($path), $path, $attr))) {
1547
  return false;
1548
  }
1549
 
1550
  $i++;
1551
 
1552
+ if ($i >= NET_SFTP_QUEUE_SIZE) {
1553
  if (!$this->_read_put_responses($i)) {
1554
  return false;
1555
  }
1559
  return true;
1560
  }
1561
 
1562
+ /**
1563
+ * Return the target of a symbolic link
1564
+ *
1565
+ * @param String $link
1566
+ * @return Mixed
1567
+ * @access public
1568
+ */
1569
+ function readlink($link)
1570
+ {
1571
+ if (!($this->bitmap & NET_SSH2_MASK_LOGIN)) {
1572
+ return false;
1573
+ }
1574
+
1575
+ $link = $this->_realpath($link);
1576
+
1577
+ if (!$this->_send_sftp_packet(NET_SFTP_READLINK, pack('Na*', strlen($link), $link))) {
1578
+ return false;
1579
+ }
1580
+
1581
+ $response = $this->_get_sftp_packet();
1582
+ switch ($this->packet_type) {
1583
+ case NET_SFTP_NAME:
1584
+ break;
1585
+ case NET_SFTP_STATUS:
1586
+ $this->_logError($response);
1587
+ return false;
1588
+ default:
1589
+ user_error('Expected SSH_FXP_NAME or SSH_FXP_STATUS');
1590
+ return false;
1591
+ }
1592
+
1593
+ extract(unpack('Ncount', $this->_string_shift($response, 4)));
1594
+ // the file isn't a symlink
1595
+ if (!$count) {
1596
+ return false;
1597
+ }
1598
+
1599
+ extract(unpack('Nlength', $this->_string_shift($response, 4)));
1600
+ return $this->_string_shift($response, $length);
1601
+ }
1602
+
1603
+ /**
1604
+ * Create a symlink
1605
+ *
1606
+ * symlink() creates a symbolic link to the existing target with the specified name link.
1607
+ *
1608
+ * @param String $target
1609
+ * @param String $link
1610
+ * @return Boolean
1611
+ * @access public
1612
+ */
1613
+ function symlink($target, $link)
1614
+ {
1615
+ if