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