]> jfr.im git - yt-dlp.git/blob - yt_dlp/aes.py
[aes] Add unpad_pkcs7
[yt-dlp.git] / yt_dlp / aes.py
1 from __future__ import unicode_literals
2
3 from math import ceil
4
5 from .compat import (
6 compat_b64decode,
7 compat_ord,
8 compat_pycrypto_AES,
9 )
10 from .utils import (
11 bytes_to_intlist,
12 intlist_to_bytes,
13 )
14
15
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)
20
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)
24
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))))
29
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))))
33
34
35 def unpad_pkcs7(data):
36 return data[:-compat_ord(data[-1])]
37
38
39 BLOCK_SIZE_BYTES = 16
40
41
42 def aes_ecb_encrypt(data, key, iv=None):
43 """
44 Encrypt with aes in ECB mode
45
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))
53
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)]
59
60 return encrypted_data
61
62
63 def aes_ecb_decrypt(data, key, iv=None):
64 """
65 Decrypt with aes in ECB mode
66
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))
74
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)]
80
81 return encrypted_data
82
83
84 def aes_ctr_decrypt(data, key, iv):
85 """
86 Decrypt with aes in counter mode
87
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)
94
95
96 def aes_ctr_encrypt(data, key, iv):
97 """
98 Encrypt with aes in counter mode
99
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
104 """
105 expanded_key = key_expansion(key)
106 block_count = int(ceil(float(len(data)) / BLOCK_SIZE_BYTES))
107 counter = iter_vector(iv)
108
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))
114
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)]
118
119 return encrypted_data
120
121
122 def aes_cbc_decrypt(data, key, iv):
123 """
124 Decrypt with aes in CBC mode
125
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
130 """
131 expanded_key = key_expansion(key)
132 block_count = int(ceil(float(len(data)) / BLOCK_SIZE_BYTES))
133
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))
139
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)]
144
145 return decrypted_data
146
147
148 def aes_cbc_encrypt(data, key, iv):
149 """
150 Encrypt with aes in CBC mode. Using PKCS#7 padding
151
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
156 """
157 expanded_key = key_expansion(key)
158 block_count = int(ceil(float(len(data)) / BLOCK_SIZE_BYTES))
159
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)
167
168 encrypted_block = aes_encrypt(mixed_block, expanded_key)
169 encrypted_data += encrypted_block
170
171 previous_cipher_block = encrypted_block
172
173 return encrypted_data
174
175
176 def aes_gcm_decrypt_and_verify(data, key, tag, nonce):
177 """
178 Decrypt with aes in GBM mode and checks authenticity using tag
179
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
185 """
186
187 # XXX: check aes, gcm param
188
189 hash_subkey = aes_encrypt([0] * BLOCK_SIZE_BYTES, key_expansion(key))
190
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)
197
198 # TODO: add nonce support to aes_ctr_decrypt
199
200 # nonce_ctr = j0[:12]
201 iv_ctr = inc(j0)
202
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
211 )
212
213 if tag != aes_ctr_encrypt(s_tag, key, j0):
214 raise ValueError("Mismatching authentication tag")
215
216 return decrypted_data
217
218
219 def aes_encrypt(data, expanded_key):
220 """
221 Encrypt one block with aes
222
223 @param {int[]} data 16-Byte state
224 @param {int[]} expanded_key 176/208/240-Byte expanded key
225 @returns {int[]} 16-Byte cipher
226 """
227 rounds = len(expanded_key) // BLOCK_SIZE_BYTES - 1
228
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])
236
237 return data
238
239
240 def aes_decrypt(data, expanded_key):
241 """
242 Decrypt one block with aes
243
244 @param {int[]} data 16-Byte cipher
245 @param {int[]} expanded_key 176/208/240-Byte expanded key
246 @returns {int[]} 16-Byte state
247 """
248 rounds = len(expanded_key) // BLOCK_SIZE_BYTES - 1
249
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])
257
258 return data
259
260
261 def aes_decrypt_text(data, password, key_size_bytes):
262 """
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'
268
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
273 """
274 NONCE_LENGTH_BYTES = 8
275
276 data = bytes_to_intlist(compat_b64decode(data))
277 password = bytes_to_intlist(password.encode('utf-8'))
278
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)
281
282 nonce = data[:NONCE_LENGTH_BYTES]
283 cipher = data[NONCE_LENGTH_BYTES:]
284
285 decrypted_data = aes_ctr_decrypt(cipher, key, nonce + [0] * (BLOCK_SIZE_BYTES - NONCE_LENGTH_BYTES))
286 plaintext = intlist_to_bytes(decrypted_data)
287
288 return plaintext
289
290
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)
364
365
366 def key_expansion(data):
367 """
368 Generate key schedule
369
370 @param {int[]} data 16/24/32-Byte cipher key
371 @returns {int[]} 176/208/240-Byte expanded key
372 """
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
377
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])
383
384 for _ in range(3):
385 temp = data[-4:]
386 data += xor(temp, data[-key_size_bytes: 4 - key_size_bytes])
387
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])
392
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]
397
398 return data
399
400
401 def iter_vector(iv):
402 while True:
403 yield iv
404 iv = inc(iv)
405
406
407 def sub_bytes(data):
408 return [SBOX[x] for x in data]
409
410
411 def sub_bytes_inv(data):
412 return [SBOX_INV[x] for x in data]
413
414
415 def rotate(data):
416 return data[1:] + [data[0]]
417
418
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]
423
424 return data
425
426
427 def xor(data1, data2):
428 return [x ^ y for x, y in zip(data1, data2)]
429
430
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
440
441
442 def shift_rows(data):
443 return [data[((column + row) & 0b11) * 4 + row] for column in range(4) for row in range(4)]
444
445
446 def shift_rows_inv(data):
447 return [data[((column - row) & 0b11) * 4 + row] for column in range(4) for row in range(4)]
448
449
450 def shift_block(data):
451 data_shifted = []
452
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)
460
461 return data_shifted
462
463
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
473
474
475 def block_product(block_x, block_y):
476 # NIST SP 800-38D, Algorithm 1
477
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)
480
481 block_r = [0xE1] + [0] * (BLOCK_SIZE_BYTES - 1)
482 block_v = block_y[:]
483 block_z = [0] * BLOCK_SIZE_BYTES
484
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)
489
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)
494
495 return block_z
496
497
498 def ghash(subkey, data):
499 # NIST SP 800-38D, Algorithm 2
500
501 if len(data) % BLOCK_SIZE_BYTES:
502 raise ValueError("Length of data should be %d bytes" % BLOCK_SIZE_BYTES)
503
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)
508
509 return last_y
510
511
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',
522 ]