背景
在一些使用python的商业项目上,开发人员不想被用户看到源代码时,就需要对python代码进行加密;进一步地,如果想限制用户只能在获得授权的机器上运行你写的代码时(利益相关),就需要使用License控制。只有经过加密的代码才能进行License控制,试想一下,如果客户能拿到你的源代码,那么License控制就成为无稽之谈。
这里提供一种代码加密与License控制的思路。
先说python代码加密。
代码加密
众所周知,python是一种开源的编程语言,在开源的语言上做加密,加密效果肯定不如编译性语言的加密效果好,其逆向工程的难度会比编译性语言的逆向工程简单,按照这个思路,既然编译性语言c/c++的逆向工程难,那么为何不先把python编译成c/c++代码,然后再加密呢?根据经验这样是可行的,且这样加密的代码比那些编译成pyd文件或者打包成exe的方法就安全得多(pyd和exe的逆向工程有专门的包可以实现)。这就是这篇文章介绍的加密方法。
思路是先将py转换为c代码,然后编译c为so文件。
准备工作:
linux安装:
-
python-dev
-
gcc
sudo apt-get install python-dev gcc
python安装第三方库
-
pycrypto
(注意:在win10环境下安装这个包可能会报错,解决办法见这里 ) -
Cython
pip install pycrypto Cython
加密脚本``setup.py`的代码如下
# coding:utf-8
from
distutils
.
core
import
setup
from
Cython
.
Build
import
cythonize
import
os
'''
该文件的执行需要的在Terminal中输入 python setup.py build_ext --inplace
使用Cpython 编译python文件,关键函数编译成pyd文件(相当于dll)
'''
# 针对多文件情况设置,单文件就只写一个就行, 文件之间用逗号隔开
key_funs
=
[
'test.py'
]
setup
(
name
=
"XX app"
,
ext_modules
=
cythonize
(
key_funs
)
,
)
'''
1、将编译后的pyd文件的命名更改成与原py文件一致
2、删除编译后得到的c文件和原py文件
'''
print
(
"——————"
,
os
.
getcwd
(
)
,
"——————"
)
files
=
os
.
listdir
(
os
.
getcwd
(
)
)
print
(
files
)
for
fi
in
files
:
if
fi
.
__contains__
(
".pyd"
)
:
re_name
=
fi
.
split
(
"."
)
[
0
]
+
".pyd"
print
(
re_name
)
os
.
rename
(
fi
,
re_name
)
elif
fi
.
__contains__
(
".c"
)
or
fi
in
key_funs
:
os
.
remove
(
fi
)
为了更好的说明,这里举个简单的例子。
另外准备两个py文件,
test.py
和
main.py
,其中
test.py
是需要加密的代码,
main.py
是调用加密代码的脚本,不需要加密。
test.py
的内容如下
import
datetime
class
Today
(
)
:
def
get_time
(
self
)
:
print
(
datetime
.
datetime
.
now
(
)
)
def
say
(
self
)
:
print
(
'hello world'
)
main.py
的内容如下
from
test
import
Today
t
=
Today
(
)
t
.
get_time
(
)
t
.
say
(
)
加密之前,测试一下运行效果,在终端执行
python main.py
,输出
2019-08-30 11:38:38.419308
hello world
使用
setup.py
对
test.py
进行加密
方法:将需要加密的代码放到列表
key_funs
里面,然后在终端运行
python setup.py build_ext --inplace
运行完加密脚本
setup.py
后,会将
test.py
删掉(请备份到其他地方!),得到
test.so
文件和文件夹
build/
,这个文件夹可以删掉。至此代码加密完成。
测试
再次在终端执行
python main.py
,输出
2019-08-30 11:49:17.986503
hello world
成功!
(注意,不能直接在IDE执行main.py,会出现错误ImportError: cannot import name ‘Today’)
License控制
知道怎么加密代码之后,就可以用license控制你的代码,以防被别人滥用。
通过License可以控制你的代码,控制方式有很多种,包括限制主机、限制时间(过期则无法执行)、限制使用地点等,这里只介绍如何通过License限制主机,其他方法大同小异,做适当修改即可。
物理地址是每台计算机独一无二的身份号码,我们可以利用物理地址作为限制主机的依据。
具体思路是,用户拿到你写的代码后,如果用户的计算机未经你权授则不能运行你的代码,这时候就需要利用物理地址作为权授的载体进行授权计算机。如需要授权计算机,用户要把需权授的机器的物理地址发给你,你使用AES加密算法把这个物理地址加密后,将得到的加密文件发给用户(这个加密文件就相当于一把钥匙,只有拥有这把钥匙才能正常运行你的代码)用户把加密文件放到指定路径下并执行代码,程序读取加密文件并解密,得到你加密的物理地址,将此物理地址与当前主机的物理地址做匹配,如果这两个物理地址相同则程序能正常运行,不同则退出程序。这里将物理地址加密的目的是防止被用户篡改。
这里涉及到的加密算法不做详细介绍,需了解请移步 here
用户计算机申请授权过程
License控制流程图
具体代码及实现例子请移步github
(别忘了点star哦)
Reference:
- 浅谈常见的七种加密算法及实现
- 加密Python源代码笔记