1
2
3
4
5
6
7
8 """
9 A pure python (slow) implementation of rijndael with a decent interface
10
11 To include -
12
13 from rijndael import rijndael
14
15 To do a key setup -
16
17 r = rijndael(key, block_size = 16)
18
19 key must be a string of length 16, 24, or 32
20 blocksize must be 16, 24, or 32. Default is 16
21
22 To use -
23
24 ciphertext = r.encrypt(plaintext)
25 plaintext = r.decrypt(ciphertext)
26
27 If any strings are of the wrong length a ValueError is thrown
28 """
29
30
31
32
33
34
35
36 import copy
37 import string
38
39
40
41
42
43
44 import os
45 if os.name != "java":
46 import exceptions
47 if hasattr(exceptions, "FutureWarning"):
48 import warnings
49 warnings.filterwarnings("ignore", category=FutureWarning, append=1)
50
51
52
53
54 shifts = [[[0, 0], [1, 3], [2, 2], [3, 1]],
55 [[0, 0], [1, 5], [2, 4], [3, 3]],
56 [[0, 0], [1, 7], [3, 5], [4, 4]]]
57
58
59 num_rounds = {16: {16: 10, 24: 12, 32: 14}, 24: {16: 12, 24: 12, 32: 14}, 32: {16: 14, 24: 14, 32: 14}}
60
61 A = [[1, 1, 1, 1, 1, 0, 0, 0],
62 [0, 1, 1, 1, 1, 1, 0, 0],
63 [0, 0, 1, 1, 1, 1, 1, 0],
64 [0, 0, 0, 1, 1, 1, 1, 1],
65 [1, 0, 0, 0, 1, 1, 1, 1],
66 [1, 1, 0, 0, 0, 1, 1, 1],
67 [1, 1, 1, 0, 0, 0, 1, 1],
68 [1, 1, 1, 1, 0, 0, 0, 1]]
69
70
71
72 alog = [1]
73 for i in xrange(255):
74 j = (alog[-1] << 1) ^ alog[-1]
75 if j & 0x100 != 0:
76 j ^= 0x11B
77 alog.append(j)
78
79 log = [0] * 256
80 for i in xrange(1, 255):
81 log[alog[i]] = i
82
83
85 if a == 0 or b == 0:
86 return 0
87 return alog[(log[a & 0xFF] + log[b & 0xFF]) % 255]
88
89
90 box = [[0] * 8 for i in xrange(256)]
91 box[1][7] = 1
92 for i in xrange(2, 256):
93 j = alog[255 - log[i]]
94 for t in xrange(8):
95 box[i][t] = (j >> (7 - t)) & 0x01
96
97 B = [0, 1, 1, 0, 0, 0, 1, 1]
98
99
100 cox = [[0] * 8 for i in xrange(256)]
101 for i in xrange(256):
102 for t in xrange(8):
103 cox[i][t] = B[t]
104 for j in xrange(8):
105 cox[i][t] ^= A[t][j] * box[i][j]
106
107
108 S = [0] * 256
109 Si = [0] * 256
110 for i in xrange(256):
111 S[i] = cox[i][0] << 7
112 for t in xrange(1, 8):
113 S[i] ^= cox[i][t] << (7-t)
114 Si[S[i] & 0xFF] = i
115
116
117 G = [[2, 1, 1, 3],
118 [3, 2, 1, 1],
119 [1, 3, 2, 1],
120 [1, 1, 3, 2]]
121
122 AA = [[0] * 8 for i in xrange(4)]
123
124 for i in xrange(4):
125 for j in xrange(4):
126 AA[i][j] = G[i][j]
127 AA[i][i+4] = 1
128
129 for i in xrange(4):
130 pivot = AA[i][i]
131 if pivot == 0:
132 t = i + 1
133 while AA[t][i] == 0 and t < 4:
134 t += 1
135 assert t != 4, 'G matrix must be invertible'
136 for j in xrange(8):
137 AA[i][j], AA[t][j] = AA[t][j], AA[i][j]
138 pivot = AA[i][i]
139 for j in xrange(8):
140 if AA[i][j] != 0:
141 AA[i][j] = alog[(255 + log[AA[i][j] & 0xFF] - log[pivot & 0xFF]) % 255]
142 for t in xrange(4):
143 if i != t:
144 for j in xrange(i+1, 8):
145 AA[t][j] ^= mul(AA[i][j], AA[t][i])
146 AA[t][i] = 0
147
148 iG = [[0] * 4 for i in xrange(4)]
149
150 for i in xrange(4):
151 for j in xrange(4):
152 iG[i][j] = AA[i][j + 4]
153
155 if a == 0:
156 return 0
157 r = 0
158 for b in bs:
159 r <<= 8
160 if b != 0:
161 r = r | mul(a, b)
162 return r
163
164 T1 = []
165 T2 = []
166 T3 = []
167 T4 = []
168 T5 = []
169 T6 = []
170 T7 = []
171 T8 = []
172 U1 = []
173 U2 = []
174 U3 = []
175 U4 = []
176
177 for t in xrange(256):
178 s = S[t]
179 T1.append(mul4(s, G[0]))
180 T2.append(mul4(s, G[1]))
181 T3.append(mul4(s, G[2]))
182 T4.append(mul4(s, G[3]))
183
184 s = Si[t]
185 T5.append(mul4(s, iG[0]))
186 T6.append(mul4(s, iG[1]))
187 T7.append(mul4(s, iG[2]))
188 T8.append(mul4(s, iG[3]))
189
190 U1.append(mul4(t, iG[0]))
191 U2.append(mul4(t, iG[1]))
192 U3.append(mul4(t, iG[2]))
193 U4.append(mul4(t, iG[3]))
194
195
196 rcon = [1]
197 r = 1
198 for t in xrange(1, 30):
199 r = mul(2, r)
200 rcon.append(r)
201
202 del A
203 del AA
204 del pivot
205 del B
206 del G
207 del box
208 del log
209 del alog
210 del i
211 del j
212 del r
213 del s
214 del t
215 del mul
216 del mul4
217 del cox
218 del iG
219
221 - def __init__(self, key, block_size = 16):
222 if block_size != 16 and block_size != 24 and block_size != 32:
223 raise ValueError('Invalid block size: ' + str(block_size))
224 if len(key) != 16 and len(key) != 24 and len(key) != 32:
225 raise ValueError('Invalid key size: ' + str(len(key)))
226 self.block_size = block_size
227
228 ROUNDS = num_rounds[len(key)][block_size]
229 BC = block_size // 4
230
231 Ke = [[0] * BC for i in xrange(ROUNDS + 1)]
232
233 Kd = [[0] * BC for i in xrange(ROUNDS + 1)]
234 ROUND_KEY_COUNT = (ROUNDS + 1) * BC
235 KC = len(key) // 4
236
237
238 tk = []
239 for i in xrange(0, KC):
240 tk.append((ord(key[i * 4]) << 24) | (ord(key[i * 4 + 1]) << 16) |
241 (ord(key[i * 4 + 2]) << 8) | ord(key[i * 4 + 3]))
242
243
244 t = 0
245 j = 0
246 while j < KC and t < ROUND_KEY_COUNT:
247 Ke[t // BC][t % BC] = tk[j]
248 Kd[ROUNDS - (t // BC)][t % BC] = tk[j]
249 j += 1
250 t += 1
251 tt = 0
252 rconpointer = 0
253 while t < ROUND_KEY_COUNT:
254
255 tt = tk[KC - 1]
256 tk[0] ^= (S[(tt >> 16) & 0xFF] & 0xFF) << 24 ^ \
257 (S[(tt >> 8) & 0xFF] & 0xFF) << 16 ^ \
258 (S[ tt & 0xFF] & 0xFF) << 8 ^ \
259 (S[(tt >> 24) & 0xFF] & 0xFF) ^ \
260 (rcon[rconpointer] & 0xFF) << 24
261 rconpointer += 1
262 if KC != 8:
263 for i in xrange(1, KC):
264 tk[i] ^= tk[i-1]
265 else:
266 for i in xrange(1, KC // 2):
267 tk[i] ^= tk[i-1]
268 tt = tk[KC // 2 - 1]
269 tk[KC // 2] ^= (S[ tt & 0xFF] & 0xFF) ^ \
270 (S[(tt >> 8) & 0xFF] & 0xFF) << 8 ^ \
271 (S[(tt >> 16) & 0xFF] & 0xFF) << 16 ^ \
272 (S[(tt >> 24) & 0xFF] & 0xFF) << 24
273 for i in xrange(KC // 2 + 1, KC):
274 tk[i] ^= tk[i-1]
275
276 j = 0
277 while j < KC and t < ROUND_KEY_COUNT:
278 Ke[t // BC][t % BC] = tk[j]
279 Kd[ROUNDS - (t // BC)][t % BC] = tk[j]
280 j += 1
281 t += 1
282
283 for r in xrange(1, ROUNDS):
284 for j in xrange(BC):
285 tt = Kd[r][j]
286 Kd[r][j] = U1[(tt >> 24) & 0xFF] ^ \
287 U2[(tt >> 16) & 0xFF] ^ \
288 U3[(tt >> 8) & 0xFF] ^ \
289 U4[ tt & 0xFF]
290 self.Ke = Ke
291 self.Kd = Kd
292
294 if len(plaintext) != self.block_size:
295 raise ValueError('wrong block length, expected ' + str(self.block_size) + ' got ' + str(len(plaintext)))
296 Ke = self.Ke
297
298 BC = self.block_size // 4
299 ROUNDS = len(Ke) - 1
300 if BC == 4:
301 SC = 0
302 elif BC == 6:
303 SC = 1
304 else:
305 SC = 2
306 s1 = shifts[SC][1][0]
307 s2 = shifts[SC][2][0]
308 s3 = shifts[SC][3][0]
309 a = [0] * BC
310
311 t = []
312
313 for i in xrange(BC):
314 t.append((ord(plaintext[i * 4 ]) << 24 |
315 ord(plaintext[i * 4 + 1]) << 16 |
316 ord(plaintext[i * 4 + 2]) << 8 |
317 ord(plaintext[i * 4 + 3]) ) ^ Ke[0][i])
318
319 for r in xrange(1, ROUNDS):
320 for i in xrange(BC):
321 a[i] = (T1[(t[ i ] >> 24) & 0xFF] ^
322 T2[(t[(i + s1) % BC] >> 16) & 0xFF] ^
323 T3[(t[(i + s2) % BC] >> 8) & 0xFF] ^
324 T4[ t[(i + s3) % BC] & 0xFF] ) ^ Ke[r][i]
325 t = copy.copy(a)
326
327 result = []
328 for i in xrange(BC):
329 tt = Ke[ROUNDS][i]
330 result.append((S[(t[ i ] >> 24) & 0xFF] ^ (tt >> 24)) & 0xFF)
331 result.append((S[(t[(i + s1) % BC] >> 16) & 0xFF] ^ (tt >> 16)) & 0xFF)
332 result.append((S[(t[(i + s2) % BC] >> 8) & 0xFF] ^ (tt >> 8)) & 0xFF)
333 result.append((S[ t[(i + s3) % BC] & 0xFF] ^ tt ) & 0xFF)
334 return string.join(map(chr, result), '')
335
337 if len(ciphertext) != self.block_size:
338 raise ValueError('wrong block length, expected ' + str(self.block_size) + ' got ' + str(len(plaintext)))
339 Kd = self.Kd
340
341 BC = self.block_size // 4
342 ROUNDS = len(Kd) - 1
343 if BC == 4:
344 SC = 0
345 elif BC == 6:
346 SC = 1
347 else:
348 SC = 2
349 s1 = shifts[SC][1][1]
350 s2 = shifts[SC][2][1]
351 s3 = shifts[SC][3][1]
352 a = [0] * BC
353
354 t = [0] * BC
355
356 for i in xrange(BC):
357 t[i] = (ord(ciphertext[i * 4 ]) << 24 |
358 ord(ciphertext[i * 4 + 1]) << 16 |
359 ord(ciphertext[i * 4 + 2]) << 8 |
360 ord(ciphertext[i * 4 + 3]) ) ^ Kd[0][i]
361
362 for r in xrange(1, ROUNDS):
363 for i in xrange(BC):
364 a[i] = (T5[(t[ i ] >> 24) & 0xFF] ^
365 T6[(t[(i + s1) % BC] >> 16) & 0xFF] ^
366 T7[(t[(i + s2) % BC] >> 8) & 0xFF] ^
367 T8[ t[(i + s3) % BC] & 0xFF] ) ^ Kd[r][i]
368 t = copy.copy(a)
369
370 result = []
371 for i in xrange(BC):
372 tt = Kd[ROUNDS][i]
373 result.append((Si[(t[ i ] >> 24) & 0xFF] ^ (tt >> 24)) & 0xFF)
374 result.append((Si[(t[(i + s1) % BC] >> 16) & 0xFF] ^ (tt >> 16)) & 0xFF)
375 result.append((Si[(t[(i + s2) % BC] >> 8) & 0xFF] ^ (tt >> 8)) & 0xFF)
376 result.append((Si[ t[(i + s3) % BC] & 0xFF] ^ tt ) & 0xFF)
377 return string.join(map(chr, result), '')
378
381
384
390 t(16, 16)
391 t(16, 24)
392 t(16, 32)
393 t(24, 16)
394 t(24, 24)
395 t(24, 32)
396 t(32, 16)
397 t(32, 24)
398 t(32, 32)
399