| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419 | 
							- """
 
- Copyright (c) 2014  Philippe Teuwen <phil@teuwen.org>
 
- Permission is hereby granted, free of charge, to any person obtaining a copy of 
 
- this software and associated documentation files (the "Software"), to deal in 
 
- the Software without restriction, including without limitation the rights to
 
- use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
 
- of the Software, and to permit persons to whom the Software is furnished to do
 
- so, subject to the following conditions:
 
- The above copyright notice and this permission notice shall be included in all
 
- copies or substantial portions of the Software.
 
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 
 
- FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 
 
- IN THE SOFTWARE.
 
- This code is taken from https://github.com/doegox/python-cryptoplus/
 
- A pure python (slow) implementation of rijndael with a decent interface
 
- To include -
 
- from rijndael import rijndael
 
- To do a key setup -
 
- r = rijndael(key, block_size = 16)
 
- key must be a string of length 16, 24, or 32
 
- blocksize must be 16, 24, or 32. Default is 16
 
- To use -
 
- ciphertext = r.encrypt(plaintext)
 
- plaintext = r.decrypt(ciphertext)
 
- If any strings are of the wrong length a ValueError is thrown
 
- """
 
- # ported from the Java reference code by Bram Cohen, bram@gawth.com, April 2001
 
- # this code is public domain, unless someone makes
 
- # an intellectual property claim against the reference
 
- # code, in which case it can be made public domain by
 
- # deleting all the comments and renaming all the variables
 
- import copy
 
- #-----------------------
 
- #TREV - ADDED BECAUSE THERE'S WARNINGS ABOUT INT OVERFLOW BEHAVIOR CHANGING IN
 
- #2.4.....
 
- #import os
 
- #if os.name != "java":
 
- #    import exceptions
 
- #    if hasattr(exceptions, "FutureWarning"):
 
- #        import warnings
 
- #        warnings.filterwarnings("ignore", category=FutureWarning, append=1)
 
- #-----------------------
 
- shifts = [[[0, 0], [1, 3], [2, 2], [3, 1]],
 
-           [[0, 0], [1, 5], [2, 4], [3, 3]],
 
-           [[0, 0], [1, 7], [3, 5], [4, 4]]]
 
- # [keysize][block_size]
 
- num_rounds = {16: {16: 10, 24: 12, 32: 14}, 24: {16: 12, 24: 12, 32: 14}, 32: {16: 14, 24: 14, 32: 14}}
 
- A = [[1, 1, 1, 1, 1, 0, 0, 0],
 
-      [0, 1, 1, 1, 1, 1, 0, 0],
 
-      [0, 0, 1, 1, 1, 1, 1, 0],
 
-      [0, 0, 0, 1, 1, 1, 1, 1],
 
-      [1, 0, 0, 0, 1, 1, 1, 1],
 
-      [1, 1, 0, 0, 0, 1, 1, 1],
 
-      [1, 1, 1, 0, 0, 0, 1, 1],
 
-      [1, 1, 1, 1, 0, 0, 0, 1]]
 
- # produce log and alog tables, needed for multiplying in the
 
- # field GF(2^m) (generator = 3)
 
- alog = [1]
 
- for i in range(255):
 
-     j = (alog[-1] << 1) ^ alog[-1]
 
-     if j & 0x100 != 0:
 
-         j ^= 0x11B
 
-     alog.append(j)
 
- log = [0] * 256
 
- for i in range(1, 255):
 
-     log[alog[i]] = i
 
- # multiply two elements of GF(2^m)
 
- def mul(a, b):
 
-     if a == 0 or b == 0:
 
-         return 0
 
-     return alog[(log[a & 0xFF] + log[b & 0xFF]) % 255]
 
- # substitution box based on F^{-1}(x)
 
- box = [[0] * 8 for i in range(256)]
 
- box[1][7] = 1
 
- for i in range(2, 256):
 
-     j = alog[255 - log[i]]
 
-     for t in range(8):
 
-         box[i][t] = (j >> (7 - t)) & 0x01
 
- B = [0, 1, 1, 0, 0, 0, 1, 1]
 
- # affine transform:  box[i] <- B + A*box[i]
 
- cox = [[0] * 8 for i in range(256)]
 
- for i in range(256):
 
-     for t in range(8):
 
-         cox[i][t] = B[t]
 
-         for j in range(8):
 
-             cox[i][t] ^= A[t][j] * box[i][j]
 
- # S-boxes and inverse S-boxes
 
- S =  [0] * 256
 
- Si = [0] * 256
 
- for i in range(256):
 
-     S[i] = cox[i][0] << 7
 
-     for t in range(1, 8):
 
-         S[i] ^= cox[i][t] << (7-t)
 
-     Si[S[i] & 0xFF] = i
 
- # T-boxes
 
- G = [[2, 1, 1, 3],
 
-     [3, 2, 1, 1],
 
-     [1, 3, 2, 1],
 
-     [1, 1, 3, 2]]
 
- AA = [[0] * 8 for i in range(4)]
 
- for i in range(4):
 
-     for j in range(4):
 
-         AA[i][j] = G[i][j]
 
-         AA[i][i+4] = 1
 
- for i in range(4):
 
-     pivot = AA[i][i]
 
-     if pivot == 0:
 
-         t = i + 1
 
-         while AA[t][i] == 0 and t < 4:
 
-             t += 1
 
-             assert t != 4, 'G matrix must be invertible'
 
-             for j in range(8):
 
-                 AA[i][j], AA[t][j] = AA[t][j], AA[i][j]
 
-             pivot = AA[i][i]
 
-     for j in range(8):
 
-         if AA[i][j] != 0:
 
-             AA[i][j] = alog[(255 + log[AA[i][j] & 0xFF] - log[pivot & 0xFF]) % 255]
 
-     for t in range(4):
 
-         if i != t:
 
-             for j in range(i+1, 8):
 
-                 AA[t][j] ^= mul(AA[i][j], AA[t][i])
 
-             AA[t][i] = 0
 
- iG = [[0] * 4 for i in range(4)]
 
- for i in range(4):
 
-     for j in range(4):
 
-         iG[i][j] = AA[i][j + 4]
 
- def mul4(a, bs):
 
-     if a == 0:
 
-         return 0
 
-     r = 0
 
-     for b in bs:
 
-         r <<= 8
 
-         if b != 0:
 
-             r = r | mul(a, b)
 
-     return r
 
- T1 = []
 
- T2 = []
 
- T3 = []
 
- T4 = []
 
- T5 = []
 
- T6 = []
 
- T7 = []
 
- T8 = []
 
- U1 = []
 
- U2 = []
 
- U3 = []
 
- U4 = []
 
- for t in range(256):
 
-     s = S[t]
 
-     T1.append(mul4(s, G[0]))
 
-     T2.append(mul4(s, G[1]))
 
-     T3.append(mul4(s, G[2]))
 
-     T4.append(mul4(s, G[3]))
 
-     s = Si[t]
 
-     T5.append(mul4(s, iG[0]))
 
-     T6.append(mul4(s, iG[1]))
 
-     T7.append(mul4(s, iG[2]))
 
-     T8.append(mul4(s, iG[3]))
 
-     U1.append(mul4(t, iG[0]))
 
-     U2.append(mul4(t, iG[1]))
 
-     U3.append(mul4(t, iG[2]))
 
-     U4.append(mul4(t, iG[3]))
 
- # round constants
 
- rcon = [1]
 
- r = 1
 
- for t in range(1, 30):
 
-     r = mul(2, r)
 
-     rcon.append(r)
 
- del A
 
- del AA
 
- del pivot
 
- del B
 
- del G
 
- del box
 
- del log
 
- del alog
 
- del i
 
- del j
 
- del r
 
- del s
 
- del t
 
- del mul
 
- del mul4
 
- del cox
 
- del iG
 
- class rijndael:
 
-     def __init__(self, key, block_size = 16):
 
-         if block_size != 16 and block_size != 24 and block_size != 32:
 
-             raise ValueError('Invalid block size: ' + str(block_size))
 
-         if len(key) != 16 and len(key) != 24 and len(key) != 32:
 
-             raise ValueError('Invalid key size: ' + str(len(key)))
 
-         self.block_size = block_size
 
-         ROUNDS = num_rounds[len(key)][block_size]
 
-         BC = block_size // 4
 
-         # encryption round keys
 
-         Ke = [[0] * BC for i in range(ROUNDS + 1)]
 
-         # decryption round keys
 
-         Kd = [[0] * BC for i in range(ROUNDS + 1)]
 
-         ROUND_KEY_COUNT = (ROUNDS + 1) * BC
 
-         KC = len(key) // 4
 
-         # copy user material bytes into temporary ints
 
-         tk = []
 
-         for i in range(0, KC):
 
-             tk.append((ord(key[i * 4]) << 24) | (ord(key[i * 4 + 1]) << 16) |
 
-                 (ord(key[i * 4 + 2]) << 8) | ord(key[i * 4 + 3]))
 
-         # copy values into round key arrays
 
-         t = 0
 
-         j = 0
 
-         while j < KC and t < ROUND_KEY_COUNT:
 
-             Ke[t // BC][t % BC] = tk[j]
 
-             Kd[ROUNDS - (t // BC)][t % BC] = tk[j]
 
-             j += 1
 
-             t += 1
 
-         tt = 0
 
-         rconpointer = 0
 
-         while t < ROUND_KEY_COUNT:
 
-             # extrapolate using phi (the round key evolution function)
 
-             tt = tk[KC - 1]
 
-             tk[0] ^= (S[(tt >> 16) & 0xFF] & 0xFF) << 24 ^  \
 
-                      (S[(tt >>  8) & 0xFF] & 0xFF) << 16 ^  \
 
-                      (S[ tt        & 0xFF] & 0xFF) <<  8 ^  \
 
-                      (S[(tt >> 24) & 0xFF] & 0xFF)       ^  \
 
-                      (rcon[rconpointer]    & 0xFF) << 24
 
-             rconpointer += 1
 
-             if KC != 8:
 
-                 for i in range(1, KC):
 
-                     tk[i] ^= tk[i-1]
 
-             else:
 
-                 for i in range(1, KC // 2):
 
-                     tk[i] ^= tk[i-1]
 
-                 tt = tk[KC // 2 - 1]
 
-                 tk[KC // 2] ^= (S[ tt        & 0xFF] & 0xFF)       ^ \
 
-                                (S[(tt >>  8) & 0xFF] & 0xFF) <<  8 ^ \
 
-                                (S[(tt >> 16) & 0xFF] & 0xFF) << 16 ^ \
 
-                                (S[(tt >> 24) & 0xFF] & 0xFF) << 24
 
-                 for i in range(KC // 2 + 1, KC):
 
-                     tk[i] ^= tk[i-1]
 
-             # copy values into round key arrays
 
-             j = 0
 
-             while j < KC and t < ROUND_KEY_COUNT:
 
-                 Ke[t // BC][t % BC] = tk[j]
 
-                 Kd[ROUNDS - (t // BC)][t % BC] = tk[j]
 
-                 j += 1
 
-                 t += 1
 
-         # inverse MixColumn where needed
 
-         for r in range(1, ROUNDS):
 
-             for j in range(BC):
 
-                 tt = Kd[r][j]
 
-                 Kd[r][j] = U1[(tt >> 24) & 0xFF] ^ \
 
-                            U2[(tt >> 16) & 0xFF] ^ \
 
-                            U3[(tt >>  8) & 0xFF] ^ \
 
-                            U4[ tt        & 0xFF]
 
-         self.Ke = Ke
 
-         self.Kd = Kd
 
-     def encrypt(self, plaintext):
 
-         if len(plaintext) != self.block_size:
 
-             raise ValueError('wrong block length, expected ' + str(self.block_size) + ' got ' + str(len(plaintext)))
 
-         Ke = self.Ke
 
-         BC = self.block_size // 4
 
-         ROUNDS = len(Ke) - 1
 
-         if BC == 4:
 
-             SC = 0
 
-         elif BC == 6:
 
-             SC = 1
 
-         else:
 
-             SC = 2
 
-         s1 = shifts[SC][1][0]
 
-         s2 = shifts[SC][2][0]
 
-         s3 = shifts[SC][3][0]
 
-         a = [0] * BC
 
-         # temporary work array
 
-         t = []
 
-         # plaintext to ints + key
 
-         for i in range(BC):
 
-             t.append((ord(plaintext[i * 4    ]) << 24 |
 
-                       ord(plaintext[i * 4 + 1]) << 16 |
 
-                       ord(plaintext[i * 4 + 2]) <<  8 |
 
-                       ord(plaintext[i * 4 + 3])        ) ^ Ke[0][i])
 
-         # apply round transforms
 
-         for r in range(1, ROUNDS):
 
-             for i in range(BC):
 
-                 a[i] = (T1[(t[ i           ] >> 24) & 0xFF] ^
 
-                         T2[(t[(i + s1) % BC] >> 16) & 0xFF] ^
 
-                         T3[(t[(i + s2) % BC] >>  8) & 0xFF] ^
 
-                         T4[ t[(i + s3) % BC]        & 0xFF]  ) ^ Ke[r][i]
 
-             t = copy.copy(a)
 
-         # last round is special
 
-         result = []
 
-         for i in range(BC):
 
-             tt = Ke[ROUNDS][i]
 
-             result.append((S[(t[ i           ] >> 24) & 0xFF] ^ (tt >> 24)) & 0xFF)
 
-             result.append((S[(t[(i + s1) % BC] >> 16) & 0xFF] ^ (tt >> 16)) & 0xFF)
 
-             result.append((S[(t[(i + s2) % BC] >>  8) & 0xFF] ^ (tt >>  8)) & 0xFF)
 
-             result.append((S[ t[(i + s3) % BC]        & 0xFF] ^  tt       ) & 0xFF)
 
-         return "".join(list(map(chr, result)))
 
-     def decrypt(self, ciphertext):
 
-         if len(ciphertext) != self.block_size:
 
-             raise ValueError('wrong block length, expected ' + str(self.block_size) + ' got ' + str(len(plaintext)))
 
-         Kd = self.Kd
 
-         BC = self.block_size // 4
 
-         ROUNDS = len(Kd) - 1
 
-         if BC == 4:
 
-             SC = 0
 
-         elif BC == 6:
 
-             SC = 1
 
-         else:
 
-             SC = 2
 
-         s1 = shifts[SC][1][1]
 
-         s2 = shifts[SC][2][1]
 
-         s3 = shifts[SC][3][1]
 
-         a = [0] * BC
 
-         # temporary work array
 
-         t = [0] * BC
 
-         # ciphertext to ints + key
 
-         for i in range(BC):
 
-             t[i] = (ord(ciphertext[i * 4    ]) << 24 |
 
-                     ord(ciphertext[i * 4 + 1]) << 16 |
 
-                     ord(ciphertext[i * 4 + 2]) <<  8 |
 
-                     ord(ciphertext[i * 4 + 3])        ) ^ Kd[0][i]
 
-         # apply round transforms
 
-         for r in range(1, ROUNDS):
 
-             for i in range(BC):
 
-                 a[i] = (T5[(t[ i           ] >> 24) & 0xFF] ^
 
-                         T6[(t[(i + s1) % BC] >> 16) & 0xFF] ^
 
-                         T7[(t[(i + s2) % BC] >>  8) & 0xFF] ^
 
-                         T8[ t[(i + s3) % BC]        & 0xFF]  ) ^ Kd[r][i]
 
-             t = copy.copy(a)
 
-         # last round is special
 
-         result = []
 
-         for i in range(BC):
 
-             tt = Kd[ROUNDS][i]
 
-             result.append((Si[(t[ i           ] >> 24) & 0xFF] ^ (tt >> 24)) & 0xFF)
 
-             result.append((Si[(t[(i + s1) % BC] >> 16) & 0xFF] ^ (tt >> 16)) & 0xFF)
 
-             result.append((Si[(t[(i + s2) % BC] >>  8) & 0xFF] ^ (tt >>  8)) & 0xFF)
 
-             result.append((Si[ t[(i + s3) % BC]        & 0xFF] ^  tt       ) & 0xFF)
 
-         return "".join(list(map(chr, result)))
 
- def encrypt(key, block):
 
-     return rijndael(key, len(block)).encrypt(block)
 
- def decrypt(key, block):
 
-     return rijndael(key, len(block)).decrypt(block)
 
- if __name__ == '__main__':
 
-     # test
 
-     def t(kl, bl):
 
-         b = 'b' * bl
 
-         r = rijndael('a' * kl, bl)
 
-         assert r.decrypt(r.encrypt(b)) == b
 
-     t(16, 16)
 
-     t(16, 24)
 
-     t(16, 32)
 
-     t(24, 16)
 
-     t(24, 24)
 
-     t(24, 32)
 
-     t(32, 16)
 
-     t(32, 24)
 
-     t(32, 32)
 
 
  |