Rename the library subdirectory to libsecret
[platform/upstream/libsecret.git] / libsecret / tests / mock / aes.py
1 #!/usr/bin/python
2 #
3 # aes.py: implements AES - Advanced Encryption Standard
4 # from the SlowAES project, http://code.google.com/p/slowaes/
5 #
6 # Copyright (c) 2008    Josh Davis ( http://www.josh-davis.org ),
7 #           Alex Martelli ( http://www.aleax.it )
8 #
9 # Ported from C code written by Laurent Haan ( http://www.progressive-coding.com )
10 #
11 # Licensed under the Apache License, Version 2.0
12 # http://www.apache.org/licenses/
13 #
14 import os
15 import sys
16 import math
17
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)
22
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))
27     numpads = ord(s[-1])
28     if numpads > 16:
29         raise ValueError("String ending with %r can't be PCKS7-padded" % s[-1])
30     return s[:-numpads]
31
32 class AES(object):
33     # valid key sizes
34     keySize = dict(SIZE_128=16, SIZE_192=24, SIZE_256=32)
35
36     # Rijndael S-box
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,
60             0x54, 0xbb, 0x16]
61
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,
86             0x21, 0x0c, 0x7d]
87
88     def getSBoxValue(self,num):
89         """Retrieves a given S-Box Value"""
90         return self.sbox[num]
91
92     def getSBoxInvert(self,num):
93         """Retrieves a given Inverted S-Box Value"""
94         return self.rsbox[num]
95
96     def rotate(self, word):
97         """ Rijndael's key schedule rotate operation.
98
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).
101         """
102         return word[1:] + word[:1]
103
104     # Rijndael Rcon
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,
128             0xe8, 0xcb ]
129
130     def getRconValue(self, num):
131         """Retrieves a given Rcon Value"""
132         return self.Rcon[num]
133
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
139         for i in range(4):
140             word[i] = self.getSBoxValue(word[i])
141         # XOR the output of the rcon operation with i to the first part
142         # (leftmost) only
143         word[0] = word[0] ^ self.getRconValue(iteration)
144         return word
145
146     def expandKey(self, key, size, expandedKeySize):
147         """Rijndael's key expansion.
148
149         Expands an 128,192,256 key into an 176,208,240 bytes key
150
151         expandedKey is a char list of large enough size,
152         key is the non-expanded key.
153         """
154         # current expanded keySize, in bytes
155         currentSize = 0
156         rconIteration = 1
157         expandedKey = [0] * expandedKeySize
158
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]
162         currentSize += size
163
164         while currentSize < expandedKeySize:
165             # assign the previous 4 bytes to the temporary value t
166             t = expandedKey[currentSize-4:currentSize]
167
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)
172                 rconIteration += 1
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])
176
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
179             # key.
180             for m in range(4):
181                 expandedKey[currentSize] = expandedKey[currentSize - size] ^ \
182                         t[m]
183                 currentSize += 1
184
185         return expandedKey
186
187     def addRoundKey(self, state, roundKey):
188         """Adds (XORs) the round key to the state."""
189         for i in range(16):
190             state[i] ^= roundKey[i]
191         return state
192
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.
197         """
198         roundKey = [0] * 16
199         for i in range(4):
200             for j in range(4):
201                 roundKey[j*4+i] = expandedKey[roundKeyPointer + i*4 + j]
202         return roundKey
203
204     def galois_multiplication(self, a, b):
205         """Galois multiplication of 8 bit characters a and b."""
206         p = 0
207         for counter in range(8):
208             if b & 1: p ^= a
209             hi_bit_set = a & 0x80
210             a <<= 1
211             # keep a 8 bit
212             a &= 0xFF
213             if hi_bit_set:
214                 a ^= 0x1b
215             b >>= 1
216         return p
217
218     #
219     # substitute all the values from the state with the value in the SBox
220     # using the state value as index for the SBox
221     #
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])
226         return state
227
228     # iterate over the 4 rows and call shiftRow() with that row
229     def shiftRows(self, state, isInv):
230         for i in range(4):
231             state = self.shiftRow(state, i*4, i, isInv)
232         return state
233
234     # each iteration shifts the row to the left by 1
235     def shiftRow(self, state, statePointer, nbr, isInv):
236         for i in range(nbr):
237             if isInv:
238                 state[statePointer:statePointer+4] = \
239                         state[statePointer+3:statePointer+4] + \
240                         state[statePointer:statePointer+3]
241             else:
242                 state[statePointer:statePointer+4] = \
243                         state[statePointer+1:statePointer+4] + \
244                         state[statePointer:statePointer+1]
245         return state
246
247     # galois multiplication of the 4x4 matrix
248     def mixColumns(self, state, isInv):
249         # iterate over the 4 columns
250         for i in range(4):
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
257
258         return state
259
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]
264         cpy = list(column)
265         g = self.galois_multiplication
266
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])
275         return column
276
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)
283         return state
284
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)
291         return state
292
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))
297         i = 1
298         while i < nbrRounds:
299             state = self.aes_round(state,
300                                    self.createRoundKey(expandedKey, 16*i))
301             i += 1
302         state = self.subBytes(state, False)
303         state = self.shiftRows(state, False)
304         state = self.addRoundKey(state,
305                                  self.createRoundKey(expandedKey, 16*nbrRounds))
306         return state
307
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))
313         i = nbrRounds - 1
314         while i > 0:
315             state = self.aes_invRound(state,
316                                       self.createRoundKey(expandedKey, 16*i))
317             i -= 1
318         state = self.shiftRows(state, True)
319         state = self.subBytes(state, True)
320         state = self.addRoundKey(state, self.createRoundKey(expandedKey, 0))
321         return state
322
323     # encrypts a 128 bit input block against the given key of size specified
324     def encrypt(self, iput, key, size):
325         output = [0] * 16
326         # the number of rounds
327         nbrRounds = 0
328         # the 128 bit block to encode
329         block = [0] * 16
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
334         else: return None
335
336         # the expanded keySize
337         expandedKeySize = 16*(nbrRounds+1)
338
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
345         #
346         # iterate over the columns
347         for i in range(4):
348             # iterate over the rows
349             for j in range(4):
350                 block[(i+(j*4))] = iput[(i*4)+j]
351
352         # expand the key into an 176, 208, 240 bytes key
353         # the expanded key
354         expandedKey = self.expandKey(key, size, expandedKeySize)
355
356         # encrypt the block using the expandedKey
357         block = self.aes_main(block, expandedKey, nbrRounds)
358
359         # unmap the block again into the output
360         for k in range(4):
361             # iterate over the rows
362             for l in range(4):
363                 output[(k*4)+l] = block[(k+(l*4))]
364         return output
365
366     # decrypts a 128 bit input block against the given key of size specified
367     def decrypt(self, iput, key, size):
368         output = [0] * 16
369         # the number of rounds
370         nbrRounds = 0
371         # the 128 bit block to decode
372         block = [0] * 16
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
377         else: return None
378
379         # the expanded keySize
380         expandedKeySize = 16*(nbrRounds+1)
381
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
388
389         # iterate over the columns
390         for i in range(4):
391             # iterate over the rows
392             for j in range(4):
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
399         for k in range(4):
400             # iterate over the rows
401             for l in range(4):
402                 output[(k*4)+l] = block[(k+(l*4))]
403         return output
404
405
406 class AESModeOfOperation(object):
407
408     aes = AES()
409
410     # structure of supported modes of operation
411     modeOfOperation = dict(OFB=0, CFB=1, CBC=2)
412
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
417         else: ar = []
418
419         i = start
420         j = 0
421         while len(ar) < end - start:
422             ar.append(0)
423         while i < end:
424             ar[j] = ord(string[i])
425             j += 1
426             i += 1
427         return ar
428
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):
436         if len(key) % size:
437             return None
438         if len(IV) % 16:
439             return None
440         # the AES input/output
441         plaintext = []
442         iput = [0] * 16
443         output = []
444         ciphertext = [0] * 16
445         # the output cipher string
446         cipherOut = []
447         # char firstRound
448         firstRound = True
449         if stringIn != None:
450             for j in range(int(math.ceil(float(len(stringIn))/16))):
451                 start = j*16
452                 end = j*16+16
453                 if  end > len(stringIn):
454                     end = len(stringIn)
455                 plaintext = self.convertString(stringIn, start, end, mode)
456                 # print 'PT@%s:%s' % (j, plaintext)
457                 if mode == self.modeOfOperation["CFB"]:
458                     if firstRound:
459                         output = self.aes.encrypt(IV, key, size)
460                         firstRound = False
461                     else:
462                         output = self.aes.encrypt(iput, key, size)
463                     for i in range(16):
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
470                         else:
471                             ciphertext[i] = plaintext[i] ^ output[i]
472                     for k in range(end-start):
473                         cipherOut.append(ciphertext[k])
474                     iput = ciphertext
475                 elif mode == self.modeOfOperation["OFB"]:
476                     if firstRound:
477                         output = self.aes.encrypt(IV, key, size)
478                         firstRound = False
479                     else:
480                         output = self.aes.encrypt(iput, key, size)
481                     for i in range(16):
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
488                         else:
489                             ciphertext[i] = plaintext[i] ^ output[i]
490                     for k in range(end-start):
491                         cipherOut.append(ciphertext[k])
492                     iput = output
493                 elif mode == self.modeOfOperation["CBC"]:
494                     for i in range(16):
495                         if firstRound:
496                             iput[i] =  plaintext[i] ^ IV[i]
497                         else:
498                             iput[i] =  plaintext[i] ^ ciphertext[i]
499                     # print 'IP@%s:%s' % (j, iput)
500                     firstRound = False
501                     ciphertext = self.aes.encrypt(iput, key, size)
502                     # always 16 bytes because of the padding for CBC
503                     for k in range(16):
504                         cipherOut.append(ciphertext[k])
505         return mode, len(stringIn), cipherOut
506
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)
516         if len(key) % size:
517             return None
518         if len(IV) % 16:
519             return None
520         # the AES input/output
521         ciphertext = []
522         iput = []
523         output = []
524         plaintext = [0] * 16
525         # the output plain text string
526         stringOut = ''
527         # char firstRound
528         firstRound = True
529         if cipherIn != None:
530             for j in range(int(math.ceil(float(len(cipherIn))/16))):
531                 start = j*16
532                 end = j*16+16
533                 if j*16+16 > len(cipherIn):
534                     end = len(cipherIn)
535                 ciphertext = cipherIn[start:end]
536                 if mode == self.modeOfOperation["CFB"]:
537                     if firstRound:
538                         output = self.aes.encrypt(IV, key, size)
539                         firstRound = False
540                     else:
541                         output = self.aes.encrypt(iput, key, size)
542                     for i in range(16):
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:
548                             plaintext[i] = 0 ^ 0
549                         else:
550                             plaintext[i] = output[i] ^ ciphertext[i]
551                     for k in range(end-start):
552                         stringOut += chr(plaintext[k])
553                     iput = ciphertext
554                 elif mode == self.modeOfOperation["OFB"]:
555                     if firstRound:
556                         output = self.aes.encrypt(IV, key, size)
557                         firstRound = False
558                     else:
559                         output = self.aes.encrypt(iput, key, size)
560                     for i in range(16):
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:
566                             plaintext[i] = 0 ^ 0
567                         else:
568                             plaintext[i] = output[i] ^ ciphertext[i]
569                     for k in range(end-start):
570                         stringOut += chr(plaintext[k])
571                     iput = output
572                 elif mode == self.modeOfOperation["CBC"]:
573                     output = self.aes.decrypt(ciphertext, key, size)
574                     for i in range(16):
575                         if firstRound:
576                             plaintext[i] = IV[i] ^ output[i]
577                         else:
578                             plaintext[i] = iput[i] ^ output[i]
579                     firstRound = False
580                     if originalsize is not None and originalsize < end:
581                         for k in range(originalsize-start):
582                             stringOut += chr(plaintext[k])
583                     else:
584                         for k in range(end-start):
585                             stringOut += chr(plaintext[k])
586                     iput = ciphertext
587         return stringOut
588
589
590 def encryptData(key, data, mode=AESModeOfOperation.modeOfOperation["CBC"]):
591     """encrypt `data` using `key`
592
593     `key` should be a string of bytes.
594
595     returned cipher is a string of bytes prepended with the initialization
596     vector.
597
598     """
599     key = map(ord, key)
600     if mode == AESModeOfOperation.modeOfOperation["CBC"]:
601         data = append_PKCS7_padding(data)
602     keysize = len(key)
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.
610     # prepend the iv.
611     return ''.join(map(chr, iv)) + ''.join(map(chr, ciph))
612
613 def decryptData(key, data, mode=AESModeOfOperation.modeOfOperation["CBC"]):
614     """decrypt `data` using `key`
615
616     `key` should be a string of bytes.
617
618     `data` should have the initialization vector prepended as a string of
619     ordinal values.
620
621     """
622
623     key = map(ord, key)
624     keysize = len(key)
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)
633     return decr
634
635 def generateRandomKey(keysize):
636     """Generates a key from random data of length `keysize`.
637
638     The returned key is a string of bytes.
639
640     """
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)
645
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)
656     print decr