speck.py 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334
  1. from __future__ import print_function
  2. class SpeckCipher(object):
  3. """Speck Block Cipher Object"""
  4. # valid cipher configurations stored:
  5. # block_size:{key_size:number_rounds}
  6. __valid_setups = {32: {64: 22},
  7. 48: {72: 22, 96: 23},
  8. 64: {96: 26, 128: 27},
  9. 96: {96: 28, 144: 29},
  10. 128: {128: 32, 192: 33, 256: 34}}
  11. __valid_modes = ['ECB', 'CTR', 'CBC', 'PCBC', 'CFB', 'OFB']
  12. def encrypt_round(self, x, y, k):
  13. """Complete One Round of Feistel Operation"""
  14. rs_x = ((x << (self.word_size - self.alpha_shift)) + (x >> self.alpha_shift)) & self.mod_mask
  15. add_sxy = (rs_x + y) & self.mod_mask
  16. new_x = k ^ add_sxy
  17. ls_y = ((y >> (self.word_size - self.beta_shift)) + (y << self.beta_shift)) & self.mod_mask
  18. new_y = new_x ^ ls_y
  19. return new_x, new_y
  20. def decrypt_round(self, x, y, k):
  21. """Complete One Round of Inverse Feistel Operation"""
  22. xor_xy = x ^ y
  23. new_y = ((xor_xy << (self.word_size - self.beta_shift)) + (xor_xy >> self.beta_shift)) & self.mod_mask
  24. xor_xk = x ^ k
  25. msub = ((xor_xk - new_y) + self.mod_mask_sub) % self.mod_mask_sub
  26. new_x = ((msub >> (self.word_size - self.alpha_shift)) + (msub << self.alpha_shift)) & self.mod_mask
  27. return new_x, new_y
  28. def __init__(self, key, key_size=128, block_size=128, mode='ECB', init=0, counter=0):
  29. # Setup block/word size
  30. try:
  31. self.possible_setups = self.__valid_setups[block_size]
  32. self.block_size = block_size
  33. self.word_size = self.block_size >> 1
  34. except KeyError:
  35. print('Invalid block size!')
  36. print('Please use one of the following block sizes:', [x for x in self.__valid_setups.keys()])
  37. raise
  38. # Setup Number of Rounds and Key Size
  39. try:
  40. self.rounds = self.possible_setups[key_size]
  41. self.key_size = key_size
  42. except KeyError:
  43. print('Invalid key size for selected block size!!')
  44. print('Please use one of the following key sizes:', [x for x in self.possible_setups.keys()])
  45. raise
  46. # Create Properly Sized bit mask for truncating addition and left shift outputs
  47. self.mod_mask = (2 ** self.word_size) - 1
  48. # Mod mask for modular subtraction
  49. self.mod_mask_sub = (2 ** self.word_size)
  50. # Setup Circular Shift Parameters
  51. if self.block_size == 32:
  52. self.beta_shift = 2
  53. self.alpha_shift = 7
  54. else:
  55. self.beta_shift = 3
  56. self.alpha_shift = 8
  57. # Parse the given iv and truncate it to the block length
  58. try:
  59. self.iv = init & ((2 ** self.block_size) - 1)
  60. self.iv_upper = self.iv >> self.word_size
  61. self.iv_lower = self.iv & self.mod_mask
  62. except (ValueError, TypeError):
  63. print('Invalid IV Value!')
  64. print('Please Provide IV as int')
  65. raise
  66. # Parse the given Counter and truncate it to the block length
  67. try:
  68. self.counter = counter & ((2 ** self.block_size) - 1)
  69. except (ValueError, TypeError):
  70. print('Invalid Counter Value!')
  71. print('Please Provide Counter as int')
  72. raise
  73. # Check Cipher Mode
  74. try:
  75. position = self.__valid_modes.index(mode)
  76. self.mode = self.__valid_modes[position]
  77. except ValueError:
  78. print('Invalid cipher mode!')
  79. print('Please use one of the following block cipher modes:', self.__valid_modes)
  80. raise
  81. # Parse the given key and truncate it to the key length
  82. try:
  83. self.key = key & ((2 ** self.key_size) - 1)
  84. except (ValueError, TypeError):
  85. print('Invalid Key Value!')
  86. print('Please Provide Key as int')
  87. raise
  88. # Pre-compile key schedule
  89. self.key_schedule = [self.key & self.mod_mask]
  90. l_schedule = [(self.key >> (x * self.word_size)) & self.mod_mask for x in
  91. range(1, self.key_size // self.word_size)]
  92. #print([hex(x) for x in l_schedule])
  93. for x in range(self.rounds - 1):
  94. new_l_k = self.encrypt_round(l_schedule[x], self.key_schedule[x], x)
  95. l_schedule.append(new_l_k[0])
  96. self.key_schedule.append(new_l_k[1])
  97. print([hex(x) for x in self.key_schedule])
  98. def encrypt(self, plaintext):
  99. try:
  100. b = (plaintext >> self.word_size) & self.mod_mask
  101. a = plaintext & self.mod_mask
  102. except TypeError:
  103. print('Invalid plaintext!')
  104. print('Please provide plaintext as int')
  105. raise
  106. if self.mode == 'ECB':
  107. b, a = self.encrypt_function(b, a)
  108. elif self.mode == 'CTR':
  109. true_counter = self.iv + self.counter
  110. d = (true_counter >> self.word_size) & self.mod_mask
  111. c = true_counter & self.mod_mask
  112. d, c = self.encrypt_function(d, c)
  113. b ^= d
  114. a ^= c
  115. self.counter += 1
  116. elif self.mode == 'CBC':
  117. b ^= self.iv_upper
  118. a ^= self.iv_lower
  119. b, a = self.encrypt_function(b, a)
  120. self.iv_upper = b
  121. self.iv_lower = a
  122. self.iv = (b << self.word_size) + a
  123. elif self.mode == 'PCBC':
  124. f, e = b, a
  125. b ^= self.iv_upper
  126. a ^= self.iv_lower
  127. b, a = self.encrypt_function(b, a)
  128. self.iv_upper = (b ^ f)
  129. self.iv_lower = (a ^ e)
  130. self.iv = (self.iv_upper << self.word_size) + self.iv_lower
  131. elif self.mode == 'CFB':
  132. d = self.iv_upper
  133. c = self.iv_lower
  134. d, c = self.encrypt_function(d, c)
  135. b ^= d
  136. a ^= c
  137. self.iv_upper = b
  138. self.iv_lower = a
  139. self.iv = (b << self.word_size) + a
  140. elif self.mode == 'OFB':
  141. d = self.iv_upper
  142. c = self.iv_lower
  143. d, c = self.encrypt_function(d, c)
  144. self.iv_upper = d
  145. self.iv_lower = c
  146. self.iv = (d << self.word_size) + c
  147. b ^= d
  148. a ^= c
  149. ciphertext = (b << self.word_size) + a
  150. return ciphertext
  151. def decrypt(self, ciphertext):
  152. try:
  153. b = (ciphertext >> self.word_size) & self.mod_mask
  154. a = ciphertext & self.mod_mask
  155. except TypeError:
  156. print('Invalid ciphertext!')
  157. print('Please provide plaintext as int')
  158. raise
  159. if self.mode == 'ECB':
  160. b, a = self.decrypt_function(b, a)
  161. elif self.mode == 'CTR':
  162. true_counter = self.iv + self.counter
  163. d = (true_counter >> self.word_size) & self.mod_mask
  164. c = true_counter & self.mod_mask
  165. d, c = self.encrypt_function(d, c)
  166. b ^= d
  167. a ^= c
  168. self.counter += 1
  169. elif self.mode == 'CBC':
  170. f, e = b, a
  171. b, a = self.decrypt_function(b, a)
  172. b ^= self.iv_upper
  173. a ^= self.iv_lower
  174. self.iv_upper = f
  175. self.iv_lower = e
  176. self.iv = (f << self.word_size) + e
  177. elif self.mode == 'PCBC':
  178. f, e = b, a
  179. b, a = self.decrypt_function(b, a)
  180. b ^= self.iv_upper
  181. a ^= self.iv_lower
  182. self.iv_upper = (b ^ f)
  183. self.iv_lower = (a ^ e)
  184. self.iv = (self.iv_upper << self.word_size) + self.iv_lower
  185. elif self.mode == 'CFB':
  186. d = self.iv_upper
  187. c = self.iv_lower
  188. self.iv_upper = b
  189. self.iv_lower = a
  190. self.iv = (b << self.word_size) + a
  191. d, c = self.encrypt_function(d, c)
  192. b ^= d
  193. a ^= c
  194. elif self.mode == 'OFB':
  195. d = self.iv_upper
  196. c = self.iv_lower
  197. d, c = self.encrypt_function(d, c)
  198. self.iv_upper = d
  199. self.iv_lower = c
  200. self.iv = (d << self.word_size) + c
  201. b ^= d
  202. a ^= c
  203. plaintext = (b << self.word_size) + a
  204. return plaintext
  205. def encrypt_function(self, upper_word, lower_word):
  206. x = upper_word
  207. y = lower_word
  208. # Run Encryption Steps For Appropriate Number of Rounds
  209. for k in self.key_schedule:
  210. rs_x = ((x << (self.word_size - self.alpha_shift)) + (x >> self.alpha_shift)) & self.mod_mask
  211. add_sxy = (rs_x + y) & self.mod_mask
  212. x = k ^ add_sxy
  213. ls_y = ((y >> (self.word_size - self.beta_shift)) + (y << self.beta_shift)) & self.mod_mask
  214. y = x ^ ls_y
  215. return x,y
  216. def decrypt_function(self, upper_word, lower_word):
  217. x = upper_word
  218. y = lower_word
  219. # Run Encryption Steps For Appropriate Number of Rounds
  220. for k in reversed(self.key_schedule):
  221. xor_xy = x ^ y
  222. y = ((xor_xy << (self.word_size - self.beta_shift)) + (xor_xy >> self.beta_shift)) & self.mod_mask
  223. xor_xk = x ^ k
  224. msub = ((xor_xk - y) + self.mod_mask_sub) % self.mod_mask_sub
  225. x = ((msub >> (self.word_size - self.alpha_shift)) + (msub << self.alpha_shift)) & self.mod_mask
  226. return x,y
  227. def update_iv(self, new_iv=None):
  228. if new_iv:
  229. try:
  230. self.iv = new_iv & ((2 ** self.block_size) - 1)
  231. self.iv_upper = self.iv >> self.word_size
  232. self.iv_lower = self.iv & self.mod_mask
  233. except TypeError:
  234. print('Invalid Initialization Vector!')
  235. print('Please provide IV as int')
  236. raise
  237. return self.iv
  238. if __name__ == "__main__":
  239. #cipher = SpeckCipher(0x1f1e1d1c1b1a191817161514131211100f0e0d0c0b0a09080706050403020100, 256, 128, 'ECB')
  240. cipher = SpeckCipher(0x8877665544332211, 64, 32, 'ECB')
  241. for i in range(22):
  242. a, b = cipher.decrypt_round(0x2211, 0x00dd, i)
  243. print(hex(a))
  244. print(hex(b))
  245. for key in range(2**16):
  246. _, a = cipher.encrypt_round(key, 0x2211, 0)
  247. if a == 0xdd:
  248. print("found: " + hex(key))
  249. #g = cipher.encrypt(0x65736f6874206e49202e72656e6f6f70)
  250. #u8 pt[4] = {0x4c, 0x69, 0x74, 0x65};
  251. g = cipher.encrypt(0x6574694c)
  252. print(hex(g))