python项目加密(模型加密,文件加密),涵盖了多种方法以及代码实现

2023-11-08

Python作为动态语言一般是以源码方式进行部署的,这就意味着他人在部署机器上可以直接获取项目代码,可能给作者带来不必要的损失和风险,这就需要对代码进行加密或混淆。常规的几类加密(混淆)方式如下:

  1. 编译为pyc文件
  2. 将项目代码打包成python包
  3. 将python文件变异成二进制文件

总体来说1和2的方式还是存在一定的风险,本文将采用第三种方式,且提供五种该类型的加密方式,分别为、Cython、cryptography、RSA、pyAesCrypt和encryptpy。

一、Cython

该方法是通过Cython将python文件编译成.c(C语言)文件,再生成.so(share object)文件,这种方式是不可逆的,所以能够起到混淆代码,起到一定程度的加密效果。
通过命令查看目录结构

$ tree -a .

目录结构如下:

.
├── setup.py
└── example
    ├── __init__.py
    ├── main.py
    ├── README.md
    ├── xxx.py
    └── utils.py

1 directory, 6 files

运行命令

python setup.py build_ext

setup.py文件如下,这段代码可通用,直接运行即可自动生成

# -*- coding: utf-8 -*- 
import os
import shutil
import fnmatch
from distutils.core import setup
from Cython.Build import cythonize


def get_delete_files(project_root):
    """这个函数会遍历指定项目根目录下的所有文件,并返回一个包含所有Python文件的列表。 这个函数会排除名为'main.py'的文件,因为它是主程序文件。"""
    matches = []
    for root, dirnames, filenames in os.walk(project_root):
        for filename in fnmatch.filter(filenames, '*.py'):
            if filename != 'main.py':  # 排除main.py文件
                matches.append(os.path.join(root, filename))
        for filename in fnmatch.filter(filenames, '*.c'):
            matches.append(os.path.join(root, filename))

    return matches


def get_py_files(project_root):
    """这个函数会遍历指定项目根目录下的所有文件,并返回一个包含所有Python文件的列表。 这个函数会排除名为'main.py'的文件,因为它是主程序文件。"""
    matches = []
    for root, dirnames, filenames in os.walk(project_root):
        for filename in fnmatch.filter(filenames, '*.py'):
            if filename != 'main.py':  # 排除main.py文件
                matches.append(os.path.join(root, filename))

    return matches


def tool(root, paths):
    """
    该函数是执行整个任务的主要函数。它以项目的根目录和Python文件的路径列表作为输入。
    :param root:
    :param paths:
    :return:
    """
    filePath3 = os.path.dirname(dis_root) + '/build/'
    if not os.path.exists(filePath3):
        os.mkdir(filePath3)

    # 1、文件加密
    setup(name='encrypt', ext_modules=cythonize(paths))
    print("加密完成")

    # 2、将加密的文件移至对应目录下
    files_1 = os.listdir(filePath3)
    for files_1_temp in files_1:
        if "lib" in files_1_temp:
            files_1 = files_1_temp
            # print(files_1)
    print('filePath3: ', filePath3)
    print('files_1: ', files_1)
    for files_2 in os.listdir(filePath3 + files_1):
        so_file = filePath3 + files_1+"/" + files_2
        print(so_file)

        # 文件移动或拷贝
        shutil.move(so_file, root)

    # 3、删除原文件和生成的附属文件夹
    files2 = get_delete_files(dis_root)
    for file in files2:
        if os.path.exists(file):
            os.remove(file)
            print('移除后test 目录下有文件:%s' % file)
        else:
            print("要删除的文件不存在!")

    # 删除附属文件夹
    try:
        shutil.rmtree(filePath3)
    except Exception as ex:
        print("错误信息:"+str(ex)) # 提示:错误信息,目录不是空的
    print("删除完成")


dis_root = '/mnt/xxx/example'
Paths = get_py_files(dis_root)
tool(dis_root, Paths)

二、加密库 cryptography

环境安装

	pip install cryptography

下面以加密一个onnx文件为例。
先进行加密,可根据配置密钥个数,保障加密强度。然后对文件内容进行加密,当然这个密钥后面在对文件进行解密的时候会派上用场,因此密钥一定要保存完好,代码如下:

import os
import base64
import argparse
from cryptography.fernet import Fernet, MultiFernet


def Parser():
    parser = argparse.ArgumentParser(description='文件加密')
    parser.add_argument('--model_file', '-mf', type=str, default=None, help='需要加密文件的绝对地路径')
    parser.add_argument('--new_model_file', '-nmf', type=str, default=None, help='文件保存的绝对地路径')
    parser.add_argument('--key_num', '-kn', type=int, default=8, help='密钥数量')
    return parser.parse_args()


def generate_key(message='') -> bytes:
    x = os.urandom(32 - len(message)) + message.encode()
    return base64.urlsafe_b64encode(x)


def add_secret(model_file=None, new_model_file=None, multi_key: int = 1):
    if new_model_file is None:
        ext = os.path.splitext(model_file)[-1]
        new_model_file = model_file.replace(ext, '.dll')

    # # 生成密钥
    ks = []
    keys = []
    if multi_key > 0:
        for i in range(multi_key):
            keyi = generate_key()
            keys.append(keyi)
            print(f'key{i + 1}: ', keyi)
            ki = Fernet(keyi)
            ks.append(ki)
        if len(ks) == 1:
            f = ks[0]
        else:
            f = MultiFernet(ks)
    else:
        raise ValueError('The "multi_key" must be greater than 0.')

    # 保存license
    file = 'license.dll'
    with open(file, 'wb') as fw:
        for j in keys:
            fw.write(j + b'\n')
    print('liscence file write in ', file)

    with open(new_model_file, 'wb') as ew:
        # 二进制读取模型文件
        content = open(model_file, 'rb').read()
        # 根据密钥解密文件
        encrypted_content = f.encrypt(content)
        # print(encrypted_content)
        # 保存到新文件
        ew.write(encrypted_content)


def desecrect(new_model_file: str = None, keys_file: str = None):
    """
    :param new_model_file:
    :param keys:
    :return:
    """

    with open(keys_file, 'rb') as f:
        x = f.read()
        keys = x.strip(b'\n').split(b'\n')

    print(keys)
    ks = []
    for keyi in keys:
        ki = Fernet(keyi)
        ks.append(ki)
    if len(ks) > 1:
        f = MultiFernet(ks)
    else:
        f = ks[0]

    onnx_file = open(new_model_file, 'rb').read()
    onnx_file = f.decrypt(onnx_file)
    if onnx_file is not None:
        print('解密成功')

    with open(desecrect_model_file, 'wb') as ew:
        ew.write(onnx_file)


def test():
    dll_file = 'xxx.dll'
    key1 = 'license.dll'
    desecrect(dll_file, key1)


def main():
    args = Parser()
    if args.model_file is None:
        model_file = 'xxx.onnx'
    else:
        model_file = args.model_file

    message = args.message if args.message is not None else ''
    add_secret(message, model_file, args.new_model_file, args.key_num)


if __name__ == '__main__':
    main()
    # test()

三、加密库 RSA

使用RSA加密算法实现数据的加密解密
环境安装

	pip install rsa
import os
import rsa

def encrypt_file(file_path, public_key_file):
    """使用RSA算法加密文件
    
    参数:
    file_path: 需要加密的文件路径
    public_key_file: 公钥文件路径
    
    返回值:
    无
    """
    # 读取文件内容
    with open(file_path, "rb") as file:
        file_content = file.read()
    # 读取公钥
    with open(public_key_file, "rb") as key_file:
        public_key = rsa.PublicKey.load_pkcs1(key_file.read())
    # 加密文件内容
    encrypted_content = rsa.encrypt(file_content, public_key)
    # 将加密后的内容写入文件
    with open(file_path, "wb") as file:
        file.write(encrypted_content)

def decrypt_file(file_path, private_key_file, password):
    """使用RSA算法解密文件
    
    参数:
    file_path: 需要解密的文件路径
    private_key_file: 私钥文件路径
    password: 私钥文件密码
    
    返回值:
    无
    """
    # 读取文件内容
    with open(file_path, "rb") as file:
        encrypted_content = file.read()
    # 读取私钥
    with open(private_key_file, "rb") as key_file:
        private_key = rsa.PrivateKey.load_pkcs1(key_file.read(), password)
    # 解密文件内容
    file_content = rsa.decrypt(encrypted_content, private_key)
    # 将解密后的内容写入文件
    with open(file_path, "wb") as file:
        file.write(file_content)

四、加密库 pyAesCrypt

个人觉得这个代码库实现最为简单,只是密钥需要我们自己指定的
环境安装

	pip install pyAesCrypt
import pyAesCrypt

def Encryption(input_file_path, output_file_path, key):
    pyAesCrypt.encryptFile(input_file_path, output_file_path, key)
    print("File has been decrypted")

def Decryption(input_file_path, output_file_path, key):
    pyAesCrypt.decryptFile(input_file_path, output_file_path, key)
    print("File has been decrypted")

五、加密库 encryptpy

encryptpy使用Cython将Python代码编译为二进制以达到加密的目的,并且支持通过git-diff来获取两次提交间的差异文件,方便地进行编译
环境安装

	pip install encryptpy

Basic Usage

Usage: encryptpy [OPTIONS] COMMAND [ARGS]...

  Encrypt your Python code

Options:
  --config TEXT  The config file, ignore if given is invalid  [default:
                 .encryptpy.cfg]
  --help         Show this message and exit.

Commands:
  clean     Simply clean `build` and `__pycache__` directory in DIRS
  git-diff  Compile files between two COMMITS, see `git-diff`: `--name-only`
  init      Copy src to build-dir and do compile, usually used for the...
  run       Compile given Python code files

子命令用法可以使用encryptpy --help来查看。

例子

例如,有一个名为package_a的项目文件目录:

$ tree -a .
.
├── .encryptpy.cfg
└── package_a
    ├── __init__.py
    ├── main.py
    ├── README.md
    ├── setup.py
    └── utils.py

1 directory, 6 files

其中 .encryptpy.cfg内容如下:

[encryptpy]
; Files will be compiled
paths =
    package_a
; Files will be ignored when compiling, support Regex
ignores =
    setup.py
; For command `init`, files will be ignored when copying, Glob-style
copy_ignores =
    *.pyc
    *.md
; The build directory
build_dir = build
; For commands `run` and `git-diff`, whether the source .py will be removed
clean_py = 0
1. 项目第一次使用,使用init
$ encryptpy init .

查看build目录:

$ tree -a build
build
├── .encryptpy.cfg
└── package_a
    ├── __init__.cpython-38-x86_64-linux-gnu.so
    ├── main.cpython-38-x86_64-linux-gnu.so
    ├── setup.py
    └── utils.cpython-38-x86_64-linux-gnu.so

1 directory, 5 files
  1. 使用run
$ encryptpy run package_a/main.py

将package_a/main.py被重新编译为package_amain.cpython-38-x86_64-linux-gnu.so

  1. 使用git-diff
$ encryptpy git-diff 0.1 0.2

标记(或提交或分支)0.1 和 0.2 之间更改的文件将被编译。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

python项目加密(模型加密,文件加密),涵盖了多种方法以及代码实现 的相关文章

  • 即使页面未完全加载,我们也可以使用 Selenium 获取页面源吗(TimeoutException: Message: timeout)?

    即使遇到 TimeoutException Message timeout 也能获取页面源码吗 当我调用 driver page source 时 有时无法加载整页 但我只需要它的部分信息 尚未确定 所以我只想在任何情况下保存页面 是否可以
  • Kivy - 文本换行工作错误

    我正在尝试在 Kivy 1 8 0 应用程序中换行文本 当没有太多文字时 一切正常 但如果文本很长并且窗口不是很大 它只是剪切文本 这是示例代码 vbox BoxLayout orientation vertical size hint y
  • Python从int到string的快速转换

    我正在用 python 求解大量阶乘 并发现当我完成计算阶乘时 需要相同的时间才能转换为字符串以保存到文件中 我试图找到一种将 int 转换为字符串的快速方法 我将举一个计算和 int 转换时间的例子 我正在使用通用的 a str a 但感
  • 如何使用 VSCode 调试 Linux 核心转储?

    我故意从我使用 VSCode 编写的 C 应用程序生成核心转储 我不知道如何调试核心转储 有没有人愿意分享这方面的经验 更新 我相信我现在已经可以使用了 我为核心文件创建了第二个调试配置 我需要添加指向生成的转储文件的 coreDumpPa
  • 如何在 PyCharm 4.5.2 中使用 PyPy 作为标准/默认解释器?

    如何在 PyCharm 4 5 2 中使用 PyPy 作为标准 默认解释器 一切都在 Ubunutu 14 10 下运行 并且 pypy 已经安装 您可以在项目的设置下进行配置 这个官方文档直接涵盖了 https www jetbrains
  • 了解 Python 中的酸洗

    我最近接到一项作业 需要以腌制形式放置一本字典 其中每个键引用一个列表 唯一的问题是我不知道腌制形式是什么 谁能给我指出一些好的资源的正确方向来帮助我学习这个概念 pickle 模块实现了一个基本但强大的算法 用于序列化和反序列化 Pyth
  • 更新 Sqlalchemy 中的多个列

    我有一个在 Flask 上运行的应用程序 并使用 sqlalchemy 与数据库交互 我想用用户指定的值更新表的列 我正在使用的查询是 def update table value1 value2 value3 query update T
  • numpy 使用 datetime64 进行数字化

    我似乎无法让 numpy digitize 与 datetime64 一起使用 date bins np array np datetime64 datetime datetime 2014 n 1 s for n in range 1 1
  • 可以用 Django 制作移动应用程序吗?

    我想知道我是否可以在我的网站上使用 Django 代码 并以某种方式在移动应用程序 Flutter 等框架中使用它 那么是否可以使用我现在拥有的 Django 后端并在移动应用程序中使用它 所以就像models views etc 是的 有
  • 如何将 self 传递给装饰器?

    我该如何通过self key下面进入装饰器 class CacheMix object def init self args kwargs super CacheMix self init args kwargs key func Cons
  • Python Pandas 根据另一列的总计从另一个数据帧中选择值

    我下面有一个 DataFrame 但我需要根据取消和订单列从每个代码中选择行 假设代码 xxx 的阶数为 6 1 5 1 阶数为 11 我需要一种算法 可以选择满足总共 11 行的行 阶数为 6 5 如果没有行匹配 则选择最接近的 id 并
  • Python多处理错误“ForkAwareLocal”对象没有属性“连接”

    下面是我的代码 我面临着多处理问题 我看到这个问题之前已经被问过 我已经尝试过这些解决方案 但它似乎不起作用 有人可以帮我吗 from multiprocessing import Pool Manager Class X def init
  • 如果输入被重定向则执行操作

    我想知道如果我的输入被重定向 我应该如何在 C 程序中执行操作 例如 假设我有已编译的程序 prog 并且我将输入 input txt 重定向到它 我这样做 prog lt input txt 我如何在代码中检测到这一点 一般来说 您无法判
  • 是否可以将 pd.Series 分配给无序 pd.DataFrame 中的列而不映射到索引(即不重新排序值)?

    在 Pandas 中创建或分配新列时 我发现了一些意外的行为 当我对 pd DataFrame 进行过滤或排序 从而混合索引 然后从 pd Series 创建新列时 Pandas 会重新排序该系列以映射到 DataFrame 索引 例如 d
  • 对数据帧的每 2 小时数据进行 Groupby

    我有一个数据框 Time T201FN1ST2010 T201FN1VT2010 1791 2017 12 26 00 00 00 854 69 0 87 1792 2017 12 26 00 20 00 855 76 0 87 1793
  • 在 virtualenvwrapper 中激活环境

    我安装了virtualenv and virtualenvwrapper用这个命令我创建了一个环境 mkvirtualenv cv 它有效 创建后我就处于新环境中 现在我重新启动了我的电脑 我想activate又是那个环境 但是怎么样 我使
  • 更改 Python Cmd 模块处理自动完成的方式

    我有一个 Cmd 控制台 设置为自动完成 Magic the Gathering 收藏管理系统的卡牌名称 它使用文本参数在数据库中查询卡片 并使用结果自动完成 建议卡片 然而 这些卡片名称有多个单词 Cmd 会从last到行尾的空间 例如
  • Django 模型:如何使用 mixin 类来覆盖 django 模型以实现 save 等功能

    我想在每次保存模型之前验证值 所以 我必须重写保存函数 代码几乎是一样的 我想把它写在 mixin 类中 但失败了 我不知道如何写 super func 我英语不好 抱歉 class SyncableMixin object def sav
  • 如何获取所有mysql元组结果并转换为json

    我能够从表中获取单个数据 但是当我试图获取表上的所有数据时 我只得到一行 cnn execute sql rows cnn fetchall column t 0 for t in cnn description for row in ro
  • 使用 urllib 编码时保持 url 参数有序

    我正在尝试用 python 模拟 get 请求 我有一个参数字典 并使用 urllib urlencode 对它们进行 urlencode 我注意到虽然字典的形式是 k1 v1 k2 v2 k3 v3 urlencoding 后参数的顺序切

随机推荐

  • 刷题之字符串的排列 以及双指针滑动窗口

    刷题 给你两个字符串 s1 和 s2 写一个函数来判断 s2 是否包含 s1 的排列 如果是 返回 true 否则 返回 false 换句话说 s1 的排列之一是 s2 的 子串 示例 1 输入 s1 ab s2 eidbaooo 输出 t
  • 力扣练习题之数组中找两个数之和等于目标数值详细讲解

    力扣练习题 1 0 题目 给定一个整数数组 nums 和一个整数目标值 target 请你在该数组中找出 和为目标值 target 的那 两个 整数 并返回它们的数组下标 你可以假设每种输入只会对应一个答案 但是 数组中同一个元素在答案里不
  • 图的深度优先遍历

    深度优先查找 原理 深度优先搜索可以从图的任意顶点开始 然后把该顶点标记为已经访问 每次迭代的时候 深度搜索紧接着处理与当前顶点邻接的未访问顶点 如果有若干个顶点 则任意选择一个 也可以按自己的条件选择 让这个过程一直持续 直到遇到一个终点
  • 2018年蓝桥杯第九届省赛b组第四题--测试次数

    第四题 标题 测试次数 x星球的居民脾气不太好 但好在他们生气的时候唯一的异常举动是 摔手机 各大厂商也就纷纷推出各种耐摔型手机 x星球的质监局规定了手机必须经过耐摔测试 并且评定出一个耐摔指数来 之后才允许上市流通 x星球有很多高耸入云的
  • 冯诺依曼体系结构、哈佛体系结构

    冯诺依曼体系结构 哈佛体系结构与改进型哈佛结构之间的区别 1 冯 诺依曼结构 冯 诺依曼结构又称作普林斯顿体系结构 Princetionarchitecture 1945年 冯 诺依曼首先提出了 存储程序 的概念和二进制原理 后来 人们把利
  • Vue之单文件组件和脚手架

    简介 主要介绍单文件组件的定义和编写方法和脚手架相关知识介绍 单文件组件的定义是一个文件只有一个组件 使用xxx vue文件 这个文件是vue团队定义的一种文件类型 xxx vue文件里面可以使用三个标签
  • SpringBoot 之AOP实现过滤器、拦截器、切面

    文章目录 AOP概述 AOP底层实现机制 过滤器 拦截器 切面区别 过滤器 Filter 使用过滤器统一请求耗时 拦截器 Interceptor 使用拦截器判断是否登录 AspectJ 简介 AspectJ 注解开发 AOP AOP 注解说
  • 【C语言进阶】文件操作

    博客主页 小王又困了 系列专栏 C语言 人之为学 不日近则日退 感谢大家点赞 收藏 评论 目录 一 什么是文件 1 1程序文件 1 2数据文件 1 3文件名 二 文件的打开和关闭 2 1文件指针 2 2文件的打开和关闭 三 文件的顺序读写
  • voc格式标签读写操作

    image load imagePath imageShape image height image width 1 if image isGrayscale else 3 writer PascalVocWriter imgFolderN
  • 使用51单片机ADC0808测量电压

    1 protues仿真图 程序 include
  • 第10篇:强化学习Q-learning求解迷宫问题 代码实现

    你好 我是郭震 zhenguo 今天重新发布强化学习第10篇 强化学习Q learning求解迷宫问题 代码实现 我想对此篇做一些更加详细的解释 1 创建地图 创建迷宫地图 包括墙网格 走到墙网格就是负奖励 注意 空白可行走网格奖励值设置为
  • 利用梳状函数求解周期函数傅里叶变换

    本文对梳状函数 1 单位冲激函数 2 梳状函数及其傅里叶变换 3 卷积和傅里叶变换 卷积是一种运算方式 针对线性时不变系统 最基础的应用就是 在时域中 一个输入 卷积上单位冲激响应 就可以得到输出 傅立叶变换的主要作用就是让函数在时域和频域
  • 在Ubuntu中配置中文输入法

    找到设置 选择区域和语言 点击Manage Installed Languagees 提示安装的话安装即可 4 点击图示内容 5 将Chinese simplified 勾选上 右键点击住 将汉语拖到第一位 重启Ubuntu 6 在输入源中
  • linux设备树节点添加新的复位属性之后设备驱动加载异常问题分析

    linux设备树节点添加新的复位属性之后设备驱动加载异常问题分析 1 linux原始设备驱动信息 1 1 设备树节点信息 1 2 linux设备驱动 1 3 makefile 1 4 Kconfig 1 5 对应的defconfig文件 2
  • Springboot ppt转pdf——aspose方式

    Springboot ppt转pdf aspose方式 1 下载ppt转pdf所需要的包 网盘地址 https pan baidu com s 1V CZ0zXcJzKofxr6qC1g8A 提取码 86lp 2 maven添加依赖 在项目
  • 编译开源软件vtr-verilog-to-routing遇到的一点问题

    vtr verilog to routing介绍 Verilog to Routing VTR 项目是一个全球性的合作项目 旨在提供一个开源框架 用于进行FPGA架构和CAD研究和开发 VTR设计流程以数字电路的Verilog描述和目标FP
  • SpringBoot连接RabbitMQ时一直显示Socket Closed或者An unexpected connection driver error occured,但是能正常访问web管理台

    问题 在使用SpringBoot去连接虚拟机或者远程主机的RabbitMQ时 出现了一直报错超时 报错 Socket Closed 或者 An unexpected connection driver error occured 解决方案
  • “程序员转型管理:从擅长代码到掌控团队的踩坑总结”

    作为程序员 很多人会在职业生涯中考虑转型管理岗位 然而 这个转换并不容易 除了需要掌握管理方面的知识和技能外 还需要处理人际关系并带领团队一起前进 在这个过程中 很多人可能会踩到一些坑 以下是我总结的一些经验教训 一 控制欲 由于程序员需要
  • jquery ajax 防止注入,javascript-jQuery在ajax全局事件中注入数据

    我正在尝试在ajax请求中注入数据 但是它失败了 我也不知道为什么 我试图查看jQuery源代码 但仍然找不到为什么它不起作用 感谢任何帮助 这是代码 someElement ajaxSend function e req options
  • python项目加密(模型加密,文件加密),涵盖了多种方法以及代码实现

    Python作为动态语言一般是以源码方式进行部署的 这就意味着他人在部署机器上可以直接获取项目代码 可能给作者带来不必要的损失和风险 这就需要对代码进行加密或混淆 常规的几类加密 混淆 方式如下 编译为pyc文件 将项目代码打包成pytho