]> jfr.im git - yt-dlp.git/blame - yt_dlp/aes.py
[hls] Better FairPlay DRM detection (#1661)
[yt-dlp.git] / yt_dlp / aes.py
CommitLineData
dcddc10a
PH
1from __future__ import unicode_literals
2
f3bcebb1 3from math import ceil
4
edf65256 5from .compat import compat_b64decode, compat_pycrypto_AES
0012690a 6from .utils import bytes_to_intlist, intlist_to_bytes
48ea9cea 7
edf65256 8
9if 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
09906f55
ÁS
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
edf65256 18else:
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
09906f55
ÁS
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
edf65256 27
f3bcebb1 28BLOCK_SIZE_BYTES = 16
29
5f6a1245 30
09906f55 31def aes_ctr_decrypt(data, key, iv):
f3bcebb1 32 """
33 Decrypt with aes in counter mode
5f6a1245 34
f3bcebb1 35 @param {int[]} data cipher
36 @param {int[]} key 16/24/32-Byte cipher key
09906f55 37 @param {int[]} iv 16-Byte initialization vector
f3bcebb1 38 @returns {int[]} decrypted data
39 """
09906f55
ÁS
40 return aes_ctr_encrypt(data, key, iv)
41
42
43def 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 """
f3bcebb1 52 expanded_key = key_expansion(key)
6e74bc41 53 block_count = int(ceil(float(len(data)) / BLOCK_SIZE_BYTES))
09906f55 54 counter = iter_vector(iv)
5f6a1245 55
09906f55 56 encrypted_data = []
f3bcebb1 57 for i in range(block_count):
09906f55 58 counter_block = next(counter)
2514d263
JW
59 block = data[i * BLOCK_SIZE_BYTES: (i + 1) * BLOCK_SIZE_BYTES]
60 block += [0] * (BLOCK_SIZE_BYTES - len(block))
5f6a1245 61
f3bcebb1 62 cipher_counter_block = aes_encrypt(counter_block, expanded_key)
09906f55
ÁS
63 encrypted_data += xor(block, cipher_counter_block)
64 encrypted_data = encrypted_data[:len(data)]
5f6a1245 65
09906f55 66 return encrypted_data
f3bcebb1 67
5f6a1245 68
c8434e83 69def aes_cbc_decrypt(data, key, iv):
70 """
71 Decrypt with aes in CBC mode
5f6a1245 72
c8434e83 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))
5f6a1245
JW
80
81 decrypted_data = []
c8434e83 82 previous_cipher_block = iv
83 for i in range(block_count):
2514d263
JW
84 block = data[i * BLOCK_SIZE_BYTES: (i + 1) * BLOCK_SIZE_BYTES]
85 block += [0] * (BLOCK_SIZE_BYTES - len(block))
5f6a1245 86
c8434e83 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)]
5f6a1245 91
c8434e83 92 return decrypted_data
93
5f6a1245 94
c9619f0a
YCH
95def 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
09906f55 123def aes_gcm_decrypt_and_verify(data, key, tag, nonce):
f3bcebb1 124 """
09906f55 125 Decrypt with aes in GBM mode and checks authenticity using tag
5f6a1245 126
09906f55
ÁS
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
f3bcebb1 132 """
5f6a1245 133
09906f55 134 # XXX: check aes, gcm param
5f6a1245 135
09906f55 136 hash_subkey = aes_encrypt([0] * BLOCK_SIZE_BYTES, key_expansion(key))
5f6a1245 137
09906f55
ÁS
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)
5f6a1245 144
09906f55 145 # TODO: add nonce support to aes_ctr_decrypt
5f6a1245 146
09906f55
ÁS
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
f3bcebb1 164
5f6a1245 165
f3bcebb1 166def aes_encrypt(data, expanded_key):
167 """
168 Encrypt one block with aes
5f6a1245 169
f3bcebb1 170 @param {int[]} data 16-Byte state
5f6a1245 171 @param {int[]} expanded_key 176/208/240-Byte expanded key
f3bcebb1 172 @returns {int[]} 16-Byte cipher
173 """
48ea9cea 174 rounds = len(expanded_key) // BLOCK_SIZE_BYTES - 1
c8434e83 175
f3bcebb1 176 data = xor(data, expanded_key[:BLOCK_SIZE_BYTES])
2514d263 177 for i in range(1, rounds + 1):
f3bcebb1 178 data = sub_bytes(data)
179 data = shift_rows(data)
180 if i != rounds:
ff1dec81 181 data = list(iter_mix_columns(data, MIX_COLUMN_MATRIX))
2514d263 182 data = xor(data, expanded_key[i * BLOCK_SIZE_BYTES: (i + 1) * BLOCK_SIZE_BYTES])
c8434e83 183
184 return data
185
5f6a1245 186
c8434e83 187def aes_decrypt(data, expanded_key):
188 """
189 Decrypt one block with aes
5f6a1245 190
c8434e83 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
5f6a1245 196
c8434e83 197 for i in range(rounds, 0, -1):
2514d263 198 data = xor(data, expanded_key[i * BLOCK_SIZE_BYTES: (i + 1) * BLOCK_SIZE_BYTES])
c8434e83 199 if i != rounds:
ff1dec81 200 data = list(iter_mix_columns(data, MIX_COLUMN_MATRIX_INV))
c8434e83 201 data = shift_rows_inv(data)
202 data = sub_bytes_inv(data)
203 data = xor(data, expanded_key[:BLOCK_SIZE_BYTES])
5f6a1245 204
f3bcebb1 205 return data
206
5f6a1245 207
f3bcebb1 208def 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'
5f6a1245 215
f3bcebb1 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
5f6a1245 222
cf282071 223 data = bytes_to_intlist(compat_b64decode(data))
48ea9cea 224 password = bytes_to_intlist(password.encode('utf-8'))
5f6a1245 225
2514d263 226 key = password[:key_size_bytes] + [0] * (key_size_bytes - len(password))
48ea9cea 227 key = aes_encrypt(key[:BLOCK_SIZE_BYTES], key_expansion(key)) * (key_size_bytes // BLOCK_SIZE_BYTES)
5f6a1245 228
f3bcebb1 229 nonce = data[:NONCE_LENGTH_BYTES]
230 cipher = data[NONCE_LENGTH_BYTES:]
5f6a1245 231
09906f55 232 decrypted_data = aes_ctr_decrypt(cipher, key, nonce + [0] * (BLOCK_SIZE_BYTES - NONCE_LENGTH_BYTES))
0012690a 233 plaintext = intlist_to_bytes(decrypted_data)
5f6a1245 234
f3bcebb1 235 return plaintext
236
582be358 237
f3bcebb1 238RCON = (0x8d, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36)
239SBOX = (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)
c8434e83 255SBOX_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)
5f6a1245
JW
271MIX_COLUMN_MATRIX = ((0x2, 0x3, 0x1, 0x1),
272 (0x1, 0x2, 0x3, 0x1),
273 (0x1, 0x1, 0x2, 0x3),
274 (0x3, 0x1, 0x1, 0x2))
275MIX_COLUMN_MATRIX_INV = ((0xE, 0xB, 0xD, 0x9),
276 (0x9, 0xE, 0xB, 0xD),
277 (0xD, 0x9, 0xE, 0xB),
278 (0xB, 0xD, 0x9, 0xE))
c8434e83 279RIJNDAEL_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)
295RIJNDAEL_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)
f3bcebb1 311
5f6a1245 312
09906f55
ÁS
313def 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
348def iter_vector(iv):
349 while True:
350 yield iv
351 iv = inc(iv)
352
353
f3bcebb1 354def sub_bytes(data):
48ea9cea 355 return [SBOX[x] for x in data]
f3bcebb1 356
5f6a1245 357
c8434e83 358def sub_bytes_inv(data):
359 return [SBOX_INV[x] for x in data]
360
5f6a1245 361
f3bcebb1 362def rotate(data):
363 return data[1:] + [data[0]]
364
5f6a1245 365
f3bcebb1 366def key_schedule_core(data, rcon_iteration):
367 data = rotate(data)
368 data = sub_bytes(data)
369 data[0] = data[0] ^ RCON[rcon_iteration]
5f6a1245 370
f3bcebb1 371 return data
372
5f6a1245 373
f3bcebb1 374def xor(data1, data2):
2514d263 375 return [x ^ y for x, y in zip(data1, data2)]
f3bcebb1 376
5f6a1245 377
ff1dec81
ÁS
378def 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
c8434e83 387
5f6a1245 388
f3bcebb1 389def shift_rows(data):
ff1dec81 390 return [data[((column + row) & 0b11) * 4 + row] for column in range(4) for row in range(4)]
f3bcebb1 391
5f6a1245 392
c8434e83 393def shift_rows_inv(data):
ff1dec81 394 return [data[((column - row) & 0b11) * 4 + row] for column in range(4) for row in range(4)]
c8434e83 395
5f6a1245 396
09906f55
ÁS
397def 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
f3bcebb1 411def inc(data):
5f6a1245 412 data = data[:] # copy
2514d263 413 for i in range(len(data) - 1, -1, -1):
f3bcebb1 414 if data[i] == 255:
415 data[i] = 0
416 else:
417 data[i] = data[i] + 1
418 break
419 return data
f36f92f4 420
582be358 421
09906f55
ÁS
422def 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
445def 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]