aes_by_crypto.py 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406
  1. # update: 2021-5-12-21
  2. from Crypto.Cipher import AES
  3. import base64
  4. import hashlib
  5. import zipfile
  6. import pyminizip
  7. import pyzipper
  8. import os
  9. class _AES(object):
  10. def __init__(self, key='7486E0264E999881D4EF7BEEDF05A9F7', model='ECB', iv='',
  11. code_type='utf-8'):
  12. """
  13. code_type: utf-8/gbk
  14. """
  15. self.code_type = code_type
  16. self.model = {'ECB': AES.MODE_ECB, 'CBC': AES.MODE_CBC}[model]
  17. self.key = self.replenish(key)
  18. # --- create aes object ---
  19. if model == 'ECB':
  20. self.aes = AES.new(self.key, self.model)
  21. elif model == 'CBC':
  22. self.aes = AES.new(self.key, self.model, iv)
  23. def replenish(self, block, block_size=16):
  24. """block_size: AES key must be either 16, 24, or 32 bytes long"""
  25. block = block.encode(self.code_type)
  26. while len(block) % block_size != 0:
  27. block += b'\x00'
  28. return block
  29. def encrypt(self, text):
  30. text = self.replenish(text)
  31. encrypt_text = self.aes.encrypt(text)
  32. return base64.encodebytes(encrypt_text).decode().strip()
  33. def decrypt(self, text):
  34. text = base64.decodebytes(text.encode(self.code_type))
  35. decrypt_text = self.aes.decrypt(text)
  36. return decrypt_text.decode(self.code_type).strip('\0')
  37. def text_to_b64(string):
  38. """b64编码"""
  39. return str(base64.b64encode(str(string).encode('utf-8')), 'utf-8')
  40. def b64_to_text(string):
  41. """b64解码"""
  42. return str(base64.b64decode(str(string).encode('utf-8')), 'utf-8')
  43. def text_to_aes(text, key='YourPassword'):
  44. """aes加密"""
  45. aes = _AES(key=key)
  46. return text_to_b64(aes.encrypt(text))
  47. def aes_to_text(text, key='YourPassword'):
  48. """aes解密"""
  49. aes = _AES(key=key)
  50. return aes.decrypt(b64_to_text(text))
  51. def get_big_file_md5(file_path, block_size=8 * 1024):
  52. """获取文件md5(默认使用8KB作为分块大小)"""
  53. m = hashlib.md5()
  54. with open(file_path, 'rb') as f:
  55. while True:
  56. block = f.read(block_size)
  57. if not block:
  58. break
  59. m.update(block)
  60. return m.hexdigest()
  61. def file_to_zip(file_path):
  62. """生成zip压缩文件"""
  63. # --- encrypt file name --- todo 如果aes后超过255的长度就不做aes了
  64. file_name = file_path.split('/')[-1]
  65. save_name = text_to_b64(file_name)
  66. # --- define zip name ---
  67. file_md5 = get_big_file_md5(file_path)
  68. zip_name = f"{file_md5}.zip"
  69. dir_path = '/'.join(file_path.split('/')[:-1])
  70. zip_path = f"{dir_path}/{zip_name}"
  71. # --- writing ---
  72. with zipfile.ZipFile(zip_path, 'w', compression=zipfile.ZIP_DEFLATED, allowZip64=True) as f1:
  73. f1.write(file_path, arcname=save_name)
  74. def zip_to_file():
  75. pass
  76. def file_to_zip_v2(file_path, key='<YourPassword@2021>', compress_level=5):
  77. """
  78. 文件转zip
  79. compress_level(int) between 1 to 9, 1 (more fast) <---> 9 (more compress) or 0 (default)
  80. """
  81. # --- check parameter ---
  82. if not os.path.isfile(file_path):
  83. return dict(code=1, details='parameter error!')
  84. # --- encrypt file name ---
  85. file_name = file_path.split('/')[-1]
  86. dir_path = '/'.join(file_path.split('/')[:-1])
  87. save_name = text_to_aes(file_name, key=key)
  88. # --- check again ---
  89. is_encrypted = len(file_name) == 37 and file_name[32] == '.'
  90. if is_encrypted:
  91. return dict(code=2, details='parameter error!')
  92. # --- check system support ---
  93. if len(save_name) > 250:
  94. return dict(code=3, details='parameter error!')
  95. # --- rename file ---
  96. save_path = f"{dir_path}/{save_name}"
  97. os.rename(file_path, save_path)
  98. # --- define zip name ---
  99. file_md5 = get_big_file_md5(save_path)
  100. zip_path = f"{dir_path}/{file_md5}.{save_name[:4]}"
  101. try:
  102. # --- writing ---
  103. """
  104. Args:
  105. 1. src file path (string)
  106. 2. src file prefix path (string) or None (path to prepend to file)
  107. 3. dst file path (string)
  108. 4. password (string) or None (to create no-password zip)
  109. 5. compress_level(int) between 1 to 9, 1 (more fast) <---> 9 (more compress) or 0 (default)
  110. """
  111. pyminizip.compress(save_path, None, zip_path, key, compress_level)
  112. # --- remove file ---
  113. os.remove(save_path)
  114. return dict(code=0, details='ended.')
  115. except Exception as exception:
  116. # --- revert ---
  117. os.rename(save_path, file_path)
  118. import traceback
  119. print(traceback.format_exc())
  120. return dict(code=-1, details=f"{traceback.format_exc()}")
  121. def zip_to_file_v2(file_path, key='<YourPassword@2021>', no_path=True):
  122. """zip转file"""
  123. # --- check parameter ---
  124. if not os.path.isfile(file_path):
  125. return dict(code=1, details='parameter error!')
  126. # --- check again ---
  127. file_name = file_path.split('/')[-1]
  128. is_encrypted = len(file_name) == 37 and file_name[32] == '.'
  129. if not is_encrypted:
  130. return dict(code=2, details='parameter error!')
  131. # --- record ---
  132. dir_path = '/'.join(file_path.split('/')[:-1])
  133. names = os.listdir(dir_path)
  134. before_files = set(f"{dir_path}/{name}" for name in names if not os.path.isdir(f"{dir_path}/{name}"))
  135. try:
  136. # --- writing ---
  137. """
  138. Args:
  139. 1. src file path (string)
  140. 2. password (string) or None (to unzip encrypted archives)
  141. 3. dir path to extract files or None (to extract in a specific dir or cwd)
  142. 4. withoutpath (exclude path of extracted)
  143. """
  144. pyminizip.uncompress(file_path, key, dir_path, no_path)
  145. # --- record ---
  146. names = os.listdir(dir_path)
  147. after_files = set(f"{dir_path}/{name}" for name in names if not os.path.isdir(f"{dir_path}/{name}"))
  148. # --- rename ---
  149. for path in list(after_files - before_files):
  150. name = path.split('/')[-1]
  151. raw_name = aes_to_text(name, key=key)
  152. os.rename(path, f"{dir_path}/{raw_name}")
  153. # --- remove file ---
  154. os.remove(file_path)
  155. return dict(code=0, details='ended.')
  156. except Exception as exception:
  157. # --- revert ---
  158. names = os.listdir(dir_path)
  159. after_files = set(f"{dir_path}/{name}" for name in names if not os.path.isdir(f"{dir_path}/{name}"))
  160. for path in list(after_files - before_files):
  161. os.remove(path)
  162. import traceback
  163. print(traceback.format_exc())
  164. return dict(code=-1, details=f"{traceback.format_exc()}")
  165. def file_to_zip_v2_1(file_path, key='<YourPassword@2021>', compress_level=1):
  166. """file转zip(双文件保存版,其中一个文件保存加密文件名)"""
  167. # --- check parameter ---
  168. if not os.path.isfile(file_path):
  169. return dict(code=1, details='parameter error!')
  170. # --- check again ---
  171. file_name = file_path.split('/')[-1]
  172. is_encrypted = len(file_name) == 37 and file_name[32] == '.'
  173. if is_encrypted:
  174. return dict(code=2, details='parameter error!')
  175. # --- create name file ---
  176. dir_path = '/'.join(file_path.split('/')[:-1])
  177. file_name_aes = text_to_aes(file_name, key=key)
  178. name_file_path = f"{dir_path}/{file_name_aes[:4]}"
  179. with open(name_file_path, 'w') as f1:
  180. f1.write(file_name_aes)
  181. # --- rename file ---
  182. file_md5 = get_big_file_md5(file_path)
  183. data_file_path = f"{dir_path}/{file_md5}"
  184. os.rename(file_path, data_file_path)
  185. # --- define zip name ---
  186. zip_path = f"{dir_path}/{file_md5}.{file_name_aes[:4]}"
  187. try:
  188. # --- writing ---
  189. # pyminizip.compress(save_path, None, zip_path, key, compress_level)
  190. """
  191. Args:
  192. 1. src file LIST path (list)
  193. 2. src file LIST prefix path (list) or []
  194. 3. dst file path (string)
  195. 4. password (string) or None (to create no-password zip)
  196. 5. compress_level(int) between 1 to 9, 1 (more fast) <---> 9 (more compress)
  197. 6. optional function to be called during processing which takes one argument, the count of how many files have been compressed
  198. """
  199. pyminizip.compress_multiple([data_file_path, name_file_path], ['', ''], zip_path, key, compress_level)
  200. # --- remove file ---
  201. os.remove(data_file_path)
  202. os.remove(name_file_path)
  203. return dict(code=0, details='ended.')
  204. except Exception as exception:
  205. # --- revert ---
  206. os.remove(name_file_path)
  207. os.rename(data_file_path, file_path)
  208. import traceback
  209. print(traceback.format_exc())
  210. return dict(code=-1, details=f"{traceback.format_exc()}")
  211. def zip_to_file_v2_1(file_path, key='<YourPassword>', no_path=True):
  212. """zip转file(双文件保存版,其中一个文件保存加密文件名)"""
  213. # --- check parameter ---
  214. if not os.path.isfile(file_path):
  215. return dict(code=1, details='parameter error!')
  216. # --- check again ---
  217. file_name = file_path.split('/')[-1]
  218. is_encrypted = len(file_name) == 37 and file_name[32] == '.'
  219. if not is_encrypted:
  220. return dict(code=2, details='parameter error!')
  221. # --- record ---
  222. dir_path = '/'.join(file_path.split('/')[:-1])
  223. names = os.listdir(dir_path)
  224. before_files = set(f"{dir_path}/{name}" for name in names if not os.path.isdir(f"{dir_path}/{name}"))
  225. try:
  226. # --- writing ---
  227. """
  228. Args:
  229. 1. src file path (string)
  230. 2. password (string) or None (to unzip encrypted archives)
  231. 3. dir path to extract files or None (to extract in a specific dir or cwd)
  232. 4. withoutpath (exclude path of extracted)
  233. """
  234. pyminizip.uncompress(file_path, key, dir_path, no_path)
  235. # --- record ---
  236. names = os.listdir(dir_path)
  237. after_files = set(f"{dir_path}/{name}" for name in names if not os.path.isdir(f"{dir_path}/{name}"))
  238. # --- check ---
  239. temp_file = list(after_files - before_files)
  240. if len(temp_file) != 2:
  241. raise Exception('something is wrong!')
  242. # --- get file name ---
  243. raw_name = str()
  244. for path in temp_file:
  245. name = path.split('/')[-1]
  246. if len(name) == 4:
  247. with open(path, 'r') as f1:
  248. raw_name = aes_to_text(f1.read(), key=key)
  249. os.remove(path)
  250. # --- rename ---
  251. for path in list(after_files - before_files):
  252. name = path.split('/')[-1]
  253. if len(name) == 32:
  254. os.rename(path, f"{dir_path}/{raw_name}")
  255. # --- remove file ---
  256. os.remove(file_path)
  257. return dict(code=0, details='ended.')
  258. except Exception as exception:
  259. # --- revert ---
  260. names = os.listdir(dir_path)
  261. after_files = set(f"{dir_path}/{name}" for name in names if not os.path.isdir(f"{dir_path}/{name}"))
  262. for path in list(after_files - before_files):
  263. os.remove(path)
  264. import traceback
  265. print(traceback.format_exc())
  266. return dict(code=-1, details=f"{traceback.format_exc()}")
  267. def file_to_zip_v3(file_path, key='YourPassword', aes_bits=128):
  268. """
  269. 生成aes加密zip压缩文件
  270. aes_bits: 128/192/256
  271. """
  272. # --- check parameter ---
  273. if not os.path.isfile(file_path):
  274. return dict(code=1, details='parameter error!')
  275. # --- encrypt file name ---
  276. file_name = file_path.split('/')[-1]
  277. save_name = text_to_aes(file_name, key=key)
  278. # --- check system support ---
  279. if len(save_name) > 250:
  280. return dict(code=2, details='parameter error!')
  281. # --- define zip name ---
  282. file_md5 = get_big_file_md5(file_path)
  283. zip_name = f"{file_md5}.zip"
  284. dir_path = '/'.join(file_path.split('/')[:-1])
  285. zip_path = f"{dir_path}/{zip_name}"
  286. # --- writing ---
  287. with pyzipper.AESZipFile(zip_path, 'w', compression=pyzipper.ZIP_LZMA) as f1:
  288. f1.setpassword(key.encode())
  289. f1.setencryption(pyzipper.WZ_AES, nbits=aes_bits)
  290. f1.write(file_path, arcname=save_name)
  291. return dict(code=0, details='ended.')
  292. def zip_to_file_v3(file_path, key='YourPassword'):
  293. """生成aes加密zip压缩文件"""
  294. dir_path = '/'.join(file_path.split('/')[:-1])
  295. # --- reading ---
  296. with pyzipper.AESZipFile(file_path) as f1:
  297. f1.setpassword(key.encode())
  298. file_list = f1.namelist()
  299. for file_name in file_list:
  300. # --- decrypt file name ---
  301. raw_name = aes_to_text(file_name, key=key)
  302. # --- writing ---
  303. with open(f"{dir_path}/{raw_name}", 'wb') as f2:
  304. f2.write(f1.read(file_name))
  305. return dict(code=0, details='ended.')
  306. def file_to_7z(file_path, key='YourPassword'):
  307. pass
  308. def folder_to_zip(folder_path):
  309. pass
  310. if __name__ == '__main__':
  311. # text1 = '0/588564d4-3bca-4ebf-83d8-1155963fbfa9/3066753951/1593578486/1595174400'
  312. text2 = 'eFVqYzZjZ3hneVZ0T09uVVlHTm1rUT09'
  313. # text2 = text_to_aes(text1, '123456')
  314. test3 = aes_to_text(text2, '123456')
  315. # print('密文:', text2)
  316. print('明文:', test3)