123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406 |
- # 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='<YourPassword@2021>', 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='<YourPassword@2021>', 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='<YourPassword@2021>', 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='<YourPassword>', 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)
|