]> git.bitcoin.ninja Git - youtube-dl/blob - youtube_dl/aes.py
[http] Rework HTTP downloader
[youtube-dl] / youtube_dl / aes.py
1 from __future__ import unicode_literals
2
3 import base64
4 from math import ceil
5
6 from .utils import bytes_to_intlist, intlist_to_bytes
7
8 BLOCK_SIZE_BYTES = 16
9
10
11 def aes_ctr_decrypt(data, key, counter):
12     """
13     Decrypt with aes in counter mode
14
15     @param {int[]} data        cipher
16     @param {int[]} key         16/24/32-Byte cipher key
17     @param {instance} counter  Instance whose next_value function (@returns {int[]}  16-Byte block)
18                                returns the next counter block
19     @returns {int[]}           decrypted data
20     """
21     expanded_key = key_expansion(key)
22     block_count = int(ceil(float(len(data)) / BLOCK_SIZE_BYTES))
23
24     decrypted_data = []
25     for i in range(block_count):
26         counter_block = counter.next_value()
27         block = data[i * BLOCK_SIZE_BYTES: (i + 1) * BLOCK_SIZE_BYTES]
28         block += [0] * (BLOCK_SIZE_BYTES - len(block))
29
30         cipher_counter_block = aes_encrypt(counter_block, expanded_key)
31         decrypted_data += xor(block, cipher_counter_block)
32     decrypted_data = decrypted_data[:len(data)]
33
34     return decrypted_data
35
36
37 def aes_cbc_decrypt(data, key, iv):
38     """
39     Decrypt with aes in CBC mode
40
41     @param {int[]} data        cipher
42     @param {int[]} key         16/24/32-Byte cipher key
43     @param {int[]} iv          16-Byte IV
44     @returns {int[]}           decrypted data
45     """
46     expanded_key = key_expansion(key)
47     block_count = int(ceil(float(len(data)) / BLOCK_SIZE_BYTES))
48
49     decrypted_data = []
50     previous_cipher_block = iv
51     for i in range(block_count):
52         block = data[i * BLOCK_SIZE_BYTES: (i + 1) * BLOCK_SIZE_BYTES]
53         block += [0] * (BLOCK_SIZE_BYTES - len(block))
54
55         decrypted_block = aes_decrypt(block, expanded_key)
56         decrypted_data += xor(decrypted_block, previous_cipher_block)
57         previous_cipher_block = block
58     decrypted_data = decrypted_data[:len(data)]
59
60     return decrypted_data
61
62
63 def aes_cbc_encrypt(data, key, iv):
64     """
65     Encrypt with aes in CBC mode. Using PKCS#7 padding
66
67     @param {int[]} data        cleartext
68     @param {int[]} key         16/24/32-Byte cipher key
69     @param {int[]} iv          16-Byte IV
70     @returns {int[]}           encrypted data
71     """
72     expanded_key = key_expansion(key)
73     block_count = int(ceil(float(len(data)) / BLOCK_SIZE_BYTES))
74
75     encrypted_data = []
76     previous_cipher_block = iv
77     for i in range(block_count):
78         block = data[i * BLOCK_SIZE_BYTES: (i + 1) * BLOCK_SIZE_BYTES]
79         remaining_length = BLOCK_SIZE_BYTES - len(block)
80         block += [remaining_length] * remaining_length
81         mixed_block = xor(block, previous_cipher_block)
82
83         encrypted_block = aes_encrypt(mixed_block, expanded_key)
84         encrypted_data += encrypted_block
85
86         previous_cipher_block = encrypted_block
87
88     return encrypted_data
89
90
91 def key_expansion(data):
92     """
93     Generate key schedule
94
95     @param {int[]} data  16/24/32-Byte cipher key
96     @returns {int[]}     176/208/240-Byte expanded key
97     """
98     data = data[:]  # copy
99     rcon_iteration = 1
100     key_size_bytes = len(data)
101     expanded_key_size_bytes = (key_size_bytes // 4 + 7) * BLOCK_SIZE_BYTES
102
103     while len(data) < expanded_key_size_bytes:
104         temp = data[-4:]
105         temp = key_schedule_core(temp, rcon_iteration)
106         rcon_iteration += 1
107         data += xor(temp, data[-key_size_bytes: 4 - key_size_bytes])
108
109         for _ in range(3):
110             temp = data[-4:]
111             data += xor(temp, data[-key_size_bytes: 4 - key_size_bytes])
112
113         if key_size_bytes == 32:
114             temp = data[-4:]
115             temp = sub_bytes(temp)
116             data += xor(temp, data[-key_size_bytes: 4 - key_size_bytes])
117
118         for _ in range(3 if key_size_bytes == 32 else 2 if key_size_bytes == 24 else 0):
119             temp = data[-4:]
120             data += xor(temp, data[-key_size_bytes: 4 - key_size_bytes])
121     data = data[:expanded_key_size_bytes]
122
123     return data
124
125
126 def aes_encrypt(data, expanded_key):
127     """
128     Encrypt one block with aes
129
130     @param {int[]} data          16-Byte state
131     @param {int[]} expanded_key  176/208/240-Byte expanded key
132     @returns {int[]}             16-Byte cipher
133     """
134     rounds = len(expanded_key) // BLOCK_SIZE_BYTES - 1
135
136     data = xor(data, expanded_key[:BLOCK_SIZE_BYTES])
137     for i in range(1, rounds + 1):
138         data = sub_bytes(data)
139         data = shift_rows(data)
140         if i != rounds:
141             data = mix_columns(data)
142         data = xor(data, expanded_key[i * BLOCK_SIZE_BYTES: (i + 1) * BLOCK_SIZE_BYTES])
143
144     return data
145
146
147 def aes_decrypt(data, expanded_key):
148     """
149     Decrypt one block with aes
150
151     @param {int[]} data          16-Byte cipher
152     @param {int[]} expanded_key  176/208/240-Byte expanded key
153     @returns {int[]}             16-Byte state
154     """
155     rounds = len(expanded_key) // BLOCK_SIZE_BYTES - 1
156
157     for i in range(rounds, 0, -1):
158         data = xor(data, expanded_key[i * BLOCK_SIZE_BYTES: (i + 1) * BLOCK_SIZE_BYTES])
159         if i != rounds:
160             data = mix_columns_inv(data)
161         data = shift_rows_inv(data)
162         data = sub_bytes_inv(data)
163     data = xor(data, expanded_key[:BLOCK_SIZE_BYTES])
164
165     return data
166
167
168 def aes_decrypt_text(data, password, key_size_bytes):
169     """
170     Decrypt text
171     - The first 8 Bytes of decoded 'data' are the 8 high Bytes of the counter
172     - The cipher key is retrieved by encrypting the first 16 Byte of 'password'
173       with the first 'key_size_bytes' Bytes from 'password' (if necessary filled with 0's)
174     - Mode of operation is 'counter'
175
176     @param {str} data                    Base64 encoded string
177     @param {str,unicode} password        Password (will be encoded with utf-8)
178     @param {int} key_size_bytes          Possible values: 16 for 128-Bit, 24 for 192-Bit or 32 for 256-Bit
179     @returns {str}                       Decrypted data
180     """
181     NONCE_LENGTH_BYTES = 8
182
183     data = bytes_to_intlist(base64.b64decode(data.encode('utf-8')))
184     password = bytes_to_intlist(password.encode('utf-8'))
185
186     key = password[:key_size_bytes] + [0] * (key_size_bytes - len(password))
187     key = aes_encrypt(key[:BLOCK_SIZE_BYTES], key_expansion(key)) * (key_size_bytes // BLOCK_SIZE_BYTES)
188
189     nonce = data[:NONCE_LENGTH_BYTES]
190     cipher = data[NONCE_LENGTH_BYTES:]
191
192     class Counter(object):
193         __value = nonce + [0] * (BLOCK_SIZE_BYTES - NONCE_LENGTH_BYTES)
194
195         def next_value(self):
196             temp = self.__value
197             self.__value = inc(self.__value)
198             return temp
199
200     decrypted_data = aes_ctr_decrypt(cipher, key, Counter())
201     plaintext = intlist_to_bytes(decrypted_data)
202
203     return plaintext
204
205
206 RCON = (0x8d, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36)
207 SBOX = (0x63, 0x7C, 0x77, 0x7B, 0xF2, 0x6B, 0x6F, 0xC5, 0x30, 0x01, 0x67, 0x2B, 0xFE, 0xD7, 0xAB, 0x76,
208         0xCA, 0x82, 0xC9, 0x7D, 0xFA, 0x59, 0x47, 0xF0, 0xAD, 0xD4, 0xA2, 0xAF, 0x9C, 0xA4, 0x72, 0xC0,
209         0xB7, 0xFD, 0x93, 0x26, 0x36, 0x3F, 0xF7, 0xCC, 0x34, 0xA5, 0xE5, 0xF1, 0x71, 0xD8, 0x31, 0x15,
210         0x04, 0xC7, 0x23, 0xC3, 0x18, 0x96, 0x05, 0x9A, 0x07, 0x12, 0x80, 0xE2, 0xEB, 0x27, 0xB2, 0x75,
211         0x09, 0x83, 0x2C, 0x1A, 0x1B, 0x6E, 0x5A, 0xA0, 0x52, 0x3B, 0xD6, 0xB3, 0x29, 0xE3, 0x2F, 0x84,
212         0x53, 0xD1, 0x00, 0xED, 0x20, 0xFC, 0xB1, 0x5B, 0x6A, 0xCB, 0xBE, 0x39, 0x4A, 0x4C, 0x58, 0xCF,
213         0xD0, 0xEF, 0xAA, 0xFB, 0x43, 0x4D, 0x33, 0x85, 0x45, 0xF9, 0x02, 0x7F, 0x50, 0x3C, 0x9F, 0xA8,
214         0x51, 0xA3, 0x40, 0x8F, 0x92, 0x9D, 0x38, 0xF5, 0xBC, 0xB6, 0xDA, 0x21, 0x10, 0xFF, 0xF3, 0xD2,
215         0xCD, 0x0C, 0x13, 0xEC, 0x5F, 0x97, 0x44, 0x17, 0xC4, 0xA7, 0x7E, 0x3D, 0x64, 0x5D, 0x19, 0x73,
216         0x60, 0x81, 0x4F, 0xDC, 0x22, 0x2A, 0x90, 0x88, 0x46, 0xEE, 0xB8, 0x14, 0xDE, 0x5E, 0x0B, 0xDB,
217         0xE0, 0x32, 0x3A, 0x0A, 0x49, 0x06, 0x24, 0x5C, 0xC2, 0xD3, 0xAC, 0x62, 0x91, 0x95, 0xE4, 0x79,
218         0xE7, 0xC8, 0x37, 0x6D, 0x8D, 0xD5, 0x4E, 0xA9, 0x6C, 0x56, 0xF4, 0xEA, 0x65, 0x7A, 0xAE, 0x08,
219         0xBA, 0x78, 0x25, 0x2E, 0x1C, 0xA6, 0xB4, 0xC6, 0xE8, 0xDD, 0x74, 0x1F, 0x4B, 0xBD, 0x8B, 0x8A,
220         0x70, 0x3E, 0xB5, 0x66, 0x48, 0x03, 0xF6, 0x0E, 0x61, 0x35, 0x57, 0xB9, 0x86, 0xC1, 0x1D, 0x9E,
221         0xE1, 0xF8, 0x98, 0x11, 0x69, 0xD9, 0x8E, 0x94, 0x9B, 0x1E, 0x87, 0xE9, 0xCE, 0x55, 0x28, 0xDF,
222         0x8C, 0xA1, 0x89, 0x0D, 0xBF, 0xE6, 0x42, 0x68, 0x41, 0x99, 0x2D, 0x0F, 0xB0, 0x54, 0xBB, 0x16)
223 SBOX_INV = (0x52, 0x09, 0x6a, 0xd5, 0x30, 0x36, 0xa5, 0x38, 0xbf, 0x40, 0xa3, 0x9e, 0x81, 0xf3, 0xd7, 0xfb,
224             0x7c, 0xe3, 0x39, 0x82, 0x9b, 0x2f, 0xff, 0x87, 0x34, 0x8e, 0x43, 0x44, 0xc4, 0xde, 0xe9, 0xcb,
225             0x54, 0x7b, 0x94, 0x32, 0xa6, 0xc2, 0x23, 0x3d, 0xee, 0x4c, 0x95, 0x0b, 0x42, 0xfa, 0xc3, 0x4e,
226             0x08, 0x2e, 0xa1, 0x66, 0x28, 0xd9, 0x24, 0xb2, 0x76, 0x5b, 0xa2, 0x49, 0x6d, 0x8b, 0xd1, 0x25,
227             0x72, 0xf8, 0xf6, 0x64, 0x86, 0x68, 0x98, 0x16, 0xd4, 0xa4, 0x5c, 0xcc, 0x5d, 0x65, 0xb6, 0x92,
228             0x6c, 0x70, 0x48, 0x50, 0xfd, 0xed, 0xb9, 0xda, 0x5e, 0x15, 0x46, 0x57, 0xa7, 0x8d, 0x9d, 0x84,
229             0x90, 0xd8, 0xab, 0x00, 0x8c, 0xbc, 0xd3, 0x0a, 0xf7, 0xe4, 0x58, 0x05, 0xb8, 0xb3, 0x45, 0x06,
230             0xd0, 0x2c, 0x1e, 0x8f, 0xca, 0x3f, 0x0f, 0x02, 0xc1, 0xaf, 0xbd, 0x03, 0x01, 0x13, 0x8a, 0x6b,
231             0x3a, 0x91, 0x11, 0x41, 0x4f, 0x67, 0xdc, 0xea, 0x97, 0xf2, 0xcf, 0xce, 0xf0, 0xb4, 0xe6, 0x73,
232             0x96, 0xac, 0x74, 0x22, 0xe7, 0xad, 0x35, 0x85, 0xe2, 0xf9, 0x37, 0xe8, 0x1c, 0x75, 0xdf, 0x6e,
233             0x47, 0xf1, 0x1a, 0x71, 0x1d, 0x29, 0xc5, 0x89, 0x6f, 0xb7, 0x62, 0x0e, 0xaa, 0x18, 0xbe, 0x1b,
234             0xfc, 0x56, 0x3e, 0x4b, 0xc6, 0xd2, 0x79, 0x20, 0x9a, 0xdb, 0xc0, 0xfe, 0x78, 0xcd, 0x5a, 0xf4,
235             0x1f, 0xdd, 0xa8, 0x33, 0x88, 0x07, 0xc7, 0x31, 0xb1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xec, 0x5f,
236             0x60, 0x51, 0x7f, 0xa9, 0x19, 0xb5, 0x4a, 0x0d, 0x2d, 0xe5, 0x7a, 0x9f, 0x93, 0xc9, 0x9c, 0xef,
237             0xa0, 0xe0, 0x3b, 0x4d, 0xae, 0x2a, 0xf5, 0xb0, 0xc8, 0xeb, 0xbb, 0x3c, 0x83, 0x53, 0x99, 0x61,
238             0x17, 0x2b, 0x04, 0x7e, 0xba, 0x77, 0xd6, 0x26, 0xe1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0c, 0x7d)
239 MIX_COLUMN_MATRIX = ((0x2, 0x3, 0x1, 0x1),
240                      (0x1, 0x2, 0x3, 0x1),
241                      (0x1, 0x1, 0x2, 0x3),
242                      (0x3, 0x1, 0x1, 0x2))
243 MIX_COLUMN_MATRIX_INV = ((0xE, 0xB, 0xD, 0x9),
244                          (0x9, 0xE, 0xB, 0xD),
245                          (0xD, 0x9, 0xE, 0xB),
246                          (0xB, 0xD, 0x9, 0xE))
247 RIJNDAEL_EXP_TABLE = (0x01, 0x03, 0x05, 0x0F, 0x11, 0x33, 0x55, 0xFF, 0x1A, 0x2E, 0x72, 0x96, 0xA1, 0xF8, 0x13, 0x35,
248                       0x5F, 0xE1, 0x38, 0x48, 0xD8, 0x73, 0x95, 0xA4, 0xF7, 0x02, 0x06, 0x0A, 0x1E, 0x22, 0x66, 0xAA,
249                       0xE5, 0x34, 0x5C, 0xE4, 0x37, 0x59, 0xEB, 0x26, 0x6A, 0xBE, 0xD9, 0x70, 0x90, 0xAB, 0xE6, 0x31,
250                       0x53, 0xF5, 0x04, 0x0C, 0x14, 0x3C, 0x44, 0xCC, 0x4F, 0xD1, 0x68, 0xB8, 0xD3, 0x6E, 0xB2, 0xCD,
251                       0x4C, 0xD4, 0x67, 0xA9, 0xE0, 0x3B, 0x4D, 0xD7, 0x62, 0xA6, 0xF1, 0x08, 0x18, 0x28, 0x78, 0x88,
252                       0x83, 0x9E, 0xB9, 0xD0, 0x6B, 0xBD, 0xDC, 0x7F, 0x81, 0x98, 0xB3, 0xCE, 0x49, 0xDB, 0x76, 0x9A,
253                       0xB5, 0xC4, 0x57, 0xF9, 0x10, 0x30, 0x50, 0xF0, 0x0B, 0x1D, 0x27, 0x69, 0xBB, 0xD6, 0x61, 0xA3,
254                       0xFE, 0x19, 0x2B, 0x7D, 0x87, 0x92, 0xAD, 0xEC, 0x2F, 0x71, 0x93, 0xAE, 0xE9, 0x20, 0x60, 0xA0,
255                       0xFB, 0x16, 0x3A, 0x4E, 0xD2, 0x6D, 0xB7, 0xC2, 0x5D, 0xE7, 0x32, 0x56, 0xFA, 0x15, 0x3F, 0x41,
256                       0xC3, 0x5E, 0xE2, 0x3D, 0x47, 0xC9, 0x40, 0xC0, 0x5B, 0xED, 0x2C, 0x74, 0x9C, 0xBF, 0xDA, 0x75,
257                       0x9F, 0xBA, 0xD5, 0x64, 0xAC, 0xEF, 0x2A, 0x7E, 0x82, 0x9D, 0xBC, 0xDF, 0x7A, 0x8E, 0x89, 0x80,
258                       0x9B, 0xB6, 0xC1, 0x58, 0xE8, 0x23, 0x65, 0xAF, 0xEA, 0x25, 0x6F, 0xB1, 0xC8, 0x43, 0xC5, 0x54,
259                       0xFC, 0x1F, 0x21, 0x63, 0xA5, 0xF4, 0x07, 0x09, 0x1B, 0x2D, 0x77, 0x99, 0xB0, 0xCB, 0x46, 0xCA,
260                       0x45, 0xCF, 0x4A, 0xDE, 0x79, 0x8B, 0x86, 0x91, 0xA8, 0xE3, 0x3E, 0x42, 0xC6, 0x51, 0xF3, 0x0E,
261                       0x12, 0x36, 0x5A, 0xEE, 0x29, 0x7B, 0x8D, 0x8C, 0x8F, 0x8A, 0x85, 0x94, 0xA7, 0xF2, 0x0D, 0x17,
262                       0x39, 0x4B, 0xDD, 0x7C, 0x84, 0x97, 0xA2, 0xFD, 0x1C, 0x24, 0x6C, 0xB4, 0xC7, 0x52, 0xF6, 0x01)
263 RIJNDAEL_LOG_TABLE = (0x00, 0x00, 0x19, 0x01, 0x32, 0x02, 0x1a, 0xc6, 0x4b, 0xc7, 0x1b, 0x68, 0x33, 0xee, 0xdf, 0x03,
264                       0x64, 0x04, 0xe0, 0x0e, 0x34, 0x8d, 0x81, 0xef, 0x4c, 0x71, 0x08, 0xc8, 0xf8, 0x69, 0x1c, 0xc1,
265                       0x7d, 0xc2, 0x1d, 0xb5, 0xf9, 0xb9, 0x27, 0x6a, 0x4d, 0xe4, 0xa6, 0x72, 0x9a, 0xc9, 0x09, 0x78,
266                       0x65, 0x2f, 0x8a, 0x05, 0x21, 0x0f, 0xe1, 0x24, 0x12, 0xf0, 0x82, 0x45, 0x35, 0x93, 0xda, 0x8e,
267                       0x96, 0x8f, 0xdb, 0xbd, 0x36, 0xd0, 0xce, 0x94, 0x13, 0x5c, 0xd2, 0xf1, 0x40, 0x46, 0x83, 0x38,
268                       0x66, 0xdd, 0xfd, 0x30, 0xbf, 0x06, 0x8b, 0x62, 0xb3, 0x25, 0xe2, 0x98, 0x22, 0x88, 0x91, 0x10,
269                       0x7e, 0x6e, 0x48, 0xc3, 0xa3, 0xb6, 0x1e, 0x42, 0x3a, 0x6b, 0x28, 0x54, 0xfa, 0x85, 0x3d, 0xba,
270                       0x2b, 0x79, 0x0a, 0x15, 0x9b, 0x9f, 0x5e, 0xca, 0x4e, 0xd4, 0xac, 0xe5, 0xf3, 0x73, 0xa7, 0x57,
271                       0xaf, 0x58, 0xa8, 0x50, 0xf4, 0xea, 0xd6, 0x74, 0x4f, 0xae, 0xe9, 0xd5, 0xe7, 0xe6, 0xad, 0xe8,
272                       0x2c, 0xd7, 0x75, 0x7a, 0xeb, 0x16, 0x0b, 0xf5, 0x59, 0xcb, 0x5f, 0xb0, 0x9c, 0xa9, 0x51, 0xa0,
273                       0x7f, 0x0c, 0xf6, 0x6f, 0x17, 0xc4, 0x49, 0xec, 0xd8, 0x43, 0x1f, 0x2d, 0xa4, 0x76, 0x7b, 0xb7,
274                       0xcc, 0xbb, 0x3e, 0x5a, 0xfb, 0x60, 0xb1, 0x86, 0x3b, 0x52, 0xa1, 0x6c, 0xaa, 0x55, 0x29, 0x9d,
275                       0x97, 0xb2, 0x87, 0x90, 0x61, 0xbe, 0xdc, 0xfc, 0xbc, 0x95, 0xcf, 0xcd, 0x37, 0x3f, 0x5b, 0xd1,
276                       0x53, 0x39, 0x84, 0x3c, 0x41, 0xa2, 0x6d, 0x47, 0x14, 0x2a, 0x9e, 0x5d, 0x56, 0xf2, 0xd3, 0xab,
277                       0x44, 0x11, 0x92, 0xd9, 0x23, 0x20, 0x2e, 0x89, 0xb4, 0x7c, 0xb8, 0x26, 0x77, 0x99, 0xe3, 0xa5,
278                       0x67, 0x4a, 0xed, 0xde, 0xc5, 0x31, 0xfe, 0x18, 0x0d, 0x63, 0x8c, 0x80, 0xc0, 0xf7, 0x70, 0x07)
279
280
281 def sub_bytes(data):
282     return [SBOX[x] for x in data]
283
284
285 def sub_bytes_inv(data):
286     return [SBOX_INV[x] for x in data]
287
288
289 def rotate(data):
290     return data[1:] + [data[0]]
291
292
293 def key_schedule_core(data, rcon_iteration):
294     data = rotate(data)
295     data = sub_bytes(data)
296     data[0] = data[0] ^ RCON[rcon_iteration]
297
298     return data
299
300
301 def xor(data1, data2):
302     return [x ^ y for x, y in zip(data1, data2)]
303
304
305 def rijndael_mul(a, b):
306     if(a == 0 or b == 0):
307         return 0
308     return RIJNDAEL_EXP_TABLE[(RIJNDAEL_LOG_TABLE[a] + RIJNDAEL_LOG_TABLE[b]) % 0xFF]
309
310
311 def mix_column(data, matrix):
312     data_mixed = []
313     for row in range(4):
314         mixed = 0
315         for column in range(4):
316             # xor is (+) and (-)
317             mixed ^= rijndael_mul(data[column], matrix[row][column])
318         data_mixed.append(mixed)
319     return data_mixed
320
321
322 def mix_columns(data, matrix=MIX_COLUMN_MATRIX):
323     data_mixed = []
324     for i in range(4):
325         column = data[i * 4: (i + 1) * 4]
326         data_mixed += mix_column(column, matrix)
327     return data_mixed
328
329
330 def mix_columns_inv(data):
331     return mix_columns(data, MIX_COLUMN_MATRIX_INV)
332
333
334 def shift_rows(data):
335     data_shifted = []
336     for column in range(4):
337         for row in range(4):
338             data_shifted.append(data[((column + row) & 0b11) * 4 + row])
339     return data_shifted
340
341
342 def shift_rows_inv(data):
343     data_shifted = []
344     for column in range(4):
345         for row in range(4):
346             data_shifted.append(data[((column - row) & 0b11) * 4 + row])
347     return data_shifted
348
349
350 def inc(data):
351     data = data[:]  # copy
352     for i in range(len(data) - 1, -1, -1):
353         if data[i] == 255:
354             data[i] = 0
355         else:
356             data[i] = data[i] + 1
357             break
358     return data
359
360
361 __all__ = ['aes_encrypt', 'key_expansion', 'aes_ctr_decrypt', 'aes_cbc_decrypt', 'aes_decrypt_text']