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