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