/home/mjc1/public_html/phpMyAdmin/libraries/phpseclib/Crypt/Rijndael.php


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376
1377
1378
1379
1380
1381
1382
1383
1384
1385
1386
1387
1388
1389
1390
1391
1392
1393
1394
1395
1396
1397
1398
1399
1400
1401
1402
1403
1404
1405
1406
1407
1408
1409
1410
1411
1412
1413
1414
1415
1416
1417
1418
1419
1420
1421
1422
1423
1424
1425
1426
1427
1428
1429
1430
1431
1432
1433
1434
1435
1436
1437
1438
1439
1440
1441
1442
1443
1444
1445
1446
1447
1448
1449
1450
1451
1452
1453
1454
1455
1456
1457
1458
1459
1460
1461
1462
1463
1464
1465
1466
1467
1468
1469
1470
1471
1472
1473
1474
1475
1476
1477
1478
1479
<?php
/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */

/**
 * Pure-PHP implementation of Rijndael.
 *
 * Does not use mcrypt, even when available, for reasons that are explained below.
 *
 * PHP versions 4 and 5
 *
 * If {@link Crypt_Rijndael::setBlockLength() setBlockLength()} isn't called, it'll be assumed to be 128 bits.  If 
 * {@link Crypt_Rijndael::setKeyLength() setKeyLength()} isn't called, it'll be calculated from 
 * {@link Crypt_Rijndael::setKey() setKey()}.  ie. if the key is 128-bits, the key length will be 128-bits.  If it's 
 * 136-bits it'll be null-padded to 160-bits and 160 bits will be the key length until 
 * {@link Crypt_Rijndael::setKey() setKey()} is called, again, at which point, it'll be recalculated.
 *
 * Not all Rijndael implementations may support 160-bits or 224-bits as the block length / key length.  mcrypt, for example,
 * does not.  AES, itself, only supports block lengths of 128 and key lengths of 128, 192, and 256.
 * {@link http://csrc.nist.gov/archive/aes/rijndael/Rijndael-ammended.pdf#page=10 Rijndael-ammended.pdf#page=10} defines the
 * algorithm for block lengths of 192 and 256 but not for block lengths / key lengths of 160 and 224.  Indeed, 160 and 224
 * are first defined as valid key / block lengths in 
 * {@link http://csrc.nist.gov/archive/aes/rijndael/Rijndael-ammended.pdf#page=44 Rijndael-ammended.pdf#page=44}: 
 * Extensions: Other block and Cipher Key lengths.
 *
 * {@internal The variable names are the same as those in 
 * {@link http://www.csrc.nist.gov/publications/fips/fips197/fips-197.pdf#page=10 fips-197.pdf#page=10}.}}
 *
 * Here's a short example of how to use this library:
 * <code>
 * <?php
 *    include('Crypt/Rijndael.php');
 *
 *    $rijndael = new Crypt_Rijndael();
 *
 *    $rijndael->setKey('abcdefghijklmnop');
 *
 *    $size = 10 * 1024;
 *    $plaintext = '';
 *    for ($i = 0; $i < $size; $i++) {
 *        $plaintext.= 'a';
 *    }
 *
 *    echo $rijndael->decrypt($rijndael->encrypt($plaintext));
 * ?>
 * </code>
 *
 * LICENSE: Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 * 
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 * 
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 *
 * @category   Crypt
 * @package    Crypt_Rijndael
 * @author     Jim Wigginton <terrafrost@php.net>
 * @copyright  MMVIII Jim Wigginton
 * @license    http://www.opensource.org/licenses/mit-license.html  MIT License
 * @version    $Id: Rijndael.php,v 1.12 2010/02/09 06:10:26 terrafrost Exp $
 * @link       http://phpseclib.sourceforge.net
 */

/**#@+
 * @access public
 * @see Crypt_Rijndael::encrypt()
 * @see Crypt_Rijndael::decrypt()
 */
/**
 * Encrypt / decrypt using the Counter mode.
 *
 * Set to -1 since that's what Crypt/Random.php uses to index the CTR mode.
 *
 * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Counter_.28CTR.29
 */
define('CRYPT_RIJNDAEL_MODE_CTR', -1);
/**
 * Encrypt / decrypt using the Electronic Code Book mode.
 *
 * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Electronic_codebook_.28ECB.29
 */
define('CRYPT_RIJNDAEL_MODE_ECB'1);
/**
 * Encrypt / decrypt using the Code Book Chaining mode.
 *
 * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Cipher-block_chaining_.28CBC.29
 */
define('CRYPT_RIJNDAEL_MODE_CBC'2);
/**
 * Encrypt / decrypt using the Cipher Feedback mode.
 *
 * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Cipher_feedback_.28CFB.29
 */
define('CRYPT_RIJNDAEL_MODE_CFB'3);
/**
 * Encrypt / decrypt using the Cipher Feedback mode.
 *
 * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Output_feedback_.28OFB.29
 */
define('CRYPT_RIJNDAEL_MODE_OFB'4);
/**#@-*/

/**#@+
 * @access private
 * @see Crypt_Rijndael::Crypt_Rijndael()
 */
/**
 * Toggles the internal implementation
 */
define('CRYPT_RIJNDAEL_MODE_INTERNAL'1);
/**
 * Toggles the mcrypt implementation
 */
define('CRYPT_RIJNDAEL_MODE_MCRYPT'2);
/**#@-*/

/**
 * Pure-PHP implementation of Rijndael.
 *
 * @author  Jim Wigginton <terrafrost@php.net>
 * @version 0.1.0
 * @access  public
 * @package Crypt_Rijndael
 */
class Crypt_Rijndael {
    
/**
     * The Encryption Mode
     *
     * @see Crypt_Rijndael::Crypt_Rijndael()
     * @var Integer
     * @access private
     */
    
var $mode;

    
/**
     * The Key
     *
     * @see Crypt_Rijndael::setKey()
     * @var String
     * @access private
     */
    
var $key "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0";

    
/**
     * The Initialization Vector
     *
     * @see Crypt_Rijndael::setIV()
     * @var String
     * @access private
     */
    
var $iv '';

    
/**
     * A "sliding" Initialization Vector
     *
     * @see Crypt_Rijndael::enableContinuousBuffer()
     * @var String
     * @access private
     */
    
var $encryptIV '';

    
/**
     * A "sliding" Initialization Vector
     *
     * @see Crypt_Rijndael::enableContinuousBuffer()
     * @var String
     * @access private
     */
    
var $decryptIV '';

    
/**
     * Continuous Buffer status
     *
     * @see Crypt_Rijndael::enableContinuousBuffer()
     * @var Boolean
     * @access private
     */
    
var $continuousBuffer false;

    
/**
     * Padding status
     *
     * @see Crypt_Rijndael::enablePadding()
     * @var Boolean
     * @access private
     */
    
var $padding true;

    
/**
     * Does the key schedule need to be (re)calculated?
     *
     * @see setKey()
     * @see setBlockLength()
     * @see setKeyLength()
     * @var Boolean
     * @access private
     */
    
var $changed true;

    
/**
     * Has the key length explicitly been set or should it be derived from the key, itself?
     *
     * @see setKeyLength()
     * @var Boolean
     * @access private
     */
    
var $explicit_key_length false;

    
/**
     * The Key Schedule
     *
     * @see _setup()
     * @var Array
     * @access private
     */
    
var $w;

    
/**
     * The Inverse Key Schedule
     *
     * @see _setup()
     * @var Array
     * @access private
     */
    
var $dw;

    
/**
     * The Block Length
     *
     * @see setBlockLength()
     * @var Integer
     * @access private
     * @internal The max value is 32, the min value is 16.  All valid values are multiples of 4.  Exists in conjunction with
     *     $Nb because we need this value and not $Nb to pad strings appropriately.  
     */
    
var $block_size 16;

    
/**
     * The Block Length divided by 32
     *
     * @see setBlockLength()
     * @var Integer
     * @access private
     * @internal The max value is 256 / 32 = 8, the min value is 128 / 32 = 4.  Exists in conjunction with $block_size 
     *    because the encryption / decryption / key schedule creation requires this number and not $block_size.  We could 
     *    derive this from $block_size or vice versa, but that'd mean we'd have to do multiple shift operations, so in lieu
     *    of that, we'll just precompute it once.
     *
     */
    
var $Nb 4;

    
/**
     * The Key Length
     *
     * @see setKeyLength()
     * @var Integer
     * @access private
     * @internal The max value is 256 / 8 = 32, the min value is 128 / 8 = 16.  Exists in conjunction with $key_size
     *    because the encryption / decryption / key schedule creation requires this number and not $key_size.  We could 
     *    derive this from $key_size or vice versa, but that'd mean we'd have to do multiple shift operations, so in lieu
     *    of that, we'll just precompute it once.
     */
    
var $key_size 16;

    
/**
     * The Key Length divided by 32
     *
     * @see setKeyLength()
     * @var Integer
     * @access private
     * @internal The max value is 256 / 32 = 8, the min value is 128 / 32 = 4
     */
    
var $Nk 4;

    
/**
     * The Number of Rounds
     *
     * @var Integer
     * @access private
     * @internal The max value is 14, the min value is 10.
     */
    
var $Nr;

    
/**
     * Shift offsets
     *
     * @var Array
     * @access private
     */
    
var $c;

    
/**
     * Precomputed mixColumns table
     *
     * @see Crypt_Rijndael()
     * @var Array
     * @access private
     */
    
var $t0;

    
/**
     * Precomputed mixColumns table
     *
     * @see Crypt_Rijndael()
     * @var Array
     * @access private
     */
    
var $t1;

    
/**
     * Precomputed mixColumns table
     *
     * @see Crypt_Rijndael()
     * @var Array
     * @access private
     */
    
var $t2;

    
/**
     * Precomputed mixColumns table
     *
     * @see Crypt_Rijndael()
     * @var Array
     * @access private
     */
    
var $t3;

    
/**
     * Precomputed invMixColumns table
     *
     * @see Crypt_Rijndael()
     * @var Array
     * @access private
     */
    
var $dt0;

    
/**
     * Precomputed invMixColumns table
     *
     * @see Crypt_Rijndael()
     * @var Array
     * @access private
     */
    
var $dt1;

    
/**
     * Precomputed invMixColumns table
     *
     * @see Crypt_Rijndael()
     * @var Array
     * @access private
     */
    
var $dt2;

    
/**
     * Precomputed invMixColumns table
     *
     * @see Crypt_Rijndael()
     * @var Array
     * @access private
     */
    
var $dt3;

    
/**
     * Is the mode one that is paddable?
     *
     * @see Crypt_Rijndael::Crypt_Rijndael()
     * @var Boolean
     * @access private
     */
    
var $paddable false;

    
/**
     * Encryption buffer for CTR, OFB and CFB modes
     *
     * @see Crypt_Rijndael::encrypt()
     * @var String
     * @access private
     */
    
var $enbuffer = array('encrypted' => '''xor' => '');

    
/**
     * Decryption buffer for CTR, OFB and CFB modes
     *
     * @see Crypt_Rijndael::decrypt()
     * @var String
     * @access private
     */
    
var $debuffer = array('ciphertext' => '');

    
/**
     * Default Constructor.
     *
     * Determines whether or not the mcrypt extension should be used.  $mode should only, at present, be
     * CRYPT_RIJNDAEL_MODE_ECB or CRYPT_RIJNDAEL_MODE_CBC.  If not explictly set, CRYPT_RIJNDAEL_MODE_CBC will be used.
     *
     * @param optional Integer $mode
     * @return Crypt_Rijndael
     * @access public
     */
    
function Crypt_Rijndael($mode CRYPT_RIJNDAEL_MODE_CBC)
    {
        switch (
$mode) {
            case 
CRYPT_RIJNDAEL_MODE_ECB:
            case 
CRYPT_RIJNDAEL_MODE_CBC:
                
$this->paddable true;
                
$this->mode $mode;
                break;
            case 
CRYPT_RIJNDAEL_MODE_CTR:
            case 
CRYPT_RIJNDAEL_MODE_CFB:
            case 
CRYPT_RIJNDAEL_MODE_OFB:
                
$this->mode $mode;
                break;
            default:
                
$this->paddable true;
                
$this->mode CRYPT_RIJNDAEL_MODE_CBC;
        }

        
$t3 = &$this->t3;
        
$t2 = &$this->t2;
        
$t1 = &$this->t1;
        
$t0 = &$this->t0;

        
$dt3 = &$this->dt3;
        
$dt2 = &$this->dt2;
        
$dt1 = &$this->dt1;
        
$dt0 = &$this->dt0;

        
// according to <http://csrc.nist.gov/archive/aes/rijndael/Rijndael-ammended.pdf#page=19> (section 5.2.1), 
        // precomputed tables can be used in the mixColumns phase.  in that example, they're assigned t0...t3, so
        // those are the names we'll use.
        
$t3 = array(
            
0x6363A5C60x7C7C84F80x777799EE0x7B7B8DF60xF2F20DFF0x6B6BBDD60x6F6FB1DE0xC5C55491
            
0x303050600x010103020x6767A9CE0x2B2B7D560xFEFE19E70xD7D762B50xABABE64D0x76769AEC
            
0xCACA458F0x82829D1F0xC9C940890x7D7D87FA0xFAFA15EF0x5959EBB20x4747C98E0xF0F00BFB
            
0xADADEC410xD4D467B30xA2A2FD5F0xAFAFEA450x9C9CBF230xA4A4F7530x727296E40xC0C05B9B
            
0xB7B7C2750xFDFD1CE10x9393AE3D0x26266A4C0x36365A6C0x3F3F417E0xF7F702F50xCCCC4F83
            
0x34345C680xA5A5F4510xE5E534D10xF1F108F90x717193E20xD8D873AB0x313153620x15153F2A
            
0x04040C080xC7C752950x232365460xC3C35E9D0x181828300x9696A1370x05050F0A0x9A9AB52F
            
0x0707090E0x121236240x80809B1B0xE2E23DDF0xEBEB26CD0x2727694E0xB2B2CD7F0x75759FEA
            
0x09091B120x83839E1D0x2C2C74580x1A1A2E340x1B1B2D360x6E6EB2DC0x5A5AEEB40xA0A0FB5B
            
0x5252F6A40x3B3B4D760xD6D661B70xB3B3CE7D0x29297B520xE3E33EDD0x2F2F715E0x84849713
            
0x5353F5A60xD1D168B90x000000000xEDED2CC10x202060400xFCFC1FE30xB1B1C8790x5B5BEDB6
            
0x6A6ABED40xCBCB468D0xBEBED9670x39394B720x4A4ADE940x4C4CD4980x5858E8B00xCFCF4A85
            
0xD0D06BBB0xEFEF2AC50xAAAAE54F0xFBFB16ED0x4343C5860x4D4DD79A0x333355660x85859411
            
0x4545CF8A0xF9F910E90x020206040x7F7F81FE0x5050F0A00x3C3C44780x9F9FBA250xA8A8E34B
            
0x5151F3A20xA3A3FE5D0x4040C0800x8F8F8A050x9292AD3F0x9D9DBC210x383848700xF5F504F1
            
0xBCBCDF630xB6B6C1770xDADA75AF0x212163420x101030200xFFFF1AE50xF3F30EFD0xD2D26DBF
            
0xCDCD4C810x0C0C14180x131335260xECEC2FC30x5F5FE1BE0x9797A2350x4444CC880x1717392E
            
0xC4C457930xA7A7F2550x7E7E82FC0x3D3D477A0x6464ACC80x5D5DE7BA0x19192B320x737395E6
            
0x6060A0C00x818198190x4F4FD19E0xDCDC7FA30x222266440x2A2A7E540x9090AB3B0x8888830B
            
0x4646CA8C0xEEEE29C70xB8B8D36B0x14143C280xDEDE79A70x5E5EE2BC0x0B0B1D160xDBDB76AD
            
0xE0E03BDB0x323256640x3A3A4E740x0A0A1E140x4949DB920x06060A0C0x24246C480x5C5CE4B8
            
0xC2C25D9F0xD3D36EBD0xACACEF430x6262A6C40x9191A8390x9595A4310xE4E437D30x79798BF2
            
0xE7E732D50xC8C8438B0x3737596E0x6D6DB7DA0x8D8D8C010xD5D564B10x4E4ED29C0xA9A9E049
            
0x6C6CB4D80x5656FAAC0xF4F407F30xEAEA25CF0x6565AFCA0x7A7A8EF40xAEAEE9470x08081810
            
0xBABAD56F0x787888F00x25256F4A0x2E2E725C0x1C1C24380xA6A6F1570xB4B4C7730xC6C65197
            
0xE8E823CB0xDDDD7CA10x74749CE80x1F1F213E0x4B4BDD960xBDBDDC610x8B8B860D0x8A8A850F
            
0x707090E00x3E3E427C0xB5B5C4710x6666AACC0x4848D8900x030305060xF6F601F70x0E0E121C
            
0x6161A3C20x35355F6A0x5757F9AE0xB9B9D0690x868691170xC1C158990x1D1D273A0x9E9EB927
            
0xE1E138D90xF8F813EB0x9898B32B0x111133220x6969BBD20xD9D970A90x8E8E89070x9494A733
            
0x9B9BB62D0x1E1E223C0x878792150xE9E920C90xCECE49870x5555FFAA0x282878500xDFDF7AA5
            
0x8C8C8F030xA1A1F8590x898980090x0D0D171A0xBFBFDA650xE6E631D70x4242C6840x6868B8D0
            
0x4141C3820x9999B0290x2D2D775A0x0F0F111E0xB0B0CB7B0x5454FCA80xBBBBD66D0x16163A2C
        
);

        
$dt3 = array(
            
0xF4A750510x4165537E0x17A4C31A0x275E963A0xAB6BCB3B0x9D45F11F0xFA58ABAC0xE303934B
            
0x30FA55200x766DF6AD0xCC7691880x024C25F50xE5D7FC4F0x2ACBD7C50x354480260x62A38FB5
            
0xB15A49DE0xBA1B67250xEA0E98450xFEC0E15D0x2F7502C30x4CF012810x4697A38D0xD3F9C66B
            
0x8F5FE7030x929C95150x6D7AEBBF0x5259DA950xBE832DD40x7421D3580xE06929490xC9C8448E
            
0xC2896A750x8E7978F40x583E6B990xB971DD270xE14FB6BE0x88AD17F00x20AC66C90xCE3AB47D
            
0xDF4A18630x1A3182E50x513360970x537F45620x6477E0B10x6BAE84BB0x81A01CFE0x082B94F9
            
0x486858700x45FD198F0xDE6C87940x7BF8B7520x73D323AB0x4B02E2720x1F8F57E30x55AB2A66
            
0xEB2807B20xB5C2032F0xC57B9A860x3708A5D30x2887F2300xBFA5B2230x036ABA020x16825CED
            
0xCF1C2B8A0x79B492A70x07F2F0F30x69E2A14E0xDAF4CD650x05BED5060x34621FD10xA6FE8AC4
            
0x2E539D340xF355A0A20x8AE132050xF6EB75A40x83EC390B0x60EFAA400x719F065E0x6E1051BD
            
0x218AF93E0xDD063D960x3E05AEDD0xE6BD464D0x548DB5910xC45D05710x06D46F040x5015FF60
            
0x98FB24190xBDE997D60x4043CC890xD99E77670xE842BDB00x898B88070x195B38E70xC8EEDB79
            
0x7C0A47A10x420FE97C0x841EC9F80x000000000x808683090x2BED48320x1170AC1E0x5A724E6C
            
0x0EFFFBFD0x8538560F0xAED51E3D0x2D3927360x0FD9640A0x5CA621680x5B54D19B0x362E3A24
            
0x0A67B10C0x57E70F930xEE96D2B40x9B919E1B0xC0C54F800xDC20A2610x774B695A0x121A161C
            
0x93BA0AE20xA02AE5C00x22E0433C0x1B171D120x090D0B0E0x8BC7ADF20xB6A8B92D0x1EA9C814
            
0xF11985570x75074CAF0x99DDBBEE0x7F60FDA30x01269FF70x72F5BC5C0x663BC5440xFB7E345B
            
0x4329768B0x23C6DCCB0xEDFC68B60xE4F163B80x31DCCAD70x638510420x972240130xC6112084
            
0x4A247D850xBB3DF8D20xF93211AE0x29A16DC70x9E2F4B1D0xB230F3DC0x8652EC0D0xC1E3D077
            
0xB3166C2B0x70B999A90x9448FA110xE96422470xFC8CC4A80xF03F1AA00x7D2CD8560x3390EF22
            
0x494EC7870x38D1C1D90xCAA2FE8C0xD40B36980xF581CFA60x7ADE28A50xB78E26DA0xADBFA43F
            
0x3A9DE42C0x78920D500x5FCC9B6A0x7E4662540x8D13C2F60xD8B8E8900x39F75E2E0xC3AFF582
            
0x5D80BE9F0xD0937C690xD52DA96F0x2512B3CF0xAC993BC80x187DA7100x9C636EE80x3BBB7BDB
            
0x267809CD0x5918F46E0x9AB701EC0x4F9AA8830x956E65E60xFFE67EAA0xBCCF08210x15E8E6EF
            
0xE79BD9BA0x6F36CE4A0x9F09D4EA0xB07CD6290xA4B2AF310x3F23312A0xA59430C60xA266C035
            
0x4EBC37740x82CAA6FC0x90D0B0E00xA7D815330x04984AF10xECDAF7410xCD500E7F0x91F62F17
            
0x4DD68D760xEFB04D430xAA4D54CC0x9604DFE40xD1B5E39E0x6A881B4C0x2C1FB8C10x65517F46
            
0x5EEA049D0x8C355D010x877473FA0x0B412EFB0x671D5AB30xDBD252920x105633E90xD647136D
            
0xD7618C9A0xA10C7A370xF8148E590x133C89EB0xA927EECE0x61C935B70x1CE5EDE10x47B13C7A
            
0xD2DF599C0xF2733F550x14CE79180xC737BF730xF7CDEA530xFDAA5B5F0x3D6F14DF0x44DB8678
            
0xAFF381CA0x68C43EB90x24342C380xA3405FC20x1DC372160xE2250CBC0x3C498B280x0D9541FF
            
0xA80171390x0CB3DE080xB4E49CD80x56C190640xCB84617B0x32B670D50x6C5C74480xB85742D0
        
);

        for (
$i 0$i 256$i++) {
            
$t2[$i <<  8] = (($t3[$i] <<  8) & 0xFFFFFF00) | (($t3[$i] >> 24) & 0x000000FF);
            
$t1[$i << 16] = (($t3[$i] << 16) & 0xFFFF0000) | (($t3[$i] >> 16) & 0x0000FFFF);
            
$t0[$i << 24] = (($t3[$i] << 24) & 0xFF000000) | (($t3[$i] >>  8) & 0x00FFFFFF);

            
$dt2[$i <<  8] = (($this->dt3[$i] <<  8) & 0xFFFFFF00) | (($dt3[$i] >> 24) & 0x000000FF);
            
$dt1[$i << 16] = (($this->dt3[$i] << 16) & 0xFFFF0000) | (($dt3[$i] >> 16) & 0x0000FFFF);
            
$dt0[$i << 24] = (($this->dt3[$i] << 24) & 0xFF000000) | (($dt3[$i] >>  8) & 0x00FFFFFF);
        }
    }

    
/**
     * Sets the key.
     *
     * Keys can be of any length.  Rijndael, itself, requires the use of a key that's between 128-bits and 256-bits long and
     * whose length is a multiple of 32.  If the key is less than 256-bits and the key length isn't set, we round the length
     * up to the closest valid key length, padding $key with null bytes.  If the key is more than 256-bits, we trim the
     * excess bits.
     *
     * If the key is not explicitly set, it'll be assumed to be all null bytes.
     *
     * @access public
     * @param String $key
     */
    
function setKey($key)
    {
        
$this->key $key;
        
$this->changed true;
    }

    
/**
     * Sets the initialization vector. (optional)
     *
     * SetIV is not required when CRYPT_RIJNDAEL_MODE_ECB is being used.  If not explictly set, it'll be assumed
     * to be all zero's.
     *
     * @access public
     * @param String $iv
     */
    
function setIV($iv)
    {
        
$this->encryptIV $this->decryptIV $this->iv str_pad(substr($iv0$this->block_size), $this->block_sizechr(0));
    }

    
/**
     * Sets the key length
     *
     * Valid key lengths are 128, 160, 192, 224, and 256.  If the length is less than 128, it will be rounded up to
     * 128.  If the length is greater then 128 and invalid, it will be rounded down to the closest valid amount.
     *
     * @access public
     * @param Integer $length
     */
    
function setKeyLength($length)
    {
        
$length >>= 5;
        if (
$length 8) {
            
$length 8;
        } else if (
$length 4) {
            
$length 4;
        }
        
$this->Nk $length;
        
$this->key_size $length << 2;

        
$this->explicit_key_length true;
        
$this->changed true;
    }

    
/**
     * Sets the password.
     *
     * Depending on what $method is set to, setPassword()'s (optional) parameters are as follows:
     *     {@link http://en.wikipedia.org/wiki/PBKDF2 pbkdf2}:
     *         $hash, $salt, $count
     *     Set $dkLen by calling setKeyLength()
     *
     * @param String $password
     * @param optional String $method
     * @access public
     */
    
function setPassword($password$method 'pbkdf2')
    {
        
$key '';

        switch (
$method) {
            default: 
// 'pbkdf2'
                
list(, , $hash$salt$count) = func_get_args();
                if (!isset(
$hash)) {
                    
$hash 'sha1';
                }
                
// WPA and WPA use the SSID as the salt
                
if (!isset($salt)) {
                    
$salt 'phpseclib/salt';
                }
                
// RFC2898#section-4.2 uses 1,000 iterations by default
                // WPA and WPA2 use 4,096.
                
if (!isset($count)) {
                    
$count 1000;
                }

                if (!
class_exists('Crypt_Hash')) {
                    require_once(
'Crypt/Hash.php');
                }

                
$i 1;
                while (
strlen($key) < $this->key_size) { // $dkLen == $this->key_size
                    //$dk.= $this->_pbkdf($password, $salt, $count, $i++);
                    
$hmac = new Crypt_Hash();
                    
$hmac->setHash($hash);
                    
$hmac->setKey($password);
                    
$f $u $hmac->hash($salt pack('N'$i++));
                    for (
$j 2$j <= $count$j++) {
                        
$u $hmac->hash($u);
                        
$f^= $u;
                    }
                    
$key.= $f;
                }
        }

        
$this->setKey(substr($key0$this->key_size));
    }

    
/**
     * Sets the block length
     *
     * Valid block lengths are 128, 160, 192, 224, and 256.  If the length is less than 128, it will be rounded up to
     * 128.  If the length is greater then 128 and invalid, it will be rounded down to the closest valid amount.
     *
     * @access public
     * @param Integer $length
     */
    
function setBlockLength($length)
    {
        
$length >>= 5;
        if (
$length 8) {
            
$length 8;
        } else if (
$length 4) {
            
$length 4;
        }
        
$this->Nb $length;
        
$this->block_size $length << 2;
        
$this->changed true;
    }

    
/**
     * Generate CTR XOR encryption key
     *
     * Encrypt the output of this and XOR it against the ciphertext / plaintext to get the
     * plaintext / ciphertext in CTR mode.
     *
     * @see Crypt_Rijndael::decrypt()
     * @see Crypt_Rijndael::encrypt()
     * @access public
     * @param Integer $length
     * @param String $iv
     */
    
function _generate_xor($length, &$iv)
    {
        
$xor '';
        
$block_size $this->block_size;
        
$num_blocks floor(($length + ($block_size 1)) / $block_size);
        for (
$i 0$i $num_blocks$i++) {
            
$xor.= $iv;
            for (
$j 4$j <= $block_size$j+=4) {
                
$temp substr($iv, -$j4);
                switch (
$temp) {
                    case 
"\xFF\xFF\xFF\xFF":
                        
$iv substr_replace($iv"\x00\x00\x00\x00", -$j4);
                        break;
                    case 
"\x7F\xFF\xFF\xFF":
                        
$iv substr_replace($iv"\x80\x00\x00\x00", -$j4);
                        break 
2;
                    default:
                        
extract(unpack('Ncount'$temp));
                        
$iv substr_replace($ivpack('N'$count 1), -$j4);
                        break 
2;
                }
            }
        }

        return 
$xor;
    }

    
/**
     * Encrypts a message.
     *
     * $plaintext will be padded with additional bytes such that it's length is a multiple of the block size.  Other Rjindael
     * implementations may or may not pad in the same manner.  Other common approaches to padding and the reasons why it's
     * necessary are discussed in the following
     * URL:
     *
     * {@link http://www.di-mgt.com.au/cryptopad.html http://www.di-mgt.com.au/cryptopad.html}
     *
     * An alternative to padding is to, separately, send the length of the file.  This is what SSH, in fact, does.
     * strlen($plaintext) will still need to be a multiple of 8, however, arbitrary values can be added to make it that
     * length.
     *
     * @see Crypt_Rijndael::decrypt()
     * @access public
     * @param String $plaintext
     */
    
function encrypt($plaintext)
    {
        
$this->_setup();
        if (
$this->paddable) {
            
$plaintext $this->_pad($plaintext);
        }

        
$block_size $this->block_size;
        
$buffer = &$this->enbuffer;
        
$continuousBuffer $this->continuousBuffer;
        
$ciphertext '';
        switch (
$this->mode) {
            case 
CRYPT_RIJNDAEL_MODE_ECB:
                for (
$i 0$i strlen($plaintext); $i+=$block_size) {
                    
$ciphertext.= $this->_encryptBlock(substr($plaintext$i$block_size));
                }
                break;
            case 
CRYPT_RIJNDAEL_MODE_CBC:
                
$xor $this->encryptIV;
                for (
$i 0$i strlen($plaintext); $i+=$block_size) {
                    
$block substr($plaintext$i$block_size);
                    
$block $this->_encryptBlock($block $xor);
                    
$xor $block;
                    
$ciphertext.= $block;
                }
                if (
$this->continuousBuffer) {
                    
$this->encryptIV $xor;
                }
                break;
            case 
CRYPT_RIJNDAEL_MODE_CTR:
                
$xor $this->encryptIV;
                if (!empty(
$buffer['encrypted'])) {
                    for (
$i 0$i strlen($plaintext); $i+=$block_size) {
                        
$block substr($plaintext$i$block_size);
                        
$buffer['encrypted'].= $this->_encryptBlock($this->_generate_xor($block_size$xor));
                        
$key $this->_string_shift($buffer['encrypted'], $block_size);
                        
$ciphertext.= $block $key;
                    }
                } else {
                    for (
$i 0$i strlen($plaintext); $i+=$block_size) {
                        
$block substr($plaintext$i$block_size);
                        
$key $this->_encryptBlock($this->_generate_xor($block_size$xor));
                        
$ciphertext.= $block $key;
                    }
                }
                if (
$this->continuousBuffer) {
                    
$this->encryptIV $xor;
                    if (
$start strlen($plaintext) % $block_size) {
                        
$buffer['encrypted'] = substr($key$start) . $buffer['encrypted'];
                    }
                }
                break;
            case 
CRYPT_RIJNDAEL_MODE_CFB:
                if (!empty(
$buffer['xor'])) {
                    
$ciphertext $plaintext $buffer['xor'];
                    
$iv $buffer['encrypted'] . $ciphertext;
                    
$start strlen($ciphertext);
                    
$buffer['encrypted'].= $ciphertext;
                    
$buffer['xor'] = substr($buffer['xor'], strlen($ciphertext));
                } else {
                    
$ciphertext '';
                    
$iv $this->encryptIV;
                    
$start 0;
                }

                for (
$i $start$i strlen($plaintext); $i+=$block_size) {
                    
$block substr($plaintext$i$block_size);
                    
$xor $this->_encryptBlock($iv);
                    
$iv $block $xor;
                    if (
$continuousBuffer && strlen($iv) != $block_size) {
                        
$buffer = array(
                            
'encrypted' => $iv,
                            
'xor' => substr($xorstrlen($iv))
                        );
                    }
                    
$ciphertext.= $iv;
                }

                if (
$this->continuousBuffer) {
                    
$this->encryptIV $iv;
                }
                break;
            case 
CRYPT_RIJNDAEL_MODE_OFB:
                
$xor $this->encryptIV;
                if (
strlen($buffer)) {
                    for (
$i 0$i strlen($plaintext); $i+=$block_size) {
                        
$xor $this->_encryptBlock($xor);
                        
$buffer.= $xor;
                        
$key $this->_string_shift($buffer$block_size);
                        
$ciphertext.= substr($plaintext$i$block_size) ^ $key;
                    }
                } else {
                    for (
$i 0$i strlen($plaintext); $i+=$block_size) {
                        
$xor $this->_encryptBlock($xor);
                        
$ciphertext.= substr($plaintext$i$block_size) ^ $xor;
                    }
                    
$key $xor;
                }
                if (
$this->continuousBuffer) {
                    
$this->encryptIV $xor;
                    if (
$start strlen($plaintext) % $block_size) {
                         
$buffer substr($key$start) . $buffer;
                    }
                }
        }

        return 
$ciphertext;
    }

    
/**
     * Decrypts a message.
     *
     * If strlen($ciphertext) is not a multiple of the block size, null bytes will be added to the end of the string until
     * it is.
     *
     * @see Crypt_Rijndael::encrypt()
     * @access public
     * @param String $ciphertext
     */
    
function decrypt($ciphertext)
    {
        
$this->_setup();

        if (
$this->paddable) {
            
// we pad with chr(0) since that's what mcrypt_generic does.  to quote from http://php.net/function.mcrypt-generic :
            // "The data is padded with "\0" to make sure the length of the data is n * blocksize."
            
$ciphertext str_pad($ciphertextstrlen($ciphertext) + ($this->block_size strlen($ciphertext) % $this->block_size) % $this->block_sizechr(0));
        }

        
$block_size $this->block_size;
        
$buffer = &$this->debuffer;
        
$continuousBuffer $this->continuousBuffer;
        
$plaintext '';
        switch (
$this->mode) {
            case 
CRYPT_RIJNDAEL_MODE_ECB:
                for (
$i 0$i strlen($ciphertext); $i+=$block_size) {
                    
$plaintext.= $this->_decryptBlock(substr($ciphertext$i$block_size));
                }
                break;
            case 
CRYPT_RIJNDAEL_MODE_CBC:
                
$xor $this->decryptIV;
                for (
$i 0$i strlen($ciphertext); $i+=$block_size) {
                    
$block substr($ciphertext$i$block_size);
                    
$plaintext.= $this->_decryptBlock($block) ^ $xor;
                    
$xor $block;
                }
                if (
$this->continuousBuffer) {
                    
$this->decryptIV $xor;
                }
                break;
            case 
CRYPT_RIJNDAEL_MODE_CTR:
                
$xor $this->decryptIV;
                if (!empty(
$buffer['ciphertext'])) {
                    for (
$i 0$i strlen($ciphertext); $i+=$block_size) {
                        
$block substr($ciphertext$i$block_size);
                        
$buffer['ciphertext'].= $this->_encryptBlock($this->_generate_xor($block_size$xor));
                        
$key $this->_string_shift($buffer['ciphertext'], $block_size);
                        
$plaintext.= $block $key;
                    }
                } else {
                    for (
$i 0$i strlen($ciphertext); $i+=$block_size) {
                        
$block substr($ciphertext$i$block_size);
                        
$key $this->_encryptBlock($this->_generate_xor($block_size$xor));
                        
$plaintext.= $block $key;
                    }
                }
                if (
$this->continuousBuffer) {
                    
$this->decryptIV $xor;
                    if (
$start strlen($ciphertext) % $block_size) {
                        
$buffer['ciphertext'] = substr($key$start) . $buffer['encrypted'];
                    }
                }
                break;
            case 
CRYPT_RIJNDAEL_MODE_CFB:
                if (!empty(
$buffer['ciphertext'])) {
                    
$plaintext $ciphertext substr($this->decryptIVstrlen($buffer['ciphertext']));
                    
$buffer['ciphertext'].= substr($ciphertext0strlen($plaintext));
                    if (
strlen($buffer['ciphertext']) == $block_size) {
                        
$xor $this->_encryptBlock($buffer['ciphertext']);
                        
$buffer['ciphertext'] = '';
                    }
                    
$start strlen($plaintext);
                    
$block $this->decryptIV;
                } else {
                    
$plaintext '';
                    
$xor $this->_encryptBlock($this->decryptIV);
                    
$start 0;
                }

                for (
$i $start$i strlen($ciphertext); $i+=$block_size) {
                    
$block substr($ciphertext$i$block_size);
                    
$plaintext.= $block $xor;
                    if (
$continuousBuffer && strlen($block) != $block_size) {
                        
$buffer['ciphertext'].= $block;
                        
$block $xor;
                    } else if (
strlen($block) == $block_size) {
                        
$xor $this->_encryptBlock($block);
                    }
                }
                if (
$this->continuousBuffer) {
                    
$this->decryptIV $block;
                }
                break;
            case 
CRYPT_RIJNDAEL_MODE_OFB:
                
$xor $this->decryptIV;
                if (
strlen($buffer)) {
                    for (
$i 0$i strlen($ciphertext); $i+=$block_size) {
                        
$xor $this->_encryptBlock($xor);
                        
$buffer.= $xor;
                        
$key $this->_string_shift($buffer$block_size);
                        
$plaintext.= substr($ciphertext$i$block_size) ^ $key;
                    }
                } else {
                    for (
$i 0$i strlen($ciphertext); $i+=$block_size) {
                        
$xor $this->_encryptBlock($xor);
                        
$plaintext.= substr($ciphertext$i$block_size) ^ $xor;
                    }
                    
$key $xor;
                }
                if (
$this->continuousBuffer) {
                    
$this->decryptIV $xor;
                    if (
$start strlen($ciphertext) % $block_size) {
                         
$buffer substr($key$start) . $buffer;
                    }
                }
        }

        return 
$this->paddable $this->_unpad($plaintext) : $plaintext;
    }

    
/**
     * Encrypts a block
     *
     * @access private
     * @param String $in
     * @return String
     */
    
function _encryptBlock($in)
    {
        
$state = array();
        
$words unpack('N*word'$in);

        
$w $this->w;
        
$t0 $this->t0;
        
$t1 $this->t1;
        
$t2 $this->t2;
        
$t3 $this->t3;
        
$Nb $this->Nb;
        
$Nr $this->Nr;
        
$c $this->c;

        
// addRoundKey
        
$i 0;
        foreach (
$words as $word) {
            
$state[] = $word $w[0][$i++];
        }

        
// fips-197.pdf#page=19, "Figure 5. Pseudo Code for the Cipher", states that this loop has four components - 
        // subBytes, shiftRows, mixColumns, and addRoundKey. fips-197.pdf#page=30, "Implementation Suggestions Regarding 
        // Various Platforms" suggests that performs enhanced implementations are described in Rijndael-ammended.pdf.
        // Rijndael-ammended.pdf#page=20, "Implementation aspects / 32-bit processor", discusses such an optimization.
        // Unfortunately, the description given there is not quite correct.  Per aes.spec.v316.pdf#page=19 [1], 
        // equation (7.4.7) is supposed to use addition instead of subtraction, so we'll do that here, as well.

        // [1] http://fp.gladman.plus.com/cryptography_technology/rijndael/aes.spec.v316.pdf
        
$temp = array();
        for (
$round 1$round $Nr$round++) {
            
$i 0// $c[0] == 0
            
$j $c[1];
            
$k $c[2];
            
$l $c[3];

            while (
$i $this->Nb) {
                
$temp[$i] = $t0[$state[$i] & 0xFF000000] ^ 
                            
$t1[$state[$j] & 0x00FF0000] ^ 
                            
$t2[$state[$k] & 0x0000FF00] ^ 
                            
$t3[$state[$l] & 0x000000FF] ^ 
                            
$w[$round][$i];
                
$i++;
                
$j = ($j 1) % $Nb;
                
$k = ($k 1) % $Nb;
                
$l = ($l 1) % $Nb;
            }

            for (
$i 0$i $Nb$i++) {
                
$state[$i] = $temp[$i];
            }
        }

        
// subWord
        
for ($i 0$i $Nb$i++) {
            
$state[$i] = $this->_subWord($state[$i]);
        }

        
// shiftRows + addRoundKey
        
$i 0// $c[0] == 0
        
$j $c[1];
        
$k $c[2];
        
$l $c[3];
        while (
$i $this->Nb) {
            
$temp[$i] = ($state[$i] & 0xFF000000) ^ 
                        (
$state[$j] & 0x00FF0000) ^ 
                        (
$state[$k] & 0x0000FF00) ^ 
                        (
$state[$l] & 0x000000FF) ^
                         
$w[$Nr][$i];
            
$i++;
            
$j = ($j 1) % $Nb;
            
$k = ($k 1) % $Nb;
            
$l = ($l 1) % $Nb;
        }
        
$state $temp;

        
array_unshift($state'N*');

        return 
call_user_func_array('pack'$state);
    }

    
/**
     * Decrypts a block
     *
     * @access private
     * @param String $in
     * @return String
     */
    
function _decryptBlock($in)
    {
        
$state = array();
        
$words unpack('N*word'$in);

        
$num_states count($state);
        
$dw $this->dw;
        
$dt0 $this->dt0;
        
$dt1 $this->dt1;
        
$dt2 $this->dt2;
        
$dt3 $this->dt3;
        
$Nb $this->Nb;
        
$Nr $this->Nr;
        
$c $this->c;

        
// addRoundKey
        
$i 0;
        foreach (
$words as $word) {
            
$state[] = $word $dw[$Nr][$i++];
        }

        
$temp = array();
        for (
$round $Nr 1$round 0$round--) {
            
$i 0// $c[0] == 0
            
$j $Nb $c[1];
            
$k $Nb $c[2];
            
$l $Nb $c[3];

            while (
$i $Nb) {
                
$temp[$i] = $dt0[$state[$i] & 0xFF000000] ^ 
                            
$dt1[$state[$j] & 0x00FF0000] ^ 
                            
$dt2[$state[$k] & 0x0000FF00] ^ 
                            
$dt3[$state[$l] & 0x000000FF] ^ 
                            
$dw[$round][$i];
                
$i++;
                
$j = ($j 1) % $Nb;
                
$k = ($k 1) % $Nb;
                
$l = ($l 1) % $Nb;
            }

            for (
$i 0$i $Nb$i++) {
                
$state[$i] = $temp[$i];
            }
        }

        
// invShiftRows + invSubWord + addRoundKey
        
$i 0// $c[0] == 0
        
$j $Nb $c[1];
        
$k $Nb $c[2];
        
$l $Nb $c[3];

        while (
$i $Nb) {
            
$temp[$i] = $dw[0][$i] ^ 
                        
$this->_invSubWord(($state[$i] & 0xFF000000) | 
                                           (
$state[$j] & 0x00FF0000) | 
                                           (
$state[$k] & 0x0000FF00) | 
                                           (
$state[$l] & 0x000000FF));
            
$i++;
            
$j = ($j 1) % $Nb;
            
$k = ($k 1) % $Nb;
            
$l = ($l 1) % $Nb;
        }

        
$state $temp;

        
array_unshift($state'N*');

        return 
call_user_func_array('pack'$state);
    }

    
/**
     * Setup Rijndael
     *
     * Validates all the variables and calculates $Nr - the number of rounds that need to be performed - and $w - the key
     * key schedule.
     *
     * @access private
     */
    
function _setup()
    {
        
// Each number in $rcon is equal to the previous number multiplied by two in Rijndael's finite field.
        // See http://en.wikipedia.org/wiki/Finite_field_arithmetic#Multiplicative_inverse
        
static $rcon = array(0,
            
0x010000000x020000000x040000000x080000000x10000000,
            
0x200000000x400000000x800000000x1B0000000x36000000,
            
0x6C0000000xD80000000xAB0000000x4D0000000x9A000000,
            
0x2F0000000x5E0000000xBC0000000x630000000xC6000000,
            
0x970000000x350000000x6A0000000xD40000000xB3000000,
            
0x7D0000000xFA0000000xEF0000000xC50000000x91000000
        
);

        if (!
$this->changed) {
            return;
        }

        if (!
$this->explicit_key_length) {
            
// we do >> 2, here, and not >> 5, as we do above, since strlen($this->key) tells us the number of bytes - not bits
            
$length strlen($this->key) >> 2;
            if (
$length 8) {
                
$length 8;
            } else if (
$length 4) {
                
$length 4;
            }
            
$this->Nk $length;
            
$this->key_size $length << 2;
        }

        
$this->key str_pad(substr($this->key0$this->key_size), $this->key_sizechr(0));
        
$this->encryptIV $this->decryptIV $this->iv str_pad(substr($this->iv0$this->block_size), $this->block_sizechr(0));

        
// see Rijndael-ammended.pdf#page=44
        
$this->Nr max($this->Nk$this->Nb) + 6;

        
// shift offsets for Nb = 5, 7 are defined in Rijndael-ammended.pdf#page=44,
        //     "Table 8: Shift offsets in Shiftrow for the alternative block lengths"
        // shift offsets for Nb = 4, 6, 8 are defined in Rijndael-ammended.pdf#page=14,
        //     "Table 2: Shift offsets for different block lengths"
        
switch ($this->Nb) {
            case 
4:
            case 
5:
            case 
6:
                
$this->= array(0123);
                break;
            case 
7:
                
$this->= array(0124);
                break;
            case 
8:
                
$this->= array(0134);
        }

        
$key $this->key;

        
$w array_values(unpack('N*words'$key));

        
$length $this->Nb * ($this->Nr 1);
        for (
$i $this->Nk$i $length$i++) {
            
$temp $w[$i 1];
            if (
$i $this->Nk == 0) {
                
// according to <http://php.net/language.types.integer>, "the size of an integer is platform-dependent".
                // on a 32-bit machine, it's 32-bits, and on a 64-bit machine, it's 64-bits. on a 32-bit machine,
                // 0xFFFFFFFF << 8 == 0xFFFFFF00, but on a 64-bit machine, it equals 0xFFFFFFFF00. as such, doing 'and'
                // with 0xFFFFFFFF (or 0xFFFFFF00) on a 32-bit machine is unnecessary, but on a 64-bit machine, it is.
                
$temp = (($temp << 8) & 0xFFFFFF00) | (($temp >> 24) & 0x000000FF); // rotWord
                
$temp $this->_subWord($temp) ^ $rcon[$i $this->Nk];
            } else if (
$this->Nk && $i $this->Nk == 4) {
                
$temp $this->_subWord($temp);
            }
            
$w[$i] = $w[$i $this->Nk] ^ $temp;
        }

        
// convert the key schedule from a vector of $Nb * ($Nr + 1) length to a matrix with $Nr + 1 rows and $Nb columns
        // and generate the inverse key schedule.  more specifically,
        // according to <http://csrc.nist.gov/archive/aes/rijndael/Rijndael-ammended.pdf#page=23> (section 5.3.3), 
        // "The key expansion for the Inverse Cipher is defined as follows:
        //        1. Apply the Key Expansion.
        //        2. Apply InvMixColumn to all Round Keys except the first and the last one."
        // also, see fips-197.pdf#page=27, "5.3.5 Equivalent Inverse Cipher"
        
$temp = array();
        for (
$i $row $col 0$i $length$i++, $col++) {
            if (
$col == $this->Nb) {
                if (
$row == 0) {
                    
$this->dw[0] = $this->w[0];
                } else {
                    
// subWord + invMixColumn + invSubWord = invMixColumn
                    
$j 0;
                    while (
$j $this->Nb) {
                        
$dw $this->_subWord($this->w[$row][$j]);
                        
$temp[$j] = $this->dt0[$dw 0xFF000000] ^ 
                                    
$this->dt1[$dw 0x00FF0000] ^ 
                                    
$this->dt2[$dw 0x0000FF00] ^ 
                                    
$this->dt3[$dw 0x000000FF];
                        
$j++;
                    }
                    
$this->dw[$row] = $temp;
                }

                
$col 0;
                
$row++;
            }
            
$this->w[$row][$col] = $w[$i];
        }

        
$this->dw[$row] = $this->w[$row];

        
$this->changed false;
    }

    
/**
     * Performs S-Box substitutions
     *
     * @access private
     */
    
function _subWord($word)
    {
        static 
$sbox0$sbox1$sbox2$sbox3;

        if (empty(
$sbox0)) {
            
$sbox0 = array(
                
0x630x7C0x770x7B0xF20x6B0x6F0xC50x300x010x670x2B0xFE0xD70xAB0x76,
                
0xCA0x820xC90x7D0xFA0x590x470xF00xAD0xD40xA20xAF0x9C0xA40x720xC0,
                
0xB70xFD0x930x260x360x3F0xF70xCC0x340xA50xE50xF10x710xD80x310x15,
                
0x040xC70x230xC30x180x960x050x9A0x070x120x800xE20xEB0x270xB20x75,
                
0x090x830x2C0x1A0x1B0x6E0x5A0xA00x520x3B0xD60xB30x290xE30x2F0x84,
                
0x530xD10x000xED0x200xFC0xB10x5B0x6A0xCB0xBE0x390x4A0x4C0x580xCF,
                
0xD00xEF0xAA0xFB0x430x4D0x330x850x450xF90x020x7F0x500x3C0x9F0xA8,
                
0x510xA30x400x8F0x920x9D0x380xF50xBC0xB60xDA0x210x100xFF0xF30xD2,
                
0xCD0x0C0x130xEC0x5F0x970x440x170xC40xA70x7E0x3D0x640x5D0x190x73,
                
0x600x810x4F0xDC0x220x2A0x900x880x460xEE0xB80x140xDE0x5E0x0B0xDB,
                
0xE00x320x3A0x0A0x490x060x240x5C0xC20xD30xAC0x620x910x950xE40x79,
                
0xE70xC80x370x6D0x8D0xD50x4E0xA90x6C0x560xF40xEA0x650x7A0xAE0x08,
                
0xBA0x780x250x2E0x1C0xA60xB40xC60xE80xDD0x740x1F0x4B0xBD0x8B0x8A,
                
0x700x3E0xB50x660x480x030xF60x0E0x610x350x570xB90x860xC10x1D0x9E,
                
0xE10xF80x980x110x690xD90x8E0x940x9B0x1E0x870xE90xCE0x550x280xDF,
                
0x8C0xA10x890x0D0xBF0xE60x420x680x410x990x2D0x0F0xB00x540xBB0x16
            
);

            
$sbox1 = array();
            
$sbox2 = array();
            
$sbox3 = array();

            for (
$i 0$i 256$i++) {
                
$sbox1[$i <<  8] = $sbox0[$i] <<  8;
                
$sbox2[$i << 16] = $sbox0[$i] << 16;
                
$sbox3[$i << 24] = $sbox0[$i] << 24;
            }
        }

        return 
$sbox0[$word 0x000000FF] | 
               
$sbox1[$word 0x0000FF00] | 
               
$sbox2[$word 0x00FF0000] | 
               
$sbox3[$word 0xFF000000];
    }

    
/**
     * Performs inverse S-Box substitutions
     *
     * @access private
     */
    
function _invSubWord($word)
    {
        static 
$sbox0$sbox1$sbox2$sbox3;

        if (empty(
$sbox0)) {
            
$sbox0 = array(
                
0x520x090x6A0xD50x300x360xA50x380xBF0x400xA30x9E0x810xF30xD70xFB,
                
0x7C0xE30x390x820x9B0x2F0xFF0x870x340x8E0x430x440xC40xDE0xE90xCB,
                
0x540x7B0x940x320xA60xC20x230x3D0xEE0x4C0x950x0B0x420xFA0xC30x4E,
                
0x080x2E0xA10x660x280xD90x240xB20x760x5B0xA20x490x6D0x8B0xD10x25,
                
0x720xF80xF60x640x860x680x980x160xD40xA40x5C0xCC0x5D0x650xB60x92,
                
0x6C0x700x480x500xFD0xED0xB90xDA0x5E0x150x460x570xA70x8D0x9D0x84,
                
0x900xD80xAB0x000x8C0xBC0xD30x0A0xF70xE40x580x050xB80xB30x450x06,
                
0xD00x2C0x1E0x8F0xCA0x3F0x0F0x020xC10xAF0xBD0x030x010x130x8A0x6B,
                
0x3A0x910x110x410x4F0x670xDC0xEA0x970xF20xCF0xCE0xF00xB40xE60x73,
                
0x960xAC0x740x220xE70xAD0x350x850xE20xF90x370xE80x1C0x750xDF0x6E,
                
0x470xF10x1A0x710x1D0x290xC50x890x6F0xB70x620x0E0xAA0x180xBE0x1B,
                
0xFC0x560x3E0x4B0xC60xD20x790x200x9A0xDB0xC00xFE0x780xCD0x5A0xF4,
                
0x1F0xDD0xA80x330x880x070xC70x310xB10x120x100x590x270x800xEC0x5F,
                
0x600x510x7F0xA90x190xB50x4A0x0D0x2D0xE50x7A0x9F0x930xC90x9C0xEF,
                
0xA00xE00x3B0x4D0xAE0x2A0xF50xB00xC80xEB0xBB0x3C0x830x530x990x61,
                
0x170x2B0x040x7E0xBA0x770xD60x260xE10x690x140x630x550x210x0C0x7D
            
);

            
$sbox1 = array();
            
$sbox2 = array();
            
$sbox3 = array();

            for (
$i 0$i 256$i++) {
                
$sbox1[$i <<  8] = $sbox0[$i] <<  8;
                
$sbox2[$i << 16] = $sbox0[$i] << 16;
                
$sbox3[$i << 24] = $sbox0[$i] << 24;
            }
        }

        return 
$sbox0[$word 0x000000FF] | 
               
$sbox1[$word 0x0000FF00] | 
               
$sbox2[$word 0x00FF0000] | 
               
$sbox3[$word 0xFF000000];
    }

    
/**
     * Pad "packets".
     *
     * Rijndael works by encrypting between sixteen and thirty-two bytes at a time, provided that number is also a multiple
     * of four.  If you ever need to encrypt or decrypt something that isn't of the proper length, it becomes necessary to
     * pad the input so that it is of the proper length.
     *
     * Padding is enabled by default.  Sometimes, however, it is undesirable to pad strings.  Such is the case in SSH,
     * where "packets" are padded with random bytes before being encrypted.  Unpad these packets and you risk stripping
     * away characters that shouldn't be stripped away. (SSH knows how many bytes are added because the length is
     * transmitted separately)
     *
     * @see Crypt_Rijndael::disablePadding()
     * @access public
     */
    
function enablePadding()
    {
        
$this->padding true;
    }

    
/**
     * Do not pad packets.
     *
     * @see Crypt_Rijndael::enablePadding()
     * @access public
     */
    
function disablePadding()
    {
        
$this->padding false;
    }

    
/**
     * Pads a string
     *
     * Pads a string using the RSA PKCS padding standards so that its length is a multiple of the blocksize.
     * $block_size - (strlen($text) % $block_size) bytes are added, each of which is equal to 
     * chr($block_size - (strlen($text) % $block_size)
     *
     * If padding is disabled and $text is not a multiple of the blocksize, the string will be padded regardless
     * and padding will, hence forth, be enabled.
     *
     * @see Crypt_Rijndael::_unpad()
     * @access private
     */
    
function _pad($text)
    {
        
$length strlen($text);

        if (!
$this->padding) {
            if (
$length $this->block_size == 0) {
                return 
$text;
            } else {
                
user_error("The plaintext's length ($length) is not a multiple of the block size ({$this->block_size})"E_USER_NOTICE);
                
$this->padding true;
            }
        }

        
$pad $this->block_size - ($length $this->block_size);

        return 
str_pad($text$length $padchr($pad));
    }

    
/**
     * Unpads a string.
     *
     * If padding is enabled and the reported padding length is invalid the encryption key will be assumed to be wrong
     * and false will be returned.
     *
     * @see Crypt_Rijndael::_pad()
     * @access private
     */
    
function _unpad($text)
    {
        if (!
$this->padding) {
            return 
$text;
        }

        
$length ord($text[strlen($text) - 1]);

        if (!
$length || $length $this->block_size) {
            return 
false;
        }

        return 
substr($text0, -$length);
    }

    
/**
     * Treat consecutive "packets" as if they are a continuous buffer.
     *
     * Say you have a 32-byte plaintext $plaintext.  Using the default behavior, the two following code snippets
     * will yield different outputs:
     *
     * <code>
     *    echo $rijndael->encrypt(substr($plaintext,  0, 16));
     *    echo $rijndael->encrypt(substr($plaintext, 16, 16));
     * </code>
     * <code>
     *    echo $rijndael->encrypt($plaintext);
     * </code>
     *
     * The solution is to enable the continuous buffer.  Although this will resolve the above discrepancy, it creates
     * another, as demonstrated with the following:
     *
     * <code>
     *    $rijndael->encrypt(substr($plaintext, 0, 16));
     *    echo $rijndael->decrypt($des->encrypt(substr($plaintext, 16, 16)));
     * </code>
     * <code>
     *    echo $rijndael->decrypt($des->encrypt(substr($plaintext, 16, 16)));
     * </code>
     *
     * With the continuous buffer disabled, these would yield the same output.  With it enabled, they yield different
     * outputs.  The reason is due to the fact that the initialization vector's change after every encryption /
     * decryption round when the continuous buffer is enabled.  When it's disabled, they remain constant.
     *
     * Put another way, when the continuous buffer is enabled, the state of the Crypt_Rijndael() object changes after each
     * encryption / decryption round, whereas otherwise, it'd remain constant.  For this reason, it's recommended that
     * continuous buffers not be used.  They do offer better security and are, in fact, sometimes required (SSH uses them),
     * however, they are also less intuitive and more likely to cause you problems.
     *
     * @see Crypt_Rijndael::disableContinuousBuffer()
     * @access public
     */
    
function enableContinuousBuffer()
    {
        
$this->continuousBuffer true;
    }

    
/**
     * Treat consecutive packets as if they are a discontinuous buffer.
     *
     * The default behavior.
     *
     * @see Crypt_Rijndael::enableContinuousBuffer()
     * @access public
     */
    
function disableContinuousBuffer()
    {
        
$this->continuousBuffer false;
        
$this->encryptIV $this->iv;
        
$this->decryptIV $this->iv;
    }

    
/**
     * String Shift
     *
     * Inspired by array_shift
     *
     * @param String $string
     * @param optional Integer $index
     * @return String
     * @access private
     */
    
function _string_shift(&$string$index 1)
    {
        
$substr substr($string0$index);
        
$string substr($string$index);
        return 
$substr;
    }
}

// vim: ts=4:sw=4:et:
// vim6: fdl=1:
?>