]> Raphaƫl G. Git Repositories - youtubedl/blob - youtube_dl/aes.py
Tidy the changelog.
[youtubedl] / youtube_dl / aes.py
1 from __future__ import unicode_literals
2
3 __all__ = ['aes_encrypt', 'key_expansion', 'aes_ctr_decrypt', 'aes_cbc_decrypt', 'aes_decrypt_text']
4
5 import base64
6 from math import ceil
7
8 from .utils import bytes_to_intlist, intlist_to_bytes
9
10 BLOCK_SIZE_BYTES = 16
11
12
13 def aes_ctr_decrypt(data, key, counter):
14 """
15 Decrypt with aes in counter mode
16
17 @param {int[]} data cipher
18 @param {int[]} key 16/24/32-Byte cipher key
19 @param {instance} counter Instance whose next_value function (@returns {int[]} 16-Byte block)
20 returns the next counter block
21 @returns {int[]} decrypted data
22 """
23 expanded_key = key_expansion(key)
24 block_count = int(ceil(float(len(data)) / BLOCK_SIZE_BYTES))
25
26 decrypted_data = []
27 for i in range(block_count):
28 counter_block = counter.next_value()
29 block = data[i * BLOCK_SIZE_BYTES: (i + 1) * BLOCK_SIZE_BYTES]
30 block += [0] * (BLOCK_SIZE_BYTES - len(block))
31
32 cipher_counter_block = aes_encrypt(counter_block, expanded_key)
33 decrypted_data += xor(block, cipher_counter_block)
34 decrypted_data = decrypted_data[:len(data)]
35
36 return decrypted_data
37
38
39 def aes_cbc_decrypt(data, key, iv):
40 """
41 Decrypt with aes in CBC mode
42
43 @param {int[]} data cipher
44 @param {int[]} key 16/24/32-Byte cipher key
45 @param {int[]} iv 16-Byte IV
46 @returns {int[]} decrypted data
47 """
48 expanded_key = key_expansion(key)
49 block_count = int(ceil(float(len(data)) / BLOCK_SIZE_BYTES))
50
51 decrypted_data = []
52 previous_cipher_block = iv
53 for i in range(block_count):
54 block = data[i * BLOCK_SIZE_BYTES: (i + 1) * BLOCK_SIZE_BYTES]
55 block += [0] * (BLOCK_SIZE_BYTES - len(block))
56
57 decrypted_block = aes_decrypt(block, expanded_key)
58 decrypted_data += xor(decrypted_block, previous_cipher_block)
59 previous_cipher_block = block
60 decrypted_data = decrypted_data[:len(data)]
61
62 return decrypted_data
63
64
65 def key_expansion(data):
66 """
67 Generate key schedule
68
69 @param {int[]} data 16/24/32-Byte cipher key
70 @returns {int[]} 176/208/240-Byte expanded key
71 """
72 data = data[:] # copy
73 rcon_iteration = 1
74 key_size_bytes = len(data)
75 expanded_key_size_bytes = (key_size_bytes // 4 + 7) * BLOCK_SIZE_BYTES
76
77 while len(data) < expanded_key_size_bytes:
78 temp = data[-4:]
79 temp = key_schedule_core(temp, rcon_iteration)
80 rcon_iteration += 1
81 data += xor(temp, data[-key_size_bytes: 4 - key_size_bytes])
82
83 for _ in range(3):
84 temp = data[-4:]
85 data += xor(temp, data[-key_size_bytes: 4 - key_size_bytes])
86
87 if key_size_bytes == 32:
88 temp = data[-4:]
89 temp = sub_bytes(temp)
90 data += xor(temp, data[-key_size_bytes: 4 - key_size_bytes])
91
92 for _ in range(3 if key_size_bytes == 32 else 2 if key_size_bytes == 24 else 0):
93 temp = data[-4:]
94 data += xor(temp, data[-key_size_bytes: 4 - key_size_bytes])
95 data = data[:expanded_key_size_bytes]
96
97 return data
98
99
100 def aes_encrypt(data, expanded_key):
101 """
102 Encrypt one block with aes
103
104 @param {int[]} data 16-Byte state
105 @param {int[]} expanded_key 176/208/240-Byte expanded key
106 @returns {int[]} 16-Byte cipher
107 """
108 rounds = len(expanded_key) // BLOCK_SIZE_BYTES - 1
109
110 data = xor(data, expanded_key[:BLOCK_SIZE_BYTES])
111 for i in range(1, rounds + 1):
112 data = sub_bytes(data)
113 data = shift_rows(data)
114 if i != rounds:
115 data = mix_columns(data)
116 data = xor(data, expanded_key[i * BLOCK_SIZE_BYTES: (i + 1) * BLOCK_SIZE_BYTES])
117
118 return data
119
120
121 def aes_decrypt(data, expanded_key):
122 """
123 Decrypt one block with aes
124
125 @param {int[]} data 16-Byte cipher
126 @param {int[]} expanded_key 176/208/240-Byte expanded key
127 @returns {int[]} 16-Byte state
128 """
129 rounds = len(expanded_key) // BLOCK_SIZE_BYTES - 1
130
131 for i in range(rounds, 0, -1):
132 data = xor(data, expanded_key[i * BLOCK_SIZE_BYTES: (i + 1) * BLOCK_SIZE_BYTES])
133 if i != rounds:
134 data = mix_columns_inv(data)
135 data = shift_rows_inv(data)
136 data = sub_bytes_inv(data)
137 data = xor(data, expanded_key[:BLOCK_SIZE_BYTES])
138
139 return data
140
141
142 def aes_decrypt_text(data, password, key_size_bytes):
143 """
144 Decrypt text
145 - The first 8 Bytes of decoded 'data' are the 8 high Bytes of the counter
146 - The cipher key is retrieved by encrypting the first 16 Byte of 'password'
147 with the first 'key_size_bytes' Bytes from 'password' (if necessary filled with 0's)
148 - Mode of operation is 'counter'
149
150 @param {str} data Base64 encoded string
151 @param {str,unicode} password Password (will be encoded with utf-8)
152 @param {int} key_size_bytes Possible values: 16 for 128-Bit, 24 for 192-Bit or 32 for 256-Bit
153 @returns {str} Decrypted data
154 """
155 NONCE_LENGTH_BYTES = 8
156
157 data = bytes_to_intlist(base64.b64decode(data))
158 password = bytes_to_intlist(password.encode('utf-8'))
159
160 key = password[:key_size_bytes] + [0] * (key_size_bytes - len(password))
161 key = aes_encrypt(key[:BLOCK_SIZE_BYTES], key_expansion(key)) * (key_size_bytes // BLOCK_SIZE_BYTES)
162
163 nonce = data[:NONCE_LENGTH_BYTES]
164 cipher = data[NONCE_LENGTH_BYTES:]
165
166 class Counter:
167 __value = nonce + [0] * (BLOCK_SIZE_BYTES - NONCE_LENGTH_BYTES)
168
169 def next_value(self):
170 temp = self.__value
171 self.__value = inc(self.__value)
172 return temp
173
174 decrypted_data = aes_ctr_decrypt(cipher, key, Counter())
175 plaintext = intlist_to_bytes(decrypted_data)
176
177 return plaintext
178
179 RCON = (0x8d, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36)
180 SBOX = (0x63, 0x7C, 0x77, 0x7B, 0xF2, 0x6B, 0x6F, 0xC5, 0x30, 0x01, 0x67, 0x2B, 0xFE, 0xD7, 0xAB, 0x76,
181 0xCA, 0x82, 0xC9, 0x7D, 0xFA, 0x59, 0x47, 0xF0, 0xAD, 0xD4, 0xA2, 0xAF, 0x9C, 0xA4, 0x72, 0xC0,
182 0xB7, 0xFD, 0x93, 0x26, 0x36, 0x3F, 0xF7, 0xCC, 0x34, 0xA5, 0xE5, 0xF1, 0x71, 0xD8, 0x31, 0x15,
183 0x04, 0xC7, 0x23, 0xC3, 0x18, 0x96, 0x05, 0x9A, 0x07, 0x12, 0x80, 0xE2, 0xEB, 0x27, 0xB2, 0x75,
184 0x09, 0x83, 0x2C, 0x1A, 0x1B, 0x6E, 0x5A, 0xA0, 0x52, 0x3B, 0xD6, 0xB3, 0x29, 0xE3, 0x2F, 0x84,
185 0x53, 0xD1, 0x00, 0xED, 0x20, 0xFC, 0xB1, 0x5B, 0x6A, 0xCB, 0xBE, 0x39, 0x4A, 0x4C, 0x58, 0xCF,
186 0xD0, 0xEF, 0xAA, 0xFB, 0x43, 0x4D, 0x33, 0x85, 0x45, 0xF9, 0x02, 0x7F, 0x50, 0x3C, 0x9F, 0xA8,
187 0x51, 0xA3, 0x40, 0x8F, 0x92, 0x9D, 0x38, 0xF5, 0xBC, 0xB6, 0xDA, 0x21, 0x10, 0xFF, 0xF3, 0xD2,
188 0xCD, 0x0C, 0x13, 0xEC, 0x5F, 0x97, 0x44, 0x17, 0xC4, 0xA7, 0x7E, 0x3D, 0x64, 0x5D, 0x19, 0x73,
189 0x60, 0x81, 0x4F, 0xDC, 0x22, 0x2A, 0x90, 0x88, 0x46, 0xEE, 0xB8, 0x14, 0xDE, 0x5E, 0x0B, 0xDB,
190 0xE0, 0x32, 0x3A, 0x0A, 0x49, 0x06, 0x24, 0x5C, 0xC2, 0xD3, 0xAC, 0x62, 0x91, 0x95, 0xE4, 0x79,
191 0xE7, 0xC8, 0x37, 0x6D, 0x8D, 0xD5, 0x4E, 0xA9, 0x6C, 0x56, 0xF4, 0xEA, 0x65, 0x7A, 0xAE, 0x08,
192 0xBA, 0x78, 0x25, 0x2E, 0x1C, 0xA6, 0xB4, 0xC6, 0xE8, 0xDD, 0x74, 0x1F, 0x4B, 0xBD, 0x8B, 0x8A,
193 0x70, 0x3E, 0xB5, 0x66, 0x48, 0x03, 0xF6, 0x0E, 0x61, 0x35, 0x57, 0xB9, 0x86, 0xC1, 0x1D, 0x9E,
194 0xE1, 0xF8, 0x98, 0x11, 0x69, 0xD9, 0x8E, 0x94, 0x9B, 0x1E, 0x87, 0xE9, 0xCE, 0x55, 0x28, 0xDF,
195 0x8C, 0xA1, 0x89, 0x0D, 0xBF, 0xE6, 0x42, 0x68, 0x41, 0x99, 0x2D, 0x0F, 0xB0, 0x54, 0xBB, 0x16)
196 SBOX_INV = (0x52, 0x09, 0x6a, 0xd5, 0x30, 0x36, 0xa5, 0x38, 0xbf, 0x40, 0xa3, 0x9e, 0x81, 0xf3, 0xd7, 0xfb,
197 0x7c, 0xe3, 0x39, 0x82, 0x9b, 0x2f, 0xff, 0x87, 0x34, 0x8e, 0x43, 0x44, 0xc4, 0xde, 0xe9, 0xcb,
198 0x54, 0x7b, 0x94, 0x32, 0xa6, 0xc2, 0x23, 0x3d, 0xee, 0x4c, 0x95, 0x0b, 0x42, 0xfa, 0xc3, 0x4e,
199 0x08, 0x2e, 0xa1, 0x66, 0x28, 0xd9, 0x24, 0xb2, 0x76, 0x5b, 0xa2, 0x49, 0x6d, 0x8b, 0xd1, 0x25,
200 0x72, 0xf8, 0xf6, 0x64, 0x86, 0x68, 0x98, 0x16, 0xd4, 0xa4, 0x5c, 0xcc, 0x5d, 0x65, 0xb6, 0x92,
201 0x6c, 0x70, 0x48, 0x50, 0xfd, 0xed, 0xb9, 0xda, 0x5e, 0x15, 0x46, 0x57, 0xa7, 0x8d, 0x9d, 0x84,
202 0x90, 0xd8, 0xab, 0x00, 0x8c, 0xbc, 0xd3, 0x0a, 0xf7, 0xe4, 0x58, 0x05, 0xb8, 0xb3, 0x45, 0x06,
203 0xd0, 0x2c, 0x1e, 0x8f, 0xca, 0x3f, 0x0f, 0x02, 0xc1, 0xaf, 0xbd, 0x03, 0x01, 0x13, 0x8a, 0x6b,
204 0x3a, 0x91, 0x11, 0x41, 0x4f, 0x67, 0xdc, 0xea, 0x97, 0xf2, 0xcf, 0xce, 0xf0, 0xb4, 0xe6, 0x73,
205 0x96, 0xac, 0x74, 0x22, 0xe7, 0xad, 0x35, 0x85, 0xe2, 0xf9, 0x37, 0xe8, 0x1c, 0x75, 0xdf, 0x6e,
206 0x47, 0xf1, 0x1a, 0x71, 0x1d, 0x29, 0xc5, 0x89, 0x6f, 0xb7, 0x62, 0x0e, 0xaa, 0x18, 0xbe, 0x1b,
207 0xfc, 0x56, 0x3e, 0x4b, 0xc6, 0xd2, 0x79, 0x20, 0x9a, 0xdb, 0xc0, 0xfe, 0x78, 0xcd, 0x5a, 0xf4,
208 0x1f, 0xdd, 0xa8, 0x33, 0x88, 0x07, 0xc7, 0x31, 0xb1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xec, 0x5f,
209 0x60, 0x51, 0x7f, 0xa9, 0x19, 0xb5, 0x4a, 0x0d, 0x2d, 0xe5, 0x7a, 0x9f, 0x93, 0xc9, 0x9c, 0xef,
210 0xa0, 0xe0, 0x3b, 0x4d, 0xae, 0x2a, 0xf5, 0xb0, 0xc8, 0xeb, 0xbb, 0x3c, 0x83, 0x53, 0x99, 0x61,
211 0x17, 0x2b, 0x04, 0x7e, 0xba, 0x77, 0xd6, 0x26, 0xe1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0c, 0x7d)
212 MIX_COLUMN_MATRIX = ((0x2, 0x3, 0x1, 0x1),
213 (0x1, 0x2, 0x3, 0x1),
214 (0x1, 0x1, 0x2, 0x3),
215 (0x3, 0x1, 0x1, 0x2))
216 MIX_COLUMN_MATRIX_INV = ((0xE, 0xB, 0xD, 0x9),
217 (0x9, 0xE, 0xB, 0xD),
218 (0xD, 0x9, 0xE, 0xB),
219 (0xB, 0xD, 0x9, 0xE))
220 RIJNDAEL_EXP_TABLE = (0x01, 0x03, 0x05, 0x0F, 0x11, 0x33, 0x55, 0xFF, 0x1A, 0x2E, 0x72, 0x96, 0xA1, 0xF8, 0x13, 0x35,
221 0x5F, 0xE1, 0x38, 0x48, 0xD8, 0x73, 0x95, 0xA4, 0xF7, 0x02, 0x06, 0x0A, 0x1E, 0x22, 0x66, 0xAA,
222 0xE5, 0x34, 0x5C, 0xE4, 0x37, 0x59, 0xEB, 0x26, 0x6A, 0xBE, 0xD9, 0x70, 0x90, 0xAB, 0xE6, 0x31,
223 0x53, 0xF5, 0x04, 0x0C, 0x14, 0x3C, 0x44, 0xCC, 0x4F, 0xD1, 0x68, 0xB8, 0xD3, 0x6E, 0xB2, 0xCD,
224 0x4C, 0xD4, 0x67, 0xA9, 0xE0, 0x3B, 0x4D, 0xD7, 0x62, 0xA6, 0xF1, 0x08, 0x18, 0x28, 0x78, 0x88,
225 0x83, 0x9E, 0xB9, 0xD0, 0x6B, 0xBD, 0xDC, 0x7F, 0x81, 0x98, 0xB3, 0xCE, 0x49, 0xDB, 0x76, 0x9A,
226 0xB5, 0xC4, 0x57, 0xF9, 0x10, 0x30, 0x50, 0xF0, 0x0B, 0x1D, 0x27, 0x69, 0xBB, 0xD6, 0x61, 0xA3,
227 0xFE, 0x19, 0x2B, 0x7D, 0x87, 0x92, 0xAD, 0xEC, 0x2F, 0x71, 0x93, 0xAE, 0xE9, 0x20, 0x60, 0xA0,
228 0xFB, 0x16, 0x3A, 0x4E, 0xD2, 0x6D, 0xB7, 0xC2, 0x5D, 0xE7, 0x32, 0x56, 0xFA, 0x15, 0x3F, 0x41,
229 0xC3, 0x5E, 0xE2, 0x3D, 0x47, 0xC9, 0x40, 0xC0, 0x5B, 0xED, 0x2C, 0x74, 0x9C, 0xBF, 0xDA, 0x75,
230 0x9F, 0xBA, 0xD5, 0x64, 0xAC, 0xEF, 0x2A, 0x7E, 0x82, 0x9D, 0xBC, 0xDF, 0x7A, 0x8E, 0x89, 0x80,
231 0x9B, 0xB6, 0xC1, 0x58, 0xE8, 0x23, 0x65, 0xAF, 0xEA, 0x25, 0x6F, 0xB1, 0xC8, 0x43, 0xC5, 0x54,
232 0xFC, 0x1F, 0x21, 0x63, 0xA5, 0xF4, 0x07, 0x09, 0x1B, 0x2D, 0x77, 0x99, 0xB0, 0xCB, 0x46, 0xCA,
233 0x45, 0xCF, 0x4A, 0xDE, 0x79, 0x8B, 0x86, 0x91, 0xA8, 0xE3, 0x3E, 0x42, 0xC6, 0x51, 0xF3, 0x0E,
234 0x12, 0x36, 0x5A, 0xEE, 0x29, 0x7B, 0x8D, 0x8C, 0x8F, 0x8A, 0x85, 0x94, 0xA7, 0xF2, 0x0D, 0x17,
235 0x39, 0x4B, 0xDD, 0x7C, 0x84, 0x97, 0xA2, 0xFD, 0x1C, 0x24, 0x6C, 0xB4, 0xC7, 0x52, 0xF6, 0x01)
236 RIJNDAEL_LOG_TABLE = (0x00, 0x00, 0x19, 0x01, 0x32, 0x02, 0x1a, 0xc6, 0x4b, 0xc7, 0x1b, 0x68, 0x33, 0xee, 0xdf, 0x03,
237 0x64, 0x04, 0xe0, 0x0e, 0x34, 0x8d, 0x81, 0xef, 0x4c, 0x71, 0x08, 0xc8, 0xf8, 0x69, 0x1c, 0xc1,
238 0x7d, 0xc2, 0x1d, 0xb5, 0xf9, 0xb9, 0x27, 0x6a, 0x4d, 0xe4, 0xa6, 0x72, 0x9a, 0xc9, 0x09, 0x78,
239 0x65, 0x2f, 0x8a, 0x05, 0x21, 0x0f, 0xe1, 0x24, 0x12, 0xf0, 0x82, 0x45, 0x35, 0x93, 0xda, 0x8e,
240 0x96, 0x8f, 0xdb, 0xbd, 0x36, 0xd0, 0xce, 0x94, 0x13, 0x5c, 0xd2, 0xf1, 0x40, 0x46, 0x83, 0x38,
241 0x66, 0xdd, 0xfd, 0x30, 0xbf, 0x06, 0x8b, 0x62, 0xb3, 0x25, 0xe2, 0x98, 0x22, 0x88, 0x91, 0x10,
242 0x7e, 0x6e, 0x48, 0xc3, 0xa3, 0xb6, 0x1e, 0x42, 0x3a, 0x6b, 0x28, 0x54, 0xfa, 0x85, 0x3d, 0xba,
243 0x2b, 0x79, 0x0a, 0x15, 0x9b, 0x9f, 0x5e, 0xca, 0x4e, 0xd4, 0xac, 0xe5, 0xf3, 0x73, 0xa7, 0x57,
244 0xaf, 0x58, 0xa8, 0x50, 0xf4, 0xea, 0xd6, 0x74, 0x4f, 0xae, 0xe9, 0xd5, 0xe7, 0xe6, 0xad, 0xe8,
245 0x2c, 0xd7, 0x75, 0x7a, 0xeb, 0x16, 0x0b, 0xf5, 0x59, 0xcb, 0x5f, 0xb0, 0x9c, 0xa9, 0x51, 0xa0,
246 0x7f, 0x0c, 0xf6, 0x6f, 0x17, 0xc4, 0x49, 0xec, 0xd8, 0x43, 0x1f, 0x2d, 0xa4, 0x76, 0x7b, 0xb7,
247 0xcc, 0xbb, 0x3e, 0x5a, 0xfb, 0x60, 0xb1, 0x86, 0x3b, 0x52, 0xa1, 0x6c, 0xaa, 0x55, 0x29, 0x9d,
248 0x97, 0xb2, 0x87, 0x90, 0x61, 0xbe, 0xdc, 0xfc, 0xbc, 0x95, 0xcf, 0xcd, 0x37, 0x3f, 0x5b, 0xd1,
249 0x53, 0x39, 0x84, 0x3c, 0x41, 0xa2, 0x6d, 0x47, 0x14, 0x2a, 0x9e, 0x5d, 0x56, 0xf2, 0xd3, 0xab,
250 0x44, 0x11, 0x92, 0xd9, 0x23, 0x20, 0x2e, 0x89, 0xb4, 0x7c, 0xb8, 0x26, 0x77, 0x99, 0xe3, 0xa5,
251 0x67, 0x4a, 0xed, 0xde, 0xc5, 0x31, 0xfe, 0x18, 0x0d, 0x63, 0x8c, 0x80, 0xc0, 0xf7, 0x70, 0x07)
252
253
254 def sub_bytes(data):
255 return [SBOX[x] for x in data]
256
257
258 def sub_bytes_inv(data):
259 return [SBOX_INV[x] for x in data]
260
261
262 def rotate(data):
263 return data[1:] + [data[0]]
264
265
266 def key_schedule_core(data, rcon_iteration):
267 data = rotate(data)
268 data = sub_bytes(data)
269 data[0] = data[0] ^ RCON[rcon_iteration]
270
271 return data
272
273
274 def xor(data1, data2):
275 return [x ^ y for x, y in zip(data1, data2)]
276
277
278 def rijndael_mul(a, b):
279 if(a == 0 or b == 0):
280 return 0
281 return RIJNDAEL_EXP_TABLE[(RIJNDAEL_LOG_TABLE[a] + RIJNDAEL_LOG_TABLE[b]) % 0xFF]
282
283
284 def mix_column(data, matrix):
285 data_mixed = []
286 for row in range(4):
287 mixed = 0
288 for column in range(4):
289 # xor is (+) and (-)
290 mixed ^= rijndael_mul(data[column], matrix[row][column])
291 data_mixed.append(mixed)
292 return data_mixed
293
294
295 def mix_columns(data, matrix=MIX_COLUMN_MATRIX):
296 data_mixed = []
297 for i in range(4):
298 column = data[i * 4: (i + 1) * 4]
299 data_mixed += mix_column(column, matrix)
300 return data_mixed
301
302
303 def mix_columns_inv(data):
304 return mix_columns(data, MIX_COLUMN_MATRIX_INV)
305
306
307 def shift_rows(data):
308 data_shifted = []
309 for column in range(4):
310 for row in range(4):
311 data_shifted.append(data[((column + row) & 0b11) * 4 + row])
312 return data_shifted
313
314
315 def shift_rows_inv(data):
316 data_shifted = []
317 for column in range(4):
318 for row in range(4):
319 data_shifted.append(data[((column - row) & 0b11) * 4 + row])
320 return data_shifted
321
322
323 def inc(data):
324 data = data[:] # copy
325 for i in range(len(data) - 1, -1, -1):
326 if data[i] == 255:
327 data[i] = 0
328 else:
329 data[i] = data[i] + 1
330 break
331 return data