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