Code Duplication    Length = 162-202 lines in 3 locations

includes/libraries/Encryption/Crypt/aesctr.php 1 location

@@ 10-211 (lines=202) @@
7
/*    form is offered.                                                                            */
8
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -  */
9
10
class Aes
11
{
12
    /**
13
     * AES Cipher function: encrypt 'input' with Rijndael algorithm
14
     *
15
     * @param input message as byte-array (16 bytes)
16
     * @param w     key schedule as 2D byte-array (Nr+1 x Nb bytes) -
17
     *              generated from the cipher key by keyExpansion()
18
     * @return ciphertext as byte-array (16 bytes)
19
     */
20
    public static function cipher($input, $w)
21
    {
22
        // main cipher function [é5.1]
23
        $Nb = 4; // block size (in words): no of columns in state (fixed at 4 for AES)
24
        $Nr = count($w) / $Nb - 1; // no of rounds: 10/12/14 for 128/192/256-bit keys
25
26
        $state = array(); // initialise 4xNb byte-array 'state' with input [é3.4]
27
        for ($i = 0; $i < 4 * $Nb; $i++) {
28
            $state[$i % 4][floor($i / 4)] = $input[$i];
29
        }
30
31
        $state = self::addRoundKey($state, $w, 0, $Nb);
32
33
        for ($round = 1; $round < $Nr; $round++) {  // apply Nr rounds
34
            $state = self::subBytes($state, $Nb);
35
            $state = self::shiftRows($state, $Nb);
36
            $state = self::mixColumns($state, $Nb);
37
            $state = self::addRoundKey($state, $w, $round, $Nb);
38
        }
39
40
        $state = self::subBytes($state, $Nb);
41
        $state = self::shiftRows($state, $Nb);
42
        $state = self::addRoundKey($state, $w, $Nr, $Nb);
43
44
        $output = array(4 * $Nb); // convert state to 1-d array before returning [é3.4]
45
        for ($i = 0; $i < 4 * $Nb; $i++) {
46
            $output[$i] = $state[$i % 4][floor($i / 4)];
47
        }
48
49
        return $output;
50
    }
51
52
    /**
53
     * @param integer $rnd
54
     * @param integer $Nb
55
     */
56
    private static function addRoundKey($state, $w, $rnd, $Nb)
57
    {
58
        // xor Round Key into state S [é5.1.4]
59
        for ($r = 0; $r < 4; $r++) {
60
            for ($c = 0; $c < $Nb; $c++) {
61
                $state[$r][$c] ^= $w[$rnd * 4 + $c][$r];
62
            }
63
        }
64
65
        return $state;
66
    }
67
68
    /**
69
     * @param integer $Nb
70
     */
71
    private static function subBytes($s, $Nb)
72
    {
73
        // apply SBox to state S [é5.1.1]
74
        for ($r = 0; $r < 4; $r++) {
75
            for ($c = 0; $c < $Nb; $c++) {
76
                $s[$r][$c] = self::$sBox[$s[$r][$c]];
77
            }
78
        }
79
80
        return $s;
81
    }
82
83
    /**
84
     * @param integer $Nb
85
     */
86
    private static function shiftRows($s, $Nb)
87
    {
88
        // shift row r of state S left by r bytes [é5.1.2]
89
        $t = array(4);
90
        for ($r = 1; $r < 4; $r++) {
91
            for ($c = 0; $c < 4; $c++) {
92
                $t[$c] = $s[$r][($c + $r) % $Nb]; // shift into temp copy
93
            }
94
            for ($c = 0; $c < 4; $c++) {
95
                $s[$r][$c] = $t[$c]; // and copy back
96
            }
97
        }          // note that this will work for Nb=4,5,6, but not 7,8 (always 4 for AES):
98
        return $s; // see fp.gladman.plus.com/cryptography_technology/rijndael/aes.spec.311.pdf
99
    }
100
101
    /**
102
     * @param integer $Nb
103
     */
104
    private static function mixColumns($s, $Nb)
105
    {
106
        // combine bytes of each col of state S [é5.1.3]
107
        for ($c = 0; $c < 4; $c++) {
108
            $a = array(4); // 'a' is a copy of the current column from 's'
109
            $b = array(4); // 'b' is aé{02} in GF(2^8)
110
            for ($i = 0; $i < 4; $i++) {
111
                $a[$i] = $s[$i][$c];
112
                $b[$i] = $s[$i][$c] & 0x80 ? $s[$i][$c] << 1 ^ 0x011b : $s[$i][$c] << 1;
113
            }
114
            // a[n] ^ b[n] is aé{03} in GF(2^8)
115
            $s[0][$c] = $b[0] ^ $a[1] ^ $b[1] ^ $a[2] ^ $a[3]; // 2*a0 + 3*a1 + a2 + a3
116
            $s[1][$c] = $a[0] ^ $b[1] ^ $a[2] ^ $b[2] ^ $a[3]; // a0 * 2*a1 + 3*a2 + a3
117
            $s[2][$c] = $a[0] ^ $a[1] ^ $b[2] ^ $a[3] ^ $b[3]; // a0 + a1 + 2*a2 + 3*a3
118
            $s[3][$c] = $a[0] ^ $b[0] ^ $a[1] ^ $a[2] ^ $b[3]; // 3*a0 + a1 + a2 + 2*a3
119
        }
120
121
        return $s;
122
    }
123
124
    /**
125
     * Key expansion for Rijndael cipher(): performs key expansion on cipher key
126
     * to generate a key schedule
127
     *
128
     * @param key cipher key byte-array (16 bytes)
129
     * @return key schedule as 2D byte-array (Nr+1 x Nb bytes)
130
     */
131
    public static function keyExpansion($key)
132
    {
133
        // generate Key Schedule from Cipher Key [é5.2]
134
        $Nb = 4; // block size (in words): no of columns in state (fixed at 4 for AES)
135
        $Nk = count($key) / 4; // key length (in words): 4/6/8 for 128/192/256-bit keys
136
        $Nr = $Nk + 6; // no of rounds: 10/12/14 for 128/192/256-bit keys
137
138
        $w = array();
139
        $temp = array();
140
141
        for ($i = 0; $i < $Nk; $i++) {
142
            $r = array($key[4 * $i], $key[4 * $i + 1], $key[4 * $i + 2], $key[4 * $i + 3]);
143
            $w[$i] = $r;
144
        }
145
146
        for ($i = $Nk; $i < ($Nb * ($Nr + 1)); $i++) {
147
            $w[$i] = array();
148
            for ($t = 0; $t < 4; $t++) {
149
                $temp[$t] = $w[$i - 1][$t];
150
            }
151
            if ($i % $Nk == 0) {
152
                $temp = self::subWord(self::rotWord($temp));
153
                for ($t = 0; $t < 4; $t++) {
154
                    $temp[$t] ^= self::$rCon[$i / $Nk][$t];
155
                }
156
            } elseif ($Nk > 6 && $i % $Nk == 4) {
157
                $temp = self::subWord($temp);
158
            }
159
            for ($t = 0; $t < 4; $t++) {
160
                $w[$i][$t] = $w[$i - $Nk][$t] ^ $temp[$t];
161
            }
162
        }
163
164
        return $w;
165
    }
166
167
    private static function subWord($w)
168
    {
169
        // apply SBox to 4-byte word w
170
        for ($i = 0; $i < 4; $i++) {
171
            $w[$i] = self::$sBox[$w[$i]];
172
        }
173
174
        return $w;
175
    }
176
177
    private static function rotWord($w)
178
    {
179
        // rotate 4-byte word w left by one byte
180
        $tmp = $w[0];
181
        for ($i = 0; $i < 3; $i++) {
182
            $w[$i] = $w[$i + 1];
183
        }
184
        $w[3] = $tmp;
185
186
        return $w;
187
    }
188
189
    // sBox is pre-computed multiplicative inverse in GF(2^8) used in subBytes and keyExpansion [é5.1.1]
190
    private static $sBox = array(
191
            0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5, 0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76,
192
            0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0, 0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0,
193
            0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc, 0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15,
194
            0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a, 0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75,
195
            0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0, 0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84,
196
            0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b, 0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf,
197
            0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85, 0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8,
198
            0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5, 0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2,
199
            0xcd, 0x0c, 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17, 0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73,
200
            0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88, 0x46, 0xee, 0xb8, 0x14, 0xde, 0x5e, 0x0b, 0xdb,
201
            0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c, 0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79,
202
            0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, 0x4e, 0xa9, 0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08,
203
            0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6, 0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a,
204
            0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e, 0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e,
205
            0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94, 0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf,
206
            0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68, 0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16
207
    );
208
209
    // rCon is Round Constant used for the Key Expansion [1st col is 2^(r-1) in GF(2^8)] [é5.2]
210
    private static $rCon = array(
211
            array(0x00, 0x00, 0x00, 0x00),
212
            array(0x01, 0x00, 0x00, 0x00),
213
            array(0x02, 0x00, 0x00, 0x00),
214
            array(0x04, 0x00, 0x00, 0x00),

install/js/crypt/aes.class.php 1 location

@@ 7-168 (lines=162) @@
4
/*    commercial or non-commercial use under CC-BY licence. No warranty of any form is offered.   */
5
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -  */
6
7
class Aes
8
{
9
    /**
10
     * AES Cipher function: encrypt 'input' with Rijndael algorithm
11
     *
12
     * @param input message as byte-array (16 bytes)
13
     * @param w     key schedule as 2D byte-array (Nr+1 x Nb bytes) -
14
     *              generated from the cipher key by keyExpansion()
15
     * @return      ciphertext as byte-array (16 bytes)
16
     */
17
    public static function cipher($input, $w) {    // main cipher function [é5.1]
18
    $Nb = 4; // block size (in words): no of columns in state (fixed at 4 for AES)
19
    $Nr = count($w) / $Nb - 1; // no of rounds: 10/12/14 for 128/192/256-bit keys
20
21
    $state = array(); // initialise 4xNb byte-array 'state' with input [é3.4]
22
    for ($i = 0; $i < 4 * $Nb; $i++) {
23
        $state[$i % 4][floor($i / 4)] = $input[$i];
24
    }
25
26
    $state = self::addRoundKey($state, $w, 0, $Nb);
27
28
    for ($round = 1; $round < $Nr; $round++) {  // apply Nr rounds
29
        $state = self::subBytes($state, $Nb);
30
        $state = self::shiftRows($state, $Nb);
31
        $state = self::mixColumns($state, $Nb);
32
        $state = self::addRoundKey($state, $w, $round, $Nb);
33
    }
34
35
    $state = self::subBytes($state, $Nb);
36
    $state = self::shiftRows($state, $Nb);
37
    $state = self::addRoundKey($state, $w, $Nr, $Nb);
38
39
    $output = array(4 * $Nb); // convert state to 1-d array before returning [é3.4]
40
    for ($i = 0; $i < 4 * $Nb; $i++) {
41
        $output[$i] = $state[$i % 4][floor($i / 4)];
42
    }
43
44
    return $output;
45
    }
46
47
    /**
48
     * @param integer $rnd
49
     * @param integer $Nb
50
     */
51
    private static function addRoundKey($state, $w, $rnd, $Nb) {  // xor Round Key into state S [é5.1.4]
52
    for ($r = 0; $r < 4; $r++) {
53
        for ($c = 0; $c < $Nb; $c++) {
54
            $state[$r][$c] ^= $w[$rnd * 4 + $c][$r];
55
        }
56
    }
57
58
    return $state;
59
    }
60
61
    /**
62
     * @param integer $Nb
63
     */
64
    private static function subBytes($s, $Nb) {    // apply SBox to state S [é5.1.1]
65
    for ($r = 0; $r < 4; $r++) {
66
        for ($c = 0; $c < $Nb; $c++) {
67
            $s[$r][$c] = self::$sBox[$s[$r][$c]];
68
        }
69
    }
70
71
    return $s;
72
    }
73
74
    /**
75
     * @param integer $Nb
76
     */
77
    private static function shiftRows($s, $Nb) {    // shift row r of state S left by r bytes [é5.1.2]
78
    $t = array(4);
79
    for ($r = 1; $r < 4; $r++) {
80
        for ($c = 0; $c < 4; $c++) {
81
            $t[$c] = $s[$r][($c + $r) % $Nb];
82
        }
83
        // shift into temp copy
84
        for ($c = 0; $c < 4; $c++) {
85
            $s[$r][$c] = $t[$c];
86
        }
87
        // and copy back
88
    }          // note that this will work for Nb=4,5,6, but not 7,8 (always 4 for AES):
89
    return $s; // see fp.gladman.plus.com/cryptography_technology/rijndael/aes.spec.311.pdf
90
    }
91
92
    /**
93
     * @param integer $Nb
94
     */
95
    private static function mixColumns($s, $Nb) {   // combine bytes of each col of state S [é5.1.3]
96
    for ($c = 0; $c < 4; $c++) {
97
        $a = array(4); // 'a' is a copy of the current column from 's'
98
        $b = array(4); // 'b' is aé{02} in GF(2^8)
99
        for ($i = 0; $i < 4; $i++) {
100
        $a[$i] = $s[$i][$c];
101
        $b[$i] = $s[$i][$c] & 0x80 ? $s[$i][$c] << 1 ^ 0x011b : $s[$i][$c] << 1;
102
        }
103
        // a[n] ^ b[n] is aé{03} in GF(2^8)
104
        $s[0][$c] = $b[0] ^ $a[1] ^ $b[1] ^ $a[2] ^ $a[3]; // 2*a0 + 3*a1 + a2 + a3
105
        $s[1][$c] = $a[0] ^ $b[1] ^ $a[2] ^ $b[2] ^ $a[3]; // a0 * 2*a1 + 3*a2 + a3
106
        $s[2][$c] = $a[0] ^ $a[1] ^ $b[2] ^ $a[3] ^ $b[3]; // a0 + a1 + 2*a2 + 3*a3
107
        $s[3][$c] = $a[0] ^ $b[0] ^ $a[1] ^ $a[2] ^ $b[3]; // 3*a0 + a1 + a2 + 2*a3
108
    }
109
110
    return $s;
111
    }
112
113
    /**
114
     * Key expansion for Rijndael cipher(): performs key expansion on cipher key
115
     * to generate a key schedule
116
     *
117
     * @param key cipher key byte-array (16 bytes)
118
     * @return    key schedule as 2D byte-array (Nr+1 x Nb bytes)
119
     */
120
    public static function keyExpansion($key) {  // generate Key Schedule from Cipher Key [é5.2]
121
    $Nb = 4; // block size (in words): no of columns in state (fixed at 4 for AES)
122
    $Nk = count($key) / 4; // key length (in words): 4/6/8 for 128/192/256-bit keys
123
    $Nr = $Nk + 6; // no of rounds: 10/12/14 for 128/192/256-bit keys
124
125
    $w = array();
126
    $temp = array();
127
128
    for ($i = 0; $i < $Nk; $i++) {
129
        $r = array($key[4 * $i], $key[4 * $i + 1], $key[4 * $i + 2], $key[4 * $i + 3]);
130
        $w[$i] = $r;
131
    }
132
133
    for ($i = $Nk; $i < ($Nb * ($Nr + 1)); $i++) {
134
        $w[$i] = array();
135
        for ($t = 0; $t < 4; $t++) {
136
            $temp[$t] = $w[$i - 1][$t];
137
        }
138
        if ($i % $Nk == 0) {
139
        $temp = self::subWord(self::rotWord($temp));
140
        for ($t = 0; $t < 4; $t++) {
141
            $temp[$t] ^= self::$rCon[$i / $Nk][$t];
142
        }
143
        } elseif ($Nk > 6 && $i % $Nk == 4) {
144
        $temp = self::subWord($temp);
145
        }
146
        for ($t = 0; $t < 4; $t++) {
147
            $w[$i][$t] = $w[$i - $Nk][$t] ^ $temp[$t];
148
        }
149
    }
150
151
    return $w;
152
    }
153
154
    private static function subWord($w) {    // apply SBox to 4-byte word w
155
    for ($i = 0; $i < 4; $i++) {
156
        $w[$i] = self::$sBox[$w[$i]];
157
    }
158
159
    return $w;
160
    }
161
162
    private static function rotWord($w) {    // rotate 4-byte word w left by one byte
163
    $tmp = $w[0];
164
    for ($i = 0; $i < 3; $i++) {
165
        $w[$i] = $w[$i + 1];
166
    }
167
    $w[3] = $tmp;
168
169
    return $w;
170
    }
171

install/libs/aesctr.php 1 location

@@ 10-211 (lines=202) @@
7
/*    form is offered.                                                                            */
8
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -  */
9
10
class Aes
11
{
12
    /**
13
     * AES Cipher function: encrypt 'input' with Rijndael algorithm
14
     *
15
     * @param input message as byte-array (16 bytes)
16
     * @param w     key schedule as 2D byte-array (Nr+1 x Nb bytes) -
17
     *              generated from the cipher key by keyExpansion()
18
     * @return ciphertext as byte-array (16 bytes)
19
     */
20
    public static function cipher($input, $w)
21
    {
22
        // main cipher function [é5.1]
23
        $Nb = 4; // block size (in words): no of columns in state (fixed at 4 for AES)
24
        $Nr = count($w) / $Nb - 1; // no of rounds: 10/12/14 for 128/192/256-bit keys
25
26
        $state = array(); // initialise 4xNb byte-array 'state' with input [é3.4]
27
        for ($i = 0; $i < 4 * $Nb; $i++) {
28
            $state[$i % 4][floor($i / 4)] = $input[$i];
29
        }
30
31
        $state = self::addRoundKey($state, $w, 0, $Nb);
32
33
        for ($round = 1; $round < $Nr; $round++) {  // apply Nr rounds
34
            $state = self::subBytes($state, $Nb);
35
            $state = self::shiftRows($state, $Nb);
36
            $state = self::mixColumns($state, $Nb);
37
            $state = self::addRoundKey($state, $w, $round, $Nb);
38
        }
39
40
        $state = self::subBytes($state, $Nb);
41
        $state = self::shiftRows($state, $Nb);
42
        $state = self::addRoundKey($state, $w, $Nr, $Nb);
43
44
        $output = array(4 * $Nb); // convert state to 1-d array before returning [é3.4]
45
        for ($i = 0; $i < 4 * $Nb; $i++) {
46
            $output[$i] = $state[$i % 4][floor($i / 4)];
47
        }
48
49
        return $output;
50
    }
51
52
    /**
53
     * @param integer $rnd
54
     * @param integer $Nb
55
     */
56
    private static function addRoundKey($state, $w, $rnd, $Nb)
57
    {
58
        // xor Round Key into state S [é5.1.4]
59
        for ($r = 0; $r < 4; $r++) {
60
            for ($c = 0; $c < $Nb; $c++) {
61
                $state[$r][$c] ^= $w[$rnd * 4 + $c][$r];
62
            }
63
        }
64
65
        return $state;
66
    }
67
68
    /**
69
     * @param integer $Nb
70
     */
71
    private static function subBytes($s, $Nb)
72
    {
73
        // apply SBox to state S [é5.1.1]
74
        for ($r = 0; $r < 4; $r++) {
75
            for ($c = 0; $c < $Nb; $c++) {
76
                $s[$r][$c] = self::$sBox[$s[$r][$c]];
77
            }
78
        }
79
80
        return $s;
81
    }
82
83
    /**
84
     * @param integer $Nb
85
     */
86
    private static function shiftRows($s, $Nb)
87
    {
88
        // shift row r of state S left by r bytes [é5.1.2]
89
        $t = array(4);
90
        for ($r = 1; $r < 4; $r++) {
91
            for ($c = 0; $c < 4; $c++) {
92
                $t[$c] = $s[$r][($c + $r) % $Nb]; // shift into temp copy
93
            }
94
            for ($c = 0; $c < 4; $c++) {
95
                $s[$r][$c] = $t[$c]; // and copy back
96
            }
97
        }          // note that this will work for Nb=4,5,6, but not 7,8 (always 4 for AES):
98
        return $s; // see fp.gladman.plus.com/cryptography_technology/rijndael/aes.spec.311.pdf
99
    }
100
101
    /**
102
     * @param integer $Nb
103
     */
104
    private static function mixColumns($s, $Nb)
105
    {
106
        // combine bytes of each col of state S [é5.1.3]
107
        for ($c = 0; $c < 4; $c++) {
108
            $a = array(4); // 'a' is a copy of the current column from 's'
109
            $b = array(4); // 'b' is aé{02} in GF(2^8)
110
            for ($i = 0; $i < 4; $i++) {
111
                $a[$i] = $s[$i][$c];
112
                $b[$i] = $s[$i][$c] & 0x80 ? $s[$i][$c] << 1 ^ 0x011b : $s[$i][$c] << 1;
113
            }
114
            // a[n] ^ b[n] is aé{03} in GF(2^8)
115
            $s[0][$c] = $b[0] ^ $a[1] ^ $b[1] ^ $a[2] ^ $a[3]; // 2*a0 + 3*a1 + a2 + a3
116
            $s[1][$c] = $a[0] ^ $b[1] ^ $a[2] ^ $b[2] ^ $a[3]; // a0 * 2*a1 + 3*a2 + a3
117
            $s[2][$c] = $a[0] ^ $a[1] ^ $b[2] ^ $a[3] ^ $b[3]; // a0 + a1 + 2*a2 + 3*a3
118
            $s[3][$c] = $a[0] ^ $b[0] ^ $a[1] ^ $a[2] ^ $b[3]; // 3*a0 + a1 + a2 + 2*a3
119
        }
120
121
        return $s;
122
    }
123
124
    /**
125
     * Key expansion for Rijndael cipher(): performs key expansion on cipher key
126
     * to generate a key schedule
127
     *
128
     * @param key cipher key byte-array (16 bytes)
129
     * @return key schedule as 2D byte-array (Nr+1 x Nb bytes)
130
     */
131
    public static function keyExpansion($key)
132
    {
133
        // generate Key Schedule from Cipher Key [é5.2]
134
        $Nb = 4; // block size (in words): no of columns in state (fixed at 4 for AES)
135
        $Nk = count($key) / 4; // key length (in words): 4/6/8 for 128/192/256-bit keys
136
        $Nr = $Nk + 6; // no of rounds: 10/12/14 for 128/192/256-bit keys
137
138
        $w = array();
139
        $temp = array();
140
141
        for ($i = 0; $i < $Nk; $i++) {
142
            $r = array($key[4 * $i], $key[4 * $i + 1], $key[4 * $i + 2], $key[4 * $i + 3]);
143
            $w[$i] = $r;
144
        }
145
146
        for ($i = $Nk; $i < ($Nb * ($Nr + 1)); $i++) {
147
            $w[$i] = array();
148
            for ($t = 0; $t < 4; $t++) {
149
                $temp[$t] = $w[$i - 1][$t];
150
            }
151
            if ($i % $Nk == 0) {
152
                $temp = self::subWord(self::rotWord($temp));
153
                for ($t = 0; $t < 4; $t++) {
154
                    $temp[$t] ^= self::$rCon[$i / $Nk][$t];
155
                }
156
            } elseif ($Nk > 6 && $i % $Nk == 4) {
157
                $temp = self::subWord($temp);
158
            }
159
            for ($t = 0; $t < 4; $t++) {
160
                $w[$i][$t] = $w[$i - $Nk][$t] ^ $temp[$t];
161
            }
162
        }
163
164
        return $w;
165
    }
166
167
    private static function subWord($w)
168
    {
169
        // apply SBox to 4-byte word w
170
        for ($i = 0; $i < 4; $i++) {
171
            $w[$i] = self::$sBox[$w[$i]];
172
        }
173
174
        return $w;
175
    }
176
177
    private static function rotWord($w)
178
    {
179
        // rotate 4-byte word w left by one byte
180
        $tmp = $w[0];
181
        for ($i = 0; $i < 3; $i++) {
182
            $w[$i] = $w[$i + 1];
183
        }
184
        $w[3] = $tmp;
185
186
        return $w;
187
    }
188
189
    // sBox is pre-computed multiplicative inverse in GF(2^8) used in subBytes and keyExpansion [é5.1.1]
190
    private static $sBox = array(
191
            0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5, 0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76,
192
            0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0, 0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0,
193
            0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc, 0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15,
194
            0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a, 0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75,
195
            0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0, 0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84,
196
            0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b, 0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf,
197
            0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85, 0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8,
198
            0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5, 0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2,
199
            0xcd, 0x0c, 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17, 0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73,
200
            0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88, 0x46, 0xee, 0xb8, 0x14, 0xde, 0x5e, 0x0b, 0xdb,
201
            0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c, 0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79,
202
            0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, 0x4e, 0xa9, 0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08,
203
            0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6, 0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a,
204
            0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e, 0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e,
205
            0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94, 0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf,
206
            0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68, 0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16
207
    );
208
209
    // rCon is Round Constant used for the Key Expansion [1st col is 2^(r-1) in GF(2^8)] [é5.2]
210
    private static $rCon = array(
211
            array(0x00, 0x00, 0x00, 0x00),
212
            array(0x01, 0x00, 0x00, 0x00),
213
            array(0x02, 0x00, 0x00, 0x00),
214
            array(0x04, 0x00, 0x00, 0x00),