rijndael.py 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451
  1. """
  2. Copyright (c) 2014 Philippe Teuwen <phil@teuwen.org>
  3. Permission is hereby granted, free of charge, to any person obtaining a copy of
  4. this software and associated documentation files (the "Software"), to deal in
  5. the Software without restriction, including without limitation the rights to
  6. use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
  7. of the Software, and to permit persons to whom the Software is furnished to do
  8. so, subject to the following conditions:
  9. The above copyright notice and this permission notice shall be included in all
  10. copies or substantial portions of the Software.
  11. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  12. IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  13. FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  14. AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  15. LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  16. FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
  17. IN THE SOFTWARE.
  18. This code is taken from https://github.com/doegox/python-cryptoplus/
  19. A pure python (slow) implementation of rijndael with a decent interface
  20. To include -
  21. from rijndael import rijndael
  22. To do a key setup -
  23. r = rijndael(key, block_size = 16)
  24. key must be a string of length 16, 24, or 32
  25. blocksize must be 16, 24, or 32. Default is 16
  26. To use -
  27. ciphertext = r.encrypt(plaintext)
  28. plaintext = r.decrypt(ciphertext)
  29. If any strings are of the wrong length a ValueError is thrown
  30. """
  31. # ported from the Java reference code by Bram Cohen, bram@gawth.com, April 2001
  32. # this code is public domain, unless someone makes
  33. # an intellectual property claim against the reference
  34. # code, in which case it can be made public domain by
  35. # deleting all the comments and renaming all the variables
  36. import copy
  37. import sys
  38. #-----------------------
  39. #TREV - ADDED BECAUSE THERE'S WARNINGS ABOUT INT OVERFLOW BEHAVIOR CHANGING IN
  40. #2.4.....
  41. #import os
  42. #if os.name != "java":
  43. # import exceptions
  44. # if hasattr(exceptions, "FutureWarning"):
  45. # import warnings
  46. # warnings.filterwarnings("ignore", category=FutureWarning, append=1)
  47. #-----------------------
  48. shifts = [[[0, 0], [1, 3], [2, 2], [3, 1]],
  49. [[0, 0], [1, 5], [2, 4], [3, 3]],
  50. [[0, 0], [1, 7], [3, 5], [4, 4]]]
  51. # [keysize][block_size]
  52. num_rounds = {16: {16: 10, 24: 12, 32: 14}, 24: {16: 12, 24: 12, 32: 14}, 32: {16: 14, 24: 14, 32: 14}}
  53. A = [[1, 1, 1, 1, 1, 0, 0, 0],
  54. [0, 1, 1, 1, 1, 1, 0, 0],
  55. [0, 0, 1, 1, 1, 1, 1, 0],
  56. [0, 0, 0, 1, 1, 1, 1, 1],
  57. [1, 0, 0, 0, 1, 1, 1, 1],
  58. [1, 1, 0, 0, 0, 1, 1, 1],
  59. [1, 1, 1, 0, 0, 0, 1, 1],
  60. [1, 1, 1, 1, 0, 0, 0, 1]]
  61. # produce log and alog tables, needed for multiplying in the
  62. # field GF(2^m) (generator = 3)
  63. alog = [1]
  64. for i in range(255):
  65. j = (alog[-1] << 1) ^ alog[-1]
  66. if j & 0x100 != 0:
  67. j ^= 0x11B
  68. alog.append(j)
  69. log = [0] * 256
  70. for i in range(1, 255):
  71. log[alog[i]] = i
  72. # multiply two elements of GF(2^m)
  73. def mul(a, b):
  74. if a == 0 or b == 0:
  75. return 0
  76. return alog[(log[a & 0xFF] + log[b & 0xFF]) % 255]
  77. # substitution box based on F^{-1}(x)
  78. box = [[0] * 8 for i in range(256)]
  79. box[1][7] = 1
  80. for i in range(2, 256):
  81. j = alog[255 - log[i]]
  82. for t in range(8):
  83. box[i][t] = (j >> (7 - t)) & 0x01
  84. B = [0, 1, 1, 0, 0, 0, 1, 1]
  85. # affine transform: box[i] <- B + A*box[i]
  86. cox = [[0] * 8 for i in range(256)]
  87. for i in range(256):
  88. for t in range(8):
  89. cox[i][t] = B[t]
  90. for j in range(8):
  91. cox[i][t] ^= A[t][j] * box[i][j]
  92. # S-boxes and inverse S-boxes
  93. S = [0] * 256
  94. Si = [0] * 256
  95. for i in range(256):
  96. S[i] = cox[i][0] << 7
  97. for t in range(1, 8):
  98. S[i] ^= cox[i][t] << (7-t)
  99. Si[S[i] & 0xFF] = i
  100. # T-boxes
  101. G = [[2, 1, 1, 3],
  102. [3, 2, 1, 1],
  103. [1, 3, 2, 1],
  104. [1, 1, 3, 2]]
  105. AA = [[0] * 8 for i in range(4)]
  106. for i in range(4):
  107. for j in range(4):
  108. AA[i][j] = G[i][j]
  109. AA[i][i+4] = 1
  110. for i in range(4):
  111. pivot = AA[i][i]
  112. if pivot == 0:
  113. t = i + 1
  114. while AA[t][i] == 0 and t < 4:
  115. t += 1
  116. assert t != 4, 'G matrix must be invertible'
  117. for j in range(8):
  118. AA[i][j], AA[t][j] = AA[t][j], AA[i][j]
  119. pivot = AA[i][i]
  120. for j in range(8):
  121. if AA[i][j] != 0:
  122. AA[i][j] = alog[(255 + log[AA[i][j] & 0xFF] - log[pivot & 0xFF]) % 255]
  123. for t in range(4):
  124. if i != t:
  125. for j in range(i+1, 8):
  126. AA[t][j] ^= mul(AA[i][j], AA[t][i])
  127. AA[t][i] = 0
  128. iG = [[0] * 4 for i in range(4)]
  129. for i in range(4):
  130. for j in range(4):
  131. iG[i][j] = AA[i][j + 4]
  132. def mul4(a, bs):
  133. if a == 0:
  134. return 0
  135. r = 0
  136. for b in bs:
  137. r <<= 8
  138. if b != 0:
  139. r = r | mul(a, b)
  140. return r
  141. T1 = []
  142. T2 = []
  143. T3 = []
  144. T4 = []
  145. T5 = []
  146. T6 = []
  147. T7 = []
  148. T8 = []
  149. U1 = []
  150. U2 = []
  151. U3 = []
  152. U4 = []
  153. for t in range(256):
  154. s = S[t]
  155. T1.append(mul4(s, G[0]))
  156. T2.append(mul4(s, G[1]))
  157. T3.append(mul4(s, G[2]))
  158. T4.append(mul4(s, G[3]))
  159. s = Si[t]
  160. T5.append(mul4(s, iG[0]))
  161. T6.append(mul4(s, iG[1]))
  162. T7.append(mul4(s, iG[2]))
  163. T8.append(mul4(s, iG[3]))
  164. U1.append(mul4(t, iG[0]))
  165. U2.append(mul4(t, iG[1]))
  166. U3.append(mul4(t, iG[2]))
  167. U4.append(mul4(t, iG[3]))
  168. # round constants
  169. rcon = [1]
  170. r = 1
  171. for t in range(1, 30):
  172. r = mul(2, r)
  173. rcon.append(r)
  174. del A
  175. del AA
  176. del pivot
  177. del B
  178. del G
  179. del box
  180. del log
  181. del alog
  182. del i
  183. del j
  184. del r
  185. del s
  186. del t
  187. del mul
  188. del mul4
  189. del cox
  190. del iG
  191. class rijndael:
  192. def __init__(self, key, block_size = 16):
  193. if block_size != 16 and block_size != 24 and block_size != 32:
  194. raise ValueError('Invalid block size: ' + str(block_size))
  195. if len(key) != 16 and len(key) != 24 and len(key) != 32:
  196. raise ValueError('Invalid key size: ' + str(len(key)))
  197. self.block_size = block_size
  198. ROUNDS = num_rounds[len(key)][block_size]
  199. BC = block_size // 4
  200. # encryption round keys
  201. Ke = [[0] * BC for i in range(ROUNDS + 1)]
  202. # decryption round keys
  203. Kd = [[0] * BC for i in range(ROUNDS + 1)]
  204. ROUND_KEY_COUNT = (ROUNDS + 1) * BC
  205. KC = len(key) // 4
  206. # copy user material bytes into temporary ints
  207. tk = []
  208. if sys.version_info.major < 3:
  209. for i in range(0, KC):
  210. tk.append((ord(key[i * 4]) << 24) |
  211. (ord(key[i * 4 + 1]) << 16) |
  212. (ord(key[i * 4 + 2]) << 8) |
  213. ord(key[i * 4 + 3]))
  214. else:
  215. for i in range(0, KC):
  216. tk.append((key[i * 4] << 24) |
  217. (key[i * 4 + 1] << 16) |
  218. (key[i * 4 + 2] << 8) |
  219. (key[i * 4 + 3]))
  220. # copy values into round key arrays
  221. t = 0
  222. j = 0
  223. while j < KC and t < ROUND_KEY_COUNT:
  224. Ke[t // BC][t % BC] = tk[j]
  225. Kd[ROUNDS - (t // BC)][t % BC] = tk[j]
  226. j += 1
  227. t += 1
  228. tt = 0
  229. rconpointer = 0
  230. while t < ROUND_KEY_COUNT:
  231. # extrapolate using phi (the round key evolution function)
  232. tt = tk[KC - 1]
  233. tk[0] ^= (S[(tt >> 16) & 0xFF] & 0xFF) << 24 ^ \
  234. (S[(tt >> 8) & 0xFF] & 0xFF) << 16 ^ \
  235. (S[ tt & 0xFF] & 0xFF) << 8 ^ \
  236. (S[(tt >> 24) & 0xFF] & 0xFF) ^ \
  237. (rcon[rconpointer] & 0xFF) << 24
  238. rconpointer += 1
  239. if KC != 8:
  240. for i in range(1, KC):
  241. tk[i] ^= tk[i-1]
  242. else:
  243. for i in range(1, KC // 2):
  244. tk[i] ^= tk[i-1]
  245. tt = tk[KC // 2 - 1]
  246. tk[KC // 2] ^= (S[ tt & 0xFF] & 0xFF) ^ \
  247. (S[(tt >> 8) & 0xFF] & 0xFF) << 8 ^ \
  248. (S[(tt >> 16) & 0xFF] & 0xFF) << 16 ^ \
  249. (S[(tt >> 24) & 0xFF] & 0xFF) << 24
  250. for i in range(KC // 2 + 1, KC):
  251. tk[i] ^= tk[i-1]
  252. # copy values into round key arrays
  253. j = 0
  254. while j < KC and t < ROUND_KEY_COUNT:
  255. Ke[t // BC][t % BC] = tk[j]
  256. Kd[ROUNDS - (t // BC)][t % BC] = tk[j]
  257. j += 1
  258. t += 1
  259. # inverse MixColumn where needed
  260. for r in range(1, ROUNDS):
  261. for j in range(BC):
  262. tt = Kd[r][j]
  263. Kd[r][j] = U1[(tt >> 24) & 0xFF] ^ \
  264. U2[(tt >> 16) & 0xFF] ^ \
  265. U3[(tt >> 8) & 0xFF] ^ \
  266. U4[ tt & 0xFF]
  267. self.Ke = Ke
  268. self.Kd = Kd
  269. def encrypt(self, plaintext):
  270. if len(plaintext) != self.block_size:
  271. raise ValueError('wrong block length, expected ' + str(self.block_size) + ' got ' + str(len(plaintext)))
  272. Ke = self.Ke
  273. BC = self.block_size // 4
  274. ROUNDS = len(Ke) - 1
  275. if BC == 4:
  276. SC = 0
  277. elif BC == 6:
  278. SC = 1
  279. else:
  280. SC = 2
  281. s1 = shifts[SC][1][0]
  282. s2 = shifts[SC][2][0]
  283. s3 = shifts[SC][3][0]
  284. a = [0] * BC
  285. # temporary work array
  286. t = []
  287. # plaintext to ints + key
  288. if sys.version_info.major < 3:
  289. for i in range(BC):
  290. t.append((ord(plaintext[i * 4 ]) << 24 |
  291. ord(plaintext[i * 4 + 1]) << 16 |
  292. ord(plaintext[i * 4 + 2]) << 8 |
  293. ord(plaintext[i * 4 + 3]) ) ^ Ke[0][i])
  294. else:
  295. for i in range(BC):
  296. t.append((plaintext[i * 4 ] << 24 |
  297. plaintext[i * 4 + 1] << 16 |
  298. plaintext[i * 4 + 2] << 8 |
  299. plaintext[i * 4 + 3]) ^ Ke[0][i])
  300. # apply round transforms
  301. for r in range(1, ROUNDS):
  302. for i in range(BC):
  303. a[i] = (T1[(t[ i ] >> 24) & 0xFF] ^
  304. T2[(t[(i + s1) % BC] >> 16) & 0xFF] ^
  305. T3[(t[(i + s2) % BC] >> 8) & 0xFF] ^
  306. T4[ t[(i + s3) % BC] & 0xFF] ) ^ Ke[r][i]
  307. t = copy.copy(a)
  308. # last round is special
  309. result = []
  310. for i in range(BC):
  311. tt = Ke[ROUNDS][i]
  312. result.append((S[(t[ i ] >> 24) & 0xFF] ^ (tt >> 24)) & 0xFF)
  313. result.append((S[(t[(i + s1) % BC] >> 16) & 0xFF] ^ (tt >> 16)) & 0xFF)
  314. result.append((S[(t[(i + s2) % BC] >> 8) & 0xFF] ^ (tt >> 8)) & 0xFF)
  315. result.append((S[ t[(i + s3) % BC] & 0xFF] ^ tt ) & 0xFF)
  316. if sys.version_info.major < 3:
  317. return "".join(list(map(chr, result)))
  318. else:
  319. return bytearray(result)
  320. def decrypt(self, ciphertext):
  321. if len(ciphertext) != self.block_size:
  322. raise ValueError('wrong block length, expected ' + str(self.block_size) + ' got ' + str(len(plaintext)))
  323. Kd = self.Kd
  324. BC = self.block_size // 4
  325. ROUNDS = len(Kd) - 1
  326. if BC == 4:
  327. SC = 0
  328. elif BC == 6:
  329. SC = 1
  330. else:
  331. SC = 2
  332. s1 = shifts[SC][1][1]
  333. s2 = shifts[SC][2][1]
  334. s3 = shifts[SC][3][1]
  335. a = [0] * BC
  336. # temporary work array
  337. t = [0] * BC
  338. # ciphertext to ints + key
  339. if sys.version_info.major < 3:
  340. for i in range(BC):
  341. t[i] = (ord(ciphertext[i * 4 ]) << 24 |
  342. ord(ciphertext[i * 4 + 1]) << 16 |
  343. ord(ciphertext[i * 4 + 2]) << 8 |
  344. ord(ciphertext[i * 4 + 3]) ) ^ Kd[0][i]
  345. else:
  346. for i in range(BC):
  347. t[i] = (ciphertext[i * 4 ] << 24 |
  348. ciphertext[i * 4 + 1] << 16 |
  349. ciphertext[i * 4 + 2] << 8 |
  350. ciphertext[i * 4 + 3] ) ^ Kd[0][i]
  351. # apply round transforms
  352. for r in range(1, ROUNDS):
  353. for i in range(BC):
  354. a[i] = (T5[(t[ i ] >> 24) & 0xFF] ^
  355. T6[(t[(i + s1) % BC] >> 16) & 0xFF] ^
  356. T7[(t[(i + s2) % BC] >> 8) & 0xFF] ^
  357. T8[ t[(i + s3) % BC] & 0xFF] ) ^ Kd[r][i]
  358. t = copy.copy(a)
  359. # last round is special
  360. result = []
  361. for i in range(BC):
  362. tt = Kd[ROUNDS][i]
  363. result.append((Si[(t[ i ] >> 24) & 0xFF] ^ (tt >> 24)) & 0xFF)
  364. result.append((Si[(t[(i + s1) % BC] >> 16) & 0xFF] ^ (tt >> 16)) & 0xFF)
  365. result.append((Si[(t[(i + s2) % BC] >> 8) & 0xFF] ^ (tt >> 8)) & 0xFF)
  366. result.append((Si[ t[(i + s3) % BC] & 0xFF] ^ tt ) & 0xFF)
  367. if sys.version_info.major < 3:
  368. return "".join(list(map(chr, result)))
  369. else:
  370. return bytearray(result)
  371. def encrypt(key, block):
  372. return rijndael(key, len(block)).encrypt(block)
  373. def decrypt(key, block):
  374. import pdb; pdb.set_trace()
  375. return rijndael(key, len(block)).decrypt(block)
  376. if __name__ == '__main__':
  377. # test
  378. def t(kl, bl):
  379. b = 'b' * bl
  380. r = rijndael('a' * kl, bl)
  381. assert r.decrypt(r.encrypt(b)) == b
  382. t(16, 16)
  383. t(16, 24)
  384. t(16, 32)
  385. t(24, 16)
  386. t(24, 24)
  387. t(24, 32)
  388. t(32, 16)
  389. t(32, 24)
  390. t(32, 32)