]> jfr.im git - yt-dlp.git/blob - yt_dlp/aes.py
[embedthumbnail] Fix thumbnail name in mp3 (#5163)
[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_AES
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 def unpad_pkcs7(data):
32 return data[:-compat_ord(data[-1])]
33
34
35 BLOCK_SIZE_BYTES = 16
36
37
38 def pad_block(block, padding_mode):
39 """
40 Pad a block with the given padding mode
41 @param {int[]} block block to pad
42 @param padding_mode padding mode
43 """
44 padding_size = BLOCK_SIZE_BYTES - len(block)
45
46 PADDING_BYTE = {
47 'pkcs7': padding_size,
48 'iso7816': 0x0,
49 'whitespace': 0x20,
50 'zero': 0x0,
51 }
52
53 if padding_size < 0:
54 raise ValueError('Block size exceeded')
55 elif padding_mode not in PADDING_BYTE:
56 raise NotImplementedError(f'Padding mode {padding_mode} is not implemented')
57
58 if padding_mode == 'iso7816' and padding_size:
59 block = block + [0x80] # NB: += mutates list
60 padding_size -= 1
61
62 return block + [PADDING_BYTE[padding_mode]] * padding_size
63
64
65 def aes_ecb_encrypt(data, key, iv=None):
66 """
67 Encrypt with aes in ECB mode
68
69 @param {int[]} data cleartext
70 @param {int[]} key 16/24/32-Byte cipher key
71 @param {int[]} iv Unused for this mode
72 @returns {int[]} encrypted data
73 """
74 expanded_key = key_expansion(key)
75 block_count = int(ceil(float(len(data)) / BLOCK_SIZE_BYTES))
76
77 encrypted_data = []
78 for i in range(block_count):
79 block = data[i * BLOCK_SIZE_BYTES: (i + 1) * BLOCK_SIZE_BYTES]
80 encrypted_data += aes_encrypt(block, expanded_key)
81 encrypted_data = encrypted_data[:len(data)]
82
83 return encrypted_data
84
85
86 def aes_ecb_decrypt(data, key, iv=None):
87 """
88 Decrypt with aes in ECB mode
89
90 @param {int[]} data cleartext
91 @param {int[]} key 16/24/32-Byte cipher key
92 @param {int[]} iv Unused for this mode
93 @returns {int[]} decrypted data
94 """
95 expanded_key = key_expansion(key)
96 block_count = int(ceil(float(len(data)) / BLOCK_SIZE_BYTES))
97
98 encrypted_data = []
99 for i in range(block_count):
100 block = data[i * BLOCK_SIZE_BYTES: (i + 1) * BLOCK_SIZE_BYTES]
101 encrypted_data += aes_decrypt(block, expanded_key)
102 encrypted_data = encrypted_data[:len(data)]
103
104 return encrypted_data
105
106
107 def aes_ctr_decrypt(data, key, iv):
108 """
109 Decrypt with aes in counter mode
110
111 @param {int[]} data cipher
112 @param {int[]} key 16/24/32-Byte cipher key
113 @param {int[]} iv 16-Byte initialization vector
114 @returns {int[]} decrypted data
115 """
116 return aes_ctr_encrypt(data, key, iv)
117
118
119 def aes_ctr_encrypt(data, key, iv):
120 """
121 Encrypt with aes in counter mode
122
123 @param {int[]} data cleartext
124 @param {int[]} key 16/24/32-Byte cipher key
125 @param {int[]} iv 16-Byte initialization vector
126 @returns {int[]} encrypted data
127 """
128 expanded_key = key_expansion(key)
129 block_count = int(ceil(float(len(data)) / BLOCK_SIZE_BYTES))
130 counter = iter_vector(iv)
131
132 encrypted_data = []
133 for i in range(block_count):
134 counter_block = next(counter)
135 block = data[i * BLOCK_SIZE_BYTES: (i + 1) * BLOCK_SIZE_BYTES]
136 block += [0] * (BLOCK_SIZE_BYTES - len(block))
137
138 cipher_counter_block = aes_encrypt(counter_block, expanded_key)
139 encrypted_data += xor(block, cipher_counter_block)
140 encrypted_data = encrypted_data[:len(data)]
141
142 return encrypted_data
143
144
145 def aes_cbc_decrypt(data, key, iv):
146 """
147 Decrypt with aes in CBC mode
148
149 @param {int[]} data cipher
150 @param {int[]} key 16/24/32-Byte cipher key
151 @param {int[]} iv 16-Byte IV
152 @returns {int[]} decrypted data
153 """
154 expanded_key = key_expansion(key)
155 block_count = int(ceil(float(len(data)) / BLOCK_SIZE_BYTES))
156
157 decrypted_data = []
158 previous_cipher_block = iv
159 for i in range(block_count):
160 block = data[i * BLOCK_SIZE_BYTES: (i + 1) * BLOCK_SIZE_BYTES]
161 block += [0] * (BLOCK_SIZE_BYTES - len(block))
162
163 decrypted_block = aes_decrypt(block, expanded_key)
164 decrypted_data += xor(decrypted_block, previous_cipher_block)
165 previous_cipher_block = block
166 decrypted_data = decrypted_data[:len(data)]
167
168 return decrypted_data
169
170
171 def aes_cbc_encrypt(data, key, iv, *, padding_mode='pkcs7'):
172 """
173 Encrypt with aes in CBC mode
174
175 @param {int[]} data cleartext
176 @param {int[]} key 16/24/32-Byte cipher key
177 @param {int[]} iv 16-Byte IV
178 @param padding_mode Padding mode to use
179 @returns {int[]} encrypted data
180 """
181 expanded_key = key_expansion(key)
182 block_count = int(ceil(float(len(data)) / BLOCK_SIZE_BYTES))
183
184 encrypted_data = []
185 previous_cipher_block = iv
186 for i in range(block_count):
187 block = data[i * BLOCK_SIZE_BYTES: (i + 1) * BLOCK_SIZE_BYTES]
188 block = pad_block(block, padding_mode)
189
190 mixed_block = xor(block, previous_cipher_block)
191
192 encrypted_block = aes_encrypt(mixed_block, expanded_key)
193 encrypted_data += encrypted_block
194
195 previous_cipher_block = encrypted_block
196
197 return encrypted_data
198
199
200 def aes_gcm_decrypt_and_verify(data, key, tag, nonce):
201 """
202 Decrypt with aes in GBM mode and checks authenticity using tag
203
204 @param {int[]} data cipher
205 @param {int[]} key 16-Byte cipher key
206 @param {int[]} tag authentication tag
207 @param {int[]} nonce IV (recommended 12-Byte)
208 @returns {int[]} decrypted data
209 """
210
211 # XXX: check aes, gcm param
212
213 hash_subkey = aes_encrypt([0] * BLOCK_SIZE_BYTES, key_expansion(key))
214
215 if len(nonce) == 12:
216 j0 = nonce + [0, 0, 0, 1]
217 else:
218 fill = (BLOCK_SIZE_BYTES - (len(nonce) % BLOCK_SIZE_BYTES)) % BLOCK_SIZE_BYTES + 8
219 ghash_in = nonce + [0] * fill + bytes_to_intlist((8 * len(nonce)).to_bytes(8, 'big'))
220 j0 = ghash(hash_subkey, ghash_in)
221
222 # TODO: add nonce support to aes_ctr_decrypt
223
224 # nonce_ctr = j0[:12]
225 iv_ctr = inc(j0)
226
227 decrypted_data = aes_ctr_decrypt(data, key, iv_ctr + [0] * (BLOCK_SIZE_BYTES - len(iv_ctr)))
228 pad_len = len(data) // 16 * 16
229 s_tag = ghash(
230 hash_subkey,
231 data
232 + [0] * (BLOCK_SIZE_BYTES - len(data) + pad_len) # pad
233 + bytes_to_intlist((0 * 8).to_bytes(8, 'big') # length of associated data
234 + ((len(data) * 8).to_bytes(8, 'big'))) # length of data
235 )
236
237 if tag != aes_ctr_encrypt(s_tag, key, j0):
238 raise ValueError("Mismatching authentication tag")
239
240 return decrypted_data
241
242
243 def aes_encrypt(data, expanded_key):
244 """
245 Encrypt one block with aes
246
247 @param {int[]} data 16-Byte state
248 @param {int[]} expanded_key 176/208/240-Byte expanded key
249 @returns {int[]} 16-Byte cipher
250 """
251 rounds = len(expanded_key) // BLOCK_SIZE_BYTES - 1
252
253 data = xor(data, expanded_key[:BLOCK_SIZE_BYTES])
254 for i in range(1, rounds + 1):
255 data = sub_bytes(data)
256 data = shift_rows(data)
257 if i != rounds:
258 data = list(iter_mix_columns(data, MIX_COLUMN_MATRIX))
259 data = xor(data, expanded_key[i * BLOCK_SIZE_BYTES: (i + 1) * BLOCK_SIZE_BYTES])
260
261 return data
262
263
264 def aes_decrypt(data, expanded_key):
265 """
266 Decrypt one block with aes
267
268 @param {int[]} data 16-Byte cipher
269 @param {int[]} expanded_key 176/208/240-Byte expanded key
270 @returns {int[]} 16-Byte state
271 """
272 rounds = len(expanded_key) // BLOCK_SIZE_BYTES - 1
273
274 for i in range(rounds, 0, -1):
275 data = xor(data, expanded_key[i * BLOCK_SIZE_BYTES: (i + 1) * BLOCK_SIZE_BYTES])
276 if i != rounds:
277 data = list(iter_mix_columns(data, MIX_COLUMN_MATRIX_INV))
278 data = shift_rows_inv(data)
279 data = sub_bytes_inv(data)
280 data = xor(data, expanded_key[:BLOCK_SIZE_BYTES])
281
282 return data
283
284
285 def aes_decrypt_text(data, password, key_size_bytes):
286 """
287 Decrypt text
288 - The first 8 Bytes of decoded 'data' are the 8 high Bytes of the counter
289 - The cipher key is retrieved by encrypting the first 16 Byte of 'password'
290 with the first 'key_size_bytes' Bytes from 'password' (if necessary filled with 0's)
291 - Mode of operation is 'counter'
292
293 @param {str} data Base64 encoded string
294 @param {str,unicode} password Password (will be encoded with utf-8)
295 @param {int} key_size_bytes Possible values: 16 for 128-Bit, 24 for 192-Bit or 32 for 256-Bit
296 @returns {str} Decrypted data
297 """
298 NONCE_LENGTH_BYTES = 8
299
300 data = bytes_to_intlist(base64.b64decode(data))
301 password = bytes_to_intlist(password.encode())
302
303 key = password[:key_size_bytes] + [0] * (key_size_bytes - len(password))
304 key = aes_encrypt(key[:BLOCK_SIZE_BYTES], key_expansion(key)) * (key_size_bytes // BLOCK_SIZE_BYTES)
305
306 nonce = data[:NONCE_LENGTH_BYTES]
307 cipher = data[NONCE_LENGTH_BYTES:]
308
309 decrypted_data = aes_ctr_decrypt(cipher, key, nonce + [0] * (BLOCK_SIZE_BYTES - NONCE_LENGTH_BYTES))
310 plaintext = intlist_to_bytes(decrypted_data)
311
312 return plaintext
313
314
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)
388
389
390 def key_expansion(data):
391 """
392 Generate key schedule
393
394 @param {int[]} data 16/24/32-Byte cipher key
395 @returns {int[]} 176/208/240-Byte expanded key
396 """
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
401
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])
407
408 for _ in range(3):
409 temp = data[-4:]
410 data += xor(temp, data[-key_size_bytes: 4 - key_size_bytes])
411
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])
416
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 data = data[:expanded_key_size_bytes]
421
422 return data
423
424
425 def iter_vector(iv):
426 while True:
427 yield iv
428 iv = inc(iv)
429
430
431 def sub_bytes(data):
432 return [SBOX[x] for x in data]
433
434
435 def sub_bytes_inv(data):
436 return [SBOX_INV[x] for x in data]
437
438
439 def rotate(data):
440 return data[1:] + [data[0]]
441
442
443 def key_schedule_core(data, rcon_iteration):
444 data = rotate(data)
445 data = sub_bytes(data)
446 data[0] = data[0] ^ RCON[rcon_iteration]
447
448 return data
449
450
451 def xor(data1, data2):
452 return [x ^ y for x, y in zip(data1, data2)]
453
454
455 def iter_mix_columns(data, matrix):
456 for i in (0, 4, 8, 12):
457 for row in matrix:
458 mixed = 0
459 for j in range(4):
460 # xor is (+) and (-)
461 mixed ^= (0 if data[i:i + 4][j] == 0 or row[j] == 0 else
462 RIJNDAEL_EXP_TABLE[(RIJNDAEL_LOG_TABLE[data[i + j]] + RIJNDAEL_LOG_TABLE[row[j]]) % 0xFF])
463 yield mixed
464
465
466 def shift_rows(data):
467 return [data[((column + row) & 0b11) * 4 + row] for column in range(4) for row in range(4)]
468
469
470 def shift_rows_inv(data):
471 return [data[((column - row) & 0b11) * 4 + row] for column in range(4) for row in range(4)]
472
473
474 def shift_block(data):
475 data_shifted = []
476
477 bit = 0
478 for n in data:
479 if bit:
480 n |= 0x100
481 bit = n & 1
482 n >>= 1
483 data_shifted.append(n)
484
485 return data_shifted
486
487
488 def inc(data):
489 data = data[:] # copy
490 for i in range(len(data) - 1, -1, -1):
491 if data[i] == 255:
492 data[i] = 0
493 else:
494 data[i] = data[i] + 1
495 break
496 return data
497
498
499 def block_product(block_x, block_y):
500 # NIST SP 800-38D, Algorithm 1
501
502 if len(block_x) != BLOCK_SIZE_BYTES or len(block_y) != BLOCK_SIZE_BYTES:
503 raise ValueError("Length of blocks need to be %d bytes" % BLOCK_SIZE_BYTES)
504
505 block_r = [0xE1] + [0] * (BLOCK_SIZE_BYTES - 1)
506 block_v = block_y[:]
507 block_z = [0] * BLOCK_SIZE_BYTES
508
509 for i in block_x:
510 for bit in range(7, -1, -1):
511 if i & (1 << bit):
512 block_z = xor(block_z, block_v)
513
514 do_xor = block_v[-1] & 1
515 block_v = shift_block(block_v)
516 if do_xor:
517 block_v = xor(block_v, block_r)
518
519 return block_z
520
521
522 def ghash(subkey, data):
523 # NIST SP 800-38D, Algorithm 2
524
525 if len(data) % BLOCK_SIZE_BYTES:
526 raise ValueError("Length of data should be %d bytes" % BLOCK_SIZE_BYTES)
527
528 last_y = [0] * BLOCK_SIZE_BYTES
529 for i in range(0, len(data), BLOCK_SIZE_BYTES):
530 block = data[i: i + BLOCK_SIZE_BYTES]
531 last_y = block_product(xor(last_y, block), subkey)
532
533 return last_y
534
535
536 __all__ = [
537 'aes_cbc_decrypt',
538 'aes_cbc_decrypt_bytes',
539 'aes_ctr_decrypt',
540 'aes_decrypt_text',
541 'aes_decrypt',
542 'aes_ecb_decrypt',
543 'aes_gcm_decrypt_and_verify',
544 'aes_gcm_decrypt_and_verify_bytes',
545
546 'aes_cbc_encrypt',
547 'aes_cbc_encrypt_bytes',
548 'aes_ctr_encrypt',
549 'aes_ecb_encrypt',
550 'aes_encrypt',
551
552 'key_expansion',
553 'pad_block',
554 'unpad_pkcs7',
555 ]