Tomasz_D

Untitled

Jun 7th, 2020
42
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 12.53 KB | None | 0 0
  1. import time
  2.  
  3. import copy
  4. class Rijndael(object):
  5. @classmethod
  6. def create(cls):
  7.  
  8. if hasattr(cls, "RIJNDAEL_CREATED"):
  9. return
  10.  
  11. # [keysize][block_size]
  12. cls.num_rounds = {16: {16: 10, 24: 12, 32: 14}, 24: {16: 12, 24: 12, 32: 14}, 32: {16: 14, 24: 14, 32: 14}}
  13.  
  14. cls.shifts = [[[0, 0], [1, 3], [2, 2], [3, 1]],
  15. [[0, 0], [1, 5], [2, 4], [3, 3]],
  16. [[0, 0], [1, 7], [3, 5], [4, 4]]]
  17.  
  18. A = [[1, 1, 1, 1, 1, 0, 0, 0],
  19. [0, 1, 1, 1, 1, 1, 0, 0],
  20. [0, 0, 1, 1, 1, 1, 1, 0],
  21. [0, 0, 0, 1, 1, 1, 1, 1],
  22. [1, 0, 0, 0, 1, 1, 1, 1],
  23. [1, 1, 0, 0, 0, 1, 1, 1],
  24. [1, 1, 1, 0, 0, 0, 1, 1],
  25. [1, 1, 1, 1, 0, 0, 0, 1]]
  26.  
  27. # produce log and alog tables, needed for multiplying in the
  28. # field GF(2^m) (generator = 3)
  29. alog = [1]
  30. for i in range(255):
  31. j = (alog[-1] << 1) ^ alog[-1]
  32. if j & 0x100 != 0:
  33. j ^= 0x11B
  34. alog.append(j)
  35.  
  36. log = [0] * 256
  37. for i in range(1, 255):
  38. log[alog[i]] = i
  39.  
  40. # multiply two elements of GF(2^m)
  41. def mul(a, b):
  42. if a == 0 or b == 0:
  43. return 0
  44. return alog[(log[a & 0xFF] + log[b & 0xFF]) % 255]
  45.  
  46. # substitution box based on F^{-1}(x)
  47. box = [[0] * 8 for i in range(256)]
  48. box[1][7] = 1
  49. for i in range(2, 256):
  50. j = alog[255 - log[i]]
  51. for t in range(8):
  52. box[i][t] = (j >> (7 - t)) & 0x01
  53.  
  54. B = [0, 1, 1, 0, 0, 0, 1, 1]
  55.  
  56. # affine transform: box[i] <- B + A*box[i]
  57. cox = [[0] * 8 for i in range(256)]
  58. for i in range(256):
  59. for t in range(8):
  60. cox[i][t] = B[t]
  61. for j in range(8):
  62. cox[i][t] ^= A[t][j] * box[i][j]
  63.  
  64. # cls.S-boxes and inverse cls.S-boxes
  65. cls.S = [0] * 256
  66. cls.Si = [0] * 256
  67. for i in range(256):
  68. cls.S[i] = cox[i][0] << 7
  69. for t in range(1, 8):
  70. cls.S[i] ^= cox[i][t] << (7-t)
  71. cls.Si[cls.S[i] & 0xFF] = i
  72.  
  73. # T-boxes
  74. G = [[2, 1, 1, 3],
  75. [3, 2, 1, 1],
  76. [1, 3, 2, 1],
  77. [1, 1, 3, 2]]
  78.  
  79. AA = [[0] * 8 for i in range(4)]
  80.  
  81. for i in range(4):
  82. for j in range(4):
  83. AA[i][j] = G[i][j]
  84. AA[i][i+4] = 1
  85.  
  86. for i in range(4):
  87. pivot = AA[i][i]
  88. if pivot == 0:
  89. t = i + 1
  90. while AA[t][i] == 0 and t < 4:
  91. t += 1
  92. assert t != 4, 'G matrix must be invertible'
  93. for j in range(8):
  94. AA[i][j], AA[t][j] = AA[t][j], AA[i][j]
  95. pivot = AA[i][i]
  96. for j in range(8):
  97. if AA[i][j] != 0:
  98. AA[i][j] = alog[(255 + log[AA[i][j] & 0xFF] - log[pivot & 0xFF]) % 255]
  99. for t in range(4):
  100. if i != t:
  101. for j in range(i+1, 8):
  102. AA[t][j] ^= mul(AA[i][j], AA[t][i])
  103. AA[t][i] = 0
  104.  
  105. iG = [[0] * 4 for i in range(4)]
  106.  
  107. for i in range(4):
  108. for j in range(4):
  109. iG[i][j] = AA[i][j + 4]
  110.  
  111. def mul4(a, bs):
  112. if a == 0:
  113. return 0
  114. r = 0
  115. for b in bs:
  116. r <<= 8
  117. if b != 0:
  118. r = r | mul(a, b)
  119. return r
  120.  
  121. cls.T1 = []
  122. cls.T2 = []
  123. cls.T3 = []
  124. cls.T4 = []
  125. cls.T5 = []
  126. cls.T6 = []
  127. cls.T7 = []
  128. cls.T8 = []
  129. cls.U1 = []
  130. cls.U2 = []
  131. cls.U3 = []
  132. cls.U4 = []
  133.  
  134. for t in range(256):
  135. s = cls.S[t]
  136. cls.T1.append(mul4(s, G[0]))
  137. cls.T2.append(mul4(s, G[1]))
  138. cls.T3.append(mul4(s, G[2]))
  139. cls.T4.append(mul4(s, G[3]))
  140.  
  141. s = cls.Si[t]
  142. cls.T5.append(mul4(s, iG[0]))
  143. cls.T6.append(mul4(s, iG[1]))
  144. cls.T7.append(mul4(s, iG[2]))
  145. cls.T8.append(mul4(s, iG[3]))
  146.  
  147. cls.U1.append(mul4(t, iG[0]))
  148. cls.U2.append(mul4(t, iG[1]))
  149. cls.U3.append(mul4(t, iG[2]))
  150. cls.U4.append(mul4(t, iG[3]))
  151.  
  152. # round constants
  153. cls.rcon = [1]
  154. r = 1
  155. for t in range(1, 30):
  156. r = mul(2, r)
  157. cls.rcon.append(r)
  158.  
  159. cls.RIJNDAEL_CREATED = True
  160.  
  161. def __init__(self, key, block_size = 16):
  162.  
  163. # create common meta-instance infrastructure
  164. self.create()
  165.  
  166. if block_size != 16 and block_size != 24 and block_size != 32:
  167. raise ValueError('Invalid block size: ' + str(block_size))
  168. if len(key) != 16 and len(key) != 24 and len(key) != 32:
  169. raise ValueError('Invalid key size: ' + str(len(key)))
  170. self.block_size = block_size
  171.  
  172. ROUNDS = Rijndael.num_rounds[len(key)][block_size]
  173. BC = int(block_size / 4)
  174. # encryption round keys
  175. Ke = [[0] * BC for i in range(ROUNDS + 1)]
  176. # decryption round keys
  177. Kd = [[0] * BC for i in range(ROUNDS + 1)]
  178. ROUND_KEY_COUNT = (ROUNDS + 1) * BC
  179. KC = int(len(key) / 4)
  180.  
  181. # copy user material bytes into temporary ints
  182. tk = []
  183. for i in range(0, KC):
  184. tk.append((ord(key[i * 4]) << 24) | (ord(key[i * 4 + 1]) << 16) |
  185. (ord(key[i * 4 + 2]) << 8) | ord(key[i * 4 + 3]))
  186.  
  187. # copy values into round key arrays
  188. t = 0
  189. j = 0
  190. while j < KC and t < ROUND_KEY_COUNT:
  191. Ke[int(t / BC)][t % BC] = tk[j]
  192. Kd[ROUNDS - (int(t / BC))][t % BC] = tk[j]
  193. j += 1
  194. t += 1
  195. tt = 0
  196. rconpointer = 0
  197. while t < ROUND_KEY_COUNT:
  198. # extrapolate using phi (the round key evolution function)
  199. tt = tk[KC - 1]
  200. tk[0] ^= (Rijndael.S[(tt >> 16) & 0xFF] & 0xFF) << 24 ^ \
  201. (Rijndael.S[(tt >> 8) & 0xFF] & 0xFF) << 16 ^ \
  202. (Rijndael.S[ tt & 0xFF] & 0xFF) << 8 ^ \
  203. (Rijndael.S[(tt >> 24) & 0xFF] & 0xFF) ^ \
  204. (Rijndael.rcon[rconpointer] & 0xFF) << 24
  205. rconpointer += 1
  206. if KC != 8:
  207. for i in range(1, KC):
  208. tk[i] ^= tk[i-1]
  209. else:
  210. for i in range(1, int(KC / 2)):
  211. tk[i] ^= tk[i-1]
  212. tt = tk[int(KC / 2 - 1)]
  213. tk[int(KC / 2)] ^= (Rijndael.S[ tt & 0xFF] & 0xFF) ^ \
  214. (Rijndael.S[(tt >> 8) & 0xFF] & 0xFF) << 8 ^ \
  215. (Rijndael.S[(tt >> 16) & 0xFF] & 0xFF) << 16 ^ \
  216. (Rijndael.S[(tt >> 24) & 0xFF] & 0xFF) << 24
  217. for i in range(int(KC / 2) + 1, KC):
  218. tk[i] ^= tk[i-1]
  219. # copy values into round key arrays
  220. j = 0
  221. while j < KC and t < ROUND_KEY_COUNT:
  222. Ke[int(t / BC)][t % BC] = tk[j]
  223. Kd[ROUNDS - (int(t / BC))][t % BC] = tk[j]
  224. j += 1
  225. t += 1
  226. # inverse MixColumn where needed
  227. for r in range(1, ROUNDS):
  228. for j in range(BC):
  229. tt = Kd[r][j]
  230. Kd[r][j] = Rijndael.U1[(tt >> 24) & 0xFF] ^ \
  231. Rijndael.U2[(tt >> 16) & 0xFF] ^ \
  232. Rijndael.U3[(tt >> 8) & 0xFF] ^ \
  233. Rijndael.U4[ tt & 0xFF]
  234. self.Ke = Ke
  235. self.Kd = Kd
  236.  
  237. def encrypt(self, plaintext):
  238. if len(plaintext) != self.block_size:
  239. raise ValueError('wrong block length, expected ' + str(self.block_size) + ' got ' + str(len(plaintext)))
  240. Ke = self.Ke
  241.  
  242. BC = int(self.block_size / 4)
  243. ROUNDS = len(Ke) - 1
  244. if BC == 4:
  245. Rijndael.SC = 0
  246. elif BC == 6:
  247. Rijndael.SC = 1
  248. else:
  249. Rijndael.SC = 2
  250. s1 = Rijndael.shifts[Rijndael.SC][1][0]
  251. s2 = Rijndael.shifts[Rijndael.SC][2][0]
  252. s3 = Rijndael.shifts[Rijndael.SC][3][0]
  253. a = [0] * BC
  254. # temporary work array
  255. t = []
  256. # plaintext to ints + key
  257. for i in range(BC):
  258. t.append((ord(plaintext[i * 4 ]) << 24 |
  259. ord(plaintext[i * 4 + 1]) << 16 |
  260. ord(plaintext[i * 4 + 2]) << 8 |
  261. ord(plaintext[i * 4 + 3]) ) ^ Ke[0][i])
  262. # apply round transforms
  263. for r in range(1, ROUNDS):
  264. for i in range(BC):
  265. a[i] = (Rijndael.T1[(t[ i ] >> 24) & 0xFF] ^
  266. Rijndael.T2[(t[(i + s1) % BC] >> 16) & 0xFF] ^
  267. Rijndael.T3[(t[(i + s2) % BC] >> 8) & 0xFF] ^
  268. Rijndael.T4[ t[(i + s3) % BC] & 0xFF] ) ^ Ke[r][i]
  269. t = copy.deepcopy(a)
  270. # last round is special
  271. result = []
  272. for i in range(BC):
  273. tt = Ke[ROUNDS][i]
  274. result.append((Rijndael.S[(t[ i ] >> 24) & 0xFF] ^ (tt >> 24)) & 0xFF)
  275. result.append((Rijndael.S[(t[(i + s1) % BC] >> 16) & 0xFF] ^ (tt >> 16)) & 0xFF)
  276. result.append((Rijndael.S[(t[(i + s2) % BC] >> 8) & 0xFF] ^ (tt >> 8)) & 0xFF)
  277. result.append((Rijndael.S[ t[(i + s3) % BC] & 0xFF] ^ tt ) & 0xFF)
  278. return ''.join(list(map(chr, result)))
  279.  
  280. def decrypt(self, ciphertext):
  281. if len(ciphertext) != self.block_size:
  282. raise ValueError('wrong block length, expected ' + str(self.block_size) + ' got ' + str(len(ciphertext)))
  283. Kd = self.Kd
  284.  
  285. BC = int(self.block_size / 4)
  286. ROUNDS = len(Kd) - 1
  287. if BC == 4:
  288. Rijndael.SC = 0
  289. elif BC == 6:
  290. Rijndael.SC = 1
  291. else:
  292. Rijndael.SC = 2
  293. s1 = Rijndael.shifts[Rijndael.SC][1][1]
  294. s2 = Rijndael.shifts[Rijndael.SC][2][1]
  295. s3 = Rijndael.shifts[Rijndael.SC][3][1]
  296. a = [0] * BC
  297. # temporary work array
  298. t = [0] * BC
  299. # ciphertext to ints + key
  300. for i in range(BC):
  301. t[i] = (ord(ciphertext[i * 4 ]) << 24 |
  302. ord(ciphertext[i * 4 + 1]) << 16 |
  303. ord(ciphertext[i * 4 + 2]) << 8 |
  304. ord(ciphertext[i * 4 + 3]) ) ^ Kd[0][i]
  305. # apply round transforms
  306. for r in range(1, ROUNDS):
  307. for i in range(BC):
  308. a[i] = (Rijndael.T5[(t[ i ] >> 24) & 0xFF] ^
  309. Rijndael.T6[(t[(i + s1) % BC] >> 16) & 0xFF] ^
  310. Rijndael.T7[(t[(i + s2) % BC] >> 8) & 0xFF] ^
  311. Rijndael.T8[ t[(i + s3) % BC] & 0xFF] ) ^ Kd[r][i]
  312. t = copy.deepcopy(a)
  313. # last round is special
  314. result = []
  315. for i in range(BC):
  316. tt = Kd[ROUNDS][i]
  317. result.append((Rijndael.Si[(t[ i ] >> 24) & 0xFF] ^ (tt >> 24)) & 0xFF)
  318. result.append((Rijndael.Si[(t[(i + s1) % BC] >> 16) & 0xFF] ^ (tt >> 16)) & 0xFF)
  319. result.append((Rijndael.Si[(t[(i + s2) % BC] >> 8) & 0xFF] ^ (tt >> 8)) & 0xFF)
  320. result.append((Rijndael.Si[ t[(i + s3) % BC] & 0xFF] ^ tt ) & 0xFF)
  321. return ''.join(list(map(chr, result)))
  322.  
  323. # @staticmethod
  324. # def encrypt_block(key, block):
  325. # return Rijndael(key, len(block)).encrypt(block)
  326.  
  327. # @staticmethod
  328. # def decrypt_block(key, block):
  329. # return Rijndael(key, len(block)).decrypt(block)
  330.  
  331. @staticmethod
  332. def test():
  333. def t(kl, bl):
  334. b = 'b' * bl
  335. r = Rijndael('a' * kl, bl)
  336. x = r.encrypt(b)
  337. assert x != b
  338. assert r.decrypt(x) == b
  339. t(16, 16)
  340. t(16, 24)
  341. t(16, 32)
  342. t(24, 16)
  343. t(24, 24)
  344. t(24, 32)
  345. t(32, 16)
  346. t(32, 24)
  347. t(32, 32)
  348.  
  349. start = time.time()
  350. r = Rijndael("abcdefg1234567890123456789012345", block_size = 32)
  351. ciphertext = r.encrypt("12345999999999999999999999954321")
  352. end = time.time()
  353. plaintext = r.decrypt(ciphertext)
  354.  
  355. #print (plaintext,ciphertext)
  356.  
  357. a=end-start
  358. print (a)
Add Comment
Please, Sign In to add comment