eric6/Utilities/crypto/py3AES.py

changeset 6942
2602857055c5
parent 6645
ad476851d7e0
child 7229
53054eb5b15a
equal deleted inserted replaced
6941:f99d60d6b59b 6942:2602857055c5
1 # -*- coding: utf-8 -*-
2
3 #
4 # aes.py: implements AES - Advanced Encryption Standard
5 # from the SlowAES project, http://code.google.com/p/slowaes/
6 #
7 # Copyright (c) 2008 Josh Davis ( http://www.josh-davis.org ),
8 # Alex Martelli ( http://www.aleax.it )
9 #
10 # Ported from C code written by Laurent Haan
11 # ( http://www.progressive-coding.com )
12 #
13 # Licensed under the Apache License, Version 2.0
14 # http://www.apache.org/licenses/
15 #
16
17 #
18 # Ported to Python3
19 #
20 # Copyright (c) 2011 - 2019 Detlev Offenbach <detlev@die-offenbachs.de>
21 #
22
23 """
24 Module implementing classes for encryption according
25 Advanced Encryption Standard.
26 """
27
28 from __future__ import unicode_literals
29
30 import os
31 import math
32
33
34 def append_PKCS7_padding(b):
35 """
36 Function to pad the given data to a multiple of 16-bytes by PKCS7 padding.
37
38 @param b data to be padded (bytes)
39 @return padded data (bytes)
40 """
41 numpads = 16 - (len(b) % 16)
42 return b + numpads * bytes(chr(numpads), encoding="ascii")
43
44
45 def strip_PKCS7_padding(b):
46 """
47 Function to strip off PKCS7 padding.
48
49 @param b data to be stripped (bytes)
50 @return stripped data (bytes)
51 @exception ValueError data padding is invalid
52 """
53 if len(b) % 16 or not b:
54 raise ValueError(
55 "Data of len {0} can't be PCKS7-padded".format(len(b)))
56 numpads = b[-1]
57 if numpads > 16:
58 raise ValueError(
59 "Data ending with {0} can't be PCKS7-padded".format(b[-1]))
60 return b[:-numpads]
61
62
63 class AES(object):
64 """
65 Class implementing the Advanced Encryption Standard algorithm.
66 """
67 # valid key sizes
68 KeySize = {
69 "SIZE_128": 16,
70 "SIZE_192": 24,
71 "SIZE_256": 32,
72 }
73
74 # Rijndael S-box
75 sbox = [0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5, 0x30, 0x01, 0x67,
76 0x2b, 0xfe, 0xd7, 0xab, 0x76, 0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59,
77 0x47, 0xf0, 0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0, 0xb7,
78 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc, 0x34, 0xa5, 0xe5, 0xf1,
79 0x71, 0xd8, 0x31, 0x15, 0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05,
80 0x9a, 0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75, 0x09, 0x83,
81 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0, 0x52, 0x3b, 0xd6, 0xb3, 0x29,
82 0xe3, 0x2f, 0x84, 0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b,
83 0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf, 0xd0, 0xef, 0xaa,
84 0xfb, 0x43, 0x4d, 0x33, 0x85, 0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c,
85 0x9f, 0xa8, 0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5, 0xbc,
86 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2, 0xcd, 0x0c, 0x13, 0xec,
87 0x5f, 0x97, 0x44, 0x17, 0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19,
88 0x73, 0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88, 0x46, 0xee,
89 0xb8, 0x14, 0xde, 0x5e, 0x0b, 0xdb, 0xe0, 0x32, 0x3a, 0x0a, 0x49,
90 0x06, 0x24, 0x5c, 0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79,
91 0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, 0x4e, 0xa9, 0x6c, 0x56, 0xf4,
92 0xea, 0x65, 0x7a, 0xae, 0x08, 0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6,
93 0xb4, 0xc6, 0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a, 0x70,
94 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e, 0x61, 0x35, 0x57, 0xb9,
95 0x86, 0xc1, 0x1d, 0x9e, 0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e,
96 0x94, 0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf, 0x8c, 0xa1,
97 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68, 0x41, 0x99, 0x2d, 0x0f, 0xb0,
98 0x54, 0xbb, 0x16]
99
100 # Rijndael Inverted S-box
101 rsbox = [0x52, 0x09, 0x6a, 0xd5, 0x30, 0x36, 0xa5, 0x38, 0xbf, 0x40, 0xa3,
102 0x9e, 0x81, 0xf3, 0xd7, 0xfb, 0x7c, 0xe3, 0x39, 0x82, 0x9b, 0x2f,
103 0xff, 0x87, 0x34, 0x8e, 0x43, 0x44, 0xc4, 0xde, 0xe9, 0xcb, 0x54,
104 0x7b, 0x94, 0x32, 0xa6, 0xc2, 0x23, 0x3d, 0xee, 0x4c, 0x95, 0x0b,
105 0x42, 0xfa, 0xc3, 0x4e, 0x08, 0x2e, 0xa1, 0x66, 0x28, 0xd9, 0x24,
106 0xb2, 0x76, 0x5b, 0xa2, 0x49, 0x6d, 0x8b, 0xd1, 0x25, 0x72, 0xf8,
107 0xf6, 0x64, 0x86, 0x68, 0x98, 0x16, 0xd4, 0xa4, 0x5c, 0xcc, 0x5d,
108 0x65, 0xb6, 0x92, 0x6c, 0x70, 0x48, 0x50, 0xfd, 0xed, 0xb9, 0xda,
109 0x5e, 0x15, 0x46, 0x57, 0xa7, 0x8d, 0x9d, 0x84, 0x90, 0xd8, 0xab,
110 0x00, 0x8c, 0xbc, 0xd3, 0x0a, 0xf7, 0xe4, 0x58, 0x05, 0xb8, 0xb3,
111 0x45, 0x06, 0xd0, 0x2c, 0x1e, 0x8f, 0xca, 0x3f, 0x0f, 0x02, 0xc1,
112 0xaf, 0xbd, 0x03, 0x01, 0x13, 0x8a, 0x6b, 0x3a, 0x91, 0x11, 0x41,
113 0x4f, 0x67, 0xdc, 0xea, 0x97, 0xf2, 0xcf, 0xce, 0xf0, 0xb4, 0xe6,
114 0x73, 0x96, 0xac, 0x74, 0x22, 0xe7, 0xad, 0x35, 0x85, 0xe2, 0xf9,
115 0x37, 0xe8, 0x1c, 0x75, 0xdf, 0x6e, 0x47, 0xf1, 0x1a, 0x71, 0x1d,
116 0x29, 0xc5, 0x89, 0x6f, 0xb7, 0x62, 0x0e, 0xaa, 0x18, 0xbe, 0x1b,
117 0xfc, 0x56, 0x3e, 0x4b, 0xc6, 0xd2, 0x79, 0x20, 0x9a, 0xdb, 0xc0,
118 0xfe, 0x78, 0xcd, 0x5a, 0xf4, 0x1f, 0xdd, 0xa8, 0x33, 0x88, 0x07,
119 0xc7, 0x31, 0xb1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xec, 0x5f, 0x60,
120 0x51, 0x7f, 0xa9, 0x19, 0xb5, 0x4a, 0x0d, 0x2d, 0xe5, 0x7a, 0x9f,
121 0x93, 0xc9, 0x9c, 0xef, 0xa0, 0xe0, 0x3b, 0x4d, 0xae, 0x2a, 0xf5,
122 0xb0, 0xc8, 0xeb, 0xbb, 0x3c, 0x83, 0x53, 0x99, 0x61, 0x17, 0x2b,
123 0x04, 0x7e, 0xba, 0x77, 0xd6, 0x26, 0xe1, 0x69, 0x14, 0x63, 0x55,
124 0x21, 0x0c, 0x7d]
125
126 # Rijndael Rcon
127 Rcon = [0x8d, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36,
128 0x6c, 0xd8, 0xab, 0x4d, 0x9a, 0x2f, 0x5e, 0xbc, 0x63, 0xc6, 0x97,
129 0x35, 0x6a, 0xd4, 0xb3, 0x7d, 0xfa, 0xef, 0xc5, 0x91, 0x39, 0x72,
130 0xe4, 0xd3, 0xbd, 0x61, 0xc2, 0x9f, 0x25, 0x4a, 0x94, 0x33, 0x66,
131 0xcc, 0x83, 0x1d, 0x3a, 0x74, 0xe8, 0xcb, 0x8d, 0x01, 0x02, 0x04,
132 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36, 0x6c, 0xd8, 0xab, 0x4d,
133 0x9a, 0x2f, 0x5e, 0xbc, 0x63, 0xc6, 0x97, 0x35, 0x6a, 0xd4, 0xb3,
134 0x7d, 0xfa, 0xef, 0xc5, 0x91, 0x39, 0x72, 0xe4, 0xd3, 0xbd, 0x61,
135 0xc2, 0x9f, 0x25, 0x4a, 0x94, 0x33, 0x66, 0xcc, 0x83, 0x1d, 0x3a,
136 0x74, 0xe8, 0xcb, 0x8d, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40,
137 0x80, 0x1b, 0x36, 0x6c, 0xd8, 0xab, 0x4d, 0x9a, 0x2f, 0x5e, 0xbc,
138 0x63, 0xc6, 0x97, 0x35, 0x6a, 0xd4, 0xb3, 0x7d, 0xfa, 0xef, 0xc5,
139 0x91, 0x39, 0x72, 0xe4, 0xd3, 0xbd, 0x61, 0xc2, 0x9f, 0x25, 0x4a,
140 0x94, 0x33, 0x66, 0xcc, 0x83, 0x1d, 0x3a, 0x74, 0xe8, 0xcb, 0x8d,
141 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36, 0x6c,
142 0xd8, 0xab, 0x4d, 0x9a, 0x2f, 0x5e, 0xbc, 0x63, 0xc6, 0x97, 0x35,
143 0x6a, 0xd4, 0xb3, 0x7d, 0xfa, 0xef, 0xc5, 0x91, 0x39, 0x72, 0xe4,
144 0xd3, 0xbd, 0x61, 0xc2, 0x9f, 0x25, 0x4a, 0x94, 0x33, 0x66, 0xcc,
145 0x83, 0x1d, 0x3a, 0x74, 0xe8, 0xcb, 0x8d, 0x01, 0x02, 0x04, 0x08,
146 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36, 0x6c, 0xd8, 0xab, 0x4d, 0x9a,
147 0x2f, 0x5e, 0xbc, 0x63, 0xc6, 0x97, 0x35, 0x6a, 0xd4, 0xb3, 0x7d,
148 0xfa, 0xef, 0xc5, 0x91, 0x39, 0x72, 0xe4, 0xd3, 0xbd, 0x61, 0xc2,
149 0x9f, 0x25, 0x4a, 0x94, 0x33, 0x66, 0xcc, 0x83, 0x1d, 0x3a, 0x74,
150 0xe8, 0xcb]
151
152 def __getSBoxValue(self, num):
153 """
154 Private method to retrieve a given S-Box value.
155
156 @param num position of the value (integer)
157 @return value of the S-Box (integer)
158 """
159 return self.sbox[num]
160
161 def __getSBoxInvert(self, num):
162 """
163 Private method to retrieve a given Inverted S-Box value.
164
165 @param num position of the value (integer)
166 @return value of the Inverted S-Box (integer)
167 """
168 return self.rsbox[num]
169
170 def __rotate(self, data):
171 """
172 Private method performing Rijndael's key schedule rotate operation.
173
174 Rotate the data word eight bits to the left: eg,
175 rotate(1d2c3a4f) == 2c3a4f1d.
176
177 @param data data of size 4 (bytearray)
178 @return rotated data (bytearray)
179 """
180 return data[1:] + data[:1]
181
182 def __getRconValue(self, num):
183 """
184 Private method to retrieve a given Rcon value.
185
186 @param num position of the value (integer)
187 @return Rcon value (integer)
188 """
189 return self.Rcon[num]
190
191 def __core(self, data, iteration):
192 """
193 Private method performing the key schedule core operation.
194
195 @param data data to operate on (bytearray)
196 @param iteration iteration counter (integer)
197 @return modified data (bytearray)
198 """
199 # rotate the 32-bit word 8 bits to the left
200 data = self.__rotate(data)
201 # apply S-Box substitution on all 4 parts of the 32-bit word
202 for i in range(4):
203 data[i] = self.__getSBoxValue(data[i])
204 # XOR the output of the rcon operation with i to the first part
205 # (leftmost) only
206 data[0] = data[0] ^ self.__getRconValue(iteration)
207 return data
208
209 def __expandKey(self, key, size, expandedKeySize):
210 """
211 Private method performing Rijndael's key expansion.
212
213 Expands a 128, 192 or 256 bit key into a 176, 208 or 240 bit key.
214
215 @param key key to be expanded (bytes or bytearray)
216 @param size size of the key in bytes (16, 24 or 32)
217 @param expandedKeySize size of the expanded key (integer)
218 @return expanded key (bytearray)
219 """
220 # current expanded keySize, in bytes
221 currentSize = 0
222 rconIteration = 1
223 expandedKey = bytearray(expandedKeySize)
224
225 # set the 16, 24, 32 bytes of the expanded key to the input key
226 for j in range(size):
227 expandedKey[j] = key[j]
228 currentSize += size
229
230 while currentSize < expandedKeySize:
231 # assign the previous 4 bytes to the temporary value t
232 t = expandedKey[currentSize - 4:currentSize]
233
234 # every 16, 24, 32 bytes we apply the core schedule to t
235 # and increment rconIteration afterwards
236 if currentSize % size == 0:
237 t = self.__core(t, rconIteration)
238 rconIteration += 1
239 # For 256-bit keys, we add an extra sbox to the calculation
240 if size == self.KeySize["SIZE_256"] and \
241 ((currentSize % size) == 16):
242 for l in range(4):
243 t[l] = self.__getSBoxValue(t[l])
244
245 # We XOR t with the four-byte block 16, 24, 32 bytes before the new
246 # expanded key. This becomes the next four bytes in the expanded
247 # key.
248 for m in range(4):
249 expandedKey[currentSize] = \
250 expandedKey[currentSize - size] ^ t[m]
251 currentSize += 1
252
253 return expandedKey
254
255 def __addRoundKey(self, state, roundKey):
256 """
257 Private method to add (XORs) the round key to the state.
258
259 @param state state to be changed (bytearray)
260 @param roundKey key to be used for the modification (bytearray)
261 @return modified state (bytearray)
262 """
263 buf = state[:]
264 for i in range(16):
265 buf[i] ^= roundKey[i]
266 return buf
267
268 def __createRoundKey(self, expandedKey, roundKeyPointer):
269 """
270 Private method to create a round key.
271
272 @param expandedKey expanded key to be used (bytearray)
273 @param roundKeyPointer position within the expanded key (integer)
274 @return round key (bytearray)
275 """
276 roundKey = bytearray(16)
277 for i in range(4):
278 for j in range(4):
279 roundKey[j * 4 + i] = expandedKey[roundKeyPointer + i * 4 + j]
280 return roundKey
281
282 def __galois_multiplication(self, a, b):
283 """
284 Private method to perform a Galois multiplication of 8 bit characters
285 a and b.
286
287 @param a first factor (byte)
288 @param b second factor (byte)
289 @return result (byte)
290 """
291 p = 0
292 for _counter in range(8):
293 if b & 1:
294 p ^= a
295 hi_bit_set = a & 0x80
296 a <<= 1
297 # keep a 8 bit
298 a &= 0xFF
299 if hi_bit_set:
300 a ^= 0x1b
301 b >>= 1
302 return p
303
304 def __subBytes(self, state, isInv):
305 """
306 Private method to substitute all the values from the state with the
307 value in the SBox using the state value as index for the SBox.
308
309 @param state state to be worked on (bytearray)
310 @param isInv flag indicating an inverse operation (boolean)
311 @return modified state (bytearray)
312 """
313 state = state[:]
314 if isInv:
315 getter = self.__getSBoxInvert
316 else:
317 getter = self.__getSBoxValue
318 for i in range(16):
319 state[i] = getter(state[i])
320 return state
321
322 def __shiftRows(self, state, isInv):
323 """
324 Private method to iterate over the 4 rows and call __shiftRow() with
325 that row.
326
327 @param state state to be worked on (bytearray)
328 @param isInv flag indicating an inverse operation (boolean)
329 @return modified state (bytearray)
330 """
331 state = state[:]
332 for i in range(4):
333 state = self.__shiftRow(state, i * 4, i, isInv)
334 return state
335
336 def __shiftRow(self, state, statePointer, nbr, isInv):
337 """
338 Private method to shift the bytes of a row to the left.
339
340 @param state state to be worked on (bytearray)
341 @param statePointer index into the state (integer)
342 @param nbr number of positions to shift (integer)
343 @param isInv flag indicating an inverse operation (boolean)
344 @return modified state (bytearray)
345 """
346 state = state[:]
347 for _ in range(nbr):
348 if isInv:
349 state[statePointer:statePointer + 4] = \
350 state[statePointer + 3:statePointer + 4] + \
351 state[statePointer:statePointer + 3]
352 else:
353 state[statePointer:statePointer + 4] = \
354 state[statePointer + 1:statePointer + 4] + \
355 state[statePointer:statePointer + 1]
356 return state
357
358 def __mixColumns(self, state, isInv):
359 """
360 Private method to perform a galois multiplication of the 4x4 matrix.
361
362 @param state state to be worked on (bytearray)
363 @param isInv flag indicating an inverse operation (boolean)
364 @return modified state (bytearray)
365 """
366 state = state[:]
367 # iterate over the 4 columns
368 for i in range(4):
369 # construct one column by slicing over the 4 rows
370 column = state[i:i + 16:4]
371 # apply the __mixColumn on one column
372 column = self.__mixColumn(column, isInv)
373 # put the values back into the state
374 state[i:i + 16:4] = column
375
376 return state
377
378 # galois multiplication of 1 column of the 4x4 matrix
379 def __mixColumn(self, column, isInv):
380 """
381 Private method to perform a galois multiplication of 1 column the
382 4x4 matrix.
383
384 @param column column to be worked on (bytearray)
385 @param isInv flag indicating an inverse operation (boolean)
386 @return modified column (bytearray)
387 """
388 column = column[:]
389 if isInv:
390 mult = [14, 9, 13, 11]
391 else:
392 mult = [2, 1, 1, 3]
393 cpy = column[:]
394 g = self.__galois_multiplication
395
396 column[0] = (
397 g(cpy[0], mult[0]) ^ g(cpy[3], mult[1]) ^
398 g(cpy[2], mult[2]) ^ g(cpy[1], mult[3])
399 )
400 column[1] = (
401 g(cpy[1], mult[0]) ^ g(cpy[0], mult[1]) ^
402 g(cpy[3], mult[2]) ^ g(cpy[2], mult[3])
403 )
404 column[2] = (
405 g(cpy[2], mult[0]) ^ g(cpy[1], mult[1]) ^
406 g(cpy[0], mult[2]) ^ g(cpy[3], mult[3])
407 )
408 column[3] = (
409 g(cpy[3], mult[0]) ^ g(cpy[2], mult[1]) ^
410 g(cpy[1], mult[2]) ^ g(cpy[0], mult[3])
411 )
412 return column
413
414 def __aes_round(self, state, roundKey):
415 """
416 Private method to apply the 4 operations of the forward round in
417 sequence.
418
419 @param state state to be worked on (bytearray)
420 @param roundKey round key to be used (bytearray)
421 @return modified state (bytearray)
422 """
423 state = self.__subBytes(state, False)
424 state = self.__shiftRows(state, False)
425 state = self.__mixColumns(state, False)
426 state = self.__addRoundKey(state, roundKey)
427 return state
428
429 def __aes_invRound(self, state, roundKey):
430 """
431 Private method to apply the 4 operations of the inverse round in
432 sequence.
433
434 @param state state to be worked on (bytearray)
435 @param roundKey round key to be used (bytearray)
436 @return modified state (bytearray)
437 """
438 state = self.__shiftRows(state, True)
439 state = self.__subBytes(state, True)
440 state = self.__addRoundKey(state, roundKey)
441 state = self.__mixColumns(state, True)
442 return state
443
444 def __aes_main(self, state, expandedKey, nbrRounds):
445 """
446 Private method to do the AES encryption for one round.
447
448 Perform the initial operations, the standard round, and the
449 final operations of the forward AES, creating a round key for
450 each round.
451
452 @param state state to be worked on (bytearray)
453 @param expandedKey expanded key to be used (bytearray)
454 @param nbrRounds number of rounds to be done (integer)
455 @return modified state (bytearray)
456 """
457 state = self.__addRoundKey(
458 state, self.__createRoundKey(expandedKey, 0))
459 i = 1
460 while i < nbrRounds:
461 state = self.__aes_round(
462 state, self.__createRoundKey(expandedKey, 16 * i))
463 i += 1
464 state = self.__subBytes(state, False)
465 state = self.__shiftRows(state, False)
466 state = self.__addRoundKey(
467 state, self.__createRoundKey(expandedKey, 16 * nbrRounds))
468 return state
469
470 def __aes_invMain(self, state, expandedKey, nbrRounds):
471 """
472 Private method to do the inverse AES encryption for one round.
473
474 Perform the initial operations, the standard round, and the
475 final operations of the inverse AES, creating a round key for
476 each round.
477
478 @param state state to be worked on (bytearray)
479 @param expandedKey expanded key to be used (bytearray)
480 @param nbrRounds number of rounds to be done (integer)
481 @return modified state (bytearray)
482 """
483 state = self.__addRoundKey(
484 state, self.__createRoundKey(expandedKey, 16 * nbrRounds))
485 i = nbrRounds - 1
486 while i > 0:
487 state = self.__aes_invRound(
488 state, self.__createRoundKey(expandedKey, 16 * i))
489 i -= 1
490 state = self.__shiftRows(state, True)
491 state = self.__subBytes(state, True)
492 state = self.__addRoundKey(
493 state, self.__createRoundKey(expandedKey, 0))
494 return state
495
496 def encrypt(self, iput, key, size):
497 """
498 Public method to encrypt a 128 bit input block against the given key
499 of size specified.
500
501 @param iput input data (bytearray)
502 @param key key to be used (bytes or bytearray)
503 @param size key size (16, 24 or 32)
504 @return encrypted data (bytes)
505 @exception ValueError key size is invalid
506 """
507 output = bytearray(16)
508 # the number of rounds
509 nbrRounds = 0
510 # the 128 bit block to encode
511 block = bytearray(16)
512 # set the number of rounds
513 if size == self.KeySize["SIZE_128"]:
514 nbrRounds = 10
515 elif size == self.KeySize["SIZE_192"]:
516 nbrRounds = 12
517 elif size == self.KeySize["SIZE_256"]:
518 nbrRounds = 14
519 else:
520 raise ValueError("Wrong key size given ({0}).".format(size))
521
522 # the expanded keySize
523 expandedKeySize = 16 * (nbrRounds + 1)
524
525 # Set the block values, for the block:
526 # a0,0 a0,1 a0,2 a0,3
527 # a1,0 a1,1 a1,2 a1,3
528 # a2,0 a2,1 a2,2 a2,3
529 # a3,0 a3,1 a3,2 a3,3
530 # the mapping order is a0,0 a1,0 a2,0 a3,0 a0,1 a1,1 ... a2,3 a3,3
531 #
532 # iterate over the columns
533 for i in range(4):
534 # iterate over the rows
535 for j in range(4):
536 block[i + j * 4] = iput[i * 4 + j]
537
538 # expand the key into an 176, 208, 240 bytes key
539 # the expanded key
540 expandedKey = self.__expandKey(key, size, expandedKeySize)
541
542 # encrypt the block using the expandedKey
543 block = self.__aes_main(block, expandedKey, nbrRounds)
544
545 # unmap the block again into the output
546 for k in range(4):
547 # iterate over the rows
548 for l in range(4):
549 output[k * 4 + l] = block[k + l * 4]
550 return bytes(output)
551
552 # decrypts a 128 bit input block against the given key of size specified
553 def decrypt(self, iput, key, size):
554 """
555 Public method to decrypt a 128 bit input block against the given key
556 of size specified.
557
558 @param iput input data (bytearray)
559 @param key key to be used (bytes or bytearray)
560 @param size key size (16, 24 or 32)
561 @return decrypted data (bytes)
562 @exception ValueError key size is invalid
563 """
564 output = bytearray(16)
565 # the number of rounds
566 nbrRounds = 0
567 # the 128 bit block to decode
568 block = bytearray(16)
569 # set the number of rounds
570 if size == self.KeySize["SIZE_128"]:
571 nbrRounds = 10
572 elif size == self.KeySize["SIZE_192"]:
573 nbrRounds = 12
574 elif size == self.KeySize["SIZE_256"]:
575 nbrRounds = 14
576 else:
577 raise ValueError("Wrong key size given ({0}).".format(size))
578
579 # the expanded keySize
580 expandedKeySize = 16 * (nbrRounds + 1)
581
582 # Set the block values, for the block:
583 # a0,0 a0,1 a0,2 a0,3
584 # a1,0 a1,1 a1,2 a1,3
585 # a2,0 a2,1 a2,2 a2,3
586 # a3,0 a3,1 a3,2 a3,3
587 # the mapping order is a0,0 a1,0 a2,0 a3,0 a0,1 a1,1 ... a2,3 a3,3
588
589 # iterate over the columns
590 for i in range(4):
591 # iterate over the rows
592 for j in range(4):
593 block[i + j * 4] = iput[i * 4 + j]
594 # expand the key into an 176, 208, 240 bytes key
595 expandedKey = self.__expandKey(key, size, expandedKeySize)
596 # decrypt the block using the expandedKey
597 block = self.__aes_invMain(block, expandedKey, nbrRounds)
598 # unmap the block again into the output
599 for k in range(4):
600 # iterate over the rows
601 for l in range(4):
602 output[k * 4 + l] = block[k + l * 4]
603 return output
604
605
606 class AESModeOfOperation(object):
607 """
608 Class implementing the different AES mode of operations.
609 """
610 aes = AES()
611
612 # structure of supported modes of operation
613 ModeOfOperation = {
614 "OFB": 0,
615 "CFB": 1,
616 "CBC": 2,
617 }
618
619 def __extractBytes(self, inputData, start, end, mode):
620 """
621 Private method to extract a range of bytes from the input.
622
623 @param inputData input data (bytes)
624 @param start start index (integer)
625 @param end end index (integer)
626 @param mode mode of operation (0, 1, 2)
627 @return extracted bytes (bytearray)
628 """
629 if end - start > 16:
630 end = start + 16
631 if mode == self.ModeOfOperation["CBC"]:
632 ar = bytearray(16)
633 else:
634 ar = bytearray()
635
636 i = start
637 j = 0
638 while len(ar) < end - start:
639 ar.append(0)
640 while i < end:
641 ar[j] = inputData[i]
642 j += 1
643 i += 1
644 return ar
645
646 def encrypt(self, inputData, mode, key, size, IV):
647 """
648 Public method to perform the encryption operation.
649
650 @param inputData data to be encrypted (bytes)
651 @param mode mode of operation (0, 1 or 2)
652 @param key key to be used (bytes)
653 @param size length of the key (16, 24 or 32)
654 @param IV initialisation vector (bytearray)
655 @return tuple with mode of operation, length of the input data and
656 the encrypted data (integer, integer, bytes)
657 @exception ValueError key size is invalid or decrypted data is invalid
658 """
659 if len(key) % size:
660 raise ValueError("Illegal size ({0}) for key '{1}'.".format(
661 size, key))
662 if len(IV) % 16:
663 raise ValueError("IV is not a multiple of 16.")
664 # the AES input/output
665 iput = bytearray(16)
666 output = bytearray()
667 ciphertext = bytearray(16)
668 # the output cipher string
669 cipherOut = bytearray()
670 # char firstRound
671 firstRound = True
672 if inputData:
673 for j in range(int(math.ceil(float(len(inputData)) / 16))):
674 start = j * 16
675 end = j * 16 + 16
676 if end > len(inputData):
677 end = len(inputData)
678 plaintext = self.__extractBytes(inputData, start, end, mode)
679 if mode == self.ModeOfOperation["CFB"]:
680 if firstRound:
681 output = self.aes.encrypt(IV, key, size)
682 firstRound = False
683 else:
684 output = self.aes.encrypt(iput, key, size)
685 for i in range(16):
686 if len(plaintext) - 1 < i:
687 ciphertext[i] = 0 ^ output[i]
688 elif len(output) - 1 < i:
689 ciphertext[i] = plaintext[i] ^ 0
690 elif len(plaintext) - 1 < i and len(output) < i:
691 ciphertext[i] = 0 ^ 0
692 else:
693 ciphertext[i] = plaintext[i] ^ output[i]
694 for k in range(end - start):
695 cipherOut.append(ciphertext[k])
696 iput = ciphertext
697 elif mode == self.ModeOfOperation["OFB"]:
698 if firstRound:
699 output = self.aes.encrypt(IV, key, size)
700 firstRound = False
701 else:
702 output = self.aes.encrypt(iput, key, size)
703 for i in range(16):
704 if len(plaintext) - 1 < i:
705 ciphertext[i] = 0 ^ output[i]
706 elif len(output) - 1 < i:
707 ciphertext[i] = plaintext[i] ^ 0
708 elif len(plaintext) - 1 < i and len(output) < i:
709 ciphertext[i] = 0 ^ 0
710 else:
711 ciphertext[i] = plaintext[i] ^ output[i]
712 for k in range(end - start):
713 cipherOut.append(ciphertext[k])
714 iput = output
715 elif mode == self.ModeOfOperation["CBC"]:
716 for i in range(16):
717 if firstRound:
718 iput[i] = plaintext[i] ^ IV[i]
719 else:
720 iput[i] = plaintext[i] ^ ciphertext[i]
721 firstRound = False
722 ciphertext = self.aes.encrypt(iput, key, size)
723 # always 16 bytes because of the padding for CBC
724 for k in range(16):
725 cipherOut.append(ciphertext[k])
726 return mode, len(inputData), bytes(cipherOut)
727
728 # Mode of Operation Decryption
729 # cipherIn - Encrypted String
730 # originalsize - The unencrypted string length - required for CBC
731 # mode - mode of type modeOfOperation
732 # key - a number array of the bit length size
733 # size - the bit length of the key
734 # IV - the 128 bit number array Initilization Vector
735 def decrypt(self, cipherIn, originalsize, mode, key, size, IV):
736 """
737 Public method to perform the decryption operation.
738
739 @param cipherIn data to be decrypted (bytes)
740 @param originalsize unencrypted string length (required for CBC)
741 (integer)
742 @param mode mode of operation (0, 1 or 2)
743 @param key key to be used (bytes)
744 @param size length of the key (16, 24 or 32)
745 @param IV initialisation vector (bytearray)
746 @return decrypted data (bytes)
747 @exception ValueError key size is invalid or decrypted data is invalid
748 """
749 if len(key) % size:
750 raise ValueError("Illegal size ({0}) for key '{1}'.".format(
751 size, key))
752 if len(IV) % 16:
753 raise ValueError("IV is not a multiple of 16.")
754 # the AES input/output
755 ciphertext = bytearray()
756 iput = bytearray()
757 output = bytearray()
758 plaintext = bytearray(16)
759 # the output bytes
760 bytesOut = bytearray()
761 # char firstRound
762 firstRound = True
763 if cipherIn is not None:
764 for j in range(int(math.ceil(float(len(cipherIn)) / 16))):
765 start = j * 16
766 end = j * 16 + 16
767 if j * 16 + 16 > len(cipherIn):
768 end = len(cipherIn)
769 ciphertext = cipherIn[start:end]
770 if mode == self.ModeOfOperation["CFB"]:
771 if firstRound:
772 output = self.aes.encrypt(IV, key, size)
773 firstRound = False
774 else:
775 output = self.aes.encrypt(iput, key, size)
776 for i in range(16):
777 if len(output) - 1 < i:
778 plaintext[i] = 0 ^ ciphertext[i]
779 elif len(ciphertext) - 1 < i:
780 plaintext[i] = output[i] ^ 0
781 elif len(output) - 1 < i and len(ciphertext) < i:
782 plaintext[i] = 0 ^ 0
783 else:
784 plaintext[i] = output[i] ^ ciphertext[i]
785 for k in range(end - start):
786 bytesOut.append(plaintext[k])
787 iput = ciphertext
788 elif mode == self.ModeOfOperation["OFB"]:
789 if firstRound:
790 output = self.aes.encrypt(IV, key, size)
791 firstRound = False
792 else:
793 output = self.aes.encrypt(iput, key, size)
794 for i in range(16):
795 if len(output) - 1 < i:
796 plaintext[i] = 0 ^ ciphertext[i]
797 elif len(ciphertext) - 1 < i:
798 plaintext[i] = output[i] ^ 0
799 elif len(output) - 1 < i and len(ciphertext) < i:
800 plaintext[i] = 0 ^ 0
801 else:
802 plaintext[i] = output[i] ^ ciphertext[i]
803 for k in range(end - start):
804 bytesOut.append(plaintext[k])
805 iput = output
806 elif mode == self.ModeOfOperation["CBC"]:
807 output = self.aes.decrypt(ciphertext, key, size)
808 for i in range(16):
809 if firstRound:
810 plaintext[i] = IV[i] ^ output[i]
811 else:
812 plaintext[i] = iput[i] ^ output[i]
813 firstRound = False
814 if originalsize is not None and originalsize < end:
815 for k in range(originalsize - start):
816 bytesOut.append(plaintext[k])
817 else:
818 for k in range(end - start):
819 bytesOut.append(plaintext[k])
820 iput = ciphertext
821 return bytes(bytesOut)
822
823
824 def encryptData(key, data, mode=AESModeOfOperation.ModeOfOperation["CBC"]):
825 """
826 Module function to encrypt the given data with the given key.
827
828 @param key key to be used for encryption (bytes)
829 @param data data to be encrypted (bytes)
830 @param mode mode of operations (0, 1 or 2)
831 @return encrypted data prepended with the initialization vector (bytes)
832 """
833 key = bytearray(key)
834 if mode == AESModeOfOperation.ModeOfOperation["CBC"]:
835 data = append_PKCS7_padding(data)
836 keysize = len(key)
837 assert keysize in AES.KeySize.values(), \
838 'invalid key size: {0}'.format(keysize)
839 # create a new iv using random data
840 iv = bytearray([i for i in os.urandom(16)])
841 moo = AESModeOfOperation()
842 mode, length, ciph = moo.encrypt(data, mode, key, keysize, iv)
843 # With padding, the original length does not need to be known. It's a bad
844 # idea to store the original message length.
845 # prepend the iv.
846 return bytes(iv) + bytes(ciph)
847
848
849 def decryptData(key, data, mode=AESModeOfOperation.ModeOfOperation["CBC"]):
850 """
851 Module function to decrypt the given data with the given key.
852
853 @param key key to be used for decryption (bytes)
854 @param data data to be decrypted (with initialization vector prepended)
855 (bytes)
856 @param mode mode of operations (0, 1 or 2)
857 @return decrypted data (bytes)
858 """
859 key = bytearray(key)
860 keysize = len(key)
861 assert keysize in AES.KeySize.values(), \
862 'invalid key size: {0}'.format(keysize)
863 # iv is first 16 bytes
864 iv = bytearray(data[:16])
865 data = bytearray(data[16:])
866 moo = AESModeOfOperation()
867 decr = moo.decrypt(data, None, mode, key, keysize, iv)
868 if mode == AESModeOfOperation.ModeOfOperation["CBC"]:
869 decr = strip_PKCS7_padding(decr)
870 return bytes(decr)

eric ide

mercurial