Python源码加密与Pytorch模型加密分别介绍
作者:专业女神杀手 时间:2023-11-30 13:05:03
前言
深度学习领域,常常用python写代码,而且是建立在一些开源框架之上,如pytorch。在实际的项目部署中,也有用conda环境和python代码去部署服务器,在这个时候,又分为两种情况。
部署方式可分为两种,一种是在线部署,算法服务器归公司所有,只开放API给客户,客户通过POST请求访问算法服务器,上传数据并得到返回结果。这种情况客户当然看不到代码。还有一种是离线部署,就是给客户私有化部署,把公司的代码放到客户的服务器上运行,这种情况下客户能够看到代码。如果是python部署的项目,就需要保护两个东西,一个是模型文件,一个是python源代码。
一、python源代码的保护
由于 Python 的动态特性和开源特点,导致 Python 代码很难做到很好的加密。在实际工程部署中,如果不想让客户看到代码,一般使用C++来部署。
可是自己把代码改成c++也太费劲了,还好python提供了转c++代码的工具cpython,代码转成c++之后,编译成.so(linux)的库文件,就完成了加密效果了。整个过程已经有人写好了响应的工具,如jumy,具体参考:GitHub - Boris-code/jmpy: python 代码加密|加固
使用之前先安装jumy
pip install jmpy3
然后找到找到项目目录,在当前打开终端,并执行下面命令就能够完成编译。
jmpy -i "xxx project dir" [-o output dir]
加密后的文件默认存储在 dist/project_name/ 下。注意工程文件夹下,凡是带有if __name__=="__main__"的只要存在都不编译,注释掉一样不编译。其他的py文件才编译。所以在使用时可以把main文件暴露出来,其他的文件都编译成了.so的库文件。
优点:.so文件为二进制文件,无法反编译出源代码,源码可以得到有效保护。
缺点:编译过程会编译一些底层的代码进去,如python版本之类的,所以编译后的工程依旧依赖于环境,不能把其他机器上编译好的文件直接拿过去用。
二、pytorch模型.pth的加密
对于一个文件的加密其实还是容易,这里我们用AES(一种对称加密算法)对模型文件进行加密。
首先要安装一个包,里面包含很多加密算法,ubuntu上安装命令为‘
pip install pycrypto
然后写一个python脚本,实现读取模型文件,加密后保护的功能,和读取加密文件,解密后保存的功能。
from Crypto.Cipher import AES
from binascii import b2a_hex, a2b_hex
# 如果text不足16位的倍数就用空格补足为16位
def add_to_16(text:bytes):
if len(text) % 16:
add = 16 - (len(text) % 16)
else:
add = 0
text = text + (b'\0' * add)
return text
# 加密函数
def encrypt(text:bytes):
# key = '9999999999999999'.encode('utf-8')
key = 'tqsktqsktqsktqsk'.encode('utf-8')
mode = AES.MODE_CBC
iv = b'qqqqqqqqqqqqqqqq'
text = add_to_16(text)
cryptos = AES.new(key, mode, iv)
cipher_text = cryptos.encrypt(text)
# 因为AES加密后的字符串不一定是ascii字符集的,输出保存可能存在问题,所以这里转为16进制字符串
return b2a_hex(cipher_text)
# 解密后,去掉补足的空格用strip() 去掉
def decrypt(text):
key = 'tqsktqsktqsktqsk'.encode('utf-8')
iv = b'qqqqqqqqqqqqqqqq'
mode = AES.MODE_CBC
cryptos = AES.new(key, mode, iv)
plain_text = cryptos.decrypt(a2b_hex(text))
return plain_text
if __name__ == '__main__':
# encryption model
with open('detect_model/checkpoints/xxx_ori.pth', 'rb') as f1:
encrypted = encrypt(f1.read())
with open('detect_model/checkpoints/xxx_encryp.pth', 'wb') as f2:
f2.write(encrypted)
# decryption model
with open("./detect_model/checkpoints/xxx_decryp.pth", 'wb') as f:
content = open('detect_model/checkpoints/xxx_encryp.pth', 'rb').read()
f.write(decrypt(content))
这里用的是Crypto.Cipher模块的AES算法。模型文件加密后会比加密前的内存大一倍左右。
问题出现了。pytorch读取模型的函数torch.load()只能读取文件,并且返回一个FileIO的对象,来对文件进行操作。底层都是封死的,如果我们使用加密文件的时候要先解密成文件,那还怎么保密,可是没有办法,只能这么做。
理论上一个可行的办法是,把加密后的文件读入内存,然后对读取的内容(Bytes指针类型)进行解密,此时解密后的内容在内存中。但torch.load()只能读取文件,所以只能使用C++自己来写一个工具,完成内存解密的内容,加载到pytorch模型的操作,这个流程就比较复杂了,暂时没有实现。
来源:https://blog.csdn.net/Eyesleft_being/article/details/120224243