一种Python工具的License授权机制

一种Python工具的License授权机制作为一种流行语言,在不同的应用领域,利用Python书写的工具越来越多。Python具有应用领域广泛、简单易学、功能强大等特点,但是在很多场合它也具有一些较难克服的缺点:代码明文,较难加密。 由于#1,python脚本很难应用于收费工具领域。那么如果我想对一个Python工具的使用加以限制,有没有什么方法可以实现呢?本文提供一种简易的License授权机制实现思路,它主要包括如下几部分内容:如何生成一个加密的License文件。 如何做License内容核验。…

大家好,又见面了,我是你们的朋友全栈君。如果您正在找激活码,请点击查看最新教程,关注关注公众号 “全栈程序员社区” 获取激活教程,可能之前旧版本教程已经失效.最新Idea2022.1教程亲测有效,一键激活。

Jetbrains全家桶1年46,售后保障稳定

       作为一种流行语言,在不同的应用领域,利用Python书写的工具越来越多。Python具有应用领域广泛、简单易学、功能强大等特点,但是在很多场合它也具有一些较难克服的缺点:

  1. 代码明文,较难加密。
  2. 由于#1,python脚本很难应用于收费工具领域。

 

       那么如果我想对一个Python工具的使用加以限制,有没有什么方法可以实现呢?本文提供一种简易的License授权机制实现思路,它主要包括如下几部分内容:

  1. 如何生成一个加密的License文件。
  2. 如何做License内容核验。
  3. 如何加密Python代码。

 

       其主要流程逻辑如下:

一种Python工具的License授权机制

图1 License授权机制流程

 

一、引题

       我写了一个python脚本eda.py,内容如下。

#!/usr/bin/env python3



def function():

    print('I am an EDA tool!')



function()

Jetbrains全家桶1年46,售后保障稳定

 

       我在Linux操作系统中执行了这个程序,成功了,输出如下。

[liyanqing@ic001 license]$ ./eda.py

I am an EDA tool!

 

       我决定把这个“牛逼”的脚本分享给别人使用。但是主要的障碍在于,我不希望别人随便传播这个脚本,不希望别人无限期使用这个脚本,不希望别人学会这几行代码的写法,于是我决定对它加上License限制。

 

二、生成License文件

       工具License常在如下方面对工具的使用加以限制:

  1. 使用的MAC地址。(防止工具被随意拷贝使用)
  2. 使用期限。(过期失效)

 

       更加复杂的应用场景,还可以对License使用数量、用户列表、工具feature等因素加以限制。

       按照这个需求,我们要设计一个简化的License文件,它需要包含以下内容:

  1. MAC :允许工具启动的机器的MAC地址。
  2. Date :工具有效期。
  3. Sign :签名,对以上明文内容的加密,用作内容核验。

 

       首先,我们可以用下面的Linux指令获取机器的MAC地址。

[liyanqing@ic001 license]$ ifconfig -a

ens33: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500

        inet 192.168.246.128  netmask 255.255.255.0  broadcast 192.168.246.255

        inet6 fe80::7e02:97:820d:1bd3  prefixlen 64  scopeid 0x20<link>

        ether 00:0c:29:4a:d4:6c  txqueuelen 1000  (Ethernet)

        RX packets 1491722  bytes 1542769755 (1.4 GiB)

        RX errors 0  dropped 0  overruns 0  frame 0

        TX packets 533500  bytes 32951033 (31.4 MiB)

        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

 

       在centos7系统下,可以从ether行抓取机器的MAC地址。其他的操作系统略有不同。

       我们限制工具的使用期限,比如2021.05.20。

       最后我们将如上信息加密。

       常见的加密算法有AES(对称加密)和RSA(非对称加密),其中AES因执行速度快和硬件支持(部分Intel的处理器支持ASE指令加速)常用作批量内容的数据加密,RSA则由于其公钥-私钥机制常用于秘钥传输。此处我们选择AES加密方式来加密MAC /Date信息。

       下面直接给出生成License文件的脚本gen_license_file.py。

#!/usr/bin/env python3



from Crypto.Cipher import AES

from binascii import b2a_hex



def encrypt(content):

    # content length must be a multiple of 16.

    while len(content) % 16:

        content += ' '



    content = content.encode('utf-8')



    # Encrypt content.

    aes = AES.new(b'2021052020210520', AES.MODE_CBC, b'2021052020210520')

    encrypted_content = aes.encrypt(content)



    return(b2a_hex(encrypted_content))



def gen_license_file():

    license_file = './License.dat'



    with open(license_file, 'w') as LF:

        LF.write('MAC : 00:0c:29:4a:d4:6c\n')

        LF.write('Date : 20210520\n')

        sign = encrypt('00:0c:29:4a:d4:6c#20210520')

        LF.write('Sign : ' + str(sign.decode('utf-8')) + '\n')



if __name__ == '__main__':

    gen_license_file()

                        

       我们利用这个脚本可以生成一个添加了限定条件的License文件。

[liyanqing@ic001 license]$ ./gen_license_file.py

[liyanqing@ic001 license]$ cat License.dat

MAC : 00:0c:29:4a:d4:6c

Date : 20210520

Sign : 6ccda9297714c2b0c9877625ad6d38aacae4d6d97a0652c926c11ff42fc30d1c

 

       其中Sign部分是以上明文信息的加密,用作校验。

 

三、核验license文件

       在原始的eda.py脚本中,我们需要载入这个License文件,并做如下几件事情:

  1. 解析License文件,获取MAC/Date/Sign信息。
  2. 解密Sign信息。
  3. 对比解密的Sign信息和MAC/Date信息,看License文件是否被篡改。
  4. 获取当前机器MAC信息和当前Date信息。
  5. 将当前机器MAC信息和当前Date信息同Sign的解密信息核验,看是否超限。

 

       那么我们把如上的License核验步骤加入到eda.py中,得到了新的代码如下。

#!/usr/bin/env python3



import os

import re

import sys

import datetime

import subprocess

from Crypto.Cipher import AES

from binascii import a2b_hex



## License check

def license_check():

    license_dic = parse_license_file()

    sign = decrypt(license_dic['Sign'])

    sign_list = sign.split('#')

    mac = sign_list[0].strip()

    date = sign_list[1].strip()



    # Check license file is modified or not.

    if (mac != license_dic['MAC']) or (date != license_dic['Date']):

        print('*Error*: License file is modified!')

        sys.exit(1)



    # Check MAC and effective date invalid or not.

    if len(sign_list) == 2:

        mac = get_mac()

        current_date = datetime.datetime.now().strftime('%Y%m%d')



        # Must run this script under specified MAC.

        if sign_list[0] != mac:

            print('*Error*: Invalid host!')

            sys.exit(1)



        # Current time must be before effective date.

        if sign_list[1] > current_date:

            print('*Error*: License is expired!')

            sys.exit(1)

    else:

        print('*Error*: Wrong Sign setting on license file.')

        sys.exit(1)



def parse_license_file():

    license_dic = {}

    license_file = './License.dat'



    with open(license_file, 'r') as LF:

        for line in LF.readlines():

            if re.match('^\s*(\S+)\s*:\s*(\S+)\s*$', line):

                my_match = re.match('^\s*(\S+)\s*:\s*(\S+)\s*$', line)

                license_dic[my_match.group(1)] = my_match.group(2)



    return(license_dic)



def decrypt(content):

    aes = AES.new(b'2021052020210520', AES.MODE_CBC, b'2021052020210520')

    decrypted_content = aes.decrypt(a2b_hex(content.encode('utf-8')))



    return(decrypted_content.decode('utf-8'))



def get_mac():

    mac = ''



    SP = subprocess.Popen('/sbin/ifconfig', shell=True, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE)

    (stdout, stderr) = SP.communicate()



    for line in str(stdout, 'utf-8').split('\n'):

        if re.match('^\s*ether\s+(\S+)\s+.*$', line):

            my_match = re.match('^\s*ether\s+(\S+)\s+.*$', line)

            mac = my_match.group(1)

            break



return(mac)



# Main function.

def function():

    print('I am an EDA tool!')



license_check()

function()

 

       执行一下,效果如下。

[liyanqing@ic001 license]$ ./eda.py

*Error*: License is expired!

 

       License过期了,工具被禁止启动,限制成功!

 

四、Python加密

       上述的License限制机制生效了,但是Python工具代码是明文的,所有的限制都可以通过篡改工具代码而绕过去,头疼。

       为此我们需要将Python工具代码加密,才能保证License的实现机制不被随便篡改。Python代码常见的5中加密机制如下:

1. 将.py文件转为.pyc文件,.pyc文件是二进制文件,不具备可读性,从而实现了代码隐藏。

    问题:.pyc文件很容易被反编译,python有一个库compileall就可以轻松实现。

2. 代码混淆。

    问题:只是降低了代码可读性,并不能完全隐藏代码逻辑和核心内容的明文信息。

3. 通过py2exe将python代码打包成二进制可执行文件。

    问题:只能在windows平台上使用。

4. 使用Cython将.py文件编译.so文件,内容就被加密了且较难激活成功教程。

    问题:部分代码可能存在不兼容的问题。

5. 修改Python解释器。

    问题:难度太高!

 

       考虑到加密效果,综合考量实现难度,我们选择#4基于Cython的加密方案。

       基于Cython的加密方案需要注意两点:

  1. .so文件可以被Python文件import,但是不可以直接运行。
  2. 执行Cython加密脚本的Python版本需要同执行Python工具的Python版本保持一致,能够显著减少代码兼容性问题。

 

       第一步,我们需要改造eda.py,将核心代码移到新文件(比如top.py),顶层脚本eda.py只保留一个空壳,同时把核心功能通过import的方式引入。

       改造后,核心脚本top.py的内容如下。同原先的eda.py相比,执行函数license_check()和function()被移除了,其它一致。

       而改造后的eda.py则成了一个空壳子,如下。

#!/usr/bin/env python3



import top



top.license_check()

top.function()

       然后我们尝试通过Cython将top.py的内容加密。这个过程主要是借助Cython和disutils两个pyton库来实现。

       首先,我们写一个setup.py文件。

import os

from distutils.core import setup

from Cython.Build import cythonize



py_files = ['top.py',]



setup(ext_modules = cythonize(py_files),)

 

       然后用指定Python脚本来执行setup.py。

[liyanqing@ic001 license]$ python3 setup.py build_ext --inplace

Compiling top.py because it changed.

[1/1] Cythonizing top.py

running build_ext

building 'top' extension

creating build

creating build/temp.linux-x86_64-3.6

gcc -pthread -B /ic/tools/anaconda3/anaconda3.5.2/compiler_compat -Wl,--sysroot=/ -Wsign-compare -DNDEBUG -g -fwrapv -O3 -Wall -Wstrict-prototypes -fPIC -I/ic/tools/anaconda3/anaconda3.5.2/include/python3.6m -c top.c -o build/temp.linux-x86_64-3.6/top.o

gcc -pthread -shared -B /ic/tools/anaconda3/anaconda3.5.2/compiler_compat -L/ic/tools/anaconda3/anaconda3.5.2/lib -Wl,-rpath=/ic/tools/anaconda3/anaconda3.5.2/lib -Wl,--no-as-needed -Wl,--sysroot=/ build/temp.linux-x86_64-3.6/top.o -o /home/liyanqing/test/license/top.cpython-36m-x86_64-linux-gnu.so

 

       我们看到新生成了.c .so文件和build目录,其中只有.so文件对我们是有用的。

[liyanqing@ic001 license]$ ls

build  eda.py  gen_license_file.py  License.dat  setup.py  top.c  top.cpython-36m-x86_64-linux-gnu.so  top.py

 

       我们清理无用文件(包括top.py),然后将.so文件更名为top.so(去掉cpython***那一堆字符串)

[liyanqing@ic001 license]$ ls

backup  eda.py  License.dat  top.so

 

       这下清爽多了。

       然后重新执行eda.py。

[liyanqing@ic001 license]$ ./eda.py

*Error*: License is expired!

 

       Good!还能正常执行。

       而此时我们看一下.so文件中的核心代码。

^?ELF^B^A^A^@^@^@^@^@^@^@^@^@^C^@>^@^A^@^@^@ð6^@^@^@^@^@^@@^@^@^@^@^@^@^@è^T^F^@^@^@^@^@^@^@^@^@@^@8^@^G^@@^@%^@$^@^A^@^@^@^E^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@l^S^... ...

 

       既然你们都看不懂这些乱码,我就放心了,哈哈。

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/234839.html原文链接:https://javaforall.net

(0)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • python少儿趣味编程案例(python少儿编程书)

    Python简单易学,功能强大,是少儿学习编程的首选语言。本书是少儿学习Python编程的趣味指南,全书共17章,按照由简到难、逐步深入的方式组织各章内容。本书从认识Python开始,首先介绍了Python的安装和IDLE的使用,然后依次介绍了变量、数字和字符串、列表、元组和字典、布尔类型等数据类型,以及条件、循环、异常和注释、函数、面向对象编程、文件操作等基础知识,并且通过实际案例讲解了海龟绘图…

    2022年4月10日
    42
  • VS2008安装失败_vs2015无法安装

    VS2008安装失败_vs2015无法安装虽然我搞了很多年的java,现在由于工作需要又要转到.net上做研究工作,以前用vb那会对ms没有什么好感,之后用过vs.net的第一个版本做开发,本以为安装一下vs2008的开发环境应该是小菜一碟,没想到经历这么曲折,赶紧写下来为同行参考。 虽然做程序开发的时间有些年头了,但是对最新的技术和工具等还总是保持着关心,vs2008中文90天试用版刚从ms网站上放出来时我就下载安装过,当时很顺

    2022年9月7日
    0
  • Android 在本地应用 启动抖音(进入主页)

    Android 在本地应用 启动抖音(进入主页)

    2021年3月12日
    651
  • java手机号正则表达式验证,面试必会「建议收藏」

    java手机号正则表达式验证,面试必会「建议收藏」什么是Arthas?Arthas是一款开源在线诊断工具,采用命令行交互模式,支持web端在线诊断,同时提供丰富的Tab自动补全功能,进一步方便进行问题的定位和诊断。这是一款开源一年多GitHubstar2万,99%的阿里研发小哥都在用的Java终极诊断利器!相对比直接下载使用,我推荐开发者可以试一下通过IDE插件CloudToolkit中使用Arthas来实现一键远程诊断功能。得益于Arthas强大且丰富的功能,让Arthas能做的事情超乎想象。下面仅仅列举几

    2022年9月17日
    0
  • WiFi安全漏洞KRACK深度解读

    WiFi安全漏洞KRACK深度解读前段时间爆出的WiFi安全漏洞KRACK,波及了全球的WLAN设备,无人幸免,也就是说wifi用户连接网络,不论是在公司,家里,还是咖啡馆,都有可能遭受攻击,问题时发现了一个,还有没有发现的,也许还更严重的问题,又该怎么办呢,如何规避协议层面的安全隐患,恐怕又是普通群众力所不及的。今天偶然看到一篇文章,文章对KRACK事件的技术缘由的进行了一番梳理剖析,纯技术系风格,看完后对此次爆出的安全漏洞有了

    2022年6月10日
    57
  • CMD进入mysql及mysql字符集设置

    CMD进入mysql及mysql字符集设置1.开始-运行-cmd-回车 或者windows+r,进入电脑或者服务器的cmd,2.执行netstartmysql,启动mysql服务(netstopmysql为停止服务),3.1找到自己mysql安装目录的bin目录(我的是C:\ProgramFiles(x86)\MySQL\MySQLServer5.1\bin),操作顺序如下图 3.2在路径栏输入cmd,     …

    2022年5月20日
    35

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号