]> Raphaƫl G. Git Repositories - youtubedl/blob - youtube_dl/aes.py
Start new release.
[youtubedl] / 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']