4 # from the SlowAES project, http://code.google.com/p/slowaes/ |
4 # from the SlowAES project, http://code.google.com/p/slowaes/ |
5 # |
5 # |
6 # Copyright (c) 2008 Josh Davis ( http://www.josh-davis.org ), |
6 # Copyright (c) 2008 Josh Davis ( http://www.josh-davis.org ), |
7 # Alex Martelli ( http://www.aleax.it ) |
7 # Alex Martelli ( http://www.aleax.it ) |
8 # |
8 # |
9 # Ported from C code written by Laurent Haan ( http://www.progressive-coding.com ) |
9 # Ported from C code written by Laurent Haan |
|
10 # ( http://www.progressive-coding.com ) |
10 # |
11 # |
11 # Licensed under the Apache License, Version 2.0 |
12 # Licensed under the Apache License, Version 2.0 |
12 # http://www.apache.org/licenses/ |
13 # http://www.apache.org/licenses/ |
13 # |
14 # |
14 |
15 |
44 |
45 |
45 @param b data to be stripped (bytes) |
46 @param b data to be stripped (bytes) |
46 @return stripped data (bytes) |
47 @return stripped data (bytes) |
47 """ |
48 """ |
48 if len(b) % 16 or not b: |
49 if len(b) % 16 or not b: |
49 raise ValueError("Data of len {0} can't be PCKS7-padded".format(len(b))) |
50 raise ValueError( |
|
51 "Data of len {0} can't be PCKS7-padded".format(len(b))) |
50 numpads = b[-1] |
52 numpads = b[-1] |
51 if numpads > 16: |
53 if numpads > 16: |
52 raise ValueError("Data ending with {0} can't be PCKS7-padded".format(b[-1])) |
54 raise ValueError( |
|
55 "Data ending with {0} can't be PCKS7-padded".format(b[-1])) |
53 return b[:-numpads] |
56 return b[:-numpads] |
54 |
57 |
55 |
58 |
56 class AES(object): |
59 class AES(object): |
57 """ |
60 """ |
162 |
165 |
163 def __rotate(self, data): |
166 def __rotate(self, data): |
164 """ |
167 """ |
165 Private method performing Rijndael's key schedule rotate operation. |
168 Private method performing Rijndael's key schedule rotate operation. |
166 |
169 |
167 Rotate the data word eight bits to the left: eg, rotate(1d2c3a4f) == 2c3a4f1d. |
170 Rotate the data word eight bits to the left: eg, |
|
171 rotate(1d2c3a4f) == 2c3a4f1d. |
168 |
172 |
169 @param data data of size 4 (bytearray) |
173 @param data data of size 4 (bytearray) |
170 """ |
174 """ |
171 return data[1:] + data[:1] |
175 return data[1:] + data[:1] |
172 |
176 |
226 # and increment rconIteration afterwards |
230 # and increment rconIteration afterwards |
227 if currentSize % size == 0: |
231 if currentSize % size == 0: |
228 t = self.__core(t, rconIteration) |
232 t = self.__core(t, rconIteration) |
229 rconIteration += 1 |
233 rconIteration += 1 |
230 # For 256-bit keys, we add an extra sbox to the calculation |
234 # For 256-bit keys, we add an extra sbox to the calculation |
231 if size == self.KeySize["SIZE_256"] and ((currentSize % size) == 16): |
235 if size == self.KeySize["SIZE_256"] and \ |
|
236 ((currentSize % size) == 16): |
232 for l in range(4): |
237 for l in range(4): |
233 t[l] = self.__getSBoxValue(t[l]) |
238 t[l] = self.__getSBoxValue(t[l]) |
234 |
239 |
235 # We XOR t with the four-byte block 16, 24, 32 bytes before the new |
240 # We XOR t with the four-byte block 16, 24, 32 bytes before the new |
236 # expanded key. This becomes the next four bytes in the expanded key. |
241 # expanded key. This becomes the next four bytes in the expanded |
|
242 # key. |
237 for m in range(4): |
243 for m in range(4): |
238 expandedKey[currentSize] = \ |
244 expandedKey[currentSize] = \ |
239 expandedKey[currentSize - size] ^ t[m] |
245 expandedKey[currentSize - size] ^ t[m] |
240 currentSize += 1 |
246 currentSize += 1 |
241 |
247 |
268 roundKey[j * 4 + i] = expandedKey[roundKeyPointer + i * 4 + j] |
274 roundKey[j * 4 + i] = expandedKey[roundKeyPointer + i * 4 + j] |
269 return roundKey |
275 return roundKey |
270 |
276 |
271 def __galois_multiplication(self, a, b): |
277 def __galois_multiplication(self, a, b): |
272 """ |
278 """ |
273 Private method to perform a Galois multiplication of 8 bit characters a and b. |
279 Private method to perform a Galois multiplication of 8 bit characters |
|
280 a and b. |
274 |
281 |
275 @param a first factor (byte) |
282 @param a first factor (byte) |
276 @param b second factor (byte) |
283 @param b second factor (byte) |
277 @return result (byte) |
284 @return result (byte) |
278 """ |
285 """ |
289 b >>= 1 |
296 b >>= 1 |
290 return p |
297 return p |
291 |
298 |
292 def __subBytes(self, state, isInv): |
299 def __subBytes(self, state, isInv): |
293 """ |
300 """ |
294 Private method to substitute all the values from the state with the value in |
301 Private method to substitute all the values from the state with the |
295 the SBox using the state value as index for the SBox. |
302 value in the SBox using the state value as index for the SBox. |
296 |
303 |
297 @param state state to be worked on (bytearray) |
304 @param state state to be worked on (bytearray) |
298 @param isInv flag indicating an inverse operation (boolean) |
305 @param isInv flag indicating an inverse operation (boolean) |
299 @return modified state (bytearray) |
306 @return modified state (bytearray) |
300 """ |
307 """ |
364 return state |
371 return state |
365 |
372 |
366 # galois multiplication of 1 column of the 4x4 matrix |
373 # galois multiplication of 1 column of the 4x4 matrix |
367 def __mixColumn(self, column, isInv): |
374 def __mixColumn(self, column, isInv): |
368 """ |
375 """ |
369 Private method to perform a galois multiplication of 1 column the 4x4 matrix. |
376 Private method to perform a galois multiplication of 1 column the |
|
377 4x4 matrix. |
370 |
378 |
371 @param column column to be worked on (bytearray) |
379 @param column column to be worked on (bytearray) |
372 @param isInv flag indicating an inverse operation (boolean) |
380 @param isInv flag indicating an inverse operation (boolean) |
373 @return modified column (bytearray) |
381 @return modified column (bytearray) |
374 """ |
382 """ |
390 g(cpy[1], mult[2]) ^ g(cpy[0], mult[3]) |
398 g(cpy[1], mult[2]) ^ g(cpy[0], mult[3]) |
391 return column |
399 return column |
392 |
400 |
393 def __aes_round(self, state, roundKey): |
401 def __aes_round(self, state, roundKey): |
394 """ |
402 """ |
395 Private method to apply the 4 operations of the forward round in sequence. |
403 Private method to apply the 4 operations of the forward round in |
|
404 sequence. |
396 |
405 |
397 @param state state to be worked on (bytearray) |
406 @param state state to be worked on (bytearray) |
398 @param roundKey round key to be used (bytearray) |
407 @param roundKey round key to be used (bytearray) |
399 @return modified state (bytearray) |
408 @return modified state (bytearray) |
400 """ |
409 """ |
404 state = self.__addRoundKey(state, roundKey) |
413 state = self.__addRoundKey(state, roundKey) |
405 return state |
414 return state |
406 |
415 |
407 def __aes_invRound(self, state, roundKey): |
416 def __aes_invRound(self, state, roundKey): |
408 """ |
417 """ |
409 Private method to apply the 4 operations of the inverse round in sequence. |
418 Private method to apply the 4 operations of the inverse round in |
|
419 sequence. |
410 |
420 |
411 @param state state to be worked on (bytearray) |
421 @param state state to be worked on (bytearray) |
412 @param roundKey round key to be used (bytearray) |
422 @param roundKey round key to be used (bytearray) |
413 @return modified state (bytearray) |
423 @return modified state (bytearray) |
414 """ |
424 """ |
418 state = self.__mixColumns(state, True) |
428 state = self.__mixColumns(state, True) |
419 return state |
429 return state |
420 |
430 |
421 def __aes_main(self, state, expandedKey, nbrRounds): |
431 def __aes_main(self, state, expandedKey, nbrRounds): |
422 """ |
432 """ |
423 Private method to perform the initial operations, the standard round, and the |
433 Private method to do the AES encryption for one round. |
424 final operations of the forward AES, creating a round key for each round. |
434 |
|
435 Perform the initial operations, the standard round, and the |
|
436 final operations of the forward AES, creating a round key for |
|
437 each round. |
425 |
438 |
426 @param state state to be worked on (bytearray) |
439 @param state state to be worked on (bytearray) |
427 @param expandedKey expanded key to be used (bytearray) |
440 @param expandedKey expanded key to be used (bytearray) |
428 @param nbrRounds number of rounds to be done (integer) |
441 @param nbrRounds number of rounds to be done (integer) |
429 @return modified state (bytearray) |
442 @return modified state (bytearray) |
430 """ |
443 """ |
431 state = self.__addRoundKey(state, self.__createRoundKey(expandedKey, 0)) |
444 state = self.__addRoundKey( |
|
445 state, self.__createRoundKey(expandedKey, 0)) |
432 i = 1 |
446 i = 1 |
433 while i < nbrRounds: |
447 while i < nbrRounds: |
434 state = self.__aes_round( |
448 state = self.__aes_round( |
435 state, self.__createRoundKey(expandedKey, 16 * i)) |
449 state, self.__createRoundKey(expandedKey, 16 * i)) |
436 i += 1 |
450 i += 1 |
440 state, self.__createRoundKey(expandedKey, 16 * nbrRounds)) |
454 state, self.__createRoundKey(expandedKey, 16 * nbrRounds)) |
441 return state |
455 return state |
442 |
456 |
443 def __aes_invMain(self, state, expandedKey, nbrRounds): |
457 def __aes_invMain(self, state, expandedKey, nbrRounds): |
444 """ |
458 """ |
445 Private method to perform the initial operations, the standard round, and the |
459 Private method to do the inverse AES encryption for one round. |
446 final operations of the inverse AES, creating a round key for each round. |
460 |
|
461 Perform the initial operations, the standard round, and the |
|
462 final operations of the inverse AES, creating a round key for |
|
463 each round. |
447 |
464 |
448 @param state state to be worked on (bytearray) |
465 @param state state to be worked on (bytearray) |
449 @param expandedKey expanded key to be used (bytearray) |
466 @param expandedKey expanded key to be used (bytearray) |
450 @param nbrRounds number of rounds to be done (integer) |
467 @param nbrRounds number of rounds to be done (integer) |
451 @return modified state (bytearray) |
468 @return modified state (bytearray) |
457 state = self.__aes_invRound( |
474 state = self.__aes_invRound( |
458 state, self.__createRoundKey(expandedKey, 16 * i)) |
475 state, self.__createRoundKey(expandedKey, 16 * i)) |
459 i -= 1 |
476 i -= 1 |
460 state = self.__shiftRows(state, True) |
477 state = self.__shiftRows(state, True) |
461 state = self.__subBytes(state, True) |
478 state = self.__subBytes(state, True) |
462 state = self.__addRoundKey(state, self.__createRoundKey(expandedKey, 0)) |
479 state = self.__addRoundKey( |
|
480 state, self.__createRoundKey(expandedKey, 0)) |
463 return state |
481 return state |
464 |
482 |
465 def encrypt(self, iput, key, size): |
483 def encrypt(self, iput, key, size): |
466 """ |
484 """ |
467 Public method to encrypt a 128 bit input block against the given key of size |
485 Public method to encrypt a 128 bit input block against the given key |
468 specified. |
486 of size specified. |
469 |
487 |
470 @param iput input data (bytearray) |
488 @param iput input data (bytearray) |
471 @param key key to be used (bytes or bytearray) |
489 @param key key to be used (bytes or bytearray) |
472 @param size key size (16, 24 or 32) |
490 @param size key size (16, 24 or 32) |
473 @return encrypted data (bytes) |
491 @return encrypted data (bytes) |
518 return bytes(output) |
536 return bytes(output) |
519 |
537 |
520 # decrypts a 128 bit input block against the given key of size specified |
538 # decrypts a 128 bit input block against the given key of size specified |
521 def decrypt(self, iput, key, size): |
539 def decrypt(self, iput, key, size): |
522 """ |
540 """ |
523 Public method to decrypt a 128 bit input block against the given key of size |
541 Public method to decrypt a 128 bit input block against the given key |
524 specified. |
542 of size specified. |
525 |
543 |
526 @param iput input data (bytearray) |
544 @param iput input data (bytearray) |
527 @param key key to be used (bytes or bytearray) |
545 @param key key to be used (bytes or bytearray) |
528 @param size key size (16, 24 or 32) |
546 @param size key size (16, 24 or 32) |
529 @return decrypted data (bytes) |
547 @return decrypted data (bytes) |
799 """ |
817 """ |
800 key = bytearray(key) |
818 key = bytearray(key) |
801 if mode == AESModeOfOperation.ModeOfOperation["CBC"]: |
819 if mode == AESModeOfOperation.ModeOfOperation["CBC"]: |
802 data = append_PKCS7_padding(data) |
820 data = append_PKCS7_padding(data) |
803 keysize = len(key) |
821 keysize = len(key) |
804 assert keysize in AES.KeySize.values(), 'invalid key size: {0}'.format(keysize) |
822 assert keysize in AES.KeySize.values(), \ |
|
823 'invalid key size: {0}'.format(keysize) |
805 # create a new iv using random data |
824 # create a new iv using random data |
806 iv = bytearray([i for i in os.urandom(16)]) |
825 iv = bytearray([i for i in os.urandom(16)]) |
807 moo = AESModeOfOperation() |
826 moo = AESModeOfOperation() |
808 mode, length, ciph = moo.encrypt(data, mode, key, keysize, iv) |
827 mode, length, ciph = moo.encrypt(data, mode, key, keysize, iv) |
809 # With padding, the original length does not need to be known. It's a bad |
828 # With padding, the original length does not need to be known. It's a bad |
815 def decryptData(key, data, mode=AESModeOfOperation.ModeOfOperation["CBC"]): |
834 def decryptData(key, data, mode=AESModeOfOperation.ModeOfOperation["CBC"]): |
816 """ |
835 """ |
817 Module function to decrypt the given data with the given key. |
836 Module function to decrypt the given data with the given key. |
818 |
837 |
819 @param key key to be used for decryption (bytes) |
838 @param key key to be used for decryption (bytes) |
820 @param data data to be decrypted (with initialization vector prepended) (bytes) |
839 @param data data to be decrypted (with initialization vector prepended) |
|
840 (bytes) |
821 @param mode mode of operations (0, 1 or 2) |
841 @param mode mode of operations (0, 1 or 2) |
822 @return decrypted data (bytes) |
842 @return decrypted data (bytes) |
823 @exception ValueError key size is invalid or decrypted data is invalid |
843 @exception ValueError key size is invalid or decrypted data is invalid |
824 """ |
844 """ |
825 key = bytearray(key) |
845 key = bytearray(key) |