3 # aes.py: implements AES - Advanced Encryption Standard
4 # from the SlowAES project, http://code.google.com/p/slowaes/
6 # Copyright (c) 2008 Josh Davis ( http://www.josh-davis.org ),
7 # Alex Martelli ( http://www.aleax.it )
9 # Ported from C code written by Laurent Haan ( http://www.progressive-coding.com )
11 # Licensed under the Apache License, Version 2.0
12 # http://www.apache.org/licenses/
18 def append_PKCS7_padding(s):
19 """return s padded to a multiple of 16-bytes by PKCS7 padding"""
20 numpads = 16 - (len(s)%16)
21 return s + numpads*chr(numpads)
23 def strip_PKCS7_padding(s):
24 """return s stripped of PKCS7 padding"""
25 if len(s)%16 or not s:
26 raise ValueError("String of len %d can't be PCKS7-padded" % len(s))
29 raise ValueError("String ending with %r can't be PCKS7-padded" % s[-1])
34 keySize = dict(SIZE_128=16, SIZE_192=24, SIZE_256=32)
37 sbox = [0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5, 0x30, 0x01, 0x67,
38 0x2b, 0xfe, 0xd7, 0xab, 0x76, 0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59,
39 0x47, 0xf0, 0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0, 0xb7,
40 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc, 0x34, 0xa5, 0xe5, 0xf1,
41 0x71, 0xd8, 0x31, 0x15, 0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05,
42 0x9a, 0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75, 0x09, 0x83,
43 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0, 0x52, 0x3b, 0xd6, 0xb3, 0x29,
44 0xe3, 0x2f, 0x84, 0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b,
45 0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf, 0xd0, 0xef, 0xaa,
46 0xfb, 0x43, 0x4d, 0x33, 0x85, 0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c,
47 0x9f, 0xa8, 0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5, 0xbc,
48 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2, 0xcd, 0x0c, 0x13, 0xec,
49 0x5f, 0x97, 0x44, 0x17, 0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19,
50 0x73, 0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88, 0x46, 0xee,
51 0xb8, 0x14, 0xde, 0x5e, 0x0b, 0xdb, 0xe0, 0x32, 0x3a, 0x0a, 0x49,
52 0x06, 0x24, 0x5c, 0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79,
53 0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, 0x4e, 0xa9, 0x6c, 0x56, 0xf4,
54 0xea, 0x65, 0x7a, 0xae, 0x08, 0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6,
55 0xb4, 0xc6, 0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a, 0x70,
56 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e, 0x61, 0x35, 0x57, 0xb9,
57 0x86, 0xc1, 0x1d, 0x9e, 0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e,
58 0x94, 0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf, 0x8c, 0xa1,
59 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68, 0x41, 0x99, 0x2d, 0x0f, 0xb0,
62 # Rijndael Inverted S-box
63 rsbox = [0x52, 0x09, 0x6a, 0xd5, 0x30, 0x36, 0xa5, 0x38, 0xbf, 0x40, 0xa3,
64 0x9e, 0x81, 0xf3, 0xd7, 0xfb , 0x7c, 0xe3, 0x39, 0x82, 0x9b, 0x2f,
65 0xff, 0x87, 0x34, 0x8e, 0x43, 0x44, 0xc4, 0xde, 0xe9, 0xcb , 0x54,
66 0x7b, 0x94, 0x32, 0xa6, 0xc2, 0x23, 0x3d, 0xee, 0x4c, 0x95, 0x0b,
67 0x42, 0xfa, 0xc3, 0x4e , 0x08, 0x2e, 0xa1, 0x66, 0x28, 0xd9, 0x24,
68 0xb2, 0x76, 0x5b, 0xa2, 0x49, 0x6d, 0x8b, 0xd1, 0x25 , 0x72, 0xf8,
69 0xf6, 0x64, 0x86, 0x68, 0x98, 0x16, 0xd4, 0xa4, 0x5c, 0xcc, 0x5d,
70 0x65, 0xb6, 0x92 , 0x6c, 0x70, 0x48, 0x50, 0xfd, 0xed, 0xb9, 0xda,
71 0x5e, 0x15, 0x46, 0x57, 0xa7, 0x8d, 0x9d, 0x84 , 0x90, 0xd8, 0xab,
72 0x00, 0x8c, 0xbc, 0xd3, 0x0a, 0xf7, 0xe4, 0x58, 0x05, 0xb8, 0xb3,
73 0x45, 0x06 , 0xd0, 0x2c, 0x1e, 0x8f, 0xca, 0x3f, 0x0f, 0x02, 0xc1,
74 0xaf, 0xbd, 0x03, 0x01, 0x13, 0x8a, 0x6b , 0x3a, 0x91, 0x11, 0x41,
75 0x4f, 0x67, 0xdc, 0xea, 0x97, 0xf2, 0xcf, 0xce, 0xf0, 0xb4, 0xe6,
76 0x73 , 0x96, 0xac, 0x74, 0x22, 0xe7, 0xad, 0x35, 0x85, 0xe2, 0xf9,
77 0x37, 0xe8, 0x1c, 0x75, 0xdf, 0x6e , 0x47, 0xf1, 0x1a, 0x71, 0x1d,
78 0x29, 0xc5, 0x89, 0x6f, 0xb7, 0x62, 0x0e, 0xaa, 0x18, 0xbe, 0x1b ,
79 0xfc, 0x56, 0x3e, 0x4b, 0xc6, 0xd2, 0x79, 0x20, 0x9a, 0xdb, 0xc0,
80 0xfe, 0x78, 0xcd, 0x5a, 0xf4 , 0x1f, 0xdd, 0xa8, 0x33, 0x88, 0x07,
81 0xc7, 0x31, 0xb1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xec, 0x5f , 0x60,
82 0x51, 0x7f, 0xa9, 0x19, 0xb5, 0x4a, 0x0d, 0x2d, 0xe5, 0x7a, 0x9f,
83 0x93, 0xc9, 0x9c, 0xef , 0xa0, 0xe0, 0x3b, 0x4d, 0xae, 0x2a, 0xf5,
84 0xb0, 0xc8, 0xeb, 0xbb, 0x3c, 0x83, 0x53, 0x99, 0x61 , 0x17, 0x2b,
85 0x04, 0x7e, 0xba, 0x77, 0xd6, 0x26, 0xe1, 0x69, 0x14, 0x63, 0x55,
88 def getSBoxValue(self,num):
89 """Retrieves a given S-Box Value"""
92 def getSBoxInvert(self,num):
93 """Retrieves a given Inverted S-Box Value"""
94 return self.rsbox[num]
96 def rotate(self, word):
97 """ Rijndael's key schedule rotate operation.
99 Rotate a word eight bits to the left: eg, rotate(1d2c3a4f) == 2c3a4f1d
100 Word is an char list of size 4 (32 bits overall).
102 return word[1:] + word[:1]
105 Rcon = [0x8d, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36,
106 0x6c, 0xd8, 0xab, 0x4d, 0x9a, 0x2f, 0x5e, 0xbc, 0x63, 0xc6, 0x97,
107 0x35, 0x6a, 0xd4, 0xb3, 0x7d, 0xfa, 0xef, 0xc5, 0x91, 0x39, 0x72,
108 0xe4, 0xd3, 0xbd, 0x61, 0xc2, 0x9f, 0x25, 0x4a, 0x94, 0x33, 0x66,
109 0xcc, 0x83, 0x1d, 0x3a, 0x74, 0xe8, 0xcb, 0x8d, 0x01, 0x02, 0x04,
110 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36, 0x6c, 0xd8, 0xab, 0x4d,
111 0x9a, 0x2f, 0x5e, 0xbc, 0x63, 0xc6, 0x97, 0x35, 0x6a, 0xd4, 0xb3,
112 0x7d, 0xfa, 0xef, 0xc5, 0x91, 0x39, 0x72, 0xe4, 0xd3, 0xbd, 0x61,
113 0xc2, 0x9f, 0x25, 0x4a, 0x94, 0x33, 0x66, 0xcc, 0x83, 0x1d, 0x3a,
114 0x74, 0xe8, 0xcb, 0x8d, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40,
115 0x80, 0x1b, 0x36, 0x6c, 0xd8, 0xab, 0x4d, 0x9a, 0x2f, 0x5e, 0xbc,
116 0x63, 0xc6, 0x97, 0x35, 0x6a, 0xd4, 0xb3, 0x7d, 0xfa, 0xef, 0xc5,
117 0x91, 0x39, 0x72, 0xe4, 0xd3, 0xbd, 0x61, 0xc2, 0x9f, 0x25, 0x4a,
118 0x94, 0x33, 0x66, 0xcc, 0x83, 0x1d, 0x3a, 0x74, 0xe8, 0xcb, 0x8d,
119 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36, 0x6c,
120 0xd8, 0xab, 0x4d, 0x9a, 0x2f, 0x5e, 0xbc, 0x63, 0xc6, 0x97, 0x35,
121 0x6a, 0xd4, 0xb3, 0x7d, 0xfa, 0xef, 0xc5, 0x91, 0x39, 0x72, 0xe4,
122 0xd3, 0xbd, 0x61, 0xc2, 0x9f, 0x25, 0x4a, 0x94, 0x33, 0x66, 0xcc,
123 0x83, 0x1d, 0x3a, 0x74, 0xe8, 0xcb, 0x8d, 0x01, 0x02, 0x04, 0x08,
124 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36, 0x6c, 0xd8, 0xab, 0x4d, 0x9a,
125 0x2f, 0x5e, 0xbc, 0x63, 0xc6, 0x97, 0x35, 0x6a, 0xd4, 0xb3, 0x7d,
126 0xfa, 0xef, 0xc5, 0x91, 0x39, 0x72, 0xe4, 0xd3, 0xbd, 0x61, 0xc2,
127 0x9f, 0x25, 0x4a, 0x94, 0x33, 0x66, 0xcc, 0x83, 0x1d, 0x3a, 0x74,
130 def getRconValue(self, num):
131 """Retrieves a given Rcon Value"""
132 return self.Rcon[num]
134 def core(self, word, iteration):
135 """Key schedule core."""
136 # rotate the 32-bit word 8 bits to the left
137 word = self.rotate(word)
138 # apply S-Box substitution on all 4 parts of the 32-bit word
140 word[i] = self.getSBoxValue(word[i])
141 # XOR the output of the rcon operation with i to the first part
143 word[0] = word[0] ^ self.getRconValue(iteration)
146 def expandKey(self, key, size, expandedKeySize):
147 """Rijndael's key expansion.
149 Expands an 128,192,256 key into an 176,208,240 bytes key
151 expandedKey is a char list of large enough size,
152 key is the non-expanded key.
154 # current expanded keySize, in bytes
157 expandedKey = [0] * expandedKeySize
159 # set the 16, 24, 32 bytes of the expanded key to the input key
160 for j in range(size):
161 expandedKey[j] = key[j]
164 while currentSize < expandedKeySize:
165 # assign the previous 4 bytes to the temporary value t
166 t = expandedKey[currentSize-4:currentSize]
168 # every 16,24,32 bytes we apply the core schedule to t
169 # and increment rconIteration afterwards
170 if currentSize % size == 0:
171 t = self.core(t, rconIteration)
173 # For 256-bit keys, we add an extra sbox to the calculation
174 if size == self.keySize["SIZE_256"] and ((currentSize % size) == 16):
175 for l in range(4): t[l] = self.getSBoxValue(t[l])
177 # We XOR t with the four-byte block 16,24,32 bytes before the new
178 # expanded key. This becomes the next four bytes in the expanded
181 expandedKey[currentSize] = expandedKey[currentSize - size] ^ \
187 def addRoundKey(self, state, roundKey):
188 """Adds (XORs) the round key to the state."""
190 state[i] ^= roundKey[i]
193 def createRoundKey(self, expandedKey, roundKeyPointer):
194 """Create a round key.
195 Creates a round key from the given expanded key and the
196 position within the expanded key.
201 roundKey[j*4+i] = expandedKey[roundKeyPointer + i*4 + j]
204 def galois_multiplication(self, a, b):
205 """Galois multiplication of 8 bit characters a and b."""
207 for counter in range(8):
209 hi_bit_set = a & 0x80
219 # substitute all the values from the state with the value in the SBox
220 # using the state value as index for the SBox
222 def subBytes(self, state, isInv):
223 if isInv: getter = self.getSBoxInvert
224 else: getter = self.getSBoxValue
225 for i in range(16): state[i] = getter(state[i])
228 # iterate over the 4 rows and call shiftRow() with that row
229 def shiftRows(self, state, isInv):
231 state = self.shiftRow(state, i*4, i, isInv)
234 # each iteration shifts the row to the left by 1
235 def shiftRow(self, state, statePointer, nbr, isInv):
238 state[statePointer:statePointer+4] = \
239 state[statePointer+3:statePointer+4] + \
240 state[statePointer:statePointer+3]
242 state[statePointer:statePointer+4] = \
243 state[statePointer+1:statePointer+4] + \
244 state[statePointer:statePointer+1]
247 # galois multiplication of the 4x4 matrix
248 def mixColumns(self, state, isInv):
249 # iterate over the 4 columns
251 # construct one column by slicing over the 4 rows
252 column = state[i:i+16:4]
253 # apply the mixColumn on one column
254 column = self.mixColumn(column, isInv)
255 # put the values back into the state
256 state[i:i+16:4] = column
260 # galois multiplication of 1 column of the 4x4 matrix
261 def mixColumn(self, column, isInv):
262 if isInv: mult = [14, 9, 13, 11]
263 else: mult = [2, 1, 1, 3]
265 g = self.galois_multiplication
267 column[0] = g(cpy[0], mult[0]) ^ g(cpy[3], mult[1]) ^ \
268 g(cpy[2], mult[2]) ^ g(cpy[1], mult[3])
269 column[1] = g(cpy[1], mult[0]) ^ g(cpy[0], mult[1]) ^ \
270 g(cpy[3], mult[2]) ^ g(cpy[2], mult[3])
271 column[2] = g(cpy[2], mult[0]) ^ g(cpy[1], mult[1]) ^ \
272 g(cpy[0], mult[2]) ^ g(cpy[3], mult[3])
273 column[3] = g(cpy[3], mult[0]) ^ g(cpy[2], mult[1]) ^ \
274 g(cpy[1], mult[2]) ^ g(cpy[0], mult[3])
277 # applies the 4 operations of the forward round in sequence
278 def aes_round(self, state, roundKey):
279 state = self.subBytes(state, False)
280 state = self.shiftRows(state, False)
281 state = self.mixColumns(state, False)
282 state = self.addRoundKey(state, roundKey)
285 # applies the 4 operations of the inverse round in sequence
286 def aes_invRound(self, state, roundKey):
287 state = self.shiftRows(state, True)
288 state = self.subBytes(state, True)
289 state = self.addRoundKey(state, roundKey)
290 state = self.mixColumns(state, True)
293 # Perform the initial operations, the standard round, and the final
294 # operations of the forward aes, creating a round key for each round
295 def aes_main(self, state, expandedKey, nbrRounds):
296 state = self.addRoundKey(state, self.createRoundKey(expandedKey, 0))
299 state = self.aes_round(state,
300 self.createRoundKey(expandedKey, 16*i))
302 state = self.subBytes(state, False)
303 state = self.shiftRows(state, False)
304 state = self.addRoundKey(state,
305 self.createRoundKey(expandedKey, 16*nbrRounds))
308 # Perform the initial operations, the standard round, and the final
309 # operations of the inverse aes, creating a round key for each round
310 def aes_invMain(self, state, expandedKey, nbrRounds):
311 state = self.addRoundKey(state,
312 self.createRoundKey(expandedKey, 16*nbrRounds))
315 state = self.aes_invRound(state,
316 self.createRoundKey(expandedKey, 16*i))
318 state = self.shiftRows(state, True)
319 state = self.subBytes(state, True)
320 state = self.addRoundKey(state, self.createRoundKey(expandedKey, 0))
323 # encrypts a 128 bit input block against the given key of size specified
324 def encrypt(self, iput, key, size):
326 # the number of rounds
328 # the 128 bit block to encode
330 # set the number of rounds
331 if size == self.keySize["SIZE_128"]: nbrRounds = 10
332 elif size == self.keySize["SIZE_192"]: nbrRounds = 12
333 elif size == self.keySize["SIZE_256"]: nbrRounds = 14
336 # the expanded keySize
337 expandedKeySize = 16*(nbrRounds+1)
339 # Set the block values, for the block:
340 # a0,0 a0,1 a0,2 a0,3
341 # a1,0 a1,1 a1,2 a1,3
342 # a2,0 a2,1 a2,2 a2,3
343 # a3,0 a3,1 a3,2 a3,3
344 # the mapping order is a0,0 a1,0 a2,0 a3,0 a0,1 a1,1 ... a2,3 a3,3
346 # iterate over the columns
348 # iterate over the rows
350 block[(i+(j*4))] = iput[(i*4)+j]
352 # expand the key into an 176, 208, 240 bytes key
354 expandedKey = self.expandKey(key, size, expandedKeySize)
356 # encrypt the block using the expandedKey
357 block = self.aes_main(block, expandedKey, nbrRounds)
359 # unmap the block again into the output
361 # iterate over the rows
363 output[(k*4)+l] = block[(k+(l*4))]
366 # decrypts a 128 bit input block against the given key of size specified
367 def decrypt(self, iput, key, size):
369 # the number of rounds
371 # the 128 bit block to decode
373 # set the number of rounds
374 if size == self.keySize["SIZE_128"]: nbrRounds = 10
375 elif size == self.keySize["SIZE_192"]: nbrRounds = 12
376 elif size == self.keySize["SIZE_256"]: nbrRounds = 14
379 # the expanded keySize
380 expandedKeySize = 16*(nbrRounds+1)
382 # Set the block values, for the block:
383 # a0,0 a0,1 a0,2 a0,3
384 # a1,0 a1,1 a1,2 a1,3
385 # a2,0 a2,1 a2,2 a2,3
386 # a3,0 a3,1 a3,2 a3,3
387 # the mapping order is a0,0 a1,0 a2,0 a3,0 a0,1 a1,1 ... a2,3 a3,3
389 # iterate over the columns
391 # iterate over the rows
393 block[(i+(j*4))] = iput[(i*4)+j]
394 # expand the key into an 176, 208, 240 bytes key
395 expandedKey = self.expandKey(key, size, expandedKeySize)
396 # decrypt the block using the expandedKey
397 block = self.aes_invMain(block, expandedKey, nbrRounds)
398 # unmap the block again into the output
400 # iterate over the rows
402 output[(k*4)+l] = block[(k+(l*4))]
406 class AESModeOfOperation(object):
410 # structure of supported modes of operation
411 modeOfOperation = dict(OFB=0, CFB=1, CBC=2)
413 # converts a 16 character string into a number array
414 def convertString(self, string, start, end, mode):
415 if end - start > 16: end = start + 16
416 if mode == self.modeOfOperation["CBC"]: ar = [0] * 16
421 while len(ar) < end - start:
424 ar[j] = ord(string[i])
429 # Mode of Operation Encryption
430 # stringIn - Input String
431 # mode - mode of type modeOfOperation
432 # hexKey - a hex key of the bit length size
433 # size - the bit length of the key
434 # hexIV - the 128 bit hex Initilization Vector
435 def encrypt(self, stringIn, mode, key, size, IV):
440 # the AES input/output
444 ciphertext = [0] * 16
445 # the output cipher string
450 for j in range(int(math.ceil(float(len(stringIn))/16))):
453 if end > len(stringIn):
455 plaintext = self.convertString(stringIn, start, end, mode)
456 # print 'PT@%s:%s' % (j, plaintext)
457 if mode == self.modeOfOperation["CFB"]:
459 output = self.aes.encrypt(IV, key, size)
462 output = self.aes.encrypt(iput, key, size)
464 if len(plaintext)-1 < i:
465 ciphertext[i] = 0 ^ output[i]
466 elif len(output)-1 < i:
467 ciphertext[i] = plaintext[i] ^ 0
468 elif len(plaintext)-1 < i and len(output) < i:
469 ciphertext[i] = 0 ^ 0
471 ciphertext[i] = plaintext[i] ^ output[i]
472 for k in range(end-start):
473 cipherOut.append(ciphertext[k])
475 elif mode == self.modeOfOperation["OFB"]:
477 output = self.aes.encrypt(IV, key, size)
480 output = self.aes.encrypt(iput, key, size)
482 if len(plaintext)-1 < i:
483 ciphertext[i] = 0 ^ output[i]
484 elif len(output)-1 < i:
485 ciphertext[i] = plaintext[i] ^ 0
486 elif len(plaintext)-1 < i and len(output) < i:
487 ciphertext[i] = 0 ^ 0
489 ciphertext[i] = plaintext[i] ^ output[i]
490 for k in range(end-start):
491 cipherOut.append(ciphertext[k])
493 elif mode == self.modeOfOperation["CBC"]:
496 iput[i] = plaintext[i] ^ IV[i]
498 iput[i] = plaintext[i] ^ ciphertext[i]
499 # print 'IP@%s:%s' % (j, iput)
501 ciphertext = self.aes.encrypt(iput, key, size)
502 # always 16 bytes because of the padding for CBC
504 cipherOut.append(ciphertext[k])
505 return mode, len(stringIn), cipherOut
507 # Mode of Operation Decryption
508 # cipherIn - Encrypted String
509 # originalsize - The unencrypted string length - required for CBC
510 # mode - mode of type modeOfOperation
511 # key - a number array of the bit length size
512 # size - the bit length of the key
513 # IV - the 128 bit number array Initilization Vector
514 def decrypt(self, cipherIn, originalsize, mode, key, size, IV):
515 # cipherIn = unescCtrlChars(cipherIn)
520 # the AES input/output
525 # the output plain text string
530 for j in range(int(math.ceil(float(len(cipherIn))/16))):
533 if j*16+16 > len(cipherIn):
535 ciphertext = cipherIn[start:end]
536 if mode == self.modeOfOperation["CFB"]:
538 output = self.aes.encrypt(IV, key, size)
541 output = self.aes.encrypt(iput, key, size)
543 if len(output)-1 < i:
544 plaintext[i] = 0 ^ ciphertext[i]
545 elif len(ciphertext)-1 < i:
546 plaintext[i] = output[i] ^ 0
547 elif len(output)-1 < i and len(ciphertext) < i:
550 plaintext[i] = output[i] ^ ciphertext[i]
551 for k in range(end-start):
552 stringOut += chr(plaintext[k])
554 elif mode == self.modeOfOperation["OFB"]:
556 output = self.aes.encrypt(IV, key, size)
559 output = self.aes.encrypt(iput, key, size)
561 if len(output)-1 < i:
562 plaintext[i] = 0 ^ ciphertext[i]
563 elif len(ciphertext)-1 < i:
564 plaintext[i] = output[i] ^ 0
565 elif len(output)-1 < i and len(ciphertext) < i:
568 plaintext[i] = output[i] ^ ciphertext[i]
569 for k in range(end-start):
570 stringOut += chr(plaintext[k])
572 elif mode == self.modeOfOperation["CBC"]:
573 output = self.aes.decrypt(ciphertext, key, size)
576 plaintext[i] = IV[i] ^ output[i]
578 plaintext[i] = iput[i] ^ output[i]
580 if originalsize is not None and originalsize < end:
581 for k in range(originalsize-start):
582 stringOut += chr(plaintext[k])
584 for k in range(end-start):
585 stringOut += chr(plaintext[k])
590 def encryptData(key, data, mode=AESModeOfOperation.modeOfOperation["CBC"]):
591 """encrypt `data` using `key`
593 `key` should be a string of bytes.
595 returned cipher is a string of bytes prepended with the initialization
600 if mode == AESModeOfOperation.modeOfOperation["CBC"]:
601 data = append_PKCS7_padding(data)
603 assert keysize in AES.keySize.values(), 'invalid key size: %s' % keysize
604 # create a new iv using random data
605 iv = [ord(i) for i in os.urandom(16)]
606 moo = AESModeOfOperation()
607 (mode, length, ciph) = moo.encrypt(data, mode, key, keysize, iv)
608 # With padding, the original length does not need to be known. It's a bad
609 # idea to store the original message length.
611 return ''.join(map(chr, iv)) + ''.join(map(chr, ciph))
613 def decryptData(key, data, mode=AESModeOfOperation.modeOfOperation["CBC"]):
614 """decrypt `data` using `key`
616 `key` should be a string of bytes.
618 `data` should have the initialization vector prepended as a string of
625 assert keysize in AES.keySize.values(), 'invalid key size: %s' % keysize
626 # iv is first 16 bytes
627 iv = map(ord, data[:16])
628 data = map(ord, data[16:])
629 moo = AESModeOfOperation()
630 decr = moo.decrypt(data, None, mode, key, keysize, iv)
631 if mode == AESModeOfOperation.modeOfOperation["CBC"]:
632 decr = strip_PKCS7_padding(decr)
635 def generateRandomKey(keysize):
636 """Generates a key from random data of length `keysize`.
638 The returned key is a string of bytes.
641 if keysize not in (16, 24, 32):
642 emsg = 'Invalid keysize, %s. Should be one of (16, 24, 32).'
643 raise ValueError, emsg % keysize
644 return os.urandom(keysize)
646 if __name__ == "__main__":
647 moo = AESModeOfOperation()
648 cleartext = "This is a test!"
649 cypherkey = [143,194,34,208,145,203,230,143,177,246,97,206,145,92,255,84]
650 iv = [103,35,148,239,76,213,47,118,255,222,123,176,106,134,98,92]
651 mode, orig_len, ciph = moo.encrypt(cleartext, moo.modeOfOperation["CBC"],
652 cypherkey, moo.aes.keySize["SIZE_128"], iv)
653 print 'm=%s, ol=%s (%s), ciph=%s' % (mode, orig_len, len(cleartext), ciph)
654 decr = moo.decrypt(ciph, orig_len, mode, cypherkey,
655 moo.aes.keySize["SIZE_128"], iv)