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