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