2
A pure python (slow) implementation of rijndael with a decent interface
6
from rijndael import rijndael
10
r = rijndael(key, block_size = 16)
12
key must be a string of length 16, 24, or 32
13
blocksize must be 16, 24, or 32. Default is 16
17
ciphertext = r.encrypt(plaintext)
18
plaintext = r.decrypt(ciphertext)
20
If any strings are of the wrong length a ValueError is thrown
23
# ported from the Java reference code by Bram Cohen, April 2001
24
# this code is public domain, unless someone makes
25
# an intellectual property claim against the reference
26
# code, in which case it can be made public domain by
27
# deleting all the comments and renaming all the variables
32
shifts = [[[0, 0], [1, 3], [2, 2], [3, 1]],
33
[[0, 0], [1, 5], [2, 4], [3, 3]],
34
[[0, 0], [1, 7], [3, 5], [4, 4]]]
36
# [keysize][block_size]
37
num_rounds = {16: {16: 10, 24: 12, 32: 14}, 24: {16: 12, 24: 12, 32: 14}, 32: {16: 14, 24: 14, 32: 14}}
39
A = [[1, 1, 1, 1, 1, 0, 0, 0],
40
[0, 1, 1, 1, 1, 1, 0, 0],
41
[0, 0, 1, 1, 1, 1, 1, 0],
42
[0, 0, 0, 1, 1, 1, 1, 1],
43
[1, 0, 0, 0, 1, 1, 1, 1],
44
[1, 1, 0, 0, 0, 1, 1, 1],
45
[1, 1, 1, 0, 0, 0, 1, 1],
46
[1, 1, 1, 1, 0, 0, 0, 1]]
48
# produce log and alog tables, needed for multiplying in the
49
# field GF(2^m) (generator = 3)
52
j = (alog[-1] << 1) ^ alog[-1]
58
for i in xrange(1, 255):
61
# multiply two elements of GF(2^m)
65
return alog[(log[a & 0xFF] + log[b & 0xFF]) % 255]
67
# substitution box based on F^{-1}(x)
68
box = [[0] * 8 for i in xrange(256)]
70
for i in xrange(2, 256):
71
j = alog[255 - log[i]]
73
box[i][t] = (j >> (7 - t)) & 0x01
75
B = [0, 1, 1, 0, 0, 0, 1, 1]
77
# affine transform: box[i] <- B + A*box[i]
78
cox = [[0] * 8 for i in xrange(256)]
83
cox[i][t] ^= A[t][j] * box[i][j]
85
# S-boxes and inverse S-boxes
90
for t in xrange(1, 8):
91
S[i] ^= cox[i][t] << (7-t)
100
AA = [[0] * 8 for i in xrange(4)]
111
while AA[t][i] == 0 and t < 4:
113
assert t != 4, 'G matrix must be invertible'
115
AA[i][j], AA[t][j] = AA[t][j], AA[i][j]
119
AA[i][j] = alog[(255 + log[AA[i][j] & 0xFF] - log[pivot & 0xFF]) % 255]
122
for j in xrange(i+1, 8):
123
AA[t][j] ^= mul(AA[i][j], AA[t][i])
126
iG = [[0] * 4 for i in xrange(4)]
130
iG[i][j] = AA[i][j + 4]
155
for t in xrange(256):
157
T1.append(mul4(s, G[0]))
158
T2.append(mul4(s, G[1]))
159
T3.append(mul4(s, G[2]))
160
T4.append(mul4(s, G[3]))
163
T5.append(mul4(s, iG[0]))
164
T6.append(mul4(s, iG[1]))
165
T7.append(mul4(s, iG[2]))
166
T8.append(mul4(s, iG[3]))
168
U1.append(mul4(t, iG[0]))
169
U2.append(mul4(t, iG[1]))
170
U3.append(mul4(t, iG[2]))
171
U4.append(mul4(t, iG[3]))
176
for t in xrange(1, 30):
199
def __init__(self, key, block_size = 16):
200
if block_size != 16 and block_size != 24 and block_size != 32:
201
raise ValueError('Invalid block size: ' + str(block_size))
202
if len(key) != 16 and len(key) != 24 and len(key) != 32:
203
raise ValueError('Invalid key size: ' + str(len(key)))
204
self.block_size = block_size
206
ROUNDS = num_rounds[len(key)][block_size]
208
# encryption round keys
209
Ke = [[0] * BC for i in xrange(ROUNDS + 1)]
210
# decryption round keys
211
Kd = [[0] * BC for i in xrange(ROUNDS + 1)]
212
ROUND_KEY_COUNT = (ROUNDS + 1) * BC
215
# copy user material bytes into temporary ints
217
for i in xrange(0, KC):
218
tk.append((ord(key[i * 4]) << 24) | (ord(key[i * 4 + 1]) << 16) |
219
(ord(key[i * 4 + 2]) << 8) | ord(key[i * 4 + 3]))
221
# copy values into round key arrays
224
while j < KC and t < ROUND_KEY_COUNT:
225
Ke[t / BC][t % BC] = tk[j]
226
Kd[ROUNDS - (t / BC)][t % BC] = tk[j]
231
while t < ROUND_KEY_COUNT:
232
# extrapolate using phi (the round key evolution function)
234
tk[0] ^= (S[(tt >> 16) & 0xFF] & 0xFF) << 24 ^ \
235
(S[(tt >> 8) & 0xFF] & 0xFF) << 16 ^ \
236
(S[ tt & 0xFF] & 0xFF) << 8 ^ \
237
(S[(tt >> 24) & 0xFF] & 0xFF) ^ \
238
(rcon[rconpointer] & 0xFF) << 24
241
for i in xrange(1, KC):
244
for i in xrange(1, KC / 2):
247
tk[KC / 2] ^= (S[ tt & 0xFF] & 0xFF) ^ \
248
(S[(tt >> 8) & 0xFF] & 0xFF) << 8 ^ \
249
(S[(tt >> 16) & 0xFF] & 0xFF) << 16 ^ \
250
(S[(tt >> 24) & 0xFF] & 0xFF) << 24
251
for i in xrange(KC / 2 + 1, KC):
253
# copy values into round key arrays
255
while j < KC and t < ROUND_KEY_COUNT:
256
Ke[t / BC][t % BC] = tk[j]
257
Kd[ROUNDS - (t / BC)][t % BC] = tk[j]
260
# inverse MixColumn where needed
261
for r in xrange(1, ROUNDS):
264
Kd[r][j] = U1[(tt >> 24) & 0xFF] ^ \
265
U2[(tt >> 16) & 0xFF] ^ \
266
U3[(tt >> 8) & 0xFF] ^ \
271
def encrypt(self, plaintext):
272
if len(plaintext) != self.block_size:
273
raise ValueError('wrong block length, expected ' + str(self.block_size) + ' got ' + str(len(plaintext)))
276
BC = self.block_size / 4
284
s1 = shifts[SC][1][0]
285
s2 = shifts[SC][2][0]
286
s3 = shifts[SC][3][0]
288
# temporary work array
290
# plaintext to ints + key
292
t.append((ord(plaintext[i * 4 ]) << 24 |
293
ord(plaintext[i * 4 + 1]) << 16 |
294
ord(plaintext[i * 4 + 2]) << 8 |
295
ord(plaintext[i * 4 + 3]) ) ^ Ke[0][i])
296
# apply round transforms
297
for r in xrange(1, ROUNDS):
299
a[i] = (T1[(t[ i ] >> 24) & 0xFF] ^
300
T2[(t[(i + s1) % BC] >> 16) & 0xFF] ^
301
T3[(t[(i + s2) % BC] >> 8) & 0xFF] ^
302
T4[ t[(i + s3) % BC] & 0xFF] ) ^ Ke[r][i]
304
# last round is special
308
result.append((S[(t[ i ] >> 24) & 0xFF] ^ (tt >> 24)) & 0xFF)
309
result.append((S[(t[(i + s1) % BC] >> 16) & 0xFF] ^ (tt >> 16)) & 0xFF)
310
result.append((S[(t[(i + s2) % BC] >> 8) & 0xFF] ^ (tt >> 8)) & 0xFF)
311
result.append((S[ t[(i + s3) % BC] & 0xFF] ^ tt ) & 0xFF)
312
return string.join(map(chr, result), '')
314
def decrypt(self, ciphertext):
315
if len(ciphertext) != self.block_size:
316
raise ValueError('wrong block length, expected ' + str(self.block_size) + ' got ' + str(len(ciphertext)))
319
BC = self.block_size / 4
327
s1 = shifts[SC][1][1]
328
s2 = shifts[SC][2][1]
329
s3 = shifts[SC][3][1]
331
# temporary work array
333
# ciphertext to ints + key
335
t[i] = (ord(ciphertext[i * 4 ]) << 24 |
336
ord(ciphertext[i * 4 + 1]) << 16 |
337
ord(ciphertext[i * 4 + 2]) << 8 |
338
ord(ciphertext[i * 4 + 3]) ) ^ Kd[0][i]
339
# apply round transforms
340
for r in xrange(1, ROUNDS):
342
a[i] = (T5[(t[ i ] >> 24) & 0xFF] ^
343
T6[(t[(i + s1) % BC] >> 16) & 0xFF] ^
344
T7[(t[(i + s2) % BC] >> 8) & 0xFF] ^
345
T8[ t[(i + s3) % BC] & 0xFF] ) ^ Kd[r][i]
347
# last round is special
351
result.append((Si[(t[ i ] >> 24) & 0xFF] ^ (tt >> 24)) & 0xFF)
352
result.append((Si[(t[(i + s1) % BC] >> 16) & 0xFF] ^ (tt >> 16)) & 0xFF)
353
result.append((Si[(t[(i + s2) % BC] >> 8) & 0xFF] ^ (tt >> 8)) & 0xFF)
354
result.append((Si[ t[(i + s3) % BC] & 0xFF] ^ tt ) & 0xFF)
355
return string.join(map(chr, result), '')
357
def encrypt(key, block):
358
return rijndael(key, len(block)).encrypt(block)
360
def decrypt(key, block):
361
return rijndael(key, len(block)).decrypt(block)
366
r = rijndael('a' * kl, bl)
367
assert r.decrypt(r.encrypt(b)) == b