]> jfr.im git - yt-dlp.git/blob - yt_dlp/aes.py
[aes] Improve performance slightly (#1135)
[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 = list(iter_mix_columns(data, MIX_COLUMN_MATRIX))
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 = list(iter_mix_columns(data, MIX_COLUMN_MATRIX_INV))
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 iter_mix_columns(data, matrix):
379 for i in (0, 4, 8, 12):
380 for row in matrix:
381 mixed = 0
382 for j in range(4):
383 # xor is (+) and (-)
384 mixed ^= (0 if data[i:i + 4][j] == 0 or row[j] == 0 else
385 RIJNDAEL_EXP_TABLE[(RIJNDAEL_LOG_TABLE[data[i + j]] + RIJNDAEL_LOG_TABLE[row[j]]) % 0xFF])
386 yield mixed
387
388
389 def shift_rows(data):
390 return [data[((column + row) & 0b11) * 4 + row] for column in range(4) for row in range(4)]
391
392
393 def shift_rows_inv(data):
394 return [data[((column - row) & 0b11) * 4 + row] for column in range(4) for row in range(4)]
395
396
397 def shift_block(data):
398 data_shifted = []
399
400 bit = 0
401 for n in data:
402 if bit:
403 n |= 0x100
404 bit = n & 1
405 n >>= 1
406 data_shifted.append(n)
407
408 return data_shifted
409
410
411 def inc(data):
412 data = data[:] # copy
413 for i in range(len(data) - 1, -1, -1):
414 if data[i] == 255:
415 data[i] = 0
416 else:
417 data[i] = data[i] + 1
418 break
419 return data
420
421
422 def block_product(block_x, block_y):
423 # NIST SP 800-38D, Algorithm 1
424
425 if len(block_x) != BLOCK_SIZE_BYTES or len(block_y) != BLOCK_SIZE_BYTES:
426 raise ValueError("Length of blocks need to be %d bytes" % BLOCK_SIZE_BYTES)
427
428 block_r = [0xE1] + [0] * (BLOCK_SIZE_BYTES - 1)
429 block_v = block_y[:]
430 block_z = [0] * BLOCK_SIZE_BYTES
431
432 for i in block_x:
433 for bit in range(7, -1, -1):
434 if i & (1 << bit):
435 block_z = xor(block_z, block_v)
436
437 do_xor = block_v[-1] & 1
438 block_v = shift_block(block_v)
439 if do_xor:
440 block_v = xor(block_v, block_r)
441
442 return block_z
443
444
445 def ghash(subkey, data):
446 # NIST SP 800-38D, Algorithm 2
447
448 if len(data) % BLOCK_SIZE_BYTES:
449 raise ValueError("Length of data should be %d bytes" % BLOCK_SIZE_BYTES)
450
451 last_y = [0] * BLOCK_SIZE_BYTES
452 for i in range(0, len(data), BLOCK_SIZE_BYTES):
453 block = data[i : i + BLOCK_SIZE_BYTES] # noqa: E203
454 last_y = block_product(xor(last_y, block), subkey)
455
456 return last_y
457
458
459 __all__ = [
460 'aes_ctr_decrypt',
461 'aes_cbc_decrypt',
462 'aes_cbc_decrypt_bytes',
463 'aes_decrypt_text',
464 'aes_encrypt',
465 'aes_gcm_decrypt_and_verify',
466 'aes_gcm_decrypt_and_verify_bytes',
467 'key_expansion'
468 ]