吾爱破解 - 52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 1097|回复: 21
收起左侧

[Python 原创] 批量加解密文件

[复制链接]
aa008u 发表于 2024-12-6 16:56
本帖最后由 aa008u 于 2024-12-6 16:58 编辑

写了一个批量加密的小程序,可以实现对文件夹下的子文件夹进行名称混淆,文件进行加密。
文件加密的时候每个文件随机生成一个AES秘钥进行加密,然后用RSA把秘钥加密后写入到加密后的文件里,防止单个文件被破解

注意:加密后的json文件是用来恢复文件夹名称的,生成的RSA公钥、RSA私钥是用来解密文档的,删了就彻底恢复不了了。



[Python] 纯文本查看 复制代码
from Crypto.Cipher import AES, PKCS1_OAEP
from Crypto.PublicKey import RSA
from Crypto.Random import get_random_bytes
import os
from loguru import logger
import uuid
import json

# logger.add("log.log", rotation="10 MB")

# Constants
CHUNK_SIZE = 64 * 1024  # 64KB per chunk
RSA_KEY_SIZE = 2048
AES_BLOCK_SIZE = 16


# Padding function (PKCS7)
def pad(data):
    padding_len = AES_BLOCK_SIZE - len(data) % AES_BLOCK_SIZE
    return data + bytes([padding_len] * padding_len)


# Unpadding function (PKCS7)
def unpad(data):
    padding_len = data[-1]
    return data[:-padding_len]


# Generate RSA key
def generate_rsa_key():
    if os.path.isfile("private_key.pem") or os.path.isfile("public_key.pem"):
        logger.warning("KYE文件已存在")
    else:
        # Generate RSA key pair
        rsa_key = RSA.generate(RSA_KEY_SIZE)
        private_key = rsa_key.export_key()
        public_key = rsa_key.publickey().export_key()
        # Save RSA keys locally
        with open("private_key.pem", "wb") as priv_file:
            priv_file.write(private_key)
        with open("public_key.pem", "wb") as pub_file:
            pub_file.write(public_key)


# Encryption function
def encrypt_file(input_file, uuid_set):
    # Generate a random AES key
    aes_key = get_random_bytes(32)

    # Initialize AES cipher in CBC mode
    cipher_aes = AES.new(aes_key, AES.MODE_CBC)

    # Read public key
    with open("public_key.pem", "rb") as public_file:
        public_key = RSA.import_key(public_file.read())

    # Encrypt the AES key using RSA
    cipher_rsa = PKCS1_OAEP.new(public_key)
    enc_aes_key = cipher_rsa.encrypt(aes_key)

    # Encrypt the file name
    file_name = os.path.basename(input_file)
    encrypted_file_name = cipher_aes.encrypt(pad(file_name.encode('utf-8')))
    file_name_length = len(encrypted_file_name)

    # Open output file
    # output_file = "ex_video"

    output_file = os.path.join(os.path.dirname(input_file), str(uuid.uuid4()))
    while output_file in uuid_set:
        output_file = str(uuid.uuid4())
    uuid_set.append(output_file)

    with open(input_file, "rb") as infile, open(output_file, "wb") as outfile:
        # Write the IV, encrypted AES key, and encrypted file name length to the output file
        outfile.write(cipher_aes.iv)
        outfile.write(enc_aes_key)
        outfile.write(file_name_length.to_bytes(2, 'big'))  # 2 bytes to store the file name length
        outfile.write(encrypted_file_name)

        # Read and encrypt the file in chunks
        while chunk := infile.read(CHUNK_SIZE):
            if len(chunk) % AES_BLOCK_SIZE != 0:
                chunk = pad(chunk)
            encrypted_chunk = cipher_aes.encrypt(chunk)
            outfile.write(encrypted_chunk)

    # Delete the original file
    os.remove(input_file)
    logger.info(f"Encryption complete. Encrypted file saved as '{output_file}'.")


# Decryption function
def decrypt_file(encrypted_file):
    # Read private key
    with open("private_key.pem", "rb") as priv_file:
        private_key = RSA.import_key(priv_file.read())

    # Open files
    with open(encrypted_file, "rb") as infile:
        # Read the IV and the encrypted AES key
        iv = infile.read(16)
        enc_aes_key = infile.read(private_key.size_in_bytes())

        # Decrypt the AES key using RSA
        cipher_rsa = PKCS1_OAEP.new(private_key)
        aes_key = cipher_rsa.decrypt(enc_aes_key)

        # Initialize AES cipher for decryption
        cipher_aes = AES.new(aes_key, AES.MODE_CBC, iv)

        # Read and decrypt the file name length and file name
        file_name_length = int.from_bytes(infile.read(2), 'big')
        encrypted_file_name = infile.read(file_name_length)
        file_name = unpad(cipher_aes.decrypt(encrypted_file_name)).decode('utf-8')

        # Set output file to the original file name
        output_file = os.path.join(os.path.dirname(encrypted_file), file_name)

        with open(output_file, "wb") as outfile:
            # Read and decrypt the file in chunks
            next_chunk = b''
            while chunk := infile.read(CHUNK_SIZE):
                if next_chunk:
                    outfile.write(next_chunk)
                next_chunk = cipher_aes.decrypt(chunk)

            # Handle the final chunk separately to remove padding
            outfile.write(unpad(next_chunk))

    os.remove(encrypted_file)
    logger.info(f"Decryption complete. Decrypted file saved as '{output_file}'.")


def get_all_file_paths(directory):
    file_paths = []
    for root, dirs, files in os.walk(directory):
        for file in files:
            file_paths.append(os.path.join(root, file))
    return file_paths


# 混淆文件夹名
def rename_folders_and_save_config(root_dir, config_file):
    all_file_paths = []
    rename_map = {}

    # 遍历指定目录及其子目录
    for root, dirs, files in os.walk(root_dir, topdown=False):
        # 收集所有子文件的路径
        for file_name in files:
            file_path = os.path.join(root, file_name)
            all_file_paths.append(file_path)

        # 修改当前目录下的所有子文件夹的名称
        for folder_name in dirs:
            # 生成一个随机的UUID
            new_name = str(uuid.uuid4())
            # 构建原始路径和新的路径
            old_folder_path = os.path.join(root, folder_name)
            new_folder_path = os.path.join(root, new_name)
            # 保存原始名称和新名称的映射
            rename_map[old_folder_path] = new_folder_path
            # 修改文件夹名称
            os.rename(old_folder_path, new_folder_path)
            logger.info(f'Renamed folder: {old_folder_path} -> {new_folder_path}')

    # 保存映射到配置文件
    with open(config_file, 'w') as f:
        json.dump(rename_map, f, indent=4)

    return all_file_paths


# 还原文件夹名
def restore_folders_from_config(config_file):
    max_depth = 0
    # 从配置文件中读取映射
    with open(config_file, 'r') as f:
        rename_map = json.load(f)

    # 遍历所有路径,计算最大层级数
    for old_folder_path, new_folder_path in rename_map.items():
        # 计算路径中的层级数
        depth = old_folder_path.count(os.sep)
        if depth > max_depth:
            max_depth = depth

    # 对路径长度进行排序,先还原子文件夹
    sorted_paths = sorted(rename_map.items(), key=lambda x: len(x[0]), reverse=True)

    while max_depth:
        max_depth -= 1
        for new_folder_path, old_folder_path in sorted_paths:
            # 确保新路径存在
            if os.path.exists(old_folder_path):
                try:
                    os.rename(old_folder_path, new_folder_path)
                    logger.info(f'Restored folder: {new_folder_path} -> {old_folder_path}')
                except Exception as e:
                    logger.error(f'Failed to restore folder {old_folder_path} -> {new_folder_path}: {e}')
            else:
                logger.warning(f'Folder not found: {old_folder_path}')


def hun_xiao(dirs, config_json):
    rename_folders_and_save_config(dirs, config_json)
    uuid_set = []
    fpaths = get_all_file_paths(dirs)
    logger.debug(fpaths)
    for file in fpaths:
        encrypt_file(file, uuid_set)
    logger.debug(uuid_set)
    logger.debug(len(uuid_set))


def hui_fu(dirs, config_json):
    fpaths = get_all_file_paths(dirs)
    logger.debug(fpaths)
    for file in fpaths:
        try:
            decrypt_file(file)
        except Exception as e:
            logger.error(e)
    restore_folders_from_config(config_json)


if __name__ == '__main__':
    generate_rsa_key()
   #混淆加密
    hun_xiao(r"文档", r"wd.json")
   #还原恢复
    #hui_fu(r"文档", r"wd.json")

免费评分

参与人数 4吾爱币 +9 热心值 +3 收起 理由
苏紫方璇 + 7 + 1 欢迎分析讨论交流,吾爱破解论坛有你更精彩!
ysjd22 + 1 感谢发布原创作品,吾爱破解论坛因你更精彩!
feijiangjun520 + 1 + 1 谢谢@Thanks!
greatzdl + 1 我很赞同!

查看全部评分

发帖前要善用论坛搜索功能,那里可能会有你要找的答案或者已经有人发布过相同内容了,请勿重复发帖。

 楼主| aa008u 发表于 2024-12-9 11:12
heguang 发表于 2024-12-8 18:48
试了一下,每次加密生成的公钥和私钥都不同,但是如果对同一个文件连续执行两次加密的话,需要解密两次才能 ...

如果同级目录下已经有RSA公钥和私钥的话,那它就不会生成新的秘钥,如果没有找到秘钥文件,那就会随机创建一对RSA秘钥。
ianlcc 发表于 2024-12-6 17:17
= RESTART: D:\111\0612\12345687788\456.py
Traceback (most recent call last):
  File "D:\111\0612\12345687788\456.py", line 1, in <module>
    from Crypto.Cipher import AES, PKCS1_OAEP
ModuleNotFoundError: No module named 'Crypto'
 楼主| aa008u 发表于 2024-12-6 17:20
ianlcc 发表于 2024-12-6 17:17
= RESTART: D:\111\0612\12345687788\456.py
Traceback (most recent call last):
  File "D:\111\0612\1 ...

要安装一下库文件
pip install pycryptodome -i https://pypi.tuna.tsinghua.edu.cn/simple
pip install loguru -i https://pypi.tuna.tsinghua.edu.cn/simple
ianlcc 发表于 2024-12-6 17:21
aa008u 发表于 2024-12-6 17:20
要安装一下库文件
pip install pycryptodome -i https://pypi.tuna.tsinghua.edu.cn/simple
pip insta ...

谢谢楼主分享!
我来安装试试
ianlcc 发表于 2024-12-6 17:28
aa008u 发表于 2024-12-6 17:20
要安装一下库文件
pip install pycryptodome -i https://pypi.tuna.tsinghua.edu.cn/simple
pip insta ...

请教楼主
这个加密的用途和用意是为了什麽呢?
另外,我刚刚运行後,文件没有任何改变,也可以正常的开启
是我哪里设置错误吗?
 楼主| aa008u 发表于 2024-12-6 17:37
ianlcc 发表于 2024-12-6 17:28
请教楼主
这个加密的用途和用意是为了什麽呢?
另外,我刚刚运行後,文件没有任何改变,也可以正常的开 ...

主要就想把一些隐私文件加密起来,我例子中是加密同目录下一个叫文档的文件夹内所有文件。
ianlcc 发表于 2024-12-6 18:01
aa008u 发表于 2024-12-6 17:37
主要就想把一些隐私文件加密起来,我例子中是加密同目录下一个叫文档的文件夹内所有文件。

喔喔!
是我忘了修改文件夹的名字
修改完後就加密成功了
再请教一下,如果我要解密的话,运行hui_fu(r"file", r"wd.json")
对吗?
 楼主| aa008u 发表于 2024-12-6 18:33
ianlcc 发表于 2024-12-6 18:01
喔喔!
是我忘了修改文件夹的名字
修改完後就加密成功了

对,自己改一下代码
52PJ070 发表于 2024-12-6 18:43
看着不错,试试跟压缩软件带的加密有啥不同,感谢分享!
孤狼微博 发表于 2024-12-6 18:54
直接用勒索病毒那一套就很完美
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则

返回列表

RSS订阅|小黑屋|处罚记录|联系我们|吾爱破解 - LCG - LSG ( 京ICP备16042023号 | 京公网安备 11010502030087号 )

GMT+8, 2025-1-7 20:03

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表