release 2015.01.07
[ytdl] / 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