]> jfr.im git - yt-dlp.git/blob - yt_dlp/aes.py
[test:download] Raise on network errors (#10283)
[yt-dlp.git] / yt_dlp / aes.py
1 import base64
2 from math import ceil
3
4 from .compat import compat_ord
5 from .dependencies import Cryptodome
6 from .utils import bytes_to_intlist, intlist_to_bytes
7
8 if Cryptodome.AES:
9 def aes_cbc_decrypt_bytes(data, key, iv):
10 """ Decrypt bytes with AES-CBC using pycryptodome """
11 return Cryptodome.AES.new(key, Cryptodome.AES.MODE_CBC, iv).decrypt(data)
12
13 def aes_gcm_decrypt_and_verify_bytes(data, key, tag, nonce):
14 """ Decrypt bytes with AES-GCM using pycryptodome """
15 return Cryptodome.AES.new(key, Cryptodome.AES.MODE_GCM, nonce).decrypt_and_verify(data, tag)
16
17 else:
18 def aes_cbc_decrypt_bytes(data, key, iv):
19 """ Decrypt bytes with AES-CBC using native implementation since pycryptodome is unavailable """
20 return intlist_to_bytes(aes_cbc_decrypt(*map(bytes_to_intlist, (data, key, iv))))
21
22 def aes_gcm_decrypt_and_verify_bytes(data, key, tag, nonce):
23 """ Decrypt bytes with AES-GCM using native implementation since pycryptodome is unavailable """
24 return intlist_to_bytes(aes_gcm_decrypt_and_verify(*map(bytes_to_intlist, (data, key, tag, nonce))))
25
26
27 def aes_cbc_encrypt_bytes(data, key, iv, **kwargs):
28 return intlist_to_bytes(aes_cbc_encrypt(*map(bytes_to_intlist, (data, key, iv)), **kwargs))
29
30
31 BLOCK_SIZE_BYTES = 16
32
33
34 def unpad_pkcs7(data):
35 return data[:-compat_ord(data[-1])]
36
37
38 def pkcs7_padding(data):
39 """
40 PKCS#7 padding
41
42 @param {int[]} data cleartext
43 @returns {int[]} padding data
44 """
45
46 remaining_length = BLOCK_SIZE_BYTES - len(data) % BLOCK_SIZE_BYTES
47 return data + [remaining_length] * remaining_length
48
49
50 def pad_block(block, padding_mode):
51 """
52 Pad a block with the given padding mode
53 @param {int[]} block block to pad
54 @param padding_mode padding mode
55 """
56 padding_size = BLOCK_SIZE_BYTES - len(block)
57
58 PADDING_BYTE = {
59 'pkcs7': padding_size,
60 'iso7816': 0x0,
61 'whitespace': 0x20,
62 'zero': 0x0,
63 }
64
65 if padding_size < 0:
66 raise ValueError('Block size exceeded')
67 elif padding_mode not in PADDING_BYTE:
68 raise NotImplementedError(f'Padding mode {padding_mode} is not implemented')
69
70 if padding_mode == 'iso7816' and padding_size:
71 block = [*block, 0x80] # NB: += mutates list
72 padding_size -= 1
73
74 return block + [PADDING_BYTE[padding_mode]] * padding_size
75
76
77 def aes_ecb_encrypt(data, key, iv=None):
78 """
79 Encrypt with aes in ECB mode. Using PKCS#7 padding
80
81 @param {int[]} data cleartext
82 @param {int[]} key 16/24/32-Byte cipher key
83 @param {int[]} iv Unused for this mode
84 @returns {int[]} encrypted data
85 """
86 expanded_key = key_expansion(key)
87 block_count = int(ceil(float(len(data)) / BLOCK_SIZE_BYTES))
88
89 encrypted_data = []
90 for i in range(block_count):
91 block = data[i * BLOCK_SIZE_BYTES: (i + 1) * BLOCK_SIZE_BYTES]
92 encrypted_data += aes_encrypt(pkcs7_padding(block), expanded_key)
93
94 return encrypted_data
95
96
97 def aes_ecb_decrypt(data, key, iv=None):
98 """
99 Decrypt with aes in ECB mode
100
101 @param {int[]} data cleartext
102 @param {int[]} key 16/24/32-Byte cipher key
103 @param {int[]} iv Unused for this mode
104 @returns {int[]} decrypted data
105 """
106 expanded_key = key_expansion(key)
107 block_count = int(ceil(float(len(data)) / BLOCK_SIZE_BYTES))
108
109 encrypted_data = []
110 for i in range(block_count):
111 block = data[i * BLOCK_SIZE_BYTES: (i + 1) * BLOCK_SIZE_BYTES]
112 encrypted_data += aes_decrypt(block, expanded_key)
113 return encrypted_data[:len(data)]
114
115
116 def aes_ctr_decrypt(data, key, iv):
117 """
118 Decrypt with aes in counter mode
119
120 @param {int[]} data cipher
121 @param {int[]} key 16/24/32-Byte cipher key
122 @param {int[]} iv 16-Byte initialization vector
123 @returns {int[]} decrypted data
124 """
125 return aes_ctr_encrypt(data, key, iv)
126
127
128 def aes_ctr_encrypt(data, key, iv):
129 """
130 Encrypt with aes in counter mode
131
132 @param {int[]} data cleartext
133 @param {int[]} key 16/24/32-Byte cipher key
134 @param {int[]} iv 16-Byte initialization vector
135 @returns {int[]} encrypted data
136 """
137 expanded_key = key_expansion(key)
138 block_count = int(ceil(float(len(data)) / BLOCK_SIZE_BYTES))
139 counter = iter_vector(iv)
140
141 encrypted_data = []
142 for i in range(block_count):
143 counter_block = next(counter)
144 block = data[i * BLOCK_SIZE_BYTES: (i + 1) * BLOCK_SIZE_BYTES]
145 block += [0] * (BLOCK_SIZE_BYTES - len(block))
146
147 cipher_counter_block = aes_encrypt(counter_block, expanded_key)
148 encrypted_data += xor(block, cipher_counter_block)
149 return encrypted_data[:len(data)]
150
151
152 def aes_cbc_decrypt(data, key, iv):
153 """
154 Decrypt with aes in CBC mode
155
156 @param {int[]} data cipher
157 @param {int[]} key 16/24/32-Byte cipher key
158 @param {int[]} iv 16-Byte IV
159 @returns {int[]} decrypted data
160 """
161 expanded_key = key_expansion(key)
162 block_count = int(ceil(float(len(data)) / BLOCK_SIZE_BYTES))
163
164 decrypted_data = []
165 previous_cipher_block = iv
166 for i in range(block_count):
167 block = data[i * BLOCK_SIZE_BYTES: (i + 1) * BLOCK_SIZE_BYTES]
168 block += [0] * (BLOCK_SIZE_BYTES - len(block))
169
170 decrypted_block = aes_decrypt(block, expanded_key)
171 decrypted_data += xor(decrypted_block, previous_cipher_block)
172 previous_cipher_block = block
173 return decrypted_data[:len(data)]
174
175
176 def aes_cbc_encrypt(data, key, iv, *, padding_mode='pkcs7'):
177 """
178 Encrypt with aes in CBC mode
179
180 @param {int[]} data cleartext
181 @param {int[]} key 16/24/32-Byte cipher key
182 @param {int[]} iv 16-Byte IV
183 @param padding_mode Padding mode to use
184 @returns {int[]} encrypted data
185 """
186 expanded_key = key_expansion(key)
187 block_count = int(ceil(float(len(data)) / BLOCK_SIZE_BYTES))
188
189 encrypted_data = []
190 previous_cipher_block = iv
191 for i in range(block_count):
192 block = data[i * BLOCK_SIZE_BYTES: (i + 1) * BLOCK_SIZE_BYTES]
193 block = pad_block(block, padding_mode)
194
195 mixed_block = xor(block, previous_cipher_block)
196
197 encrypted_block = aes_encrypt(mixed_block, expanded_key)
198 encrypted_data += encrypted_block
199
200 previous_cipher_block = encrypted_block
201
202 return encrypted_data
203
204
205 def aes_gcm_decrypt_and_verify(data, key, tag, nonce):
206 """
207 Decrypt with aes in GBM mode and checks authenticity using tag
208
209 @param {int[]} data cipher
210 @param {int[]} key 16-Byte cipher key
211 @param {int[]} tag authentication tag
212 @param {int[]} nonce IV (recommended 12-Byte)
213 @returns {int[]} decrypted data
214 """
215
216 # XXX: check aes, gcm param
217
218 hash_subkey = aes_encrypt([0] * BLOCK_SIZE_BYTES, key_expansion(key))
219
220 if len(nonce) == 12:
221 j0 = [*nonce, 0, 0, 0, 1]
222 else:
223 fill = (BLOCK_SIZE_BYTES - (len(nonce) % BLOCK_SIZE_BYTES)) % BLOCK_SIZE_BYTES + 8
224 ghash_in = nonce + [0] * fill + bytes_to_intlist((8 * len(nonce)).to_bytes(8, 'big'))
225 j0 = ghash(hash_subkey, ghash_in)
226
227 # TODO: add nonce support to aes_ctr_decrypt
228
229 # nonce_ctr = j0[:12]
230 iv_ctr = inc(j0)
231
232 decrypted_data = aes_ctr_decrypt(data, key, iv_ctr + [0] * (BLOCK_SIZE_BYTES - len(iv_ctr)))
233 pad_len = len(data) // 16 * 16
234 s_tag = ghash(
235 hash_subkey,
236 data
237 + [0] * (BLOCK_SIZE_BYTES - len(data) + pad_len) # pad
238 + bytes_to_intlist((0 * 8).to_bytes(8, 'big') # length of associated data
239 + ((len(data) * 8).to_bytes(8, 'big'))), # length of data
240 )
241
242 if tag != aes_ctr_encrypt(s_tag, key, j0):
243 raise ValueError('Mismatching authentication tag')
244
245 return decrypted_data
246
247
248 def aes_encrypt(data, expanded_key):
249 """
250 Encrypt one block with aes
251
252 @param {int[]} data 16-Byte state
253 @param {int[]} expanded_key 176/208/240-Byte expanded key
254 @returns {int[]} 16-Byte cipher
255 """
256 rounds = len(expanded_key) // BLOCK_SIZE_BYTES - 1
257
258 data = xor(data, expanded_key[:BLOCK_SIZE_BYTES])
259 for i in range(1, rounds + 1):
260 data = sub_bytes(data)
261 data = shift_rows(data)
262 if i != rounds:
263 data = list(iter_mix_columns(data, MIX_COLUMN_MATRIX))
264 data = xor(data, expanded_key[i * BLOCK_SIZE_BYTES: (i + 1) * BLOCK_SIZE_BYTES])
265
266 return data
267
268
269 def aes_decrypt(data, expanded_key):
270 """
271 Decrypt one block with aes
272
273 @param {int[]} data 16-Byte cipher
274 @param {int[]} expanded_key 176/208/240-Byte expanded key
275 @returns {int[]} 16-Byte state
276 """
277 rounds = len(expanded_key) // BLOCK_SIZE_BYTES - 1
278
279 for i in range(rounds, 0, -1):
280 data = xor(data, expanded_key[i * BLOCK_SIZE_BYTES: (i + 1) * BLOCK_SIZE_BYTES])
281 if i != rounds:
282 data = list(iter_mix_columns(data, MIX_COLUMN_MATRIX_INV))
283 data = shift_rows_inv(data)
284 data = sub_bytes_inv(data)
285 return xor(data, expanded_key[:BLOCK_SIZE_BYTES])
286
287
288 def aes_decrypt_text(data, password, key_size_bytes):
289 """
290 Decrypt text
291 - The first 8 Bytes of decoded 'data' are the 8 high Bytes of the counter
292 - The cipher key is retrieved by encrypting the first 16 Byte of 'password'
293 with the first 'key_size_bytes' Bytes from 'password' (if necessary filled with 0's)
294 - Mode of operation is 'counter'
295
296 @param {str} data Base64 encoded string
297 @param {str,unicode} password Password (will be encoded with utf-8)
298 @param {int} key_size_bytes Possible values: 16 for 128-Bit, 24 for 192-Bit or 32 for 256-Bit
299 @returns {str} Decrypted data
300 """
301 NONCE_LENGTH_BYTES = 8
302
303 data = bytes_to_intlist(base64.b64decode(data))
304 password = bytes_to_intlist(password.encode())
305
306 key = password[:key_size_bytes] + [0] * (key_size_bytes - len(password))
307 key = aes_encrypt(key[:BLOCK_SIZE_BYTES], key_expansion(key)) * (key_size_bytes // BLOCK_SIZE_BYTES)
308
309 nonce = data[:NONCE_LENGTH_BYTES]
310 cipher = data[NONCE_LENGTH_BYTES:]
311
312 decrypted_data = aes_ctr_decrypt(cipher, key, nonce + [0] * (BLOCK_SIZE_BYTES - NONCE_LENGTH_BYTES))
313 return intlist_to_bytes(decrypted_data)
314
315
316 RCON = (0x8d, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36)
317 SBOX = (0x63, 0x7C, 0x77, 0x7B, 0xF2, 0x6B, 0x6F, 0xC5, 0x30, 0x01, 0x67, 0x2B, 0xFE, 0xD7, 0xAB, 0x76,
318 0xCA, 0x82, 0xC9, 0x7D, 0xFA, 0x59, 0x47, 0xF0, 0xAD, 0xD4, 0xA2, 0xAF, 0x9C, 0xA4, 0x72, 0xC0,
319 0xB7, 0xFD, 0x93, 0x26, 0x36, 0x3F, 0xF7, 0xCC, 0x34, 0xA5, 0xE5, 0xF1, 0x71, 0xD8, 0x31, 0x15,
320 0x04, 0xC7, 0x23, 0xC3, 0x18, 0x96, 0x05, 0x9A, 0x07, 0x12, 0x80, 0xE2, 0xEB, 0x27, 0xB2, 0x75,
321 0x09, 0x83, 0x2C, 0x1A, 0x1B, 0x6E, 0x5A, 0xA0, 0x52, 0x3B, 0xD6, 0xB3, 0x29, 0xE3, 0x2F, 0x84,
322 0x53, 0xD1, 0x00, 0xED, 0x20, 0xFC, 0xB1, 0x5B, 0x6A, 0xCB, 0xBE, 0x39, 0x4A, 0x4C, 0x58, 0xCF,
323 0xD0, 0xEF, 0xAA, 0xFB, 0x43, 0x4D, 0x33, 0x85, 0x45, 0xF9, 0x02, 0x7F, 0x50, 0x3C, 0x9F, 0xA8,
324 0x51, 0xA3, 0x40, 0x8F, 0x92, 0x9D, 0x38, 0xF5, 0xBC, 0xB6, 0xDA, 0x21, 0x10, 0xFF, 0xF3, 0xD2,
325 0xCD, 0x0C, 0x13, 0xEC, 0x5F, 0x97, 0x44, 0x17, 0xC4, 0xA7, 0x7E, 0x3D, 0x64, 0x5D, 0x19, 0x73,
326 0x60, 0x81, 0x4F, 0xDC, 0x22, 0x2A, 0x90, 0x88, 0x46, 0xEE, 0xB8, 0x14, 0xDE, 0x5E, 0x0B, 0xDB,
327 0xE0, 0x32, 0x3A, 0x0A, 0x49, 0x06, 0x24, 0x5C, 0xC2, 0xD3, 0xAC, 0x62, 0x91, 0x95, 0xE4, 0x79,
328 0xE7, 0xC8, 0x37, 0x6D, 0x8D, 0xD5, 0x4E, 0xA9, 0x6C, 0x56, 0xF4, 0xEA, 0x65, 0x7A, 0xAE, 0x08,
329 0xBA, 0x78, 0x25, 0x2E, 0x1C, 0xA6, 0xB4, 0xC6, 0xE8, 0xDD, 0x74, 0x1F, 0x4B, 0xBD, 0x8B, 0x8A,
330 0x70, 0x3E, 0xB5, 0x66, 0x48, 0x03, 0xF6, 0x0E, 0x61, 0x35, 0x57, 0xB9, 0x86, 0xC1, 0x1D, 0x9E,
331 0xE1, 0xF8, 0x98, 0x11, 0x69, 0xD9, 0x8E, 0x94, 0x9B, 0x1E, 0x87, 0xE9, 0xCE, 0x55, 0x28, 0xDF,
332 0x8C, 0xA1, 0x89, 0x0D, 0xBF, 0xE6, 0x42, 0x68, 0x41, 0x99, 0x2D, 0x0F, 0xB0, 0x54, 0xBB, 0x16)
333 SBOX_INV = (0x52, 0x09, 0x6a, 0xd5, 0x30, 0x36, 0xa5, 0x38, 0xbf, 0x40, 0xa3, 0x9e, 0x81, 0xf3, 0xd7, 0xfb,
334 0x7c, 0xe3, 0x39, 0x82, 0x9b, 0x2f, 0xff, 0x87, 0x34, 0x8e, 0x43, 0x44, 0xc4, 0xde, 0xe9, 0xcb,
335 0x54, 0x7b, 0x94, 0x32, 0xa6, 0xc2, 0x23, 0x3d, 0xee, 0x4c, 0x95, 0x0b, 0x42, 0xfa, 0xc3, 0x4e,
336 0x08, 0x2e, 0xa1, 0x66, 0x28, 0xd9, 0x24, 0xb2, 0x76, 0x5b, 0xa2, 0x49, 0x6d, 0x8b, 0xd1, 0x25,
337 0x72, 0xf8, 0xf6, 0x64, 0x86, 0x68, 0x98, 0x16, 0xd4, 0xa4, 0x5c, 0xcc, 0x5d, 0x65, 0xb6, 0x92,
338 0x6c, 0x70, 0x48, 0x50, 0xfd, 0xed, 0xb9, 0xda, 0x5e, 0x15, 0x46, 0x57, 0xa7, 0x8d, 0x9d, 0x84,
339 0x90, 0xd8, 0xab, 0x00, 0x8c, 0xbc, 0xd3, 0x0a, 0xf7, 0xe4, 0x58, 0x05, 0xb8, 0xb3, 0x45, 0x06,
340 0xd0, 0x2c, 0x1e, 0x8f, 0xca, 0x3f, 0x0f, 0x02, 0xc1, 0xaf, 0xbd, 0x03, 0x01, 0x13, 0x8a, 0x6b,
341 0x3a, 0x91, 0x11, 0x41, 0x4f, 0x67, 0xdc, 0xea, 0x97, 0xf2, 0xcf, 0xce, 0xf0, 0xb4, 0xe6, 0x73,
342 0x96, 0xac, 0x74, 0x22, 0xe7, 0xad, 0x35, 0x85, 0xe2, 0xf9, 0x37, 0xe8, 0x1c, 0x75, 0xdf, 0x6e,
343 0x47, 0xf1, 0x1a, 0x71, 0x1d, 0x29, 0xc5, 0x89, 0x6f, 0xb7, 0x62, 0x0e, 0xaa, 0x18, 0xbe, 0x1b,
344 0xfc, 0x56, 0x3e, 0x4b, 0xc6, 0xd2, 0x79, 0x20, 0x9a, 0xdb, 0xc0, 0xfe, 0x78, 0xcd, 0x5a, 0xf4,
345 0x1f, 0xdd, 0xa8, 0x33, 0x88, 0x07, 0xc7, 0x31, 0xb1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xec, 0x5f,
346 0x60, 0x51, 0x7f, 0xa9, 0x19, 0xb5, 0x4a, 0x0d, 0x2d, 0xe5, 0x7a, 0x9f, 0x93, 0xc9, 0x9c, 0xef,
347 0xa0, 0xe0, 0x3b, 0x4d, 0xae, 0x2a, 0xf5, 0xb0, 0xc8, 0xeb, 0xbb, 0x3c, 0x83, 0x53, 0x99, 0x61,
348 0x17, 0x2b, 0x04, 0x7e, 0xba, 0x77, 0xd6, 0x26, 0xe1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0c, 0x7d)
349 MIX_COLUMN_MATRIX = ((0x2, 0x3, 0x1, 0x1),
350 (0x1, 0x2, 0x3, 0x1),
351 (0x1, 0x1, 0x2, 0x3),
352 (0x3, 0x1, 0x1, 0x2))
353 MIX_COLUMN_MATRIX_INV = ((0xE, 0xB, 0xD, 0x9),
354 (0x9, 0xE, 0xB, 0xD),
355 (0xD, 0x9, 0xE, 0xB),
356 (0xB, 0xD, 0x9, 0xE))
357 RIJNDAEL_EXP_TABLE = (0x01, 0x03, 0x05, 0x0F, 0x11, 0x33, 0x55, 0xFF, 0x1A, 0x2E, 0x72, 0x96, 0xA1, 0xF8, 0x13, 0x35,
358 0x5F, 0xE1, 0x38, 0x48, 0xD8, 0x73, 0x95, 0xA4, 0xF7, 0x02, 0x06, 0x0A, 0x1E, 0x22, 0x66, 0xAA,
359 0xE5, 0x34, 0x5C, 0xE4, 0x37, 0x59, 0xEB, 0x26, 0x6A, 0xBE, 0xD9, 0x70, 0x90, 0xAB, 0xE6, 0x31,
360 0x53, 0xF5, 0x04, 0x0C, 0x14, 0x3C, 0x44, 0xCC, 0x4F, 0xD1, 0x68, 0xB8, 0xD3, 0x6E, 0xB2, 0xCD,
361 0x4C, 0xD4, 0x67, 0xA9, 0xE0, 0x3B, 0x4D, 0xD7, 0x62, 0xA6, 0xF1, 0x08, 0x18, 0x28, 0x78, 0x88,
362 0x83, 0x9E, 0xB9, 0xD0, 0x6B, 0xBD, 0xDC, 0x7F, 0x81, 0x98, 0xB3, 0xCE, 0x49, 0xDB, 0x76, 0x9A,
363 0xB5, 0xC4, 0x57, 0xF9, 0x10, 0x30, 0x50, 0xF0, 0x0B, 0x1D, 0x27, 0x69, 0xBB, 0xD6, 0x61, 0xA3,
364 0xFE, 0x19, 0x2B, 0x7D, 0x87, 0x92, 0xAD, 0xEC, 0x2F, 0x71, 0x93, 0xAE, 0xE9, 0x20, 0x60, 0xA0,
365 0xFB, 0x16, 0x3A, 0x4E, 0xD2, 0x6D, 0xB7, 0xC2, 0x5D, 0xE7, 0x32, 0x56, 0xFA, 0x15, 0x3F, 0x41,
366 0xC3, 0x5E, 0xE2, 0x3D, 0x47, 0xC9, 0x40, 0xC0, 0x5B, 0xED, 0x2C, 0x74, 0x9C, 0xBF, 0xDA, 0x75,
367 0x9F, 0xBA, 0xD5, 0x64, 0xAC, 0xEF, 0x2A, 0x7E, 0x82, 0x9D, 0xBC, 0xDF, 0x7A, 0x8E, 0x89, 0x80,
368 0x9B, 0xB6, 0xC1, 0x58, 0xE8, 0x23, 0x65, 0xAF, 0xEA, 0x25, 0x6F, 0xB1, 0xC8, 0x43, 0xC5, 0x54,
369 0xFC, 0x1F, 0x21, 0x63, 0xA5, 0xF4, 0x07, 0x09, 0x1B, 0x2D, 0x77, 0x99, 0xB0, 0xCB, 0x46, 0xCA,
370 0x45, 0xCF, 0x4A, 0xDE, 0x79, 0x8B, 0x86, 0x91, 0xA8, 0xE3, 0x3E, 0x42, 0xC6, 0x51, 0xF3, 0x0E,
371 0x12, 0x36, 0x5A, 0xEE, 0x29, 0x7B, 0x8D, 0x8C, 0x8F, 0x8A, 0x85, 0x94, 0xA7, 0xF2, 0x0D, 0x17,
372 0x39, 0x4B, 0xDD, 0x7C, 0x84, 0x97, 0xA2, 0xFD, 0x1C, 0x24, 0x6C, 0xB4, 0xC7, 0x52, 0xF6, 0x01)
373 RIJNDAEL_LOG_TABLE = (0x00, 0x00, 0x19, 0x01, 0x32, 0x02, 0x1a, 0xc6, 0x4b, 0xc7, 0x1b, 0x68, 0x33, 0xee, 0xdf, 0x03,
374 0x64, 0x04, 0xe0, 0x0e, 0x34, 0x8d, 0x81, 0xef, 0x4c, 0x71, 0x08, 0xc8, 0xf8, 0x69, 0x1c, 0xc1,
375 0x7d, 0xc2, 0x1d, 0xb5, 0xf9, 0xb9, 0x27, 0x6a, 0x4d, 0xe4, 0xa6, 0x72, 0x9a, 0xc9, 0x09, 0x78,
376 0x65, 0x2f, 0x8a, 0x05, 0x21, 0x0f, 0xe1, 0x24, 0x12, 0xf0, 0x82, 0x45, 0x35, 0x93, 0xda, 0x8e,
377 0x96, 0x8f, 0xdb, 0xbd, 0x36, 0xd0, 0xce, 0x94, 0x13, 0x5c, 0xd2, 0xf1, 0x40, 0x46, 0x83, 0x38,
378 0x66, 0xdd, 0xfd, 0x30, 0xbf, 0x06, 0x8b, 0x62, 0xb3, 0x25, 0xe2, 0x98, 0x22, 0x88, 0x91, 0x10,
379 0x7e, 0x6e, 0x48, 0xc3, 0xa3, 0xb6, 0x1e, 0x42, 0x3a, 0x6b, 0x28, 0x54, 0xfa, 0x85, 0x3d, 0xba,
380 0x2b, 0x79, 0x0a, 0x15, 0x9b, 0x9f, 0x5e, 0xca, 0x4e, 0xd4, 0xac, 0xe5, 0xf3, 0x73, 0xa7, 0x57,
381 0xaf, 0x58, 0xa8, 0x50, 0xf4, 0xea, 0xd6, 0x74, 0x4f, 0xae, 0xe9, 0xd5, 0xe7, 0xe6, 0xad, 0xe8,
382 0x2c, 0xd7, 0x75, 0x7a, 0xeb, 0x16, 0x0b, 0xf5, 0x59, 0xcb, 0x5f, 0xb0, 0x9c, 0xa9, 0x51, 0xa0,
383 0x7f, 0x0c, 0xf6, 0x6f, 0x17, 0xc4, 0x49, 0xec, 0xd8, 0x43, 0x1f, 0x2d, 0xa4, 0x76, 0x7b, 0xb7,
384 0xcc, 0xbb, 0x3e, 0x5a, 0xfb, 0x60, 0xb1, 0x86, 0x3b, 0x52, 0xa1, 0x6c, 0xaa, 0x55, 0x29, 0x9d,
385 0x97, 0xb2, 0x87, 0x90, 0x61, 0xbe, 0xdc, 0xfc, 0xbc, 0x95, 0xcf, 0xcd, 0x37, 0x3f, 0x5b, 0xd1,
386 0x53, 0x39, 0x84, 0x3c, 0x41, 0xa2, 0x6d, 0x47, 0x14, 0x2a, 0x9e, 0x5d, 0x56, 0xf2, 0xd3, 0xab,
387 0x44, 0x11, 0x92, 0xd9, 0x23, 0x20, 0x2e, 0x89, 0xb4, 0x7c, 0xb8, 0x26, 0x77, 0x99, 0xe3, 0xa5,
388 0x67, 0x4a, 0xed, 0xde, 0xc5, 0x31, 0xfe, 0x18, 0x0d, 0x63, 0x8c, 0x80, 0xc0, 0xf7, 0x70, 0x07)
389
390
391 def key_expansion(data):
392 """
393 Generate key schedule
394
395 @param {int[]} data 16/24/32-Byte cipher key
396 @returns {int[]} 176/208/240-Byte expanded key
397 """
398 data = data[:] # copy
399 rcon_iteration = 1
400 key_size_bytes = len(data)
401 expanded_key_size_bytes = (key_size_bytes // 4 + 7) * BLOCK_SIZE_BYTES
402
403 while len(data) < expanded_key_size_bytes:
404 temp = data[-4:]
405 temp = key_schedule_core(temp, rcon_iteration)
406 rcon_iteration += 1
407 data += xor(temp, data[-key_size_bytes: 4 - key_size_bytes])
408
409 for _ in range(3):
410 temp = data[-4:]
411 data += xor(temp, data[-key_size_bytes: 4 - key_size_bytes])
412
413 if key_size_bytes == 32:
414 temp = data[-4:]
415 temp = sub_bytes(temp)
416 data += xor(temp, data[-key_size_bytes: 4 - key_size_bytes])
417
418 for _ in range(3 if key_size_bytes == 32 else 2 if key_size_bytes == 24 else 0):
419 temp = data[-4:]
420 data += xor(temp, data[-key_size_bytes: 4 - key_size_bytes])
421 return data[:expanded_key_size_bytes]
422
423
424 def iter_vector(iv):
425 while True:
426 yield iv
427 iv = inc(iv)
428
429
430 def sub_bytes(data):
431 return [SBOX[x] for x in data]
432
433
434 def sub_bytes_inv(data):
435 return [SBOX_INV[x] for x in data]
436
437
438 def rotate(data):
439 return data[1:] + [data[0]]
440
441
442 def key_schedule_core(data, rcon_iteration):
443 data = rotate(data)
444 data = sub_bytes(data)
445 data[0] = data[0] ^ RCON[rcon_iteration]
446
447 return data
448
449
450 def xor(data1, data2):
451 return [x ^ y for x, y in zip(data1, data2)]
452
453
454 def iter_mix_columns(data, matrix):
455 for i in (0, 4, 8, 12):
456 for row in matrix:
457 mixed = 0
458 for j in range(4):
459 # xor is (+) and (-)
460 mixed ^= (0 if data[i:i + 4][j] == 0 or row[j] == 0 else
461 RIJNDAEL_EXP_TABLE[(RIJNDAEL_LOG_TABLE[data[i + j]] + RIJNDAEL_LOG_TABLE[row[j]]) % 0xFF])
462 yield mixed
463
464
465 def shift_rows(data):
466 return [data[((column + row) & 0b11) * 4 + row] for column in range(4) for row in range(4)]
467
468
469 def shift_rows_inv(data):
470 return [data[((column - row) & 0b11) * 4 + row] for column in range(4) for row in range(4)]
471
472
473 def shift_block(data):
474 data_shifted = []
475
476 bit = 0
477 for n in data:
478 if bit:
479 n |= 0x100
480 bit = n & 1
481 n >>= 1
482 data_shifted.append(n)
483
484 return data_shifted
485
486
487 def inc(data):
488 data = data[:] # copy
489 for i in range(len(data) - 1, -1, -1):
490 if data[i] == 255:
491 data[i] = 0
492 else:
493 data[i] = data[i] + 1
494 break
495 return data
496
497
498 def block_product(block_x, block_y):
499 # NIST SP 800-38D, Algorithm 1
500
501 if len(block_x) != BLOCK_SIZE_BYTES or len(block_y) != BLOCK_SIZE_BYTES:
502 raise ValueError(f'Length of blocks need to be {BLOCK_SIZE_BYTES} bytes')
503
504 block_r = [0xE1] + [0] * (BLOCK_SIZE_BYTES - 1)
505 block_v = block_y[:]
506 block_z = [0] * BLOCK_SIZE_BYTES
507
508 for i in block_x:
509 for bit in range(7, -1, -1):
510 if i & (1 << bit):
511 block_z = xor(block_z, block_v)
512
513 do_xor = block_v[-1] & 1
514 block_v = shift_block(block_v)
515 if do_xor:
516 block_v = xor(block_v, block_r)
517
518 return block_z
519
520
521 def ghash(subkey, data):
522 # NIST SP 800-38D, Algorithm 2
523
524 if len(data) % BLOCK_SIZE_BYTES:
525 raise ValueError(f'Length of data should be {BLOCK_SIZE_BYTES} bytes')
526
527 last_y = [0] * BLOCK_SIZE_BYTES
528 for i in range(0, len(data), BLOCK_SIZE_BYTES):
529 block = data[i: i + BLOCK_SIZE_BYTES]
530 last_y = block_product(xor(last_y, block), subkey)
531
532 return last_y
533
534
535 __all__ = [
536 'aes_cbc_decrypt',
537 'aes_cbc_decrypt_bytes',
538 'aes_ctr_decrypt',
539 'aes_decrypt_text',
540 'aes_decrypt',
541 'aes_ecb_decrypt',
542 'aes_gcm_decrypt_and_verify',
543 'aes_gcm_decrypt_and_verify_bytes',
544
545 'aes_cbc_encrypt',
546 'aes_cbc_encrypt_bytes',
547 'aes_ctr_encrypt',
548 'aes_ecb_encrypt',
549 'aes_encrypt',
550
551 'key_expansion',
552 'pad_block',
553 'pkcs7_padding',
554 'unpad_pkcs7',
555 ]