# update: 2021-5-12-21 from Crypto.Cipher import AES import base64 import hashlib import zipfile import pyminizip import pyzipper import os class _AES(object): def __init__(self, key='7486E0264E999881D4EF7BEEDF05A9F7', model='ECB', iv='', code_type='utf-8'): """ code_type: utf-8/gbk """ self.code_type = code_type self.model = {'ECB': AES.MODE_ECB, 'CBC': AES.MODE_CBC}[model] self.key = self.replenish(key) # --- create aes object --- if model == 'ECB': self.aes = AES.new(self.key, self.model) elif model == 'CBC': self.aes = AES.new(self.key, self.model, iv) def replenish(self, block, block_size=16): """block_size: AES key must be either 16, 24, or 32 bytes long""" block = block.encode(self.code_type) while len(block) % block_size != 0: block += b'\x00' return block def encrypt(self, text): text = self.replenish(text) encrypt_text = self.aes.encrypt(text) return base64.encodebytes(encrypt_text).decode().strip() def decrypt(self, text): text = base64.decodebytes(text.encode(self.code_type)) decrypt_text = self.aes.decrypt(text) return decrypt_text.decode(self.code_type).strip('\0') def text_to_b64(string): """b64编码""" return str(base64.b64encode(str(string).encode('utf-8')), 'utf-8') def b64_to_text(string): """b64解码""" return str(base64.b64decode(str(string).encode('utf-8')), 'utf-8') def text_to_aes(text, key='YourPassword'): """aes加密""" aes = _AES(key=key) return text_to_b64(aes.encrypt(text)) def aes_to_text(text, key='YourPassword'): """aes解密""" aes = _AES(key=key) return aes.decrypt(b64_to_text(text)) def get_big_file_md5(file_path, block_size=8 * 1024): """获取文件md5(默认使用8KB作为分块大小)""" m = hashlib.md5() with open(file_path, 'rb') as f: while True: block = f.read(block_size) if not block: break m.update(block) return m.hexdigest() def file_to_zip(file_path): """生成zip压缩文件""" # --- encrypt file name --- todo 如果aes后超过255的长度就不做aes了 file_name = file_path.split('/')[-1] save_name = text_to_b64(file_name) # --- define zip name --- file_md5 = get_big_file_md5(file_path) zip_name = f"{file_md5}.zip" dir_path = '/'.join(file_path.split('/')[:-1]) zip_path = f"{dir_path}/{zip_name}" # --- writing --- with zipfile.ZipFile(zip_path, 'w', compression=zipfile.ZIP_DEFLATED, allowZip64=True) as f1: f1.write(file_path, arcname=save_name) def zip_to_file(): pass def file_to_zip_v2(file_path, key='', compress_level=5): """ 文件转zip compress_level(int) between 1 to 9, 1 (more fast) <---> 9 (more compress) or 0 (default) """ # --- check parameter --- if not os.path.isfile(file_path): return dict(code=1, details='parameter error!') # --- encrypt file name --- file_name = file_path.split('/')[-1] dir_path = '/'.join(file_path.split('/')[:-1]) save_name = text_to_aes(file_name, key=key) # --- check again --- is_encrypted = len(file_name) == 37 and file_name[32] == '.' if is_encrypted: return dict(code=2, details='parameter error!') # --- check system support --- if len(save_name) > 250: return dict(code=3, details='parameter error!') # --- rename file --- save_path = f"{dir_path}/{save_name}" os.rename(file_path, save_path) # --- define zip name --- file_md5 = get_big_file_md5(save_path) zip_path = f"{dir_path}/{file_md5}.{save_name[:4]}" try: # --- writing --- """ Args: 1. src file path (string) 2. src file prefix path (string) or None (path to prepend to file) 3. dst file path (string) 4. password (string) or None (to create no-password zip) 5. compress_level(int) between 1 to 9, 1 (more fast) <---> 9 (more compress) or 0 (default) """ pyminizip.compress(save_path, None, zip_path, key, compress_level) # --- remove file --- os.remove(save_path) return dict(code=0, details='ended.') except Exception as exception: # --- revert --- os.rename(save_path, file_path) import traceback print(traceback.format_exc()) return dict(code=-1, details=f"{traceback.format_exc()}") def zip_to_file_v2(file_path, key='', no_path=True): """zip转file""" # --- check parameter --- if not os.path.isfile(file_path): return dict(code=1, details='parameter error!') # --- check again --- file_name = file_path.split('/')[-1] is_encrypted = len(file_name) == 37 and file_name[32] == '.' if not is_encrypted: return dict(code=2, details='parameter error!') # --- record --- dir_path = '/'.join(file_path.split('/')[:-1]) names = os.listdir(dir_path) before_files = set(f"{dir_path}/{name}" for name in names if not os.path.isdir(f"{dir_path}/{name}")) try: # --- writing --- """ Args: 1. src file path (string) 2. password (string) or None (to unzip encrypted archives) 3. dir path to extract files or None (to extract in a specific dir or cwd) 4. withoutpath (exclude path of extracted) """ pyminizip.uncompress(file_path, key, dir_path, no_path) # --- record --- names = os.listdir(dir_path) after_files = set(f"{dir_path}/{name}" for name in names if not os.path.isdir(f"{dir_path}/{name}")) # --- rename --- for path in list(after_files - before_files): name = path.split('/')[-1] raw_name = aes_to_text(name, key=key) os.rename(path, f"{dir_path}/{raw_name}") # --- remove file --- os.remove(file_path) return dict(code=0, details='ended.') except Exception as exception: # --- revert --- names = os.listdir(dir_path) after_files = set(f"{dir_path}/{name}" for name in names if not os.path.isdir(f"{dir_path}/{name}")) for path in list(after_files - before_files): os.remove(path) import traceback print(traceback.format_exc()) return dict(code=-1, details=f"{traceback.format_exc()}") def file_to_zip_v2_1(file_path, key='', compress_level=1): """file转zip(双文件保存版,其中一个文件保存加密文件名)""" # --- check parameter --- if not os.path.isfile(file_path): return dict(code=1, details='parameter error!') # --- check again --- file_name = file_path.split('/')[-1] is_encrypted = len(file_name) == 37 and file_name[32] == '.' if is_encrypted: return dict(code=2, details='parameter error!') # --- create name file --- dir_path = '/'.join(file_path.split('/')[:-1]) file_name_aes = text_to_aes(file_name, key=key) name_file_path = f"{dir_path}/{file_name_aes[:4]}" with open(name_file_path, 'w') as f1: f1.write(file_name_aes) # --- rename file --- file_md5 = get_big_file_md5(file_path) data_file_path = f"{dir_path}/{file_md5}" os.rename(file_path, data_file_path) # --- define zip name --- zip_path = f"{dir_path}/{file_md5}.{file_name_aes[:4]}" try: # --- writing --- # pyminizip.compress(save_path, None, zip_path, key, compress_level) """ Args: 1. src file LIST path (list) 2. src file LIST prefix path (list) or [] 3. dst file path (string) 4. password (string) or None (to create no-password zip) 5. compress_level(int) between 1 to 9, 1 (more fast) <---> 9 (more compress) 6. optional function to be called during processing which takes one argument, the count of how many files have been compressed """ pyminizip.compress_multiple([data_file_path, name_file_path], ['', ''], zip_path, key, compress_level) # --- remove file --- os.remove(data_file_path) os.remove(name_file_path) return dict(code=0, details='ended.') except Exception as exception: # --- revert --- os.remove(name_file_path) os.rename(data_file_path, file_path) import traceback print(traceback.format_exc()) return dict(code=-1, details=f"{traceback.format_exc()}") def zip_to_file_v2_1(file_path, key='', no_path=True): """zip转file(双文件保存版,其中一个文件保存加密文件名)""" # --- check parameter --- if not os.path.isfile(file_path): return dict(code=1, details='parameter error!') # --- check again --- file_name = file_path.split('/')[-1] is_encrypted = len(file_name) == 37 and file_name[32] == '.' if not is_encrypted: return dict(code=2, details='parameter error!') # --- record --- dir_path = '/'.join(file_path.split('/')[:-1]) names = os.listdir(dir_path) before_files = set(f"{dir_path}/{name}" for name in names if not os.path.isdir(f"{dir_path}/{name}")) try: # --- writing --- """ Args: 1. src file path (string) 2. password (string) or None (to unzip encrypted archives) 3. dir path to extract files or None (to extract in a specific dir or cwd) 4. withoutpath (exclude path of extracted) """ pyminizip.uncompress(file_path, key, dir_path, no_path) # --- record --- names = os.listdir(dir_path) after_files = set(f"{dir_path}/{name}" for name in names if not os.path.isdir(f"{dir_path}/{name}")) # --- check --- temp_file = list(after_files - before_files) if len(temp_file) != 2: raise Exception('something is wrong!') # --- get file name --- raw_name = str() for path in temp_file: name = path.split('/')[-1] if len(name) == 4: with open(path, 'r') as f1: raw_name = aes_to_text(f1.read(), key=key) os.remove(path) # --- rename --- for path in list(after_files - before_files): name = path.split('/')[-1] if len(name) == 32: os.rename(path, f"{dir_path}/{raw_name}") # --- remove file --- os.remove(file_path) return dict(code=0, details='ended.') except Exception as exception: # --- revert --- names = os.listdir(dir_path) after_files = set(f"{dir_path}/{name}" for name in names if not os.path.isdir(f"{dir_path}/{name}")) for path in list(after_files - before_files): os.remove(path) import traceback print(traceback.format_exc()) return dict(code=-1, details=f"{traceback.format_exc()}") def file_to_zip_v3(file_path, key='YourPassword', aes_bits=128): """ 生成aes加密zip压缩文件 aes_bits: 128/192/256 """ # --- check parameter --- if not os.path.isfile(file_path): return dict(code=1, details='parameter error!') # --- encrypt file name --- file_name = file_path.split('/')[-1] save_name = text_to_aes(file_name, key=key) # --- check system support --- if len(save_name) > 250: return dict(code=2, details='parameter error!') # --- define zip name --- file_md5 = get_big_file_md5(file_path) zip_name = f"{file_md5}.zip" dir_path = '/'.join(file_path.split('/')[:-1]) zip_path = f"{dir_path}/{zip_name}" # --- writing --- with pyzipper.AESZipFile(zip_path, 'w', compression=pyzipper.ZIP_LZMA) as f1: f1.setpassword(key.encode()) f1.setencryption(pyzipper.WZ_AES, nbits=aes_bits) f1.write(file_path, arcname=save_name) return dict(code=0, details='ended.') def zip_to_file_v3(file_path, key='YourPassword'): """生成aes加密zip压缩文件""" dir_path = '/'.join(file_path.split('/')[:-1]) # --- reading --- with pyzipper.AESZipFile(file_path) as f1: f1.setpassword(key.encode()) file_list = f1.namelist() for file_name in file_list: # --- decrypt file name --- raw_name = aes_to_text(file_name, key=key) # --- writing --- with open(f"{dir_path}/{raw_name}", 'wb') as f2: f2.write(f1.read(file_name)) return dict(code=0, details='ended.') def file_to_7z(file_path, key='YourPassword'): pass def folder_to_zip(folder_path): pass if __name__ == '__main__': # text1 = '0/588564d4-3bca-4ebf-83d8-1155963fbfa9/3066753951/1593578486/1595174400' text2 = 'eFVqYzZjZ3hneVZ0T09uVVlHTm1rUT09' # text2 = text_to_aes(text1, '123456') test3 = aes_to_text(text2, '123456') # print('密文:', text2) print('明文:', test3)